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.

1196 lines
31 KiB

  1. /*++
  2. Copyright (c) 1997-2001 Microsoft Corporation
  3. Module Name:
  4. NsIcmp.c
  5. Abstract:
  6. IpSec NAT shim ICMP management
  7. Author:
  8. Jonathan Burstein (jonburs) 11-July-2001
  9. Environment:
  10. Kernel mode
  11. Revision History:
  12. --*/
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. //
  16. // Global Variables
  17. //
  18. LIST_ENTRY NsIcmpList;
  19. KSPIN_LOCK NsIcmpLock;
  20. NPAGED_LOOKASIDE_LIST NsIcmpLookasideList;
  21. //
  22. // Function Prototypes
  23. //
  24. NTSTATUS
  25. NspCreateIcmpEntry(
  26. ULONG64 ul64AddressKey,
  27. USHORT usOriginalIdentifier,
  28. PVOID pvIpSecContext,
  29. BOOLEAN fIdConflicts,
  30. PLIST_ENTRY pInsertionPoint,
  31. PNS_ICMP_ENTRY *ppNewEntry
  32. );
  33. NTSTATUS
  34. FASTCALL
  35. NspHandleInboundIcmpError(
  36. PNS_PACKET_CONTEXT pContext,
  37. PVOID pvIpSecContext
  38. );
  39. NTSTATUS
  40. FASTCALL
  41. NspHandleOutboundIcmpError(
  42. PNS_PACKET_CONTEXT pContext,
  43. PVOID *ppvIpSecContext
  44. );
  45. PNS_ICMP_ENTRY
  46. NspLookupInboundIcmpEntry(
  47. ULONG64 ul64AddressKey,
  48. USHORT usOriginalIdentifier,
  49. PVOID pvIpSecContext,
  50. BOOLEAN *pfIdentifierConflicts,
  51. PLIST_ENTRY *ppInsertionPoint
  52. );
  53. PNS_ICMP_ENTRY
  54. NspLookupOutboundIcmpEntry(
  55. ULONG64 ul64AddressKey,
  56. USHORT usTranslatedIdentifier
  57. );
  58. NTSTATUS
  59. NsInitializeIcmpManagement(
  60. VOID
  61. )
  62. /*++
  63. Routine Description:
  64. This routine is invoked to initialize the ICMP management module.
  65. Arguments:
  66. none.
  67. Return Value:
  68. NTSTATUS.
  69. --*/
  70. {
  71. CALLTRACE(("NsInitializeIcmpManagement\n"));
  72. InitializeListHead(&NsIcmpList);
  73. KeInitializeSpinLock(&NsIcmpLock);
  74. ExInitializeNPagedLookasideList(
  75. &NsIcmpLookasideList,
  76. NULL,
  77. NULL,
  78. 0,
  79. sizeof(NS_ICMP_ENTRY),
  80. NS_TAG_ICMP,
  81. NS_ICMP_LOOKASIDE_DEPTH
  82. );
  83. return STATUS_SUCCESS;
  84. } // NsInitializeIcmpManagement
  85. NTSTATUS
  86. FASTCALL
  87. NspHandleInboundIcmpError(
  88. PNS_PACKET_CONTEXT pContext,
  89. PVOID pvIpSecContext
  90. )
  91. /*++
  92. Routine Description:
  93. This routine is called to process inbound ICMP error messages. Based
  94. on the protocol of the embedded packet it will attempt to find a
  95. matching connection entry (for TCP, UDP, or ICMP) and perform any
  96. necessary translations.
  97. Arguments:
  98. pContext - the context information for the packet.
  99. pvIpSecContext - the IpSec context for this packet; this is considered
  100. an opaque value.
  101. Return Value:
  102. NTSTATUS.
  103. --*/
  104. {
  105. KIRQL Irql;
  106. PNS_CONNECTION_ENTRY pEntry;
  107. PNS_ICMP_ENTRY pIcmpEntry;
  108. ICMP_HEADER UNALIGNED *pIcmpHeader;
  109. UCHAR ucProtocol;
  110. ULONG64 ul64AddressKey;
  111. ULONG ulChecksum;
  112. ULONG ulChecksumDelta;
  113. ULONG ulChecksumDelta2;
  114. ULONG ulPortKey;
  115. ASSERT(NULL != pContext);
  116. //
  117. // Make sure that the buffer is large enough to contain the
  118. // encapsulated packet.
  119. //
  120. if (pContext->ulProtocolHeaderLength < sizeof(ICMP_HEADER))
  121. {
  122. return STATUS_INVALID_PARAMETER;
  123. }
  124. //
  125. // If the embedded header is not TCP, UDP, or ICMP exit quickly,
  126. // as we have nothing to do.
  127. //
  128. pIcmpHeader = pContext->pIcmpHeader;
  129. ucProtocol = pIcmpHeader->EncapsulatedIpHeader.Protocol;
  130. if (NS_PROTOCOL_TCP != ucProtocol
  131. && NS_PROTOCOL_UDP != ucProtocol
  132. && NS_PROTOCOL_ICMP != ucProtocol
  133. )
  134. {
  135. return STATUS_SUCCESS;
  136. }
  137. //
  138. // See if the embedded packet belongs to a known conection. Notice that
  139. // the order of the addresses here -- since the embedded packet is one
  140. // that we sent, the source address is local and the destination address
  141. // is remote.
  142. //
  143. MAKE_ADDRESS_KEY(
  144. ul64AddressKey,
  145. pIcmpHeader->EncapsulatedIpHeader.SourceAddress,
  146. pIcmpHeader->EncapsulatedIpHeader.DestinationAddress
  147. );
  148. if (NS_PROTOCOL_ICMP == ucProtocol)
  149. {
  150. KeAcquireSpinLock(&NsIcmpLock, &Irql);
  151. pIcmpEntry =
  152. NspLookupInboundIcmpEntry(
  153. ul64AddressKey,
  154. pIcmpHeader->EncapsulatedIcmpHeader.Identifier,
  155. pvIpSecContext,
  156. NULL,
  157. NULL
  158. );
  159. if (NULL != pIcmpEntry)
  160. {
  161. KeQueryTickCount((PLARGE_INTEGER)&pIcmpEntry->l64LastAccessTime);
  162. if (pIcmpEntry->usTranslatedId != pIcmpEntry->usOriginalId)
  163. {
  164. //
  165. // We found an ICMP entry for the embedded packet that
  166. // has a translated ID. This means that we need to:
  167. //
  168. // 1) Change the ID in the embedded packet.
  169. // 2) Update the ICMP checksum of the embedded packet.
  170. // 3) Update the ICMP checksum of the original packet, based
  171. // on the previous changes.
  172. //
  173. pIcmpHeader->EncapsulatedIcmpHeader.Identifier =
  174. pIcmpEntry->usTranslatedId;
  175. ulChecksumDelta = 0;
  176. CHECKSUM_LONG(ulChecksumDelta, ~pIcmpEntry->usOriginalId);
  177. CHECKSUM_LONG(ulChecksumDelta, pIcmpEntry->usTranslatedId);
  178. ulChecksumDelta2 = ulChecksumDelta;
  179. CHECKSUM_LONG(
  180. ulChecksumDelta2,
  181. ~pIcmpHeader->EncapsulatedIcmpHeader.Checksum
  182. );
  183. CHECKSUM_UPDATE(pIcmpHeader->EncapsulatedIcmpHeader.Checksum);
  184. CHECKSUM_LONG(
  185. ulChecksumDelta2,
  186. pIcmpHeader->EncapsulatedIcmpHeader.Checksum
  187. );
  188. ulChecksumDelta = ulChecksumDelta2;
  189. CHECKSUM_UPDATE(pIcmpHeader->Checksum);
  190. }
  191. }
  192. KeReleaseSpinLock(&NsIcmpLock, Irql);
  193. }
  194. else
  195. {
  196. MAKE_PORT_KEY(
  197. ulPortKey,
  198. pIcmpHeader->EncapsulatedUdpHeader.SourcePort,
  199. pIcmpHeader->EncapsulatedUdpHeader.DestinationPort
  200. );
  201. KeAcquireSpinLock(&NsConnectionLock, &Irql);
  202. pEntry =
  203. NsLookupInboundConnectionEntry(
  204. ul64AddressKey,
  205. ulPortKey,
  206. ucProtocol,
  207. pvIpSecContext,
  208. NULL,
  209. NULL
  210. );
  211. if (NULL != pEntry
  212. && pEntry->ulPortKey[NsInboundDirection]
  213. != pEntry->ulPortKey[NsOutboundDirection])
  214. {
  215. //
  216. // We found a connection entry that contains a translated
  217. // port. This means we need to:
  218. //
  219. // 1) Change the remote (destination) port in the
  220. // embedded packet.
  221. // 2) Update the checksum of the embedded packet, if it's
  222. // UDP. (An embedded TCP packet is not long enough to
  223. // contain the checksum.)
  224. // 3) Update the ICMP checksum of the original packet, based
  225. // on the previous changes.
  226. //
  227. pIcmpHeader->EncapsulatedUdpHeader.DestinationPort =
  228. CONNECTION_REMOTE_PORT(pEntry->ulPortKey[NsOutboundDirection]);
  229. ulChecksumDelta = 0;
  230. CHECKSUM_LONG(
  231. ulChecksumDelta,
  232. ~CONNECTION_REMOTE_PORT(pEntry->ulPortKey[NsInboundDirection])
  233. );
  234. CHECKSUM_LONG(
  235. ulChecksumDelta,
  236. CONNECTION_REMOTE_PORT(pEntry->ulPortKey[NsOutboundDirection])
  237. );
  238. if (NS_PROTOCOL_UDP == ucProtocol)
  239. {
  240. ulChecksumDelta2 = ulChecksumDelta;
  241. CHECKSUM_LONG(
  242. ulChecksumDelta2,
  243. ~pIcmpHeader->EncapsulatedUdpHeader.Checksum
  244. );
  245. CHECKSUM_UPDATE(pIcmpHeader->EncapsulatedUdpHeader.Checksum);
  246. CHECKSUM_LONG(
  247. ulChecksumDelta2,
  248. pIcmpHeader->EncapsulatedUdpHeader.Checksum
  249. );
  250. ulChecksumDelta = ulChecksumDelta2;
  251. }
  252. CHECKSUM_UPDATE(pIcmpHeader->Checksum);
  253. }
  254. KeReleaseSpinLock(&NsConnectionLock, Irql);
  255. }
  256. return STATUS_SUCCESS;
  257. } // NspHandleInboundIcmpError
  258. NTSTATUS
  259. FASTCALL
  260. NspHandleOutboundIcmpError(
  261. PNS_PACKET_CONTEXT pContext,
  262. PVOID *ppvIpSecContext
  263. )
  264. /*++
  265. Routine Description:
  266. This routine is called to process outbound ICMP error messages. Based
  267. on the protocol of the embedded packet it will attempt to find a
  268. matching connection entry (for TCP, UDP, or ICMP), obtain the IpSec
  269. context for the embedded packet, and perform any necessary translations.
  270. Arguments:
  271. pContext - the context information for the packet.
  272. ppvIpSecContext - receives the IpSec context for this packet, if any;
  273. receives NULL if no context exists.
  274. Return Value:
  275. NTSTATUS.
  276. --*/
  277. {
  278. KIRQL Irql;
  279. PNS_CONNECTION_ENTRY pEntry;
  280. PNS_ICMP_ENTRY pIcmpEntry;
  281. ICMP_HEADER UNALIGNED *pIcmpHeader;
  282. UCHAR ucProtocol;
  283. ULONG64 ul64AddressKey;
  284. ULONG ulChecksum;
  285. ULONG ulChecksumDelta;
  286. ULONG ulChecksumDelta2;
  287. ULONG ulPortKey;
  288. ASSERT(NULL != pContext);
  289. ASSERT(NULL != ppvIpSecContext);
  290. //
  291. // Make sure that the buffer is large enough to contain the
  292. // encapsulated packet.
  293. //
  294. if (pContext->ulProtocolHeaderLength < sizeof(ICMP_HEADER))
  295. {
  296. return STATUS_INVALID_PARAMETER;
  297. }
  298. //
  299. // If the embedded header is not TCP, UDP, or ICMP exit quickly,
  300. // as we have nothing to do.
  301. //
  302. pIcmpHeader = pContext->pIcmpHeader;
  303. ucProtocol = pIcmpHeader->EncapsulatedIpHeader.Protocol;
  304. if (NS_PROTOCOL_TCP != ucProtocol
  305. && NS_PROTOCOL_UDP != ucProtocol
  306. && NS_PROTOCOL_ICMP != ucProtocol
  307. )
  308. {
  309. return STATUS_SUCCESS;
  310. }
  311. //
  312. // See if the embedded packet belongs to a known conection. Notice that
  313. // the order of the addresses here -- since the embedded packet is one
  314. // that we received, the source address is remote and the destination
  315. // address is local.
  316. //
  317. MAKE_ADDRESS_KEY(
  318. ul64AddressKey,
  319. pIcmpHeader->EncapsulatedIpHeader.DestinationAddress,
  320. pIcmpHeader->EncapsulatedIpHeader.SourceAddress
  321. );
  322. if (NS_PROTOCOL_ICMP == ucProtocol)
  323. {
  324. KeAcquireSpinLock(&NsIcmpLock, &Irql);
  325. pIcmpEntry =
  326. NspLookupOutboundIcmpEntry(
  327. ul64AddressKey,
  328. pIcmpHeader->EncapsulatedIcmpHeader.Identifier
  329. );
  330. if (NULL != pIcmpEntry)
  331. {
  332. *ppvIpSecContext = pIcmpEntry->pvIpSecContext;
  333. KeQueryTickCount((PLARGE_INTEGER)&pIcmpEntry->l64LastAccessTime);
  334. if (pIcmpEntry->usTranslatedId != pIcmpEntry->usOriginalId)
  335. {
  336. //
  337. // We found an ICMP entry for the embedded packet that
  338. // has a translated ID. This means that we need to:
  339. //
  340. // 1) Change the ID in the embedded packet.
  341. // 2) Update the ICMP checksum of the embedded packet.
  342. // 3) Update the ICMP checksum of the original packet, based
  343. // on the previous changes.
  344. //
  345. pIcmpHeader->EncapsulatedIcmpHeader.Identifier =
  346. pIcmpEntry->usOriginalId;
  347. ulChecksumDelta = 0;
  348. CHECKSUM_LONG(ulChecksumDelta, ~pIcmpEntry->usTranslatedId);
  349. CHECKSUM_LONG(ulChecksumDelta, pIcmpEntry->usOriginalId);
  350. ulChecksumDelta2 = ulChecksumDelta;
  351. CHECKSUM_LONG(
  352. ulChecksumDelta2,
  353. ~pIcmpHeader->EncapsulatedIcmpHeader.Checksum
  354. );
  355. CHECKSUM_UPDATE(pIcmpHeader->EncapsulatedIcmpHeader.Checksum);
  356. CHECKSUM_LONG(
  357. ulChecksumDelta2,
  358. pIcmpHeader->EncapsulatedIcmpHeader.Checksum
  359. );
  360. ulChecksumDelta = ulChecksumDelta2;
  361. CHECKSUM_UPDATE(pIcmpHeader->Checksum);
  362. }
  363. }
  364. KeReleaseSpinLock(&NsIcmpLock, Irql);
  365. }
  366. else
  367. {
  368. MAKE_PORT_KEY(
  369. ulPortKey,
  370. pIcmpHeader->EncapsulatedUdpHeader.DestinationPort,
  371. pIcmpHeader->EncapsulatedUdpHeader.SourcePort
  372. );
  373. KeAcquireSpinLock(&NsConnectionLock, &Irql);
  374. pEntry =
  375. NsLookupOutboundConnectionEntry(
  376. ul64AddressKey,
  377. ulPortKey,
  378. ucProtocol,
  379. NULL
  380. );
  381. if (NULL != pEntry)
  382. {
  383. *ppvIpSecContext = pEntry->pvIpSecContext;
  384. if (pEntry->ulPortKey[NsInboundDirection]
  385. != pEntry->ulPortKey[NsOutboundDirection])
  386. {
  387. //
  388. // We found a connection entry that contains a translated
  389. // port. This means we need to:
  390. //
  391. // 1) Change the remote (source) port in the
  392. // embedded packet.
  393. // 2) Update the checksum of the embedded packet, if it's
  394. // UDP. (An embedded TCP packet is not long enough to
  395. // contain the checksum.)
  396. // 3) Update the ICMP checksum of the original packet, based
  397. // on the previous changes.
  398. //
  399. pIcmpHeader->EncapsulatedUdpHeader.SourcePort =
  400. CONNECTION_REMOTE_PORT(pEntry->ulPortKey[NsInboundDirection]);
  401. ulChecksumDelta = 0;
  402. CHECKSUM_LONG(
  403. ulChecksumDelta,
  404. ~CONNECTION_REMOTE_PORT(pEntry->ulPortKey[NsOutboundDirection])
  405. );
  406. CHECKSUM_LONG(
  407. ulChecksumDelta,
  408. CONNECTION_REMOTE_PORT(pEntry->ulPortKey[NsInboundDirection])
  409. );
  410. if (NS_PROTOCOL_UDP == ucProtocol)
  411. {
  412. ulChecksumDelta2 = ulChecksumDelta;
  413. CHECKSUM_LONG(
  414. ulChecksumDelta2,
  415. ~pIcmpHeader->EncapsulatedUdpHeader.Checksum
  416. );
  417. CHECKSUM_UPDATE(pIcmpHeader->EncapsulatedUdpHeader.Checksum);
  418. CHECKSUM_LONG(
  419. ulChecksumDelta2,
  420. pIcmpHeader->EncapsulatedUdpHeader.Checksum
  421. );
  422. ulChecksumDelta = ulChecksumDelta2;
  423. }
  424. CHECKSUM_UPDATE(pIcmpHeader->Checksum);
  425. }
  426. }
  427. KeReleaseSpinLock(&NsConnectionLock, Irql);
  428. }
  429. return STATUS_SUCCESS;
  430. } // NspHandleOutboundIcmpError
  431. NTSTATUS
  432. NspCreateIcmpEntry(
  433. ULONG64 ul64AddressKey,
  434. USHORT usOriginalIdentifier,
  435. PVOID pvIpSecContext,
  436. BOOLEAN fIdConflicts,
  437. PLIST_ENTRY pInsertionPoint,
  438. PNS_ICMP_ENTRY *ppNewEntry
  439. )
  440. /*++
  441. Routine Description:
  442. Creates an ICMP entry (for request / response message types). If
  443. necessary this routine will allocate a new identifier.
  444. Arguments:
  445. ul64AddressKey - the addressing information for the entry
  446. usOriginalIdentifier - the original ICMP identifier for the entry
  447. pvIpSecContext - the IpSec context for the entry
  448. fIdConflicts - TRUE if the original identifier is known to conflict
  449. with an existing entry on the inbound path
  450. pInsertionPoint - the insertion point for the new entry
  451. ppNewEntry - receives the newly created entry on success
  452. Return Value:
  453. NTSTATUS
  454. Environment:
  455. Invoked with 'NsIcmpLock' held by the caller.
  456. --*/
  457. {
  458. PNS_ICMP_ENTRY pEntry;
  459. NTSTATUS Status = STATUS_UNSUCCESSFUL;
  460. USHORT usTranslatedId;
  461. TRACE(ICMP, ("NspCreateIcmpEntry\n"));
  462. ASSERT(NULL != pInsertionPoint);
  463. ASSERT(NULL != ppNewEntry);
  464. //
  465. // Determine what translated ID should be used for this
  466. // entry
  467. //
  468. if (fIdConflicts)
  469. {
  470. usTranslatedId = (USHORT) -1;
  471. }
  472. else
  473. {
  474. usTranslatedId = usOriginalIdentifier;
  475. }
  476. do
  477. {
  478. if (NULL == NspLookupOutboundIcmpEntry(ul64AddressKey, usTranslatedId))
  479. {
  480. //
  481. // This identifier does not conflict.
  482. //
  483. Status = STATUS_SUCCESS;
  484. break;
  485. }
  486. if (fIdConflicts)
  487. {
  488. usTranslatedId -= 1;
  489. }
  490. else
  491. {
  492. fIdConflicts = TRUE;
  493. usTranslatedId = (USHORT) -1;
  494. }
  495. }
  496. while (usTranslatedId > 0);
  497. if (STATUS_SUCCESS == Status)
  498. {
  499. //
  500. // Allocate and initialize the new entry
  501. //
  502. pEntry = ALLOCATE_ICMP_BLOCK();
  503. if (NULL != pEntry)
  504. {
  505. RtlZeroMemory(pEntry, sizeof(*pEntry));
  506. pEntry->ul64AddressKey = ul64AddressKey;
  507. pEntry->usOriginalId = usOriginalIdentifier;
  508. pEntry->usTranslatedId = usTranslatedId;
  509. pEntry->pvIpSecContext = pvIpSecContext;
  510. InsertTailList(pInsertionPoint, &pEntry->Link);
  511. *ppNewEntry = pEntry;
  512. }
  513. else
  514. {
  515. ERROR(("NspCreateIcmpEntry: Allocation Failed\n"));
  516. Status = STATUS_NO_MEMORY;
  517. }
  518. }
  519. return Status;
  520. } // NspCreateIcmpEntry
  521. PNS_ICMP_ENTRY
  522. NspLookupInboundIcmpEntry(
  523. ULONG64 ul64AddressKey,
  524. USHORT usOriginalIdentifier,
  525. PVOID pvIpSecContext,
  526. BOOLEAN *pfIdentifierConflicts,
  527. PLIST_ENTRY *ppInsertionPoint
  528. )
  529. /*++
  530. Routine Description:
  531. Called to lookup an inbound ICMP entry.
  532. Arguments:
  533. ul64AddressKey - the addressing information for the entry
  534. usOriginalIdentifier - the original ICMP identifier for the entry
  535. pvIpSecContext - the IpSec context for the entry
  536. pfIdentifierConflicts - on failure, receives a boolean the indicates why
  537. the lookup failed: TRUE if the lookup failed because there is
  538. an identical entry w/ different IpSec context, FALSE
  539. otherwise. (optional)
  540. ppInsertionPoint - receives the insertion point if not found (optional)
  541. Return Value:
  542. PNS_ICMP_ENTRY - a pointer to the connection entry, if found, or
  543. NULL otherwise.
  544. Environment:
  545. Invoked with 'NsIcmpLock' held by the caller.
  546. --*/
  547. {
  548. PNS_ICMP_ENTRY pEntry;
  549. PLIST_ENTRY pLink;
  550. if (pfIdentifierConflicts)
  551. {
  552. *pfIdentifierConflicts = FALSE;
  553. }
  554. for (pLink = NsIcmpList.Flink; pLink != &NsIcmpList; pLink = pLink->Flink)
  555. {
  556. pEntry = CONTAINING_RECORD(pLink, NS_ICMP_ENTRY, Link);
  557. //
  558. // For inbound entries the search order is:
  559. // 1) address key
  560. // 2) original identifier
  561. // 3) IpSec context
  562. //
  563. if (ul64AddressKey > pEntry->ul64AddressKey)
  564. {
  565. continue;
  566. }
  567. else if (ul64AddressKey < pEntry->ul64AddressKey)
  568. {
  569. break;
  570. }
  571. else if (usOriginalIdentifier > pEntry->usOriginalId)
  572. {
  573. continue;
  574. }
  575. else if (usOriginalIdentifier < pEntry->usOriginalId)
  576. {
  577. break;
  578. }
  579. else if (pvIpSecContext > pEntry->pvIpSecContext)
  580. {
  581. //
  582. // This entry matches everything requested except
  583. // for the IpSec context. Inform the caller of this
  584. // fact (if desired).
  585. //
  586. if (pfIdentifierConflicts)
  587. {
  588. *pfIdentifierConflicts = TRUE;
  589. }
  590. continue;
  591. }
  592. else if (pvIpSecContext < pEntry->pvIpSecContext)
  593. {
  594. //
  595. // This entry matches everything requested except
  596. // for the IpSec context. Inform the caller of this
  597. // fact (if desired).
  598. //
  599. if (pfIdentifierConflicts)
  600. {
  601. *pfIdentifierConflicts = TRUE;
  602. }
  603. break;
  604. }
  605. //
  606. // This is the requested entry.
  607. //
  608. return pEntry;
  609. }
  610. //
  611. // Entry not found -- set insertion point if so requested.
  612. //
  613. if (ppInsertionPoint)
  614. {
  615. *ppInsertionPoint = pLink;
  616. }
  617. return NULL;
  618. } // NspLookupInboundIcmpEntry
  619. PNS_ICMP_ENTRY
  620. NspLookupOutboundIcmpEntry(
  621. ULONG64 ul64AddressKey,
  622. USHORT usTranslatedIdentifier
  623. )
  624. /*++
  625. Routine Description:
  626. Called to lookup an outbound ICMP entry.
  627. Arguments:
  628. ul64AddressKey - the addressing information for the entry
  629. usTranslatedIdentifier - the translated ICMP identifier for the entry
  630. Return Value:
  631. PNS_ICMP_ENTRY - a pointer to the entry, if found, or NULL otherwise.
  632. Environment:
  633. Invoked with 'NsIcmpLock' held by the caller.
  634. --*/
  635. {
  636. PNS_ICMP_ENTRY pEntry;
  637. PLIST_ENTRY pLink;
  638. for (pLink = NsIcmpList.Flink; pLink != &NsIcmpList; pLink = pLink->Flink)
  639. {
  640. pEntry = CONTAINING_RECORD(pLink, NS_ICMP_ENTRY, Link);
  641. //
  642. // When searching for an outbound entry, we can depend on the
  643. // ordering of address keys. However, we cannot depend on the
  644. // order of the translated identifiers, so we have to perform
  645. // an exhaustive search of all entries with the proper
  646. // address key.
  647. //
  648. if (ul64AddressKey > pEntry->ul64AddressKey)
  649. {
  650. continue;
  651. }
  652. else if (ul64AddressKey < pEntry->ul64AddressKey)
  653. {
  654. break;
  655. }
  656. else if (usTranslatedIdentifier == pEntry->usTranslatedId)
  657. {
  658. //
  659. // This is the requested entry.
  660. //
  661. return pEntry;
  662. }
  663. }
  664. //
  665. // Entry not found.
  666. //
  667. return NULL;
  668. } // NspLookupOutboundIcmpEntry
  669. NTSTATUS
  670. FASTCALL
  671. NsProcessIncomingIcmpPacket(
  672. PNS_PACKET_CONTEXT pContext,
  673. PVOID pvIpSecContext
  674. )
  675. /*++
  676. Routine Description:
  677. This routine is invoked by IpSec for each incoming ICMP packet.
  678. Arguments:
  679. pContext - the context information for the packet.
  680. pvIpSecContext - the IpSec context for this packet; this is considered
  681. an opaque value.
  682. Return Value:
  683. NTSTATUS.
  684. --*/
  685. {
  686. BOOLEAN fIdConflicts;
  687. KIRQL Irql;
  688. PNS_ICMP_ENTRY pIcmpEntry;
  689. PLIST_ENTRY pInsertionPoint;
  690. NTSTATUS Status = STATUS_SUCCESS;
  691. ULONG64 ul64AddressKey;
  692. ULONG ulChecksum;
  693. ULONG ulChecksumDelta;
  694. ASSERT(NULL != pContext);
  695. TRACE(
  696. ICMP,
  697. ("NsProcessIncomingIcmpPacket: %d.%d.%d.%d -> %d.%d.%d.%d : %d, %d : %d\n",
  698. ADDRESS_BYTES(pContext->ulSourceAddress),
  699. ADDRESS_BYTES(pContext->ulDestinationAddress),
  700. pContext->pIcmpHeader->Type,
  701. pContext->pIcmpHeader->Code,
  702. pvIpSecContext
  703. ));
  704. //
  705. // Branch to proper behavior based on ICMP Type
  706. //
  707. switch (pContext->pIcmpHeader->Type)
  708. {
  709. case ICMP_ROUTER_REPLY:
  710. case ICMP_MASK_REPLY:
  711. case ICMP_ECHO_REPLY:
  712. case ICMP_TIMESTAMP_REPLY:
  713. {
  714. //
  715. // No action is needed for inbound replies.
  716. //
  717. break;
  718. }
  719. case ICMP_ROUTER_REQUEST:
  720. case ICMP_MASK_REQUEST:
  721. case ICMP_ECHO_REQUEST:
  722. case ICMP_TIMESTAMP_REQUEST:
  723. {
  724. //
  725. // See if we have an ICMP entry that matches this packet.
  726. //
  727. MAKE_ADDRESS_KEY(
  728. ul64AddressKey,
  729. pContext->ulDestinationAddress,
  730. pContext->ulSourceAddress
  731. );
  732. KeAcquireSpinLock(&NsIcmpLock, &Irql);
  733. pIcmpEntry =
  734. NspLookupInboundIcmpEntry(
  735. ul64AddressKey,
  736. pContext->pIcmpHeader->Identifier,
  737. pvIpSecContext,
  738. &fIdConflicts,
  739. &pInsertionPoint
  740. );
  741. if (NULL == pIcmpEntry)
  742. {
  743. //
  744. // No entry was found; attempt to create a new
  745. // one. (The creation function will allocate
  746. // a new ID, if necessary.)
  747. //
  748. Status =
  749. NspCreateIcmpEntry(
  750. ul64AddressKey,
  751. pContext->pIcmpHeader->Identifier,
  752. pvIpSecContext,
  753. fIdConflicts,
  754. pInsertionPoint,
  755. &pIcmpEntry
  756. );
  757. }
  758. if (STATUS_SUCCESS == Status)
  759. {
  760. ASSERT(NULL != pIcmpEntry);
  761. KeQueryTickCount((PLARGE_INTEGER)&pIcmpEntry->l64LastAccessTime);
  762. if (pIcmpEntry->usTranslatedId != pIcmpEntry->usOriginalId)
  763. {
  764. //
  765. // Need to translate the ICMP ID for this packet, and
  766. // adjust the checksum accordingly.
  767. //
  768. pContext->pIcmpHeader->Identifier =
  769. pIcmpEntry->usTranslatedId;
  770. ulChecksumDelta = 0;
  771. CHECKSUM_LONG(ulChecksumDelta, ~pIcmpEntry->usOriginalId);
  772. CHECKSUM_LONG(ulChecksumDelta, pIcmpEntry->usTranslatedId);
  773. CHECKSUM_UPDATE(pContext->pIcmpHeader->Checksum);
  774. }
  775. }
  776. KeReleaseSpinLock(&NsIcmpLock, Irql);
  777. break;
  778. }
  779. case ICMP_TIME_EXCEED:
  780. case ICMP_PARAM_PROBLEM:
  781. case ICMP_DEST_UNREACH:
  782. case ICMP_SOURCE_QUENCH:
  783. {
  784. Status = NspHandleInboundIcmpError(pContext, pvIpSecContext);
  785. break;
  786. }
  787. default:
  788. {
  789. break;
  790. }
  791. }
  792. return Status;
  793. } // NsProcessIncomingIcmpPacket
  794. NTSTATUS
  795. FASTCALL
  796. NsProcessOutgoingIcmpPacket(
  797. PNS_PACKET_CONTEXT pContext,
  798. PVOID *ppvIpSecContext
  799. )
  800. /*++
  801. Routine Description:
  802. This routine is invoked by IpSec for each outgoing ICMP packet.
  803. Arguments:
  804. pContext - the context information for the packet.
  805. ppvIpSecContext - receives the IpSec context for this packet, if any;
  806. receives NULL if no context exists.
  807. Return Value:
  808. NTSTATUS.
  809. --*/
  810. {
  811. KIRQL Irql;
  812. PNS_ICMP_ENTRY pIcmpEntry;
  813. NTSTATUS Status = STATUS_SUCCESS;
  814. ULONG64 ul64AddressKey;
  815. ULONG ulChecksum;
  816. ULONG ulChecksumDelta;
  817. ASSERT(NULL != pContext);
  818. ASSERT(NULL != ppvIpSecContext);
  819. TRACE(
  820. ICMP,
  821. ("NsProcessOutgoingIcmpPacket: %d.%d.%d.%d -> %d.%d.%d.%d : %d, %d\n",
  822. ADDRESS_BYTES(pContext->ulSourceAddress),
  823. ADDRESS_BYTES(pContext->ulDestinationAddress),
  824. pContext->pIcmpHeader->Type,
  825. pContext->pIcmpHeader->Code
  826. ));
  827. //
  828. // Set context to the default value
  829. //
  830. *ppvIpSecContext = NULL;
  831. //
  832. // Branch to proper behavior based on ICMP Type
  833. //
  834. switch (pContext->pIcmpHeader->Type)
  835. {
  836. case ICMP_ROUTER_REPLY:
  837. case ICMP_MASK_REPLY:
  838. case ICMP_ECHO_REPLY:
  839. case ICMP_TIMESTAMP_REPLY:
  840. {
  841. //
  842. // See if we have an ICMP entry that matches this packet.
  843. //
  844. MAKE_ADDRESS_KEY(
  845. ul64AddressKey,
  846. pContext->ulSourceAddress,
  847. pContext->ulDestinationAddress
  848. );
  849. KeAcquireSpinLock(&NsIcmpLock, &Irql);
  850. pIcmpEntry =
  851. NspLookupOutboundIcmpEntry(
  852. ul64AddressKey,
  853. pContext->pIcmpHeader->Identifier
  854. );
  855. if (NULL != pIcmpEntry)
  856. {
  857. *ppvIpSecContext = pIcmpEntry->pvIpSecContext;
  858. KeQueryTickCount((PLARGE_INTEGER)&pIcmpEntry->l64LastAccessTime);
  859. if (pIcmpEntry->usTranslatedId != pIcmpEntry->usOriginalId)
  860. {
  861. //
  862. // Need to translate the ICMP ID for this packet, and
  863. // adjust the checksum accordingly.
  864. //
  865. pContext->pIcmpHeader->Identifier =
  866. pIcmpEntry->usOriginalId;
  867. ulChecksumDelta = 0;
  868. CHECKSUM_LONG(ulChecksumDelta, ~pIcmpEntry->usTranslatedId);
  869. CHECKSUM_LONG(ulChecksumDelta, pIcmpEntry->usOriginalId);
  870. CHECKSUM_UPDATE(pContext->pIcmpHeader->Checksum);
  871. }
  872. }
  873. KeReleaseSpinLock(&NsIcmpLock, Irql);
  874. break;
  875. }
  876. case ICMP_ROUTER_REQUEST:
  877. case ICMP_MASK_REQUEST:
  878. case ICMP_ECHO_REQUEST:
  879. case ICMP_TIMESTAMP_REQUEST:
  880. {
  881. //
  882. // No action is needed for outgoing requests.
  883. //
  884. break;
  885. }
  886. case ICMP_TIME_EXCEED:
  887. case ICMP_PARAM_PROBLEM:
  888. case ICMP_DEST_UNREACH:
  889. case ICMP_SOURCE_QUENCH:
  890. {
  891. Status = NspHandleOutboundIcmpError(pContext, ppvIpSecContext);
  892. break;
  893. }
  894. default:
  895. {
  896. break;
  897. }
  898. }
  899. return Status;
  900. } // NsProcessOutgoingIcmpPacket
  901. VOID
  902. NsShutdownIcmpManagement(
  903. VOID
  904. )
  905. /*++
  906. Routine Description:
  907. This routine is invoked to cleanup the ICMP management module.
  908. Arguments:
  909. none.
  910. Return Value:
  911. none.
  912. --*/
  913. {
  914. KIRQL Irql;
  915. PNS_ICMP_ENTRY pEntry;
  916. CALLTRACE(("NsShutdownIcmpManagement\n"));
  917. KeAcquireSpinLock(&NsIcmpLock, &Irql);
  918. while (!IsListEmpty(&NsIcmpList))
  919. {
  920. pEntry =
  921. CONTAINING_RECORD(
  922. RemoveHeadList(&NsIcmpList),
  923. NS_ICMP_ENTRY,
  924. Link
  925. );
  926. FREE_ICMP_BLOCK(pEntry);
  927. }
  928. KeReleaseSpinLock(&NsIcmpLock, Irql);
  929. ExDeleteNPagedLookasideList(&NsIcmpLookasideList);
  930. } // NsShutdownIcmpManagement