def pack_auth_data(self, auth_data, buf): data = auth_data data_len = 12 + 4 + 16 + 4 data = data + (struct.pack('<H', self.server_info.overhead) + struct.pack('<H', 0)) mac_key = self.server_info.iv + self.server_info.key check_head = os.urandom(4) self.last_client_hash = hmac.new(mac_key, check_head, self.hashfunc).digest() check_head += self.last_client_hash[:8] if b':' in to_bytes(self.server_info.protocol_param): try: items = to_bytes(self.server_info.protocol_param).split(b':') self.user_key = items[1] uid = struct.pack('<I', int(items[0])) except: uid = os.urandom(4) else: uid = os.urandom(4) if self.user_key is None: self.user_key = self.server_info.key encryptor = encrypt.Encryptor( to_bytes(base64.b64encode(self.user_key)) + self.salt, 'aes-128-cbc', b'\x00' * 16) uid = struct.unpack('<I', uid)[0] ^ struct.unpack('<I', self.last_client_hash[8:12])[0] uid = struct.pack('<I', uid) data = uid + encryptor.encrypt(data)[16:] self.last_server_hash = hmac.new(self.user_key, data, self.hashfunc).digest() data = check_head + data + self.last_server_hash[:4] self.encryptor = encrypt.Encryptor( to_bytes(base64.b64encode(self.user_key)) + to_bytes(base64.b64encode(self.last_client_hash)), 'rc4') return data + self.pack_client_data(buf)
def pack_auth_data(self, auth_data, buf): if len(buf) == 0: return b'' if len(buf) > 400: rnd_len = struct.unpack('<H', os.urandom(2))[0] % 512 else: rnd_len = struct.unpack('<H', os.urandom(2))[0] % 1024 data = auth_data data_len = 7 + 4 + 16 + 4 + len(buf) + (rnd_len + 4) + 4 # data:12b, date_len:2b, rnd_len:2b data = data + struct.pack('<H', data_len) + struct.pack('<H', rnd_len) mac_key = self.server_info['iv'] + self.server_info['key'] uid = os.urandom(4) if self.user_key is None: self.user_key = self.server_info['key'] encryptor = encrypt.Encryptor( to_bytes(base64.b64encode(self.user_key)) + self.salt, 'aes-128-cbc', b'\x00' * 16) data = uid + encryptor.encrypt(data)[16:] #data is:20b data += hmac.new(mac_key, data, self.hashfunc).digest()[:4] check_head = os.urandom(1) check_head += hmac.new(mac_key, check_head, self.hashfunc).digest()[:6] rnd_data = os.urandom(rnd_len) rnd_data += hmac.new(mac_key, rnd_data, self.hashfunc).digest()[:4] data = check_head + data + rnd_data + buf # 7 + 16 + 4 + 4 + rnd_len + len(buf) data += hmac.new(self.user_key, data, self.hashfunc).digest()[:4] # +4 return data
def __init__(self, server, fd_to_handlers, loop, local_sock, config, dns_resolver, is_local): self._server = server self._fd_to_handlers = fd_to_handlers self._loop = loop self._local_sock = local_sock self._remote_sock = None self._config = config self._dns_resolver = dns_resolver self._is_local = is_local # 状态机:初始化 self._stage = STAGE_INIT self._encryptor = encrypt.Encryptor(config['password'], config['method']) self._fastopen_connected = False self._data_to_write_to_local = [] self._data_to_write_to_remote = [] self._upstream_status = WAIT_STATUS_READING self._downstream_status = WAIT_STATUS_INIT self._remote_address = None if is_local: self._chosen_server = self._get_a_server() # 指定一个file描述符 fd_to_handlers[local_sock.fileno()] = self # 非阻塞 local_sock.setblocking(False) # TCP_NODELAY选项禁止Nagle算法。 # Nagle算法通过将未确认的数据存入缓冲区直到蓄足一个包一起发送的方法,来减少主机发送的零碎小数据包的数目。 local_sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1) # loop的定义在哪里,怎么就有一个add方法? loop.add(local_sock, eventloop.POLL_IN | eventloop.POLL_ERR) self.last_activity = 0 # 更新为“最近有活跃的链接”,否则超时 self._update_activity()
def pack_auth_data(self, auth_data, buf): if len(buf) == 0: return b'' if len(buf) > 400: rnd_len = struct.unpack('<H', os.urandom(2))[0] % 512 else: rnd_len = struct.unpack('<H', os.urandom(2))[0] % 1024 data = auth_data data_len = 7 + 4 + 16 + 4 + len(buf) + rnd_len + 4 data = data + struct.pack('<H', data_len) + struct.pack('<H', rnd_len) mac_key = self.server_info.iv + self.server_info.key uid = os.urandom(4) if b':' in to_bytes(self.server_info.protocol_param): try: items = to_bytes(self.server_info.protocol_param).split(b':') self.user_key = self.hashfunc(items[1]).digest() uid = struct.pack('<I', int(items[0])) except: pass if self.user_key is None: self.user_key = self.server_info.key encryptor = encrypt.Encryptor(to_bytes(base64.b64encode(self.user_key)) + self.salt, 'aes-128-cbc', b'\x00' * 16) data = uid + encryptor.encrypt(data)[16:] data += hmac.new(mac_key, data, self.hashfunc).digest()[:4] check_head = os.urandom(1) check_head += hmac.new(mac_key, check_head, self.hashfunc).digest()[:6] data = check_head + data + os.urandom(rnd_len) + buf data += hmac.new(self.user_key, data, self.hashfunc).digest()[:4] return data
def client_udp_pre_encrypt(self, buf): if self.user_key is None: if b':' in to_bytes(self.server_info.protocol_param): try: items = to_bytes( self.server_info.protocol_param).split(':') self.user_key = self.hashfunc(items[1]).digest() self.user_id = struct.pack('<I', int(items[0])) except: pass if self.user_key is None: self.user_id = os.urandom(4) self.user_key = self.server_info.key authdata = os.urandom(3) mac_key = self.server_info.key md5data = hmac.new(mac_key, authdata, self.hashfunc).digest() uid = struct.unpack('<I', self.user_id)[0] ^ struct.unpack( '<I', md5data[:4])[0] uid = struct.pack('<I', uid) rand_len = self.udp_rnd_data_len(md5data, self.random_client) encryptor = encrypt.Encryptor( to_bytes(base64.b64encode(self.user_key)) + to_bytes(base64.b64encode(md5data)), 'rc4') out_buf = encryptor.encrypt(buf) buf = out_buf + os.urandom(rand_len) + authdata + uid return buf + hmac.new(self.user_key, buf, self.hashfunc).digest()[:1]
def __init__(self, server, fd_to_handlers, loop, local_sock, config, dns_resolver, is_local): self._server = server self._fd_to_handlers = fd_to_handlers self._loop = loop self._local_sock = local_sock self._remote_sock = None self._config = config self._dns_resolver = dns_resolver self._is_local = is_local self._stage = STAGE_INIT self._encryptor = encrypt.Encryptor(config['password'], config['method']) self._fastopen_connected = False self._data_to_write_to_local = [] self._data_to_write_to_remote = [] self._upstream_status = WAIT_STATUS_READING self._downstream_status = WAIT_STATUS_INIT self._remote_address = None if is_local: self._chosen_server = self._get_a_server() fd_to_handlers[local_sock.fileno()] = self local_sock.setblocking(False) local_sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1) loop.add(local_sock, eventloop.POLL_IN | eventloop.POLL_ERR) self.last_activity = 0 self._update_activity()
def _handle_local(self, local, event): remote = self._local_to_remote[local] encryptor = self._local_to_encryptor.get(local, None) if event & eventloop.POLL_ERR: self._destroy(local, remote) elif event & eventloop.POLL_IN: try: data = local.recv(BUF_SIZE) if not data: self._destroy(local, remote) else: if not encryptor: try: req = asyncdns.parse_response(data[2:]) if req: logging.info('request %s', req.hostname) except Exception as e: logging.error(e) encryptor = \ encrypt.Encryptor(self._config['password'], self._config['method']) self._local_to_encryptor[local] = encryptor data = self._address_to_send + data data = encryptor.encrypt(data) remote.send(data) except (OSError, IOError) as e: self._destroy(local, self._local_to_remote[local]) logging.error(e)
def pack_auth_data(self, auth_data, buf): if len(buf) == 0: return b'' if len(buf) > 400: rnd_len = struct.unpack('<H', os.urandom(2))[0] % 512 else: rnd_len = struct.unpack('<H', os.urandom(2))[0] % 1024 data = auth_data data_len = 7 + 4 + 16 + 4 + len(buf) + rnd_len + 4 # data:12b, date_len:2b, rnd_len:2b data = data + struct.pack('<H', data_len) + struct.pack('<H', rnd_len) mac_key = self.server_info['iv'] + self.server_info['key'] uid = os.urandom(4) # if b':' in to_bytes(self.server_info['protocol_param']): # try: # items = to_bytes(self.server_info['protocol_param']).split(b':') # self.user_key = self.hashfunc(items[1]).digest() # uid = struct.pack('<I', int(items[0])) # except: # pass if self.user_key is None: self.user_key = self.server_info['key'] encryptor = encrypt.Encryptor( to_bytes(base64.b64encode(self.user_key)) + self.salt, 'aes-128-cbc', b'\x00' * 16) data = uid + encryptor.encrypt(data)[16:] #data is:20b data += hmac.new(mac_key, data, self.hashfunc).digest()[:4] check_head = os.urandom(1) check_head += hmac.new(mac_key, check_head, self.hashfunc).digest()[:6] data = check_head + data + os.urandom( rnd_len) + buf # 7 + 16 + 4 +4 + rnd_len + len(buf) data += hmac.new(self.user_key, data, self.hashfunc).digest()[:4] # +4 return data
def __init__(self, server, fd_to_handlers, loop, local_sock, config, dns_resolver, is_local): self._server = server self._fd_to_handlers = fd_to_handlers self._loop = loop self._local_sock = local_sock self._remote_sock = None self._remote_sock_v6 = None self._remote_udp = False self._config = config self._dns_resolver = dns_resolver # TCP Relay works as either sslocal or ssserver # if is_local, this is sslocal self._is_local = is_local self._stage = STAGE_INIT self._encryptor = encrypt.Encryptor(config['password'], config['method']) self._encrypt_correct = True self._obfs = obfs.obfs(config['obfs']) server_info = obfs.server_info(server.obfs_data) server_info.host = config['server'] server_info.port = server._listen_port server_info.tcp_mss = 1440 server_info.param = config['obfs_param'] self._obfs.set_server_info(server_info) self._protocol = obfs.obfs(config['protocol']) server_info = obfs.server_info(server.protocol_data) server_info.host = config['server'] server_info.port = server._listen_port server_info.tcp_mss = 1440 server_info.param = '' self._protocol.set_server_info(server_info) self._fastopen_connected = False self._data_to_write_to_local = [] self._data_to_write_to_remote = [] self._udp_data_send_buffer = b'' self._upstream_status = WAIT_STATUS_READING self._downstream_status = WAIT_STATUS_INIT self._client_address = local_sock.getpeername()[:2] self._remote_address = None if 'forbidden_ip' in config: self._forbidden_iplist = config['forbidden_ip'] else: self._forbidden_iplist = None if is_local: self._chosen_server = self._get_a_server() fd_to_handlers[local_sock.fileno()] = self local_sock.setblocking(False) local_sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1) loop.add(local_sock, eventloop.POLL_IN | eventloop.POLL_ERR, self._server) self.last_activity = 0 self._update_activity() self._server.add_connection(1)
def client_udp_post_decrypt(self, buf): if len(buf) <= 8: return (b'', None) if hmac.new(self.user_key, buf[:-1], self.hashfunc).digest()[:1] != buf[-1:]: return (b'', None) mac_key = self.server_info.key md5data = hmac.new(mac_key, buf[-8:-1], self.hashfunc).digest() rand_len = self.udp_rnd_data_len(md5data, self.random_server) encryptor = encrypt.Encryptor(to_bytes(base64.b64encode(self.user_key)) + to_bytes(base64.b64encode(md5data)), 'rc4') return encryptor.decrypt(buf[:-8 - rand_len])
def __init__(self, server, fd_to_handlers, loop, local_sock, config, dns_resolver, is_local): """ 建立一个TCP连接后初始化一个Handle专门负责该连接任务 :param server: 与该handler连接的IP地址 :param fd_to_handlers: 建立Socket返回的fd标识符 :param loop: 所属的事件循环 :param local_sock: 与本地服务端的socket链接 :param config: 配置信息 :param dns_resolver: dns服务器 :param is_local: 是否为本地服务端 """ self._server = server self._fd_to_handlers = fd_to_handlers self._loop = loop self._local_sock = local_sock self._remote_sock = None self._config = config self._dns_resolver = dns_resolver # TCP Relay works as either sslocal or ssserver # if is_local, this is sslocal self._is_local = is_local self._stage = STAGE_INIT self._encryptor = encrypt.Encryptor(config['password'], config['method']) self._fastopen_connected = False self._data_to_write_to_local = [] self._data_to_write_to_remote = [] self._upstream_status = WAIT_STATUS_READING self._downstream_status = WAIT_STATUS_INIT self._client_address = local_sock.getpeername()[:2] self._remote_address = None if 'forbidden_ip' in config: self._forbidden_iplist = config['forbidden_ip'] else: self._forbidden_iplist = None if is_local: self._chosen_server = self._get_a_server() fd_to_handlers[local_sock.fileno()] = self local_sock.setblocking(False) local_sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1) loop.add(local_sock, eventloop.POLL_IN | eventloop.POLL_ERR, self._server) self.last_activity = 0 self._update_activity()
def __init__(self, server, fd_to_handlers, loop, local_sock, config, users, dns_resolver, is_local): self._server = server self._fd_to_handlers = fd_to_handlers self._loop = loop self._local_sock = local_sock self._remote_sock = None self._config = config self._users = users self._dns_resolver = dns_resolver # TCP Relay works as either sslocal or ssserver # if is_local, this is sslocal self._is_local = is_local self._stage = STAGE_INIT self._encryptor = None if is_local: self._encryptor = encrypt.Encryptor(config['password'], config['method']) self._vendor_encryptor = encrypt.Encryptor(self._config['vendor_key'], self._config['method']) self._fastopen_connected = False self._auth_header_buffer = b'' self._data_to_write_to_local = [] self._data_to_write_to_remote = [] self._upstream_status = WAIT_STATUS_READING self._downstream_status = WAIT_STATUS_INIT self._client_address = local_sock.getpeername()[:2] self._remote_address = None if 'forbidden_ip' in config: self._forbidden_iplist = config['forbidden_ip'] else: self._forbidden_iplist = None if is_local: self._chosen_server = self._get_a_server() fd_to_handlers[local_sock.fileno()] = self local_sock.setblocking(False) local_sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1) loop.add(local_sock, eventloop.POLL_IN | eventloop.POLL_ERR) self.last_activity = 0 self._update_activity()
def __init__(self, server, fd_to_handlers, loop, local_sock, config, dns_resolver, is_local): self._server = server self._fd_to_handlers = fd_to_handlers self._loop = loop # _local_sock is # for sslocal, a socket connected to client # for ssremote, a socket connected to sslocal # _remote_sock is # for sslocal, a socket connected to ssremote # for ssremote, a socket connected to dest self._local_sock = local_sock self._remote_sock = None self._config = config self._dns_resolver = dns_resolver # TCP Relay works as either sslocal or ssserver # if is_local, this is sslocal self._is_local = is_local self._stage = STAGE_INIT self._encryptor = encrypt.Encryptor(config['password'], config['method']) self._fastopen_connected = False self._data_to_write_to_local = [] self._data_to_write_to_remote = [] self._upstream_status = WAIT_STATUS_READING self._downstream_status = WAIT_STATUS_INIT self._client_address = local_sock.getpeername()[:2] self._remote_address = None if 'forbidden_ip' in config: self._forbidden_iplist = config['forbidden_ip'] else: self._forbidden_iplist = None if is_local: self._chosen_server = self._get_a_server() fd_to_handlers[local_sock.fileno()] = self local_sock.setblocking(False) local_sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1) # add() sets event and handler for f # note that the 3rd arg of add() is handler # _server is an implicit arg parsed to TCPRelayHandler? # then in eventloop.run() # use handler.handle_event() to handle f with specific event loop.add(local_sock, eventloop.POLL_IN | eventloop.POLL_ERR, self._server) self.last_activity = 0 self._update_activity()
def __init__(self, server, fd_to_handlers, loop, local_sock, config, dns_resolver, is_local): # 创建当前对象的TCPRelay对象 self._server = server self._fd_to_handlers = fd_to_handlers self._loop = loop # 与ss client的socket连接 self._local_sock = local_sock self._remote_sock = None self._config = config self._dns_resolver = dns_resolver # TCP Relay works as either sslocal or ssserver # if is_local, this is sslocal self._is_local = is_local # 请注意初始状态值 self._stage = STAGE_INIT self._encryptor = encrypt.Encryptor(config['password'], config['method']) self._ota_enable = config.get('one_time_auth', False) self._ota_enable_session = self._ota_enable self._ota_buff_head = b'' self._ota_buff_data = b'' self._ota_len = 0 self._ota_chunk_idx = 0 self._fastopen_connected = False self._data_to_write_to_local = [] self._data_to_write_to_remote = [] self._upstream_status = WAIT_STATUS_READING self._downstream_status = WAIT_STATUS_INIT self._client_address = local_sock.getpeername()[:2] self._remote_address = None self._forbidden_iplist = config.get('forbidden_ip') if is_local: self._chosen_server = self._get_a_server() # ... # 将socket(与ss client连接)加入到TCPRelay的fd_to_handlers的字典中 # 此时字典里只有一项(假定当前是第一个也是唯一一个ss client的连接) # 即ss client与ss server的连接socket fd_to_handlers[local_sock.fileno()] = self local_sock.setblocking(False) local_sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1) # 将与ss client连接的socket注册至EventLoop。首先注册的是POLL_IN事件 # socket被添加到EventLoop的字典_fdmap中 loop.add(local_sock, eventloop.POLL_IN | eventloop.POLL_ERR, self._server) self.last_activity = 0 # 更新活动信息,以免被TCPRelay清理 self._update_activity()
def __init__(self, server, fd_to_handlers, loop, local_sock, config, dns_resolver, is_local): self._server = server self._fd_to_handlers = fd_to_handlers self._loop = loop self._local_sock = local_sock self._remote_sock = None self._config = config self._dns_resolver = dns_resolver # TCP Relay works as either sslocal or ssserver # if is_local, this is sslocal self._is_local = is_local self._stage = STAGE_INIT self._encryptor = encrypt.Encryptor(config['password'], config['method']) if 'one_time_auth' in config and config['one_time_auth']: self._ota_enable = True else: self._ota_enable = False self._ota_buff_head = b'' self._ota_buff_data = b'' self._ota_len = 0 self._ota_chunk_idx = 0 self._fastopen_connected = False self._data_to_write_to_local = [] self._data_to_write_to_remote = [] # upstream 数据从client->sserver->web,为WRITING输出到remote_sock,为READING读取local_sock self._upstream_status = WAIT_STATUS_READING # downstream 数据从web->ssserver->client,为WRITTING输出到local_sock,为READING读取remote_sock self._downstream_status = WAIT_STATUS_INIT self._client_address = local_sock.getpeername()[:2] self._remote_address = None if 'forbidden_ip' in config: self._forbidden_iplist = config['forbidden_ip'] else: self._forbidden_iplist = None if is_local: self._chosen_server = self._get_a_server() fd_to_handlers[local_sock.fileno()] = self # 注册socket local_sock.setblocking(False) local_sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1) # 添加到事件循环loop loop.add(local_sock, eventloop.POLL_IN | eventloop.POLL_ERR, self._server) self.last_activity = 0 # 上一次活动的时间 # 下面的函数就是更新这个变量 self._update_activity()
def __init__(self, server, fd_to_handlers, loop, local_sock, config, dns_resolver, is_local): self._server = server self._fd_to_handlers = fd_to_handlers self._loop = loop self._local_sock = local_sock self._remote_sock = None self._config = config self._dns_resolver = dns_resolver # TCP Relay works as either sslocal or ssserver # if is_local, this is sslocal self._is_local = is_local self._stage = STAGE_INIT self._encryptor = encrypt.Encryptor(config['password'], config['method']) self._fastopen_connected = False self._data_to_write_to_local = [] self._data_to_write_to_remote = [] self._upstream_status = WAIT_STATUS_READING self._downstream_status = WAIT_STATUS_INIT self._client_address = local_sock.getpeername()[:2] self._remote_address = None if 'forbidden_ip' in config: self._forbidden_iplist = config['forbidden_ip'] else: self._forbidden_iplist = None if is_local: self._chosen_server = self._get_a_server() self._user_valid = True if 'socks_auth' in config and type( config['socks_auth']) == list and len( config['socks_auth']) > 1: self._username = config['socks_auth'][0] self._userpass = config['socks_auth'][1] self._user_valid = False self._reply_to_wrong_pass = False self._valid_stage = 0 if len(config['socks_auth']) >= 3 and int( config['socks_auth'][2]) == 1: self._reply_to_wrong_pass = True fd_to_handlers[local_sock.fileno()] = self local_sock.setblocking(False) local_sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1) loop.add(local_sock, eventloop.POLL_IN | eventloop.POLL_ERR, self._server) self.last_activity = 0 self._update_activity()
def __init__(self, server, fd_to_handlers, loop, local_sock, config, dns_resolver, is_local): self._server = server self._fd_to_handlers = fd_to_handlers # 封装好的事件轮询器 self._loop = loop # 接收/发送本地数据的socket self._local_sock = local_sock # 接收/发送远程数据的socket self._remote_sock = None # 初始化配置 self._config = config # 封装好的DNS查询器 self._dns_resolver = dns_resolver # TCP Relay works as either sslocal or ssserver # if is_local, this is sslocal self._is_local = is_local # 初始化状态机 self._stage = STAGE_INIT self._encryptor = encrypt.Encryptor(config['password'], config['method']) self._fastopen_connected = False # 发送以及接收缓冲列表 self._data_to_write_to_local = [] self._data_to_write_to_remote = [] # 初始化流状态,决定了是否监听相应的事件 self._upstream_status = WAIT_STATUS_READING self._downstream_status = WAIT_STATUS_INIT self._client_address = local_sock.getpeername()[:2] self._remote_address = None if 'forbidden_ip' in config: self._forbidden_iplist = config['forbidden_ip'] else: self._forbidden_iplist = None # 若是sslocal,则随机选择一个服务器 if is_local: self._chosen_server = self._get_a_server() fd_to_handlers[local_sock.fileno()] = self local_sock.setblocking(False) local_sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1) # 事件轮询开始监听该socket loop.add(local_sock, eventloop.POLL_IN | eventloop.POLL_ERR, self._server) self.last_activity = 0 self._update_activity()
def __init__(self, server, fd_to_handlers, loop, local_sock, config, dns_resolver, is_local): # 这里的_server被赋予了一个TCPRelay object self._server = server # 此处fd_to_handlers参数来自TCPRelay对象的_fd_to_handlers,初始为{} self._fd_to_handlers = fd_to_handlers self._loop = loop self._local_sock = local_sock # _remote_sock指是ssserver与真正目标服务器(如Google,FaceBook等)的socket self._remote_sock = None self._config = config self._dns_resolver = dns_resolver # TCP Relay works as either sslocal or ssserver # if is_local, this is sslocal self._is_local = is_local self._stage = STAGE_INIT self._encryptor = encrypt.Encryptor(config['password'], config['method']) self._fastopen_connected = False self._data_to_write_to_local = [] self._data_to_write_to_remote = [] # UP和DOWN两个方向的流的初始状态不同 self._upstream_status = WAIT_STATUS_READING self._downstream_status = WAIT_STATUS_INIT # socket.getpeername()返回socket对端(也就是client端)的(hostaddr, port) self._client_address = local_sock.getpeername()[:2] self._remote_address = None if 'forbidden_ip' in config: self._forbidden_iplist = config['forbidden_ip'] else: self._forbidden_iplist = None if is_local: self._chosen_server = self._get_a_server() # 更新_fd_to_handlers fd_to_handlers[local_sock.fileno()] = self local_sock.setblocking(False) # TCP_NODELAY选项关闭Nagle算法, 现在的TCP/IP协议栈默认就关闭Nagle算法 # Nagle算法通俗解释见https://www.zhihu.com/question/42308970 local_sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1) # 这里add的sock是local_sock,但是handler却是_server,也就是说发生事件时,仍然是先 # 调用TCPRelay的handler_event,由其负责分发到不同的local_sock的handler上 loop.add(local_sock, eventloop.POLL_IN | eventloop.POLL_ERR, self._server) self.last_activity = 0 self._update_activity()
def server_udp_pre_encrypt(self, buf, uid): if uid in self.server_info.users: user_key = self.server_info.users[uid] else: uid = None if not self.server_info.users: user_key = self.server_info.key else: user_key = self.server_info.recv_iv authdata = os.urandom(7) mac_key = self.server_info.key md5data = hmac.new(mac_key, authdata, self.hashfunc).digest() rand_len = self.udp_rnd_data_len(md5data, self.random_server) encryptor = encrypt.Encryptor(to_bytes(base64.b64encode(user_key)) + to_bytes(base64.b64encode(md5data)), 'rc4') out_buf = encryptor.encrypt(buf) buf = out_buf + os.urandom(rand_len) + authdata return buf + hmac.new(user_key, buf, self.hashfunc).digest()[:1]
def server_udp_post_decrypt(self, buf): mac_key = self.server_info.key md5data = hmac.new(mac_key, buf[-8:-5], self.hashfunc).digest() uid = struct.unpack('<I', buf[-5:-1])[0] ^ struct.unpack('<I', md5data[:4])[0] if uid in self.server_info.users: user_key = self.server_info.users[uid]['passwd'].encode('utf-8') else: uid = None if not self.server_info.users: user_key = self.server_info.key else: user_key = self.server_info.recv_iv if hmac.new(user_key, buf[:-1], self.hashfunc).digest()[:1] != buf[-1:]: return (b'', None) rand_len = self.udp_rnd_data_len(md5data, self.random_client) encryptor = encrypt.Encryptor(to_bytes(base64.b64encode(user_key)) + to_bytes(base64.b64encode(md5data)), 'rc4') out_buf = encryptor.decrypt(buf[:-8 - rand_len]) return (out_buf, uid)
def __init__(self, local_sock, local_addr, remote_addr=None, dns_resolver=None): self._loop = None self._local_sock = local_sock self._local_addr = local_addr self._remote_addr = remote_addr # self._crypt = None self._crypt = encrypt.Encryptor(b'PassThrouthGFW', 'aes-256-cfb') self._dns_resolver = dns_resolver self._remote_sock = None self._local_sock_mode = 0 self._remote_sock_mode = 0 self._data_to_write_to_local = [] self._data_to_write_to_remote = [] self._id = id(self)
def __init__(self, server, fd_to_handlers, loop, local_sock, config, dns_resolver, is_local): self._server = server self._fd_to_handlers = fd_to_handlers self._loop = loop self._local_sock = local_sock self._remote_sock = None self._config = config self._dns_resolver = dns_resolver self.tunnel_remote = config.get('tunnel_remote', "8.8.8.8") self.tunnel_remote_port = config.get('tunnel_remote_port', 53) self.tunnel_port = config.get('tunnel_port', 53) self._is_tunnel = server._is_tunnel # TCP Relay works as either sslocal or ssserver # if is_local, this is sslocal self._is_local = is_local self._stage = STAGE_INIT self._encryptor = encrypt.Encryptor(config['password'], config['method']) self._ota_enable = config.get('one_time_auth', False) self._ota_enable_session = self._ota_enable self._ota_buff_head = b'' self._ota_buff_data = b'' self._ota_len = 0 self._ota_chunk_idx = 0 self._fastopen_connected = False self._data_to_write_to_local = [] self._data_to_write_to_remote = [] self._upstream_status = WAIT_STATUS_READING self._downstream_status = WAIT_STATUS_INIT self._client_address = local_sock.getpeername()[:2] self._remote_address = None self._forbidden_iplist = config.get('forbidden_ip') if is_local: self._chosen_server = self._get_a_server() fd_to_handlers[local_sock.fileno()] = self local_sock.setblocking(False) local_sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1) loop.add(local_sock, eventloop.POLL_IN | eventloop.POLL_ERR, self._server) self.last_activity = 0 self._update_activity()
def __init__(self, local_sock, local_addr, method, password, remote_addr=None, dns_resolver=None): self._loop = None self._local_sock = local_sock self._local_addr = local_addr self._remote_addr = remote_addr # self._crypt = None self._crypt = encrypt.Encryptor(password.encode('utf-8'), method) self._dns_resolver = dns_resolver self._remote_sock = None self._local_sock_mode = 0 self._remote_sock_mode = 0 self._data_to_write_to_local = [] self._data_to_write_to_remote = [] self._id = id(self)
def __init__(self, server, fd_to_handlers, loop, local_sock, config, dns_resolver, is_local): self._server = server self._fd_to_handlers = fd_to_handlers self._loop = loop self._local_sock = local_sock self._remote_sock = None self._config = config self._dns_resolver = dns_resolver # TCP Relay works as either sslocal or ssserver # if is_local, this is sslocal self._is_local = is_local self._stage = STAGE_INIT self._encryptor = encrypt.Encryptor(config['password'], config['method']) self._fastopen_connected = False self._data_to_write_to_local = [] self._data_to_write_to_remote = [] self._upstream_status = WAIT_STATUS_READING self._downstream_status = WAIT_STATUS_INIT self._client_address = local_sock.getpeername()[:2] self._remote_address = None if 'forbidden_ip' in config: self._forbidden_iplist = config['forbidden_ip'] else: self._forbidden_iplist = None if is_local: self._chosen_server = self._get_a_server() fd_to_handlers[local_sock.fileno()] = self local_sock.setblocking(False) if sys.platform.startswith('linux') and 'cc_algo' in config: TCP_CONGESTION = getattr(socket, 'TCP_CONGESTION', 13) local_sock.setsockopt(socket.IPPROTO_TCP, TCP_CONGESTION, config['cc_algo']) local_sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1) loop.add(local_sock, eventloop.POLL_IN | eventloop.POLL_ERR, self._server) self.last_activity = 0 self._update_activity()
def __init__(self, server, fd_to_handlers, loop, local_sock, config, dns_resolver, terminal_type): self._server = server self._protocol_type = protocol.ProtocolType.TCP self._protocol_request = None self._protocol_response = None self._content_type = None self._fd_to_handlers = fd_to_handlers self._loop = loop self._local_sock = local_sock self._remote_sock = None self._config = config self._dns_resolver = dns_resolver # TCP Relay works as either sslocal or ssserver # if is_local, this is sslocal self._terminal_type = terminal_type self._stage = STAGE_INIT self._encryptor = encrypt.Encryptor(config['password'], config['method']) self._fastopen_connected = False self._data_to_write_to_local = [] self._data_to_write_to_remote = [] self._upstream_status = WAIT_STATUS_READING self._downstream_status = WAIT_STATUS_INIT self._client_address = local_sock.getpeername()[:2] self._remote_address = None if 'forbidden_ip' in config: self._forbidden_iplist = config['forbidden_ip'] else: self._forbidden_iplist = None if terminal_type == terminal.TerminalType.Local: self._chosen_server = self._get_a_server() fd_to_handlers[local_sock.fileno()] = self local_sock.setblocking(False) local_sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1) loop.add(local_sock, eventloop.POLL_IN | eventloop.POLL_ERR) self.last_activity = 0 self._update_activity()
async def socks5_handle(client, addr): print('accept:', addr) async with client: data = await client.recv(3) assert data == b'\x05\x01\x00', 'auth err' await client.sendall(b'\x05\x00') data = await client.recv(5) assert data[:4] == b'\x05\x01\x00\x03', 'addr1 err' ln = data[4] data = await client.recv(data[4] + 2) remote = socket(AF_INET, SOCK_STREAM) host, port = '', 16813 await remote.connect((host, port)) addr_data = b'\x03' + chr(ln).encode() + data enc = encryptx.Encryptor('woshimima1234', 'aes-256-cfb') await remote.sendall(enc.encrypt(addr_data)) await client.sendall(b'\x05\x00\x00\x01\x00\x00\x00\x00\x10\x10') async with TaskGroup() as group: await group.spawn(pipe, client, remote, enc.encrypt) await group.spawn(pipe, remote, client, enc.decrypt) print('pipe: %r <-> %r' % tuple([s.getsockname() for s in (client, remote)])) print('closed:', addr)
def __init__(self, server, fd_to_handlers, loop, local_sock, config, dns_resolver, is_local): self._server = server self._fd_to_handlers = fd_to_handlers self._loop = loop self._local_sock = local_sock self._remote_sock = None self._config = config self._dns_resolver = dns_resolver # TCP Relay works as either sslocal or ssserver or ssrelay # if is_local, this is sslocal # if is_relay, this is ssrelay which relay data only self._is_relay = config.get('is_relay', False) self._is_local = is_local self._stage = STAGE_INIT self._encryptor = encrypt.Encryptor(config['password'], config['method']) self._fastopen_connected = False self._data_to_write_to_local = [] self._data_to_write_to_remote = [] self._upstream_status = WAIT_STATUS_READING self._downstream_status = WAIT_STATUS_INIT self._client_address = local_sock.getpeername()[:2] self._remote_address = None self._forbidden_iplist = config.get('forbidden_ip', None) self._blackurl = config.get('blackurl', None) self._data_len_to_relay = 0 if self._is_local or self._is_relay: self._chosen_server = self._get_a_server() fd_to_handlers[local_sock.fileno()] = self local_sock.setblocking(False) local_sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1) loop.add(local_sock, eventloop.POLL_IN | eventloop.POLL_ERR, self._server) self.last_activity = 0 self._update_activity()
def server_post_decrypt(self, buf): if self.raw_trans: return (buf, False) self.recv_buf += buf out_buf = b'' sendback = False if not self.has_recv_header: if len(self.recv_buf) >= 7 or len(self.recv_buf) in [2, 3]: recv_len = min(len(self.recv_buf), 7) mac_key = self.server_info.recv_iv + self.server_info.key sha1data = hmac.new(mac_key, self.recv_buf[:1], self.hashfunc).digest()[:recv_len - 1] if sha1data != self.recv_buf[1:recv_len]: return self.not_match_return(self.recv_buf) if len(self.recv_buf) < 31: return (b'', False) sha1data = hmac.new(mac_key, self.recv_buf[7:27], self.hashfunc).digest()[:4] if sha1data != self.recv_buf[27:31]: logging.error('%s data uncorrect auth HMAC-SHA1 from %s:%d, data %s' % (self.no_compatible_method, self.server_info.client, self.server_info.client_port, binascii.hexlify(self.recv_buf))) if len(self.recv_buf) < 31 + self.extra_wait_size: return (b'', False) return self.not_match_return(self.recv_buf) uid = self.recv_buf[7:11] if uid in self.server_info.users: self.user_id = uid self.user_key = self.hashfunc(self.server_info.users[uid]).digest() self.server_info.update_user_func(uid) else: if not self.server_info.users: self.user_key = self.server_info.key else: self.user_key = self.server_info.recv_iv encryptor = encrypt.Encryptor(to_bytes(base64.b64encode(self.user_key)) + self.salt, 'aes-128-cbc') head = encryptor.decrypt(b'\x00' * 16 + self.recv_buf[11:27] + b'\x00') # need an extra byte or recv empty length = struct.unpack('<H', head[12:14])[0] if len(self.recv_buf) < length: return (b'', False) utc_time = struct.unpack('<I', head[:4])[0] client_id = struct.unpack('<I', head[4:8])[0] connection_id = struct.unpack('<I', head[8:12])[0] rnd_len = struct.unpack('<H', head[14:16])[0] if hmac.new(self.user_key, self.recv_buf[:length - 4], self.hashfunc).digest()[:4] != self.recv_buf[length - 4:length]: logging.info('%s: checksum error, data %s' % (self.no_compatible_method, binascii.hexlify(self.recv_buf[:length]))) return self.not_match_return(self.recv_buf) time_dif = common.int32(utc_time - (int(time.time()) & 0xffffffff)) if time_dif < -self.max_time_dif or time_dif > self.max_time_dif: logging.info('%s: wrong timestamp, time_dif %d, data %s' % (self.no_compatible_method, time_dif, binascii.hexlify(head))) return self.not_match_return(self.recv_buf) elif self.server_info.data.insert(self.user_id, client_id, connection_id): self.has_recv_header = True out_buf = self.recv_buf[31 + rnd_len:length - 4] self.client_id = client_id self.connection_id = connection_id else: logging.info('%s: auth fail, data %s' % (self.no_compatible_method, binascii.hexlify(out_buf))) return self.not_match_return(self.recv_buf) self.recv_buf = self.recv_buf[length:] self.has_recv_header = True sendback = True while len(self.recv_buf) > 4: mac_key = self.user_key + struct.pack('<I', self.recv_id) mac = hmac.new(mac_key, self.recv_buf[:2], self.hashfunc).digest()[:2] if mac != self.recv_buf[2:4]: self.raw_trans = True logging.info(self.no_compatible_method + ': wrong crc') if self.recv_id == 0: logging.info(self.no_compatible_method + ': wrong crc') return (b'E'*2048, False) else: raise Exception('server_post_decrype data error') length = struct.unpack('<H', self.recv_buf[:2])[0] if length >= 8192 or length < 7: self.raw_trans = True self.recv_buf = b'' if self.recv_id == 0: logging.info(self.no_compatible_method + ': over size') return (b'E'*2048, False) else: raise Exception('server_post_decrype data error') if length > len(self.recv_buf): break if hmac.new(mac_key, self.recv_buf[:length - 4], self.hashfunc).digest()[:4] != self.recv_buf[length - 4:length]: logging.info('%s: checksum error, data %s' % (self.no_compatible_method, binascii.hexlify(self.recv_buf[:length]))) self.raw_trans = True self.recv_buf = b'' if self.recv_id == 0: return (b'E'*2048, False) else: raise Exception('server_post_decrype data uncorrect checksum') self.recv_id = (self.recv_id + 1) & 0xFFFFFFFF pos = common.ord(self.recv_buf[4]) if pos < 255: pos += 4 else: pos = struct.unpack('<H', self.recv_buf[5:7])[0] + 4 out_buf += self.recv_buf[pos:length - 4] self.recv_buf = self.recv_buf[length:] if pos == length - 4: sendback = True if out_buf: self.server_info.data.update(self.user_id, self.client_id, self.connection_id) return (out_buf, sendback)
def __init__(self, server, fd_to_handlers, loop, local_sock, config, dns_resolver, is_local): self._server = server self._fd_to_handlers = fd_to_handlers self._loop = loop self._local_sock = local_sock self._remote_sock = None self._remote_sock_v6 = None self._remote_udp = False self._config = config self._dns_resolver = dns_resolver # TCP Relay works as either sslocal or ssserver # if is_local, this is sslocal self._is_local = is_local self._stage = STAGE_INIT try: self._encryptor = encrypt.Encryptor(config['password'], config['method']) except Exception: self._stage = STAGE_DESTROYED logging.error('creater encryptor fail at port %d', server._listen_port) return self._encrypt_correct = True self._obfs = obfs.obfs(config['obfs']) server_info = obfs.server_info(server.obfs_data) server_info.host = config['server'] server_info.port = server._listen_port server_info.protocol_param = '' server_info.obfs_param = config['obfs_param'] server_info.iv = self._encryptor.cipher_iv server_info.recv_iv = b'' server_info.key = self._encryptor.cipher_key server_info.head_len = 30 server_info.tcp_mss = 1440 self._obfs.set_server_info(server_info) self._protocol = obfs.obfs(config['protocol']) server_info = obfs.server_info(server.protocol_data) server_info.host = config['server'] server_info.port = server._listen_port server_info.protocol_param = config['protocol_param'] server_info.obfs_param = '' server_info.iv = self._encryptor.cipher_iv server_info.recv_iv = b'' server_info.key = self._encryptor.cipher_key server_info.head_len = 30 server_info.tcp_mss = 1440 self._protocol.set_server_info(server_info) self._redir_list = config.get('redirect', ["0.0.0.0:0"]) self._bind = config.get('out_bind', '') self._bindv6 = config.get('out_bindv6', '') self._ignore_bind_list = config.get('ignore_bind', []) self._fastopen_connected = False self._data_to_write_to_local = [] self._data_to_write_to_remote = [] self._udp_data_send_buffer = b'' self._upstream_status = WAIT_STATUS_READING self._downstream_status = WAIT_STATUS_INIT self._client_address = local_sock.getpeername()[:2] self._accept_address = local_sock.getsockname()[:2] self._remote_address = None if 'forbidden_ip' in config: self._forbidden_iplist = config['forbidden_ip'] else: self._forbidden_iplist = None if is_local: self._chosen_server = self._get_a_server() fd_to_handlers[local_sock.fileno()] = self local_sock.setblocking(False) local_sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1) loop.add(local_sock, eventloop.POLL_IN | eventloop.POLL_ERR, self._server) self.last_activity = 0 self._update_activity() self._server.add_connection(1) self._server.stat_add(self._client_address[0], 1)
def server_post_decrypt(self, buf): if self.raw_trans: return (buf, False) self.recv_buf += buf out_buf = b'' sendback = False if not self.has_recv_header: if len(self.recv_buf) >= 12 or len(self.recv_buf) in [7, 8]: recv_len = min(len(self.recv_buf), 12) mac_key = self.server_info.recv_iv + self.server_info.key md5data = hmac.new(mac_key, self.recv_buf[:4], self.hashfunc).digest() if md5data[:recv_len - 4] != self.recv_buf[4:recv_len]: return self.not_match_return(self.recv_buf) if len(self.recv_buf) < 12 + 24: return (b'', False) self.last_client_hash = md5data uid = struct.unpack('<I', self.recv_buf[12:16])[0] ^ struct.unpack( '<I', md5data[8:12])[0] self.user_id_num = uid uid = struct.pack('<I', uid) if uid in self.server_info.users: self.user_id = uid self.user_key = self.server_info.users[uid] self.server_info.update_user_func(uid) else: self.user_id_num = 0 if not self.server_info.users: self.user_key = self.server_info.key else: self.user_key = self.server_info.recv_iv md5data = hmac.new(self.user_key, self.recv_buf[12:12 + 20], self.hashfunc).digest() if md5data[:4] != self.recv_buf[32:36]: logging.error( '%s data uncorrect auth HMAC-MD5 from %s:%d, data %s' % (self.no_compatible_method, self.server_info.client, self.server_info.client_port, binascii.hexlify(self.recv_buf))) if len(self.recv_buf) < 36: return (b'', False) return self.not_match_return(self.recv_buf) self.last_server_hash = md5data encryptor = encrypt.Encryptor( to_bytes(base64.b64encode(self.user_key)) + self.salt, 'aes-128-cbc') head = encryptor.decrypt( b'\x00' * 16 + self.recv_buf[16:32] + b'\x00') # need an extra byte or recv empty self.client_over_head = struct.unpack('<H', head[12:14])[0] utc_time = struct.unpack('<I', head[:4])[0] client_id = struct.unpack('<I', head[4:8])[0] connection_id = struct.unpack('<I', head[8:12])[0] time_dif = common.int32(utc_time - (int(time.time()) & 0xffffffff)) if time_dif < -self.max_time_dif or time_dif > self.max_time_dif: logging.info('%s: wrong timestamp, time_dif %d, data %s' % (self.no_compatible_method, time_dif, binascii.hexlify(head))) return self.not_match_return(self.recv_buf) elif self.server_info.data.insert(self.user_id, client_id, connection_id): self.has_recv_header = True self.client_id = client_id self.connection_id = connection_id else: logging.info( '%s: auth fail, data %s' % (self.no_compatible_method, binascii.hexlify(out_buf))) return self.not_match_return(self.recv_buf) self.encryptor = encrypt.Encryptor( to_bytes(base64.b64encode(self.user_key)) + to_bytes(base64.b64encode(self.last_client_hash)), 'rc4') self.recv_buf = self.recv_buf[36:] self.has_recv_header = True sendback = True while len(self.recv_buf) > 4: mac_key = self.user_key + struct.pack('<I', self.recv_id) data_len = struct.unpack('<H', self.recv_buf[:2])[0] ^ struct.unpack( '<H', self.last_client_hash[14:16])[0] rand_len = self.rnd_data_len(data_len, self.last_client_hash, self.random_client) length = data_len + rand_len if length >= 4096: self.raw_trans = True self.recv_buf = b'' if self.recv_id == 0: logging.info(self.no_compatible_method + ': over size') return (b'E' * 2048, False) else: raise Exception('server_post_decrype data error') if length + 4 > len(self.recv_buf): break client_hash = hmac.new(mac_key, self.recv_buf[:length + 2], self.hashfunc).digest() if client_hash[:2] != self.recv_buf[length + 2:length + 4]: logging.info('%s: checksum error, data %s' % (self.no_compatible_method, binascii.hexlify(self.recv_buf[:length]))) self.raw_trans = True self.recv_buf = b'' if self.recv_id == 0: return (b'E' * 2048, False) else: raise Exception( 'server_post_decrype data uncorrect checksum') self.recv_id = (self.recv_id + 1) & 0xFFFFFFFF pos = 2 if data_len > 0 and rand_len > 0: pos = 2 + self.rnd_start_pos(rand_len, self.random_client) out_buf += self.encryptor.decrypt(self.recv_buf[pos:data_len + pos]) self.last_client_hash = client_hash self.recv_buf = self.recv_buf[length + 4:] if data_len == 0: sendback = True if out_buf: self.server_info.data.update(self.user_id, self.client_id, self.connection_id) return (out_buf, sendback)