Чтобы завершить круг (и, надеюсь, помочь тем, кто ищет похожее решение), мы решили нашу проблему, используя libnetfilter_queue. Проблема заключалась в том, что у нас не было доступа к исходному коду приложения, иначе мы могли бы выполнить фрагментацию на уровне самого приложения.
Вот соответствующая выдержка из нашего внутреннего документа, подготовленного Шрирамом Дхарвадкаром, который также выполнял реализацию. Некоторые ссылки относятся к нашим внутренним именам приложений, но не думаю, что у вас должны возникнуть проблемы с пониманием.
Окончательное решение
Очереди NetFilter — это библиотека пользовательского пространства, предоставляющая API-интерфейсы для обработки пакетов, поставленных в очередь фильтром пакетов ядра. Приложение, желающее использовать эту функцию, должно динамически ссылаться на netfilter_queue и nfnetlink и включать необходимые заголовки из sysroot-target/usr/include/libnetfilter_queue/ и sysroot-target/usr. /include/libnfnetlink/. Требуется добавить Iptables с NFQUEUE в качестве цели. NFQUEUE — это цель iptables и ip6tables, которая делегирует решение о пакетах программному обеспечению пользовательского пространства. Например, следующее правило будет запрашивать решение для прослушивающей программы пользовательского пространства для всех пакетов, стоящих в очереди.
iptables -A INPUT -j NFQUEUE --queue-num 0
В пространстве пользователя программное обеспечение должно использовать API libnetfilter_queue для подключения к очереди 0 (по умолчанию) и получения сообщений от ядра. Затем он должен вынести вердикт пакету.
Когда пакет достигает цели NFQUEUE, он ставится в очередь в очередь, соответствующую номеру, заданному параметром --queue-num. Очередь пакетов реализована в виде связанного списка, элементом которого является пакет и метаданные (skb ядра Linux):
- Это очередь фиксированной длины, реализованная в виде связанного списка пакетов.
- Хранение пакетов, которые индексируются целым числом
- Пакет выпускается, когда пользовательское пространство выносит вердикт соответствующему целому индексу.
- Когда очередь заполнена, ни один пакет не может быть помещен в нее.
- Пользовательское пространство может читать несколько пакетов и ждать вынесения вердикта. Если очередь не заполнена, это не влияет на это поведение.
- Пакеты могут быть вынесены без порядка. Пользовательское пространство может читать пакеты 1,2,3,4 и выносить вердикт 4,2,3,1 в указанном порядке.
- Слишком медленный вердикт приведет к полной очереди. Затем ядро отбрасывает входящие пакеты вместо того, чтобы ставить их в очередь.
- Между ядром и пользовательским пространством используется протокол nfnetlink. Это протокол на основе сообщений, который не использует общую память. Когда пакет поставлен в очередь, ядро отправляет в сокет сообщение в формате nfnetlink, содержащее данные пакета и соответствующую информацию. Пользовательское пространство читает это сообщение и выносит вердикт
Логика префрагментации реализована в AvPreFragApp (новое приложение), а также в Security Broker (существующее приложение-контроллер).
В Security Broker, как только будет установлен туннель. Следующие два правила добавляются в таблицу RAW.
Для предварительной фрагментации TCP:
/usr/sbin/iptables -t raw -I ВЫВОД 1 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss 1360
Приведенное выше правило согласовывает правильный размер MSS во время трехстороннего рукопожатия. Можно с уверенностью предположить, что 1360+TCPH+IPH+ESP+IPH ‹= 1500, так что после шифрования не произойдет фрагментации.
Для предварительной фрагментации UDP:
/usr/sbin/iptables -t raw -I OUTPUT 2 -s ‹tia> -p udp -m mark ! --mark 0xbeef0000/0xffff0000 -j NFQUEUE
Вышеупомянутое правило ставит в очередь все пакеты udp с src ip как TIA (туннельный адрес) и пометкой не равной 0xbeef0000 в очередь netfilter для обработки приложением. 0xbeef0000 будет помечен AvPreFragApp на всех udp-пакетах, стоящих в очереди. Это сделано для того, чтобы избежать повторной постановки пакетов в очередь.
Приложение AvPreFrag
Приложение AvPreFragApp использует очереди сетевого фильтра для обработки пакетов, поставленных в очередь целью NFQUEUE. Как упоминалось выше, правило iptables ставит в очередь пакеты udp, имеющие TIA, поскольку src ip добавляется в брокере безопасности. Это правило добавляется при установлении туннеля и обновляется при возврате туннеля с помощью нового TIA. Таким образом, все пакеты с TIA в качестве исходного IP-адреса ставятся в очередь для обработки AvPreFragApp.
- AvPreFragApp вызывает набор API из libnetfilter_queue для настройки очереди и копирования пакета из ядра в приложение.
- При создании очереди передать адрес функции обратного вызова, которая вызывается после того, как пакет поставлен в очередь для обработки
- Необходимо установить режим NFQNL_COPY_PACKET, он копирует весь пакет из ядра в приложение.
- Дескриптор файла можно получить с помощью обработчика очереди netfilter. С помощью буфера пакетов функции recv можно получить
- При обработке пакета AvPreFragApp проверяет размер пакета. Если размер пакета ‹= 1376. Выдается вердикт ACCEPT. Также, если установлен бит DF, выдается вердикт ACCEPT.
- Если размер пакета > 1376 и бит DF не установлен, выдается вердикт DROP. Это означает, что исходный пакет отброшен. Но до этого пакет копировался бы в буфер приложения. Теперь AvPreFragApp выполняет фрагментацию в приложении. Все эти фрагменты записываются в необработанный сокет с меткой 0xbeef0000. sendmsg используется для записи пакетов в необработанный сокет
- Эти предварительно фрагментированные пакеты шифруются и инкапсулируются ESP в ядре.
Примечание. TIA: внутренний адрес туннеля, логический интерфейс IPSec.
person
Nikhil Utane
schedule
11.01.2016