
简介这份资源是面向高校计算机、网络工程等专业学生的课程设计/期末大作业参考方案主题为基于SDN的DDoS攻击检测与防御系统适合正在准备网络方向课程项目、需要完整可运行源码与实现思路的同学。压缩包共89个文件以Java源码为主体71个配合11个XML配置、2个YML与2个TXT说明另有gitignore、md、sh等辅助文件整体约96KB结构紧凑、便于快速导入IDE运行调试。项目围绕SDN控制器与DDoS流量识别展开涵盖检测逻辑、防御策略与模块化代码组织可作为课程答辩、实验复现与二次开发的基础。目前已有898人学习下载说明该方案在同类课程作业中具有一定参考价值。读者可据此理解SDN环境下攻击检测与缓解的工程实现路径并对照自身选题完成功能扩展与文档撰写。1. 从一份课程大作业说起SDN 环境下的 DDoS 检测与防御到底在做什么如果你手头正拿着一份标着“95分以上课程大作业”的 SDN DDoS 攻击检测与防御系统源码第一反应大概率是跑起来看看效果。但多数人卡在第一步——不知道这套东西的边界在哪。SDN 把控制平面和数据平面拆开控制器掌握全局拓扑视图这给 DDoS 检测带来了传统网络没有的优势你可以在控制器上集中采集流表统计、端口流量、Packet-In 速率而不必在每台交换机上单独部署探针。这套源码要解决的核心问题就一个在 SDN 环境中如何利用控制器采集的流级特征识别 DDoS 攻击流量并下发流表规则进行缓解。适合谁看正在做网络安全课程设计的学生、想从传统 IDS 转向 SDN 安全方向的运维、以及需要快速搭一个可演示原型的工程师。下面按“原理选型 → 环境搭建 → 数据采集 → 检测实现 → 防御下发 → 避坑 → 进阶”的顺序拆开讲。2. 为什么选 SDN 做 DDoS 检测架构选型与控制器对比2.1 传统 DDoS 检测方案在 SDN 场景下的三个局限传统网络里做 DDoS 检测常见做法是在出口路由器镜像流量送到旁路 IDS 分析。这套方案在 SDN 环境里会遇到三个硬伤。第一镜像流量需要额外端口和带宽在 Mininet 模拟环境里根本没有物理镜像口你只能靠控制器或交换机主动上报。第二传统 IDS 基于包特征匹配面对 SYN Flood、UDP Flood 这类体积型攻击逐包检测的吞吐跟不上而 SDN 控制器可以按流粒度统计一条 Flow Entry 就代表一条流聚合效率高得多。第三传统方案检测到攻击后缓解手段依赖 ACL 手工下发或 BGP 黑洞路由响应慢SDN 控制器可以直接用 OpenFlow 流表在毫秒级下发丢弃或限速规则。所以选 SDN 不是赶时髦是它的集中式视图和可编程转发面天然适合做“检测—决策—执行”闭环。2.2 控制器选型Ryu、ONOS、Floodlight 怎么选课程大作业场景下控制器选型直接决定你后面写代码的工作量。Ryu 是 Python 写的轻量文档和示例多适合快速验证检测逻辑ONOS 是 Java 写的集群能力强适合运营商级场景但学习曲线陡Floodlight 也是 JavaREST API 完善但社区活跃度不如前两者。如果你只是要在 Mininet 里跑通 DDoS 检测与防御Ryu 是最稳的选择——它的ryu.app.ofctl_rest和ryu.controller.controller能让你在同一个进程里既收 Packet-In 又下发 FlowMod。常见做法是用 Ryu 做控制器Mininet 做拓扑Open vSwitch 做转发面。这套组合在课程作业里复现率最高遇到问题也最容易搜到答案。2.3 检测与防御的闭环架构整套系统的数据流是这样的Mininet 启动拓扑后OVS 交换机连接 Ryu 控制器控制器通过EventOFPPacketIn和EventOFPFlowStatsReply采集流统计检测模块周期性拉取流表计算特征如包速率、字节速率、流持续时间、源 IP 熵值一旦判定为攻击防御模块构造OFPFlowMod消息匹配攻击流特征并执行DROP或METER限速。这里的关键设计点是检测周期不能太短否则控制器 CPU 被流统计请求打满也不能太长否则攻击已经造成拥塞才响应。我一般把轮询周期设在 5 到 10 秒配合滑动窗口做二次确认。3. 把环境跑起来Mininet Ryu OVS 的最小可用配置3.1 安装与版本确认先确认你的环境。Ubuntu 20.04 或 22.04 都行Mininet 用 apt 装Ryu 用 pip 装。注意 Ryu 对 Python 版本敏感Python 3.8 以上基本没问题但如果你用 Python 3.10部分老版本 Ryu 会有collections.MutableMapping报错需要升级到 Ryu 4.34 以上。# 安装 Mininet 和 Open vSwitch sudo apt update sudo apt install -y mininet openvswitch-switch # 安装 Ryu 控制器 pip3 install ryu4.34 # 验证版本 mn --version ryu-manager --version ovs-vsctl --version逻辑说明Mininet 负责创建虚拟网络拓扑OVS 负责实际转发Ryu 负责控制逻辑。版本确认这一步不能省我见过太多因为 Ryu 版本和 Python 版本不匹配导致ryu-manager启动即崩的情况。参数上ryu4.34是当前兼容性较好的版本如果你用系统自带的 pip 装不上加--user或建虚拟环境。3.2 启动 Ryu 控制器并验证连接写一个最简单的 Ryu 应用只打印交换机连接事件确认控制器和 OVS 能握手。# simple_monitor.py 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 class SimpleMonitor(app_manager.RyuApp): OFP_VERSIONS [ofproto_v1_3.OFP_VERSION] set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER) def switch_features_handler(self, ev): datapath ev.msg.datapath self.logger.info(交换机已连接: dpid%s, datapath.id) # 下发一条默认流表匹配所有包并上送控制器 ofproto datapath.ofproto parser datapath.ofproto_parser match parser.OFPMatch() actions [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER, ofproto.OFPCML_NO_BUFFER)] inst [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS, actions)] mod parser.OFPFlowMod(datapathdatapath, priority0, matchmatch, instructionsinst) datapath.send_msg(mod)逻辑说明EventOFPSwitchFeatures是交换机与控制器建立连接后触发的第一个事件在这里下发默认流表让后续所有包都上送控制器。参数上priority0是最低优先级OFPP_CONTROLLER表示上送控制器OFPCML_NO_BUFFER表示不缓冲整个包。启动命令ryu-manager simple_monitor.py --verbose然后在另一个终端启动 Mininetsudo mn --controllerremote,ip127.0.0.1,port6653 --switchovs,protocolsOpenFlow13 --topotree,2如果 Ryu 终端打印出交换机已连接: dpid...说明控制通道通了。这一步是后面所有检测逻辑的基础连不上后面全白搭。3.3 用 iperf 和 hping3 构造正常流量与攻击流量环境通了之后先构造正常流量基线。在 Mininet CLI 里# 正常 TCP 流量 mininet h1 iperf -s mininet h2 iperf -c h1 -t 10 # SYN Flood 攻击流量 mininet h3 hping3 -S --flood -V -p 80 h1逻辑说明iperf产生正常 TCP 流hping3 -S --flood产生 SYN Flood。注意--flood会以最大速率发包在 Mininet 里可能把虚拟交换机 CPU 打满建议先用-i u1000控制速率。参数上-S指定 SYN 标志-p 80指定目标端口-V输出详细信息。这一步的目的是让你在检测模块里能看到正常流和攻击流的特征差异——正常 TCP 流的包速率和字节速率相对稳定SYN Flood 的包速率极高但平均包长很小。4. 流统计采集与特征计算从 OpenFlow 流表到检测输入4.1 用 OFPFlowStatsRequest 周期性拉取流统计Ryu 控制器可以通过OFPFlowStatsRequest向交换机请求流统计信息。下面是一个周期性采集的代码片段# flow_collector.py 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 import hub class FlowCollector(app_manager.RyuApp): OFP_VERSIONS [ofproto_v1_3.OFP_VERSION] def __init__(self, *args, **kwargs): super(FlowCollector, self).__init__(*args, **kwargs) self.datapaths {} self.monitor_thread hub.spawn(self._monitor) set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER) def switch_features_handler(self, ev): datapath ev.msg.datapath self.datapaths[datapath.id] datapath def _monitor(self): while True: for dp in self.datapaths.values(): self._request_stats(dp) hub.sleep(5) # 每 5 秒采集一次 def _request_stats(self, datapath): ofproto datapath.ofproto parser datapath.ofproto_parser req parser.OFPFlowStatsRequest(datapath) datapath.send_msg(req) set_ev_cls(ofp_event.EventOFPFlowStatsReply, MAIN_DISPATCHER) def flow_stats_reply_handler(self, ev): body ev.msg.body for stat in body: # 提取关键特征 match stat.match src_ip match.get(ipv4_src, N/A) dst_ip match.get(ipv4_dst, N/A) packet_count stat.packet_count byte_count stat.byte_count duration stat.duration_sec self.logger.info(流: %s - %s, 包数%d, 字节数%d, 持续%ds, src_ip, dst_ip, packet_count, byte_count, duration)逻辑说明hub.spawn启动一个协程每 5 秒向所有已连接的交换机发送流统计请求。EventOFPFlowStatsReply返回每条流的统计信息包括匹配字段、包数、字节数、持续时间。参数上hub.sleep(5)的 5 秒是采集周期实际部署时可以根据控制器负载调整到 10 秒。注意stat.match.get(ipv4_src)在非 IP 流上会返回None需要做空值处理。4.2 计算 DDoS 检测的核心特征拿到原始流统计后需要计算有区分度的特征。常用的几个特征名计算方式正常范围SYN Flood 表现包速率packet_count / duration几十到几百 pps数千到数万 pps字节速率byte_count / duration与包速率成正比包速率高但字节速率低平均包长byte_count / packet_count500-1500 字节40-60 字节流持续时间duration_sec较长极短或持续增长源 IP 熵值对源 IP 分布计算熵较高攻击时熵值下降import math from collections import Counter def calc_entropy(ip_list): 计算源 IP 分布的熵值 if not ip_list: return 0.0 counter Counter(ip_list) total len(ip_list) entropy 0.0 for count in counter.values(): p count / total entropy - p * math.log2(p) return entropy def extract_features(flow_stats): 从流统计中提取检测特征 features [] for stat in flow_stats: duration max(stat.duration_sec, 1) pkt_rate stat.packet_count / duration byte_rate stat.byte_count / duration avg_pkt_len stat.byte_count / max(stat.packet_count, 1) features.append({ src_ip: stat.match.get(ipv4_src, 0.0.0.0), pkt_rate: pkt_rate, byte_rate: byte_rate, avg_pkt_len: avg_pkt_len, duration: duration }) return features逻辑说明calc_entropy用来衡量源 IP 的分散程度DDoS 攻击如果使用伪造源 IP熵值会异常如果使用固定源 IP熵值会极低。extract_features把原始统计转换成数值特征向量供后续阈值判断或机器学习模型使用。参数上max(stat.duration_sec, 1)防止除零max(stat.packet_count, 1)同理。这些特征的计算逻辑是后面检测模块的输入特征选得对不对直接决定检测效果。4.3 阈值法与轻量机器学习的取舍课程大作业场景下我建议先用阈值法跑通闭环再考虑加机器学习。阈值法的逻辑简单如果某条流的包速率超过PKT_RATE_THRESHOLD且平均包长低于AVG_LEN_THRESHOLD判定为攻击。阈值怎么定先在正常流量下采集 5 分钟取包速率的 95 分位数作为基线攻击阈值设为基线的 3 到 5 倍。机器学习可以用 Isolation Forest 或简单的 KMeans但需要标注数据课程作业里往往没有现成数据集自己构造又费时间。常见做法是阈值法做第一层过滤机器学习做第二层确认但如果你时间紧阈值法调好参数也能拿到不错的演示效果。5. 检测到攻击之后流表下发防御与限速策略5.1 构造 OFPFlowMod 下发丢弃规则检测到攻击流后最直接的防御是下发高优先级流表匹配攻击流特征并执行DROP。def install_drop_flow(datapath, src_ip, dst_ip, priority100): 下发丢弃指定流的规则 ofproto datapath.ofproto parser datapath.ofproto_parser match parser.OFPMatch( eth_type0x0800, ipv4_srcsrc_ip, ipv4_dstdst_ip ) # 空 actions 表示丢弃 inst [] mod parser.OFPFlowMod( datapathdatapath, prioritypriority, matchmatch, instructionsinst, hard_timeout300 # 5 分钟后自动删除 ) datapath.send_msg(mod)逻辑说明OFPFlowMod的instructions为空列表时匹配的包会被丢弃。priority100要高于默认流表的 0确保优先匹配。hard_timeout300让规则 5 分钟后自动过期避免误判导致永久断流。参数上eth_type0x0800表示 IPv4ipv4_src和ipv4_dst根据检测结果填入。注意如果攻击源 IP 是伪造的按源 IP 丢弃可能误伤正常流量这时候要考虑按目的 IP 或端口丢弃。5.2 用 Meter 表做限速而不是一刀切直接丢弃可能影响正常用户更温和的做法是用 OpenFlow Meter 表做限速。def install_meter_flow(datapath, src_ip, rate_kbps1000): 对指定流限速 ofproto datapath.ofproto parser datapath.ofproto_parser # 创建 Meter meter_id 1 bands [parser.OFPMeterBandDrop(raterate_kbps, burst_size100)] meter_mod parser.OFPMeterMod( datapathdatapath, commandofproto.OFPMC_ADD, flagsofproto.OFPMF_KBPS, meter_idmeter_id, bandsbands ) datapath.send_msg(meter_mod) # 下发流表引用 Meter match parser.OFPMatch(eth_type0x0800, ipv4_srcsrc_ip) inst [parser.OFPInstructionMeter(meter_id)] mod parser.OFPFlowMod( datapathdatapath, priority100, matchmatch, instructionsinst, hard_timeout300 ) datapath.send_msg(mod)逻辑说明OFPMeterBandDrop表示超过速率阈值的包被丢弃rate1000表示限速 1000 Kbpsburst_size100允许突发。OFPInstructionMeter把流表项和 Meter 关联。参数上OFPMF_KBPS指定速率单位meter_id需要唯一。限速比直接丢弃更精细适合演示“缓解”而不是“阻断”的场景。5.3 防御策略的触发条件与误判回滚防御不能一检测到就触发要有确认机制。我一般用滑动窗口连续 3 个采集周期都判定为攻击才下发规则。回滚方面hard_timeout是最简单的后悔药规则到期自动删除。如果误判严重可以在控制器里维护一个已下发规则的列表提供 REST API 手动删除。Ryu 的ofctl_rest模块可以让你用 HTTP 请求查看和删除流表调试时很方便。6. 避坑与排查SDN DDoS 检测系统最常见的五个翻车点6.1 坑一控制器收不到 Packet-In检测模块拿不到数据现象Ryu 启动正常Mininet 也连上了但检测模块日志里没有任何流统计。原因默认流表的priority0且没有匹配所有包上送控制器或者 OVS 的 OpenFlow 版本不匹配。解决确认simple_monitor.py里下发了默认流表且OFP_VERSIONS设为ofproto_v1_3Mininet 启动时加--switchovs,protocolsOpenFlow13。如果还是不行用ovs-ofctl dump-flows s1查看流表是否真的下发了。6.2 坑二流统计请求返回空特征计算全为零现象EventOFPFlowStatsReply触发了但body为空。原因OVS 默认只统计已安装流表的流如果流量走的是默认流表且没有精确匹配统计信息可能不完整。解决在采集前先下发一条低优先级的精确匹配流表或者用ovs-ofctl dump-flows确认流表存在。另一个常见原因是采集周期太短流还没建立就请求统计。6.3 坑三SYN Flood 攻击把 Mininet 虚拟交换机打崩现象hping3 --flood一开Mininet CLI 卡死OVS 进程 CPU 100%。原因Mininet 的虚拟交换机没有硬件加速--flood以最大速率发包会耗尽 CPU。解决用-i u1000限制发包间隔或者用--rand-source模拟多源攻击但降低速率。演示时建议把攻击速率控制在 1000 pps 以内既能触发检测又不至于打崩环境。6.4 坑四防御规则下发后正常流量也被阻断现象攻击停止后正常用户无法访问。原因按源 IP 丢弃时如果攻击源 IP 和正常用户 IP 在同一网段或者匹配条件太宽比如只匹配目的 IP会误伤。解决匹配条件尽量精确加上ipv4_src和ipv4_dst和tcp_dst三元组设置hard_timeout让规则自动过期在控制器里加白名单机制对已知正常流不下发丢弃规则。6.5 坑五Ryu 控制器内存泄漏跑几小时就 OOM现象控制器运行一段时间后内存持续增长最终被系统杀掉。原因self.datapaths字典只增不减交换机断开后没有清理或者流统计回调里累积了大量未处理的数据。解决监听EventOFPStateChange在交换机断开时从datapaths中删除对应条目流统计回调里只保留最近 N 条记录用collections.deque(maxlen1000)替代普通列表。7. 从课程作业到可演示原型三个让效果更稳的进阶技巧7.1 用滑动窗口做二次确认降低误报单次阈值判断容易误报尤其是正常流量突发时。我一般用长度为 3 的滑动窗口连续 3 个周期都超过阈值才触发防御。代码上用一个deque保存最近 3 次判定结果from collections import deque class AttackDetector: def __init__(self, window_size3): self.window deque(maxlenwindow_size) def is_attack(self, pkt_rate, threshold): self.window.append(pkt_rate threshold) # 窗口满且全部为 True 才判定攻击 return len(self.window) self.window.maxlen and all(self.window)逻辑说明deque(maxlen3)自动保持最近 3 次结果all(self.window)要求全部为 True。参数上window_size越大误报越低但响应越慢课程演示用 3 比较平衡。这个技巧能让你的演示在正常流量波动时不被误触发答辩时更稳。7.2 用 REST API 暴露检测状态方便演示Ryu 自带ofctl_rest但检测状态需要自己暴露。可以用ryu.app.wsgi起一个简单 HTTP 服务返回当前检测到的攻击流列表和已下发的防御规则。演示时打开浏览器就能看到实时状态比盯日志直观得多。常见做法是继承WSGIApplication注册一个/stats路由返回 JSON 格式的检测结果。7.3 用 tc 或 OVS Meter 做对比实验答辩时老师常问“你的防御效果怎么量化”。我一般做两组对比一组不开启防御用iperf测正常流量的吞吐另一组开启防御同样测吞吐。如果防御生效攻击流被限速或丢弃后正常流量的吞吐应该恢复到接近基线。数据用表格呈现场景正常流吞吐攻击流包速率控制器响应时间无防御下降 80%5000 pps无阈值防御恢复至基线 90%被限速至 1000 pps5-10 秒滑动窗口防御恢复至基线 95%被丢弃15-30 秒这张表能让你的演示从“能跑”变成“有数据支撑”。最后说个血泪教训我当初做这个作业时光顾着调检测算法忘了给防御规则设hard_timeout结果演示到一半正常流量全断了当场翻车。后来养成习惯任何下发的流表都加超时任何防御都留回滚接口。希望帮到你。本文还有配套的精品资源点击获取