2

Я использую Linux-контейнер на основе Debian под Proxmox 4.4. У этого хоста есть пять сетевых интерфейсов (хотя в проблеме, с которой я столкнулся, участвуют только два).

Пока я захожу на этот хост, я пингую IP-адрес, связанный с eth1. То, что происходит, и то, что, я считаю, должно произойти, - это две совершенно разные вещи.

Я хочу, чтобы пакет ping вышел из eth3, где он будет направлен в eth1.

Происходит следующее: стек IP видит, что я проверяю локальный интерфейс, а затем отправляет ответ обратно в стек. Я знаю, что пакет не выходит и не возвращается по двум причинам:

  1. Захват пакета не показывает ничего, что попадает ни в eth1, ни в eth3.
  2. Задержка пинга составляет в среднем 0,013 мс. Если бы пакет выходил и возвращался, как предполагалось, задержка составляла бы около 60 мс.

Конечно, я желаю соответствующего поведения, когда я пингую IP-адрес, связанный с eth3. В этом случае я хочу, чтобы пакет вышел из eth1, где он будет направлен в eth3. К сожалению, поведение, подобное описанному выше, происходит.

Ниже я показываю статические маршруты, которые я настроил, чтобы попытаться вызвать желаемое поведение. Такие маршруты работают так, как и предполагалось, на компьютере с Windows, но они не работают в используемой мной установке Linux.

Как я могу настроить этот хост для пересылки, как предполагалось?

root@my-host:~# uname -a
Linux my-host 4.4.35-1-pve #1 SMP Fri Dec 9 11:09:55 CET 2016 x86_64 GNU/Linux
root@my-host:~#
root@my-host:~# cat /etc/debian_version
8.9
root@my-host:~#
root@my-host:~# ifconfig
eth0      Link encap:Ethernet  HWaddr xx:xx:xx:xx:xx:xx
          inet addr:192.0.2.65  Bcast:192.0.2.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:195028 errors:0 dropped:0 overruns:0 frame:0
          TX packets:12891 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:92353608 (88.0 MiB)  TX bytes:11164530 (10.6 MiB)

eth1      Link encap:Ethernet  HWaddr xx:xx:xx:xx:xx:xx
          inet addr:128.66.100.10  Bcast:128.66.100.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:816 errors:0 dropped:0 overruns:0 frame:0
          TX packets:486 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:149517 (146.0 KiB)  TX bytes:34107 (33.3 KiB)

eth2      Link encap:Ethernet  HWaddr xx:xx:xx:xx:xx:xx
          inet addr:203.0.113.1  Bcast:203.0.113.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:738 errors:0 dropped:0 overruns:0 frame:0
          TX packets:880 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:423603 (413.6 KiB)  TX bytes:94555 (92.3 KiB)

eth3      Link encap:Ethernet  HWaddr xx:xx:xx:xx:xx:xx
          inet addr:128.66.200.10  Bcast:128.66.200.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:611 errors:0 dropped:0 overruns:0 frame:0
          TX packets:182 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:43921 (42.8 KiB)  TX bytes:13614 (13.2 KiB)

eth4      Link encap:Ethernet  HWaddr xx:xx:xx:xx:xx:xx
          inet addr:198.51.100.206  Bcast:198.51.100.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:183427 errors:0 dropped:0 overruns:0 frame:0
          TX packets:83 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:85706791 (81.7 MiB)  TX bytes:3906 (3.8 KiB)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:252 errors:0 dropped:0 overruns:0 frame:0
          TX packets:252 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1
          RX bytes:22869 (22.3 KiB)  TX bytes:22869 (22.3 KiB)
