@@ -138,6 +138,20 @@ def pack_addr(address): | |||
address = address[:255] # TODO | |||
return b'\x03' + chr(len(address)) + address | |||
def pre_parse_header(data): | |||
datatype = ord(data[0]) | |||
if datatype == 0x80 : | |||
if len(data) <= 2: | |||
return None | |||
rand_data_size = ord(data[1]) | |||
if rand_data_size + 2 >= len(data): | |||
logging.warn('header too short, maybe wrong password or ' | |||
'encryption method') | |||
return None | |||
data = data[rand_data_size + 2:] | |||
elif datatype == 0x81: | |||
data = data[1:] | |||
return data | |||
def parse_header(data): | |||
addrtype = ord(data[0]) | |||
@@ -173,8 +187,8 @@ def parse_header(data): | |||
else: | |||
logging.warn('header is too short') | |||
else: | |||
logging.warn('unsupported addrtype %d, maybe wrong password' % | |||
addrtype) | |||
logging.warn('unsupported addrtype %d, maybe wrong password or ' | |||
'encryption method' % addrtype) | |||
if dest_addr is None: | |||
return None | |||
return connecttype, to_bytes(dest_addr), dest_port, header_length |
@@ -0,0 +1,33 @@ | |||
from __future__ import absolute_import, division, print_function, \ | |||
with_statement | |||
import sys | |||
import os | |||
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../')) | |||
from crypto import rc4_md5 | |||
from crypto import openssl | |||
from crypto import sodium | |||
from crypto import table | |||
def main(): | |||
print("\n""rc4_md5") | |||
rc4_md5.test() | |||
print("\n""aes-256-cfb") | |||
openssl.test_aes_256_cfb() | |||
print("\n""aes-128-cfb") | |||
openssl.test_aes_128_cfb() | |||
print("\n""rc4") | |||
openssl.test_rc4() | |||
print("\n""salsa20") | |||
sodium.test_salsa20() | |||
print("\n""chacha20") | |||
sodium.test_chacha20() | |||
print("\n""table") | |||
table.test_encryption() | |||
if __name__ == '__main__': | |||
main() | |||
@@ -27,7 +27,7 @@ import traceback | |||
import random | |||
from shadowsocks import encrypt, eventloop, shell, common | |||
from shadowsocks.common import parse_header | |||
from shadowsocks.common import pre_parse_header, parse_header | |||
# we clear at most TIMEOUTS_CLEAN_SIZE timeouts each time | |||
TIMEOUTS_CLEAN_SIZE = 512 | |||
@@ -320,12 +320,15 @@ class TCPRelayHandler(object): | |||
logging.error('unknown command %d', cmd) | |||
self.destroy() | |||
return | |||
data = pre_parse_header(data) | |||
if data is None: | |||
raise Exception('can not parse header') | |||
header_result = parse_header(data) | |||
if header_result is None: | |||
raise Exception('can not parse header') | |||
connecttype, remote_addr, remote_port, header_length = header_result | |||
logging.info('%s connecting %s:%d from %s:%d' % | |||
((connecttype == 0) and 'tcp' or 'udp', | |||
((connecttype == 0) and 'TCP' or 'UDP', | |||
common.to_str(remote_addr), remote_port, | |||
self._client_address[0], self._client_address[1])) | |||
self._remote_address = (common.to_str(remote_addr), remote_port) | |||
@@ -356,15 +359,6 @@ class TCPRelayHandler(object): | |||
# TODO use logging when debug completed | |||
self.destroy() | |||
def _has_ipv6_addr(self, addr_list): | |||
for item in addr_list: | |||
if type(item) is list: | |||
if self._has_ipv6_addr(item): | |||
return True | |||
elif ':' in item: | |||
return True | |||
return False | |||
def _create_remote_socket(self, ip, port): | |||
if self._remote_udp: | |||
addrs_v6 = socket.getaddrinfo("::", 0, 0, socket.SOCK_DGRAM, socket.SOL_UDP) | |||
@@ -505,7 +499,7 @@ class TCPRelayHandler(object): | |||
except Exception as e: | |||
ip = socket.inet_pton(socket.AF_INET6, addr[0]) | |||
data = '\x00\x00\x00\x04' + ip + port + data | |||
logging.info('udp recvfrom %s:%d %d bytes to %s:%d' % (addr[0], addr[1], len(data), self._client_address[0], self._client_address[1])) | |||
logging.info('UDP recvfrom %s:%d %d bytes to %s:%d' % (addr[0], addr[1], len(data), self._client_address[0], self._client_address[1])) | |||
else: | |||
data = self._remote_sock.recv(BUF_SIZE) | |||
except (OSError, IOError) as e: |
@@ -70,7 +70,7 @@ import errno | |||
import random | |||
from shadowsocks import encrypt, eventloop, lru_cache, common, shell | |||
from shadowsocks.common import parse_header, pack_addr | |||
from shadowsocks.common import pre_parse_header, parse_header, pack_addr | |||
BUF_SIZE = 65536 | |||
@@ -159,6 +159,10 @@ class UDPRelay(object): | |||
if not data: | |||
logging.debug('UDP handle_server: data is empty after decrypt') | |||
return | |||
data = pre_parse_header(data) | |||
if data is None: | |||
return | |||
header_result = parse_header(data) | |||
if header_result is None: | |||
return | |||
@@ -173,7 +177,7 @@ class UDPRelay(object): | |||
client = self._cache.get(key, None) | |||
if not client: | |||
# TODO async getaddrinfo | |||
logging.info('UDP handle_server %s:%d from %s:%d' % (common.to_str(server_addr), server_port, self._listen_addr, self._listen_port)) | |||
#logging.info('UDP handle_server %s:%d from %s:%d' % (common.to_str(server_addr), server_port, self._listen_addr, self._listen_port)) | |||
addrs = socket.getaddrinfo(server_addr, server_port, 0, | |||
socket.SOCK_DGRAM, socket.SOL_UDP) | |||
if addrs: |