def update_assign(self, transaction): """ Updates the state for an Assign transaction :param transaction: <dict> An assign transaction """ prefix = transaction['input'][0] as_source = transaction['input'][1] asn_list = transaction['input'][2] ld = transaction['input'][4] tt = transaction['input'][5] last_assign = transaction['txid'] found = 0 for asn in asn_list: for i in range(len(state[prefix])): if asn in state[prefix][i]: found = 1 break if found == 0: state[prefix].append((asn, ld, tt, last_assign)) for i in range(len(state[prefix])): if as_source == state[prefix][i][0]: state[prefix].pop(i) break # the as_source has been removed from the state dict. # also reject the previous topo for this prefix and start a new one. topo_mutex.acquire() topo = AS_topo[prefix] self.clear_topology(topo, prefix, as_source) for AS in asn_list: topo.add_edge(AS, prefix) topo_mutex.release()
def verify_origin(self): """ Verifies the origin of this transaction, based on the topo of this prefix. :return: <Bool> True if the origin is verified. False otherwise. """ topo_mutex.acquire() topo = AS_topo[self.prefix] topo_mutex.release() if len(self.as_source_list) == 0 or not self.check_network(): return False if self.as_source_list[0] == '0' and len(self.as_source_list) == 1: return topo.has_edge(self.as_source, self.prefix) elif self.as_source_list[0] == '0' and len(self.as_source_list) > 1: direct = topo.has_edge(self.as_source, self.prefix) src_l = self.as_source_list[1:] src_l.append(self.prefix) successors = list(topo.successors(self.as_source)) src_l.sort() successors.sort() return direct and src_l == successors else: src_l = self.as_source_list successors = list(topo.successors(self.as_source)) src_l.sort() successors.sort() return src_l == successors
def return_topos(): """ Returns all the topologies of all the prefixes. """ topos = {} topo_mutex.acquire() for prefix in AS_topo.keys(): topos[prefix] = list(AS_topo[prefix].edges) topo_mutex.release() return jsonify(topos), 200
def update_revoke(self, transaction): """ Updates the state for a Revoke transaction :param transaction: <dict> A revoke transaction """ as_source = transaction['input'][0] assign_tran_id = transaction['input'][1] ld = transaction['output'][0][2] tt = transaction['output'][0][-1] assign_tran = self.find_by_txid(assign_tran_id) if assign_tran is not None: tran = assign_tran['trans'] prefix = tran['input'][0] as_dest_list = tran['input'][2] last_assign = tran['input'][-1] for asn in as_dest_list: for i in range(len(state[prefix])): if asn == state[prefix][i][0]: state[prefix].pop(i) # remove the others break # found it! found = 0 for i in range(len(state[prefix])): if as_source in state[prefix][i]: state[prefix].pop(i) state[prefix].append((as_source, ld, tt, last_assign)) # ? found = 1 break if found == 0: state[prefix].append( (as_source, ld, tt, last_assign)) # the one that did the revocation # also restore the topology of this prefix. topo_mutex.acquire() topo = AS_topo[prefix] for AS in as_dest_list: self.clear_topology( topo, prefix, AS) # remove the ASes that no longer own the prefix. topo.add_edge( as_source, prefix ) # add the AS that did the revocation and now owns the prefix. topo_mutex.release()
def update_bgp_announce(self, transaction): """ Updates the topology of a prefix given in an Announce transaction. :param transaction: <dict> A BGP Announce transaction """ prefix = transaction['input'][0] sub_paths = transaction['output'] topo_mutex.acquire() topo = AS_topo[prefix] for path in sub_paths: if path[1] == '0': topo.add_edges_from([(path[2], prefix), (path[3], path[2]) ]) # don't add the 0 node in the graph else: topo.add_edges_from([(path[2], path[1]), (path[3], path[2])]) topo_mutex.release()
def check_loops(self): """ Checks if this transaction introduces loops in the topology of this prefix. :return: <bool> True if there are loops. False otherwise. """ topo_mutex.acquire() old_topo = AS_topo[self.prefix] new_topo = copy.deepcopy(old_topo) self.find_new_topo(new_topo) try: nx.find_cycle(new_topo, source=self.as_source, orientation='original') topo_mutex.release() return True except nx.NetworkXNoCycle: topo_mutex.release() return False
def verify_path(self): """ Checks if there is at least one path from the Withdrawing AS to the prefix. :return: <Bool> True if there's at least one path, False otherwise. """ topo_mutex.acquire() topo = AS_topo[self.prefix] # paths from as_source to prefix. try: paths = nx.all_simple_paths(topo, self.as_source, self.prefix) topo_mutex.release() except nx.NodeNotFound: print("Error: Node not in graph") topo_mutex.release() return False if len(list(paths)) == 0: # no paths found. return False else: return True
def graph_visualization(): """ Creates an image of the graph of the prefix requested. """ values = request.get_json() required = ['prefix'] if not all(k in values for k in required): return 'Missing Values', 400 prefix = values['prefix'] topo_mutex.acquire() try: graph = AS_topo[prefix] graph.nodes[prefix].update(style='filled', fillcolor='lightblue') A = to_agraph(graph) A.layout('dot') prefix = prefix.replace('/', '+') A.draw('graph_for_' + prefix + '.png') topo_mutex.release() except KeyError: topo_mutex.release() return 'The prefix does not exists', 400 return 'Check your folder for a pic of the graph', 200
def update_bgp_withdraw(self, transaction): """ Updates the topology of a prefix after a Withdraw transaction. :param transaction: <dict> A BGP Withdraw transaction. """ redundant_nodes = set() prefix = transaction['input'][0] as_source = transaction['input'][1] topo_mutex.acquire() topo = AS_topo[prefix] # remove the edges between the withdrawing node and its predecessors. pred_edges = [] for pred in topo.predecessors(as_source): pred_edges.append((pred, as_source)) topo.remove_edges_from(pred_edges) # find all the other nodes that cannot reach the prefix. for node in topo.nodes: paths = nx.all_simple_paths(topo, node, prefix) if len(list(paths)) == 0 and node != prefix: redundant_nodes.add( node) # these nodes cannot reach the prefix. topo.remove_nodes_from(redundant_nodes) topo_mutex.release()