762 lines
13 KiB
C
762 lines
13 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1996-2000 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
dnsapi.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Domain Name System (DNS) API
|
||
|
|
||
|
Dnsapi.dll infrastructure (init, shutdown, etc)
|
||
|
Routines to access DNS resolver
|
||
|
|
||
|
Author:
|
||
|
|
||
|
GlennC 22-Jan-1997
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
Jim Gilroy (jamesg) March 2000 cleanup
|
||
|
|
||
|
--*/
|
||
|
|
||
|
|
||
|
#include "local.h"
|
||
|
#include <lmcons.h>
|
||
|
|
||
|
|
||
|
#define DNS_NET_FAILURE_CACHE_TIME 30 // Seconds
|
||
|
|
||
|
|
||
|
//
|
||
|
// Global Definitions
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// Globals
|
||
|
//
|
||
|
|
||
|
CRITICAL_SECTION g_RegistrationListCS;
|
||
|
CRITICAL_SECTION g_RegistrationThreadCS;
|
||
|
CRITICAL_SECTION g_QueueCS;
|
||
|
CRITICAL_SECTION g_NetFailureCS;
|
||
|
|
||
|
DWORD g_NetFailureTime;
|
||
|
DNS_STATUS g_NetFailureStatus;
|
||
|
|
||
|
IP_ADDRESS g_LastDNSServerUpdated = 0;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Local Function Prototypes
|
||
|
//
|
||
|
|
||
|
BOOL
|
||
|
DnsInitialize(
|
||
|
VOID
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
DnsCleanup(
|
||
|
VOID
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
ClearDnsCacheEntry_A (
|
||
|
IN LPSTR,
|
||
|
IN WORD );
|
||
|
|
||
|
VOID
|
||
|
ClearDnsCacheEntry_W (
|
||
|
IN LPWSTR,
|
||
|
IN WORD );
|
||
|
|
||
|
VOID
|
||
|
FreeRpcIpAddressList(
|
||
|
IN PDNS_IP_ADDR_LIST );
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// System public Network Information
|
||
|
//
|
||
|
// The dnsapi.dll interface is in config.c
|
||
|
//
|
||
|
|
||
|
PDNS_NETWORK_INFORMATION
|
||
|
CreateNetworkInformation(
|
||
|
IN DWORD cAdapterCount
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
None.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
None.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PDNS_NETWORK_INFORMATION pNetworkInfo = NULL;
|
||
|
DWORD dwAdapterListBufLen = sizeof( DNS_NETWORK_INFORMATION ) -
|
||
|
sizeof( PDNS_ADAPTER_INFORMATION ) +
|
||
|
( sizeof( PDNS_ADAPTER_INFORMATION ) *
|
||
|
cAdapterCount );
|
||
|
|
||
|
pNetworkInfo = (PDNS_NETWORK_INFORMATION) ALLOCATE_HEAP_ZERO(
|
||
|
dwAdapterListBufLen );
|
||
|
|
||
|
return pNetworkInfo;
|
||
|
}
|
||
|
|
||
|
|
||
|
PDNS_SEARCH_INFORMATION
|
||
|
CreateSearchInformation(
|
||
|
IN DWORD cNameCount,
|
||
|
IN LPSTR pszName
|
||
|
)
|
||
|
{
|
||
|
PDNS_SEARCH_INFORMATION pSearchInfo = NULL;
|
||
|
DWORD dwSearchInfoBufLen = sizeof( DNS_SEARCH_INFORMATION ) -
|
||
|
sizeof( LPSTR ) +
|
||
|
( sizeof( LPSTR ) *
|
||
|
cNameCount );
|
||
|
|
||
|
if ( ( cNameCount == 0 ) && ( ! pszName ) )
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
pSearchInfo =
|
||
|
(PDNS_SEARCH_INFORMATION) ALLOCATE_HEAP_ZERO( dwSearchInfoBufLen );
|
||
|
|
||
|
if ( ! pSearchInfo )
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if ( pszName )
|
||
|
{
|
||
|
pSearchInfo->pszPrimaryDomainName = Dns_NameCopyAllocate(
|
||
|
pszName,
|
||
|
0,
|
||
|
DnsCharSetUtf8,
|
||
|
DnsCharSetUtf8 );
|
||
|
|
||
|
if ( ! pSearchInfo->pszPrimaryDomainName )
|
||
|
{
|
||
|
FREE_HEAP( pSearchInfo );
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return pSearchInfo;
|
||
|
}
|
||
|
|
||
|
|
||
|
PDNS_SEARCH_INFORMATION
|
||
|
CreateSearchInformationCopyFromList(
|
||
|
IN PSEARCH_LIST pSearchList
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
None.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
None.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PDNS_SEARCH_INFORMATION pSearchInformation;
|
||
|
DWORD iter;
|
||
|
|
||
|
if ( ! pSearchList )
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
pSearchInformation = CreateSearchInformation(
|
||
|
pSearchList->NameCount,
|
||
|
pSearchList->pszDomainOrZoneName );
|
||
|
if ( ! pSearchInformation )
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
for ( iter = 0; iter < pSearchList->NameCount; iter++ )
|
||
|
{
|
||
|
if ( pSearchList->SearchNameArray[iter].pszName )
|
||
|
{
|
||
|
pSearchInformation->aSearchListNames[iter] =
|
||
|
Dns_NameCopyAllocate(
|
||
|
pSearchList->SearchNameArray[iter].pszName,
|
||
|
0,
|
||
|
DnsCharSetUtf8,
|
||
|
DnsCharSetUtf8 );
|
||
|
}
|
||
|
|
||
|
if ( pSearchInformation->aSearchListNames[iter] )
|
||
|
{
|
||
|
pSearchInformation->cNameCount++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return pSearchInformation;
|
||
|
}
|
||
|
|
||
|
|
||
|
PDNS_ADAPTER_INFORMATION
|
||
|
CreateAdapterInformation(
|
||
|
IN DWORD cServerCount,
|
||
|
IN DWORD dwFlags,
|
||
|
IN LPSTR pszDomain,
|
||
|
IN LPSTR pszGuidName
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
None.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
None.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PDNS_ADAPTER_INFORMATION pAdapter = NULL;
|
||
|
DWORD dwAdapterInfoBufLen = sizeof( DNS_ADAPTER_INFORMATION ) -
|
||
|
sizeof( DNS_SERVER_INFORMATION ) +
|
||
|
( sizeof( DNS_SERVER_INFORMATION ) *
|
||
|
cServerCount );
|
||
|
|
||
|
pAdapter = (PDNS_ADAPTER_INFORMATION)
|
||
|
ALLOCATE_HEAP_ZERO( dwAdapterInfoBufLen );
|
||
|
if ( ! pAdapter )
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
pAdapter->InfoFlags = dwFlags;
|
||
|
pAdapter->cServerCount = 0;
|
||
|
if ( pszDomain )
|
||
|
{
|
||
|
pAdapter->pszDomain = Dns_NameCopyAllocate(
|
||
|
pszDomain,
|
||
|
0,
|
||
|
DnsCharSetUtf8,
|
||
|
DnsCharSetUtf8 );
|
||
|
}
|
||
|
|
||
|
if ( pszGuidName )
|
||
|
{
|
||
|
pAdapter->pszAdapterGuidName = Dns_NameCopyAllocate(
|
||
|
pszGuidName,
|
||
|
0,
|
||
|
DnsCharSetUtf8,
|
||
|
DnsCharSetUtf8 );
|
||
|
}
|
||
|
|
||
|
return pAdapter;
|
||
|
}
|
||
|
|
||
|
|
||
|
PDNS_ADAPTER_INFORMATION
|
||
|
CreateAdapterInformationCopyFromList(
|
||
|
IN PDNS_ADAPTER pAdapter
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
None.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
None.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PDNS_ADAPTER_INFORMATION pAdapterInformation;
|
||
|
DWORD iter;
|
||
|
|
||
|
if ( ! pAdapter )
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
pAdapterInformation = CreateAdapterInformation(
|
||
|
pAdapter->ServerCount,
|
||
|
pAdapter->InfoFlags,
|
||
|
pAdapter->pszAdapterDomain,
|
||
|
pAdapter->pszAdapterGuidName );
|
||
|
if ( ! pAdapterInformation )
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
pAdapterInformation->pIPAddresses =
|
||
|
Dns_CreateIpArrayCopy( pAdapter->pAdapterIPAddresses );
|
||
|
|
||
|
pAdapterInformation->pIPSubnetMasks =
|
||
|
Dns_CreateIpArrayCopy( pAdapter->pAdapterIPSubnetMasks );
|
||
|
|
||
|
for ( iter = 0; iter < pAdapter->ServerCount; iter++ )
|
||
|
{
|
||
|
pAdapterInformation->aipServers[iter].ipAddress =
|
||
|
pAdapter->ServerArray[iter].IpAddress;
|
||
|
pAdapterInformation->aipServers[iter].Priority =
|
||
|
pAdapter->ServerArray[iter].Priority;
|
||
|
}
|
||
|
|
||
|
pAdapterInformation->cServerCount = pAdapter->ServerCount;
|
||
|
|
||
|
return pAdapterInformation ;
|
||
|
}
|
||
|
|
||
|
|
||
|
PDNS_NETWORK_INFORMATION
|
||
|
WINAPI
|
||
|
GetNetworkInformation(
|
||
|
VOID )
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
None.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
None.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PDNS_NETINFO pNetInfo = GetNetworkInfo();
|
||
|
DWORD iter;
|
||
|
PDNS_NETWORK_INFORMATION pNetworkInformation = NULL;
|
||
|
|
||
|
if ( !pNetInfo )
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// create Network Information of desired size
|
||
|
// then copy entire structure
|
||
|
//
|
||
|
|
||
|
pNetworkInformation = CreateNetworkInformation( pNetInfo->AdapterCount );
|
||
|
if ( ! pNetworkInformation )
|
||
|
{
|
||
|
goto Done;
|
||
|
}
|
||
|
|
||
|
pNetworkInformation->pSearchInformation =
|
||
|
CreateSearchInformationCopyFromList( pNetInfo->pSearchList );
|
||
|
|
||
|
for ( iter = 0; iter < pNetInfo->AdapterCount; iter++ )
|
||
|
{
|
||
|
pNetworkInformation->aAdapterInfoList[iter] =
|
||
|
CreateAdapterInformationCopyFromList( pNetInfo->AdapterArray[iter] );
|
||
|
|
||
|
if ( pNetworkInformation->aAdapterInfoList[iter] )
|
||
|
{
|
||
|
pNetworkInformation->cAdapterCount += 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Done:
|
||
|
|
||
|
NetInfo_Free( pNetInfo );
|
||
|
|
||
|
return pNetworkInformation;
|
||
|
}
|
||
|
|
||
|
|
||
|
PDNS_SEARCH_INFORMATION
|
||
|
WINAPI
|
||
|
GetSearchInformation(
|
||
|
VOID )
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
None.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
None.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
PDNS_NETINFO pNetInfo = GetNetworkInfo();
|
||
|
PDNS_SEARCH_INFORMATION pSearchInformation = NULL;
|
||
|
|
||
|
if ( !pNetInfo )
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
pSearchInformation = CreateSearchInformationCopyFromList(
|
||
|
pNetInfo->pSearchList );
|
||
|
|
||
|
NetInfo_Free( pNetInfo );
|
||
|
|
||
|
return pSearchInformation;
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
WINAPI
|
||
|
FreeAdapterInformation(
|
||
|
IN PDNS_ADAPTER_INFORMATION pAdapterInformation
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
None.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
None.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
if ( pAdapterInformation )
|
||
|
{
|
||
|
if ( pAdapterInformation->pszAdapterGuidName )
|
||
|
{
|
||
|
FREE_HEAP( pAdapterInformation->pszAdapterGuidName );
|
||
|
}
|
||
|
|
||
|
if ( pAdapterInformation->pszDomain )
|
||
|
{
|
||
|
FREE_HEAP( pAdapterInformation->pszDomain );
|
||
|
}
|
||
|
|
||
|
if ( pAdapterInformation->pIPAddresses )
|
||
|
{
|
||
|
FREE_HEAP( pAdapterInformation->pIPAddresses );
|
||
|
}
|
||
|
|
||
|
if ( pAdapterInformation->pIPSubnetMasks )
|
||
|
{
|
||
|
FREE_HEAP( pAdapterInformation->pIPSubnetMasks );
|
||
|
}
|
||
|
|
||
|
FREE_HEAP( pAdapterInformation );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
WINAPI
|
||
|
FreeSearchInformation(
|
||
|
IN PDNS_SEARCH_INFORMATION pSearchInformation
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
None.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
None.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
DWORD iter;
|
||
|
|
||
|
if ( pSearchInformation )
|
||
|
{
|
||
|
if ( pSearchInformation->pszPrimaryDomainName )
|
||
|
{
|
||
|
FREE_HEAP( pSearchInformation->pszPrimaryDomainName );
|
||
|
}
|
||
|
|
||
|
for ( iter = 0; iter < pSearchInformation->cNameCount; iter++ )
|
||
|
{
|
||
|
if ( pSearchInformation->aSearchListNames[iter] )
|
||
|
{
|
||
|
FREE_HEAP( pSearchInformation->aSearchListNames[iter] );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
FREE_HEAP( pSearchInformation );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
WINAPI
|
||
|
FreeNetworkInformation(
|
||
|
IN PDNS_NETWORK_INFORMATION pNetworkInformation
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
None.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
None.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
DWORD iter;
|
||
|
|
||
|
if ( pNetworkInformation )
|
||
|
{
|
||
|
FreeSearchInformation( pNetworkInformation->pSearchInformation );
|
||
|
|
||
|
for ( iter = 0; iter < pNetworkInformation->cAdapterCount; iter++ )
|
||
|
{
|
||
|
FreeAdapterInformation( pNetworkInformation ->
|
||
|
aAdapterInfoList[iter] );
|
||
|
}
|
||
|
|
||
|
FREE_HEAP( pNetworkInformation );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Net failure caching
|
||
|
//
|
||
|
|
||
|
BOOL
|
||
|
IsKnownNetFailure(
|
||
|
VOID
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
None.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
None.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
BOOL flag = FALSE;
|
||
|
|
||
|
DNSDBG( TRACE, ( "IsKnownNetFailure()\n" ));
|
||
|
|
||
|
EnterCriticalSection( &g_NetFailureCS );
|
||
|
|
||
|
if ( g_NetFailureStatus )
|
||
|
{
|
||
|
if ( g_NetFailureTime < Dns_GetCurrentTimeInSeconds() )
|
||
|
{
|
||
|
g_NetFailureTime = 0;
|
||
|
g_NetFailureStatus = ERROR_SUCCESS;
|
||
|
flag = FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SetLastError( g_NetFailureStatus );
|
||
|
flag = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LeaveCriticalSection( &g_NetFailureCS );
|
||
|
|
||
|
return flag;
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
SetKnownNetFailure(
|
||
|
IN DNS_STATUS Status
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
None.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
None.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
None.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
DNSDBG( TRACE, ( "SetKnownNetFailure()\n" ));
|
||
|
|
||
|
EnterCriticalSection( &g_NetFailureCS );
|
||
|
|
||
|
g_NetFailureTime = Dns_GetCurrentTimeInSeconds() +
|
||
|
DNS_NET_FAILURE_CACHE_TIME;
|
||
|
g_NetFailureStatus = Status;
|
||
|
|
||
|
LeaveCriticalSection( &g_NetFailureCS );
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
WINAPI
|
||
|
DnsGetCacheDataTable(
|
||
|
OUT PDNS_CACHE_TABLE * ppTable
|
||
|
)
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Get cache data table.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
ppTable -- address to receive ptr to cache data table
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
ERROR_SUCCES if successful.
|
||
|
Error code on failure.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
DNS_STATUS status = ERROR_SUCCESS;
|
||
|
DWORD rpcStatus = ERROR_SUCCESS;
|
||
|
PDNS_RPC_CACHE_TABLE pcacheTable = NULL;
|
||
|
|
||
|
DNSDBG( TRACE, ( "DnsGetCacheDataTable()\n" ));
|
||
|
|
||
|
if ( ! ppTable )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
#if DNSBUILDOLD
|
||
|
if ( g_IsWin9X )
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
RpcTryExcept
|
||
|
{
|
||
|
status = CRrReadCache( NULL, &pcacheTable );
|
||
|
}
|
||
|
RpcExcept( DNS_RPC_EXCEPTION_FILTER )
|
||
|
{
|
||
|
status = RpcExceptionCode();
|
||
|
}
|
||
|
RpcEndExcept
|
||
|
|
||
|
// set out param
|
||
|
|
||
|
*ppTable = (PDNS_CACHE_TABLE) pcacheTable;
|
||
|
|
||
|
#if DBG
|
||
|
if ( status != ERROR_SUCCESS )
|
||
|
{
|
||
|
DNSDBG( RPC, (
|
||
|
"DnsGetCacheDataTable() status = %d\n",
|
||
|
status ));
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
return( pcacheTable && status == ERROR_SUCCESS );
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
IsLocalIpAddress(
|
||
|
IN IP_ADDRESS IpAddress
|
||
|
)
|
||
|
|
||
|
//
|
||
|
// DCR_FIX: this has no customers other than debug code in update.c
|
||
|
//
|
||
|
// If wanted this API it should be remoteable -- we could avoid alloc
|
||
|
// and include IP6
|
||
|
//
|
||
|
|
||
|
{
|
||
|
BOOL bfound = FALSE;
|
||
|
PIP_ARRAY ipList = Dns_GetLocalIpAddressArray();
|
||
|
DWORD iter;
|
||
|
|
||
|
if ( !ipList )
|
||
|
{
|
||
|
return bfound;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// check if IpAddress is in local list
|
||
|
//
|
||
|
|
||
|
for ( iter = 0; iter < ipList->AddrCount; iter++ )
|
||
|
{
|
||
|
if ( IpAddress == ipList->AddrArray[iter] )
|
||
|
{
|
||
|
bfound = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
FREE_HEAP( ipList );
|
||
|
|
||
|
return bfound;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// End dnsapi.c
|
||
|
//
|