Skip to content

Commit 1bc0e60

Browse files
committed
merge manyuser branch
1 parent 3200b7d commit 1bc0e60

File tree

8 files changed

+232
-37
lines changed

8 files changed

+232
-37
lines changed

shadowsocks/common.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ def pre_parse_header(data):
160160
'encryption method')
161161
return None
162162
data = data[rand_data_size + 3:]
163-
elif datatype == 0x88:
163+
elif datatype == 0x88 or (~datatype & 0xff) == 0x88:
164164
if len(data) <= 7 + 7:
165165
return None
166166
data_size = struct.unpack('>H', data[1:3])[0]

shadowsocks/obfs.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,28 @@
2727

2828

2929
method_supported = {}
30-
method_supported.update(plain.obfs)
31-
method_supported.update(http_simple.obfs)
32-
method_supported.update(verify_simple.obfs)
30+
method_supported.update(plain.obfs_map)
31+
method_supported.update(http_simple.obfs_map)
32+
method_supported.update(verify_simple.obfs_map)
3333

34-
class Obfs(object):
34+
class server_info(object):
35+
def __init__(self, data):
36+
self.data = data
37+
38+
class obfs(object):
3539
def __init__(self, method):
3640
self.method = method
3741
self._method_info = self.get_method_info(method)
3842
if self._method_info:
3943
self.obfs = self.get_obfs(method)
4044
else:
41-
logging.error('method %s not supported' % method)
42-
sys.exit(1)
45+
raise Exception('method %s not supported' % method)
46+
47+
def init_data(self):
48+
return self.obfs.init_data()
49+
50+
def set_server_info(self, server_info):
51+
return self.obfs.set_server_info(server_info)
4352

4453
def get_method_info(self, method):
4554
method = method.lower()

shadowsocks/obfsplugin/http_simple.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
import base64
2626
import datetime
2727

28-
from shadowsocks.obfsplugin import plain
2928
from shadowsocks import common
29+
from shadowsocks.obfsplugin import plain
3030
from shadowsocks.common import to_bytes, to_str, ord
3131

3232
def create_http_obfs(method):
@@ -41,7 +41,7 @@ def create_tls_obfs(method):
4141
def create_random_head_obfs(method):
4242
return random_head(method)
4343

