news 2026/6/24 2:37:07

ICMP Address Mask 探测存活主机(包含完整实现代码)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ICMP Address Mask 探测存活主机(包含完整实现代码)

目录

前言

地址掩码

基本概念

常见的子网掩码

ICMP Address Mask探测存活主机原理

基本原理

工作流程

ICMP报文构造模块

响应验证模块

主探测流程

代码分析

定义ICMP地址掩码相关常量

创建ICMP连接

构造并发送数据

监听并分析响应

输出结果

源代码

其它


前言

这里讲解icmp的第三种常用探测方法,下面我进行详细讲解,从最根本的原理入手,最后给出源代码。

地址掩码

基本概念

地址掩码(也叫子网掩码)是用来区分IP地址中网络部分主机部分的32位二进制数。

常见的子网掩码

CIDR表示法 子网掩码 可用主机数 /24 255.255.255.0 254 /16 255.255.0.0 65,534 /8 255.0.0.0 16,777,214

ICMP Address Mask探测存活主机原理

基本原理

ICMP地址掩码请求/回复是ICMP协议的一种类型,用于查询主机的子网掩码信息:

  • ICMP类型17:地址掩码请求(Address Mask Request)
  • ICMP类型18:地址掩码回复(Address Mask Reply)
//请求:向目标发送地址掩码请求,掩码字段为0 请求数据: [ID][Seq][00000000] = 8字节 //响应:目标主机回复自己的子网掩码 响应数据: [ID][Seq][实际掩码] = 8字节 //示例:如果目标掩码是255.255.255.0 addressMask := binary.BigEndian.Uint32(responseData[4:8]) //addressMask = 0xFFFFFF00 (255.255.255.0)

工作流程

  1. 请求发送:向目标主机发送ICMP地址掩码请求包
  2. 存活判断:如果目标主机存活且支持该功能,会回复地址掩码信息
  3. 响应验证:通过匹配ID和序列号确认响应有效性

ICMP报文构造模块

// 地址掩码请求数据包结构 type AddressMaskRequest struct { ID uint16 // 进程ID标识 Seq uint16 // 序列号 Mask uint32 // 请求时为0,回复时为子网掩码 } // 使用RawBody构造ICMP消息体 msg := icmp.Message{ Type: ipv4.ICMPType(17), // 地址掩码请求类型 Code: 0, Body: &icmp.RawBody{ Data: addressMaskData, // 8字节数据 },

响应验证模块

// 四层验证机制 1. 来源IP验证:确认响应来自目标IP 2. ICMP类型验证:必须是类型18(地址掩码回复) 3. 数据长度验证:响应数据至少8字节 4. ID/序列号匹配:确保响应与请求对应

主探测流程

开始 ↓ 遍历IP地址列表 ↓ 启动并发探测(最多20个) ↓ 对于每个IP: ├─ 构造ICMP地址掩码请求 ├─ 发送请求包 ├─ 等待响应(总超时3秒) ├─ 验证响应有效性 └─ 记录存活主机 ↓ 等待所有探测完成 ↓ 输出结果统计 结束

代码分析

定义ICMP地址掩码相关常量

// 定义ICMP地址掩码相关常量 const ( ICMPTypeAddressMaskRequest = 17 // 地址掩码请求 ICMPTypeAddressMaskReply = 18 // 地址掩码回复 )

因为Go的icmp包中没有预定义地址掩码相关的常量

// 在 golang.org/x/net/icmp/message.go 中只有: const ( ICMPTypeEchoReply = 0 ICMPTypeDestinationUnreachable = 3 ICMPTypeEcho = 8 ICMPTypeTimeExceeded = 11 // 没有 ICMPTypeAddressMaskRequest/Reply )

创建ICMP连接

// 创建ICMP连接 conn, err := icmp.ListenPacket("ip4:icmp", "0.0.0.0") if err != nil { fmt.Printf("创建连接失败 %s: %v\n", Ip, err) return } defer conn.Close()

构造并发送数据

详细分析参考探测存活主机7的部分

