由于openwrt的防火墙逐步从iptables向nftables升级,官方24.10.2的dnsmasq包默认不将ipset纳入编译选项,只支持nftset, 由此带来v2ray透明代理的配置必须进行升级,此次主要是调整了v2ray的配置和dnsmasq-full的配置。

1)修改/etc/init.d/v2ray


  
#!/bin/sh /etc/rc.common
#
# This is free software, licensed under the GNU General Public License v3.
# See /LICENSE for more information.
#
# To use this file, install chinadns,v2ray,dnsmasq-full,coreutils-nohup,coreutils-paste first
#
#!/bin/sh /etc/rc.common

START=90
USE_PROCD=1

DOMAIN="xxx.com" #需改为实际网址。同时在dnsmasq配置文件中设置nftset=/xxx.com/114.114.114.114
DNS_SERVER="114.114.114.114"
BACKUP_DNS_SERVER="119.29.29.29 223.5.5.5 180.76.76.76"
LOCAL_IP="127.0.0.1"
#CHINADNS和V2RAY端口范围:5354-5355 5356-5357 5358-5359 5360-5361,须搭配对应的chinadns和v2ray配置文件使用
CHINADNS_MIN_PORT="5354"
CHNROUTE_FILE="/etc/chinadns_chnroute.txt"
V2RAY_PORT="1060"
V2RAY_MAX_DNS_PORT="5361"
V2RAY_DNS_PORTS="5357 5359 5361"
V2RAY_BIN="/usr/bin/v2ray"
V2RAY_CONF="/etc/config/v2ray.json"

set_multi_domestic_dns() {
    current_dns_list=`uci get dhcp.@dnsmasq[0].server 2>/dev/null`
    if [ x${DNS_SERVER:0:15} != x${current_dns_list:0:15} ]; then
        echo "[+] 设置使用国内DNS服务器"
        uci -q delete dhcp.@dnsmasq[0].server
        uci add_list dhcp.@dnsmasq[0].server=${DNS_SERVER}
        for dns in $BACKUP_DNS_SERVER; do
            uci add_list dhcp.@dnsmasq[0].server="${dns}"
        done
        uci set dhcp.@dnsmasq[0].noresolv=0
        uci set dhcp.@dnsmasq[0].nohosts=0
        uci commit dhcp
        echo "[+] 重启dnsmasq服务"
        /etc/init.d/dnsmasq restart 1>/dev/null 2>&1
        echo "[✓] 完成"
    fi
}

set_multi_foreign_dns() {
    current_dns_list=`uci get dhcp.@dnsmasq[0].server 2>/dev/null`
    if [ x${LOCAL_IP:0:9} != x${current_dns_list:0:9} ]; then
        echo "[+] 设置使用ChinaDNS DNS服务器"
        chinadns_port=`uci get chinadns.@chinadns[0].port 2>/dev/null`
        chinadns_listen_ipport=${LOCAL_IP}"#"${chinadns_port}
        uci -q delete dhcp.@dnsmasq[0].server
        uci add_list dhcp.@dnsmasq[0].server=${chinadns_listen_ipport}
        for port in $V2RAY_DNS_PORTS; do
            uci add_list dhcp.@dnsmasq[0].server="${LOCAL_IP}#${port}"
        done
        uci set dhcp.@dnsmasq[0].noresolv=1
        uci set dhcp.@dnsmasq[0].nohosts=1
        uci commit dhcp
        echo "[+] 重启dnsmasq服务"
        /etc/init.d/dnsmasq restart 1>/dev/null 2>&1
        echo "[✓] 完成"
    fi
}

