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 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)