Hello All,
I need to simulate slow SYN attack in mininet with Ryu. I need to fill the
switch flow table with 1500 flow entries. However, when I run the code the
maximum number of flows I saw was 67, and after a while of running the code,
my laptop holds.My Laptop has Intel Core i5 cpu with 8GB RAM. I need to know if
the problem from limited resources or from bug in the code.The attached is my
topology code with the controller code and the shell the host needs to run to
generate SYN packets.
Any help will be appreciated.
Regards,
#!/usr/bin/python
from mininet.net import Mininet
from mininet.node import Controller, RemoteController, OVSController
from mininet.node import CPULimitedHost, Host, Node
from mininet.node import OVSKernelSwitch, UserSwitch
from mininet.node import IVSSwitch
from mininet.cli import CLI
from mininet.link import TCLink
from mininet.log import setLogLevel, info
from mininet.link import Intf
from subprocess import call
from time import clock
import time
import random
def myNetwork():
net = Mininet( topo=None, build=False, link=TCLink, controller=RemoteController)
linkopts1 = dict(bw=100, delay='1us', loss=0)
info( '*** Adding controller ***\n' )
controller1=net.addController(name='controller1', controller=RemoteController, protocol='tcp', port=6633)
info( '*** Adding switche ***\n')
switch1 = net.addSwitch('s1', cls=OVSKernelSwitch)
server = net.addHost('server', cls=Node, ip='192.168.1.100', mac='00:00:00:00:00:01')
net.addLink(switch1, server, **linkopts1)
client = net.addHost('client', cls=Node, ip='192.168.1.250', mac= '00:00:00:00:00:02')
net.addLink(switch1, client, **linkopts1)
attacker = net.addHost('attacker', cls=Node, ip='192.168.1.200', mac= '00:00:00:00:00:03')
net.addLink(switch1, attacker, **linkopts1)
info( '*** Starting network ***\n')
net.build()
net. staticArp()
controller1.start()
net.start()
s1=net.get('s1')
s1.cmd ('ovs-vsctl set Bridge s1 protocols=OpenFlow13')
info( '\n*** Starting web server ***\n')
server = net.get('server')
server.cmd('iperf -s -p 80 &')
server.cmd('tcpdump tcp port 80 -i server-eth0 -w server.pcap &')
client = net.get('client')
#Start the simulation
info( '*** Starting the simulation ***\n')
start_time = time.time()
#for i in range(1,375):
#client.cmd('iperf -p 80 -c 192.168.1.100 -t 300 &')
#time.sleep(.5)
attacker = net.get('attacker')
ips = generate_IP()
c = 0
for ip in ips:
#attacker.cmd('(sudo python SYN-ACK.py %s 192.168.1.100 %d 80) &'%(ip,ips[ip]))
attacker.cmd('(watch -n 3 sudo python SYN-ACK.py %s 192.168.1.100 %d 80 ) & '%(ip,ips[ip]))
time.sleep(.3125)
c = c+1
#attacker.cmd('sudo python SYN-ACK.py 192.168.1.150 192.168.1.100 80 &')
print len(ips)
finish_time = time.time() - start_time
CLI(net)
net.stop()
def generate_IP():
"""Generate 760 diffrent IPs to simulate Botnets
"""
#init_ip = '192.168.2.3'
bot_IPs = {}
c = 1
r = 1
for n in range(0,760):
ip = '192.168.2.%s'%(n+1)
port = random.randint(1024,65535)
if n >=254 and n<= 505:
ip = '192.168.3.%s'%(c+1)
c = c+1
if n> 505 and n<759:
ip = '192.168.4.%s'%(r+1)
r = r+1
if n ==759:
ip ='192.168.1.150'
bot_IPs[ip] = port
return bot_IPs
if __name__ == '__main__':
setLogLevel( 'info' )
myNetwork()
#!/usr/local/bin/python
from scapy.all import *
# VARIABLES
src = sys.argv[1]
dst = sys.argv[2]
sport = int(sys.argv[3])
dport = int(sys.argv[4])
# SYN
ip=IP(src=src,dst=dst)
SYN=TCP(sport=sport,dport=dport,flags='S',seq=1000)
SYNACK=sr1(ip/SYN)
# ACK
#ACK=TCP(sport=sport, dport=dport, flags='A', seq=SYNACK.ack, ack=SYNACK.seq + 1)
#send(ip/ACK)
# Copyright (C) 2011 Nippon Telegraph and Telephone Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from ryu.base import app_manager
from ryu.controller import ofp_event
from ryu.controller.handler import MAIN_DISPATCHER, CONFIG_DISPATCHER, DEAD_DISPATCHER, HANDSHAKE_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 ipv4
from ryu.lib.packet import tcp
from ryu.lib.packet import ethernet
from ryu.lib.packet import ether_types
from ryu.lib.packet import arp
from ryu.lib.packet.arp import ARP_REQUEST, ARP_REPLY
from ryu import utils
from ryu.lib import hub
from time import clock
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 = {}
self.datapaths = {}
self.monitor_thread = hub.spawn(self._monitor)
self.count = 1
self.t = clock()
self.flow_mod = 0
self.last_flow_mod =0
##################################################################################################################
@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
# install table-miss flow entry
#
# We specify NO BUFFER to max_len of the output action due to
# OVS bug. At this moment, if we specify a lesser number, e.g.,
# 128, OVS will send Packet-In with invalid buffer_id and
# truncated packet data. In that case, we cannot output packets
# correctly. The bug has been fixed in OVS v2.1.0.
match = parser.OFPMatch()
actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
ofproto.OFPCML_NO_BUFFER)]
self.add_flow(datapath, 0, match, actions, 0)
#############################################################################################################
@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 not datapath.id 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 add_flow(self, datapath, priority, match, actions, idle_timeout, buffer_id=None):
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
actions)]
if buffer_id:
self.flow_mod = self.flow_mod +1
mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id, idle_timeout=idle_timeout, hard_timeout=0,
priority=priority,flags= ofproto.OFPFF_SEND_FLOW_REM, match=match,
instructions=inst)
else:
self.flow_mod = self.flow_mod +1
mod = parser.OFPFlowMod(datapath=datapath, priority=priority , idle_timeout=idle_timeout, hard_timeout=0,
flags= ofproto.OFPFF_SEND_FLOW_REM, match=match, instructions=inst)
if self.count <= 1500:
#self.count = self.count +1
datapath.send_msg(mod)
else:
print "The TCAM memory is full"
return
###############################################################################################################
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
def _packet_in_handler(self, ev):
# If you hit this you might want to increase
# the "miss_send_length" of your switch
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:
# ignore lldp packet
return
if eth.ethertype == ether_types.ETH_TYPE_ARP:
self.logger.info("ARP packet")
arpPacket = pkt.get_protocol(arp.arp)
if (arpPacket.opcode == arp.ARP_REQUEST) and (arpPacket.dst_ip != '192.168.1.1250' and arpPacket.dst_ip !='192.168.1.100'):
arp_dstIp = arpPacket.dst_ip
print arp_dstIp
# From the dest IP figure out the mac address
targetMac = eth.src
print targetMac
targetIp = arpPacket.src_ip
srcMac = '00:00:00:00:00:03'#ipToMac(arp_dstIp) # Get the MAC address of the ip looked up
e = ethernet.ethernet(targetMac, srcMac, ether_types.ETH_TYPE_ARP)
a = arp.arp(opcode=arp.ARP_REPLY, src_mac=srcMac, src_ip=arp_dstIp, dst_mac=targetMac, dst_ip=targetIp)
p = packet.Packet()
p.add_protocol(e)
p.add_protocol(a)
p.serialize()
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
datapath.send_msg(parser.OFPPacketOut(datapath=datapath, buffer_id=ofproto.OFP_NO_BUFFER, in_port=ofproto.OFPP_CONTROLLER, actions=[ parser.OFPActionOutput(in_port) ], data=p.data))
elif arpPacket.opcode == ARP_REPLY:
pass
dst = eth.dst
src = eth.src
ipsrc = '0.0.0.0'
ipdst = '0.0.0.0'
protocol =0
src_port =0
dst_port =0
if pkt.get_protocol(ethernet.ethernet) and pkt.get_protocol(ipv4.ipv4) :
(ip4,) = pkt.get_protocols(ipv4.ipv4)
ipsrc = ip4.src
ipdst = ip4.dst
protocol = ip4.proto
pkt_tcp = pkt.get_protocol(tcp.tcp)
if pkt_tcp is not None:
src_port = pkt_tcp.src_port
dst_port = pkt_tcp.dst_port
print "IP src ", ipsrc, "IP dst ", ipdst, "src port", src_port, "dst port ", dst_port
dpid = datapath.id
self.mac_to_port.setdefault(dpid, {})
self.logger.info("packet in %s %s %s %s", dpid, src, dst, in_port)
# 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:
if ipsrc != '192.168.1.250':
out_port = 1
else:
if ipsrc == '192.168.1.100' and ipdst != '192.168.1.250':
out_port = 3
else:
out_port = ofproto.OFPP_FLOOD
print "output port ", out_port
actions = [parser.OFPActionOutput(out_port)]
# install a flow to avoid packet_in next time
if out_port != ofproto.OFPP_FLOOD:
match = parser.OFPMatch(in_port=in_port, eth_dst=dst, eth_src=src, eth_type=ether_types.ETH_TYPE_IP, ipv4_src=ipsrc, ipv4_dst=ipdst,
ip_proto=protocol, tcp_src=src_port, tcp_dst=dst_port)
# verify if we have a valid buffer_id, if yes avoid to send both
# flow_mod & packet_out
print "Number of flows = ", repr(self.count)
if msg.buffer_id != ofproto.OFP_NO_BUFFER:
self.add_flow(datapath, 1, match, actions, 10, msg.buffer_id)
return
else:
self.add_flow(datapath, 1, match, actions, 10)
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)
################################################################################################################################
def _monitor(self):
while True:
for dp in self.datapaths.values():
self._request_stats(dp)
hub.sleep(1)
############################################################################################################
def _request_stats(self, datapath):
self.logger.debug('send stats request: %016x', datapath.id)
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
req = parser.OFPFlowStatsRequest(datapath)
datapath.send_msg(req)
#self.send_flow_mod(datapath)
############################################################################################################
@set_ev_cls(ofp_event.EventOFPFlowStatsReply, MAIN_DISPATCHER)
def _flow_stats_reply_handler(self, ev):
body = ev.msg.body
flows = []
for stat in body:
flows.append('table_id=%s '
'duration_sec=%d duration_nsec=%d '
'priority=%d '
'idle_timeout=%d hard_timeout=%d flags=0x%04x '
'cookie=%d packet_count=%d byte_count=%d '
'match=%s instructions=%s' %
(stat.table_id,
stat.duration_sec, stat.duration_nsec,
stat.priority,
stat.idle_timeout, stat.hard_timeout, stat.flags,
stat.cookie, stat.packet_count, stat.byte_count,
stat.match, stat.instructions))
num_Of_flows = len(flows)
self.count = num_Of_flows
print '#flows', num_Of_flows
now = clock()
time = now - self.t
self.t = clock()
with open('./result.txt', 'a+') as fd:
fd.write("Time")
fd.flush()
fd.write(str(time))
fd.flush()
fd.write(" #of_flows ")
fd.flush()
fd.write(str(self.count))
fd.flush()
fd.write(" #of_FLOW_MOD messages ")
fd.flush()
fd.write(str(self.flow_mod))
fd.flush()
self.flow_mod = 0
fd.write("\n")
fd.flush()
fd.close()
#////////////////////////////////////////////////////////////////////////////
@set_ev_cls(ofp_event.EventOFPFlowRemoved, MAIN_DISPATCHER)
def flow_removed_handler(self, ev):
msg = ev.msg
dp = msg.datapath
ofp = dp.ofproto
dpid = dp.id
if msg.reason == ofp.OFPRR_IDLE_TIMEOUT:
reason = 'IDLE TIMEOUT'
#self.count = self.count -1
print "Idle Timeout removed the entry"
elif msg.reason == ofp.OFPRR_HARD_TIMEOUT:
reason = 'HARD TIMEOUT'
print "Hard Timeout removed the entry"
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Ryu-devel mailing list
Ryu-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ryu-devel