/*
FwHookDrv.c
Author: Jes�s O.
Last Updated: 12/09/03
*/
#include <string.h>
#include <stdio.h>
#include <ntddk.h>
#include <ndis.h>
#include <ipFirewall.h>
#include "FwHookDrv.h"
#include "NetHeaders.h"
#if DBG
#define dprintf DbgPrint
#else
#define dprintf(x)
#endif
BOOLEAN loaded = FALSE;
#define NT_DEVICE_NAME L"\\Device\\FwHookDrv"
#define DOS_DEVICE_NAME L"\\DosDevices\\FwHookDrv"
// Structure to define the linked list of rules
struct filterList
{
IPFilter ipf;
struct filterList *next;
};
// Function declarations
NTSTATUS DrvDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
VOID DrvUnload(IN PDRIVER_OBJECT DriverObject);
NTSTATUS SetFilterFunction(IPPacketFirewallPtr filterFunction, BOOLEAN load);
NTSTATUS AddFilterToList(IPFilter *pf);
void ClearFilterList(void);
FORWARD_ACTION cbFilterFunction(VOID **pData,
UINT RecvInterfaceIndex,
UINT *pSendInterfaceIndex,
UCHAR *pDestinationType,
VOID *pContext,
UINT ContextLength,
struct IPRcvBuf **pRcvBuf);
FORWARD_ACTION FilterPacket(unsigned char *PacketHeader,
unsigned char *Packet,
unsigned int PacketLength,
DIRECTION_E direction,
unsigned int RecvInterfaceIndex,
unsigned int SendInterfaceIndex);
struct filterList *first = NULL;
struct filterList *last = NULL;
/*++
Description:
Entry point of the driver.
Arguments:
DriverObject - pointer to a driver object
RegistryPath - pointer to a unicode string that contain registry path.
Return:
STATUS_SUCCESS if success
STATUS_UNSUCCESSFUL If the function fails
--*/
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
PDEVICE_OBJECT deviceObject = NULL;
NTSTATUS ntStatus;
UNICODE_STRING deviceNameUnicodeString;
UNICODE_STRING deviceLinkUnicodeString;
dprintf("FwHookDrv.sys: Loading Driver....\n");
// Create the device
RtlInitUnicodeString(&deviceNameUnicodeString, NT_DEVICE_NAME);
ntStatus = IoCreateDevice(DriverObject,
0,
&deviceNameUnicodeString,
FILE_DEVICE_FWHOOKDRV,
0,
FALSE,
&deviceObject);
if ( NT_SUCCESS(ntStatus) )
{
// Create symbolic link
RtlInitUnicodeString(&deviceLinkUnicodeString, DOS_DEVICE_NAME);
ntStatus = IoCreateSymbolicLink(&deviceLinkUnicodeString, &deviceNameUnicodeString);
if ( !NT_SUCCESS(ntStatus) )
{
dprintf("FwHookDrv.sys: Error al crear el enlace simb�lico.\n");
}
// Define driver's control functions
DriverObject->MajorFunction[IRP_MJ_CREATE] =
DriverObject->MajorFunction[IRP_MJ_CLOSE] =
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DrvDispatch;
DriverObject->DriverUnload = DrvUnload;
}
if ( !NT_SUCCESS(ntStatus) )
{
dprintf("Error Intitializing. Unloading driver...");
DrvUnload(DriverObject);
}
return ntStatus;
}
/*++
Description:
Process all IRPs the driver receive
Arguments:
DeviceObject - Pointer to device object
Irp - IRP
--*/
NTSTATUS DrvDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
PIO_STACK_LOCATION irpStack;
PVOID ioBuffer;
ULONG inputBufferLength;
ULONG outputBufferLength;
ULONG ioControlCode;
NTSTATUS ntStatus;
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
// Get pointer to current stack location
irpStack = IoGetCurrentIrpStackLocation(Irp);
// Get pointer to buffer information
ioBuffer = Irp->AssociatedIrp.SystemBuffer;
inputBufferLength = irpStack->Parameters.DeviceIoControl.InputBufferLength;
outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
switch (irpStack->MajorFunction)
{
case IRP_MJ_CREATE:
dprintf("FwHookDrv.sys: IRP_MJ_CREATE\n");
break;
case IRP_MJ_CLOSE:
dprintf("FwHookDrv.sys: IRP_MJ_CLOSE\n");
break;
case IRP_MJ_DEVICE_CONTROL:
dprintf("DrvFltIp.SYS: IRP_MJ_DEVICE_CONTROL\n");
ioControlCode = irpStack->Parameters.DeviceIoControl.IoControlCode;
switch (ioControlCode)
{
// IOCTL to install filter function.
case START_IP_HOOK:
{
if(!loaded)
{
loaded = TRUE;
SetFilterFunction(cbFilterFunction, TRUE);
}
break;
}
// IOCTL to delete filter function.
case STOP_IP_HOOK:
{
if(loaded)
{
loaded = FALSE;
SetFilterFunction(cbFilterFunction, FALSE);
}
break;
}
// IOCTL to add filter rule.
case ADD_FILTER:
{
if(inputBufferLength == sizeof(IPFilter))
{
IPFilter *nf;
nf = (IPFilter *)ioBuffer;
AddFilterToList(nf);
}
break;
}
// IOCTL to delete filter rule.
case CLEAR_FILTER:
{
ClearFilterList();
break;
}
default:
Irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
dprintf("FwHookDrv.sys: Unknown IOCTL.\n");
break;
}
break;
}
// We can't return Irp-IoStatus directly because after IoCompleteRequest
// we aren't the owners of the IRP.
ntStatus = Irp->IoStatus.Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return ntStatus;
}
/*++
Description:
Unload the driver. Free all resources.
Arguments:
DriverObject - Pointer to driver object.
--*/
VOID DrvUnload(IN PDRIVER_OBJECT DriverObject)
{
UNICODE_STRING deviceLinkUnicodeString;
dprintf("FwHookDrv.sys: Unloading driver...\n");
if(loaded)
{
loaded = FALSE;
SetFilterFunction(cbFilterFunction, FALSE);
}
// Free filter rules
ClearFilterList();
// Remove symbolic link
RtlInitUnicodeString(&deviceLinkUnicodeString, DOS_DEVICE_NAME);
IoDeleteSymbolicLink(&deviceLinkUnicodeString);
// Remove the device
IoDeleteDevice(DriverObject->DeviceObject);
}
/*++
Description:
Install/Uninstall the filter function
Arguments:
filterFunction - Pointer to the filter function.
load - If TRUE, the function is added. Else, the function will be removed.
Return:
STATUS_SUCCESS If success,
--*/
NTSTATUS SetFilterFunction(IPPacketFirewallPtr filterFunction, BOOLEAN load)
{
NTSTATUS status = STATUS_SUCCESS, waitStatus=STATUS_SUCCESS;
UNICODE_STRING filterName;
PDEVICE_OBJECT ipDeviceObject=NULL;
PFILE_OBJECT ipFileObject=NULL;
IP_SET_FIREWALL_HOOK_INFO filterData;
KEVENT event;
IO_STATUS_BLOCK ioStatus;
PIRP irp;
// Get pointer to Ip device
RtlInitUnicodeString(&filterName, DD_IP_DEVICE_NAME);
status = IoGetDeviceObjectPointer(&filterName,STANDARD_RIGHTS_ALL, &ipFileObject, &ipDeviceObject);
if(NT_SUCCESS(status))
{
// Init firewall hook structure
filterData.FirewallPtr = filterFunction;
filterData.Priority = 1;
filterData.Add = load;
KeInitializeEvent(&event, NotificationEvent, FALSE);
// Build Irp to establish filter function
irp = IoBuildDeviceIoControlRequest(IOCTL_IP_SET_FIREWALL_HOOK,
ipDeviceObject,
(PVOID) &filterData,
sizeof(IP_SET_FIREWALL_HOOK_INFO),
NULL,
0,
FALSE,
&event,
&ioStatus);
if(irp != NULL)
{
// Send the Irp and wait for its completion
status = IoCallDriver(ipDeviceObject, irp);
if (status == STATUS_PENDING)
{
waitStatus = KeWaitForSingleObject(&event, Ex