Search code examples
linux-kernelkernelbpfebpf

eBPF: printing UDP payload and source IP as hex


I am new in eBPF and want to learn how to do a few basic things. My question is how to write in the C code for my eBPF code in order to print (bpf_trace_printk) the UPD payload of an obtained packet in HEX. I have tried with no luck. Here is my current code:

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;
}

Special attention to the final lines with the traces. Could you help me on how to print the UDP payload in hex format as well as the source IP?

Thanks.


Solution

  • I would strongly recommend doing this sort of post processing in userspace; bpf_trace_printk isn't meant for production environment anyway (see the large warnings it leaves in syslogs). It will also be difficult and inefficient to print the UDP payload with bpf_trace_printk.


    To post-process in userspace, you can rely on bpf_skb_output, or its higher-level counterpart in bcc, perf_submit_skb(). That will allow you to pass the packet to userspace, which can then display its UDP payload.

    You can find a tutorial and an example on the bcc repository.


    What you can do on the BPF side:

    • Printing src_ip in the IP address format is fairly easy. You can follow this StackOverflow answer.
    • You can't print the full, variable-length UDP payload, but you could print the first N bytes by passing them to bpf_trace_printk as follows.
    __u32 *data = payload;
    bpf_trace_printk("payload= %x %x %x\n", *data, *(data+1), *(data+2));