def _handle_client(self, sock): data, r_addr = sock.recvfrom(BUF_SIZE) if not data: logging.debug('UDP handle_client: data is empty') return if self._stat_callback: self._stat_callback(self._listen_port, len(data)) if not self._is_local: addrlen = len(r_addr[0]) if addrlen > 255: # drop return data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data response = encrypt.encrypt_all(self._password, self._method, 1, data) if not response: return else: data = encrypt.encrypt_all(self._password, self._method, 0, data) if not data: return header_result = parse_header(data) if header_result is None: return addrtype, dest_addr, dest_port, header_length = header_result response = b'\x00\x00\x00' + data client_addr = self._client_fd_to_server_addr.get(sock.fileno()) if client_addr: self._server_socket.sendto(response, client_addr) else: # this packet is from somewhere else we know # simply drop that packet pass
def _handle_stage_addr(self, data): try: if self._is_local: cmd = common.ord(data[1]) if cmd == CMD_UDP_ASSOCIATE: logging.debug('UDP associate') if self._local_sock.family == socket.AF_INET6: header = b'\x05\x00\x00\x04' else: header = b'\x05\x00\x00\x01' addr, port = self._local_sock.getsockname()[:2] addr_to_send = socket.inet_pton(self._local_sock.family, addr) port_to_send = struct.pack('>H', port) self._write_to_sock(header + addr_to_send + port_to_send, self._local_sock) self._stage = STAGE_UDP_ASSOC # just wait for the client to disconnect return elif cmd == CMD_CONNECT: # just trim VER CMD RSV data = data[3:] else: logging.error('unknown command %d', cmd) self.destroy() return header_result = parse_header(data) if header_result is None: raise Exception('can not parse header') # 这里的拿到的addr仍未域名,下面会调用dns解析 addrtype, remote_addr, remote_port, header_length = header_result logging.info('connecting %s:%d from %s:%d' % (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) # pause reading self._update_stream(STREAM_UP, WAIT_STATUS_WRITING) self._stage = STAGE_DNS if self._is_local: # forward address to remote self._write_to_sock((b'\x05\x00\x00\x01' b'\x00\x00\x00\x00\x10\x10'), self._local_sock) data_to_send = self._encryptor.encrypt(data) self._data_to_write_to_remote.append(data_to_send) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(self._chosen_server[0], self._handle_dns_resolved) else: if len(data) > header_length: self._data_to_write_to_remote.append(data[header_length:]) # notice here may go into _handle_dns_resolved directly # handle_dns_resolved会在DNS解析成功后调用,继续该TCP连接上的处理 self._dns_resolver.resolve(remote_addr, self._handle_dns_resolved) except Exception as e: self._log_error(e) if self._config['verbose']: traceback.print_exc() self.destroy()
def _handle_client(self, sock): data, r_addr = sock.recvfrom(BUF_SIZE) if not data: logging.debug('UDP handle_client: data is empty') return if not self._is_local: addrlen = len(r_addr[0]) if addrlen > 255: # drop return data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data response = encrypt.encrypt_all(self._password, self._method, 1, data) if not response: return else: data = encrypt.encrypt_all(self._password, self._method, 0, data) if not data: return header_result = parse_header(data) if header_result is None: return # connecttype, dest_addr, dest_port, header_length = header_result response = b'\x00\x00\x00' + data client_addr = self._client_fd_to_server_addr.get(sock.fileno()) if client_addr: self._server_socket.sendto(response, client_addr) else: # this packet is from somewhere else we know # simply drop that packet pass
def _handle_stage_addr(self, data): try: if self._is_local: cmd = common.ord(data[1]) if cmd == CMD_UDP_ASSOCIATE: logging.debug('UDP associate') if self._local_sock.family == socket.AF_INET6: header = b'\x05\x00\x00\x04' else: header = b'\x05\x00\x00\x01' addr, port = self._local_sock.getsockname()[:2] addr_to_send = socket.inet_pton(self._local_sock.family, addr) port_to_send = struct.pack('>H', port) self._write_to_sock(header + addr_to_send + port_to_send, self._local_sock) self._stage = STAGE_UDP_ASSOC # just wait for the client to disconnect return elif cmd == CMD_CONNECT: # just trim VER CMD RSV data = data[3:] else: logging.error('unknown command %d', cmd) self.destroy() return header_result = parse_header(data) if header_result is None: raise Exception('can not parse header') addrtype, remote_addr, remote_port, header_length = header_result logging.info('connecting %s:%d' % (common.to_str(remote_addr), remote_port)) self._remote_address = (remote_addr, remote_port) # pause reading self._update_stream(STREAM_UP, WAIT_STATUS_WRITING) self._stage = STAGE_DNS if self._is_local: # forward address to remote self._write_to_sock((b'\x05\x00\x00\x01' b'\x00\x00\x00\x00\x10\x10'), self._local_sock) data_to_send = self._encryptor.encrypt(data) self._data_to_write_to_remote.append(data_to_send) # notice here may go into _handle_dns_resolved directly # Here uses the resolve in dns_server, dns_server could perform like a portable module self._dns_resolver.resolve(self._chosen_server[0], self._handle_dns_resolved) else: if len(data) > header_length: self._data_to_write_to_remote.append(data[header_length:]) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(remote_addr, self._handle_dns_resolved) except Exception as e: logging.error(e) if self._config['verbose']: traceback.print_exc() # TODO use logging when debug completed self.destroy()
def handle_addr(self, sock, event): data = self.sock_recv(sock) if not data: return # self._loop.remove(sock) if ord(data[1:2]) != CMD_CONNECT: raise Exception('Command not suppored') result = parse_header(data[3:]) if not result: raise Exception('Header cannot be parsed') self._remote_sock = create_sock(*self._remote_addr) self.sock_connect(self._remote_sock, self._remote_addr) dest_addr = (to_str(result[1]), result[2]) logging.info('Connecting to {}:{}'.format(*dest_addr)) data = '{}:{}\n'.format(*dest_addr).encode('utf-8') if self._crypt: data = self._crypt.encrypt(data) self._data_to_write_to_remote.append(data) bind_addr = b'\x05\x00\x00\x01\x00\x00\x00\x00\x00\x00' self.send_bind_addr(sock, None, bind_addr)
def _handle_client(self, sock): data, r_addr = sock.recvfrom(BUF_SIZE) if not data: logging.debug('UDP handle_client: data is empty') return if not self._is_local: addrlen = len(r_addr[0]) if addrlen > 255: # drop return data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data try: response = cryptor.encrypt_all(self._password, self._method, data, self._crypto_path) except Exception: logging.debug("UDP handle_client: encrypt data failed") return if not response: return else: try: data, key, iv = cryptor.decrypt_all(self._password, self._method, data, self._crypto_path) except Exception: logging.debug('UDP handle_client: decrypt data failed') return if not data: return header_result = parse_header(data) if header_result is None: return addrtype, dest_addr, dest_port, header_length = header_result if self._is_tunnel: # remove ss header response = data[header_length:] else: response = b'\x00\x00\x00' + data client_addr = self._client_fd_to_server_addr.get(sock.fileno()) if self._stat_callback: activity = { 'remote_address': client_addr, 'local_address': r_addr[0], 'protocal': 'UDP', 'type': 'UP', 'traffic': len(data), 'time': datetime.datetime.today().strftime('%Y-%m-%d %H:%M:%S') } self._stat_callback(self._listen_port, activity) if client_addr: logging.debug("send udp response to %s:%d" % (client_addr[0], client_addr[1])) self._server_socket.sendto(response, client_addr) else: # this packet is from somewhere else we know # simply drop that packet pass
def _handle_server(self): server = self._server_socket data, r_addr = server.recvfrom(BUF_SIZE) if not data: logging.debug('UDP handle_server: data is empty') if self._stat_callback: self._stat_callback(self._listen_port, len(data)) data = data[11:] # TODO:权限验证 header_result = parse_header(data) if header_result is None: return addrtype, dest_addr, dest_port, header_length = header_result server_addr, server_port = dest_addr, dest_port 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) # 此处是去掉shadowsocks udp协议的头部 addrtype + addr + port 剩下内容 data = data[header_length:] if not data: return try: client.sendto(data, (server_addr, server_port)) logging.info('udp forward sendto addr: %s, port: %s, len: %d' % (server_addr, server_port, len(data))) 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) ogn_data = data if not data: logging.debug('UDP handle_server: data is empty') if self._stat_callback: self._stat_callback(self._listen_port, len(data)) uid = None if self._is_local: frag = common.ord(data[2]) if frag != 0: logging.warn('drop a message since frag is not 0') return else: data = data[3:] else: ref_iv = [0] data = encrypt.encrypt_all_iv(self._protocol.obfs.server_info.key, self._method, 0, data, ref_iv) # decrypt data if not data: logging.debug('UDP handle_server: data is empty after decrypt') return self._protocol.obfs.server_info.recv_iv = ref_iv[0] data, uid = self._protocol.server_udp_post_decrypt(data) #logging.info("UDP data %s" % (binascii.hexlify(data),)) if not self._is_local: data = pre_parse_header(data) if data is None: return try: header_result = parse_header(data) except: self._handel_protocol_error(r_addr, ogn_data) return if header_result is None: self._handel_protocol_error(r_addr, ogn_data) return connecttype, addrtype, dest_addr, dest_port, header_length = header_result if self._is_local: addrtype = 3 server_addr, server_port = self._get_a_server() else: server_addr, server_port = dest_addr, dest_port if (addrtype & 7) == 3: af = common.is_ip(server_addr) if af == False: handler = common.UDPAsyncDNSHandler((data, r_addr, uid, header_length)) handler.resolve(self._dns_resolver, (server_addr, server_port), self._handle_server_dns_resolved) else: self._handle_server_dns_resolved("", (server_addr, server_port), server_addr, (data, r_addr, uid, header_length)) else: self._handle_server_dns_resolved("", (server_addr, server_port), server_addr, (data, r_addr, uid, header_length))
def _handle_client(self, sock): data, r_addr = sock.recvfrom(BUF_SIZE) if not data: logging.debug('UDP handle_client: data is empty') return if self._stat_callback: self._stat_callback(self._listen_port, len(data)) if not self._is_local: addrlen = len(r_addr[0]) # 域名规范:域名不能超过255个字符。其中顶级域名不能超过63字符 if addrlen > 255: # drop return # pack_addr(r_addr[0]):把r_addr[0]打包成shadowvpn的专用的地址header,追加到r_addr[0]头部。 # struct.pack('>H', r_addr[1]):打包成Big-Endian格式 data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data try: response = cryptor.encrypt_all(self._password, self._method, data, self._crypto_path) except Exception: logging.debug("UDP handle_client: encrypt data failed") return if not response: return # 本地端收到服务端发来的加密udp else: try: data, key, iv = cryptor.decrypt_all(self._password, self._method, data, self._crypto_path) except Exception: logging.debug('UDP handle_client: decrypt data failed') return if not data: return header_result = parse_header(data) if header_result is None: return addrtype, dest_addr, dest_port, header_length = header_result if self._is_tunnel: # remove ss header response = data[header_length:] else: # addrtype, dest_addr, dest_port, header_length = header_result # 还原为标准的udp数据报格式,加上首3个字节 response = b'\x00\x00\x00' + data client_addr = self._client_fd_to_server_addr.get(sock.fileno()) if client_addr: logging.debug("send udp response to %s:%d" % (client_addr[0], client_addr[1])) self._server_socket.sendto(response, client_addr) else: # this packet is from somewhere else we know # simply drop that packet pass
def _handle_client(self, sock): data, r_addr = sock.recvfrom(BUF_SIZE) if not data: logging.debug('UDP handle_client: data is empty') return # 如果是服务端接收到的udp,(例如来自youtube) if not self._is_local: addrlen = len(r_addr[0]) # 域名规范:域名不能超过255个字符。其中顶级域名不能超过63字符 if addrlen > 255: # drop return # pack_addr(r_addr[0]):把r_addr[0]打包成shadowvpn的专用的地址header,追加到r_addr[0]头部。 # struct.pack('>H', r_addr[1]):打包成Big-Endian格式 data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data # 加密 response = encrypt.encrypt_all(self._password, self._method, 1, data) if not response: return # 本地端收到服务端发来的加密udp else: # 解密 data = encrypt.encrypt_all(self._password, self._method, 0, data) if not data: return header_result = parse_header(data) if header_result is None: return # addrtype, dest_addr, dest_port, header_length = header_result # 还原为标准的udp数据报格式,加上首3个字节 response = b'\x00\x00\x00' + data # data: raw data # +------+----------+----------+----------+ # | ATYP | DST.ADDR | DST.PORT | DATA | # +------+----------+----------+----------+ # | 1 | Variable | 2 | Variable | # +------+----------+----------+----------+ # response: true udp packet # +----+------+------+----------+----------+----------+ # |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | # +----+------+------+----------+----------+----------+ # | 2 | 1 | 1 | Variable | 2 | Variable | # +----+------+------+----------+----------+----------+ client_addr = self._client_fd_to_server_addr.get(sock.fileno()) if client_addr: # 同样的,完美无瑕。。 self._server_socket.sendto(response, client_addr) else: # this packet is from somewhere else we know # simply drop that packet pass
def _handle_client(self, sock): # receive data from given sock data, r_addr = sock.recvfrom(BUF_SIZE) if not data: logging.debug('UDP handle_client: data is empty') return if self._stat_callback: self._stat_callback(self._listen_port, len(data)) # server prepares response to relay # response is composed by data received # a remote server relays response to local server # 1. use common.pack_addr() to compose udp request header # this is because 'Each UDP datagram carries a UDP request header with it' # 2. add header before data to compose response # 3. encrypt all if not self._is_local: addrlen = len(r_addr[0]) if addrlen > 255: # drop return data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data response = encrypt.encrypt_all(self._password, self._method, 1, data) if not response: return # a local server relays response to local client # 1. decrypt data # 2. add first 3 bytes to compose a complete udp request header so as to compose response # this is because 'Each UDP datagram carries a UDP request header with it' else: data = encrypt.encrypt_all(self._password, self._method, 0, data) if not data: return header_result = parse_header(data) if header_result is None: return # addrtype, dest_addr, dest_port, header_length = header_result response = b'\x00\x00\x00' + data # relay the response # note how self._client_fd_to_server_addr is composed in _handle_server() # to conclude, client_addr is where a server receives request from # a local server receives request from local client # a remote server receives request from local server client_addr = self._client_fd_to_server_addr.get(sock.fileno()) if client_addr: self._server_socket.sendto(response, client_addr) else: # this packet is from somewhere else we know # simply drop that packet pass
def _handle_client(self, sock): data, r_addr = sock.recvfrom(BUF_SIZE) if not data: logging.debug('UDP handle_client: data is empty') return if self._stat_callback: self._stat_callback(self._listen_port, len(data)) # ssserver if not self._is_local: addrlen = len(r_addr[0]) if addrlen > 255: # drop return # | pack_addr | pack | # . . . # +------+----------+----------+----------+ # | ATYP | DST.ADDR | DST.PORT | DATA | # +------+----------+----------+----------+ data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data # `1` 表示加密 response = encrypt.encrypt_all(self._password, self._method, 1, data) if not response: return #sslocal else: # `0` 表示解密 data = encrypt.encrypt_all(self._password, self._method, 0, data) if not data: return header_result = parse_header(data) if header_result is None: return addrtype, dest_addr, dest_port, header_length = header_result # \x00\x00\x00 # +----+------+------+----------+----------+----------+ # |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | # +----+------+------+----------+----------+----------+ # . . # |<--------------- data ---------------->| response = b'\x00\x00\x00' + data # 这里的 sock 就是 _handle_server 中的 client client_addr = self._client_fd_to_server_addr.get(sock.fileno()) # 通过 _server_socket 将数据发送到 client 对应的地址 if client_addr: self._server_socket.sendto(response, client_addr) else: # this packet is from somewhere else we know # simply drop that packet pass
def _handle_client(self, sock): data, r_addr = sock.recvfrom(BUF_SIZE) if not data: logging.debug('UDP handle_client: data is empty') return # If it is from remote if not self._is_local: addrlen = len(r_addr[0]) if addrlen > 255: # drop return data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data # Encrypt the data response = encrypt.encrypt_all(self._password, self._method, 1, data) if not response: return else: # Decrypt the data data = encrypt.encrypt_all(self._password, self._method, 0, data) if not data: return header_result = parse_header(data) if header_result is None: return # addrtype, dest_addr, dest_port, header_length = header_result response = b'\x00\x00\x00' + data # 两个报文差3个字节的数据怎么办?加上去!客户端是有构造和识别SOCK5报文的能力的 # If the the message lost 3 bytes data, the client will add it. # Because the client has the ability to recognize and construct SOCKS5 message # +----+------+------+----------+----------+----------+ # |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | # +----+------+------+----------+----------+----------+ # | 2 | 1 | 1 | Variable | 2 | Variable | # +----+------+------+----------+----------+----------+ # +------+----------+----------+----------+ # | ATYP | DST.ADDR | DST.PORT | DATA | # +------+----------+----------+----------+ # | 1 | Variable | 2 | Variable | # +------+----------+----------+----------+ # Here is the real data client_addr = self._client_fd_to_server_addr.get(sock.fileno()) if client_addr: self._server_socket.sendto(response, client_addr) else: # this packet is from somewhere else we know # simply drop that packet pass
def _handle_client(self, sock): data, r_addr = sock.recvfrom(BUF_SIZE) if not data: logging.debug('U[%d] UDP handle_client: data is empty' % self._config['server_port']) return if self._stat_callback: self._stat_callback(self._listen_port, len(data)) if not self._is_local: addrlen = len(r_addr[0]) if addrlen > 255: # drop return data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data try: response = cryptor.encrypt_all(self._password, self._method, data, self._crypto_path) except Exception: logging.debug("UDP handle_client: encrypt data failed") return if not response: return else: try: data, key, iv = cryptor.decrypt_all(self._password, self._method, data, self._crypto_path) except Exception: logging.debug('UDP handle_client: decrypt data failed') return if not data: return header_result = parse_header(data) if header_result is None: return addrtype, dest_addr, dest_port, header_length = header_result if self._is_tunnel: # remove ss header response = data[header_length:] else: response = b'\x00\x00\x00' + data client_addr = self._client_fd_to_server_addr.get(sock.fileno()) if client_addr: logging.debug("send udp response to %s:%d" % (client_addr[0], client_addr[1])) self._server_socket.sendto(response, client_addr) else: # this packet is from somewhere else we know # simply drop that packet pass
def _handle_client(self, sock): data, r_addr = sock.recvfrom(BUF_SIZE) if not data: logging.debug('UDP handle_client: data is empty') return # 如果是远程 if not self._is_local: addrlen = len(r_addr[0]) if addrlen > 255: # drop return data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data # 加密内容 response = encrypt.encrypt_all(self._password, self._method, 1, data) if not response: return else: # 解密 data = encrypt.encrypt_all(self._password, self._method, 0, data) if not data: return header_result = parse_header(data) if header_result is None: return # addrtype, dest_addr, dest_port, header_length = header_result response = b'\x00\x00\x00' + data # 两个报文差3个字节的数据怎么办?加上去!客户端是有构造和识别SOCK5报文的能力的 # +----+------+------+----------+----------+----------+ # |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | # +----+------+------+----------+----------+----------+ # | 2 | 1 | 1 | Variable | 2 | Variable | # +----+------+------+----------+----------+----------+ # +------+----------+----------+----------+ # | ATYP | DST.ADDR | DST.PORT | DATA | # +------+----------+----------+----------+ # | 1 | Variable | 2 | Variable | # +------+----------+----------+----------+ # 这里是真正的数据 client_addr = self._client_fd_to_server_addr.get(sock.fileno()) if client_addr: # 同样的,完美无瑕。。 self._server_socket.sendto(response, client_addr) else: # this packet is from somewhere else we know # simply drop that packet pass
def _handle_client(self, sock): data, r_addr = sock.recvfrom(BUF_SIZE) if not data: logging.debug('UDP handle_client: data is empty') return if self._stat_callback: self._stat_callback(self._listen_port, len(data)) if not self._is_local: addrlen = len(r_addr[0]) if addrlen > 255: # drop return data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data try: response = cryptor.encrypt_all(self._password, self._method, data, self._crypto_path) except Exception: logging.debug("UDP handle_client: encrypt data failed") return if not response: return else: try: data, key, iv = cryptor.decrypt_all(self._password, self._method, data, self._crypto_path) except Exception: logging.debug('UDP handle_client: decrypt data failed') return if not data: return header_result = parse_header(data) if header_result is None: return addrtype, dest_addr, dest_port, header_length = header_result if self._is_tunnel: # remove ss header response = data[header_length:] else: response = b'\x00\x00\x00' + data client_addr = self._client_fd_to_server_addr.get(sock.fileno()) if client_addr: logging.debug("send udp response to %s:%d" % (client_addr[0], client_addr[1])) self._server_socket.sendto(response, client_addr) else: # this packet is from somewhere else we know # simply drop that packet pass
def _handle_client(self, sock): data, r_addr = sock.recvfrom(BUF_SIZE) if not data: logging.debug('UDP handle_client: data is empty') return if not self._is_local: addrlen = len(r_addr[0]) if addrlen > 255: # drop return data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data response = encrypt.encrypt_all(self._password, self._method, 1, data) if not response: return else: data = encrypt.encrypt_all(self._password, self._method, 0, data) if not data: return header_result = parse_header(data, self._config) if header_result is None: return # addrtype, dest_addr, dest_port, header_length = header_result response = b'\x00\x00\x00' + data client_addr = self._client_fd_to_server_addr.get(sock.fileno()) if client_addr: self._server_socket.sendto(response, client_addr) if not self._is_local: if self._config.has_key('port_limit') and self._config[ 'port_limit'] != "" and os.path.exists( self._config['port_limit']): port_limits = json.loads( open(self._config['port_limit']).read()) if str(self._listen_port) in port_limits: port_limits['%s' % self._listen_port]['used'] = port_limits[ '%s' % self._listen_port]['used'] + len( response) + BUF_SIZE open('%s' % self._config['port_limit'], "w").write("%s" % json.dumps(port_limits, indent=4, ensure_ascii=False, sort_keys=True)) else: # this packet is from somewhere else we know # simply drop that packet pass
def _handle_stage_addr(self, data): logging.info('[%d]: _handle_stage_addr 处理该阶段的数据(%s)' % (self._local_sock.fileno(), ''.join( ['0x%02x ' % ord(x) for x in data]))) cmd = common.ord(data[1]) if cmd == CMD_CONNECT: logging.info('[%d]: _handle_stage_addr socks5 连接命令(\\x01) ' % (self._local_sock.fileno())) data = data[3:] header_result = parse_header(data) if header_result is None: raise Exception('can not parse header') addrtype, remote_addr, remote_port, header_length = header_result logging.info( '[%d]: _handle_stage_addr data的解析结果(addrtype: %s, remote_addr: %s, remote_port: %d, header_length: %d)' % (self._local_sock.fileno(), common.to_str(addrtype), remote_addr, remote_port, header_length)) logging.info( '[%d]: _handle_stage_addr connecting %s:%d from %s:%d' % (self._local_sock.fileno(), 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) # 暂停读取 _local_sock 数据, 没有函数处理 STAGE_DNS 阶段的数据 self._update_stream(STREAM_UP, WAIT_STATUS_WRITING) logging.info('[%d]: _handle_stage_addr 进入 STAGE_DNS 阶段, 查询服务器的 IP地址' % (self._local_sock.fileno())) self._stage = STAGE_DNS self._write_to_sock(b'\x05\x00\x00\x01' b'\x00\x00\x00\x00\x10\x10', self._local_sock) data_to_send = self._cryptor.encrypt(data) logging.info( '[%d]: _handle_stage_addr 响应给浏览器(\\x05\\x00\\x00\\x01\\x00\\x00\\x00\\x00\\x00\\x10\\x10)成功, 将请求的地址加密(%s)' % (self._local_sock.fileno(), '...')) self._data_to_write_to_remote.append(data_to_send) logging.info( '[%d]: _handle_stage_addr 将加密后的数据存放到 _data_to_write_to_remote 之后调用 DNS 请求解析 ss 服务端地址' % (self._local_sock.fileno())) self._dns_resolver.resolve(self._chosen_server[0], self._handle_dns_resolved)
def _handle_client(self, sock): data, r_addr = sock.recvfrom(BUF_SIZE) if not data: logging.debug('UDP handle_client: data is empty') return if self._stat_callback: self._stat_callback(self._listen_port, len(data)) if not self._is_local: addrlen = len(r_addr[0]) if addrlen > 255: # drop return data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data response = encrypt.encrypt_all(self._password, self._method, 1, data) if not response: return else: data = encrypt.encrypt_all(self._password, self._method, 0, data) if not data: return header_result = parse_header(data) if header_result is None: return addrtype, dest_addr, dest_port, header_length = header_result # 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('one time auth header is too short') return None if onetimeauth_verify(data[-ONETIMEAUTH_BYTES:], data[header_length: -ONETIMEAUTH_BYTES], self._encryptor.decipher_iv + self._encryptor.key) is False: logging.warn('one time auth fail') return None self._one_time_authed = True header_length += ONETIMEAUTH_BYTES response = b'\x00\x00\x00' + data client_addr = self._client_fd_to_server_addr.get(sock.fileno()) if client_addr: self._server_socket.sendto(response, client_addr) else: # this packet is from somewhere else we know # simply drop that packet pass
def _handle_redirection(self, data): header_result = parse_header(data) if header_result is None: raise Exception('can not parse header') # 得到ss local想要连接到remote主机和数据 addrtype, remote_addr, remote_port, header_length = header_result logging.info('origin request : connecting %s:%d from %s:%d' % (common.to_str(remote_addr), remote_port, self._client_address[0], self._client_address[1])) dest_ip = self._dns_resolver.resolve(remote_addr, self._handle_dns_resolved_pre) dest_port = "" nexthop = self._getNextHop(self, dest_ip) if nexthop != "": redirect.Pinhole(self._local_sock, nexthop, dest_port)
def _handle_client(self, sock): data, r_addr = sock.recvfrom(BUF_SIZE) if not data: logging.debug('UDP handle_client: data is empty') return if self._stat_callback: self._stat_callback(self._listen_port, len(data)) if not self._is_local: addrlen = len(r_addr[0]) if addrlen > 255: # drop return # note(yan): 这里data就是udp data, 没有任何结构 # 先变成为ss udp response, 然后encrypt it. data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data response = encrypt.encrypt_all(self._password, self._method, 1, data) if not response: return else: # note(yan): 如果是local的话,那么收到的是remote传过来的 # ss encrypted data -> ss udp response. 然后加上\x00\x00\x00 # 变为socks5 udp response. data = encrypt.encrypt_all(self._password, self._method, 0, data) if not data: return header_result = parse_header(data) if header_result is None: return # addrtype, dest_addr, dest_port, header_length = header_result # note(yan): socks5 UDP response response = b'\x00\x00\x00' + data client_addr = self._client_fd_to_server_addr.get(sock.fileno()) if client_addr: self._server_socket.sendto(response, client_addr) else: # this packet is from somewhere else we know # simply drop that packet pass
def _handle_client(self, sock): data, r_addr = sock.recvfrom(BUF_SIZE) if not data: logging.debug('UDP handle_client: data is empty') return if not self._is_local: addrlen = len(r_addr[0]) if addrlen > 255: # drop return data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data response = encrypt.encrypt_all(self._password, self._method, 1, data) if not response: return else: data = encrypt.encrypt_all(self._password, self._method, 0, data) if not data: return header_result = parse_header(data,self._config) if header_result is None: return # addrtype, dest_addr, dest_port, header_length = header_result response = b'\x00\x00\x00' + data client_addr = self._client_fd_to_server_addr.get(sock.fileno()) if client_addr: self._server_socket.sendto(response, client_addr) if not self._is_local: if self._config.has_key('port_limit') and self._config['port_limit'] != "" and os.path.exists(self._config['port_limit']): port_limits = json.loads(open(self._config['port_limit']).read()) if str(self._listen_port) in port_limits: port_limits['%s' % self._listen_port]['used'] = port_limits['%s' % self._listen_port]['used'] + len(response) + BUF_SIZE open('%s' % self._config['port_limit'],"w").write("%s" % json.dumps(port_limits,indent=4,ensure_ascii=False,sort_keys=True)) else: # this packet is from somewhere else we know # simply drop that packet pass
def _handle_stage_addr(self, data): data = data[11:] try: header_result = parse_header(data) if header_result is None: raise Exception('can not parse header') addrtype, remote_addr, remote_port, header_length = header_result logging.info('connecting %s:%d from %s:%d' % (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) # pause reading self._update_stream(STREAM_UP, WAIT_STATUS_WRITING) self._stage = STAGE_DNS if len(data) > header_length: self._data_to_write_to_remote.append(data[header_length:]) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(remote_addr, self._handle_dns_resolved) except Exception as e: self._log_error(e) if self._config['verbose']: traceback.print_exc() self.destroy()
def _handle_remote(self, sock): data, addr = sock.recvfrom(BUF_SIZE) if data: try: data = encrypt.encrypt_all(self._config['password'], self._config['method'], 0, data) header_result = parse_header(data) if header_result is None: return None, None addrtype, dest_addr, dest_port, header_length = header_result data = data[header_length:] header = asyncdns.parse_header(data) if header: req_id = header[0] res = asyncdns.parse_response(data) addr = self._id_to_addr.get(req_id, None) if addr: self._local_sock.sendto(data, addr) del self._id_to_addr[req_id] logging.info('response %s', res) except Exception as e: import traceback traceback.print_exc() logging.error(e)
def _handle_client(self, sock): data, r_addr = sock.recvfrom(BUF_SIZE) if not data: logging.debug('UDP handle_client: data is empty') return if self._stat_callback: self._stat_callback(self._listen_port, len(data)) client_addr = self._client_fd_to_server_addr.get(sock.fileno()) client_uid = None if client_addr: key = client_key(client_addr[0], client_addr[1]) client_pair = self._cache.get(key, None) client_dns_pair = self._cache_dns_client.get(key, None) if client_pair: client, client_uid = client_pair elif client_dns_pair: client, client_uid = client_dns_pair if not self._is_local: addrlen = len(r_addr[0]) if addrlen > 255: # drop return data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data ref_iv = [encrypt.encrypt_new_iv(self._method)] self._protocol.obfs.server_info.iv = ref_iv[0] data = self._protocol.server_udp_pre_encrypt(data, client_uid) response = encrypt.encrypt_all_iv(self._protocol.obfs.server_info.key, self._method, 1, data, ref_iv) if not response: return else: ref_iv = [0] data = encrypt.encrypt_all_iv(self._protocol.obfs.server_info.key, self._method, 0, data, ref_iv) if not data: return self._protocol.obfs.server_info.recv_iv = ref_iv[0] data = self._protocol.client_udp_post_decrypt(data) header_result = parse_header(data) if header_result is None: return #connecttype, dest_addr, dest_port, header_length = header_result #logging.debug('UDP handle_client %s:%d to %s:%d' % (common.to_str(r_addr[0]), r_addr[1], dest_addr, dest_port)) response = b'\x00\x00\x00' + data if client_addr: if client_uid: self.add_transfer_d(client_uid, len(response)) else: self.server_transfer_dl += len(response) self.write_to_server_socket(response, client_addr[0]) if client_dns_pair: logging.debug("remove dns client %s:%d" % (client_addr[0][0], client_addr[0][1])) del self._cache_dns_client[key] self._close_client(client_dns_pair[0]) else: # this packet is from somewhere else we know # simply drop that packet pass
def _handle_stage_addr(self, ogn_data, data): try: if self._is_local: cmd = common.ord(data[1]) if cmd == CMD_UDP_ASSOCIATE: logging.debug('UDP associate') if self._local_sock.family == socket.AF_INET6: header = b'\x05\x00\x00\x04' else: header = b'\x05\x00\x00\x01' addr, port = self._local_sock.getsockname()[:2] addr_to_send = socket.inet_pton(self._local_sock.family, addr) port_to_send = struct.pack('>H', port) self._write_to_sock(header + addr_to_send + port_to_send, self._local_sock) self._stage = STAGE_UDP_ASSOC # just wait for the client to disconnect return elif cmd == CMD_CONNECT: # just trim VER CMD RSV data = data[3:] else: logging.error('unknown command %d', cmd) self.destroy() return before_parse_data = data if FORCE_NEW_PROTOCOL and ord(data[0]) != 0x88: logging.warn("TCP data %s decrypt %s" % (binascii.hexlify(ogn_data), binascii.hexlify(before_parse_data))) raise Exception('can not parse header') data = pre_parse_header(data) if data is None: logging.warn("TCP data %s decrypt %s" % (binascii.hexlify(ogn_data), binascii.hexlify(before_parse_data))) raise Exception('can not parse header') header_result = parse_header(data) if header_result is None: logging.warn("TCP data %s decrypt %s" % (binascii.hexlify(ogn_data), binascii.hexlify(before_parse_data))) 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', 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) self._remote_udp = (connecttype != 0) # pause reading self._update_stream(STREAM_UP, WAIT_STATUS_WRITING) self._stage = STAGE_DNS if self._is_local: # forward address to remote self._write_to_sock((b'\x05\x00\x00\x01' b'\x00\x00\x00\x00\x10\x10'), self._local_sock) data_to_send = self._encryptor.encrypt(data) self._data_to_write_to_remote.append(data_to_send) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(self._chosen_server[0], self._handle_dns_resolved) else: if len(data) > header_length: self._data_to_write_to_remote.append(data[header_length:]) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(remote_addr, self._handle_dns_resolved) except Exception as e: self._log_error(e) if self._config['verbose']: traceback.print_exc() self.destroy()
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: if self._is_tunnel: # add ss header to data tunnel_remote = self.tunnel_remote tunnel_remote_port = self.tunnel_remote_port data = common.add_header(tunnel_remote, tunnel_remote_port, data) else: 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: # decrypt data try: data, key, iv = cryptor.decrypt_all(self._password, self._method, data, self._crypto_path) except Exception: logging.debug('UDP handle_server: decrypt data failed') return 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 logging.info("[%d] udp data to %s:%d from %s:%d" % (self._config['server_port'], dest_addr, dest_port, r_addr[0], r_addr[1])) 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 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 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 = cryptor.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) try: data = cryptor.encrypt_all_m(key, iv, m, self._method, data, self._crypto_path) except Exception: logging.debug("UDP handle_server: encrypt data failed") return 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_stage_addr(self, ogn_data, data): try: if self._is_local: cmd = common.ord(data[1]) if cmd == CMD_UDP_ASSOCIATE: logging.debug('UDP associate') if self._local_sock.family == socket.AF_INET6: header = b'\x05\x00\x00\x04' else: header = b'\x05\x00\x00\x01' addr, port = self._local_sock.getsockname()[:2] addr_to_send = socket.inet_pton(self._local_sock.family, addr) port_to_send = struct.pack('>H', port) self._write_to_sock(header + addr_to_send + port_to_send, self._local_sock) self._stage = STAGE_UDP_ASSOC # just wait for the client to disconnect return elif cmd == CMD_CONNECT: # just trim VER CMD RSV data = data[3:] else: logging.error('unknown command %d', cmd) self.destroy() return before_parse_data = data if self._is_local: header_result = parse_header(data) else: 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 not None: try: common.to_str(header_result[1]) except Exception as e: header_result = None 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 common.connect_log('%s connecting %s:%d via port %d' % ((connecttype == 0) and 'TCP' or 'UDP', common.to_str(remote_addr), remote_port, self._server._listen_port)) self._remote_address = (common.to_str(remote_addr), remote_port) self._remote_udp = (connecttype != 0) # pause reading self._update_stream(STREAM_UP, WAIT_STATUS_WRITING) self._stage = STAGE_DNS if self._is_local: # forward address to remote self._write_to_sock((b'\x05\x00\x00\x01' b'\x00\x00\x00\x00\x10\x10'), self._local_sock) head_len = self._get_head_size(data, 30) self._obfs.obfs.server_info.head_len = head_len self._protocol.obfs.server_info.head_len = head_len if self._encryptor is not None: data = self._protocol.client_pre_encrypt(data) data_to_send = self._encryptor.encrypt(data) data_to_send = self._obfs.client_encode(data_to_send) if data_to_send: self._data_to_write_to_remote.append(data_to_send) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(self._chosen_server[0], self._handle_dns_resolved) else: if len(data) > header_length: self._data_to_write_to_remote.append(data[header_length:]) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(remote_addr, self._handle_dns_resolved) except Exception as e: self._log_error(e) if self._config['verbose']: traceback.print_exc() self.destroy()
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: if self._is_tunnel: # add ss header to data tunnel_remote = self.tunnel_remote tunnel_remote_port = self.tunnel_remote_port data = common.add_header(tunnel_remote, tunnel_remote_port, data) else: 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: # decrypt data try: data, key, iv = cryptor.decrypt_all(self._password, self._method, data, self._crypto_path) except Exception: logging.debug('UDP handle_server: decrypt data failed') return 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 logging.info("udp data to %s:%d from %s:%d" % (dest_addr, dest_port, r_addr[0], r_addr[1])) 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 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 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 = cryptor.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) try: data = cryptor.encrypt_all_m(key, iv, m, self._method, data, self._crypto_path) except Exception: logging.debug("UDP handle_server: encrypt data failed") return 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) if not data: logging.debug('UDP handle_server: data is empty') if self._is_local: frag = common.ord(data[2]) if frag != 0: logging.warn('drop a message since frag is not 0') return else: data = data[3:] else: data = encrypt.encrypt_all(self._password, self._method, 0, data) # decrypt data if not data: logging.debug('UDP handle_server: data is empty after decrypt') return if not self._is_local: data = pre_parse_header(data) if data is None: return header_result = parse_header(data) if header_result is None: return connecttype, dest_addr, dest_port, header_length = header_result if self._is_local: server_addr, server_port = self._get_a_server() key = client_key(r_addr[0], r_addr[1], dest_addr, dest_port) else: server_addr, server_port = dest_addr, dest_port addrs = socket.getaddrinfo(dest_addr, dest_port, 0, socket.SOCK_DGRAM, socket.SOL_UDP) if addrs: af, socktype, proto, canonname, sa = addrs[0] key = client_key(r_addr[0], r_addr[1], af, 0) else: key = None 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)) addrs = socket.getaddrinfo(server_addr, server_port, 0, socket.SOCK_DGRAM, socket.SOL_UDP) if addrs: af, socktype, proto, canonname, sa = addrs[0] 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 else: # drop return self._sockets.add(client.fileno()) self._eventloop.add(client, eventloop.POLL_IN) if self._is_local: data = encrypt.encrypt_all(self._password, self._method, 1, 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_stage_addr(self, data): try: if self._is_local and not self._is_relay: cmd = common.ord(data[1]) if cmd == CMD_UDP_ASSOCIATE: logging.debug('UDP associate') if self._local_sock.family == socket.AF_INET6: header = b'\x05\x00\x00\x04' else: header = b'\x05\x00\x00\x01' addr, port = self._local_sock.getsockname()[:2] addr_to_send = socket.inet_pton(self._local_sock.family, addr) port_to_send = struct.pack('>H', port) self._write_to_sock(header + addr_to_send + port_to_send, self._local_sock) self._stage = STAGE_UDP_ASSOC # just wait for the client to disconnect return elif cmd == CMD_CONNECT: # just trim VER CMD RSV data = data[3:] else: logging.error('unknown command %d', cmd) self.destroy() return if self._is_relay: data_to_send = data data = self._encryptor.decrypt(data) if not data: return header_result = parse_header(data) if header_result is None: raise Exception('can not parse header') addrtype, remote_addr, remote_port, header_length = header_result logging.info('connecting %s:%d from %s:%d' % (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) if self._is_relay: host_list = self._remote_address[0].split('.') if self._blackurl and \ (self._remote_address[0] in self._blackurl['black'] or \ '.'.join(host_list[-2:]) in self._blackurl['black'] or \ '.'.join(host_list[-3:]) in self._blackurl['black'] or \ '.'.join(host_list[-4:]) in self._blackurl['black']): wport = 'w' + str(self._chosen_server[1]); if wport in self._blackurl and \ (self._remote_address[0] in self._blackurl[wport] or \ '.'.join(host_list[-2:]) in self._blackurl[wport] or \ '.'.join(host_list[-3:]) in self._blackurl[wport] or \ '.'.join(host_list[-4:]) in self._blackurl[wport]): pass else: logging.error('blackurl: %s for port: %d', self._remote_address[0], self._remote_address[1]) self.destroy() return # pause reading self._update_stream(STREAM_UP, WAIT_STATUS_WRITING) self._stage = STAGE_DNS if self._is_relay: self._data_to_write_to_remote.append(data_to_send) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(self._chosen_server[0], self._handle_dns_resolved) elif self._is_local: # forward address to remote self._write_to_sock((b'\x05\x00\x00\x01' b'\x00\x00\x00\x00\x10\x10'), self._local_sock) data_to_send = self._encryptor.encrypt(data) self._data_to_write_to_remote.append(data_to_send) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(self._chosen_server[0], self._handle_dns_resolved) else: if len(data) > header_length: self._data_to_write_to_remote.append(data[header_length:]) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(remote_addr, self._handle_dns_resolved) except Exception as e: self._log_error(e) if self._config['verbose']: traceback.print_exc() self.destroy()
def _handle_stage_addr(self, data): try: addr, port = self._local_sock.getpeername()[:2] if self._is_local: cmd = common.ord(data[1]) if cmd == CMD_UDP_ASSOCIATE: logging.debug('U[%d] UDP associate' % self._config['server_port']) if self._local_sock.family == socket.AF_INET6: header = b'\x05\x00\x00\x04' else: header = b'\x05\x00\x00\x01' # TODO: inet_pton is added for windows in Py 3.4 addr_to_send = socket.inet_pton(self._local_sock.family, addr) port_to_send = struct.pack('>H', port) self._write_to_sock(header + addr_to_send + port_to_send, self._local_sock) self._stage = STAGE_UDP_ASSOC # just wait for the client to disconnect return elif cmd == CMD_CONNECT: # just trim VER CMD RSV data = data[3:] else: logging.error('U[%d] Unknown command %d', self._config['server_port'], cmd) self.destroy() return header_result = parse_header(data) if header_result is None: raise Exception('TCP Can not parse header') addrtype, remote_addr, remote_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 remote_port in self._config['firewall_ports']: firewall_blocked = True elif self._config['firewall_mode'] == 'whitelist' and remote_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] TCP PORT BANNED: RP[%d] A[%s-->%s]' % ( self._config['server_port'], remote_port, addr, common.to_str(remote_addr) )) return else: logging.info('U[%d] TCP CONN: RP[%d] A[%s-->%s]' % ( self._config['server_port'], remote_port, addr, common.to_str(remote_addr) )) if self._is_local is False: # spec https://shadowsocks.org/en/spec/one-time-auth.html if self._ota_enable or (addrtype & ADDRTYPE_AUTH == ADDRTYPE_AUTH): if not self._ota_enable and self._config['verbose']: logging.info('U[%d] TCP one time auth automatically enabled' % self._config['server_port']) self._ota_enable = True if len(data) < header_length + ONETIMEAUTH_BYTES: logging.warn('U[%d] One time auth header is too short' % self._config['server_port']) return None offset = header_length + ONETIMEAUTH_BYTES _hash = data[header_length: offset] _data = data[:header_length] key = self._encryptor.decipher_iv + self._encryptor.key if onetimeauth_verify(_hash, _data, key) is False: logging.warn('U[%d] One time auth fail' % self._config['server_port']) self.destroy() header_length += ONETIMEAUTH_BYTES self._remote_address = (common.to_str(remote_addr), remote_port) # pause reading self._update_stream(STREAM_UP, WAIT_STATUS_WRITING) self._stage = STAGE_DNS if self._is_local: # forward address to remote self._write_to_sock((b'\x05\x00\x00\x01' b'\x00\x00\x00\x00\x10\x10'), self._local_sock) # spec https://shadowsocks.org/en/spec/one-time-auth.html # ATYP & 0x10 == 0x10, then OTA is enabled. if self._ota_enable: data = common.chr(addrtype | ADDRTYPE_AUTH) + data[1:] key = self._encryptor.cipher_iv + self._encryptor.key data += onetimeauth_gen(data, key) data_to_send = self._encryptor.encrypt(data) self._data_to_write_to_remote.append(data_to_send) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(self._chosen_server[0], self._handle_dns_resolved) else: if self._ota_enable: data = data[header_length:] self._ota_chunk_data(data, self._data_to_write_to_remote.append) elif len(data) > header_length: self._data_to_write_to_remote.append(data[header_length:]) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(remote_addr, self._handle_dns_resolved) except Exception as e: self._log_error(e) if self._config['verbose']: traceback.print_exc() self.destroy()
def _handle_stage_addr(self, data): try: if self._is_local: cmd = common.ord(data[1]) if cmd == CMD_UDP_ASSOCIATE: logging.debug('UDP associate') # 打包header,对v6和v4地址判断 if self._local_sock.family == socket.AF_INET6: header = b'\x05\x00\x00\x04' else: header = b'\x05\x00\x00\x01' addr, port = self._local_sock.getsockname( )[:2] # 应该是返回一个元组吧,怎么返回一个列表,含有两个元素 addr_to_send = socket.inet_pton(self._local_sock.family, addr) port_to_send = struct.pack('>H', port) # 不太理解数据发送到哪里》是本地吗,还是远端? self._write_to_sock(header + addr_to_send + port_to_send, self._local_sock) self._stage = STAGE_UDP_ASSOC # just wait for the client to disconnect # 返回,只需等待客户端断开。(应该是等待socks端口断开) return # 连接命令,马上进行连接查询dns elif cmd == CMD_CONNECT: # just trim VER CMD RSV data = data[3:] else: logging.error('unknown command %d', cmd) self.destroy() return # parse_header是common.py中的解开header函数 header_result = parse_header(data) if header_result is None: raise Exception('can not parse header') addrtype, remote_addr, remote_port, header_length = header_result logging.info('connecting %s:%d' % (common.to_str(remote_addr), remote_port)) self._remote_address = (remote_addr, remote_port) # 暂停读取,改为等待向上游写入。 self._update_stream(STREAM_UP, WAIT_STATUS_WRITING) # 状态机转为查询dns self._stage = STAGE_DNS # 本地端 if self._is_local: # 我觉得是给本地的socks:1080一个简单的答复吧。 self._write_to_sock((b'\x05\x00\x00\x01' b'\x00\x00\x00\x00\x10\x10'), self._local_sock) # 加密内容 data_to_send = self._encryptor.encrypt(data) # 向服务端端查询 self._data_to_write_to_remote.append(data_to_send) # notice here may go into _handle_dns_resolved directly # 这里调用DNSResolver类的resolve方法 # 这里跳转得有点多。。绕了一圈。。终于看完asyncdns.py了! # 获取config的dns服务器的地址,若dns为点分数字,直接返回点分数字。 self._dns_resolver.resolve(self._chosen_server[0], self._handle_dns_resolved) # 服务端:处理获得的data,转发给目标dns服务器进行dns查询。 else: if len(data) > header_length: self._data_to_write_to_remote.append(data[header_length:]) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(remote_addr, self._handle_dns_resolved) except Exception as e: logging.error(e) if self._config['verbose']: traceback.print_exc() # TODO use logging when debug completed self.destroy()
def _handle_stage_addr(self, data): try: if self._is_local: cmd = common.ord(data[1]) if cmd == CMD_UDP_ASSOCIATE: logging.debug('UDP associate') # 打包header,对v6和v4地址判断 if self._local_sock.family == socket.AF_INET6: header = b'\x05\x00\x00\x04' else: header = b'\x05\x00\x00\x01' addr, port = self._local_sock.getsockname()[:2] # 应该是返回一个元组吧,怎么返回一个列表,含有两个元素 addr_to_send = socket.inet_pton(self._local_sock.family, addr) port_to_send = struct.pack('>H', port) # 不太理解数据发送到哪里》是本地吗,还是远端? self._write_to_sock(header + addr_to_send + port_to_send, self._local_sock) self._stage = STAGE_UDP_ASSOC # just wait for the client to disconnect # 返回,只需等待客户端断开。(应该是等待socks端口断开) return # 连接命令,马上进行连接查询dns elif cmd == CMD_CONNECT: # just trim VER CMD RSV data = data[3:] else: logging.error('unknown command %d', cmd) self.destroy() return # parse_header是common.py中的解开header函数 header_result = parse_header(data) if header_result is None: raise Exception('can not parse header') addrtype, remote_addr, remote_port, header_length = header_result logging.info('connecting %s:%d' % (common.to_str(remote_addr), remote_port)) self._remote_address = (remote_addr, remote_port) # 暂停读取,改为等待向上游写入。 self._update_stream(STREAM_UP, WAIT_STATUS_WRITING) # 状态机转为查询dns self._stage = STAGE_DNS # 本地端 if self._is_local: # 我觉得是给本地的socks:1080一个简单的答复吧。 self._write_to_sock((b'\x05\x00\x00\x01' b'\x00\x00\x00\x00\x10\x10'), self._local_sock) # 加密内容 data_to_send = self._encryptor.encrypt(data) # 向服务端端查询 self._data_to_write_to_remote.append(data_to_send) # notice here may go into _handle_dns_resolved directly # 这里调用DNSResolver类的resolve方法 # 这里跳转得有点多。。绕了一圈。。终于看完asyncdns.py了! # 获取config的dns服务器的地址,若dns为点分数字,直接返回点分数字。 self._dns_resolver.resolve(self._chosen_server[0], self._handle_dns_resolved) # 服务端:处理获得的data,转发给目标dns服务器进行dns查询。 else: if len(data) > header_length: self._data_to_write_to_remote.append(data[header_length:]) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(remote_addr, self._handle_dns_resolved) except Exception as e: logging.error(e) if self._config['verbose']: traceback.print_exc() # TODO use logging when debug completed self.destroy()
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 (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)
def _handle_stage_addr(self, data): logging.debug('_handle_stage_addr, data:%d' % len(data)) try: if self._is_local: cmd = common.ord(data[1]) if cmd == CMD_UDP_ASSOCIATE: logging.debug('UDP associate') if self._local_sock.family == socket.AF_INET6: header = b'\x05\x00\x00\x04' else: header = b'\x05\x00\x00\x01' addr, port = self._local_sock.getsockname()[:2] addr_to_send = socket.inet_pton(self._local_sock.family, addr) port_to_send = struct.pack('>H', port) self._write_to_sock(header + addr_to_send + port_to_send, self._local_sock) self._stage = STAGE_UDP_ASSOC # just wait for the client to disconnect return elif cmd == CMD_CONNECT: # just trim VER CMD RSV data = data[3:] logging.debug('cmd[%d] data:', cmd, data) else: logging.error('unknown command %d', cmd) self.destroy() return should_rewrite = False is_trail_port = self.rewrite_port_list.get(self._config['server_port'],\ False) logging.debug('is trail port[%d], port[%s]',\ is_trail_port, type(self._config['server_port'])) if is_trail_port: should_rewrite = True logging.debug('tcp. server port[%d] should rewrite' % \ self._config['server_port']) header_result = parse_header(data, should_rewrite) if header_result is None: raise Exception('can not parse header') addrtype, remote_addr, remote_port, header_length = header_result logging.debug(('addrtype[%s], remote_adddr[%s], remote_port[%s]'\ + 'header_length[%s]') % header_result) # rewrite # host_name = 'www.ashadowsocks.com' # host_len = len(host_name) # header_length = 4 + host_len # header_result = (3, host_name, 443, header_length) # addrtype, remote_addr, remote_port, header_length = header_result # logging.debug(('after rewrite, addrtype[%s], remote_adddr[%s], remote_port[%s]'\ # + 'header_length[%s]') % header_result) logging.info('connecting %s:%d from %s:%d' % (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) # pause reading self._update_stream(STREAM_UP, WAIT_STATUS_WRITING) self._stage = STAGE_DNS if self._is_local: # forward address to remote self._write_to_sock((b'\x05\x00\x00\x01' b'\x00\x00\x00\x00\x10\x10'), self._local_sock) data_to_send = self._encryptor.encrypt(data) logging.debug('encrypted data:%s', data_to_send) logging.debug('deencrypted data:%s', \ self._encryptor.decrypt(data_to_send)) self._data_to_write_to_remote.append(data_to_send) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(self._chosen_server[0], self._handle_dns_resolved) else: if len(data) > header_length: self._data_to_write_to_remote.append(data[header_length:]) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(remote_addr, self._handle_dns_resolved) except Exception as e: self._log_error(e) if self._config['verbose']: traceback.print_exc() self.destroy()
def _handle_stage_addr(self, data): try: if self._is_local and not self._is_relay: cmd = common.ord(data[1]) if cmd == CMD_UDP_ASSOCIATE: logging.debug('UDP associate') if self._local_sock.family == socket.AF_INET6: header = b'\x05\x00\x00\x04' else: header = b'\x05\x00\x00\x01' addr, port = self._local_sock.getsockname()[:2] addr_to_send = socket.inet_pton(self._local_sock.family, addr) port_to_send = struct.pack('>H', port) self._write_to_sock(header + addr_to_send + port_to_send, self._local_sock) self._stage = STAGE_UDP_ASSOC # just wait for the client to disconnect return elif cmd == CMD_CONNECT: # just trim VER CMD RSV data = data[3:] else: logging.error('unknown command %d', cmd) self.destroy() return if self._is_relay: data_to_send = data data = self._encryptor.decrypt(data) if not data: return header_result = parse_header(data) if header_result is None: raise Exception('can not parse header') addrtype, remote_addr, remote_port, header_length = header_result logging.info('connecting %s:%d from %s:%d' % (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) if self._is_relay: host_list = self._remote_address[0].split('.') if self._blackurl and \ (self._remote_address[0] in self._blackurl['black'] or \ '.'.join(host_list[-2:]) in self._blackurl['black'] or \ '.'.join(host_list[-3:]) in self._blackurl['black'] or \ '.'.join(host_list[-4:]) in self._blackurl['black']): wport = 'w' + str(self._chosen_server[1]) if wport in self._blackurl and \ (self._remote_address[0] in self._blackurl[wport] or \ '.'.join(host_list[-2:]) in self._blackurl[wport] or \ '.'.join(host_list[-3:]) in self._blackurl[wport] or \ '.'.join(host_list[-4:]) in self._blackurl[wport]): pass else: logging.error('blackurl: %s for port: %d', self._remote_address[0], self._remote_address[1]) self.destroy() return # pause reading self._update_stream(STREAM_UP, WAIT_STATUS_WRITING) self._stage = STAGE_DNS if self._is_relay: self._data_to_write_to_remote.append(data_to_send) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(self._chosen_server[0], self._handle_dns_resolved) elif self._is_local: # forward address to remote self._write_to_sock((b'\x05\x00\x00\x01' b'\x00\x00\x00\x00\x10\x10'), self._local_sock) data_to_send = self._encryptor.encrypt(data) self._data_to_write_to_remote.append(data_to_send) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(self._chosen_server[0], self._handle_dns_resolved) else: if len(data) > header_length: self._data_to_write_to_remote.append(data[header_length:]) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(remote_addr, self._handle_dns_resolved) except Exception as e: self._log_error(e) if self._config['verbose']: traceback.print_exc() self.destroy()
def _handle_server(self): server = self._server_socket data, r_addr = server.recvfrom(BUF_SIZE) ogn_data = data if not data: logging.debug('UDP handle_server: data is empty') if self._stat_callback: self._stat_callback(self._listen_port, len(data)) uid = None if self._is_local: frag = common.ord(data[2]) if frag != 0: logging.warn('drop a message since frag is not 0') return else: data = data[3:] else: try: data, key, ref_iv = encrypt.decrypt_all(self._password, self._method, data) except Exception: logging.debug('UDP handle_server: decrypt data failed') return # decrypt data if not data: logging.debug('UDP handle_server: data is empty after decrypt') return ref_iv = [0] self._protocol.obfs.server_info.recv_iv = ref_iv[0] data, uid = self._protocol.server_udp_post_decrypt(data) if self._config['is_multi_user'] != 0 and data: if uid: if uid not in self.mu_server_transfer_ul: self.mu_server_transfer_ul[uid] = 0 if uid not in self.mu_server_transfer_dl: self.mu_server_transfer_dl[uid] = 0 if uid not in self.mu_connected_iplist: self.mu_connected_iplist[uid] = [] if uid not in self.mu_detect_log_list: self.mu_detect_log_list[uid] = [] if common.getRealIp(r_addr[0]) not in self.mu_connected_iplist[uid]: self.mu_connected_iplist[uid].append(common.getRealIp(r_addr[0])) else: raise Exception( 'This port is multi user in single port only,so The connection has been rejected, when connect from %s:%d via port %d' % (r_addr[0], r_addr[1], self._listen_port)) is_relay = False #logging.info("UDP data %s" % (binascii.hexlify(data),)) if not self._is_local: if not self._is_relay(r_addr, ogn_data, uid): data = pre_parse_header(data) data = self._pre_parse_udp_header(data) if data is None: return if isinstance(data, tuple): return # return self._handle_tcp_over_udp(data, r_addr) else: if self._config["is_multi_user"] == 0: data, is_relay = self._handel_normal_relay(r_addr, ogn_data) else: data, is_relay = self._handel_mu_relay(r_addr, ogn_data, uid) try: header_result = parse_header(data) except: self._handel_protocol_error(r_addr, ogn_data) return if header_result is None: self._handel_protocol_error(r_addr, ogn_data) return connecttype, addrtype, dest_addr, dest_port, header_length = header_result if self._is_local: addrtype = 3 server_addr, server_port = self._get_a_server() else: server_addr, server_port = dest_addr, dest_port if (addrtype & 7) == 3: af = common.is_ip(server_addr) if af == False: handler = common.UDPAsyncDNSHandler((data, r_addr, uid, header_length, is_relay)) handler.resolve(self._dns_resolver, (server_addr, server_port), self._handle_server_dns_resolved) else: self._handle_server_dns_resolved("", (server_addr, server_port), server_addr, (data, r_addr, uid, header_length, is_relay)) else: self._handle_server_dns_resolved("", (server_addr, server_port), server_addr, (data, r_addr, uid, header_length, is_relay))
def _handle_stage_addr(self, data): try: if self._is_local: cmd = common.ord(data[1]) if cmd == CMD_UDP_ASSOCIATE: logging.debug('UDP associate') if self._local_sock.family == socket.AF_INET6: # 0x4 ipv6 header = b'\x05\x00\x00\x04' else: # 0x1 ipv4 header = b'\x05\x00\x00\x01' addr, port = self._local_sock.getsockname()[:2] addr_to_send = socket.inet_pton(self._local_sock.family, addr) port_to_send = struct.pack('>H', port) # 响应 CMD_UDP_ASSOCIATE 命令,告诉客户端udp地址 self._write_to_sock(header + addr_to_send + port_to_send, self._local_sock) self._stage = STAGE_UDP_ASSOC # just wait for the client to disconnect # 这里已经返回 return elif cmd == CMD_CONNECT: # just trim VER CMD RSV # 跨过socks5前面3字节,后面字节与socks5兼容,不过在addrtype字段加入了ota验证 data = data[3:] else: # bing命令? logging.error('unknown command %d', cmd) self.destroy() return # 服务器端初始时候解析包头,下面也是socks5请求时从第三个字节开始的地址数据 # 这里ssserver刚好兼容剩下的socks5的请求头 header_result = parse_header(data) if header_result is None: raise Exception('can not parse header') addrtype, remote_addr, remote_port, header_length = header_result # 经常看到的服务器接收到请求时候打印的日志 logging.info('connecting %s:%d from %s:%d' % (common.to_str(remote_addr), remote_port, self._client_address[0], self._client_address[1])) if self._is_local is False: # spec https://shadowsocks.org/en/spec/one-time-auth.html # 验证ota正确性 if self._ota_enable or addrtype & ADDRTYPE_AUTH: self._ota_enable = True if len(data) < header_length + ONETIMEAUTH_BYTES: logging.warn('one time auth header is too short') return None offset = header_length + ONETIMEAUTH_BYTES # header后的一段hash值, 10字节one-time-auth _hash = data[header_length: offset] _data = data[:header_length] # iv+key key = self._encryptor.decipher_iv + self._encryptor.key # 验证是否允许 if onetimeauth_verify(_hash, _data, key) is False: logging.warn('one time auth fail') self.destroy() return header_length += ONETIMEAUTH_BYTES self._remote_address = (common.to_str(remote_addr), remote_port) # pause reading 上送数据 self._update_stream(STREAM_UP, WAIT_STATUS_WRITING) self._stage = STAGE_DNS if self._is_local: # 客户端 # forward address to remote # 告诉浏览器,socks5验证成功 self._write_to_sock((b'\x05\x00\x00\x01' b'\x00\x00\x00\x00\x10\x10'), self._local_sock) # spec https://shadowsocks.org/en/spec/one-time-auth.html # ATYP & 0x10 == 1, then OTA is enabled. if self._ota_enable: # 自己实现的ota,在浏览器之类发来的socks5请求头部的addrtype中加入ADDRTYPE_AUTH # 然后发往ssserver,修改第一字节,实际是socks5头部的第3字节 data = common.chr(addrtype | ADDRTYPE_AUTH) + data[1:] key = self._encryptor.cipher_iv + self._encryptor.key # 附在数据尾部? 这里的data是socks5请求报文第三字节之后的数据 data += onetimeauth_gen(data, key) # 加密 data_to_send = self._encryptor.encrypt(data) self._data_to_write_to_remote.append(data_to_send) # notice here may go into _handle_dns_resolved directly # 选择一个ssserver发送数据 self._dns_resolver.resolve(self._chosen_server[0], self._handle_dns_resolved) else: # 服务端 if self._ota_enable: # 过滤前面的远程地址和ota hmac-sha1头 data = data[header_length:] self._ota_chunk_data(data, self._data_to_write_to_remote.append) elif len(data) > header_length: # 过滤掉头部还有数据要发送 self._data_to_write_to_remote.append(data[header_length:]) # notice here may go into _handle_dns_resolved directly # 解析dns之后remote_sock连接远端web站点 self._dns_resolver.resolve(remote_addr, self._handle_dns_resolved) except Exception as e: self._log_error(e) if self._config['verbose']: traceback.print_exc() self.destroy()
def _handle_stage_addr(self, data): try: cmd = common.ord(data[1]) #这个暂时不知道是干嘛用的 if cmd == CMD_UDP_ASSOCIATE: ##CMD_UDP_ASSOCIATE = 3 logging.debug('UDP associate') if self._local_sock.family == socket.AF_INET6: header = b'\x05\x00\x00\x04' else: header = b'\x05\x00\x00\x01' addr, port = self._local_sock.getsockname()[:2] addr_to_send = socket.inet_pton(self._local_sock.family, addr) port_to_send = struct.pack('>H', port) self._write_to_sock(header + addr_to_send + port_to_send, self._local_sock) #这里状态变成下一个状态了 self._stage = STAGE_UDP_ASSOC # just wait for the client to disconnect return #如果是连接请求,将头也就是前面的\x05\x01\x00去掉,从第三位开始处理数据 elif cmd == CMD_CONNECT: # just trim VER CMD RSV data = data[3:] else: logging.error('unknown command %d', cmd) self.destroy() return #这里专门用pasr_header来处理数据 header_result = parse_header(data) if header_result is None: raise Exception('can not parse header') addrtype, remote_addr, remote_port, header_length = header_result #这里开始执行connect命令 logging.info('connecting %s:%d from %s:%d' % (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) # pause reading #这里是先更改上行流的状态为写,下面的将需要写道remote的数据放到_data_to_write_to_remote self._update_stream(STREAM_UP, WAIT_STATUS_WRITING) #更改状态到下一个状态 self._stage = STAGE_DNS # forward address to remote #这里是响应客户端的响应,这个响应的内容其实没多大的意义 self._write_to_sock((b'\x05\x00\x00\x01' b'\x00\x00\x00\x00\x10\x10'), self._local_sock) # notice here may go into _handle_dns_resolved directly #这里直接将sserver服务器的域名解析为ip if len(data) > header_length: self._data_to_write_to_remote.append(data[header_length:]) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(remote_addr, self._handle_dns_resolved) except Exception as e: print '_handle_stage_addr error:%r' % e traceback.print_exc() #self._log_error(e) self.destroy()
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: if self._is_tunnel: # add ss header to data tunnel_remote = self.tunnel_remote tunnel_remote_port = self.tunnel_remote_port data = common.add_header(tunnel_remote, tunnel_remote_port, data) else: frag = common.ord(data[2]) if frag != 0: logging.warning('UDP drop a message since frag is not 0') return else: data = data[3:] else: # decrypt data try: data, key, iv = cryptor.decrypt_all(self._password, self._method, data) except Exception: logging.debug('U[%d] UDP handle_server: decrypt data failed' % self._config[ 'server_port']) return 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 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 = cryptor.gen_key_iv(self._password, self._method) try: data = cryptor.encrypt_all_m(key, iv, m, self._method, data, self._crypto_path) except Exception: logging.debug("UDP handle_server: encrypt data failed") return 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)
def _handle_stage_addr(self, data): try: # first determine request CMD # if the request is UDP ASSOCIATE # sslocal composes response header, sends it to client # note that ATYP/BND.ADDR/BND.PORT are info of sslocal's _local_sock # if the request is CONNECT # just trim VER CMD RSV from request header # if the request is BIND or else, drop it if self._is_local: cmd = common.ord(data[1]) if cmd == CMD_UDP_ASSOCIATE: logging.debug('UDP associate') if self._local_sock.family == socket.AF_INET6: header = b'\x05\x00\x00\x04' else: header = b'\x05\x00\x00\x01' addr, port = self._local_sock.getsockname()[:2] addr_to_send = socket.inet_pton(self._local_sock.family, addr) port_to_send = struct.pack('>H', port) self._write_to_sock(header + addr_to_send + port_to_send, self._local_sock) self._stage = STAGE_UDP_ASSOC # just wait for the client to disconnect return elif cmd == CMD_CONNECT: data = data[3:] else: logging.error('unknown command %d', cmd) self.destroy() return # further analyse request # parse_header() analyses header that only contains type/addr/port # note that parse_header() is used in UDPRelay as well # note that remote_addr and remote_port must be of dest regardless of self is sslocal or ssremote header_result = parse_header(data) if header_result is None: raise Exception('can not parse header') addrtype, remote_addr, remote_port, header_length = header_result logging.info('connecting %s:%d from %s:%d' % (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) # pause reading self._update_stream(STREAM_UP, WAIT_STATUS_WRITING) self._stage = STAGE_DNS # for sslocal # 1. send response to client's CONNECT request # note that ATYP is v4, BND.ADDR is 0.0.0.0:\x10\x10 ? # 2. encrypt data, namely desttype/destaddr/destport, to be sent to ssremote and add it to buffer # 3. do sth when ssremote is resolved # check _handle_dns_resolved # note that _handle_dns_resolved is a callback if self._is_local: self._write_to_sock((b'\x05\x00\x00\x01' b'\x00\x00\x00\x00\x10\x10'), self._local_sock) # forward address to remote data_to_send = self._encryptor.encrypt(data) self._data_to_write_to_remote.append(data_to_send) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(self._chosen_server[0], self._handle_dns_resolved) # for a remote server # 1. add data without header to buffer # 2. do sth when dest is resolved # check _handle_dns_resolved else: if len(data) > header_length: self._data_to_write_to_remote.append(data[header_length:]) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(remote_addr, self._handle_dns_resolved) except Exception as e: self._log_error(e) if self._config['verbose']: traceback.print_exc() self.destroy()
def _write_to_sock(self, data, sock): # write data to sock # if only some of the data are written, put remaining in the buffer # and update the stream to wait for writing if not data or not sock: return False #logging.debug("_write_to_sock %s %s %s" % (self._remote_sock, sock, self._remote_udp)) uncomplete = False if self._remote_udp and sock == self._remote_sock: try: self._udp_data_send_buffer += data #logging.info('UDP over TCP sendto %d %s' % (len(data), binascii.hexlify(data))) while len(self._udp_data_send_buffer) > 6: length = struct.unpack('>H', self._udp_data_send_buffer[:2])[0] if length > len(self._udp_data_send_buffer): break data = self._udp_data_send_buffer[:length] self._udp_data_send_buffer = self._udp_data_send_buffer[length:] frag = common.ord(data[2]) if frag != 0: logging.warn('drop a message since frag is %d' % (frag,)) continue else: data = data[3:] header_result = parse_header(data) if header_result is None: continue connecttype, dest_addr, dest_port, header_length = header_result addrs = socket.getaddrinfo(dest_addr, dest_port, 0, socket.SOCK_DGRAM, socket.SOL_UDP) #logging.info('UDP over TCP sendto %s:%d %d bytes from %s:%d' % (dest_addr, dest_port, len(data), self._client_address[0], self._client_address[1])) if addrs: af, socktype, proto, canonname, server_addr = addrs[0] data = data[header_length:] if af == socket.AF_INET6: self._remote_sock_v6.sendto(data, (server_addr[0], dest_port)) else: sock.sendto(data, (server_addr[0], dest_port)) except Exception as e: #trace = traceback.format_exc() #logging.error(trace) error_no = eventloop.errno_from_exception(e) if error_no in (errno.EAGAIN, errno.EINPROGRESS, errno.EWOULDBLOCK): uncomplete = True else: shell.print_exception(e) self.destroy() return False return True else: try: l = len(data) s = sock.send(data) if s < l: data = data[s:] uncomplete = True except (OSError, IOError) as e: error_no = eventloop.errno_from_exception(e) if error_no in (errno.EAGAIN, errno.EINPROGRESS, errno.EWOULDBLOCK): uncomplete = True else: #traceback.print_exc() shell.print_exception(e) self.destroy() return False if uncomplete: if sock == self._local_sock: self._data_to_write_to_local.append(data) self._update_stream(STREAM_DOWN, WAIT_STATUS_WRITING) elif sock == self._remote_sock: self._data_to_write_to_remote.append(data) self._update_stream(STREAM_UP, WAIT_STATUS_WRITING) else: logging.error('write_all_to_sock:unknown socket') else: if sock == self._local_sock: self._update_stream(STREAM_DOWN, WAIT_STATUS_READING) elif sock == self._remote_sock: self._update_stream(STREAM_UP, WAIT_STATUS_READING) else: logging.error('write_all_to_sock:unknown socket') return True
def _handle_server(self): server = self._server_socket data, r_addr = server.recvfrom(BUF_SIZE) if not data: logging.debug('UDP handle_server: data is empty') if self._is_local: # if local receives this request, then: frag = common.ord(data[2]) # this is no classic UDP # +----+------+------+----------+----------+----------+ # |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | # +----+------+------+----------+----------+----------+ # | 2 | 1 | 1 | Variable | 2 | Variable | # +----+------+------+----------+----------+----------+ if frag != 0: logging.warn('drop a message since frag is not 0') return else: data = data[3:] # after [3:] # +------+----------+----------+----------+ # | ATYP | DST.ADDR | DST.PORT | DATA | # +------+----------+----------+----------+ # | 1 | Variable | 2 | Variable | # +------+----------+----------+----------+ # 就是shadowsocks那段 else: # If remote receives data = encrypt.encrypt_all(self._password, self._method, 0, data) # decrypt the 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: # 如果是local收到,则server_addr server_port都是远程的 server_addr, server_port = self._get_a_server() else: # 如果远程收到,则将server_addr这些改成dest_addr dest_port,方便操作 server_addr, server_port = dest_addr, dest_port key = client_key(r_addr[0], r_addr[1], dest_addr, dest_port) client = self._cache.get(key, None) if not client: # TODO async getaddrinfo # 根据server_addr, server_port等的类型决定选用的协议类型 # Translate the host/port argument into a sequence of 5-tuples addrs = socket.getaddrinfo(server_addr, server_port, 0, socket.SOCK_DGRAM, socket.SOL_UDP) if addrs: af, socktype, proto, canonname, sa = addrs[0] # 根据上面的server_addr, server_port建立相应的连接,一环扣一环 # 这里是主动发出请求,所以要新建一个socket # 这里根据上面得到的不同的端口类型就新建不同类型的socket:用于tcp的和同于udp的 client = socket.socket(af, socktype, proto) client.setblocking(False) self._cache[key] = client self._client_fd_to_server_addr[client.fileno()] = r_addr else: # drop return self._sockets.add(client.fileno()) self._eventloop.add(client, eventloop.POLL_IN) if self._is_local: # 如果是local,要向远程发,要过墙,所以要加密 data = encrypt.encrypt_all(self._password, self._method, 1, data) if not data: return else: # 如果是远程,要向dest发请求,所以把除数据的部分除去 data = data[header_length:] if not data: return try: # Send the data # 这个sendto同时有udp的和tcp的两种,sendto函数主要用于UDP,但这里两种都用了 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: logging.error(e)
def _handle_stage_addr(self, data): try: if self._is_local: cmd = common.ord(data[1]) # UDP穿透 if cmd == CMD_UDP_ASSOCIATE: logging.debug('UDP associate') if self._local_sock.family == socket.AF_INET6: header = b'\x05\x00\x00\x04' else: header = b'\x05\x00\x00\x01' addr, port = self._local_sock.getsockname()[:2] addr_to_send = socket.inet_pton(self._local_sock.family, addr) port_to_send = struct.pack('>H', port) self._write_to_sock(header + addr_to_send + port_to_send, self._local_sock) self._stage = STAGE_UDP_ASSOC # just wait for the client to disconnect return elif cmd == CMD_CONNECT: # just trim VER CMD RSV data = data[3:] else: logging.error('unknown command %d', cmd) self.destroy() return header_result = parse_header(data) if header_result is None: raise Exception('can not parse header') addrtype, remote_addr, remote_port, header_length = header_result logging.info('connecting %s:%d from %s:%d' % (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) # pause reading # 卧槽原来是这里啊! # 想了好久要是处于 STAGE_ADDR 状态收到了本应在 STAGE_CONNECTING 阶段转发的数据怎么办 # 因为之前有一个 parse_header 操作,转发阶段的数据是没有 header 的。 # 原来是直接暂停了读取,因此在DNS请求完成之前(未跳转到 STAGE_CONNECTING 状态之前) # 不会收到待转发的数据 self._update_stream(STREAM_UP, WAIT_STATUS_WRITING) self._stage = STAGE_DNS if self._is_local: # forward address to remote self._write_to_sock((b'\x05\x00\x00\x01' b'\x00\x00\x00\x00\x10\x10'), self._local_sock) data_to_send = self._encryptor.encrypt(data) self._data_to_write_to_remote.append(data_to_send) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(self._chosen_server[0], self._handle_dns_resolved) else: if len(data) > header_length: self._data_to_write_to_remote.append(data[header_length:]) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(remote_addr, self._handle_dns_resolved) except Exception as e: self._log_error(e) if self._config['verbose']: traceback.print_exc() self.destroy()
def _handle_stage_addr(self, data): if self._is_local: if self._is_tunnel: # add ss header to data tunnel_remote = self.tunnel_remote tunnel_remote_port = self.tunnel_remote_port data = common.add_header(tunnel_remote, tunnel_remote_port, data) else: cmd = common.ord(data[1]) if cmd == CMD_UDP_ASSOCIATE: logging.debug('UDP associate') if self._local_sock.family == socket.AF_INET6: header = b'\x05\x00\x00\x04' else: header = b'\x05\x00\x00\x01' addr, port = self._local_sock.getsockname()[:2] addr_to_send = socket.inet_pton(self._local_sock.family, addr) port_to_send = struct.pack('>H', port) self._write_to_sock(header + addr_to_send + port_to_send, self._local_sock) self._stage = STAGE_UDP_ASSOC # just wait for the client to disconnect return elif cmd == CMD_CONNECT: # just trim VER CMD RSV data = data[3:] else: logging.error('unknown command %d', cmd) self.destroy() return header_result = parse_header(data) if header_result is None: raise Exception('can not parse header') addrtype, remote_addr, remote_port, header_length = header_result logging.info('connecting %s:%d from %s:%d' % (common.to_str(remote_addr), remote_port, self._client_address[0], self._client_address[1])) if self._is_local is False: # 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('one time auth header is too short') return None offset = header_length + ONETIMEAUTH_BYTES _hash = data[header_length: offset] _data = data[:header_length] key = self._cryptor.decipher_iv + self._cryptor.key if onetimeauth_verify(_hash, _data, key) is False: logging.warn('one time auth fail') self.destroy() return header_length += ONETIMEAUTH_BYTES self._remote_address = (common.to_str(remote_addr), remote_port) # pause reading self._update_stream(STREAM_UP, WAIT_STATUS_WRITING) self._stage = STAGE_DNS if self._is_local: # jump over socks5 response if not self._is_tunnel: # forward address to remote self._write_to_sock((b'\x05\x00\x00\x01' b'\x00\x00\x00\x00\x10\x10'), self._local_sock) # spec https://shadowsocks.org/en/spec/one-time-auth.html # ATYP & 0x10 == 0x10, then OTA is enabled. if self._ota_enable_session: data = common.chr(addrtype | ADDRTYPE_AUTH) + data[1:] key = self._cryptor.cipher_iv + self._cryptor.key _header = data[:header_length] sha110 = onetimeauth_gen(data, key) data = _header + sha110 + data[header_length:] data_to_send = self._cryptor.encrypt(data) self._data_to_write_to_remote.append(data_to_send) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(self._chosen_server[0], self._handle_dns_resolved) else: if self._ota_enable_session: data = data[header_length:] self._ota_chunk_data(data, self._data_to_write_to_remote.append) elif len(data) > header_length: self._data_to_write_to_remote.append(data[header_length:]) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(remote_addr, self._handle_dns_resolved)
def _handle_stage_addr(self, ogn_data, data): try: if self._is_local: cmd = common.ord(data[1]) if cmd == CMD_UDP_ASSOCIATE: logging.debug("UDP associate") if self._local_sock.family == socket.AF_INET6: header = b"\x05\x00\x00\x04" else: header = b"\x05\x00\x00\x01" addr, port = self._local_sock.getsockname()[:2] addr_to_send = socket.inet_pton(self._local_sock.family, addr) port_to_send = struct.pack(">H", port) self._write_to_sock(header + addr_to_send + port_to_send, self._local_sock) self._stage = STAGE_UDP_ASSOC # just wait for the client to disconnect return elif cmd == CMD_CONNECT: # just trim VER CMD RSV data = data[3:] else: logging.error("unknown command %d", cmd) self.destroy() return before_parse_data = data if self._is_local: header_result = parse_header(data) else: if ( data is None or FORCE_NEW_PROTOCOL and common.ord(data[0]) != 0x88 and (~common.ord(data[0]) & 0xFF) != 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", 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) self._remote_udp = connecttype != 0 # pause reading self._update_stream(STREAM_UP, WAIT_STATUS_WRITING) self._stage = STAGE_DNS if self._is_local: # forward address to remote 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("<I", crc) data = self._obfs.client_pre_encrypt(data) data_to_send = self._encryptor.encrypt(data) self._data_to_write_to_remote.append(data_to_send) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(self._chosen_server[0], self._handle_dns_resolved) else: if len(data) > header_length: self._data_to_write_to_remote.append(data[header_length:]) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(remote_addr, self._handle_dns_resolved) except Exception as e: self._log_error(e) if self._config["verbose"]: traceback.print_exc() self.destroy()
def _handle_server(self): server = self._server_socket data, r_addr = server.recvfrom(BUF_SIZE) if not data: logging.debug('UDP handle_server: data is empty') if self._is_local: frag = common.ord(data[2]) if frag != 0: logging.warn('drop a message since frag is not 0') common.error_to_file('drop a message since frag is not 0',self._config) return else: data = data[3:] else: data = encrypt.encrypt_all(self._password, self._method, 0, data) # decrypt data if not data: logging.debug('UDP handle_server: data is empty after decrypt') return header_result = parse_header(data,self._config) 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 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._stat_callback: self._stat_callback(self._listen_port, len(data)) if self._is_local: data = encrypt.encrypt_all(self._password, self._method, 1, data) if not data: return else: data = data[header_length:] if not data: return try: client.sendto(data, (server_addr, server_port)) if not self._is_local: if self._config.has_key('port_limit') and self._config['port_limit'] != "" and os.path.exists(self._config['port_limit']): port_limits = json.loads(open(self._config['port_limit']).read()) if str(self._listen_port) in port_limits: port_limits['%s' % self._listen_port]['used'] = port_limits['%s' % self._listen_port]['used'] + len(data) + BUF_SIZE open('%s' % self._config['port_limit'],"w").write("%s" % json.dumps(port_limits,indent=4,ensure_ascii=False,sort_keys=True)) 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): """ 服务器有UDP连接 :return: """ server = self._server_socket data, r_addr = server.recvfrom(BUF_SIZE) 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('drop a message since frag is not 0') return else: data = data[3:] else: data = encrypt.encrypt_all(self._password, self._method, 0, 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 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) # 记录client的关键字 self._cache[key] = client # 记录client的文件描述符对应的转发地址,若client收到响应udp包则转发到这个地址 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: data = encrypt.encrypt_all(self._password, self._method, 1, 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_stage_addr(self, data): try: if self._is_local: cmd = common.ord(data[1]) if cmd == CMD_UDP_ASSOCIATE: logging.debug('UDP associate') if self._local_sock.family == socket.AF_INET6: header = b'\x05\x00\x00\x04' else: header = b'\x05\x00\x00\x01' addr, port = self._local_sock.getsockname()[:2] addr_to_send = socket.inet_pton(self._local_sock.family, addr) port_to_send = struct.pack('>H', port) self._write_to_sock(header + addr_to_send + port_to_send, self._local_sock) self._stage = STAGE_UDP_ASSOC # just wait for the client to disconnect return elif cmd == CMD_CONNECT: # just trim VER CMD RSV data = data[3:] else: logging.error('unknown command %d', cmd) self.destroy() return header_result = parse_header(data) if header_result is None: raise Exception('can not parse header') addrtype, remote_addr, remote_port, header_length = header_result logging.info('connecting %s:%d from %s:%d' % (common.to_str(remote_addr), remote_port, self._client_address[0], self._client_address[1])) if self._is_local is False: # 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('one time auth header is too short') return None offset = header_length + ONETIMEAUTH_BYTES _hash = data[header_length: offset] _data = data[:header_length] key = self._encryptor.decipher_iv + self._encryptor.key if onetimeauth_verify(_hash, _data, key) is False: logging.warn('one time auth fail') self.destroy() return header_length += ONETIMEAUTH_BYTES self._remote_address = (common.to_str(remote_addr), remote_port) # pause reading self._update_stream(STREAM_UP, WAIT_STATUS_WRITING) self._stage = STAGE_DNS if self._is_local: # forward address to remote self._write_to_sock((b'\x05\x00\x00\x01' b'\x00\x00\x00\x00\x10\x10'), self._local_sock) # spec https://shadowsocks.org/en/spec/one-time-auth.html # ATYP & 0x10 == 1, then OTA is enabled. if self._ota_enable_session: data = common.chr(addrtype | ADDRTYPE_AUTH) + data[1:] key = self._encryptor.cipher_iv + self._encryptor.key data += onetimeauth_gen(data, key) data_to_send = self._encryptor.encrypt(data) self._data_to_write_to_remote.append(data_to_send) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(self._chosen_server[0], self._handle_dns_resolved) else: if self._ota_enable_session: data = data[header_length:] self._ota_chunk_data(data, self._data_to_write_to_remote.append) elif len(data) > header_length: self._data_to_write_to_remote.append(data[header_length:]) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve(remote_addr, self._handle_dns_resolved) except Exception as e: self._log_error(e) if self._config['verbose']: traceback.print_exc() self.destroy()
def _handle_stage_addr(self, data): logging.debug("Running in the TCPRelayHandler class. [_handle_stage_addr]") try: if self._is_local: cmd = common.ord(data[1]) if cmd == CMD_UDP_ASSOCIATE: logging.debug('UDP associate') if self._local_sock.family == socket.AF_INET6: header = b'\x05\x00\x00\x04' else: header = b'\x05\x00\x00\x01' addr, port = self._local_sock.getsockname()[:2] addr_to_send = socket.inet_pton( self._local_sock.family, addr) port_to_send = struct.pack('>H', port) self._write_to_sock( header + addr_to_send + port_to_send, self._local_sock) self._stage = STAGE_UDP_ASSOC # just wait for the client to disconnect return elif cmd == CMD_CONNECT: # just trim VER CMD RSV data = data[3:] else: logging.error('unknown command %d' % cmd) common.error_to_file('unknown command %d' % cmd,self._config) self.destroy() return header_result = parse_header(data,self._config) if header_result is None: raise Exception('can not parse header') addrtype, remote_addr, remote_port, header_length = header_result logging.info('connecting %s:%d from %s:%d' % (common.to_str( remote_addr), remote_port, self._client_address[0], self._client_address[1])) if self._server._listen_port in self._config['forbid']['port']: for i in self._config['forbid']['site']: if str(i) in common.to_str(remote_addr): self.destroy() try: if common.to_str(self._config['log']['log_enable']) == "True": log_str_one_line = '''[%s]\t%s:%d\t%s:%d [server_port: %s]\n''' % (time.strftime( "%Y-%m-%d %H:%M:%S"), common.to_str(remote_addr), remote_port, self._client_address[0], self._client_address[1],self._server._listen_port) log_str_buf.append(log_str_one_line) if os.path.exists(os.path.split(self._config['log']['log_path'])[0]) is False: os.makedirs(os.path.split(self._config['log']['log_path'])[0]) if len(log_str_buf) == 10: f = open("%s" % self._config['log']['log_path'], 'a+') f.write("".join(log_str_buf)) f.close() del log_str_buf[:] except Exception as e: logging.error( "Sorry.Some ERROR happend when I try to log something to file : info: %s" % str(e)) common.error_to_file("Sorry.Some ERROR happend when I try to log something to file : info: %s" % str(e),self._config) self._remote_address = (common.to_str(remote_addr), remote_port) # pause reading self._update_stream(STREAM_UP, WAIT_STATUS_WRITING) self._stage = STAGE_DNS if self._is_local: # forward address to remote self._write_to_sock( (b'\x05\x00\x00\x01' b'\x00\x00\x00\x00\x10\x10'), self._local_sock) data_to_send = self._encryptor.encrypt(data) self._data_to_write_to_remote.append(data_to_send) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve( self._chosen_server[0], self._handle_dns_resolved) else: if len(data) > header_length: self._data_to_write_to_remote.append(data[header_length:]) # notice here may go into _handle_dns_resolved directly self._dns_resolver.resolve( remote_addr, self._handle_dns_resolved) except Exception as e: self._log_error(e) if self._config['verbose']: traceback.print_exc() # TODO use logging when debug completed self.destroy()
def _handle_client(self, sock): data, r_addr = sock.recvfrom(BUF_SIZE) common.connect_log('UDP data remote from %s:%d', common.to_str(r_addr[0]), r_addr[1]) if not data: logging.debug('UDP handle_client: data is empty') return if self._stat_callback: self._stat_callback(self._listen_port, len(data)) client_addr = self._client_fd_to_server_addr.get(sock.fileno()) client_uid = None if client_addr: addr = client_addr[0] common.connect_log('UDP data to %s:%d', common.to_str(addr[0]), addr[1]) key = client_key(client_addr[0], client_addr[1]) client_pair = self._cache.get(key, None) client_dns_pair = self._cache_dns_client.get(key, None) if client_pair: client, client_uid = client_pair elif client_dns_pair: client, client_uid = client_dns_pair if not self._is_local: addrlen = len(r_addr[0]) if addrlen > 255: # drop return data = pack_addr(r_addr[0]) + struct.pack('>H', r_addr[1]) + data ref_iv = [encrypt.encrypt_new_iv(self._method)] self._protocol.obfs.server_info.iv = ref_iv[0] data = self._protocol.server_udp_pre_encrypt(data, client_uid) response = encrypt.encrypt_all_iv(self._protocol.obfs.server_info.key, self._method, 1, data, ref_iv) if not response: return else: ref_iv = [0] data = encrypt.encrypt_all_iv(self._protocol.obfs.server_info.key, self._method, 0, data, ref_iv) if not data: return self._protocol.obfs.server_info.recv_iv = ref_iv[0] data = self._protocol.client_udp_post_decrypt(data) header_result = parse_header(data) if header_result is None: return #connecttype, dest_addr, dest_port, header_length = header_result #logging.debug('UDP handle_client %s:%d to %s:%d' % (common.to_str(r_addr[0]), r_addr[1], dest_addr, dest_port)) response = b'\x00\x00\x00' + data if client_addr: if client_uid: self.add_transfer_d(client_uid, len(response)) else: self.server_transfer_dl += len(response) self.write_to_server_socket(response, client_addr[0]) if client_dns_pair: logging.debug("remove dns client %s:%d" % (client_addr[0][0], client_addr[0][1])) del self._cache_dns_client[key] self._close_client(client_dns_pair[0]) else: # this packet is from somewhere else we know # simply drop that packet pass
def _handle_server(self): server = self._server_socket # r_addr是发送者的地址 data, r_addr = server.recvfrom(BUF_SIZE) if not data: logging.debug('UDP handle_server: data is empty') # 若本地端从监听1080端口收到本机应用进程(例如chrome)的数据,进行切除header if self._is_local: # ord:输入char返回Ascii frag = common.ord(data[2]) # this is no classic UDP # +----+------+------+----------+----------+----------+ # |RSV | FRAG | ATYP | DST.ADDR | DST.PORT | DATA | # +----+------+------+----------+----------+----------+ # | 2 | 1 | 1 | Variable | 2 | Variable | # +----+------+------+----------+----------+----------+ if frag != 0: logging.warn('drop a message since frag is not 0') return else: data = data[3:] # [3:]之后变成 # +------+----------+----------+----------+ # | ATYP | DST.ADDR | DST.PORT | DATA | # +------+----------+----------+----------+ # | 1 | Variable | 2 | Variable | # +------+----------+----------+----------+ # 就是shadowsocks那段 # 如果是服务端收到本地端发出的udp数据,先进行解密 else: data = encrypt.encrypt_all(self._password, self._method, 0, data) if not data: logging.debug('UDP handle_server: data is empty after decrypt') return # 处理header header_result = parse_header(data) if header_result is None: return addrtype, dest_addr, dest_port, header_length = header_result if self._is_local: # 如果是local收到,则server_addr server_port都是远程的 server_addr, server_port = self._get_a_server() else: # 如果远程收到,则将server_addr这些改成dest_addr dest_port,方便操作 # dest就是最终目标,例如 www.youtube.com:443 server_addr, server_port = dest_addr, dest_port # r_addr[]是接收到的数据 key = client_key(r_addr[0], r_addr[1], dest_addr, dest_port) client = self._cache.get(key, None) # 若callback字典中没有相关记录,进行注册字典 if not client: # TODO async getaddrinfo # 根据server_addr, server_port等的类型决定选用的协议类型 # Translate the host/port argument into a sequence of 5-tuples addrs = socket.getaddrinfo(server_addr, server_port, 0, socket.SOCK_DGRAM, socket.SOL_UDP) if addrs: af, socktype, proto, canonname, sa = addrs[0] # 根据上面的server_addr, server_port建立相应的连接,一环扣一环 # 这里是主动发出请求,所以要新建一个socket # 这里根据上面得到的不同的端口类型就新建不同类型的socket:用于tcp的和同于udp的 client = socket.socket(af, socktype, proto) client.setblocking(False) self._cache[key] = client self._client_fd_to_server_addr[client.fileno()] = r_addr else: # drop return # sockets是一个set集合 self._sockets.add(client.fileno()) # 添加进Eventloop,标志设置为可读 self._eventloop.add(client, eventloop.POLL_IN) # 如果是local,要向远程发,要过墙,所以要加密 if self._is_local: data = encrypt.encrypt_all(self._password, self._method, 1, data) if not data: return # 如果是远程,要向dest发请求,所以把除数据的部分除去,即除去header。 else: # data已经在上面进行数据解密了。不需要像local一样加密发送。 # data已经被切除头的3个字节了 data = data[header_length:] if not data: return try: # 发送,完美无瑕。。。。 # 这个sendto同时有udp的和tcp的两种,sendto函数主要用于UDP,但这里两种都用了 # 调用sendto时候会自动加上那个首3个字节,貌似是x00 x00 x00 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: logging.error(e)