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.

2060 lines
65 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. icmp.c
  5. Abstract:
  6. This module contains the code for manipulating ICMP request/reply mappings.
  7. When the NAT decides to translate an ICMP request, it creates a mapping
  8. and places it on the interface's ICMP-mapping list, so that when the reply
  9. to the request arrives, it can be directed to the appropriate client.
  10. Author:
  11. Abolade Gbadegesin (t-abolag) 31-July-1997
  12. Revision History:
  13. --*/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. //
  17. // GLOBAL DATA DECLARATIONS
  18. //
  19. NPAGED_LOOKASIDE_LIST IcmpLookasideList;
  20. LIST_ENTRY IcmpMappingList[NatMaximumDirection];
  21. KSPIN_LOCK IcmpMappingLock;
  22. //
  23. // FORWARD DECLARATIONS
  24. //
  25. FORWARD_ACTION
  26. NatpFirewallIcmp(
  27. PNAT_INTERFACE Interfacep,
  28. IP_NAT_DIRECTION Direction,
  29. PNAT_XLATE_CONTEXT Contextp
  30. );
  31. BOOLEAN
  32. NatTranslateIcmpEncapsulatedRequest(
  33. PNAT_INTERFACE Interfacep OPTIONAL,
  34. IP_NAT_DIRECTION Direction,
  35. PIP_HEADER IpHeader,
  36. PICMP_HEADER IcmpHeader,
  37. PIP_HEADER EncapsulatedIpHeader,
  38. struct _ENCAPSULATED_ICMP_HEADER* EncapsulatedIcmpHeader,
  39. BOOLEAN ChecksumOffloaded
  40. );
  41. BOOLEAN
  42. NatTranslateIcmpRequest(
  43. PNAT_INTERFACE Interfacep OPTIONAL,
  44. IP_NAT_DIRECTION Direction,
  45. PNAT_XLATE_CONTEXT Contextp,
  46. BOOLEAN ReplyCode,
  47. BOOLEAN ChecksumOffloaded
  48. );
  49. BOOLEAN
  50. NatTranslateEncapsulatedRequest(
  51. PNAT_INTERFACE Interfacep OPTIONAL,
  52. IP_NAT_DIRECTION Direction,
  53. PIP_HEADER IpHeader,
  54. PICMP_HEADER IcmpHeader,
  55. PIP_HEADER EncapsulatedIpHeader,
  56. struct _ENCAPSULATED_UDP_HEADER* EncapsulatedHeader,
  57. BOOLEAN ChecksumOffloaded
  58. );
  59. NTSTATUS
  60. NatCreateIcmpMapping(
  61. PNAT_INTERFACE Interfacep,
  62. ULONG RemoteAddress,
  63. ULONG PrivateAddress,
  64. ULONG PublicAddress,
  65. PUSHORT PrivateId,
  66. PUSHORT PublicId,
  67. PLIST_ENTRY InboundInsertionPoint,
  68. PLIST_ENTRY OutboundInsertionPoint,
  69. PNAT_ICMP_MAPPING* MappingCreated
  70. )
  71. /*++
  72. Routine Description:
  73. Called to create, initialize, and insert an ICMP mapping in an interface's
  74. list of ICMP mappings.
  75. For outbound ICMP requests, we allocate a unique 'PublicId' for the mapping,
  76. and for inbound requests, we allocate a unique 'PrivateId' for the mapping.
  77. Arguments:
  78. Interfacep - the interface for the new mapping
  79. RemoteAddress - the address of the remote endpoint
  80. PrivateAddress - the address of the machine on the private network
  81. PublicAddress - the publicly-visible address to replace 'PrivateAddress';
  82. in case this is 0, an address is chosen in this routine.
  83. PrivateId - the private-endpoint's identifier for the ICMP message,
  84. or NULL if an identifier should be chosen by this routine.
  85. PublicId - the public-endpoint's identifier for the ICMP message,
  86. or NULL if an identifier should be chosen by this routine.
  87. InboundInsertionPoint - the entry preceding the new mapping in the list
  88. sorted for inbound searching
  89. OutboundInsertionPoint - the entry preceding the new mapping in the list
  90. sorted for outbound searching
  91. MappingCreated - receives the mapping created
  92. Return Value:
  93. NTSTATUS - indicates success/failure
  94. Environment:
  95. Invoked with 'IcmpMappingLock' held by the caller.
  96. --*/
  97. {
  98. USHORT Id;
  99. PLIST_ENTRY Link;
  100. PNAT_ICMP_MAPPING Mapping;
  101. PNAT_ICMP_MAPPING DuplicateMapping;
  102. NTSTATUS status;
  103. PNAT_ICMP_MAPPING Temp;
  104. PNAT_USED_ADDRESS UsedAddress;
  105. CALLTRACE(("NatCreateIcmpMapping\n"));
  106. //
  107. // Allocate a new mapping
  108. //
  109. Mapping = ALLOCATE_ICMP_BLOCK();
  110. if (!Mapping) {
  111. ERROR(("NatCreateIcmpMapping: allocation failed\n"));
  112. return STATUS_NO_MEMORY;
  113. }
  114. //
  115. // Initialize the mapping
  116. //
  117. Mapping->PrivateKey = MAKE_ICMP_KEY(RemoteAddress, PrivateAddress);
  118. //
  119. // See if the public address is specified, and if not, acquire an address
  120. //
  121. if (PublicAddress) {
  122. Mapping->PublicKey = MAKE_ICMP_KEY(RemoteAddress, PublicAddress);
  123. } else {
  124. //
  125. // Acquire an address mapping for the ICMP mapping
  126. //
  127. KeAcquireSpinLockAtDpcLevel(&Interfacep->Lock);
  128. status =
  129. NatAcquireFromAddressPool(
  130. Interfacep,
  131. PrivateAddress,
  132. 0,
  133. &UsedAddress
  134. );
  135. if (!NT_SUCCESS(status)) {
  136. KeReleaseSpinLockFromDpcLevel(&Interfacep->Lock);
  137. TRACE(ICMP, ("NatCreateIcmpMapping: no address available\n"));
  138. FREE_ICMP_BLOCK(Mapping);
  139. return STATUS_UNSUCCESSFUL;
  140. }
  141. PublicAddress = UsedAddress->PublicAddress;
  142. NatDereferenceAddressPoolEntry(Interfacep, UsedAddress);
  143. KeReleaseSpinLockFromDpcLevel(&Interfacep->Lock);
  144. Mapping->PublicKey = MAKE_ICMP_KEY(RemoteAddress, PublicAddress);
  145. }
  146. //
  147. // If no 'PrivateId' is specified, select one.
  148. //
  149. if (PrivateId) {
  150. Mapping->PrivateId = *PrivateId;
  151. } else {
  152. //
  153. // Find the next available identifier
  154. // by searching the list of inbound mappings
  155. //
  156. Id = 1;
  157. for (Link = IcmpMappingList[NatOutboundDirection].Flink;
  158. Link != &IcmpMappingList[NatOutboundDirection];
  159. Link = Link->Flink) {
  160. Temp =
  161. CONTAINING_RECORD(
  162. Link, NAT_ICMP_MAPPING, Link[NatOutboundDirection]
  163. );
  164. if (Mapping->PrivateKey > Temp->PrivateKey) {
  165. continue;
  166. } else if (Mapping->PrivateKey < Temp->PrivateKey) {
  167. break;
  168. }
  169. //
  170. // Primary key equal; see if the identifier we've chosen
  171. // collides with this one
  172. //
  173. if (Id > Temp->PrivateId) {
  174. continue;
  175. } else if (Id < Temp->PrivateId) {
  176. break;
  177. }
  178. //
  179. // The identifier's collide; choose another and go on
  180. //
  181. ++Id;
  182. }
  183. if (Link == &IcmpMappingList[NatOutboundDirection] && !Id) {
  184. //
  185. // We are at the end of the list, and all 64K-1 IDs are taken
  186. //
  187. FREE_ICMP_BLOCK(Mapping);
  188. return STATUS_UNSUCCESSFUL;
  189. }
  190. Mapping->PrivateId = Id;
  191. //
  192. // And by the way, we now have the outbound insertion point
  193. //
  194. if (!OutboundInsertionPoint) { OutboundInsertionPoint = Link; }
  195. }
  196. //
  197. // If no 'PublicId' is specified, select one.
  198. //
  199. if (PublicId) {
  200. Mapping->PublicId = *PublicId;
  201. } else {
  202. //
  203. // Find the next available identifier
  204. // by searching the list of inbound mappings
  205. //
  206. Id = 1;
  207. for (Link = IcmpMappingList[NatInboundDirection].Flink;
  208. Link != &IcmpMappingList[NatInboundDirection];
  209. Link = Link->Flink) {
  210. Temp =
  211. CONTAINING_RECORD(
  212. Link, NAT_ICMP_MAPPING, Link[NatInboundDirection]
  213. );
  214. if (Mapping->PublicKey > Temp->PublicKey) {
  215. continue;
  216. } else if (Mapping->PublicKey < Temp->PublicKey) {
  217. break;
  218. }
  219. //
  220. // Primary key equal; see if the identifier we've chosen
  221. // collides with this one
  222. //
  223. if (Id > Temp->PublicId) {
  224. continue;
  225. } else if (Id < Temp->PublicId) {
  226. break;
  227. }
  228. //
  229. // The identifier's collide; choose another and go on
  230. //
  231. ++Id;
  232. }
  233. if (Link == &IcmpMappingList[NatInboundDirection] && !Id) {
  234. //
  235. // We are at the end of the list, and all 64K-1 IDs are taken
  236. //
  237. FREE_ICMP_BLOCK(Mapping);
  238. return STATUS_UNSUCCESSFUL;
  239. }
  240. Mapping->PublicId = Id;
  241. //
  242. // And by the way, we now have the inbound insertion point
  243. //
  244. if (!InboundInsertionPoint) { InboundInsertionPoint = Link; }
  245. }
  246. TRACE(
  247. MAPPING,
  248. ("NatCreateIcmpMapping: Icmp=%016I64X:%04X::%016I64X:%04X\n",
  249. Mapping->PrivateKey, Mapping->PrivateId,
  250. Mapping->PublicKey, Mapping->PublicId
  251. ));
  252. //
  253. // Insert the mapping in the inbound list
  254. //
  255. if (!InboundInsertionPoint) {
  256. DuplicateMapping =
  257. NatLookupInboundIcmpMapping(
  258. Mapping->PrivateKey,
  259. Mapping->PrivateId,
  260. &InboundInsertionPoint
  261. );
  262. if (NULL != DuplicateMapping) {
  263. //
  264. // This mapping already exists on the inbound path
  265. //
  266. FREE_ICMP_BLOCK(Mapping);
  267. return STATUS_UNSUCCESSFUL;
  268. }
  269. }
  270. InsertTailList(InboundInsertionPoint, &Mapping->Link[NatInboundDirection]);
  271. //
  272. // Insert the mapping in the outbound list
  273. //
  274. if (!OutboundInsertionPoint) {
  275. DuplicateMapping =
  276. NatLookupOutboundIcmpMapping(
  277. Mapping->PublicKey,
  278. Mapping->PublicId,
  279. &OutboundInsertionPoint
  280. );
  281. if (NULL != DuplicateMapping) {
  282. //
  283. // This mapping already exists on the outbound path
  284. //
  285. RemoveEntryList(&Mapping->Link[NatInboundDirection]);
  286. FREE_ICMP_BLOCK(Mapping);
  287. return STATUS_UNSUCCESSFUL;
  288. }
  289. }
  290. InsertTailList(
  291. OutboundInsertionPoint, &Mapping->Link[NatOutboundDirection]
  292. );
  293. *MappingCreated = Mapping;
  294. return STATUS_SUCCESS;
  295. } // NatCreateIcmpMapping
  296. VOID
  297. NatInitializeIcmpManagement(
  298. VOID
  299. )
  300. /*++
  301. Routine Description:
  302. This routine is called to initialize the ICMP translation module.
  303. Arguments:
  304. none.
  305. Return Value:
  306. none.
  307. --*/
  308. {
  309. CALLTRACE(("NatInitializeIcmpManagement\n"));
  310. KeInitializeSpinLock(&IcmpMappingLock);
  311. InitializeListHead(&IcmpMappingList[NatInboundDirection]);
  312. InitializeListHead(&IcmpMappingList[NatOutboundDirection]);
  313. ExInitializeNPagedLookasideList(
  314. &IcmpLookasideList,
  315. NatAllocateFunction,
  316. NULL,
  317. 0,
  318. sizeof(NAT_ICMP_MAPPING),
  319. NAT_TAG_ICMP,
  320. ICMP_LOOKASIDE_DEPTH
  321. );
  322. } // NatInitializeIcmpManagement
  323. PNAT_ICMP_MAPPING
  324. NatLookupInboundIcmpMapping(
  325. ULONG64 PublicKey,
  326. USHORT PublicId,
  327. PLIST_ENTRY* InsertionPoint
  328. )
  329. /*++
  330. Routine Description:
  331. This routine is called to find an ICMP mapping using the remote-address
  332. and the publicly-visible address, which correspond to the 'PublicKey',
  333. and the 'PublicId' field.
  334. Arguments:
  335. PublicKey - the remote-address/public-address combination
  336. PublicId - the mapping's public identifier
  337. InsertionPoint - receives the insertion-point if the mapping is not found.
  338. Return Value:
  339. PNAT_ICMP_MAPPING - the mapping found, or NULL if not found.
  340. --*/
  341. {
  342. PLIST_ENTRY Link;
  343. PNAT_ICMP_MAPPING Mapping;
  344. CALLTRACE(("NatLookupInboundIcmpMapping\n"));
  345. if (InsertionPoint) { *InsertionPoint = NULL; }
  346. for (Link = IcmpMappingList[NatInboundDirection].Flink;
  347. Link != &IcmpMappingList[NatInboundDirection]; Link = Link->Flink) {
  348. Mapping =
  349. CONTAINING_RECORD(
  350. Link, NAT_ICMP_MAPPING, Link[NatInboundDirection]
  351. );
  352. if (PublicKey > Mapping->PublicKey) {
  353. continue;
  354. } else if (PublicKey < Mapping->PublicKey) {
  355. break;
  356. }
  357. //
  358. // Primary keys equal; check secondary keys.
  359. //
  360. if (PublicId > Mapping->PublicId) {
  361. continue;
  362. } else if (PublicId < Mapping->PublicId) {
  363. break;
  364. }
  365. //
  366. // Secondary keys equal, too. This is the requested item.
  367. //
  368. return Mapping;
  369. }
  370. if (InsertionPoint) { *InsertionPoint = Link; }
  371. return NULL;
  372. } // NatLookupInboundIcmpMapping
  373. PNAT_ICMP_MAPPING
  374. NatLookupOutboundIcmpMapping(
  375. ULONG64 PrivateKey,
  376. USHORT PrivateId,
  377. PLIST_ENTRY* InsertionPoint
  378. )
  379. /*++
  380. Routine Description:
  381. This routine is called to find an ICMP mapping using the remote-address
  382. and the private address, which correspond to the 'PrivateKey'.
  383. Arguments:
  384. PrivateKey - the remote-address/private-address combination
  385. PrivateId - the mapping's private identifier
  386. InsertionPoint - receives insertion-point if mapping not found.
  387. Return Value:
  388. PNAT_ICMP_MAPPING - the mapping found, or NULL if not found.
  389. --*/
  390. {
  391. PLIST_ENTRY Link;
  392. PNAT_ICMP_MAPPING Mapping;
  393. CALLTRACE(("NatLookupOutboundIcmpMapping\n"));
  394. if (InsertionPoint) { *InsertionPoint = NULL; }
  395. for (Link = IcmpMappingList[NatOutboundDirection].Flink;
  396. Link != &IcmpMappingList[NatOutboundDirection]; Link = Link->Flink) {
  397. Mapping =
  398. CONTAINING_RECORD(
  399. Link, NAT_ICMP_MAPPING, Link[NatOutboundDirection]
  400. );
  401. if (PrivateKey > Mapping->PrivateKey) {
  402. continue;
  403. } else if (PrivateKey < Mapping->PrivateKey) {
  404. break;
  405. }
  406. //
  407. // Primary keys equal; check secondary keys.
  408. //
  409. if (PrivateId > Mapping->PrivateId) {
  410. continue;
  411. } else if (PrivateId < Mapping->PrivateId) {
  412. break;
  413. }
  414. //
  415. // Keys are equal, so we've found it.
  416. //
  417. return Mapping;
  418. }
  419. if (InsertionPoint) { *InsertionPoint = Link; }
  420. return NULL;
  421. } // NatLookupOutboundIcmpMapping
  422. FORWARD_ACTION
  423. NatpFirewallIcmp(
  424. PNAT_INTERFACE Interfacep,
  425. IP_NAT_DIRECTION Direction,
  426. PNAT_XLATE_CONTEXT Contextp
  427. )
  428. /*++
  429. Routine Description:
  430. This routine encapsulates the ICMP firewall logic. It is
  431. only used (as of now) for non-boundary FW interfaces
  432. Arguments:
  433. Interfacep - the boundary interface over which to translate.
  434. Direction - the direction in which the packet is traveling
  435. Contextp - initialized with context-information for the packet
  436. Return Value:
  437. FORWARD_ACTION - indicates action to take on packet.
  438. Environment:
  439. Invoked with a reference made to 'Interfacep'.
  440. --*/
  441. {
  442. FORWARD_ACTION act;
  443. ULONG i;
  444. PICMP_HEADER IcmpHeader;
  445. PIP_HEADER IpHeader;
  446. PNAT_ICMP_MAPPING IcmpMapping;
  447. ULONG64 PublicKey;
  448. ULONG64 RemoteKey;
  449. PLIST_ENTRY InsertionPoint;
  450. NTSTATUS ntStatus;
  451. TRACE(XLATE, ("NatpFirewallIcmp\n"));
  452. if (NatOutboundDirection == Direction) {
  453. //
  454. // Make sure this packet has a valid source address
  455. // for this interface.
  456. //
  457. act = DROP;
  458. for (i = 0; i < Interfacep->AddressCount; i++) {
  459. if (Contextp->SourceAddress ==
  460. Interfacep->AddressArray[i].Address
  461. ) {
  462. act = FORWARD;
  463. break;
  464. }
  465. }
  466. if (DROP == act) {
  467. //
  468. // Invalid source addess -- packet should be
  469. // dropped w/o any further processing.
  470. //
  471. return act;
  472. }
  473. }
  474. IpHeader = Contextp->Header;
  475. IcmpHeader = (PICMP_HEADER)Contextp->ProtocolHeader;
  476. switch (IcmpHeader->Type) {
  477. //
  478. // Message forewarded only if a corresponding mapping
  479. // exists. A mapping for an outbound packet can exist only
  480. // if the use chooses to allow the corresponding request
  481. // type.
  482. //
  483. case ICMP_ECHO_REPLY:
  484. case ICMP_TIMESTAMP_REPLY:
  485. case ICMP_ROUTER_REPLY:
  486. case ICMP_MASK_REPLY: {
  487. if (NatInboundDirection == Direction) {
  488. PublicKey =
  489. MAKE_ICMP_KEY(
  490. Contextp->SourceAddress,
  491. Contextp->DestinationAddress
  492. );
  493. KeAcquireSpinLockAtDpcLevel(&IcmpMappingLock);
  494. IcmpMapping =
  495. NatLookupInboundIcmpMapping(
  496. PublicKey,
  497. IcmpHeader->Identifier,
  498. &InsertionPoint
  499. );
  500. if (NULL != IcmpMapping) {
  501. KeQueryTickCount(
  502. (PLARGE_INTEGER)&IcmpMapping->LastAccessTime
  503. );
  504. }
  505. KeReleaseSpinLockFromDpcLevel(&IcmpMappingLock);
  506. act = IcmpMapping != NULL ? FORWARD : DROP;
  507. } else {
  508. PublicKey =
  509. MAKE_ICMP_KEY(
  510. Contextp->DestinationAddress,
  511. Contextp->SourceAddress
  512. );
  513. KeAcquireSpinLockAtDpcLevel(&IcmpMappingLock);
  514. IcmpMapping =
  515. NatLookupOutboundIcmpMapping(
  516. PublicKey,
  517. IcmpHeader->Identifier,
  518. &InsertionPoint
  519. );
  520. if (NULL != IcmpMapping) {
  521. KeQueryTickCount(
  522. (PLARGE_INTEGER)&IcmpMapping->LastAccessTime
  523. );
  524. }
  525. KeReleaseSpinLockFromDpcLevel(&IcmpMappingLock);
  526. act = IcmpMapping != NULL ? FORWARD : DROP;
  527. }
  528. break;
  529. }
  530. //
  531. // Outbound messages create a mapping and are forwarded.
  532. // Inbound messages are dropped, unless configured to
  533. // allow inbound; if this is the case, create a mapping
  534. // and forward. The mapping will allow the response
  535. // to go through the firewall
  536. //
  537. case ICMP_ECHO_REQUEST:
  538. case ICMP_TIMESTAMP_REQUEST:
  539. case ICMP_ROUTER_REQUEST:
  540. case ICMP_MASK_REQUEST: {
  541. if (NatOutboundDirection == Direction) {
  542. act = FORWARD;
  543. //
  544. // Check to see if a mapping already exists
  545. //
  546. PublicKey =
  547. MAKE_ICMP_KEY(
  548. Contextp->DestinationAddress,
  549. Contextp->SourceAddress
  550. );
  551. KeAcquireSpinLockAtDpcLevel (&IcmpMappingLock);
  552. IcmpMapping =
  553. NatLookupOutboundIcmpMapping(
  554. PublicKey,
  555. IcmpHeader->Identifier,
  556. &InsertionPoint
  557. );
  558. if (NULL == IcmpMapping) {
  559. //
  560. // One didn't -- create a new mappping.
  561. //
  562. ntStatus =
  563. NatCreateIcmpMapping(
  564. Interfacep,
  565. Contextp->DestinationAddress,
  566. Contextp->SourceAddress,
  567. Contextp->SourceAddress,
  568. &IcmpHeader->Identifier,
  569. &IcmpHeader->Identifier,
  570. NULL,
  571. NULL,
  572. &IcmpMapping
  573. );
  574. if (!NT_SUCCESS(ntStatus)) {
  575. TRACE(
  576. XLATE, (
  577. "NatIcmpFirewall: error 0x%x creating mapping\n",
  578. ntStatus
  579. ));
  580. act = DROP;
  581. }
  582. } else {
  583. KeQueryTickCount(
  584. (PLARGE_INTEGER)&IcmpMapping->LastAccessTime
  585. );
  586. }
  587. KeReleaseSpinLockFromDpcLevel( &IcmpMappingLock );
  588. } else {
  589. //
  590. // Check to see if inbound for this type is permitted. If
  591. // so, create a mapping and forward.
  592. //
  593. if (NAT_INTERFACE_ALLOW_ICMP(Interfacep, IcmpHeader->Type)) {
  594. act = FORWARD;
  595. //
  596. // Check to see if a mapping already exists
  597. //
  598. PublicKey =
  599. MAKE_ICMP_KEY(
  600. Contextp->SourceAddress,
  601. Contextp->DestinationAddress
  602. );
  603. KeAcquireSpinLockAtDpcLevel (&IcmpMappingLock);
  604. IcmpMapping =
  605. NatLookupInboundIcmpMapping(
  606. PublicKey,
  607. IcmpHeader->Identifier,
  608. &InsertionPoint
  609. );
  610. if (NULL == IcmpMapping) {
  611. //
  612. // One didn't -- create a new mappping.
  613. //
  614. ntStatus =
  615. NatCreateIcmpMapping(
  616. Interfacep,
  617. Contextp->SourceAddress,
  618. Contextp->DestinationAddress,
  619. Contextp->DestinationAddress,
  620. &IcmpHeader->Identifier,
  621. &IcmpHeader->Identifier,
  622. NULL,
  623. NULL,
  624. &IcmpMapping
  625. );
  626. if (!NT_SUCCESS(ntStatus)) {
  627. TRACE(
  628. XLATE, (
  629. "NatIcmpFirewall: error 0x%x creating mapping\n",
  630. ntStatus
  631. ));
  632. act = DROP;
  633. }
  634. } else {
  635. KeQueryTickCount(
  636. (PLARGE_INTEGER)&IcmpMapping->LastAccessTime
  637. );
  638. }
  639. KeReleaseSpinLockFromDpcLevel(&IcmpMappingLock);
  640. } else {
  641. //
  642. // Not permitted.
  643. //
  644. act = DROP;
  645. }
  646. }
  647. break;
  648. }
  649. //
  650. // These messages are allowed inbound, but are dropped outbound
  651. // (unless the user chooses to allow them). Allowing outbound creates
  652. // more avenues of attack for port-scanning tools.
  653. //
  654. case ICMP_TIME_EXCEED:
  655. case ICMP_PARAM_PROBLEM:
  656. case ICMP_DEST_UNREACH:
  657. case ICMP_SOURCE_QUENCH: {
  658. if (NatInboundDirection == Direction) {
  659. act = FORWARD;
  660. } else {
  661. act =
  662. (NAT_INTERFACE_ALLOW_ICMP(Interfacep, IcmpHeader->Type)
  663. ? FORWARD
  664. : DROP);
  665. }
  666. break;
  667. }
  668. //
  669. // These messages are always dropped, no matter the direction
  670. // (unless the user chooses to allow them).
  671. //
  672. case ICMP_REDIRECT: {
  673. act =
  674. (NAT_INTERFACE_ALLOW_ICMP(Interfacep, IcmpHeader->Type)
  675. ? FORWARD
  676. : DROP);
  677. break;
  678. }
  679. //
  680. // Anything else is dropped by default.
  681. //
  682. default: {
  683. act = DROP;
  684. break;
  685. }
  686. }
  687. return act;
  688. } // NatpFirewallIcmp
  689. VOID
  690. NatShutdownIcmpManagement(
  691. VOID
  692. )
  693. /*++
  694. Routine Description:
  695. This routine is invoked to clean up the ICMP management module
  696. when the NAT driver is unloaded.
  697. Arguments:
  698. none.
  699. Return Value:
  700. none.
  701. --*/
  702. {
  703. ExDeleteNPagedLookasideList(&IcmpLookasideList);
  704. } // NatShutdownIcmpManagement
  705. FORWARD_ACTION
  706. NatTranslateIcmp(
  707. PNAT_INTERFACE Interfacep OPTIONAL,
  708. IP_NAT_DIRECTION Direction,
  709. PNAT_XLATE_CONTEXT Contextp,
  710. IPRcvBuf** InRecvBuffer,
  711. IPRcvBuf** OutRecvBuffer
  712. )
  713. /*++
  714. Routine Description:
  715. This routine is invoked to perform translation on an ICMP message.
  716. Arguments:
  717. Interfacep - the boundary interface over which to translate, or NULL
  718. if the packet is inbound and the receiving interface has not been
  719. added to the NAT.
  720. Direction - the direction in which the packet is traveling
  721. Contextp - initialized with context-information for the packet
  722. InRecvBuffer - input buffer-chain
  723. OutRecvBuffer - receives modified buffer-chain.
  724. Return Value:
  725. FORWARD_ACTION - indicates action to take on packet.
  726. Environment:
  727. Invoked with a reference made to 'Interfacep' by the caller.
  728. --*/
  729. {
  730. FORWARD_ACTION act;
  731. BOOLEAN ChecksumOffloaded;
  732. ULONG i;
  733. PICMP_HEADER IcmpHeader;
  734. PIP_HEADER IpHeader;
  735. BOOLEAN LocallySent = FALSE;
  736. TRACE(XLATE, ("NatTranslateIcmp\n"));
  737. //
  738. // If the interface is in FW mode and is not a
  739. // boundary interface, go directly to the firewall
  740. // logic
  741. //
  742. if (Interfacep
  743. && NAT_INTERFACE_FW(Interfacep)
  744. && !NAT_INTERFACE_BOUNDARY(Interfacep)) {
  745. return NatpFirewallIcmp(
  746. Interfacep,
  747. Direction,
  748. Contextp
  749. );
  750. }
  751. IpHeader = Contextp->Header;
  752. IcmpHeader = (PICMP_HEADER)Contextp->ProtocolHeader;
  753. ChecksumOffloaded = Contextp->ChecksumOffloaded;
  754. //
  755. // The default action is chosen as follows:
  756. // i. if the packet is incoming on a boundary interface
  757. // a. drop if not locally destined
  758. // b. drop if the interface is firewalled
  759. // c. forward otherwise
  760. // ii. the packet is outgoing on a boundary interface, drop
  761. // if source-address is private.
  762. //
  763. if (Direction == NatInboundDirection) {
  764. if ((*Contextp->DestinationType >= DEST_REMOTE)
  765. || (Interfacep
  766. && NAT_INTERFACE_FW(Interfacep)
  767. && !NAT_INTERFACE_ALLOW_ICMP(Interfacep, IcmpHeader->Type))) {
  768. act = DROP;
  769. } else {
  770. act = FORWARD;
  771. }
  772. } else {
  773. //
  774. // See if the packet's source-address is private
  775. //
  776. // N.B. 'Interfacep' is always valid for outbound packets.
  777. //
  778. act = DROP;
  779. for (i = 0; i < Interfacep->AddressCount; i++) {
  780. if (Contextp->SourceAddress ==
  781. Interfacep->AddressArray[i].Address
  782. ) {
  783. //
  784. // The packet's source-address is public,
  785. // so we'll allow it onto the public network.
  786. //
  787. act = FORWARD;
  788. LocallySent = TRUE;
  789. break;
  790. }
  791. }
  792. }
  793. //
  794. // See what kind of ICMP message this is,
  795. // and translate it if possible.
  796. //
  797. switch (IcmpHeader->Type) {
  798. case ICMP_ROUTER_REPLY:
  799. case ICMP_MASK_REPLY:
  800. case ICMP_ECHO_REPLY:
  801. case ICMP_TIMESTAMP_REPLY: {
  802. if (IpHeader->TimeToLive <= 1
  803. && NatOutboundDirection == Direction
  804. && FALSE == LocallySent) {
  805. TRACE(XLATE, ("NatTranslateIcmp: ttl<=1, no translation\n"));
  806. return FORWARD;
  807. }
  808. if (Contextp->ProtocolRecvBuffer->ipr_size <
  809. FIELD_OFFSET(ICMP_HEADER, EncapsulatedIpHeader) ||
  810. !NatTranslateIcmpRequest(
  811. Interfacep,
  812. Direction,
  813. Contextp,
  814. TRUE,
  815. ChecksumOffloaded
  816. )) {
  817. return act;
  818. }
  819. *OutRecvBuffer = *InRecvBuffer; *InRecvBuffer = NULL;
  820. *Contextp->DestinationType = DEST_INVALID;
  821. return FORWARD;
  822. }
  823. case ICMP_ROUTER_REQUEST:
  824. case ICMP_MASK_REQUEST:
  825. case ICMP_ECHO_REQUEST:
  826. case ICMP_TIMESTAMP_REQUEST: {
  827. if (IpHeader->TimeToLive <= 1
  828. && NatOutboundDirection == Direction
  829. && FALSE == LocallySent) {
  830. TRACE(XLATE, ("NatTranslateIcmp: ttl<=1, no translation\n"));
  831. return FORWARD;
  832. }
  833. if (Contextp->ProtocolRecvBuffer->ipr_size <
  834. FIELD_OFFSET(ICMP_HEADER, EncapsulatedIpHeader) ||
  835. !NatTranslateIcmpRequest(
  836. Interfacep,
  837. Direction,
  838. Contextp,
  839. FALSE,
  840. ChecksumOffloaded
  841. )) {
  842. //
  843. // If the interface is in FW mode, we don't want to let
  844. // a non-translated packet through, unless the user has
  845. // configured the interface otherwise.
  846. //
  847. if (Interfacep
  848. && NAT_INTERFACE_FW(Interfacep)
  849. && !NAT_INTERFACE_ALLOW_ICMP(
  850. Interfacep,
  851. IcmpHeader->Type
  852. )) {
  853. act = DROP;
  854. }
  855. return act;
  856. }
  857. *OutRecvBuffer = *InRecvBuffer; *InRecvBuffer = NULL;
  858. *Contextp->DestinationType = DEST_INVALID;
  859. return FORWARD;
  860. }
  861. case ICMP_TIME_EXCEED: {
  862. //
  863. // Outgoing on a firewalled interface are dropped, unless
  864. // the user has specified otherwise
  865. //
  866. if (Direction == NatOutboundDirection
  867. && Interfacep
  868. && NAT_INTERFACE_FW(Interfacep)
  869. && !NAT_INTERFACE_ALLOW_ICMP(Interfacep, IcmpHeader->Type)) {
  870. return DROP;
  871. }
  872. //
  873. // Time-exceeded messages will be triggered at each hop
  874. // to the final destination of a traceroute sequence.
  875. // Such messages must be translated like ICMP replies.
  876. // Time-exceeded messages may also be generated
  877. // in response to TCP/UDP packets, so we translate them
  878. // in the latter case as well.
  879. //
  880. if (Contextp->ProtocolRecvBuffer->ipr_size <
  881. sizeof(ICMP_HEADER) ||
  882. (IcmpHeader->EncapsulatedIpHeader.VersionAndHeaderLength
  883. & 0x0f) != 5) {
  884. return act;
  885. } else if (IcmpHeader->EncapsulatedIpHeader.Protocol ==
  886. NAT_PROTOCOL_ICMP) {
  887. if ((IcmpHeader->EncapsulatedIcmpHeader.Type !=
  888. ICMP_ECHO_REQUEST
  889. && IcmpHeader->EncapsulatedIcmpHeader.Type !=
  890. ICMP_MASK_REQUEST
  891. && IcmpHeader->EncapsulatedIcmpHeader.Type !=
  892. ICMP_ROUTER_REQUEST
  893. && IcmpHeader->EncapsulatedIcmpHeader.Type !=
  894. ICMP_TIMESTAMP_REQUEST) ||
  895. !NatTranslateIcmpEncapsulatedRequest(
  896. Interfacep,
  897. Direction,
  898. IpHeader,
  899. IcmpHeader,
  900. &IcmpHeader->EncapsulatedIpHeader,
  901. &IcmpHeader->EncapsulatedIcmpHeader,
  902. ChecksumOffloaded
  903. )) {
  904. return act;
  905. }
  906. } else if (IcmpHeader->EncapsulatedIpHeader.Protocol
  907. == NAT_PROTOCOL_TCP ||
  908. IcmpHeader->EncapsulatedIpHeader.Protocol
  909. == NAT_PROTOCOL_UDP) {
  910. if (!NatTranslateEncapsulatedRequest(
  911. Interfacep,
  912. Direction,
  913. IpHeader,
  914. IcmpHeader,
  915. &IcmpHeader->EncapsulatedIpHeader,
  916. &IcmpHeader->EncapsulatedUdpHeader,
  917. ChecksumOffloaded
  918. )) {
  919. return act;
  920. }
  921. } else {
  922. return act;
  923. }
  924. *OutRecvBuffer = *InRecvBuffer; *InRecvBuffer = NULL;
  925. *Contextp->DestinationType = DEST_INVALID;
  926. return FORWARD;
  927. }
  928. case ICMP_PARAM_PROBLEM:
  929. case ICMP_DEST_UNREACH: {
  930. //
  931. // Outgoing on a firewalled interface are dropped, unless
  932. // the user has specified otherwise
  933. //
  934. if (Direction == NatOutboundDirection
  935. && Interfacep
  936. && NAT_INTERFACE_FW(Interfacep)
  937. && !NAT_INTERFACE_ALLOW_ICMP(Interfacep, IcmpHeader->Type)) {
  938. return DROP;
  939. }
  940. //
  941. // Destination unreachable messages will be generated for a variety
  942. // of reasons. We are interested in the following cases:
  943. // * Packet-too-big: When a packet received on a boundary
  944. // interface has the 'DF' bit set, the local forwarder may
  945. // generate an ICMP error message to the remote endpoint
  946. // indicating that the remote system should reduce its MSS.
  947. // This error, however, will contain the IP address of the
  948. // private network in the encapsulated packet, since the ICMP
  949. // error was generated after translation.
  950. // * Port-unreachable: Indicates that no application is listening
  951. // at the UDP port to which a packet was sent.
  952. //
  953. if (Contextp->ProtocolRecvBuffer->ipr_size <
  954. sizeof(ICMP_HEADER) ||
  955. (IcmpHeader->EncapsulatedIpHeader.VersionAndHeaderLength
  956. & 0x0f) != 5) {
  957. return act;
  958. } else if (IcmpHeader->EncapsulatedIpHeader.Protocol ==
  959. NAT_PROTOCOL_ICMP) {
  960. if ((IcmpHeader->EncapsulatedIcmpHeader.Type !=
  961. ICMP_ECHO_REQUEST
  962. && IcmpHeader->EncapsulatedIcmpHeader.Type !=
  963. ICMP_MASK_REQUEST
  964. && IcmpHeader->EncapsulatedIcmpHeader.Type !=
  965. ICMP_ROUTER_REQUEST
  966. && IcmpHeader->EncapsulatedIcmpHeader.Type !=
  967. ICMP_TIMESTAMP_REQUEST) ||
  968. !NatTranslateIcmpEncapsulatedRequest(
  969. Interfacep,
  970. Direction,
  971. IpHeader,
  972. IcmpHeader,
  973. &IcmpHeader->EncapsulatedIpHeader,
  974. &IcmpHeader->EncapsulatedIcmpHeader,
  975. ChecksumOffloaded
  976. )) {
  977. return act;
  978. }
  979. } else if (IcmpHeader->EncapsulatedIpHeader.Protocol
  980. == NAT_PROTOCOL_TCP ||
  981. IcmpHeader->EncapsulatedIpHeader.Protocol
  982. == NAT_PROTOCOL_UDP) {
  983. if (!NatTranslateEncapsulatedRequest(
  984. Interfacep,
  985. Direction,
  986. IpHeader,
  987. IcmpHeader,
  988. &IcmpHeader->EncapsulatedIpHeader,
  989. &IcmpHeader->EncapsulatedUdpHeader,
  990. ChecksumOffloaded
  991. )) {
  992. return act;
  993. }
  994. } else {
  995. return act;
  996. }
  997. *OutRecvBuffer = *InRecvBuffer; *InRecvBuffer = NULL;
  998. *Contextp->DestinationType = DEST_INVALID;
  999. return FORWARD;
  1000. }
  1001. case ICMP_SOURCE_QUENCH: {
  1002. //
  1003. // Outgoing on a firewalled interface are dropped, unless
  1004. // the user has specified otherwise
  1005. //
  1006. if (Direction == NatOutboundDirection
  1007. && Interfacep
  1008. && NAT_INTERFACE_FW(Interfacep)
  1009. && !NAT_INTERFACE_ALLOW_ICMP(Interfacep, IcmpHeader->Type)) {
  1010. return DROP;
  1011. }
  1012. return act;
  1013. }
  1014. case ICMP_REDIRECT: {
  1015. //
  1016. // We do not translate ICMP redirect errors, since we want
  1017. // the NAT's IP forwarder to see the redirects and adjust
  1018. // its routing table accordingly.
  1019. //
  1020. // However, we do not allow inbound or outbound redirects
  1021. // across a firwall interface, unless the user has
  1022. // specified otherwise
  1023. //
  1024. if (Interfacep
  1025. && NAT_INTERFACE_FW(Interfacep)
  1026. && NAT_INTERFACE_ALLOW_ICMP(Interfacep, IcmpHeader->Type)) {
  1027. act = FORWARD;
  1028. }
  1029. return act;
  1030. }
  1031. default: {
  1032. break;
  1033. }
  1034. }
  1035. return act;
  1036. } // NatTranslateIcmp
  1037. BOOLEAN
  1038. NatTranslateIcmpEncapsulatedRequest(
  1039. PNAT_INTERFACE Interfacep OPTIONAL,
  1040. IP_NAT_DIRECTION Direction,
  1041. PIP_HEADER IpHeader,
  1042. PICMP_HEADER IcmpHeader,
  1043. PIP_HEADER EncapsulatedIpHeader,
  1044. struct _ENCAPSULATED_ICMP_HEADER* EncapsulatedIcmpHeader,
  1045. BOOLEAN ChecksumOffloaded
  1046. )
  1047. /*++
  1048. Routine Description:
  1049. This routine is invoked to translate an ICMP error message in which
  1050. we have another ICMP message encapsulated. This is necessary, for instance,
  1051. in the case of ICMP time-exceeded errors, upon which 'traceroute' relies.
  1052. Arguments:
  1053. Interfacep - the interface across which the ICMP message will be forwarded,
  1054. or NULL if the packet was received on a non-boundary interface
  1055. unknown to the NAT.
  1056. Direction - the direction in which the ICMP message is traveling
  1057. IpHeader - points to the IP header of the ICMP message
  1058. IcmpHeader - points to the ICMP header within the IP packet
  1059. EncapsulatedIpHeader - points to the IP header of the ICMP message
  1060. encapsulated in the data portion of the message
  1061. EncapsulatedIcmpHeader - points to the ICMP header of the ICMP message
  1062. encapsulated in the data portion of the message
  1063. Return Value:
  1064. BOOLEAN - TRUE if the packet was translated, FALSE otherwise
  1065. Environment:
  1066. Invoked at dispatch IRQL with a reference made to 'Interfacep'.
  1067. --*/
  1068. {
  1069. ULONG Checksum;
  1070. ULONG ChecksumDelta;
  1071. ULONG ChecksumDelta2;
  1072. PNAT_ICMP_MAPPING IcmpMapping;
  1073. ULONG64 Key;
  1074. CALLTRACE(("NatTranslateIcmpEncapsulatedRequest\n"));
  1075. //
  1076. // The checksum processing for encapsulated messages
  1077. // is extremely complicated since we must update
  1078. // (1) the ICMP checksum of the encapsulated ICMP message,
  1079. // using the change to the encapsulated ICMP identifier
  1080. // (2) the IP header-checksum of the encapsulated ICMP message
  1081. // using the change to the encapsulated IP addresses
  1082. // (3) the ICMP checksum of the containing ICMP error message
  1083. // using both the above changes as well as the changes
  1084. // to both the above checksums
  1085. // (4) the IP header-checksum of the containing ICMP error message
  1086. // using the change to the containing IP addresses
  1087. // Any changes to the logic below must be made with extreme care.
  1088. //
  1089. if (Direction == NatInboundDirection) {
  1090. Key =
  1091. MAKE_ICMP_KEY(
  1092. EncapsulatedIpHeader->DestinationAddress,
  1093. EncapsulatedIpHeader->SourceAddress
  1094. );
  1095. KeAcquireSpinLockAtDpcLevel(&IcmpMappingLock);
  1096. IcmpMapping =
  1097. NatLookupInboundIcmpMapping(
  1098. Key,
  1099. EncapsulatedIcmpHeader->Identifier,
  1100. NULL
  1101. );
  1102. if (!IcmpMapping) {
  1103. KeReleaseSpinLockFromDpcLevel(&IcmpMappingLock);
  1104. TRACE(
  1105. XLATE, (
  1106. "NatTranslateIcmpEncapsulatedRequest: "
  1107. "no mapping for error message\n"
  1108. ));
  1109. return FALSE;
  1110. }
  1111. ChecksumDelta = 0;
  1112. CHECKSUM_LONG(ChecksumDelta, ~EncapsulatedIcmpHeader->Identifier);
  1113. EncapsulatedIcmpHeader->Identifier = IcmpMapping->PrivateId;
  1114. CHECKSUM_LONG(ChecksumDelta, EncapsulatedIcmpHeader->Identifier);
  1115. ChecksumDelta2 = ChecksumDelta;
  1116. CHECKSUM_LONG(ChecksumDelta2, ~EncapsulatedIcmpHeader->Checksum);
  1117. CHECKSUM_UPDATE(EncapsulatedIcmpHeader->Checksum);
  1118. CHECKSUM_LONG(ChecksumDelta2, EncapsulatedIcmpHeader->Checksum);
  1119. ChecksumDelta = ChecksumDelta2; CHECKSUM_UPDATE(IcmpHeader->Checksum);
  1120. ChecksumDelta = 0;
  1121. CHECKSUM_LONG(ChecksumDelta, ~EncapsulatedIpHeader->SourceAddress);
  1122. EncapsulatedIpHeader->SourceAddress =
  1123. ICMP_KEY_PRIVATE(IcmpMapping->PrivateKey);
  1124. CHECKSUM_LONG(ChecksumDelta, EncapsulatedIpHeader->SourceAddress);
  1125. ChecksumDelta2 = ChecksumDelta;
  1126. CHECKSUM_LONG(ChecksumDelta2, ~EncapsulatedIpHeader->Checksum);
  1127. CHECKSUM_UPDATE(EncapsulatedIpHeader->Checksum);
  1128. CHECKSUM_LONG(ChecksumDelta2, EncapsulatedIpHeader->Checksum);
  1129. ChecksumDelta = ChecksumDelta2; CHECKSUM_UPDATE(IcmpHeader->Checksum);
  1130. ChecksumDelta = 0;
  1131. CHECKSUM_LONG(ChecksumDelta, ~IpHeader->DestinationAddress);
  1132. IpHeader->DestinationAddress =
  1133. ICMP_KEY_PRIVATE(IcmpMapping->PrivateKey);
  1134. CHECKSUM_LONG(ChecksumDelta, IpHeader->DestinationAddress);
  1135. CHECKSUM_UPDATE(IpHeader->Checksum);
  1136. KeQueryTickCount((PLARGE_INTEGER)&IcmpMapping->LastAccessTime);
  1137. } else {
  1138. Key =
  1139. MAKE_ICMP_KEY(
  1140. EncapsulatedIpHeader->SourceAddress,
  1141. EncapsulatedIpHeader->DestinationAddress
  1142. );
  1143. KeAcquireSpinLockAtDpcLevel(&IcmpMappingLock);
  1144. IcmpMapping =
  1145. NatLookupOutboundIcmpMapping(
  1146. Key,
  1147. EncapsulatedIcmpHeader->Identifier,
  1148. NULL
  1149. );
  1150. if (!IcmpMapping) {
  1151. KeReleaseSpinLockFromDpcLevel(&IcmpMappingLock);
  1152. TRACE(
  1153. XLATE, (
  1154. "NatTranslateIcmpEncapsulatedRequest: "
  1155. "no mapping for error message\n"
  1156. ));
  1157. return FALSE;
  1158. }
  1159. ChecksumDelta = 0;
  1160. CHECKSUM_LONG(ChecksumDelta, ~EncapsulatedIcmpHeader->Identifier);
  1161. EncapsulatedIcmpHeader->Identifier = IcmpMapping->PublicId;
  1162. CHECKSUM_LONG(ChecksumDelta, EncapsulatedIcmpHeader->Identifier);
  1163. ChecksumDelta2 = ChecksumDelta;
  1164. CHECKSUM_LONG(ChecksumDelta2, ~EncapsulatedIcmpHeader->Checksum);
  1165. CHECKSUM_UPDATE(EncapsulatedIcmpHeader->Checksum);
  1166. CHECKSUM_LONG(ChecksumDelta2, EncapsulatedIcmpHeader->Checksum);
  1167. ChecksumDelta = ChecksumDelta2; CHECKSUM_UPDATE(IcmpHeader->Checksum);
  1168. ChecksumDelta = 0;
  1169. CHECKSUM_LONG(ChecksumDelta, ~EncapsulatedIpHeader->DestinationAddress);
  1170. EncapsulatedIpHeader->DestinationAddress =
  1171. ICMP_KEY_PUBLIC(IcmpMapping->PublicKey);
  1172. CHECKSUM_LONG(ChecksumDelta, EncapsulatedIpHeader->DestinationAddress);
  1173. ChecksumDelta2 = ChecksumDelta;
  1174. CHECKSUM_LONG(ChecksumDelta2, ~EncapsulatedIpHeader->Checksum);
  1175. CHECKSUM_UPDATE(EncapsulatedIpHeader->Checksum);
  1176. CHECKSUM_LONG(ChecksumDelta2, EncapsulatedIpHeader->Checksum);
  1177. ChecksumDelta = ChecksumDelta2; CHECKSUM_UPDATE(IcmpHeader->Checksum);
  1178. ChecksumDelta = 0;
  1179. CHECKSUM_LONG(ChecksumDelta, ~IpHeader->SourceAddress);
  1180. IpHeader->SourceAddress =
  1181. ICMP_KEY_PUBLIC(IcmpMapping->PublicKey);
  1182. CHECKSUM_LONG(ChecksumDelta, IpHeader->SourceAddress);
  1183. CHECKSUM_UPDATE(IpHeader->Checksum);
  1184. KeQueryTickCount((PLARGE_INTEGER)&IcmpMapping->LastAccessTime);
  1185. }
  1186. KeReleaseSpinLockFromDpcLevel(&IcmpMappingLock);
  1187. //
  1188. // If checksum offloading is enabled on this packet, recompute the
  1189. // IP checksum. (There is no ICMP checksum-offload, so we will never
  1190. // need to fully recompute that.)
  1191. //
  1192. if (ChecksumOffloaded) {
  1193. NatComputeIpChecksum(IpHeader);
  1194. }
  1195. return TRUE;
  1196. } // NatTranslateIcmpEncapsulatedRequest
  1197. BOOLEAN
  1198. NatTranslateIcmpRequest(
  1199. PNAT_INTERFACE Interfacep OPTIONAL,
  1200. IP_NAT_DIRECTION Direction,
  1201. PNAT_XLATE_CONTEXT Contextp,
  1202. BOOLEAN ReplyCode,
  1203. BOOLEAN ChecksumOffloaded
  1204. )
  1205. /*++
  1206. Routine Description:
  1207. This routine is invoked to translate an ICMP request or reply message.
  1208. Arguments:
  1209. Interfacep - the interface across which the ICMP message is to be forwarded,
  1210. or NULL if the packet was received on a non-boundary interface unknown
  1211. to the NAT.
  1212. Direction - the direction in which the ICMP message is traveling
  1213. Contextp - contains information about the packet
  1214. ReplyCode - if TRUE, the message is a reply; otherwise, it is a request.
  1215. Return Value:
  1216. BOOLEAN - TRUE if the message was translated, FALSE otherwise.
  1217. Environment:
  1218. Invoked at dispatch IRQL with a reference made to 'Interfacep'.
  1219. --*/
  1220. {
  1221. ULONG Checksum;
  1222. ULONG ChecksumDelta;
  1223. ULONG i;
  1224. PICMP_HEADER IcmpHeader;
  1225. PNAT_ICMP_MAPPING IcmpMapping;
  1226. PIP_HEADER IpHeader;
  1227. PLIST_ENTRY InsertionPoint;
  1228. PNAT_DYNAMIC_MAPPING Mapping;
  1229. ULONG64 PrivateKey;
  1230. UCHAR Protocol;
  1231. ULONG64 PublicKey;
  1232. ULONG64 RemoteKey;
  1233. NTSTATUS status;
  1234. CALLTRACE(("NatTranslateIcmpRequest\n"));
  1235. IpHeader = Contextp->Header;
  1236. IcmpHeader = (PICMP_HEADER)Contextp->ProtocolHeader;
  1237. //
  1238. // For ICMP requests/replies we must maintain mappings, so begin by seeing
  1239. // if there is already a mapping for this particular message
  1240. //
  1241. InsertionPoint = NULL;
  1242. if (Direction == NatOutboundDirection) {
  1243. PrivateKey =
  1244. MAKE_ICMP_KEY(
  1245. Contextp->DestinationAddress,
  1246. Contextp->SourceAddress
  1247. );
  1248. KeAcquireSpinLockAtDpcLevel(&IcmpMappingLock);
  1249. IcmpMapping =
  1250. NatLookupOutboundIcmpMapping(
  1251. PrivateKey,
  1252. IcmpHeader->Identifier,
  1253. &InsertionPoint
  1254. );
  1255. if (!IcmpMapping) {
  1256. //
  1257. // No mapping was found, so try to create one.
  1258. //
  1259. // If the packet is an outbound reply-message,
  1260. // there really ought to be a corresponding inbound-mapping.
  1261. // Hence don't try to create one here, as it will just
  1262. // confuse the remote endpoint, which may find itself
  1263. // looking at a reply whose origin seems to be different
  1264. // from the machine to which it sent a request.
  1265. //
  1266. if (ReplyCode) {
  1267. KeReleaseSpinLockFromDpcLevel(&IcmpMappingLock);
  1268. TRACE(
  1269. XLATE, (
  1270. "NatTranslateIcmpRequest: ignoring outbound reply\n"
  1271. ));
  1272. return FALSE;
  1273. }
  1274. //
  1275. // First look for a static mapping from this private address
  1276. // to a public address. If one is found, it will be used
  1277. // in the call to 'NatCreateIcmpMapping' below. Otherwise,
  1278. // a public address will be chosen from the address-pool.
  1279. //
  1280. // N.B. When a packet is outbound, 'Interfacep' is always valid.
  1281. //
  1282. PublicKey = 0;
  1283. if (!Interfacep->NoStaticMappingExists) {
  1284. KeReleaseSpinLockFromDpcLevel(&IcmpMappingLock);
  1285. KeAcquireSpinLockAtDpcLevel(&Interfacep->Lock);
  1286. for (i = 0; i < Interfacep->AddressMappingCount; i++) {
  1287. if (Contextp->SourceAddress >
  1288. Interfacep->AddressMappingArray[i].PrivateAddress) {
  1289. continue;
  1290. } else if (Contextp->SourceAddress <
  1291. Interfacep->AddressMappingArray[i].PrivateAddress) {
  1292. break;
  1293. }
  1294. PublicKey =
  1295. Interfacep->AddressMappingArray[i].PublicAddress;
  1296. break;
  1297. }
  1298. KeReleaseSpinLockFromDpcLevel(&Interfacep->Lock);
  1299. KeAcquireSpinLockAtDpcLevel(&IcmpMappingLock);
  1300. }
  1301. status =
  1302. NatCreateIcmpMapping(
  1303. Interfacep,
  1304. Contextp->DestinationAddress,
  1305. Contextp->SourceAddress,
  1306. (ULONG)PublicKey,
  1307. &IcmpHeader->Identifier,
  1308. NULL,
  1309. NULL,
  1310. InsertionPoint,
  1311. &IcmpMapping
  1312. );
  1313. if (!NT_SUCCESS(status)) {
  1314. KeReleaseSpinLockFromDpcLevel(&IcmpMappingLock);
  1315. TRACE(
  1316. XLATE, (
  1317. "NatTranslateIcmpRequest: error creating mapping\n"
  1318. ));
  1319. return FALSE;
  1320. }
  1321. }
  1322. //
  1323. // Replace the Identifier in the packet,
  1324. // and replace the destination in the packet,
  1325. // updating the checksum as we go.
  1326. //
  1327. ChecksumDelta = 0;
  1328. CHECKSUM_LONG(ChecksumDelta, ~IcmpHeader->Identifier);
  1329. IcmpHeader->Identifier = IcmpMapping->PublicId;
  1330. CHECKSUM_LONG(ChecksumDelta, IcmpHeader->Identifier);
  1331. CHECKSUM_UPDATE(IcmpHeader->Checksum);
  1332. ChecksumDelta = 0;
  1333. CHECKSUM_LONG(ChecksumDelta, ~IpHeader->SourceAddress);
  1334. IpHeader->SourceAddress = ICMP_KEY_PUBLIC(IcmpMapping->PublicKey);
  1335. CHECKSUM_LONG(ChecksumDelta, IpHeader->SourceAddress);
  1336. CHECKSUM_UPDATE(IpHeader->Checksum);
  1337. KeQueryTickCount((PLARGE_INTEGER)&IcmpMapping->LastAccessTime);
  1338. } else {
  1339. //
  1340. // The packet is inbound.
  1341. //
  1342. PublicKey =
  1343. MAKE_ICMP_KEY(
  1344. Contextp->SourceAddress,
  1345. Contextp->DestinationAddress
  1346. );
  1347. KeAcquireSpinLockAtDpcLevel(&IcmpMappingLock);
  1348. IcmpMapping =
  1349. NatLookupInboundIcmpMapping(
  1350. PublicKey,
  1351. IcmpHeader->Identifier,
  1352. &InsertionPoint
  1353. );
  1354. if (!IcmpMapping) {
  1355. //
  1356. // No mapping was found, so try to create one,
  1357. // if there is a static mapping which allows inbound sessions.
  1358. // We make an exception for inbound reply-messages;
  1359. // if the packet is a reply-message, it might be locally destined,
  1360. // in which case we pass it untouched to the stack.
  1361. //
  1362. // Don't create a mapping for an inbound reply;
  1363. // it's probably a reply to a locally-initiated request.
  1364. //
  1365. if (ReplyCode) {
  1366. KeReleaseSpinLockFromDpcLevel(&IcmpMappingLock);
  1367. return FALSE;
  1368. }
  1369. //
  1370. // First look for a static mapping from this public address
  1371. // to a private address. If one is found, it will be used
  1372. // in the call to 'NatCreateIcmpMapping' below. Otherwise,
  1373. // a public address will be chosen from the address-pool.
  1374. //
  1375. // This involves an exhaustive search since the address-mappings
  1376. // are sorted on private address rather than public address.
  1377. //
  1378. if (!Interfacep) {
  1379. KeReleaseSpinLockFromDpcLevel(&IcmpMappingLock);
  1380. return FALSE;
  1381. } else if (Interfacep->NoStaticMappingExists) {
  1382. KeReleaseSpinLockFromDpcLevel(&IcmpMappingLock);
  1383. TRACE(
  1384. XLATE, (
  1385. "NatTranslateIcmpRequest: ignoring inbound message\n"
  1386. ));
  1387. return FALSE;
  1388. } else {
  1389. PrivateKey = 0;
  1390. KeReleaseSpinLockFromDpcLevel(&IcmpMappingLock);
  1391. KeAcquireSpinLockAtDpcLevel(&Interfacep->Lock);
  1392. for (i = 0; i < Interfacep->AddressMappingCount; i++) {
  1393. if (Interfacep->AddressMappingArray[i].PublicAddress !=
  1394. Contextp->DestinationAddress ||
  1395. !Interfacep->AddressMappingArray[i].AllowInboundSessions) {
  1396. continue;
  1397. }
  1398. PrivateKey =
  1399. Interfacep->AddressMappingArray[i].PrivateAddress;
  1400. break;
  1401. }
  1402. KeReleaseSpinLockFromDpcLevel(&Interfacep->Lock);
  1403. if (!PrivateKey) {
  1404. TRACE(
  1405. XLATE, (
  1406. "NatTranslateIcmpRequest: ignoring inbound message\n"
  1407. ));
  1408. return FALSE;
  1409. }
  1410. KeAcquireSpinLockAtDpcLevel(&IcmpMappingLock);
  1411. }
  1412. status =
  1413. NatCreateIcmpMapping(
  1414. Interfacep,
  1415. Contextp->SourceAddress,
  1416. (ULONG)PrivateKey,
  1417. Contextp->DestinationAddress,
  1418. NULL,
  1419. &IcmpHeader->Identifier,
  1420. InsertionPoint,
  1421. NULL,
  1422. &IcmpMapping
  1423. );
  1424. if (!NT_SUCCESS(status)) {
  1425. KeReleaseSpinLockFromDpcLevel(&IcmpMappingLock);
  1426. TRACE(
  1427. XLATE, (
  1428. "NatTranslateIcmpRequest: error creating mapping\n"
  1429. ));
  1430. return FALSE;
  1431. }
  1432. }
  1433. //
  1434. // Replace the Identifier in the packet
  1435. // and replace the destination in the packet,
  1436. // updating the checksum as we go.
  1437. //
  1438. ChecksumDelta = 0;
  1439. CHECKSUM_LONG(ChecksumDelta, ~IcmpHeader->Identifier);
  1440. IcmpHeader->Identifier = IcmpMapping->PrivateId;
  1441. CHECKSUM_LONG(ChecksumDelta, IcmpHeader->Identifier);
  1442. CHECKSUM_UPDATE(IcmpHeader->Checksum);
  1443. ChecksumDelta = 0;
  1444. CHECKSUM_LONG(ChecksumDelta, ~IpHeader->DestinationAddress);
  1445. IpHeader->DestinationAddress =
  1446. ICMP_KEY_PRIVATE(IcmpMapping->PrivateKey);
  1447. CHECKSUM_LONG(ChecksumDelta, IpHeader->DestinationAddress);
  1448. CHECKSUM_UPDATE(IpHeader->Checksum);
  1449. KeQueryTickCount((PLARGE_INTEGER)&IcmpMapping->LastAccessTime);
  1450. }
  1451. KeReleaseSpinLockFromDpcLevel(&IcmpMappingLock);
  1452. //
  1453. // If checksum offloading is enabled on this packet, recompute the
  1454. // IP checksum. (There is no ICMP checksum-offload, so we will never
  1455. // need to fully recompute that.)
  1456. //
  1457. if (ChecksumOffloaded) {
  1458. NatComputeIpChecksum(IpHeader);
  1459. }
  1460. return TRUE;
  1461. } // NatTranslateIcmpRequest
  1462. BOOLEAN
  1463. NatTranslateEncapsulatedRequest(
  1464. PNAT_INTERFACE Interfacep OPTIONAL,
  1465. IP_NAT_DIRECTION Direction,
  1466. PIP_HEADER IpHeader,
  1467. PICMP_HEADER IcmpHeader,
  1468. PIP_HEADER EncapsulatedIpHeader,
  1469. struct _ENCAPSULATED_UDP_HEADER* EncapsulatedHeader,
  1470. BOOLEAN ChecksumOffloaded
  1471. )
  1472. /*++
  1473. Routine Description:
  1474. This routine is invoked to translate an ICMP error message in which
  1475. we have TCP segment or UDP datagram encapsulated. This is necessary,
  1476. for instance, in the case of ICMP destination-unreachable errors,
  1477. particularly where the target will take some action (such as reducing MTU)
  1478. upon receipt of the message.
  1479. Arguments:
  1480. Interfacep - the interface across which the ICMP message will be forwarded,
  1481. or NULL if the packet was received on a non-boundary interface.
  1482. Direction - the direction in which the ICMP message is traveling
  1483. IpHeader - points to the IP header of the ICMP message
  1484. IcmpHeader - points to the ICMP header within the IP packet
  1485. EncapsulatedIpHeader - points to the IP header of the TCP segment
  1486. encapsulated in the data portion of the ICMP message
  1487. EncapsulatedHeader - points to the TCP/UDP header of the TCP segment
  1488. encapsulated in the data portion of the ICMP message
  1489. Return Value:
  1490. BOOLEAN - TRUE if the packet was translated, FALSE otherwise
  1491. Environment:
  1492. Invoked at dispatch IRQL with a reference made to 'Interfacep'.
  1493. N.B.!!! This routine will acquire the mapping lock in order to search
  1494. the mapping-tree for the entry corresponding to the session for which
  1495. this ICMP error message was generated. All callers must take note,
  1496. and must ensure that the mapping lock is not already held on entry.
  1497. --*/
  1498. {
  1499. ULONG Checksum;
  1500. ULONG ChecksumDelta;
  1501. ULONG ChecksumDelta2;
  1502. ULONG64 DestinationKey;
  1503. PNAT_DYNAMIC_MAPPING Mapping;
  1504. ULONG64 ReplacementKey;
  1505. ULONG64 SourceKey;
  1506. CALLTRACE(("NatTranslateEncapsulatedRequest\n"));
  1507. //
  1508. // We begin by retrieving the mapping for the TCP session
  1509. // to which the contained segment belongs.
  1510. //
  1511. // We need to save the key with which we will replace the
  1512. // encapsulted message's contents. When an error is inbound,
  1513. // it must have been generated in response to an outbound message,
  1514. // and the outbound message contained in the error will have in it
  1515. // the public IP address and port to which we originally translated
  1516. // the outbound message. We therefore need to put back
  1517. // the private IP address and port so that the private machine
  1518. // will be able to identify the error.
  1519. // Similarly, when the error is outbound, we need to put in
  1520. // the public IP address and port so that the remote machine
  1521. // will be able to identify the error.
  1522. //
  1523. // Onward, then. Construct the key to be used for the lookup,
  1524. // take the mapping lock, and look up forward or reverse mappings.
  1525. //
  1526. MAKE_MAPPING_KEY(
  1527. DestinationKey,
  1528. EncapsulatedIpHeader->Protocol,
  1529. EncapsulatedIpHeader->SourceAddress,
  1530. EncapsulatedHeader->SourcePort
  1531. );
  1532. MAKE_MAPPING_KEY(
  1533. SourceKey,
  1534. EncapsulatedIpHeader->Protocol,
  1535. EncapsulatedIpHeader->DestinationAddress,
  1536. EncapsulatedHeader->DestinationPort
  1537. );
  1538. KeAcquireSpinLockAtDpcLevel(&MappingLock);
  1539. if (Direction == NatInboundDirection) {
  1540. Mapping = NatLookupReverseMapping(DestinationKey, SourceKey, NULL);
  1541. if (Mapping) {
  1542. ReplacementKey = Mapping->SourceKey[NatForwardPath];
  1543. } else {
  1544. Mapping = NatLookupForwardMapping(DestinationKey, SourceKey, NULL);
  1545. if (Mapping) {
  1546. ReplacementKey = Mapping->SourceKey[NatReversePath];
  1547. }
  1548. }
  1549. } else {
  1550. Mapping = NatLookupForwardMapping(DestinationKey, SourceKey, NULL);
  1551. if (Mapping) {
  1552. ReplacementKey = Mapping->DestinationKey[NatReversePath];
  1553. } else {
  1554. Mapping = NatLookupReverseMapping(DestinationKey, SourceKey, NULL);
  1555. if (Mapping) {
  1556. ReplacementKey = Mapping->DestinationKey[NatForwardPath];
  1557. }
  1558. }
  1559. }
  1560. KeReleaseSpinLockFromDpcLevel(&MappingLock);
  1561. if (!Mapping) {
  1562. TRACE(
  1563. XLATE, (
  1564. "NatTranslateEncapsulatedRequest: no mapping for message\n"
  1565. ));
  1566. return FALSE;
  1567. }
  1568. //
  1569. // The checksum processing for encapsulated messages
  1570. // remains extremely complicated since we must update
  1571. // [0] for UDP messages, the UDP message checksum, using the change
  1572. // to the encapsulated UDP source port. (Note that this step is
  1573. // skipped if the encapsulated UDP header did not contain a
  1574. // checksum.) No corresponding change is required for TCP segments,
  1575. // whose checksum appears beyond the eight bytes included in ICMP
  1576. // error messages.
  1577. // (1) the IP header-checksum of the encapsulated TCP segment
  1578. // using the change to the encapsulated IP addresses
  1579. // (2) the ICMP checksum of the containing ICMP error message
  1580. // using both the above change as well as the change
  1581. // to the above checksum
  1582. // (3) the IP header-checksum of the containing ICMP error message
  1583. // using the change to the containing IP addresses
  1584. // Any changes to the logic below must be made with extreme care.
  1585. //
  1586. if (Direction == NatInboundDirection) {
  1587. ChecksumDelta = 0;
  1588. CHECKSUM_LONG(ChecksumDelta, ~EncapsulatedHeader->SourcePort);
  1589. EncapsulatedHeader->SourcePort = MAPPING_PORT(ReplacementKey);
  1590. CHECKSUM_LONG(ChecksumDelta, EncapsulatedHeader->SourcePort);
  1591. if (EncapsulatedIpHeader->Protocol == NAT_PROTOCOL_UDP
  1592. && 0 != EncapsulatedHeader->Checksum) {
  1593. ChecksumDelta2 = ChecksumDelta;
  1594. CHECKSUM_LONG(ChecksumDelta2, ~EncapsulatedHeader->Checksum);
  1595. CHECKSUM_UPDATE(EncapsulatedHeader->Checksum);
  1596. CHECKSUM_LONG(ChecksumDelta2, EncapsulatedHeader->Checksum);
  1597. ChecksumDelta = ChecksumDelta2;
  1598. }
  1599. CHECKSUM_UPDATE(IcmpHeader->Checksum);
  1600. ChecksumDelta = 0;
  1601. CHECKSUM_LONG(ChecksumDelta, ~EncapsulatedIpHeader->SourceAddress);
  1602. EncapsulatedIpHeader->SourceAddress = MAPPING_ADDRESS(ReplacementKey);
  1603. CHECKSUM_LONG(ChecksumDelta, EncapsulatedIpHeader->SourceAddress);
  1604. ChecksumDelta2 = ChecksumDelta;
  1605. CHECKSUM_LONG(ChecksumDelta2, ~EncapsulatedIpHeader->Checksum);
  1606. CHECKSUM_UPDATE(EncapsulatedIpHeader->Checksum);
  1607. CHECKSUM_LONG(ChecksumDelta2, EncapsulatedIpHeader->Checksum);
  1608. ChecksumDelta = ChecksumDelta2; CHECKSUM_UPDATE(IcmpHeader->Checksum);
  1609. ChecksumDelta = 0;
  1610. CHECKSUM_LONG(ChecksumDelta, ~IpHeader->DestinationAddress);
  1611. IpHeader->DestinationAddress = MAPPING_ADDRESS(ReplacementKey);
  1612. CHECKSUM_LONG(ChecksumDelta, IpHeader->DestinationAddress);
  1613. CHECKSUM_UPDATE(IpHeader->Checksum);
  1614. } else {
  1615. ChecksumDelta = 0;
  1616. CHECKSUM_LONG(ChecksumDelta, ~EncapsulatedHeader->DestinationPort);
  1617. EncapsulatedHeader->DestinationPort = MAPPING_PORT(ReplacementKey);
  1618. CHECKSUM_LONG(ChecksumDelta, EncapsulatedHeader->DestinationPort);
  1619. if (EncapsulatedIpHeader->Protocol == NAT_PROTOCOL_UDP
  1620. && 0 != EncapsulatedHeader->Checksum) {
  1621. ChecksumDelta2 = ChecksumDelta;
  1622. CHECKSUM_LONG(ChecksumDelta2, ~EncapsulatedHeader->Checksum);
  1623. CHECKSUM_UPDATE(EncapsulatedHeader->Checksum);
  1624. CHECKSUM_LONG(ChecksumDelta2, EncapsulatedHeader->Checksum);
  1625. ChecksumDelta = ChecksumDelta2;
  1626. }
  1627. CHECKSUM_UPDATE(IcmpHeader->Checksum);
  1628. ChecksumDelta = 0;
  1629. CHECKSUM_LONG(ChecksumDelta, ~EncapsulatedIpHeader->DestinationAddress);
  1630. EncapsulatedIpHeader->DestinationAddress =
  1631. MAPPING_ADDRESS(ReplacementKey);
  1632. CHECKSUM_LONG(ChecksumDelta, EncapsulatedIpHeader->DestinationAddress);
  1633. ChecksumDelta2 = ChecksumDelta;
  1634. CHECKSUM_LONG(ChecksumDelta2, ~EncapsulatedIpHeader->Checksum);
  1635. CHECKSUM_UPDATE(EncapsulatedIpHeader->Checksum);
  1636. CHECKSUM_LONG(ChecksumDelta2, EncapsulatedIpHeader->Checksum);
  1637. ChecksumDelta = ChecksumDelta2; CHECKSUM_UPDATE(IcmpHeader->Checksum);
  1638. ChecksumDelta = 0;
  1639. CHECKSUM_LONG(ChecksumDelta, ~IpHeader->SourceAddress);
  1640. IpHeader->SourceAddress = MAPPING_ADDRESS(ReplacementKey);
  1641. CHECKSUM_LONG(ChecksumDelta, IpHeader->SourceAddress);
  1642. CHECKSUM_UPDATE(IpHeader->Checksum);
  1643. }
  1644. //
  1645. // If checksum offloading is enabled on this packet, recompute the
  1646. // IP checksum. (There is no ICMP checksum-offload, so we will never
  1647. // need to fully recompute that.)
  1648. //
  1649. if (ChecksumOffloaded) {
  1650. NatComputeIpChecksum(IpHeader);
  1651. }
  1652. return TRUE;
  1653. } // NatTranslateEncapsulatedRequest