Go语言icmp.ListenPacket接收ICMP包始终长度为0的问题求助
UDP端口探测中ICMP监听消息为空的问题
核心需求是通过向UDP端口发送数据、监听ICMP端口不可达消息来探测开放UDP端口。使用以下Go函数作为goroutine运行:
func listenIcmp(ipAddr string) { conn, err := icmp.ListenPacket("ip4:1", ipAddr) if err != nil { log.Println("Error while listening for ICMP packets: ") log.Println(err) } for { var incoming []byte length, sourceIP, err := conn.ReadFrom(incoming) if err != nil { log.Println(err) continue } log.Printf("message = '%s', length = %d, source-ip = %s", string(incoming), length, sourceIP) } }
该函数能检测到ICMP ping和目标不可达消息,但始终返回长度为0的空消息,示例日志:
2023/10/11 14:38:32 message = '', length = 0, source-ip = 127.0.0.1
尝试解析消息时因内容为空触发运行时错误,已赋予程序root权限,操作系统为Ubuntu 20.04,问题仍存在。
问题原因
var incoming []byte声明的是nil切片,其长度和容量均为0,ReadFrom方法无法向nil切片写入任何数据,因此返回读取长度为0。
解决方案
初始化一个足够大的字节切片作为缓冲区,用于存储ICMP数据包内容。ICMP数据包大小通常不会超过MTU(一般为1500字节),因此可以初始化一个长度为1500的切片。同时建议添加defer conn.Close()避免资源泄漏。
修改后的代码:
func listenIcmp(ipAddr string) { conn, err := icmp.ListenPacket("ip4:1", ipAddr) if err != nil { log.Println("Error while listening for ICMP packets: ") log.Println(err) return } defer conn.Close() // 确保连接关闭,避免资源泄漏 for { incoming := make([]byte, 1500) // 初始化足够大的缓冲区 length, sourceIP, err := conn.ReadFrom(incoming) if err != nil { log.Println(err) continue } log.Printf("message = '%s', length = %d, source-ip = %s", string(incoming[:length]), length, sourceIP) // 使用incoming[:length]截取实际读取到的内容,避免多余空字节 } }
额外说明
- 使用
incoming[:length]截取实际读取到的字节范围,避免日志中出现多余的空字符 - 确保程序以root权限运行(ICMP监听需要raw socket权限),Ubuntu下可通过
sudo ./your-program执行
内容的提问来源于stack exchange,提问作者Thibault
相关产品推荐
相关产品推荐

