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