Esempio n. 1
0
 def test_basic(self, time_):
     path_policy = MagicMock(spec_set=['history_limit'])
     path_policy.history_limit = 3
     pth_str = PathStore(path_policy)
     pth_str.candidates = [
         MagicMock(spec_set=['expiration_time', 'id']) for i in range(5)
     ]
     for i in range(5):
         pth_str.candidates[i].expiration_time = i
         pth_str.candidates[i].id = i
     time_.return_value = 2
     pth_str.remove_segments = MagicMock(spec_set=[])
     pth_str._remove_expired_segments()
     pth_str.remove_segments.assert_called_once_with([0, 1, 2])
Esempio n. 2
0
 def test_basic(self):
     pth_str = PathStore(self.path_policy)
     pth_str.candidates = [
         MagicMock(spec_set=['id', 'fidelity']) for i in range(5)
     ]
     for i in range(5):
         pth_str.candidates[i].id = i
         pth_str.candidates[i].fidelity = i
     pth_str._update_all_fidelity = MagicMock(spec_set=[])
     pth_str.remove_segments([1, 2, 3])
     ntools.eq_(len(pth_str.candidates), 2)
     ntools.eq_(pth_str.candidates[0].id, 4)
     ntools.eq_(pth_str.candidates[1].id, 0)
     pth_str._update_all_fidelity.assert_called_once_with()
Esempio n. 3
0
 def __init__(self, server_id, conf_dir, prom_export=None):
     """
     :param str server_id: server identifier.
     :param str conf_dir: configuration directory.
     :param str prom_export: prometheus export address.
     """
     super().__init__(server_id, conf_dir, prom_export)
     # Sanity check that we should indeed be a local beacon server.
     assert not self.topology.is_core_as, "This shouldn't be a core BS!"
     self.beacons = PathStore(self.path_policy)
     self.up_segments = PathStore(self.path_policy)
     self.down_segments = PathStore(self.path_policy)
     self.cert_chain = self.trust_store.get_cert(self.addr.isd_as)
     assert self.cert_chain
Esempio n. 4
0
 def test_not_present(self):
     pth_str = PathStore(self.path_policy)
     pth_str.candidates = [MagicMock(spec_set=['id']) for i in range(5)]
     ntools.assert_is_none(pth_str.get_segment(2))
Esempio n. 5
0
 def test_false(self):
     pth_str = PathStore(self._setup())
     ntools.eq_(pth_str.get_latest_history_snapshot(3), [])
