コード例 #1
0
ファイル: turnserver.py プロジェクト: miScw/aioice
    def handle_channel_bind(self, message, addr):
        try:
            key = (self, addr)
            allocation = self.server.allocations[key]
        except KeyError:
            return self.error_response(message, 437, 'Allocation does not exist')

        if message.attributes['USERNAME'] != allocation.username:
            return self.error_response(message, 441, 'Wrong credentials')

        for attr in ['CHANNEL-NUMBER', 'XOR-PEER-ADDRESS']:
            if attr not in message.attributes:
                return self.error_response(message, 400, 'Missing %s attribute' % attr)

        channel = message.attributes['CHANNEL-NUMBER']
        peer_address = message.attributes['XOR-PEER-ADDRESS']
        if channel not in CHANNEL_RANGE:
            return self.error_response(message, 400, 'Channel number is outside valid range')

        if allocation.channel_to_peer.get(channel) not in [None, peer_address]:
            return self.error_response(message, 400, 'Channel is already bound to another peer')
        if allocation.peer_to_channel.get(peer_address) not in [None, channel]:
            return self.error_response(message, 400, 'Peer is already bound to another channel')

        # register channel
        allocation.channel_to_peer[channel] = peer_address
        allocation.peer_to_channel[peer_address] = channel

        # build response
        response = stun.Message(
            message_method=message.message_method,
            message_class=stun.Class.RESPONSE,
            transaction_id=message.transaction_id)
        return response
コード例 #2
0
ファイル: test_ice.py プロジェクト: xobs/aioice
    def test_peer_reflexive(self):
        connection = ice.Connection(ice_controlling=True)
        connection.remote_password = '******'
        connection.remote_username = '******'
        protocol = ProtocolMock()

        request = stun.Message(message_method=stun.Method.BINDING,
                               message_class=stun.Class.REQUEST)
        request.attributes['PRIORITY'] = 456789

        connection.check_incoming(request, ('2.3.4.5', 2345), protocol)
        self.assertIsNone(protocol.sent_message)

        # check we have discovered a peer-reflexive candidate
        self.assertEqual(len(connection.remote_candidates), 1)
        candidate = connection.remote_candidates[0]
        self.assertEqual(candidate.component, 1)
        self.assertEqual(candidate.transport, 'udp')
        self.assertEqual(candidate.priority, 456789)
        self.assertEqual(candidate.host, '2.3.4.5')
        self.assertEqual(candidate.port, 2345)
        self.assertEqual(candidate.type, 'prflx')
        self.assertEqual(candidate.generation, None)

        # check a new pair was formed
        self.assertEqual(len(connection._check_list), 1)
        pair = connection._check_list[0]
        self.assertEqual(pair.protocol, protocol)
        self.assertEqual(pair.remote_candidate, candidate)

        # check a triggered check was scheduled
        self.assertIsNotNone(pair.handle)
        protocol.response_addr = ('2.3.4.5', 2345)
        protocol.response_message = 'bad'
        run(pair.handle)
コード例 #3
0
ファイル: turnserver.py プロジェクト: alexeydevil/aioice
    def handle_refresh(self, message, addr):
        try:
            key = (self, addr)
            allocation = self.server.allocations[key]
        except KeyError:
            return self.error_response(message, 437, "Allocation does not exist")

        if message.attributes["USERNAME"] != allocation.username:
            return self.error_response(message, 441, "Wrong credentials")

        if "LIFETIME" not in message.attributes:
            return self.error_response(message, 400, "Missing LIFETIME attribute")

        # refresh allocation
        lifetime = min(message.attributes["LIFETIME"], self.server.maximum_lifetime)
        if lifetime:
            logger.info("Allocation refreshed %s", allocation.relayed_address)
            allocation.expiry = time.time() + lifetime
        else:
            logger.info("Allocation deleted %s", allocation.relayed_address)
            del self.server.allocations[key]

        # build response
        response = stun.Message(
            message_method=message.message_method,
            message_class=stun.Class.RESPONSE,
            transaction_id=message.transaction_id,
        )
        response.attributes["LIFETIME"] = lifetime
        return response
コード例 #4
0
ファイル: turnserver.py プロジェクト: miScw/aioice
 def handle_binding(self, message, addr):
     response = stun.Message(
         message_method=message.message_method,
         message_class=stun.Class.RESPONSE,
         transaction_id=message.transaction_id)
     response.attributes['XOR-MAPPED-ADDRESS'] = addr
     return response
