Пример #1
0
 def handle_pcbs_propagation(self):
     """
     Generate a new beacon or gets ready to forward the one received.
     """
     timestamp = int(SCIONTime.get_time())
     # Create beacon for downstream ASes.
     down_iof = InfoOpaqueField.from_values(timestamp, self.addr.isd_as[0])
     downstream_pcb = PathSegment.from_values(down_iof)
     propagated_pcbs = self.propagate_downstream_pcb(downstream_pcb)
     # Create beacon for core ASes.
     core_iof = InfoOpaqueField.from_values(timestamp, self.addr.isd_as[0])
     core_pcb = PathSegment.from_values(core_iof)
     propagated = self.propagate_core_pcb(core_pcb)
     for k, v in propagated.items():
         propagated_pcbs[k].extend(v)
     # Propagate received beacons. A core beacon server can only receive
     # beacons from other core beacon servers.
     beacons = []
     with self._rev_seg_lock:
         for ps in self.core_beacons.values():
             beacons.extend(ps.get_best_segments())
     for pcb in beacons:
         propagated = self.propagate_core_pcb(pcb)
         for k, v in propagated.items():
             propagated_pcbs[k].extend(v)
     self._log_propagations(propagated_pcbs)
Пример #2
0
 def _check_remote_ifid(self, pcb: PathSegment) -> Optional[ISD_AS]:
     Requires(Acc(pcb.State(), 1 / 20))
     Ensures(Acc(pcb.State(), 1 / 20))
     """
     Checkes whether any PCB markings have unset remote IFID values for
     up/downstream ASes. This can happen during normal startup depending
     on the timing of PCB propagation vs IFID keep-alives, but should
     not happen once the infrastructure is settled.
     Remote IFID is only allowed to be 0 if the corresponding ISD-AS is
     0-0.
     """
     asms = pcb.iter_asms()
     for asm in asms:
         Invariant(Forall(asms, lambda a: (Acc(a.State(), 1 / 4), [])))
         pcbms = asm.iter_pcbms()
         for pcbm in pcbms:
             Invariant(Forall(pcbms, lambda p: (Acc(p.State(), 1 / 4), [])))
             if (pcbm.inIA().to_int() and not Unfolding(
                     Acc(pcbm.State(), 1 / 8),
                     Unfolding(Acc(pcbm.p.State(), 1 / 16), pcbm.p.inIF))):
                 return pcbm.inIA()
             if (pcbm.outIA().to_int() and not Unfolding(
                     Acc(pcbm.State(), 1 / 8),
                     Unfolding(Acc(pcbm.p.State(), 1 / 16), pcbm.p.outIF))):
                 return pcbm.outIA()
     return None
Пример #3
0
    def check_filters(self, pcb: PathSegment) -> bool:
        Requires(Acc(pcb.State(), 1 / 10))
        Requires(Acc(self.State(), 1 / 7))
        Requires(self.valid_ranges())
        Ensures(Acc(pcb.State(), 1 / 10))
        Ensures(Acc(self.State(), 1 / 7))
        """
        Runs some checks, including: unwanted ASes and min/max property values.

        :param pcb: beacon to analyze.
        :type pcb: :class:`PathSegment`
        :returns:
            True if any unwanted AS is present or a range is not respected.
        :rtype: bool
        """
        assert isinstance(pcb, PathSegment)
        isd_as = self._check_unwanted_ases(pcb)
        if isd_as:
            logging.warning("PathStore: pcb discarded, unwanted AS(%s): %s",
                            isd_as, pcb.short_desc())
            return False
        reasons = self._check_property_ranges(pcb)
        if reasons:
            logging.info("PathStore: pcb discarded(%s): %s",
                         ", ".join(reasons), pcb.short_desc())
            return False
        ia = self._check_remote_ifid(pcb)
        if ia:
            logging.error(
                "PathStore: pcb discarded, remote IFID of %s unknown", )
            return False
        return True
Пример #4
0
 def _setup(self):
     asms = []
     for i in range(3):
         pcbm = create_mock_full({"hof()": "hof %d" % i})
         asms.append(create_mock_full({"pcbm()": pcbm}))
     inst = PathSegment(None)
     inst.iter_asms = create_mock_full(return_value=asms)
     return inst
Пример #5
0
 def _setup(self):
     inst = PathSegment({})
     inst.get_all_iftokens = create_mock_full(return_value=("t0", "t1"))
     h = create_mock_full({
         'update()': None,
         'digest()': "digest",
         'hexdigest()': "hexdigest"
     })
     return inst, h
