Esempio n. 1
0
    def __init__(self, prefix, etrr, locators, nat_info, control_plane_sockets, data_plane_sockets, want_map_notify=False):
        assert isinstance(etrr, ETRRegistration)

        # Extract RTRs
        rtrs = nat_info and nat_info.rtr_rlocs or set()

        # Store input
        self.prefix = prefix
        self.etrr = etrr
        self.nat_info = nat_info
        self.control_plane_sockets = control_plane_sockets
        self.data_plane_sockets = data_plane_sockets
        self.want_map_notify = want_map_notify or bool(rtrs)

        # Generate the map-register
        self.map_register = MapRegisterMessage(proxy_map_reply=self.etrr.proxy_map_reply,
                                               for_rtr=bool(rtrs),
                                               want_map_notify=self.want_map_notify,
                                               nonce=os.urandom(8),
                                               key_id=self.etrr.key_id,
                                               records=[MapRegisterRecord(ttl=1440,
                                                                          authoritative=True,
                                                                          eid_prefix=self.prefix,
                                                                          locator_records=locators)],
                                               xtr_id=settings.config.XTR_ID,
                                               site_id=settings.config.SITE_ID)
        self.map_register.insert_authentication_data(self.etrr.key)

        # Remember source and destination of the outgoing register
        self.sent_from = None
        self.sent_to = None

        # Here the notify is stored
        self.notify = None

        # This event will be triggered when the notify is received
        self.notify_received = threading.Event()
