如何使IPv4/IPv6翻译器的指定路由始终优先生效?
看起来你遇到的核心问题有两个:一是把目标IP绑到本地接口后,内核直接把它当成本地地址走lo路由,绕开了你设置的翻译路由;二是不用绑定IP的话,ARP代理又不工作,其他设备找不到这个IP的MAC地址。我来帮你一步步梳理解决思路:
一、先解决ARP代理不响应的问题(避免把目标IP绑到本地接口)
你之前尝试了ip -4 neigh add proxy和arp -s但没生效,大概率是IPv4的proxy ARP开关没正确打开——你之前误开了IPv6的proxy_ndp,这和IPv4的proxy ARP是完全独立的功能,别搞混了。
- 先在连接192.168.132.0/24网段的接口(ens256)上启用proxy ARP:
echo 1 > /proc/sys/net/ipv4/conf/ens256/proxy_arp
- 然后添加ARP代理条目,让翻译器替192.168.132.95回应ARP请求:
ip -4 neigh add proxy 192.168.132.95 dev ens256
这样其他设备(比如服务器192.168.132.85)发ARP请求找192.168.132.95时,你的翻译器就会用ens256的MAC地址回应,流量就能正常到达翻译器了。
二、解决路由优先级问题:让流量进入joolns而不走本地
现在流量能到翻译器了,但你需要让目标IP的流量转发到joolns的veth接口,而不是被内核当成本地地址处理。这里的关键是绝对不要把192.168.132.95绑定到翻译器的任何物理接口上——一旦绑定,内核会自动生成优先级最高的local路由,直接走lo接口,完全绕开你的静态路由。
推荐用策略路由来针对特定目标IP做特殊转发,步骤如下:
- 创建一个专门的路由表(比如表号100):
echo "100 jool" >> /etc/iproute2/rt_tables
- 在这个路由表里添加规则,把目标IP的流量指向joolns的veth接口:
ip route add 192.168.132.95/32 via 192.168.0.2 dev to_jool table 100
这里的192.168.0.2是你之前在joolns里给to_world接口配置的IPv4地址。
3. 添加策略路由规则,让所有到192.168.132.95的流量都优先使用这个表:
ip rule add to 192.168.132.95/32 table 100 priority 100
这个优先级(100)比默认的main表(32766)高,能确保规则被优先匹配。
三、验证流量走向的实用方法
要确认数据包到底去哪了,你可以用这些工具一步步排查:
- 查看路由规则和实际路由选择:
# 查看所有策略路由规则 ip rule show # 查看针对目标IP的实际路由路径 ip route get 192.168.132.95
如果配置正确,这里应该显示走to_jool接口,而不是lo。
2. 多接口同步抓包:
同时在ens256、to_jool和joolns内的to_world接口抓包,追踪流量走向:
# 窗口1:抓ens256的流量 tcpdump -n -i ens256 host 192.168.132.95 # 窗口2:抓to_jool的流量 tcpdump -n -i to_jool host 192.168.132.95 # 窗口3:在joolns里抓to_world的流量 ip netns exec joolns tcpdump -n -i to_world host 192.168.132.95
- 实时监控路由变化:
ip route monitor
可以实时看到路由表的动态变化,确认你的规则是否生效。
四、修改后的完整测试脚本
把你原来的脚本里绑定192.168.132.95到ens256的步骤删掉,换成上面的proxy ARP和策略路由配置,修改后的脚本如下:
#!/bin/bash # 1: 创建虚拟接口和新命名空间 ip netns add joolns ip link add name to_jool type veth peer name to_world ip link set up dev to_jool ip link set dev to_world netns joolns ip netns exec joolns ip link set up dev to_world #2: 获取veth对的链路本地地址(后续用作下一跳) LL_TO_JOOL=$(ip -6 -br address show scope link dev to_jool | awk '{print $3}' | awk -F"/" '{print $1}') LL_TO_WORLD=$(ip netns exec joolns ip -6 -br address show scope link dev to_world | awk '{print $3}' | awk -F"/" '{print $1}') #3: 配置joolns内的IP和路由 ip netns exec joolns ip -6 route add default via $LL_TO_JOOL dev to_world ip netns exec joolns ip -4 address add 192.168.0.2/24 dev to_world #4: 配置全局命名空间的IP、ARP代理和策略路由 # IPv4 proxy ARP 关键配置 echo 1 > /proc/sys/net/ipv4/conf/ens256/proxy_arp ip -4 neigh add proxy 192.168.132.95 dev ens256 # IPv6 proxy NDP(如果需要IPv6侧代理的话) echo 1 > /proc/sys/net/ipv6/conf/ens256/proxy_ndp # veth接口的IPv4地址配置 ip -4 address add 192.168.0.1/24 dev to_jool # 策略路由配置 echo "100 jool" >> /etc/iproute2/rt_tables ip route add 192.168.132.95/32 via 192.168.0.2 dev to_jool table 100 ip rule add to 192.168.132.95/32 table 100 priority 100 # 启用转发 echo 1 | tee /proc/sys/net/ipv6/conf/*/forwarding echo 1 | tee /proc/sys/net/ipv4/conf/*/forwarding #5: 在joolns内启动Jool SIIT modprobe jool_siit ip netns exec joolns sysctl -w net.ipv4.conf.all.forwarding=1 ip netns exec joolns sysctl -w net.ipv6.conf.all.forwarding=1 ip netns exec joolns jool_siit instance add --netfilter --pool6 fd79:db8:ee00::/96 ip netns exec joolns jool_siit eamt add 192.168.132.95 2001:db8:1::44
最后别忘了测试:从服务器192.168.132.85 ping 192.168.132.95,同时在joolns里抓包,确认流量是否被正确翻译到IPv6的2001:db8:1::44。
备注:内容来源于stack exchange,提问作者elysch

