Example #1
0
 def _parse(self, raw):
     """
     Parses the raw data and populates the fields accordingly.
     """
     data = Raw(raw, self.NAME, self.LEN)
     (types, self.total_len, self.hdr_len, iof_off, hof_off,
      self.next_hdr) = struct.unpack("!HHBBBB", data.pop())
     self.version = types >> 12
     if self.version != SCION_PROTO_VERSION:
         raise SCMPBadVersion("Unsupported SCION version: %s" % self.version)
     self.dst_addr_type = (types >> 6) & 0x3f
     self.src_addr_type = types & 0x3f
     self.addrs_len, _ = SCIONAddrHdr.calc_lens(
         self.dst_addr_type, self.src_addr_type)
     if self.hdr_len_bytes() < self.LEN + self.addrs_len:
         # Can't send an SCMP error, as there isn't enough information to
         # parse the path and the l4 header.
         raise SCIONParseError(
             "hdr_len (%sB) < common header len (%sB) + addrs len (%sB) " %
             (self.hdr_len_bytes(), self.LEN, self.addrs_len))
     if iof_off == hof_off == 0:
         self._iof_idx = self._hof_idx = 0
         return
     if iof_off == 0 or hof_off <= iof_off:
         raise SCIONParseError(
             "invalid CurrINF, CurrHF combination: (%s, %s) " % (iof_off, hof_off))
     first_of_offset = self.LEN + self.addrs_len
     # FIXME(kormat): NB this assumes that all OFs have the same length.
     self._iof_idx = (iof_off * LINE_LEN - first_of_offset) // OpaqueField.LEN
     self._hof_idx = (hof_off * LINE_LEN - first_of_offset) // OpaqueField.LEN
Example #2
0
 def _parse_isd_str(self, raw):
     try:
         self._isd = int(raw)
     except ValueError:
         raise SCIONParseError("Unable to parse ISD from string: %s" %
                               raw) from None
     if self._isd > self.MAX_ISD:
         raise SCIONParseError("ISD too large (max: %d): %s" %
                               (self.MAX_ISD, raw))
Example #3
0
 def _parse_dec_as(self, raw):
     try:
         self._as = int(raw, base=10)
     except ValueError:
         raise SCIONParseError(
             "Unable to parse decimal AS from string: %s" % raw) from None
     if self._as > self.MAX_BGP_AS:
         raise SCIONParseError("Decimal AS too large (max: %d): %s" %
                               (self.MAX_BGP_AS, raw))
Example #4
0
 def from_raw(cls, raw):
     data = Raw(raw, "%s.from_raw" % cls.NAME)
     plen = struct.unpack("!I", data.pop(4))[0]
     if len(data) != plen:
         raise SCIONParseError("Payload length mismatch. Expected: %s Actual: %s" %
                               (plen, len(data)))
     try:
         p = cls.P_CLS.from_bytes_packed(data.pop()).as_builder()
     except capnp.lib.capnp.KjException as e:
         raise SCIONParseError("Unable to parse %s capnp message: %s" % (cls.NAME, e)) from None
     return cls.from_proto(p)
Example #5
0
 def _parse_str(self, raw):
     """
     :param str raw: a string of the format "isd-as".
     """
     isd, as_ = raw.split("-", 1)
     try:
         self._isd = int(isd)
     except ValueError:
         raise SCIONParseError("Unable to parse ISD from string: %s", raw)
     try:
         self._as = int(as_)
     except ValueError:
         raise SCIONParseError("Unable to parse AS from string: %s", raw)
Example #6
0
 def _parse_path(self, data):
     count = self.cmn_hdr.hdr_len - data.offset()
     if count < 0:
         raise SCIONParseError(
             "Bad header len field (%sB), implies negative path length" %
             self.cmn_hdr.hdr_len, )
     if count > len(data):
         raise SCIONParseError(
             "Bad header len field (%sB), "
             "implies path is longer than packet (%sB)" %
             (self.cmn_hdr.hdr_len, len(data) + data.offset()))
     self.path = parse_path(data.get(count))
     data.pop(len(self.path))
     iof_idx, hof_idx = self.cmn_hdr.get_of_idxs()
     self.path.set_of_idxs(iof_idx, hof_idx)
