1

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.

Qeole
  • 8,284
  • 1
  • 24
  • 52
Tryhard3r
  • 43
  • 1
  • 7

1 Answers1

2

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));
pchaigno
  • 11,313
  • 2
  • 29
  • 54
  • When I do that, I don't see any output from that line: Code: trace_printk("payload_size= %u\n", payload_size); trace_printk("a= %02x b= %02x c= %02x\n", data, data+1, data+2); Output: -0 [000] ..s. 795860.863937: 0: payload_size= 15 The payload is not printed. – Tryhard3r Jan 17 '21 at 18:44
  • See warning: bpf.c:115:9: warning: incompatible pointer types initializing '__u32 *' (aka 'unsigned int *') with an expression of type 'unsigned char *' [-Wincompatible-pointer-types] __u32 *dataudp = payload; – Tryhard3r Jan 17 '21 at 18:46
  • 1
    Maybe try something like `bpf_trace_printk("payload= %x %x %x\n", *data, *(data+1), *(data+2));`? It looks like you need to dereference those pointers, and also format modifiers (the `02` in `%02x`) are not supported and suppress the output for `bpf_trace_printk()`. – Qeole Jan 18 '21 at 01:00
  • @Qeole is correct on the two mistakes. I updated the answer. – pchaigno Jan 18 '21 at 09:28
  • 1
    Pointer for future readers: the description of `bpf_trace_printk()` in [`bpf-helpers` man page](https://www.man7.org/linux/man-pages/man7/bpf-helpers.7.html) has a note on supported format specifiers and modifiers. – Qeole Jan 18 '21 at 09:31