From c681ce101dbfad80929dbbed2df8a2adbc2af70f Mon Sep 17 00:00:00 2001 From: mitnk Date: Sun, 9 Dec 2012 18:44:28 +0800 Subject: [PATCH 01/11] clearfied the code - Read exactly bytes we should. - Use self.rfile / self.wfile install of mixed. - Do not make the band port specified. --- local.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/local.py b/local.py index bd6e09d..1028fa9 100755 --- a/local.py +++ b/local.py @@ -75,9 +75,9 @@ class Socks5Server(SocketServer.StreamRequestHandler): def handle(self): try: - sock = self.connection - sock.recv(262) - sock.send("\x05\x00") + data = self.rfile.read(2) + self.rfile.read(ord(data[1])) + self.wfile.write("\x05\x00") data = self.rfile.read(4) mode = ord(data[1]) if mode != 1: @@ -90,7 +90,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: @@ -102,8 +102,8 @@ class Socks5Server(SocketServer.StreamRequestHandler): port = struct.unpack('>H', addr_port) try: reply = "\x05\x00\x00\x01" - reply += socket.inet_aton('0.0.0.0') + struct.pack(">H", 2222) - sock.send(reply) + reply += socket.inet_aton('0.0.0.0') + struct.pack(">H", 0) + self.wfile.write(reply) # reply immediately if '-6' in sys.argv[1:]: remote = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) @@ -115,7 +115,7 @@ class Socks5Server(SocketServer.StreamRequestHandler): except socket.error, e: logging.warn(e) return - self.handle_tcp(sock, remote) + self.handle_tcp(self.connection, remote) except socket.error, e: logging.warn(e) From 1bec9f051eb37cb138dedd6307597f644737deed Mon Sep 17 00:00:00 2001 From: clowwindy Date: Mon, 10 Dec 2012 14:39:22 +0800 Subject: [PATCH 02/11] add Python version requirement in README.md --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e329e80..a5f3050 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,12 @@ shadowsocks is a lightweight tunnel proxy which can help you get through firewal usage ----------- -Edit `config.json`, change the following values: +First, make sure you have Python 2.6 or 2.7. + + $ python --version + Python 2.6.8 + +Then edit `config.json`, change the following values: server your server ip or hostname server_port server port From 075be61de816ee54f48c8e03cd91fc08f9cfde87 Mon Sep 17 00:00:00 2001 From: clowwindy Date: Wed, 12 Dec 2012 15:19:51 +0800 Subject: [PATCH 03/11] add troubleshooting --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index a5f3050..2a6b079 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ Change proxy settings of your browser into SOCKS5 127.0.0.1:local_port + advanced ------------ @@ -33,3 +34,20 @@ You can use args to override settings from `config.json`. python local.py -s server_name -p server_port -l local_port -k password python server.py -p server_port -k password + + +troubleshooting +--------------- + +* I can only load some websites + Check the logs of local.py. If you see only IPs, not hostnames, your may got DNS poisoned, but your browser hasn't + been configured to let the proxy resolve DNS. + To set proper DNS config, you can simply install FoxyProxy / Autoproxy for Firefox, or ProxySwitchy / SwitchySharp for + Chrome. They will set the config in your browser automatically. + Or you can change network.proxy.socks_remote_dns into true in about:config page if you use Firefox. +* I can't load any websites and the log prints mode != 1 + Make sure proxy protocol is set to Socks5, not Socks4 or HTTP. +* I use IE and I can't get my proxy to work + Since you can't specify Socks4 or Socks5 in IE settings, you may want to use a PAC(Proxy auto-config) script, or + just use Firefox instead. + From 3960e6495ee95d87b3da6b03aedcb3ab34a9ef58 Mon Sep 17 00:00:00 2001 From: clowwindy Date: Sun, 16 Dec 2012 00:47:46 +0800 Subject: [PATCH 04/11] replace send with sendall --- local.py | 10 ++++++++-- server.py | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/local.py b/local.py index e45fffe..3abc8a5 100755 --- a/local.py +++ b/local.py @@ -54,10 +54,16 @@ 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 data <= 0: + break + if remote.sendall(self.encrypt(data)) is not None: break if remote in r: - if sock.send(self.decrypt(remote.recv(4096))) <= 0: + data = remote.recv(4096) + if data <= 0: + break + if sock.sendall(self.decrypt(data)) is not None: break finally: sock.close() diff --git a/server.py b/server.py index 670c6d8..10ad75d 100755 --- a/server.py +++ b/server.py @@ -54,10 +54,16 @@ class Socks5Server(SocketServer.StreamRequestHandler): while True: r, w, e = select.select(fdset, [], []) if sock in r: - if remote.send(self.decrypt(sock.recv(4096))) <= 0: + data = sock.recv(4096) + if data <= 0: + break + if remote.sendall(self.decrypt(data)) is not None: break if remote in r: - if sock.send(self.encrypt(remote.recv(4096))) <= 0: + data = remote.recv(4096) + if data <= 0: + break + if sock.sendall(self.encrypt(data)) is not None: break finally: sock.close() From 8c5c40915ea8fbd22a0f1a6a9596010565118b35 Mon Sep 17 00:00:00 2001 From: clowwindy Date: Sun, 30 Dec 2012 12:28:23 +0800 Subject: [PATCH 05/11] add version --- README.md | 2 ++ local.py | 1 + server.py | 2 ++ 3 files changed, 5 insertions(+) diff --git a/README.md b/README.md index 2a6b079..2ad1ee1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ shadowsocks =========== +Current version: 0.9 + shadowsocks is a lightweight tunnel proxy which can help you get through firewalls usage diff --git a/local.py b/local.py index 574709f..079bdb7 100755 --- a/local.py +++ b/local.py @@ -128,6 +128,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) diff --git a/server.py b/server.py index f23d72b..6af8c7a 100755 --- a/server.py +++ b/server.py @@ -105,6 +105,8 @@ 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) From 12173a66d19cbba2bc15570001c046f9406b4533 Mon Sep 17 00:00:00 2001 From: clowwindy Date: Sun, 30 Dec 2012 13:28:51 +0800 Subject: [PATCH 06/11] add gevent --- README.md | 6 +++++- local.py | 13 ++++++++++--- server.py | 13 ++++++++++--- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 2ad1ee1..b93107f 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ First, make sure you have Python 2.6 or 2.7. $ python --version Python 2.6.8 + Then edit `config.json`, change the following values: server your server ip or hostname @@ -36,7 +37,10 @@ You can use args to override settings from `config.json`. python local.py -s server_name -p server_port -l local_port -k password python server.py -p server_port -k password - + +You may want to install gevent for better performance. + + $ sudo easy_install gevent troubleshooting --------------- diff --git a/local.py b/local.py index 079bdb7..8a5e507 100755 --- a/local.py +++ b/local.py @@ -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 @@ -58,13 +65,13 @@ class Socks5Server(SocketServer.StreamRequestHandler): data = sock.recv(4096) if data <= 0: break - if remote.sendall(self.encrypt(data)) is not None: + if remote.send(self.encrypt(data)) <= 0: break if remote in r: data = remote.recv(4096) if data <= 0: break - if sock.sendall(self.decrypt(data)) is not None: + if sock.send(self.decrypt(data)) <= 0: break finally: sock.close() diff --git a/server.py b/server.py index 6af8c7a..3558e22 100755 --- a/server.py +++ b/server.py @@ -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 @@ -58,13 +65,13 @@ class Socks5Server(SocketServer.StreamRequestHandler): data = sock.recv(4096) if data <= 0: break - if remote.sendall(self.decrypt(data)) is not None: + if remote.send(self.decrypt(data)) <= 0: break if remote in r: data = remote.recv(4096) if data <= 0: break - if sock.sendall(self.encrypt(data)) is not None: + if sock.send(self.encrypt(data)) <= 0: break finally: sock.close() From 65444c5b066cd1a64f3b4e8fcb67f59cbac204b4 Mon Sep 17 00:00:00 2001 From: clowwindy Date: Sun, 30 Dec 2012 14:01:41 +0800 Subject: [PATCH 07/11] use sendall() --- README.md | 6 +++++- local.py | 10 ++++------ server.py | 9 +++------ 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index b93107f..9472e79 100644 --- a/README.md +++ b/README.md @@ -40,8 +40,12 @@ You can use args to override settings from `config.json`. You may want to install gevent for better performance. + $ apt-get install python-gevent + +Or: + $ sudo easy_install gevent - + troubleshooting --------------- diff --git a/local.py b/local.py index 8a5e507..d0f9452 100755 --- a/local.py +++ b/local.py @@ -52,7 +52,7 @@ def get_table(key): class ThreadingTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): - pass + allow_reuse_address = True class Socks5Server(SocketServer.StreamRequestHandler): @@ -65,14 +65,13 @@ class Socks5Server(SocketServer.StreamRequestHandler): data = sock.recv(4096) if data <= 0: break - if remote.send(self.encrypt(data)) <= 0: - break + remote.sendall(self.encrypt(data)) + if remote in r: data = remote.recv(4096) if data <= 0: break - if sock.send(self.decrypt(data)) <= 0: - break + sock.sendall(self.decrypt(data)) finally: sock.close() remote.close() @@ -162,7 +161,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: diff --git a/server.py b/server.py index 3558e22..552599e 100755 --- a/server.py +++ b/server.py @@ -52,7 +52,7 @@ def get_table(key): class ThreadingTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): - pass + allow_reuse_address = True class Socks5Server(SocketServer.StreamRequestHandler): @@ -65,14 +65,12 @@ class Socks5Server(SocketServer.StreamRequestHandler): data = sock.recv(4096) if data <= 0: break - if remote.send(self.decrypt(data)) <= 0: - break + remote.sendall(self.decrypt(data)) if remote in r: data = remote.recv(4096) if data <= 0: break - if sock.send(self.encrypt(data)) <= 0: - break + sock.send(self.encrypt(data)) finally: sock.close() remote.close() @@ -137,7 +135,6 @@ if __name__ == '__main__': ThreadingTCPServer.address_family = socket.AF_INET6 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: From 004e9292f4ee2fdadd2511154c2042aba5978382 Mon Sep 17 00:00:00 2001 From: clowwindy Date: Sun, 30 Dec 2012 14:12:15 +0800 Subject: [PATCH 08/11] implement send_all myself --- local.py | 13 +++++++++++-- server.py | 14 ++++++++++++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/local.py b/local.py index d0f9452..aaa4a4d 100755 --- a/local.py +++ b/local.py @@ -50,6 +50,15 @@ 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): allow_reuse_address = True @@ -65,13 +74,13 @@ class Socks5Server(SocketServer.StreamRequestHandler): data = sock.recv(4096) if data <= 0: break - remote.sendall(self.encrypt(data)) + send_all(remote, self.encrypt(data)) if remote in r: data = remote.recv(4096) if data <= 0: break - sock.sendall(self.decrypt(data)) + send_all(sock, self.decrypt(data)) finally: sock.close() remote.close() diff --git a/server.py b/server.py index 552599e..b608c24 100755 --- a/server.py +++ b/server.py @@ -50,6 +50,16 @@ 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): allow_reuse_address = True @@ -65,12 +75,12 @@ class Socks5Server(SocketServer.StreamRequestHandler): data = sock.recv(4096) if data <= 0: break - remote.sendall(self.decrypt(data)) + send_all(remote, self.decrypt(data)) if remote in r: data = remote.recv(4096) if data <= 0: break - sock.send(self.encrypt(data)) + send_all(sock, self.encrypt(data)) finally: sock.close() remote.close() From 480c9ec51e7c6a049fc5de9c97f3fdb0de2b1982 Mon Sep 17 00:00:00 2001 From: clowwindy Date: Sun, 30 Dec 2012 14:43:18 +0800 Subject: [PATCH 09/11] fix infinite loop bug --- local.py | 12 ++++++++---- server.py | 14 +++++++++----- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/local.py b/local.py index aaa4a4d..25121b4 100755 --- a/local.py +++ b/local.py @@ -72,15 +72,19 @@ class Socks5Server(SocketServer.StreamRequestHandler): r, w, e = select.select(fdset, [], []) if sock in r: data = sock.recv(4096) - if data <= 0: + if len(data) <= 0: break - send_all(remote, self.encrypt(data)) + 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 data <= 0: + if len(data) <= 0: break - send_all(sock, self.decrypt(data)) + result = send_all(sock, self.decrypt(data)) + if result < len(data): + raise Exception('failed to send all data') finally: sock.close() remote.close() diff --git a/server.py b/server.py index b608c24..35f2a51 100755 --- a/server.py +++ b/server.py @@ -60,7 +60,6 @@ def send_all(sock, data): if bytes_sent == len(data): return bytes_sent - class ThreadingTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): allow_reuse_address = True @@ -73,14 +72,19 @@ class Socks5Server(SocketServer.StreamRequestHandler): r, w, e = select.select(fdset, [], []) if sock in r: data = sock.recv(4096) - if data <= 0: + if len(data) <= 0: break - send_all(remote, self.decrypt(data)) + result = send_all(remote, self.decrypt(data)) + if result < len(data): + raise Exception('failed to send all data') if remote in r: data = remote.recv(4096) - if data <= 0: + if len(data) <= 0: break - send_all(sock, self.encrypt(data)) + result = send_all(sock, self.encrypt(data)) + if result < len(data): + raise Exception('failed to send all data') + finally: sock.close() remote.close() From e8454cf9b15cc390ee093ed5572eb15cbaa56c3b Mon Sep 17 00:00:00 2001 From: clowwindy Date: Sun, 30 Dec 2012 14:47:24 +0800 Subject: [PATCH 10/11] add TCP_NODELAY --- local.py | 1 + server.py | 1 + 2 files changed, 2 insertions(+) diff --git a/local.py b/local.py index 25121b4..f0e889f 100755 --- a/local.py +++ b/local.py @@ -134,6 +134,7 @@ class Socks5Server(SocketServer.StreamRequestHandler): 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])) diff --git a/server.py b/server.py index 35f2a51..3beddca 100755 --- a/server.py +++ b/server.py @@ -112,6 +112,7 @@ class Socks5Server(SocketServer.StreamRequestHandler): try: logging.info('connecting %s:%d' % (addr, port[0])) remote = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + remote.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) remote.connect((addr, port[0])) except socket.error, e: # Connection refused From dd8ccf6f6eee0114e79018a55be3a01a2830fcdb Mon Sep 17 00:00:00 2001 From: clowwindy Date: Sun, 30 Dec 2012 14:57:56 +0800 Subject: [PATCH 11/11] rollback --- local.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/local.py b/local.py index f0e889f..04f283b 100755 --- a/local.py +++ b/local.py @@ -100,9 +100,9 @@ class Socks5Server(SocketServer.StreamRequestHandler): def handle(self): try: - data = self.rfile.read(2) - self.rfile.read(ord(data[1])) - self.wfile.write("\x05\x00") + sock = self.connection + sock.recv(262) + sock.send("\x05\x00") data = self.rfile.read(4) mode = ord(data[1]) if mode != 1: @@ -127,7 +127,7 @@ class Socks5Server(SocketServer.StreamRequestHandler): port = struct.unpack('>H', addr_port) try: reply = "\x05\x00\x00\x01" - reply += socket.inet_aton('0.0.0.0') + struct.pack(">H", 0) + reply += socket.inet_aton('0.0.0.0') + struct.pack(">H", 2222) self.wfile.write(reply) # reply immediately if '-6' in sys.argv[1:]: @@ -141,7 +141,7 @@ class Socks5Server(SocketServer.StreamRequestHandler): except socket.error, e: logging.warn(e) return - self.handle_tcp(self.connection, remote) + self.handle_tcp(sock, remote) except socket.error, e: logging.warn(e)