Example #7
0
 def _parse(self, raw):
     """
     Parses the raw data and populates the fields accordingly.
     """
     data = Raw(raw, self.NAME, self.LEN)
     (types, self.total_len, curr_iof_p, curr_hof_p, self.next_hdr,
      self.hdr_len) = struct.unpack("!HHBBBB", data.pop())
     self.version = types >> 12
     if self.version != SCION_PROTO_VERSION:
         raise SCMPBadVersion("Unsupported SCION version: %s" %
                              self.version)
     self.src_addr_type = (types & 0x0fc0) >> 6
     self.dst_addr_type = types & 0x003f
     self.addrs_len, _ = SCIONAddrHdr.calc_lens(self.src_addr_type,
                                                self.dst_addr_type)
     if self.hdr_len < self.LEN + self.addrs_len:
         # Can't send an SCMP error, as there isn't enough information to
         # parse the path and the l4 header.
         raise SCIONParseError(
             "hdr_len (%sB) < common header len (%sB) + addrs len (%sB)" %
             (self.hdr_len, self.LEN, self.addrs_len))
     first_of_offset = self.LEN + self.addrs_len
     # FIXME(kormat): NB this assumes that all OFs have the same length.
     self._iof_idx = (curr_iof_p - first_of_offset) // OpaqueField.LEN
     self._hof_idx = (curr_hof_p - first_of_offset) // OpaqueField.LEN
Example #8
0
 def _gen_as_certs(self, topo_id, as_conf):
     # Self-signed if cert_issuer is missing.
     issuer = TopoID(as_conf.get('cert_issuer', str(topo_id)))
     # Make sure that issuer is a core AS
     if issuer not in self.pub_online_root_keys:
         raise SCIONParseError("Certificate issuer is not a core AS: %s" % issuer)
     # Create core AS certificate
     if self.is_core(as_conf):
         signing_key = self.priv_online_root_keys[topo_id]
         can_issue = True
         comment = "Core AS Certificate"
         self.core_certs[topo_id] = Certificate.from_values(
             str(topo_id), str(issuer), INITIAL_TRC_VERSION, INITIAL_CERT_VERSION,
             comment, can_issue, DEFAULT_CORE_CERT_VALIDITY, self.enc_pub_keys[topo_id],
             self.pub_core_sig_keys[topo_id], signing_key
         )
     # Create regular AS certificate
     signing_key = self.priv_core_sig_keys[issuer]
     can_issue = False
     comment = "AS Certificate"
     self.certs[topo_id] = Certificate.from_values(
         str(topo_id), str(issuer), INITIAL_TRC_VERSION, INITIAL_CERT_VERSION,
         comment, can_issue, DEFAULT_LEAF_CERT_VALIDITY, self.enc_pub_keys[topo_id],
         self.sig_pub_keys[topo_id], signing_key, issuing_time=int(time.time())+2,
     )
Example #9
0
 def from_raw(cls, raw):
     try:
         p = cls.P_CLS.from_bytes_packed(raw).as_builder()
     except capnp.lib.capnp.KjException as e:
         raise SCIONParseError("Unable to parse %s capnp message: %s" %
                               (cls.NAME, e)) from None
     return cls.from_proto(p)
Example #10
0
 def _parse_pld_ctrl(self, data):
     plen = struct.unpack("!I", data.pop(4))[0]
     if len(data) != plen:
         raise SCIONParseError(
             "Payload length mismatch. Reported: %s Actual: %s" %
             (plen, len(data)))
     return msg_from_raw(data.pop())
Example #11
0
    def __init__(self, trc_dict):
        """
        :param dict trc_dict: TRC as dict.
        """
        for k, (name, type_) in self.FIELDS_MAP.items():
            val = trc_dict[k]
            if type_ in (int, ):
                val = int(val)
            elif type_ in (dict, ):
                val = copy.deepcopy(val)
            setattr(self, name, val)

        for attr, decode_list in self.MULTI_DICT_DECODE_FIELDS.items():
            field = getattr(self, self.FIELDS_MAP[attr][0])
            for entry in field.values():
                for key in decode_list:
                    entry[key] = base64.b64decode(entry[key].encode('utf-8'))

        for attr, decode_list in self.SIMPLE_DICT_DECODE_FIELDS.items():
            entry = getattr(self, self.FIELDS_MAP[attr][0])
            if not entry:
                continue
            for key in decode_list or entry:
                entry[key] = base64.b64decode(entry[key].encode('utf-8'))

        for subject, entry in trc_dict[CERT_LOGS_STRING].items():
            try:
                addr, pub_key = next(iter(entry.items()))
                self.cert_logs[subject][addr] = base64.b64decode(
                    pub_key.encode('utf-8'))
            except StopIteration:
                raise SCIONParseError("Invalid CertLogs entry for %s: %s",
                                      subject, entry)
Example #12
0
def parse_sciond_msg(raw):  # pragma: no cover
    wrapper = P.SCIONDMsg.from_bytes_packed(raw).as_builder()
    type_ = wrapper.which()
    for cls_ in _MSG_TYPES:
        if cls_.MSG_TYPE == type_:
            return cls_(getattr(wrapper, type_), wrapper.id)
    raise SCIONParseError("Unsupported SCIOND message type: %s" % type_)