Пример #6
0
 def _parse(self, raw):
     """
     Parse payload to extract path.
     """
     data = Raw(raw, self.NAME, self.MIN_LEN, min_=True)
     super()._parse(data)
     self.path_type = data.pop(1)
     if self.path_type == PathTransType.OF_PATH:
         self.path = PathTransOFPath(data.pop())
     elif self.path_type == PathTransType.PCB_PATH:
         self.path = PathSegment(data.pop())
     else:
         raise SCIONParseError("Unsupported path type: %s", self.path_type)
Пример #7
0
 def test(self, _):
     asms = []
     for i in range(3):
         pcbms = []
         for j in range(2):
             pcbms.append(
                 create_mock_full({"igRevToken": "ig %d %d" % (i, j)}))
         asms.append(
             create_mock_full({
                 "pcbms": pcbms,
                 "egRevToken": "eg %d" % i
             }))
     inst = PathSegment(create_mock_full({"asms": asms}))
     expected = [
         'ig 0 0', 'ig 0 1', 'eg 0', 'ig 1 0', 'ig 1 1', 'eg 1', 'ig 2 0',
         'ig 2 1', 'eg 2'
     ]
     # Call
     ntools.eq_(inst.get_all_iftokens(), expected)
Пример #8
0
 def _handle_pcbs_from_zk(self, pcbs):
     """
     Handles cached pcbs through ZK, passed as a list.
     """
     for pcb in pcbs:
         try:
             pcb = PathSegment.from_raw(pcb)
         except SCIONParseError as e:
             logging.error("Unable to parse raw pcb: %s", e)
             continue
         self.handle_pcb(pcb)
     logging.debug("Processed %s PCBs from ZK", len(pcbs))
Пример #9
0
    def _check_property_ranges(self, pcb: PathSegment) -> List[str]:
        Requires(Acc(self.State(), 1 / 100))
        Requires(self.valid_ranges())
        Ensures(Acc(self.State(), 1 / 100))
        Ensures(Acc(list_pred(Result())))
        """
        Checks whether any of the path properties has a value outside the
        predefined min-max range.

        :param pcb: beacon to analyze.
        :type pcb: :class:`PathSegment`
        """

        reasons = []  # type: List[str]
        self._check_range(reasons, "PeerLinks", pcb.get_n_peer_links())
        self._check_range(reasons, "HopsLength", pcb.get_n_hops())
        self._check_range(reasons, "DelayTime",
                          int(SCIONTime.get_time()) - pcb.get_timestamp())
        self._check_range(reasons, "GuaranteedBandwidth", 10)
        self._check_range(reasons, "AvailableBandwidth", 10)
        self._check_range(reasons, "TotalBandwidth", 10)
        return reasons
Пример #10
0
 def handle_pcbs_propagation(self):
     """
     Generate a new beacon or gets ready to forward the one received.
     """
     timestamp = int(SCIONTime.get_time())
     # Create beacon for downstream ASes.
     down_iof = InfoOpaqueField.from_values(timestamp, self.addr.isd_as[0])
     downstream_pcb = PathSegment.from_values(down_iof)
     self.propagate_downstream_pcb(downstream_pcb)
     # Create beacon for core ASes.
     core_iof = InfoOpaqueField.from_values(timestamp, self.addr.isd_as[0])
     core_pcb = PathSegment.from_values(core_iof)
     core_count = self.propagate_core_pcb(core_pcb)
     # Propagate received beacons. A core beacon server can only receive
     # beacons from other core beacon servers.
     beacons = []
     for ps in self.core_beacons.values():
         beacons.extend(ps.get_best_segments())
     for pcb in beacons:
         core_count += self.propagate_core_pcb(pcb)
     if core_count:
         logging.info("Propagated %d Core PCBs", core_count)
Пример #11
0
    def _check_unwanted_ases(
            self, pcb: PathSegment) -> Optional[ISD_AS]:  # pragma: no cover
        Requires(Acc(pcb.State(), 1 / 20))
        Requires(Acc(self.State(), 1 / 8))
        Ensures(Acc(pcb.State(), 1 / 20))
        Ensures(Acc(self.State(), 1 / 8))
        """
        Checks whether any of the ASes in the path belong to the black list.

        :param pcb: beacon to analyze.
        :type pcb: :class:`PathSegment`
        """
        asms = pcb.iter_asms()
        for asm in asms:
            Invariant(Forall(asms, lambda a: (Acc(a.State(), 1 / 4), [])))
            Invariant(Acc(self.State(), 1 / 9))
            Invariant(Acc(pcb.State(), 1 / 20))
            isd_as = asm.isd_as()
            Unfold(Acc(self.State(), 1 / 10))
            if isd_as in self.unwanted_ases:
                Fold(Acc(self.State(), 1 / 10))
                return isd_as
            Fold(Acc(self.State(), 1 / 10))
