Advertisement
Guest User

shadowsocks - http&socks5

a guest
Jan 11th, 2013
4,643
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.94 KB | None | 0 0
  1. #!/usr/bin/env python
  2.  
  3. # Copyright (c) 2012 clowwindy
  4. #
  5. # Permission is hereby granted, free of charge, to any person obtaining a copy
  6. # of this software and associated documentation files (the "Software"), to deal
  7. # in the Software without restriction, including without limitation the rights
  8. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. # copies of the Software, and to permit persons to whom the Software is
  10. # furnished to do so, subject to the following conditions:
  11. #
  12. # The above copyright notice and this permission notice shall be included in
  13. # all copies or substantial portions of the Software.
  14. #
  15. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  21. # SOFTWARE.
  22.  
  23. import sys
  24.  
  25. try:
  26.     import gevent, gevent.monkey
  27.     gevent.monkey.patch_all(dns=gevent.version_info[0]>=1)
  28. except ImportError:
  29.     gevent = None
  30.     print >>sys.stderr, 'warning: gevent not found, using threading instead'
  31.  
  32. import socket
  33. import select
  34. import SocketServer
  35. import struct
  36. import string
  37. import hashlib
  38. import os
  39. import json
  40. import logging
  41. import getopt
  42.  
  43. def get_table(key):
  44.     m = hashlib.md5()
  45.     m.update(key)
  46.     s = m.digest()
  47.     (a, b) = struct.unpack('<QQ', s)
  48.     table = [c for c in string.maketrans('', '')]
  49.     for i in xrange(1, 1024):
  50.         table.sort(lambda x, y: int(a % (ord(x) + i) - a % (ord(y) + i)))
  51.     return table
  52.  
  53. def send_all(sock, data):
  54.     bytes_sent = 0
  55.     while True:
  56.         r = sock.send(data[bytes_sent:])
  57.         if r < 0:
  58.             return r
  59.         bytes_sent += r
  60.         if bytes_sent == len(data):
  61.             return bytes_sent
  62.  
  63. class ThreadingTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
  64.     allow_reuse_address = True
  65.  
  66.  
  67. class Socks5Server(SocketServer.StreamRequestHandler):
  68.     def handle_tcp(self, sock, remote):
  69.         try:
  70.             fdset = [sock, remote]
  71.             while True:
  72.                 r, w, e = select.select(fdset, [], [])
  73.                 if sock in r:
  74.                     data = sock.recv(4096)
  75.                     if len(data) <= 0:
  76.                         break
  77.                     result = send_all(remote, self.encrypt(data))
  78.                     if result < len(data):
  79.                         raise Exception('failed to send all data')
  80.  
  81.                 if remote in r:
  82.                     data = remote.recv(4096)
  83.                     if len(data) <= 0:
  84.                         break
  85.                     result = send_all(sock, self.decrypt(data))
  86.                     if result < len(data):
  87.                         raise Exception('failed to send all data')
  88.         finally:
  89.             sock.close()
  90.             remote.close()
  91.  
  92.     def encrypt(self, data):
  93.         return data.translate(encrypt_table)
  94.  
  95.     def decrypt(self, data):
  96.         return data.translate(decrypt_table)
  97.  
  98.     def send_encrypt(self, sock, data):
  99.         sock.send(self.encrypt(data))
  100.  
  101.     def handle(self):
  102.         first_send = None # Only use in HTTP Proxy
  103.         try:
  104.             sock = self.connection
  105.             socks_ver = sock.recv(1)
  106.             if not socks_ver:
  107.                 logging.debug('receive nothing')
  108.                 return
  109.             elif socks_ver == '\x05': # SOCKS5 Protocol
  110.                 sock.recv(261)
  111.                 sock.send("\x05\x00")
  112.                 data = self.rfile.read(4)
  113.                 mode = ord(data[1])
  114.                 if mode != 1:
  115.                     logging.warn('mode != 1')
  116.                     return
  117.                 addrtype = ord(data[3])
  118.                 addr_to_send = data[3]
  119.                 if addrtype == 1:
  120.                     addr_ip = self.rfile.read(4)
  121.                     addr = socket.inet_ntoa(addr_ip)
  122.                     addr_to_send += addr_ip
  123.                 elif addrtype == 3:
  124.                     addr_len = self.rfile.read(1)
  125.                     addr = self.rfile.read(ord(addr_len))
  126.                     addr_to_send += addr_len + addr
  127.                 else:
  128.                     logging.warn('addr_type not support')
  129.                     # not support
  130.                     return
  131.                 addr_port = self.rfile.read(2)
  132.                 addr_to_send += addr_port
  133.                 port = struct.unpack('>H', addr_port)
  134.                 reply = "\x05\x00\x00\x01"
  135.                 reply += socket.inet_aton('0.0.0.0') + struct.pack(">H", 2222)
  136.                 self.wfile.write(reply) # reply immediately
  137.                
  138.             elif ord(socks_ver) >= 65: # HTTP Protocol
  139.                 #first_line = socks_ver + self.rfile.readline()
  140.                 first_line = ''
  141.                 recv = socks_ver
  142.                 while(recv != '\r'):
  143.                     first_line += recv
  144.                     recv = sock.recv(1)
  145.                 (method, uri, http_var) = first_line.split()
  146.                 if method == 'CONNECT':
  147.                     line = self.rfile.readline()
  148.                     while line != '\r\n':
  149.                         line = self.rfile.readline()
  150.                     self.wfile.write('HTTP/1.1 200 Connection established\r\n\r\n')
  151.                     domain = uri
  152.                 else:
  153.                     domain = uri[7:].split('/',1)[0]
  154.                     uri = uri[7 + len(domain):]
  155.                     first_send = ' '.join((method, uri, http_var)) + '\r'
  156.                 if ':' in domain:
  157.                     domain, port = uri.split(':')
  158.                     port = int(port)
  159.                 else:
  160.                     port = 80
  161.                 addr_to_send = '\x03' + chr(len(domain)) + \
  162.                                 domain + struct.pack(">H", port)
  163.                 addr = domain
  164.                 port = (port, )
  165.                                
  166.             try:
  167.                 if '-6' in sys.argv[1:]:
  168.                     remote = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
  169.                 else:
  170.                     remote = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  171.                 remote.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
  172.                 remote.connect((SERVER, REMOTE_PORT))
  173.                 self.send_encrypt(remote, addr_to_send)
  174.                 if first_send:
  175.                     self.send_encrypt(remote, first_send)
  176.                 logging.info('connecting %s:%d' % (addr, port[0]))
  177.             except socket.error, e:
  178.                 logging.warn(e)
  179.                 return
  180.             self.handle_tcp(sock, remote)
  181.         except socket.error, e:
  182.             logging.warn(e)
  183.  
  184.  
  185. if __name__ == '__main__':
  186.     os.chdir(os.path.dirname(__file__) or '.')
  187.     print 'shadowsocks v0.9.2'
  188.  
  189.     with open('config.json', 'rb') as f:
  190.         config = json.load(f)
  191.     SERVER = config['server']
  192.     REMOTE_PORT = config['server_port']
  193.     PORT = config['local_port']
  194.     KEY = config['password']
  195.  
  196.     optlist, args = getopt.getopt(sys.argv[1:], 's:p:k:l:')
  197.     for key, value in optlist:
  198.         if key == '-p':
  199.             REMOTE_PORT = int(value)
  200.         elif key == '-k':
  201.             KEY = value
  202.         elif key == '-l':
  203.             PORT = int(value)
  204.         elif key == '-s':
  205.             SERVER = value
  206.  
  207.     logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)-8s %(message)s',
  208.         datefmt='%Y-%m-%d %H:%M:%S', filemode='a+')
  209.  
  210.     encrypt_table = ''.join(get_table(KEY))
  211.     decrypt_table = string.maketrans(encrypt_table, string.maketrans('', ''))
  212.     try:
  213.         server = ThreadingTCPServer(('', PORT), Socks5Server)
  214.         logging.info("starting server at port %d ..." % PORT)
  215.         server.serve_forever()
  216.     except socket.error, e:
  217.         logging.error(e)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement