socks5代理服务器协议的说明

socks5代理和socks4 socks4a比,多了一个验证功能和udp代理的功能。

socks5的tcp代理几乎和socks4 socks4a一样简单,但是udp却比较复杂一点,但是再复杂也没有http代理那么复杂。

首先说验证,不管是要代理tcp还是udp,开始验证都是要一个tcp连接的,而且验证过程一样,验证完了才分tcp和udp的实际代理过程,有好几种验证,别管了,其他的都用不到太小众化了,那些协议是什么都没听说过,也没处试验去,信我的,就记住3种就行

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单独部分:

先说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秒后才会自动关闭,所以这个问题要慎重,保守一点好。

具体代码可参照些此文


socks4,socks5代理服务器实现

======================================================================================

 最近,需要用到socks5协议,实现与代理相关的功能,所以,从网上查找资料,找到了RFC1928的中文版本,现把其记录下来,作为后用。


1、介绍

  

        防火墙的使用,有效的隔离了机构内部网络和外部网络,这种类型的Internet架构变得越来越流行了。这种防火墙系统大都充当着网络之间的应用层网关的角色,通常提供经过控制的TelnetFTPSMTP访问。为了推动全球信息的交流,更多的新的应用层协议的推出,这就有必要提供一个总的架构使这些协议能够更明显和更安全的穿过防火墙,也有必要在实际上为它们穿过防火墙提供一个更强的认证机制。这种需要源于客户机-服务器联系在不同组织网络之间的实现,而这种联系需要得到控制并有安全的认证。

        在这儿所描述的协议框架是为了让使用TCPUDP的客户/服务器应用程序更方便地使用网络防火墙所提供的服务所设计的。这个协议从概念上来讲是介于应用层和传输层之间的中介层,因而不提供如传递ICMP信息之类由网络层网关的所提供的服务。


2、现有的协议


         当前存在一个协议socks4,它为TelnetFTPHTTPWAISGOPHER等基于TCP协议的客户/服务器程序提供一个不安全的防火墙。而这个新协议扩展了socks4,以使其支持UDP框架规定的安全认证方案、地址解析方案中所规定的域名和IPV6。为了实现这个socks协议,通过需要重新编译或者重新链接基于TCP的客户端应用程序以使用socks库中相应的加密函数。


        注意:

        除非特别注明,所有出现在数据包格式图中的十进制数字均以字节表示相应域的长度。如果某域需要给定一个字节的值,用X'hh'来表示这个字节中的值。如果某域中用到单词'Variable',这表示该域的长度是可变的,且该长度定义在一个和这个域相关联(1-2个字节)的域中,或一个数据类型域中。


3、基于TCP协议的客户


        当一个基于TCP协议的客户端希望与一个只能通过防火墙可以到达的目标(这个由实现决定的)建立连接,它必须先建立一个与socks服务器上socks端口的TCP连接。通常这个TCP端口是1080。当连接建立后,客户端进入协议的握手过程:认证方式的选择,根据选中的方式进行认证,然后发送转发的请求。sockds服务器检查这个请求,根据结果,或建立合适的连接,或拒绝。


        除非特别注明,所有出现在数据包格式图中的十进制数字均以字节表示相应域的长度。如果某域需要给定一个字节的值,用X'hh'来表示这个字节中的值。如果某域中用到单词'Variable',这表示该域的长度是可变的,且该长度定义在一个和这个域相关联(1-2个字节)的域中,或一个数据类型中。


        客户端连到服务器后,然后就发送请求来协商版本和认证方法:


  +----+----------+----------+ 

  |VER | NMETHODS | METHODS  | 

  +----+----------+----------+ 

  | 1 |   1  | 1 to 255 | 

  +----+----------+----------+ 


        VER(版本)在这个协议版本中被设置为X'05'NMETHODS(方法选择)中包含在METHODS(方法)中出现的方法标识的数据(用字节表示)。


       服务器从METHODS给出的方法中选出一种,发送一个METHOD(方法)选择报文:

        +----+--------+ 


  |VER | METHOD | 

  +----+--------+ 

  | 1 |  1  | 

  +----+--------+ 

    

    如果所选择的METHOD的值是X'FF',则客户端所列出的方法是没有可以被接受的,客户机就必须关闭连接。


    当前被定义的METHOD的值有:

    -> X'00'    无验证需求


    -> X'01'    通用安全服务应用程序接口(GSSAPI)


    -> X'02'    用户名/密码(USERNAME/PASSWORD) 

  -> X'03'    至 X'7F' IANA 分配(IANA ASSIGNED) 

  -> X'80'    至 X'FE' 私人方法保留(RESERVED FOR PRIVATE METHODS) 

  -> X'FF'    无可接受方法(NO ACCEPTABLE METHODS) 


    

        其中,IANA是负责全球Internet上的IP地址进行编号分配的机构。


        于是客户端和服务器进入方法细节的子商议。方法选择子商议描述于独立的文档中。


        欲得到该协议新的METHOD支持的开发者可以和IANA联系以求得METHOD号。已分配号码的文档需要参考METHOD号码的当前列表和它们的通讯协议


       如果想顺利的执行则必须支持GSSAPI和支持用户名/密码(USERAE/PASSWORD)认证方法。


