You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 16:28:33