Enrutamiento Linux con dos NIC (LAN vs Internet) con NAT y puente para VM

Enrutamiento Linux con dos NIC (LAN vs Internet) con NAT y puente para VM

Mi configuración:

Sólo hay una máquina física en esta configuración, un sistema host para máquinas virtuales (VM) con dos adaptadores de red.

Una NIC (eth0) está conectada a una red interna (subred LAN, por ejemplo, 10.xxx/24) y se utilizará para el tráfico interno.

La otra NIC (eth1) está conectada a Internet pública (tiene configurada una IP pública enrutable). Esta conexión se utilizará para reenviar el tráfico de Internet público a las IP internas de las máquinas virtuales (tráfico entrante) y para permitir que las máquinas virtuales accedan a Internet pública (tráfico saliente) a través de NAT.

Las máquinas virtuales usan direcciones IP en la subred LAN (10.xxx/24, igual que eth0)

Tengo un dispositivo puente (br0) configurado para interfaces de red virtuales de las VM (vnet0, vnet1, ...) y LAN-NIC (eth0). Eso significa:

  • br0 tiene una dirección IP en la subred LAN (10.xxx/24)
  • eth0 se agrega al puente
  • vnet0, vnet1, ... (utilizados por las VM) se agregan dinámicamente al puente

Problemas

La comunicación dentro de la LAN funciona bien. Además, se puede acceder al VM-Host a través de la IP pública y tiene acceso a Internet.

Mi problema es la configuración de NAT para permitir que las máquinas virtuales también accedan a Internet pública.

Intenté utilizar una regla (S)NAT simple:

iptables -t nat -I POSTROUTING -s 10.x.x.x/24 ! -d 10.x.x.x/24 -j SNAT --to-source y.y.y.102

Mientras que yyy102 es la IP pública enrutable de la segunda NIC (eth1).

Descubrí que necesito habilitar "ip_forward" y "bridge-nf-call-iptables":

echo 1 > /proc/sys/net/ipv4/ip_forward
echo 1 > /proc/sys/net/bridge/bridge-nf-call-iptables

De lo contrario, iptables no procesará los paquetes puenteados.

Ahora los paquetes de las VM parecen pasar por las siguientes cadenas de iptables:

  • "ADELANTE" (normal) - Los acepto allí (-j ACEPTAR, el contador sube)
  • "PREROUTING" (nat): los acepto allí (política ACEPTAR, el contador sube)
  • "POSTROUTING" (nat): coinciden con la regla SNAT

Pero no todos los paquetes parecen llegar a PRE/POSTROUTING por algún motivo que no pude entender hasta ahora.

Sin embargo, lo más interesante tcpdump -i eth0es tcpdump -i eth1que los paquetes (intenté hacer ping a una IP externa desde una VM) parecen enviarse a través de la interfaz incorrecta eth0 (=LAN-NIC). Incluso se aplicó la regla NAT, por lo que la dirección de origen se cambió a la IP de la otra NIC (eth1).

Preguntas:

¿Cómo puedo configurar el sistema para generar paquetes NAT con la IP pública como dirección de origen para enviarlos a través de la NIC correcta (eth1)?

¿De alguna manera necesito agregar eth1 al puente (br0)? Si es así, ¿cómo asigno correctamente la dirección IP pública? Por lo general, es necesario configurar la IP en el dispositivo puente. ¿Necesitaría asignar una dirección de alias al puente (IP pública en br0:0)?

Detalles de configuración

La configuración de enrutamiento en el sistema host:

# ip r
default via y.y.y.126 dev eth1
10.x.x.0/24 dev br0  proto kernel  scope link  src 10.x.x.11
y.y.y.96/27 dev eth1 proto kernel  scope link  src y.y.y.102
  • IP: yyy126 es nuestro enrutador para internet público.
  • IP: yyy102 es la IP pública de la máquina host
  • IP: 10.xx11 es la IP de LAN de la máquina host
  • SUBRED: 10.xx0/24 es la LAN
  • SUBRED: yyy96/27 es la subred IP pública

Configuración de la tarjeta de red:

