Контексты обработчиков TCPIP.SYS, NDIS.SYS, ...
От: Аноним  
Дата: 12.03.07 13:57
Оценка:
Вопрос по контекстам, в которых выполняются обработчики этих драйверов.

Обработчики драйвера TCPIP.SYS и аналогичных (которые указываются в DriverObject -> MajorFunction [...]) выполняются насколько мне известно в контексте потока, вызвавшего DeviceIoControl(), IoCallDriver(), ...

А вот обработчики состояния NDIS (RecieveHandler, SendHandler, RecieveCompleteHandler, SendCompleteHandler, ...) в контексте какого потока/процесса вызываются?

Возможно ли как-то узнать какой процесс/поток был инициатором запроса на соединение на NDIS-уровне?
Re: Контексты обработчиков TCPIP.SYS, NDIS.SYS, ...
От: TarasCo  
Дата: 12.03.07 14:43
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Вопрос по контекстам, в которых выполняются обработчики этих драйверов.


А>Обработчики драйвера TCPIP.SYS и аналогичных (которые указываются в DriverObject -> MajorFunction [...]) выполняются насколько мне известно в контексте потока, вызвавшего DeviceIoControl(), IoCallDriver(), ...


Это так, только для случая, когда клиентом транспортного драйвера является приложение пользовательского режима. Если клиентом является драйвер, то вызовы некоторые вызовы ( вроде TDI_CONNECT ) будут проходить в контексте процесса SYSTEM, а некоторые ( вроде TDI_SEND ) могут проходить в контексте текущего потока, обрабатывающего DPC.

А>А вот обработчики состояния NDIS (RecieveHandler, SendHandler, RecieveCompleteHandler, SendCompleteHandler, ...) в контексте какого потока/процесса вызываются?


обработчики вроде SendHandler обычно ( хотя это и не обязательно ), работают в контексте процесса, инициировавшего отправку данных, остальные — как придется. Механизм примерно таков: драйвер сетевой карты обрабатывает прерывания в своей ISR и далее инициирует DPC для дальнейшей обработки. При обработки DPC как раз и срабатывают обработчики типа RecieveHandler. DPC процедуры срабатывают как только IRQL опустится до уровня DISPATCH_LEVEL и контекст, в котором это происходит никак не связан с контекстом процесса, которому в конце-концов данные адресуются.

А>Возможно ли как-то узнать какой процесс/поток был инициатором запроса на соединение на NDIS-уровне?

Сказать, что отправка SYN пакета будет всегда происходить в контексте процесса, устанавливающего соединение, нельзя. Кроме всего прочего, процедура отправки еще зависит и от платформы и состава драйверов. Например, я могу написать NDIS фильтр, который будет отправлять все пакеты из собственного рабочего потока и всякие предположения о контексте станут неправомочными.
Да пребудет с тобою сила
Re[2]: Контексты обработчиков TCPIP.SYS, NDIS.SYS, ...
От: Аноним  
Дата: 12.03.07 15:14
Оценка:
А>>А вот обработчики состояния NDIS (RecieveHandler, SendHandler, RecieveCompleteHandler, SendCompleteHandler, ...) в контексте какого потока/процесса вызываются?

TC>обработчики вроде SendHandler обычно ( хотя это и не обязательно ), работают в контексте процесса, инициировавшего отправку данных, остальные — как придется. Механизм примерно таков: драйвер сетевой карты обрабатывает прерывания в своей ISR и далее инициирует DPC для дальнейшей обработки. При обработки DPC как раз и срабатывают обработчики типа RecieveHandler. DPC процедуры срабатывают как только IRQL опустится до уровня DISPATCH_LEVEL и контекст, в котором это происходит никак не связан с контекстом процесса, которому в конце-концов данные адресуются.


Предположим, я повесил хук на обработчики драйвера NDIS, которые будут вызваны при наступлении того или иного события. Мне нужно связать отправляемые/принимаемые пакеты, коннекты и т.п. с потоком-инициатором. Т.е. грубо говоря нужно в обработчике понять: этот ETHREAD инициировал коннект или нет?..

А>>Возможно ли как-то узнать какой процесс/поток был инициатором запроса на соединение на NDIS-уровне?

TC>Сказать, что отправка SYN пакета будет всегда происходить в контексте процесса, устанавливающего соединение, нельзя. Кроме всего прочего, процедура отправки еще зависит и от платформы и состава драйверов. Например, я могу написать NDIS фильтр, который будет отправлять все пакеты из собственного рабочего потока и всякие предположения о контексте станут неправомочными.

