我正在尝试在 OpenWRT 路由器上通过 OpenVPN 设置按 IP 地址过滤的流量的选择性路由
我有一个 OpenVPN 配置文件,并使用 route-nopull 选项来禁用设置默认网关。
以下命令用于将数据包定位到一组 IP 地址,并在 mangle 预路由部分中用 0x1 标记进行标记:
nft add set inet fw4 marker { type ipv4_addr \;}
nft add element inet fw4 marker {40.81.94.43}
nft insert rule inet fw4 mangle_prerouting ip daddr @marker counter meta mark set 0x1
然后我设置了一个 IP 路由表来通过 VPN 网关路由标记的数据包:
ip rule add fwmark 1 table vpn
ip route add default via 10.211.1.118 dev tun_vpn table vpn
由于某种原因,此设置不起作用:尽管 nft 计数器显示数据包已达到标记规则,但流量仅通过默认 wan 网关。
但是如果我明确设置用于 IP 地址的路由表,它就会按预期工作:
ip rule add to 40.81.94.43 table vpn
按预期通过 VPN 网关将流量定向到 40.81.94.43
似乎 nft 没有用 0x1 标记来标记数据包,或者ip rule add fwmark 1
由于某种原因没有捕获它。我遗漏了什么?
答案1
我从这个问题中学到了很多东西,但是由于 nftables 配置对每个人来说都不是“小菜一碟”,所以我想分享我自己的配置,我会尝试尽可能详细地分享,这样有人可能会对如何使用 nftables 做 pbr 有一个更直观的想法:
步骤1,定义一个独立的nft表。
table inet classify {
set pbrips {
type ipv4_addr
elements = { 1.0.0.1, 8.8.4.4,
8.8.8.8 }
}
chain output {
type route hook output priority filter; policy accept;
ip daddr @pbrips counter packets 29795 bytes 3021764 ct mark set 0x00000002
ip daddr @pbrips counter packets 29795 bytes 3021764 meta mark set ct mark
}
chain prerouting {
type filter hook prerouting priority mangle; policy accept;
ip daddr @pbrips counter packets 193712 bytes 60796012 ct mark set 0x00000002
ip daddr @pbrips counter packets 193712 bytes 60796012 meta mark set ct mark
}
}
这里我定义了一个独立的表,叫classify,而不是使用fw4
openwrt 23.05现有的表,我这样做是因为我尝试过直接在fw4
表上操作但是好像没有效果。
在表中我定义了一个名为的 nftset pbrips
,使用一些预定义的 IP(就我而言,我将始终重新路由这些 IP)在这种设置下,每个ip都被设计成路由到另一个接口而不是默认网关,因此叫做policy-based-routing,即pbr。
你可能已经注意到计数器数据包 29795 字节 3021764部分,它是由 nftables 自动生成的,当您创建规则时,您只需要一个裸counter
指令。
由于某些原因,我必须在那里放两条链子,一条output
链子,一条prerouting
链子,请注意每个链中使用的钩子,它们是重新路由流量的关键点,我在这里放置两个链的原因是,如果我只使用输出链,则只有来自 openwrt 路由器本身的流量(与集合中的 3 个 ip 相关)可以重新路由,而使用预路由链,来自我的 LAN 的所有流量都可以正确地重新路由(ps 如果有人知道,请提醒我如何修复它,谢谢!)
步骤2,为pbr添加专用路由表
这是我的/etc/iproute2/rt_tables
:
root@OpenWrt:~# cat /etc/iproute2/rt_tables
#
# reserved values
#
128 prelocal
255 local
254 main
253 default
0 unspec
#
# local
#
#1 inr.ruhep
123 pbr
您可以看到在最后一行我放了一个新表,里面有 id123
和 name pbr
,您可以在这里使用任何 id 和 name ,只是不要使用上面已经存在的,它们是系统级值。您可以直接用 vi 编辑此文件并保存
步骤 3,在表中创建一条路由来接收所有流量
这是我的输出ip route list table 123
(注意:您可以通过表的 ID 或名称来引用表,它们都可以)
root@OpenWrt:~# ip route list table 123
default dev tun0 scope link
root@OpenWrt:~#
如您所见,表 123 中只有一条规则,如果要通过表 123 重新路由所有流量,则此路由就足够了。
第四步,关键的一步,创建ip规则来消耗fwmark
这是我的输出ip rule
root@OpenWrt:~# ip rule
0: from all lookup local
32765: from all fwmark 0x2 lookup pbr
32766: from all lookup main
32767: from all lookup default
root@OpenWrt:~#
这里的关键点在第三行,也就是fwmark 0x2
0x2 部分,这里指的是十六进制值 2,但十六进制值 0x2 相当于十进制值 2,而我的 nft 规则中的值为0x00000002
,因为0x00000002
的十六进制值完全相同0x2
,并且都等于十进制值2
,我建议您始终使用十进制值,例如 1,2,3,而不是 0x1,0x2,0x3,以免混淆(就像我以前做的那样)
步骤 5,使用你喜欢的方法来将元素添加到 nftset
只要您将新元素(即 IP)添加到 nftset 中pbrips
,您就可以进行测试traceroute 8.8.8.8
以验证 pbr 策略是否有效。理论上,您现在可以开始了。
再次感谢 Alexey Martemyanov 提出的问题和回答,这对我学习 pbr 有很大帮助!
答案2
回答我自己的问题,以防它对某人有用:
在找到“[已解决] iproute2 忽略使用 nftables 设置的连接标记”线程后,我已将 nft 规则设置更新为以下内容:
nft insert rule inet fw4 mangle_prerouting ip daddr @marker counter ct mark set 390
nft add rule inet fw4 mangle_prerouting ip daddr @marker counter meta mark set ct mark
成功了!原来我需要设置一个连接标记,而不是元标记