Не удается выполнить TCP-рукопожатие через NAT между двумя сетевыми адаптерами с SO_BINDTODEVICE.

Я пытаюсь подключить свой компьютер к обеим сторонам NAT (под управлением OpenWRT) и установить TCP-соединение через NAT:

  • Я запускаю DHCP-сервер на своем первом сетевом адаптере (eth0, IP-адрес 129.104.0.1) и подключаю его к WAN-порту маршрутизатора (IP-адрес 129.104.0.198).
  • Я подключаю свой Wi-Fi (wlan0, IP-адрес 192.168.1.119) к SSID маршрутизатора за NAT

Я использую python и параметр SO_BINDTODEVICE для отправки пакета между сервером (на eth0) и клиентом (на wlan0) через NAT:

Для сервера:

self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server.bind((str(self.local_ip_addr),self.handler.port))
self.server.setsockopt(socket.SOL_SOCKET,25,self.iface.name+"\0")    
self.server.listen(10)

while self.stopped() is False:
    connect = self.server.accept()[0]
    connect.settimeout(1)
    connect.close()
self.server.close()

Для клиента:

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, 25, self.iface.name + "\0")
sock.settimeout(1)
try:
    sock.connect((self.dest,self.handler.port))
    sock.close()
expect socket.timeout, socket.error as e:
    return -1

Моя проблема в том, что время ожидания соединения истекло раньше. Я подключил оба своих интерфейса, и кажется, что проблема находится на стороне клиента:

  1. wlan0 отправляет пакет TCP SYN на 129.104.0.1
  2. Пакет правильно транслируется маршрутизатором по NAT и принимается с адреса 129.104.0.198 через eth0.
  3. eth0 отвечает пакетом SYN, ACK, который корректно пересылается по NAT обратно на wlan0.
  4. wlan0 не понимает этот SYN,ACK и пытается повторно передать первый SYN-пакет

Я думаю, что это может быть как-то связано с отказом ядра linux получать пакет с адреса, принадлежащего машине, но если кто-нибудь знает, это будет очень полезно!

РЕДАКТИРОВАТЬ: я сузил его: это действительно проблема ядра, пакеты, отправленные из eth0, воспринимаются ядром как «марсиане», потому что они имеют локальный IP-адрес в качестве источника. Установка net.ipv4.conf.all.accept_local=1 не помогла, отключение net.ipv4.conf.all.rp_filter=0 тоже.


person CaptainCap    schedule 03.06.2014    source источник


Ответы (1)


После просмотра исходных кодов ядра и добавления большого количества KERNEL_WARNING мы обнаружили, откуда оно взялось: ядро ​​Linux настроено в некоторых основных дистрибутивах (Ubuntu...) для работы в качестве маршрутизатора и отбрасывания пакетов, где исходный адрес вызывает подозрение, чтобы предотвратить спуфинг (ищите «rp_filter» на https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt и RFC3704) .

Чтобы разрешить такой трафик, вы должны установить некоторые переменные на вашем компьютере (как root):

sysctl -w net.ipv4.conf.all.accept_local=1
sysctl -w net.ipv4.conf.all.rp_filter=0
sysctl -w net.ipv4.conf.your_nic.rp_filter=0

где your_nic — сетевой интерфейс, принимающий пакет. Остерегайтесь изменять как net.ipv4.conf.all.rp_filter, так и net.ipv4.conf.your_nic.rp_filter, иначе это не сработает (ядро по умолчанию использует самые строгие настройки).

person CaptainCap    schedule 03.06.2014