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.

728 lines
15 KiB

  1. /*++
  2. Copyright (c) 2000-2000 Microsoft Corporation
  3. Module Name:
  4. ip.c
  5. Abstract:
  6. DNS Resolver Service.
  7. IP list and change notification.
  8. Author:
  9. Jim Gilroy (jamesg) November 2000
  10. Revision History:
  11. --*/
  12. #include "local.h"
  13. #include "iphlpapi.h"
  14. //
  15. // IP notify thread globals
  16. //
  17. HANDLE g_IpNotifyThread;
  18. DWORD g_IpNotifyThreadId;
  19. HANDLE g_IpNotifyEvent;
  20. HANDLE g_IpNotifyHandle;
  21. OVERLAPPED g_IpNotifyOverlapped;
  22. //
  23. // Cluster record TTLs -- use max TTL
  24. //
  25. #define CLUSTER_RECORD_TTL (g_MaxCacheTtl)
  26. //
  27. // Shutdown\close locking
  28. //
  29. // Since GQCS and GetOverlappedResult() don't directly wait
  30. // on StopEvent, we need to be able to close notification handle
  31. // and port in two different threads.
  32. //
  33. // Note: this should probably be some general CS that is
  34. // overloaded to do service control stuff.
  35. // I'm not using the server control CS because it's not clear
  36. // that the functions it does in dnsrslvr.c even need locking.
  37. //
  38. #define LOCK_IP_NOTIFY_HANDLE() EnterCriticalSection( &NetworkFailureCS )
  39. #define UNLOCK_IP_NOTIFY_HANDLE() LeaveCriticalSection( &NetworkFailureCS )
  40. CRITICAL_SECTION g_IpListCS;
  41. #define LOCK_IP_LIST() EnterCriticalSection( &g_IpListCS );
  42. #define UNLOCK_IP_LIST() LeaveCriticalSection( &g_IpListCS );
  43. //
  44. // Cluster Tag
  45. //
  46. #define CLUSTER_TAG 0xd734453d
  47. VOID
  48. CloseIpNotifyHandle(
  49. VOID
  50. )
  51. /*++
  52. Routine Description:
  53. Close IP notify handle.
  54. Wrapping up code since this close must be MT
  55. safe and is done in several places.
  56. Arguments:
  57. None
  58. Return Value:
  59. None
  60. --*/
  61. {
  62. LOCK_IP_NOTIFY_HANDLE();
  63. if ( g_IpNotifyHandle )
  64. {
  65. //CloseHandle( g_IpNotifyHandle );
  66. PostQueuedCompletionStatus(
  67. g_IpNotifyHandle,
  68. 0, // no bytes
  69. 0, // no key
  70. & g_IpNotifyOverlapped );
  71. g_IpNotifyHandle = NULL;
  72. }
  73. UNLOCK_IP_NOTIFY_HANDLE();
  74. }
  75. DNS_STATUS
  76. IpNotifyThread(
  77. IN LPVOID pvDummy
  78. )
  79. /*++
  80. Routine Description:
  81. IP notification thread.
  82. Arguments:
  83. pvDummy -- unused
  84. Return Value:
  85. NO_ERROR on normal service shutdown
  86. Win32 error on abnormal termination
  87. --*/
  88. {
  89. DNS_STATUS status = NO_ERROR;
  90. DWORD bytesRecvd;
  91. BOOL fstartedNotify;
  92. BOOL fhaveIpChange = FALSE;
  93. BOOL fsleep = FALSE;
  94. HANDLE notifyHandle;
  95. DNSDBG( INIT, ( "\nStart IpNotifyThread.\n" ));
  96. g_IpNotifyHandle = NULL;
  97. //
  98. // wait in loop on notifications
  99. //
  100. while ( !g_StopFlag )
  101. {
  102. //
  103. // spin protect
  104. // - if error in previous NotifyAddrChange or
  105. // GetOverlappedResult do short sleep to avoid
  106. // chance of hard spin
  107. //
  108. if ( fsleep )
  109. {
  110. WaitForSingleObject(
  111. g_hStopEvent,
  112. 60000 );
  113. fsleep = FALSE;
  114. continue;
  115. }
  116. //
  117. // start notification
  118. //
  119. // do this before checking result as we want notification
  120. // down BEFORE we read so we don't leave window where
  121. // IP change is not picked up
  122. //
  123. RtlZeroMemory(
  124. &g_IpNotifyOverlapped,
  125. sizeof(OVERLAPPED) );
  126. if ( g_IpNotifyEvent )
  127. {
  128. g_IpNotifyOverlapped.hEvent = g_IpNotifyEvent;
  129. ResetEvent( g_IpNotifyEvent );
  130. }
  131. notifyHandle = 0;
  132. fstartedNotify = FALSE;
  133. status = NotifyAddrChange(
  134. & notifyHandle,
  135. & g_IpNotifyOverlapped );
  136. if ( status == ERROR_IO_PENDING )
  137. {
  138. DNSDBG( INIT, (
  139. "NotifyAddrChange()\n"
  140. "\tstatus = %d\n"
  141. "\thandle = %d\n"
  142. "\toverlapped event = %d\n",
  143. status,
  144. notifyHandle,
  145. g_IpNotifyOverlapped.hEvent ));
  146. g_IpNotifyHandle = notifyHandle;
  147. fstartedNotify = TRUE;
  148. }
  149. else
  150. {
  151. DNSDBG( ANY, (
  152. "NotifyAddrChange() FAILED\n"
  153. "\tstatus = %d\n"
  154. "\thandle = %d\n"
  155. "\toverlapped event = %d\n",
  156. status,
  157. notifyHandle,
  158. g_IpNotifyOverlapped.hEvent ));
  159. fsleep = TRUE;
  160. }
  161. if ( g_StopFlag )
  162. {
  163. goto Done;
  164. }
  165. //
  166. // previous notification -- refresh data
  167. //
  168. // FlushCache currently include local IP list
  169. // sleep keeps us from spinning in this loop
  170. //
  171. // DCR: better spin protection;
  172. // if hit X times then sleep longer?
  173. //
  174. if ( fhaveIpChange )
  175. {
  176. DNSDBG( ANY, ( "\nIP notification, flushing cache and restarting.\n" ));
  177. HandleConfigChange(
  178. "IP-notification",
  179. TRUE // flush cache
  180. );
  181. fhaveIpChange = FALSE;
  182. }
  183. //
  184. // starting --
  185. // clear list to force rebuild of IP list AFTER starting notify
  186. // so we can know that we don't miss any changes;
  187. // need this on startup, but also to protect against any
  188. // NotifyAddrChange failues
  189. //
  190. // FIX6: should invalidate netinfo on notify start?
  191. // same reasoning as for IP list -- make sure we have fresh data?
  192. //
  193. else if ( fstartedNotify )
  194. {
  195. // local addr now carried in netinfo
  196. //ClearLocalAddrArray();
  197. }
  198. //
  199. // anti-spin protection
  200. // - 15 second sleep between any notifications
  201. //
  202. WaitForSingleObject(
  203. g_hStopEvent,
  204. 15000 );
  205. if ( g_StopFlag )
  206. {
  207. goto Done;
  208. }
  209. //
  210. // wait on notification
  211. // - save notification result
  212. // - sleep on error, but never if notification
  213. //
  214. if ( fstartedNotify )
  215. {
  216. fhaveIpChange = GetOverlappedResult(
  217. g_IpNotifyHandle,
  218. & g_IpNotifyOverlapped,
  219. & bytesRecvd,
  220. TRUE // wait
  221. );
  222. fsleep = !fhaveIpChange;
  223. status = NO_ERROR;
  224. if ( !fhaveIpChange )
  225. {
  226. status = GetLastError();
  227. }
  228. DNSDBG( ANY, (
  229. "GetOverlappedResult() => %d.\n"
  230. "\t\tstatus = %d\n",
  231. fhaveIpChange,
  232. status ));
  233. }
  234. }
  235. Done:
  236. DNSDBG( ANY, ( "Stop IP Notify thread on service shutdown.\n" ));
  237. CloseIpNotifyHandle();
  238. return( status );
  239. }
  240. VOID
  241. ZeroInitIpListGlobals(
  242. VOID
  243. )
  244. /*++
  245. Routine Description:
  246. Zero-init IP globals just for failure protection.
  247. The reason to have this is there is some interaction with
  248. the cache from the notify thread. To avoid that being a
  249. problem we start the cache first.
  250. But just for safety we should at least zero init these
  251. globals first to protect us from cache touching them.
  252. Arguments:
  253. Return Value:
  254. NO_ERROR on normal service shutdown
  255. Win32 error on abnormal termination
  256. --*/
  257. {
  258. //
  259. // clear out globals to smoothly handle failure cases
  260. //
  261. g_IpNotifyThread = NULL;
  262. g_IpNotifyThreadId = 0;
  263. g_IpNotifyEvent = NULL;
  264. g_IpNotifyHandle = NULL;
  265. }
  266. DNS_STATUS
  267. InitIpListAndNotification(
  268. VOID
  269. )
  270. /*++
  271. Routine Description:
  272. Start IP notification thread.
  273. Arguments:
  274. None
  275. Globals:
  276. Initializes IP list and notify thread globals.
  277. Return Value:
  278. NO_ERROR on normal service shutdown
  279. Win32 error on abnormal termination
  280. --*/
  281. {
  282. DNS_STATUS status = NO_ERROR;
  283. DNSDBG( TRACE, ( "InitIpListAndNotification()\n" ));
  284. //
  285. // CS for IP list access
  286. //
  287. InitializeCriticalSection( &g_IpListCS );
  288. //
  289. // create event for overlapped I/O
  290. //
  291. g_IpNotifyEvent = CreateEvent(
  292. NULL, // no security descriptor
  293. TRUE, // manual reset event
  294. FALSE, // start not signalled
  295. NULL // no name
  296. );
  297. if ( !g_IpNotifyEvent )
  298. {
  299. status = GetLastError();
  300. DNSDBG( ANY, ( "\nFAILED IpNotifyEvent create.\n" ));
  301. goto Done;
  302. }
  303. //
  304. // fire up IP notify thread
  305. //
  306. g_IpNotifyThread = CreateThread(
  307. NULL,
  308. 0,
  309. (LPTHREAD_START_ROUTINE) IpNotifyThread,
  310. NULL,
  311. 0,
  312. & g_IpNotifyThreadId
  313. );
  314. if ( !g_IpNotifyThread )
  315. {
  316. status = GetLastError();
  317. DNSDBG( ANY, (
  318. "FAILED to create IP notify thread = %d\n",
  319. status ));
  320. }
  321. Done:
  322. // not currently stopping on init failure
  323. return( ERROR_SUCCESS );
  324. }
  325. VOID
  326. ShutdownIpListAndNotify(
  327. VOID
  328. )
  329. /*++
  330. Routine Description:
  331. Stop IP notify thread.
  332. Note: currently this is blocking call, we'll wait until
  333. thread shuts down.
  334. Arguments:
  335. None.
  336. Return Value:
  337. None.
  338. --*/
  339. {
  340. DNSDBG( TRACE, ( "ShutdownIpListAndNotify()\n" ));
  341. //
  342. // MUST be stopping
  343. // - if not thread won't wake
  344. //
  345. ASSERT( g_StopFlag );
  346. g_StopFlag = TRUE;
  347. //
  348. // close IP notify handles -- waking thread if still running
  349. //
  350. if ( g_IpNotifyEvent )
  351. {
  352. SetEvent( g_IpNotifyEvent );
  353. }
  354. CloseIpNotifyHandle();
  355. //
  356. // wait for thread to stop
  357. //
  358. ThreadShutdownWait( g_IpNotifyThread );
  359. g_IpNotifyThread = NULL;
  360. //
  361. // close event
  362. //
  363. CloseHandle( g_IpNotifyEvent );
  364. g_IpNotifyEvent = NULL;
  365. //
  366. // kill off CS
  367. //
  368. DeleteCriticalSection( &g_IpListCS );
  369. }
  370. //
  371. // Cluster registration
  372. //
  373. DNS_STATUS
  374. R_ResolverRegisterCluster(
  375. IN DNS_RPC_HANDLE Handle,
  376. IN DWORD Tag,
  377. IN PWSTR pwsName,
  378. IN PDNS_ADDR pAddr,
  379. IN DWORD Flag
  380. )
  381. /*++
  382. Routine Description:
  383. Make the query to remote DNS server.
  384. Arguments:
  385. Handle -- RPC handle
  386. Tag -- RPC API tag
  387. pwsName -- name of cluster
  388. pIpUnion -- IP union
  389. Flag -- registration flag
  390. DNS_CLUSTER_ADD
  391. DNS_CLUSTER_DELETE_NAME
  392. DNS_CLUSTER_DELETE_IP
  393. Return Value:
  394. None
  395. --*/
  396. {
  397. PDNS_RECORD prrAddr = NULL;
  398. PDNS_RECORD prrPtr = NULL;
  399. DNS_STATUS status = NO_ERROR;
  400. DNSLOG_F1( "R_ResolverRegisterCluster" );
  401. DNSDBG( RPC, (
  402. "R_ResolverRegisterCluster()\n"
  403. "\tpName = %s\n"
  404. "\tpAddr = %p\n"
  405. "\tFlag = %08x\n",
  406. pwsName,
  407. pAddr,
  408. Flag ));
  409. //
  410. // DCR: cluster not doing local registration
  411. // removed for .net to avoid any possible security hole
  412. //
  413. #if 0
  414. if ( !Rpc_AccessCheck( RESOLVER_ACCESS_REGISTER ) )
  415. {
  416. DNSLOG_F1( "R_ResolverRegisterClusterIp - ERROR_ACCESS_DENIED" );
  417. return ERROR_ACCESS_DENIED;
  418. }
  419. if ( Tag != CLUSTER_TAG )
  420. {
  421. return ERROR_ACCESS_DENIED;
  422. }
  423. //
  424. // validate address
  425. //
  426. if ( Flag != DNS_CLUSTER_DELETE_NAME &&
  427. !DnsAddr_IsIp4(pAddr) &&
  428. !DnsAddr_IsIp6(pAddr) )
  429. {
  430. DNS_ASSERT( FALSE );
  431. return ERROR_INVALID_PARAMETER;
  432. }
  433. //
  434. // cluster add -- cache cluster records
  435. // - forward and reverse
  436. //
  437. if ( !pwsName )
  438. {
  439. DNSDBG( ANY, ( "WARNING: no cluster name given!\n" ));
  440. return ERROR_INVALID_PARAMETER;
  441. }
  442. //
  443. // build records
  444. // - address and corresponding PTR
  445. //
  446. if ( Flag != DNS_CLUSTER_DELETE_NAME )
  447. {
  448. prrAddr = Dns_CreateForwardRecord(
  449. pwsName,
  450. 0, // type for addr
  451. pAddr,
  452. CLUSTER_RECORD_TTL,
  453. DnsCharSetUnicode,
  454. DnsCharSetUnicode );
  455. if ( !prrAddr )
  456. {
  457. goto Failed;
  458. }
  459. SET_RR_CLUSTER( prrAddr );
  460. prrPtr = Dns_CreatePtrRecordEx(
  461. pAddr,
  462. pwsName,
  463. CLUSTER_RECORD_TTL,
  464. DnsCharSetUnicode,
  465. DnsCharSetUnicode );
  466. if ( !prrPtr )
  467. {
  468. goto Failed;
  469. }
  470. SET_RR_CLUSTER( prrPtr );
  471. }
  472. //
  473. // add records to cache
  474. //
  475. if ( Flag == DNS_CLUSTER_ADD )
  476. {
  477. Cache_RecordSetAtomic(
  478. NULL, // record name
  479. 0, // record type
  480. prrAddr );
  481. if ( prrPtr )
  482. {
  483. Cache_RecordSetAtomic(
  484. NULL, // record name
  485. 0, // record type
  486. prrPtr );
  487. }
  488. prrAddr = NULL;
  489. prrPtr = NULL;
  490. }
  491. //
  492. // if delete cluster, flush cache entries for name\type
  493. //
  494. // DCR: not deleting PTR for CLUSTER_DELETE_NAME
  495. // would need to extract and reverse existing A\AAAA records
  496. //
  497. // DCR: build reverse name independently so whack works
  498. // even without cluster name
  499. //
  500. if ( Flag == DNS_CLUSTER_DELETE_NAME )
  501. {
  502. Cache_FlushRecords(
  503. pwsName,
  504. FLUSH_LEVEL_STRONG,
  505. 0 );
  506. // delete record matching PTR
  507. // need to flush JUST PTR pointing to this name
  508. // this may be optional -- whether we're given an IP
  509. // with the name or not
  510. goto Done;
  511. }
  512. //
  513. // delete specific cluster IP (name\addr pair)
  514. //
  515. if ( Flag == DNS_CLUSTER_DELETE_IP )
  516. {
  517. Cache_DeleteMatchingRecords( prrAddr );
  518. Cache_DeleteMatchingRecords( prrPtr );
  519. goto Done;
  520. }
  521. DNSDBG( ANY, (
  522. "ERROR: invalid cluster flag %d!\n",
  523. Flag ));
  524. status = ERROR_INVALID_PARAMETER;
  525. Failed:
  526. if ( status == NO_ERROR )
  527. {
  528. status = GetLastError();
  529. if ( status == NO_ERROR )
  530. {
  531. status = ERROR_INVALID_DATA;
  532. }
  533. }
  534. Done:
  535. // cleanup uncached records
  536. Dns_RecordFree( prrAddr );
  537. Dns_RecordFree( prrPtr );
  538. DNSDBG( RPC, (
  539. "Leave R_ResolverRegisterCluster() => %d\n",
  540. status ));
  541. #endif
  542. return status;
  543. }
  544. //
  545. // End ip.c
  546. //