Skip to content

Commit

Permalink
Merge pull request #27 from wlanslovenija/rogue-node-detection
Browse files Browse the repository at this point in the history
Rogue node detection.
  • Loading branch information
mitar committed Aug 21, 2016
2 parents ae64278 + 49d9037 commit 672b8a2
Show file tree
Hide file tree
Showing 20 changed files with 12,322 additions and 58 deletions.
Empty file.
Empty file.
38 changes: 38 additions & 0 deletions nodewatcher/modules/analysis/rogue_nodes/algorithm.py
@@ -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.
39 changes: 39 additions & 0 deletions nodewatcher/modules/analysis/rogue_nodes/tasks.py
@@ -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.

0 comments on commit 672b8a2

Please sign in to comment.