wireguard服务器完美分流(IP+域名)

中国大陆与外部世界的网络已经存在了巨大的差异,中国大陆的人难以访问外面的网络,外面的人也难以访问中国大陆的网络。这对于游走于中国大陆内外的商人和学者来说,是极其不方便的,wireguard是一个极度高效简洁和安全的虚拟网络软件(VPN),但是中国大陆到国外的wireguard是被封锁的,无法使用,但是国外可以通过wireguard连接中国大陆。
很多中国大陆的网站,比如银行是必须中国大陆ip才能访问的,很多国外的服务比如chatgpt就必须国外的ip才能访问。因此,wireguard就存在一个根据IP分流的问题,网上不少文章简述了在电脑或手机等客户端实现分流,但很少有文章提到在wireguard的服务器上做分流,经过几天的研究,我终于完成了在wireguard服务器上根据ip分流了。当我游走在中国大陆和国外的时候,就感觉不到网络封锁了,而且国外的网络、中国大陆的网络和局域网内的设备全部互联互通,一劳永逸了。
其原理就是在国内的服务器(debian 12)上建立wireguard服务器,然后再建立一个透明网关。我在国外的是IPLC服务器,所以干脆用比较简单的shadowsocks服务与国内的服务器相连,当然如果你不是IPLC服务器那就只能用别的协议了,因为大部分shadowsocks服务也是被封锁的。通过连接国内wireguard服务器实现访问国内网站用国内ip,访问国外网站用国外ip,实现了wireguard服务器的完美分流。

这里面涉及了shadowsocks-libev(ss-tunnel和ss-redir)、Dnsmasq、wireguard和透明网关iptables的设置,比较繁琐。本人用的是一台国内的debian 12 linux服务器进行了测试安装,nftables未测试,我也不熟悉,我干脆禁用了nftables,只用iptables。

具体步骤如下:
1,安装dnsmasq

apt update
apt install dnsmasq

2,配置dnsmasq

vi /etc/dnsmasq.conf
粘贴下面两行到文件末尾

no-resolv
server=127.0.0.1#5353

3,配置dnsmasq的解析白名单,这个目的是国内域名用国内DNS解析,国外域名用国外DNS解析
这里使用了felixonmars/dnsmasq-china-list的大陆域名白名单
这个列表使用了114.114.114.114的dns服务器,这里建议使用运营商给你的dns服务器,一是解析会快一点,二是cdn识别会更准确
这里假设拨号获得的dns服务器是223.5.5.5,可以使用下面命令来生成使用中国大陆常用的域名列表
curl -s https://raw.githubusercontent.com/felixonmars/dnsmasq-china-list/master/accelerated-domains.china.conf|sed ‘s/114.114.114.114/223.5.5.5/g’ >/etc/dnsmasq.d/accelerated-domains.china.223.5.5.5.conf

4. 安装shadowsocks-libev和ipset
apt install shadowsocks-libev
apt install ipset
127.0.0.1#5353这个dns服务器需要用ss-tunnel生成,具体命令:ss-tunnel -s 服务器IP -p 服务器Port -m 加密方式 -k 密码 -b 0.0.0.0 -l 5353 -L 8.8.8.8:53 -u

5.生成中国大陆ip段,可以用下面的命令:
wget -c http://ftp.apnic.net/stats/apnic/delegated-apnic-latest
cat delegated-apnic-latest | awk -F ‘|’ ‘/CN/&&/ipv4/ {print $4 “/” 32-log($5)/log(2)}’ | cat > /usr/rule/cn_rules.conf

6. 设置透明代理,实现国内ip直连,国外ip走代理
下面的代码是透明代理的主要代码:
#!/bin/bash

# 初始化 ipset 规则,创建 chnroute 列表
start_ipset() {
echo “Initializing chnroute ipset…”
ipset -N chnroute hash:net maxelem 65536 -exist
for ip in $(cat ‘/usr/rule/cn_rules.conf’); do
ipset add chnroute $ip -exist
done
}

# 清除 ipset 规则
stop_ipset() {
echo “Flushing and removing chnroute ipset…”
ipset flush chnroute &>/dev/null
ipset destroy chnroute &>/dev/null
}

start_ssredir() {
echo “Starting ss-redir…”
# 请修改 国外shadowsocks服务器的MyIP, MyPort, 加密方式, password,etc.
(ss-redir -s Myip -p Myport -m 加密方式 -k password -b 127.0.0.1 -l 60080 –no-delay -u -T -v >/var/log/ss-redir.log &)
}

stop_ssredir() {
echo “Stopping ss-redir…”
kill -9 $(pidof ss-redir) &>/dev/null
}

