在传统网络中,存在着一定的广播流量,占据了一部分的网络带宽。同时,在有环的拓扑中,如果不运行某些协议,广播数据还会引起网络风暴,使网络瘫痪。
如有以下的一个网络拓扑结构(3_2_topoplus.py)
from mininet.net import Mininet
from mininet.node import OVSSwitch, Host
from mininet.cli import CLI
from mininet.link import Link
from mininet.node import RemoteController
#import networkx as nx
#import matplotlib.pyplot as pltdef create_network():net = Mininet()# 创建单个OVS交换机switch1 = net.addSwitch('s1', cls=OVSSwitch,protocols='OpenFlow13')switch2 = net.addSwitch('s2', cls=OVSSwitch,protocols='OpenFlow13')# 创建2个主机host1 = net.addHost('h1', cls=Host, ip='192.168.0.1/24', defaultRoute='via 192.168.0.254')host2 = net.addHost('h2', cls=Host, ip='192.168.0.2/24', defaultRoute='via 192.168.0.254')host3 = net.addHost('h3', cls=Host, ip='192.168.0.3/24', defaultRoute='via 192.168.0.254')host4 = net.addHost('h4', cls=Host, ip='192.168.0.4/24', defaultRoute='via 192.168.0.254')# 连接主机到交换机net.addLink(host1, switch1)net.addLink(host2, switch1)net.addLink(host3, switch2)net.addLink(host4, switch2)
#交换机连接交换机net.addLink(switch1, switch2)net.addLink(switch1, switch2)#环路# 指定控制器的IP地址和端口#可以先使用ss -tlnp | grep ryu-manager查看ryu运行后的监听端口controller_ip = '127.0.0.1'controller_port = 6633# 创建Mininet网络,并指定控制器和OpenFlow协议版本net.addController('controller', controller=RemoteController, ip=controller_ip, port=controller_port,protocols='OpenFlow13')# 启动网络net.start()# 打开命令行界面CLI(net)# 关闭网络net.stop()if __name__ == '__main__':create_network()
结合上一篇文章中已经实现的控制器应用程序,我们进行测试,并观察产生的数据交互信息,因产生广播风暴(瞬间达到千万级别的包)导致资源崩溃,无法ping通
在软件定义网络中,要解决以上安全问题,我们可以在控制器应用程序中进行编程实现。下文将实现在控制器RYU应用程序上开发ARP代理功能模块,以解决目前的网络广播风暴安全隐患。
进入/etc/sysctl.conf修改linux内核配置,关闭icmpv6功能
root@zmq-virtual-machine:/etc# vi sysctl.conf
root@zmq-virtual-machine:/etc# nano sysctl.conf
root@zmq-virtual-machine:/etc# nano sysctl.conf
在文件的末尾添加以下行来禁用 ICMPv6:
复制
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6=1
这将禁用所有接口(all)和默认接口(default)的 IPv6 功能。
然后保存并重新加载配置文件并应用更改:
以上关闭后最后,重启一下linux系统会重启ipv6
经过以上操作后,如果生成的host中仍然还有ipv6因为我们在构建网络中比有IP协议的支撑,即使关掉HOST的IPv6 后仍然有ovs生成的虚拟交换机发送相关信息(即使禁用所有设备的ipv6相关你握手包,也还会有IPv4的包,如果都没有握手包,IP协议将因无法正常协商而出现异常)
因此,需要使用编程的办法在ryu控制器APP上进行数据包剔除,把相关的促发信息改为ARP(ping的先行数据包)才进行响应,包括下发流表和mac地址学习等。
解决问题: 前面的packet_in数据包是没有ip地址的?只有ARP才开始有?
1 在packet_in_handler函数中剔除ICMP
from ryu.base import app_manager
from ryu.controller import ofp_event
from ryu.controller.handler import set_ev_cls
from ryu.controller.handler import MAIN_DISPATCHER
from ryu.controller.handler import CONFIG_DISPATCHER
from ryu.ofproto import ofproto_v1_3
from ryu.lib.packet import packet
from ryu.lib.packet import ethernet
from ryu.lib.packet import ipv6
from ryu.lib.packet import icmp
from ryu.lib.packet import icmpv6class L2Switch(app_manager.RyuApp):def __init__(self, *args, **kwargs):super(L2Switch, self).__init__(*args, **kwargs)self.mac_port_table={}@set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)def switch_features_handler(self, ev):datapath = ev.msg.datapathofproto = datapath.ofproto#msg = ev.msg #features阶段的数据包没有封装承载其他的协议,因此没有data字段 parser=datapath.ofproto_parser#pkt = packet.Packet(msg.data)#features阶段的数据包没有封装承载其他的协议,因此没有data字段 #icmp_pkt = pkt.get_protocol(icmp.icmp)#features阶段的数据包没有封装承载其他的协议,因此没有data字段 #icmp6_pkt = pkt.get_protocol(icmpv6.icmpv6)#features阶段的数据包没有封装承载其他的协议,因此没有data字段 #if not icmp_pkt and not icmp6_pkt: #无需判断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):ofproto = datapath.ofprotoparser = datapath.ofproto_parserinst=[parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,actions)]mod=parser.OFPFlowMod(datapath=datapath, priority=priority,match=match, instructions=inst)datapath.send_msg(mod)@set_ev_cls(ofp_event.EventOFPPacketIn,MAIN_DISPATCHER)def packet_in_hander(self,ev):msg = ev.msgdp = msg.datapathofp = dp.ofprotoofp_parser = dp.ofproto_parserin_port = msg.match['in_port']dpid=dp.idpkt = packet.Packet(msg.data)icmp_pkt = pkt.get_protocol(icmp.icmp)icmp6_pkt = pkt.get_protocol(icmpv6.icmpv6)if not icmp_pkt and not icmp6_pkt:self.mac_port_table.setdefault(dpid, {})pkt = packet.Packet(msg.data)eth_pkt = pkt.get_protocols(ethernet.ethernet)[0]dst = eth_pkt.dstprint(dst)src = eth_pkt.srcself.mac_port_table[dpid][src] = in_portif dst in self.mac_port_table[dpid]:out_port = self.mac_port_table[dpid][dst]else:out_port = ofp.OFPP_FLOODactions = [ofp_parser.OFPActionOutput(out_port)]if out_port != ofp.OFPP_FLOOD:match = ofp_parser.OFPMatch(in_port=in_port, eth_dst=dst, eth_src=src)# verify if we have a valid buffer_id, if yes avoid to send both# flow_mod & packet_outif msg.buffer_id != ofp.OFP_NO_BUFFER:self.add_flow(dp, 1, match, actions, msg.buffer_id)print("1")returnelse:self.add_flow(dp, 1, match, actions)print("2")data = Noneif msg.buffer_id == ofp.OFP_NO_BUFFER:data = msg.dataout = ofp_parser.OFPPacketOut(datapath=dp, buffer_id=msg.buffer_id,in_port=in_port, actions=actions, data=data)dp.send_msg(out)
本代码运行后,因为剔除了icmp,因此不会因为因为icmp直接产生风暴风险,但是在mininet中执行ping后将产生ARP风暴,效果如下图所示。