tunsocks 是一个可以将 Linux Tunnel 设备流量包装成 Socks 的开源软件,通常可以结合 OpenConnect 给 VPN 加一层 Socks,供某些特定场景使用。比如,如果我希望将 OpenConnect VPN 作为 V2Ray 的出口(Outbound),就可以用到 tunsocks。

因为我的 OpenConnect 跑在 OpenWrt 上,而 OpenWrt 的官方软件源里并没有 tunsocks 的 ipk 软件包,也没有第三方提供,所以需要自己从源码编译。

tunsocks 使用 C 语言编写,编译虽然是 configuremake 这样的老一套,但是在 OpenWrt 这种嵌入式 Linux 发行版上碰到了一些特殊情况,所以略记一笔,以供日后参考。

event2 库缺失的问题

执行 ./configure 然后 make 会提示 event2 的头文件缺失。

lwip-libevent/netif/fdif.c:18:10: fatal error: event2/event.h: No such file or directory
 #include <event2/event.h>
          ^~~~~~~~~~~~~~~~

libevent2 在 OpenWrt 的官方软件源中已有,所以可以使用 opkg 安装,也可以选择下载最新版源代码之后编译安装。

我选择的后者,从官方网站下载,然后正常编译安装即可,未遇见任何异常。

libdl 库缺失的问题

因为编译安装的 libevent2 会放在 /usr/local 目录下,所以我们需要指定 CFLAGSLDFLAGS 后重新 configure。如使用 opkg 安装,则无需指定。

CFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib" ./configure
make clean
make

此时出现如下错误,也就是找不到 libdl 库。实际上在多数 Linux 操作系统上,这个是 glibc 的一部分,通常会随机附送。

/usr/bin/ld: cannot find -ldl

另外,编译过程中还会出现如下 Warning,提示 reallocarray 函数不存在,而这个函数同样也是 glibc 标准库中理应自带的。

lwip-libevent/netif/udptapif.c:213:18: warning: implicit declaration of function 'reallocarray'; did you mean 'realloc'? [-Wimplicit-function-declaration]
     client->hw = reallocarray(client->hw, client->n, sizeof(*client->hw));
                  ^~~~~~~~~~~~
                  realloc

使用 ldd 命令可以查看当前系统的 libc 版本,如下所示,我的 OpenWrt 上使用的是 musl libc 1.1.24 版,并非 glibc。

# ldd --version
musl libc (aarch64)
Version 1.1.24

搜索得知 musl 一个针对嵌入式设备的 C 标准库实现,从 Changelog 上看,musl 从 1.2.2 版本开始才支持 reallocarray 这个函数

既然如此,我们编译安装一个新版的 musl 就好了。

  1. 下载 musl 1.2.2 或更新的版本。

  2. 运行如下命令编译安装

    ./configure
    make
    make install
    

生成的 libc 头文件和库文件默认会安装在 /usr/local/musl 下,这样也不会污染系统中已安装的版本。

最终编译安装 tunsocks

添加相应的 CFLAGS 和 LDFLAGS 重新运行 configure。

CFLAGS="-I/usr/local/include -I/usr/local/musl/include" LDFLAGS="-L/usr/local/lib -L/usr/local/musl/lib" ./configure

然后 make 编译安装。

# 清除之前生成的文件
make clean

# 编译、安装
make
make install

如果一切正常 tunsock 的二进制文件会安装在 /usr/local/bin 下。

总结

所以在 OpenWrt 上编译安装 tunsocks,正确的步骤应该是:

  1. 安装 libevent2
  2. 编译安装新版 musl
  3. 编译安装 tunsocks

我猜 OpenWrt 上使用 tunsocks 的人不会太多,不然可以考虑做一个第三方 Repo,提供 tunsocks 的 ipk 版。