Так, хорошо... Я понимаю, что всё жутко сложно и вариантов 1000. Один только вопрос: ведь персональные фаеры (например, Outpost) как-то определяют процесс, инициировавший соединение на уровне NDIS! Как же они это делают???
Re[3]: Контексты обработчиков TCPIP.SYS, NDIS.SYS, ...
От: TarasCo  
Дата: 12.03.07 15:22
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Так, хорошо... Я понимаю, что всё жутко сложно и вариантов 1000. Один только вопрос: ведь персональные фаеры (например, Outpost) как-то определяют процесс, инициировавший соединение на уровне NDIS! Как же они это делают???


Они все используют двухуровневую фильтрацию. Верхний уровень ( TDI фильтр ) отслеживает выделении сетевых ресурсов ( локальные порты, запросы на соединения и.т.п ). Все эти действия происходят в контексте процесса. Затем на основе этих данных создаются фильтрующие правила для нижнего уровня ( NDIS фильтра ). Таким образом, NDIS фильтр не знает, что SYN запрос послан конкретным приложением, он лишь предполагает это на основе работы своего верхнего фильтра. В принципе, TDI фильтр можно заменить на опрос драйвера tcpip.sys ( аналог netstat в режиме ядра ), но смысл от этого не меняется.
Да пребудет с тобою сила
Re[4]: Контексты обработчиков TCPIP.SYS, NDIS.SYS, ...
От: Аноним  
Дата: 12.03.07 15:46
Оценка:
А>>ведь персональные фаеры (например, Outpost) как-то определяют процесс, инициировавший соединение на уровне NDIS! Как же они это делают???
TC>Они все используют двухуровневую фильтрацию.

Это я понял. Ну допустим NDIS-фильтр сообщает более высокоуровневому фильтру, что сейчас будет выполнен запрос туда-то. Каким же образом верхний фильтр понимает, что это запрос от одного из процессов, которого он отфильтровал ранее? Может быть возможно сопоставить по номеру локального порта, он всегда уникален?
Re[5]: Контексты обработчиков TCPIP.SYS, NDIS.SYS, ...
От: TarasCo  
Дата: 12.03.07 16:03
Оценка:
A>Каким же образом верхний фильтр понимает, что это запрос от одного из процессов, которого он отфильтровал ранее? Может быть возможно сопоставить по номеру локального порта, он всегда уникален?

Для ТСР уникален квартет: пара адресов ( локальный и удаленный ) и пара портов ( локальный и удаленный ). Именно по этим значением NDIS фильтр и считает пакеты принадлежащим определенному процессу. Он конечно может анализировать еще другие поля сетевых пакетов, чтобы предотвратить прохождение "похожих" пакетов. Например, отслеживать номера последовательностей для ТСР потока, соответствие MAC и ip и.т.д, но это не имеет отношения к разграничению доступа процессов к сети.
Да пребудет с тобою сила
Re[6]: Контексты обработчиков TCPIP.SYS, NDIS.SYS, ...
От: Аноним  
Дата: 12.03.07 16:46
Оценка:
Вот один из обработчиков NDIS:

VOID
  ProtocolSendComplete(
    IN NDIS_HANDLE  ProtocolBindingContext,
    IN PNDIS_PACKET  Packet,
    IN NDIS_STATUS Status
    );


Допустим я нахожусь внутри этого обработчика. Откуда мне здесь взять информацию о соединении Т.е. мне нужны порты и IP-адреса.
Re[7]: Контексты обработчиков TCPIP.SYS, NDIS.SYS, ...
От: TarasCo  
Дата: 12.03.07 16:50
Оценка:
В PNDIS_PACKET находится весь сетевой пакет, вместе со всеми заголовками. Форматы сетевых протоколов известны, нужно его разобрать — сначала ethernet заголовок, потом ip ( если это ip пакет ) — там адреса, потом ТСР заголовок — там порты.
Да пребудет с тобою сила
Re[8]: Контексты обработчиков TCPIP.SYS, NDIS.SYS, ...
От: Аноним  
Дата: 12.03.07 17:17
Оценка: -1
TC>В PNDIS_PACKET находится весь сетевой пакет, вместе со всеми заголовками. Форматы сетевых протоколов известны, нужно его разобрать — сначала ethernet заголовок, потом ip ( если это ip пакет ) — там адреса, потом ТСР заголовок — там порты.

Извините, я вас совсем достал наверно Я никогда не работал с NDIS, только с TDI немного. Не могли бы вы малюсенький кусочек кода дать, как это всё извлечь?
Re[9]: Контексты обработчиков TCPIP.SYS, NDIS.SYS, ...
От: Аноним  
Дата: 13.03.07 07:31
Оценка:
TC>>В PNDIS_PACKET находится весь сетевой пакет, вместе со всеми заголовками. Форматы сетевых протоколов известны, нужно его разобрать — сначала ethernet заголовок, потом ip ( если это ip пакет ) — там адреса, потом ТСР заголовок — там порты.

