分享一个 tun2socks 实现

2023-01-31 20:31:05 +08:00
 heiher

自用分享,一个 C 语言实现、基于协程和 LwIP 用户态协议栈的 tun2socks 实现,当前支持 Linux 和 Android 系统。

项目地址: https://github.com/heiher/hev-socks5-tunnel

功能

  1. IPv4/IPv6 双栈。
  2. 支持重定向 TCP 连接。
  3. 支持重定向 UDP 报文。(UDP over TCP ,需配合hev-socks5-server)

性能

详细信息

速率

CPU 使用率

4961 次点击
所在节点    分享创造
38 条回复
missdeer
2023-02-01 09:14:17 +08:00
更想要 windows 版,因为 Linux 、mac 上用 iptables ,pf 就能工作得很好
heiher
2023-02-01 09:17:57 +08:00
@missdeer 确实,Linux 上我也是使用 tproxy 方案,性能更好,我也主要是用在 Android 系统上的。可惜底层的协程框架目前还不支持 Windows [Doggy]
nmap
2023-02-01 11:06:48 +08:00
请问原理是什么
heiher
2023-02-01 11:31:29 +08:00
@nmap 简述原理:创建 tun 虚拟网卡,配置策略路由使网络应用程序的 TCP 和 UDP 流量经过虚拟网卡,前向链路上 tun2socks 程序从虚拟网卡接收经过操作系统网络协议栈分片的 TCP/IP(UDP/IP)报文,程序再通过用户态网络协议栈 LwIP 将 TCP 分片重组成流,转发至连接着 socks5 服务端的 socket 上。反向链路,程序从 socks5 服务端接收到流数据后,通过 LwIP 的 TCP 写 API 送到用户态网络协议栈进行分片,再将分片后的报文送入虚拟网卡,随后被操作系统重组,最终送到网络应用程序。
aa51513
2023-02-03 09:36:27 +08:00
需要预先手动创建 tun 网卡吗,如果是自动创建 tun ,自动修改路由就好了
heiher
2023-02-03 09:53:08 +08:00
@aa51513 #5 自动创建 tun 网卡设备,但不会自动创建路由规则,主要是考虑到使用需求不同,比如最简单的用法是直接创建一个默认路由,而有些用户可能用策略路由只针对 TCP 、UDP 协议或指定用户下的进程的网络流量。
TongNianShanHe
2023-02-05 17:08:26 +08:00
楼主您好,有 android 端的参考例子吗,我这边根据您的代码调用了 TProxyStartService ,然而好像没生效(第二个参数应该填的是 v*nservice 创建后的 fd 吧)
heiher
2023-02-05 17:40:13 +08:00
TongNianShanHe
2023-02-05 21:44:18 +08:00
感谢,找过没找到,应该是被我忽略了。
但问题似乎还是没有解决,试过 demo 里的写法,没法连通,我的 local 端没有数据(此前用的 xjasonlyu 的 tun2socks 实现),logcat 报“getIfIndex: cannot find interface tun0”,把 demo 的 release 跑了一遍,也不行。
我先放一下吧,近期没有多余时间去排错了,但是看图感觉性能会比之前好一些,先 star 一下,后续有时间再弄。
heiher
2023-02-05 21:53:48 +08:00
@TongNianShanHe #9 重点检查配置文件对不对,可以先用生成的配置文件在 Linux 上验证一遍。另外一个需要注意的地方是 JNI 的 PKGNAME ,我不知道你改了没有,可以在 Makefile 中用宏定义覆盖为你的项目包名。
TongNianShanHe
2023-02-05 22:10:31 +08:00
@heiher PKGNAME 和 hev-jni.c 的 64 行( class 名)都改过,配置文件我注意到你给的例子里填写 IPv4 地址是没有单引号的,但是安卓 demo 的代码里是加了单引号,两种都试过了,看 logcat 感觉加了单引号是对的,因为改动后 local 端有了 socks5 的握手,但只发出了第一部分,后续都无法接收到。
heiher
2023-02-05 22:24:33 +08:00
@TongNianShanHe #11 看你描述的现象,我怀疑是没有处理好访问 socks5 server 要加入例外(不通过 VPN)的情况。Android VpnService 给出了 protect(Socket)的[方法]( https://developer.android.com/reference/android/net/VpnService#protect(java.net.Socket)),但 socks5-tunnel 在 jni 里创建 socket ,所以我的 demo 里是把当前应用加入到 disallow 列表里,当处于全局模式时。在 per app 模式是是不允许选择当前应用的。

https://github.com/heiher/hev-htproxy/blob/master/app/src/main/java/hev/htproxy/TProxyService.java#L99-L105
TongNianShanHe
2023-02-05 22:56:01 +08:00
@heiher 这个情况其实考虑过,但我用的是白名单(白名单是硬编码),local 是一个独立进程(通过 sh 运行,写的很糙,因为是自己用)
我再去看看源码吧,不排除 local 端某些情况下的不兼容的可能性,谢谢你的解答。
heiher
2023-02-05 23:03:33 +08:00
@TongNianShanHe #13 好,不客气哈~ 也可以试试在 htproxy 上改改 socks5 server address 来验证。
TongNianShanHe
2023-02-06 12:02:55 +08:00
@heiher 我调试了一下,发现是 tun2socks 确实是连通的状态,但是有俩问题:
1. 握手“黏包”(其实这也不算问题,毕竟 tcp 流,已经自行处理过了)
2. socks5 里面,通过 ip 地址进行访问是正常的(也就是 command 为 0x01 ),通过域名访问就“死”了,检查了一下发现 DNS 请求头(也就是 udp )的 command 是 0x05 ,我以为是协议做过魔改,所以我把 command=0x05 映射到了 udp 转发上,但也是无法工作。(刚重新看了一遍帖子才发现,是必须要用 UDP over TCP 方式做吗?)
TongNianShanHe
2023-02-06 12:33:22 +08:00
@heiher 试着做了个 UDP over TCP 的 demo ,证实了这个想法,确实需要用 UDP over TCP 方式,没有问题了,打扰你了
heiher
2023-02-06 12:37:09 +08:00
@TongNianShanHe #15 是的,hev-socks5-tunnel 的 udp relay 是采用扩展的 socks5 cmd 实现的 udp over tcp ,不是协议标准的 udp 方式,原因是为了让所有流量都走 tcp ,这样方便过 cdn 。
heiher
2023-02-06 12:37:59 +08:00
@TongNianShanHe #16 好的,hev-socks5-tunnel 的 udp 功能需要配合 hev-socks5-server 或兼容的服务端使用。
TongNianShanHe
2023-02-06 18:33:18 +08:00
@heiher 花了点时间把我那边的适配做好了(我没想到 UDP over TCP 包也做了魔改)

如果想使用这个库的话这边有几个提示:这个 tun2socks 实现基于 socks5 ,支持两个模式( 0x01 是 CONNECT ,0x05 是 UDP over TCP ),并且 UDP over TCP 包的前两位和 10 ,11 位是当前包的长度,中间的和 socks5 udp relay 转发头是差不多的(也就是说 IPV4 relay 头的长度会从 10 变为 14 ,IPv6 同理加 4 ),其他的都是差不多的,直接转发就行。

等哪天真闲下来就试着啃啃这个项目吧,感谢分享。
heiher
2023-02-15 13:38:47 +08:00
@TongNianShanHe Android VPN over socks5 proxy 参考实现: https://github.com/heiher/sockstun

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/912044

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX