Compare commits
	
		
			No commits in common. "7f377620ef07303171ab65924bce539ea0fc2f7d" and "b45084ec0625fe2f61fd053a371fcc6a8ad6913b" have entirely different histories.
		
	
	
		
			7f377620ef
			...
			b45084ec06
		
	
		
							
								
								
									
										9
									
								
								common.h
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										9
									
								
								common.h
									
									
									
									
									
								
							| @ -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 | ||||||
|  | |||||||
							
								
								
									
										5
									
								
								exec.sh
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										5
									
								
								exec.sh
									
									
									
									
									
								
							| @ -1,5 +0,0 @@ | |||||||
| #!/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
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										24
									
								
								influxdb.py
									
									
									
									
									
								
							| @ -1,24 +0,0 @@ | |||||||
| 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.
										
									
								
							
							
								
								
									
										69
									
								
								load_bpf.c
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										69
									
								
								load_bpf.c
									
									
									
									
									
								
							| @ -5,7 +5,6 @@ | |||||||
| #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"); | ||||||
| @ -19,12 +18,8 @@ int main(void){ | |||||||
|     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; |  | ||||||
| 
 | 
 | ||||||
|     obj = bpf_object__open_file(fileObj, NULL); |     obj = bpf_object__open_file(fileObj, NULL); | ||||||
|     if (!obj){ |     if (!obj){ | ||||||
| @ -32,20 +27,19 @@ 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); | ||||||
|     //map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, 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("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; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -57,25 +51,7 @@ 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"); | ||||||
|     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){ | ||||||
| @ -83,40 +59,15 @@ 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){ | ||||||
|         // Get the index
 |         int e = bpf_map_lookup_elem(map_fd, &keys, &s_reset); | ||||||
|         // and we compare with the local variable
 |         if (e == 0){ | ||||||
|         // If it's different, we get the new variable
 |             //printf("%lld\n", stats);
 | ||||||
|         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 *src = (struct in_addr*)&s_reset.saddr; | ||||||
|             struct in_addr *dest = (struct in_addr*)&s_reset.daddr; |             struct in_addr *dest = (struct in_addr*)&s_reset.daddr; | ||||||
|                 char *s = inet_ntoa(*src); |             printf("Sport: %d; dport: %d %s %s\n", s_reset.sport, s_reset.dport, inet_ntoa(*src), inet_ntoa(*dest)); | ||||||
|                 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,25 +1,12 @@ | |||||||
| #define BPF_NO_GLOBAL_DATA | #define BPF_NO_GLOBAL_DATA | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
| #include "ic.h" | #include <linux/bpf.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"); | ||||||
|     char buf[300]; |     execve("/usr/bin/ls", argv, argp); | ||||||
| 
 |  | ||||||
|     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
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										9
									
								
								main.py
									
									
									
									
									
								
							| @ -1,9 +0,0 @@ | |||||||
| #!/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") |  | ||||||
| @ -1,30 +0,0 @@ | |||||||
| 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) |  | ||||||
							
								
								
									
										125
									
								
								tp_tcp.c
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										125
									
								
								tp_tcp.c
									
									
									
									
									
								
							| @ -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,11 +9,11 @@ | |||||||
| char LICENSE[] SEC("license") = "Dual BSD/GPL"; | char LICENSE[] SEC("license") = "Dual BSD/GPL"; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| struct ctx_receive_reset { | struct ctx_reset { | ||||||
|     __u16 common_type; // unsigned short
 |     __u16 common_type; | ||||||
|     __u8 common_flags; // unsigned char
 |     __u8 common_flags; | ||||||
|     __u8 common_count; // unsigned char 
 |     __u8 common_count; | ||||||
|     __s32 pid;         // int
 |     __s32 pid; | ||||||
| 
 | 
 | ||||||
|     const void *skaddr; |     const void *skaddr; | ||||||
|     __u16 sport;  |     __u16 sport;  | ||||||
| @ -26,59 +25,17 @@ struct ctx_receive_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, 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
 | ||||||
| 
 | 
 | ||||||
| /*
 |  | ||||||
|  * 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 | ||||||
| @ -96,55 +53,33 @@ struct { | |||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| //SEC("tp/tcp_retransmit_synack")
 | //SEC("tp/tcp_retransmit_synack")
 | ||||||
| //SEC("tracepoint/tcp/tcp_receive_reset")
 | SEC("tracepoint/tcp/tcp_receive_reset") | ||||||
| SEC("tracepoint/tcp/tcp_send_reset") | //int tcp_retransmit(struct sock *sk){
 | ||||||
| int tcp_retransmit(struct ctx_send_reset *ctx){ | int tcp_retransmit(struct ctx_reset *ctx){ | ||||||
|     struct reset s_reset = {}; |     long long *stats; | ||||||
|     int *index; |     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; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     index = bpf_map_lookup_elem(&tcp_stats_index, &keys); |  | ||||||
|     if (!index) |  | ||||||
|         return 0; |         return 0; | ||||||
| 
 | 
 | ||||||
|      |     if (!ctx) | ||||||
|     // Get the family of the socket
 |  | ||||||
|     bpf_probe_read_kernel(&family, sizeof(family), &sk->__sk_common.skc_family); |  | ||||||
|     if (family != *f_family) |  | ||||||
|         return 0; |         return 0; | ||||||
| 
 | 
 | ||||||
|     // Get and update the index in the map
 |     //*stats += 1;
 | ||||||
|     *index += 1; |     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]; | ||||||
|  |     /*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; | ||||||
| 
 | 
 | ||||||
|     // Proto type: here it's 6 (TCP)
 |     //bpf_printk("BPF detected TCP received reset %d - %d %d\n", *stats, dport, sport);
 | ||||||
|     bpf_probe_read_kernel(&proto, sizeof(proto), &sk->sk_protocol); |     bpf_printk("BPF detected TCP received reset %d %d\n", s_reset->sport, s_reset->dport); | ||||||
| 
 |  | ||||||
|     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
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										
											BIN
										
									
								
								tp_tcp.o
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										149
									
								
								tp_tcp_py.c
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										149
									
								
								tp_tcp_py.c
									
									
									
									
									
								
							| @ -1,149 +0,0 @@ | |||||||
| #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