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

Я пытаюсь создать виртуальные сетевые устройства для тестирования и разработки многоадресных программ. Мой компьютер имеет одну сетевую карту с одним портом Ethernet, который подключен к Интернету. Мне нужен второй (виртуальная) Сетевая карта, подключенная к мосту, к которому для тестирования подключены 2 других компьютера. Другими словами:

  1. Создать виртуальную сетевую карту
  2. Создать виртуальный мост/коммутатор
  3. Подключить виртуальную сетевую карту
  4. Создайте два дополнительных виртуальных устройства NIC (для использования в качестве удаленных хостов) и подключите их к виртуальному мосту.

Насколько я понимаю, создание виртуального моста в Linux неявно создает и подключает к нему виртуальный сетевой адаптер, который доступен как сетевой интерфейс. На вопрос объясняющий это я ответил здесь(хотя могу ошибаться).

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

ip link add br0 type bridge
ip link add dum0 type dummy
ip link add dum1 type dummy
ip link set dev dum0 master br0
ip link set dev dum1 master br0
ip addr add 10.0.0.1/24 brd + dev br0
ip addr add 10.0.0.2/24 brd + dev dum0
ip addr add 10.0.0.3/24 brd + dev dum1
ip link set br0 up
ip link set dum0 up
ip link set dum1 up
ip route del 10.0.0.0/24 dev dum0
ip route del 10.0.0.0/24 dev dum1
ip route del broadcast 10.0.0.0 dev dum0
ip route del broadcast 10.0.0.0 dev dum1
ip route del broadcast 10.0.0.255 dev dum0
ip route del broadcast 10.0.0.255 dev dum1
ip route del local 10.0.0.2
ip route del local 10.0.0.3

Для удобства вы можете использовать следующее, чтобы отменить это:

ip link del dev dum1
ip link del dev dum0
ip link del dev br0

После проверки все настроено точно так же, как и с физическим оборудованием:

$ ip addr show br0
41: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 56:47:31:fd:10:c0 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.1/24 brd 10.0.0.255 scope global br0
       valid_lft forever preferred_lft forever
    inet6 fe80::5447:31ff:fefd:10c0/64 scope link
       valid_lft forever preferred_lft forever
$ ip addr show dum0
42: dum0: <BROADCAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc noqueue master br0 state UNKNOWN group default qlen 1000
    link/ether 56:47:31:fd:10:c0 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.2/24 brd 10.0.0.255 scope global dum0
       valid_lft forever preferred_lft forever
    inet6 fe80::5447:31ff:fefd:10c0/64 scope link
       valid_lft forever preferred_lft forever
$ ip addr show dum1
43: dum1: <BROADCAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc noqueue master br0 state UNKNOWN group default qlen 1000
    link/ether d2:47:c8:19:4a:60 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.3/24 brd 10.0.0.255 scope global dum1
       valid_lft forever preferred_lft forever
    inet6 fe80::d047:c8ff:fe19:4a60/64 scope link
       valid_lft forever preferred_lft forever
$ ip route show table main
10.0.0.0/24 dev br0 proto kernel scope link src 10.0.0.1
$ ip route show table local
broadcast 10.0.0.0 dev br0 proto kernel scope link src 10.0.0.1
local 10.0.0.1 dev br0 proto kernel scope host src 10.0.0.1
broadcast 10.0.0.255 dev br0 proto kernel scope link src 10.0.0.1
broadcast 127.0.0.0 dev lo proto kernel scope link src 127.0.0.1
local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1
local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1
broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1
$ ip route get to 10.0.0.1
local 10.0.0.1 dev lo src 10.0.0.1 uid 1000
    cache <local>
$ ip route get to 10.0.0.2
10.0.0.2 dev br0 src 10.0.0.1 uid 1000
    cache

... за одним исключением: MAC адрес dum0и br0одинаковый. Это беспокоит меня, потому что предполагает, что я неправильно понимаю мостовое устройство, что на самом деле это не виртуальная сетевая карта, подключенная к мостовому устройству, а какая-то странная ни мостовая, ни сетевая карта, которая не может быть используется нормально. В любом случае, я не думаю, что это мешает остальной части тестирования. Маршрутизация через фиктивные устройства также не работает.

Что касается тестирования, то я могу пропинговать любое из устройств только через петлевое устройство ( lo). Таблица маршрутизации правильно направляет пакеты через br0в dum0и dum1, но возвращает Узел назначения недоступен :

$ ping -c 2 10.0.0.1 # br0 through lo OK
PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data.
64 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=0.053 ms
64 bytes from 10.0.0.1: icmp_seq=2 ttl=64 time=0.029 ms

--- 10.0.0.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 56ms
rtt min/avg/max/mdev = 0.029/0.041/0.053/0.012 ms
$ ping -c 2 10.0.0.2 # dum0 through br0 BAD
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
From 10.0.0.1 icmp_seq=1 Destination Host Unreachable
From 10.0.0.1 icmp_seq=2 Destination Host Unreachable

