Маршрутизация Linux с двумя сетевыми картами (LAN против Интернета) с NAT и мостом для виртуальных машин

Маршрутизация Linux с двумя сетевыми картами (LAN против Интернета) с NAT и мостом для виртуальных машин

Моя установка:

В этой конфигурации есть только одна физическая машина — хост-система для виртуальных машин (ВМ) с двумя сетевыми адаптерами.

Одна сетевая карта (eth0) подключена к внутренней сети (подсеть LAN, например, 10.xxx/24) и должна использоваться для внутреннего трафика.

Другой сетевой адаптер (eth1) подключен к публичному Интернету (он имеет настроенный публичный маршрутизируемый IP). Это подключение будет использоваться для переадресации трафика публичного Интернета на внутренние IP-адреса виртуальных машин (входящий трафик) и для предоставления виртуальным машинам доступа к публичному Интернету (исходящий трафик) через NAT.

Виртуальные машины используют IP-адреса в локальной подсети (10.xxx/24, как и eth0)

У меня есть устройство моста (br0), настроенное для виртуальных сетевых интерфейсов виртуальных машин (vnet0, vnet1, ...) и LAN-NIC (eth0). Это означает:

  • br0 имеет IP-адрес в подсети LAN (10.xxx/24)
  • eth0 добавлен в мост
  • vnet0, vnet1, ... (используемые виртуальными машинами) динамически добавляются к мосту

Проблемы

Связь внутри локальной сети работает нормально. Также VM-Host доступен через публичный IP и имеет выход в интернет.

Моя проблема заключается в настройке NAT, которая позволяет виртуальным машинам также получать доступ к публичному Интернету.

Я попытался использовать простое правило (S)NAT:

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

Тогда как yyy102 — это общедоступный маршрутизируемый IP-адрес второй сетевой карты (eth1).

Я обнаружил, что мне нужно включить «ip_forward» и «bridge-nf-call-iptables»:

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

В противном случае пакеты, подключенные через мост, не будут обрабатываться iptables.

Теперь пакеты от виртуальных машин, похоже, проходят через следующие цепочки iptables:

  • "FORWARD" (обычный) - я принимаю их там (-j ACCEPT, счетчик увеличивается)
  • "PREROUTING" (nat) - я принимаю их там (политика ПРИНЯТЬ, счетчик увеличивается)
  • "POSTROUTING" (nat) - Они соответствуют правилу SNAT

Но, похоже, не все пакеты доходят до PRE/POSTROUTING по какой-то причине, которую я пока не смог выяснить.

Однако, что более интересно, tcpdump -i eth0vs. tcpdump -i eth1показывают, что пакеты (я пытался пинговать внешний IP из виртуальной машины), похоже, отправляются через неправильный интерфейс eth0 (=LAN-NIC). Даже правило NAT было применено, поэтому адрес источника был изменен на IP другой сетевой карты (eth1).

Вопросы:

Как настроить систему для вывода NAT-пакетов с публичным IP-адресом в качестве исходного адреса для отправки через правильный сетевой адаптер (eth1)?

Нужно ли мне как-то добавлять eth1 к мосту (br0)? Если да, то как правильно назначить публичный IP-адрес? Обычно IP-адрес нужно настроить на устройстве моста. Нужно ли мне назначать псевдоним мосту (публичный IP на br0:0)?

Подробности конфигурации

Конфигурация маршрутизации в хост-системе:

# 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 — наш маршрутизатор для публичного Интернета.
  • IP: yyy102 — публичный IP хост-компьютера
  • IP: 10.xx11 — это LAN IP хост-машины.
  • ПОДСЕТЬ: 10.xx0/24 — это локальная сеть
  • ПОДСЕТЬ: yyy96/27 — это публичная IP-подсеть

Конфигурация сетевой карты:

# 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

Конфигурация моста:

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

И правила 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

А вот перехваченный NAT-пакет (ping с виртуальной машины) на сетевой карте:

# 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

Вывод «правила ip»:

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

решение1

  1. Проверьте, что ваши виртуальные машины имеют IP-адреса в диапазоне 10.xxx/24 (маска сети 255.255.255.0)

  2. Установите 10.xx11 (IP-адрес br0) в качестве шлюза по умолчанию для ваших виртуальных машин.

  3. Включить переадресацию IP на физическом хосте

  4. Включите SNAT с помощью:

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

решение2

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

это должно быть изменено на

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

Согласно вашему первому правилу, должны обрабатываться только пакеты с назначением на 10.xxx. Так что насчет трафика извне в вашу сеть? (источник - со всего мира, назначение - ваш публичный IP :)

Как настроить систему для вывода NAT-пакетов с публичным IP-адресом в качестве исходного адреса для отправки через правильный сетевой адаптер (eth1)?

читайте выше. Просто измените правило NAT.

Нужно ли мне как-то добавлять eth1 к мосту (br0)? Если да, то как правильно назначить публичный IP-адрес? Обычно IP-адрес нужно настроить на устройстве моста. Нужно ли мне назначать псевдоним мосту (публичный IP на br0:0)?

Ни в коем случае, если вы не знаете, что и почему вы это делаете. Разделяйте внутренние и внешние интерфейсы. Разрешите только маршрутизацию.

Я описал вам конфигурацию live (production) более 5 лет. Работает гладко для 3 хост-серверов и 25 виртуальных машин, включая мостовые соединения через туннели openvpn.

решение3

Пост Сильвио помог мне заставить работать похожую конфигурацию. В дополнение к его посту, вот пара вещей, которые мне также нужно было сделать.

  1. В новых версиях ядер Linux (например, Redhat 7) вам потребуется включить модуль ядра bridge:

    modprobe br_netfilter
    

а затем, чтобы сделать это изменение постоянным при перезапусках сервера, добавьте ту же строку в файл с именем /etc/modules-load.d/.conf

  1. После включения br_netfilter мне также пришлось включить правила пересылки iptable для виртуальных машин, например:

    iptables -I FORWARD -d 10.x.x.x/24 -j ACCEPT
    iptables -I FORWARD -s 10.x.x.x/24 -j ACCEPT
    
  2. Вместо SNAT я использовал правило маскарада, поскольку мне был нужен только один маршрут в пределах хостинг-сервера.

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

Связанный контент