Source code of Windows XP (NT5)
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.

2129 lines
49 KiB

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