|
|
@ -20,6 +20,14 @@ |
|
|
|
# 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 |
|
|
@ -27,7 +35,6 @@ import SocketServer |
|
|
|
import struct |
|
|
|
import string |
|
|
|
import hashlib |
|
|
|
import sys |
|
|
|
import os |
|
|
|
import json |
|
|
|
import logging |
|
|
@ -43,9 +50,18 @@ def get_table(key): |
|
|
|
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): |
|
|
|
pass |
|
|
|
allow_reuse_address = True |
|
|
|
|
|
|
|
|
|
|
|
class Socks5Server(SocketServer.StreamRequestHandler): |
|
|
@ -55,11 +71,20 @@ class Socks5Server(SocketServer.StreamRequestHandler): |
|
|
|
while True: |
|
|
|
r, w, e = select.select(fdset, [], []) |
|
|
|
if sock in r: |
|
|
|
if remote.send(self.encrypt(sock.recv(4096))) <= 0: |
|
|
|
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: |
|
|
|
if sock.send(self.decrypt(remote.recv(4096))) <= 0: |
|
|
|
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() |
|
|
@ -90,7 +115,7 @@ class Socks5Server(SocketServer.StreamRequestHandler): |
|
|
|
addr = socket.inet_ntoa(addr_ip) |
|
|
|
addr_to_send += addr_ip |
|
|
|
elif addrtype == 3: |
|
|
|
addr_len = sock.recv(1) |
|
|
|
addr_len = self.rfile.read(1) |
|
|
|
addr = self.rfile.read(ord(addr_len)) |
|
|
|
addr_to_send += addr_len + addr |
|
|
|
else: |
|
|
@ -103,12 +128,13 @@ class Socks5Server(SocketServer.StreamRequestHandler): |
|
|
|
try: |
|
|
|
reply = "\x05\x00\x00\x01" |
|
|
|
reply += socket.inet_aton('0.0.0.0') + struct.pack(">H", 2222) |
|
|
|
sock.send(reply) |
|
|
|
self.wfile.write(reply) |
|
|
|
# reply immediately |
|
|
|
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) |
|
|
|
logging.info('connecting %s:%d' % (addr, port[0])) |
|
|
@ -122,6 +148,7 @@ class Socks5Server(SocketServer.StreamRequestHandler): |
|
|
|
|
|
|
|
if __name__ == '__main__': |
|
|
|
os.chdir(os.path.dirname(__file__) or '.') |
|
|
|
print 'shadowsocks v0.9' |
|
|
|
|
|
|
|
with open('config.json', 'rb') as f: |
|
|
|
config = json.load(f) |
|
|
@ -148,7 +175,6 @@ if __name__ == '__main__': |
|
|
|
decrypt_table = string.maketrans(encrypt_table, string.maketrans('', '')) |
|
|
|
try: |
|
|
|
server = ThreadingTCPServer(('', PORT), Socks5Server) |
|
|
|
server.allow_reuse_address = True |
|
|
|
logging.info("starting server at port %d ..." % PORT) |
|
|
|
server.serve_forever() |
|
|
|
except socket.error, e: |
|
|
|