
¿Cómo puedo reenviar puertos en un servidor que ejecuta libvirt/KVM a puertos específicos en VM cuando uso NAT?
Por ejemplo, el host tiene una IP pública de 1.2.3.4. Quiero reenviar el puerto 80 al 10.0.0.1 y el puerto 22 al 10.0.0.2.
Supongo que necesito agregar reglas de iptables, pero no estoy seguro de dónde es apropiado y qué se debe especificar exactamente.
Salida 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
Salida de 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)
Estoy usando Ubuntu 10.04.
Respuesta1
La última versión estable de libvirt para Ubuntu es la versión 0.7.5, que no tiene algunas características más nuevas (es decir, enlaces de script y filtros de red) que facilitan la configuración automática de la red. Dicho esto, aquí se explica cómo habilitar el reenvío de puertos para libvirt 0.7.5 en Ubuntu 10.04 Lucid Lynx.
Estas reglas de iptables deberían funcionar:
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
La configuración predeterminada de KVM NAT proporciona una regla similar a la tercera que proporcioné anteriormente, pero omite el estado NUEVO, que es esencial para aceptar conexiones entrantes.
Si escribe un script de inicio para agregar estas reglas y no tiene cuidado, libvirt 0.7.5 las anula insertando las suyas propias. Entonces, para asegurarse de que estas reglas se apliquen correctamente al inicio, debe asegurarse de que libvirt se haya inicializadoantesinsertas tus reglas.
Agregue las siguientes líneas a /etc/rc.local, antes de la línea 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
) &
Lo sleep 10
anterior es un truco para asegurar que el demonio libvirt haya tenido la oportunidad de inicializar sus reglas de iptables antes de que agreguemos las nuestras. No puedo esperar hasta que lancen la versión 0.8.3 de libvirt para Ubuntu.
Respuesta2
Hay una manera de configurar la redirección de puertos sobre la marchacuando el invitado está utilizando la red en modo de usuario, escribí un blog sobre esto aquí:
http://blog.adamspiers.org/2012/01/23/port-redirection-from-kvm-host-to-guest/
Puede ver los detalles allí, pero por conveniencia, aquí está la solución que descubrí:
virsh qemu-monitor-command --hmp sles11 'hostfwd_add ::2222-:22'
Esta frase breve es mucho más fácil que las otras respuestas, pero solo funciona en algunos escenarios (pila de red en modo usuario).
Respuesta3
Una forma más "oficial"[1] de hacer esto es crear un script de enlace como se describe en el sitio web de libvirt:
http://wiki.libvirt.org/page/Networking#Forwarding_Incoming_Connections
... básicamente, este script se invocará cuando se inicie un invitado KVM. El script en sí agregará las reglas de iptable apropiadas (similar a la respuesta anterior de Isaac Sutherland) con el estado de conexión 'NUEVO' agregado correctamente. Tenga en cuenta que debe modificar el script con los valores correctos para sus hosts y puertos.
[1] aunque la documentación de libvirt dice que esto es una especie de truco, imagínate
Respuesta4
En Ubuntu 20.04 hice el siguiente script, que se guarda 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
La situación de entrada es que nos falta NUEVO por cierto. el indicador DNAT para la cadena FORWARDING, que se crea automáticamente.
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
Mi script agrega la bandera DNAT a todas las definiciones.
De esa manera, simplemente agregué el reenvío de puertos en iptables con
iptables -A PREROUTING -i mylanIF -p tcp --dport 3389 -j DNAT --to-destination 192.168.122.110:3389
Puede usar los paquetes iptables-persistent
para guardar este estado (pero seguro que debe eliminar las cadenas libvirt del volcado)
O utiliza ufw
cualquier otro script de firewall para ello.
Mi guión se basa en los hallazgos de esta dirección.https://www.cyberciti.biz/faq/kvm-forward-ports-to-guests-vm-with-ufw-on-linux/