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

如何获取ICMP超时响应报头ID?Traceroute程序包校验问题

解决ICMP超时响应的请求匹配问题

嘿,这个问题我之前写traceroute工具的时候也踩过坑!其实超时响应里不是没有你要的ID,只是它藏的位置和回显响应不一样,得换个地方找~

核心原因:超时ICMP包的结构特殊性

当中间路由器返回TTL过期超时(ICMP类型11,代码0)的响应时,这个包的外层ICMP头ID确实是0(因为这是路由器生成的新ICMP包,它自己不需要用ID标识请求)。但路由器会把你原始发送的ICMP请求包的前若干字节(通常是前8字节,包含完整的ICMP头)嵌入到超时响应的数据字段里——这才是你要找的关键!

具体匹配步骤

你需要分两种情况处理收到的ICMP包:

  • 回显响应(类型0):直接读取外层ICMP头的ID字段,和你的进程PID对比即可
  • 超时响应(类型11,代码0):解析响应包数据字段里的内嵌原始ICMP请求头,从中提取ID(以及序列号)来匹配

额外的验证技巧

为了避免极端情况下的PID冲突(比如不同进程刚好复用了同一个PID),建议发送请求时给每个包分配递增的序列号,收到响应时同时校验ID和序列号,这样匹配的准确性会更高。

代码示例(C语言思路)

#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <unistd.h>

void process_icmp_packet(char *buf, int len) {
    struct iphdr *ip_header = (struct iphdr *)buf;
    int ip_header_len = ip_header->ihl * 4; // IP头长度(以4字节为单位)
    
    // 跳过IP头,拿到外层ICMP头
    struct icmphdr *outer_icmp = (struct icmphdr *)(buf + ip_header_len);

    if (outer_icmp->type == ICMP_ECHOREPLY) {
        // 处理回显响应:直接用外层ICMP的ID
        if (outer_icmp->un.echo.id == getpid()) {
            printf("匹配到自己的回显响应,序列号:%d\n", outer_icmp->un.echo.sequence);
        }
    } else if (outer_icmp->type == ICMP_TIME_EXCEEDED && outer_icmp->code == ICMP_EXC_TTL) {
        // 处理超时响应:解析内嵌的原始ICMP请求头
        // 跳过外层ICMP头,拿到内嵌的原始IP包(包含我们发的ICMP请求)
        struct icmphdr *inner_icmp = (struct icmphdr *)(buf + ip_header_len + sizeof(struct icmphdr));
        
        // 确认内嵌的是我们发的回显请求
        if (inner_icmp->type == ICMP_ECHO && inner_icmp->un.echo.id == getpid()) {
            printf("匹配到自己的超时响应,原始序列号:%d\n", inner_icmp->un.echo.sequence);
        }
    }
}

内容的提问来源于stack exchange,提问作者Marcin Barański

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:25:59