Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #27 from wlanslovenija/rogue-node-detection
Rogue node detection.
- Loading branch information
Showing
20 changed files
with
12,322 additions
and
58 deletions.
There are no files selected for viewing
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import networkx as nx | ||
|
||
|
||
def rogue_node_detection_algorithm(graph, friendly_nodes): | ||
""" | ||
Detects rogue nodes and outputs an array of detected rogue nodes in the graph. The algorithm first creates a | ||
minimum spanning tree of the graph and then computes the probability of a node being rogue from | ||
the number of edges that node has in a MST. The algorithm takes at most O(E log(V)) time. | ||
:param graph: A graph datastructure which contains both friendly and unknown nodes. | ||
:param friendly_nodes: An array of nodes that are monitored by nodewatcher and are considered friendly. | ||
:return: An array of all unknown nodes with an associated probability of being a rogue node. | ||
""" | ||
|
||
nx_graph = nx.Graph() | ||
nx_graph.add_nodes_from([(node['i'], {'b': node['b']}) if 'b' in node else node['i'] for node in graph['v']]) | ||
nx_graph.add_edges_from([(edge['f'], edge['t'], { | ||
's': -1 * edge['s'], | ||
'c': edge['c'], | ||
'n': edge['n'], | ||
}) for edge in graph['e']]) | ||
|
||
# Create a MST with Kruskal's | ||
mst = nx.minimum_spanning_tree(nx_graph, weight='s') | ||
|
||
unknown_nodes = [] | ||
for node_name in mst.node: | ||
if node_name not in friendly_nodes: | ||
node_probability = min((mst.degree(node_name) - 1) / 2.0, 1) | ||
ssids = set() | ||
for edge in mst.edges(node_name, data=True): | ||
ssids.add(edge[2]['n']) | ||
unknown_nodes.append({ | ||
'name': node_name, | ||
'probability_being_rogue': node_probability, | ||
'ssids': list(ssids), | ||
}) | ||
return unknown_nodes |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import datetime | ||
|
||
from django.core import mail | ||
|
||
from nodewatcher import celery | ||
|
||
from . import algorithm | ||
from ...monitor.http.survey import extract_nodes | ||
|
||
|
||
# Register the periodic schedule. | ||
celery.app.conf.CELERYBEAT_SCHEDULE['nodewatcher.modules.analysis.rogue_nodes.tasks.rogue_node_detection'] = { | ||
'task': 'nodewatcher.modules.analysis.rogue_nodes.tasks.rogue_node_detection', | ||
'schedule': datetime.timedelta(days=1), | ||
} | ||
|
||
|
||
@celery.app.task(queue='monitor', bind=True) | ||
def rogue_node_detection(self): | ||
""" | ||
Detects rogues nodes and issues a warning to its neighbors that are monitored by nodewatcher. | ||
""" | ||
|
||
extracted_graph = extract_nodes.all_nodes_survey_graph(datetime.datetime.utcnow()) | ||
|
||
if not extracted_graph: | ||
return | ||
|
||
# Run the algorithm on the meta graph. | ||
unknown_node_list = algorithm.rogue_node_detection_algorithm(extracted_graph['graph'], extracted_graph['known_nodes']) | ||
|
||
rogue_node_list = filter(lambda unknown_node: unknown_node['probability_being_rogue'] > 0.9, unknown_node_list) | ||
|
||
if rogue_node_list: | ||
# TODO: Replace sending of e-mails with network-wide notifications/warnings. | ||
mail.mail_admins( | ||
subject="Rogue nodes detected", | ||
message="We detected the following rogue nodes: {0}".format(rogue_node_list), | ||
) |
Empty file.
Oops, something went wrong.