使用 nftables 根据 UID 做出路由决策

Ale*_*ßen 3 networking linux firewall nftables

我正在尝试根据原始进程的 uid 来路由数据包。

我知道传出数据包不会命中 PREROUTING。在 iptables 中有一个 MANGLE 表,您可以将这些规则放置在 OUTPUT 链中。nftables 没有 MANGLE 钩子之类的东西。只有 OUTPUT 挂钩。

这是 nftables 的限制吗?在路由决策之前,无法标记源自主机的传出数据包?

nftables v0.7 (Scrooge McDuck)
Linux 4.14.5-1-ARCH #1 SMP PREEMPT Sun Dec 10 14:50:30 UTC 2017 x86_64 GNU/Linux
Run Code Online (Sandbox Code Playgroud)

A.B*_*A.B 5

nftables 中的命名约定可能会误导您,让您认为该功能不存在。

来自nftables 的 wiki

Route,用于在任何相关的 IP 标头字段或数据包标记被修改时重新路由数据包。如果您熟悉 iptables,此链类型提供与mangle 表等效的语义,但仅适用于输出挂钩(对于其他挂钩,请使用类型过滤器 )。ip 和 ip6 表系列支持这一点。

因此,从 LXC 容器中使用 debianstretch 的内核执行所有这些操作4.9.0-4-amd64 #1 SMP Debian 4.9.65-3 (2017-12-03),我将使 uid 1001 成为唯一能够连接到互联网的用户(这里是使用 TCP 的 Google 公共 DNS):

# IP 路由
默认通过 10.0.3.1 dev eth0
10.0.3.0/24 dev eth0 原型内核范围链接 src 10.0.3.66
# pkill -9 dhclient
# ip 路由删除默认值
# ip route add default via 10.0.3.2 dev eth0 # 10.0.3.2不存在,但是路由代码根本需要默认路由才能触发fwmark规则,否则直接“网络不可达”无数据包生成的。
# ip route add default via 10.0.3.1 表 10
# ip 规则添加 fwmark 1 表 10

下面的 mangle 规范命名可以在这里找到(或 /usr/share/doc ...)。-150 的值为NF_IP_PRI_MANGLE

# nft 添加表 ip mangle
# nft '添加链 ip mangle 输出 { 类型路由钩子输出优先级 -150; }'
# nft 添加规则 ip mangle 输出 skuid 1001 计数器标记设置 1
# ID
uid=0(root) gid=0(root) groups=0(root)
# nc -v -n -z 8.8.8.8 53 # 对 10.0.3.2 的 ARP 请求将超时
nc:连接到 8.8.8.8 端口 53 (tcp) 失败:没有到主机的路由
# su-测试
$ ID
uid=1001(测试) gid=1001(测试) groups=1001(测试)
$ nc -v -n -z 8.8.8.8 53
连接8.8.8.8 53端口[tcp/*]成功!

最后一点。有一个关于使用网络命名空间来简化配置的评论,我只能同意:如果没有容器(具有自己的网络命名空间),给出这个示例会更困难。又例如,如果存在使用网络的 suid root 命令,则根据该命令的工作方式,它可能会触发或不触发标记和路由。

更新:由用户连接发起的某些数据包不再属于该用户。这种情况可能发生在连接结束时最后一次ACK确认数据包的情况下,并且当连接过早中止时数据包的情况更常见。这些数据包与所有者不匹配,因此不会收到标记,不会重新路由,这可能会导致传输结束时超时。为了避免这种情况,应该与其他功能结合使用,例如/ (相当于' )。有关 conntrack 标记和等效 iptables 问题及解决方案的更多信息:FINRSTct mark set markmark set ct markiptablesCONNMARK

nftables 标记和 conntrack 标记

Netfilter康马克

Iptables:将传出流量与 conntrack 和所有者相匹配。适用于奇怪的水滴

是否可以在任意 TCP 回复数据包中强制 fwmark 反射?

没有 uid 的 iptables 数据包

在前面的“成功”测试中确实发生了超时nc,但由于命令返回,如果没有网络捕获,它是不可见的。超时发生在对等服务器端。要解决这个问题,请保留相同的路由命令,但将上面的 nft 规则替换为:

# nft add table ip mangle
# nft 'add chain ip mangle output { type route hook output priority -150; }'
# nft flush chain ip mangle output
# nft add rule ip mangle output mark set ct mark counter
# nft add rule ip mangle output mark ne 0 counter accept
# nft add rule ip mangle output skuid 1001 counter mark set 1
# nft add rule ip mangle output ct mark set mark counter
Run Code Online (Sandbox Code Playgroud)

scounter仅用于调试。