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