если NPF отбрасывает пакет (пакеты) это значит, что пакеты не будут перехвачены или что пакеты не будут отправлены/получены?
Пакет не будет перехвачен, но он все равно будет доставлен в остальную часть сетевого стека. Это, я полагаю, по двум причинам:
Инструменты захвата пакетов, как правило, используются для диагностики, поэтому их философия не делает хуже. Все инструменты захвата пакетов, которые я знаю, предпочтут позволить пакетам продолжать проходить мимо них, даже если они не в состоянии идти в ногу.
В частности, NPF (также известный как winpcap/wireshark) разработан таким образом, что предотвращает блокировку/отбрасывание трафика. Даже если вы захотите внести некоторые изменения в NPF, вы не сможете этого сделать. Причина в том, что NPF реализован как драйвер протокола. Как драйвер протокола, он является аналогом TCPIP и не может напрямую вмешиваться в то, что делает TCPIP. (Это маленькое чудо, что NPF даже может видеть, что передает TCPIP - это делается с помощью магии loopback уровня 2. [Не связано с loopback уровня 3, например :: 1 и 127.0.0.1 и т. д.])
В проекте nmap есть ответвление NPF, которое реализует его как драйвер фильтра NDIS. Такой драйвер способен блокировать, задерживать, перезаписывать или вводить трафик. Поэтому, если вы заинтересованы в изменении философии № 1 выше, вам следует начать с форка nmap, а не официального winpcap.
(И вообще, лично я бы порекомендовал форк nmap, даже если вам не нужно отбрасывать трафик. Драйверы-фильтры будут намного быстрее, чем драйвер протокола, переводящий сетевой адаптер в режим loopback уровня 2.)
После того, как вы просмотрите nmap-npf, вы сможете найти обратные вызовы из примера драйвера фильтра NDIS, например FilterReceiveNetBufferLists.
Отбрасывать пакеты на самом деле довольно просто ;) Однако есть некоторые подводные камни, так что давайте рассмотрим несколько примеров.
На пути передачи у нас есть связанный список NBL, и мы хотим разделить его на два списка, один для удаления и один для продолжения отправки. Один NBL может содержать несколько пакетов, но каждый пакет гарантированно относится к одному и тому же потоку (например, сокету TCP). Поэтому обычно вы можете сделать упрощающее предположение, что каждый пакет в NBL всегда обрабатывается одинаково: если вы хотите отбросить один, вы хотите отбросить их все.
Если это предположение не верно, т. е. если вы хотите выборочно отбрасывать некоторые пакеты из сокета TCP, но не все пакеты, то вам нужно сделать что-то более сложное. Вы не можете напрямую удалить один NET_BUFFER из NET_BUFFER_LIST; вместо этого вы должны клонировать NET_BUFFER_LIST и копировать NET_BUFFER, которые вы хотите сохранить.
Поскольку это бесплатный форум, я приведу пример простого и распространенного случая ;)
void
FilterSendNetBufferLists(NET_BUFFER_LIST *nblChain, ULONG sendFlags)
{
NET_BUFFER_LIST *drop = NULL;
NET_BUFFER_LIST *keep = NULL;
NET_BUFFER_LIST *next = NULL;
NET_BUFFER_LIST *nbl = NULL;
for (nbl = nblChain; nbl != NULL; nbl = next) {
next = nbl->Next;
// If the first NB in the NBL is drop-worthy, then all NBs are
if (MyShouldDropPacket(nbl->FirstNetBuffer)) {
nbl->Next = drop;
drop = nbl;
nbl->Status = NDIS_STATUS_FAILURE; // tell the protocol
} else {
nbl->Next = keep;
keep = nbl;
}
}
// Above would reverse the order of packets; let's undo that here.
keep = ReverseNblChain(keep);
. . . do something with the NBLs you want to keep. . .;
// Send the keepers down the stack to be transmitted by the NIC.
NdisFSendNetBufferLists(context, keep, portNumber, sendFlags);
// Return the dropped packets back up to whoever tried to send them.
NdisFSendCompleteNetBufferLists(context, drop, 0);
}
На пути получения вам гарантировано только один NET_BUFFER на NET_BUFFER_LIST. (Сетевая карта не может полностью знать, какие пакеты являются частью одного и того же потока, поэтому группировка еще не выполнена.) Итак, эта маленькая хитрость исчезла, но есть новая: вы должны проверить Флаг NDIS_RECEIVE_FLAGS_RESOURCES. Отсутствие проверки этого флага является причиной № 1 потери времени на поиск ошибок в драйверах фильтров, поэтому я должен придать этому большое значение.
void
FilterReceiveNetBufferLists(NET_BUFFER_LIST *nblChain, ULONG count, ULONG receiveFlags)
{
NET_BUFFER_LIST *drop = NULL;
NET_BUFFER_LIST *keep = NULL;
NET_BUFFER_LIST *next = NULL;
NET_BUFFER_LIST *nbl = NULL;
for (nbl = nblChain; nbl != NULL; nbl = next) {
next = nbl->Next;
// There's only one packet in the NBL
if (MyShouldDropPacket(nbl->FirstNetBuffer)) {
nbl->Next = drop;
drop = nbl;
count -= 1; // decrement the NumberOfNetBufferLists
} else {
nbl->Next = keep;
keep = nbl;
}
}
keep = ReverseNblChain(keep);
. . . do something with the NBLs you want to keep. . .;
// Pass the keepers up the stack to be processed by protocols.
NdisFIndicateReceiveNetBufferLists(context, keep, portNumber, count, receiveFlags);
// Checking this flag is critical; never ever call
// NdisFReturnNetBufferLists if the flag is set.
if (0 == (NDIS_RECEIVE_FLAGS_RESOURCES & receiveFlags)) {
NdisFReturnNetBufferLists(context, keep, 0);
}
}
Обратите внимание, что я использовал вспомогательную функцию под названием ReverseNblChain
. Технически допустимо менять порядок пакетов, но это снижает производительность. TCPIP может достичь максимальной производительности только тогда, когда пакеты обычно приходят по порядку. Цикл манипулирования связанным списком в примере кода имеет побочный эффект в виде обращения списка NBL, поэтому мы устраняем ущерб с помощью ReverseNblChain
. Нам не нужно переворачивать цепочку отбрасывания, поскольку никто не пытается собрать отброшенные пакеты; вы можете оставить их в любом порядке.
NET_BUFFER_LIST * ReverseNblChain(NET_BUFFER_LIST *nblChain)
{
NET_BUFFER_LIST *head = NULL;
NET_BUFFER_LIST *next = NULL;
NET_BUFFER_LIST *nbl = NULL;
for (nbl = nblChain; nbl != NULL; nbl = next) {
next = nbl->Next;
nbl->Next = head;
head = nbl;
}
return head;
}
Наконец, если вы читаете это из будущего, я предлагаю вам найти образец заголовочного файла от Microsoft с именем nblutil.h
. (Мы еще не опубликовали его, но я работаю над ним.) В нем есть очень хорошая подпрограмма с именем ndisClassifyNblChain
, которая делает почти всю работу за вас. Он предназначен для высокой масштабируемости и использует несколько приемов для повышения производительности, чем то, что вы найдете в уже слишком длинном ответе StackOverflow.
Обновление из будущего: https://github.com/microsoft/ndis-driver-library имеет NdisClassifyNblChain2
person
Jeffrey Tippet
schedule
13.04.2019