Esempio n. 6
0
class LocalBeaconServer(BeaconServer):
    """
    PathConstructionBeacon Server in a non-core AS.

    Receives, processes, and propagates beacons received by other beacon
    servers.
    """
    def __init__(self,
                 server_id,
                 conf_dir,
                 spki_cache_dir=GEN_CACHE_PATH,
                 prom_export=None,
                 sciond_path=None):
        """
        :param str server_id: server identifier.
        :param str conf_dir: configuration directory.
        :param str prom_export: prometheus export address.
        :param str sciond_path: path to sciond socket
        """
        super().__init__(server_id,
                         conf_dir,
                         spki_cache_dir=spki_cache_dir,
                         prom_export=prom_export,
                         sciond_path=sciond_path)
        # Sanity check that we should indeed be a local beacon server.
        assert not self.topology.is_core_as, "This shouldn't be a core BS!"
        self.beacons = PathStore(self.path_policy)
        self.up_segments = PathStore(self.path_policy)
        self.down_segments = PathStore(self.path_policy)
        self.cert_chain = self.trust_store.get_cert(self.addr.isd_as)
        assert self.cert_chain

    def register_up_segment(self, pcb, svc_type):
        """
        Send up-segment to Local Path Servers and Sibra Servers

        :raises:
            SCIONServiceLookupError: service type lookup failure
        """
        pcb.sign(self.signing_key)
        records = PathRecordsReg.from_values({PST.UP: [pcb]})
        addr, port = self.dns_query_topo(svc_type)[0]
        meta = self._build_meta(host=addr, port=port)
        self.send_meta(CtrlPayload(PathMgmt(records)), meta)
        return meta

    def register_down_segment(self, pcb):
        """
        Send down-segment to Core Path Server
        """
        pcb.sign(self.signing_key)
        core_path = pcb.get_path(reverse_direction=True)
        records = PathRecordsReg.from_values({PST.DOWN: [pcb]})
        dst_ia = pcb.asm(0).isd_as()
        meta = self._build_meta(ia=dst_ia,
                                host=SVCType.PS_A,
                                path=core_path,
                                reuse=True)
        self.send_meta(CtrlPayload(PathMgmt(records)), meta)
        return meta

    def register_segments(self):
        """
        Register paths according to the received beacons.
        """
        self.register_up_segments()
        self.register_down_segments()

    def _remove_revoked_pcbs(self, rev_info):
        with self._rev_seg_lock:
            candidates = (self.down_segments.candidates +
                          self.up_segments.candidates +
                          self.beacons.candidates)
            to_remove = self._pcb_list_to_remove(candidates, rev_info)
            # Remove the affected segments from the path stores.
            self.beacons.remove_segments(to_remove)
            self.up_segments.remove_segments(to_remove)
            self.down_segments.remove_segments(to_remove)

    def _handle_verified_beacon(self, pcb):
        """
        Once a beacon has been verified, place it into the right containers.
        """
        with self._rev_seg_lock:
            self.beacons.add_segment(pcb)
            self.up_segments.add_segment(pcb)
            self.down_segments.add_segment(pcb)

    def handle_pcbs_propagation(self):
        """
        Main loop to propagate received beacons.
        """
        # TODO: define function that dispatches the pcbs among the interfaces
        with self._rev_seg_lock:
            best_segments = self.beacons.get_best_segments()
        propagated_pcbs = defaultdict(list)
        for pcb in best_segments:
            propagated = self.propagate_downstream_pcb(pcb)
            for k, v in propagated.items():
                propagated_pcbs[k].extend(v)
        self._log_propagations(propagated_pcbs)

    def register_up_segments(self):
        """
        Register the paths to the core.
        """
        with self._rev_seg_lock:
            best_segments = self.up_segments.get_best_segments(sending=False)
        registered_paths = defaultdict(list)
        for pcb in best_segments:
            new_pcb = self._terminate_pcb(pcb)
            if not new_pcb:
                continue
            try:
                dst_meta = self.register_up_segment(new_pcb, ServiceType.PS)
            except SCIONServiceLookupError as e:
                logging.warning("Unable to send up-segment registration: %s",
                                e)
                continue
            # Keep the ID of the not-terminated PCB to relate to previously received ones.
            registered_paths[(str(dst_meta),
                              ServiceType.PS)].append(pcb.short_id())
        self._log_registrations(registered_paths, "up")

    def register_down_segments(self):
        """
        Register the paths from the core.
        """
        with self._rev_seg_lock:
            best_segments = self.down_segments.get_best_segments(sending=False)
        registered_paths = defaultdict(list)
        for pcb in best_segments:
            new_pcb = self._terminate_pcb(pcb)
            if not new_pcb:
                continue
            dst_ps = self.register_down_segment(new_pcb)
            # Keep the ID of the not-terminated PCB to relate to previously received ones.
            registered_paths[(str(dst_ps),
                              ServiceType.PS)].append(pcb.short_id())
        self._log_registrations(registered_paths, "down")
