Как мне естественным образом перевести заголовки уровня 3 в ядре Linux?

Мне поручили написать транслятор IPv4-IPv6 (RFC 6146) для ядра Linux. . Короче говоря, это шлюз, который стоит между сетями IPv4 и IPv6 и обеспечивает прозрачную связь между ними путем переключения заголовков пакетов и маскирования адресов.

Увидев, что в ядре есть Netfilter, фреймворк для изменения пакетов, изначально я подумал, что могу просто написать модуль Netfilter и транслировать оттуда. Я мог бы перехватить все пакеты, изменить их размер с помощью обычных операций skb_pull/skb_push, переопределить некоторые байты и, наконец, счастливо вернуть их ядру.

Как оказалось, переключение протоколов слишком экстремально для Netfilter. Поскольку код, обрабатывающий пакеты IPv4, полностью независим от кода, обрабатывающего пакеты IPv6, как предыдущий, так и последующий код модулей Netfilter предполагают, что заголовок сетевого протокола сохраняется. Поэтому, если я изменю заголовок IPv4 на заголовок IPv6, ядро ​​сойдет с ума, потому что оно будет продолжать читать заголовок, как если бы он был заголовком IPv4.

(По крайней мере, так я считаю после прочтения net/ipv4/ip_input.c; первое, что делает ядро ​​после вызова NF_HOOK, — извлекает заголовок IPv4 во время ip_rcv_finish().)

Я вижу второй вариант: вывести новый sk_buff с нуля, попросить Netfilter сделать NF_DROP исходный пакет, а затем каким-то образом отправить новый пакет.

Вот где мое ограниченное знакомство с принципами и стилем ядра застопорило меня: я хотел бы свести к минимуму неодобрение моего решения, но замена всего пакета вместо изменения его заголовков кажется неестественной, неэффективной и даже кощунственной для дизайна Netfilter. Но точно сказать не могу, хотелось бы совета опытных. Кроме того, я не вижу другого выхода.

Вопросы: Есть ли другие варианты? Какой подход был бы наиболее естественным?

Я хотел бы поддерживать все версии ядра, начиная с 2.6. Если это невозможно, новее лучше.


person Yd Ahhrk    schedule 10.10.2012    source источник
comment
Я не понимаю, как вы можете избежать замены всего пакета, поскольку вы меняете местами разные сетевые заголовки. Вам придется повторно ввести новый пакет в стек, и ожидается, что он будет иметь заголовки канала передачи данных (например, Ethernet). В любом случае NAT64 — тупой хак; пытаясь каким-то образом сделать его эффективным, вы эффективно полируете какашку. Только сначала заставь это работать.   -  person Kaz    schedule 10.10.2012


Ответы (1)


Однажды я написал, что цель ebtables состоит в том, чтобы пометить кадр Ethernet тегом VLAN. Это требовало сдвига и изменения заголовка Ethernet перед данными кадра. Так что он делает то же самое, но на более низком уровне. skb может быть увеличен в начале на месте (по крайней мере, в большинстве случаев, я думаю), поэтому производительность должна быть в порядке.

Прямая ссылка: http://goo.gl/3DPEB

Это «008-ebt-vlan_t-0.1.diff.bz2» в:

http://goo.gl/S1tVv

Обратите внимание, что я не занимался этим кодом более 4 лет, и с тех пор я не работал с сетевым кодом Linux. Тем временем Ebtables был объединен с netfilter, насколько мне известно. Но я думаю, что базовый подход все еще должен работать и может вам помочь.

person dpc.pw    schedule 10.10.2012
comment
Я мог бы вкладывать слова в ваши уста; позвольте мне посмотреть, правильно ли я понял: используя ebtables (уровень 2), а не iptables (уровень 3+), я бы изменил сетевой заголовок до того, как кадр достигнет сетевого уровня ядра. Таким образом, в первую очередь не было бы необходимости в переносе конвейера. Опасение: Находясь на уровне 2, я не буду защищен такими функциями, как conntrack (поскольку это происходит позже), поэтому мне придется собирать фрагменты самостоятельно. На ум приходят и другие основные проверки; Мне пришлось бы переделать много вещей. Я ошибся? - person Yd Ahhrk; 11.10.2012
comment
@YdAhhrk: Вам не нужно использовать ebtables как что-то новое. На самом деле ebtables и iptables в какой-то момент были объединены в xtables и работают одинаково внутри сетевого фильтра (см. find net/netfilter | grep xt_). Я считаю, что смещение будет работать в любой точке крючков netfilter. Каждому skb выделяется некоторое пространство до и после данных skb на случай, если Linux потребуется добавить что-то еще. - person dpc.pw; 11.10.2012
comment
Я думаю, что мы немного рассинхронизированы :/. Добавить заголовки относительно просто, потому что это не слишком сильно влияет на фундаментальные предположения ядра (например, указатели на действующий канал передачи данных и сетевые заголовки в sk_buff). Но, как оказалось, преобразование заголовков IPv4 в заголовки IPv6 считается слишком навязчивым, что является моей проблемой. Теперь я понимаю, что мой вопрос может быть лучше структурирован. Извините, отредактирую через минуту. - person Yd Ahhrk; 16.10.2012
comment
@YdAhhrk: В этом случае я уверен, что вы можете использовать skb, изменить его, а затем ввести в сетевой фильтр для повторной обработки. Но код, работающий с пакетом, должен каким-то образом знать, что это за протокол, через некоторые данные внутри skb, и вам, вероятно, потребуется изменить больше вещей, чем просто необработанные данные skb. Тщательная отладка и понимание того, что идет не так и где должно помочь. - person dpc.pw; 18.10.2012
comment
Тогда еще один голос за повторную инъекцию. Я оставлю вопрос открытым еще на неделю; если это больше не привлечет мнений, я приму этот ответ. - person Yd Ahhrk; 23.10.2012