Compare commits
	
		
			No commits in common. "main" and "castip" have entirely different histories.
		
	
	
		
	
		
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -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:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										3
									
								
								Server/Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										3
									
								
								Server/Dockerfile
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
			
		||||
FROM ubuntu:latest
 | 
			
		||||
 | 
			
		||||
RUN apt-get update -y && apt-get install -y nmap
 | 
			
		||||
							
								
								
									
										14
									
								
								exec.sh
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										14
									
								
								exec.sh
									
									
									
									
									
								
							@ -1,15 +1,5 @@
 | 
			
		||||
#!/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
 | 
			
		||||
gcc load_bpf.c -o load_bpf -lbpf && \
 | 
			
		||||
sudo ./load_bpf
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										42
									
								
								ic.c
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										42
									
								
								ic.c
									
									
									
									
									
								
							@ -41,8 +41,6 @@ long influx_port = 0;
 | 
			
		||||
char influx_database[256+1];		/* the influxdb database  */
 | 
			
		||||
char influx_username[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 */
 | 
			
		||||
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)
 | 
			
		||||
{
 | 
			
		||||
	DEBUG fprintf(stderr,"ic_influx_userpw(username=%s,pssword=%s))\n",user,pw);
 | 
			
		||||
@ -288,8 +278,9 @@ void ic_push()
 | 
			
		||||
    if (influx_port) {
 | 
			
		||||
	DEBUG fprintf(stderr, "ic_push() size=%ld\n", output_char);
 | 
			
		||||
	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);
 | 
			
		||||
	    if ((ret = write(sockfd, buffer, strlen(buffer))) != strlen(buffer)) {
 | 
			
		||||
			fprintf(stderr, "warning: \"write post to sockfd failed.\" errno=%d\n", errno);
 | 
			
		||||
@ -332,30 +323,3 @@ void ic_push()
 | 
			
		||||
    output[0] = 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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										3
									
								
								ic.h
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										3
									
								
								ic.h
									
									
									
									
									
								
							@ -5,8 +5,6 @@
 | 
			
		||||
 */
 | 
			
		||||
 void ic_influx_database(char *host, long port, char *db);
 | 
			
		||||
 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_measure(char *section);
 | 
			
		||||
@ -20,6 +18,5 @@
 | 
			
		||||
 void ic_string(char *name, char *value);
 | 
			
		||||
 | 
			
		||||
 void ic_push();
 | 
			
		||||
 int ic_read(const char *, const char *);
 | 
			
		||||
 void ic_debug(int level);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										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
									
									
									
									
									
										Executable file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										
											BIN
										
									
								
								load_bpf
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										93
									
								
								load_bpf.c
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										93
									
								
								load_bpf.c
									
									
									
									
									
								
							@ -1,4 +1,3 @@
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <bpf/bpf.h>
 | 
			
		||||
#include <bpf/libbpf.h>
 | 
			
		||||
@ -7,40 +6,12 @@
 | 
			
		||||
#include <arpa/inet.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){
 | 
			
		||||
    printf("Cleaning\n");
 | 
			
		||||
    bpf_object__close(obj);
 | 
			
		||||
}
 | 
			
		||||
static void usage(char *app){
 | 
			
		||||
    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[]){
 | 
			
		||||
}   
 | 
			
		||||
int main(void){
 | 
			
		||||
    const char *fileObj = "tp_tcp.o";
 | 
			
		||||
    struct bpf_object *obj;
 | 
			
		||||
    struct bpf_program *program;
 | 
			
		||||
@ -54,51 +25,24 @@ int main(int argc, char *argv[]){
 | 
			
		||||
    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);
 | 
			
		||||
    if (!obj){
 | 
			
		||||
        printf("Failed to open %s\n", fileObj);
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //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_ARRAY, sizeof(int), sizeof(struct reset), 4096, BPF_ANY);
 | 
			
		||||
 | 
			
		||||
    err = bpf_object__load(obj);
 | 
			
		||||
    if (err){
 | 
			
		||||
        printf("%s\n", strerror(errno));
 | 
			
		||||
        printf("Failed to load object\n");
 | 
			
		||||
        clean_obj(obj);
 | 
			
		||||
        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){
 | 
			
		||||
        printf("Failed to find the program\n");
 | 
			
		||||
        clean_obj(obj);
 | 
			
		||||
@ -147,42 +91,31 @@ int main(int argc, char *argv[]){
 | 
			
		||||
    __s16 f = AF_INET;
 | 
			
		||||
    err = bpf_map_update_elem(map_fd_filter_family, &keys, &f, BPF_ANY);
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    while(1){
 | 
			
		||||
        // Get the index
 | 
			
		||||
        // and we compare with the local variable
 | 
			
		||||
        // If it's different, we get the new variable
 | 
			
		||||
        err = bpf_map_lookup_elem(map_fd_index, &keys, &indexPackets);
 | 
			
		||||
 | 
			
		||||
        // 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 *d;
 | 
			
		||||
                char tmp[35];
 | 
			
		||||
                int lastValue;
 | 
			
		||||
                memcpy(tmp, s, 35);
 | 
			
		||||
                d = inet_ntoa(*dest);
 | 
			
		||||
                char *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);
 | 
			
		||||
                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));
 | 
			
		||||
            //sleep(1);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								main
									
									
									
									
									
										Executable file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										
											BIN
										
									
								
								main
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										25
									
								
								main.c
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										25
									
								
								main.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,25 @@
 | 
			
		||||
#define BPF_NO_GLOBAL_DATA
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
#include "ic.h"
 | 
			
		||||
 | 
			
		||||
int main(int argc, char *argv[], char *argp[]){
 | 
			
		||||
    printf("Hello world\n");
 | 
			
		||||
    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;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										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)
 | 
			
		||||
@ -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"
 | 
			
		||||
							
								
								
									
										38
									
								
								tp_tcp.c
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										38
									
								
								tp_tcp.c
									
									
									
									
									
								
							@ -10,7 +10,22 @@
 | 
			
		||||
char LICENSE[] SEC("license") = "Dual BSD/GPL";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Format: /sys/kernel/debug/tracing/events/tcp/tcp_send_reset/format
 | 
			
		||||
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
 | 
			
		||||
@ -59,13 +74,31 @@ struct {
 | 
			
		||||
// 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_rst_stats(struct ctx_send_reset *ctx){
 | 
			
		||||
int tcp_retransmit(struct ctx_send_reset *ctx){
 | 
			
		||||
    struct reset s_reset = {};
 | 
			
		||||
    int *index;
 | 
			
		||||
    int keys = 0;
 | 
			
		||||
@ -87,6 +120,7 @@ int tcp_rst_stats(struct ctx_send_reset *ctx){
 | 
			
		||||
    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)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								tp_tcp.o
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										
											BIN
										
									
								
								tp_tcp.o
									
									
									
									
									
										Normal file
									
								
							
										
											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