C# Socks5
最近在做一socks5代理,也整理了一些资料
而SOCKS5的官方文档:
http://www.faqs.org/rfcs/rfc1928.html
下面这一篇即是他的中文版吧,只要弄懂了,依着样子写个客户端是没多大问题的
原文出处:http://www.china-pub.com/computers/eMook/emooknew/rfctxt/RFC1928.txt
组织:中国互动出版网(http://www.china-pub.com/)
RFC文档中文翻译计划(http://www.china-pub.com/compters/emook/aboutemook.htm)
E-mail:ouyang@china-pub.com
译者:Radeon(Radeon bise@cmmail.com)
译文发布时间:2001-6-18
版权:本中文翻译文档版权归中国互动出版网所有。可以用于非商业用途自由转载,但必须保留本文档的翻译及版权信息。
Network Working Group M. Leech
Request for Comments: 1928 Bell-Northern Research Ltd
Category: Standard Track M. Ganis
International Business Machines
Y. Lee
NEC Systems Laboratory
R. Kuris
Unify Corporation
D. Koblas
Independent Consultant
L. Jones
Hewlett-Packard Company
March 1996
SOCKS V5
(RFC1928 SOCKS Protocol Version 5)
本备忘录状态:
本文档讲述了一种Internet社区的Internet标准跟踪协议,它需要进一步进行讨论和建议以得到改进。请参考最新版的“Internet正式协议标准” (STD1)来获得本协议的标准化程度和状态。本备忘录的发布不受任何限制。
知识背景
这个备忘录描述了从同一协议的前一版本(版本4[1])发展而来的一个协议。这个新的协议起源于当前的一些讨论和原型的实现(active discussions and prototype implementations)。关键的贡献人有:Marcus Leech: Bell-Northern Research, David Koblas: Independent Consultant, Ying-Da Lee: NEC Systems Laboratory, LaMont Jones: Hewlett-Packard Company, Ron Kuris: Unify Corporation, Matt Ganis: International Business Machines。
目录
1.介绍
2.现有的协议
3.基于TCP协议的客户
4.请求
5.地址
6.应答
7.基于UDP协议的客户
8. 安全性考虑
9. 参考书目
1.介绍
利用网络防火墙可以将组织内部的网络结构从外部网络如INTERNET中有效地隔离,这种方法在许多网络系统中正变得流行起来。这种防火墙系统通常以应用 层网关的形式工作在两个网络之间,提供TELNET、FTP、SMTP等的接入。随着越来越多的使全球信息查找更容易的复杂的应用层协议的出现,有必要提 供一个通用框架来使这些协议安全透明地穿过防火墙。而且在实际应用中还需要一种安全的认证方式用以穿越防火墙。这个要求起源于两个组织的网络中客户/服务 器关系的出现,这个关系需要得到控制并要求有安全的认证。
在这儿所描述的协议框架是为了让使用TCP和UDP的客户/服务器应用程序更方便安全地使用网络防火墙所提供的服务所设计的。这个协议从概念上来讲是介于 应用层和传输层之间的“中介层(shim-layer)”,因而不提供如传递ICMP信息之类由网络层网关的所提供的服务。
2.现有的协议
当前存在一个协议SOCKS 4,它为TELNET、FTP、HTTP、WAIS和GOPHER等基于TCP协议的客户/服务器程序提供了一个不安全的防火墙。而这个新的协议扩展了SOCKS V4,以使其支持UDP、框架规定的安全认证方案、地址解析方案(addressing scheme)中所规定的域名和IPV6。为了实现这个SOCKS协议,通常需要重新编译或者重新链接基于TCP的客户端应用程序以使用SOCKS库中相应的加密函数。
注意:
除非特别注明,所有出现在数据包格式图中的十进制数字均以字节表示相应域的长度。如果某域需要给定一个字节的值,用X’hh’来表示这个字节中的值。如果某域中用到单词’Variable’,这表示该域的长度是可变的,且该长度定义在一个和这个域相关联(1 – 2个字节)的域中,或一个数据类型域中。
3.基于TCP协议的客户
当一个基于TCP协议的客户端希望与一个只能通过防火墙可以到达的目标(这是由实现所决定的)建立连接,它必须先建立一个与SOCKS服务器上SOCKS 端口的TCP连接。通常这个TCP端口是1080。当连接建立后,客户端进入协议的“握手(negotiation)”过程:认证方式的选择,根据选中的 方式进行认证,然后发送转发的要求。SOCKS服务器检查这个要求,根据结果,或建立合适的连接,或拒绝。
除非特别注明,所有出现在数据包格式图中的十进制数字均以字节表示相应域的长度。如果某域需要给定一个字节的值,用X’hh’来表示这个字节中的值。如果某域中用到单词’Variable’,这表示该域的长度是可变的,且该长度定义在一个和这个域相关联(1 – 2个字节)的域中,或一个数据类型域中。
客户端连到服务器后,然后就发送请求来协商版本和认证方法:
VER |
NMETHODS |
METHODS |
1 |
1 |
1 to 255 |
这个版本的SOCKS协议中,VER字段被设置成X'05'。NMETHODS字段包含了在METHODS字段中出现的方法标示的数目(以字节为单位)。
以上红色部分在http://www.cnblogs.com/kingthy/archive/2008/10/22/1317132.html描述得很清楚,他还提供了一服务端,谢谢
当客户端与Socks5代理服务器连接上并进行握手时,客户端将会发送以下格式的握手报文:
版本号(1字节) | 认证方法数(1字节) | 认证方法序列(1-255个字节长度)
比如报文(假如为V5版本):
0x05 0x01 0x00 则表示客户端只支持一种(0x1)认证方法0x00 (无验证需求)
0x05 0x01 0x02 则表示客户端只支持一种(0x01)认证方法0x02(用户名/密码 验证)
0x05 0x02 0x00 0x02 则表示客户端支持两种(0x02)认证方法“0x00与0x02”
代码:
IPEndPoint proxyEndPoint = new IPEndPoint(proxyIP, proxyPort);
// open a TCP connection to SOCKS server...
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
s.Connect(proxyEndPoint);
nIndex = 0;
request[nIndex++] = 0x05; // Version 5.
request[nIndex++] = 0x02; // 2 Authentication methods are in packet...
request[nIndex++] = 0x00; // NO AUTHENTICATION REQUIRED
request[nIndex++] = 0x02; // USERNAME/PASSWORD
// Send the authentication negotiation request...
s.Send(request, nIndex, SocketFlags.None);
服务器从这些给定的方法中选择一个并发送一个方法选中的消息回客户端:
VER |
METHOD |
1 |
1 |
如果选中的消息是X’FF’,这表示客户端所列出的方法列表中没有一个方法被选中,客户端必须关闭连接。
当前定义的方法有:
· X’00’ 不需要认证
· X’01’ GSSAPI
· X’02’ 用户名/密码
· X’03’ -- X’7F’ 由IANA分配
· X’80’ -- X’FE’ 为私人方法所保留的
· X’FF’ 没有可以接受的方法
然后客户和服务器进入由选定认证方法所决定的子协商过程(sub-negotiation)。各种不同的方法的子协商过程的描述请参考各自的备忘录。
开发者如果要为自己的方法得到一个方法号,可以联系IANA。可以参考关于已经被分配号码的文档以得到当前所有方法的列表和相应的协议。
符合本文档的SOCKS V5实现必须支持GSSAPI,并且在将来支持用户名/密码认证方式。
int nGot = s.Receive(response, 2, SocketFlags.None);
if (nGot != 2)
throw new ConnectionException("Bad response received from proxy server.");
if (response[1] == 0xFF)
{ // No authentication method was accepted close the socket.
s.Close();
throw new ConnectionException("None of the authentication method was accepted by proxy server.");
}
在KINGTHY里描述着发送用户名密码的报文
“在这里,我们要详解了解的则是“0x02 用户名/密码”验证的过程。
当客户端发送带有0x02认证方法的报文(如:“0x05 0x01 0x02”)到服务端时,根据报文,服务端得知客户端支持用户名/密码认证(0x02),因此如果服务端需要验证,则发送“0x05 0x02”应答,这样客户端将会进入“用户名/密码”验证过程。
“0x02 用户名/密码”验证协议的报文格式是:
0x01 | 用户名长度(1字节)| 用户名(长度根据用户名长度域指定) | 口令长度(1字节) | 口令(长度由口令长度域指定)
所以报文的长度是根据用户名与密码的长度而定,比如以下报文:
0x01 0x02 0x41 0x42 0x02 0x43 0x43
则表示发送用户名为“AB”密码为“CC”的验证报文。
服务端接收到用户名/密码验证报文后进行相应处理并返回以下格式的应答报文:
0x01 | 验证结果标志
如果验证通过则“验证结果标志”的值为“0x00”,否则其它值都表示验证失败!不允许再进行下一步的操作。“
if (response[1]==0x02)
{//Username/Password Authentication protocol
nIndex = 0;
request[nIndex++] = 0x05; // Version 5.
// add user name
request[nIndex++] = (byte)userName.Length;
rawBytes = Encoding.Default.GetBytes(userName);
rawBytes.CopyTo(request, nIndex);
nIndex += (ushort)rawBytes.Length;
// add password
request[nIndex++] = (byte)password.Length;
rawBytes = Encoding.Default.GetBytes(password);
rawBytes.CopyTo(request, nIndex);
nIndex += (ushort)rawBytes.Length;
// Send the Username/Password request
s.Send(request, nIndex, SocketFlags.None);
4.请求
一旦子协商过程结束后,客户端就发送详细的请求信息。如果协商的方法中有以完整性检查和/或安全性为目的的封装,这些请求必须按照该方法所定义的方式进行封装。
SOCKS请求的格式如下:
VER |
CMD |
RSV |
ATYP |
DST.ADDR |
DST.PROT |
1 |
1 |
X’00’ |
1 |
Variable |
2 |
其中
· VER 协议版本: X’05’
· CMD
· CONNECT:X’01’
· BIND:X’02’
· UDP ASSOCIATE:X’03’
· RSV 保留
· ATYP 后面的地址类型
· IPV4:X’01’
· 域名:X’03’
· IPV6:X’04’'
· DST.ADDR 目的地址
· DST.PORT 以网络字节顺序出现的端口号
SOCKS服务器会根据源地址和目的地址来分析请求,然后根据请求类型返回一个或多个应答。
5.地址
ATYP字段中描述了地址字段(DST.ADDR,BND.ADDR)所包含的地址类型:
· X'01'
基于IPV4的IP地址,4个字节长
· X'03'
基于域名的地址,地址字段中的第一字节是以字节为单位的该域名的长度,没有结尾的NUL字节。
· X'04'
基于IPV6的IP地址,16个字节长
代码:
// Send connect request now...
nIndex = 0;
request[nIndex++] = 0x05; // version 5.
request[nIndex++] = 0x01; // command = connect.
request[nIndex++] = 0x00; // Reserve = must be 0x00
if (destIP != null)
{// Destination adress in an IP.
switch (destIP.AddressFamily)
{
case AddressFamily.InterNetwork:
// Address is IPV4 format
request[nIndex++] = 0x01;
rawBytes = destIP.GetAddressBytes();
rawBytes.CopyTo(request, nIndex);
nIndex += (ushort)rawBytes.Length;
break;
case AddressFamily.InterNetworkV6:
// Address is IPV6 format
request[nIndex++] = 0x04;
rawBytes = destIP.GetAddressBytes();
rawBytes.CopyTo(request, nIndex);
nIndex += (ushort)rawBytes.Length;
break;
}
}
else
{// Dest. address is domain name.
request[nIndex++] = 0x03; // Address is full-qualified domain name.
request[nIndex++] = Convert.ToByte(destAddress.Length); // length of address.
rawBytes = Encoding.Default.GetBytes(destAddress);
rawBytes.CopyTo(request, nIndex);
nIndex += (ushort)rawBytes.Length;
}
// using big-edian byte order
byte[] portBytes = BitConverter.GetBytes(destPort);
for (int i = portBytes.Length - 1; i >= 0; i--)
request[nIndex++] = portBytes[i];
// send connect request.
s.Send(request, nIndex, SocketFlags.None);
即如果此时应答回来的是00,则成功,此时的SOCKET就可以拿来用了
6.应答
一旦建立了一个到SOCKS服务器的连接,并且完成了认证方式的协商过程,客户机将会发送一个SOCKS请求信息给服务器。服务器将会根据请求,以如下格式返回:
VER |
REP |
RSV |
ATYP |
BND.ADDR |
BND.PORT |
1 |
1 |
X’00’ |
1 |
Variable |
2 |
其中:
· VER 协议版本: X’05’
· REP 应答字段:
· X’00’ 成功
· X’01’ 普通的SOCKS服务器请求失败
· X’02’ 现有的规则不允许的连接
· X’03’ 网络不可达
· X’04’ 主机不可达
· X’05’ 连接被拒
· X’06’ TTL超时
· X’07’ 不支持的命令
· X’08’ 不支持的地址类型
· X’09’ – X’FF’ 未定义
· RSV 保留
· ATYP 后面的地址类型
· IPV4:X’01’
· 域名:X’03’
· IPV6:X’04’
· BND.ADDR 服务器绑定的地址
· BND.PORT 以网络字节顺序表示的服务器绑定的段口
标识为RSV的字段必须设为X’00’。
如果选中的方法中有以完整性检查和/或安全性为目的的封装,这些应答必须按照该方法所定义的方式进行封装。
CONNECT
在对一个CONNECT命令的应答中,BND.PORT包含了服务器分配的用来连到目标机的端口号,BND.ADDR则是相应的IP地址。由于SOCKS服务器通常有多个IP,应答中的BND.ADDR常和客户端连到SOCKS服务器的那个IP不同。
SOCKS服务器可以利用DST.ADDR和DST.PORT,以及客户端源地址和端口来对一个CONNECT请求进行分析。
BIND
BIND请求通常被用在那些要求客户端接受来自服务器的连接的协议上。FTP是一个典型的例子。它建立一个从客户端到服务器端的连接来执行命令以及接收状态的报告,而使用另一个从服务器到客户端的连接来接收传输数据的要求(如LS,GET,PUT)。
建议只有在一个应用协议的客户端在使用CONNECT命令建立主连接后才可以使用BIND命令建立第二个连接。建议SOCKS服务器使用DST.ADDR和DST.PORT来评价BIND请求。
在一个BIND请求的操作过程中,SOCKS服务器要发送两个应答给客户端。当服务器建立并绑定一个新的套接口时发送第一个应答。BND.PORT字段包 含SOCKS服务器用来监听进入的连接的端口号,BAND.ADDR字段包含了对应的IP地址。客户端通常使用这些信息来告诉(通过主连接或控制连接)应 用服务器连接的汇接点。第二个应答仅发生在所期望到来的连接成功或失败之后。在第二个应答中,BND.PORT和BND.ADDR字段包含了连上来的主机 的IP地址和端口号。
UDP ASSOCIATE
UDP ASSOCIATE请求通常是要求建立一个UDP转发进程来控制到来的UDP数据报。DST.ADDR和DST.PORT 字段包含客户端所希望的用来发送UDP数据报的IP地址和端口号。服务器可以使用这个信息来限制进入的连接。如果客户端在发送这个请求时没有地址和端口信 息,客户端必须用全0来填充。
当与UDP相应的TCP连接中断时,该UDP连接也必须中断。
应答UDP ASSOCIATE请求时,BND.PORT 和BND.ADDR字段指明了客户发送UDP消息至服务器的端口和地址。
应答处理
当一个应答(REP值不等于00)指明出错时,SOCKS服务器必须在发送完应答消息后一小段时间内终止TCP连接。这段时间应该在发现错误后少于10秒。
如果一个应答(REP值等于00)指明成功,并且请求是一个BIND或CONNECT时,客户端就可以开始发送数据了。如果协商的认证方法中有以完整性、 认证和/或安全性为目的的封装,这些请求必须按照该方法所定义的方式进行封装。类似的,当以客户机为目的地的数据到达SOCKS服务器时,SOCKS服务 器必须用正在使用的方法对这些数据进行封装。
7.基于UDP协议的客户
在UDP ASSOCIATE应答中由BND.PORT指明了服务器所使用的UDP端口,一个基于UDP协议的客户必须发送数据报至UDP转发服务器的该端口上。如 果协商的认证方法中有以完整性、认证和/或安全性为目的的封装,这些数据报必须按照该方法所定义的方式进行封装。每个UDP数据报都有一个UDP请求头在 其首部:
RSV |
FRAG |
ATYP |
DST.ADDR |
DST.PORT |
DATA |
2 |
1 |
1 |
Variable |
2 |
Variable |
在UDP请求头中的字段是:
· RSV 保留 X’0000’
· FRAG 当前的分段号
· ATYP 后面的地址类型
· IPV4:X’01’
· 域名:X’03’
· IPV6:X’04’
· DST.ADDR 目的地址
· DST.PORT 以网络字节顺序出现的端口号
· DATA 用户数据
当一个UDP转发服务器转发一个UDP数据报时,不会发送任何通知给客户端;同样,它也将丢弃任何它不能发至远端主机的数据报。当UDP转发服务器从远端服务器收到一个应答的数据报时,必须加上上述UDP请求头,并对数据报进行封装。
UDP转发服务器必须从SOCKS服务器得到期望的客户端IP地址,并将数据报发送到UDP ASSOCIATE应答中给定的端口号。如果数据报从任何IP地址到来,而该IP地址与该特定连接中指定的IP地址不同,那么该数据报会被丢弃。
FRAG字段指明数据报是否是一些分片中的一片。如果SOCKS服务器要实现这个功能,X’00’指明数据报是独立的;其他则越大越是数据报的尾端。介于 1到127之间的值说明了该分片在分片序列里的位置。每个接收者都为这些分片提供一个重组队列和一个重组的计时器。这个重组队列必须在重组计时器超时后重 新初始化,并丢弃相应的数据报。或者当一个新到达的数据报有一个比当前在处理的数据报序列中最大的FRAG值要小时,也必须重新初始化从组队列。重组计时 器必须小于5秒。只要有可能,应用程序最好不要使用分片。
分片的实现是可选的;如果某实现不支持分片,所有FRAG字段不为0的数据报都必须被丢弃。
一个SOCKS的UDP编程界面(The programming interface for a SOCKS-aware UDP)必须报告当前可用UDP数据报缓存空间小于操作系统提供的实际空间。
· 如果 ATYP是 X’01’ - 10+method_dependent octets smaller
· 如果 ATYP是X’03’ - 262+method_dependent octets smaller
· 如果 ATYP是X’04’ - 20+method_dependent octets smaller
8. 安全性考虑
这篇文档描述了一个用来透过IP网络防火墙的应用层协议。这种传输的安全性在很大程度上依赖于特定实现所拥有以及在SOCKS客户与SOCKS服务器之间经协商所选定的特殊的认证和封装方式。
系统管理员需要对用户认证方式的选择进行仔细考虑。
9. 参考书目
[1] Koblas, D., "SOCKS", Proceedings: 1992 Usenix Security Symposium.
作者地址
Marcus Leech
Bell-Northern Research Ltd
P.O. Box 3511, Station C
Ottawa, ON
CANADA K1Y 4H7
Phone: (613) 763 - 9145
EMail: mleech@bnr.ca
SOCKET扫盲篇:
如果您的机器具有一个合法的 Internet IP 地址, 或者您利用自己机器上的调制解调器拨号上网, 可以自由和 Internet 上任何主机沟通, 那么您通常不必关心 SOCKS5 协议。
SOCKS5 协议对于处在内部网络中的机器, 需要透过网络中某些可以联通外部 Internet 的机器访问外部时,有用。
SOCKS5 是一个代理协议,它在使用 TCP/IP协议通讯的前端机器和服务器机器之间扮演一个中介角色,使得内部网中的前端机器变得能够访问Internet网中的服务器,或者使通讯更加安全。
SOCKS5 服务器通过将前端发来的请求转发给真正的目标服务器, 模拟了一个前端的行为。在这里,前端和SOCKS5之间也是通过TCP/IP协议进行通讯,前端将原本要发送给真正服务器的请求发送给SOCKS5服务 器,然后SOCKS5服务器将请求转发给真正的服务器。SOCKS5服务器在将通讯请求发送给真正服务器的过程中,对于请求数据包本身不加任何改变。 SOCKS5服务器接收到真正服务器的响应后,也原样转发给前端。
因此,SOCKS5 协议是一种代理协议,对于各种基于 TCP/IP的应用层协议都能够适应,几乎是万能的。它虽然不能理解自己转发的数据的内部结构,但是它能够忠实地转发通讯包,完成协议本来要完成的功能。
与SOCKS5协议不同,HTTP代理是通过HTTP协议进行的,HTTP代理服务器软件了解通讯包的内部结构,在转发过程中还要对通讯进行某种程序的修改和转换。和HTTP代理协议不同,SOCKS5实际上是一个传输层的代理协议。
我们可以想象,如果每个具体的应用层协议都要设计对应的代理协议表达办法,一个特定的代理服务器无论如何也支持不过来那么多新出现的协议。因此,可以说SOCKS5的出现缓解了各种具体协议需要专门设计代理协议的困难局面。
不过,并不是凡是使用基于TCP/IP协议的应用协议的软件,都可以无条件地透过SOCKS5服务器进行通讯,还要求前端软件本身具有SOCKS5的接口,才能利用SOCKS5代理服务器。
一个支持SOCKS5协议的前端,通常具有两种运行状态:
1)直接通讯状态,不使用SOCKS5接口。这时的通讯是针对最终服务器进行的。
2)SOCKS5 状态。 使用 SOCKS5 接口将本来要发送给最终服务器的请求发送给 SOCKS5 服务器。在前端和 SOCKS5 服务器进行初始化会话的时候,前端告诉了 SOCKS5 服务器关于最终服务器的 IP 地址和端口信息,所以 SOCKS5服务器能够忠实按照前端的要求启动和最终服务器的通讯过程。
下面摘自一网友总结,备注下
http://blog.chinaunix.net/u/355/showart.php?id=76121
socks5连接建立的时候首先由客户端发出如下格式数据给服务端:
+----+----------+----------+
|VER | NMETHODS | METHODS |
+----+----------+----------+
| 1 | 1 | 1 to 255 |
+----+----------+----------+
在SOCKS5中VER字节总是0x05代表socks5,NMETHODS存放客户端可以接受的认证方法数量n,后面的n个字节就是各个方法对应的编号了.
收到客户端发出的请求后,服务端做出回应.
+----+--------+
|VER | METHOD |
+----+--------+
| 1 | 1 |
+----+--------+
其中验证方法对应的编号如下:
o X'00' NO AUTHENTICATION REQUIRED
o X'01' GSSAPI
o X'02' USERNAME/PASSWORD
o X'03' to X'7F' IANA ASSIGNED
o X'80' to X'FE' RESERVED FOR PRIVATE METHODS
o X'FF' NO ACCEPTABLE METHODS
客户端接受到如此回应后就可以开始与服务端进行验证了.在此0x02号代表的用户名密码验证方式在RFC1929文档中有介绍.我先不管验证.先实
现匿名socks5代理.以后再考虑添加验证功能.
验证完毕后,客户端就可以开始提出要求了.到底要socks5代理为它做什么.
请求数据包的格式如下:
+----+-----+-------+------+----------+----------+
|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
这里的目标地址可以有三种格式(IPV4 IP,域名,IPV6 IP)
其中IPV4,IPV6地址固定长度分别为4字节,16字节.
域名以pascal字符串保存:第一字节为字符串长度,后面跟字符串内容.
收到客户端的请求后,服务端开始回应
+----+-----+-------+------+----------+----------+
|VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
+----+-----+-------+------+----------+----------+
| 1 | 1 | X'00' | 1 | Variable | 2 |
+----+-----+-------+------+----------+----------+
Where:
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
Fields marked RESERVED (RSV) must be set to X'00'.
对应客户端的3种不同要求:
针对CONNECT请求的回复:
BND.PORT里面保存的是服务端连接到远程服务器所分配的端口,BND.ADDR保存的是分配的IP地址.(这里socks5为什么这么做我还有点不清楚,
不过不管它,先实现再说,以后在看看socks5 proxy client那边是怎么利用的.)
针对BIND请求的回复:
服务端将两次回复客户端.第一次回复是在服务端开启新的socket并开启一个端口侦听后.BND.PORT存放服务端侦听的端口.BND.ADDR存放IP
地址.客户端一般会利用这段信息来告诉远端服务器.第二次回复是用来表明远端服务器连接成功.BND.PORT和BND.ADDR分别存放远端服务器连接
用的端口及IP.
转于:http://www.cnblogs.com/yellowyu/archive/2008/11/05/1327089.html
————————————————————————————————————————————————————————————————————
早上,逛园子时看到breeze写了一篇Socks5代理协议的文章《C# 实现Socket5代理协议通讯 》,并在评论里看到howaaa说“顺便也讲讲用C#实现一个Socks5代理服务器吧,这方面资料很少,相信很有价值”,于是一时兴起,花了一个下午的时间捣鼓出Socks5代理的服务端程序。程序很简单(只要弄懂了Socks5协议就基本明白了)、代码很零乱。有兴趣的可以看看,没兴趣的就飘过吧,嘿嘿....
在breeze的文章中少了一个密码身份验证的讲解,在这里我补一下。
============================================================================================
当客户端与Socks5代理服务器连接上并进行握手时,客户端将会发送以下格式的握手报文:
版本号(1字节) | 认证方法数(1字节) | 认证方法序列(1-255个字节长度)
比如报文(假如为V5版本):
0x05 0x01 0x00 则表示客户端只支持一种(0x1)认证方法0x00 (无验证需求)
0x05 0x01 0x02 则表示客户端只支持一种(0x01)认证方法0x02(用户名/密码 验证)
0x05 0x02 0x00 0x02 则表示客户端支持两种(0x02)认证方法“0x00与0x02”
其中Socks5协议定义了以下几种认证方法:
0x00 无验证需求
0x01 通用安全服务应用程序接口(GSSAPI)
0x02 用户名/密码(USERNAME/PASSWORD)
0x03 至 X'7F' IANA 分配(IANA ASSIGNED)
0x80 至 X'FE' 私人方法保留(RESERVED FOR PRIVATE METHODS)
0xFF 无可接受方法(NO ACCEPTABLE METHODS)
在这里,我们要详解了解的则是“0x02 用户名/密码”验证的过程。
当客户端发送带有0x02认证方法的报文(如:“0x05 0x01 0x02”)到服务端时,根据报文,服务端得知客户端支持用户名/密码认证(0x02),因此如果服务端需要验证,则发送“0x05 0x02”应答,这样客户端将会进入“用户名/密码”验证过程。
“0x02 用户名/密码”验证协议的报文格式是:
0x01 | 用户名长度(1字节)| 用户名(长度根据用户名长度域指定) | 口令长度(1字节) | 口令(长度由口令长度域指定)
所以报文的长度是根据用户名与密码的长度而定,比如以下报文:
0x01 0x02 0x41 0x42 0x02 0x43 0x43
则表示发送用户名为“AB”密码为“CC”的验证报文。
服务端接收到用户名/密码验证报文后进行相应处理并返回以下格式的应答报文:
0x01 | 验证结果标志
如果验证通过则“验证结果标志”的值为“0x00”,否则其它值都表示验证失败!不允许再进行下一步的操作。
当握手与身份验证过程都通过后,将进入“连接请求”过程,在这步中服务端应该需要对客户端发送过来的远程服务端地址进行连接状态检查的,但在我这个程序中,我偷了懒没做,简单的就去后面的“连接”会话过程了,嘿嘿。
转于:http://www.cnblogs.com/kingthy/archive/2008/10/22/1317132.html