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.

430 lines
11 KiB

  1. /*++
  2. Copyright (c) 2000, Microsoft Corporation
  3. Module Name:
  4. ipfw.c
  5. Abstract:
  6. This module implements a driver which demonstrates the use of
  7. the TCP/IP driver's support for firewall hooks. It interacts with
  8. a user-mode control-program to support registration of multiple
  9. firewall routines.
  10. Author:
  11. Abolade Gbadegesin (aboladeg) 7-March-2000
  12. Revision History:
  13. --*/
  14. #include <ndis.h>
  15. #include <ipfirewall.h>
  16. #include "ipfw.h"
  17. //
  18. // Structure: IPFW_ROUTINE
  19. //
  20. // Used to manage the table of routines registered with TCP/IP.
  21. //
  22. typedef struct _IPFW_ROUTINE {
  23. IPPacketFirewallPtr Routine;
  24. UINT Priority;
  25. ULONG Flags;
  26. ULONG PacketCount;
  27. } IPFW_ROUTINE, *PIPFW_ROUTINE;
  28. #define IPFW_ROUTINE_FLAG_REGISTERED 0x00000001
  29. extern IPFW_ROUTINE IpfwRoutineTable[];
  30. #define DEFINE_IPFW_ROUTINE(_Index) \
  31. FORWARD_ACTION IpfwRoutine##_Index( \
  32. VOID** Data, \
  33. UINT ReceiveIndex, \
  34. UINT* SendIndex, \
  35. PUCHAR DestinationType, \
  36. PVOID Context, \
  37. UINT ContextLength, \
  38. IPRcvBuf** OutputData \
  39. ) { \
  40. InterlockedIncrement(&IpfwRoutineTable[_Index].PacketCount); \
  41. return FORWARD; \
  42. }
  43. #define INCLUDE_IPFW_ROUTINE(_Index) \
  44. { IpfwRoutine##_Index, 0, 0 },
  45. DEFINE_IPFW_ROUTINE(0)
  46. DEFINE_IPFW_ROUTINE(1)
  47. DEFINE_IPFW_ROUTINE(2)
  48. DEFINE_IPFW_ROUTINE(3)
  49. DEFINE_IPFW_ROUTINE(4)
  50. DEFINE_IPFW_ROUTINE(5)
  51. DEFINE_IPFW_ROUTINE(6)
  52. DEFINE_IPFW_ROUTINE(7)
  53. DEFINE_IPFW_ROUTINE(8)
  54. DEFINE_IPFW_ROUTINE(9)
  55. IPFW_ROUTINE IpfwRoutineTable[IPFW_ROUTINE_COUNT] = {
  56. INCLUDE_IPFW_ROUTINE(0)
  57. INCLUDE_IPFW_ROUTINE(1)
  58. INCLUDE_IPFW_ROUTINE(2)
  59. INCLUDE_IPFW_ROUTINE(3)
  60. INCLUDE_IPFW_ROUTINE(4)
  61. INCLUDE_IPFW_ROUTINE(5)
  62. INCLUDE_IPFW_ROUTINE(6)
  63. INCLUDE_IPFW_ROUTINE(7)
  64. INCLUDE_IPFW_ROUTINE(8)
  65. INCLUDE_IPFW_ROUTINE(9)
  66. };
  67. KSPIN_LOCK IpfwRoutineLock;
  68. PDEVICE_OBJECT IpfwDeviceObject = NULL;
  69. //
  70. // FORWARD DECLARATIONS
  71. //
  72. NTSTATUS
  73. IpfwClose(
  74. PDEVICE_OBJECT DeviceObject,
  75. PIRP Irp
  76. );
  77. NTSTATUS
  78. IpfwCreate(
  79. PDEVICE_OBJECT DeviceObject,
  80. PIRP Irp
  81. );
  82. VOID
  83. IpfwUnload(
  84. IN PDRIVER_OBJECT DriverObject
  85. );
  86. NTSTATUS
  87. DriverEntry(
  88. IN PDRIVER_OBJECT DriverObject,
  89. IN PUNICODE_STRING RegistryPath
  90. )
  91. /*++
  92. Routine Description:
  93. This routine implements the standard driver-entry for an NT driver.
  94. It is responsible for registering with the TCP/IP driver.
  95. Arguments:
  96. DriverObject - object to be initialized with NT driver entrypoints
  97. RegistryPath - contains path to this driver's registry key
  98. Return Value:
  99. NTSTATUS - indicates success/failure.
  100. --*/
  101. {
  102. UNICODE_STRING DeviceName;
  103. OBJECT_ATTRIBUTES ObjectAttributes;
  104. HANDLE ServiceKey;
  105. NTSTATUS status;
  106. KdPrint(("DriverEntry\n"));
  107. KeInitializeSpinLock(&IpfwRoutineLock);
  108. //
  109. // Create a device-object on which to communicate with the control program.
  110. //
  111. RtlInitUnicodeString(&DeviceName, DD_IPFW_DEVICE_NAME);
  112. status =
  113. IoCreateDevice(
  114. DriverObject,
  115. 0,
  116. &DeviceName,
  117. FILE_DEVICE_NETWORK,
  118. FILE_DEVICE_SECURE_OPEN,
  119. FALSE,
  120. &IpfwDeviceObject
  121. );
  122. if (!NT_SUCCESS(status)) {
  123. KdPrint(("DriverEntry: IoCreateDevice=%08x\n", status));
  124. return status;
  125. }
  126. //
  127. // Create dispatch points for create/open, cleanup, unload.
  128. //
  129. DriverObject->MajorFunction[IRP_MJ_CREATE] = IpfwCreate;
  130. DriverObject->MajorFunction[IRP_MJ_CLOSE] = IpfwClose;
  131. DriverObject->DriverUnload = IpfwUnload;
  132. return STATUS_SUCCESS;
  133. } // DriverEntry
  134. NTSTATUS
  135. IpfwClose(
  136. PDEVICE_OBJECT DeviceObject,
  137. PIRP Irp
  138. )
  139. {
  140. UNICODE_STRING DeviceString;
  141. KEVENT Event;
  142. PFILE_OBJECT FileObject;
  143. ULONG i;
  144. IO_STATUS_BLOCK IoStatus;
  145. PDEVICE_OBJECT IpDeviceObject;
  146. KIRQL Irql;
  147. PIRP RegisterIrp;
  148. IP_SET_FIREWALL_HOOK_INFO SetHookInfo;
  149. NTSTATUS status;
  150. KdPrint(("IpfwClose\n"));
  151. i = PtrToUlong(IoGetCurrentIrpStackLocation(Irp)->FileObject->FsContext);
  152. #if DBG
  153. KeAcquireSpinLock(&IpfwRoutineLock, &Irql);
  154. ASSERT(IpfwRoutineTable[i].Flags & IPFW_ROUTINE_FLAG_REGISTERED);
  155. KeReleaseSpinLock(&IpfwRoutineLock, Irql);
  156. #endif
  157. //
  158. // Revoke the registration made on behalf of the client whose file-object
  159. // is being closed.
  160. // Obtain a pointer to the IP device-object,
  161. // construct a registration IRP, and attempt to register the routine
  162. // selected above.
  163. //
  164. RtlInitUnicodeString(&DeviceString, DD_IP_DEVICE_NAME);
  165. status =
  166. IoGetDeviceObjectPointer(
  167. &DeviceString,
  168. SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE,
  169. &FileObject,
  170. &IpDeviceObject
  171. );
  172. if (NT_SUCCESS(status)) {
  173. ObReferenceObject(IpDeviceObject);
  174. SetHookInfo.FirewallPtr = IpfwRoutineTable[i].Routine;
  175. SetHookInfo.Priority = 0; // Unused
  176. SetHookInfo.Add = FALSE;
  177. KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
  178. RegisterIrp =
  179. IoBuildDeviceIoControlRequest(
  180. IOCTL_IP_SET_FIREWALL_HOOK,
  181. IpDeviceObject,
  182. (PVOID)&SetHookInfo,
  183. sizeof(SetHookInfo),
  184. NULL,
  185. 0,
  186. FALSE,
  187. &Event,
  188. &IoStatus
  189. );
  190. if (!RegisterIrp) {
  191. status = STATUS_UNSUCCESSFUL;
  192. } else {
  193. status = IoCallDriver(IpDeviceObject, RegisterIrp);
  194. if (status == STATUS_PENDING) {
  195. KeWaitForSingleObject(
  196. &Event, Executive, KernelMode, FALSE, NULL
  197. );
  198. status = IoStatus.Status;
  199. }
  200. ASSERT(NT_SUCCESS(status));
  201. }
  202. ObDereferenceObject((PVOID)FileObject);
  203. ObDereferenceObject(IpDeviceObject);
  204. }
  205. //
  206. // Release the entry in the table of routines.
  207. //
  208. KeAcquireSpinLock(&IpfwRoutineLock, &Irql);
  209. IpfwRoutineTable[i].Flags &= ~IPFW_ROUTINE_FLAG_REGISTERED;
  210. KeReleaseSpinLock(&IpfwRoutineLock, Irql);
  211. Irp->IoStatus.Status = STATUS_SUCCESS;
  212. Irp->IoStatus.Information = 0;
  213. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  214. return STATUS_SUCCESS;
  215. } // IpfwClose
  216. NTSTATUS
  217. IpfwCreate(
  218. PDEVICE_OBJECT DeviceObject,
  219. PIRP Irp
  220. )
  221. /*++
  222. Routine Description:
  223. This routine is invoked by the I/O manager to inform us that a handle has
  224. been opened on our device-object.
  225. --*/
  226. {
  227. PIPFW_CREATE_PACKET CreatePacket;
  228. UNICODE_STRING DeviceString;
  229. PFILE_FULL_EA_INFORMATION EaBuffer;
  230. KEVENT Event;
  231. PFILE_OBJECT FileObject;
  232. ULONG i;
  233. IO_STATUS_BLOCK IoStatus;
  234. PDEVICE_OBJECT IpDeviceObject;
  235. KIRQL Irql;
  236. UINT Priority;
  237. PIRP RegisterIrp;
  238. IP_SET_FIREWALL_HOOK_INFO SetHookInfo;
  239. NTSTATUS status;
  240. KdPrint(("IpfwCreate\n"));
  241. //
  242. // Extract the parameters supplied by the caller.
  243. //
  244. if ((EaBuffer = Irp->AssociatedIrp.SystemBuffer) &&
  245. EaBuffer->EaValueLength >= sizeof(IPFW_CREATE_PACKET)) {
  246. CreatePacket =
  247. (PIPFW_CREATE_PACKET)
  248. (EaBuffer->EaName + EaBuffer->EaNameLength + 1);
  249. Priority = CreatePacket->Priority;
  250. } else {
  251. Priority = 0;
  252. }
  253. //
  254. // Look for a free entry in the function-table
  255. //
  256. KeAcquireSpinLock(&IpfwRoutineLock, &Irql);
  257. for (i = 0; i < IPFW_ROUTINE_COUNT; i++) {
  258. if (!(IpfwRoutineTable[i].Flags & IPFW_ROUTINE_FLAG_REGISTERED)) {
  259. IpfwRoutineTable[i].Flags |= IPFW_ROUTINE_FLAG_REGISTERED;
  260. break;
  261. }
  262. }
  263. KeReleaseSpinLock(&IpfwRoutineLock, Irql);
  264. if (i >= IPFW_ROUTINE_COUNT) {
  265. status = STATUS_UNSUCCESSFUL;
  266. } else {
  267. //
  268. // Obtain a pointer to the IP device-object,
  269. // construct a registration IRP, and attempt to register the routine
  270. // selected above.
  271. //
  272. RtlInitUnicodeString(&DeviceString, DD_IP_DEVICE_NAME);
  273. status =
  274. IoGetDeviceObjectPointer(
  275. &DeviceString,
  276. SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE,
  277. &FileObject,
  278. &IpDeviceObject
  279. );
  280. if (NT_SUCCESS(status)) {
  281. ObReferenceObject(IpDeviceObject);
  282. SetHookInfo.FirewallPtr = IpfwRoutineTable[i].Routine;
  283. SetHookInfo.Priority = Priority ? Priority : i + 1;
  284. SetHookInfo.Add = TRUE;
  285. KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
  286. RegisterIrp =
  287. IoBuildDeviceIoControlRequest(
  288. IOCTL_IP_SET_FIREWALL_HOOK,
  289. IpDeviceObject,
  290. (PVOID)&SetHookInfo,
  291. sizeof(SetHookInfo),
  292. NULL,
  293. 0,
  294. FALSE,
  295. &Event,
  296. &IoStatus
  297. );
  298. if (!RegisterIrp) {
  299. status = STATUS_UNSUCCESSFUL;
  300. } else {
  301. status = IoCallDriver(IpDeviceObject, RegisterIrp);
  302. if (status == STATUS_PENDING) {
  303. KeWaitForSingleObject(
  304. &Event, Executive, KernelMode, FALSE, NULL
  305. );
  306. status = IoStatus.Status;
  307. }
  308. }
  309. ObDereferenceObject((PVOID)FileObject);
  310. ObDereferenceObject(IpDeviceObject);
  311. }
  312. //
  313. // If the routine was successfully registered, remember its index
  314. // in the client's file-object. Otherwise, if the routine could not be
  315. // registered for any reason, release it.
  316. //
  317. if (NT_SUCCESS(status)) {
  318. IoGetCurrentIrpStackLocation(Irp)->FileObject->FsContext = UlongToPtr(i);
  319. } else {
  320. KeAcquireSpinLock(&IpfwRoutineLock, &Irql);
  321. IpfwRoutineTable[i].Flags &= ~IPFW_ROUTINE_FLAG_REGISTERED;
  322. KeReleaseSpinLock(&IpfwRoutineLock, Irql);
  323. }
  324. }
  325. IoStatus.Status = status;
  326. IoStatus.Information = 0;
  327. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  328. return status;
  329. } // IpfwCreate
  330. VOID
  331. IpfwUnload(
  332. IN PDRIVER_OBJECT DriverObject
  333. )
  334. /*++
  335. Routine Description:
  336. This routine is invoked by the I/O manager to unload this driver.
  337. Arguments:
  338. DriverObject - the object for this driver
  339. Return Value:
  340. none.
  341. --*/
  342. {
  343. KdPrint(("IpfwUnload\n"));
  344. if (IpfwDeviceObject) {
  345. IoDeleteDevice(IpfwDeviceObject);
  346. }
  347. }