Esempio n. 7
0
class LocalBeaconServer(BeaconServer):
    """
    PathConstructionBeacon Server in a non-core AS.

    Receives, processes, and propagates beacons received by other beacon
    servers.
    """
    def __init__(self, server_id, conf_dir):
        """
        :param str server_id: server identifier.
        :param str conf_dir: configuration directory.
        """
        super().__init__(server_id, conf_dir)
        # Sanity check that we should indeed be a local beacon server.
        assert not self.topology.is_core_as, "This shouldn't be a core BS!"
        self.beacons = PathStore(self.path_policy)
        self.up_segments = PathStore(self.path_policy)
        self.down_segments = PathStore(self.path_policy)
        self.cert_chain_requests = {}
        self.cert_chains = {}
        self.cert_chain = self.trust_store.get_cert(self.addr.isd_as)
        assert self.cert_chain

    def _check_trc(self, isd_as, trc_ver):
        """
        Return True or False whether the necessary Certificate and TRC files are
        found.

        :param ISD_AS isd_as: ISD-AS identifier.
        :param int trc_ver: TRC file version.
        :returns: True if the files exist, False otherwise.
        :rtype: bool
        """
        if self._get_trc(isd_as, trc_ver):
            return True
        return False

    def register_up_segment(self, pcb):
        """
        Send up-segment to Local Path Servers and Sibra Servers

        :raises:
            SCIONServiceLookupError: path server lookup failure
        """
        records = PathRecordsReg.from_values({PST.UP: [pcb]})
        addr, port = self.dns_query_topo(PATH_SERVICE)[0]
        meta = self.DefaultMeta.from_values(host=addr, port=port)
        self.send_meta(records.copy(), meta)
        addr, port = self.dns_query_topo(SIBRA_SERVICE)[0]
        meta = self.DefaultMeta.from_values(host=addr, port=port)
        self.send_meta(records, meta)

    def register_down_segment(self, pcb):
        """
        Send down-segment to Core Path Server
        """
        core_path = pcb.get_path(reverse_direction=True)
        records = PathRecordsReg.from_values({PST.DOWN: [pcb]})
        dst_ia = pcb.asm(0).isd_as()
        meta = self.DefaultMeta.from_values(ia=dst_ia,
                                            host=SVCType.PS_A,
                                            path=core_path)
        self.send_meta(records, meta)

    def register_segments(self):
        """
        Register paths according to the received beacons.
        """
        self.register_up_segments()
        self.register_down_segments()

    def process_pcbs(self, pcbs, raw=True):
        """
        Process new beacons and appends them to beacon list.
        """
        for pcb in pcbs:
            if raw:
                try:
                    pcb = PathSegment.from_raw(pcb)
                except SCIONParseError as e:
                    logging.error("Unable to parse raw pcb: %s", e)
                    continue
            if self.path_policy.check_filters(pcb):
                self._try_to_verify_beacon(pcb)
                self.handle_ext(pcb)

    def process_cert_chain_rep(self, rep, meta):
        """
        Process the Certificate chain reply.

        :param rep: certificate chain reply.
        :type rep: CertChainReply
        """
        logging.info("Certificate chain reply received for %s",
                     rep.short_desc())
        rep_key = rep.cert_chain.get_leaf_isd_as_ver()
        self.trust_store.add_cert(rep.cert_chain)
        if rep_key in self.cert_chain_requests:
            del self.cert_chain_requests[rep_key]

    def _remove_revoked_pcbs(self, rev_info):
        candidates = (self.down_segments.candidates +
                      self.up_segments.candidates + self.beacons.candidates)
        to_remove = self._pcb_list_to_remove(candidates, rev_info)
        # Remove the affected segments from the path stores.
        self.beacons.remove_segments(to_remove)
        self.up_segments.remove_segments(to_remove)
        self.down_segments.remove_segments(to_remove)

    def _handle_verified_beacon(self, pcb):
        """
        Once a beacon has been verified, place it into the right containers.
        """
        self.beacons.add_segment(pcb)
        self.up_segments.add_segment(pcb)
        self.down_segments.add_segment(pcb)

    def handle_pcbs_propagation(self):
        """
        Main loop to propagate received beacons.
        """
        # TODO: define function that dispatches the pcbs among the interfaces
        best_segments = self.beacons.get_best_segments()
        for pcb in best_segments:
            self.propagate_downstream_pcb(pcb)

    def register_up_segments(self):
        """
        Register the paths to the core.
        """
        best_segments = self.up_segments.get_best_segments(sending=False)
        for pcb in best_segments:
            pcb = self._terminate_pcb(pcb)
            if not pcb:
                continue
            pcb.remove_crypto()
            pcb.sign(self.signing_key)
            try:
                self.register_up_segment(pcb)
            except SCIONServiceLookupError as e:
                logging.warning("Unable to send up path registration: %s", e)
                continue
            logging.info("Up path registered: %s", pcb.short_desc())

    def register_down_segments(self):
        """
        Register the paths from the core.
        """
        best_segments = self.down_segments.get_best_segments(sending=False)
        for pcb in best_segments:
            pcb = self._terminate_pcb(pcb)
            if not pcb:
                continue
            pcb.remove_crypto()
            pcb.sign(self.signing_key)
            self.register_down_segment(pcb)
            logging.info("Down path registered: %s", pcb.short_desc())
