Socks5代理和socks4 socks4a相比,多了一个验证功能和udp代理的功能。
而Socks5的tcp代理几乎和socks4、socks4a一样简单,但udp相对复杂一些。
首先来说验证,无论是要代理tcp还是udp,开始验证都是要一个tcp连接的,验证过程也一样,验证完了才分tcp和udp的实际代理过程,其中市面上有很多种不同验证方式,但是今天咱们只需知道这三种最实用的验证方法即可,下面为大家讲解下。
UDP和TCP公共部分
如果一个客户想通过Socks5代理,那么开始他会发送以下3种内容
05 01 00 共3字节,这种是要求匿名代理
05 01 02 共3字节,这种是要求以用户名密码方式验证代理
05 02 00 02 共4字节,这种是要求以匿名或者用户名密码方式代理
如果Socks5代理允许匿名那么就返回05 00两个字节,如果要求验证就返回05 02两个字节。
这里匿名等一下,先说要求密码验证的,因为要求验证就比匿名多了一步而已,后头是一样的,所以先说密码验证。
当上面Socks5返回05 02两个字节后
客户端发送01 06 6C 61 6F 74 73 65 06 36 36 36 38 38 38
1、01固定的
2、06这一个字节这是指明用户名长度,说明后面紧跟的6个字节就是用户名
3、6C 61 6F 74 73 65这就是那6个是用户名,是laotse的ascii
4、又一个06共1个字节指明密码长度,说明后面紧跟的6个字节就是密码
5、36 36 36 38 38 38就是这6个是密码,666888的ascii。
6、假如这后面还有字节,一律无视。
这时Socks5代理就验证了用户名laotse密码666888对不对,如果不对直接关闭连接就可不用反馈了。
如果这个用户名和密码通过了,可以进行代理,那么就发送01 00给客户端。那么下面就和匿名是一样的了,匿名就是省略了这一步而已。
这时无论匿名或者通过了密码验证的客户端向Socks5发送下列三种方式:
TCP单独部分:
第一种
05 01 00 03 13 77 65 62 2E 73 6F 75 72 63 65 66 6F 72 67 65 2E 6E 65 74 00 16
1、05固定
2、01说明是tcp
3、00固定
4、03说明后面跟着的是域名而不是ip地址,由Socks5服务器进行dns解析
5、13前面指明了是域名,那么0x13(19字节)是域名字符长度
6、77 65 62 2E 73 6F 75 72 63 65 66 6F 72 67 65 2E 6E 65 74 就这19个是域名web.sourceforge.net的ascii。
7、00 16端口,即为22端口。
第二种
05 01 00 01 CA 6C 16 05 00 50
1、05固定
2、01说明tcp
3、00固定
4、01说明是ip地址
5、CA 6C 16 05就是202.108.22.5了,百度ip
6、00 50端口,即为80端口
看到了吗,tcp的可以本地解析出ip来,只让Socks5代理去连,也可以发过域名去让Socks5去用它的dns去解析ip再连接
这时代理服务器收到了上面的请求后,如果是域名的,先解析出ip来连接,如果直接是ip的就用一个tcp连接去连接那个ip和端口,如果和远程主机连接成功了,就向客户发送什么呢
05 00 00 01 C0 A8 00 08 16 CE共10个字节
无论上面两种哪一种都是这样
1、05 00 00 01固定的
2、后面8个字节可以全是00,也可以发送Socks5服务器连接远程主机用到的ip地址和端口,比如这里C0 A8 00 08,就是192.168.0.8,这是我Socks5服务器的ip地址,16 CE即5838端口,即是Socks5服务器用5838端口去连接百度的80端口。也可以05 00 00 01 00 00 00 00 00 00,只告知客户连接成功不告诉他细节,但是0不要省略。
后面就是在客户和远程主机之间转发转发啊的,是不是很容易啊,比http代理简单太多了。
然后说udp的,udp的要复杂不少。首先要说下原理,udp和tcp不一样,不是一个连接中一口气下来的,上面说了不管tcp还是udp上面的那个tcp协商部分都是一样的,而且如果是udp的话会占用Socks5代理一个tcp连接一个udp。
UDP专用部分:
第三种udp的
客户端如qq发送(仍在刚才的tcp中发送)
05 03 00 01 00 00 00 00 E5 F0
1、05固定
2、03说明是要代理udp
3、00固定
4、01固定,只能制定后面跟着的是ip地址
5、00 00 00 00这里可以由客户端如qq发送客户的ip,也可全是0,因为这个ip地址没用。
6、E5 F0最重要的一条,客户端比如qq,向Socks5代理说明它预备开放的udp端口,这里是58864。
那么Socks5怎么回答呢?如果不同意代理直接关闭连接就可以了不用反馈了。如果同意的话,Socks5要这么做,首先准备一个ip和一个udp端口,比如我用192.168.0.8这个ip上开放58865udp端口给客户转发用。然后返回
05 00 00 01 C0 A8 00 08 E5 F1
1、05 00 00 01固定
2、C0 A8 00 08预备开放udp端口开放给客户的ip,这里是192.168.0.8,如果多ip机器,那么返回下面开放udp端口绑定的那个ip。
3、E5 F1返回给客户说明预备开放哪个端口,这里是58865。
好了tcp协商部分完成了,注意这个tcp连接一定不要关闭,要一直开着,虽然再也不会发送和接受数据了,但是要一直开着,如果这个连接一关,那么客户就认为连接被断开了,因为这就是Socks5协议,所以说socsk5转发udp不但要占用一个udp还要占用一个tcp连接。麻烦吧。
上面那个tcp不要关,下面就是客户和Socks5的2个udp端口之间进行数据交换了,这里udp麻烦的一方面又体现出来了,它就是无连接的,它不像tcp那样因为tcp协议部分就保证了数据的可靠性,这么说吧比如tcp连接qq发送abcdef,这些数据太大了一次发送不完,那么就会分片,那么Socks5可能会收到ab第二次c第三次def这样的,虽然不知道能一次收多少,但是只要连起来还是abcdef的顺序,而且不会出现数据丢失而发送方不知道的情况。udp就不一样,可能第一次就接到了def,第二次才接到a,bc可能直接就丢了还不知道,所以要保证udp数据的完整,不能靠udp协议这一层了,得自己手动指定,那么在Socks5里就有一个udp分包的概念,就是在头几个字节指定这是1号包还是2号包,Socks5程序必须自己弄个排序,比如第一次接到标记为3号的包,那么先存起来等着1号2号来了把3号放后面再发,所以说是很麻烦的,而且rfc也说了应用程序尽量不要弄这种分包,而且rfc说了,Socks5程序可以选择拒绝这种分包方式接到后直接丢弃而不通知客户端,所以既然那么麻烦,咱也不用去实现这用不大上的功能,因为即使你这Socks5程序实现了,对于应用程序比如qq来说还是不可靠的,而使用udp的应用程序在它应用程序本身就有个完整性和排序的功能,比如丢包了,qq之间自己就知道了,qq之间自己会去想办法重发还是排序的什么的,所以我们就不用去管分包了,让应用程序自己去解决吧,我们只实现转发不分包的那种就行了。
既然只实现不分包的,那么格式就固定了
客户端qq的58864udp端口向Socks5的58865udp端口发送什么呢,仍然是ip+端口或者域名+端口方式
00 00 00 01 70 5F F0 3C 1F 40 +实体数据
比如这个,00 00 00 01开头,那么后面4个就是ip地址70 5F F0 3C即112.95.240.60,1F 40 即端口8000,后面的全都是实体数据了。那么Socks5服务器就用58865udp端口向qq的服务器112.95.240.60的8000端口发送后面的实体数据而不要发送前面那些封装内容,那么会受到qq服务器返回58865udp端口的数据,返回的都是实体数据,因为代理嘛,就像是Socks5那台机器在用qq一样,所以收到的数据没有前面的封装都是实体数据。那么Socks5就要返回给客户端,还不能直接返回,得包装一下
00 00 00 01 70 5F F0 3C 1F 40 +收到远程主机返回的数据
把这个返回给客户端的58864udp端口
是不是前面包装内容都是一样的啊,是一样的,因为客户端已经指明了ip,所以肯定是一样的。
还一种是这样域名的,qq的58864udp端口发送给Socks5的58865udp端口
00 00 00 03 12 67 72 6F 75 70 63 6C 69 65 6E 74 2E 71 71 2E 63 6F 6D 23 29+实体数据
00 00 00 03开头说明后面跟的是域名,紧跟着的12说明后面0x12(十进制18)字节就是域名,解出来就是groupclient.qq.com
后面23 29即端口9001。那么Socks5服务器就要先把groupclient.qq.com的ip给dns出来58.251.62.164(3A FB 3E A4 ),用58865up端口向58.251.62.164的9001udp发送后面的实体数据,返回来后和上面一样向客户qq的58864udp发送
00 00 00 01 3A FB 3E A4 23 29 +收到远程主机返回的数据,03变01了,直接就ip+端口了
大家注意到了没,客户和Socks5tcp协商后,Socks5开放的udp端口,既和客户开放的udp端口联系,也和需要连接的远程主机之间联系,都用一个端口所以有点乱,这样就得判断了,如果发现像这个端口如58864udp发送数据的ip和udp端口,是之前协商的那个,就说明是客户的数据,这时就要把客户要发送的远程主机的ip和端口记录下来,比如上例的58.251.62.164的9001udp端口,如果发现是从58.251.62.164的9001udp发送过来的数据,那么说明是远程主机发回的,那么需要转发给协商好的客户,还有一种情况,既不是客户也不在远程主机列表中的机器发过来的数据,就要丢弃,而且比如说客户发过来一条数据是要发送给远程A的a端口,那么发送出去接收到返回给客户,客户又继续发过来一条,这次要发给远程B的b端口,那么就要发出去接收返回给客户,那么这时远程主机就要有个列表了,现在有2条记录,只要接收到的udp在这2条中,就要转发给客户,如果客户又要发给C的c,那么列表就3条记录了,那么可能4条5条。
看出来了吧,Socks5代理udp比起tcp来是很麻烦很麻烦的,不但要占用一个tcp一直维持连接,而且还要手动搞这种列表,但是话说回来了,虽然麻烦,但是比起编写http代理去解析http还是要容易多了。
Socks5还有一种bind的tcp方式,说是ftp协议中有一种主动模式是一个tcp连上ftp服务器的21后,经过协商,服务器的某端口会反向主动连接客户端的某端口,很早以前好像见过,现在这种模式基本没用,ftp服务器和主机协商有什么用啊,现在的机器要么是在防火墙后,要么是在局域网中,ftp服务器反向连接怎么能连上客户呢是吧,所以现在的ftp几乎都用的是客户主动连接ftp服务器的被动模式,Socks5的bind就适用于那种老的主动模式,用处很小很小,所以咱不去考虑。
ie9只能用sock4,4a和5不行
火狐4可以用sock4, 4a不行,可以用sock5,但是是个半残,不支持用户名和密码验证,而且sock5中我上面说了可以发域名过去让sock5代理去dns解析,但是火狐4却非要在本地解析域名,只用sock5的ip模式,无法达到彻底隐藏的目的,话说如果你想上某些不和谐站,如果被人发现你老是在本地dns解析那些域名……是吧。rfc管这叫dns泄露。
超时了要如何做?
我觉得,无论4 4a 还是5,对于tcp的代理,如果发现无论远程还是客户只要5分钟内没有数据传输,就把远程和客户的这2条tcp连接断开就行了,对于5的udp也是,如果发现udp端口5分钟都没有客户的udp数据包发过来,就把这个udp端口关闭,把那个和客户维持的tcp断开。而不论4 4a 还是5,只要客户主动断开,那么就把为这个客户开的一切资源全都关闭掉。不用担心,一般程序都会定时发送维持性连接信息的,不会在那连着不收不发就那么耗着不管了的,所以5分钟都没数据,就可以认为已经断开了,就关闭就行。
这个问题很严重,如果不做好不一会就会把服务器的端口全部占满,亲身体会,其实早断开了,但就是不释放,好几天都显示ESTABLISHED,等到4294967295秒后才会自动关闭,所以这个问题要慎重,保守一点好。