通过 iptables 从同一网桥将端口转发到虚拟机

通过 iptables 从同一网桥将端口转发到虚拟机

我正在运行一个 proxmox 服务器,其中有两个虚拟机连接到桥接接口vmbr0

  • 主机:(10.10.10.1外部 IP 123.123.123.123:)
  • VM1:10.10.10.2
  • VM2:10.10.10.3

在 VM2 上,负载均衡器在端口 443 上运行(是的,我希望它在那里运行,而不是在主机上)。我添加了一个预路由 iptables 规则,将端口 443 上的所有传入流量转发到 VM2。此规则有效,允许从端口 443(在 VM2 上)上的“互联网”进行连接。我还在公共 IP 上添加了一个输出规则以转发到 VM2,以便主机可以使用外部 IP 连接到 VM2 的负载均衡器。

现在一个未解决的问题是,通过外部 IP ( 123.123.123.123) 从 VM1 连接到 VM2,但无法连接:

# from VM1
$ curl -v https://123.123.123.123
*   Trying 123.123.123.123:443...
^C

如果我直接使用内部 IP(https://10.10.10.3),它就可以正常工作。我的意思是我可以更改,/etc/hosts但这不是理想的方法。那么你有什么建议可以解决这个问题吗?

主机的输出(我删除了不必要的部分以最小化输出):

$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: enp0s31f6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 01:01:01:01:01:01 brd ff:ff:ff:ff:ff:ff
    inet 123.123.123.123/26 scope global enp0s31f6
       valid_lft forever preferred_lft forever
3: vmbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 01:01:01:01:01:01 brd ff:ff:ff:ff:ff:ff
    inet 10.10.10.1/24 scope global vmbr0
       valid_lft forever preferred_lft forever


$ iptables -t nat -L -v -n
Chain PREROUTING (policy ACCEPT 1697 packets, 96837 bytes)
 pkts bytes target     prot opt in     out     source               destination
  149  8924 DNAT       tcp  --  *      *       0.0.0.0/0            123.123.123.123      tcp dpt:443 to:10.10.10.3:443

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

Chain OUTPUT (policy ACCEPT 10 packets, 723 bytes)
 pkts bytes target     prot opt in     out     source               destination
    3   180 DNAT       tcp  --  *      *       0.0.0.0/0            123.123.123.123      tcp dpt:443 to:10.10.10.3:443

Chain POSTROUTING (policy ACCEPT 534 packets, 39072 bytes)
 pkts bytes target     prot opt in     out     source               destination
1908K  138M MASQUERADE  all  --  *      enp0s31f6  10.10.10.0/24        0.0.0.0/0


$ iptables -L -v -n             
Chain INPUT (policy ACCEPT 8078 packets, 834K bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain FORWARD (policy ACCEPT 70853 packets, 12M bytes)
 pkts bytes target     prot opt in     out     source               destination         

Chain OUTPUT (policy ACCEPT 7079 packets, 926K bytes)
 pkts bytes target     prot opt in     out     source               destination 


$ cat /proc/sys/net/ipv4/ip_forward
1

答案1

这是一个典型的NAT 发夹结构当客户端(VM1 甚至 VM2)与服务器(VM2)位于同一 LAN 上时,流量变得不对称:回复将绕过执行 NAT 的部分,因此回复不会被取消 DNAT,并且客户端会从它没有询问任何内容的地址(VM2)(而不是公共主机)收到回复并被拒绝。

解决此问题最简单的方法是,当这种情况发生时,除了 DNAT 之外,还执行 SNAT。因此,除了:

1908K 138M MASQUERADE 全部 -- * enp0s31f6 10.10.10.0/24 0.0.0.0/0

请注意,在这种情况下,传出接口不是面向公众的接口,而是面向 VM2 的接口(它是vmbr0)。

可以添加(此处使用针对端口 443 的特定过滤器,如果无论服务是什么,结果都是预期的,则可以删除此过滤器):

iptables -t nat -A POSTROUTING -s 10.10.10.0/24 -d 123.123.123.123 -p tcp --dport 443 -j MASQUERADE

更新:上述规则不起作用,因为(初始)数据包的目标 123.123.123.123 在 nat/PREROUTING 处更改为 10.10.10.3。下面的规则可以代替(它在 DNAT 发生之前向 Netfilter 查询初始目标):

iptables -t nat -A POSTROUTING -s 10.10.10.0/24 -m conntrack --ctorigdst 123.123.123.123 -p tcp --dport 443 -j MASQUERADE

但考虑到这是最没用的例子,而且不必要地复杂,我们就忘掉它吧。

与上述情况不同,特别是如果主机有多个 IP 公网 IP 地址和/或多个内部 LAN(每个 LAN 都在同一个位置有一个客户端和一个服务器),查询 Netfilter 以了解何时必须执行此操作会更有用:当 DNAT 已经发生时(然后它甚至不需要指定端口来处理所有情况):

iptables -t nat -A POSTROUTING -m conntrack --ctstate DNAT -j MASQUERADE

相反MASQUERADE,你可以选择任意源 NAT 到网络前缀(iptables'NETMAP) 与服务器的默认路由匹配,因此回复正确地通过主机并正确地取消 DNAT。这样就可以在服务器上记录日志,也可以用来了解哪些特定的内部的客户端执行了查询。由于它对每个 LAN 都很有用,因此应该再次声明 LAN,并且该规则对多个 LAN 多次使用(这不是 OP 当前的情况,但这个答案旨在考虑更多情况)。

例如,如果所选的虚拟网络为 10.11.10.0/24(未在其他地方使用),则它将是默认VM2 的路由),而不是上面的,使用这个:

iptables -t nat -A POSTROUTING -s 10.10.10.0/24 -m conntrack --ctstate DNAT -j NETMAP --to 10.11.10.0/24

VM2 的日志现在可以显示 3 种情况:

  • 从公共 IP 地址查询:实际的客户端地址,包括主机(如果它选择查询 123.123.123.123 的话)(套接字最初选择123.123.123.123 所以这是源)然后被 nat/OUTPUT 重定向。

  • 从 10.10.10.0/24 中的地址进行查询:从 LAN 直接查询(包括来自主机的查询)到 VM2,而不使用 123.123.123.123 作为目的地。

  • 从 10 中的地址进行查询。11.10.0/24:从 LAN 查询到已重定向的 123.123.123.123。VM1 将始终显示为 10.11.10.2 源,因为NETMAP保持宿主部分完好。

    最后一部分还可以区分 VM1 是否执行了查询,或者说最初在 10.10.10.4 的新 VM VM3 被视为 10.11.10.4。

相关内容