g00*_*dds 2 linux routing iproute
在我的机器上,我有两个接口:(wlan0
默认路由)和tun0
. 该tun0
接口只是一个本地网络,它的 IP 范围是172.16.150.0/24
,我的机器(机器 A)的 IP 地址是172.16.150.1
,另一台机器(机器 B)的 IP 地址是172.16.150.128
。我设置了一个 wifi 热点,它为我创建了另一个界面ap0
。我想ap0
通过机器B路由来自接口的所有流量(因此网关应该是172.16.150.128
)。
$ ip route
default via 192.168.0.1 dev wlan0 proto dhcp src 192.168.0.179 metric 1024
172.16.150.0/24 dev tun0 proto kernel scope link src 172.16.150.1 metric 1024
192.168.0.0/24 dev wlan0 proto kernel scope link src 192.168.0.179 metric 1024
192.168.0.1 dev wlan0 proto dhcp scope link src 192.168.0.179 metric 1024
192.168.12.0/24 dev ap0 proto kernel scope link src 192.168.12.1
Run Code Online (Sandbox Code Playgroud)
此时,由于默认路由是192.168.0.1
,因此它将所有流量路由wlan0
到我的家庭路由器的接口。
我不是一个经验丰富的 Linux 用户,所以我不确定如何让 Linux 内核通过ap0
网关路由所有流量172.16.150.128
,但这就是我尝试过的:
$ ip route add default 192.168.12.0/24 via 172.16.150.128
Error: either "to" is duplicate, or "192.168.12.0/24" is a garbage.
Run Code Online (Sandbox Code Playgroud)
在这里,我尝试让内核192.168.12.0/24
通过网关路由来自子网的所有流量172.16.150.128
。
$ ip route add 192.168.12.0/24 via 172.16.150.128
RTNETLINK answers: File exists
Run Code Online (Sandbox Code Playgroud)
与之前的命令相同,但没有这个default
词。我读到过ip addr flush dev ap0
可能有帮助的地方,但它会重置接口及其 IP 地址,因此我需要通过手动恢复 IP 地址ip addr add
或重新启动 wifi 热点。
我认为这不是正确的方法,因为我不想刷新接口,而是想将路由更改default
为特定网关。
我怎样才能做到这一点?
简单的路由在这里是不够的。简单路由关心目的地。但这里的目标是根据来源改变路线。这样做称为策略路由。在 Linux 上,这是通过使用其他选择器(不仅仅是目的地)来实现的,例如源 IP 地址或源数据包的传入接口来选择备用路由表。这些备用路由表可以具有其他路由,包括其他默认路由,最终为数据包选择与主路由表中的常用路由不同的路由。
这通常与 some + some的组合一起使用,并根据要解决的问题量身定制选择。通常会有基于源的选择器来进行不同的处理,同时会有(并且只能有)用于这种情况的替代目标。ip rule
add ... lookup TABLE
ip route add ...
table TABLE
ip rule ...
ip route ...
因此,对于这种情况,可以像下面这样做。
准备备用路由表(使用任意表 1000)
该表应包含所需的所有内容,因此将手动复制主路由表的部分内容
ip route add 192.168.12.0/24 dev ap0 table 1000
ip route add 172.16.150.0/24 dev tun0 table 1000
Run Code Online (Sandbox Code Playgroud)
当然,为了实现目标,还需要备用默认路由:
ip route add default via 172.16.150.128 dev tun0 table 1000
Run Code Online (Sandbox Code Playgroud)
为两个相关接口选择备用路由表
ip rule add iif ap0 lookup 1000
ip rule add iif tun0 lookup 1000
Run Code Online (Sandbox Code Playgroud)
路由规则应如下所示:
# ip rule
0: from all lookup local
32764: from all iif tun0 lookup 1000
32765: from all iif ap0 lookup 1000
32766: from all lookup main
32767: from all lookup default
Run Code Online (Sandbox Code Playgroud)
这解决了机器上的路由问题(但请参阅下一部分有关远程系统路由或使用 NAT 的内容):
来自的任何数据包ap0
将使用备用路由表并将被发送到tun0
这包括发送到互联网的流量,该流量将通过 172.16.150.128。详细信息:专门发送到该计算机的流量实际上将首先使用本地路由表,因此仍将照常工作。
来自的任何数据包都tun0
将使用备用路由表
(如果发送到本系统,实际上本地路由表会先路由到本系统)
如果发送到 192.168.12.0/24 它将使用ap0
有关详细信息:在其他情况下,路由查找会将流量发送回 172.16.150.128
但这种情况在实践中绝对不应该发生。
如果ap0
或tun0
曾经下降然后上升,则表1000中的相关路由将丢失并且必须重新添加。
还剩下一个问题:如果 172.16.150.0/24 LAN 上的系统对 192.168.12.0/24 一无所知,它们将永远不会向该系统 (172.16.150.1) 发回回复流量。他们可能会使用自己的默认网关,即 172.16.150.128。同样,172.16.150.128 可能会将 192.168.12.0/24 的任何流量发送到其自己的上游网关,远离该计算机,而不是通过该计算机。
要解决这个问题:
让 172.16.150.0/24 中的其他系统知道该 LAN(首选)
只需在 172.16.150.128 上添加路由就足够了:172.16.150.0/24 中的其他系统将尝试通过 172.16.150.128 发送数据包,除了通过 172.16.150.1 路由数据包之外,还会发送 ICMP 重定向以告诉这些其他系统发送他们直接在那里。如果 172.16.150.128 系统也运行 Linux,这应该很简单:
ip route add 192.168.12.0/24 via 172.16.150.1
Run Code Online (Sandbox Code Playgroud)
所有系统也可以直接添加完全相同的路线。如果通过 DHCP 配置,则应使用 DHCP 选项 121(对于较旧的 Windows 客户端可能使用选项 249)将此设置添加到 DHCP 配置中,但这超出了本答案的范围。
否则,如果之前的更改无法完成(例如:无法控制 172.16.150.128),请使用 NAT
如果无法在 172.16.150.0/24(尤其是 172.16.150.128)中的系统上设置正确的路由,那么仍然可以使用 NAT 将所有 192.168.12.0/24 折叠到可到达的 172.16.150.1 中。在机器上添加:
iptables -t nat -A POSTROUTING -s 192.168.12.0/24 -o tun0 -j MASQUERADE
Run Code Online (Sandbox Code Playgroud)
此方法允许从 192.168.12.0/24 到 172.16.150.0/24 并通过 172.16.150.128 的流量沿着回复数据包到达 Internet,但不允许从除此之外的任何其他位置访问 192.168.12.0/24 上的任何服务机器。需要针对特定端口/服务进行其他 NAT 设置才能创建例外。