def _handle_server(self): server = self._server_socket data, r_addr = server.recvfrom(BUF_SIZE) key = None iv = None if not data: logging.debug('UDP handle_server: data is empty') if self._stat_callback: self._stat_callback(self._listen_port, len(data)) if self._is_local: frag = common.ord(data[2]) if frag != 0: logging.warn('UDP drop a message since frag is not 0') return else: data = data[3:] else: data, key, iv = encrypt.dencrypt_all(self._password, self._method, data) # decrypt data if not data: logging.debug( 'UDP handle_server: data is empty after decrypt' ) return header_result = parse_header(data) if header_result is None: return addrtype, dest_addr, dest_port, header_length = header_result if self._is_local: server_addr, server_port = self._get_a_server() else: server_addr, server_port = dest_addr, dest_port # spec https://shadowsocks.org/en/spec/one-time-auth.html if self._one_time_auth_enable or addrtype & ADDRTYPE_AUTH: if len(data) < header_length + ONETIMEAUTH_BYTES: logging.warn('UDP one time auth header is too short') return _hash = data[-ONETIMEAUTH_BYTES:] data = data[: -ONETIMEAUTH_BYTES] _key = iv + key if onetimeauth_verify(_hash, data, _key) is False: logging.warn('UDP one time auth fail') return addrs = self._dns_cache.get(server_addr, None) if addrs is None: addrs = socket.getaddrinfo(server_addr, server_port, 0, socket.SOCK_DGRAM, socket.SOL_UDP) if not addrs: # drop return else: self._dns_cache[server_addr] = addrs af, socktype, proto, canonname, sa = addrs[0] key = client_key(r_addr, af) client = self._cache.get(key, None) if not client: # TODO async getaddrinfo if self._forbidden_iplist: if common.to_str(sa[0]) in self._forbidden_iplist: logging.debug('IP %s is in forbidden list, drop' % common.to_str(sa[0])) # drop return client = socket.socket(af, socktype, proto) client.setblocking(False) self._cache[key] = client self._client_fd_to_server_addr[client.fileno()] = r_addr self._sockets.add(client.fileno()) self._eventloop.add(client, eventloop.POLL_IN, self) if self._is_local: key, iv, m = encrypt.gen_key_iv(self._password, self._method) # spec https://shadowsocks.org/en/spec/one-time-auth.html if self._one_time_auth_enable: data = self._ota_chunk_data_gen(key, iv, data) data = encrypt.encrypt_all_m(key, iv, m, self._method, data) if not data: return else: data = data[header_length:] if not data: return try: client.sendto(data, (server_addr, server_port)) except IOError as e: err = eventloop.errno_from_exception(e) if err in (errno.EINPROGRESS, errno.EAGAIN): pass else: shell.print_exception(e)
def _handle_server(self): server = self._server_socket data, r_addr = server.recvfrom(BUF_SIZE) key = None iv = None if not data: logging.debug('UDP handle_server: data is empty') if self._stat_callback: self._stat_callback(self._listen_port, len(data)) if self._is_local: # +----+------+------+----------+----------+----------+ # |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | # +----+------+------+----------+----------+----------+ # ~~~~~~~~ frag = common.ord(data[2]) #shadowsocks中FRAG就使用0 if frag != 0: logging.warn('UDP drop a message since frag is not 0') return else: # +------+----------+----------+----------+ # | ATYP | DST.ADDR | DST.PORT | DATA | # +------+----------+----------+----------+ data = data[3:] else: data, key, iv = encrypt.dencrypt_all(self._password, self._method, data) # decrypt data if not data: logging.debug('UDP handle_server: data is empty after decrypt') return header_result = parse_header(data) if header_result is None: return # +------+----------+----------+----------+ # | ATYP | DST.ADDR | DST.PORT | DATA | # +------+----------+----------+----------+ # . . # |<----- header_length ------>| addrtype, dest_addr, dest_port, header_length = header_result # 如果是sslocal,则需要查找的是ssserver的地址及端口 # 如果是ssserver,则需要获取的是目标服务器的地址及端口 if self._is_local: # ssserver 地址和端口 server_addr, server_port = self._get_a_server() else: # 「目标服务器」地址和端口 server_addr, server_port = dest_addr, dest_port # spec https://shadowsocks.org/en/spec/one-time-auth.html self._ota_enable_session = addrtype & ADDRTYPE_AUTH if self._ota_enable and not self._ota_enable_session: logging.warn('client one time auth is required') return if self._ota_enable_session: if len(data) < header_length + ONETIMEAUTH_BYTES: logging.warn('UDP one time auth header is too short') return _hash = data[-ONETIMEAUTH_BYTES:] data = data[:-ONETIMEAUTH_BYTES] _key = iv + key if onetimeauth_verify(_hash, data, _key) is False: logging.warn('UDP one time auth fail') return # 从缓存中取 server_addr 解析后的地址 addrs = self._dns_cache.get(server_addr, None) # 如果找不到,则解析 server_addr 的地址并存入缓存 if addrs is None: # 注意,getaddrinfo 函数是阻塞的 addrs = socket.getaddrinfo(server_addr, server_port, 0, socket.SOCK_DGRAM, socket.SOL_UDP) if not addrs: # drop return else: self._dns_cache[server_addr] = addrs af, socktype, proto, canonname, sa = addrs[0] # 根据地址、端口、af 生成一个 key,这个 key 与 UDP 套接字一一对应 key = client_key(r_addr, af) client = self._cache.get(key, None) if not client: # TODO async getaddrinfo if self._forbidden_iplist: if common.to_str(sa[0]) in self._forbidden_iplist: logging.debug('IP %s is in forbidden list, drop' % common.to_str(sa[0])) # drop return # 创建 UDP 套接字 client = socket.socket(af, socktype, proto) client.setblocking(False) self._cache[key] = client # 将套接字与其地址关联起来,`_handle_client` 会用到 self._client_fd_to_server_addr[client.fileno()] = r_addr # 将套接字关联的文件描述符加入 `self._sockets` 中,`handle_event` 会用到 self._sockets.add(client.fileno()) # 将套接字加入事件循环, self._eventloop.add(client, eventloop.POLL_IN, self) # 如果是 sslocal,那么需要将数据加密 if self._is_local: key, iv, m = encrypt.gen_key_iv(self._password, self._method) # spec https://shadowsocks.org/en/spec/one-time-auth.html if self._ota_enable_session: data = self._ota_chunk_data_gen(key, iv, data) data = encrypt.encrypt_all_m(key, iv, m, self._method, data) if not data: return # 如果是 ssserver,在将接收到的数据发送给目标服务器之前, # 需要解密并且去掉头部,解密在上面已经完成了 else: # +------+----------+----------+----------+ # | ATYP | DST.ADDR | DST.PORT | DATA | # +------+----------+----------+----------+ # data = data[header_length:] if not data: return # - 对于 sslocal 而言,将加密后的数据发送给 ssserver,数据格式如下: # # +------+----------+----------+----------+ # | ATYP | DST.ADDR | DST.PORT | DATA | # +------+----------+----------+----------+ # # - 对于 ssserver 而言,将解密后的数据发送给目标服务器(只剩 `DATA` 部分了) try: client.sendto(data, (server_addr, server_port)) except IOError as e: err = eventloop.errno_from_exception(e) if err in (errno.EINPROGRESS, errno.EAGAIN): pass else: shell.print_exception(e)
def _handle_server(self): server = self._server_socket data, r_addr = server.recvfrom(BUF_SIZE) key = None iv = None if not data: logging.debug('UDP handle_server: data is empty') if self._stat_callback: self._stat_callback(self._listen_port, len(data)) if self._is_local: frag = common.ord(data[2]) if frag != 0: logging.warn('UDP drop a message since frag is not 0') return else: data = data[3:] else: data, key, iv = encrypt.dencrypt_all(self._password, self._method, data) # decrypt data if not data: logging.debug( 'UDP handle_server: data is empty after decrypt' ) return header_result = parse_header(data) if header_result is None: return addrtype, dest_addr, dest_port, header_length = header_result if self._is_local: server_addr, server_port = self._get_a_server() else: server_addr, server_port = dest_addr, dest_port # spec https://shadowsocks.org/en/spec/one-time-auth.html if self._one_time_auth_enable or addrtype & ADDRTYPE_AUTH: self._one_time_auth_enable = True if len(data) < header_length + ONETIMEAUTH_BYTES: logging.warn('UDP one time auth header is too short') return _hash = data[-ONETIMEAUTH_BYTES:] data = data[: -ONETIMEAUTH_BYTES] _key = iv + key if onetimeauth_verify(_hash, data, _key) is False: logging.warn('UDP one time auth fail') return addrs = self._dns_cache.get(server_addr, None) if addrs is None: addrs = socket.getaddrinfo(server_addr, server_port, 0, socket.SOCK_DGRAM, socket.SOL_UDP) if not addrs: # drop return else: self._dns_cache[server_addr] = addrs af, socktype, proto, canonname, sa = addrs[0] key = client_key(r_addr, af) client = self._cache.get(key, None) if not client: # TODO async getaddrinfo if self._forbidden_iplist: if common.to_str(sa[0]) in self._forbidden_iplist: logging.debug('IP %s is in forbidden list, drop' % common.to_str(sa[0])) # drop return client = socket.socket(af, socktype, proto) client.setblocking(False) self._cache[key] = client self._client_fd_to_server_addr[client.fileno()] = r_addr self._sockets.add(client.fileno()) self._eventloop.add(client, eventloop.POLL_IN, self) if self._is_local: key, iv, m = encrypt.gen_key_iv(self._password, self._method) # spec https://shadowsocks.org/en/spec/one-time-auth.html if self._one_time_auth_enable: data = self._ota_chunk_data_gen(key, iv, data) data = encrypt.encrypt_all_m(key, iv, m, self._method, data) if not data: return else: data = data[header_length:] if not data: return try: client.sendto(data, (server_addr, server_port)) except IOError as e: err = eventloop.errno_from_exception(e) if err in (errno.EINPROGRESS, errno.EAGAIN): pass else: shell.print_exception(e)
def _handle_server(self): server = self._server_socket data, r_addr = server.recvfrom(BUF_SIZE) client_address = r_addr[0] key = None iv = None if not data: logging.debug('U[%d] UDP handle_server: data is empty' % self._config['server_port']) if self._stat_callback: self._stat_callback(self._listen_port, len(data)) if self._is_local: frag = common.ord(data[2]) if frag != 0: logging.warn('U[%d] UDP drop a message since frag is not 0' % self._config['server_port']) return else: data = data[3:] else: data, key, iv = encrypt.dencrypt_all(self._password, self._method, data) # decrypt data if not data: logging.debug( 'U[%d] UDP handle_server: data is empty after decrypt' % self._config['server_port']) return header_result = parse_header(data) if header_result is None: return addrtype, dest_addr, dest_port, header_length = header_result if self._config['firewall_ports'] and self._config[ 'server_port'] not in self._config['firewall_trusted']: # Firewall enabled if self._config[ 'firewall_mode'] == 'blacklist' and dest_port in self._config[ 'firewall_ports']: firewall_blocked = True elif self._config[ 'firewall_mode'] == 'whitelist' and dest_port not in self._config[ 'firewall_ports']: firewall_blocked = True else: firewall_blocked = False else: firewall_blocked = False if firewall_blocked: logging.warning('U[%d] UDP PORT BANNED: RP[%d] A[%s-->%s]' % (self._config['server_port'], dest_port, client_address, common.to_str(dest_addr))) return else: logging.info('U[%d] UDP CONN: RP[%d] A[%s-->%s]' % (self._config['server_port'], dest_port, client_address, common.to_str(dest_addr))) if self._is_local: server_addr, server_port = self._get_a_server() else: server_addr, server_port = dest_addr, dest_port # spec https://shadowsocks.org/en/spec/one-time-auth.html if self._one_time_auth_enable or (addrtype & ADDRTYPE_AUTH == ADDRTYPE_AUTH): if not self._one_time_auth_enable and self._config['verbose']: logging.info( 'U[%d] UDP one time auth automatically enabled' % self._config['server_port']) self._one_time_auth_enable = True if len(data) < header_length + ONETIMEAUTH_BYTES: logging.warn( 'U[%d] UDP one time auth header is too short' % self._config['server_port']) return _hash = data[-ONETIMEAUTH_BYTES:] data = data[:-ONETIMEAUTH_BYTES] _key = iv + key if onetimeauth_verify(_hash, data, _key) is False: logging.warn('U[%d] UDP one time auth fail' % self._config['server_port']) return addrs = self._dns_cache.get(server_addr, None) if addrs is None: addrs = socket.getaddrinfo(server_addr, server_port, 0, socket.SOCK_DGRAM, socket.SOL_UDP) if not addrs: # drop return else: self._dns_cache[server_addr] = addrs af, socktype, proto, canonname, sa = addrs[0] key = client_key(r_addr, af) client = self._cache.get(key, None) if not client: # TODO async getaddrinfo if self._forbidden_iplist: if common.to_str(sa[0]) in self._forbidden_iplist: logging.debug( 'U[%d] IP %s is in forbidden list, drop' % (self._config['server_port'], common.to_str(sa[0]))) # drop return client = socket.socket(af, socktype, proto) client.setblocking(False) self._cache[key] = client self._client_fd_to_server_addr[client.fileno()] = r_addr self._sockets.add(client.fileno()) self._eventloop.add(client, eventloop.POLL_IN, self) if self._is_local: key, iv, m = encrypt.gen_key_iv(self._password, self._method) # spec https://shadowsocks.org/en/spec/one-time-auth.html if self._one_time_auth_enable: data = self._ota_chunk_data_gen(key, iv, data) data = encrypt.encrypt_all_m(key, iv, m, self._method, data) if not data: return else: data = data[header_length:] if not data: return try: client.sendto(data, (server_addr, server_port)) except (socket.error, OSError, IOError) as e: error_no = eventloop.errno_from_exception(e) if sys.platform == "win32": if error_no in (errno.EAGAIN, errno.EINPROGRESS, errno.EWOULDBLOCK, errno.WSAEWOULDBLOCK): pass else: shell.print_exception(e) elif error_no in (errno.EAGAIN, errno.EINPROGRESS, errno.EWOULDBLOCK): pass else: shell.print_exception(e)