diff --git a/shadowsocks/obfs.py b/shadowsocks/obfs.py index c54eaa8..9d6d58e 100644 --- a/shadowsocks/obfs.py +++ b/shadowsocks/obfs.py @@ -49,13 +49,15 @@ class Obfs(object): m = self._method_info return m[0](method) - def encode(self, buf): - #if len(buf) == 0: - # return buf - return self.obfs.encode(buf) - - def decode(self, buf): - #if len(buf) == 0: - # return (buf, True, False) - return self.obfs.decode(buf) + def client_encode(self, buf): + return self.obfs.client_encode(buf) + + def client_decode(self, buf): + return self.obfs.client_decode(buf) + + def server_encode(self, buf): + return self.obfs.server_encode(buf) + + def server_decode(self, buf): + return self.obfs.server_decode(buf) diff --git a/shadowsocks/obfsplugin/http_simple.py b/shadowsocks/obfsplugin/http_simple.py index 36e9028..592811c 100644 --- a/shadowsocks/obfsplugin/http_simple.py +++ b/shadowsocks/obfsplugin/http_simple.py @@ -40,7 +40,15 @@ class http_simple(object): self.port = 0 self.recv_buffer = "" - def encode(self, buf): + def client_encode(self, buf): + # TODO + return buf + + def client_decode(self, buf): + # TODO + return (buf, False) + + def server_encode(self, buf): if self.has_sent_header: return buf else: @@ -50,7 +58,7 @@ class http_simple(object): self.has_sent_header = True return header + buf - def decode(self, buf): + def server_decode(self, buf): if self.has_recv_header: return (buf, True, False) else: diff --git a/shadowsocks/obfsplugin/plain.py b/shadowsocks/obfsplugin/plain.py index 90b5ea0..5834f89 100644 --- a/shadowsocks/obfsplugin/plain.py +++ b/shadowsocks/obfsplugin/plain.py @@ -33,9 +33,16 @@ class plain(object): def __init__(self, method): self.method = method - def encode(self, buf): + def client_encode(self, buf): return buf - def decode(self, buf): + def client_decode(self, buf): + # (buffer_to_recv, is_need_to_encode_and_send_back) + return (buf, False) + + def server_encode(self, buf): + return buf + + def server_decode(self, buf): # (buffer_to_recv, is_need_decrypt, is_need_to_encode_and_send_back) return (buf, True, False) diff --git a/shadowsocks/tcprelay.py b/shadowsocks/tcprelay.py index e304fe5..0438249 100644 --- a/shadowsocks/tcprelay.py +++ b/shadowsocks/tcprelay.py @@ -33,6 +33,8 @@ from shadowsocks.common import pre_parse_header, parse_header # set it 'False' to use both new protocol and the original shadowsocks protocal # set it 'True' to use new protocol ONLY, to avoid GFW detecting FORCE_NEW_PROTOCOL = False +# set it 'True' if run as a local client and connect to a server which support new protocol +CLIENT_NEW_PROTOCOL = False # we clear at most TIMEOUTS_CLEAN_SIZE timeouts each time TIMEOUTS_CLEAN_SIZE = 512 @@ -250,9 +252,12 @@ class TCPRelayHandler(object): return True else: try: - if sock == self._local_sock and self._encrypt_correct: - obfs_encode = self._obfs.encode(data) - data = obfs_encode + if self._is_local: + pass + else: + if sock == self._local_sock and self._encrypt_correct: + obfs_encode = self._obfs.server_encode(data) + data = obfs_encode l = len(data) s = sock.send(data) if s < l: @@ -303,7 +308,7 @@ class TCPRelayHandler(object): def _handel_protocol_error(self, client_address, ogn_data): #raise Exception('can not parse header') - logging.warn("Protocol ERROR, TCP ogn data %s" % (binascii.hexlify(ogn_data), )) + logging.warn("Protocol ERROR, TCP ogn data %s from %s:%d" % (binascii.hexlify(ogn_data), client_address[0], client_address[1])) self._encrypt_correct = False #create redirect or disconnect by hash code host, port = self._get_redirect_host(client_address, ogn_data) @@ -314,6 +319,7 @@ class TCPRelayHandler(object): def _handle_stage_connecting(self, data): if self._is_local: data = self._encryptor.encrypt(data) + data = self._obfs.client_encode(data) self._data_to_write_to_remote.append(data) if self._is_local and not self._fastopen_connected and \ self._config['fast_open']: @@ -377,15 +383,18 @@ class TCPRelayHandler(object): return before_parse_data = data - if FORCE_NEW_PROTOCOL and ord(data[0]) != 0x88: - data = self._handel_protocol_error(self._client_address, ogn_data) - data = pre_parse_header(data) - if data is None: - data = self._handel_protocol_error(self._client_address, ogn_data) - header_result = parse_header(data) - if header_result is None: - data = self._handel_protocol_error(self._client_address, ogn_data) + if self._is_local: header_result = parse_header(data) + else: + if FORCE_NEW_PROTOCOL and common.ord(data[0]) != 0x88: + data = self._handel_protocol_error(self._client_address, ogn_data) + data = pre_parse_header(data) + if data is None: + data = self._handel_protocol_error(self._client_address, ogn_data) + header_result = parse_header(data) + if header_result is None: + data = self._handel_protocol_error(self._client_address, ogn_data) + header_result = parse_header(data) connecttype, remote_addr, remote_port, header_length = header_result logging.info('%s connecting %s:%d from %s:%d' % ((connecttype == 0) and 'TCP' or 'UDP', @@ -401,6 +410,12 @@ class TCPRelayHandler(object): self._write_to_sock((b'\x05\x00\x00\x01' b'\x00\x00\x00\x00\x10\x10'), self._local_sock) + if CLIENT_NEW_PROTOCOL: + rnd_len = random.randint(1, 32) + total_len = 7 + rnd_len + len(data) + data = b'\x88' + struct.pack('>H', total_len) + chr(rnd_len) + (b' ' * (rnd_len - 1)) + data + crc = (0xffffffff - binascii.crc32(data)) & 0xffffffff + data += struct.pack(' self.end_id: - for eid in xrange(self.end_id, end_id): + eid = self.end_id + while eid < pack_id: self.miss_queue.add(eid) + eid += 1 self.end_id = end_id def get_begin_id(self): @@ -302,7 +306,7 @@ class TCPRelayHandler(object): #loop.add(local_sock, eventloop.POLL_IN | eventloop.POLL_ERR) self.last_activity = 0 self._update_activity() - self._random_mtu_size = [random.randint(POST_MTU_MIN, POST_MTU_MAX) for i in xrange(1024)] + self._random_mtu_size = [random.randint(POST_MTU_MIN, POST_MTU_MAX) for i in range(1024)] self._random_mtu_index = 0 self._rand_data = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10" * 4 @@ -474,7 +478,7 @@ class TCPRelayHandler(object): addr = self.get_local_address() - for i in xrange(2): + for i in range(2): rsp_data = self._pack_rsp_data(CMD_RSP_CONNECT_REMOTE, RSP_STATE_CONNECTEDREMOTE) self._write_to_sock(rsp_data, self._local_sock, addr) @@ -671,7 +675,7 @@ class TCPRelayHandler(object): if self._stage == STAGE_RSP_ID: if cmd == CMD_CONNECT: - for i in xrange(2): + for i in range(2): rsp_data = self._pack_rsp_data(CMD_RSP_CONNECT, RSP_STATE_CONNECTED) self._write_to_sock(rsp_data, self._local_sock, addr) elif cmd == CMD_CONNECT_REMOTE: @@ -695,7 +699,7 @@ class TCPRelayHandler(object): if cmd == CMD_CONNECT_REMOTE: local_id = data[0:4] if self._local_id == local_id: - for i in xrange(2): + for i in range(2): rsp_data = self._pack_rsp_data(CMD_RSP_CONNECT_REMOTE, RSP_STATE_CONNECTEDREMOTE) self._write_to_sock(rsp_data, self._local_sock, addr) else: @@ -927,7 +931,7 @@ class UDPRelay(object): def _pre_parse_udp_header(self, data): if data is None: return - datatype = ord(data[0]) + datatype = common.ord(data[0]) if datatype == 0x8: if len(data) >= 8: crc = binascii.crc32(data) & 0xffffffff @@ -935,17 +939,17 @@ class UDPRelay(object): logging.warn('uncorrect CRC32, maybe wrong password or ' 'encryption method') return None - cmd = ord(data[1]) + cmd = common.ord(data[1]) request_id = struct.unpack('>H', data[2:4])[0] data = data[4:-4] return (cmd, request_id, data) - elif len(data) >= 6 and ord(data[1]) == 0x0: + elif len(data) >= 6 and common.ord(data[1]) == 0x0: crc = binascii.crc32(data) & 0xffffffff if crc != 0xffffffff: logging.warn('uncorrect CRC32, maybe wrong password or ' 'encryption method') return None - cmd = ord(data[1]) + cmd = common.ord(data[1]) data = data[2:-4] return (cmd, 0, data) else: @@ -994,12 +998,12 @@ class UDPRelay(object): try: if data[0] == 0: if len(data[2]) >= 4: - for i in xrange(64): + for i in range(64): req_id = random.randint(1, 65535) if req_id not in self._reqid_to_hd: break if req_id in self._reqid_to_hd: - for i in xrange(64): + for i in range(64): req_id = random.randint(1, 65535) if type(self._reqid_to_hd[req_id]) is tuple: break