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.

1270 lines
34 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. dispatch.c
  5. Abstract:
  6. This file contains the code for handling I/O request packets.
  7. Author:
  8. Abolade Gbadegesin (t-abolag) 11-July-1997
  9. Revision History:
  10. Abolade Gbadegesin (aboladeg) 19-July-1998
  11. Cleaned up fast-path processing, and corrected input/output buffer logic
  12. while making the mapping-tree global rather than per-interface.
  13. --*/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. //
  17. // Fast-io-dispatch structure; we only support fast-IO for IOCTLs
  18. //
  19. FAST_IO_DISPATCH NatFastIoDispatch =
  20. {
  21. FIELD_OFFSET(FAST_IO_DISPATCH, FastIoDeviceControl),
  22. NULL,
  23. NULL,
  24. NULL,
  25. NULL,
  26. NULL,
  27. NULL,
  28. NULL,
  29. NULL,
  30. NULL,
  31. NatFastIoDeviceControl
  32. };
  33. //
  34. // Spinlock to guard file object create / close
  35. //
  36. KSPIN_LOCK NatFileObjectLock;
  37. //
  38. // The process that owns the outstanding file objects
  39. //
  40. HANDLE NatOwnerProcessId;
  41. //
  42. // The count of outstanding user-mode file objects.
  43. //
  44. ULONG NatFileObjectCount;
  45. //
  46. // FORWARD DECLARATIONS
  47. //
  48. NTSTATUS
  49. NatpExecuteIoDeviceControl(
  50. PIRP Irp,
  51. PFILE_OBJECT FileObject,
  52. MODE RequestorMode,
  53. PVOID InputBuffer,
  54. ULONG InputBufferLength,
  55. PVOID OutputBuffer,
  56. ULONG OutputBufferLength,
  57. ULONG IoControlCode,
  58. PULONG Size
  59. );
  60. NTSTATUS
  61. NatpSetGlobalInfo(
  62. PVOID InputBuffer,
  63. ULONG InputBufferLength,
  64. PVOID OutputBuffer,
  65. ULONG OutputBufferLength,
  66. PULONG Size
  67. );
  68. BOOLEAN FASTCALL
  69. NatpValidateHeader(
  70. PRTR_INFO_BLOCK_HEADER Header,
  71. ULONG Size
  72. );
  73. NTSTATUS
  74. NatDispatch(
  75. IN PDEVICE_OBJECT DeviceObject,
  76. IN PIRP Irp
  77. )
  78. /*++
  79. Routine Description:
  80. This routine is invoked to handle interrupt-request packets
  81. queued to the NAT's device object. A single routine serves
  82. to handle all the varios requests in which we are interested.
  83. Arguments:
  84. DeviceObject - the NAT's device-object
  85. Irp - the interrupt request packet
  86. Return Value:
  87. NTSTATUS - status code.
  88. --*/
  89. {
  90. PVOID Buffer;
  91. PRTR_TOC_ENTRY Entry;
  92. PRTR_INFO_BLOCK_HEADER Header;
  93. ULONG i;
  94. PIO_STACK_LOCATION IrpSp;
  95. KIRQL Irql;
  96. HANDLE ProcessId;
  97. ULONG Size = 0;
  98. NTSTATUS status = STATUS_SUCCESS;
  99. BOOLEAN ShouldComplete = TRUE;
  100. CALLTRACE(("NatDispatch\n"));
  101. Irp->IoStatus.Status = STATUS_SUCCESS;
  102. Irp->IoStatus.Information = 0;
  103. Buffer = Irp->AssociatedIrp.SystemBuffer;
  104. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  105. switch (IrpSp->MajorFunction) {
  106. case IRP_MJ_CREATE: {
  107. //
  108. // If this is a user-mode request check process
  109. // ownership.
  110. //
  111. if (UserMode == Irp->RequestorMode) {
  112. ProcessId = PsGetCurrentProcessId();
  113. KeAcquireSpinLock(&NatFileObjectLock, &Irql);
  114. if (0 == NatFileObjectCount) {
  115. //
  116. // No process currently owns the NAT -- record
  117. // the new owning process id, and update the
  118. // outstanding file object count.
  119. //
  120. ASSERT(NULL == NatOwnerProcessId);
  121. NatOwnerProcessId = ProcessId;
  122. NatFileObjectCount = 1;
  123. } else if (ProcessId == NatOwnerProcessId) {
  124. //
  125. // The owning process is creating another
  126. // file object.
  127. //
  128. NatFileObjectCount += 1;
  129. } else {
  130. //
  131. // A process that is not our owner is trying
  132. // to create a file object -- fail the request.
  133. //
  134. status = STATUS_ACCESS_DENIED;
  135. }
  136. KeReleaseSpinLock(&NatFileObjectLock, Irql);
  137. }
  138. break;
  139. }
  140. case IRP_MJ_CLEANUP: {
  141. NatDeleteAnyAssociatedInterface(IrpSp->FileObject);
  142. NatCleanupAnyAssociatedRedirect(IrpSp->FileObject);
  143. NatCleanupAnyAssociatedNotification(IrpSp->FileObject);
  144. NatDeleteAnyAssociatedDynamicTicket(IrpSp->FileObject);
  145. break;
  146. }
  147. case IRP_MJ_CLOSE: {
  148. //
  149. // If this is a user-mode request update the outstanding
  150. // file object count and process ownership.
  151. //
  152. if (UserMode == Irp->RequestorMode) {
  153. KeAcquireSpinLock(&NatFileObjectLock, &Irql);
  154. ASSERT(NatFileObjectCount > 0);
  155. ASSERT(PsGetCurrentProcessId() == NatOwnerProcessId);
  156. NatFileObjectCount -= 1;
  157. if (0 == NatFileObjectCount) {
  158. //
  159. // The process has closed its last outstanding
  160. // file object, and thus is no longer our
  161. // owner.
  162. //
  163. NatOwnerProcessId = NULL;
  164. }
  165. KeReleaseSpinLock(&NatFileObjectLock, Irql);
  166. }
  167. break;
  168. }
  169. case IRP_MJ_DEVICE_CONTROL: {
  170. status =
  171. NatpExecuteIoDeviceControl(
  172. Irp,
  173. IrpSp->FileObject,
  174. Irp->RequestorMode,
  175. Buffer,
  176. IrpSp->Parameters.DeviceIoControl.InputBufferLength,
  177. Buffer,
  178. IrpSp->Parameters.DeviceIoControl.OutputBufferLength,
  179. IrpSp->Parameters.DeviceIoControl.IoControlCode,
  180. &Size
  181. );
  182. break;
  183. }
  184. #if NAT_WMI
  185. case IRP_MJ_SYSTEM_CONTROL: {
  186. status =
  187. NatExecuteSystemControl(
  188. DeviceObject,
  189. Irp,
  190. &ShouldComplete
  191. );
  192. if (ShouldComplete) {
  193. ShouldComplete = FALSE;
  194. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  195. }
  196. break;
  197. }
  198. #endif
  199. }
  200. if (status != STATUS_PENDING && ShouldComplete) {
  201. Irp->IoStatus.Status = status;
  202. Irp->IoStatus.Information = Size;
  203. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  204. }
  205. return status;
  206. } // NatDispatch
  207. BOOLEAN
  208. NatFastIoDeviceControl(
  209. PFILE_OBJECT FileObject,
  210. BOOLEAN Wait,
  211. PVOID InputBuffer,
  212. ULONG InputBufferLength,
  213. PVOID OutputBuffer,
  214. ULONG OutputBufferLength,
  215. ULONG IoControlCode,
  216. PIO_STATUS_BLOCK IoStatus,
  217. PDEVICE_OBJECT DeviceObject
  218. )
  219. /*++
  220. Routine Description:
  221. This routine is invoked by the I/O system in an attempt to complete
  222. an I/O control request without constructing an IRP.
  223. Arguments:
  224. FileObject - the file associated with the I/O request
  225. Wait - indicates whether a wait is allowed in this context
  226. InputBuffer - input information for the I/O request
  227. InputBufferLength - length of 'InputBuffer'
  228. OutputBuffer - output information for the I/O request
  229. OutputBufferLength - length of 'OutputBuffer'
  230. IoControlCode - I/O request code
  231. IoStatus - receives the status of the I/O request
  232. DeviceObject - device object of the NAT
  233. Return Value:
  234. BOOLEAN - TRUE if completed synchronously, FALSE otherwise
  235. --*/
  236. {
  237. ULONG Size = 0;
  238. NTSTATUS Status;
  239. PVOID LocalInputBuffer;
  240. MODE PreviousMode;
  241. //
  242. // We are in the context of the requesting thread,
  243. // so exceptions may occur, and must be handled.
  244. // To deal with modifications to the user-provided information
  245. // capture the contents of the input buffer in non-paged pool.
  246. //
  247. if (!InputBufferLength) {
  248. LocalInputBuffer = NULL;
  249. } else {
  250. LocalInputBuffer =
  251. ExAllocatePoolWithTag(
  252. NonPagedPool,
  253. InputBufferLength,
  254. NAT_TAG_IOCTL
  255. );
  256. if (!LocalInputBuffer) {
  257. return FALSE;
  258. }
  259. }
  260. PreviousMode = ExGetPreviousMode();
  261. __try {
  262. if (InputBufferLength) {
  263. if (PreviousMode != KernelMode) {
  264. ProbeForRead(InputBuffer, InputBufferLength, sizeof(UCHAR));
  265. }
  266. RtlCopyMemory(LocalInputBuffer, InputBuffer, InputBufferLength);
  267. }
  268. Status =
  269. NatpExecuteIoDeviceControl(
  270. NULL,
  271. FileObject,
  272. PreviousMode,
  273. LocalInputBuffer,
  274. InputBufferLength,
  275. OutputBuffer,
  276. OutputBufferLength,
  277. IoControlCode,
  278. &Size
  279. );
  280. if (Status != STATUS_PENDING && NT_SUCCESS(Status)) {
  281. IoStatus->Information = Size;
  282. IoStatus->Status = Status;
  283. } else {
  284. Status = STATUS_PENDING;
  285. }
  286. } __except(EXCEPTION_EXECUTE_HANDLER) {
  287. if (LocalInputBuffer) { ExFreePool(LocalInputBuffer); }
  288. return FALSE;
  289. }
  290. if (LocalInputBuffer) { ExFreePool(LocalInputBuffer); }
  291. return ((Status == STATUS_PENDING) ? FALSE : TRUE);
  292. } // NatFastIoDeviceControl
  293. NTSTATUS
  294. NatpExecuteIoDeviceControl(
  295. PIRP Irp,
  296. PFILE_OBJECT FileObject,
  297. MODE RequestorMode,
  298. PVOID InputBuffer,
  299. ULONG InputBufferLength,
  300. PVOID OutputBuffer,
  301. ULONG OutputBufferLength,
  302. ULONG IoControlCode,
  303. PULONG Size
  304. )
  305. /*++
  306. Routine Description:
  307. This routine is invoked to handle I/O controls, either in the context
  308. of the requesting thread (via FastIoDispatch) or in the context of a
  309. system thread (with a corresponding IRP).
  310. For certain requests, particularly those requiring output information,
  311. we return 'STATUS_PENDING' when invoked in the fast path since we cannot
  312. write into the output buffer at raised IRQL. Instead, we wait to be
  313. reinvoked via the slow path with a non-paged system buffer.
  314. Arguments:
  315. Irp - in the slow-path, the IRP associated with the control;
  316. in the fast-path, NULL
  317. FileObject - the file-object associated with the control
  318. RequestorMode - indicates whether the requestor is in kernel-mode
  319. or user-mode
  320. InputBuffer/InputBufferLength - describe data passed in with the control;
  321. may be user-mode or kernel-mode buffer
  322. OutputBuffer/OutputBufferLength - describe space in which to return
  323. information; may be user-mode or kernel-mode buffer
  324. IoControlCode - indicates control requested
  325. Size - on output, number of bytes stored in 'OutputBuffer'.
  326. Return Value:
  327. NTSTATUS - status code.
  328. --*/
  329. {
  330. PIP_ADAPTER_BINDING_INFO BindingInfo;
  331. PRTR_TOC_ENTRY Entry;
  332. PRTR_INFO_BLOCK_HEADER Header;
  333. ULONG i;
  334. NTSTATUS status = STATUS_SUCCESS;
  335. *Size = 0;
  336. switch (IoControlCode) {
  337. case IOCTL_IP_NAT_REQUEST_NOTIFICATION: {
  338. if (!Irp) { return STATUS_PENDING; }
  339. if (InputBufferLength < sizeof(IP_NAT_REQUEST_NOTIFICATION)) {
  340. status = STATUS_INVALID_BUFFER_SIZE;
  341. break;
  342. }
  343. status =
  344. NatRequestNotification(
  345. (PIP_NAT_REQUEST_NOTIFICATION)InputBuffer,
  346. Irp,
  347. FileObject
  348. );
  349. break;
  350. }
  351. case IOCTL_IP_NAT_SET_GLOBAL_INFO: {
  352. status =
  353. NatpSetGlobalInfo(
  354. InputBuffer,
  355. InputBufferLength,
  356. OutputBuffer,
  357. OutputBufferLength,
  358. Size
  359. );
  360. break;
  361. }
  362. case IOCTL_IP_NAT_CREATE_INTERFACE: {
  363. if (InputBufferLength <
  364. sizeof(IP_NAT_CREATE_INTERFACE) +
  365. sizeof(IP_ADAPTER_BINDING_INFO)
  366. ) {
  367. status = STATUS_INVALID_BUFFER_SIZE;
  368. break;
  369. }
  370. BindingInfo =
  371. (PIP_ADAPTER_BINDING_INFO)
  372. ((PIP_NAT_CREATE_INTERFACE)InputBuffer)->BindingInfo;
  373. if (BindingInfo->AddressCount >= MAXLONG / sizeof(NAT_ADDRESS) ||
  374. SIZEOF_IP_BINDING(BindingInfo->AddressCount) +
  375. sizeof(IP_NAT_CREATE_INTERFACE) > InputBufferLength) {
  376. status = STATUS_INVALID_PARAMETER;
  377. break;
  378. }
  379. status =
  380. NatCreateInterface(
  381. (PIP_NAT_CREATE_INTERFACE)InputBuffer,
  382. FileObject
  383. );
  384. break;
  385. }
  386. case IOCTL_IP_NAT_DELETE_INTERFACE: {
  387. if (InputBufferLength != sizeof(ULONG)) {
  388. status = STATUS_INVALID_BUFFER_SIZE;
  389. break;
  390. }
  391. status =
  392. NatDeleteInterface(
  393. *(PULONG)InputBuffer,
  394. FileObject
  395. );
  396. if (status == STATUS_PENDING) {
  397. //
  398. // A return of STATUS_PENDING indicates that the interface
  399. // is now marked for deletion but an active thread holds
  400. // a reference to it; convert this to a STATUS_SUCCESS code
  401. // to avoid bypassing our IRP-completion code in 'NatDispatch'.
  402. //
  403. status = STATUS_SUCCESS;
  404. }
  405. break;
  406. }
  407. case IOCTL_IP_NAT_SET_INTERFACE_INFO: {
  408. if (InputBufferLength <
  409. FIELD_OFFSET(IP_NAT_INTERFACE_INFO, Header) +
  410. FIELD_OFFSET(RTR_INFO_BLOCK_HEADER, TocEntry)
  411. ) {
  412. status = STATUS_INVALID_BUFFER_SIZE;
  413. break;
  414. }
  415. Header = &((PIP_NAT_INTERFACE_INFO)InputBuffer)->Header;
  416. if (!NatpValidateHeader(
  417. Header,
  418. InputBufferLength -
  419. FIELD_OFFSET(IP_NAT_INTERFACE_INFO, Header)
  420. )) {
  421. status = STATUS_INVALID_BUFFER_SIZE;
  422. break;
  423. }
  424. status =
  425. NatConfigureInterface(
  426. (PIP_NAT_INTERFACE_INFO)InputBuffer,
  427. FileObject
  428. );
  429. break;
  430. }
  431. case IOCTL_IP_NAT_GET_INTERFACE_INFO: {
  432. *Size = OutputBufferLength;
  433. if (InputBufferLength != sizeof(ULONG)) {
  434. status = STATUS_INVALID_BUFFER_SIZE;
  435. break;
  436. }
  437. status =
  438. NatQueryInformationInterface(
  439. *(PULONG)InputBuffer,
  440. (PIP_NAT_INTERFACE_INFO)OutputBuffer,
  441. Size
  442. );
  443. break;
  444. }
  445. case IOCTL_IP_NAT_GET_INTERFACE_STATISTICS: {
  446. if (InputBufferLength != sizeof(ULONG)) {
  447. status = STATUS_INVALID_BUFFER_SIZE;
  448. break;
  449. }
  450. if (OutputBufferLength < sizeof(IP_NAT_INTERFACE_STATISTICS)) {
  451. status = STATUS_BUFFER_TOO_SMALL;
  452. break;
  453. }
  454. *Size = sizeof(IP_NAT_INTERFACE_STATISTICS);
  455. status =
  456. NatQueryStatisticsInterface(
  457. *(PULONG)InputBuffer,
  458. (PIP_NAT_INTERFACE_STATISTICS)OutputBuffer
  459. );
  460. break;
  461. }
  462. case IOCTL_IP_NAT_GET_INTERFACE_MAPPING_TABLE: {
  463. if (!Irp) { return STATUS_PENDING; }
  464. *Size = OutputBufferLength;
  465. if (InputBufferLength <
  466. FIELD_OFFSET(IP_NAT_ENUMERATE_SESSION_MAPPINGS,
  467. EnumerateTable)) {
  468. status = STATUS_INVALID_BUFFER_SIZE;
  469. break;
  470. }
  471. if (OutputBufferLength <
  472. FIELD_OFFSET(IP_NAT_ENUMERATE_SESSION_MAPPINGS,
  473. EnumerateTable)) {
  474. status = STATUS_INVALID_BUFFER_SIZE;
  475. break;
  476. }
  477. status =
  478. NatQueryInterfaceMappingTable(
  479. (PIP_NAT_ENUMERATE_SESSION_MAPPINGS)InputBuffer,
  480. (PIP_NAT_ENUMERATE_SESSION_MAPPINGS)OutputBuffer,
  481. Size
  482. );
  483. break;
  484. }
  485. case IOCTL_IP_NAT_GET_MAPPING_TABLE: {
  486. if (!Irp) { return STATUS_PENDING; }
  487. *Size = OutputBufferLength;
  488. if (InputBufferLength <
  489. FIELD_OFFSET(IP_NAT_ENUMERATE_SESSION_MAPPINGS,
  490. EnumerateTable)) {
  491. status = STATUS_INVALID_BUFFER_SIZE;
  492. break;
  493. }
  494. if (OutputBufferLength <
  495. FIELD_OFFSET(IP_NAT_ENUMERATE_SESSION_MAPPINGS,
  496. EnumerateTable)) {
  497. status = STATUS_INVALID_BUFFER_SIZE;
  498. break;
  499. }
  500. status =
  501. NatQueryMappingTable(
  502. (PIP_NAT_ENUMERATE_SESSION_MAPPINGS)InputBuffer,
  503. (PIP_NAT_ENUMERATE_SESSION_MAPPINGS)OutputBuffer,
  504. Size
  505. );
  506. break;
  507. }
  508. case IOCTL_IP_NAT_REGISTER_DIRECTOR: {
  509. *Size = sizeof(IP_NAT_REGISTER_DIRECTOR);
  510. //
  511. // Only kernel-mode drivers can register as directors
  512. //
  513. if (RequestorMode != KernelMode ||
  514. SharedUserData->NtProductType == NtProductWinNt) {
  515. status = STATUS_ACCESS_DENIED;
  516. break;
  517. }
  518. if (InputBufferLength != sizeof(IP_NAT_REGISTER_DIRECTOR)) {
  519. status = STATUS_INVALID_BUFFER_SIZE;
  520. break;
  521. }
  522. if (OutputBufferLength < sizeof(IP_NAT_REGISTER_DIRECTOR)) {
  523. status = STATUS_BUFFER_TOO_SMALL;
  524. break;
  525. }
  526. //
  527. // Perform the director-registration
  528. //
  529. status =
  530. NatCreateDirector(
  531. (PIP_NAT_REGISTER_DIRECTOR)InputBuffer
  532. );
  533. break;
  534. }
  535. case IOCTL_IP_NAT_GET_DIRECTOR_TABLE: {
  536. if (!Irp) { return STATUS_PENDING; }
  537. *Size = OutputBufferLength;
  538. if (InputBufferLength <
  539. FIELD_OFFSET(IP_NAT_ENUMERATE_DIRECTORS, EnumerateTable)) {
  540. status = STATUS_INVALID_BUFFER_SIZE;
  541. break;
  542. }
  543. if (OutputBufferLength <
  544. FIELD_OFFSET(IP_NAT_ENUMERATE_DIRECTORS, EnumerateTable)) {
  545. status = STATUS_INVALID_BUFFER_SIZE;
  546. break;
  547. }
  548. status =
  549. NatQueryDirectorTable(
  550. (PIP_NAT_ENUMERATE_DIRECTORS)InputBuffer,
  551. (PIP_NAT_ENUMERATE_DIRECTORS)OutputBuffer,
  552. Size
  553. );
  554. break;
  555. }
  556. case IOCTL_IP_NAT_REGISTER_EDITOR: {
  557. *Size = sizeof(IP_NAT_REGISTER_EDITOR);
  558. //
  559. // Only kernel-mode drivers can register as editors
  560. //
  561. if (RequestorMode != KernelMode) {
  562. status = STATUS_ACCESS_DENIED;
  563. break;
  564. }
  565. if (InputBufferLength != sizeof(IP_NAT_REGISTER_EDITOR)) {
  566. status = STATUS_INVALID_BUFFER_SIZE;
  567. break;
  568. }
  569. if (OutputBufferLength < sizeof(IP_NAT_REGISTER_EDITOR)) {
  570. status = STATUS_BUFFER_TOO_SMALL;
  571. break;
  572. }
  573. //
  574. // Perform the editor-registration
  575. //
  576. status = NatCreateEditor((PIP_NAT_REGISTER_EDITOR)InputBuffer);
  577. break;
  578. }
  579. case IOCTL_IP_NAT_GET_EDITOR_TABLE: {
  580. if (!Irp) { return STATUS_PENDING; }
  581. *Size = OutputBufferLength;
  582. if (InputBufferLength <
  583. FIELD_OFFSET(IP_NAT_ENUMERATE_EDITORS, EnumerateTable)) {
  584. status = STATUS_INVALID_BUFFER_SIZE;
  585. break;
  586. }
  587. if (OutputBufferLength <
  588. FIELD_OFFSET(IP_NAT_ENUMERATE_EDITORS, EnumerateTable)) {
  589. status = STATUS_INVALID_BUFFER_SIZE;
  590. break;
  591. }
  592. status =
  593. NatQueryEditorTable(
  594. (PIP_NAT_ENUMERATE_EDITORS)InputBuffer,
  595. (PIP_NAT_ENUMERATE_EDITORS)OutputBuffer,
  596. Size
  597. );
  598. break;
  599. }
  600. case IOCTL_IP_NAT_CREATE_REDIRECT: {
  601. if (!Irp) { return STATUS_PENDING; }
  602. #if 0
  603. if (SharedUserData->NtProductType == NtProductWinNt) {
  604. status = STATUS_ACCESS_DENIED;
  605. break;
  606. }
  607. #endif
  608. if (InputBufferLength != sizeof(IP_NAT_CREATE_REDIRECT) ||
  609. OutputBufferLength != sizeof(IP_NAT_REDIRECT_STATISTICS)) {
  610. status = STATUS_INVALID_BUFFER_SIZE;
  611. break;
  612. }
  613. status =
  614. NatCreateRedirect(
  615. (PIP_NAT_CREATE_REDIRECT)InputBuffer,
  616. Irp,
  617. FileObject
  618. );
  619. break;
  620. }
  621. case IOCTL_IP_NAT_CREATE_REDIRECT_EX: {
  622. if (!Irp) { return STATUS_PENDING; }
  623. #if 0
  624. if (SharedUserData->NtProductType == NtProductWinNt) {
  625. status = STATUS_ACCESS_DENIED;
  626. break;
  627. }
  628. #endif
  629. if (InputBufferLength != sizeof(IP_NAT_CREATE_REDIRECT_EX) ||
  630. OutputBufferLength != sizeof(IP_NAT_REDIRECT_STATISTICS)) {
  631. status = STATUS_INVALID_BUFFER_SIZE;
  632. break;
  633. }
  634. status =
  635. NatCreateRedirectEx(
  636. (PIP_NAT_CREATE_REDIRECT_EX)InputBuffer,
  637. Irp,
  638. FileObject
  639. );
  640. break;
  641. }
  642. case IOCTL_IP_NAT_CANCEL_REDIRECT: {
  643. if (InputBufferLength != sizeof(IP_NAT_LOOKUP_REDIRECT)) {
  644. status = STATUS_INVALID_BUFFER_SIZE;
  645. break;
  646. }
  647. status =
  648. NatCancelRedirect(
  649. (PIP_NAT_LOOKUP_REDIRECT)InputBuffer,
  650. FileObject
  651. );
  652. break;
  653. }
  654. case IOCTL_IP_NAT_GET_REDIRECT_STATISTICS: {
  655. if (!Irp) { return STATUS_PENDING; }
  656. if (InputBufferLength != sizeof(IP_NAT_LOOKUP_REDIRECT) ||
  657. OutputBufferLength != sizeof(IP_NAT_REDIRECT_STATISTICS)) {
  658. status = STATUS_INVALID_BUFFER_SIZE;
  659. break;
  660. }
  661. status =
  662. NatQueryInformationRedirect(
  663. (PIP_NAT_LOOKUP_REDIRECT)InputBuffer,
  664. OutputBuffer,
  665. OutputBufferLength,
  666. NatStatisticsRedirectInformation
  667. );
  668. if (NT_SUCCESS(status)) { *Size = OutputBufferLength; }
  669. break;
  670. }
  671. case IOCTL_IP_NAT_GET_REDIRECT_DESTINATION_MAPPING: {
  672. if (!Irp) { return STATUS_PENDING; }
  673. if (InputBufferLength != sizeof(IP_NAT_LOOKUP_REDIRECT) ||
  674. OutputBufferLength !=
  675. sizeof(IP_NAT_REDIRECT_DESTINATION_MAPPING)) {
  676. status = STATUS_INVALID_BUFFER_SIZE;
  677. break;
  678. }
  679. status =
  680. NatQueryInformationRedirect(
  681. (PIP_NAT_LOOKUP_REDIRECT)InputBuffer,
  682. OutputBuffer,
  683. OutputBufferLength,
  684. NatDestinationMappingRedirectInformation
  685. );
  686. if (NT_SUCCESS(status)) { *Size = OutputBufferLength; }
  687. break;
  688. }
  689. case IOCTL_IP_NAT_GET_REDIRECT_SOURCE_MAPPING: {
  690. if (!Irp) { return STATUS_PENDING; }
  691. if (InputBufferLength != sizeof(IP_NAT_LOOKUP_REDIRECT) ||
  692. OutputBufferLength != sizeof(IP_NAT_REDIRECT_SOURCE_MAPPING)) {
  693. status = STATUS_INVALID_BUFFER_SIZE;
  694. break;
  695. }
  696. status =
  697. NatQueryInformationRedirect(
  698. (PIP_NAT_LOOKUP_REDIRECT)InputBuffer,
  699. OutputBuffer,
  700. OutputBufferLength,
  701. NatSourceMappingRedirectInformation
  702. );
  703. if (NT_SUCCESS(status)) { *Size = OutputBufferLength; }
  704. break;
  705. }
  706. case IOCTL_IP_NAT_LOOKUP_SESSION_MAPPING_KEY: {
  707. PIP_NAT_LOOKUP_SESSION_MAPPING LookupMapping;
  708. if (!Irp) { return STATUS_PENDING; }
  709. if (InputBufferLength != sizeof(IP_NAT_LOOKUP_SESSION_MAPPING) ||
  710. OutputBufferLength != sizeof(IP_NAT_SESSION_MAPPING_KEY)) {
  711. status = STATUS_INVALID_BUFFER_SIZE;
  712. break;
  713. }
  714. LookupMapping = (PIP_NAT_LOOKUP_SESSION_MAPPING)InputBuffer;
  715. status =
  716. NatLookupAndQueryInformationMapping(
  717. LookupMapping->Protocol,
  718. LookupMapping->DestinationAddress,
  719. LookupMapping->DestinationPort,
  720. LookupMapping->SourceAddress,
  721. LookupMapping->SourcePort,
  722. OutputBuffer,
  723. OutputBufferLength,
  724. NatKeySessionMappingInformation
  725. );
  726. if (NT_SUCCESS(status)) { *Size = OutputBufferLength; }
  727. break;
  728. }
  729. case IOCTL_IP_NAT_LOOKUP_SESSION_MAPPING_KEY_EX: {
  730. PIP_NAT_LOOKUP_SESSION_MAPPING LookupMapping;
  731. if (!Irp) { return STATUS_PENDING; }
  732. if (InputBufferLength != sizeof(IP_NAT_LOOKUP_SESSION_MAPPING) ||
  733. OutputBufferLength != sizeof(IP_NAT_SESSION_MAPPING_KEY_EX)) {
  734. status = STATUS_INVALID_BUFFER_SIZE;
  735. break;
  736. }
  737. LookupMapping = (PIP_NAT_LOOKUP_SESSION_MAPPING)InputBuffer;
  738. status =
  739. NatLookupAndQueryInformationMapping(
  740. LookupMapping->Protocol,
  741. LookupMapping->DestinationAddress,
  742. LookupMapping->DestinationPort,
  743. LookupMapping->SourceAddress,
  744. LookupMapping->SourcePort,
  745. OutputBuffer,
  746. OutputBufferLength,
  747. NatKeySessionMappingExInformation
  748. );
  749. if (NT_SUCCESS(status)) { *Size = OutputBufferLength; }
  750. break;
  751. }
  752. case IOCTL_IP_NAT_LOOKUP_SESSION_MAPPING_STATISTICS: {
  753. PIP_NAT_LOOKUP_SESSION_MAPPING LookupMapping;
  754. if (!Irp) { return STATUS_PENDING; }
  755. if (InputBufferLength != sizeof(IP_NAT_LOOKUP_SESSION_MAPPING) ||
  756. OutputBufferLength != sizeof(IP_NAT_SESSION_MAPPING_STATISTICS)) {
  757. status = STATUS_INVALID_BUFFER_SIZE;
  758. break;
  759. }
  760. LookupMapping = (PIP_NAT_LOOKUP_SESSION_MAPPING)InputBuffer;
  761. status =
  762. NatLookupAndQueryInformationMapping(
  763. LookupMapping->Protocol,
  764. LookupMapping->DestinationAddress,
  765. LookupMapping->DestinationPort,
  766. LookupMapping->SourceAddress,
  767. LookupMapping->SourcePort,
  768. OutputBuffer,
  769. OutputBufferLength,
  770. NatStatisticsSessionMappingInformation
  771. );
  772. if (NT_SUCCESS(status)) { *Size = OutputBufferLength; }
  773. break;
  774. }
  775. case IOCTL_IP_NAT_CREATE_DYNAMIC_TICKET: {
  776. if (InputBufferLength < sizeof(IP_NAT_CREATE_DYNAMIC_TICKET)) {
  777. status = STATUS_INVALID_BUFFER_SIZE;
  778. break;
  779. }
  780. status =
  781. NatCreateDynamicTicket(
  782. (PIP_NAT_CREATE_DYNAMIC_TICKET)InputBuffer,
  783. InputBufferLength,
  784. FileObject
  785. );
  786. break;
  787. }
  788. case IOCTL_IP_NAT_DELETE_DYNAMIC_TICKET: {
  789. if (InputBufferLength != sizeof(IP_NAT_DELETE_DYNAMIC_TICKET)) {
  790. status = STATUS_INVALID_BUFFER_SIZE;
  791. break;
  792. }
  793. status =
  794. NatDeleteDynamicTicket(
  795. (PIP_NAT_DELETE_DYNAMIC_TICKET)InputBuffer,
  796. FileObject
  797. );
  798. break;
  799. }
  800. case IOCTL_IP_NAT_CREATE_TICKET: {
  801. if (InputBufferLength != sizeof(IP_NAT_CREATE_TICKET)) {
  802. status = STATUS_INVALID_BUFFER_SIZE;
  803. break;
  804. }
  805. status =
  806. NatProcessCreateTicket(
  807. (PIP_NAT_CREATE_TICKET)InputBuffer,
  808. FileObject
  809. );
  810. break;
  811. }
  812. case IOCTL_IP_NAT_DELETE_TICKET: {
  813. if (InputBufferLength != sizeof(IP_NAT_CREATE_TICKET)) {
  814. status = STATUS_INVALID_BUFFER_SIZE;
  815. break;
  816. }
  817. status =
  818. NatProcessDeleteTicket(
  819. (PIP_NAT_CREATE_TICKET)InputBuffer,
  820. FileObject
  821. );
  822. break;
  823. }
  824. case IOCTL_IP_NAT_LOOKUP_TICKET: {
  825. if (InputBufferLength != sizeof(IP_NAT_CREATE_TICKET)) {
  826. status = STATUS_INVALID_BUFFER_SIZE;
  827. break;
  828. }
  829. if (OutputBufferLength != sizeof(IP_NAT_PORT_MAPPING)) {
  830. status = STATUS_INVALID_BUFFER_SIZE;
  831. break;
  832. }
  833. status =
  834. NatProcessLookupTicket(
  835. (PIP_NAT_CREATE_TICKET)InputBuffer,
  836. (PIP_NAT_PORT_MAPPING)OutputBuffer,
  837. FileObject
  838. );
  839. break;
  840. }
  841. default: {
  842. status = STATUS_INVALID_PARAMETER;
  843. break;
  844. }
  845. }
  846. return status;
  847. } // NatpExecuteIoDeviceControl
  848. NTSTATUS
  849. NatpSetGlobalInfo(
  850. PVOID InputBuffer,
  851. ULONG InputBufferLength,
  852. PVOID OutputBuffer,
  853. ULONG OutputBufferLength,
  854. PULONG Size
  855. )
  856. /*++
  857. Routine Description:
  858. This routine is invoked upon receipt of the NAT's configuration.
  859. Arguments:
  860. InputBuffer/InputBufferLength - describe configuration information
  861. OutputBuffer/OutputBufferLength - unused.
  862. Size - unused
  863. Return Value:
  864. NTSTATUS - status code.
  865. --*/
  866. {
  867. PRTR_TOC_ENTRY Entry;
  868. PRTR_INFO_BLOCK_HEADER Header;
  869. ULONG i;
  870. ULONG Protocol;
  871. if (InputBufferLength <
  872. FIELD_OFFSET(IP_NAT_GLOBAL_INFO, Header) +
  873. FIELD_OFFSET(RTR_INFO_BLOCK_HEADER, TocEntry)
  874. ) {
  875. return STATUS_INVALID_BUFFER_SIZE;
  876. }
  877. Header = &((PIP_NAT_GLOBAL_INFO)InputBuffer)->Header;
  878. if (!NatpValidateHeader(
  879. Header,
  880. InputBufferLength - FIELD_OFFSET(IP_NAT_GLOBAL_INFO, Header)
  881. )) {
  882. return STATUS_INVALID_BUFFER_SIZE;
  883. }
  884. for (i = 0; i < Header->TocEntriesCount; i++) {
  885. Entry = &Header->TocEntry[i];
  886. switch (Entry->InfoType) {
  887. case IP_NAT_TIMEOUT_TYPE: {
  888. PIP_NAT_TIMEOUT Timeout = GetInfoFromTocEntry(Header,Entry);
  889. InterlockedExchange(
  890. &TcpTimeoutSeconds,
  891. Timeout->TCPTimeoutSeconds
  892. );
  893. InterlockedExchange(
  894. &UdpTimeoutSeconds,
  895. Timeout->UDPTimeoutSeconds
  896. );
  897. break;
  898. }
  899. case IP_NAT_PROTOCOLS_ALLOWED_TYPE: {
  900. PIP_NAT_PROTOCOLS_ALLOWED ProtocolsAllowed =
  901. GetInfoFromTocEntry(Header,Entry);
  902. //
  903. // The protocols allowed are specified using a 256-bit bitmap;
  904. // an allowed protocol has the bit for its protocol number set.
  905. // For each protocol enabled in the bitmap, we now install the
  906. // default IP-header translation routine, with the exception
  907. // of protocols which are always enabled.
  908. //
  909. #define IS_BIT_SET(b,i) ((b)[(i) / 32] & (1 << ((i) & 31)))
  910. for (Protocol = 0; Protocol < 256; Protocol++) {
  911. if (Protocol == NAT_PROTOCOL_ICMP ||
  912. Protocol == NAT_PROTOCOL_PPTP ||
  913. Protocol == NAT_PROTOCOL_TCP ||
  914. Protocol == NAT_PROTOCOL_UDP
  915. ) {
  916. continue;
  917. }
  918. if (IS_BIT_SET(ProtocolsAllowed->Bitmap, Protocol)) {
  919. InterlockedExchangePointer(
  920. (PVOID)TranslateRoutineTable[Protocol],
  921. (PVOID)NatTranslateIp
  922. );
  923. }
  924. else {
  925. InterlockedExchangePointer(
  926. (PVOID)TranslateRoutineTable[Protocol],
  927. NULL
  928. );
  929. }
  930. }
  931. break;
  932. }
  933. }
  934. }
  935. return STATUS_SUCCESS;
  936. }
  937. BOOLEAN FASTCALL
  938. NatpValidateHeader(
  939. PRTR_INFO_BLOCK_HEADER Header,
  940. ULONG Size
  941. )
  942. /*++
  943. Routine Description:
  944. This routine is invoked to ensure that the given header is consistent.
  945. This is the case if
  946. * the header's size is less than or equal to 'Size'
  947. * each entry in the header is contained in 'Header->Size'.
  948. * the data for each entry is contained in 'Header->Size'.
  949. Arguments:
  950. Header - the header to be validated
  951. Size - the size of the buffer in which 'Header' appears
  952. Return Value:
  953. BOOLEAN - TRUE if valid, FALSE otherwise.
  954. --*/
  955. {
  956. ULONG i;
  957. ULONG64 Length;
  958. //
  959. // Check that the base structure is present
  960. //
  961. if (Size < FIELD_OFFSET(RTR_INFO_BLOCK_HEADER, TocEntry) ||
  962. Size < Header->Size) {
  963. return FALSE;
  964. }
  965. //
  966. // Check that the table of contents is present
  967. //
  968. Length = (ULONG64)Header->TocEntriesCount * sizeof(RTR_TOC_ENTRY);
  969. if (Length > MAXLONG) {
  970. return FALSE;
  971. }
  972. Length += FIELD_OFFSET(RTR_INFO_BLOCK_HEADER, TocEntry);
  973. if (Length > Header->Size) {
  974. return FALSE;
  975. }
  976. //
  977. // Check that all the data is present
  978. //
  979. for (i = 0; i < Header->TocEntriesCount; i++) {
  980. Length =
  981. (ULONG64)Header->TocEntry[i].Count * Header->TocEntry[i].InfoSize;
  982. if (Length > MAXLONG) {
  983. return FALSE;
  984. }
  985. if ((Length + Header->TocEntry[i].Offset) > Header->Size) {
  986. return FALSE;
  987. }
  988. }
  989. return TRUE;
  990. } // NatpValidateHeader