Update project
This commit is contained in:
parent
b45084ec06
commit
1f53a2b4d2
9
common.h
9
common.h
@ -1,11 +1,18 @@
|
|||||||
#ifndef H_COMMON
|
#ifndef H_COMMON
|
||||||
#define H_COMMON
|
#define H_COMMON
|
||||||
|
|
||||||
|
typedef unsigned char __u8;
|
||||||
|
typedef unsigned short __u16;
|
||||||
|
typedef unsigned int __u32;
|
||||||
|
typedef unsigned long long __u64;
|
||||||
|
|
||||||
struct reset {
|
struct reset {
|
||||||
__u8 saddr[4];
|
__u8 saddr[4];
|
||||||
__u8 daddr[4];
|
__u8 daddr[4];
|
||||||
__u16 sport;
|
__u16 sport;
|
||||||
__u16 dport;
|
__u16 dport;
|
||||||
};
|
__u16 family;
|
||||||
|
__u16 proto;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
5
exec.sh
Executable file
5
exec.sh
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
#!/usr/bin/sh
|
||||||
|
|
||||||
|
clang-11 -g -O2 -target bpf -c tp_tcp.c -o tp_tcp.o && \
|
||||||
|
gcc load_bpf.c -o load_bpf -lbpf && \
|
||||||
|
sudo ./load_bpf
|
24
influxdb.py
Normal file
24
influxdb.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import influxdb_client
|
||||||
|
from influxdb_client import InfluxDBClient, Point, WritePrecision
|
||||||
|
from influxdb_client.client.write_api import SYNCHRONOUS
|
||||||
|
import os
|
||||||
|
|
||||||
|
#token = os.environ.get("dQV0BbJvy7W9Bool6FGh1ryb_uXBNqZB8BlJqb8yC4yNB8RTDSooT5hixoqMf8cBeXUXTRUdmkwlxnkI9PCsBA==")
|
||||||
|
token = os.environ.get("sySU58aCfMdTGtBTttduzSS_x_4CBI1twpicYw4Idq9abZWGsAXdbvww2wWmwmLDTtrALAx4Q0wZK9PUIr4ejg==")
|
||||||
|
org = "gbucchino"
|
||||||
|
url = "http://192.168.1.68:8086"
|
||||||
|
|
||||||
|
write_client = influxdb_client.InfluxDBClient(url=url, token=token, org=org)
|
||||||
|
|
||||||
|
bucket="tcp"
|
||||||
|
|
||||||
|
write_api = write_client.write_api(write_options=SYNCHRONOUS)
|
||||||
|
|
||||||
|
for value in range(5):
|
||||||
|
point = (
|
||||||
|
Point("measurement1")
|
||||||
|
.tag("tagname1", "tagvalue1")
|
||||||
|
.field("field1", value)
|
||||||
|
)
|
||||||
|
write_api.write(bucket=bucket, org="gbucchino", record=point)
|
||||||
|
time.sleep(1) # separate points by 1 second
|
BIN
load_bpf
BIN
load_bpf
Binary file not shown.
73
load_bpf.c
73
load_bpf.c
@ -5,6 +5,7 @@
|
|||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
static void clean_obj(struct bpf_object *obj){
|
static void clean_obj(struct bpf_object *obj){
|
||||||
printf("Cleaning\n");
|
printf("Cleaning\n");
|
||||||
@ -18,8 +19,12 @@ int main(void){
|
|||||||
struct reset s_reset;
|
struct reset s_reset;
|
||||||
int err;
|
int err;
|
||||||
int map_fd;
|
int map_fd;
|
||||||
long long stats;
|
int map_fd_filter_family;
|
||||||
|
int map_fd_filter_sport;
|
||||||
|
int map_fd_index;
|
||||||
int keys = 0;
|
int keys = 0;
|
||||||
|
int indexPackets = 0;
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
obj = bpf_object__open_file(fileObj, NULL);
|
obj = bpf_object__open_file(fileObj, NULL);
|
||||||
if (!obj){
|
if (!obj){
|
||||||
@ -27,19 +32,20 @@ int main(void){
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
//LIBBPF_OPTS(bpf_map_create_opts, opts, .map_flags = BPF_F_MMAPABLE);
|
//LIBBPF_OPTS(bpf_map_create_opts, opts, .map_flags = BPF_F_MMAPABLE);
|
||||||
map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(int), sizeof(struct reset), 4096, BPF_ANY);
|
//map_fd = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(int), sizeof(struct reset), 4096, BPF_ANY);
|
||||||
printf("Create map: %d\n", map_fd);
|
//map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(int), sizeof(struct reset), 4096, BPF_ANY);
|
||||||
|
|
||||||
err = bpf_object__load(obj);
|
err = bpf_object__load(obj);
|
||||||
printf("Object loaded: %d\n", err);
|
|
||||||
if (err){
|
if (err){
|
||||||
printf("Failed to load object\n");
|
printf("Failed to load object\n");
|
||||||
|
clean_obj(obj);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
program = bpf_object__find_program_by_name(obj, "tcp_retransmit");
|
program = bpf_object__find_program_by_name(obj, "tcp_retransmit");
|
||||||
if (!program){
|
if (!program){
|
||||||
printf("Failed to find the program\n");
|
printf("Failed to find the program\n");
|
||||||
|
clean_obj(obj);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,7 +57,25 @@ int main(void){
|
|||||||
}
|
}
|
||||||
|
|
||||||
map_fd = bpf_object__find_map_fd_by_name(obj, "tcp_reset_stats");
|
map_fd = bpf_object__find_map_fd_by_name(obj, "tcp_reset_stats");
|
||||||
printf("Map fd: %d\n", map_fd);
|
if (map_fd < 0){
|
||||||
|
printf("Failed to find the map 'tcp_reset_stats'\n");
|
||||||
|
clean_obj(obj);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
map_fd_filter_family = bpf_object__find_map_fd_by_name(obj, "filter_family");
|
||||||
|
if (map_fd_filter_family < 0){
|
||||||
|
printf("Failed to find the map 'filter_family'\n");
|
||||||
|
clean_obj(obj);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
map_fd_index = bpf_object__find_map_fd_by_name(obj, "tcp_stats_index");
|
||||||
|
if (map_fd_index < 0){
|
||||||
|
printf("Failed to find the map 'tcp_stats_index'\n");
|
||||||
|
clean_obj(obj);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
struct bpf_link *link = bpf_program__attach(program);
|
struct bpf_link *link = bpf_program__attach(program);
|
||||||
if (!link){
|
if (!link){
|
||||||
@ -59,15 +83,40 @@ int main(void){
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sepcify our filters
|
||||||
|
/*
|
||||||
|
* IPv4: AF_INET -> 2
|
||||||
|
* IPv6: AF_INET6 -> 10
|
||||||
|
*/
|
||||||
|
__s16 f = AF_INET;
|
||||||
|
err = bpf_map_update_elem(map_fd_filter_family, &keys, &f, BPF_ANY);
|
||||||
|
|
||||||
|
|
||||||
while(1){
|
while(1){
|
||||||
int e = bpf_map_lookup_elem(map_fd, &keys, &s_reset);
|
// Get the index
|
||||||
if (e == 0){
|
// and we compare with the local variable
|
||||||
//printf("%lld\n", stats);
|
// If it's different, we get the new variable
|
||||||
struct in_addr *src = (struct in_addr*)&s_reset.saddr;
|
err = bpf_map_lookup_elem(map_fd_index, &keys, &indexPackets);
|
||||||
struct in_addr *dest = (struct in_addr*)&s_reset.daddr;
|
|
||||||
printf("Sport: %d; dport: %d %s %s\n", s_reset.sport, s_reset.dport, inet_ntoa(*src), inet_ntoa(*dest));
|
// We have a new packet
|
||||||
|
if (indexPackets > index){
|
||||||
|
index = indexPackets;
|
||||||
|
printf("Index: %d %d\n", index, indexPackets);
|
||||||
|
err = bpf_map_lookup_elem(map_fd, &keys, &s_reset);
|
||||||
|
if (err == 0){
|
||||||
|
struct in_addr *src = (struct in_addr*)&s_reset.saddr;
|
||||||
|
struct in_addr *dest = (struct in_addr*)&s_reset.daddr;
|
||||||
|
char *s = inet_ntoa(*src);
|
||||||
|
char tmp[35];
|
||||||
|
memcpy(tmp, s, 35);
|
||||||
|
char *d = inet_ntoa(*dest);
|
||||||
|
|
||||||
|
printf("Sport: %d; dport: %d %d %d %s - %s\n", s_reset.sport, s_reset.dport, s_reset.family, s_reset.proto, tmp, d);
|
||||||
|
|
||||||
|
}
|
||||||
|
memset(&s_reset, 0, sizeof(struct reset));
|
||||||
|
//sleep(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
BIN
main
BIN
main
Binary file not shown.
21
main.c
21
main.c
@ -1,12 +1,25 @@
|
|||||||
#define BPF_NO_GLOBAL_DATA
|
#define BPF_NO_GLOBAL_DATA
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <linux/bpf.h>
|
#include "ic.h"
|
||||||
#include <bpf/bpf_helpers.h>
|
|
||||||
#include <bpf/bpf_tracing.h>
|
|
||||||
|
|
||||||
int main(int argc, char *argv[], char *argp[]){
|
int main(int argc, char *argv[], char *argp[]){
|
||||||
printf("Hello world\n");
|
printf("Hello world\n");
|
||||||
execve("/usr/bin/ls", argv, argp);
|
char buf[300];
|
||||||
|
|
||||||
|
ic_influx_database("192.168.1.68", 8086, "tcp");
|
||||||
|
ic_influx_userpw("admin", "Geta,Fte#");
|
||||||
|
ic_debug(2);
|
||||||
|
|
||||||
|
snprintf(buf, 300, "host=192.168.1.68");
|
||||||
|
ic_tags(buf);
|
||||||
|
|
||||||
|
ic_measure("tcp_reset");
|
||||||
|
|
||||||
|
ic_string("ipsrc", "192.168.1.1");
|
||||||
|
|
||||||
|
ic_measureend();
|
||||||
|
ic_push();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
9
main.py
Normal file
9
main.py
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from bcc import BPF
|
||||||
|
|
||||||
|
with open("tp_tcp.c", 'r') as f:
|
||||||
|
data = f.read()
|
||||||
|
|
||||||
|
b = BPF(text=data)
|
||||||
|
#b = BPF(src_file="tp_tcp_py.c")
|
30
prometheus.py
Normal file
30
prometheus.py
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
from prometheus_client import start_http_server, Summary, Counter
|
||||||
|
import random
|
||||||
|
import time
|
||||||
|
|
||||||
|
# Create a metric to track time spent and requests made.
|
||||||
|
#REQUEST_TIME = Summary('request_processing_seconds', 'Time spent processing request', 'foo')
|
||||||
|
#REQUEST_TIME = Summary('request_processing_seconds', 'foo')
|
||||||
|
|
||||||
|
|
||||||
|
# Decorate function with metric.
|
||||||
|
#@REQUEST_TIME.time()
|
||||||
|
#def process_request(t):
|
||||||
|
# """A dummy function that takes some time."""
|
||||||
|
# time.sleep(t)
|
||||||
|
|
||||||
|
c = Counter("tcp_reset_stats", "TCP RST stats")
|
||||||
|
def tcp_rst_stats():
|
||||||
|
c.inc()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
# Start up the server to expose the metrics.
|
||||||
|
start_http_server(8000)
|
||||||
|
# Generate some requests.
|
||||||
|
while True:
|
||||||
|
# process_request(random.random())
|
||||||
|
|
||||||
|
# Count
|
||||||
|
print("Inc")
|
||||||
|
tcp_rst_stats()
|
||||||
|
time.sleep(30)
|
124
tp_tcp.c
124
tp_tcp.c
@ -1,6 +1,7 @@
|
|||||||
#define BPF_NO_GLOBAL_DATA
|
#define BPF_NO_GLOBAL_DATA
|
||||||
//#define __TARGET_ARCH_x86
|
//#define __TARGET_ARCH_x86
|
||||||
#include "vmlinux.h"
|
#include "vmlinux.h"
|
||||||
|
#include <string.h>
|
||||||
#include <bpf/bpf_helpers.h>
|
#include <bpf/bpf_helpers.h>
|
||||||
#include <bpf/bpf_tracing.h>
|
#include <bpf/bpf_tracing.h>
|
||||||
#include <bpf/bpf_core_read.h>
|
#include <bpf/bpf_core_read.h>
|
||||||
@ -9,11 +10,11 @@
|
|||||||
char LICENSE[] SEC("license") = "Dual BSD/GPL";
|
char LICENSE[] SEC("license") = "Dual BSD/GPL";
|
||||||
|
|
||||||
|
|
||||||
struct ctx_reset {
|
struct ctx_receive_reset {
|
||||||
__u16 common_type;
|
__u16 common_type; // unsigned short
|
||||||
__u8 common_flags;
|
__u8 common_flags; // unsigned char
|
||||||
__u8 common_count;
|
__u8 common_count; // unsigned char
|
||||||
__s32 pid;
|
__s32 pid; // int
|
||||||
|
|
||||||
const void *skaddr;
|
const void *skaddr;
|
||||||
__u16 sport;
|
__u16 sport;
|
||||||
@ -25,17 +26,59 @@ struct ctx_reset {
|
|||||||
__u8 daddr_v6[16];
|
__u8 daddr_v6[16];
|
||||||
__u64 sock_cookie;
|
__u64 sock_cookie;
|
||||||
};
|
};
|
||||||
|
struct ctx_send_reset {
|
||||||
|
__u16 common_type; // unsigned short
|
||||||
|
__u8 common_flags; // unsigned char
|
||||||
|
__u8 common_count; // unsigned char
|
||||||
|
__s32 pid; // int
|
||||||
|
|
||||||
|
const void *skbaddr;
|
||||||
|
const void *skaddr;
|
||||||
|
__s32 state; // int
|
||||||
|
__u16 sport;
|
||||||
|
__u16 dport;
|
||||||
|
__u8 saddr[4];
|
||||||
|
__u8 daddr[4];
|
||||||
|
__u8 saddr_v6[16];
|
||||||
|
__u8 daddr_v6[16];
|
||||||
|
};
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
// __uint(type, BPF_MAP_TYPE_ARRAY);
|
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||||
__uint(type, BPF_MAP_TYPE_HASH);
|
|
||||||
__uint(max_entries, 4096);
|
__uint(max_entries, 4096);
|
||||||
__type(key, int);
|
__type(key, 1);
|
||||||
__type(value, sizeof(struct reset));
|
__type(value, __s32);
|
||||||
|
} tcp_stats_index SEC(".maps");
|
||||||
|
|
||||||
|
struct {
|
||||||
|
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||||
|
__uint(max_entries, 4096);
|
||||||
|
__type(key, 4);
|
||||||
|
__type(value, struct reset);
|
||||||
} tcp_reset_stats SEC(".maps");
|
} tcp_reset_stats SEC(".maps");
|
||||||
|
|
||||||
|
struct {
|
||||||
|
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||||
|
__uint(max_entries, 1);
|
||||||
|
__type(key, __s32);
|
||||||
|
__type(value, __u16);
|
||||||
|
} filter_family SEC(".maps");
|
||||||
|
|
||||||
|
struct {
|
||||||
|
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||||
|
__uint(max_entries, 1);
|
||||||
|
__type(key, __s32);
|
||||||
|
__type(value, __u16);
|
||||||
|
} filter_sport SEC(".maps");
|
||||||
|
|
||||||
// sudo tcpdump -i any 'tcp[13] & 4 != 0' -n -> filter TCP reset flags
|
// sudo tcpdump -i any 'tcp[13] & 4 != 0' -n -> filter TCP reset flags
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This project do not trace any sniffing ports, because, the tracepoint tcp:tcp_send_reset
|
||||||
|
* works only for an establish socket, but, if you have a lot of TCP RST, you can have
|
||||||
|
* an issue with your system
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Identify all tracepoint available
|
* Identify all tracepoint available
|
||||||
* - cat /sys/kernel/tracing/available_events
|
* - cat /sys/kernel/tracing/available_events
|
||||||
@ -53,33 +96,54 @@ struct {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
//SEC("tp/tcp_retransmit_synack")
|
//SEC("tp/tcp_retransmit_synack")
|
||||||
SEC("tracepoint/tcp/tcp_receive_reset")
|
//SEC("tracepoint/tcp/tcp_receive_reset")
|
||||||
//int tcp_retransmit(struct sock *sk){
|
SEC("tracepoint/tcp/tcp_send_reset")
|
||||||
int tcp_retransmit(struct ctx_reset *ctx){
|
int tcp_retransmit(struct ctx_send_reset *ctx){
|
||||||
long long *stats;
|
struct reset s_reset = {};
|
||||||
struct reset *s_reset;
|
int *index;
|
||||||
int keys = 0;
|
int keys = 0;
|
||||||
|
struct sock *sk;
|
||||||
|
__u16 family;
|
||||||
|
__s16 *f_family;
|
||||||
|
__u16 proto;
|
||||||
|
int err;
|
||||||
|
|
||||||
s_reset = bpf_map_lookup_elem(&tcp_reset_stats, &keys);
|
memset(&s_reset, 0, sizeof(struct reset));
|
||||||
if (!s_reset)
|
|
||||||
|
// Get filter
|
||||||
|
sk = (struct sock*)ctx->skaddr;
|
||||||
|
f_family = bpf_map_lookup_elem(&filter_family, &keys);
|
||||||
|
if (!f_family)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!ctx)
|
index = bpf_map_lookup_elem(&tcp_stats_index, &keys);
|
||||||
|
if (!index)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
//*stats += 1;
|
|
||||||
s_reset->saddr[0] = ctx->saddr[0];
|
// Get the family of the socket
|
||||||
s_reset->saddr[1] = ctx->saddr[1];
|
bpf_probe_read_kernel(&family, sizeof(family), &sk->__sk_common.skc_family);
|
||||||
s_reset->saddr[2] = ctx->saddr[2];
|
if (family != *f_family)
|
||||||
s_reset->saddr[3] = ctx->saddr[3];
|
return 0;
|
||||||
/*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);
|
// Get and update the index in the map
|
||||||
bpf_printk("BPF detected TCP received reset %d %d\n", s_reset->sport, s_reset->dport);
|
*index += 1;
|
||||||
|
|
||||||
|
// Proto type: here it's 6 (TCP)
|
||||||
|
bpf_probe_read_kernel(&proto, sizeof(proto), &sk->sk_protocol);
|
||||||
|
|
||||||
|
memcpy(s_reset.saddr, ctx->saddr, 4);
|
||||||
|
memcpy(s_reset.daddr, ctx->daddr, 4);
|
||||||
|
|
||||||
|
//bpf_probe_read_kernel(&s_reset.saddr, 4, &ctx->saddr);
|
||||||
|
//bpf_probe_read_kernel(&s_reset.daddr, 4, &ctx->daddr);
|
||||||
|
|
||||||
|
s_reset.sport = ctx->sport;
|
||||||
|
s_reset.dport = ctx->dport;
|
||||||
|
s_reset.family = family;
|
||||||
|
s_reset.proto = proto;
|
||||||
|
|
||||||
|
bpf_printk("BPF detected TCP send reset %d %d", s_reset.sport, s_reset.dport);
|
||||||
|
bpf_map_update_elem(&tcp_reset_stats, &keys, &s_reset, BPF_ANY);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
BIN
tp_tcp.o
BIN
tp_tcp.o
Binary file not shown.
149
tp_tcp_py.c
Normal file
149
tp_tcp_py.c
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
#define BPF_NO_GLOBAL_DATA
|
||||||
|
//#define __TARGET_ARCH_x86
|
||||||
|
#include "vmlinux.h"
|
||||||
|
#include <string.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_receive_reset {
|
||||||
|
__u16 common_type; // unsigned short
|
||||||
|
__u8 common_flags; // unsigned char
|
||||||
|
__u8 common_count; // unsigned char
|
||||||
|
__s32 pid; // int
|
||||||
|
|
||||||
|
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 ctx_send_reset {
|
||||||
|
__u16 common_type; // unsigned short
|
||||||
|
__u8 common_flags; // unsigned char
|
||||||
|
__u8 common_count; // unsigned char
|
||||||
|
__s32 pid; // int
|
||||||
|
|
||||||
|
const void *skbaddr;
|
||||||
|
const void *skaddr;
|
||||||
|
__s32 state; // int
|
||||||
|
__u16 sport;
|
||||||
|
__u16 dport;
|
||||||
|
__u8 saddr[4];
|
||||||
|
__u8 daddr[4];
|
||||||
|
__u8 saddr_v6[16];
|
||||||
|
__u8 daddr_v6[16];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct {
|
||||||
|
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||||
|
__uint(max_entries, 4096);
|
||||||
|
__type(key, 1);
|
||||||
|
__type(value, __s32);
|
||||||
|
} tcp_stats_index SEC(".maps");
|
||||||
|
|
||||||
|
struct {
|
||||||
|
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||||
|
__uint(max_entries, 4096);
|
||||||
|
__type(key, 4);
|
||||||
|
__type(value, struct reset);
|
||||||
|
} tcp_reset_stats SEC(".maps");
|
||||||
|
|
||||||
|
struct {
|
||||||
|
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||||
|
__uint(max_entries, 1);
|
||||||
|
__type(key, __s32);
|
||||||
|
__type(value, __u16);
|
||||||
|
} filter_family SEC(".maps");
|
||||||
|
|
||||||
|
struct {
|
||||||
|
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||||
|
__uint(max_entries, 1);
|
||||||
|
__type(key, __s32);
|
||||||
|
__type(value, __u16);
|
||||||
|
} filter_sport SEC(".maps");
|
||||||
|
|
||||||
|
// sudo tcpdump -i any 'tcp[13] & 4 != 0' -n -> filter TCP reset flags
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This project do not trace any sniffing ports, because, the tracepoint tcp:tcp_send_reset
|
||||||
|
* works only for an establish socket, but, if you have a lot of TCP RST, you can have
|
||||||
|
* an issue with your system
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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")
|
||||||
|
//SEC("tracepoint/tcp/tcp_receive_reset")
|
||||||
|
//SEC("tracepoint/tcp/tcp_send_reset")
|
||||||
|
int tcp_retransmit(struct ctx_send_reset *ctx){
|
||||||
|
struct reset s_reset = {};
|
||||||
|
int *index;
|
||||||
|
int keys = 0;
|
||||||
|
struct sock *sk;
|
||||||
|
__u16 family;
|
||||||
|
__s16 *f_family;
|
||||||
|
__u16 proto;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
memset(&s_reset, 0, sizeof(struct reset));
|
||||||
|
|
||||||
|
// Get filter
|
||||||
|
sk = (struct sock*)ctx->skaddr;
|
||||||
|
f_family = bpf_map_lookup_elem(&filter_family, &keys);
|
||||||
|
if (!f_family)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
index = bpf_map_lookup_elem(&tcp_stats_index, &keys);
|
||||||
|
if (!index)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
|
||||||
|
// Get the family of the socket
|
||||||
|
bpf_probe_read_kernel(&family, sizeof(family), &sk->__sk_common.skc_family);
|
||||||
|
if (family != *f_family)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Get and update the index in the map
|
||||||
|
*index += 1;
|
||||||
|
|
||||||
|
// Proto type: here it's 6 (TCP)
|
||||||
|
bpf_probe_read_kernel(&proto, sizeof(proto), &sk->sk_protocol);
|
||||||
|
|
||||||
|
memcpy(s_reset.saddr, ctx->saddr, 4);
|
||||||
|
memcpy(s_reset.daddr, ctx->daddr, 4);
|
||||||
|
|
||||||
|
//bpf_probe_read_kernel(&s_reset.saddr, 4, &ctx->saddr);
|
||||||
|
//bpf_probe_read_kernel(&s_reset.daddr, 4, &ctx->daddr);
|
||||||
|
|
||||||
|
s_reset.sport = ctx->sport;
|
||||||
|
s_reset.dport = ctx->dport;
|
||||||
|
s_reset.family = family;
|
||||||
|
s_reset.proto = proto;
|
||||||
|
|
||||||
|
bpf_printk("BPF detected TCP send reset %d %d", s_reset.sport, s_reset.dport);
|
||||||
|
bpf_map_update_elem(&tcp_reset_stats, &keys, &s_reset, BPF_ANY);
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user