bpf/headers/inspector.h (192 lines of code) (raw):

/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ // +build ignore #pragma once #include <bpf/bpf_endian.h> #include "bpf_core_read.h" #include "bpf_helpers.h" #include "bpf_tracing.h" #include "vmlinux.h" #define ETH_P_IP 0x800 #define ETH_P_IPV6 0x86dd #define PF_INET 2 /* IP protocol family. */ #define PF_INET6 10 /* IP version 6. */ #define MAX_STACK_TP 20 #define TASK_COMM_LEN 20 #define KERN_STACKID_FLAGS (0 | BPF_F_FAST_STACK_CMP) #define USER_STACKID_FLAGS (0 | BPF_F_FAST_STACK_CMP | BPF_F_USER_STACK) #define PERF_MAX_STACK_DEPTH 32 struct flow_tuple_4 { unsigned char proto; u32 src; u32 dst; u16 sport; u16 dport; }; union addr { unsigned char v6addr[16]; u32 v4addr; } __attribute__((packed)); const union addr *unused_addr __attribute__((unused)); struct skb_meta { u32 netns; u32 mark; u32 ifindex; u32 len; u32 mtu; u32 sk_state; u16 protocol; u16 pad; } __attribute__((packed)); struct tuple { union addr saddr; union addr daddr; u16 sport; u16 dport; u16 l3_proto; u8 l4_proto; u8 pad; } __attribute__((packed)); static __always_inline u16 get_sock_protocol(struct sock *sock) { u16 protocol = 0; #ifndef CORE #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 6, 0)) // kernel 4.18-5.5: sk_protocol bit-field: use sk_gso_max_segs field and go // back 24 bits to reach sk_protocol field index. bpf_probe_read(&protocol, 1, (void *)(&sock->sk_gso_max_segs) - 3); #else // kernel 5.6 protocol = READ_KERN(sock->sk_protocol); #endif #else // CORE // commit bf9765145b85 ("sock: Make sk_protocol a 16-bit value") struct sock___old *check = NULL; if (bpf_core_field_exists(check->__sk_flags_offset)) { check = (struct sock___old *)sock; bpf_core_read(&protocol, 1, (void *)(&check->sk_gso_max_segs) - 3); } else { protocol = READ_KERN(sock->sk_protocol); } #endif return protocol; } static __always_inline u32 get_sock_netns(struct sock *sk) { u32 netns; netns = BPF_CORE_READ(sk, __sk_common.skc_net.net, ns.inum); return netns; } static __always_inline u32 get_netns(struct sk_buff *skb) { u32 netns; struct net_device *dev = BPF_CORE_READ(skb, dev); // Get netns id. The code below is equivalent to: netns = // dev->nd_net.net->ns.inum netns = BPF_CORE_READ(dev, nd_net.net, ns.inum); // maybe the skb->dev is not init, for this situation, we can get ns by // sk->__sk_common.skc_net.net->ns.inum if (netns == 0) { struct sock *sk; sk = BPF_CORE_READ(skb, sk); if (sk != NULL) { netns = BPF_CORE_READ(sk, __sk_common.skc_net.net, ns.inum); } } return netns; } static __always_inline int set_flow_tuple4(struct __sk_buff *skb, struct flow_tuple_4 *tuple, bool port){ void *data = (void *)(long)skb->data; struct ethhdr *eth = data; void *data_end = (void *)(long)skb->data_end; u16 l4_off = 0; //u16 bytes = 0; if (data + sizeof(*eth) > data_end) return -1; if (eth->h_proto == bpf_htons(ETH_P_IP)) { struct iphdr *iph = data + sizeof(*eth); if (data + sizeof(*eth) + sizeof(*iph) > data_end) return -1; tuple->src = iph->saddr; tuple->dst = iph->daddr; tuple->proto = iph->protocol; if (!port){ return 0; } l4_off = sizeof(*eth) + iph->ihl * 4; if (iph->protocol == IPPROTO_TCP){ struct tcphdr *tcph = data + l4_off; if (data + l4_off + sizeof(*tcph) > data_end) return -1; tuple->sport = tcph->source; tuple->dport = tcph->dest; //bytes = tcph->doff * 4; }else if(iph->protocol == IPPROTO_UDP){ struct udphdr *udph = data + l4_off; if(data + l4_off + sizeof(*udph) > data_end) return -1; tuple->sport = udph->source; tuple->dport = udph->dest; //bytes = tcph->len; } } else if (eth->h_proto == bpf_htons(ETH_P_IPV6)) { //not supported yet } return 0; } static __always_inline int set_tuple(struct sk_buff *skb, struct tuple *tpl) { unsigned char *skb_head = 0; u16 l3_off; u16 l4_off; struct iphdr *ip; u8 iphdr_first_byte; u8 ip_vsn; skb_head = BPF_CORE_READ(skb, head); l3_off = BPF_CORE_READ(skb, network_header); l4_off = BPF_CORE_READ(skb, transport_header); if (l3_off == 0){ return -1; } ip = (struct iphdr *)(skb_head + l3_off); bpf_probe_read(&iphdr_first_byte, 1, ip); ip_vsn = iphdr_first_byte >> 4; if (ip_vsn == 4) { bpf_probe_read(&tpl->saddr, sizeof(tpl->saddr.v4addr), &ip->saddr); bpf_probe_read(&tpl->daddr, sizeof(tpl->daddr.v4addr), &ip->daddr); bpf_probe_read(&tpl->l4_proto, 1, &ip->protocol); tpl->l3_proto = ETH_P_IP; } else if (ip_vsn == 6) { struct ipv6hdr *ip6 = (struct ipv6hdr *)ip; bpf_probe_read(&tpl->saddr, sizeof(tpl->saddr), &ip6->saddr); bpf_probe_read(&tpl->daddr, sizeof(tpl->daddr), &ip6->daddr); bpf_probe_read(&tpl->l4_proto, 1, &ip6->nexthdr); tpl->l3_proto = ETH_P_IPV6; }else { return -1; } if (tpl->l4_proto == IPPROTO_TCP) { struct tcphdr *tcp = (struct tcphdr *)(skb_head + l4_off); bpf_probe_read(&tpl->sport, sizeof(tpl->sport), &tcp->source); bpf_probe_read(&tpl->dport, sizeof(tpl->dport), &tcp->dest); } else if (tpl->l4_proto == IPPROTO_UDP) { struct udphdr *udp = (struct udphdr *)(skb_head + l4_off); bpf_probe_read(&tpl->sport, sizeof(tpl->sport), &udp->source); bpf_probe_read(&tpl->dport, sizeof(tpl->dport), &udp->dest); } tpl->sport = bpf_htons(tpl->sport); tpl->dport = bpf_htons(tpl->dport); return 0; } static __always_inline void set_meta(struct sk_buff *skb, struct skb_meta *meta) { meta->netns = get_netns(skb); meta->mark = BPF_CORE_READ(skb, mark); meta->len = BPF_CORE_READ(skb, len); meta->protocol = BPF_CORE_READ(skb, protocol); meta->ifindex = BPF_CORE_READ(skb, dev, ifindex); meta->mtu = BPF_CORE_READ(skb, dev, mtu); } static __always_inline void set_meta_sock(struct sock *sk, struct skb_meta *meta) { meta->netns = BPF_CORE_READ(sk, __sk_common.skc_net.net, ns.inum); meta->protocol = get_sock_protocol(sk); // meta->sk_state = BPF_CORE_READ(sk, __sk_common.skc_state); } static __always_inline void set_tuple_sock(struct sock *sk, struct tuple *tpl) { short unsigned int skc_family; skc_family = BPF_CORE_READ(sk, __sk_common.skc_family); if (skc_family == PF_INET6) { // TODO: add v6 sock support tpl->l3_proto = ETH_P_IPV6; } else { bpf_probe_read(&tpl->saddr, sizeof(tpl->saddr.v4addr), &sk->__sk_common.skc_rcv_saddr); bpf_probe_read(&tpl->daddr, sizeof(tpl->daddr.v4addr), &sk->__sk_common.skc_daddr); tpl->l3_proto = ETH_P_IP; } tpl->sport = BPF_CORE_READ(sk, __sk_common.skc_num); tpl->dport = BPF_CORE_READ(sk, __sk_common.skc_dport); tpl->l4_proto = get_sock_protocol(sk); ; }