def test_binding_request_ice_controlled_bad_integrity(self): data = read_message("binding_request_ice_controlled.bin") with self.assertRaises(ValueError) as cm: stun.parse_message(data, integrity_key=b"bogus-key") self.assertEqual(str(cm.exception), "STUN message integrity does not match")
def test_binding_request_ice_controlled_bad_fingerprint(self): data = read_message("binding_request_ice_controlled.bin")[0:-1] + b"z" with self.assertRaises(ValueError) as cm: stun.parse_message(data) self.assertEqual(str(cm.exception), "STUN message fingerprint does not match")
def datagram_received(self, data, addr): # demultiplex channel data if len(data) >= 4 and is_channel_data(data): channel, length = struct.unpack("!HH", data[0:4]) allocation = self.server.allocations.get((self, addr)) if len(data) >= length + 4 and allocation: peer_address = allocation.channel_to_peer.get(channel) if peer_address: payload = data[4:4 + length] allocation.transport.sendto(payload, peer_address) return try: message = stun.parse_message(data) except ValueError: return logger.debug("< %s %s", addr, message) assert message.message_class == stun.Class.REQUEST if message.message_method == stun.Method.BINDING: response = self.handle_binding(message, addr) self.send_stun(response, addr) return if "USERNAME" not in message.attributes: response = self.error_response(message, 401, "Unauthorized") response.attributes["NONCE"] = random_string(16).encode("ascii") response.attributes["REALM"] = self.server.realm self.send_stun(response, addr) return # check credentials username = message.attributes["USERNAME"] password = self.server.users[username] integrity_key = make_integrity_key(username, self.server.realm, password) try: stun.parse_message(data, integrity_key=integrity_key) except ValueError: return if message.message_method == stun.Method.ALLOCATE: asyncio.ensure_future( self.handle_allocate(message, addr, integrity_key)) return elif message.message_method == stun.Method.REFRESH: response = self.handle_refresh(message, addr) elif message.message_method == stun.Method.CHANNEL_BIND: response = self.handle_channel_bind(message, addr) else: response = self.error_response(message, 400, "Unsupported STUN request method") response.add_message_integrity(integrity_key) response.add_fingerprint() self.send_stun(response, addr)
def test_binding_request_ice_controlled(self): data = read_message("binding_request_ice_controlled.bin") message = stun.parse_message(data) self.assertEqual(message.message_method, stun.Method.BINDING) self.assertEqual(message.message_class, stun.Class.REQUEST) self.assertEqual(message.transaction_id, b"wxaNbAdXjwG3") self.assertEqual( message.attributes, OrderedDict( [ ("USERNAME", "AYeZ:sw7YvCSbcVex3bhi"), ("PRIORITY", 1685987071), ("SOFTWARE", "FreeSWITCH (-37-987c9b9 64bit)"), ("ICE-CONTROLLED", 5491930053772927353), ( "MESSAGE-INTEGRITY", unhexlify("1963108a4f764015a66b3fea0b1883dfde1436c8"), ), ("FINGERPRINT", 3230414530), ] ), ) self.assertEqual(bytes(message), data)
def test_binding_request(self): data = read_message('binding_request.bin') message = stun.parse_message(data) self.assertEqual(message.message_method, stun.Method.BINDING) self.assertEqual(message.message_class, stun.Class.REQUEST) self.assertEqual(message.transaction_id, b'Nvfx3lU7FUBF') self.assertEqual(message.attributes, OrderedDict()) self.assertEqual(bytes(message), data)
def test_binding_request(self): data = read_message("binding_request.bin") message = stun.parse_message(data) self.assertEqual(message.message_method, stun.Method.BINDING) self.assertEqual(message.message_class, stun.Class.REQUEST) self.assertEqual(message.transaction_id, b"Nvfx3lU7FUBF") self.assertEqual(message.attributes, OrderedDict()) self.assertEqual(bytes(message), data) self.assertEqual( repr(message), "Message(message_method=Method.BINDING, message_class=Class.REQUEST, " "transaction_id=b'Nvfx3lU7FUBF')", )
def test_binding_request_ice_controlling(self): data = read_message('binding_request_ice_controlling.bin') message = stun.parse_message(data) self.assertEqual(message.message_method, stun.Method.BINDING) self.assertEqual(message.message_class, stun.Class.REQUEST) self.assertEqual(message.transaction_id, b'JEwwUxjLWaa2') self.assertEqual(message.attributes, OrderedDict([ ('USERNAME', 'sw7YvCSbcVex3bhi:AYeZ'), ('ICE-CONTROLLING', 5943294521425135761), ('USE-CANDIDATE', None), ('PRIORITY', 1853759231), ('MESSAGE-INTEGRITY', unhexlify('c87b58eccbacdbc075d497ad0c965a82937ab587')), ('FINGERPRINT', 1347006354), ]))
def test_binding_response(self): data = read_message('binding_response.bin') message = stun.parse_message(data) self.assertEqual(message.message_method, stun.Method.BINDING) self.assertEqual(message.message_class, stun.Class.RESPONSE) self.assertEqual(message.transaction_id, b'Nvfx3lU7FUBF') self.assertEqual(message.attributes, OrderedDict([ ('XOR-MAPPED-ADDRESS', ('80.200.136.90', 53054)), ('MAPPED-ADDRESS', ('80.200.136.90', 53054)), ('RESPONSE-ORIGIN', ('52.17.36.97', 3478)), ('OTHER-ADDRESS', ('52.17.36.97', 3479)), ('SOFTWARE', "Citrix-3.2.4.5 'Marshal West'"), ])) self.assertEqual(bytes(message), data)
def test_binding_request_ice_controlled(self): data = read_message('binding_request_ice_controlled.bin') message = stun.parse_message(data) self.assertEqual(message.message_method, stun.Method.BINDING) self.assertEqual(message.message_class, stun.Class.REQUEST) self.assertEqual(message.transaction_id, b'wxaNbAdXjwG3') self.assertEqual(message.attributes, OrderedDict([ ('USERNAME', 'AYeZ:sw7YvCSbcVex3bhi'), ('PRIORITY', 1685987071), ('SOFTWARE', 'FreeSWITCH (-37-987c9b9 64bit)'), ('ICE-CONTROLLED', 5491930053772927353), ('MESSAGE-INTEGRITY', unhexlify('1963108a4f764015a66b3fea0b1883dfde1436c8')), ('FINGERPRINT', 3230414530), ])) self.assertEqual(bytes(message), data)
def datagram_received(self, data: Union[bytes, Text], addr: Tuple) -> None: addr = (addr[0], addr[1]) data = cast(bytes, data) try: msg = stun.parse_message(data) print("[Info] Recv pkt from %s: %s" % (repr(addr), "".join("0x%02x," % c for c in data)[:-1])) except: print("[Error] packet parse error! pkt = " + "".join("0x%02x," % c for c in data)) return if msg.message_class == stun.Class.RESPONSE or msg.message_class == stun.Class.ERROR: if msg.transaction_id in self.transactions: trans = self.transactions[msg.transaction_id] trans.response_received(msg, addr) else: print("[Info] not expected message: %s" % (repr(msg)))
def test_binding_response(self): data = read_message("binding_response.bin") message = stun.parse_message(data) self.assertEqual(message.message_method, stun.Method.BINDING) self.assertEqual(message.message_class, stun.Class.RESPONSE) self.assertEqual(message.transaction_id, b"Nvfx3lU7FUBF") self.assertEqual( message.attributes, OrderedDict([ ("XOR-MAPPED-ADDRESS", ("80.200.136.90", 53054)), ("MAPPED-ADDRESS", ("80.200.136.90", 53054)), ("RESPONSE-ORIGIN", ("52.17.36.97", 3478)), ("OTHER-ADDRESS", ("52.17.36.97", 3479)), ("SOFTWARE", "Citrix-3.2.4.5 'Marshal West'"), ]), ) self.assertEqual(bytes(message), data)
def test_binding_request_ice_controlling(self): data = read_message("binding_request_ice_controlling.bin") message = stun.parse_message(data) self.assertEqual(message.message_method, stun.Method.BINDING) self.assertEqual(message.message_class, stun.Class.REQUEST) self.assertEqual(message.transaction_id, b"JEwwUxjLWaa2") self.assertEqual( message.attributes, OrderedDict([ ("USERNAME", "sw7YvCSbcVex3bhi:AYeZ"), ("ICE-CONTROLLING", 5943294521425135761), ("USE-CANDIDATE", None), ("PRIORITY", 1853759231), ( "MESSAGE-INTEGRITY", unhexlify("c87b58eccbacdbc075d497ad0c965a82937ab587"), ), ("FINGERPRINT", 1347006354), ]), )
def test_message_shorter_than_header(self): with self.assertRaises(ValueError) as cm: stun.parse_message(b"123") self.assertEqual(str(cm.exception), "STUN message length is less than 20 bytes")
def test_message_body_length_mismatch(self): data = read_message("binding_response.bin") + b"123" with self.assertRaises(ValueError) as cm: stun.parse_message(data) self.assertEqual(str(cm.exception), "STUN message length does not match")
def datagram_received(self, data, addr): # demultiplex channel data if len(data) >= 4 and (data[0]) & 0xc0 == 0x40: channel, length = struct.unpack('!HH', data[0:4]) assert len(data) >= length + 4 # echo test if data[4:] == b'ping': response = b'pong' self.transport.sendto( struct.pack('!HH', channel, len(response)) + response, addr) # send back some junk too self.transport.sendto(b'\x00\x00', addr) return try: message = stun.parse_message(data) except ValueError: return assert message.message_class == stun.Class.REQUEST if 'USERNAME' not in message.attributes: response = stun.Message(message_method=message.message_method, message_class=stun.Class.ERROR, transaction_id=message.transaction_id) response.attributes['ERROR-CODE'] = (401, 'Unauthorized') response.attributes['NONCE'] = random_string(16).encode('ascii') response.attributes['REALM'] = self.realm self.transport.sendto(bytes(response), addr) return # check credentials username = message.attributes['USERNAME'] password = self.users[username] integrity_key = hashlib.md5(':'.join([username, self.realm, password ]).encode('utf8')).digest() try: stun.parse_message(data, integrity_key=integrity_key) except ValueError: return if message.message_method == stun.Method.ALLOCATE: response = stun.Message(message_method=message.message_method, message_class=stun.Class.RESPONSE, transaction_id=message.transaction_id) response.attributes['LIFETIME'] = message.attributes['LIFETIME'] response.attributes['XOR-MAPPED-ADDRESS'] = addr response.attributes['XOR-RELAYED-ADDRESS'] = ('1.2.3.4', 1234) response.add_message_integrity(integrity_key) response.add_fingerprint() self.transport.sendto(bytes(response), addr) elif message.message_method == stun.Method.REFRESH: response = stun.Message(message_method=message.message_method, message_class=stun.Class.RESPONSE, transaction_id=message.transaction_id) response.attributes['LIFETIME'] = message.attributes['LIFETIME'] response.add_message_integrity(integrity_key) response.add_fingerprint() self.transport.sendto(bytes(response), addr) elif message.message_method == stun.Method.CHANNEL_BIND: response = stun.Message(message_method=message.message_method, message_class=stun.Class.RESPONSE, transaction_id=message.transaction_id) response.add_message_integrity(integrity_key) response.add_fingerprint() self.transport.sendto(bytes(response), addr)