// 生成唯一ID pid := uint16(os.Getpid() & 0xffff) // 构造地址掩码请求数据 (8字节) addressMaskData := make([]byte, 8) binary.BigEndian.PutUint16(addressMaskData[0:2], pid) // ID (2字节) binary.BigEndian.PutUint16(addressMaskData[2:4], uint16(seq)) // Seq (2字节) binary.BigEndian.PutUint32(addressMaskData[4:8], 0) // Address Mask (4字节,请求时为0) // 创建ICMP地址掩码请求消息 - 使用 RawBody msg := icmp.Message{ Type: ipv4.ICMPType(ICMPTypeAddressMaskRequest), Code: 0, Body: &icmp.RawBody{ Data: addressMaskData, }, } // 序列化消息 wb, err := msg.Marshal(nil) if err != nil { fmt.Printf("序列化失败 %s: %v\n", Ip, err) return } // 解析目标地址 host, err := net.ResolveIPAddr("ip4", Ip) if err != nil { fmt.Printf("解析地址失败 %s: %v\n", Ip, err) return } // 发送地址掩码请求 _, err = conn.WriteTo(wb, host) if err != nil { fmt.Printf("发送失败 %s: %v\n", Ip, err) return }

监听并分析响应

// 设置总超时 deadline := time.Now().Add(3 * time.Second) for { // 检查总超时 if time.Now().After(deadline) { return } // 设置读取超时 conn.SetReadDeadline(time.Now().Add(500 * time.Millisecond)) // 读取响应 rb := make([]byte, 1500) n, peer, err := conn.ReadFrom(rb) if err != nil { if netErr, ok := err.(net.Error); ok && netErr.Timeout() { continue // 超时继续等待 } return } // 验证响应来源IP peerIP, ok := peer.(*net.IPAddr) if !ok { continue } if peerIP.String() != Ip { continue // 不是目标IP的响应 } // 解析ICMP消息 rm, err := icmp.ParseMessage(1, rb[:n]) //告诉解析器这是ICMP协议的数据,解析出完整的ICMP消息结构 if err != nil { continue } // 检查是否为地址掩码回复 if rm.Type != ipv4.ICMPType(ICMPTypeAddressMaskReply) { fmt.Printf("非地址掩码回复 %s: Type=%d\n", Ip, rm.Type) continue } // 提取消息体数据 var responseData []byte switch body := rm.Body.(type) { case *icmp.RawBody: responseData = body.Data default: continue } // 验证响应数据长度 if len(responseData) < 8 { continue } // 解析响应中的ID和序列号 responseID := binary.BigEndian.Uint16(responseData[0:2]) responseSeq := binary.BigEndian.Uint16(responseData[2:4]) // 检查ID和序列号是否匹配 if responseID == pid && responseSeq == uint16(seq) { mu.Lock() survival[Ip] = "up" mu.Unlock() return // 收到响应,退出循环 } }

// 解析ICMP消息 rm, err := icmp.ParseMessage(1, rb[:n]) //告诉解析器这是ICMP协议的数据,解析出完整的ICMP消息结构 if err != nil { continue }

这里的1表示告诉解析器这是ICMP协议的数据,解析出完整的ICMP消息结构。

//icmp ping rm, err := icmp.ParseMessage(ipv4.ICMPTypeEchoReply.Protocol(), rb[:n]) //icmp timestamp rm, err := icmp.ParseMessage(ipv4.ICMPTypeTimestampReply.Protocol(), rb[:n]) // 它们最终都是:icmp.ParseMessage(1, rb[:n]) // 在源码中是这样定义的 func (ICMPType) Protocol() int { return 1 }

总结:

方法不依赖于具体的ICMPType值,都是告诉解析器这是ICMP协议的数据,解析出完整的ICMP消息结构的意思。

任何 ipv4.ICMPType 实例调用 Protocol() 都返回 1

甚至零值 ipv4.ICMPType(0).Protocol() 也返回 1

当然在ping里写成ICMPTypeEchoReply可读性更好,这里写1是因为Go的icmp包中没有预定义地址掩码相关的常量

// 在 golang.org/x/net/icmp/message.go 中只有: const ( ICMPTypeEchoReply = 0 ICMPTypeDestinationUnreachable = 3 ICMPTypeEcho = 8 ICMPTypeTimeExceeded = 11 // 没有 ICMPTypeAddressMaskRequest/Reply )

