www.pudn.com > tdi_fw.rar > tdi_fw.c, change:2009-04-28,size:26499b
/* Copyright (c) 2002-2005 Vladislav Goncharov. * * Redistribution and use in source forms, with and without modification, * are permitted provided that this entire comment appears intact. * * Redistribution in binary form may occur without any restrictions. * * This software is provided ``AS IS'' without any warranties of any kind. */ // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil -*- (for GNU Emacs) // // $Id: tdi_fw.c,v 1.1 2009/04/28 12:53:28 tanwen Exp $ /* * TDI-based open source personal firewall (TdiFw) */ #include <ntddk.h> #include <tdikrnl.h> #include "sock.h" #include "conn_state.h" #include "dispatch.h" #include "filter.h" #include "memtrack.h" #include "obj_tbl.h" #include "tdi_fw.h" #define IOCTL_TRANSFER_TYPE(ioctl) ((ioctl) & 3) /* context for tdi_skip_complete */ typedef struct { PIO_COMPLETION_ROUTINE old_cr; /* old (original) completion routine */ PVOID old_context; /* old (original) parameter for old_cr */ PIO_COMPLETION_ROUTINE new_cr; /* new (replaced) completion routine */ PVOID new_context; /* new (replaced) parameter for new_cr */ PFILE_OBJECT fileobj; /* FileObject from IO_STACK_LOCATION */ PDEVICE_OBJECT new_devobj; /* filter device object */ UCHAR old_control; /* old (original) irps->Control */ } TDI_SKIP_CTX; /* prototypes */ static NTSTATUS DeviceDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP irp); static VOID OnUnload(IN PDRIVER_OBJECT DriverObject); #ifndef USE_TDI_HOOKING static NTSTATUS c_n_a_device(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT *fltobj, PDEVICE_OBJECT *oldobj, wchar_t *devname); static void d_n_d_device(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT oldobj, PDEVICE_OBJECT fltobj); #else static NTSTATUS hook_tcpip(DRIVER_OBJECT *old_DriverObject, BOOLEAN b_hook); static NTSTATUS get_device_object(wchar_t *name, PDEVICE_OBJECT *devobj); #endif static NTSTATUS tdi_skip_complete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context); /* device objects for: */ PDEVICE_OBJECT g_tcpfltobj = NULL, // \Device\Tcp g_udpfltobj = NULL, // \Device\Udp g_ipfltobj = NULL, // \Device\RawIp g_devcontrol = NULL, // control device (exclusive access only!) g_devnfo = NULL; // information device BOOLEAN g_got_log = FALSE; // got log app #ifndef USE_TDI_HOOKING // original device objects PDEVICE_OBJECT g_tcpoldobj, g_udpoldobj, g_ipoldobj; #else // original driver object DRIVER_OBJECT g_old_DriverObject; BOOLEAN g_hooked = FALSE; #endif /* for IOCTL_TDI_QUERY_DIRECT_SEND_HANDLER */ typedef NTSTATUS TCPSendData_t(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp); static TCPSendData_t *g_TCPSendData = NULL; static TCPSendData_t new_TCPSendData; /* global traffic stats */ unsigned __int64 g_traffic[TRAFFIC_MAX]; KSPIN_LOCK g_traffic_guard; /* add by tan wen */ #define TDI_USER_DEV_MAX 5 PDEVICE_OBJECT g_user_devices[TDI_USER_DEV_MAX] = { NULL }; BOOLEAN tdifw_register_user_device(PDEVICE_OBJECT dev) { int i; for(i=0;i<TDI_USER_DEV_MAX;++i) { if(g_user_devices[i] == NULL) { g_user_devices[i] = dev; return TRUE; } } return FALSE; } extern NTSTATUS tdifw_driver_entry( IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath); /* initialization */ NTSTATUS DriverEntry(IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath) { NTSTATUS status = STATUS_SUCCESS; int i; UNICODE_STRING name, linkname; if(status != STATUS_SUCCESS) goto done; memtrack_init(); KeInitializeSpinLock(&g_traffic_guard); #ifdef USE_TDI_HOOKING KdPrint(("[tdi_fw] WARNING! Using unstable working mode: TDI hooking!\n")); #endif status = ot_init(); if (status != STATUS_SUCCESS) { KdPrint(("[tdi_fw] DriverEntry: ot_init: 0x%x\n", status)); goto done; } status = filter_init(); if (status != STATUS_SUCCESS) { KdPrint(("[tdi_fw] DriverEntry: filter_init: 0x%x\n", status)); goto done; } status = conn_state_init(); if (status != STATUS_SUCCESS) { KdPrint(("[tdi_fw] DriverEntry: conn_state_init: 0x%x\n", status)); goto done; } for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) theDriverObject->MajorFunction[i] = DeviceDispatch; #if DBG // register UnLoad procedure theDriverObject->DriverUnload = OnUnload; #endif /* create control device and symbolic link */ RtlInitUnicodeString(&name, L"\\Device\\tdifw"); status = IoCreateDevice(theDriverObject, 0, &name, 0, 0, TRUE, // exclusive! &g_devcontrol); if (status != STATUS_SUCCESS) { KdPrint(("[tdi_fw] DriverEntry: IoCreateDevice(control): 0x%x!\n", status)); goto done; } RtlInitUnicodeString(&linkname, L"\\??\\tdifw"); status = IoCreateSymbolicLink(&linkname, &name); if (status != STATUS_SUCCESS) { KdPrint(("[tdi_fw] DriverEntry: IoCreateSymbolicLink: 0x%x!\n", status)); goto done; } RtlInitUnicodeString(&name, L"\\Device\\tdifw_nfo"); status = IoCreateDevice(theDriverObject, 0, &name, 0, 0, FALSE, // not exclusive! &g_devnfo); if (status != STATUS_SUCCESS) { KdPrint(("[tdi_fw] DriverEntry: IoCreateDevice(nfo): 0x%x!\n", status)); goto done; } RtlInitUnicodeString(&linkname, L"\\??\\tdifw_nfo"); status = IoCreateSymbolicLink(&linkname, &name); if (status != STATUS_SUCCESS) { KdPrint(("[tdi_fw] DriverEntry: IoCreateSymbolicLink: 0x%x!\n", status)); goto done; } #ifndef USE_TDI_HOOKING // Add by tanwen. // Call this function before hooking! So that when tdifw_filter() happened, // Our driver has been initialized. status = tdifw_driver_entry(theDriverObject,theRegistryPath); status = c_n_a_device(theDriverObject, &g_tcpfltobj, &g_tcpoldobj, L"\\Device\\Tcp"); if (status != STATUS_SUCCESS) { KdPrint(("[tdi_fw] DriverEntry: c_n_a_device: 0x%x\n", status)); goto done; } status = c_n_a_device(theDriverObject, &g_udpfltobj, &g_udpoldobj, L"\\Device\\Udp"); if (status != STATUS_SUCCESS) { KdPrint(("[tdi_fw] DriverEntry: c_n_a_device: 0x%x\n", status)); goto done; } status = c_n_a_device(theDriverObject, &g_ipfltobj, &g_ipoldobj, L"\\Device\\RawIp"); if (status != STATUS_SUCCESS) { KdPrint(("[tdi_fw] DriverEntry: c_n_a_device: 0x%x\n", status)); goto done; } #else /* USE_TDI_HOOKING */ // Add by tanwen. // Call this function before hooking! So that when tdifw_filter() happened, // Our driver has been initialized. status = tdifw_driver_entry(theDriverObject,theRegistryPath); /* get device objects for tcp/udp/ip */ status = get_device_object(L"\\Device\\Tcp", &g_tcpfltobj); if (status != STATUS_SUCCESS) { KdPrint(("[tdi_fw] DriverEntry: get_device_object(tcp): 0x%x\n", status)); goto done; } status = get_device_object(L"\\Device\\Udp", &g_udpfltobj); if (status != STATUS_SUCCESS) { KdPrint(("[tdi_fw] DriverEntry: get_device_object(udp): 0x%x\n", status)); goto done; } status = get_device_object(L"\\Device\\RawIp", &g_ipfltobj); if (status != STATUS_SUCCESS) { KdPrint(("[tdi_fw] DriverEntry: get_device_object(ip): 0x%x\n", status)); goto done; } /* hook tcpip */ status = hook_tcpip(&g_old_DriverObject, TRUE); if (status != STATUS_SUCCESS) { KdPrint(("[tdi_fw] DriverEntry: hook_driver: 0x%x\n", status)); goto done; } g_hooked = TRUE; #endif /* USE_TDI_HOOKING */ status = STATUS_SUCCESS; done: if (status != STATUS_SUCCESS) { // cleanup OnUnload(theDriverObject); } return status; } extern VOID tdifw_driver_unload( IN PDRIVER_OBJECT DriverObject); /* deinitialization */ VOID OnUnload(IN PDRIVER_OBJECT DriverObject) { // Add by tan wen. tdifw_driver_unload(DriverObject); #ifndef USE_TDI_HOOKING d_n_d_device(DriverObject, g_tcpoldobj, g_tcpfltobj); d_n_d_device(DriverObject, g_udpoldobj, g_udpfltobj); d_n_d_device(DriverObject, g_ipoldobj, g_ipfltobj); #else if (g_hooked) hook_tcpip(&g_old_DriverObject, FALSE); #endif // delete control device and symbolic link if (g_devcontrol != NULL) { UNICODE_STRING linkname; RtlInitUnicodeString(&linkname, L"\\??\\tdifw"); IoDeleteSymbolicLink(&linkname); IoDeleteDevice(g_devcontrol); } // delete info device and symbolic link if (g_devnfo != NULL) { UNICODE_STRING linkname; RtlInitUnicodeString(&linkname, L"\\??\\tdifw_nfo"); IoDeleteSymbolicLink(&linkname); IoDeleteDevice(g_devnfo); } filter_free(); ot_free(); conn_state_free(); // call after ot_free() memtrack_free(); } #ifndef USE_TDI_HOOKING /* create & attach device */ NTSTATUS c_n_a_device(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT *fltobj, PDEVICE_OBJECT *oldobj, wchar_t *devname) { NTSTATUS status; UNICODE_STRING str; /* create filter device */ status = IoCreateDevice(DriverObject, 0, NULL, FILE_DEVICE_UNKNOWN, 0, TRUE, fltobj); if (status != STATUS_SUCCESS) { KdPrint(("[tdi_fw] c_n_a_device: IoCreateDevice(%S): 0x%x\n", devname, status)); return status; } (*fltobj)->Flags |= DO_DIRECT_IO; RtlInitUnicodeString(&str, devname); status = IoAttachDevice(*fltobj, &str, oldobj); if (status != STATUS_SUCCESS) { KdPrint(("[tdi_fw] DriverEntry: IoAttachDevice(%S): 0x%x\n", devname, status)); return status; } KdPrint(("[tdi_fw] DriverEntry: %S fileobj: 0x%x\n", devname, *fltobj)); return STATUS_SUCCESS; } /* detach & delete device */ void d_n_d_device(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT oldobj, PDEVICE_OBJECT fltobj) { /* * Detaching of a filter driver at runtime is a high-risk deal */ #if 1 // for extremal guys only! if (oldobj != NULL && fltobj != NULL) { int i; for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) DriverObject->MajorFunction[i] = g_tcpoldobj->DriverObject->MajorFunction[i]; } #endif if (oldobj != NULL) IoDetachDevice(oldobj); if (fltobj != NULL) IoDeleteDevice(fltobj); } #else /* USE_TDI_HOOKING */ /* hook/unhook driver */ NTSTATUS hook_tcpip(DRIVER_OBJECT *old_DriverObject, BOOLEAN b_hook) { UNICODE_STRING drv_name; NTSTATUS status; PDRIVER_OBJECT new_DriverObject; int i; RtlInitUnicodeString(&drv_name, L"\\Driver\\Tcpip"); status = ObReferenceObjectByName(&drv_name, OBJ_CASE_INSENSITIVE, NULL, 0, IoDriverObjectType, KernelMode, NULL, &new_DriverObject); if (status != STATUS_SUCCESS) { KdPrint(("[tdi_fw] hook_driver: ObReferenceObjectByName\n")); return status; } for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) { if (b_hook) { old_DriverObject->MajorFunction[i] = new_DriverObject->MajorFunction[i]; new_DriverObject->MajorFunction[i] = DeviceDispatch; } else new_DriverObject->MajorFunction[i] = old_DriverObject->MajorFunction[i]; } return STATUS_SUCCESS; } /* get device object by its name */ NTSTATUS get_device_object(wchar_t *name, PDEVICE_OBJECT *devobj) { UNICODE_STRING str; NTSTATUS status; PFILE_OBJECT fileobj; RtlInitUnicodeString(&str, name); status = IoGetDeviceObjectPointer(&str, FILE_ALL_ACCESS, &fileobj, devobj); if (status == STATUS_SUCCESS) ObDereferenceObject(fileobj); return status; } #endif /* USE_TDI_HOOKING */ extern NTSTATUS tdifw_user_device_dispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP irp); /* dispatch */ NTSTATUS DeviceDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP irp) { PIO_STACK_LOCATION irps; NTSTATUS status; int i; // add by tanwen // sanity check if (irp == NULL) { KdPrint(("[tdi_fw] DeviceDispatch: !irp\n")); return STATUS_SUCCESS; } // add by tanwen for(i=0;i<TDI_USER_DEV_MAX;++i) { if(g_user_devices[i] == DeviceObject) return tdifw_user_device_dispatch(DeviceObject,irp); } irps = IoGetCurrentIrpStackLocation(irp); if (DeviceObject == g_tcpfltobj || DeviceObject == g_udpfltobj || DeviceObject == g_ipfltobj) { /* * This IRP is for filtered device */ int result; struct completion completion; memset(&completion, 0, sizeof(completion)); // Analyze MajorFunction switch (irps->MajorFunction) { case IRP_MJ_CREATE: /* create fileobject */ result = tdi_create(irp, irps, &completion); status = tdi_dispatch_complete(DeviceObject, irp, result, completion.routine, completion.context); break; case IRP_MJ_DEVICE_CONTROL: KdPrint(("[tdi_fw] DeviceDispatch: IRP_MJ_DEVICE_CONTROL, control 0x%x for 0x%08X\n", irps->Parameters.DeviceIoControl.IoControlCode, irps->FileObject)); if (KeGetCurrentIrql() == PASSIVE_LEVEL) { /* * try to convert it to IRP_MJ_INTERNAL_DEVICE_CONTROL * (works on PASSIVE_LEVEL only!) */ status = TdiMapUserRequest(DeviceObject, irp, irps); } else status = STATUS_NOT_IMPLEMENTED; // set fake status if (status != STATUS_SUCCESS) { void *buf = (irps->Parameters.DeviceIoControl.IoControlCode == IOCTL_TDI_QUERY_DIRECT_SEND_HANDLER) ? irps->Parameters.DeviceIoControl.Type3InputBuffer : NULL; // send IRP to original driver status = tdi_dispatch_complete(DeviceObject, irp, FILTER_ALLOW, NULL, NULL); if (buf != NULL && status == STATUS_SUCCESS) { g_TCPSendData = *(TCPSendData_t **)buf; KdPrint(("[tdi_fw] DeviceDispatch: IOCTL_TDI_QUERY_DIRECT_SEND_HANDLER: TCPSendData = 0x%x\n", g_TCPSendData)); *(TCPSendData_t **)buf = new_TCPSendData; } break; } // don't break! go to internal device control! case IRP_MJ_INTERNAL_DEVICE_CONTROL: { /* * Analyze ioctl for TDI driver */ int i; for (i = 0; g_tdi_ioctls[i].MinorFunction != 0; i++) if (g_tdi_ioctls[i].MinorFunction == irps->MinorFunction) { #if DBG // print description KdPrint(("[tdi_fw] DeviceDispatch: %s (0x%x) for 0x%x\n", g_tdi_ioctls[i].desc, irps->MinorFunction, irps->FileObject)); #endif if (g_tdi_ioctls[i].fn == NULL) { // send IRP to original driver status = tdi_dispatch_complete(DeviceObject, irp, FILTER_ALLOW, NULL, NULL); break; } // call dispatch function result = g_tdi_ioctls[i].fn(irp, irps, &completion); // complete request status = tdi_dispatch_complete(DeviceObject, irp, result, completion.routine, completion.context); break; } // if dispatch function hasn't been found if (g_tdi_ioctls[i].MinorFunction == 0) { // send IRP to original driver status = tdi_dispatch_complete(DeviceObject, irp, FILTER_ALLOW, NULL, NULL); } break; } case IRP_MJ_CLEANUP: /* cleanup fileobject */ result = tdi_cleanup(irp, irps, &completion); status = tdi_dispatch_complete(DeviceObject, irp, result, completion.routine, completion.context); break; case IRP_MJ_CLOSE: KdPrint(("[tdi_fw] DeviceDispatch: IRP_MJ_CLOSE fileobj 0x%x\n", irps->FileObject)); // passthrough IRP status = tdi_dispatch_complete(DeviceObject, irp, FILTER_ALLOW, completion.routine, completion.context); break; default: KdPrint(("[tdi_fw] DeviceDispatch: major 0x%x, minor 0x%x for 0x%x\n", irps->MajorFunction, irps->MinorFunction, irps->FileObject)); // passthrough IRP status = tdi_dispatch_complete(DeviceObject, irp, FILTER_ALLOW, completion.routine, completion.context); } } else if (DeviceObject == g_devcontrol) { /* * this IRP is for control device */ // set default status status = STATUS_SUCCESS; if (irps->MajorFunction == IRP_MJ_CREATE) { // initialize for user-mode part (exclusive access - 1 user-mode logging part) filter_init_2(); g_got_log = TRUE; } else if (irps->MajorFunction == IRP_MJ_CLOSE) { // cleanup for user-mode logging part filter_free_2(); g_got_log = FALSE; } if (irps->MajorFunction == IRP_MJ_DEVICE_CONTROL) { /* * control request */ ULONG ioctl = irps->Parameters.DeviceIoControl.IoControlCode, len = irps->Parameters.DeviceIoControl.InputBufferLength, size = irps->Parameters.DeviceIoControl.OutputBufferLength; char *out_buf; if (IOCTL_TRANSFER_TYPE(ioctl) == METHOD_NEITHER) { // this type of transfer unsupported out_buf = NULL; } else out_buf = (char *)irp->AssociatedIrp.SystemBuffer; // process control request status = process_request(ioctl, out_buf, &len, size); irp->IoStatus.Information = len; } irp->IoStatus.Status = status; IoCompleteRequest(irp, IO_NO_INCREMENT); } else if (DeviceObject == g_devnfo) { /* * this IRP is for information device */ // set default status status = STATUS_SUCCESS; if (irps->MajorFunction == IRP_MJ_DEVICE_CONTROL) { /* * control request */ ULONG ioctl = irps->Parameters.DeviceIoControl.IoControlCode, len = irps->Parameters.DeviceIoControl.InputBufferLength, size = irps->Parameters.DeviceIoControl.OutputBufferLength; char *out_buf; if (IOCTL_TRANSFER_TYPE(ioctl) == METHOD_NEITHER) { // this type of transfer unsupported out_buf = NULL; } else out_buf = (char *)irp->AssociatedIrp.SystemBuffer; // process control request status = process_nfo_request(ioctl, out_buf, &len, size); irp->IoStatus.Information = len; } irp->IoStatus.Status = status; IoCompleteRequest(irp, IO_NO_INCREMENT); } else { KdPrint(("[tdi_fw] DeviceDispatch: ioctl for unknown DeviceObject 0x%x\n", DeviceObject)); #ifndef USE_TDI_HOOKING // ??? just complete IRP status = irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(irp, IO_NO_INCREMENT); #else // call original handler status = g_old_DriverObject.MajorFunction[irps->MajorFunction]( DeviceObject, irp); #endif } return status; } /* * Dispatch routines call this function to complete their processing. * They _MUST_ call this function anyway. */ NTSTATUS tdi_dispatch_complete(PDEVICE_OBJECT devobj, PIRP irp, int filter, PIO_COMPLETION_ROUTINE cr, PVOID context) { PIO_STACK_LOCATION irps = IoGetCurrentIrpStackLocation(irp); NTSTATUS status; if (filter == FILTER_DENY) { /* * DENY: complete request with status "Access violation" */ KdPrint(("[tdi_fw] tdi_dispatch_complete: [DROP!]" " major 0x%x, minor 0x%x for devobj 0x%x; fileobj 0x%x\n", irps->MajorFunction, irps->MinorFunction, devobj, irps->FileObject)); if (irp->IoStatus.Status == STATUS_SUCCESS) { // change status status = irp->IoStatus.Status = STATUS_ACCESS_DENIED; } else { // set IRP status unchanged status = irp->IoStatus.Status; } IoCompleteRequest (irp, IO_NO_INCREMENT); } else if (filter == FILTER_ALLOW) { /* * ALLOW: pass IRP to the next driver */ #ifndef USE_TDI_HOOKING PDEVICE_OBJECT old_devobj = get_original_devobj(devobj, NULL); if (old_devobj == NULL) { KdPrint(("[tdi_fw] tdi_send_irp_to_old_driver: Unknown DeviceObject 0x%x!\n", devobj)); status = irp->IoStatus.Status = STATUS_UNSUCCESSFUL; IoCompleteRequest (irp, IO_NO_INCREMENT); return status; } #endif KdPrint(("[tdi_fw] tdi_dispatch_complete: [ALLOW.]" " major 0x%x, minor 0x%x for devobj 0x%x; fileobj 0x%x\n", irps->MajorFunction, irps->MinorFunction, devobj, irps->FileObject)); #ifndef USE_TDI_HOOKING if (cr == NULL || irp->CurrentLocation <= 1) { /* * we use _THIS_ way of sending IRP to old driver * a) to avoid NO_MORE_STACK_LOCATIONS * b) and if we haven't our completions - no need to copy stack locations! */ // stay on this location after IoCallDriver IoSkipCurrentIrpStackLocation(irp); #endif if (cr != NULL) { /* * set completion routine (this way is slow) */ // save old completion routine and context TDI_SKIP_CTX *ctx = (TDI_SKIP_CTX *)malloc_np(sizeof(*ctx)); if (ctx == NULL) { KdPrint(("[tdi_fw] tdi_send_irp_to_old_driver: malloc_np\n")); status = irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; IoCompleteRequest(irp, IO_NO_INCREMENT); return status; } ctx->old_cr = irps->CompletionRoutine; ctx->old_context = irps->Context; ctx->new_cr = cr; ctx->new_context = context; ctx->fileobj = irps->FileObject; ctx->new_devobj = devobj; ctx->old_control = irps->Control; IoSetCompletionRoutine(irp, tdi_skip_complete, ctx, TRUE, TRUE, TRUE); } #ifndef USE_TDI_HOOKING } else { PIO_STACK_LOCATION irps = IoGetCurrentIrpStackLocation(irp), next_irps = IoGetNextIrpStackLocation(irp); memcpy(next_irps, irps, sizeof(*irps)); if (cr != NULL) { /* * this way for completion is more quicker than used above */ IoSetCompletionRoutine(irp, cr, context, TRUE, TRUE, TRUE); } else IoSetCompletionRoutine(irp, tdi_generic_complete, NULL, TRUE, TRUE, TRUE); } #endif /* call original driver */ #ifndef USE_TDI_HOOKING status = IoCallDriver(old_devobj, irp); #else status = g_old_DriverObject.MajorFunction[irps->MajorFunction](devobj, irp); #endif } else { /* FILTER_UNKNOWN */ /* * UNKNOWN: just complete the request */ status = irp->IoStatus.Status = STATUS_SUCCESS; // ??? IoCompleteRequest (irp, IO_NO_INCREMENT); } return status; } /* * completion routine for case if we use IoSkipCurrentIrpStackLocation way * or we USE_TDI_HOOKING */ NTSTATUS tdi_skip_complete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) { TDI_SKIP_CTX *ctx = (TDI_SKIP_CTX *)Context; NTSTATUS status; PIO_STACK_LOCATION irps; if (Irp->IoStatus.Status != STATUS_SUCCESS) KdPrint(("[tdi_fw] tdi_skip_complete: status 0x%x\n", Irp->IoStatus.Status)); // restore IRP for using in our completion Irp->CurrentLocation--; Irp->Tail.Overlay.CurrentStackLocation--; irps = IoGetCurrentIrpStackLocation(Irp); KdPrint(("[tdi_fw] tdi_skip_complete: DeviceObject = 0x%x; FileObject = 0x%x\n", DeviceObject, irps->FileObject)); DeviceObject = irps->DeviceObject; if (ctx->new_cr != NULL) { // restore fileobject (it's NULL) irps->FileObject = ctx->fileobj; // set new device object in irps irps->DeviceObject = ctx->new_devobj; // call new completion status = ctx->new_cr(ctx->new_devobj, Irp, ctx->new_context); } else status = STATUS_SUCCESS; /* patch IRP back */ // restore routine and context (and even control!) irps->CompletionRoutine = ctx->old_cr; irps->Context = ctx->old_context; irps->Control = ctx->old_control; // restore device object irps->DeviceObject = DeviceObject; Irp->CurrentLocation++; Irp->Tail.Overlay.CurrentStackLocation++; if (ctx->old_cr != NULL) { if (status != STATUS_MORE_PROCESSING_REQUIRED) { // call old completion (see the old control) BOOLEAN b_call = FALSE; if (Irp->Cancel) { // cancel if (ctx->old_control & SL_INVOKE_ON_CANCEL) b_call = TRUE; } else { if (Irp->IoStatus.Status >= STATUS_SUCCESS) { // success if (ctx->old_control & SL_INVOKE_ON_SUCCESS) b_call = TRUE; } else { // error if (ctx->old_control & SL_INVOKE_ON_ERROR) b_call = TRUE; } } if (b_call) status = ctx->old_cr(DeviceObject, Irp, ctx->old_context); } else { /* * patch IRP to set IoManager to call completion next time */ // restore Control irps->Control = ctx->old_control; } } free(ctx); return status; } /* get original device object by filtered */ PDEVICE_OBJECT get_original_devobj(PDEVICE_OBJECT flt_devobj, int *proto) { #ifndef USE_TDI_HOOKING PDEVICE_OBJECT result; int ipproto; if (flt_devobj == g_tcpfltobj) { result = g_tcpoldobj; ipproto = IPPROTO_TCP; } else if (flt_devobj == g_udpfltobj) { result = g_udpoldobj; ipproto = IPPROTO_UDP; } else if (flt_devobj == g_ipfltobj) { result = g_ipoldobj; ipproto = IPPROTO_IP; } else { KdPrint(("[tdi_fw] get_original_devobj: Unknown DeviceObject 0x%x!\n", flt_devobj)); ipproto = IPPROTO_IP; // what else? result = NULL; } if (result != NULL && proto != NULL) *proto = ipproto; return result; #else /* USE_TDI_HOOKING */ // just stub for original devobj; return proto by devobj int ipproto; if (flt_devobj == g_tcpfltobj) ipproto = IPPROTO_TCP; else if (flt_devobj == g_udpfltobj) ipproto = IPPROTO_UDP; else if (flt_devobj == g_ipfltobj) ipproto = IPPROTO_IP; else { KdPrint(("[tdi_fw] get_original_devobj: Unknown DeviceObject 0x%x!\n", flt_devobj)); ipproto = IPPROTO_IP; // what else? flt_devobj = NULL; } if (proto != NULL) *proto = ipproto; return flt_devobj; #endif } /* * Completion routines must call this function at the end of their execution */ NTSTATUS tdi_generic_complete(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context) { KdPrint(("[tdi_fw] tdi_generic_complete: STATUS = 0x%x\n", Irp->IoStatus.Status)); if (Irp->PendingReturned) { KdPrint(("[tdi_fw] tdi_generic_complete: PENDING\n")); IoMarkIrpPending(Irp); } return STATUS_SUCCESS; } /* * for IOCTL_TDI_QUERY_DIRECT_SEND_HANDLER */ NTSTATUS new_TCPSendData(IN PIRP Irp, IN PIO_STACK_LOCATION IrpSp) { struct completion completion; int result; KdPrint(("[tdi_fw] new_TCPSendData\n")); #if 1 memset(&completion, 0, sizeof(completion)); result = tdi_send(Irp, IrpSp, &completion); // complete request return tdi_dispatch_complete(IrpSp->DeviceObject, Irp, result, completion.routine, completion.context); #else return g_TCPSendData(Irp, IrpSp); #endif } /* * deny stub for dispatch table */ int tdi_deny_stub(PIRP irp, PIO_STACK_LOCATION irps, struct completion *completion) { KdPrint(("[tdi_fw] tdi_deny_stub!\n")); return FILTER_DENY; }