AF_PACKET套接字接收重复报文 多进程trio实现SYN扫描问题咨询
AF_PACKET重复收包问题原因
- AF_PACKET套接字的内核复制机制:你启动的8个进程各自独立创建并绑定了同一个网卡的
AF_PACKET套接字,且BPF过滤规则逻辑一致。内核默认会将每个匹配BPF规则的网卡报文,复制一份发给所有绑定了对应协议的AF_PACKET套接字,因此同一个响应报文会被8个进程各收到一次,外部抓包自然看不到重复。 - 异步接收逻辑错位:你当前的代码是串行执行端口扫描,发一个端口的SYN包就立刻调用
recvfrom等待响应,但网络报文是乱序到达的,你本次recvfrom拿到的可能是之前发送的其他端口的响应,后续处理对应端口时又会收到一次,也会导致重复统计。 - 代码逻辑缺陷:
microworker中无论收到什么类型的报文都会直接break退出重传循环,3次重传逻辑完全失效,同时没有对收到的响应报文和当前扫描端口做匹配校验,很容易把其他端口的响应当成当前端口的结果。
对应的解决方法
- 调整套接字创建逻辑:改为仅启动1个独立的收包进程负责AF_PACKET套接字的监听,所有收上来的报文通过进程间队列分发给对应负责该端口的扫描进程,避免多进程同时监听AF_PACKET导致的重复复制。
- 优化BPF规则:如果要保留多进程各自监听AF_PACKET的设计,给每个进程的BPF规则添加端口区间过滤条件,仅允许当前进程负责的端口区间的响应报文进入,内核就不会把其他端口的报文复制给当前进程。
- 重构异步扫描逻辑:不要串行执行单端口扫描任务,将所有端口的扫描任务提交到trio的nursery中并发执行,同时用全局字典存储已发SYN的端口状态,收到报文后先匹配端口再更新状态,避免乱序导致的错收。
- 补充端口校验逻辑:收到响应报文后,先校验源端口是否为当前等待的端口,匹配成功再处理端口状态,不匹配就缓存或者丢弃。
多进程+trio的设计合理性
这个架构本身是合理的:
- 多进程拆分端口区间可以规避Python GIL的CPU瓶颈,每个进程跑独立的trio事件循环没有兼容性问题,trio本身完全支持多进程场景下的独立运行。
- 你当前的实现没有发挥异步的优势:
jumboworker中串行awaitmicroworker,相当于每个端口都要等上一个端口处理完才开始扫描,性能和同步代码没有区别,应该把所有单端口扫描任务提交到nursery并发执行,同时添加并发数控制避免发包速度过快被网络设备限流。 - 额外注意:你主进程创建子进程的代码存在笔误,循环变量是
interval,但传递给trio.run的参数是未定义的i,需要修正为interval。
内容的提问来源于stack exchange,提问作者adder
相关产品推荐
相关产品推荐