Example #13
0
 def _parse(self, raw: bytes) -> None:
     try:
         decoded = raw.decode("utf-8")
     except UnicodeDecodeError as e:
         raise SCIONParseError(e) from None
     groups = self.FMT_RE.findall(decoded)
     if not groups:
         raise SCIONParseError("Input does not match pattern. Decoded: %s" %
                               decoded) from None
     try:
         self.ia = ISD_AS(groups[0][0])
     except SCIONParseError as e:
         raise SCIONParseError("Unable to parse IA. Decoded: %s error: %s" %
                               (decoded, e)) from None
     self.chain_ver = int(groups[0][1])
     self.trc_ver = int(groups[0][2])
Example #14
0
 def from_raw(cls, raw):
     assert isinstance(raw, bytes), type(raw)
     try:
         return cls(cls.P_CLS.from_bytes_packed(raw).as_builder())
     except capnp.lib.capnp.KjException as e:
         raise SCIONParseError("Unable to parse %s capnp message: %s" %
                               (cls, e)) from None
Example #15
0
def parse_sciond_msg(raw):  # pragma: no cover
    wrapper = P.SCIONDMsg.from_bytes_packed(raw).as_builder()
    type_ = wrapper.which()
    for cls_ in (SCIONDPathReply, SCIONDPathRequest, SCIONDRevNotification,
                 SCIONDASInfoRequest, SCIONDASInfoReply):
        if cls_.MSG_TYPE == type_:
            return cls_(getattr(wrapper, type_))
    raise SCIONParseError("Unsupported SCIOND message type: %s" % type_)
Example #16
0
def parse_pathmgmt_payload(wrapper):  # pragma: no cover
    type_ = wrapper.which()
    for cls_ in (PathSegmentReq, PathRecordsReply, PathRecordsReg,
                 PathRecordsSync, RevocationInfo, IFStatePayload,
                 IFStateRequest):
        if cls_.PAYLOAD_TYPE == type_:
            return cls_(getattr(wrapper, type_))
    raise SCIONParseError("Unsupported path management type: %s" % type_)
Example #17
0
 def __init__(self, cert_list):
     """
     :param list(Certificate) cert_list: certificate chain as list.
     """
     if len(cert_list) != 2:
         raise SCIONParseError("Certificate chains must have length 2.")
     self.as_cert = cert_list[0]
     self.core_as_cert = cert_list[1]
Example #18
0
 def from_raw_multiple(cls, raw):
     assert isinstance(raw, bytes), type(raw)
     try:
         for p in cls.P_CLS.read_multiple_bytes_packed(raw):
             yield cls(p.as_builder())
     except capnp.lib.capnp.KjException as e:
         raise SCIONParseError("Unable to parse %s capnp message: %s" %
                               (cls, e)) from None
Example #19
0
def parse_pcb_payload(type_, data):  # pragma: no cover
    type_map = {
        PCBType.SEGMENT: PathSegment.from_raw,
    }
    if type_ not in type_map:
        raise SCIONParseError("Unsupported pcb type: %s", type_)
    handler = type_map[type_]
    return handler(data.pop())
Example #20
0
def parse_ifid_payload(type_, data):
    type_map = {
        IFIDType.PAYLOAD: IFIDPayload.from_raw,
    }
    if type_ not in type_map:
        raise SCIONParseError("Unsupported IFID type: %s", type_)
    handler = type_map[type_]
    return handler(data.pop())
Example #21
0
def parse_sibra_payload(type_, data):  # pragma: no cover
    type_map = {
        SIBRAPayloadType.EMPTY: SIBRAPayload,
    }
    if type_ not in type_map:
        raise SCIONParseError("Unsupported sibra payload type: %s", type_)
    handler = type_map[type_]
    return handler.from_raw(data.pop())
Example #22
0
def msg_from_raw(raw):
    try:
        wrapper = P.SCION.from_bytes_packed(raw).as_builder()
    except capnp.lib.capnp.KjException as e:
        raise SCIONParseError(
            "Unable to parse SCION capnp message: %s" % e) from None
    pld_class = wrapper.which()
    class_map = {
        PayloadClass.PCB: parse_pcb_payload,
        PayloadClass.IFID: parse_ifid_payload,
        PayloadClass.CERT: parse_certmgmt_payload,
        PayloadClass.PATH: parse_pathmgmt_payload,
        PayloadClass.SIBRA: parse_sibra_payload,
    }
    handler = class_map.get(pld_class)
    if not handler:
        raise SCIONParseError("Unsupported payload class: %s" % pld_class)
    return handler(getattr(wrapper, pld_class))
