
简介这是一套基于Python实现TCP入侵检测系统的完整源码项目主要面向毕业设计、期末大作业与课程设计场景也适合网络安全方向学习者作为课设参考。系统核心功能包括检测端口扫描与Dos攻击并联动iptables自动进行防御代码中带有详细注释结构清晰便于二次理解与部署。资源包共6个文件以5个Python脚本和1个说明文档为主涵盖数据嗅探、流量分析、数据库存储、主控逻辑等模块压缩包大小仅5KB轻量易上手不过包体较小下载后需按说明补充依赖库后再运行。该项目作者自述为手打的高分项目经过严格调试可直接作为毕设或期末大作业的基础框架使用。目前已有111人浏览学习适合需要快速搭建入侵检测演示系统的初学者参考。1. TCP入侵检测为什么选择Python iptables这条路线有一类代码你明明知道它是对的但上线前一秒心里还在打鼓——TCP 入侵检测就属于这种。抓包能抓到特征也匹配可真到被端口扫描、被 DoS 打的时候能不能在几秒内响应并把攻击源封掉才是这套系统值不值的唯一标准。这套基于 Python 实现的 TCP 入侵检测系统做的事很聚焦抓网卡 TCP 流量识别端口扫描和 DoS 攻击联动 iptables 封禁攻击源。不依赖 GPU 和复杂框架一台 Linux 服务器 Python 3.8 环境就能跑。适合两类人拿它做毕设、期末大作业需要跑通并能演示、答辩的学生想给小型服务器加一层低成本 TCP 攻击检测的运维新手。代码注释做得比较足新手也能顺着链路摸清楚哪里是抓包、哪里是检测、哪里是封禁。2. 系统架构与核心文件五个Python模块怎么分工拿到压缩包后先别急着跑花五分钟把文件结构看明白后面调参会顺手很多。这套系统没有用 Django、Flask 之类的框架也没有用 Scapy 这种重型抓包库就是五个 Python 文件加一个 README每个文件管一段职责哪怕你把代码全删了自己重写只要保持这个边界功能也能复现。2.1 压缩包里的文件清单与职责边界解压后就是下面这六个文件README 是第一个要看的因为作者把依赖、启动命令和默认参数都写在里面。五个 Python 模块的调用方向是单向的抓包线程在 Data_Sniff 里跑recv 出来的裸帧先交给 Flitter 过滤过滤完的 TCP 报文进 Analysis 做特征统计Analysis 一旦判定攻击就把事件丢给 MainMain 调 iptables 封禁同时往 Database 写一条记录。整个链路是单向的只有 Main 能调 iptables 和 Database模块之间不互相掺和。文件职责Data_Sniff.py原始套接字抓包解析以太网头 / IP 头 / TCP 头输出结构化数据Flitter.py过滤非 TCP 报文与无效地址维护白名单减少误报Analysis.py统计特征判定端口扫描 / DoS 攻击生成封禁建议Main.py主控入口线程调度调用 iptables组织封禁与解封Database.pySQLite 落库记录攻击日志并支持简单查询README.md部署说明、依赖清单、运行参数这里有个很容易忽略的小坑源码里这个文件拼的是 Flitter.py不是 Filter.pyREADME 里也是这个名别手动改成 Filter否则 import 直接断掉。我猜是作者当时打字打顺手了但既然源码包里这么写的就按它的名字用。数据流再强调一遍因为后面对照着看参数会很有用Data_Sniff 抓包 → Flitter 过滤 → Analysis 检测 → Main 执行 iptables 封禁 → Database 落库。封禁是最后一步检测错了封禁就会误伤所以第 5 章里我专门写了几个最容易翻车的判断错误。2.2 Main.py主控逻辑参数怎么设、线程怎么起从模块职责来看Main.py 是整个系统的入口负责把其他几个模块串起来。这类项目最顺手的写法是解析命令行参数、初始化数据库连接、启动抓包线程、启动检测线程、再启动一个消费封禁事件的线程。我按常见的实现骨架复现一下入口参数和线程分工基本固定是这个框架import argparse from Data_Sniff import Sniffer from Analysis import Analyzer from Database import AttackDB parser argparse.ArgumentParser(descriptionTCP Intrusion Detection) parser.add_argument(--interface, defaulteth0, help监听网卡名) parser.add_argument(--syn-threshold, typeint, default50, helpSYN包速率阈值每秒超过即判定DoS) parser.add_argument(--port-threshold, typeint, default30, help端口扫描阈值10秒内不同目的端口数) parser.add_argument(--ban-seconds, typeint, default600, helpiptables封禁时长秒) args parser.parse_args() db AttackDB(attack.db) analyzer Analyzer(args.syn_threshold, args.port_threshold) sniffer Sniffer(args.interface, analyzer.handle_packet) sniffer.start() # 消费攻击事件并执行封禁 for ip, attack_type in analyzer.event_queue(): db.insert(src_ipip, attack_typeattack_type, actionDROP) block_ip(ip, args.ban_seconds)逻辑上分三段参数解析决定行为和阈值Sniffer 把网卡上抓到的每个包通过回调塞给 AnalyzerAnalyzer 内部做统计一旦判定出攻击就把 IP 和攻击类型塞到事件队列里。主循环只在队列有事件时才活动抓包线程和检测线程都不阻塞它这样封禁动作不会拖慢抓包速率。参数默认值不是我乱写的是从这个项目的使用场景推出来的。毕设演示时流量不大SYN 阈值 50、端口扫描阈值 30 就能很快触发但放到有真实业务的服务器上要往大了调。各参数含义如下表参数名默认值含义--interfaceeth0监听网卡名云服务器可能是 ens3 / ens5--syn-threshold50每秒收到的纯 SYN 包数量超过判定 DoS--port-threshold3010秒窗口内同一源 IP 访问的不同目的端口数--ban-seconds600封禁持续时间单位秒2.3 Database.py记录模块为什么用SQLiteDatabase.py 承担的不只是“存日志”这一件事它还负责给答辩演示提供证据。攻击发生之后你能从数据库里查到是哪个 IP、什么攻击类型、在什么时间被封禁的比直接在终端里翻日志直观得多。这个项目用 SQLite 是很务实的选择原因很简单单机部署、零配置、一个文件就是整个库不需要额外装 MySQL 服务。建表语句通常长这样CREATE TABLE IF NOT EXISTS attack_log ( id INTEGER PRIMARY KEY AUTOINCREMENT, src_ip TEXT NOT NULL, dst_ip TEXT, dst_port INTEGER, attack_type TEXT, timestamp DATETIME DEFAULT CURRENT_TIMESTAMP, action TEXT );src_ip 是攻击源地址attack_type 区分是 port_scan 还是 syn_floodaction 记录执行的动作一般是 DROP。后面做验证时直接查这张表就能确认系统有没有真的在干活。提示如果要在课程答辩里现场演示建议把 --ban-seconds 临时调到 60 秒。这样你现场跑端口扫描触发封禁后等一分钟规则自动消失不影响继续演示其他功能。默认 600 秒的话演示完你的测试 IP 还会被封十分钟网页都打不开。3. 抓包与特征提取从原始套接字到TCP头解析检测要准前提是包抓得干净、解析得对。这套系统的抓包层选的是 Linux 上的 AF_PACKET 原始套接字而不是 Scapy 这类封装库。Scapy 写起来爽但依赖重、解析慢还要额外装 Npcap / libpcap对一台只跑检测的空服务器来说没必要。原始套接字直接拿链路层数据帧自己用 struct.unpack 去拆字节性能更好也更能看清 TCP 头里每一位的含义答辩时也更有说头。3.1 Data_Sniff.py如何从网卡拿TCP帧原始套接字的逻辑是创建一个 AF_PACKET SOCK_RAW 套接字 bind 到指定网卡然后 recvfrom 循环取数据帧。每一帧都是完整的以太网帧从目的 MAC 开始到 IP 头、TCP 头全部要自己按偏移量拆。这个解析链路是整项目最关键的 20 行代码import socket import struct def parse_frame(frame): # 以太网头目的MAC 6字节 源MAC 6字节 类型 2字节 eth_type struct.unpack(!H, frame[12:14])[0] if eth_type ! 0x0800: # 0x0800 表示 IPv4 return None # IP头从第14字节开始第9字节是协议号6表示TCP if frame[23] ! 6: return None src_ip socket.inet_ntoa(frame[26:30]) dst_ip socket.inet_ntoa(frame[30:34]) # IP头长度字段低4位是IHL单位4字节通常为520字节 ihl (frame[14] 0x0F) * 4 tcp frame[14 ihl:] src_port, dst_port struct.unpack(!HH, tcp[0:4]) flags tcp[13] # TCP flags 字节0x02 是 SYN return { src_ip: src_ip, dst_ip: dst_ip, src_port: src_port, dst_port: dst_port, tcp_flags: flags, } def sniff(interface): sock socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.ntohs(0x0003)) sock.bind((interface, 0)) while True: frame, addr sock.recvfrom(65535) pkt parse_frame(frame) if pkt: analyzer.handle_packet(pkt) # 交给检测层一步步对一下偏移frame[12:14] 是 EtherTypeIPv4 固定是 0x0800IP 头里协议号在第 9 字节所以是 frame[23]源 IP 在 IP 头第 12 到 15 字节加上以太网头的 14 字节偏移就是 frame[26:30]。IP 头长度不是固定 20 字节如果带了 Options 字段会变长所以用 IHL 字段乘 4 算出真实偏移再往后切 TCP 头。每个第一次手拼包的开发者都会在偏移量上栽跟头建议写完后用 tcpdump -i eth0 tcp port 80 -c 10 -xx 抓一组真实报文逐字节对照着验证。为什么用 AF_PACKET 而不是 SOCK_STREAMSOCK_STREAM 拿到的是已经被内核协议栈处理过的数据看不到 SYN 包、看不到半连接状态而端口扫描和 SYN Flood 的特征恰恰藏在这些“不完整连接”里。原始套接字能让你在 TCP 三次握手完成之前就看到第一个 SYN这是检测的前提。3.2 Flitter.py过滤逻辑只留要看的包不是所有 TCP 包都需要参与统计。如果不过滤健康检查探针、内网广播、纯 ACK 包都会混进来推高计数导致误报。Flitter.py 干的就是这件事把不相关的流量挡在检测层外面# 白名单支持 IP 和网段 WHITELIST [127.0.0.1, 10.0.0.0/8, 192.168.0.0/16] def in_whitelist(ip): for entry in WHITELIST: if ip_matches(ip, entry): return True return False def should_pass(pkt): # 0x02 是纯 SYN0x12 是 SYNACK if pkt[tcp_flags] 0x10: # 纯 ACK 不参与统计 return False if in_whitelist(pkt[src_ip]): return False # 只统计发往本机检测范围的包 if pkt[dst_ip] ! LOCAL_IP: return False return True过滤逻辑分三层协议层把纯 ACK 丢掉因为 SYN 洪泛和端口扫描都不依赖 ACK地址层把本机、内网网段排除掉避免误封方向层只统计目的 IP 是本机的包防止把经过本机转发的流量也算进来。白名单这个设计很重要很多部署翻车就翻在这。这里要特别说一下 0x02 和 0x12 的区别。TCP flags 是一个字节按位组合SYN 是 0x02ACK 是 0x10。三次握手的第二步 SYNACK 就是 0x12。如果你检测 SYN 时只判断tcp_flags 0x02 ! 0那么每一条正常 TCP 连接都会算进来计数直接爆炸所以 Flitter 和 Analysis 里要区分“纯 SYN”和“带 SYN 的包”语义完全不同。3.3 三次握手与攻击流量的本质区别把检测逻辑讲透之前先花点时间说清楚正常的 TCP 是什么样。客户端发 SYN服务端回 SYNACK客户端再回 ACK三次握手完成之后才进入数据传输。这个过程中服务端内核会为第一个 SYN 建立半连接放进半连接队列等 ACK 到达再把它转成正式连接。SYN Flood 的攻击方式就是只发第一步攻击者拿伪造或真实 IP 疯狂发 SYN但永远不回第三步的 ACK。服务端半连接队列被塞满新的正常连接请求进不了队列应用层即使还活着用户也连不上。这套系统检测 DoS 的思路本质上就是在估算“半连接队列被灌满的速度”单位时间内纯 SYN 包数量超过阈值就认为有人在灌队列。端口扫描又是另一类行为。扫描器想快速摸清一台机器开了哪些端口会向连续多个端口发 SYN观察返回的是 SYNACK 还是有 RST。如果返回 SYNACK 说明端口开放返回 RST 说明未开放。从抓包视角看就是同一个源 IP 在极短时间内访问了大量不同目的端口这正是 4.1 里统计窗口要做的事。一句话总结正常用户访问一台服务器源 IP 固定目的端口也就那么一两个扫描器和攻击器不一样它们在时间轴上把自己的行为特征暴露得很明显。检测算法就是在时间窗口内找这些异常集中度。4. 检测算法与iptables联动阈值怎么设、封禁怎么落这一章是整个系统的核心也是答辩时最容易被追问的地方。理解两个检测算法怎么统计、阈值怎么影响误报率、iptables 封禁为什么用 -I 不用 -A比背代码重要得多。4.1 端口扫描检测时间窗口内的目的端口集合端口扫描最朴素的特征是“短时间内访问大量不同端口”。实现上要解决两个问题一个是时间窗口怎么划一个是“不同端口”怎么去重。常见做法是给每个源 IP 和目的 IP 的组合维护一个最近 10 秒的访问记录队列窗口滑过去之后旧记录就丢弃import time from collections import defaultdict, deque PORT_WINDOW 10.0 # 10秒统计窗口 PORT_THRESHOLD 30 # 窗口内不同端口数阈值 # key: (src_ip, dst_ip), value: [(时间戳, 目的端口), ...] scan_tracker defaultdict(deque) def check_port_scan(pkt): key (pkt[src_ip], pkt[dst_ip]) now time.time() q scan_tracker[key] q.append((now, pkt[dst_port])) # 清理超过窗口期的记录 while q and q[0][0] now - PORT_WINDOW: q.popleft() # 统计窗口内出现的不同端口数量 ports set() for _, p in q: ports.add(p) if len(ports) PORT_THRESHOLD: return key return None代码里有两处值得说。一是用 deque 存记录队头在左边最老的数据在队头清理时从左边 popleft新数据追加在右边天然就是滑动窗口。二是统计数量时用 set 对目的端口去重因为扫描器即使重复探测同一个端口也不能算“两个端口”。窗口大小和阈值怎么配演示环境 10 秒 / 30 端口很灵敏Nmap 一条nmap -sS -p 1-1000命令几秒钟就触发但真实服务器上如果内部系统有批量健康检查可能一分钟探测几十个端口建议把阈值抬到 60 或更高的 80否则误报会很难受。还有一个容易忽略的细节阈值统计的是“不同目的端口数”不是“包数”。一个纯 SYN 洪泛如果固定打 80 端口端口数永远是 1不会触发扫描检测同样地端口扫描虽然包多但目的端口分散所以两种攻击要分两个算法去盯。4.2 DoS攻击检测SYN速率与半连接队列特征SYN Flood 检测比端口扫描要敏感得多因为它直接关系到服务器能不能继续对外服务。本站用一个全局的 SYN 时间戳队列来估算单位时间内的 SYN 速率每秒超过阈值就判定 DoSfrom collections import deque syn_timestamps deque() # 记录每个纯SYN包到达的秒级时间戳 SYN_THRESHOLD 50 # 每秒SYN包数阈值来自Main参数 def check_syn_flood(pkt): # 只认纯SYN0x02不认SYNACK0x12 if pkt[tcp_flags] ! 0x02: return None now time.time() syn_timestamps.append(now) # 队列只保留最近1秒的记录 while syn_timestamps and syn_timestamps[0] now - 1.0: syn_timestamps.popleft() if len(syn_timestamps) SYN_THRESHOLD: return pkt[src_ip] return None这个算法的本质是滑动窗口计数。每次来一个纯 SYN就把当前时间戳塞进队列然后从头把超过 1 秒的旧记录清理掉剩下队列长度就是“最近一秒的 SYN 包数量”。当这个数量超过阈值就对当前源 IP 返回封禁目标。阈值 50 这个默认值对应的是每秒 50 个纯 SYN 包。一台流量很小的服务器正常每秒可能也就几个 SYN50 是很安全的但如果你部署的是一台有真实业务、甚至被频繁访问的 Web 服务器动态请求一多每秒几十个 SYN 很正常。我一般建议线上先拉到 200 再观察毕设演示用 50 就好太低会在大流量下疯狂误封。SYN Flood 判定的不只是速率理论上还应该看“SYN 与 SYNACK 的比例”但真实实现里这个比值不好统计速率阈值是最简单且大概率准确的模型。答辩时被问到就答“半连接队列被灌满的速度超过阈值”这个说法是站得住的。4.3 iptables联动封禁为什么用-I不是-A超时怎么解封检测出攻击 IP 之后剩下的事就是让内核把包扔掉。这里直接用 subprocess 调 iptables 命令插入一条 INPUT 链 DROP 规则把源 IP 封掉。但插入位置有讲究这是我在第一次跑这套系统时踩过的最实在的坑import subprocess import threading blocked set() def block_ip(ip, ban_seconds): if ip in blocked: return # 先查规则是否已存在避免重复插入 check subprocess.run( [iptables, -C, INPUT, -s, ip, -j, DROP], capture_outputTrue, ) if check.returncode ! 0: # -I INPUT 1 表示插到链的最前面立即生效 subprocess.run( [iptables, -I, INPUT, 1, -s, ip, -j, DROP], checkTrue, ) blocked.add(ip) # 到点自动解除封禁不阻塞主流程 threading.Timer(ban_seconds, unblock_ip, args(ip,)).start() def unblock_ip(ip): subprocess.run( [iptables, -D, INPUT, -s, ip, -j, DROP], checkTrue, ) blocked.discard(ip)-C参数用来检查规则是否已存在返回码非 0 表示不存在避免同一个 IP 被重复插入几十条同样的规则。-I INPUT 1把规则插到链的最前面这是和-A最大的区别。很多新手用-A追加到链尾如果 INPUT 链前面已经有一条ACCEPT all之类的放行规则新加的 DROP 规则永远不会被匹配到表现就是“日志里已经记录攻击了但流量照样进来”。超时解封用的是 threading.Timer到时间之后自动执行 iptables -D 删除规则。这个设计兼顾了实际场景攻击可能是短时的封 10 分钟足够扛过一波永久封禁反而可能误伤正常用户。600 秒是默认值如果你在演示调成 60 会更友好。4.4 事件回传机制队列解耦检测与执行检测线程和执行封禁的线程不应该互相阻塞。Analysis.py 里十几个包的解析和统计可能很密集但如果它直接去调 iptables一条命令执行几十毫秒抓包线程就卡住了丢包率会飙升。所以常见做法是在两者之间放一个线程安全的队列from queue import Queue # 检测线程往队列里丢攻击事件 attack_queue Queue() def analyzer_loop(pkt): hit check_port_scan(pkt) or check_syn_flood(pkt) if hit: attack_queue.put((hit[0], port_scan)) # dos 的判定结果也是同理这里不展开 # 主线程消费队列执行封禁 def action_loop(): while True: ip, attack_type attack_queue.get() block_ip(ip, args.ban_seconds) db.insert(src_ipip, attack_typeattack_type, actionDROP)队列的意义在于检测层只需要把“谁被打了、什么类型”丢进队列不用关心后面是调用 iptables 还是写数据库执行层消费队列时即使 iptables 命令执行得慢也不会拖累抓包循环。这也是 Main.py 的逻辑骨架代码走通之后整个系统的耦合被这一层解得很干净。5. 部署避坑与常见问题从权限到规则的五个排查点这套系统代码量不大真正的门槛都在环境上。我把它跑起来、跑坏、再修好的过程里遇到过的几个坑按“现象 → 原因 → 解决”列在下面任何一条都可能导致你怀疑代码是坏的但基本都是环境问题。5.1 iptables规则被已有ACCEPT吞掉封禁不生效现象攻击日志一直在写数据库里记录越来越长但被封的 IP 流量照样能进来业务高峰一点没降。原因封禁规则是用-A追加到 INPUT 链尾部的。很多 Linux 发行版默认 INPUT 链里有一条ACCEPT all或 status 相关的放行规则在前包在到达你追加的 DROP 规则之前就被 ACCEPT 了内核根本不会继续往下匹配。解决把追加改成插入用-I INPUT 1把 DROP 规则插到链的最前面。另外新版本 Debian / Ubuntu 默认是 nftables 后端直接跑 iptables 命令有时会报cant initialize iptables table之类的错那不是规则错了是系统用的兼容层不对先执行update-alternatives --config iptables切换到 legacy 或 nft 模式再试。5.2 没带sudo跑抓包线程静默失败现象python Main.py --interface eth0启动后不报错但看统计计数一直是 0程序“像死了一样”。原因AF_PACKET 原始套接字需要 root 权限或CAP_NET_RAW能力。普通用户创建套接字时可能直接抛Operation not permitted也可能在 recv 阶段被内核拒掉表现成静默失败。解决全程用sudo跑先ifconfig -a确认网卡名不是 eth0 而是 ens3 / ens5。启动之前先写一个三行测试脚本只创建套接字并打印recvfrom拿到的帧长度能出数字说明权限和网卡都对再去跑整套系统。5.3 把自己或内网出口IP封了SSH直接断开现象在云服务器上部署完没过多久 SSH 突然断开服务器怎么也连不上最后只能重启。原因云平台的健康检查探针、NAT 网关出口 IP、本机公网 IP都有可能被当成攻击源。尤其当服务器本身在 NAT 后面回程流量源 IP 看起来可能是网关地址检测算法会把网关当坏人直接 DROP。解决Flitter.py 的白名单里默认排除127.0.0.1和 RFC1918 内网网段还要把云平台健康检查 IP 加进去。封禁前再做一个校验如果 src_ip 等于本机所有网卡上的 IP 之一直接跳过不封。这个校验逻辑要放在 block_ip 入口因为检测层看不到本机 IP 列表。5.4 SYN标志位判断偏移算错正常连接被误报成攻击现象没有被打数据库里却全是封禁记录而且封的 IP 五花八门连正常访问用户都封。原因TCP flags 解析偏移量算错了。IP 头长度不是固定 20 字节如果 IHL 计算错误TCP head 的起点就错了flags 字节解析出来的值是错的纯 ACK 包被当成 SYN 包统计。另一个常见错误是用tcp_flags 0x02判断 SYN把三次握手的第二步 SYNACK0x12也算进来计数直接翻倍。解决先抓一组真实报文对照。tcpdump -i eth0 tcp port 80 -c 10 -xx输出十六进制原始包逐字节核对你的偏移量flags 判断改成pkt[tcp_flags] 0x02只认纯 SYN。如果确实想覆盖 SYNACK 形式的探测用pkt[tcp_flags] 0x02 ! 0但要把阈值同步调高否则误报会让你怀疑人生。5.5 程序退出后iptables规则残留封禁规则越积越多现象CtrlC 退出程序后iptables -L -n -v里躺着几十条 DROP 规则重启服务器才会清空。原因threading.Timer 创建的线程是守护线程主进程一退出解封定时器就直接被掐断unblock_ip 永远不会执行。blocked 集合只存在内存里进程一退出就没了下次启动时它也不知道哪些 IP 还没解封。解决Main.py 里注册信号处理器捕获 SIGINT / SIGTERM 后遍历 blocked 集合逐个执行iptables -D。更稳的做法是把封禁列表落盘到文件启动时先读文件把上一次残留的规则清一遍再开始抓包。从那以后我每次改完代码重启检测程序都会先看一眼iptables -L -n是不是干净的这个习惯救过我很多次。6. 验证这套系统是否真在干活模拟攻击与日常巡检习惯代码部署完第一件事不是改功能而是验证它真的能检测、能封禁、能解封。这套流程我每次都会过一遍大概五分钟就能出结论。先准备工具Debian / Ubuntu 下直接装apt install -y hping3 nmap然后起两路验证。第一路验证端口扫描检测用 Nmap 的半开扫描# 从另一台机器执行 nmap -sS -p 1-500 检测服务器IP预期是几秒内数据库出现 port_scan 记录同时检测服务器上iptables -L -n -v能看到一条针对你测试 IP 的 DROP 规则。第二路验证 DoS 检测用 hping3 发 SYN 洪泛# 持续发10秒触发 SYN 速率阈值 hping3 -S -p 80 --flood 检测服务器IP预期是数据库出现 syn_flood 记录源 IP 被封禁。攻击停止后等 ban-seconds 时间规则自动消失。最后查一下数据库确认落库sqlite3 attack.db select * from attack_log order by id desc limit 5;正常会看到两条记录一条 attack_type 是 port_scan一条是 syn_floodaction 都是 DROP。如果你用 Python 自己写验证脚本也可以只用 socket 发大量 SYN但需要自己构造 IP 头和 TCP 头还要算校验和不如 hping3 一条命令省事。Nmap 和 hping3 是安全测试标准工具毕设答辩现场演示直接用命令行足够直观。这套源码包拿到手之后建议先按上面的流程走一遍Nmap 触发端口扫描、hping3 触发 SYN 洪泛、查库看两条记录。跑通了再去调阈值、改白名单。从那以后我每次部署完都强制跑一遍模拟 SYN 洪泛和端口扫描看到 attack_log 里出现记录、iptables 里出现对应 DROP 规则才敢说这系统是真的在干活。希望帮到你。本文还有配套的精品资源点击获取