Esempio n. 8
0
class LocalBeaconServer(BeaconServer):
    """
    PathConstructionBeacon Server in a non-core AS.

    Receives, processes, and propagates beacons received by other beacon
    servers.
    """
    def __init__(self, server_id, conf_dir):
        """
        :param str server_id: server identifier.
        :param str conf_dir: configuration directory.
        """
        super().__init__(server_id, conf_dir)
        # Sanity check that we should indeed be a local beacon server.
        assert not self.topology.is_core_as, "This shouldn't be a core BS!"
        self.beacons = PathStore(self.path_policy)
        self.up_segments = PathStore(self.path_policy)
        self.down_segments = PathStore(self.path_policy)
        self.cert_chain = self.trust_store.get_cert(self.addr.isd_as)
        assert self.cert_chain

    def register_up_segment(self, pcb):
        """
        Send up-segment to Local Path Servers and Sibra Servers

        :raises:
            SCIONServiceLookupError: path server lookup failure
        """
        records = PathRecordsReg.from_values({PST.UP: [pcb]})
        addr, port = self.dns_query_topo(PATH_SERVICE)[0]
        meta = self.DefaultMeta.from_values(host=addr, port=port)
        self.send_meta(records.copy(), meta)
        addr, port = self.dns_query_topo(SIBRA_SERVICE)[0]
        meta = self.DefaultMeta.from_values(host=addr, port=port)
        self.send_meta(records, meta)

    def register_down_segment(self, pcb):
        """
        Send down-segment to Core Path Server
        """
        core_path = pcb.get_path(reverse_direction=True)
        records = PathRecordsReg.from_values({PST.DOWN: [pcb]})
        dst_ia = pcb.asm(0).isd_as()
        meta = self.DefaultMeta.from_values(ia=dst_ia,
                                            host=SVCType.PS_A,
                                            path=core_path)
        self.send_meta(records, meta)

    def register_segments(self):
        """
        Register paths according to the received beacons.
        """
        self.register_up_segments()
        self.register_down_segments()

    def _remove_revoked_pcbs(self, rev_info):
        with self._rev_seg_lock:
            candidates = (self.down_segments.candidates +
                          self.up_segments.candidates +
                          self.beacons.candidates)
            to_remove = self._pcb_list_to_remove(candidates, rev_info)
            # Remove the affected segments from the path stores.
            self.beacons.remove_segments(to_remove)
            self.up_segments.remove_segments(to_remove)
            self.down_segments.remove_segments(to_remove)

    def _handle_verified_beacon(self, pcb):
        """
        Once a beacon has been verified, place it into the right containers.
        """
        with self._rev_seg_lock:
            self.beacons.add_segment(pcb)
            self.up_segments.add_segment(pcb)
            self.down_segments.add_segment(pcb)

    def handle_pcbs_propagation(self):
        """
        Main loop to propagate received beacons.
        """
        # TODO: define function that dispatches the pcbs among the interfaces
        with self._rev_seg_lock:
            best_segments = self.beacons.get_best_segments()
        for pcb in best_segments:
            self.propagate_downstream_pcb(pcb)

    def register_up_segments(self):
        """
        Register the paths to the core.
        """
        with self._rev_seg_lock:
            best_segments = self.up_segments.get_best_segments(sending=False)
        for pcb in best_segments:
            pcb = self._terminate_pcb(pcb)
            if not pcb:
                continue
            pcb.sign(self.signing_key)
            try:
                self.register_up_segment(pcb)
            except SCIONServiceLookupError as e:
                logging.warning("Unable to send up path registration: %s", e)
                continue
            logging.info("Up path registered: %s", pcb.short_desc())

    def register_down_segments(self):
        """
        Register the paths from the core.
        """
        with self._rev_seg_lock:
            best_segments = self.down_segments.get_best_segments(sending=False)
        for pcb in best_segments:
            pcb = self._terminate_pcb(pcb)
            if not pcb:
                continue
            pcb.sign(self.signing_key)
            self.register_down_segment(pcb)
            logging.info("Down path registered: %s", pcb.short_desc())