![同一子网上的多个接口之间无法通信](https://linux22.com/image/669902/%E5%90%8C%E4%B8%80%E5%AD%90%E7%BD%91%E4%B8%8A%E7%9A%84%E5%A4%9A%E4%B8%AA%E6%8E%A5%E5%8F%A3%E4%B9%8B%E9%97%B4%E6%97%A0%E6%B3%95%E9%80%9A%E4%BF%A1.png)
我在一台机器上有多个以太网接口,都在同一个子网上。通常这些接口被设置为在单独的虚拟机上运行,我理解 Linux 所施加的限制,如下所述这里,但我的任务是尝试让它在一台主机上工作。我已经能够配置它们,以便主机的进出流量通过正确的设备进行引导。我无法做的是从一台设备到另一台设备的通信。以下是我迄今为止对设备的配置:
设置静态 IP 地址:
ip addr add 192.168.1.124 dev eth0
ip addr add 192.168.1.125 dev eth1
ip addr add 192.168.1.126 dev eth2
...
启用 arp 过滤:
sysctl -w net.ipv4.conf.all.arp_filter=1
按如下方式实现基于源的路由:
将以下内容附加到/etc/iproute2/rt_tables
1 eth0
2 eth1
3 eth2
...
将默认路线添加到表
ip route add default via 192.168.1.11 table eth0
ip route add default via 192.168.1.11 table eth1
ip route add default via 192.168.1.11 table eth2
...
根据源 IP 通过特定设备添加子网路由
ip route add 192.168.1.0/24 dev eth0 src 192.168.1.124 table eth0
ip route add 192.168.1.0/24 dev eth0 src 192.168.1.124 table eth1
ip route add 192.168.1.0/24 dev eth0 src 192.168.1.124 table eth2
...
添加规则
ip rule add from 192.168.1.124 table eth0
ip rule add from 192.168.1.124 table eth1
ip rule add from 192.168.1.124 table eth2
...
设备硬件负责根据目标 IP 过滤入口数据包。
就像我说的,此时我可以使用 tcpdump 确认主机的进出流量是通过正确的设备引导的。只要源 IP 已绑定,出口多播就会转到正确的设备。从一个设备发送的多播数据包会被所有其他设备接收。我无法从一个设备 ping 到另一个设备。使用 tcpdump,我看到发送设备上的出口 arp 请求和接收设备上的入口 arp 请求,但没有响应。如果我直接添加 arp 条目,我同样会在两个设备上看到 ping 请求,但没有响应。
更新:
数据可以在分配给接口的 IP 地址之间发送,但网络堆栈不会通过设备发送数据。ICMP 和多播数据包确实会通过设备,但不会发回任何响应。
有没有办法:
A)即使向同一主机发送数据包,也强制将其传出设备?
B)强制主机响应来自同一主机的 ICMP 请求?
答案1
除了各种小问题之外,问题还在于策略路由:必须区分出站数据包的路由和入口数据包的路由。确切地相同的内容:它们使用了两种不同的路径。
让我们完全重写它(使用数字作为表值,这样无需更改文件即可轻松测试)。
需要正确的 ARP 处理来遵循策略路由并将 ARP 流量绑定到正确的接口:
sysctl -w net.ipv4.conf.eth0.arp_filter=1
sysctl -w net.ipv4.conf.eth1.arp_filter=1
sysctl -w net.ipv4.conf.eth2.arp_filter=1
添加地址,按照OP的方式:
ip address add 192.168.1.124/32 dev eth0
ip address add 192.168.1.125/32 dev eth1
ip address add 192.168.1.126/32 dev eth2
添加 LAN 路由,每个表一个不同的路由(OP 粘贴了相同的内容)。无需提示源(每个源都是不同的地址):它由稍后添加的路由规则选择。
ip route add 192.168.1.0/24 dev eth0 table 124
ip route add 192.168.1.0/24 dev eth1 table 125
ip route add 192.168.1.0/24 dev eth2 table 126
添加网关路由(现在它们可以在其表内访问):
ip route add default via 192.168.1.11 table 124
ip route add default via 192.168.1.11 table 125
ip route add default via 192.168.1.11 table 126
策略路由:必须区别对待从 192.168.1.124 到 192.168.1.125 的两个方向的数据包:当数据包通过 发出时eth0
,以及当同一个数据包通过 接收时eth1
。iif lo
是特殊语法,指示仅对发出的数据包应用策略路由规则(而不是任何情况,包括从接口接收的数据包)。 使用特定首选项(这对以下步骤很有用):
ip rule add pref 124 iif lo from 192.168.1.124 lookup 124
ip rule add pref 125 iif lo from 192.168.1.125 lookup 125
ip rule add pref 126 iif lo from 192.168.1.126 lookup 126
可惜的是,策略路由规则优先级为 0 的本地表阻止了这些规则的应用。例如,这里没有任何变化:
$ ip route get from 192.168.1.124 to 192.168.1.125
local 192.168.1.125 from 192.168.1.124 dev lo table local uid 1000
cache <local>
只需移动当地的表格查找后这些规则:
ip rule add pref 200 lookup local
ip rule delete pref 0 lookup local
现在为同一个数据包提供了两条路径:一条用于出口,一条用于入口(移动的当地的表仍然解析入口路径):
$ ip route get from 192.168.1.124 to 192.168.1.125
192.168.1.125 from 192.168.1.124 dev eth0 table 124 uid 1000
cache
$ ip route get from 192.168.1.124 iif eth1 to 192.168.1.125
local 192.168.1.125 from 192.168.1.124 dev lo table local
cache <local> iif eth1
注意:arp_filter
将选择正确的接口进行回复(即:它不会是eth2
上述示例,而是始终eth1
),因为只有正确的接口才会回复 ARP 查询。
可以选择通过以下方式进一步执行严格反向路径转发使用rp_filter
:
之前(使用意外路径):
$ ip route get from 192.168.1.124 iif eth2 to 192.168.1.125
local 192.168.1.125 from 192.168.1.124 dev lo table local
cache <local> iif eth2
sysctl -w net.ipv4.conf.eth0.rp_filter=1
sysctl -w net.ipv4.conf.eth1.rp_filter=1
sysctl -w net.ipv4.conf.eth2.rp_filter=1
后:
$ ip route get from 192.168.1.124 iif eth2 to 192.168.1.125
RTNETLINK answers: Invalid cross-device link
从一个 IP 地址到同一个 IP 地址的 ping 没有必要通过网络进行,因为它会使用两次相同的接口:从 192.168.1.124 到 192.168.1.124 应该使用,eth0
但交换机(甚至集线器)默认情况下永远不会将数据包发回原处(这将是发夹模式),因此,无论配置如何,解析目的地的 ARP 请求都会失败,甚至在发送或接收 IP 数据包之前(失败)。这种情况应该放回到当地的设备上的路由表lo
与最初一样。要么再添加 3 条策略规则,要么使用以下方法在路由表中添加“漏洞”扔因此规则评估将被提升到以下规则,从而到达本地路由表:
前:
$ ip route get from 192.168.1.124 to 192.168.1.124
192.168.1.124 from 192.168.1.124 dev eth0 table 124 uid 1000
cache
ip route add throw 192.168.1.124/32 table 124
ip route add throw 192.168.1.125/32 table 125
ip route add throw 192.168.1.126/32 table 126
后:
$ ip route get from 192.168.1.124 to 192.168.1.124
local 192.168.1.124 from 192.168.1.124 dev lo table local uid 1000
cache <local>
请注意,由于没有这样的路由,系统无法在不先绑定源地址的情况下发出数据包,但这是使用 /32 地址时 OP 的选择:
$ ip route get 192.168.1.127
RTNETLINK answers: Network is unreachable
$ ip route get from 192.168.1.126 to 192.168.1.127
192.168.1.127 from 192.168.1.126 dev eth2 table 126 uid 1000
cache
例如,仍然可以添加默认选项主要的如果需要,请配置路由表。例如,如果 192.168.1.125 是默认值:
# ip route add 192.168.1.0/24 dev eth1
# ip route get 192.168.1.127
192.168.1.127 dev eth1 src 192.168.1.125 uid 0
cache
真正默认的默认路由也必须在主表中再次指定(隐式的也可以,eth1
可以从之前添加的条目中解析):
ip route add default via 192.168.1.11
使用这些设置,只要指定了源,主机就可以从其任何接口访问任何地方的其他系统(否则它将默认为 192.168.1.125 eth1
),并且还可以解决 OP 的目标,可以通过网络将自身从一个地址 ping 到另一个不同的地址。使用网络命名空间进行模拟:
# ip neigh flush all
# ping -c3 -I 192.168.1.124 192.168.1.125
PING 192.168.1.125 (192.168.1.125) from 192.168.1.124 : 56(84) bytes of data.
64 bytes from 192.168.1.125: icmp_seq=1 ttl=64 time=0.087 ms
64 bytes from 192.168.1.125: icmp_seq=2 ttl=64 time=0.059 ms
64 bytes from 192.168.1.125: icmp_seq=3 ttl=64 time=0.063 ms
--- 192.168.1.125 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2027ms
rtt min/avg/max/mdev = 0.059/0.069/0.087/0.012 ms
这里第一次 ping 的时间比较长,因为首先需要 ARP 请求。当然tcpdump
可以证实这一点(此处捕获了所涉及的接口):
# tcpdump -ttttt -l -e -n -s0 -p -i eth0
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
00:00:00.000000 fe:c7:45:36:a1:84 > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 42: Request who-has 192.168.1.125 tell 192.168.1.124, length 28
00:00:00.000042 ce:59:ff:a1:96:ff > fe:c7:45:36:a1:84, ethertype ARP (0x0806), length 42: Reply 192.168.1.125 is-at ce:59:ff:a1:96:ff, length 28
00:00:00.000045 fe:c7:45:36:a1:84 > ce:59:ff:a1:96:ff, ethertype IPv4 (0x0800), length 98: 192.168.1.124 > 192.168.1.125: ICMP echo request, id 59125, seq 1, length 64
00:00:00.000061 ce:59:ff:a1:96:ff > fe:c7:45:36:a1:84, ethertype IPv4 (0x0800), length 98: 192.168.1.125 > 192.168.1.124: ICMP echo reply, id 59125, seq 1, length 64
00:00:01.003101 fe:c7:45:36:a1:84 > ce:59:ff:a1:96:ff, ethertype IPv4 (0x0800), length 98: 192.168.1.124 > 192.168.1.125: ICMP echo request, id 59125, seq 2, length 64
00:00:01.003135 ce:59:ff:a1:96:ff > fe:c7:45:36:a1:84, ethertype IPv4 (0x0800), length 98: 192.168.1.125 > 192.168.1.124: ICMP echo reply, id 59125, seq 2, length 64
00:00:02.027155 fe:c7:45:36:a1:84 > ce:59:ff:a1:96:ff, ethertype IPv4 (0x0800), length 98: 192.168.1.124 > 192.168.1.125: ICMP echo request, id 59125, seq 3, length 64
00:00:02.027190 ce:59:ff:a1:96:ff > fe:c7:45:36:a1:84, ethertype IPv4 (0x0800), length 98: 192.168.1.125 > 192.168.1.124: ICMP echo reply, id 59125, seq 3, length 64
00:00:05.099215 ce:59:ff:a1:96:ff > fe:c7:45:36:a1:84, ethertype ARP (0x0806), length 42: Request who-has 192.168.1.124 tell 192.168.1.125, length 28
00:00:05.099248 fe:c7:45:36:a1:84 > ce:59:ff:a1:96:ff, ethertype ARP (0x0806), length 42: Reply 192.168.1.124 is-at fe:c7:45:36:a1:84, length 28
^C
10 packets captured
10 packets received by filter
0 packets dropped by kernel
# tcpdump -ttttt -l -e -n -s0 -p -i eth1
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on eth1, link-type EN10MB (Ethernet), snapshot length 262144 bytes
00:00:00.000000 fe:c7:45:36:a1:84 > ff:ff:ff:ff:ff:ff, ethertype ARP (0x0806), length 42: Request who-has 192.168.1.125 tell 192.168.1.124, length 28
00:00:00.000022 ce:59:ff:a1:96:ff > fe:c7:45:36:a1:84, ethertype ARP (0x0806), length 42: Reply 192.168.1.125 is-at ce:59:ff:a1:96:ff, length 28
00:00:00.000031 fe:c7:45:36:a1:84 > ce:59:ff:a1:96:ff, ethertype IPv4 (0x0800), length 98: 192.168.1.124 > 192.168.1.125: ICMP echo request, id 59125, seq 1, length 64
00:00:00.000041 ce:59:ff:a1:96:ff > fe:c7:45:36:a1:84, ethertype IPv4 (0x0800), length 98: 192.168.1.125 > 192.168.1.124: ICMP echo reply, id 59125, seq 1, length 64
00:00:01.003098 fe:c7:45:36:a1:84 > ce:59:ff:a1:96:ff, ethertype IPv4 (0x0800), length 98: 192.168.1.124 > 192.168.1.125: ICMP echo request, id 59125, seq 2, length 64
00:00:01.003113 ce:59:ff:a1:96:ff > fe:c7:45:36:a1:84, ethertype IPv4 (0x0800), length 98: 192.168.1.125 > 192.168.1.124: ICMP echo reply, id 59125, seq 2, length 64
00:00:02.027154 fe:c7:45:36:a1:84 > ce:59:ff:a1:96:ff, ethertype IPv4 (0x0800), length 98: 192.168.1.124 > 192.168.1.125: ICMP echo request, id 59125, seq 3, length 64
00:00:02.027170 ce:59:ff:a1:96:ff > fe:c7:45:36:a1:84, ethertype IPv4 (0x0800), length 98: 192.168.1.125 > 192.168.1.124: ICMP echo reply, id 59125, seq 3, length 64
00:00:05.099052 ce:59:ff:a1:96:ff > fe:c7:45:36:a1:84, ethertype ARP (0x0806), length 42: Request who-has 192.168.1.124 tell 192.168.1.125, length 28
00:00:05.099241 fe:c7:45:36:a1:84 > ce:59:ff:a1:96:ff, ethertype ARP (0x0806), length 42: Reply 192.168.1.124 is-at fe:c7:45:36:a1:84, length 28
^C
10 packets captured
10 packets received by filter
0 packets dropped by kernel