python 3 support; not stable yet
This commit is contained in:
parent
0814888ba5
commit
2a53b67c65
17 changed files with 204 additions and 115 deletions
|
@ -1 +1,24 @@
|
|||
#!/usr/bin/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
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
# 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 time
|
||||
import os
|
||||
import socket
|
||||
|
@ -33,7 +36,7 @@ from shadowsocks import common, lru_cache, eventloop
|
|||
|
||||
CACHE_SWEEP_INTERVAL = 30
|
||||
|
||||
VALID_HOSTNAME = re.compile(r"(?!-)[A-Z\d-]{1,63}(?<!-)$", re.IGNORECASE)
|
||||
VALID_HOSTNAME = re.compile(br"(?!-)[A-Z\d-]{1,63}(?<!-)$", re.IGNORECASE)
|
||||
|
||||
common.patch_socket()
|
||||
|
||||
|
@ -77,17 +80,17 @@ QCLASS_IN = 1
|
|||
|
||||
|
||||
def build_address(address):
|
||||
address = address.strip('.')
|
||||
labels = address.split('.')
|
||||
address = address.strip(b'.')
|
||||
labels = address.split(b'.')
|
||||
results = []
|
||||
for label in labels:
|
||||
l = len(label)
|
||||
if l > 63:
|
||||
return None
|
||||
results.append(chr(l))
|
||||
results.append(common.chr(l))
|
||||
results.append(label)
|
||||
results.append('\0')
|
||||
return ''.join(results)
|
||||
results.append(b'\0')
|
||||
return b''.join(results)
|
||||
|
||||
|
||||
def build_request(address, qtype, request_id):
|
||||
|
@ -111,7 +114,7 @@ def parse_ip(addrtype, data, length, offset):
|
|||
def parse_name(data, offset):
|
||||
p = offset
|
||||
labels = []
|
||||
l = ord(data[p])
|
||||
l = common.ord(data[p])
|
||||
while l > 0:
|
||||
if (l & (128 + 64)) == (128 + 64):
|
||||
# pointer
|
||||
|
@ -121,12 +124,12 @@ def parse_name(data, offset):
|
|||
labels.append(r[1])
|
||||
p += 2
|
||||
# pointer is the end
|
||||
return p - offset, '.'.join(labels)
|
||||
return p - offset, b'.'.join(labels)
|
||||
else:
|
||||
labels.append(data[p + 1:p + 1 + l])
|
||||
p += 1 + l
|
||||
l = ord(data[p])
|
||||
return p - offset + 1, '.'.join(labels)
|
||||
l = common.ord(data[p])
|
||||
return p - offset + 1, b'.'.join(labels)
|
||||
|
||||
|
||||
# rfc1035
|
||||
|
@ -198,20 +201,20 @@ def parse_response(data):
|
|||
qds = []
|
||||
ans = []
|
||||
offset = 12
|
||||
for i in xrange(0, res_qdcount):
|
||||
for i in range(0, res_qdcount):
|
||||
l, r = parse_record(data, offset, True)
|
||||
offset += l
|
||||
if r:
|
||||
qds.append(r)
|
||||
for i in xrange(0, res_ancount):
|
||||
for i in range(0, res_ancount):
|
||||
l, r = parse_record(data, offset)
|
||||
offset += l
|
||||
if r:
|
||||
ans.append(r)
|
||||
for i in xrange(0, res_nscount):
|
||||
for i in range(0, res_nscount):
|
||||
l, r = parse_record(data, offset)
|
||||
offset += l
|
||||
for i in xrange(0, res_arcount):
|
||||
for i in range(0, res_arcount):
|
||||
l, r = parse_record(data, offset)
|
||||
offset += l
|
||||
response = DNSResponse()
|
||||
|
@ -232,6 +235,8 @@ def parse_response(data):
|
|||
def is_ip(address):
|
||||
for family in (socket.AF_INET, socket.AF_INET6):
|
||||
try:
|
||||
if type(address) != str:
|
||||
address = address.decode('utf8')
|
||||
socket.inet_pton(family, address)
|
||||
return family
|
||||
except (TypeError, ValueError, OSError, IOError):
|
||||
|
@ -242,9 +247,9 @@ def is_ip(address):
|
|||
def is_valid_hostname(hostname):
|
||||
if len(hostname) > 255:
|
||||
return False
|
||||
if hostname[-1] == ".":
|
||||
if hostname[-1] == b'.':
|
||||
hostname = hostname[:-1]
|
||||
return all(VALID_HOSTNAME.match(x) for x in hostname.split("."))
|
||||
return all(VALID_HOSTNAME.match(x) for x in hostname.split(b'.'))
|
||||
|
||||
|
||||
class DNSResponse(object):
|
||||
|
@ -287,11 +292,13 @@ class DNSResolver(object):
|
|||
for line in content:
|
||||
line = line.strip()
|
||||
if line:
|
||||
if line.startswith('nameserver'):
|
||||
if line.startswith(b'nameserver'):
|
||||
parts = line.split()
|
||||
if len(parts) >= 2:
|
||||
server = parts[1]
|
||||
if is_ip(server) == socket.AF_INET:
|
||||
if type(server) != str:
|
||||
server = server.decode('utf8')
|
||||
self._servers.append(server)
|
||||
except IOError:
|
||||
pass
|
||||
|
@ -310,7 +317,7 @@ class DNSResolver(object):
|
|||
if len(parts) >= 2:
|
||||
ip = parts[0]
|
||||
if is_ip(ip):
|
||||
for i in xrange(1, len(parts)):
|
||||
for i in range(1, len(parts)):
|
||||
hostname = parts[i]
|
||||
if hostname:
|
||||
self._hosts[hostname] = ip
|
||||
|
|
|
@ -21,16 +21,37 @@
|
|||
# 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 socket
|
||||
import struct
|
||||
import logging
|
||||
|
||||
|
||||
def compat_ord(s):
|
||||
if type(s) == int:
|
||||
return s
|
||||
return _ord(s)
|
||||
|
||||
|
||||
def compat_chr(d):
|
||||
if bytes == str:
|
||||
return _chr(d)
|
||||
return bytes([d])
|
||||
|
||||
|
||||
_ord = ord
|
||||
_chr = chr
|
||||
ord = compat_ord
|
||||
chr = compat_chr
|
||||
|
||||
|
||||
def inet_ntop(family, ipstr):
|
||||
if family == socket.AF_INET:
|
||||
return socket.inet_ntoa(ipstr)
|
||||
elif family == socket.AF_INET6:
|
||||
v6addr = ':'.join(('%02X%02X' % (ord(i), ord(j)))
|
||||
v6addr = b':'.join((b'%02X%02X' % (ord(i), ord(j)))
|
||||
for i, j in zip(ipstr[::2], ipstr[1::2]))
|
||||
return v6addr
|
||||
|
||||
|
@ -39,15 +60,15 @@ def inet_pton(family, addr):
|
|||
if family == socket.AF_INET:
|
||||
return socket.inet_aton(addr)
|
||||
elif family == socket.AF_INET6:
|
||||
if '.' in addr: # a v4 addr
|
||||
v4addr = addr[addr.rindex(':') + 1:]
|
||||
if b'.' in addr: # a v4 addr
|
||||
v4addr = addr[addr.rindex(b':') + 1:]
|
||||
v4addr = socket.inet_aton(v4addr)
|
||||
v4addr = map(lambda x: ('%02X' % ord(x)), v4addr)
|
||||
v4addr.insert(2, ':')
|
||||
newaddr = addr[:addr.rindex(':') + 1] + ''.join(v4addr)
|
||||
v4addr = map(lambda x: (b'%02X' % ord(x)), v4addr)
|
||||
v4addr.insert(2, b':')
|
||||
newaddr = addr[:addr.rindex(b':') + 1] + b''.join(v4addr)
|
||||
return inet_pton(family, newaddr)
|
||||
dbyts = [0] * 8 # 8 groups
|
||||
grps = addr.split(':')
|
||||
grps = addr.split(b':')
|
||||
for i, v in enumerate(grps):
|
||||
if v:
|
||||
dbyts[i] = int(v, 16)
|
||||
|
@ -58,7 +79,7 @@ def inet_pton(family, addr):
|
|||
else:
|
||||
break
|
||||
break
|
||||
return ''.join((chr(i // 256) + chr(i % 256)) for i in dbyts)
|
||||
return b''.join((chr(i // 256) + chr(i % 256)) for i in dbyts)
|
||||
else:
|
||||
raise RuntimeError("What family?")
|
||||
|
||||
|
|
|
@ -19,3 +19,6 @@
|
|||
# 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
|
||||
|
|
|
@ -20,6 +20,9 @@
|
|||
# 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
|
||||
from ctypes import CDLL, c_char_p, c_int, c_long, byref,\
|
||||
create_string_buffer, c_void_p
|
||||
|
@ -117,31 +120,31 @@ class CtypesCrypto(object):
|
|||
|
||||
|
||||
ciphers = {
|
||||
'aes-128-cfb': (16, 16, CtypesCrypto),
|
||||
'aes-192-cfb': (24, 16, CtypesCrypto),
|
||||
'aes-256-cfb': (32, 16, CtypesCrypto),
|
||||
'aes-128-ofb': (16, 16, CtypesCrypto),
|
||||
'aes-192-ofb': (24, 16, CtypesCrypto),
|
||||
'aes-256-ofb': (32, 16, CtypesCrypto),
|
||||
'aes-128-ctr': (16, 16, CtypesCrypto),
|
||||
'aes-192-ctr': (24, 16, CtypesCrypto),
|
||||
'aes-256-ctr': (32, 16, CtypesCrypto),
|
||||
'aes-128-cfb8': (16, 16, CtypesCrypto),
|
||||
'aes-192-cfb8': (24, 16, CtypesCrypto),
|
||||
'aes-256-cfb8': (32, 16, CtypesCrypto),
|
||||
'aes-128-cfb1': (16, 16, CtypesCrypto),
|
||||
'aes-192-cfb1': (24, 16, CtypesCrypto),
|
||||
'aes-256-cfb1': (32, 16, CtypesCrypto),
|
||||
'bf-cfb': (16, 8, CtypesCrypto),
|
||||
'camellia-128-cfb': (16, 16, CtypesCrypto),
|
||||
'camellia-192-cfb': (24, 16, CtypesCrypto),
|
||||
'camellia-256-cfb': (32, 16, CtypesCrypto),
|
||||
'cast5-cfb': (16, 8, CtypesCrypto),
|
||||
'des-cfb': (8, 8, CtypesCrypto),
|
||||
'idea-cfb': (16, 8, CtypesCrypto),
|
||||
'rc2-cfb': (16, 8, CtypesCrypto),
|
||||
'rc4': (16, 0, CtypesCrypto),
|
||||
'seed-cfb': (16, 16, CtypesCrypto),
|
||||
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),
|
||||
}
|
||||
|
||||
|
||||
|
@ -167,7 +170,7 @@ def test():
|
|||
# decipher = Salsa20Cipher('salsa20-ctr', 'k' * 32, 'i' * 8, 1)
|
||||
results = []
|
||||
pos = 0
|
||||
print 'salsa20 test start'
|
||||
print('salsa20 test start')
|
||||
start = time.time()
|
||||
while pos < len(plain):
|
||||
l = random.randint(100, 32768)
|
||||
|
@ -182,7 +185,7 @@ def test():
|
|||
results.append(decipher.update(c[pos:pos + l]))
|
||||
pos += l
|
||||
end = time.time()
|
||||
print 'speed: %d bytes/s' % (BLOCK_SIZE * rounds / (end - start))
|
||||
print('speed: %d bytes/s' % (BLOCK_SIZE * rounds / (end - start)))
|
||||
assert ''.join(results) == plain
|
||||
|
||||
|
||||
|
|
|
@ -20,6 +20,9 @@
|
|||
# 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
|
||||
|
||||
|
@ -49,19 +52,19 @@ def err(alg, key, iv, op, key_as_bytes=0, d=None, salt=None, i=1, padding=1):
|
|||
|
||||
if has_m2:
|
||||
ciphers = {
|
||||
'aes-128-cfb': (16, 16, create_cipher),
|
||||
'aes-192-cfb': (24, 16, create_cipher),
|
||||
'aes-256-cfb': (32, 16, create_cipher),
|
||||
'bf-cfb': (16, 8, create_cipher),
|
||||
'camellia-128-cfb': (16, 16, create_cipher),
|
||||
'camellia-192-cfb': (24, 16, create_cipher),
|
||||
'camellia-256-cfb': (32, 16, create_cipher),
|
||||
'cast5-cfb': (16, 8, create_cipher),
|
||||
'des-cfb': (8, 8, create_cipher),
|
||||
'idea-cfb': (16, 8, create_cipher),
|
||||
'rc2-cfb': (16, 8, create_cipher),
|
||||
'rc4': (16, 0, create_cipher),
|
||||
'seed-cfb': (16, 16, create_cipher),
|
||||
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 = {}
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
# 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 hashlib
|
||||
|
||||
|
@ -50,5 +52,5 @@ def create_cipher(alg, key, iv, op, key_as_bytes=0, d=None, salt=None,
|
|||
|
||||
|
||||
ciphers = {
|
||||
'rc4-md5': (16, 16, create_cipher),
|
||||
b'rc4-md5': (16, 16, create_cipher),
|
||||
}
|
||||
|
|
|
@ -20,6 +20,9 @@
|
|||
# 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 time
|
||||
import struct
|
||||
import logging
|
||||
|
@ -39,13 +42,13 @@ def run_imports():
|
|||
if not imported:
|
||||
imported = True
|
||||
try:
|
||||
__import__('numpy')
|
||||
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:
|
||||
__import__('salsa20')
|
||||
salsa20 = __import__('salsa20')
|
||||
except ImportError:
|
||||
logging.error('you have to install salsa20 before you use salsa20')
|
||||
sys.exit(1)
|
||||
|
@ -116,7 +119,7 @@ class Salsa20Cipher(object):
|
|||
|
||||
|
||||
ciphers = {
|
||||
'salsa20-ctr': (32, 8, Salsa20Cipher),
|
||||
b'salsa20-ctr': (32, 8, Salsa20Cipher),
|
||||
}
|
||||
|
||||
|
||||
|
@ -138,7 +141,7 @@ def test():
|
|||
decipher = Salsa20Cipher('salsa20-ctr', 'k' * 32, 'i' * 8, 1)
|
||||
results = []
|
||||
pos = 0
|
||||
print 'salsa20 test start'
|
||||
print('salsa20 test start')
|
||||
start = time.time()
|
||||
while pos < len(plain):
|
||||
l = random.randint(100, 32768)
|
||||
|
@ -153,7 +156,7 @@ def test():
|
|||
results.append(decipher.update(c[pos:pos + l]))
|
||||
pos += l
|
||||
end = time.time()
|
||||
print 'speed: %d bytes/s' % (BLOCK_SIZE * rounds / (end - start))
|
||||
print('speed: %d bytes/s' % (BLOCK_SIZE * rounds / (end - start)))
|
||||
assert ''.join(results) == plain
|
||||
|
||||
|
||||
|
|
|
@ -20,6 +20,9 @@
|
|||
# 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 os
|
||||
import sys
|
||||
import hashlib
|
||||
|
@ -74,23 +77,20 @@ def init_table(key, method=None):
|
|||
string.maketrans('', ''))
|
||||
cached_tables[key] = [encrypt_table, decrypt_table]
|
||||
else:
|
||||
try:
|
||||
Encryptor(key, method) # test if the settings if OK
|
||||
except Exception as e:
|
||||
logging.error(e)
|
||||
sys.exit(1)
|
||||
Encryptor(key, method) # test if the settings if OK
|
||||
|
||||
|
||||
def EVP_BytesToKey(password, key_len, iv_len):
|
||||
# equivalent to OpenSSL's EVP_BytesToKey() with count 1
|
||||
# so that we make the same key and iv as nodejs version
|
||||
password = str(password)
|
||||
if hasattr(password, 'encode'):
|
||||
password = password.encode('utf-8')
|
||||
r = cached_keys.get(password, None)
|
||||
if r:
|
||||
return r
|
||||
m = []
|
||||
i = 0
|
||||
while len(''.join(m)) < (key_len + iv_len):
|
||||
while len(b''.join(m)) < (key_len + iv_len):
|
||||
md5 = hashlib.md5()
|
||||
data = password
|
||||
if i > 0:
|
||||
|
@ -98,7 +98,7 @@ def EVP_BytesToKey(password, key_len, iv_len):
|
|||
md5.update(data)
|
||||
m.append(md5.digest())
|
||||
i += 1
|
||||
ms = ''.join(m)
|
||||
ms = b''.join(m)
|
||||
key = ms[:key_len]
|
||||
iv = ms[key_len:key_len + iv_len]
|
||||
cached_keys[password] = (key, iv)
|
||||
|
@ -107,13 +107,13 @@ def EVP_BytesToKey(password, key_len, iv_len):
|
|||
|
||||
class Encryptor(object):
|
||||
def __init__(self, key, method=None):
|
||||
if method == 'table':
|
||||
if method == b'table':
|
||||
method = None
|
||||
self.key = key
|
||||
self.method = method
|
||||
self.iv = None
|
||||
self.iv_sent = False
|
||||
self.cipher_iv = ''
|
||||
self.cipher_iv = b''
|
||||
self.decipher = None
|
||||
if method:
|
||||
self.cipher = self.get_cipher(key, method, 1, iv=random_string(32))
|
||||
|
@ -130,7 +130,8 @@ class Encryptor(object):
|
|||
return len(self.cipher_iv)
|
||||
|
||||
def get_cipher(self, password, method, op, iv=None):
|
||||
password = password.encode('utf-8')
|
||||
if hasattr(password, 'encode'):
|
||||
password = password.encode('utf-8')
|
||||
method = method.lower()
|
||||
m = self.get_cipher_param(method)
|
||||
if m:
|
||||
|
@ -176,7 +177,7 @@ class Encryptor(object):
|
|||
|
||||
|
||||
def encrypt_all(password, method, op, data):
|
||||
if method is not None and method.lower() == 'table':
|
||||
if method is not None and method.lower() == b'table':
|
||||
method = None
|
||||
if not method:
|
||||
[encrypt_table, decrypt_table] = init_table(password)
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
# from ssloop
|
||||
# https://github.com/clowwindy/ssloop
|
||||
|
||||
from __future__ import absolute_import, division, print_function, \
|
||||
with_statement
|
||||
|
||||
import os
|
||||
import socket
|
||||
|
@ -100,7 +102,7 @@ class KqueueLoop(object):
|
|||
results[fd] |= POLL_IN
|
||||
elif e.filter == select.KQ_FILTER_WRITE:
|
||||
results[fd] |= POLL_OUT
|
||||
return results.iteritems()
|
||||
return results.items()
|
||||
|
||||
def add_fd(self, fd, mode):
|
||||
self._fds[fd] = mode
|
||||
|
|
|
@ -21,11 +21,15 @@
|
|||
# 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 os
|
||||
import logging
|
||||
import signal
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../'))
|
||||
from shadowsocks import utils, encrypt, eventloop, tcprelay, udprelay, asyncdns
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import absolute_import, division, print_function, \
|
||||
with_statement
|
||||
|
||||
import collections
|
||||
import logging
|
||||
import time
|
||||
|
|
|
@ -21,11 +21,15 @@
|
|||
# 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 os
|
||||
import logging
|
||||
import signal
|
||||
|
||||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../'))
|
||||
from shadowsocks import utils, encrypt, eventloop, tcprelay, udprelay, asyncdns
|
||||
|
||||
|
||||
|
@ -66,13 +70,13 @@ def main():
|
|||
def run_server():
|
||||
def child_handler(signum, _):
|
||||
logging.warn('received SIGQUIT, doing graceful shutting down..')
|
||||
map(lambda s: s.close(next_tick=True), tcp_servers + udp_servers)
|
||||
list(map(lambda s: s.close(next_tick=True), tcp_servers + udp_servers))
|
||||
signal.signal(getattr(signal, 'SIGQUIT', signal.SIGTERM),
|
||||
child_handler)
|
||||
try:
|
||||
loop = eventloop.EventLoop()
|
||||
dns_resolver.add_to_loop(loop)
|
||||
map(lambda s: s.add_to_loop(loop), tcp_servers + udp_servers)
|
||||
list(map(lambda s: s.add_to_loop(loop), tcp_servers + udp_servers))
|
||||
loop.run()
|
||||
except (KeyboardInterrupt, IOError, OSError) as e:
|
||||
logging.error(e)
|
||||
|
@ -85,7 +89,7 @@ def main():
|
|||
if os.name == 'posix':
|
||||
children = []
|
||||
is_child = False
|
||||
for i in xrange(0, int(config['workers'])):
|
||||
for i in range(0, int(config['workers'])):
|
||||
r = os.fork()
|
||||
if r == 0:
|
||||
logging.info('worker started')
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
# 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 time
|
||||
import socket
|
||||
import errno
|
||||
|
@ -29,7 +32,7 @@ import logging
|
|||
import traceback
|
||||
import random
|
||||
|
||||
from shadowsocks import encrypt, eventloop, utils
|
||||
from shadowsocks import encrypt, eventloop, utils, common
|
||||
from shadowsocks.common import parse_header
|
||||
|
||||
|
||||
|
@ -231,13 +234,13 @@ class TCPRelayHandler(object):
|
|||
def _handle_stage_hello(self, data):
|
||||
try:
|
||||
if self._is_local:
|
||||
cmd = ord(data[1])
|
||||
cmd = common.ord(data[1])
|
||||
if cmd == CMD_UDP_ASSOCIATE:
|
||||
logging.debug('UDP associate')
|
||||
if self._local_sock.family == socket.AF_INET6:
|
||||
header = '\x05\x00\x00\x04'
|
||||
header = b'\x05\x00\x00\x04'
|
||||
else:
|
||||
header = '\x05\x00\x00\x01'
|
||||
header = b'\x05\x00\x00\x01'
|
||||
addr, port = self._local_sock.getsockname()
|
||||
addr_to_send = socket.inet_pton(self._local_sock.family,
|
||||
addr)
|
||||
|
@ -265,7 +268,7 @@ class TCPRelayHandler(object):
|
|||
self._stage = STAGE_DNS
|
||||
if self._is_local:
|
||||
# forward address to remote
|
||||
self._write_to_sock('\x05\x00\x00\x01\x00\x00\x00\x00\x10\x10',
|
||||
self._write_to_sock(b'\x05\x00\x00\x01\x00\x00\x00\x00\x10\x10',
|
||||
self._local_sock)
|
||||
data_to_send = self._encryptor.encrypt(data)
|
||||
self._data_to_write_to_remote.append(data_to_send)
|
||||
|
@ -366,7 +369,7 @@ class TCPRelayHandler(object):
|
|||
return
|
||||
elif is_local and self._stage == STAGE_INIT:
|
||||
# TODO check auth method
|
||||
self._write_to_sock('\x05\00', self._local_sock)
|
||||
self._write_to_sock(b'\x05\00', self._local_sock)
|
||||
self._stage = STAGE_HELLO
|
||||
return
|
||||
elif self._stage == STAGE_REPLY:
|
||||
|
@ -411,7 +414,7 @@ class TCPRelayHandler(object):
|
|||
def _on_remote_write(self):
|
||||
self._stage = STAGE_STREAM
|
||||
if self._data_to_write_to_remote:
|
||||
data = ''.join(self._data_to_write_to_remote)
|
||||
data = b''.join(self._data_to_write_to_remote)
|
||||
self._data_to_write_to_remote = []
|
||||
self._write_to_sock(data, self._remote_sock)
|
||||
else:
|
||||
|
|
|
@ -65,6 +65,8 @@
|
|||
# `client` means UDP clients that connects to other servers
|
||||
# `server` means the UDP server that handles user requests
|
||||
|
||||
from __future__ import absolute_import, division, print_function, \
|
||||
with_statement
|
||||
|
||||
import time
|
||||
import socket
|
||||
|
@ -73,7 +75,7 @@ import struct
|
|||
import errno
|
||||
import random
|
||||
|
||||
from shadowsocks import encrypt, eventloop, lru_cache
|
||||
from shadowsocks import encrypt, eventloop, lru_cache, common
|
||||
from shadowsocks.common import parse_header, pack_addr
|
||||
|
||||
|
||||
|
@ -146,7 +148,7 @@ class UDPRelay(object):
|
|||
if not data:
|
||||
logging.debug('UDP handle_server: data is empty')
|
||||
if self._is_local:
|
||||
frag = ord(data[2])
|
||||
frag = common.ord(data[2])
|
||||
if frag != 0:
|
||||
logging.warn('drop a message since frag is not 0')
|
||||
return
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
# 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 os
|
||||
import json
|
||||
import sys
|
||||
|
@ -33,9 +36,9 @@ VERBOSE_LEVEL = 5
|
|||
|
||||
def check_python():
|
||||
info = sys.version_info
|
||||
if not (info[0] == 2 and info[1] >= 6):
|
||||
print 'Python 2.6 or 2.7 required'
|
||||
sys.exit(1)
|
||||
# if not (info[0] == 2 and info[1] >= 6):
|
||||
# print('Python 2.6 or 2.7 required')
|
||||
# sys.exit(1)
|
||||
|
||||
|
||||
def print_shadowsocks():
|
||||
|
@ -45,7 +48,7 @@ def print_shadowsocks():
|
|||
version = pkg_resources.get_distribution('shadowsocks').version
|
||||
except Exception:
|
||||
pass
|
||||
print 'shadowsocks %s' % version
|
||||
print('shadowsocks %s' % version)
|
||||
|
||||
|
||||
def find_config():
|
||||
|
@ -76,7 +79,7 @@ def check_config(config):
|
|||
if config.get('timeout', 300) > 600:
|
||||
logging.warn('warning: your timeout %d seems too long' %
|
||||
int(config.get('timeout')))
|
||||
if config.get('password') in ['mypassword', 'barfoo!']:
|
||||
if config.get('password') in ['mypassword']:
|
||||
logging.error('DON\'T USE DEFAULT PASSWORD! Please change it in your '
|
||||
'config.json!')
|
||||
exit(1)
|
||||
|
@ -102,7 +105,8 @@ def get_config(is_local):
|
|||
logging.info('loading config from %s' % config_path)
|
||||
with open(config_path, 'rb') as f:
|
||||
try:
|
||||
config = json.load(f, object_hook=_decode_dict)
|
||||
config = json.loads(f.read().decode('utf8'),
|
||||
object_hook=_decode_dict)
|
||||
except ValueError as e:
|
||||
logging.error('found an error in config.json: %s',
|
||||
e.message)
|
||||
|
@ -145,7 +149,7 @@ def get_config(is_local):
|
|||
v_count -= 1
|
||||
config['verbose'] = v_count
|
||||
except getopt.GetoptError as e:
|
||||
print >>sys.stderr, e
|
||||
print(e, file=sys.stderr)
|
||||
print_help(is_local)
|
||||
sys.exit(2)
|
||||
|
||||
|
@ -218,7 +222,7 @@ def print_help(is_local):
|
|||
|
||||
|
||||
def print_local_help():
|
||||
print '''usage: sslocal [-h] -s SERVER_ADDR [-p SERVER_PORT]
|
||||
print('''usage: sslocal [-h] -s SERVER_ADDR [-p SERVER_PORT]
|
||||
[-b LOCAL_ADDR] [-l LOCAL_PORT] -k PASSWORD [-m METHOD]
|
||||
[-t TIMEOUT] [-c CONFIG] [--fast-open] [-v] [-q]
|
||||
|
||||
|
@ -237,11 +241,11 @@ optional arguments:
|
|||
-q, -qq quiet mode, only show warnings/errors
|
||||
|
||||
Online help: <https://github.com/clowwindy/shadowsocks>
|
||||
'''
|
||||
''')
|
||||
|
||||
|
||||
def print_server_help():
|
||||
print '''usage: ssserver [-h] [-s SERVER_ADDR] [-p SERVER_PORT] -k PASSWORD
|
||||
print('''usage: ssserver [-h] [-s SERVER_ADDR] [-p SERVER_PORT] -k PASSWORD
|
||||
-m METHOD [-t TIMEOUT] [-c CONFIG] [--fast-open]
|
||||
[--workers WORKERS] [-v] [-q]
|
||||
|
||||
|
@ -259,13 +263,13 @@ optional arguments:
|
|||
-q, -qq quiet mode, only show warnings/errors
|
||||
|
||||
Online help: <https://github.com/clowwindy/shadowsocks>
|
||||
'''
|
||||
''')
|
||||
|
||||
|
||||
def _decode_list(data):
|
||||
rv = []
|
||||
for item in data:
|
||||
if isinstance(item, unicode):
|
||||
if hasattr(item, 'encode'):
|
||||
item = item.encode('utf-8')
|
||||
elif isinstance(item, list):
|
||||
item = _decode_list(item)
|
||||
|
@ -277,10 +281,8 @@ def _decode_list(data):
|
|||
|
||||
def _decode_dict(data):
|
||||
rv = {}
|
||||
for key, value in data.iteritems():
|
||||
if isinstance(key, unicode):
|
||||
key = key.encode('utf-8')
|
||||
if isinstance(value, unicode):
|
||||
for key, value in data.items():
|
||||
if hasattr(value, 'encode'):
|
||||
value = value.encode('utf-8')
|
||||
elif isinstance(value, list):
|
||||
value = _decode_list(value)
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import absolute_import, division, print_function, \
|
||||
with_statement
|
||||
|
||||
import sys
|
||||
import os
|
||||
import signal
|
||||
|
@ -22,7 +25,7 @@ else:
|
|||
if 'salsa20' in sys.argv[-1]:
|
||||
from shadowsocks.crypto import salsa20_ctr
|
||||
salsa20_ctr.test()
|
||||
print 'encryption test passed'
|
||||
print('encryption test passed')
|
||||
|
||||
p1 = Popen(['python', 'shadowsocks/server.py', '-c', server_config],
|
||||
stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)
|
||||
|
@ -69,7 +72,7 @@ try:
|
|||
sys.exit(r)
|
||||
else:
|
||||
sys.exit(1)
|
||||
print 'test passed'
|
||||
print('test passed')
|
||||
|
||||
finally:
|
||||
for p in [p1, p2]:
|
||||
|
|
Loading…
Add table
Reference in a new issue