def process_revocation(self, error, srev_info, meta, pld): rev_info = srev_info.rev_info() status = None if error is None: status = SCIONDRevReplyStatus.VALID self.rev_cache.add(srev_info) self.remove_revoked_segments(rev_info) else: if type(error) == RevInfoValidationError: logging.error("Failed to validate RevInfo %s from %s: %s", srev_info.short_desc(), meta, error) status = SCIONDRevReplyStatus.INVALID if type(error) == RevInfoExpiredError: logging.info("Ignoring expired Revinfo, %s from %s", srev_info.short_desc(), meta) status = SCIONDRevReplyStatus.STALE if type(error) == SignedRevInfoCertFetchError: logging.error("Failed to fetch certificate for SignedRevInfo %s from %s: %s", srev_info.short_desc(), meta, error) status = SCIONDRevReplyStatus.UNKNOWN if type(error) == SignedRevInfoVerificationError: logging.error("Failed to verify SRevInfo %s from %s: %s", srev_info.short_desc(), meta, error) status = SCIONDRevReplyStatus.SIGFAIL if type(error) == SCIONBaseError: logging.error("Revocation check failed for %s from %s:\n%s", srev_info.short_desc(), meta, error) status = SCIONDRevReplyStatus.UNKNOWN if pld: rev_reply = SCIONDMsg(SCIONDRevReply.from_values(status), pld.id) self.send_meta(rev_reply.pack(), meta)
def _api_handle_seg_type_request(self, pld, meta): request = pld.union assert isinstance(request, SCIONDSegTypeHopRequest), type(request) segmentType = request.p.type db = [] if segmentType == PST.CORE: db = self.core_segments elif segmentType == PST.UP: db = self.up_segments elif segmentType == PST.DOWN: db = self.down_segments else: logging.error("Requesting segment type %s unrecognized.", segmentType) seg_entries = [] for segment in db(full=True): if_list = [] for asm in segment.iter_asms(): isd_as = asm.isd_as() hof = asm.pcbm(0).hof() egress = hof.egress_if ingress = hof.ingress_if if ingress: if_list.append(PathInterface.from_values(isd_as, ingress)) if egress: if_list.append(PathInterface.from_values(isd_as, egress)) reply_entry = SCIONDSegTypeHopReplyEntry.from_values( if_list, segment.get_timestamp(), segment.get_expiration_time()) seg_entries.append(reply_entry) seg_reply = SCIONDMsg( SCIONDSegTypeHopReply.from_values(seg_entries), pld.id) self.send_meta(seg_reply.pack(), meta)
def _api_handle_rev_notification(self, pld, meta): request = pld.union assert isinstance(request, SCIONDRevNotification), type(request) status = self.handle_revocation( CtrlPayload(PathMgmt(request.rev_info())), meta) rev_reply = SCIONDMsg(SCIONDRevReply.from_values(status), pld.id) self.send_meta(rev_reply.pack(), meta)
def send_rev_notification(self, srev_info): # pragma: no cover req_id = self._req_id.inc() rev_not = SCIONDMsg(SCIONDRevNotification.from_values(srev_info), req_id) with closing(self._create_socket()) as socket: if not socket.send(rev_not.pack()): raise SCIONDRequestError response = self._get_response(socket, req_id, SMT.REVOCATIONREPLY) return response.p.result return None
def get_segtype_hops(self, seg_type): req_id = self._req_id.inc() valid_pst = set([PST.CORE, PST.UP, PST.DOWN]) assert seg_type in valid_pst, 'PathSegmentType %s is unrecognized.' % seg_type request = SCIONDMsg(SCIONDSegTypeHopRequest.from_values(seg_type), req_id) with closing(self._create_socket()) as socket: if not socket.send(request.pack()): raise SCIONDRequestError response = self._get_response(socket, req_id, SMT.SEGTYPEHOP_REPLY) return list(response.iter_entries())
def _api_handle_as_request(self, pld, meta): request = pld.union assert isinstance(request, SCIONDASInfoRequest), type(request) req_ia = request.isd_as() if not req_ia or req_ia.is_zero() or req_ia == self.addr.isd_as: # Request is for the local AS. reply_entry = SCIONDASInfoReplyEntry.from_values( self.addr.isd_as, self.is_core_as(), self.topology.mtu) else: # Request is for a remote AS. reply_entry = SCIONDASInfoReplyEntry.from_values(req_ia, self.is_core_as(req_ia)) as_reply = SCIONDMsg(SCIONDASInfoReply.from_values([reply_entry]), pld.id) self.send_meta(as_reply.pack(), meta)
def _api_handle_as_request(self, pld, meta): request = pld.union assert isinstance(request, SCIONDASInfoRequest), type(request) remote_as = request.isd_as() if remote_as: reply_entry = SCIONDASInfoReplyEntry.from_values( remote_as, self.is_core_as(remote_as)) else: reply_entry = SCIONDASInfoReplyEntry.from_values( self.addr.isd_as, self.is_core_as(), self.topology.mtu) as_reply = SCIONDMsg(SCIONDASInfoReply.from_values([reply_entry]), pld.id) self.send_meta(as_reply.pack(), meta)
def get_paths(self, dst_ia, src_ia, max_paths, flags=None): if not flags: flags = PathRequestFlags(flush=False, sibra=False) req_id = self._req_id.inc() request = SCIONDMsg(SCIONDPathRequest.from_values( dst_ia, src_ia, max_paths, flags.flush, flags.sibra), req_id) with closing(self._create_socket()) as socket: if not socket.send(request.pack()): raise SCIONDRequestError response = self._get_response(socket, req_id, SMT.PATH_REPLY) if response.p.errorCode != SCIONDPathReplyError.OK: raise SCIONDResponseError( SCIONDPathReplyError.describe(response.p.errorCode)) return list(response.iter_entries())
def _api_handle_if_request(self, pld, meta): request = pld.union assert isinstance(request, SCIONDIFInfoRequest), type(request) all_brs = request.all_brs() if_list = [] if not all_brs: if_list = list(request.iter_ids()) if_entries = [] for if_id, br in self.ifid2br.items(): if all_brs or if_id in if_list: br_addr, br_port = br.int_addrs.public[0] info = HostInfo.from_values([br_addr], br_port) reply_entry = SCIONDIFInfoReplyEntry.from_values(if_id, info) if_entries.append(reply_entry) if_reply = SCIONDMsg(SCIONDIFInfoReply.from_values(if_entries), pld.id) self.send_meta(if_reply.pack(), meta)
def get_as_info(self, isd_as=None): q_ia = isd_as if not q_ia: q_ia = "local" with self._as_infos_lock: _, as_infos = self._try_cache(self._as_infos, [q_ia]) as_info = as_infos.get(q_ia) if as_info: return as_info req_id = self._req_id.inc() as_req = SCIONDMsg(SCIONDASInfoRequest.from_values(isd_as), req_id) with closing(self._create_socket()) as socket: if not socket.send(as_req.pack()): raise SCIONDRequestError response = self._get_response(socket, req_id, SMT.AS_REPLY) self._as_infos[q_ia] = list(response.iter_entries()) return self._as_infos[q_ia]
def _api_handle_service_request(self, pld, meta): request = pld.union assert isinstance(request, SCIONDServiceInfoRequest), type(request) all_svcs = request.all_services() svc_list = [] if not all_svcs: svc_list = list(request.iter_service_types()) svc_entries = [] for svc_type in ServiceType.all(): if all_svcs or svc_type in svc_list: lookup_res = self.dns_query_topo(svc_type) host_infos = [] for addr, port in lookup_res: host_infos.append(HostInfo.from_values([addr], port)) reply_entry = SCIONDServiceInfoReplyEntry.from_values( svc_type, host_infos) svc_entries.append(reply_entry) svc_reply = SCIONDMsg(SCIONDServiceInfoReply.from_values(svc_entries), pld.id) self.send_meta(svc_reply.pack(), meta)
def get_service_info(self, service_types=None): with self._svc_infos_lock: if service_types: service_types, svc_infos = self._try_cache(self._svc_infos, service_types) if not service_types: # The request could be satisfied with cached IF infos. return svc_infos else: svc_infos = {} service_types = set() # Request missing service infos. req_id = self._req_id.inc() svc_req = SCIONDMsg(SCIONDServiceInfoRequest.from_values(service_types), req_id) with closing(self._create_socket()) as socket: if not socket.send(svc_req.pack()): raise SCIONDRequestError response = self._get_response(socket, req_id, SMT.SERVICE_REPLY) for entry in response.iter_entries(): self._svc_infos[entry.service_type()] = entry svc_infos[entry.service_type()] = entry return svc_infos
def get_if_info(self, if_list=None): with self._if_infos_lock: if if_list: if_list, if_infos = self._try_cache(self._if_infos, if_list) if not if_list: # The request could be satisfied with cached IF infos. return if_infos else: if_infos = {} if_list = set() # Request missing IF infos. req_id = self._req_id.inc() if_req = SCIONDMsg(SCIONDIFInfoRequest.from_values(if_list), req_id) with closing(self._create_socket()) as socket: if not socket.send(if_req.pack()): raise SCIONDRequestError response = self._get_response(socket, req_id, SMT.IF_REPLY) for entry in response.iter_entries(): self._if_infos[entry.p.ifID] = entry if_infos[entry.p.ifID] = entry return if_infos
def handle_msg_meta(self, msg, meta): """ Main routine to handle incoming SCION messages. """ if isinstance(meta, SockOnlyMetadata): # From SCIOND API try: sciond_msg = SCIONDMsg.from_raw(msg) except SCIONParseError as err: logging.error(str(err)) return self.api_handle_request(sciond_msg, meta) return super().handle_msg_meta(msg, meta)
def _get_response(self, socket, expected_id, expected_type): # pragma: no cover try: data = socket.recv()[0] except timeout: raise SCIONDResponseError("Socket timed out.") except SCIONIOError: raise SCIONDResponseError("Socket IO error.") if not data: raise SCIONDResponseError("Received empty response from SCIOND.") try: response = SCIONDMsg.from_raw(data) except SCIONParseError as e: raise SCIONDResponseError(str(e)) if response.type() != expected_type: raise SCIONDResponseError( "Unexpected SCIOND msg type received: %s" % response.NAME) if response.id != expected_id: raise SCIONDResponseError("Wrong response ID: %d (expected %d)" % (response.id, expected_id)) return response.union
def send_rev_notification(self, srev_info): # pragma: no cover rev_not = SCIONDMsg(SCIONDRevNotification.from_values(srev_info), self._req_id.inc()) with closing(self._create_socket()) as socket: if not socket.send(rev_not.pack()): raise SCIONDRequestError
def _send_path_reply(self, req_id, reply_entries, error, meta): path_reply = SCIONDMsg(SCIONDPathReply.from_values(reply_entries, error), req_id) self.send_meta(path_reply.pack(), meta)