【问题标题】:eBPF: printing UDP payload and source IP as hexeBPF:将 UDP 有效负载和源 IP 打印为十六进制
【发布时间】:2021-04-22 00:47:49
【问题描述】:

我是 eBPF 的新手,想学习如何做一些基本的事情。我的问题是如何为我的 eBPF 代码编写 C 代码,以便以 HEX 格式打印 (bpf_trace_printk) 获得的数据包的 UPD 有效负载。我试过没有运气。这是我当前的代码:

int udppingpong(struct __sk_buff *skb)
{
        void *data = (void *)(long)skb->data;
        void *data_end = (void *)(long)skb->data_end;
        struct ethhdr *eth  = data;
        struct iphdr  *ip;
        struct udphdr *udpdata;

        if ((void *)eth + sizeof(*eth) > data_end) {
                return TC_ACT_UNSPEC;
        }

        ip   = data + sizeof(*eth);
        if ((void *)ip + sizeof(*ip) > data_end) {
                return TC_ACT_UNSPEC;
        }

        udpdata = (void *)ip + sizeof(*ip);
        if ((void *)udpdata + sizeof(*udpdata) > data_end) {
                return TC_ACT_UNSPEC;
        }

        if (eth->h_proto != htons(ETH_P_IP)) {
                return TC_ACT_UNSPEC;
        }
        
        if (ip->protocol != IPPROTO_UDP) {
                return TC_ACT_UNSPEC;
        }

        unsigned int payload_size;
        unsigned char *payload;
        payload_size = ntohs(udpdata->len) - sizeof(*udpdata);
        payload = (unsigned char *)udpdata + sizeof(*udpdata);
        
        if ((void *)payload + payload_size > data_end) {
                return TC_ACT_UNSPEC;
        }

        __be16 port = udpdata->dest;
        __be16 portToFilter = htons(7878);

        if (port != portToFilter) {
                return TC_ACT_OK;
        }
        
        __u32 src_ip = ip->saddr;

        bpf_trace_printk("proto= %d, src= %lu\n", ip->protocol, src_ip); // --> This shows in decimal and network format (reversed), how to show actual IP like 1.2.3.4?
        bpf_trace_printk("payload= %02x\n", payload); // --> HOW? I need it in hex to compare what is received
        
        return TC_ACT_OK;
}

特别注意最后一行的痕迹。您能否帮助我了解如何以十六进制格式打印 UDP 有效负载以及源 IP?

谢谢。

【问题讨论】:

    标签: linux-kernel kernel bpf ebpf


    【解决方案1】:

    我会强烈建议在用户空间进行这种后期处理bpf_trace_printk 无论如何都不适用于生产环境(请参阅它在系统日志中留下的大量警告)。使用bpf_trace_printk 打印 UDP 有效负载也会很困难且效率低下。


    在用户空间中进行后期处理,您可以依赖bpf_skb_output,或者它在密件抄送中的更高级别对应物perf_submit_skb()。这将允许您将数据包传递给用户空间,然后用户空间可以显示其 UDP 有效负载。

    您可以在密件抄送存储库中找到tutorialan example


    在 BPF 方面你可以做什么

    • 以 IP 地址格式打印src_ip 相当容易。你可以关注this StackOverflow answer
    • 您无法打印完整的可变长度 UDP 有效负载,但您可以通过将前 N 个字节传递给 bpf_trace_printk 来打印它们,如下所示。
    __u32 *data = payload;
    bpf_trace_printk("payload= %x %x %x\n", *data, *(data+1), *(data+2));
    

    【讨论】:

    • 当我这样做时,我看不到该行的任何输出: Code: trace_printk("payload_size= %u\n", payload_size); trace_printk("a= %02x b= %02x c= %02x\n", 数据, 数据+1, 数据+2);输出:-0 [000] ..s。 795860.863937: 0: payload_size= 15 不打印有效载荷。
    • 请参阅警告:bpf.c:115:9:警告:不兼容的指针类型初始化 '__u32 *'(又名 'unsigned int *')使用类型为 'unsigned char *' [-Wincompatible -pointer-types] __u32 *dataudp = 有效载荷;
    • 也许可以试试bpf_trace_printk("payload= %x %x %x\n", *data, *(data+1), *(data+2));?看起来您需要取消引用这些指针,并且不支持格式修饰符(%02x 中的 02)并抑制 bpf_trace_printk() 的输出。
    • @Qeole 在这两个错误上是正确的。我更新了答案。
    • 未来读者的指针:bpf-helpers man page 中对bpf_trace_printk() 的描述有关于支持的格式说明符和修饰符的说明。
    猜你喜欢
    • 1970-01-01
    • 2011-04-19
    • 1970-01-01
    • 2015-02-14
    • 2012-12-14
    • 2012-11-12
    • 1970-01-01
    • 2014-09-18
    • 1970-01-01
    相关资源
    最近更新 更多