44-
obfs = {
44+
obfs_map = {
4545
'http_simple': (create_http_obfs,),
4646
'http_simple_compatible': (create_http_obfs,),
4747
'http2_simple': (create_http2_obfs,),

shadowsocks/obfsplugin/plain.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,20 @@
2525
def create_obfs(method):
2626
return plain(method)
2727

28-
obfs = {
28+
obfs_map = {
2929
'plain': (create_obfs,),
3030
}
3131

3232
class plain(object):
3333
def __init__(self, method):
3434
self.method = method
35+
self.server_info = None
36+
37+
def init_data(self):
38+
return b''
39+
40+
def set_server_info(self, server_info):
41+
self.server_info = server_info
3542

3643
def client_pre_encrypt(self, buf):
3744
return buf

shadowsocks/obfsplugin/verify_simple.py

Lines changed: 143 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,22 @@
2525
import base64
2626
import datetime
2727
import struct
28+
import zlib
2829

29-
from shadowsocks.obfsplugin import plain
30+
import shadowsocks
3031
from shadowsocks import common
32+
from shadowsocks.obfsplugin import plain
3133
from shadowsocks.common import to_bytes, to_str, ord
3234

3335
def create_verify_obfs(method):
3436
return verify_simple(method)
3537

36-
obfs = {
38+
def create_verify_deflate(method):
39+
return verify_deflate(method)
40+
41+
obfs_map = {
3742
'verify_simple': (create_verify_obfs,),
43+
'verify_deflate': (create_verify_deflate,),
3844
}
3945

4046
def match_begin(str1, str2):
@@ -43,9 +49,64 @@ def match_begin(str1, str2):
4349
return True
4450
return False
4551

46-
class verify_simple(plain.plain):
52+
class sub_encode_obfs(object):
53+
def __init__(self):
54+
self.sub_obfs = None
55+
56+
class verify_base(plain.plain):
4757
def __init__(self, method):
58+
super(verify_base, self).__init__(method)
4859
self.method = method
60+
self.sub_obfs = None
61+
62+
def init_data(self):
63+
return sub_encode_obfs()
64+
65+
def set_server_info(self, server_info):
66+
try:
67+
if server_info.param:
68+
sub_param = ''
69+
param_list = server_info.param.split(',', 1)
70+
if len(param_list) > 1:
71+
self.sub_obfs = shadowsocks.obfs.obfs(param_list[0])
72+
sub_param = param_list[1]
73+
else:
74+
self.sub_obfs = shadowsocks.obfs.obfs(server_info.param)
75+
if server_info.data.sub_obfs is None:
76+
server_info.data.sub_obfs = self.sub_obfs.init_data()
77+
_server_info = shadowsocks.obfs.server_info(server_info.data.sub_obfs)
78+
_server_info.host = server_info.host
79+
_server_info.port = server_info.port
80+
_server_info.tcp_mss = server_info.tcp_mss
81+
_server_info.param = sub_param
82+
self.sub_obfs.set_server_info(_server_info)
83+
except Exception as e:
84+
shadowsocks.shell.print_exception(e)
85+
self.server_info = server_info
86+
87+
def client_encode(self, buf):
88+
if self.sub_obfs is not None:
89+
return self.sub_obfs.client_encode(buf)
90+
return buf
91+
92+
def client_decode(self, buf):
93+
if self.sub_obfs is not None:
94+
return self.sub_obfs.client_decode(buf)
95+
return (buf, False)
96+
97+
def server_encode(self, buf):
98+
if self.sub_obfs is not None:
99+
return self.sub_obfs.server_encode(buf)
100+
return buf
101+
102+
def server_decode(self, buf):
103+
if self.sub_obfs is not None:
104+
return self.sub_obfs.server_decode(buf)
105+
return (buf, True, False)
106+
107+
class verify_simple(verify_base):
108+
def __init__(self, method):
109+
super(verify_simple, self).__init__(method)
49110
self.recv_buf = b''
50111
self.unit_len = 8100
51112
self.decrypt_packet_num = 0
@@ -69,13 +130,6 @@ def client_pre_encrypt(self, buf):
69130
ret += self.pack_data(buf)
70131
return ret
71132

72-
def client_encode(self, buf):
73-
return buf
74-
75-
def client_decode(self, buf):
76-
# (buffer_to_recv, is_need_to_encode_and_send_back)
77-
return (buf, False)
78-
79133
def client_post_decrypt(self, buf):
80134
if self.raw_trans:
81135
return buf
@@ -117,13 +171,6 @@ def server_pre_encrypt(self, buf):
117171
ret += self.pack_data(buf)
118172
return ret
119173

120-
def server_encode(self, buf):
121-
return buf
122-
123-
def server_decode(self, buf):
124-
# (buffer_to_recv, is_need_decrypt, is_need_to_encode_and_send_back)
125-
return (buf, True, False)
126-
127174
def server_post_decrypt(self, buf):
128175
if self.raw_trans:
129176
return buf
@@ -157,3 +204,82 @@ def server_post_decrypt(self, buf):
157204
self.decrypt_packet_num += 1
158205
return out_buf
159206

207+
class verify_deflate(verify_base):
208+
def __init__(self, method):
209+
super(verify_deflate, self).__init__(method)
210+
self.recv_buf = b''
211+
self.unit_len = 32700
212+
self.decrypt_packet_num = 0
213+
self.raw_trans = False
214+
215+
def pack_data(self, buf):
216+
if len(buf) == 0:
217+
return b''
218+
data = zlib.compress(buf)
219+
data = struct.pack('>H', len(data)) + data[2:]
220+
return data
221+
222+
def client_pre_encrypt(self, buf):
223+
ret = b''
224+
while len(buf) > self.unit_len:
225+
ret += self.pack_data(buf[:self.unit_len])
226+
buf = buf[self.unit_len:]
227+
ret += self.pack_data(buf)
228+
return ret
229+
230+
def client_post_decrypt(self, buf):
231+
if self.raw_trans:
232+
return buf
233+
self.recv_buf += buf
234+
out_buf = b''
235+
while len(self.recv_buf) > 2:
236+
length = struct.unpack('>H', self.recv_buf[:2])[0]
237+
if length >= 32768:
238+
self.raw_trans = True
239+
self.recv_buf = b''
240+
if self.decrypt_packet_num == 0:
241+
return None
242+
else:
243+
raise Exception('server_post_decrype data error')
244+
if length > len(self.recv_buf):
245+
break
246+
247+
out_buf += zlib.decompress(b'x\x9c' + self.recv_buf[2:length])
248+
self.recv_buf = self.recv_buf[length:]
249+
250+
if out_buf:
251+
self.decrypt_packet_num += 1
252+
return out_buf
253+
254+
def server_pre_encrypt(self, buf):
255+
ret = b''
256+
while len(buf) > self.unit_len:
257+
ret += self.pack_data(buf[:self.unit_len])
258+
buf = buf[self.unit_len:]
259+
ret += self.pack_data(buf)
260+
return ret
261+
262+
def server_post_decrypt(self, buf):
263+
if self.raw_trans:
264+
return buf
265+
self.recv_buf += buf
266+
out_buf = b''
267+
while len(self.recv_buf) > 2:
268+
length = struct.unpack('>H', self.recv_buf[:2])[0]
269+
if length >= 32768:
270+
self.raw_trans = True
271+
self.recv_buf = b''
272+
if self.decrypt_packet_num == 0:
273+
return None
274+
else:
275+
raise Exception('server_post_decrype data error')
276+
if length > len(self.recv_buf):
277+
break
278+
279+
out_buf += zlib.decompress(b'\x78\x9c' + self.recv_buf[2:length])
280+
self.recv_buf = self.recv_buf[length:]
281+
282+
if out_buf:
283+
self.decrypt_packet_num += 1
284+
return out_buf
285+

shadowsocks/shell.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,11 +130,11 @@ def get_config(is_local):
130130
logging.basicConfig(level=logging.INFO,
131131
format='%(levelname)-s: %(message)s')
132132
if is_local:
133-
shortopts = 'hd:s:b:p:k:l:m:c:t:vq'
133+
shortopts = 'hd:s:b:p:k:l:m:o:c:t:vq'
134134
longopts = ['help', 'fast-open', 'pid-file=', 'log-file=', 'user=',
135135
'version']
136136
else:
137-
shortopts = 'hd:s:p:k:m:c:t:vq'
137+
shortopts = 'hd:s:p:k:m:o:c:t:vq'
138138
longopts = ['help', 'fast-open', 'pid-file=', 'log-file=', 'workers=',
139139
'forbidden-ip=', 'user=', 'manager-address=', 'version']
140140
try:
@@ -168,6 +168,8 @@ def get_config(is_local):
168168
config['server'] = to_str(value)
169169
elif key == '-m':
170170
config['method'] = to_str(value)
171+
elif key == '-o':
172+
config['obfs'] = to_str(value)
171173
elif key == '-b':
172174
config['local_address'] = to_str(value)
173175
elif key == '-v':
@@ -217,6 +219,7 @@ def get_config(is_local):
217219
config['password'] = to_bytes(config.get('password', b''))
218220
config['method'] = to_str(config.get('method', 'aes-256-cfb'))
219221
config['obfs'] = to_str(config.get('obfs', 'plain'))
222+
config['obfs_param'] = to_str(config.get('obfs_param', ''))
220223
config['port_password'] = config.get('port_password', None)
221224
config['timeout'] = int(config.get('timeout', 300))
222225
config['fast_open'] = config.get('fast_open', False)
@@ -286,6 +289,7 @@ def print_local_help():
286289
-l LOCAL_PORT local port, default: 1080
287290
-k PASSWORD password
288291
-m METHOD encryption method, default: aes-256-cfb
292+
-o OBFS obfsplugin, default: http_simple
289293
-t TIMEOUT timeout in seconds, default: 300
290294
--fast-open use TCP_FASTOPEN, requires Linux 3.7+
291295
@@ -315,6 +319,7 @@ def print_server_help():
315319
-p SERVER_PORT server port, default: 8388
316320
-k PASSWORD password
317321
-m METHOD encryption method, default: aes-256-cfb
322+
-o OBFS obfsplugin, default: http_simple
318323
-t TIMEOUT timeout in seconds, default: 300
319324
--fast-open use TCP_FASTOPEN, requires Linux 3.7+
320325
--workers WORKERS number of workers, available on Unix/Linux

0 commit comments

Comments
 (0)