--- 10.0.0.2 ping statistics ---
2 packets transmitted, 0 received, +2 errors, 100% packet loss, time 62ms
pipe 2
$ ping -c 2 -I lo 10.0.0.2 # dum0 through lo OK
ping: Warning: source address might be selected on device other than lo.
PING 10.0.0.2 (10.0.0.2) from x.x.x.x lo: 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.047 ms
64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.033 ms

--- 10.0.0.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 35ms
rtt min/avg/max/mdev = 0.033/0.040/0.047/0.007 ms

На данный момент Я действительно не знаю, что я могу делать неправильно. Я пропатчил все через мой брандмауэр.Я думаю, что единственное, что это фиктивные устройства. Я пытался исследовать, как «просто создать виртуальную сетевую карту», ​​и это меня очень разочаровало. Страница руководства ip-link(8)перечисляет буквально десятки возможных устройств, не давая абсолютно никакого представления о том, чем они отличаются друг от друга или когда вы будете их использовать. Я не могу не подчеркнуть, как усердно я пытался исследовать это, потому что это кажется достаточно простым, но очень трудно найти информацию об этом (если вы этого еще не знаете).

Я читал, что фиктивные устройства могут просто отбрасывать данные (из одного неясного источника и больше нигде), и в этом случае, возможно, они сбрасывают ARP-запросы, и я не могу найти их MAC-адрес (если это вообще необходимо в этой виртуальной конфигурации). ). Я также пытался использовать ip tuntap(отводы Linux), и это тоже не сработало, но, если я правильно понимаю, они предоставляют необработанные IP-пакеты (для туннелей) или кадры Ethernet (для ответвлений) для программы, которые запрашивают их у ядра, а в противном случае тоже удаляют все данные.

Итак, какое устройство мне нужно? Будет ли это вообще работать для тестирования многоадресных программ? Смогу ли я привязаться к адресу устройства, отправить многоадресный трафик с него, отправить его через мост и получить программой многоадресной рассылки, привязанной к другому адресу устройства? Это было довольно сложно, поэтому я ценю любую помощь и всех, кто может ее прочитать. Спасибо!

1
24.06.2020, 12:40
1 ответ

Как предложил @A.B, решение состоит в использовании нескольких сетевых пространств имен. Мы можем думать о сетевом стеке хоста как о процессе :Ввод -> Обработка -> Вывод. Linux не позволяет зацикливать исходящий поток обратно на вход, поэтому, несмотря на то, что маршрутизация в моей исходной конфигурации была правильной, пакеты были отброшены --, существует только один сетевой стек, и исходящие пакеты не могут быть повторно обработаны одним и тем же сетевым стеком.. Использование сетевых пространств имен позволяет создавать несколько сетевых стеков, которые затем могут отвечать на запросы ARP, эхо-запросы и многоадресный трафик по желанию.

Канал типа vethможет использоваться для создания пар Ethernet, так что каждое сетевое устройство vethпредставляет собой один конец канала (или, возможно, более точно, виртуальное сетевое устройство Ethernet, подключенное к одному концу Кабель Ethernet ). Один конец остается в сетевом пространстве имен по умолчанию и добавляется к виртуальному мосту, а другой добавляется в созданное сетевое пространство имен. Это позволяет общаться между пространствами имен! Вот код:

ip link add br0 type bridge mcast_snooping 1 mcast_router 2
ip netns add net0
ip link add veth0 type veth peer name veth
ip link set veth netns net0
ip link set dev veth0 master br0
ip netns add net1
ip link add veth1 type veth peer name veth
ip link set veth netns net1
ip link set dev veth1 master br0
ip addr add 10.0.0.1/24 brd + dev br0
ip link set br0 up
ip link set veth0 up
ip link set veth1 up
ip netns exec net0 ip addr add 10.0.0.2/24 brd + dev veth
ip netns exec net1 ip addr add 10.0.0.3/24 brd + dev veth
ip -all netns exec ip link set lo up
ip -all netns exec ip link set veth up

Вы можете использовать следующее, чтобы отменить это:

ip link del dev veth1
ip link del dev veth0
ip link del dev br0
ip netns del net1
ip netns del net0

При этом создается виртуальный мост(br0)и две пары виртуальных Ethernet(veth0vethи veth1veth)с добавлением устройств vethв отдельные сетевые пространства имен (до возникновения конфликтов имен. ). Здесь мы можем увидеть результат:

$ ip addr show br0
25: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 1a:96:25:a0:43:c3 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.1/24 brd 10.0.0.255 scope global br0
       valid_lft forever preferred_lft forever
    inet6 fe80::3c91:4be6:d418:e045/64 scope link 
       valid_lft forever preferred_lft forever
$ ip addr show veth0
27: veth0@if26: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br0 state UP group default qlen 1000
    link/ether 1a:96:25:a0:43:c3 brd ff:ff:ff:ff:ff:ff link-netns net0
    inet6 fe80::3c91:4be6:d418:e045/64 scope link 
       valid_lft forever preferred_lft forever
$ ip addr show veth1
29: veth1@if28: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br0 state UP group default qlen 1000
    link/ether b6:41:52:5f:ef:eb brd ff:ff:ff:ff:ff:ff link-netns net1
    inet6 fe80::b4fa:8f8c:5976:59c9/64 scope link 
       valid_lft forever preferred_lft forever

