Linux-Routing mit zwei Netzwerkkarten (LAN vs. Internet) mit NAT und Bridging für VMs

Linux-Routing mit zwei Netzwerkkarten (LAN vs. Internet) mit NAT und Bridging für VMs

Mein Setup:

In diesem Setup gibt es nur eine physische Maschine, ein Hostsystem für virtuelle Maschinen (VMs) mit zwei Netzwerkadaptern.

Eine Netzwerkkarte (eth0) ist an ein internes Netzwerk (LAN-Subnetz, z. B. 10.xxx/24) angeschlossen und soll für den internen Datenverkehr verwendet werden.

Die andere Netzwerkkarte (eth1) ist mit dem öffentlichen Internet verbunden (sie hat eine öffentlich routbare IP konfiguriert). Diese Verbindung soll verwendet werden, um den öffentlichen Internetverkehr an die internen IPs der VMs weiterzuleiten (eingehender Verkehr) und den VMs den Zugriff auf das öffentliche Internet (ausgehender Verkehr) über NAT zu ermöglichen.

Virtuelle Maschinen verwenden IP-Adressen im LAN-Subnetz (10.xxx/24, dasselbe wie eth0)

Ich habe ein Bridge-Gerät (br0) für die virtuellen Netzwerkschnittstellen der VMs (vnet0, vnet1, ...) und der LAN-NIC (eth0) konfiguriert. Das bedeutet:

  • br0 hat eine IP-Adresse im LAN-Subnetz (10.xxx/24)
  • eth0 wird zur Brücke hinzugefügt
  • vnet0, vnet1, ... (von den VMs verwendet) werden dynamisch zur Bridge hinzugefügt

Probleme

Die Kommunikation im LAN klappt einwandfrei. Auch der VM-Host ist über die öffentliche IP erreichbar und hat Internetzugang.

Mein Problem ist die NAT-Konfiguration, die den VMs auch den Zugriff auf das öffentliche Internet ermöglicht.

Ich habe versucht, eine einfache (S)NAT-Regel zu verwenden:

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

Wobei yyy102 die öffentliche, routbare IP der zweiten Netzwerkkarte (eth1) ist.

Ich habe herausgefunden, dass ich „ip_forward“ und „bridge-nf-call-iptables“ aktivieren muss:

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

Andernfalls werden die überbrückten Pakete nicht von iptables verarbeitet.

Jetzt scheinen die Pakete von den VMs die folgenden iptables-Ketten zu durchlaufen:

  • „FORWARD“ (regulär) – ich akzeptiere sie dort (-j ACCEPT, Zähler geht hoch)
  • „PREROUTING“ (nat) – ich akzeptiere sie dort (Richtlinie ACCEPT, Zähler geht hoch)
  • "POSTROUTING" (nat) - Sie entsprechen der SNAT-Regel

Aber aus einem Grund, den ich bisher nicht herausfinden konnte, scheinen nicht alle Pakete bei PRE/POSTROUTING anzukommen.

Interessanter ist jedoch, tcpdump -i eth0dass tcpdump -i eth1die Pakete (ich habe versucht, eine externe IP aus einer VM heraus anzupingen) anscheinend über die falsche Schnittstelle eth0 (=LAN-NIC) gesendet werden. Sogar die NAT-Regel wurde angewendet, sodass die Quelladresse auf die IP der anderen NIC (eth1) geändert wurde.

Fragen:

Wie kann ich das System so konfigurieren, dass die NAT-Pakete mit der öffentlichen IP als Quelladresse ausgegeben werden, damit sie über die richtige Netzwerkkarte (eth1) gesendet werden?

Muss ich eth1 irgendwie zur Bridge (br0) hinzufügen? Wenn ja, wie weise ich die öffentliche IP-Adresse richtig zu? Normalerweise muss die IP auf dem Bridge-Gerät konfiguriert werden. Muss ich der Bridge eine Alias-Adresse zuweisen (öffentliche IP auf br0:0)?

