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

基于XDP+BCC的NAT64中ICMP校验和错误问题求助

问题排查与修复方案

核心问题分析

从代码与tcpdump输出来看,ICMP校验和错误的根源集中在3处:ICMP校验和未包含IP伪头部、长度计算误用指针大小、IP校验和参数错误,同时头部调整顺序也存在指针偏移风险。

1. ICMP校验和未包含IP伪头部

ICMPv4校验和必须基于IP伪头部(源IPv4、目的IPv4、协议号、ICMP总长度)+ ICMP数据包(头部+数据)计算,你当前仅计算了ICMP头部本身,这是校验和错误的核心原因。

2. sizeof(icmp)导致长度计算错误

icmp是指针类型,sizeof(icmp)在64位系统中为8字节,而非实际ICMP头部/数据包长度,直接使用会导致校验和计算的长度参数错误。

3. IP校验和计算参数错误

你使用bpf_csum_diff((__be32 *)&dst_hdr, 0, (__be32 *)&dst_hdr, sizeof(dst_hdr), 0)计算IP校验和时,第一个参数应为NULL(表示无旧数据),当前传入同一份数据会导致计算逻辑偏差。

4. 头部调整顺序引发指针失效

先调整ICMP头部长度再调整IP头部长度,会导致之前的ICMP指针偏移失效,建议先完成IPv6到IPv4的头部替换,再处理ICMP转换。


具体修复步骤

修复ICMP校验和计算

构造IP伪头部,再结合ICMP数据包计算校验和:

// 构造ICMP伪头部(必须按网络字节序对齐)
struct {
    __be32 src_ip;
    __be32 dst_ip;
    __u8   zero;
    __u8   proto;
    __be16 icmp_len;
} __attribute__((packed)) icmp_pseudo;

icmp_pseudo.src_ip = dst_hdr.saddr;
icmp_pseudo.dst_ip = dst_hdr.daddr;
icmp_pseudo.zero = 0;
icmp_pseudo.proto = IPPROTO_ICMP;
// ICMP总长度 = 原IPv6 payload长度 - ICMPv6头部长度 + ICMPv4头部长度
icmp_pseudo.icmp_len = bpf_htons(bpf_ntohs(ip6h->payload_len) - sizeof(struct icmp6hdr) + sizeof(struct icmphdr));

// 重置ICMP校验和字段
icmp->checksum = 0;

// 先计算伪头部的校验和,再叠加ICMP数据包的校验和
__u64 csum = bpf_csum_diff(NULL, 0, (__be32 *)&icmp_pseudo, sizeof(icmp_pseudo), 0);
csum = bpf_csum_diff(NULL, 0, (__be32 *)icmp, bpf_ntohs(icmp_pseudo.icmp_len), csum);
icmp->checksum = csum_fold_helper(csum);

修复长度计算错误

将所有sizeof(icmp)替换为sizeof(struct icmphdr)或实际ICMP数据包长度,避免指针大小干扰。

修复IP校验和计算

// 先重置IP校验和字段
dst_hdr.check = 0;
// 正确计算IP头部校验和:无旧数据,直接计算整个IPv4头部的校验和
dst_hdr.check = csum_fold_helper(bpf_csum_diff(NULL, 0, (__be32 *)&dst_hdr, sizeof(dst_hdr), 0));

调整头部修改顺序

建议按以下流程操作,避免指针偏移混乱:

  1. 拷贝以太网头部到临时变量
  2. 构造并计算IPv4头部校验和
  3. 调整头部长度,完成IPv6到IPv4的替换
  4. 重新定位数据包指针,处理ICMPv6到ICMPv4的转换
  5. 计算ICMP校验和

额外验证点

  • 确认write_icmp函数正确转换类型:ICMPv6 Echo Request(type 128)对应ICMPv4 Echo Request(type 8),ICMPv6 Echo Reply(type 129)对应ICMPv4 Echo Reply(type 0),ID与序列号需直接拷贝网络字节序值。
  • 验证IPv4的tot_len计算:bpf_htons(bpf_ntohs(ip6h->payload_len) + sizeof(dst_hdr))需确保等于以太网头部后的总长度。
  • 用bpf_trace_printk打印计算出的ICMP校验和,与tcpdump显示的预期值6fc9对比,确认是否匹配。

内容的提问来源于stack exchange,提问作者CiZ

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 08:36:01