root@my-host:~#
root@my-host:~# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
192.0.2.0       0.0.0.0         255.255.255.0   U     0      0        0 eth0
128.66.100.0    0.0.0.0         255.255.255.0   U     0      0        0 eth1
203.0.113.0     0.0.0.0         255.255.255.0   U     0      0        0 eth2
128.66.200.0    0.0.0.0         255.255.255.0   U     0      0        0 eth3
198.51.100.0    0.0.0.0         255.255.255.0   U     0      0        0 eth4
root@my-host:~#
root@my-host:~# route -v add 128.66.200.10/32 gw 128.66.100.1
root@my-host:~# route -v add 128.66.100.10/32 gw 128.66.200.1
root@my-host:~#
root@my-host:~# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
192.0.2.0       0.0.0.0         255.255.255.0   U     0      0        0 eth0
203.0.113.0     0.0.0.0         255.255.255.0   U     0      0        0 eth2
198.51.100.0    0.0.0.0         255.255.255.0   U     0      0        0 eth4
128.66.100.0    0.0.0.0         255.255.255.0   U     0      0        0 eth1
128.66.100.10   128.66.200.1    255.255.255.255 UGH   0      0        0 eth3
128.66.200.0    0.0.0.0         255.255.255.0   U     0      0        0 eth3
128.66.200.10   128.66.100.1    255.255.255.255 UGH   0      0        0 eth1
root@my-host:~#
root@my-host:~# ping -c 3 128.66.100.10
PING 128.66.100.10 (128.66.100.10) 56(84) bytes of data.
64 bytes from 128.66.100.10: icmp_seq=1 ttl=64 time=0.008 ms
64 bytes from 128.66.100.10: icmp_seq=2 ttl=64 time=0.014 ms
64 bytes from 128.66.100.10: icmp_seq=3 ttl=64 time=0.017 ms

--- 128.66.100.10 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1998ms
rtt min/avg/max/mdev = 0.008/0.013/0.017/0.003 ms
root@my-host:~#

Четверг, 17.08.2017, 8:12 PDT ОБНОВЛЕНИЕ

По просьбе Диркта я уточняю нашу архитектуру и причину моего вопроса.

Виртуальный хост, который является предметом этого поста (то есть хост с сетевыми интерфейсами eth1, eth3 и тремя другими сетевыми интерфейсами, не связанными с моим вопросом), используется для тестирования физической, проводной сетевой инфраструктуры TCP/IP, которую мы настроили , В частности, мы проверяем функциональность маршрутизации этой сетевой инфраструктуры TCP/IP.

У нас было два виртуальных хоста, а не один, как я описал в своем первоначальном посте. Пинг между этими двумя хостами был бы нашим тестом дыма, чтобы убедиться, что тестируемая сетевая инфраструктура TCP/IP все еще работает.

По слишком подробным причинам, наличие двух хостов затрудняло сбор журналов, которые нам нужны. Итак, мы переключились на один хост, дали ему два сетевых адаптера, настроили статические маршруты так, чтобы все, что предназначалось для сетевого адаптера 2, выходило из сетевого адаптера 1 и наоборот. Проблема в том, что, как я уже сказал, они не выходят.

Эта настройка одного хоста / двух сетевых карт работала под Windows в течение многих лет. Я не знаю, происходит ли это из-за того, что Windows сломана, и мы непреднамеренно воспользовались ошибкой, или если Windows работает нормально (то есть RFC-совместимо), и нам просто нужно правильно настроить конфигурацию на наших виртуальных машинах Linux, чтобы получить такую же поведение.

Подведем итоги и вычеркнем длинный блок текста оболочки выше:

Два интерфейса:

eth1: 128.66.100.10/24; the router on this interface's network has IP address 128.66.100.1
eth3: 128.66.200.10/24; the router on this interface's network has IP address 128.66.200.1

Соответствующие маршруты:

Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
128.66.100.0    0.0.0.0         255.255.255.0   U     0      0        0 eth1
128.66.100.10   128.66.200.1    255.255.255.255 UGH   0      0        0 eth3
128.66.200.0    0.0.0.0         255.255.255.0   U     0      0        0 eth3
128.66.200.10   128.66.100.1    255.255.255.255 UGH   0      0        0 eth1

