本人对网络协议很菜,刚接触,希望各位前辈多多指教。
最近在写socks5代理服务器,所以需要接触socks5协议,随即分析一通。自写了个客户端,然后用ccproxy作为服务端来进行分析。。
OK,废话不多说,用客户端连接后,用科来抓取ccproxy服务端的数据包。
首先前三个数据包也就是我们经常说的三次握手。
如下图。
之前虽然写过socket程序,不过对三次握手原理一直不明白(菜啊)。今天用科来对数据包解码后才明白。。
原来当客户端通过connect函数连接服务端的时候,会首先发送一个SYN(同步位,用来建立连接)tcp数据包,服务端接受到这个数据包后会向->客户端发送一个SYN+ACK(ACK为确认号),这样客户端收到数据包后表示服务端已经确认,此时客户端也需要向服务端发送一个标志位为ACK的数据包,服务端接收到这个数据包后,表示客户端已经确认。此时三次握手已经建立。 此时connect函数也就会返回一个套接字句柄,用来接收和发送数据包。。
这个过程如下图
1:
2:
3:
OK! 接下来,socks5协议的客户端会发送一个请求版本和认证方法的数据包,长度为3,我们此时也成为socks5协议的握手过程。
数据包如下图:
这里有一个疑问,也就是为何发送的数据包长度为3,但是额外数据里确实6个字节。。这里不解,希望有经验的朋友解答下我的疑问。。。
这里发送的数据包为0x05, 0x01, 0x00 。 这里是socks5协议的一个预定义的结构规定。具体大家可以去看rfc1928文档!
0x05代表的版本号,0x01表示的认证方法的次数,0x00代表的认证是无用户名密码验证的,如果这里是0x02则表示代表的认证是有用户名密码验证的!
此时服务端接受到这个数据包后进行分析,如果发送的第二个字节是0x01,且第三个字节是00的话,则表示无需用户名密码验证,则会发送给客户端两个字节的数据包,这两个字节是0x05,0x00。如果第二个字节是0x01,且第三个字节是0x02的话,服务端则会发送两个字节的数据包,这两个字节是0x05,0x02,以表示给客户端,此服务端支持此socks5协议。
服务端返回的数据包如下:
客户端此时就会进行判断,如果是0x05,0x00或者0x05, 0x02的话,表示服务器是支持socks5协议的,那么此刻如果是无用户名\密码验证的方式,客户端就会按照socks5协议规定的结构把目标ip和端口发送给服务端。
在这里客户端会首先发送一个ACK的数据包来确认连接,然后继续发送PSH+ACK的一个数据包,此时数据包里包含了目标ip和端口以及连接方式.数据包如下图:
此时服务端接收到这个数据包后,会去连接数据包里包含的目标ip和端口。(继续三次握手过程),如果连接成功后会返回客户端之前的结构,并且设置rep成员为00,以表示成功。
数据包如下:
此时客户端判断返回的rep成员是否为0,如果为0的话,则表示代理服务器已经连接目标主机,我可以给代理服务器发送数据包了。。
此时发送一个ACK包后,然后将数据包发送给代理服务器。
数据包如下:
同样这里不解,为何发送的数据包为4个,这里的额外数据为6个字节。
此时服务端接受到数据包后,直接将数据包发送给之前连接的目标IP socket中。
数据包为:
这里有点不解,为何服务端端ccproxy是直接发送ACK+PSH数据包,而不是先发送ACK数据包后,再发送ACK+PSH数据包。
紧接着 代理服务器发->客户端一个ACK数据包,目标IP也发送一个ACK数据包->代理服务器。客户端此时发送一个ACK+FIN的数据包给代理服务器(标志完成传送)数据包。代理服务器发送ACK包确认。代理服务器发送ACK+FIN包给目标IP以确认数据包是否发完,目标IP发送ACK包确认。代理服务器给客户端发送ACK+FIN包确认是否发送完成,客户端发送ACK包确认。同样代理服务器也重复以上工作。 OK基本工作完成。。 此时一个socks5协议的工作流程基本就是这样,小弟第一次发文章可能有很多地方解释的不是很清楚,多多包含。 |