使用 nftables mark 将 fwmark 路由到 VPN 网关

使用 nftables mark 将 fwmark 路由到 VPN 网关

我正在尝试在 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,而不是使用fw4openwrt 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 0x20x2 部分,这里指的是十六进制值 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 

成功了!原来我需要设置一个连接标记,而不是元标记

相关内容