Команда, которую я выполняю:

ping -c 3 128.66.100.10

Пункт назначения 128.66.100.10 соответствует двум из указанных выше маршрутов:

Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
128.66.100.0    0.0.0.0         255.255.255.0   U     0      0        0 eth1
128.66.100.10   128.66.200.1    255.255.255.255 UGH   0      0        0 eth3

Маршрут с самым длинным совпадением префикса:

Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
128.66.100.10   128.66.200.1    255.255.255.255 UGH   0      0        0 eth3

Я пытаюсь понять, почему, учитывая существование этого маршрута, пакет не будет выходить из eth3, проходить через нашу сетевую инфраструктуру TCP/IP, возвращаться и попадать в eth1 извне.

Стек TCP/IP, очевидно, не обращается к таблице пересылки. Как будто, когда он видит, что я пингую локально подключенный интерфейс, стек TCP/IP просто говорит: «О, это локальный интерфейс. Так что я не собираюсь консультироваться с таблицей пересылки. Вместо этого я просто отправлю эхо-ответ прямо обратно в стек ".

Является ли поведение, которое я желаю, RFC-совместимым? Если это не так, я должен отказаться от попытки. Но если он совместим с RFC, я хотел бы узнать, как настроить стек TCP/IP в Linux, чтобы разрешить такое поведение.

ПОНЕДЕЛЬНИК, 21.08.2017 ОБНОВЛЕНИЕ

Я обнаружил параметры ядра sysctl rp_filter и accept_local . Я установил их следующим образом:

root@my-host:~# cat /proc/sys/net/ipv4/conf/eth1/accept_local
1
root@my-host:~# cat /proc/sys/net/ipv4/conf/eth3/accept_local
1
root@my-host:~# cat /proc/sys/net/ipv4/conf/all/accept_local
1
root@my-host:~# cat /proc/sys/net/ipv4/conf/default/accept_local
1
root@my-host:~# cat /proc/sys/net/ipv4/conf/eth1/rp_filter
0
root@my-host:~# cat /proc/sys/net/ipv4/conf/eth3/rp_filter
0
root@my-host:~# cat /proc/sys/net/ipv4/conf/all/rp_filter
0
root@my-host:~# cat /proc/sys/net/ipv4/conf/default/rp_filter
0

Установка параметров этого ядра, перезагрузка, проверка того, что они пережили перезагрузку, и повторное тестирование не показали различий в поведении.

Обратите внимание, что my-host - это Linux-контейнер lxc, работающий под Proxmox 4.4. Я также установил rp_filter и accept_local, как показано выше, на интерфейсах гипервизора, которые соответствуют интерфейсам eth1 и eth3 на my-host.

Чтобы подвести итог моей цели, у меня есть хост Linux с двумя сетевыми картами, eth1 и eth3. Я пытаюсь пропинговать eth1, маршрутизировать пакет ping через тестируемую сетевую инфраструктуру TCP/IP и возвращаться к eth3.

Ничто из того, что я пробовал выше, не позволило мне сделать это. Как я могу это сделать?

27.08.2017 ОБНОВЛЕНИЕ

Согласно примечанию dirkt, которое я не упомянул, являются ли eth1 и eth3 чисто виртуальными или соответствуют ли они физическому интерфейсу ... eth1 и eth3 оба соответствуют одному и тому же физическому интерфейсу на гипервизоре. Намерение состоит в том, что пакет, который выходит из eth1, фактически физически покидает блок гипервизора, выходит в настоящую сеть TCP/IP и возвращается обратно.

27.08.2017 ОБНОВЛЕНИЕ № 2

По сути, я исследовал сетевые пространства имен, так как это казалось довольно многообещающим. Однако это не "просто работает".

Я использую контейнеры LXC, и кажется, что некоторые механизмы изоляции, присутствующие в контейнерах, мешают мне создать пространство имен сети. Если бы я не работал в контейнере, думаю, у меня не было бы проблем с добавлением сетевого пространства имен.

