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.

4562 lines
104 KiB

  1. /*++
  2. Copyright (c) 2000-2001 Microsoft Corporation
  3. Module Name:
  4. netinfo.c
  5. Abstract:
  6. Domain Name System (DNS) API
  7. DNS network info routines.
  8. Author:
  9. Jim Gilroy (jamesg) March 2000
  10. Revision History:
  11. --*/
  12. #include "local.h"
  13. #include "registry.h" // Registry reading definitions
  14. // Netinfo cache
  15. //
  16. // Do in process caching of netinfo for brief period for perf
  17. // Currently cache for only 10s
  18. // Locking currently just using general CS
  19. //
  20. PDNS_NETINFO g_pNetInfo = NULL;
  21. #define NETINFO_CACHE_TIMEOUT (15) // 15 seconds
  22. BOOL g_NetInfoCacheLockInitialized = FALSE;
  23. CRITICAL_SECTION g_NetInfoCacheLock;
  24. #define LOCK_NETINFO_CACHE() EnterCriticalSection( &g_NetInfoCacheLock );
  25. #define UNLOCK_NETINFO_CACHE() LeaveCriticalSection( &g_NetInfoCacheLock );
  26. //
  27. // Netinfo build requires drop into other services
  28. // which could
  29. // a) be waiting
  30. // b) have dependencies back on DNS
  31. // so we protect with timed lock -- failing if not complete in a few seconds.
  32. //
  33. BOOL g_NetInfoBuildLockInitialized = FALSE;
  34. TIMED_LOCK g_NetInfoBuildLock;
  35. #define LOCK_NETINFO_BUILD() TimedLock_Enter( &g_NetInfoBuildLock, 5000 );
  36. #define UNLOCK_NETINFO_BUILD() TimedLock_Leave( &g_NetInfoBuildLock );
  37. //
  38. // DNS_ADDR screening
  39. //
  40. // Use a user-defined field in DNS_ADDR as screening mask, in screening function.
  41. // Mask is set in screening address.
  42. #define DnsAddrFlagScreeningMask DnsAddrUser1Dword1
  43. VOID
  44. AdapterInfo_Free(
  45. IN OUT PDNS_ADAPTER pAdapter,
  46. IN BOOL fFreeAdapterStruct
  47. )
  48. /*++
  49. Routine Description:
  50. Free DNS_ADAPTER structure.
  51. Arguments:
  52. pAdapter -- pointer to adapter blob to free
  53. Return Value:
  54. None.
  55. --*/
  56. {
  57. DNSDBG( TRACE, ( "AdapterInfo_Free( %p, %d )\n", pAdapter, fFreeAdapterStruct ));
  58. if ( !pAdapter )
  59. {
  60. return;
  61. }
  62. if ( pAdapter->pszAdapterGuidName )
  63. {
  64. FREE_HEAP( pAdapter->pszAdapterGuidName );
  65. }
  66. if ( pAdapter->pszAdapterDomain )
  67. {
  68. FREE_HEAP( pAdapter->pszAdapterDomain );
  69. }
  70. if ( pAdapter->pLocalAddrs )
  71. {
  72. FREE_HEAP( pAdapter->pLocalAddrs );
  73. }
  74. if ( pAdapter->pDnsAddrs )
  75. {
  76. FREE_HEAP( pAdapter->pDnsAddrs );
  77. }
  78. if ( fFreeAdapterStruct )
  79. {
  80. FREE_HEAP( pAdapter );
  81. }
  82. }
  83. VOID
  84. AdapterInfo_Init(
  85. OUT PDNS_ADAPTER pAdapter,
  86. IN BOOL fZeroInit,
  87. IN DWORD InfoFlags,
  88. IN PWSTR pszGuidName,
  89. IN PWSTR pszDomain,
  90. IN PDNS_ADDR_ARRAY pLocalAddrs,
  91. IN PDNS_ADDR_ARRAY pDnsAddrs
  92. )
  93. /*++
  94. Routine Description:
  95. Init adapter info blob.
  96. This sets the blob DIRECTLY with these pointers,
  97. no reallocation.
  98. Arguments:
  99. pAdapter -- adapter blob to fill in
  100. fZeroInit -- clear to zero
  101. InfoFlags -- flags
  102. pszGuidName -- GUID name
  103. pszAdapterDomain -- adapter domain name
  104. pLocalAddrs -- local addrs
  105. pDnsAddrs -- DNS server addrs
  106. Return Value:
  107. Ptr to adapter info, if successful
  108. NULL on failure.
  109. --*/
  110. {
  111. DNSDBG( TRACE, ( "AdapterInfo_Init()\n" ));
  112. //
  113. // setup adapter info blob
  114. //
  115. if ( fZeroInit )
  116. {
  117. RtlZeroMemory(
  118. pAdapter,
  119. sizeof( *pAdapter ) );
  120. }
  121. // names
  122. pAdapter->pszAdapterGuidName = pszGuidName;
  123. pAdapter->pszAdapterDomain = pszDomain;
  124. pAdapter->pLocalAddrs = pLocalAddrs;
  125. pAdapter->pDnsAddrs = pDnsAddrs;
  126. // if no DNS servers -- set ignore flag
  127. if ( fZeroInit && !pDnsAddrs )
  128. {
  129. InfoFlags |= AINFO_FLAG_IGNORE_ADAPTER;
  130. }
  131. pAdapter->InfoFlags = InfoFlags;
  132. }
  133. DNS_STATUS
  134. AdapterInfo_Create(
  135. OUT PDNS_ADAPTER pAdapter,
  136. IN BOOL fZeroInit,
  137. IN DWORD InfoFlags,
  138. IN PWSTR pszGuidName,
  139. IN PWSTR pszDomain,
  140. IN PDNS_ADDR_ARRAY pLocalAddrs,
  141. IN PDNS_ADDR_ARRAY pDnsAddrs
  142. )
  143. /*++
  144. Routine Description:
  145. Create adapter info blob.
  146. This initializes blob with copies of names and addr arrays
  147. provided.
  148. Arguments:
  149. pAdapter -- adapter blob to fill in
  150. fZeroInit -- clear to zero
  151. InfoFlags -- flags
  152. pszGuidName -- GUID name
  153. pszAdapterDomain -- adapter domain name
  154. pLocalAddrs -- local addrs
  155. pDnsAddrs -- DNS server addrs
  156. Return Value:
  157. Ptr to adapter info, if successful
  158. NULL on failure.
  159. --*/
  160. {
  161. PDNS_ADDR_ARRAY paddrs;
  162. PWSTR pname;
  163. DNSDBG( TRACE, ( "AdapterInfo_Create()\n" ));
  164. //
  165. // setup adapter info blob
  166. //
  167. if ( fZeroInit )
  168. {
  169. RtlZeroMemory(
  170. pAdapter,
  171. sizeof( *pAdapter ) );
  172. }
  173. // names
  174. if ( pszGuidName )
  175. {
  176. pname = Dns_CreateStringCopy_W( pszGuidName );
  177. if ( !pname )
  178. {
  179. goto Failed;
  180. }
  181. pAdapter->pszAdapterGuidName = pname;
  182. }
  183. if ( pszDomain )
  184. {
  185. pname = Dns_CreateStringCopy_W( pszDomain );
  186. if ( !pname )
  187. {
  188. goto Failed;
  189. }
  190. pAdapter->pszAdapterDomain = pname;
  191. }
  192. // addresses
  193. if ( pLocalAddrs )
  194. {
  195. paddrs = DnsAddrArray_CreateCopy( pLocalAddrs );
  196. if ( !paddrs )
  197. {
  198. goto Failed;
  199. }
  200. pAdapter->pLocalAddrs = paddrs;
  201. }
  202. if ( pDnsAddrs )
  203. {
  204. paddrs = DnsAddrArray_CreateCopy( pDnsAddrs );
  205. if ( !paddrs )
  206. {
  207. goto Failed;
  208. }
  209. pAdapter->pDnsAddrs = paddrs;
  210. }
  211. // if no DNS servers -- set ignore flag
  212. if ( fZeroInit && !paddrs )
  213. {
  214. InfoFlags |= AINFO_FLAG_IGNORE_ADAPTER;
  215. }
  216. pAdapter->InfoFlags = InfoFlags;
  217. return NO_ERROR;
  218. Failed:
  219. AdapterInfo_Free(
  220. pAdapter,
  221. FALSE // no structure free
  222. );
  223. return DNS_ERROR_NO_MEMORY;
  224. }
  225. DNS_STATUS
  226. AdapterInfo_Copy(
  227. OUT PDNS_ADAPTER pCopy,
  228. IN PDNS_ADAPTER pAdapter
  229. )
  230. /*++
  231. Routine Description:
  232. Create copy of DNS adapter info.
  233. Arguments:
  234. pAdapter -- DNS adapter to copy
  235. Return Value:
  236. Ptr to DNS adapter info copy, if successful
  237. NULL on failure.
  238. --*/
  239. {
  240. DNS_STATUS status;
  241. DNSDBG( TRACE, ( "AdapterInfo_Copy( %p )\n", pAdapter ));
  242. if ( !pAdapter || !pCopy )
  243. {
  244. return ERROR_INVALID_PARAMETER;
  245. }
  246. //
  247. // copy all fields
  248. //
  249. RtlCopyMemory(
  250. pCopy,
  251. pAdapter,
  252. sizeof( *pAdapter ) );
  253. pCopy->pszAdapterGuidName = NULL;
  254. pCopy->pszAdapterDomain = NULL;
  255. pCopy->pLocalAddrs = NULL;
  256. pCopy->pDnsAddrs = NULL;
  257. //
  258. // do create copy
  259. //
  260. return AdapterInfo_Create(
  261. pCopy,
  262. FALSE, // no zero init
  263. pAdapter->InfoFlags,
  264. pAdapter->pszAdapterGuidName,
  265. pAdapter->pszAdapterDomain,
  266. pAdapter->pLocalAddrs,
  267. pAdapter->pDnsAddrs );
  268. }
  269. DNS_STATUS
  270. AdapterInfo_CreateFromIp4Array(
  271. OUT PDNS_ADAPTER pAdapter,
  272. IN PIP4_ARRAY pServerArray,
  273. IN DWORD Flags,
  274. IN PWSTR pszDomainName,
  275. IN PWSTR pszGuidName
  276. )
  277. /*++
  278. Routine Description:
  279. Create copy of IP address array as a DNS Server list.
  280. Arguments:
  281. pIpArray -- IP address array to convert
  282. Flags -- Flags that describe the adapter
  283. pszDomainName -- The default domain name for the adapter
  284. pszGuidName -- The registry GUID name for the adapter (if NT)
  285. Return Value:
  286. ERROR_SUCCESS if successful.
  287. ErrorCode on error.
  288. --*/
  289. {
  290. DNS_STATUS status;
  291. PDNS_ADDR_ARRAY pdnsArray;
  292. DWORD i;
  293. DWORD count;
  294. DNSDBG( TRACE, ( "AdapterInfo_CreateFromIp4Array()\n" ));
  295. //
  296. // get count of DNS servers
  297. //
  298. if ( !pServerArray )
  299. {
  300. count = 0;
  301. }
  302. else
  303. {
  304. count = pServerArray->AddrCount;
  305. }
  306. //
  307. // copy DNS server IPs
  308. //
  309. pdnsArray = DnsAddrArray_CreateFromIp4Array( pServerArray );
  310. if ( !pdnsArray )
  311. {
  312. status = DNS_ERROR_NO_MEMORY;
  313. goto Done;
  314. }
  315. //
  316. // build adapter info
  317. //
  318. status = AdapterInfo_Create(
  319. pAdapter,
  320. TRUE, // zero init
  321. Flags,
  322. pszDomainName,
  323. pszGuidName,
  324. NULL,
  325. pdnsArray );
  326. Done:
  327. DnsAddrArray_Free( pdnsArray );
  328. return status;
  329. }
  330. //
  331. // Search list routines
  332. //
  333. PSEARCH_LIST
  334. SearchList_Alloc(
  335. IN DWORD MaxNameCount
  336. )
  337. /*++
  338. Routine Description:
  339. Create uninitialized search list.
  340. Arguments:
  341. NameCount -- count of search names list will hold
  342. Return Value:
  343. Ptr to uninitialized DNS search list, if successful
  344. NULL on failure.
  345. --*/
  346. {
  347. PSEARCH_LIST psearchList = NULL;
  348. DWORD length;
  349. DNSDBG( TRACE, ( "SearchList_Alloc()\n" ));
  350. //
  351. // note: specifically allowing alloc even if no name count
  352. // or domain name as could have no PDN and still need
  353. // search list referenced in query
  354. //
  355. #if 0
  356. if ( MaxNameCount == 0 )
  357. {
  358. return NULL;
  359. }
  360. #endif
  361. //
  362. // allocate for max entries
  363. //
  364. length = sizeof(SEARCH_LIST)
  365. - sizeof(SEARCH_NAME)
  366. + ( sizeof(SEARCH_NAME) * MaxNameCount );
  367. psearchList = (PSEARCH_LIST) ALLOCATE_HEAP_ZERO( length );
  368. if ( ! psearchList )
  369. {
  370. return NULL;
  371. }
  372. psearchList->MaxNameCount = MaxNameCount;
  373. return psearchList;
  374. }
  375. VOID
  376. SearchList_Free(
  377. IN OUT PSEARCH_LIST pSearchList
  378. )
  379. /*++
  380. Routine Description:
  381. Free SEARCH_LIST structure.
  382. Arguments:
  383. pSearchList -- ptr to search list to free
  384. Return Value:
  385. None
  386. --*/
  387. {
  388. DWORD i;
  389. DNSDBG( TRACE, ( "SearchList_Free( %p )\n", pSearchList ));
  390. //
  391. // free all search names, then list itself
  392. //
  393. if ( pSearchList )
  394. {
  395. for ( i=0; i < pSearchList->NameCount; i++ )
  396. {
  397. PWSTR pname = pSearchList->SearchNameArray[i].pszName;
  398. if ( pname )
  399. {
  400. FREE_HEAP( pname );
  401. }
  402. }
  403. FREE_HEAP( pSearchList );
  404. }
  405. }
  406. PSEARCH_LIST
  407. SearchList_Copy(
  408. IN PSEARCH_LIST pSearchList
  409. )
  410. /*++
  411. Routine Description:
  412. Create copy of search list.
  413. Arguments:
  414. pSearchList -- search list to copy
  415. Return Value:
  416. Ptr to DNS Search list copy, if successful
  417. NULL on failure.
  418. --*/
  419. {
  420. PSEARCH_LIST pcopy;
  421. DWORD i;
  422. DNSDBG( TRACE, ( "SearchList_Copy()\n" ));
  423. if ( ! pSearchList )
  424. {
  425. return NULL;
  426. }
  427. //
  428. // create DNS Search list of desired size
  429. //
  430. // since we don't add and delete from search list once
  431. // created, size copy only for actual name count
  432. //
  433. pcopy = SearchList_Alloc( pSearchList->NameCount );
  434. if ( ! pcopy )
  435. {
  436. return NULL;
  437. }
  438. for ( i=0; i < pSearchList->NameCount; i++ )
  439. {
  440. PWSTR pname = pSearchList->SearchNameArray[i].pszName;
  441. if ( pname )
  442. {
  443. pname = Dns_CreateStringCopy_W( pname );
  444. if ( pname )
  445. {
  446. pcopy->SearchNameArray[i].pszName = pname;
  447. pcopy->SearchNameArray[i].Flags = pSearchList->SearchNameArray[i].Flags;
  448. pcopy->NameCount++;
  449. }
  450. }
  451. }
  452. return pcopy;
  453. }
  454. BOOL
  455. SearchList_ContainsName(
  456. IN PSEARCH_LIST pSearchList,
  457. IN PWSTR pszName
  458. )
  459. /*++
  460. Routine Description:
  461. Check if name is in search list.
  462. Arguments:
  463. pSearchList -- ptr to search list being built
  464. pszName -- name to check
  465. Return Value:
  466. TRUE if name is in search list.
  467. FALSE otherwise.
  468. --*/
  469. {
  470. DWORD count = pSearchList->NameCount;
  471. //
  472. // check every search list entry for this name
  473. //
  474. while ( count-- )
  475. {
  476. if ( Dns_NameCompare_W(
  477. pSearchList->SearchNameArray[ count ].pszName,
  478. pszName ) )
  479. {
  480. return( TRUE );
  481. }
  482. }
  483. return( FALSE );
  484. }
  485. VOID
  486. SearchList_AddName(
  487. IN OUT PSEARCH_LIST pSearchList,
  488. IN PWSTR pszName,
  489. IN DWORD Flag
  490. )
  491. /*++
  492. Routine Description:
  493. Add name to search list.
  494. Arguments:
  495. pSearchList -- ptr to search list being built
  496. pszName -- name to add to search list
  497. Flag -- flag value
  498. Return Value:
  499. None. Name is added to search list, unless memory alloc failure.
  500. --*/
  501. {
  502. DWORD count = pSearchList->NameCount;
  503. PWSTR pallocName;
  504. DNSDBG( TRACE, ( "Search_AddName()\n" ));
  505. //
  506. // ignore name is already in list
  507. // ignore if at list max
  508. //
  509. if ( SearchList_ContainsName(
  510. pSearchList,
  511. pszName )
  512. ||
  513. count >= pSearchList->MaxNameCount )
  514. {
  515. return;
  516. }
  517. // copy name and put in list
  518. pallocName = Dns_CreateStringCopy_W( pszName );
  519. if ( !pallocName )
  520. {
  521. return;
  522. }
  523. pSearchList->SearchNameArray[count].pszName = pallocName;
  524. //
  525. // set flag -- but first flag always zero (normal timeouts)
  526. // this protects against no PDN situation where use adapter
  527. // name as PDN;
  528. if ( count == 0 )
  529. {
  530. Flag = 0;
  531. }
  532. pSearchList->SearchNameArray[count].Flags = Flag;
  533. pSearchList->NameCount = ++count;
  534. }
  535. DNS_STATUS
  536. SearchList_Parse(
  537. IN OUT PSEARCH_LIST pSearchList,
  538. IN PWSTR pszList
  539. )
  540. /*++
  541. Routine Description:
  542. Parse registry search list string into SEARCH_LIST structure.
  543. Arguments:
  544. pSearchList -- search list array
  545. pszList -- registry list of search names;
  546. names are comma or white space separated
  547. Return Value:
  548. ERROR_SUCCESS if successful.
  549. Error code on failure.
  550. --*/
  551. {
  552. register PWCHAR pch = pszList;
  553. WCHAR ch;
  554. PWCHAR pnameStart;
  555. PWSTR pname;
  556. DWORD countNames = pSearchList->NameCount;
  557. DNSDBG( NETINFO, (
  558. "SearchList_Parse( %p, %S )\n",
  559. pSearchList,
  560. pszList ));
  561. //
  562. // extract each domain name string in buffer,
  563. // and add to search list array
  564. //
  565. while( ch = *pch && countNames < MAX_SEARCH_LIST_ENTRIES )
  566. {
  567. // skip leading whitespace, find start of domain name string
  568. while( ch == ' ' || ch == '\t' || ch == ',' )
  569. {
  570. ch = *++pch;
  571. }
  572. if ( ch == 0 )
  573. {
  574. break;
  575. }
  576. pnameStart = pch;
  577. //
  578. // find end of string and NULL terminate
  579. //
  580. ch = *pch;
  581. while( ch != L' ' && ch != L'\t' && ch != L'\0' && ch != L',' )
  582. {
  583. ch = *++pch;
  584. }
  585. *pch = L'\0';
  586. //
  587. // end of buffer?
  588. //
  589. if ( pch == pnameStart )
  590. {
  591. break;
  592. }
  593. //
  594. // whack any trailing dot on name
  595. //
  596. pch--;
  597. if ( *pch == L'.' )
  598. {
  599. *pch = L'\0';
  600. }
  601. pch++;
  602. //
  603. // make copy of the name
  604. //
  605. pname = Dns_CreateStringCopy_W( pnameStart );
  606. if ( pname )
  607. {
  608. pSearchList->SearchNameArray[ countNames ].pszName = pname;
  609. pSearchList->SearchNameArray[ countNames ].Flags = 0;
  610. countNames++;
  611. }
  612. // if more continue
  613. if ( ch != 0 )
  614. {
  615. pch++;
  616. continue;
  617. }
  618. break;
  619. }
  620. // reset name count
  621. pSearchList->NameCount = countNames;
  622. return( ERROR_SUCCESS );
  623. }
  624. PSEARCH_LIST
  625. SearchList_Build(
  626. IN PWSTR pszPrimaryDomainName,
  627. IN PREG_SESSION pRegSession,
  628. IN HKEY hKey,
  629. IN OUT PDNS_NETINFO pNetInfo,
  630. IN BOOL fUseDomainNameDevolution
  631. )
  632. /*++
  633. Routine Description:
  634. Build search list.
  635. Arguments:
  636. pszPrimaryDomainName -- primary domain name
  637. pRegSession -- registry session
  638. hKey -- registry key
  639. Return Value:
  640. Ptr to search list.
  641. NULL on error or no search list.
  642. --*/
  643. {
  644. PSEARCH_LIST ptempList;
  645. PWSTR pregList = NULL;
  646. DWORD status;
  647. DNSDBG( TRACE, ( "Search_ListBuild()\n" ));
  648. ASSERT( pRegSession || hKey );
  649. //
  650. // create search list using PDN
  651. //
  652. ptempList = SearchList_Alloc( MAX_SEARCH_LIST_ENTRIES );
  653. if ( !ptempList )
  654. {
  655. return( NULL );
  656. }
  657. //
  658. // read search list from registry
  659. //
  660. status = Reg_GetValue(
  661. pRegSession,
  662. hKey,
  663. RegIdSearchList,
  664. REGTYPE_SEARCH_LIST,
  665. (PBYTE*) &pregList
  666. );
  667. if ( status == ERROR_SUCCESS )
  668. {
  669. ASSERT( pregList != NULL );
  670. SearchList_Parse(
  671. ptempList,
  672. pregList );
  673. FREE_HEAP( pregList );
  674. }
  675. else if ( status == DNS_ERROR_NO_MEMORY )
  676. {
  677. FREE_HEAP( ptempList );
  678. return NULL;
  679. }
  680. //
  681. // if no registry search list -- build one
  682. //
  683. // DCR: eliminate autobuilt search list
  684. //
  685. if ( ! ptempList->NameCount )
  686. {
  687. //
  688. // use PDN in first search list slot
  689. //
  690. if ( pszPrimaryDomainName )
  691. {
  692. SearchList_AddName(
  693. ptempList,
  694. pszPrimaryDomainName,
  695. 0 );
  696. }
  697. //
  698. // add devolved PDN if have NameDevolution
  699. //
  700. // note, we devolve only down to second level
  701. // domain name "microsoft.com" NOT "com";
  702. // to avoid being fooled by name like "com."
  703. // also check that last dot is not terminal
  704. //
  705. if ( pszPrimaryDomainName && fUseDomainNameDevolution )
  706. {
  707. PWSTR pname = pszPrimaryDomainName;
  708. while ( pname )
  709. {
  710. PWSTR pnext = wcschr( pname, '.' );
  711. if ( !pnext )
  712. {
  713. break;
  714. }
  715. pnext++;
  716. if ( !*pnext )
  717. {
  718. //DNS_ASSERT( FALSE );
  719. break;
  720. }
  721. // add name, but not on first pass
  722. // - already have PDN in first slot
  723. if ( pname != pszPrimaryDomainName )
  724. {
  725. SearchList_AddName(
  726. ptempList,
  727. pname,
  728. DNS_QUERY_USE_QUICK_TIMEOUTS );
  729. }
  730. pname = pnext;
  731. }
  732. }
  733. // indicate this is dummy search list
  734. if ( pNetInfo )
  735. {
  736. pNetInfo->InfoFlags |= NINFO_FLAG_DUMMY_SEARCH_LIST;
  737. }
  738. }
  739. return ptempList;
  740. }
  741. PWSTR
  742. SearchList_GetNextName(
  743. IN OUT PSEARCH_LIST pSearchList,
  744. IN BOOL fReset,
  745. OUT PDWORD pdwSuffixFlags OPTIONAL
  746. )
  747. /*++
  748. Routine Description:
  749. Gets the next name from the search list.
  750. Arguments:
  751. pSearchList -- search list
  752. fReset -- TRUE to reset to beginning of search list
  753. pdwSuffixFlags -- flags associate with using this suffix
  754. Return Value:
  755. Ptr to the next search name. Note, this is a pointer
  756. to a name in the search list NOT an allocation. Search
  757. list structure must stay valid during use.
  758. NULL when out of search names.
  759. --*/
  760. {
  761. DWORD flag = 0;
  762. PWSTR pname = NULL;
  763. DWORD index;
  764. DNSDBG( TRACE, ( "SearchList_GetNextName()\n" ));
  765. // no list
  766. if ( !pSearchList )
  767. {
  768. goto Done;
  769. }
  770. //
  771. // reset?
  772. //
  773. if ( fReset )
  774. {
  775. pSearchList->CurrentNameIndex = 0;
  776. }
  777. //
  778. // if valid name -- retrieve it
  779. //
  780. index = pSearchList->CurrentNameIndex;
  781. if ( index < pSearchList->NameCount )
  782. {
  783. pname = pSearchList->SearchNameArray[index].pszName;
  784. flag = pSearchList->SearchNameArray[index].Flags;
  785. pSearchList->CurrentNameIndex = ++index;
  786. }
  787. Done:
  788. if ( pdwSuffixFlags )
  789. {
  790. *pdwSuffixFlags = flag;
  791. }
  792. return pname;
  793. }
  794. //
  795. // Net info routines
  796. //
  797. PDNS_NETINFO
  798. NetInfo_Alloc(
  799. IN DWORD AdapterCount
  800. )
  801. /*++
  802. Routine Description:
  803. Allocate network info.
  804. Arguments:
  805. AdapterCount -- count of net adapters info will hold
  806. Return Value:
  807. Ptr to uninitialized DNS network info, if successful
  808. NULL on failure.
  809. --*/
  810. {
  811. PDNS_NETINFO pnetInfo;
  812. DWORD length;
  813. DNSDBG( TRACE, ( "NetInfo_Alloc()\n" ));
  814. //
  815. // alloc
  816. // - zero to avoid garbage on early free
  817. //
  818. length = sizeof(DNS_NETINFO)
  819. - sizeof(DNS_ADAPTER)
  820. + (sizeof(DNS_ADAPTER) * AdapterCount);
  821. pnetInfo = (PDNS_NETINFO) ALLOCATE_HEAP_ZERO( length );
  822. if ( ! pnetInfo )
  823. {
  824. return NULL;
  825. }
  826. pnetInfo->MaxAdapterCount = AdapterCount;
  827. return( pnetInfo );
  828. }
  829. VOID
  830. NetInfo_Free(
  831. IN OUT PDNS_NETINFO pNetInfo
  832. )
  833. /*++
  834. Routine Description:
  835. Free DNS_NETINFO structure.
  836. Arguments:
  837. pNetInfo -- ptr to netinfo to free
  838. Return Value:
  839. None
  840. --*/
  841. {
  842. DWORD i;
  843. DNSDBG( TRACE, ( "NetInfo_Free( %p )\n", pNetInfo ));
  844. if ( ! pNetInfo )
  845. {
  846. return;
  847. }
  848. IF_DNSDBG( OFF )
  849. {
  850. DnsDbg_NetworkInfo(
  851. "Network Info before free: ",
  852. pNetInfo );
  853. }
  854. //
  855. // free
  856. // - search list
  857. // - domain name
  858. // - all the adapter info blobs
  859. //
  860. SearchList_Free( pNetInfo->pSearchList );
  861. if ( pNetInfo->pszDomainName )
  862. {
  863. FREE_HEAP( pNetInfo->pszDomainName );
  864. }
  865. if ( pNetInfo->pszHostName )
  866. {
  867. FREE_HEAP( pNetInfo->pszHostName );
  868. }
  869. for ( i=0; i < pNetInfo->AdapterCount; i++ )
  870. {
  871. AdapterInfo_Free(
  872. NetInfo_GetAdapterByIndex( pNetInfo, i ),
  873. FALSE // no structure free
  874. );
  875. }
  876. FREE_HEAP( pNetInfo );
  877. }
  878. PDNS_NETINFO
  879. NetInfo_Copy(
  880. IN PDNS_NETINFO pNetInfo
  881. )
  882. /*++
  883. Routine Description:
  884. Create copy of DNS Network info.
  885. Arguments:
  886. pNetInfo -- DNS Network info to copy
  887. Return Value:
  888. Ptr to DNS Network info copy, if successful
  889. NULL on failure.
  890. --*/
  891. {
  892. PDNS_NETINFO pcopy;
  893. PDNS_ADAPTER padapter;
  894. DWORD adapterCount;
  895. DNS_STATUS status;
  896. DWORD iter;
  897. DNSDBG( TRACE, ( "NetInfo_Copy( %p )\n", pNetInfo ));
  898. if ( ! pNetInfo )
  899. {
  900. return NULL;
  901. }
  902. IF_DNSDBG( OFF )
  903. {
  904. DnsDbg_NetworkInfo(
  905. "Netinfo to copy: ",
  906. pNetInfo );
  907. }
  908. //
  909. // create network info struct of desired size
  910. //
  911. pcopy = NetInfo_Alloc( pNetInfo->AdapterCount );
  912. if ( ! pcopy )
  913. {
  914. return NULL;
  915. }
  916. //
  917. // copy flat fields
  918. // - must reset MaxAdapterCount to actual allocation
  919. // - AdapterCount reset below
  920. //
  921. RtlCopyMemory(
  922. pcopy,
  923. pNetInfo,
  924. (PBYTE) &pcopy->AdapterArray[0] - (PBYTE)pcopy );
  925. pcopy->MaxAdapterCount = pNetInfo->AdapterCount;
  926. pcopy->AdapterCount = 0;
  927. //
  928. // copy subcomponents
  929. // - domain name
  930. // - search list
  931. //
  932. pcopy->pszDomainName = Dns_CreateStringCopy_W( pNetInfo->pszDomainName );
  933. pcopy->pszHostName = Dns_CreateStringCopy_W( pNetInfo->pszHostName );
  934. pcopy->pSearchList = SearchList_Copy( pNetInfo->pSearchList );
  935. if ( (!pcopy->pszDomainName && pNetInfo->pszDomainName) ||
  936. (!pcopy->pszHostName && pNetInfo->pszHostName) ||
  937. (!pcopy->pSearchList && pNetInfo->pSearchList) )
  938. {
  939. status = DNS_ERROR_NO_MEMORY;
  940. goto Failed;
  941. }
  942. //
  943. // copy adapter info
  944. //
  945. adapterCount = 0;
  946. for ( iter=0; iter<pNetInfo->AdapterCount; iter++ )
  947. {
  948. padapter = NetInfo_GetAdapterByIndex( pNetInfo, iter );
  949. status = AdapterInfo_Copy(
  950. &pcopy->AdapterArray[ adapterCount ],
  951. padapter
  952. );
  953. if ( status == NO_ERROR )
  954. {
  955. pcopy->AdapterCount = ++adapterCount;
  956. continue;
  957. }
  958. goto Failed;
  959. }
  960. IF_DNSDBG( OFF )
  961. {
  962. DnsDbg_NetworkInfo(
  963. "Netinfo copy: ",
  964. pcopy );
  965. }
  966. return pcopy;
  967. Failed:
  968. NetInfo_Free( pcopy );
  969. SetLastError( status );
  970. return NULL;
  971. }
  972. VOID
  973. NetInfo_Clean(
  974. IN OUT PDNS_NETINFO pNetInfo,
  975. IN DWORD ClearLevel
  976. )
  977. /*++
  978. Routine Description:
  979. Clean network info.
  980. Removes all query specific info and restores to
  981. state that is "fresh" for next query.
  982. Arguments:
  983. pNetInfo -- DNS network info
  984. ClearLevel -- level of runtime flag cleaning
  985. Return Value:
  986. None
  987. --*/
  988. {
  989. PDNS_ADAPTER padapter;
  990. DWORD iter;
  991. DNSDBG( TRACE, (
  992. "Enter NetInfo_Clean( %p, %08x )\n",
  993. pNetInfo,
  994. ClearLevel ));
  995. IF_DNSDBG( NETINFO2 )
  996. {
  997. DnsDbg_NetworkInfo(
  998. "Cleaning network info:",
  999. pNetInfo
  1000. );
  1001. }
  1002. //
  1003. // clean up info
  1004. // - clear status fields
  1005. // - clear RunFlags
  1006. // - clear temp bits on InfoFlags
  1007. //
  1008. // note, runtime flags are wiped depending on level
  1009. // specified in call
  1010. // - all (includes disabled\timedout adapter info)
  1011. // - query (all query info)
  1012. // - name (all info for single name query)
  1013. //
  1014. // finally we set NETINFO_PREPARED flag so that we can
  1015. // can check for and do this initialization in the send
  1016. // code if not previously done;
  1017. //
  1018. // in the standard query path we can
  1019. // - do this init
  1020. // - disallow adapters based on query name
  1021. // - send without the info getting wiped
  1022. //
  1023. // in other send paths
  1024. // - send checks that NETINFO_PREPARED is not set
  1025. // - does basic init
  1026. //
  1027. pNetInfo->ReturnFlags &= ClearLevel;
  1028. pNetInfo->ReturnFlags |= RUN_FLAG_NETINFO_PREPARED;
  1029. for ( iter=0; iter<pNetInfo->AdapterCount; iter++ )
  1030. {
  1031. DWORD j;
  1032. PDNS_ADDR_ARRAY pserverArray;
  1033. padapter = NetInfo_GetAdapterByIndex( pNetInfo, iter );
  1034. pserverArray = padapter->pDnsAddrs;
  1035. if ( !pserverArray )
  1036. {
  1037. continue;
  1038. }
  1039. padapter->Status = 0;
  1040. padapter->RunFlags &= ClearLevel;
  1041. // clear server status fields
  1042. for ( j=0; j<pserverArray->AddrCount; j++ )
  1043. {
  1044. pserverArray->AddrArray[j].Flags = SRVFLAG_NEW;
  1045. pserverArray->AddrArray[j].Status = SRVSTATUS_NEW;
  1046. }
  1047. }
  1048. }
  1049. VOID
  1050. NetInfo_ResetServerPriorities(
  1051. IN OUT PDNS_NETINFO pNetInfo,
  1052. IN BOOL fLocalDnsOnly
  1053. )
  1054. /*++
  1055. Routine Description:
  1056. Resets the DNS server priority values for the DNS servers.
  1057. Arguments:
  1058. pNetInfo -- pointer to a DNS network info structure.
  1059. fLocalDnsOnly - TRUE to reset priority ONLY on local DNS servers
  1060. Note that this requires that the network info contain the IP address
  1061. list for each adapter so that the IP address list can be compared
  1062. to the DNS server list.
  1063. Return Value:
  1064. Nothing
  1065. --*/
  1066. {
  1067. PDNS_ADAPTER padapter;
  1068. DWORD iter;
  1069. DNSDBG( TRACE, ( "NetInfo_ResetServerPriorities( %p )\n", pNetInfo ));
  1070. if ( !pNetInfo )
  1071. {
  1072. return;
  1073. }
  1074. //
  1075. // reset priorities on server
  1076. // when
  1077. // - not do local only OR
  1078. // - server IP matches one of adapter IPs
  1079. //
  1080. // FIX6: local DNS check needs IP6 fixups
  1081. // DCR: encapsulate as "NetInfo_IsLocalAddress
  1082. for ( iter=0; iter<pNetInfo->AdapterCount; iter++ )
  1083. {
  1084. DWORD j;
  1085. PDNS_ADDR_ARRAY pserverArray;
  1086. padapter = NetInfo_GetAdapterByIndex( pNetInfo, iter );
  1087. pserverArray = padapter->pDnsAddrs;
  1088. if ( !pserverArray )
  1089. {
  1090. continue;
  1091. }
  1092. for ( j=0; j < pserverArray->AddrCount; j++ )
  1093. {
  1094. PDNS_ADDR pserver = &pserverArray->AddrArray[j];
  1095. // loopback goes first
  1096. // - we plumb it in for specific AD scenarios
  1097. // - the cost of failure is low (should just generate
  1098. // ICMP -- CONNRESET -- if server not running)
  1099. if ( DnsAddr_IsLoopback(pserver, 0) )
  1100. {
  1101. pserver->Priority = SRVPRI_LOOPBACK;
  1102. continue;
  1103. }
  1104. if ( !fLocalDnsOnly )
  1105. {
  1106. if ( DnsAddr_IsIp6DefaultDns( pserver ) )
  1107. {
  1108. pserver->Priority = SRVPRI_IP6_DEFAULT;
  1109. continue;
  1110. }
  1111. else
  1112. {
  1113. pserver->Priority = SRVPRI_DEFAULT;
  1114. continue;
  1115. }
  1116. }
  1117. // pull this into local test
  1118. if ( LocalIp_IsAddrLocal(
  1119. pserver,
  1120. NULL, // no local array
  1121. pNetInfo // use netinfo to screen local addrs
  1122. ) )
  1123. {
  1124. pserver->Priority = SRVPRI_DEFAULT;
  1125. continue;
  1126. }
  1127. }
  1128. }
  1129. }
  1130. PDNS_ADAPTER
  1131. NetInfo_GetNextAdapter(
  1132. IN OUT PDNS_NETINFO pNetInfo
  1133. )
  1134. /*++
  1135. Routine Description:
  1136. Get next adapter.
  1137. Note, this must be preceeded by a call to macro
  1138. NetInfo_StartAdapterLoop()
  1139. Arguments:
  1140. pNetInfo -- netinfo to get adapter from
  1141. note, internal index is incremented
  1142. Return Value:
  1143. Ptr to next DNS_ADAPTER
  1144. NULL when out of adapters.
  1145. --*/
  1146. {
  1147. DWORD index;
  1148. PDNS_ADAPTER padapter = NULL;
  1149. //
  1150. // get next adapter if still in range
  1151. //
  1152. index = pNetInfo->AdapterIndex;
  1153. if ( index < pNetInfo->AdapterCount )
  1154. {
  1155. padapter = &pNetInfo->AdapterArray[ index++ ];
  1156. pNetInfo->AdapterIndex = index;
  1157. }
  1158. return padapter;
  1159. }
  1160. PDNS_ADAPTER
  1161. NetInfo_GetAdapterByName(
  1162. IN PDNS_NETINFO pNetInfo,
  1163. IN PWSTR pwsAdapterName
  1164. )
  1165. /*++
  1166. Routine Description:
  1167. Find adapter in netinfo by name.
  1168. Arguments:
  1169. pNetInfo -- DNS net adapter list to convert
  1170. pAdapterName -- adapter name
  1171. Return Value:
  1172. Ptr to adapter, if adapter name found.
  1173. NULL on failure.
  1174. --*/
  1175. {
  1176. PDNS_ADAPTER padapterFound = NULL;
  1177. PDNS_ADAPTER padapter;
  1178. DWORD iter;
  1179. DNSDBG( TRACE, ( "NetInfo_GetAdapterByName( %p )\n", pNetInfo ));
  1180. if ( !pNetInfo || !pwsAdapterName )
  1181. {
  1182. SetLastError( ERROR_INVALID_PARAMETER );
  1183. return NULL;
  1184. }
  1185. //
  1186. // find matching adapter
  1187. //
  1188. for ( iter=0; iter<pNetInfo->AdapterCount; iter++ )
  1189. {
  1190. padapter = NetInfo_GetAdapterByIndex( pNetInfo, iter );
  1191. if ( wcscmp( padapter->pszAdapterGuidName, pwsAdapterName ) == 0 )
  1192. {
  1193. padapterFound = padapter;
  1194. break;
  1195. }
  1196. }
  1197. return( padapterFound );
  1198. }
  1199. PDNS_ADDR_ARRAY
  1200. NetInfo_ConvertToAddrArray(
  1201. IN PDNS_NETINFO pNetInfo,
  1202. IN PWSTR pwsAdapterName,
  1203. IN DWORD Family OPTIONAL
  1204. )
  1205. /*++
  1206. Routine Description:
  1207. Create IP array of DNS servers from network info.
  1208. Arguments:
  1209. pNetInfo -- DNS net adapter list to convert
  1210. pwsAdapterName -- specific adapter
  1211. Family -- required specific address family
  1212. Return Value:
  1213. Ptr to IP array, if successful
  1214. NULL on failure.
  1215. --*/
  1216. {
  1217. PDNS_ADDR_ARRAY parray = NULL;
  1218. DWORD countServers = 0;
  1219. PDNS_ADAPTER padapter;
  1220. PDNS_ADAPTER padapterSingle = NULL;
  1221. DNS_STATUS status = NO_ERROR;
  1222. DWORD iter;
  1223. DNSDBG( TRACE, ( "NetInfo_ConvertToAddrArray( %p )\n", pNetInfo ));
  1224. //
  1225. // get count
  1226. //
  1227. if ( ! pNetInfo )
  1228. {
  1229. return NULL;
  1230. }
  1231. if ( pwsAdapterName )
  1232. {
  1233. padapterSingle = NetInfo_GetAdapterByName( pNetInfo, pwsAdapterName );
  1234. if ( !padapterSingle )
  1235. {
  1236. goto Done;
  1237. }
  1238. countServers = DnsAddrArray_GetFamilyCount(
  1239. padapterSingle->pDnsAddrs,
  1240. Family );
  1241. }
  1242. else
  1243. {
  1244. for ( iter=0; iter<pNetInfo->AdapterCount; iter++ )
  1245. {
  1246. padapter = NetInfo_GetAdapterByIndex( pNetInfo, iter );
  1247. countServers += DnsAddrArray_GetFamilyCount(
  1248. padapter->pDnsAddrs,
  1249. Family );
  1250. }
  1251. }
  1252. //
  1253. // allocate required array
  1254. //
  1255. parray = DnsAddrArray_Create( countServers );
  1256. if ( !parray )
  1257. {
  1258. status = DNS_ERROR_NO_MEMORY;
  1259. goto Done;
  1260. }
  1261. DNS_ASSERT( parray->MaxCount == countServers );
  1262. //
  1263. // read all servers into IP array
  1264. //
  1265. for ( iter=0; iter<pNetInfo->AdapterCount; iter++ )
  1266. {
  1267. padapter = NetInfo_GetAdapterByIndex( pNetInfo, iter );
  1268. if ( !padapterSingle ||
  1269. padapterSingle == padapter )
  1270. {
  1271. status = DnsAddrArray_AppendArrayEx(
  1272. parray,
  1273. padapter->pDnsAddrs,
  1274. 0, // append all
  1275. Family, // family screen
  1276. 0, // no dup screen
  1277. NULL, // no other screening
  1278. NULL // no other screening
  1279. );
  1280. DNS_ASSERT( status == NO_ERROR );
  1281. }
  1282. }
  1283. Done:
  1284. if ( status != NO_ERROR )
  1285. {
  1286. SetLastError( status );
  1287. }
  1288. return( parray );
  1289. }
  1290. PDNS_NETINFO
  1291. NetInfo_CreateForUpdate(
  1292. IN PWSTR pszZone,
  1293. IN PWSTR pszServerName,
  1294. IN PDNS_ADDR_ARRAY pServerArray,
  1295. IN DWORD dwFlags
  1296. )
  1297. /*++
  1298. Routine Description:
  1299. Create network info suitable for update.
  1300. Arguments:
  1301. pszZone -- target zone name
  1302. pszServerName -- target server name
  1303. pServerArray -- IP array with target server IP
  1304. dwFlags -- flags
  1305. Return Value:
  1306. Ptr to resulting update compatible network info.
  1307. NULL on failure.
  1308. --*/
  1309. {
  1310. PDNS_ADAPTER padapter;
  1311. PDNS_NETINFO pnetInfo;
  1312. DNSDBG( TRACE, ( "NetInfo_CreateForUpdate()\n" ));
  1313. //
  1314. // allocate
  1315. //
  1316. pnetInfo = NetInfo_Alloc( 1 );
  1317. if ( !pnetInfo )
  1318. {
  1319. return NULL;
  1320. }
  1321. //
  1322. // save zone name
  1323. //
  1324. if ( pszZone )
  1325. {
  1326. pnetInfo->pszDomainName = Dns_CreateStringCopy_W( pszZone );
  1327. if ( !pnetInfo->pszDomainName )
  1328. {
  1329. goto Fail;
  1330. }
  1331. }
  1332. //
  1333. // convert IP array and server name to server list
  1334. //
  1335. if ( NO_ERROR != AdapterInfo_Create(
  1336. &pnetInfo->AdapterArray[0],
  1337. TRUE, // zero init
  1338. dwFlags,
  1339. NULL, // no GUID
  1340. pszServerName, // use as domain name
  1341. NULL, // no local addrs
  1342. pServerArray
  1343. ) )
  1344. {
  1345. goto Fail;
  1346. }
  1347. pnetInfo->AdapterCount = 1;
  1348. IF_DNSDBG( NETINFO2 )
  1349. {
  1350. DnsDbg_NetworkInfo(
  1351. "Update network info is: ",
  1352. pnetInfo );
  1353. }
  1354. return pnetInfo;
  1355. Fail:
  1356. DNSDBG( TRACE, ( "Failed NetInfo_CreateForUpdate()!\n" ));
  1357. NetInfo_Free( pnetInfo );
  1358. return NULL;
  1359. }
  1360. #if 0
  1361. PDNS_NETINFO
  1362. NetInfo_CreateForUpdateIp4(
  1363. IN PWSTR pszZone,
  1364. IN PWSTR pszServerName,
  1365. IN PIP4_ARRAY pServ4Array,
  1366. IN DWORD dwFlags
  1367. )
  1368. /*++
  1369. Routine Description:
  1370. Create network info suitable for update -- IP4 version.
  1371. DCR: Used only by Dns_UpdateLib() once killed, kill this.
  1372. Arguments:
  1373. pszZone -- target zone name
  1374. pszServerName -- target server name
  1375. pServ4Array -- IP$ array with target server IP
  1376. dwFlags -- flags
  1377. Return Value:
  1378. Ptr to resulting update compatible network info.
  1379. NULL on failure.
  1380. --*/
  1381. {
  1382. PADDR_ARRAY parray;
  1383. PDNS_NETINFO pnetInfo;
  1384. //
  1385. // convert 4 to 6, then call real routine
  1386. //
  1387. parray = DnsAddrArray_CreateFromIp4Array( pServ4Array );
  1388. pnetInfo = NetInfo_CreateForUpdate(
  1389. pszZone,
  1390. pszServerName,
  1391. parray,
  1392. dwFlags );
  1393. DnsAddrArray_Free( parray );
  1394. return pnetInfo;
  1395. }
  1396. #endif
  1397. PWSTR
  1398. NetInfo_UpdateZoneName(
  1399. IN PDNS_NETINFO pNetInfo
  1400. )
  1401. /*++
  1402. Routine Description:
  1403. Retrieve update zone name.
  1404. Arguments:
  1405. pNetInfo -- blob to check
  1406. Return Value:
  1407. Ptr to update zone name.
  1408. NULL on error.
  1409. --*/
  1410. {
  1411. return pNetInfo->pszDomainName;
  1412. }
  1413. PWSTR
  1414. NetInfo_UpdateServerName(
  1415. IN PDNS_NETINFO pNetInfo
  1416. )
  1417. /*++
  1418. Routine Description:
  1419. Retrieve update servere name.
  1420. Arguments:
  1421. pNetInfo -- blob to check
  1422. Return Value:
  1423. Ptr to update zone name.
  1424. NULL on error.
  1425. --*/
  1426. {
  1427. return pNetInfo->AdapterArray[0].pszAdapterDomain;
  1428. }
  1429. BOOL
  1430. NetInfo_IsForUpdate(
  1431. IN PDNS_NETINFO pNetInfo
  1432. )
  1433. /*++
  1434. Routine Description:
  1435. Check if network info blob if "update capable".
  1436. This means whether it is the result of a FAZ and
  1437. can be used to send updates.
  1438. Arguments:
  1439. pNetInfo -- blob to check
  1440. Return Value:
  1441. TRUE if update network info.
  1442. FALSE otherwise.
  1443. --*/
  1444. {
  1445. DNSDBG( TRACE, ( "NetInfo_IsForUpdate()\n" ));
  1446. return ( pNetInfo &&
  1447. pNetInfo->pszDomainName &&
  1448. pNetInfo->AdapterCount == 1 );
  1449. }
  1450. PDNS_NETINFO
  1451. NetInfo_CreateFromAddrArray(
  1452. IN PADDR_ARRAY pDnsServers,
  1453. IN PDNS_ADDR pServerIp,
  1454. IN BOOL fSearchInfo,
  1455. IN PDNS_NETINFO pNetInfo OPTIONAL
  1456. )
  1457. /*++
  1458. Routine Description:
  1459. Create network info given DNS server list.
  1460. Arguments:
  1461. pDnsServers -- IP array of DNS servers
  1462. ServerIp -- single IP in list
  1463. fSearchInfo -- TRUE if need search info
  1464. pNetInfo -- current network info blob to copy search info
  1465. from; this field is only relevant if fSearchInfo is TRUE
  1466. Return Value:
  1467. Ptr to resulting network info.
  1468. NULL on failure.
  1469. --*/
  1470. {
  1471. PDNS_NETINFO pnetInfo;
  1472. ADDR_ARRAY ipArray;
  1473. PADDR_ARRAY parray = pDnsServers;
  1474. PSEARCH_LIST psearchList;
  1475. PWSTR pdomainName;
  1476. DWORD flags = 0;
  1477. //
  1478. // DCR: eliminate search list form this routine
  1479. // i believe this routine is only used for query of
  1480. // FQDNs (usually in update) and doesn't require
  1481. // any default search info
  1482. //
  1483. // DCR: possibly combine with "BuildForUpdate" routine
  1484. // where search info included tacks this on
  1485. //
  1486. //
  1487. // if given single IP, ONLY use it
  1488. //
  1489. if ( pServerIp )
  1490. {
  1491. DnsAddrArray_InitSingleWithAddr(
  1492. & ipArray,
  1493. pServerIp );
  1494. parray = &ipArray;
  1495. }
  1496. //
  1497. // convert server IPs into network info blob
  1498. // - simply use update function above to avoid duplicate code
  1499. //
  1500. pnetInfo = NetInfo_CreateForUpdate(
  1501. NULL, // no zone
  1502. NULL, // no server name
  1503. parray,
  1504. 0 // no flags
  1505. );
  1506. if ( !pnetInfo )
  1507. {
  1508. return( NULL );
  1509. }
  1510. //
  1511. // get search list and primary domain info
  1512. // - copy from passed in network info
  1513. // OR
  1514. // - cut directly out of new netinfo
  1515. //
  1516. if ( fSearchInfo )
  1517. {
  1518. if ( pNetInfo )
  1519. {
  1520. flags = pNetInfo->InfoFlags;
  1521. psearchList = SearchList_Copy( pNetInfo->pSearchList );
  1522. pdomainName = Dns_CreateStringCopy_W( pNetInfo->pszDomainName );
  1523. }
  1524. else
  1525. {
  1526. PDNS_NETINFO ptempNetInfo = GetNetworkInfo();
  1527. if ( ptempNetInfo )
  1528. {
  1529. flags = ptempNetInfo->InfoFlags;
  1530. psearchList = ptempNetInfo->pSearchList;
  1531. pdomainName = ptempNetInfo->pszDomainName;
  1532. ptempNetInfo->pSearchList = NULL;
  1533. ptempNetInfo->pszDomainName = NULL;
  1534. NetInfo_Free( ptempNetInfo );
  1535. }
  1536. else
  1537. {
  1538. psearchList = NULL;
  1539. pdomainName = NULL;
  1540. }
  1541. }
  1542. // plug search info into new netinfo blob
  1543. pnetInfo->pSearchList = psearchList;
  1544. pnetInfo->pszDomainName = pdomainName;
  1545. pnetInfo->InfoFlags |= (flags & NINFO_FLAG_DUMMY_SEARCH_LIST);
  1546. }
  1547. return( pnetInfo );
  1548. }
  1549. #if 0
  1550. PDNS_NETINFO
  1551. NetInfo_CreateFromIp4Array(
  1552. IN PIP4_ARRAY pDnsServers,
  1553. IN IP4_ADDRESS ServerIp,
  1554. IN BOOL fSearchInfo,
  1555. IN PDNS_NETINFO pNetInfo OPTIONAL
  1556. )
  1557. /*++
  1558. Routine Description:
  1559. Create network info given DNS server list.
  1560. Used only in Glenn update routines -- kill when they are deleted.
  1561. Arguments:
  1562. pDnsServers -- IP array of DNS servers
  1563. ServerIp -- single IP in list
  1564. fSearchInfo -- TRUE if need search info
  1565. pNetInfo -- current network info blob to copy search info
  1566. from; this field is only relevant if fSearchInfo is TRUE
  1567. Return Value:
  1568. Ptr to resulting network info.
  1569. NULL on failure.
  1570. --*/
  1571. {
  1572. PDNS_NETINFO pnetInfo;
  1573. IP4_ARRAY ipArray;
  1574. PIP4_ARRAY parray = pDnsServers;
  1575. PSEARCH_LIST psearchList;
  1576. PWSTR pdomainName;
  1577. DWORD flags = 0;
  1578. //
  1579. // DCR: eliminate search list form this routine
  1580. // i believe this routine is only used for query of
  1581. // FQDNs (usually in update) and doesn't require
  1582. // any default search info
  1583. //
  1584. // DCR: possibly combine with "BuildForUpdate" routine
  1585. // where search info included tacks this on
  1586. //
  1587. //
  1588. // if given single IP, ONLY use it
  1589. //
  1590. if ( ServerIp )
  1591. {
  1592. ipArray.AddrCount = 1;
  1593. ipArray.AddrArray[0] = ServerIp;
  1594. parray = &ipArray;
  1595. }
  1596. //
  1597. // convert server IPs into network info blob
  1598. // - simply use update function above to avoid duplicate code
  1599. //
  1600. pnetInfo = NetInfo_CreateForUpdateIp4(
  1601. NULL, // no zone
  1602. NULL, // no server name
  1603. parray,
  1604. 0 // no flags
  1605. );
  1606. if ( !pnetInfo )
  1607. {
  1608. return( NULL );
  1609. }
  1610. //
  1611. // get search list and primary domain info
  1612. // - copy from passed in network info
  1613. // OR
  1614. // - cut directly out of new netinfo
  1615. //
  1616. if ( fSearchInfo )
  1617. {
  1618. if ( pNetInfo )
  1619. {
  1620. flags = pNetInfo->InfoFlags;
  1621. psearchList = SearchList_Copy( pNetInfo->pSearchList );
  1622. pdomainName = Dns_CreateStringCopy_W( pNetInfo->pszDomainName );
  1623. }
  1624. else
  1625. {
  1626. PDNS_NETINFO ptempNetInfo = GetNetworkInfo();
  1627. if ( ptempNetInfo )
  1628. {
  1629. flags = ptempNetInfo->InfoFlags;
  1630. psearchList = ptempNetInfo->pSearchList;
  1631. pdomainName = ptempNetInfo->pszDomainName;
  1632. ptempNetInfo->pSearchList = NULL;
  1633. ptempNetInfo->pszDomainName = NULL;
  1634. NetInfo_Free( ptempNetInfo );
  1635. }
  1636. else
  1637. {
  1638. psearchList = NULL;
  1639. pdomainName = NULL;
  1640. }
  1641. }
  1642. // plug search info into new netinfo blob
  1643. pnetInfo->pSearchList = psearchList;
  1644. pnetInfo->pszDomainName = pdomainName;
  1645. pnetInfo->InfoFlags |= (flags & NINFO_FLAG_DUMMY_SEARCH_LIST);
  1646. }
  1647. return( pnetInfo );
  1648. }
  1649. #endif
  1650. //
  1651. // NetInfo building utilities
  1652. //
  1653. // DNS server reachability routines
  1654. //
  1655. // These are used to build netinfo that has unreachable DNS
  1656. // servers screened out of the list.
  1657. //
  1658. BOOL
  1659. IsReachableDnsServer(
  1660. IN PDNS_NETINFO pNetInfo,
  1661. IN PDNS_ADAPTER pAdapter,
  1662. IN IP4_ADDRESS Ip4Addr
  1663. )
  1664. /*++
  1665. Routine Description:
  1666. Determine if DNS server is reachable.
  1667. Arguments:
  1668. pNetInfo -- network info blob
  1669. pAdapter -- struct with list of DNS servers
  1670. Ip4Addr -- DNS server address to test for reachability
  1671. Return Value:
  1672. TRUE if DNS server is reachable.
  1673. FALSE otherwise.
  1674. --*/
  1675. {
  1676. DWORD interfaceIndex;
  1677. DNS_STATUS status;
  1678. DNSDBG( NETINFO, (
  1679. "Enter IsReachableDnsServer( %p, %p, %08x )\n",
  1680. pNetInfo,
  1681. pAdapter,
  1682. Ip4Addr ));
  1683. DNS_ASSERT( pNetInfo && pAdapter );
  1684. //
  1685. // DCR: should do reachablity once on netinfo build
  1686. //
  1687. // DCR: reachability test can be smarter
  1688. // - reachable if same subnet as adapter IP
  1689. // question: multiple IPs?
  1690. // - reachable if same subnet as previous reachable IP
  1691. // question: can tell if same subnet?
  1692. //
  1693. // DCR: reachability on multi-homed connected
  1694. // - if send on another interface, does that interface
  1695. // "seem" to be connected
  1696. // probably see if
  1697. // - same subnet as this inteface
  1698. // question: multiple IPs
  1699. // - or share DNS servers in common
  1700. // question: just let server go, this doesn't work if
  1701. // the name is not the same
  1702. //
  1703. //
  1704. // if only one interface, assume reachability
  1705. //
  1706. if ( pNetInfo->AdapterCount <= 1 )
  1707. {
  1708. DNSDBG( SEND, (
  1709. "One interface, assume reachability!\n" ));
  1710. return( TRUE );
  1711. }
  1712. //
  1713. // check if server IP is reachable on its interface
  1714. //
  1715. status = IpHelp_GetBestInterface(
  1716. Ip4Addr,
  1717. & interfaceIndex );
  1718. if ( status != NO_ERROR )
  1719. {
  1720. DNS_ASSERT( FALSE );
  1721. DNSDBG( ANY, (
  1722. "GetBestInterface() failed! %d\n",
  1723. status ));
  1724. return( TRUE );
  1725. }
  1726. if ( pAdapter->InterfaceIndex != interfaceIndex )
  1727. {
  1728. DNSDBG( NETINFO, (
  1729. "IP %s on interface %d is unreachable!\n"
  1730. "\tsend would be on interface %d\n",
  1731. IP_STRING( Ip4Addr ),
  1732. pAdapter->InterfaceIndex,
  1733. interfaceIndex ));
  1734. return( FALSE );
  1735. }
  1736. return( TRUE );
  1737. }
  1738. BOOL
  1739. IsDnsReachableOnAlternateInterface(
  1740. IN PDNS_NETINFO pNetInfo,
  1741. IN DWORD InterfaceIndex,
  1742. IN PDNS_ADDR pAddr
  1743. )
  1744. /*++
  1745. Routine Description:
  1746. Determine if IP address is reachable on adapter.
  1747. This function determines whether DNS IP can be reached
  1748. on the interface that the stack indicates, when that
  1749. interface is NOT the one containing the DNS server.
  1750. We need this so we catch the multi-homed CONNECTED cases
  1751. where a DNS server is still reachable even though the
  1752. interface the stack will send on is NOT the interface for
  1753. the DNS server.
  1754. Arguments:
  1755. pNetInfo -- network info blob
  1756. Interface -- interface stack will send to IP on
  1757. pAddr -- DNS server address to test for reachability
  1758. Return Value:
  1759. TRUE if DNS server is reachable.
  1760. FALSE otherwise.
  1761. --*/
  1762. {
  1763. PDNS_ADAPTER padapter = NULL;
  1764. PDNS_ADDR_ARRAY pserverArray;
  1765. DWORD i;
  1766. PIP4_ARRAY pipArray;
  1767. PIP4_ARRAY psubnetArray;
  1768. DWORD ipCount;
  1769. IP4_ADDRESS ip4;
  1770. DNSDBG( NETINFO, (
  1771. "Enter IsDnsReachableOnAlternateInterface( %p, %d, %08x )\n",
  1772. pNetInfo,
  1773. InterfaceIndex,
  1774. pAddr ));
  1775. //
  1776. // find DNS adapter for interface
  1777. //
  1778. for( i=0; i<pNetInfo->AdapterCount; i++ )
  1779. {
  1780. padapter = NetInfo_GetAdapterByIndex( pNetInfo, i );
  1781. if ( padapter->InterfaceIndex != InterfaceIndex )
  1782. {
  1783. padapter = NULL;
  1784. continue;
  1785. }
  1786. break;
  1787. }
  1788. if ( !padapter )
  1789. {
  1790. DNSDBG( ANY, (
  1791. "WARNING: indicated send inteface %d NOT in netinfo!\n",
  1792. InterfaceIndex ));
  1793. return FALSE;
  1794. }
  1795. //
  1796. // success conditions:
  1797. // 1) DNS IP matches IP of DNS server for send interface
  1798. // 2) DNS IP is on subnet of IP of send interface
  1799. // 3) DNS IP4 is same default class subnet of send interface
  1800. //
  1801. // if either of these is TRUE then either
  1802. // - there is misconfiguration (not our problem)
  1803. // OR
  1804. // - there's a somewhat unlikely condition of a default network address
  1805. // being subnetted in such a way that it appears on two adapters for
  1806. // the machine but is not connected and routeable
  1807. // OR
  1808. // - these interfaces are connected and we can safely send on them
  1809. //
  1810. //
  1811. // #3 is the issue of multiple adapters in the same (corporate) name space
  1812. // example:
  1813. // adapter 1 -- default gateway
  1814. // IP 157.59.1.1
  1815. // DNS 158.10.1.1
  1816. //
  1817. // adapter 2
  1818. // IP 157.59.7.9
  1819. // DNS 159.65.7.8 -- send interface adapter 1
  1820. //
  1821. // adapter 3
  1822. // IP 159.57.12.3
  1823. // DNS 157.59.134.7 -- send interface adapter 1
  1824. //
  1825. // adapter 4
  1826. // IP 196.12.13.3
  1827. // DNS 200.59.73.2
  1828. //
  1829. // From GetBestInterface, adapter 1, (default gateway) is given as send interface
  1830. // for adapter 2 and 3's DNS servers.
  1831. //
  1832. // For adapter #2, it's DNS is NOT in adapter1's list, but it's IP shares the same
  1833. // class B network as adapter 1. It is unlikely that the subnetting is such that
  1834. // it's DNS is not reachable through adapter 1.
  1835. //
  1836. // For adapter #3, it's DNS is NOT in adapter1's list, but it's DNS is on the same
  1837. // class B network as adapter 1's interface. Again it's extremely unlikely it is
  1838. // not reachable.
  1839. //
  1840. // For adapter #4, however, it's plain that there's no connection. Neither it's IP
  1841. // nor DNS share default network with adapter 1. So send -- which will go out -- adapter
  1842. // #1 has a high likelyhood of being to a disjoint network and being unreturnable.
  1843. //
  1844. //
  1845. if ( DnsAddrArray_ContainsAddr(
  1846. padapter->pDnsAddrs,
  1847. pAddr,
  1848. DNSADDR_MATCH_ADDR ) )
  1849. {
  1850. DNSDBG( NETINFO, (
  1851. "DNS server %p also DNS server on send interface %d\n",
  1852. pAddr,
  1853. InterfaceIndex ));
  1854. return( TRUE );
  1855. }
  1856. //
  1857. // DCR: should do subnet matching on IPs
  1858. // if DNS server is for one interface with IP on same subnet as IP
  1859. // of the interface you'll send on, then it should be kosher
  1860. //
  1861. //
  1862. // test for subnet match for IP4 addrs
  1863. //
  1864. // FIX6: subnet matching fixup for new subnet info
  1865. // DCR: encapsulate subnet matching -- local subnet test
  1866. //
  1867. // FIX6: local subnet matching on IP6
  1868. //
  1869. #if SUB4NET
  1870. ip4 = DnsAddr_GetIp4( pAddr );
  1871. if ( ip4 != BAD_IP4_ADDR )
  1872. {
  1873. pipArray = padapter->pIp4Addrs;
  1874. psubnetArray = padapter->pIp4SubnetMasks;
  1875. if ( !pipArray ||
  1876. !psubnetArray ||
  1877. (ipCount = pipArray->AddrCount) != psubnetArray->AddrCount )
  1878. {
  1879. DNSDBG( ANY, ( "WARNING: missing or invalid interface IP\\subnet info!\n" ));
  1880. DNS_ASSERT( FALSE );
  1881. return( FALSE );
  1882. }
  1883. for ( i=0; i<ipCount; i++ )
  1884. {
  1885. IP4_ADDRESS subnet = psubnetArray->AddrArray[i];
  1886. if ( (subnet & ip4) == (subnet & pipArray->AddrArray[i]) )
  1887. {
  1888. DNSDBG( NETINFO, (
  1889. "DNS server %08x on subnet of IP for send interface %d\n"
  1890. "\tip = %08x, subnet = %08x\n",
  1891. ip4,
  1892. InterfaceIndex,
  1893. pipArray->AddrArray[i],
  1894. subnet ));
  1895. return( TRUE );
  1896. }
  1897. }
  1898. }
  1899. #endif
  1900. return( FALSE );
  1901. }
  1902. DNS_STATUS
  1903. StrikeOutUnreachableDnsServers(
  1904. IN OUT PDNS_NETINFO pNetInfo
  1905. )
  1906. /*++
  1907. Routine Description:
  1908. Eliminate unreachable DNS servers from the list.
  1909. Arguments:
  1910. pNetInfo -- DNS netinfo to fix up
  1911. Return Value:
  1912. ERROR_SUCCESS if successful
  1913. --*/
  1914. {
  1915. DNS_STATUS status;
  1916. DWORD validServers;
  1917. PDNS_ADAPTER padapter;
  1918. PDNS_ADDR_ARRAY pserverArray;
  1919. DWORD adapterIfIndex;
  1920. DWORD serverIfIndex;
  1921. DWORD i;
  1922. DWORD j;
  1923. DNSDBG( NETINFO, (
  1924. "Enter StrikeOutUnreachableDnsServers( %p )\n",
  1925. pNetInfo ));
  1926. DNS_ASSERT( pNetInfo );
  1927. //
  1928. // if only one interface, assume reachability
  1929. //
  1930. if ( pNetInfo->AdapterCount <= 1 )
  1931. {
  1932. DNSDBG( NETINFO, (
  1933. "One interface, assume reachability!\n" ));
  1934. return( TRUE );
  1935. }
  1936. //
  1937. // loop through adapters
  1938. //
  1939. for( i=0; i<pNetInfo->AdapterCount; i++ )
  1940. {
  1941. BOOL found4;
  1942. BOOL found6;
  1943. BOOL found6NonDefault;
  1944. padapter = NetInfo_GetAdapterByIndex( pNetInfo, i );
  1945. // ignore this adapter because there are no DNS
  1946. // servers configured?
  1947. if ( padapter->InfoFlags & AINFO_FLAG_IGNORE_ADAPTER )
  1948. {
  1949. continue;
  1950. }
  1951. //
  1952. // test all adapter's DNS servers for reachability
  1953. //
  1954. // note: currently save no server specific reachability,
  1955. // so if any server reachable, proceed;
  1956. // also if iphelp fails just assume reachability and proceed,
  1957. // better timeouts then not reaching server we can reach
  1958. //
  1959. adapterIfIndex = padapter->InterfaceIndex;
  1960. validServers = 0;
  1961. //
  1962. // FIX6: need GetBestInteface for IP6
  1963. //
  1964. found4 = FALSE;
  1965. found6 = FALSE;
  1966. found6NonDefault = FALSE;
  1967. pserverArray = padapter->pDnsAddrs;
  1968. for ( j=0; j<pserverArray->AddrCount; j++ )
  1969. {
  1970. PDNS_ADDR paddr = &pserverArray->AddrArray[j];
  1971. IP4_ADDRESS ip4;
  1972. ip4 = DnsAddr_GetIp4( paddr );
  1973. //
  1974. // IP6
  1975. //
  1976. if ( ip4 == BAD_IP4_ADDR )
  1977. {
  1978. found6 = TRUE;
  1979. if ( !DnsAddr_IsIp6DefaultDns( paddr ) )
  1980. {
  1981. found6NonDefault = TRUE;
  1982. }
  1983. continue;
  1984. }
  1985. //
  1986. // IP4 server
  1987. //
  1988. found4 = TRUE;
  1989. serverIfIndex = 0; // prefix happiness
  1990. status = IpHelp_GetBestInterface(
  1991. ip4,
  1992. & serverIfIndex );
  1993. if ( status == ERROR_NETWORK_UNREACHABLE )
  1994. {
  1995. DNSDBG( NETINFO, (
  1996. "GetBestInterface() NETWORK_UNREACH for server %s\n",
  1997. IP_STRING(ip4) ));
  1998. continue;
  1999. }
  2000. if ( status != NO_ERROR )
  2001. {
  2002. DNSDBG( ANY, (
  2003. "GetBestInterface() failed! %d\n",
  2004. status ));
  2005. //DNS_ASSERT( FALSE );
  2006. validServers++;
  2007. break;
  2008. //continue;
  2009. }
  2010. // server is reachable
  2011. // - queried on its adapter?
  2012. // - reachable through loopback
  2013. //
  2014. // DCR: tag unreachable servers individually
  2015. if ( serverIfIndex == adapterIfIndex ||
  2016. serverIfIndex == 1 )
  2017. {
  2018. validServers++;
  2019. break;
  2020. //continue;
  2021. }
  2022. // server can be reached on query interface
  2023. if ( IsDnsReachableOnAlternateInterface(
  2024. pNetInfo,
  2025. serverIfIndex,
  2026. paddr ) )
  2027. {
  2028. validServers++;
  2029. break;
  2030. //continue;
  2031. }
  2032. }
  2033. //
  2034. // mark adapter if no reachable servers found
  2035. //
  2036. // => if no servers or IP4 tested and failed, ignore the adapter
  2037. // => if only IP6 default server, mark, we'll use but not
  2038. // continue on adapter after NAME_ERROR
  2039. // =>
  2040. //
  2041. // - any IP6 will be considered "found" (until get explicit test)
  2042. // BUT if we test IP4 on that interface, then it's status wins
  2043. //
  2044. // DCR: alternative to ignoring unreachable
  2045. // - tag as unreachable
  2046. // - don't send to it on first pass
  2047. // - don't continue name error on unreachable
  2048. // (it would count as "heard from" when send.c routine
  2049. // works back through)
  2050. if ( validServers == 0 )
  2051. {
  2052. if ( found4 || !found6 )
  2053. {
  2054. padapter->InfoFlags |= (AINFO_FLAG_IGNORE_ADAPTER |
  2055. AINFO_FLAG_SERVERS_UNREACHABLE);
  2056. DNSDBG( NETINFO, (
  2057. "No reachable servers on interface %d\n"
  2058. "\tthis adapter (%p) ignored in DNS list!\n",
  2059. adapterIfIndex,
  2060. padapter ));
  2061. }
  2062. else if ( !found6NonDefault )
  2063. {
  2064. padapter->InfoFlags |= AINFO_FLAG_SERVERS_IP6_DEFAULT;
  2065. DNSDBG( NETINFO, (
  2066. "Only IP6 default servers on interface %d\n"
  2067. "\twill not continue on this adapter after response.\n",
  2068. adapterIfIndex,
  2069. padapter ));
  2070. }
  2071. }
  2072. }
  2073. return ERROR_SUCCESS;
  2074. }
  2075. //
  2076. // Network info caching\state routines
  2077. //
  2078. BOOL
  2079. InitNetworkInfo(
  2080. VOID
  2081. )
  2082. /*++
  2083. Routine Description:
  2084. Initialize network info.
  2085. Arguments:
  2086. None
  2087. Return Value:
  2088. None
  2089. --*/
  2090. {
  2091. //
  2092. // standard up-n-running path -- allows cheap runtime check
  2093. //
  2094. if ( g_NetInfoCacheLockInitialized &&
  2095. g_NetInfoBuildLockInitialized )
  2096. {
  2097. return TRUE;
  2098. }
  2099. //
  2100. // if netinfo not initialzied
  2101. //
  2102. LOCK_GENERAL();
  2103. g_pNetInfo = NULL;
  2104. if ( !g_NetInfoCacheLockInitialized )
  2105. {
  2106. g_NetInfoCacheLockInitialized =
  2107. ( RtlInitializeCriticalSection( &g_NetInfoCacheLock ) == NO_ERROR );
  2108. }
  2109. if ( !g_NetInfoBuildLockInitialized )
  2110. {
  2111. g_NetInfoBuildLockInitialized =
  2112. ( TimedLock_Initialize( &g_NetInfoBuildLock, 5000 ) == NO_ERROR );
  2113. }
  2114. UNLOCK_GENERAL();
  2115. return ( g_NetInfoCacheLockInitialized && g_NetInfoBuildLockInitialized );
  2116. }
  2117. VOID
  2118. CleanupNetworkInfo(
  2119. VOID
  2120. )
  2121. /*++
  2122. Routine Description:
  2123. Initialize network info.
  2124. Arguments:
  2125. None
  2126. Return Value:
  2127. None
  2128. --*/
  2129. {
  2130. LOCK_GENERAL();
  2131. NetInfo_MarkDirty();
  2132. if ( g_NetInfoBuildLockInitialized )
  2133. {
  2134. TimedLock_Cleanup( &g_NetInfoBuildLock );
  2135. }
  2136. if ( g_NetInfoCacheLockInitialized )
  2137. {
  2138. DeleteCriticalSection( &g_NetInfoCacheLock );
  2139. }
  2140. UNLOCK_GENERAL();
  2141. }
  2142. //
  2143. // Read config from resolver
  2144. //
  2145. PDNS_NETINFO
  2146. UpdateDnsConfig(
  2147. VOID
  2148. )
  2149. /*++
  2150. Routine Description:
  2151. Update DNS configuration.
  2152. This includes entire config
  2153. - flat registry DWORD\BOOL globals
  2154. - netinfo list
  2155. Arguments:
  2156. None
  2157. Return Value:
  2158. Ptr to network info blob.
  2159. --*/
  2160. {
  2161. DNS_STATUS status = ERROR_SUCCESS;
  2162. PDNS_NETINFO pnetworkInfo = NULL;
  2163. PDNS_GLOBALS_BLOB pglobalsBlob = NULL;
  2164. DNSDBG( TRACE, ( "UpdateDnsConfig()\n" ));
  2165. // DCR_CLEANUP: RPC TryExcept should be in RPC client library
  2166. RpcTryExcept
  2167. {
  2168. R_ResolverGetConfig(
  2169. NULL, // default handle
  2170. g_ConfigCookie,
  2171. & pnetworkInfo,
  2172. & pglobalsBlob
  2173. );
  2174. }
  2175. RpcExcept( DNS_RPC_EXCEPTION_FILTER )
  2176. {
  2177. status = RpcExceptionCode();
  2178. }
  2179. RpcEndExcept
  2180. if ( status != ERROR_SUCCESS )
  2181. {
  2182. DNSDBG( RPC, (
  2183. "R_ResolverGetConfig() RPC failed status = %d\n",
  2184. status ));
  2185. return NULL;
  2186. }
  2187. //
  2188. // DCR: save other config info here
  2189. // - flat memcpy of DWORD globals
  2190. // - save off cookie (perhaps include as one of them
  2191. // - save global copy of pnetworkInfo?
  2192. // (the idea being that we just copy it if
  2193. // RPC cookie is valid)
  2194. //
  2195. // - maybe return flags?
  2196. // memcpy is cheap but if more expensive config
  2197. // then could alert what needs update?
  2198. //
  2199. //
  2200. // DCR: once move, single "update global network info"
  2201. // then call it here to save global copy
  2202. // but global copy doesn't do much until RPC fails
  2203. // unless using cookie
  2204. //
  2205. // QUESTION: not sure about forcing global build here
  2206. // q: is this to be "read config" all
  2207. // or just "update config" and then individual
  2208. // routines for various pieces of config can
  2209. // determine what to do?
  2210. //
  2211. // note, doing eveything is fine if going to always
  2212. // read entire registry on cache failure; if so
  2213. // reasonable to push here
  2214. //
  2215. // if cache-on required for "real time" config, then
  2216. // should protect registry DWORD read with reasonable time
  2217. // (say read every five\ten\fifteen minutes?)
  2218. //
  2219. // perhaps NO read here, but have DWORD reg read update
  2220. // routine that called before registry reread when
  2221. // building adapter list in registry; then skip this
  2222. // step in cache
  2223. //
  2224. //
  2225. // copy in config
  2226. //
  2227. if ( pglobalsBlob )
  2228. {
  2229. RtlCopyMemory(
  2230. & DnsGlobals,
  2231. pglobalsBlob,
  2232. sizeof(DnsGlobals) );
  2233. MIDL_user_free( pglobalsBlob );
  2234. }
  2235. IF_DNSDBG( RPC )
  2236. {
  2237. DnsDbg_NetworkInfo(
  2238. "Network Info returned from cache:",
  2239. pnetworkInfo );
  2240. }
  2241. return pnetworkInfo;
  2242. }
  2243. //
  2244. // Public netinfo routine
  2245. //
  2246. PDNS_NETINFO
  2247. NetInfo_Get(
  2248. IN DWORD Flag,
  2249. IN DWORD AcceptLocalCacheTime OPTIONAL
  2250. )
  2251. /*++
  2252. Routine Description:
  2253. Read DNS network info from registry.
  2254. This is in process, limited caching version.
  2255. Note, this is macro'd as GetNetworkInfo() with parameters
  2256. NetInfo_Get( FALSE, TRUE ) throughout dnsapi code.
  2257. Arguments:
  2258. Flag -- flag; read order and IP
  2259. NIFLAG_GET_LOCAL_ADDRS
  2260. NIFLAG_FORCE_REGISTRY_READ
  2261. NIFLAG_READ_RESOLVER_FIRST
  2262. NIFLAG_READ_RESOLVER
  2263. NIFLAG_READ_PROCESS_CACHE
  2264. AcceptLocalCacheTime -- acceptable cache time on in process copy
  2265. Return Value:
  2266. ERROR_SUCCESS if successful.
  2267. Error code on failure.
  2268. --*/
  2269. {
  2270. PDNS_NETINFO pnetInfo = NULL;
  2271. PDNS_NETINFO poldNetInfo = NULL;
  2272. BOOL fcacheLock = FALSE;
  2273. BOOL fbuildLock = FALSE;
  2274. BOOL fcacheable = TRUE;
  2275. DNSDBG( NETINFO, (
  2276. "NetInfo_Get( %08x, %d )\n",
  2277. Flag,
  2278. AcceptLocalCacheTime ));
  2279. //
  2280. // init netinfo locks\caching
  2281. //
  2282. if ( !InitNetworkInfo() )
  2283. {
  2284. return NULL;
  2285. }
  2286. //
  2287. // get netinfo from one of several sources
  2288. // try
  2289. // - very recent local cached copy
  2290. // - RPC copy from resolver
  2291. // - build new
  2292. //
  2293. // note the locking model
  2294. // two SEPARATE locks
  2295. // - cache lock, for very quick, very local access
  2296. // to cached copy
  2297. // - build lock, for remote process access to cached (resolver)
  2298. // or newly built netinfo
  2299. //
  2300. // the locking hierarchy
  2301. // - build lock
  2302. // - cache lock (maybe taken inside build lock)
  2303. //
  2304. //
  2305. // Locking implementation note:
  2306. //
  2307. // The reason for the two locks is that when calling down for netinfo
  2308. // build it is possible to have a circular dependency.
  2309. //
  2310. // Here's the deadlock scenario if we have a single lock handling
  2311. // build and caching:
  2312. // - call into resolver and down to iphlpapi
  2313. // - iphlpapi RPC's into MPR (router service)
  2314. // - RtrMgr calls GetHostByName() which ends up in a
  2315. // iphlpapi!GetBestInterface call which in turn calls
  2316. // Mprapi!IsRouterRunning (which is an RPC to mprdim).
  2317. // - Mprdim is blocked on a CS which is held by a thread waiting
  2318. // for a demand-dial disconnect to complete - this is completely
  2319. // independent of 1.
  2320. // - Demand-dial disconnect is waiting for ppp to finish graceful
  2321. // termination.
  2322. // - PPP is waiting for dns to return from DnsSetConfigDword
  2323. // - DnsSetConfigDword, sets, alerts the cache, then calls
  2324. // NetInfo_MarkDirty()
  2325. // - NetInfo_MarkDirty() is waiting on CS to access the netinfo global.
  2326. //
  2327. // Now, this could be avoided by changing MarkDirty() to safely set some
  2328. // dirty bit (interlock). The build function would have to check the bit
  2329. // and go down again if it was set.
  2330. //
  2331. // However, there'd still be a chance that the call down to iphlpapi, could
  2332. // depend under some odd circumstance on some service that came back through
  2333. // the resolver. And the bottom line is that the real distinction is not
  2334. // between caching and marking cache dirty. It's between completely local
  2335. // cache get\set\clear activity, which can be safely overloaded on the general CS,
  2336. // AND the longer time, multi-service dependent building operation. So
  2337. // separate CS for both is correct.
  2338. //
  2339. if ( !(Flag & NIFLAG_FORCE_REGISTRY_READ)
  2340. &&
  2341. !g_DnsTestMode )
  2342. {
  2343. //
  2344. // RPC to resolver
  2345. //
  2346. if ( Flag & NIFLAG_READ_RESOLVER_FIRST )
  2347. {
  2348. // DCR: this could present "cookie" of existing netinfo
  2349. // and only get new if "cookie" is old, though the
  2350. // cost of that versus local copy seems small since
  2351. // still must do RPC and allocations -- only the copy
  2352. // for RPC on the resolver side is saved
  2353. fbuildLock = LOCK_NETINFO_BUILD();
  2354. if ( !fbuildLock )
  2355. {
  2356. goto Unlock;
  2357. }
  2358. pnetInfo = UpdateDnsConfig();
  2359. if ( pnetInfo )
  2360. {
  2361. DNSDBG( TRACE, (
  2362. "Netinfo read from resolver.\n" ));
  2363. goto CacheCopy;
  2364. }
  2365. }
  2366. //
  2367. // use in-process cached copy?
  2368. //
  2369. if ( Flag & NIFLAG_READ_PROCESS_CACHE )
  2370. {
  2371. DWORD timeout = NETINFO_CACHE_TIMEOUT;
  2372. LOCK_NETINFO_CACHE();
  2373. fcacheLock = TRUE;
  2374. if ( AcceptLocalCacheTime )
  2375. {
  2376. timeout = AcceptLocalCacheTime;
  2377. }
  2378. // check if valid copy cached in process
  2379. if ( g_pNetInfo &&
  2380. (g_pNetInfo->TimeStamp + timeout > Dns_GetCurrentTimeInSeconds()) )
  2381. {
  2382. pnetInfo = NetInfo_Copy( g_pNetInfo );
  2383. if ( pnetInfo )
  2384. {
  2385. DNSDBG( TRACE, (
  2386. "Netinfo found in process cache.\n" ));
  2387. goto Unlock;
  2388. }
  2389. }
  2390. UNLOCK_NETINFO_CACHE();
  2391. fcacheLock = FALSE;
  2392. }
  2393. //
  2394. // last chance on resolver
  2395. //
  2396. if ( !fbuildLock && (Flag & NIFLAG_READ_RESOLVER) )
  2397. {
  2398. fbuildLock = LOCK_NETINFO_BUILD();
  2399. if ( !fbuildLock )
  2400. {
  2401. goto Unlock;
  2402. }
  2403. pnetInfo = UpdateDnsConfig();
  2404. if ( pnetInfo )
  2405. {
  2406. DNSDBG( TRACE, (
  2407. "Netinfo read from resolver.\n" ));
  2408. goto CacheCopy;
  2409. }
  2410. }
  2411. }
  2412. //
  2413. // build fresh network info
  2414. //
  2415. DNS_ASSERT( !fcacheLock );
  2416. if ( !fbuildLock )
  2417. {
  2418. fbuildLock = LOCK_NETINFO_BUILD();
  2419. if ( !fbuildLock )
  2420. {
  2421. goto Unlock;
  2422. }
  2423. }
  2424. fcacheable = (Flag & NIFLAG_GET_LOCAL_ADDRS);
  2425. pnetInfo = NetInfo_Build( fcacheable );
  2426. if ( !pnetInfo )
  2427. {
  2428. goto Unlock;
  2429. }
  2430. CacheCopy:
  2431. //
  2432. // update cached copy
  2433. // - but not if built without local IPs;
  2434. // resolver copy always contains local IPs
  2435. //
  2436. if ( fcacheable )
  2437. {
  2438. if ( !fcacheLock )
  2439. {
  2440. LOCK_NETINFO_CACHE();
  2441. fcacheLock = TRUE;
  2442. }
  2443. poldNetInfo = g_pNetInfo;
  2444. g_pNetInfo = NetInfo_Copy( pnetInfo );
  2445. }
  2446. Unlock:
  2447. if ( fcacheLock )
  2448. {
  2449. UNLOCK_NETINFO_CACHE();
  2450. }
  2451. if ( fbuildLock )
  2452. {
  2453. UNLOCK_NETINFO_BUILD();
  2454. }
  2455. NetInfo_Free( poldNetInfo );
  2456. DNSDBG( TRACE, (
  2457. "Leave: NetInfo_Get( %p )\n",
  2458. pnetInfo ));
  2459. return( pnetInfo );
  2460. }
  2461. VOID
  2462. NetInfo_MarkDirty(
  2463. VOID
  2464. )
  2465. /*++
  2466. Routine Description:
  2467. Mark netinfo dirty so force reread.
  2468. Arguments:
  2469. None
  2470. Return Value:
  2471. None
  2472. --*/
  2473. {
  2474. PDNS_NETINFO pold;
  2475. DNSDBG( NETINFO, ( "NetInfo_MarkDirty()\n" ));
  2476. //
  2477. // init netinfo locks\caching
  2478. //
  2479. if ( !InitNetworkInfo() )
  2480. {
  2481. return;
  2482. }
  2483. //
  2484. // dump global network info to force reread
  2485. //
  2486. // since the resolve is always notified by DnsSetDwordConfig()
  2487. // BEFORE entering this function, the resolve should always be
  2488. // providing before we are in this function; all we need to do
  2489. // is insure that cached copy is dumped
  2490. //
  2491. LOCK_NETINFO_CACHE();
  2492. pold = g_pNetInfo;
  2493. g_pNetInfo = NULL;
  2494. UNLOCK_NETINFO_CACHE();
  2495. NetInfo_Free( pold );
  2496. }
  2497. PDNS_NETINFO
  2498. NetInfo_Build(
  2499. IN BOOL fGetIpAddrs
  2500. )
  2501. /*++
  2502. Routine Description:
  2503. Build network info blob from registry.
  2504. This is the FULL recreate function.
  2505. Arguments:
  2506. fGetIpAddrs -- TRUE to include local IP addrs for each adapter
  2507. (currently ignored -- always get all the info)
  2508. Return Value:
  2509. ERROR_SUCCESS if successful.
  2510. Error code on failure.
  2511. --*/
  2512. {
  2513. REG_SESSION regSession;
  2514. PREG_SESSION pregSession = NULL;
  2515. PDNS_NETINFO pnetInfo = NULL;
  2516. PDNS_ADAPTER pdnsAdapter = NULL;
  2517. DNS_STATUS status = NO_ERROR;
  2518. DWORD count;
  2519. DWORD createdAdapterCount = 0;
  2520. BOOL fuseIp;
  2521. PIP_ADAPTER_ADDRESSES padapterList = NULL;
  2522. PIP_ADAPTER_ADDRESSES padapter = NULL;
  2523. DWORD value;
  2524. PREG_GLOBAL_INFO pregInfo = NULL;
  2525. REG_GLOBAL_INFO regInfo;
  2526. REG_ADAPTER_INFO regAdapterInfo;
  2527. DWORD flag;
  2528. BOOL fhaveDnsServers = FALSE;
  2529. DNSDBG( TRACE, ( "\n\n\nNetInfo_Build()\n\n" ));
  2530. //
  2531. // open the registry
  2532. //
  2533. pregSession = &regSession;
  2534. status = Reg_OpenSession(
  2535. pregSession,
  2536. 0,
  2537. 0 );
  2538. if ( status != ERROR_SUCCESS )
  2539. {
  2540. status = DNS_ERROR_NO_DNS_SERVERS;
  2541. goto Cleanup;
  2542. }
  2543. //
  2544. // read global registry info
  2545. //
  2546. pregInfo = &regInfo;
  2547. status = Reg_ReadGlobalInfo(
  2548. pregSession,
  2549. pregInfo
  2550. );
  2551. if ( status != ERROR_SUCCESS )
  2552. {
  2553. status = DNS_ERROR_NO_DNS_SERVERS;
  2554. goto Cleanup;
  2555. }
  2556. //
  2557. // get adapter\address info from IP help
  2558. //
  2559. // note: always getting IP addresses
  2560. // - for multi-adapter need for routing
  2561. // - need for local lookups
  2562. // (might as well just include)
  2563. //
  2564. // DCR: could skip include when RPCing to client for
  2565. // query\update that does not require
  2566. //
  2567. flag = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST;
  2568. #if 0
  2569. if ( !fGetIpAddrs )
  2570. {
  2571. flag |= GAA_FLAG_SKIP_UNICAST;
  2572. }
  2573. #endif
  2574. padapterList = IpHelp_GetAdaptersAddresses(
  2575. PF_UNSPEC,
  2576. flag );
  2577. if ( !padapterList )
  2578. {
  2579. status = GetLastError();
  2580. DNS_ASSERT( status != NO_ERROR );
  2581. goto Cleanup;
  2582. }
  2583. // count up the active adapters
  2584. padapter = padapterList;
  2585. count = 0;
  2586. while ( padapter )
  2587. {
  2588. count++;
  2589. padapter = padapter->Next;
  2590. }
  2591. //
  2592. // allocate net info blob
  2593. // allocate DNS server IP array
  2594. //
  2595. pnetInfo = NetInfo_Alloc( count );
  2596. if ( !pnetInfo )
  2597. {
  2598. status = DNS_ERROR_NO_MEMORY;
  2599. goto Cleanup;
  2600. }
  2601. //
  2602. // loop through adapters -- build network info for each
  2603. //
  2604. padapter = padapterList;
  2605. while ( padapter )
  2606. {
  2607. DWORD adapterFlags = 0;
  2608. PWSTR pnameAdapter = NULL;
  2609. PWSTR padapterDomainName = NULL;
  2610. PDNS_ADDR_ARRAY pserverArray = NULL;
  2611. PDNS_ADDR_ARRAY plocalArray = NULL;
  2612. //
  2613. // read adapter registry info
  2614. //
  2615. // DCR: can skip adapter domain name read
  2616. // it's in IP help adapter, just need policy override
  2617. // DCR: can skip DDNS read, and register read
  2618. // again, except for policy overrides
  2619. //
  2620. // DCR: could just have an "ApplyPolicyOverridesToAdapterInfo()" sort
  2621. // of function and get the rest from
  2622. //
  2623. pnameAdapter = Dns_StringCopyAllocate(
  2624. padapter->AdapterName,
  2625. 0,
  2626. DnsCharSetAnsi,
  2627. DnsCharSetUnicode );
  2628. if ( !pnameAdapter )
  2629. {
  2630. status = DNS_ERROR_NO_MEMORY;
  2631. goto Cleanup;
  2632. }
  2633. status = Reg_ReadAdapterInfo(
  2634. pnameAdapter,
  2635. pregSession,
  2636. & regInfo, // policy adapter info
  2637. & regAdapterInfo // receives reg info read
  2638. );
  2639. if ( status != NO_ERROR )
  2640. {
  2641. status = Reg_DefaultAdapterInfo(
  2642. & regAdapterInfo,
  2643. & regInfo,
  2644. padapter );
  2645. if ( status != NO_ERROR )
  2646. {
  2647. DNS_ASSERT( FALSE );
  2648. goto Skip;
  2649. }
  2650. }
  2651. // translate results into flags
  2652. if ( regAdapterInfo.fRegistrationEnabled )
  2653. {
  2654. adapterFlags |= AINFO_FLAG_REGISTER_IP_ADDRESSES;
  2655. }
  2656. if ( regAdapterInfo.fRegisterAdapterName )
  2657. {
  2658. adapterFlags |= AINFO_FLAG_REGISTER_DOMAIN_NAME;
  2659. }
  2660. // use domain name?
  2661. // - if disable on per adapter basis, then it's dead
  2662. if ( regAdapterInfo.fQueryAdapterName )
  2663. {
  2664. padapterDomainName = regAdapterInfo.pszAdapterDomainName;
  2665. regAdapterInfo.pszAdapterDomainName = NULL;
  2666. }
  2667. // DCR: could get DDNS and registration for adapter
  2668. // set flag on DHCP adapters
  2669. if ( padapter->Flags & IP_ADAPTER_DHCP_ENABLED )
  2670. {
  2671. adapterFlags |= AINFO_FLAG_IS_DHCP_CFG_ADAPTER;
  2672. }
  2673. //
  2674. // get adapter's IP addresses
  2675. //
  2676. fuseIp = fGetIpAddrs;
  2677. if ( fuseIp )
  2678. {
  2679. status = IpHelp_ReadAddrsFromList(
  2680. padapter->FirstUnicastAddress,
  2681. TRUE, // unicast addrs
  2682. 0, // no screening
  2683. 0, // no screening
  2684. & plocalArray, // local addrs
  2685. NULL, // IP6 only
  2686. NULL, // IP4 only
  2687. NULL, // no IP6 count
  2688. NULL // no IP4 count
  2689. );
  2690. if ( status != NO_ERROR )
  2691. {
  2692. goto Cleanup;
  2693. }
  2694. }
  2695. #if 0
  2696. //
  2697. // get per-adapter information from the iphlpapi.dll.
  2698. // -- autonet
  2699. //
  2700. // FIX6: do we need autonet info?
  2701. pserverArray = NULL;
  2702. status = IpHelp_GetPerAdapterInfo(
  2703. padapter->Index,
  2704. & pperAdapterInfo );
  2705. if ( status == NO_ERROR )
  2706. {
  2707. if ( pperAdapterInfo->AutoconfigEnabled &&
  2708. pperAdapterInfo->AutoconfigActive )
  2709. {
  2710. adapterFlags |= AINFO_FLAG_IS_AUTONET_ADAPTER;
  2711. }
  2712. }
  2713. #endif
  2714. //
  2715. // build DNS list
  2716. //
  2717. if ( padapter->FirstDnsServerAddress )
  2718. {
  2719. status = IpHelp_ReadAddrsFromList(
  2720. padapter->FirstDnsServerAddress,
  2721. FALSE, // not unicast addrs
  2722. 0, // no screening
  2723. 0, // no screening
  2724. & pserverArray, // get combined list
  2725. NULL, // no IP6 only
  2726. NULL, // no IP4 only
  2727. NULL, // no IP6 count
  2728. NULL // no IP4 count
  2729. );
  2730. if ( status != NO_ERROR )
  2731. {
  2732. goto Cleanup;
  2733. }
  2734. fhaveDnsServers = TRUE;
  2735. }
  2736. else
  2737. {
  2738. #if 0
  2739. //
  2740. // note: this feature doesn't work very well
  2741. // it kicks in when cable unplugged and get into auto-net
  2742. // scenario ... and then can bring in an unconfigured
  2743. // DNS server and give us long timeouts
  2744. //
  2745. // DCR: pointing to local DNS server
  2746. // a good approach would be to point to local DNS on ALL
  2747. // adapters when we fail to find ANY DNS servers at all
  2748. //
  2749. //
  2750. // if no DNS servers found -- use loopback if on DNS server
  2751. //
  2752. if ( g_IsDnsServer )
  2753. {
  2754. pserverArray = DnsAddrArray_Create( 1 );
  2755. if ( !pserverArray )
  2756. {
  2757. goto Skip;
  2758. }
  2759. DnsAddrArray_InitSingleWithIp4(
  2760. pserverArray,
  2761. DNS_NET_ORDER_LOOPBACK );
  2762. }
  2763. #endif
  2764. }
  2765. //
  2766. // build adapter info
  2767. //
  2768. // optionally add IP and subnet list; note this is
  2769. // direct add of data (not alloc\copy) so clear pointers
  2770. // after to skip free
  2771. //
  2772. // DCR: no failure case on adapter create failure???
  2773. //
  2774. // DCR: when do we need non-server adapters? for mcast?
  2775. //
  2776. // DCR: we could create Adapter name in unicode (above) then
  2777. // just copy it in;
  2778. // DCR: could preserve adapter domain name in blob, and NULL
  2779. // out the string in regAdapterInfo
  2780. //
  2781. if ( pserverArray || plocalArray )
  2782. {
  2783. PDNS_ADAPTER pnewAdapter = &pnetInfo->AdapterArray[ createdAdapterCount ];
  2784. AdapterInfo_Init(
  2785. pnewAdapter,
  2786. TRUE, // zero init
  2787. adapterFlags,
  2788. pnameAdapter,
  2789. padapterDomainName,
  2790. plocalArray,
  2791. pserverArray
  2792. );
  2793. pnewAdapter->InterfaceIndex = padapter->IfIndex;
  2794. pnetInfo->AdapterCount = ++createdAdapterCount;
  2795. pnameAdapter = NULL;
  2796. padapterDomainName = NULL;
  2797. plocalArray = NULL;
  2798. pserverArray = NULL;
  2799. }
  2800. Skip:
  2801. //
  2802. // cleanup adapter specific data
  2803. //
  2804. // note: no free of pserverArray, it IS the
  2805. // ptempArray buffer that we free at the end
  2806. //
  2807. Reg_FreeAdapterInfo(
  2808. &regAdapterInfo,
  2809. FALSE // don't free blob, it is on stack
  2810. );
  2811. if ( pnameAdapter );
  2812. {
  2813. FREE_HEAP( pnameAdapter );
  2814. }
  2815. if ( padapterDomainName );
  2816. {
  2817. FREE_HEAP( padapterDomainName );
  2818. }
  2819. if ( pserverArray );
  2820. {
  2821. DnsAddrArray_Free( pserverArray );
  2822. }
  2823. if ( plocalArray )
  2824. {
  2825. DnsAddrArray_Free( plocalArray );
  2826. }
  2827. // get next adapter
  2828. // reset status, so failure on the last adapter is not
  2829. // seen as global failure
  2830. padapter = padapter->Next;
  2831. status = ERROR_SUCCESS;
  2832. }
  2833. //
  2834. // no DNS servers?
  2835. // - use loopback if we are on MS DNS
  2836. // - otherwise note netinfo useless for lookup
  2837. //
  2838. // when self-pointing:
  2839. // - setup all adapters so we preserve adapter domain names for lookup
  2840. // - mark adapters as auto-loopback; send code will then avoid continuing
  2841. // query on other adapters
  2842. //
  2843. // note, i specifically choose this approach rather than configuring on any
  2844. // serverless adapter even if other adapters have DNS servers
  2845. // this avoids two problems:
  2846. // - server is poorly configured but CAN answer and fast local resolution
  2847. // blocks resolution through real DNS servers
  2848. // - network edge scenarios where DNS may be out-facing, but DNS client
  2849. // resolution may be intentionally desired to be only internal (admin network)
  2850. // in both cases i don't want to "pop" local DNS into the mix when it is unintended.
  2851. // when it is intended the easy workaround is to configure it explicitly
  2852. //
  2853. if ( !fhaveDnsServers )
  2854. {
  2855. if ( g_IsDnsServer )
  2856. {
  2857. DWORD i;
  2858. for ( i=0; i<pnetInfo->AdapterCount; i++ )
  2859. {
  2860. PDNS_ADAPTER padapt = NetInfo_GetAdapterByIndex( pnetInfo, i );
  2861. PDNS_ADDR_ARRAY pserverArray = NULL;
  2862. pserverArray = DnsAddrArray_Create( 1 );
  2863. if ( !pserverArray )
  2864. {
  2865. status = DNS_ERROR_NO_MEMORY;
  2866. goto Cleanup;
  2867. }
  2868. DnsAddrArray_InitSingleWithIp4(
  2869. pserverArray,
  2870. DNS_NET_ORDER_LOOPBACK );
  2871. padapt->pDnsAddrs = pserverArray;
  2872. padapt->InfoFlags &= ~AINFO_FLAG_IGNORE_ADAPTER;
  2873. padapt->InfoFlags |= AINFO_FLAG_SERVERS_AUTO_LOOPBACK;
  2874. }
  2875. }
  2876. else
  2877. {
  2878. pnetInfo->InfoFlags |= NINFO_FLAG_NO_DNS_SERVERS;
  2879. }
  2880. }
  2881. //
  2882. // eliminate unreachable DNS servers
  2883. //
  2884. if ( g_ScreenUnreachableServers )
  2885. {
  2886. StrikeOutUnreachableDnsServers( pnetInfo );
  2887. }
  2888. //
  2889. // build search list for network info
  2890. // - skip if no active adapters found
  2891. //
  2892. // DCR: shouldn't build search list?
  2893. //
  2894. // DCR: only build if actually read search list
  2895. //
  2896. if ( pnetInfo->AdapterCount )
  2897. {
  2898. pnetInfo->pSearchList = SearchList_Build(
  2899. regInfo.pszPrimaryDomainName,
  2900. pregSession,
  2901. NULL, // no explicit key
  2902. pnetInfo,
  2903. regInfo.fUseNameDevolution
  2904. );
  2905. if ( !pnetInfo->pSearchList )
  2906. {
  2907. status = DNS_ERROR_NO_MEMORY;
  2908. goto Cleanup;
  2909. }
  2910. }
  2911. //
  2912. // host and domain name info
  2913. //
  2914. pnetInfo->pszDomainName = Dns_CreateStringCopy_W( regInfo.pszPrimaryDomainName );
  2915. pnetInfo->pszHostName = Dns_CreateStringCopy_W( regInfo.pszHostName );
  2916. // timestamp
  2917. pnetInfo->TimeStamp = Dns_GetCurrentTimeInSeconds();
  2918. //
  2919. // set default server priorities
  2920. //
  2921. NetInfo_ResetServerPriorities( pnetInfo, FALSE );
  2922. Cleanup:
  2923. // free allocated reg info
  2924. Reg_FreeGlobalInfo(
  2925. pregInfo,
  2926. FALSE // don't free blob, it is on stack
  2927. );
  2928. if ( padapterList )
  2929. {
  2930. FREE_HEAP( padapterList );
  2931. }
  2932. if ( pnetInfo &&
  2933. pnetInfo->AdapterCount == 0 )
  2934. {
  2935. status = DNS_ERROR_NO_DNS_SERVERS;
  2936. }
  2937. // close registry session
  2938. Reg_CloseSession( pregSession );
  2939. if ( status != ERROR_SUCCESS )
  2940. {
  2941. NetInfo_Free( pnetInfo );
  2942. DNSDBG( TRACE, (
  2943. "Leave: NetInfo_Build()\n"
  2944. "\tstatus = %d\n",
  2945. status ));
  2946. SetLastError( status );
  2947. return( NULL );
  2948. }
  2949. IF_DNSDBG( NETINFO2 )
  2950. {
  2951. DnsDbg_NetworkInfo(
  2952. "New Netinfo:",
  2953. pnetInfo );
  2954. }
  2955. DNSDBG( TRACE, (
  2956. "\nLeave: NetInfo_Build()\n\n\n"
  2957. "\treturning fresh built network info (%p)\n",
  2958. pnetInfo ));
  2959. return( pnetInfo );
  2960. }
  2961. //
  2962. // Local address list
  2963. //
  2964. DWORD
  2965. netinfo_AddrFlagForConfigFlag(
  2966. IN DWORD ConfigFlag
  2967. )
  2968. /*++
  2969. Routine Description:
  2970. Build the DNS_ADDR flag for a given config flag.
  2971. Arguments:
  2972. ConfigFlag -- config flag we're given.
  2973. Return Value:
  2974. Flag in DNS_ADDR. Note this covers only the bits in DNSADDR_FLAG_TYPE_MASK
  2975. not the entire flag.
  2976. --*/
  2977. {
  2978. DWORD flag = 0;
  2979. if ( ConfigFlag & DNS_CONFIG_FLAG_ADDR_PUBLIC )
  2980. {
  2981. flag |= DNSADDR_FLAG_PUBLIC;
  2982. }
  2983. if ( ConfigFlag & DNS_CONFIG_FLAG_ADDR_CLUSTER )
  2984. {
  2985. flag |= DNSADDR_FLAG_TRANSIENT;
  2986. }
  2987. return flag;
  2988. }
  2989. BOOL
  2990. netinfo_LocalAddrScreen(
  2991. IN PDNS_ADDR pAddr,
  2992. IN PDNS_ADDR pScreenAddr
  2993. )
  2994. /*++
  2995. Routine Description:
  2996. Check DNS_ADDR against screening critera for local addr build.
  2997. Arguments:
  2998. pAddr -- address to screen
  2999. pScreenAddr -- screening info
  3000. Return Value:
  3001. TRUE if local addr passes screen.
  3002. FALSE otherwise.
  3003. --*/
  3004. {
  3005. DWORD family = DnsAddr_Family( pScreenAddr );
  3006. DWORD flags;
  3007. // screen family
  3008. if ( family &&
  3009. family != DnsAddr_Family(pAddr) )
  3010. {
  3011. return FALSE;
  3012. }
  3013. // screen flags
  3014. // - exact match on address type flag bits
  3015. return ( (pAddr->Flags & pScreenAddr->DnsAddrFlagScreeningMask)
  3016. == pScreenAddr->Flags);
  3017. }
  3018. DNS_STATUS
  3019. netinfo_ReadLocalAddrs(
  3020. IN OUT PDNS_ADDR_ARRAY pAddrArray,
  3021. IN PDNS_NETINFO pNetInfo,
  3022. IN PDNS_ADAPTER pSingleAdapter, OPTIONAL
  3023. IN OUT PDNS_ADDR pScreenAddr,
  3024. IN DWORD AddrFlags,
  3025. IN DWORD AddrMask,
  3026. IN DWORD ReadCount
  3027. )
  3028. /*++
  3029. Routine Description:
  3030. Create IP array of DNS servers from network info.
  3031. Arguments:
  3032. pAddrArray -- local address array being built
  3033. pNetInfo -- DNS net adapter list to convert
  3034. pSingleAdapter -- just do this one adapter
  3035. pScreenAddr -- address screening blob;
  3036. note: there's no true OUT info, but the screen addr
  3037. is altered to match AddrFlags
  3038. AddrFlags -- addr flag we're interested in
  3039. ReadCount -- count to read
  3040. 1 -- just one
  3041. MAXDWORD -- all
  3042. 0 -- all on second pass
  3043. Return Value:
  3044. NO_ERROR if successful.
  3045. Otherwise error code from add.
  3046. --*/
  3047. {
  3048. PDNS_ADDR_ARRAY parray = NULL;
  3049. PDNS_ADAPTER padapter;
  3050. DNS_STATUS status = NO_ERROR;
  3051. DWORD dupFlag = 0;
  3052. DWORD screenMask;
  3053. DWORD iter;
  3054. DNSDBG( TRACE, (
  3055. "netinfo_ReadLocalAddrs( %p, %p, %p, %08x, %08x, %d )\n",
  3056. pNetInfo,
  3057. pSingleAdapter,
  3058. pScreenAddr,
  3059. AddrFlags,
  3060. AddrMask,
  3061. ReadCount ));
  3062. //
  3063. // get DNS_ADDR flag for the address type we're reading
  3064. //
  3065. // note we have the classic and\or problem
  3066. // the addresses are denoted by two flags (from iphelp):
  3067. // DNSADDR_FLAG_PUBLIC
  3068. // DNSADDR_FLAG_TRANSIENT
  3069. //
  3070. // but we need both flags and mask to determine all the possible gatherings
  3071. // we want to do
  3072. //
  3073. // right now the DNS_CONFIG_FLAG_X are ORd together to get UNIONS of addresses
  3074. // we are willing to accept, but we go through the list multiple times to build
  3075. // the list favoring the public over private, non-cluster over cluster
  3076. //
  3077. // so currently when say you want DNS_CONFIG_PUBLIC you mean public and not-cluster;
  3078. // ditto for private; on the other hand when you say DNS_CONFIG_CLUSTER you are
  3079. // asking for all cluster (though we could screen on whether PUBLIC, PRIVATE both or
  3080. // neither were specified
  3081. //
  3082. pScreenAddr->Flags = netinfo_AddrFlagForConfigFlag( AddrFlags );
  3083. screenMask = DNSADDR_FLAG_TYPE_MASK;
  3084. if ( AddrMask != 0 )
  3085. {
  3086. screenMask = netinfo_AddrFlagForConfigFlag( AddrMask );
  3087. }
  3088. pScreenAddr->DnsAddrFlagScreeningMask = screenMask;
  3089. //
  3090. // read count
  3091. // = 0 means second pass on list
  3092. // -> read all, but do full duplicate screen to skip the
  3093. // addresses read on the first pass
  3094. if ( ReadCount == 0 )
  3095. {
  3096. ReadCount = MAXDWORD;
  3097. dupFlag = DNSADDR_MATCH_ALL;
  3098. }
  3099. //
  3100. // loop through all adapters
  3101. //
  3102. for ( iter=0; iter<pNetInfo->AdapterCount; iter++ )
  3103. {
  3104. padapter = NetInfo_GetAdapterByIndex( pNetInfo, iter );
  3105. if ( !pSingleAdapter ||
  3106. pSingleAdapter == padapter )
  3107. {
  3108. status = DnsAddrArray_AppendArrayEx(
  3109. pAddrArray,
  3110. padapter->pLocalAddrs,
  3111. ReadCount, // read address count
  3112. 0, // family check handled by screening
  3113. dupFlag,
  3114. netinfo_LocalAddrScreen,
  3115. pScreenAddr
  3116. );
  3117. }
  3118. //DNS_ASSERT( status == NO_ERROR );
  3119. }
  3120. return status;
  3121. }
  3122. PADDR_ARRAY
  3123. NetInfo_CreateLocalAddrArray(
  3124. IN PDNS_NETINFO pNetInfo,
  3125. IN PWSTR pwsAdapterName, OPTIONAL
  3126. IN PDNS_ADAPTER pAdapter, OPTIONAL
  3127. IN DWORD Family, OPTIONAL
  3128. IN DWORD AddrFlags OPTIONAL
  3129. )
  3130. /*++
  3131. Routine Description:
  3132. Create IP array of DNS servers from network info.
  3133. Arguments:
  3134. pNetInfo -- DNS net adapter list to convert
  3135. pwsAdapterName -- specific adapter; NULL for all adapters
  3136. pAdapter -- specific adapter; NULL for all adapters
  3137. Family -- required specific address family; 0 for any family
  3138. AddrFlags -- address selection flags
  3139. DNS_CONFIG_FLAG_INCLUDE_CLUSTER
  3140. AddrFlagsMask -- mask on selecting flags
  3141. Return Value:
  3142. Ptr to IP array, if successful
  3143. NULL on failure.
  3144. --*/
  3145. {
  3146. PADDR_ARRAY parray = NULL;
  3147. DWORD iter;
  3148. DWORD countAddrs = 0;
  3149. PDNS_ADAPTER padapter;
  3150. PDNS_ADAPTER padapterSingle = NULL;
  3151. DNS_STATUS status = NO_ERROR;
  3152. DNS_ADDR screenAddr;
  3153. DNSDBG( TRACE, (
  3154. "NetInfo_CreateLocalAddrArray( %p, %S, %p, %d, %08x )\n",
  3155. pNetInfo,
  3156. pwsAdapterName,
  3157. pAdapter,
  3158. Family,
  3159. AddrFlags ));
  3160. //
  3161. // get count
  3162. //
  3163. if ( ! pNetInfo )
  3164. {
  3165. return NULL;
  3166. }
  3167. padapterSingle = pAdapter;
  3168. if ( pwsAdapterName && !padapterSingle )
  3169. {
  3170. padapterSingle = NetInfo_GetAdapterByName( pNetInfo, pwsAdapterName );
  3171. if ( !padapterSingle )
  3172. {
  3173. goto Done;
  3174. }
  3175. }
  3176. //
  3177. // setup screening addr
  3178. //
  3179. // if not address flag -- get all types
  3180. //
  3181. if ( AddrFlags == 0 )
  3182. {
  3183. AddrFlags = (DWORD)(-1);
  3184. }
  3185. RtlZeroMemory( &screenAddr, sizeof(screenAddr) );
  3186. screenAddr.Sockaddr.sa_family = (WORD)Family;
  3187. //
  3188. // count addrs
  3189. //
  3190. // DCR: could count with based on addr info
  3191. //
  3192. for ( iter=0; iter<pNetInfo->AdapterCount; iter++ )
  3193. {
  3194. padapter = NetInfo_GetAdapterByIndex( pNetInfo, iter );
  3195. if ( !padapterSingle ||
  3196. padapterSingle == padapter )
  3197. {
  3198. countAddrs += DnsAddrArray_GetFamilyCount(
  3199. padapter->pLocalAddrs,
  3200. Family );
  3201. }
  3202. }
  3203. //
  3204. // allocate required array
  3205. //
  3206. parray = DnsAddrArray_Create( countAddrs );
  3207. if ( !parray )
  3208. {
  3209. status = DNS_ERROR_NO_MEMORY;
  3210. goto Done;
  3211. }
  3212. DNS_ASSERT( parray->MaxCount == countAddrs );
  3213. //
  3214. // read addrs "in order"
  3215. //
  3216. // historically gethostbyname() presented addrs
  3217. // - one from each adapter
  3218. // - then the rest from all adapters
  3219. //
  3220. // we preserve this, plus order by type
  3221. // - public DNS_ELIGIBLE first
  3222. // - private (autonet, IP6 local scope stuff)
  3223. // - cluster\transient last
  3224. //
  3225. //
  3226. // public (DNS_ELIGIBLE) addrs
  3227. // - screen on all flags, specifically don't pick up public cluster addrs
  3228. //
  3229. if ( AddrFlags & DNS_CONFIG_FLAG_ADDR_PUBLIC )
  3230. {
  3231. // read first "public" addr of each (or single) adapter
  3232. status = netinfo_ReadLocalAddrs(
  3233. parray,
  3234. pNetInfo,
  3235. padapterSingle,
  3236. & screenAddr,
  3237. DNS_CONFIG_FLAG_ADDR_PUBLIC,
  3238. 0, // exact match on all flags
  3239. 1 // read only one address
  3240. );
  3241. // read the rest of "public" addrs
  3242. status = netinfo_ReadLocalAddrs(
  3243. parray,
  3244. pNetInfo,
  3245. padapterSingle,
  3246. & screenAddr,
  3247. DNS_CONFIG_FLAG_ADDR_PUBLIC,
  3248. 0, // exact match on all flags
  3249. 0 // read the rest
  3250. );
  3251. }
  3252. //
  3253. // private (non-DNS-publish) addrs (autonet, IP6 local, sitelocal, etc.)
  3254. // - screen on all flags, specifically don't pick up private cluster addrs
  3255. //
  3256. if ( AddrFlags & DNS_CONFIG_FLAG_ADDR_PRIVATE )
  3257. {
  3258. status = netinfo_ReadLocalAddrs(
  3259. parray,
  3260. pNetInfo,
  3261. padapterSingle,
  3262. & screenAddr,
  3263. DNS_CONFIG_FLAG_ADDR_PRIVATE,
  3264. 0, // exact match on all flags
  3265. MAXDWORD // read all addrs
  3266. );
  3267. }
  3268. //
  3269. // cluster at end
  3270. // - only screen on cluster flag as public flag may
  3271. // also be set\clear
  3272. //
  3273. if ( AddrFlags & DNS_CONFIG_FLAG_ADDR_CLUSTER )
  3274. {
  3275. status = netinfo_ReadLocalAddrs(
  3276. parray,
  3277. pNetInfo,
  3278. padapterSingle,
  3279. & screenAddr,
  3280. DNS_CONFIG_FLAG_ADDR_CLUSTER,
  3281. DNS_CONFIG_FLAG_ADDR_CLUSTER, // any cluster match
  3282. MAXDWORD // read all addrs
  3283. );
  3284. }
  3285. Done:
  3286. if ( status != NO_ERROR )
  3287. {
  3288. SetLastError( status );
  3289. }
  3290. return( parray );
  3291. }
  3292. //
  3293. // Local address list presentation
  3294. //
  3295. PDNS_ADDR_ARRAY
  3296. NetInfo_GetLocalAddrArray(
  3297. IN PDNS_NETINFO pNetInfo,
  3298. IN PWSTR pwsAdapterName, OPTIONAL
  3299. IN DWORD AddrFamily, OPTIONAL
  3300. IN DWORD AddrFlags, OPTIONAL
  3301. IN BOOL fForce
  3302. )
  3303. /*++
  3304. Routine Description:
  3305. Get local addrs as array.
  3306. This is a combination NetInfo_Get\ConvertToLocalAddrArray routine.
  3307. It's purpose is to simplify getting local address info, while avoiding
  3308. costly NetInfo rebuilds where they are unnecessary.
  3309. Arguments:
  3310. pNetInfo -- existing netinfo to use
  3311. pwsAdapterName -- specific adapter name; NULL for all adapters
  3312. AddrFamily -- specific address family; 0 for all
  3313. AddrFlags -- flags to indicate addrs to consider
  3314. DNS_CONFIG_FLAG_INCLUDE_CLUSTER
  3315. fForce -- force reread from registry
  3316. Return Value:
  3317. ERROR_SUCCESS if successful.
  3318. Error code on failure.
  3319. --*/
  3320. {
  3321. PDNS_NETINFO pnetInfo = NULL;
  3322. PADDR_ARRAY parray = NULL;
  3323. DNS_STATUS status = NO_ERROR;
  3324. DNSDBG( TRACE, (
  3325. "NetInfo_GetLocalAddrArray()\n"
  3326. "\tpnetinfo = %p\n"
  3327. "\tadapter = %S\n"
  3328. "\tfamily = %d\n"
  3329. "\tflags = %08x\n"
  3330. "\tforce = %d\n",
  3331. pNetInfo,
  3332. pwsAdapterName,
  3333. AddrFamily,
  3334. AddrFlags,
  3335. fForce
  3336. ));
  3337. //
  3338. // get network info to make list from
  3339. // - if force, full reread
  3340. // - otherwise gethostbyname() scenario
  3341. // - accept local caching for very short interval just for perf
  3342. // - accept resolver
  3343. //
  3344. // DCR: force first gethostbyname() call to resolver\registry?
  3345. // have to define "first", in a way that's different from netinfo()
  3346. // in last second
  3347. //
  3348. pnetInfo = pNetInfo;
  3349. if ( !pnetInfo )
  3350. {
  3351. DWORD getFlag = NIFLAG_GET_LOCAL_ADDRS;
  3352. DWORD timeout;
  3353. if ( fForce )
  3354. {
  3355. getFlag |= NIFLAG_FORCE_REGISTRY_READ;
  3356. timeout = 0;
  3357. }
  3358. else
  3359. {
  3360. getFlag |= NIFLAG_READ_RESOLVER;
  3361. getFlag |= NIFLAG_READ_PROCESS_CACHE;
  3362. timeout = 1;
  3363. }
  3364. pnetInfo = NetInfo_Get(
  3365. getFlag,
  3366. timeout
  3367. );
  3368. if ( !pnetInfo )
  3369. {
  3370. status = DNS_ERROR_NO_TCPIP;
  3371. goto Done;
  3372. }
  3373. }
  3374. //
  3375. // cluster filter info
  3376. // -- check environment variable
  3377. //
  3378. // DCR: once RnR no longer using myhostent() for gethostbyname()
  3379. // then can remove
  3380. if ( g_IsServer &&
  3381. (AddrFlags & DNS_CONFIG_FLAG_READ_CLUSTER_ENVAR) &&
  3382. !(AddrFlags & DNS_CONFIG_FLAG_ADDR_CLUSTER) )
  3383. {
  3384. ENVAR_DWORD_INFO filterInfo;
  3385. Reg_ReadDwordEnvar(
  3386. RegIdFilterClusterIp,
  3387. &filterInfo );
  3388. if ( !filterInfo.fFound ||
  3389. !filterInfo.Value )
  3390. {
  3391. AddrFlags |= DNS_CONFIG_FLAG_ADDR_CLUSTER;
  3392. }
  3393. }
  3394. //
  3395. // convert network info to IP4_ARRAY
  3396. //
  3397. parray = NetInfo_CreateLocalAddrArray(
  3398. pnetInfo,
  3399. pwsAdapterName,
  3400. NULL, // no specific adapter ptr
  3401. AddrFamily,
  3402. AddrFlags
  3403. );
  3404. if ( !parray )
  3405. {
  3406. status = GetLastError();
  3407. goto Done;
  3408. }
  3409. // if no IPs found, return
  3410. if ( parray->AddrCount == 0 )
  3411. {
  3412. DNS_PRINT((
  3413. "NetInfo_GetLocalAddrArray() failed: no addrs found\n"
  3414. "\tstatus = %d\n" ));
  3415. status = DNS_ERROR_NO_TCPIP;
  3416. goto Done;
  3417. }
  3418. IF_DNSDBG( NETINFO )
  3419. {
  3420. DNS_PRINT(( "Leaving Netinfo_GetLocalAddrArray()\n" ));
  3421. DnsDbg_DnsAddrArray(
  3422. "Local addr list",
  3423. "server",
  3424. parray );
  3425. }
  3426. Done:
  3427. // free netinfo built here
  3428. if ( pnetInfo != pNetInfo )
  3429. {
  3430. NetInfo_Free( pnetInfo );
  3431. }
  3432. if ( status != NO_ERROR )
  3433. {
  3434. FREE_HEAP( parray );
  3435. parray = NULL;
  3436. SetLastError( status );
  3437. }
  3438. return( parray );
  3439. }
  3440. PIP4_ARRAY
  3441. NetInfo_GetLocalAddrArrayIp4(
  3442. IN PWSTR pwsAdapterName, OPTIONAL
  3443. IN DWORD Flags,
  3444. IN BOOL fForce
  3445. )
  3446. /*++
  3447. Routine Description:
  3448. Get DNS server list as IP array.
  3449. Arguments:
  3450. pwsAdapterName -- specific adapter name; NULL for all adapters
  3451. Flags -- flags to indicate addrs to consider
  3452. DNS_CONFIG_FLAG_X
  3453. fForce -- force reread from registry
  3454. Return Value:
  3455. ERROR_SUCCESS if successful.
  3456. Error code on failure.
  3457. --*/
  3458. {
  3459. PADDR_ARRAY parray;
  3460. PIP4_ARRAY parray4 = NULL;
  3461. DNS_STATUS status = NO_ERROR;
  3462. DNSDBG( TRACE, ( "NetInfo_GetLocalAddrArrayIp4()\n" ));
  3463. //
  3464. // get DNS server list
  3465. //
  3466. parray = NetInfo_GetLocalAddrArray(
  3467. NULL, // no existing netinfo
  3468. pwsAdapterName,
  3469. AF_INET,
  3470. Flags,
  3471. fForce );
  3472. if ( !parray )
  3473. {
  3474. goto Done;
  3475. }
  3476. //
  3477. // convert array to IP4 array
  3478. //
  3479. parray4 = DnsAddrArray_CreateIp4Array( parray );
  3480. if ( !parray4 )
  3481. {
  3482. status = DNS_ERROR_NO_MEMORY;
  3483. goto Done;
  3484. }
  3485. DNS_ASSERT( parray4->AddrCount > 0 );
  3486. Done:
  3487. DnsAddrArray_Free( parray );
  3488. if ( status != NO_ERROR )
  3489. {
  3490. SetLastError( status );
  3491. }
  3492. return( parray4 );
  3493. }
  3494. //
  3495. // End netinfo.c
  3496. //