Skip to main content
Re:Linked

Linux 上的透明代理:这次是 nftables、cgroups v2 和 systemd.slice

· #devops · 约 2.5k 字
本文距离上次更新已经超过 900 天。因此,其中的信息可能已经过时。

透明代理是本站著名冷饭了。nftables 支持 cgroups v2 也算大事,那就把这饭再炒一次。

Re:Linked 在一年半多之前写了篇用 iptables 等做透明代理的文章。当时有这么几个没解决的问题:

  • 能不能用 nftables
    • 不能。因为 nftables 当时还不支持 cgroups v2。
  • 能不能把 IPv4 和 IPv6 的规则一起处理了?
    • 不能。iptables 在这点分得很开。IPv6 要用 ip6tables 重写一遍。
  • cgroups v2 还要手动开启,好麻烦啊。和 Docker 还不兼容
    • 对啊。

那么这几个问题陆陆续续都有解决,于是就有了这篇文章。

本来十月发的第一篇文章应该是关于谢斯塔,但既然那篇还没写完,就先把这篇比较好写的技术向文章发出来吧。笔者对白毛女主的爱就往后推一推。

「客观情况发生重大变化」

这篇文章写得出来,要多亏了这么几件事:

优势与不足

和其它许多方案,以及上次的方案相比,主要的好处有这么几点:

  • IPv4 和 IPv6 规则几乎可以放在一起
  • nftables 的语法比 iptables 的要好看多得多(个人理解)
  • 不再需要使用 ipset 定义静态地址范围

不过也会产生一些代价:

  • Docker 内容器走全局代理的需要单独配置(因为它的各种规则还在 iptables 那边)
    • (本文暂时不提及关于容器走全局代理的配置。)

示例

XTLS 的文档给出了一份很不错的配置。这里稍作修改和解释:

#!/usr/sbin/nft -f

# 清空之前的 nftables 规则,方便覆盖
flush ruleset

# 定义总是不代理的地址
define RESERVED_IP = {
    10.0.0.0/8,
    100.64.0.0/10,
    127.0.0.0/8,
    169.254.0.0/16,
    172.16.0.0/12,
    192.0.0.0/24,
    224.0.0.0/4,
    240.0.0.0/4,
    255.255.255.255/32,
    # ....
}

table ip trxproxy {
    chain prerouting {
        type filter hook prerouting priority mangle; policy accept;
        # 这里我们并没有配置作为网关的一些设置,所以不处理非本地请求
        iif != "lo" return
        ip daddr $RESERVED_IP return
        ip protocol {tcp, udp} tproxy to 127.0.0.1:7890 meta mark set 0x2333
      }
    chain output {
        type route hook output priority mangle; policy accept;
        ip daddr $RESERVED_IP return
        # cgroup 在这里!
        socket cgroupv2 level 1 "bypassed.slice" return
        ip protocol {tcp, udp} meta mark set 0x2333
    }
}

以及路由配置。记得 fwmark 需要和上文中规则定义的一致:

ip route add local 0/0 dev lo table 100
ip rule add fwmark 0x2333 lookup 100

评论



LIKE