예제 #1
0
    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)
예제 #2
0
    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)