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])
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()
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
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))
def test_false(self): pth_str = PathStore(self._setup()) ntools.eq_(pth_str.get_latest_history_snapshot(3), [])
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")
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())
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())