前言

在 PVE 虚拟化环境中,本人为特定业务分配了一台 LXC 容器并有全局代理的需求。初衷是利用 TUN 模式接管网卡,但受限于宿主机未开启内核 TUN 支持,且考虑到通过 Tailscale 远程维护时重启宿主机存在失联风险,最终决定采用对内核侵入性更小、无需虚拟网卡的 TProxy 透明代理方案。

工具

nftables
sing-box (https://sing-box.sagernet.org) 或者其他代理工具

本教程采用 sing-box 作为示例,由于 sing-box 频繁 break change 配置文档,仅推荐爱折腾且有能力阅读文档的人使用。

基础知识补充

TProxy 即 Transparent Proxy。广义上指代一种网络代理技术,核心的特征在于“透明”,即客户端不能感知到代理的存在。在 TProxy 模式下,防火墙在 Prerouting 阶段识别特定的流量,并在不修改数据包目标地址的前提下,通过内核标记与策略路由,将本应转发出的数据包强制递交给本地的监听进程。

sing-box 配置模板

本配置模板在 sing-box version 1.13.11 测试下可用。

{
  "log": {
    "level": "info"
  },
  "dns": {
    "servers": [
      {
        "tag": "local-dns",
        "type": "udp",
        "server": "223.5.5.5"
      },
      {
        "tag": "proxy-dns",
        "type": "tls",
        "server": "8.8.8.8"
      }
    ],
    "rules": [
      {
        "query_type": [
          "A",
          "AAAA"
        ],
        "server": "proxy-dns"
      }
    ]
  },
  "inbounds": [
    {
      "type": "tproxy",
      "tag": "tproxy-in",
      "listen": "::",
      "listen_port": 12345
    },
    {
      "type": "direct",
      "tag": "dns-in",
      "listen": "127.0.0.1",
      "listen_port": 53
    }
  ],
  "outbounds": [
    {
      "type": "shadowsocks",
      "tag": "proxy",
      "server": "",
      "server_port": 11451,
      "method": "2022-blake3-aes-256-gcm",
      "password": "",
      "detour": ""
    },
    {
      "type": "direct",
      "tag": "direct"
    }
  ],
  "route": {
    "default_domain_resolver": "local-dns",
    "rules": [
      {
        "port": 53,
        "action": "hijack-dns"
      },
      {
        "ip_cidr": [
          "223.5.5.5"
        ],
        "outbound": "direct"
      },
      {
        "outbound": "proxy"
      }
    ],
    "auto_detect_interface": true
  },
  "experimental": {
    "cache_file": {
      "enabled": true
    }
  }
}

如果需要配置代理链,在落地节点同层级添加 "detour": "<tag>" 即可。 DNS 需要代理出站同上。

操作流程

确保你已经安装了 nftables 和 sing-box:

如果没有

sudo apt update
sudo apt install nftables -y
curl -fsSL https://sing-box.app/install.sh | sh

首先,配置 sing-box 暴露 TProxy 和 DNS 入站。

模板示例:

"inbounds": [
      {
        "type": "tproxy",
        "tag": "tproxy-in",
        "listen": "::",
        "listen_port": 12345
      },
      {
        "type": "direct",
        "tag": "dns-in",
        "listen": "127.0.0.1",
        "listen_port": 53
  }
]

其余部分不做过多阐述。

接下来配置 nftables。

vim /etc/nftables.conf

添加以下内容:

table inet singbox {
    set private_ips {
        type ipv4_addr
        flags interval
        elements = { 10.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 }
    }

    chain prerouting {
        type filter hook prerouting priority mangle; policy accept;
        
        ct direction reply return
        iifname "lo" meta mark 1 udp dport 53 tproxy to :53 accept
        iifname "lo" meta mark 1 meta l4proto { tcp, udp } tproxy to :12345 accept
    }

    chain output {
        type route hook output priority mangle; policy accept;

        ip daddr @private_ips return
        fib daddr type local return
        
        udp dport 53 meta mark set 1
        meta l4proto { tcp, udp } meta mark set 1
    }
}

保存后,执行 nft -c -f /etc/nftables.conf 检查语法是否有问题,随后执行 nft -f /etc/nftables.conf 加载配置文件。

如果你在使用 systemd 管理的 linux 系统,可以执行 systemd enable nftables.service 使 nftables 开机自启动。

最后,添加策略路由。

ip rule add fwmark 1 lookup 100
ip route add local default dev lo table 100

所有被打上特定标记的数据包,会被强行捕获并转交给本地回环设备(lo),从而进入本机的监听进程。在本教程中,nftables 会给符合条件的数据包打上标记,从而使得匹配的包走编号为 100 的自定义路由表。

针对 Debian / Ubuntu 系统,可以配置 /etc/network/interfaces 使策略路由配置持久化:

auto eth0
iface eth0 inet dhcp
    post-up ip rule add fwmark 1 lookup 100
    post-up ip route add local default dev lo table 100

注意修改 eth0 为自己的真实出站网卡。

在终端中执行 curl ipinfo.io,现在应该可以看到出站 IP 已经是你的代理 IP 了。

话题

评论

评论加载中…