Пример #12
0
 def _verify_path_seg(self, seg_meta):
     """
     Signature verification for all AS markings within this pcb/path segment.
     This function is called, when all TRCs and CCs used within this pcb/path
     segment are available.
     """
     seg = seg_meta.seg
     ver_seg = PathSegment.from_values(seg.info)
     for asm in seg.iter_asms():
         cert_ia = asm.isd_as()
         trc = self.trust_store.get_trc(cert_ia[0], asm.p.trcVer)
         chain = self.trust_store.get_cert(asm.isd_as(), asm.p.certVer)
         ver_seg.add_asm(asm)
         verify_sig_chain_trc(ver_seg.sig_pack3(), asm.p.sig, cert_ia, chain, trc)
Пример #13
0
 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)
Пример #14
0
 def _verify_path_seg(self, seg_meta):
     """
     Signature verification for all AS markings within this pcb/path segment.
     This function is called, when all TRCs and CCs used within this pcb/path
     segment are available.
     """
     seg = seg_meta.seg
     ver_seg = PathSegment.from_values(seg.info)
     for asm in seg.iter_asms():
         cert_ia = asm.isd_as()
         trc = self.trust_store.get_trc(cert_ia[0], asm.p.trcVer)
         chain = self.trust_store.get_cert(asm.isd_as(), asm.p.certVer)
         ver_seg.add_asm(asm)
         if not verify_sig_chain_trc(ver_seg.sig_pack3(), asm.p.sig,
                                     str(cert_ia), chain, trc, asm.p.trcVer):
             logging.error("ASM verification failed: %s" % asm.short_desc())
             return False
     return True
Пример #15
0
 def test_3(self, _):
     asms = []
     for i in range(3):
         asms.append(
             create_mock_full({"sig_pack()": bytes("asm %i" % i, "ascii")}))
     inst = PathSegment(create_mock_full({"info": b"info"}))
     inst.is_sibra = create_mock_full()
     inst.iter_asms = create_mock_full(return_value=asms)
     inst.sibra_ext = create_mock_full({"sig_pack()": b"sibraext"})
     expected = b"".join(
         [b"info", b"asm 0", b"asm 1", b"asm 2", b"sibraext"])
     # Call
     ntools.eq_(inst.sig_pack(3), expected)
Пример #16
0
 def process_pcbs(self, pcbs, raw=True):
     """
     Process new beacons and appends them to beacon list.
     """
     count = 0
     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 not self._filter_pcb(pcb):
             count += 1
             continue
         self._try_to_verify_beacon(pcb)
         self.handle_ext(pcb)
     if count:
         logging.debug("Dropped %d looping Core Segment PCBs", count)
Пример #17
0
 def _create_reg_pcb(self, remote):
     # TODO(kormat): It might make sense to remove peer markings also, but
     # they might also be needed for sibra steady paths that traverse peer
     # links in the future.
     latest = self.blocks[-1]
     assert latest.num_hops == len(latest.sofs)
     info = copy.deepcopy(latest.info)
     info.fwd_dir = not remote
     sofs = latest.sofs[:]
     up = True
     if remote:
         sofs.reverse()
         if self.link_type == LinkType.PARENT:
             up = False
     pcb_d = self.seg.to_dict()
     if remote and self.link_type == LinkType.CORE:
         pcb_d['asms'].reverse()
     pcb = PathSegment.from_dict(pcb_d)
     pcb_ext = SibraPCBExt.from_values(self.id, info, sofs, up)
     pcb.add_sibra_ext(pcb_ext.p)
     pcb.sign(self.signing_key)
     logging.debug(self._reg_pcb_str(pcb))
     return pcb
