× К оглавлению На главную Об авторе

   Дата и время публикации:

Проблемы и решение

1. Суть проблем

В случае, если узел виртуальной машины имеет два подключения к физической сети центрального узла гипервизора через устанавливаемые эмулятором Qemu связки сетевых интерфейсов eth0 → tap1 и eth1 → tap2, которые образуют две подсети с ip:192.168.7.0/24 и ip:192.168.8.0/24 соответственно, может иметь место путиница при передачи и приеме пакетов , как показано в дапме 1.1

Дамп 1.1

user@kvm-host:~$ sudo tcpdump -i any host 192.168.7.1 or host 192.168.7.2
tcpdump: data link type LINUX_SLL2
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes

19:50:56.246215 tap2  In  IP 192.168.7.2 > 192.168.2.10: ICMP echo request, id 36866, seq 0, length 64
19:50:56.246279 tap1  Out IP 192.168.7.1 > 192.168.7.2: ICMP 192.168.2.10 protocol 1 port 40584 unreachable, length 92

В дампе 1.1 показано, что при попытке передать ICMP-пакет на узел с ip:192.168.2.10, указанный пакет был передан по связке eth0 → tap2, а ответ о не найденом адресе (или порта) узла пришел на связку tap1 → eth1 c соответствующими ip:192.168.7.1 / 192.168.7.2

Маршрутизация и связка сетевых интерфейсов eth0 → tap1 и eth1 → tap2 эмулятором Qemu/KVM, конфигурация которой устанавливалась в соответствие с рецептом мультиподжерки сетевых устройств виртуальной машины "ВМ ОС Yocto/poky". Кроме того, настройка подсети с "ip:192.168.2.10", где живет узел "ВМ ОС Debian-10", осуществлялась с помощью программной надстройки libvirt, которая устанавливает свои правила пакетной фильтрации (Packet filtering) и управляет продвижением пакетов (Packet forwarding) межсетевого экрана iptables / netfilter в операционной системе Linux на центральном узле гипервизора.

Движение трафика между узлами "ВМ ОС Debian-10" и "ВМ ОС Yocto/poky" по выше перечисленным интерфейсам функционально можно представить, как показано на рисунке 1.2

Рисунок 1.2

Как показано на рисунке 1.2, фактическое движение трафика от узла "ВМ ОС Debian-10" к узлу "ВМ ОС Yocto/poky" идет через интерфейсы eth0 → tap1, tap2 → eth1, virbr1, и программный межсетевой экран, который реализуется подсистемой netfilter ядра ОС GNU/Linux центрального узла гипервизора.

Конфигурация сетевых интерфейсов tap1, tap2, и virbr1 центрального узла гипервизора показана в дампе 1.3

Дамп 1.3

user@kvm-host:~$ ip a
...
5: virbr1:  mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 52:54:00:77:1d:d5 brd ff:ff:ff:ff:ff:ff
    inet 192.168.2.2/24 brd 192.168.2.255 scope global virbr1
       valid_lft forever preferred_lft forever
6: tap0:  mtu 1500 qdisc pfifo_fast master virbr1 state UNKNOWN group default qlen 1000
    link/ether fe:8b:32:5d:3c:5c brd ff:ff:ff:ff:ff:ff
    inet6 fe80::fc8b:32ff:fe5d:3c5c/64 scope link 
       valid_lft forever preferred_lft forever
7: tap1:  mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether ca:07:44:b6:06:7a brd ff:ff:ff:ff:ff:ff
    inet 192.168.7.1/32 brd 192.168.7.255 scope global tap1
       valid_lft forever preferred_lft forever
    inet6 fe80::c807:44ff:feb6:67a/64 scope link 
       valid_lft forever preferred_lft forever
8: tap2:  mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether b2:35:63:60:f0:33 brd ff:ff:ff:ff:ff:ff
    inet 192.168.8.1/32 brd 192.168.8.255 scope global tap2
       valid_lft forever preferred_lft forever
    inet6 fe80::b035:63ff:fe60:f033/64 scope link 
       valid_lft forever preferred_lft forever

При этом показанная далее в дампе 1.4 маршрутизация на центральном узле гипревизора кажется на первый взгляд не совсем верной из-за путница в интерфейсах с "ВМ ОС Yocto/poky".

Дамп 1.4

$ ip route show 
...
192.168.2.0/24 dev virbr1 proto kernel scope link src 192.168.2.2 
192.168.7.2 dev tap1 scope link 
192.168.8.2 dev tap2 scope link 

И не вяжется с маршрутизацией виртуального узла "ВМ ОС Yocto/poky", показанной в дампе 1.5