4、需求


         一旦方法选择子商议结束,客户机就发送请求细节。如果商议方法包括了完整性检查的目的或机密性封装,则请求必然被封在方法选择的封装中。 


    SOCKS请求如下表所示: 

  +----+-----+-------+------+----------+----------+ 

  |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | 

  +----+-----+-------+------+----------+----------+ 

  | 1 |  1 | X'00' |  1 | Variable |   2  | 

  +----+-----+-------+------+----------+----------+ 

    其中: 

   o VER protocol version:X'05' 

   o CMD 

  o CONNECT X'01' 

  o BIND X'02' 

  o UDP ASSOCIATE X'03' 

   o RSV RESERVED 

   o ATYP address type of following address 

  o IP V4 address: X'01' 

  o DOMAINNAME: X'03' 

  o IP V6 address: X'04' 

   o DST.ADDR desired destination address 

   o DST.PORT desired destination port in network octet order 


5、地址


    在地址域(DST.ADDR,BND.ADDR)中,ATYP域详细说明了包含在该域内部的地址类型: 


    o X'01' 

   该地址是IPv4地址,长4个八位组。 

    o X'03' 

   该地址包含一个完全的域名。第一个八位组包含了后面名称的八位组的数目,没有中止的空八位组。 

    o X'04' 

   该地址是IPv6地址,长16个八位组。


    注:我在应用该协议时,纠结了好久,当时选择X'03',填写相应字段时,到底该怎么填写呢?是写socks服务器的还是写请求的?现在想想,自己好无知啊。。如我们想发生HTTP请求:www.baidu.com,则DST.ADDR为: 13www.baidu.com0x000x50。其中,13是www.baidu.com的长度,然后接www.baidu.com,然后是两个字节的端口号,这里为80端口。