create_bypasslist() {
    echo "[*] 创建 inet v2ray 表和 bypasslist 集合"

    # 创建 table(如不存在)
    nft list table inet v2ray 2>/dev/null >/dev/null
    if [ $? -ne 0 ]; then
        nft add table inet v2ray
    fi

    # 创建或清空 set:bypasslist
    if nft list set inet v2ray bypasslist 2>/dev/null >/dev/null; then
        nft delete set inet v2ray bypasslist
    fi

    # 创建 bypasslist 集合
    nft add set inet v2ray bypasslist { type ipv4_addr\; flags interval\;}

    # 添加私有地址段
    echo "[+] 添加内网地址段到 bypasslist"
    nft add element inet v2ray bypasslist { \
        0.0.0.0/8, 10.0.0.0/8, 127.0.0.0/8, \
        169.254.0.0/16, 172.16.0.0/12, \
        192.168.0.0/16, 224.0.0.0/4, 240.0.0.0/4 \
    }

    # 加载国内 IP(来自文件)
    if [ -f "$CHNROUTE_FILE" ]; then
        echo "[+] 加载国内 IP 到 bypasslist(来源: $CHNROUTE_FILE)"
        BATCH_SIZE=1000
        count=0
        batch=""

        echo "[*] 正在批量导入到 nftables..."

        while read -r line; do
            [ -z "$line" ] && continue
            [ "${line#\#}" != "$line" ] && continue

            batch="$batch $line,"
            count=$((count + 1))

            if [ "$count" -ge "$BATCH_SIZE" ]; then
                batch="${batch%,}"
                nft add element inet v2ray bypasslist { $batch }
                count=0
                batch=""
            fi
        done < "$CHNROUTE_FILE"

        if [ -n "$batch" ]; then
            batch="${batch%,}"
            nft add element inet v2ray bypasslist { $batch }
        fi

        echo "[✓] 导入完成"
    else
        echo "[!] 未找到国内 IP 文件: $CHNROUTE_FILE"
    fi

    # 加载 VPS 域名解析结果
    echo "[+] 解析 $DOMAIN 并加入 bypasslist"
    for ip in $(dig +short "$DOMAIN" @"$DNS_SERVER" | grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}'); do
        nft add element inet v2ray bypasslist { $ip }
        echo "    加入 $ip"
    done
    echo "    bypasslist 已载入 $(nft list set inet v2ray bypasslist | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+(/[0-9]+)?' | wc -l) 条目"

    # 创建 nat 类型链
    nft list chain inet v2ray prerouting 1>/dev/null 2>&1 || nft add chain inet v2ray prerouting { type nat hook prerouting priority dstnat\; }
    nft list chain inet v2ray output 1>/dev/null 2>&1 || nft add chain inet v2ray output { type nat hook output priority -100\; }
}

create_gfwlist(){
    echo "[*] 创建 inet v2ray 表和 gfwlist 集合"

    # 创建 table(如不存在)
    nft list table inet v2ray 2>/dev/null >/dev/null
    if [ $? -ne 0 ]; then
        nft add table inet v2ray
    fi

    # 创建或清空 set:gfwlist
    if nft list set inet v2ray gfwlist 2>/dev/null >/dev/null; then
        nft delete set inet v2ray gfwlist
    fi

    # 创建 gfwlist 集合
    nft add set inet v2ray gfwlist { type ipv4_addr\;}

    # 注意dnsmasq配置文件中也有gfwlist的内容,所以需要重新加载,此操作不会直接增加gfwlist条目数,只会在解析网址时动态增加
    /etc/init.d/dnsmasq reload 1>/dev/null 2>&1
    echo "    gfwlist 已载入 $(nft list set inet v2ray gfwlist | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+(/[0-9]+)?' | wc -l) 条目"

    # 创建 nat 类型链
    nft list chain inet v2ray prerouting 1>/dev/null 2>&1 || nft add chain inet v2ray prerouting { type nat hook prerouting priority dstnat\; }
    nft list chain inet v2ray output 1>/dev/null 2>&1 || nft add chain inet v2ray output { type nat hook output priority -100\; }
}

enable_bypasslist_firewall_rules(){
    nft add rule inet v2ray prerouting ip daddr != @bypasslist tcp dport 0-65535 counter redirect to :${V2RAY_PORT} 2>/dev/null
    nft add rule inet v2ray output ip daddr != @bypasslist tcp dport 0-65535 counter redirect to :${V2RAY_PORT} 2>/dev/null
    nft add rule inet v2ray prerouting ip daddr ${LOCAL_IP} udp dport ${CHINADNS_MIN_PORT}-${V2RAY_MAX_DNS_PORT} return 2>/dev/null
    nft add rule inet v2ray output ip daddr ${LOCAL_IP} udp dport ${CHINADNS_MIN_PORT}-${V2RAY_MAX_DNS_PORT} return 2>/dev/null
    nft add rule inet v2ray prerouting ip daddr != @bypasslist udp dport 0-65535 counter redirect to :${V2RAY_PORT} 2>/dev/null
    nft add rule inet v2ray output ip daddr != @bypasslist udp dport 0-65535 counter redirect to :${V2RAY_PORT} 2>/dev/null
}

