def test_equal(self): header1 = ShadowsocksPacketHeader( port=80, addr_type=constants.SOCKS5_ADDRTYPE_HOST, addr='www.google.com') header2 = ShadowsocksPacketHeader( port=80, addr_type=constants.SOCKS5_ADDRTYPE_HOST, addr='www.google.com') self.assertEqual(header1, header2)
def test_fields(self): header = ShadowsocksPacketHeader() header.port = 999 header.addr_type = 1 header.addr = '192.168.18.1' self.assertEqual(header.port, 999) self.assertEqual(header.addr_type, 1) self.assertEqual(header.addr, '192.168.18.1') # specified fields that do not assigned will return None instead of rasing KeyError self.assertIsNone(header.sha1_hmac) with self.assertRaises(KeyError): header.not_exist = 9
def test_data_relay(self): # Create a pair of connected sockets lsock, rsock = socketpair() loop = asyncio.get_event_loop() _args = { constants.ARG_CIPHER_METHOD: encrypt.AES_256_CFB, constants.ARG_PASSWORD: '******' } config = Namespace(**_args) # Register the socket to wait for data connect_coro = loop.create_connection( lambda: ShadowsocksProxyServerProtocol(loop, config), sock=lsock) transport, protocol = loop.run_until_complete(connect_coro) cipher_method = encrypt.AES_256_CFB password = '******' encoder = encoder = ShadowsocksEncryptionWrapperEncoder( encrypt_method=cipher_method, password=password, encript_mode=True) decoder = ShadowsocksEncryptionWrapperEncoder( encrypt_method=cipher_method, password=password, encript_mode=False) packer = StreamPacker() protocol.loop = loop header = ShadowsocksPacketHeader( addr='example.com', port=80, addr_type=constants.SOCKS5_ADDRTYPE_HOST) http_request_content = b'GET / HTTP/1.1\r\nHost: example.com\r\nUser-Agent: curl/7.43.0\r\nAccept: */*\r\n\r\n' # Simulate the reception of data from the network encoded_data = packer.pack(header=header, data=http_request_content) encoded_data = encoder.encode(encoded_data) loop.call_soon(rsock.send, encoded_data) def reader(): data = rsock.recv(100) if not data or len(data) == 0: return data = decoder.decode(data) _, http_response_content = packer.unpack(data, header=None) self.assertEqual(http_response_content[:4], b'HTTP') # We are done: unregister the file descriptor loop.remove_reader(rsock) lsock.close() rsock.close() # Stop the event loop loop.stop() # Register the file descriptor for read event loop.add_reader(rsock, reader) # Run the event loop loop.run_forever()
def test_client(self): # Create a pair of connected sockets lsock, rsock = socketpair() loop = asyncio.get_event_loop() _args = { constants.ARG_CIPHER_METHOD: encrypt.AES_256_CFB, constants.ARG_PASSWORD: '******' } config = Namespace(**_args) # Register the socket to wait for data connect_coro = loop.create_connection( lambda: ShadowsocksProxyServerProtocol(loop, config), sock=rsock) _, server_protocol = loop.run_until_complete(connect_coro) def data_callback(client, data): self.assertEqual(data[:4], b'HTTP') lsock.close() rsock.close() # Stop the event loop loop.stop() def conn_lost_callback(*args): pass connect_coro = loop.create_connection( lambda: ShadowsocksClientRelayProtocol(data_callback, conn_lost_callback, config), sock=lsock) _, client_protocol = loop.run_until_complete(connect_coro) header = ShadowsocksPacketHeader( addr='example.com', port=80, addr_type=constants.SOCKS5_ADDRTYPE_HOST) http_request_content = b'GET / HTTP/1.1\r\nHost: example.com\r\nUser-Agent: curl/7.43.0\r\nAccept: */*\r\n\r\n' client_protocol.send_data(header.to_bytes() + http_request_content) # Simulate the reception of data from the network # loop.call_soon(rsock.send, encoded_data) # Run the event loop loop.run_forever()
def data_received(self, data): if self.decoder: data = self.decoder.decode(data) if not self.relay_target_addr: try: self.relay_target_addr, data = self.stream_packer.unpack( data, header=ShadowsocksPacketHeader()) except AttributeError: settings.PROTO_LOG.error( 'parsing header error from %s:%d', *self.transport.get_extra_info('peername')) self.transport.close() else: if not self.relay_target_addr: # need more data to be a header return else: _, data = self.stream_packer.unpack(data) if not data: return if self.relay_state == constants.RELAY_STATE_CONECTED: # TODO: inspect the relay client' connection status, try to reconnect if disconn asyncio.ensure_future(self.send_data_to_remote(self.client, data), loop=self.loop) elif self.relay_state == constants.RELAY_STATE_CONNECTING: settings.PROTO_LOG.error( 'unexpected state: receive data before connection completes') elif self.relay_state == constants.RELAY_STATE_NOT_CONNECTED: f = asyncio.ensure_future(self.set_up_relay( self.relay_target_addr.addr, self.relay_target_addr.port), loop=self.loop) self.relay_state = constants.RELAY_STATE_CONNECTING def send_data(future): succed = future.result() if succed: self.relay_state = constants.RELAY_STATE_CONECTED asyncio.ensure_future(self.send_data_to_remote( self.client, data), loop=self.loop) else: self.relay_state = constants.RELAY_STATE_NOT_CONNECTED settings.PROTO_LOG.warning( 'can not create relay connection to %s:%d', self.relay_target_addr.addr, self.relay_target_addr.port) self.transport.close() f.add_done_callback(send_data)
def test_client(self): # Create a pair of connected sockets lsock, rsock = socketpair() loop = asyncio.get_event_loop() _args = {constants.ARG_CIPHER_METHOD: encrypt.AES_256_CFB, constants.ARG_PASSWORD: '******'} config = Namespace(**_args) # Register the socket to wait for data connect_coro = loop.create_connection(lambda: ShadowsocksProxyServerProtocol(loop, config), sock=rsock) _, server_protocol = loop.run_until_complete(connect_coro) def data_callback(client, data): self.assertEqual(data[:4], b'HTTP') lsock.close() rsock.close() # Stop the event loop loop.stop() def conn_lost_callback(*args): pass connect_coro = loop.create_connection( lambda: ShadowsocksClientRelayProtocol(data_callback, conn_lost_callback, config), sock=lsock) _, client_protocol = loop.run_until_complete(connect_coro) header = ShadowsocksPacketHeader(addr='example.com', port=80, addr_type=constants.SOCKS5_ADDRTYPE_HOST) http_request_content = b'GET / HTTP/1.1\r\nHost: example.com\r\nUser-Agent: curl/7.43.0\r\nAccept: */*\r\n\r\n' client_protocol.send_data(header.to_bytes() + http_request_content) # Simulate the reception of data from the network # loop.call_soon(rsock.send, encoded_data) # Run the event loop loop.run_forever()
def test_to_bytes_and_from_bytes(self): header1 = ShadowsocksPacketHeader( port=80, addr_type=constants.SOCKS5_ADDRTYPE_HOST, addr='www.google.com') bytes1 = b'\x03\x0ewww.google.com\x00\x50' self.assertEqual(header1.to_bytes(), bytes1) header1_new = ShadowsocksPacketHeader() header1_new.from_bytes(bytes1) self.assertEqual(header1_new, header1) header2 = ShadowsocksPacketHeader( port=53, addr_type=constants.SOCKS5_ADDRTYPE_IPV4, addr='8.8.8.8') bytes2 = b'\x01\x08\x08\x08\x08\x00\x35' self.assertEqual(header2.to_bytes(), bytes2) header2_new = ShadowsocksPacketHeader() header2_new.from_bytes(bytes2) self.assertEqual(header2_new, header2) header3 = ShadowsocksPacketHeader( port=80, addr_type=constants.SOCKS5_ADDRTYPE_IPV6, addr='2404:6800:4005:805::1011') bytes3 = b'\x04$\x04h\x00@\x05\x08\x05\x00\x00\x00\x00\x00\x00\x10\x11\x00\x50' self.assertEqual(header3.to_bytes(), bytes3) header3_new = ShadowsocksPacketHeader() header3_new.from_bytes(bytes3) self.assertEqual(header3_new, header3)
def test_to_bytes_and_from_bytes(self): header1 = ShadowsocksPacketHeader(port=80, addr_type=constants.SOCKS5_ADDRTYPE_HOST, addr='www.google.com') bytes1 = b'\x03\x0ewww.google.com\x00\x50' self.assertEqual(header1.to_bytes(), bytes1) header1_new = ShadowsocksPacketHeader() header1_new.from_bytes(bytes1) self.assertEqual(header1_new, header1) header2 = ShadowsocksPacketHeader(port=53, addr_type=constants.SOCKS5_ADDRTYPE_IPV4, addr='8.8.8.8') bytes2 = b'\x01\x08\x08\x08\x08\x00\x35' self.assertEqual(header2.to_bytes(), bytes2) header2_new = ShadowsocksPacketHeader() header2_new.from_bytes(bytes2) self.assertEqual(header2_new, header2) header3 = ShadowsocksPacketHeader(port=80, addr_type=constants.SOCKS5_ADDRTYPE_IPV6, addr='2404:6800:4005:805::1011') bytes3 = b'\x04$\x04h\x00@\x05\x08\x05\x00\x00\x00\x00\x00\x00\x10\x11\x00\x50' self.assertEqual(header3.to_bytes(), bytes3) header3_new = ShadowsocksPacketHeader() header3_new.from_bytes(bytes3) self.assertEqual(header3_new, header3)