使用“ip”命令创建路由时,全局作用域怎么会无效?

使用“ip”命令创建路由时,全局作用域怎么会无效?

我正在尝试创建静态 NAT,但是当我运行该命令时ip route add nat 172.31.19.02 via 10.0.2.2,它给出了错误Error: Invalid scope.,并且在指定全局范围时给出了相同的错误。我正在尝试复制上面描述的内容使用 iproute2 进行无状态 NAT页。

我的网络设置由同一子网上的两个物理接口(ens5、ens6)和一个用于我的 tinc vpn (vpn) 的虚拟接口组成。可以从 tinc 接口访问地址 10.0.2.2。目标是将流量从 转发172.31.19.0210.0.2.2

据我了解IP地址文档页面global应为“在任何地方有效”。这是否不正确?

的相关部分ip a

2: ens5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether [...]
    inet 172.31.19.01/20 brd 172.31.31.255 scope global ens5
       valid_lft forever preferred_lft forever
[...]
3: ens6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether [...]
    inet 172.31.19.02/20 brd 172.31.31.255 scope global ens6
       valid_lft forever preferred_lft forever
[...]
4: vpn: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 500
    link/none
    inet 10.0.2.1/24 scope global homeforward
       valid_lft forever preferred_lft forever
[...]

我的路由表:

$ ip r
default via 172.31.16.1 dev ens5 proto static
10.0.2.0/24 dev homeforward proto kernel scope link src 10.0.2.1
172.31.16.0/20 dev ens6 proto kernel scope link src 172.31.19.02
172.31.16.0/20 dev ens5 proto kernel scope link src 172.31.19.01
$ ip r ls table 1000
default via 172.31.16.1 dev ens5 proto static
172.31.19.01 dev ens5 proto static scope link
$ ip r ls table 1001
default via 172.31.16.1 dev ens6 proto static
172.31.19.02 dev ens6 proto static scope link

答案1

Linux 的路由无状态 NAT 又名“IP NAT 哑”不再起作用,原因很简单:手册页告诉:

警告:Linux 2.6 不再支持路由 NAT。

所以像这样的例子这个:

[root@masq-gw]# ip route add nat 205.254.211.17 via 192.168.100.17
[root@masq-gw]# ip rule add nat 205.254.211.17 from 192.168.100.17
[root@masq-gw]# ip route flush cache
[root@masq-gw]# ip route show table all | grep ^nat
nat 205.254.211.17 via 192.168.100.17  table local  scope host
[root@masq-gw]# ip rule show
0:      from all lookup local 
32765:  from 192.168.100.17 lookup main map-to 205.254.211.17 
32766:  from all lookup main 
32767:  from all lookup 253

将不再工作了。

该功能已添加到内核中2.1.15(1996)和在内核 2.6.9 中删除(2004)(但可能之前有一些内核):

<[email protected]>
  [IPV4]: Kill remnant of ip_nat_dumb

  This line in net/ipv4/Makefile was left behind when the rest of the
  dumb NAT option was taken out.

  Signed-off-by: Herbert Xu <[email protected]>
  Signed-off-by: David S. Miller <[email protected]>

解释在备用无状态 NAT 中给出,使用tc nat在内核 2.6.24 中重新添加:

以前我们有无状态 NAT 功能,该功能已集成到 IPv4 路由子系统中。只要 NAT 在子网到子网的基础上工作,这样 NAT 规则的数量相对较少,这就是一个很好的解决方案。原因是对于 SNAT,基于路由的系统必须通过规则执行线性扫描。

如果规则数量很大,则需要对路由子系统进行重大改造才能使其切实可行。


TC

这是一个基本的我制作的 DNAT 示例。进行无状态NAT的接口是ens5(我不会将您的设置与同一 LAN 中的两个网卡一起使用:如果没有额外的设置,将会出现与以下相关的其他问题ARP通量和反向路径过滤。看来您已经意识到这一点,因为您有额外的路由表,但让我们保持这个示例简单),其上的本地地址是 172.31.19.1 和 172.31.19.2。任何入口到 172.31.19.2 的流量被 DNAT 到目的地 10.0.2.2,任何出口来自 10.0.2.2 的流量被 SNAT 到源 172.31.19.2。正如通常所做的那样,普里奥队列盘使用它是因为它的简单性,而不是因为它的优先特性。

tc qdisc add dev ens5 ingress
tc filter add dev ens5 ingress protocol ip matchall \
   action nat ingress 172.31.19.2/32 10.0.2.2/32

tc qdisc add dev ens5 root handle 1: prio
tc filter add dev ens5 parent 1: protocol ip matchall \
   action nat egress 10.0.2.2/32 172.31.19.2/32

可能会与 netfilter 的状态连接跟踪发生不可预见的交互。


nftables

也可以使用 nftables 执行相同的操作,如中所述nftables 维基

nft add table ip natdumb

nft add chain ip natdumb prerouting '{ type filter hook prerouting priority -350; policy accept; }'
nft add rule ip natdumb prerouting ip daddr 172.31.19.2 ip daddr set 10.0.2.2

nft add chain ip natdumb postrouting '{ type filter hook postrouting priority 350; policy accept; }'
nft add rule ip natdumb postrouting ip saddr 10.0.2.2 ip saddr set 172.31.19.2

同样,可能会与 netfilter 的 conntrack 进行交互。notrack如果没有加载或至少在当前名称空间中激活 netfilter NAT 内核模块,我删除了任何可能使其仍然工作的内容(同时notrack将所有回复数据包视为NEW流而不是ESTABLISHED)。请随意尝试。

答案2

添加路由时,内核会检查它是否可以通过较低范围访问新范围,因为路由网关必须在同一 L2(数据链路层)连接上直接可达。

这个答案(https://superuser.com/a/1389304)对这个范围概念以及为什么/何时需要设置它有一个很好的快速澄清:

这些路由是您告诉 Linux 内核您所在的子网的方式。

当您添加 IP 地址时,此信息不会存储在隐藏的“我当前的子网”字段中;而是存储在隐藏的“我当前的子网”字段中。相反,它总是转换为没有指定网关的“范围链接”路由(也称为“设备路由”或“接口路由”),并且每当内核需要确定某个地址是否可直接访问时,它只执行路由表检查。

通常,一旦您配置了 IP 地址,这些路由就会自动添加 - 例如,运行 ip addr add 192.168.1.5/24 会分配 IP 地址 192.168.1.5 并为 192.168.1.0/24 创建子网路由。所以正常使用时不需要添加这些路由。

但是当你盲目地“删除所有路由”时,你最终也会删除这些自动创建的路由,并且内核的“这个地址是否在我的子网中”检查不再起作用。这就是为什么您最终必须手动重新添加路由。

(内核需要在 ip Route add 期间执行此检查,因为路由网关(下一跳)必须在同一 L2 连接上直接可达 - 它们不能位于另一个网关后面。也就是说,网关必须位于您的子网中。

路由范围是表达此限制的通用机制:新路由的下一跳需要通过具有较低范围的现有路由可达。换句话说,您必须先经过本地主机(链接范围),然后才能到达远程主机(全局范围)。)

编辑

但这还不够:我一直在尝试让它在测试环境中运行,但到目前为止还没有成功。Error: Invalid scope.也不断发生。

相关内容