Linux下强制本地目标数据包走外部以太网接口及解决ICMP Ping回复问题
Linux下强制本地目标数据包走外部以太网接口及解决ICMP Ping回复问题
首先得搞清楚你遇到的核心问题:Linux内核默认会把所有配置在本机的IP地址归为本地路由(local table),所以当你从本机一个IP发往另一个本机IP时,内核会直接走lo接口转发,完全忽略你配置的普通路由表条目——这就是为什么你抓包看不到流量经过交换机的原因。
下面分两步解决你的问题:
一、强制跨接口流量走外部交换机
要绕开内核的本地路由逻辑,我们需要结合策略路由和内核参数调整:
1. 开启允许本地地址路由到外部接口
首先修改内核参数,让内核允许发往本机IP的数据包通过外部网卡转发,而不是仅限lo:
# 临时生效 sysctl -w net.ipv4.conf.all.route_localnet=1 sysctl -w net.ipv4.conf.enp1s0f0.route_localnet=1 sysctl -w net.ipv4.conf.enp1s0f1.route_localnet=1
2. 配置策略路由规则
我们需要给每个网卡的源IP指定专属的路由表,强制对应流量从指定网卡出站:
- 首先在路由表配置文件里添加自定义表(方便识别):
echo "100 enp1s0f0-table" >> /etc/iproute2/rt_tables echo "101 enp1s0f1-table" >> /etc/iproute2/rt_tables - 添加策略路由规则和路由条目:
# 让从enp1s0f0的IP发出的流量使用自定义表100 ip rule add from 172.16.0.100 table enp1s0f0-table # 给表100添加子网路由,指定从enp1s0f0出站 ip route add 172.16.0.0/16 dev enp1s0f0 src 172.16.0.100 table enp1s0f0-table # 同理配置enp1s0f1 ip rule add from 172.16.1.100 table enp1s0f1-table ip route add 172.16.0.0/16 dev enp1s0f1 src 172.16.1.100 table enp1s0f1-table
3. 验证配置
现在执行以下命令,应该能看到流量不再走lo了:
ip route get from 172.16.0.100 to 172.16.1.100
正常输出应该显示dev enp1s0f0而非dev lo。
二、解决ICMP Ping无回复的问题
你提到ping能发送包但收不到回复,这和内核的反向路径过滤(rp_filter)、ARP行为配置有关,按以下步骤调整:
1. 关闭反向路径过滤
反向路径过滤会检查数据包的源IP是否符合入站网卡的路由,这里我们需要关闭严格检查:
# 临时生效 sysctl -w net.ipv4.conf.all.rp_filter=0 sysctl -w net.ipv4.conf.enp1s0f0.rp_filter=0 sysctl -w net.ipv4.conf.enp1s0f1.rp_filter=0
2. 调整ARP行为避免地址混淆
因为两个网卡在同一子网,内核可能会混淆ARP请求/响应的绑定,需要调整参数让每个网卡只处理自己的IP:
# 临时生效 sysctl -w net.ipv4.conf.all.arp_ignore=1 sysctl -w net.ipv4.conf.all.arp_announce=2 sysctl -w net.ipv4.conf.enp1s0f0.arp_ignore=1 sysctl -w net.ipv4.conf.enp1s0f0.arp_announce=2 sysctl -w net.ipv4.conf.enp1s0f1.arp_ignore=1 sysctl -w net.ipv4.conf.enp1s0f1.arp_announce=2
arp_ignore=1:只响应目标IP是当前网卡配置IP的ARP请求arp_announce=2:发送ARP请求时,仅使用当前网卡的IP作为源IP
3. 允许外部接口接收本机IP的数据包
确保内核允许从外部网卡接收发往本机IP的数据包:
# 临时生效 sysctl -w net.ipv4.conf.all.accept_local=1 sysctl -w net.ipv4.conf.enp1s0f0.accept_local=1 sysctl -w net.ipv4.conf.enp1s0f1.accept_local=1
三、配置持久化(重启后生效)
上面的配置都是临时的,要让重启后依然生效:
1. 保存sysctl参数
创建/etc/sysctl.d/99-custom-routing.conf文件,写入以下内容:
net.ipv4.conf.all.route_localnet=1 net.ipv4.conf.enp1s0f0.route_localnet=1 net.ipv4.conf.enp1s0f1.route_localnet=1 net.ipv4.conf.all.rp_filter=0 net.ipv4.conf.enp1s0f0.rp_filter=0 net.ipv4.conf.enp1s0f1.rp_filter=0 net.ipv4.conf.all.arp_ignore=1 net.ipv4.conf.all.arp_announce=2 net.ipv4.conf.enp1s0f0.arp_ignore=1 net.ipv4.conf.enp1s0f0.arp_announce=2 net.ipv4.conf.enp1s0f1.arp_ignore=1 net.ipv4.conf.enp1s0f1.arp_announce=2 net.ipv4.conf.all.accept_local=1 net.ipv4.conf.enp1s0f0.accept_local=1 net.ipv4.conf.enp1s0f1.accept_local=1
执行以下命令加载配置:
sysctl --system
2. 持久化策略路由
创建systemd服务来开机自动配置策略路由:
- 创建
/etc/systemd/system/policy-routing.service文件:[Unit] Description=Custom Policy Routing Setup After=network.target [Service] Type=oneshot ExecStart=/bin/bash -c "ip rule add from 172.16.0.100 table enp1s0f0-table; ip rule add from 172.16.1.100 table enp1s0f1-table; ip route add 172.16.0.0/16 dev enp1s0f0 src 172.16.0.100 table enp1s0f0-table; ip route add 172.16.0.0/16 dev enp1s0f1 src 172.16.1.100 table enp1s0f1-table" ExecStop=/bin/bash -c "ip rule del from 172.16.0.100 table enp1s0f0-table; ip rule del from 172.16.1.100 table enp1s0f1-table" RemainAfterExit=yes [Install] WantedBy=multi-user.target - 启用并启动服务:
systemctl daemon-reload systemctl enable --now policy-routing.service
现在你再测试telnet -b 172.16.0.100 172.16.1.100 22或者ping -I enp1s0f0 172.16.1.100,应该能看到流量经过交换机,并且ping能收到回复了。
备注:内容来源于stack exchange,提问作者Donlon




