tcp_metrics/tp_tcp.c
2024-07-08 07:55:39 +02:00

105 lines
3.6 KiB
C

#define BPF_NO_GLOBAL_DATA
//#define __TARGET_ARCH_x86
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>
#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 <port> -j REJECT --reject-with tcp-reset
*/
//SEC("tp/tcp_retransmit_synack")
//int tcp_retransmit(struct sock *sk){
//SEC("tracepoint/tcp/tcp_receive_reset")
SEC("tracepoint/tcp/tcp_send_reset")
int tcp_retransmit(struct ctx_reset *ctx){
struct reset *s_reset;
int keys = 0;
s_reset = bpf_map_lookup_elem(&tcp_reset_stats, &keys);
if (!s_reset){
bpf_printk("Failed to get the map");
return 0;
}
/*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];*/
//memcpy(s_reset->saddr, ctx->saddr, 4);
s_reset->saddr = (ctx->saddr[0]) +
(ctx->saddr[1] << 8) +
(ctx->saddr[2] << 16) +
(ctx->saddr[3] << 24);
__u8 saddr[4];
saddr[0] = s_reset->saddr & 0xFF;
saddr[1] = (s_reset->saddr >> 8) & 0xFF;
saddr[2] = (s_reset->saddr >> 16) & 0xFF;
saddr[3] = (s_reset->saddr >> 24) & 0xFF;
bpf_printk("Saddr: %d %d", ctx->saddr[0], ctx->saddr[1]);
bpf_printk("Saddr: %d %d", ctx->saddr[2], ctx->saddr[3]);
bpf_printk("Saddr: %d %d", saddr[0], saddr[1]);
bpf_printk("Saddr: %d %d", saddr[2], saddr[3]);
//bpf_printk("Daddr: %d %d\n", ctx->daddr[0], ctx->daddr[1]);
//bpf_printk("Daddr: %d %d\n", ctx->daddr[2], ctx->daddr[3]);
//bpf_printk("D: %d %d", s_reset->daddr[0], s_reset->daddr[1]);
//if (sizeof(ctx->daddr) == 4)
bpf_printk("%d", sizeof(struct reset));
//memcpy(s_reset->daddr, ctx->daddr, 4);
/*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 = ctx->sport;
s_reset->dport = ctx->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", s_reset->sport, s_reset->dport);
return 0;
}