通过特定接口 (tum1) 路由用户流量

jam*_*mes 3 ubuntu routing iptables

问题:如何为特定用户通过 tun1 路由流量?

到目前为止我已经尝试过:我遵循:

1:iptables 将所有流量转发到接口

sudo iptables -t nat -A POSTROUTING -m owner --uid-owner user1 -j SNAT --to-source 192.168.1.1
Run Code Online (Sandbox Code Playgroud)

结果:流量没有到达tun1,我可以在wireshark中看到它,并且“host google.com”没有给出任何结果。

2:

sudo iptables -t nat -A POSTROUTING -m owner --uid-owner test --out-interface tun1
Run Code Online (Sandbox Code Playgroud)

结果:流量通过默认路由,即不经过tun1(vpn)即可到达互联网。

更多信息:

ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
3: enx0c5b8f279a64: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 1000
    link/ether 0c:5b:8f:27:9a:64 brd ff:ff:ff:ff:ff:ff
    inet 192.168.8.100/24 brd 192.168.8.255 scope global dynamic noprefixroute enx0c5b8f279a64
       valid_lft 53043sec preferred_lft 53043sec
    inet6 fe80::5f5a:e5de:ae93:e80b/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever
9: tun1: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 500
    link/none 
    inet 10.0.0.1/24 scope global tun1
       valid_lft forever preferred_lft forever
    inet6 fe80::c626:a226:a66c:2b0/64 scope link stable-privacy 
       valid_lft forever preferred_lft forever
Run Code Online (Sandbox Code Playgroud)
ip route list
default via 192.168.8.1 dev enx0c5b8f279a64 proto dhcp metric 100 
10.0.0.0/24 dev tun1 proto kernel scope link src 10.0.0.1 
169.254.0.0/16 dev enx0c5b8f279a64 scope link metric 1000 
192.168.8.0/24 dev enx0c5b8f279a64 proto kernel scope link src 192.168.8.100 metric 100 
linkdown
Run Code Online (Sandbox Code Playgroud)

A.B*_*A.B 8

我完全同意德克的评论:使用网络命名空间可以使路由更容易,无需特殊情况。但我希望这里的答案与平常不同,它需要 Linux 内核 >= 4.10。

关于失败的尝试:POSTROUTING顾名思义,是在路由决策完成之后进行的。这条链永远不会改变路线。应该用于本地发起的流量的是mangle/OUTPUT(以及 nftables 上的特殊type route hook output链)。然后,它仍然需要通过使用标记与路由堆栈进行交互并纠正极端情况,也可能通过使用而CONNMARK不是仅使用MARK. 要让它正常工作仍然很困难。

无论如何,这里有一个不依赖而是依赖于 2016 年内核 4.10中出现的iptables网络路由堆栈功能的方法:uidrange

添加对每个 UID 路由的支持。它允许管理员配置规则,例如:
# ip rule add uidrange 100-200 lookup 123。自 5.0 起,所有 Android 设备都在使用此功能。它主要用于实施每个应用程序的路由策略(在 Android 上,每个应用程序都有自己的 UID),而不必在 iptables 中重新路由数据包,这会破坏 getsockname() 和 MTU/MSS 计算,并且通常会破坏端到端结束连接提交, 提交,提交

由于路由堆栈将立即选择正确的路由,从而选择匹配的源 IP,因此不需要SNAT此 IP。仍然需要一个小的“不干净”部分:它需要在tun设备上使用松散的反向路径过滤器,因为虽然目标用户获得与其他用户不同的路由表,但从该接口返回的返回流量不属于任何用户,因此不会使用此路由表。

在此示例中,user1的 UID 将为 1234,并且为备用路由任意选择的表 1001234。

将相关主路由复制/更改到表1001234并放宽路由。每次重新建立隧道时都必须重新添加这些路由和设置,因为当接口消失和/或关闭时,路由和设置会丢失:

ip route add table 1001234 10.0.0.0/24 dev tun1 src 10.0.0.1
ip route add table 1001234 default dev tun1 #no need of a gateway on a layer 3 interface
sysctl -w net.ipv4.conf.tun1.rp_filter=2
Run Code Online (Sandbox Code Playgroud)

这只需要一次,然后将立即影响用户:

ip rule add uidrange 1234-1234 lookup 1001234
Run Code Online (Sandbox Code Playgroud)

不要添加任何iptablesnat 规则。当然仍然需要足够的防火墙规则。请注意,如果用户查询本地服务(例如:127.0.0.1:53 上可用的本地 DNS 缓存守护进程),守护进程发出的查询将不会使用隧道,因为守护进程具有不同的 uid。