Compare commits
3 Commits
main
..
b45084ec06
| Author | SHA1 | Date | |
|---|---|---|---|
| b45084ec06 | |||
| 27fbf2b6e0 | |||
| d4fbe5fdac |
@@ -1,3 +0,0 @@
|
|||||||
load_bpf
|
|
||||||
tp_tcp.o
|
|
||||||
.**.swp
|
|
||||||
@@ -5,12 +5,6 @@ This project collect some metrics for TCP. For doing that, I use eBPF.
|
|||||||
For executing and loading the eBPF program and to send data to InfluxDB, you need to install some packages:
|
For executing and loading the eBPF program and to send data to InfluxDB, you need to install some packages:
|
||||||
|
|
||||||
```
|
```
|
||||||
sudo apt install linux-headers-`uname -r` clang-11 gcc gcc-multilib libbpf-dev libbpfcc bpfcc-tools
|
|
||||||
```
|
|
||||||
|
|
||||||
For installing bpftool command:
|
|
||||||
```
|
|
||||||
sudo apt install linux-tools-common linux-tools-generic
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Compile eBPF program
|
## Compile eBPF program
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
FROM ubuntu:latest
|
||||||
|
|
||||||
|
RUN apt-get update -y && apt-get install -y nmap
|
||||||
@@ -1,18 +1,11 @@
|
|||||||
#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
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
#!/usr/bin/sh
|
|
||||||
|
|
||||||
use_influxdb=true
|
|
||||||
influxdb_host="<ip>"
|
|
||||||
influxdb_orgid="<org ID>"
|
|
||||||
influxdb_token="<token>"
|
|
||||||
influxdb_bucket="tcp_metrics"
|
|
||||||
|
|
||||||
clang-11 -g -O2 -target bpf -c tp_tcp.c -o tp_tcp.o && \
|
|
||||||
gcc ic.c load_bpf.c -o load_bpf -lbpf && \
|
|
||||||
if [ "$use_influxdb" = true ]; then
|
|
||||||
sudo ./load_bpf $influxdb_host $influxdb_orgid $influxdb_token $influxdb_bucket
|
|
||||||
else
|
|
||||||
sudo ./load_bpf --no-influxdb
|
|
||||||
fi
|
|
||||||
@@ -41,8 +41,6 @@ long influx_port = 0;
|
|||||||
char influx_database[256+1]; /* the influxdb database */
|
char influx_database[256+1]; /* the influxdb database */
|
||||||
char influx_username[64+1]; /* optional for influxdb access */
|
char influx_username[64+1]; /* optional for influxdb access */
|
||||||
char influx_password[64+1]; /* optional for influxdb access */
|
char influx_password[64+1]; /* optional for influxdb access */
|
||||||
char influx_token[128+1];
|
|
||||||
char influx_orgID[64+1];
|
|
||||||
|
|
||||||
char *output; /* all the stats must fit in this buffer */
|
char *output; /* all the stats must fit in this buffer */
|
||||||
long output_size = 0;
|
long output_size = 0;
|
||||||
@@ -119,14 +117,6 @@ void ic_influx_database(char *host, long port, char *db) /* note: converts influ
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ic_influx_token(char *token){
|
|
||||||
DEBUG fprintf(stderr, "ic_influx_token(token=%s))\n", token);
|
|
||||||
strncpy(influx_token, token, 128);
|
|
||||||
}
|
|
||||||
void ic_influx_orgID(char *orgID){
|
|
||||||
DEBUG fprintf(stderr, "ic_influx_orgID(ordID=%s))\n", orgID);
|
|
||||||
strncpy(influx_orgID, orgID, 64);
|
|
||||||
}
|
|
||||||
void ic_influx_userpw(char *user, char *pw)
|
void ic_influx_userpw(char *user, char *pw)
|
||||||
{
|
{
|
||||||
DEBUG fprintf(stderr,"ic_influx_userpw(username=%s,pssword=%s))\n",user,pw);
|
DEBUG fprintf(stderr,"ic_influx_userpw(username=%s,pssword=%s))\n",user,pw);
|
||||||
@@ -288,8 +278,9 @@ void ic_push()
|
|||||||
if (influx_port) {
|
if (influx_port) {
|
||||||
DEBUG fprintf(stderr, "ic_push() size=%ld\n", output_char);
|
DEBUG fprintf(stderr, "ic_push() size=%ld\n", output_char);
|
||||||
if (create_socket() == 1) {
|
if (create_socket() == 1) {
|
||||||
sprintf(buffer, "POST /api/v2/write?bucket=%s&orgID=%s HTTP/1.1\r\nHost: %s:%ld\r\nContent-Length: %ld\r\nAuthorization: Token %s\r\n\r\n",
|
|
||||||
influx_database, influx_orgID, influx_hostname, influx_port, output_char, influx_token);
|
sprintf(buffer, "POST /write?db=%s&u=%s&p=%s HTTP/1.1\r\nHost: %s:%ld\r\nContent-Length: %ld\r\n\r\n",
|
||||||
|
influx_database, influx_username, influx_password, influx_hostname, influx_port, output_char);
|
||||||
DEBUG fprintf(stderr, "buffer size=%ld\nbuffer=<%s>\n", strlen(buffer), buffer);
|
DEBUG fprintf(stderr, "buffer size=%ld\nbuffer=<%s>\n", strlen(buffer), buffer);
|
||||||
if ((ret = write(sockfd, buffer, strlen(buffer))) != strlen(buffer)) {
|
if ((ret = write(sockfd, buffer, strlen(buffer))) != strlen(buffer)) {
|
||||||
fprintf(stderr, "warning: \"write post to sockfd failed.\" errno=%d\n", errno);
|
fprintf(stderr, "warning: \"write post to sockfd failed.\" errno=%d\n", errno);
|
||||||
@@ -332,30 +323,3 @@ void ic_push()
|
|||||||
output[0] = 0;
|
output[0] = 0;
|
||||||
output_char = 0;
|
output_char = 0;
|
||||||
}
|
}
|
||||||
int ic_read(const char *ipsrc, const char *ipdst){
|
|
||||||
int value;
|
|
||||||
int ret;
|
|
||||||
char buffer[1024 * 8];
|
|
||||||
char request[1024];
|
|
||||||
char result[1024];
|
|
||||||
int len = 0;
|
|
||||||
|
|
||||||
sprintf(request, "from(bucket: \"tcp_metrics\")|> range(start: -1m)|> filter(fn: (r) => r[\"_measurement\"] == \"tcp_reset\")|> filter(fn: (r) => r[\"host\"] == \"%s\")|> filter(fn: (r) => r[\"_field\"] == \"%s\")|> last()", ipsrc, ipdst);
|
|
||||||
len = strlen(request);
|
|
||||||
|
|
||||||
if (create_socket() == 1) {
|
|
||||||
sprintf(buffer, "POST /api/v2/query?bucket=%s&orgID=%s HTTP/1.1\r\nHost: %s:%ld\r\nContent-Type: application/vnd.flux\r\nAccept: application/csv\r\nContent-Length: %d\r\nAuthorization: Token %s\r\n\r\n%s",
|
|
||||||
influx_database, influx_orgID, influx_hostname, influx_port, len, influx_token, request);
|
|
||||||
DEBUG fprintf(stderr, "buffer size=%ld\nbuffer=<%s>\n", strlen(buffer), buffer);
|
|
||||||
printf("%s\n", buffer);
|
|
||||||
if ((ret = write(sockfd, buffer, strlen(buffer))) != strlen(buffer)) {
|
|
||||||
fprintf(stderr, "warning: \"write post to sockfd failed.\" errno=%d\n", errno);
|
|
||||||
}
|
|
||||||
if ((ret = read(sockfd, result, sizeof(result))) > 0) {
|
|
||||||
printf("%s\n", result);
|
|
||||||
}
|
|
||||||
close(sockfd);
|
|
||||||
sockfd = 0;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,8 +5,6 @@
|
|||||||
*/
|
*/
|
||||||
void ic_influx_database(char *host, long port, char *db);
|
void ic_influx_database(char *host, long port, char *db);
|
||||||
void ic_influx_userpw(char *user, char *pw);
|
void ic_influx_userpw(char *user, char *pw);
|
||||||
void ic_influx_orgID(char *orgID);
|
|
||||||
void ic_influx_token(char *token);
|
|
||||||
void ic_tags(char *tags);
|
void ic_tags(char *tags);
|
||||||
|
|
||||||
void ic_measure(char *section);
|
void ic_measure(char *section);
|
||||||
@@ -20,6 +18,5 @@
|
|||||||
void ic_string(char *name, char *value);
|
void ic_string(char *name, char *value);
|
||||||
|
|
||||||
void ic_push();
|
void ic_push();
|
||||||
int ic_read(const char *, const char *);
|
|
||||||
void ic_debug(int level);
|
void ic_debug(int level);
|
||||||
|
|
||||||
|
|||||||
+16
-132
@@ -1,4 +1,3 @@
|
|||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <bpf/bpf.h>
|
#include <bpf/bpf.h>
|
||||||
#include <bpf/libbpf.h>
|
#include <bpf/libbpf.h>
|
||||||
@@ -6,41 +5,12 @@
|
|||||||
#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>
|
|
||||||
#include <errno.h>
|
|
||||||
#include "ic.h"
|
|
||||||
|
|
||||||
#define BUF_SIZE 300
|
|
||||||
#define BUCKET_SIZE 16 // Bucket size for InfluxDB
|
|
||||||
#define INFLUXDB_SIZE 64 // Host and ordID size for InfluxDB
|
|
||||||
#define TOKEN_SIZE 128 // Token size for InfluxDB
|
|
||||||
#define CNT_ARGS 5 // Number of args
|
|
||||||
|
|
||||||
|
|
||||||
static void clean_obj(struct bpf_object *obj){
|
static void clean_obj(struct bpf_object *obj){
|
||||||
printf("Cleaning\n");
|
printf("Cleaning\n");
|
||||||
bpf_object__close(obj);
|
bpf_object__close(obj);
|
||||||
}
|
}
|
||||||
static void usage(char *app){
|
int main(void){
|
||||||
printf("Usage: %s <host> <ordID> <token> <bucket>\n", app);
|
|
||||||
}
|
|
||||||
static int check_arguments(int argc, char *argv[]){
|
|
||||||
if (argc < 1){
|
|
||||||
usage(argv[0]);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(argv[1], "--no-influxdb") == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (argc < CNT_ARGS){
|
|
||||||
usage(argv[0]);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return argc; // Return the number of arguments
|
|
||||||
}
|
|
||||||
int main(int argc, char *argv[]){
|
|
||||||
const char *fileObj = "tp_tcp.o";
|
const char *fileObj = "tp_tcp.o";
|
||||||
struct bpf_object *obj;
|
struct bpf_object *obj;
|
||||||
struct bpf_program *program;
|
struct bpf_program *program;
|
||||||
@@ -48,60 +18,28 @@ int main(int argc, char *argv[]){
|
|||||||
struct reset s_reset;
|
struct reset s_reset;
|
||||||
int err;
|
int err;
|
||||||
int map_fd;
|
int map_fd;
|
||||||
int map_fd_filter_family;
|
long long stats;
|
||||||
int map_fd_filter_sport;
|
|
||||||
int map_fd_index;
|
|
||||||
int keys = 0;
|
int keys = 0;
|
||||||
int indexPackets = 0;
|
|
||||||
int index = 0;
|
|
||||||
char buf[BUF_SIZE];
|
|
||||||
char host[INFLUXDB_SIZE];
|
|
||||||
char orgID[INFLUXDB_SIZE];
|
|
||||||
char token[TOKEN_SIZE];
|
|
||||||
char bucket[BUCKET_SIZE];
|
|
||||||
int use_influxdb = 0;
|
|
||||||
int debug = 1;
|
|
||||||
|
|
||||||
// We get args
|
|
||||||
err = check_arguments(argc, argv);
|
|
||||||
if (err == -1)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (err == CNT_ARGS){
|
|
||||||
strncpy(host, argv[1], INFLUXDB_SIZE);
|
|
||||||
strncpy(orgID, argv[2], INFLUXDB_SIZE);
|
|
||||||
strncpy(token, argv[3], TOKEN_SIZE);
|
|
||||||
strncpy(bucket, argv[4], BUCKET_SIZE);
|
|
||||||
use_influxdb = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Connect to InfluxDB
|
|
||||||
if (use_influxdb) {
|
|
||||||
ic_influx_database(host, 8086, bucket);
|
|
||||||
ic_influx_orgID(orgID);
|
|
||||||
ic_influx_token(token);
|
|
||||||
}
|
|
||||||
|
|
||||||
obj = bpf_object__open_file(fileObj, NULL);
|
obj = bpf_object__open_file(fileObj, NULL);
|
||||||
if (!obj){
|
if (!obj){
|
||||||
printf("Failed to open %s\n", fileObj);
|
printf("Failed to open %s\n", fileObj);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
//LIBBPF_OPTS(bpf_map_create_opts, opts, .map_flags = BPF_F_MMAPABLE);
|
||||||
//map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, 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);
|
||||||
|
|
||||||
err = bpf_object__load(obj);
|
err = bpf_object__load(obj);
|
||||||
|
printf("Object loaded: %d\n", err);
|
||||||
if (err){
|
if (err){
|
||||||
printf("%s\n", strerror(errno));
|
|
||||||
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_rst_stats");
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,25 +51,7 @@ int main(int argc, char *argv[]){
|
|||||||
}
|
}
|
||||||
|
|
||||||
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");
|
||||||
if (map_fd < 0){
|
printf("Map fd: %d\n", map_fd);
|
||||||
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){
|
||||||
@@ -139,51 +59,15 @@ int main(int argc, char *argv[]){
|
|||||||
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){
|
||||||
err = bpf_map_lookup_elem(map_fd_index, &keys, &indexPackets);
|
int e = bpf_map_lookup_elem(map_fd, &keys, &s_reset);
|
||||||
|
if (e == 0){
|
||||||
// We have a new packet
|
//printf("%lld\n", stats);
|
||||||
if (indexPackets > index){
|
struct in_addr *src = (struct in_addr*)&s_reset.saddr;
|
||||||
index = 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));
|
||||||
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 *d;
|
|
||||||
char tmp[35];
|
|
||||||
int lastValue;
|
|
||||||
memcpy(tmp, s, 35);
|
|
||||||
d = inet_ntoa(*dest);
|
|
||||||
|
|
||||||
if (debug)
|
|
||||||
printf("Sport: %d; dport: %d %d %d %s - %s\n", s_reset.sport, s_reset.dport, s_reset.family, s_reset.proto, tmp, d);
|
|
||||||
|
|
||||||
if (use_influxdb) {
|
|
||||||
printf("Send data to influx\n");
|
|
||||||
// Send data to InfluxDB
|
|
||||||
snprintf(buf, BUF_SIZE, "host=%s", s);
|
|
||||||
ic_tags(buf);
|
|
||||||
|
|
||||||
ic_measure("tcp_reset");
|
|
||||||
ic_long("value", 1);
|
|
||||||
ic_measureend();
|
|
||||||
ic_push();
|
|
||||||
|
|
||||||
memset(buf, 0, BUF_SIZE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
memset(&s_reset, 0, sizeof(struct reset));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
#define BPF_NO_GLOBAL_DATA
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <linux/bpf.h>
|
||||||
|
#include <bpf/bpf_helpers.h>
|
||||||
|
#include <bpf/bpf_tracing.h>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[], char *argp[]){
|
||||||
|
printf("Hello world\n");
|
||||||
|
execve("/usr/bin/ls", argv, argp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
import socket
|
|
||||||
import struct
|
|
||||||
|
|
||||||
def server(host, port):
|
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
|
|
||||||
l_onoff = 1
|
|
||||||
l_linger = 0
|
|
||||||
s.setsockopt(
|
|
||||||
socket.SOL_SOCKET,
|
|
||||||
socket.SO_LINGER,
|
|
||||||
struct.pack('ii', l_onoff, l_linger)
|
|
||||||
)
|
|
||||||
s.bind(('', port))
|
|
||||||
s.listen(5)
|
|
||||||
|
|
||||||
while 1:
|
|
||||||
skclt, addrclt = s.accept()
|
|
||||||
print(f"New connection from client: {addrclt}")
|
|
||||||
|
|
||||||
|
|
||||||
skclt.close()
|
|
||||||
|
|
||||||
server('0.0.0.0', 8080)
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
#!/usr/bin/bash
|
|
||||||
|
|
||||||
curl -i -X POST "http://192.168.1.68:8086/api/v2/query?bucket=tcp_metrics&orgID=f32d493484526abc" \
|
|
||||||
--header "Authorization: Token $1" \
|
|
||||||
--header "Accept: application/csv" \
|
|
||||||
--header "Content-Type: application/vnd.flux" \
|
|
||||||
--data 'from(bucket: "tcp_metrics")
|
|
||||||
|> range(start: -5m)
|
|
||||||
|> filter(fn: (r) => r["_measurement"] == "tcp_reset")
|
|
||||||
|> filter(fn: (r) => r["host"] == "127.0.0.1")
|
|
||||||
|> filter(fn: (r) => r["_field"] == "value")
|
|
||||||
|> yield(name: "mean")'
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
#!/usr/bin/bash
|
|
||||||
|
|
||||||
curl -i -X POST "http://localhost:8086/api/v2/write?bucket=tcp_metrics&orgID=392fcb79fc296d8e" \
|
|
||||||
--header "Authorization: Token $1" \
|
|
||||||
--data "cpu_load_short,host=server01, value=1"
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
#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>
|
||||||
@@ -10,106 +9,77 @@
|
|||||||
char LICENSE[] SEC("license") = "Dual BSD/GPL";
|
char LICENSE[] SEC("license") = "Dual BSD/GPL";
|
||||||
|
|
||||||
|
|
||||||
// Format: /sys/kernel/debug/tracing/events/tcp/tcp_send_reset/format
|
struct ctx_reset {
|
||||||
struct ctx_send_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 *skbaddr;
|
|
||||||
const void *skaddr;
|
const void *skaddr;
|
||||||
__s32 state; // int
|
|
||||||
__u16 sport;
|
__u16 sport;
|
||||||
__u16 dport;
|
__u16 dport;
|
||||||
|
__u16 family;
|
||||||
__u8 saddr[4];
|
__u8 saddr[4];
|
||||||
__u8 daddr[4];
|
__u8 daddr[4];
|
||||||
__u8 saddr_v6[16];
|
__u8 saddr_v6[16];
|
||||||
__u8 daddr_v6[16];
|
__u8 daddr_v6[16];
|
||||||
|
__u64 sock_cookie;
|
||||||
};
|
};
|
||||||
|
|
||||||
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, 1);
|
__type(key, int);
|
||||||
__type(value, __s32);
|
__type(value, sizeof(struct reset));
|
||||||
} 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
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
* 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:
|
* 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:
|
* 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
|
* But we can also block all receive RST: iptables -I INPUT -p tcp --dport <port> -j REJECT --reject-with tcp-reset
|
||||||
*/
|
*/
|
||||||
|
|
||||||
SEC("tracepoint/tcp/tcp_send_reset")
|
//SEC("tp/tcp_retransmit_synack")
|
||||||
int tcp_rst_stats(struct ctx_send_reset *ctx){
|
SEC("tracepoint/tcp/tcp_receive_reset")
|
||||||
struct reset s_reset = {};
|
//int tcp_retransmit(struct sock *sk){
|
||||||
int *index;
|
int tcp_retransmit(struct ctx_reset *ctx){
|
||||||
|
long long *stats;
|
||||||
|
struct reset *s_reset;
|
||||||
int keys = 0;
|
int keys = 0;
|
||||||
struct sock *sk;
|
|
||||||
__u16 family;
|
|
||||||
__s16 *f_family;
|
|
||||||
__u16 proto;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
memset(&s_reset, 0, sizeof(struct reset));
|
s_reset = bpf_map_lookup_elem(&tcp_reset_stats, &keys);
|
||||||
|
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;
|
||||||
|
|
||||||
index = bpf_map_lookup_elem(&tcp_stats_index, &keys);
|
if (!ctx)
|
||||||
if (!index)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// Get the family of the socket
|
//*stats += 1;
|
||||||
bpf_probe_read_kernel(&family, sizeof(family), &sk->__sk_common.skc_family);
|
s_reset->saddr[0] = ctx->saddr[0];
|
||||||
if (family != *f_family)
|
s_reset->saddr[1] = ctx->saddr[1];
|
||||||
return 0;
|
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 = ctx->sport;
|
||||||
|
s_reset->dport = ctx->dport;
|
||||||
|
|
||||||
// Get and update the index in the map
|
//bpf_printk("BPF detected TCP received reset %d - %d %d\n", *stats, dport, sport);
|
||||||
*index += 1;
|
bpf_printk("BPF detected TCP received reset %d %d\n", s_reset->sport, s_reset->dport);
|
||||||
|
|
||||||
// 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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user