Browse Source

support UDP protocol plugin

dev
BreakWa11 9 years ago
parent
commit
42a05d22d6
  1. 34
      shadowsocks/encrypt.py
  2. 12
      shadowsocks/obfs.py
  3. 12
      shadowsocks/obfsplugin/plain.py
  4. 16
      shadowsocks/obfsplugin/verify.py
  5. 41
      shadowsocks/udprelay.py

34
shadowsocks/encrypt.py

@ -159,6 +159,40 @@ def encrypt_all(password, method, op, data):
result.append(cipher.update(data))
return b''.join(result)
def encrypt_key(password, method):
method = method.lower()
(key_len, iv_len, m) = method_supported[method]
if key_len > 0:
key, _ = EVP_BytesToKey(password, key_len, iv_len)
else:
key = password
return key
def encrypt_iv_len(method):
method = method.lower()
(key_len, iv_len, m) = method_supported[method]
return iv_len
def encrypt_new_iv(method):
method = method.lower()
(key_len, iv_len, m) = method_supported[method]
return random_string(iv_len)
def encrypt_all_iv(key, method, op, data, ref_iv):
result = []
method = method.lower()
(key_len, iv_len, m) = method_supported[method]
if op:
iv = ref_iv[0]
result.append(iv)
else:
iv = data[:iv_len]
data = data[iv_len:]
ref_iv[0] = iv
cipher = m(method, key, iv, op)
result.append(cipher.update(data))
return b''.join(result)
CIPHERS_TO_TEST = [
'aes-128-cfb',

12
shadowsocks/obfs.py

@ -85,6 +85,18 @@ class obfs(object):
def server_post_decrypt(self, buf):
return self.obfs.server_post_decrypt(buf)
def client_udp_pre_encrypt(self, buf):
return self.obfs.client_udp_pre_encrypt(buf)
def client_udp_post_decrypt(self, buf):
return self.obfs.client_udp_post_decrypt(buf)
def server_udp_pre_encrypt(self, buf):
return self.obfs.server_udp_pre_encrypt(buf)
def server_udp_post_decrypt(self, buf):
return self.obfs.server_udp_post_decrypt(buf)
def dispose(self):
self.obfs.dispose()
del self.obfs

12
shadowsocks/obfsplugin/plain.py

@ -69,6 +69,18 @@ class plain(object):
def server_post_decrypt(self, buf):
return buf
def client_udp_pre_encrypt(self, buf):
return buf
def client_udp_post_decrypt(self, buf):
return buf
def server_udp_pre_encrypt(self, buf):
return buf
def server_udp_post_decrypt(self, buf):
return buf
def dispose(self):
pass

16
shadowsocks/obfsplugin/verify.py

@ -342,3 +342,19 @@ class verify_sha1(verify_base):
return out_buf
def client_udp_pre_encrypt(self, buf):
ret = self.pack_auth_data(buf)
return chr(ord(buf[0]) | 0x10) + buf[1:]
def server_udp_post_decrypt(self, buf):
if buf and ((ord(buf[0]) & 0x10) == 0x10):
if len(buf) <= 11:
return b'E'
sha1data = hmac.new(self.server_info.recv_iv + self.server_info.key, buf[:-10], hashlib.sha1).digest()[:10]
if sha1data != buf[-10:]:
logging.error('server_udp_post_decrypt data uncorrect auth HMAC-SHA1')
return b'E'
return to_bytes(chr(ord(buf[0]) & 0xEF)) + buf[1:-10]
else:
return buf

41
shadowsocks/udprelay.py

@ -71,7 +71,7 @@ import random
import binascii
import traceback
from shadowsocks import encrypt, eventloop, lru_cache, common, shell
from shadowsocks import encrypt, obfs, eventloop, lru_cache, common, shell
from shadowsocks.common import pre_parse_header, parse_header, pack_addr
# we clear at most TIMEOUTS_CLEAN_SIZE timeouts each time
@ -890,6 +890,20 @@ class UDPRelay(object):
self.server_transfer_ul = 0
self.server_transfer_dl = 0
self.protocol_data = obfs.obfs(config['protocol']).init_data()
self._protocol = obfs.obfs(config['protocol'])
server_info = obfs.server_info(self.protocol_data)
server_info.host = self._listen_addr
server_info.port = self._listen_port
server_info.protocol_param = config['protocol_param']
server_info.obfs_param = ''
server_info.iv = b''
server_info.recv_iv = b''
server_info.key = encrypt.encrypt_key(self._password, self._method)
server_info.head_len = 30
server_info.tcp_mss = 1440
self._protocol.set_server_info(server_info)
self._sockets = set()
self._fd_to_handlers = {}
self._reqid_to_hd = {}
@ -991,11 +1005,14 @@ class UDPRelay(object):
else:
data = data[3:]
else:
data = encrypt.encrypt_all(self._password, self._method, 0, data)
ref_iv = [0]
data = encrypt.encrypt_all_iv(self._protocol.obfs.server_info.key, self._method, 0, data, ref_iv)
# decrypt data
if not data:
logging.debug('UDP handle_server: data is empty after decrypt')
return
self._protocol.obfs.server_info.recv_iv = ref_iv[0]
data = self._protocol.server_udp_post_decrypt(data)
#logging.info("UDP data %s" % (binascii.hexlify(data),))
if not self._is_local:
@ -1121,7 +1138,11 @@ class UDPRelay(object):
r_addr[0], r_addr[1]))
if self._is_local:
data = encrypt.encrypt_all(self._password, self._method, 1, data)
ref_iv = [encrypt.encrypt_new_iv(self._method)]
self._protocol.obfs.server_info.iv = ref_iv[0]
data = self._protocol.client_udp_pre_encrypt(data)
logging.info("%s" % (binascii.hexlify(data),))
data = encrypt.encrypt_all_iv(self._protocol.obfs.server_info.key, self._method, 1, data, ref_iv)
if not data:
return
else:
@ -1151,15 +1172,21 @@ class UDPRelay(object):
# drop
return
data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data
response = encrypt.encrypt_all(self._password, self._method, 1,
data)
ref_iv = [encrypt.encrypt_new_iv(self._method)]
self._protocol.obfs.server_info.iv = ref_iv[0]
data = self._protocol.server_udp_pre_encrypt(data)
response = encrypt.encrypt_all_iv(self._protocol.obfs.server_info.key, self._method, 1,
data, ref_iv)
if not response:
return
else:
data = encrypt.encrypt_all(self._password, self._method, 0,
data)
ref_iv = [0]
data = encrypt.encrypt_all_iv(self._protocol.obfs.server_info.key, self._method, 0,
data, ref_iv)
if not data:
return
self._protocol.obfs.server_info.recv_iv = ref_iv[0]
data = self._protocol.client_udp_post_decrypt(data)
header_result = parse_header(data)
if header_result is None:
return

Loading…
Cancel
Save