Linux透明网关、nftables+xray tproxy代理

默认分类
5237 2
作为旁路由、透明代理(网关),大多数人可以选择opewnrt+科学插件,可视化及快速上手。
但我的想法是折腾更多的玩法,最终形成了这篇帖子,希望可以帮到其他爱好者--少踩坑

2025年了,之前很纳闷为什么xray tproxy之后,产生了大量的未关闭udp链接,直到我尝试在nft提前放行国内直连IP,
这个问题解决了。当下在用的方案是mosdns(dns分流)+xraytproxy(透明网关)+nftables

小白入门:TProxy 透明代理(ipv4 and ipv6)配置教程

可以参阅上面的文档之后再参考我的方案。

mosdns国内外分流配置:

log:
  level: error

plugins:
  - tag: cache
    type: cache
    args:
      size: 2048
      lazy_cache_ttl: 86400

  - tag: forward_local
    type: forward
    args:
      concurrent: 2
      upstreams:
        - addr: "tls://dot.pub"
          dial_addr: "120.53.53.53"
          enable_pipeline: true
        - addr: "tls://dns.alidns.com"
          dial_addr: "223.5.5.5"
          enable_pipeline: true

  - tag: forward_remote
    type: forward
    args:
      concurrent: 1
      upstreams:
        - addr: "tls://dns.google"
          dial_addr: "8.8.4.4"
          enable_pipeline: true

  - tag: gfw_list # 代理域名
    type: domain_set
    args:
      files:
        - /usr/local/share/v2ray/proxy-list.txt
        - /usr/local/share/v2ray/gfw.txt

  - tag: ad_list # 广告域名
    type: domain_set
    args:
      files:
        - /usr/local/share/v2ray/reject-list.txt

  - tag: main_sequence
    type: sequence
    args:
      - matches: qtype 12 65
        exec: reject 0

      - matches: qname $ad_list
        exec: reject 3

      - exec: $cache
      - matches: has_resp
        exec: accept

      - matches: qname $gfw_list
        exec: prefer_ipv4 $forward_remote
      - matches: has_resp
        exec: accept

      - exec: $forward_local
      - matches: has_resp
        exec: accept

  - tag: udp_server
    type: udp_server
    args:
      entry: main_sequence
      listen: :53

  - tag: tcp_server
    type: tcp_server
    args:
      entry: main_sequence
      listen: :53

nftables配置:

#!/usr/sbin/nft -f

# 清空所有规则
flush ruleset

table inet xray {
        # 本地/私有IPv4地址集合
        set local_ips {
                type ipv4_addr
                flags interval
                elements = { 
                        127.0.0.0/8,    # 本地回环
                        10.0.0.0/8,     # RFC1918私有网络
                        172.16.0.0/12,  # RFC1918私有网络(包含172.17.0.0/16)
                        192.168.0.0/16, # RFC1918私有网络
                        169.254.0.0/16, # 链路本地地址
                        224.0.0.0/4,    # 组播地址
                        240.0.0.0/4,    # 保留地址
                        100.64.0.0/10,  # CGNAT地址 
                        192.0.0.0/24,   # IETF协议分配
                        198.51.100.0/24 # 文档示例地址
                }
        }

        # 本地/私有IPv6地址集合
        set local_ips6 {
                type ipv6_addr
                flags interval
                elements = { 
                        ::1/128,         # 本地回环
                        fc00::/7,        # 唯一本地地址
                        fe80::/10,       # 链路本地地址
                        ff00::/8,        # 组播地址
                        ::ffff:0:0/96,   # IPv4映射地址
                        ::/128,          # 未指定地址
                        2001:db8::/32,   # 文档示例地址
                        2002::/16,       # 6to4地址
                        100::/64         # 保留地址
                }
        }

        # 中国IP地址集合 - 由更新脚本动态填充
        set cnip_v4 { 
                type ipv4_addr
                flags interval
                auto-merge
        }

        set cnip_v6 { 
                type ipv6_addr
                flags interval
                auto-merge
        }

        # 预路由链 - 处理进入系统的包
        chain prerouting {
                type filter hook prerouting priority filter
                policy accept

                # 跳过本地、中国IP的流量以及已标记的流量
                ip daddr @local_ips return
                ip6 daddr @local_ips6 return
                ip daddr @cnip_v4 return
                ip6 daddr @cnip_v6 return
                meta mark 2 return

                # 将TCP和UDP流量重定向到Xray的TPROXY端口
                meta l4proto { tcp, udp } meta mark set 1 tproxy to :12345 accept
        }

        # 输出链 - 处理从本机发出的包
        chain output {
                type route hook output priority filter
                policy accept

                # 跳过本地、中国IP的流量以及已标记的流量
                ip daddr @local_ips return
                ip6 daddr @local_ips6 return
                ip daddr @cnip_v4 return
                ip6 daddr @cnip_v6 return
                meta mark 2 return

                # 标记非直连流量
                meta l4proto { tcp, udp } meta mark set 1 accept
        }

        # 分流链 - 用于处理本地发起但由透明代理接管的连接
        chain divert {
                type filter hook prerouting priority mangle
                policy accept

                # 检测到已建立的TCP连接,设置标记以便重用相同的路径
                meta l4proto tcp socket transparent 1 meta mark set 1 accept
        }
}

