我只是在多网卡和 IP 地址服务器上遇到了问题。我为 Cent OS 7 服务器配置了一个属于 eth1 的附加公共 IP 地址。当启用 iptables 源 NAT 时,只有附加 IP 地址无法使用。
在本文中,两个公网 IP 地址分别为 99.0.1.100 (eth0) 和 99.0.2.100 (eth1)。99.0.2.100 的子网掩码为 255.255.254.0,默认网关设置正确(99.0.1.1 对应 99.0.1.100,99.0.2.1 对应 99.0.2.100)。
以下是 的内容/etc/sysconfig/network-scripts/ifcfg-eth1
。(HWADDR 已被审查)
DEVICE=eth1
TYPE=Ethernet
HWADDR=**:**:**:**:**:**
ONBOOT=yes
NM_CONTROLLED=no
BOOTPROTO=static
IPADDR=99.0.2.100
NETMASK=255.255.254.0
以下是 的输出ip route
。
default via 99.0.1.1 dev eth0 proto static metric 100
99.0.1.0/23 dev eth0 proto kernel scope link src 99.0.1.100 metric 100
99.0.2.0/23 dev eth1 proto kernel scope link src 99.0.2.100
以下是 的输出ip rule
。
0: from all lookup local
32765: from 99.0.2.100 lookup subroute-eth1
32766: from all lookup main
32767: from all lookup default
以下为 的内容/etc/sysconfig/network-scripts/route-eth1
。
default via 99.0.2.1 table subroute-eth1
以下为 的内容/etc/sysconfig/network-scripts/rule-eth1
。
from 99.0.2.100 table subroute-eth1
然后,以下请求已被正确发送,并且对于每个公共 IP 地址,以字符串形式响应正确的 IP 地址。
# curl --interface eth0 api.ipify.org # outputs 99.0.1.100
# curl --interface eth1 api.ipify.org # outputs 99.0.2.100
这里,我希望系统的每个用户使用不同的公网 IP 地址。因此应用了以下 iptables 源 NAT。其中 uid=1000 为 A,uid=1001 为 B。
# iptables -t nat -m owner --uid-owner 1000 -A POSTROUTING -j SNAT --to-source 99.0.1.100
# iptables -t nat -m owner --uid-owner 1001 -A POSTROUTING -j SNAT --to-source 99.0.2.100
在这种情况下,eth0工作正常,但eth1已超时。
# curl api.ipify.org # outputs 99.0.1.100
# sudo -u A curl api.ipify.org # outputs 99.0.1.100
# sudo -u B curl api.ipify.org # **time out**
由于缺乏网络经验,我不知道哪里出了问题。如果有人有想法,请帮助我。请注意,在这种情况下,互联网仍然正常工作。ssh [email protected]
编辑:以下是输出ip route show table subroute-eth1
default via 99.0.2.1 dev eth1
答案1
uid 应该触发路由更改eth1
以代替eth0
。nat/POSTROUTING
的 SNAT(虽然仍然需要)来得太晚了,因为正如名称 POSTROUTING 所暗示的那样,它发生在路由决策之后:网络接口被选择并且不会再改变。
对于本地流量,规则必须在mangle/OUTPUT
链中发生以改变路线,通过使用可以触发ip rule
查找的标记:
# iptables -t mangle -A OUTPUT -m owner --uid-owner 1000 -j MARK --set-mark 1000
# iptables -t mangle -A OUTPUT -m owner --uid-owner 1001 -j MARK --set-mark 1001
然后通过 重新使用这些信息ip rule
。甚至 1000 也必须考虑(以处理uid1000$ curl --interface eth1 http://api.ipify.org/
不应使用条目 32765 的特定情况):
ip rule add fwmark 1000 lookup main
ip rule add fwmark 1001 lookup subroute-eth1
请注意,初始默认 IP 是之前选择的:仍然需要 SNAT 将其修复为新的正确 IP。既然已经有了规则,为什么还要使用此标记from 99.0.2.100 lookup subroute-eth1
?同样,这是因为网络堆栈中各种评估的顺序,如下所述Netfilter 中的数据包流和通用网络示意图:只有发生改变mangle/OUTPUT
才能触发重新路由检查如图所示,此时 IP 尚未更正为 99.0.2.100。
在反向路径中,一些网络元素无论如何都不会及时了解这些路由表,因此必须将松散模式设置eth1
为rp_过滤器否则返回数据包将被丢弃:
# echo 2 > /proc/sys/net/ipv4/conf/eth1/rp_filter
eth0
处理上述 uid 1000 的具体情况也是一样的( uid1000$ curl --interface eth1 http://api.ipify.org/
):
# echo 2 > /proc/sys/net/ipv4/conf/eth0/rp_filter
这样就应该大多可以工作。但实际上,一些数据包不属于 uid 1001:,TCP RST
最后一个数据包ACK
在进程结束后,或者对于 UDP,相关的 ICMP 错误... 仅由内核拥有。它们与 uid 1001 不匹配,将在错误的接口上发送(在这个错误的接口上使用错误的 IP),这将在连接结束时造成一些超时,更可能是在远程端而不是本地。这可以通过在kill -KILL
客户端上执行 来看到,该客户端通过 与用户 1001 建立更改的连接eth1
,并见证ACK
通过eth0
(而不是eth1
)发送的源 99.0.2.100 的几个重试数据包,确认FIN
在 上多次收到来自远程的数据包eth1
。
因此,所有这些都必须重新使用CONNMARK
追踪流量由用户发起,而不是数据包由用户发起(一些解释这里)。nat
无需更改,因为NEW
无论如何只有状态中的第一个数据包会通过 iptables 规则,并且它已经在跟踪流量。让我们重新开始:
# iptables -t mangle -F
# iptables -t mangle -A PREROUTING -j CONNMARK --restore-mark
# iptables -t mangle -A OUTPUT -j CONNMARK --restore-mark
# iptables -t mangle -A OUTPUT -m owner --uid-owner 1000 -j MARK --set-mark 1000
# iptables -t mangle -A OUTPUT -m owner --uid-owner 1001 -j MARK --set-mark 1001
# iptables -t mangle -A OUTPUT -j CONNMARK --save-mark
现在一切都应该正常运行。
最后说明:虽然您的设置中不需要它,但 eth1 的链接本地路由应该在表中重复subroute-eth1
,否则eth1
从 uid 1001 访问的 LAN 将产生奇怪的结果,因为规则 32765 在规则 32766 之前读取,因此永远不会定义链接本地路由,正如此命令的结果所示:
# ip route get 99.0.2.55 mark 1001
99.0.2.55 via 99.0.2.1 dev eth1 table subroute-eth1 src 99.0.2.100 mark 0x3e9 uid 0 \ cache
它可能会阻止访问网关以外的所有 LAN。
您应该添加(或根据需要放入系统配置文件中):
ip route add table subroute-eth1 99.0.2.0/23 dev eth1 scope link src 99.0.2.100
然后前一个ip route get
命令将给出正确的结果:
99.0.2.55 dev eth1 table subroute-eth1 src 99.0.2.100 mark 0x3e9 uid 0 \ cache