6、回应


    到SOCKS服务器的连接一经建立,客户机即发送SOCKS请求信息,并且完成认证商议。服务器评估请求,返回一个回应如下表所示: 


  +----+-----+-------+------+----------+----------+ 

  |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | 

  +----+-----+-------+------+----------+----------+ 

  | 1 | 1 | X'00' | 1  | Variable |   2  | 

  +----+-----+-------+------+----------+----------+ 

    其中: 

  o VER protocol version: X'05' 

  o REP Reply field: 

   o X'00' succeeded 

   o X'01' general SOCKS server failure 

   o X'02' connection not allowed by ruleset 

   o X'03' Network unreachable 

   o X'04' Host unreachable 

   o X'05' Connection refused 

  o X'06' TTL expired 

  o X'07' Command not supported 

   o X'08' Address type not supported 

   o X'09' to X'FF' unassigned 

  o RSV RESERVED 

  o ATYP address type of following address 

   o IP V4 address: X'01' 

   o DOMAINNAME: X'03' 

   o IP V6 address: X'04' 

    o BND.ADDR server bound address 

    o BND.PORT server bound port in network octet order 


    标志RESERVED(RSV)的地方必须设置为X'00'。

    

    如果被选中的方法包括有认证目的封装,完整性和/或机密性的检查,则回应就被封装在方法选择的封装套中。 


    CONNECT 

  在CONNECT的回应中,BND.PORT包括了服务器分配的连接到目标主机的端口号,同时BND.ADDR包含了关联的IP地址。此处所提供的BND.ADDR通常情况不同于客户机连接到SOCKS服务器所用的IP地址,因为这些服务器提供的经常都是多址的(muti-homed)。都期望SOCKS主机能使用DST.ADDR和DST.PORT,连接请求评估中的客户端源地址和端口。 

    BIND 

  BIND请求被用在那些需要客户机接受到服务器连接的协议中。FTP就是一个众所周知的例子,它通过使用命令和状态报告建立最基本的客户机-服务器连接,按照需要使用服务器-客户端连接来传输数据。(例如:ls,get,put) 都期望在使用应用协议的客户端在使用CONNECT建立首次连接之后仅仅使用BIND请求建立第二次连接。都期望SOCKS主机在评估BIND请求时能够使用ST.ADDR和DST.PORT。 

  有两次应答都是在BIND操作期间从SOCKS服务器发送到客户端的。第一次是发送在服务器创建和绑定一个新的socket之后。BIND.PORT域包含了SOCKS主机分配和侦听一个接入连接的端口号。BND.ADDR域包含了关联的IP地址。  

  客户端具有代表性的是使用这些信息来通报应用程序连接到指定地址的服务器。第二次应答只是发生在预期的接入连接成功或者失败之后。在第二次应答中,BND.PORT和BND.ADDR域包含了欲连接主机的地址和端口号。 

    UDP ASSOCIATE(不太懂) 

  UDP连接请求用来建立一个在UDP延迟过程中操作UDP数据报的连接。DST.ADDR和DST.PORT域包含了客户机期望在这个连接上用来发送UDP数据报的地址和端口。服务器可以利用该信息来限制至这个连接的访问。如果客户端在UDP连接时不持有信息,则客户端必须使用一个全零的端口号和地址。 

  当一个含有UDP连接请求到达的TCP连接中断时,UDP连接中断。 

  在UDP连接请求的回应中,BND.PORT和BND.ADDR域指明了客户端需要被发送UDP请求消息的端口号/地址。 

    回应过程 

  当一个回应(REP值非X'00')指明失败时,SOCKS主机必须在发送后马上中断该TCP连接。该过程时间必须为在侦测到引起失败的原因后不超过10秒。 

  如果回应代码(REP值为X'00')时,则标志成功,请求或是BIND或是CONNECT,客户机现在就可以传送数据了。如果所选择的认证方法支持完整性、认证机制和/或机密性的封装,则数据被方法选择封装包来进行封装。类似,当数据从客户机到达SOCKS主机时,主机必须使用恰当的认证方法来封装数据。 


7.基于UDP客户机的程序 

  一个基于UDP的客户端必须使用在BND.PORT中指出的UDP端口来发送数据报到UDP延迟服务器,而该过程是作为对UDP连接请求的回应而进行的。如果所选择的认证方法提供认证机制、完整性、和/或机密性,则数据报必须使用恰当的封装套给予封装。每一个UDP数据报携带一个UDP请求的报头(header): 

  +----+------+------+----------+----------+----------+ 

  |RSV | FRAG | ATYP | DST.ADDR | DST.PORT |  DATA | 

  +----+------+------+----------+----------+----------+ 

  | 2 |  1 |  1 | Variable |  2   | Variable | 

  +----+------+------+----------+----------+----------+ 

    UDP请求报头是: 

    o RSV Reserved X'0000' 

    o FRAG Current fragment number 

    o ATYP address type of following addresses: 

o IP V4 address: X'01' 

o DOMAINNAME: X'03' 

