int skb_in_or_egress()

in elastic-ebpf/GPL/Events/Network/Probe.bpf.c [238:340]


int skb_in_or_egress(struct __sk_buff *skb, int ingress)
{
    struct udphdr udp;
    struct bpf_sock *sk;
    u32 *tgid, cap_len, zero = 0;
    u64 *sk_addr;
    struct ebpf_dns_event *event;
    struct ebpf_varlen_field *field;

    if (skb->family != AF_INET && skb->family != AF_INET6)
        goto ignore;
    if ((sk = skb->sk) == NULL)
        goto ignore;
    if ((sk = bpf_sk_fullsock(sk)) == NULL)
        goto ignore;
    if (sk->protocol != IPPROTO_UDP)
        goto ignore;

    if (sk->family == AF_INET) {
        struct iphdr ip;

        if (bpf_skb_load_bytes(skb, 0, &ip, sizeof(ip)))
            goto ignore;
        if (ip.protocol != IPPROTO_UDP)
            goto ignore;
        if (bpf_skb_load_bytes(skb, ip.ihl << 2, &udp, sizeof(udp)))
            goto ignore;
    } else {
        goto ignore;
    }
#ifdef notyet /* ipv6 needs further work */
    else if (sk->family == AF_INET6)
    {
        int t_off;

        t_off = skb_peel_nexthdr(skb, NEXTHDR_UDP);
        if (t_off == -1)
            goto ignore;

        if (bpf_skb_load_bytes(skb, t_off, &udp, sizeof(udp)))
            goto ignore;
    }
#endif

    if (bpf_ntohs(udp.dest) != 53 && bpf_ntohs(udp.source) != 53)
        goto ignore;

    /*
     * Needed for kernels prior to f79efcb0075a20633cbf9b47759f2c0d538f78d8
     * bpf: Permits pointers on stack for helper calls
     */
    sk_addr = bpf_map_lookup_elem(&scratch64, &zero);
    if (sk_addr == NULL)
        goto ignore;
    *sk_addr = (u64)sk;
    tgid     = bpf_map_lookup_elem(&sk_to_tgid, sk_addr);
    if (tgid == NULL)
        goto ignore;

    cap_len = skb->len;
    /*
     * verifier will complain, even with a skb->len
     * check at the beginning.
     */
    if (cap_len > MAX_DNS_PACKET)
        cap_len = MAX_DNS_PACKET;

    /*
     * Yes this code is weird, but it convinces old verifiers (5.10), don't
     * blame me, be sure to test 5.10 if you change it.  The minimal packet
     * should be iphlen + udphlen + 12(dns header size). Old verifiers
     * (5.10) are very sensitive here and a non constant right expression
     * (since iphlen is not constant due to options) fails. Do what we can
     * and filter the remaining bad packets in userland, same applies to
     * ipv6. Also be careful with `if cap_len > 0`, as clang will compile it
     * to a JNZ, which doesn't adjust umin, causing the
     * bpf_skb_load_bytes() down below to think cap_len can be zero.
     */
    if (cap_len >= (sizeof(struct iphdr) + sizeof(udp) + 12)) {
        event = get_event_buffer();
        if (event == NULL)
            goto ignore;

        event->hdr.type    = EBPF_EVENT_NETWORK_DNS_PKT;
        event->hdr.ts      = bpf_ktime_get_ns();
        event->hdr.ts_boot = bpf_ktime_get_boot_ns_helper();
        event->tgid        = *tgid;
        event->cap_len     = cap_len;
        event->orig_len    = skb->len;
        event->direction   = ingress ? EBPF_NETWORK_DIR_INGRESS : EBPF_NETWORK_DIR_EGRESS;

        ebpf_vl_fields__init(&event->vl_fields);
        field = ebpf_vl_field__add(&event->vl_fields, EBPF_VL_FIELD_DNS_BODY);
        if (bpf_skb_load_bytes(skb, 0, field->data, cap_len))
            goto ignore;
        ebpf_vl_field__set_size(&event->vl_fields, field, cap_len);

        ebpf_ringbuf_write(&ringbuf, event, EVENT_SIZE(event), 0);
    }

ignore:
    return (1);
}