当前位置: 首页 > news >正文

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

http://www.cnnetsun.cn/news/3280.html

相关文章:

  • 2025谷歌博士奖学金学者特邀专场 ︳7位学者齐聚,分享探索之路
  • TranslucentTB 完全指南:3步实现Windows任务栏透明美化
  • VideoDownloadHelper视频下载助手终极指南:轻松获取在线视频资源
  • CBconvert:漫画格式转换的革命性工具,让数字阅读更智能
  • DeepSeek-V3.2开源大模型企业级AI应用终极指南
  • 【AUTOSAR通信】Com简介(4)——信号过滤
  • 助力企业级应用开发不再头疼:DevUI组件库的实战秘籍 - 表单如何增加校验规则
  • 助力企业级应用开发不再头疼:DevUI组件库的实战秘籍 - 登陆页面样式布局完成
  • 电子战侦察干扰技术在反无人机领域的技术浅析
  • 必看!商业数据分析指标术语大全
  • GPT-5.2:创意工作的未来,会不会越来越依赖AI?
  • 收藏!网络安全赛事:大厂招聘的“捷径“,从参赛到offer的全攻略
  • IT技术从业人员如何转型转行网络安全?零基础入门到精通,收藏这零基础入门到精通指南,收藏这篇就够了
  • PC软件多系统兼容性测试覆盖策略与实践指南
  • 主流压测工具对比与应用场景分析:全链路性能验证的关键方法
  • 2025年国内主流移动端自动化测试平台深度盘点
  • 2025年移动应用渗透测试完整操作指南与技术要点
  • 2025年主流接口监控平台对比与选型指南01
  • Vibe Coding 配置的全球化:在 AI 竞赛中,如何平衡 IP 保护与知识普惠?
  • 初级黑客必看的技术—中间人攻击全解析:无线网络安全攻防技术与工具应用
  • 【必收藏】CTF网络安全竞赛入门指南:零基础小白也能快速上手,打开黑客新世界!
  • 27、Docker网络模拟与容器编排:技术详解与实践
  • 28、容器编排入门:从单主机到多主机的实践指南
  • 29、容器编排与服务发现:Helios 与 Consul 的应用实践
  • 30、容器编排与服务发现:Registrator 与 Docker Swarm 模式的应用
  • 31、Kubernetes:容器编排的强大利器
  • 32、本地开发:使用 OpenShift 运行 AWS APIs 与构建 Mesos 框架
  • 33、使用Marathon微管理Mesos及Docker平台选择
  • 34、深入解析 Docker 平台选择与安全控制
  • 35、采用 Docker 时的考虑要点与相关技术分析