Обратите внимание, что виртуальные Ethernet-устройства в пространстве имен по умолчанию не имеют IP-адресов --они им не нужны, потому что мы маршрутизируем через мост, чтобы добраться до хостов. Мы могли бы дать им IP-адреса соответствующих vethустройств, чтобы при желании маршрутизироваться к ним напрямую, без моста. Вот что видят созданные пространства имен:

# ip netns exec net0 ip addr show veth
26: veth@if27: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 46:11:7c:77:fc:01 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.0.0.2/24 brd 10.0.0.255 scope global veth
       valid_lft forever preferred_lft forever
    inet6 fe80::4411:7cff:fe77:fc01/64 scope link 
       valid_lft forever preferred_lft forever
# ip netns exec net1 ip addr show veth
28: veth@if29: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 12:bc:a0:99:8d:43 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.0.0.3/24 brd 10.0.0.255 scope global veth
       valid_lft forever preferred_lft forever
    inet6 fe80::10bc:a0ff:fe99:8d43/64 scope link 
       valid_lft forever preferred_lft forever

Теперь попробуем пропинговать. Мы можем отслеживать кэш ARP с помощью ip neighbourи мост с помощью tcpdump, чтобы убедиться, что все работает как задумано :

.
$ ip neigh
$ ping -c 2 10.0.0.2
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=0.124 ms
64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.059 ms

--- 10.0.0.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 58ms
rtt min/avg/max/mdev = 0.059/0.091/0.124/0.033 ms
$ ip neigh
10.0.0.2 dev br0 lladdr 46:11:7c:77:fc:01 REACHABLE

С другого терминала,запущен до пинга:

# tcpdump -i br0
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on br0, link-type EN10MB (Ethernet), capture size 262144 bytes
00:54:49.536867 ARP, Request who-has 10.0.0.2 tell 10.0.0.1, length 28
00:54:49.536908 ARP, Reply 10.0.0.2 is-at 46:11:7c:77:fc:01 (oui Unknown), length 28
00:54:49.536911 IP 10.0.0.1 > 10.0.0.2: ICMP echo request, id 9342, seq 1, length 64
00:54:49.536937 IP 10.0.0.2 > 10.0.0.1: ICMP echo reply, id 9342, seq 1, length 64
00:54:50.594136 IP 10.0.0.1 > 10.0.0.2: ICMP echo request, id 9342, seq 2, length 64
00:54:50.594174 IP 10.0.0.2 > 10.0.0.1: ICMP echo reply, id 9342, seq 2, length 64

Это можно повторить из каждого сетевого пространства имен с помощью команды ip netns execс тем же результатом. Наконец, мы можем протестировать многоадресный трафик в двух пространствах имен с помощью простой socatпрограммы, прослушивающей многоадресный адрес в одном пространстве имен и отправляющей многоадресный трафик в другом :

.
# ip netns exec net0 socat PIPE \
> UDP-RECVFROM:9000,bind=239.0.0.1,ip-add-membership=239.0.0.1:veth &
[1] 9474
# echo ECHO | ip netns exec net1 socat STDIO \
> UDP-DATAGRAM:239.0.0.1:9000,bind=10.0.0.3:9000
ECHO
[1]+  Done

Типы адресовsocatPIPEи UDP-RECVFROMожидают получения дейтаграммы UDP на порту 9000, записывают ее в безымянный канал, считывают обратно из безымянного канала и отправляют обратно в виде одноадресной дейтаграммы UDP на порт 9000. на исходный IP-адрес. Типы адресов STDIOи UDP-DATAGRAMсчитывают данные из stdin, отправляют их как многоадресную дейтаграмму UDP, принимают одноадресную дейтаграмму UDP и записывают ее содержимое в stdout.

С другого терминала, запущенного до сервера:

# tcpdump -i br0
dropped privs to tcpdump
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on br0, link-type EN10MB (Ethernet), capture size 262144 bytes
01:06:04.002116 ARP, Request who-has 10.0.0.3 tell 10.0.0.2, length 28
01:06:04.002129 ARP, Reply 10.0.0.3 is-at 12:bc:a0:99:8d:43 (oui Unknown), length 28
01:06:05.126134 IP 10.0.0.2 > igmp.mcast.net: igmp v3 report, 1 group record(s)
01:06:05.858118 IP 10.0.0.2 > igmp.mcast.net: igmp v3 report, 1 group record(s)
01:06:06.368349 IP 10.0.0.3.9000 > 239.0.0.1.9000: UDP, length 5
01:06:06.368499 IP 10.0.0.2.9000 > 10.0.0.3.9000: UDP, length 5
01:06:06.371106 IP 10.0.0.2 > igmp.mcast.net: igmp v3 report, 1 group record(s)
01:06:06.946105 IP 10.0.0.2 > igmp.mcast.net: igmp v3 report, 1 group record(s)

Невероятно.

1
18.03.2021, 23:24

Теги

Похожие вопросы