disable_bypasslist_firewall_rules(){
    nft delete rule inet v2ray prerouting ip daddr != @bypasslist tcp dport 0-65535 counter redirect to :${V2RAY_PORT} 2>/dev/null
    nft delete rule inet v2ray output ip daddr != @bypasslist tcp dport 0-65535 counter redirect to :${V2RAY_PORT} 2>/dev/null
    nft delete rule inet v2ray prerouting ip daddr ${LOCAL_IP} udp dport ${CHINADNS_MIN_PORT}-${V2RAY_MAX_DNS_PORT} return 2>/dev/null
    nft delete rule inet v2ray output ip daddr ${LOCAL_IP} udp dport ${CHINADNS_MIN_PORT}-${V2RAY_MAX_DNS_PORT} return 2>/dev/null
    nft delete rule inet v2ray prerouting ip daddr != @bypasslist udp dport 0-65535 counter redirect to :${V2RAY_PORT} 2>/dev/null
    nft delete rule inet v2ray output ip daddr != @bypasslist udp dport 0-65535 counter redirect to :${V2RAY_PORT} 2>/dev/null
}

enable_gfwlist_firewall_rules(){
    nft add rule inet v2ray prerouting ip daddr @gfwlist tcp dport 0-65535 counter redirect to :${V2RAY_PORT} 2>/dev/null
    nft add rule inet v2ray output ip daddr @gfwlist tcp dport 0-65535 counter redirect to :${V2RAY_PORT} 2>/dev/null
    nft add rule inet v2ray prerouting ip daddr ${LOCAL_IP} udp dport ${CHINADNS_MIN_PORT}-${V2RAY_MAX_DNS_PORT} return 2>/dev/null
    nft add rule inet v2ray output ip daddr ${LOCAL_IP} udp dport ${CHINADNS_MIN_PORT}-${V2RAY_MAX_DNS_PORT} return 2>/dev/null
    nft add rule inet v2ray prerouting ip daddr @gfwlist udp dport 0-65535 counter redirect to :${V2RAY_PORT} 2>/dev/null
    nft add rule inet v2ray output ip daddr @gfwlist udp dport 0-65535 counter redirect to :${V2RAY_PORT} 2>/dev/null
}

disable_gfwlist_firewall_rules(){
    nft delete rule inet v2ray prerouting ip daddr @gfwlist tcp dport 0-65535 counter redirect to :${V2RAY_PORT} 2>/dev/null
    nft delete rule inet v2ray output ip daddr @gfwlist tcp dport 0-65535 counter redirect to :${V2RAY_PORT} 2>/dev/null
    nft delete rule inet v2ray prerouting ip daddr ${LOCAL_IP} udp dport ${CHINADNS_MIN_PORT}-${V2RAY_MAX_DNS_PORT} return 2>/dev/null
    nft delete rule inet v2ray output ip daddr ${LOCAL_IP} udp dport ${CHINADNS_MIN_PORT}-${V2RAY_MAX_DNS_PORT} return 2>/dev/null
    nft delete rule inet v2ray prerouting ip daddr @gfwlist udp dport 0-65535 counter redirect to :${V2RAY_PORT} 2>/dev/null
    nft delete rule inet v2ray output ip daddr @gfwlist udp dport 0-65535 counter redirect to :${V2RAY_PORT} 2>/dev/null
}

disable_v2ray_rules() {
    if nft list table inet v2ray 2>/dev/null >/dev/null; then
        nft flush table inet v2ray
    else
        nft add table inet v2ray
    fi
    
    # 创建或清空 set:gfwlist
    if nft list set inet v2ray gfwlist 2>/dev/null >/dev/null; then
        nft delete set inet v2ray gfwlist
    fi

    # 创建 gfwlist 集合
    nft add set inet v2ray gfwlist { type ipv4_addr\;}
    set_multi_domestic_dns
    echo "ingfw" > /tmp/v2raymode.txt
    
}

stop_service()  {
    echo "[+] 停止 v2ray 服务"
    disable_v2ray_rules
}

enable_v2ray_rules(){
    running_v2ray_mode=$(cat /tmp/v2raymode.txt 2>/dev/null | tr -d '\r')
    v2ray_mode=`uci get advancedconfig.@rules[0].v2raymode 2>/dev/null`

    if [ x${v2ray_mode} = x${running_v2ray_mode} ]; then
        echo "[+] v2ray模式未变化"
    else
        echo "[+] v2ray模式已变化"
        echo "[+] 设置${v2ray_mode}模式中"
        if [ "${v2ray_mode}" = "outlands" ]; then
            disable_gfwlist_firewall_rules
            create_bypasslist
            enable_bypasslist_firewall_rules
            set_multi_foreign_dns
        
        elif [ "${v2ray_mode}" = "gfwlist" ]; then
            disable_bypasslist_firewall_rules
            create_gfwlist
            enable_gfwlist_firewall_rules
            set_multi_foreign_dns
        
        elif [ "${v2ray_mode}" = "ingfw" ]; then
            disable_v2ray_rules
        fi
        echo "${v2ray_mode}" > /tmp/v2raymode.txt
    fi
}

