这里的地址是最终接收此UDP数据的代理外的服务器地址,我们这个例子中就是192。168。0。250。端口就是8100。根据地址类型不同,具体的需要传送的数据起始位置也不同。如果是Ipv4,那么数据从整个UDP报文的10字节处开始,如果是指定了域名,那么就是从262处开始,Ipv6地址类型就从20处开始为数据字段。这些需要我们在实际传输数据时注意。假如要传送10字节的数据9到96.96.96.96的1024端口,那么传送的数据字节序列大致为:
00 00 00 01 60 60 60 60 04 00 09 09 09 …….09
保留 是否分段重组 Ipv4 96.96.96.96目标主机IP 端口1024 从此处开始为数据
而这之后,如果远端的目标主机有数据返回,代理服务器会在将数据传回给UDP 客户端时将数据也做类似上面的封装,即添加一个报头。客户需要接收这个报头,实际上也明确通知UDP 客户端,这个数据报是哪一个服务器发回的。
下面就来看一看给出的代码:见附件工程。我将支持Socks5的UDP写成一个
Java类,供大家参考。相关解释见注释部分。
通过上面分析我们可以大体上总结到透过Socks5进行UDP编程需要注意的几点:
1、 Socks5编程的身份验证
由于防火墙作用几乎是隔绝内外的非正常连接,而Socket可以通过任何端口连接到外部,所以作为对Socket4的改进,Socket5增加了对socket协议访问的验证功能。这些验证功能没有规定一定采用什么方法,一般看防火墙自身支持以及客户端能够支持什么方法,这意味着作为客户端必须将自己支持的方法在协商阶段之初就告诉代理服务器,而代理服务器自己根据已经实现支持哪种验证方法而选择特定的方法回复客户端。意味着针对不同的代理服务器以及不同的客户端,很可能对于验证方法支持上有区别,需要视具体的应用环境而定。这些增加了Socket5客户端以及Proxy server软件的编写难度,但是增强了安全性。
2、 TCP保持重要性
要发送穿透代理服务器的UDP数据报,其实首先需要建立客户端到代理服务器的TCP连接,通过一系列的交互,获得代理服务器的许可才能够发送出去(同时代理服务器业记录下连接的在Socks5服务的客户IP和端口),也确保从远端发回的数据能够通过代理服务启发回给某个UDP客户端(因为它登记了一个关于Socket UDP的通路映射)。所以为了发送UDP数据,必须建立和保持这个TCP数据。RFC1928也提到,不能取得代理服务器的通道后就关闭TCP连接,否则代理服务器以为UDP Socket通过代理的请求已经结束,不需要继续保留UDP的对外Socket映射记录,从而导致每发送一次UDP就要重新建立TCP连接协商UDP映射,增加不必要的麻烦。所以,我们需要保持UDP客户端到到代理服务器的TCP连接持久,不必显式关闭它。
3、 UDP本地端口选定
UDP大多数是同具体端口相关的,所以一定要在同代理服务器协商UDP映射时告知客户端UDP的端口。一来将UDP同某个端口绑定,使得代理服务器接收UDP数据并转发,二来也告诉了代理服务器将来在某个端口发出去后得到的反馈数据也按照线路返回给客户的此端口。这一点很重要,笔者在此处犯了错误导致浪费了很多时间。
4、 TCP/UDP连接二重性
可以看到Socks5 的使用会占用至少一个TCP连接,这样导致代理服务器的负担很重。所以在具体的应用时,需要考虑关于代理服务器的存在的负载问题。
以上即关于UDP穿透Socks5代理的一点心得,希望能够得到大家的指正。