def _parse_bytes(self, raw): """ :param bytes raw: a byte string containing a 64-bit unsigned integer. """ data = Raw(raw, self.NAME, self.LEN) isd_as = struct.unpack("!Q", data.pop())[0] self._parse_int(isd_as)
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
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
def _parse(self, raw): """ Parses raw bytes and populates the fields. """ data = Raw(raw, self.NAME) self.if_id, self.hash_chain_idx = struct.unpack("!II", data.pop(8)) self.rev_info = RevocationInfo.from_raw(data.pop())
def _check(self, count, start_off, expected): # Setup r = Raw(b"data") r._offset = start_off # Call data = r.get(count) # Tests ntools.eq_(data, expected)
def _parse(self, raw): data = Raw(raw, self.NAME, self.LEN) flags, self.exp_time = struct.unpack("!BB", data.pop(2)) self._parse_flags(flags) ifs = int.from_bytes(data.pop(3), byteorder="big") self.ingress_if = (ifs & 0xFFF000) >> 12 self.egress_if = ifs & 0x000FFF self.mac = data.pop(3)
def _parse(self, raw): """ Parse SVC address :param bytes raw: Raw SVC address """ data = Raw(raw, self.NAME, self.LEN) self.addr = struct.unpack("!H", data.pop(self.LEN))[0]
def _parse(self, raw): data = Raw(raw, self.NAME, self.MIN_LEN, min_=True) self.info = self.RESVINFO(data.pop(self.RESVINFO.LEN)) self.num_hops = len(data) // SibraOpaqueField.LEN while data: raw_sof = data.pop(SibraOpaqueField.LEN) if raw_sof == bytes(SibraOpaqueField.LEN): break self.sofs.append(SibraOpaqueField(raw_sof))
def _parse_bytes(self, raw): """ :param bytes raw: a byte string containing ISD ID, AS ID. ISD and AS are respectively represented as 12 and 20 most significant bits. """ data = Raw(raw, self.NAME, self.LEN) isd_as = cast(int, struct.unpack("!I", data.pop())[0]) self._parse_int(isd_as)
def _check(self, pop, start_off, end_off, get): # Setup r = Raw(b"data") r._offset = start_off # Call r.pop(pop) # Tests get.assert_called_once_with(r, pop, True) ntools.eq_(r._offset, end_off)
def _parse(self, raw): data = Raw(raw, self.NAME, self.MIN_LEN, min_=True) src_type = data.pop(1) dst_type = data.pop(1) self.src = SCIONAddr((src_type, data.get())) data.pop(len(self.src)) self.dst = SCIONAddr((dst_type, data.get())) data.pop(len(self.dst)) padding_len = len(data) % OpaqueField.LEN self.path = parse_path(data.pop(len(data) - padding_len))
def _parse(self, raw): """ Parse byte string representation :param raw: Byte string representing interface info :type raw: bytes object """ data = Raw(raw, self.NAME, self.LEN) self.isd_as = ISD_AS(data.pop(ISD_AS.LEN)) self.ifid = struct.unpack("!H", data.pop())[0]
def _parse(self, raw): """ Parse payload to extract values :param bytes raw: Raw payload """ super()._parse(raw) data = Raw(raw, self.NAME, self.LEN) self.is_ack = bool(data.pop(1)) self.probe_id = struct.unpack("!I", data.pop(4))[0]
def _parse(self, raw): """ Parse payload to extract values. :param bytes raw: raw payload. """ data = Raw(raw, self.NAME) super()._parse(data) self.sec_mode = data.pop(SPSELengths.SECMODE) self.metadata = data.pop(SPSELengths.META[self.sec_mode]) self.authenticator = data.pop(SPSELengths.AUTH[self.sec_mode])
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)
def _parse_start(self, raw): """ Parse the first line of the extension header, which is common between steady and ephemeral reservations. """ super()._parse(raw) data = Raw(raw, self.NAME, self.MIN_LEN, min_=True) req = self._parse_flags(data.pop(1)) self.sof_idx = data.pop(1) self.path_lens = list(struct.unpack("!BBB", data.pop(3))) self._calc_total_hops() return data, req
def _parse(self, addr_type, raw): """ Parse a raw byte string. :param int addr_type: Host address type :param bytes raw: raw bytes. """ haddr_type = haddr_get_type(addr_type) addr_len = ISD_AS.LEN + haddr_type.LEN data = Raw(raw, "SCIONAddr", addr_len, min_=True) self.isd_as = ISD_AS(data.pop(ISD_AS.LEN)) self.host = haddr_type(data.pop(haddr_type.LEN))
def _parse(self, dst_type, src_type, raw): data = Raw(raw, self.NAME, self.calc_lens(dst_type, src_type)[0]) dst_ia = ISD_AS(data.pop(ISD_AS.LEN)) src_ia = ISD_AS(data.pop(ISD_AS.LEN)) dst_addr_t = haddr_get_type(dst_type) dst_addr = dst_addr_t(data.pop(dst_addr_t.LEN)) self.dst = SCIONAddr.from_values(dst_ia, dst_addr) src_addr_t = haddr_get_type(src_type) src_addr = src_addr_t(data.pop(src_addr_t.LEN)) self.src = SCIONAddr.from_values(src_ia, src_addr) self.update() if self.src.host.TYPE == AddrType.SVC: raise SCMPBadSrcType("Invalid source type: SVC")
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 _parse(self, src_type, dst_type, raw): data = Raw(raw, self.NAME, self.calc_lens(src_type, dst_type)[0]) self.src = SCIONAddr((src_type, data.get())) data.pop(len(self.src)) self.dst = SCIONAddr((dst_type, data.get())) data.pop(len(self.dst)) self.update() if self.src.host.TYPE == AddrType.SVC: raise SCMPBadSrcType("Invalid source type: SVC")
def _parse(self, raw): """ Parse payload to extract values. :param bytes raw: raw payload. """ data = Raw(raw, self.NAME) super()._parse(data) self.sec_mode = data.pop(SPSELengths.SECMODE) self.height = data.pop(SCMPAuthHashtreeLengths.HEIGHT) data.pop(SCMPAuthHashtreeLengths.RESERVED) self.order = data.pop(SCMPAuthHashtreeLengths.ORDER) self.signature = data.pop(SCMPAuthHashtreeLengths.SIGNATURE) self.hashes = data.pop(self.height * SCMPAuthHashtreeLengths.HASH)
def _parse(self, class_, type_, raw): data = Raw(raw, self.NAME) (info_len, cmn_hdr_len, addrs_len, path_len, exts_len, l4_len, self.l4_proto) = struct.unpack(self.STRUCT_FMT, data.pop(self.META_LEN)) self.info = parse_scmp_info(class_, type_, data.pop(info_len * LINE_LEN)) self._cmn_hdr = data.pop(cmn_hdr_len * LINE_LEN) self._addrs = data.pop(addrs_len * LINE_LEN) self._path = data.pop(path_len * LINE_LEN) self._exts = data.pop(exts_len * LINE_LEN) self._l4_hdr = data.pop(l4_len * LINE_LEN)
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
def _parse(self, raw): data = Raw(raw, self.NAME, self.LEN) self.exp_tick = struct.unpack("!I", data.pop(4))[0] self.bw = BWClass(data.pop(1), data.pop(1)) index_flags = data.pop(1) self.fwd_dir = bool((index_flags >> 3) & 1) self.index = index_flags >> 4 # FIXME(kormat): needs error handling assert self.index < SIBRA_MAX_IDX self.fail_hop = data.pop(1)
def _parse(self, raw): """ Parse payload to extract values. :param bytes raw: raw payload. """ data = Raw(raw, self.NAME) super()._parse(data) self.sec_mode = data.pop(SPSELengths.SECMODE) self.direction = data.pop(SCMPAuthDRKeyLengths.DIRECTION) data.pop(SCMPAuthDRKeyLengths.PADDING) self.mac = data.pop(SCMPAuthDRKeyLengths.MAC)
def _parse(self, raw): """ Parse serialized stats data :param raw: Serialized stats data :type raw: bytes object """ data = Raw(raw, "Serialized SCION stats", self.FIXED_DATA_LEN, True) while len(data): values = data.pop(self.FIXED_DATA_LEN) # The stats are native byte order rp, sp, ap, rtt, lr, ifc = struct.unpack("IIIIdI", values) self.received_packets.append(rp) self.sent_packets.append(sp) self.acked_packets.append(ap) self.rtts.append(rtt) self.loss_rates.append(lr) self.if_counts.append(ifc) if ifc: if_list = [] for j in range(ifc): saddr = SCIONInterface(data.pop(ISD_AS.LEN + 2)) if_list.append(saddr) self.if_lists.append(if_list)
def _parse(self, raw): data = Raw(raw, self.NAME) if data: # Parse first segment a_iof = self._parse_iof(data, self.A_IOF) self._parse_hofs(data, self.A_HOFS, a_iof.hops) if data: # Parse second segment b_iof = self._parse_iof(data, self.B_IOF) self._parse_hofs(data, self.B_HOFS, b_iof.hops) if data: # Parse third segment assert not a_iof.shortcut c_iof = self._parse_iof(data, self.C_IOF) self._parse_hofs(data, self.C_HOFS, c_iof.hops) self._init_of_idxs()
def _try_sciond_api(self): sock = ReliableSocket() msg = b'\x00' + self.dst.isd_as.pack() start = time.time() try: sock.connect(self.sd.api_addr) except OSError as e: logging.critical("Error connecting to sciond: %s", e) kill_self() while time.time() - start < API_TOUT: logging.debug("Sending path request to local API at %s", self.sd.api_addr) sock.send(msg) data = Raw(sock.recv()[0], "Path response") if data: sock.close() return data logging.debug("Empty response from local api.") logging.critical("Unable to get path from local api.") sock.close() kill_self()
def _parse(self, raw): """ Parse payload to extract hop informations. """ hops_no = raw[0] data = Raw(raw, self.NAME, self.MIN_LEN + hops_no * self.HOP_LEN, min_=True) super()._parse(data) # Drop hops no and padding from the first row. data.pop(self.MIN_LEN) for _ in range(hops_no): isd_as = ISD_AS(data.pop(ISD_AS.LEN)) # 4 bytes if_id, timestamp = struct.unpack( "!HH", data.pop(self.HOP_LEN - ISD_AS.LEN)) self.append_hop(isd_as, if_id, timestamp)
def _parse(self, raw): # pragma: no cover data = Raw(raw, self.NAME, self.LEN) flags, self.timestamp, self.isd, self.hops = \ struct.unpack("!BIHB", data.pop(self.LEN)) self._parse_flags(flags)