start_iptables() {
echo “Setting up iptables rules…”

##################### SSREDIR #####################
iptables -t mangle -N SSREDIR

# connection-mark -> packet-mark
iptables -t mangle -A SSREDIR -j CONNMARK –restore-mark
iptables -t mangle -A SSREDIR -m mark –mark 0x2333 -j RETURN

# 直接放行 chnroute 里的 IP(不走代理)
iptables -t mangle -A SSREDIR -m set –match-set chnroute dst -j RETURN

# 忽略发往 ss-server 的流量
iptables -t mangle -A SSREDIR -p tcp -d myip –dport myport -j RETURN
iptables -t mangle -A SSREDIR -p udp -d myip –dport myport -j RETURN

# 忽略保留地址段
iptables -t mangle -A SSREDIR -d 0.0.0.0/8 -j RETURN
iptables -t mangle -A SSREDIR -d 10.0.0.0/8 -j RETURN
iptables -t mangle -A SSREDIR -d 100.64.0.0/10 -j RETURN
iptables -t mangle -A SSREDIR -d 127.0.0.0/8 -j RETURN
iptables -t mangle -A SSREDIR -d 169.254.0.0/16 -j RETURN
iptables -t mangle -A SSREDIR -d 172.16.0.0/12 -j RETURN
iptables -t mangle -A SSREDIR -d 192.168.0.0/16 -j RETURN
iptables -t mangle -A SSREDIR -d 224.0.0.0/4 -j RETURN
iptables -t mangle -A SSREDIR -d 240.0.0.0/4 -j RETURN
iptables -t mangle -A SSREDIR -p udp –dport 59999 -j RETURN #这是国内wireguard服务器端口
# 标记新建的 TCP/UDP 连接
iptables -t mangle -A SSREDIR -p tcp –syn -j MARK –set-mark 0x2333
iptables -t mangle -A SSREDIR -p udp -m conntrack –ctstate NEW -j MARK –set-mark 0x2333

# packet-mark -> connection-mark
iptables -t mangle -A SSREDIR -j CONNMARK –save-mark

##################### OUTPUT #####################
iptables -t mangle -A OUTPUT -p tcp -m addrtype –src-type LOCAL ! –dst-type LOCAL -j SSREDIR
iptables -t mangle -A OUTPUT -p udp -m addrtype –src-type LOCAL ! –dst-type LOCAL -j SSREDIR

##################### PREROUTING #####################
iptables -t mangle -A PREROUTING -p tcp -m addrtype ! –src-type LOCAL ! –dst-type LOCAL -j SSREDIR
iptables -t mangle -A PREROUTING -p udp -m addrtype ! –src-type LOCAL ! –dst-type LOCAL -j SSREDIR

# 交给 TPROXY 处理
iptables -t mangle -A PREROUTING -p tcp -m mark –mark 0x2333 -j TPROXY –on-ip 127.0.0.1 –on-port 60080
iptables -t mangle -A PREROUTING -p udp -m mark –mark 0x2333 -j TPROXY –on-ip 127.0.0.1 –on-port 60080
}

stop_iptables() {
echo “Flushing iptables rules…”

iptables -t mangle -F SSREDIR &>/dev/null
iptables -t mangle -F &>/dev/null
iptables -t mangle -X SSREDIR &>/dev/null
}

start_iproute2() {
echo “Setting up iproute2 rules…”
ip route add local default dev lo table 100
ip rule add fwmark 0x2333 table 100
}

stop_iproute2() {
echo “Flushing iproute2 rules…”
ip rule del table 100 &>/dev/null
ip route flush table 100 &>/dev/null
}

start() {
echo “Starting transparent proxy…”
start_ipset
start_ssredir
start_iptables
start_iproute2
echo “Transparent proxy started.”
}

stop() {
echo “Stopping transparent proxy…”
stop_iproute2
stop_iptables
stop_ssredir
stop_ipset
echo “Transparent proxy stopped.”
}

restart() {
stop
sleep 1
start
}

main() {
if [ $# -eq 0 ]; then
echo “Usage: $0 start|stop|restart”
return 1
fi

for funcname in “$@”; do
if [ “$(type -t $funcname)” != ‘function’ ]; then
echo “‘$funcname’ is not a valid function”
return 1
fi
done

for funcname in “$@”; do
$funcname
done
return 0
}

main “$@”

把上面代码写入ss-tproxy.sh

chmod +x ss-tproxy.sh

./ss-tproxy.sh start

7.wireguard的安装请参考网上资料,这里要注意的是Debian 12上是wireguard服务器,手机或电脑上是wireguard客户端,客户端的DNS必须是Debian 12的主IP地址,比如说是192.168.2.8,这是把Debian 12的dnsmasq安装后产生的127.0.0.1的dns服务器传出来

8.如果需要DNS解锁netflix或chatgpt,那就需要建立另外一条ss-tunnel(连接解锁的DNS),生成另外一个dns,比如127.0.0.1#6363,通过 nano /etc/dnsmasq.d/chatgpt.conf 写入如下代码
server=/openai.com/127.0.0.1#6363
server=/chatgpt.com/127.0.0.1#6363
server=/cdn.auth0.com/127.0.0.1#6363
server=/azureedge.net/127.0.0.1#6363
server=/sentry.io/127.0.0.1#6363
server=/azurefd.net/127.0.0.1#6363
server=/intercomcdn.com/127.0.0.1#6363
server=/intercom.io/127.0.0.1#6363
server=/identrust.com/127.0.0.1#6363
server=/challenges.cloudflare.com/127.0.0.1#6363
server=/ai.com/127.0.0.1#6363
server=/oaistatic.com/127.0.0.1#6363
server=/oaiusercontent.com/127.0.0.1#6363

9.上面的规则仅仅涉及ipv4,我实在是没有时间去搞ipv6了,而且大部分国外的酒店是没有ipv6的。上面的中国大陆域名列表和中国大陆IP段可以用crontab自动更新。另外要注意的是,iptables中有个TPROXY参数,是透明代理的意思,一般linux会自动加载TPROXY这个模块,如果无法加载,请自行chatgpt解决。另外iptables有个rediect参数只对本机有效,无法做透明代理,所以必须用TPROXY参数。iptables -t mangle -A SSREDIR -p udp –dport 59999 -j RETURN 这条规则极其重要,这是让wireguard流量不要错误地被透明代理。

10. 特别提示:如果你的网络通了IPv6,你如果不处理ipv6 规则或禁用ipv6,那么有些windows 浏览器会以ipv6优先,可导致访问失败。

11. 最后调试发现,尽管上述方案可以实现分流,但是首次打开网页速度慢或错误,搞不清楚是dns缓存问题还是iptalbes规则优化问题,没有时间测试。最后推荐别人测试好的方案:https://github.com/zfl9/ss-tproxy

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注