Пример #18
0
    def test(self):
        """
        Test the main functionalities of the path store.
        """
        path_policy_file = "topology/ISD1/path_policies/ISD1-AD10.json"
        path_policy = PathPolicy.from_file(path_policy_file)
        test_segments = PathStore(path_policy)
        print("Best paths: " + str(len(test_segments.get_best_segments())))
        print("Paths in path store: " + str(len(test_segments.candidates)))
        print("Paths in latest history snapshot: " +
              str(len(test_segments.get_latest_history_snapshot())) + "\n")

        path = 1
        for _ in range(1, 6):
            for _ in range(1, 6):
                pcb = PathSegment()
                pcb.iof = InfoOpaqueField.from_values(OFT.TDC_XOVR, False,
                                                      int(time.time()), path)
                ad_marking = self._create_ad_marking()
                pcb.add_ad(ad_marking)
                print("insert path " + str(path) + ", exp time: " +
                      str(pcb.get_expiration_time()))
                test_segments.add_segment(pcb)
                path += 1
            print("Best paths: " + str(len(test_segments.get_best_segments())))
            print("Paths in path store: " + str(len(test_segments.candidates)))
            print("Paths in latest history snapshot: " +
                  str(len(test_segments.get_latest_history_snapshot())))
            print("Time: " + str(int(time.time())) + "\n")
            time.sleep(5)

        print("Waiting for some paths to expire...")
        time.sleep(25)
        print("Best paths: " + str(len(test_segments.get_best_segments())))
        print("Paths in path store: " + str(len(test_segments.candidates)))
        print("Paths in latest history snapshot: " +
              str(len(test_segments.get_latest_history_snapshot())))
Пример #19
0
class PathTransportExt(EndToEndExtension):
    """
    For path of type OF_PATH, the  header is presented below, path is in
    data-plane format and instantiated as object of PathTransOFPath.
    0B       1        2        3        4        5        6        7
    +--------+--------+--------+--------+--------+--------+--------+--------+
    | xxxxxxxxxxxxxxxxxxxxxxxx |OF_PATH |src_type|dst_type|  scion_src_addr |
    +--------+--------+--------+--------+--------+--------+--------+--------+
    |     (cont., var len)     |         scion_dst_addr (var len)           |
    +--------+--------+--------+--------+--------+--------+--------+--------+
    |    Path (list of opaque fields, var len) + padding (if necessary)     |
    +--------+--------+--------+--------+--------+--------+--------+--------+

    For path of type PCB_PATH, the  header is presented below, path is in
    control-plane format and instantiated as object of PathSegment.
    0B       1        2        3        4        5        6        7
    +--------+--------+--------+--------+--------+--------+--------+--------+
    | xxxxxxxxxxxxxxxxxxxxxxxx |PCB_PATH|       Path (as PathSegment)       |
    +--------+--------+--------+--------+--------+--------+--------+--------+
    |             Path (cont., var len) + padding (if necessary)            |
    +--------+--------+--------+--------+--------+--------+--------+--------+
    """
    NAME = "PathTransportExt"
    EXT_TYPE = ExtEndToEndType.PATH_TRANSPORT

    def __init__(self, raw=None):  # pragma: no cover
        self.path_type = None
        self.path = None
        super().__init__(raw)

    @classmethod
    def from_values(cls, path_type, path):
        """
        Construct extension with a path of type path_type.
        """
        inst = cls()
        inst.path_type = path_type
        inst.path = path
        plen = len(inst.path.pack())
        # How many additional lines are needed for a path.
        inst._init_size(math.ceil((plen - 4) / inst.LINE_LEN))
        return inst

    def _parse(self, raw):
        """
        Parse payload to extract path.
        """
        data = Raw(raw, self.NAME, self.MIN_LEN, min_=True)
        super()._parse(data)
        self.path_type = data.pop(1)
        if self.path_type == PathTransType.OF_PATH:
            self.path = PathTransOFPath(data.pop())
        elif self.path_type == PathTransType.PCB_PATH:
            self.path = PathSegment(data.pop())
        else:
            raise SCIONParseError("Unsupported path type: %s", self.path_type)

    def pack(self):
        packed = []
        packed.append(struct.pack("!B", self.path_type))
        path_packed = self.path.pack()
        packed.append(path_packed)
        # Add possible padding.
        packed.append(bytes(calc_padding(len(path_packed) - 4, self.LINE_LEN)))
        raw = b"".join(packed)
        self._check_len(raw)
        return raw

    def __str__(self):  # pragma: no cover
        return "%s(%dB): type: %s\n  %s" % (self.NAME, len(self),
                                            PathTransType.to_str(
                                                self.path_type), self.path)
Пример #20
0
 def iter_pcbs(self):
     for rec in self.p.recs:
         yield rec.type, PathSegment(rec.pcb)