添加新表流时的Ryu控制器struct.error

时间:2019-03-05 23:05:31

标签: python ryu

我正在编写一个Ryu L4 swtich应用程序,我正在尝试执行以下操作:当识别到TCP / UDP数据包时,该应用程序在本地数据库中检查以查看数据包参数是否来自已知的攻击者(源IP,目标IP和目标端口)。

如果数据包与攻击者数据库中记录的数据包匹配,则会向交换机添加一个流以丢弃特定数据包(此流的持续时间为2小时),如果数据包不匹配,则将数据流添加至转发给特定的交换机端口(此流程持续5分钟)。

问题是,当控制器将新流发送到交换机/数据路径时,我收到以下错误:

SimpleSwitch13: Exception occurred during handler processing. Backtrace from offending handler [_packet_in_handler] servicing event [EventOFPPacketIn] follows.
Traceback (most recent call last):
File "/root/SecAPI/Code/lib/python3.5/site-packages/ryu/base/app_manager.py", line 290, in _event_loop
handler(ev)
File "/root/SecAPI/Flasks/Code/SDN/switchL3.py", line 237, in _packet_in_handler
self.add_security_flow(datapath, 1, match, actions)
File "/root/SecAPI/Flasks/Code/SDN/switchL3.py", line 109, in add_security_flow
datapath.send_msg(mod)
File "/root/SecAPI/Code/lib/python3.5/site-packages/ryu/controller/controller.py", line 423, in send_msg
msg.serialize()
File "/root/SecAPI/Code/lib/python3.5/site-packages/ryu/ofproto/ofproto_parser.py", line 270, in serialize
self._serialize_body()
File "/root/SecAPI/Code/lib/python3.5/site-packages/ryu/ofproto/ofproto_v1_3_parser.py", line 2738, in _serialize_body
self.out_group, self.flags)
File "/root/SecAPI/Code/lib/python3.5/site-packages/ryu/lib/pack_utils.py", line 25, in msg_pack_into
struct.pack_into(fmt, buf, offset, *args)
struct.error: 'H' format requires 0 <= number <= 65535

这是我的完整代码:

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 ipv4
from ryu.lib.packet import tcp
from ryu.lib.packet import udp
from ryu.lib.packet import in_proto
import sqlite3

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.initial = True
    self.security_alert = False

@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()
    self.initial = True
    actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,
                                      ofproto.OFPCML_NO_BUFFER)]
    self.add_flow(datapath, 0, match, actions)
    self.initial = False

# Adds a flow into a specific datapath, with a hard_timeout of 5 minutes.
# Meaning that a certain packet flow ceases existing after 5 minutes.
def add_flow(self, datapath, priority, match, actions, buffer_id=None):
    ofproto = datapath.ofproto
    parser = datapath.ofproto_parser

    inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
                                         actions)]
    if buffer_id:
        if self.initial == True:
            mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id,
                                    priority=priority, match=match,
                                    instructions=inst)
        elif self.initial == False:
            mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id,
                                    priority=priority, match=match,
                                    instructions=inst,hard_timeout=300)
    else:
        if self.initial == True:
            mod = parser.OFPFlowMod(datapath=datapath, priority=priority,
                                    match=match, instructions=inst)

        elif self.initial == False:
            mod = parser.OFPFlowMod(datapath=datapath, priority=priority,
                                    match=match, instructions=inst,
                                    hard_timeout=300)
    datapath.send_msg(mod)

# Adds a security flow into the controlled device, a secured flow differs from a normal
# flow in it's duration, a security flow has a duration of 2 hours.
def add_security_flow(self, datapath, priority, match, actions, buffer_id=None):
    ofproto = datapath.ofproto
    parser = datapath.ofproto_parser

    #inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,
    #                                     actions)]
    inst = [parser.OFPInstructionActions(ofproto.OFPIT_CLEAR_ACTIONS, [])]

    if buffer_id:
        mod = parser.OFPFlowMod(datapath=datapath, buffer_id=buffer_id,
                                priority=priority,match=match,command=ofproto.OFPFC_ADD,
                                instructions=inst, hard_timeout=432000)
    else:
        mod = parser.OFPFlowMod(datapath=datapath, priority=priority,
                                match=match, instructions=inst, command=ofproto.OFPFC_ADD,
                                hard_timeout=432000)

    datapath.send_msg(mod)

