我正在编写一个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()类方法的末尾开关/数据路径。
我在做什么错?我是否缺少某种变量?
答案 0 :(得分:0)
在Ryu控制器的邮件列表中,一个名为IWAMOTO的用户告诉我,缩小结构后,我的hard_timeout值太大(2小时为7200秒,我不知道我的头在哪里可以找到432000 haha) hard_timeout达到7200秒,一切正常。
始终检查您要发送到数据路径的值的大小,看是否不超过65535。