From 176e97bb452d5715417a6e9e7cb87a2ff68a935f Mon Sep 17 00:00:00 2001 From: fa08c <0xfa08c@gmail.com> Date: Thu, 8 Jan 2015 11:03:12 +0800 Subject: [PATCH 01/20] Fixing some minor issues --- shadowsocks/crypto/ctypes_openssl.py | 2 +- shadowsocks/eventloop.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/shadowsocks/crypto/ctypes_openssl.py b/shadowsocks/crypto/ctypes_openssl.py index 9e0dfca..5ddff15 100644 --- a/shadowsocks/crypto/ctypes_openssl.py +++ b/shadowsocks/crypto/ctypes_openssl.py @@ -83,9 +83,9 @@ def load_cipher(cipher_name): class CtypesCrypto(object): def __init__(self, cipher_name, key, iv, op): + self._ctx = None if not loaded: load_openssl() - self._ctx = None cipher = libcrypto.EVP_get_cipherbyname(cipher_name) if not cipher: cipher = load_cipher(cipher_name) diff --git a/shadowsocks/eventloop.py b/shadowsocks/eventloop.py index 55c30bb..2b2459f 100644 --- a/shadowsocks/eventloop.py +++ b/shadowsocks/eventloop.py @@ -234,7 +234,7 @@ class EventLoop(object): traceback.print_exc() for handler in self._handlers_to_remove: self._handlers.remove(handler) - self._handlers_to_remove = [] + self._handlers_to_remove = [] self._iterating = False From 18da3554ff3e51aaa53a6b051fc8e35b04cda6b8 Mon Sep 17 00:00:00 2001 From: fa08c <0xfa08c@gmail.com> Date: Thu, 8 Jan 2015 08:27:28 -0600 Subject: [PATCH 02/20] Minor fix: never use except: unless you reraise --- shadowsocks/crypto/rc4_md5.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shadowsocks/crypto/rc4_md5.py b/shadowsocks/crypto/rc4_md5.py index 3062dcc..aa22b16 100644 --- a/shadowsocks/crypto/rc4_md5.py +++ b/shadowsocks/crypto/rc4_md5.py @@ -39,7 +39,7 @@ def create_cipher(alg, key, iv, op, key_as_bytes=0, d=None, salt=None, try: from shadowsocks.crypto import ctypes_openssl return ctypes_openssl.CtypesCrypto(b'rc4', rc4_key, b'', op) - except: + except Exception: import M2Crypto.EVP return M2Crypto.EVP.Cipher(b'rc4', rc4_key, b'', op, key_as_bytes=0, d='md5', salt=None, i=1, From 3294a92a61463abd8527eb1e3f83b1666b476204 Mon Sep 17 00:00:00 2001 From: fa08c <0xfa08c@gmail.com> Date: Sat, 10 Jan 2015 22:26:20 +0800 Subject: [PATCH 03/20] Search libcrypto.so in more locations Some linux distro may store .so in some alternative locations. Now we try harder to find them. --- shadowsocks/crypto/ctypes_openssl.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/shadowsocks/crypto/ctypes_openssl.py b/shadowsocks/crypto/ctypes_openssl.py index 5ddff15..6e80461 100644 --- a/shadowsocks/crypto/ctypes_openssl.py +++ b/shadowsocks/crypto/ctypes_openssl.py @@ -45,9 +45,29 @@ def load_openssl(): if libcrypto_path: break else: + # We may get here when find_library fails because, for example, + # the user does not have sufficient privileges to access those + # tools underlying find_library on linux. + import glob - for libcrypto_path in glob.glob('/usr/lib/libcrypto.*'): - pass + import sys + + patterns = ['/usr/lib/libcrypto.*'] + + # Some linux distros may store so in alternative locations + if sys.maxsize > 2 ** 32: + # Python is 64-bit + patterns.extend(['/usr/lib64/libcrypto.*']) + else: + # Python is 32-bit + patterns.extend(['/usr/lib32/libcrypto.*']) + + for pat in patterns: + files = glob.glob(pat) + if files: + libcrypto_path = files[0] + break + if libcrypto_path is None: raise Exception('libcrypto(OpenSSL) not found') logging.info('loading libcrypto from %s', libcrypto_path) From 6eadfca78ec2e731e9f7f9445c1143899009ed58 Mon Sep 17 00:00:00 2001 From: fa08c <0xfa08c@gmail.com> Date: Sun, 11 Jan 2015 15:19:31 +0800 Subject: [PATCH 04/20] Removing trailing whites --- shadowsocks/crypto/ctypes_openssl.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shadowsocks/crypto/ctypes_openssl.py b/shadowsocks/crypto/ctypes_openssl.py index 6e80461..22238c0 100644 --- a/shadowsocks/crypto/ctypes_openssl.py +++ b/shadowsocks/crypto/ctypes_openssl.py @@ -45,8 +45,8 @@ def load_openssl(): if libcrypto_path: break else: - # We may get here when find_library fails because, for example, - # the user does not have sufficient privileges to access those + # We may get here when find_library fails because, for example, + # the user does not have sufficient privileges to access those # tools underlying find_library on linux. import glob From ebfd1486d884190dd26b7af5c694b9dadccd85c3 Mon Sep 17 00:00:00 2001 From: fa08c <0xfa08c@gmail.com> Date: Mon, 12 Jan 2015 10:32:03 +0800 Subject: [PATCH 05/20] Removing the overhead of creating a new list per event --- shadowsocks/eventloop.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/shadowsocks/eventloop.py b/shadowsocks/eventloop.py index 2b2459f..304b229 100644 --- a/shadowsocks/eventloop.py +++ b/shadowsocks/eventloop.py @@ -232,9 +232,10 @@ class EventLoop(object): logging.error(e) import traceback traceback.print_exc() - for handler in self._handlers_to_remove: - self._handlers.remove(handler) - self._handlers_to_remove = [] + if self._handlers_to_remove: + for handler in self._handlers_to_remove: + self._handlers.remove(handler) + self._handlers_to_remove = [] self._iterating = False From 3d03dbf7169dc4d16e4728bd74710573a2a86795 Mon Sep 17 00:00:00 2001 From: clowwindy Date: Mon, 12 Jan 2015 14:00:35 +0800 Subject: [PATCH 06/20] extract find_library --- shadowsocks/crypto/ctypes_libsodium.py | 28 +++-------- shadowsocks/crypto/ctypes_openssl.py | 44 ++++------------- shadowsocks/crypto/util.py | 65 ++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 57 deletions(-) diff --git a/shadowsocks/crypto/ctypes_libsodium.py b/shadowsocks/crypto/ctypes_libsodium.py index e74d577..7e9f6a4 100644 --- a/shadowsocks/crypto/ctypes_libsodium.py +++ b/shadowsocks/crypto/ctypes_libsodium.py @@ -23,10 +23,11 @@ from __future__ import absolute_import, division, print_function, \ with_statement -import logging -from ctypes import CDLL, c_char_p, c_int, c_ulonglong, byref, \ +from ctypes import c_char_p, c_int, c_ulonglong, byref, \ create_string_buffer, c_void_p +from shadowsocks.crypto import util + __all__ = ['ciphers'] libsodium = None @@ -41,21 +42,11 @@ BLOCK_SIZE = 64 def load_libsodium(): global loaded, libsodium, buf - from ctypes.util import find_library - libsodium_path = None - for p in ('sodium', 'libsodium'): - libsodium_path = find_library(p) - if libsodium_path: - break - else: - import glob - for libsodium_path in glob.glob('/usr/lib/libsodium.*'): - pass - if libsodium_path is None: + libsodium = util.find_library('sodium', 'crypto_stream_salsa20_xor_ic', + 'libsodium') + if libsodium is None: raise Exception('libsodium not found') - logging.info('loading libsodium from %s', libsodium_path) - libsodium = CDLL(libsodium_path) - libsodium.sodium_init.restype = c_int + libsodium.crypto_stream_salsa20_xor_ic.restype = c_int libsodium.crypto_stream_salsa20_xor_ic.argtypes = (c_void_p, c_char_p, c_ulonglong, @@ -67,8 +58,6 @@ def load_libsodium(): c_char_p, c_ulonglong, c_char_p) - libsodium.sodium_init() - buf = create_string_buffer(buf_size) loaded = True @@ -118,8 +107,6 @@ ciphers = { def test_salsa20(): - from shadowsocks.crypto import util - cipher = Salsa20Crypto(b'salsa20', b'k' * 32, b'i' * 16, 1) decipher = Salsa20Crypto(b'salsa20', b'k' * 32, b'i' * 16, 0) @@ -127,7 +114,6 @@ def test_salsa20(): def test_chacha20(): - from shadowsocks.crypto import util cipher = Salsa20Crypto(b'chacha20', b'k' * 32, b'i' * 16, 1) decipher = Salsa20Crypto(b'chacha20', b'k' * 32, b'i' * 16, 0) diff --git a/shadowsocks/crypto/ctypes_openssl.py b/shadowsocks/crypto/ctypes_openssl.py index 22238c0..3bdd99d 100644 --- a/shadowsocks/crypto/ctypes_openssl.py +++ b/shadowsocks/crypto/ctypes_openssl.py @@ -23,10 +23,11 @@ from __future__ import absolute_import, division, print_function, \ with_statement -import logging -from ctypes import CDLL, c_char_p, c_int, c_long, byref,\ +from ctypes import c_char_p, c_int, c_long, byref,\ create_string_buffer, c_void_p +from shadowsocks.crypto import util + __all__ = ['ciphers'] libcrypto = None @@ -38,40 +39,12 @@ buf_size = 2048 def load_openssl(): global loaded, libcrypto, buf - from ctypes.util import find_library - libcrypto_path = None - for p in ('crypto', 'eay32', 'libeay32'): - libcrypto_path = find_library(p) - if libcrypto_path: - break - else: - # We may get here when find_library fails because, for example, - # the user does not have sufficient privileges to access those - # tools underlying find_library on linux. - - import glob - import sys - - patterns = ['/usr/lib/libcrypto.*'] - - # Some linux distros may store so in alternative locations - if sys.maxsize > 2 ** 32: - # Python is 64-bit - patterns.extend(['/usr/lib64/libcrypto.*']) - else: - # Python is 32-bit - patterns.extend(['/usr/lib32/libcrypto.*']) - - for pat in patterns: - files = glob.glob(pat) - if files: - libcrypto_path = files[0] - break - - if libcrypto_path is None: + libcrypto = util.find_library(('crypto', 'eay32'), + 'EVP_get_cipherbyname', + 'libcrypto') + if libcrypto is None: raise Exception('libcrypto(OpenSSL) not found') - logging.info('loading libcrypto from %s', libcrypto_path) - libcrypto = CDLL(libcrypto_path) + libcrypto.EVP_get_cipherbyname.restype = c_void_p libcrypto.EVP_CIPHER_CTX_new.restype = c_void_p @@ -173,7 +146,6 @@ ciphers = { def run_method(method): - from shadowsocks.crypto import util cipher = CtypesCrypto(method, b'k' * 32, b'i' * 16, 1) decipher = CtypesCrypto(method, b'k' * 32, b'i' * 16, 0) diff --git a/shadowsocks/crypto/util.py b/shadowsocks/crypto/util.py index 3bac1db..68cfabd 100644 --- a/shadowsocks/crypto/util.py +++ b/shadowsocks/crypto/util.py @@ -20,6 +20,57 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. +from __future__ import absolute_import, division, print_function, \ + with_statement + +import logging + + +def find_library(possible_lib_names, search_symbol, library_name): + from ctypes.util import find_library + from ctypes import CDLL + + paths = [] + + if type(possible_lib_names) is not list: + possible_lib_names = [possible_lib_names] + + for name in possible_lib_names: + path = find_library(name) + if path: + paths.append(path) + + if not paths: + # We may get here when find_library fails because, for example, + # the user does not have sufficient privileges to access those + # tools underlying find_library on linux. + import glob + + for name in possible_lib_names: + patterns = [ + '/usr/local/lib*/lib%s.*' % name, + '/usr/lib*/lib%s.*' % name, + 'lib%s.*' % name, + '%s.dll' % name, + 'lib%s.dll' % name] + + for pat in patterns: + files = glob.glob(pat) + if files: + paths.extend(files) + for path in paths: + try: + lib = CDLL(path) + if hasattr(lib, search_symbol): + logging.info('loading %s from %s', library_name, path) + return lib + else: + logging.warn('can\'t find symbol %s in %s', search_symbol, + path) + except Exception: + pass + return None + def run_cipher(cipher, decipher): from os import urandom @@ -49,3 +100,17 @@ def run_cipher(cipher, decipher): end = time.time() print('speed: %d bytes/s' % (BLOCK_SIZE * rounds / (end - start))) assert b''.join(results) == plain + + +def test_find_library(): + assert find_library('c', 'strcpy', 'libc') is not None + assert find_library(['c'], 'strcpy', 'libc') is not None + assert find_library('crypto', 'EVP_CipherUpdate', 'libcrypto') is not None + assert find_library('notexist', 'strcpy', 'libnotexist') is None + assert find_library('c', 'symbol_not_exist', 'c') is None + assert find_library(['notexist', 'c', 'crypto'], + 'EVP_CipherUpdate', 'libc') is not None + + +if __name__ == '__main__': + test_find_library() From e582b2b9298755bb0bd9f3ce2d0aa6c26a46bbc7 Mon Sep 17 00:00:00 2001 From: clowwindy Date: Mon, 12 Jan 2015 14:05:20 +0800 Subject: [PATCH 07/20] rename ctypes_* and remove salsa20-ctr --- .../crypto/{ctypes_openssl.py => openssl.py} | 56 +++---- shadowsocks/crypto/rc4_md5.py | 4 +- shadowsocks/crypto/salsa20_ctr.py | 140 ------------------ .../crypto/{ctypes_libsodium.py => sodium.py} | 14 +- shadowsocks/encrypt.py | 10 +- 5 files changed, 41 insertions(+), 183 deletions(-) rename shadowsocks/crypto/{ctypes_openssl.py => openssl.py} (78%) delete mode 100644 shadowsocks/crypto/salsa20_ctr.py rename shadowsocks/crypto/{ctypes_libsodium.py => sodium.py} (91%) diff --git a/shadowsocks/crypto/ctypes_openssl.py b/shadowsocks/crypto/openssl.py similarity index 78% rename from shadowsocks/crypto/ctypes_openssl.py rename to shadowsocks/crypto/openssl.py index 3bdd99d..bb11627 100644 --- a/shadowsocks/crypto/ctypes_openssl.py +++ b/shadowsocks/crypto/openssl.py @@ -74,7 +74,7 @@ def load_cipher(cipher_name): return None -class CtypesCrypto(object): +class OpenSSLCrypto(object): def __init__(self, cipher_name, key, iv, op): self._ctx = None if not loaded: @@ -117,38 +117,38 @@ class CtypesCrypto(object): ciphers = { - b'aes-128-cfb': (16, 16, CtypesCrypto), - b'aes-192-cfb': (24, 16, CtypesCrypto), - b'aes-256-cfb': (32, 16, CtypesCrypto), - b'aes-128-ofb': (16, 16, CtypesCrypto), - b'aes-192-ofb': (24, 16, CtypesCrypto), - b'aes-256-ofb': (32, 16, CtypesCrypto), - b'aes-128-ctr': (16, 16, CtypesCrypto), - b'aes-192-ctr': (24, 16, CtypesCrypto), - b'aes-256-ctr': (32, 16, CtypesCrypto), - b'aes-128-cfb8': (16, 16, CtypesCrypto), - b'aes-192-cfb8': (24, 16, CtypesCrypto), - b'aes-256-cfb8': (32, 16, CtypesCrypto), - b'aes-128-cfb1': (16, 16, CtypesCrypto), - b'aes-192-cfb1': (24, 16, CtypesCrypto), - b'aes-256-cfb1': (32, 16, CtypesCrypto), - b'bf-cfb': (16, 8, CtypesCrypto), - b'camellia-128-cfb': (16, 16, CtypesCrypto), - b'camellia-192-cfb': (24, 16, CtypesCrypto), - b'camellia-256-cfb': (32, 16, CtypesCrypto), - b'cast5-cfb': (16, 8, CtypesCrypto), - b'des-cfb': (8, 8, CtypesCrypto), - b'idea-cfb': (16, 8, CtypesCrypto), - b'rc2-cfb': (16, 8, CtypesCrypto), - b'rc4': (16, 0, CtypesCrypto), - b'seed-cfb': (16, 16, CtypesCrypto), + b'aes-128-cfb': (16, 16, OpenSSLCrypto), + b'aes-192-cfb': (24, 16, OpenSSLCrypto), + b'aes-256-cfb': (32, 16, OpenSSLCrypto), + b'aes-128-ofb': (16, 16, OpenSSLCrypto), + b'aes-192-ofb': (24, 16, OpenSSLCrypto), + b'aes-256-ofb': (32, 16, OpenSSLCrypto), + b'aes-128-ctr': (16, 16, OpenSSLCrypto), + b'aes-192-ctr': (24, 16, OpenSSLCrypto), + b'aes-256-ctr': (32, 16, OpenSSLCrypto), + b'aes-128-cfb8': (16, 16, OpenSSLCrypto), + b'aes-192-cfb8': (24, 16, OpenSSLCrypto), + b'aes-256-cfb8': (32, 16, OpenSSLCrypto), + b'aes-128-cfb1': (16, 16, OpenSSLCrypto), + b'aes-192-cfb1': (24, 16, OpenSSLCrypto), + b'aes-256-cfb1': (32, 16, OpenSSLCrypto), + b'bf-cfb': (16, 8, OpenSSLCrypto), + b'camellia-128-cfb': (16, 16, OpenSSLCrypto), + b'camellia-192-cfb': (24, 16, OpenSSLCrypto), + b'camellia-256-cfb': (32, 16, OpenSSLCrypto), + b'cast5-cfb': (16, 8, OpenSSLCrypto), + b'des-cfb': (8, 8, OpenSSLCrypto), + b'idea-cfb': (16, 8, OpenSSLCrypto), + b'rc2-cfb': (16, 8, OpenSSLCrypto), + b'rc4': (16, 0, OpenSSLCrypto), + b'seed-cfb': (16, 16, OpenSSLCrypto), } def run_method(method): - cipher = CtypesCrypto(method, b'k' * 32, b'i' * 16, 1) - decipher = CtypesCrypto(method, b'k' * 32, b'i' * 16, 0) + cipher = OpenSSLCrypto(method, b'k' * 32, b'i' * 16, 1) + decipher = OpenSSLCrypto(method, b'k' * 32, b'i' * 16, 0) util.run_cipher(cipher, decipher) diff --git a/shadowsocks/crypto/rc4_md5.py b/shadowsocks/crypto/rc4_md5.py index aa22b16..728412d 100644 --- a/shadowsocks/crypto/rc4_md5.py +++ b/shadowsocks/crypto/rc4_md5.py @@ -37,8 +37,8 @@ def create_cipher(alg, key, iv, op, key_as_bytes=0, d=None, salt=None, rc4_key = md5.digest() try: - from shadowsocks.crypto import ctypes_openssl - return ctypes_openssl.CtypesCrypto(b'rc4', rc4_key, b'', op) + from shadowsocks.crypto import openssl + return openssl.OpenSSLCrypto(b'rc4', rc4_key, b'', op) except Exception: import M2Crypto.EVP return M2Crypto.EVP.Cipher(b'rc4', rc4_key, b'', op, diff --git a/shadowsocks/crypto/salsa20_ctr.py b/shadowsocks/crypto/salsa20_ctr.py deleted file mode 100644 index 0ea13b8..0000000 --- a/shadowsocks/crypto/salsa20_ctr.py +++ /dev/null @@ -1,140 +0,0 @@ -#!/usr/bin/env python - -# Copyright (c) 2014 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. - -from __future__ import absolute_import, division, print_function, \ - with_statement - -import struct -import logging -import sys - -slow_xor = False -imported = False - -salsa20 = None -numpy = None - -BLOCK_SIZE = 16384 - - -def run_imports(): - global imported, slow_xor, salsa20, numpy - if not imported: - imported = True - try: - numpy = __import__('numpy') - except ImportError: - logging.error('can not import numpy, using SLOW XOR') - logging.error('please install numpy if you use salsa20') - slow_xor = True - try: - salsa20 = __import__('salsa20') - except ImportError: - logging.error('you have to install salsa20 before you use salsa20') - sys.exit(1) - - -def numpy_xor(a, b): - if slow_xor: - return py_xor_str(a, b) - dtype = numpy.byte - if len(a) % 4 == 0: - dtype = numpy.uint32 - elif len(a) % 2 == 0: - dtype = numpy.uint16 - - ab = numpy.frombuffer(a, dtype=dtype) - bb = numpy.frombuffer(b, dtype=dtype) - c = numpy.bitwise_xor(ab, bb) - r = c.tostring() - return r - - -def py_xor_str(a, b): - c = [] - if bytes == str: - for i in range(0, len(a)): - c.append(chr(ord(a[i]) ^ ord(b[i]))) - return ''.join(c) - else: - for i in range(0, len(a)): - c.append(a[i] ^ b[i]) - return bytes(c) - - -class Salsa20Cipher(object): - """a salsa20 CTR implemetation, provides m2crypto like cipher API""" - - def __init__(self, alg, key, iv, op, key_as_bytes=0, d=None, salt=None, - i=1, padding=1): - run_imports() - if alg != b'salsa20-ctr': - raise Exception('unknown algorithm') - self._key = key - self._nonce = struct.unpack('= BLOCK_SIZE: - self._next_stream() - self._pos = 0 - if not data: - break - return b''.join(results) - - -ciphers = { - b'salsa20-ctr': (32, 8, Salsa20Cipher), -} - - -def test(): - from shadowsocks.crypto import util - - cipher = Salsa20Cipher(b'salsa20-ctr', b'k' * 32, b'i' * 8, 1) - decipher = Salsa20Cipher(b'salsa20-ctr', b'k' * 32, b'i' * 8, 1) - - util.run_cipher(cipher, decipher) - - -if __name__ == '__main__': - test() diff --git a/shadowsocks/crypto/ctypes_libsodium.py b/shadowsocks/crypto/sodium.py similarity index 91% rename from shadowsocks/crypto/ctypes_libsodium.py rename to shadowsocks/crypto/sodium.py index 7e9f6a4..74fbb33 100644 --- a/shadowsocks/crypto/ctypes_libsodium.py +++ b/shadowsocks/crypto/sodium.py @@ -62,7 +62,7 @@ def load_libsodium(): loaded = True -class Salsa20Crypto(object): +class SodiumCrypto(object): def __init__(self, cipher_name, key, iv, op): if not loaded: load_libsodium() @@ -101,22 +101,22 @@ class Salsa20Crypto(object): ciphers = { - b'salsa20': (32, 8, Salsa20Crypto), - b'chacha20': (32, 8, Salsa20Crypto), + b'salsa20': (32, 8, SodiumCrypto), + b'chacha20': (32, 8, SodiumCrypto), } def test_salsa20(): - cipher = Salsa20Crypto(b'salsa20', b'k' * 32, b'i' * 16, 1) - decipher = Salsa20Crypto(b'salsa20', b'k' * 32, b'i' * 16, 0) + cipher = SodiumCrypto(b'salsa20', b'k' * 32, b'i' * 16, 1) + decipher = SodiumCrypto(b'salsa20', b'k' * 32, b'i' * 16, 0) util.run_cipher(cipher, decipher) def test_chacha20(): - cipher = Salsa20Crypto(b'chacha20', b'k' * 32, b'i' * 16, 1) - decipher = Salsa20Crypto(b'chacha20', b'k' * 32, b'i' * 16, 0) + cipher = SodiumCrypto(b'chacha20', b'k' * 32, b'i' * 16, 1) + decipher = SodiumCrypto(b'chacha20', b'k' * 32, b'i' * 16, 0) util.run_cipher(cipher, decipher) diff --git a/shadowsocks/encrypt.py b/shadowsocks/encrypt.py index ba02101..8b6b6d4 100644 --- a/shadowsocks/encrypt.py +++ b/shadowsocks/encrypt.py @@ -28,16 +28,14 @@ import sys import hashlib import logging -from shadowsocks.crypto import m2, rc4_md5, salsa20_ctr,\ - ctypes_openssl, ctypes_libsodium, table +from shadowsocks.crypto import m2, rc4_md5, openssl, sodium, table method_supported = {} method_supported.update(rc4_md5.ciphers) -method_supported.update(salsa20_ctr.ciphers) -method_supported.update(ctypes_openssl.ciphers) -method_supported.update(ctypes_libsodium.ciphers) -# let M2Crypto override ctypes_openssl +method_supported.update(openssl.ciphers) +method_supported.update(sodium.ciphers) +# let M2Crypto override openssl method_supported.update(m2.ciphers) method_supported.update(table.ciphers) From a4b0ea5b8fb80217c438219eb6522b7aa17db865 Mon Sep 17 00:00:00 2001 From: clowwindy Date: Mon, 12 Jan 2015 14:08:21 +0800 Subject: [PATCH 08/20] fix find_library --- shadowsocks/crypto/util.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/shadowsocks/crypto/util.py b/shadowsocks/crypto/util.py index 68cfabd..c8cbab5 100644 --- a/shadowsocks/crypto/util.py +++ b/shadowsocks/crypto/util.py @@ -32,7 +32,7 @@ def find_library(possible_lib_names, search_symbol, library_name): paths = [] - if type(possible_lib_names) is not list: + if type(possible_lib_names) not in (list, tuple): possible_lib_names = [possible_lib_names] for name in possible_lib_names: @@ -105,10 +105,11 @@ def run_cipher(cipher, decipher): def test_find_library(): assert find_library('c', 'strcpy', 'libc') is not None assert find_library(['c'], 'strcpy', 'libc') is not None + assert find_library(('c',), 'strcpy', 'libc') is not None assert find_library('crypto', 'EVP_CipherUpdate', 'libcrypto') is not None assert find_library('notexist', 'strcpy', 'libnotexist') is None assert find_library('c', 'symbol_not_exist', 'c') is None - assert find_library(['notexist', 'c', 'crypto'], + assert find_library(('notexist', 'c', 'crypto'), 'EVP_CipherUpdate', 'libc') is not None From 80b8bd70147a28b87456c2326af366226877e205 Mon Sep 17 00:00:00 2001 From: clowwindy Date: Mon, 12 Jan 2015 14:11:33 +0800 Subject: [PATCH 09/20] remove M2Crypto completely --- .travis.yml | 4 +- shadowsocks/crypto/m2.py | 119 ---------------------------------- shadowsocks/crypto/rc4_md5.py | 11 +--- shadowsocks/encrypt.py | 10 +-- 4 files changed, 6 insertions(+), 138 deletions(-) delete mode 100644 shadowsocks/crypto/m2.py diff --git a/.travis.yml b/.travis.yml index 4fbe78c..7a222ea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,10 +9,10 @@ cache: - dante-1.4.0 before_install: - sudo apt-get update -qq - - sudo apt-get install -qq build-essential libssl-dev swig python-m2crypto python-numpy dnsutils iproute nginx bc + - sudo apt-get install -qq build-essential dnsutils iproute nginx bc - sudo dd if=/dev/urandom of=/usr/share/nginx/www/file bs=1M count=10 - sudo service nginx restart - - pip install m2crypto salsa20 pep8 pyflakes nose coverage + - pip install pep8 pyflakes nose coverage - sudo tests/socksify/install.sh - sudo tests/libsodium/install.sh - sudo tests/setup_tc.sh diff --git a/shadowsocks/crypto/m2.py b/shadowsocks/crypto/m2.py deleted file mode 100644 index 5ad48a8..0000000 --- a/shadowsocks/crypto/m2.py +++ /dev/null @@ -1,119 +0,0 @@ -#!/usr/bin/env python - -# Copyright (c) 2014 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. - -from __future__ import absolute_import, division, print_function, \ - with_statement - -import sys -import logging - -__all__ = ['ciphers'] - -has_m2 = True -try: - __import__('M2Crypto') -except ImportError: - has_m2 = False -if bytes != str: - has_m2 = False - - -def create_cipher(alg, key, iv, op, key_as_bytes=0, d=None, salt=None, i=1, - padding=1): - - import M2Crypto.EVP - return M2Crypto.EVP.Cipher(alg.replace('-', '_'), key, iv, op, - key_as_bytes=0, d='md5', salt=None, i=1, - padding=1) - - -def err(alg, key, iv, op, key_as_bytes=0, d=None, salt=None, i=1, padding=1): - logging.error(('M2Crypto is required to use %s, please run' - ' `apt-get install python-m2crypto`') % alg) - sys.exit(1) - - -if has_m2: - ciphers = { - b'aes-128-cfb': (16, 16, create_cipher), - b'aes-192-cfb': (24, 16, create_cipher), - b'aes-256-cfb': (32, 16, create_cipher), - b'bf-cfb': (16, 8, create_cipher), - b'camellia-128-cfb': (16, 16, create_cipher), - b'camellia-192-cfb': (24, 16, create_cipher), - b'camellia-256-cfb': (32, 16, create_cipher), - b'cast5-cfb': (16, 8, create_cipher), - b'des-cfb': (8, 8, create_cipher), - b'idea-cfb': (16, 8, create_cipher), - b'rc2-cfb': (16, 8, create_cipher), - b'rc4': (16, 0, create_cipher), - b'seed-cfb': (16, 16, create_cipher), - } -else: - ciphers = {} - - -def run_method(method): - from shadowsocks.crypto import util - - cipher = create_cipher(method, b'k' * 32, b'i' * 16, 1) - decipher = create_cipher(method, b'k' * 32, b'i' * 16, 0) - - util.run_cipher(cipher, decipher) - - -def check_env(): - # skip this test on pypy and Python 3 - try: - import __pypy__ - del __pypy__ - from nose.plugins.skip import SkipTest - raise SkipTest - except ImportError: - pass - if bytes != str: - from nose.plugins.skip import SkipTest - raise SkipTest - - -def test_aes_128_cfb(): - check_env() - run_method(b'aes-128-cfb') - - -def test_aes_256_cfb(): - check_env() - run_method(b'aes-256-cfb') - - -def test_bf_cfb(): - check_env() - run_method(b'bf-cfb') - - -def test_rc4(): - check_env() - run_method(b'rc4') - - -if __name__ == '__main__': - test_aes_128_cfb() diff --git a/shadowsocks/crypto/rc4_md5.py b/shadowsocks/crypto/rc4_md5.py index 728412d..33d481d 100644 --- a/shadowsocks/crypto/rc4_md5.py +++ b/shadowsocks/crypto/rc4_md5.py @@ -25,6 +25,7 @@ from __future__ import absolute_import, division, print_function, \ import hashlib +from shadowsocks.crypto import openssl __all__ = ['ciphers'] @@ -35,15 +36,7 @@ def create_cipher(alg, key, iv, op, key_as_bytes=0, d=None, salt=None, md5.update(key) md5.update(iv) rc4_key = md5.digest() - - try: - from shadowsocks.crypto import openssl - return openssl.OpenSSLCrypto(b'rc4', rc4_key, b'', op) - except Exception: - import M2Crypto.EVP - return M2Crypto.EVP.Cipher(b'rc4', rc4_key, b'', op, - key_as_bytes=0, d='md5', salt=None, i=1, - padding=1) + return openssl.OpenSSLCrypto(b'rc4', rc4_key, b'', op) ciphers = { diff --git a/shadowsocks/encrypt.py b/shadowsocks/encrypt.py index 8b6b6d4..3dd9264 100644 --- a/shadowsocks/encrypt.py +++ b/shadowsocks/encrypt.py @@ -28,24 +28,18 @@ import sys import hashlib import logging -from shadowsocks.crypto import m2, rc4_md5, openssl, sodium, table +from shadowsocks.crypto import rc4_md5, openssl, sodium, table method_supported = {} method_supported.update(rc4_md5.ciphers) method_supported.update(openssl.ciphers) method_supported.update(sodium.ciphers) -# let M2Crypto override openssl -method_supported.update(m2.ciphers) method_supported.update(table.ciphers) def random_string(length): - try: - import M2Crypto.Rand - return M2Crypto.Rand.rand_bytes(length) - except ImportError: - return os.urandom(length) + return os.urandom(length) cached_keys = {} From f29bfb0cc772c755f0a9648c79e741b4c0dda919 Mon Sep 17 00:00:00 2001 From: clowwindy Date: Mon, 12 Jan 2015 14:15:41 +0800 Subject: [PATCH 10/20] remove salsa20-ctr test --- .jenkins.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/.jenkins.sh b/.jenkins.sh index 4c85f1c..7aa3257 100755 --- a/.jenkins.sh +++ b/.jenkins.sh @@ -38,7 +38,6 @@ run_test python tests/test.py --with-coverage -c tests/aes-cfb8.json run_test python tests/test.py --with-coverage -c tests/rc4-md5.json run_test python tests/test.py --with-coverage -c tests/salsa20.json run_test python tests/test.py --with-coverage -c tests/chacha20.json -run_test python tests/test.py --with-coverage -c tests/salsa20-ctr.json run_test python tests/test.py --with-coverage -c tests/table.json run_test python tests/test.py --with-coverage -c tests/server-multi-ports.json run_test python tests/test.py --with-coverage -s tests/server-multi-passwd.json -c tests/server-multi-passwd-client-side.json From eb94bd1cc34eb4b228e675011236d090329d5a7f Mon Sep 17 00:00:00 2001 From: clowwindy Date: Mon, 12 Jan 2015 22:30:03 +0800 Subject: [PATCH 11/20] support forbidden iplist --- shadowsocks/tcprelay.py | 9 +++++++++ shadowsocks/utils.py | 6 +++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/shadowsocks/tcprelay.py b/shadowsocks/tcprelay.py index 79bd1a5..6afcad4 100644 --- a/shadowsocks/tcprelay.py +++ b/shadowsocks/tcprelay.py @@ -123,6 +123,10 @@ class TCPRelayHandler(object): self._downstream_status = WAIT_STATUS_INIT self._client_address = local_sock.getpeername()[:2] self._remote_address = None + if 'forbidden_ip' in self._config: + self._forbidden_iplist = self._config['forbidden_ip'] + else: + self._forbidden_iplist = None if is_local: self._chosen_server = self._get_a_server() fd_to_handlers[local_sock.fileno()] = self @@ -331,6 +335,10 @@ class TCPRelayHandler(object): if len(addrs) == 0: raise Exception("getaddrinfo failed for %s:%d" % (ip, port)) af, socktype, proto, canonname, sa = addrs[0] + if self._forbidden_iplist: + if common.to_str(sa[0]) in self._forbidden_iplist: + raise Exception('IP %s is in forbidden list, reject' % + common.to_str(sa[0])) remote_sock = socket.socket(af, socktype, proto) self._remote_sock = remote_sock self._fd_to_handlers[remote_sock.fileno()] = self @@ -346,6 +354,7 @@ class TCPRelayHandler(object): if result: ip = result[1] if ip: + try: self._stage = STAGE_CONNECTING remote_addr = ip diff --git a/shadowsocks/utils.py b/shadowsocks/utils.py index 0247d0f..a51c965 100644 --- a/shadowsocks/utils.py +++ b/shadowsocks/utils.py @@ -100,7 +100,8 @@ def get_config(is_local): longopts = ['help', 'fast-open', 'pid-file=', 'log-file='] else: shortopts = 'hd:s:p:k:m:c:t:vq' - longopts = ['help', 'fast-open', 'pid-file=', 'log-file=', 'workers='] + longopts = ['help', 'fast-open', 'pid-file=', 'log-file=', 'workers=', + 'forbidden-ip='] try: config_path = find_config() optlist, args = getopt.getopt(sys.argv[1:], shortopts, longopts) @@ -146,6 +147,8 @@ def get_config(is_local): config['fast_open'] = True elif key == '--workers': config['workers'] = int(value) + elif key == '--forbidden-ip': + config['forbidden_ip'] = to_str(value).split(',') elif key in ('-h', '--help'): if is_local: print_local_help() @@ -286,6 +289,7 @@ Proxy options: -t TIMEOUT timeout in seconds, default: 300 --fast-open use TCP_FASTOPEN, requires Linux 3.7+ --workers WORKERS number of workers, available on Unix/Linux + --forbidden-ip IPLIST comma seperated IP list forbidden to connect General options: -d start/stop/restart daemon mode From 4312eb9e58f9438b76870101169be5e065695c6c Mon Sep 17 00:00:00 2001 From: clowwindy Date: Mon, 12 Jan 2015 23:02:59 +0800 Subject: [PATCH 12/20] add forbidden support for UDP and add tests --- .jenkins.sh | 1 + shadowsocks/tcprelay.py | 4 ++-- shadowsocks/udprelay.py | 11 +++++++++++ tests/test.py | 28 ++++++++++++++++++++-------- 4 files changed, 34 insertions(+), 10 deletions(-) diff --git a/.jenkins.sh b/.jenkins.sh index 7aa3257..bb58e04 100755 --- a/.jenkins.sh +++ b/.jenkins.sh @@ -45,6 +45,7 @@ run_test python tests/test.py --with-coverage -c tests/workers.json run_test python tests/test.py --with-coverage -s tests/ipv6.json -c tests/ipv6-client-side.json run_test python tests/test.py --with-coverage -b "-m rc4-md5 -k testrc4 -s 127.0.0.1 -p 8388 -q" -a "-m rc4-md5 -k testrc4 -s 127.0.0.1 -p 8388 -l 1081 -vv" run_test python tests/test.py --with-coverage -b "-m aes-256-cfb -k testrc4 -s 127.0.0.1 -p 8388 --workers 1" -a "-m aes-256-cfb -k testrc4 -s 127.0.0.1 -p 8388 -l 1081 -t 30 -qq -b 127.0.0.1" +run_test python tests/test.py --with-coverage --should-fail --url="http://127.0.0.1/" -b "-m aes-256-cfb -k testrc4 -s 127.0.0.1 -p 8388 --forbidden-ip=127.0.0.1,::1,8.8.8.8" -a "-m aes-256-cfb -k testrc4 -s 127.0.0.1 -p 8388 -l 1081 -t 30 -b 127.0.0.1" if [ -f /proc/sys/net/ipv4/tcp_fastopen ] ; then if [ 3 -eq `cat /proc/sys/net/ipv4/tcp_fastopen` ] ; then diff --git a/shadowsocks/tcprelay.py b/shadowsocks/tcprelay.py index 6afcad4..c148208 100644 --- a/shadowsocks/tcprelay.py +++ b/shadowsocks/tcprelay.py @@ -123,8 +123,8 @@ class TCPRelayHandler(object): self._downstream_status = WAIT_STATUS_INIT self._client_address = local_sock.getpeername()[:2] self._remote_address = None - if 'forbidden_ip' in self._config: - self._forbidden_iplist = self._config['forbidden_ip'] + if 'forbidden_ip' in config: + self._forbidden_iplist = config['forbidden_ip'] else: self._forbidden_iplist = None if is_local: diff --git a/shadowsocks/udprelay.py b/shadowsocks/udprelay.py index 2b8b12f..ccc0413 100644 --- a/shadowsocks/udprelay.py +++ b/shadowsocks/udprelay.py @@ -112,6 +112,11 @@ class UDPRelay(object): self._closed = False self._last_time = time.time() self._sockets = set() + print(config) + if 'forbidden_ip' in config: + self._forbidden_iplist = config['forbidden_ip'] + else: + self._forbidden_iplist = None addrs = socket.getaddrinfo(self._listen_addr, self._listen_port, 0, socket.SOCK_DGRAM, socket.SOL_UDP) @@ -178,6 +183,12 @@ class UDPRelay(object): socket.SOCK_DGRAM, socket.SOL_UDP) if addrs: af, socktype, proto, canonname, sa = addrs[0] + if self._forbidden_iplist: + if common.to_str(sa[0]) in self._forbidden_iplist: + logging.warn('IP %s is in forbidden list, drop' % + common.to_str(sa[0])) + # drop + return client = socket.socket(af, socktype, proto) client.setblocking(False) self._cache[key] = client diff --git a/tests/test.py b/tests/test.py index 0b63a18..f160366 100755 --- a/tests/test.py +++ b/tests/test.py @@ -40,6 +40,9 @@ parser.add_argument('-s', '--server-conf', type=str, default=None) parser.add_argument('-a', '--client-args', type=str, default=None) parser.add_argument('-b', '--server-args', type=str, default=None) parser.add_argument('--with-coverage', action='store_true', default=None) +parser.add_argument('--should-fail', action='store_true', default=None) +parser.add_argument('--url', type=str, default='http://www.example.com/') +parser.add_argument('--dns', type=str, default='8.8.8.8') config = parser.parse_args() @@ -87,6 +90,7 @@ try: for fd in r: line = fd.readline() + sys.stderr.write(line) if not line: if stage == 2 and fd == p3.stdout: stage = 3 @@ -94,7 +98,6 @@ try: stage = 5 if bytes != str: line = str(line, 'utf8') - sys.stdout.write(line) if line.find('starting local') >= 0: local_ready = True if line.find('starting server') >= 0: @@ -103,7 +106,7 @@ try: if stage == 1: time.sleep(2) - p3 = Popen(['curl', 'http://www.example.com/', '-v', '-L', + p3 = Popen(['curl', config.url, '-v', '-L', '--socks5-hostname', '127.0.0.1:1081', '-m', '15', '--connect-timeout', '10'], stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True) @@ -118,9 +121,13 @@ try: fdset.remove(p3.stdout) fdset.remove(p3.stderr) r = p3.wait() - if r != 0: - sys.exit(1) - p4 = Popen(['socksify', 'dig', '@8.8.8.8', 'www.google.com'], + if config.should_fail: + if r == 0: + sys.exit(1) + else: + if r != 0: + sys.exit(1) + p4 = Popen(['socksify', 'dig', '@%s' % config.dns, 'www.google.com'], stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True) if p4 is not None: fdset.append(p4.stdout) @@ -131,9 +138,14 @@ try: if stage == 5: r = p4.wait() - if r != 0: - sys.exit(1) - print('test passed') + if config.should_fail: + if r == 0: + sys.exit(1) + print('test passed (expecting failure)') + else: + if r != 0: + sys.exit(1) + print('test passed') break finally: for p in [p1, p2]: From cc36de5a2f694b6eab020b3649fc9927f86acfd9 Mon Sep 17 00:00:00 2001 From: clowwindy Date: Mon, 12 Jan 2015 23:05:19 +0800 Subject: [PATCH 13/20] fix pep8 --- tests/test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test.py b/tests/test.py index f160366..d213780 100755 --- a/tests/test.py +++ b/tests/test.py @@ -127,7 +127,8 @@ try: else: if r != 0: sys.exit(1) - p4 = Popen(['socksify', 'dig', '@%s' % config.dns, 'www.google.com'], + p4 = Popen(['socksify', 'dig', '@%s' % config.dns, + 'www.google.com'], stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True) if p4 is not None: fdset.append(p4.stdout) From f7316c004738e95e7f64e0030dd5a31f855d2f56 Mon Sep 17 00:00:00 2001 From: clowwindy Date: Mon, 12 Jan 2015 23:08:27 +0800 Subject: [PATCH 14/20] change logging level for UDP warning --- shadowsocks/udprelay.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shadowsocks/udprelay.py b/shadowsocks/udprelay.py index ccc0413..1bdd153 100644 --- a/shadowsocks/udprelay.py +++ b/shadowsocks/udprelay.py @@ -185,8 +185,8 @@ class UDPRelay(object): af, socktype, proto, canonname, sa = addrs[0] if self._forbidden_iplist: if common.to_str(sa[0]) in self._forbidden_iplist: - logging.warn('IP %s is in forbidden list, drop' % - common.to_str(sa[0])) + logging.debug('IP %s is in forbidden list, drop' % + common.to_str(sa[0])) # drop return client = socket.socket(af, socktype, proto) From 9fe2f4ef16c9951289fb19c416c48e6463763c90 Mon Sep 17 00:00:00 2001 From: clowwindy Date: Mon, 12 Jan 2015 23:11:23 +0800 Subject: [PATCH 15/20] bump --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 2bfc2c5..725ec71 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ with codecs.open('README.rst', encoding='utf-8') as f: setup( name="shadowsocks", - version="2.6.2", + version="2.6.3", license='MIT', description="A fast tunnel proxy that help you get through firewalls", author='clowwindy', From 32a6b8fd7a0ca7999e7c17d2f1b1b9692c342f6d Mon Sep 17 00:00:00 2001 From: clowwindy Date: Mon, 12 Jan 2015 23:13:29 +0800 Subject: [PATCH 16/20] update CHANGES --- CHANGES | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGES b/CHANGES index 62aec8a..b5c9062 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,8 @@ +2.6.3 2015-01-03 +- Support --forbidden-ip to ban some IP, i.e. localhost +- Search OpenSSL and libsodium harder +- Now works on OpenWRT + 2.6.2 2015-01-03 - Log client IP From 5e476843ec8fc708033170a68a9c3bc425ecfb95 Mon Sep 17 00:00:00 2001 From: clowwindy Date: Mon, 12 Jan 2015 23:19:24 +0800 Subject: [PATCH 17/20] fix python3 --- tests/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test.py b/tests/test.py index d213780..933027b 100755 --- a/tests/test.py +++ b/tests/test.py @@ -90,7 +90,6 @@ try: for fd in r: line = fd.readline() - sys.stderr.write(line) if not line: if stage == 2 and fd == p3.stdout: stage = 3 @@ -98,6 +97,7 @@ try: stage = 5 if bytes != str: line = str(line, 'utf8') + sys.stderr.write(line) if line.find('starting local') >= 0: local_ready = True if line.find('starting server') >= 0: From 53a7e4d0e4a8909a9825ad956a0a4c7265561dad Mon Sep 17 00:00:00 2001 From: clowwindy Date: Mon, 12 Jan 2015 23:21:16 +0800 Subject: [PATCH 18/20] remove print --- shadowsocks/udprelay.py | 1 - 1 file changed, 1 deletion(-) diff --git a/shadowsocks/udprelay.py b/shadowsocks/udprelay.py index 1bdd153..ff6391c 100644 --- a/shadowsocks/udprelay.py +++ b/shadowsocks/udprelay.py @@ -112,7 +112,6 @@ class UDPRelay(object): self._closed = False self._last_time = time.time() self._sockets = set() - print(config) if 'forbidden_ip' in config: self._forbidden_iplist = config['forbidden_ip'] else: From 5c05a74727ee22a06859c5f50ed0af88ad65cdd4 Mon Sep 17 00:00:00 2001 From: clowwindy Date: Tue, 13 Jan 2015 00:42:27 +0800 Subject: [PATCH 19/20] fix a potential name conflict --- shadowsocks/crypto/util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shadowsocks/crypto/util.py b/shadowsocks/crypto/util.py index c8cbab5..5425908 100644 --- a/shadowsocks/crypto/util.py +++ b/shadowsocks/crypto/util.py @@ -27,7 +27,7 @@ import logging def find_library(possible_lib_names, search_symbol, library_name): - from ctypes.util import find_library + import ctypes.util from ctypes import CDLL paths = [] @@ -36,7 +36,7 @@ def find_library(possible_lib_names, search_symbol, library_name): possible_lib_names = [possible_lib_names] for name in possible_lib_names: - path = find_library(name) + path = ctypes.util.find_library(name) if path: paths.append(path) From af6c6f3f238fe866e0d9a0b21f49d0edfd97852b Mon Sep 17 00:00:00 2001 From: clowwindy Date: Wed, 14 Jan 2015 12:59:43 +0800 Subject: [PATCH 20/20] also search lib* for library names --- shadowsocks/crypto/util.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/shadowsocks/crypto/util.py b/shadowsocks/crypto/util.py index 5425908..6d7d222 100644 --- a/shadowsocks/crypto/util.py +++ b/shadowsocks/crypto/util.py @@ -35,7 +35,12 @@ def find_library(possible_lib_names, search_symbol, library_name): if type(possible_lib_names) not in (list, tuple): possible_lib_names = [possible_lib_names] - for name in possible_lib_names: + lib_names = [] + for lib_name in possible_lib_names: + lib_names.append(lib_name) + lib_names.append('lib' + lib_name) + + for name in lib_names: path = ctypes.util.find_library(name) if path: paths.append(path) @@ -46,7 +51,7 @@ def find_library(possible_lib_names, search_symbol, library_name): # tools underlying find_library on linux. import glob - for name in possible_lib_names: + for name in lib_names: patterns = [ '/usr/local/lib*/lib%s.*' % name, '/usr/lib*/lib%s.*' % name, @@ -106,10 +111,11 @@ def test_find_library(): assert find_library('c', 'strcpy', 'libc') is not None assert find_library(['c'], 'strcpy', 'libc') is not None assert find_library(('c',), 'strcpy', 'libc') is not None - assert find_library('crypto', 'EVP_CipherUpdate', 'libcrypto') is not None + assert find_library(('crypto', 'eay32'), 'EVP_CipherUpdate', + 'libcrypto') is not None assert find_library('notexist', 'strcpy', 'libnotexist') is None assert find_library('c', 'symbol_not_exist', 'c') is None - assert find_library(('notexist', 'c', 'crypto'), + assert find_library(('notexist', 'c', 'crypto', 'eay32'), 'EVP_CipherUpdate', 'libc') is not None