
Как перенаправить порты на сервере, на котором запущен libvirt/KVM, на указанные порты виртуальных машин при использовании NAT?
Например, у хоста публичный IP 1.2.3.4. Я хочу перенаправить порт 80 на 10.0.0.1, а порт 22 на 10.0.0.2.
Я предполагаю, что мне нужно добавить правила iptables, но я не уверен, где это уместно и что именно следует указать.
Вывод iptables -L
Chain INPUT (policy ACCEPT)
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:bootps
Chain FORWARD (policy ACCEPT)
target prot opt source destination
ACCEPT all -- anywhere 10.0.0.0/24 state RELATED,ESTABLISHED
ACCEPT all -- 10.0.0.0/24 anywhere
ACCEPT all -- anywhere anywhere
REJECT all -- anywhere anywhere reject-with icmp-port-unreachable
REJECT all -- anywhere anywhere reject-with icmp-port-unreachable
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Вывод ifconfig
eth0 Link encap:Ethernet HWaddr 00:1b:fc:46:73:b9
inet addr:192.168.1.14 Bcast:192.168.1.255 Mask:255.255.255.0
inet6 addr: fe80::21b:fcff:fe46:73b9/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:201 errors:0 dropped:0 overruns:0 frame:0
TX packets:85 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:31161 (31.1 KB) TX bytes:12090 (12.0 KB)
Interrupt:17
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
inet6 addr: ::1/128 Scope:Host
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
virbr1 Link encap:Ethernet HWaddr ca:70:d1:77:b2:48
inet addr:10.0.0.1 Bcast:10.0.0.255 Mask:255.255.255.0
inet6 addr: fe80::c870:d1ff:fe77:b248/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:6 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:0 (0.0 B) TX bytes:468 (468.0 B)
Я использую Ubuntu 10.04.
решение1
Последняя стабильная версия libvirt для Ubuntu — это версия 0.7.5, в которой нет некоторых новых функций (например, скриптовых хуков и сетевых фильтров), которые упрощают автоматическую настройку сети. Тем не менее, вот как включить переадресацию портов для libvirt 0.7.5 в Ubuntu 10.04 Lucid Lynx.
Эти правила iptables должны помочь:
iptables -t nat -I PREROUTING -p tcp -d 1.2.3.4 --dport 80 -j DNAT --to-destination 10.0.0.1:80
iptables -t nat -I PREROUTING -p tcp -d 1.2.3.4 --dport 22 -j DNAT --to-destination 10.0.0.2:22
iptables -I FORWARD -m state -d 10.0.0.0/24 --state NEW,RELATED,ESTABLISHED -j ACCEPT
Конфигурация KVM NAT по умолчанию содержит правило, похожее на третье, которое я привел выше, но в нем отсутствует состояние NEW, которое необходимо для приема входящих подключений.
Если вы напишете скрипт запуска, чтобы добавить эти правила, и не будете осторожны, libvirt 0.7.5 переопределит их, вставив свои собственные. Поэтому, чтобы убедиться, что эти правила применяются правильно при запуске, вам нужно убедиться, что libvirt инициализировалдовы вставляете свои правила.
Добавьте следующие строки в /etc/rc.local перед строкой exit 0
:
(
# Make sure the libvirt has started and has initialized its network.
while [ `ps -e | grep -c libvirtd` -lt 1 ]; do
sleep 1
done
sleep 10
# Set up custom iptables rules.
iptables -t nat -I PREROUTING -p tcp -d 1.2.3.4 --dport 80 -j DNAT --to-destination 10.0.0.1:80
iptables -t nat -I PREROUTING -p tcp -d 1.2.3.4 --dport 22 -j DNAT --to-destination 10.0.0.2:22
iptables -I FORWARD -m state -d 10.0.0.0/24 --state NEW,RELATED,ESTABLISHED -j ACCEPT
) &
Вышеприведенный sleep 10
хак позволяет убедиться, что демон libvirt имел возможность инициализировать свои правила iptables, прежде чем мы добавим свои собственные. Не могу дождаться, когда они выпустят версию libvirt 0.8.3 для Ubuntu.
решение2
Есть способ настроить перенаправление портов на летукогда гость использует сетевой режим пользователя, я писал об этом здесь:
http://blog.adamspiers.org/2012/01/23/port-redirection-from-kvm-host-to-guest/
Подробности вы можете увидеть там, но для удобства вот решение, которое я нашел:
virsh qemu-monitor-command --hmp sles11 'hostfwd_add ::2222-:22'
Этот однострочный ответ намного проще других, но работает только в некоторых сценариях (сетевой стек пользовательского режима).
решение3
Более «официальный»[1] способ сделать это — создать скрипт-ловушку, как описано на сайте libvirt:
http://wiki.libvirt.org/page/Networking#Forwarding_Incoming_Connections
... в основном этот скрипт будет вызываться при загрузке гостя KVM. Сам скрипт добавит соответствующие правила iptable (похожие на ответ Айзека Сазерленда выше) с правильно добавленным состоянием соединения 'NEW'. Обратите внимание, что вы должны изменить скрипт, указав правильные значения для ваших хостов и портов.
[1] хотя в документации libvirt говорится, что это своего рода хак, поймите правильно
решение4
В Ubuntu 20.04 я создал следующий скрипт, который сохранил как /etc/libvirt/hooks/allow-portfw
(chmod +x):
#!/bin/bash
CHAIN=LIBVIRT_FWI
IPTCMD="iptables -L $CHAIN -vn"
FILTERCMD="grep -v -e Chain -e pkts -e reject-with -e DNAT"
while $IPTCMD | grep ESTABLISHED | grep -v DNAT >/dev/null
do
IF=$($IPTCMD | $FILTERCMD | awk '{print $7}' | head -n1)
NET=$($IPTCMD | $FILTERCMD | awk '{print $9}' | head -n1)
iptables -D $CHAIN -o $IF -d $NET -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -I $CHAIN 1 -o $IF -d $NET -m conntrack --ctstate DNAT,RELATED,ESTABLISHED -j ACCEPT
done
ситуация входа такова, что нам не хватает NEW, кстати, флага DNAT для цепочки FORWARDING, который создается автоматически.
sudo iptables -L LIBVIRT_FWI -vn
Chain LIBVIRT_FWI (1 references)
pkts bytes target prot opt in out source destination
1741K 2661M ACCEPT all -- * virbr0 0.0.0.0/0 192.168.122.0/24 ctstate RELATED,ESTABLISHED
38 1972 REJECT all -- * virbr0 0.0.0.0/0 0.0.0.0/0 reject-with icmp-port-unreachable
Мой скрипт добавляет флаг DNAT ко всем определениям.
Таким образом, я просто добавил переадресацию портов в iptables с помощью
iptables -A PREROUTING -i mylanIF -p tcp --dport 3389 -j DNAT --to-destination 192.168.122.110:3389
Вы можете использовать пакеты iptables-persistent
для сохранения этого состояния (но для этого вам обязательно придется удалить цепочки libvirt из дампа)
Или вы используете ufw
любой другой скрипт брандмауэра.
Мой сценарий основан на выводах из этого обращенияhttps://www.cyberciti.biz/faq/kvm-forward-ports-to-guests-vm-with-ufw-on-linux/