#define BPF_NO_GLOBAL_DATA //#define __TARGET_ARCH_x86 #include "vmlinux.h" #include #include #include #include "common.h" char LICENSE[] SEC("license") = "Dual BSD/GPL"; struct ctx_reset { __u16 common_type; __u8 common_flags; __u8 common_count; __s32 pid; const void *skaddr; __u16 sport; __u16 dport; __u16 family; __u8 saddr[4]; __u8 daddr[4]; __u8 saddr_v6[16]; __u8 daddr_v6[16]; __u64 sock_cookie; }; struct { // __uint(type, BPF_MAP_TYPE_ARRAY); __uint(type, BPF_MAP_TYPE_HASH); __uint(max_entries, 4096); __type(key, int); __type(value, sizeof(struct reset)); } tcp_reset_stats SEC(".maps"); // sudo tcpdump -i any 'tcp[13] & 4 != 0' -n -> filter TCP reset flags /* * Identify all tracepoint available * - cat /sys/kernel/tracing/available_events * Enable an event: * - echo 'tcp_receive_reset' >> /sys/kernel/tracing/set_event -> important to add the '>>' * Docs: https://docs.kernel.org/trace/events.html * https://events.linuxfoundation.org/wp-content/uploads/2022/10/elena-zannoni-tracing-tutorial-LF-2021.pdf * https://docs.kernel.org/trace/tracepoints.html * Why we need to detect RST: * When we scan the port, the scanner send an SYN flag and if the port is block, we receive a RST flag: * listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes 10:48:28.531295 lo In IP localhost.43961 > localhost.tproxy: Flags [S], seq 2197047013, win 1024, options [mss 1460], length 0 10:48:28.531306 lo In IP localhost.tproxy > localhost.43961: Flags [R.], seq 0, ack 2197047014, win 0, length 0 * But we can also block all receive RST: iptables -I INPUT -p tcp --dport -j REJECT --reject-with tcp-reset */ //SEC("tp/tcp_retransmit_synack") SEC("tracepoint/tcp/tcp_receive_reset") //int tcp_retransmit(struct sock *sk){ int tcp_retransmit(struct ctx_reset *ctx){ long long *stats; struct reset *s_reset; int keys = 0; __u16 sport = 0; __u16 dport = 0; s_reset = bpf_map_lookup_elem(&tcp_reset_stats, &keys); if (!s_reset) return 0; //*stats += 1; sport = ctx->sport; dport = ctx->dport; s_reset->saddr[0] = ctx->saddr[0]; s_reset->saddr[1] = ctx->saddr[1]; s_reset->saddr[2] = ctx->saddr[2]; s_reset->saddr[3] = ctx->saddr[3]; /*s_reset->daddr[0] = ctx->daddr[0]; s_reset->daddr[1] = ctx->daddr[1]; s_reset->daddr[2] = ctx->daddr[2]; s_reset->daddr[3] = ctx->daddr[3];*/ s_reset->sport = sport; s_reset->dport = dport; //bpf_printk("BPF detected TCP received reset %d - %d %d\n", *stats, dport, sport); bpf_printk("BPF detected TCP received reset %d %d\n", dport, sport); return 0; }