o IP V6 address: X'04' 

    o DST.ADDR desired destination address 

    o DST.PORT desired destination port 

    o DATA user data 

  当一个UDP延迟服务器决定延迟一个UDP数据报时,它会按兵不动,对客户机无任何通报。类似的,它会将它不能或不打算延迟的数据报Drop?掉。当一个UDP延迟服务器接收到一个来自远程主机的延迟数据报,它必须使用上面的UDP请求报头来封装该数据报,和任何认证方法选择的封装。 

  一个UDP延迟服务器必须从SOCKS服务器获得所期望的客户机的IP地址,而该客户机要发送数据报到BND.PORT--在至UDP连接的回应中已经给出。UDP延迟服务器还必须drop掉除了特定连接中的一条记录之外的其它的所有源IP地址。 

   FRAG域指出了数据报是否为大量的数据片(flagments)中的一片。如果标明了,高序(high-order)位说明是序列的结束段,而值为X'00'则说明该数据报是独立的。值介于1-127之间片断位于数据片序列中间。每一个接收端都有一个和这些数据片相关的重组队列表(REASSEMBLY QUEUE)和一个重组时间表(REASSEMBLY TIMER)。重组队列必须被再次初始化并且相关联的数据片必须被丢掉,而无论该重组时间表是否过期,或者一个新的携带FRAG域的数据报到达,并且FRAG域的值要小于正在进行的数据片序列中的FRAG域的最大值。且重组时间表必须不少于5秒。无论如何最好避免应用程序直接与数据片接触(?)。 

  数据片的执行是可选的,一个不支持数据片的执行必须drop掉任何除了FRAG域值为X'00'了数据报。 

  一个利用SOCKS的UDP程序接口必须预设有效的缓冲区来装载数据报,并且系统提供的实际缓冲区的空间要比数据报大: 

    o if ATYP is X'01' - 10+method_dependent octets smaller 

    o if ATYP is X'03' - 262+method_dependent octets smaller 

    o if ATYP is X'04' - 20+method_dependent octets smaller 


8、安全性考虑


    这篇文档描述了一个用来透过IP网络防火墙的应用层协议。这种传输的安全性在很大程度上依赖于特定实现所拥有以及在SOCKS客户与SOCKS服务器之间经协商所选定的特殊的认证和封装方式。系统管理员需要对用户认证方式的选择进行仔细考虑。 


9、引用


        [1] Koblas, D., "SOCKS", Proceedings: 1992 Usenix Security Symposium.

     Author's Address

     Marcus Leech

     Bell-Northern Research Ltd

     P.O. Box 3511, Stn. C,

     Ottawa, ON

     CANADA K1Y 4H7

     Phone: (613) 763-9145

     EMail: [email protected]


10、译者

      

译者:RadeonRadeon [email protected]

TCP代理测试:

// socks5.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include
#include  
#pragma comment(lib, "WS2_32.lib")  

int main(int argc, char* argv[])  
{  
	WSADATA wsaData;  
	WORD sockVersion = MAKEWORD(2,0);//指定版本号  
	::WSAStartup(sockVersion, &wsaData);//载入winsock的dll  

	//建立socket,基于tcp  
	SOCKET s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);  
	if(s == INVALID_SOCKET)  
	{
		printf("error");  
		::WSACleanup(); //释放资源  
		return 0;  
	}  

	sockaddr_in servAddr;  
	servAddr.sin_family = AF_INET;  
	servAddr.sin_port = htons(1080);//端口号  
	servAddr.sin_addr.S_un.S_addr = inet_addr("192.168.50.103");//IP

	//连接  
	if(::connect(s, (sockaddr*)&servAddr, sizeof(servAddr)) == -1)  
	{  
		printf("error");  
		::WSACleanup(); //释放资源  
		return 0;  
	}

	//发送链接请求
	char request[10] = {0x05,0x01,0x02};
	int ret = send(s,request,3,0);
	char buff[156];//缓冲区  
	int nRecv = ::recv(s, buff, 156, 0);//接收数据  
	if(nRecv > 0)  
	{  
		buff[nRecv] = '\0';  
	}

	//发送账户密码
	char username[30] = "liujiayu";
	char pwd[30] = "liujiayu";
	char validatebuf[100]={0};
	validatebuf[0] = 0x01;
	validatebuf[1] = strlen(username);
	memcpy(validatebuf+2,username,strlen(username));
	validatebuf[2+strlen(username)] = strlen(pwd);
	memcpy(validatebuf+3+strlen(username),pwd,strlen(pwd));
	ret = send(s,validatebuf,3+strlen(username)+strlen(pwd),0);
	nRecv = ::recv(s, buff, 156, 0);//接收数据  

	//发送远程目标连接

	unsigned long l = inet_addr("124.115.16.165");

	char dest[11] = {0x05,0x01,0x00,0x01,0x7c,0x73,0x10,0xa5,0x00,0x50};
	ret = send(s,dest,10,0);
	nRecv = ::recv(s, buff, 156, 0);//接收数据


	char copntent[11] = "get";
	ret = send(s,copntent,4,0);
	nRecv = ::recv(s, buff, 156, 0);//接收数据


	::closesocket(s); //关闭套接字  
	::WSACleanup(); //释放资源  



	return 0;  
} 

