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.

1874 lines
49 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. pool.c
  5. Abstract:
  6. This module contains code for managing the NAT's pool of addresses
  7. as well as its ranges of ports.
  8. Author:
  9. Abolade Gbadegesin (t-abolag) 13-July-1997
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #define IP_NAT_MAX_ADDRESS_RANGE (1<<16)
  15. #define IP_NAT_MAX_CLIENT_COUNT (5+2)
  16. //
  17. // Macro used to avoid the fact that RtlInitializeBitMap is pageable
  18. // and hence cannot be called at DPC-level
  19. //
  20. #define INITIALIZE_BITMAP(BMH,B,S) \
  21. ((BMH)->Buffer = (B), (BMH)->SizeOfBitMap = (S))
  22. //
  23. // FORWARD DECLARATIONS
  24. //
  25. NTSTATUS
  26. NatCreateAddressPoolEntry(
  27. PNAT_INTERFACE Interfacep,
  28. ULONG PrivateAddress,
  29. ULONG PublicAddress,
  30. DWORD InitialFlags,
  31. PNAT_USED_ADDRESS* InsertionPoint,
  32. PNAT_USED_ADDRESS* AddressCreated
  33. );
  34. PNAT_USED_ADDRESS
  35. NatInsertAddressPoolEntry(
  36. PNAT_USED_ADDRESS Parent,
  37. PNAT_USED_ADDRESS Addressp
  38. );
  39. //
  40. // ADDRESS-POOL ROUTINES (alphabetically)
  41. //
  42. NTSTATUS
  43. NatAcquireFromAddressPool(
  44. PNAT_INTERFACE Interfacep,
  45. ULONG PrivateAddress,
  46. ULONG PublicAddress OPTIONAL,
  47. PNAT_USED_ADDRESS* AddressAcquired
  48. )
  49. /*++
  50. Routine Description:
  51. This routine acquires an address from an address pool.
  52. It initializes the address's port-pool.
  53. Arguments:
  54. Interfacep - interface on which to acquire an address.
  55. PrivateAddress - private address for whom to acquire a public address
  56. PublicAddress - optionally specifies the public-address to be acquired
  57. AddressAcquired - receives a pointer to the address acquired.
  58. Return Value:
  59. NTSTATUS - status code.
  60. --*/
  61. {
  62. ULONG ClientCount;
  63. PNAT_USED_ADDRESS InsertionPoint;
  64. PLIST_ENTRY Link;
  65. PNAT_USED_ADDRESS Sharedp;
  66. NTSTATUS status;
  67. PNAT_USED_ADDRESS Usedp;
  68. CALLTRACE(("NatAcquireFromAddressPool\n"));
  69. *AddressAcquired = NULL;
  70. TRACE(
  71. POOL, ("NatAcquireFromAddressPool: acquiring for %d.%d.%d.%d\n",
  72. ADDRESS_BYTES(PrivateAddress)
  73. ));
  74. //
  75. // See if the requesting private address already has a public address
  76. //
  77. for (Link = Interfacep->UsedAddressList.Flink, ClientCount = 0;
  78. Link != &Interfacep->UsedAddressList;
  79. Link = Link->Flink, ClientCount++) {
  80. Usedp = CONTAINING_RECORD(Link, NAT_USED_ADDRESS, Link);
  81. if (Usedp->PrivateAddress == PrivateAddress &&
  82. (!PublicAddress || Usedp->PublicAddress == PublicAddress)) {
  83. break;
  84. }
  85. }
  86. if (Link != &Interfacep->UsedAddressList) {
  87. NatReferenceAddressPoolEntry(Usedp);
  88. *AddressAcquired = Usedp;
  89. return STATUS_SUCCESS;
  90. } else if (ClientCount > IP_NAT_MAX_CLIENT_COUNT &&
  91. SharedUserData->NtProductType == NtProductWinNt) {
  92. #if 0
  93. TRACE(
  94. POOL, ("NatAcquireFromAddressPool: quota exceeded (%d clients)\n",
  95. ClientCount
  96. ));
  97. return STATUS_LICENSE_QUOTA_EXCEEDED;
  98. #endif
  99. }
  100. //
  101. // Create a new entry, inserting it in the list and tree
  102. //
  103. status =
  104. NatCreateAddressPoolEntry(
  105. Interfacep,
  106. PrivateAddress,
  107. PublicAddress,
  108. 0,
  109. NULL,
  110. AddressAcquired
  111. );
  112. if (NT_SUCCESS(status)) { return STATUS_SUCCESS; }
  113. TRACE(POOL, ("NatAcquireFromAddressPool: no free addresses\n"));
  114. //
  115. // No entry was available;
  116. // if the caller specified a specific address
  117. // or if the interface has port-translation disabled,
  118. // this is a total failure.
  119. // Otherwise, we can try to find an address which we can share.
  120. //
  121. if (PublicAddress || !NAT_INTERFACE_NAPT(Interfacep)) {
  122. return STATUS_UNSUCCESSFUL;
  123. }
  124. //
  125. // Look for an address which can be shared
  126. //
  127. for (Link = Interfacep->UsedAddressList.Flink;
  128. Link != &Interfacep->UsedAddressList; Link = Link->Flink) {
  129. Usedp = CONTAINING_RECORD(Link, NAT_USED_ADDRESS, Link);
  130. //
  131. // We cannot reuse statically mapped addresses,
  132. // and we ignore placeholders while searching.
  133. //
  134. if (NAT_POOL_STATIC(Usedp) || NAT_POOL_PLACEHOLDER(Usedp)) { continue; }
  135. //
  136. // We cannot reuse an entry which would result in our tree
  137. // containing duplicate keys.
  138. //
  139. if (NatLookupAddressPoolEntry(
  140. Interfacep->UsedAddressTree,
  141. PrivateAddress,
  142. Usedp->PublicAddress,
  143. &InsertionPoint
  144. )) { continue; }
  145. break;
  146. }
  147. if (Link == &Interfacep->UsedAddressList) { return STATUS_UNSUCCESSFUL; }
  148. //
  149. // Reuse the used-address;
  150. // If it is referenced, we're sharing it.
  151. //
  152. TRACE(
  153. POOL, ("NatAcquireFromAddressPool: reusing %d.%d.%d.%d\n",
  154. ADDRESS_BYTES(Usedp->PublicAddress)
  155. ));
  156. //
  157. // Allocate and initialize a placeholder which we can find
  158. // by searching on 'PrivateAddress'
  159. //
  160. Sharedp =
  161. ExAllocatePoolWithTag(
  162. NonPagedPool,
  163. sizeof(NAT_USED_ADDRESS),
  164. NAT_TAG_USED_ADDRESS
  165. );
  166. if (!Sharedp) {
  167. ERROR(("NatAcquireFromAddressPool: allocation failed\n"));
  168. return STATUS_NO_MEMORY;
  169. }
  170. RtlZeroMemory(Sharedp, sizeof(*Sharedp));
  171. Sharedp->Flags = NAT_POOL_FLAG_PLACEHOLDER;
  172. Sharedp->PrivateAddress = PrivateAddress;
  173. Sharedp->PublicAddress = Usedp->PublicAddress;
  174. Sharedp->Key =
  175. MAKE_USED_ADDRESS_KEY(
  176. Sharedp->PrivateAddress, Sharedp->PublicAddress
  177. );
  178. Sharedp->ReferenceCount = 1;
  179. InitializeListHead(&Sharedp->Link);
  180. RtlInitializeSplayLinks(&Sharedp->SLink);
  181. InsertTailList(&Interfacep->UsedAddressList, &Sharedp->Link);
  182. Interfacep->UsedAddressTree =
  183. NatInsertAddressPoolEntry(InsertionPoint, Sharedp);
  184. //
  185. // Set the placeholder's 'SharedAddress' field
  186. // to point to the actual address containing the port-pools
  187. //
  188. Sharedp->SharedAddress = Usedp;
  189. NatReferenceAddressPoolEntry(Usedp);
  190. *AddressAcquired = Sharedp;
  191. return STATUS_SUCCESS;
  192. } // NatAcquireFromAddressPool
  193. NTSTATUS
  194. NatAcquireEndpointFromAddressPool(
  195. PNAT_INTERFACE Interfacep,
  196. ULONG64 PrivateKey,
  197. ULONG64 RemoteKey,
  198. ULONG PublicAddress OPTIONAL,
  199. USHORT PreferredPort,
  200. BOOLEAN AllowAnyPort,
  201. PNAT_USED_ADDRESS* AddressAcquired,
  202. PUSHORT PortAcquired
  203. )
  204. /*++
  205. Routine Description:
  206. This routine is called to acquire an address and port for a session.
  207. Arguments:
  208. PrivateKey - the private endpoint for the session
  209. RemoteKey - the remote endpoint for the session
  210. PublicAddress - optionally specifies the public address to be acquired
  211. PreferredPort - optionally specifies the port preferred by the caller
  212. AllowAnyPort - if TRUE, any available port can be used for the mapping
  213. if 'Portp' is not available.
  214. AddressAcquired - receives the address acquired
  215. PortAcquired - receives the port acquired
  216. Return Value:
  217. NTSTATUS - indicates success/failure.
  218. Environment:
  219. Invoked with 'MappingLock' and 'Interfacep->Lock' held by the caller.
  220. --*/
  221. {
  222. PNAT_USED_ADDRESS Addressp;
  223. USHORT StopPort;
  224. ULONG i;
  225. PLIST_ENTRY Link;
  226. USHORT Port;
  227. UCHAR Protocol;
  228. ULONG64 PublicKey;
  229. PNAT_USED_ADDRESS SharedAddress;
  230. NTSTATUS status;
  231. CALLTRACE(("NatAcquireEndpointFromAddressPool\n"));
  232. //
  233. // Acquire an address for the session
  234. //
  235. status =
  236. NatAcquireFromAddressPool(
  237. Interfacep,
  238. MAPPING_ADDRESS(PrivateKey),
  239. PublicAddress,
  240. &Addressp
  241. );
  242. if (!NT_SUCCESS(status)) { return status; }
  243. SharedAddress = Addressp;
  244. PLACEHOLDER_TO_ADDRESS(SharedAddress);
  245. //
  246. // Now look for a port range which contains the preferred port
  247. //
  248. Protocol = MAPPING_PROTOCOL(PrivateKey);
  249. if (PreferredPort) {
  250. do {
  251. //
  252. // The caller prefers that we acquire a particular port;
  253. // see if we can satisfy the request.
  254. //
  255. Port = NTOHS(PreferredPort);
  256. if (Port < NTOHS(SharedAddress->StartPort) ||
  257. Port > NTOHS(SharedAddress->EndPort)) {
  258. break;
  259. }
  260. //
  261. // The preferred port is in the current range.
  262. // See if it is in use by another mapping
  263. //
  264. MAKE_MAPPING_KEY(
  265. PublicKey,
  266. Protocol,
  267. Addressp->PublicAddress,
  268. PreferredPort
  269. );
  270. if (NatLookupReverseMapping(PublicKey, RemoteKey, NULL)) { break; }
  271. //
  272. // Now see if it is in use by a ticket
  273. //
  274. if (NatIsPortUsedByTicket(Interfacep, Protocol, PreferredPort)) {
  275. break;
  276. }
  277. //
  278. // The preferred port is available; return
  279. //
  280. *AddressAcquired = Addressp;
  281. *PortAcquired = PreferredPort;
  282. TRACE(
  283. POOL,
  284. ("NatAcquireEndpointFromAddressPool: using preferred port %d\n",
  285. NTOHS(PreferredPort)
  286. ));
  287. return STATUS_SUCCESS;
  288. } while(FALSE);
  289. //
  290. // We couldn't acquire the preferred port;
  291. // fail if no other port is acceptable.
  292. //
  293. if (!AllowAnyPort || !NAT_INTERFACE_NAPT(Interfacep)) {
  294. NatDereferenceAddressPoolEntry(Interfacep, Addressp);
  295. return STATUS_UNSUCCESSFUL;
  296. }
  297. }
  298. //
  299. // If this is for a UDP session, check to see if there is another
  300. // session with the same private endpoint. If such a session
  301. // exists we want to use the same public endpoint for this session
  302. // (unless it would create a conflict with a different existing
  303. // session).
  304. //
  305. if (NAT_PROTOCOL_UDP == MAPPING_PROTOCOL(PrivateKey)) {
  306. PNAT_DYNAMIC_MAPPING Mapping;
  307. IP_NAT_PATH Path;
  308. //
  309. // Perform a source-only mapping lookup
  310. //
  311. Mapping = NatSourceLookupForwardMapping(PrivateKey,NULL);
  312. if (NULL == Mapping) {
  313. Mapping = NatSourceLookupReverseMapping(PrivateKey,NULL);
  314. }
  315. if (NULL != Mapping) {
  316. //
  317. // There's another UDP session with this private endpoint;
  318. // if it has the same public address that we've already
  319. // acquired then use the same public port.
  320. //
  321. Path = NAT_MAPPING_INBOUND(Mapping)
  322. ? NatForwardPath
  323. : NatReversePath;
  324. if (SharedAddress->PublicAddress
  325. == MAPPING_ADDRESS(Mapping->DestinationKey[Path])) {
  326. //
  327. // Check to see if using this public endpoint would
  328. // create a conflict with an existing mapping.
  329. //
  330. Port = MAPPING_PORT(Mapping->DestinationKey[Path]);
  331. MAKE_MAPPING_KEY(
  332. PublicKey,
  333. Protocol,
  334. SharedAddress->PublicAddress,
  335. Port
  336. );
  337. if (NULL == NatLookupReverseMapping(PublicKey, RemoteKey, NULL)) {
  338. //
  339. // Same public address, and no conflict exists
  340. // -- use the port from this session.
  341. //
  342. *AddressAcquired = Addressp;
  343. *PortAcquired = Port;
  344. TRACE(
  345. POOL,
  346. ("NatAcquireEndpointFromAddressPool: reusing UDP port %d\n",
  347. NTOHS(Port)
  348. ));
  349. return STATUS_SUCCESS;
  350. }
  351. }
  352. }
  353. }
  354. //
  355. // Acquire the first available port for the session
  356. //
  357. if (SharedAddress->NextPortToTry != SharedAddress->StartPort) {
  358. StopPort =
  359. RtlUshortByteSwap(
  360. (USHORT)(NTOHS(SharedAddress->NextPortToTry) - 1)
  361. );
  362. } else {
  363. StopPort = SharedAddress->EndPort;
  364. }
  365. for (Port = SharedAddress->NextPortToTry; Port != StopPort;
  366. Port = (Port != SharedAddress->EndPort
  367. ? RtlUshortByteSwap((USHORT)(NTOHS(Port) + 1))
  368. : SharedAddress->StartPort)) {
  369. //
  370. // See if this port is in use by a mapping
  371. //
  372. MAKE_MAPPING_KEY(PublicKey, Protocol, Addressp->PublicAddress, Port);
  373. if (NatLookupReverseMapping(PublicKey, RemoteKey, NULL)) { continue; }
  374. //
  375. // Now see if it is in use by a ticket
  376. //
  377. if (NatIsPortUsedByTicket(Interfacep, Protocol, Port)) { continue; }
  378. //
  379. // The port is available; return
  380. //
  381. *AddressAcquired = Addressp;
  382. *PortAcquired = Port;
  383. //
  384. // Update the address pool entry with the port with which to
  385. // start the search on the next allocation attempt.
  386. //
  387. if (Port == SharedAddress->EndPort) {
  388. SharedAddress->NextPortToTry = SharedAddress->StartPort;
  389. } else {
  390. SharedAddress->NextPortToTry =
  391. RtlUshortByteSwap(
  392. (USHORT)(NTOHS(Port) + 1)
  393. );
  394. }
  395. TRACE(
  396. POOL, ("NatAcquireEndpointFromAddressPool: using port %d\n",
  397. NTOHS(Port)
  398. ));
  399. return STATUS_SUCCESS;
  400. }
  401. //
  402. // We were unable to acquire a port for the session; fail.
  403. //
  404. NatDereferenceAddressPoolEntry(Interfacep, Addressp);
  405. TRACE(POOL, ("NatAcquireEndpointFromAddressPool: no ports available\n"));
  406. return STATUS_UNSUCCESSFUL;
  407. } // NatAcquireEndpointFromAddressPool
  408. NTSTATUS
  409. NatCreateAddressPool(
  410. PNAT_INTERFACE Interfacep
  411. )
  412. /*++
  413. Routine Description:
  414. This routine initializes an interface's address-pool.
  415. This involves setting up the bitmap of free addresses
  416. and reserving the statically mapped IP addresses.
  417. Arguments:
  418. Interfacep - the interface on which to create the address pool.
  419. Return Value:
  420. NTSTATUS - status code
  421. --*/
  422. {
  423. ULONG Address;
  424. BOOLEAN Changed;
  425. PNAT_FREE_ADDRESS FreeMapArray;
  426. ULONG FreeMapCount;
  427. PNAT_FREE_ADDRESS Freep;
  428. ULONG i;
  429. PNAT_USED_ADDRESS InsertionPoint;
  430. ULONG j;
  431. PRTL_SPLAY_LINKS Parent;
  432. PIP_NAT_ADDRESS_RANGE* RangeArrayIndirect;
  433. NTSTATUS status;
  434. PNAT_USED_ADDRESS Usedp;
  435. CALLTRACE(("NatCreateAddressPool\n"));
  436. if (Interfacep->AddressRangeCount <= 1) {
  437. RangeArrayIndirect = &Interfacep->AddressRangeArray;
  438. } else {
  439. //
  440. // Allocate a temporary block of pointers
  441. // to be used to do an indirect sort of the range-array.
  442. //
  443. RangeArrayIndirect =
  444. (PIP_NAT_ADDRESS_RANGE*)ExAllocatePoolWithTag(
  445. NonPagedPool,
  446. Interfacep->AddressRangeCount * sizeof(PVOID),
  447. NAT_TAG_RANGE_ARRAY
  448. );
  449. if (!RangeArrayIndirect) {
  450. ERROR(("NatCreateAddressPool: error allocating sort-buffer\n"));
  451. return STATUS_NO_MEMORY;
  452. }
  453. for (i = 0; i < Interfacep->AddressRangeCount; i++) {
  454. RangeArrayIndirect[i] = &Interfacep->AddressRangeArray[i];
  455. }
  456. do {
  457. //
  458. // Now do a bubble-sort of the ranges
  459. //
  460. Changed = FALSE;
  461. for (i = 0; i < Interfacep->AddressRangeCount - 1; i++) {
  462. PIP_NAT_ADDRESS_RANGE CurrentRange = RangeArrayIndirect[i];
  463. ULONG CurrentRangeStartAddress =
  464. RtlUlongByteSwap(CurrentRange->StartAddress);
  465. PIP_NAT_ADDRESS_RANGE NextRange;
  466. for (j = i+1, NextRange = RangeArrayIndirect[j];
  467. j < Interfacep->AddressRangeCount;
  468. j++, NextRange = RangeArrayIndirect[j]) {
  469. //
  470. // Do a swap if necessary
  471. //
  472. if (CurrentRangeStartAddress <=
  473. RtlUlongByteSwap(NextRange->StartAddress)) { continue; }
  474. RangeArrayIndirect[i] = NextRange;
  475. RangeArrayIndirect[j] = CurrentRange;
  476. CurrentRange = NextRange;
  477. CurrentRangeStartAddress =
  478. RtlUlongByteSwap(NextRange->StartAddress);
  479. Changed = TRUE;
  480. }
  481. }
  482. } while (Changed);
  483. }
  484. //
  485. // Copy the ranges into NAT_FREE_ADDRESS blocks.
  486. // There will be at most 'RangeCount' of these,
  487. // and possibly less, since we will merge any ranges
  488. // which overlap or are adjacent.
  489. //
  490. FreeMapCount = 0;
  491. if (!Interfacep->AddressRangeCount) {
  492. FreeMapArray = NULL;
  493. } else {
  494. FreeMapArray =
  495. (PNAT_FREE_ADDRESS)ExAllocatePoolWithTag(
  496. NonPagedPool,
  497. Interfacep->AddressRangeCount * sizeof(NAT_FREE_ADDRESS),
  498. NAT_TAG_FREE_MAP
  499. );
  500. if (!FreeMapArray) {
  501. ExFreePool(RangeArrayIndirect);
  502. return STATUS_NO_MEMORY;
  503. }
  504. }
  505. for (i = 0, j = 0; i < Interfacep->AddressRangeCount; i++) {
  506. ULONG RangeStartAddress =
  507. RtlUlongByteSwap(RangeArrayIndirect[i]->StartAddress);
  508. //
  509. // See if we should merge with the preceding block;
  510. //
  511. if (FreeMapCount) {
  512. //
  513. // Incrementing the end-address of the preceding range
  514. // enables us to catch both overlaps and adjacencies.
  515. //
  516. if (RangeStartAddress <=
  517. RtlUlongByteSwap(FreeMapArray[j].EndAddress) + 1) {
  518. //
  519. // We need to merge.
  520. //
  521. if (RtlUlongByteSwap(FreeMapArray[j].EndAddress) <
  522. RtlUlongByteSwap(RangeArrayIndirect[i]->EndAddress)) {
  523. FreeMapArray[j].EndAddress =
  524. RangeArrayIndirect[i]->EndAddress;
  525. }
  526. if (RtlUlongByteSwap(FreeMapArray[j].SubnetMask) <
  527. RtlUlongByteSwap(RangeArrayIndirect[i]->SubnetMask)) {
  528. FreeMapArray[j].SubnetMask =
  529. RangeArrayIndirect[i]->SubnetMask;
  530. }
  531. continue;
  532. }
  533. //
  534. // No merge; move to next slot.
  535. //
  536. ++j;
  537. }
  538. FreeMapArray[j].StartAddress = RangeArrayIndirect[i]->StartAddress;
  539. FreeMapArray[j].EndAddress = RangeArrayIndirect[i]->EndAddress;
  540. FreeMapArray[j].SubnetMask = RangeArrayIndirect[i]->SubnetMask;
  541. FreeMapCount++;
  542. }
  543. if (Interfacep->AddressRangeCount > 1) { ExFreePool(RangeArrayIndirect); }
  544. //
  545. // Now we have an array of disjoint, non-adjacent address-ranges;
  546. // Initialize the bitmap for each address-range.
  547. //
  548. for (i = 0; i < FreeMapCount; i++) {
  549. //
  550. // We can't allocate large enough bitmaps to support huge ranges;
  551. // for instance, if the address pool is 128.0.0.0-128.255.255.255,
  552. // the corresponding bitmap would have 2^24 bits, or 2MB.
  553. // For now, shrink all ranges to allow at most 2^16 bits, or 8K.
  554. //
  555. j = RtlUlongByteSwap(FreeMapArray[i].EndAddress) -
  556. RtlUlongByteSwap(FreeMapArray[i].StartAddress) + 1;
  557. if (j >= IP_NAT_MAX_ADDRESS_RANGE) {
  558. ERROR(("NatCreateAddressPool: shrinking %d-bit bitmap\n", j));
  559. //
  560. // Resize the range
  561. //
  562. FreeMapArray[i].EndAddress =
  563. RtlUlongByteSwap(
  564. RtlUlongByteSwap(FreeMapArray[i].StartAddress) +
  565. IP_NAT_MAX_ADDRESS_RANGE
  566. );
  567. j = IP_NAT_MAX_ADDRESS_RANGE;
  568. }
  569. //
  570. // Allocate a bitmap for the range
  571. //
  572. FreeMapArray[i].Bitmap =
  573. (PRTL_BITMAP)ExAllocatePoolWithTag(
  574. NonPagedPool,
  575. sizeof(RTL_BITMAP) +
  576. (j + sizeof(ULONG) * 8 - 1) / sizeof(ULONG) * 8,
  577. NAT_TAG_BITMAP
  578. );
  579. if (!FreeMapArray[i].Bitmap) {
  580. ERROR(("NatCreateAddressPool: error allocating bitmap\n"));
  581. while ((LONG)--i >= 0) { ExFreePool(FreeMapArray[i].Bitmap); }
  582. ExFreePool(FreeMapArray);
  583. return STATUS_NO_MEMORY;
  584. }
  585. INITIALIZE_BITMAP(
  586. FreeMapArray[i].Bitmap, (PULONG)(FreeMapArray[i].Bitmap + 1), j
  587. );
  588. RtlClearAllBits(FreeMapArray[i].Bitmap);
  589. }
  590. status = STATUS_SUCCESS;
  591. Interfacep->FreeMapArray = FreeMapArray;
  592. Interfacep->FreeMapCount = FreeMapCount;
  593. //
  594. // Create address-pool entries for each local address
  595. //
  596. for (i = 0; i < Interfacep->AddressCount; i++) {
  597. TRACE(
  598. POOL, ("NatCreateAddressPool: address %d.%d.%d.%d\n",
  599. ADDRESS_BYTES(Interfacep->AddressArray[i].Address))
  600. );
  601. status =
  602. NatCreateAddressPoolEntry(
  603. Interfacep,
  604. Interfacep->AddressArray[i].Address,
  605. Interfacep->AddressArray[i].Address,
  606. NAT_POOL_FLAG_BINDING,
  607. NULL,
  608. &Usedp
  609. );
  610. if (!NT_SUCCESS(status)) { break; }
  611. }
  612. //
  613. // Creating address-pool entries for each statically-mapped address
  614. //
  615. for (i = 0; i < Interfacep->AddressMappingCount; i++) {
  616. TRACE(
  617. POOL, ("NatCreateAddressPool: mapping %d.%d.%d.%d\n",
  618. ADDRESS_BYTES(Interfacep->AddressMappingArray[i].PrivateAddress))
  619. );
  620. status =
  621. NatCreateAddressPoolEntry(
  622. Interfacep,
  623. Interfacep->AddressMappingArray[i].PrivateAddress,
  624. Interfacep->AddressMappingArray[i].PublicAddress,
  625. NAT_POOL_FLAG_STATIC,
  626. NULL,
  627. &Usedp
  628. );
  629. if (!NT_SUCCESS(status)) { break; }
  630. Usedp->AddressMapping = &Interfacep->AddressMappingArray[i];
  631. }
  632. //
  633. // Create address-pool entries for statically-mapped port's address
  634. //
  635. for (i = Interfacep->PortMappingCount; i > 0; i--) {
  636. status =
  637. NatCreateStaticPortMapping(
  638. Interfacep,
  639. &Interfacep->PortMappingArray[i - 1]
  640. );
  641. if (!NT_SUCCESS(status)) { break; }
  642. }
  643. if (!NT_SUCCESS(status)) {
  644. //
  645. // An error occurred. Restore the original state.
  646. //
  647. NatDeleteAddressPool(Interfacep);
  648. return status;
  649. }
  650. return STATUS_SUCCESS;
  651. } // NatCreateAddressPool
  652. NTSTATUS
  653. NatCreateAddressPoolEntry(
  654. PNAT_INTERFACE Interfacep,
  655. ULONG PrivateAddress,
  656. ULONG PublicAddress,
  657. DWORD InitialFlags,
  658. PNAT_USED_ADDRESS* InsertionPoint,
  659. PNAT_USED_ADDRESS* AddressCreated
  660. )
  661. /*++
  662. Routine Description:
  663. This routine creates, initializes and inserts an address pool entry.
  664. Arguments:
  665. Interfacep - theinterface on which to create the entry.
  666. PrivateAddress - the address of the private machine using the address
  667. PublicAddress - the address for the entry, or 0 to allocate any address.
  668. InitialFlags - initial flags for the address-entry, as follows:
  669. NAT_POOL_FLAG_BINDING - if set, the address-entry is treated as
  670. a binding-entry
  671. NAT_POOL_FLAG_STATIC - if set, the address-entry corresponds to
  672. a static mapping
  673. InsertionPoint - optionally supplies the point where the entry
  674. should be inserted in the tree.
  675. AddressCreated - receives the entry created, or the existing entry
  676. if there is a collision.
  677. Return Value:
  678. NTSTATUS - success/failure code.
  679. --*/
  680. {
  681. ULONG ClassMask;
  682. ULONG Hint;
  683. ULONG HostOrderPublicAddress;
  684. ULONG i;
  685. ULONG Index;
  686. PNAT_USED_ADDRESS Insert;
  687. NTSTATUS status = STATUS_SUCCESS;
  688. PNAT_USED_ADDRESS Usedp;
  689. CALLTRACE(("NatCreateAddressPoolEntry\n"));
  690. *AddressCreated = NULL;
  691. if (PublicAddress) {
  692. HostOrderPublicAddress = RtlUlongByteSwap(PublicAddress);
  693. }
  694. //
  695. // Find the free-map which contains this binding, if any.
  696. //
  697. Index = (ULONG)-1;
  698. for (i = 0; i < Interfacep->FreeMapCount; i++) {
  699. //
  700. // See if we're supposed to be looking for a free address
  701. //
  702. if (!PublicAddress) {
  703. //
  704. // See if this free-map has any free addresses.
  705. //
  706. for (Hint = 0; ; Hint = Index + 1) {
  707. Index =
  708. RtlFindClearBits(
  709. Interfacep->FreeMapArray[i].Bitmap, 1, Hint
  710. );
  711. if (Index == (ULONG)-1) { break; }
  712. //
  713. // We've got a free address.
  714. // Make sure it isn't a prohibited address
  715. // (i.e. having 0 or all-ones in the subnet host portion).
  716. //
  717. PublicAddress =
  718. RtlUlongByteSwap(
  719. Index +
  720. RtlUlongByteSwap(
  721. Interfacep->FreeMapArray[i].StartAddress
  722. ));
  723. ClassMask = GET_CLASS_MASK(PublicAddress);
  724. if ((PublicAddress &
  725. ~Interfacep->FreeMapArray[i].SubnetMask) == 0 ||
  726. (PublicAddress & ~Interfacep->FreeMapArray[i].SubnetMask) ==
  727. ~Interfacep->FreeMapArray[i].SubnetMask ||
  728. (PublicAddress & ~ClassMask) == 0 ||
  729. (PublicAddress & ~ClassMask) == ~ClassMask) {
  730. //
  731. // The address is prohibited.
  732. // Mark it as unavailable so we don't waste time
  733. // looking at it ever again.
  734. //
  735. RtlSetBits(Interfacep->FreeMapArray[i].Bitmap, Index, 1);
  736. PublicAddress = 0; continue;
  737. }
  738. //
  739. // The address is not prohibited
  740. //
  741. break;
  742. }
  743. //
  744. // Go on to the next free-map if this one was of no use
  745. //
  746. if (Index == (ULONG)-1) { continue; }
  747. //
  748. // We found an address in the current free-map;
  749. // go on to initialize a used-address entry
  750. //
  751. break;
  752. }
  753. //
  754. // We're not looking for just any free-address;
  755. // We're looking for the free-map of a particular address.
  756. // See if the current free-map contains the address in question.
  757. //
  758. if (HostOrderPublicAddress >
  759. RtlUlongByteSwap(Interfacep->FreeMapArray[i].EndAddress)) {
  760. continue;
  761. } else {
  762. Index = RtlUlongByteSwap(Interfacep->FreeMapArray[i].StartAddress);
  763. if (HostOrderPublicAddress < Index) {
  764. Index = (ULONG)-1;
  765. continue;
  766. }
  767. }
  768. //
  769. // This is the free-map we want.
  770. // See if the address is prohibited, and if so fail.
  771. //
  772. Index = HostOrderPublicAddress - Index;
  773. if ((PublicAddress & ~Interfacep->FreeMapArray[i].SubnetMask) == 0 ||
  774. (PublicAddress & ~Interfacep->FreeMapArray[i].SubnetMask) ==
  775. ~Interfacep->FreeMapArray[i].SubnetMask) {
  776. //
  777. // The address is prohibited. Mark it so we don't waste time
  778. // looking at it ever again.
  779. //
  780. RtlSetBits(Interfacep->FreeMapArray[i].Bitmap, Index, 1);
  781. TRACE(POOL, ("NatCreateAddressPoolEntry: bad address requested\n"));
  782. return STATUS_UNSUCCESSFUL;
  783. }
  784. break;
  785. }
  786. if (!PublicAddress) {
  787. //
  788. // We couldn't find a free address.
  789. //
  790. TRACE(POOL, ("NatCreateAddressPoolEntry: no free addresses\n"));
  791. return STATUS_UNSUCCESSFUL;
  792. }
  793. //
  794. // Find the insertion point in the used-tree.
  795. //
  796. if (!InsertionPoint) {
  797. InsertionPoint = &Insert;
  798. Usedp =
  799. NatLookupAddressPoolEntry(
  800. Interfacep->UsedAddressTree,
  801. PrivateAddress,
  802. PublicAddress,
  803. InsertionPoint
  804. );
  805. if (Usedp) {
  806. //
  807. // This private-address already has a mapping; fail.
  808. //
  809. TRACE(POOL, ("NatCreateAddressPoolEntry: duplicate mapping\n"));
  810. return STATUS_UNSUCCESSFUL;
  811. }
  812. }
  813. //
  814. // Allocate a new entry for the new address
  815. //
  816. Usedp =
  817. ExAllocatePoolWithTag(
  818. NonPagedPool,
  819. sizeof(NAT_USED_ADDRESS),
  820. NAT_TAG_USED_ADDRESS
  821. );
  822. if (!Usedp) {
  823. ERROR(("NatCreateAddressPoolEntry: allocation failed\n"));
  824. return STATUS_NO_MEMORY;
  825. }
  826. RtlZeroMemory(Usedp, sizeof(*Usedp));
  827. Usedp->PrivateAddress = PrivateAddress;
  828. Usedp->PublicAddress = PublicAddress;
  829. Usedp->Key = MAKE_USED_ADDRESS_KEY(PrivateAddress, PublicAddress);
  830. Usedp->Flags = InitialFlags;
  831. Usedp->ReferenceCount = 1;
  832. InitializeListHead(&Usedp->Link);
  833. RtlInitializeSplayLinks(&Usedp->SLink);
  834. if (NAT_POOL_BINDING(Usedp)) {
  835. Usedp->StartPort = ReservedPortsLowerRange;
  836. Usedp->EndPort = ReservedPortsUpperRange;
  837. } else {
  838. Usedp->StartPort = NTOHS(1);
  839. Usedp->EndPort = NTOHS(65534);
  840. }
  841. Usedp->NextPortToTry = Usedp->StartPort;
  842. //
  843. // Insert the entry in the splay tree and list.
  844. //
  845. InsertTailList(&Interfacep->UsedAddressList, &Usedp->Link);
  846. Interfacep->UsedAddressTree =
  847. NatInsertAddressPoolEntry(*InsertionPoint, Usedp);
  848. //
  849. // Update the free-map
  850. //
  851. if (Index != (ULONG)-1) {
  852. RtlSetBits(Interfacep->FreeMapArray[i].Bitmap, Index, 1);
  853. }
  854. *AddressCreated = Usedp;
  855. return STATUS_SUCCESS;
  856. }
  857. NTSTATUS
  858. NatCreateStaticPortMapping(
  859. PNAT_INTERFACE Interfacep,
  860. PIP_NAT_PORT_MAPPING PortMapping
  861. )
  862. /*++
  863. Routine Description:
  864. This routine creates a static port mapping (i.e., persistent
  865. ticket) on an interace
  866. Arguments:
  867. Interfacep - the interface on which to create the port mapping.
  868. PortMapping - describes the port mapping to be created.
  869. Return Value:
  870. NTSTATUS - status code
  871. Environment:
  872. Invoked with Interfacep->Lock held by the caller.
  873. --*/
  874. {
  875. PNAT_USED_ADDRESS InsertionPoint;
  876. ULONG PublicAddress;
  877. USHORT PublicPort;
  878. NTSTATUS status;
  879. PNAT_TICKET Ticketp;
  880. PNAT_USED_ADDRESS Usedp;
  881. CALLTRACE(("NatCreateStaticPortMapping\n"));
  882. //
  883. // The handling of the static port-mapping depends upon whether
  884. // its public address is for the interface or from the address-pool.
  885. // If the 'PublicAddress' is zero, then the port-mapping refers
  886. // to sessions destined for the interface's actual address.
  887. // Otherwise, the port-mapping refers to sessions destined for
  888. // an address in the interface's address pool.
  889. //
  890. if (!PortMapping->PublicAddress) {
  891. status =
  892. NatAcquireFromAddressPool(
  893. Interfacep,
  894. PortMapping->PrivateAddress,
  895. 0,
  896. &Usedp
  897. );
  898. } else {
  899. Usedp =
  900. NatLookupAddressPoolEntry(
  901. Interfacep->UsedAddressTree,
  902. PortMapping->PrivateAddress,
  903. PortMapping->PublicAddress,
  904. &InsertionPoint
  905. );
  906. if (Usedp) {
  907. status = STATUS_SUCCESS;
  908. NatReferenceAddressPoolEntry(Usedp);
  909. } else {
  910. //
  911. // The mapping was not in use, so we need to create an
  912. // entry for its address.
  913. //
  914. status =
  915. NatCreateAddressPoolEntry(
  916. Interfacep,
  917. PortMapping->PrivateAddress,
  918. PortMapping->PublicAddress,
  919. 0,
  920. &InsertionPoint,
  921. &Usedp
  922. );
  923. }
  924. }
  925. //
  926. // Now create a ticket which will direct all incoming sessions
  927. // to the private endpoint specified in the static port-mapping.
  928. //
  929. if (NT_SUCCESS(status)) {
  930. status =
  931. NatCreateTicket(
  932. Interfacep,
  933. PortMapping->Protocol,
  934. PortMapping->PrivateAddress,
  935. PortMapping->PrivatePort,
  936. 0,
  937. 0,
  938. NAT_TICKET_FLAG_PORT_MAPPING|NAT_TICKET_FLAG_PERSISTENT,
  939. Usedp,
  940. PortMapping->PublicPort,
  941. &PublicAddress,
  942. &PublicPort
  943. );
  944. NatDereferenceAddressPoolEntry(Interfacep, Usedp);
  945. }
  946. return status;
  947. }// NatCreateStaticPortMapping
  948. NTSTATUS
  949. NatDeleteAddressPool(
  950. PNAT_INTERFACE Interfacep
  951. )
  952. /*++
  953. Routine Description:
  954. Destroys an address pool, freeing the memory used by the free-maps
  955. and optionally, the used-address entries.
  956. Arguments:
  957. Interfacep - the interface whose address pool is to be deleted.
  958. Return Value:
  959. NTSTATUS - status code.
  960. --*/
  961. {
  962. ULONG i;
  963. PLIST_ENTRY Link;
  964. PNAT_TICKET Ticketp;
  965. PNAT_USED_ADDRESS Usedp;
  966. CALLTRACE(("NatDeleteAddressPool\n"));
  967. //
  968. // Dispose of the free-maps
  969. //
  970. for (i = 0; i < Interfacep->FreeMapCount; i++) {
  971. if (Interfacep->FreeMapArray[i].Bitmap) {
  972. ExFreePool(Interfacep->FreeMapArray[i].Bitmap);
  973. }
  974. }
  975. Interfacep->FreeMapCount = 0;
  976. if (Interfacep->FreeMapArray) { ExFreePool(Interfacep->FreeMapArray); }
  977. Interfacep->FreeMapArray = NULL;
  978. //
  979. // Clear out port-mappings created as tickets
  980. //
  981. for (Link = Interfacep->TicketList.Flink; Link != &Interfacep->TicketList;
  982. Link = Link->Flink) {
  983. Ticketp = CONTAINING_RECORD(Link, NAT_TICKET, Link);
  984. if (!NAT_TICKET_PORT_MAPPING(Ticketp)) { continue; }
  985. Link = Link->Blink;
  986. NatDeleteTicket(Interfacep, Ticketp);
  987. }
  988. //
  989. // Deal with the used-list;
  990. //
  991. while (!IsListEmpty(&Interfacep->UsedAddressList)) {
  992. Link = RemoveHeadList(&Interfacep->UsedAddressList);
  993. Usedp = CONTAINING_RECORD(Link, NAT_USED_ADDRESS, Link);
  994. Usedp->Flags |= NAT_POOL_FLAG_DELETED;
  995. NatDereferenceAddressPoolEntry(Interfacep, Usedp);
  996. }
  997. Interfacep->UsedAddressTree = NULL;
  998. return STATUS_SUCCESS;
  999. } // NatDeleteAddressPool
  1000. PNAT_USED_ADDRESS
  1001. NatInsertAddressPoolEntry(
  1002. PNAT_USED_ADDRESS Parent,
  1003. PNAT_USED_ADDRESS Addressp
  1004. )
  1005. /*++
  1006. Routine Description:
  1007. This routine is called to insert an address in the interface's
  1008. splay-tree of address-pool entries. The key is the 'PrivateAddress'
  1009. field of the address-pool entry.
  1010. Arguments:
  1011. Parent - the parent of the entry to be inserted, which may be obtained
  1012. from NatLookupAddressPoolEntry
  1013. Addressp - the address pool entry to be inserted
  1014. Return Value:
  1015. The new root of the splay tree if successful, NULL otherwise.
  1016. --*/
  1017. {
  1018. ULONG64 Key;
  1019. PRTL_SPLAY_LINKS Root;
  1020. CALLTRACE(("NatInsertAddressPoolEntry\n"));
  1021. if (!Parent) {
  1022. TRACE(POOL, ("NatInsertAddressPoolEntry: inserting as root\n"));
  1023. return Addressp;
  1024. }
  1025. //
  1026. // Insert as left or right child
  1027. //
  1028. Key =
  1029. MAKE_USED_ADDRESS_KEY(Addressp->PrivateAddress,Addressp->PublicAddress);
  1030. if (Addressp->Key < Parent->Key) {
  1031. RtlInsertAsLeftChild(&Parent->SLink, &Addressp->SLink);
  1032. } else if (Addressp->Key > Parent->Key) {
  1033. RtlInsertAsRightChild(&Parent->SLink, &Addressp->SLink);
  1034. } else {
  1035. //
  1036. // Keys are equal; fail.
  1037. //
  1038. ERROR((
  1039. "NatInsertAddressPoolEntry: collision on key 0x%016I64X\n",
  1040. Addressp->Key
  1041. ));
  1042. return NULL;
  1043. }
  1044. //
  1045. // Splay the new node and return the resulting root.
  1046. //
  1047. Root = RtlSplay(&Addressp->SLink);
  1048. return CONTAINING_RECORD(Root, NAT_USED_ADDRESS, SLink);
  1049. } // NatInsertAddressPoolEntry
  1050. PNAT_USED_ADDRESS
  1051. NatLookupAddressPoolEntry(
  1052. PNAT_USED_ADDRESS Root,
  1053. ULONG PrivateAddress,
  1054. ULONG PublicAddress,
  1055. PNAT_USED_ADDRESS* InsertionPoint
  1056. )
  1057. /*++
  1058. Routine Description:
  1059. This routine searches the interface's splay tree of address-pool entries
  1060. for a particular entry, returning the entry if found, otherwise supplying
  1061. the insertion point for the entry.
  1062. Arguments:
  1063. Root - the root of the splay tree ('Interfacep->UsedAddressTree').
  1064. PrivateAddress - the private part of the address-mapping to be looked up
  1065. PublicAddress - the public part of the address-mapping to be looked up
  1066. InsertionPoint - receives the insertion point for the entry
  1067. Return Value:
  1068. The entry if found, NULL otherwise.
  1069. --*/
  1070. {
  1071. PNAT_USED_ADDRESS Addressp;
  1072. ULONG64 Key;
  1073. PNAT_USED_ADDRESS Parent = NULL;
  1074. PRTL_SPLAY_LINKS SLink;
  1075. TRACE(PER_PACKET, ("NatLookupAddressPoolEntry\n"));
  1076. Key = MAKE_USED_ADDRESS_KEY(PrivateAddress, PublicAddress);
  1077. for (SLink = !Root ? NULL : &Root->SLink; SLink; ) {
  1078. Addressp = CONTAINING_RECORD(SLink, NAT_USED_ADDRESS, SLink);
  1079. if (Key < Addressp->Key) {
  1080. Parent = Addressp;
  1081. SLink = RtlLeftChild(SLink);
  1082. continue;
  1083. } else if (Key > Addressp->Key) {
  1084. Parent = Addressp;
  1085. SLink = RtlRightChild(SLink);
  1086. continue;
  1087. }
  1088. //
  1089. // Private-addresses match; we got it.
  1090. //
  1091. return Addressp;
  1092. }
  1093. //
  1094. // We didn't get it; tell the caller where to insert it.
  1095. //
  1096. if (InsertionPoint) { *InsertionPoint = Parent; }
  1097. return NULL;
  1098. } // NatLookupAddressPoolEntry
  1099. PNAT_USED_ADDRESS
  1100. NatLookupStaticAddressPoolEntry(
  1101. PNAT_INTERFACE Interfacep,
  1102. ULONG PublicAddress,
  1103. BOOLEAN RequireInboundSessions
  1104. )
  1105. /*++
  1106. Routine Description:
  1107. This routine is invoked to search for an address pool entry
  1108. which is marked static and which corresponds to the given public address.
  1109. Arguments:
  1110. Interfacep - the interface whose address pool is to be searched
  1111. PublicAddress - the public address for which to search
  1112. RequireInboundSessions - if TRUE, a match is declared only if
  1113. the entry found allows inbound sessions.
  1114. Return Value:
  1115. PNAT_USED_ADDRESS - the address pool entry found, if any.
  1116. --*/
  1117. {
  1118. ULONG i;
  1119. PNAT_USED_ADDRESS Addressp;
  1120. PIP_NAT_ADDRESS_MAPPING AddressMapping;
  1121. if (!Interfacep->AddressMappingCount) {
  1122. return NULL;
  1123. } else {
  1124. //
  1125. // Perform exhaustive search since static address-mappings
  1126. // are sorted by private address rather than public address.
  1127. //
  1128. AddressMapping = NULL;
  1129. for (i = 0; i < Interfacep->AddressMappingCount; i++) {
  1130. if (PublicAddress !=
  1131. Interfacep->AddressMappingArray[i].PublicAddress) {
  1132. continue;
  1133. }
  1134. AddressMapping = &Interfacep->AddressMappingArray[i];
  1135. break;
  1136. }
  1137. }
  1138. if (!AddressMapping ||
  1139. !(Addressp =
  1140. NatLookupAddressPoolEntry(
  1141. Interfacep->UsedAddressTree,
  1142. AddressMapping->PrivateAddress,
  1143. AddressMapping->PublicAddress,
  1144. NULL
  1145. )) ||
  1146. !NAT_POOL_STATIC(Addressp) ||
  1147. (RequireInboundSessions && !AddressMapping->AllowInboundSessions)) {
  1148. return NULL;
  1149. }
  1150. return Addressp;
  1151. } // NatLookupStaticAddressPoolEntry
  1152. NTSTATUS
  1153. NatDereferenceAddressPoolEntry(
  1154. PNAT_INTERFACE Interfacep,
  1155. PNAT_USED_ADDRESS AddressToRelease
  1156. )
  1157. /*++
  1158. Routine Description:
  1159. Drops the reference count on an address pool entry.
  1160. This routine invalidates the supplied NAT_USED_ADDRESS pointer.
  1161. Note, though, that it might not be freed, e.g. in the case where
  1162. the address is being shared.
  1163. If the entry is a placeholder and its reference count drops to zero,
  1164. we also drop the reference count of its target ('SharedAddress') entry.
  1165. N.B. If the entry is marked 'deleted', we ignore the 'Interfacep' argument
  1166. since the entry must have been already removed from its interface's
  1167. address pool.
  1168. Arguments:
  1169. Interfacep - the interface whose address pool is to be deleted.
  1170. AddressToRelease - contains a pointer to the address to be released.
  1171. Return Value:
  1172. NTSTATUS - status code.
  1173. --*/
  1174. {
  1175. ULONG HostOrderPublicAddress;
  1176. ULONG i;
  1177. ULONG Index;
  1178. PRTL_SPLAY_LINKS SLink;
  1179. PNAT_USED_ADDRESS Usedp = AddressToRelease;
  1180. CALLTRACE(("NatDereferenceAddressPoolEntry\n"));
  1181. if (NAT_POOL_PLACEHOLDER(Usedp)) {
  1182. //
  1183. // Do nothing if there are other references to the placeholder
  1184. //
  1185. if (InterlockedDecrement(&Usedp->ReferenceCount)) {
  1186. return STATUS_SUCCESS;
  1187. }
  1188. //
  1189. // Unlink and free the placeholder
  1190. //
  1191. if (!NAT_POOL_DELETED(Usedp)) {
  1192. RemoveEntryList(&Usedp->Link);
  1193. SLink = RtlDelete(&Usedp->SLink);
  1194. Interfacep->UsedAddressTree =
  1195. !SLink
  1196. ? NULL
  1197. : CONTAINING_RECORD(SLink, NAT_USED_ADDRESS, SLink);
  1198. }
  1199. //
  1200. // Move on to the shared-address
  1201. //
  1202. Usedp = Usedp->SharedAddress;
  1203. ExFreePool(AddressToRelease);
  1204. }
  1205. //
  1206. // Do nothing if there are others sharing this address
  1207. //
  1208. if (InterlockedDecrement(&Usedp->ReferenceCount)) { return STATUS_SUCCESS; }
  1209. if (!NAT_POOL_DELETED(Usedp)) {
  1210. //
  1211. // Marking the entry's address as free in the interface's bitmap.
  1212. //
  1213. Index = Usedp->PublicAddress;
  1214. HostOrderPublicAddress = RtlUlongByteSwap(Usedp->PublicAddress);
  1215. for (i = 0; i < Interfacep->FreeMapCount; i++) {
  1216. if (HostOrderPublicAddress <
  1217. RtlUlongByteSwap(Interfacep->FreeMapArray[i].StartAddress) ||
  1218. HostOrderPublicAddress >
  1219. RtlUlongByteSwap(Interfacep->FreeMapArray[i].EndAddress)) {
  1220. continue;
  1221. }
  1222. Index =
  1223. HostOrderPublicAddress -
  1224. RtlUlongByteSwap(Interfacep->FreeMapArray[i].StartAddress);
  1225. RtlClearBits(Interfacep->FreeMapArray[i].Bitmap, Index, 1);
  1226. break;
  1227. }
  1228. //
  1229. // Now we're done; just unlink and free the used-address block
  1230. //
  1231. RemoveEntryList(&Usedp->Link);
  1232. SLink = RtlDelete(&Usedp->SLink);
  1233. Interfacep->UsedAddressTree =
  1234. !SLink ? NULL : CONTAINING_RECORD(SLink, NAT_USED_ADDRESS, SLink);
  1235. }
  1236. ExFreePool(Usedp);
  1237. return STATUS_SUCCESS;
  1238. } // NatDereferenceAddressPoolEntry
  1239. //
  1240. // PORT-POOL ROUTINES (alphabetically)
  1241. //
  1242. NTSTATUS
  1243. NatAcquireFromPortPool(
  1244. PNAT_INTERFACE Interfacep,
  1245. PNAT_USED_ADDRESS Addressp,
  1246. UCHAR Protocol,
  1247. USHORT PreferredPort,
  1248. PUSHORT PortAcquired
  1249. )
  1250. /*++
  1251. Routine Description:
  1252. This routine is invoked to acquire a unique public port from the pool.
  1253. The port acquired is guaranteed to not be in use by any mapping.
  1254. This is needed, for instance, when we are obtaining a port for a ticket
  1255. to be created by an editor for a dynamically negotiated session.
  1256. Arguments:
  1257. Interfacep - the interface on which to acquire the port
  1258. Addressp - the address on which to acquire the port
  1259. Protocol - the protocol for which to acquire the port
  1260. PreferredPort - the port preferred by the caller
  1261. PortAcquired - receives the port acquired
  1262. Return Value:
  1263. NTSTATUS - success/failure code.
  1264. Environment:
  1265. Invoked with 'MappingLock' and 'Interfacep->Lock' held by the caller.
  1266. --*/
  1267. {
  1268. #define QUERY_PUBLIC_PORT(m,p) \
  1269. NatQueryInformationMapping((m),NULL,NULL,NULL,NULL,NULL,NULL,p,NULL)
  1270. USHORT EndPort;
  1271. ULONG i;
  1272. PLIST_ENTRY Link;
  1273. PNAT_DYNAMIC_MAPPING Mapping;
  1274. USHORT Port;
  1275. USHORT PublicPort;
  1276. PNAT_USED_ADDRESS SharedAddress;
  1277. CALLTRACE(("NatAcquireFromPortPool\n"));
  1278. SharedAddress = Addressp;
  1279. PLACEHOLDER_TO_ADDRESS(SharedAddress);
  1280. //
  1281. // First attempt to satisfy the caller's preference
  1282. //
  1283. if (PreferredPort) {
  1284. //
  1285. // The caller prefers that we acquire a particular port;
  1286. // see if we can satisfy the request.
  1287. //
  1288. do {
  1289. Port = NTOHS(PreferredPort);
  1290. if (Port < NTOHS(SharedAddress->StartPort) ||
  1291. Port > NTOHS(SharedAddress->EndPort)) {
  1292. break;
  1293. }
  1294. //
  1295. // The preferred port is in the current range.
  1296. // See if it is in use by another mapping
  1297. //
  1298. KeAcquireSpinLockAtDpcLevel(&InterfaceMappingLock);
  1299. for (Link = Interfacep->MappingList.Flink;
  1300. Link != &Interfacep->MappingList; Link = Link->Flink) {
  1301. Mapping =
  1302. CONTAINING_RECORD(Link, NAT_DYNAMIC_MAPPING, InterfaceLink);
  1303. QUERY_PUBLIC_PORT(Mapping, &PublicPort);
  1304. if (PreferredPort == PublicPort) { break; }
  1305. }
  1306. if (Link != &Interfacep->MappingList) {
  1307. KeReleaseSpinLockFromDpcLevel(&InterfaceMappingLock);
  1308. break;
  1309. }
  1310. KeReleaseSpinLockFromDpcLevel(&InterfaceMappingLock);
  1311. //
  1312. // Now see if it is in use by a ticket
  1313. //
  1314. if (NatIsPortUsedByTicket(Interfacep, Protocol, PreferredPort)) {
  1315. break;
  1316. }
  1317. //
  1318. // The preferred port is available; return
  1319. //
  1320. TRACE(
  1321. POOL,
  1322. ("NatAcquireFromPortPool: using preferred port %d\n",
  1323. NTOHS(PreferredPort)
  1324. ));
  1325. *PortAcquired = PreferredPort;
  1326. return STATUS_SUCCESS;
  1327. } while(FALSE);
  1328. //
  1329. // We couldn't acquire the preferred port;
  1330. // fail if no other port is acceptable.
  1331. //
  1332. if (!NAT_INTERFACE_NAPT(Interfacep)) {
  1333. TRACE(
  1334. POOL,
  1335. ("NatAcquireFromPortPool: unable to use preferred port %d\n",
  1336. NTOHS(PreferredPort)
  1337. ));
  1338. return STATUS_UNSUCCESSFUL;
  1339. }
  1340. }
  1341. //
  1342. // Search the port pool, looking for a port which
  1343. // (a) is not already in use by any mapping, and
  1344. // (b) is not already in use by any ticket.
  1345. //
  1346. EndPort = RtlUshortByteSwap((USHORT)(NTOHS(SharedAddress->EndPort) + 1));
  1347. for (Port = SharedAddress->StartPort; Port != EndPort;
  1348. Port = RtlUshortByteSwap((USHORT)(NTOHS(Port) + 1))) {
  1349. //
  1350. // Look through the interface's mappings
  1351. //
  1352. KeAcquireSpinLockAtDpcLevel(&InterfaceMappingLock);
  1353. for (Link = Interfacep->MappingList.Flink;
  1354. Link != &Interfacep->MappingList; Link = Link->Flink) {
  1355. Mapping =
  1356. CONTAINING_RECORD(Link, NAT_DYNAMIC_MAPPING, InterfaceLink);
  1357. QUERY_PUBLIC_PORT(Mapping, &PublicPort);
  1358. if (Port == PublicPort) { break; }
  1359. }
  1360. if (Link != &Interfacep->MappingList) {
  1361. KeReleaseSpinLockFromDpcLevel(&InterfaceMappingLock);
  1362. continue;
  1363. }
  1364. KeReleaseSpinLockFromDpcLevel(&InterfaceMappingLock);
  1365. //
  1366. // No mapping is using the public-port;
  1367. // Now see if any ticket is using the public port
  1368. //
  1369. if (NatIsPortUsedByTicket(Interfacep, Protocol, Port)) { continue; }
  1370. //
  1371. // The port is not in use by any mapping or ticket; we're done.
  1372. //
  1373. TRACE(
  1374. POOL, ("NatAcquireFromPortPool: acquiring port %d\n",
  1375. NTOHS(Port)
  1376. ));
  1377. *PortAcquired = Port;
  1378. return STATUS_SUCCESS;
  1379. }
  1380. TRACE(POOL, ("NatAcquireFromPortPool: no available ports\n"));
  1381. return STATUS_UNSUCCESSFUL;
  1382. } // NatAcquireFromPortPool