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.

2143 lines
49 KiB

  1. /*++
  2. Copyright (c) 1998, Microsoft Corporation
  3. Module Name:
  4. natio.h
  5. Abstract:
  6. This module contains declarations for the NAT's I/O interface
  7. to the kernel-mode driver.
  8. Author:
  9. Abolade Gbadegesin (aboladeg) 10-Mar-1998
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #pragma hdrstop
  14. #include <ras.h>
  15. #include <rasuip.h>
  16. #include <raserror.h>
  17. //
  18. // PRIVATE GLOBAL VARIABLES
  19. //
  20. HANDLE NatFileHandle;
  21. LIST_ENTRY NatInterfaceList;
  22. //
  23. // Controls access to 'NatFileHandle' and 'NatInterfaceList'.
  24. //
  25. CRITICAL_SECTION NatInterfaceLock;
  26. //
  27. // FORWARD DECLARATIONS
  28. //
  29. VOID
  30. NatpDisableLoadDriverPrivilege(
  31. PBOOLEAN WasEnabled
  32. );
  33. BOOLEAN
  34. NatpEnableLoadDriverPrivilege(
  35. PBOOLEAN WasEnabled
  36. );
  37. PNAT_INTERFACE
  38. NatpLookupInterface(
  39. ULONG Index,
  40. OUT PLIST_ENTRY* InsertionPoint OPTIONAL
  41. );
  42. ULONG
  43. NatBindInterface(
  44. ULONG Index,
  45. PNAT_INTERFACE Interfacep OPTIONAL,
  46. PIP_ADAPTER_BINDING_INFO BindingInfo,
  47. ULONG AdapterIndex
  48. )
  49. /*++
  50. Routine Description:
  51. This routine is invoked to bind the NAT to an interface.
  52. Arguments:
  53. Index - the interface to be bound
  54. Interfacep - optionally supplies the interface-structure to be bound
  55. (See 'NATCONN.C' which passes in a static interface-structure).
  56. BindingInfo - the interface's address-information
  57. AdapterIndex - optionally specifies the interface's TCP/IP adapter index.
  58. This is set only for home-router interfaces.
  59. Return Value:
  60. ULONG - Win32 status code.
  61. --*/
  62. {
  63. PIP_NAT_CREATE_INTERFACE CreateInterface;
  64. ULONG Error;
  65. IO_STATUS_BLOCK IoStatus;
  66. ULONG Size;
  67. NTSTATUS status;
  68. HANDLE WaitEvent;
  69. PROFILE("NatBindInterface");
  70. Error = NO_ERROR;
  71. //
  72. // Look up the interface to be bound
  73. //
  74. EnterCriticalSection(&NatInterfaceLock);
  75. if (!Interfacep && !(Interfacep = NatpLookupInterface(Index, NULL))) {
  76. LeaveCriticalSection(&NatInterfaceLock);
  77. NhTrace(
  78. TRACE_FLAG_NAT,
  79. "NatBindInterface: interface %d not found",
  80. Index
  81. );
  82. return ERROR_NO_SUCH_INTERFACE;
  83. }
  84. //
  85. // Make sure the interface isn't already bound
  86. //
  87. if (NAT_INTERFACE_BOUND(Interfacep)) {
  88. LeaveCriticalSection(&NatInterfaceLock);
  89. NhTrace(
  90. TRACE_FLAG_NAT,
  91. "NatBindInterface: interface %d is already bound",
  92. Index
  93. );
  94. return ERROR_ADDRESS_ALREADY_ASSOCIATED;
  95. }
  96. //
  97. // Allocate the bind-structure
  98. //
  99. Size =
  100. sizeof(IP_NAT_CREATE_INTERFACE) +
  101. SIZEOF_IP_BINDING(BindingInfo->AddressCount);
  102. CreateInterface = reinterpret_cast<PIP_NAT_CREATE_INTERFACE>(
  103. NH_ALLOCATE(Size));
  104. if (!CreateInterface) {
  105. LeaveCriticalSection(&NatInterfaceLock);
  106. NhTrace(
  107. TRACE_FLAG_NAT,
  108. "NatBindInterface: allocation failed for interface %d binding",
  109. Index
  110. );
  111. NhErrorLog(
  112. IP_NAT_LOG_ALLOCATION_FAILED,
  113. 0,
  114. "%d",
  115. Size
  116. );
  117. return ERROR_NOT_ENOUGH_MEMORY;
  118. }
  119. Interfacep->AdapterIndex =
  120. (AdapterIndex != (ULONG)-1)
  121. ? AdapterIndex
  122. : NhMapInterfaceToAdapter(Interfacep->Index);
  123. if (Interfacep->AdapterIndex == (ULONG)-1) {
  124. LeaveCriticalSection(&NatInterfaceLock);
  125. NhTrace(
  126. TRACE_FLAG_NAT,
  127. "NatBindInterface: NhMapInterfaceToAdapter failed for %d",
  128. Index
  129. );
  130. return ERROR_INVALID_INDEX;
  131. }
  132. CreateInterface->Index = Interfacep->AdapterIndex;
  133. CopyMemory(
  134. CreateInterface->BindingInfo,
  135. BindingInfo,
  136. SIZEOF_IP_BINDING(BindingInfo->AddressCount)
  137. );
  138. WaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  139. if (WaitEvent == NULL) {
  140. LeaveCriticalSection(&NatInterfaceLock);
  141. NhTrace(
  142. TRACE_FLAG_NAT,
  143. "NatBindInterface: CreateEvent failed [%d] for interface %d",
  144. GetLastError(),
  145. Index
  146. );
  147. return ERROR_NOT_ENOUGH_MEMORY;
  148. }
  149. //
  150. // Install the interface
  151. //
  152. status =
  153. NtDeviceIoControlFile(
  154. NatFileHandle,
  155. WaitEvent,
  156. NULL,
  157. NULL,
  158. &IoStatus,
  159. IOCTL_IP_NAT_CREATE_INTERFACE,
  160. (PVOID)CreateInterface,
  161. Size,
  162. NULL,
  163. 0
  164. );
  165. if (status == STATUS_PENDING) {
  166. WaitForSingleObject(WaitEvent, INFINITE);
  167. status = IoStatus.Status;
  168. }
  169. NH_FREE(CreateInterface);
  170. if (!NT_SUCCESS(status)) {
  171. CloseHandle(WaitEvent);
  172. LeaveCriticalSection(&NatInterfaceLock);
  173. NhTrace(
  174. TRACE_FLAG_NAT,
  175. "NatBindInterface: status %08x binding interface %d",
  176. status,
  177. Index
  178. );
  179. Error = RtlNtStatusToDosError(status);
  180. NhErrorLog(
  181. IP_NAT_LOG_IOCTL_FAILED,
  182. Error,
  183. ""
  184. );
  185. return Error;
  186. }
  187. //
  188. // Now set its configuration
  189. //
  190. Interfacep->Info->Index = Interfacep->AdapterIndex;
  191. Size =
  192. FIELD_OFFSET(IP_NAT_INTERFACE_INFO, Header) +
  193. Interfacep->Info->Header.Size;
  194. status =
  195. NtDeviceIoControlFile(
  196. NatFileHandle,
  197. WaitEvent,
  198. NULL,
  199. NULL,
  200. &IoStatus,
  201. IOCTL_IP_NAT_SET_INTERFACE_INFO,
  202. (PVOID)Interfacep->Info,
  203. Size,
  204. NULL,
  205. 0
  206. );
  207. if (status == STATUS_PENDING) {
  208. WaitForSingleObject(WaitEvent, INFINITE);
  209. status = IoStatus.Status;
  210. }
  211. if (!NT_SUCCESS(status)) {
  212. ULONG AdapterIndex = Interfacep->AdapterIndex;
  213. LeaveCriticalSection(&NatInterfaceLock);
  214. NhTrace(
  215. TRACE_FLAG_NAT,
  216. "NatBindInterface: status %08x setting info for interface %d (%d)",
  217. status,
  218. Index,
  219. AdapterIndex
  220. );
  221. Error = RtlNtStatusToDosError(status);
  222. NhErrorLog(
  223. IP_NAT_LOG_IOCTL_FAILED,
  224. Error,
  225. ""
  226. );
  227. status =
  228. NtDeviceIoControlFile(
  229. NatFileHandle,
  230. WaitEvent,
  231. NULL,
  232. NULL,
  233. &IoStatus,
  234. IOCTL_IP_NAT_DELETE_INTERFACE,
  235. (PVOID)&AdapterIndex,
  236. sizeof(ULONG),
  237. NULL,
  238. 0
  239. );
  240. if (status == STATUS_PENDING) {
  241. WaitForSingleObject(WaitEvent, INFINITE);
  242. status = IoStatus.Status;
  243. }
  244. CloseHandle(WaitEvent);
  245. return Error;
  246. }
  247. Interfacep->Flags |= NAT_INTERFACE_FLAG_BOUND;
  248. if (Interfacep->Type == ROUTER_IF_TYPE_DEDICATED) {
  249. NatUpdateProxyArp(Interfacep, TRUE);
  250. }
  251. CloseHandle(WaitEvent);
  252. LeaveCriticalSection(&NatInterfaceLock);
  253. return Error;
  254. } // NatBindInterface
  255. ULONG
  256. NatConfigureDriver(
  257. PIP_NAT_GLOBAL_INFO GlobalInfo
  258. )
  259. /*++
  260. Routine Description:
  261. This routine is called to update the configuration for the NAT driver.
  262. Arguments:
  263. GlobalInfo - the new configuration for the NAT.
  264. Return Value:
  265. ULONG - Win32 status code.
  266. --*/
  267. {
  268. ULONG Error = NO_ERROR;
  269. IO_STATUS_BLOCK IoStatus;
  270. NTSTATUS status;
  271. HANDLE WaitEvent;
  272. PROFILE("NatConfigureDriver");
  273. WaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  274. if (WaitEvent == NULL) {
  275. NhTrace(
  276. TRACE_FLAG_NAT,
  277. "NatConfigureDriver: CreateEvent failed [%d]",
  278. GetLastError()
  279. );
  280. return ERROR_NOT_ENOUGH_MEMORY;
  281. }
  282. //
  283. // Attempt to configure the driver
  284. //
  285. EnterCriticalSection(&NatInterfaceLock);
  286. status =
  287. NtDeviceIoControlFile(
  288. NatFileHandle,
  289. WaitEvent,
  290. NULL,
  291. NULL,
  292. &IoStatus,
  293. IOCTL_IP_NAT_SET_GLOBAL_INFO,
  294. (PVOID)GlobalInfo,
  295. FIELD_OFFSET(IP_NAT_GLOBAL_INFO, Header) + GlobalInfo->Header.Size,
  296. NULL,
  297. 0
  298. );
  299. if (status == STATUS_PENDING) {
  300. WaitForSingleObject(WaitEvent, INFINITE);
  301. status = IoStatus.Status;
  302. }
  303. LeaveCriticalSection(&NatInterfaceLock);
  304. if (!NT_SUCCESS(status)) {
  305. NhTrace(
  306. TRACE_FLAG_NAT,
  307. "NatConfigureDriver: status %08x setting global info",
  308. status
  309. );
  310. Error = RtlNtStatusToDosError(status);
  311. NhErrorLog(
  312. IP_NAT_LOG_IOCTL_FAILED,
  313. Error,
  314. ""
  315. );
  316. }
  317. CloseHandle(WaitEvent);
  318. return Error;
  319. } // NatConfigureDriver
  320. ULONG
  321. NatConfigureInterface(
  322. ULONG Index,
  323. PIP_NAT_INTERFACE_INFO InterfaceInfo
  324. )
  325. /*++
  326. Routine Description:
  327. This routine is invoked to set the configuration for a NAT interface.
  328. Arguments:
  329. Index - the interface to be configured
  330. InterfaceInfo - the configuration for the interface
  331. Return Value:
  332. ULONG - Win32 status code.
  333. --*/
  334. {
  335. ULONG Error;
  336. PIP_NAT_INTERFACE_INFO Info;
  337. PNAT_INTERFACE Interfacep;
  338. IO_STATUS_BLOCK IoStatus;
  339. ULONG Size;
  340. NTSTATUS status;
  341. PROFILE("NatConfigureInterface");
  342. if (!InterfaceInfo) {
  343. NhTrace(
  344. TRACE_FLAG_NAT,
  345. "NatConfigureInterface: no interface info for %d",
  346. Index
  347. );
  348. return ERROR_INVALID_PARAMETER;
  349. }
  350. //
  351. // Make a copy of the information
  352. //
  353. Size =
  354. FIELD_OFFSET(IP_NAT_INTERFACE_INFO, Header) +
  355. InterfaceInfo->Header.Size;
  356. Info = (PIP_NAT_INTERFACE_INFO)NH_ALLOCATE(Size);
  357. if (!Info) {
  358. NhTrace(
  359. TRACE_FLAG_NAT,
  360. "NatConfigureInterface: error allocating copy of configuration"
  361. );
  362. NhErrorLog(
  363. IP_NAT_LOG_ALLOCATION_FAILED,
  364. 0,
  365. "%d",
  366. Size
  367. );
  368. return ERROR_NOT_ENOUGH_MEMORY;
  369. }
  370. CopyMemory(
  371. Info,
  372. InterfaceInfo,
  373. Size
  374. );
  375. //
  376. // Look up the interface to be configured
  377. //
  378. EnterCriticalSection(&NatInterfaceLock);
  379. if (!(Interfacep = NatpLookupInterface(Index, NULL))) {
  380. LeaveCriticalSection(&NatInterfaceLock);
  381. NhTrace(
  382. TRACE_FLAG_NAT,
  383. "NatConfigureInterface: interface %d not found",
  384. Index
  385. );
  386. NH_FREE(Info);
  387. return ERROR_NO_SUCH_INTERFACE;
  388. }
  389. //
  390. // See if the configuration changed
  391. //
  392. if ((Size ==
  393. FIELD_OFFSET(IP_NAT_INTERFACE_INFO, Header) +
  394. Interfacep->Info->Header.Size) &&
  395. memcmp(InterfaceInfo, Interfacep->Info, Size) == 0
  396. ) {
  397. LeaveCriticalSection(&NatInterfaceLock);
  398. NhTrace(
  399. TRACE_FLAG_NAT,
  400. "NatConfigureInterface: no change to interface %d configuration",
  401. Index
  402. );
  403. NH_FREE(Info);
  404. return NO_ERROR;
  405. }
  406. //
  407. // See if the interface is bound;
  408. // if so we need to update the kernel-mode driver's configuration.
  409. //
  410. if (!NAT_INTERFACE_BOUND(Interfacep)) {
  411. status = STATUS_SUCCESS;
  412. } else {
  413. HANDLE WaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  414. if (WaitEvent != NULL) {
  415. Info->Index = Interfacep->AdapterIndex;
  416. //
  417. // Attempt to configure the interface
  418. //
  419. status =
  420. NtDeviceIoControlFile(
  421. NatFileHandle,
  422. WaitEvent,
  423. NULL,
  424. NULL,
  425. &IoStatus,
  426. IOCTL_IP_NAT_SET_INTERFACE_INFO,
  427. (PVOID)Info,
  428. Size,
  429. NULL,
  430. 0
  431. );
  432. if (status == STATUS_PENDING) {
  433. WaitForSingleObject(WaitEvent, INFINITE);
  434. status = IoStatus.Status;
  435. }
  436. CloseHandle(WaitEvent);
  437. } else {
  438. status = STATUS_UNSUCCESSFUL;
  439. NhTrace(
  440. TRACE_FLAG_NAT,
  441. "NatConfigureInterface: CreateEvent failed [%d]",
  442. GetLastError()
  443. );
  444. }
  445. }
  446. if (!NT_SUCCESS(status)) {
  447. NH_FREE(Info);
  448. NhTrace(
  449. TRACE_FLAG_NAT,
  450. "NatConfigureInterface: status %08x setting interface info",
  451. status
  452. );
  453. Error = RtlNtStatusToDosError(status);
  454. NhErrorLog(
  455. IP_NAT_LOG_IOCTL_FAILED,
  456. Error,
  457. ""
  458. );
  459. } else {
  460. Error = NO_ERROR;
  461. //
  462. // Update proxy ARP entries for LAN interfaces
  463. //
  464. if (NAT_INTERFACE_BOUND(Interfacep) &&
  465. Interfacep->Type == ROUTER_IF_TYPE_DEDICATED
  466. ) {
  467. NatUpdateProxyArp(Interfacep, FALSE);
  468. }
  469. if (Interfacep->Info) { NH_FREE(Interfacep->Info); }
  470. Interfacep->Info = Info;
  471. if (NAT_INTERFACE_BOUND(Interfacep) &&
  472. Interfacep->Type == ROUTER_IF_TYPE_DEDICATED
  473. ) {
  474. NatUpdateProxyArp(Interfacep, TRUE);
  475. }
  476. }
  477. LeaveCriticalSection(&NatInterfaceLock);
  478. if (NT_SUCCESS(status)) {
  479. if (InterfaceInfo->Flags & IP_NAT_INTERFACE_FLAGS_BOUNDARY) {
  480. NhSignalNatInterface(
  481. Index,
  482. TRUE
  483. );
  484. } else {
  485. NhSignalNatInterface(
  486. Index,
  487. FALSE
  488. );
  489. }
  490. }
  491. return Error;
  492. } // NatConfigureInterface
  493. ULONG
  494. NatCreateInterface(
  495. ULONG Index,
  496. NET_INTERFACE_TYPE Type,
  497. PIP_NAT_INTERFACE_INFO InterfaceInfo
  498. )
  499. /*++
  500. Routine Description:
  501. This routine is invoked to create an interface with the NAT driver.
  502. Arguments:
  503. Index - the index of the new interface
  504. InterfaceInfo - the configuration for the new interface
  505. Return Value:
  506. ULONG - Win32 status code.
  507. --*/
  508. {
  509. ULONG Error;
  510. PIP_NAT_INTERFACE_INFO Info;
  511. PLIST_ENTRY InsertionPoint;
  512. PNAT_INTERFACE Interfacep;
  513. IO_STATUS_BLOCK IoStatus;
  514. ULONG Size;
  515. NTSTATUS status;
  516. ROUTER_INTERFACE_TYPE IfType;
  517. PROFILE("NatCreateInterface");
  518. if (!InterfaceInfo) {
  519. NhTrace(
  520. TRACE_FLAG_NAT,
  521. "NatCreateInterface: no interface info for %d",
  522. Index
  523. );
  524. return ERROR_INVALID_PARAMETER;
  525. }
  526. //
  527. // Check for the interface in our table
  528. //
  529. EnterCriticalSection(&NatInterfaceLock);
  530. if (NatpLookupInterface(Index, &InsertionPoint)) {
  531. LeaveCriticalSection(&NatInterfaceLock);
  532. NhTrace(
  533. TRACE_FLAG_NAT,
  534. "NatCreateInterface: interface %d already exists",
  535. Index
  536. );
  537. return ERROR_INTERFACE_ALREADY_EXISTS;
  538. }
  539. //
  540. // Allocate a new interface
  541. //
  542. Interfacep =
  543. reinterpret_cast<PNAT_INTERFACE>(NH_ALLOCATE(sizeof(NAT_INTERFACE)));
  544. if (!Interfacep) {
  545. LeaveCriticalSection(&NatInterfaceLock);
  546. NhTrace(
  547. TRACE_FLAG_NAT,
  548. "NatCreateInterface: error allocating interface"
  549. );
  550. NhErrorLog(
  551. IP_NAT_LOG_ALLOCATION_FAILED,
  552. 0,
  553. "%d",
  554. sizeof(NAT_INTERFACE)
  555. );
  556. return ERROR_NOT_ENOUGH_MEMORY;
  557. }
  558. //
  559. // Make a copy of the information
  560. //
  561. Size =
  562. FIELD_OFFSET(IP_NAT_INTERFACE_INFO, Header) +
  563. InterfaceInfo->Header.Size;
  564. Info = (PIP_NAT_INTERFACE_INFO)NH_ALLOCATE(Size);
  565. if (!Info) {
  566. LeaveCriticalSection(&NatInterfaceLock);
  567. NH_FREE(Interfacep);
  568. NhTrace(
  569. TRACE_FLAG_NAT,
  570. "NatCreateInterface: error allocating copy of configuration"
  571. );
  572. return ERROR_NOT_ENOUGH_MEMORY;
  573. }
  574. CopyMemory(
  575. Info,
  576. InterfaceInfo,
  577. Size
  578. );
  579. //
  580. // Initialize the new interface
  581. //
  582. ZeroMemory(Interfacep, sizeof(*Interfacep));
  583. Interfacep->Index = Index;
  584. Interfacep->AdapterIndex = (ULONG)-1;
  585. Interfacep->Type = IfType =
  586. ((Type == PERMANENT)
  587. ? ROUTER_IF_TYPE_DEDICATED
  588. : ROUTER_IF_TYPE_FULL_ROUTER);
  589. Interfacep->Info = Info;
  590. InsertTailList(InsertionPoint, &Interfacep->Link);
  591. LeaveCriticalSection(&NatInterfaceLock);
  592. if (InterfaceInfo->Flags & IP_NAT_INTERFACE_FLAGS_BOUNDARY) {
  593. NhSignalNatInterface(
  594. Index,
  595. TRUE
  596. );
  597. } else {
  598. NhSignalNatInterface(
  599. Index,
  600. FALSE
  601. );
  602. }
  603. return NO_ERROR;
  604. } // NatCreateInterface
  605. ULONG
  606. NatCreateTicket(
  607. ULONG InterfaceIndex,
  608. UCHAR Protocol,
  609. USHORT PublicPort,
  610. ULONG PublicAddress,
  611. USHORT PrivatePort,
  612. ULONG PrivateAddress
  613. )
  614. /*++
  615. Routine Description:
  616. This routine is invoked to add a ticket (static port mapping)
  617. to an interface.
  618. Arguments:
  619. InterfaceIndex - the interface to which to add the ticket
  620. Protocol, PublicPort, PublicAddress, PrivatePort, PrivateAddress -
  621. describes the ticket to be created
  622. Return Value:
  623. ULONG - Win32 status code.
  624. --*/
  625. {
  626. IP_NAT_CREATE_TICKET CreateTicket;
  627. ULONG Error;
  628. IO_STATUS_BLOCK IoStatus;
  629. NTSTATUS status;
  630. HANDLE WaitEvent;
  631. PROFILE("NatCreateTicket");
  632. WaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  633. if (WaitEvent == NULL) {
  634. NhTrace(
  635. TRACE_FLAG_NAT,
  636. "NatCreateTicket: CreateEvent failed [%d]",
  637. GetLastError()
  638. );
  639. return ERROR_NOT_ENOUGH_MEMORY;
  640. }
  641. CreateTicket.InterfaceIndex = InterfaceIndex;
  642. CreateTicket.PortMapping.Protocol = Protocol;
  643. CreateTicket.PortMapping.PublicPort = PublicPort;
  644. CreateTicket.PortMapping.PublicAddress = PublicAddress;
  645. CreateTicket.PortMapping.PrivatePort = PrivatePort;
  646. CreateTicket.PortMapping.PrivateAddress = PrivateAddress;
  647. EnterCriticalSection(&NatInterfaceLock);
  648. status =
  649. NtDeviceIoControlFile(
  650. NatFileHandle,
  651. WaitEvent,
  652. NULL,
  653. NULL,
  654. &IoStatus,
  655. IOCTL_IP_NAT_CREATE_TICKET,
  656. (PVOID)&CreateTicket,
  657. sizeof(CreateTicket),
  658. NULL,
  659. 0
  660. );
  661. LeaveCriticalSection(&NatInterfaceLock);
  662. if (status == STATUS_PENDING) {
  663. WaitForSingleObject(WaitEvent, INFINITE);
  664. status = IoStatus.Status;
  665. }
  666. if (NT_SUCCESS(status)) {
  667. Error = NO_ERROR;
  668. } else {
  669. Error = RtlNtStatusToDosError(status);
  670. NhTrace(
  671. TRACE_FLAG_NAT,
  672. "NatCreateTicket: Ioctl = %d",
  673. Error
  674. );
  675. }
  676. CloseHandle(WaitEvent);
  677. return Error;
  678. } // NatCreateTicket
  679. ULONG
  680. NatDeleteInterface(
  681. ULONG Index
  682. )
  683. /*++
  684. Routine Description:
  685. This routine is invoked to remove an interface from the NAT.
  686. Arguments:
  687. Index - the interface to be removed
  688. Return Value:
  689. ULONG - Win32 status code.
  690. --*/
  691. {
  692. ULONG Error;
  693. PNAT_INTERFACE Interfacep;
  694. IO_STATUS_BLOCK IoStatus;
  695. NTSTATUS status;
  696. HANDLE WaitEvent;
  697. PROFILE("NatDeleteInterface");
  698. WaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  699. if (WaitEvent == NULL) {
  700. NhTrace(
  701. TRACE_FLAG_NAT,
  702. "NatDeleteInterface: CreateEvent failed [%d]",
  703. GetLastError()
  704. );
  705. return ERROR_NOT_ENOUGH_MEMORY;
  706. }
  707. //
  708. // Retrieve the interface to be deleted.
  709. //
  710. EnterCriticalSection(&NatInterfaceLock);
  711. if (!(Interfacep = NatpLookupInterface(Index, NULL))) {
  712. LeaveCriticalSection(&NatInterfaceLock);
  713. CloseHandle(WaitEvent);
  714. NhTrace(
  715. TRACE_FLAG_NAT,
  716. "NatDeleteInterface: interface %d not found",
  717. Index
  718. );
  719. return ERROR_NO_SUCH_INTERFACE;
  720. }
  721. Error = NO_ERROR;
  722. if (NAT_INTERFACE_BOUND(Interfacep)) {
  723. //
  724. // Delete the interface from the kernel-mode driver
  725. //
  726. status =
  727. NtDeviceIoControlFile(
  728. NatFileHandle,
  729. WaitEvent,
  730. NULL,
  731. NULL,
  732. &IoStatus,
  733. IOCTL_IP_NAT_DELETE_INTERFACE,
  734. (PVOID)&Interfacep->AdapterIndex,
  735. sizeof(ULONG),
  736. NULL,
  737. 0
  738. );
  739. if (status == STATUS_PENDING) {
  740. WaitForSingleObject(WaitEvent, INFINITE);
  741. status = IoStatus.Status;
  742. }
  743. if (NT_SUCCESS(status)) {
  744. Error = NO_ERROR;
  745. } else {
  746. Error = RtlNtStatusToDosError(status);
  747. NhErrorLog(
  748. IP_NAT_LOG_IOCTL_FAILED,
  749. Error,
  750. ""
  751. );
  752. }
  753. }
  754. CloseHandle(WaitEvent);
  755. //
  756. // Remove the interface from our list
  757. //
  758. RemoveEntryList(&Interfacep->Link);
  759. if (Interfacep->Info) {
  760. NH_FREE(Interfacep->Info);
  761. }
  762. NH_FREE(Interfacep);
  763. LeaveCriticalSection(&NatInterfaceLock);
  764. NhSignalNatInterface(
  765. Index,
  766. FALSE
  767. );
  768. return Error;
  769. } // NatDeleteInterface
  770. ULONG
  771. NatDeleteTicket(
  772. ULONG InterfaceIndex,
  773. UCHAR Protocol,
  774. USHORT PublicPort,
  775. ULONG PublicAddress,
  776. USHORT PrivatePort,
  777. ULONG PrivateAddress
  778. )
  779. /*++
  780. Routine Description:
  781. This routine is invoked to remove a ticket (static port mapping)
  782. from an interface.
  783. Arguments:
  784. InterfaceIndex - the interface from which to remove the ticket
  785. Protocol, PublicPort, PublicAddress, PrivatePort, PrivateAddress -
  786. describes the ticket to be deleted
  787. Return Value:
  788. ULONG - Win32 status code.
  789. --*/
  790. {
  791. IP_NAT_CREATE_TICKET DeleteTicket;
  792. ULONG Error;
  793. IO_STATUS_BLOCK IoStatus;
  794. NTSTATUS status;
  795. HANDLE WaitEvent;
  796. PROFILE("NatDeleteTicket");
  797. WaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  798. if (WaitEvent == NULL) {
  799. NhTrace(
  800. TRACE_FLAG_NAT,
  801. "NatDeleteTicket: CreateEvent failed [%d]",
  802. GetLastError()
  803. );
  804. return ERROR_NOT_ENOUGH_MEMORY;
  805. }
  806. DeleteTicket.InterfaceIndex = InterfaceIndex;
  807. DeleteTicket.PortMapping.Protocol = Protocol;
  808. DeleteTicket.PortMapping.PublicPort = PublicPort;
  809. DeleteTicket.PortMapping.PublicAddress = PublicAddress;
  810. DeleteTicket.PortMapping.PrivatePort = PrivatePort;
  811. DeleteTicket.PortMapping.PrivateAddress = PrivateAddress;
  812. EnterCriticalSection(&NatInterfaceLock);
  813. status =
  814. NtDeviceIoControlFile(
  815. NatFileHandle,
  816. WaitEvent,
  817. NULL,
  818. NULL,
  819. &IoStatus,
  820. IOCTL_IP_NAT_DELETE_TICKET,
  821. (PVOID)&DeleteTicket,
  822. sizeof(DeleteTicket),
  823. NULL,
  824. 0
  825. );
  826. LeaveCriticalSection(&NatInterfaceLock);
  827. if (status == STATUS_PENDING) {
  828. WaitForSingleObject(WaitEvent, INFINITE);
  829. status = IoStatus.Status;
  830. }
  831. if (NT_SUCCESS(status)) {
  832. Error = NO_ERROR;
  833. } else {
  834. Error = RtlNtStatusToDosError(status);
  835. NhTrace(
  836. TRACE_FLAG_NAT,
  837. "NatDeleteTicket: Ioctl = %d",
  838. Error
  839. );
  840. }
  841. CloseHandle(WaitEvent);
  842. return Error;
  843. } // NatDeleteTicket
  844. ULONG
  845. NatGetInterfaceCharacteristics(
  846. ULONG Index
  847. )
  848. /*++
  849. Routine Description:
  850. This routine is invoked to determine whether the given interface:
  851. 1) Is a NAT boundary interface
  852. 2) Is a NAT private interface
  853. 3) Has the firewall enabled
  854. Note that this routine may be invoked even when the NAT
  855. is neither installed nor running; it operates as expected,
  856. since the interface list and lock are always initialized in 'DllMain'.
  857. Arguments:
  858. Index - the interface in question
  859. IsNatInterface - optionally set to TRUE if the given index
  860. is at all a NAT interface.
  861. Return Value:
  862. BOOLEAN - TRUE if the interface is a NAT boundary interface,
  863. FALSE otherwise.
  864. --*/
  865. {
  866. ULONG Result = 0;
  867. PNAT_INTERFACE Interfacep;
  868. PROFILE("NatGetInterfaceCharacteristics");
  869. EnterCriticalSection(&NatInterfaceLock);
  870. if (!(Interfacep = NatpLookupInterface(Index, NULL))) {
  871. LeaveCriticalSection(&NatInterfaceLock);
  872. return Result;
  873. }
  874. if (Interfacep->Info &&
  875. (Interfacep->Info->Flags & IP_NAT_INTERFACE_FLAGS_FW)) {
  876. Result = NAT_IF_CHAR_FW;
  877. }
  878. if (Interfacep->Info &&
  879. (Interfacep->Info->Flags & IP_NAT_INTERFACE_FLAGS_BOUNDARY)) {
  880. Result |= NAT_IF_CHAR_BOUNDARY;
  881. } else if (!NAT_IFC_FW(Result)) {
  882. //
  883. // As the interface isn't public and isn't firewalled, it must
  884. // be a private interface (or we wouldn't have a record of it).
  885. //
  886. Result |= NAT_IF_CHAR_PRIVATE;
  887. }
  888. LeaveCriticalSection(&NatInterfaceLock);
  889. return Result;
  890. } // NatGetInterfaceCharacteristics
  891. VOID
  892. NatInstallApplicationSettings(
  893. VOID
  894. )
  895. /*++
  896. Routine Description:
  897. This routine is invoked to update the application settings
  898. (i.e., dynamic tickets) stored with the kernel-mode translation module.
  899. Arguments:
  900. none
  901. Return Value:
  902. none.
  903. --*/
  904. {
  905. PNAT_APP_ENTRY pAppEntry;
  906. ULONG Count;
  907. PIP_NAT_CREATE_DYNAMIC_TICKET CreateTicket;
  908. IO_STATUS_BLOCK IoStatus;
  909. ULONG Length;
  910. PLIST_ENTRY Link;
  911. NTSTATUS status;
  912. HANDLE WaitEvent;
  913. PROFILE("NatInstallApplicationSettings");
  914. //
  915. // Install a dynamic ticket for each entry in the applications list
  916. //
  917. EnterCriticalSection(&NatInterfaceLock);
  918. EnterCriticalSection(&NhLock);
  919. WaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  920. if (WaitEvent == NULL) {
  921. LeaveCriticalSection(&NhLock);
  922. LeaveCriticalSection(&NatInterfaceLock);
  923. NhTrace(
  924. TRACE_FLAG_NAT,
  925. "NatInstallSharedAccessSettings: CreateEvent failed [%d]",
  926. GetLastError()
  927. );
  928. return;
  929. }
  930. for (Link = NhApplicationSettingsList.Flink;
  931. Link != &NhApplicationSettingsList;
  932. Link = Link->Flink)
  933. {
  934. //
  935. // Each 'application' has a list of 'responses' which specify
  936. // the ports on which response-sessions are expected.
  937. // Enumerate the responses and allocate a ticket-structure
  938. // large enough to hold the list as an array.
  939. //
  940. pAppEntry = CONTAINING_RECORD(Link, NAT_APP_ENTRY, Link);
  941. Length =
  942. pAppEntry->ResponseCount * sizeof(CreateTicket->ResponseArray[0]) +
  943. FIELD_OFFSET(IP_NAT_CREATE_DYNAMIC_TICKET, ResponseArray);
  944. if (!(CreateTicket =
  945. reinterpret_cast<PIP_NAT_CREATE_DYNAMIC_TICKET>(
  946. NH_ALLOCATE(Length)
  947. )))
  948. { break; }
  949. //
  950. // Fill in the ticket structure from the application entry
  951. // and its list of response-entries.
  952. //
  953. CreateTicket->Protocol = pAppEntry->Protocol;
  954. CreateTicket->Port = pAppEntry->Port;
  955. CreateTicket->ResponseCount = pAppEntry->ResponseCount;
  956. for (Count = 0; Count < pAppEntry->ResponseCount; Count++)
  957. {
  958. CreateTicket->ResponseArray[Count].Protocol =
  959. pAppEntry->ResponseArray[Count].ucIPProtocol;
  960. CreateTicket->ResponseArray[Count].StartPort =
  961. pAppEntry->ResponseArray[Count].usStartPort;
  962. CreateTicket->ResponseArray[Count].EndPort =
  963. pAppEntry->ResponseArray[Count].usEndPort;
  964. }
  965. //
  966. // Install the dynamic ticket for this application, and continue.
  967. //
  968. status = NtDeviceIoControlFile(
  969. NatFileHandle,
  970. WaitEvent,
  971. NULL,
  972. NULL,
  973. &IoStatus,
  974. IOCTL_IP_NAT_CREATE_DYNAMIC_TICKET,
  975. (PVOID)CreateTicket,
  976. Length,
  977. NULL,
  978. 0
  979. );
  980. if (status == STATUS_PENDING) {
  981. WaitForSingleObject(WaitEvent, INFINITE);
  982. status = IoStatus.Status;
  983. }
  984. NH_FREE(CreateTicket);
  985. }
  986. LeaveCriticalSection(&NhLock);
  987. LeaveCriticalSection(&NatInterfaceLock);
  988. CloseHandle(WaitEvent);
  989. } // NatInstallApplicationSettings
  990. BOOLEAN
  991. NatIsBoundaryInterface(
  992. ULONG Index,
  993. PBOOLEAN IsNatInterface OPTIONAL
  994. )
  995. /*++
  996. Routine Description:
  997. This routine is invoked to determine whether the given interface
  998. has the NAT enabled and is marked as a boundary interface.
  999. Note that this routine may be invoked even when the NAT
  1000. is neither installed nor running; it operates as expected,
  1001. since the interface list and lock are always initialized in 'DllMain'.
  1002. Arguments:
  1003. Index - the interface in question
  1004. IsNatInterface - optionally set to TRUE if the given index
  1005. is at all a NAT interface.
  1006. Return Value:
  1007. BOOLEAN - TRUE if the interface is a NAT boundary interface,
  1008. FALSE otherwise.
  1009. --*/
  1010. {
  1011. PNAT_INTERFACE Interfacep;
  1012. PROFILE("NatIsBoundaryInterface");
  1013. EnterCriticalSection(&NatInterfaceLock);
  1014. if (!(Interfacep = NatpLookupInterface(Index, NULL))) {
  1015. LeaveCriticalSection(&NatInterfaceLock);
  1016. if (IsNatInterface) { *IsNatInterface = FALSE; }
  1017. return FALSE;
  1018. }
  1019. if (IsNatInterface) { *IsNatInterface = TRUE; }
  1020. if (Interfacep->Info &&
  1021. (Interfacep->Info->Flags & IP_NAT_INTERFACE_FLAGS_BOUNDARY)) {
  1022. LeaveCriticalSection(&NatInterfaceLock);
  1023. return TRUE;
  1024. }
  1025. LeaveCriticalSection(&NatInterfaceLock);
  1026. return FALSE;
  1027. } // NatIsBoundaryInterface
  1028. PNAT_INTERFACE
  1029. NatpLookupInterface(
  1030. ULONG Index,
  1031. OUT PLIST_ENTRY* InsertionPoint OPTIONAL
  1032. )
  1033. /*++
  1034. Routine Description:
  1035. This routine is called to retrieve an interface given its index.
  1036. Arguments:
  1037. Index - the index of the interface to be retrieved
  1038. InsertionPoint - if the interface is not found, optionally receives
  1039. the point where the interface would be inserted in the interface list
  1040. Return Value:
  1041. PNAT_INTERFACE - the interface, if found; otherwise, NULL.
  1042. Environment:
  1043. Invoked internally from an arbitrary context, with 'NatInterfaceLock'
  1044. held by caller.
  1045. --*/
  1046. {
  1047. PNAT_INTERFACE Interfacep;
  1048. PLIST_ENTRY Link;
  1049. PROFILE("NatpLookupInterface");
  1050. for (Link = NatInterfaceList.Flink; Link != &NatInterfaceList;
  1051. Link = Link->Flink) {
  1052. Interfacep = CONTAINING_RECORD(Link, NAT_INTERFACE, Link);
  1053. if (Index > Interfacep->Index) {
  1054. continue;
  1055. } else if (Index < Interfacep->Index) {
  1056. break;
  1057. }
  1058. return Interfacep;
  1059. }
  1060. if (InsertionPoint) { *InsertionPoint = Link; }
  1061. return NULL;
  1062. } // NatpLookupInterface
  1063. ULONG
  1064. NatQueryInterface(
  1065. ULONG Index,
  1066. PIP_NAT_INTERFACE_INFO InterfaceInfo,
  1067. PULONG InterfaceInfoSize
  1068. )
  1069. /*++
  1070. Routine Description:
  1071. This routine is invoked to retrieve the information for a NAT interface.
  1072. Arguments:
  1073. Index - the interface whose information is to be queried
  1074. InterfaceInfo - receives the information
  1075. InterfaceInfoSize - receives the information size
  1076. Return Value:
  1077. ULONG - Win32 status code.
  1078. --*/
  1079. {
  1080. ULONG Error;
  1081. PNAT_INTERFACE Interfacep;
  1082. ULONG Size;
  1083. PROFILE("NatQueryInterface");
  1084. //
  1085. // Look up the interface to be queried
  1086. //
  1087. EnterCriticalSection(&NatInterfaceLock);
  1088. if (!(Interfacep = NatpLookupInterface(Index, NULL))) {
  1089. LeaveCriticalSection(&NatInterfaceLock);
  1090. NhTrace(
  1091. TRACE_FLAG_NAT,
  1092. "NatQueryInterface: interface %d not found",
  1093. Index
  1094. );
  1095. return ERROR_NO_SUCH_INTERFACE;
  1096. }
  1097. //
  1098. // Compute the required size
  1099. //
  1100. Size =
  1101. FIELD_OFFSET(IP_NAT_INTERFACE_INFO, Header) +
  1102. Interfacep->Info->Header.Size;
  1103. if (Size >= *InterfaceInfoSize) {
  1104. *InterfaceInfoSize = Size;
  1105. Error = ERROR_INSUFFICIENT_BUFFER;
  1106. } else {
  1107. *InterfaceInfoSize = Size;
  1108. CopyMemory(
  1109. InterfaceInfo,
  1110. Interfacep->Info,
  1111. Size
  1112. );
  1113. Error = NO_ERROR;
  1114. }
  1115. LeaveCriticalSection(&NatInterfaceLock);
  1116. return Error;
  1117. } // NatQueryInterface
  1118. ULONG
  1119. NatQueryInterfaceMappingTable(
  1120. ULONG Index,
  1121. PIP_NAT_ENUMERATE_SESSION_MAPPINGS EnumerateTable,
  1122. PULONG EnumerateTableSize
  1123. )
  1124. /*++
  1125. Routine Description:
  1126. This routine is invoked to retrieve the session mappings for an interface.
  1127. Arguments:
  1128. EnumerateTable - receives the enumerated mappings
  1129. EnumerateTableSize - indicates the size of 'EnumerateTable'
  1130. Return Value:
  1131. ULONG - Win32 error code.
  1132. --*/
  1133. {
  1134. IP_NAT_ENUMERATE_SESSION_MAPPINGS Enumerate;
  1135. PNAT_INTERFACE Interfacep;
  1136. IO_STATUS_BLOCK IoStatus;
  1137. ULONG RequiredSize;
  1138. NTSTATUS status;
  1139. HANDLE WaitEvent;
  1140. PROFILE("NatQueryInterfaceMappingTable");
  1141. EnterCriticalSection(&NatInterfaceLock);
  1142. if (!(Interfacep = NatpLookupInterface(Index, NULL))) {
  1143. LeaveCriticalSection(&NatInterfaceLock);
  1144. NhTrace(
  1145. TRACE_FLAG_NAT,
  1146. "NatQueryInterfaceMappingTable: interface %d not found",
  1147. Index
  1148. );
  1149. return ERROR_NO_SUCH_INTERFACE;
  1150. }
  1151. if (!NAT_INTERFACE_BOUND(Interfacep)) {
  1152. //
  1153. // The interface is not bound, so there aren't any mappings.
  1154. // Indicate zero mappings in the caller's request-buffer.
  1155. //
  1156. LeaveCriticalSection(&NatInterfaceLock);
  1157. RequiredSize =
  1158. FIELD_OFFSET(IP_NAT_ENUMERATE_SESSION_MAPPINGS, EnumerateTable[0]);
  1159. if (*EnumerateTableSize < RequiredSize) {
  1160. *EnumerateTableSize = RequiredSize;
  1161. return ERROR_INSUFFICIENT_BUFFER;
  1162. }
  1163. EnumerateTable->Index = Index;
  1164. EnumerateTable->EnumerateContext[0] = 0;
  1165. EnumerateTable->EnumerateCount = 0;
  1166. *EnumerateTableSize = RequiredSize;
  1167. return NO_ERROR;
  1168. }
  1169. WaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  1170. if (WaitEvent == NULL) {
  1171. LeaveCriticalSection(&NatInterfaceLock);
  1172. NhTrace(
  1173. TRACE_FLAG_NAT,
  1174. "NatQueryInterfaceMappingTable: CreateEvent failed [%d]",
  1175. GetLastError()
  1176. );
  1177. return ERROR_NOT_ENOUGH_MEMORY;
  1178. }
  1179. //
  1180. // Determine the amount of space required
  1181. //
  1182. Enumerate.Index = Interfacep->AdapterIndex;
  1183. Enumerate.EnumerateCount = 0;
  1184. Enumerate.EnumerateContext[0] = 0;
  1185. status =
  1186. NtDeviceIoControlFile(
  1187. NatFileHandle,
  1188. WaitEvent,
  1189. NULL,
  1190. NULL,
  1191. &IoStatus,
  1192. IOCTL_IP_NAT_GET_INTERFACE_MAPPING_TABLE,
  1193. (PVOID)&Enumerate,
  1194. sizeof(Enumerate),
  1195. (PVOID)&Enumerate,
  1196. sizeof(Enumerate)
  1197. );
  1198. if (status == STATUS_PENDING) {
  1199. WaitForSingleObject(WaitEvent, INFINITE);
  1200. status = IoStatus.Status;
  1201. }
  1202. if (!NT_SUCCESS(status)) {
  1203. CloseHandle(WaitEvent);
  1204. LeaveCriticalSection(&NatInterfaceLock);
  1205. *EnumerateTableSize = 0;
  1206. return RtlNtStatusToDosError(status);
  1207. }
  1208. RequiredSize =
  1209. FIELD_OFFSET(IP_NAT_ENUMERATE_SESSION_MAPPINGS, EnumerateTable[0]) +
  1210. Enumerate.EnumerateTotalHint * sizeof(IP_NAT_SESSION_MAPPING);
  1211. //
  1212. // If the caller doesn't have enough space for all these mappings, fail
  1213. //
  1214. if (*EnumerateTableSize < RequiredSize) {
  1215. CloseHandle(WaitEvent);
  1216. LeaveCriticalSection(&NatInterfaceLock);
  1217. *EnumerateTableSize = RequiredSize + 5 * sizeof(IP_NAT_SESSION_MAPPING);
  1218. return ERROR_INSUFFICIENT_BUFFER;
  1219. }
  1220. //
  1221. // Attempt to read the mappings
  1222. //
  1223. Enumerate.Index = Interfacep->AdapterIndex;
  1224. Enumerate.EnumerateCount = 0;
  1225. Enumerate.EnumerateContext[0] = 0;
  1226. status =
  1227. NtDeviceIoControlFile(
  1228. NatFileHandle,
  1229. WaitEvent,
  1230. NULL,
  1231. NULL,
  1232. &IoStatus,
  1233. IOCTL_IP_NAT_GET_INTERFACE_MAPPING_TABLE,
  1234. (PVOID)&Enumerate,
  1235. sizeof(Enumerate),
  1236. (PVOID)EnumerateTable,
  1237. *EnumerateTableSize
  1238. );
  1239. if (status == STATUS_PENDING) {
  1240. WaitForSingleObject(WaitEvent, INFINITE);
  1241. status = IoStatus.Status;
  1242. }
  1243. CloseHandle(WaitEvent);
  1244. LeaveCriticalSection(&NatInterfaceLock);
  1245. EnumerateTable->Index = Index;
  1246. *EnumerateTableSize =
  1247. FIELD_OFFSET(IP_NAT_ENUMERATE_SESSION_MAPPINGS, EnumerateTable[0]) +
  1248. EnumerateTable->EnumerateCount * sizeof(IP_NAT_SESSION_MAPPING);
  1249. return NT_SUCCESS(status) ? NO_ERROR : RtlNtStatusToDosError(status);
  1250. } // NatQueryInterfaceMappingTable
  1251. ULONG
  1252. NatQueryMappingTable(
  1253. PIP_NAT_ENUMERATE_SESSION_MAPPINGS EnumerateTable,
  1254. PULONG EnumerateTableSize
  1255. )
  1256. /*++
  1257. Routine Description:
  1258. This routine is invoked to retrieve the session mappings for an interface.
  1259. Arguments:
  1260. EnumerateTable - receives the enumerated mappings
  1261. EnumerateTableSize - indicates the size of 'EnumerateTable'
  1262. Return Value:
  1263. ULONG - Win32 error code.
  1264. --*/
  1265. {
  1266. IP_NAT_ENUMERATE_SESSION_MAPPINGS Enumerate;
  1267. IO_STATUS_BLOCK IoStatus;
  1268. ULONG RequiredSize;
  1269. NTSTATUS status;
  1270. HANDLE WaitEvent;
  1271. PROFILE("NatQueryMappingTable");
  1272. WaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  1273. if (WaitEvent == NULL) {
  1274. NhTrace(
  1275. TRACE_FLAG_NAT,
  1276. "NatQueryMappingTable: CreateEvent failed [%d]",
  1277. GetLastError()
  1278. );
  1279. return ERROR_NOT_ENOUGH_MEMORY;
  1280. }
  1281. EnterCriticalSection(&NatInterfaceLock);
  1282. //
  1283. // Determine the amount of space required
  1284. //
  1285. Enumerate.EnumerateCount = 0;
  1286. Enumerate.EnumerateContext[0] = 0;
  1287. status =
  1288. NtDeviceIoControlFile(
  1289. NatFileHandle,
  1290. WaitEvent,
  1291. NULL,
  1292. NULL,
  1293. &IoStatus,
  1294. IOCTL_IP_NAT_GET_MAPPING_TABLE,
  1295. (PVOID)&Enumerate,
  1296. sizeof(Enumerate),
  1297. (PVOID)&Enumerate,
  1298. sizeof(Enumerate)
  1299. );
  1300. if (status == STATUS_PENDING) {
  1301. WaitForSingleObject(WaitEvent, INFINITE);
  1302. status = IoStatus.Status;
  1303. }
  1304. if (!NT_SUCCESS(status)) {
  1305. LeaveCriticalSection(&NatInterfaceLock);
  1306. CloseHandle(WaitEvent);
  1307. *EnumerateTableSize = 0;
  1308. return RtlNtStatusToDosError(status);
  1309. }
  1310. RequiredSize =
  1311. FIELD_OFFSET(IP_NAT_ENUMERATE_SESSION_MAPPINGS, EnumerateTable[0]) +
  1312. Enumerate.EnumerateTotalHint * sizeof(IP_NAT_SESSION_MAPPING);
  1313. //
  1314. // If the caller doesn't have enough space for all these mappings, fail
  1315. //
  1316. if (*EnumerateTableSize < RequiredSize) {
  1317. LeaveCriticalSection(&NatInterfaceLock);
  1318. CloseHandle(WaitEvent);
  1319. *EnumerateTableSize = RequiredSize + 5 * sizeof(IP_NAT_SESSION_MAPPING);
  1320. return ERROR_INSUFFICIENT_BUFFER;
  1321. }
  1322. //
  1323. // Attempt to read the mappings
  1324. //
  1325. Enumerate.EnumerateCount = 0;
  1326. Enumerate.EnumerateContext[0] = 0;
  1327. status =
  1328. NtDeviceIoControlFile(
  1329. NatFileHandle,
  1330. WaitEvent,
  1331. NULL,
  1332. NULL,
  1333. &IoStatus,
  1334. IOCTL_IP_NAT_GET_MAPPING_TABLE,
  1335. (PVOID)&Enumerate,
  1336. sizeof(Enumerate),
  1337. (PVOID)EnumerateTable,
  1338. *EnumerateTableSize
  1339. );
  1340. if (status == STATUS_PENDING) {
  1341. WaitForSingleObject(WaitEvent, INFINITE);
  1342. status = IoStatus.Status;
  1343. }
  1344. CloseHandle(WaitEvent);
  1345. LeaveCriticalSection(&NatInterfaceLock);
  1346. EnumerateTable->Index = (ULONG)-1;
  1347. *EnumerateTableSize =
  1348. FIELD_OFFSET(IP_NAT_ENUMERATE_SESSION_MAPPINGS, EnumerateTable[0]) +
  1349. EnumerateTable->EnumerateCount * sizeof(IP_NAT_SESSION_MAPPING);
  1350. return NT_SUCCESS(status) ? NO_ERROR : RtlNtStatusToDosError(status);
  1351. } // NatQueryMappingTable
  1352. ULONG
  1353. NatQueryStatisticsInterface(
  1354. ULONG Index,
  1355. PIP_NAT_INTERFACE_STATISTICS InterfaceStatistics,
  1356. PULONG InterfaceStatisticsSize
  1357. )
  1358. /*++
  1359. Routine Description:
  1360. This routine is invoked to retrieve the statistics for a NAT interface.
  1361. Arguments:
  1362. Index - the index of the interface whose statistics are to be retrieved
  1363. Return Value:
  1364. ULONG - Win32 error code.
  1365. --*/
  1366. {
  1367. PNAT_INTERFACE Interfacep;
  1368. IO_STATUS_BLOCK IoStatus;
  1369. NTSTATUS status;
  1370. HANDLE WaitEvent;
  1371. PROFILE("NatQueryStatisticsInterface");
  1372. //
  1373. // Look up the interface to be queried
  1374. //
  1375. EnterCriticalSection(&NatInterfaceLock);
  1376. if (!(Interfacep = NatpLookupInterface(Index, NULL))) {
  1377. LeaveCriticalSection(&NatInterfaceLock);
  1378. NhTrace(
  1379. TRACE_FLAG_NAT,
  1380. "NatQueryStatisticsInterface: interface %d not found",
  1381. Index
  1382. );
  1383. return ERROR_NO_SUCH_INTERFACE;
  1384. }
  1385. //
  1386. // If the interface is not bound, supply zero statistics.
  1387. //
  1388. if (!NAT_INTERFACE_BOUND(Interfacep)) {
  1389. LeaveCriticalSection(&NatInterfaceLock);
  1390. if (*InterfaceStatisticsSize < sizeof(IP_NAT_INTERFACE_STATISTICS)) {
  1391. *InterfaceStatisticsSize = sizeof(IP_NAT_INTERFACE_STATISTICS);
  1392. return ERROR_INSUFFICIENT_BUFFER;
  1393. }
  1394. *InterfaceStatisticsSize = sizeof(IP_NAT_INTERFACE_STATISTICS);
  1395. ZeroMemory(InterfaceStatistics, sizeof(IP_NAT_INTERFACE_STATISTICS));
  1396. return NO_ERROR;
  1397. }
  1398. WaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  1399. if (WaitEvent == NULL) {
  1400. LeaveCriticalSection(&NatInterfaceLock);
  1401. NhTrace(
  1402. TRACE_FLAG_NAT,
  1403. "NatQueryStatisticsInterface: CreateEvent failed [%d]",
  1404. GetLastError()
  1405. );
  1406. return ERROR_NOT_ENOUGH_MEMORY;
  1407. }
  1408. //
  1409. // Attempt to read the statistics for the interface
  1410. //
  1411. status =
  1412. NtDeviceIoControlFile(
  1413. NatFileHandle,
  1414. WaitEvent,
  1415. NULL,
  1416. NULL,
  1417. &IoStatus,
  1418. IOCTL_IP_NAT_GET_INTERFACE_STATISTICS,
  1419. (PVOID)&Interfacep->AdapterIndex,
  1420. sizeof(ULONG),
  1421. (PVOID)InterfaceStatistics,
  1422. *InterfaceStatisticsSize
  1423. );
  1424. if (status == STATUS_PENDING) {
  1425. WaitForSingleObject(WaitEvent, INFINITE);
  1426. status = IoStatus.Status;
  1427. }
  1428. CloseHandle(WaitEvent);
  1429. LeaveCriticalSection(&NatInterfaceLock);
  1430. if (NT_SUCCESS(status) && IoStatus.Information > *InterfaceStatisticsSize) {
  1431. *InterfaceStatisticsSize = (ULONG)IoStatus.Information;
  1432. return ERROR_INSUFFICIENT_BUFFER;
  1433. }
  1434. *InterfaceStatisticsSize = (ULONG)IoStatus.Information;
  1435. return NT_SUCCESS(status) ? NO_ERROR : RtlNtStatusToDosError(status);
  1436. } // NatQueryStatisticsInterface
  1437. VOID
  1438. NatRemoveApplicationSettings(
  1439. VOID
  1440. )
  1441. /*++
  1442. Routine Description:
  1443. This routine is invoked to remove the advanced application settings (i.e.,
  1444. dynamic tickets), and supply the settings to the kernel-mode translation
  1445. module.
  1446. Arguments:
  1447. none.
  1448. Return Value:
  1449. none.
  1450. --*/
  1451. {
  1452. PNAT_APP_ENTRY pAppEntry;
  1453. IP_NAT_DELETE_DYNAMIC_TICKET DeleteTicket;
  1454. IO_STATUS_BLOCK IoStatus;
  1455. PLIST_ENTRY Link;
  1456. NTSTATUS status;
  1457. HANDLE WaitEvent;
  1458. PROFILE("NatRemoveApplicationSettings");
  1459. //
  1460. // Each 'application' entry in the shared access settings
  1461. // corresponds to a dynamic ticket for the kernel-mode translator.
  1462. // We begin by removing the dynamic tickets for the old settings, if any,
  1463. // and then we free the old settings in preparation for reloading.
  1464. //
  1465. WaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  1466. if (WaitEvent == NULL) {
  1467. NhTrace(
  1468. TRACE_FLAG_NAT,
  1469. "NatRemoveSharedAccessSettings: CreateEvent failed [%d]",
  1470. GetLastError()
  1471. );
  1472. return;
  1473. }
  1474. EnterCriticalSection(&NatInterfaceLock);
  1475. EnterCriticalSection(&NhLock);
  1476. for (Link = NhApplicationSettingsList.Flink;
  1477. Link != &NhApplicationSettingsList;
  1478. Link = Link->Flink)
  1479. {
  1480. pAppEntry = CONTAINING_RECORD(Link, NAT_APP_ENTRY, Link);
  1481. DeleteTicket.Protocol = pAppEntry->Protocol;
  1482. DeleteTicket.Port = pAppEntry->Port;
  1483. status =
  1484. NtDeviceIoControlFile(
  1485. NatFileHandle,
  1486. WaitEvent,
  1487. NULL,
  1488. NULL,
  1489. &IoStatus,
  1490. IOCTL_IP_NAT_DELETE_DYNAMIC_TICKET,
  1491. (PVOID)&DeleteTicket,
  1492. sizeof(DeleteTicket),
  1493. NULL,
  1494. 0
  1495. );
  1496. if (status == STATUS_PENDING) {
  1497. WaitForSingleObject(WaitEvent, INFINITE);
  1498. status = IoStatus.Status;
  1499. }
  1500. }
  1501. LeaveCriticalSection(&NhLock);
  1502. LeaveCriticalSection(&NatInterfaceLock);
  1503. CloseHandle(WaitEvent);
  1504. } // NatRemoveSharedAccessSettings
  1505. ULONG
  1506. NatUnbindInterface(
  1507. ULONG Index,
  1508. PNAT_INTERFACE Interfacep
  1509. )
  1510. /*++
  1511. Routine Description:
  1512. This routine is invoked to remove a binding from the NAT.
  1513. Arguments:
  1514. Index - the interface to be unbound
  1515. Interfacep - optionally supplies the interface-structure to be unbound
  1516. (See 'NATCONN.C' which passes in a static interface-structure).
  1517. Return Value:
  1518. ULONG - Win32 status code.
  1519. --*/
  1520. {
  1521. ULONG Error;
  1522. IO_STATUS_BLOCK IoStatus;
  1523. NTSTATUS status;
  1524. HANDLE WaitEvent;
  1525. PROFILE("NatUnbindInterface");
  1526. WaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  1527. if (WaitEvent == NULL) {
  1528. NhTrace(
  1529. TRACE_FLAG_NAT,
  1530. "NatUnbindInterface: CreateEvent failed [%d]",
  1531. GetLastError()
  1532. );
  1533. return ERROR_NOT_ENOUGH_MEMORY;
  1534. }
  1535. //
  1536. // Retrieve the interface to be unbound.
  1537. //
  1538. EnterCriticalSection(&NatInterfaceLock);
  1539. if (!Interfacep && !(Interfacep = NatpLookupInterface(Index, NULL))) {
  1540. LeaveCriticalSection(&NatInterfaceLock);
  1541. NhTrace(
  1542. TRACE_FLAG_NAT,
  1543. "NatUnbindInterface: interface %d not found",
  1544. Index
  1545. );
  1546. return ERROR_NO_SUCH_INTERFACE;
  1547. }
  1548. //
  1549. // Make sure the interface is not already unbound
  1550. //
  1551. if (!NAT_INTERFACE_BOUND(Interfacep)) {
  1552. LeaveCriticalSection(&NatInterfaceLock);
  1553. NhTrace(
  1554. TRACE_FLAG_NAT,
  1555. "NatUnbindInterface: interface %d already unbound",
  1556. Index
  1557. );
  1558. return ERROR_ADDRESS_NOT_ASSOCIATED;
  1559. }
  1560. Interfacep->Flags &= ~NAT_INTERFACE_FLAG_BOUND;
  1561. if (Interfacep->Type == ROUTER_IF_TYPE_DEDICATED) {
  1562. NatUpdateProxyArp(Interfacep, FALSE);
  1563. }
  1564. //
  1565. // Remove the interface from the kernel-mode driver
  1566. //
  1567. status =
  1568. NtDeviceIoControlFile(
  1569. NatFileHandle,
  1570. WaitEvent,
  1571. NULL,
  1572. NULL,
  1573. &IoStatus,
  1574. IOCTL_IP_NAT_DELETE_INTERFACE,
  1575. (PVOID)&Interfacep->AdapterIndex,
  1576. sizeof(ULONG),
  1577. NULL,
  1578. 0
  1579. );
  1580. if (status == STATUS_PENDING) {
  1581. WaitForSingleObject(WaitEvent, INFINITE);
  1582. status = IoStatus.Status;
  1583. }
  1584. LeaveCriticalSection(&NatInterfaceLock);
  1585. CloseHandle(WaitEvent);
  1586. Error = NT_SUCCESS(status) ? NO_ERROR : RtlNtStatusToDosError(status);
  1587. if (Error) {
  1588. NhErrorLog(
  1589. IP_NAT_LOG_IOCTL_FAILED,
  1590. Error,
  1591. ""
  1592. );
  1593. }
  1594. return Error;
  1595. } // NatUnbindInterface
  1596. ULONG
  1597. NatLookupPortMappingAdapter(
  1598. ULONG AdapterIndex,
  1599. UCHAR Protocol,
  1600. ULONG PublicAddress,
  1601. USHORT PublicPort,
  1602. PIP_NAT_PORT_MAPPING PortMappingp
  1603. )
  1604. /*++
  1605. Routine Description:
  1606. This routine is invoked to find a mapping that matches the given adapter,
  1607. protocol, public address and public port number. The routine tries to
  1608. match both port and address mapping.
  1609. Arguments:
  1610. AdapterIndex - the adapter to be looked up
  1611. Protocol - protocol used to match a mapping
  1612. PublicAddress - public address used to match a mapping
  1613. PublicPort - public port number used to match a mapping
  1614. PortMappingp - pointer to a caller-supplied storage to save the mapping if
  1615. found
  1616. Return Value:
  1617. ULONG - Win32 status code.
  1618. --*/
  1619. {
  1620. IP_NAT_CREATE_TICKET LookupTicket;
  1621. ULONG Error;
  1622. IO_STATUS_BLOCK IoStatus;
  1623. NTSTATUS status;
  1624. HANDLE WaitEvent;
  1625. PROFILE("NatLookupPortMappingAdapter");
  1626. Error = NO_ERROR;
  1627. WaitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  1628. if (WaitEvent == NULL) {
  1629. NhTrace(
  1630. TRACE_FLAG_NAT,
  1631. "NatLookupPortMappingAdapter:"
  1632. " CreateEvent failed [%d] for adapter %d",
  1633. GetLastError(),
  1634. AdapterIndex
  1635. );
  1636. return ERROR_NOT_ENOUGH_MEMORY;
  1637. }
  1638. LookupTicket.InterfaceIndex = AdapterIndex;
  1639. LookupTicket.PortMapping.Protocol = Protocol;
  1640. LookupTicket.PortMapping.PublicPort = PublicPort;
  1641. LookupTicket.PortMapping.PublicAddress = PublicAddress;
  1642. LookupTicket.PortMapping.PrivatePort = 0;
  1643. LookupTicket.PortMapping.PrivateAddress = 0;
  1644. status =
  1645. NtDeviceIoControlFile(
  1646. NatFileHandle,
  1647. WaitEvent,
  1648. NULL,
  1649. NULL,
  1650. &IoStatus,
  1651. IOCTL_IP_NAT_LOOKUP_TICKET,
  1652. (PVOID)&LookupTicket,
  1653. sizeof(LookupTicket),
  1654. (PVOID)PortMappingp,
  1655. sizeof(*PortMappingp)
  1656. );
  1657. if (status == STATUS_PENDING) {
  1658. WaitForSingleObject(WaitEvent, INFINITE);
  1659. status = IoStatus.Status;
  1660. }
  1661. if (!NT_SUCCESS(status)) {
  1662. NhTrace(
  1663. TRACE_FLAG_NAT,
  1664. "NatLookupPortMappingAdapter:"
  1665. " status %08x getting info for adapter %d",
  1666. status,
  1667. AdapterIndex
  1668. );
  1669. Error = RtlNtStatusToDosError(status);
  1670. }
  1671. CloseHandle(WaitEvent);
  1672. return Error;
  1673. }