# Deletes a already existing flow that matches has a given packet match.
def del_flow(self, datapath, priority, match, actions, buffer_id=None):
    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,
                                priority=priority,match=match,instruction=inst,
                                command=ofproto.OFPFC_DELETE)
    else:
        mod = parser.OFPFlowMod(datapath=datapath, priority=priority,
                                match=match, instructions=inst,
                                command=ofproto.OFPFC_DELETE)

    datapath.send_msg(mod)

@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
    dst = eth.dst
    src = eth.src

    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:
        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:
        #match = parser.OFPMatch(in_port=in_port, eth_dst=dst, eth_src=src)
        # check IP Protocol and create a match for IP
        if eth.ethertype == ether_types.ETH_TYPE_IP:
            conn = sqlite3.connect("database/sdnDatabase.db")
            cursor = conn.cursor()
            ip = pkt.get_protocol(ipv4.ipv4)
            srcip = ip.src
            dstip = ip.dst
            #match = parser.OFPMatch(eth_type=ether_types.ETH_TYPE_IP,ipv4_src=srcip,ipv4_dst=dstip)
            protocol = ip.proto

            # ICMP Protocol
            if protocol == in_proto.IPPROTO_ICMP:
                print("WARN - We have a ICMP packet")
                cursor.execute('select id from knownAttackers where srcaddr =  \"{0}\" and dstaddr = \"{1}\" and protocol = "icmp";'.format(srcip, dstip))
                result = cursor.fetchall()
                match = parser.OFPMatch(eth_type=ether_types.ETH_TYPE_IP, ipv4_src=srcip, ipv4_dst=dstip,
                                        ip_proto=protocol)
                if len(result) == 0:
                    self.security_alert = False
                else:
                    self.security_alert = True

            # TCP Protocol
            elif protocol == in_proto.IPPROTO_TCP:
                print("WARN - We have a TCP packet")
                t = pkt.get_protocol(tcp.tcp)
                cursor.execute('select id from knownAttackers where srcaddr =  \"{0}\" and dstaddr = \"{1}\" and dstport = \"{2}\" and protocol = "tcp";'.format(srcip, dstip, t.dst_port))
                result = cursor.fetchall()
                match = parser.OFPMatch(eth_type=ether_types.ETH_TYPE_IP, ipv4_src=srcip, ipv4_dst=dstip,
                                        ip_proto=protocol, tcp_dst=t.dst_port)
                if len(result) == 0:
                    self.security_alert = False
                else:
                    print("We have a register in the database for this specific packet: {0}".format(result))
                    self.security_alert = True

            # UDP Protocol
            elif protocol == in_proto.IPPROTO_UDP:
                print("WARN - We have a UDP packet")
                u = pkt.get_protocol(udp.udp)
                cursor.execute('select id from knownAttackers where srcaddr =  \"{0}\" and dstaddr = \"{1}\" and dstport = \"{2}\" and protocol = "udp";'.format(srcip, dstip, u.dst_port))
                result = cursor.fetchall()
                match = parser.OFPMatch(eth_type=ether_types.ETH_TYPE_IP, ipv4_src=srcip, ipv4_dst=dstip,
                                        ip_proto=protocol, udp_dst=u.dst_port)
                if len(result) == 0:
                    self.security_alert = False
                else:
                    self.security_alert = True

            else:
                self.security_alert = False
                match = 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_out
            if self.security_alert == False:
                if msg.buffer_id != ofproto.OFP_NO_BUFFER:
                    self.add_flow(datapath, 1, match, actions, msg.buffer_id)
                    return
                else:
                    self.add_flow(datapath, 1, match, actions)

            elif self.security_alert == True:
                if msg.buffer_id != ofproto.OFP_NO_BUFFER:
                    self.add_security_flow(datapath, 1, match, actions, msg.buffer_id)
                    return
                else:
                    self.add_security_flow(datapath, 1, match, actions)


    data = None
    if msg.buffer_id == ofproto.OFP_NO_BUFFER:
        data = msg.data

    if self.security_alert == False:
        out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id,
                              in_port=in_port, actions=actions, data=data)
        datapath.send_msg(out)

当我尝试建立被标识为已知攻击者的TCP连接时,当他尝试将流修改(datapath.send_msg(mod))发送到时,上述错误出现在add_security_flow()类方法的末尾开关/数据路径。

我在做什么错?我是否缺少某种变量?

1 个答案:

答案 0 :(得分:0)

在Ryu控制器的邮件列表中,一个名为IWAMOTO的用户告诉我,缩小结构后,我的hard_timeout值太大(2小时为7200秒,我不知道我的头在哪里可以找到432000 haha​​) hard_timeout达到7200秒,一切正常。

始终检查您要发送到数据路径的值的大小,看是否不超过65535。