Дамп 1.5

$ ip route show 
default via 192.168.7.1 dev eth0 
192.168.7.0/24 dev eth0 scope link  src 192.168.7.2 
192.168.8.0/24 dev eth1 scope link  src 192.168.8.2 

При этом нельзя утверждать, что связка tap1 → eth0 и tap2 → eth1 со стороны центрального узла гипервизора KVM не правильно установлена, потому что подтверждается отправкой ответных ICMP пакетов (выделено жирным) от узла "ВМ ОС Yocto/poky" к узлу центрального гипервизора через ip:192.168.7.1 / 192.168.7.2, интерфейсы tap1 / eth0 и ip:192.168.8.1 / 192.168.8.1, интерфейс tap2 / eth1 соответственно. При этом отправка начального ICMP-пакета производилась на стороне "ВМ ОС Yocto/poky" путем последовательного ввода команд ping -c1 192.168.8.1 и ping -c1 192.168.7.1 соответственно.

Дамп 1.6

user@kvm-host:~$ sudo tcpdump -i any host 192.168.7.1 or host 192.168.8.1
...
15:12:29.026694 tap1  In  IP 192.168.8.2 > 192.168.8.1: ICMP echo request, id 36354, seq 0, length 64
15:12:29.026750 tap2  Out IP 192.168.8.1 > 192.168.8.2: ICMP echo reply, id 36354, seq 0, length 64
...
15:12:34.567164 tap2  In  IP 192.168.7.2 > 192.168.7.1: ICMP echo request, id 36610, seq 0, length 64
15:12:34.567230 tap1  Out IP 192.168.7.1 > 192.168.7.2: ICMP echo reply, id 36610, seq 0, length 64
...

Поэтому, как показано в дампе 1.6, такая путаница затрудняет прохождение пакетов от узла "ВМ ОС Yocto/poky" до "ВМ ОС Debian-10" и завершается с отсечкой любых ICMP-пакетов, потому что в работу маршрутизации вмешивается механизм фильтрации пакетов межсетевого экрана в ядре центрального узла гипервизора, который реализован в подсистемы netfilter ядра ОС GNU/Linux и настроен на свой лад (для подсети c ip:192.168.2.0/24) программной прослойкой libvirt с помощью правил фильтрации через утилиту командной строки iptables

2. Решение

2.1 Реализация прямого канала

Производилась путем дополнения цепочек YP_FWI, YP_FWO к уже созданными ранее программной прослойкой libvirt и состоящим из последовательности цепочек LIBVIRT-{FWO,FWX,FWI, INP, OUT} таблицы filter пакетной фильтрации [3.4]. Вместе с тем, также дополняется цепочка YP_PRT, вставляемой пред уже активированной цепочки LIBVIRT_PRT в POSTROUTE таблицы nat, функционально обеспечивающие движение трафика, как показано на рисунке 2.1

Рисунок 2.1

Как показано на рисунке 2.1, для перенаправления исходящего пакета c узла "ВМ ОС Yocto/poky" на узел "ВМ ОС Debian-10" необходимо воспользоваться цепочками FORWARD и MASQUERADE бэкенда iptables, которые реализуют соответствующие политики.

Политика FORWARD через одноименную цепочку обеспечивает фильтрацию пакетов, получаемых с tap2 и с разу же перенаправляет их на virbr1 при условии, что ip-адрес источника является 192.168.7.2/32, а ip-адрес приемника находится в пуле адресов подсети, имеющей ip: 192.168.2.0/24

Это значить, что нужно определить дополнительно пользовательские цепочки YP_FWI, YP_FWO и YP_PRT к уже имеющимся и определенным libvirt в таблицах filter и nat соответственно.

Для прямого канала в цепочке YP_FWI нужно определить переход на цепочку YP_FWO, которая будет иметь необходимые правила для организации прямого канала передачи исходящего сообщения в виде ICMP-пакета. Их нужно добавить, а вернее вставить, в цепочку FORWARD, в той последовательности в какой они следуют на рисунке 2.1 и применить через фронтенд iptables, как показано в дампе 2.2

Дамп 2.2

user@kvm-host:~$sudo iptables -N YP_FWI
user@kvm-host:~$ sudo iptables -I FORWARD 2 -j YP_FWI
user@kvm-host:~$ sudo iptables -N YP_FWO
user@kvm-host:~$ sudo iptables -I FORWARD 5 -j YP_FWO

В результате , пользовательские цепочки в FORWARD должны идти в той последовательности и нумерацией в какой они показаны в листинге 2.3 и на рисунке 2.1

Дамп 2.3

