Hello everyone , Myself harsh , working on botnet detection using ryu and
ML. I am able to detect botnet traffic using various features , linke
src_ip , tp-src, dst-ip , tp-dst, duration .... , I need in help in
mitigation where when we identify the botnet traffic we must drop the flow
or drop all those packets , so is there any way of thing it ? detection
code is pasted below , and thankyou in advance !!!!!!!!
####################swith code###################
#master
from ryu.base import app_manager
from ryu.controller import ofp_event
from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_3
from ryu.lib.packet import packet
from ryu.lib.packet import ethernet
from ryu.lib.packet import ether_types
from ryu.lib.packet import in_proto
from ryu.lib.packet import ipv4
from ryu.lib.packet import icmp
from ryu.lib.packet import tcp
from ryu.lib.packet import udp
from ryu.lib.packet import sctp
from ryu.lib.packet import igmp
class SimpleSwitch13(app_manager.RyuApp):
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
def __init__(self, *args, **kwargs):
super(SimpleSwitch13, self).__init__(*args, **kwargs)
self.mac_to_port = {}
@set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)
def switch_features_handler(self, ev):
datapath = ev.msg.datapath
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
match = parser.OFPMatch()
actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
ofproto.OFPCML_NO_BUFFER)]
self.add_flow(datapath, 0, match, actions)
def add_flow(self, datapath, priority, match, actions, buffer_id=None,
idle=0, hard=0):
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
actions)]
if buffer_id:
mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id,
idle_timeout=idle, hard_timeout=hard,
priority=priority, match=match,
instructions=inst)
else:
mod = parser.OFPFlowMod(datapath=datapath, priority=priority,
idle_timeout=idle, hard_timeout=hard,
match=match, instructions=inst)
datapath.send_msg(mod)
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
def _packet_in_handler(self, ev):
if ev.msg.msg_len < ev.msg.total_len:
self.logger.debug("packet truncated: only %s of %s bytes",
ev.msg.msg_len, ev.msg.total_len)
msg = ev.msg
datapath = msg.datapath
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
in_port = msg.match['in_port']
pkt = packet.Packet(msg.data)
eth = pkt.get_protocols(ethernet.ethernet)[0]
if eth.ethertype == ether_types.ETH_TYPE_LLDP:
return
dst = eth.dst
src = eth.src
dpid = datapath.id
self.mac_to_port.setdefault(dpid, {})
# learn a mac address to avoid FLOOD next time.
self.mac_to_port[dpid][src] = in_port
if dst in self.mac_to_port[dpid]:
out_port = self.mac_to_port[dpid][dst]
else:
out_port = ofproto.OFPP_FLOOD
actions = [parser.OFPActionOutput(out_port)]
# install a flow to avoid packet_in next time
if out_port != ofproto.OFPP_FLOOD:
# check IP Protocol and create a match for IP
if eth.ethertype == ether_types.ETH_TYPE_IP:
ip = pkt.get_protocol(ipv4.ipv4)
srcip = ip.src
dstip = ip.dst
protocol = ip.proto
# if ICMP Protocol
if protocol == in_proto.IPPROTO_ICMP:
i = pkt.get_protocol(icmp.icmp)
match =
parser.OFPMatch(eth_type=ether_types.ETH_TYPE_IP,
ipv4_src=srcip, ipv4_dst=dstip,
ip_proto=protocol,icmpv4_code=i.code,
icmpv4_type=i.type)
# if TCP Protocol
elif protocol == in_proto.IPPROTO_TCP:
t = pkt.get_protocol(tcp.tcp)
match =
parser.OFPMatch(eth_type=ether_types.ETH_TYPE_IP,
ipv4_src=srcip, ipv4_dst=dstip,
ip_proto=protocol,
tcp_src=t.src_port,
tcp_dst=t.dst_port,)
# If UDP Protocol
elif protocol == in_proto.IPPROTO_UDP:
u = pkt.get_protocol(udp.udp)
match =
parser.OFPMatch(eth_type=ether_types.ETH_TYPE_IP,
ipv4_src=srcip, ipv4_dst=dstip,
ip_proto=protocol,
udp_src=u.src_port,
udp_dst=u.dst_port,)
# If IGMP Protocol
elif protocol == in_proto.IPPROTO_IGMP:
g = pkt.get_protocol(igmp.igmp)
match =
parser.OFPMatch(eth_type=ether_types.ETH_TYPE_IP,
ipv4_src=srcip, ipv4_dst=dstip,
ip_proto=protocol)
# If SCTP Protocol
elif protocol == in_proto.IPPROTO_SCTP:
s = pkt.get_protocol(sctp.sctp)
match =
parser.OFPMatch(eth_type=ether_types.ETH_TYPE_IP,
ipv4_src=srcip, ipv4_dst=dstip,
ip_proto=protocol,
scpt_src=s.src_port,
sctp_dst=s.dst_port,)
# verify if we have a valid buffer_id, if yes avoid to send
both
# flow_mod & packet_out
if msg.buffer_id != ofproto.OFP_NO_BUFFER:
self.add_flow(datapath, 1, match, actions,
msg.buffer_id, idle=20, hard=100)
return
else:
self.add_flow(datapath, 1, match, actions, idle=20,
hard=100)
data = None
if msg.buffer_id == ofproto.OFP_NO_BUFFER:
data = msg.data
out = parser.OFPPacketOut(datapath=datapath,
buffer_id=msg.buffer_id,
in_port=in_port, actions=actions,
data=data)
datapath.send_msg(out)
##########################################################
########### detection module ################################
def __init__(self, *args, **kwargs):
super(SimpleMonitor13, self).__init__(*args, **kwargs)
self.datapaths = {}
self.monitor_thread = hub.spawn(self._monitor)
start = datetime.now()
self.flow_training()
end = datetime.now()
print("Training time: ", (end-start))
@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]
def _monitor(self):
while True:
for dp in self.datapaths.values():
self._request_stats(dp)
hub.sleep(10)
self.flow_predict()
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)
@set_ev_cls(ofp_event.EventOFPFlowStatsReply, MAIN_DISPATCHER)
def _flow_stats_reply_handler(self, ev):
file0 = open("PredictFlowStatsfile.csv","w")
file0.write('ip_src,tp_src,ip_dst,tp_dst,ip_proto,flow_duration_sec,flags,packet_count,byte_count,packet_count_per_second,byte_count_per_second\n')
body = ev.msg.body
tp_src = 0
tp_dst = 0
for stat in sorted([flow for flow in body if (flow.priority == 1)
], key=lambda flow:
(flow.match['eth_type'],flow.match['ipv4_src'],flow.match['ipv4_dst'],flow.match['ip_proto'])):
ip_src = stat.match['ipv4_src']
ip_dst = stat.match['ipv4_dst']
ip_proto = stat.match['ip_proto']
if stat.match['ip_proto'] == 1:
icmp_code = stat.match['icmpv4_code']
icmp_type = stat.match['icmpv4_type']
elif stat.match['ip_proto'] == 6:
tp_src = stat.match['tcp_src']
tp_dst = stat.match['tcp_dst']
elif stat.match['ip_proto'] == 17:
tp_src = stat.match['udp_src']
tp_dst = stat.match['udp_dst']
try:
packet_count_per_second =
stat.packet_count/stat.duration_sec
except:
packet_count_per_second = 0
try:
byte_count_per_second = stat.byte_count/stat.duration_sec
except:
byte_count_per_second = 0
file0.write("{},{},{},{},{},{},{},{},{},{},{}\n"
.format(ip_src, tp_src,ip_dst, tp_dst,
stat.match['ip_proto'],stat.duration_sec,
stat.flags, stat.packet_count,stat.byte_count,
packet_count_per_second,byte_count_per_second,))
file0.close()
def flow_training(self):
self.logger.info("Flow Training ...")
flow_dataset = pd.read_csv('FlowStatsfile.csv')
flow_dataset.iloc[:, 0] = flow_dataset.iloc[:, 0].str.replace('.',
'')
flow_dataset.iloc[:, 3] = flow_dataset.iloc[:, 3].str.replace('.',
'')
X_flow = flow_dataset.iloc[:, :-1].values
X_flow = X_flow.astype('float64')
y_flow = flow_dataset.iloc[:, -1].values
X_flow_train, X_flow_test, y_flow_train, y_flow_test =
train_test_split(X_flow, y_flow, test_size=0.20, random_state=0)
classifier = RandomForestClassifier(n_estimators=10,
criterion="entropy", random_state=0)
self.flow_model = classifier.fit(X_flow_train, y_flow_train)
y_flow_pred = self.flow_model.predict(X_flow_test)
self.logger.info
("------------------------------------------------------------------------------")
self.logger.info("confusion matrix")
cm = confusion_matrix(y_flow_test, y_flow_pred)
self.logger.info(cm)
acc = accuracy_score(y_flow_test, y_flow_pred)
self.logger.info("succes accuracy = {0:.2f} %".format(acc*100))
fail = 1.0 - acc
self.logger.info("fail accuracy = {0:.2f} %".format(fail*100))
self.logger.info
("------------------------------------------------------------------------------")
def flow_predict(self):
try:
predict_flow_dataset = pd.read_csv('PredictFlowStatsfile.csv')
pdf = copy.deepcopy(predict_flow_dataset)
predict_flow_dataset.iloc[:, 3] = predict_flow_dataset.iloc[:,
3].str.replace('.', '')
predict_flow_dataset.iloc[:, 0] = predict_flow_dataset.iloc[:,
0].str.replace('.', '')
#pdf.iloc[:, 2] = pdf.iloc[:, 2].str.replace('.', '')
#pdf.iloc[:, 0] = pdf.iloc[:, 0].str.replace('.', '')
X_predict_flow = predict_flow_dataset.iloc[:, :].values
X_predict_flow = X_predict_flow.astype('float64')
y_flow_pred = self.flow_model.predict(X_predict_flow)
legitimate_trafic = 0
botnet_trafic = 0
for i in y_flow_pred:
if i == 0:
legitimate_trafic = legitimate_trafic + 1
else:
botnet_trafic = botnet_trafic + 1
victim = pdf.iloc[i, 2]#%20
attacker = pdf.iloc[i, 0]#%20
self.logger.info
("------------------------------------------------------------------------------")
if (legitimate_trafic/len(y_flow_pred)*100) > 80:
print("legitimate trafic
...",legitimate_trafic/len(y_flow_pred))
else:
print("botnet trafic ...",botnet_trafic/len(y_flow_pred))
print("Attacker IP: {}".format(attacker))
self.logger.info
("------------------------------------------------------------------------------")
file0 = open("PredictFlowStatsfile.csv","w")
file0.write('ip_src,tp_src,ip_dst,tp_dst,ip_proto,flow_duration_sec,flags,packet_count,byte_count,packet_count_per_second,byte_count_per_second,\n')
file0.close()
except:
pass
###########################################################
please any help in mitigation , or remove flows with bad traffic ( botnet
traffic ) it will be a ton of help. thank you so much in advance !!!
--
Best Regards,
Harsh Verdhan Singh
M.Tech (CSE)
PDPM-IIITDM, Jabalpur
_______________________________________________
Ryu-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ryu-devel