Source code of Windows XP (NT5)
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.

528 lines
12 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. raw.c
  5. Abstract:
  6. This module contains the code for manipulating IP mappings.
  7. When the NAT decides to translate an IP packet for an unrecognized protocol
  8. it creates a mapping and places it on the interface's IP-mapping list,
  9. so that if a reply to the packet arrives, it can be directed to the
  10. appropriate client.
  11. Author:
  12. Abolade Gbadegesin (aboladeg) 18-Apr-1998
  13. Revision History:
  14. Abolade Gbadegesin (aboladeg) 18-Apr-1998
  15. Based on icmp.c.
  16. --*/
  17. #include "precomp.h"
  18. #pragma hdrstop
  19. //
  20. // GLOBAL DATA DECLARATIONS
  21. //
  22. NPAGED_LOOKASIDE_LIST IpLookasideList;
  23. LIST_ENTRY IpMappingList[NatMaximumDirection];
  24. KSPIN_LOCK IpMappingLock;
  25. NTSTATUS
  26. NatCreateIpMapping(
  27. PNAT_INTERFACE Interfacep,
  28. ULONG RemoteAddress,
  29. ULONG PrivateAddress,
  30. ULONG PublicAddress,
  31. UCHAR Protocol,
  32. PLIST_ENTRY InboundInsertionPoint,
  33. PLIST_ENTRY OutboundInsertionPoint,
  34. PNAT_IP_MAPPING* MappingCreated
  35. )
  36. /*++
  37. Routine Description:
  38. Called to create, initialize, and insert an IP mapping in an interface's
  39. list of IP mappings.
  40. Arguments:
  41. Interfacep - the interface for the new mapping
  42. RemoteAddress - the address of the remote endpoint
  43. PrivateAddress - the address of the machine on the private network
  44. PublicAddress - the publicly-visible address to replace 'PrivateAddress';
  45. in case this is 0, an address is chosen in this routine.
  46. Protocol - the protocol field of the IP header
  47. InboundInsertionPoint - the entry preceding the new mapping in the list
  48. sorted for inbound searching
  49. OutboundInsertionPoint - the entry preceding the new mapping in the list
  50. sorted for outbound searching
  51. MappingCreated - receives the mapping created
  52. Return Value:
  53. NTSTATUS - indicates success/failure
  54. Environment:
  55. Invoked with 'IpMappingLock' held by the caller.
  56. --*/
  57. {
  58. PLIST_ENTRY Link;
  59. PNAT_IP_MAPPING Mapping;
  60. NTSTATUS status;
  61. PNAT_IP_MAPPING Temp;
  62. PNAT_USED_ADDRESS UsedAddress;
  63. CALLTRACE(("NatCreateIpMapping\n"));
  64. //
  65. // Allocate a new mapping
  66. //
  67. Mapping = ALLOCATE_IP_BLOCK();
  68. if (!Mapping) {
  69. ERROR(("NatCreateIpMapping: allocation failed\n"));
  70. return STATUS_NO_MEMORY;
  71. }
  72. //
  73. // Initialize the mapping
  74. //
  75. Mapping->PrivateKey = MAKE_IP_KEY(RemoteAddress, PrivateAddress);
  76. Mapping->Protocol = Protocol;
  77. //
  78. // See if the public address is specified, and if not, acquire an address
  79. //
  80. if (!PublicAddress) {
  81. //
  82. // Acquire an address mapping for the IP mapping;
  83. //
  84. KeAcquireSpinLockAtDpcLevel(&Interfacep->Lock);
  85. status =
  86. NatAcquireFromAddressPool(
  87. Interfacep,
  88. PrivateAddress,
  89. 0,
  90. &UsedAddress
  91. );
  92. if (!NT_SUCCESS(status)) {
  93. KeReleaseSpinLockFromDpcLevel(&Interfacep->Lock);
  94. TRACE(IP, ("NatCreateIpMapping: no address available\n"));
  95. FREE_IP_BLOCK(Mapping);
  96. return STATUS_UNSUCCESSFUL;
  97. }
  98. PublicAddress = UsedAddress->PublicAddress;
  99. NatDereferenceAddressPoolEntry(Interfacep, UsedAddress);
  100. KeReleaseSpinLockFromDpcLevel(&Interfacep->Lock);
  101. }
  102. Mapping->PublicKey = MAKE_IP_KEY(RemoteAddress, PublicAddress);
  103. TRACE(
  104. MAPPING,
  105. ("NatCreateIpMapping: Ip=%d:%016I64X:%016I64X\n",
  106. Mapping->Protocol, Mapping->PrivateKey, Mapping->PublicKey
  107. ));
  108. //
  109. // Insert the mapping in the inbound list
  110. //
  111. if (!InboundInsertionPoint) {
  112. Temp =
  113. NatLookupInboundIpMapping(
  114. Mapping->PrivateKey,
  115. Protocol,
  116. &InboundInsertionPoint
  117. );
  118. if (Temp) {
  119. TRACE(IP, ("NatCreateIpMapping: duplicated inbound mapping\n"));
  120. return STATUS_UNSUCCESSFUL;
  121. }
  122. }
  123. //
  124. // Insert the mapping in the outbound list
  125. //
  126. if (!OutboundInsertionPoint) {
  127. Temp =
  128. NatLookupOutboundIpMapping(
  129. Mapping->PublicKey,
  130. Protocol,
  131. &OutboundInsertionPoint
  132. );
  133. if (Temp) {
  134. TRACE(IP, ("NatCreateIpMapping: duplicated outbound mapping\n"));
  135. return STATUS_UNSUCCESSFUL;
  136. }
  137. }
  138. InsertTailList(InboundInsertionPoint, &Mapping->Link[NatInboundDirection]);
  139. InsertTailList(OutboundInsertionPoint, &Mapping->Link[NatOutboundDirection]);
  140. *MappingCreated = Mapping;
  141. return STATUS_SUCCESS;
  142. } // NatCreateIpMapping
  143. VOID
  144. NatInitializeRawIpManagement(
  145. VOID
  146. )
  147. /*++
  148. Routine Description:
  149. This routine is called to initialize the raw IP-layer translation module.
  150. Arguments:
  151. none.
  152. Return Value:
  153. none.
  154. --*/
  155. {
  156. KeInitializeSpinLock(&IpMappingLock);
  157. InitializeListHead(&IpMappingList[NatInboundDirection]);
  158. InitializeListHead(&IpMappingList[NatOutboundDirection]);
  159. ExInitializeNPagedLookasideList(
  160. &IpLookasideList,
  161. NatAllocateFunction,
  162. NULL,
  163. 0,
  164. sizeof(NAT_IP_MAPPING),
  165. NAT_TAG_IP,
  166. IP_LOOKASIDE_DEPTH
  167. );
  168. } // NatInitializeRawIpManagement
  169. PNAT_IP_MAPPING
  170. NatLookupInboundIpMapping(
  171. ULONG64 PublicKey,
  172. UCHAR Protocol,
  173. PLIST_ENTRY* InsertionPoint
  174. )
  175. /*++
  176. Routine Description:
  177. This routine is called to find an IP mapping using the remote-address
  178. and the publicly-visible address, which correspond to the 'PublicKey',
  179. and the 'Protocol' field.
  180. Arguments:
  181. PublicKey - the remote-address/public-address combination
  182. Protocol - the IP protocol of the mapping to be found
  183. InsertionPoint - receives the insertion-point if the mapping is not found.
  184. Return Value:
  185. PNAT_IP_MAPPING - the mapping found, or NULL if not found.
  186. --*/
  187. {
  188. PLIST_ENTRY Link;
  189. PNAT_IP_MAPPING Mapping;
  190. CALLTRACE(("NatLookupInboundIpMapping\n"));
  191. if (InsertionPoint) { *InsertionPoint = NULL; }
  192. for (Link = IpMappingList[NatInboundDirection].Flink;
  193. Link != &IpMappingList[NatInboundDirection]; Link = Link->Flink) {
  194. Mapping =
  195. CONTAINING_RECORD(
  196. Link, NAT_IP_MAPPING, Link[NatInboundDirection]
  197. );
  198. if (PublicKey > Mapping->PublicKey) {
  199. continue;
  200. } else if (PublicKey < Mapping->PublicKey) {
  201. break;
  202. }
  203. //
  204. // Primary keys equal; check secondary keys.
  205. //
  206. if (Protocol > Mapping->Protocol) {
  207. continue;
  208. } else if (Protocol < Mapping->Protocol) {
  209. break;
  210. }
  211. //
  212. // Secondary keys equal, too. This is the requested item.
  213. //
  214. return Mapping;
  215. }
  216. if (InsertionPoint) { *InsertionPoint = Link; }
  217. return NULL;
  218. } // NatLookupInboundIpMapping
  219. PNAT_IP_MAPPING
  220. NatLookupOutboundIpMapping(
  221. ULONG64 PrivateKey,
  222. UCHAR Protocol,
  223. PLIST_ENTRY* InsertionPoint
  224. )
  225. /*++
  226. Routine Description:
  227. This routine is called to find an IP mapping using the remote-address
  228. and the private address, which correspond to the 'PrivateKey'.
  229. Arguments:
  230. PrivateKey - the remote-address/private-address combination
  231. Protocol - the IP protocol of the mapping to be found
  232. InsertionPoint - receives insertion-point if mapping not found.
  233. Return Value:
  234. PNAT_IP_MAPPING - the mapping found, or NULL if not found.
  235. --*/
  236. {
  237. PLIST_ENTRY Link;
  238. PNAT_IP_MAPPING Mapping;
  239. CALLTRACE(("NatLookupOutboundIpMapping\n"));
  240. if (InsertionPoint) { *InsertionPoint = NULL; }
  241. for (Link = IpMappingList[NatOutboundDirection].Flink;
  242. Link != &IpMappingList[NatOutboundDirection]; Link = Link->Flink) {
  243. Mapping =
  244. CONTAINING_RECORD(
  245. Link, NAT_IP_MAPPING, Link[NatOutboundDirection]
  246. );
  247. if (PrivateKey > Mapping->PrivateKey) {
  248. continue;
  249. } else if (PrivateKey < Mapping->PrivateKey) {
  250. break;
  251. }
  252. //
  253. // Primary keys equal; check secondary keys.
  254. //
  255. if (Protocol > Mapping->Protocol) {
  256. continue;
  257. } else if (Protocol < Mapping->Protocol) {
  258. break;
  259. }
  260. //
  261. // Keys are equal, so we've found it.
  262. //
  263. return Mapping;
  264. }
  265. if (InsertionPoint) { *InsertionPoint = Link; }
  266. return NULL;
  267. } // NatLookupOutboundIpMapping
  268. VOID
  269. NatShutdownRawIpManagement(
  270. VOID
  271. )
  272. /*++
  273. Routine Description:
  274. This routine is called to clean up the raw IP-layer translation module.
  275. Arguments:
  276. none.
  277. Return Value:
  278. none.
  279. --*/
  280. {
  281. ExDeleteNPagedLookasideList(&IpLookasideList);
  282. } // NatShutdownRawIpManagement
  283. FORWARD_ACTION
  284. NatTranslateIp(
  285. PNAT_INTERFACE Interfacep,
  286. IP_NAT_DIRECTION Direction,
  287. PNAT_XLATE_CONTEXT Contextp,
  288. IPRcvBuf** InReceiveBuffer,
  289. IPRcvBuf** OutReceiveBuffer
  290. )
  291. /*++
  292. Routine Description:
  293. This routine is called to translate a IP data packet.
  294. Arguments:
  295. Interfacep - the boundary interface over which to translate.
  296. Direction - the direction in which the packet is traveling
  297. Contextp - initialized with context-information for the packet
  298. InReceiveBuffer - input buffer-chain
  299. OutReceiveBuffer - receives modified buffer-chain.
  300. Return Value:
  301. FORWARD_ACTION - indicates action to take on the packet.
  302. Environment:
  303. Invoked with a reference made to 'Interfacep' by the caller.
  304. --*/
  305. {
  306. ULONG Checksum;
  307. ULONG ChecksumDelta = 0;
  308. PIP_HEADER IpHeader;
  309. PNAT_IP_MAPPING Mapping;
  310. ULONG64 PrivateKey;
  311. ULONG64 PublicKey;
  312. BOOLEAN FirewallMode;
  313. TRACE(XLATE, ("NatTranslateIp\n"));
  314. FirewallMode = Interfacep && NAT_INTERFACE_FW(Interfacep);
  315. IpHeader = Contextp->Header;
  316. if (Direction == NatInboundDirection) {
  317. //
  318. // Look for the IP mapping for the data packet
  319. //
  320. PublicKey =
  321. MAKE_IP_KEY(
  322. Contextp->SourceAddress,
  323. Contextp->DestinationAddress
  324. );
  325. KeAcquireSpinLockAtDpcLevel(&IpMappingLock);
  326. Mapping =
  327. NatLookupInboundIpMapping(
  328. PublicKey,
  329. IpHeader->Protocol,
  330. NULL
  331. );
  332. if (!Mapping) {
  333. KeReleaseSpinLockFromDpcLevel(&IpMappingLock);
  334. return
  335. ((*Contextp->DestinationType < DEST_REMOTE) && !FirewallMode
  336. ? FORWARD : DROP);
  337. }
  338. CHECKSUM_LONG(ChecksumDelta, ~IpHeader->DestinationAddress);
  339. IpHeader->DestinationAddress = IP_KEY_PRIVATE(Mapping->PrivateKey);
  340. CHECKSUM_LONG(ChecksumDelta, IpHeader->DestinationAddress);
  341. CHECKSUM_UPDATE(IpHeader->Checksum);
  342. } else {
  343. //
  344. // Look for the IP mapping for the data packet
  345. //
  346. PrivateKey =
  347. MAKE_IP_KEY(
  348. Contextp->DestinationAddress,
  349. Contextp->SourceAddress
  350. );
  351. KeAcquireSpinLockAtDpcLevel(&IpMappingLock);
  352. Mapping =
  353. NatLookupOutboundIpMapping(
  354. PrivateKey,
  355. IpHeader->Protocol,
  356. NULL
  357. );
  358. if (!Mapping) {
  359. KeReleaseSpinLockFromDpcLevel(&IpMappingLock);
  360. return DROP;
  361. }
  362. CHECKSUM_LONG(ChecksumDelta, ~IpHeader->SourceAddress);
  363. IpHeader->SourceAddress = IP_KEY_PUBLIC(Mapping->PublicKey);
  364. CHECKSUM_LONG(ChecksumDelta, IpHeader->SourceAddress);
  365. CHECKSUM_UPDATE(IpHeader->Checksum);
  366. }
  367. KeQueryTickCount((PLARGE_INTEGER)&Mapping->LastAccessTime);
  368. KeReleaseSpinLockFromDpcLevel(&IpMappingLock);
  369. *OutReceiveBuffer = *InReceiveBuffer; *InReceiveBuffer = NULL;
  370. *Contextp->DestinationType = DEST_INVALID;
  371. return FORWARD;
  372. } // NatTranslateIp