Я нахожу некоторые ссылки на выполнение этой работы в контейнерах LXC, но они довольно туманны и неясны. Пока нет, и придется на сегодня бросить полотенце ... Если у кого-то есть какие-либо предложения на этот счет, пожалуйста, сообщите ...

2 ответа2

1

(Я оставлю другой ответ из-за комментариев).

Описание задачи: При наличии одного виртуального хоста в контейнере LXC с двумя сетевыми интерфейсами eth1 и eth3 , которые находятся в разных сегментах локальной сети и внешне подключены через маршрутизаторы, как можно реализовать пинг "бумеранга", который выходит на eth3 и возвращается на eth1 (или наоборот)?

Проблема здесь в том, что ядро Linux обнаружит, что адрес назначения назначен eth1 , и попытается напрямую доставить пакеты к eth1 , даже если таблицы маршрутизации предписывают, что пакеты должны маршрутизироваться через eth3 .

Невозможно просто удалить IP-адрес из eth1 , потому что на пинг нужно ответить. Таким образом, единственное решение - как-то использовать два разных адреса (или отделить eth1 и eth3 друг от друга).

Один из способов сделать это - использовать iptables , как в этом ответе, связанном с harrymc в комментариях.

Другой способ, который я протестировал на своей машине со следующей настройкой, используя одно пространство имен сети для имитации внешней сети и два пространства имен сети для разделения IP-адресов назначения:

Routing NS     Main NS      Two NS's

+----------+                   +----------+
|   veth0b |--- veth0a ....... | ipvl0    |
| 10.0.0.1 |    10.0.0.254     | 10.0.0.2 |
|          |                   +----------+
|          |                   +----------+
|   veth1b |--- veth1a ....... | ipvl1    |
| 10.0.1.1 |    10.0.1.254     | 10.0.1.2 |
+----------+                   +----------+

На Routing NS включена переадресация. Дополнительный 10.0.*.2 адреса назначаются устройству IPVLAN , которое можно рассматривать как дополнительный IP-адрес, назначенный главному интерфейсу , к которому оно подключено. Более подробную информацию о IPVLAN, например, здесь. Создать как

ip link add ipvl0 link veth0a type ipvlan mode l2
ip link set ipvl0 netns nsx

где nsx - это новое пространство имен сети, затем в этом пространстве имен,

ip netns exec nsx ip addr add 10.0.0.2/24 dev ipvl0
ip netns exec nsx ip link set ipvl0 up
ip netns exec nsx ip route add default via 10.0.0.1 dev ipvl0

Main NS имеет следующие правила маршрутизации в дополнение к правилам по умолчанию

ip route add 10.0.0.2/32 via 10.0.1.1 dev veth1a
ip route add 10.0.1.2/32 via 10.0.0.1 dev veth0a

а затем ping 10.0.0.2 выполнит "бумеранг" в оба конца, что видно по tcpdump как на veth0a и на veth1a . Таким образом, при такой настройке все журналирование может быть выполнено из Main NS в том, что касается проверки связи и т.д., Но для более сложных тестов с nc и т.д. Могут потребоваться другие пространства имен, по крайней мере, для обеспечения получателя и т.д.

Контейнер LXC использует сетевые пространства имен (и другие пространства имен). Я не слишком знаком с контейнерами LXC, но если создание новых пространств имен внутри контейнера заблокировано, работайте извне контейнера. Сначала идентифицируйте название контейнера с

ip netns list

а затем выполните ip netns exec NAME_OF_LXC_NS ... как указано выше. Вы также можете отложить перемещение eth1 и eth3 в контейнер LXC и сначала создать две IPVLAN, а затем переместить их в контейнер. Сценарий по необходимости.

редактировать

Есть третий вариант, который работает без сетевых пространств имен. Хитрость заключается в том, чтобы использовать политику маршрутизации и дать локальному поиску более высокий ("худший") приоритет, чем обычно, и обрабатывать пакеты из сокета, привязанного к определенному интерфейсу, по-разному. Это предотвращает доставку на локальный адрес, который был основным источником проблемы.