Подскажите хотя бы как называются эти структуры-заголовки пакетов plz
Re[10]: Контексты обработчиков TCPIP.SYS, NDIS.SYS, ...
От: TarasCo  
Дата: 13.03.07 08:33
Оценка: 5 (1)
А>Подскажите хотя бы как называются эти структуры-заголовки пакетов plz

А никак не называются. В DDK структуры сетевых пакетов не описываются. Я их задавал по необходимости сам в удобной мне форме. Найти описание того или иного протокола — не проблема. Например: http://book.itep.ru/1/intro1.htm — очень неплохой ресурс.
Да пребудет с тобою сила
Re[11]: Контексты обработчиков TCPIP.SYS, NDIS.SYS, ...
От: Аноним  
Дата: 13.03.07 10:16
Оценка:
TC>А никак не называются. В DDK структуры сетевых пакетов не описываются. Я их задавал по необходимости сам в удобной мне форме. Найти описание того или иного протокола — не проблема. Например: http://book.itep.ru/1/intro1.htm — очень неплохой ресурс.

Вот что нашёл:

Заголовки IP, TCP, UDP


Чтобы получить смещение IP и TCP заголовков из NDIS_PACKET в моём случае мне нужно сделать примерно так:

typedef struct _ETHERNET_FRAME
{
  BYTE dst [6];        // destination address
  BYTE src [6];        // source address
  USHORT type;         // frame type
}
ETHERNET_FRAME, *PETHERNET_FRAME;

typedef struct _IP4_HEADER
{
  ULONG dummy [3];     // ver, IHL, length, identification, flags, protocol, ...
  ULONG src;           // source address
  ULONG dst;           // destination address
  ULONG padding;       // padding bytes
}
IP4_HEADER, *PIP4_HEADER;

typedef struct _TCP_HEADER
{
  USHORT src_port;     // source port
  USHORT dst_port;     // destination port
  ULONG seq_num;       // sequence number
  ULONG ack_num;       // acknowledgement number
  ULONG flags;         // offset, resrvd, U, A, ..., window
  USHORT chk_sum;      // check sum
  USHORT urg_ptr;      // urgent pointer
  ULONG padding;       // padding  
}
_TCP_HEADER, *PTCP_HEADER;

...

PNDIS_PACKET packet = ...;
UINT bufcnt = 0;
PNDIS_BUFFER pnbuff = NULL;
PETHERNET_FRAME pethf = NULL;
PIP_HEADER piph = NULL;
PTCP_HEADER ptcph = NULL;

NdisQueryPacket (
  &packet,
  NULL,
  &bufcnt,
  &pnbuff,
  NULL);

pethf = (PETHERNET_FRAME) pnubff;

if (pethf -> type == FRAME_TYPE_IP4)
{
  // здесь будет адрес IP4-заголовка
  piph = pnbuff + sizeof (ETHERNET_FRAME);

  // здесь будет адрес TCP-заголовка
  ptcph = piph + sizeof (IP4_HEADER);
}


Я прав?
Re[12]: Контексты обработчиков TCPIP.SYS, NDIS.SYS, ...
От: Аноним  
Дата: 13.03.07 10:23
Оценка:
А>typedef struct _ETHERNET_FRAME
А>{
А> BYTE dst [6]; // destination address
А> BYTE src [6]; // source address
А> USHORT type; // frame type
А>}
А>ETHERNET_FRAME, *PETHERNET_FRAME;

Здесь видимо я ошибся, согласно этой схеме, надо так:

typedef struct _ETHERNET_FRAME
{
  BYTE preamble [7];   // preamble
  BYTE sfd;            // start-of-frame [SFD]
  BYTE dst [6];        // destination address [MAC]
  BYTE src [6];        // source address [MAC]
  USHORT type;         // frame type
}
ETHERNET_FRAME, *PETHERNET_FRAME;
Re[12]: Контексты обработчиков TCPIP.SYS, NDIS.SYS, ...
От: TarasCo  
Дата: 13.03.07 10:29
Оценка:
А> в моём случае мне нужно сделать примерно так ... Я прав?

На уровне псевдокода да.... Если по-настоящему, то у Вас две больших ошибки:
1. NDIS_BUFFER — это не буфер с данными, это псевдоним для широкоизвестной структуры MDL, т.е это не сам буфер — это его описатель. Чтобы получить указатель на сами данные нужно позвать NdisQueryBuffer(Safe).
2. NDIS_PACKET может ( и для случая передачи будет одназначно ) содержать несколько буферов ( цепочку ) NDIS_BUFFER. Т.е сетевой пакет фрагментирован по отношению к виртуальной памяти. NdisQueryPacket вернет только первый буфер цепочки. Затем нужно в цикле вызывать NdisGetNextBuffer для анализа последующих данных.
Да пребудет с тобою сила
Re[13]: Контексты обработчиков TCPIP.SYS, NDIS.SYS, ...
От: TarasCo  
Дата: 13.03.07 10:32
Оценка:
Здравствуйте, Аноним, Вы писали:

А>
А>typedef struct _ETHERNET_FRAME
А>{
А>  BYTE preamble [7];   // preamble
А>  BYTE sfd;            // start-of-frame [SFD]
А>  BYTE dst [6];        // destination address [MAC]
А>  BYTE src [6];        // source address [MAC]
А>  USHORT type;         // frame type
А>}
А>ETHERNET_FRAME, *PETHERNET_FRAME;
А>


Нет, Вы не ошиблись, первый вариант — правильный. Преамбула, стартовый байт ( еще тогда уже нужно помянуть и трейлер ) — все остается на уровне сетевой карты — это формат данных на уровне физического канала. Вы же получаете девственно чистый эзернет заголовок.
Да пребудет с тобою сила
Re[13]: Контексты обработчиков TCPIP.SYS, NDIS.SYS, ...
От: Аноним  
Дата: 13.03.07 10:37
Оценка:
TC>1. NDIS_BUFFER — это не буфер с данными, это псевдоним для широкоизвестной структуры MDL, т.е это не сам буфер — это его описатель. Чтобы получить указатель на сами данные нужно позвать NdisQueryBuffer(Safe).
TC>2. NDIS_PACKET может ( и для случая передачи будет одназначно ) содержать несколько буферов ( цепочку ) NDIS_BUFFER. Т.е сетевой пакет фрагментирован по отношению к виртуальной памяти. NdisQueryPacket вернет только первый буфер цепочки. Затем нужно в цикле вызывать NdisGetNextBuffer для анализа последующих данных.

1. Понятно, ну это несложно исправить. Кстати чем отличаются NdisQueryBuffer() от NdisQueryBufferSafe() ?
2. Я так понимаю, каждый из буферов в цепочке будет содержать именно кадры? Т.е. каждый буфер будет начинаться со структуры ETHERNET_FRAME и т.д. ?

Большое спасибо! А структуры я правильно описал (см. пост ниже — там немного поправил структуру кадра)? Я не очень понимаю, там нужно поле padding или нет?
Re[14]: Контексты обработчиков TCPIP.SYS, NDIS.SYS, ...
От: Аноним  
Дата: 13.03.07 10:42
Оценка:
TC>Нет, Вы не ошиблись, первый вариант — правильный. Преамбула, стартовый байт ( еще тогда уже нужно помянуть и трейлер ) — все остается на уровне сетевой карты — это формат данных на уровне физического канала. Вы же получаете девственно чистый эзернет заголовок.

Спасибо, разъяснили! А как насчёт поля padding в других заголовках? Оно нужно?
Re[15]: Контексты обработчиков TCPIP.SYS, NDIS.SYS, ...
От: Аноним  
Дата: 13.03.07 10:59
Оценка:
Кстати нашёл значения поля типа кадра:

Internet Protocol (IP) — 0x0800;
Address Resolution Protocol (ARP) — 0x0806;
AppleTalk — 0x809B;
Xerox Network System (XNS) — 0x0600;
NetWare IPX/SPX — 0x8137.


Здесь.
Re[14]: Контексты обработчиков TCPIP.SYS, NDIS.SYS, ...
От: TarasCo  
Дата: 13.03.07 11:06
Оценка:
А> чем отличаются NdisQueryBuffer() от NdisQueryBufferSafe() ?
В документации это описано. Если драйвер разрабатывается для NT >= 5.0, то рекомендуется использовать безопасный вариант NdisQueryBufferSafe

А>2. Я так понимаю, каждый из буферов в цепочке будет содержать именно кадры? Т.е. каждый буфер будет начинаться со структуры ETHERNET_FRAME и т.д. ?

Нет. NDIS_PACKET описывает один сетевой пакет. Он может быть устроен примерно так: первый буфер — заголовок эзернет, второй буфер — загловок IP, третий — заголовок UDP, четвертый — пользовательские данные. Так сделано, чтобы избежать лишних операций копирования при обработке пакета сетевым стеком.

А>А структуры я правильно описал (см. пост ниже — там немного поправил структуру кадра)? Я не очень понимаю, там нужно поле padding или нет?

обычно padding не нужен, в основном ip имеет длину заголовка 20 байт, однако иногда длина может увеличиваться за счет дополнительной информации, читайте доки . Еще совет — все описания должны быть сделаны с однобайтовым выравниванием, иначе поля разъедутся.
Да пребудет с тобою сила
Re[16]: Контексты обработчиков TCPIP.SYS, NDIS.SYS, ...
От: TarasCo  
Дата: 13.03.07 11:10
Оценка:
Могу еще добавить
IPv6 — 0xdd86
Да пребудет с тобою сила
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.