在不使用原始套接字的情况下,Linux 上是否有办法强制网络数据包首先物理发送到网关,即使目标地址是绑定到本地接口的地址?
我的系统有一个活动接口 ,eno1
它被分配了一个192.168.1.1
带有/20
掩码的 IPv4 。网关有地址192.168.0.1
。我尝试使用 来添加路由ip route add 192.168.1.0/24 via 192.168.0.1
,该路由具有最高的路由特异性192.168.1.1
。但是调用traceroute 192.168.1.1
仍然只显示一个跃点,表明它没有去任何地方。我希望它显示第一跳192.168.0.1
,然后是192.168.1.1
。未遵循路由的其他证据是发送数据包SO_TIMESTAMPING
会导致丢失硬件时间戳,这表明数据包实际上并没有放在网络上。
如果这是一个 XY 问题,我正在尝试构建一个类似 ping 的测量工具,用于测量我的 ISP 的 CMTS 的往返延迟和数据包丢失,但那里的路由器对 ICMP 响应使用速率限制,所以我可以t 尽可能频繁地测量延迟。此外,来自我网络上本地设备的 ping 计入速率限制,导致虚假丢弃数据包(尽管我想我可以阻止以 CMTS 作为目标或 TTL=1 的数据包转发)。请注意,虽然我使用我自己的路由器作为第一跳在我的私有网络上的系统上本地测试它,但实际上我将在路由器本身上运行它,.1.1
用我的公共 IPv4 地址和地址替换.0.1
地址与 CMTS 的上游路由器地址。
我的想法是向上游路由器发送一个数据包,其目的地是我自己的公共 IP,这有望导致它被直接发送回我自己的路由器,每条腿都遍历一次,但在 ISP 看来是通用转发的流量,而不是 CMTS 直接响应的东西。
理想情况下,该解决方案可以配置为超级用户一次,然后由用户空间作业使用,即不需要以超级用户身份运行该工具(因此希望避免原始套接字)。
创建一个单独的网络命名空间:
在物理接口之上创建一个虚拟以太网接口,然后将其移动到 netns:
配置您的 IP 地址:
运行程序:
(实际上并不需要“持久”命名空间——您可以使用
unshare --net <program>
,并通过 PID 将虚拟接口移动到其中——但这不太方便。)在路由之前,所有数据包都会根据 中设置的规则进行检查
ip -4 rule
。默认情况下,第一条规则首先通过特殊的“本地”路由表(其中包含所有“本地”IP 地址的环回路由)发送它们。仅当“本地”表中没有匹配项时才使用“主”路由表中的路由。
setcap cap_net_raw=ep
如果它是 CLI 工具,则仅授予该工具 CAP_NET_RAW 权限,如果它AmbientCapabilities=
是服务,则使用 systemd 的权限。然后,您可以使用原始套接字而无需获得任何其他 root 权限。前者(可执行文件上的 setcap)经常被工具使用
ping
,mtr
所以这实际上并不是什么新东西。(嵌入式文件系统可能不支持文件级“功能”,但在这种情况下,您仍然可以设置 setuid 位。它需要更加注意安全性,因为您的工具即使在由普通用户运行时也可以获得完全的 root 权限。)
setcap/suid 仅适用于已编译的二进制可执行文件,不适用于解释的脚本可执行文件。