我的配置:
# ip route sh zzz.zzz.zzz.0/24 dev eth3 proto kernel scope link src zzz.zzz.zzz.1 yyy.yyy.yyy.0/24 dev eth1 proto kernel scope link src yyy.yyy.yyy.146 xxx.xxx.xx8.0/23 dev eth4 proto kernel scope link src xxx.xxx.xx9.47 169.254.0.0/16 dev eth3 scope link metric 1002 169.254.0.0/16 dev eth4 scope link metric 1003 169.254.0.0/16 dev eth1 scope link metric 1004 default via xxx.xxx.xxx.1 dev eth4
# ip rule sh 0: from all lookup local 217: from xxx.xxx.xx9.47 lookup table1 219: from yyy.yyy.yyy.146 lookup table2 32766: from all lookup main 32767: from all lookup default
# ip ro sh table table2 zzz.zzz.zzz.0/24 dev eth3 proto kernel scope link src zzz.zzz.zzz.1 yyy.yyy.yyy.0/24 dev eth1 proto kernel scope link src yyy.yyy.yyy.146 default via yyy.yyy.yyy.1 dev eth1
# ip ro sh table table1 zzz.zzz.zzz.0/24 dev eth3 proto kernel scope link src zzz.zzz.zzz.1 xxx.xxx.xx8.0/23 dev eth4 proto kernel scope link src xxx.xxx.xx9.47 default via xxx.xxx.xx8.1 dev eth4
iptables -t nat -L POSTROUTING MASQUERADE all -- * eth4 0.0.0.0/0 0.0.0.0/0 MASQUERADE all -- * eth1 0.0.0.0/0 0.0.0.0/0
rp_filter 设置为 0(尝试过 2,结果相同)
当我尝试从互联网访问 xxx.xxx.xx9.47 或 yyy.yyy.yyy.146 时,它们在该配置下运行完美。从局域网 (zzz.zzz.zzz.0/24) 互联网运行完美,流量通过默认路由传出。
我将一个端口转发到 zzz.zzz.zzz.0/24 局域网中的一台计算机
# iptables -t nat -L PREROUTING -nv DNAT tcp -- eth4 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:aa to:zzz.zzz.zzz.3:bb DNAT tcp -- eth1 * 0.0.0.0/0 0.0.0.0/0 tcp dpt:aa to:zzz.zzz.zzz.3:bb
从互联网上,我只能通过使用 xxx.xxx.xx9.47(默认路由的 IP)到达端口 aa 上的 zzz.zzz.zzz.3。我从 yyy.yyy.yyy.146 连接失败,这不是默认路由。如果我对默认路由接口(此例为 eth4)进行 tcpdump,eth1 上的 tcpdump 仅显示传入流量,我会看到数据包试图离开源 IP 为 yyy.yyy.yyy.146 的接口,当然它不起作用
如果我将默认路由更改为 eth1,则会发生完全相反的事情。我从端口 aa 上的 yyy.yyy.yyy.146 获得响应,并且从 xxx.xxx.xx9.47 tcpdump eth1 连接失败,当尝试访问 aa 端口上的 xxx.xxx.xx9.47 时,我看到数据包试图通过 xxx.xxx.xx9.47 离开 eth1
用 snat 替换了 maquede
# iptables -t nat -L POSTROUTING SNAT all -- * eth1 0.0.0.0/0 0.0.0.0/0 to:yyy.yyy.yyy.146 SNAT all -- * eth4 0.0.0.0/0 0.0.0.0/0 to:xxx.xxx.xx9.47
并且默认路由上的 tcpdump 仍然显示源 yyy.yyy.yyy.146 的响应包离开 eth4 所以.. snat 或伪装工作,contrack 工作。我真的不明白为什么它只尝试在默认接口上响应,即使源 ip 来自另一个接口......以及它怎么会在一个接口上使用来自另一个接口的 ip 进行 snat。操作系统是 centos 6.8。
答案1
当数据包通过接口 X 进入,并由同一台机器立即响应时,您的基于源的路由规则可以捕获响应,因为其源 IP 地址必然与规则匹配。
当这些数据包随后通过接口 Y 转发到另一个 IP 时,通信的第一部分将正常工作。但是,一旦第一个响应数据包从该其他 IP 到达,它将使用自己的源 IP 地址(而不是此路由器的源 IP 地址)进入路由规则解析器。然后它将错过基于源的路由规则,而是匹配默认查找,该查找将像往常一样基于目的地。
您需要做的是在数据包到达接口 X 时对其进行标记,并使此标记在转发过程中保持不变,然后在路由规则中匹配该标记,以便使用不同的传出路由表。
答案2
我认为需要通过标记数据包来完成。
我通过使用 mangle 解决了这个问题
# iptables -t mangle -L PREROUTING -nv
CONNMARK all -- * * 0.0.0.0/0 0.0.0.0/0 CONNMARK restore
MARK all -- eth4 * 0.0.0.0/0 0.0.0.0/0 MARK set 0xc8
MARK all -- eth1 * 0.0.0.0/0 0.0.0.0/0 MARK set 0xd3
CONNMARK all -- * * 0.0.0.0/0 0.0.0.0/0 CONNMARK save
基本上,我会在每个接口上标记传入连接,并在跟踪的连接上恢复标记。因此,标记为来自 eth1 的连接将始终通过规则 fwmark 211(0xd3) 和规则 fwmark 200 (0xc8) 转到 eth4