Esempio n. 2
0
class MapRegister(object):
    def __init__(self, prefix, etrr, locators, nat_info, control_plane_sockets, data_plane_sockets, want_map_notify=False):
        assert isinstance(etrr, ETRRegistration)

        # Extract RTRs
        rtrs = nat_info and nat_info.rtr_rlocs or set()

        # Store input
        self.prefix = prefix
        self.etrr = etrr
        self.nat_info = nat_info
        self.control_plane_sockets = control_plane_sockets
        self.data_plane_sockets = data_plane_sockets
        self.want_map_notify = want_map_notify or bool(rtrs)

        # Generate the map-register
        self.map_register = MapRegisterMessage(proxy_map_reply=self.etrr.proxy_map_reply,
                                               for_rtr=bool(rtrs),
                                               want_map_notify=self.want_map_notify,
                                               nonce=os.urandom(8),
                                               key_id=self.etrr.key_id,
                                               records=[MapRegisterRecord(ttl=1440,
                                                                          authoritative=True,
                                                                          eid_prefix=self.prefix,
                                                                          locator_records=locators)],
                                               xtr_id=settings.config.XTR_ID,
                                               site_id=settings.config.SITE_ID)
        self.map_register.insert_authentication_data(self.etrr.key)

        # Remember source and destination of the outgoing register
        self.sent_from = None
        self.sent_to = None

        # Here the notify is stored
        self.notify = None

        # This event will be triggered when the notify is received
        self.notify_received = threading.Event()

    def send(self):
        if not self.nat_info:
            # Plain Map_Register
            logger.debug(u"Sending Map-Register for {0} to Map-Server {1}".format(self.prefix, self.etrr.map_server))
            self.sent_from, self.sent_to = send_message(message=self.map_register,
                                                        my_sockets=self.control_plane_sockets,
                                                        destinations=[self.etrr.map_server],
                                                        port=4342)
        else:
            logger.debug(u"Sending NATT Map-Register for {0} to Map-Server {1}".format(self.prefix, self.etrr.map_server))

            # Create an IP packet
            if self.etrr.map_server.version != self.nat_info.private_etr_rloc.version:
                logger.error("Address family mismatch between local RLOC and Map-Server")
                return

            if self.etrr.map_server.version == 4:
                ip_packet = IPv4Packet()
            else:
                ip_packet = IPv6Packet()

            # Fill the packet
            ip_packet.ttl = 63
            ip_packet.source = self.nat_info.private_etr_rloc
            ip_packet.destination = self.etrr.map_server

            # UDP payload
            inner_udp = UDPMessage(source_port=4342,
                                   destination_port=4342,
                                   payload=self.map_register)
            inner_udp.checksum = inner_udp.calculate_checksum(source=ip_packet.source,
                                                              destination=ip_packet.destination)

            # Put UDP in the packet
            ip_packet.next_header = inner_udp.header_type
            ip_packet.payload = inner_udp

            # Encapsulate it in an ECM
            ecm = EncapsulatedControlMessage(payload=ip_packet)

            send_message(message=ecm,
                         my_sockets=self.data_plane_sockets,
                         destinations=self.nat_info.rtr_rlocs,
                         port=4342)

    def set_notify_if_matches(self, source, notify):
        assert isinstance(notify, MapNotifyMessage)

        if source != self.etrr.map_server \
        or notify.nonce != self.map_register.nonce:
            # Not for us
            return False

        logger.debug(u"Received a MapNotify from {0}".format(source))
        self.notify = notify
        self.notify_received.set()
        return True

    def notify_content_ok(self):
        if not self.notify_received.is_set():
            logger.error("Cannot validate a MapNotify message without actually receiving it")
            return False

        if not self.notify.verify_authentication_data(self.etrr.key):
            logger.debug(u"MapNotify authentication data is not valid")
            return False

        if self.notify.nonce != self.map_register.nonce:
            logger.debug(u"MapNotify nonce {0x} != MapRegister {1x}".format(self.notify.nonce,
                                                                           self.map_register.nonce))
            return False

        if self.notify.key_id != self.map_register.key_id:
            logger.debug(u"MapNotify key-id {0} != MapRegister {1}".format(self.notify.key_id,
                                                                          self.map_register.key_id))
            return False

        if self.notify.xtr_id != 0 and self.notify.xtr_id != self.map_register.xtr_id:
            logger.debug(u"MapNotify XTR-id {0x} != MapRegister {1x}".format(self.notify.xtr_id,
                                                                            self.map_register.xtr_id))
            return False

        if self.notify.site_id != 0 and self.notify.site_id != self.map_register.site_id:
            logger.debug(u"MapNotify Site-id {0x} != MapRegister {1x}".format(self.notify.site_id,
                                                                             self.map_register.site_id))
            return False

        # Validate records
        if len(self.notify.records) != len(self.map_register.records):
            logger.debug(u"MapNotify contains {0} records != MapRegister {1}".format(len(self.notify.records),
                                                                                    len(self.map_register.records)))
            return False

        for reg_record in self.map_register.records:
            assert isinstance(reg_record, MapRegisterRecord)

            record_found = False
            for record in self.notify.records:
                assert isinstance(record, MapRegisterRecord)

                if record.eid_prefix != reg_record.eid_prefix \
                or record.ttl != reg_record.ttl \
                or record.action != reg_record.action \
                or record.map_version != reg_record.map_version \
                or len(record.locator_records) != len(reg_record.locator_records):
                    # No match
                    continue

                for reg_locator in reg_record.locator_records:
                    assert isinstance(reg_locator, LocatorRecord)

                    locator_found = False
                    for locator in record.locator_records:
                        assert isinstance(locator, LocatorRecord)

                        if locator.priority == reg_locator.priority \
                        and locator.weight == reg_locator.weight \
                        and locator.m_priority == reg_locator.m_priority \
                        and locator.m_weight == reg_locator.m_weight \
                        and locator.reachable == reg_locator.reachable \
                        and locator.address == reg_locator.address:
                            locator_found = True
                            break

                    if not locator_found:
                        logger.debug("Locators for {0} do not match".format(record.eid_prefix))

                # That seemed ok
                record_found = True
                break

            if not record_found:
                logger.debug(u"MapNotify does not contain record for {0} from MapRegister".format(reg_record.eid_prefix))
                return False

        logger.debug(u"MapNotify validated")
        return True