def handle_ifid_packet(self, pld, meta): """ Update the interface state for the corresponding interface. :param pld: The IFIDPayload. :type pld: IFIDPayload """ ifid = pld.p.relayIF with self.ifid_state_lock: if ifid not in self.ifid_state: raise SCIONKeyError("Invalid IF %d in IFIDPayload" % ifid) br = self.ifid2br[ifid] br.interfaces[ifid].to_if_id = pld.p.origIF prev_state = self.ifid_state[ifid].update() if prev_state == InterfaceState.INACTIVE: logging.info("IF %d activated", ifid) elif prev_state in [ InterfaceState.TIMED_OUT, InterfaceState.REVOKED ]: logging.info("IF %d came back up.", ifid) if not prev_state == InterfaceState.ACTIVE: if self.zk.have_lock(): # Inform BRs about the interface coming up. state_info = IFStateInfo.from_values( ifid, True, self._get_ht_proof(ifid)) pld = IFStatePayload.from_values([state_info]) for br in self.topology.border_routers: br_addr, br_port = br.int_addrs[0].public[0] meta = UDPMetadata.from_values(host=br_addr, port=br_port) self.send_meta(pld.copy(), meta, (br_addr, br_port))
def _handle_ifstate_request(self, req, meta): # Only master replies to ifstate requests. if not self.zk.have_lock(): return assert isinstance(req, IFStateRequest) infos = [] with self.ifid_state_lock: if req.p.ifID == IFStateRequest.ALL_INTERFACES: ifid_states = self.ifid_state.items() elif req.p.ifID in self.ifid_state: ifid_states = [(req.p.ifID, self.ifid_state[req.p.ifID])] else: logging.error( "Received ifstate request from %s for unknown " "interface %s.", meta, req.p.ifID) return for (ifid, state) in ifid_states: # Don't include inactive interfaces in response. if state.is_inactive(): continue info = IFStateInfo.from_values(ifid, state.is_active(), self._get_ht_proof(ifid)) infos.append(info) if not infos and not self._quiet_startup(): logging.warning("No IF state info to put in response. Req: %s" % req.short_desc()) return payload = IFStatePayload.from_values(infos) self.send_meta(payload, meta, (meta.host, meta.port))
def _handle_ifstate_request(self, cpld, meta): # Only master replies to ifstate requests. pmgt = cpld.union req = pmgt.union assert isinstance(req, IFStateRequest), type(req) if not self.zk.have_lock(): return with self.ifid_state_lock: infos = [] for (ifid, state) in self.ifid_state.items(): # Don't include inactive interfaces in update. if state.is_inactive(): continue srev_info = None if state.is_revoked(): srev_info = self.if_revocations.get(ifid, None) if not srev_info: logging.warning( "No revocation in cache for revoked IFID: %s", ifid) continue infos.append( IFStateInfo.from_values(ifid, state.is_active(), srev_info)) if not infos and not self._quiet_startup(): logging.warning( "No IF state info to put in IFState update for %s.", meta) return self._send_ifstate_update(infos, [meta])
def _handle_ifstate_request(self, mgmt_pkt): # Only master replies to ifstate requests. if not self.zk.have_lock(): return req = mgmt_pkt.get_payload() assert isinstance(req, IFStateRequest) logging.debug("Received ifstate req:\n%s", mgmt_pkt) infos = [] if req.p.ifID == IFStateRequest.ALL_INTERFACES: ifid_states = self.ifid_state.items() elif req.p.ifID in self.ifid_state: ifid_states = [(req.p.ifID, self.ifid_state[req.p.ifID])] else: logging.error( "Received ifstate request from %s for unknown " "interface %s.", mgmt_pkt.addrs.src, req.p.ifID) return for (ifid, state) in ifid_states: # Don't include inactive interfaces in response. if state.is_inactive(): continue chain = self._get_if_hash_chain(ifid) info = IFStateInfo.from_values(ifid, state.is_active(), chain.next_element()) infos.append(info) if not infos and not self._quiet_startup(): logging.warning("No IF state info to put in response.") return payload = IFStatePayload.from_values(infos) state_pkt = self._build_packet(mgmt_pkt.addrs.src.host, payload=payload) self.send(state_pkt, mgmt_pkt.addrs.src.host)
def handle_ifid_packet(self, cpld, meta): """ Update the interface state for the corresponding interface. :param pld: The IFIDPayload. :type pld: IFIDPayload """ pld = cpld.union assert isinstance(pld, IFIDPayload), type(pld) ifid = meta.pkt.path.get_hof().ingress_if with self.ifid_state_lock: if ifid not in self.ifid_state: raise SCIONKeyError("Invalid IF %d in IFIDPayload" % ifid) br = self.ifid2br[ifid] br.interfaces[ifid].to_if_id = pld.p.origIF prev_state = self.ifid_state[ifid].update() if prev_state == InterfaceState.INACTIVE: logging.info("IF %d activated.", ifid) elif prev_state in [ InterfaceState.TIMED_OUT, InterfaceState.REVOKED ]: logging.info("IF %d came back up.", ifid) if prev_state != InterfaceState.ACTIVE: if self.zk.have_lock(): # Inform BRs about the interface coming up. metas = [] for br in self.topology.border_routers: br_addr, br_port = br.ctrl_addrs.public metas.append( UDPMetadata.from_values(host=br_addr, port=br_port)) info = IFStateInfo.from_values(ifid, True) self._send_ifstate_update([info], metas)
def handle_ifid_packet(self, pkt): """ Update the interface state for the corresponding interface. :param ipkt: The IFIDPayload. :type ipkt: IFIDPayload """ payload = pkt.get_payload() ifid = payload.p.relayIF if ifid not in self.ifid_state: raise SCIONKeyError("Invalid IF %d in IFIDPayload" % ifid) er = self.ifid2er[ifid] er.interface.to_if_id = payload.p.origIF prev_state = self.ifid_state[ifid].update() if prev_state == InterfaceState.INACTIVE: logging.info("IF %d activated", ifid) elif prev_state in [InterfaceState.TIMED_OUT, InterfaceState.REVOKED]: logging.info("IF %d came back up.", ifid) if not prev_state == InterfaceState.ACTIVE: if self.zk.have_lock(): # Inform ERs about the interface coming up. chain = self._get_if_hash_chain(ifid) if chain is None: return state_info = IFStateInfo.from_values(ifid, True, chain.current_element()) pld = IFStatePayload.from_values([state_info]) mgmt_packet = self._build_packet() for er in self.topology.get_all_edge_routers(): if er.interface.if_id != ifid: mgmt_packet.addrs.dst.host = er.addr mgmt_packet.set_payload(pld.copy()) self.send(mgmt_packet, er.addr)
def _issue_revocation(self, if_id, chain): """ Store a RevocationObject in ZK and send a revocation to all ERs. :param if_id: The interface that needs to be revoked. :type if_id: int :param chain: The hash chain corresponding to if_id. :type chain: :class:`lib.crypto.hash_chain.HashChain` """ # Only the master BS issues revocations. if not self.zk.have_lock(): return rev_info = RevocationInfo.from_values(chain.next_element()) logging.info("Storing revocation in ZK.") rev_obj = RevocationObject.from_values(if_id, chain.current_index(), chain.next_element()) entry_name = "%s:%s" % (chain.start_element(hex_=True), chain.next_element(hex_=True)) self.revobjs_cache.store(entry_name, rev_obj.pack()) logging.info("Issuing revocation for IF %d.", if_id) # Issue revocation to all ERs. info = IFStateInfo.from_values(if_id, False, chain.next_element()) pld = IFStatePayload.from_values([info]) state_pkt = self._build_packet() for er in self.topology.get_all_edge_routers(): state_pkt.addrs.dst.host = er.addr state_pkt.set_payload(pld.copy()) self.send(state_pkt, er.addr) self._process_revocation(rev_info, if_id)
def _issue_revocations(self, revoked_ifs): """ Store a RevocationInfo in ZK and send a revocation to all BRs. :param list revoked_ifs: A list of interfaces that needs to be revoked. """ # Only the master BS issues revocations. if not self.zk.have_lock(): return # Process revoked interfaces. infos = [] for if_id in revoked_ifs: rev_info = self._get_ht_proof(if_id) logging.info("Issuing revocation: %s", rev_info.short_desc()) if self._labels: REVOCATIONS_ISSUED.labels(**self._labels).inc() self._process_revocation(rev_info) infos.append(IFStateInfo.from_values(if_id, False, rev_info)) border_metas = [] # Add all BRs. for br in self.topology.border_routers: br_addr, br_port = br.int_addrs[0].public[0] border_metas.append( UDPMetadata.from_values(host=br_addr, port=br_port)) # Add local path server. ps_meta = [] if self.topology.path_servers: try: addr, port = self.dns_query_topo(PATH_SERVICE)[0] except SCIONServiceLookupError: addr, port = None, None # Create a meta if there is a local path service if addr: ps_meta.append(UDPMetadata.from_values(host=addr, port=port)) self._send_ifstate_update(infos, border_metas, ps_meta)
def _issue_revocations(self, revoked_ifs): """ Store a RevocationInfo in ZK and send a revocation to all BRs. :param list revoked_ifs: A list of interfaces that needs to be revoked. """ # Only the master BS issues revocations. if not self.zk.have_lock(): return # Process revoked interfaces. infos = [] for if_id in revoked_ifs: br = self.ifid2br[if_id] rev_info = RevocationInfo.from_values( self.addr.isd_as, if_id, br.interfaces[if_id].link_type, int(time.time()), self.REVOCATION_TTL) logging.info("Issuing revocation: %s", rev_info.short_desc()) if self._labels: REVOCATIONS_ISSUED.labels(**self._labels).inc() chain = self._get_my_cert() _, cert_ver = chain.get_leaf_isd_as_ver() src = DefaultSignSrc.from_values( rev_info.isd_as(), cert_ver, self._get_my_trc().version).pack() srev_info = SignedRevInfo.from_values(rev_info.copy().pack(), ProtoSignType.ED25519, src) srev_info.sign(self.signing_key) # Add to revocation cache self.if_revocations[if_id] = srev_info self._process_revocation(srev_info) infos.append(IFStateInfo.from_values(if_id, False, srev_info)) border_metas = [] # Add all BRs. for br in self.topology.border_routers: br_addr, br_port = br.int_addrs.public[0] border_metas.append( UDPMetadata.from_values(host=br_addr, port=br_port)) # Add local path server. ps_meta = [] if self.topology.path_servers: try: addr, port = self.dns_query_topo(ServiceType.PS)[0] except SCIONServiceLookupError: addr, port = None, None # Create a meta if there is a local path service if addr: ps_meta.append(UDPMetadata.from_values(host=addr, port=port)) self._send_ifstate_update(infos, border_metas, ps_meta)
def process_path_mgmt_packet(self, mgmt_pkt, from_local_as): """ Process path management packets. :param mgmt_pkt: The path mgmt packet. :type mgmt_pkt: :class:`lib.packet.path_mgmt.PathMgmtPacket` :param bool from_local_as: whether or not the packet is from the local AS. """ payload = mgmt_pkt.get_payload() if payload.PAYLOAD_TYPE == PMT.IFSTATE_INFOS: # handle state update logging.debug("Received IFState update:\n%s", str(mgmt_pkt.get_payload())) for p in payload.p.infos: self.if_states[p.ifID].update(IFStateInfo(p)) return self.handle_data(mgmt_pkt, from_local_as)
def _send_ifstate_update(self, border_metas, server_metas=None): server_metas = server_metas or [] with self.ifid_state_lock: infos = [] for (ifid, state) in self.ifid_state.items(): # Don't include inactive interfaces in update. if state.is_inactive(): continue rev_info = self._get_ht_proof(ifid) if state.is_revoked() else None info = IFStateInfo.from_values(ifid, state.is_active(), rev_info) infos.append(info) if not infos and not self._quiet_startup(): logging.warning("No IF state info to put in IFState update for %s.", ", ".join([str(m) for m in border_metas + server_metas])) return payload = IFStatePayload.from_values(infos) for meta in border_metas: self.send_meta(payload.copy(), meta, (meta.host, meta.port)) for meta in server_metas: self.send_meta(payload.copy(), meta)
def _issue_revocation(self, if_id): """ Store a RevocationInfo in ZK and send a revocation to all BRs. :param if_id: The interface that needs to be revoked. :type if_id: int """ # Only the master BS issues revocations. if not self.zk.have_lock(): return rev_info = self._get_ht_proof(if_id) logging.error("Issuing revocation for IF %d.", if_id) # Issue revocation to all BRs. info = IFStateInfo.from_values(if_id, False, rev_info) pld = IFStatePayload.from_values([info]) for br in self.topology.get_all_border_routers(): meta = UDPMetadata.from_values(host=br.addr, port=br.port) self.send_meta(pld.copy(), meta, (br.addr, br.port)) self._process_revocation(rev_info) self._send_rev_to_local_ps(rev_info)
def _issue_revocation(self, if_id): """ Store a RevocationInfo in ZK and send a revocation to all BRs. :param if_id: The interface that needs to be revoked. :type if_id: int """ # Only the master BS issues revocations. if not self.zk.have_lock(): return rev_info = self._get_ht_proof(if_id) logging.info("Issuing revocation: %s", rev_info.short_desc()) if self._labels: REVOCATIONS_ISSUED.labels(**self._labels).inc() # Issue revocation to all BRs. info = IFStateInfo.from_values(if_id, False, rev_info) pld = IFStatePayload.from_values([info]) for br in self.topology.border_routers: br_addr, br_port = br.int_addrs[0].public[0] meta = UDPMetadata.from_values(host=br_addr, port=br_port) self.send_meta(pld.copy(), meta, (br_addr, br_port)) self._process_revocation(rev_info) self._send_rev_to_local_ps(rev_info)