-1

我正在使用 xdp(使用 XDP_TX 操作)来构造一个 icmp resv 数据包。

linux:centos8

内核 4.18.0-80.el8.x86_64

llvm:7.0.1

clang:clang 版本 7.0.1 (tags/RELEASE_701/final)

这是我的代码:

SEC("xdp_icmp")
int _xdp_icmp(struct xdp_md *xdp)
{
    void *data_end = (void *)(long)xdp->data_end;
    void *data = (void *)(long)xdp->data;
    struct ethhdr *eth = data;
    struct iphdr *iph;
    struct icmphdr *icmph;
    __u16 h_proto;
    __be32 raddr;

    ....
    icmph = data + sizeof(*eth) + sizeof(*iph);
    if (icmph + 1 > data_end)
        return  XDP_DROP;

    if (icmph -> type != ICMP_ECHO)
    {
        return XDP_PASS;
    }

    if (handle_ipv4(xdp) != XDP_TX)
    {
        return XDP_PASS;
    }

    raddr = iph->saddr;
    swap_src_dst_mac(data);
    iph->saddr = iph->daddr;
    iph->daddr = raddr;
    icmph->type = ICMP_ECHOREPLY;
    icmph->checksum = 0;
    __u32 sum = 0;
    sum = bpf_csum_diff(0, 0, icmph, ICMP_ECHO_LEN, 0);
    icmph->checksum = csum_fold_helper(sum);
    return XDP_TX;
}

但是编译结果告诉我“验证器失败”:

错误:

libbpf: load bpf program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
...
48: (b7) r5 = 0
49: (85) call bpf_csum_diff#28
invalid access to packet, off=34 size=64, R3(id=0,off=34,r=42)
R3 offset is outside of the packet
4

1 回答 1

0

我相信在调用时:

// s64 bpf_csum_diff(__be32 *from, u32 from_size, __be32 *to, u32 to_size, __wsum seed)
sum = bpf_csum_diff(0, 0, icmph, ICMP_ECHO_LEN, 0);

作为第三个参数传递的to_size应该是字节数。假设您ICMP_ECHO_LEN从内核自测中复制,我怀疑它的值为 64,因此要求内核在 64 字节长的缓冲区上计算校验和。但是您从未检查过您的数据包有那么长(您有if (icmph + 1 > data_end),这对我来说看起来是正确的)。

我怀疑您应该尝试将标头的长度作为第三个参数传递,如下所示(未测试):

um = bpf_csum_diff(0, 0, icmph, sizeof(struct icmphdr), 0);

struct icmphdr在中定义include/uapi/linux/icmp.h并且似乎有 8 个字节的长度,尽管您不需要知道这一点,只要您为标题传递正确的长度就应该没问题。

于 2020-02-04T08:59:53.197 回答