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.

527 lines
14 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module:
  4. timer.c
  5. Abstract:
  6. Contains code for the NAT's periodic-timer routine.
  7. Author:
  8. Abolade Gbadegesin (t-abolag) 22-July-1997
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. #pragma hdrstop
  13. //
  14. // Defines the interval at which the timer fires, in 100-nanosecond intervals
  15. //
  16. #define TIMER_INTERVAL (60 * 1000 * 1000 * 10)
  17. //
  18. // DPC object for stress-triggered invocations of NatTimerRoutine
  19. //
  20. KDPC CleanupDpcObject;
  21. //
  22. // Flag indicating whether stress-triggered cleanup has been scheduled.
  23. //
  24. ULONG CleanupDpcPending;
  25. //
  26. // Return-value of KeQueryTimeIncrement, used for normalizing tick-counts
  27. //
  28. ULONG TimeIncrement;
  29. //
  30. // DPC object for NatTimerRoutine
  31. //
  32. KDPC TimerDpcObject;
  33. //
  34. // Timer object for NatTimerRoutine
  35. //
  36. KTIMER TimerObject;
  37. //
  38. // FORWARD DECLARATIONS
  39. //
  40. VOID
  41. NatCleanupDpcRoutine(
  42. PKDPC Dpc,
  43. PVOID DeferredContext,
  44. PVOID SystemArgument1,
  45. PVOID SystemArgument2
  46. );
  47. VOID
  48. NatTimerRoutine(
  49. PKDPC Dpc,
  50. PVOID DeferredContext,
  51. PVOID SystemArgument1,
  52. PVOID SystemArgument2
  53. );
  54. VOID
  55. NatCleanupDpcRoutine(
  56. PKDPC Dpc,
  57. PVOID DeferredContext,
  58. PVOID SystemArgument1,
  59. PVOID SystemArgument2
  60. )
  61. {
  62. KIRQL Irql;
  63. PLIST_ENTRY Link;
  64. PNAT_DYNAMIC_MAPPING Mapping;
  65. KeAcquireSpinLock(&MappingLock, &Irql);
  66. for (Link = MappingList.Flink; Link != &MappingList; Link = Link->Flink) {
  67. Mapping = CONTAINING_RECORD(Link, NAT_DYNAMIC_MAPPING, Link);
  68. if (NAT_MAPPING_EXPIRED(Mapping)) {
  69. Link = Link->Blink;
  70. NatDeleteMapping(Mapping);
  71. }
  72. }
  73. KeReleaseSpinLock(&MappingLock, Irql);
  74. InterlockedExchange(&CleanupDpcPending, FALSE);
  75. }
  76. VOID
  77. NatInitializeTimerManagement(
  78. VOID
  79. )
  80. /*++
  81. Routine Description:
  82. This routine is called to initialize the timer-management module,
  83. in preparation for active operation.
  84. Arguments:
  85. none.
  86. Return Value:
  87. none.
  88. --*/
  89. {
  90. CALLTRACE(("NatInitializeTimerManagement\n"));
  91. TimeIncrement = KeQueryTimeIncrement();
  92. KeInitializeDpc(&TimerDpcObject, NatTimerRoutine, NULL);
  93. KeInitializeTimer(&TimerObject);
  94. CleanupDpcPending = FALSE;
  95. KeInitializeDpc(&CleanupDpcObject, NatCleanupDpcRoutine, NULL);
  96. } // NatInitializeTimerManagement
  97. VOID
  98. NatShutdownTimerManagement(
  99. VOID
  100. )
  101. /*++
  102. Routine Description:
  103. This routine is called to shutdown the timer management module.
  104. Arguments:
  105. none.
  106. Return Value:
  107. none.
  108. --*/
  109. {
  110. CALLTRACE(("NatShutdownTimerManagement\n"));
  111. NatStopTimer();
  112. } // NatShutdownTimerManagement
  113. VOID
  114. NatStartTimer(
  115. VOID
  116. )
  117. /*++
  118. Routine Description:
  119. This routine is invoked to start the periodic timer.
  120. Arguments:
  121. none.
  122. Return Value:
  123. none.
  124. --*/
  125. {
  126. LARGE_INTEGER DueTime;
  127. //
  128. // Launch the periodic timer
  129. //
  130. DueTime.LowPart = TIMER_INTERVAL;
  131. DueTime.HighPart = 0;
  132. DueTime = RtlLargeIntegerNegate(DueTime);
  133. KeSetTimerEx(
  134. &TimerObject,
  135. DueTime,
  136. TIMER_INTERVAL / 10000,
  137. &TimerDpcObject
  138. );
  139. }
  140. VOID
  141. NatStopTimer(
  142. VOID
  143. )
  144. /*++
  145. Routine Description:
  146. This routine is invoked to stop the periodic timer.
  147. Arguments:
  148. none.
  149. Return Value:
  150. none.
  151. --*/
  152. {
  153. KeCancelTimer(&TimerObject);
  154. }
  155. VOID
  156. NatTimerRoutine(
  157. PKDPC Dpc,
  158. PVOID DeferredContext,
  159. PVOID SystemArgument1,
  160. PVOID SystemArgument2
  161. )
  162. /*++
  163. Routine Description:
  164. This routine is invoked periodically to garbage-collect expired mappings.
  165. Arguments:
  166. Dpc - associated DPC object
  167. DeferredContext - unused.
  168. SystemArgument1 - unused.
  169. SystemArgument2 - unused.
  170. Return Value:
  171. none.
  172. --*/
  173. {
  174. LONG64 CurrentTime;
  175. PNAT_EDITOR Editor;
  176. PNAT_ICMP_MAPPING IcmpMapping;
  177. PNAT_INTERFACE Interfacep;
  178. PNAT_IP_MAPPING IpMapping;
  179. KIRQL Irql;
  180. PLIST_ENTRY Link;
  181. PNAT_DYNAMIC_MAPPING Mapping;
  182. PNAT_PPTP_MAPPING PptpMapping;
  183. LONG64 PptpMinAccessTime;
  184. UCHAR Protocol;
  185. PRTL_SPLAY_LINKS SLink;
  186. PNAT_TICKET Ticketp;
  187. LONG64 Timeout;
  188. LONG64 TcpMinAccessTime;
  189. LONG64 UdpMinAccessTime;
  190. CALLTRACE(("NatTimerRoutine\n"));
  191. //
  192. // Compute the minimum values allowed in TCP/UDP 'LastAccessTime' fields;
  193. // any mappings last accessed before these thresholds will be eliminated.
  194. //
  195. KeQueryTickCount((PLARGE_INTEGER)&CurrentTime);
  196. TcpMinAccessTime = CurrentTime - SECONDS_TO_TICKS(TcpTimeoutSeconds);
  197. UdpMinAccessTime = CurrentTime - SECONDS_TO_TICKS(UdpTimeoutSeconds);
  198. PptpMinAccessTime = CurrentTime - SECONDS_TO_TICKS(2 * UdpTimeoutSeconds);
  199. //
  200. // Update mapping statistics and clean out expired mappings,
  201. // using the above precomputed minimum access times
  202. //
  203. KeAcquireSpinLock(&MappingLock, &Irql);
  204. for (Link = MappingList.Flink; Link != &MappingList; Link = Link->Flink) {
  205. Mapping = CONTAINING_RECORD(Link, NAT_DYNAMIC_MAPPING, Link);
  206. NatUpdateStatisticsMapping(Mapping);
  207. //
  208. // Don't check for expiration if the mapping is marked no-timeout;
  209. // however, if it is detached from its director, then go ahead
  210. // with the expiration-check.
  211. //
  212. if (!NAT_MAPPING_EXPIRED(Mapping) && NAT_MAPPING_NO_TIMEOUT(Mapping) &&
  213. Mapping->Director) {
  214. continue;
  215. }
  216. //
  217. // See if the mapping has expired
  218. //
  219. KeAcquireSpinLockAtDpcLevel(&Mapping->Lock);
  220. Protocol = MAPPING_PROTOCOL(Mapping->SourceKey[NatForwardPath]);
  221. if (!NAT_MAPPING_EXPIRED(Mapping)) {
  222. //
  223. // The mapping is not explicitly marked for expiration;
  224. // see if its last access time is too long ago
  225. //
  226. if (Protocol == NAT_PROTOCOL_TCP) {
  227. if (!NAT_MAPPING_INBOUND(Mapping)) {
  228. if ((Mapping->Flags & NAT_MAPPING_FLAG_FWD_SYN)
  229. && !(Mapping->Flags & NAT_MAPPING_FLAG_REV_SYN)) {
  230. //
  231. // This is an outbound connection for which we've seen
  232. // the outbound SYN (which means we've been tracking
  233. // it from the beginning), but not an inbound SYN. We
  234. // want to use a smaller timeout here so that we may
  235. // reclaim memory for mappings created for connection
  236. // attempts to non-existant servers. (A large number
  237. // of these types of mappings would exist if a machine
  238. // on the private network is performing some sort of a
  239. // network scan; e.g., a machine infected w/ nimda.)
  240. //
  241. if (Mapping->LastAccessTime >= UdpMinAccessTime) {
  242. KeReleaseSpinLockFromDpcLevel(&Mapping->Lock);
  243. continue;
  244. }
  245. }
  246. else if (Mapping->LastAccessTime >= TcpMinAccessTime) {
  247. KeReleaseSpinLockFromDpcLevel(&Mapping->Lock);
  248. continue;
  249. }
  250. } else if (!NAT_MAPPING_TCP_OPEN(Mapping)) {
  251. //
  252. // This is an inbound connection for which we have not
  253. // yet completed the 3-way handshake. We want to use
  254. // a shorter timeout here to reduce memory consumption
  255. // in those cases where someone is performing a synflood
  256. // against us.
  257. //
  258. if (Mapping->LastAccessTime >= UdpMinAccessTime) {
  259. KeReleaseSpinLockFromDpcLevel(&Mapping->Lock);
  260. continue;
  261. }
  262. } else if (Mapping->LastAccessTime >= TcpMinAccessTime) {
  263. KeReleaseSpinLockFromDpcLevel(&Mapping->Lock);
  264. continue;
  265. }
  266. }
  267. else
  268. if (Mapping->LastAccessTime >= UdpMinAccessTime) {
  269. KeReleaseSpinLockFromDpcLevel(&Mapping->Lock);
  270. continue;
  271. }
  272. }
  273. KeReleaseSpinLockFromDpcLevel(&Mapping->Lock);
  274. //
  275. // The mapping has expired; remove it
  276. //
  277. TRACE(
  278. MAPPING, (
  279. "NatTimerRoutine: >Source,Destination=%016I64X:%016I64X\n",
  280. Mapping->SourceKey[NatForwardPath],
  281. Mapping->DestinationKey[NatForwardPath]
  282. ));
  283. TRACE(
  284. MAPPING, (
  285. "NatTimerRoutine: <Source,Destination=%016I64X:%016I64X\n",
  286. Mapping->SourceKey[NatReversePath],
  287. Mapping->DestinationKey[NatReversePath]
  288. ));
  289. Link = Link->Blink;
  290. NatDeleteMapping(Mapping);
  291. }
  292. KeReleaseSpinLockFromDpcLevel(&MappingLock);
  293. //
  294. // Traverse the PPTP-mapping list and remove all expired entries.
  295. //
  296. KeAcquireSpinLockAtDpcLevel(&PptpMappingLock);
  297. for (Link = PptpMappingList[NatInboundDirection].Flink;
  298. Link != &PptpMappingList[NatInboundDirection]; Link = Link->Flink) {
  299. PptpMapping =
  300. CONTAINING_RECORD(
  301. Link, NAT_PPTP_MAPPING, Link[NatInboundDirection]
  302. );
  303. if (!NAT_PPTP_DISCONNECTED(PptpMapping) &&
  304. PptpMapping->LastAccessTime >= PptpMinAccessTime) {
  305. continue;
  306. }
  307. Link = Link->Blink;
  308. RemoveEntryList(&PptpMapping->Link[NatInboundDirection]);
  309. RemoveEntryList(&PptpMapping->Link[NatOutboundDirection]);
  310. TRACE(
  311. MAPPING, ("NatTimerRoutine: Pptp=%016I64X:%016I64X:%d:%d:%d\n",
  312. PptpMapping->PrivateKey,
  313. PptpMapping->PublicKey,
  314. PptpMapping->PrivateCallId,
  315. PptpMapping->PublicCallId,
  316. PptpMapping->RemoteCallId
  317. ));
  318. FREE_PPTP_BLOCK(PptpMapping);
  319. }
  320. KeReleaseSpinLockFromDpcLevel(&PptpMappingLock);
  321. //
  322. // Traverse the ICMP-mapping list and remove each expired entry.
  323. //
  324. KeAcquireSpinLockAtDpcLevel(&IcmpMappingLock);
  325. for (Link = IcmpMappingList[NatInboundDirection].Flink;
  326. Link != &IcmpMappingList[NatInboundDirection]; Link = Link->Flink) {
  327. IcmpMapping =
  328. CONTAINING_RECORD(
  329. Link, NAT_ICMP_MAPPING, Link[NatInboundDirection]
  330. );
  331. if (IcmpMapping->LastAccessTime >= UdpMinAccessTime) { continue; }
  332. Link = Link->Blink;
  333. RemoveEntryList(&IcmpMapping->Link[NatInboundDirection]);
  334. RemoveEntryList(&IcmpMapping->Link[NatOutboundDirection]);
  335. TRACE(
  336. MAPPING,
  337. ("NatTimerRoutine: Icmp=%016I64X:%04X::%016I64X:%04X\n",
  338. IcmpMapping->PrivateKey, IcmpMapping->PrivateId,
  339. IcmpMapping->PublicKey, IcmpMapping->PublicId
  340. ));
  341. FREE_ICMP_BLOCK(IcmpMapping);
  342. }
  343. KeReleaseSpinLockFromDpcLevel(&IcmpMappingLock);
  344. //
  345. // Traverse the interface's IP-mapping list
  346. // and remove each expired entry.
  347. //
  348. KeAcquireSpinLockAtDpcLevel(&IpMappingLock);
  349. for (Link = IpMappingList[NatInboundDirection].Flink;
  350. Link != &IpMappingList[NatInboundDirection]; Link = Link->Flink) {
  351. IpMapping =
  352. CONTAINING_RECORD(
  353. Link, NAT_IP_MAPPING, Link[NatInboundDirection]
  354. );
  355. if (IpMapping->LastAccessTime >= UdpMinAccessTime) { continue; }
  356. Link = Link->Blink;
  357. RemoveEntryList(&IpMapping->Link[NatInboundDirection]);
  358. RemoveEntryList(&IpMapping->Link[NatOutboundDirection]);
  359. TRACE(
  360. MAPPING, (
  361. "NatTimerRoutine: Ip=%d:%016I64X:%016I64X\n",
  362. IpMapping->Protocol, IpMapping->PrivateKey, IpMapping->PublicKey
  363. ));
  364. FREE_IP_BLOCK(IpMapping);
  365. }
  366. KeReleaseSpinLockFromDpcLevel(&IpMappingLock);
  367. //
  368. // Garbage collect all interfaces' structures
  369. //
  370. KeAcquireSpinLockAtDpcLevel(&InterfaceLock);
  371. for (Link = InterfaceList.Flink; Link != &InterfaceList;
  372. Link = Link->Flink) {
  373. Interfacep = CONTAINING_RECORD(Link, NAT_INTERFACE, Link);
  374. //
  375. // Traverse the interface's ticket list
  376. //
  377. KeAcquireSpinLockAtDpcLevel(&Interfacep->Lock);
  378. for (Link = Interfacep->TicketList.Flink;
  379. Link != &Interfacep->TicketList; Link = Link->Flink) {
  380. Ticketp = CONTAINING_RECORD(Link, NAT_TICKET, Link);
  381. if (NAT_TICKET_PERSISTENT(Ticketp)) { continue; }
  382. if (Ticketp->LastAccessTime >= UdpMinAccessTime) { continue; }
  383. Link = Link->Blink;
  384. NatDeleteTicket(Interfacep, Ticketp);
  385. }
  386. KeReleaseSpinLockFromDpcLevel(&Interfacep->Lock);
  387. Link = &Interfacep->Link;
  388. }
  389. KeReleaseSpinLock(&InterfaceLock, Irql);
  390. return;
  391. } // NatTimerRoutine
  392. VOID
  393. NatTriggerTimer(
  394. VOID
  395. )
  396. {
  397. if (!InterlockedCompareExchange(&CleanupDpcPending, TRUE, FALSE)) {
  398. #if DBG
  399. DbgPrint("NatTriggerTimer: scheduling DPC\n");
  400. #endif
  401. KeInsertQueueDpc(&CleanupDpcObject, NULL, NULL);
  402. }
  403. }