首页
/ ZMap项目中的IP层数据包发送问题分析与解决方案

ZMap项目中的IP层数据包发送问题分析与解决方案

2025-06-05 06:25:41作者:何举烈Damon

问题背景

在ZMap网络扫描工具的使用过程中,开发人员发现当使用-X参数(即--iplayer选项)仅发送IP层数据包时,在Ubuntu系统上无法获得任何扫描结果。这一问题不仅出现在本地虚拟机环境中,在Digital Ocean云服务器上同样可以复现。

问题现象

当执行以下命令时:

sudo ./src/zmap -p 80 -N 5 -X -i enp0s8 -T 1

ZMap会持续发送数据包但收不到任何响应,扫描进度始终显示0%命中率。相比之下,不使用-X参数时扫描能够正常工作。

技术分析

通过对网络数据包的抓取分析,发现两种模式下发送的数据包在IP层和TCP层内容上基本一致,主要区别在于:

  1. IP ID字段:使用-X时IP ID是随机生成的,而不使用时是固定值
  2. 校验和:两种模式下的TCP校验和不同
  3. MAC地址:深入分析发现使用-X时数据包的目标MAC地址被设置为00:00:00:00:00:00

进一步调试发现,当启用--iplayer选项时,ZMap当前使用AF_PACKETSOCK_DGRAM创建原始套接字,这导致了MAC地址处理异常。正确的做法应该是使用PF_INETSOCK_RAW来创建IP层原始套接字。

解决方案

经过开发者验证,以下代码修改可以解决该问题:

diff --git a/src/socket-linux.c b/src/socket-linux.c
index b1710c7..c1e2208 100644
--- a/src/socket-linux.c
+++ b/src/socket-linux.c
@@ -20,7 +20,7 @@ sock_t get_socket(UNUSED uint32_t id)
 {
        int sock;
        if (zconf.send_ip_pkts) {
-               sock = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL));
+               sock = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);
        } else {
                sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
        }

这一修改将IP层数据包发送的套接字创建方式从数据链路层的DGRAM套接字改为网络层的RAW套接字,确保IP数据包能够被正确构造和发送。

技术原理

在Linux网络编程中,有几种不同的原始套接字创建方式:

  1. AF_PACKET+SOCK_RAW:可以发送和接收包括以太网头在内的完整数据帧
  2. AF_PACKET+SOCK_DGRAM:可以发送和接收不包括链路层头部的数据包
  3. PF_INET+SOCK_RAW:可以构造和发送自定义IP层数据包

原来的实现错误地使用了AF_PACKET+SOCK_DGRAM组合来发送IP层数据包,导致底层网络栈无法正确处理数据包。修改后使用PF_INET+SOCK_RAW组合,让内核网络栈处理链路层细节,只关注IP层及以上的数据构造。

影响范围

该问题主要影响:

  1. 使用-X--iplayer选项的扫描
  2. Linux平台上的ZMap运行
  3. 需要发送纯IP数据包的特殊扫描场景

对于常规的以太网帧扫描不受此问题影响。

总结

ZMap工具中IP层数据包发送功能的这一问题,揭示了Linux网络编程中不同原始套接字类型的细微差别。正确的套接字类型选择对于网络工具的正常工作至关重要。这一修复不仅解决了功能性问题,也为理解Linux网络协议栈的实现提供了有价值的参考。

登录后查看全文
热门项目推荐
相关项目推荐