コード例 #5
0
    def test_timeout(self):
        class DummyProtocol:
            def send_stun(self, message, address):
                pass

        request = stun.Message(message_method=stun.Method.BINDING,
                               message_class=stun.Class.REQUEST)
        transaction = stun.Transaction(request, ('127.0.0.1', 1234), DummyProtocol())

        # timeout
        with self.assertRaises(exceptions.TransactionTimeout):
            run(transaction.run())

        # receive response after timeout
        response = stun.Message(message_method=stun.Method.BINDING,
                                message_class=stun.Class.RESPONSE)
        transaction.response_received(response, ('127.0.0.1', 1234))
コード例 #6
0
ファイル: test_exceptions.py プロジェクト: alexeydevil/aioice
    def test_transaction_failed(self):
        response = stun.Message(
            message_method=stun.Method.BINDING, message_class=stun.Class.RESPONSE
        )
        response.attributes["ERROR-CODE"] = (487, "Role Conflict")

        exc = exceptions.TransactionFailed(response)
        self.assertEqual(str(exc), "STUN transaction failed (487 - Role Conflict)")
コード例 #7
0
ファイル: turnserver.py プロジェクト: rushib1/aioice
 def error_response(self, request, code, message):
     """
     Build an error response for the given request.
     """
     response = stun.Message(message_method=request.message_method,
                             message_class=stun.Class.ERROR,
                             transaction_id=request.transaction_id)
     response.attributes['ERROR-CODE'] = (code, message)
     return response
コード例 #8
0
ファイル: test_ice.py プロジェクト: sebastianriese/aioice
    def test_request_with_invalid_method(self):
        connection = ice.Connection(ice_controlling=True)
        protocol = ProtocolMock()

        request = stun.Message(
            message_method=stun.Method.ALLOCATE,
            message_class=stun.Class.REQUEST)

        connection.request_received(request, ('2.3.4.5', 2345), protocol, bytes(request))
        self.assertIsNotNone(protocol.sent_message)
        self.assertEqual(protocol.sent_message.message_method, stun.Method.ALLOCATE)
        self.assertEqual(protocol.sent_message.message_class, stun.Class.ERROR)
        self.assertEqual(protocol.sent_message.attributes['ERROR-CODE'], (400, 'Bad Request'))
コード例 #9
0
async def stunTest(protocol: StunProtocol, server_ip: Tuple[str, int],
                   change_ip: bool,
                   change_port: bool) -> Tuple[bool, Tuple[str, int]]:
    cmd = stun.Message(message_method=stun.Method.BINDING,
                       message_class=stun.Class.REQUEST)
    if change_ip:
        cmd.attributes["CHANGE-REQUEST"] = 0x4
    if change_port:
        cmd.attributes["CHANGE-REQUEST"] = 0x2
    try:
        ack, _ = await protocol.request(cmd, server_ip, retransmissions=3)
        if ack:
            return True, ack.attributes["XOR-MAPPED-ADDRESS"]
    except Exception as e:
        print("[ERROR] %s" % str(e))
    return False, None
コード例 #10
0
ファイル: turnserver.py プロジェクト: arushkharbanda/aioice
    async def handle_allocate(self, message, addr, integrity_key):
        key = (self, addr)
        if key in self.server.allocations:
            response = self.error_response(message, 437,
                                           "Allocation already exists")
        elif "REQUESTED-TRANSPORT" not in message.attributes:
            response = self.error_response(
                message, 400, "Missing REQUESTED-TRANSPORT attribute")
        elif message.attributes["REQUESTED-TRANSPORT"] != UDP_TRANSPORT:
            response = self.error_response(message, 442,
                                           "Unsupported transport protocol")
        else:
            lifetime = message.attributes.get("LIFETIME",
                                              self.server.default_lifetime)
            lifetime = min(lifetime, self.server.maximum_lifetime)

            # create allocation
            loop = asyncio.get_event_loop()
            _, allocation = await loop.create_datagram_endpoint(
                lambda: Allocation(
                    client_address=addr,
                    client_protocol=self,
                    expiry=time.time() + lifetime,
                    username=message.attributes["USERNAME"],
                ),
                local_addr=("127.0.0.1", 0),
            )
            self.server.allocations[key] = allocation

            logger.info("Allocation created %s", allocation.relayed_address)

            # build response
            response = stun.Message(
                message_method=message.message_method,
                message_class=stun.Class.RESPONSE,
                transaction_id=message.transaction_id,
            )
            response.attributes["LIFETIME"] = lifetime
            response.attributes["XOR-MAPPED-ADDRESS"] = addr
            response.attributes[
                "XOR-RELAYED-ADDRESS"] = allocation.relayed_address

        # send response
        response.add_message_integrity(integrity_key)
        response.add_fingerprint()
        self.send_stun(response, addr)
コード例 #11
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)