eBPF: печать полезной нагрузки UDP и исходного IP-адреса в шестнадцатеричном формате

Я новичок в eBPF и хочу научиться делать несколько основных вещей. Мой вопрос заключается в том, как написать код C для моего кода eBPF, чтобы напечатать (bpf_trace_printk) полезную нагрузку UPD полученного пакета в HEX. Я пробовал безуспешно. Вот мой текущий код:

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-адрес?

Спасибо.


person Tryhard3r    schedule 17.01.2021    source источник


Ответы (1)


Я бы настоятельно рекомендовал выполнять такую ​​пост-обработку в пользовательском пространстве; bpf_trace_printk в любом случае не предназначен для производственной среды (см. большие предупреждения, которые он оставляет в системных журналах). Также будет сложно и неэффективно распечатать полезную нагрузку UDP с помощью bpf_trace_printk.


Для постобработки в пользовательском пространстве вы можете использовать bpf_skb_output или его аналог более высокого уровня в скрытой копии, perf_submit_skb(). Это позволит вам передать пакет в пользовательское пространство, которое затем сможет отобразить его полезную нагрузку UDP.

Вы можете найти руководство и пример в репозитории скрытой копии.


Что вы можете сделать на стороне BPF:

  • Напечатать src_ip в формате IP-адреса довольно просто. Вы можете следить за этим ответом StackOverflow.
  • Вы не можете распечатать полную полезную нагрузку UDP переменной длины, но вы можете распечатать первые N байтов, передав их bpf_trace_printk следующим образом.
__u32 *data = payload;
bpf_trace_printk("payload= %x %x %x\n", *data, *(data+1), *(data+2));
person pchaigno    schedule 17.01.2021
comment
Когда я это делаю, я не вижу никакого вывода из этой строки: Код: trace_printk(payload_size= %u\n, payload_size); trace_printk(a= %02x b= %02x c= %02x\n, данные, данные+1, данные+2); Вывод: ‹idle›-0 [000] ..s. 795860.863937: 0: payload_size= 15 Полезная нагрузка не печатается. - person Tryhard3r; 17.01.2021
comment
См. предупреждение: bpf.c:115:9: предупреждение: несовместимые типы указателей, инициализирующие '__u32 *' (он же 'unsigned int *') с выражением типа 'unsigned char *' [-Wincompiled-pointer-types] __u32 *dataudp = полезная нагрузка; - person Tryhard3r; 17.01.2021
comment
Может быть, попробовать что-то вроде bpf_trace_printk("payload= %x %x %x\n", *data, *(data+1), *(data+2));? Похоже, вам нужно разыменовать эти указатели, а также модификаторы формата (02 в %02x) не поддерживаются и подавляют вывод для bpf_trace_printk(). - person Qeole; 18.01.2021
comment
@Qeole прав в отношении двух ошибок. Я обновил ответ. - person pchaigno; 18.01.2021
comment
Указатель для будущих читателей: описание bpf_trace_printk() в bpf-helpers man страница содержит примечание о поддерживаемых спецификаторах и модификаторах формата. - person Qeole; 18.01.2021