Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python
- # Copyright (c) 2012 clowwindy
- #
- # Permission is hereby granted, free of charge, to any person obtaining a copy
- # of this software and associated documentation files (the "Software"), to deal
- # in the Software without restriction, including without limitation the rights
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- # copies of the Software, and to permit persons to whom the Software is
- # furnished to do so, subject to the following conditions:
- #
- # The above copyright notice and this permission notice shall be included in
- # all copies or substantial portions of the Software.
- #
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- # SOFTWARE.
- import sys
- try:
- import gevent, gevent.monkey
- gevent.monkey.patch_all(dns=gevent.version_info[0]>=1)
- except ImportError:
- gevent = None
- print >>sys.stderr, 'warning: gevent not found, using threading instead'
- import socket
- import select
- import SocketServer
- import struct
- import string
- import hashlib
- import os
- import json
- import logging
- import getopt
- def get_table(key):
- m = hashlib.md5()
- m.update(key)
- s = m.digest()
- (a, b) = struct.unpack('<QQ', s)
- table = [c for c in string.maketrans('', '')]
- for i in xrange(1, 1024):
- table.sort(lambda x, y: int(a % (ord(x) + i) - a % (ord(y) + i)))
- return table
- def send_all(sock, data):
- bytes_sent = 0
- while True:
- r = sock.send(data[bytes_sent:])
- if r < 0:
- return r
- bytes_sent += r
- if bytes_sent == len(data):
- return bytes_sent
- class ThreadingTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
- allow_reuse_address = True
- class Socks5Server(SocketServer.StreamRequestHandler):
- def handle_tcp(self, sock, remote):
- try:
- fdset = [sock, remote]
- while True:
- r, w, e = select.select(fdset, [], [])
- if sock in r:
- data = sock.recv(4096)
- if len(data) <= 0:
- break
- result = send_all(remote, self.encrypt(data))
- if result < len(data):
- raise Exception('failed to send all data')
- if remote in r:
- data = remote.recv(4096)
- if len(data) <= 0:
- break
- result = send_all(sock, self.decrypt(data))
- if result < len(data):
- raise Exception('failed to send all data')
- finally:
- sock.close()
- remote.close()
- def encrypt(self, data):
- return data.translate(encrypt_table)
- def decrypt(self, data):
- return data.translate(decrypt_table)
- def send_encrypt(self, sock, data):
- sock.send(self.encrypt(data))
- def handle(self):
- first_send = None # Only use in HTTP Proxy
- try:
- sock = self.connection
- socks_ver = sock.recv(1)
- if not socks_ver:
- logging.debug('receive nothing')
- return
- elif socks_ver == '\x05': # SOCKS5 Protocol
- sock.recv(261)
- sock.send("\x05\x00")
- data = self.rfile.read(4)
- mode = ord(data[1])
- if mode != 1:
- logging.warn('mode != 1')
- return
- addrtype = ord(data[3])
- addr_to_send = data[3]
- if addrtype == 1:
- addr_ip = self.rfile.read(4)
- addr = socket.inet_ntoa(addr_ip)
- addr_to_send += addr_ip
- elif addrtype == 3:
- addr_len = self.rfile.read(1)
- addr = self.rfile.read(ord(addr_len))
- addr_to_send += addr_len + addr
- else:
- logging.warn('addr_type not support')
- # not support
- return
- addr_port = self.rfile.read(2)
- addr_to_send += addr_port
- port = struct.unpack('>H', addr_port)
- reply = "\x05\x00\x00\x01"
- reply += socket.inet_aton('0.0.0.0') + struct.pack(">H", 2222)
- self.wfile.write(reply) # reply immediately
- elif ord(socks_ver) >= 65: # HTTP Protocol
- #first_line = socks_ver + self.rfile.readline()
- first_line = ''
- recv = socks_ver
- while(recv != '\r'):
- first_line += recv
- recv = sock.recv(1)
- (method, uri, http_var) = first_line.split()
- if method == 'CONNECT':
- line = self.rfile.readline()
- while line != '\r\n':
- line = self.rfile.readline()
- self.wfile.write('HTTP/1.1 200 Connection established\r\n\r\n')
- domain = uri
- else:
- domain = uri[7:].split('/',1)[0]
- uri = uri[7 + len(domain):]
- first_send = ' '.join((method, uri, http_var)) + '\r'
- if ':' in domain:
- domain, port = uri.split(':')
- port = int(port)
- else:
- port = 80
- addr_to_send = '\x03' + chr(len(domain)) + \
- domain + struct.pack(">H", port)
- addr = domain
- port = (port, )
- try:
- if '-6' in sys.argv[1:]:
- remote = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
- else:
- remote = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- remote.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
- remote.connect((SERVER, REMOTE_PORT))
- self.send_encrypt(remote, addr_to_send)
- if first_send:
- self.send_encrypt(remote, first_send)
- logging.info('connecting %s:%d' % (addr, port[0]))
- except socket.error, e:
- logging.warn(e)
- return
- self.handle_tcp(sock, remote)
- except socket.error, e:
- logging.warn(e)
- if __name__ == '__main__':
- os.chdir(os.path.dirname(__file__) or '.')
- print 'shadowsocks v0.9.2'
- with open('config.json', 'rb') as f:
- config = json.load(f)
- SERVER = config['server']
- REMOTE_PORT = config['server_port']
- PORT = config['local_port']
- KEY = config['password']
- optlist, args = getopt.getopt(sys.argv[1:], 's:p:k:l:')
- for key, value in optlist:
- if key == '-p':
- REMOTE_PORT = int(value)
- elif key == '-k':
- KEY = value
- elif key == '-l':
- PORT = int(value)
- elif key == '-s':
- SERVER = value
- logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)-8s %(message)s',
- datefmt='%Y-%m-%d %H:%M:%S', filemode='a+')
- encrypt_table = ''.join(get_table(KEY))
- decrypt_table = string.maketrans(encrypt_table, string.maketrans('', ''))
- try:
- server = ThreadingTCPServer(('', PORT), Socks5Server)
- logging.info("starting server at port %d ..." % PORT)
- server.serve_forever()
- except socket.error, e:
- logging.error(e)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement