Tan*_*ner 5 networking linux ip-routing interface
我在一台机器上有多个以太网接口,全部位于同一子网上。通常,它们被设置为在单独的虚拟机上运行,并且我了解 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
...
Run Code Online (Sandbox Code Playgroud)
启用arp过滤:
sysctl -w net.ipv4.conf.all.arp_filter=1
Run Code Online (Sandbox Code Playgroud)
实现基于源的路由如下:
将以下内容附加到/etc/iproute2/rt_tables
1 eth0
2 eth1
3 eth2
...
Run Code Online (Sandbox Code Playgroud)
将默认路由添加到表中
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
...
Run Code Online (Sandbox Code Playgroud)
根据源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
...
Run Code Online (Sandbox Code Playgroud)
添加规则
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
...
Run Code Online (Sandbox Code Playgroud)
设备硬件负责根据目标 IP 过滤入口数据包。
就像我说的,此时我可以使用 tcpdump 确认进出主机的流量是通过正确的设备定向的。只要绑定了源 IP,出口多播就会前往正确的设备。从一台设备发送的多播数据包会被所有其他设备接收。我不能做的是从一台设备 ping 到另一台设备。使用 tcpdump,我看到发送设备上的出口 arp 请求和接收设备上的入口 arp 请求,但没有做出任何响应。如果我直接添加 arp 条目,我同样会在两个设备上看到 ping 请求,但没有响应。
更新:
数据可以在分配给接口的 IP 地址之间发送,但网络堆栈不会通过设备将其发送出去。ICMP 和多播数据包正在通过设备,但不会发回响应。
有没有办法:
A) 即使发送到同一主机也强制将数据包从设备中发出?
B) 强制主机响应来自同一主机的 ICMP 请求?
除了各种小问题之外,问题还在于策略路由:必须区分具有完全相同内容的出口数据包的路由和入口数据包的路由:它们使用两条不同的路径。
让我们完全重写它(使用数字作为表值,因此无需更改文件即可轻松测试)。
正确的 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
Run Code Online (Sandbox Code Playgroud)
按照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
Run Code Online (Sandbox Code Playgroud)
添加 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
Run Code Online (Sandbox Code Playgroud)
添加网关路由(现在可以在其表中访问它们):
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
Run Code Online (Sandbox Code Playgroud)
策略路由:必须区别对待从 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
Run Code Online (Sandbox Code Playgroud)
遗憾的是,策略路由规则优先级为 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>
Run Code Online (Sandbox Code Playgroud)
只需将本地表查找移到这些规则之后即可:
ip rule add pref 200 lookup local
ip rule delete pref 0 lookup local
Run Code Online (Sandbox Code Playgroud)
现在给出同一数据包的两条路径:一条用于出口,一条用于入口(移动的本地表仍然解析入口路径):
$ 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
Run Code Online (Sandbox Code Playgroud)
注意: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
Run Code Online (Sandbox Code Playgroud)
后:
$ ip route get from 192.168.1.124 iif eth2 to 192.168.1.125
RTNETLINK answers: Invalid cross-device link
Run Code Online (Sandbox Code Playgroud)
从 IP 地址到同一 IP 地址的 ping 没有意义通过线路,因为它会使用两个相同的接口:从 192.168.1.124 到 192.168.1.124 应该使用,eth0但默认情况下会使用交换机(甚至集线器)永远不要将数据包发送回其来源处(这将是发夹模式),因此,即使是解析目标的 ARP 请求也会失败,无论进行什么配置,甚至在发送或接收回 IP 数据包(失败)之前。这种情况应该像最初一样通过设备放回本地路由表lo。添加 3 个以上的策略规则,或者使用throw在路由表中添加一个“漏洞”,以便规则评估会碰到以下规则,从而到达本地路由表:
前:
$ 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
Run Code Online (Sandbox Code Playgroud)
后:
$ 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>
Run Code Online (Sandbox Code Playgroud)
请注意,系统无法在不首先绑定源地址的情况下发出数据包,因为没有这样的路由,但这是使用 /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
Run Code Online (Sandbox Code Playgroud)
如果需要,人们仍然可以添加默认选择,例如在主路由表中。例如,如果 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
Run Code Online (Sandbox Code Playgroud)
真正默认的默认路由也必须在主表中再次指定(隐式也可以,eth1从之前添加的条目解析):
ip route add default via 192.168.1.11
Run Code Online (Sandbox Code Playgroud)
通过这些设置,主机可以从任何地方的任何接口到达其他系统,只要指定源(否则它将默认为 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
Run Code Online (Sandbox Code Playgroud)
由于首先需要 ARP 请求,因此第一个 ping 时间较长。当然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
Run Code Online (Sandbox Code Playgroud)