С той же настройкой моделирования, что и выше, минус IPVLAN,

ip rule add pref 1000 lookup local
ip rule del pref 0
ip rule add pref 100 oif veth0a lookup 100
ip rule add pref 100 oif veth1a lookup 101
ip route add default dev veth0a via 10.0.0.1 table 100
ip route add default dev veth1a via 10.0.1.1 table 101

команды

ping 10.0.1.254 -I veth0a
ping 10.0.0.254 -I veth1a

правильно отправлять запросы ping. Чтобы также получить ответ ping, необходимо отключить тесты от подмены исходного кода:

echo "0" > /proc/sys/net/ipv4/conf/veth{0,1}a/rp_filter
echo "1" > /proc/sys/net/ipv4/conf/veth{0,1}a/accept_local

Я также попробовал nc или socat , но не смог заставить их работать, потому что у nc нет опций заставить слушателя отвечать на конкретное устройство, и хотя у socat есть такая опция, она не кажется иметь эффект.

Таким образом, тестирование сети за пределами пинга несколько ограничено этой настройкой.

0

Таким образом, чтобы подвести итог, у вас есть следующая конфигурация:

Host 1           Main Host            Host 2
  ethX -------- eth1   eth3 --------- ethY
       128.66.200.10   128.66.100.10

На главном хосте включена /proc/sys/net/ipv4/ip_forward , и вы хотите проверить, работает ли соединение между хостом 1 и хостом 2.

Краткое напоминание о том, как Linux обрабатывает IP-пакеты для каждого интерфейса:

Обработка пакетов в Linux

Таким образом, входящий пакет с физического уровня проходит PREROUTING входного интерфейса, затем маршрутизируется по назначению, затем проходит POSTROUTING выходного интерфейса и выходит на физический уровень. И наоборот, такие приложения, как ping отправляют пакеты в цепочку OUTPUT , затем они маршрутизируются (не показано на рисунке), затем проходят через цепочку POSTROUTING и, наконец, выходят.

Здесь я использую вход в смысле "входит в физический уровень", а выход в смысле "покидаю физический уровень".

То, что вы пытаетесь сделать, - это как-то сказать ядру Linux не обрабатывать пакеты таким образом, а вместо этого имитировать входящий пакет на eth3 с помощью ping приложения, который затем должен быть перенаправлен на eth1 , где он выходит.

Но это просто не работает: приложения отправляют пакеты через цепочку OUTPUT . Если вы заставите ping связываться с eth3 с опцией -I , Linux просто решит, что это неправильный интерфейс для пакета, и отбросит пакет. Он никогда не будет пытаться лечить этот пакет , как если бы он был ingressing в eth3

Поэтому нормальный способ справиться с этим - просто отправить пинг с хоста 1 и проверить, поступает ли он на хост 2 (и в другом направлении). Красиво, просто и легко, никаких искажений не требуется.

Поскольку "главный хост" является виртуальным, eth1 и eth3 , скорее всего, не являются реальными интерфейсами (вы не сказали). Если они являются только одним концом пары ветеринаров, легко получить другой конец и просто произвести ping на этом конце (где бы это ни было).

Если вы настаиваете на проверку все на "узловой" по каким - то причинам, вы можете пройти через некоторые искривления и мост eth3 в какой - то другой интерфейс Veth пару, а затем ping на другом конце этой Veth пары. Поскольку пакет соединен с веткой, он будет рассматриваться как входящий в eth3 , так что он делает то, что вы хотите. Но это действительно излишне сложно.

Я не знаю других способов имитации входящих пакетов.

Вы можете попробовать некоторую магию iptable , но если вы пытаетесь проверить сетевое соединение, это плохая идея: вы никогда не узнаете, что ваши правила iptables также работают для реального трафика, потому что это не то, что вы тестируете.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .