def rnd_data(self, buf_size, full_buf_size): data_len = self.rnd_data_len(buf_size, full_buf_size) if data_len < 128: return common.chr(data_len + 1) + os.urandom(data_len) return common.chr(255) + struct.pack('<H', data_len + 1) + os.urandom(data_len - 2)
def rnd_data(self, buf_size): if buf_size > 1300: return b'\x01' if buf_size > 400: rnd_data = os.urandom(common.ord(os.urandom(1)[0]) % 128) return common.chr(len(rnd_data) + 1) + rnd_data rnd_data = os.urandom(struct.unpack('>H', os.urandom(2))[0] % 1024) return common.chr(255) + struct.pack('>H', len(rnd_data) + 3) + rnd_data
def rnd_data(self, buf_size): if buf_size > 1200: return b'\x01' if buf_size > 400: rnd_data = os.urandom(common.ord(os.urandom(1)[0]) % 256) else: rnd_data = os.urandom(struct.unpack('>H', os.urandom(2))[0] % 512) if len(rnd_data) < 128: return common.chr(len(rnd_data) + 1) + rnd_data else: return common.chr(255) + struct.pack('>H', len(rnd_data) + 3) + rnd_data
def server_post_decrypt(self, buf): if self.raw_trans: return (buf, False) self.recv_buf += buf out_buf = b'' if not self.has_recv_header: if len(self.recv_buf) < 2: return (b'', False) if (ord(self.recv_buf[0]) & 0x10) != 0x10: return self.not_match_return(self.recv_buf) head_size = self.get_head_size(self.recv_buf, 65536) if len(self.recv_buf) < head_size + 10: return self.not_match_return(self.recv_buf) sha1data = hmac.new(self.server_info.recv_iv + self.server_info.key, self.recv_buf[:head_size], hashlib.sha1).digest()[:10] if sha1data != self.recv_buf[head_size:head_size + 10]: logging.error('server_post_decrype data uncorrect auth HMAC-SHA1') return self.not_match_return(self.recv_buf) out_buf = to_bytes(chr(ord(self.recv_buf[0]) & 0xEF)) + self.recv_buf[1:head_size] self.recv_buf = self.recv_buf[head_size + 10:] self.has_recv_header = True while len(self.recv_buf) > 2: length = struct.unpack('>H', self.recv_buf[:2])[0] + 12 if length > len(self.recv_buf): break data = self.recv_buf[12:length] sha1data = hmac.new(self.server_info.recv_iv + struct.pack('>I', self.recv_id), data, hashlib.sha1).digest()[:10] if sha1data != self.recv_buf[2:12]: raise Exception('server_post_decrype data uncorrect chunk HMAC-SHA1') self.recv_id = (self.recv_id + 1) & 0xFFFFFFFF out_buf += data self.recv_buf = self.recv_buf[length:] return (out_buf, False)
def pack_data(self, buf): rnd_data = os.urandom(common.ord(os.urandom(1)[0]) % 16) data = common.chr(len(rnd_data) + 1) + rnd_data + buf data = struct.pack('>H', len(data) + 6) + data adler32 = zlib.adler32(data) & 0xFFFFFFFF data += struct.pack('<I', adler32) return data
def build_address(address): # str.strip() remove leading and trailing b'.' # check http://stackoverflow.com/questions/6269765/what-does-the-b-character-do-in-front-of-a-string-literal # '' is normal text # in python2, the result is the same as if there's no prefix 'b' # >>> '.' == b'.' # True address = address.strip(b'.') labels = address.split(b'.') results = [] # append octet length and label for each part for label in labels: l = len(label) # Label must be 63 characters or less. if l > 63: return None # length should be in the octet form, namely an ASCII char # common.chr() replaces builtin chr() for the difference in bytes, namely b'...' between python2/3 # check common.py for reference results.append(common.chr(l)) results.append(label) # append end 0 # in python2, b'\0' = '\0' # check http://stackoverflow.com/questions/1182812/what-is-the-meaning-of-x00-x04-in-php # \x use two hexadecimal digits/one byte to repr x # so '\0' = '\x00' results.append(b'\0') return b''.join(results)
def _handel_normal_relay(self, client_address, ogn_data): host, port = self._get_relay_host(client_address, ogn_data) self._encrypt_correct = False if port is None: raise Exception('can not parse header') data = b"\x03" + common.to_bytes(common.chr(len(host))) + \ common.to_bytes(host) + struct.pack('>H', port) return (data + ogn_data, True)
def _pack_rsp_data(self, cmd, request_id, data): _rand_data = b"123456789abcdefghijklmnopqrstuvwxyz" * 2 reqid_str = struct.pack(">H", request_id) return b''.join([ CMD_VER_STR, common.chr(cmd), reqid_str, data, _rand_data[:random.randint(0, len(_rand_data))], reqid_str ])
def _handel_protocol_error(self, client_address, ogn_data): #raise Exception('can not parse header') logging.warn("Protocol ERROR, TCP ogn data %s from %s:%d" % (binascii.hexlify(ogn_data), client_address[0], client_address[1])) self._encrypt_correct = False #create redirect or disconnect by hash code host, port = self._get_redirect_host(client_address, ogn_data) data = b"\x03" + common.chr(len(host)) + host + struct.pack('>H', port) logging.warn("TCP data redir %s:%d %s" % (host, port, binascii.hexlify(data))) return data + ogn_data
def pack_data(self, buf): if len(buf) == 0: return b'' rnd_data = os.urandom(common.ord(os.urandom(1)[0]) % 16) data = common.chr(len(rnd_data) + 1) + rnd_data + buf data = struct.pack('>H', len(data) + 6) + data crc = (0xffffffff - binascii.crc32(data)) & 0xffffffff data += struct.pack('<I', crc) return data
def server_udp_post_decrypt(self, buf): if buf and ((ord(buf[0]) & 0x10) == 0x10): if len(buf) <= 11: return b'' sha1data = hmac.new(self.server_info.recv_iv + self.server_info.key, buf[:-10], hashlib.sha1).digest()[:10] if sha1data != buf[-10:]: return b'' return to_bytes(chr(ord(buf[0]) & 0xEF)) + buf[1:-10] else: return buf
def pack_auth_data(self, buf): if len(buf) == 0: return b'' rnd_data = os.urandom(common.ord(os.urandom(1)[0]) % 128) data = common.chr(len(rnd_data) + 1) + rnd_data + buf data = struct.pack('>H', len(data) + 16) + data crc = binascii.crc32(self.server_info.key) & 0xFFFFFFFF data = struct.pack('<I', crc) + data data += hmac.new(self.server_info.iv + self.server_info.key, data, hashlib.sha1).digest()[:10] return data
def server_udp_post_decrypt(self, buf): if buf and ((ord(buf[0]) & 0x10) == 0x10): if len(buf) <= 11: return (b'', None) sha1data = hmac.new(self.server_info.recv_iv + self.server_info.key, buf[:-10], hashlib.sha1).digest()[:10] if sha1data != buf[-10:]: return (b'', None) return (to_bytes(chr(ord(buf[0]) & 0xEF)) + buf[1:-10], None) else: return (buf, None)
def server_udp_post_decrypt(self, buf): if buf and ((ord(buf[0]) & 0x10) == 0x10): if len(buf) <= 11: return b'E' sha1data = hmac.new(self.server_info.recv_iv + self.server_info.key, buf[:-10], hashlib.sha1).digest()[:10] if sha1data != buf[-10:]: logging.error('server_udp_post_decrypt data uncorrect auth HMAC-SHA1') return b'E' return to_bytes(chr(ord(buf[0]) & 0xEF)) + buf[1:-10] else: return buf
def build_address(address): address = address.strip(b'.') labels = address.split(b'.') results = [] for label in labels: l = len(label) if l > 63: return None results.append(common.chr(l)) results.append(label) results.append(b'\0') return b''.join(results)
def build_address(address): # strip()删除序列是只要边(开头或结尾)上的字符在删除序列内,就删除掉 address = address.strip(b'.') labels = address.split(b'.') results = [] for label in labels: l = len(label) if l > 63: # hostname太长 return None results.append(common.chr(l)) # 这个l对应的ascii是什么意思 results.append(label) results.append(b'\0') return b''.join(results)
def build_address(address): # 处理二进制字符串 address = address.strip(b'.') # 去除两边多余的. labels = address.split(b'.') # 按.切分为列表 results = [] for label in labels: l = len(label) if l > 63: return None results.append(common.chr(l)) # 补充元素大小 results.append(label) # 追加元素 results.append(b'\0') return b''.join(results)
def init_data_size(self, key): if self.data_size_list0: self.data_size_list0 = [] random = xorshift128plus() # key xor with key_change_datetime_key new_key = bytearray(key) new_key_str = '' for i in range(0, 8): new_key[i] ^= self.key_change_datetime_key_bytes[i] new_key_str += chr(new_key[i]) for i in range(8, len(new_key)): new_key_str += chr(new_key[i]) random.init_from_bin(to_bytes(new_key_str)) # 补全数组长为12~24-1 list_len = random.next() % (8 + 16) + (4 + 8) for i in range(0, list_len): self.data_size_list0.append(int(random.next() % 2340 % 2040 % 1440)) self.data_size_list0.sort() old_len = len(self.data_size_list0) self.check_and_patch_data_size(random) # if check_and_patch_data_size are work, re-sort again. if old_len != len(self.data_size_list0): self.data_size_list0.sort()
def build_address(address): # strip()删除序列是只要边(开头或结尾)上的字符在删除序列内,就删除掉 address = address.strip(b'.') labels = address.split(b'.') results = [] for label in labels: l = len(label) if l > 63: # hostname太长 return None # result分别追加数据:逐级域名的长度,逐级域名的字符串 results.append(common.chr(l)) results.append(label) results.append(b'\0') return b''.join(results)
def build_address(address): """ 填充DNS请求中的QNAME字段 :param address: 查询的域名 :return: 若域名合法则返回填充的字节流,否则返回None """ address = address.strip(b'.') labels = address.split(b'.') results = [] for label in labels: l = len(label) if l > 63: return None # 将“.”替换为下一个有效字段长度 results.append(common.chr(l)) results.append(label) results.append(b'\0') return b''.join(results)
def build_address(address): """ 该方法主要是构建DNS报文中的域名信息,即DNS请求报文中的QNAME部分。 :param address: 域名。 :return: DNS报文中的域名信息,即DNS请求报文中的QNAME部分。 """ # DNS报文中的域名信息格式为“\x01w\x02ww\00” address = address.strip(b'.') labels = address.split(b'.') results = [] for label in labels: l = len(label) if l > 63: return None results.append(common.chr(l)) results.append(label) results.append(b'\0') return b''.join(results)
def server_post_decrypt(self, buf): if self.raw_trans: return buf self.recv_buf += buf out_buf = b'' if not self.has_recv_header: if len(self.recv_buf) < 2: return b'' if (ord(self.recv_buf[0]) & 0x10) != 0x10: if self.method == 'verify_sha1': logging.error('Not One-time authentication header') return b'E' else: self.raw_trans = True return self.recv_buf head_size = self.get_head_size(self.recv_buf, 30) if len(self.recv_buf) < head_size + 10: return b'' sha1data = hmac.new(self.server_info.recv_iv + self.server_info.key, self.recv_buf[:head_size], hashlib.sha1).digest()[:10] if sha1data != self.recv_buf[head_size:head_size + 10]: logging.error('server_post_decrype data uncorrect auth HMAC-SHA1') return b'E' out_buf = to_bytes(chr(ord(self.recv_buf[0]) & 0xEF)) + self.recv_buf[1:head_size] self.recv_buf = self.recv_buf[head_size + 10:] self.has_recv_header = True while len(self.recv_buf) > 2: length = struct.unpack('>H', self.recv_buf[:2])[0] + 12 if length > len(self.recv_buf): break data = self.recv_buf[12:length] sha1data = hmac.new(self.server_info.recv_iv + struct.pack('>I', self.recv_id), data, hashlib.sha1).digest()[:10] if sha1data != self.recv_buf[2:12]: raise Exception('server_post_decrype data uncorrect chunk HMAC-SHA1') self.recv_id = (self.recv_id + 1) & 0xFFFFFFFF out_buf += data self.recv_buf = self.recv_buf[length:] return out_buf
def nonce_increment(nonce, nlen): """ Increase nonce by 1 in little endian From libsodium sodium_increment(): for (; i < nlen; i++) { c += (uint_fast16_t) n[i]; n[i] = (unsigned char) c; c >>= 8; } :param nonce: string_buffer nonce :param nlen: nonce length :return: nonce plus by 1 """ c = 1 i = 0 # n = create_string_buffer(nlen) while i < nlen: c += ord(nonce[i]) nonce[i] = chr(c & 0xFF) c >>= 8 i += 1 return # n.raw
def build_address(address): """ Convert domain name to QNAME used in the DNS Question section. Return a sequence of labels, where each label consists of a length octet followed by that number of octets. The domain name terminates with the zero length octet for the null label of the root. Ref: RFC 1035 4.1.2. Question section format :param address: domain name """ address = address.strip(b'.') labels = address.split(b'.') results = [] # Labels must be 63 characters or less. Ref: RFC 1035 for label in labels: l = len(label) if l > 63: return None results.append(common.chr(l)) results.append(label) results.append(b'\0') return b''.join(results)
def _on_remote_read(self, is_remote_sock): # handle all remote read events data = None try: if self._remote_udp: if is_remote_sock: data, addr = self._remote_sock.recvfrom(UDP_MAX_BUF_SIZE) else: data, addr = self._remote_sock_v6.recvfrom( UDP_MAX_BUF_SIZE) port = struct.pack('>H', addr[1]) try: ip = socket.inet_aton(addr[0]) data = b'\x00\x01' + ip + port + data except Exception as e: ip = socket.inet_pton(socket.AF_INET6, addr[0]) data = b'\x00\x04' + ip + port + data size = len(data) + 2 if size >= 0xff00: data = common.chr(0xff) + struct.pack( '>H', size - 0xff00 + 1) + data else: data = struct.pack('>H', size) + data #logging.info('UDP over TCP recvfrom %s:%d %d bytes to %s:%d' % (addr[0], addr[1], len(data), self._client_address[0], self._client_address[1])) else: data = self._remote_sock.recv(BUF_SIZE) except (OSError, IOError) as e: if eventloop.errno_from_exception(e) in \ (errno.ETIMEDOUT, errno.EAGAIN, errno.EWOULDBLOCK, 10035): #errno.WSAEWOULDBLOCK return if not data: self.destroy() return if self._encryptor is not None: if self._is_local: try: obfs_decode = self._obfs.client_decode(data) except Exception as e: shell.print_exception(e) logging.error( "exception from %s:%d" % (self._client_address[0], self._client_address[1])) self.destroy() return if obfs_decode[1]: send_back = self._obfs.client_encode(b'') self._write_to_sock(send_back, self._remote_sock) if not self._protocol.obfs.server_info.recv_iv: iv_len = len(self._protocol.obfs.server_info.iv) self._protocol.obfs.server_info.recv_iv = obfs_decode[ 0][:iv_len] data = self._encryptor.decrypt(obfs_decode[0]) try: data = self._protocol.client_post_decrypt(data) except Exception as e: shell.print_exception(e) logging.error( "exception from %s:%d" % (self._client_address[0], self._client_address[1])) self.destroy() return else: if self._encrypt_correct: data = self._protocol.server_pre_encrypt(data) data = self._encryptor.encrypt(data) data = self._obfs.server_encode(data) self._update_activity(len(data)) self._server.server_transfer_dl += len(data) else: return try: self._write_to_sock(data, self._local_sock) except Exception as e: shell.print_exception(e) if self._config['verbose']: traceback.print_exc() logging.error("exception from %s:%d" % (self._client_address[0], self._client_address[1])) 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])) 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 client_udp_pre_encrypt(self, buf): ret = self.pack_auth_data(buf) return chr(ord(buf[0]) | 0x10) + buf[1:]
def pack_auth_data(self, buf): data = chr(ord(buf[0]) | 0x10) + buf[1:] data += hmac.new(self.server_info.iv + self.server_info.key, data, hashlib.sha1).digest()[:10] return data
def _on_remote_read(self, is_remote_sock): # handle all remote read events data = None try: if self._remote_udp: if is_remote_sock: data, addr = self._remote_sock.recvfrom(UDP_MAX_BUF_SIZE) else: data, addr = self._remote_sock_v6.recvfrom(UDP_MAX_BUF_SIZE) port = struct.pack('>H', addr[1]) try: ip = socket.inet_aton(addr[0]) data = b'\x00\x01' + ip + port + data except Exception as e: ip = socket.inet_pton(socket.AF_INET6, addr[0]) data = b'\x00\x04' + ip + port + data size = len(data) + 2 if size >= 0xff00: data = common.chr(0xff) + struct.pack('>H', size - 0xff00 + 1) + data else: data = struct.pack('>H', size) + data #logging.info('UDP over TCP recvfrom %s:%d %d bytes to %s:%d' % (addr[0], addr[1], len(data), self._client_address[0], self._client_address[1])) else: data = self._remote_sock.recv(BUF_SIZE) except (OSError, IOError) as e: if eventloop.errno_from_exception(e) in \ (errno.ETIMEDOUT, errno.EAGAIN, errno.EWOULDBLOCK, 10035): #errno.WSAEWOULDBLOCK return if not data: self.destroy() return if self._encryptor is not None: if self._is_local: try: obfs_decode = self._obfs.client_decode(data) except Exception as e: shell.print_exception(e) logging.error("exception from %s:%d" % (self._client_address[0], self._client_address[1])) self.destroy() return if obfs_decode[1]: send_back = self._obfs.client_encode(b'') self._write_to_sock(send_back, self._remote_sock) if not self._protocol.obfs.server_info.recv_iv: iv_len = len(self._protocol.obfs.server_info.iv) self._protocol.obfs.server_info.recv_iv = obfs_decode[0][:iv_len] data = self._encryptor.decrypt(obfs_decode[0]) try: data = self._protocol.client_post_decrypt(data) except Exception as e: shell.print_exception(e) logging.error("exception from %s:%d" % (self._client_address[0], self._client_address[1])) self.destroy() return else: if self._encrypt_correct: data = self._protocol.server_pre_encrypt(data) data = self._encryptor.encrypt(data) data = self._obfs.server_encode(data) self._update_activity(len(data)) self._server.server_transfer_dl += len(data) else: return try: self._write_to_sock(data, self._local_sock) except Exception as e: shell.print_exception(e) if self._config['verbose']: traceback.print_exc() logging.error("exception from %s:%d" % (self._client_address[0], self._client_address[1])) 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') 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: 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): 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()