Введение.
В данной статье даются основные сведения по способам фильтрации сетевого траффика в Windows 9x/2000/Net.2003 Server, даётся описание фильтрации IP-траффика в Windows 2000 на основе Windows 2000 Filter-Hook Driver способа.Также указываются особенности реализации других методов фильтрации.
Часть первая, теоретическая.
Способы фильтрации сетевого трафика .
Существует несколько способов фильтрации сетевого траффика .Для начала кратко рассмотрим основы сетевой подсистемы Windows:
1) NDIS. В 1989 году Microsoft и 3Com совместно разработали Network Driver Interface Specification (NDIS), которая позволяет драйверам сетевых протоколов использовать сервисы сетевых интерфейсов (отправка/прием сетевых пакетов) скрывая детали их реализации. Драйвер сетевого адаптера, разработанный в соответствии с этой спецификацией, принято называть NDIS минипортом (miniport).Одно из преимуществ - то, что код свободно переносится из 9x/ME - winNT/2000 . Детальное описание предмета можно найти в документации DDK (раздел NetworkDrivers), вкратце NDIS описывает правила (интерфейсы и структуры), в соответствии, с которыми должны разрабатываться драйвера сетевых адаптеров, а так же предоставляет библиотеку функций, к которой должен обращаться разработчик вместо прямого использования сервисов ядра.
2) Драйвера сетевых протоколов. Вкратце, драйвер сетевого протокола (такого как, например TCP/IP) для работы с сетевыми интерфейсами использует функции уже упомянутой библиотеки NDIS и может предоставлять TDI (Transport Data Interface) вышележащим уровням (TDI-клиентам, одним из типичных представителей которых в ядре NT/2000/XP является afd.sys - kernel-mode часть Windows Sockets).
3) User-Mode DLL's которые формируют интерфейс WindowsSockets. Это ws2_32.dll, msafd.dll, wshtcpip.dll и другие.
Тех, кто хочет более детально рассмотреть сетевую подсистему Windows , отсылаю к David Solomon, Mark Russinovich : Inside Windows 2000, часть 13.
Технологии фильтрации:
Технологии фильтрации в User-mode автор не рассматривает.
Технологии фильтрации сетевого трафика в режиме ядра:
1) Kernel-mode sockets filter. Эта технология применима для WindowsNT/2000. Основана на перехвате всех вызовов из msafd.dll (самая низкоуровневая user-mode DLL из состава Windows Sockets) к модулю ядра afd.sys (kernel-mode часть WindowsSockets). Данная технология требует аккуратного обращения с интерфейсами AFD , т.к. они изменяются в разных версиях NT. AFD является TDI клиентом и реализует приём/отправку данных через драйвер протокола. Msafd.dll сообщает AFD название протокола для каждого сокета.Для более подробного изучения отправляю в Inside Windows 2000, раздел 13, подраздел Networking APIs.Способ бесполезен при маршрутизации, т.к. она осуществляется внутри TCPIP.SYS(иногда и вне его - поиск по DDK: Fast Forwarding Path - происходит внутри NDIS ) и не доходит до сокетов. Хотя данный способ удобен для шифрования потоков данных и QoS - Quality of Service - предоставляется специальное API (смотреть в MSDN - поиск по QOS Reference).
2) TDI-filter driver. Технология применима как в Windows 9x/ME так и в WindowsNT/2000, хотя конкретные реализации сильно отличаются. Что касается Windows NT/2000, то в случае TCP/IP фильтрации необходимо перехватывать все вызовы, направленные устройствам (devices) созданным модулем tcpip.sys (\Device\RawIp, \Device\Udp, \Device\Tcp). Технология достаточно известная и используется в ряде коммерческих продуктов (например, OutpostFirewall).
3) NDIS Intermediate Driver Способ очень неудобен в инсталляции и программировании. Желающие могут изучить DDK. Ниже приведён пример кода, показывающего громоздкость программирования :
local status: NTSTATUS
local PChars: NDIS_PROTOCOL_CHARACTERISTICS
local MChars: NDIS_MINIPORT_CHARACTERISTICS
local Param: PNDIS_CONFIGURATION_PARAMETER
local Name1: NDIS_STRING
local WrapperHandle:NDIS_HANDLE
local DriverHandler: NDIS_HANDLE
local ProtHandler: NDIS_HANDLE
mov DriverHandler,NULL
mov ProtHandler,NULL
invoke NdisInitializeWrapper,addr WrapperHandle,pDriverObject, pusRegistryPath,NULL
invoke RtlZeroMemory,addr MChars,sizeof NDIS_MINIPORT_CHARACTERISTICS
mov MChars.MajorNdisVersion, 5
mov MChars.MinorNdisVersion, NULL
mov MChars.InitializeHandler, offset MPInitialize
mov MChars.QueryInformationHandler, offset MPQueryInformation
mov MChars.SetInformationHandler, offset MPSetInformation
mov MChars.ResetHandler, offset MPReset
mov MChars.TransferDataHandler, offset MPTransferData
mov MChars.HaltHandler, offset MPHalt
mov MChars.CheckForHangHandler, NULL
mov MChars.SendHandler, offset MPSend
mov MChars.ReturnPacketHandler, offset MPReturnPacket
invoke NdisIMRegisterLayeredMiniport,WrapperHandle,addr MChars, sizeof MChars,\
addr DriverHandler
.if eax == STATUS_SUCCESS
invoke NdisMRegisterUnloadHandler,WrapperHandle,offset Unload
invoke RtlZeroMemory,addr PChars, sizeof NDIS_PROTOCOL_CHARACTERISTICS
mov PChars.MajorNdisVersion, 5
mov PChars.MinorNdisVersion, 0
invoke RtlInitUnicodeString,addr PChars.Name_,addr stroka
mov PChars.OpenAdapterCompleteHandler, offset PtOpenAdapterComplete
mov PChars.CloseAdapterCompleteHandler, offset PtCloseAdapterComplete
mov PChars.SendCompleteHandler , offset PtSendComplete
mov PChars.TransferDataCompleteHandler , offset PtTransferDataComplete
mov PChars.ResetCompleteHandler , offset PtResetComplete
mov PChars.RequestCompleteHandler, offset PtRequestComplete
mov PChars.ReceiveHandler , offset PtReceive
mov PChars.ReceiveCompleteHandler , offset PtReceiveComplete
mov PChars.StatusHandler, offset PtStatus
mov PChars.StatusCompleteHandler, offset PtStatusComplete
mov PChars.BindAdapterHandler , offset PtBindAdapter
mov PChars.UnbindAdapterHandler , offset PtUnbindAdapter
mov PChars.UnloadHandler , NULL
mov PChars.ReceivePacketHandler , offset PtReceivePacket
mov PChars.PnPEventHandler, offset PtPNPHandler
invoke NdisRegisterProtocol,addr status,addr ProtHandler,addr PChars,\
sizeof NDIS_PROTOCOL_CHARACTERISTICS
.if eax==STATUS_SUCCESS
invoke NdisIMAssociateMiniport,DriverHandler,ProtHandler
mov eax,STATUS_SUCCESS
ret
.endif
.endif
Вкратце способ заключается в создании виртуального адаптера и его установки таким образом,что при каждом вызове реального адаптера сначала шло обращение к виртуальному.Т.е мы как бы накладываем наш виртуальный адаптер на реальный.
Вся обработка поступивших вызовов идёт в MP* и Pt* функциях. Где MP* -относится к Miniport, т.е. к нашему виртуальному адаптеру, а Pt* - к Protocol , протоколу, реализуемуму нашим адаптером.
Т.е если мы хотим фильтровать TCP/IP , Protocol должен уметь обрабатывать IP - пакеты .
4) Windows 2000 Filter-Hook Driver. Метод описан в документации DDK и применим только в Windows 2000 и выше, его мы и будем рассматривать в практической части.
5) NDIS Hooking Filter Driver.Способ сводится к перехвату некоторых функций NDIS библиотеки, которые в дальнейшем позволяют отследить регистрацию всех протоколов установленных в операционной системе и открытие ими сетевых интерфейсов. Используется в небезызвестном ZoneAlarm. Для Windows 2000 достаточно перехватить 4 функции:
6) Packet Filtering API. На данный момент доступно в Windows 2000 Server и Windows .NET Server 2003.
Насчёт пунктов 2,3,5 : автор надеется осветить их в отдельной обширной статье по NDIS и TDI.
Часть вторая, практическая.
Использование Windows 2000 Filter-Hook Driver
Начиная с Windows 2000 Microsoft включила возможность фильтрации IP траффика в контексте IP Filter driver - стандартного сервиса Windows 2000. Как написано в DDK ,драйвера , используемые IP Filter driver сервисом, могут обрабатывать и фильтровать IP траффик, т.е расширять возможности IP Filter driver сервиса.
Правда при этом необходимо учитывать нюанс - только один драйвер может использоваться при фильтрации.
Драйвер для фильтрации траффика представляет собой обычный Kernel Mode Driver, реализующий определённую функцию фильтрации , которую он и регестрирует в IP Filter driver сервисе .Фильтруются как исходящий, так и входящий траффик.
Вот исходный текст простейшего драйвера для IP Filter driver, драйвер просто drop -ает все пакеты :
.386
.model flat, stdcall
; I N C L U D E F I L E S
;#########################################################################
include D:\masm32\include\w2k\ntstatus.inc
include D:\masm32\include\w2k\ntddk.inc
include D:\masm32\include\w2k\pfhook.inc
include D:\masm32\include\w2k\ntoskrnl.inc
include D:\masm32\Macros\Strings.mac
includelib D:\NTDDK\libfre\i386\ntdll.lib
includelib D:\NTDDK\libfre\i386\ntoskrnl.lib
; P R O T O
;##########################################################################
set_hook PROTO :PacketFilterExtensionPtr
; D A T A
;##########################################################################
.data
CCOUNTED_UNICODE_STRING "\\Device\\IPFILTERDRIVER" ,drvsmbl,4
ipfilter_name UNICODE_STRING <>
hook_nfo PF_SET_EXTENSION_HOOK_INFO <>
status NTSTATUS ?
devobj PDEVICE_OBJECT ?
isb IO_STATUS_BLOCK <>
fileobj PFILE_OBJECT NULL
myirp PIRP NULL
; C O D E
;############################################################################
.code
; DriverEntry
;############################################################################
DriverEntry proc pDriverObject:PDRIVER_OBJECT, pusRegistryPath:PUNICODE_STRING
mov eax,offset hookproc
invoke set_hook, eax
.if eax != STATUS_SUCCESS
ret
.endif
mov eax, pDriverObject
assume eax:PTR DRIVER_OBJECT
mov [eax].DriverUnload,offset Unload
assume eax:nothing
mov eax,STATUS_SUCCESS
ret
DriverEntry endp
; Windows 2000 hook (built in)
;###############################################################################
Unload proc p1DriverObject:PDRIVER_OBJECT
invoke set_hook,NULL
ret
Unload endp
;###############################################################################
set_hook proc hook_fn:PacketFilterExtensionPtr
invoke IoGetDeviceObjectPointer,addr drvsmbl,STANDARD_RIGHTS_ALL,\
addr fileobj,addr devobj
mov status,eax
.if eax != STATUS_SUCCESS
jmp exit
.endif
mov eax,hook_fn
mov hook_nfo.ExtensionPointer,eax
invoke IoBuildDeviceIoControlRequest,IOCTL_PF_SET_EXTENSION_POINTER(),\
devobj, addr hook_nfo,\
sizeof hook_nfo, NULL, 0, FALSE, NULL,addr isb
mov myirp,eax
.if eax == NULL
mov status ,STATUS_INSUFFICIENT_RESOURCES
jmp exit
.endif
invoke IoCallDriver,devobj,myirp
mov myirp,NULL
mov eax,STATUS_SUCCESS
ret
exit:
.if fileobj!=NULL
invoke ObDereferenceObject,fileobj
.endif
mov eax,status
ret
set_hook endp
;###############################################################################
hookproc proc PacketHeader:PTR BYTE, Packet:PTR BYTE, PacketLength:WORD,
RecvInterfaceIndex:WORD,SendInterfaceIndex:WORD,RecvLinkNextHop:DWORD,
SendLinkNextHop:DWORD
mov eax,PF_DROP
ret
hookproc endp
end DriverEntry
Для компиляции потребуется masm32 by hutch ,последний KMDKit by Four-F, Update KMDKit by van (пока состоит из pfhook.inc и неполного ndis.inc).
Рассмотрим более подробно данный код.
1) CCOUNTED_UNICODE_STRING "\\Device\\IPFILTERDRIVER" ,drvsmbl,4 - название нашего IP Filter driver сервиса.
2) hook_nfo PF_SET_EXTENSION_HOOK_INFO <> - структура , содержащая указатель типа PacketFilterExtensionPtr, т.е на нашу функцию фильтрации. Все остальные типы описаны в MSDN и KMD by Four-F.
3)
mov eax,offset hookproc
invoke set_hook, eax
.if eax != STATUS_SUCCESS
ret
.endif
Вызываем set_hook , в качестве параметра выступает offset нашей функции фильтрации.
Если хук не удалось установить, выходим.
4)
mov eax, pDriverObject
assume eax:PTR DRIVER_OBJECT
mov [eax].DriverUnload,offset Unload
assume eax:nothing
mov eax,STATUS_SUCCESS
ret
Стандартная процедура регистрации функции выхода.
5)
Unload proc p1DriverObject:PDRIVER_OBJECT
invoke set_hook,NULL
ret
Unload endp
Устанавливаем указатель на функцию фильтрации в IP Filter driver сервисе в NULL
6)
set_hook proc hook_fn:PacketFilterExtensionPtr
invoke IoGetDeviceObjectPointer,addr drvsmbl,STANDARD_RIGHTS_ALL,addr fileobj,
addr devobj
Наша функция установки фильтра.
IoGetDeviceObjectPointer - возвращает указатель в devobj на Device и file object , соответсвующий ему , название которого в drvsmbl . При условии, что доступ к нему разрешён.
7)
invoke IoBuildDeviceIoControlRequest,IOCTL_PF_SET_EXTENSION_POINTER(),devobj, \
addr hook_nfo ,sizeof hook_nfo, NULL, 0, FALSE, NULL,addr isb
Данная функция подробно описана в Walter Oney's Programming the Microsoft Windows Driver Model.
Макрос IOCTL_PF_SET_EXTENSION_POINTER() определён в pfhook.inc
Результат - устанавливаем irp для нашего драйвера.
Все остальные функции в данном разделе описаны в DDK и Programming the Microsoft Windows Driver Model.
8)
hookproc proc PacketHeader: DWORD , Packet: DWORD, PacketLength:WORD,
RecvInterfaceIndex:WORD,SendInterfaceIndex:WORD,RecvLinkNextHop:DWORD,
SendLinkNextHop:DWORD
mov eax,PF_DROP
ret
hookproc endp
Наш фильтр. Как видно, перед нами внутренности пакета.Заголовок и содержимое.
Возвращаем PF_DROP.
В pfhook.inc определены следующие константы для работы с IP пакетами:
PF_FORWARD EQU 0t
PF_DROP EQU 1t
PF_PASS EQU 2t
PF_ICMP_ON_DROP EQU 3t
PF_FORWARD - форвардит пакет. Т.е. если destination address != наш адрес и включена маршрутизация, то немедленно посылается forward response в IP стек.
PF_PASS - пропускает пакет на наш компьютер.
PF_ICMP_ON_DROP - дропает пакет и отправляет ICMP - сообщение.
Данная константа недокументирована, хотя и определена.
Как установить наш драйвер ?
Автор использовал утилиту instdrv из NT DDK . К сожалению, в Win2000 DDK она отсутсвует.
Итак, набираем в консоли:
net start ipfilterdriver
instdrv filter D:\projects\asm\filter\filter.sys
ping 127.0.0.1
Destination host unreachable. ; host unreachable,
Destination host unreachable. ; что и следовало ожидать,
Destination host unreachable. ; потому что все пакеты
Destination host unreachable. ; уничтожены, ICMP - сообщение
Ping statistics for 127.0.0.1: ; не отправлялось.
Packets: Sent = 4, Received = 0, Lost = 4 (100% loss),
Approximate round trip times in milli-seconds:
Minimum = 0ms, Maximum = 0ms, Average = 0ms
.
instdrv filter remove
Заключение.
Автор не претендует на полноту изложения , он постарался дать лишь общее представление о предмете. Автор также надеется , что данная статья позволит самостоятельно создавать firewall'ы на основе IP Filter driver сервиса и данного сэмпла.
Рекомендуемая литература:
Walter Oney's Programming the Microsoft Windows Driver Model.
David Solomon, Mark Russinovich : Inside Windows 2000
Благодарности:
Volodya /wasm.ru , за то, что терпел и наставлял меня , и за instdrv.
Four-F/wasm.ru ,за KMDKit и замечательные статьи.
gl00my , за моральную поддержку.
Файлы:
[C] van