前一阵子把我曾经折腾的那套透明代理方案(细节可以看https://cloud.tencent.com/developer/article/1934521)搬到了NAS上,不过由于众所周知的原因,文章就没在当时发出来。于是虽然都整了3个星期5个月了,现在才整理当时的各种操作。文章主要的操作是安装clash、supervisor、overture、ipt2socks、n2n、透明代理规则。如果不需要透明代理,那仅完成第1项或前2项就可以实现HTTP代理了。而后面配置的主要难点其实是iptables相关组件的安装,由于涉及到了内核组件编译,因此不建议没有编译经验的朋友尝试。另外,由于本篇文章只是记录了编译、配置的方法,所以大概会非常枯燥,还请见谅。
对于懒得看过程的旁友,我也提供了一个免编译的文件包,适用于x86_64架构的黑白群晖。直接上传整个文件包到群晖任意目录,然后按照文章配置。为了不破坏文章的整体结构,文件包的使用方式我写在了每一节的使用文件包部分,除了配置Supervisor需要整节照做,其余看这一小节就行。【下载地址】
配置Supervisor
Supervisor主要的目的是守护进程的运行,对我们而言关键的功能是
- 设置开机自启动程序
- 可以设置自启动的先后顺序
- 在进程退出时自动重启
基本的安装流程参照:https://soulteary.com/2018/06/13/synology-with-supervisor.html,这里稍微修改抄录如下。使用文件包的朋友也请按此操作。
首先确认是否已经安装python,可以运行python --version
观察是否能打印Python版本。如果没有,可以在自带的套件中心
中安装。之后执行指令安装easy_install
wget https://bootstrap.pypa.io/ez_setup.py -O - | python
安装完毕后,再用easy_install安装supervisor
代码语言:javascript复制easy_install supervisor
此时就完成了supervisor的安装。之后进行配置,首先安装默认配置文件。如果执行失败,请运行sudo -i
指令切换到root用户再试。
echo_supervisord_conf > /etc/supervisord.conf
mkdir -p /etc/supervisor/conf.d/
默认的配置文件还不够完善,需要再进行修改。编辑文件vi /etc/supervisord.conf
,在文件的末尾增加如下内容
[include]
files = /etc/supervisor/conf.d/*.conf
然后还没完,还需要配置supervisor本身开机自启。参考之前的博文,将如下内容存储到文件/usr/share/init/supervisor.conf
中即可。文件包包含了这个文件,直接复制到目录即可(sudo cp supervisor.conf /usr/share/init/
)。
author "SOULTEARY"
description "start supervisord"
start on stopped hostname
oom score -999
respawn
respawn limit 5 10
console log
script
if [ ! -f /tmp/supervisord.pid ]; then
exec /bin/supervisord -c /etc/supervisor/supervisord.conf
fi
echo "Starting supervisord"
end script
至此,supervisor就成功的安装完毕了。重启后supervisor应该就会自动运行,运行sudo supervisorctl status
应该就可以看到输出了。
关于路径的一些约定
在之后的文章中会用到非常多的路径,表述起来会非常不方便,所以这里先做一些整理。主要的目录结构和文件包是一样的,即每个小节都有独立的文件夹:
{HOME}
:放置所有小节文件夹,对应于文件包的transparent_proxy
文件夹{HOME}/clash
:放置Clash相关配置{HOME}/ipt2socks
:放置ipt2socks相关配置{HOME}/overture
:放置overture相关配置{HOME}/iptables
:放置透明代理规则相关配置
配置Clash
安装clash最简单的方法就是用群晖自带的Docker程序下载clash镜像。如果只需要安装clash,这种方法确实没有问题,但是因为我需要多个程序的启动按顺序进行,因此Docker的方式还是没法满足需求,只得自己编译。
由于我的目标平台是x86_64的,而clash是用go语言编写的,因此并不需要构建交叉编译环境就能进行编译。不过由于clash的Github已经有预编译的版本了,所以其实也不需要自己编译,直接在Release页下载amd64的版本即可(其他架构同理)。把文件上传到群晖的任意目录,比如{HOME}/clash
。之后把配置文件config.yaml
放在同目录下。
开机自启(Supervisor)
Supervisor的配置其实不难,只需要把配置文件放到/etc/supervisor/conf.d/
目录即可。对于clash,可以用如下的配置
[program:clash]
command={HOME}/clash/clash -d {HOME}/clash
priority=1
numprocs=1
autostart=true
autorestart=true
startretries=10
exitcodes=0
stopsignal=KILL
stopwaitsecs=10
redirect_stderr=true
注意替换{HOME}
为真实路径。放置配置文件后,运行sudo supervisorctl reload
即可。
使用文件包
修改config.yml
为Clash配置,替换clash_daemon.conf
中的{HOME}
为真实路径。之后运行如下命令即可。
# 复制配置
sudo cp clash_daemon.conf /etc/supervisor/conf.d/
# 重载 Supervisor
sudo supervisorctl reload
*安装clash控制面板yacd
由于yacd就是个简单的控制面板,没必要在意它运行是否高效,所以自然就可以选择最简单的Docker安装方式。如果还没有安装Docker套件
,可以在套件中心
中搜索下载。
之后打开Docker
,选择注册表
(原文是Registry,虽然没错但我还是觉得注册表听起来怪怪的)搜索yacd
,下载haishanh/yacd
。之后在映像
中选择该镜像,点击启动
。可以在高级设置-端口设置
配置固定的本地端口用于面板的访问。启动容器后,就可以通过http://{NAS的IP}:{本地端口}
访问yacd面板了。
在Docker中配置交叉编译环境
到此为止的文章已经完成了Clash的配置,因此已经可以通过设置HTTP代理达到相当不错的代理效果了。之后的文章主要面向透明代理,如果你并不关心透明代理,那我十分不建议你继续操作,因为后面的配置流程要相对复杂许多。不过透明代理也是有若干优势的:
- 可以在不支持HTTP代理的设备上使用。只要可以自由设置网关地址即可开启代理,这对设备实现几乎没有要求
- 可以实现Fullcone NAT。不过这需要你的代理服务器支持
- 可以提供无污染的DNS。攻击者可能会安插有广告等的恶意DNS记录都是境外反动分子干的坏事!
- 可以不需要在开启代理的设备上设置。只需要在路由器上配置DHCP即可
- ……
如果你只想用文件包,那你可以直接跳到配置ipt2socks一节。
在Docker中配置交叉编译环境
准备Docker镜像
所以让我们开始吧!首先就是要进行交叉编译环境的配置。群晖有一个社区维护并且包含Dockerfile
的交叉编译环境:https://github.com/SynoCommunity/spksrc/。因此配置基础环境的过程很简单
- 克隆仓库至本地:
git clone https://github.com/SynoCommunity/spksrc ~/spksrc
- 下载镜像:
docker pull synocommunity/spksrc
- 启动镜像:
docker run -it --name spksrc --net host -v ~/spksrc:/spksrc synocommunity/spksrc /bin/bash
其中~/spksrc
可以换成其他文件夹,不过必须是绝对路径。之后就可以进入交叉编译的环境了。
下载交叉编译工具链
不过此时还没有完成工具链的配置,因此还需要下载群晖官方提供的工具链。spksrc
将这部分逻辑都用Makefile的形式放置在toolchain/
下,因此找到群晖对应的型号即可。spksrc
官方维护了一个表格用于查找:https://github.com/SynoCommunity/spksrc/wiki/Synology-and-SynoCommunity-Package-Architectures
。比如对于DS918 ,它的SynoCommunity Arch
是apollolake
,因此就对应于toolchain/syno-apollolake-*
。
查到了对应的架构,就可以下载相关工具链了。比如对于DS918 的6.2系统,它的工具链位于toolchain/syno-apollolake-6.2
,因此
- 进入目录:
cd toolchain/syno-apollolake-6.2
- 配置环境:
make
这样就完成了工具链的下载。
配置必要的环境变量
其实spksrc
提供了很优雅的方案解决环境变量的配置问题,但是由于我懒得写Makefile,因此还是用一个shell脚本来配置环境变量比较方面。在spksrc
文件夹下(可以直接在宿主机操作)创建work
文件夹用于编译操作,并创建env.sh
脚本:
# 脚本以 syno-apollolake-6.2 (x86_64) 为例,其他平台请自行调整
# 基础工具配置
export PATH="${PATH}:/spksrc/toolchain/syno-apollolake-6.2/work/x86_64-pc-linux-gnu/bin"
export CROSS=x86_64-pc-linux-gnu
export CC=${CROSS}-gcc
export LD=${CROSS}-ld
export AS=${CROSS}-as
export CXX=${CROSS}-g
之后运行source env.sh
就能初始化环境变量了。对于使用Makefile等方式控制编译的程序,此时直接编译即可完成目标产物了。如果你不是很确定环境变量具体的值,可以参考work/tc_vars.mk
文件的内容。
配置ipt2socks
编译
首先在Release页面下载ip2socks的源码:https://github.com/zfl9/ipt2socks/releases。之后解压至work/
,并进入文件夹。在Docker环境下先配置环境变量(执行source env.sh
),之后执行make -j4
即可完成编译,若顺利的话目录中将生成ipt2socks
文件。
配置
有了supervisor
,配置ipt2socks
就相当容易了。ipt2socks
不需要配置文件,所有设置都可以通过参数传递。所以创建配置(同样放到/etc/supervisor/conf.d/
目录即可):
[program:ipt2socks]
command={HOME}/ipt2socks/ipt2socks -s 127.0.0.1 -p 10080 -l 11451 -j 5
priority=2
numprocs=1
autostart=true
autorestart=true
startretries=10
exitcodes=0
stopsignal=KILL
stopwaitsecs=10
redirect_stderr=true
此处注意,如果你的Clash配置中Socks5端口不是10080,请换成对应的端口。
使用文件包
替换ipt2socks_daemon.conf
中的{HOME}
为真实路径。之后运行如下命令即可。
# 复制配置
sudo cp ipt2socks_daemon.conf /etc/supervisor/conf.d/
# 重载 Supervisor
sudo supervisorctl reload
配置overture
编译
overture也是用go写的,所以和clash一样也没什么交叉编译的问题(当然如果你不是x86架构的群晖,还是需要交叉编译的)。不过官方也提供了预编译好的包(Release),所以同样也是下过来就行。如果需要手动编译的话也是在Docker环境下,clone仓库之后运行CGO_ENABLED=0 GOOS=linux go build
就行了。
配置
具体配置可以参考官方给出的配置与之前透明代理文章中的配置。文件包中包含了一个我目前用的配置,可能需要根据实际情况进行修改。
使用文件包
替换overture_daemon.conf
、config.json
中的{HOME}
为真实路径。之后运行如下命令即可。
# 复制配置
sudo cp overture_daemon.conf /etc/supervisor/conf.d/
# 重载 Supervisor
sudo supervisorctl reload
内核下载与环境配置
之前的部分都比较简单,但是接下来的部分就比较折磨了(熟悉了其实也还好)。主要原因是群晖缺少了一些透明代理的必要模块(比如TPROXY),所以就需要自己手动编译了。所以首先还是需要准备内核编译环境,这一点spksrc再次帮我们做了不少工作。和之前类似,也是进入对应目录然后下载。
- 进入目录:
cd kernel/syno-apollolake-6.2
- 配置环境:
make
之后扩充一下之前的env.sh
,基本的内核编译环境就搭建完成了。
# 脚本以 syno-apollolake-6.2 (x86_64) 为例,其他平台请自行调整
# 基础工具配置
export PATH="${PATH}:/spksrc/toolchain/syno-apollolake-6.2/work/x86_64-pc-linux-gnu/bin"
export CROSS=x86_64-pc-linux-gnu
export CC=${CROSS}-gcc
export LD=${CROSS}-ld
export AS=${CROSS}-as
export CXX=${CROSS}-g
# 内核编译配置
export CROSS_COMPILE=/spksrc/toolchain/syno-apollolake-6.2/work/x86_64-pc-linux-gnu/bin/x86_64-pc-linux-gnu-
export ARCH=x86_64
export KSRC=/spksrc/kernel/syno-apollolake-6.2/work/linux
配置iptables
编译
iptables本身只是配置netfilter的命令行工具,因此要支持一个扩展不仅需要安装内核模块,同时也需要安装iptables的扩展。
内核模块
首先是内核模块。虽然spksrc支持下载内核源码,但是内核模块编译的支持尚在日程中(#8),因此还是需要手动编译。交叉编译下其实和正常的内核模块编译没有什么两样,就是需要多设置若干变量。我的配置只需要编译xt_connmark
和xt_tproxy
两个模块别问,问就是一条条指令试出来的,所以可以写如下脚本编译:
# 设置环境变量
source env.sh
# 编译 netfilter 模块
MODULE=/spksrc/kernel/syno-apollolake-6.2/work/linux/net/netfilter
export CONFIG_NETFILTER_XT_CONNMARK=m
export CONFIG_NETFILTER_XT_TARGET_TPROXY=m
make ARCH=$ARCH CROSS_COMPILE=$CROSS_COMPILE -C $KSRC M=$MODULE clean
make ARCH=$ARCH CROSS_COMPILE=$CROSS_COMPILE -C $KSRC M=$MODULE modules -j 4
# 整理编译产物
rm -rf build
mkdir build
cp $MODULE/*.ko build
mkdir build/ipset
cp $MODULE/ipset/*.ko build/ipset
iptables扩展
iptables的扩展要更麻烦些,需要自己下载源码(https://www.netfilter.org/pub/iptables/)并交叉编译。下载源码的时候一定要注意版本匹配,对我的情况来说(6.2系统)需要下载1.6.0版本的源码。编译其实也挺简单的
- 源码丢进
work
目录,然后运行env.sh
配置交叉编译环境 - 在源码目录执行:
./configure --prefix="
[install目录的绝对路径]
"
- 执行:
make && make install
需要的.so
就都可以在install/lib/xtables/
下找到了。
配置
- 需要复制进来的内核模块有:
ip_set_hash_net.ko
、xt_connmark.ko
、xt_TPROXY
。 - 需要复制的iptables扩展:
libxt_CONNMARK.so
、libxt_connmark.so
、libxt_mark.so
、libxt_TPROXY.so
。
iptables扩展需要复制到/usr/lib/iptables
,内核模块可以复制到群晖存放内核模块的路径/lib/modules
。这个路径已经包含了一些群晖编译的但不一定安装的内核模块,统一管理也方便一点。然后在透明代理配置的脚本之前加入一段内核模块的安装:
#------------
# 安装内核模块
#------------
insmod /lib/modules/nfnetlink.ko
insmod /lib/modules/ip_set.ko
insmod /lib/modules/ip_set_hash_ip.ko
insmod /lib/modules/xt_set.ko
insmod /lib/modules/ip_set_hash_net.ko
insmod /lib/modules/xt_mark.ko
insmod /lib/modules/xt_connmark.ko
insmod /lib/modules/xt_TPROXY.ko
这样基本就算完事了。最后我们再给它写个supervisor的配置,以便在启动时自动配置。这里的sleep 30
其实是个玄学,因为启动过程中太早的时间点还没法跑这个脚本,原因未知也懒得知。
[program:transparent_proxy]
command=sh -c 'sleep 30 && sh {HOME}/iptables/transparent_proxy.sh'
priority=3 ; 必须在其他代理程序执行后执行
numprocs=1
autostart=true
exitcodes=0
redirect_stderr=true
; 脚本执行
startsecs = 0
autorestart = false
startretries = 1
使用文件包
之后替换transparent_proxy.conf
中的{HOME}
为真实路径。之后运行如下命令即可。
# 安装必要模块
sudo sh {HOME}/iptables/script/install.sh
# 复制配置
sudo cp transparent_proxy.conf /etc/supervisor/conf.d/
# 重载 Supervisor
sudo supervisorctl reload
Reference
- 聊聊群晖的进程守护:https://soulteary.com/2018/06/13/synology-with-supervisor.html
- SynoCommunity/spksrc:https://github.com/SynoCommunity/spksrc/
- 感谢这个贴子让我知道需要kmod-ipset:https://forum.archive.openwrt.org/viewtopic.php?id=62084&p=3