首先介绍我想最终达到的目的,以便判断能否和你需求匹配。再去简单介绍下所用的程序。
大陆 IP/网站直连 + 海外域名/IP 全部走代理 + 部分海外白名单域名直连
大陆网站/IP 直连:无论是通过域名解析的大陆 IP,还是某些应用程序硬编码的 IP 或者其他方式下发的大陆 IP 进行直连。
海外域名/IP 全部走代理:无论在不在 gfwlist 的域名,包括任何海外 IP 走代理。
部分海外白名单域名直连:包括 pt tracker 域名、需要直连的服务器域名,即使 IP 在海外也能够直连。(和上条冲突,例外)
这里就不一步步写我的测试和部署逻辑了,直接附上最终可用的成果,过程中遇到的问题将在最后问题列表追加解析。
我的 dns 解析程序选择使用 chinadns 来处理国内域名和海外域名,通过设置两个不同的 DNS 解析服务器,分别解析来避免得到污染过的 IP 地址。
国内域名可以以最快的速度从 dnspod 拿到有效解析,海外域名也能够从 1.1.1.1 拿到正确没有污染的 IP 地址。
选用它,是因为配置文件比 smartdns 简单,单文件体积也小很多。
只是这个程序作者写的文档不是很明白,处于初次接触的人很难快速搞明白解析逻辑和配置文件的逻辑,后面我将以简单的方式告知你。
下载,可根据你的实际情况选择对应的二进制文件
https://github.com/zfl9/chinadns-ng/releases
wget https://github.com/zfl9/chinadns-ng/releases/download/2024.12.22/chinadns-ng+wolfssl@x86_64-linux-musl@x86_64_v2@fast+lto
mv chinadns-ng+wolfssl@x86_64-linux-musl@x86_64_v2@fast+lto /usr/bin/chinadns
chmod +x /usr/bin/chinadns
/etc/chinadns/config.conf
# 监听地址和端口
bind-addr 0.0.0.0
bind-port 5335
# 国内上游、可信上游
china-dns 119.29.29.29
trust-dns tcp://1.1.1.1
# 域名列表,用于分流
chnlist-file /etc/chinadns/chnlist.txt
gfwlist-file /etc/chinadns/gfwlist.txt
# chnlist-first
group white
group-dnl /etc/chinadns/white.txt
group-upstream 1.0.0.1
group-ipset whiteip
# 收集 tag:chn、tag:gfw 域名的 IP
add-tagchn-ip chnip,chnip6
add-taggfw-ip gfwip,gfwip6
# 用于测试 tag:none 域名的 IP (国内上游)
ipset-name4 chnroute
ipset-name6 chnroute6
# dns 缓存
cache 4096
cache-stale 86400
cache-refresh 20
# verdict 缓存 (用于 tag:none 域名)
verdict-cache 4096
no-ipv6 tag:none@ip:non_china
no-ipv6 tag:gfw
white.txt
tracker.m-team.cc
daydream.dmhy.best
china-dns 119.29.29.29 配置大陆域名解析上游、trust-dns tcp://1.1.1.1 配置 gfwlist 域名和其他域名解析上游
大陆域名、gfw 域名来源是什么?
答: chnlist-file /etc/chinadns/chnlist.txt 来源于这个配置文件,同样 gfwlist.txt 是 gfw 域名来源。
海外域名、其他域名来源是什么?
答:不在大陆域名列表的网站、不在 gfwlist 的域名有非常之多,所以当域名都不在上述列表时,将通过两台服务器分别查询。
如果 IP 在大陆,则 DNS 回答响应大陆 IP。
如果 IP 在海外,则 DNS 回答响应 海外 IP。
如果两台服务器解析都不一样,则以海外输出的 IP 为准,以避免大陆 DNS 污染的问题,这也就是配置项为什么是 trust-dns(信任的 DNS 上游) 。
收集 IP 功能是什么?
比如配置中的 add-tagchn-ip chnip,chnip6,是将大陆域名的解析结果存入 ipset 中,如果是 IPV4 则存进 chnip,如果是 IPV6 则进 chnip6.
add-taggfw-ip 同理。
需要注意:add-tagchn-ip 和 add-taggfw-ip 这两个参数项是固定用法,不是可变的,比如 add-tagwhite-ip 这个是错误的。
将 IP 收集起来后,你就可以使用 iptables 进行一些代理或者放行操作。
ipset-name 是什么?
ipset-name4 chnroute 和 ipset-name6 chnroute6 所配置的值都是一个 ipset 集合名字。
它预设了一些大陆的 IP 段,程序将域名解析成 IP 后,要通过与这个 chnroute 集合匹配,如果匹配上了则代表这是大陆的 IP,如果没有匹配上则它就是海外 IP,来决定是否将这个 IP 写入 chnip ,进而去分流。
tag:是什么?
比如 tag 是程序内置的一种标签集合表达方式
固定的有:
tag:gfw 来源于 gfwlist-file 配置的域名列表
tag:chn 来源于 chnlist-file 配置的域名列表。
还有 tag:none 是即不属于任意 tag 的域名列表。
可变的有:
tag:white 比如上文配置中 white 就是由 group {name} 去配置的名字,才能在后面配置中引用。属于自定义组/tag 配置。
no-ipv6 如何配置?
这里配置的是想要忽略 ipv6 解析的规则列表。
大陆域名希望直连,哪怕 IPV6 速度也不慢,也为了能够远程连接穿透等需求这里希望能够正确返回 IPV6。所以这里不能配置 no-ipv6。
海外域名希望屏蔽 IPV6,因为海外 IPV6 路由很差劲,二者服务器也不一定能够支持 IPV6,所以在这里全部屏蔽。
白名单域名希望能够直连,因为这里是 pt tracker 希望服务端能够正确识别到本机的 IPV4 和 IPV6 而不是代理服务器,但这里实际 IP 又是海外的,所以有一些冲突。
最终的配置解答
no-ipv6 tag:gfw 忽略 gfw 域名中所有 IPV6 解析。
no-ipv6 tag:none@ip:non_china 忽略 none 域名列表中且 IP 解析是非大陆的 IP。
tag:none 是一个特殊的组/tag,它是不存在于任何预设组的列表,即不存在于(chnlist, gfwlist, white.txt)的组。
这里的逻辑是反向的,理解起来有点别扭。
原本需求和配置的关系变成了:
海外所有 IP 忽略 IPV6 (但 white.txt 例外) = gfwlist + none (海外 IP)
到这一步,先忽略后面的代理和路由。域名匹配都能够完成正确解析。
举例说明:
查询 taobao.com 响应大陆 IP 和 大陆 IPV6,通过 dnspod 解析,后续也会直连。
查询 google.com 响应海外 IP,没有 IPV6,通过 1.1.1.1 解析,因为在 gfwlist 中,被 no-ipv6 忽略。
查询 tracker.m-team.cc 响应海外 IP 和海外 IPV6,通过 1.1.1.1 解析,后续也会直连,因为在 white.txt 配置了,没有经过 no-ipv6 处理。
/etc/init.d/chinadns
#!/bin/sh /etc/rc.common
START=01
STOP=90
USE_PROCD=1
PROG=/usr/bin/chinadns
start_service(){
procd_open_instance [chinadns]
procd_set_param command /usr/bin/chinadns # service executable that has to run in **foreground**.
procd_append_param command --config /etc/chinadns/config.conf # append command parameters
procd_set_param respawn ${respawn_threshold:-3600} ${respawn_timeout:-5} ${respawn_retry:-5}
procd_set_param limits core="unlimited" # If you need to set ulimit for your process
procd_set_param file /etc/chinadns/config.conf # /etc/init.d/your_service reload will restart the daemon if these files have changed
procd_set_param stdout 1 # forward stdout of the command to logd
procd_set_param stderr 1 # same for stderr
procd_set_param user root # run service as user nobody
#procd_set_param user nobody # run service as user nobody
procd_set_param pidfile /var/run/chinadns.pid # write a pid file on instance start and remove it on stop
procd_set_param term_timeout 60 # wait before sending SIGKILL
procd_close_instance
}
启动和开机自启
chmod +x /etc/init.d/chinadns
/etc/init.d/chinadns start
/etc/init.d/chinadns enable
很强的多合一代理程序,不必多介绍。这里主要是讲解客户端的使用方式,服务器你可以使用任意常见稳定的代理程序,两边都是 xray 也可以。
我的分流规则也都是参考 xray 来的,客户端粘性很高。
下载 xray
mkdir /etc/chinadns/xray
cd /etc/chinadns/xray && wget https://github.com/XTLS/Xray-core/releases/download/v24.12.18/Xray-linux-64.zip
unzip Xray-linux-64.zip
/etc/chinadns/xray/config.json
{
"log": {
"loglevel": "warning",
"access": "none",
"error": "error.log"
},
"routing": {
"domainStrategy": "AsIs",
"rules": [{
"type": "field",
"inboundTag": ["all-in"],
"port": 53,
"outboundTag": "dns-out"
}, {
"type": "field",
"ip": [
"geoip:private"
],
"outboundTag": "block"
}, {
"type": "field",
"domain": [
"geosite:category-ads-all"
],
"outboundTag": "block"
}
]
},
"inbounds": [{
"port": 12345,
"protocol": "dokodemo-door",
"settings": {
"network": "tcp,udp",
"followRedirect": true
},
"streamSettings": {
"sockopt": {
"tproxy": "tproxy"
}
}
}, {
"tag": "http2",
"port": 5556,
"listen": "0.0.0.0",
"protocol": "http",
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
},
"settings": {
"auth": "noauth",
"udp": true,
"allowTransparent": false
}
}, {
"tag": "socks",
"port": 5555,
"listen": "0.0.0.0",
"protocol": "socks",
"sniffing": {
"enabled": true,
"destOverride": [
"http",
"tls"
]
},
"settings": {
"auth": "noauth",
"udp": true,
"allowTransparent": false
}
}
],
"outbounds": [{
"tag": "proxy",
"protocol": "vmess",
"settings": {
"vnext": [{
"address": "x.x.x.x",
"port": 80,
"users": [{
"id": "*************************",
"alterId": 0,
"email": "[email protected]",
"security": "auto"
}
]
}
]
},
"streamSettings": {
"sockopt": {
"mark": 2
},
"network": "tcp"
},
"mux": {
"enabled": true,
"concurrency": 8
}
}, {
"protocol": "freedom",
"tag": "direct",
"streamSettings": {
"sockopt": {
"mark": 2
}
}
}, {
"protocol": "blackhole",
"tag": "block"
}, {
"tag": "dns-out",
"protocol": "dns",
"settings": {
"address": "1.0.0.1"
},
"proxySettings": {
"tag": "proxy"
},
"streamSettings": {
"sockopt": {
"mark": 2
}
}
}
]
}
这里的核心配置是
在 rules 增加捕获所有 53 端口的流量,为它设置 "dns-out" 的出口。并在 outbounds 出口新增 dns 协议并配置 sockopt.mark=2
在 outbounds 主要出口以及任意你可能存在的多个出口,均配置 sockopt.mark=2
配置 mark = 2 的目的就是避免流量回环,无限重置,后面将在 iptables 放行 mark = 2 的流量。
启动脚本
/etc/chinadns/xray/xray -config /etc/chinadns/xray/config.json
由于我的 openwrt 比较旧,无法安装大量依赖以供新的 luci 插件使用,由于 bios 限制,也无法刷机最新的 openwrt,刷 bios 也怕炸机。还是尽量避免折腾这种主网络,同时由于我只熟悉 iptables 所以不去选择 nftables,逻辑应该相同。。
当你掌握了这种路由配置方式后,你可以在任何 openwrt 路由器中折腾代理程序和分流,实用性更强。
proxy.sh
#!/bin/bash
ip route add local default dev lo table 100
ip rule add fwmark 1 table 100
#代理局域网
iptables -t mangle -N XRAY
iptables -t mangle -A XRAY -d 119.29.29.29/32 -j RETURN
iptables -t mangle -A XRAY -d 10.0.0.0/8 -j RETURN
iptables -t mangle -A XRAY -d 100.64.0.0/10 -j RETURN
iptables -t mangle -A XRAY -d 127.0.0.0/8 -j RETURN
iptables -t mangle -A XRAY -d 169.254.0.0/16 -j RETURN
iptables -t mangle -A XRAY -d 172.16.0.0/12 -j RETURN
iptables -t mangle -A XRAY -d 192.0.0.0/24 -j RETURN
iptables -t mangle -A XRAY -d 192.168.1.0/24 -j RETURN
iptables -t mangle -A XRAY -d 192.168.0.0/24 -j RETURN
iptables -t mangle -A XRAY -d 224.0.0.0/4 -j RETURN
iptables -t mangle -A XRAY -d 240.0.0.0/4 -j RETURN
iptables -t mangle -A XRAY -d 255.255.255.255/32 -j RETURN
iptables -t mangle -A XRAY -m set --match-set whiteip dst -j RETURN
iptables -t mangle -A XRAY -m set --match-set chnroute dst -j RETURN
iptables -t mangle -A XRAY -p tcp --dport 10001:65535 -j RETURN
iptables -t mangle -A XRAY -p udp --dport 10001:65535 -j RETURN
iptables -t mangle -A XRAY -m set --match-set chnip dst -j RETURN
iptables -t mangle -A XRAY -d 192.168.0.0/16 -p tcp ! --dport 53 -j RETURN
iptables -t mangle -A XRAY -d 192.168.0.0/16 -p udp ! --dport 53 -j RETURN
iptables -t mangle -A XRAY -m mark --mark 2 -j RETURN
iptables -t mangle -A XRAY -p tcp -j TPROXY --on-port 12345 --tproxy-mark 1
iptables -t mangle -A XRAY -p udp -j TPROXY --on-port 12345 --tproxy-mark 1
iptables -t mangle -A PREROUTING -j XRAY
#代理本机
iptables -t mangle -N XRAY_SELF
iptables -t mangle -A XRAY_SELF -d 119.29.29.29/32 -j RETURN
iptables -t mangle -A XRAY_SELF -d 192.168.1.0/24 -j RETURN
iptables -t mangle -A XRAY_SELF -d 192.168.0.0/24 -j RETURN
iptables -t mangle -A XRAY_SELF -d 10.0.0.0/8 -j RETURN
iptables -t mangle -A XRAY_SELF -d 100.64.0.0/10 -j RETURN
iptables -t mangle -A XRAY_SELF -d 127.0.0.0/8 -j RETURN
iptables -t mangle -A XRAY_SELF -d 169.254.0.0/16 -j RETURN
iptables -t mangle -A XRAY_SELF -d 172.16.0.0/12 -j RETURN
iptables -t mangle -A XRAY_SELF -d 192.0.0.0/24 -j RETURN
iptables -t mangle -A XRAY_SELF -d 224.0.0.0/4 -j RETURN
iptables -t mangle -A XRAY_SELF -d 240.0.0.0/4 -j RETURN
iptables -t mangle -A XRAY_SELF -d 255.255.255.255/32 -j RETURN
iptables -t mangle -A XRAY_SELF -m set --match-set whiteip dst -j RETURN
iptables -t mangle -A XRAY_SELF -m set --match-set chnroute dst -j RETURN
iptables -t mangle -A XRAY_SELF -p tcp --dport 10001:65535 -j RETURN
iptables -t mangle -A XRAY_SELF -p udp --dport 10001:65535 -j RETURN
iptables -t mangle -A XRAY_SELF -m set --match-set chnip dst -j RETURN
iptables -t mangle -I XRAY_SELF -d 192.168.0.0/16 -p tcp ! --dport 53 -j RETURN
iptables -t mangle -I XRAY_SELF -d 192.168.0.0/16 -p udp ! --dport 53 -j RETURN
iptables -t mangle -A XRAY_SELF -m mark --mark 2 -j RETURN
iptables -t mangle -A XRAY_SELF -p tcp -j MARK --set-mark 1
iptables -t mangle -A XRAY_SELF -p udp -j MARK --set-mark 1
iptables -t mangle -A OUTPUT -j XRAY_SELF
disable_proxy.sh
#!/bin/bash
iptables -t mangle -D PREROUTING -j XRAY
iptables -t mangle -F XRAY
iptables -t mangle -X XRAY
iptables -t mangle -D OUTPUT -p tcp -j XRAY_SELF
iptables -t mangle -D OUTPUT -p udp -j XRAY_SELF
iptables -t mangle -F XRAY_SELF
iptables -t mangle -X XRAY_SELF
ip rule del fwmark 1 table 100
ip route flush table 100
iptables 命令简单解释
iptables [-t 表名] 管理选项 [链名] [匹配条件] [-j 控制类型]
语法规则
表名
、链名
:指定iptables
命令所操作的表
和链
,未指定表名时将默认使用filter
表;
管理选项
:表示iptables
规则的操作方式,比如:插入
、增加
、删除
、查看
等;
匹配条件
:指定要处理的数据包的特征,不符合指定条件的数据包不处理;
控制类型
:指数据包的处理方式,比如:允许 accept
、拒绝 reject
、丢弃 drop
、日志 LOG
等;
主要的配置是参考自 xray 文档的,https://xtls.github.io/document/level-2/tproxy.html#netfilter-%E9%85%8D%E7%BD%AE
结合这张图还有上述配置,这里先介绍下配置和流量路由方向
在 mangle 表里创建了 XRAY 链,用于将 LAN 网段的主机都能够使得都能够走代理。
在 mangle 表创建了 XRAY_SELF 链,用于将 openwrt 本机的网络链接都能够走代理。
为了让 LAN 网段的主机能够走代理的核心命令是 iptables -t mangle -A PREROUTING -j XRAY,在 PREROUTING 里把流量导入 XRAY 链,进行 TPROXY 透明代理转发往 12345 端口。
为了让本机的代理能够走 TPROXY 代理,在 mangle 表的 OUTPUT 链上将流量导入 XRAY_SELF 并标记 mark1。
由于创建了路由表 100,他会将流量导入本地回环,即流量又会重新进入 mangle 表的 PREROUTING 链中。使得后续能够走 tproxy 出去。
其他的配置就是在 XRAY 和 XRAY_SELF 链分别做的 bypass 行为,过滤一些局域网、国内 IP、广播地址、保留地址等
10001:65535 bypass 是为了避免 PT 等很多常用于 10000 以上端口的应用程序走代理。
🙋openwrt 路由器本身 dns 解析错误的问题
修改 /etc/resolve.conf, 改掉错误的 192.168.0.1 地址
🙋远程访问慢问题,chnip 中没有解析的远程主机地址,手动添加后正常。
IP 是大陆的但是没有加进去,不知道原因,额外将这个域名增加到 white.txt 重启 chinadns,后续通过 whiteip 绕过。
🙋手机 wifi 显示无网络,或者微信用着用着突然出现无网络链接,或者访问国内网站时很慢,或者 APP 有些图片加载很慢。
以及发现 api.bilibili.com 解析出来是美国等地方的 IP 23.236.97.62
blog.csdn.net 也很慢出不来任何数据
则尝试使用 nslookup [blog.csdn.net](<http://blog.csdn.net>) 127.0.0.1:5335
和 nslookup [blog.csdn.net](<http://blog.csdn.net>) 119.29.29.29
均很慢或者超时或者出不来数据
最终定位是因为 dns 全部通过代理解析了,那么需要在规则里绕过。
iptables -t mangle -A XRAY -d 119.29.29.29/32 -j RETURN
iptables -t mangle -A XRAY_SELF -d 119.29.29.29/32 -j RETURN
如果已经缓存了错误的 IP,把大陆网站解析到了海外 CDN,网站还是访问很慢,即解析到了国外,但有没有走代理或者走代理也慢。
可执行下列命令,清空错误的 ipset 列表
ipset flush chnip
ipset flush chnip6