# NAT表 - 用于网络地址转换
table inet nat {
        chain postrouting {
                type nat hook postrouting priority 100
                policy accept

                # 将Docker容器网络流量进行源地址转换
                ip saddr 172.17.0.0/16 oif "enp1s0" masquerade
        }
}

策略路由:

ip rule add fwmark 1 table 100
ip -6 rule add fwmark 1 table 106
ip route add local 0.0.0.0/0 dev lo table 100
ip -6 route add local ::/0 dev lo table 106

一些域名IP文件资源

  ["geosite.dat"]="https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat"
  ["geoip.dat"]="https://raw.githubusercontent.com/Loyalsoldier/geoip/release/geoip-only-cn-private.dat"
  ["geoip-asn.dat"]="https://raw.githubusercontent.com/Loyalsoldier/geoip/release/geoip-asn.dat"
  ["direct-list.txt"]="https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/direct-list.txt"
  ["proxy-list.txt"]="https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/proxy-list.txt"
  ["reject-list.txt"]="https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/reject-list.txt"
  ["apple-cn.txt"]="https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/apple-cn.txt"
  ["google-cn.txt"]="https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/google-cn.txt"
  ["gfw.txt"]="https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/gfw.txt"
  ["cn-ip.txt"]="https://github.com/Loyalsoldier/geoip/raw/refs/heads/release/text/cn.txt"
  ["private.txt"]="https://github.com/Loyalsoldier/geoip/raw/refs/heads/release/text/private.txt"

分离cnip的脚本

#!/bin/bash
# --- 配置 ---
CNIP_FILE="/usr/local/share/v2ray/cn-ip.txt"
IPV4_FILE="/usr/local/share/v2ray/china_ipv4.txt"
IPV6_FILE="/usr/local/share/v2ray/china_ipv6.txt"
NFT_TABLE="inet xray"
NFT_SET_V4="cnip_v4"
NFT_SET_V6="cnip_v6"
# --- 配置结束 ---

# 错误处理函数
error_exit() {
    echo "❌ 错误: $1" >&2
    exit 1
}

# 检查必要的文件和命令是否存在
[ -f "$CNIP_FILE" ] || error_exit "$CNIP_FILE 文件不存在"
command -v nft >/dev/null 2>&1 || error_exit "nft 命令未找到,请安装 nftables"
command -v awk >/dev/null 2>&1 || error_exit "awk 命令未找到"

echo "🔄 开始更新 nftables 直连IP..."

# 创建临时文件
TEMP_FILE_V4=$(mktemp) || error_exit "无法创建临时文件"
TEMP_FILE_V6=$(mktemp) || error_exit "无法创建临时文件"

# 确保脚本退出时删除临时文件
trap 'rm -f "$TEMP_FILE_V4" "$TEMP_FILE_V6"; echo "🧹 清理临时文件"; exit' EXIT INT TERM

# 分离IPv4和IPv6地址
echo "🔍 分离IPv4和IPv6地址..."
> "$IPV4_FILE"  # 清空文件
> "$IPV6_FILE"  # 清空文件
awk -v ipv4_file="$IPV4_FILE" -v ipv6_file="$IPV6_FILE" '{
    if ($1 ~ /^[0-9]+\./) 
        print $1 > ipv4_file; 
    else if ($1 ~ /^[0-9a-fA-F:]+/) 
        print $1 > ipv6_file;
}' "$CNIP_FILE" || error_exit "地址分离失败"

# 检查分离后的文件是否为空
[ -s "$IPV4_FILE" ] || echo "⚠️ 警告: 未找到IPv4地址"
[ -s "$IPV6_FILE" ] || echo "⚠️ 警告: 未找到IPv6地址"

# 准备 IPv4 批量添加命令
echo "📝 准备IPv4规则..."
{
    echo "flush set $NFT_TABLE $NFT_SET_V4"
    echo "add element $NFT_TABLE $NFT_SET_V4 {"
    awk '{printf "%s,\n", $1}' "$IPV4_FILE" | sed '$ s/,$//'
    echo "}"
} > "$TEMP_FILE_V4"

# 准备 IPv6 批量添加命令
echo "📝 准备IPv6规则..."
{
    echo "flush set $NFT_TABLE $NFT_SET_V6"
    echo "add element $NFT_TABLE $NFT_SET_V6 {"
    awk '{printf "%s,\n", $1}' "$IPV6_FILE" | sed '$ s/,$//'
    echo "}"
} > "$TEMP_FILE_V6"

# 执行批量更新
echo "🔄 正在应用 IPv4 地址..."
nft -f "$TEMP_FILE_V4" || error_exit "应用IPv4规则失败"

echo "🔄 正在应用 IPv6 地址..."
nft -f "$TEMP_FILE_V6" || error_exit "应用IPv6规则失败"

# 验证规则是否成功应用
IPV4_COUNT=$(wc -l < "$IPV4_FILE")
IPV6_COUNT=$(wc -l < "$IPV6_FILE")
echo "✅ nftables 规则更新成功!IPv4地址: $IPV4_COUNT 条, IPv6地址: $IPV6_COUNT 条"
最后更新 2025-04-04
评论 ( 2 )
OωO
隐私评论
  1. 请问一下dae+sing-box该怎么用debian配置

    1年前美国回复
  2. bensonlai

    101.6.6.6被ban了,方便出个VPS版本的Linux旁路由方案不?

    2年前广东省江门市回复