start_service()  {
    echo "[+] 启动 v2ray 服务"
    mkdir -p /var/log/v2ray
    ulimit -n 65535
    procd_open_instance
    procd_set_param command $V2RAY_BIN run -config $V2RAY_CONF
    procd_set_param file $V2RAY_CONF
    procd_set_param respawn
    procd_set_param stdout 1
    procd_set_param stderr 1
    procd_set_param pidfile /var/run/v2ray.pid
    enable_v2ray_rules
    procd_close_instance
}

service_triggers() {
    procd_add_reload_trigger "advancedconfig"
}
      

2)修改/etc/dnsmasq.d/下的conf文件:

将原来的所有


ipset=/xxxx.com/gfwlist

全部修改为:


nftset=/xxxx.com/4#inet#v2ray#gfwlist

需要注意的是,conf文件不能有windows换行符,因为nftset对于格式非常敏感,之前windows换行符对于ipset没有问题,但是对于nftset就无法正常执行。

3)对应的/etc/config/chinadns文件:


config chinadns
	option chnroute '/etc/chinadns_chnroute.txt'
	option addr '0.0.0.0'
	option enable '1'
	option port '5355'
	option bidirectional '0'
	option server '114.114.114.114,127.0.0.1:5354'

4)对应的/root/start_multi_chinadns.sh文件:


#!/bin/sh
# 启动多个 chinadns 实例并使用不同的国内 DNS 和端口
# 依赖:chinadns、v2ray、dnsmasq-full、coreutils-nohup

killall chinadns 2>/dev/null
/etc/init.d/chinadns restart
sleep 1

start_chinadns() {
  local port=$1
  local dns=$2
  local v2port=$3
  nohup /usr/bin/chinadns -m -b 0.0.0.0 -p "$port" \
    -s "$dns",127.0.0.1:"$v2port" -c /etc/chinadns_chnroute.txt \
    >/dev/null 2>&1 &
  sleep 1
}

start_chinadns 5357 119.29.29.29 5356
start_chinadns 5359 223.5.5.5    5358
start_chinadns 5361 180.76.76.76 5360

5)对应的/etc/config/v2ray配置:


{
  "inbounds": [
    {    
      "protocol": "dokodemo-door",
      "port": 1060,
      "listen":"0.0.0.0",
      "sniffing": {
        "enabled": false,
        "destOverride": ["http", "tls"]
      },
       "settings": {
         "network": "tcp,udp",
         "followRedirect": true 
       },
       "streamSettings": {
            "sockopt": {
            "tproxy": "redirect" 
           }
       }
    },
    {
      "protocol": "dokodemo-door",
      "listen":"0.0.0.0",
      "port": 5354,
      "settings": {
        "address": "8.8.8.8",
        "port": 53,
        "network": "udp",
        "timeout": 0,
        "followRedirect": false
      }
    },
    {
      "protocol": "dokodemo-door",
      "listen":"0.0.0.0",
      "port": 5356,
      "settings": {
        "address": "8.8.8.8",
        "port": 53,
        "network": "udp",
        "timeout": 0,
        "followRedirect": false
      }
    },
    {
      "protocol": "dokodemo-door",
      "listen":"0.0.0.0",
      "port": 5358,
      "settings": {
        "address": "1.1.1.1",
        "port": 53,
        "network": "udp",
        "timeout": 0,
        "followRedirect": false
      }
    },
    {
      "protocol": "dokodemo-door",
      "listen":"0.0.0.0",
      "port": 5360,
      "settings": {
        "address": "8.8.4.4",
        "port": 53,
        "network": "udp",
        "timeout": 0,
        "followRedirect": false
      }
    }
  ],
  "outbounds": [
    {
      "protocol": "vless",
      "tag": "proxy",
      "settings": {
        "vnext": [
          {
            "address": "xxx.com", #需改为实际网址
            "port": 443,
            "users": [
              {
                "id": "UUID", #需改为实际UUID
                "encryption": "none"
              }
            ]
          }
        ]
      },
      "streamSettings": {
        "network": "ws",
        "security": "tls",
        "wsSettings": {
          "path": "/path"  #需改为实际路径
        },
        "tcpSettings": {
          "allowInsecureCiphers": false
        }
      }
    }
  ]
}


参考: 1.chatgpt 2.https://www.abcde.im/archives/112.html