Почему NdisFSendNetBufferLists работает только при вызове из FilterSendNetBufferLists?

У меня есть драйвер фильтра NDIS (см. https://pastebin.com/c5r87NNw) и пользовательское приложение.

Я хочу отправить произвольный пакет с моим драйвером фильтра (в функции SendData). С помощью DbgPrint в функции FilterReceiveNetBufferLists я вижу, что получил пакет, но не могу найти пакет в WireShark.

Пока код из SendData вызывался или непосредственно вставлялся в FilterSendNetBufferLists-функцию, он работал нормально. Но теперь, когда выполнение SendData запускается приложением пользовательского пространства, оно больше не работает.

У вас есть предположения, почему это может быть?


person Gigliotti    schedule 06.09.2020    source источник


Ответы (2)


Wireshark — интересная вещь, потому что она не обязательно говорит вам точную правду. Если возможно, я предлагаю запустить Wireshark на другом ПК, что даст вам более четкое представление о том, что на самом деле было передано в сеть. (Для самой чистой перспективы: отключите аппаратную разгрузку другого ПК, особенно RSC, чтобы сетевая карта другого ПК не искажала пакеты, прежде чем вы сможете их перехватить.)

В более старых версиях Wireshark есть драйвер протокола NDIS5 с именем NPF. Этот парень сидит выше всех драйверов фильтров, поэтому обычно он не видит никакого трафика Tx. Но в качестве особой уступки в этой ситуации NDIS закольцовывает путь Tx обратно на путь Rx (с установленным флагом NDIS_NBL_FLAGS_IS_LOOPBACK_PACKET), чтобы старые драйверы, такие как NPF, могли видеть копию пакета Tx в своем пути Rx.

Недавно проект npcap преобразовал старый драйвер NPF в NDIS6 LWF с именем NPCAP. . Этот драйвер намного лучше по ряду причин, но следует иметь в виду, что как драйвер фильтра он находится где-то в стеке фильтров. Если он находится над вашим LWF, то он не увидит никаких пакетов, которые вы передаете (или модифицируете).

Проверьте с помощью !ndiskd.miniport, как выглядит wireshark на вашем компьютере: это протокол с именем NPF или драйвер фильтра с именем NPCAP. Если последнее, то выше или ниже вашего драйвера фильтра?

В любом случае, все это говорит о том, что вы не можете полностью доверять wireshark на той же машине, что и тестируемые драйверы. Лучше и проще делать захват пакетов на отдельной машине.

Что касается вашего кода, убедитесь, что ваш обработчик FilterSendNetBufferListsComplete просматривает все NBL и удаляет те, чей NET_BUFFER_LIST::SourceHandle равен вашему OriginalNdisFilterHandle. Их следует вернуть обратно в NdisFreeNetBufferList (или кэшировать для последующего повторного использования, но NDIS уже выполняет достойную работу по кэшированию). Возможно, у вас уже есть этот код, но он просто не попал в pastebin.

Я не вижу ничего, что могло бы привести к сбою Tx. Вам нужно отслеживать состояние паузы фильтра и предотвращать (или ставить в очередь) операции Tx во время паузы. Таким образом, ваша функция SendData может быть написана так:

NTSTATUS SendData(MY_FILTER *filter) {
    if (!ExAcquireRundownProtection(&filter->PauseRundown)) {
        return STATUS_NDIS_PAUSED;
    }

    . . . allocate and send NBL . . .;

    return STATUS_SUCCESS;
}

void FilterSendNetBufferListsComplete(MY_FILTER *filter, NET_BUFFER_LIST *nblChain) {
    for (auto nbl = nblChain; nbl; nbl = nbl->Next) {
        if (nbl->SourceHandle == filter->NdisHandle) {
            . . . detach NBL from chain . . .;
            . . . free NBL back to NDIS . . .;
            ExReleaseRundownProtection(&filter->PauseRundown);
        }
    }
}

void FilterPause(MY_FILTER *filter) {
    ExWaitForRundownProtectionRelease(&filter->PauseRundown);
}

void FilterRestart(MY_FILTER *filter) {
    ExReInitializeRundownProtection(&filter->PauseRundown);
}

Если вы ошибетесь, то иногда NDIS будет давать сбой при отправке пакета. Некоторые пакеты также не будут передаваться, если вам не повезет отправить их, когда путь данных приостановлен. (Исправление этого волшебным образом не приведет к тому, что пакеты всегда будут успешно передаваться — это просто будет означать, что больше не будет тихо: вы увидите STATUS_NDIS_PAUSED при попытке отправить пакет, когда сетевая карта еще не готова. )

person Jeffrey Tippet    schedule 08.09.2020
comment
Я добавил RundownProtection в свой код, и в функции SendData он не возвращал STATUS_NDIS_PAUSED. Так что ясно, что он не приостановлен. Я также посмотрел положение своего драйвера фильтра, и оказалось, что это самый верхний драйвер фильтра. Мой WireShark уже использует NPCAP. Я уже освободил свои NBL в функции FilterSendNetBufferListsComplete. - person Gigliotti; 09.09.2020
comment
Я заставил это работать: ошибка была в моем OriginalNdisFilterHandle. Я установил его в функции FilterAttach и не думал, что функция вызывается несколько раз. Из-за этого переменная имела неправильное значение. Спасибо за помощь! - person Gigliotti; 09.09.2020
comment
Отлично, рад, что работает. Согласен с вашим анализом - у вас, как правило, не так много глобального состояния в LWF (за исключением, возможно, пула NBL и устройства управления). - person Jeffrey Tippet; 10.09.2020

Я заставил это работать: ошибка была в моем OriginalNdisFilterHandle. Я установил его в функции FilterAttach и не думал, что функция вызывается несколько раз. Из-за этого переменная имела неправильное значение.

person Gigliotti    schedule 09.09.2020