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

前一阵子把我曾经折腾的那套透明代理方案(细节可以看https://blog.kaaass.net/archives/1446)搬到了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

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

  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脚本:

# 脚本以 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.confconfig.json中的{HOME}为真实路径。之后运行如下命令即可。

# 复制配置
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,基本的内核编译环境就搭建完成了。

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

# 设置环境变量
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。这个路径已经包含了一些群晖编译的但不一定安装的内核模块,统一管理也方便一点。然后在透明代理配置的脚本之前加入一段内核模块的安装:

#------------
# 安装内核模块
#------------

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

  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
分享到

KAAAsS

喜欢二次元的程序员,喜欢发发教程,或者偶尔开坑。(←然而并不打算填)

相关日志

  1. 没有图片
  2. 没有图片
  3. 没有图片
  4. 没有图片

评论

  1. haven li 2021.08.24 10:12上午

    进入目录:cd kernel/syno-apollolake-6.2
    下载:make download

    这两部,没有在spksrc/kernel/syno-apollolake-6.2/work/里下载东西

    • KAAAsS 2021.08.24 11:36上午

      我刚刚试了下应该是可以的才对。终端里有输出什么报错信息吗?

      • haven li 2021.08.24 4:40下午

        make download下载交叉编译工具链的时候,/spksrc/toolchain/syno-apollolake-6.2/work/目录下也没有,直到
        cd kernel/syno-apollolake-6.2
        make download结束后/spksrc/toolchain/syno-apollolake-6.2/work/才有x86_64-pc-linux-gnu目录,有执行了env.sh了,下面是kernel的make download信息,没有发现报错

        ===> Set up toolchain
        ===> Verifying files for syno-apollolake
        ===> Checking sha1sum of file apollolake-gcc493_glibc220_linaro_x86_64-GPL.txz
        ===> Checking sha256sum of file apollolake-gcc493_glibc220_linaro_x86_64-GPL.txz
        ===> Checking md5sum of file apollolake-gcc493_glibc220_linaro_x86_64-GPL.txz
        /spksrc/toolchain/syno-apollolake-6.2.3/../../distrib/toolchain/6.2.3/apollolake-gcc493_glibc220_linaro_x86_64-GPL.txz
        ===> Extracting for syno-apollolake
        tar -xpf /spksrc/toolchain/syno-apollolake-6.2.3/../../distrib/toolchain/6.2.3/apollolake-gcc493_glibc220_linaro_x86_64-GPL.txz -C /spksrc/toolchain/syno-apollolake-6.2.3/work
        ===> Patching for syno-apollolake
        ===> Fixing libtool files for syno-apollolake
        chmod -R u+w /spksrc/toolchain/syno-apollolake-6.2.3/work
        env make –no-print-directory tc_vars > /spksrc/toolchain/syno-apollolake-6.2.3/work/tc_vars.mk 2>/dev/null;
        ===> Downloading files for syno-apollolake-6.2.3
        ===> wget https://sourceforge.net/projects/dsgpl/files/Synology%20NAS%20GPL%20Source/25426branch/apollolake-source/linux-4.4.x.txz
        2021-08-24 01:45:41 URL:https://udomain.dl.sourceforge.net/project/dsgpl/Synology%20NAS%20GPL%20Source/25426branch/apollolake-source/linux-4.4.x.txz [101464808/101464808] -> "apollolake-linux-4.4.x.txz.part" [1]

        • KAAAsS 2021.08.24 4:57下午

          看了下,应该直接执行 make 指令就行了。感谢提醒,我去修改下文章

        • itol 2022.12.04 4:09下午

          博主你好,我按照您的步骤都编译好了,把相应配置的[home]路径都修改成了实际路径,将ipt2socks_daemon.conf中的10080端口修改成了7890,其它没动。但是用supervisorctl status查看状态时,transparent_proxy总是exited,其它3个都运行正常,我感觉是配置文件设置不对,但是不知怎么修改?(我clash配置文件config.yaml是mix-port=7890,redir-port=7892,dns设置里是listen: 0.0.0.0:1053)
          root@SynologyNas:/etc/supervisor/conf.d# supervisorctl status
          clash RUNNING pid 21646, uptime 0:00:47
          ipt2socks RUNNING pid 21647, uptime 0:00:47
          overture RUNNING pid 21648, uptime 0:00:47
          transparent_proxy EXITED Dec 04 04:00 PM

          • KAAAsS 2022.12.04 4:52下午

            transparent_proxy 显示为 EXITED 是正常的~ 因为只需要在启动时配置一次防火墙规则,脚本配置完成后就退出了。

          • itol 2022.12.04 9:45下午

            尝试下载ipset的源码编译一下,可是在执行./configure的时候显示这样的错误“configure: error: Invalid kernel source directory /lib/modules/4.4.180+/source”,无解了。博主方便把ipset的模块或者扩展上传一下吗

          • KAAAsS 2022.12.04 9:48下午

            好奇怪,我印象中我没有安装过 ipset。好像我这边 DSM 里是自带了 ipset 的。

          • itol 2022.12.04 10:02下午

            我是dsm7.1,内核是4.4.180+,但就是没有ipset,编译又搞不出来,差在这最后一步老不爽了

  2. haven li 2021.08.25 3:57下午

    在源码目录执行:./configure –prefix="install"

    –prefix参数必须用绝对路径,不然会报错。

    • KAAAsS 2021.08.25 4:15下午

      感谢提醒,我修改下

  3. lao wang 2021.11.17 9:29上午

    所以这么搞其实相当于把群晖的内核打了个patch,然后如果群晖升级会不会要再来一次。

    • KAAAsS 2021.11.19 1:26下午

      如果更新内核版本过高的话确实需要重新编译,不过一般来说不会吧(我猜)

  4. kimi 2021.12.16 7:26下午

    群晖7.0怎么办,kernel文件夹下好像没7.0的文件夹

  5. kimi 2021.12.16 7:38下午

    然后iptables版本要怎么确定,是直接查看系统上的iptables版本吗?

  6. 鹤心 2022.01.08 2:26下午

    博主您好,在DSM 7.0.1-42218 Linux DS920 4.4.180+ #42218 SMP Mon Oct 18 19:16:55 CST 2021 x86_64 GNU/Linux synology_geminilake_920+ 上,编译成功,但是加载模块的时候提示 x86/modules: Skipping invalid relocation target, existing value is nonzero for type 1, loc ffffffffa086a0e0, val ffffffffa0869b29,请问您知道如何解决吗?或者如果您现在在用这个系统的话,能否将您编译的模块发给我呢?

    • KAAAsS 2022.01.08 5:20下午

      这种问题通常是编译用的内核版本没有对上。看起来你机器的内核是 4.4.180+,7.0 的话可以用官方的下载工具(https://github.com/SynologyOpenSource/pkgscripts-ng)下载 kernel 源码。

      我编译的全部内容都已经在文章里给出了,见第一节的“下载地址”。我的 kernel 是 4.4.59+,感觉应该是可以通用的。

  7. itol 2022.12.03 10:42下午

    编译内核模块时出现以下错误是为什么呢:
    ERROR: Kernel configuration is invalid.
    include/generated/autoconf.h or include/config/auto.conf are missing.
    Run ‘make oldconfig && make prepare’ on kernel src to fix it.

    WARNING: Symbol version dump ./Module.symvers
    is missing; modules will have no dependencies and modversions.

    • itol 2022.12.04 6:45下午

      但是实际上并不起作用,单独运行transparent_proxy.sh的话有错误提示如下:
      -ash ipset:command not found
      是没有安装ipset模块吗?请问怎么安装?

在此评论中不能使用 HTML 标签。