具有两个 NIC(LAN 与 Internet)的 Linux 路由,带有 NAT 和虚拟机桥接

具有两个 NIC(LAN 与 Internet)的 Linux 路由,带有 NAT 和虚拟机桥接

我的设置:

此设置中只有一台物理机,即具有两个网络适配器的虚拟机 (VM) 的主机系统。

一个 NIC(eth0)连接到内部网络(LAN 子网,例如 10.xxx/24)并且将用于内部流量。

另一个 NIC(eth1)连接到公共互联网(它配置了一个公共可路由 IP)。此连接应用于将公共互联网流量端口转发到虚拟机的内部 IP(传入流量),并允许虚拟机通过 NAT 访问公共互联网(传出流量)。

虚拟机使用 LAN 子网中的 IP 地址(10.xxx/24,与 eth0 相同)

我已为虚拟机 (vnet0、vnet1、...) 和 LAN-NIC (eth0) 的虚拟网络接口配置了一个桥接设备 (br0)。这意味着:

  • br0 在 LAN 子网中有一个 IP 地址 (10.xxx/24)
  • eth0 已添加到网桥
  • vnet0、vnet1、...(由虚拟机使用)被动态添加到网桥

问题

LAN 内的通信正常。此外,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 是第二个 NIC(eth1)的公共可路由 IP。

我发现我需要启用“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显示数据包(我尝试从虚拟机内部 ping 外部 IP)似乎是通过错误的接口 eth0(=LAN-NIC)发送的。即使应用了 NAT 规则,源地址也更改为另一个 NIC(eth1)的 IP。

问题:

如何配置系统以输出以公共 IP 作为源地址的 NAT 数据包,并通过正确的 NIC(eth1)发送?

我是否需要以某种方式将 eth1 添加到网桥 (br0)?如果是这样,我该如何正确分配公共 IP 地址?通常需要在网桥设备上配置 IP。我是否需要为网桥分配一个别名地址(br0:0 上的公共 IP)?

配置详细信息

主机系统上的路由配置:

# 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 是 LAN
  • 子网: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

下面是在 LAN 接口卡上捕获的 NAT 数据包(从 VM 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 rule”的输出:

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

答案1

  1. 检查您的虚拟机是否具有 10.xxx/24 上的 IP 地址(网络掩码 255.255.255.0)

  2. 将 10.xx11(br0 ip 地址)设置为虚拟机的默认网关

  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 :)

如何配置系统以输出以公共 IP 作为源地址的 NAT 数据包,并通过正确的 NIC(eth1)发送?

请参阅上文。只需更改 NAT 规则。

我是否需要以某种方式将 eth1 添加到网桥 (br0)?如果是这样,我该如何正确分配公共 IP 地址?通常需要在网桥设备上配置 IP。我是否需要为网桥分配一个别名地址(br0:0 上的公共 IP)?

除非您清楚自己在做什么以及为什么这么做,否则绝对不要这么做。保持内部和外部接口分离。仅允许路由。

我已经描述了您配置的实时(生产)超过 5 年。 3 个主机服务器和 25 个虚拟机运行顺畅,包括通过 openvpn 隧道的桥接链接。

答案3

Silvio 的帖子帮助我实现了类似的配置。除了他的帖子之外,这里还有一些我需要做的事情。

  1. 在较新版本的 Linux 内核(例如 Redhat 7)中,您将需要启用桥接内核模块:

    modprobe br_netfilter
    

然后,为了使该更改在服务器重启后保持不变,请将同一行添加到名为 /etc/modules-load.d/.conf 的文件中

  1. 一旦我启用了 br_netfilter,我还必须为 VM 启用 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
    

相关内容