V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
heiher
V2EX  ›  分享创造

Android VPN 转 Socks5 代理应用分享

  •  2
     
  •   heiher ·
    heiher · 2023-02-17 21:20:27 +08:00 · 6255 次点击
    这是一个创建于 678 天前的主题,其中的信息可能已经有所发展或是发生改变。

    大家好,我又来分享轮子啦~

    SocksTun是我最近开源的一个基于HevSocks5Tunnel实现的 Android VPN ,用于将手机端的 TCP 、UDP 流量通过 Socks5 代理进行转发。其实它只是一个参考实现,主要用于演示如何用 HevSocks5Tunnel 实现 VPN 。它可以对接明文的标准 Socks5 协议,比如 Socks5 服务(或映射)部署在本地局域网,也是能具有一些实用性的吧。

    特性支持

    • 支持重定向 TCP 连接。
    • 支持重定向 UDP 报文。(Fullcone NAT ,UDP 从 UDP 转发、UDP 从 TCP 转发)
    • 支持简单用户名 /密码认证。
    • 支持指定 DNS 地址。
    • IPv4/IPv6 双栈。
    • 全局 /按应用双重模式。

    使用方法

    服务端

    HevSocks5Server

    HevSocks5Server支持 UDP 从 TCP 转发,可以运行在 Linux/BSD 和 macOS 系统上,配置、使用方法也比较简单。

    # 下载、编译
    git clone --recursive https://github.com/heiher/hev-socks5-server
    cd hev-socks5-server
    make
    
    # 运行
    hev-socks5-server conf.yml
    

    conf.yml:

    main:
      workers: 4
      port: 1080
      listen-address: '::'
    
    misc:
      limit-nofile: 65535
    

    其它

    任意支持标准 Socks5 协议的 TCP(Connect)和 UDP(Associate)的服务端即可。

    手机客户端

    1. 从项目发布页下载 APK 并安装。
    2. 打开应用,配置 Socks5 地址、端口和 DNS 地址。
    3. 如果使用 HevSocks5Server 服务端,钩选 UDP relay over TCP ;使用其它服务端则去掉。
    4. 保存配置后,点击启用开启 VPN 服务。

    性能评测

    Android VPN App 目前还没有做过性能、能耗的评测(其实是不会~),之前在低性能的 RK3399(AArch64 架构)设备做过几款 tun2socks 的评测,结论是只有 HevSocks5Tunnel 可以几乎跑满物理网卡的最大带宽,并且对应的 CPU 资源使用最少。那么,基于它实现的 Android VPN 应该具有相对较好的节能效果吧。

    速率

    CPU 使用率

    最后

    最开心的事情当然是开源的这些小轮子能跑起来,确实对大家有用,期待支持与反馈~

    43 条回复    2024-10-07 11:34:12 +08:00
    HXHGTS
        1
    HXHGTS  
       2023-02-18 10:42:27 +08:00 via Android   ❤️ 3
    建议改成 socks2tun ,和 tun2socks 反过来,哈哈
    Achophiark
        2
    Achophiark  
       2023-02-18 19:49:00 +08:00 via Android
    支持开源。
    mogging
        3
    mogging  
       2023-02-19 07:48:21 +08:00 via Android
    感觉可以用于抓包?
    studyingss
        4
    studyingss  
       2023-02-19 09:28:01 +08:00 via Android
    DNS 那一栏不支持填端口号,没办法和其他代理配合使用。
    参考 https://www.pishifu.org/Logs/clash-and-adguard.html
    原因是需要接管 dns 实现分流。
    heiher
        5
    heiher  
    OP
       2023-02-19 23:25:17 +08:00 via Android
    @mogging 确实可能,一些使用 VPN 方案的抓包应用就是使用 tun2socks 方案实现的 TCP 流重组并直接对接到物理网络。
    heiher
        6
    heiher  
    OP
       2023-02-19 23:28:03 +08:00 via Android
    @studyingss 是的,DNS 两项是配置的 VPN 网络的 DNS 地址,不支持直接指定端口。就分流的需求来说,其实可以实现在服务端,因为 DNS 流量也是通过 Socks5 的。
    t6attack
        7
    t6attack  
       2023-04-04 12:16:14 +08:00
    一直有疑惑,为什么此类应用必须设置 DNS 呢? socks5 代理不应该是直接把域名传到代理端吗?
    为什么要在本地解析域名?
    heiher
        8
    heiher  
    OP
       2023-04-04 23:02:55 +08:00 via Android
    @t6attack 因为 IP 网络的地址类型只有 uint32 和 uint128 两种,假设支持 domain string 就像 socks5 一样,那么你这个想法就可以实现啦。
    cxc520589
        9
    cxc520589  
       2023-07-02 17:54:48 +08:00
    这用途我正需要,请问安卓手机怎么部署?使用 termux 来部署吗
    heiher
        10
    heiher  
    OP
       2023-07-02 23:36:03 +08:00 via Android
    @cxc520589 APK 直接安装
    cxc520589
        11
    cxc520589  
       2023-07-03 11:44:53 +08:00
    @heiher 我的意思是安卓上的服务端
    cxc520589
        12
    cxc520589  
       2023-07-03 12:07:09 +08:00
    @heiher 我的用途是把手机上的 Google oneVPN 转接到局域网上
    ClarkAbe
        13
    ClarkAbe  
       2023-07-20 15:23:05 +08:00
    挺不错, 但是 DNS 那里能不能继承 WIFI 或者 4G 的 DNS...
    heiher
        14
    heiher  
    OP
       2023-07-20 16:32:26 +08:00
    @ClarkAbe 如果网络出口变成了 Socks5 代理服务器,那么客户端本地的 WIFI 或 4G 的 DNS 未必是合适的。
    ClarkAbe
        15
    ClarkAbe  
       2023-07-21 08:33:52 +08:00 via Android
    @heiher #14 但是会有可能用家庭内网 DNS 的情况
    anciusone
        16
    anciusone  
       2023-09-06 14:47:08 +08:00
    已 star ,试了下,挺简单方便的。
    studyingss
        17
    studyingss  
       2023-10-29 12:26:23 +08:00
    @heiher
    我的表述有误。
    在 clash 这一系的代理工具里,使用了 fake-ip 或者类似的机制来让代理工具可以取得域名,因此从 tun 接管流量的时候需要把 dns 填写成代理工具在本地开放的端口。
    heiher
        18
    heiher  
    OP
       2023-10-29 12:32:31 +08:00 via Android   ❤️ 1
    @studyingss 其实代理工具可以直接使用标准端口,因为它接管了 tun 上所有的流量,也就是可以虚拟任何地址上任意端口的服务。也就是不管 tun2socks 的客户端填写或继承动态分配的 dns 地址是什么,只要流量经过代理工具都可以捕获,我这的应用场景是这样处理的。
    studyingss
        19
    studyingss  
       2023-11-05 22:08:29 +08:00
    @heiher 虽然没听懂,但是还是谢谢。
    clash 的配置一般会在 127.0.0.1:6060 这样的端口上开一个 dns server ,我不是很懂如果使用标准配置要怎么写,127.0.0.1:53 ? 后续我会尝试下。

    我有一个新的问题,就是你的 banchmark 看起来很好看,比其他所有实现都更好,但是根据我粗浅的理解,在某一方面的提升一般会付出另外一些代价,比方说速度更快一般就会消耗更多的内存,要么就是支持的特性少一些,但在你的测试里,速度更快,内存消耗也更少,
    你的实现里面用了 lwip ,badvpn 的 tun2socks 也一样用了这个库,在这个部分应该是没有区别的,在我的理解里 tcp stack 的实现应该是最影响性能的部分,我有点疑惑。
    翻了一下 readme ,没有找到你的实现的相关文档,所以想请教一下,你的实现在测试的表现上比其他实现更好的主要原因是什么?可以简单讲解一下吗?或者提供一点线索?
    heiher
        20
    heiher  
    OP
       2023-11-08 14:12:22 +08:00   ❤️ 1
    @studyingss #19

    如果是在 clash 分流规则中捕获 dns 访问,填写任何 dns 服务器地址都行,只要与分流规则中一致。

    关于性能我认为主要有这两方面:
    1. 内存使用方面:编程语言的影响很明显,比如 GoLang 就明显没有 C 语言容易精细控制内存。
    2. 传输速度方面:一方面是对 lwip 的调参,提高单次 IO 的载荷从而提高整体性能;另一方面是将 lwip 的 zero-copy 真正应用起来。
    specture
        21
    specture  
       2023-12-26 19:43:25 +08:00
    @heiher 请问一下在 ios 或者安卓上怎么做 dns 的 hijack ? 我看 clash.meta 的实现是在 tun 中判断 udp 的目的 IP 和端口,然后调用 fakedns server 做解析。Hev-socks5-tunnel 的实现下应该怎么做呢?
    heiher
        22
    heiher  
    OP
       2023-12-26 21:00:53 +08:00
    @specture #21 在 Socks5 服务端做分流、规则策略等。
    specture
        23
    specture  
       2023-12-27 14:02:22 +08:00
    @heiher 请问下这个 socks5 服务端是值本机的 socks5 服务端部分还是指 远程服务器侧的 socks5 服务?按我理解应该是本机的部分?因为并不是所有流量都要走代理,所以一定会在本机这做解析和分流
    specture
        24
    specture  
       2023-12-27 14:04:57 +08:00
    @heiher 如果是本机的服务端部分,我理解是否正确:dns 请求的 UDP 53 端口请求流量通过 socks-tunnel 从 tun 到 tunnel 再到本机运行的 clash/v2ray 等 socks5“服务端”。 服务端里面基于 dst.port 和 dst.ip 判断是否为 dns 请求,如果是 dns 请求调用 fakedns 做解析,拿到解析结果后通过一个 udpconn 写回发起 dns 请求的 127.0.0.1:59001 这样的源地址?
    cnfzv
        25
    cnfzv  
       363 天前
    用的别的普通 socket 服务器( https://github.com/txthinking/socks5),失败了 socks5: 2023/12/29 23:42:38 [E]: client want to used addr 0.0.0.0:0, listen addr: [::]:56804
    cnfzv
        26
    cnfzv  
       363 天前
    @cnfzv 。找到问题了,简单的 socks 服务器不支持 udp bind 导致的。。。。。。
    heiher
        27
    heiher  
    OP
       363 天前
    @specture hev-socks5-tunnel 只做 tun2socks 业务,如果有部分流量本地直连的需求,那么分流器要运行在本地侧。分流器是 socks5 服务器,通过 socks5 协议与 socks5-tunnel 交互。关于 fakedns 流程大概是这样:

    1. 应用程序请求解析域名的 ip 地址,相应的 dns 请求发送到 tun 。
    2. socks5-tunnel 收到 tun 上的 udp 协议的 dns 请求后,通过 socks5 udp associate 方式发送给分流器。
    3. 分流器通过协议识别(比如目标端口或报文内容等)发现是 dns 请求,重定向请求至内部的 fakedns 模块,生成 fake ip 的 dns 响应,发回 socks5-tunnel 。
    4. 应用程序收到 dns 响应后,开始发起对 fake ip 的访问。相应的 tcp 或 udp 报文再次被分流器捕获,分流器通过报文中目标地址的 fake ip 查找分流规则, 建立与远程服务器的连接。
    heiher
        28
    heiher  
    OP
       363 天前
    @cnfzv 如果 socks5 服务端不支持 udp associate 命令,只能支持 tcp/ip 。基于 udp 的 dns 也不能支持。换一些 socks5 服务端即可。
    cnfzv
        29
    cnfzv  
       362 天前
    @heiher 0,0 我测试了,包括你提供的服务器都不好用。。。。使用你的 hev-socks5-server ,选择使用 tcp 中继可以使用,取消选择后 udp 请求会有问题。
    hev-socks5-server 部署在 Ubuntu22 上,使用你的安卓应用 sockstun 访问,安卓代码使用 Windows 编译,hev-socks5-tunnel 已经更新到 2.6.5 。
    以下是使用的其他 socks5 服务器,
    https://github.com/snail007/goproxy
    https://github.com/txthinking/socks5
    https://github.com/things-go/go-socks5
    heiher
        30
    heiher  
    OP
       362 天前 via Android
    @cnfzv udp 走 udp 传输的话,客户端要求有访问到服务器端任意 udp 端口的能力。
    cnfzv
        31
    cnfzv  
       362 天前
    @heiher Windows 防火墙已经关闭,Ubuntu 默认防火墙没有开启。
    在你的 hev-socks5-server 上,使用 https://github.com/tabjy/android-vpn-tun2socks 可以访问,但是访问多个网站后域名解析用的 udp 请求好像会有问题,浏览器会提示 DNS_PROBE_FINISHED_NO_INTERNET 。
    cnfzv
        32
    cnfzv  
       361 天前
    核实了,应该就是 issues 中提到的服务端 TCP 流处理问题,服务端没有处理,没有正常返回请求。但是看了下协议,这种方式好像不符合协议标准吧? https://datatracker.ietf.org/doc/html/rfc1928#autoid-3
    实在研究不动了,希望作者能解答
    cnfzv
        33
    cnfzv  
       361 天前
    😭找到另一个帖子的回复了。 有关 TCP delay 都是系统默认配置,“粘包”效果是因为 socks5 客户端有意实现为预测发送,是有减少延迟作用的。不知道切换前怎样,切换后应该是 dns 经过 socks5 服务器端,不知道是不是因为 dns 的延迟。浏览器的开发者选项中网络传输页面应该可以显示每个资源的加载时间,不妨对比看看,需要注意的是尽可能网络环境的抖动影响,比如本地跑 socks5 服务器,访问本地或国内 http 资源。
    这么操作明显和 rfc1928 协议逻辑不一样了,在握手未完成之前就提交了请求,而遵守协议的其他服务端会因为没有在握手后收到请求而无法进行相应。
    --另外我找到的 https://github.com/tabjy/android-vpn-tun2socks 好像也有问题,UDP 请求貌似不太对,会导致服务端疯狂监听端口但又不进行连接。
    23 年最后一折腾,我好像总会踩坑,唉,心累
    heiher
        34
    heiher  
    OP
       361 天前
    @cnfzv 如果将 TCP 视作为流,而不是报文。在客户端对服务端的响应预测无误的情况下,服务端仍不能正确处理流上数据,我觉得这是服务端的实现问题。
    specture
        35
    specture  
       361 天前
    @heiher 感谢解答。按照类似的方式实现了目标
    cnfzv
        36
    cnfzv  
       361 天前
    @heiher 但是这种预测和协议的标准不符了吧? 就像去传统的自动售货机买饮料一样,你需要先投币,等机器识别后按按钮饮料才会掉下来,但是你投币和按按钮同时进行购买是没法成功的。你的这种实现等于是做出了一个部分兼容 socks5 的新协议出来了
    heiher
        37
    heiher  
    OP
       361 天前
    @cnfzv socks5 协议标准有对这一细节做具体的约束吗?在你的类比味结论是没法成功,而 socks5 协议的消息格式设计其实是可以成功的。比如 hev-socks5-server 、xray 等就是严谨处理流上数据的实现。

    我不否则事实上与某些服务端存在兼容问题,之前分析过一个案例,问题实质就是:服务端分配了一块较大的接收缓存区,简单粗暴的读取了这一时刻客户端方向的全部流数据,假定接收缓存区中只有当前阶段的请求消息,而不是按照 socks5 消息格式一段一段处理掉,导致后续片断被丢弃。

    因此,我自己目前得出的结论是:不是我设计了个新协议,而是有的服务端实现的不好。:D (除了降低 rtt 以外,合并发送还有消除 socks5 传输特征的考虑
    cnfzv
        38
    cnfzv  
       360 天前
    @heiher 这个是协议说明 https://datatracker.ietf.org/doc/html/rfc1928 ,根据标准里的说明。
    客户端连接到服务器并发送版本 标识符/方法选择消息,服务端是要返回方法选择信息的,在交互完成后可以传输子协商信息的,而在子协商之后才是发送详细请求。Once the method-dependent subnegotiation has completed, the client sends the request details.
    而你使用传输方式或者说用了预测发送,但是这种方式,是基于“服务器一定允许连接“的假设而进行的。
    诚然,这种方式确实如你所说优化了传输效率,对于实际使用会有不少的提升,但是这种方式并不符合协议的标准。
    并不是我非得在这里认死理抬杠,是因为这么个搞法兼容性真的很爆炸,github 找了好几个 go 的 socks 服务没有一个能好用的,使用 openssh 的 sock5 转发也是没法使用的,不是我事多,是这么个搞法兼容性真的很难受😭
    heiher
        39
    heiher  
    OP
       360 天前
    @cnfzv 理解。openssh 的 socks5 server 是可以的。ssh -D 1080
    cnfzv
        40
    cnfzv  
       360 天前
    @heiher 😥你确定吗? ssh -D 0.0.0.0:8000 并不好用,使用你的安卓程序连接的,并不好用。只有 dns 请求过不去
    heiher
        41
    heiher  
    OP
       360 天前 via Android
    @cnfzv 这是另外一个事情,因为 openssh socks5 不支持 udp 。
    heiher
        42
    heiher  
    OP
       340 天前
    @cnfzv 哈喽,hev-socks5-tunnel 2.6.6 版本,sockstun 2.0 版本开始,支持流水化 socks5 握手开关(请求写合并),且默认关闭。

    https://github.com/heiher/hev-socks5-tunnel/releases/tag/2.6.6
    https://github.com/heiher/sockstun/releases/tag/2.0
    ChasenTsai
        43
    ChasenTsai  
       81 天前
    大佬你好,希望能得到指点:
    我的需求:在安卓设备上重定向指定网址,全局、免 root 。
    举个例子: http://abc.com/list -> http://127.0.0.1:8080/list
    再举例子: https://abc.com/list -> https://127.0.0.1:8443/list

    DNS 解析的部分我用 Virtual-Hosts 启动 vpn 搞好了,然而端口把我难倒了。
    在项目里调试了两天,始终找不到可以修改端口的地方,原谅我只是个前端仔,网络基础薄弱

    当我看到 tun2socks 的时候,第一反应是 这把牛刀可以杀我这只鸡
    幻想:用 Socks5 启动一个服务,实现上述规则;再用 SocksTun 连接这个服务
    于是 clone 了源码企图读懂,想多了 C 的部分根本读不懂

    于是前来求助:我想象中的路子是否能实现?
    或者说根本不需要借用 socks 的力量,而是单纯解析 vpn 截获的消息进行修改就能实现?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2749 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 11:59 · PVG 19:59 · LAX 03:59 · JFK 06:59
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.