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.

897 lines
18 KiB

  1. /*++
  2. Copyright (c) 2000-2001 Microsoft Corporation
  3. Module Name:
  4. config.c
  5. Abstract:
  6. DNS Resolver Service.
  7. Network configuration info
  8. Author:
  9. Jim Gilroy (jamesg) March 2000
  10. Revision History:
  11. --*/
  12. #include "local.h"
  13. //
  14. // Network info
  15. //
  16. PDNS_NETINFO g_NetworkInfo = NULL;
  17. DWORD g_TimeOfLastPnPUpdate;
  18. DWORD g_NetInfoTag = 0;
  19. DWORD g_ResetServerPriorityTime = 0;
  20. //
  21. // Network failure caching
  22. //
  23. DWORD g_NetFailureTime;
  24. DNS_STATUS g_NetFailureStatus;
  25. DWORD g_TimedOutAdapterTime;
  26. BOOL g_fTimedOutAdapter;
  27. DNS_STATUS g_PreviousNetFailureStatus;
  28. DWORD g_MessagePopupStrikes;
  29. DWORD g_NumberOfMessagePopups;
  30. //
  31. // Config globals
  32. //
  33. // DCR: eliminate useless config globals
  34. //
  35. DWORD g_HashTableSize;
  36. DWORD g_MaxSOACacheEntryTtlLimit;
  37. DWORD g_NegativeSOACacheTime;
  38. DWORD g_NetFailureCacheTime;
  39. DWORD g_MessagePopupLimit;
  40. //
  41. // Network Info reread time
  42. // - currently fifteen minutes
  43. //
  44. #define NETWORK_INFO_REREAD_TIME (900)
  45. //
  46. // Locking
  47. //
  48. CRITICAL_SECTION NetinfoCS;
  49. TIMED_LOCK NetinfoBuildLock;
  50. #define LOCK_NETINFO() EnterCriticalSection( &NetinfoCS )
  51. #define UNLOCK_NETINFO() LeaveCriticalSection( &NetinfoCS )
  52. #define LOCK_NETINFO_BUILD() TimedLock_Enter( &NetinfoBuildLock, 5000 )
  53. #define UNLOCK_NETINFO_BUILD() TimedLock_Leave( &NetinfoBuildLock )
  54. //
  55. // Network info configuration
  56. //
  57. VOID
  58. UpdateNetworkInfo(
  59. IN PDNS_NETINFO pNetInfo OPTIONAL
  60. )
  61. /*++
  62. Routine Description:
  63. Update network info global.
  64. Arguments:
  65. pNetInfo -- desired network info; if NULL clear cached copy
  66. Return Value:
  67. None
  68. --*/
  69. {
  70. PDNS_NETINFO poldInfo = NULL;
  71. DNSDBG( TRACE, (
  72. "UpdateNetworkInfo( %p )\n",
  73. pNetInfo ));
  74. LOCK_NETINFO();
  75. //
  76. // cache previous netinfo to pickup server priority changes
  77. // - don't cache if not same version
  78. // - kills copy that was created before last build
  79. // - kills copy that was before last PnP (cache clear)
  80. // - don't cache if never reset priorities
  81. //
  82. if ( pNetInfo )
  83. {
  84. if ( pNetInfo->Tag != g_NetInfoTag )
  85. {
  86. DNSDBG( INIT, (
  87. "Skip netinfo update -- previous version"
  88. "\tptr = %p\n"
  89. "\tversion = %d\n"
  90. "\tcurrent version = %d\n",
  91. pNetInfo,
  92. pNetInfo->Tag,
  93. g_NetInfoTag ));
  94. poldInfo = pNetInfo;
  95. DNS_ASSERT( pNetInfo->Tag < g_NetInfoTag );
  96. goto Cleanup;
  97. }
  98. if ( g_ServerPriorityTimeLimit == 0 )
  99. {
  100. DNSDBG( INIT, (
  101. "Skip netinfo update -- no priority reset!\n" ));
  102. poldInfo = pNetInfo;
  103. goto Cleanup;
  104. }
  105. NetInfo_Clean(
  106. pNetInfo,
  107. CLEAR_LEVEL_QUERY
  108. );
  109. }
  110. //
  111. // no netinfo means clear cached copy
  112. // - push up tag count, so no copy out for update can
  113. // come back and be reused through path above
  114. else
  115. {
  116. g_NetInfoTag++;
  117. }
  118. //
  119. // swap -- caches copy or clears
  120. //
  121. poldInfo = g_NetworkInfo;
  122. g_NetworkInfo = pNetInfo;
  123. Cleanup:
  124. UNLOCK_NETINFO();
  125. NetInfo_Free( poldInfo );
  126. }
  127. PDNS_NETINFO
  128. GrabNetworkInfo(
  129. VOID
  130. )
  131. /*++
  132. Routine Description:
  133. Get copy of network info.
  134. Named it "Grab" to avoid confusion with GetNetworkInfo()
  135. in dnsapi.dll.
  136. Arguments:
  137. None
  138. Return Value:
  139. Ptr to copy of network info (caller must free).
  140. NULL on error.
  141. --*/
  142. {
  143. PDNS_NETINFO poldInfo = NULL;
  144. PDNS_NETINFO pnewInfo = NULL;
  145. DWORD currentTime = Dns_GetCurrentTimeInSeconds();
  146. DWORD newTag;
  147. BOOL fbuildLock = FALSE;
  148. BOOL fnetLock = FALSE;
  149. DNSDBG( TRACE, ( "GrabNetworkInfo()\n" ));
  150. //
  151. // Locking note:
  152. //
  153. // Can not hold a single NET_LIST lock during netinfo build.
  154. // - IpHlpApi doing routing info call RPCs to router which can
  155. // depend on PnP notifications, which in turn can be causing calls
  156. // back into resolver indicating config change; overall the loss
  157. // of control is too large
  158. //
  159. // There are ways to make the config change issue go away (ex setting
  160. // some sort of "invalid" flag under interlock), but they basically boil
  161. // down to introducing some other sort of lock.
  162. //
  163. // The bottom line is there are TWO SEPARATE issues here:
  164. //
  165. // 1) Access to cache netinfo, which may be invalidated.
  166. // 2) Single build of netinfo for perf.
  167. //
  168. // Implementation wise, you can have the invalidation\clear under a
  169. // separate interlock, and thus have a single lock for copy-access\build,
  170. // but the reality is the same.
  171. //
  172. //
  173. // Algorithm:
  174. // - check for valid cached copy
  175. // => found, out
  176. // - get build lock
  177. // - check again for valid cached copy
  178. // => found, out
  179. // - build
  180. // - cache new netinfo
  181. // - release build lock
  182. //
  183. // Where the check and cache work are independently locked with the shorter
  184. // duration NET_LIST lock, which simply protects access to the cached global
  185. // (and hence is also used in invalidation and update).
  186. //
  187. //
  188. // check for valid cached netinfo
  189. // - within forced reread time
  190. // - reset server priorities if
  191. //
  192. // DCR: priority reset time should move into netinfo blob
  193. //
  194. // for perf we do this BEFORE entering build lock
  195. // then again once have build lock
  196. //
  197. while ( 1 )
  198. {
  199. LOCK_NETINFO();
  200. fnetLock = TRUE;
  201. if ( g_NetworkInfo &&
  202. g_NetworkInfo->TimeStamp + NETWORK_INFO_REREAD_TIME > currentTime )
  203. {
  204. if ( g_ResetServerPriorityTime < currentTime )
  205. {
  206. NetInfo_ResetServerPriorities( g_NetworkInfo, TRUE );
  207. g_ResetServerPriorityTime = currentTime + g_ServerPriorityTimeLimit;
  208. }
  209. goto Copy;
  210. }
  211. //
  212. // if no cached info
  213. // - get build lock
  214. // - loop back and recheck cache
  215. //
  216. if ( fbuildLock )
  217. {
  218. goto Build;
  219. }
  220. UNLOCK_NETINFO();
  221. fnetLock = FALSE;
  222. fbuildLock = LOCK_NETINFO_BUILD();
  223. if ( fbuildLock )
  224. {
  225. continue;
  226. }
  227. goto Unlock;
  228. }
  229. //
  230. // current global expired
  231. // - build new netinfo
  232. // - tag it with unique monotonically increasing id
  233. // this makes sure we never use older version
  234. // - push forward priorities reset time
  235. // - make newinfo the global copy
  236. //
  237. Build:
  238. DNS_ASSERT( fnetLock && fbuildLock );
  239. newTag = ++g_NetInfoTag;
  240. UNLOCK_NETINFO();
  241. fnetLock = FALSE;
  242. pnewInfo = NetInfo_Build( TRUE );
  243. if ( !pnewInfo )
  244. {
  245. DNSDBG( ANY, ( "ERROR: GrabNetworkInfo() failed -- no netinfo blob!\n" ));
  246. goto Unlock;
  247. }
  248. LOCK_NETINFO();
  249. fnetLock = TRUE;
  250. pnewInfo->Tag = newTag;
  251. if ( newTag != g_NetInfoTag )
  252. {
  253. DNS_ASSERT( newTag < g_NetInfoTag );
  254. DNSDBG( ANY, (
  255. "WARNING: New netinfo uncacheable -- tag is old!\n"
  256. "\tour tag = %d\n"
  257. "\tcurrent tag = %d\n",
  258. newTag,
  259. g_NetInfoTag ));
  260. goto Unlock;
  261. }
  262. // if tag still current cache this new netinfo
  263. g_ResetServerPriorityTime = currentTime + g_ServerPriorityTimeLimit;
  264. g_TimedOutAdapterTime = 0;
  265. g_fTimedOutAdapter = FALSE;
  266. poldInfo = g_NetworkInfo;
  267. g_NetworkInfo = pnewInfo;
  268. Copy:
  269. //
  270. // make copy of global (new or reset)
  271. //
  272. pnewInfo = NetInfo_Copy( g_NetworkInfo );
  273. Unlock:
  274. if ( fnetLock )
  275. {
  276. UNLOCK_NETINFO();
  277. }
  278. if ( fbuildLock )
  279. {
  280. UNLOCK_NETINFO_BUILD();
  281. }
  282. NetInfo_Free( poldInfo );
  283. return pnewInfo;
  284. }
  285. VOID
  286. ZeroNetworkConfigGlobals(
  287. VOID
  288. )
  289. /*++
  290. Routine Description:
  291. Zero init network globals.
  292. Arguments:
  293. None
  294. Return Value:
  295. None
  296. --*/
  297. {
  298. // net failure
  299. g_NetFailureTime = 0;
  300. g_NetFailureStatus = NO_ERROR;
  301. g_PreviousNetFailureStatus = NO_ERROR;
  302. g_fTimedOutAdapter = FALSE;
  303. g_TimedOutAdapterTime = 0;
  304. g_MessagePopupStrikes = 0;
  305. g_NumberOfMessagePopups = 0;
  306. // network info
  307. g_TimeOfLastPnPUpdate = 0;
  308. g_NetworkInfo = NULL;
  309. }
  310. VOID
  311. CleanupNetworkInfo(
  312. VOID
  313. )
  314. /*++
  315. Routine Description:
  316. Cleanup network info.
  317. Arguments:
  318. None
  319. Return Value:
  320. None
  321. --*/
  322. {
  323. LOCK_NETINFO();
  324. if ( g_NetworkInfo )
  325. {
  326. NetInfo_Free( g_NetworkInfo );
  327. g_NetworkInfo = NULL;
  328. }
  329. UNLOCK_NETINFO();
  330. }
  331. //
  332. // General configuration
  333. //
  334. VOID
  335. ReadRegistryConfig(
  336. VOID
  337. )
  338. {
  339. //
  340. // re-read full DNS registry info
  341. //
  342. Reg_ReadGlobalsEx( 0, NULL );
  343. //
  344. // set "we are the resolver" global
  345. //
  346. g_InResolver = TRUE;
  347. //
  348. // just default old config globals until remove
  349. //
  350. // DCR: status of old config globals?
  351. //
  352. g_MaxSOACacheEntryTtlLimit = DNS_DEFAULT_MAX_SOA_TTL_LIMIT;
  353. g_NegativeSOACacheTime = DNS_DEFAULT_NEGATIVE_SOA_CACHE_TIME;
  354. g_NetFailureCacheTime = DNS_DEFAULT_NET_FAILURE_CACHE_TIME;
  355. g_HashTableSize = DNS_DEFAULT_HASH_TABLE_SIZE;
  356. g_MessagePopupLimit = DNS_DEFAULT_MESSAGE_POPUP_LIMIT;
  357. }
  358. VOID
  359. HandleConfigChange(
  360. IN PSTR pszReason,
  361. IN BOOL fCacheFlush
  362. )
  363. /*++
  364. Routine Description:
  365. Response to configuration change.
  366. Arguments:
  367. pszReason -- config change cause (informational only)
  368. fCache_Flush -- flush if config change requires cache flush
  369. Return Value:
  370. None
  371. --*/
  372. {
  373. DNSDBG( INIT, (
  374. "\n"
  375. "HandleConfigChange() => %s\n"
  376. "\tflush = %d\n",
  377. pszReason,
  378. fCacheFlush ));
  379. //
  380. // lock out all work while tear down everything
  381. // - lock with no start option so if we are already torn
  382. // down we don't rebuild
  383. // - optionally flush cache
  384. // - dump IP list
  385. // - dump network info
  386. //
  387. LOCK_CACHE_NO_START();
  388. //
  389. // cache flush?
  390. //
  391. // all config changes don't necessarily require cache flush;
  392. // if not required just rebuild local list and config
  393. //
  394. if ( fCacheFlush )
  395. {
  396. Cache_Flush();
  397. }
  398. #if 0
  399. // FIX6: no separate local addr info now
  400. // UpdateNetworkInfo() handles freshness issue
  401. else
  402. {
  403. ClearLocalAddrArray();
  404. }
  405. #endif
  406. //
  407. // clear network info
  408. // save PnP time
  409. // clear net failure flags
  410. //
  411. UpdateNetworkInfo( NULL );
  412. g_TimeOfLastPnPUpdate = Dns_GetCurrentTimeInSeconds();
  413. g_NetFailureTime = 0;
  414. g_NetFailureStatus = NO_ERROR;
  415. DNSDBG( INIT, (
  416. "Leave HandleConfigChange() => %s\n"
  417. "\tflush = %d\n\n",
  418. pszReason,
  419. fCacheFlush ));
  420. UNLOCK_CACHE();
  421. }
  422. //
  423. // Remote APIs
  424. //
  425. VOID
  426. R_ResolverGetConfig(
  427. IN DNS_RPC_HANDLE Handle,
  428. IN DWORD Cookie,
  429. OUT PDNS_NETINFO * ppNetInfo,
  430. OUT PDNS_GLOBALS_BLOB * ppGlobals
  431. )
  432. /*++
  433. Routine Description:
  434. Make the query to remote DNS server.
  435. Arguments:
  436. Handle -- RPC handle
  437. Cookie -- cookie of last succesful config transfer
  438. zero indicates no previous successful transfer
  439. ppNetInfo -- addr to receive ptr to network info
  440. ppGlobals -- addr to receive ptr to globals blob
  441. Return Value:
  442. None
  443. --*/
  444. {
  445. PDNS_GLOBALS_BLOB pblob;
  446. DNSLOG_F1( "R_ResolverGetConfig" );
  447. DNSDBG( RPC, (
  448. "R_ResolverGetConfig\n"
  449. "\tcookie = %p\n",
  450. Cookie ));
  451. if ( !ppNetInfo || !ppGlobals )
  452. {
  453. return;
  454. }
  455. //
  456. // DCR: config cookie check
  457. // - no need to get data if client has current copy
  458. //
  459. //
  460. // copy network info global
  461. //
  462. // note: currently RPC is using same allocator (dnslib)
  463. // as GrabNetworkInfo(); so we are ok just passing
  464. // NETINFO blob as is
  465. //
  466. // note: could build on "no-global" but since we create on
  467. // cache start we should always have global or be
  468. // just starting
  469. //
  470. *ppNetInfo = (PDNS_NETINFO) GrabNetworkInfo();
  471. pblob = (PDNS_GLOBALS_BLOB) RPC_HEAP_ALLOC( sizeof(*pblob) );
  472. if ( pblob )
  473. {
  474. RtlCopyMemory(
  475. pblob,
  476. & DnsGlobals,
  477. sizeof(DnsGlobals) );
  478. // clear "in resolver" flag
  479. pblob->InResolver = FALSE;
  480. }
  481. *ppGlobals = pblob;
  482. DNSDBG( RPC, ( "Leave R_ResolverGetConfig\n\n" ));
  483. }
  484. VOID
  485. R_ResolverPoke(
  486. IN DNS_RPC_HANDLE Handle,
  487. IN DWORD Cookie,
  488. IN DWORD Id
  489. )
  490. /*++
  491. Routine Description:
  492. Test interface to poke resolver to update.
  493. Arguments:
  494. Handle -- RPC handle
  495. Cookie -- cookie
  496. Id -- operation Id
  497. Return Value:
  498. None
  499. --*/
  500. {
  501. DNSLOG_F1( "R_ResolverPoke" );
  502. DNSDBG( RPC, (
  503. "R_ResolverPoke\n"
  504. "\tcookie = %08x\n"
  505. "\tid = %d\n",
  506. Cookie,
  507. Id ));
  508. if ( !Rpc_AccessCheck( RESOLVER_ACCESS_FLUSH ) )
  509. {
  510. DNSLOG_F1( "R_ResolverPoke - ERROR_ACCESS_DENIED" );
  511. return;
  512. }
  513. //
  514. // do operation for particular id
  515. // - update netinfo clears cached copy
  516. if ( Id == POKE_OP_UPDATE_NETINFO )
  517. {
  518. if ( Cookie == POKE_COOKIE_UPDATE_NETINFO )
  519. {
  520. UpdateNetworkInfo( NULL );
  521. }
  522. }
  523. }
  524. //
  525. // Net failure stuff -- of dubious value
  526. //
  527. #if 0
  528. BOOL
  529. IsKnownNetFailure(
  530. VOID
  531. )
  532. /*++
  533. Routine Description:
  534. Determine if we are in known net failure window.
  535. Arguments:
  536. None
  537. Return Value:
  538. TRUE if in known net failure
  539. FALSE otherwise
  540. --*/
  541. {
  542. BOOL flag = FALSE;
  543. DNSDBG( TRACE, ( "IsKnownNetFailure()\n" ));
  544. //
  545. // DCR: should have NetFailure check outside of lock for perf
  546. //
  547. LOCK_NET_FAILURE();
  548. if ( g_NetFailureStatus )
  549. {
  550. if ( g_NetFailureTime < Dns_GetCurrentTimeInSeconds() )
  551. {
  552. g_NetFailureTime = 0;
  553. g_NetFailureStatus = ERROR_SUCCESS;
  554. flag = FALSE;
  555. }
  556. else
  557. {
  558. SetLastError( g_NetFailureStatus );
  559. flag = TRUE;
  560. }
  561. }
  562. UNLOCK_NET_FAILURE();
  563. return flag;
  564. }
  565. VOID
  566. SetKnownNetFailure(
  567. IN DNS_STATUS Status
  568. )
  569. /*++
  570. Routine Description:
  571. Set cause of net failure.
  572. Arguments:
  573. Status -- status code for cause of net failure
  574. Return Value:
  575. None
  576. --*/
  577. {
  578. LPSTR DnsString = NULL;
  579. LPWSTR InsertStrings[3];
  580. WCHAR String1[25];
  581. WCHAR String2[256];
  582. WCHAR String3[25];
  583. DNSDBG( TRACE, ( "SetKnownNetFailure()\n" ));
  584. //
  585. // don't indicate failure during boot
  586. //
  587. if ( Dns_GetCurrentTimeInSeconds() < THREE_MINUTES_FROM_SYSTEM_BOOT )
  588. {
  589. return;
  590. }
  591. //
  592. // DCR: need to detect no-net
  593. //
  594. // FIX6: should detect no-net and skip this
  595. //
  596. if ( g_NetFailureCacheTime == 0 )
  597. {
  598. //
  599. // We are in a no-net configuration, there is no need
  600. // to display the pop-up message. No point warning
  601. // of DNS configuration problems when the system is
  602. // off the net.
  603. // - or -
  604. // We are on a NT server, and therefore don't do poor network
  605. // performance caching.
  606. //
  607. return;
  608. }
  609. LOCK_NET_FAILURE();
  610. g_NetFailureTime = Dns_GetCurrentTimeInSeconds() + g_NetFailureCacheTime;
  611. g_NetFailureStatus = Status;
  612. wsprintfW( String1, L"0x%.8X", Status );
  613. DnsString = DnsStatusString( Status );
  614. if ( DnsString )
  615. {
  616. Dns_StringCopy( (PBYTE) String2,
  617. NULL,
  618. (PCHAR) DnsString,
  619. (WORD) strlen( DnsString ),
  620. DnsCharSetAnsi,
  621. DnsCharSetUnicode );
  622. //
  623. // No need to free this since the string is just a pointer
  624. // to a global table entry.
  625. //
  626. // FREE_HEAP( DnsString );
  627. }
  628. else
  629. {
  630. wsprintfW( String2, L"<?>" );
  631. }
  632. wsprintfW( String3, L"%d", g_NetFailureCacheTime );
  633. if ( g_MessagePopupStrikes < 3 )
  634. {
  635. g_MessagePopupStrikes++;
  636. }
  637. else
  638. {
  639. if ( Status != g_PreviousNetFailureStatus )
  640. {
  641. //
  642. // DCR_PERF: should remove logging from inside lock
  643. //
  644. InsertStrings[0] = String1;
  645. InsertStrings[1] = String2;
  646. InsertStrings[2] = String3;
  647. ResolverLogEvent(
  648. EVENT_DNS_CACHE_NETWORK_PERF_WARNING,
  649. EVENTLOG_WARNING_TYPE,
  650. 3,
  651. InsertStrings,
  652. Status );
  653. g_PreviousNetFailureStatus = Status;
  654. }
  655. g_MessagePopupStrikes = 0;
  656. }
  657. UNLOCK_NET_FAILURE();
  658. }
  659. #endif
  660. //
  661. // End config.c
  662. //