Example #23
0
 def parse_payload(self):
     data = Raw(self._payload.pack(), "SCIONL4Packet.parse_payload")
     if not self.l4_hdr:
         raise SCIONParseError("Cannot parse payload of non-L4 packet")
     if self.l4_hdr.TYPE == L4Proto.UDP:
         # Treat as SCION control message
         pld = self._parse_pld_ctrl(data)
     elif self.l4_hdr.TYPE == L4Proto.SCMP:
         pld = self._parse_pld_scmp(data)
     self.set_payload(pld)
     return pld
Example #24
0
 def parse_payload(self):
     if not self.l4_hdr:
         raise SCIONParseError("Cannot parse payload of non-L4 packet")
     praw = self._payload.pack()
     if self.l4_hdr.TYPE == L4Proto.UDP:
         # Treat as SCION control message
         pld = SignedCtrlPayload.from_raw(praw).pld()
     elif self.l4_hdr.TYPE == L4Proto.SCMP:
         pld = SCMPPayload((self.l4_hdr.class_, self.l4_hdr.type, praw))
     self.set_payload(pld)
     return pld
Example #25
0
    def _parse(self, raw):
        """
        Parse IPv6 address

        :param raw: Can be either `bytes` or `str`
        """
        try:
            intf = IPv6Interface(raw)
        except AddressValueError as e:
            raise SCIONParseError("Unable to parse %s address: %s" %
                                  (self.name(), e)) from None
        self.addr = intf.ip
Example #26
0
 def from_proto(cls, p):  # pragma: no cover
     """
     Internal constructor, used by sub-classes to create the corresponding python object from a
     capnp object. The appropriate python class is selected by looking up the union field name in
     CLASS_FIELD_MAP.
     """
     type_ = p.which()
     for cls_, field in cls.CLASS_FIELD_MAP.items():
         if type_ == field:
             return cls._from_union(p, cls_.from_proto(getattr(p, type_)))
     raise SCIONParseError("Unsupported %s proto type: %s" %
                           (cls.NAME, type_))
Example #27
0
def parse_l4_hdr(proto, data, dst=None, src=None):
    if proto == L4Proto.UDP:
        raw_hdr = data.pop(SCIONUDPHeader.LEN)
        assert src
        assert dst
        return SCIONUDPHeader((src, dst, raw_hdr))
    if proto == L4Proto.SCMP:
        raw_hdr = data.pop(SCMPHeader.LEN)
        return SCMPHeader((src, dst, raw_hdr))
    if proto in L4Proto.L4:
        return None
    raise SCIONParseError("Unsupported L4 protocol type: %s" % proto)
Example #28
0
def haddr_parse_interface(intf):
    """
    Try to parse a string as either an ipv6 or ipv4 interface

    :param str interface: E.g. ``127.0.0.1/8``.
    """
    for type_ in AddrType.IPV6, AddrType.IPV4:
        try:
            return haddr_parse(type_, intf)
        except SCIONParseError:
            pass
    else:
        raise SCIONParseError("Unable to parse interface '%s'" % intf)
Example #29
0
 def _parse_hex_as(self, raw, as_sep=HEX_SEPARATOR):
     try:
         as_parts = raw.split(as_sep)
     except ValueError:
         raise SCIONParseError("Unable to parse hex AS from string: %s" %
                               raw) from None
     if len(as_parts) != self.HEX_AS_PARTS:
         raise SCIONParseError(
             "Wrong number of separators (%s) in hex AS number (expected: %d actual: %s): %s"
             % (self.HEX_SEPARATOR, self.HEX_AS_PARTS, as_parts, raw))
     self._as = 0
     for i, s in enumerate(as_parts):
         self._as <<= 16
         v = int(s, base=16)
         if v > self.MAX_HEX_AS_PART:
             raise SCIONParseError(
                 "Hex AS number has part greater than %x: %s" %
                 (self.MAX_HEX_AS_PART, raw))
         self._as |= v
     if self._as > self.MAX_AS:
         raise SCIONParseError("AS too large (max: %d): %s" %
                               (self.MAX_AS, raw))
Example #30
0
 def _parse_pld_ctrl(self, data):
     pld_class = data.pop(1)
     class_map = {
         PayloadClass.PCB: parse_pcb_payload,
         PayloadClass.IFID: parse_ifid_payload,
         PayloadClass.CERT: parse_certmgmt_payload,
         PayloadClass.PATH: parse_pathmgmt_payload,
         PayloadClass.SIBRA: parse_sibra_payload,
     }
     handler = class_map.get(pld_class)
     if not handler:
         raise SCIONParseError("Unsupported payload class: %s" % pld_class)
     return handler(data.pop(1), data)