как избежать маршрутизации через локальный стек в Linux - PullRequest
5 голосов
/ 16 декабря 2011

У меня есть следующая среда: 2 хоста, каждый с 2 ​​интерфейсами Ethernet, подключенными друг к другу (как на схеме ниже):

 +---------+               +---------+                     
 |      (1)+---------------+(2)      |    
 |  host1  |               |  host2  |
 |         |               |         |
 |      (3)+---------------+(4)      |
 +---------+               +---------+

Я хотел бы написать инструмент сокет клиент / сервер, который откроет обасокеты клиента и сервера на host1.Я хотел бы, чтобы клиент отправлял TCP-пакеты через интерфейс (1) и сервер прослушивал интерфейс (3), эти пакеты будут проходить через host2.

Обычно Linux-стек маршрутизирует эти пакеты через локальный стек TCP / IP безотправив их на host2.

Я попытался использовать опцию SO_BINDTODEVICE для сервера и клиента, и кажется, что сервер действительно привязан к интерфейсу (3) и не прослушивает трафик localhost.Я проверил, что клиент от host1 не может быть принят, в то время как клиент от host2 делает.

К сожалению, клиентские пакеты не отправляются (даже tcpdump на интерфейсе (1) не видит пакеты) через интерфейс (1) на интерфейс (2).Конечно, маршрутизация верна (я могу пропинговать (2) из ​​(1), (4) из (1), (4) из (3) и т. Д.).

Мой вопрос: возможно ли это?быть реализованным без использования пользовательского стека TCP / IP?

Может быть, я должен попытаться изменить IP-адрес назначения (от клиента), чтобы он был из внешней сети (и затем будет отправлен с использованием шлюза по умолчанию из интерфейса (1) -interface (2)), а затем в пост-маршрутизации изменить их снова на оригинальные?Возможно ли работать такое решение?

Я пишу свое приложение на C под Debian.

Добавление некоторых дополнительных деталей и уточнений:

  1. , конечно, обе пары (1) - (2) и (3) - (4) являются разными подсетями
  2. то, чего я хочу добиться - это (1) -> (2) -> (4) -> (3)
  3. host2 - это черный ящик, поэтому я не могу установить туда ни одного перенаправителя пакетов (который откроетсяпрослушивание сокета на интерфейсе (2) и переадресация их на (3) - (4)) - это именно то, чего я хочу избежать

Основная проблема, кажется, локальная доставка.Когда я открываю сокет на host1 и хочу подключиться к сокету, то есть прослушивание другого адреса того же ядра хоста просто использует локальный стек для доставки пакетов.См. Диаграмму сетевого фильтра ниже:

 --->[1]--->[ROUTE]--->[3]--->[4]--->
             |            ^
             |            |
             |         [ROUTE]
             v            |
            [2]          [5]
             |            ^
             |            |
             v            |

Пакеты проходят через [5] NF_IP_LOCAL_OUT и [2] NF_IP_LOCAL_IN, тогда как я хочу заставить их проходить через [4].

Ответы [ 3 ]

4 голосов
/ 17 декабря 2011

Не проверено (должно работать, но я, возможно, что-то пропустил):

В Linux есть несколько таблиц маршрутизации. Таблица local содержит некоторые маршруты, которые ядро ​​автоматически добавляет для каждого IP-адреса, добавляемого к хосту. Вы можете увидеть их с помощью ip route show table local. Маршруты, помеченные как local , указывают на локальные маршруты, которые проходят через интерфейс обратной связи. Вы можете удалить этот маршрут и добавить обычный одноадресный маршрут для его замены:

ip route del table local <ip> dev <NIC>
ip route add table local <ip> dev <NIC>
ip route flush cache

Теперь ваш первый ящик попытается отправить дейтаграммы IP на этот IP-адрес, как если бы это был удаленный адрес, например, он будет использовать ARP. Таким образом, ваш 2-й ящик должен будет либо ответить на запросы ARP, если он действует как маршрутизатор или выполняет прокси-ARP, либо вам нужно будет добавить ассоциацию в кэш ARP:

arp -s <ip> <MAC>

Тогда вам, вероятно, придется отключить rp_filter на интерфейсах:

echo 0 > /proc/sys/net/ipv4/conf/<NIC>/rp_filter

Опять же, если это не сработает, вы, вероятно, могли бы что-то настроить с L2 NAT, используя ebtables .

2 голосов
/ 01 октября 2013

Для очень похожей задачи я использую такой скрипт:

ip rule add from all lookup local # add one more local table lookup rule with high pref
ip rule del pref 0 # delete default local table lookup rule
ip rout add ${ip3} via ${ip2} src ${ip1} table 100 # add correct route to some table
ip rule add from all lookup 100 pref 1000 # add rule to lookup new table before local table
0 голосов
/ 16 декабря 2011

Вы можете назначить разные подсети парам (1) - (2) и (3) - (4), и хост2 будет пересылать пакеты от (2) до (3).Клиент на хосте host1 будет подключаться по адресу (2), поэтому стек локальной сети не будет знать, что целевой сервер на самом деле тоже работает локально.

...