//go:build ignore #include "common.h" #include "bpf_endian.h" #include "bpf_tracing.h" #define AF_INET 2 char __license[] SEC("license") = "Dual MIT/GPL"; /** * For CO-RE relocatable eBPF programs, __attribute__((preserve_access_index)) * preserves the offset of the specified fields in the original kernel struct. * So here we don't need to include "vmlinux.h". Instead we only need to define * the kernel struct and their fields the eBPF program actually requires. * * Also note that BTF-enabled programs like fentry, fexit, fmod_ret, tp_btf, * lsm, etc. declared using the BPF_PROG macro can read kernel memory without * needing to call bpf_probe_read*(). */ /** * struct sock_common is the minimal network layer representation of sockets. * This is a simplified copy of the kernel's struct sock_common. * This copy contains only the fields needed for this example to * fetch the source and destination port numbers and IP addresses. */ struct sock_common { union { struct { // skc_daddr is destination IP address __be32 skc_daddr; // skc_rcv_saddr is the source IP address __be32 skc_rcv_saddr; }; }; union { struct { // skc_dport is the destination TCP/UDP port __be16 skc_dport; // skc_num is the source TCP/UDP port __u16 skc_num; }; }; // skc_family is the network address family (2 for IPV4) short unsigned int skc_family; } __attribute__((preserve_access_index)); /** * struct sock is the network layer representation of sockets. * This is a simplified copy of the kernel's struct sock. * This copy is needed only to access struct sock_common. */ struct sock { struct sock_common __sk_common; } __attribute__((preserve_access_index)); /** * struct tcp_sock is the Linux representation of a TCP socket. * This is a simplified copy of the kernel's struct tcp_sock. * For this example we only need srtt_us to read the smoothed RTT. */ struct tcp_sock { u32 srtt_us; } __attribute__((preserve_access_index)); struct { __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 1 << 24); } events SEC(".maps"); /** * The sample submitted to userspace over a ring buffer. * Emit struct event's type info into the ELF's BTF so bpf2go * can generate a Go type from it. */ struct event { u16 sport; u16 dport; u32 saddr; u32 daddr; u32 srtt; }; struct event *unused_event __attribute__((unused)); SEC("fentry/tcp_close") int BPF_PROG(tcp_close, struct sock *sk) { if (sk->__sk_common.skc_family != AF_INET) { return 0; } // The input struct sock is actually a tcp_sock, so we can type-cast struct tcp_sock *ts = bpf_skc_to_tcp_sock(sk); if (!ts) { return 0; } struct event *tcp_info; tcp_info = bpf_ringbuf_reserve(&events, sizeof(struct event), 0); if (!tcp_info) { return 0; } tcp_info->saddr = sk->__sk_common.skc_rcv_saddr; tcp_info->daddr = sk->__sk_common.skc_daddr; tcp_info->dport = bpf_ntohs(sk->__sk_common.skc_dport); tcp_info->sport = sk->__sk_common.skc_num; tcp_info->srtt = ts->srtt_us >> 3; tcp_info->srtt /= 1000; bpf_ringbuf_submit(tcp_info, 0); return 0; }