专注于互联网--专注于架构

最新标签
网站地图
文章索引
Rss订阅

首页 »Java教程 » udp穿透nat:穿透Socks5 代理的UDP编程 »正文

udp穿透nat:穿透Socks5 代理的UDP编程

来源: 发布时间:星期三, 2008年12月17日 浏览:80次 评论:0
穿透Socks5 代理UDP编程 杨山河 关键词:Socks5 TCP/IP UDP 代理服务器 RFC1928 Java 网络编程 网络编程中对于数据传输实时性要求较高场合大家都会选择UDP来作为数据传输协议在TCP/IP协议族中UDP协议较TCP协议需要网络系统资源更少然而在企业应用中由于网络安全原因等会导致除了特定端口以外IP数据无法通过专用路由或网关为了支持这类应用制定了专门支持Socks连接socks4/socsk5协议Socks协议允许实现此类功能代理软件Software可以允许防火墙(本文以下内容中防火墙和代理称谓可以等同视的)以内客户通过防火墙实现对外部访问甚至可以允许等待外部连接对于防火墙内部软件Software客户端仅同防火墙协商同防火墙特定端口取得联系然后交换数据而防火墙外部也直同防火墙进行数据交换外部看不到防火墙内部网情况这样起到了防火墙监护功能也满足了大多数通过非常用(如http ftp等)端口交换数据应用需求防火墙内部应用如何通过防火墙将UDP数据传输到防火墙外部并且接受外部UDP数据报文这就是所谓穿透Socks代理UDP编程 RFC1928描述了Socks协议细节告诉我们客户如何同Socks代理协商取得透过该协议对外传输途径英文URL为:http://www.ietf.org/rfc/rfc1928.txt中文翻译参考不是很贴切(但译者还是值得尊敬)但对于E文不大好可以将就下:http://www.china-pub.com/computers/emook/0541/info.htm建议先了解以上链接内容后在阅读下文 代理软件Software都实现了两个版本Socks协议—Socks4以及Socks5,其中Socks5协议支持UDP报文传输以及多种验证思路方法该协议还考虑IP发展需要支持Ipv6 TCP透过代理支持两种思路方法:Bind以及ConnectionConnection是指作为客户端主动连接代理外部服务在这种方式中代理将替代客户发起真正对外部服务连接并来回传输在此连接中需要交流数据;Bind方式则用在那些需要客户机接受到服务器连接协议中例如FTP协议的类除了需要建立个客户--服务器连接报告状态外还需要建立个服务器—客户连接来传输实际数据(当然要注意这里FTP协议通过Socks协议连接远程主机并非通过FTP代理协议)UDP报文传输则意味着代理充当UDP数据传输中间人将防火墙内主机对外数据传递出去将需要引入到防火墙内UDP数据报文转给防火墙特定主机有关TCP穿透讨论和例子很多(给出个实现例子:http://www.codeproject.com/ernet/casyncproxy.asp )就不多讲了在此着重讨论如何实现UDP数据穿透Socks5代理 为了测试方便我简单写了个服务进程在代理外IP为1921680250上监听UDP8100端口接收到个UDP数据报后返回服务器上当前时间给发送UDP报文客户端代理采用Wingate,他在19216801上运行Socks标准端口1080来运行服务监听机器为192168010你可以看到我不能够直接联系运行时间服务机器我会向代理提出我要求由代理进程负责UDP数据报文转发代理软件Software选择Wingate并且为了简单起见采用不需要验证客户验证思路方法好了交代了背景后下面我们就开始穿越代理旅程吧 无论是TCP还是UDP通过代理首先要同代理取得联系为了能够确保在第阶段顺利确保数据传输协议规定客户端采用TCP方式连接联系代理服务器 旦客户同代理1080端口连接上客户首先要发送个版本标识/思路方法选择TCP报文给代理服务器具体格式为:   版本号(1字节) | 可供选择认证思路方法(1字节) | 思路方法序列(1-255个字节长度) 如果是socks4协议版本号就是0x04但是这里是支持UDPSocks5所以是字节0x05此介绍说明对于后面报文格式解释版本部分也都适用 Socks协议定义了0-255种通过代理认证思路方法: 0x00 无验证需求 0x01 通用安全服务应用接口(GSSAPI)   0x02 用户名/密码(USERNAME/PASSWORD)   0x03 至 X'7F' IANA 分配(IANA ASSIGNED)   0x80 至 X'FE' 私人思路方法保留(RESERVED FOR PRIVATE METHODS) 0xFF 无可接受思路方法(NO ACCEPTABLE METHODS) 显然无论是发起Socks请求客户端还是负责转发Socks数据代理都不可能完全实现所有(起码目前还没有)思路方法所以客户端需要把自己能够支持思路方法列出来供代理服务器选择如果支持无验证那么此报文字节序列就为:0x05 0x01 0x00其中0x01表示客户端只支持种验证0x00表示能够支持思路方法是编号为0x00(无验证)思路方法如果客户端还支持用户名/密码验证方式那么报文就应当是:0x05 0x02 0x00 0x02 代理接收到客户请求会根据自身系统实现返回告诉客户验证采用哪种思路方法返回保文格式为: 版本号 | 服务器选定思路方法 如果服务器仅支持无验证验证思路方法它返回字节序列:0x05 0x00客户端同代理数据报文来回应答就是Socks协议验证思路方法选择阶段 接下来就是根据选择思路方法来验证客户身份了虽然我们这里不需要验证但是还是简单讲下0x02用户名/口令验证客户端发送报文格式: 0x01 | 用户名长度(1字节)| 用户名(长度根据用户名长度域指定) | 口令长度(1字节) | 口令(长度由口令长度域指定) 不清楚为什么报文首字节是0x01(按照惯例应当是0x05)整个报文长度根据用户名和口令实际长度决定用户名和口令都不需要以’\0’结束服务器会根据提供信息进行验证返回如下报文字节序列映像为: 0x01 | 验证结果标志 验证结果标志可以为:0x00 验证通过其余均表示有故障不可以继续下协议步骤 在通过了验证步骤的后接下来就是确定UDP传输端口了这里面需要确定两个重要端口:1、客户端发送UDP数据本机端口方面可以为发送数据指定端口方面告诉代理如果有数据返回就传递给该端口构成个UDP传输回路2、代理想在哪个端口接收客户发送UDP数据报作为对外UDP Socket申请方双方协商确定个端口后可以持续通过此端口向外部主机发送数据也可以通过此端口由代理接收外部主机发回UDP数据再通过此端口发给UDP发送请求客户端客户端会按照以下格式发送TCP数据字节序列: 协议版本 | Socks命令 | 保留字节 | 地址类型 | 特定地址 | 特定端口 Socks命令有3种:CONNECT (编号0x01) BIND (0x02) UDP(编号0x03) 保留字节长度1为0x00 地址类型有3种: 0X01  该地址是IPv4地址长4个8bit字节 0X03  该地址包含个完全域名个8bit字节包含了后面名称8bit数目没有中止’\0’ 0X04 该地址是IPv6地址长16个8bit字节 特定地址般对于多IP主机有意义如果不是或者不关心哪个IP发起UDP数据传输就可以填0000地址类型选择0x01比较重要就是UDP传输将要从哪个UDP端口发起般为了避免硬性指定个端口导致引起冲突会首先生成个UDP套接字用生成套接字既定端口来作为自己传输UDP端口并通过此步骤告知代理服务器譬如临时生成个UDP套接字UDP选择端口2233作为传输UDP数据本地端口那么此报文就为:0x05 0x03 0x00 0x00 0x00 0x00 0x00 0x08 0xb9 其中0x08 0xb9换算成10进制就是2233 代理服务器会根据自己端口占用情况给出个有关代理服务器端口回复字节序列告诉客户可以将UDP数据发送到此地址和端口中去以实现UDP穿透代理返回字节序列为: 版本 | 代理应答 | 保留1字节 | 地址类型 | 代理服务器地址 | 绑定代理端口 代理应答可以为值: 0X00 成功协商 0X01 常见Socks故障 0x02 不允许连接 0X03 网络不可到达 0X04 主机不可到达 0X05 连接被重置 0X06 TTL 失效 0X07 命令不支持 0X08 地址类型不支持 0X09 直到0xff都保留 代理地址指客户端需要发给那个IP绑定端口指代理将在哪个端口上为客户接收数据并转发出去地址类型、地址参照上面解释 通过以上TCP协商几个步骤后现在客户端明确了自己将需要发送UDP数据发给代理服务器某个IP某个端口了代理服务器也知道是哪个IP发送数据报给自己如果接收到由于转发此UDP数据报而从远端目标主机传回数据报他需要根据协议将收到数据报返回给客户特定端口此特定端口就是此步骤中字节序列中绑定代理端口 在传输UDP数据时由于通过代理所以需要按照格式进行包装在需要传送数据的前添加个报头具体为: 保留2字节0 | 是否数据报分段重组标志 | 地址类型 | 将要发到代理外目标地址 | 远端目标主机端口 | 需要通过代理传送出去数据 是否数据报分段重组标志为0表示该数据报文是独立不需要重新组合其他表示特定序列号以利于UDP报文整合 这里地址是最终接收此UDP数据代理外服务器地址我们这个例子中就是1921680250端口就是8100根据地址类型区别具体需要传送数据起始位置也区别如果是Ipv4那么数据从整个UDP报文10字节处开始如果是指定了域名那么就是从262处开始Ipv6地址类型就从20处开始为数据字段这些需要我们在实际传输数据时注意假如要传送10字节数据9到96.96.96.961024端口那么传送数据字节序列大致为: 00 00 00 01 60 60 60 60 04 00 09 09 09 …….09 保留 是否分段重组 Ipv4 96.96.96.96目标主机IP 端口1024 从此处开始为数据 而这的后如果远端目标主机有数据返回代理服务器会在将数据传回给UDP 客户端时将数据也做类似上面封装即添加个报头客户需要接收这个报头实际上也明确通知UDP 客户端这个数据报是哪个服务器发回 下面就来看看给出代码:见附件工程我将支持Socks5UDP写成个Java类供大家参考相关解释见注释部分 通过上面分析我们可以大体上整理总结到透过Socks5进行UDP编程需要注意几点: 1、 Socks5编程身份验证 由于防火墙作用几乎是隔绝内外非正常连接而Socket可以通过任何端口连接到外部所以作为对Socket4改进Socket5增加了对协议访问验证功能这些验证功能没有规定定采用什么思路方法般看防火墙自身支持以及客户端能够支持什么思路方法这意味着作为客户端必须将自己支持思路方法在协商阶段的初就告诉代理服务器而代理服务器自己根据已经实现支持哪种验证思路方法而选择特定思路方法回复客户端意味着针对区别代理服务器以及区别客户端很可能对于验证思路方法支持上有区别需要视具体应用环境而定这些增加了Socket5客户端以及Proxy server软件Software编写难度但是增强了安全性 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数据并转发 2来也告诉了代理服务器将来在某个端口发出去后得到反馈数据也按照线路返回给客户此端口点很重要笔者在此处犯了导致浪费了很多时间 4、 TCP/UDP连接 2重性 可以看到Socks5 使用会占用至少个TCP连接这样导致代理服务器负担很重所以在具体应用时需要考虑有关代理服务器存在负载问题 以上即有关UDP穿透Socks5代理点心得体会希望能够得到大家指正
0

相关文章

读者评论

发表评论

  • 昵称:
  • 内容: