From 1c9c7ca9d730bf06cba08e650ab944ad77b5bb2e Mon Sep 17 00:00:00 2001 From: Nodir Temirkhodjaev Date: Tue, 30 Dec 2014 16:00:52 +0500 Subject: [PATCH] Initial commit. --- .gitignore | 3 + README | 4 + src/common.h | 11 ++ src/drv/msvcbuild.bat | 5 + src/drv/wipfdrv.c | 375 ++++++++++++++++++++++++++++++++++++++++ src/drv/wipfdrv.h | 38 ++++ src/drv/wipfdrv.vcxproj | 90 ++++++++++ 7 files changed, 526 insertions(+) create mode 100644 .gitignore create mode 100644 README create mode 100644 src/common.h create mode 100644 src/drv/msvcbuild.bat create mode 100644 src/drv/wipfdrv.c create mode 100644 src/drv/wipfdrv.h create mode 100644 src/drv/wipfdrv.vcxproj diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..2c8e77ae --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +bin/*.pdb +bin/*.sys +src/drv/Win*/ diff --git a/README b/README new file mode 100644 index 00000000..4eae231a --- /dev/null +++ b/README @@ -0,0 +1,4 @@ +Windows IP Filter is a simple firewall. + +-- +Nodir Temirkhodjaev, diff --git a/src/common.h b/src/common.h new file mode 100644 index 00000000..6c95d236 --- /dev/null +++ b/src/common.h @@ -0,0 +1,11 @@ +#ifndef COMMON_H +#define COMMON_H + +typedef struct wipf_conf { + UINT32 len; + UCHAR data[1]; +} WIPF_CONF, *PWIPF_CONF; + +#define UNUSED(p) ((void) (p)) + +#endif COMMON_H diff --git a/src/drv/msvcbuild.bat b/src/drv/msvcbuild.bat new file mode 100644 index 00000000..865cc351 --- /dev/null +++ b/src/drv/msvcbuild.bat @@ -0,0 +1,5 @@ +@rem Open "Visual Studio .NET Command Prompt" to run this script + +@setlocal + +MSBuild wipfdrv.vcxproj diff --git a/src/drv/wipfdrv.c b/src/drv/wipfdrv.c new file mode 100644 index 00000000..9b4431f1 --- /dev/null +++ b/src/drv/wipfdrv.c @@ -0,0 +1,375 @@ +/* Windows IP Filter Driver */ + +#define NDIS_WDM 1 +#define NDIS630 1 + +#include +#include +#include +#include + +#include "../common.h" +#include "wipfdrv.h" + +typedef struct wipf_conf_ref { + UINT32 volatile refcount; + + WIPF_CONF conf; +} WIPF_CONF_REF, *PWIPF_CONF_REF; + +typedef struct wipf_driver { + UINT32 connect4_id; + UINT32 accept4_id; + + PWIPF_CONF_REF volatile conf_ref; + + KSPIN_LOCK lock; +} WIPF_DRIVER, *PWIPF_DRIVER; + +static PWIPF_DRIVER g_driver; + +#define WIPF_POOL_TAG 'WIPF' + +#define wipf_request_complete(irp, status) \ + do { \ + (irp)->IoStatus.Status = (status); \ + (irp)->IoStatus.Information = 0; \ + IoCompleteRequest((irp), IO_NO_INCREMENT); \ + } while(0) + + +static PWIPF_CONF_REF +wipf_conf_ref_new (const PWIPF_CONF conf, ULONG len) +{ + const ULONG ref_len = len + offsetof(WIPF_CONF_REF, conf); + PWIPF_CONF_REF conf_ref = ExAllocatePoolWithTag(NonPagedPool, ref_len, WIPF_POOL_TAG); + + if (conf_ref != NULL) { + conf_ref->refcount = 0; + + RtlCopyMemory(&conf_ref->conf, conf, len); + } + + return conf_ref; +} + +static void +wipf_conf_ref_put (PWIPF_CONF_REF conf_ref) +{ + KIRQL irq; + + KeAcquireSpinLock(&g_driver->lock, &irq); + { + const UINT32 refcount = --conf_ref->refcount; + + if (refcount == 0 && conf_ref != g_driver->conf_ref) { + ExFreePoolWithTag(conf_ref, WIPF_POOL_TAG); + } + } + KeReleaseSpinLock(&g_driver->lock, irq); +} + +static PWIPF_CONF_REF +wipf_conf_ref_take (void) +{ + PWIPF_CONF_REF conf_ref; + KIRQL irq; + + KeAcquireSpinLock(&g_driver->lock, &irq); + { + conf_ref = g_driver->conf_ref; + if (conf_ref) { + ++conf_ref->refcount; + } + } + KeReleaseSpinLock(&g_driver->lock, irq); + + return conf_ref; +} + +static void +wipf_conf_ref_set (PWIPF_CONF_REF conf_ref) +{ + PWIPF_CONF_REF old_conf_ref; + KIRQL irq; + + old_conf_ref = wipf_conf_ref_take(); + + KeAcquireSpinLock(&g_driver->lock, &irq); + { + g_driver->conf_ref = conf_ref; + } + KeReleaseSpinLock(&g_driver->lock, irq); + + wipf_conf_ref_put(old_conf_ref); +} + +static BOOL +wipf_conf_ipblocked (const PWIPF_CONF conf, UINT32 local_ip, UINT32 remote_ip) +{ + UNUSED(conf); + UNUSED(local_ip); + UNUSED(remote_ip); + + return TRUE; +} + +static NTSTATUS +wipf_callout_classify_v4 (const FWPS_INCOMING_VALUES0 *inFixedValues, + const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues, + VOID *packet, const FWPS_FILTER0 *filter, UINT64 flowContext, + FWPS_CLASSIFY_OUT0 *classifyOut, + int localIpField, int remoteIpField) +{ + PWIPF_CONF_REF conf_ref; + BOOL blocked; + + UNUSED(inMetaValues); + UNUSED(packet); + UNUSED(filter); + UNUSED(flowContext); + + conf_ref = wipf_conf_ref_take(); + if (conf_ref == NULL) + return STATUS_SUCCESS; + + /* Check IP */ + { + const UINT32 local_ip = inFixedValues->incomingValue[localIpField].value.uint32; + const UINT32 remote_ip = inFixedValues->incomingValue[remoteIpField].value.uint32; + + blocked = wipf_conf_ipblocked(&conf_ref->conf, local_ip, remote_ip); + } + + wipf_conf_ref_put(conf_ref); + + if (blocked) { + if (filter->flags & FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT) { + classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE; + } + classifyOut->actionType = FWP_ACTION_BLOCK; + + return STATUS_SUCCESS; + } + + classifyOut->actionType = FWP_ACTION_CONTINUE; + + return STATUS_SUCCESS; +} + +static NTSTATUS +wipf_callout_connect_v4 (const FWPS_INCOMING_VALUES0 *inFixedValues, + const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues, + VOID *packet, const FWPS_FILTER0 *filter, UINT64 flowContext, + FWPS_CLASSIFY_OUT0 *classifyOut) +{ + return wipf_callout_classify_v4(inFixedValues, inMetaValues, packet, filter, flowContext, classifyOut, + FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_LOCAL_ADDRESS, + FWPS_FIELD_ALE_AUTH_CONNECT_V4_IP_REMOTE_ADDRESS); +} + +static NTSTATUS +wipf_callout_accept_v4 (const FWPS_INCOMING_VALUES0 *inFixedValues, + const FWPS_INCOMING_METADATA_VALUES0 *inMetaValues, + VOID *packet, const FWPS_FILTER0 *filter, UINT64 flowContext, + FWPS_CLASSIFY_OUT0 *classifyOut) +{ + return wipf_callout_classify_v4(inFixedValues, inMetaValues, packet, filter, flowContext, classifyOut, + FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_LOCAL_ADDRESS, + FWPS_FIELD_ALE_AUTH_RECV_ACCEPT_V4_IP_REMOTE_ADDRESS); +} + +static NTSTATUS NTAPI +wipf_callout_notify (FWPS_CALLOUT_NOTIFY_TYPE notifyType, const GUID *filterKey, const FWPS_FILTER0 *filter) +{ + UNUSED(notifyType); + UNUSED(filterKey); + UNUSED(filter); + + return STATUS_SUCCESS; +} + +static NTSTATUS +wipf_callout_install (PDEVICE_OBJECT device) +{ + FWPS_CALLOUT0 c = {0}; + NTSTATUS status; + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_TRACE_LEVEL, "wipf: > wipf_callout_install()\n"); + + c.notifyFn = wipf_callout_notify; + + /* IPv4 connect filter */ + + c.calloutKey = WIPF_CONNECT_CALLOUT_V4; + c.classifyFn = wipf_callout_connect_v4; + + status = FwpsCalloutRegister0(device, &c, &g_driver->connect4_id); + if (!NT_SUCCESS(status)) { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_TRACE_LEVEL, "wipf: Register Connect V4: Error: %d\n", status); + return status; + } + + /* IPv4 accept filter */ + + c.calloutKey = WIPF_ACCEPT_CALLOUT_V4; + c.classifyFn = wipf_callout_accept_v4; + + status = FwpsCalloutRegister0(device, &c, &g_driver->accept4_id); + if (!NT_SUCCESS(status)) { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_TRACE_LEVEL, "wipf: Register Accept V4: Error: %d\n", status); + return status; + } + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_TRACE_LEVEL, "wipf: < wipf_callout_install()\n"); + return STATUS_SUCCESS; +} + +static NTSTATUS +wipf_driver_complete (PDEVICE_OBJECT device, PIRP irp) +{ + UNUSED(device); + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_TRACE_LEVEL, "wipf: > wipf_driver_complete()\n"); + + wipf_request_complete(irp, STATUS_SUCCESS); + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_TRACE_LEVEL, "wipf: < wipf_driver_complete()\n"); + return STATUS_SUCCESS; +} + +static NTSTATUS +wipf_driver_cleanup (PDEVICE_OBJECT device, PIRP irp) +{ + UNUSED(device); + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_TRACE_LEVEL, "wipf: > wipf_driver_cleanup()\n"); + + wipf_conf_ref_set(NULL); + + wipf_request_complete(irp, STATUS_SUCCESS); + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_TRACE_LEVEL, "wipf: < wipf_driver_cleanup()\n"); + return STATUS_SUCCESS; +} + +static NTSTATUS +wipf_driver_control (PDEVICE_OBJECT device, PIRP irp) +{ + PIO_STACK_LOCATION irp_stack; + NTSTATUS status = STATUS_INVALID_PARAMETER; + + UNUSED(device); + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_TRACE_LEVEL, "wipf: > wipf_driver_control()\n"); + + irp_stack = IoGetCurrentIrpStackLocation(irp); + + switch (irp_stack->Parameters.DeviceIoControl.IoControlCode) { + case WIPF_IOCTL_SETCONF: { + const PWIPF_CONF conf = irp->AssociatedIrp.SystemBuffer; + const ULONG len = irp_stack->Parameters.DeviceIoControl.InputBufferLength; + + if (len >= sizeof(WIPF_CONF)) { + PWIPF_CONF_REF conf_ref = wipf_conf_ref_new(conf, len); + + if (conf_ref == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + } else { + wipf_conf_ref_set(conf_ref); + status = STATUS_SUCCESS; + } + } + break; + } + default: break; + } + + if (!NT_SUCCESS(status)) { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, "wipf: Control: Error: %d\n", status); + } + + wipf_request_complete(irp, status); + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_TRACE_LEVEL, "wipf: < wipf_driver_control()\n"); + return status; +} + +static void +wipf_driver_unload (PDRIVER_OBJECT driver) +{ + UNICODE_STRING device_link; + NTSTATUS status; + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_TRACE_LEVEL, "wipf: > wipf_driver_unload()\n"); + + if (g_driver->connect4_id) { + status = FwpsCalloutUnregisterById0(g_driver->connect4_id); + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_TRACE_LEVEL, "wipf: Unregister Connect V4: %d\n", status); + } + + if (g_driver->accept4_id) { + status = FwpsCalloutUnregisterById0(g_driver->accept4_id); + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_TRACE_LEVEL, "wipf: Unregister Accept V4: %d\n", status); + } + + RtlInitUnicodeString(&device_link, DOS_DEVICE_NAME); + IoDeleteSymbolicLink(&device_link); + + IoDeleteDevice(driver->DeviceObject); + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_TRACE_LEVEL, "wipf: < wipf_driver_unload()\n"); +} + +NTSTATUS +DriverEntry (PDRIVER_OBJECT driver, PUNICODE_STRING reg_path) +{ + UNICODE_STRING device_name; + PDEVICE_OBJECT device; + NTSTATUS status; + + UNUSED(reg_path); + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_TRACE_LEVEL, "wipf: > DriverEntry()\n"); + + RtlInitUnicodeString(&device_name, NT_DEVICE_NAME); + status = IoCreateDevice(driver, sizeof(WIPF_DRIVER), &device_name, + WIPF_DEVICE_TYPE, 0, FALSE, &device); + + if (NT_SUCCESS(status)) { + UNICODE_STRING device_link; + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_TRACE_LEVEL, "wipf: Device created\n"); + + RtlInitUnicodeString(&device_link, DOS_DEVICE_NAME); + status = IoCreateSymbolicLink(&device_link, &device_name); + + if (NT_SUCCESS(status)) { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_TRACE_LEVEL, "wipf: Device link created\n"); + + driver->MajorFunction[IRP_MJ_CREATE] = + driver->MajorFunction[IRP_MJ_CLOSE] = wipf_driver_complete; + driver->MajorFunction[IRP_MJ_CLEANUP] = wipf_driver_cleanup; + driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = wipf_driver_control; + driver->DriverUnload = wipf_driver_unload; + + device->Flags |= DO_BUFFERED_IO; + + g_driver = device->DeviceExtension; + + RtlZeroMemory(g_driver, sizeof(WIPF_DRIVER)); + + KeInitializeSpinLock(&g_driver->lock); + + status = wipf_callout_install(device); + } + } + + if (!NT_SUCCESS(status)) { + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_ERROR_LEVEL, "wipf: Entry: Error: %d\n", status); + wipf_driver_unload(driver); + } + + DbgPrintEx(DPFLTR_IHVNETWORK_ID, DPFLTR_TRACE_LEVEL, "wipf: < DriverEntry()\n"); + return status; +} diff --git a/src/drv/wipfdrv.h b/src/drv/wipfdrv.h new file mode 100644 index 00000000..e18db036 --- /dev/null +++ b/src/drv/wipfdrv.h @@ -0,0 +1,38 @@ +#ifndef WIPFDRV_H +#define WIPFDRV_H + +#define INITGUID +#include + +#define NT_DEVICE_NAME L"\\Device\\wipf" +#define DOS_DEVICE_NAME L"\\DosDevices\\wipf" +#define WIPF_DEVICE_NAME _T("\\\\.\\wipf") + +#define WIPF_DEVICE_TYPE 0xD000 +#define WIPF_IOCTL_BASE 0xD00 + +#define WIPF_CTL_CODE(i,a) CTL_CODE(WIPF_DEVICE_TYPE, WIPF_IOCTL_BASE + (i), METHOD_BUFFERED, (a)) + +#define WIPF_IOCTL_SETCONF WIPF_CTL_CODE(0, FILE_WRITE_DATA) + +/* {749978E2-CB6A-42F9-9C30-1A3EA9810185} */ +DEFINE_GUID(WIPF_CONNECT_CALLOUT_V4, + 0x749978e2, 0xcb6a, 0x42f9, 0x9c, 0x30, 0x1a, 0x3e, 0xa9, 0x81, 0x1, 0x85); + +/* {CED9C0FC-DF22-4F39-9185-B435726CABB2} */ +DEFINE_GUID(WIPF_ACCEPT_CALLOUT_V4, + 0xced9c0fc, 0xdf22, 0x4f39, 0x91, 0x85, 0xb4, 0x35, 0x72, 0x6c, 0xab, 0xb2); + +/* {AFA06CD5-4942-4FDF-8A4A-2EDEB25BBECE} */ +DEFINE_GUID(WIPF_FILTER_SUBLAYER, + 0xafa06cd5, 0x4942, 0x4fdf, 0x8a, 0x4a, 0x2e, 0xde, 0xb2, 0x5b, 0xbe, 0xce); + +/* {91CF8B80-7BB2-42BA-8A26-8242E14532FC} */ +DEFINE_GUID(WIPF_CONNECT_FILTER_V4, + 0x91cf8b80, 0x7bb2, 0x42ba, 0x8a, 0x26, 0x82, 0x42, 0xe1, 0x45, 0x32, 0xfc); + +/* {544A3E25-7BEB-4970-88EF-B4BCA2CE2482} */ +DEFINE_GUID(WIPF_ACCEPT_FILTER_V4, + 0x544a3e25, 0x7beb, 0x4970, 0x88, 0xef, 0xb4, 0xbc, 0xa2, 0xce, 0x24, 0x82); + +#endif WIPFDRV_H diff --git a/src/drv/wipfdrv.vcxproj b/src/drv/wipfdrv.vcxproj new file mode 100644 index 00000000..17ba71e3 --- /dev/null +++ b/src/drv/wipfdrv.vcxproj @@ -0,0 +1,90 @@ + + + + + Win8.1 Debug + Win32 + + + Win8.1 Release + Win32 + + + Win8.1 Debug + x64 + + + Win8.1 Release + x64 + + + + 11.0 + Win8.1 Release + Win32 + + + + WindowsV6.3 + true + WindowsKernelModeDriver8.1 + Driver + WDM + wipfdrv32 + + + WindowsV6.3 + false + WindowsKernelModeDriver8.1 + Driver + WDM + wipfdrv32 + + + WindowsV6.3 + true + WindowsKernelModeDriver8.1 + Driver + WDM + wipfdrv64 + + + WindowsV6.3 + false + WindowsKernelModeDriver8.1 + Driver + WDM + wipfdrv64 + + + + + + + DbgengKernelDebugger + + + DbgengKernelDebugger + + + ..\..\bin\ + + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\fwpkclnt.lib;$(SDK_LIB_PATH)\uuid.lib + + + true + Level3 + + + + + + + + + + + +