要说我为啥要搞这个,只因我身边的一个玄学网络环境死活届不到 Mojang。🌚

1

怎么办?给 Minecraft 加特技。
这事放到 Windows/MacOS 都好办,客户端本身就能做系统代理和访问规则,就算做不到也可以来个 PAC 规则自己加着用。然而 Linux 客户端没有这种方便的系统代理功能,之前一直靠着浏览器 SwitchyOmega、终端 proxychains 全局苟命,现在仅靠 proxychains 难以解决这个问题,尝试 NetworkManager 设置 PAC 也没有见效,我需要一个船新的解决方案。

怎么办?问 Google。
搜索一番之后我找到了它,Linux TCP+UDP 透明代理 ss-tproxy,应该算得上是终极解决方案,就决定用它了。


目录

开始

Update: ⚠️ 原项目持续更新,本文内容可能落后,仅供参考。

这个 Github 项目本身的 README 文档还是写得比较详细的,作者在 blog 写得更详细,最后还有作者在 blog 写的 FAQ 链接,大部分操作我就直接复制过来了。开始偷懒

安装

首先确保解决依赖问题: iptablesip6tablesipsetdnsmasqchinadns-ngxt_TPROXYipdns2tcpcurlbase64perl。部分软件包可直接从各发行版的包管理器获取,我就不全写出来了。偷懒

TPROXY

# 查找 TPROXY 模块
find /lib/modules/$(uname -r) -type f -name '*.ko*' | grep 'xt_TPROXY'

# 正常情况下的输出
/lib/modules/4.19.14-1-MANJARO/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

新 V2Ray 白话文指南

客户端

shadowsocks

/etc/shadowsocks/config.json

{
       "server":"",
       "server_port":,
       "local_address": "",
       "local_port":,
       "password":"",
       "timeout":,
       "method":""
}

服务器地址/端口/密码/加密方式,还有超时时间这些就不用说了,本地监听地址和端口要注意一下。
local_port 要和 ss-tproxy 的proxy_tcpportproxy_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_tcpportproxy_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

设置开机自启

  1. cp -af ss-tproxy.service /etc/systemd/system
  2. systemctl daemon-reload
  3. 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 黑名单 ipset
  • ss-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。

这个也能用到软路由上,以后要是有软路由了,就靠它了?嘛,谁知道呢。

算是有生之年码的首篇长 blog 吧,难得难得,有空再写吧。老板:上班时间写 blog,扣你钱

标签: none

知识共享许可协议 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。

添加新评论