...
FORWARD:
1: -A FORWARD -j LIBVIRT_FWX
2: -A FORWARD -j YP_FWI
3: -A FORWARD -j LIBVIRT_FWI
4: -A FORWARD -j LIBVIRT_FWO
5: -A FORWARD -j YP_FWO
...

Далее, нужно было определить правила для перехода по условию, когда приходит ICMP-пакет на вход tap2 , имеющего IP-адрес источника 192.168.7.2/32 и направленного к узлу-приемника в подсети c ip:192.168.2.0/24, как показано в листинге 2.4

Листинг 2.4

YP_FWI:
1: -A YP_FWI -s 192.168.7.0/24 -d 192.168.2.0/24 -i tap2 -j YP_FWO 
...

Затем, в первой позиции цепочки YP_FWO изменил (установил) правило перенаправления ICMP-пакета на нужный интерфейс, как показано в листинге 2.5

Листинг 2.5

YP_FWO:
1: -A YP_FWO -s 192.168.7.2/32 -i tap2 -o virbr1 -j ACCEPT
...

После чего, с узла "ВМ ОС Yocto/poky" послал ICMP-пакет и наблюдал в дампе 2.6 изменение количество зарегистрированных пакетов по сравнению с дампом 1.1

Дамп 2.6

user@kvm-host:~$ sudo tcpdump -i any host 192.168.7.1 or host 192.168.7.2
...
12:45:00.742026 tap2  In  IP 192.168.7.2 > 192.168.2.10: ICMP echo request, id 36610, seq 0, length 64
12:45:00.742070 virbr1 Out IP 192.168.7.2 > 192.168.2.10: ICMP echo request, id 36610, seq 0, length 64
12:45:00.742078 tap0  Out IP 192.168.7.2 > 192.168.2.10: ICMP echo request, id 36610, seq 0, length 64
12:45:00.742326 tap0  P   IP 192.168.2.10 > 192.168.7.2: ICMP echo reply, id 36610, seq 0, length 64
12:45:00.742326 virbr1 In  IP 192.168.2.10 > 192.168.7.2: ICMP echo reply, id 36610, seq 0, length 64
12:45:00.742373 virbr1 Out IP 192.168.2.2 > 192.168.2.10: ICMP 192.168.7.2 protocol 1 port 42706 unreachable, length 92
...

Казалось бы все хорошо и прекрасно, потому что канал связи наконец-то заработал в ожидаемом направлении и ICMP-пакет доставлен конечному адресату, как показано в дампе 2.6 . Но, так как речь идет об изоляции двух узлов виртуальных машин друг от друга , поэтому адресату назначения необязательно знать кто на самом деле является отправителем до того момента, когда они попали на шлюз с ip:192.168.2.2, как показано в дампе 2.7

Дамп 2.7

user@debian10-uni:~$ 
...
13:01:03.214124 IP 192.168.2.2 > 192.168.2.10: ICMP echo request, id 37890, seq 0, length 64
13:01:03.214165 IP 192.168.2.10 > 192.168.2.2: ICMP echo reply, id 37890, seq 0, length 64
13:01:03.214343 IP 192.168.2.2 > 192.168.2.10: ICMP 192.168.7.2 protocol 1 port 7282 unreachable, length 92
...

Поэтому, чтобы на узле "ВМ Debain-10" был лишь виден IP-адрес шлюза с ip:192.168.2.2, а не IP-адресом узла-инициатора "ВМ ОС Yocto/poky" с ip:192.168.7.2, мне пришлось использовать политику MASQUERADE для интерфейса virbr1

Политика MASQUERADE делает то, что она означает – скрывает все возможное, что находится за интерфейсом virbr1, являющийся шлюзом, IP-адрес которого показан в дампе 2.8, и обеспечивающий одним обратным IP-адресом последующие за ним интерфейсы узлов подсети [3.2], в данном случае "ВМ Debain-10".

Дамп 2.8

user@debian10-uni:~$ ip route show
default via 192.168.2.2 dev ens1 proto dhcp metric 100 
192.168.2.0/24 dev ens1 proto kernel scope link src 192.168.2.10 metric 100 

Поэтому изюминкой нашего десерта будет цепочка YP_PRT в POSTROUTE таблицы nat, которая создается с помощью iptables, как показано в дампе 2.9

Дамп 2.8

sudo iptables -t nat -N YP_PRT
sudo iptables -t nat -I POSTROUTING 1 -j YP_PRT
sudo iptables -t nat -I YP_PRT 1 ! -s 192.168.7.2/32 -i tap2 -j RETURN
sudo iptables -t nat -I YP_PRT 2 -d 192.168.2.0/24 -o virbr1 -j MASQUERADE

