
Como posso encaminhar portas em um servidor executando libvirt/KVM para portas especificadas em VMs, ao usar NAT?
Por exemplo, o host possui um IP público 1.2.3.4. Quero encaminhar a porta 80 para 10.0.0.1 e a porta 22 para 10.0.0.2.
Presumo que preciso adicionar regras de iptables, mas não tenho certeza de onde é apropriado e o que exatamente deve ser especificado.
Saída de 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
Saída do 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)
Estou usando o Ubuntu 10.04.
Responder1
A versão estável mais recente do libvirt para Ubuntu é a versão 0.7.5, que não possui alguns recursos mais recentes (ou seja, ganchos de script e filtros de rede) que facilitam a configuração automática da rede. Dito isto, veja como habilitar o encaminhamento de porta para libvirt 0.7.5 no Ubuntu 10.04 Lucid Lynx.
Estas regras do iptables devem resolver o problema:
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
A configuração padrão do KVM NAT fornece uma regra semelhante à terceira que forneci acima, mas omite o estado NOVO, que é essencial para aceitar conexões de entrada.
Se você escrever um script de inicialização para adicionar essas regras e não tomar cuidado, a libvirt 0.7.5 as substituirá inserindo as suas próprias. Portanto, para garantir que essas regras sejam aplicadas corretamente na inicialização, você precisa ter certeza de que a libvirt foi inicializadaantesvocê insere suas regras.
Adicione as seguintes linhas ao /etc/rc.local, antes da linha 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
) &
O sleep 10
texto acima é um truque para garantir que o daemon libvirt tenha tido a chance de inicializar suas regras de iptables antes de adicionarmos as nossas. Mal posso esperar até que eles lancem a versão 0.8.3 da libvirt para Ubuntu.
Responder2
Existe uma maneira de configurar o redirecionamento de porta instantaneamentequando o convidado está usando rede em modo de usuário, escrevi sobre isso aqui:
http://blog.adamspiers.org/2012/01/23/port-redirection-from-kvm-host-to-guest/
Você pode ver os detalhes lá, mas por conveniência, aqui está a solução que descobri:
virsh qemu-monitor-command --hmp sles11 'hostfwd_add ::2222-:22'
Essa linha única é muito mais fácil do que as outras respostas, mas só funciona em alguns cenários (pilha de rede no modo de usuário).
Responder3
Uma maneira mais "oficial"[1] de fazer isso é criar um script de gancho conforme descrito no site da libvirt:
http://wiki.libvirt.org/page/Networking#Forwarding_Incoming_Connections
... basicamente, este script será invocado quando um convidado KVM for inicializado. O próprio script adicionará as regras de iptable apropriadas (semelhantes à resposta de Isaac Sutherland acima) com o estado de conexão 'NOVO' adicionado corretamente. Observe que você deve modificar o script com os valores corretos para seus hosts e portas.
[1] embora a própria documentação da libvirt diga que isso é uma espécie de hack, vai entender
Responder4
No Ubuntu 20.04 criei o seguinte script, que é salvo como /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
a situação de entrada é que estamos faltando NOVO aliás. o sinalizador DNAT para a cadeia FORWARDING, que é criada automaticamente.
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
Meu script adiciona o sinalizador DNAT a todas as definições.
Dessa forma, acabei de adicionar o portforwarding no iptables com
iptables -A PREROUTING -i mylanIF -p tcp --dport 3389 -j DNAT --to-destination 192.168.122.110:3389
Você pode usar os pacotes iptables-persistent
para salvar este estado (mas com certeza você terá que retirar as cadeias libvirt do dump)
Ou você usa ufw
qualquer outro script de firewall para isso.
Meu script é baseado nas descobertas deste endereçohttps://www.cyberciti.biz/faq/kvm-forward-ports-to-guests-vm-with-ufw-on-linux/