// 验证响应数据长度 if len(responseData) < 8 { continue }

长度必须>=8的原因:

// responseData 的8字节结构: // 字节 0-1: Identifier (2字节) // 字节 2-3: Sequence Number (2字节) // 字节 4-7: Address Mask (4字节) responseData := make([]byte, 8) // [0:2] - ID // [2:4] - 序列号 // [4:8] - 地址掩码值

输出结果

// 输出结果 fmt.Println("存活主机列表:") fmt.Println("IP地址\t\t状态") j := 0 for k, v := range survival { fmt.Printf("%s %s\n", k, v) j++ } usetime := time.Since(start) fmt.Printf("\n存活主机数量:%d\n", j) fmt.Printf("运行时间: %v\n", usetime)

源代码

直接给出最终源代码

https://github.com/yty0v0/ReconQuiver/blob/main/internal/discovery/icmp_host/addressmask.go

其它

在我写完针对多协议端口扫描和主机探测的工具后,希望通过文章整理用到的知识点,非常欢迎各位大佬指正文章内容的错误和工具的问题。

这里附上工具链接 https://github.com/yty0v0/ReconQuiver

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/23 10:31:59

2025谷歌博士奖学金学者特邀专场 ︳7位学者齐聚,分享探索之路

点击蓝字关注我们AI TIME欢迎每一位AI爱好者的加入&#xff01;AITIME012025年度谷歌博士奖学金学者特邀专场AITIME02观看地址A微信视频号直播点击预约AI TIME 视频号直播BBilibili直播进入Bilibili直播间观看&#xff0c;提问有可能会被选中由讲者回答&#xff01;欢迎关注AIT…

作者头像 李华
网站建设 2026/6/24 1:20:20

TranslucentTB 完全指南:3步实现Windows任务栏透明美化

TranslucentTB 完全指南&#xff1a;3步实现Windows任务栏透明美化 【免费下载链接】TranslucentTB A lightweight utility that makes the Windows taskbar translucent/transparent. 项目地址: https://gitcode.com/gh_mirrors/tr/TranslucentTB TranslucentTB是一款专…

作者头像 李华
网站建设 2026/6/23 16:56:38

VideoDownloadHelper视频下载助手终极指南:轻松获取在线视频资源

VideoDownloadHelper视频下载助手终极指南&#xff1a;轻松获取在线视频资源 【免费下载链接】VideoDownloadHelper Chrome Extension to Help Download Video for Some Video Sites. 项目地址: https://gitcode.com/gh_mirrors/vi/VideoDownloadHelper 还在为无法保存心…

作者头像 李华
网站建设 2026/6/24 2:33:50

CBconvert:漫画格式转换的革命性工具,让数字阅读更智能

CBconvert&#xff1a;漫画格式转换的革命性工具&#xff0c;让数字阅读更智能 【免费下载链接】cbconvert CBconvert is a Comic Book converter 项目地址: https://gitcode.com/gh_mirrors/cb/cbconvert 还在为不同设备上的漫画格式兼容性问题头疼吗&#xff1f;&…

作者头像 李华
网站建设 2026/6/22 12:22:10

DeepSeek-V3.2开源大模型企业级AI应用终极指南

DeepSeek-V3.2开源大模型企业级AI应用终极指南 【免费下载链接】DeepSeek-V3.2-Exp-Base 项目地址: https://ai.gitcode.com/hf_mirrors/deepseek-ai/DeepSeek-V3.2-Exp-Base 你是否面临企业AI部署成本高昂、技术门槛过高的困境&#xff1f;&#x1f914; 是否在为选择…

作者头像 李华
网站建设 2026/6/18 7:20:12

【AUTOSAR通信】Com简介(4)——信号过滤

信号滤波功能是可选功能&#xff0c;用户可为信号选择不同的滤波算法&#xff0c;在发送端和接收端&#xff0c;信号滤波有着不一样的功能。 1、信号接收滤波是过滤掉不想要的信号值&#xff1b; 2、信号发送滤波为计算出signal的TMC值&#xff0c;报文中所有signal的TMC决定…

作者头像 李华