2130 lines
49 KiB
C
2130 lines
49 KiB
C
/*++
|
||
|
||
Copyright (c) 1997-2001 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
faz.c
|
||
|
||
Abstract:
|
||
|
||
Domain Name System (DNS) API
|
||
|
||
Find Authoritative Zone (FAZ) routines
|
||
|
||
Author:
|
||
|
||
Jim Gilroy (jamesg) January, 1997
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
|
||
#include "local.h"
|
||
|
||
|
||
|
||
//
|
||
// Max number of server's we'll ever bother to extract from packet
|
||
// (much more and you're out of UDP packet space anyway)
|
||
//
|
||
|
||
#define MAX_NAME_SERVER_COUNT (20)
|
||
|
||
|
||
|
||
|
||
#if 1
|
||
//
|
||
// Original FAZ routines -- now obsolete
|
||
//
|
||
|
||
PDNS_NETINFO
|
||
Dns_BuildUpdateNetworkInfoFromFAZ(
|
||
IN LPSTR pszZone,
|
||
IN LPSTR pszPrimaryDns,
|
||
IN PDNS_RECORD pRecord
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Build new DNS network info from record list.
|
||
|
||
Arguments:
|
||
|
||
paipServers -- addr to receive ptr to zone's DNS server list
|
||
|
||
pRR - incoming RR set
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
Error code on failure.
|
||
|
||
--*/
|
||
{
|
||
INT countIp = 0;
|
||
IP_ADDRESS arrayIp[ MAX_NAME_SERVER_COUNT + 1];
|
||
PIP_ARRAY piparray = (PIP_ARRAY)arrayIp;
|
||
BOOL fmatch = FALSE;
|
||
|
||
DNS_ASSERT( &piparray->AddrCount == &arrayIp[0] );
|
||
|
||
//
|
||
// DNS hostname unknown, extract from SOA or NS records
|
||
//
|
||
|
||
if ( !pszPrimaryDns )
|
||
{
|
||
return( NULL );
|
||
}
|
||
|
||
//
|
||
// find IP addresses of primary DNS server
|
||
// - skip first entry, so array can mimic PIP_ARRAY structure
|
||
//
|
||
|
||
while ( pRecord )
|
||
{
|
||
// if not A record
|
||
// - we're done if already read records, otherwise continue
|
||
|
||
if ( pRecord->wType != DNS_TYPE_A )
|
||
{
|
||
if ( countIp != 0 )
|
||
{
|
||
break;
|
||
}
|
||
fmatch = FALSE;
|
||
pRecord = pRecord->pNext;
|
||
continue;
|
||
}
|
||
|
||
// if record has name, check it
|
||
// otherwise match is the same as previous record
|
||
|
||
if ( pRecord->pName )
|
||
{
|
||
fmatch = Dns_NameCompare_UTF8(
|
||
pRecord->pName,
|
||
pszPrimaryDns );
|
||
}
|
||
if ( fmatch )
|
||
{
|
||
arrayIp[ ++countIp ] = pRecord->Data.A.IpAddress;
|
||
}
|
||
pRecord = pRecord->pNext;
|
||
continue;
|
||
}
|
||
|
||
if ( countIp == 0 )
|
||
{
|
||
return( NULL );
|
||
}
|
||
piparray->AddrCount = countIp;
|
||
|
||
//
|
||
// convert into UPDATE adapter list
|
||
//
|
||
|
||
return NetInfo_CreateForUpdate(
|
||
pszZone,
|
||
pszPrimaryDns,
|
||
piparray,
|
||
0 );
|
||
}
|
||
|
||
|
||
|
||
DNS_STATUS
|
||
Dns_FindAuthoritativeZoneLib(
|
||
IN PDNS_NAME pszName,
|
||
IN DWORD dwFlags,
|
||
IN PIP_ARRAY aipQueryServers,
|
||
OUT PDNS_NETINFO * ppNetworkInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Find name of authoritative zone.
|
||
|
||
Result of FAZ:
|
||
- zone name
|
||
- primary DNS server name
|
||
- primary DNS IP list
|
||
|
||
Arguments:
|
||
|
||
pszName -- name to find authoritative zone for
|
||
Unicode string if dwFlags has DNSQUERY_UNICODE_NAME set.
|
||
ANSI string otherwise.
|
||
|
||
dwFlags -- flags to use for DnsQuery
|
||
|
||
aipQueryServers -- servers to query, defaults used if NULL
|
||
|
||
ppNetworkInfo -- ptr to network info built for FAZ
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
Error code on failure.
|
||
|
||
--*/
|
||
{
|
||
DNS_STATUS status;
|
||
PDNS_RECORD precord = NULL;
|
||
PDNS_RECORD precordPrimary = NULL;
|
||
LPSTR pszdnsHost = NULL;
|
||
PDNS_NETINFO pNetworkInfo = NULL;
|
||
|
||
DNSDBG( QUERY, (
|
||
"Dns_FindAuthoritativeZoneLib()\n"
|
||
"\tname %s\n"
|
||
"\tflags %08x\n",
|
||
pszName,
|
||
dwFlags ));
|
||
|
||
//
|
||
// query until find name with SOA record -- the zone root
|
||
//
|
||
// note, MUST check that actually get SOA record
|
||
// - servers may return referral
|
||
// - lame server might return CNAME to name
|
||
//
|
||
|
||
while ( pszName )
|
||
{
|
||
if ( precord )
|
||
{
|
||
Dns_RecordListFree( precord );
|
||
precord = NULL;
|
||
}
|
||
|
||
status = QueryDirectEx(
|
||
NULL, // no return message buffer
|
||
& precord,
|
||
NULL, // no header
|
||
0, // no header counts
|
||
(LPSTR) pszName,
|
||
DNS_TYPE_SOA,
|
||
NULL, // no input records
|
||
dwFlags,
|
||
aipQueryServers,
|
||
NULL // no network info
|
||
);
|
||
|
||
if ( status == ERROR_SUCCESS ||
|
||
status == DNS_ERROR_RCODE_NAME_ERROR ||
|
||
status == DNS_INFO_NO_RECORDS )
|
||
{
|
||
if ( precord && precord->wType == DNS_TYPE_SOA )
|
||
{
|
||
// received SOA
|
||
// devolve name to zone name
|
||
|
||
DNSDBG( QUERY, (
|
||
"FAZ found SOA (section %d) at zone %s\n",
|
||
precord->Flags.S.Section,
|
||
precord->pName ));
|
||
|
||
while( pszName &&
|
||
! Dns_NameCompare_UTF8( pszName, precord->pName ) )
|
||
{
|
||
pszName = Dns_GetDomainName( pszName );
|
||
}
|
||
break;
|
||
}
|
||
|
||
// this could be because server no-recurse or
|
||
// bum server (BIND) that CNAMEs even when type=SOA
|
||
// drop down to devolve name and continue
|
||
|
||
DNSDBG( ANY, (
|
||
"ERROR: response from FAZ query with no SOA records.\n" ));
|
||
}
|
||
|
||
//
|
||
// other errors besides
|
||
// - name error
|
||
// - no records
|
||
// indicate terminal problem
|
||
//
|
||
|
||
else
|
||
{
|
||
DNS_ASSERT( precord == NULL );
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// name error or empty response, continue with next higher domain
|
||
//
|
||
|
||
pszName = Dns_GetDomainName( pszName );
|
||
}
|
||
|
||
//
|
||
// if reached root, we're dead
|
||
//
|
||
|
||
if ( !pszName )
|
||
{
|
||
if ( status == ERROR_SUCCESS )
|
||
{
|
||
DNS_ASSERT( FALSE );
|
||
status = DNS_ERROR_RCODE_SERVER_FAILURE;
|
||
}
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// have SOA record
|
||
//
|
||
// if primary server A record in the packet, use it
|
||
// otherwise query for primary DNS A record
|
||
//
|
||
|
||
DNS_ASSERT( precord->wType == DNS_TYPE_SOA );
|
||
DNS_ASSERT( status == ERROR_SUCCESS );
|
||
|
||
pszdnsHost = (LPSTR) precord->Data.SOA.pNamePrimaryServer;
|
||
|
||
pNetworkInfo = Dns_BuildUpdateNetworkInfoFromFAZ(
|
||
pszName,
|
||
pszdnsHost,
|
||
precord );
|
||
if ( !pNetworkInfo )
|
||
{
|
||
status = QueryDirectEx(
|
||
NULL, // no return message buffer
|
||
& precordPrimary,
|
||
NULL, // no header
|
||
0, // no header counts
|
||
pszdnsHost,
|
||
DNS_TYPE_A,
|
||
NULL, // no input records
|
||
dwFlags,
|
||
aipQueryServers,
|
||
NULL // no network info
|
||
);
|
||
|
||
if ( status != ERROR_SUCCESS || precordPrimary == NULL )
|
||
{
|
||
DNS_PRINT(( "ERROR: no response to primary A query\n" ));
|
||
TEST_ASSERT( FALSE );
|
||
status = DNS_ERROR_RCODE_SERVER_FAILURE;
|
||
goto Cleanup;
|
||
}
|
||
pNetworkInfo = Dns_BuildUpdateNetworkInfoFromFAZ(
|
||
pszName,
|
||
pszdnsHost,
|
||
precordPrimary );
|
||
if ( !pNetworkInfo )
|
||
{
|
||
status = DNS_ERROR_RCODE_SERVER_FAILURE;
|
||
}
|
||
}
|
||
|
||
Cleanup:
|
||
|
||
if ( precord )
|
||
{
|
||
Dns_RecordListFree( precord );
|
||
}
|
||
if ( precordPrimary )
|
||
{
|
||
Dns_RecordListFree( precordPrimary );
|
||
}
|
||
|
||
*ppNetworkInfo = pNetworkInfo;
|
||
|
||
IF_DNSDBG( QUERY )
|
||
{
|
||
DNS_PRINT((
|
||
"Leaving Dns_FindAuthoritativeZoneLib()\n"
|
||
"\tstatus = %d\n"
|
||
"\tzone = %s\n",
|
||
status,
|
||
pszName ));
|
||
}
|
||
|
||
return( status );
|
||
}
|
||
#endif
|
||
|
||
|
||
|
||
//
|
||
// Private utilities
|
||
//
|
||
|
||
PDNS_NETINFO
|
||
buildUpdateNetworkInfoFromFAZ(
|
||
IN LPSTR pszZone,
|
||
IN LPSTR pszPrimaryDns,
|
||
IN PDNS_RECORD pRecord
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Build new DNS server list from record list.
|
||
|
||
Arguments:
|
||
|
||
pszZone -- zone name
|
||
|
||
pszPrimaryDns -- DNS server name
|
||
|
||
pRecord -- record list from FAZ or other lookup that contain DNS server
|
||
host records
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
Error code on failure.
|
||
|
||
--*/
|
||
{
|
||
INT countIp = 0;
|
||
IP_ADDRESS arrayIp[ MAX_NAME_SERVER_COUNT + 1];
|
||
PIP_ARRAY piparray = (PIP_ARRAY)arrayIp;
|
||
BOOL fmatch = FALSE;
|
||
|
||
DNS_ASSERT( &piparray->AddrCount == &arrayIp[0] );
|
||
|
||
DNSDBG( TRACE, (
|
||
"buildUpdateNetworkInfoFromFAZ( %s )\n",
|
||
pszZone ));
|
||
|
||
//
|
||
// DNS hostname unknown, extract from SOA or NS records
|
||
//
|
||
|
||
if ( !pszPrimaryDns )
|
||
{
|
||
return( NULL );
|
||
}
|
||
|
||
//
|
||
// find IP addresses of primary DNS server
|
||
// - skip first entry, so array can mimic PIP_ARRAY structure
|
||
//
|
||
|
||
while ( pRecord )
|
||
{
|
||
// if not A record
|
||
// - we're done if already read records, otherwise continue
|
||
|
||
if ( pRecord->wType != DNS_TYPE_A )
|
||
{
|
||
if ( countIp != 0 )
|
||
{
|
||
break;
|
||
}
|
||
fmatch = FALSE;
|
||
pRecord = pRecord->pNext;
|
||
continue;
|
||
}
|
||
|
||
// if record has name, check it
|
||
// otherwise match is the same as previous record
|
||
|
||
if ( pRecord->pName )
|
||
{
|
||
fmatch = Dns_NameCompare_UTF8(
|
||
pRecord->pName,
|
||
pszPrimaryDns );
|
||
}
|
||
if ( fmatch &&
|
||
countIp < MAX_NAME_SERVER_COUNT )
|
||
{
|
||
arrayIp[ ++countIp ] = pRecord->Data.A.IpAddress;
|
||
}
|
||
pRecord = pRecord->pNext;
|
||
continue;
|
||
}
|
||
|
||
if ( countIp == 0 )
|
||
{
|
||
return( NULL );
|
||
}
|
||
piparray->AddrCount = countIp;
|
||
|
||
//
|
||
// convert into UPDATE adapter list
|
||
//
|
||
|
||
return NetInfo_CreateForUpdate(
|
||
pszZone,
|
||
pszPrimaryDns,
|
||
piparray,
|
||
0 );
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
ValidateZoneNameForUpdate(
|
||
IN PSTR pszZone
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Check if zone is valid for update.
|
||
|
||
Arguments:
|
||
|
||
pszZone -- zone name
|
||
|
||
Return Value:
|
||
|
||
TRUE -- zone is valid for update
|
||
FALSE -- zone is invalid, should NOT send update to this zone
|
||
|
||
--*/
|
||
{
|
||
PSTR pzoneExclusions = NULL;
|
||
PSTR pch;
|
||
PSTR pnext;
|
||
DNS_STATUS status;
|
||
DWORD length;
|
||
BOOL returnVal = TRUE;
|
||
DWORD labelCount;
|
||
|
||
DNSDBG( TRACE, (
|
||
"ValidateZoneNameForUpdate( %s )\n",
|
||
pszZone ));
|
||
|
||
//
|
||
// never update the root
|
||
//
|
||
|
||
if ( !pszZone || *pszZone=='.' )
|
||
{
|
||
return( FALSE );
|
||
}
|
||
|
||
//
|
||
// never update TLD
|
||
// - except config override in case someone
|
||
// gave themselves a single label domain name
|
||
//
|
||
|
||
if ( g_UpdateTopLevelDomains )
|
||
{
|
||
return( TRUE );
|
||
}
|
||
|
||
labelCount = Dns_NameLabelCount( pszZone );
|
||
|
||
if ( labelCount > 2 )
|
||
{
|
||
return( TRUE );
|
||
}
|
||
if ( labelCount < 2 )
|
||
{
|
||
return( FALSE );
|
||
}
|
||
|
||
//
|
||
// screen out
|
||
// - "in-addr.arpa"
|
||
// - "ip6.int"
|
||
//
|
||
|
||
if ( Dns_NameCompare_UTF8(
|
||
"in-addr.arpa",
|
||
pszZone ) )
|
||
{
|
||
return( FALSE );
|
||
}
|
||
if ( Dns_NameCompare_UTF8(
|
||
"ip6.int",
|
||
pszZone ) )
|
||
{
|
||
return( FALSE );
|
||
}
|
||
|
||
return( TRUE );
|
||
|
||
#if 0
|
||
//
|
||
// DCR: "update zone allowed" list?
|
||
//
|
||
// note: this is complicated as need to test
|
||
// SECOND label because tough cases are
|
||
// "co.uk" -- difficult to test first label
|
||
//
|
||
|
||
//
|
||
// read exclusion list from registry
|
||
//
|
||
|
||
status = DnsRegGetValueEx(
|
||
NULL, // no session
|
||
NULL, // no adapter
|
||
NULL, // no adapter name
|
||
DnsRegUpdateZoneExclusions,
|
||
REGTYPE_UPDATE_ZONE_EXCLUSIONS,
|
||
DNSREG_FLAG_DUMP_EMPTY, // dump empty string
|
||
(PBYTE *) &pzoneExclusions
|
||
);
|
||
|
||
if ( status != ERROR_SUCCESS ||
|
||
!pzoneExclusions )
|
||
{
|
||
ASSERT( pzoneExclusions == NULL );
|
||
return( TRUE );
|
||
}
|
||
|
||
//
|
||
// check all exclusion zones
|
||
//
|
||
// note: UTF8 compare mediocre perfwise
|
||
// if critically would keep exclusions in
|
||
// cannonical form so don't go to unicode
|
||
// for case-insensitive compare
|
||
//
|
||
|
||
pch = pzoneExclusions;
|
||
|
||
while ( 1 )
|
||
{
|
||
// check for termination
|
||
// or find next string
|
||
|
||
length = strlen( pch );
|
||
if ( length == 0 )
|
||
{
|
||
break;
|
||
}
|
||
pnext = pch + length + 1;
|
||
|
||
//
|
||
// check this string
|
||
//
|
||
|
||
DNSDBG( TRACE, (
|
||
"Update zone compare to %s\n",
|
||
pch ));
|
||
|
||
if ( Dns_NameCompare_UTF8(
|
||
pch,
|
||
pszZone ) )
|
||
{
|
||
returnVal = FALSE;
|
||
break;
|
||
}
|
||
|
||
pch = pnext;
|
||
}
|
||
|
||
// if no match, zone is valid
|
||
|
||
FREE_HEAP( pzoneExclusions );
|
||
|
||
return( returnVal );
|
||
#endif
|
||
}
|
||
|
||
|
||
|
||
DNS_STATUS
|
||
DnsFindAuthoritativeZone(
|
||
IN PDNS_NAME pszName,
|
||
IN DWORD dwFlags,
|
||
IN PIP_ARRAY aipQueryServers,
|
||
OUT PDNS_NETINFO * ppNetworkInfo
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Find name of authoritative zone.
|
||
|
||
Result of FAZ:
|
||
- zone name
|
||
- primary DNS server name
|
||
- primary DNS IP list
|
||
|
||
Arguments:
|
||
|
||
pszName -- name to find authoritative zone for
|
||
|
||
dwFlags -- flags to use for DnsQuery
|
||
|
||
aipQueryServers -- servers to query, defaults used if NULL
|
||
|
||
ppNetworkInfo -- ptr to adapter list built for FAZ
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
Error code on failure.
|
||
|
||
--*/
|
||
{
|
||
DNS_STATUS status;
|
||
PDNS_RECORD precord = NULL;
|
||
PDNS_RECORD precordPrimary = NULL;
|
||
PDNS_RECORD precordSOA = NULL;
|
||
LPSTR pszdnsHost = NULL;
|
||
PDNS_NETINFO pnetInfo = NULL;
|
||
PSTR pzoneName;
|
||
|
||
DNSDBG( QUERY, (
|
||
"DnsFindAuthoritativeZone()\n"
|
||
"\tname %s\n"
|
||
"\tflags %08x\n",
|
||
pszName,
|
||
dwFlags ));
|
||
|
||
//
|
||
// query until find name with SOA record -- the zone root
|
||
//
|
||
// note, MUST check that actually get SOA record
|
||
// - servers may return referral
|
||
// - lame server might return CNAME to name
|
||
//
|
||
|
||
pzoneName = pszName;
|
||
|
||
while ( pzoneName )
|
||
{
|
||
if ( precord )
|
||
{
|
||
Dns_RecordListFree( precord );
|
||
precord = NULL;
|
||
}
|
||
|
||
status = DnsQuery_UTF8(
|
||
(LPSTR) pzoneName,
|
||
DNS_TYPE_SOA,
|
||
dwFlags |
|
||
DNS_QUERY_TREAT_AS_FQDN |
|
||
DNS_QUERY_ALLOW_EMPTY_AUTH_RESP,
|
||
aipQueryServers,
|
||
& precord,
|
||
NULL );
|
||
|
||
//
|
||
// find SOA and possibly primary name A
|
||
//
|
||
// test for ERROR_SUCCESS, AUTH_EMPTY or NAME_ERROR
|
||
// in all cases first record should be SOA
|
||
// ERROR_SUCCESS -- answer section
|
||
// NAME_ERROR or AUTH_EMPTY -- authority section
|
||
// all MAY also have additional record for SOA primary server
|
||
//
|
||
|
||
if ( status == ERROR_SUCCESS ||
|
||
status == DNS_INFO_NO_RECORDS ||
|
||
status == DNS_ERROR_RCODE_NAME_ERROR )
|
||
{
|
||
if ( precord && precord->wType == DNS_TYPE_SOA )
|
||
{
|
||
// received SOA
|
||
// devolve name to zone name
|
||
|
||
DNSDBG( QUERY, (
|
||
"FAZ found SOA (section %d) at zone %s\n",
|
||
precord->Flags.S.Section,
|
||
precord->pName ));
|
||
|
||
while( pzoneName &&
|
||
! Dns_NameCompare_UTF8( pzoneName, precord->pName ) )
|
||
{
|
||
pzoneName = DnsGetDomainName( pzoneName );
|
||
}
|
||
precordSOA = precord;
|
||
status = ERROR_SUCCESS;
|
||
break;
|
||
}
|
||
// this could be because server no-recurse or
|
||
// bum server (BIND) that CNAMEs even when type=SOA
|
||
// drop down to devolve name and continue
|
||
|
||
DNSDBG( ANY, (
|
||
"ERROR: response from FAZ query with no SOA records.\n" ));
|
||
}
|
||
|
||
//
|
||
// other errors besides
|
||
// - name error
|
||
// - no records
|
||
// indicate terminal problem
|
||
//
|
||
|
||
else
|
||
{
|
||
DNS_ASSERT( precord == NULL );
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// name error or empty response, continue with next higher domain
|
||
//
|
||
|
||
pzoneName = DnsGetDomainName( pzoneName );
|
||
}
|
||
|
||
//
|
||
// if reached root or TLD -- no update
|
||
// - note currently returning SERVFAIL because of
|
||
// screwy netlogon logic
|
||
//
|
||
|
||
if ( !ValidateZoneNameForUpdate(pzoneName) )
|
||
{
|
||
//status = DNS_ERROR_INVALID_ZONE_OPERATION;
|
||
status = DNS_ERROR_RCODE_SERVER_FAILURE;
|
||
//status = DNS_ERROR_RCODE_REFUSED;
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// have SOA record
|
||
//
|
||
// if primary server A record in the packet, use it
|
||
// otherwise query for primary DNS A record
|
||
//
|
||
|
||
DNS_ASSERT( precordSOA );
|
||
DNS_ASSERT( status == ERROR_SUCCESS );
|
||
|
||
pszdnsHost = (LPSTR) precordSOA->Data.SOA.pNamePrimaryServer;
|
||
|
||
//
|
||
// check additional for primary A record
|
||
// if found, build network info blob for update
|
||
// that points only to update server
|
||
//
|
||
|
||
pnetInfo = buildUpdateNetworkInfoFromFAZ(
|
||
pzoneName,
|
||
pszdnsHost,
|
||
precordSOA );
|
||
|
||
|
||
//
|
||
// if no primary server A record found -- must query
|
||
//
|
||
|
||
if ( !pnetInfo )
|
||
{
|
||
DNSDBG( QUERY, (
|
||
"WARNING: FAZ making additional query for primary!\n"
|
||
"\tPrimary (%s) A record should have been in additional section!\n",
|
||
pszdnsHost ));
|
||
|
||
status = DnsQuery_UTF8(
|
||
pszdnsHost,
|
||
DNS_TYPE_A,
|
||
dwFlags |
|
||
DNS_QUERY_TREAT_AS_FQDN |
|
||
DNS_QUERY_ALLOW_EMPTY_AUTH_RESP,
|
||
aipQueryServers,
|
||
& precordPrimary,
|
||
NULL );
|
||
|
||
if ( status != ERROR_SUCCESS || precordPrimary == NULL )
|
||
{
|
||
DNS_PRINT(( "ERROR: no response to primary A query\n" ));
|
||
TEST_ASSERT( FALSE );
|
||
status = DNS_ERROR_RCODE_SERVER_FAILURE;
|
||
goto Cleanup;
|
||
}
|
||
pnetInfo = buildUpdateNetworkInfoFromFAZ(
|
||
pzoneName,
|
||
pszdnsHost,
|
||
precordPrimary );
|
||
if ( !pnetInfo )
|
||
{
|
||
status = DNS_ERROR_RCODE_SERVER_FAILURE;
|
||
}
|
||
}
|
||
|
||
Cleanup:
|
||
|
||
Dns_RecordListFree( precord );
|
||
Dns_RecordListFree( precordPrimary );
|
||
|
||
*ppNetworkInfo = pnetInfo;
|
||
|
||
IF_DNSDBG( QUERY )
|
||
{
|
||
DNS_PRINT((
|
||
"Leaving DnsFindAuthoritativeZone()\n"
|
||
"\tstatus = %d\n"
|
||
"\tzone = %s\n",
|
||
status,
|
||
pzoneName ));
|
||
}
|
||
|
||
return( status );
|
||
}
|
||
|
||
|
||
|
||
DNS_STATUS
|
||
DoQuickFAZ(
|
||
OUT PDNS_NETINFO * ppNetworkInfo,
|
||
IN LPSTR pszName,
|
||
IN PIP_ARRAY aipServerList OPTIONAL
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
FAZ to build network info from FAZ result
|
||
|
||
Result of FAZ:
|
||
- zone name
|
||
- primary DNS server name
|
||
- primary DNS IP list
|
||
|
||
This routine is cheap shell around real FAZ to handle
|
||
network failure issue, speeding things in net down
|
||
condition.
|
||
|
||
Arguments:
|
||
|
||
ppNetworkInfo -- addr to recv ptr to network info
|
||
|
||
pszName -- name for update
|
||
|
||
aipServerList -- IP array of DNS servers to contact
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
ErrorCode on failure
|
||
|
||
--*/
|
||
{
|
||
DNS_STATUS status;
|
||
|
||
DNSDBG( TRACE, ( "DoQuickFAZ( %s )\n", pszName ));
|
||
|
||
if ( IsKnownNetFailure() )
|
||
{
|
||
return GetLastError();
|
||
}
|
||
|
||
//
|
||
// call real FAZ
|
||
// - get results as adapter list struct
|
||
//
|
||
|
||
status = DnsFindAuthoritativeZone(
|
||
pszName,
|
||
aipServerList ? DNS_QUERY_BYPASS_CACHE : 0,
|
||
aipServerList,
|
||
ppNetworkInfo // build adapter list from results
|
||
);
|
||
|
||
//
|
||
// if unsuccessful, check if network failure
|
||
//
|
||
|
||
if ( status != ERROR_SUCCESS && !aipServerList )
|
||
{
|
||
if ( status == WSAEFAULT ||
|
||
status == WSAENOTSOCK ||
|
||
status == WSAENETDOWN ||
|
||
status == WSAENETUNREACH ||
|
||
status == WSAEPFNOSUPPORT ||
|
||
status == WSAEAFNOSUPPORT ||
|
||
status == WSAEHOSTDOWN ||
|
||
status == WSAEHOSTUNREACH ||
|
||
status == ERROR_TIMEOUT )
|
||
{
|
||
SetKnownNetFailure( status );
|
||
return status;
|
||
}
|
||
}
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
|
||
//
|
||
// Update network info preparation
|
||
//
|
||
|
||
DWORD
|
||
GetDnsServerListsForUpdate(
|
||
IN OUT PIP_ARRAY * DnsServerListArray,
|
||
IN DWORD ArrayLength,
|
||
IN DWORD Flags
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Get DNS server lists for update.
|
||
|
||
One DNS server list returned for each valid updateable adapter.
|
||
|
||
Arguments:
|
||
|
||
DnsServerListArray -- array to hold DNS server lists found
|
||
|
||
ArrayLength -- length of array
|
||
|
||
Flags -- update flags
|
||
|
||
Return Value:
|
||
|
||
Count of DNS server lists found.
|
||
|
||
--*/
|
||
{
|
||
PDNS_NETINFO pnetInfo;
|
||
DWORD iter1;
|
||
DWORD iter2;
|
||
DWORD countNets = 0;
|
||
|
||
// clear server list array
|
||
|
||
RtlZeroMemory(
|
||
DnsServerListArray,
|
||
sizeof(PIP_ARRAY) * ArrayLength );
|
||
|
||
|
||
// build list from current netinfo
|
||
|
||
pnetInfo = GetNetworkInfo();
|
||
if ( ! pnetInfo )
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
//
|
||
// check if update is disabled
|
||
// - update dependent on registration state
|
||
// - global registration state is OFF
|
||
// => then skip
|
||
//
|
||
|
||
if ( (Flags & DNS_UPDATE_SKIP_NO_UPDATE_ADAPTERS)
|
||
&&
|
||
! g_RegistrationEnabled )
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
//
|
||
// build DNS server list for each updateable adapter
|
||
//
|
||
|
||
for ( iter1 = 0; iter1 < pnetInfo->AdapterCount; iter1++ )
|
||
{
|
||
PDNS_ADAPTER padapter;
|
||
DWORD serverCount;
|
||
PIP_ARRAY pdnsArray;
|
||
|
||
if ( iter1 >= ArrayLength )
|
||
{
|
||
break;
|
||
}
|
||
|
||
padapter = pnetInfo->AdapterArray[iter1];
|
||
if ( !padapter )
|
||
{
|
||
continue;
|
||
}
|
||
|
||
// skip if no DNS servers
|
||
|
||
serverCount = padapter->ServerCount;
|
||
if ( serverCount== 0 )
|
||
{
|
||
continue;
|
||
}
|
||
|
||
// skip "no-update" adapter?
|
||
// - if skip-disabled flag set for this update
|
||
// - and no-update flag on adapter
|
||
|
||
if ( (Flags & DNS_UPDATE_SKIP_NO_UPDATE_ADAPTERS) &&
|
||
!(padapter->InfoFlags & DNS_FLAG_REGISTER_IP_ADDRESSES) )
|
||
{
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// valid update adapter
|
||
// - create\save DNS server list
|
||
// - bump count of lists
|
||
//
|
||
// DCR: functionalize adapter DNS list to IP array
|
||
//
|
||
// DCR_PERF: collapse DNS server lists in netinfo BEFORE allocating them
|
||
// in other words bring this function into collapse and fix
|
||
//
|
||
|
||
pdnsArray = Dns_CreateIpArray( serverCount );
|
||
if ( ! pdnsArray )
|
||
{
|
||
goto Exit;
|
||
}
|
||
|
||
for ( iter2 = 0; iter2 < serverCount; iter2++ )
|
||
{
|
||
pdnsArray->AddrArray[iter2] = padapter->ServerArray[iter2].IpAddress;
|
||
}
|
||
|
||
DnsServerListArray[countNets] = pdnsArray;
|
||
countNets++;
|
||
}
|
||
|
||
Exit:
|
||
|
||
// free network info
|
||
// return count of DNS server lists found
|
||
|
||
NetInfo_Free( pnetInfo );
|
||
|
||
return countNets;
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
cleanDeadAdaptersFromArray(
|
||
IN OUT PIP_ARRAY * IpArrayArray,
|
||
IN OUT PDNS_NETINFO * NetworkInfoArray, OPTIONAL
|
||
IN DWORD Count
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Cleanup and remove from array(s) adapter info, when an
|
||
adapter is determined to be dead, useless or duplicate for
|
||
the update.
|
||
|
||
Arguments:
|
||
|
||
IpArrayArray -- array of IP array pointers
|
||
|
||
NetworkInfoArray -- array of ptrs to network info structs
|
||
|
||
Count -- length arrays (current adapter count)
|
||
|
||
Return Value:
|
||
|
||
New adapter count.
|
||
|
||
--*/
|
||
{
|
||
register DWORD iter;
|
||
|
||
//
|
||
// remove useless adapters
|
||
// useless means no DNS server list
|
||
//
|
||
|
||
for ( iter = 0; iter < Count; iter++ )
|
||
{
|
||
PIP_ARRAY parray = IpArrayArray[iter];
|
||
|
||
if ( !parray || parray->AddrCount==0 )
|
||
{
|
||
if ( parray )
|
||
{
|
||
FREE_HEAP( parray );
|
||
IpArrayArray[ iter ] = NULL;
|
||
}
|
||
Count--;
|
||
IpArrayArray[ iter ] = IpArrayArray[ Count ];
|
||
IpArrayArray[ Count ] = NULL;
|
||
|
||
// if have corresponding NetworkInfo array, clean it in same fashion
|
||
|
||
if ( NetworkInfoArray )
|
||
{
|
||
if ( NetworkInfoArray[iter] )
|
||
{
|
||
NetInfo_Free( NetworkInfoArray[iter] );
|
||
NetworkInfoArray[iter] = NULL;
|
||
}
|
||
NetworkInfoArray[ iter ] = NetworkInfoArray[ Count ];
|
||
NetworkInfoArray[ Count ] = NULL;
|
||
}
|
||
}
|
||
}
|
||
|
||
// return count of cleaned list
|
||
|
||
return Count;
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
eliminateDuplicateAdapterFromArrays(
|
||
IN OUT PIP_ARRAY * IpArrayArray,
|
||
IN OUT PDNS_NETINFO * NetworkInfoArray,
|
||
IN OUT PDNS_RECORD * NsRecordArray,
|
||
IN DWORD Count,
|
||
IN DWORD DuplicateIndex
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Cleanup and remove from array(s) adapter info, when an
|
||
adapter is determined to be dead, useless or duplicate for
|
||
the update.
|
||
|
||
Arguments:
|
||
|
||
IpArrayArray -- array of IP array pointers
|
||
|
||
NetworkInfoArray -- array of ptrs to network info structs
|
||
|
||
NsRecordArray -- array of NS record lists for FAZed zone
|
||
|
||
Count -- length arrays (current adapter count)
|
||
|
||
DuplicateIndex -- index of duplicate
|
||
|
||
Return Value:
|
||
|
||
New adapter count.
|
||
|
||
--*/
|
||
{
|
||
ASSERT( DuplicateIndex < Count );
|
||
|
||
DNSDBG( TRACE, (
|
||
"eliminateDuplicateAdapterFromArrays( dup=%d, max=%d )\n",
|
||
DuplicateIndex,
|
||
Count ));
|
||
|
||
//
|
||
// free any info on duplicate adapter
|
||
//
|
||
|
||
FREE_HEAP( IpArrayArray[DuplicateIndex] );
|
||
NetInfo_Free( NetworkInfoArray[DuplicateIndex] );
|
||
Dns_RecordListFree( NsRecordArray[DuplicateIndex] );
|
||
|
||
//
|
||
// copy top entry to this spot
|
||
//
|
||
|
||
Count--;
|
||
|
||
if ( Count != DuplicateIndex )
|
||
{
|
||
IpArrayArray[DuplicateIndex] = IpArrayArray[Count];
|
||
NetworkInfoArray[DuplicateIndex] = NetworkInfoArray[Count];
|
||
NsRecordArray[DuplicateIndex] = NsRecordArray[Count];
|
||
}
|
||
|
||
return Count;
|
||
}
|
||
|
||
|
||
|
||
DWORD
|
||
combineDnsServerListsForTwoAdapters(
|
||
IN OUT PIP_ARRAY * IpArrayArray,
|
||
IN DWORD Count,
|
||
IN DWORD Index1,
|
||
IN DWORD Index2
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Combine DNS server lists for two adapters.
|
||
|
||
Note, this unions the DNS server lists for the two
|
||
adapters and eliminates the higher indexed adapter
|
||
from the list.
|
||
|
||
Arguments:
|
||
|
||
IpArrayArray -- array of IP array pointers
|
||
|
||
Count -- length of pointer array
|
||
|
||
Index1 -- low index to union
|
||
|
||
Index2 -- high index to union
|
||
|
||
Return Value:
|
||
|
||
New adapter count.
|
||
|
||
--*/
|
||
{
|
||
PIP_ARRAY punionArray = NULL;
|
||
|
||
DNSDBG( TRACE, (
|
||
"combineDnsServerListsForTwoAdapters( count=%d, i1=%d, i2=%d )\n",
|
||
Count,
|
||
Index1,
|
||
Index2 ));
|
||
|
||
ASSERT( Index1 < Count );
|
||
ASSERT( Index2 < Count );
|
||
ASSERT( Index1 < Index2 );
|
||
|
||
//
|
||
// union the arrays
|
||
//
|
||
// if unable to allocate union, then just use list in first array
|
||
// and dump second
|
||
//
|
||
|
||
Dns_UnionOfIpArrays( IpArrayArray[Index1], IpArrayArray[Index2], &punionArray );
|
||
|
||
if ( punionArray )
|
||
{
|
||
FREE_HEAP( IpArrayArray[Index1] );
|
||
IpArrayArray[Index1] = punionArray;
|
||
}
|
||
|
||
FREE_HEAP( IpArrayArray[Index2] );
|
||
IpArrayArray[Index2] = NULL;
|
||
|
||
//
|
||
// swap deleted entry with last entry in list
|
||
//
|
||
|
||
Count--;
|
||
IpArrayArray[Index2] = IpArrayArray[ Count ];
|
||
|
||
return( Count );
|
||
}
|
||
|
||
|
||
|
||
DNS_STATUS
|
||
CollapseDnsServerListsForUpdate(
|
||
IN OUT PIP_ARRAY * DnsServerListArray,
|
||
OUT PDNS_NETINFO * NetworkInfoArray,
|
||
IN OUT PDWORD pNetCount,
|
||
IN LPSTR pszUpdateName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Builds update network info blob for each unique name space.
|
||
|
||
This essentially starts with DNS server list for each adapter
|
||
and progressively detects adapters pointing at same name space
|
||
until down minimum number of name spaces.
|
||
|
||
Arguments:
|
||
|
||
DnsServerListArray -- array of ptrs to DNS server lists for each adapter
|
||
|
||
NetworkInfoArray -- array to hold pointer to update network info for each
|
||
adapter on return contains ptr to network info for each unique name
|
||
space update should be sent to
|
||
|
||
dwNetCount -- starting count of individual adapters networks
|
||
|
||
pszUpdateName -- name to update
|
||
|
||
Return Value:
|
||
|
||
Count of unique name spaces to update.
|
||
NetworkInfoArray contains update network info blob for each name space.
|
||
|
||
--*/
|
||
{
|
||
PDNS_RECORD NsRecordArray[ UPDATE_ADAPTER_LIMIT ];
|
||
PIP_ARRAY parray1;
|
||
DWORD iter1;
|
||
DWORD iter2;
|
||
DWORD maxCount = *pNetCount;
|
||
DNS_STATUS status = DNS_ERROR_NO_DNS_SERVERS;
|
||
|
||
|
||
DNSDBG( TRACE, (
|
||
"collapseDnsServerListsForUpdate( count=%d )\n"
|
||
"\tupdate name = %s\n",
|
||
maxCount,
|
||
pszUpdateName ));
|
||
|
||
//
|
||
// clean list of any useless adapters
|
||
//
|
||
|
||
maxCount = cleanDeadAdaptersFromArray(
|
||
DnsServerListArray,
|
||
NULL, // no network info yet
|
||
maxCount );
|
||
|
||
//
|
||
// if only one adapter -- nothing to compare
|
||
// - do FAZ to build update network info, if
|
||
// successful, we're done
|
||
//
|
||
|
||
if ( maxCount <= 1 )
|
||
{
|
||
if ( maxCount == 1 )
|
||
{
|
||
NetworkInfoArray[0] = NULL;
|
||
|
||
status = DoQuickFAZ(
|
||
&NetworkInfoArray[0],
|
||
pszUpdateName,
|
||
DnsServerListArray[0] );
|
||
|
||
if ( NetworkInfoArray[0] )
|
||
{
|
||
goto Done;
|
||
}
|
||
FREE_HEAP( DnsServerListArray[0] );
|
||
maxCount = 0;
|
||
goto Done;
|
||
}
|
||
goto Done;
|
||
}
|
||
|
||
//
|
||
// clear NetworkInfo
|
||
//
|
||
|
||
RtlZeroMemory(
|
||
NetworkInfoArray,
|
||
maxCount * sizeof(PVOID) );
|
||
|
||
//
|
||
// loop through combining adapters with shared DNS servers
|
||
//
|
||
// as we combine entries we shrink the list
|
||
//
|
||
|
||
for ( iter1 = 0; iter1 < maxCount; iter1++ )
|
||
{
|
||
parray1 = DnsServerListArray[ iter1 ];
|
||
|
||
for ( iter2=iter1+1; iter2 < maxCount; iter2++ )
|
||
{
|
||
if ( Dns_IsIntersectionOfIpArrays( parray1, DnsServerListArray[iter2] ) )
|
||
{
|
||
DNSDBG( UPDATE, (
|
||
"collapseDSLFU: whacking intersecting DNS server lists\n"
|
||
"\tadapters %d and %d (max =%d)\n",
|
||
iter1,
|
||
iter2,
|
||
maxCount ));
|
||
|
||
maxCount = combineDnsServerListsForTwoAdapters(
|
||
DnsServerListArray,
|
||
maxCount,
|
||
iter1,
|
||
iter2 );
|
||
iter2--;
|
||
parray1 = DnsServerListArray[ iter1 ];
|
||
}
|
||
}
|
||
}
|
||
|
||
DNSDBG( TRACE, (
|
||
"collapseDSLFU: count after dup server whack = %d\n",
|
||
maxCount ));
|
||
|
||
|
||
#if 0
|
||
// clean again, in case we missed something
|
||
|
||
maxCount = cleanDeadAdaptersFromArray(
|
||
DnsServerListArray,
|
||
NULL, // no network info yet
|
||
maxCount );
|
||
#endif
|
||
|
||
//
|
||
// FAZ remaining adapters
|
||
//
|
||
// save result NetworkInfo struct
|
||
// => for comparison to determine adapters that share DNS name space
|
||
// => to return to caller to do actual update
|
||
//
|
||
// if FAZ fails this adapter is useless for update -- dead issue
|
||
// adapter is removed and replaced by highest array entry
|
||
//
|
||
|
||
for ( iter1 = 0; iter1 < maxCount; iter1++ )
|
||
{
|
||
status = DnsFindAuthoritativeZone(
|
||
pszUpdateName,
|
||
DNS_QUERY_BYPASS_CACHE,
|
||
DnsServerListArray[ iter1 ],
|
||
& NetworkInfoArray[ iter1 ] );
|
||
|
||
if ( status != ERROR_SUCCESS )
|
||
{
|
||
FREE_HEAP( DnsServerListArray[ iter1 ] );
|
||
DnsServerListArray[ iter1 ] = NULL;
|
||
maxCount--;
|
||
DnsServerListArray[ iter1 ] = DnsServerListArray[ maxCount ];
|
||
iter1--;
|
||
continue;
|
||
}
|
||
}
|
||
|
||
#if 0
|
||
// clean out failed FAZ entries
|
||
|
||
maxCount = cleanDeadAdaptersFromArray(
|
||
DnsServerListArray,
|
||
NetworkInfoArray,
|
||
maxCount );
|
||
#endif
|
||
|
||
// if only able to FAZ one adapter -- we're done
|
||
// only point here is to skip a bunch of unnecessary
|
||
// stuff in the most typical case multi-adapter case
|
||
|
||
if ( maxCount <= 1 )
|
||
{
|
||
DNSDBG( TRACE, (
|
||
"collapseDSLFU: down to single FAZ adapter\n" ));
|
||
goto Done;
|
||
}
|
||
|
||
//
|
||
// compare FAZ results to see if adapters are in same name space
|
||
//
|
||
// do two passes
|
||
// - on first pass only compare based on FAZ results, if successful
|
||
// we eliminate duplicate adapter
|
||
//
|
||
// - on second pass, adapters that are still separate are compared;
|
||
// if they don't fail FAZ matches (which are retried) then NS queries
|
||
// are used to determine if separate nets;
|
||
// note that NS query results are saved, so NS query is order N, even
|
||
// though we are in N**2 loop
|
||
//
|
||
|
||
RtlZeroMemory(
|
||
NsRecordArray,
|
||
maxCount * sizeof(PVOID) );
|
||
|
||
for ( iter1=0; iter1 < maxCount; iter1++ )
|
||
{
|
||
for ( iter2=iter1+1; iter2 < maxCount; iter2++ )
|
||
{
|
||
if ( CompareTwoAdaptersForSameNameSpace(
|
||
DnsServerListArray[iter1],
|
||
NetworkInfoArray[iter1],
|
||
NULL, // no NS list
|
||
DnsServerListArray[iter2],
|
||
NetworkInfoArray[iter2],
|
||
NULL, // no NS list
|
||
FALSE // don't use NS queries
|
||
) )
|
||
{
|
||
DNSDBG( UPDATE, (
|
||
"collapseDSLFU: whacking same-FAZ adapters\n"
|
||
"\tadapters %d and %d (max =%d)\n",
|
||
iter1,
|
||
iter2,
|
||
maxCount ));
|
||
|
||
eliminateDuplicateAdapterFromArrays(
|
||
DnsServerListArray,
|
||
NetworkInfoArray,
|
||
NsRecordArray,
|
||
maxCount,
|
||
iter2 );
|
||
|
||
maxCount--;
|
||
iter2--;
|
||
}
|
||
}
|
||
}
|
||
|
||
DNSDBG( TRACE, (
|
||
"collapseDSLFU: count after dup FAZ whack = %d\n",
|
||
maxCount ));
|
||
|
||
|
||
// second pass using NS info
|
||
// if NS info is created, we save it to avoid requery
|
||
|
||
for ( iter1=0; iter1 < maxCount; iter1++ )
|
||
{
|
||
for ( iter2=iter1+1; iter2 < maxCount; iter2++ )
|
||
{
|
||
if ( CompareTwoAdaptersForSameNameSpace(
|
||
DnsServerListArray[iter1],
|
||
NetworkInfoArray[iter1],
|
||
& NsRecordArray[iter1],
|
||
DnsServerListArray[iter2],
|
||
NetworkInfoArray[iter2],
|
||
& NsRecordArray[iter2],
|
||
TRUE // follow up with NS queries
|
||
) )
|
||
{
|
||
DNSDBG( UPDATE, (
|
||
"collapseDSLFU: whacking same-zone-NS adapters\n"
|
||
"\tadapters %d and %d (max =%d)\n",
|
||
iter1,
|
||
iter2,
|
||
maxCount ));
|
||
|
||
eliminateDuplicateAdapterFromArrays(
|
||
DnsServerListArray,
|
||
NetworkInfoArray,
|
||
NsRecordArray,
|
||
maxCount,
|
||
iter2 );
|
||
|
||
maxCount--;
|
||
iter2--;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// kill off any NS records found
|
||
//
|
||
|
||
for ( iter1=0; iter1 < maxCount; iter1++ )
|
||
{
|
||
Dns_RecordListFree( NsRecordArray[iter1] );
|
||
}
|
||
|
||
Done:
|
||
|
||
//
|
||
// set count of remaining adapters (update DNS server lists)
|
||
//
|
||
// return status
|
||
// - success if have any update adapter
|
||
// - on failure bubble up FAZ error
|
||
//
|
||
|
||
DNSDBG( TRACE, (
|
||
"Leave CollapseDnsServerListsForUpdate( collapsed count=%d )\n",
|
||
maxCount ));
|
||
|
||
*pNetCount = maxCount;
|
||
|
||
if ( maxCount > 0 )
|
||
{
|
||
status = ERROR_SUCCESS;
|
||
}
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
WINAPI
|
||
CompareTwoAdaptersForSameNameSpace(
|
||
IN PIP_ARRAY pDnsServerList1,
|
||
IN PDNS_NETINFO pNetworkInfo1,
|
||
IN OUT PDNS_RECORD * ppNsRecord1,
|
||
IN PIP_ARRAY pDnsServerList2,
|
||
IN PDNS_NETINFO pNetworkInfo2,
|
||
IN OUT PDNS_RECORD * ppNsRecord2,
|
||
IN BOOL bDoNsCheck
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Compare two adapters to see if in same name space for update.
|
||
|
||
Arguments:
|
||
|
||
pDnsServerList1 -- IP array of DNS servers for first adapter
|
||
|
||
pNetworkInfo1 -- update netinfo for first adapter
|
||
|
||
ppNsRecord1 -- addr of ptr to NS record list of update zone done on
|
||
first adapter; NULL if no NS check required; if
|
||
NS check required and *ppNsRecord1 is NULL, NS query
|
||
is made and results returned
|
||
|
||
pDnsServerList2 -- IP array of DNS servers for second adapter
|
||
|
||
pNetworkInfo2 -- update netinfo for second adapter
|
||
|
||
ppNsRecord2 -- addr of ptr to NS record list of update zone done on
|
||
second adapter; NULL if no NS check required; if
|
||
NS check required and *ppNsRecord2 is NULL, NS query
|
||
is made and results returned
|
||
|
||
bDoNsCheck -- include update-zone NS check compare; if NS overlap then
|
||
name spaces assumed to be the same
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful.
|
||
Error status on failure.
|
||
|
||
--*/
|
||
{
|
||
DNS_STATUS status = NO_ERROR;
|
||
BOOL fsame = FALSE;
|
||
PDNS_ADAPTER padapter1 = pNetworkInfo1->AdapterArray[0];
|
||
PDNS_ADAPTER padapter2 = pNetworkInfo2->AdapterArray[0];
|
||
PDNS_RECORD pns1 = NULL;
|
||
PDNS_RECORD pns2 = NULL;
|
||
PDNS_RECORD pnotUsed = NULL;
|
||
PSTR pzoneName;
|
||
|
||
|
||
//
|
||
// done if bad params
|
||
//
|
||
|
||
if ( !pDnsServerList1 || !pDnsServerList2 )
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// validity check
|
||
// - note: could probably be just ASSERT()
|
||
//
|
||
|
||
if ( ! NetInfo_IsForUpdate(pNetworkInfo1) ||
|
||
! NetInfo_IsForUpdate(pNetworkInfo2) )
|
||
{
|
||
ASSERT( FALSE );
|
||
return( FALSE );
|
||
}
|
||
|
||
//
|
||
// compare FAZ results
|
||
//
|
||
// first compare zone names
|
||
// if FAZ returns different zone names, then clearly
|
||
// have disjoint name spaces
|
||
//
|
||
|
||
pzoneName = NetInfo_UpdateZoneName( pNetworkInfo1 );
|
||
|
||
if ( ! Dns_NameCompare_UTF8(
|
||
pzoneName,
|
||
NetInfo_UpdateZoneName( pNetworkInfo2 ) ) )
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// check if pointing at same server:
|
||
// - if have same update DNS server -- have a match
|
||
// - if same server name -- have a match
|
||
//
|
||
|
||
if ( padapter1->ServerCount == 1 &&
|
||
padapter2->ServerCount == 1 &&
|
||
padapter1->ServerArray[0].IpAddress == padapter2->ServerArray[0].IpAddress )
|
||
{
|
||
return TRUE;
|
||
}
|
||
else
|
||
{
|
||
fsame = Dns_NameCompare_UTF8(
|
||
NetInfo_UpdateServerName( pNetworkInfo1 ),
|
||
NetInfo_UpdateServerName( pNetworkInfo2 ) );
|
||
}
|
||
|
||
//
|
||
// if matched or not doing NS check => then done
|
||
//
|
||
|
||
if ( fsame || !bDoNsCheck )
|
||
{
|
||
return( fsame );
|
||
}
|
||
|
||
//
|
||
// NS check
|
||
//
|
||
// if not pointing at same server, may be two multimaster primaries
|
||
//
|
||
// use NS queries to determine if NS lists for same servers are in
|
||
// fact a match
|
||
//
|
||
|
||
if ( ppNsRecord1 )
|
||
{
|
||
pns1 = *ppNsRecord1;
|
||
}
|
||
if ( !pns1 )
|
||
{
|
||
status = DnsQuery_UTF8(
|
||
pzoneName,
|
||
DNS_TYPE_NS,
|
||
DNS_QUERY_BYPASS_CACHE,
|
||
pDnsServerList1,
|
||
&pns1,
|
||
NULL );
|
||
|
||
if ( status != ERROR_SUCCESS )
|
||
{
|
||
goto Done;
|
||
}
|
||
pnotUsed = DnsRecordSetDetach( pns1 );
|
||
if ( pnotUsed )
|
||
{
|
||
Dns_RecordListFree( pnotUsed );
|
||
pnotUsed = NULL;
|
||
}
|
||
}
|
||
|
||
if ( ppNsRecord2 )
|
||
{
|
||
pns2 = *ppNsRecord2;
|
||
}
|
||
if ( !pns2 )
|
||
{
|
||
status = DnsQuery_UTF8(
|
||
pzoneName,
|
||
DNS_TYPE_NS,
|
||
DNS_QUERY_BYPASS_CACHE,
|
||
pDnsServerList2,
|
||
&pns2,
|
||
NULL );
|
||
|
||
if ( status != ERROR_SUCCESS )
|
||
{
|
||
goto Done;
|
||
}
|
||
pnotUsed = DnsRecordSetDetach( pns2 );
|
||
if ( pnotUsed )
|
||
{
|
||
Dns_RecordListFree( pnotUsed );
|
||
pnotUsed = NULL;
|
||
}
|
||
}
|
||
|
||
//
|
||
// if NS lists the same -- same namespace
|
||
//
|
||
|
||
fsame = Dns_RecordSetCompareForIntersection( pns1, pns2 );
|
||
|
||
Done:
|
||
|
||
//
|
||
// cleanup or return NS lists
|
||
//
|
||
// note, purpose of returning is so caller can avoid requerying
|
||
// NS if must make compare against multiple other adapters
|
||
//
|
||
|
||
if ( ppNsRecord1 )
|
||
{
|
||
*ppNsRecord1 = pns1;
|
||
}
|
||
else
|
||
{
|
||
Dns_RecordListFree( pns1 );
|
||
}
|
||
|
||
if ( ppNsRecord2 )
|
||
{
|
||
*ppNsRecord2 = pns2;
|
||
}
|
||
else
|
||
{
|
||
Dns_RecordListFree( pns2 );
|
||
}
|
||
|
||
return fsame;
|
||
}
|
||
|
||
|
||
|
||
BOOL
|
||
WINAPI
|
||
CompareMultiAdapterSOAQueries(
|
||
IN LPSTR pszDomainName,
|
||
IN PIP_ARRAY pDnsServerList1,
|
||
IN PIP_ARRAY pDnsServerList2
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Compare two adapters to see if in same name space for update.
|
||
|
||
Arguments:
|
||
|
||
pszDomainName -- domain name to update
|
||
|
||
pDnsServerList1 -- IP array of DNS servers for first adapter
|
||
|
||
pDnsServerList2 -- IP array of DNS servers for second adapter
|
||
|
||
Return Value:
|
||
|
||
TRUE -- if adapters are found to be on same net
|
||
FALSE -- otherwise (definitely NOT or unable to determine)
|
||
|
||
--*/
|
||
{
|
||
DNS_STATUS status;
|
||
BOOL fsame = FALSE;
|
||
PDNS_NETINFO pnetInfo1 = NULL;
|
||
PDNS_NETINFO pnetInfo2 = NULL;
|
||
|
||
|
||
DNSDBG( TRACE, (
|
||
"CompareMultiAdapterSOAQueries()\n" ));
|
||
|
||
|
||
// bad param screening
|
||
|
||
if ( !pDnsServerList1 || !pDnsServerList2 || !pszDomainName )
|
||
{
|
||
return FALSE;
|
||
}
|
||
|
||
//
|
||
// compare DNS server lists
|
||
// if any overlap, them effectively in same DNS namespace
|
||
//
|
||
|
||
if ( Dns_IsIntersectionOfIpArrays( pDnsServerList1, pDnsServerList2 ) )
|
||
{
|
||
return TRUE;
|
||
}
|
||
|
||
//
|
||
// if no DNS server overlap, must compare FAZ results
|
||
//
|
||
// note: FAZ failures interpreted as FALSE response
|
||
// required for callers in asyncreg.c
|
||
//
|
||
|
||
status = DnsFindAuthoritativeZone(
|
||
pszDomainName,
|
||
DNS_QUERY_BYPASS_CACHE,
|
||
pDnsServerList1,
|
||
&pnetInfo1 );
|
||
|
||
if ( status != ERROR_SUCCESS )
|
||
{
|
||
goto Cleanup;
|
||
}
|
||
|
||
status = DnsFindAuthoritativeZone(
|
||
pszDomainName,
|
||
DNS_QUERY_BYPASS_CACHE,
|
||
pDnsServerList2,
|
||
&pnetInfo2 );
|
||
|
||
if ( status != ERROR_SUCCESS )
|
||
{
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// call the comparison routine
|
||
//
|
||
|
||
fsame = CompareTwoAdaptersForSameNameSpace(
|
||
pDnsServerList1,
|
||
pnetInfo1,
|
||
NULL, // no NS record list
|
||
pDnsServerList2,
|
||
pnetInfo2,
|
||
NULL, // no NS record list
|
||
TRUE // follow up with NS queries
|
||
);
|
||
|
||
Cleanup:
|
||
|
||
NetInfo_Free( pnetInfo1 );
|
||
NetInfo_Free( pnetInfo2 );
|
||
|
||
return fsame;
|
||
}
|
||
|
||
|
||
|
||
IP_ADDRESS
|
||
FindHostIpAddressInRecordList(
|
||
IN PDNS_RECORD pRecordList,
|
||
IN LPSTR pszHostName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Find IP for hostname, if its A record is in list.
|
||
|
||
NOTE: This code was borrowed from \dns\dnslib\query.c! ;-)
|
||
|
||
Arguments:
|
||
|
||
pRecordList - incoming RR set
|
||
|
||
pszHostName - hostname to find (in UTF8)
|
||
|
||
Return Value:
|
||
|
||
IP address matching hostname, if A record for hostname found.
|
||
Zero if not found.
|
||
|
||
--*/
|
||
{
|
||
register PDNS_RECORD prr = pRecordList;
|
||
|
||
//
|
||
// loop through all records until find IP matching hostname
|
||
//
|
||
|
||
while ( prr )
|
||
{
|
||
if ( prr->wType == DNS_TYPE_A &&
|
||
Dns_NameCompare_UTF8(
|
||
prr->pName,
|
||
pszHostName ) )
|
||
{
|
||
return( prr->Data.A.IpAddress );
|
||
}
|
||
prr = prr->pNext;
|
||
}
|
||
|
||
return( 0 );
|
||
}
|
||
|
||
|
||
|
||
PIP_ARRAY
|
||
GetNameServersListForDomain(
|
||
IN LPSTR pDomainName,
|
||
IN PIP_ARRAY aipServers
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Get IPs for all DNS servers for zone.
|
||
|
||
Arguments:
|
||
|
||
pDomainName -- zone name
|
||
|
||
aipServers -- server list to query
|
||
|
||
Return Value:
|
||
|
||
IP array of IPs of DNS servers for zone.
|
||
NULL if error.
|
||
|
||
--*/
|
||
{
|
||
DNS_STATUS status = NO_ERROR;
|
||
PDNS_RECORD prrQuery = NULL;
|
||
PIP_ARRAY aipNSList = NULL;
|
||
DWORD countAddr = 0;
|
||
|
||
status = DnsQuery_UTF8(
|
||
pDomainName,
|
||
DNS_TYPE_NS,
|
||
DNS_QUERY_BYPASS_CACHE,
|
||
aipServers,
|
||
&prrQuery,
|
||
NULL );
|
||
|
||
if ( status == NO_ERROR )
|
||
{
|
||
PDNS_RECORD pTemp = prrQuery;
|
||
DWORD dwCount = 0;
|
||
|
||
while ( pTemp )
|
||
{
|
||
dwCount++;
|
||
pTemp = pTemp->pNext;
|
||
}
|
||
|
||
aipNSList = Dns_CreateIpArray( dwCount );
|
||
|
||
if ( aipNSList )
|
||
{
|
||
pTemp = prrQuery;
|
||
|
||
while ( pTemp )
|
||
{
|
||
if ( pTemp->wType == DNS_TYPE_NS )
|
||
{
|
||
IP_ADDRESS ip = 0;
|
||
|
||
ip = FindHostIpAddressInRecordList(
|
||
pTemp,
|
||
pTemp->Data.NS.pNameHost );
|
||
|
||
if ( !ip )
|
||
{
|
||
PDNS_RECORD pARecord = NULL;
|
||
|
||
//
|
||
// Query again to get the server's address
|
||
//
|
||
|
||
status = DnsQuery_UTF8( pTemp->Data.NS.pNameHost,
|
||
DNS_TYPE_A,
|
||
DNS_QUERY_BYPASS_CACHE,
|
||
aipServers,
|
||
&pARecord,
|
||
NULL );
|
||
|
||
if ( status == NO_ERROR &&
|
||
pARecord )
|
||
{
|
||
ip = pARecord->Data.A.IpAddress;
|
||
Dns_RecordListFree( pARecord );
|
||
}
|
||
}
|
||
|
||
if ( ip &&
|
||
!Dns_IsAddressInIpArray( aipNSList, ip ) )
|
||
{
|
||
Dns_AddIpToIpArray( aipNSList, ip );
|
||
countAddr++;
|
||
}
|
||
}
|
||
|
||
pTemp = pTemp->pNext;
|
||
}
|
||
}
|
||
}
|
||
|
||
if ( prrQuery )
|
||
{
|
||
Dns_RecordListFree( prrQuery );
|
||
}
|
||
|
||
if ( aipNSList )
|
||
{
|
||
aipNSList->AddrCount = countAddr;
|
||
}
|
||
|
||
return aipNSList;
|
||
}
|
||
|
||
|
||
//
|
||
// End of faz.c
|
||
//
|