Socks5『未必』可代理UDP

warning: 这篇文章距离上次修改已过98天,其中的内容可能已经有所变动。

Socks5(下面就简称为s5),掐指一算,岁数已经比站长大不少了,现在成为了被众多设备支持的代理协议之一(另一个是HTTP CONNECT)

s5支持代理UDP,这对于游戏党以及做跨境电商需要直播带货的朋友来说是个福音。但是很多人未必清楚的是:即使是服务端开启了支持,S5也未必可以代理UDP流量

欲知后事如何,请听下面分解

太长不看版

除非特殊实现,否则Socks5无法在同一个端口上面处理TCP和UDP流量。他对于UDP流量的处理实际上是另开一个端口去传输UDP流量

在某些情境下,这种方法会传输失败——比如说服务器防火墙仅开放了s5本身的代理端口,比如说s5服务器位于NAT之后且没做映射,比如说不正确的Socks5 over TLS实现

详解

s5的定义位于RFC1928,我们直接看原文

In the reply to a UDP ASSOCIATE request, the BND.PORT and BND.ADDR fields indicate the port number/address where the client MUST send UDP request messages to be relayed.

说人话就是,Socks5在建立连接之后,默认情况下并不是通过原监听端口(比如1080)去接收UDP流量,而是服务端另起一个端口来监听(端口号随机)并告知客户端,客户端把UDP流量发到这个地址上,服务端再把收到的数据转发到指定目标。之后的话,默认处理方式是一直转发,直到原监听端口的TCP连接断开为止

明眼人应该已经看出来问题在哪了:这个随机选择的端口其实是不能预料到的,虽然部分s5代理服务器支持限定端口范围以方便防火墙控制什么的,但是本质上还是一个治标不治本的处理方式,毕竟还是涉及到了『另开端口』

而且不知读者发现没有,规定并没有说明这个地址一定要是原服务器,换句话说,服务端大可指定另外一台机器来专门转发UDP流量,然后让自己事不关己高高挂起

影响?

为方便理解起见,下面场景假设:有一台支持代理UDP(正式说法是UDP Associate)的s5服务器,监听端口1080

场景一:防火墙控制

此时,在服务器的防火墙放通1080,那么客户端就可以连上并代理TCP流量了

但如果此时客户端发起UDP请求,服务器就去指定端口(比如4170)监听UDP,**问题是,防火墙并不知情,因此阻断了4170UDP入站流量,导致客户端流量发不过去,自然也就无法代理

场景二:错误配置的NAT

如果这个S5服务器:

  • 是内网机器,而入口只做了1080端口映射
  • 是NAT VPS,只能开放有限的端口

以上两个分场景均属于这种情况

和防火墙差不多,『没有设置映射』的请求,因为不知道要转发到哪,会被NAT直接丢弃,更何谈流量代理呢

场景三:错误配置的隧道

早期科学上网教程里面有一种相对少用(但其实好用)的方式:先用Stunnel建立SSL隧道,然后隧道内传输HTTP代理(也就是众所周知的Squid+Stunnel翻墙)

info:笔者的怪习惯:
用SSL指代SSL/TLS

这么干其实问题不大,Stunnel的SSL隧道可以提供足够的安全性,因此底层跑的协议可以随意些(不过HTTP代理被主动探测到时特征很明显,不是407 Auth required就是200 Conn ESDT,很容易被干)

所以嘛,就有些聪明人(褒义,毕竟也算不上是大聪明)在想,HTTP可以,Socks5是否可以呢?说干就干,把Stunnel设置为指向1080端口,客户端也相应修改,一连,成了!

.....吗?

此时你会发现,还是和上面的例子一样,TCP正常,UDP不一定行,因为平时上网页流量TCP压了大头,而且s5支持远程域名解析,所以平时使用压根看不出异常,只有在游戏打不了或者跨境电商视频电话打不通,才开始挠头

很显然,此时SSL是没问题的,成功的保护了原始链接。但是当客户端想要访问UDP内容时候,根据s5工作原理,实际上UDP流量并没有经过Stunnel,而是直接发给了目标服务器,换句话说,UDP在裸奔

裸奔,很多情况下,可能能连上,不过虽然说地址交换过程已经在之前的TCP连接(被SSL保护)中完成,但是后续呢?经研究发现,UDP流量的目标地址其实是在流量前面拼接包头来实现的,换句话说,中间人也能抓到目标地址和实际传输内容,如果UDP内容有那么点功夫王不是很喜欢的内容的话......

常见解决方案

要想解决这个问题,最普遍的方案就是换协议,就s5的协议结构来言,进行深度魔改不太适合

经典解决方案。比如shadowsocks,采用的是TCP和UDP各监听一个端口来解决问题,因为它的udp流量会在开头拼接上目标地址,所以也就不存在说需要通过TCP连接来维持udp的情况(删除原因:研究发现:无实际关联)

info:TCP和UDP为啥可以同一个端口?

因为他们本来就是不同的东西
只是他们恰好都有一个东西叫端口
而且恰巧取值范围都是1到65535罢了

但是这种方案的话,如果要对udp流量进行加密等处理,SSL就不太适合了,需要考虑DTLS

(这也就是为什么ss插件很多对udp流量都是直通处理,因为他根本就没办法处理)

(而且这大概也就是为什么人们在手机上装了ss之后,发现节点很快会挂:像这样TCP和UDP分开不同协议(不同混淆)却是同一个端口的流量,特征其实很大)

另外的一个解决方案就是采用UDP over TCP(UoT),直接把所有UDP流量都当成TCP来看待,也就能顺便把一些针对TCP的措施(比如SSL)都加上去,OpenVPN和Vmess和Trojan差不多都是这样

写在最后

水文章一篇

不过我也好久没更过博客了,权当发表一下个人想法吧

(完)

none
最后修改于:2024年08月14日 19:50

添加新评论