def test_afi_65535(self):
        '''
        AFI 65535 is reserved
        '''
        afi_address_hex = 'ffffabcdabcdabcd'
        bitstream = ConstBitStream(hex=afi_address_hex)

        with self.assertRaisesRegexp(ValueError, 'AFI'):
            afi.read_afi_address_from_bitstream(bitstream)
    def from_bytes(cls, bitstream):
        '''
        Parse the given packet and update properties accordingly
        '''
        packet = cls()

        # Convert to ConstBitStream (if not already provided)
        if not isinstance(bitstream, ConstBitStream):
            if isinstance(bitstream, Bits):
                bitstream = ConstBitStream(auto=bitstream)
            else:
                bitstream = ConstBitStream(bytes=bitstream)

        # Read the type
        type_nr = bitstream.read('uint:4')
        if type_nr != packet.message_type:
            msg = 'Invalid bitstream for a {0} packet'
            class_name = packet.__class__.__name__
            raise ValueError(msg.format(class_name))

        # Read if this is a reply
        packet.is_reply = bitstream.read('bool')

        # Skip reserved bits
        packet._reserved1 = bitstream.read(27)

        # Read the nonce
        packet.nonce = bitstream.read('bytes:8')

        # Read the key id
        packet.key_id = bitstream.read('uint:16')

        # Read the authentication data
        data_length = bitstream.read('uint:16')
        packet.authentication_data = bitstream.read('bytes:%d' % data_length)

        # Read the TTL
        packet.ttl = bitstream.read('uint:32')

        # Skip reserved bits
        packet._reserved2 = bitstream.read(8)

        # Store the EID prefix mask length until we need it
        eid_prefix_len = bitstream.read('uint:8')

        # Read the EID prefix
        packet.eid_prefix = read_afi_address_from_bitstream(bitstream, eid_prefix_len)

        # Read the reply
        packet.reply = read_afi_address_from_bitstream(bitstream)

        # Verify that the properties make sense
        packet.sanitize()

        return packet
    def test_afi_0_with_prefixlen(self):
        '''
        Specifying a prefix length for an empty AFI address is invalid
        '''
        bitstream = ConstBitStream(hex='0000')

        with self.assertRaisesRegexp(ValueError, r'prefix'):
            afi.read_afi_address_from_bitstream(bitstream, 16)

        self.assertEqual(bitstream.pos, bitstream.len,
                         'unprocessed bits remaining in bitstream')
    def test_afi_2_with_bad_prefixlen(self):
        '''
        Test decoding of AFI 2 (IPv6) prefixes with a bad prefix length
        '''
        afi_address_hex = '000220010db80102abcd000000000000cafe'
        bitstream = ConstBitStream(hex=afi_address_hex)

        with self.assertRaisesRegexp(ValueError, 'invalid.prefix.length'):
            afi.read_afi_address_from_bitstream(bitstream, 64)

        self.assertEqual(bitstream.pos, bitstream.len,
                         'unprocessed bits remaining in bitstream')
 def _from_data_bytes(cls, data, prefix_len=None, rsvd1=None, flags=None,
                      rsvd2=None):
     (north, latitude_degrees, latitude_minutes,
      latitude_seconds) = data.readlist('bool, uint:15, 2*uint:8')
     (east, longitude_degrees, longitude_minutes,
      longitude_seconds) = data.readlist('bool, uint:15, 2*uint:8')
     altitude = data.read('int:32')
     address = read_afi_address_from_bitstream(data)
     if prefix_len is not None:
         orig_address = address
         address = ip_network(address).supernet(new_prefix=prefix_len)
         if address[0] != orig_address:
             raise ValueError("invalid prefix length %s for %r"
                              % (prefix_len, address))
     lcaf = cls(north=north,
                latitude_degrees=latitude_degrees,
                latitude_minutes=latitude_minutes,
                latitude_seconds=latitude_seconds,
                east=east,
                longitude_degrees=longitude_degrees,
                longitude_minutes=longitude_minutes,
                longitude_seconds=longitude_seconds,
                altitude=altitude,
                address=address)
     lcaf.sanitize()
     return lcaf
    def from_bytes(cls, bitstream):
        """
        Parse the given record and update properties accordingly
        """
        record = cls()

        # Convert to ConstBitStream (if not already provided)
        if not isinstance(bitstream, ConstBitStream):
            if isinstance(bitstream, Bits):
                bitstream = ConstBitStream(auto=bitstream)
            else:
                bitstream = ConstBitStream(bytes=bitstream)

        # Read the record TTL
        record.ttl = bitstream.read("uint:32")

        # Store the locator record count until we need it
        referral_count = bitstream.read("uint:8")

        # Store the EID prefix mask length until we need it
        eid_prefix_len = bitstream.read("uint:8")

        # Read the Negative Map_Reply action
        record.action = bitstream.read("uint:3")

        # Read the flags
        (record.authoritative, record.incomplete) = bitstream.readlist("2*bool")

        # Read reserved bits
        record._reserved1 = bitstream.read(11)

        # Read the signature count
        sig_count = bitstream.read("uint:4")

        # Read the map version
        record.map_version = bitstream.read("uint:12")

        # Read the EID prefix
        record.eid_prefix = read_afi_address_from_bitstream(bitstream, eid_prefix_len)

        # Read the locator records
        for dummy in range(referral_count):
            locator_record = LocatorRecord.from_bytes(bitstream)
            record.locator_records.append(locator_record)

        # TODO: Can't handle signatures yet! [LISP-Security]
        if sig_count:
            raise NotImplementedError("Cannot handle signatures yet")

        # Verify that the properties make sense
        record.sanitize()

        return record
    def _from_data_bytes(cls, data, prefix_len=None, rsvd1=None, flags=None, rsvd2=None):
        # These are fixed
        map_server_port, etr_port = data.readlist('2*uint:16')
        global_etr_rloc = read_afi_address_from_bitstream(data)
        map_server_rloc = read_afi_address_from_bitstream(data)
        private_etr_rloc = read_afi_address_from_bitstream(data)

        # The rest of the data is RTR RLOCs
        rtr_rlocs = []
        while data.pos != data.len:
            rtr_rlocs.append(read_afi_address_from_bitstream(data))

        # Build the object
        lcaf = cls(map_server_port=map_server_port,
                   etr_port=etr_port,
                   global_etr_rloc=global_etr_rloc,
                   map_server_rloc=map_server_rloc,
                   private_etr_rloc=private_etr_rloc,
                   rtr_rlocs=rtr_rlocs)
        lcaf.sanitize()
        return lcaf
 def _from_data_bytes(cls, data, prefix_len=None, rsvd1=None, flags=None,
                      rsvd2=None):
     asn = data.read('uint:32')
     address = read_afi_address_from_bitstream(data)
     if prefix_len is not None:
         orig_address = address
         address = ip_network(address).supernet(new_prefix=prefix_len)
         if address[0] != orig_address:
             raise ValueError("invalid prefix length %s for %r"
                              % (prefix_len, address))
     lcaf = cls(asn=asn,
                address=address)
     lcaf.sanitize()
     return lcaf
    def test_afi_1_with_prefixlen(self):
        '''
        Test decoding of AFI 1 (IPv4) prefixes
        '''
        afi_address_hex = '0001c0000200'
        bitstream = ConstBitStream(hex=afi_address_hex)

        address = afi.read_afi_address_from_bitstream(bitstream, 24)

        self.assertEqual(address, IPv4Network(u'192.0.2.0/24'))
        self.assertEqual(bitstream.pos, bitstream.len,
                         'unprocessed bits remaining in bitstream')

        new_bitstream = afi.get_bitstream_for_afi_address(address)

        self.assertEqual(new_bitstream.tobytes(), bitstream.tobytes())
    def test_afi_0_without_prefixlen(self):
        '''
        Test en/decoding of empty AFI addresses
        '''
        afi_address_hex = '0000'
        bitstream = ConstBitStream(hex=afi_address_hex)

        address = afi.read_afi_address_from_bitstream(bitstream)

        self.assertIsNone(address, 'wrong address')
        self.assertEqual(bitstream.pos, bitstream.len,
                         'unprocessed bits remaining in bitstream')

        new_bitstream = afi.get_bitstream_for_afi_address(address)

        self.assertEqual(new_bitstream.tobytes(), bitstream.tobytes())
    def test_afi_2_with_prefixlen(self):
        '''
        Test decoding of AFI 2 (IPv6) prefixes
        '''
        afi_address_hex = '000220010db80102abcd0000000000000000'
        bitstream = ConstBitStream(hex=afi_address_hex)

        address = afi.read_afi_address_from_bitstream(bitstream, 64)

        self.assertEqual(address, IPv6Network(u'2001:db8:102:abcd::/64'))
        self.assertEqual(bitstream.pos, bitstream.len,
                         'unprocessed bits remaining in bitstream')

        new_bitstream = afi.get_bitstream_for_afi_address(address)

        self.assertEqual(new_bitstream.tobytes(), bitstream.tobytes())
    def from_bytes(cls, bitstream):
        '''
        Parse the given record and update properties accordingly
        '''
        record = cls()

        # Convert to ConstBitStream (if not already provided)
        if not isinstance(bitstream, ConstBitStream):
            if isinstance(bitstream, Bits):
                bitstream = ConstBitStream(auto=bitstream)
            else:
                bitstream = ConstBitStream(bytes=bitstream)

        # Read the record TTL
        record.ttl = bitstream.read('uint:32')

        # Store the locator record count until we need it
        locator_record_count = bitstream.read('uint:8')

        # Store the EID prefix mask length until we need it
        eid_prefix_len = bitstream.read('uint:8')

        # Read the Negative Map_Reply action
        record.action = bitstream.read('uint:3')

        # Read the flag
        record.authoritative = bitstream.read('bool')

        # Read reserved bits
        record._reserved1 = bitstream.read(12 + 4)

        # Read the map version
        record.map_version = bitstream.read('uint:12')

        # Read the EID prefix
        record.eid_prefix = read_afi_address_from_bitstream(bitstream,
                                                            eid_prefix_len)

        # Read the locator records
        for dummy in range(locator_record_count):
            locator_record = LocatorRecord.from_bytes(bitstream)
            record.locator_records.append(locator_record)

        # Verify that the properties make sense
        record.sanitize()

        return record
    def test_afi_0_with_prefixlen_0(self):
        '''
        Although a prefix length of 0 is allowed (since that is how many
        implementations transmit it on the wire)
        '''
        afi_address_hex = '0000'
        bitstream = ConstBitStream(hex=afi_address_hex)

        address = afi.read_afi_address_from_bitstream(bitstream, 0)

        self.assertIsNone(address, 'wrong address')
        self.assertEqual(bitstream.pos, bitstream.len,
                         'unprocessed bits remaining in bitstream')

        new_bitstream = afi.get_bitstream_for_afi_address(address)

        self.assertEqual(new_bitstream.tobytes(), bitstream.tobytes())
    def from_bytes(cls, bitstream):
        r'''
        Parse the given packet and update properties accordingly

        >>> data_hex = ('13000001ae92b5574f849cd00001ac10'
        ...             '1f0300015cfe1cbd00200001ac101f01')
        >>> data = data_hex.decode('hex')
        >>> message = ControlMessage.from_bytes(data)
        >>> message.message_type
        1
        >>> message.authoritative
        False
        >>> message.probe
        True
        >>> message.smr
        True
        >>> message.pitr
        False
        >>> message.smr_invoked
        False
        >>> message.nonce
        '\xae\x92\xb5WO\x84\x9c\xd0'
        >>> message.source_eid
        IPv4Address(u'172.16.31.3')
        >>> message.itr_rlocs
        [IPv4Address(u'92.254.28.189')]
        >>> message.eid_prefixes
        [IPv4Network(u'172.16.31.1/32')]
        >>> message.map_reply
        '''
        packet = cls()

        # Convert to ConstBitStream (if not already provided)
        if not isinstance(bitstream, ConstBitStream):
            if isinstance(bitstream, Bits):
                bitstream = ConstBitStream(auto=bitstream)
            else:
                bitstream = ConstBitStream(bytes=bitstream)

        # Read the message type
        type_nr = bitstream.read('uint:4')
        if type_nr != packet.message_type:
            msg = 'Invalid bitstream for a {0} packet'
            class_name = packet.__class__.__name__
            raise ValueError(msg.format(class_name))

        # Read the flags
        (packet.authoritative,
         map_data_present,
         packet.probe,
         packet.smr,
         packet.pitr,
         packet.smr_invoked) = bitstream.readlist('6*bool')

        # Skip over reserved bits
        packet._reserved1 = bitstream.read(9)

        # Save the IRC until we reach the actual data
        irc = bitstream.read('uint:5')

        # Save the record count until we reach the actual data
        record_count = bitstream.read('uint:8')

        # Read the nonce
        packet.nonce = bitstream.read('bytes:8')

        # Read the source EID
        packet.source_eid = read_afi_address_from_bitstream(bitstream)

        # Read the ITR RLOCs
        for dummy in range(irc + 1):
            itr_rloc = read_afi_address_from_bitstream(bitstream)
            packet.itr_rlocs.append(itr_rloc)

        # Read the EIDs
        for dummy in range(record_count):
            # A records begins with 8 reserved bits: skip
            bitstream.read(8)

            # Read 8 bits for the prefix length
            prefix_len = bitstream.read('uint:8')

            # Then an AFI style prefix
            eid_prefix = read_afi_address_from_bitstream(bitstream, prefix_len)
            packet.eid_prefixes.append(eid_prefix)

        # Read the map-reply record if present
        if map_data_present:
            packet.map_reply = MapReplyRecord.from_bytes(bitstream)

        # Verify that the properties make sense
        packet.sanitize()

        return packet