Esempio n. 1
0
    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")
Esempio n. 2
0
    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")
Esempio n. 3
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)
Esempio n. 4
0
    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)
Esempio n. 5
0
    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)
Esempio n. 6
0
    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')",
        )
Esempio n. 7
0
    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),
        ]))
Esempio n. 8
0
    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)
Esempio n. 9
0
    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)
Esempio n. 10
0
    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)))
Esempio n. 11
0
    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)
Esempio n. 12
0
    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),
            ]),
        )
Esempio n. 13
0
 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")
Esempio n. 14
0
 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")
Esempio n. 15
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)