def get_head_size(self, buf, def_value): if len(buf) < 2: return def_value head_type = ord(buf[0]) & 0x7 if head_type == 1: return 7 if head_type == 4: return 19 if head_type == 3: return 4 + ord(buf[1]) return def_value
def client_decode(self, buf): if self.handshake_status == -1: return (buf, False) if self.handshake_status == 8: ret = b'' self.recv_buffer += buf while len(self.recv_buffer) > 5: if ord(self.recv_buffer[0]) != 0x17: logging.info("data = %s" % (binascii.hexlify(self.recv_buffer))) raise Exception('server_decode appdata error') size = struct.unpack('>H', self.recv_buffer[3:5])[0] if len(self.recv_buffer) < size + 5: break buf = self.recv_buffer[5:size+5] ret += buf self.recv_buffer = self.recv_buffer[size+5:] return (ret, False) if len(buf) < 11 + 32 + 1 + 32: raise Exception('client_decode data error') verify = buf[11:33] if hmac.new(self.server_info.key + self.server_info.data.client_id, verify, hashlib.sha1).digest()[:10] != buf[33:43]: raise Exception('client_decode data error') if hmac.new(self.server_info.key + self.server_info.data.client_id, buf[:-10], hashlib.sha1).digest()[:10] != buf[-10:]: raise Exception('client_decode data error') return (b'', True)
def parse_name(data, offset): p = offset labels = [] l = common.ord(data[p]) while l > 0: if (l & (128 + 64)) == (128 + 64): # pointer pointer = struct.unpack('!H', data[p:p + 2])[0] pointer &= 0x3FFF r = parse_name(data, pointer) labels.append(r[1]) p += 2 # pointer is the end return p - offset, b'.'.join(labels) else: labels.append(data[p + 1:p + 1 + l]) p += 1 + l l = common.ord(data[p]) return p - offset + 1, b'.'.join(labels)
def rnd_data_len(self, buf_size, full_buf_size): if full_buf_size >= self.server_info.buffer_size: return 0 tcp_mss = self.server_info.tcp_mss rev_len = tcp_mss - buf_size - 9 if rev_len == 0: return 0 if rev_len < 0: if rev_len > -tcp_mss: return self.trapezoid_random_int(rev_len + tcp_mss, -0.3) return common.ord(os.urandom(1)[0]) % 32 if buf_size > 900: return struct.unpack('>H', os.urandom(2))[0] % rev_len return self.trapezoid_random_int(rev_len, -0.3)
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 client_encode(self, buf): if self.raw_trans_sent: return buf self.send_buffer += buf if not self.has_sent_header: self.has_sent_header = True data = os.urandom(common.ord(os.urandom(1)[0]) % 96 + 4) crc = (0xffffffff - binascii.crc32(data)) & 0xffffffff return data + struct.pack('<I', crc) if self.raw_trans_recv: ret = self.send_buffer self.send_buffer = b'' self.raw_trans_sent = True return ret return b''
def client_post_decrypt(self, buf): if self.raw_trans: return buf self.recv_buf += buf out_buf = b'' while len(self.recv_buf) > 4: mac_key = self.user_key + struct.pack('<I', self.recv_id) mac = hmac.new(mac_key, self.recv_buf[:2], self.hashfunc).digest()[:2] if mac != self.recv_buf[2:4]: raise Exception('client_post_decrypt data uncorrect mac') length = struct.unpack('<H', self.recv_buf[:2])[0] if length >= 8192 or length < 7: self.raw_trans = True self.recv_buf = b'' raise Exception('client_post_decrypt data error') if length > len(self.recv_buf): break if hmac.new(mac_key, self.recv_buf[:length - 4], self.hashfunc).digest()[:4] != self.recv_buf[length - 4:length]: self.raw_trans = True self.recv_buf = b'' raise Exception('client_post_decrypt data uncorrect checksum') self.recv_id = (self.recv_id + 1) & 0xFFFFFFFF pos = common.ord(self.recv_buf[4]) if pos < 255: pos += 4 else: pos = struct.unpack('<H', self.recv_buf[5:7])[0] + 4 out_buf += self.recv_buf[pos:length - 4] self.recv_buf = self.recv_buf[length:] return out_buf
def client_post_decrypt(self, buf): if self.raw_trans: return buf self.recv_buf += buf out_buf = b'' while len(self.recv_buf) > 4: crc = struct.pack('<H', binascii.crc32(self.recv_buf[:2]) & 0xFFFF) if crc != self.recv_buf[2:4]: raise Exception('client_post_decrypt data uncorrect crc') length = struct.unpack('>H', self.recv_buf[:2])[0] if length >= 8192 or length < 7: self.raw_trans = True self.recv_buf = b'' raise Exception('client_post_decrypt data error') if length > len(self.recv_buf): break if struct.pack( '<I', zlib.adler32(self.recv_buf[:length - 4]) & 0xFFFFFFFF) != self.recv_buf[length - 4:length]: self.raw_trans = True self.recv_buf = b'' raise Exception('client_post_decrypt data uncorrect checksum') pos = common.ord(self.recv_buf[4]) if pos < 255: pos += 4 else: pos = struct.unpack('>H', self.recv_buf[5:7])[0] + 4 out_buf += self.recv_buf[pos:length - 4] self.recv_buf = self.recv_buf[length:] if out_buf: self.decrypt_packet_num += 1 return out_buf
def server_decode(self, buf): if self.handshake_status == -1: return (buf, True, False) if (self.handshake_status & 4) == 4: ret = b'' self.recv_buffer += buf while len(self.recv_buffer) > 5: if ord(self.recv_buffer[0]) != 0x17 or ord(self.recv_buffer[1]) != 0x3 or ord(self.recv_buffer[2]) != 0x3: logging.info("data = %s" % (binascii.hexlify(self.recv_buffer))) raise Exception('server_decode appdata error') size = struct.unpack('>H', self.recv_buffer[3:5])[0] if len(self.recv_buffer) < size + 5: break ret += self.recv_buffer[5:size+5] self.recv_buffer = self.recv_buffer[size+5:] return (ret, True, False) if (self.handshake_status & 1) == 1: self.recv_buffer += buf buf = self.recv_buffer verify = buf if len(buf) < 11: raise Exception('server_decode data error') if not match_begin(buf, b"\x14" + self.tls_version + b"\x00\x01\x01"): #ChangeCipherSpec raise Exception('server_decode data error') buf = buf[6:] if not match_begin(buf, b"\x16" + self.tls_version + b"\x00"): #Finished raise Exception('server_decode data error') verify_len = struct.unpack('>H', buf[3:5])[0] + 1 # 11 - 10 if len(verify) < verify_len + 10: return (b'', False, False) if hmac.new(self.server_info.key + self.client_id, verify[:verify_len], hashlib.sha1).digest()[:10] != verify[verify_len:verify_len+10]: raise Exception('server_decode data error') self.recv_buffer = verify[verify_len + 10:] status = self.handshake_status self.handshake_status |= 4 ret = self.server_decode(b'') return ret; #raise Exception("handshake data = %s" % (binascii.hexlify(buf))) self.recv_buffer += buf buf = self.recv_buffer ogn_buf = buf if len(buf) < 3: return (b'', False, False) if not match_begin(buf, b'\x16\x03\x01'): return self.decode_error_return(ogn_buf) buf = buf[3:] header_len = struct.unpack('>H', buf[:2])[0] if header_len > len(buf) - 2: return (b'', False, False) self.recv_buffer = self.recv_buffer[header_len + 5:] self.handshake_status = 1 buf = buf[2:header_len + 2] if not match_begin(buf, b'\x01\x00'): #client hello logging.info("tls_auth not client hello message") return self.decode_error_return(ogn_buf) buf = buf[2:] if struct.unpack('>H', buf[:2])[0] != len(buf) - 2: logging.info("tls_auth wrong message size") return self.decode_error_return(ogn_buf) buf = buf[2:] if not match_begin(buf, self.tls_version): logging.info("tls_auth wrong tls version") return self.decode_error_return(ogn_buf) buf = buf[2:] verifyid = buf[:32] buf = buf[32:] sessionid_len = ord(buf[0]) if sessionid_len < 32: logging.info("tls_auth wrong sessionid_len") return self.decode_error_return(ogn_buf) sessionid = buf[1:sessionid_len + 1] buf = buf[sessionid_len+1:] self.client_id = sessionid sha1 = hmac.new(self.server_info.key + sessionid, verifyid[:22], hashlib.sha1).digest()[:10] utc_time = struct.unpack('>I', verifyid[:4])[0] time_dif = common.int32((int(time.time()) & 0xffffffff) - utc_time) if self.server_info.obfs_param: try: self.max_time_dif = int(self.server_info.obfs_param) except: pass if self.max_time_dif > 0 and (time_dif < -self.max_time_dif or time_dif > self.max_time_dif \ or common.int32(utc_time - self.server_info.data.startup_time) < -self.max_time_dif / 2): logging.info("tls_auth wrong time") return self.decode_error_return(ogn_buf) if sha1 != verifyid[22:]: logging.info("tls_auth wrong sha1") return self.decode_error_return(ogn_buf) if self.server_info.data.client_data.get(verifyid[:22]): logging.info("replay attack detect, id = %s" % (binascii.hexlify(verifyid))) return self.decode_error_return(ogn_buf) self.server_info.data.client_data.sweep() self.server_info.data.client_data[verifyid[:22]] = sessionid if len(self.recv_buffer) >= 11: ret = self.server_decode(b'') return (ret[0], True, True) # (buffer_to_recv, is_need_decrypt, is_need_to_encode_and_send_back) return (b'', False, True)
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 server_post_decrypt(self, buf): if self.raw_trans: return (buf, False) self.recv_buf += buf out_buf = b'' sendback = False if not self.has_recv_header: if len(self.recv_buf) >= 7 or len(self.recv_buf) in [2, 3]: recv_len = min(len(self.recv_buf), 7) mac_key = self.server_info.recv_iv + self.server_info.key sha1data = hmac.new(mac_key, self.recv_buf[:1], self.hashfunc).digest()[:recv_len - 1] if sha1data != self.recv_buf[1:recv_len]: return self.not_match_return(self.recv_buf) if len(self.recv_buf) < 31: return (b'', False) sha1data = hmac.new(mac_key, self.recv_buf[7:27], self.hashfunc).digest()[:4] if sha1data != self.recv_buf[27:31]: logging.error( '%s data uncorrect auth HMAC-SHA1 from %s:%d, data %s' % (self.no_compatible_method, self.server_info.client, self.server_info.client_port, binascii.hexlify(self.recv_buf))) if len(self.recv_buf) < 31 + self.extra_wait_size: return (b'', False) return self.not_match_return(self.recv_buf) uid = self.recv_buf[7:11] if uid in self.server_info.users: self.user_id = uid self.user_key = self.hashfunc( self.server_info.users[uid]).digest() self.server_info.update_user_func(uid) else: if not self.server_info.users: self.user_key = self.server_info.key else: self.user_key = self.server_info.recv_iv encryptor = encrypt.Encryptor( to_bytes(base64.b64encode(self.user_key)) + self.salt, 'aes-128-cbc') head = encryptor.decrypt( b'\x00' * 16 + self.recv_buf[11:27] + b'\x00') # need an extra byte or recv empty length = struct.unpack('<H', head[12:14])[0] if len(self.recv_buf) < length: return (b'', False) utc_time = struct.unpack('<I', head[:4])[0] client_id = struct.unpack('<I', head[4:8])[0] connection_id = struct.unpack('<I', head[8:12])[0] rnd_len = struct.unpack('<H', head[14:16])[0] if hmac.new(self.user_key, self.recv_buf[:length - 4], self.hashfunc).digest()[:4] != self.recv_buf[length - 4:length]: logging.info('%s: checksum error, data %s' % (self.no_compatible_method, binascii.hexlify(self.recv_buf[:length]))) return self.not_match_return(self.recv_buf) time_dif = common.int32(utc_time - (int(time.time()) & 0xffffffff)) if time_dif < -self.max_time_dif or time_dif > self.max_time_dif: logging.info('%s: wrong timestamp, time_dif %d, data %s' % (self.no_compatible_method, time_dif, binascii.hexlify(head))) return self.not_match_return(self.recv_buf) elif self.server_info.data.insert(self.user_id, client_id, connection_id): self.has_recv_header = True out_buf = self.recv_buf[31 + rnd_len:length - 4] self.client_id = client_id self.connection_id = connection_id else: logging.info( '%s: auth fail, data %s' % (self.no_compatible_method, binascii.hexlify(out_buf))) return self.not_match_return(self.recv_buf) self.recv_buf = self.recv_buf[length:] self.has_recv_header = True sendback = True while len(self.recv_buf) > 4: mac_key = self.user_key + struct.pack('<I', self.recv_id) mac = hmac.new(mac_key, self.recv_buf[:2], self.hashfunc).digest()[:2] if mac != self.recv_buf[2:4]: self.raw_trans = True logging.info(self.no_compatible_method + ': wrong crc') if self.recv_id == 0: logging.info(self.no_compatible_method + ': wrong crc') return (b'E' * 2048, False) else: raise Exception('server_post_decrype data error') length = struct.unpack('<H', self.recv_buf[:2])[0] if length >= 8192 or length < 7: self.raw_trans = True self.recv_buf = b'' if self.recv_id == 0: logging.info(self.no_compatible_method + ': over size') return (b'E' * 2048, False) else: raise Exception('server_post_decrype data error') if length > len(self.recv_buf): break if hmac.new(mac_key, self.recv_buf[:length - 4], self.hashfunc).digest()[:4] != self.recv_buf[length - 4:length]: logging.info('%s: checksum error, data %s' % (self.no_compatible_method, binascii.hexlify(self.recv_buf[:length]))) self.raw_trans = True self.recv_buf = b'' if self.recv_id == 0: return (b'E' * 2048, False) else: raise Exception( 'server_post_decrype data uncorrect checksum') self.recv_id = (self.recv_id + 1) & 0xFFFFFFFF pos = common.ord(self.recv_buf[4]) if pos < 255: pos += 4 else: pos = struct.unpack('<H', self.recv_buf[5:7])[0] + 4 out_buf += self.recv_buf[pos:length - 4] self.recv_buf = self.recv_buf[length:] if pos == length - 4: sendback = True if out_buf: self.server_info.data.update(self.user_id, self.client_id, self.connection_id) return (out_buf, sendback)
def server_post_decrypt(self, buf): if self.raw_trans: return (buf, False) self.recv_buf += buf out_buf = b'' sendback = False if not self.has_recv_header: if len(self.recv_buf) <= 6: return (b'', False) crc = struct.pack( '<I', binascii.crc32(self.recv_buf[:2] + self.salt + self.server_info.key) & 0xFFFFFFFF) if crc != self.recv_buf[2:6]: return self.not_match_return(self.recv_buf) length = struct.unpack('>H', self.recv_buf[:2])[0] if length > len(self.recv_buf): return (b'', False) sha1data = hmac.new( self.server_info.recv_iv + self.server_info.key, self.recv_buf[:length - 10], hashlib.sha1).digest()[:10] if sha1data != self.recv_buf[length - 10:length]: logging.error('auth_sha1_v4 data uncorrect auth HMAC-SHA1') return self.not_match_return(self.recv_buf) pos = common.ord(self.recv_buf[6]) if pos < 255: pos += 6 else: pos = struct.unpack('>H', self.recv_buf[7:9])[0] + 6 out_buf = self.recv_buf[pos:length - 10] if len(out_buf) < 12: logging.info('auth_sha1_v4: too short, data %s' % (binascii.hexlify(self.recv_buf), )) return self.not_match_return(self.recv_buf) utc_time = struct.unpack('<I', out_buf[:4])[0] client_id = struct.unpack('<I', out_buf[4:8])[0] connection_id = struct.unpack('<I', out_buf[8:12])[0] time_dif = common.int32(utc_time - (int(time.time()) & 0xffffffff)) if time_dif < -self.max_time_dif or time_dif > self.max_time_dif: logging.info( 'auth_sha1_v4: wrong timestamp, time_dif %d, data %s' % ( time_dif, binascii.hexlify(out_buf), )) return self.not_match_return(self.recv_buf) elif self.server_info.data.insert(client_id, connection_id): self.has_recv_header = True out_buf = out_buf[12:] self.client_id = client_id self.connection_id = connection_id else: logging.info('auth_sha1_v4: auth fail, data %s' % (binascii.hexlify(out_buf), )) return self.not_match_return(self.recv_buf) self.recv_buf = self.recv_buf[length:] self.has_recv_header = True sendback = True while len(self.recv_buf) > 4: crc = struct.pack('<H', binascii.crc32(self.recv_buf[:2]) & 0xFFFF) if crc != self.recv_buf[2:4]: self.raw_trans = True logging.info('auth_sha1_v4: wrong crc') if self.decrypt_packet_num == 0: logging.info('auth_sha1_v4: wrong crc') return (b'E' * 2048, False) else: raise Exception('server_post_decrype data error') length = struct.unpack('>H', self.recv_buf[:2])[0] if length >= 8192 or length < 7: self.raw_trans = True self.recv_buf = b'' if self.decrypt_packet_num == 0: logging.info('auth_sha1_v4: over size') return (b'E' * 2048, False) else: raise Exception('server_post_decrype data error') if length > len(self.recv_buf): break if struct.pack( '<I', zlib.adler32(self.recv_buf[:length - 4]) & 0xFFFFFFFF) != self.recv_buf[length - 4:length]: logging.info('auth_sha1_v4: checksum error, data %s' % (binascii.hexlify(self.recv_buf[:length]), )) self.raw_trans = True self.recv_buf = b'' if self.decrypt_packet_num == 0: return (b'E' * 2048, False) else: raise Exception( 'server_post_decrype data uncorrect checksum') pos = common.ord(self.recv_buf[4]) if pos < 255: pos += 4 else: pos = struct.unpack('>H', self.recv_buf[5:7])[0] + 4 out_buf += self.recv_buf[pos:length - 4] self.recv_buf = self.recv_buf[length:] if pos == length - 4: sendback = True if out_buf: self.server_info.data.update(self.client_id, self.connection_id) self.decrypt_packet_num += 1 return (out_buf, sendback)
def server_encode(self, buf): if self.has_sent_header: return buf self.has_sent_header = True return os.urandom(common.ord(os.urandom(1)[0]) % 96 + 4)