開發 Linux 平台防火牆時,資源與原始碼唾手可得;但若要在 Windows 2000/XP 上建構防火牆,相關技術文件與程式碼卻極難尋覓。本文將詳細介紹如何利用 Windows 2000 DDK 中的 Filter-Hook Driver,以相對簡單的方式實現核心層級的封包過濾,並提供完整原始碼供參考。
Filter-Hook Driver 並非全新的網路驅動模型,實際上它是擴展了 IP 過濾驅動(IP Filter Driver)的功能。本質上屬於核心模式驅動,其運作機制為:驅動提供回呼函數,透過 IP Filter Driver 註冊該回呼。當封包收發時,IP Filter Driver 會呼叫此回呼函數,讓開發者得以檢查、修改或丟棄封包。
IoGetDeviceObjectPointer 獲取 \\Device\\IpFilterDriver 的裝置物件與檔案物件指標。PF_SET_EXTENSION_HOOK_INFO 結構,包含過濾函數指標,發送 IOCTL_PF_SET_EXTENSION_POINTER IRP 給 IP Filter Driver。PF_FORWARD(放行)、PF_DROP(丟棄)或 PF_PASS(交由 IP Filter Driver 續處理)。NULL 函數指標發送相同 IRP 即可移除掛鉤。NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) {
// 建立裝置與符號連結
RtlInitUnicodeString(&deviceNameUnicodeString, NT_DEVICE_NAME);
ntStatus = IoCreateDevice(DriverObject, 0, &deviceNameUnicodeString,
FILE_DEVICE_DRVFLTIP, 0, FALSE, &deviceObject);
if (NT_SUCCESS(ntStatus)) {
RtlInitUnicodeString(&deviceLinkUnicodeString, DOS_DEVICE_NAME);
IoCreateSymbolicLink(&deviceLinkUnicodeString, &deviceNameUnicodeString);
// 設定 IRP 分派函數
DriverObject->MajorFunction[IRP_MJ_CREATE] =
DriverObject->MajorFunction[IRP_MJ_CLOSE] =
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DrvDispatch;
DriverObject->DriverUnload = DrvUnload;
}
return ntStatus;
}
NTSTATUS SetFilterFunction(PacketFilterExtensionPtr filterFunction) {
UNICODE_STRING filterName;
PDEVICE_OBJECT ipDeviceObject = NULL;
PFILE_OBJECT ipFileObject = NULL;
PF_SET_EXTENSION_HOOK_INFO filterData;
KEVENT event;
IO_STATUS_BLOCK ioStatus;
PIRP irp;
RtlInitUnicodeString(&filterName, DD_IPFLTRDRVR_DEVICE_NAME);
status = IoGetDeviceObjectPointer(&filterName, STANDARD_RIGHTS_ALL,
&ipFileObject, &ipDeviceObject);
if (NT_SUCCESS(status)) {
filterData.ExtensionPointer = filterFunction;
KeInitializeEvent(&event, NotificationEvent, FALSE);
irp = IoBuildDeviceIoControlRequest(IOCTL_PF_SET_EXTENSION_POINTER,
ipDeviceObject, &filterData, sizeof(filterData),
NULL, 0, FALSE, &event, &ioStatus);
if (irp) {
status = IoCallDriver(ipDeviceObject, irp);
if (status == STATUS_PENDING)
KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
status = ioStatus.Status;
}
ObDereferenceObject(ipFileObject);
}
return status;
}
typedef PF_FORWARD_ACTION (*PacketFilterExtensionPtr)(
IN unsigned char *PacketHeader, // IP 標頭
IN unsigned char *Packet, // 封包資料(不含 IP 標頭)
IN unsigned int PacketLength, // 封包長度
IN unsigned int RecvInterfaceIndex,
IN unsigned int SendInterfaceIndex,
IN IPAddr RecvLinkNextHop,
IN IPAddr SendLinkNextHop
);
雖非商業級防火牆的最佳選擇,Filter-Hook Driver 仍是學習 Windows 核心網路過濾機制的絕佳切入點。完整原始碼包含用戶端 MFC 管理程式與核心驅動,可作為進階開發基礎。