Socks5代码的一点解析

来源:互联网 发布:windows上软件无法卸载 编辑:程序博客网 时间:2024/06/06 00:22

      最近,看了一下Socks5的RFC,在网上找了一下Scoks5的Python实现,有几个地方自己看得不是很明白,就多查看了一下,Wireshark抓包也看了一下,稍微记录一下。

      网上找的源码如下:其中我不是很明白的地方在如下:

  1: #!/usr/bin/python
  2: # Filename s5.py
  3: # Python Dynamic Socks5 Proxy
  4: # Usage: python s5.py 1080
  5: # Background Run: nohup python s5.py 1080 &
  6: 
  7: import socket, sys, select, SocketServer, struct, time
  8: 
  9: class ThreadingTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): pass
 10: class Socks5Server(SocketServer.StreamRequestHandler):
 11:   def handle_tcp(self, sock, remote):
 12:     fdset = [sock, remote]
 13:     while True:
 14:       r, w, e = select.select(fdset, [], [])
 15:       if sock in r:
 16:         if remote.send(sock.recv(4096)) <= 0: break
 17:       if remote in r:
 18:         if sock.send(remote.recv(4096)) <= 0: break
 19:   def handle(self):
 20:     try:
 21:       pass # print 'from ', self.client_address nothing to do.
 22:       sock = self.connection
 23:       # 1. Version
 24:       sock.recv(262) 
 25:       sock.send("\x05\x00");
 26:       # 2. Request
 27:       data = self.rfile.read(4)
 28:       mode = ord(data[1])
 29:       addrtype = ord(data[3])
 30:       if addrtype == 1:    # IPv4
 31:         addr = socket.inet_ntoa(self.rfile.read(4))
 32:       elif addrtype == 3:   # Domain name
 33:         addr = self.rfile.read(ord(sock.recv(1)[0])) 
 34:       port = struct.unpack('>H', self.rfile.read(2)) 
 35:       reply = "\x05\x00\x00\x01"
 36:       try:
 37:         if mode == 1: # 1. Tcp connect
 38:           remote = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 39:           remote.connect((addr, port[0]))
 40:           pass # print 'To', addr, port[0] nothing do to.
 41:         else:
 42:           reply = "\x05\x07\x00\x01" # Command not supported
 43:         local = remote.getsockname()
 44:         reply += socket.inet_aton(local[0]) + struct.pack(">H", local[1])
 45:       except socket.error:
 46:         # Connection refused
 47:         reply = '\x05\x05\x00\x01\x00\x00\x00\x00\x00\x00'
 48:       sock.send(reply)
 49:       # 3. Transfering
 50:       if reply[1] == '\x00': # Success
 51:         if mode == 1:  # 1. Tcp connect
 52:           self.handle_tcp(sock, remote) 
 53:     except socket.error:
 54:       pass #print 'error' nothing to do .
 55:     except IndexError:
 56:       pass
 57: def main():
 58:   filename = sys.argv[0];
 59:   if len(sys.argv)<2:
 60:     print 'usage: ' + filename + ' port'
 61:     sys.exit()
 62:   socks_port = int(sys.argv[1]);
 63:   server = ThreadingTCPServer(('', socks_port), Socks5Server)
 64:   print 'bind port: %d' % socks_port + ' ok!'
 65:   server.serve_forever()
 66: if __name__ == '__main__':
 67:   main()
 68: 

      为啥要接收262个字节的数据,抓包发现其实没有这么多,可以看下抓包的结果。

      首先是TCP三次握手建立连接:

three

      客户端给服务器发送05 01 00共三个字节,要求匿名代理:

s1

      服务器端发送05 00两个字节,表示允许匿名代理。

s2

      客户端如果发送05 01 00 03 表示后面跟的是域名而不是IP地址,由Socks5服务器进行DNS解析。

s3

      RFC中有这样一句。

The programming interface for a SOCKS-aware UDP MUST report an
   available buffer space for UDP datagrams that is smaller than the
   actual space provided by the operating system:
          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

      我琢磨是不是这个的原因,recv那里写的是262字节了。我把262改的很小也是可以的,但是改的太小,比如10就报错了。如果有知道原因的朋友,请留言告诉我。

      还有几个是Python语法相关的问题,在源码中看到了第39行的port[0],就是因为struct.unpack返回的是一个元组,即使返回值只要一个元素。recv(1)的意思是接收<=1个byte的数据,[0]取第一个byte也就是后续域名的长度。

      上面源码实现的只是Socks5的TCP连接方式。

      参考链接:http://blog.csdn.net/liujiayu2/article/details/51691778

0 0
原创粉丝点击