105 lines
3.6 KiB
C
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;
|
|
}
|