def _ota_chunk_data_gen(self, data): data_len = struct.pack(">H", len(data)) index = struct.pack('>I', self._ota_chunk_idx) key = self._cryptor.cipher_iv + index sha110 = onetimeauth_gen(data, key) self._ota_chunk_idx += 1 return data_len + sha110 + data
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 _ota_chunk_data_gen(self, key, iv, data): data = common.chr(common.ord(data[0]) | ADDRTYPE_AUTH) + data[1:] key = iv + key return data + onetimeauth_gen(data, key)
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])) #logging.info('connecting %s:%d from %s:%d, %s' % # (common.to_str(remote_addr), remote_port, # self._client_address[0], self._client_address[1], data)) 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)