Дата и время публикации:
Дата и время модификации:
Проблемы и решение
1. Суть проблемы
Под капотом у GNOME Boxes находится эмулятор QEMU, которая по умолчанию "эмулирует" доступ гостевых ОС (guest) простым пробором ("passes through ", он же – в virt-manager "Пользовательский режим сети") за счет использования тех же самых возможностей доступа к Internet, что и хозяйская ОС (host) . При этом эмулятор для guest по умолчанию назначает шлюзe IP: 10.0.2.2 , но не доступен со стороны host, т.к реализуемая эмулятором QEMU локальная вычислительная сеть для guest изолирована от него по умолчанию. Поэтому , кроме доступа к IP: 127.0.0.1 своего локального узла пользователи guest не имеют, ну и разве что к ограниченному числу сети Internet. Полная схема распределения адресного пространства в эмуляторе QEMU [3.2], показана на рисунке 1.1
Рисунок 1.1, взят с wiki.qemu.org
На рисунке 1.1, кроме шлюза (Gateway) доступа к хозяйской сети (Host network) показан встроенный сервер DNS с IP:10.0.2.3 и сама Guest с IP: 10.0.2.15 , а также опционально подключаемый узел SMB c IP: 10.0.2.4, что и иллюстрирует следующий рисунок 1.2
Рисунок 1.2
На рисунке 1.1, кроме шлюза (gateway) доступа к хозяйской сети (Host network) показан встроенный сервер DNS с IP:10.0.2.3 и сама guest с IP: 10.0.2.15 , а также опционально подключаемый узел SMB с IP: 10.0.2.4. Что и иллюстрирует следующий рисунок 1.2
Как показано на рисунке 1.2, результат вывода сообщений netlink в guest команды ip -ts monitor, которая, в данном случае, выводит нам интересующую информацию к каким IP-адресам эмулятора производится обращение guest. В данном случае, к DNS серверу c IP:10.0.2.3 и шлюзу с IP:10.0.2.2. При этом, все попытки получить какую-либо активность на интерфейсах host c использованием той же ip -ts monitor потерпели неудачу.
Поэтому, чтобы обеспечить доступ к host из guest, можно воспользоваться самым простым решением использовать virbr0, настраиваемый с помощью программных средств virt-manager, но как мне кажется более полнофункциональным и интересным решением будет использовать программный сетевой интерфейс TAP, который обеспечивает на уровне ядра Linux сопряжения c канальным уровнем модели OSI [3.4], оперируя с кадрами Ethernet[3.3]
2. Решение
2.1 Создание сетевого интерфейса TAP
На стороне host в консоле набиваем небольшой скрипт gboxes-tapdev-up.sh, содержимое которого показано в листинге 2.1.1
Дамп 1.1
#!/bin/sh TAP="tap2" VIRTBR="virbr1" UID=`id -u` sudo $TUNCTL -u $UID -t $TAP 2>&1 if [ $? -eq 0 ] ; then sudo ip addr add 192.168.2.1/32 broadcast 192.168.2.255 dev $TAP if [ $? -eq 0 ] ; then sudo ip link set dev $TAP up if [ $? -eq 0 ] ; then sudo ip route add to 192.168.3.1 dev $TAP if [ $? -eq 0 ] ; then sudo brctl addif $VIRTBR $TAP echo "Success." exit 0 fi echo "Failure." exit 1 fi fi fi
Который создает с использованием команды tunctl сетевой интерфейс tap2, присваивает IP: 192.168.2.1, поднимает созданный TUN/TAP интерфейс, подключает к внутри сетевому коммутатору, выполняющий gataway, и устанавливает маршрут к шлюзу гостевого узла
В роли шлюза с гостевым узлом выступает внутри сетевой, программный коммутатор, имеющий адрес IP:192.168.2.1. Наличие же TUN/TAP интерфейса позволит другим сетям использовать его в установке маршрута.
В роли шлюза с гостевым узлом выступает внутри сетевой коммутатор, имеющий адрес 192.168.2.1, а сопряженное с ним виртуальное сетевой интерфейс TUN/TAP позволит другим сетям обеспечивать доступ через виртуальную сеть к guest. Так, например, как показано в том же листинге 2.1.1 устанавливается IP:192.168.3.1/32 на host и играющий роль шлюза уже с сетью IP:192.168.3.0/24
2.2 Настройка межсетевой ретрансляции адреса
Производить не требуется, т.к. будет создана автоматически при создании сети командой net-create в virsh, результат установки межсетевой ретрансляции адреса показан в дампе 2.2.1
Дамп 2.1.1
$ sudo iptables --list [sudo] пароль для user: Chain INPUT (policy ACCEPT) target prot opt source destination LIBVIRT_INP all -- anywhere anywhere Chain FORWARD (policy ACCEPT) target prot opt source destination LIBVIRT_FWX all -- anywhere anywhere LIBVIRT_FWI all -- anywhere anywhere LIBVIRT_FWO all -- anywhere anywhere Chain OUTPUT (policy ACCEPT) target prot opt source destination LIBVIRT_OUT all -- anywhere anywhere Chain LIBVIRT_FWI (1 references) target prot opt source destination ACCEPT all -- anywhere 192.168.2.0/24 REJECT all -- anywhere anywhere reject-with icmp-port-unreachable Chain LIBVIRT_FWO (1 references) target prot opt source destination ACCEPT all -- 192.168.2.0/24 anywhere REJECT all -- anywhere anywhere reject-with icmp-port-unreachable Chain LIBVIRT_FWX (1 references) target prot opt source destination ACCEPT all -- anywhere anywhere Chain LIBVIRT_INP (1 references) target prot opt source destination ACCEPT udp -- anywhere anywhere udp dpt:domain ACCEPT tcp -- anywhere anywhere tcp dpt:domain ACCEPT udp -- anywhere anywhere udp dpt:bootps ACCEPT tcp -- anywhere anywhere tcp dpt:67 Chain LIBVIRT_OUT (1 references) target prot opt source destination ACCEPT udp -- anywhere anywhere udp dpt:domain ACCEPT tcp -- anywhere anywhere tcp dpt:domain ACCEPT udp -- anywhere anywhere udp dpt:bootpc ACCEPT tcp -- anywhere anywhere tcp dpt:68
2.3 Настройка Gnome-boxes
Для настройки доступа host к guest в gnome-boxes необходимо остановить гостевую ОС, если она запущена, и открыть её свойства: кликнуть правой кнопки на значке гостевой машины в gnome-boxes. Затем, в открывшемся диалоге свойств guest выбрать раздел система и открыть редактор XML, который показан на рисунке 2.3.1
Рисунок 2.3.1
Так как основная конфигурация в формате XML хранится в двух директориях: основная – в $HOME/.config/libvirt/qemu , а выполняемая – в $HOME/.config/gnome-boxes, то как показала практика, лучше редактировать её в основной директории.
Но, это не безопасно, потому что Gnome Boxes является графическим интерфейсом, сходной с virt-manager, который может и должен быть использован (на момент написания статьи сохранение результатов редактирования конфигурации XML получался через раз) для создания, отображения доступа и управления виртуальными машинами, запускаемыми в эмуляторе QEMU и гипервизоре KVM
Поэтому несмотря на всякие смелые утверждения в сети, связка QEMU/KVM представляет собой технологию визуализации ОС GNU/Linux, управление которой легко реализуется через virt-manager, являющиеся в свою очередь частью программной надстройки Libvirt, оперирующей конфигурацией виртуальной машины в формате XML, хранимой в данном случае в директории $HOME/.config/libvirt/qemu[3.7], которую ранее назвали основной.
Особенно, virt-manager будет привычен для пользователей привыкших к диспетчеру устройств 7-x,8-x версий Windows. Пример визуализации конфигурации виртуальной машины в формате XML показан на рисунке 2.3.2
Рисунок 2.3.2
Соответственно, virt-manager имеет три режима работы виртуальной NIC, установка которых показана на рисунке 2.3.3
Рисунок 2.3.3
Как оказалось и особенно будет неприятно любителям решать проблемы по кавалерийски, что кроме быстро устанавливаемого по умолчанию "Пользовательский режим сети", остальные два режима имеют свои маленькие хитрости, несколько из которых будут показаны далее во время создания NIC в режиме "устройства моста".
2.4 Настройка "Устройства моста"
Создаем файл xml c названием libvirt-mysubnet.xml и сетевым адресом 192.168.2.0/24, содержимое которого показан в листинге 2.4.1а
Листинг 2.4.1а
<network> <name>mysubnet</name> <bridge name='virbr1'/> <forward mode="route" dev="tap2"/> <ip address='192.168.2.1' netmask='255.255.255.0'> <dhcp> <range start='192.168.2.11' end='192.168.2.11'/> </dhcp> </ip> </network> </pre>
Как показано в листинге 2.4.1, файл libvirt-mysubnet.xml содержит корневой элемент <network> виртуальной сети mysubnet, имя которой задается через подчиненный элемент <name>. Два следующих элемента <bridge> и <forward> определяют тип и режим сопряжения с физической сетью (physical network) на стороне host
Несмотря на то, что элемент <forward> является опциональным, именно его отсутствие указывает на то, что данная виртуальная изолирована от физической сети [3.15]. Поэтому этот элемент имеет всего два атрибута — 'mode' и 'dev', которые соответственно устанавливают режим работы виртуального моста и устройство на стороне host, на которое замыкается весь пробрасываемый трафик.
Так, если для атрибута 'mode' указано значение 'route' [3.16] для пробрасывания трафика будут использоваться средствами маршрутизации взамен межсетевой ретрансляции (преобразования) адреса (Network Address Translation, NAT), котрая задается значением 'nat' с использованием встроенного в ядро GNU/Linux программного межсетевого экрана iptables, как показано в листинге 2.4.1б
Листинг 2.4.1б
<network> <name>mysubnet</name> <bridge name='virbr1'/> <forward mode="nat" dev="tap2"/> <ip address='192.168.2.1' netmask='255.255.255.0'> <dhcp> <range start='192.168.2.11' end='192.168.2.11'/> </dhcp> </ip> </network> </pre>
Элемент <bridge> определяет имя виртуального сетевого устройства моста на стороне host, в данном случае созданным выше 'virbr1'
И наконец, набор элементов определяющие динамически выделяемых адресов IPv4 с опционально включаемой поддержкой DHCP. Так, элемент определяет адрес
Соответственно, внутри <ip> указывается элемент <dhcp>, а внутри него – <range>, который устанавливает начальный IP (атрибут 'start') и конечный IP (атрибут 'end'). В данном случае, будет выделятся будет один – 192.168.2.11
Далее, запускаем сеть в утилите virsh , как показано в дампе 2.4.2
Дамп 2.4.2
$ sudo virsh virsh # net-create /home/user/libvirt-mysubnet.xml Сеть centin создана из /home/user/libvirt-mysubnet.xml
Соответственно, до выхода из virsh , рекомендую выполнить команду net-list, которой должна отобразить плоды наших усилий и выдать на консоль что-то подобное, как показано в дампе 2.4.3
Дамп 2.4.3
virsh # net-list Имя Состояние Автозапуск Постоянный ----------------------------------------------- mysubnet активен no no
Далее, выполняем gboxes-tapdev-up.sh и проверяем, что все срослось, как показано в дампе 2.4.4
Дамп 2.4.4
$ brctl show bridge name bridge id STP enabled interfaces virbr1 8000.52540062969d yes tap2 $ ip a ... 31: virbr1:mtu 1500 qdisc noqueue state DOWN group default qlen 1000 link/ether 52:54:00:62:96:9d brd ff:ff:ff:ff:ff:ff inet 192.168.2.1/24 brd 192.168.2.255 scope global virbr1 valid_lft forever preferred_lft forever 32: tap2: mtu 1500 qdisc pfifo_fast master virbr1 state DOWN group default qlen 1000 link/ether b2:35:63:60:f0:33 brd ff:ff:ff:ff:ff:ff inet 192.168.2.10/32 brd 192.168.2.255 scope global tap2 valid_lft forever preferred_lft forever
Нужно выполнить еще ряд действий, чтобы избежать проблемы, связанные с доступом к внутри вычислительной сети mysubnet и прекращения запуска гостевой ОС с ошибкой, детализация которой показана в дапме 2.4.5а
Дамп 2.4.5а
... qemu-bridge-helper --br=virbr1 --fd=36: failed to communicate with bridge helper: Transport endpoint is not connected stderr=failed to create tun device: Operation not permitted ...
Исправление ошибки, показанной в дампе 2.4.5а, заключалась в дополнительной настройки запуска вспомогательного скрипта qemu-bridge-helper, который запускается во время инициализации гостевой ОС в виртуальной среде эмулятора Qemu гипервизора KVM
Первым, понадобилось установить атрибут SETUID самому вспомогательному скрипту qemu-bridge-helper, потому что в выбранной мной ОС Debain-11, на базе которого разворачивал виртуальную среду эмулятора Qemu и гипервизора KVM под управлением программы gnome-boxes этот атрибут отсутствовал, что и показано в дапме 2.4.5б
Дамп 2.4.5б
user@home2:~$ ls -al /usr/lib/qemu/qemu-bridge-helper -rwxr-xr-x 1 root root 279392 июл 18 16:14 /usr/lib/qemu/qemu-bridge-helper
Для установки атрибута SETUID, нужно выполнить команду chmod, как показано в дампе 2.4.5в
Дамп 2.4.5в
user@home2:~$ sudo chmod u+s /usr/lib/qemu/qemu-bridge-helper
Затем, так как эмулятор Qemu запускается в gnome-boxes с правами непривилегированного пользователя, создал файл /etc/qemu/bridge.conf, который участвует в реализации упрощенного реализации списка доступа непривеллигированных пользователей, что и показано в дапме 2.4.5г
Дамп 2.4.5г
user@home2:~$ echo "allow all" | sudo tee /etc/qemu/${USER}.conf user@home2:~$ echo "include /etc/qemu/${USER}.conf" | sudo tee --append /etc/qemu/bridge.conf user@home2:~$ sudo chown root:${USER} /etc/qemu/${USER}.conf user@home2:~$ sudo chmod 640 /etc/qemu/${USER}.conf
После чего, выполняем финальную настройку NIC в режиме "Устройства моста»" с помощью утилиты virt-manager, как показано на рисунке 2.4.6
Рисунок 2.4.6
В заключении нам остается лишь повторить эксперимент, который проводили в самом начале по команде ip -ts monitor all, результаты которого показано на рисунке 2.4.7
Рисунок 2.4.7
На котором видно, что шлюз с IP: 192.168.2.2 (устройство virbr0) и NIC (устройство tap2) на host с IP: 192.168.2.1 являются доступными. В то время как IP: 192.168.2.2, планируемый для использования встроенным DNS, остается недоступным, но это уже другая история.
3. Библиография
3.1 Unix & Linux. Allow VM in gnome boxes to access webserver on host
3.2 Qemu.Documentation/Networking
3.5 How to enable proxy arp on Linux 2.4
3.6 Gnome Boxes – A Front-end Tool For QEMU And KVM
3.7 Gul Raeez Gulshan. Virtual Networking in Linux
3.8 Cole Robinson. Easy qemu commandline passthrough with virt-xml
3.10 Libvirt. QEMUSwitchToLibvirt
3.11 How to access the internet from a virtual machine in gnome boxes
3.12 Configuring GNOME Boxes VMs using virt-manager
3.13 Gnome. Support Bridged Networking to enable guests accessible from LAN
3.14 How to auto-scale the display in GNOME Boxes