|
Ушел с форума
|
|
Краткий обзор Windows Filtering Platform04.11.2014, 11:21. Показов 49237. Ответов 9
Метки нет (Все метки)
Здесь я постараюсь дать небольшой обзор WFP, а также затронуть некоторые
технические моменты. Без каких-либо претензий на полноту, точность и т.д. Часть 1, Основы. Что такое WFP ? WFP расшифровывается как Windows Filtering Platform, платформа фильтрации Windows. Внимание ! Не путать с технологией WPF из .NET ! WFP - это универсальная технология фильтрации сети, охватывающая все основные уровни, от транспортного (TCP/UDP) до канального (Ethernet), и дающая разработчикам массу интересных возможностей. Почему WFP ? До WFP разработчики фаерволов, спам-фильтров, родконтролей и других программ такого плана были вынуждены использовать сложные, разрозненные, а часто просто недокументированные способы, которые во многих отношениях не давали нужного эффекта или требовали высокой квалификации и учета многочисленных деталей, с которыми то и дело возникали проблемы при переносе на другие версии Windows. Пример таких технологий - TDI, LSP, NDIS, а также старые Filter-Hook Drivers и Firewall-Hook Drivers. В WFP многие типовые проблемы этих технологий были учтены, некоторые решения вообще не имеют аналогов, либо тяжелореализуемы в TDI/LSP/NDIS. Сама технология имеет достаточно простую и понятную объектную модель, хорошо документирована и при желании ее может освоить человек весьма средней квалификации. Добавлю, что WFP - единственная на сегодняшний день технология, позволяющая полноценно фильтровать трафик от modern-приложений на Windows 8 и выше. И не только. Например, TDI и LSP в настоящее время уже не справляются даже с Internet Explorer 11 на Windows 7. Поэтому при выборе технологии для нового проекта следует в первую очередь рассматривать WFP, и только потом (если есть причины, например совместимость с XP или отсутствие каких-то важных функций WFP на целевых версиях Windows) другие. Краткая история. Появилась в Windows Vista, с тех пор постепенно развивается и дополняется. В Windows 7 появилась возможность фильтрации на уровне Ethernet, возможность делать редиректы соединений (как исходящих, так и входящих), а также разные вспомогательные функции, например для своевременной очистки ресурсов. В Windows 8 появилось то, чего так долго ждали некоторые разработчики - возможность многократно перекидывать соединение с одного прокси на другой. Раньше из-за отсутствия этой возможности было почти нереальным иметь в системе, к примеру, параллельно работающий фаервол и какой-нибудь спам-фильтр от разных производителей. Есть и другие изменения, все они описаны в MSDN. Ложка дегтя. Лично для меня ложкой дегтя в WFP является то, что наиболее "вкусные" вещи в ней появились только в Windows 7 - Windows 8 и для того, чтобы сделать коммерческий продукт, реально совместимый со всей современной линейкой Windows, не списывая со счетов XP и Vista, все равно приходится использовать TDI/LSP вместе с WFP. Также я замечал, что документация местами недостаточно детальная, а кое-где содержит ошибки. В итоге приходилось иногда закапываться надолго в отладчик, чтобы узнать, в чем дело. И в WFP, как и в любой технологии, есть недочеты и даже ошибки. Сам я с ними на практике не сталкивался, но не раз слышал о проблемах с Teredo, например, в результате чего система выпадает в синий экран (BSOD). Документация и исходники. Главный источник информации по WFP - конечно же, MSDN. Обращаю внимание, что WFP имеет функции как в kernel mode, так и в user mode, поэтому одну часть документации следует искать в разделе о программировании драйверов, а вторую - в разделе "network programming" из WinAPI: Windows Filtering Platform http://msdn.microsoft.com/en-u... 85%29.aspx Windows Filtering Platform Callout Drivers http://msdn.microsoft.com/en-u... 85%29.aspx Аналогично, исходники примеров для WFP есть как в Windows SDK Samples (diagevents и msnfilter) и в Windows Driver Kit Samples (ddproxy, inspect, msnmntr и stmedit). Вероятно, на MSDN Gallery можно найти и другие исходники, а где-нибудь на codeproject, sourceforge и других опенсорсных хостингах - исходники проектов с использованием WFP. В следующей части: Архитектура WFP, объектная модель, принципы работы.
11
|
|
| 04.11.2014, 11:21 | |
|
Ответы с готовыми решениями:
9
Обсуждение "Краткий обзор Windows Filtering Platform"
Windows Filtering Platform траблы с портом из Fixed Value |
|
Ушел с форума
|
|
| 04.11.2014, 15:19 [ТС] | |
|
Часть 2, Архитектура.
Введение. Рассмотрим типичный жизненный цикл обмена информацией по протоколу TCP. 1. Приложение (клиент) вызывает функцию connect, указывая адрес и порт пункта назначения, а также семейство и тип протокола. Или же (сервер) оно вызывает accept в ожидании подключений. 2. Через некоторое время соединение установлено. Клиенту возвращается управление из функции connect (ну или приходит соответствующий сигнал, как в случае с моделью select или асинхронным I/O - это уже за рамками темы), серверу возвращается новый сокет, связанный с клиентом. 3. Приложения обмениваются данными посредством функций send и recv. 4. Приложения закрывают свои концы соединений функцией shutdown. Когда оба конца закрыты, связь завершается, соединение считается разомкнутым. Представим, что мы пишем фильтр TCP-трафика, и нас на каждом шаге этой последовательности интересуют определенные данные: 1. Адрес и порт пункта назначения, ID процесса, который выполнил connect/accept. Имя и вообще контекст безопасности пользователя, которому принадлежит процесс. 2. Статус операции connect (успех или ошибка). 3. Буферы, передаваемые через send и recv. Предположим, мы хотим блокировать нежелательные соединения (по набору запрещенных IP-адресов и портов, а также по процессам или пользователям). Мы также хотим получать уведомление о закрытии соединения (п.4), чтобы освободить все связанные с ним данные. WFP для решения этой задачи предлагает несколько абстракций: Layers - уровни фильтрации. Каждым уровнем обслуживается определенный этап обработки соединения или передачи данных. Например, установка соединения обрабатывается на уровне ALE (будет рассмотрен ниже), а работа с буферами send/recv - на уровне Stream. У каждого уровня своя специфика и свой набор свойств, с которыми можно работать. Часто ту информацию, что можно достать на одном уровне, уже нельзя увидеть на других. Аналогично, не все функции, которые работают на одних уровнях, работают на других. Sublayers - подуровни. Нужны для организации более гибкой стратегии фильтрации. Например, можно зарегистрировать проверки на разных Sublayers и они будут выполняться по очереди. Filters - фильтры. Задают разные условия, при которых должна (или не должна) выполняться фильтрация. Например, можно фильтровать только трафик, идущий на порт 80, а остальной игнорировать. Фильтры определяют не только условия, но и действия, т.е. что делать с трафиком, когда условие срабатывает. Основные операции: разрешить, заблокировать, задержать, либо вызвать соответствующий Callout. Про Callout-ы будет написано ниже. Conditions - условия, заданные в фильтре. В фильтре может быть несколько условий. Shims - исполнительные объекты, расположенные во всех ключевых точках сетевого стека. Если Filters и Conditions только задают правила, что делать с трафиком, то Shims отвечают за само выполнение этих правил, т.е. блокировка, задержка трафика, вызов Callout-а и так далее. Callout - блок функций, которые обрабатывают трафик и решают, что конкретно с ним делать. Callout Driver - драйвер, реализующий один или несколько Callout-ов. Provider - поставщик. Объединяет логически связанные Filters, Sublayers и Callouts, принадлежащие одной программе, одной задаче/политике, или объединенные какими-то другими общими признаками. Filter Engine (Engine) - функциональное ядро WFP, которое управляет фильтрами, Shim-ами, Callout-ами и остальными объектами технологии. Base Filter Engine (BFE) - служба, отвечающая за координацию компонентов WFP, за регистрацию новых фильтров, за хранение конфигурации, настройки безопасности и т.д. Ссылки по теме: WFP Architecture http://msdn.microsoft.com/en-u... 85%29.aspx Object Model http://msdn.microsoft.com/en-u... 85%29.aspx Как это работает. Когда в сетевом стеке происходит какое-то событие, например установка или закрытие соединения, приход дейтаграммы, получение буфера с данными и т.п., Filter Engine с помощью Filters определяет, нужно ли как-то обрабатывать это событие. В терминах WFP данный процесс называется классификацией (classify). Если хотя бы один Condition срабатывает, вызывается Shim, который, в зависимости от того, что задано в фильтре, выполняет нужное действие. В частности, Shim может вызвать ваш зарегистрированный Callout, точнее, одну из его функций (их всего три). Все остальное выполняет Callout, в соответствии с логикой фильтрации трафика. Если, к примеру, Callout работает на уровне ALE, то в функцию ему будут переданы адрес и порт пункта назначения и источника, тип протокола, ID приложения, полный путь к exe и другая полезная информация. Если на уровне Stream, там будут другие данные - направление трафика (входящий/исходящий), флаги и т.д. Далее Callout может поступать с данными на свое усмотрение: блокировка, игнор, редирект, анализ, задержка трафика и многое другое. Все ограничено лишь фантазией разработчика. Выше была описана типичная последовательность операций при работе с TCP. Давайте посмотрим, как она будет фильтроваться WFP. 1. Установка соединения (connect). Здесь будут срабатывать фильтры на уровне FWPS_LAYER_ALE_AUTH_CONNECT_V4. Здесь же можно заблокировать соединение. 2. Соединение установлено. Сработают фильтры на уровне FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4. Добавлю, что на этом уровне блокировать коннект не рекомендуется, он создан только для того, чтобы Callout получил уведомление о том, успешно или нет создано соединение. Здесь же можно установить связь между коннектом и потоком данных. 3. Передача данных. Будут срабатывать фильтры на уровне FWPS_LAYER_STREAM_V4, причем как для send (outgoing data), так и для recv (incoming data). 4. Закрытие соединения. Если с потоком данных был ассоциирован контекст, будет вызвана одна из функций Callout-а. Также на Windows 7 есть специальные уровни для очистки ресурсов - FWPS_LAYER_ALE_RESOURCE_RELEASE_V4. Еще определения. Flow (поток данных). Каждое соединение - это отдельный двунаправленный поток данных. Если, к примеру, программа создает два коннекта на один и тот же адрес, вы будете в драйвере видеть два разных потока данных, каждый со своим состоянием. Flow Context (контекст потока). 64-битное число, ассоциированное с определенным потоком данных. Нужно, чтобы отличать потоки друг от друга. Fixed Values. Фиксированный набор аргументов, приходящий в Callout. Описан здесь: Data Field Identifiers http://msdn.microsoft.com/en-u... 85%29.aspx Для каждого Layer-а свой набор аргументов. Например, на уровне FWPS_LAYER_ALE_CONNECT_REDIRECT_V4 (установка соединения) через Fixed Values можно получить имя пользователя, а на уровне FWPS_LAYER_STREAM_V4 его уже нет. Meta Values. Аналогично Fixed Values. Информация здесь: Metadata Fields at Each Filtering Layer http://msdn.microsoft.com/en-u... 85%29.aspx Итак, Callout, заглядывая в Fixed Values и Meta Values, решает, что делать с данным событием/трафиком и предпринимает определенные действия, после чего весь цикл повторяется заново. Доступ к буферам с данными осуществляется через структуру NET_BUFFER (будет описана в следующих частях).
13
|
|
|
Ушел с форума
|
|||||||||||||||||||||
| 05.11.2014, 22:56 [ТС] | |||||||||||||||||||||
|
Часть 3-а, Регистрация в системе.
Регистрация выполняется в режиме пользователя, обычно эта функция возлагается на установщик программы. Впрочем, никто не мешает регистрировать драйвер каждый раз при запуске программы, WFP дает такую возможность. Регистрация начинается с функции FwpmEngineOpen0. Кстати, небольшое отступление. В WFP, как и в некоторых других специфических компонентах Windows, принята своя система именования: ПрефиксТипОбъектОперацияВерсия. Префикс - Fwp, общий для подсистемы WFP. Тип - означает тип операции, managed (m) или run-time (s). Все, что managed, относится к user mode, а run-time относится к kernel mode. Например, при регистрации из user mode в качестве Layer передается константа FWPM_LAYER_INBOUND_IPPACKET_V4, а в kernel mode она же фигурирует под именем FWPS_LAYER_INBOUND_IPPACKET_V4. Объект - указывает сущность, к которой применяется операция. В данном случае Engine. Open - операция. 0 - номер версии. Похожие соглашения можно встретить в Windows еще кое-где (например, в WDF). Итак, FwpmEngineOpen0:
В простейшем случае Session достаточно заполнить нулями, указав только displayData.name и displayData.description. Отдельно стоит отметить флаг FWPM_SESSION_FLAG_DYNAMIC - при его использовании регистрация действует до того момента, когда будет закрыт хэндл hEngine (или до того момента, когда приложение завершится). MSDN настоятельно рекомендует оборачивать операции установки и удаления внутрь транзакции, и я не вижу причин, по которым не стоит следовать этому совету. Для этого нам помогут функции FwpmTransactionBegin0 и FwpmTransactionCommit0, а также FwpmTransactionAbort0. Все очень просто: сразу после FwpmEngineOpen открываем транзакцию и все остальные объекты регистрируем между Begin и Commit. Если что-то пошло не так, зовется функция Abort, отменяющая все сделанные изменения. Следующий необходимый шаг - регистрация провайдера. Как нетрудно догадаться, для этого нужна функция FwpmProviderAdd0. И здесь все достаточно тривиально, обойдемся без комментариев. Обращаю внимание на флаг FWPM_PROVIDER_FLAG_PERSISTENT: если его не поставить, то после перезагрузки компьютера можно с удивлением обнаружить, что никакого провайдера в системе нет. Аналогичные флаги персистентности есть у Filters, Callouts и Sublayers.
При чтении документации WFP становится не сразу понятно, зачем вообще нужны подуровни и почему нельзя поставить свой фильтр на какой-нибудь существующий уровень/подуровень. Ответ находится здесь: Filter Arbitration http://msdn.microsoft.com/en-u... 85%29.aspx Если вкратце, смысл вот в чем. Представьте, что на одном и том же подуровне сидят два фильтра от разных провайдеров, которые анализирут трафик и решают, пропускать его или нет. В этом случае, если верхний фильтр (т.е. тот, который вызывается раньше другого) явным образом разрешит прохождение трафика (FWP_ACTION_PERMIT), нижний фильтр вообще не будет участвовать в "голосовании". Почему - спросите у разработчиков WFP. Так задумано. Но в таком случае это поведение нарушает логику работы второго фильтра, который при других обстоятельствах запретил бы трафик. Впрочем, вы можете посадить фильтр на какой-нибудь предопределенный подуровень и не мучиться. Только потом не удивляйтесь, если ваш Callout не всегда будет срабатывать. Добавить Sublayer очень просто, как и все остальное:
Более "тяжелые" Sublayer-ы обрабатываются первыми. Этот параметр нужен для упорядочивания своих Sublayer-ов, а вовсе не для того, чтобы записать туда 0xFFFF в надежде быть всегда первым. Регистрируем Callout:
Здесь я зарегистрировал Callout на уровне FWPM_LAYER_ALE_AUTH_CONNECT_V4. Вы можете использовать другой уровень, можете добавить еще один или несколько Callout-ов или Sublayer-ов, WFP это позволяет.
13
|
|||||||||||||||||||||
|
Ушел с форума
|
|||||||||||
| 05.11.2014, 22:59 [ТС] | |||||||||||
|
Часть 3-б, Регистрация.
Регистрация фильтров. Переходим к самому сложному этапу:
2) порт 80. Таким образом, мы хотим ловить весь трафик, проходящий по TCP на 80 порту (обычно HTTP). В каждом условии fieldKey задает признак, который будет проверяться. Их достаточно много: Filtering Condition Identifiers http://msdn.microsoft.com/en-u... 85%29.aspx Кроме этого, можно проверять также различные флаги, например на Windows 8 с помощью флага FWP_CONDITION_FLAG_IS_PROXY_CONNECTION можно проверить, является ли соединение проксируемым. Полный список здесь: Filtering Condition Flags http://msdn.microsoft.com/en-u... 85%29.aspx Но будьте осторожны ! Как и в случае с Fixed Values / Meta Values, конкретные свойства и флаги доступны только на конкретных уровнях. Filtering Conditions Available at Each Filtering Layer http://msdn.microsoft.com/en-u... 85%29.aspx matchType задает тип проверки - равно/не равно, больше/меньше, проверка диапазона и т.д. Например, если бы я вместо FWP_MATCH_EQUAL поставил FWP_MATCH_GREATER, фильтр стал бы срабатывать на всех соединениях с номером порта больше 80. Вот список доступных типов проверки:
значение, которое требуется сравнивать. Фильтр устанавливается на конкретном Sublayer-е (Filter.subLayerKey) и, как и другие объекты, имеет схожие флаги. "Вес" фильтра имеет значение, когда у вас на одном Sublayer сидят два или более фильтров. В других случаях конкретное значение роли не играет. Но на всякий случай все равно советую заглянуть сюда: Filter Weight Assignment http://msdn.microsoft.com/en-u... 85%29.aspx Filter Weight Identifiers http://msdn.microsoft.com/en-u... 85%29.aspx Ну и ключевой момент: в action.type указывается тип действия, которое будет выполняться при срабатывании фильтра. Возможных значений всего пять: FWP_ACTION_BLOCK Заблокировать трафик. FWP_ACTION_PERMIT Разрешить трафик. FWP_ACTION_CALLOUT_TERMINATING FWP_ACTION_CALLOUT_INSPECTION FWP_ACTION_CALLOUT_UNKNOWN Вызвать Callout. Разница между TERMINATING, INSPECTION и UNKNOWN только в том, что позволено делать Callout-у. TERMINATING-Callout обязан явным образом либо разрешить, либо заблокировать соединение. INSPECTION-Callout может только наблюдать. UNKNOWN-Callout может, но не обязан, блокировать или разрешать трафик. Если вы ассоциируете с фильтром Callout, то должны указать его GUID в поле action.calloutKey. Пока Callout Driver еще не написан, так что делать этот фильтр ничего полезного не будет. Кстати, здесь может возникнуть вопрос: а зачем вообще нужен Callout, если можно создать правило и установить в фильтре action.type = FWP_ACTION_BLOCK, блокируя нежелательные соединения ? Правильно, так можно и нужно делать, если этого достаточно для вашей задачи. Добавлю, что в WFP есть несколько предопределенных Callout-ов для некоторых задач, собраны они здесь: Built-in Callout Identifiers http://msdn.microsoft.com/en-u... 85%29.aspx Но все же FWP_ACTION_BLOCK и встроенных Callout-ов часто бывает недостаточно. Если вам нужно анализировать, а тем более изменять трафик, работая с буферами данных, то без написания Callout-драйвера не обойтись. Итак, подытожим. Мы создаем хэндл Engine, открываем транзакцию, затем внутри транзакции регистрируем своего провайдера, связываем с ним один или несколько Sublayers, добавляем Callouts и Filters на нужные уровни/подуровни, остается только позвать FwpmTransactionCommit0 и позакрывать хэндлы. С этого момента ваши объекты вступают в "игру" в сетевом стеке Windows. Отмена регистрации - обратная процедура, еще более простая. Функции FwpmEngineOpen0 и FwpmTransactionBegin0 должны быть уже вам знакомы, они и здесь используются. Для удаления фильтров используйте FwpmFilterDeleteByKey0, для удаления Callout-ов - FwpmCalloutDeleteByKey0, затем можно удалить Sublayer - FwpmSubLayerDeleteByKey, и наконец, провайдера - FwpmProviderDeleteByKey0, после чего завершаете транзакцию и закрываете хэндлы. В следующей части: реализация Callout в драйвере.
12
|
|||||||||||
|
Ушел с форума
|
||||||
| 09.11.2014, 23:32 [ТС] | ||||||
|
Часть 4-а, реализация Callout-драйвера.
Переходим к реализации Callout-драйвера. Первое, что нужно сделать - создать устройство (DEVICE_OBJECT), для этого используется функция IoCreateDevice. Далее вызываем FwpsCalloutRegister0 столько раз, сколько Callout-ов нам требуется зарегистрировать:
classifyFn, notifyFn и flowDelete. Вы можете использовать одни и те же функции для разных Callout-ов. Кстати, в Windows 7 и выше доступна функция FwpsCalloutRegister1, а в Windows 8 - FwpsCalloutRegister2. Они предоставляют более интересные возможности, например редирект соединений. Обращаю внимание на флаг FWP_CALLOUT_FLAG_CONDITIONAL_ON_FLOW: если установить его, Callout будет срабатывать только для данных, с которыми связан определенный Flow Context. Иными словами, можно выборочно контролировать определенный трафик, игнорируя остальные. Также замечу, что если необходимые фильтры уже зарегистрированы, Callout начинает действовать сразу же, еще до выхода из функции FwpsCalloutRegister0, так что если у вас есть какие-то общие данные, разделяемые с Callout-ом, они должны быть инициализированы до того, как эта функция будет вызвана. Удалить Callout также просто: FwpsCalloutUnregisterById0, функция принимает единственный аргумент - ID Callout-а. После удаления Callout-ов не забудьте удалить устройство, созданное IoCreateDevice.
13
|
||||||
|
Ушел с форума
|
|||||||||||||||||||||||||||||||
| 09.11.2014, 23:41 [ТС] | |||||||||||||||||||||||||||||||
|
Часть 4-б, функции Callout-а.
Их всего три: classifyFn, notifyFn и flowDelete, причем notifyFn может быть реализована очень просто, а flowDelete опциональна и вместо нее можно передать NULL (если вы не работаете с Flow Context). classifyFn
над Callout-драйвером. Разберем по порядку параметры: pInFixedValues - Массив Fixed Values (рассматривалось выше). Вытаскивать данные из этого массива следует примерно так:
pInMetaValues - Массив Meta Values. Перед тем, как обращаться к полям этого массива, следует проверить, присутствует ли значение в нужном поле. Например:
Здесь может быть либо NULL, в зависимости от условий, либо указатель на структуру FWPS_STREAM_CALLOUT_IO_PACKET0 (для stream-уровней, таких как FWPS_LAYER_STREAM_V4), либо NET_BUFFER. Так или иначе все сведется к работе с NET_BUFFER (будет описана в одной из следующих частей). Состав данных, которые приходят в pLayerData, сильно зависит от уровня фильтрации, на котором зарегистрирован Callout. Например, обрабатывая TCP-поток на уровне FWPS_LAYER_STREAM_V4, вы не увидите в данных заголовков IP-пакетов и т.п. pFilter - указатель на Filter, по условию которого сработал ваш Callout. Здесь находятся важные данные, которые нельзя проигнорировать. Отнеситесь с вниманием к флагам FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT и FWPS_FILTER_FLAG_PERMIT_IF_CALLOUT_UNREG ISTERED, как описано здесь: FWPS_FILTER0 structure http://msdn.microsoft.com/en-u... 85%29.aspx Если FWPS_FILTER_FLAG_CLEAR_ACTION_RIGHT установлен, вы должны сбросить флаг FWPS_RIGHT_ACTION_WRITE в соответствующей структуре (будет описана ниже), если завершаете classifyFn с кодом FWP_ACTION_PERMIT (разрешить) или FWP_ACTION_BLOCK (заблокировать). Обычно сбрасывать FWPS_RIGHT_ACTION_WRITE требуется только при FWP_ACTION_BLOCK. Флаг FWPS_FILTER_FLAG_PERMIT_IF_CALLOUT_UNREG ISTERED означает, что если Callout не зарегистрирован, вам следует пропустить трафик дальше, не блокируя его. В поле action фильтра будет указан тип Callout-а, в зависимости от которого вам разрешается или нет использовать соответствующие коды завершения, об этом я уже писал выше: FWP_ACTION_CALLOUT_TERMINATING требует, чтобы Callout установил для трафика FWP_ACTION_PERMIT или FWP_ACTION_BLOCK, FWP_ACTION_CALLOUT_INSPECTION может только наблюдать (FWP_ACTION_CONTINUE) и т.д. Вы не должны нарушать эти требования, иначе правильная система фильтрации не гарантируется. На таких принципах, кстати, построено очень многое во взаимодействии фильтрующих драйверов, не только сетевых: вам дается большая гибкость и разнообразие средств, но вместе с тем вы должны придерживаться определенных правил и не ставить "палки в колеса" другим драйверам. FlowContext - название говорит само за себя. Здесь передается значение, связанное с потоком данных, при условии, что вы задали его где-то раньше. Это значение вы можете использовать на свое усмотрение, например передавать через него адрес каких-то структур данных или функций, связанных именно с этим потоком, либо что-то еще. Размер поля FlowContext - 64 бита, хватит на все, единственное ограничение - нельзя иметь Flow Context, равный нулю. Про Flow Context и потоки данных будет написано в одной из следующих частей. pClassifyOut - сюда вы указываете, как хотите поступить с трафиком. Поле actionType: FWP_ACTION_PERMIT - разрешить; FWP_ACTION_BLOCK - заблокировать; FWP_ACTION_CONTINUE - передать запрос на рассмотрение в другой фильтр. Вы можете установить любой код, если он не противоречит условиям action фильтра, описанным выше. Обратите внимание, что если флаг FWPS_RIGHT_ACTION_WRITE в поле rights сброшен, то вы не имеете права ничего писать в actionType, кроме FWP_ACTION_BLOCK. То есть, либо пишете FWP_ACTION_BLOCK, либо оставляете поле как есть, без изменений. Попробуем сложить все вместе. Пример ниже подразумевает, что в фильтре указан action.type FWP_ACTION_CALLOUT_UNKNOWN, т.е. Callout может возвращать и permit, и block, и continue:
составлять суть вашей программы, кроется за комментариями "//...". Напоследок добавлю, что вы не можете просто взять и изменить данные в pLayerData. Для подобных вещей в WFP принято несколько схем: "close-reinject", "drop-reinject", и т.д. То есть, чтобы изменить данные, следует сначала заблокировать (FWP_ACTION_BLOCK) нужный фрагмент (см. структуру FWPS_STREAM_CALLOUT_IO_PACKET0), а затем вставить новый - FwpsStreamInjectAsync0. Если требуется отложить обработку трафика, например задать вопрос пользователю в интерактивном режиме, следует использовать специальные функции: на ALE-уровнях есть FwpsPendOperation0/FwpsCompleteOperation0, на Stream- уровнях есть FwpsCloneStreamData0/FwpsStreamInjectAsync0 и т.д. Собственно, здесь все достаточно хорошо расписано, еще и с примерами: Inspecting Packet and Stream Data http://msdn.microsoft.com/en-u... 85%29.aspx notifyFn
Сюда приходят уведомления о добавлении и удалении фильтров: FWPS_CALLOUT_NOTIFY_ADD_FILTER и FWPS_CALLOUT_NOTIFY_DELETE_FILTER. Все, что вам нужно - вернуть STATUS_SUCCESS, либо код ошибки, если вы не хотите, чтобы фильтр был добавлен в Filter Engine. Своего рода фильтр для фильтров. flowDeleteFn
Здесь последняя возможность очистить связанные с потоком данные, используя значение FlowContext. Если вы не используете FlowContext, можете игнорировать эту функцию или вообще установить ее в NULL при регистрации Callout-а. Не забывайте, что все три функции Callout-а вызываются на IRQL <= DISPATCH_LEVEL. В следующей части: потоки данных, работа с Flow Context, как отличить данные одного соединения от другого.
13
|
|||||||||||||||||||||||||||||||
|
Ушел с форума
|
|||
| 12.11.2014, 21:33 [ТС] | |||
|
Часть 5, Flow Context, потоки и их контексты.
Часто при написании WFP-драйверов возникает проблема: как в функции classifyFn понять, с каким именно потоком данных мы работаем. Проще говоря, к какому соединению этот поток данных относится. Знатоки TCP/IP могут уверенно возразить, что TCP-соединение однозначно идентифицируется четырьмя числами (4-tuple): IP-адрес источника, порт источника, IP-адрес пункта назначения, порт пункта назначения. Осталось только вытащить эти данные откуда-нибудь из Fixed Values или Meta Values и всего делов. В голову приходит схема "ключ-значение": в ключе у нас будет 4-tuple, в значении указатель на данные, связанные с потоком, все это заворачиваем в какой-нибудь AVL Tree, защищаем спин-локом и готово... Но в WFP для этих целей уже существует простое и эффективное средство, которое называется Flow Context. На определенных уровнях фильтрации, где понятия "соединение" или "поток" имеют хоть какой-то смысл, вместе с данными приходит хэндл потока (Flow Handle), и вы можете, используя этот хэндл, связать с потоком произвольное 64-битное значение (обычно указатель). Делается это функцией FwpsFlowAssociateContext0 function http://msdn.microsoft.com/en-u... 85%29.aspx Базовая информация здесь: Associating Context with a Data Flow http://msdn.microsoft.com/en-u... 85%29.aspx Flow Handle лежит в массиве Meta Values, поле так и называется - flowHandle. Не забудьте проверить, что это поле доступно для уровня, на котором вы к нему обращаетесь - FWPS_IS_METADATA_FIELD_PRESENT. В FwpsFlowAssociateContext0 вы должны также указать ID Callout-а, который будет работать с потоком, и Layer, на котором этот Callout зарегистрирован. Ну и, собственно, 64-битное значение на ваш выбор (кроме нуля), которое и называется Flow Context. С этого момента classifyFn указанного Callout-а, обрабатывая данный поток, будет давать вам Flow Context в одном из параметров. Когда соединение будет закрыто, сработает функция Callout-а flowDeleteFn, в которой вы можете освободить связанные с потоком данные, которые больше не нужны. Если Flow Context нужно освободить где-то раньше, воспользуйтесь функцией FwpsFlowRemoveContext0 function http://msdn.microsoft.com/en-u... 85%29.aspx При этом сработает flowDeleteFn, где вы сможете выполнить необходимую очистку. После этого с потоком снова можно будет связать контекст. Обратите внимание на ремарку: FwpsFlowRemoveContext0 может вернуть STATUS_PENDING, если потоком в данный момент занята функция classifyFn, т.е. очистка Flow Context будет отложена на некоторое время. Также добавлю, что внутри flowDeleteFn звать FwpsFlowRemoveContext0 не нужно, т.к. Flow Context к этому моменту уже уничтожен. Пример использования. Представьте, что вы хотите вести статистику, сколько данных по каким TCP- соединениям принято или отправлено. Можно поступить следующим образом: зарегистрировать два Callout-а, один на FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4, второй на FWPS_LAYER_STREAM_V4. Когда сработает верхний Callout, т.е. установлено новое соединение, вы создаете в памяти экземпляр некой структуры для хранения статистики по данному соединению, и связываете его с данным потоком через Flow Context. При этом в FwpsFlowAssociateContext0 следует указать ID нижнего Callout-а и уровень, на котором он работает. В classifyFn нижнего Callout-а будет приходить Flow Context - вы превращаете его в указатель и работаете с полями структуры. Когда срабатывает flowDeleteFn, экземпляр структуры можно удалить. Кстати, при регистрации нижнего Callout-а вы можете указать флаг FWP_CALLOUT_FLAG_CONDITIONAL_ON_FLOW. В этом случае его classifyFn вообще не будет вызываться для потоков, с которыми не связан Flow Context. Некоторые могут спросить: не лучше ли здесь использовать FWPS_LAYER_ALE_AUTH_CONNECT_V4 вместо FWPS_LAYER_ALE_FLOW_ESTABLISHED_V4 ? Ведь на нем можно еще и блокировать соединения, если потребуется. Дело в том, что на Windows Vista и Windows Server 2008 на уровне FWPS_LAYER_ALE_AUTH_CONNECT_V4, вопреки официальной документации, хэндла потока (Flow Handle) нет и вызывать FwpsFlowAssociateContext0 не с чем. Metadata Fields at Each Filtering Layer http://msdn.microsoft.com/en-u... 85%29.aspx
https://social.msdn.microsoft.... ?forum=wfp
В следующей части: NET_BUFFER - что это и как с ним работать.
12
|
|||
|
Ушел с форума
|
||||||||||||||||||||||||||
| 20.11.2014, 22:43 [ТС] | ||||||||||||||||||||||||||
|
Часть 6-а, архитектура NET_BUFFER, общие данные.
Эта часть, возможно, будет самой сложной для восприятия. Для начала небольшое отступление. Если вы знакомы с сетевой моделью OSI и TCP/IP и читали соответствующую литературу, например Стивенса или Таненбаума, - а я надеюсь, что это так, ибо в противном случае вам еще рано писать WFP-фильтры, - то наверняка вы знаете, что данные в сетях не ходят "просто так", а проходят через стек протоколов, от прикладного (верхний уровень) до канального (нижний) и обратно, причем формат обмена на каждом уровне свой. На транспортном уровне (TCP и UDP) весь поток данных заворачивается в так называемые сегменты. Сегменты позволяют, в числе прочего, организовать контроль доставки данных и их порядка, что для протокола TCP является одним из главных требований, иначе это не TCP никакой вовсе. Например, если сегмент с определенным номером не пришел в пункт назначения, то он будет отправлен повторно. Структуру сегмента рассматривать не будем, здесь достаточно знать, что у сегмента есть заголовок и данные. Итак, данные при прохождении через транспортный уровень обрастают заголовками. Пример (утрированный):
сверху, с TCP/IP, будут разбиты на IP-пакеты и обрастут IP-заголовками:
Такова специфика данного уровня. Для программ, работающих с сетью на прикладном уровне (SMTP, HTTP, FTP и т.д.) или на TCP, все это прозрачно: они видят просто поток данных туда и сюда, никаких пакетов, перемешивания и прочего. Наконец, канальный уровень (Ethernet) делит поток на кадры (фреймы):
Для большей наглядности всего "хаоса", который творится в сетевом стеке, я специально запихнул два IP-пакета в один Ethernet-фрейм. При приеме данных происходит обратная картина: сначала канальный уровень формирует IP-пакеты, убирая свои заголовки, затем сетевой уровень из пакетов составляет TCP-поток, после этого транспортный уровень очищает поток от своих сегментов и отдает данные в клиентское приложение:
Здесь не затронуты промежуточные уровни (например, ICMP или IpSec) и другие протоколы (например, для беспроводных или модемных соединений), не показано, как данные сжимаются, шифруются, проходят через многочисленные сетевые компоненты - прокси, маршрутизаторы и т.п. Цель картинки - показать фрагментацию данных на каждом уровне, а также обрастание заголовками и служебными данными. На этом отступление можно закончить. Часть 6-б, архитектура NET_BUFFER: need to go deeper. NET_BUFFER. Краткое определение: структура работы с данными, оптимизированная под особенности сетевого стека Windows. Ссылки: NET_BUFFER Architecture http://msdn.microsoft.com/en-u... 85%29.aspx NDIS 6 Net Buffer Lists and Net Buffers http://codemachine.com/article_ndis6nbls.html Если NET_BUFFER для вас в новинку, то прежде чем читать дальше, обязательно пройдите по ссылкам выше. При первом знакомстве NET_BUFFER производит примерно такое впечатление: - что за бред (WTF) ? - почему так завернуто, крыша поедет ведь ? - они что там, свихнулись все ? - как прочесть хотя бы первый байт данных ? - как хоть что-нибудь прочитать оттуда ? - лю-ю-ю-ди-и-и-и-и ?!?.. Да, структура сложна в эксплуатации, с этим ничего не поделаешь. Но давайте попробуем понять почему. Представьте, что драйвер сетевого адаптера (NDIS) только что принял некую порцию данных. Теперь ему нужно удалить оттуда всю служебную информацию, т.е. Ethernet-заголовки. Это, упрощенно говоря, выливается в такую операцию: "создать буфер 2, пройтись по буферу 1, копируя из него только нужную информацию в буфер 2, удалить буфер 1, отдать буфер 2 на уровень выше". Выше у нас уровень IP и там происходит то же самое: необходимо удалить IP-заголовки, дубликаты пакетов и "выпрямить" TCP-поток, а это снова создание промежуточных буферов и снова копирование. Далее "эстафету" принимает транспортный уровень и там опять наблюдается та же картина. В итоге имеем кучу лишних операций. Это отрицательно сказывается на производительности, повышает загрузку CPU и т.д. Вспомните, к примеру, загрузку файла через торрент-протокол в несколько потоков... И вот здесь на сцену выходит NET_BUFFER. NET_BUFFER организует данные в виде набора буферов, соединенных в систему связных списков. Сами данные никуда не копируются и не перемещаются, если только в этом нет острой необходимости. Когда нужно удалить или переместить часть данных, в NET_BUFFER просто двигаются соответствующие указатели. То же самое происходит, если требуется дописать что-то "сбоку". Вставить что-нибудь в середину данных ? Не проблема. Ну, может быть, придется перевыделить и скопировать парочку буферов справа и слева, но это все равно намного лучше, чем выделять один большой буфер и снова выполнять дорогие операции копирования. При движении данных с уровня на уровень заголовки не уничтожаются физически, просто указатели в NET_BUFFER сдвигаются так, чтобы заголовков не было видно. В этой оптимизации и есть смысл NET_BUFFER:
только указатели на буферы (P1, P2 и т.д.) и их позиции. Перед тем, как пойти дальше, следует познакомиться с еще одной структурой.
10
|
||||||||||||||||||||||||||
|
Ушел с форума
|
|
| 20.11.2014, 22:44 [ТС] | |
|
Часть 6-в, NET_BUFFER: Memory Descriptor List (MDL).
NET_BUFFER опирается на структуру MDL (Memory Descriptor List), вы должны представлять себе, что это такое, хотя бы в общих чертах. Я очень надеюсь, что вы знакомы с устройством виртуальной памяти и адресного пространства в Windows, иначе дальнейшее чтение вряд ли имеет смысл. Начать знакомство можно отсюда: Преодолевая ограничения Windows: виртуальная память http://blogs.technet.com/b/mar... 82311.aspx Преодолевая ограничения Windows: физическая память http://blogs.technet.com/b/mar... 51288.aspx Преодолевая ограничения Windows: выгружаемый и невыгружаемый пулы http://blogs.technet.com/b/mar... 36407.aspx Virtual address spaces http://msdn.microsoft.com/en-u... 85%29.aspx About Memory Management http://msdn.microsoft.com/en-u... 85%29.aspx Memory Management for Windows Drivers http://msdn.microsoft.com/en-u... 85%29.aspx MDL описывает физические страницы памяти и соответствующие им виртуальные адреса. По сути, это мощнейший инструмент для работы с памятью и разного рода "выкрутасов". Например, можно сделать отображение одной и той же физической страницы памяти на разные виртуальные адреса, можно с помощью отображения писать в память, доступную только для чтения, можно "залочить" в памяти пользовательский буфер, находящийся в user mode, и затем работать с ним в контексте любого потока и на любом IRQL... MDL могут соединяться в цепочки (MDL chain). В общем, что говорить, лучше один раз прочитать и несколько раз попробовать: Master of the Obvious -- MDLs are Lists that Describe Memory http://www.osronline.com/article.cfm?id=423 What Is Really in That MDL? http://msdn.microsoft.com/en-u... 85%29.aspx Using MDLs http://msdn.microsoft.com/en-u... 85%29.aspx Несколько типичных функций, так или иначе связанных с MDL: IoAllocateMdl - создает новый MDL для указанного буфера. MmBuildMdlForNonPagedPool - "заполняет" MDL. MmProbeAndLockPages - блокирует буфер в памяти, предотвращая его возможную выгрузку на диск (paging), также проверяет права доступа. MmMapLockedPagesSpecifyCache - создает отображение физических страниц, описанных MDL, на виртуальный адрес. MmProtectMdlSystemAddress - позволяет изменять защиту страниц. MmGetSystemAddressForMdlSafe - возвращает ядерный указатель на память, которую описывает MDL. Если это еще не сделано, создает отображение буфера на ядерные адреса. MmGetMdlByteCount, MmGetMdlByteOffset, MmGetMdlVirtualAddress - вспомогательные функции для получения различной информации из MDL.
10
|
|
|
Ушел с форума
|
||
| 20.11.2014, 22:48 [ТС] | ||
|
Часть 6-г, NET_BUFFER: финал.
Ну а теперь мы подошли к тому, ради чего написана эта часть. Итак, на двоичном уровне архитектура NET_BUFFER представляет собой связный список объектов NET_BUFFER_LIST, каждый из которых может иметь связный список объектов NET_BUFFER, каждый из которых может иметь связный список MDL, каждый из которых описывает конкретный буфер в памяти, включая размер полезной нагрузки и ее смещение от начала буфера. Не слабо, да ? Написанное выше лучше проиллюстрировать графически: (картинка позаимствована с сайта CodeMachine, ссылка есть выше). На самом деле, все не так страшно. Ну представьте себе какой-нибудь std::list из C++, у которого все элементы - тоже списки, а элементы этих списков - снова списки: "list<list<list<type> > > MyList;". Мудрено ? Да, пожалуй. Сложно ? Вряд ли. Чтобы прочесть все данные из NET_BUFFER_LIST, нужно написать что-то типа цикла с тройной вложенностью: на верхнем уровне обойти все NET_BUFFER_LIST, на среднем все NET_BUFFER каждого NET_BUFFER_LIST, на нижнем все MDL для каждого NET_BUFFER каждого NET_BUFFER_LIST. Используйте вспомогательные макросы NET_BUFFER_DATA_LENGTH, NET_BUFFER_NEXT_NB, NET_BUFFER_CURRENT_MDL и другие NET_BUFFER_XXXX. Вы также можете найти где-нибудь готовый код, но я крайне не советую этого делать. Во-первых, чужой, найденный неизвестно где код - почти всегда полный отстой. Со временем вы сами в этом убедитесь, и не раз. Во-вторых, написать парсер NET_BUFFER_LIST - прекрасное упражнение для ума, а написав и хорошенько протестировав его однажды, вы сможете использовать этот код в любых проектах, связанных с WFP и NDIS 6+. Добавлю, что моя версия полного разбора NET_BUFFER_LIST занимает примерно 100 строк кода. Так что не отчаивайтесь, если что ;) А "для ленивых" существует удобная и простая функция: NdisGetDataBuffer function http://msdn.microsoft.com/en-u... 85%29.aspx
лишних копирований.
15
|
||
| 20.11.2014, 22:48 | |
|
Помогаю со студенческими работами здесь
10
Windows Filtering Platform и сниффинг пакетов в соединении типа Мост Windows Filtering Platform (WFP) Windows Filtering Platform blocking ports and adresses on the c# Блокировка прокси соединения Windows Filtering Platform (WFP) краткий обзор методов спектрального оценивания Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
|||
|
Модель микоризы: классовый агентный подход 3
anaschu 06.01.2026
aa0a7f55b50dd51c5ec569d2d10c54f6/
O1rJuneU_ls
https:/ / vkvideo. ru/ video-115721503_456239114
|
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR
ФедосеевПавел 06.01.2026
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR
ВВЕДЕНИЕ
Введу сокращения:
аналоговый ПИД — ПИД регулятор с управляющим выходом в виде числа в диапазоне от 0% до. . .
|
Модель микоризы: классовый агентный подход 2
anaschu 06.01.2026
репозиторий https:/ / github. com/ shumilovas/ fungi
ветка по-частям.
коммит Create переделка под биомассу. txt
вход sc, но sm считается внутри мицелия. кстати, обьем тоже должен там считаться. . . .
|
Расчёт токов в цепи постоянного тока
igorrr37 05.01.2026
/ *
Дана цепь постоянного тока с сопротивлениями и напряжениями. Надо найти токи в ветвях.
Программа составляет систему уравнений по 1 и 2 законам Кирхгофа и решает её.
Последовательность действий:. . .
|
|
Новый CodeBlocs. Версия 25.03
palva 04.01.2026
Оказывается, недавно вышла новая версия CodeBlocks за номером 25. 03. Когда-то давно я возился с только что вышедшей тогда версией 20. 03. С тех пор я давно снёс всё с компьютера и забыл. Теперь. . .
|
Модель микоризы: классовый агентный подход
anaschu 02.01.2026
Раньше это было два гриба и бактерия. Теперь три гриба, растение.
И на уровне агентов добавится между грибами или бактериями взаимодействий.
До того я пробовал подход через многомерные массивы,. . .
|
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Programma_Boinc 28.12.2025
Советы по крайней бережливости. Внимание, это ОЧЕНЬ длинный пост.
Налог на собак: https:/ / **********/ gallery/ V06K53e
Финансовый отчет в Excel: https:/ / **********/ gallery/ bKBkQFf
Пост отсюда. . .
|
Кто-нибудь знает, где можно бесплатно получить настольный компьютер или ноутбук? США.
Programma_Boinc 26.12.2025
Нашел на реддите интересную статью под названием Anyone know where to get a free Desktop or Laptop?
Ниже её машинный перевод.
После долгих разбирательств я наконец-то вернула себе. . .
|