UDP代理测试:

// tt2.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"  
#include  
#include    
#pragma comment(lib, "WS2_32.lib")    

int main(int argc, char* argv[])    
{    
	WSADATA wsaData;    
	WORD sockVersion = MAKEWORD(2,0);//指定版本号    
	::WSAStartup(sockVersion, &wsaData);//载入winsock的dll    

	//建立socket,基于tcp    
	SOCKET s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);    
	if(s == INVALID_SOCKET)    
	{  
		printf("error");    
		::WSACleanup(); //释放资源    
		return 0;    
	}    

	sockaddr_in servAddr;    
	servAddr.sin_family = AF_INET;    
	servAddr.sin_port = htons(1080);//端口号    
	servAddr.sin_addr.S_un.S_addr = inet_addr("192.168.50.197");//IP  

	//连接    
	if(::connect(s, (sockaddr*)&servAddr, sizeof(servAddr)) == -1)    
	{    
		printf("error");    
		::WSACleanup(); //释放资源    
		return 0;    
	}  

	//发送链接请求  
	char request[10] = {0x05,0x01,0x02};  
	int ret = send(s,request,3,0);  
	char buff[156];//缓冲区    
	int nRecv = ::recv(s, buff, 156, 0);//接收数据    
	if(nRecv > 0)    
	{    
		buff[nRecv] = '\0';    
	}  

	//发送账户密码  
	char username[30] = "liujiayu";  
	char pwd[30] = "liujiayu";  
	char validatebuf[100]={0};  
	validatebuf[0] = 0x01;  
	validatebuf[1] = strlen(username);  
	memcpy(validatebuf+2,username,strlen(username));  
	validatebuf[2+strlen(username)] = strlen(pwd);  
	memcpy(validatebuf+3+strlen(username),pwd,strlen(pwd));  
	ret = send(s,validatebuf,3+strlen(username)+strlen(pwd),0);  
	nRecv = ::recv(s, buff, 156, 0);//接收数据    

	//发送远程目标连接  

	unsigned long l = inet_addr("192.168.50.197");  

	char dest[10] = {0x05,0x03,0x00,0x01,0xc0,0xa8,0x32,0xc5,0x00,0x5a};  
	ret = send(s,dest,10,0);  
	nRecv = ::recv(s, buff, 156, 0);//接收数据

	unsigned short udpserverport = (buff[8] << 8)  + buff[9] ;

	SOCKET sockClient=socket(AF_INET,SOCK_DGRAM,0);
	SOCKADDR_IN addrSrv;
	addrSrv.sin_addr.S_un.S_addr=inet_addr("192.168.50.197");
	addrSrv.sin_family=AF_INET;
	addrSrv.sin_port=htons(udpserverport);
	char sendtobuf[30] = {0x00,0x00,0x00,0x01,0xc0,0xa8,0x32,0xc5,0x04,0x38,0x31,0x11,0x11,0x11,0x11};
	int to = sendto(sockClient,sendtobuf,16,0,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));


	::closesocket(s); //关闭套接字    
	::WSACleanup(); //释放资源    



	return 0;    
}  


你可能感兴趣的:(网络编程深入研究,网络编程)