Konfigurationsdetails

Die Routing-Konfiguration auf dem Hostsystem:

# 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 ist unser Router für das öffentliche Internet.
  • IP: yyy102 ist die öffentliche IP des Hostcomputers
  • IP: 10.xx11 ist die LAN-IP des Host-Rechners
  • SUBNET: 10.xx0/24 ist das LAN
  • SUBNET: yyy96/27 ist das öffentliche IP-Subnetz

NIC-Konfiguration:

# 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

Brückenkonfiguration:

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

Und iptables-Regeln:

# 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

Und hier ein erfasstes NAT-Paket (Ping von VM) auf der LAN-Schnittstellenkarte:

# 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

Ausgabe von „ip rule“:

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

Antwort1

  1. Überprüfen Sie, ob Ihre VMs IP-Adressen auf 10.xxx/24 (Netzmaske 255.255.255.0) haben.

  2. Legen Sie 10.xx11 (br0 IP-Adresse) als Standard-Gateway Ihrer VMs fest

  3. Aktivieren Sie die IP-Weiterleitung auf dem physischen Host

  4. Aktivieren Sie SNAT mit:

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

Antwort2

iptables -t nat -I POSTROUTING -s 10.xxx/24 ! -d 10.xxx/24 -j SNAT --to-source yyy102

Dies muss geändert werden in

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

Gemäß Ihrer ersten Regel dürfen nur Pakete mit dem Ziel 10.xxx verarbeitet werden. Wie sieht es also mit dem Datenverkehr von außerhalb Ihres Netzwerks aus? (Quelle – aus aller Welt, Ziel ist Ihre öffentliche IP :)

Wie kann ich das System so konfigurieren, dass die NAT-Pakete mit der öffentlichen IP als Quelladresse ausgegeben werden, damit sie über die richtige Netzwerkkarte (eth1) gesendet werden?

Lesen Sie oben. Ändern Sie einfach die NAT-Regel.

Muss ich eth1 irgendwie zur Bridge (br0) hinzufügen? Wenn ja, wie weise ich die öffentliche IP-Adresse richtig zu? Normalerweise muss die IP auf dem Bridge-Gerät konfiguriert werden. Muss ich der Bridge eine Alias-Adresse zuweisen (öffentliche IP auf br0:0)?

Auf keinen Fall, es sei denn, Sie wissen, was und warum Sie das tun. Halten Sie interne und externe Schnittstellen getrennt. Erlauben Sie nur Routing.

Ich habe die von Ihnen beschriebene Konfiguration seit mehr als 5 Jahren live (Produktion). Funktioniert reibungslos für 3 Hostserver und 25 VMs, einschließlich Bridge-Links über OpenVPN-Tunnel.

Antwort3

Silvios Beitrag hat mir geholfen, eine ähnliche Konfiguration zum Laufen zu bringen. Zusätzlich zu seinem Beitrag sind hier noch ein paar Dinge, die ich ebenfalls tun musste.

  1. In neueren Versionen des Linux-Kernels (z. B. Redhat 7) müssen Sie das Bridge-Kernelmodul aktivieren:

    modprobe br_netfilter
    

und um diese Änderung auch nach einem Neustart des Servers dauerhaft zu machen, fügen Sie die gleiche Zeile zu einer Datei mit dem Namen /etc/modules-load.d/.conf hinzu.

  1. Nachdem ich br_netfilter aktiviert hatte, musste ich auch iptable-Weiterleitungsregeln für die VM(s) aktivieren, z. B.:

    iptables -I FORWARD -d 10.x.x.x/24 -j ACCEPT
    iptables -I FORWARD -s 10.x.x.x/24 -j ACCEPT
    
  2. Anstelle von SNAT habe ich eine Maskerade-Regel verwendet, da ich innerhalb einer Server-Hosting-Einrichtung nur eine einzige Route benötigte.

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

verwandte Informationen