配置 ss-tproxy 实现 Linux 透明代理
要说我为啥要搞这个,只因我身边的一个玄学网络环境死活届不到 Mojang。🌚
怎么办?给 Minecraft 加特技。
这事放到 Windows/MacOS 都好办,客户端本身就能做系统代理和访问规则,就算做不到也可以来个 PAC 规则自己加着用。然而 Linux 客户端没有这种方便的系统代理功能,之前一直靠着浏览器 SwitchyOmega、终端 proxychains 全局苟命,现在仅靠 proxychains 难以解决这个问题,尝试 NetworkManager 设置 PAC 也没有见效,我需要一个船新的解决方案。
怎么办?问 Google。
搜索一番之后我找到了它,Linux TCP+UDP 透明代理 ss-tproxy,应该算得上是终极解决方案,就决定用它了。
目录
开始
Update:⚠️原项目持续更新,本文内容可能落后,仅供参考。
这个 Github 项目本身的 README 文档还是写得比较详细的,作者在 blog 写得更详细,最后还有作者在 blog 写的 FAQ 链接,大部分操作我就直接复制过来了。开始偷懒
安装
首先确保解决依赖问题: iptables
、ip6tables
、ipset
、dnsmasq
、chinadns-ng
、xt_TPROXY
、ip
、dns2tcp
、curl
、base64
、perl
。部分软件包可直接从各发行版的包管理器获取,我就不全写出来了。偷懒
TPROXY
# 查找 TPROXY 模块
find /lib/modules/$(uname -r) -type f -name '*.ko*' | grep 'xt_TPROXY'
# 正常情况下的输出
/lib/modules/5.5.7-1-default/kernel/net/netfilter/xt_TPROXY.ko.xz
ChinaDNS-NG
快速编译
git clone https://github.com/zfl9/chinadns-ng
cd chinadns-ng
make && sudo make install
chinadns-ng 默认安装到 /usr/local/bin
目录,可安装到其它目录,如 sudo make install DESTDIR=/opt/local/bin
。
交叉编译
# 指定 CC 环境变量即可,如
make CC=aarch64-linux-gnu-gcc
dns2tcp
动态链接 libuv
适用于本地编译,使用包管理器安装 libuv
依赖库即可(如 pacman -S libuv
):
git clone https://github.com/zfl9/dns2tcp
cd dns2tcp
make && sudo make install
dns2tcp 默认安装到 /usr/local/bin/dns2tcp
,可安装到其它目录,如 make install DESTDIR=/opt/local/bin
。
静态链接 libuv
适用于交叉编译,此方式编译出来的 dns2tcp
不依赖任何第三方库,可直接拷贝到目标系统运行:
# 进入某个目录
cd /opt
# 获取 libuv 源码包
libuv_version="1.32.0" # 定义 libuv 版本号
wget https://github.com/libuv/libuv/archive/v$libuv_version.tar.gz -Olibuv-$libuv_version.tar.gz
tar xvf libuv-$libuv_version.tar.gz
# 进入源码目录,编译
cd libuv-$libuv_version
./autogen.sh
./configure --prefix=/opt/libuv --enable-shared=no --enable-static=yes CC="gcc -O3"
make && sudo make install
cd ..
# 获取 dns2tcp 源码
git clone https://github.com/zfl9/dns2tcp
# 进入源码目录,编译
cd dns2tcp
make INCLUDES="-I/opt/libuv/include" LDFLAGS="-L/opt/libuv/lib" && sudo make install
安装主程序之前
你需要在 ss/ssr/v2ray 之中选择一个作为客户端,我使用的是 shadowsocks-libev / v2ray。
安装主程序
git clone https://github.com/zfl9/ss-tproxy
cd ss-tproxy
chmod +x ss-tproxy
cp -af ss-tproxy /usr/local/bin
mkdir -p /etc/ss-tproxy
cp -af ss-tproxy.conf gfwlist.* chnroute.* /etc/ss-tproxy
配置
服务端
shadowsocks
shadowsocks-libev 服务端的部署 by 飞羽博客
请确保服务端启用了 UDP 转发,否则本地无法解析国外网站。国外网站的国内 DNS 解析结果被滤了,没启用 UDP 转发下的代理查询请求没有返回,你会永远查不到 IP,此处被坑两小时
修改 shadowsocks 的 systemd 文件,在 ExecStart
添加 -u
参数,执行 systemctl daemon-reload
后重启服务,UDP 转发就开启了。
V2Ray
客户端
shadowsocks
/etc/shadowsocks/config.json
{
"server":"",
"server_port":,
"local_address": "",
"local_port":,
"password":"",
"timeout":,
"method":""
}
服务器地址/端口/密码/加密方式,还有超时时间这些就不用说了,本地监听地址和端口要注意一下。
local_port
要和 ss-tproxy 的proxy_tcpport
、proxy_udpport
一致。
local_address
的设置这点,由于我只用于本机代理,就设置为 127.0.0.1。如果有需要请设置为 0.0.0.0,并按作者 blog 操作。
V2Ray
/etc/v2ray/config.json
"inbounds": [{
"protocol": "dokodemo-door",
"listen": "",
"port": 60080,
"settings": {
"network": "tcp,udp",
"followRedirect": true
},
"streamSettings": {
"sockopt": {
//"tproxy": "tproxy" // tproxy + tproxy 模式
"tproxy": "redirect" // redirect + tproxy 模式
}
}
}]
同理 listen
我只用于本机就设置 127.0.0.1,port
与 ss-tproxy 的proxy_tcpport
、proxy_udpport
一致。
添加 "udp": true
确保 pxy/udp
工作正常。
主程序
/etc/ss-tproxy/ss-tproxy.conf
## mode
#mode='global' # global 模式 (不分流)
mode='gfwlist' # gfwlist 模式 (黑名单)
#mode='chnroute' # chnroute 模式 (白名单)
## ipv4/6
ipv4='true' # true:启用ipv4透明代理; false:关闭ipv4透明代理
ipv6='false' # true:启用ipv6透明代理; false:关闭ipv6透明代理
## tproxy
tproxy='false' # true:TPROXY+TPROXY; false:REDIRECT+TPROXY
## tcponly
tcponly='false' # true:仅代理TCP流量; false:代理TCP和UDP流量
## selfonly
selfonly='true' # true:仅代理本机流量; false:代理本机及"内网"流量
## proxy
proxy_svraddr4=() # 服务器的 IPv4 地址或域名,允许填写多个服务器地址,空格隔开
proxy_svraddr6=() # 服务器的 IPv6 地址或域名,允许填写多个服务器地址,空格隔开
proxy_svrport='666' # 服务器的监听端口,可填多个端口,格式同 ipts_proxy_dst_port
proxy_tcpport='60080' # ss/ssr/v2ray 等本机进程的 TCP 监听端口,该端口支持透明代理
proxy_udpport='60080' # ss/ssr/v2ray 等本机进程的 UDP 监听端口,该端口支持透明代理
proxy_startcmd='ss-redir -c /etc/shadowsocks/config.json -u </dev/null &>>/var/log/ss-redir.log &' # 用于启动本机代理进程的 shell 命令,该命令应该能立即执行完毕
proxy_stopcmd='kill -9 $(pidof ss-redir)' # 用于关闭本机代理进程的 shell 命令,该命令应该能立即执行完毕
# proxy_startcmd='systemctl start v2ray' # 用于 V2Ray
# proxy_stopcmd='systemctl stop v2ray' # 用于 V2Ray
## dns
dns_direct='119.29.29.29' # 本地 IPv4 DNS,不能指定端口,也可以填组织、公司内部 DNS
dns_direct6='240C::6666' # 本地 IPv6 DNS,不能指定端口,也可以填组织、公司内部 DNS
dns_remote='1.1.1.1#53' # 远程 IPv4 DNS,必须指定端口,提示:访问远程 DNS 会走代理
dns_remote6='2606:4700:4700::1111#53' # 远程 IPv6 DNS,必须指定端口,提示:访问远程 DNS 会走代理
## dnsmasq
dnsmasq_bind_port='53' # dnsmasq 服务器监听端口,见 README
dnsmasq_cache_size='4096' # DNS 缓存大小,大小为 0 表示禁用缓存
dnsmasq_cache_time='3600' # DNS 缓存时间,单位是秒,最大 3600 秒
dnsmasq_log_enable='false' # 记录详细日志,除非进行调试,否则不建议启用
dnsmasq_log_file='/var/log/dnsmasq.log' # 日志文件,如果不想保存日志可以改为 /dev/null
dnsmasq_conf_dir=() # `--conf-dir` 选项的参数,可以填多个,空格隔开
dnsmasq_conf_file=() # `--conf-file` 选项的参数,可以填多个,空格隔开
dnsmasq_conf_string=() # 自定义配置,一个数组元素就是一行配置,空格隔开
## chinadns
chinadns_bind_port='65353' # chinadns-ng 服务器监听端口,通常不用改动
chinadns_timeout='3' # 等待上游 DNS 返回响应的超时时间,单位为秒
chinadns_repeat='1' # 向可信 DNS 发送几次 DNS 查询请求,默认为 1
chinadns_fairmode='false' # 使用公平模式,具体看 chinadns-ng 的 README
chinadns_gfwlist_mode='false' # gfwlist 模式,加载 gfwlist.txt/gfwlist.ext
chinadns_noip_as_chnip='false' # 启用 chinadns-ng 的 `--noip-as-chnip` 选项
chinadns_verbose='false' # 记录详细日志,除非进行调试,否则不建议启用
chinadns_logfile='/var/log/chinadns.log' # 日志文件,如果不想保存日志可以改为 /dev/null
chinadns_privaddr4=() # IPv4 私有地址段,多个用空格隔开,具体见 README
chinadns_privaddr6=() # IPv6 私有地址段,多个用空格隔开,具体见 README
## dns2tcp
dns2tcp_bind_port='65454' # dns2tcp 转发服务器监听端口,如有冲突请修改
dns2tcp_verbose='false' # 记录详细日志,除非进行调试,否则不建议启用
dns2tcp_logfile='/var/log/dns2tcp.log' # 日志文件,如果不想保存日志可以改为 /dev/null
## ipts
ipts_if_lo='lo' # 环回接口的名称,在标准发行版中,通常为 lo,如果不是请修改
ipts_rt_tab='233' # iproute2 路由表名或表 ID,除非产生冲突,否则不建议改动该选项
ipts_rt_mark='0x2333' # iproute2 策略路由的防火墙标记,除非产生冲突,否则不建议改动该选项
ipts_set_snat='false' # 设置 iptables 的 MASQUERADE 规则,布尔值,`true/false`,详见 README
ipts_set_snat6='false' # 设置 ip6tables 的 MASQUERADE 规则,布尔值,`true/false`,详见 README
ipts_reddns_onstop='true' # ss-tproxy stop 后,是否将其它主机发至本机的 DNS 重定向至直连 DNS,详见 README
ipts_proxy_dst_port='1:65535' # 黑名单 IP 的哪些端口走代理,多个用逗号隔开,冒号为端口范围(含边界),详见 README
## opts
opts_ss_netstat='auto' # auto/ss/netstat,用哪个端口检测命令,见 README
opts_overwrite_resolv='false' # true/false,定义如何修改 resolv.conf,见 README
opts_ip_for_check_net='114.114.114.114' # 用来检测外网是否可访问的 IP,该 IP 需要允许 ping
## file
file_gfwlist_txt='/etc/ss-tproxy/gfwlist.txt' # gfwlist 黑名单文件 (默认规则)
file_gfwlist_ext='/etc/ss-tproxy/gfwlist.ext' # gfwlist 黑名单文件 (扩展规则)
file_chnroute_set='/etc/ss-tproxy/chnroute.set' # chnroute 地址段文件 (iptables)
file_chnroute6_set='/etc/ss-tproxy/chnroute6.set' # chnroute6 地址段文件 (ip6tables)
file_dnsserver_pid='/etc/ss-tproxy/.dnsserver.pid' # dns 服务器进程的 pid 文件 (shell)
/etc/ss-tproxy/gfwlist.ext
# gfwlist 扩展黑名单语法简述
# 注释:以井号开头的行以及空行都视为注释行
# IPv4地址:必须以 - 符号开头,如 -123.123.123.1
# IPv4网段:必须以 - 符号开头,如 -123.123.0.0/16
# IPv6地址:必须以 ~ 符号开头,如 ~2333:2333:2333::
# IPv6网段:必须以 ~ 符号开头,如 ~2333:2333:2333::/64
# 网址域名:必须以 @ 符号开头,如 @abc.net,匹配 abc.net、*.abc.net
# 注意:修改此文件需重启 ss-tproxy 生效,另外请删除每行首尾多余的空白符
# Telegram IPv4
-91.108.4.0/22
-91.108.8.0/22
-91.108.12.0/22
-91.108.20.0/22
-91.108.36.0/23
-91.108.38.0/23
-91.108.56.0/22
-149.154.160.0/20
-149.154.164.0/22
-149.154.172.0/22
# Telegram IPv6
~2001:67c:4e8::/48
~2001:0b28:f23d::/48
# Minecraft
@mojang.com
@minecraft.net
@amazonaws.com
@minecraftforge.net
@liteloader.com
需要指定代理的地址/网段/域名请添加到这个文件里,我在这里加入了 Minecraft 的 Mojang 服务器。
启动
ss-tproxy start
设置开机自启
cp -af ss-tproxy.service /etc/systemd/system
systemctl daemon-reload
systemctl enable ss-tproxy
检查状态
ss-tproxy status
没有什么问题的话就可以开始用了。
顺便贴上 ss-tproxy
命令用法
ss-tproxy help
:查看帮助信息ss-tproxy version
:查看版本号ss-tproxy start
:启动透明代理ss-tproxy stop
:关闭透明代理ss-tproxy restart
:重启透明代理ss-tproxy status
:查看代理状态ss-tproxy show-iptables
:查看当前的 iptables 规则ss-tproxy flush-postrule
:清空遗留的 iptables 规则ss-tproxy flush-dnscache
:清空 dnsmasq 的查询缓存ss-tproxy delete-gfwlist
:删除 gfwlist 黑名单 ipsetss-tproxy update-chnlist
:更新 chnlist(restart 生效)ss-tproxy update-gfwlist
:更新 gfwlist(restart 生效)ss-tproxy update-chnroute
:更新 chnroute(restart 生效)- 在任意位置指定
-x
选项可启用调试,如ss-tproxy start -x
- 在任意位置指定
NAME=VALUE
可覆盖ss-tproxy.conf
中的同名配置
结束
结束了?是的,结束了。如果配置遇到问题,还有更多需求的请阅读 GitHub 文档和作者 blog。咕
这个也能用到软路由上,以后要是有软路由了,就靠它了?嘛,谁知道呢。(Update:我现在有了软路由,可是我直接用 OpenWrt 插件了。)
算是有生之年码的首篇长 blog 吧,难得难得,有空再写吧。老板:上班时间写 blog,扣你钱
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。