# ifconfig
br0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.x.x.11  netmask 255.255.255.0  broadcast 10.x.x.255
        inet6 ####::###:####:####:####  prefixlen 64  scopeid 0x20<link>
        ether ##:##:##:##:##:##  txqueuelen 0  (Ethernet)
        RX packets 2139490  bytes 243693436 (232.4 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 29085  bytes 2398024 (2.2 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 ####::###:####:####:####  prefixlen 64  scopeid 0x20<link>
        ether ##:##:##:##:##:##  txqueuelen 1000  (Ethernet)
        RX packets 2521995  bytes 290600491 (277.1 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 383089  bytes 48876399 (46.6 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
        device memory 0xdfa60000-dfa7ffff

eth1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet y.y.y.102  netmask 255.255.255.224  broadcast y.y.y.127
        inet6 ####::###:####:####:####  prefixlen 64  scopeid 0x20<link>
        ether ##:##:##:##:##:##  txqueuelen 1000  (Ethernet)
        RX packets 2681476  bytes 597532550 (569.8 MiB)
        RX errors 0  dropped 130  overruns 0  frame 0
        TX packets 187755  bytes 21894113 (20.8 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
        device memory 0xdfa00000-dfa1ffff

Configuración del puente:

# brctl show
bridge name     bridge id               STP enabled     interfaces
br0             8000.002590eb1900       no              eth0
                                                        vnet0

Y reglas de iptables:

# iptables -vnL
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
  723  106K DROP       udp  --  *      *       y.y.y.0/24           0.0.0.0/0            udp spt:5404
  586 40052 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            state RELATED,ESTABLISHED
    5   420 ACCEPT     icmp --  *      *       0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     all  --  lo     *       0.0.0.0/0            0.0.0.0/0
    0     0 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            state NEW tcp dpt:22
    2   458 LOG        all  --  *      *       0.0.0.0/0            0.0.0.0/0            LOG flags 0 level 4
    2   458 REJECT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            reject-with icmp-host-prohibited

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
 1343  173K ACCEPT     tcp  --  *      *       10.x.x.2             0.0.0.0/0            tcp spt:3389
 1648  127K ACCEPT     tcp  --  *      *       0.0.0.0/0            10.x.x.2             tcp dpt:3389
   18  1040 LOG        all  --  *      *       0.0.0.0/0            0.0.0.0/0            LOG flags 0 level 4
   18  1040 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0

Chain OUTPUT (policy ACCEPT 525 packets, 84016 bytes)
 pkts bytes target     prot opt in     out     source               destination


# iptables -vnL -t nat
Chain PREROUTING (policy ACCEPT 13 packets, 1218 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain INPUT (policy ACCEPT 5 packets, 420 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 13 packets, 880 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain POSTROUTING (policy ACCEPT 14 packets, 920 bytes)
 pkts bytes target     prot opt in     out     source               destination
    5   300 SNAT       all  --  *      *       10.x.x.0/24          !10.x.x.0/24           to:y.y.y.102

Y aquí un paquete NAT capturado (ping desde VM) en la tarjeta de interfaz LAN:

# tcpdump -i eth0
12:53:55.243350 IP y.y.y.102 > y.y.y.110: ICMP echo request, id 2, seq 5, length 40

Salida de "regla ip":

# ip rule
0:      from all lookup local
32766:  from all lookup main
32767:  from all lookup default

Respuesta1

  1. Verifique que sus máquinas virtuales tengan direcciones IP en 10.xxx/24 (máscara de red 255.255.255.0)

  2. Configure 10.xx11 (dirección IP br0) como la puerta de enlace predeterminada de sus máquinas virtuales

  3. Habilite el reenvío de IP en el host físico

  4. Habilite SNAT con:

    iptables -t nat -A POSTROUTING -s 10.x.x.x/24 -o eth1 -j SNAT --to y.y.y.102
    

Respuesta2

iptables -t nat -I POSTROUTING -s 10.xxx/24 ! -d 10.xxx/24 -j SNAT --a la fuente yyy102

esto debe cambiarse a

iptables -t nat -I POSTROUTING --out-interface eth1 -j SNAT --to-source y.y.y.102

Según su primera regla, solo se deben procesar paquetes con destino 10.xxx. Entonces, ¿qué pasa con el tráfico externo a su red? (fuente: de todo el mundo, el destino es su IP pública :)

¿Cómo puedo configurar el sistema para generar paquetes NAT con la IP pública como dirección de origen para enviarlos a través de la NIC correcta (eth1)?

lea arriba. Simplemente cambie la regla NAT.

¿De alguna manera necesito agregar eth1 al puente (br0)? Si es así, ¿cómo asigno correctamente la dirección IP pública? Por lo general, es necesario configurar la IP en el dispositivo puente. ¿Necesitaría asignar una dirección de alias al puente (IP pública en br0:0)?

De ninguna manera, a menos que seas consciente de qué y por qué estás haciendo esto. Mantenga las interfaces internas y externas separadas. Permitir solo enrutamiento.

He descrito por usted la configuración en vivo (producción) durante más de 5 años. Funciona sin problemas para 3 servidores host y 25 máquinas virtuales, incluidos enlaces puente sobre túneles openvpn.

Respuesta3

La publicación de Silvio me ayudó a hacer funcionar una configuración similar. Además de su publicación, aquí hay un par de cosas que también necesitaba hacer.

  1. En versiones más recientes de los kernels de Linux (Redhat 7, por ejemplo), deberá habilitar el módulo del kernel puente:

    modprobe br_netfilter
    

y luego, para que ese cambio sea persistente durante los reinicios del servidor, agregue la misma línea a un archivo llamado /etc/modules-load.d/.conf

  1. Una vez que habilité br_netfilter, tuve que habilitar también las reglas de reenvío de iptable a las máquinas virtuales, por ejemplo:

    iptables -I FORWARD -d 10.x.x.x/24 -j ACCEPT
    iptables -I FORWARD -s 10.x.x.x/24 -j ACCEPT
    
  2. En lugar de SNAT, utilicé una regla de enmascaramiento ya que solo necesitaba una ruta única dentro de una instalación de alojamiento de servidor.

    iptables -t nat -A POSTROUTING -s <single-local-vm-ip>/32 -d <my-destination-subnet>/24 -p tcp -j MASQUERADE --to-ports 1024-65535
    

información relacionada