Мне нужно создать сессию TCP "вручную", без использования функции connect()
. Я пытался использовать сокеты RAW. Но в этом случае я получаю только копии входящих IP-пакетов. Исходные входящие пакеты проскальзывают к ядру, и оно генерирует ответный пакет ACK, который повреждает мой протокол.
Далее, вариант 2, я могу написать драйвер интерфейса виртуального eth (модуль ядра) и маршрутизировать входящий трафик на него с помощью iptables. Но на аппарате стоит пропатченное неоригинальное (не ванильное) ядро. Нормальная связка модуля с ядром невозможна.
Вариант 3. Так же пробовал не назначать IP адрес NIC интерфейсу. В этом случае модуль сетевого уровня TCP/IP в ядре не активирован, и можно генерировать и получать произвольные IP-пакеты на канальном (ethernet) уровне, используя тип домена сокета PF_PACKET
в функции socket(). Но в это время любые другие приложения, использующие протокол TCP/IP, работать не могут.
Как можно решить эту проблему другими способами?
Было бы неплохо, если бы можно было перехватывать пакеты, идущие от сетевого интерфейса к ядру, то есть перехватывать буфер SKBuf
. Но я не знаю, как это реализовать.
@Remy Lebeau Мне нужно повторно отправить инкапсулированные TCP-пакеты, поступающие с других хостов, в виде UDP-пакета. Что-то вроде туннеля. Поэтому требуется, чтобы локальная машина действовала только как ретранслятор UDP(TCP-IP) -> IP.
Звучит как довольно странная вещь для реализации. В любом случае, вы можете использовать XDP
для перехвата исходного пакета до того, как он достигнет сетевого стека, и таким образом применить инкапсуляцию UDP.
Включено ли ядро CONFIG_VETH
(встроенное или модульное)?
Судя по всему, вы пытаетесь создать туннель. Вместо того, чтобы пытаться захватить существующий интерфейс, правильный способ создать туннель — создать новый интерфейс, используя модуль ядра или TUN/TAP. Однако туннели обычно предназначены для приема трафика, генерируемого на машине, на которой запущено программное обеспечение туннеля, или, по крайней мере, маршрутизируемого через нее. Это означает, что вам также придется настроить ядро для маршрутизации трафика в ваш туннель.
Вы можете создать новый интерфейс как TUN/TAP-интерфейс. Это похоже на виртуальный драйвер Ethernet, за исключением того, что вам не нужно писать новый модуль ядра. Он предназначен для тоннелей (отсюда и название).
Разница между TUN и TAP заключается в том, что TUN-интерфейс — это IP-интерфейс, который получает IP-пакеты от системы IP-маршрутизации ядра, а TAP-интерфейс получает Ethernet-пакеты (которые могут содержать IP-пакеты), поэтому в качестве альтернативы он может быть частью моста ( виртуальный коммутатор Ethernet, который смотрит только на заголовок Ethernet, а не на заголовок IP).
Я думаю, что для вашего сценария вам будет проще всего создать интерфейс TAP, а затем создать мост (виртуальный коммутатор Ethernet) между интерфейсом TAP и интерфейсом, к которому подключен другой хост. Ни одному из них не нужен IP-адрес — ядро с радостью пропустит трафик Ethernet-уровня, не пытаясь обработать IP-информацию в пакете. Затем ваше программное обеспечение туннеля может эмулировать хост или туннелировать к реальному хосту, или делать то, что вы хотите.
Если вы хотите, чтобы хост также мог взаимодействовать с машиной, на которой запущено программное обеспечение туннеля, не проходя через программное обеспечение туннеля, вы можете указать IP-адрес на мосту.
"Мне нужно создать сеанс TCP "вручную"" - почему? Что вы планируете реализовать, что TCP еще не обрабатывает для вас? Для меня это звучит как XY-проблема. Чего вы действительно пытаетесь достичь?