-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmonitor.py
126 lines (102 loc) · 4.84 KB
/
monitor.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER, DEAD_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.lib import hub
import predictor
import controller
from datetime import datetime
import pandas as pd
from parameters import *
from flow_inspector import ml_flow
from detector import flow_labeller
from ml_models import get_model, ML_Model
class SimpleMonitor13(controller.SimpleSwitch13):
def __init__(self, *args, **kwargs):
super(SimpleMonitor13, self).__init__(*args, **kwargs)
self.datapaths = {}
self.monitor_thread = hub.spawn(self._monitor)
@set_ev_cls(ofp_event.EventOFPStateChange,
[MAIN_DISPATCHER, DEAD_DISPATCHER])
def _state_change_handler(self, ev):
datapath = ev.datapath
if ev.state == MAIN_DISPATCHER:
if datapath.id not in self.datapaths:
self.logger.debug('register datapath: %016x', datapath.id)
self.datapaths[datapath.id] = datapath
elif ev.state == DEAD_DISPATCHER:
if datapath.id in self.datapaths:
self.logger.debug('unregister datapath: %016x', datapath.id)
del self.datapaths[datapath.id]
## TODO remove flowlar uzerinden ML calistirip kac tane flowun suspected oldugunu bulup sonrasinda stat cekmek daha mantikli olabilir
## Eger remove flowlarda suspected var ise stat cekmek mantikli olabilir
def _monitor(self):
while True:
if predictor.LOW_RATE_FLAG:
for dp in self.datapaths.values():
## TODO eger capacity cok yuksek degilse mitigation icin 3 stat daha beklenir burada capacity kontrol bir daha yapalim stat atmadan once eger azsa biraz bekleyelim
self._request_stats(dp)
if predictor.HIGH_RATE_FLAG:
for dp in self.datapaths.values():
# TODO no need to request stats in high rate, at first drop the newly appended flows
self._request_stats(dp)
predictor.LOW_RATE_FLAG = False
predictor.LOW_RATE_FLAG = False
hub.sleep(5)
def _request_stats(self, datapath):
self.logger.debug('send stats request: %016x', datapath.id)
parser = datapath.ofproto_parser
req = parser.OFPFlowStatsRequest(datapath)
datapath.send_msg(req)
def predict(self, model_type, flow_table):
model = get_model(model_type, flow_table, False)
# predict_test_data_individually(model, )
return model
@set_ev_cls(ofp_event.EventOFPFlowStatsReply, MAIN_DISPATCHER)
def _flow_stats_reply_handler(self, ev):
timestamp = datetime.now()
body = ev.msg.body
datapath = ev.msg.datapath
icmp_code = -1
icmp_type = -1
tp_src = 0
tp_dst = 0
flow_list = []
## store the flows in the body in a dataframe
flow_rules = pd.DataFrame(columns=['ipv4_src','ipv4_dst','port_src','port_dst','ip_proto', 'cookie', 'duration_sec', 'byte_count', 'packet_count'])
for stat in body:
match = controller.format_match(stat.match)
if ( match == {} or 'ip_proto' not in match ):
continue
ip_src = match['ipv4_src']
ip_dst = match['ipv4_dst']
ip_proto = match['ip_proto']
if stat.match['ip_proto'] == 1:
icmp_code =match['icmpv4_code']
icmp_type = match['icmpv4_type']
elif stat.match['ip_proto'] == 6:
tp_src = match['tcp_src']
tp_dst = match['tcp_dst']
elif stat.match['ip_proto'] == 17:
tp_src = match['udp_src']
tp_dst = match['udp_dst']
row = pd.Series([ip_src, ip_dst, tp_src, tp_dst, ip_proto, stat.cookie, stat.duration_sec, stat.byte_count, stat.packet_count], index=flow_rules.columns)
flow_rules.loc[len(flow_rules)] = row
flow_ml = ml_flow(flow_rules)
flow_ml['is_attack'] = 0
## get the suspected flows
# flow_rules = flow_labeller(flow_rules)
# suspected_flows = flow_rules[flow_rules['label'] == 1]
switch = self.switch_list[ev.msg.datapath.id]
# switch has the history batches of flow statistics get the related columns and compare it with current flow to understand whether it is suspected or not
related_batch = switch.get_related_batch(num_of_batch=5)
removed_flow_average_duration = related_batch['removed_flow_average_duration'].mean()
removed_flow_byte_per_packet = related_batch['removed_flow_byte_per_packet'].mean() # the second important feature to distunguish mice and elephant
removed_average_byte_per_sec = related_batch['removed_average_byte_per_sec'].mean() # the most important to distunguish
self.predict(ML_Model.KNN, flow_ml)
for index, flow in flow_ml.iterrows():
if flow['bps'] < BYTE_PER_SEC_BLACK_LIST * removed_average_byte_per_sec and flow['bpp'] < BYTE_PER_PACKET_BLACK_LIST * removed_flow_byte_per_packet:
self.add_banned_list(flow)
# self.drop_flow(datapath, flow['cookie'])
# self.block_ip(datapath, flow['ipv4_src'] )
if flow['bps'] > 2 * removed_average_byte_per_sec:
self.add_white_list(flow)