在傳統網絡中,存在著一定的廣播流量,占據了一部分的網絡帶寬。同時,在有環的拓撲中,如果不運行某些協議,廣播數據還會引起網絡風暴,使網絡癱瘓。
如有以下的一個網絡拓撲結構(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風暴,效果如下圖所示。