Как показано в дампе 2.9, цепочка YP_PRT содержит правила разрешения ретрансляции адреса для политики MASQUERADE или ее запрета, если полученный пакет из tap2 не содержит IP-адрес источника 192.168.7.2

2.2 Реализация обратного канала

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

Поэтому нужно реализовать пакетную фильтрацию ответного ICMP-пакета от узла "ВМ ОС Debian-10" к узлу "ВМ ОС Debian-10" через имеющийся шлюз virbr1 с использованием ранее созданных цепочек YP_ FWI и YP_ FWO, как показано на рисунке 2.9

Рисунок 2.9

Как показано на риcунке 2.9, ответный ICMP-пакет от узла "ВМ ОС Debain-10" к "ВМ ОС Yocto/poky" приходит на virbr1, который перенаправляется на tap1 в цепочке YP_ FWI с завершающий всю эту картину безусловный переход на конечную цепочку YP_FWO, правило которого показано в листинге 2.11

Листинг 2.11

YP_ FWI:
1: -A YP_FWI -s 192.168.2.10/32 -i virbr1 -o tap1 -j ACCEPT
2: -A YP_FWI -s 192.168.2.10/32 -i virbr1 -j YP_FWO
3: -A YP_FWI -s 192.168.7.0/24 -d 192.168.2.0/24 -i tap2 -j YP_FWO

Таким образом, для реализации обратного канала, чтобы восстановить обмен между узлами "ВМ ОС Debain-10" (ip:192.168.2.10) и "ВМ ОС Yocto/poky" (ip:192.168.7.2), по сути мне нужно было лишь произвести добавление (вставку) правил в цепочку YP_ FWI, обеспечивающую нужную фильтрацию (коммутацию) пакета на нужный интерфейс центрального узла гипервизора и выполнить переход на конечную цепочку YP_FWO

Дамп 2.12

user@home2:~$ sudo tcpdump -i any host 192.168.7.1 or host 192.168.7.2 or host 192.168.2.10
...
13:07:02.960013 tap2  In  IP 192.168.7.2 > 192.168.2.10: ICMP echo request, id 38914, seq 0, length 64
13:07:02.960060 virbr1 Out IP 192.168.2.2 > 192.168.2.10: ICMP echo request, id 38914, seq 0, length 64
13:07:02.960067 tap0  Out IP 192.168.2.2 > 192.168.2.10: ICMP echo request, id 38914, seq 0, length 64
13:07:02.960284 tap0  P   IP 192.168.2.10 > 192.168.2.2: ICMP echo reply, id 38914, seq 0, length 64
13:07:02.960284 virbr1 In  IP 192.168.2.10 > 192.168.2.2: ICMP echo reply, id 38914, seq 0, length 64
13:07:02.960298 tap1  Out IP 192.168.2.10 > 192.168.7.2: ICMP echo reply, id 38914, seq 0, length 64

Прохождение в оба конца ICMP пакетов с id 39938 в дампе 2.12 показывает, что набор правил, добавленный в цепочках YP_FWI, YP_FWO и YP_PRT, полностью обеспечивает обмен при существующих ошибках маршрутизации из-за путаницы эмулятором Qemu/KVM связки интерфесов eth0, eth1 на узле "ВМ ОС Yocto/poky" с интерфейсами tap1, tap2 на центральном узле гипервизора. При этом, в случае использования иных протоколов, основанных на UDP или TCP и прочих, потребуются цепочки PREROUTE и POSTROUTE таблицы nat, а вместе с ними политики DNAT и SNAT для ретрансляции сетевых адресов и портов соответственно. А политика MASQUERADE будет лишь маскировать IP-адрес источника на стороне центрального узла так, что будет казаться узел "ВМ Debain-10" общается только со своим шлюзом и более ни с кем, как показано в дампе 2.13

Дамп 2.13

...
user@debian10-uni:~$ sudo tcpdump -n -i any host 192.168.7.1 or host 192.168.7.2 or 192.168.2.10
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
...
13:07:02.236150 IP 192.168.2.2 > 192.168.2.10: ICMP echo request, id 38914, seq 0, length 64
13:07:02.236181 IP 192.168.2.10 > 192.168.2.2: ICMP echo reply, id 38914, seq 0, length 64

$ ∞ $

3. Библиография

3.1 Superuser.What is MASQUERADE made for?

3.2 Stackoverflow.How target RETURN for iptables work?

3.3 eSecureData Inc. Add a Static Route on CentOS

3.4 [libvirt] [PATCH RFC] network: Delay creating private chains until starting network