Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3247 lines
67 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. //
  15. // Registry info
  16. //
  17. #define DNS_REG_READ_BUF_SIZE (1000)
  18. #define LOCALHOST "127.0.0.1"
  19. //
  20. // Netinfo cache
  21. //
  22. // Do in process caching of netinfo for brief period for perf
  23. // Currently cache for only 10s
  24. // Locking currently just using general CS
  25. //
  26. PDNS_NETINFO g_pNetInfo = NULL;
  27. #define NETINFO_CACHE_TIMEOUT (10) // 10 seconds
  28. #define LOCK_NETINFO() LOCK_GENERAL()
  29. #define UNLOCK_NETINFO() UNLOCK_GENERAL()
  30. //
  31. // Adapter info routines
  32. //
  33. DWORD
  34. AdapterInfo_SizeForServerCount(
  35. IN DWORD ServerCount
  36. )
  37. /*++
  38. Routine Description:
  39. Size in bytes of adapter info for given server count.
  40. Arguments:
  41. ServerCount -- max count of servers adapter will hold
  42. Return Value:
  43. Size in bytes of ADAPTER_INFO blob.
  44. --*/
  45. {
  46. return sizeof(DNS_ADAPTER)
  47. - sizeof(DNS_SERVER_INFO)
  48. + (sizeof(DNS_SERVER_INFO) * ServerCount);
  49. }
  50. PDNS_ADAPTER
  51. AdapterInfo_Alloc(
  52. IN DWORD ServerCount
  53. )
  54. /*++
  55. Routine Description:
  56. Create uninitialized DNS Server list.
  57. Arguments:
  58. ServerCount -- count of servers list will hold
  59. Return Value:
  60. Ptr to uninitialized adapter, if successful
  61. NULL on failure.
  62. --*/
  63. {
  64. DNSDBG( TRACE, ( "AdapterInfo_Alloc()\n" ));
  65. //
  66. // allocate blob for adapter info
  67. //
  68. return (PDNS_ADAPTER)
  69. ALLOCATE_HEAP_ZERO(
  70. AdapterInfo_SizeForServerCount( ServerCount ) );
  71. }
  72. VOID
  73. AdapterInfo_Free(
  74. IN OUT PDNS_ADAPTER pAdapter
  75. )
  76. /*++
  77. Routine Description:
  78. Free DNS_ADAPTER structure.
  79. Arguments:
  80. pAdapter -- pointer to adapter blob to free
  81. Return Value:
  82. None.
  83. --*/
  84. {
  85. DNSDBG( TRACE, ( "AdapterInfo_Free( %p )\n", pAdapter ));
  86. if ( !pAdapter )
  87. {
  88. return;
  89. }
  90. if ( pAdapter->pszAdapterGuidName )
  91. {
  92. FREE_HEAP( pAdapter->pszAdapterGuidName );
  93. }
  94. if ( pAdapter->pszAdapterDomain )
  95. {
  96. FREE_HEAP( pAdapter->pszAdapterDomain );
  97. }
  98. if ( pAdapter->pAdapterIPAddresses )
  99. {
  100. FREE_HEAP( pAdapter->pAdapterIPAddresses );
  101. }
  102. if ( pAdapter->pAdapterIPSubnetMasks )
  103. {
  104. FREE_HEAP( pAdapter->pAdapterIPSubnetMasks );
  105. }
  106. FREE_HEAP( pAdapter );
  107. }
  108. PDNS_ADAPTER
  109. AdapterInfo_Copy(
  110. IN PDNS_ADAPTER pAdapter
  111. )
  112. /*++
  113. Routine Description:
  114. Create copy of DNS adapter info.
  115. Arguments:
  116. pAdapter -- DNS adapter to copy
  117. Return Value:
  118. Ptr to DNS adapter info copy, if successful
  119. NULL on failure.
  120. --*/
  121. {
  122. PDNS_ADAPTER pcopy;
  123. DNSDBG( TRACE, ( "AdapterInfo_Copy( %p )\n", pAdapter ));
  124. if ( ! pAdapter )
  125. {
  126. return NULL;
  127. }
  128. pcopy = AdapterInfo_Alloc( pAdapter->ServerCount );
  129. if ( ! pcopy )
  130. {
  131. return NULL;
  132. }
  133. //
  134. // copy the whole blob
  135. // - reset MaxServerCount to actual allocation
  136. RtlCopyMemory(
  137. pcopy,
  138. pAdapter,
  139. AdapterInfo_SizeForServerCount( pAdapter->ServerCount ) );
  140. pcopy->MaxServerCount = pAdapter->ServerCount;
  141. // fixup allocated subfields
  142. pcopy->pszAdapterGuidName = Dns_CreateStringCopy(
  143. pAdapter->pszAdapterGuidName,
  144. 0 );
  145. pcopy->pszAdapterDomain = Dns_CreateStringCopy(
  146. pAdapter->pszAdapterDomain,
  147. 0 );
  148. pcopy->pAdapterIPAddresses = Dns_CreateIpArrayCopy(
  149. pAdapter->pAdapterIPAddresses );
  150. pcopy->pAdapterIPSubnetMasks = Dns_CreateIpArrayCopy(
  151. pAdapter->pAdapterIPSubnetMasks );
  152. return( pcopy );
  153. }
  154. PDNS_ADAPTER
  155. AdapterInfo_Create(
  156. IN DWORD ServerCount,
  157. IN DWORD dwFlags,
  158. IN PSTR pszDomain,
  159. IN PSTR pszGuidName
  160. )
  161. /*++
  162. Routine Description:
  163. Create uninitialized DNS Server list.
  164. Arguments:
  165. ServerCount -- count of servers list will hold
  166. dwFlags -- flags
  167. pszAdapterDomain -- the names of the domain associated with this
  168. interface
  169. pszGuidName -- GUID name
  170. Return Value:
  171. Ptr to adapter info, if successful
  172. NULL on failure.
  173. --*/
  174. {
  175. PDNS_ADAPTER padapter = NULL;
  176. DNSDBG( TRACE, ( "AdapterInfo_Create()\n" ));
  177. //
  178. // allocate blob for adapter info
  179. //
  180. padapter = AdapterInfo_Alloc( ServerCount );
  181. if ( ! padapter )
  182. {
  183. return NULL;
  184. }
  185. DNS_ASSERT( padapter->RunFlags == 0 );
  186. DNS_ASSERT( padapter->ServerCount == 0 );
  187. padapter->pszAdapterGuidName = Dns_CreateStringCopy( pszGuidName, 0 );
  188. padapter->pszAdapterDomain = Dns_CreateStringCopy( pszDomain, 0 );
  189. padapter->MaxServerCount = ServerCount;
  190. padapter->InfoFlags = dwFlags;
  191. return padapter;
  192. }
  193. PDNS_ADAPTER
  194. AdapterInfo_CreateFromIpArray(
  195. IN PIP_ARRAY pServerArray,
  196. IN DWORD dwFlags,
  197. IN PSTR pszDomainName,
  198. IN PSTR pszGuidName
  199. )
  200. /*++
  201. Routine Description:
  202. Create copy of IP address array as a DNS Server list.
  203. Arguments:
  204. pIpArray -- IP address array to convert
  205. dwFlags -- Flags that describe the adapter
  206. pszDomainName -- The default domain name for the adapter
  207. pszGuidName -- The registry GUID name for the adapter (if NT)
  208. Return Value:
  209. Ptr to DNS Server list copy, if successful
  210. NULL on failure.
  211. --*/
  212. {
  213. PDNS_ADAPTER padapter;
  214. DWORD i;
  215. DWORD count;
  216. DNSDBG( TRACE, ( "AdapterInfo_CreateFromIpArray()\n" ));
  217. //
  218. // get count of DNS servers
  219. //
  220. if ( !pServerArray )
  221. {
  222. count = 0;
  223. }
  224. else
  225. {
  226. count = pServerArray->AddrCount;
  227. }
  228. //
  229. // create adapter with server list of required size
  230. //
  231. padapter = AdapterInfo_Create(
  232. count,
  233. dwFlags,
  234. pszDomainName,
  235. pszGuidName );
  236. if ( !padapter )
  237. {
  238. return NULL;
  239. }
  240. //
  241. // copy DNS server IPs and clear other fields
  242. //
  243. // DCR_QUESTION: are fields already zero'd?
  244. //
  245. for ( i=0; i < count; i++ )
  246. {
  247. padapter->ServerArray[i].IpAddress = pServerArray->AddrArray[i];
  248. padapter->ServerArray[i].Status = NO_ERROR;
  249. padapter->ServerArray[i].Priority = 0;
  250. }
  251. padapter->ServerCount = count;
  252. return padapter;
  253. }
  254. //
  255. // Search list routines
  256. //
  257. PSEARCH_LIST
  258. SearchList_Alloc(
  259. IN DWORD MaxNameCount,
  260. IN PSTR pszName
  261. )
  262. /*++
  263. Routine Description:
  264. Create uninitialized search list.
  265. Arguments:
  266. NameCount -- count of search names list will hold
  267. pszName -- primary domain name
  268. Return Value:
  269. Ptr to uninitialized DNS search list, if successful
  270. NULL on failure.
  271. --*/
  272. {
  273. PSEARCH_LIST psearchList = NULL;
  274. DWORD length;
  275. DNSDBG( TRACE, ( "SearchList_Create()\n" ));
  276. if ( MaxNameCount == 0 && !pszName )
  277. {
  278. return NULL;
  279. }
  280. //
  281. // allocate for max entries
  282. //
  283. length = sizeof(SEARCH_LIST)
  284. - sizeof(SEARCH_NAME)
  285. + ( sizeof(SEARCH_NAME) * MaxNameCount );
  286. psearchList = (PSEARCH_LIST) ALLOCATE_HEAP_ZERO( length );
  287. if ( ! psearchList )
  288. {
  289. return NULL;
  290. }
  291. psearchList->MaxNameCount = MaxNameCount;
  292. if ( pszName )
  293. {
  294. psearchList->pszDomainOrZoneName = Dns_CreateStringCopy( pszName, 0 );
  295. if ( ! psearchList->pszDomainOrZoneName )
  296. {
  297. FREE_HEAP( psearchList );
  298. return NULL;
  299. }
  300. }
  301. return psearchList;
  302. }
  303. VOID
  304. SearchList_Free(
  305. IN OUT PSEARCH_LIST pSearchList
  306. )
  307. /*++
  308. Routine Description:
  309. Free SEARCH_LIST structure.
  310. Arguments:
  311. pSearchList -- ptr to search list to free
  312. Return Value:
  313. None
  314. --*/
  315. {
  316. DWORD i;
  317. DNSDBG( TRACE, ( "SearchList_Free( %p )\n", pSearchList ));
  318. //
  319. // DCR: eliminate search list DomainOrZoneName
  320. //
  321. if ( pSearchList )
  322. {
  323. if ( pSearchList->pszDomainOrZoneName )
  324. {
  325. FREE_HEAP( pSearchList->pszDomainOrZoneName );
  326. }
  327. for ( i=0; i < pSearchList->MaxNameCount; i++ )
  328. {
  329. PSTR pname = pSearchList->SearchNameArray[i].pszName;
  330. if ( pname )
  331. {
  332. FREE_HEAP( pname );
  333. }
  334. }
  335. FREE_HEAP( pSearchList );
  336. }
  337. }
  338. PSEARCH_LIST
  339. SearchList_Copy(
  340. IN PSEARCH_LIST pSearchList
  341. )
  342. /*++
  343. Routine Description:
  344. Create copy of search list.
  345. Arguments:
  346. pSearchList -- search list to copy
  347. Return Value:
  348. Ptr to DNS Search list copy, if successful
  349. NULL on failure.
  350. --*/
  351. {
  352. PSEARCH_LIST pcopy;
  353. DWORD i;
  354. DNSDBG( TRACE, ( "SearchList_Copy()\n" ));
  355. if ( ! pSearchList )
  356. {
  357. return NULL;
  358. }
  359. //
  360. // create DNS Search list of desired size
  361. //
  362. // since we don't add and delete from search list once
  363. // created, size copy only for actual name count
  364. //
  365. pcopy = SearchList_Alloc(
  366. pSearchList->NameCount,
  367. pSearchList->pszDomainOrZoneName );
  368. if ( ! pcopy )
  369. {
  370. return NULL;
  371. }
  372. for ( i=0; i < pSearchList->NameCount; i++ )
  373. {
  374. PSTR pname = pSearchList->SearchNameArray[i].pszName;
  375. if ( pname )
  376. {
  377. pname = Dns_CreateStringCopy(
  378. pname,
  379. 0 );
  380. if ( pname )
  381. {
  382. pcopy->SearchNameArray[i].pszName = pname;
  383. pcopy->SearchNameArray[i].Flags =
  384. pSearchList->SearchNameArray[i].Flags;
  385. pcopy->NameCount++;
  386. }
  387. }
  388. }
  389. return pcopy;
  390. }
  391. BOOL
  392. SearchList_ContainsName(
  393. IN PSEARCH_LIST pSearchList,
  394. IN PSTR pszName
  395. )
  396. /*++
  397. Routine Description:
  398. Check if name is in search list.
  399. Arguments:
  400. pSearchList -- ptr to search list being built
  401. pszName -- name to check
  402. Return Value:
  403. TRUE if name is in search list.
  404. FALSE otherwise.
  405. --*/
  406. {
  407. DWORD count = pSearchList->NameCount;
  408. //
  409. // check every search list entry for this name
  410. //
  411. while ( count-- )
  412. {
  413. if ( Dns_NameCompare_UTF8(
  414. pSearchList->SearchNameArray[ count ].pszName,
  415. pszName ) )
  416. {
  417. return( TRUE );
  418. }
  419. }
  420. return( FALSE );
  421. }
  422. VOID
  423. SearchList_AddName(
  424. IN OUT PSEARCH_LIST pSearchList,
  425. IN PSTR pszName,
  426. IN DWORD Flag
  427. )
  428. /*++
  429. Routine Description:
  430. Add name to search list.
  431. Arguments:
  432. pSearchList -- ptr to search list being built
  433. pszName -- name to add to search list
  434. Flag -- flag value
  435. Return Value:
  436. None. Name is added to search list, unless memory alloc failure.
  437. --*/
  438. {
  439. DWORD count = pSearchList->NameCount;
  440. PSTR pallocName;
  441. DNSDBG( TRACE, ( "Search_AddName()\n" ));
  442. //
  443. // ignore name is already in list
  444. // ignore if at list max
  445. //
  446. if ( SearchList_ContainsName(
  447. pSearchList,
  448. pszName )
  449. ||
  450. count >= pSearchList->MaxNameCount )
  451. {
  452. return;
  453. }
  454. // copy name and put in list
  455. pallocName = Dns_CreateStringCopy( pszName, 0 );
  456. if ( !pallocName )
  457. {
  458. return;
  459. }
  460. pSearchList->SearchNameArray[count].pszName = pallocName;
  461. //
  462. // set flag -- but first flag always zero (normal timeouts)
  463. // this protects against no PDN situation where use adapter
  464. // name as PDN;
  465. if ( count == 0 )
  466. {
  467. Flag = 0;
  468. }
  469. pSearchList->SearchNameArray[count].Flags = Flag;
  470. pSearchList->NameCount = ++count;
  471. }
  472. DNS_STATUS
  473. SearchList_Parse(
  474. IN OUT PSEARCH_LIST pSearchList,
  475. IN PSTR pszList
  476. )
  477. /*++
  478. Routine Description:
  479. Parse registry search list string into SEARCH_LIST structure.
  480. Arguments:
  481. pSearchList -- search list array
  482. pszList -- registry list of search names;
  483. names are comma or white space separated
  484. Return Value:
  485. ERROR_SUCCESS if successful.
  486. Error code on failure.
  487. --*/
  488. {
  489. register PCHAR pch = pszList;
  490. CHAR ch;
  491. PUCHAR pnameStart;
  492. DWORD countNames = pSearchList->NameCount;
  493. DNSDBG( NETINFO, (
  494. "SearchList_Parse( %p, %s )\n",
  495. pSearchList,
  496. pszList ));
  497. //
  498. // extract each domain name string in buffer,
  499. // and add to search list array
  500. //
  501. while( ch = *pch && countNames < DNS_MAX_SEARCH_LIST_ENTRIES )
  502. {
  503. // skip leading whitespace, find start of domain name string
  504. while( ch == ' ' || ch == '\t' || ch == ',' )
  505. {
  506. ch = *++pch;
  507. }
  508. if ( ch == 0 )
  509. {
  510. break;
  511. }
  512. pnameStart = pch;
  513. //
  514. // find end of string and NULL terminate
  515. //
  516. ch = *pch;
  517. while( ch != ' ' && ch != '\t' && ch != '\0' && ch != ',' )
  518. {
  519. ch = *++pch;
  520. }
  521. *pch = '\0';
  522. //
  523. // end of buffer?
  524. //
  525. if ( pch == pnameStart )
  526. {
  527. break;
  528. }
  529. //
  530. // whack any trailing dot on name
  531. //
  532. pch--;
  533. if ( *pch == '.' )
  534. {
  535. *pch = '\0';
  536. }
  537. pch++;
  538. //
  539. // make copy of the name
  540. //
  541. pSearchList->SearchNameArray[ countNames ].pszName =
  542. Dns_CreateStringCopy( pnameStart, 0 );
  543. if ( pSearchList->SearchNameArray[ countNames ].pszName )
  544. {
  545. pSearchList->SearchNameArray[ countNames ].Flags = 0;
  546. countNames++;
  547. }
  548. // if more continue
  549. if ( ch != 0 )
  550. {
  551. pch++;
  552. continue;
  553. }
  554. break;
  555. }
  556. // reset name count
  557. pSearchList->NameCount = countNames;
  558. return( ERROR_SUCCESS );
  559. }
  560. PSEARCH_LIST
  561. SearchList_Build(
  562. IN PSTR pszPrimaryDomainName,
  563. IN PREG_SESSION pRegSession,
  564. IN HKEY hKey,
  565. IN OUT PDNS_NETINFO pNetInfo,
  566. IN BOOL fUseDomainNameDevolution,
  567. IN BOOL fUseDotLocalDomain
  568. )
  569. /*++
  570. Routine Description:
  571. Build search list.
  572. Arguments:
  573. pszPrimaryDomainName -- primary domain name
  574. pRegSession -- registry session
  575. hKey -- registry key
  576. Return Value:
  577. Ptr to search list.
  578. NULL on error or no search list.
  579. --*/
  580. {
  581. PSEARCH_LIST ptempList;
  582. PSTR pregList = NULL;
  583. DWORD status;
  584. DNSDBG( TRACE, ( "Search_ListBuild()\n" ));
  585. ASSERT( pRegSession || hKey );
  586. //
  587. // create search list using PDN
  588. //
  589. ptempList = SearchList_Alloc(
  590. DNS_MAX_SEARCH_LIST_ENTRIES,
  591. pszPrimaryDomainName );
  592. if ( !ptempList )
  593. {
  594. return( NULL );
  595. }
  596. //
  597. // read search list from registry
  598. //
  599. ptempList->NameCount = 0;
  600. status = Reg_GetValue(
  601. pRegSession,
  602. hKey,
  603. RegIdSearchList,
  604. REGTYPE_SEARCH_LIST,
  605. (PBYTE*) &pregList
  606. );
  607. if ( status == ERROR_SUCCESS )
  608. {
  609. ASSERT( pregList != NULL );
  610. SearchList_Parse(
  611. ptempList,
  612. pregList );
  613. FREE_HEAP( pregList );
  614. }
  615. //
  616. // if no registry search list -- build one
  617. //
  618. // DCR: eliminate autobuilt search list
  619. //
  620. if ( ! ptempList->NameCount )
  621. {
  622. PSTR pname;
  623. DWORD countNames = 0;
  624. DWORD iter;
  625. //
  626. // use PDN in first search list slot
  627. //
  628. if ( pszPrimaryDomainName )
  629. {
  630. SearchList_AddName(
  631. ptempList,
  632. pszPrimaryDomainName,
  633. 0 );
  634. }
  635. //
  636. // add devolved PDN if have NameDevolution
  637. //
  638. if ( ptempList->pszDomainOrZoneName &&
  639. fUseDomainNameDevolution )
  640. {
  641. PSTR ptoken = ptempList->pszDomainOrZoneName;
  642. ptoken = strchr( ptoken, '.' );
  643. while ( ptoken )
  644. {
  645. ptoken += 1;
  646. if ( strchr( ptoken, '.' ) )
  647. {
  648. SearchList_AddName(
  649. ptempList,
  650. ptoken,
  651. DNS_QUERY_USE_QUICK_TIMEOUTS );
  652. ptoken = strchr( ptoken, '.' );
  653. continue;
  654. }
  655. break;
  656. }
  657. }
  658. //
  659. // add ".local" to search list if enabled
  660. //
  661. if ( fUseDotLocalDomain )
  662. {
  663. SearchList_AddName(
  664. ptempList,
  665. MULTICAST_DNS_LOCAL_DOMAIN,
  666. DNS_QUERY_MULTICAST_ONLY
  667. );
  668. }
  669. // indicate this is dummy search list
  670. if ( pNetInfo )
  671. {
  672. pNetInfo->InfoFlags |= DNS_FLAG_DUMMY_SEARCH_LIST;
  673. }
  674. }
  675. return ptempList;
  676. }
  677. PSTR
  678. SearchList_GetNextName(
  679. IN OUT PSEARCH_LIST pSearchList,
  680. IN BOOL fReset,
  681. OUT PDWORD pdwSuffixFlags OPTIONAL
  682. )
  683. /*++
  684. Routine Description:
  685. Gets the next name from the search list.
  686. Arguments:
  687. pSearchList -- search list
  688. fReset -- TRUE to reset to beginning of search list
  689. pdwSuffixFlags -- flags associate with using this suffix
  690. Return Value:
  691. Ptr to the next search name. Note, this is a pointer
  692. to a name in the search list NOT an allocation. Search
  693. list structure must stay valid during use.
  694. NULL when out of search names.
  695. --*/
  696. {
  697. DWORD flag = 0;
  698. PSTR pname = NULL;
  699. DWORD index;
  700. DNSDBG( TRACE, ( "SearchList_GetNextName()\n" ));
  701. // no list
  702. if ( !pSearchList )
  703. {
  704. goto Done;
  705. }
  706. //
  707. // reset?
  708. //
  709. if ( fReset )
  710. {
  711. pSearchList->CurrentNameIndex = 0;
  712. }
  713. //
  714. // if valid name -- retrieve it
  715. //
  716. index = pSearchList->CurrentNameIndex;
  717. if ( index < pSearchList->NameCount )
  718. {
  719. pname = pSearchList->SearchNameArray[index].pszName;
  720. flag = pSearchList->SearchNameArray[index].Flags;
  721. pSearchList->CurrentNameIndex = ++index;
  722. }
  723. Done:
  724. if ( pdwSuffixFlags )
  725. {
  726. *pdwSuffixFlags = flag;
  727. }
  728. return pname;
  729. }
  730. //
  731. // Net info routines
  732. //
  733. PDNS_NETINFO
  734. NetInfo_Alloc(
  735. IN DWORD AdapterCount
  736. )
  737. /*++
  738. Routine Description:
  739. Allocate network info.
  740. Arguments:
  741. AdapterCount -- count of net adapters info will hold
  742. Return Value:
  743. Ptr to uninitialized DNS network info, if successful
  744. NULL on failure.
  745. --*/
  746. {
  747. PDNS_NETINFO pnetInfo;
  748. DWORD length;
  749. DNSDBG( TRACE, ( "NetInfo_Alloc()\n" ));
  750. //
  751. // alloc
  752. // - zero to avoid garbage on early free
  753. //
  754. length = sizeof(DNS_NETINFO)
  755. - sizeof(PDNS_ADAPTER)
  756. + (sizeof(PDNS_ADAPTER) * AdapterCount);
  757. pnetInfo = (PDNS_NETINFO) ALLOCATE_HEAP_ZERO( length );
  758. if ( ! pnetInfo )
  759. {
  760. return NULL;
  761. }
  762. pnetInfo->MaxAdapterCount = AdapterCount;
  763. return( pnetInfo );
  764. }
  765. VOID
  766. NetInfo_Free(
  767. IN OUT PDNS_NETINFO pNetInfo
  768. )
  769. /*++
  770. Routine Description:
  771. Free DNS_NETINFO structure.
  772. Arguments:
  773. pNetInfo -- ptr to netinfo to free
  774. Return Value:
  775. None
  776. --*/
  777. {
  778. DWORD i;
  779. DNSDBG( TRACE, ( "NetInfo_Free( %p )\n", pNetInfo ));
  780. if ( ! pNetInfo )
  781. {
  782. return;
  783. }
  784. IF_DNSDBG( OFF )
  785. {
  786. DnsDbg_NetworkInfo(
  787. "Network Info before free: ",
  788. pNetInfo );
  789. }
  790. //
  791. // free
  792. // - search list
  793. // - domain name
  794. // - all the adapter info blobs
  795. //
  796. SearchList_Free( pNetInfo->pSearchList );
  797. if ( pNetInfo->pszDomainName )
  798. {
  799. FREE_HEAP( pNetInfo->pszDomainName );
  800. }
  801. if ( pNetInfo->pszHostName )
  802. {
  803. FREE_HEAP( pNetInfo->pszHostName );
  804. }
  805. for ( i=0; i < pNetInfo->AdapterCount; i++ )
  806. {
  807. AdapterInfo_Free( pNetInfo->AdapterArray[i] );
  808. }
  809. FREE_HEAP( pNetInfo );
  810. }
  811. PDNS_NETINFO
  812. NetInfo_Copy(
  813. IN PDNS_NETINFO pNetInfo
  814. )
  815. /*++
  816. Routine Description:
  817. Create copy of DNS Network info.
  818. Arguments:
  819. pNetInfo -- DNS Network info to copy
  820. Return Value:
  821. Ptr to DNS Network info copy, if successful
  822. NULL on failure.
  823. --*/
  824. {
  825. PDNS_NETINFO pcopy;
  826. DWORD adapterCount;
  827. DWORD i;
  828. DNSDBG( TRACE, ( "NetInfo_Copy( %p )\n", pNetInfo ));
  829. if ( ! pNetInfo )
  830. {
  831. return NULL;
  832. }
  833. IF_DNSDBG( NETINFO2 )
  834. {
  835. DnsDbg_NetworkInfo(
  836. "Netinfo to copy: ",
  837. pNetInfo );
  838. }
  839. //
  840. // create network info struct of desired size
  841. //
  842. pcopy = NetInfo_Alloc( pNetInfo->AdapterCount );
  843. if ( ! pcopy )
  844. {
  845. return NULL;
  846. }
  847. //
  848. // copy flat fields
  849. // - must reset MaxAdapterCount to actual allocation
  850. // - AdapterCount reset below
  851. RtlCopyMemory(
  852. pcopy,
  853. pNetInfo,
  854. (PBYTE) &pcopy->AdapterArray[0] - (PBYTE)pcopy );
  855. pcopy->MaxAdapterCount = pNetInfo->AdapterCount;
  856. //
  857. // copy subcomponents
  858. // - domain name
  859. // - search list
  860. // - adapter info for each adapter
  861. //
  862. pcopy->pszDomainName = Dns_CreateStringCopy(
  863. pNetInfo->pszDomainName,
  864. 0 );
  865. pcopy->pszHostName = Dns_CreateStringCopy(
  866. pNetInfo->pszHostName,
  867. 0 );
  868. pcopy->pSearchList = SearchList_Copy( pNetInfo->pSearchList );
  869. adapterCount = 0;
  870. for ( i=0; i < pNetInfo->AdapterCount; i++ )
  871. {
  872. PDNS_ADAPTER pnew = AdapterInfo_Copy( pNetInfo->AdapterArray[i] );
  873. if ( pnew )
  874. {
  875. pcopy->AdapterArray[ adapterCount++ ] = pnew;
  876. }
  877. }
  878. pcopy->AdapterCount = adapterCount;
  879. IF_DNSDBG( NETINFO2 )
  880. {
  881. DnsDbg_NetworkInfo(
  882. "Netinfo copy: ",
  883. pcopy );
  884. }
  885. return pcopy;
  886. }
  887. BOOL
  888. NetInfo_AddAdapter(
  889. IN OUT PDNS_NETINFO pNetInfo,
  890. IN PDNS_ADAPTER pAdapter
  891. )
  892. /*++
  893. Routine Description:
  894. Add adapter info to network info.
  895. Arguments:
  896. pNetInfo -- netinfo to add to
  897. pAdapter -- actual adapter to add (it is plugged in NOT copied)
  898. Return Value:
  899. TRUE if successful.
  900. FALSE if list full.
  901. --*/
  902. {
  903. DWORD i;
  904. DNSDBG( TRACE, ( "NetInfo_AddAdapter( %p )\n", pNetInfo ));
  905. //
  906. // find first open slot
  907. //
  908. for ( i = 0; i < pNetInfo->MaxAdapterCount; i++ )
  909. {
  910. if ( ! pNetInfo->AdapterArray[i] )
  911. {
  912. pNetInfo->AdapterArray[i] = pAdapter;
  913. pNetInfo->AdapterCount++;
  914. return( TRUE );
  915. }
  916. }
  917. IF_DNSDBG( NETINFO )
  918. {
  919. DnsDbg_NetworkInfo(
  920. "Network info failed adapter add: ",
  921. pNetInfo );
  922. }
  923. return( FALSE );
  924. }
  925. VOID
  926. NetInfo_Clean(
  927. IN OUT PDNS_NETINFO pNetInfo,
  928. IN DWORD ClearLevel
  929. )
  930. /*++
  931. Routine Description:
  932. Clean network info.
  933. Removes all query specific info and restores to
  934. state that is "fresh" for next query.
  935. Arguments:
  936. pNetInfo -- DNS network info
  937. ClearLevel -- level of runtime flag cleaning
  938. Return Value:
  939. None
  940. --*/
  941. {
  942. DWORD i;
  943. DNSDBG( TRACE, (
  944. "Enter NetInfo_Clean( %p, %08x )\n",
  945. pNetInfo,
  946. ClearLevel ));
  947. IF_DNSDBG( NETINFO2 )
  948. {
  949. DnsDbg_NetworkInfo(
  950. "Cleaning network info:",
  951. pNetInfo
  952. );
  953. }
  954. //
  955. // clean up info
  956. // - clear status fields
  957. // - clear RunFlags
  958. // - clear temp bits on InfoFlags
  959. //
  960. // note, runtime flags are wiped depending on level
  961. // specified in call
  962. // - all (includes disabled\timedout adapter info)
  963. // - query (all query info)
  964. // - name (all info for single name query)
  965. //
  966. // finally we set NETINFO_PREPARED flag so that we can
  967. // can check for and do this initialization in the send
  968. // code if not previously done;
  969. //
  970. // in the standard query path we can
  971. // - do this init
  972. // - disallow adapters based on query name
  973. // - send without the info getting wiped
  974. //
  975. // in other send paths
  976. // - send checks that NETINFO_PREPARED is not set
  977. // - does basic init
  978. //
  979. pNetInfo->ReturnFlags &= ClearLevel;
  980. pNetInfo->ReturnFlags |= RUN_FLAG_NETINFO_PREPARED;
  981. for( i=0; i<pNetInfo->AdapterCount; i++ )
  982. {
  983. PDNS_ADAPTER padapter;
  984. DWORD j;
  985. padapter = pNetInfo->AdapterArray[i];
  986. padapter->Status = 0;
  987. padapter->RunFlags &= ClearLevel;
  988. padapter->ServerIndex = EMPTY_SERVER_INDEX;
  989. // clear server status fields
  990. for ( j=0; j<padapter->ServerCount; j++ )
  991. {
  992. padapter->ServerArray[j].Status = DNSSS_NEW;
  993. }
  994. }
  995. }
  996. VOID
  997. NetInfo_ResetServerPriorities(
  998. IN OUT PDNS_NETINFO pNetInfo,
  999. IN BOOL fLocalDnsOnly
  1000. )
  1001. /*++
  1002. Routine Description:
  1003. Resets the DNS server priority values for the DNS servers.
  1004. Arguments:
  1005. pNetInfo -- pointer to a DNS network info structure.
  1006. fLocalDnsOnly - TRUE to reset priority ONLY on local DNS servers
  1007. Note that this requires that the network info contain the IP address
  1008. list for each adapter so that the IP address list can be compared
  1009. to the DNS server list.
  1010. Return Value:
  1011. Nothing
  1012. --*/
  1013. {
  1014. DWORD i;
  1015. DWORD j;
  1016. DNSDBG( TRACE, ( "NetInfo_ResetServerPriorities( %p )\n", pNetInfo ));
  1017. if ( ! pNetInfo )
  1018. {
  1019. return;
  1020. }
  1021. //
  1022. // reset priorities on server
  1023. // when
  1024. // - not do local only OR
  1025. // - server IP matches one of adapter IPs
  1026. //
  1027. // DCR: local DNS check needs IP6 fixups
  1028. //
  1029. for ( i = 0; i < pNetInfo->AdapterCount; i++ )
  1030. {
  1031. PDNS_ADAPTER padapter = pNetInfo->AdapterArray[i];
  1032. for ( j=0; j < padapter->ServerCount; j++ )
  1033. {
  1034. PDNS_SERVER_INFO pserver = &padapter->ServerArray[j];
  1035. if ( !fLocalDnsOnly ||
  1036. Dns_IsAddressInIpArray(
  1037. padapter->pAdapterIPAddresses,
  1038. pserver->IpAddress ) ||
  1039. pserver->IpAddress == DNS_NET_ORDER_LOOPBACK )
  1040. {
  1041. pserver->Priority = 0;
  1042. }
  1043. }
  1044. }
  1045. }
  1046. PIP_ARRAY
  1047. NetInfo_ConvertToIpArray(
  1048. IN PDNS_NETINFO pNetInfo
  1049. )
  1050. /*++
  1051. Routine Description:
  1052. Create IP array of DNS servers from network info.
  1053. Arguments:
  1054. pNetInfo -- DNS net adapter list to convert
  1055. Return Value:
  1056. Ptr to IP array, if successful
  1057. NULL on failure.
  1058. --*/
  1059. {
  1060. PIP_ARRAY parray;
  1061. DWORD i;
  1062. DWORD j;
  1063. DWORD countServers = 0;
  1064. DNSDBG( TRACE, ( "NetInfo_ConvertToIpArray( %p )\n", pNetInfo ));
  1065. if ( ! pNetInfo )
  1066. {
  1067. return NULL;
  1068. }
  1069. //
  1070. // count up all the servers in list, create IP array of desired size
  1071. //
  1072. for ( i = 0;
  1073. i < pNetInfo->AdapterCount;
  1074. i++ )
  1075. {
  1076. countServers += pNetInfo->AdapterArray[i]->ServerCount;
  1077. }
  1078. parray = Dns_CreateIpArray( countServers );
  1079. if ( !parray )
  1080. {
  1081. SetLastError( DNS_ERROR_NO_MEMORY );
  1082. return( NULL );
  1083. }
  1084. DNS_ASSERT( parray->AddrCount == countServers );
  1085. //
  1086. // read all servers into IP array
  1087. //
  1088. countServers = 0;
  1089. for ( i = 0;
  1090. i < pNetInfo->AdapterCount;
  1091. i++ )
  1092. {
  1093. PDNS_ADAPTER padapter = pNetInfo->AdapterArray[i];
  1094. for ( j = 0;
  1095. j < padapter->ServerCount;
  1096. j++ )
  1097. {
  1098. parray->AddrArray[ countServers++ ]
  1099. = padapter->ServerArray[j].IpAddress;
  1100. }
  1101. }
  1102. DNS_ASSERT( parray->AddrCount == countServers );
  1103. return( parray );
  1104. }
  1105. PDNS_NETINFO
  1106. NetInfo_CreateForUpdate(
  1107. IN PSTR pszZone,
  1108. IN PSTR pszServerName,
  1109. IN PIP_ARRAY pServerArray,
  1110. IN DWORD dwFlags
  1111. )
  1112. /*++
  1113. Routine Description:
  1114. Create network info suitable for update.
  1115. Arguments:
  1116. pszZone -- target zone name
  1117. pszServerName -- target server name
  1118. pServerArray -- IP array with target server IP
  1119. dwFlags -- flags
  1120. Return Value:
  1121. Ptr to resulting update compatible network info.
  1122. NULL on failure.
  1123. --*/
  1124. {
  1125. PSEARCH_LIST psearchList;
  1126. PDNS_ADAPTER padapter;
  1127. PDNS_NETINFO pnetworkInfo;
  1128. DNSDBG( TRACE, ( "NetInfo_BuildForUpdate()\n" ));
  1129. //
  1130. // allocate
  1131. //
  1132. pnetworkInfo = NetInfo_Alloc( 1 );
  1133. if ( !pnetworkInfo )
  1134. {
  1135. return NULL;
  1136. }
  1137. //
  1138. // make search list from desired zone
  1139. //
  1140. if ( pszZone )
  1141. {
  1142. psearchList = SearchList_Alloc( 0, pszZone );
  1143. if ( ! psearchList )
  1144. {
  1145. goto Fail;
  1146. }
  1147. pnetworkInfo->pSearchList = psearchList;
  1148. }
  1149. //
  1150. // convert IP array and server name to server list
  1151. //
  1152. padapter = AdapterInfo_CreateFromIpArray(
  1153. pServerArray,
  1154. dwFlags,
  1155. pszServerName,
  1156. NULL );
  1157. if ( ! padapter )
  1158. {
  1159. goto Fail;
  1160. }
  1161. pnetworkInfo->AdapterArray[0] = padapter;
  1162. pnetworkInfo->AdapterCount = 1;
  1163. IF_DNSDBG( NETINFO2 )
  1164. {
  1165. DnsDbg_NetworkInfo(
  1166. "Update network info is: ",
  1167. pnetworkInfo );
  1168. }
  1169. return pnetworkInfo;
  1170. Fail:
  1171. NetInfo_Free( pnetworkInfo );
  1172. return NULL;
  1173. }
  1174. PSTR
  1175. NetInfo_UpdateZoneName(
  1176. IN PDNS_NETINFO pNetInfo
  1177. )
  1178. /*++
  1179. Routine Description:
  1180. Retrieve update zone name.
  1181. Arguments:
  1182. pNetInfo -- blob to check
  1183. Return Value:
  1184. Ptr to update zone name.
  1185. NULL on error.
  1186. --*/
  1187. {
  1188. return pNetInfo->pSearchList->pszDomainOrZoneName;
  1189. // return pNetInfo->AdapterArray[0]-pszAdapterGuidName;
  1190. // return pNetInfo->pszDomainName;
  1191. }
  1192. PSTR
  1193. NetInfo_UpdateServerName(
  1194. IN PDNS_NETINFO pNetInfo
  1195. )
  1196. /*++
  1197. Routine Description:
  1198. Retrieve update servere name.
  1199. Arguments:
  1200. pNetInfo -- blob to check
  1201. Return Value:
  1202. Ptr to update zone name.
  1203. NULL on error.
  1204. --*/
  1205. {
  1206. return pNetInfo->AdapterArray[0]->pszAdapterDomain;
  1207. }
  1208. BOOL
  1209. NetInfo_IsForUpdate(
  1210. IN PDNS_NETINFO pNetInfo
  1211. )
  1212. /*++
  1213. Routine Description:
  1214. Check if network info blob if "update capable".
  1215. This means whether it is the result of a FAZ and
  1216. can be used to send updates.
  1217. Arguments:
  1218. pNetInfo -- blob to check
  1219. Return Value:
  1220. TRUE if update network info.
  1221. FALSE otherwise.
  1222. --*/
  1223. {
  1224. DNSDBG( TRACE, ( "NetInfo_IsForUpdate()\n" ));
  1225. return ( pNetInfo &&
  1226. pNetInfo->pSearchList &&
  1227. pNetInfo->pSearchList->pszDomainOrZoneName &&
  1228. pNetInfo->AdapterCount == 1 &&
  1229. pNetInfo->AdapterArray[0] );
  1230. }
  1231. PDNS_NETINFO
  1232. NetInfo_CreateFromIpArray(
  1233. IN PIP4_ARRAY pDnsServers,
  1234. IN IP4_ADDRESS ServerIp,
  1235. IN BOOL fSearchInfo,
  1236. IN PDNS_NETINFO pNetInfo OPTIONAL
  1237. )
  1238. /*++
  1239. Routine Description:
  1240. Create network info given DNS server list.
  1241. Arguments:
  1242. pDnsServers -- IP array of DNS servers
  1243. ServerIp -- single IP in list
  1244. fSearchInfo -- TRUE if need search info
  1245. pNetInfo -- current network info blob to copy search info
  1246. from; this field is only relevant if fSearchInfo is TRUE
  1247. Return Value:
  1248. Ptr to resulting network info.
  1249. NULL on failure.
  1250. --*/
  1251. {
  1252. PDNS_NETINFO pnetInfo;
  1253. IP4_ARRAY ipArray;
  1254. PIP4_ARRAY parray = pDnsServers;
  1255. PSEARCH_LIST psearchList;
  1256. PSTR pdomainName;
  1257. DWORD flags = 0;
  1258. //
  1259. // DCR: eliminate search list form this routine
  1260. // i believe this routine is only used for query of
  1261. // FQDNs (usually in update) and doesn't require
  1262. // any default search info
  1263. //
  1264. // DCR: possibly combine with "BuildForUpdate" routine
  1265. // where search info included tacks this on
  1266. //
  1267. //
  1268. // if given single IP, ONLY use it
  1269. //
  1270. if ( ServerIp )
  1271. {
  1272. ipArray.AddrCount = 1;
  1273. ipArray.AddrArray[0] = ServerIp;
  1274. parray = &ipArray;
  1275. }
  1276. //
  1277. // convert server IPs into network info blob
  1278. // - simply use update function above to avoid duplicate code
  1279. //
  1280. pnetInfo = NetInfo_CreateForUpdate(
  1281. NULL, // no zone
  1282. NULL, // no server name
  1283. parray,
  1284. 0 // no flags
  1285. );
  1286. if ( !pnetInfo )
  1287. {
  1288. return( NULL );
  1289. }
  1290. //
  1291. // get search list and primary domain info
  1292. // - copy from passed in network info
  1293. // OR
  1294. // - cut directly out of new netinfo
  1295. //
  1296. if ( fSearchInfo )
  1297. {
  1298. if ( pNetInfo )
  1299. {
  1300. flags = pNetInfo->InfoFlags;
  1301. psearchList = SearchList_Copy( pNetInfo->pSearchList );
  1302. pdomainName = Dns_CreateStringCopy(
  1303. pNetInfo->pszDomainName,
  1304. 0 );
  1305. }
  1306. else
  1307. {
  1308. PDNS_NETINFO ptempNetInfo = GetNetworkInfo();
  1309. if ( ptempNetInfo )
  1310. {
  1311. flags = ptempNetInfo->InfoFlags;
  1312. psearchList = ptempNetInfo->pSearchList;
  1313. pdomainName = ptempNetInfo->pszDomainName;
  1314. ptempNetInfo->pSearchList = NULL;
  1315. ptempNetInfo->pszDomainName = NULL;
  1316. NetInfo_Free( ptempNetInfo );
  1317. }
  1318. else
  1319. {
  1320. psearchList = NULL;
  1321. pdomainName = NULL;
  1322. }
  1323. }
  1324. // plug search info into new netinfo blob
  1325. pnetInfo->pSearchList = psearchList;
  1326. pnetInfo->pszDomainName = pdomainName;
  1327. pnetInfo->InfoFlags |= (flags & DNS_FLAG_DUMMY_SEARCH_LIST);
  1328. }
  1329. return( pnetInfo );
  1330. }
  1331. //
  1332. // DNS server reachability routines
  1333. //
  1334. // These are used to build netinfo that has unreachable DNS
  1335. // servers screened out of the list.
  1336. //
  1337. BOOL
  1338. IsReachableDnsServer(
  1339. IN PDNS_NETINFO pNetInfo,
  1340. IN PDNS_ADAPTER pAdapter,
  1341. IN IP4_ADDRESS Ip4Addr
  1342. )
  1343. /*++
  1344. Routine Description:
  1345. Determine if DNS server is reachable.
  1346. Arguments:
  1347. pNetInfo -- network info blob
  1348. pAdapter -- struct with list of DNS servers
  1349. Ip4Addr -- DNS server address to test for reachability
  1350. Return Value:
  1351. TRUE if DNS server is reachable.
  1352. FALSE otherwise.
  1353. --*/
  1354. {
  1355. DWORD interfaceIndex;
  1356. DNS_STATUS status;
  1357. DNSDBG( NETINFO, (
  1358. "Enter IsReachableDnsServer( %p, %p, %08x )\n",
  1359. pNetInfo,
  1360. pAdapter,
  1361. Ip4Addr ));
  1362. DNS_ASSERT( pNetInfo && pAdapter );
  1363. //
  1364. // DCR: should do reachablity once on netinfo build
  1365. //
  1366. // DCR: reachability test can be smarter
  1367. // - reachable if same subnet as adapter IP
  1368. // question: multiple IPs?
  1369. // - reachable if same subnet as previous reachable IP
  1370. // question: can tell if same subnet?
  1371. //
  1372. // DCR: reachability on multi-homed connected
  1373. // - if send on another interface, does that interface
  1374. // "seem" to be connected
  1375. // probably see if
  1376. // - same subnet as this inteface
  1377. // question: multiple IPs
  1378. // - or share DNS servers in common
  1379. // question: just let server go, this doesn't work if
  1380. // the name is not the same
  1381. //
  1382. //
  1383. // if only one interface, assume reachability
  1384. //
  1385. if ( pNetInfo->AdapterCount <= 1 )
  1386. {
  1387. DNSDBG( SEND, (
  1388. "One interface, assume reachability!\n" ));
  1389. return( TRUE );
  1390. }
  1391. //
  1392. // check if server IP is reachable on its interface
  1393. //
  1394. status = IpHelp_GetBestInterface(
  1395. Ip4Addr,
  1396. & interfaceIndex );
  1397. if ( status != NO_ERROR )
  1398. {
  1399. DNS_ASSERT( FALSE );
  1400. DNSDBG( ANY, (
  1401. "GetBestInterface() failed! %d\n",
  1402. status ));
  1403. return( TRUE );
  1404. }
  1405. if ( pAdapter->InterfaceIndex != interfaceIndex )
  1406. {
  1407. DNSDBG( NETINFO, (
  1408. "IP %s on interface %d is unreachable!\n"
  1409. "\tsend would be on interface %d\n",
  1410. IP_STRING( Ip4Addr ),
  1411. pAdapter->InterfaceIndex,
  1412. interfaceIndex ));
  1413. return( FALSE );
  1414. }
  1415. return( TRUE );
  1416. }
  1417. BOOL
  1418. IsDnsReachableOnAlternateInterface(
  1419. IN PDNS_NETINFO pNetInfo,
  1420. IN DWORD InterfaceIndex,
  1421. IN IP4_ADDRESS Ip4Addr
  1422. )
  1423. /*++
  1424. Routine Description:
  1425. Determine if IP address is reachable on adapter.
  1426. This function determines whether DNS IP can be reached
  1427. on the interface that the stack indicates, when that
  1428. interface is NOT the one containing the DNS server.
  1429. We need this so we catch the multi-homed CONNECTED cases
  1430. where a DNS server is still reachable even though the
  1431. interface the stack will send on is NOT the interface for
  1432. the DNS server.
  1433. Arguments:
  1434. pNetInfo -- network info blob
  1435. Interface -- interface stack will send to IP on
  1436. Ip4Addr -- DNS server address to test for reachability
  1437. Return Value:
  1438. TRUE if DNS server is reachable.
  1439. FALSE otherwise.
  1440. --*/
  1441. {
  1442. PDNS_ADAPTER padapter;
  1443. DWORD i;
  1444. PIP4_ARRAY pipArray;
  1445. PIP4_ARRAY psubnetArray;
  1446. DWORD ipCount;
  1447. DNSDBG( NETINFO, (
  1448. "Enter IsDnsReachableOnAlternateInterface( %p, %d, %08x )\n",
  1449. pNetInfo,
  1450. InterfaceIndex,
  1451. Ip4Addr ));
  1452. //
  1453. // find DNS adapter for interface
  1454. //
  1455. for( i=0; i<pNetInfo->AdapterCount; i++ )
  1456. {
  1457. padapter = pNetInfo->AdapterArray[i];
  1458. if ( padapter->InterfaceIndex != InterfaceIndex )
  1459. {
  1460. padapter = NULL;
  1461. continue;
  1462. }
  1463. break;
  1464. }
  1465. if ( !padapter )
  1466. {
  1467. DNSDBG( ANY, (
  1468. "WARNING: indicated send inteface %d NOT in netinfo!\n",
  1469. InterfaceIndex ));
  1470. return FALSE;
  1471. }
  1472. //
  1473. // two success conditions:
  1474. // 1) our IP matches IP of DNS server for this interface
  1475. // 2) our IP is on subnet of IP on this interface
  1476. //
  1477. // if either of these is TRUE then either
  1478. // - there is misconfiguration (not our problem)
  1479. // OR
  1480. // - these interfaces are connected and we can safely send on
  1481. // them
  1482. //
  1483. // DCR: it would be cool to save the default gateway for the interface
  1484. // and use it?
  1485. for ( i=0; i<padapter->ServerCount; i++ )
  1486. {
  1487. if ( Ip4Addr == padapter->ServerArray[i].IpAddress )
  1488. {
  1489. DNSDBG( NETINFO, (
  1490. "DNS server %08x also DNS server on send interface %d\n",
  1491. Ip4Addr,
  1492. InterfaceIndex ));
  1493. return( TRUE );
  1494. }
  1495. }
  1496. // test for subnet match
  1497. pipArray = padapter->pAdapterIPAddresses;
  1498. psubnetArray = padapter->pAdapterIPSubnetMasks;
  1499. if ( !pipArray ||
  1500. !psubnetArray ||
  1501. (ipCount = pipArray->AddrCount) != psubnetArray->AddrCount )
  1502. {
  1503. DNSDBG( ANY, ( "WARNING: missing or invalid interface IP\\subnet info!\n" ));
  1504. DNS_ASSERT( FALSE );
  1505. return( FALSE );
  1506. }
  1507. for ( i=0; i<ipCount; i++ )
  1508. {
  1509. IP4_ADDRESS subnet = psubnetArray->AddrArray[i];
  1510. if ( (subnet & Ip4Addr) == (subnet & pipArray->AddrArray[i]) )
  1511. {
  1512. DNSDBG( NETINFO, (
  1513. "DNS server %08x on subnet of IP for send interface %d\n"
  1514. "\tip = %08x, subnet = %08x\n",
  1515. Ip4Addr,
  1516. InterfaceIndex,
  1517. pipArray->AddrArray[i],
  1518. subnet ));
  1519. return( TRUE );
  1520. }
  1521. }
  1522. return( FALSE );
  1523. }
  1524. DNS_STATUS
  1525. StrikeOutUnreachableDnsServers(
  1526. IN OUT PDNS_NETINFO pNetInfo
  1527. )
  1528. /*++
  1529. Routine Description:
  1530. Eliminate unreachable DNS servers from the list.
  1531. Arguments:
  1532. pNetInfo -- DNS netinfo to fix up
  1533. Return Value:
  1534. ERROR_SUCCESS if successful
  1535. --*/
  1536. {
  1537. DNS_STATUS status;
  1538. DWORD validServers;
  1539. PDNS_ADAPTER padapter;
  1540. DWORD adapterIfIndex;
  1541. DWORD serverIfIndex;
  1542. DWORD i;
  1543. DWORD j;
  1544. DNSDBG( NETINFO, (
  1545. "Enter StrikeOutUnreachableDnsServers( %p )\n",
  1546. pNetInfo ));
  1547. DNS_ASSERT( pNetInfo );
  1548. //
  1549. // if only one interface, assume reachability
  1550. //
  1551. if ( pNetInfo->AdapterCount <= 1 )
  1552. {
  1553. DNSDBG( NETINFO, (
  1554. "One interface, assume reachability!\n" ));
  1555. return( TRUE );
  1556. }
  1557. //
  1558. // loop through adapters
  1559. //
  1560. for( i=0; i<pNetInfo->AdapterCount; i++ )
  1561. {
  1562. padapter = pNetInfo->AdapterArray[i];
  1563. // ignore this adapter because there are no DNS
  1564. // servers configured?
  1565. if ( padapter->InfoFlags & DNS_FLAG_IGNORE_ADAPTER )
  1566. {
  1567. continue;
  1568. }
  1569. //
  1570. // test all adapter's DNS servers for reachability
  1571. //
  1572. // note: currently save no server specific reachability,
  1573. // so if any server reachable, proceed;
  1574. // also if iphelp fails just assume reachability and proceed,
  1575. // better timeouts then not reaching server we can reach
  1576. //
  1577. adapterIfIndex = padapter->InterfaceIndex;
  1578. validServers = 0;
  1579. for ( j=0; j<padapter->ServerCount; j++ )
  1580. {
  1581. IP4_ADDRESS dnsIp = padapter->ServerArray[j].IpAddress;
  1582. status = IpHelp_GetBestInterface(
  1583. dnsIp,
  1584. & serverIfIndex );
  1585. if ( status != NO_ERROR )
  1586. {
  1587. DNS_ASSERT( FALSE );
  1588. DNSDBG( ANY, (
  1589. "GetBestInterface() failed! %d\n",
  1590. status ));
  1591. validServers++;
  1592. break;
  1593. //continue;
  1594. }
  1595. // server is reachable
  1596. // - queried on its adapter?
  1597. // - reachable through loopback
  1598. //
  1599. // DCR: tag unreachable servers individually
  1600. if ( serverIfIndex == adapterIfIndex ||
  1601. serverIfIndex == 1 )
  1602. {
  1603. validServers++;
  1604. break;
  1605. //continue;
  1606. }
  1607. // server can be reached on query interface
  1608. if ( IsDnsReachableOnAlternateInterface(
  1609. pNetInfo,
  1610. serverIfIndex,
  1611. dnsIp ) )
  1612. {
  1613. validServers++;
  1614. break;
  1615. //continue;
  1616. }
  1617. }
  1618. //
  1619. // disable adapter if no servers found
  1620. //
  1621. // DCR: alternative to ignoring unreachable
  1622. // - tag as unreachable
  1623. // - don't send to it on first pass
  1624. // - don't continue name error on unreachable
  1625. // (it would count as "heard from" when send.c routine
  1626. // works back through)
  1627. if ( validServers == 0 )
  1628. {
  1629. padapter->InfoFlags |= (DNS_FLAG_IGNORE_ADAPTER |
  1630. DNS_FLAG_SERVERS_UNREACHABLE);
  1631. DNSDBG( NETINFO, (
  1632. "No reachable servers on interface %d\n"
  1633. "\tthis adapter (%p) ignored in DNS list!\n",
  1634. adapterIfIndex,
  1635. padapter ));
  1636. }
  1637. }
  1638. return ERROR_SUCCESS;
  1639. }
  1640. //
  1641. // Main netinfo build routine
  1642. //
  1643. PDNS_NETINFO
  1644. NetInfo_Build(
  1645. IN BOOL fGetIpAddrs
  1646. )
  1647. /*++
  1648. Routine Description:
  1649. Build network info blob from registry.
  1650. This is the FULL recreate function.
  1651. Arguments:
  1652. fGetIpAddrs -- TRUE to include local IP addrs for each adapter
  1653. Return Value:
  1654. ERROR_SUCCESS if successful.
  1655. Error code on failure.
  1656. --*/
  1657. {
  1658. REG_SESSION regSession;
  1659. PREG_SESSION pregSession = NULL;
  1660. PDNS_NETINFO pnetInfo = NULL;
  1661. PDNS_ADAPTER padapter = NULL;
  1662. PIP_ARRAY ptempArray = NULL;
  1663. PIP_ARRAY plocalIpArray = NULL;
  1664. PIP_ARRAY psubnetIpArray = NULL;
  1665. PIP_ARRAY pserverIpArray = NULL;
  1666. DNS_STATUS status = NO_ERROR;
  1667. DWORD count;
  1668. PIP_ADAPTER_INFO pipAdapterInfo = NULL;
  1669. PIP_ADAPTER_INFO pipAdapter = NULL;
  1670. DWORD value;
  1671. PREG_GLOBAL_INFO pregInfo = NULL;
  1672. REG_GLOBAL_INFO regInfo;
  1673. REG_ADAPTER_INFO regAdapterInfo;
  1674. DNSDBG( TRACE, (
  1675. "NetInfo_Build( %d )\n",
  1676. fGetIpAddrs ));
  1677. //
  1678. // always get IP addresses
  1679. // - for multi-adapter need for routing
  1680. // - need for local lookups
  1681. // (might as well just include)
  1682. //
  1683. // DCR: could skip include when RPCing to client for
  1684. // query\update that does not require
  1685. //
  1686. fGetIpAddrs = TRUE;
  1687. //
  1688. // get adapters info from IP help
  1689. //
  1690. status = IpHelp_GetAdaptersInfo( &pipAdapterInfo );
  1691. if ( status != ERROR_SUCCESS )
  1692. {
  1693. goto Cleanup;
  1694. }
  1695. //
  1696. // open the registry
  1697. //
  1698. pregSession = &regSession;
  1699. status = Reg_OpenSession(
  1700. pregSession,
  1701. 0,
  1702. 0 );
  1703. if ( status != ERROR_SUCCESS )
  1704. {
  1705. status = DNS_ERROR_NO_DNS_SERVERS;
  1706. goto Cleanup;
  1707. }
  1708. //
  1709. // read global registry info
  1710. //
  1711. pregInfo = &regInfo;
  1712. status = Reg_ReadGlobalInfo(
  1713. pregSession,
  1714. pregInfo
  1715. );
  1716. if ( status != ERROR_SUCCESS )
  1717. {
  1718. status = DNS_ERROR_NO_DNS_SERVERS;
  1719. goto Cleanup;
  1720. }
  1721. //
  1722. // build adapter information
  1723. //
  1724. // count up the active adapters
  1725. pipAdapter = pipAdapterInfo;
  1726. count = 0;
  1727. while ( pipAdapter )
  1728. {
  1729. count++;
  1730. pipAdapter = pipAdapter->Next;
  1731. }
  1732. //
  1733. // allocate net info blob
  1734. // allocate DNS server IP array
  1735. //
  1736. pnetInfo = NetInfo_Alloc( count );
  1737. ptempArray = Dns_CreateIpArray( DNS_MAX_IP_INTERFACE_COUNT );
  1738. if ( !pnetInfo ||
  1739. !ptempArray )
  1740. {
  1741. status = DNS_ERROR_NO_MEMORY;
  1742. goto Cleanup;
  1743. }
  1744. //
  1745. // set network info flags
  1746. //
  1747. // DCR: can use globals
  1748. //
  1749. if ( regInfo.fUseMulticast )
  1750. {
  1751. pnetInfo->InfoFlags |= DNS_FLAG_ALLOW_MULTICAST;
  1752. }
  1753. if ( regInfo.fUseMulticastOnNameError )
  1754. {
  1755. pnetInfo->InfoFlags |= DNS_FLAG_MULTICAST_ON_NAME_ERROR;
  1756. }
  1757. //
  1758. // loop through adapters -- build network info for each
  1759. //
  1760. pipAdapter = pipAdapterInfo;
  1761. while ( pipAdapter )
  1762. {
  1763. DWORD adapterFlags = 0;
  1764. PIP_PER_ADAPTER_INFO pperAdapterInfo = NULL;
  1765. PSTR padapterDomainName = NULL;
  1766. //
  1767. // read adapter registry info
  1768. //
  1769. status = Reg_ReadAdapterInfo(
  1770. pipAdapter->AdapterName,
  1771. pregSession,
  1772. & regInfo, // policy adapter info
  1773. & regAdapterInfo // receives reg info read
  1774. );
  1775. if ( status != NO_ERROR )
  1776. {
  1777. goto Skip;
  1778. }
  1779. // translate results into flags
  1780. if ( regAdapterInfo.fRegistrationEnabled )
  1781. {
  1782. adapterFlags |= DNS_FLAG_REGISTER_IP_ADDRESSES;
  1783. }
  1784. if ( regAdapterInfo.fRegisterAdapterName )
  1785. {
  1786. adapterFlags |= DNS_FLAG_REGISTER_DOMAIN_NAME;
  1787. }
  1788. // use domain name?
  1789. // - if disable on per adapter basis, then it's dead
  1790. if ( regAdapterInfo.fQueryAdapterName )
  1791. {
  1792. padapterDomainName = regAdapterInfo.pszAdapterDomainName;
  1793. }
  1794. // set flag on DHCP adapters
  1795. if ( pipAdapter->DhcpEnabled )
  1796. {
  1797. adapterFlags |= DNS_FLAG_IS_DHCP_CFG_ADAPTER;
  1798. }
  1799. //
  1800. // get adapter's IP addresses
  1801. //
  1802. // DCR_FIX: why get IPs if aren't going to use
  1803. //
  1804. ptempArray->AddrCount = 0;
  1805. status = IpHelp_ParseIpAddressString(
  1806. ptempArray,
  1807. & pipAdapter->IpAddressList,
  1808. FALSE, // Get the ip address(es)
  1809. TRUE // Reverse the order because
  1810. ); // of broken iphlpapi!
  1811. if ( ( status == NO_ERROR ) &&
  1812. ( fGetIpAddrs || g_IsDnsServer ) )
  1813. {
  1814. plocalIpArray = Dns_CreateIpArrayCopy( ptempArray );
  1815. //
  1816. // Go the subnet mask(s)
  1817. //
  1818. // DCR_QUESTION: why failure case on getting subnets
  1819. // if doesn't work then IP help gave bad info and
  1820. // we should just agree we are dead
  1821. //
  1822. // DCR_FIX: default subnetting is class B!
  1823. //
  1824. ptempArray->AddrCount = 0;
  1825. status = IpHelp_ParseIpAddressString(
  1826. ptempArray,
  1827. &pipAdapter->IpAddressList,
  1828. TRUE, // Get the subnet mask(s)
  1829. TRUE ); // Reverse the order because
  1830. // of broken iphlpapi!
  1831. if ( status == NO_ERROR )
  1832. {
  1833. psubnetIpArray = Dns_CreateIpArrayCopy( ptempArray );
  1834. }
  1835. else
  1836. {
  1837. psubnetIpArray = Dns_CreateIpArrayCopy( plocalIpArray );
  1838. if ( psubnetIpArray )
  1839. {
  1840. DWORD i;
  1841. for ( i=0;
  1842. i < psubnetIpArray->AddrCount;
  1843. i++ )
  1844. {
  1845. psubnetIpArray->AddrArray[i] = 0x0000ffff;
  1846. }
  1847. status = NO_ERROR;
  1848. }
  1849. }
  1850. }
  1851. if ( status != NO_ERROR )
  1852. {
  1853. goto Skip;
  1854. }
  1855. //
  1856. // get per-adapter information from the iphlpapi.dll.
  1857. // -- autonet
  1858. // -- DNS server list
  1859. //
  1860. status = IpHelp_GetPerAdapterInfo(
  1861. pipAdapter->Index,
  1862. & pperAdapterInfo );
  1863. if ( status == NO_ERROR )
  1864. {
  1865. if ( pperAdapterInfo->AutoconfigEnabled &&
  1866. pperAdapterInfo->AutoconfigActive )
  1867. {
  1868. adapterFlags |= DNS_FLAG_IS_AUTONET_ADAPTER;
  1869. }
  1870. }
  1871. //
  1872. // build DNS servers list for adapter
  1873. // - if policy override use it
  1874. // - otherwise use IP help list
  1875. //
  1876. if ( regInfo.pDnsServerArray )
  1877. {
  1878. pserverIpArray = regInfo.pDnsServerArray;
  1879. }
  1880. else if ( status == NO_ERROR )
  1881. {
  1882. // parse DNS servers from IP help
  1883. //
  1884. // DCR: must be able to get IPv6
  1885. pserverIpArray = ptempArray;
  1886. ptempArray->AddrCount = 0;
  1887. status = IpHelp_ParseIpAddressString(
  1888. ptempArray,
  1889. &pperAdapterInfo->DnsServerList,
  1890. FALSE, // get IP addresses
  1891. FALSE // no reverse
  1892. );
  1893. if ( status != ERROR_SUCCESS )
  1894. {
  1895. //
  1896. // if no DNS servers found -- write loopback if on DNS server
  1897. //
  1898. // DCR: should we bother to write -- why not just use in
  1899. // memory?
  1900. //
  1901. if ( g_IsDnsServer &&
  1902. !(adapterFlags & DNS_FLAG_IS_DHCP_CFG_ADAPTER) &&
  1903. plocalIpArray &&
  1904. psubnetIpArray )
  1905. {
  1906. Reg_WriteLoopbackDnsServerList(
  1907. pipAdapter->AdapterName,
  1908. pregSession );
  1909. ptempArray->AddrCount = 1;
  1910. ptempArray->AddrArray[0] = DNS_NET_ORDER_LOOPBACK;
  1911. }
  1912. else // no DNS servers
  1913. {
  1914. pserverIpArray = NULL;
  1915. goto Skip;
  1916. }
  1917. }
  1918. }
  1919. //
  1920. // build adapter info
  1921. //
  1922. // optionally add IP and subnet list; note this is
  1923. // direct add of data (not alloc\copy) so clear pointers
  1924. // after to skip free
  1925. //
  1926. padapter = AdapterInfo_CreateFromIpArray(
  1927. pserverIpArray,
  1928. adapterFlags,
  1929. padapterDomainName,
  1930. pipAdapter->AdapterName );
  1931. if ( padapter )
  1932. {
  1933. padapter->InterfaceIndex = pipAdapter->Index;
  1934. if ( fGetIpAddrs &&
  1935. plocalIpArray &&
  1936. psubnetIpArray )
  1937. {
  1938. padapter->pAdapterIPAddresses = plocalIpArray;
  1939. plocalIpArray = NULL;
  1940. padapter->pAdapterIPSubnetMasks = psubnetIpArray;
  1941. psubnetIpArray = NULL;
  1942. }
  1943. NetInfo_AddAdapter(
  1944. pnetInfo,
  1945. padapter );
  1946. }
  1947. Skip:
  1948. //
  1949. // cleanup adapter specific data
  1950. //
  1951. // note: no free of pserverIpArray, it IS the
  1952. // ptempArray buffer that we free at the end
  1953. //
  1954. Reg_FreeAdapterInfo(
  1955. &regAdapterInfo,
  1956. FALSE // don't free blob, it is on stack
  1957. );
  1958. if ( pperAdapterInfo )
  1959. {
  1960. FREE_HEAP( pperAdapterInfo );
  1961. pperAdapterInfo = NULL;
  1962. }
  1963. if ( plocalIpArray )
  1964. {
  1965. FREE_HEAP( plocalIpArray );
  1966. plocalIpArray = NULL;
  1967. }
  1968. if ( psubnetIpArray )
  1969. {
  1970. FREE_HEAP( psubnetIpArray );
  1971. psubnetIpArray = NULL;
  1972. }
  1973. // get next adapter
  1974. // reset status, so failure on the last adapter is not
  1975. // seen as global failure
  1976. pipAdapter = pipAdapter->Next;
  1977. status = ERROR_SUCCESS;
  1978. }
  1979. //
  1980. // eliminate unreachable DNS servers
  1981. //
  1982. if ( g_ScreenUnreachableServers )
  1983. {
  1984. StrikeOutUnreachableDnsServers( pnetInfo );
  1985. }
  1986. //
  1987. // build search list for network info
  1988. // - skip if no active adapters found
  1989. //
  1990. // DCR: shouldn't build search list?
  1991. //
  1992. // DCR: only build if actually read search list
  1993. //
  1994. if ( pnetInfo->AdapterCount )
  1995. {
  1996. pnetInfo->pSearchList = SearchList_Build(
  1997. regInfo.pszPrimaryDomainName,
  1998. pregSession,
  1999. NULL, // no explicit key
  2000. pnetInfo,
  2001. regInfo.fUseNameDevolution,
  2002. regInfo.fUseDotLocalDomain
  2003. );
  2004. }
  2005. //
  2006. // host and domain name info
  2007. //
  2008. pnetInfo->pszDomainName = Dns_CreateStringCopy(
  2009. regInfo.pszPrimaryDomainName,
  2010. 0 );
  2011. pnetInfo->pszHostName = Dns_CreateStringCopy(
  2012. regInfo.pszHostName,
  2013. 0 );
  2014. // timestamp
  2015. pnetInfo->TimeStamp = Dns_GetCurrentTimeInSeconds();
  2016. Cleanup:
  2017. // free allocated reg info
  2018. Reg_FreeGlobalInfo(
  2019. pregInfo,
  2020. FALSE // don't free blob, it is on stack
  2021. );
  2022. if ( pipAdapterInfo )
  2023. {
  2024. FREE_HEAP( pipAdapterInfo );
  2025. }
  2026. if ( ptempArray )
  2027. {
  2028. FREE_HEAP( ptempArray );
  2029. }
  2030. if ( pnetInfo &&
  2031. pnetInfo->AdapterCount == 0 )
  2032. {
  2033. status = DNS_ERROR_NO_DNS_SERVERS;
  2034. }
  2035. // close registry session
  2036. Reg_CloseSession( pregSession );
  2037. if ( status != ERROR_SUCCESS )
  2038. {
  2039. NetInfo_Free( pnetInfo );
  2040. DNSDBG( TRACE, (
  2041. "Leave: NetInfo_Build()\n"
  2042. "\tstatus = %d\n",
  2043. status ));
  2044. SetLastError( status );
  2045. return( NULL );
  2046. }
  2047. DNSDBG( TRACE, (
  2048. "Leave: NetInfo_Build()\n"
  2049. "\treturning fresh built network info (%p)\n",
  2050. pnetInfo ));
  2051. return( pnetInfo );
  2052. }
  2053. //
  2054. // Network info caching\state routines
  2055. //
  2056. VOID
  2057. InitNetworkInfo(
  2058. VOID
  2059. )
  2060. /*++
  2061. Routine Description:
  2062. Initialize network info.
  2063. Arguments:
  2064. None
  2065. Return Value:
  2066. None
  2067. --*/
  2068. {
  2069. //
  2070. // currently using general CS as netinfo cache lock
  2071. // so no real init here
  2072. //
  2073. // InitializeCriticalSection( &csNetworkInfo );
  2074. g_pNetInfo = NULL;
  2075. }
  2076. VOID
  2077. CleanupNetworkInfo(
  2078. VOID
  2079. )
  2080. /*++
  2081. Routine Description:
  2082. Initialize network info.
  2083. Arguments:
  2084. None
  2085. Return Value:
  2086. None
  2087. --*/
  2088. {
  2089. DNS_NETINFO pold;
  2090. LOCK_NETINFO();
  2091. NetInfo_Free( g_pNetInfo );
  2092. g_pNetInfo = NULL;
  2093. UNLOCK_NETINFO();
  2094. }
  2095. //
  2096. // Read config from resolver
  2097. //
  2098. PDNS_NETINFO
  2099. UpdateDnsConfig(
  2100. VOID
  2101. )
  2102. /*++
  2103. Routine Description:
  2104. Update DNS configuration.
  2105. This includes entire config
  2106. - flat registry DWORD\BOOL globals
  2107. - netinfo list
  2108. Arguments:
  2109. None
  2110. Return Value:
  2111. Ptr to network info blob.
  2112. --*/
  2113. {
  2114. DNS_STATUS status = ERROR_SUCCESS;
  2115. PDNS_NETINFO pnetworkInfo = NULL;
  2116. PDNS_GLOBALS_BLOB pglobalsBlob = NULL;
  2117. DNSDBG( TRACE, ( "UpdateDnsConfig()\n" ));
  2118. #if DNSBUILDOLD
  2119. if ( !g_IsWin2000 )
  2120. {
  2121. return NULL;
  2122. }
  2123. #endif
  2124. // DCR_CLEANUP: RPC TryExcept should be in RPC client library
  2125. RpcTryExcept
  2126. {
  2127. R_ResolverGetConfig(
  2128. NULL, // default handle
  2129. g_ConfigCookie,
  2130. & pnetworkInfo,
  2131. & pglobalsBlob
  2132. );
  2133. }
  2134. RpcExcept( DNS_RPC_EXCEPTION_FILTER )
  2135. {
  2136. status = RpcExceptionCode();
  2137. }
  2138. RpcEndExcept
  2139. if ( status != ERROR_SUCCESS )
  2140. {
  2141. DNSDBG( RPC, (
  2142. "R_ResolverGetConfig() RPC failed status = %d\n",
  2143. status ));
  2144. return NULL;
  2145. }
  2146. //
  2147. // DCR: save other config info here
  2148. // - flat memcpy of DWORD globals
  2149. // - save off cookie (perhaps include as one of them
  2150. // - save global copy of pnetworkInfo?
  2151. // (the idea being that we just copy it if
  2152. // RPC cookie is valid)
  2153. //
  2154. // - maybe return flags?
  2155. // memcpy is cheap but if more expensive config
  2156. // then could alert what needs update?
  2157. //
  2158. //
  2159. // DCR: once move, single "update global network info"
  2160. // then call it here to save global copy
  2161. // but global copy doesn't do much until RPC fails
  2162. // unless using cookie
  2163. //
  2164. // QUESTION: not sure about forcing global build here
  2165. // q: is this to be "read config" all
  2166. // or just "update config" and then individual
  2167. // routines for various pieces of config can
  2168. // determine what to do?
  2169. //
  2170. // note, doing eveything is fine if going to always
  2171. // read entire registry on cache failure; if so
  2172. // reasonable to push here
  2173. //
  2174. // if cache-on required for "real time" config, then
  2175. // should protect registry DWORD read with reasonable time
  2176. // (say read every five\ten\fifteen minutes?)
  2177. //
  2178. // perhaps NO read here, but have DWORD reg read update
  2179. // routine that called before registry reread when
  2180. // building adapter list in registry; then skip this
  2181. // step in cache
  2182. //
  2183. //
  2184. // copy in config
  2185. //
  2186. if ( pglobalsBlob )
  2187. {
  2188. RtlCopyMemory(
  2189. & DnsGlobals,
  2190. pglobalsBlob,
  2191. sizeof(DnsGlobals) );
  2192. MIDL_user_free( pglobalsBlob );
  2193. }
  2194. IF_DNSDBG( RPC )
  2195. {
  2196. DnsDbg_NetworkInfo(
  2197. "Network Info returned from cache:",
  2198. pnetworkInfo );
  2199. }
  2200. return pnetworkInfo;
  2201. }
  2202. //
  2203. // Public netinfo routine
  2204. //
  2205. PDNS_NETINFO
  2206. NetInfo_Get(
  2207. IN BOOL fForce,
  2208. IN BOOL fGetIpAddresses
  2209. )
  2210. /*++
  2211. Routine Description:
  2212. Read DNS network info from registry.
  2213. This is in process, limited caching version.
  2214. Note, this is macro'd as GetNetworkInfo() with parameters
  2215. NetInfo_Get( FALSE, TRUE ) throughout dnsapi code.
  2216. Arguments:
  2217. fForce -- force reread from registry
  2218. fGetIpAddresses -- keep the local IP addresses for each adapter
  2219. and store within the structure.
  2220. Return Value:
  2221. ERROR_SUCCESS if successful.
  2222. Error code on failure.
  2223. --*/
  2224. {
  2225. PDNS_NETINFO pnetInfo;
  2226. PDNS_NETINFO poldNetInfo = NULL;
  2227. BOOL flocked = FALSE;
  2228. BOOL fcacheable = TRUE;
  2229. DNSDBG( NETINFO, ( "NetInfo_Get()\n" ));
  2230. //
  2231. // hold lock while accessing cached network info
  2232. //
  2233. // try
  2234. // - very recent local cached copy
  2235. // - RPC copy from resolver
  2236. // - build new
  2237. //
  2238. if ( ! fForce &&
  2239. ! g_DnsTestMode )
  2240. {
  2241. LOCK_NETINFO();
  2242. flocked = TRUE;
  2243. // check if valid copy cached in process
  2244. if ( g_pNetInfo &&
  2245. (g_pNetInfo->TimeStamp + NETINFO_CACHE_TIMEOUT)
  2246. > Dns_GetCurrentTimeInSeconds() )
  2247. {
  2248. pnetInfo = NetInfo_Copy( g_pNetInfo );
  2249. if ( pnetInfo )
  2250. {
  2251. DNSDBG( TRACE, (
  2252. "Netinfo found in process cache.\n" ));
  2253. goto Unlock;
  2254. }
  2255. }
  2256. // check RPC to resolver
  2257. //
  2258. // DCR: this could present "cookie" of existing netinfo
  2259. // and only get new if "cookie" is old, though the
  2260. // cost of that versus local copy seems small since
  2261. // still must do RPC and allocations -- only the copy
  2262. // for RPC on the resolver side is saved
  2263. pnetInfo = UpdateDnsConfig();
  2264. if ( pnetInfo )
  2265. {
  2266. DNSDBG( TRACE, (
  2267. "Netinfo read from resolver.\n" ));
  2268. goto CacheCopy;
  2269. }
  2270. }
  2271. //
  2272. // build fresh network info
  2273. // - if successful clear "dirty" flag
  2274. //
  2275. // Note: we call down unlocked. Ideally we'd have only one thread
  2276. // in the process building at a given time, and let other threads
  2277. // wait for completion. However during call down, iphlpapi RPCs
  2278. // to MPR (router service) which can result in deadlock through
  2279. // a PPP call back to our DnsSetDwordConfig() => NetInfo_MarkDirty.
  2280. //
  2281. // Here's the deadlock scenario:
  2282. // 1. RtrMgr calls GetHostByName() which ends up in a
  2283. // iphlpapi!GetBestInterface call which in turn calls
  2284. // Mprapi!IsRouterRunning (which is an RPC to mprdim).
  2285. // 2. Mprdim is blocked on a CS which is held by a thread waiting
  2286. // for a demand-dial disconnect to complete - this is completely
  2287. // independent of 1.
  2288. // 3. Demand-dial disconnect is waiting for ppp to finish graceful
  2289. // termination.
  2290. // 4. PPP is waiting for dnsto return from DnsSetConfigDword, hence
  2291. // the deadlock.
  2292. //
  2293. // This gave us a deadlock because NetInfo_MarkDirty() also waits
  2294. // on this lock. MarkDirty could skip the lock -- one method would be
  2295. // to have this function clear the dirty flag, then call down again
  2296. // IF it got done and the flag was again dirty. But that method could
  2297. // result if something is bogus down below. And even if MarkDirty is
  2298. // fixed cleanly we still have the possibility that some service that
  2299. // IpHlpApi RPCs to, will issue name resolution and come back to the
  2300. // lock on a different thread. (Because our many services in process
  2301. // model is busted.)
  2302. //
  2303. // So best solution is not to do anything this big while holding a lock.
  2304. // (We could do hacking stuff here like have an event and wait for a
  2305. // second or so before figuring we were part of a deadlock and proceeding.)
  2306. //
  2307. // Finally note that the perf hit is negligible because usually the netinfo
  2308. // is grabbed from the resolver.
  2309. //
  2310. if ( flocked )
  2311. {
  2312. UNLOCK_NETINFO();
  2313. flocked = FALSE;
  2314. }
  2315. pnetInfo = NetInfo_Build( fGetIpAddresses );
  2316. if ( !pnetInfo )
  2317. {
  2318. goto Unlock;
  2319. }
  2320. fcacheable = fGetIpAddresses;
  2321. CacheCopy:
  2322. //
  2323. // update cached copy
  2324. // - but not if built without local IPs;
  2325. // resolver copy always contains local IPs
  2326. //
  2327. if ( fcacheable )
  2328. {
  2329. if ( !flocked )
  2330. {
  2331. LOCK_NETINFO();
  2332. flocked = TRUE;
  2333. }
  2334. poldNetInfo = g_pNetInfo;
  2335. g_pNetInfo = NetInfo_Copy( pnetInfo );
  2336. }
  2337. Unlock:
  2338. if ( flocked )
  2339. {
  2340. UNLOCK_NETINFO();
  2341. }
  2342. NetInfo_Free( poldNetInfo );
  2343. DNSDBG( TRACE, (
  2344. "Leave: NetInfo_Get( %p )\n",
  2345. pnetInfo ));
  2346. return( pnetInfo );
  2347. }
  2348. VOID
  2349. NetInfo_MarkDirty(
  2350. VOID
  2351. )
  2352. /*++
  2353. Routine Description:
  2354. Mark netinfo dirty so force reread.
  2355. Arguments:
  2356. None
  2357. Return Value:
  2358. None
  2359. --*/
  2360. {
  2361. PDNS_NETINFO pold;
  2362. DNSDBG( NETINFO, ( "NetInfo_MarkDirty()\n" ));
  2363. //
  2364. // dump global network info to force reread
  2365. //
  2366. // since the resolve is always notified by DnsSetDwordConfig()
  2367. // BEFORE entering this function, the resolve should always be
  2368. // providing before we are in this function; all we need to do
  2369. // is insure that cached copy is dumped
  2370. //
  2371. LOCK_NETINFO();
  2372. pold = g_pNetInfo;
  2373. g_pNetInfo = NULL;
  2374. UNLOCK_NETINFO();
  2375. NetInfo_Free( pold );
  2376. }
  2377. //
  2378. // DNS server list
  2379. //
  2380. PIP4_ARRAY
  2381. GetDnsServerList(
  2382. IN BOOL fForce
  2383. )
  2384. /*++
  2385. Routine Description:
  2386. Get DNS server list as IP array.
  2387. Arguments:
  2388. fForce -- force reread from registry
  2389. Return Value:
  2390. ERROR_SUCCESS if successful.
  2391. Error code on failure.
  2392. --*/
  2393. {
  2394. PDNS_NETINFO pnetInfo = NULL;
  2395. PIP_ARRAY pserverIpArray = NULL;
  2396. DNSDBG( TRACE, ( "GetDnsServerList()" ));
  2397. //
  2398. // get network info to make list from
  2399. // - don't need IP address lists
  2400. //
  2401. pnetInfo = NetInfo_Get(
  2402. fForce, // force registry read
  2403. FALSE // no IP address lists
  2404. );
  2405. if ( !pnetInfo )
  2406. {
  2407. SetLastError( DNS_ERROR_NO_DNS_SERVERS );
  2408. return( NULL );
  2409. }
  2410. //
  2411. // convert network info to IP_ARRAY
  2412. //
  2413. pserverIpArray = NetInfo_ConvertToIpArray( pnetInfo );
  2414. NetInfo_Free( pnetInfo );
  2415. if ( !pserverIpArray )
  2416. {
  2417. SetLastError( DNS_ERROR_NO_MEMORY );
  2418. return( NULL );
  2419. }
  2420. // if no servers read, return
  2421. if ( pserverIpArray->AddrCount == 0 )
  2422. {
  2423. FREE_HEAP( pserverIpArray );
  2424. DNS_PRINT((
  2425. "Dns_GetDnsServerList() failed: no DNS servers found\n"
  2426. "\tstatus = %d\n" ));
  2427. SetLastError( DNS_ERROR_NO_DNS_SERVERS );
  2428. return( NULL );
  2429. }
  2430. IF_DNSDBG( NETINFO )
  2431. {
  2432. DnsDbg_IpArray(
  2433. "DNS server list",
  2434. "server",
  2435. pserverIpArray );
  2436. }
  2437. return( pserverIpArray );
  2438. }
  2439. //
  2440. // End netinfo.c
  2441. //