Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2077 lines
49 KiB

  1. /*++
  2. Copyright (c) 1997-2002 Microsoft Corporation
  3. Module Name:
  4. faz.c
  5. Abstract:
  6. Domain Name System (DNS) API
  7. Find Authoritative Zone (FAZ) routines
  8. Author:
  9. Jim Gilroy (jamesg) January, 1997
  10. Revision History:
  11. --*/
  12. #include "local.h"
  13. //
  14. // Max number of server's we'll ever bother to extract from packet
  15. // (much more and you're out of UDP packet space anyway)
  16. //
  17. #define MAX_NAME_SERVER_COUNT (20)
  18. //
  19. // Private protos
  20. //
  21. BOOL
  22. IsRootServerAddressIp4(
  23. IN IP4_ADDRESS Ip
  24. );
  25. //
  26. // Private utilities
  27. //
  28. PDNS_NETINFO
  29. buildUpdateNetworkInfoFromFAZ(
  30. IN PWSTR pszZone,
  31. IN PWSTR pszPrimaryDns,
  32. IN PDNS_RECORD pRecord,
  33. IN BOOL fIp4,
  34. IN BOOL fIp6
  35. )
  36. /*++
  37. Routine Description:
  38. Build new DNS server list from record list.
  39. Arguments:
  40. pszZone -- zone name
  41. pszPrimaryDns -- DNS server name
  42. pRecord -- record list from FAZ or other lookup that contain DNS server
  43. host records
  44. fIp4 -- running IP4
  45. fIp6 -- running IP6
  46. Return Value:
  47. ERROR_SUCCESS if successful.
  48. Error code on failure.
  49. --*/
  50. {
  51. CHAR buffer[ MAX_NAME_SERVER_COUNT*sizeof(DNS_ADDR) + sizeof(DNS_ADDR_ARRAY) ];
  52. PDNS_ADDR_ARRAY parray = (PDNS_ADDR_ARRAY)buffer;
  53. BOOL fmatch = FALSE;
  54. WORD wtype;
  55. DNSDBG( TRACE, (
  56. "buildUpdateNetworkInfoFromFAZ( %S )\n",
  57. pszZone ));
  58. //
  59. // DNS hostname unknown, extract from SOA or NS records
  60. //
  61. if ( !pszPrimaryDns || !pRecord )
  62. {
  63. return( NULL );
  64. }
  65. //
  66. // init IP array
  67. //
  68. DnsAddrArray_Init( parray, MAX_NAME_SERVER_COUNT );
  69. //
  70. // find IP addresses of primary DNS server
  71. //
  72. while ( pRecord )
  73. {
  74. // if not A record
  75. // - we're done if already read records, otherwise continue
  76. wtype = pRecord->wType;
  77. if ( wtype != DNS_TYPE_AAAA && wtype != DNS_TYPE_A )
  78. {
  79. if ( parray->AddrCount != 0 )
  80. {
  81. break;
  82. }
  83. fmatch = FALSE;
  84. pRecord = pRecord->pNext;
  85. continue;
  86. }
  87. // if record has name, check it
  88. // otherwise match is the same as previous record
  89. if ( pRecord->pName )
  90. {
  91. fmatch = Dns_NameCompare_W(
  92. pRecord->pName,
  93. pszPrimaryDns );
  94. }
  95. if ( fmatch )
  96. {
  97. if ( wtype == DNS_TYPE_AAAA )
  98. {
  99. if ( fIp6 )
  100. {
  101. DnsAddrArray_AddIp6(
  102. parray,
  103. & pRecord->Data.AAAA.Ip6Address,
  104. 0, // no scope
  105. DNSADDR_MATCH_ADDR
  106. );
  107. }
  108. }
  109. else if ( wtype == DNS_TYPE_A )
  110. {
  111. if ( fIp4 &&
  112. !IsRootServerAddressIp4( pRecord->Data.A.IpAddress ) )
  113. {
  114. DnsAddrArray_AddIp4(
  115. parray,
  116. pRecord->Data.A.IpAddress,
  117. DNSADDR_MATCH_ADDR
  118. );
  119. }
  120. }
  121. }
  122. pRecord = pRecord->pNext;
  123. continue;
  124. }
  125. if ( parray->AddrCount == 0 )
  126. {
  127. return( NULL );
  128. }
  129. //
  130. // convert into UPDATE adapter list
  131. //
  132. return NetInfo_CreateForUpdate(
  133. pszZone,
  134. pszPrimaryDns,
  135. parray,
  136. 0 );
  137. }
  138. BOOL
  139. ValidateZoneNameForUpdate(
  140. IN PWSTR pszZone
  141. )
  142. /*++
  143. Routine Description:
  144. Check if zone is valid for update.
  145. Arguments:
  146. pszZone -- zone name
  147. Return Value:
  148. TRUE -- zone is valid for update
  149. FALSE -- zone is invalid, should NOT send update to this zone
  150. --*/
  151. {
  152. PWSTR pzoneExclusions = NULL;
  153. PWSTR pch;
  154. PWSTR pnext;
  155. DNS_STATUS status;
  156. DWORD length;
  157. BOOL returnVal = TRUE;
  158. DWORD labelCount;
  159. DNSDBG( TRACE, (
  160. "ValidateZoneNameForUpdate( %S )\n",
  161. pszZone ));
  162. //
  163. // never update the root
  164. //
  165. if ( !pszZone || *pszZone==L'.' )
  166. {
  167. return( FALSE );
  168. }
  169. //
  170. // never update TLD
  171. // - except config override in case someone
  172. // gave themselves a single label domain name
  173. //
  174. if ( g_UpdateTopLevelDomains )
  175. {
  176. return( TRUE );
  177. }
  178. labelCount = Dns_NameLabelCountW( pszZone );
  179. if ( labelCount > 2 )
  180. {
  181. return( TRUE );
  182. }
  183. if ( labelCount < 2 )
  184. {
  185. return( FALSE );
  186. }
  187. //
  188. // screen out
  189. // - "in-addr.arpa"
  190. // - "ip6.arpa"
  191. //
  192. if ( Dns_NameCompare_W(
  193. L"in-addr.arpa",
  194. pszZone ) )
  195. {
  196. return( FALSE );
  197. }
  198. if ( Dns_NameCompare_W(
  199. L"ip6.arpa",
  200. pszZone ) )
  201. {
  202. return( FALSE );
  203. }
  204. return( TRUE );
  205. #if 0
  206. //
  207. // DCR: "update zone allowed" list?
  208. //
  209. // note: this is complicated as need to test
  210. // SECOND label because tough cases are
  211. // "co.uk" -- difficult to test first label
  212. //
  213. //
  214. // read exclusion list from registry
  215. //
  216. status = DnsRegGetValueEx(
  217. NULL, // no session
  218. NULL, // no adapter
  219. NULL, // no adapter name
  220. DnsRegUpdateZoneExclusions,
  221. REGTYPE_UPDATE_ZONE_EXCLUSIONS,
  222. DNSREG_FLAG_DUMP_EMPTY, // dump empty string
  223. (PBYTE *) &pzoneExclusions
  224. );
  225. if ( status != ERROR_SUCCESS ||
  226. !pzoneExclusions )
  227. {
  228. ASSERT( pzoneExclusions == NULL );
  229. return( TRUE );
  230. }
  231. //
  232. // check all exclusion zones
  233. //
  234. pch = pzoneExclusions;
  235. while ( 1 )
  236. {
  237. // check for termination
  238. // or find next string
  239. length = wcslen( pch );
  240. if ( length == 0 )
  241. {
  242. break;
  243. }
  244. pnext = pch + length + 1;
  245. //
  246. // check this string
  247. //
  248. DNSDBG( TRACE, (
  249. "Update zone compare to %S\n",
  250. pch ));
  251. if ( Dns_NameCompare_W(
  252. pch,
  253. pszZone ) )
  254. {
  255. returnVal = FALSE;
  256. break;
  257. }
  258. pch = pnext;
  259. }
  260. // if no match, zone is valid
  261. FREE_HEAP( pzoneExclusions );
  262. return( returnVal );
  263. #endif
  264. }
  265. DNS_STATUS
  266. Faz_Private(
  267. IN PWSTR pszName,
  268. IN DWORD dwFlags,
  269. IN PADDR_ARRAY pServArray,
  270. OUT PDNS_NETINFO * ppNetworkInfo
  271. )
  272. /*++
  273. Routine Description:
  274. Find name of authoritative zone.
  275. Result of FAZ:
  276. - zone name
  277. - primary DNS server name
  278. - primary DNS IP list
  279. Arguments:
  280. pszName -- name to find authoritative zone for
  281. dwFlags -- flags to use for DnsQuery
  282. pServArray -- servers to query, defaults used if NULL
  283. ppNetworkInfo -- ptr to adapter list built for FAZ
  284. Return Value:
  285. ERROR_SUCCESS if successful.
  286. Error code on failure.
  287. --*/
  288. {
  289. DNS_STATUS status;
  290. PDNS_RECORD precord = NULL;
  291. PDNS_RECORD precordPrimary = NULL;
  292. PDNS_RECORD precordSOA = NULL;
  293. PWSTR pszdnsHost = NULL;
  294. PDNS_NETINFO pnetInfo = NULL;
  295. PWSTR pzoneName;
  296. BOOL fip4;
  297. BOOL fip6;
  298. BOOL queriedA = FALSE;
  299. BOOL queriedAAAA = FALSE;
  300. DNSDBG( QUERY, (
  301. "Faz_Private()\n"
  302. "\tname %S\n"
  303. "\tflags %08x\n"
  304. "\tserver list %p\n"
  305. "\tnetinfo addr %p\n",
  306. pszName,
  307. dwFlags,
  308. pServArray,
  309. ppNetworkInfo ));
  310. //
  311. // query until find name with SOA record -- the zone root
  312. //
  313. // note, MUST check that actually get SOA record
  314. // - servers may return referral
  315. // - lame server might return CNAME to name
  316. //
  317. pzoneName = pszName;
  318. while ( pzoneName )
  319. {
  320. if ( precord )
  321. {
  322. Dns_RecordListFree( precord );
  323. precord = NULL;
  324. }
  325. status = Query_Private(
  326. pzoneName,
  327. DNS_TYPE_SOA,
  328. dwFlags |
  329. DNS_QUERY_TREAT_AS_FQDN |
  330. DNS_QUERY_ALLOW_EMPTY_AUTH_RESP,
  331. pServArray,
  332. & precord );
  333. //
  334. // find SOA and possibly primary name A
  335. //
  336. // test for ERROR_SUCCESS, AUTH_EMPTY or NAME_ERROR
  337. // in all cases first record should be SOA
  338. // ERROR_SUCCESS -- answer section
  339. // NAME_ERROR or AUTH_EMPTY -- authority section
  340. // all MAY also have additional record for SOA primary server
  341. //
  342. if ( status == ERROR_SUCCESS ||
  343. status == DNS_INFO_NO_RECORDS ||
  344. status == DNS_ERROR_RCODE_NAME_ERROR )
  345. {
  346. if ( precord && precord->wType == DNS_TYPE_SOA )
  347. {
  348. // received SOA
  349. // devolve name to zone name
  350. DNSDBG( QUERY, (
  351. "FAZ found SOA (section %d) at zone %S\n",
  352. precord->Flags.S.Section,
  353. precord->pName ));
  354. while( pzoneName &&
  355. ! Dns_NameCompare_W( pzoneName, precord->pName ) )
  356. {
  357. pzoneName = Dns_GetDomainNameW( pzoneName );
  358. }
  359. precordSOA = precord;
  360. status = ERROR_SUCCESS;
  361. break;
  362. }
  363. // this could be because server no-recurse or
  364. // bum server (BIND) that CNAMEs even when type=SOA
  365. // drop down to devolve name and continue
  366. DNSDBG( ANY, (
  367. "ERROR: response from FAZ query with no SOA records.\n" ));
  368. }
  369. //
  370. // other errors besides
  371. // - name error
  372. // - no records
  373. // indicate terminal problem
  374. //
  375. else
  376. {
  377. DNS_ASSERT( precord == NULL );
  378. goto Cleanup;
  379. }
  380. //
  381. // name error or empty response, continue with next higher domain
  382. //
  383. pzoneName = Dns_GetDomainNameW( pzoneName );
  384. }
  385. //
  386. // if reached root or TLD -- no update
  387. // - note currently returning SERVFAIL because of
  388. // screwy netlogon logic
  389. //
  390. if ( !ValidateZoneNameForUpdate(pzoneName) )
  391. {
  392. //status = DNS_ERROR_INVALID_ZONE_OPERATION;
  393. status = DNS_ERROR_RCODE_SERVER_FAILURE;
  394. //status = DNS_ERROR_RCODE_REFUSED;
  395. goto Cleanup;
  396. }
  397. //
  398. // determine required protocol for update
  399. //
  400. // need to insure we get server address records for protocol that is
  401. // reachable from this client;
  402. //
  403. // more specifically the ideal protocol for the update is a protocol
  404. // that the target DNS server supports and that the client also supports
  405. // ON THE ADAPTER that the server is reached through;
  406. // this is close to being the protocol that the FAZ went over -- but
  407. // if from the cache, we don't have (can't yet get) that info; and that
  408. // is a sufficient but not necessary condition;
  409. //
  410. // furthermore we can't even make the global determination that we don't
  411. // support IP4, because we can always open an IP4 socket (on loopback interface)
  412. //
  413. // solution:
  414. // - IP4 only => trivial done
  415. // - IP6 =>
  416. // - try to build from FAZ, insisting on IP6
  417. // -
  418. //
  419. // note, even here we're assuming
  420. //
  421. //
  422. // get supported protocol info
  423. //
  424. Util_GetActiveProtocols(
  425. & fip6,
  426. & fip4 );
  427. //
  428. // have SOA record
  429. //
  430. // if primary server A record in the packet, use it
  431. // otherwise query for primary DNS A record
  432. //
  433. DNS_ASSERT( precordSOA );
  434. DNS_ASSERT( status == ERROR_SUCCESS );
  435. pszdnsHost = precordSOA->Data.SOA.pNamePrimaryServer;
  436. //
  437. // check additional for primary A\AAAA record
  438. // if found, build network info blob for update
  439. // that points only to update server
  440. //
  441. pnetInfo = buildUpdateNetworkInfoFromFAZ(
  442. pzoneName,
  443. pszdnsHost,
  444. precordSOA,
  445. fip4,
  446. fip6 );
  447. if ( pnetInfo )
  448. {
  449. goto Cleanup;
  450. }
  451. //
  452. // if no primary server A\AAAA record found -- must query
  453. //
  454. DNSDBG( QUERY, (
  455. "WARNING: FAZ making additional query for primary!\n"
  456. "\tPrimary (%S) address record should have been in additional section!\n",
  457. pszdnsHost ));
  458. while ( 1 )
  459. {
  460. WORD wtype;
  461. //
  462. // protocol order IP6 first
  463. //
  464. // this protects us in the IP6 only scenario from getting IP4
  465. // DNS address when in fact we can't use it because of no IP4
  466. // binding; the reverse issue is not much of a problem, the
  467. // autoconfig IP6 address works and we probably won't be
  468. // getting an IP6 address, unless IP6 DNS is desired
  469. //
  470. // DCR: update address\protocol problem
  471. // ultimately should either
  472. // A) verify received address is reachable
  473. // if not direct from IpHlpApi, then find adapter and verify
  474. // we have address of requeried protocol on the adapter
  475. // B) get addresses for any protocols we have, and make sure
  476. // send code uses them
  477. //
  478. if ( fip6 && !queriedAAAA )
  479. {
  480. wtype = DNS_TYPE_AAAA;
  481. queriedAAAA = TRUE;
  482. }
  483. else if ( fip4 && !queriedA )
  484. {
  485. wtype = DNS_TYPE_A;
  486. queriedA = TRUE;
  487. }
  488. else
  489. {
  490. DNSDBG( FAZ, (
  491. "No more protocols for FAZ server address query!\n"
  492. "\tserver = %S\n"
  493. "\tqueried AAAA = %d\n"
  494. "\tqueried A = %d\n",
  495. pszdnsHost,
  496. queriedAAAA,
  497. queriedA ));
  498. status = DNS_ERROR_RCODE_SERVER_FAILURE;
  499. goto Cleanup;
  500. }
  501. status = Query_Private(
  502. pszdnsHost,
  503. wtype,
  504. dwFlags |
  505. DNS_QUERY_TREAT_AS_FQDN |
  506. DNS_QUERY_ALLOW_EMPTY_AUTH_RESP,
  507. pServArray,
  508. & precordPrimary );
  509. if ( status == ERROR_SUCCESS )
  510. {
  511. pnetInfo = buildUpdateNetworkInfoFromFAZ(
  512. pzoneName,
  513. pszdnsHost,
  514. precordPrimary,
  515. fip4,
  516. fip6 );
  517. if ( pnetInfo )
  518. {
  519. goto Cleanup;
  520. }
  521. }
  522. DNSDBG( FAZ, (
  523. "FAZ server address query failed to produce records!\n"
  524. "\tserver = %S\n"
  525. "\ttype = %d\n"
  526. "\tstatus = %d\n"
  527. "\tprecords = %p\n",
  528. pszdnsHost,
  529. wtype,
  530. status,
  531. precordPrimary ));
  532. Dns_RecordListFree( precordPrimary );
  533. precordPrimary = NULL;
  534. continue;
  535. }
  536. Cleanup:
  537. Dns_RecordListFree( precord );
  538. Dns_RecordListFree( precordPrimary );
  539. *ppNetworkInfo = pnetInfo;
  540. DNSDBG( QUERY, (
  541. "Leaving Faz_Private()\n"
  542. "\tstatus = %d\n"
  543. "\tzone = %S\n",
  544. status,
  545. pzoneName ));
  546. return( status );
  547. }
  548. DNS_STATUS
  549. DoQuickFAZ(
  550. OUT PDNS_NETINFO * ppNetworkInfo,
  551. IN PWSTR pszName,
  552. IN PADDR_ARRAY aipServerList OPTIONAL
  553. )
  554. /*++
  555. Routine Description:
  556. FAZ to build network info from FAZ result
  557. Result of FAZ:
  558. - zone name
  559. - primary DNS server name
  560. - primary DNS IP list
  561. This routine is cheap shell around real FAZ to handle
  562. network failure issue, speeding things in net down
  563. condition.
  564. Arguments:
  565. ppNetworkInfo -- addr to recv ptr to network info
  566. pszName -- name for update
  567. aipServerList -- IP array of DNS servers to contact
  568. Return Value:
  569. ERROR_SUCCESS if successful.
  570. ErrorCode on failure
  571. --*/
  572. {
  573. DNS_STATUS status;
  574. DNSDBG( TRACE, ( "DoQuickFAZ( %S )\n", pszName ));
  575. if ( IsKnownNetFailure() )
  576. {
  577. return GetLastError();
  578. }
  579. //
  580. // call real FAZ
  581. // - get results as adapter list struct
  582. //
  583. status = Faz_Private(
  584. pszName,
  585. aipServerList ? DNS_QUERY_BYPASS_CACHE : 0,
  586. aipServerList,
  587. ppNetworkInfo // build adapter list from results
  588. );
  589. //
  590. // if unsuccessful, check if network failure
  591. //
  592. if ( status != ERROR_SUCCESS && !aipServerList )
  593. {
  594. if ( status == WSAEFAULT ||
  595. status == WSAENOTSOCK ||
  596. status == WSAENETDOWN ||
  597. status == WSAENETUNREACH ||
  598. status == WSAEPFNOSUPPORT ||
  599. status == WSAEAFNOSUPPORT ||
  600. status == WSAEHOSTDOWN ||
  601. status == WSAEHOSTUNREACH ||
  602. status == ERROR_TIMEOUT )
  603. {
  604. SetKnownNetFailure( status );
  605. return status;
  606. }
  607. }
  608. return status;
  609. }
  610. //
  611. // Update network info preparation
  612. //
  613. DWORD
  614. GetDnsServerListsForUpdate(
  615. IN OUT PDNS_ADDR_ARRAY * DnsServerListArray,
  616. IN DWORD ArrayLength,
  617. IN DWORD Flags
  618. )
  619. /*++
  620. Routine Description:
  621. Get DNS server lists for update.
  622. One DNS server list returned for each valid updateable adapter.
  623. Arguments:
  624. DnsServerListArray -- array to hold DNS server lists found
  625. ArrayLength -- length of array
  626. Flags -- update flags
  627. Return Value:
  628. Count of DNS server lists found.
  629. --*/
  630. {
  631. PDNS_NETINFO pnetInfo;
  632. DWORD iter1;
  633. DWORD iter2;
  634. DWORD countNets = 0;
  635. // clear server list array
  636. RtlZeroMemory(
  637. DnsServerListArray,
  638. sizeof(PADDR_ARRAY) * ArrayLength );
  639. // build list from current netinfo
  640. pnetInfo = GetNetworkInfo();
  641. if ( ! pnetInfo )
  642. {
  643. return 0;
  644. }
  645. //
  646. // check if update is disabled
  647. // - update dependent on registration state
  648. // - global registration state is OFF
  649. // => then skip
  650. //
  651. if ( (Flags & DNS_UPDATE_SKIP_NO_UPDATE_ADAPTERS)
  652. &&
  653. ! g_RegistrationEnabled )
  654. {
  655. return 0;
  656. }
  657. //
  658. // build DNS server list for each updateable adapter
  659. //
  660. for ( iter1 = 0; iter1 < pnetInfo->AdapterCount; iter1++ )
  661. {
  662. PDNS_ADAPTER padapter;
  663. DWORD serverCount;
  664. PDNS_ADDR_ARRAY parray;
  665. if ( iter1 >= ArrayLength )
  666. {
  667. break;
  668. }
  669. padapter = NetInfo_GetAdapterByIndex( pnetInfo, iter1 );
  670. if ( !padapter )
  671. {
  672. continue;
  673. }
  674. // skip if no DNS servers
  675. if ( !padapter->pDnsAddrs )
  676. {
  677. continue;
  678. }
  679. // skip "no-update" adapter?
  680. // - if skip-disabled flag set for this update
  681. // - and no-update flag on adapter
  682. if ( (Flags & DNS_UPDATE_SKIP_NO_UPDATE_ADAPTERS) &&
  683. !(padapter->InfoFlags & AINFO_FLAG_REGISTER_IP_ADDRESSES) )
  684. {
  685. continue;
  686. }
  687. //
  688. // valid update adapter
  689. // - create\save DNS server list
  690. // - bump count of lists
  691. //
  692. // DCR: functionalize adapter DNS list to IP array
  693. //
  694. // DCR_PERF: collapse DNS server lists in netinfo BEFORE allocating them
  695. // in other words bring this function into collapse and fix
  696. //
  697. parray = DnsAddrArray_CreateCopy( padapter->pDnsAddrs );
  698. if ( ! parray )
  699. {
  700. goto Exit;
  701. }
  702. DnsServerListArray[countNets] = parray;
  703. countNets++;
  704. }
  705. Exit:
  706. // free network info
  707. // return count of DNS server lists found
  708. NetInfo_Free( pnetInfo );
  709. return countNets;
  710. }
  711. DWORD
  712. cleanDeadAdaptersFromArray(
  713. IN OUT PADDR_ARRAY * IpArrayArray,
  714. IN OUT PDNS_NETINFO * NetworkInfoArray, OPTIONAL
  715. IN DWORD Count
  716. )
  717. /*++
  718. Routine Description:
  719. Cleanup and remove from array(s) adapter info, when an
  720. adapter is determined to be dead, useless or duplicate for
  721. the update.
  722. Arguments:
  723. IpArrayArray -- array of IP array pointers
  724. NetworkInfoArray -- array of ptrs to network info structs
  725. Count -- length arrays (current adapter count)
  726. Return Value:
  727. New adapter count.
  728. --*/
  729. {
  730. register DWORD iter;
  731. //
  732. // remove useless adapters
  733. // useless means no DNS server list
  734. //
  735. for ( iter = 0; iter < Count; iter++ )
  736. {
  737. PADDR_ARRAY parray = IpArrayArray[iter];
  738. if ( !parray || parray->AddrCount==0 )
  739. {
  740. if ( parray )
  741. {
  742. DnsAddrArray_Free( parray );
  743. IpArrayArray[ iter ] = NULL;
  744. }
  745. Count--;
  746. IpArrayArray[ iter ] = IpArrayArray[ Count ];
  747. IpArrayArray[ Count ] = NULL;
  748. // if have corresponding NetworkInfo array, clean it in same fashion
  749. if ( NetworkInfoArray )
  750. {
  751. if ( NetworkInfoArray[iter] )
  752. {
  753. NetInfo_Free( NetworkInfoArray[iter] );
  754. NetworkInfoArray[iter] = NULL;
  755. }
  756. NetworkInfoArray[ iter ] = NetworkInfoArray[ Count ];
  757. NetworkInfoArray[ Count ] = NULL;
  758. }
  759. }
  760. }
  761. // return count of cleaned list
  762. return Count;
  763. }
  764. DWORD
  765. eliminateDuplicateAdapterFromArrays(
  766. IN OUT PADDR_ARRAY* IpArrayArray,
  767. IN OUT PDNS_NETINFO * NetworkInfoArray,
  768. IN OUT PDNS_RECORD * NsRecordArray,
  769. IN DWORD Count,
  770. IN DWORD DuplicateIndex
  771. )
  772. /*++
  773. Routine Description:
  774. Cleanup and remove from array(s) adapter info, when an
  775. adapter is determined to be dead, useless or duplicate for
  776. the update.
  777. Arguments:
  778. IpArrayArray -- array of IP array pointers
  779. NetworkInfoArray -- array of ptrs to network info structs
  780. NsRecordArray -- array of NS record lists for FAZed zone
  781. Count -- length arrays (current adapter count)
  782. DuplicateIndex -- index of duplicate
  783. Return Value:
  784. New adapter count.
  785. --*/
  786. {
  787. ASSERT( DuplicateIndex < Count );
  788. DNSDBG( TRACE, (
  789. "eliminateDuplicateAdapterFromArrays( dup=%d, max=%d )\n",
  790. DuplicateIndex,
  791. Count ));
  792. //
  793. // free any info on duplicate adapter
  794. //
  795. FREE_HEAP( IpArrayArray[DuplicateIndex] );
  796. NetInfo_Free( NetworkInfoArray[DuplicateIndex] );
  797. Dns_RecordListFree( NsRecordArray[DuplicateIndex] );
  798. //
  799. // copy top entry to this spot
  800. //
  801. Count--;
  802. if ( Count != DuplicateIndex )
  803. {
  804. IpArrayArray[DuplicateIndex] = IpArrayArray[Count];
  805. NetworkInfoArray[DuplicateIndex] = NetworkInfoArray[Count];
  806. NsRecordArray[DuplicateIndex] = NsRecordArray[Count];
  807. }
  808. return Count;
  809. }
  810. DWORD
  811. combineDnsServerListsForTwoAdapters(
  812. IN OUT PADDR_ARRAY* IpArrayArray,
  813. IN DWORD Count,
  814. IN DWORD Index1,
  815. IN DWORD Index2
  816. )
  817. /*++
  818. Routine Description:
  819. Combine DNS server lists for two adapters.
  820. Note, this unions the DNS server lists for the two
  821. adapters and eliminates the higher indexed adapter
  822. from the list.
  823. Arguments:
  824. IpArrayArray -- array of IP array pointers
  825. Count -- length of pointer array
  826. Index1 -- low index to union
  827. Index2 -- high index to union
  828. Return Value:
  829. New adapter count.
  830. --*/
  831. {
  832. PADDR_ARRAY punionArray = NULL;
  833. DNSDBG( TRACE, (
  834. "combineDnsServerListsForTwoAdapters( count=%d, i1=%d, i2=%d )\n",
  835. Count,
  836. Index1,
  837. Index2 ));
  838. ASSERT( Index1 < Count );
  839. ASSERT( Index2 < Count );
  840. ASSERT( Index1 < Index2 );
  841. //
  842. // union the arrays
  843. //
  844. // if unable to allocate union, then just use list in first array
  845. // and dump second
  846. //
  847. DnsAddrArray_Union( IpArrayArray[Index1], IpArrayArray[Index2], &punionArray );
  848. if ( punionArray )
  849. {
  850. FREE_HEAP( IpArrayArray[Index1] );
  851. IpArrayArray[Index1] = punionArray;
  852. }
  853. FREE_HEAP( IpArrayArray[Index2] );
  854. IpArrayArray[Index2] = NULL;
  855. //
  856. // swap deleted entry with last entry in list
  857. //
  858. Count--;
  859. IpArrayArray[Index2] = IpArrayArray[ Count ];
  860. return( Count );
  861. }
  862. DNS_STATUS
  863. CollapseDnsServerListsForUpdate(
  864. IN OUT PADDR_ARRAY* DnsServerListArray,
  865. OUT PDNS_NETINFO * NetworkInfoArray,
  866. IN OUT PDWORD pNetCount,
  867. IN PWSTR pszUpdateName
  868. )
  869. /*++
  870. Routine Description:
  871. Builds update network info blob for each unique name space.
  872. This essentially starts with DNS server list for each adapter
  873. and progressively detects adapters pointing at same name space
  874. until down minimum number of name spaces.
  875. Arguments:
  876. DnsServerListArray -- array of ptrs to DNS server lists for each adapter
  877. NetworkInfoArray -- array to hold pointer to update network info for each
  878. adapter on return contains ptr to network info for each unique name
  879. space update should be sent to
  880. dwNetCount -- starting count of individual adapters networks
  881. pszUpdateName -- name to update
  882. Return Value:
  883. Count of unique name spaces to update.
  884. NetworkInfoArray contains update network info blob for each name space.
  885. --*/
  886. {
  887. PDNS_RECORD NsRecordArray[ UPDATE_ADAPTER_LIMIT ];
  888. PADDR_ARRAY parray1;
  889. DWORD iter1;
  890. DWORD iter2;
  891. DWORD maxCount = *pNetCount;
  892. DNS_STATUS status = DNS_ERROR_NO_DNS_SERVERS;
  893. DNSDBG( TRACE, (
  894. "collapseDnsServerListsForUpdate( count=%d )\n"
  895. "\tupdate name = %S\n",
  896. maxCount,
  897. pszUpdateName ));
  898. //
  899. // clean list of any useless adapters
  900. //
  901. maxCount = cleanDeadAdaptersFromArray(
  902. DnsServerListArray,
  903. NULL, // no network info yet
  904. maxCount );
  905. //
  906. // if only one adapter -- nothing to compare
  907. // - do FAZ to build update network info, if
  908. // successful, we're done
  909. //
  910. if ( maxCount <= 1 )
  911. {
  912. if ( maxCount == 1 )
  913. {
  914. NetworkInfoArray[0] = NULL;
  915. status = DoQuickFAZ(
  916. &NetworkInfoArray[0],
  917. pszUpdateName,
  918. DnsServerListArray[0] );
  919. if ( NetworkInfoArray[0] )
  920. {
  921. goto Done;
  922. }
  923. FREE_HEAP( DnsServerListArray[0] );
  924. maxCount = 0;
  925. goto Done;
  926. }
  927. goto Done;
  928. }
  929. //
  930. // clear NetworkInfo
  931. //
  932. RtlZeroMemory(
  933. NetworkInfoArray,
  934. maxCount * sizeof(PVOID) );
  935. //
  936. // loop through combining adapters with shared DNS servers
  937. //
  938. // as we combine entries we shrink the list
  939. //
  940. for ( iter1 = 0; iter1 < maxCount; iter1++ )
  941. {
  942. parray1 = DnsServerListArray[ iter1 ];
  943. for ( iter2=iter1+1; iter2 < maxCount; iter2++ )
  944. {
  945. if ( AddrArray_IsIntersection(
  946. parray1,
  947. DnsServerListArray[iter2] ) )
  948. {
  949. DNSDBG( UPDATE, (
  950. "collapseDSLFU: whacking intersecting DNS server lists\n"
  951. "\tadapters %d and %d (max =%d)\n",
  952. iter1,
  953. iter2,
  954. maxCount ));
  955. maxCount = combineDnsServerListsForTwoAdapters(
  956. DnsServerListArray,
  957. maxCount,
  958. iter1,
  959. iter2 );
  960. iter2--;
  961. parray1 = DnsServerListArray[ iter1 ];
  962. }
  963. }
  964. }
  965. DNSDBG( TRACE, (
  966. "collapseDSLFU: count after dup server whack = %d\n",
  967. maxCount ));
  968. #if 0
  969. // clean again, in case we missed something
  970. maxCount = cleanDeadAdaptersFromArray(
  971. DnsServerListArray,
  972. NULL, // no network info yet
  973. maxCount );
  974. #endif
  975. //
  976. // FAZ remaining adapters
  977. //
  978. // save result NetworkInfo struct
  979. // => for comparison to determine adapters that share DNS name space
  980. // => to return to caller to do actual update
  981. //
  982. // if FAZ fails this adapter is useless for update -- dead issue
  983. // adapter is removed and replaced by highest array entry
  984. //
  985. for ( iter1 = 0; iter1 < maxCount; iter1++ )
  986. {
  987. status = Faz_Private(
  988. pszUpdateName,
  989. DNS_QUERY_BYPASS_CACHE,
  990. DnsServerListArray[ iter1 ],
  991. & NetworkInfoArray[ iter1 ] );
  992. if ( status != ERROR_SUCCESS )
  993. {
  994. FREE_HEAP( DnsServerListArray[ iter1 ] );
  995. DnsServerListArray[ iter1 ] = NULL;
  996. maxCount--;
  997. DnsServerListArray[ iter1 ] = DnsServerListArray[ maxCount ];
  998. iter1--;
  999. continue;
  1000. }
  1001. }
  1002. #if 0
  1003. // clean out failed FAZ entries
  1004. maxCount = cleanDeadAdaptersFromArray(
  1005. DnsServerListArray,
  1006. NetworkInfoArray,
  1007. maxCount );
  1008. #endif
  1009. // if only able to FAZ one adapter -- we're done
  1010. // only point here is to skip a bunch of unnecessary
  1011. // stuff in the most typical case multi-adapter case
  1012. if ( maxCount <= 1 )
  1013. {
  1014. DNSDBG( TRACE, (
  1015. "collapseDSLFU: down to single FAZ adapter\n" ));
  1016. goto Done;
  1017. }
  1018. //
  1019. // compare FAZ results to see if adapters are in same name space
  1020. //
  1021. // do two passes
  1022. // - on first pass only compare based on FAZ results, if successful
  1023. // we eliminate duplicate adapter
  1024. //
  1025. // - on second pass, adapters that are still separate are compared;
  1026. // if they don't fail FAZ matches (which are retried) then NS queries
  1027. // are used to determine if separate nets;
  1028. // note that NS query results are saved, so NS query is order N, even
  1029. // though we are in N**2 loop
  1030. //
  1031. RtlZeroMemory(
  1032. NsRecordArray,
  1033. maxCount * sizeof(PVOID) );
  1034. for ( iter1=0; iter1 < maxCount; iter1++ )
  1035. {
  1036. for ( iter2=iter1+1; iter2 < maxCount; iter2++ )
  1037. {
  1038. if ( Faz_CompareTwoAdaptersForSameNameSpace(
  1039. DnsServerListArray[iter1],
  1040. NetworkInfoArray[iter1],
  1041. NULL, // no NS list
  1042. DnsServerListArray[iter2],
  1043. NetworkInfoArray[iter2],
  1044. NULL, // no NS list
  1045. FALSE // don't use NS queries
  1046. ) )
  1047. {
  1048. DNSDBG( UPDATE, (
  1049. "collapseDSLFU: whacking same-FAZ adapters\n"
  1050. "\tadapters %d and %d (max =%d)\n",
  1051. iter1,
  1052. iter2,
  1053. maxCount ));
  1054. eliminateDuplicateAdapterFromArrays(
  1055. DnsServerListArray,
  1056. NetworkInfoArray,
  1057. NsRecordArray,
  1058. maxCount,
  1059. iter2 );
  1060. maxCount--;
  1061. iter2--;
  1062. }
  1063. }
  1064. }
  1065. DNSDBG( TRACE, (
  1066. "collapseDSLFU: count after dup FAZ whack = %d\n",
  1067. maxCount ));
  1068. // second pass using NS info
  1069. // if NS info is created, we save it to avoid requery
  1070. for ( iter1=0; iter1 < maxCount; iter1++ )
  1071. {
  1072. for ( iter2=iter1+1; iter2 < maxCount; iter2++ )
  1073. {
  1074. if ( Faz_CompareTwoAdaptersForSameNameSpace(
  1075. DnsServerListArray[iter1],
  1076. NetworkInfoArray[iter1],
  1077. & NsRecordArray[iter1],
  1078. DnsServerListArray[iter2],
  1079. NetworkInfoArray[iter2],
  1080. & NsRecordArray[iter2],
  1081. TRUE // follow up with NS queries
  1082. ) )
  1083. {
  1084. DNSDBG( UPDATE, (
  1085. "collapseDSLFU: whacking same-zone-NS adapters\n"
  1086. "\tadapters %d and %d (max =%d)\n",
  1087. iter1,
  1088. iter2,
  1089. maxCount ));
  1090. eliminateDuplicateAdapterFromArrays(
  1091. DnsServerListArray,
  1092. NetworkInfoArray,
  1093. NsRecordArray,
  1094. maxCount,
  1095. iter2 );
  1096. maxCount--;
  1097. iter2--;
  1098. }
  1099. }
  1100. }
  1101. //
  1102. // kill off any NS records found
  1103. //
  1104. for ( iter1=0; iter1 < maxCount; iter1++ )
  1105. {
  1106. Dns_RecordListFree( NsRecordArray[iter1] );
  1107. }
  1108. Done:
  1109. //
  1110. // set count of remaining adapters (update DNS server lists)
  1111. //
  1112. // return status
  1113. // - success if have any update adapter
  1114. // - on failure bubble up FAZ error
  1115. //
  1116. DNSDBG( TRACE, (
  1117. "Leave CollapseDnsServerListsForUpdate( collapsed count=%d )\n",
  1118. maxCount ));
  1119. *pNetCount = maxCount;
  1120. if ( maxCount > 0 )
  1121. {
  1122. status = ERROR_SUCCESS;
  1123. }
  1124. return status;
  1125. }
  1126. BOOL
  1127. WINAPI
  1128. Faz_CompareTwoAdaptersForSameNameSpace(
  1129. IN PDNS_ADDR_ARRAY pDnsServerList1,
  1130. IN PDNS_NETINFO pNetInfo1,
  1131. IN OUT PDNS_RECORD * ppNsRecord1,
  1132. IN PDNS_ADDR_ARRAY pDnsServerList2,
  1133. IN PDNS_NETINFO pNetInfo2,
  1134. IN OUT PDNS_RECORD * ppNsRecord2,
  1135. IN BOOL bDoNsCheck
  1136. )
  1137. /*++
  1138. Routine Description:
  1139. Compare two adapters to see if in same name space for update.
  1140. Arguments:
  1141. pDnsServerList1 -- IP array of DNS servers for first adapter
  1142. pNetInfo1 -- update netinfo for first adapter
  1143. ppNsRecord1 -- addr of ptr to NS record list of update zone done on
  1144. first adapter; NULL if no NS check required; if
  1145. NS check required and *ppNsRecord1 is NULL, NS query
  1146. is made and results returned
  1147. pDnsServerList2 -- IP array of DNS servers for second adapter
  1148. pNetInfo2 -- update netinfo for second adapter
  1149. ppNsRecord2 -- addr of ptr to NS record list of update zone done on
  1150. second adapter; NULL if no NS check required; if
  1151. NS check required and *ppNsRecord2 is NULL, NS query
  1152. is made and results returned
  1153. bDoNsCheck -- include update-zone NS check compare; if NS overlap then
  1154. name spaces assumed to be the same
  1155. Return Value:
  1156. ERROR_SUCCESS if successful.
  1157. Error status on failure.
  1158. --*/
  1159. {
  1160. DNS_STATUS status = NO_ERROR;
  1161. BOOL fsame = FALSE;
  1162. PDNS_ADAPTER padapter1;
  1163. PDNS_ADAPTER padapter2;
  1164. PDNS_RECORD pns1 = NULL;
  1165. PDNS_RECORD pns2 = NULL;
  1166. PDNS_RECORD pnotUsed = NULL;
  1167. PWSTR pzoneName;
  1168. //
  1169. // done if bad params
  1170. //
  1171. if ( !pDnsServerList1 || !pDnsServerList2 )
  1172. {
  1173. return FALSE;
  1174. }
  1175. //
  1176. // validity check
  1177. // - note: could probably be just ASSERT()
  1178. //
  1179. if ( ! NetInfo_IsForUpdate(pNetInfo1) ||
  1180. ! NetInfo_IsForUpdate(pNetInfo2) )
  1181. {
  1182. ASSERT( FALSE );
  1183. return( FALSE );
  1184. }
  1185. //
  1186. // compare FAZ results
  1187. //
  1188. // first compare zone names
  1189. // if FAZ returns different zone names, then clearly
  1190. // have disjoint name spaces
  1191. //
  1192. pzoneName = NetInfo_UpdateZoneName( pNetInfo1 );
  1193. if ( ! Dns_NameCompare_W(
  1194. pzoneName,
  1195. NetInfo_UpdateZoneName( pNetInfo2 ) ) )
  1196. {
  1197. return FALSE;
  1198. }
  1199. //
  1200. // check if pointing at same server:
  1201. // - if have same update DNS server -- have a match
  1202. // - if same server name -- have a match
  1203. //
  1204. padapter1 = NetInfo_GetAdapterByIndex( pNetInfo1, 0 );
  1205. padapter2 = NetInfo_GetAdapterByIndex( pNetInfo2, 0 );
  1206. if ( DnsAddrArray_IsEqual(
  1207. padapter1->pDnsAddrs,
  1208. padapter2->pDnsAddrs,
  1209. DNSADDR_MATCH_ADDR ) )
  1210. {
  1211. return TRUE;
  1212. }
  1213. else
  1214. {
  1215. fsame = Dns_NameCompare_W(
  1216. NetInfo_UpdateServerName( pNetInfo1 ),
  1217. NetInfo_UpdateServerName( pNetInfo2 ) );
  1218. }
  1219. //
  1220. // if matched or not doing NS check => then done
  1221. //
  1222. if ( fsame || !bDoNsCheck )
  1223. {
  1224. return( fsame );
  1225. }
  1226. //
  1227. // NS check
  1228. //
  1229. // if not pointing at same server, may be two multimaster primaries
  1230. //
  1231. // use NS queries to determine if NS lists for same servers are in
  1232. // fact a match
  1233. //
  1234. if ( ppNsRecord1 )
  1235. {
  1236. pns1 = *ppNsRecord1;
  1237. }
  1238. if ( !pns1 )
  1239. {
  1240. status = Query_Private(
  1241. pzoneName,
  1242. DNS_TYPE_NS,
  1243. DNS_QUERY_BYPASS_CACHE,
  1244. pDnsServerList1,
  1245. &pns1 );
  1246. if ( status != ERROR_SUCCESS )
  1247. {
  1248. goto Done;
  1249. }
  1250. pnotUsed = DnsRecordSetDetach( pns1 );
  1251. if ( pnotUsed )
  1252. {
  1253. Dns_RecordListFree( pnotUsed );
  1254. pnotUsed = NULL;
  1255. }
  1256. }
  1257. if ( ppNsRecord2 )
  1258. {
  1259. pns2 = *ppNsRecord2;
  1260. }
  1261. if ( !pns2 )
  1262. {
  1263. status = Query_Private(
  1264. pzoneName,
  1265. DNS_TYPE_NS,
  1266. DNS_QUERY_BYPASS_CACHE,
  1267. pDnsServerList2,
  1268. &pns2 );
  1269. if ( status != ERROR_SUCCESS )
  1270. {
  1271. goto Done;
  1272. }
  1273. pnotUsed = DnsRecordSetDetach( pns2 );
  1274. if ( pnotUsed )
  1275. {
  1276. Dns_RecordListFree( pnotUsed );
  1277. pnotUsed = NULL;
  1278. }
  1279. }
  1280. //
  1281. // if NS lists the same -- same namespace
  1282. //
  1283. fsame = Dns_RecordSetCompareForIntersection( pns1, pns2 );
  1284. Done:
  1285. //
  1286. // cleanup or return NS lists
  1287. //
  1288. // note, purpose of returning is so caller can avoid requerying
  1289. // NS if must make compare against multiple other adapters
  1290. //
  1291. if ( ppNsRecord1 )
  1292. {
  1293. *ppNsRecord1 = pns1;
  1294. }
  1295. else
  1296. {
  1297. Dns_RecordListFree( pns1 );
  1298. }
  1299. if ( ppNsRecord2 )
  1300. {
  1301. *ppNsRecord2 = pns2;
  1302. }
  1303. else
  1304. {
  1305. Dns_RecordListFree( pns2 );
  1306. }
  1307. return fsame;
  1308. }
  1309. BOOL
  1310. WINAPI
  1311. Faz_AreServerListsInSameNameSpace(
  1312. IN PWSTR pszDomainName,
  1313. IN PADDR_ARRAY pServerList1,
  1314. IN PADDR_ARRAY pServerList2
  1315. )
  1316. /*++
  1317. Routine Description:
  1318. Compare two adapters to see if in same name space for update.
  1319. Arguments:
  1320. pszDomainName -- domain name to update
  1321. pServerList1 -- IP array of DNS servers for first adapter
  1322. pServerList2 -- IP array of DNS servers for second adapter
  1323. Return Value:
  1324. TRUE -- if adapters are found to be on same net
  1325. FALSE -- otherwise (definitely NOT or unable to determine)
  1326. --*/
  1327. {
  1328. DNS_STATUS status;
  1329. BOOL fsame = FALSE;
  1330. PDNS_NETINFO pnetInfo1 = NULL;
  1331. PDNS_NETINFO pnetInfo2 = NULL;
  1332. DNSDBG( TRACE, (
  1333. "Faz_AreServerListsInSameNameSpace()\n" ));
  1334. // bad param screening
  1335. if ( !pServerList1 || !pServerList2 || !pszDomainName )
  1336. {
  1337. return FALSE;
  1338. }
  1339. //
  1340. // compare DNS server lists
  1341. // if any overlap, them effectively in same DNS namespace
  1342. //
  1343. if ( AddrArray_IsIntersection( pServerList1, pServerList2 ) )
  1344. {
  1345. return TRUE;
  1346. }
  1347. //
  1348. // if no DNS server overlap, must compare FAZ results
  1349. //
  1350. // note: FAZ failures interpreted as FALSE response
  1351. // required for callers in asyncreg.c
  1352. //
  1353. status = Faz_Private(
  1354. pszDomainName,
  1355. DNS_QUERY_BYPASS_CACHE,
  1356. pServerList1,
  1357. &pnetInfo1 );
  1358. if ( status != ERROR_SUCCESS )
  1359. {
  1360. goto Cleanup;
  1361. }
  1362. status = Faz_Private(
  1363. pszDomainName,
  1364. DNS_QUERY_BYPASS_CACHE,
  1365. pServerList2,
  1366. &pnetInfo2 );
  1367. if ( status != ERROR_SUCCESS )
  1368. {
  1369. goto Cleanup;
  1370. }
  1371. //
  1372. // call the comparison routine
  1373. //
  1374. fsame = Faz_CompareTwoAdaptersForSameNameSpace(
  1375. pServerList1,
  1376. pnetInfo1,
  1377. NULL, // no NS record list
  1378. pServerList2,
  1379. pnetInfo2,
  1380. NULL, // no NS record list
  1381. TRUE // follow up with NS queries
  1382. );
  1383. Cleanup:
  1384. NetInfo_Free( pnetInfo1 );
  1385. NetInfo_Free( pnetInfo2 );
  1386. return fsame;
  1387. }
  1388. BOOL
  1389. WINAPI
  1390. CompareMultiAdapterSOAQueries(
  1391. IN PWSTR pszDomainName,
  1392. IN PIP4_ARRAY pServerList1,
  1393. IN PIP4_ARRAY pServerList2
  1394. )
  1395. /*++
  1396. Routine Description:
  1397. Compare two adapters to see if in same name space for update.
  1398. Note, IP4 routine called by asyncreg.c code.
  1399. The working routine is Faz_CompareServerListsForSameNameSpace().
  1400. Arguments:
  1401. pszDomainName -- domain name to update
  1402. pServerList1 -- IP array of DNS servers for first adapter
  1403. pServerList2 -- IP array of DNS servers for second adapter
  1404. Return Value:
  1405. TRUE -- if adapters are found to be on same net
  1406. FALSE -- otherwise (definitely NOT or unable to determine)
  1407. --*/
  1408. {
  1409. PADDR_ARRAY parray1;
  1410. PADDR_ARRAY parray2;
  1411. BOOL bresult;
  1412. DNSDBG( TRACE, (
  1413. "CompareMultiAdapterSOAQueries()\n" ));
  1414. parray1 = DnsAddrArray_CreateFromIp4Array( pServerList1 );
  1415. parray2 = DnsAddrArray_CreateFromIp4Array( pServerList2 );
  1416. bresult = Faz_AreServerListsInSameNameSpace(
  1417. pszDomainName,
  1418. parray1,
  1419. parray2 );
  1420. DnsAddrArray_Free( parray1 );
  1421. DnsAddrArray_Free( parray2 );
  1422. return bresult;
  1423. }
  1424. //
  1425. // DCR: IP6 support for FAZ NS list address grab
  1426. //
  1427. IP4_ADDRESS
  1428. FindHostIpAddressInRecordList(
  1429. IN PDNS_RECORD pRecordList,
  1430. IN PWSTR pszHostName
  1431. )
  1432. /*++
  1433. Routine Description:
  1434. Find IP for hostname, if its A record is in list.
  1435. NOTE: This code was borrowed from \dns\dnslib\query.c! ;-)
  1436. Arguments:
  1437. pRecordList - incoming RR set
  1438. pszHostName - hostname to find
  1439. Return Value:
  1440. IP address matching hostname, if A record for hostname found.
  1441. Zero if not found.
  1442. --*/
  1443. {
  1444. register PDNS_RECORD prr = pRecordList;
  1445. //
  1446. // loop through all records until find IP matching hostname
  1447. //
  1448. while ( prr )
  1449. {
  1450. if ( prr->wType == DNS_TYPE_A &&
  1451. Dns_NameCompare_W(
  1452. prr->pName,
  1453. pszHostName ) )
  1454. {
  1455. return( prr->Data.A.IpAddress );
  1456. }
  1457. prr = prr->pNext;
  1458. }
  1459. return( 0 );
  1460. }
  1461. PADDR_ARRAY
  1462. GetNameServersListForDomain(
  1463. IN PWSTR pDomainName,
  1464. IN PADDR_ARRAY pServerList
  1465. )
  1466. /*++
  1467. Routine Description:
  1468. Get IPs for all DNS servers for zone.
  1469. Arguments:
  1470. pDomainName -- zone name
  1471. pServerList -- server list to query
  1472. Return Value:
  1473. IP array of IPs of DNS servers for zone.
  1474. NULL if error.
  1475. --*/
  1476. {
  1477. DNS_STATUS status = NO_ERROR;
  1478. PDNS_RECORD prrQuery = NULL;
  1479. PADDR_ARRAY pnsArray = NULL;
  1480. DWORD countAddr = 0;
  1481. DNSDBG( TRACE, (
  1482. "GetNameServersListForDomain()\n"
  1483. "\tdomain name %S\n"
  1484. "\tserver list %p\n",
  1485. pDomainName,
  1486. pServerList ));
  1487. status = Query_Private(
  1488. pDomainName,
  1489. DNS_TYPE_NS,
  1490. DNS_QUERY_BYPASS_CACHE,
  1491. pServerList,
  1492. &prrQuery );
  1493. if ( status == NO_ERROR )
  1494. {
  1495. PDNS_RECORD pTemp = prrQuery;
  1496. DWORD dwCount = 0;
  1497. while ( pTemp )
  1498. {
  1499. dwCount++;
  1500. pTemp = pTemp->pNext;
  1501. }
  1502. pnsArray = DnsAddrArray_Create( dwCount );
  1503. if ( pnsArray )
  1504. {
  1505. pTemp = prrQuery;
  1506. while ( pTemp )
  1507. {
  1508. if ( pTemp->wType == DNS_TYPE_NS )
  1509. {
  1510. IP4_ADDRESS ip = 0;
  1511. ip = FindHostIpAddressInRecordList(
  1512. pTemp,
  1513. pTemp->Data.NS.pNameHost );
  1514. if ( !ip )
  1515. {
  1516. PDNS_RECORD pARecord = NULL;
  1517. //
  1518. // Query again to get the server's address
  1519. //
  1520. status = Query_Private(
  1521. pTemp->Data.NS.pNameHost,
  1522. DNS_TYPE_A,
  1523. DNS_QUERY_BYPASS_CACHE,
  1524. pServerList,
  1525. &pARecord );
  1526. if ( status == NO_ERROR &&
  1527. pARecord )
  1528. {
  1529. ip = pARecord->Data.A.IpAddress;
  1530. Dns_RecordListFree( pARecord );
  1531. }
  1532. }
  1533. if ( ip )
  1534. {
  1535. DnsAddrArray_AddIp4(
  1536. pnsArray,
  1537. ip,
  1538. TRUE );
  1539. }
  1540. }
  1541. pTemp = pTemp->pNext;
  1542. }
  1543. }
  1544. }
  1545. if ( prrQuery )
  1546. {
  1547. Dns_RecordListFree( prrQuery );
  1548. }
  1549. return pnsArray;
  1550. }
  1551. //
  1552. // Root server screening
  1553. //
  1554. // Root servers as of .net 2003 ship:
  1555. // 198.41.0.4
  1556. // 128.9.0.107
  1557. // 192.33.4.12
  1558. // 128.8.10.90
  1559. // 192.203.230.10
  1560. // 192.5.5.241
  1561. // 192.112.36.4
  1562. // 128.63.2.53
  1563. // 192.36.148.17
  1564. // 192.58.128.30
  1565. // 193.0.14.129
  1566. // 198.32.64.12
  1567. // 202.12.27.33
  1568. //
  1569. IP4_ADDRESS g_RootServers4[] =
  1570. {
  1571. 0x040029c6,
  1572. 0x6b000980,
  1573. 0x0c0421c0,
  1574. 0x5a0a0880,
  1575. 0x0ae6cbc0,
  1576. 0xf10505c0,
  1577. 0x042470c0,
  1578. 0x35023f80,
  1579. 0x119424c0,
  1580. 0x1e803ac0,
  1581. 0x810e00c1,
  1582. 0x0c4020c6,
  1583. 0x211b0cca,
  1584. 0
  1585. };
  1586. BOOL
  1587. IsRootServerAddressIp4(
  1588. IN IP4_ADDRESS Ip
  1589. )
  1590. /*++
  1591. Routine Description:
  1592. Determine if address is root server address.
  1593. Arguments:
  1594. Ip -- IP to screen
  1595. Return Value:
  1596. TRUE if root server address.
  1597. FALSE otherwise.
  1598. --*/
  1599. {
  1600. DWORD iter;
  1601. IP4_ADDRESS rootIp;
  1602. //
  1603. // check against all root servers
  1604. //
  1605. iter = 0;
  1606. while ( (rootIp = g_RootServers4[iter++]) != 0 )
  1607. {
  1608. if ( rootIp == Ip )
  1609. {
  1610. return TRUE;
  1611. }
  1612. }
  1613. return FALSE;
  1614. }
  1615. //
  1616. // End of faz.c
  1617. //