在群晖部署适用IPv6、Fullcone NAT的旁路由透明代理

2022-01-14 16:17:41 浏览数 (1)

前一阵子把我曾经折腾的那套透明代理方案(细节可以看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

代码语言:javascript复制
wget https://bootstrap.pypa.io/ez_setup.py -O - | python

安装完毕后,再用easy_install安装supervisor

代码语言:javascript复制
easy_install supervisor

此时就完成了supervisor的安装。之后进行配置,首先安装默认配置文件。如果执行失败,请运行sudo -i指令切换到root用户再试。

代码语言:javascript复制
echo_supervisord_conf > /etc/supervisord.conf
mkdir -p /etc/supervisor/conf.d/

默认的配置文件还不够完善,需要再进行修改。编辑文件vi /etc/supervisord.conf,在文件的末尾增加如下内容

代码语言:javascript复制
[include]
files = /etc/supervisor/conf.d/*.conf

然后还没完,还需要配置supervisor本身开机自启。参考之前的博文,将如下内容存储到文件/usr/share/init/supervisor.conf中即可。文件包包含了这个文件,直接复制到目录即可(sudo cp supervisor.conf /usr/share/init/)。

代码语言:javascript复制
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,可以用如下的配置

代码语言:javascript复制
[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}为真实路径。之后运行如下命令即可。

代码语言:javascript复制
# 复制配置
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代理达到相当不错的代理效果了。之后的文章主要面向透明代理,如果你并不关心透明代理,那我十分不建议你继续操作,因为后面的配置流程要相对复杂许多。不过透明代理也是有若干优势的:

  1. 可以在不支持HTTP代理的设备上使用。只要可以自由设置网关地址即可开启代理,这对设备实现几乎没有要求
  2. 可以实现Fullcone NAT。不过这需要你的代理服务器支持
  3. 可以提供无污染的DNS。攻击者可能会安插有广告等的恶意DNS记录都是境外反动分子干的坏事!
  4. 可以不需要在开启代理的设备上设置。只需要在路由器上配置DHCP即可
  5. ……

如果你只想用文件包,那你可以直接跳到配置ipt2socks一节。

在Docker中配置交叉编译环境

准备Docker镜像

所以让我们开始吧!首先就是要进行交叉编译环境的配置。群晖有一个社区维护并且包含Dockerfile的交叉编译环境:https://github.com/SynoCommunity/spksrc/。因此配置基础环境的过程很简单

  1. 克隆仓库至本地:git clone https://github.com/SynoCommunity/spksrc ~/spksrc
  2. 下载镜像:docker pull synocommunity/spksrc
  3. 启动镜像: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 Archapollolake,因此就对应于toolchain/syno-apollolake-*

查到了对应的架构,就可以下载相关工具链了。比如对于DS918 的6.2系统,它的工具链位于toolchain/syno-apollolake-6.2,因此

  1. 进入目录:cd toolchain/syno-apollolake-6.2
  2. 配置环境:make

这样就完成了工具链的下载。

配置必要的环境变量

其实spksrc提供了很优雅的方案解决环境变量的配置问题,但是由于我懒得写Makefile,因此还是用一个shell脚本来配置环境变量比较方面。在spksrc文件夹下(可以直接在宿主机操作)创建work文件夹用于编译操作,并创建env.sh脚本:

代码语言:javascript复制
# 脚本以 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/目录即可):

代码语言:javascript复制
[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}为真实路径。之后运行如下命令即可。

代码语言:javascript复制
# 复制配置
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.confconfig.json中的{HOME}为真实路径。之后运行如下命令即可。

代码语言:javascript复制
# 复制配置
sudo cp overture_daemon.conf /etc/supervisor/conf.d/
# 重载 Supervisor
sudo supervisorctl reload

内核下载与环境配置

之前的部分都比较简单,但是接下来的部分就比较折磨了(熟悉了其实也还好)。主要原因是群晖缺少了一些透明代理的必要模块(比如TPROXY),所以就需要自己手动编译了。所以首先还是需要准备内核编译环境,这一点spksrc再次帮我们做了不少工作。和之前类似,也是进入对应目录然后下载。

  1. 进入目录:cd kernel/syno-apollolake-6.2
  2. 配置环境:make

之后扩充一下之前的env.sh,基本的内核编译环境就搭建完成了。

代码语言:javascript复制
# 脚本以 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_connmarkxt_tproxy两个模块别问,问就是一条条指令试出来的,所以可以写如下脚本编译:

代码语言:javascript复制
# 设置环境变量
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版本的源码。编译其实也挺简单的

  1. 源码丢进work目录,然后运行env.sh配置交叉编译环境
  2. 在源码目录执行:./configure --prefix="[install目录的绝对路径]"
  3. 执行:make && make install

需要的.so就都可以在install/lib/xtables/下找到了。

配置

  • 需要复制进来的内核模块有:ip_set_hash_net.koxt_connmark.koxt_TPROXY
  • 需要复制的iptables扩展:libxt_CONNMARK.solibxt_connmark.solibxt_mark.solibxt_TPROXY.so

iptables扩展需要复制到/usr/lib/iptables,内核模块可以复制到群晖存放内核模块的路径/lib/modules。这个路径已经包含了一些群晖编译的但不一定安装的内核模块,统一管理也方便一点。然后在透明代理配置的脚本之前加入一段内核模块的安装:

代码语言:javascript复制
#------------
# 安装内核模块
#------------

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其实是个玄学,因为启动过程中太早的时间点还没法跑这个脚本,原因未知也懒得知。

代码语言:javascript复制
[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}为真实路径。之后运行如下命令即可。

代码语言:javascript复制
# 安装必要模块
sudo sh {HOME}/iptables/script/install.sh
# 复制配置
sudo cp transparent_proxy.conf /etc/supervisor/conf.d/
# 重载 Supervisor
sudo supervisorctl reload

Reference

  1. 聊聊群晖的进程守护:https://soulteary.com/2018/06/13/synology-with-supervisor.html
  2. SynoCommunity/spksrc:https://github.com/SynoCommunity/spksrc/
  3. 感谢这个贴子让我知道需要kmod-ipset:https://forum.archive.openwrt.org/viewtopic.php?id=62084&p=3

0 人点赞