From 0a472c3646ad0553821b25e68ecb189f4e2c865f Mon Sep 17 00:00:00 2001 From: wynyibo Date: Fri, 6 Sep 2024 15:31:28 +0800 Subject: [PATCH 01/13] add use protocol percentage --- .../net_watcher/common.bpf.h | 31 ++- .../net_watcher/netwatcher.bpf.c | 14 +- .../net_watcher/netwatcher.c | 228 ++++++++++-------- .../net_watcher/netwatcher.h | 73 +++++- .../net_watcher/packet.bpf.h | 156 ++++++++---- 5 files changed, 346 insertions(+), 156 deletions(-) diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/common.bpf.h b/eBPF_Supermarket/Network_Subsystem/net_watcher/common.bpf.h index b7e775a8a..952b35939 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/common.bpf.h +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/common.bpf.h @@ -62,7 +62,7 @@ struct tcpstate { int newstate; u64 time; }; -#define MAX_SLOTS 27 + enum { e_ip_rcv = 0, e_ip_local_deliver, @@ -75,6 +75,14 @@ enum { nf_max } nf_hook; +enum { + PROTO_TCP = 0, + PROTO_UDP, + PROTO_ICMP, + PROTO_UNKNOWN, + PROTO_MAX, +}; + struct filtertime { struct packet_tuple init; struct packet_tuple done; @@ -149,6 +157,8 @@ struct trace_event_raw_tcp_receive_reset { __u8 daddr_v6[16]; __u64 sock_cookie; }; +#define MAX_CONN 1000 +#define MAX_SLOTS 27 // 操作BPF映射的一个辅助函数 static __always_inline void * //__always_inline强制内联 bpf_map_lookup_or_try_init(void *map, const void *key, const void *init) { @@ -169,8 +179,6 @@ bpf_map_lookup_or_try_init(void *map, const void *key, const void *init) { char LICENSE[] SEC("license") = "Dual BSD/GPL"; -#define MAX_CONN 1000 - // 存储每个packet_tuple包所对应的ktime_info时间戳 struct { __uint(type, BPF_MAP_TYPE_LRU_HASH); @@ -240,6 +248,11 @@ struct { __uint(max_entries, 256 * 1024); } events SEC(".maps"); +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 1024); +} port_rb SEC(".maps"); + // 存储每个tcp连接所对应的conn_t struct { __uint(type, BPF_MAP_TYPE_LRU_HASH); @@ -352,13 +365,22 @@ struct { __type(value, u64); __uint(max_entries, 1024); } counters SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(max_entries, MAX_COMM *MAX_PACKET); + __type(key, u32); + __type(value, struct packet_count); +} proto_stats SEC(".maps"); + const volatile int filter_dport = 0; const volatile int filter_sport = 0; const volatile int all_conn = 0, err_packet = 0, extra_conn_info = 0, layer_time = 0, http_info = 0, retrans_info = 0, udp_info = 0, net_filter = 0, drop_reason = 0, icmp_info = 0, tcp_info = 0, dns_info = 0, stack_info = 0, mysql_info = 0, - redis_info = 0, rtt_info = 0, rst_info = 0; + redis_info = 0, rtt_info = 0, rst_info = 0, + protocol_count = 0; /* help macro */ @@ -631,6 +653,7 @@ static __always_inline u64 log2l(u64 v) { else return log2(v); } + /* help functions end */ #endif diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.bpf.c b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.bpf.c index 46834bfc4..aac2ca650 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.bpf.c +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.bpf.c @@ -101,7 +101,11 @@ int BPF_KPROBE(tcp_set_state, struct sock *sk, int state) { /** in ipv4 && ipv6 */ SEC("kprobe/eth_type_trans") // 进入eth_type_trans int BPF_KPROBE(eth_type_trans, struct sk_buff *skb) { - return __eth_type_trans(skb); + if (protocol_count) { + return sum_protocol(skb, false); // receive + } else { + return __eth_type_trans(skb); + } } /** in only ipv4 */ @@ -197,7 +201,11 @@ int BPF_KPROBE(__dev_queue_xmit, struct sk_buff *skb) { */ SEC("kprobe/dev_hard_start_xmit") int BPF_KPROBE(dev_hard_start_xmit, struct sk_buff *skb) { - return __dev_hard_start_xmit(skb); + if (protocol_count) { + return sum_protocol(skb, true); // send + } else { + return __dev_hard_start_xmit(skb); + } }; // retrans @@ -318,6 +326,8 @@ SEC("uprobe/processCommand") int BPF_KPROBE(query__start_redis_process) { return __handle_redis_start(ctx); } SEC("uretprobe/call") int BPF_KPROBE(query__end_redis) { return __handle_redis_end(ctx); } +SEC("uprobe/lookupKey") +int BPF_KPROBE(redis_uprobe) { return __handle_lookupKey(ctx); } // rtt SEC("kprobe/tcp_rcv_established") int BPF_KPROBE(tcp_rcv_established, struct sock *sk, struct sk_buff *skb) { diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c index 263459c7c..452666aa9 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c @@ -29,31 +29,30 @@ #include #include #include +#include #include #include -#include static volatile bool exiting = false; - +struct packet_count proto_stats[256] = {0}; +static u64 rst_count = 0; +static struct reset_event_t event_store[MAX_EVENTS]; +static int event_count = 0; static char connects_file_path[1024]; static char err_file_path[1024]; static char packets_file_path[1024]; static char udp_file_path[1024]; +static char binary_path[64] = ""; +int num_symbols = 0; +int cache_size = 0; static int sport = 0, dport = 0; // for filter static int all_conn = 0, err_packet = 0, extra_conn_info = 0, layer_time = 0, http_info = 0, retrans_info = 0, udp_info = 0, net_filter = 0, drop_reason = 0, addr_to_func = 0, icmp_info = 0, tcp_info = 0, time_load = 0, dns_info = 0, stack_info = 0, mysql_info = 0, - redis_info = 0, count_info = 0, rtt_info = 0, rst_info = 0; // flag - -static const char *tcp_states[] = { - [1] = "ESTABLISHED", [2] = "SYN_SENT", [3] = "SYN_RECV", - [4] = "FIN_WAIT1", [5] = "FIN_WAIT2", [6] = "TIME_WAIT", - [7] = "CLOSE", [8] = "CLOSE_WAIT", [9] = "LAST_ACK", - [10] = "LISTEN", [11] = "CLOSING", [12] = "NEW_SYN_RECV", - [13] = "UNKNOWN", -}; + redis_info = 0, count_info = 0, rtt_info = 0, rst_info = 0, + protocol_count = 0; // flag static const char argp_program_doc[] = "Watch tcp/ip in network subsystem \n"; static const struct argp_option opts[] = { @@ -85,6 +84,7 @@ static const struct argp_option opts[] = { "specify the time to count the number of requests"}, {"rtt", 'T', 0, 0, "set to trace rtt"}, {"rst_counters", 'U', 0, 0, "set to trace rst"}, + {"protocol_count", 'p', 0, 0, "set to trace protocol count"}, {}}; static error_t parse_arg(int key, char *arg, struct argp_state *state) { @@ -153,6 +153,9 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) { case 'U': rst_info = 1; break; + case 'p': + protocol_count = 1; + break; case 'C': count_info = strtoul(arg, &end, 10); break; @@ -161,32 +164,11 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) { } return 0; } - static const struct argp argp = { .options = opts, .parser = parse_arg, .doc = argp_program_doc, }; - -struct SymbolEntry { - unsigned long addr; - char name[30]; -}; - -enum MonitorMode { - MODE_UDP, - MODE_NET_FILTER, - MODE_DROP_REASON, - MODE_ICMP, - MODE_TCP, - MODE_DNS, - MODE_MYSQL, - MODE_REDIS, - MODE_RTT, - MODE_RST, - MODE_DEFAULT -}; - enum MonitorMode get_monitor_mode() { if (udp_info) { return MODE_UDP; @@ -208,6 +190,8 @@ enum MonitorMode get_monitor_mode() { return MODE_RTT; } else if (rst_info) { return MODE_RST; + } else if (protocol_count) { + return MODE_PROTOCOL_COUNT; } else { return MODE_DEFAULT; } @@ -229,7 +213,6 @@ enum MonitorMode get_monitor_mode() { " \\/_/\\/_/\\/____/ \\/__/ \\/__//__ / \\/_/ \\/_/\\/__/\\/____/ " \ "\\/_/\\/_/\\/____/ \\/_/ \n\n" -// 通过lolcat命令彩色处理 void print_logo() { char *logo = LOGO_STRING; int i = 0; @@ -248,7 +231,6 @@ void print_logo() { pclose(lolcat_pipe); } -static char binary_path[64] = ""; #define __ATTACH_UPROBE(skel, sym_name, prog_name, is_retprobe) \ do { \ LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts, .func_name = #sym_name, \ @@ -280,12 +262,9 @@ static char binary_path[64] = ""; __ATTACH_UPROBE_CHECKED(skel, sym_name, prog_name, false) #define ATTACH_URETPROBE_CHECKED(skel, sym_name, prog_name) \ __ATTACH_UPROBE_CHECKED(skel, sym_name, prog_name, true) + struct SymbolEntry symbols[300000]; -int num_symbols = 0; -// 定义快表 -#define CACHEMAXSIZE 5 struct SymbolEntry cache[CACHEMAXSIZE]; -int cache_size = 0; // LRU算法查找函数 struct SymbolEntry find_in_cache(unsigned long int addr) { // 查找地址是否在快表中 @@ -306,7 +285,6 @@ struct SymbolEntry find_in_cache(unsigned long int addr) { empty_entry.addr = 0; return empty_entry; } - // 将新的符号条目加入快表 void add_to_cache(struct SymbolEntry entry) { // 如果快表已满,则移除最久未使用的条目 @@ -324,7 +302,6 @@ void add_to_cache(struct SymbolEntry entry) { cache_size++; } } - struct SymbolEntry findfunc(unsigned long int addr) { // 先在快表中查找 struct SymbolEntry entry = find_in_cache(addr); @@ -376,17 +353,6 @@ void readallsym() { 3.可以快速适应数据的变化,并能够有效地检测异常时延 */ -struct LayerDelayInfo { - float delay; // 时延数据 - int layer_index; // 层索引 -}; -#define GRANULARITY 3 -#define ALPHA 0.2 // 衰减因子 -#define MAXTIME 10000 -#define SLOW_QUERY_THRESHOLD 10000 // -#define ANSI_COLOR_RED "\x1b[31m" -#define ANSI_COLOR_RESET "\x1b[0m" - // 全局变量用于存储每层的移动平均值 float ewma_values[NUM_LAYERS] = {0}; int count[NUM_LAYERS] = {0}; @@ -422,7 +388,6 @@ int process_delay(float layer_delay, int layer_index) { } return 0; } - static void set_rodata_flags(struct netwatcher_bpf *skel) { skel->rodata->filter_dport = dport; skel->rodata->filter_sport = sport; @@ -443,6 +408,7 @@ static void set_rodata_flags(struct netwatcher_bpf *skel) { skel->rodata->redis_info = redis_info; skel->rodata->rtt_info = rtt_info; skel->rodata->rst_info = rst_info; + skel->rodata->protocol_count = protocol_count; } static void set_disable_load(struct netwatcher_bpf *skel) { @@ -485,7 +451,7 @@ static void set_disable_load(struct netwatcher_bpf *skel) { bpf_program__set_autoload(skel->progs.eth_type_trans, (all_conn || err_packet || extra_conn_info || retrans_info || layer_time || http_info || - rtt_info) + rtt_info || protocol_count) ? true : false); bpf_program__set_autoload(skel->progs.ip_rcv_core, @@ -561,7 +527,7 @@ static void set_disable_load(struct netwatcher_bpf *skel) { bpf_program__set_autoload(skel->progs.dev_hard_start_xmit, (all_conn || err_packet || extra_conn_info || retrans_info || layer_time || http_info || - rtt_info) + rtt_info || protocol_count) ? true : false); bpf_program__set_autoload(skel->progs.tcp_enter_recovery, @@ -603,6 +569,8 @@ static void set_disable_load(struct netwatcher_bpf *skel) { redis_info ? true : false); bpf_program__set_autoload(skel->progs.query__start_redis_process, redis_info ? true : false); + bpf_program__set_autoload(skel->progs.redis_uprobe, + redis_info ? true : false); bpf_program__set_autoload(skel->progs.tcp_rcv_established, (all_conn || err_packet || extra_conn_info || retrans_info || layer_time || http_info || @@ -614,7 +582,6 @@ static void set_disable_load(struct netwatcher_bpf *skel) { bpf_program__set_autoload(skel->progs.handle_receive_reset, rst_info ? true : false); } - static void print_header(enum MonitorMode mode) { switch (mode) { case MODE_UDP: @@ -704,9 +671,14 @@ static void print_header(enum MonitorMode mode) { "SOCK", "Saddr", "Sport", "Daddr", "Dport", "MAC_TIME/μs", "IP_TIME/μs", "TRAN_TIME/μs", "RX/direction", "HTTP"); break; + case MODE_PROTOCOL_COUNT: + printf("===============================================================" + "=MODE_PROTOCOL_COUNT===========================================" + "========" + "======================\n"); + break; } } - static void open_log_files() { FILE *connect_file = fopen(connects_file_path, "w+"); if (connect_file == NULL) { @@ -736,9 +708,7 @@ static void open_log_files() { } fclose(udp_file); } - static void sig_handler(int signo) { exiting = true; } - static void bytes_to_str(char *str, unsigned long long num) { if (num > 1e9) { sprintf(str, "%.8lfG", (double)num / 1e9); @@ -750,7 +720,6 @@ static void bytes_to_str(char *str, unsigned long long num) { sprintf(str, "%llu", num); } } - static int print_conns(struct netwatcher_bpf *skel) { FILE *file = fopen(connects_file_path, "w"); @@ -841,10 +810,9 @@ static int print_conns(struct netwatcher_bpf *skel) { fclose(file); return 0; } - static int print_packet(void *ctx, void *packet_info, size_t size) { if (udp_info || net_filter || drop_reason || icmp_info || tcp_info || - dns_info || mysql_info || redis_info || rtt_info) + dns_info || mysql_info || redis_info || rtt_info || protocol_count) return 0; const struct pack_t *pack_info = packet_info; if (pack_info->mac_time > MAXTIME || pack_info->ip_time > MAXTIME || @@ -861,11 +829,9 @@ static int print_packet(void *ctx, void *packet_info, size_t size) { if (dport) if (pack_info->dport != dport) return 0; - if (sport) if (pack_info->sport != sport) return 0; - if (pack_info->err) { FILE *file = fopen(err_file_path, "a"); char reason[20]; @@ -991,10 +957,8 @@ static int print_udp(void *ctx, void *packet_info, size_t size) { printf("%-15s", "abnormal data"); } printf("\n"); - return 0; } - static int print_netfilter(void *ctx, void *packet_info, size_t size) { if (!net_filter) return 0; @@ -1041,7 +1005,6 @@ static int print_netfilter(void *ctx, void *packet_info, size_t size) { return 0; } - static int print_tcpstate(void *ctx, void *packet_info, size_t size) { if (!tcp_info) return 0; @@ -1058,7 +1021,81 @@ static int print_tcpstate(void *ctx, void *packet_info, size_t size) { return 0; } +static void calculate_protocol_usage(struct packet_count proto_stats[], + int num_protocols, int interval) { + static uint64_t last_rx[256] = {0}, last_tx[256] = {0}; + uint64_t current_rx = 0, current_tx = 0; + uint64_t delta_rx[256] = {0}, delta_tx[256] = {0}; + //遍历所有的协议 + for (int i = 0; i < num_protocols; i++) { + //计算数据包增量 + if (proto_stats[i].rx_count >= last_rx[i]) { + delta_rx[i] = proto_stats[i].rx_count - last_rx[i]; + } else { + delta_rx[i] = proto_stats[i].rx_count; + } + if (proto_stats[i].tx_count >= last_tx[i]) { + delta_tx[i] = proto_stats[i].tx_count - last_tx[i]; + } else { + delta_tx[i] = proto_stats[i].tx_count; + } + //时间段内总的接收和发送包数 + current_rx += delta_rx[i]; + current_tx += delta_tx[i]; + //更新上次统计的包数 + last_rx[i] = proto_stats[i].rx_count; + last_tx[i] = proto_stats[i].tx_count; + } + printf("Protocol Usage in Last %d Seconds:\n", interval); + printf("Total_rx_count:%ld Total_tx_count:%ld\n", current_rx, current_tx); + + if (current_rx > 0) { + printf("Receive Protocol Usage:\n"); + for (int i = 0; i < num_protocols; i++) { + if (delta_rx[i] > 0) { + double rx_percentage = (double)delta_rx[i] / current_rx * 100; + if (rx_percentage >= 80.0) { + printf(RED_TEXT + "Protocol %s: %.2f%% Rx_count:%ld\n" RESET_TEXT, + protocol[i], rx_percentage, delta_rx[i]); + } else { + printf("Protocol %s: %.2f%% Rx_count:%ld\n", protocol[i], + rx_percentage, delta_rx[i]); + } + } + } + } + if (current_tx > 0) { + printf("Transmit Protocol Usage:\n"); + for (int i = 0; i < num_protocols; i++) { + if (delta_tx[i] > 0) { + double tx_percentage = (double)delta_tx[i] / current_tx * 100; + if (tx_percentage >= 80.0) { + printf(RED_TEXT + "Protocol %s: %.2f%% Tx_count:%ld\n" RESET_TEXT, + protocol[i], tx_percentage, delta_tx[i]); + } else { + printf("Protocol %s: %.2f%% Tx_count:%ld\n", protocol[i], + tx_percentage, delta_tx[i]); + } + } + } + } + memset(proto_stats, 0, num_protocols * sizeof(struct packet_count)); +} +static int print_protocol_count(void *ctx, void *packet_info, size_t size) { + const struct packet_info *pack_protocol_info = + (const struct packet_info *)packet_info; + if (!protocol_count) { + return 0; + } + proto_stats[pack_protocol_info->proto].rx_count = + pack_protocol_info->count.rx_count; + proto_stats[pack_protocol_info->proto].tx_count = + pack_protocol_info->count.tx_count; + return 0; +} static int print_kfree(void *ctx, void *packet_info, size_t size) { if (!drop_reason) return 0; @@ -1097,7 +1134,6 @@ static int print_kfree(void *ctx, void *packet_info, size_t size) { printf("%s\n", SKB_Drop_Reason_Strings[pack_info->drop_reason]); return 0; } - static int print_icmptime(void *ctx, void *packet_info, size_t size) { if (!icmp_info) return 0; @@ -1122,13 +1158,10 @@ static int print_icmptime(void *ctx, void *packet_info, size_t size) { printf("\n"); return 0; } -#define MAX_EVENTS 1024 - -static __u64 rst_count = 0; -static struct reset_event_t event_store[MAX_EVENTS]; -static int event_count = 0; - static int print_rst(void *ctx, void *packet_info, size_t size) { + if (!rst_info) { + return 0; + } struct reset_event_t *event = packet_info; // 将事件存储到全局存储中 @@ -1140,7 +1173,7 @@ static int print_rst(void *ctx, void *packet_info, size_t size) { rst_count++; return 0; } -void print_stored_events() { +static void print_stored_events() { char s_str[INET_ADDRSTRLEN]; char d_str[INET_ADDRSTRLEN]; @@ -1168,7 +1201,6 @@ void print_stored_events() { } } } -// 从DNS数据包中提取并打印域名 static void print_domain_name(const unsigned char *data, char *output) { const unsigned char *next = data; int pos = 0, first = 1; @@ -1187,7 +1219,6 @@ static void print_domain_name(const unsigned char *data, char *output) { } output[pos] = '\0'; // 确保字符串正确结束 } - static int print_dns(void *ctx, void *packet_info, size_t size) { if (!packet_info) return 0; @@ -1214,7 +1245,6 @@ static int print_dns(void *ctx, void *packet_info, size_t size) { pack_info->rx); return 0; } - static int print_mysql(void *ctx, void *packet_info, size_t size) { if (!mysql_info) { return 0; @@ -1223,7 +1253,6 @@ static int print_mysql(void *ctx, void *packet_info, size_t size) { const mysql_query *pack_info = packet_info; printf("%-20d %-20d %-20s %-20u %-41s", pack_info->pid, pack_info->tid, pack_info->comm, pack_info->size, pack_info->msql); - // 当 duratime 大于 count_info 时,才打印 duratime if (pack_info->duratime > count_info) { printf("%-21llu", pack_info->duratime); } else { @@ -1232,7 +1261,6 @@ static int print_mysql(void *ctx, void *packet_info, size_t size) { printf("%-20d\n", pack_info->count); return 0; } - static int print_redis(void *ctx, void *packet_info, size_t size) { const struct redis_query *pack_info = packet_info; int i = 0; @@ -1283,7 +1311,6 @@ static int print_trace(void *_ctx, void *data, size_t size) { printf("\n"); return 0; } - static int print_rtt(void *ctx, void *data, size_t size) { if (!rtt_info) return 0; @@ -1331,12 +1358,9 @@ static int print_rtt(void *ctx, void *data, size_t size) { printf("\n"); bucket_size *= 2; //以对数方式扩展 } - printf("===============================================================\n"); - return 0; } - int attach_uprobe_mysql(struct netwatcher_bpf *skel) { ATTACH_UPROBE_CHECKED( @@ -1377,6 +1401,7 @@ int main(int argc, char **argv) { struct ring_buffer *redis_rb = NULL; struct ring_buffer *rtt_rb = NULL; struct ring_buffer *events = NULL; + struct ring_buffer *port_rb = NULL; struct netwatcher_bpf *skel; int err; /* Parse command line arguments */ @@ -1385,12 +1410,10 @@ int main(int argc, char **argv) { if (err) return err; } - libbpf_set_print(libbpf_print_fn); /* Cleaner handling of Ctrl-C */ signal(SIGINT, sig_handler); signal(SIGTERM, sig_handler); - /* Open load and verify BPF application */ skel = netwatcher_bpf__open(); if (!skel) { @@ -1403,13 +1426,11 @@ int main(int argc, char **argv) { if (addr_to_func) readallsym(); - err = netwatcher_bpf__load(skel); if (err) { fprintf(stderr, "Failed to load and verify BPF skeleton\n"); goto cleanup; } - /* Attach tracepoint handler */ if (mysql_info) { strcpy(binary_path, "/usr/sbin/mysqld"); @@ -1517,6 +1538,14 @@ int main(int argc, char **argv) { fprintf(stderr, "Failed to create ring buffer(rst_rb)\n"); goto cleanup; } + + port_rb = ring_buffer__new(bpf_map__fd(skel->maps.port_rb), + print_protocol_count, NULL, NULL); + if (!port_rb) { + err = -1; + fprintf(stderr, "Failed to create ring buffer(trace)\n"); + goto cleanup; + } /* Set up ring buffer polling */ rb = ring_buffer__new(bpf_map__fd(skel->maps.rb), print_packet, NULL, NULL); if (!rb) { @@ -1542,6 +1571,8 @@ int main(int argc, char **argv) { err = ring_buffer__poll(redis_rb, 100 /* timeout, ms */); err = ring_buffer__poll(rtt_rb, 100 /* timeout, ms */); err = ring_buffer__poll(events, 100 /* timeout, ms */); + err = ring_buffer__poll(port_rb, 100 /* timeout, ms */); + print_conns(skel); sleep(1); /* Ctrl-C will cause -EINTR */ @@ -1555,14 +1586,21 @@ int main(int argc, char **argv) { } gettimeofday(&end, NULL); - if ((end.tv_sec - start.tv_sec) >= 5) { - print_stored_events(); - printf("Total RSTs in the last 5 seconds: %llu\n\n", rst_count); - - // 重置计数器和事件存储 - rst_count = 0; - event_count = 0; - gettimeofday(&start, NULL); + if (rst_info || protocol_count) { + if ((end.tv_sec - start.tv_sec) >= 5) { + if (rst_info) { + print_stored_events(); + printf("Total RSTs in the last 5 seconds: %llu\n\n", + rst_count); + + // 重置计数器和事件存储 + rst_count = 0; + event_count = 0; + } else if (protocol_count) { + calculate_protocol_usage(proto_stats, 256, 5); + } + gettimeofday(&start, NULL); + } } } diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.h b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.h index e7559671d..546cd1886 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.h +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.h @@ -41,6 +41,21 @@ typedef unsigned long long u64; #define MAX_COMM 16 #define TCP 1 #define UDP 2 +#define MAX_PACKET 1000 +#define MAX_HTTP_HEADER 256 +#define NUM_LAYERS 5 +#define RED_TEXT "\033[31m" +#define RESET_TEXT "\033[0m" +#define GRANULARITY 3 +#define ALPHA 0.2 // 衰减因子 +#define MAXTIME 10000 +#define SLOW_QUERY_THRESHOLD 10000 // +#define ANSI_COLOR_RED "\x1b[31m" +#define ANSI_COLOR_RESET "\x1b[0m" +#define MAX_STACK_DEPTH 128 +#define MAX_EVENTS 1024 +#define CACHEMAXSIZE 5 +typedef u64 stack_trace_t[MAX_STACK_DEPTH]; struct conn_t { void *sock; // 此tcp连接的 socket 地址 @@ -75,10 +90,6 @@ struct conn_t { u64 duration; // 连接已建立时长 }; -#define MAX_PACKET 1000 -#define MAX_HTTP_HEADER 256 -#define NUM_LAYERS 5 - struct pack_t { int err; // no err(0) invalid seq(1) invalid checksum(2) u64 mac_time; // mac layer 处理时间(us) @@ -144,7 +155,6 @@ struct tcp_state { int newstate; u64 time; }; - struct dns_information { u32 saddr; u32 daddr; @@ -159,8 +169,6 @@ struct dns_information { int response_count; int request_count; }; -#define MAX_STACK_DEPTH 128 -typedef u64 stack_trace_t[MAX_STACK_DEPTH]; struct stacktrace_event { u32 pid; u32 cpu_id; @@ -170,7 +178,6 @@ struct stacktrace_event { stack_trace_t kstack; stack_trace_t ustack; }; - typedef struct mysql_query { int pid; int tid; @@ -180,7 +187,6 @@ typedef struct mysql_query { u64 duratime; int count; } mysql_query; - struct redis_query { int pid; int tid; @@ -192,7 +198,6 @@ struct redis_query { u64 begin_time; int argc; }; - struct RTT { u32 saddr; u32 daddr; @@ -200,7 +205,6 @@ struct RTT { u64 latency; u64 cnt; }; - struct reset_event_t { int pid; char comm[16]; @@ -216,4 +220,51 @@ struct reset_event_t { u64 timestamp; u8 state; }; +struct packet_count { + u64 rx_count; + u64 tx_count; +}; +struct packet_info { + u32 saddr; + u32 daddr; + u16 sport; + u16 dport; + u16 proto; + struct packet_count count; +}; +struct SymbolEntry { + unsigned long addr; + char name[30]; +}; +enum MonitorMode { + MODE_UDP, + MODE_NET_FILTER, + MODE_DROP_REASON, + MODE_ICMP, + MODE_TCP, + MODE_DNS, + MODE_MYSQL, + MODE_REDIS, + MODE_RTT, + MODE_RST, + MODE_PROTOCOL_COUNT, + MODE_DEFAULT +}; +static const char *protocol[] = { + [0] = "TCP", + [1] = "UDP", + [2] = "ICMP", + [3] = "UNKNOWN", +}; +static const char *tcp_states[] = { + [1] = "ESTABLISHED", [2] = "SYN_SENT", [3] = "SYN_RECV", + [4] = "FIN_WAIT1", [5] = "FIN_WAIT2", [6] = "TIME_WAIT", + [7] = "CLOSE", [8] = "CLOSE_WAIT", [9] = "LAST_ACK", + [10] = "LISTEN", [11] = "CLOSING", [12] = "NEW_SYN_RECV", + [13] = "UNKNOWN", +}; +struct LayerDelayInfo { + float delay; // 时延数据 + int layer_index; // 层索引 +}; #endif /* __NETWATCHER_H */ \ No newline at end of file diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/packet.bpf.h b/eBPF_Supermarket/Network_Subsystem/net_watcher/packet.bpf.h index d515ef54b..c75dbea20 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/packet.bpf.h +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/packet.bpf.h @@ -30,9 +30,93 @@ kprobe/tcp_v6_do_rcv kprobe/skb_copy_datagram_iter */ -static __always_inline -int __eth_type_trans(struct sk_buff *skb) -{ +static __always_inline struct packet_count *count_packet(u32 proto, + bool is_tx) { + struct packet_count *count; + struct packet_count initial_count = {0}; + + count = bpf_map_lookup_elem(&proto_stats, &proto); + if (!count) { + initial_count.tx_count = 0; + initial_count.rx_count = 0; + if (bpf_map_update_elem(&proto_stats, &proto, &initial_count, + BPF_ANY)) { + return NULL; + } + count = bpf_map_lookup_elem(&proto_stats, &proto); + if (!count) { + return NULL; + } + } + + if (is_tx) + __sync_fetch_and_add(&count->tx_count, 1); + else + __sync_fetch_and_add(&count->rx_count, 1); + return count; +} + +static __always_inline int sum_protocol(struct sk_buff *skb, bool is_tx) { + const struct ethhdr *eth = (struct ethhdr *)BPF_CORE_READ(skb, data); + u16 proto = BPF_CORE_READ(eth, h_proto); + + struct packet_info *pkt = bpf_ringbuf_reserve(&port_rb, sizeof(*pkt), 0); + if (!pkt) { + return 0; + } + + if (BPF_CORE_READ(eth, h_proto) != __bpf_htons(ETH_P_IP)) { + bpf_ringbuf_discard(pkt, 0); + return 0; + } + + struct iphdr *ip = (struct iphdr *)(BPF_CORE_READ(skb, data) + 14); + if (!ip) { + bpf_ringbuf_discard(pkt, 0); + return 0; + } + + pkt->saddr = BPF_CORE_READ(ip, saddr); + pkt->daddr = BPF_CORE_READ(ip, daddr); + pkt->proto = BPF_CORE_READ(ip, protocol); + + if (pkt->proto == IPPROTO_TCP) { + struct tcphdr *tcp = + (struct tcphdr *)(BPF_CORE_READ(skb, data) + sizeof(struct ethhdr) + + sizeof(struct iphdr)); + pkt->sport = BPF_CORE_READ(tcp, source); + pkt->dport = BPF_CORE_READ(tcp, dest); + pkt->proto = PROTO_TCP; + } else if (pkt->proto == IPPROTO_UDP) { + struct udphdr *udp = + (struct udphdr *)(BPF_CORE_READ(skb, data) + sizeof(struct ethhdr) + + sizeof(struct iphdr)); + pkt->sport = BPF_CORE_READ(udp, source); + pkt->dport = BPF_CORE_READ(udp, dest); + pkt->proto = PROTO_UDP; + } else if (pkt->proto == IPPROTO_ICMP) { + pkt->proto = PROTO_ICMP; + } else { + pkt->proto = PROTO_UNKNOWN; + } + struct packet_count *count = count_packet(pkt->proto, is_tx); + if (count) { + pkt->count.tx_count = count->tx_count; + pkt->count.rx_count = count->rx_count; + } else { + pkt->count.tx_count = 0; + pkt->count.rx_count = 0; + } + + // bpf_printk("pkt: saddr=%u, daddr=%u, proto=%u\n", pkt->saddr, pkt->daddr, + // pkt->proto); bpf_printk("sport=%d, dport=%d\n", pkt->sport, pkt->dport); + // bpf_printk("count_tx=%llu, count_rx=%llu\n", pkt->count.tx_count, + // pkt->count.rx_count); + bpf_ringbuf_submit(pkt, 0); + + return 0; +} +static __always_inline int __eth_type_trans(struct sk_buff *skb) { const struct ethhdr *eth = (struct ethhdr *)BPF_CORE_READ(skb, data); // 读取里面的报文数据 u16 protocol = BPF_CORE_READ(eth, h_proto); // 读取包ID @@ -81,9 +165,7 @@ int __eth_type_trans(struct sk_buff *skb) return 0; } -static __always_inline -int __ip_rcv_core(struct sk_buff *skb) -{ +static __always_inline int __ip_rcv_core(struct sk_buff *skb) { if (!layer_time) { return 0; } @@ -105,9 +187,7 @@ int __ip_rcv_core(struct sk_buff *skb) return 0; } -static __always_inline -int __ip6_rcv_core( struct sk_buff *skb) -{ +static __always_inline int __ip6_rcv_core(struct sk_buff *skb) { if (!layer_time) { return 0; } @@ -128,9 +208,7 @@ int __ip6_rcv_core( struct sk_buff *skb) // bpf_printk("rx enter ipv6 layer.\n"); return 0; } -static __always_inline -int __tcp_v4_rcv(struct sk_buff *skb) -{ +static __always_inline int __tcp_v4_rcv(struct sk_buff *skb) { if (!layer_time) { return 0; } @@ -149,9 +227,7 @@ int __tcp_v4_rcv(struct sk_buff *skb) // bpf_printk("rx enter tcp4 layer.\n"); return 0; } -static __always_inline -int __tcp_v6_rcv(struct sk_buff *skb) -{ +static __always_inline int __tcp_v6_rcv(struct sk_buff *skb) { if (!layer_time) { return 0; } @@ -171,9 +247,8 @@ int __tcp_v6_rcv(struct sk_buff *skb) // bpf_printk("rx enter tcp6 layer.\n"); return 0; } -static __always_inline -int __tcp_v4_do_rcv(struct sock *sk,struct sk_buff *skb) -{ +static __always_inline int __tcp_v4_do_rcv(struct sock *sk, + struct sk_buff *skb) { if (sk == NULL || skb == NULL) return 0; struct conn_t *conn = bpf_map_lookup_elem(&conns_info, &sk); @@ -201,9 +276,8 @@ int __tcp_v4_do_rcv(struct sock *sk,struct sk_buff *skb) return 0; } -static __always_inline -int __tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) -{ +static __always_inline int __tcp_v6_do_rcv(struct sock *sk, + struct sk_buff *skb) { if (sk == NULL || skb == NULL) return 0; // bpf_printk("rx enter tcp6_do_rcv. \n"); @@ -233,9 +307,7 @@ int __tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) return 0; } -static __always_inline -int __skb_copy_datagram_iter(struct sk_buff *skb) -{ +static __always_inline int __skb_copy_datagram_iter(struct sk_buff *skb) { if (skb == NULL) return 0; __be16 protocol = BPF_CORE_READ(skb, protocol); // 读取skb协议字段 @@ -296,8 +368,7 @@ int __skb_copy_datagram_iter(struct sk_buff *skb) int doff = BPF_CORE_READ_BITFIELD_PROBED(tcp, doff); // 得用bitfield_probed // 读取tcp头部中的数据偏移字段 - u8 *user_data = - (u8 *)((u8 *)tcp + (doff * 4)); + u8 *user_data = (u8 *)((u8 *)tcp + (doff * 4)); // 计算tcp的负载开始位置就是tcp头部之后的数据,将tcp指针指向tcp头部位置将其转换成unsigned // char类型 // doff * @@ -321,9 +392,8 @@ int __skb_copy_datagram_iter(struct sk_buff *skb) kprobe/dev_queue_xmit kprobe/dev_hard_start_xmit */ -static __always_inline -int __tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) -{ +static __always_inline int __tcp_sendmsg(struct sock *sk, struct msghdr *msg, + size_t size) { struct conn_t *conn = bpf_map_lookup_elem(&conns_info, &sk); if (conn == NULL) { return 0; @@ -403,9 +473,8 @@ int __tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) } return 0; } -static __always_inline -int __ip_queue_xmit(struct sock *sk, struct sk_buff *skb) -{ +static __always_inline int __ip_queue_xmit(struct sock *sk, + struct sk_buff *skb) { if (!layer_time) { return 0; } @@ -431,11 +500,11 @@ int __ip_queue_xmit(struct sock *sk, struct sk_buff *skb) } tinfo->ip_time = bpf_ktime_get_ns() / 1000; } + return 0; } -static __always_inline -int __inet6_csk_xmit(struct sock *sk, struct sk_buff *skb) -{ +static __always_inline int __inet6_csk_xmit(struct sock *sk, + struct sk_buff *skb) { if (!layer_time) { return 0; } @@ -472,9 +541,7 @@ int __inet6_csk_xmit(struct sock *sk, struct sk_buff *skb) } return 0; } -static __always_inline -int dev_queue_xmit(struct sk_buff *skb) -{ +static __always_inline int dev_queue_xmit(struct sk_buff *skb) { if (!layer_time) { return 0; } @@ -484,7 +551,7 @@ int dev_queue_xmit(struct sk_buff *skb) eth, h_proto); // 以太网头部协议字段该字段存储的是以太网帧所封装的上层协议类型 struct tcphdr *tcp = skb_to_tcphdr(skb); -struct packet_tuple pkt_tuple = {0}; + struct packet_tuple pkt_tuple = {0}; struct ktime_info *tinfo; if (protocol == __bpf_ntohs(ETH_P_IP)) { /** ipv4 */ @@ -507,9 +574,7 @@ struct packet_tuple pkt_tuple = {0}; } return 0; } -static __always_inline -int __dev_hard_start_xmit(struct sk_buff *skb) -{ +static __always_inline int __dev_hard_start_xmit(struct sk_buff *skb) { const struct ethhdr *eth = (struct ethhdr *)BPF_CORE_READ(skb, data); u16 protocol = BPF_CORE_READ(eth, h_proto); struct tcphdr *tcp = skb_to_tcphdr(skb); @@ -555,14 +620,17 @@ int __dev_hard_start_xmit(struct sk_buff *skb) if (layer_time) { packet->tran_time = tinfo->ip_time - tinfo->tran_time; packet->ip_time = tinfo->mac_time - tinfo->ip_time; - packet->mac_time =tinfo->qdisc_time -tinfo->mac_time; // 队列纪律层,处于网络协议栈最底层,负责实际数据传输与接收 + packet->mac_time = + tinfo->qdisc_time - + tinfo + ->mac_time; // 队列纪律层,处于网络协议栈最底层,负责实际数据传输与接收 } packet->rx = 0; // 发送一个数据包 // TX HTTP Info if (http_info) { bpf_probe_read_str(packet->data, sizeof(packet->data), tinfo->data); - // bpf_printk("%s", packet->data); + // bpf_printk("%s", packet->data); } bpf_ringbuf_submit(packet, 0); From 3140cbecfa980df6ba45648642b252981db44a81 Mon Sep 17 00:00:00 2001 From: wynyibo Date: Fri, 6 Sep 2024 15:35:06 +0800 Subject: [PATCH 02/13] update --- eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c index 452666aa9..af54d02c4 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c @@ -1592,8 +1592,6 @@ int main(int argc, char **argv) { print_stored_events(); printf("Total RSTs in the last 5 seconds: %llu\n\n", rst_count); - - // 重置计数器和事件存储 rst_count = 0; event_count = 0; } else if (protocol_count) { @@ -1603,7 +1601,6 @@ int main(int argc, char **argv) { } } } - cleanup: netwatcher_bpf__destroy(skel); return err < 0 ? -err : 0; From 009d485b493a541e92ba2a0eb657343790abbbaa Mon Sep 17 00:00:00 2001 From: wynyibo Date: Fri, 6 Sep 2024 15:51:28 +0800 Subject: [PATCH 03/13] delete --- .../Network_Subsystem/net_watcher/netwatcher.bpf.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.bpf.c b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.bpf.c index aac2ca650..ab34155d9 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.bpf.c +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.bpf.c @@ -326,8 +326,7 @@ SEC("uprobe/processCommand") int BPF_KPROBE(query__start_redis_process) { return __handle_redis_start(ctx); } SEC("uretprobe/call") int BPF_KPROBE(query__end_redis) { return __handle_redis_end(ctx); } -SEC("uprobe/lookupKey") -int BPF_KPROBE(redis_uprobe) { return __handle_lookupKey(ctx); } + // rtt SEC("kprobe/tcp_rcv_established") int BPF_KPROBE(tcp_rcv_established, struct sock *sk, struct sk_buff *skb) { From 6e54d1d4079150c7794a6de45708a043179000d7 Mon Sep 17 00:00:00 2001 From: wynyibo Date: Fri, 6 Sep 2024 15:57:02 +0800 Subject: [PATCH 04/13] delete --- eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c index af54d02c4..a207afccd 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/netwatcher.c @@ -569,8 +569,6 @@ static void set_disable_load(struct netwatcher_bpf *skel) { redis_info ? true : false); bpf_program__set_autoload(skel->progs.query__start_redis_process, redis_info ? true : false); - bpf_program__set_autoload(skel->progs.redis_uprobe, - redis_info ? true : false); bpf_program__set_autoload(skel->progs.tcp_rcv_established, (all_conn || err_packet || extra_conn_info || retrans_info || layer_time || http_info || From 266fdf8ed652804933e4bfa86407dd2efaf09347 Mon Sep 17 00:00:00 2001 From: wynyibo Date: Fri, 13 Sep 2024 21:51:22 +0800 Subject: [PATCH 05/13] move net_watcher to MagicEyes --- .../backend/net/net_watcher/bpf/common.bpf.h | 670 ++++++++ .../backend/net/net_watcher/bpf/drop.bpf.h | 48 + .../backend/net/net_watcher/bpf/icmp.bpf.h | 90 + .../backend/net/net_watcher/bpf/mysql.bpf.h | 78 + .../net/net_watcher/bpf/mysql_helper.bpf.h | 171 ++ .../net/net_watcher/bpf/net_watcher.bpf.c | 1416 ++-------------- .../net/net_watcher/bpf/netfilter.bpf.h | 132 ++ .../backend/net/net_watcher/bpf/packet.bpf.h | 638 +++++++ .../backend/net/net_watcher/bpf/redis.bpf.h | 167 ++ .../net/net_watcher/bpf/redis_helper.bpf.h | 55 + .../src/backend/net/net_watcher/bpf/tcp.bpf.h | 444 +++++ .../src/backend/net/net_watcher/bpf/udp.bpf.h | 206 +++ .../net/net_watcher/include/dropreason.h | 100 ++ .../net/net_watcher/include/net_watcher.h | 272 ++- .../backend/net/net_watcher/src/net_watcher.c | 1507 +++++++++++++++-- 15 files changed, 4561 insertions(+), 1433 deletions(-) create mode 100644 MagicEyes/src/backend/net/net_watcher/bpf/common.bpf.h create mode 100644 MagicEyes/src/backend/net/net_watcher/bpf/drop.bpf.h create mode 100644 MagicEyes/src/backend/net/net_watcher/bpf/icmp.bpf.h create mode 100644 MagicEyes/src/backend/net/net_watcher/bpf/mysql.bpf.h create mode 100644 MagicEyes/src/backend/net/net_watcher/bpf/mysql_helper.bpf.h create mode 100644 MagicEyes/src/backend/net/net_watcher/bpf/netfilter.bpf.h create mode 100644 MagicEyes/src/backend/net/net_watcher/bpf/packet.bpf.h create mode 100644 MagicEyes/src/backend/net/net_watcher/bpf/redis.bpf.h create mode 100644 MagicEyes/src/backend/net/net_watcher/bpf/redis_helper.bpf.h create mode 100644 MagicEyes/src/backend/net/net_watcher/bpf/tcp.bpf.h create mode 100644 MagicEyes/src/backend/net/net_watcher/bpf/udp.bpf.h create mode 100644 MagicEyes/src/backend/net/net_watcher/include/dropreason.h diff --git a/MagicEyes/src/backend/net/net_watcher/bpf/common.bpf.h b/MagicEyes/src/backend/net/net_watcher/bpf/common.bpf.h new file mode 100644 index 000000000..de6d3e5cd --- /dev/null +++ b/MagicEyes/src/backend/net/net_watcher/bpf/common.bpf.h @@ -0,0 +1,670 @@ +// Copyright 2023 The LMP Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://github.com/linuxkerneltravel/lmp/blob/develop/LICENSE +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: blown.away@qq.com +// +// net_watcher libbpf 内核<->用户 传递信息相关结构体 + +#ifndef __COMMON_BPF_H +#define __COMMON_BPF_H + +#include "net_watcher.h" +#include "vmlinux.h" +#include +#include +#include +#include +#include +#include + +struct ktime_info { // us time stamp info发送数据包 + u64 qdisc_time; // tx包离开mac层时间戳 + u64 mac_time; // tx、rx包到达mac层时间戳 + u64 ip_time; // tx、rx包到达ip层时间戳 + // u64 tcp_time; // tx、rx包到达tcp层时间戳 + u64 tran_time; // tx、rx包到达传输层时间戳 + u64 app_time; // rx包离开tcp层时间戳 + void *sk; // 此包所属 socket套接字 + u8 data[MAX_HTTP_HEADER]; // 用户层数据 +}; + +struct packet_tuple { + unsigned __int128 saddr_v6; // ipv6 源地址 + unsigned __int128 daddr_v6; // ipv6 目的地址 + u32 saddr; // 源地址 + u32 daddr; // 目的地址 + u16 sport; // 源端口号 + u16 dport; // 目的端口号 + u32 seq; // seq报文序号 + u32 ack; // ack确认号 + u32 tran_flag; // 1:tcp 2:udp + u32 len; +}; + +struct tcpstate { + u32 saddr; + u32 daddr; + u16 sport; + u16 dport; + u16 family; + int oldstate; + int newstate; + u64 time; +}; + +enum { + e_ip_rcv = 0, + e_ip_local_deliver, + e_ip_local_deliver_finish, + e_ip__forward, + e_ip_local_out, + e_ip_output, + e_ip_finish_output, + e_ip_forward, + nf_max +} nf_hook; + +enum { + PROTO_TCP = 0, + PROTO_UDP, + PROTO_ICMP, + PROTO_UNKNOWN, + PROTO_MAX, +}; + +struct filtertime { + struct packet_tuple init; + struct packet_tuple done; + u64 time[nf_max]; +}; + +struct ip_packet { + unsigned int saddr; // 源地址 + unsigned int daddr; // 目的地址 +}; + +struct dns_header { + u16 id; // 事务ID + u16 flags; // 标志字段 + u16 qdcount; // 问题部分计数 + u16 ancount; // 应答记录计数 + u16 nscount; // 授权记录计数 + u16 arcount; // 附加记录计数 +}; + +struct dns_query { + struct dns_header header; // DNS头部 + char data[64]; // 可变长度数据(域名+类型+类) +}; + +struct dns { + u32 saddr; + u32 daddr; +}; + +struct query_info { + char msql[256]; + u32 size; + u64 start_time; +}; + +struct hist { + u64 slots[MAX_SLOTS]; + u64 latency; + u64 cnt; +}; + +struct trace_event_raw_tcp_send_reset { + unsigned short common_type; + unsigned char common_flags; + unsigned char common_preempt_count; + int common_pid; + const void *skbaddr; + const void *skaddr; + int state; + __u16 sport; + __u16 dport; + __u16 family; + __u8 saddr[4]; + __u8 daddr[4]; + __u8 saddr_v6[16]; + __u8 daddr_v6[16]; +}; + +struct trace_event_raw_tcp_receive_reset { + unsigned short common_type; + unsigned char common_flags; + unsigned char common_preempt_count; + int common_pid; + const void *skaddr; + __u16 sport; + __u16 dport; + __u16 family; + __u8 saddr[4]; + __u8 daddr[4]; + __u8 saddr_v6[16]; + __u8 daddr_v6[16]; + __u64 sock_cookie; +}; +#define MAX_CONN 1000 +#define MAX_SLOTS 27 +// 操作BPF映射的一个辅助函数 +static __always_inline void * //__always_inline强制内联 +bpf_map_lookup_or_try_init(void *map, const void *key, const void *init) { + void *val; + long err; + + val = bpf_map_lookup_elem(map, key); // 在BPF映射中查找具有给定键的条目 + if (val) + return val; + // 此时没有对应key的value + err = bpf_map_update_elem(map, key, init, + BPF_NOEXIST); // 向BPF映射中插入或更新一个条目 + if (err && err != -EEXIST) // 插入失败 + return 0; + + return bpf_map_lookup_elem(map, key); // 返回对应value值 +} + +char LICENSE[] SEC("license") = "Dual BSD/GPL"; + +// 存储每个packet_tuple包所对应的ktime_info时间戳 +struct { + __uint(type, BPF_MAP_TYPE_LRU_HASH); + __uint(max_entries, MAX_CONN *MAX_PACKET); + __type(key, struct packet_tuple); + __type(value, struct ktime_info); +} timestamps SEC(".maps"); + +// 包相关信息通过此buffer提供给userspace +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 1024); +} rb SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 1024); +} rtt_rb SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 1024); +} udp_rb SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 1024); +} netfilter_rb SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 1024); +} mysql_rb SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 1024); +} redis_rb SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 1024); +} kfree_rb SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 1024); +} icmp_rb SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 1024); +} tcp_rb SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 1024); +} dns_rb SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 1024); +} trace_rb SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 1024); +} redis_stat_rb SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 1024); +} events SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 1024); +} port_rb SEC(".maps"); + +// 存储每个tcp连接所对应的conn_t +struct { + __uint(type, BPF_MAP_TYPE_LRU_HASH); + __uint(max_entries, MAX_CONN); + __type(key, struct sock *); + __type(value, struct conn_t); +} conns_info SEC(".maps"); + +// 根据ptid存储sock指针,从而在上下文无sock的内核探测点获得sock +struct { + __uint(type, BPF_MAP_TYPE_LRU_HASH); + __uint(max_entries, MAX_CONN); + __type(key, u64); + __type(value, struct sock *); +} sock_stores SEC(".maps"); + +// 存储每个pid所对应的udp包 +struct { + __uint(type, BPF_MAP_TYPE_LRU_HASH); + __uint(max_entries, MAX_CONN *MAX_PACKET); + __type(key, int); + __type(value, struct packet_tuple); +} pid_UDP SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_LRU_HASH); + __uint(max_entries, MAX_CONN *MAX_PACKET); + __type(key, struct sk_buff *); + __type(value, struct filtertime); +} netfilter_time SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_LRU_HASH); + __uint(max_entries, MAX_CONN *MAX_PACKET); + __type(key, int); + __type(value, struct packet_tuple); +} kfree SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_LRU_HASH); + __uint(max_entries, MAX_CONN *MAX_PACKET); + __type(key, struct ip_packet); + __type(value, unsigned long long); +} icmp_time SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 256 * 1024); + __type(key, struct sock *); + __type(value, __u64); +} tcp_state SEC(".maps"); + +// sql 耗时 +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 256 * 1024); + __type(key, __u32); + __type(value, __u64); +} mysql_time SEC(".maps"); + +// redis 耗时 +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 256 * 1024); + __type(key, __u32); + __type(value, struct redis_query); +} redis_time SEC(".maps"); + +// sql请求数 +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 1024); + __type(key, __u32); + __type(value, __u64); +} sql_count SEC(".maps"); + +// dns计数根据每个saddr、daddr +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 1024); + __type(key, struct dns); + __type(value, __u64); +} dns_request_count SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 1024); + __type(key, struct dns); + __type(value, __u64); +} dns_response_count SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 1024); + __type(key, __u32); + __type(value, struct query_info); +} queries SEC(".maps"); + +// 定义一个哈希映射,用于存储直方图数据 +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 256 * 1024); + __type(key, struct ip_packet); + __type(value, struct hist); +} hists SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __type(key, u32); + __type(value, u64); + __uint(max_entries, 1024); +} counters SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(max_entries, MAX_COMM *MAX_PACKET); + __type(key, u32); + __type(value, struct packet_count); +} proto_stats SEC(".maps"); +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __type(key, char*); // 键的最大长度,假设为 256 字节 + __type(value, u32); // 计数值 + __uint(max_entries, 1024); // 最大条目数 +} key_count SEC(".maps"); + +const volatile int filter_dport = 0; +const volatile int filter_sport = 0; +const volatile int all_conn = 0, err_packet = 0, extra_conn_info = 0, + layer_time = 0, http_info = 0, retrans_info = 0, + udp_info = 0, net_filter = 0, drop_reason = 0, icmp_info = 0, + tcp_info = 0, dns_info = 0, stack_info = 0, mysql_info = 0, + redis_info = 0, rtt_info = 0, rst_info = 0, + protocol_count = 0,redis_stat = 0;; + +/* help macro */ + +#define FILTER \ + if (filter_dport && filter_dport != pkt_tuple.dport) \ + return 0; \ + if (filter_sport && filter_sport != pkt_tuple.sport) \ + return 0; + +// 连接的目标端口是否匹配于filter_dport的值 +#define FILTER_DPORT \ + if (filter_dport) { \ + if (conn.dport != filter_dport) { \ + return 0; \ + } \ + } +// 连接的源端口是否匹配于filter_sport的值 +#define FILTER_SPORT \ + if (filter_sport) { \ + if (conn.sport != filter_sport) { \ + return 0; \ + } \ + } + +// 初始化conn_t结构 +#define CONN_INIT \ + struct conn_t conn = {0}; \ + conn.pid = ptid >> 32; \ + conn.ptid = ptid; \ + u16 protocol = BPF_CORE_READ(sk, sk_protocol); \ + if (protocol != IPPROTO_TCP) \ + return 0; \ + bpf_get_current_comm(&conn.comm, sizeof(conn.comm)); \ + conn.sock = sk; \ + u16 family = BPF_CORE_READ(sk, __sk_common.skc_family); \ + __be16 dport = BPF_CORE_READ(sk, __sk_common.skc_dport); \ + u16 sport = BPF_CORE_READ(sk, __sk_common.skc_num); \ + conn.family = family; \ + conn.sport = sport; \ + conn.dport = __bpf_ntohs(dport); \ + conn.init_timestamp = bpf_ktime_get_ns() / 1000; + +//初始化conn_t地址相关信息 +#define CONN_ADD_ADDRESS \ + if (family == AF_INET) { \ + conn.saddr = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr); \ + conn.daddr = BPF_CORE_READ(sk, __sk_common.skc_daddr); \ + } else if (family == AF_INET6) { \ + bpf_probe_read_kernel( \ + &conn.saddr_v6, \ + sizeof(sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32), \ + &sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32); \ + bpf_probe_read_kernel( \ + &conn.daddr_v6, \ + sizeof(sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32), \ + &sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32); \ + } + +//初始化conn其余额外信息 +#define CONN_ADD_EXTRA_INFO \ + if (extra_conn_info) { \ + struct tcp_sock *tp = (struct tcp_sock *)sk; \ + conn->srtt = BPF_CORE_READ(tp, srtt_us); \ + conn->duration = bpf_ktime_get_ns() / 1000 - conn->init_timestamp; \ + conn->bytes_acked = BPF_CORE_READ(tp, bytes_acked); \ + conn->bytes_received = BPF_CORE_READ(tp, bytes_received); \ + conn->snd_cwnd = BPF_CORE_READ(tp, snd_cwnd); \ + conn->rcv_wnd = BPF_CORE_READ(tp, rcv_wnd); \ + conn->snd_ssthresh = BPF_CORE_READ(tp, snd_ssthresh); \ + conn->total_retrans = BPF_CORE_READ(tp, total_retrans); \ + conn->sndbuf = BPF_CORE_READ(sk, sk_sndbuf); \ + conn->sk_wmem_queued = BPF_CORE_READ(sk, sk_wmem_queued); \ + conn->tcp_backlog = BPF_CORE_READ(sk, sk_ack_backlog); \ + conn->max_tcp_backlog = BPF_CORE_READ(sk, sk_max_ack_backlog); \ + } + +#define CONN_INFO_TRANSFER tinfo->sk = conn->sock; // 将conn->sock赋给tinfo->sk + +#define PACKET_INIT_WITH_COMMON_INFO \ + struct pack_t *packet; \ + packet = bpf_ringbuf_reserve(&rb, sizeof(*packet), 0); \ + if (!packet) { \ + return 0; \ + } \ + packet->err = 0; \ + packet->sock = sk; \ + packet->ack = pkt_tuple.ack; \ + packet->seq = pkt_tuple.seq; + +#define READ_ONCE(x) (*(volatile typeof(x) *)&(x)) +#define WRITE_ONCE(x, val) ((*(volatile typeof(x) *)&(x)) = val) + +#define INIT_PACKET_TCP_TUPLE(sk, pkt) \ + struct packet_tuple pkt = { \ + .saddr = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr), \ + .daddr = BPF_CORE_READ(sk, __sk_common.skc_daddr), \ + .sport = BPF_CORE_READ(sk, __sk_common.skc_num), \ + .dport = __bpf_ntohs(BPF_CORE_READ(sk, __sk_common.skc_dport)), \ + .tran_flag = TCP} + +#define INIT_PACKET_UDP_TUPLE(sk, pkt) \ + struct packet_tuple pkt = { \ + .saddr = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr), \ + .daddr = BPF_CORE_READ(sk, __sk_common.skc_daddr), \ + .sport = BPF_CORE_READ(sk, __sk_common.skc_num), \ + .dport = __bpf_ntohs(BPF_CORE_READ(sk, __sk_common.skc_dport)), \ + .tran_flag = UDP} +/* help macro end */ + +/* help functions */ +// 将struct sock类型的指针转化为struct tcp_sock类型的指针 +static __always_inline struct tcp_sock *tcp_sk(const struct sock *sk) { + return (struct tcp_sock *)sk; +} +// 将struct sk_buff类型的指针转化为struct udphdr类型的指针 +static __always_inline struct udphdr *skb_to_udphdr(const struct sk_buff *skb) { + return (struct udphdr *)(( + BPF_CORE_READ(skb, head) + // 报文头部偏移 + BPF_CORE_READ(skb, transport_header))); // 传输层部分偏移 +} +// 将struct sk_buff类型的指针转化为struct tcphdr类型的指针 +static __always_inline struct tcphdr *skb_to_tcphdr(const struct sk_buff *skb) { + return (struct tcphdr *)(( + BPF_CORE_READ(skb, head) + // 报文头部偏移 + BPF_CORE_READ(skb, transport_header))); // 传输层部分偏移 +} +// 将struct sk_buff类型的指针转化为struct iphdr类型的指针 +static __always_inline struct iphdr *skb_to_iphdr(const struct sk_buff *skb) { + return (struct iphdr *)(BPF_CORE_READ(skb, head) + + BPF_CORE_READ(skb, network_header)); +} +// 将struct sk_buff类型的指针转化为struct ipv6hdr类型的指针 +static __always_inline struct ipv6hdr * +skb_to_ipv6hdr(const struct sk_buff *skb) { + return (struct ipv6hdr *)(BPF_CORE_READ(skb, head) + + BPF_CORE_READ(skb, network_header)); +} +// 初始化ip_packet +static void get_ip_pkt_tuple(struct ip_packet *ipk, struct iphdr *ip) { + ipk->saddr = BPF_CORE_READ(ip, saddr); + ipk->daddr = BPF_CORE_READ(ip, daddr); +} + +// 初始化packet_tuple结构指针pkt_tuple +static __always_inline void get_pkt_tuple(struct packet_tuple *pkt_tuple, + struct iphdr *ip, + struct tcphdr *tcp) { + pkt_tuple->saddr = BPF_CORE_READ(ip, saddr); + pkt_tuple->daddr = BPF_CORE_READ(ip, daddr); + u16 sport = BPF_CORE_READ(tcp, source); + u16 dport = BPF_CORE_READ(tcp, dest); + pkt_tuple->sport = __bpf_ntohs(sport); + //__bpf_ntohs根据字节序来转化为真实值(16位) 网络传输中为大端序(即为真实值) + pkt_tuple->dport = __bpf_ntohs(dport); + u32 seq = BPF_CORE_READ(tcp, seq); + u32 ack = BPF_CORE_READ(tcp, ack_seq); + pkt_tuple->seq = __bpf_ntohl(seq); + //__bpf_ntohls根据字节序来转化为真实值(32位) + pkt_tuple->ack = __bpf_ntohl(ack); + + pkt_tuple->tran_flag = TCP; // tcp包 + + pkt_tuple->saddr_v6 = 0; + pkt_tuple->daddr_v6 = 0; + pkt_tuple->len = 0; +} +// 初始化packet_tuple结构指针pkt_tuple +static __always_inline void get_udp_pkt_tuple(struct packet_tuple *pkt_tuple, + struct iphdr *ip, + struct udphdr *udp) { + pkt_tuple->saddr = BPF_CORE_READ(ip, saddr); + pkt_tuple->daddr = BPF_CORE_READ(ip, daddr); + u16 sport = BPF_CORE_READ(udp, source); + u16 dport = BPF_CORE_READ(udp, dest); + pkt_tuple->sport = __bpf_ntohs(sport); + //__bpf_ntohs根据字节序来转化为真实值(16位) 网络传输中为大端序(即为真实值) + pkt_tuple->dport = __bpf_ntohs(dport); + pkt_tuple->seq = 0; + pkt_tuple->ack = 0; + pkt_tuple->tran_flag = UDP; // udp包 +} + +static __always_inline void get_pkt_tuple_v6(struct packet_tuple *pkt_tuple, + struct ipv6hdr *ip6h, + struct tcphdr *tcp) { + bpf_probe_read_kernel(&pkt_tuple->saddr_v6, sizeof(pkt_tuple->saddr_v6), + &ip6h->saddr.in6_u.u6_addr32); + bpf_probe_read_kernel(&pkt_tuple->daddr_v6, sizeof(pkt_tuple->daddr_v6), + &ip6h->daddr.in6_u.u6_addr32); + u16 sport = BPF_CORE_READ(tcp, source); + u16 dport = BPF_CORE_READ(tcp, dest); + pkt_tuple->sport = __bpf_ntohs(sport); + pkt_tuple->dport = __bpf_ntohs(dport); + u32 seq = BPF_CORE_READ(tcp, seq); + u32 ack = BPF_CORE_READ(tcp, ack_seq); + pkt_tuple->seq = __bpf_ntohl(seq); + pkt_tuple->ack = __bpf_ntohl(ack); + + pkt_tuple->tran_flag = 1; // tcp包 +} +int getstack(void *ctx) { + int pid = bpf_get_current_pid_tgid() >> 32; + int cpu_id = bpf_get_smp_processor_id(); + struct stacktrace_event *event; + int cp; + + event = bpf_ringbuf_reserve(&trace_rb, sizeof(*event), 0); + if (!event) + return 1; + + event->pid = pid; + event->cpu_id = cpu_id; + + if (bpf_get_current_comm(event->comm, sizeof(event->comm))) + event->comm[0] = 0; + + event->kstack_sz = + bpf_get_stack(ctx, event->kstack, sizeof(event->kstack), 0); + bpf_ringbuf_submit(event, 0); + + return 0; +} +#if KERNEL_VERSION(VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH) >= \ + KERNEL_VERSION(6, 3, 1) +#define GET_USER_DATA(msg) BPF_CORE_READ(msg, msg_iter.__iov, iov_base) +#else +#define GET_USER_DATA(msg) BPF_CORE_READ(msg, msg_iter.iov, iov_base) +#endif + +/* +例子: log2(16384) =14 +16384 2进制表示 1000000000000000 +初始值: v=16384 r=0 +1、16384 > 65535 不成立,r=0; v右移动0位 +2、16384 > 255 成立,shift = 8,v右移动8位100000000,r=0|8=8 +3、256 > 15 成立,shift = 4,v右移4位10000,r=8|4=12 +4、16 > 3 成立,shift = 2,右移2位100,r=12|2=14 +5、v=4,右移1位10,r|=2>>1=1 r=14|1=14 +*/ + +static __always_inline u64 log2(u32 v) { + u32 shift, r; + //检测v是否大于0xFFFF(65535),如果是,则将r设置为16 + r = (v > 0xFFFF) << 4; + v >>= r; //右移 + shift = (v > 0xFF) << 3; + v >>= shift; + r |= shift; + shift = (v > 0xF) << 2; + v >>= shift; + r |= shift; + shift = (v > 0x3) << 1; + v >>= shift; + r |= shift; + //右移v一位并将结果累加到r中 + r |= (v >> 1); + return r; +} +/* +例子:log2l(4294967296)=32 +4294967296 2进制表示 100000000000000000000000000000000 +1、v右移32位 1 +2、log2(1)=0 计算得0+32=32 +*/ +static __always_inline u64 log2l(u64 v) { + u32 hi = v >> 32; //取v的高32位 + // 如果高32位非0,计算高32位的对数并加32 + if (hi) + return log2(hi) + 32; + else + return log2(v); +} + +/* help functions end */ + +#endif diff --git a/MagicEyes/src/backend/net/net_watcher/bpf/drop.bpf.h b/MagicEyes/src/backend/net/net_watcher/bpf/drop.bpf.h new file mode 100644 index 000000000..56848f52f --- /dev/null +++ b/MagicEyes/src/backend/net/net_watcher/bpf/drop.bpf.h @@ -0,0 +1,48 @@ +// Copyright 2023 The LMP Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://github.com/linuxkerneltravel/lmp/blob/develop/LICENSE +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: blown.away@qq.com +// net_watcher libbpf 丢包 + +#include "common.bpf.h" +static __always_inline +int __tp_kfree(struct trace_event_raw_kfree_skb *ctx) +{ + if(!drop_reason) + return 0; + struct sk_buff *skb=ctx->skbaddr; + if (skb == NULL) // 判断是否为空 + return 0; + struct iphdr *ip = skb_to_iphdr(skb); + struct tcphdr *tcp = skb_to_tcphdr(skb); + struct packet_tuple pkt_tuple = {0}; + get_pkt_tuple(&pkt_tuple, ip, tcp); + + struct reasonissue *message; + message = bpf_ringbuf_reserve(&kfree_rb, sizeof(*message), 0); + if(!message){ + return 0; + } + message->saddr = pkt_tuple.saddr; + message->daddr = pkt_tuple.daddr; + message->sport = pkt_tuple.sport; + message->dport = pkt_tuple.dport; + message->protocol = ctx->protocol; + message->location = (long)ctx->location; + message->drop_reason = ctx->reason; + bpf_ringbuf_submit(message,0); + if(stack_info) + getstack(ctx); + return 0; +} \ No newline at end of file diff --git a/MagicEyes/src/backend/net/net_watcher/bpf/icmp.bpf.h b/MagicEyes/src/backend/net/net_watcher/bpf/icmp.bpf.h new file mode 100644 index 000000000..46286e5c4 --- /dev/null +++ b/MagicEyes/src/backend/net/net_watcher/bpf/icmp.bpf.h @@ -0,0 +1,90 @@ +// Copyright 2023 The LMP Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://github.com/linuxkerneltravel/lmp/blob/develop/LICENSE +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: blown.away@qq.com +// net_watcher libbpf icmp + +#include "common.bpf.h" + +static __always_inline +int __icmp_time(struct sk_buff *skb) +{ + if(!icmp_info||skb==NULL) + return 0; + struct iphdr *ip = skb_to_iphdr(skb); + struct ip_packet ipk = {0}; + get_ip_pkt_tuple(&ipk, ip); + unsigned long long time= bpf_ktime_get_ns() / 1000; + bpf_map_update_elem(&icmp_time, &ipk, &time, BPF_ANY); + return 0; +} + +static __always_inline +int __rcvend_icmp_time(struct sk_buff *skb) +{ + if(!icmp_info) + return 0; + if(skb==NULL) + return 0; + struct iphdr *ip = skb_to_iphdr(skb); + struct ip_packet ipk = {0}; + get_ip_pkt_tuple(&ipk, ip); + unsigned long long *pre_time = bpf_map_lookup_elem(&icmp_time, &ipk); + if(pre_time==NULL) + return 0; + + unsigned long long new_time= bpf_ktime_get_ns() / 1000; + unsigned long long time=new_time-*pre_time; + struct icmptime *message; + message = bpf_ringbuf_reserve(&icmp_rb, sizeof(*message), 0); + if(!message){ + return 0; + } + + message->saddr = ipk.saddr; + message->daddr =ipk.daddr; + message->icmp_tran_time =time; + message->flag =0; + bpf_ringbuf_submit(message,0); + return 0; +} + +static __always_inline +int __reply_icmp_time(struct sk_buff *skb) +{ + if(!icmp_info) + return 0; + if(skb==NULL) + return 0; + struct iphdr *ip = skb_to_iphdr(skb); + struct ip_packet ipk = {0}; + get_ip_pkt_tuple(&ipk, ip); + unsigned long long *pre_time = bpf_map_lookup_elem(&icmp_time, &ipk); + if(pre_time==NULL) + return 0; + unsigned long long new_time= bpf_ktime_get_ns() / 1000; + unsigned long long time=new_time-*pre_time; + struct icmptime *message; + message = bpf_ringbuf_reserve(&icmp_rb, sizeof(*message), 0); + if(!message){ + return 0; + } + + message->saddr = ipk.saddr; + message->daddr =ipk.daddr; + message->icmp_tran_time =time; + message->flag =1; + bpf_ringbuf_submit(message,0); + return 0; +} \ No newline at end of file diff --git a/MagicEyes/src/backend/net/net_watcher/bpf/mysql.bpf.h b/MagicEyes/src/backend/net/net_watcher/bpf/mysql.bpf.h new file mode 100644 index 000000000..13e802887 --- /dev/null +++ b/MagicEyes/src/backend/net/net_watcher/bpf/mysql.bpf.h @@ -0,0 +1,78 @@ +// Copyright 2023 The LMP Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://github.com/linuxkerneltravel/lmp/blob/develop/LICENSE +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: blown.away@qq.com +// mysql + +#include "common.bpf.h" +#include "mysql_helper.bpf.h" +static __always_inline int __handle_mysql_start(struct pt_regs *ctx) { + // dispatch_command(THD *thd, const COM_DATA *com_data, enum + enum enum_server_command command = PT_REGS_PARM3(ctx); + union COM_DATA *com_data = (union COM_DATA *)PT_REGS_PARM2(ctx); + pid_t pid = bpf_get_current_pid_tgid() >> 32; + pid_t tid = bpf_get_current_pid_tgid(); + void *thd = (void *)PT_REGS_PARM1(ctx); + struct query_info info; + u32 size = 0; + char *sql; + + if (command != COM_QUERY) { + return 0; + } + + bpf_probe_read(&info.size, sizeof(info.size), &com_data->com_query.length); + bpf_probe_read_str(&sql, sizeof(sql), &com_data->com_query.query); + bpf_probe_read_str(&info.msql, sizeof(info.msql), sql); + // bpf_printk("sql1==%s size1==%lu", info.msql,info.size); + info.start_time = bpf_ktime_get_ns() / 1000; + + bpf_map_update_elem(&queries, &tid, &info, BPF_ANY); + return 0; +} + +static __always_inline int __handle_mysql_end(struct pt_regs *ctx) { + char comm[16]; + pid_t pid = bpf_get_current_pid_tgid() >> 32; + pid_t tid = bpf_get_current_pid_tgid(); + struct query_info *info = bpf_map_lookup_elem(&queries, &tid); + if (!info) { + return 0; + } + + struct mysql_query *message = + bpf_ringbuf_reserve(&mysql_rb, sizeof(*message), 0); + if (!message) { + return 0; + } + u64 *count_ptr, count = 1; + count_ptr = bpf_map_lookup_elem(&sql_count, &tid); + if (count_ptr) { + count = *count_ptr + 1; + } + + message->count = count; + bpf_map_update_elem(&sql_count, &tid, &count, BPF_ANY); + message->duratime = bpf_ktime_get_ns() / 1000 - info->start_time; + message->pid = pid; + message->tid = tid; + bpf_get_current_comm(&message->comm, sizeof(comm)); + message->size = info->size; + bpf_probe_read_str(&message->msql, sizeof(message->msql), info->msql); + // bpf_printk("C==%d D==%lu S==%lu SQL==%s",count, + // message->duratime,message->size,message->msql); + + bpf_ringbuf_submit(message, 0); + return 0; +} diff --git a/MagicEyes/src/backend/net/net_watcher/bpf/mysql_helper.bpf.h b/MagicEyes/src/backend/net/net_watcher/bpf/mysql_helper.bpf.h new file mode 100644 index 000000000..67847d9a3 --- /dev/null +++ b/MagicEyes/src/backend/net/net_watcher/bpf/mysql_helper.bpf.h @@ -0,0 +1,171 @@ +// Copyright 2023 The LMP Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://github.com/linuxkerneltravel/lmp/blob/develop/LICENSE +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: blown.away@qq.com +// +// net_watcher libbpf 内核<->用户 传递信息相关结构体 + +#ifndef __MYSQL_HELPER_BPF_H +#define __MYSQL_HELPER_BPF_H + +#include "net_watcher.h" +#include "vmlinux.h" +#include +#include +#include +#include +#include +#include + +enum enum_server_command { + COM_SLEEP, + COM_QUIT, + COM_INIT_DB, + COM_QUERY, + COM_FIELD_LIST, + COM_CREATE_DB, + COM_DROP_DB, + COM_REFRESH, + COM_SHUTDOWN, + COM_STATISTICS, + COM_PROCESS_INFO, + COM_CONNECT, + COM_PROCESS_KILL, + COM_DEBUG, + COM_PING, + COM_TIME, + COM_DELAYED_INSERT, + COM_CHANGE_USER, + COM_BINLOG_DUMP, + COM_TABLE_DUMP, + COM_CONNECT_OUT, + COM_REGISTER_SLAVE, + COM_STMT_PREPARE, + COM_STMT_EXECUTE, + COM_STMT_SEND_LONG_DATA, + COM_STMT_CLOSE, + COM_STMT_RESET, + COM_SET_OPTION, + COM_STMT_FETCH, + COM_DAEMON, + COM_BINLOG_DUMP_GTID, + COM_RESET_CONNECTION, + /* don't forget to update const char *command_name[] in sql_parse.cc */ + /* Must be last */ + COM_END +}; + +typedef struct st_com_init_db_data { + const char *db_name; + unsigned long length; +} COM_INIT_DB_DATA; + +#define MYSQL_SHUTDOWN_KILLABLE_CONNECT (unsigned char)(1 << 0) +#define MYSQL_SHUTDOWN_KILLABLE_TRANS (unsigned char)(1 << 1) +#define MYSQL_SHUTDOWN_KILLABLE_LOCK_TABLE (unsigned char)(1 << 2) +#define MYSQL_SHUTDOWN_KILLABLE_UPDATE (unsigned char)(1 << 3) + +#define LOCK_MODE_MASK 0xFUL +#define LOCK_TYPE_MASK 0xF0UL + +enum mysql_enum_shutdown_level { + SHUTDOWN_DEFAULT = 0, + SHUTDOWN_WAIT_CONNECTIONS = MYSQL_SHUTDOWN_KILLABLE_CONNECT, + SHUTDOWN_WAIT_TRANSACTIONS = MYSQL_SHUTDOWN_KILLABLE_TRANS, + SHUTDOWN_WAIT_UPDATES = MYSQL_SHUTDOWN_KILLABLE_UPDATE, + SHUTDOWN_WAIT_ALL_BUFFERS = (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1), + SHUTDOWN_WAIT_CRITICAL_BUFFERS = (MYSQL_SHUTDOWN_KILLABLE_UPDATE << 1) + 1, + KILL_QUERY = 254, + KILL_CONNECTION = 255 +}; + +typedef struct st_com_refresh_data { + unsigned char options; +} COM_REFRESH_DATA; + +typedef struct st_com_shutdown_data { + enum mysql_enum_shutdown_level level; +} COM_SHUTDOWN_DATA; + +typedef struct st_com_kill_data { + unsigned long id; +} COM_KILL_DATA; + +typedef struct st_com_set_option_data { + unsigned int opt_command; +} COM_SET_OPTION_DATA; + +typedef struct st_com_stmt_execute_data { + unsigned long stmt_id; + unsigned long flags; + unsigned char *params; + unsigned long params_length; +} COM_STMT_EXECUTE_DATA; + +typedef struct st_com_stmt_fetch_data { + unsigned long stmt_id; + unsigned long num_rows; +} COM_STMT_FETCH_DATA; + +typedef struct st_com_stmt_send_long_data_data { + unsigned long stmt_id; + unsigned int param_number; + unsigned char *longdata; + unsigned long length; +} COM_STMT_SEND_LONG_DATA_DATA; + +typedef struct st_com_stmt_prepare_data { + const char *query; + unsigned int length; +} COM_STMT_PREPARE_DATA; + +typedef struct st_stmt_close_data { + unsigned int stmt_id; +} COM_STMT_CLOSE_DATA; + +typedef struct st_com_stmt_reset_data { + unsigned int stmt_id; +} COM_STMT_RESET_DATA; + +typedef struct st_com_query_data { + const char *query; + unsigned int length; +} COM_QUERY_DATA; + +typedef struct st_com_field_list_data { + unsigned char *table_name; + unsigned int table_name_length; + const unsigned char *query; + unsigned int query_length; +} COM_FIELD_LIST_DATA; + +union COM_DATA { + COM_INIT_DB_DATA com_init_db; + COM_REFRESH_DATA com_refresh; + COM_SHUTDOWN_DATA com_shutdown; + COM_KILL_DATA com_kill; + COM_SET_OPTION_DATA com_set_option; + COM_STMT_EXECUTE_DATA com_stmt_execute; + COM_STMT_FETCH_DATA com_stmt_fetch; + COM_STMT_SEND_LONG_DATA_DATA com_stmt_send_long_data; + COM_STMT_PREPARE_DATA com_stmt_prepare; + COM_STMT_CLOSE_DATA com_stmt_close; + COM_STMT_RESET_DATA com_stmt_reset; + COM_QUERY_DATA com_query; + COM_FIELD_LIST_DATA com_field_list; +}; + +/* help functions end */ + +#endif diff --git a/MagicEyes/src/backend/net/net_watcher/bpf/net_watcher.bpf.c b/MagicEyes/src/backend/net/net_watcher/bpf/net_watcher.bpf.c index 7aef79b8c..5db4a8064 100644 --- a/MagicEyes/src/backend/net/net_watcher/bpf/net_watcher.bpf.c +++ b/MagicEyes/src/backend/net/net_watcher/bpf/net_watcher.bpf.c @@ -16,509 +16,57 @@ // // tcpwatch libbpf 内核函数 -#include "net_watcher.h" -#include "vmlinux.h" -#include -#include -#include -#include -#include -#include +#include "common.bpf.h" -struct ktime_info { // us time stamp info发送数据包 - unsigned long long qdisc_time; // tx包离开mac层时间戳 - unsigned long long mac_time; // tx、rx包到达mac层时间戳 - unsigned long long ip_time; // tx、rx包到达ip层时间戳 - // unsigned long long tcp_time; // tx、rx包到达tcp层时间戳 - unsigned long long tran_time; // tx、rx包到达传输层时间戳 - unsigned long long app_time; // rx包离开tcp层时间戳 - void *sk; // 此包所属 socket套接字 - unsigned char data[MAX_HTTP_HEADER]; // 用户层数据 -}; - -struct packet_tuple { - unsigned __int128 saddr_v6; // ipv6 源地址 - unsigned __int128 daddr_v6; // ipv6 目的地址 - unsigned int saddr; // 源地址 - unsigned int daddr; // 目的地址 - unsigned short sport; // 源端口号 - unsigned short dport; // 目的端口号 - unsigned int seq; // seq报文序号 - unsigned int ack; // ack确认号 - unsigned int tran_flag; // 1:tcp 2:udp - unsigned int len; -}; -struct filtertime { - unsigned long long ip_rcv_time; - unsigned long long ip_local_deliver_time; - unsigned long long ip_local_deliver_finish_time; - unsigned long long ip__forward_time; - unsigned long long ip_local_out_time; - unsigned long long ip_output_time; - unsigned long long ip_finish_output_time; - unsigned long long ipv6_rcv_time; - -}; -// 操作BPF映射的一个辅助函数 -static __always_inline void * //__always_inline强制内联 -bpf_map_lookup_or_try_init(void *map, const void *key, const void *init) { - void *val; - long err; - - val = bpf_map_lookup_elem(map, key); // 在BPF映射中查找具有给定键的条目 - if (val) - return val; - // 此时没有对应key的value - err = bpf_map_update_elem(map, key, init, - BPF_NOEXIST); // 向BPF映射中插入或更新一个条目 - if (err && err != -EEXIST) // 插入失败 - return 0; - - return bpf_map_lookup_elem(map, key); // 返回对应value值 -} - -char LICENSE[] SEC("license") = "Dual BSD/GPL"; +#include "netfilter.bpf.h" -#define MAX_CONN 1000 +#include "icmp.bpf.h" -// 存储每个packet_tuple包所对应的ktime_info时间戳 -struct { - __uint(type, BPF_MAP_TYPE_LRU_HASH); - __uint(max_entries, MAX_CONN *MAX_PACKET); - __type(key, struct packet_tuple); - __type(value, struct ktime_info); -} timestamps SEC(".maps"); +#include "tcp.bpf.h" -// 包相关信息通过此buffer提供给userspace -struct { - __uint(type, BPF_MAP_TYPE_RINGBUF); - __uint(max_entries, 256 * 1024); -} rb SEC(".maps"); +#include "packet.bpf.h" -struct { - __uint(type, BPF_MAP_TYPE_RINGBUF); - __uint(max_entries, 256 * 1024); -} udp_rb SEC(".maps"); +#include "udp.bpf.h" -struct { - __uint(type, BPF_MAP_TYPE_RINGBUF); - __uint(max_entries, 256 * 1024); -} netfilter_rb SEC(".maps"); -// 存储每个tcp连接所对应的conn_t -struct { - __uint(type, BPF_MAP_TYPE_LRU_HASH); - __uint(max_entries, MAX_CONN); - __type(key, struct sock *); - __type(value, struct conn_t); -} conns_info SEC(".maps"); +#include "mysql.bpf.h" -// 根据ptid存储sock指针,从而在上下文无sock的内核探测点获得sock -struct { - __uint(type, BPF_MAP_TYPE_LRU_HASH); - __uint(max_entries, MAX_CONN); - __type(key, u64); - __type(value, struct sock *); -} sock_stores SEC(".maps"); - -// 存储每个pid所对应的udp包 -struct { - __uint(type, BPF_MAP_TYPE_LRU_HASH); - __uint(max_entries, MAX_CONN *MAX_PACKET); - __type(key, int); - __type(value, struct packet_tuple); -} pid_UDP SEC(".maps"); - -struct { - __uint(type, BPF_MAP_TYPE_LRU_HASH); - __uint(max_entries, MAX_CONN *MAX_PACKET); - __type(key, int); - __type(value, struct packet_tuple); -} pid_filter SEC(".maps"); - -struct { - __uint(type, BPF_MAP_TYPE_LRU_HASH); - __uint(max_entries, MAX_CONN *MAX_PACKET); - __type(key, u32); - __type(value, struct filtertime); -} netfilter_time SEC(".maps"); - -const volatile int filter_dport = 0; -const volatile int filter_sport = 0; -const volatile int all_conn = 0, err_packet = 0, extra_conn_info = 0, - layer_time = 0, http_info = 0, retrans_info = 0, udp_info =0,net_filter = 0; - -/* help macro */ - -// 连接的目标端口是否匹配于filter_dport的值 -#define FILTER_DPORT \ - if (filter_dport) { \ - if (conn.dport != filter_dport) { \ - return 0; \ - } \ - } -// 连接的源端口是否匹配于filter_sport的值 -#define FILTER_SPORT \ - if (filter_sport) { \ - if (conn.sport != filter_sport) { \ - return 0; \ - } \ - } - -// 初始化conn_t结构 -/* -#define CONN_INIT - struct conn_t conn = {0}; //声明一各conn_t结构,并初始化为0 conn.pid = ptid ->> 32; //将ptid的高32位赋给pid conn.ptid = ptid; -//初始化ptid u16 protocol = BPF_CORE_READ(sk, sk_protocol); //读取协议字段 if -(protocol != IPPROTO_TCP) //检查其协议字段是否为IPPROTO_TCP - return 0; - bpf_get_current_comm(&conn.comm, sizeof(conn.comm)); //获取当前进程名字 - conn.sock = sk; //套接字指针sk - u16 family = BPF_CORE_READ(sk, __sk_common.skc_family); //地址族字段 - __be16 dport = BPF_CORE_READ(sk, __sk_common.skc_dport); //目标端口字段 - u16 sport = BPF_CORE_READ(sk, __sk_common.skc_num); //源端口字段 - conn.family = family; - conn.sport = sport; - conn.dport = __bpf_ntohs(dport); //字节序转换 - conn.init_timestamp = bpf_ktime_get_ns() / 1000; //将当前时间戳(s) -*/ -#define CONN_INIT \ - struct conn_t conn = {0}; \ - conn.pid = ptid >> 32; \ - conn.ptid = ptid; \ - u16 protocol = BPF_CORE_READ(sk, sk_protocol); \ - if (protocol != IPPROTO_TCP) \ - return 0; \ - bpf_get_current_comm(&conn.comm, sizeof(conn.comm)); \ - conn.sock = sk; \ - u16 family = BPF_CORE_READ(sk, __sk_common.skc_family); \ - __be16 dport = BPF_CORE_READ(sk, __sk_common.skc_dport); \ - u16 sport = BPF_CORE_READ(sk, __sk_common.skc_num); \ - conn.family = family; \ - conn.sport = sport; \ - conn.dport = __bpf_ntohs(dport); \ - conn.init_timestamp = bpf_ktime_get_ns() / 1000; -/* -初始化conn_t地址相关信息 -#define CONN_ADD_ADDRESS - if (family == AF_INET) { //Internet IP -Protocol conn.saddr = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr);//获取源地址 - conn.daddr = BPF_CORE_READ(sk, __sk_common.skc_daddr); //获取目的地址 - } else if (family == AF_INET6) { //IP version 6 - bpf_probe_read_kernel( //从sk中读取IPv6连接的源地址 &conn.saddr_v6, -//存放位置 sizeof(sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32), //读取大小 - &sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32); //读取位置 - bpf_probe_read_kernel( //从sk中读取IPv6连接的目的地址 &conn.daddr_v6, - sizeof(sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32), - &sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32); - } -*/ -#define CONN_ADD_ADDRESS \ - if (family == AF_INET) { \ - conn.saddr = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr); \ - conn.daddr = BPF_CORE_READ(sk, __sk_common.skc_daddr); \ - } else if (family == AF_INET6) { \ - bpf_probe_read_kernel( \ - &conn.saddr_v6, \ - sizeof(sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32), \ - &sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32); \ - bpf_probe_read_kernel( \ - &conn.daddr_v6, \ - sizeof(sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32), \ - &sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32); \ - } -/* -初始化conn其余额外信息 -#define CONN_ADD_EXTRA_INFO //添加额外信息 - if (extra_conn_info) { - struct tcp_sock *tp = (struct tcp_sock *)sk; //新建tcp_sock结构体 - conn->srtt = BPF_CORE_READ(tp, srtt_us); //平滑往返时间 - conn->duration = bpf_ktime_get_ns() / 1000 - conn->init_timestamp; // -已连接建立时长 conn->bytes_acked = BPF_CORE_READ(tp, bytes_acked); -//已确认的字节数 conn->bytes_received = BPF_CORE_READ(tp, -bytes_received);//已接收的字节数 conn->snd_cwnd = BPF_CORE_READ(tp, snd_cwnd); -//拥塞窗口大小 conn->rcv_wnd = BPF_CORE_READ(tp, rcv_wnd); //接收窗口大小 - conn->snd_ssthresh = BPF_CORE_READ(tp, snd_ssthresh); //慢启动阈值 - conn->total_retrans = BPF_CORE_READ(tp, total_retrans); //重传包数 - conn->sndbuf = BPF_CORE_READ(sk, sk_sndbuf); //发送缓冲区大小(byte) - conn->sk_wmem_queued = BPF_CORE_READ(sk, -sk_wmem_queued);//已使用的发送缓冲区 conn->tcp_backlog = BPF_CORE_READ(sk, -sk_ack_backlog); //backlog传入连接请求的当前最大排队队列大小 - conn->max_tcp_backlog = BPF_CORE_READ(sk, sk_max_ack_backlog); -//max_backlog传入连接请求的最大挂起队列大小 - } - -*/ -#define CONN_ADD_EXTRA_INFO \ - if (extra_conn_info) { \ - struct tcp_sock *tp = (struct tcp_sock *)sk; \ - conn->srtt = BPF_CORE_READ(tp, srtt_us); \ - conn->duration = bpf_ktime_get_ns() / 1000 - conn->init_timestamp; \ - conn->bytes_acked = BPF_CORE_READ(tp, bytes_acked); \ - conn->bytes_received = BPF_CORE_READ(tp, bytes_received); \ - conn->snd_cwnd = BPF_CORE_READ(tp, snd_cwnd); \ - conn->rcv_wnd = BPF_CORE_READ(tp, rcv_wnd); \ - conn->snd_ssthresh = BPF_CORE_READ(tp, snd_ssthresh); \ - conn->total_retrans = BPF_CORE_READ(tp, total_retrans); \ - conn->sndbuf = BPF_CORE_READ(sk, sk_sndbuf); \ - conn->sk_wmem_queued = BPF_CORE_READ(sk, sk_wmem_queued); \ - conn->tcp_backlog = BPF_CORE_READ(sk, sk_ack_backlog); \ - conn->max_tcp_backlog = BPF_CORE_READ(sk, sk_max_ack_backlog); \ - } - -#define CONN_INFO_TRANSFER tinfo->sk = conn->sock; // 将conn->sock赋给tinfo->sk - -/* -初始化pack_t结构 -#define PACKET_INIT_WITH_COMMON_INFO - struct pack_t *packet; //创建pack_t指针 - packet = bpf_ringbuf_reserve(&rb, sizeof(*packet), 0); -//为pack_t结构体分配内存空间 if (!packet) { //分配失败 return 0; - } - packet->err = 0; //err - packet->sock = sk; //socket 指针 - packet->ack = pkt_tuple.ack; //确认号 - packet->seq = pkt_tuple.seq; //序号 -*/ -#define PACKET_INIT_WITH_COMMON_INFO \ - struct pack_t *packet; \ - packet = bpf_ringbuf_reserve(&rb, sizeof(*packet), 0); \ - if (!packet) { \ - return 0; \ - } \ - packet->err = 0; \ - packet->sock = sk; \ - packet->ack = pkt_tuple.ack; \ - packet->seq = pkt_tuple.seq; - -/* help macro end */ - -/* help functions */ -// 将struct sock类型的指针转化为struct tcp_sock类型的指针 -static struct tcp_sock *tcp_sk(const struct sock *sk) { - return (struct tcp_sock *)sk; -} -// 将struct sk_buff类型的指针转化为struct udphdr类型的指针 -static struct udphdr *skb_to_udphdr(const struct sk_buff *skb) { - return (struct udphdr *)(( - BPF_CORE_READ(skb, head) + // 报文头部偏移 - BPF_CORE_READ(skb, transport_header))); // 传输层部分偏移 -} -// 将struct sk_buff类型的指针转化为struct tcphdr类型的指针 -static struct tcphdr *skb_to_tcphdr(const struct sk_buff *skb) { - return (struct tcphdr *)(( - BPF_CORE_READ(skb, head) + // 报文头部偏移 - BPF_CORE_READ(skb, transport_header))); // 传输层部分偏移 -} -// 将struct sk_buff类型的指针转化为struct iphdr类型的指针 -static inline struct iphdr *skb_to_iphdr(const struct sk_buff *skb) { - return (struct iphdr *)(BPF_CORE_READ(skb, head) + - BPF_CORE_READ(skb, network_header)); -} -// 将struct sk_buff类型的指针转化为struct ipv6hdr类型的指针 -static inline struct ipv6hdr *skb_to_ipv6hdr(const struct sk_buff *skb) { - return (struct ipv6hdr *)(BPF_CORE_READ(skb, head) + - BPF_CORE_READ(skb, network_header)); -} +#include "redis.bpf.h" -// 初始化packet_tuple结构指针pkt_tuple -static void get_pkt_tuple(struct packet_tuple *pkt_tuple, struct iphdr *ip, - struct tcphdr *tcp) { - pkt_tuple->saddr = BPF_CORE_READ(ip, saddr); - pkt_tuple->daddr = BPF_CORE_READ(ip, daddr); - u16 sport = BPF_CORE_READ(tcp, source); - u16 dport = BPF_CORE_READ(tcp, dest); - pkt_tuple->sport = __bpf_ntohs(sport); - //__bpf_ntohs根据字节序来转化为真实值(16位) 网络传输中为大端序(即为真实值) - pkt_tuple->dport = __bpf_ntohs(dport); - u32 seq = BPF_CORE_READ(tcp, seq); - u32 ack = BPF_CORE_READ(tcp, ack_seq); - pkt_tuple->seq = __bpf_ntohl(seq); - //__bpf_ntohls根据字节序来转化为真实值(32位) - pkt_tuple->ack = __bpf_ntohl(ack); +#include "drop.bpf.h" - pkt_tuple->tran_flag = TCP; // tcp包 -} -// 初始化packet_tuple结构指针pkt_tuple -static void get_udp_pkt_tuple(struct packet_tuple *pkt_tuple, struct iphdr *ip, - struct udphdr *udp) { - pkt_tuple->saddr = BPF_CORE_READ(ip, saddr); - pkt_tuple->daddr = BPF_CORE_READ(ip, daddr); - u16 sport = BPF_CORE_READ(udp, source); - u16 dport = BPF_CORE_READ(udp, dest); - pkt_tuple->sport = __bpf_ntohs(sport); - //__bpf_ntohs根据字节序来转化为真实值(16位) 网络传输中为大端序(即为真实值) - pkt_tuple->dport = __bpf_ntohs(dport); - pkt_tuple->seq = 0; - pkt_tuple->ack = 0; - pkt_tuple->tran_flag = UDP; // udp包 -} - -static void get_pkt_tuple_v6(struct packet_tuple *pkt_tuple, - struct ipv6hdr *ip6h, struct tcphdr *tcp) { - bpf_probe_read_kernel(&pkt_tuple->saddr_v6, sizeof(pkt_tuple->saddr_v6), - &ip6h->saddr.in6_u.u6_addr32); - bpf_probe_read_kernel(&pkt_tuple->daddr_v6, sizeof(pkt_tuple->daddr_v6), - &ip6h->daddr.in6_u.u6_addr32); - u16 sport = BPF_CORE_READ(tcp, source); - u16 dport = BPF_CORE_READ(tcp, dest); - pkt_tuple->sport = __bpf_ntohs(sport); - pkt_tuple->dport = __bpf_ntohs(dport); - u32 seq = BPF_CORE_READ(tcp, seq); - u32 ack = BPF_CORE_READ(tcp, ack_seq); - pkt_tuple->seq = __bpf_ntohl(seq); - pkt_tuple->ack = __bpf_ntohl(ack); - - pkt_tuple->tran_flag = 1; // tcp包 -} -/* help functions end */ - -/** - accecpt an TCP connection -*/ +// accecpt an TCP connection SEC("kretprobe/inet_csk_accept") int BPF_KRETPROBE(inet_csk_accept_exit, // 接受tcp连接 struct sock *sk) { // this func return a newsk - // bpf_printk("inet_accept_ret\n"); - if (sk == NULL) { // newsk is null - // bpf_printk("inet_accept_ret err: newsk is null\n"); - return 0; - } - u64 ptid = bpf_get_current_pid_tgid(); // 获取当前进程pid - - CONN_INIT // 初始化conn_t结构中基本信息 - conn.is_server = 1; - - FILTER_DPORT // 过滤目标端口 - - FILTER_SPORT // 过滤源端口 - - CONN_ADD_ADDRESS // conn_t结构中增加地址信息 - - // 更新/插入conns_info中的键值对 - int err = bpf_map_update_elem(&conns_info, &sk, &conn, BPF_ANY); - if (err) { // 更新错误 - // bpf_printk("inet_accept update err.\n"); - return 0; - } - - return 0; + return __inet_csk_accept(sk); } -/** - accecpt an TCP connection end -*/ -/** - connect an TCP connection -*/ +// connect an TCP connection SEC("kprobe/tcp_v4_connect") // 进入tcp_v4_connect int BPF_KPROBE(tcp_v4_connect, const struct sock *sk) { - // bpf_printk("tcp_v4_connect\n"); - u64 ptid = bpf_get_current_pid_tgid(); // 获取当前pid - int err = bpf_map_update_elem(&sock_stores, &ptid, &sk, BPF_ANY); - // 更新/插入sock_stores中的键值对 - if (err) { - // bpf_printk("tcp_v4_connect update sock_stores err.\n"); - return 0; - } - return 0; + return __tcp_v4_connect(sk); } SEC("kretprobe/tcp_v4_connect") // 退出tcp_v4_connect int BPF_KRETPROBE(tcp_v4_connect_exit, int ret) { - u64 ptid = bpf_get_current_pid_tgid(); // 获取当前pid - struct sock **skp = bpf_map_lookup_elem(&sock_stores, &ptid); - // 获得sock_stores中ptid对应的*sk 用skp指向 - if (skp == NULL) { - return 0; - } - // bpf_printk("tcp_v4_connect_exit\n"); - if (ret != 0) { // 连接失败 - // bpf_printk("tcp_v4_connect_exit but ret %d\n", ret); - bpf_map_delete_elem(&sock_stores, &ptid); // 删除对应键值对 - return 0; - } - struct sock *sk = *skp; - CONN_INIT // 初始化conn_t结构中基本信息 - conn.is_server = 0; // 主动连接 - - FILTER_DPORT // 过滤目标端口 - - FILTER_SPORT // 过滤源端口 - - CONN_ADD_ADDRESS // conn_t结构中增加地址信息 - - long err = bpf_map_update_elem(&conns_info, &sk, &conn, BPF_ANY); - // 更新conns_info中sk对应的conn - if (err) { - return 0; - } - return 0; + return __tcp_v4_connect_exit(ret); } SEC("kprobe/tcp_v6_connect") // 进入tcp_v6_connect函数 int BPF_KPROBE(tcp_v6_connect, const struct sock *sk) { - u64 pid = bpf_get_current_pid_tgid(); // 获取pid - int err = bpf_map_update_elem(&sock_stores, &pid, &sk, BPF_ANY); - // 更新sock_stores中对应pid对应的sk - if (err) { - return 0; - } - return 0; + return __tcp_v6_connect(sk); } SEC("kretprobe/tcp_v6_connect") // 退出tcp_v6_connect函数 int BPF_KRETPROBE(tcp_v6_connect_exit, int ret) { - u64 ptid = bpf_get_current_pid_tgid(); // 获取pid - struct sock **skp = bpf_map_lookup_elem(&sock_stores, &ptid); - // 获得sock_stores中ptid对应的*sk 用skp指向 - if (skp == NULL) { - return 0; - } - if (ret != 0) { // 错误 - bpf_map_delete_elem(&sock_stores, &ptid); // 删除对应键值对 - return 0; - } - struct sock *sk = *skp; - - CONN_INIT // 初始化conn_t结构中基本信息 - conn.is_server = 0; // 主动连接 - - FILTER_DPORT // 过滤目标端口 - - FILTER_SPORT // 过滤源端口 - - CONN_ADD_ADDRESS // conn_t结构中增加地址信息 - - long err = bpf_map_update_elem(&conns_info, &sk, &conn, BPF_ANY); - // 更新conns_info中sk对应的conn - if (err) { - return 0; - } - // bpf_printk("tcp_v4_connect_exit update sk: %p.\n", sk); - return 0; + return __tcp_v6_connect_exit(ret); } -/** - connect an TCP connection end -*/ - -/* erase CLOSED TCP connection */ +// erase CLOSED TCP connection SEC("kprobe/tcp_set_state") int BPF_KPROBE(tcp_set_state, struct sock *sk, int state) { - if (all_conn) { - return 0; - } - struct conn_t *value = bpf_map_lookup_elem(&conns_info, &sk); - // 查找sk对应的conn_t - if (state == TCP_CLOSE && value != NULL) { // TCP_CLOSE置1 说明关闭连接 - // delete - bpf_map_delete_elem(&sock_stores, &value->ptid); // 删除sock_stores - bpf_map_delete_elem(&conns_info, &sk); // 删除conns_info - } - return 0; + return __tcp_set_state(sk, state); } -/* erase CLOSED TCP connection end*/ /*! in_ipv4: @@ -553,380 +101,61 @@ int BPF_KPROBE(tcp_set_state, struct sock *sk, int state) { /** in ipv4 && ipv6 */ SEC("kprobe/eth_type_trans") // 进入eth_type_trans int BPF_KPROBE(eth_type_trans, struct sk_buff *skb) { - const struct ethhdr *eth = - (struct ethhdr *)BPF_CORE_READ(skb, data); // 读取里面的报文数据 - u16 protocol = BPF_CORE_READ(eth, h_proto); // 读取包ID - // bpf_printk("protocol: %d\n", __bpf_ntohs(protocol)); - if (protocol == __bpf_htons(ETH_P_IP)) { // Protocol is IP 0x0800 - // 14 --> sizeof(struct ethhdr) / define - struct iphdr *ip = - (struct iphdr *)(BPF_CORE_READ(skb, data) + - 14); // 链路层头部长度为14 源端口6字节 - // 目的端口6字节 类型2字节 - struct tcphdr *tcp = (struct tcphdr *)(BPF_CORE_READ(skb, data) + - sizeof(struct iphdr) + 14); - struct packet_tuple pkt_tuple = {0}; // 声明packet_tuple结构pkt_tuple - get_pkt_tuple(&pkt_tuple, ip, tcp); // 初始化pkt_tuple - - struct ktime_info *tinfo, zero = {0}; // 定义ktime_info结构zero以及tinfo - - tinfo = (struct ktime_info *)bpf_map_lookup_or_try_init( - ×tamps, &pkt_tuple, &zero); - if (tinfo == NULL) { // 初始化失败 - // bpf_printk("v4 rx tinfo init fail.\n"); - return 0; - } - // 成功则获取当前内核时间并转换成毫秒 - tinfo->mac_time = bpf_ktime_get_ns() / 1000; - // bpf_printk("v4 rx init.\n"); - } else if (protocol == __bpf_htons(ETH_P_IPV6)) { // Protocol is IPV6 - struct ipv6hdr *ip6h = - (struct ipv6hdr *)(BPF_CORE_READ(skb, data) + 14); - struct tcphdr *tcp = (struct tcphdr *)(BPF_CORE_READ(skb, data) + - sizeof(struct ipv6hdr) + 14); - struct packet_tuple pkt_tuple = {0}; - get_pkt_tuple_v6(&pkt_tuple, ip6h, tcp); - - struct ktime_info *tinfo, zero = {0}; - - tinfo = (struct ktime_info *)bpf_map_lookup_or_try_init( - ×tamps, &pkt_tuple, &zero); - if (tinfo == NULL) { - // bpf_printk("v6 rx tinfo init fail.\n"); - return 0; - } - tinfo->mac_time = bpf_ktime_get_ns() / 1000; - // bpf_printk("v6 rx init.\n"); + if (protocol_count) { + return sum_protocol(skb, false); // receive + } else { + return __eth_type_trans(skb); } - return 0; } /** in only ipv4 */ SEC("kprobe/ip_rcv_core") // 跟踪记录ipv4数据包在内核中的处理时间 -int BPF_KPROBE(ip_rcv_core, struct sk_buff *skb) { - if (!layer_time) { - return 0; - } - if (skb == NULL) - return 0; - struct iphdr *ip = skb_to_iphdr(skb); // 通过skb获取ipv4包头信息 - struct tcphdr *tcp = skb_to_tcphdr(skb); // 获取tcp包头信息 - struct packet_tuple pkt_tuple = { - 0}; // 定义一个packet_tuple结构体变量pkt_tuple并初始化 - get_pkt_tuple(&pkt_tuple, ip, tcp); - struct ktime_info *tinfo; - tinfo = bpf_map_lookup_elem( - ×tamps, &pkt_tuple); // 在timestamps映射中查找元素pkt_tuple - if (tinfo == NULL) { - return 0; - } - tinfo->ip_time = bpf_ktime_get_ns() / 1000; - // bpf_printk("rx enter ipv4 layer.\n"); - return 0; -} +int BPF_KPROBE(ip_rcv_core, struct sk_buff *skb) { return __ip_rcv_core(skb); } /** in only ipv6 */ SEC("kprobe/ip6_rcv_core") int BPF_KPROBE(ip6_rcv_core, struct sk_buff *skb) { - if (!layer_time) { - return 0; - } - if (skb == NULL) - return 0; - struct ipv6hdr *ip6h = skb_to_ipv6hdr(skb); - struct tcphdr *tcp = skb_to_tcphdr(skb); - struct packet_tuple pkt_tuple = {0}; - get_pkt_tuple_v6(&pkt_tuple, ip6h, tcp); - - struct ktime_info *tinfo; - tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple); - if (tinfo == NULL) { - return 0; - } - - tinfo->ip_time = bpf_ktime_get_ns() / 1000; - // bpf_printk("rx enter ipv6 layer.\n"); - return 0; + return __ip6_rcv_core(skb); } /**in only ipv4 */ // 接收数据包 SEC("kprobe/tcp_v4_rcv") // 记录数据包在tcpv4层时间戳 -int BPF_KPROBE(tcp_v4_rcv, struct sk_buff *skb) { - if (!layer_time) { - return 0; - } - if (skb == NULL) - return 0; - struct iphdr *ip = skb_to_iphdr(skb); - struct tcphdr *tcp = skb_to_tcphdr(skb); - struct packet_tuple pkt_tuple = {0}; - get_pkt_tuple(&pkt_tuple, ip, tcp); - struct ktime_info *tinfo; - tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple); - if (tinfo == NULL) { - return 0; - } - tinfo->tran_time = bpf_ktime_get_ns() / 1000; - // bpf_printk("rx enter tcp4 layer.\n"); - return 0; -} +int BPF_KPROBE(tcp_v4_rcv, struct sk_buff *skb) { return __tcp_v4_rcv(skb); } /** in only ipv6 */ SEC("kprobe/tcp_v6_rcv") // 接收tcpv6数据包 -int BPF_KPROBE(tcp_v6_rcv, struct sk_buff *skb) { - if (!layer_time) { - return 0; - } - if (skb == NULL) - return 0; - struct ipv6hdr *ip6h = skb_to_ipv6hdr(skb); - struct tcphdr *tcp = skb_to_tcphdr(skb); - struct packet_tuple pkt_tuple = {0}; - get_pkt_tuple_v6(&pkt_tuple, ip6h, tcp); - - struct ktime_info *tinfo; - tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple); - if (tinfo == NULL) { - return 0; - } - tinfo->tran_time = bpf_ktime_get_ns() / 1000; - // bpf_printk("rx enter tcp6 layer.\n"); - return 0; -} +int BPF_KPROBE(tcp_v6_rcv, struct sk_buff *skb) { return __tcp_v6_rcv(skb); } // v4 & v6 do_rcv to get sk and other info SEC("kprobe/tcp_v4_do_rcv") int BPF_KPROBE(tcp_v4_do_rcv, struct sock *sk, struct sk_buff *skb) { - - if (sk == NULL || skb == NULL) - return 0; - struct conn_t *conn = bpf_map_lookup_elem(&conns_info, &sk); - if (conn == NULL) { - // bpf_printk("get a v4 rx pack but conn not record, its sock is: - // %p",sk); - return 0; - } - struct iphdr *ip = skb_to_iphdr(skb); - struct tcphdr *tcp = skb_to_tcphdr(skb); - struct packet_tuple pkt_tuple = {0}; - get_pkt_tuple(&pkt_tuple, ip, tcp); - - struct ktime_info *tinfo; - tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple); - if (tinfo == NULL) { - return 0; - } - - CONN_INFO_TRANSFER - - // bpf_printk("rx enter tcp4_do_rcv, sk: %p \n", sk); - - CONN_ADD_EXTRA_INFO - - return 0; + return __tcp_v4_do_rcv(sk, skb); } SEC("kprobe/tcp_v6_do_rcv") // tcp层包时间 int BPF_KPROBE(tcp_v6_do_rcv, struct sock *sk, struct sk_buff *skb) { - if (sk == NULL || skb == NULL) - return 0; - // bpf_printk("rx enter tcp6_do_rcv. \n"); - struct conn_t *conn = bpf_map_lookup_elem(&conns_info, &sk); - if (conn == NULL) { - // bpf_printk("get a v6 rx pack but conn not record, its sock is: %p", - // sk); - return 0; - } - - struct ipv6hdr *ip6h = skb_to_ipv6hdr(skb); - struct tcphdr *tcp = skb_to_tcphdr(skb); - struct packet_tuple pkt_tuple = {0}; - get_pkt_tuple_v6(&pkt_tuple, ip6h, tcp); // 使用ip和tcp信息填充pkt_tuple - - struct ktime_info *tinfo; - tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple); - if (tinfo == NULL) { - return 0; - } - - CONN_INFO_TRANSFER - - // bpf_printk("rx enter tcp6_do_rcv, sk: %p \n", sk); - - CONN_ADD_EXTRA_INFO - - return 0; + return __tcp_v6_do_rcv(sk, skb); } /** in ipv4 && ipv6 */ SEC("kprobe/skb_copy_datagram_iter") // 处理网络数据包,记录分析包在不同网络层之间的时间差,分ipv4以及ipv6 int BPF_KPROBE(skb_copy_datagram_iter, struct sk_buff *skb) { - if (skb == NULL) - return 0; - __be16 protocol = BPF_CORE_READ(skb, protocol); // 读取skb协议字段 - struct tcphdr *tcp = skb_to_tcphdr(skb); - struct packet_tuple pkt_tuple = {0}; - struct ktime_info *tinfo; - if (protocol == __bpf_htons(ETH_P_IP)) { /** ipv4 */ - - struct iphdr *ip = skb_to_iphdr(skb); - get_pkt_tuple(&pkt_tuple, ip, tcp); - tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple); - if (tinfo == NULL) { - return 0; - } - - tinfo->app_time = bpf_ktime_get_ns() / 1000; - } else if (protocol == __bpf_ntohs(ETH_P_IPV6)) { - /** ipv6 */ - struct ipv6hdr *ip6h = skb_to_ipv6hdr(skb); - get_pkt_tuple_v6(&pkt_tuple, ip6h, tcp); - - if ((tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple)) == NULL) { - return 0; - } - tinfo->app_time = bpf_ktime_get_ns() / 1000; - } else { - return 0; - } - /*----- record packet time info ------*/ - - if (tinfo == NULL) { - return 0; - } - struct sock *sk = tinfo->sk; - if (sk == NULL) { - return 0; - } - // bpf_printk("rx enter app layer.\n"); - - PACKET_INIT_WITH_COMMON_INFO - - if (layer_time) { - packet->mac_time = tinfo->ip_time - tinfo->mac_time; - // 计算MAC层和ip层之间的时间差 - packet->ip_time = tinfo->tran_time - tinfo->ip_time; - // 计算ip层和tcp层之间的时间差 - packet->tran_time = tinfo->app_time - tinfo->tran_time; - // 计算tcp层和应用层之间的时间差 - } - packet->rx = 1; // 数据包已经被接收 - - // RX HTTP INFO - if (http_info) { - int doff = - BPF_CORE_READ_BITFIELD_PROBED(tcp, doff); // 得用bitfield_probed - // 读取tcp头部中的数据偏移字段 - unsigned char *user_data = - (unsigned char *)((unsigned char *)tcp + (doff * 4)); - // 计算tcp的负载开始位置就是tcp头部之后的数据,将tcp指针指向tcp头部位置将其转换成unsigned - // char类型 - // doff * - // 4数据偏移值(tcp的头部长度20个字节)乘以4计算tcp头部实际字节长度,32位为单位就是4字节 - bpf_probe_read_str(packet->data, sizeof(packet->data), - user_data); // 将tcp负载数据读取到packet->data - } - bpf_ringbuf_submit(packet, 0); // 将packet提交到缓冲区 - return 0; + return __skb_copy_datagram_iter(skb); } -/**** end of receive path ****/ - -/**** receive error packet ****/ +// receive error packet /* TCP invalid seq error */ // 根据传入的数据包提取关键信息(如IP和TCP头部信息),并将这些信息与其他元数据(如套接字信息和错误标识)一同存储到BPF // ring buffer中 SEC("kprobe/tcp_validate_incoming") // 验证传入数据包的序列号 int BPF_KPROBE(tcp_validate_incoming, struct sock *sk, struct sk_buff *skb) { - if (!err_packet) { - return 0; - } - if (sk == NULL || skb == NULL) - return 0; - struct conn_t *conn = - bpf_map_lookup_elem(&conns_info, &sk); // BPFmap查找与套接字sk关联的信息 - if (conn == NULL) { - return 0; - } - struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); // 数据包信息 - u32 start_seq = BPF_CORE_READ(tcb, seq); // 开始序列号 - u32 end_seq = BPF_CORE_READ(tcb, end_seq); // 结束序列号 - struct tcp_sock *tp = tcp_sk(sk); // 套接字信息 - u32 rcv_wup = BPF_CORE_READ( - tp, rcv_wup); // 接收方已经确认并准备接收的数据最后一个字节的序列号 - u32 rcv_nxt = - BPF_CORE_READ(tp, rcv_nxt); // 期望发送发下次发送的数据字节序列号 - u32 rcv_wnd = BPF_CORE_READ(tp, rcv_wnd); // tcp接收窗口大小 - u32 receive_window = rcv_wup + rcv_nxt - rcv_wnd; // 当前可用的接收窗口 - receive_window = 0; - - if (end_seq >= rcv_wup && rcv_nxt + receive_window >= start_seq) { - // bpf_printk("error_identify: tcp seq validated. \n"); - return 0; - // 检查数据包序列号是否在接收窗口内 - } - // bpf_printk("error_identify: tcp seq err. \n"); - // invalid seq - u16 family = BPF_CORE_READ( - sk, __sk_common.skc_family); // 获取套接字的地址族就是获得当前ip协议 - struct packet_tuple pkt_tuple = {0}; - if (family == AF_INET) { - struct iphdr *ip = skb_to_iphdr(skb); - struct tcphdr *tcp = skb_to_tcphdr(skb); - get_pkt_tuple(&pkt_tuple, ip, tcp); - } else if (family == AF_INET6) { - struct ipv6hdr *ip6h = skb_to_ipv6hdr(skb); - struct tcphdr *tcp = skb_to_tcphdr(skb); - get_pkt_tuple_v6(&pkt_tuple, ip6h, tcp); - } else { - return 0; - } - struct pack_t *packet; - packet = bpf_ringbuf_reserve(&rb, sizeof(*packet), 0); - if (!packet) { - return 0; - } - packet->err = 1; // 错误标记此数据包有问题 - packet->sock = sk; - packet->ack = pkt_tuple.ack; - packet->seq = pkt_tuple.seq; - bpf_ringbuf_submit(packet, 0); - return 0; + return __tcp_validate_incoming(sk, skb); } // 跟踪网络数据包检测tcp检验和错误 /* TCP invalid checksum error*/ SEC("kretprobe/__skb_checksum_complete") int BPF_KRETPROBE(__skb_checksum_complete_exit, int ret) { - if (!err_packet) { - return 0; - } - u64 pid = bpf_get_current_pid_tgid(); - struct sock **skp = bpf_map_lookup_elem(&sock_stores, &pid); - if (skp == NULL) { - return 0; - } - if (ret == 0) { - // bpf_printk("error_identify: tcp checksum validated. \n"); - return 0; - } - // bpf_printk("error_identify: tcp checksum error. \n"); - struct sock *sk = *skp; - struct conn_t *conn = bpf_map_lookup_elem(&conns_info, &sk); - if (conn == NULL) { - return 0; - } - struct pack_t *packet; - packet = bpf_ringbuf_reserve(&rb, sizeof(*packet), 0); - if (!packet) { - return 0; - } - packet->err = 2; // 校验和错误 - packet->sock = sk; // 存储socket信息到sock字段中 - bpf_ringbuf_submit(packet, 0); - - return 0; + return skb_checksum_complete(ret); } -/**** receive error packet end ****/ - /**** send path ****/ /*! * \brief: 获取数据包进入TCP层时刻的时间戳, 发送tcp层起始点 @@ -934,85 +163,7 @@ int BPF_KRETPROBE(__skb_checksum_complete_exit, int ret) { */ SEC("kprobe/tcp_sendmsg") // 跟踪tcp发送包信息 int BPF_KPROBE(tcp_sendmsg, struct sock *sk, struct msghdr *msg, size_t size) { - - struct conn_t *conn = bpf_map_lookup_elem(&conns_info, &sk); - if (conn == NULL) { - return 0; - } - - u16 family = BPF_CORE_READ(sk, __sk_common.skc_family); - struct ktime_info *tinfo, zero = {0}; // 存储时间 - struct packet_tuple pkt_tuple = {0}; // 存储数据包信息 - /** ipv4 */ - if (family == AF_INET) { - u16 dport = BPF_CORE_READ(sk, __sk_common.skc_dport); - pkt_tuple.saddr = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr); // 源ip - pkt_tuple.daddr = BPF_CORE_READ(sk, __sk_common.skc_daddr); // 目的ip - pkt_tuple.sport = BPF_CORE_READ(sk, __sk_common.skc_num); // 源端口 - pkt_tuple.dport = __bpf_ntohs(dport); // 目的端口并进行字节序转换 - - u32 snd_nxt = - BPF_CORE_READ(tcp_sk(sk), snd_nxt); // tcp要发送的下一个字节序列号 - u32 rcv_nxt = BPF_CORE_READ(tcp_sk(sk), - rcv_nxt); // tcp接收的下一个字节的期望序列号 - pkt_tuple.seq = snd_nxt; - pkt_tuple.ack = rcv_nxt; - pkt_tuple.tran_flag = TCP; - tinfo = (struct ktime_info *)bpf_map_lookup_or_try_init( - ×tamps, &pkt_tuple, - &zero); // timestamps的BPF map保存数据包与时间戳的映射 - if (tinfo == NULL) { - return 0; - } - tinfo->tran_time = bpf_ktime_get_ns() / 1000; - } else if (family == AF_INET6) { - // 读取ipv6源地址 - bpf_probe_read_kernel( - &pkt_tuple.saddr_v6, - sizeof(sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32), - &sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32); - // 获取ipv6目的地址 - bpf_probe_read_kernel( - &pkt_tuple.daddr_v6, - sizeof(sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32), - &sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32); - // sk套接字中获取源端口号 - pkt_tuple.sport = BPF_CORE_READ(sk, __sk_common.skc_num); - // 获取目的端口 - u16 dport = BPF_CORE_READ(sk, __sk_common.skc_dport); - pkt_tuple.dport = __bpf_ntohs(dport); - - u32 snd_nxt = - BPF_CORE_READ(tcp_sk(sk), snd_nxt); // 发送的下一个字节序列号 - u32 rcv_nxt = - BPF_CORE_READ(tcp_sk(sk), rcv_nxt); // 期望接收的下一个字节序列号 - pkt_tuple.seq = snd_nxt; - pkt_tuple.ack = rcv_nxt; - pkt_tuple.tran_flag = TCP; - - tinfo = (struct ktime_info *)bpf_map_lookup_or_try_init( - ×tamps, &pkt_tuple, &zero); - if (tinfo == NULL) { - return 0; - } - tinfo->tran_time = bpf_ktime_get_ns() / 1000; - } - - CONN_INFO_TRANSFER - - CONN_ADD_EXTRA_INFO - - // TX HTTP info - if (http_info) { - unsigned char *user_data = BPF_CORE_READ(msg, msg_iter.iov, iov_base); - tinfo = (struct ktime_info *)bpf_map_lookup_or_try_init( - ×tamps, &pkt_tuple, &zero); - if (tinfo == NULL) { - return 0; - } - bpf_probe_read_str(tinfo->data, sizeof(tinfo->data), user_data); - } - return 0; + return __tcp_sendmsg(sk, msg, size); } /*! @@ -1022,32 +173,7 @@ tcp)获取ip段的数据 out only ipv4 */ SEC("kprobe/ip_queue_xmit") int BPF_KPROBE(ip_queue_xmit, struct sock *sk, struct sk_buff *skb) { - if (!layer_time) { - return 0; - } - u16 family = BPF_CORE_READ(sk, __sk_common.skc_family); - struct packet_tuple pkt_tuple = {0}; - struct ktime_info *tinfo; - struct tcphdr *tcp = skb_to_tcphdr(skb); - if (family == AF_INET) { - u16 dport; - u32 seq, ack; - pkt_tuple.saddr = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr); - pkt_tuple.daddr = BPF_CORE_READ(sk, __sk_common.skc_daddr); - pkt_tuple.sport = BPF_CORE_READ(sk, __sk_common.skc_num); - dport = BPF_CORE_READ(sk, __sk_common.skc_dport); - pkt_tuple.dport = __bpf_ntohs(dport); - seq = BPF_CORE_READ(tcp, seq); - ack = BPF_CORE_READ(tcp, ack_seq); - pkt_tuple.seq = __bpf_ntohl(seq); - pkt_tuple.ack = __bpf_ntohl(ack); - pkt_tuple.tran_flag = TCP; - if ((tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple)) == NULL) { - return 0; - } - tinfo->ip_time = bpf_ktime_get_ns() / 1000; - } - return 0; + return __ip_queue_xmit(sk, skb); }; /*! @@ -1057,41 +183,7 @@ tcp)获取ip段的数据 out only ipv6 */ SEC("kprobe/inet6_csk_xmit") int BPF_KPROBE(inet6_csk_xmit, struct sock *sk, struct sk_buff *skb) { - if (!layer_time) { - return 0; - } - u16 family = BPF_CORE_READ(sk, __sk_common.skc_family); - struct tcphdr *tcp = skb_to_tcphdr(skb); - struct packet_tuple pkt_tuple = {0}; - struct ktime_info *tinfo; - if (family == AF_INET6) { - u16 dport; - u32 seq, ack; - - bpf_probe_read_kernel( - &pkt_tuple.saddr_v6, - sizeof(sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32), - &sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32); - - bpf_probe_read_kernel( - &pkt_tuple.daddr_v6, - sizeof(sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32), - &sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32); - - pkt_tuple.sport = BPF_CORE_READ(sk, __sk_common.skc_num); - dport = BPF_CORE_READ(sk, __sk_common.skc_dport); - pkt_tuple.dport = __bpf_ntohs(dport); - seq = BPF_CORE_READ(tcp, seq); - ack = BPF_CORE_READ(tcp, ack_seq); - pkt_tuple.seq = __bpf_ntohl(seq); - pkt_tuple.ack = __bpf_ntohl(ack); - pkt_tuple.tran_flag = TCP; - if ((tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple)) == NULL) { - return 0; - } - tinfo->ip_time = bpf_ktime_get_ns() / 1000; - } - return 0; + return __inet6_csk_xmit(sk, skb); }; /*! @@ -1100,40 +192,7 @@ int BPF_KPROBE(inet6_csk_xmit, struct sock *sk, struct sk_buff *skb) { */ SEC("kprobe/__dev_queue_xmit") int BPF_KPROBE(__dev_queue_xmit, struct sk_buff *skb) { - if (!layer_time) { - return 0; - } - // 从skb中读取以太网头部 - const struct ethhdr *eth = (struct ethhdr *)BPF_CORE_READ(skb, data); - u16 protocol = BPF_CORE_READ( - eth, - h_proto); // 以太网头部协议字段该字段存储的是以太网帧所封装的上层协议类型 - struct tcphdr *tcp = skb_to_tcphdr(skb); - struct packet_tuple pkt_tuple = {0}; - struct ktime_info *tinfo; - if (protocol == __bpf_ntohs(ETH_P_IP)) { - /** ipv4 */ - struct iphdr *ip = skb_to_iphdr(skb); - get_pkt_tuple(&pkt_tuple, ip, tcp); - - // FILTER_DPORT - // FILTER_SPORT - - if ((tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple)) == NULL) { - return 0; - } - tinfo->mac_time = bpf_ktime_get_ns() / 1000; - } else if (protocol == __bpf_ntohs(ETH_P_IPV6)) { - /** ipv6 */ - struct ipv6hdr *ip6h = skb_to_ipv6hdr(skb); - get_pkt_tuple_v6(&pkt_tuple, ip6h, tcp); - - if ((tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple)) == NULL) { - return 0; - } - tinfo->mac_time = bpf_ktime_get_ns() / 1000; - } - return 0; + return dev_queue_xmit(skb); }; /*! @@ -1142,83 +201,21 @@ int BPF_KPROBE(__dev_queue_xmit, struct sk_buff *skb) { */ SEC("kprobe/dev_hard_start_xmit") int BPF_KPROBE(dev_hard_start_xmit, struct sk_buff *skb) { - const struct ethhdr *eth = (struct ethhdr *)BPF_CORE_READ(skb, data); - u16 protocol = BPF_CORE_READ(eth, h_proto); - struct tcphdr *tcp = skb_to_tcphdr(skb); - struct packet_tuple pkt_tuple = {0}; - struct ktime_info *tinfo; - if (protocol == __bpf_ntohs(ETH_P_IP)) { - /** ipv4 */ - struct iphdr *ip = skb_to_iphdr(skb); - get_pkt_tuple(&pkt_tuple, ip, tcp); - - if ((tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple)) == NULL) { - return 0; - } - // 数据包在队列中等待的时间 - tinfo->qdisc_time = bpf_ktime_get_ns() / 1000; - } else if (protocol == __bpf_ntohs(ETH_P_IPV6)) { - /** ipv6 */ - struct ipv6hdr *ip6h = skb_to_ipv6hdr(skb); - get_pkt_tuple_v6(&pkt_tuple, ip6h, tcp); - - if ((tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple)) == NULL) { - return 0; - } - tinfo->qdisc_time = bpf_ktime_get_ns() / 1000; + if (protocol_count) { + return sum_protocol(skb, true); // send } else { - return 0; - } - - /*----- record packet time info ------*/ - if (tinfo == NULL) { - return 0; + return __dev_hard_start_xmit(skb); } - struct sock *sk = tinfo->sk; - if (!sk) { - return 0; - } - PACKET_INIT_WITH_COMMON_INFO - // 记录各层的时间差值 - if (layer_time) { - packet->tran_time = tinfo->ip_time - tinfo->tran_time; - packet->ip_time = tinfo->mac_time - tinfo->ip_time; - packet->mac_time =tinfo->qdisc_time -tinfo->mac_time; // 队列纪律层,处于网络协议栈最底层,负责实际数据传输与接收 - } - - packet->rx = 0; // 发送一个数据包 - - // TX HTTP Info - if (http_info) { - bpf_probe_read_str(packet->data, sizeof(packet->data), tinfo->data); - bpf_printk("%s", packet->data); - } - bpf_ringbuf_submit(packet, 0); - - return 0; }; -/**** send path end ****/ - -/**** retrans ****/ +// retrans /* 在进入快速恢复阶段时,不管是基于Reno或者SACK的快速恢复, * 还是RACK触发的快速恢复,都将使用函数tcp_enter_recovery进入 * TCP_CA_Recovery拥塞阶段。 */ SEC("kprobe/tcp_enter_recovery") // tcp连接进入恢复状态调用 int BPF_KPROBE(tcp_enter_recovery, struct sock *sk) { - if (!retrans_info) { - return 0; - } - struct conn_t *conn = bpf_map_lookup_elem(&conns_info, &sk); - if (conn == NULL) { - // bpf_printk("get a v4 rx pack but conn not record, its sock is: %p", - // sk); - return 0; - } - conn->fastRe += 1; // 统计进入tcp恢复状态的次数 - - return 0; + return __tcp_enter_recovery(sk); } /* Enter Loss state. If we detect SACK reneging, forget all SACK information @@ -1227,266 +224,137 @@ int BPF_KPROBE(tcp_enter_recovery, struct sock *sk) { * 在报文的重传定时器到期时,在tcp_retransmit_timer函数中,进入TCP_CA_Loss拥塞状态。 */ SEC("kprobe/tcp_enter_loss") -int BPF_KPROBE(tcp_enter_loss, struct sock *sk) { - if (!retrans_info) { - return 0; - } - struct conn_t *conn = bpf_map_lookup_elem(&conns_info, &sk); - if (conn == NULL) { - return 0; - } - conn->timeout += 1; - return 0; -} - -/**** retrans end ****/ - -/* new */ +int BPF_KPROBE(tcp_enter_loss, struct sock *sk) { return __tcp_enter_loss(sk); } +/* udp */ SEC("kprobe/udp_rcv") int BPF_KPROBE(udp_rcv, struct sk_buff *skb) { - if (!udp_info) - return 0; - if (skb == NULL) // 判断是否为空 - return 0; - struct iphdr *ip = skb_to_iphdr(skb); - struct udphdr *udp = skb_to_udphdr(skb); - struct packet_tuple pkt_tuple = {0}; - get_udp_pkt_tuple(&pkt_tuple, ip, udp); - struct ktime_info *tinfo, zero = {0}; - tinfo = (struct ktime_info *)bpf_map_lookup_or_try_init(×tamps, - &pkt_tuple, &zero); - if (tinfo == NULL) { + if (udp_info) + return __udp_rcv(skb); + else if (dns_info) + return __dns_rcv(skb); + else return 0; - } - tinfo->tran_time = bpf_ktime_get_ns() / 1000; - return 0; } SEC("kprobe/__udp_enqueue_schedule_skb") int BPF_KPROBE(__udp_enqueue_schedule_skb, struct sock *sk, struct sk_buff *skb) { - if (!udp_info) - return 0; - if (skb == NULL) // 判断是否为空 - return 0; - struct iphdr *ip = skb_to_iphdr(skb); - struct udphdr *udp = skb_to_udphdr(skb); - struct packet_tuple pkt_tuple = {0}; - u16 dport = BPF_CORE_READ(sk, __sk_common.skc_dport); - pkt_tuple.daddr = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr); - pkt_tuple.saddr = BPF_CORE_READ(sk, __sk_common.skc_daddr); - pkt_tuple.dport = BPF_CORE_READ(sk, __sk_common.skc_num); - pkt_tuple.sport = __bpf_ntohs(dport); - pkt_tuple.tran_flag = 2; - struct ktime_info *tinfo, zero = {0}; - tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple); - if (tinfo == NULL) { - return 0; - } - struct udp_message *message; - struct udp_message *udp_message = - bpf_map_lookup_elem(×tamps, &pkt_tuple); - ; - message = bpf_ringbuf_reserve(&udp_rb, sizeof(*message), 0); - if (!message) { - return 0; - } - message->tran_time = bpf_ktime_get_ns() / 1000 - tinfo->tran_time; - message->saddr = BPF_CORE_READ(sk, __sk_common.skc_daddr); - message->daddr = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr); - message->sport = __bpf_ntohs(BPF_CORE_READ(sk, __sk_common.skc_dport)); - message->dport = BPF_CORE_READ(sk, __sk_common.skc_num); - message->rx=0;//收包 - message->len=__bpf_ntohs(BPF_CORE_READ(udp,len)); - bpf_ringbuf_submit(message, 0); - return 0; + return udp_enqueue_schedule_skb(sk, skb); } -SEC("kprobe/udp_send_skb") -int BPF_KPROBE(udp_send_skb, struct sk_buff *skb,struct flowi4 *fl4) { - if (!udp_info) - return 0; - if (skb == NULL) // 判断是否为空 - return 0; - struct iphdr *ip = skb_to_iphdr(skb); - - struct udphdr *udp = skb_to_udphdr(skb); - struct packet_tuple pkt_tuple = {0}; - get_udp_pkt_tuple(&pkt_tuple, ip, udp); - - struct sock *sk = BPF_CORE_READ(skb, sk); - u16 dport = BPF_CORE_READ(sk, __sk_common.skc_dport); - pkt_tuple.daddr = BPF_CORE_READ(sk, __sk_common.skc_daddr); - pkt_tuple.saddr = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr); - pkt_tuple.dport = __bpf_ntohs(dport); - pkt_tuple.sport = BPF_CORE_READ(sk, __sk_common.skc_num); - pkt_tuple.tran_flag = UDP; - struct ktime_info *tinfo, zero = {0}; - tinfo = (struct ktime_info *)bpf_map_lookup_or_try_init(×tamps, - &pkt_tuple, &zero); - if (tinfo == NULL) { +SEC("kprobe/udp_send_skb") +int BPF_KPROBE(udp_send_skb, struct sk_buff *skb) { + if (udp_info) + return __udp_send_skb(skb); + else if (dns_info) + return __dns_send(skb); + else return 0; - } - tinfo->tran_time = bpf_ktime_get_ns() / 1000; - - unsigned int pid = bpf_get_current_pid_tgid(); - bpf_map_update_elem(&pid_UDP, &pid, &pkt_tuple, BPF_ANY); - - return 0; } SEC("kprobe/ip_send_skb") -int BPF_KPROBE(ip_send_skb, struct net *net,struct sk_buff *skb) { - if (!udp_info) - return 0; - if (skb == NULL) // 判断是否为空 - return 0; - unsigned int pid = bpf_get_current_pid_tgid(); - struct packet_tuple *pt = bpf_map_lookup_elem(&pid_UDP, &pid); - if (!pt) { - return 0; - } - - struct ktime_info *tinfo, zero = {0}; - struct udphdr *udp = skb_to_udphdr(skb); - tinfo = bpf_map_lookup_elem(×tamps, pt); - if (tinfo == NULL) { - return 0; - } - struct udp_message *message; - struct udp_message *udp_message = - bpf_map_lookup_elem(×tamps, pt); - message = bpf_ringbuf_reserve(&udp_rb, sizeof(*message), 0); - if (!message) { - return 0; - } - message->tran_time = bpf_ktime_get_ns() / 1000 - tinfo->tran_time; - message->saddr = pt->saddr; - message->daddr = pt->daddr; - message->sport = pt->sport; - message->dport = pt->dport; - message->rx=1; - message->len=__bpf_ntohs(BPF_CORE_READ(udp,len)); - bpf_ringbuf_submit(message, 0); - return 0; +int BPF_KPROBE(ip_send_skb, struct net *net, struct sk_buff *skb) { + return __ip_send_skb(skb); } -//netfilter +// netfilter SEC("kprobe/ip_rcv") -int BPF_KPROBE(ip_rcv, struct sk_buff *skb) { - if (skb == NULL) // 判断是否为空 - return 0; - struct iphdr *ip = skb_to_iphdr(skb); - struct tcphdr *tcp = skb_to_tcphdr(skb); - struct packet_tuple pkt_tuple = {0}; - get_pkt_tuple(&pkt_tuple, ip, tcp); - unsigned int pid = bpf_get_current_pid_tgid(); - struct filtertime *tinfo, zero = {0}; - tinfo = (struct filtertime *)bpf_map_lookup_or_try_init(&netfilter_time, - &pid, &zero); - bpf_map_update_elem(&pid_filter, &pid, &pkt_tuple, BPF_ANY); - if (tinfo == NULL) { - return 0; - } - tinfo->ip_rcv_time = bpf_ktime_get_ns() / 1000; - return 0; +int BPF_KPROBE(ip_rcv, struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt, struct net_device *orig_dev) { + return store_nf_time(skb, e_ip_rcv); } SEC("kprobe/ip_local_deliver") -int BPF_KPROBE(ip_local_deliver) { - unsigned int pid = bpf_get_current_pid_tgid(); - struct filtertime *tinfo, zero = {0}; - tinfo = (struct filtertime *)bpf_map_lookup_or_try_init(&netfilter_time, - &pid, &zero); - if (tinfo == NULL) { - return 0; - } - tinfo->ip_local_deliver_time = bpf_ktime_get_ns() / 1000; - return 0; +int BPF_KPROBE(ip_local_deliver, struct sk_buff *skb) { + return store_nf_time(skb, e_ip_local_deliver); } SEC("kprobe/ip_local_deliver_finish") -int BPF_KPROBE(ip_local_deliver_finish) { - unsigned int pid = bpf_get_current_pid_tgid(); - struct packet_tuple *pkt_tuple = bpf_map_lookup_elem(&pid_filter, &pid); - if (!pkt_tuple) { - return 0; - } - struct filtertime *tinfo, zero = {0}; - tinfo = (struct filtertime *)bpf_map_lookup_or_try_init(&netfilter_time, - &pid, &zero); - if (tinfo == NULL) { - return 0; - } - tinfo->ip_local_deliver_finish_time = bpf_ktime_get_ns() / 1000; - - struct netfilter *message; - struct netfilter *netfilter =bpf_map_lookup_elem(&netfilter_time, pkt_tuple); - message = bpf_ringbuf_reserve(&netfilter_rb, sizeof(*message), 0); - if (!message) { - return 0; - } - message->saddr = pkt_tuple->saddr; - message->daddr =pkt_tuple->daddr; - message->sport =pkt_tuple->sport; - message->dport = pkt_tuple->dport; - message->local_input_time = tinfo->ip_local_deliver_finish_time - tinfo->ip_local_deliver_time; - message->pre_routing_time = tinfo->ip_local_deliver_time - tinfo->ip_rcv_time; - message->flag=1;//收包 - bpf_ringbuf_submit(message, 0); - return 0; +int BPF_KPROBE(ip_local_deliver_finish, struct net *net, struct sock *sk, + struct sk_buff *skb) { + return store_nf_time(skb, e_ip_local_deliver_finish); } SEC("kprobe/ip_local_out") -int BPF_KPROBE(ip_local_out, struct sk_buff *skb) { - unsigned int pid = bpf_get_current_pid_tgid(); - struct filtertime *tinfo, zero = {0}; - tinfo = (struct filtertime *)bpf_map_lookup_or_try_init(&netfilter_time, - &pid, &zero); - if (tinfo == NULL) { - return 0; - } - tinfo->ip_local_out_time = bpf_ktime_get_ns() / 1000; - return 0; +int BPF_KPROBE(ip_local_out, struct net *net, struct sock *sk, + struct sk_buff *skb) { + return store_nf_time(skb, e_ip_local_out); } SEC("kprobe/ip_output") -int BPF_KPROBE(ip_output) { - unsigned int pid = bpf_get_current_pid_tgid(); - struct filtertime *tinfo, zero = {0}; - tinfo = (struct filtertime *)bpf_map_lookup_or_try_init(&netfilter_time, - &pid, &zero); - if (tinfo == NULL) { - return 0; - } - tinfo->ip_output_time = bpf_ktime_get_ns() / 1000; - return 0; +int BPF_KPROBE(ip_output, struct net *net, struct sock *sk, + struct sk_buff *skb) { + return store_nf_time(skb, e_ip_output); } -SEC("kprobe/ip_finish_output") -int BPF_KPROBE(ip_finish_output) { - unsigned int pid = bpf_get_current_pid_tgid(); - struct packet_tuple *pkt_tuple = bpf_map_lookup_elem(&pid_filter, &pid); - if (!pkt_tuple) { - return 0; - } - struct filtertime *tinfo, zero = {0}; - tinfo = (struct filtertime *)bpf_map_lookup_or_try_init(&netfilter_time, - &pid, &zero); - if (tinfo == NULL) { - return 0; - } - tinfo->ip_finish_output_time = bpf_ktime_get_ns() / 1000; - struct netfilter *message; - struct netfilter *netfilter =bpf_map_lookup_elem(&netfilter_time, pkt_tuple); - message = bpf_ringbuf_reserve(&netfilter_rb, sizeof(*message), 0); - if(!message){ - return 0; - } - message->local_out_time=tinfo->ip_output_time-tinfo->ip_local_out_time; - message->post_routing_time=tinfo->ip_finish_output_time-tinfo->ip_output_time; - message->flag=2; - bpf_ringbuf_submit(message,0); - return 0; +SEC("kprobe/__ip_finish_output") +int BPF_KPROBE(__ip_finish_output, struct net *net, struct sock *sk, + struct sk_buff *skb) { + return store_nf_time(skb, e_ip_finish_output); +} + +SEC("kprobe/ip_forward") +int BPF_KPROBE(ip_forward, struct sk_buff *skb) { + return store_nf_time(skb, e_ip_forward); +} + +// drop +SEC("tp/skb/kfree_skb") +int tp_kfree(struct trace_event_raw_kfree_skb *ctx) { return __tp_kfree(ctx); } + +SEC("kprobe/icmp_rcv") +int BPF_KPROBE(icmp_rcv, struct sk_buff *skb) { return __icmp_time(skb); } + +SEC("kprobe/__sock_queue_rcv_skb") +int BPF_KPROBE(__sock_queue_rcv_skb, struct sock *sk, struct sk_buff *skb) { + return __rcvend_icmp_time(skb); +} + +SEC("kprobe/icmp_reply") +int BPF_KPROBE(icmp_reply, struct icmp_bxm *icmp_param, struct sk_buff *skb) { + return __reply_icmp_time(skb); +} + +// mysql +SEC("uprobe/_Z16dispatch_commandP3THDPK8COM_DATA19enum_server_command") +int BPF_KPROBE(query__start) { return __handle_mysql_start(ctx); } + +SEC("uretprobe/_Z16dispatch_commandP3THDPK8COM_DATA19enum_server_command") +int BPF_KPROBE(query__end) { return __handle_mysql_end(ctx); } + +//redis +SEC("uprobe/processCommand") +int BPF_KPROBE(redis_processCommand) { return __handle_redis_start(ctx); } + +SEC("uretprobe/call") +int BPF_KPROBE(redis_call) { return __handle_redis_end(ctx); } + +SEC("uprobe/lookupKey") +int BPF_UPROBE(redis_lookupKey) { + return __handle_redis_key(ctx); +} +SEC("uprobe/addReply") +int BPF_UPROBE(redis_addReply) { + return __handle_redis_value(ctx); +} +// rtt +SEC("kprobe/tcp_rcv_established") +int BPF_KPROBE(tcp_rcv_established, struct sock *sk, struct sk_buff *skb) { + return __tcp_rcv_established(sk, skb); +} + +// tcpstate +SEC("tracepoint/sock/inet_sock_set_state") +int handle_set_state(struct trace_event_raw_inet_sock_set_state *ctx) { + return __handle_set_state(ctx); +} +// RST +SEC("tracepoint/tcp/tcp_send_reset") +int handle_send_reset(struct trace_event_raw_tcp_send_reset *ctx) { + return __handle_send_reset(ctx); } +SEC("tracepoint/tcp/tcp_receive_reset") +int handle_receive_reset(struct trace_event_raw_tcp_receive_reset *ctx) { + return __handle_receive_reset(ctx); +} \ No newline at end of file diff --git a/MagicEyes/src/backend/net/net_watcher/bpf/netfilter.bpf.h b/MagicEyes/src/backend/net/net_watcher/bpf/netfilter.bpf.h new file mode 100644 index 000000000..f6eea5202 --- /dev/null +++ b/MagicEyes/src/backend/net/net_watcher/bpf/netfilter.bpf.h @@ -0,0 +1,132 @@ +// Copyright 2023 The LMP Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://github.com/linuxkerneltravel/lmp/blob/develop/LICENSE +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: blown.away@qq.com +// net_watcher libbpf netfilter + +#include "common.bpf.h" + +static __always_inline +int submit_nf_time(struct packet_tuple pkt_tuple, struct filtertime *tinfo, int rx) +{ + int time =0; + struct netfilter *message; + FILTER + message = bpf_ringbuf_reserve(&netfilter_rb, sizeof(*message), 0); + if(!message){ + return 0; + } + + message->saddr = pkt_tuple.saddr; + message->daddr =pkt_tuple.daddr; + message->sport =pkt_tuple.sport; + message->dport = pkt_tuple.dport; + message->local_input_time = 0; + message->pre_routing_time = 0; + message->local_out_time = 0; + message->post_routing_time = 0; + message->forward_time=0; + message->rx = rx; //收/发/转发方向 + + if(rx == 1){ + if(tinfo->time[e_ip_local_deliver_finish] && + tinfo->time[e_ip_local_deliver] && + tinfo->time[e_ip_rcv]) + { + message->local_input_time = tinfo->time[e_ip_local_deliver_finish] - + tinfo->time[e_ip_local_deliver]; + message->pre_routing_time = tinfo->time[e_ip_local_deliver] - + tinfo->time[e_ip_rcv]; + if((int)message->local_input_time < 0 || (int)message->pre_routing_time < 0){ + bpf_ringbuf_discard(message, 0); + return 0; + } + } + }else{ + if(tinfo->time[e_ip_local_deliver_finish] && + tinfo->time[e_ip_local_deliver] && + tinfo->time[e_ip_rcv] && + tinfo->time[e_ip_forward] && + tinfo->time[e_ip_output]) + { + message->local_input_time = tinfo->time[e_ip_local_deliver_finish] - + tinfo->time[e_ip_local_deliver]; + message->pre_routing_time = tinfo->time[e_ip_local_deliver] - + tinfo->time[e_ip_rcv]; + + u64 forward_time = tinfo->time[e_ip_output] - tinfo->time[e_ip_forward]; + + if((int)forward_time < 0){ + bpf_ringbuf_discard(message, 0); + return 0; + } + message->forward_time = forward_time; + message->rx = 2; + } + if(tinfo->time[e_ip_output] && + tinfo->time[e_ip_local_out] && + tinfo->time[e_ip_finish_output]) + { + message->local_out_time = tinfo->time[e_ip_output] - + tinfo->time[e_ip_local_out]; + message->post_routing_time = tinfo->time[e_ip_finish_output] - + tinfo->time[e_ip_output]; + if((int)message->local_out_time < 0 || (int)message->post_routing_time < 0){ + bpf_ringbuf_discard(message, 0); + return 0; + } + } + } + bpf_ringbuf_submit(message,0); + return 0; +} + +static __always_inline +int store_nf_time(struct sk_buff *skb, int hook) +{ + if(!net_filter) + return 0; + if (skb == NULL) // 判断是否为空 + return 0; + struct iphdr *ip = skb_to_iphdr(skb); + struct tcphdr *tcp = skb_to_tcphdr(skb); + + struct filtertime *tinfo, zero = {.init = {0}, .done={0}, .time={0}}; + if(hook == e_ip_rcv || hook == e_ip_local_out){ + tinfo = (struct filtertime *)bpf_map_lookup_or_try_init(&netfilter_time, + &skb, &zero); + if(tinfo == NULL) + return 0; + get_pkt_tuple(&tinfo->init, ip, tcp); + } + else{ + tinfo = (struct filtertime *)bpf_map_lookup_elem(&netfilter_time, &skb); + if (tinfo == NULL) { + return 0; + } + } + tinfo->time[hook] = bpf_ktime_get_ns() / 1000; + if(hook == e_ip_local_deliver_finish){ + submit_nf_time(tinfo->init, tinfo, 1); + bpf_map_delete_elem(&netfilter_time, &skb); + } + + if(hook == e_ip_finish_output){ + submit_nf_time(tinfo->init, tinfo, 0); + bpf_map_delete_elem(&netfilter_time, &skb); + } + + return 0; +} + diff --git a/MagicEyes/src/backend/net/net_watcher/bpf/packet.bpf.h b/MagicEyes/src/backend/net/net_watcher/bpf/packet.bpf.h new file mode 100644 index 000000000..c75dbea20 --- /dev/null +++ b/MagicEyes/src/backend/net/net_watcher/bpf/packet.bpf.h @@ -0,0 +1,638 @@ +// Copyright 2023 The LMP Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://github.com/linuxkerneltravel/lmp/blob/develop/LICENSE +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: blown.away@qq.com + +#include "common.bpf.h" +/* +in_ipv4: + kprobe/eth_type_trans + kprobe/ip_rcv_core.isra.0 + kprobe/tcp_v4_rcv + kprobe/tcp_v4_do_rcv + kprobe/skb_copy_datagram_iter + +in_ipv6: + kprobe/eth_type_trans + kprobe/ip6_rcv_core.isra.0 + kprobe/tcp_v6_rcv + kprobe/tcp_v6_do_rcv + kprobe/skb_copy_datagram_iter +*/ +static __always_inline struct packet_count *count_packet(u32 proto, + bool is_tx) { + struct packet_count *count; + struct packet_count initial_count = {0}; + + count = bpf_map_lookup_elem(&proto_stats, &proto); + if (!count) { + initial_count.tx_count = 0; + initial_count.rx_count = 0; + if (bpf_map_update_elem(&proto_stats, &proto, &initial_count, + BPF_ANY)) { + return NULL; + } + count = bpf_map_lookup_elem(&proto_stats, &proto); + if (!count) { + return NULL; + } + } + + if (is_tx) + __sync_fetch_and_add(&count->tx_count, 1); + else + __sync_fetch_and_add(&count->rx_count, 1); + return count; +} + +static __always_inline int sum_protocol(struct sk_buff *skb, bool is_tx) { + const struct ethhdr *eth = (struct ethhdr *)BPF_CORE_READ(skb, data); + u16 proto = BPF_CORE_READ(eth, h_proto); + + struct packet_info *pkt = bpf_ringbuf_reserve(&port_rb, sizeof(*pkt), 0); + if (!pkt) { + return 0; + } + + if (BPF_CORE_READ(eth, h_proto) != __bpf_htons(ETH_P_IP)) { + bpf_ringbuf_discard(pkt, 0); + return 0; + } + + struct iphdr *ip = (struct iphdr *)(BPF_CORE_READ(skb, data) + 14); + if (!ip) { + bpf_ringbuf_discard(pkt, 0); + return 0; + } + + pkt->saddr = BPF_CORE_READ(ip, saddr); + pkt->daddr = BPF_CORE_READ(ip, daddr); + pkt->proto = BPF_CORE_READ(ip, protocol); + + if (pkt->proto == IPPROTO_TCP) { + struct tcphdr *tcp = + (struct tcphdr *)(BPF_CORE_READ(skb, data) + sizeof(struct ethhdr) + + sizeof(struct iphdr)); + pkt->sport = BPF_CORE_READ(tcp, source); + pkt->dport = BPF_CORE_READ(tcp, dest); + pkt->proto = PROTO_TCP; + } else if (pkt->proto == IPPROTO_UDP) { + struct udphdr *udp = + (struct udphdr *)(BPF_CORE_READ(skb, data) + sizeof(struct ethhdr) + + sizeof(struct iphdr)); + pkt->sport = BPF_CORE_READ(udp, source); + pkt->dport = BPF_CORE_READ(udp, dest); + pkt->proto = PROTO_UDP; + } else if (pkt->proto == IPPROTO_ICMP) { + pkt->proto = PROTO_ICMP; + } else { + pkt->proto = PROTO_UNKNOWN; + } + struct packet_count *count = count_packet(pkt->proto, is_tx); + if (count) { + pkt->count.tx_count = count->tx_count; + pkt->count.rx_count = count->rx_count; + } else { + pkt->count.tx_count = 0; + pkt->count.rx_count = 0; + } + + // bpf_printk("pkt: saddr=%u, daddr=%u, proto=%u\n", pkt->saddr, pkt->daddr, + // pkt->proto); bpf_printk("sport=%d, dport=%d\n", pkt->sport, pkt->dport); + // bpf_printk("count_tx=%llu, count_rx=%llu\n", pkt->count.tx_count, + // pkt->count.rx_count); + bpf_ringbuf_submit(pkt, 0); + + return 0; +} +static __always_inline int __eth_type_trans(struct sk_buff *skb) { + const struct ethhdr *eth = + (struct ethhdr *)BPF_CORE_READ(skb, data); // 读取里面的报文数据 + u16 protocol = BPF_CORE_READ(eth, h_proto); // 读取包ID + // bpf_printk("protocol: %d\n", __bpf_ntohs(protocol)); + if (protocol == __bpf_htons(ETH_P_IP)) { // Protocol is IP 0x0800 + // 14 --> sizeof(struct ethhdr) / define + struct iphdr *ip = + (struct iphdr *)(BPF_CORE_READ(skb, data) + + 14); // 链路层头部长度为14 源端口6字节 + // 目的端口6字节 类型2字节 + struct tcphdr *tcp = (struct tcphdr *)(BPF_CORE_READ(skb, data) + + sizeof(struct iphdr) + 14); + struct packet_tuple pkt_tuple = {0}; // 声明packet_tuple结构pkt_tuple + get_pkt_tuple(&pkt_tuple, ip, tcp); // 初始化pkt_tuple + + struct ktime_info *tinfo, zero = {0}; // 定义ktime_info结构zero以及tinfo + + tinfo = (struct ktime_info *)bpf_map_lookup_or_try_init( + ×tamps, &pkt_tuple, &zero); + if (tinfo == NULL) { // 初始化失败 + // bpf_printk("v4 rx tinfo init fail.\n"); + return 0; + } + // 成功则获取当前内核时间并转换成毫秒 + tinfo->mac_time = bpf_ktime_get_ns() / 1000; + // bpf_printk("v4 rx init.\n"); + } else if (protocol == __bpf_htons(ETH_P_IPV6)) { // Protocol is IPV6 + struct ipv6hdr *ip6h = + (struct ipv6hdr *)(BPF_CORE_READ(skb, data) + 14); + struct tcphdr *tcp = (struct tcphdr *)(BPF_CORE_READ(skb, data) + + sizeof(struct ipv6hdr) + 14); + struct packet_tuple pkt_tuple = {0}; + get_pkt_tuple_v6(&pkt_tuple, ip6h, tcp); + + struct ktime_info *tinfo, zero = {0}; + + tinfo = (struct ktime_info *)bpf_map_lookup_or_try_init( + ×tamps, &pkt_tuple, &zero); + if (tinfo == NULL) { + // bpf_printk("v6 rx tinfo init fail.\n"); + return 0; + } + tinfo->mac_time = bpf_ktime_get_ns() / 1000; + // bpf_printk("v6 rx init.\n"); + } + return 0; +} + +static __always_inline int __ip_rcv_core(struct sk_buff *skb) { + if (!layer_time) { + return 0; + } + if (skb == NULL) + return 0; + struct iphdr *ip = skb_to_iphdr(skb); // 通过skb获取ipv4包头信息 + struct tcphdr *tcp = skb_to_tcphdr(skb); // 获取tcp包头信息 + struct packet_tuple pkt_tuple = { + 0}; // 定义一个packet_tuple结构体变量pkt_tuple并初始化 + get_pkt_tuple(&pkt_tuple, ip, tcp); + struct ktime_info *tinfo; + tinfo = bpf_map_lookup_elem( + ×tamps, &pkt_tuple); // 在timestamps映射中查找元素pkt_tuple + if (tinfo == NULL) { + return 0; + } + tinfo->ip_time = bpf_ktime_get_ns() / 1000; + // bpf_printk("rx enter ipv4 layer.\n"); + return 0; +} + +static __always_inline int __ip6_rcv_core(struct sk_buff *skb) { + if (!layer_time) { + return 0; + } + if (skb == NULL) + return 0; + struct ipv6hdr *ip6h = skb_to_ipv6hdr(skb); + struct tcphdr *tcp = skb_to_tcphdr(skb); + struct packet_tuple pkt_tuple = {0}; + get_pkt_tuple_v6(&pkt_tuple, ip6h, tcp); + + struct ktime_info *tinfo; + tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple); + if (tinfo == NULL) { + return 0; + } + + tinfo->ip_time = bpf_ktime_get_ns() / 1000; + // bpf_printk("rx enter ipv6 layer.\n"); + return 0; +} +static __always_inline int __tcp_v4_rcv(struct sk_buff *skb) { + if (!layer_time) { + return 0; + } + if (skb == NULL) + return 0; + struct iphdr *ip = skb_to_iphdr(skb); + struct tcphdr *tcp = skb_to_tcphdr(skb); + struct packet_tuple pkt_tuple = {0}; + get_pkt_tuple(&pkt_tuple, ip, tcp); + struct ktime_info *tinfo; + tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple); + if (tinfo == NULL) { + return 0; + } + tinfo->tran_time = bpf_ktime_get_ns() / 1000; + // bpf_printk("rx enter tcp4 layer.\n"); + return 0; +} +static __always_inline int __tcp_v6_rcv(struct sk_buff *skb) { + if (!layer_time) { + return 0; + } + if (skb == NULL) + return 0; + struct ipv6hdr *ip6h = skb_to_ipv6hdr(skb); + struct tcphdr *tcp = skb_to_tcphdr(skb); + struct packet_tuple pkt_tuple = {0}; + get_pkt_tuple_v6(&pkt_tuple, ip6h, tcp); + + struct ktime_info *tinfo; + tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple); + if (tinfo == NULL) { + return 0; + } + tinfo->tran_time = bpf_ktime_get_ns() / 1000; + // bpf_printk("rx enter tcp6 layer.\n"); + return 0; +} +static __always_inline int __tcp_v4_do_rcv(struct sock *sk, + struct sk_buff *skb) { + if (sk == NULL || skb == NULL) + return 0; + struct conn_t *conn = bpf_map_lookup_elem(&conns_info, &sk); + if (conn == NULL) { + // bpf_printk("get a v4 rx pack but conn not record, its sock is: + // %p",sk); + return 0; + } + struct iphdr *ip = skb_to_iphdr(skb); + struct tcphdr *tcp = skb_to_tcphdr(skb); + struct packet_tuple pkt_tuple = {0}; + get_pkt_tuple(&pkt_tuple, ip, tcp); + + struct ktime_info *tinfo; + tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple); + if (tinfo == NULL) { + return 0; + } + + CONN_INFO_TRANSFER + + // bpf_printk("rx enter tcp4_do_rcv, sk: %p \n", sk); + + CONN_ADD_EXTRA_INFO + + return 0; +} +static __always_inline int __tcp_v6_do_rcv(struct sock *sk, + struct sk_buff *skb) { + if (sk == NULL || skb == NULL) + return 0; + // bpf_printk("rx enter tcp6_do_rcv. \n"); + struct conn_t *conn = bpf_map_lookup_elem(&conns_info, &sk); + if (conn == NULL) { + // bpf_printk("get a v6 rx pack but conn not record, its sock is: %p", + // sk); + return 0; + } + + struct ipv6hdr *ip6h = skb_to_ipv6hdr(skb); + struct tcphdr *tcp = skb_to_tcphdr(skb); + struct packet_tuple pkt_tuple = {0}; + get_pkt_tuple_v6(&pkt_tuple, ip6h, tcp); // 使用ip和tcp信息填充pkt_tuple + + struct ktime_info *tinfo; + tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple); + if (tinfo == NULL) { + return 0; + } + + CONN_INFO_TRANSFER + + // bpf_printk("rx enter tcp6_do_rcv, sk: %p \n", sk); + + CONN_ADD_EXTRA_INFO + + return 0; +} +static __always_inline int __skb_copy_datagram_iter(struct sk_buff *skb) { + if (skb == NULL) + return 0; + __be16 protocol = BPF_CORE_READ(skb, protocol); // 读取skb协议字段 + struct tcphdr *tcp = skb_to_tcphdr(skb); + struct packet_tuple pkt_tuple = {0}; + struct ktime_info *tinfo; + if (protocol == __bpf_htons(ETH_P_IP)) { /** ipv4 */ + + struct iphdr *ip = skb_to_iphdr(skb); + get_pkt_tuple(&pkt_tuple, ip, tcp); + tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple); + if (tinfo == NULL) { + return 0; + } + + tinfo->app_time = bpf_ktime_get_ns() / 1000; + } else if (protocol == __bpf_ntohs(ETH_P_IPV6)) { + /** ipv6 */ + struct ipv6hdr *ip6h = skb_to_ipv6hdr(skb); + get_pkt_tuple_v6(&pkt_tuple, ip6h, tcp); + + if ((tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple)) == NULL) { + return 0; + } + tinfo->app_time = bpf_ktime_get_ns() / 1000; + } else { + return 0; + } + /*----- record packet time info ------*/ + + if (tinfo == NULL) { + return 0; + } + struct sock *sk = tinfo->sk; + if (sk == NULL) { + return 0; + } + // bpf_printk("rx enter app layer.\n"); + + PACKET_INIT_WITH_COMMON_INFO + packet->saddr = pkt_tuple.saddr; + packet->daddr = pkt_tuple.daddr; + packet->sport = pkt_tuple.sport; + packet->dport = pkt_tuple.dport; + + if (layer_time) { + packet->mac_time = tinfo->ip_time - tinfo->mac_time; + // 计算MAC层和ip层之间的时间差 + packet->ip_time = tinfo->tran_time - tinfo->ip_time; + // 计算ip层和tcp层之间的时间差 + packet->tran_time = tinfo->app_time - tinfo->tran_time; + // 计算tcp层和应用层之间的时间差 + } + packet->rx = 1; // 数据包已经被接收 + + // RX HTTP INFO + if (http_info) { + int doff = + BPF_CORE_READ_BITFIELD_PROBED(tcp, doff); // 得用bitfield_probed + // 读取tcp头部中的数据偏移字段 + u8 *user_data = (u8 *)((u8 *)tcp + (doff * 4)); + // 计算tcp的负载开始位置就是tcp头部之后的数据,将tcp指针指向tcp头部位置将其转换成unsigned + // char类型 + // doff * + // 4数据偏移值(tcp的头部长度20个字节)乘以4计算tcp头部实际字节长度,32位为单位就是4字节 + bpf_probe_read_str(packet->data, sizeof(packet->data), + user_data); // 将tcp负载数据读取到packet->data + } + bpf_ringbuf_submit(packet, 0); // 将packet提交到缓冲区 + return 0; +} +/* +out_ipv4: + kprobe/tcp_sendmsg + kprobe/ip_queue_xmit + kprobe/dev_queue_xmit + kprobe/dev_hard_start_xmit + +out_ipv6: + kprobe/tcp_sendmsg + kprobe/inet6_csk_xmit + kprobe/dev_queue_xmit + kprobe/dev_hard_start_xmit +*/ +static __always_inline int __tcp_sendmsg(struct sock *sk, struct msghdr *msg, + size_t size) { + struct conn_t *conn = bpf_map_lookup_elem(&conns_info, &sk); + if (conn == NULL) { + return 0; + } + + u16 family = BPF_CORE_READ(sk, __sk_common.skc_family); + struct ktime_info *tinfo, zero = {0}; // 存储时间 + struct packet_tuple pkt_tuple = {0}; // 存储数据包信息 + /** ipv4 */ + if (family == AF_INET) { + u16 dport = BPF_CORE_READ(sk, __sk_common.skc_dport); + pkt_tuple.saddr = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr); // 源ip + pkt_tuple.daddr = BPF_CORE_READ(sk, __sk_common.skc_daddr); // 目的ip + pkt_tuple.sport = BPF_CORE_READ(sk, __sk_common.skc_num); // 源端口 + pkt_tuple.dport = __bpf_ntohs(dport); // 目的端口并进行字节序转换 + + u32 snd_nxt = + BPF_CORE_READ(tcp_sk(sk), snd_nxt); // tcp要发送的下一个字节序列号 + u32 rcv_nxt = BPF_CORE_READ(tcp_sk(sk), + rcv_nxt); // tcp接收的下一个字节的期望序列号 + pkt_tuple.seq = snd_nxt; + pkt_tuple.ack = rcv_nxt; + pkt_tuple.tran_flag = TCP; + tinfo = (struct ktime_info *)bpf_map_lookup_or_try_init( + ×tamps, &pkt_tuple, + &zero); // timestamps的BPF map保存数据包与时间戳的映射 + if (tinfo == NULL) { + return 0; + } + tinfo->tran_time = bpf_ktime_get_ns() / 1000; + } else if (family == AF_INET6) { + // 读取ipv6源地址 + bpf_probe_read_kernel( + &pkt_tuple.saddr_v6, + sizeof(sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32), + &sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32); + // 获取ipv6目的地址 + bpf_probe_read_kernel( + &pkt_tuple.daddr_v6, + sizeof(sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32), + &sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32); + // sk套接字中获取源端口号 + pkt_tuple.sport = BPF_CORE_READ(sk, __sk_common.skc_num); + // 获取目的端口 + u16 dport = BPF_CORE_READ(sk, __sk_common.skc_dport); + pkt_tuple.dport = __bpf_ntohs(dport); + + u32 snd_nxt = + BPF_CORE_READ(tcp_sk(sk), snd_nxt); // 发送的下一个字节序列号 + u32 rcv_nxt = + BPF_CORE_READ(tcp_sk(sk), rcv_nxt); // 期望接收的下一个字节序列号 + pkt_tuple.seq = snd_nxt; + pkt_tuple.ack = rcv_nxt; + pkt_tuple.tran_flag = TCP; + + tinfo = (struct ktime_info *)bpf_map_lookup_or_try_init( + ×tamps, &pkt_tuple, &zero); + if (tinfo == NULL) { + return 0; + } + tinfo->tran_time = bpf_ktime_get_ns() / 1000; + } + + CONN_INFO_TRANSFER + + CONN_ADD_EXTRA_INFO + + // TX HTTP info + if (http_info) { + u8 *user_data = GET_USER_DATA(msg); + tinfo = (struct ktime_info *)bpf_map_lookup_or_try_init( + ×tamps, &pkt_tuple, &zero); + if (tinfo == NULL) { + return 0; + } + bpf_probe_read_str(tinfo->data, sizeof(tinfo->data), user_data); + } + return 0; +} +static __always_inline int __ip_queue_xmit(struct sock *sk, + struct sk_buff *skb) { + if (!layer_time) { + return 0; + } + u16 family = BPF_CORE_READ(sk, __sk_common.skc_family); + struct packet_tuple pkt_tuple = {0}; + struct ktime_info *tinfo; + struct tcphdr *tcp = skb_to_tcphdr(skb); + if (family == AF_INET) { + u16 dport; + u32 seq, ack; + pkt_tuple.saddr = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr); + pkt_tuple.daddr = BPF_CORE_READ(sk, __sk_common.skc_daddr); + pkt_tuple.sport = BPF_CORE_READ(sk, __sk_common.skc_num); + dport = BPF_CORE_READ(sk, __sk_common.skc_dport); + pkt_tuple.dport = __bpf_ntohs(dport); + seq = BPF_CORE_READ(tcp, seq); + ack = BPF_CORE_READ(tcp, ack_seq); + pkt_tuple.seq = __bpf_ntohl(seq); + pkt_tuple.ack = __bpf_ntohl(ack); + pkt_tuple.tran_flag = TCP; + if ((tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple)) == NULL) { + return 0; + } + tinfo->ip_time = bpf_ktime_get_ns() / 1000; + } + + return 0; +} +static __always_inline int __inet6_csk_xmit(struct sock *sk, + struct sk_buff *skb) { + if (!layer_time) { + return 0; + } + u16 family = BPF_CORE_READ(sk, __sk_common.skc_family); + struct tcphdr *tcp = skb_to_tcphdr(skb); + struct packet_tuple pkt_tuple = {0}; + struct ktime_info *tinfo; + if (family == AF_INET6) { + u16 dport; + u32 seq, ack; + + bpf_probe_read_kernel( + &pkt_tuple.saddr_v6, + sizeof(sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32), + &sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32); + + bpf_probe_read_kernel( + &pkt_tuple.daddr_v6, + sizeof(sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32), + &sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32); + + pkt_tuple.sport = BPF_CORE_READ(sk, __sk_common.skc_num); + dport = BPF_CORE_READ(sk, __sk_common.skc_dport); + pkt_tuple.dport = __bpf_ntohs(dport); + seq = BPF_CORE_READ(tcp, seq); + ack = BPF_CORE_READ(tcp, ack_seq); + pkt_tuple.seq = __bpf_ntohl(seq); + pkt_tuple.ack = __bpf_ntohl(ack); + pkt_tuple.tran_flag = TCP; + if ((tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple)) == NULL) { + return 0; + } + tinfo->ip_time = bpf_ktime_get_ns() / 1000; + } + return 0; +} +static __always_inline int dev_queue_xmit(struct sk_buff *skb) { + if (!layer_time) { + return 0; + } + // 从skb中读取以太网头部 + const struct ethhdr *eth = (struct ethhdr *)BPF_CORE_READ(skb, data); + u16 protocol = BPF_CORE_READ( + eth, + h_proto); // 以太网头部协议字段该字段存储的是以太网帧所封装的上层协议类型 + struct tcphdr *tcp = skb_to_tcphdr(skb); + struct packet_tuple pkt_tuple = {0}; + struct ktime_info *tinfo; + if (protocol == __bpf_ntohs(ETH_P_IP)) { + /** ipv4 */ + struct iphdr *ip = skb_to_iphdr(skb); + get_pkt_tuple(&pkt_tuple, ip, tcp); + + if ((tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple)) == NULL) { + return 0; + } + tinfo->mac_time = bpf_ktime_get_ns() / 1000; + } else if (protocol == __bpf_ntohs(ETH_P_IPV6)) { + /** ipv6 */ + struct ipv6hdr *ip6h = skb_to_ipv6hdr(skb); + get_pkt_tuple_v6(&pkt_tuple, ip6h, tcp); + + if ((tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple)) == NULL) { + return 0; + } + tinfo->mac_time = bpf_ktime_get_ns() / 1000; + } + return 0; +} +static __always_inline int __dev_hard_start_xmit(struct sk_buff *skb) { + const struct ethhdr *eth = (struct ethhdr *)BPF_CORE_READ(skb, data); + u16 protocol = BPF_CORE_READ(eth, h_proto); + struct tcphdr *tcp = skb_to_tcphdr(skb); + struct packet_tuple pkt_tuple = {0}; + struct ktime_info *tinfo; + if (protocol == __bpf_ntohs(ETH_P_IP)) { + /** ipv4 */ + struct iphdr *ip = skb_to_iphdr(skb); + get_pkt_tuple(&pkt_tuple, ip, tcp); + + if ((tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple)) == NULL) { + return 0; + } + // 数据包在队列中等待的时间 + tinfo->qdisc_time = bpf_ktime_get_ns() / 1000; + } else if (protocol == __bpf_ntohs(ETH_P_IPV6)) { + /** ipv6 */ + struct ipv6hdr *ip6h = skb_to_ipv6hdr(skb); + get_pkt_tuple_v6(&pkt_tuple, ip6h, tcp); + + if ((tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple)) == NULL) { + return 0; + } + tinfo->qdisc_time = bpf_ktime_get_ns() / 1000; + } else { + return 0; + } + + /*----- record packet time info ------*/ + if (tinfo == NULL) { + return 0; + } + struct sock *sk = tinfo->sk; + if (!sk) { + return 0; + } + PACKET_INIT_WITH_COMMON_INFO + packet->saddr = pkt_tuple.saddr; + packet->daddr = pkt_tuple.daddr; + packet->sport = pkt_tuple.sport; + packet->dport = pkt_tuple.dport; + // 记录各层的时间差值 + if (layer_time) { + packet->tran_time = tinfo->ip_time - tinfo->tran_time; + packet->ip_time = tinfo->mac_time - tinfo->ip_time; + packet->mac_time = + tinfo->qdisc_time - + tinfo + ->mac_time; // 队列纪律层,处于网络协议栈最底层,负责实际数据传输与接收 + } + packet->rx = 0; // 发送一个数据包 + + // TX HTTP Info + if (http_info) { + bpf_probe_read_str(packet->data, sizeof(packet->data), tinfo->data); + // bpf_printk("%s", packet->data); + } + bpf_ringbuf_submit(packet, 0); + + return 0; +} diff --git a/MagicEyes/src/backend/net/net_watcher/bpf/redis.bpf.h b/MagicEyes/src/backend/net/net_watcher/bpf/redis.bpf.h new file mode 100644 index 000000000..dc0aa533e --- /dev/null +++ b/MagicEyes/src/backend/net/net_watcher/bpf/redis.bpf.h @@ -0,0 +1,167 @@ +// Copyright 2023 The LMP Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://github.com/linuxkerneltravel/lmp/blob/develop/LICENSE +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: blown.away@qq.com +// redis + +#include "common.bpf.h" +#include "redis_helper.bpf.h" +#define MAXEPOLL 5 +static __always_inline int __handle_redis_start(struct pt_regs *ctx) { + if(!redis_info) return 0; + struct client *cli = (struct client *)PT_REGS_PARM1(ctx); + struct redis_query start={}; + void *ptr; + char name[100]=""; + int argv_len; + bpf_probe_read(&start.argc, sizeof(start.argc), &cli->argc); + robj **arg0; + robj *arg1; + bpf_probe_read(&arg0, sizeof(arg0), &cli->argv); + bpf_probe_read(&arg1, sizeof(arg1), &arg0[0]); + for(int i=0;iptr); + bpf_probe_read_str(&start.redis[i], sizeof(start.redis[i]), ptr); + } + pid_t pid = bpf_get_current_pid_tgid() >> 32; + u64 start_time = bpf_ktime_get_ns() / 1000; + start.begin_time=start_time; + bpf_map_update_elem(&redis_time, &pid, &start, BPF_ANY); + return 0; +} + +static __always_inline int __handle_redis_end(struct pt_regs *ctx) { + if(!redis_info) return 0; + pid_t pid = bpf_get_current_pid_tgid() >> 32; + struct redis_query *start; + u64 end_time = bpf_ktime_get_ns() / 1000; + start = bpf_map_lookup_elem(&redis_time, &pid); + if (!start) { + return 0; + } + struct redis_query *message = bpf_ringbuf_reserve(&redis_rb, sizeof(*message), 0); + if (!message) { + return 0; + } + message->pid = pid; + message->argc = start->argc; + bpf_get_current_comm(&message->comm, sizeof(message->comm)); + for(int i=0;iargc&&iredis[i], sizeof(message->redis[i]), start->redis[i]); + } + bpf_probe_read_str(&message->redis, sizeof(start->redis), start->redis); + message->duratime = end_time - start->begin_time; + bpf_ringbuf_submit(message, 0); + return 0; +} +static __always_inline int __handle_redis_key(struct pt_regs *ctx) { + if(!redis_stat) return 0; + robj *key_obj = (robj *)PT_REGS_PARM2(ctx); + char redis_key[256]; + u32 *count; + u32 initial_count = 1; + + if (!key_obj) + return 0; + + robj local_key_obj; + if (bpf_probe_read_user(&local_key_obj, sizeof(local_key_obj), key_obj) != 0) { + bpf_printk("Failed to read local_key_obj\n"); + return 0; + } + + if (!local_key_obj.ptr) { + bpf_printk("local_key_obj.ptr is null\n"); + return 0; + } + + int ret; + ret = bpf_probe_read_user_str(redis_key, sizeof(redis_key), local_key_obj.ptr); + if (ret <= 0) { + bpf_printk("Read string failed: %d\n", ret); + return 0; + } + + // 打印读取到的键值 + bpf_printk("Read key: %s\n", redis_key); + + // 查找或更新键的计数 + count = bpf_map_lookup_elem(&key_count, redis_key); + if (count) { + //bpf_printk("Found key, incrementing count\n"); + // 如果已经存在,增加计数值 + (*count)++; + bpf_map_update_elem(&key_count, redis_key, count, BPF_ANY); + } else { + //bpf_printk("Key not found, initializing count\n"); + // 如果不存在,初始化计数值为 1 + bpf_map_update_elem(&key_count, redis_key, &initial_count, BPF_ANY); + } + + // 打印调试信息 + struct redis_stat_query *message = bpf_ringbuf_reserve(&redis_stat_rb, sizeof(*message), 0); + if (!message) { + return 0; + } + message->pid=bpf_get_current_pid_tgid() >> 32; + bpf_get_current_comm(&message->comm, sizeof(message->comm)); + memcpy(message->key, redis_key, sizeof(message->key)); + message->key_count=count ? *count : initial_count; + message->value_type=0; + memset(message->value, 0, sizeof(message->value)); + bpf_printk("Key: %s\n", message->key); + bpf_printk("Count: %d\n", message->key_count); + bpf_ringbuf_submit(message, 0); + + return 0; +} +static __always_inline int __handle_redis_value(struct pt_regs *ctx) { + if(!redis_stat) return 0; + robj *key_obj = (robj *)PT_REGS_PARM2(ctx); + int ret; + char redis_value[64]; + if (!key_obj) + return 0; + robj local_key_obj; + if (bpf_probe_read_user(&local_key_obj, sizeof(local_key_obj), key_obj) != 0) { + bpf_printk("Failed to read local_key_obj\n"); + return 0; + } + if (!local_key_obj.ptr) { + bpf_printk("local_key_obj.ptr is null\n"); + return 0; + } + ret = bpf_probe_read_user_str(redis_value, sizeof(redis_value), local_key_obj.ptr); + if (ret <= 0) { + bpf_printk("Read string failed: %d\n", ret); + return 0; + } + struct redis_stat_query *message = bpf_ringbuf_reserve(&redis_stat_rb, sizeof(*message), 0); + if (!message) { + return 0; + } + message->pid=bpf_get_current_pid_tgid() >> 32; + bpf_get_current_comm(&message->comm, sizeof(message->comm)); + memset(message->key, 0, sizeof(message->key)); + message->key_count=0; + message->value_type=local_key_obj.type; + memcpy(message->value, redis_value, sizeof(message->value)); + bpf_printk("Value: %s\n", message->value); + bpf_printk("type: %d\n", message->value_type); + bpf_ringbuf_submit(message, 0); + return 0; +} \ No newline at end of file diff --git a/MagicEyes/src/backend/net/net_watcher/bpf/redis_helper.bpf.h b/MagicEyes/src/backend/net/net_watcher/bpf/redis_helper.bpf.h new file mode 100644 index 000000000..322fa66f4 --- /dev/null +++ b/MagicEyes/src/backend/net/net_watcher/bpf/redis_helper.bpf.h @@ -0,0 +1,55 @@ +// Copyright 2023 The LMP Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://github.com/linuxkerneltravel/lmp/blob/develop/LICENSE +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: blown.away@qq.com +// +// net_watcher libbpf 内核<->用户 传递信息相关结构体 + +#ifndef __REDIS_HELPER_BPF_H +#define __REDIS_HELPER_BPF_H + +#include "../include/net_watcher.h" +#include "vmlinux.h" +#include +#include +#include +#include +#include +#include + +#define LRU_BITS 24 +typedef struct redisObject { + unsigned type:4; + unsigned encoding:4; + unsigned lru:24; + int refcount; + void *ptr; +} robj; + +struct client { + u64 id; /* Client incremental unique ID. */ + u64 conn; + int resp; /* RESP protocol version. Can be 2 or 3. */ + u64 db; /* Pointer to currently SELECTed DB. */ + robj *name; /* As set by CLIENT SETNAME. */ + char* querybuf; /* Buffer we use to accumulate client queries. */ + unsigned long qb_pos; /* The position we have read in querybuf. */ + char* pending_querybuf; + unsigned long querybuf_peak; /* Recent (100ms or more) peak of querybuf size. */ + int argc; /* Num of arguments of current command. */ + robj **argv; /* Arguments of current command. */ + unsigned long argv_len_sum; /* Size of argv array (may be more than argc) */ +}; + +#endif diff --git a/MagicEyes/src/backend/net/net_watcher/bpf/tcp.bpf.h b/MagicEyes/src/backend/net/net_watcher/bpf/tcp.bpf.h new file mode 100644 index 000000000..abcc05698 --- /dev/null +++ b/MagicEyes/src/backend/net/net_watcher/bpf/tcp.bpf.h @@ -0,0 +1,444 @@ +// Copyright 2023 The LMP Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://github.com/linuxkerneltravel/lmp/blob/develop/LICENSE +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: blown.away@qq.com +// netwatcher libbpf tcp + +#include "common.bpf.h" + +static __always_inline int __inet_csk_accept(struct sock *sk) { + if (sk == NULL) { // newsk is null + // bpf_printk("inet_accept_ret err: newsk is null\n"); + return 0; + } + u64 ptid = bpf_get_current_pid_tgid(); // 获取当前进程pid + + CONN_INIT // 初始化conn_t结构中基本信息 + conn.is_server = 1; + + FILTER_DPORT // 过滤目标端口 + + FILTER_SPORT // 过滤源端口 + + CONN_ADD_ADDRESS // conn_t结构中增加地址信息 + + // 更新/插入conns_info中的键值对 + int err = bpf_map_update_elem(&conns_info, &sk, &conn, BPF_ANY); + if (err) { // 更新错误 + // bpf_printk("inet_accept update err.\n"); + return 0; + } + + return 0; +} + +static __always_inline int __tcp_v4_connect(const struct sock *sk) { + u64 ptid = bpf_get_current_pid_tgid(); // 获取当前pid + int err = bpf_map_update_elem(&sock_stores, &ptid, &sk, BPF_ANY); + // 更新/插入sock_stores中的键值对 + if (err) { + // bpf_printk("tcp_v4_connect update sock_stores err.\n"); + return 0; + } + return 0; +} + +static __always_inline int __tcp_v4_connect_exit(int ret) { + u64 ptid = bpf_get_current_pid_tgid(); // 获取当前pid + struct sock **skp = bpf_map_lookup_elem(&sock_stores, &ptid); + // 获得sock_stores中ptid对应的*sk 用skp指向 + if (skp == NULL) { + return 0; + } + // bpf_printk("tcp_v4_connect_exit\n"); + if (ret != 0) { // 连接失败 + // bpf_printk("tcp_v4_connect_exit but ret %d\n", ret); + bpf_map_delete_elem(&sock_stores, &ptid); // 删除对应键值对 + return 0; + } + struct sock *sk = *skp; + CONN_INIT // 初始化conn_t结构中基本信息 + conn.is_server = 0; // 主动连接 + + FILTER_DPORT // 过滤目标端口 + + FILTER_SPORT // 过滤源端口 + + CONN_ADD_ADDRESS // conn_t结构中增加地址信息 + + long err = bpf_map_update_elem(&conns_info, &sk, &conn, BPF_ANY); + // 更新conns_info中sk对应的conn + if (err) { + return 0; + } + return 0; +} + +static __always_inline int __tcp_v6_connect(const struct sock *sk) { + u64 pid = bpf_get_current_pid_tgid(); // 获取pid + int err = bpf_map_update_elem(&sock_stores, &pid, &sk, BPF_ANY); + // 更新sock_stores中对应pid对应的sk + if (err) { + return 0; + } + return 0; +} + +static __always_inline int __tcp_v6_connect_exit(int ret) { + u64 ptid = bpf_get_current_pid_tgid(); // 获取pid + struct sock **skp = bpf_map_lookup_elem(&sock_stores, &ptid); + // 获得sock_stores中ptid对应的*sk 用skp指向 + if (skp == NULL) { + return 0; + } + if (ret != 0) { // 错误 + bpf_map_delete_elem(&sock_stores, &ptid); // 删除对应键值对 + return 0; + } + struct sock *sk = *skp; + + CONN_INIT // 初始化conn_t结构中基本信息 + conn.is_server = 0; // 主动连接 + + FILTER_DPORT // 过滤目标端口 + + FILTER_SPORT // 过滤源端口 + + CONN_ADD_ADDRESS // conn_t结构中增加地址信息 + + long err = bpf_map_update_elem(&conns_info, &sk, &conn, BPF_ANY); + // 更新conns_info中sk对应的conn + if (err) { + return 0; + } + // bpf_printk("tcp_v4_connect_exit update sk: %p.\n", sk); + return 0; +} +static __always_inline int __tcp_set_state(struct sock *sk, int state) { + if (all_conn) { + return 0; + } + struct conn_t *value = bpf_map_lookup_elem(&conns_info, &sk); + // 查找sk对应的conn_t + if (state == TCP_CLOSE && value != NULL) { // TCP_CLOSE置1 说明关闭连接 + // delete + bpf_map_delete_elem(&sock_stores, &value->ptid); // 删除sock_stores + bpf_map_delete_elem(&conns_info, &sk); // 删除conns_info + } + return 0; +} + +// receive error packet +static __always_inline int __tcp_validate_incoming(struct sock *sk, + struct sk_buff *skb) { + if (!err_packet) { + return 0; + } + if (sk == NULL || skb == NULL) + return 0; + struct conn_t *conn = + bpf_map_lookup_elem(&conns_info, &sk); // BPFmap查找与套接字sk关联的信息 + if (conn == NULL) { + return 0; + } + struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); // 数据包信息 + u32 start_seq = BPF_CORE_READ(tcb, seq); // 开始序列号 + u32 end_seq = BPF_CORE_READ(tcb, end_seq); // 结束序列号 + struct tcp_sock *tp = tcp_sk(sk); // 套接字信息 + u32 rcv_wup = BPF_CORE_READ( + tp, rcv_wup); // 接收方已经确认并准备接收的数据最后一个字节的序列号 + u32 rcv_nxt = + BPF_CORE_READ(tp, rcv_nxt); // 期望发送发下次发送的数据字节序列号 + u32 rcv_wnd = BPF_CORE_READ(tp, rcv_wnd); // tcp接收窗口大小 + u32 receive_window = rcv_wup + rcv_nxt - rcv_wnd; // 当前可用的接收窗口 + receive_window = 0; + + if (end_seq >= rcv_wup && rcv_nxt + receive_window >= start_seq) { + // bpf_printk("error_identify: tcp seq validated. \n"); + return 0; + // 检查数据包序列号是否在接收窗口内 + } + // bpf_printk("error_identify: tcp seq err. \n"); + // invalid seq + u16 family = BPF_CORE_READ( + sk, __sk_common.skc_family); // 获取套接字的地址族就是获得当前ip协议 + struct packet_tuple pkt_tuple = {0}; + if (family == AF_INET) { + struct iphdr *ip = skb_to_iphdr(skb); + struct tcphdr *tcp = skb_to_tcphdr(skb); + get_pkt_tuple(&pkt_tuple, ip, tcp); + } else if (family == AF_INET6) { + struct ipv6hdr *ip6h = skb_to_ipv6hdr(skb); + struct tcphdr *tcp = skb_to_tcphdr(skb); + get_pkt_tuple_v6(&pkt_tuple, ip6h, tcp); + } else { + return 0; + } + struct pack_t *packet; + packet = bpf_ringbuf_reserve(&rb, sizeof(*packet), 0); + if (!packet) { + return 0; + } + packet->err = 1; // 错误标记此数据包有问题 + packet->sock = sk; + packet->ack = pkt_tuple.ack; + packet->seq = pkt_tuple.seq; + bpf_ringbuf_submit(packet, 0); + return 0; +} +static __always_inline int skb_checksum_complete(int ret) { + if (!err_packet) { + return 0; + } + u64 pid = bpf_get_current_pid_tgid(); + struct sock **skp = bpf_map_lookup_elem(&sock_stores, &pid); + if (skp == NULL) { + return 0; + } + if (ret == 0) { + // bpf_printk("error_identify: tcp checksum validated. \n"); + return 0; + } + // bpf_printk("error_identify: tcp checksum error. \n"); + struct sock *sk = *skp; + struct conn_t *conn = bpf_map_lookup_elem(&conns_info, &sk); + if (conn == NULL) { + return 0; + } + struct pack_t *packet; + packet = bpf_ringbuf_reserve(&rb, sizeof(*packet), 0); + if (!packet) { + return 0; + } + packet->err = 2; // 校验和错误 + packet->sock = sk; // 存储socket信息到sock字段中 + bpf_ringbuf_submit(packet, 0); + + return 0; +} +////retrans packet +static __always_inline int __tcp_enter_recovery(struct sock *sk) { + if (!retrans_info) { + return 0; + } + struct conn_t *conn = bpf_map_lookup_elem(&conns_info, &sk); + if (conn == NULL) { + // bpf_printk("get a v4 rx pack but conn not record, its sock is: %p", + // sk); + return 0; + } + conn->fastRe += 1; // 统计进入tcp恢复状态的次数 + + return 0; +} +static __always_inline int __tcp_enter_loss(struct sock *sk) { + if (!retrans_info) { + return 0; + } + struct conn_t *conn = bpf_map_lookup_elem(&conns_info, &sk); + if (conn == NULL) { + return 0; + } + conn->timeout += 1; + return 0; +} +static __always_inline int +__handle_set_state(struct trace_event_raw_inet_sock_set_state *ctx) { + if (ctx->protocol != IPPROTO_TCP) + return 0; + + struct sock *sk = (struct sock *)ctx->skaddr; + __u64 *before_time, new_time, time; + + before_time = bpf_map_lookup_elem(&tcp_state, &sk); + new_time = bpf_ktime_get_ns(); + if (!before_time) + time = 0; + else + time = (new_time - *before_time) / 1000; + struct tcpstate tcpstate = {}; + tcpstate.oldstate = ctx->oldstate; + tcpstate.newstate = ctx->newstate; + tcpstate.family = ctx->family; + tcpstate.sport = ctx->sport; + tcpstate.dport = ctx->dport; + bpf_probe_read_kernel(&tcpstate.saddr, sizeof(tcpstate.saddr), + &sk->__sk_common.skc_rcv_saddr); + bpf_probe_read_kernel(&tcpstate.daddr, sizeof(tcpstate.daddr), + &sk->__sk_common.skc_daddr); + tcpstate.time = time; + if (ctx->newstate == TCP_CLOSE) + bpf_map_delete_elem(&tcp_state, &sk); + else + bpf_map_update_elem(&tcp_state, &sk, &new_time, BPF_ANY); + + struct tcp_state *message; + message = bpf_ringbuf_reserve(&tcp_rb, sizeof(*message), 0); + if (!message) { + return 0; + } + message->saddr = tcpstate.saddr; + message->daddr = tcpstate.daddr; + message->sport = tcpstate.sport; + message->dport = tcpstate.dport; + message->oldstate = tcpstate.oldstate; + message->newstate = tcpstate.newstate; + message->time = tcpstate.time; + bpf_printk("Dport:%d time:%d", tcpstate.dport, tcpstate.time); + bpf_ringbuf_submit(message, 0); + return 0; +} + +static __always_inline int __tcp_rcv_established(struct sock *sk, + struct sk_buff *skb) { + const struct inet_sock *inet = (struct inet_sock *)(sk); + struct tcp_sock *ts; + struct hist *histp; + u64 slot; + u32 srtt; + struct iphdr *ip = skb_to_iphdr(skb); + struct tcphdr *tcp = skb_to_tcphdr(skb); + struct packet_tuple pkt_tuple = {0}; + get_pkt_tuple(&pkt_tuple, ip, tcp); + // INIT_PACKET_TCP_TUPLE(sk, pkt_tuple); + struct ip_packet key = {.saddr = pkt_tuple.saddr, .daddr = pkt_tuple.daddr}; + + histp = bpf_map_lookup_elem(&hists, &key); + if (!histp) { + // 初始化值 + struct hist zero = {}; + bpf_map_update_elem(&hists, &key, &zero, BPF_ANY); + histp = bpf_map_lookup_elem(&hists, &key); + if (!histp) + return 0; // 如果仍然查找失败,则返回 + } + ts = (struct tcp_sock *)(sk); + + // 读取并处理SRTT(平滑往返时间) + srtt = BPF_CORE_READ(ts, srtt_us) >> 3; + // 计算对数值,根据得到的结果决定数据应该归入直方图的哪个槽位 + slot = log2l(srtt); + if (slot >= MAX_SLOTS) + slot = MAX_SLOTS - 1; // 确保槽位置不超过最大槽数 + + // 更新 + __sync_fetch_and_add(&histp->slots[slot], 1); + __sync_fetch_and_add(&histp->latency, srtt); + __sync_fetch_and_add(&histp->cnt, 1); + + struct RTT *message; + message = bpf_ringbuf_reserve(&rtt_rb, sizeof(*message), 0); + if (!message) { + return 0; + } + message->saddr = pkt_tuple.saddr; + message->daddr = pkt_tuple.daddr; + // bpf_printk("Saddr:%u Daddr:%u", pkt_tuple.saddr, pkt_tuple.daddr); + bpf_probe_read_kernel(message->slots, sizeof(message->slots), histp->slots); + message->latency = histp->latency; + message->cnt = histp->cnt; + // bpf_printk("Updating histogram: latency %llu, cnt %llu, slot %llu, + // slot_count %llu", histp->latency, histp->cnt, slot, histp->slots[slot]); + bpf_ringbuf_submit(message, 0); + return 0; +} + +static __always_inline int ret(void *ctx, u8 direction, u16 sport, + u16 dport) { + struct reset_event_t *message = + bpf_ringbuf_reserve(&events, sizeof(*message), 0); + if (!message) + return 0; + + message->pid = bpf_get_current_pid_tgid() >> 32; + bpf_get_current_comm(&message->comm, sizeof(message->comm)); + + struct sock *sk = (struct sock *)ctx; + message->family = BPF_CORE_READ(sk, __sk_common.skc_family); + message->timestamp = bpf_ktime_get_ns(); + + if (message->family == AF_INET) { + if (direction == 0) { // Send + message->saddr = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr); + message->daddr = BPF_CORE_READ(sk, __sk_common.skc_daddr); + } else { // Receive + message->saddr = BPF_CORE_READ(sk, __sk_common.skc_daddr); + message->daddr = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr); + } + message->saddr_v6 = 0; + message->daddr_v6 = 0; + } else if (message->family == AF_INET6) { + if (direction == 0) { // Send + bpf_probe_read_kernel( + &message->saddr_v6, sizeof(message->saddr_v6), + &sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32); + bpf_probe_read_kernel( + &message->daddr_v6, sizeof(message->daddr_v6), + &sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32); + } else { // Receive + bpf_probe_read_kernel( + &message->saddr_v6, sizeof(message->saddr_v6), + &sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32); + bpf_probe_read_kernel( + &message->daddr_v6, sizeof(message->daddr_v6), + &sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32); + } + + message->saddr = 0; + message->daddr = 0; + } + + if (direction == 0) { // Send + message->sport = bpf_ntohs(sport); + message->dport = bpf_ntohs(dport); + } else { // Receive + message->sport = bpf_ntohs(dport); + message->dport = bpf_ntohs(sport); + } + message->direction = direction; + + // 增加 RST 计数 + u32 pid = message->pid; + u64 *count = bpf_map_lookup_elem(&counters, &pid); + if (count) { + *count += 1; + } else { + u64 initial_count = 1; + bpf_map_update_elem(&counters, &pid, &initial_count, BPF_ANY); + count = &initial_count; + } + message->count = *count; + + bpf_ringbuf_submit(message, 0); + + return 0; +} +static __always_inline int +__handle_send_reset(struct trace_event_raw_tcp_send_reset *ctx) { + struct sock *sk = (struct sock *)ctx->skaddr; + if (!sk) + return 0; + // bpf_printk("Send reset: sport=%u, dport=%u\n", ctx->sport, ctx->dport); + return ret((void *)ctx->skaddr, 0, ctx->sport, ctx->dport); +} + +static __always_inline int +__handle_receive_reset(struct trace_event_raw_tcp_receive_reset *ctx) { + struct sock *sk = (struct sock *)ctx->skaddr; + if (!sk) + return 0; + // bpf_printk("Receive reset: sport=%u, dport=%u\n", ctx->sport, + // ctx->dport); + return ret((void *)ctx->skaddr, 1, ctx->sport, ctx->dport); +} \ No newline at end of file diff --git a/MagicEyes/src/backend/net/net_watcher/bpf/udp.bpf.h b/MagicEyes/src/backend/net/net_watcher/bpf/udp.bpf.h new file mode 100644 index 000000000..0b38ebb40 --- /dev/null +++ b/MagicEyes/src/backend/net/net_watcher/bpf/udp.bpf.h @@ -0,0 +1,206 @@ +// Copyright 2023 The LMP Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://github.com/linuxkerneltravel/lmp/blob/develop/LICENSE +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: blown.away@qq.com + +#include "common.bpf.h" + +static __always_inline int __udp_rcv(struct sk_buff *skb) { + if (!udp_info || skb == NULL) + return 0; + struct iphdr *ip = skb_to_iphdr(skb); + struct udphdr *udp = skb_to_udphdr(skb); + struct packet_tuple pkt_tuple = {0}; + get_udp_pkt_tuple(&pkt_tuple, ip, udp); + FILTER + struct ktime_info *tinfo, zero = {0}; + tinfo = (struct ktime_info *)bpf_map_lookup_or_try_init(×tamps, + &pkt_tuple, &zero); + if (tinfo == NULL) { + return 0; + } + tinfo->tran_time = bpf_ktime_get_ns() / 1000; + return 0; +} +static __always_inline int udp_enqueue_schedule_skb(struct sock *sk, + struct sk_buff *skb) { + if (!udp_info || skb == NULL) + return 0; + struct iphdr *ip = skb_to_iphdr(skb); + struct udphdr *udp = skb_to_udphdr(skb); + struct packet_tuple pkt_tuple = {0}; + get_udp_pkt_tuple(&pkt_tuple, ip, udp); + FILTER + struct ktime_info *tinfo, zero = {0}; + tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple); + if (tinfo == NULL) { + return 0; + } + struct udp_message *message; + struct udp_message *udp_message = + bpf_map_lookup_elem(×tamps, &pkt_tuple); + message = bpf_ringbuf_reserve(&udp_rb, sizeof(*message), 0); + if (!message) { + return 0; + } + message->saddr = pkt_tuple.saddr; + message->daddr = pkt_tuple.daddr; + message->dport = pkt_tuple.dport; + message->sport = pkt_tuple.sport; + message->tran_time = bpf_ktime_get_ns() / 1000 - tinfo->tran_time; + message->rx = 1; // 收包 + message->len = __bpf_ntohs(BPF_CORE_READ(udp, len)); + bpf_ringbuf_submit(message, 0); + return 0; +} + +static __always_inline int __udp_send_skb(struct sk_buff *skb) { + if (!udp_info || skb == NULL) + return 0; + struct packet_tuple pkt_tuple = {0}; + struct sock *sk = BPF_CORE_READ(skb, sk); + u16 dport = BPF_CORE_READ(sk, __sk_common.skc_dport); + u16 sport = BPF_CORE_READ(sk, __sk_common.skc_num); + pkt_tuple.saddr = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr); // 源ip + pkt_tuple.daddr = BPF_CORE_READ(sk, __sk_common.skc_daddr); // 目的ip + pkt_tuple.sport = sport; // 源端口 + pkt_tuple.dport = __bpf_ntohs(dport); // 目的端口并进行字节序转换 + pkt_tuple.tran_flag = UDP; + FILTER + struct ktime_info *tinfo, zero = {0}; + bpf_printk("udp_send_skb%d %d %d %d", pkt_tuple.saddr, pkt_tuple.daddr, + pkt_tuple.sport, pkt_tuple.dport); + tinfo = (struct ktime_info *)bpf_map_lookup_or_try_init(×tamps, + &pkt_tuple, &zero); + if (tinfo == NULL) { + return 0; + } + tinfo->tran_time = bpf_ktime_get_ns() / 1000; + return 0; +} +static __always_inline int __ip_send_skb(struct sk_buff *skb) { + if (!udp_info || skb == NULL) + return 0; + struct iphdr *ip = skb_to_iphdr(skb); + struct udphdr *udp = skb_to_udphdr(skb); + struct packet_tuple pkt_tuple = {0}; + get_udp_pkt_tuple(&pkt_tuple, ip, udp); + FILTER + struct ktime_info *tinfo, zero = {0}; + tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple); + if (tinfo == NULL) { + return 0; + } + struct udp_message *message; + struct udp_message *udp_message = + bpf_map_lookup_elem(×tamps, &pkt_tuple); + message = bpf_ringbuf_reserve(&udp_rb, sizeof(*message), 0); + if (!message) { + return 0; + } + udp = skb_to_udphdr(skb); + message->tran_time = bpf_ktime_get_ns() / 1000 - tinfo->tran_time; + message->saddr = pkt_tuple.saddr; + message->daddr = pkt_tuple.daddr; + message->sport = pkt_tuple.sport; + message->dport = pkt_tuple.dport; + message->rx = 0; // 发包 + message->len = __bpf_ntohs(BPF_CORE_READ(udp, len)); + bpf_ringbuf_submit(message, 0); + return 0; +} +static __always_inline int process_dns_packet(struct sk_buff *skb, int rx) { + if (skb == NULL) + return 0; + u16 QR_flags; + u64 *count_ptr, response_count = 0, request_count = 0; + struct sock *sk = BPF_CORE_READ(skb, sk); + INIT_PACKET_UDP_TUPLE(sk, pkt_tuple); + // 使用saddr、daddr作为key + struct dns key = {.saddr = pkt_tuple.saddr, .daddr = pkt_tuple.daddr}; + + if ((pkt_tuple.sport != 53) && (pkt_tuple.dport != 53)) + return 0; + + struct dns_information *message = + bpf_ringbuf_reserve(&dns_rb, sizeof(*message), 0); + if (!message) + return 0; + + // 计算dns数据开始偏移 传输层头部的位置加上 UDP 头部的大小 + u32 dns_offset = + BPF_CORE_READ(skb, transport_header) + sizeof(struct udphdr); + struct dns_query query; + // dns头部位置 + bpf_probe_read_kernel(&query.header, sizeof(query.header), + BPF_CORE_READ(skb, head) + dns_offset); + // dns数据部分 + bpf_probe_read_kernel(message->data, sizeof(message->data), + BPF_CORE_READ(skb, head) + dns_offset + + sizeof(struct dns_header)); + QR_flags = __bpf_ntohs(query.header.flags); + /* + 1000 0000 0000 0000 + &运算提取最高位QR, QR=1 Response QR=0 Request + */ + if (QR_flags & 0x8000) { // 响应 + count_ptr = bpf_map_lookup_elem(&dns_response_count, &key); + if (count_ptr) { + response_count = *count_ptr + 1; + } else { + response_count = 1; + } + bpf_map_update_elem(&dns_response_count, &key, &response_count, + BPF_ANY); + // 保留映射中的请求计数值 + count_ptr = bpf_map_lookup_elem(&dns_request_count, &key); + if (count_ptr) { + request_count = *count_ptr; + } + } else { // 请求 + count_ptr = bpf_map_lookup_elem(&dns_request_count, &key); + if (count_ptr) { + request_count = *count_ptr + 1; + } else { + request_count = 1; + } + bpf_map_update_elem(&dns_request_count, &key, &request_count, BPF_ANY); + // 保留映射中的响应计数值 + count_ptr = bpf_map_lookup_elem(&dns_response_count, &key); + if (count_ptr) { + response_count = *count_ptr; + } + } + message->saddr = rx ? pkt_tuple.saddr : pkt_tuple.daddr; + message->daddr = rx ? pkt_tuple.daddr : pkt_tuple.saddr; + message->id = __bpf_ntohs(query.header.id); + message->flags = __bpf_ntohs(query.header.flags); + message->qdcount = __bpf_ntohs(query.header.qdcount); + message->ancount = __bpf_ntohs(query.header.ancount); + message->nscount = __bpf_ntohs(query.header.nscount); + message->arcount = __bpf_ntohs(query.header.arcount); + message->request_count = request_count; + message->response_count = response_count; + message->rx = rx; + + bpf_ringbuf_submit(message, 0); + return 0; +} +static __always_inline int __dns_rcv(struct sk_buff *skb) { + return process_dns_packet(skb, 0); // 0 收 +} + +static __always_inline int __dns_send(struct sk_buff *skb) { + return process_dns_packet(skb, 1); // 1 发 +} \ No newline at end of file diff --git a/MagicEyes/src/backend/net/net_watcher/include/dropreason.h b/MagicEyes/src/backend/net/net_watcher/include/dropreason.h new file mode 100644 index 000000000..880fdf1b7 --- /dev/null +++ b/MagicEyes/src/backend/net/net_watcher/include/dropreason.h @@ -0,0 +1,100 @@ +// Copyright 2023 The LMP Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://github.com/linuxkerneltravel/lmp/blob/develop/LICENSE +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// author: blown.away@qq.com +// net_watcher libbpf 丢包原因 + +#ifndef __DROPREASON_H +#define __DROPREASON_H +const char *SKB_Drop_Reason_Strings[] = { + "SKB_NOT_DROPPED_YET", + "SKB_CONSUMED", + "SKB_DROP_REASON_NOT_SPECIFIED", + "SKB_DROP_REASON_NO_SOCKET", + "SKB_DROP_REASON_PKT_TOO_SMALL", + "SKB_DROP_REASON_TCP_CSUM", + "SKB_DROP_REASON_SOCKET_FILTER", + "SKB_DROP_REASON_UDP_CSUM", + "SKB_DROP_REASON_NETFILTER_DROP", + "SKB_DROP_REASON_OTHERHOST", + "SKB_DROP_REASON_IP_CSUM", + "SKB_DROP_REASON_IP_INHDR", + "SKB_DROP_REASON_IP_RPFILTER", + "SKB_DROP_REASON_UNICAST_IN_L2_MULTICAST", + "SKB_DROP_REASON_XFRM_POLICY", + "SKB_DROP_REASON_IP_NOPROTO", + "SKB_DROP_REASON_SOCKET_RCVBUFF", + "SKB_DROP_REASON_PROTO_MEM", + "SKB_DROP_REASON_TCP_MD5NOTFOUND", + "SKB_DROP_REASON_TCP_MD5UNEXPECTED", + "SKB_DROP_REASON_TCP_MD5FAILURE", + "SKB_DROP_REASON_SOCKET_BACKLOG", + "SKB_DROP_REASON_TCP_FLAGS", + "SKB_DROP_REASON_TCP_ZEROWINDOW", + "SKB_DROP_REASON_TCP_OLD_DATA", + "SKB_DROP_REASON_TCP_OVERWINDOW", + "SKB_DROP_REASON_TCP_OFOMERGE", + "SKB_DROP_REASON_TCP_RFC7323_PAWS", + "SKB_DROP_REASON_TCP_INVALID_SEQUENCE", + "SKB_DROP_REASON_TCP_RESET", + "SKB_DROP_REASON_TCP_INVALID_SYN", + "SKB_DROP_REASON_TCP_CLOSE", + "SKB_DROP_REASON_TCP_FASTOPEN", + "SKB_DROP_REASON_TCP_OLD_ACK", + "SKB_DROP_REASON_TCP_TOO_OLD_ACK", + "SKB_DROP_REASON_TCP_ACK_UNSENT_DATA", + "SKB_DROP_REASON_TCP_OFO_QUEUE_PRUNE", + "SKB_DROP_REASON_TCP_OFO_DROP", + "SKB_DROP_REASON_IP_OUTNOROUTES", + "SKB_DROP_REASON_BPF_CGROUP_EGRESS", + "SKB_DROP_REASON_IPV6DISABLED", + "SKB_DROP_REASON_NEIGH_CREATEFAIL", + "SKB_DROP_REASON_NEIGH_FAILED", + "SKB_DROP_REASON_NEIGH_QUEUEFULL", + "SKB_DROP_REASON_NEIGH_DEAD", + "SKB_DROP_REASON_TC_EGRESS", + "SKB_DROP_REASON_QDISC_DROP", + "SKB_DROP_REASON_CPU_BACKLOG", + "SKB_DROP_REASON_XDP", + "SKB_DROP_REASON_TC_INGRESS", + "SKB_DROP_REASON_UNHANDLED_PROTO", + "SKB_DROP_REASON_SKB_CSUM", + "SKB_DROP_REASON_SKB_GSO_SEG", + "SKB_DROP_REASON_SKB_UCOPY_FAULT", + "SKB_DROP_REASON_DEV_HDR", + "SKB_DROP_REASON_DEV_READY", + "SKB_DROP_REASON_FULL_RING", + "SKB_DROP_REASON_NOMEM", + "SKB_DROP_REASON_HDR_TRUNC", + "SKB_DROP_REASON_TAP_FILTER", + "SKB_DROP_REASON_TAP_TXFILTER", + "SKB_DROP_REASON_ICMP_CSUM", + "SKB_DROP_REASON_INVALID_PROTO", + "SKB_DROP_REASON_IP_INADDRERRORS", + "SKB_DROP_REASON_IP_INNOROUTES", + "SKB_DROP_REASON_PKT_TOO_BIG", + "SKB_DROP_REASON_DUP_FRAG", + "SKB_DROP_REASON_FRAG_REASM_TIMEOUT", + "SKB_DROP_REASON_FRAG_TOO_FAR", + "SKB_DROP_REASON_TCP_MINTTL", + "SKB_DROP_REASON_IPV6_BAD_EXTHDR", + "SKB_DROP_REASON_IPV6_NDISC_FRAG", + "SKB_DROP_REASON_IPV6_NDISC_HOP_LIMIT", + "SKB_DROP_REASON_IPV6_NDISC_BAD_CODE", + "SKB_DROP_REASON_IPV6_NDISC_BAD_OPTIONS", + "SKB_DROP_REASON_IPV6_NDISC_NS_OTHERHOST", + "SKB_DROP_REASON_MAX", + "SKB_DROP_REASON_SUBSYS_MASK", +}; +#endif \ No newline at end of file diff --git a/MagicEyes/src/backend/net/net_watcher/include/net_watcher.h b/MagicEyes/src/backend/net/net_watcher/include/net_watcher.h index e56b21a8c..e331c59f7 100644 --- a/MagicEyes/src/backend/net/net_watcher/include/net_watcher.h +++ b/MagicEyes/src/backend/net/net_watcher/include/net_watcher.h @@ -14,13 +14,19 @@ // // author: blown.away@qq.com // -// netwatcher libbpf 内核<->用户 传递信息相关结构体 +// net_watcher libbpf 内核<->用户 传递信息相关结构体 -#ifndef __NETWATCHER_H -#define __NETWATCHER_H +#ifndef __NET_WATCHER_H +#define __NET_WATCHER_H + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; +typedef unsigned long long u64; #define ETH_P_IP 0x0800 /* Internet Protocol packet */ #define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */ +#define MAX_SLOTS 27 #ifndef AF_INET #define AF_INET 2 @@ -35,76 +41,226 @@ #define MAX_COMM 16 #define TCP 1 #define UDP 2 +#define MAX_PACKET 1000 +#define MAX_HTTP_HEADER 256 +#define NUM_LAYERS 5 +#define RED_TEXT "\033[31m" +#define RESET_TEXT "\033[0m" +#define GRANULARITY 3 +#define ALPHA 0.2 // 衰减因子 +#define MAXTIME 10000 +#define SLOW_QUERY_THRESHOLD 10000 // +#define ANSI_COLOR_RED "\x1b[31m" +#define ANSI_COLOR_RESET "\x1b[0m" +#define MAX_STACK_DEPTH 128 +#define MAX_EVENTS 1024 +#define CACHEMAXSIZE 5 +typedef u64 stack_trace_t[MAX_STACK_DEPTH]; struct conn_t { - void *sock; // 此tcp连接的 socket 地址 - int pid; // pid - unsigned long long ptid; // 此tcp连接的 ptid(ebpf def) - char comm[MAX_COMM]; // 此tcp连接的 command - unsigned short family; // 10(AF_INET6):v6 or 2(AF_INET):v4 + void *sock; // 此tcp连接的 socket 地址 + int pid; // pid + u64 ptid; // 此tcp连接的 ptid(ebpf def) + char comm[MAX_COMM]; // 此tcp连接的 command + u16 family; // 10(AF_INET6):v6 or 2(AF_INET):v4 unsigned __int128 saddr_v6; unsigned __int128 daddr_v6; - unsigned int saddr; - unsigned int daddr; - unsigned short sport; - unsigned short dport; + u32 saddr; + u32 daddr; + u16 sport; + u16 dport; int is_server; // 1: 被动连接 0: 主动连接 - unsigned int tcp_backlog; // backlog - unsigned int max_tcp_backlog; // max_backlog - unsigned long long bytes_acked; // 已确认的字节数 - unsigned long long bytes_received; // 已接收的字节数 + u32 tcp_backlog; // backlog + u32 max_tcp_backlog; // max_backlog + u64 bytes_acked; // 已确认的字节数 + u64 bytes_received; // 已接收的字节数 - unsigned int snd_cwnd; // 拥塞窗口大小 - unsigned int rcv_wnd; // 接收窗口大小 - unsigned int snd_ssthresh; // 慢启动阈值 - unsigned int sndbuf; // 发送缓冲区大小(byte) - unsigned int sk_wmem_queued; // 已使用的发送缓冲区 - unsigned int total_retrans; // 重传包数 - unsigned int fastRe; // 快速重传次数 - unsigned int timeout; // 超时重传次数 + u32 snd_cwnd; // 拥塞窗口大小 + u32 rcv_wnd; // 接收窗口大小 + u32 snd_ssthresh; // 慢启动阈值 + u32 sndbuf; // 发送缓冲区大小(byte) + u32 sk_wmem_queued; // 已使用的发送缓冲区 + u32 total_retrans; // 重传包数 + u32 fastRe; // 快速重传次数 + u32 timeout; // 超时重传次数 - unsigned int srtt; // 平滑往返时间 - unsigned long long init_timestamp; // 建立连接时间戳 - unsigned long long duration; // 连接已建立时长 + u32 srtt; // 平滑往返时间 + u64 init_timestamp; // 建立连接时间戳 + u64 duration; // 连接已建立时长 }; -#define MAX_PACKET 1000 -#define MAX_HTTP_HEADER 256 - struct pack_t { - int err; // no err(0) invalid seq(1) invalid checksum(2) - unsigned long long mac_time; // mac layer 处理时间(us) - unsigned long long ip_time; // ip layer 处理时间(us) - // unsigned long long tcp_time; // tcp layer 处理时间(us) - unsigned long long tran_time; // tcp layer 处理时间(us) - unsigned int seq; // the seq num of packet - unsigned int ack; // the ack num of packet - unsigned char data[MAX_HTTP_HEADER]; // 用户层数据 - const void *sock; // 此包tcp连接的 socket 指针 - int rx; // rx packet(1) or tx packet(0) + int err; // no err(0) invalid seq(1) invalid checksum(2) + u64 mac_time; // mac layer 处理时间(us) + u64 ip_time; // ip layer 处理时间(us) + // u64 tcp_time; // tcp layer 处理时间(us) + u64 tran_time; // tcp layer 处理时间(us) + u32 seq; // the seq num of packet + u32 ack; // the ack num of packet + u8 data[MAX_HTTP_HEADER]; // 用户层数据 + const void *sock; // 此包tcp连接的 socket 指针 + int rx; // rx packet(1) or tx packet(0) + u32 saddr; + u32 daddr; + unsigned __int128 saddr_v6; + unsigned __int128 daddr_v6; + u16 sport; + u16 dport; }; struct udp_message { - unsigned int saddr; - unsigned int daddr; - unsigned short sport; - unsigned short dport; - unsigned long long tran_time; - int rx; + u32 saddr; + u32 daddr; + u16 sport; + u16 dport; + u64 tran_time; + int rx; int len; }; -struct netfilter -{ +struct netfilter { + u32 saddr; + u32 daddr; + u16 sport; + u16 dport; + u64 local_input_time; + u64 pre_routing_time; + u64 forward_time; + u64 local_out_time; + u64 post_routing_time; + u32 rx; +}; +struct reasonissue { + u32 saddr; + u32 daddr; + u16 sport; + u16 dport; + long location; + u16 protocol; + int drop_reason; +}; +struct icmptime { unsigned int saddr; unsigned int daddr; - unsigned short sport; - unsigned short dport; - unsigned long long local_input_time; - unsigned long long pre_routing_time; - unsigned long long forward_time; - unsigned long long local_out_time; - unsigned long long post_routing_time; - unsigned int flag; -}; -#endif /* __NETWATCHER_H */ \ No newline at end of file + unsigned long long icmp_tran_time; + unsigned int flag; // 0 send 1 rcv +}; + +struct tcp_state { + u32 saddr; + u32 daddr; + u16 sport; + u16 dport; + int oldstate; + int newstate; + u64 time; +}; +struct dns_information { + u32 saddr; + u32 daddr; + u16 id; + u16 flags; + u16 qdcount; + u16 ancount; + u16 nscount; + u16 arcount; + char data[64]; + int rx; + int response_count; + int request_count; +}; +struct stacktrace_event { + u32 pid; + u32 cpu_id; + char comm[16]; + signed int kstack_sz; + signed int ustack_sz; + stack_trace_t kstack; + stack_trace_t ustack; +}; +typedef struct mysql_query { + int pid; + int tid; + char comm[20]; + u32 size; + char msql[256]; + u64 duratime; + int count; +} mysql_query; +struct redis_query { + int pid; + int tid; + char comm[20]; + u32 size; + char redis[4][8]; + u64 duratime; + int count; + u64 begin_time; + int argc; +}; +struct redis_stat_query { + int pid; + char comm[20]; + char key[20]; + int key_count; + char value[64]; + int value_type; +}; + +struct RTT { + u32 saddr; + u32 daddr; + u64 slots[64]; + u64 latency; + u64 cnt; +}; +struct reset_event_t { + int pid; + char comm[16]; + u16 family; + unsigned __int128 saddr_v6; + unsigned __int128 daddr_v6; + u32 saddr; + u32 daddr; + u16 sport; + u16 dport; + u8 direction; // 0 for send, 1 for receive + u64 count; + u64 timestamp; + u8 state; +}; +struct packet_count { + u64 rx_count; + u64 tx_count; +}; +struct packet_info { + u32 saddr; + u32 daddr; + u16 sport; + u16 dport; + u16 proto; + struct packet_count count; +}; +struct SymbolEntry { + unsigned long addr; + char name[30]; +}; + +static const char *protocol[] = { + [0] = "TCP", + [1] = "UDP", + [2] = "ICMP", + [3] = "UNKNOWN", +}; +static const char *tcp_states[] = { + [1] = "ESTABLISHED", [2] = "SYN_SENT", [3] = "SYN_RECV", + [4] = "FIN_WAIT1", [5] = "FIN_WAIT2", [6] = "TIME_WAIT", + [7] = "CLOSE", [8] = "CLOSE_WAIT", [9] = "LAST_ACK", + [10] = "LISTEN", [11] = "CLOSING", [12] = "NEW_SYN_RECV", + [13] = "UNKNOWN", +}; +struct LayerDelayInfo { + float delay; // 时延数据 + int layer_index; // 层索引 +}; +#endif /* __NET_WATCHER_H */ \ No newline at end of file diff --git a/MagicEyes/src/backend/net/net_watcher/src/net_watcher.c b/MagicEyes/src/backend/net/net_watcher/src/net_watcher.c index 248599179..96e719dbc 100644 --- a/MagicEyes/src/backend/net/net_watcher/src/net_watcher.c +++ b/MagicEyes/src/backend/net/net_watcher/src/net_watcher.c @@ -16,6 +16,9 @@ // // net_watcher libbpf 用户态代码 +#include "net_watcher/include/net_watcher.h" +#include "net_watcher/include/dropreason.h" +#include "net/net_watcher/net_watcher.skel.h" #include #include #include @@ -26,25 +29,40 @@ #include #include #include +#include +#include #include -#include "net_watcher/include/net_watcher.h" - -#include "net/net_watcher/net_watcher.skel.h" - static volatile bool exiting = false; - +struct packet_count proto_stats[256] = {0}; +static u64 rst_count = 0; +static struct reset_event_t event_store[MAX_EVENTS]; +static int event_count = 0; static char connects_file_path[1024]; static char err_file_path[1024]; static char packets_file_path[1024]; static char udp_file_path[1024]; +static char binary_path[64] = ""; +int num_symbols = 0; +int cache_size = 0; + +// 用于存储从 eBPF map 读取的数据 +typedef struct { + char key[256]; + u32 value; +} kv_pair; + +static int map_fd; static int sport = 0, dport = 0; // for filter static int all_conn = 0, err_packet = 0, extra_conn_info = 0, layer_time = 0, - http_info = 0, retrans_info = 0, udp_info = 0,net_filter = 0; // flag + http_info = 0, retrans_info = 0, udp_info = 0, net_filter = 0, + drop_reason = 0, addr_to_func = 0, icmp_info = 0, tcp_info = 0, + time_load = 0, dns_info = 0, stack_info = 0, mysql_info = 0, + redis_info = 0, count_info = 0, rtt_info = 0, rst_info = 0, + protocol_count = 0,redis_stat = 0; // flag static const char argp_program_doc[] = "Watch tcp/ip in network subsystem \n"; - static const struct argp_option opts[] = { {"all", 'a', 0, 0, "set to trace CLOSED connection"}, {"err", 'e', 0, 0, "set to trace TCP error packets"}, @@ -55,7 +73,27 @@ static const struct argp_option opts[] = { {"sport", 's', "SPORT", 0, "trace this source port only"}, {"dport", 'd', "DPORT", 0, "trace this destination port only"}, {"udp", 'u', 0, 0, "trace the udp message"}, - {"net_filter",'n',0,0,"trace ipv4 packget filter "}, + {"net_filter", 'n', 0, 0, "trace ipv4 packget filter "}, + {"drop_reason", 'k', 0, 0, "trace kfree "}, + {"addr_to_func", 'F', 0, 0, "translation addr to func and offset"}, + {"icmptime", 'I', 0, 0, "set to trace layer time of icmp"}, + {"tcpstate", 'S', 0, 0, "set to trace tcpstate"}, + {"timeload", 'L', 0, 0, "analysis time load"}, + {"dns", 'D', 0, 0, + "set to trace dns information info include Id 事务ID、Flags 标志字段、Qd " + "问题部分计数、An 应答记录计数、Ns 授权记录计数、Ar 附加记录计数、Qr " + "域名、rx 收发包 、Qc请求数、Sc响应数"}, + {"stack", 'A', 0, 0, "set to trace of stack "}, + {"mysql", 'M', 0, 0, + "set to trace mysql information info include Pid 进程id、Comm " + "进程名、Size sql语句字节大小、Sql 语句"}, + {"redis", 'R', 0, 0}, + {"redis-stat", 'b', 0, 0}, + {"count", 'C', "NUMBER", 0, + "specify the time to count the number of requests"}, + {"rtt", 'T', 0, 0, "set to trace rtt"}, + {"rst_counters", 'U', 0, 0, "set to trace rst"}, + {"protocol_count", 'p', 0, 0, "set to trace protocol count"}, {}}; static error_t parse_arg(int key, char *arg, struct argp_state *state) { @@ -91,20 +129,626 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) { case 'n': net_filter = 1; break; + case 'k': + drop_reason = 1; + break; + case 'F': + addr_to_func = 1; + break; + case 'I': + icmp_info = 1; + break; + case 'S': + tcp_info = 1; + break; + case 'L': + time_load = 1; + break; + case 'D': + dns_info = 1; + break; + case 'A': + stack_info = 1; + break; + case 'M': + mysql_info = 1; + break; + case 'R': + redis_info = 1; + break; + case 'T': + rtt_info = 1; + break; + case 'U': + rst_info = 1; + break; + case 'p': + protocol_count = 1; + break; + case 'b': + redis_stat = 1; + break; + case 'C': + count_info = strtoul(arg, &end, 10); + break; default: return ARGP_ERR_UNKNOWN; } return 0; } - static const struct argp argp = { .options = opts, .parser = parse_arg, .doc = argp_program_doc, }; +enum MonitorMode { + MODE_UDP, + MODE_NET_FILTER, + MODE_DROP_REASON, + MODE_ICMP, + MODE_TCP, + MODE_DNS, + MODE_MYSQL, + MODE_REDIS, + MODE_RTT, + MODE_RST, + MODE_PROTOCOL_COUNT, + MODE_REDIS_STAT, + MODE_DEFAULT +}; +enum MonitorMode get_monitor_mode() { + if (udp_info) { + return MODE_UDP; + } else if (net_filter) { + return MODE_NET_FILTER; + } else if (drop_reason) { + return MODE_DROP_REASON; + } else if (icmp_info) { + return MODE_ICMP; + } else if (tcp_info) { + return MODE_TCP; + } else if (dns_info) { + return MODE_DNS; + } else if (mysql_info) { + return MODE_MYSQL; + } else if (redis_info) { + return MODE_REDIS; + } else if (redis_stat) { + return MODE_REDIS_STAT; + } else if (rtt_info) { + return MODE_RTT; + } else if (rst_info) { + return MODE_RST; + } else if (protocol_count) { + return MODE_PROTOCOL_COUNT; + } else { + return MODE_DEFAULT; + } +} +#define LOGO_STRING \ + " " \ + " __ __ __ " \ + " \n" \ + " /\\ \\__ /\\ \\__ /\\ \\ " \ + " \n" \ + " ___ __\\ \\ _\\ __ __ __ __ \\ \\ _\\ ___\\ \\ \\___ " \ + " __ _ __ \n" \ + "/ _ \\ / __ \\ \\ \\/ /\\ \\/\\ \\/\\ \\ / __ \\ \\ \\ \\/ / ___\\ " \ + "\\ _ \\ / __ \\/\\ __\\ \n" \ + "/\\ \\/\\ \\/\\ __/\\ \\ \\_\\ \\ \\_/ \\_/ \\/\\ \\_\\ \\_\\ \\ " \ + "\\_/\\ \\__/\\ \\ \\ \\ \\/\\ __/\\ \\ \\/ \n" \ + "\\ \\_\\ \\_\\ \\____\\ \\__\\ \\_______ / /\\ \\__/\\ \\_\\ \\__\\ " \ + "\\____/\\ \\_\\ \\_\\ \\____ \\ \\_\\ \n" \ + " \\/_/\\/_/\\/____/ \\/__/ \\/__//__ / \\/_/ \\/_/\\/__/\\/____/ " \ + "\\/_/\\/_/\\/____/ \\/_/ \n\n" -static void sig_handler(int signo) { exiting = true; } +void print_logo() { + char *logo = LOGO_STRING; + int i = 0; + FILE *lolcat_pipe = popen("/usr/games/lolcat", "w"); + if (lolcat_pipe == NULL) { + printf("Error: Unable to execute lolcat command.\n"); + return; + } + // 像lolcat管道逐个字符写入字符串 + while (logo[i] != '\0') { + fputc(logo[i], lolcat_pipe); + fflush(lolcat_pipe); // 刷新管道,确保字符被立即发送给lolcat + usleep(150); + i++; + } + + pclose(lolcat_pipe); +} +#define __ATTACH_UPROBE(skel, sym_name, prog_name, is_retprobe) \ + do { \ + LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts, .func_name = #sym_name, \ + .retprobe = is_retprobe); \ + skel->links.prog_name = bpf_program__attach_uprobe_opts( \ + skel->progs.prog_name, -1, binary_path, 0, &uprobe_opts); \ + } while (false) + +#define __CHECK_PROGRAM(skel, prog_name) \ + do { \ + if (!skel->links.prog_name) { \ + perror("no program attached for " #prog_name); \ + return -errno; \ + } \ + } while (false) + +#define __ATTACH_UPROBE_CHECKED(skel, sym_name, prog_name, is_retprobe) \ + do { \ + __ATTACH_UPROBE(skel, sym_name, prog_name, is_retprobe); \ + __CHECK_PROGRAM(skel, prog_name); \ + } while (false) + +#define ATTACH_UPROBE(skel, sym_name, prog_name) \ + __ATTACH_UPROBE(skel, sym_name, prog_name, false) +#define ATTACH_URETPROBE(skel, sym_name, prog_name) \ + __ATTACH_UPROBE(skel, sym_name, prog_name, true) + +#define ATTACH_UPROBE_CHECKED(skel, sym_name, prog_name) \ + __ATTACH_UPROBE_CHECKED(skel, sym_name, prog_name, false) +#define ATTACH_URETPROBE_CHECKED(skel, sym_name, prog_name) \ + __ATTACH_UPROBE_CHECKED(skel, sym_name, prog_name, true) + +struct SymbolEntry symbols[300000]; +struct SymbolEntry cache[CACHEMAXSIZE]; +// LRU算法查找函数 +struct SymbolEntry find_in_cache(unsigned long int addr) { + // 查找地址是否在快表中 + for (int i = 0; i < cache_size; i++) { + if (cache[i].addr == addr) { + // 更新访问时间 + struct SymbolEntry temp = cache[i]; + // 将访问的元素移动到快表的最前面,即最近使用的位置 + for (int j = i; j > 0; j--) { + cache[j] = cache[j - 1]; + } + cache[0] = temp; + return temp; + } + } + // 如果地址不在快表中,则返回空 + struct SymbolEntry empty_entry; + empty_entry.addr = 0; + return empty_entry; +} +// 将新的符号条目加入快表 +void add_to_cache(struct SymbolEntry entry) { + // 如果快表已满,则移除最久未使用的条目 + if (cache_size == CACHEMAXSIZE) { + for (int i = cache_size - 1; i > 0; i--) { + cache[i] = cache[i - 1]; + } + cache[0] = entry; + } else { + // 否则,直接加入快表 + for (int i = cache_size; i > 0; i--) { + cache[i] = cache[i - 1]; + } + cache[0] = entry; + cache_size++; + } +} +struct SymbolEntry findfunc(unsigned long int addr) { + // 先在快表中查找 + struct SymbolEntry entry = find_in_cache(addr); + if (entry.addr != 0) { + return entry; + } + unsigned long long low = 0, high = num_symbols - 1; + unsigned long long result = -1; + + while (low <= high) { + int mid = low + (high - low) / 2; + if (symbols[mid].addr < addr) { + result = mid; + low = mid + 1; + } else { + high = mid - 1; + } + } + add_to_cache(symbols[result]); + return symbols[result]; +}; +void readallsym() { + FILE *file = fopen("/proc/kallsyms", "r"); + if (!file) { + perror("Error opening file"); + exit(EXIT_FAILURE); + } + char line[256]; + while (fgets(line, sizeof(line), file)) { + unsigned long addr; + char type, name[30]; + int ret = sscanf(line, "%lx %c %s", &addr, &type, name); + if (ret == 3) { + symbols[num_symbols].addr = addr; + strncpy(symbols[num_symbols].name, name, 30); + num_symbols++; + } + } + + fclose(file); +} +/* + 指数加权移动平均算法(EWMA) + 1.使用指数加权移动平均算法(EWMA)来计算每层的指数加权移动平均值, + 公式EWMA_new = alpha * new_value + (1 - alpha) * old_ewma ,alpha + 指数加权系数,表示新数据点的权重,new_value 当前时延,old_ewma + 旧的指数加权移动平均值 + 2.根据当前时延和指数加权移动平均值*预先设定的粒度阈值(GRANULARITY)对比,来判断时延是否异常 + 3.可以快速适应数据的变化,并能够有效地检测异常时延 + +*/ +// 全局变量用于存储每层的移动平均值 +float ewma_values[NUM_LAYERS] = {0}; +int count[NUM_LAYERS] = {0}; + +// 指数加权移动平均算法 +float calculate_ewma(float new_value, float old_ewma) { + return ALPHA * new_value + (1 - ALPHA) * old_ewma; +} + +// 收集时延数据并检测异常 +int process_delay(float layer_delay, int layer_index) { + + if (layer_delay == 0) + return 0; + count[layer_index]++; + if (ewma_values[layer_index] == 0) { + ewma_values[layer_index] = layer_delay; + return 0; + } + // 计算阈值,指数加权移动平均值乘以粒度因子 + ewma_values[layer_index] = + calculate_ewma(layer_delay, ewma_values[layer_index]); + float threshold = ewma_values[layer_index] * GRANULARITY; + if (count[layer_index] > 30) { + // 判断当前时延是否超过阈值 + // printf("%d %d:%f %f + // ",layer_index,count[layer_index]++,threshold,layer_delay); + if (layer_delay > threshold) { // 异常 + return 1; + } else { + return 0; + } + } + return 0; +} +static void set_rodata_flags(struct net_watcher_bpf *skel) { + skel->rodata->filter_dport = dport; + skel->rodata->filter_sport = sport; + skel->rodata->all_conn = all_conn; + skel->rodata->err_packet = err_packet; + skel->rodata->extra_conn_info = extra_conn_info; + skel->rodata->layer_time = layer_time; + skel->rodata->http_info = http_info; + skel->rodata->retrans_info = retrans_info; + skel->rodata->udp_info = udp_info; + skel->rodata->net_filter = net_filter; + skel->rodata->drop_reason = drop_reason; + skel->rodata->tcp_info = tcp_info; + skel->rodata->icmp_info = icmp_info; + skel->rodata->dns_info = dns_info; + skel->rodata->stack_info = stack_info; + skel->rodata->mysql_info = mysql_info; + skel->rodata->redis_info = redis_info; + skel->rodata->redis_stat = redis_stat; + skel->rodata->rtt_info = rtt_info; + skel->rodata->rst_info = rst_info; + skel->rodata->protocol_count = protocol_count; +} +static void set_disable_load(struct net_watcher_bpf *skel) { + + bpf_program__set_autoload(skel->progs.inet_csk_accept_exit, + (all_conn || err_packet || extra_conn_info || + retrans_info || layer_time || http_info || + rtt_info) + ? true + : false); + bpf_program__set_autoload(skel->progs.tcp_v4_connect, + (all_conn || err_packet || extra_conn_info || + retrans_info || layer_time || http_info || + rtt_info) + ? true + : false); + bpf_program__set_autoload(skel->progs.tcp_v4_connect_exit, + (all_conn || err_packet || extra_conn_info || + retrans_info || layer_time || http_info || + rtt_info) + ? true + : false); + bpf_program__set_autoload(skel->progs.tcp_v6_connect, + (all_conn || err_packet || extra_conn_info || + retrans_info || layer_time || http_info || + rtt_info) + ? true + : false); + bpf_program__set_autoload(skel->progs.tcp_v6_connect_exit, + (all_conn || err_packet || extra_conn_info || + retrans_info || layer_time || http_info || + rtt_info) + ? true + : false); + bpf_program__set_autoload(skel->progs.tcp_set_state, + (all_conn || err_packet || extra_conn_info || + retrans_info || layer_time || http_info || + rtt_info) + ? true + : false); + bpf_program__set_autoload(skel->progs.eth_type_trans, + (all_conn || err_packet || extra_conn_info || + retrans_info || layer_time || http_info || + rtt_info || protocol_count) + ? true + : false); + bpf_program__set_autoload(skel->progs.ip_rcv_core, + (all_conn || err_packet || extra_conn_info || + retrans_info || layer_time || http_info || + rtt_info) + ? true + : false); + bpf_program__set_autoload(skel->progs.ip6_rcv_core, + (all_conn || err_packet || extra_conn_info || + retrans_info || layer_time || http_info || + rtt_info) + ? true + : false); + bpf_program__set_autoload(skel->progs.tcp_v4_rcv, + (all_conn || err_packet || extra_conn_info || + retrans_info || layer_time || http_info || + rtt_info) + ? true + : false); + bpf_program__set_autoload(skel->progs.tcp_v6_rcv, + (all_conn || err_packet || extra_conn_info || + retrans_info || layer_time || http_info || + rtt_info) + ? true + : false); + bpf_program__set_autoload(skel->progs.tcp_v4_do_rcv, + (all_conn || err_packet || extra_conn_info || + retrans_info || layer_time || http_info || + rtt_info) + ? true + : false); + bpf_program__set_autoload(skel->progs.tcp_v6_do_rcv, + (all_conn || err_packet || extra_conn_info || + retrans_info || layer_time || http_info || + rtt_info) + ? true + : false); + bpf_program__set_autoload(skel->progs.skb_copy_datagram_iter, + (all_conn || err_packet || extra_conn_info || + retrans_info || layer_time || http_info || + rtt_info) + ? true + : false); + bpf_program__set_autoload(skel->progs.tcp_validate_incoming, + err_packet ? true : false); + bpf_program__set_autoload(skel->progs.__skb_checksum_complete_exit, + err_packet ? true : false); + bpf_program__set_autoload(skel->progs.tcp_sendmsg, + (all_conn || err_packet || extra_conn_info || + retrans_info || layer_time || http_info || + rtt_info) + ? true + : false); + bpf_program__set_autoload(skel->progs.ip_queue_xmit, + (all_conn || err_packet || extra_conn_info || + retrans_info || layer_time || http_info || + rtt_info) + ? true + : false); + bpf_program__set_autoload(skel->progs.inet6_csk_xmit, + (all_conn || err_packet || extra_conn_info || + retrans_info || layer_time || http_info || + rtt_info) + ? true + : false); + bpf_program__set_autoload(skel->progs.__dev_queue_xmit, + (all_conn || err_packet || extra_conn_info || + retrans_info || layer_time || http_info || + rtt_info) + ? true + : false); + bpf_program__set_autoload(skel->progs.dev_hard_start_xmit, + (all_conn || err_packet || extra_conn_info || + retrans_info || layer_time || http_info || + rtt_info || protocol_count) + ? true + : false); + bpf_program__set_autoload(skel->progs.tcp_enter_recovery, + retrans_info ? true : false); + bpf_program__set_autoload(skel->progs.tcp_enter_loss, + retrans_info ? true : false); + bpf_program__set_autoload(skel->progs.udp_rcv, + udp_info || dns_info ? true : false); + bpf_program__set_autoload(skel->progs.__udp_enqueue_schedule_skb, + udp_info || dns_info ? true : false); + bpf_program__set_autoload(skel->progs.udp_send_skb, + udp_info || dns_info ? true : false); + bpf_program__set_autoload(skel->progs.ip_send_skb, + udp_info || dns_info ? true : false); + bpf_program__set_autoload(skel->progs.ip_rcv, net_filter ? true : false); + bpf_program__set_autoload(skel->progs.ip_local_deliver, + net_filter ? true : false); + bpf_program__set_autoload(skel->progs.ip_local_deliver_finish, + net_filter ? true : false); + bpf_program__set_autoload(skel->progs.ip_local_out, + net_filter ? true : false); + bpf_program__set_autoload(skel->progs.ip_output, net_filter ? true : false); + bpf_program__set_autoload(skel->progs.__ip_finish_output, + net_filter ? true : false); + bpf_program__set_autoload(skel->progs.ip_forward, + net_filter ? true : false); + bpf_program__set_autoload(skel->progs.tp_kfree, drop_reason ? true : false); + bpf_program__set_autoload(skel->progs.icmp_rcv, icmp_info ? true : false); + bpf_program__set_autoload(skel->progs.__sock_queue_rcv_skb, + icmp_info ? true : false); + bpf_program__set_autoload(skel->progs.icmp_reply, icmp_info ? true : false); + bpf_program__set_autoload(skel->progs.handle_set_state, + tcp_info ? true : false); + bpf_program__set_autoload(skel->progs.query__start, + mysql_info ? true : false); + bpf_program__set_autoload(skel->progs.query__end, + mysql_info ? true : false); + bpf_program__set_autoload(skel->progs.redis_addReply, + redis_stat ? true : false); + bpf_program__set_autoload(skel->progs.redis_lookupKey, + redis_stat ? true : false); + bpf_program__set_autoload(skel->progs.redis_processCommand, + redis_info ? true : false); + bpf_program__set_autoload(skel->progs.redis_call, + redis_info ? true : false); + bpf_program__set_autoload(skel->progs.tcp_rcv_established, + (all_conn || err_packet || extra_conn_info || + retrans_info || layer_time || http_info || + rtt_info) + ? true + : false); + bpf_program__set_autoload(skel->progs.handle_send_reset, + rst_info ? true : false); + bpf_program__set_autoload(skel->progs.handle_receive_reset, + rst_info ? true : false); +} +static void print_header(enum MonitorMode mode) { + switch (mode) { + case MODE_UDP: + printf("===============================================================" + "UDP " + "INFORMATION====================================================" + "====\n"); + printf("%-20s %-20s %-20s %-20s %-20s %-20s %-20s\n", "Saddr", "Daddr", + "Sprot", "Dprot", "udp_time/μs", "RX/direction", "len/byte"); + break; + case MODE_NET_FILTER: + printf("===============================================================" + "===NETFILTER " + "INFORMATION====================================================" + "=======\n"); + printf("%-20s %-20s %-12s %-12s %-8s %-8s %-7s %-8s %-8s %-8s\n", + "Saddr", "Daddr", "Sprot", "Dprot", "PreRT/μs", "L_IN/μs", + "FW/μs", "PostRT/μs", "L_OUT/μs", "RX/direction"); + break; + case MODE_DROP_REASON: + printf("===============================================================" + "DROP " + "INFORMATION====================================================" + "====\n"); + printf("%-13s %-17s %-17s %-10s %-10s %-9s %-33s %-30s\n", "Time", + "Saddr", "Daddr", "Sprot", "Dprot", "prot", "addr", "reason"); + break; + case MODE_ICMP: + printf("=================================================ICMP " + "INFORMATION==============================================\n"); + printf("%-20s %-20s %-20s %-20s\n", "Saddr", "Daddr", "icmp_time/μs", + "RX/direction"); + break; + case MODE_TCP: + printf("===============================================================" + "TCP STATE " + "INFORMATION====================================================" + "====\n"); + printf("%-20s %-20s %-20s %-20s %-20s %-20s %-20s \n", "Saddr", "Daddr", + "Sport", "Dport", "oldstate", "newstate", "time/μs"); + break; + case MODE_DNS: + printf("===============================================================" + "====================DNS " + "INFORMATION====================================================" + "============================\n"); + printf("%-20s %-20s %-12s %-12s %-5s %-5s %-5s %-5s %-47s %-10s %-10s " + "%-10s \n", + "Saddr", "Daddr", "Id", "Flags", "Qd", "An", "Ns", "Ar", "Qr", + "Qc", "Sc", "RX/direction"); + break; + case MODE_MYSQL: + printf("===============================================================" + "====================MYSQL " + "INFORMATION====================================================" + "============================\n"); + printf("%-20s %-20s %-20s %-20s %-40s %-20s %-20s \n", "Pid", "Tid", + "Comm", "Size", "Sql", "Duration/μs", "Request"); + break; + case MODE_REDIS: + printf("===============================================================" + "====================REDIS " + "INFORMATION====================================================" + "============================\n"); + printf("%-20s %-20s %-20s %-20s %-20s \n", "Pid", "Comm", "Size", + "Redis", "duration/μs"); + break; + case MODE_REDIS_STAT: + printf("===============================================================" + "====================REDIS " + "INFORMATION====================================================" + "============================\n"); + printf("%-20s %-20s %-20s %-20s %-20s %-20s\n", "Pid", "Comm", "key", "Key_count","Value_Type","Value"); + break; + case MODE_RTT: + printf("===============================================================" + "====================RTT " + "INFORMATION====================================================" + "============================\n"); + break; + case MODE_RST: + printf("===============================================================" + "====================RST " + "INFORMATION====================================================" + "============================\n"); + printf("%-20s %-20s %-20s %-20s %-20s %-20s %-20s \n", "Pid", "Comm", + "Saddr", "Daddr", "Sport", "Dport", "Time"); + break; + case MODE_DEFAULT: + printf("===============================================================" + "=INFORMATION===================================================" + "======================\n"); + printf("%-22s %-20s %-8s %-20s %-8s %-15s %-15s %-15s %-15s %-15s \n", + "SOCK", "Saddr", "Sport", "Daddr", "Dport", "MAC_TIME/μs", + "IP_TIME/μs", "TRAN_TIME/μs", "RX/direction", "HTTP"); + break; + case MODE_PROTOCOL_COUNT: + printf("===============================================================" + "=MODE_PROTOCOL_COUNT===========================================" + "========" + "======================\n"); + break; + } +} +static void open_log_files() { + FILE *connect_file = fopen(connects_file_path, "w+"); + if (connect_file == NULL) { + fprintf(stderr, "Failed to open connect.log: (%s)\n", strerror(errno)); + exit(EXIT_FAILURE); + } + fclose(connect_file); + FILE *err_file = fopen(err_file_path, "w+"); + if (err_file == NULL) { + fprintf(stderr, "Failed to open err.log: (%s)\n", strerror(errno)); + exit(EXIT_FAILURE); + } + fclose(err_file); + + FILE *packet_file = fopen(packets_file_path, "w+"); + if (packet_file == NULL) { + fprintf(stderr, "Failed to open packets.log: (%s)\n", strerror(errno)); + exit(EXIT_FAILURE); + } + fclose(packet_file); + + FILE *udp_file = fopen(udp_file_path, "w+"); + if (udp_file == NULL) { + fprintf(stderr, "Failed to open udp.log: (%s)\n", strerror(errno)); + exit(EXIT_FAILURE); + } + fclose(udp_file); +} + +static void sig_handler(int signo) { exiting = true; } static void bytes_to_str(char *str, unsigned long long num) { if (num > 1e9) { sprintf(str, "%.8lfG", (double)num / 1e9); @@ -116,10 +760,9 @@ static void bytes_to_str(char *str, unsigned long long num) { sprintf(str, "%llu", num); } } - static int print_conns(struct net_watcher_bpf *skel) { - FILE *file = fopen(connects_file_path, "w+"); + FILE *file = fopen(connects_file_path, "w"); if (file == NULL) { fprintf(stderr, "Failed to open connects.log: (%s)\n", strerror(errno)); return 0; @@ -145,7 +788,9 @@ static int print_conns(struct net_watcher_bpf *skel) { char s_ip_port_str[INET6_ADDRSTRLEN + 6]; char d_ip_port_str[INET6_ADDRSTRLEN + 6]; - + if ((d.saddr & 0x0000FFFF) == 0x0000007F || + (d.daddr & 0x0000FFFF) == 0x0000007F) + return 0; if (d.family == AF_INET) { sprintf(s_ip_port_str, "%s:%d", inet_ntop(AF_INET, &d.saddr, s_str, sizeof(s_str)), @@ -199,16 +844,34 @@ static int print_conns(struct net_watcher_bpf *skel) { } else { fprintf(file, ",fast_retrans=\"-\",timeout_retrans=\"-\""); } - fprintf(file, "} 0\n"); + fprintf(file, "}\n"); } + fflush(file); fclose(file); return 0; } - static int print_packet(void *ctx, void *packet_info, size_t size) { - if (udp_info || net_filter) + if (udp_info || net_filter || drop_reason || icmp_info || tcp_info || + dns_info || mysql_info || redis_info || rtt_info || protocol_count||redis_stat) return 0; const struct pack_t *pack_info = packet_info; + if (pack_info->mac_time > MAXTIME || pack_info->ip_time > MAXTIME || + pack_info->tran_time > MAXTIME) { + return 0; + } + char d_str[INET_ADDRSTRLEN]; + char s_str[INET_ADDRSTRLEN]; + unsigned int saddr = pack_info->saddr; + unsigned int daddr = pack_info->daddr; + if ((daddr & 0x0000FFFF) == 0x0000007F || + (saddr & 0x0000FFFF) == 0x0000007F) + return 0; + if (dport) + if (pack_info->dport != dport) + return 0; + if (sport) + if (pack_info->sport != sport) + return 0; if (pack_info->err) { FILE *file = fopen(err_file_path, "a"); char reason[20]; @@ -246,38 +909,64 @@ static int print_packet(void *ctx, void *packet_info, size_t size) { sprintf(http_data, "-"); } if (layer_time) { - printf("%-22p %-10u %-10u %-10llu %-10llu %-10llu %-5d %s\n", - pack_info->sock, pack_info->seq, pack_info->ack, - pack_info->mac_time, pack_info->ip_time, + printf("%-22p %-20s %-8d %-20s %-8d %-14llu %-14llu %-14llu %-15d " + "%-16s", + pack_info->sock, + inet_ntop(AF_INET, &saddr, s_str, sizeof(s_str)), + pack_info->sport, + inet_ntop(AF_INET, &daddr, d_str, sizeof(d_str)), + pack_info->dport, pack_info->mac_time, pack_info->ip_time, pack_info->tran_time, pack_info->rx, http_data); fprintf( file, - "packet{sock=\"%p\",seq=\"%u\",ack=\"%u\"," + "packet{sock=\"%p\",saddr=\"%s\",sport=\"%d\",daddr=\"%s\"," + "dport=\"%d\",seq=\"%u\",ack=\"%u\"," "mac_time=\"%llu\",ip_time=\"%llu\",tran_time=\"%llu\",http_" "info=\"%s\",rx=\"%d\"} \n", - pack_info->sock, pack_info->seq, pack_info->ack, + pack_info->sock, + inet_ntop(AF_INET, &saddr, s_str, sizeof(s_str)), + pack_info->sport, + inet_ntop(AF_INET, &daddr, d_str, sizeof(d_str)), + pack_info->dport, pack_info->seq, pack_info->ack, pack_info->mac_time, pack_info->ip_time, pack_info->tran_time, http_data, pack_info->rx); } else { - printf("%-22p %-10u %-10u %-10d %-10d %-10d %-5d %s\n", - pack_info->sock, pack_info->seq, pack_info->ack, 0, 0, 0, - pack_info->rx, http_data); + printf("%-22p %-20s %-8d %-20s %-8d %-10d %-10d %-10d %-5d %-10s", + pack_info->sock, + inet_ntop(AF_INET, &saddr, s_str, sizeof(s_str)), + pack_info->sport, + inet_ntop(AF_INET, &daddr, d_str, sizeof(d_str)), + pack_info->dport, 0, 0, 0, pack_info->rx, http_data); fprintf(file, - "packet{sock=\"%p\",seq=\"%u\",ack=\"%u\"," + "packet{sock=\"%p\",saddr=\"%s\",sport=\"%d\",daddr=\"%s\"," + "dport=\"%d\",seq=\"%u\",ack=\"%u\"," "mac_time=\"%d\",ip_time=\"%d\",tran_time=\"%d\",http_" "info=\"%s\",rx=\"%d\"} \n", - pack_info->sock, pack_info->seq, pack_info->ack, 0, 0, 0, + pack_info->sock, + inet_ntop(AF_INET, &saddr, s_str, sizeof(s_str)), + pack_info->sport, + inet_ntop(AF_INET, &daddr, d_str, sizeof(d_str)), + pack_info->dport, pack_info->seq, pack_info->ack, 0, 0, 0, http_data, pack_info->rx); } fclose(file); } + if (time_load) { + int mac = process_delay(pack_info->mac_time, 0); + int ip = process_delay(pack_info->ip_time, 1); + int tran = process_delay(pack_info->tran_time, 2); + if (mac || ip || tran) { + printf("%-15s", "abnormal data"); + } + } + printf("\n"); return 0; } static int print_udp(void *ctx, void *packet_info, size_t size) { if (!udp_info) return 0; - FILE *file = fopen(udp_file_path, "a+");//追加 - if (file == NULL) { + FILE *file = fopen(udp_file_path, "a+"); // 追加 + if (file == NULL) { fprintf(stderr, "Failed to open udp.log: (%s)\n", strerror(errno)); return 0; } @@ -286,44 +975,546 @@ static int print_udp(void *ctx, void *packet_info, size_t size) { const struct udp_message *pack_info = packet_info; unsigned int saddr = pack_info->saddr; unsigned int daddr = pack_info->daddr; - if(udp_info) - { - printf("%-20s %-20s %-20u %-20u %-20llu %-20d %-20d\n", + if (pack_info->tran_time > MAXTIME || (daddr & 0x0000FFFF) == 0x0000007F || + (saddr & 0x0000FFFF) == 0x0000007F) + return 0; + printf("%-20s %-20s %-20u %-20u %-20llu %-20d %-20d", inet_ntop(AF_INET, &saddr, s_str, sizeof(s_str)), inet_ntop(AF_INET, &daddr, d_str, sizeof(d_str)), pack_info->sport, - pack_info->dport, pack_info->tran_time,pack_info->rx,pack_info->len); - fprintf( - file, + pack_info->dport, pack_info->tran_time, pack_info->rx, + pack_info->len); + fprintf(file, "packet{saddr=\"%s\",daddr=\"%s\",sport=\"%u\"," "dport=\"%u\",udp_time=\"%llu\",rx=\"%d\",len=\"%d\"} \n", inet_ntop(AF_INET, &saddr, s_str, sizeof(s_str)), inet_ntop(AF_INET, &daddr, d_str, sizeof(d_str)), pack_info->sport, - pack_info->dport, pack_info->tran_time,pack_info->rx,pack_info->len); - //fseek(file, 0, SEEK_END); //指针移动到文件头部 - } - + pack_info->dport, pack_info->tran_time, pack_info->rx, + pack_info->len); fclose(file); + if (time_load) { + int flag = process_delay(pack_info->tran_time, 3); + if (flag) + printf("%-15s", "abnormal data"); + } + printf("\n"); return 0; } static int print_netfilter(void *ctx, void *packet_info, size_t size) { - if(!net_filter) + if (!net_filter) return 0; char d_str[INET_ADDRSTRLEN]; - char s_str[INET_ADDRSTRLEN]; + char s_str[INET_ADDRSTRLEN]; const struct netfilter *pack_info = packet_info; + if (pack_info->local_input_time > MAXTIME || + pack_info->forward_time > MAXTIME || + pack_info->local_out_time > MAXTIME || + pack_info->post_routing_time > MAXTIME || + pack_info->pre_routing_time > MAXTIME) + return 0; unsigned int saddr = pack_info->saddr; unsigned int daddr = pack_info->daddr; - if(net_filter) - { - printf("%-20s %-20s %-20u %-20u %-20llu %-20llu %-20llu %-20llu %-20d\n", + // if ((daddr & 0x0000FFFF) == 0x0000007F || + // (saddr & 0x0000FFFF) == 0x0000007F) + // return 0; + printf("%-20s %-20s %-12d %-12d %-8lld %-8lld% -8lld %-8lld %-8lld %-8d", + inet_ntop(AF_INET, &saddr, s_str, sizeof(s_str)), + inet_ntop(AF_INET, &daddr, d_str, sizeof(d_str)), pack_info->sport, + pack_info->dport, pack_info->pre_routing_time, + pack_info->local_input_time, pack_info->forward_time, + pack_info->post_routing_time, pack_info->local_out_time, + pack_info->rx); + // 定义一个数组用于存储需要检测的时延数据和对应的层索引 + struct LayerDelayInfo layer_delay_infos[] = { + {pack_info->pre_routing_time, 4}, + {pack_info->local_input_time, 5}, + {pack_info->forward_time, 6}, + {pack_info->post_routing_time, 7}, + {pack_info->local_out_time, 8}}; + if (time_load) { + // 循环遍历数组 + for (int i = 0; i < 5; i++) { + // 数组的总字节数除以第一个元素的字节数得到元素的个数 + float delay = layer_delay_infos[i].delay; + int layer_net = layer_delay_infos[i].layer_index; + int flag = process_delay(delay, layer_net); + if (flag) + printf("%-15s", "abnormal data"); + } + } + printf("\n"); + + return 0; +} +static int print_tcpstate(void *ctx, void *packet_info, size_t size) { + if (!tcp_info) + return 0; + char d_str[INET_ADDRSTRLEN]; + char s_str[INET_ADDRSTRLEN]; + const struct tcp_state *pack_info = packet_info; + unsigned int saddr = pack_info->saddr; + unsigned int daddr = pack_info->daddr; + printf("%-20s %-20s %-20d %-20d %-20s %-20s %-20lld\n", + inet_ntop(AF_INET, &saddr, s_str, sizeof(s_str)), + inet_ntop(AF_INET, &daddr, d_str, sizeof(d_str)), pack_info->sport, + pack_info->dport, tcp_states[pack_info->oldstate], + tcp_states[pack_info->newstate], pack_info->time); + + return 0; +} +static void calculate_protocol_usage(struct packet_count proto_stats[], + int num_protocols, int interval) { + static uint64_t last_rx[256] = {0}, last_tx[256] = {0}; + uint64_t current_rx = 0, current_tx = 0; + uint64_t delta_rx[256] = {0}, delta_tx[256] = {0}; + //遍历所有的协议 + for (int i = 0; i < num_protocols; i++) { + //计算数据包增量 + if (proto_stats[i].rx_count >= last_rx[i]) { + delta_rx[i] = proto_stats[i].rx_count - last_rx[i]; + } else { + delta_rx[i] = proto_stats[i].rx_count; + } + + if (proto_stats[i].tx_count >= last_tx[i]) { + delta_tx[i] = proto_stats[i].tx_count - last_tx[i]; + } else { + delta_tx[i] = proto_stats[i].tx_count; + } + //时间段内总的接收和发送包数 + current_rx += delta_rx[i]; + current_tx += delta_tx[i]; + //更新上次统计的包数 + last_rx[i] = proto_stats[i].rx_count; + last_tx[i] = proto_stats[i].tx_count; + } + printf("Protocol Usage in Last %d Seconds:\n", interval); + printf("Total_rx_count:%ld Total_tx_count:%ld\n", current_rx, current_tx); + + if (current_rx > 0) { + printf("Receive Protocol Usage:\n"); + for (int i = 0; i < num_protocols; i++) { + if (delta_rx[i] > 0) { + double rx_percentage = (double)delta_rx[i] / current_rx * 100; + if (rx_percentage >= 80.0) { + printf(RED_TEXT + "Protocol %s: %.2f%% Rx_count:%ld\n" RESET_TEXT, + protocol[i], rx_percentage, delta_rx[i]); + } else { + printf("Protocol %s: %.2f%% Rx_count:%ld\n", protocol[i], + rx_percentage, delta_rx[i]); + } + } + } + } + if (current_tx > 0) { + printf("Transmit Protocol Usage:\n"); + for (int i = 0; i < num_protocols; i++) { + if (delta_tx[i] > 0) { + double tx_percentage = (double)delta_tx[i] / current_tx * 100; + if (tx_percentage >= 80.0) { + printf(RED_TEXT + "Protocol %s: %.2f%% Tx_count:%ld\n" RESET_TEXT, + protocol[i], tx_percentage, delta_tx[i]); + } else { + printf("Protocol %s: %.2f%% Tx_count:%ld\n", protocol[i], + tx_percentage, delta_tx[i]); + } + } + } + } + memset(proto_stats, 0, num_protocols * sizeof(struct packet_count)); +} +static int print_protocol_count(void *ctx, void *packet_info, size_t size) { + const struct packet_info *pack_protocol_info = + (const struct packet_info *)packet_info; + if (!protocol_count) { + return 0; + } + proto_stats[pack_protocol_info->proto].rx_count = + pack_protocol_info->count.rx_count; + proto_stats[pack_protocol_info->proto].tx_count = + pack_protocol_info->count.tx_count; + return 0; +} +static int print_kfree(void *ctx, void *packet_info, size_t size) { + if (!drop_reason) + return 0; + char d_str[INET_ADDRSTRLEN]; + char s_str[INET_ADDRSTRLEN]; + const struct reasonissue *pack_info = packet_info; + unsigned int saddr = pack_info->saddr; + unsigned int daddr = pack_info->daddr; + if (saddr == 0 && daddr == 0) { + return 0; + } + char prot[6]; + if (pack_info->protocol == 2048) { + strcpy(prot, "ipv4"); + } else if (pack_info->protocol == 34525) { + strcpy(prot, "ipv6"); + } else { + // 其他协议 + strcpy(prot, "other"); + } + time_t now = time(NULL); + struct tm *localTime = localtime(&now); + printf("%02d:%02d:%02d %-17s %-17s %-10u %-10u %-10s", + localTime->tm_hour, localTime->tm_min, localTime->tm_sec, + inet_ntop(AF_INET, &saddr, s_str, sizeof(s_str)), + inet_ntop(AF_INET, &daddr, d_str, sizeof(d_str)), pack_info->sport, + pack_info->dport, prot); + if (!addr_to_func) + printf("%-34lx", pack_info->location); + else { + struct SymbolEntry data = findfunc(pack_info->location); + char result[40]; + sprintf(result, "%s+0x%lx", data.name, pack_info->location - data.addr); + printf("%-34s", result); + } + printf("%s\n", SKB_Drop_Reason_Strings[pack_info->drop_reason]); + return 0; +} +static int print_icmptime(void *ctx, void *packet_info, size_t size) { + if (!icmp_info) + return 0; + char d_str[INET_ADDRSTRLEN]; + char s_str[INET_ADDRSTRLEN]; + const struct icmptime *pack_info = packet_info; + if (pack_info->icmp_tran_time > MAXTIME) { + return 0; + } + unsigned int saddr = pack_info->saddr; + unsigned int daddr = pack_info->daddr; + printf("%-20s %-20s %-20lld %-20d", inet_ntop(AF_INET, &saddr, s_str, sizeof(s_str)), inet_ntop(AF_INET, &daddr, d_str, sizeof(d_str)), - pack_info->sport,pack_info->dport,pack_info->local_input_time,pack_info->pre_routing_time,pack_info->local_out_time, - pack_info->post_routing_time,pack_info->flag); + pack_info->icmp_tran_time, pack_info->flag); + if (time_load) { + int icmp_data = process_delay(pack_info->icmp_tran_time, 9); + if (icmp_data) { + printf("%-15s\n", "abnormal data"); + } + } + printf("\n"); + return 0; +} +static int print_rst(void *ctx, void *packet_info, size_t size) { + if (!rst_info) { + return 0; + } + struct reset_event_t *event = packet_info; + + // 将事件存储到全局存储中 + if (event_count < MAX_EVENTS) { + memcpy(&event_store[event_count], event, sizeof(struct reset_event_t)); + event_count++; + } + + rst_count++; + return 0; +} +static void print_stored_events() { + char s_str[INET_ADDRSTRLEN]; + char d_str[INET_ADDRSTRLEN]; + + for (int i = 0; i < event_count; i++) { + struct reset_event_t *event = &event_store[i]; + unsigned int saddr = event->saddr; + unsigned int daddr = event->daddr; + + if (event->family == AF_INET) { + inet_ntop(AF_INET, &saddr, s_str, sizeof(s_str)); + inet_ntop(AF_INET, &daddr, d_str, sizeof(d_str)); + printf("%-20llu %-20s %-20s %-20s %-20u %-20u %-20llu\n", + (unsigned long long)event->pid, event->comm, s_str, d_str, + event->sport, event->dport, + (unsigned long long)event->timestamp); + } else if (event->family == AF_INET6) { + char saddr_v6[INET6_ADDRSTRLEN]; + char daddr_v6[INET6_ADDRSTRLEN]; + inet_ntop(AF_INET6, &event->saddr_v6, saddr_v6, sizeof(saddr_v6)); + inet_ntop(AF_INET6, &event->daddr_v6, daddr_v6, sizeof(daddr_v6)); + printf("%-10llu %-16s %-16s %-16s %-8u %-8u %-20llu\n", + (unsigned long long)event->pid, event->comm, saddr_v6, + daddr_v6, event->sport, event->dport, + (unsigned long long)event->timestamp); + } + } +} +static void print_domain_name(const unsigned char *data, char *output) { + const unsigned char *next = data; + int pos = 0, first = 1; + // 循环到尾部,标志0 + while (*next != 0) { + if (!first) { + output[pos++] = '.'; // 在每个段之前添加点号 + } else { + first = 0; // 第一个段后清除标志 + } + int len = *next++; // 下一个段长度 + + for (int i = 0; i < len; ++i) { + output[pos++] = *next++; + } + } + output[pos] = '\0'; // 确保字符串正确结束 +} +static int print_dns(void *ctx, void *packet_info, size_t size) { + if (!packet_info) + return 0; + char d_str[INET_ADDRSTRLEN]; + char s_str[INET_ADDRSTRLEN]; + const struct dns_information *pack_info = + (const struct dns_information *)packet_info; // 强制类型转换 + unsigned int saddr = pack_info->saddr; + unsigned int daddr = pack_info->daddr; + char domain_name[256]; // 用于存储输出的域名 + + inet_ntop(AF_INET, &saddr, s_str, sizeof(s_str)); + inet_ntop(AF_INET, &daddr, d_str, sizeof(d_str)); + + print_domain_name((const unsigned char *)pack_info->data, domain_name); + if (pack_info->daddr == 0) { + return 0; + } + printf("%-20s %-20s %-#12x %-#12x %-5x %-5x %-5x %-5x %-47s %-10d %-10d " + "%-10d \n", + s_str, d_str, pack_info->id, pack_info->flags, pack_info->qdcount, + pack_info->ancount, pack_info->nscount, pack_info->arcount, + domain_name, pack_info->request_count, pack_info->response_count, + pack_info->rx); + return 0; +} +static int print_mysql(void *ctx, void *packet_info, size_t size) { + if (!mysql_info) { + return 0; + } + + const mysql_query *pack_info = packet_info; + printf("%-20d %-20d %-20s %-20u %-41s", pack_info->pid, pack_info->tid, + pack_info->comm, pack_info->size, pack_info->msql); + if (pack_info->duratime > count_info) { + printf("%-21llu", pack_info->duratime); + } else { + printf("%-21s", ""); + } + printf("%-20d\n", pack_info->count); + return 0; +} +static int print_redis(void *ctx, void *packet_info, size_t size) { + const struct redis_query *pack_info = packet_info; + int i = 0; + char redis[64]; + for (i = 0; i < pack_info->argc; i++) { + strcat(redis, pack_info->redis[i]); + strcat(redis, " "); + } + printf("%-20d %-20s %-20d %-20s %-21llu\n", pack_info->pid, pack_info->comm, + pack_info->argc, redis, pack_info->duratime); + strcpy(redis, ""); + return 0; +} +static int process_redis_first(char flag,char *message) { + if(flag=='+') + { + strcpy(message, "Status Reply"); + } + else if (flag=='-') + { + strcpy(message, "Error Reply"); + } + else if (flag==':') + { + strcpy(message, "Integer Reply"); + } + else if (flag=='$') + { + strcpy(message, "Bulk String Reply"); + } + else if (flag=='*') + { + strcpy(message, "Array Reply"); + } + else{ + strcpy(message, "Unknown Type"); + } + return 0; +} + +static int print_redis_stat(void *ctx, void *packet_info, size_t size) { + if (!redis_stat) { + return 0; + } + char message[20]={}; + const struct redis_stat_query *pack_info = packet_info; + if(pack_info->key_count) + { + printf("%-20d %-20s %-20s %-20d %-20s %-20s\n", pack_info->pid, pack_info->comm, + pack_info->key,pack_info->key_count,"-","-"); + } + else + { + process_redis_first(pack_info->value[0],message); + printf("%-20d %-20s %-20s %-20s %-20s %-20s\n", pack_info->pid, pack_info->comm, + "-","-",message,pack_info->value); + } + + return 0; +} + +static int libbpf_print_fn(enum libbpf_print_level level, const char *format, + va_list args) { + return vfprintf(stderr, format, args); +} +static void show_stack_trace(__u64 *stack, int stack_sz, pid_t pid) { + int i; + printf("-----------------------------------\n"); + for (i = 1; i < stack_sz; i++) { + if (addr_to_func) { + struct SymbolEntry data = findfunc(stack[i]); + char result[40]; + sprintf(result, "%s+0x%llx", data.name, stack[i] - data.addr); + printf("%-10d [<%016llx>]=%s\n", i, stack[i], result); + } else { + printf("%-10d [<%016llx>]\n", i, stack[i]); + } } + printf("-----------------------------------\n"); +} +static int print_trace(void *_ctx, void *data, size_t size) { + struct stacktrace_event *event = data; + + if (event->kstack_sz <= 0 && event->ustack_sz <= 0) + return 1; + + printf("COMM: %s (pid=%d) @ CPU %d\n", event->comm, event->pid, + event->cpu_id); + + if (event->kstack_sz > 0) { + printf("Kernel:\n"); + show_stack_trace(event->kstack, event->kstack_sz / sizeof(__u64), 0); + } else { + printf("No Kernel Stack\n"); + } + printf("\n"); return 0; } +static int print_rtt(void *ctx, void *data, size_t size) { + if (!rtt_info) + return 0; + struct RTT *rtt_tuple = data; + unsigned long long total_latency = 0; + unsigned long long total_count = 0; + char d_str[INET_ADDRSTRLEN]; + char s_str[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &rtt_tuple->saddr, s_str, sizeof(s_str)); + inet_ntop(AF_INET, &rtt_tuple->daddr, d_str, sizeof(d_str)); + if ((rtt_tuple->saddr & 0x0000FFFF) == 0x0000007F || + (rtt_tuple->daddr & 0x0000FFFF) == 0x0000007F || + rtt_tuple->saddr == htonl(0xC0A83C01) || + rtt_tuple->daddr == htonl(0xC0A83C01)) { + return 0; // 如果匹配任一过滤条件,放弃处理这些数据包 + } + // 打印源地址和目的地址 + printf("Source Address: %s\n", s_str); + printf("Destination Address: %s\n", d_str); + // 更新总延迟和计数 + total_latency += rtt_tuple->latency; + total_count += rtt_tuple->cnt; + // 打印总延迟和平均RTT + double average_rtt = + (total_count > 0) ? (double)total_latency / total_count : 0; + printf("Total Latency: %llu μs\n", total_latency); + printf("Average RTT: %.2f ms\n", average_rtt / 1000.0); + + // 计算和打印RTT分布图 + printf(" usecs : count distribution\n"); + int bucket_size = 1; + for (int i = 0; i < MAX_SLOTS; i++) { + int start_range = bucket_size == 1 ? 0 : bucket_size; + int end_range = bucket_size * 2 - 1; + printf("%8d -> %-8d : %-8llu |", start_range, end_range, + rtt_tuple->slots[i]); + int bar_length = + rtt_tuple->slots[i] / + 10; //计算该延迟范围内的计数对应的直方图条形长度,每个'*' + //表示 10 个计数 + for (int j = 0; j < bar_length; j++) { + printf("*"); + } + printf("\n"); + bucket_size *= 2; //以对数方式扩展 + } + printf("===============================================================\n"); + return 0; +} +int attach_uprobe_mysql(struct net_watcher_bpf *skel) { + + ATTACH_UPROBE_CHECKED( + skel, _Z16dispatch_commandP3THDPK8COM_DATA19enum_server_command, + query__start); + ATTACH_URETPROBE_CHECKED( + skel, _Z16dispatch_commandP3THDPK8COM_DATA19enum_server_command, + query__end); + return 0; +} +int attach_uprobe_redis(struct net_watcher_bpf *skel) { + if(redis_info){ + ATTACH_UPROBE_CHECKED(skel, call, redis_call); + ATTACH_UPROBE_CHECKED(skel, processCommand, redis_processCommand); + } + if(redis_stat){ + ATTACH_UPROBE_CHECKED(skel, lookupKey, redis_lookupKey); + ATTACH_UPROBE_CHECKED(skel, addReply, redis_addReply); + } + return 0; +} + +void print_top_5_keys() { + kv_pair *pairs; + pairs = malloc(sizeof(kv_pair) * 1024); + if (!pairs) { + perror("Failed to allocate memory"); + exit(EXIT_FAILURE); + } + int index = 0; + char *key = NULL; + while (bpf_map_get_next_key(map_fd, &key, &key) == 0) { + // fprintf(stdout, "next_sk: (%p)\n", sk); + int count; + int err = bpf_map_lookup_elem(map_fd, &key, &count); + if (err) { + fprintf(stderr, "Failed to read value from the conns map: (%s)\n", + strerror(errno)); + return ; + } + memcpy(pairs[index].key, &key, 256); + pairs[index].value = count; + //printf("Key: %s, Count: %u\n", pairs[index].key, pairs[index].value); + index++; + } + // 获取所有键值对 + + // 排序前 5 个元素 + // 简单选择排序(可替换为其他高效排序算法) + for (int i = 0; i < index - 1; i++) { + for (int j = i + 1; j < index; j++) { + if (pairs[j].value > pairs[i].value) { + kv_pair temp = pairs[i]; + pairs[i] = pairs[j]; + pairs[j] = temp; + } + } + } + printf("----------------------------\n"); + // 打印前 5 个元素 + printf("Top 5 Keys:\n"); + for (int i = 0; i < 5 && i < index; i++) { + printf("Key: %s, Count: %u\n", pairs[i].key, pairs[i].value); + } + free(pairs); +} int main(int argc, char **argv) { char *last_slash = strrchr(argv[0], '/'); if (last_slash) { @@ -333,13 +1524,28 @@ int main(int argc, char **argv) { strcpy(err_file_path, argv[0]); strcpy(packets_file_path, argv[0]); strcpy(udp_file_path, argv[0]); - strcat(connects_file_path, "data/connects.log"); - strcat(err_file_path, "data/err.log"); - strcat(packets_file_path, "data/packets.log"); - strcat(udp_file_path,"data/udp.log"); + if (connects_file_path[strlen(connects_file_path) - 1] != '/') + strcat(connects_file_path, "/connects.log"); + else + strcat(connects_file_path, "connects.log"); + // strcat(connects_file_path, "./connects.log"); + strcat(err_file_path, "./err.log"); + strcat(packets_file_path, "./packets.log"); + strcat(udp_file_path, "./udp.log"); struct ring_buffer *rb = NULL; struct ring_buffer *udp_rb = NULL; struct ring_buffer *netfilter_rb = NULL; + struct ring_buffer *kfree_rb = NULL; + struct ring_buffer *icmp_rb = NULL; + struct ring_buffer *tcp_rb = NULL; + struct ring_buffer *dns_rb = NULL; + struct ring_buffer *trace_rb = NULL; + struct ring_buffer *mysql_rb = NULL; + struct ring_buffer *redis_rb = NULL; + struct ring_buffer *redis_stat_rb = NULL; + struct ring_buffer *rtt_rb = NULL; + struct ring_buffer *events = NULL; + struct ring_buffer *port_rb = NULL; struct net_watcher_bpf *skel; int err; /* Parse command line arguments */ @@ -348,97 +1554,176 @@ int main(int argc, char **argv) { if (err) return err; } - + libbpf_set_print(libbpf_print_fn); /* Cleaner handling of Ctrl-C */ signal(SIGINT, sig_handler); signal(SIGTERM, sig_handler); - /* Open load and verify BPF application */ skel = net_watcher_bpf__open(); if (!skel) { fprintf(stderr, "Failed to open BPF skeleton\n"); return 1; } - /* Parameterize BPF code */ - skel->rodata->filter_dport = dport; - skel->rodata->filter_sport = sport; - skel->rodata->all_conn = all_conn; - skel->rodata->err_packet = err_packet; - skel->rodata->extra_conn_info = extra_conn_info; - skel->rodata->layer_time = layer_time; - skel->rodata->http_info = http_info; - skel->rodata->retrans_info = retrans_info; - skel->rodata->udp_info = udp_info; - skel->rodata->net_filter = net_filter; + set_rodata_flags(skel); + set_disable_load(skel); + if (addr_to_func) + readallsym(); err = net_watcher_bpf__load(skel); if (err) { fprintf(stderr, "Failed to load and verify BPF skeleton\n"); goto cleanup; } - /* Attach tracepoint handler */ - err = net_watcher_bpf__attach(skel); - if (err) { - fprintf(stderr, "Failed to attach BPF skeleton\n"); + if (mysql_info) { + strcpy(binary_path, "/usr/sbin/mysqld"); + err = attach_uprobe_mysql(skel); + if (err) { + fprintf(stderr, "failed to attach uprobes\n"); + + goto cleanup; + } + } else if (redis_info||redis_stat) { + strcpy(binary_path, "/usr/bin/redis-server"); + err = attach_uprobe_redis(skel); + if (err) { + fprintf(stderr, "failed to attach uprobes\n"); + + goto cleanup; + } + } else { + err = net_watcher_bpf__attach(skel); + if (err) { + fprintf(stderr, "Failed to attach BPF skeleton\n"); + goto cleanup; + } + } + enum MonitorMode mode = get_monitor_mode(); + + // print_logo(); + + print_header(mode); + + udp_rb = + ring_buffer__new(bpf_map__fd(skel->maps.udp_rb), print_udp, NULL, NULL); + if (!udp_rb) { + err = -1; + fprintf(stderr, "Failed to create ring buffer(udp)\n"); goto cleanup; } - if (udp_info) { - printf("%-20s %-20s %-20s %-20s %-20s %-20s %-20s\n", "saddr", "daddr", "sprot", - "dprot", "udp_time","rx","len"); + netfilter_rb = ring_buffer__new(bpf_map__fd(skel->maps.netfilter_rb), + print_netfilter, NULL, NULL); + if (!netfilter_rb) { + err = -1; + fprintf(stderr, "Failed to create ring buffer(netfilter)\n"); + goto cleanup; } - else if(net_filter) - { - printf("%-20s %-20s %-20s %-20s %-20s %-20s %-20s %-20s %-20s\n", "saddr", "daddr","dprot", "sprot","local_input","pre_routing","local_out","post_routing","flag"); + kfree_rb = ring_buffer__new(bpf_map__fd(skel->maps.kfree_rb), print_kfree, + NULL, NULL); + if (!kfree_rb) { + err = -1; + fprintf(stderr, "Failed to create ring buffer(kfree)\n"); + goto cleanup; } - else{ - printf("%-22s %-10s %-10s %-10s %-10s %-10s %-5s %s\n", "SOCK", "SEQ", - "ACK", "MAC_TIME", "IP_TIME", "TRAN_TIME", "RX", "HTTP"); + icmp_rb = ring_buffer__new(bpf_map__fd(skel->maps.icmp_rb), print_icmptime, + NULL, NULL); + if (!icmp_rb) { + err = -1; + fprintf(stderr, "Failed to create ring buffer(icmp)\n"); + goto cleanup; } - udp_rb =ring_buffer__new(bpf_map__fd(skel->maps.udp_rb), print_udp, NULL, NULL); - if (!udp_rb) { + tcp_rb = ring_buffer__new(bpf_map__fd(skel->maps.tcp_rb), print_tcpstate, + NULL, NULL); + if (!tcp_rb) { err = -1; - fprintf(stderr, "Failed to create ring buffer\n"); + fprintf(stderr, "Failed to create ring buffer(tcp)\n"); goto cleanup; } - netfilter_rb =ring_buffer__new(bpf_map__fd(skel->maps.netfilter_rb), print_netfilter, NULL, NULL); - if (!netfilter_rb) { + dns_rb = + ring_buffer__new(bpf_map__fd(skel->maps.dns_rb), print_dns, NULL, NULL); + if (!dns_rb) { err = -1; - fprintf(stderr, "Failed to create ring buffer\n"); + fprintf(stderr, "Failed to create ring buffer(dns)\n"); goto cleanup; } - /* Set up ring buffer polling */ - rb = ring_buffer__new(bpf_map__fd(skel->maps.rb), print_packet, NULL, NULL); - if (!rb) { + trace_rb = ring_buffer__new(bpf_map__fd(skel->maps.trace_rb), print_trace, + NULL, NULL); + if (!trace_rb) { err = -1; - fprintf(stderr, "Failed to create ring buffer\n"); + fprintf(stderr, "Failed to create ring buffer(trace)\n"); goto cleanup; } - FILE *err_file = fopen(err_file_path, "w+"); - if (err_file == NULL) { - fprintf(stderr, "Failed to open err.log: (%s)\n", strerror(errno)); - return 0; + mysql_rb = ring_buffer__new(bpf_map__fd(skel->maps.mysql_rb), print_mysql, + NULL, NULL); + if (!mysql_rb) { + err = -1; + fprintf(stderr, "Failed to create ring buffer(trace)\n"); + goto cleanup; } - fclose(err_file); - FILE *packet_file = fopen(packets_file_path, "w+"); - if (packet_file == NULL) { - fprintf(stderr, "Failed to open packets.log: (%s)\n", strerror(errno)); - return 0; + redis_rb = ring_buffer__new(bpf_map__fd(skel->maps.redis_rb), print_redis, + NULL, NULL); + if (!redis_rb) { + err = -1; + fprintf(stderr, "Failed to create ring buffer(trace)\n"); + goto cleanup; } - fclose(packet_file); - FILE *udp_file = fopen(udp_file_path, "w+"); - if (udp_file == NULL) { - fprintf(stderr, "Failed to open udp.log: (%s)\n", strerror(errno)); - return 0; + redis_stat_rb = ring_buffer__new(bpf_map__fd(skel->maps.redis_stat_rb), print_redis_stat, + NULL, NULL); + if (!redis_stat_rb) { + err = -1; + fprintf(stderr, "Failed to create ring buffer(trace)\n"); + goto cleanup; + } + rtt_rb = + ring_buffer__new(bpf_map__fd(skel->maps.rtt_rb), print_rtt, NULL, NULL); + if (!rtt_rb) { + err = -1; + fprintf(stderr, "Failed to create ring buffer(connect_rb)\n"); + goto cleanup; + } + events = + ring_buffer__new(bpf_map__fd(skel->maps.events), print_rst, NULL, NULL); + if (!events) { + err = -1; + fprintf(stderr, "Failed to create ring buffer(rst_rb)\n"); + goto cleanup; + } + + port_rb = ring_buffer__new(bpf_map__fd(skel->maps.port_rb), + print_protocol_count, NULL, NULL); + if (!port_rb) { + err = -1; + fprintf(stderr, "Failed to create ring buffer(trace)\n"); + goto cleanup; + } + /* Set up ring buffer polling */ + rb = ring_buffer__new(bpf_map__fd(skel->maps.rb), print_packet, NULL, NULL); + if (!rb) { + err = -1; + fprintf(stderr, "Failed to create ring buffer(packet)\n"); + goto cleanup; } - fclose(udp_file); + //open_log_files(); + struct timeval start, end; + gettimeofday(&start, NULL); /* Process events */ while (!exiting) { err = ring_buffer__poll(rb, 100 /* timeout, ms */); err = ring_buffer__poll(udp_rb, 100 /* timeout, ms */); err = ring_buffer__poll(netfilter_rb, 100 /* timeout, ms */); + err = ring_buffer__poll(kfree_rb, 100 /* timeout, ms */); + err = ring_buffer__poll(icmp_rb, 100 /* timeout, ms */); + err = ring_buffer__poll(tcp_rb, 100 /* timeout, ms */); + err = ring_buffer__poll(dns_rb, 100 /* timeout, ms */); + err = ring_buffer__poll(trace_rb, 100 /* timeout, ms */); + err = ring_buffer__poll(mysql_rb, 100 /* timeout, ms */); + err = ring_buffer__poll(redis_rb, 100 /* timeout, ms */); + err = ring_buffer__poll(rtt_rb, 100 /* timeout, ms */); + err = ring_buffer__poll(events, 100 /* timeout, ms */); + err = ring_buffer__poll(port_rb, 100 /* timeout, ms */); + err = ring_buffer__poll(redis_stat_rb, 100 /* timeout, ms */); print_conns(skel); sleep(1); /* Ctrl-C will cause -EINTR */ @@ -450,8 +1735,28 @@ int main(int argc, char **argv) { printf("Error polling perf buffer: %d\n", err); break; } - } + gettimeofday(&end, NULL); + if ((end.tv_sec - start.tv_sec) >= 5) { + if (rst_info) { + print_stored_events(); + printf("Total RSTs in the last 5 seconds: %llu\n\n",rst_count); + rst_count = 0; + event_count = 0; + }else if (protocol_count) { + calculate_protocol_usage(proto_stats, 256, 5); + }else if(redis_stat) + { + map_fd = bpf_map__fd(skel->maps.key_count); + if (map_fd < 0) { + perror("Failed to get map FD"); + return 1; + } + print_top_5_keys(); + } + gettimeofday(&start, NULL); + } + } cleanup: net_watcher_bpf__destroy(skel); return err < 0 ? -err : 0; From ec5972cf3059b636cc1c08507ba440c1b582034c Mon Sep 17 00:00:00 2001 From: wynyibo Date: Thu, 26 Sep 2024 23:07:22 +0800 Subject: [PATCH 06/13] adaptation version --- .../backend/net/net_watcher/CMakeLists.txt | 38 ++++++++++++++++++- .../backend/net/net_watcher/bpf/common.bpf.h | 12 +++--- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/MagicEyes/src/backend/net/net_watcher/CMakeLists.txt b/MagicEyes/src/backend/net/net_watcher/CMakeLists.txt index 9ff84ac2b..4be5ef3ae 100644 --- a/MagicEyes/src/backend/net/net_watcher/CMakeLists.txt +++ b/MagicEyes/src/backend/net/net_watcher/CMakeLists.txt @@ -53,4 +53,40 @@ set(CPU_WATCHER_INSTALL_DIR backend/${TOOL_BELONG_TO_MODULE}/${TOOL_NAME}) # 安装可执行文件到 ${CPU_WATCHER_INSTALL_DIR}/bin install(TARGETS ${TOOL_NAME} RUNTIME DESTINATION ${CPU_WATCHER_INSTALL_DIR}/bin) -# 安装配置文件到 ${CPU_WATCHER_INSTALL_DIR}/etc \ No newline at end of file +# 安装配置文件到 ${CPU_WATCHER_INSTALL_DIR}/etc + +# 获取内核版本信息 +execute_process( + COMMAND uname -r # 运行命令 'uname -r' 来获取内核版本 + OUTPUT_VARIABLE VERSION_INFO # 将输出结果存储在变量 VERSION_INFO 中 + OUTPUT_STRIP_TRAILING_WHITESPACE # 去除输出末尾的空白字符 +) + +# 输出原始内核版本信息 +message(STATUS "Raw Kernel Version: ${VERSION_INFO}") + +# 使用 '-' 分隔版本信息,存储到 VERSION_PARTS 列表中 +string(REPLACE "-" ";" VERSION_PARTS ${VERSION_INFO}) + +list(GET VERSION_PARTS 0 VERSION_BASE) + +# 从 VERSION_BASE 中提取主、次和补丁版本号 +string(REPLACE "." ";" VERSION_NUMBERS ${VERSION_BASE}) # 用 '.' 分隔 +list(GET VERSION_NUMBERS 0 VERSION_MAJOR) # 获取主版本号 +list(GET VERSION_NUMBERS 1 VERSION_MINOR) # 获取次版本号 +list(GET VERSION_NUMBERS 2 VERSION_PATCH) # 获取补丁版本号 + +# 输出解析后的版本号信息 +message(STATUS "Kernel Major: ${VERSION_MAJOR}, Minor: ${VERSION_MINOR}, Patch: ${VERSION_PATCH}") + +# 定义最小支持的版本 +set(MIN_MAJOR 6) # 最小主版本号 +set(MIN_MINOR 4) # 最小次版本号 +set(MIN_PATCH 0) # 最小补丁版本号 + +# 根据版本比较结果来定义宏 +if(VERSION_MAJOR GREATER ${MIN_MAJOR} OR # 如果主版本号大于最小主版本号 + (VERSION_MAJOR EQUAL ${MIN_MAJOR} AND VERSION_MINOR GREATER ${MIN_MINOR}) OR # 或者主版本号等于最小主版本号且次版本号大于最小次版本号 + (VERSION_MAJOR EQUAL ${MIN_MAJOR} AND VERSION_MINOR EQUAL ${MIN_MINOR} AND VERSION_PATCH GREATER_EQUAL ${MIN_PATCH})) # 或者主、次版本号均相等且补丁版本号大于或等于最小补丁版本号 + add_definitions(-DUSE_NEW_GET_USER_DATA) # 如果满足条件,则定义宏 USE_NEW_GET_USER_DATA +endif() diff --git a/MagicEyes/src/backend/net/net_watcher/bpf/common.bpf.h b/MagicEyes/src/backend/net/net_watcher/bpf/common.bpf.h index de6d3e5cd..7e48d17e8 100644 --- a/MagicEyes/src/backend/net/net_watcher/bpf/common.bpf.h +++ b/MagicEyes/src/backend/net/net_watcher/bpf/common.bpf.h @@ -499,6 +499,12 @@ const volatile int all_conn = 0, err_packet = 0, extra_conn_info = 0, .sport = BPF_CORE_READ(sk, __sk_common.skc_num), \ .dport = __bpf_ntohs(BPF_CORE_READ(sk, __sk_common.skc_dport)), \ .tran_flag = UDP} +//http data +#ifdef USE_NEW_GET_USER_DATA +#define GET_USER_DATA(msg) BPF_CORE_READ(msg, msg_iter.__iov, iov_base) +#else +#define GET_USER_DATA(msg) BPF_CORE_READ(msg, msg_iter.iov, iov_base) +#endif /* help macro end */ /* help functions */ @@ -614,12 +620,6 @@ int getstack(void *ctx) { return 0; } -#if KERNEL_VERSION(VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH) >= \ - KERNEL_VERSION(6, 3, 1) -#define GET_USER_DATA(msg) BPF_CORE_READ(msg, msg_iter.__iov, iov_base) -#else -#define GET_USER_DATA(msg) BPF_CORE_READ(msg, msg_iter.iov, iov_base) -#endif /* 例子: log2(16384) =14 From 6b67caa271cb2547f3713689194be5b7a2af28d3 Mon Sep 17 00:00:00 2001 From: wynyibo Date: Fri, 27 Sep 2024 10:31:23 +0800 Subject: [PATCH 07/13] update --- .../backend/net/net_watcher/CMakeLists.txt | 43 ++++++++----------- .../backend/net/net_watcher/bpf/common.bpf.h | 9 ++-- 2 files changed, 24 insertions(+), 28 deletions(-) diff --git a/MagicEyes/src/backend/net/net_watcher/CMakeLists.txt b/MagicEyes/src/backend/net/net_watcher/CMakeLists.txt index 4be5ef3ae..ff08451fe 100644 --- a/MagicEyes/src/backend/net/net_watcher/CMakeLists.txt +++ b/MagicEyes/src/backend/net/net_watcher/CMakeLists.txt @@ -54,39 +54,32 @@ set(CPU_WATCHER_INSTALL_DIR backend/${TOOL_BELONG_TO_MODULE}/${TOOL_NAME}) install(TARGETS ${TOOL_NAME} RUNTIME DESTINATION ${CPU_WATCHER_INSTALL_DIR}/bin) # 安装配置文件到 ${CPU_WATCHER_INSTALL_DIR}/etc - -# 获取内核版本信息 +# 获取内核版本 execute_process( - COMMAND uname -r # 运行命令 'uname -r' 来获取内核版本 - OUTPUT_VARIABLE VERSION_INFO # 将输出结果存储在变量 VERSION_INFO 中 - OUTPUT_STRIP_TRAILING_WHITESPACE # 去除输出末尾的空白字符 + COMMAND uname -r + OUTPUT_VARIABLE VERSION_INFO + OUTPUT_STRIP_TRAILING_WHITESPACE ) -# 输出原始内核版本信息 -message(STATUS "Raw Kernel Version: ${VERSION_INFO}") - -# 使用 '-' 分隔版本信息,存储到 VERSION_PARTS 列表中 +# 使用'-'分隔版本 string(REPLACE "-" ";" VERSION_PARTS ${VERSION_INFO}) - list(GET VERSION_PARTS 0 VERSION_BASE) -# 从 VERSION_BASE 中提取主、次和补丁版本号 -string(REPLACE "." ";" VERSION_NUMBERS ${VERSION_BASE}) # 用 '.' 分隔 -list(GET VERSION_NUMBERS 0 VERSION_MAJOR) # 获取主版本号 -list(GET VERSION_NUMBERS 1 VERSION_MINOR) # 获取次版本号 -list(GET VERSION_NUMBERS 2 VERSION_PATCH) # 获取补丁版本号 +# 从VERSION_BASE中提取主、次和补丁版本 +string(REPLACE "." ";" VERSION_NUMBERS ${VERSION_BASE}) +list(GET VERSION_NUMBERS 0 VERSION_MAJOR) +list(GET VERSION_NUMBERS 1 VERSION_MINOR) +list(GET VERSION_NUMBERS 2 VERSION_PATCH) -# 输出解析后的版本号信息 message(STATUS "Kernel Major: ${VERSION_MAJOR}, Minor: ${VERSION_MINOR}, Patch: ${VERSION_PATCH}") -# 定义最小支持的版本 -set(MIN_MAJOR 6) # 最小主版本号 -set(MIN_MINOR 4) # 最小次版本号 -set(MIN_PATCH 0) # 最小补丁版本号 +set(MIN_VERSION_MAJOR 6) +set(MIN_VERSION_MINOR 4) -# 根据版本比较结果来定义宏 -if(VERSION_MAJOR GREATER ${MIN_MAJOR} OR # 如果主版本号大于最小主版本号 - (VERSION_MAJOR EQUAL ${MIN_MAJOR} AND VERSION_MINOR GREATER ${MIN_MINOR}) OR # 或者主版本号等于最小主版本号且次版本号大于最小次版本号 - (VERSION_MAJOR EQUAL ${MIN_MAJOR} AND VERSION_MINOR EQUAL ${MIN_MINOR} AND VERSION_PATCH GREATER_EQUAL ${MIN_PATCH})) # 或者主、次版本号均相等且补丁版本号大于或等于最小补丁版本号 - add_definitions(-DUSE_NEW_GET_USER_DATA) # 如果满足条件,则定义宏 USE_NEW_GET_USER_DATA +if(MAJOR GREATER MIN_VERSION_MAJOR OR (MAJOR EQUAL MIN_VERSION_MAJOR AND MINOR GREATER_EQUAL MIN_VERSION_MINOR)) + add_definitions(-DUSE_NEW_GET_USER_DATA) +else() + add_definitions(-DUSE_OLD_GET_USER_DATA) endif() + + diff --git a/MagicEyes/src/backend/net/net_watcher/bpf/common.bpf.h b/MagicEyes/src/backend/net/net_watcher/bpf/common.bpf.h index 7e48d17e8..93e5080cf 100644 --- a/MagicEyes/src/backend/net/net_watcher/bpf/common.bpf.h +++ b/MagicEyes/src/backend/net/net_watcher/bpf/common.bpf.h @@ -499,12 +499,15 @@ const volatile int all_conn = 0, err_packet = 0, extra_conn_info = 0, .sport = BPF_CORE_READ(sk, __sk_common.skc_num), \ .dport = __bpf_ntohs(BPF_CORE_READ(sk, __sk_common.skc_dport)), \ .tran_flag = UDP} + + //http data -#ifdef USE_NEW_GET_USER_DATA -#define GET_USER_DATA(msg) BPF_CORE_READ(msg, msg_iter.__iov, iov_base) -#else +#if defined(USE_NEW_GET_USER_DATA) #define GET_USER_DATA(msg) BPF_CORE_READ(msg, msg_iter.iov, iov_base) +#else +#define GET_USER_DATA(msg) BPF_CORE_READ(msg, msg_iter.__iov, iov_base) #endif + /* help macro end */ /* help functions */ From c5bd078c24fa8c89c1177fae319f28f2374944df Mon Sep 17 00:00:00 2001 From: wynyibo Date: Thu, 10 Oct 2024 20:28:24 +0800 Subject: [PATCH 08/13] fix bug --- .../backend/net/net_watcher/bpf/common.bpf.h | 382 +++--- .../backend/net/net_watcher/bpf/drop.bpf.h | 20 +- .../backend/net/net_watcher/bpf/mysql.bpf.h | 8 +- .../net/net_watcher/bpf/net_watcher.bpf.c | 7 +- .../net/net_watcher/bpf/netfilter.bpf.h | 2 +- .../backend/net/net_watcher/bpf/packet.bpf.h | 301 +++-- .../src/backend/net/net_watcher/bpf/tcp.bpf.h | 203 ++-- .../net/net_watcher/include/net_watcher.h | 71 +- .../backend/net/net_watcher/src/net_watcher.c | 1082 ++++++++++------- 9 files changed, 1264 insertions(+), 812 deletions(-) diff --git a/MagicEyes/src/backend/net/net_watcher/bpf/common.bpf.h b/MagicEyes/src/backend/net/net_watcher/bpf/common.bpf.h index 93e5080cf..87a70d5fd 100644 --- a/MagicEyes/src/backend/net/net_watcher/bpf/common.bpf.h +++ b/MagicEyes/src/backend/net/net_watcher/bpf/common.bpf.h @@ -28,7 +28,8 @@ #include #include -struct ktime_info { // us time stamp info发送数据包 +struct ktime_info +{ // us time stamp info发送数据包 u64 qdisc_time; // tx包离开mac层时间戳 u64 mac_time; // tx、rx包到达mac层时间戳 u64 ip_time; // tx、rx包到达ip层时间戳 @@ -39,7 +40,8 @@ struct ktime_info { // us time stamp info发送数据包 u8 data[MAX_HTTP_HEADER]; // 用户层数据 }; -struct packet_tuple { +struct packet_tuple +{ unsigned __int128 saddr_v6; // ipv6 源地址 unsigned __int128 daddr_v6; // ipv6 目的地址 u32 saddr; // 源地址 @@ -52,7 +54,8 @@ struct packet_tuple { u32 len; }; -struct tcpstate { +struct tcpstate +{ u32 saddr; u32 daddr; u16 sport; @@ -63,7 +66,8 @@ struct tcpstate { u64 time; }; -enum { +enum +{ e_ip_rcv = 0, e_ip_local_deliver, e_ip_local_deliver_finish, @@ -75,7 +79,8 @@ enum { nf_max } nf_hook; -enum { +enum +{ PROTO_TCP = 0, PROTO_UDP, PROTO_ICMP, @@ -83,18 +88,21 @@ enum { PROTO_MAX, }; -struct filtertime { +struct filtertime +{ struct packet_tuple init; struct packet_tuple done; u64 time[nf_max]; }; -struct ip_packet { +struct ip_packet +{ unsigned int saddr; // 源地址 unsigned int daddr; // 目的地址 }; -struct dns_header { +struct dns_header +{ u16 id; // 事务ID u16 flags; // 标志字段 u16 qdcount; // 问题部分计数 @@ -103,29 +111,34 @@ struct dns_header { u16 arcount; // 附加记录计数 }; -struct dns_query { +struct dns_query +{ struct dns_header header; // DNS头部 char data[64]; // 可变长度数据(域名+类型+类) }; -struct dns { +struct dns +{ u32 saddr; u32 daddr; }; -struct query_info { +struct query_info +{ char msql[256]; u32 size; u64 start_time; }; -struct hist { +struct hist +{ u64 slots[MAX_SLOTS]; u64 latency; u64 cnt; }; -struct trace_event_raw_tcp_send_reset { +struct trace_event_raw_tcp_send_reset +{ unsigned short common_type; unsigned char common_flags; unsigned char common_preempt_count; @@ -142,7 +155,8 @@ struct trace_event_raw_tcp_send_reset { __u8 daddr_v6[16]; }; -struct trace_event_raw_tcp_receive_reset { +struct trace_event_raw_tcp_receive_reset +{ unsigned short common_type; unsigned char common_flags; unsigned char common_preempt_count; @@ -159,16 +173,17 @@ struct trace_event_raw_tcp_receive_reset { }; #define MAX_CONN 1000 #define MAX_SLOTS 27 -// 操作BPF映射的一个辅助函数 -static __always_inline void * //__always_inline强制内联 -bpf_map_lookup_or_try_init(void *map, const void *key, const void *init) { + +static __always_inline void * +bpf_map_lookup_or_try_init(void *map, const void *key, const void *init) +{ void *val; long err; - val = bpf_map_lookup_elem(map, key); // 在BPF映射中查找具有给定键的条目 + val = bpf_map_lookup_elem(map, key); if (val) return val; - // 此时没有对应key的value + err = bpf_map_update_elem(map, key, init, BPF_NOEXIST); // 向BPF映射中插入或更新一个条目 if (err && err != -EEXIST) // 插入失败 @@ -180,7 +195,8 @@ bpf_map_lookup_or_try_init(void *map, const void *key, const void *init) { char LICENSE[] SEC("license") = "Dual BSD/GPL"; // 存储每个packet_tuple包所对应的ktime_info时间戳 -struct { +struct +{ __uint(type, BPF_MAP_TYPE_LRU_HASH); __uint(max_entries, MAX_CONN *MAX_PACKET); __type(key, struct packet_tuple); @@ -188,78 +204,93 @@ struct { } timestamps SEC(".maps"); // 包相关信息通过此buffer提供给userspace -struct { +struct +{ __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 256 * 1024); } rb SEC(".maps"); -struct { +struct +{ __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 256 * 1024); } rtt_rb SEC(".maps"); -struct { +struct +{ __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 256 * 1024); } udp_rb SEC(".maps"); -struct { +struct +{ __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 256 * 1024); } netfilter_rb SEC(".maps"); -struct { +struct +{ __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 256 * 1024); } mysql_rb SEC(".maps"); -struct { +struct +{ __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 256 * 1024); } redis_rb SEC(".maps"); -struct { +struct +{ __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 256 * 1024); } kfree_rb SEC(".maps"); -struct { +struct +{ __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 256 * 1024); } icmp_rb SEC(".maps"); -struct { +struct +{ __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 256 * 1024); } tcp_rb SEC(".maps"); -struct { +struct +{ __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 256 * 1024); } dns_rb SEC(".maps"); -struct { +struct +{ __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 256 * 1024); } trace_rb SEC(".maps"); -struct { +struct +{ __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 256 * 1024); } redis_stat_rb SEC(".maps"); -struct { +struct +{ __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 256 * 1024); } events SEC(".maps"); -struct { +struct +{ __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 256 * 1024); } port_rb SEC(".maps"); // 存储每个tcp连接所对应的conn_t -struct { +struct +{ __uint(type, BPF_MAP_TYPE_LRU_HASH); __uint(max_entries, MAX_CONN); __type(key, struct sock *); @@ -267,7 +298,8 @@ struct { } conns_info SEC(".maps"); // 根据ptid存储sock指针,从而在上下文无sock的内核探测点获得sock -struct { +struct +{ __uint(type, BPF_MAP_TYPE_LRU_HASH); __uint(max_entries, MAX_CONN); __type(key, u64); @@ -275,35 +307,40 @@ struct { } sock_stores SEC(".maps"); // 存储每个pid所对应的udp包 -struct { +struct +{ __uint(type, BPF_MAP_TYPE_LRU_HASH); __uint(max_entries, MAX_CONN *MAX_PACKET); __type(key, int); __type(value, struct packet_tuple); } pid_UDP SEC(".maps"); -struct { +struct +{ __uint(type, BPF_MAP_TYPE_LRU_HASH); __uint(max_entries, MAX_CONN *MAX_PACKET); __type(key, struct sk_buff *); __type(value, struct filtertime); } netfilter_time SEC(".maps"); -struct { +struct +{ __uint(type, BPF_MAP_TYPE_LRU_HASH); __uint(max_entries, MAX_CONN *MAX_PACKET); __type(key, int); __type(value, struct packet_tuple); } kfree SEC(".maps"); -struct { +struct +{ __uint(type, BPF_MAP_TYPE_LRU_HASH); __uint(max_entries, MAX_CONN *MAX_PACKET); __type(key, struct ip_packet); __type(value, unsigned long long); } icmp_time SEC(".maps"); -struct { +struct +{ __uint(type, BPF_MAP_TYPE_HASH); __uint(max_entries, 256 * 1024); __type(key, struct sock *); @@ -311,7 +348,8 @@ struct { } tcp_state SEC(".maps"); // sql 耗时 -struct { +struct +{ __uint(type, BPF_MAP_TYPE_HASH); __uint(max_entries, 256 * 1024); __type(key, __u32); @@ -319,7 +357,8 @@ struct { } mysql_time SEC(".maps"); // redis 耗时 -struct { +struct +{ __uint(type, BPF_MAP_TYPE_HASH); __uint(max_entries, 256 * 1024); __type(key, __u32); @@ -327,7 +366,8 @@ struct { } redis_time SEC(".maps"); // sql请求数 -struct { +struct +{ __uint(type, BPF_MAP_TYPE_HASH); __uint(max_entries, 1024); __type(key, __u32); @@ -335,21 +375,24 @@ struct { } sql_count SEC(".maps"); // dns计数根据每个saddr、daddr -struct { +struct +{ __uint(type, BPF_MAP_TYPE_HASH); __uint(max_entries, 1024); __type(key, struct dns); __type(value, __u64); } dns_request_count SEC(".maps"); -struct { +struct +{ __uint(type, BPF_MAP_TYPE_HASH); __uint(max_entries, 1024); __type(key, struct dns); __type(value, __u64); } dns_response_count SEC(".maps"); -struct { +struct +{ __uint(type, BPF_MAP_TYPE_HASH); __uint(max_entries, 1024); __type(key, __u32); @@ -357,31 +400,35 @@ struct { } queries SEC(".maps"); // 定义一个哈希映射,用于存储直方图数据 -struct { +struct +{ __uint(type, BPF_MAP_TYPE_HASH); __uint(max_entries, 256 * 1024); __type(key, struct ip_packet); __type(value, struct hist); } hists SEC(".maps"); -struct { +struct +{ __uint(type, BPF_MAP_TYPE_HASH); __type(key, u32); __type(value, u64); __uint(max_entries, 1024); } counters SEC(".maps"); -struct { +struct +{ __uint(type, BPF_MAP_TYPE_ARRAY); __uint(max_entries, MAX_COMM *MAX_PACKET); __type(key, u32); __type(value, struct packet_count); } proto_stats SEC(".maps"); -struct { +struct +{ __uint(type, BPF_MAP_TYPE_HASH); - __type(key, char*); // 键的最大长度,假设为 256 字节 - __type(value, u32); // 计数值 - __uint(max_entries, 1024); // 最大条目数 + __type(key, char *); // 键的最大长度,假设为 256 字节 + __type(value, u32); // 计数值 + __uint(max_entries, 1024); // 最大条目数 } key_count SEC(".maps"); const volatile int filter_dport = 0; @@ -391,117 +438,126 @@ const volatile int all_conn = 0, err_packet = 0, extra_conn_info = 0, udp_info = 0, net_filter = 0, drop_reason = 0, icmp_info = 0, tcp_info = 0, dns_info = 0, stack_info = 0, mysql_info = 0, redis_info = 0, rtt_info = 0, rst_info = 0, - protocol_count = 0,redis_stat = 0;; + protocol_count = 0, redis_stat = 0; +; /* help macro */ -#define FILTER \ - if (filter_dport && filter_dport != pkt_tuple.dport) \ - return 0; \ - if (filter_sport && filter_sport != pkt_tuple.sport) \ +#define FILTER \ + if (filter_dport && filter_dport != pkt_tuple.dport) \ + return 0; \ + if (filter_sport && filter_sport != pkt_tuple.sport) \ return 0; // 连接的目标端口是否匹配于filter_dport的值 -#define FILTER_DPORT \ - if (filter_dport) { \ - if (conn.dport != filter_dport) { \ - return 0; \ - } \ +#define FILTER_DPORT \ + if (filter_dport) \ + { \ + if (conn.dport != filter_dport) \ + { \ + return 0; \ + } \ } // 连接的源端口是否匹配于filter_sport的值 -#define FILTER_SPORT \ - if (filter_sport) { \ - if (conn.sport != filter_sport) { \ - return 0; \ - } \ +#define FILTER_SPORT \ + if (filter_sport) \ + { \ + if (conn.sport != filter_sport) \ + { \ + return 0; \ + } \ } // 初始化conn_t结构 -#define CONN_INIT \ - struct conn_t conn = {0}; \ - conn.pid = ptid >> 32; \ - conn.ptid = ptid; \ - u16 protocol = BPF_CORE_READ(sk, sk_protocol); \ - if (protocol != IPPROTO_TCP) \ - return 0; \ - bpf_get_current_comm(&conn.comm, sizeof(conn.comm)); \ - conn.sock = sk; \ - u16 family = BPF_CORE_READ(sk, __sk_common.skc_family); \ - __be16 dport = BPF_CORE_READ(sk, __sk_common.skc_dport); \ - u16 sport = BPF_CORE_READ(sk, __sk_common.skc_num); \ - conn.family = family; \ - conn.sport = sport; \ - conn.dport = __bpf_ntohs(dport); \ +#define CONN_INIT \ + struct conn_t conn = {0}; \ + conn.pid = ptid >> 32; \ + conn.ptid = ptid; \ + u16 protocol = BPF_CORE_READ(sk, sk_protocol); \ + if (protocol != IPPROTO_TCP) \ + return 0; \ + bpf_get_current_comm(&conn.comm, sizeof(conn.comm)); \ + conn.sock = sk; \ + u16 family = BPF_CORE_READ(sk, __sk_common.skc_family); \ + __be16 dport = BPF_CORE_READ(sk, __sk_common.skc_dport); \ + u16 sport = BPF_CORE_READ(sk, __sk_common.skc_num); \ + conn.family = family; \ + conn.sport = sport; \ + conn.dport = __bpf_ntohs(dport); \ conn.init_timestamp = bpf_ktime_get_ns() / 1000; -//初始化conn_t地址相关信息 -#define CONN_ADD_ADDRESS \ - if (family == AF_INET) { \ - conn.saddr = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr); \ - conn.daddr = BPF_CORE_READ(sk, __sk_common.skc_daddr); \ - } else if (family == AF_INET6) { \ - bpf_probe_read_kernel( \ - &conn.saddr_v6, \ - sizeof(sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32), \ - &sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32); \ - bpf_probe_read_kernel( \ - &conn.daddr_v6, \ - sizeof(sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32), \ - &sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32); \ +// 初始化conn_t地址相关信息 +#define CONN_ADD_ADDRESS \ + if (family == AF_INET) \ + { \ + conn.saddr = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr); \ + conn.daddr = BPF_CORE_READ(sk, __sk_common.skc_daddr); \ + } \ + else if (family == AF_INET6) \ + { \ + bpf_probe_read_kernel( \ + &conn.saddr_v6, \ + sizeof(sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32), \ + &sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32); \ + bpf_probe_read_kernel( \ + &conn.daddr_v6, \ + sizeof(sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32), \ + &sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32); \ } -//初始化conn其余额外信息 -#define CONN_ADD_EXTRA_INFO \ - if (extra_conn_info) { \ - struct tcp_sock *tp = (struct tcp_sock *)sk; \ - conn->srtt = BPF_CORE_READ(tp, srtt_us); \ - conn->duration = bpf_ktime_get_ns() / 1000 - conn->init_timestamp; \ - conn->bytes_acked = BPF_CORE_READ(tp, bytes_acked); \ - conn->bytes_received = BPF_CORE_READ(tp, bytes_received); \ - conn->snd_cwnd = BPF_CORE_READ(tp, snd_cwnd); \ - conn->rcv_wnd = BPF_CORE_READ(tp, rcv_wnd); \ - conn->snd_ssthresh = BPF_CORE_READ(tp, snd_ssthresh); \ - conn->total_retrans = BPF_CORE_READ(tp, total_retrans); \ - conn->sndbuf = BPF_CORE_READ(sk, sk_sndbuf); \ - conn->sk_wmem_queued = BPF_CORE_READ(sk, sk_wmem_queued); \ - conn->tcp_backlog = BPF_CORE_READ(sk, sk_ack_backlog); \ - conn->max_tcp_backlog = BPF_CORE_READ(sk, sk_max_ack_backlog); \ +// 初始化conn其余额外信息 +#define CONN_ADD_EXTRA_INFO \ + if (extra_conn_info) \ + { \ + struct tcp_sock *tp = (struct tcp_sock *)sk; \ + conn->srtt = BPF_CORE_READ(tp, srtt_us); \ + conn->duration = bpf_ktime_get_ns() / 1000 - conn->init_timestamp; \ + conn->bytes_acked = BPF_CORE_READ(tp, bytes_acked); \ + conn->bytes_received = BPF_CORE_READ(tp, bytes_received); \ + conn->snd_cwnd = BPF_CORE_READ(tp, snd_cwnd); \ + conn->rcv_wnd = BPF_CORE_READ(tp, rcv_wnd); \ + conn->snd_ssthresh = BPF_CORE_READ(tp, snd_ssthresh); \ + conn->total_retrans = BPF_CORE_READ(tp, total_retrans); \ + conn->sndbuf = BPF_CORE_READ(sk, sk_sndbuf); \ + conn->sk_wmem_queued = BPF_CORE_READ(sk, sk_wmem_queued); \ + conn->tcp_backlog = BPF_CORE_READ(sk, sk_ack_backlog); \ + conn->max_tcp_backlog = BPF_CORE_READ(sk, sk_max_ack_backlog); \ } #define CONN_INFO_TRANSFER tinfo->sk = conn->sock; // 将conn->sock赋给tinfo->sk -#define PACKET_INIT_WITH_COMMON_INFO \ - struct pack_t *packet; \ - packet = bpf_ringbuf_reserve(&rb, sizeof(*packet), 0); \ - if (!packet) { \ - return 0; \ - } \ - packet->err = 0; \ - packet->sock = sk; \ - packet->ack = pkt_tuple.ack; \ +#define PACKET_INIT_WITH_COMMON_INFO \ + struct pack_t *packet; \ + packet = bpf_ringbuf_reserve(&rb, sizeof(*packet), 0); \ + if (!packet) \ + { \ + return 0; \ + } \ + packet->err = 0; \ + packet->sock = sk; \ + packet->ack = pkt_tuple.ack; \ packet->seq = pkt_tuple.seq; #define READ_ONCE(x) (*(volatile typeof(x) *)&(x)) #define WRITE_ONCE(x, val) ((*(volatile typeof(x) *)&(x)) = val) -#define INIT_PACKET_TCP_TUPLE(sk, pkt) \ - struct packet_tuple pkt = { \ - .saddr = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr), \ - .daddr = BPF_CORE_READ(sk, __sk_common.skc_daddr), \ - .sport = BPF_CORE_READ(sk, __sk_common.skc_num), \ - .dport = __bpf_ntohs(BPF_CORE_READ(sk, __sk_common.skc_dport)), \ +#define INIT_PACKET_TCP_TUPLE(sk, pkt) \ + struct packet_tuple pkt = { \ + .saddr = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr), \ + .daddr = BPF_CORE_READ(sk, __sk_common.skc_daddr), \ + .sport = BPF_CORE_READ(sk, __sk_common.skc_num), \ + .dport = __bpf_ntohs(BPF_CORE_READ(sk, __sk_common.skc_dport)), \ .tran_flag = TCP} -#define INIT_PACKET_UDP_TUPLE(sk, pkt) \ - struct packet_tuple pkt = { \ - .saddr = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr), \ - .daddr = BPF_CORE_READ(sk, __sk_common.skc_daddr), \ - .sport = BPF_CORE_READ(sk, __sk_common.skc_num), \ - .dport = __bpf_ntohs(BPF_CORE_READ(sk, __sk_common.skc_dport)), \ +#define INIT_PACKET_UDP_TUPLE(sk, pkt) \ + struct packet_tuple pkt = { \ + .saddr = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr), \ + .daddr = BPF_CORE_READ(sk, __sk_common.skc_daddr), \ + .sport = BPF_CORE_READ(sk, __sk_common.skc_num), \ + .dport = __bpf_ntohs(BPF_CORE_READ(sk, __sk_common.skc_dport)), \ .tran_flag = UDP} - -//http data +// http data #if defined(USE_NEW_GET_USER_DATA) #define GET_USER_DATA(msg) BPF_CORE_READ(msg, msg_iter.iov, iov_base) #else @@ -512,34 +568,40 @@ const volatile int all_conn = 0, err_packet = 0, extra_conn_info = 0, /* help functions */ // 将struct sock类型的指针转化为struct tcp_sock类型的指针 -static __always_inline struct tcp_sock *tcp_sk(const struct sock *sk) { +static __always_inline struct tcp_sock *tcp_sk(const struct sock *sk) +{ return (struct tcp_sock *)sk; } // 将struct sk_buff类型的指针转化为struct udphdr类型的指针 -static __always_inline struct udphdr *skb_to_udphdr(const struct sk_buff *skb) { +static __always_inline struct udphdr *skb_to_udphdr(const struct sk_buff *skb) +{ return (struct udphdr *)(( - BPF_CORE_READ(skb, head) + // 报文头部偏移 - BPF_CORE_READ(skb, transport_header))); // 传输层部分偏移 + BPF_CORE_READ(skb, head) + + BPF_CORE_READ(skb, transport_header))); } // 将struct sk_buff类型的指针转化为struct tcphdr类型的指针 -static __always_inline struct tcphdr *skb_to_tcphdr(const struct sk_buff *skb) { +static __always_inline struct tcphdr *skb_to_tcphdr(const struct sk_buff *skb) +{ return (struct tcphdr *)(( - BPF_CORE_READ(skb, head) + // 报文头部偏移 - BPF_CORE_READ(skb, transport_header))); // 传输层部分偏移 + BPF_CORE_READ(skb, head) + + BPF_CORE_READ(skb, transport_header))); } // 将struct sk_buff类型的指针转化为struct iphdr类型的指针 -static __always_inline struct iphdr *skb_to_iphdr(const struct sk_buff *skb) { +static __always_inline struct iphdr *skb_to_iphdr(const struct sk_buff *skb) +{ return (struct iphdr *)(BPF_CORE_READ(skb, head) + BPF_CORE_READ(skb, network_header)); } // 将struct sk_buff类型的指针转化为struct ipv6hdr类型的指针 static __always_inline struct ipv6hdr * -skb_to_ipv6hdr(const struct sk_buff *skb) { +skb_to_ipv6hdr(const struct sk_buff *skb) +{ return (struct ipv6hdr *)(BPF_CORE_READ(skb, head) + BPF_CORE_READ(skb, network_header)); } // 初始化ip_packet -static void get_ip_pkt_tuple(struct ip_packet *ipk, struct iphdr *ip) { +static void get_ip_pkt_tuple(struct ip_packet *ipk, struct iphdr *ip) +{ ipk->saddr = BPF_CORE_READ(ip, saddr); ipk->daddr = BPF_CORE_READ(ip, daddr); } @@ -547,7 +609,8 @@ static void get_ip_pkt_tuple(struct ip_packet *ipk, struct iphdr *ip) { // 初始化packet_tuple结构指针pkt_tuple static __always_inline void get_pkt_tuple(struct packet_tuple *pkt_tuple, struct iphdr *ip, - struct tcphdr *tcp) { + struct tcphdr *tcp) +{ pkt_tuple->saddr = BPF_CORE_READ(ip, saddr); pkt_tuple->daddr = BPF_CORE_READ(ip, daddr); u16 sport = BPF_CORE_READ(tcp, source); @@ -570,7 +633,8 @@ static __always_inline void get_pkt_tuple(struct packet_tuple *pkt_tuple, // 初始化packet_tuple结构指针pkt_tuple static __always_inline void get_udp_pkt_tuple(struct packet_tuple *pkt_tuple, struct iphdr *ip, - struct udphdr *udp) { + struct udphdr *udp) +{ pkt_tuple->saddr = BPF_CORE_READ(ip, saddr); pkt_tuple->daddr = BPF_CORE_READ(ip, daddr); u16 sport = BPF_CORE_READ(udp, source); @@ -585,7 +649,8 @@ static __always_inline void get_udp_pkt_tuple(struct packet_tuple *pkt_tuple, static __always_inline void get_pkt_tuple_v6(struct packet_tuple *pkt_tuple, struct ipv6hdr *ip6h, - struct tcphdr *tcp) { + struct tcphdr *tcp) +{ bpf_probe_read_kernel(&pkt_tuple->saddr_v6, sizeof(pkt_tuple->saddr_v6), &ip6h->saddr.in6_u.u6_addr32); bpf_probe_read_kernel(&pkt_tuple->daddr_v6, sizeof(pkt_tuple->daddr_v6), @@ -601,7 +666,8 @@ static __always_inline void get_pkt_tuple_v6(struct packet_tuple *pkt_tuple, pkt_tuple->tran_flag = 1; // tcp包 } -int getstack(void *ctx) { +int getstack(void *ctx) +{ int pid = bpf_get_current_pid_tgid() >> 32; int cpu_id = bpf_get_smp_processor_id(); struct stacktrace_event *event; @@ -635,11 +701,12 @@ int getstack(void *ctx) { 5、v=4,右移1位10,r|=2>>1=1 r=14|1=14 */ -static __always_inline u64 log2(u32 v) { +static __always_inline u64 log2(u32 v) +{ u32 shift, r; - //检测v是否大于0xFFFF(65535),如果是,则将r设置为16 + // 检测v是否大于0xFFFF(65535),如果是,则将r设置为16 r = (v > 0xFFFF) << 4; - v >>= r; //右移 + v >>= r; // 右移 shift = (v > 0xFF) << 3; v >>= shift; r |= shift; @@ -649,7 +716,7 @@ static __always_inline u64 log2(u32 v) { shift = (v > 0x3) << 1; v >>= shift; r |= shift; - //右移v一位并将结果累加到r中 + // 右移v一位并将结果累加到r中 r |= (v >> 1); return r; } @@ -659,8 +726,9 @@ static __always_inline u64 log2(u32 v) { 1、v右移32位 1 2、log2(1)=0 计算得0+32=32 */ -static __always_inline u64 log2l(u64 v) { - u32 hi = v >> 32; //取v的高32位 +static __always_inline u64 log2l(u64 v) +{ + u32 hi = v >> 32; // 取v的高32位 // 如果高32位非0,计算高32位的对数并加32 if (hi) return log2(hi) + 32; diff --git a/MagicEyes/src/backend/net/net_watcher/bpf/drop.bpf.h b/MagicEyes/src/backend/net/net_watcher/bpf/drop.bpf.h index 56848f52f..d4fbe23c9 100644 --- a/MagicEyes/src/backend/net/net_watcher/bpf/drop.bpf.h +++ b/MagicEyes/src/backend/net/net_watcher/bpf/drop.bpf.h @@ -16,22 +16,22 @@ // net_watcher libbpf 丢包 #include "common.bpf.h" -static __always_inline -int __tp_kfree(struct trace_event_raw_kfree_skb *ctx) +static __always_inline int __tp_kfree(struct trace_event_raw_kfree_skb *ctx) { - if(!drop_reason) + if (!drop_reason) return 0; - struct sk_buff *skb=ctx->skbaddr; - if (skb == NULL) // 判断是否为空 + struct sk_buff *skb = ctx->skbaddr; + if (skb == NULL) return 0; struct iphdr *ip = skb_to_iphdr(skb); struct tcphdr *tcp = skb_to_tcphdr(skb); struct packet_tuple pkt_tuple = {0}; get_pkt_tuple(&pkt_tuple, ip, tcp); - struct reasonissue *message; + struct reasonissue *message; message = bpf_ringbuf_reserve(&kfree_rb, sizeof(*message), 0); - if(!message){ + if (!message) + { return 0; } message->saddr = pkt_tuple.saddr; @@ -41,8 +41,8 @@ int __tp_kfree(struct trace_event_raw_kfree_skb *ctx) message->protocol = ctx->protocol; message->location = (long)ctx->location; message->drop_reason = ctx->reason; - bpf_ringbuf_submit(message,0); - if(stack_info) + bpf_ringbuf_submit(message, 0); + if (stack_info) getstack(ctx); return 0; -} \ No newline at end of file +} \ No newline at end of file diff --git a/MagicEyes/src/backend/net/net_watcher/bpf/mysql.bpf.h b/MagicEyes/src/backend/net/net_watcher/bpf/mysql.bpf.h index 13e802887..93af7d4cb 100644 --- a/MagicEyes/src/backend/net/net_watcher/bpf/mysql.bpf.h +++ b/MagicEyes/src/backend/net/net_watcher/bpf/mysql.bpf.h @@ -33,9 +33,9 @@ static __always_inline int __handle_mysql_start(struct pt_regs *ctx) { } bpf_probe_read(&info.size, sizeof(info.size), &com_data->com_query.length); - bpf_probe_read_str(&sql, sizeof(sql), &com_data->com_query.query); - bpf_probe_read_str(&info.msql, sizeof(info.msql), sql); - // bpf_printk("sql1==%s size1==%lu", info.msql,info.size); + bpf_probe_read(&sql, sizeof(sql), &com_data->com_query.query); + bpf_probe_read(&info.msql, sizeof(info.msql), sql); + bpf_printk("sql1==%s size1==%lu", info.msql,info.size); info.start_time = bpf_ktime_get_ns() / 1000; bpf_map_update_elem(&queries, &tid, &info, BPF_ANY); @@ -70,8 +70,6 @@ static __always_inline int __handle_mysql_end(struct pt_regs *ctx) { bpf_get_current_comm(&message->comm, sizeof(comm)); message->size = info->size; bpf_probe_read_str(&message->msql, sizeof(message->msql), info->msql); - // bpf_printk("C==%d D==%lu S==%lu SQL==%s",count, - // message->duratime,message->size,message->msql); bpf_ringbuf_submit(message, 0); return 0; diff --git a/MagicEyes/src/backend/net/net_watcher/bpf/net_watcher.bpf.c b/MagicEyes/src/backend/net/net_watcher/bpf/net_watcher.bpf.c index 5db4a8064..d1a095425 100644 --- a/MagicEyes/src/backend/net/net_watcher/bpf/net_watcher.bpf.c +++ b/MagicEyes/src/backend/net/net_watcher/bpf/net_watcher.bpf.c @@ -317,14 +317,15 @@ int BPF_KPROBE(icmp_reply, struct icmp_bxm *icmp_param, struct sk_buff *skb) { // mysql SEC("uprobe/_Z16dispatch_commandP3THDPK8COM_DATA19enum_server_command") -int BPF_KPROBE(query__start) { return __handle_mysql_start(ctx); } +int BPF_UPROBE(query__start) { return __handle_mysql_start(ctx); } SEC("uretprobe/_Z16dispatch_commandP3THDPK8COM_DATA19enum_server_command") -int BPF_KPROBE(query__end) { return __handle_mysql_end(ctx); } +int BPF_UPROBE(query__end) { return __handle_mysql_end(ctx); } //redis SEC("uprobe/processCommand") -int BPF_KPROBE(redis_processCommand) { return __handle_redis_start(ctx); } +int BPF_KPROBE(redis_processCommand) { + return __handle_redis_start(ctx); } SEC("uretprobe/call") int BPF_KPROBE(redis_call) { return __handle_redis_end(ctx); } diff --git a/MagicEyes/src/backend/net/net_watcher/bpf/netfilter.bpf.h b/MagicEyes/src/backend/net/net_watcher/bpf/netfilter.bpf.h index f6eea5202..8fc9772ef 100644 --- a/MagicEyes/src/backend/net/net_watcher/bpf/netfilter.bpf.h +++ b/MagicEyes/src/backend/net/net_watcher/bpf/netfilter.bpf.h @@ -97,7 +97,7 @@ int store_nf_time(struct sk_buff *skb, int hook) { if(!net_filter) return 0; - if (skb == NULL) // 判断是否为空 + if (skb == NULL) return 0; struct iphdr *ip = skb_to_iphdr(skb); struct tcphdr *tcp = skb_to_tcphdr(skb); diff --git a/MagicEyes/src/backend/net/net_watcher/bpf/packet.bpf.h b/MagicEyes/src/backend/net/net_watcher/bpf/packet.bpf.h index c75dbea20..c74ed2482 100644 --- a/MagicEyes/src/backend/net/net_watcher/bpf/packet.bpf.h +++ b/MagicEyes/src/backend/net/net_watcher/bpf/packet.bpf.h @@ -31,20 +31,24 @@ kprobe/skb_copy_datagram_iter */ static __always_inline struct packet_count *count_packet(u32 proto, - bool is_tx) { + bool is_tx) +{ struct packet_count *count; struct packet_count initial_count = {0}; count = bpf_map_lookup_elem(&proto_stats, &proto); - if (!count) { + if (!count) + { initial_count.tx_count = 0; initial_count.rx_count = 0; if (bpf_map_update_elem(&proto_stats, &proto, &initial_count, - BPF_ANY)) { + BPF_ANY)) + { return NULL; } count = bpf_map_lookup_elem(&proto_stats, &proto); - if (!count) { + if (!count) + { return NULL; } } @@ -56,22 +60,26 @@ static __always_inline struct packet_count *count_packet(u32 proto, return count; } -static __always_inline int sum_protocol(struct sk_buff *skb, bool is_tx) { +static __always_inline int sum_protocol(struct sk_buff *skb, bool is_tx) +{ const struct ethhdr *eth = (struct ethhdr *)BPF_CORE_READ(skb, data); u16 proto = BPF_CORE_READ(eth, h_proto); struct packet_info *pkt = bpf_ringbuf_reserve(&port_rb, sizeof(*pkt), 0); - if (!pkt) { + if (!pkt) + { return 0; } - if (BPF_CORE_READ(eth, h_proto) != __bpf_htons(ETH_P_IP)) { + if (BPF_CORE_READ(eth, h_proto) != __bpf_htons(ETH_P_IP)) + { bpf_ringbuf_discard(pkt, 0); return 0; } struct iphdr *ip = (struct iphdr *)(BPF_CORE_READ(skb, data) + 14); - if (!ip) { + if (!ip) + { bpf_ringbuf_discard(pkt, 0); return 0; } @@ -80,48 +88,55 @@ static __always_inline int sum_protocol(struct sk_buff *skb, bool is_tx) { pkt->daddr = BPF_CORE_READ(ip, daddr); pkt->proto = BPF_CORE_READ(ip, protocol); - if (pkt->proto == IPPROTO_TCP) { + if (pkt->proto == IPPROTO_TCP) + { struct tcphdr *tcp = (struct tcphdr *)(BPF_CORE_READ(skb, data) + sizeof(struct ethhdr) + sizeof(struct iphdr)); pkt->sport = BPF_CORE_READ(tcp, source); pkt->dport = BPF_CORE_READ(tcp, dest); pkt->proto = PROTO_TCP; - } else if (pkt->proto == IPPROTO_UDP) { + } + else if (pkt->proto == IPPROTO_UDP) + { struct udphdr *udp = (struct udphdr *)(BPF_CORE_READ(skb, data) + sizeof(struct ethhdr) + sizeof(struct iphdr)); pkt->sport = BPF_CORE_READ(udp, source); pkt->dport = BPF_CORE_READ(udp, dest); pkt->proto = PROTO_UDP; - } else if (pkt->proto == IPPROTO_ICMP) { + } + else if (pkt->proto == IPPROTO_ICMP) + { pkt->proto = PROTO_ICMP; - } else { + } + else + { pkt->proto = PROTO_UNKNOWN; } struct packet_count *count = count_packet(pkt->proto, is_tx); - if (count) { + if (count) + { pkt->count.tx_count = count->tx_count; pkt->count.rx_count = count->rx_count; - } else { + } + else + { pkt->count.tx_count = 0; pkt->count.rx_count = 0; } - - // bpf_printk("pkt: saddr=%u, daddr=%u, proto=%u\n", pkt->saddr, pkt->daddr, - // pkt->proto); bpf_printk("sport=%d, dport=%d\n", pkt->sport, pkt->dport); - // bpf_printk("count_tx=%llu, count_rx=%llu\n", pkt->count.tx_count, - // pkt->count.rx_count); bpf_ringbuf_submit(pkt, 0); return 0; } -static __always_inline int __eth_type_trans(struct sk_buff *skb) { +static __always_inline int __eth_type_trans(struct sk_buff *skb) +{ const struct ethhdr *eth = - (struct ethhdr *)BPF_CORE_READ(skb, data); // 读取里面的报文数据 - u16 protocol = BPF_CORE_READ(eth, h_proto); // 读取包ID + (struct ethhdr *)BPF_CORE_READ(skb, data); + u16 protocol = BPF_CORE_READ(eth, h_proto); // bpf_printk("protocol: %d\n", __bpf_ntohs(protocol)); - if (protocol == __bpf_htons(ETH_P_IP)) { // Protocol is IP 0x0800 + if (protocol == __bpf_htons(ETH_P_IP)) + { // Protocol is IP 0x0800 // 14 --> sizeof(struct ethhdr) / define struct iphdr *ip = (struct iphdr *)(BPF_CORE_READ(skb, data) + @@ -129,21 +144,24 @@ static __always_inline int __eth_type_trans(struct sk_buff *skb) { // 目的端口6字节 类型2字节 struct tcphdr *tcp = (struct tcphdr *)(BPF_CORE_READ(skb, data) + sizeof(struct iphdr) + 14); - struct packet_tuple pkt_tuple = {0}; // 声明packet_tuple结构pkt_tuple - get_pkt_tuple(&pkt_tuple, ip, tcp); // 初始化pkt_tuple + struct packet_tuple pkt_tuple = {0}; + get_pkt_tuple(&pkt_tuple, ip, tcp); - struct ktime_info *tinfo, zero = {0}; // 定义ktime_info结构zero以及tinfo + struct ktime_info *tinfo, zero = {0}; tinfo = (struct ktime_info *)bpf_map_lookup_or_try_init( ×tamps, &pkt_tuple, &zero); - if (tinfo == NULL) { // 初始化失败 + if (tinfo == NULL) + { // bpf_printk("v4 rx tinfo init fail.\n"); return 0; } - // 成功则获取当前内核时间并转换成毫秒 + tinfo->mac_time = bpf_ktime_get_ns() / 1000; // bpf_printk("v4 rx init.\n"); - } else if (protocol == __bpf_htons(ETH_P_IPV6)) { // Protocol is IPV6 + } + else if (protocol == __bpf_htons(ETH_P_IPV6)) + { // Protocol is IPV6 struct ipv6hdr *ip6h = (struct ipv6hdr *)(BPF_CORE_READ(skb, data) + 14); struct tcphdr *tcp = (struct tcphdr *)(BPF_CORE_READ(skb, data) + @@ -155,7 +173,8 @@ static __always_inline int __eth_type_trans(struct sk_buff *skb) { tinfo = (struct ktime_info *)bpf_map_lookup_or_try_init( ×tamps, &pkt_tuple, &zero); - if (tinfo == NULL) { + if (tinfo == NULL) + { // bpf_printk("v6 rx tinfo init fail.\n"); return 0; } @@ -165,21 +184,24 @@ static __always_inline int __eth_type_trans(struct sk_buff *skb) { return 0; } -static __always_inline int __ip_rcv_core(struct sk_buff *skb) { - if (!layer_time) { +static __always_inline int __ip_rcv_core(struct sk_buff *skb) +{ + if (!layer_time) + { return 0; } if (skb == NULL) return 0; - struct iphdr *ip = skb_to_iphdr(skb); // 通过skb获取ipv4包头信息 - struct tcphdr *tcp = skb_to_tcphdr(skb); // 获取tcp包头信息 + struct iphdr *ip = skb_to_iphdr(skb); + struct tcphdr *tcp = skb_to_tcphdr(skb); struct packet_tuple pkt_tuple = { - 0}; // 定义一个packet_tuple结构体变量pkt_tuple并初始化 + 0}; get_pkt_tuple(&pkt_tuple, ip, tcp); struct ktime_info *tinfo; tinfo = bpf_map_lookup_elem( - ×tamps, &pkt_tuple); // 在timestamps映射中查找元素pkt_tuple - if (tinfo == NULL) { + ×tamps, &pkt_tuple); + if (tinfo == NULL) + { return 0; } tinfo->ip_time = bpf_ktime_get_ns() / 1000; @@ -187,8 +209,10 @@ static __always_inline int __ip_rcv_core(struct sk_buff *skb) { return 0; } -static __always_inline int __ip6_rcv_core(struct sk_buff *skb) { - if (!layer_time) { +static __always_inline int __ip6_rcv_core(struct sk_buff *skb) +{ + if (!layer_time) + { return 0; } if (skb == NULL) @@ -200,7 +224,8 @@ static __always_inline int __ip6_rcv_core(struct sk_buff *skb) { struct ktime_info *tinfo; tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple); - if (tinfo == NULL) { + if (tinfo == NULL) + { return 0; } @@ -208,8 +233,10 @@ static __always_inline int __ip6_rcv_core(struct sk_buff *skb) { // bpf_printk("rx enter ipv6 layer.\n"); return 0; } -static __always_inline int __tcp_v4_rcv(struct sk_buff *skb) { - if (!layer_time) { +static __always_inline int __tcp_v4_rcv(struct sk_buff *skb) +{ + if (!layer_time) + { return 0; } if (skb == NULL) @@ -220,15 +247,18 @@ static __always_inline int __tcp_v4_rcv(struct sk_buff *skb) { get_pkt_tuple(&pkt_tuple, ip, tcp); struct ktime_info *tinfo; tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple); - if (tinfo == NULL) { + if (tinfo == NULL) + { return 0; } tinfo->tran_time = bpf_ktime_get_ns() / 1000; // bpf_printk("rx enter tcp4 layer.\n"); return 0; } -static __always_inline int __tcp_v6_rcv(struct sk_buff *skb) { - if (!layer_time) { +static __always_inline int __tcp_v6_rcv(struct sk_buff *skb) +{ + if (!layer_time) + { return 0; } if (skb == NULL) @@ -240,7 +270,8 @@ static __always_inline int __tcp_v6_rcv(struct sk_buff *skb) { struct ktime_info *tinfo; tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple); - if (tinfo == NULL) { + if (tinfo == NULL) + { return 0; } tinfo->tran_time = bpf_ktime_get_ns() / 1000; @@ -248,11 +279,13 @@ static __always_inline int __tcp_v6_rcv(struct sk_buff *skb) { return 0; } static __always_inline int __tcp_v4_do_rcv(struct sock *sk, - struct sk_buff *skb) { + struct sk_buff *skb) +{ if (sk == NULL || skb == NULL) return 0; struct conn_t *conn = bpf_map_lookup_elem(&conns_info, &sk); - if (conn == NULL) { + if (conn == NULL) + { // bpf_printk("get a v4 rx pack but conn not record, its sock is: // %p",sk); return 0; @@ -264,7 +297,8 @@ static __always_inline int __tcp_v4_do_rcv(struct sock *sk, struct ktime_info *tinfo; tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple); - if (tinfo == NULL) { + if (tinfo == NULL) + { return 0; } @@ -277,12 +311,14 @@ static __always_inline int __tcp_v4_do_rcv(struct sock *sk, return 0; } static __always_inline int __tcp_v6_do_rcv(struct sock *sk, - struct sk_buff *skb) { + struct sk_buff *skb) +{ if (sk == NULL || skb == NULL) return 0; // bpf_printk("rx enter tcp6_do_rcv. \n"); struct conn_t *conn = bpf_map_lookup_elem(&conns_info, &sk); - if (conn == NULL) { + if (conn == NULL) + { // bpf_printk("get a v6 rx pack but conn not record, its sock is: %p", // sk); return 0; @@ -291,11 +327,12 @@ static __always_inline int __tcp_v6_do_rcv(struct sock *sk, struct ipv6hdr *ip6h = skb_to_ipv6hdr(skb); struct tcphdr *tcp = skb_to_tcphdr(skb); struct packet_tuple pkt_tuple = {0}; - get_pkt_tuple_v6(&pkt_tuple, ip6h, tcp); // 使用ip和tcp信息填充pkt_tuple + get_pkt_tuple_v6(&pkt_tuple, ip6h, tcp); struct ktime_info *tinfo; tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple); - if (tinfo == NULL) { + if (tinfo == NULL) + { return 0; } @@ -307,42 +344,52 @@ static __always_inline int __tcp_v6_do_rcv(struct sock *sk, return 0; } -static __always_inline int __skb_copy_datagram_iter(struct sk_buff *skb) { +static __always_inline int __skb_copy_datagram_iter(struct sk_buff *skb) +{ if (skb == NULL) return 0; - __be16 protocol = BPF_CORE_READ(skb, protocol); // 读取skb协议字段 + __be16 protocol = BPF_CORE_READ(skb, protocol); struct tcphdr *tcp = skb_to_tcphdr(skb); struct packet_tuple pkt_tuple = {0}; struct ktime_info *tinfo; - if (protocol == __bpf_htons(ETH_P_IP)) { /** ipv4 */ + if (protocol == __bpf_htons(ETH_P_IP)) + { /** ipv4 */ struct iphdr *ip = skb_to_iphdr(skb); get_pkt_tuple(&pkt_tuple, ip, tcp); tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple); - if (tinfo == NULL) { + if (tinfo == NULL) + { return 0; } tinfo->app_time = bpf_ktime_get_ns() / 1000; - } else if (protocol == __bpf_ntohs(ETH_P_IPV6)) { + } + else if (protocol == __bpf_ntohs(ETH_P_IPV6)) + { /** ipv6 */ struct ipv6hdr *ip6h = skb_to_ipv6hdr(skb); get_pkt_tuple_v6(&pkt_tuple, ip6h, tcp); - if ((tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple)) == NULL) { + if ((tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple)) == NULL) + { return 0; } tinfo->app_time = bpf_ktime_get_ns() / 1000; - } else { + } + else + { return 0; } /*----- record packet time info ------*/ - if (tinfo == NULL) { + if (tinfo == NULL) + { return 0; } struct sock *sk = tinfo->sk; - if (sk == NULL) { + if (sk == NULL) + { return 0; } // bpf_printk("rx enter app layer.\n"); @@ -353,7 +400,8 @@ static __always_inline int __skb_copy_datagram_iter(struct sk_buff *skb) { packet->sport = pkt_tuple.sport; packet->dport = pkt_tuple.dport; - if (layer_time) { + if (layer_time) + { packet->mac_time = tinfo->ip_time - tinfo->mac_time; // 计算MAC层和ip层之间的时间差 packet->ip_time = tinfo->tran_time - tinfo->ip_time; @@ -364,7 +412,8 @@ static __always_inline int __skb_copy_datagram_iter(struct sk_buff *skb) { packet->rx = 1; // 数据包已经被接收 // RX HTTP INFO - if (http_info) { + if (http_info) + { int doff = BPF_CORE_READ_BITFIELD_PROBED(tcp, doff); // 得用bitfield_probed // 读取tcp头部中的数据偏移字段 @@ -376,7 +425,7 @@ static __always_inline int __skb_copy_datagram_iter(struct sk_buff *skb) { bpf_probe_read_str(packet->data, sizeof(packet->data), user_data); // 将tcp负载数据读取到packet->data } - bpf_ringbuf_submit(packet, 0); // 将packet提交到缓冲区 + bpf_ringbuf_submit(packet, 0); return 0; } /* @@ -393,22 +442,25 @@ static __always_inline int __skb_copy_datagram_iter(struct sk_buff *skb) { kprobe/dev_hard_start_xmit */ static __always_inline int __tcp_sendmsg(struct sock *sk, struct msghdr *msg, - size_t size) { + size_t size) +{ struct conn_t *conn = bpf_map_lookup_elem(&conns_info, &sk); - if (conn == NULL) { + if (conn == NULL) + { return 0; } u16 family = BPF_CORE_READ(sk, __sk_common.skc_family); - struct ktime_info *tinfo, zero = {0}; // 存储时间 - struct packet_tuple pkt_tuple = {0}; // 存储数据包信息 + struct ktime_info *tinfo, zero = {0}; + struct packet_tuple pkt_tuple = {0}; /** ipv4 */ - if (family == AF_INET) { + if (family == AF_INET) + { u16 dport = BPF_CORE_READ(sk, __sk_common.skc_dport); - pkt_tuple.saddr = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr); // 源ip - pkt_tuple.daddr = BPF_CORE_READ(sk, __sk_common.skc_daddr); // 目的ip - pkt_tuple.sport = BPF_CORE_READ(sk, __sk_common.skc_num); // 源端口 - pkt_tuple.dport = __bpf_ntohs(dport); // 目的端口并进行字节序转换 + pkt_tuple.saddr = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr); + pkt_tuple.daddr = BPF_CORE_READ(sk, __sk_common.skc_daddr); + pkt_tuple.sport = BPF_CORE_READ(sk, __sk_common.skc_num); + pkt_tuple.dport = __bpf_ntohs(dport); u32 snd_nxt = BPF_CORE_READ(tcp_sk(sk), snd_nxt); // tcp要发送的下一个字节序列号 @@ -419,12 +471,15 @@ static __always_inline int __tcp_sendmsg(struct sock *sk, struct msghdr *msg, pkt_tuple.tran_flag = TCP; tinfo = (struct ktime_info *)bpf_map_lookup_or_try_init( ×tamps, &pkt_tuple, - &zero); // timestamps的BPF map保存数据包与时间戳的映射 - if (tinfo == NULL) { + &zero); + if (tinfo == NULL) + { return 0; } tinfo->tran_time = bpf_ktime_get_ns() / 1000; - } else if (family == AF_INET6) { + } + else if (family == AF_INET6) + { // 读取ipv6源地址 bpf_probe_read_kernel( &pkt_tuple.saddr_v6, @@ -451,7 +506,8 @@ static __always_inline int __tcp_sendmsg(struct sock *sk, struct msghdr *msg, tinfo = (struct ktime_info *)bpf_map_lookup_or_try_init( ×tamps, &pkt_tuple, &zero); - if (tinfo == NULL) { + if (tinfo == NULL) + { return 0; } tinfo->tran_time = bpf_ktime_get_ns() / 1000; @@ -462,11 +518,13 @@ static __always_inline int __tcp_sendmsg(struct sock *sk, struct msghdr *msg, CONN_ADD_EXTRA_INFO // TX HTTP info - if (http_info) { + if (http_info) + { u8 *user_data = GET_USER_DATA(msg); tinfo = (struct ktime_info *)bpf_map_lookup_or_try_init( ×tamps, &pkt_tuple, &zero); - if (tinfo == NULL) { + if (tinfo == NULL) + { return 0; } bpf_probe_read_str(tinfo->data, sizeof(tinfo->data), user_data); @@ -474,15 +532,18 @@ static __always_inline int __tcp_sendmsg(struct sock *sk, struct msghdr *msg, return 0; } static __always_inline int __ip_queue_xmit(struct sock *sk, - struct sk_buff *skb) { - if (!layer_time) { + struct sk_buff *skb) +{ + if (!layer_time) + { return 0; } u16 family = BPF_CORE_READ(sk, __sk_common.skc_family); struct packet_tuple pkt_tuple = {0}; struct ktime_info *tinfo; struct tcphdr *tcp = skb_to_tcphdr(skb); - if (family == AF_INET) { + if (family == AF_INET) + { u16 dport; u32 seq, ack; pkt_tuple.saddr = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr); @@ -495,7 +556,8 @@ static __always_inline int __ip_queue_xmit(struct sock *sk, pkt_tuple.seq = __bpf_ntohl(seq); pkt_tuple.ack = __bpf_ntohl(ack); pkt_tuple.tran_flag = TCP; - if ((tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple)) == NULL) { + if ((tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple)) == NULL) + { return 0; } tinfo->ip_time = bpf_ktime_get_ns() / 1000; @@ -504,15 +566,18 @@ static __always_inline int __ip_queue_xmit(struct sock *sk, return 0; } static __always_inline int __inet6_csk_xmit(struct sock *sk, - struct sk_buff *skb) { - if (!layer_time) { + struct sk_buff *skb) +{ + if (!layer_time) + { return 0; } u16 family = BPF_CORE_READ(sk, __sk_common.skc_family); struct tcphdr *tcp = skb_to_tcphdr(skb); struct packet_tuple pkt_tuple = {0}; struct ktime_info *tinfo; - if (family == AF_INET6) { + if (family == AF_INET6) + { u16 dport; u32 seq, ack; @@ -534,81 +599,99 @@ static __always_inline int __inet6_csk_xmit(struct sock *sk, pkt_tuple.seq = __bpf_ntohl(seq); pkt_tuple.ack = __bpf_ntohl(ack); pkt_tuple.tran_flag = TCP; - if ((tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple)) == NULL) { + if ((tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple)) == NULL) + { return 0; } tinfo->ip_time = bpf_ktime_get_ns() / 1000; } return 0; } -static __always_inline int dev_queue_xmit(struct sk_buff *skb) { - if (!layer_time) { +static __always_inline int dev_queue_xmit(struct sk_buff *skb) +{ + if (!layer_time) + { return 0; } // 从skb中读取以太网头部 const struct ethhdr *eth = (struct ethhdr *)BPF_CORE_READ(skb, data); u16 protocol = BPF_CORE_READ( eth, - h_proto); // 以太网头部协议字段该字段存储的是以太网帧所封装的上层协议类型 + h_proto); struct tcphdr *tcp = skb_to_tcphdr(skb); struct packet_tuple pkt_tuple = {0}; struct ktime_info *tinfo; - if (protocol == __bpf_ntohs(ETH_P_IP)) { + if (protocol == __bpf_ntohs(ETH_P_IP)) + { /** ipv4 */ struct iphdr *ip = skb_to_iphdr(skb); get_pkt_tuple(&pkt_tuple, ip, tcp); - if ((tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple)) == NULL) { + if ((tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple)) == NULL) + { return 0; } tinfo->mac_time = bpf_ktime_get_ns() / 1000; - } else if (protocol == __bpf_ntohs(ETH_P_IPV6)) { + } + else if (protocol == __bpf_ntohs(ETH_P_IPV6)) + { /** ipv6 */ struct ipv6hdr *ip6h = skb_to_ipv6hdr(skb); get_pkt_tuple_v6(&pkt_tuple, ip6h, tcp); - if ((tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple)) == NULL) { + if ((tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple)) == NULL) + { return 0; } tinfo->mac_time = bpf_ktime_get_ns() / 1000; } return 0; } -static __always_inline int __dev_hard_start_xmit(struct sk_buff *skb) { +static __always_inline int __dev_hard_start_xmit(struct sk_buff *skb) +{ const struct ethhdr *eth = (struct ethhdr *)BPF_CORE_READ(skb, data); u16 protocol = BPF_CORE_READ(eth, h_proto); struct tcphdr *tcp = skb_to_tcphdr(skb); struct packet_tuple pkt_tuple = {0}; struct ktime_info *tinfo; - if (protocol == __bpf_ntohs(ETH_P_IP)) { + if (protocol == __bpf_ntohs(ETH_P_IP)) + { /** ipv4 */ struct iphdr *ip = skb_to_iphdr(skb); get_pkt_tuple(&pkt_tuple, ip, tcp); - if ((tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple)) == NULL) { + if ((tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple)) == NULL) + { return 0; } - // 数据包在队列中等待的时间 + tinfo->qdisc_time = bpf_ktime_get_ns() / 1000; - } else if (protocol == __bpf_ntohs(ETH_P_IPV6)) { + } + else if (protocol == __bpf_ntohs(ETH_P_IPV6)) + { /** ipv6 */ struct ipv6hdr *ip6h = skb_to_ipv6hdr(skb); get_pkt_tuple_v6(&pkt_tuple, ip6h, tcp); - if ((tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple)) == NULL) { + if ((tinfo = bpf_map_lookup_elem(×tamps, &pkt_tuple)) == NULL) + { return 0; } tinfo->qdisc_time = bpf_ktime_get_ns() / 1000; - } else { + } + else + { return 0; } /*----- record packet time info ------*/ - if (tinfo == NULL) { + if (tinfo == NULL) + { return 0; } struct sock *sk = tinfo->sk; - if (!sk) { + if (!sk) + { return 0; } PACKET_INIT_WITH_COMMON_INFO @@ -616,19 +699,21 @@ static __always_inline int __dev_hard_start_xmit(struct sk_buff *skb) { packet->daddr = pkt_tuple.daddr; packet->sport = pkt_tuple.sport; packet->dport = pkt_tuple.dport; - // 记录各层的时间差值 - if (layer_time) { + + if (layer_time) + { packet->tran_time = tinfo->ip_time - tinfo->tran_time; packet->ip_time = tinfo->mac_time - tinfo->ip_time; packet->mac_time = tinfo->qdisc_time - tinfo - ->mac_time; // 队列纪律层,处于网络协议栈最底层,负责实际数据传输与接收 + ->mac_time; } packet->rx = 0; // 发送一个数据包 // TX HTTP Info - if (http_info) { + if (http_info) + { bpf_probe_read_str(packet->data, sizeof(packet->data), tinfo->data); // bpf_printk("%s", packet->data); } diff --git a/MagicEyes/src/backend/net/net_watcher/bpf/tcp.bpf.h b/MagicEyes/src/backend/net/net_watcher/bpf/tcp.bpf.h index abcc05698..e81932871 100644 --- a/MagicEyes/src/backend/net/net_watcher/bpf/tcp.bpf.h +++ b/MagicEyes/src/backend/net/net_watcher/bpf/tcp.bpf.h @@ -17,12 +17,14 @@ #include "common.bpf.h" -static __always_inline int __inet_csk_accept(struct sock *sk) { - if (sk == NULL) { // newsk is null +static __always_inline int __inet_csk_accept(struct sock *sk) +{ + if (sk == NULL) + { // newsk is null // bpf_printk("inet_accept_ret err: newsk is null\n"); return 0; } - u64 ptid = bpf_get_current_pid_tgid(); // 获取当前进程pid + u64 ptid = bpf_get_current_pid_tgid(); CONN_INIT // 初始化conn_t结构中基本信息 conn.is_server = 1; @@ -35,7 +37,8 @@ static __always_inline int __inet_csk_accept(struct sock *sk) { // 更新/插入conns_info中的键值对 int err = bpf_map_update_elem(&conns_info, &sk, &conn, BPF_ANY); - if (err) { // 更新错误 + if (err) + { // 更新错误 // bpf_printk("inet_accept update err.\n"); return 0; } @@ -43,33 +46,38 @@ static __always_inline int __inet_csk_accept(struct sock *sk) { return 0; } -static __always_inline int __tcp_v4_connect(const struct sock *sk) { - u64 ptid = bpf_get_current_pid_tgid(); // 获取当前pid +static __always_inline int __tcp_v4_connect(const struct sock *sk) +{ + u64 ptid = bpf_get_current_pid_tgid(); int err = bpf_map_update_elem(&sock_stores, &ptid, &sk, BPF_ANY); // 更新/插入sock_stores中的键值对 - if (err) { + if (err) + { // bpf_printk("tcp_v4_connect update sock_stores err.\n"); return 0; } return 0; } -static __always_inline int __tcp_v4_connect_exit(int ret) { - u64 ptid = bpf_get_current_pid_tgid(); // 获取当前pid +static __always_inline int __tcp_v4_connect_exit(int ret) +{ + u64 ptid = bpf_get_current_pid_tgid(); struct sock **skp = bpf_map_lookup_elem(&sock_stores, &ptid); - // 获得sock_stores中ptid对应的*sk 用skp指向 - if (skp == NULL) { + + if (skp == NULL) + { return 0; } // bpf_printk("tcp_v4_connect_exit\n"); - if (ret != 0) { // 连接失败 + if (ret != 0) + { // 连接失败 // bpf_printk("tcp_v4_connect_exit but ret %d\n", ret); bpf_map_delete_elem(&sock_stores, &ptid); // 删除对应键值对 return 0; } struct sock *sk = *skp; - CONN_INIT // 初始化conn_t结构中基本信息 - conn.is_server = 0; // 主动连接 + CONN_INIT + conn.is_server = 0; // 主动连接 FILTER_DPORT // 过滤目标端口 @@ -79,31 +87,37 @@ static __always_inline int __tcp_v4_connect_exit(int ret) { long err = bpf_map_update_elem(&conns_info, &sk, &conn, BPF_ANY); // 更新conns_info中sk对应的conn - if (err) { + if (err) + { return 0; } return 0; } -static __always_inline int __tcp_v6_connect(const struct sock *sk) { +static __always_inline int __tcp_v6_connect(const struct sock *sk) +{ u64 pid = bpf_get_current_pid_tgid(); // 获取pid int err = bpf_map_update_elem(&sock_stores, &pid, &sk, BPF_ANY); // 更新sock_stores中对应pid对应的sk - if (err) { + if (err) + { return 0; } return 0; } -static __always_inline int __tcp_v6_connect_exit(int ret) { +static __always_inline int __tcp_v6_connect_exit(int ret) +{ u64 ptid = bpf_get_current_pid_tgid(); // 获取pid struct sock **skp = bpf_map_lookup_elem(&sock_stores, &ptid); // 获得sock_stores中ptid对应的*sk 用skp指向 - if (skp == NULL) { + if (skp == NULL) + { return 0; } - if (ret != 0) { // 错误 - bpf_map_delete_elem(&sock_stores, &ptid); // 删除对应键值对 + if (ret != 0) + { + bpf_map_delete_elem(&sock_stores, &ptid); return 0; } struct sock *sk = *skp; @@ -119,19 +133,23 @@ static __always_inline int __tcp_v6_connect_exit(int ret) { long err = bpf_map_update_elem(&conns_info, &sk, &conn, BPF_ANY); // 更新conns_info中sk对应的conn - if (err) { + if (err) + { return 0; } // bpf_printk("tcp_v4_connect_exit update sk: %p.\n", sk); return 0; } -static __always_inline int __tcp_set_state(struct sock *sk, int state) { - if (all_conn) { +static __always_inline int __tcp_set_state(struct sock *sk, int state) +{ + if (all_conn) + { return 0; } struct conn_t *value = bpf_map_lookup_elem(&conns_info, &sk); // 查找sk对应的conn_t - if (state == TCP_CLOSE && value != NULL) { // TCP_CLOSE置1 说明关闭连接 + if (state == TCP_CLOSE && value != NULL) + { // TCP_CLOSE置1 说明关闭连接 // delete bpf_map_delete_elem(&sock_stores, &value->ptid); // 删除sock_stores bpf_map_delete_elem(&conns_info, &sk); // 删除conns_info @@ -141,15 +159,18 @@ static __always_inline int __tcp_set_state(struct sock *sk, int state) { // receive error packet static __always_inline int __tcp_validate_incoming(struct sock *sk, - struct sk_buff *skb) { - if (!err_packet) { + struct sk_buff *skb) +{ + if (!err_packet) + { return 0; } if (sk == NULL || skb == NULL) return 0; struct conn_t *conn = bpf_map_lookup_elem(&conns_info, &sk); // BPFmap查找与套接字sk关联的信息 - if (conn == NULL) { + if (conn == NULL) + { return 0; } struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); // 数据包信息 @@ -159,12 +180,13 @@ static __always_inline int __tcp_validate_incoming(struct sock *sk, u32 rcv_wup = BPF_CORE_READ( tp, rcv_wup); // 接收方已经确认并准备接收的数据最后一个字节的序列号 u32 rcv_nxt = - BPF_CORE_READ(tp, rcv_nxt); // 期望发送发下次发送的数据字节序列号 + BPF_CORE_READ(tp, rcv_nxt); // 期望发送发下次发送的数据字节序列号 u32 rcv_wnd = BPF_CORE_READ(tp, rcv_wnd); // tcp接收窗口大小 u32 receive_window = rcv_wup + rcv_nxt - rcv_wnd; // 当前可用的接收窗口 receive_window = 0; - if (end_seq >= rcv_wup && rcv_nxt + receive_window >= start_seq) { + if (end_seq >= rcv_wup && rcv_nxt + receive_window >= start_seq) + { // bpf_printk("error_identify: tcp seq validated. \n"); return 0; // 检查数据包序列号是否在接收窗口内 @@ -174,20 +196,26 @@ static __always_inline int __tcp_validate_incoming(struct sock *sk, u16 family = BPF_CORE_READ( sk, __sk_common.skc_family); // 获取套接字的地址族就是获得当前ip协议 struct packet_tuple pkt_tuple = {0}; - if (family == AF_INET) { + if (family == AF_INET) + { struct iphdr *ip = skb_to_iphdr(skb); struct tcphdr *tcp = skb_to_tcphdr(skb); get_pkt_tuple(&pkt_tuple, ip, tcp); - } else if (family == AF_INET6) { + } + else if (family == AF_INET6) + { struct ipv6hdr *ip6h = skb_to_ipv6hdr(skb); struct tcphdr *tcp = skb_to_tcphdr(skb); get_pkt_tuple_v6(&pkt_tuple, ip6h, tcp); - } else { + } + else + { return 0; } struct pack_t *packet; packet = bpf_ringbuf_reserve(&rb, sizeof(*packet), 0); - if (!packet) { + if (!packet) + { return 0; } packet->err = 1; // 错误标记此数据包有问题 @@ -197,28 +225,34 @@ static __always_inline int __tcp_validate_incoming(struct sock *sk, bpf_ringbuf_submit(packet, 0); return 0; } -static __always_inline int skb_checksum_complete(int ret) { - if (!err_packet) { +static __always_inline int skb_checksum_complete(int ret) +{ + if (!err_packet) + { return 0; } u64 pid = bpf_get_current_pid_tgid(); struct sock **skp = bpf_map_lookup_elem(&sock_stores, &pid); - if (skp == NULL) { + if (skp == NULL) + { return 0; } - if (ret == 0) { + if (ret == 0) + { // bpf_printk("error_identify: tcp checksum validated. \n"); return 0; } // bpf_printk("error_identify: tcp checksum error. \n"); struct sock *sk = *skp; struct conn_t *conn = bpf_map_lookup_elem(&conns_info, &sk); - if (conn == NULL) { + if (conn == NULL) + { return 0; } struct pack_t *packet; packet = bpf_ringbuf_reserve(&rb, sizeof(*packet), 0); - if (!packet) { + if (!packet) + { return 0; } packet->err = 2; // 校验和错误 @@ -227,13 +261,16 @@ static __always_inline int skb_checksum_complete(int ret) { return 0; } -////retrans packet -static __always_inline int __tcp_enter_recovery(struct sock *sk) { - if (!retrans_info) { +// retrans packet +static __always_inline int __tcp_enter_recovery(struct sock *sk) +{ + if (!retrans_info) + { return 0; } struct conn_t *conn = bpf_map_lookup_elem(&conns_info, &sk); - if (conn == NULL) { + if (conn == NULL) + { // bpf_printk("get a v4 rx pack but conn not record, its sock is: %p", // sk); return 0; @@ -242,19 +279,23 @@ static __always_inline int __tcp_enter_recovery(struct sock *sk) { return 0; } -static __always_inline int __tcp_enter_loss(struct sock *sk) { - if (!retrans_info) { +static __always_inline int __tcp_enter_loss(struct sock *sk) +{ + if (!retrans_info) + { return 0; } struct conn_t *conn = bpf_map_lookup_elem(&conns_info, &sk); - if (conn == NULL) { + if (conn == NULL) + { return 0; } conn->timeout += 1; return 0; } static __always_inline int -__handle_set_state(struct trace_event_raw_inet_sock_set_state *ctx) { +__handle_set_state(struct trace_event_raw_inet_sock_set_state *ctx) +{ if (ctx->protocol != IPPROTO_TCP) return 0; @@ -278,6 +319,7 @@ __handle_set_state(struct trace_event_raw_inet_sock_set_state *ctx) { bpf_probe_read_kernel(&tcpstate.daddr, sizeof(tcpstate.daddr), &sk->__sk_common.skc_daddr); tcpstate.time = time; + if (ctx->newstate == TCP_CLOSE) bpf_map_delete_elem(&tcp_state, &sk); else @@ -285,9 +327,11 @@ __handle_set_state(struct trace_event_raw_inet_sock_set_state *ctx) { struct tcp_state *message; message = bpf_ringbuf_reserve(&tcp_rb, sizeof(*message), 0); - if (!message) { + if (!message) + { return 0; } + message->saddr = tcpstate.saddr; message->daddr = tcpstate.daddr; message->sport = tcpstate.sport; @@ -295,13 +339,14 @@ __handle_set_state(struct trace_event_raw_inet_sock_set_state *ctx) { message->oldstate = tcpstate.oldstate; message->newstate = tcpstate.newstate; message->time = tcpstate.time; - bpf_printk("Dport:%d time:%d", tcpstate.dport, tcpstate.time); + bpf_ringbuf_submit(message, 0); return 0; } static __always_inline int __tcp_rcv_established(struct sock *sk, - struct sk_buff *skb) { + struct sk_buff *skb) +{ const struct inet_sock *inet = (struct inet_sock *)(sk); struct tcp_sock *ts; struct hist *histp; @@ -315,13 +360,14 @@ static __always_inline int __tcp_rcv_established(struct sock *sk, struct ip_packet key = {.saddr = pkt_tuple.saddr, .daddr = pkt_tuple.daddr}; histp = bpf_map_lookup_elem(&hists, &key); - if (!histp) { - // 初始化值 + if (!histp) + { + struct hist zero = {}; bpf_map_update_elem(&hists, &key, &zero, BPF_ANY); histp = bpf_map_lookup_elem(&hists, &key); if (!histp) - return 0; // 如果仍然查找失败,则返回 + return 0; } ts = (struct tcp_sock *)(sk); @@ -339,7 +385,8 @@ static __always_inline int __tcp_rcv_established(struct sock *sk, struct RTT *message; message = bpf_ringbuf_reserve(&rtt_rb, sizeof(*message), 0); - if (!message) { + if (!message) + { return 0; } message->saddr = pkt_tuple.saddr; @@ -355,7 +402,8 @@ static __always_inline int __tcp_rcv_established(struct sock *sk, } static __always_inline int ret(void *ctx, u8 direction, u16 sport, - u16 dport) { + u16 dport) +{ struct reset_event_t *message = bpf_ringbuf_reserve(&events, sizeof(*message), 0); if (!message) @@ -366,27 +414,36 @@ static __always_inline int ret(void *ctx, u8 direction, u16 sport, struct sock *sk = (struct sock *)ctx; message->family = BPF_CORE_READ(sk, __sk_common.skc_family); - message->timestamp = bpf_ktime_get_ns(); + message->timestamp = bpf_ktime_get_ns() / 1000; - if (message->family == AF_INET) { - if (direction == 0) { // Send + if (message->family == AF_INET) + { + if (direction == 0) + { // Send message->saddr = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr); message->daddr = BPF_CORE_READ(sk, __sk_common.skc_daddr); - } else { // Receive + } + else + { // Receive message->saddr = BPF_CORE_READ(sk, __sk_common.skc_daddr); message->daddr = BPF_CORE_READ(sk, __sk_common.skc_rcv_saddr); } message->saddr_v6 = 0; message->daddr_v6 = 0; - } else if (message->family == AF_INET6) { - if (direction == 0) { // Send + } + else if (message->family == AF_INET6) + { + if (direction == 0) + { // Send bpf_probe_read_kernel( &message->saddr_v6, sizeof(message->saddr_v6), &sk->__sk_common.skc_v6_rcv_saddr.in6_u.u6_addr32); bpf_probe_read_kernel( &message->daddr_v6, sizeof(message->daddr_v6), &sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32); - } else { // Receive + } + else + { // Receive bpf_probe_read_kernel( &message->saddr_v6, sizeof(message->saddr_v6), &sk->__sk_common.skc_v6_daddr.in6_u.u6_addr32); @@ -399,10 +456,13 @@ static __always_inline int ret(void *ctx, u8 direction, u16 sport, message->daddr = 0; } - if (direction == 0) { // Send + if (direction == 0) + { // Send message->sport = bpf_ntohs(sport); message->dport = bpf_ntohs(dport); - } else { // Receive + } + else + { // Receive message->sport = bpf_ntohs(dport); message->dport = bpf_ntohs(sport); } @@ -411,9 +471,12 @@ static __always_inline int ret(void *ctx, u8 direction, u16 sport, // 增加 RST 计数 u32 pid = message->pid; u64 *count = bpf_map_lookup_elem(&counters, &pid); - if (count) { + if (count) + { *count += 1; - } else { + } + else + { u64 initial_count = 1; bpf_map_update_elem(&counters, &pid, &initial_count, BPF_ANY); count = &initial_count; @@ -425,7 +488,8 @@ static __always_inline int ret(void *ctx, u8 direction, u16 sport, return 0; } static __always_inline int -__handle_send_reset(struct trace_event_raw_tcp_send_reset *ctx) { +__handle_send_reset(struct trace_event_raw_tcp_send_reset *ctx) +{ struct sock *sk = (struct sock *)ctx->skaddr; if (!sk) return 0; @@ -434,7 +498,8 @@ __handle_send_reset(struct trace_event_raw_tcp_send_reset *ctx) { } static __always_inline int -__handle_receive_reset(struct trace_event_raw_tcp_receive_reset *ctx) { +__handle_receive_reset(struct trace_event_raw_tcp_receive_reset *ctx) +{ struct sock *sk = (struct sock *)ctx->skaddr; if (!sk) return 0; diff --git a/MagicEyes/src/backend/net/net_watcher/include/net_watcher.h b/MagicEyes/src/backend/net/net_watcher/include/net_watcher.h index e331c59f7..c3253b607 100644 --- a/MagicEyes/src/backend/net/net_watcher/include/net_watcher.h +++ b/MagicEyes/src/backend/net/net_watcher/include/net_watcher.h @@ -57,7 +57,8 @@ typedef unsigned long long u64; #define CACHEMAXSIZE 5 typedef u64 stack_trace_t[MAX_STACK_DEPTH]; -struct conn_t { +struct conn_t +{ void *sock; // 此tcp连接的 socket 地址 int pid; // pid u64 ptid; // 此tcp连接的 ptid(ebpf def) @@ -90,7 +91,8 @@ struct conn_t { u64 duration; // 连接已建立时长 }; -struct pack_t { +struct pack_t +{ int err; // no err(0) invalid seq(1) invalid checksum(2) u64 mac_time; // mac layer 处理时间(us) u64 ip_time; // ip layer 处理时间(us) @@ -109,7 +111,8 @@ struct pack_t { u16 dport; }; -struct udp_message { +struct udp_message +{ u32 saddr; u32 daddr; u16 sport; @@ -118,7 +121,8 @@ struct udp_message { int rx; int len; }; -struct netfilter { +struct netfilter +{ u32 saddr; u32 daddr; u16 sport; @@ -130,7 +134,8 @@ struct netfilter { u64 post_routing_time; u32 rx; }; -struct reasonissue { +struct reasonissue +{ u32 saddr; u32 daddr; u16 sport; @@ -139,14 +144,16 @@ struct reasonissue { u16 protocol; int drop_reason; }; -struct icmptime { +struct icmptime +{ unsigned int saddr; unsigned int daddr; unsigned long long icmp_tran_time; unsigned int flag; // 0 send 1 rcv }; -struct tcp_state { +struct tcp_state +{ u32 saddr; u32 daddr; u16 sport; @@ -155,7 +162,8 @@ struct tcp_state { int newstate; u64 time; }; -struct dns_information { +struct dns_information +{ u32 saddr; u32 daddr; u16 id; @@ -169,7 +177,8 @@ struct dns_information { int response_count; int request_count; }; -struct stacktrace_event { +struct stacktrace_event +{ u32 pid; u32 cpu_id; char comm[16]; @@ -178,7 +187,9 @@ struct stacktrace_event { stack_trace_t kstack; stack_trace_t ustack; }; -typedef struct mysql_query { + +typedef struct mysql_query +{ int pid; int tid; char comm[20]; @@ -187,7 +198,8 @@ typedef struct mysql_query { u64 duratime; int count; } mysql_query; -struct redis_query { +struct redis_query +{ int pid; int tid; char comm[20]; @@ -198,7 +210,8 @@ struct redis_query { u64 begin_time; int argc; }; -struct redis_stat_query { +struct redis_stat_query +{ int pid; char comm[20]; char key[20]; @@ -207,14 +220,16 @@ struct redis_stat_query { int value_type; }; -struct RTT { +struct RTT +{ u32 saddr; u32 daddr; u64 slots[64]; u64 latency; u64 cnt; }; -struct reset_event_t { +struct reset_event_t +{ int pid; char comm[16]; u16 family; @@ -229,11 +244,13 @@ struct reset_event_t { u64 timestamp; u8 state; }; -struct packet_count { +struct packet_count +{ u64 rx_count; u64 tx_count; }; -struct packet_info { +struct packet_info +{ u32 saddr; u32 daddr; u16 sport; @@ -241,7 +258,8 @@ struct packet_info { u16 proto; struct packet_count count; }; -struct SymbolEntry { +struct SymbolEntry +{ unsigned long addr; char name[30]; }; @@ -253,13 +271,22 @@ static const char *protocol[] = { [3] = "UNKNOWN", }; static const char *tcp_states[] = { - [1] = "ESTABLISHED", [2] = "SYN_SENT", [3] = "SYN_RECV", - [4] = "FIN_WAIT1", [5] = "FIN_WAIT2", [6] = "TIME_WAIT", - [7] = "CLOSE", [8] = "CLOSE_WAIT", [9] = "LAST_ACK", - [10] = "LISTEN", [11] = "CLOSING", [12] = "NEW_SYN_RECV", + [1] = "ESTABLISHED", + [2] = "SYN_SENT", + [3] = "SYN_RECV", + [4] = "FIN_WAIT1", + [5] = "FIN_WAIT2", + [6] = "TIME_WAIT", + [7] = "CLOSE", + [8] = "CLOSE_WAIT", + [9] = "LAST_ACK", + [10] = "LISTEN", + [11] = "CLOSING", + [12] = "NEW_SYN_RECV", [13] = "UNKNOWN", }; -struct LayerDelayInfo { +struct LayerDelayInfo +{ float delay; // 时延数据 int layer_index; // 层索引 }; diff --git a/MagicEyes/src/backend/net/net_watcher/src/net_watcher.c b/MagicEyes/src/backend/net/net_watcher/src/net_watcher.c index 96e719dbc..bf139e05e 100644 --- a/MagicEyes/src/backend/net/net_watcher/src/net_watcher.c +++ b/MagicEyes/src/backend/net/net_watcher/src/net_watcher.c @@ -37,17 +37,11 @@ static volatile bool exiting = false; struct packet_count proto_stats[256] = {0}; static u64 rst_count = 0; static struct reset_event_t event_store[MAX_EVENTS]; -static int event_count = 0; -static char connects_file_path[1024]; -static char err_file_path[1024]; -static char packets_file_path[1024]; -static char udp_file_path[1024]; +static int event_count = 0, num_symbols = 0, cache_size = 0; static char binary_path[64] = ""; -int num_symbols = 0; -int cache_size = 0; -// 用于存储从 eBPF map 读取的数据 -typedef struct { +typedef struct +{ char key[256]; u32 value; } kv_pair; @@ -60,7 +54,7 @@ static int all_conn = 0, err_packet = 0, extra_conn_info = 0, layer_time = 0, drop_reason = 0, addr_to_func = 0, icmp_info = 0, tcp_info = 0, time_load = 0, dns_info = 0, stack_info = 0, mysql_info = 0, redis_info = 0, count_info = 0, rtt_info = 0, rst_info = 0, - protocol_count = 0,redis_stat = 0; // flag + protocol_count = 0, redis_stat = 0; // flag static const char argp_program_doc[] = "Watch tcp/ip in network subsystem \n"; static const struct argp_option opts[] = { @@ -96,9 +90,11 @@ static const struct argp_option opts[] = { {"protocol_count", 'p', 0, 0, "set to trace protocol count"}, {}}; -static error_t parse_arg(int key, char *arg, struct argp_state *state) { +static error_t parse_arg(int key, char *arg, struct argp_state *state) +{ char *end; - switch (key) { + switch (key) + { case 'a': all_conn = 1; break; @@ -181,7 +177,8 @@ static const struct argp argp = { .parser = parse_arg, .doc = argp_program_doc, }; -enum MonitorMode { +enum MonitorMode +{ MODE_UDP, MODE_NET_FILTER, MODE_DROP_REASON, @@ -194,34 +191,80 @@ enum MonitorMode { MODE_RST, MODE_PROTOCOL_COUNT, MODE_REDIS_STAT, + MODE_EXTRA_CONN, + MODE_RETRANS, + MODE_CONN, + MODE_ERROR, MODE_DEFAULT }; -enum MonitorMode get_monitor_mode() { - if (udp_info) { +enum MonitorMode get_monitor_mode() +{ + if (udp_info) + { return MODE_UDP; - } else if (net_filter) { + } + else if (net_filter) + { return MODE_NET_FILTER; - } else if (drop_reason) { + } + else if (drop_reason) + { return MODE_DROP_REASON; - } else if (icmp_info) { + } + else if (icmp_info) + { return MODE_ICMP; - } else if (tcp_info) { + } + else if (tcp_info) + { return MODE_TCP; - } else if (dns_info) { + } + else if (dns_info) + { return MODE_DNS; - } else if (mysql_info) { + } + else if (mysql_info) + { return MODE_MYSQL; - } else if (redis_info) { + } + else if (redis_info) + { return MODE_REDIS; - } else if (redis_stat) { + } + else if (redis_stat) + { return MODE_REDIS_STAT; - } else if (rtt_info) { + } + else if (rtt_info) + { return MODE_RTT; - } else if (rst_info) { + } + else if (rst_info) + { return MODE_RST; - } else if (protocol_count) { + } + else if (protocol_count) + { return MODE_PROTOCOL_COUNT; - } else { + } + else if (extra_conn_info) + { + return MODE_EXTRA_CONN; + } + else if (retrans_info) + { + return MODE_RETRANS; + } + else if (all_conn) + { + return MODE_CONN; + } + else if (err_packet) + { + return MODE_ERROR; + } + else + { return MODE_DEFAULT; } } @@ -242,16 +285,19 @@ enum MonitorMode get_monitor_mode() { " \\/_/\\/_/\\/____/ \\/__/ \\/__//__ / \\/_/ \\/_/\\/__/\\/____/ " \ "\\/_/\\/_/\\/____/ \\/_/ \n\n" -void print_logo() { +void print_logo() +{ char *logo = LOGO_STRING; int i = 0; FILE *lolcat_pipe = popen("/usr/games/lolcat", "w"); - if (lolcat_pipe == NULL) { + if (lolcat_pipe == NULL) + { printf("Error: Unable to execute lolcat command.\n"); return; } // 像lolcat管道逐个字符写入字符串 - while (logo[i] != '\0') { + while (logo[i] != '\0') + { fputc(logo[i], lolcat_pipe); fflush(lolcat_pipe); // 刷新管道,确保字符被立即发送给lolcat usleep(150); @@ -260,49 +306,57 @@ void print_logo() { pclose(lolcat_pipe); } -#define __ATTACH_UPROBE(skel, sym_name, prog_name, is_retprobe) \ - do { \ - LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts, .func_name = #sym_name, \ - .retprobe = is_retprobe); \ - skel->links.prog_name = bpf_program__attach_uprobe_opts( \ - skel->progs.prog_name, -1, binary_path, 0, &uprobe_opts); \ +#define __ATTACH_UPROBE(skel, sym_name, prog_name, is_retprobe) \ + do \ + { \ + LIBBPF_OPTS(bpf_uprobe_opts, uprobe_opts, .func_name = #sym_name, \ + .retprobe = is_retprobe); \ + skel->links.prog_name = bpf_program__attach_uprobe_opts( \ + skel->progs.prog_name, -1, binary_path, 0, &uprobe_opts); \ } while (false) -#define __CHECK_PROGRAM(skel, prog_name) \ - do { \ - if (!skel->links.prog_name) { \ - perror("no program attached for " #prog_name); \ - return -errno; \ - } \ +#define __CHECK_PROGRAM(skel, prog_name) \ + do \ + { \ + if (!skel->links.prog_name) \ + { \ + perror("no program attached for " #prog_name); \ + return -errno; \ + } \ } while (false) -#define __ATTACH_UPROBE_CHECKED(skel, sym_name, prog_name, is_retprobe) \ - do { \ - __ATTACH_UPROBE(skel, sym_name, prog_name, is_retprobe); \ - __CHECK_PROGRAM(skel, prog_name); \ +#define __ATTACH_UPROBE_CHECKED(skel, sym_name, prog_name, is_retprobe) \ + do \ + { \ + __ATTACH_UPROBE(skel, sym_name, prog_name, is_retprobe); \ + __CHECK_PROGRAM(skel, prog_name); \ } while (false) -#define ATTACH_UPROBE(skel, sym_name, prog_name) \ +#define ATTACH_UPROBE(skel, sym_name, prog_name) \ __ATTACH_UPROBE(skel, sym_name, prog_name, false) -#define ATTACH_URETPROBE(skel, sym_name, prog_name) \ +#define ATTACH_URETPROBE(skel, sym_name, prog_name) \ __ATTACH_UPROBE(skel, sym_name, prog_name, true) -#define ATTACH_UPROBE_CHECKED(skel, sym_name, prog_name) \ +#define ATTACH_UPROBE_CHECKED(skel, sym_name, prog_name) \ __ATTACH_UPROBE_CHECKED(skel, sym_name, prog_name, false) -#define ATTACH_URETPROBE_CHECKED(skel, sym_name, prog_name) \ +#define ATTACH_URETPROBE_CHECKED(skel, sym_name, prog_name) \ __ATTACH_UPROBE_CHECKED(skel, sym_name, prog_name, true) struct SymbolEntry symbols[300000]; struct SymbolEntry cache[CACHEMAXSIZE]; // LRU算法查找函数 -struct SymbolEntry find_in_cache(unsigned long int addr) { +struct SymbolEntry find_in_cache(unsigned long int addr) +{ // 查找地址是否在快表中 - for (int i = 0; i < cache_size; i++) { - if (cache[i].addr == addr) { + for (int i = 0; i < cache_size; i++) + { + if (cache[i].addr == addr) + { // 更新访问时间 struct SymbolEntry temp = cache[i]; // 将访问的元素移动到快表的最前面,即最近使用的位置 - for (int j = i; j > 0; j--) { + for (int j = i; j > 0; j--) + { cache[j] = cache[j - 1]; } cache[0] = temp; @@ -315,55 +369,72 @@ struct SymbolEntry find_in_cache(unsigned long int addr) { return empty_entry; } // 将新的符号条目加入快表 -void add_to_cache(struct SymbolEntry entry) { +void add_to_cache(struct SymbolEntry entry) +{ // 如果快表已满,则移除最久未使用的条目 - if (cache_size == CACHEMAXSIZE) { - for (int i = cache_size - 1; i > 0; i--) { + if (cache_size == CACHEMAXSIZE) + { + for (int i = cache_size - 1; i > 0; i--) + { cache[i] = cache[i - 1]; } cache[0] = entry; - } else { + } + else + { // 否则,直接加入快表 - for (int i = cache_size; i > 0; i--) { + for (int i = cache_size; i > 0; i--) + { cache[i] = cache[i - 1]; } cache[0] = entry; cache_size++; } } -struct SymbolEntry findfunc(unsigned long int addr) { +struct SymbolEntry findfunc(unsigned long int addr) +{ // 先在快表中查找 struct SymbolEntry entry = find_in_cache(addr); - if (entry.addr != 0) { + if (entry.addr != 0) + { return entry; } unsigned long long low = 0, high = num_symbols - 1; unsigned long long result = -1; - while (low <= high) { + while (low <= high) + { int mid = low + (high - low) / 2; - if (symbols[mid].addr < addr) { + if (symbols[mid].addr < addr) + { result = mid; low = mid + 1; - } else { + } + else + { high = mid - 1; } } add_to_cache(symbols[result]); return symbols[result]; }; -void readallsym() { + +void readallsym() +{ FILE *file = fopen("/proc/kallsyms", "r"); - if (!file) { + if (!file) + { perror("Error opening file"); exit(EXIT_FAILURE); } char line[256]; - while (fgets(line, sizeof(line), file)) { + while (fgets(line, sizeof(line), file)) + { unsigned long addr; char type, name[30]; int ret = sscanf(line, "%lx %c %s", &addr, &type, name); - if (ret == 3) { + if (ret == 3) + { symbols[num_symbols].addr = addr; strncpy(symbols[num_symbols].name, name, 30); num_symbols++; @@ -387,17 +458,20 @@ float ewma_values[NUM_LAYERS] = {0}; int count[NUM_LAYERS] = {0}; // 指数加权移动平均算法 -float calculate_ewma(float new_value, float old_ewma) { +float calculate_ewma(float new_value, float old_ewma) +{ return ALPHA * new_value + (1 - ALPHA) * old_ewma; } // 收集时延数据并检测异常 -int process_delay(float layer_delay, int layer_index) { +int process_delay(float layer_delay, int layer_index) +{ if (layer_delay == 0) return 0; count[layer_index]++; - if (ewma_values[layer_index] == 0) { + if (ewma_values[layer_index] == 0) + { ewma_values[layer_index] = layer_delay; return 0; } @@ -405,19 +479,24 @@ int process_delay(float layer_delay, int layer_index) { ewma_values[layer_index] = calculate_ewma(layer_delay, ewma_values[layer_index]); float threshold = ewma_values[layer_index] * GRANULARITY; - if (count[layer_index] > 30) { + if (count[layer_index] > 30) + { // 判断当前时延是否超过阈值 // printf("%d %d:%f %f // ",layer_index,count[layer_index]++,threshold,layer_delay); - if (layer_delay > threshold) { // 异常 + if (layer_delay > threshold) + { // 异常 return 1; - } else { + } + else + { return 0; } } return 0; } -static void set_rodata_flags(struct net_watcher_bpf *skel) { +static void set_rodata_flags(struct net_watcher_bpf *skel) +{ skel->rodata->filter_dport = dport; skel->rodata->filter_sport = sport; skel->rodata->all_conn = all_conn; @@ -440,7 +519,8 @@ static void set_rodata_flags(struct net_watcher_bpf *skel) { skel->rodata->rst_info = rst_info; skel->rodata->protocol_count = protocol_count; } -static void set_disable_load(struct net_watcher_bpf *skel) { +static void set_disable_load(struct net_watcher_bpf *skel) +{ bpf_program__set_autoload(skel->progs.inet_csk_accept_exit, (all_conn || err_packet || extra_conn_info || @@ -614,8 +694,10 @@ static void set_disable_load(struct net_watcher_bpf *skel) { bpf_program__set_autoload(skel->progs.handle_receive_reset, rst_info ? true : false); } -static void print_header(enum MonitorMode mode) { - switch (mode) { +static void print_header(enum MonitorMode mode) +{ + switch (mode) + { case MODE_UDP: printf("===============================================================" "UDP " @@ -681,12 +763,12 @@ static void print_header(enum MonitorMode mode) { printf("%-20s %-20s %-20s %-20s %-20s \n", "Pid", "Comm", "Size", "Redis", "duration/μs"); break; - case MODE_REDIS_STAT: + case MODE_REDIS_STAT: printf("===============================================================" "====================REDIS " "INFORMATION====================================================" "============================\n"); - printf("%-20s %-20s %-20s %-20s %-20s %-20s\n", "Pid", "Comm", "key", "Key_count","Value_Type","Value"); + printf("%-20s %-20s %-20s %-20s %-20s %-20s\n", "Pid", "Comm", "key", "Key_count", "Value_Type", "Value"); break; case MODE_RTT: printf("===============================================================" @@ -699,16 +781,44 @@ static void print_header(enum MonitorMode mode) { "====================RST " "INFORMATION====================================================" "============================\n"); - printf("%-20s %-20s %-20s %-20s %-20s %-20s %-20s \n", "Pid", "Comm", + printf("%-10s %-20s %-10s %-10s %-10s %-10s %-20s \n", "Pid", "Comm", "Saddr", "Daddr", "Sport", "Dport", "Time"); break; + case MODE_EXTRA_CONN: + printf("===============================================================" + "====================EXTRA CONN " + "INFORMATION====================================================" + "============================\n"); + printf("%-15s %-15s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-10s %-13s %-10s %-10s %-10s %-10s\n", "Saddr", "Daddr", "Sport", "Dport", "backlog", "maxbacklog", "rwnd", "cwnd", "ssthresh", "sndbuf", "wmem_queued", "rx_bytes", "tx_bytes", "srtt", "duration"); + break; + case MODE_RETRANS: + printf("===============================================================" + "====================RETRANS " + "INFORMATION====================================================" + "============================\n"); + printf("%-15s %-15s %-10s %-10s %-10s %-10s %-10s\n", "Saddr", "Daddr", "Sport", "Dport", "fastRe", "total_retrans", "timeout"); + break; + case MODE_CONN: + printf("===============================================================" + "====================CONN " + "INFORMATION====================================================" + "============================\n"); + printf("%-15s %-20s %-15s %-15s %-10s %-10s %-10s\n", "Pid", "Sock", "Saddr", "Daddr", "Sport", "Dport", "Is_Server"); + break; case MODE_DEFAULT: printf("===============================================================" "=INFORMATION===================================================" "======================\n"); - printf("%-22s %-20s %-8s %-20s %-8s %-15s %-15s %-15s %-15s %-15s \n", + printf("%-22s %-20s %-8s %-20s %-8s %-15s %-15s %-15s %-14s %-14s %-14s %-16s \n", "SOCK", "Saddr", "Sport", "Daddr", "Dport", "MAC_TIME/μs", - "IP_TIME/μs", "TRAN_TIME/μs", "RX/direction", "HTTP"); + "IP_TIME/μs", "TRAN_TIME/μs", "Seq", "Ack", "RX/direction", "HTTP"); + break; + case MODE_ERROR: + printf("===============================================================" + "=ERROR INFORMATION===================================================" + "======================\n"); + printf("%-22s %-20s %-8s %-20s %-8s %-14s %-14s %-15s \n", + "SOCK", "Saddr", "Sport", "Daddr", "Dport", "Seq", "Ack", "Reason"); break; case MODE_PROTOCOL_COUNT: printf("===============================================================" @@ -718,64 +828,40 @@ static void print_header(enum MonitorMode mode) { break; } } -static void open_log_files() { - FILE *connect_file = fopen(connects_file_path, "w+"); - if (connect_file == NULL) { - fprintf(stderr, "Failed to open connect.log: (%s)\n", strerror(errno)); - exit(EXIT_FAILURE); - } - fclose(connect_file); - - FILE *err_file = fopen(err_file_path, "w+"); - if (err_file == NULL) { - fprintf(stderr, "Failed to open err.log: (%s)\n", strerror(errno)); - exit(EXIT_FAILURE); - } - fclose(err_file); - - FILE *packet_file = fopen(packets_file_path, "w+"); - if (packet_file == NULL) { - fprintf(stderr, "Failed to open packets.log: (%s)\n", strerror(errno)); - exit(EXIT_FAILURE); - } - fclose(packet_file); - - FILE *udp_file = fopen(udp_file_path, "w+"); - if (udp_file == NULL) { - fprintf(stderr, "Failed to open udp.log: (%s)\n", strerror(errno)); - exit(EXIT_FAILURE); - } - fclose(udp_file); -} static void sig_handler(int signo) { exiting = true; } -static void bytes_to_str(char *str, unsigned long long num) { - if (num > 1e9) { +static void bytes_to_str(char *str, unsigned long long num) +{ + if (num > 1e9) + { sprintf(str, "%.8lfG", (double)num / 1e9); - } else if (num > 1e6) { + } + else if (num > 1e6) + { sprintf(str, "%.6lfM", (double)num / 1e6); - } else if (num > 1e3) { + } + else if (num > 1e3) + { sprintf(str, "%.3lfK", (double)num / 1e3); - } else { + } + else + { sprintf(str, "%llu", num); } } -static int print_conns(struct net_watcher_bpf *skel) { - - FILE *file = fopen(connects_file_path, "w"); - if (file == NULL) { - fprintf(stderr, "Failed to open connects.log: (%s)\n", strerror(errno)); - return 0; - } +static int print_conns(struct net_watcher_bpf *skel) +{ int map_fd = bpf_map__fd(skel->maps.conns_info); struct sock *sk = NULL; - while (bpf_map_get_next_key(map_fd, &sk, &sk) == 0) { + while (bpf_map_get_next_key(map_fd, &sk, &sk) == 0) + { // fprintf(stdout, "next_sk: (%p)\n", sk); struct conn_t d = {}; int err = bpf_map_lookup_elem(map_fd, &sk, &d); - if (err) { + if (err) + { fprintf(stderr, "Failed to read value from the conns map: (%s)\n", strerror(errno)); return 0; @@ -791,72 +877,59 @@ static int print_conns(struct net_watcher_bpf *skel) { if ((d.saddr & 0x0000FFFF) == 0x0000007F || (d.daddr & 0x0000FFFF) == 0x0000007F) return 0; - if (d.family == AF_INET) { - sprintf(s_ip_port_str, "%s:%d", - inet_ntop(AF_INET, &d.saddr, s_str, sizeof(s_str)), - d.sport); - sprintf(d_ip_port_str, "%s:%d", - inet_ntop(AF_INET, &d.daddr, d_str, sizeof(d_str)), - d.dport); - } else { // AF_INET6 - sprintf( - s_ip_port_str, "%s:%d", - inet_ntop(AF_INET6, &d.saddr_v6, s_str_v6, sizeof(s_str_v6)), - d.sport); - sprintf( - d_ip_port_str, "%s:%d", - inet_ntop(AF_INET6, &d.daddr_v6, d_str_v6, sizeof(d_str_v6)), - d.dport); + if (d.family == AF_INET) + { + inet_ntop(AF_INET, &d.saddr, s_str, sizeof(s_str)); + inet_ntop(AF_INET, &d.daddr, d_str, sizeof(d_str)); + sprintf(s_ip_port_str, "%s:%d", s_str, d.sport); + sprintf(d_ip_port_str, "%s:%d", d_str, d.dport); + } + else + { + inet_ntop(AF_INET6, &d.saddr_v6, s_str_v6, sizeof(s_str_v6)); + inet_ntop(AF_INET6, &d.daddr_v6, d_str_v6, sizeof(d_str_v6)); + sprintf(s_ip_port_str, "%s:%d", s_str_v6, d.sport); + sprintf(d_ip_port_str, "%s:%d", d_str_v6, d.dport); } + + char s_ip_only[INET_ADDRSTRLEN]; + char d_ip_only[INET_ADDRSTRLEN]; + strncpy(s_ip_only, s_str, sizeof(s_ip_only)); + strncpy(d_ip_only, d_str, sizeof(d_ip_only)); + char received_bytes[11], acked_bytes[11]; bytes_to_str(received_bytes, d.bytes_received); bytes_to_str(acked_bytes, d.bytes_acked); - fprintf(file, - "connection{pid=\"%d\",sock=\"%p\",src=\"%s\",dst=\"%s\"," - "is_server=\"%d\"", - d.pid, d.sock, s_ip_port_str, d_ip_port_str, d.is_server); - if (extra_conn_info) { - fprintf(file, - ",backlog=\"%u\"" - ",maxbacklog=\"%u\"" - ",rwnd=\"%u\"" - ",cwnd=\"%u\"" - ",ssthresh=\"%u\"" - ",sndbuf=\"%u\"" - ",wmem_queued=\"%u\"" - ",rx_bytes=\"%s\"" - ",tx_bytes=\"%s\"" - ",srtt=\"%u\"" - ",duration=\"%llu\"" - ",total_retrans=\"%u\"", - d.tcp_backlog, d.max_tcp_backlog, d.rcv_wnd, d.snd_cwnd, - d.snd_ssthresh, d.sndbuf, d.sk_wmem_queued, received_bytes, - acked_bytes, d.srtt, d.duration, d.total_retrans); - } else { - fprintf(file, - ",backlog=\"-\",maxbacklog=\"-\",cwnd=\"-\",ssthresh=\"-\"," - "sndbuf=\"-\",wmem_queued=\"-\",rx_bytes=\"-\",tx_bytes=\"-" - "\",srtt=\"-\",duration=\"-\",total_retrans=\"-\""); + + if (extra_conn_info) + { + printf("%-15s %-15s %-10d %-10d %-10u %-10u %-10u %-10u %-10u %-10u %-13u %-10s %-10s %-10u %-10llu\n", + s_ip_only, d_ip_only, d.sport, d.dport, d.tcp_backlog, + d.max_tcp_backlog, d.rcv_wnd, d.snd_cwnd, d.snd_ssthresh, + d.sndbuf, d.sk_wmem_queued, received_bytes, acked_bytes, d.srtt, + d.duration); } - if (retrans_info) { - fprintf(file, ",fast_retrans=\"%u\",timeout_retrans=\"%u\"", - d.fastRe, d.timeout); - } else { - fprintf(file, ",fast_retrans=\"-\",timeout_retrans=\"-\""); + if (retrans_info) + { + printf("%-15s %-15s %-10d %-10d %-10u %-14u %-10u\n", s_ip_only, d_ip_only, d.sport, d.dport, d.fastRe, d.total_retrans, d.timeout); + } + if (all_conn) + { + printf("%-15d %-20p %-15s %-15s %-10d %-10d %-10u\n", d.pid, d.sock, s_ip_only, d_ip_only, d.sport, d.dport, d.is_server); } - fprintf(file, "}\n"); } - fflush(file); - fclose(file); return 0; } -static int print_packet(void *ctx, void *packet_info, size_t size) { - if (udp_info || net_filter || drop_reason || icmp_info || tcp_info || - dns_info || mysql_info || redis_info || rtt_info || protocol_count||redis_stat) +static int print_packet(void *ctx, void *packet_info, size_t size) +{ + if (udp_info || net_filter || drop_reason || icmp_info || tcp_info || all_conn || + dns_info || mysql_info || redis_info || rtt_info || protocol_count || redis_stat || extra_conn_info || retrans_info) return 0; + char http_data[256]; const struct pack_t *pack_info = packet_info; if (pack_info->mac_time > MAXTIME || pack_info->ip_time > MAXTIME || - pack_info->tran_time > MAXTIME) { + pack_info->tran_time > MAXTIME) + { return 0; } char d_str[INET_ADDRSTRLEN]; @@ -872,104 +945,95 @@ static int print_packet(void *ctx, void *packet_info, size_t size) { if (sport) if (pack_info->sport != sport) return 0; - if (pack_info->err) { - FILE *file = fopen(err_file_path, "a"); - char reason[20]; - if (pack_info->err == 1) { - printf("[X] invalid SEQ: sock = %p,seq= %u,ack = %u\n", - pack_info->sock, pack_info->seq, pack_info->ack); - sprintf(reason, "Invalid SEQ"); - } else if (pack_info->err == 2) { - printf("[X] invalid checksum: sock = %p\n", pack_info->sock); - sprintf(reason, "Invalid checksum"); - } else { - printf("UNEXPECTED packet error %d.\n", pack_info->err); - sprintf(reason, "Unkonwn"); - } - fprintf(file, - "error{sock=\"%p\",seq=\"%u\",ack=\"%u\"," - "reason=\"%s\"} \n", - pack_info->sock, pack_info->seq, pack_info->ack, reason); - fclose(file); - } else { - FILE *file = fopen(packets_file_path, "a"); - char http_data[256]; - - if (strstr((char *)pack_info->data, "HTTP/1")) { + if (strstr((char *)pack_info->data, "HTTP/1")) + { - for (int i = 0; i < sizeof(pack_info->data); ++i) { - if (pack_info->data[i] == '\r') { - http_data[i] = '\0'; - break; - } - http_data[i] = pack_info->data[i]; + for (int i = 0; i < sizeof(pack_info->data); ++i) + { + if (pack_info->data[i] == '\r') + { + http_data[i] = '\0'; + break; } - } else { - - sprintf(http_data, "-"); + http_data[i] = pack_info->data[i]; } - if (layer_time) { - printf("%-22p %-20s %-8d %-20s %-8d %-14llu %-14llu %-14llu %-15d " - "%-16s", - pack_info->sock, - inet_ntop(AF_INET, &saddr, s_str, sizeof(s_str)), - pack_info->sport, - inet_ntop(AF_INET, &daddr, d_str, sizeof(d_str)), - pack_info->dport, pack_info->mac_time, pack_info->ip_time, - pack_info->tran_time, pack_info->rx, http_data); - fprintf( - file, - "packet{sock=\"%p\",saddr=\"%s\",sport=\"%d\",daddr=\"%s\"," - "dport=\"%d\",seq=\"%u\",ack=\"%u\"," - "mac_time=\"%llu\",ip_time=\"%llu\",tran_time=\"%llu\",http_" - "info=\"%s\",rx=\"%d\"} \n", - pack_info->sock, - inet_ntop(AF_INET, &saddr, s_str, sizeof(s_str)), - pack_info->sport, - inet_ntop(AF_INET, &daddr, d_str, sizeof(d_str)), - pack_info->dport, pack_info->seq, pack_info->ack, - pack_info->mac_time, pack_info->ip_time, pack_info->tran_time, - http_data, pack_info->rx); - } else { - printf("%-22p %-20s %-8d %-20s %-8d %-10d %-10d %-10d %-5d %-10s", + } + else + { + sprintf(http_data, "-"); + } + if (layer_time) + { + printf("%-22p %-20s %-8d %-20s %-8d %-14llu %-14llu %-14llu %-14u %-14u %-14d " + "%-16s", + pack_info->sock, + inet_ntop(AF_INET, &saddr, s_str, sizeof(s_str)), + pack_info->sport, + inet_ntop(AF_INET, &daddr, d_str, sizeof(d_str)), + pack_info->dport, pack_info->mac_time, pack_info->ip_time, + pack_info->tran_time, pack_info->seq, pack_info->ack, pack_info->rx, http_data); + } + else if (err_packet) + { + if (pack_info->err) + { + char reason[20]; + if (pack_info->err == 1) + { + printf("[X] invalid SEQ: sock = %p,seq= %u,ack = %u\n", + pack_info->sock, pack_info->seq, pack_info->ack); + sprintf(reason, "Invalid SEQ"); + } + else if (pack_info->err == 2) + { + printf("[X] invalid checksum: sock = %p\n", pack_info->sock); + sprintf(reason, "Invalid checksum"); + } + else + { + printf("UNEXPECTED packet error %d.\n", pack_info->err); + sprintf(reason, "Unkonwn"); + } + printf("%-22p %-20s %-8d %-20s %-8d %-14u %-14u %-14s ", pack_info->sock, inet_ntop(AF_INET, &saddr, s_str, sizeof(s_str)), pack_info->sport, inet_ntop(AF_INET, &daddr, d_str, sizeof(d_str)), - pack_info->dport, 0, 0, 0, pack_info->rx, http_data); - fprintf(file, - "packet{sock=\"%p\",saddr=\"%s\",sport=\"%d\",daddr=\"%s\"," - "dport=\"%d\",seq=\"%u\",ack=\"%u\"," - "mac_time=\"%d\",ip_time=\"%d\",tran_time=\"%d\",http_" - "info=\"%s\",rx=\"%d\"} \n", - pack_info->sock, - inet_ntop(AF_INET, &saddr, s_str, sizeof(s_str)), - pack_info->sport, - inet_ntop(AF_INET, &daddr, d_str, sizeof(d_str)), - pack_info->dport, pack_info->seq, pack_info->ack, 0, 0, 0, - http_data, pack_info->rx); + pack_info->dport, pack_info->seq, pack_info->ack, reason); } - fclose(file); } - if (time_load) { + else + { + printf("%-22p %-20s %-8d %-20s %-8d %-14u %-14u %-14u %-14u %-14u %-14d %-16s\n", + pack_info->sock, + inet_ntop(AF_INET, &saddr, s_str, sizeof(s_str)), + pack_info->sport, + inet_ntop(AF_INET, &daddr, d_str, sizeof(d_str)), + pack_info->dport, 0, 0, 0, pack_info->seq, pack_info->ack, pack_info->rx, http_data); + } + if (time_load) + { int mac = process_delay(pack_info->mac_time, 0); int ip = process_delay(pack_info->ip_time, 1); int tran = process_delay(pack_info->tran_time, 2); - if (mac || ip || tran) { + if (mac || ip || tran) + { printf("%-15s", "abnormal data"); } } printf("\n"); return 0; } -static int print_udp(void *ctx, void *packet_info, size_t size) { +static int print_udp(void *ctx, void *packet_info, size_t size) +{ if (!udp_info) return 0; - FILE *file = fopen(udp_file_path, "a+"); // 追加 - if (file == NULL) { - fprintf(stderr, "Failed to open udp.log: (%s)\n", strerror(errno)); - return 0; - } + // FILE *file = fopen(udp_file_path, "a+"); // 追加 + // if (file == NULL) + // { + // fprintf(stderr, "Failed to open udp.log: (%s)\n", strerror(errno)); + // return 0; + // } char d_str[INET_ADDRSTRLEN]; char s_str[INET_ADDRSTRLEN]; const struct udp_message *pack_info = packet_info; @@ -983,15 +1047,16 @@ static int print_udp(void *ctx, void *packet_info, size_t size) { inet_ntop(AF_INET, &daddr, d_str, sizeof(d_str)), pack_info->sport, pack_info->dport, pack_info->tran_time, pack_info->rx, pack_info->len); - fprintf(file, - "packet{saddr=\"%s\",daddr=\"%s\",sport=\"%u\"," - "dport=\"%u\",udp_time=\"%llu\",rx=\"%d\",len=\"%d\"} \n", - inet_ntop(AF_INET, &saddr, s_str, sizeof(s_str)), - inet_ntop(AF_INET, &daddr, d_str, sizeof(d_str)), pack_info->sport, - pack_info->dport, pack_info->tran_time, pack_info->rx, - pack_info->len); - fclose(file); - if (time_load) { + // fprintf(file, + // "packet{saddr=\"%s\",daddr=\"%s\",sport=\"%u\"," + // "dport=\"%u\",udp_time=\"%llu\",rx=\"%d\",len=\"%d\"} \n", + // inet_ntop(AF_INET, &saddr, s_str, sizeof(s_str)), + // inet_ntop(AF_INET, &daddr, d_str, sizeof(d_str)), pack_info->sport, + // pack_info->dport, pack_info->tran_time, pack_info->rx, + // pack_info->len); + // fclose(file); + if (time_load) + { int flag = process_delay(pack_info->tran_time, 3); if (flag) printf("%-15s", "abnormal data"); @@ -999,7 +1064,8 @@ static int print_udp(void *ctx, void *packet_info, size_t size) { printf("\n"); return 0; } -static int print_netfilter(void *ctx, void *packet_info, size_t size) { +static int print_netfilter(void *ctx, void *packet_info, size_t size) +{ if (!net_filter) return 0; char d_str[INET_ADDRSTRLEN]; @@ -1030,9 +1096,11 @@ static int print_netfilter(void *ctx, void *packet_info, size_t size) { {pack_info->forward_time, 6}, {pack_info->post_routing_time, 7}, {pack_info->local_out_time, 8}}; - if (time_load) { + if (time_load) + { // 循环遍历数组 - for (int i = 0; i < 5; i++) { + for (int i = 0; i < 5; i++) + { // 数组的总字节数除以第一个元素的字节数得到元素的个数 float delay = layer_delay_infos[i].delay; int layer_net = layer_delay_infos[i].layer_index; @@ -1045,7 +1113,8 @@ static int print_netfilter(void *ctx, void *packet_info, size_t size) { return 0; } -static int print_tcpstate(void *ctx, void *packet_info, size_t size) { +static int print_tcpstate(void *ctx, void *packet_info, size_t size) +{ if (!tcp_info) return 0; char d_str[INET_ADDRSTRLEN]; @@ -1062,60 +1131,80 @@ static int print_tcpstate(void *ctx, void *packet_info, size_t size) { return 0; } static void calculate_protocol_usage(struct packet_count proto_stats[], - int num_protocols, int interval) { + int num_protocols, int interval) +{ static uint64_t last_rx[256] = {0}, last_tx[256] = {0}; uint64_t current_rx = 0, current_tx = 0; uint64_t delta_rx[256] = {0}, delta_tx[256] = {0}; - //遍历所有的协议 - for (int i = 0; i < num_protocols; i++) { - //计算数据包增量 - if (proto_stats[i].rx_count >= last_rx[i]) { + // 遍历所有的协议 + for (int i = 0; i < num_protocols; i++) + { + // 计算数据包增量 + if (proto_stats[i].rx_count >= last_rx[i]) + { delta_rx[i] = proto_stats[i].rx_count - last_rx[i]; - } else { + } + else + { delta_rx[i] = proto_stats[i].rx_count; } - if (proto_stats[i].tx_count >= last_tx[i]) { + if (proto_stats[i].tx_count >= last_tx[i]) + { delta_tx[i] = proto_stats[i].tx_count - last_tx[i]; - } else { + } + else + { delta_tx[i] = proto_stats[i].tx_count; } - //时间段内总的接收和发送包数 + // 时间段内总的接收和发送包数 current_rx += delta_rx[i]; current_tx += delta_tx[i]; - //更新上次统计的包数 + // 更新上次统计的包数 last_rx[i] = proto_stats[i].rx_count; last_tx[i] = proto_stats[i].tx_count; } printf("Protocol Usage in Last %d Seconds:\n", interval); printf("Total_rx_count:%ld Total_tx_count:%ld\n", current_rx, current_tx); - if (current_rx > 0) { + if (current_rx > 0) + { printf("Receive Protocol Usage:\n"); - for (int i = 0; i < num_protocols; i++) { - if (delta_rx[i] > 0) { + for (int i = 0; i < num_protocols; i++) + { + if (delta_rx[i] > 0) + { double rx_percentage = (double)delta_rx[i] / current_rx * 100; - if (rx_percentage >= 80.0) { + if (rx_percentage >= 80.0) + { printf(RED_TEXT "Protocol %s: %.2f%% Rx_count:%ld\n" RESET_TEXT, protocol[i], rx_percentage, delta_rx[i]); - } else { + } + else + { printf("Protocol %s: %.2f%% Rx_count:%ld\n", protocol[i], rx_percentage, delta_rx[i]); } } } } - if (current_tx > 0) { + if (current_tx > 0) + { printf("Transmit Protocol Usage:\n"); - for (int i = 0; i < num_protocols; i++) { - if (delta_tx[i] > 0) { + for (int i = 0; i < num_protocols; i++) + { + if (delta_tx[i] > 0) + { double tx_percentage = (double)delta_tx[i] / current_tx * 100; - if (tx_percentage >= 80.0) { + if (tx_percentage >= 80.0) + { printf(RED_TEXT "Protocol %s: %.2f%% Tx_count:%ld\n" RESET_TEXT, protocol[i], tx_percentage, delta_tx[i]); - } else { + } + else + { printf("Protocol %s: %.2f%% Tx_count:%ld\n", protocol[i], tx_percentage, delta_tx[i]); } @@ -1124,10 +1213,12 @@ static void calculate_protocol_usage(struct packet_count proto_stats[], } memset(proto_stats, 0, num_protocols * sizeof(struct packet_count)); } -static int print_protocol_count(void *ctx, void *packet_info, size_t size) { +static int print_protocol_count(void *ctx, void *packet_info, size_t size) +{ const struct packet_info *pack_protocol_info = (const struct packet_info *)packet_info; - if (!protocol_count) { + if (!protocol_count) + { return 0; } proto_stats[pack_protocol_info->proto].rx_count = @@ -1136,7 +1227,8 @@ static int print_protocol_count(void *ctx, void *packet_info, size_t size) { pack_protocol_info->count.tx_count; return 0; } -static int print_kfree(void *ctx, void *packet_info, size_t size) { +static int print_kfree(void *ctx, void *packet_info, size_t size) +{ if (!drop_reason) return 0; char d_str[INET_ADDRSTRLEN]; @@ -1144,15 +1236,21 @@ static int print_kfree(void *ctx, void *packet_info, size_t size) { const struct reasonissue *pack_info = packet_info; unsigned int saddr = pack_info->saddr; unsigned int daddr = pack_info->daddr; - if (saddr == 0 && daddr == 0) { + if (saddr == 0 && daddr == 0) + { return 0; } char prot[6]; - if (pack_info->protocol == 2048) { + if (pack_info->protocol == 2048) + { strcpy(prot, "ipv4"); - } else if (pack_info->protocol == 34525) { + } + else if (pack_info->protocol == 34525) + { strcpy(prot, "ipv6"); - } else { + } + else + { // 其他协议 strcpy(prot, "other"); } @@ -1165,7 +1263,8 @@ static int print_kfree(void *ctx, void *packet_info, size_t size) { pack_info->dport, prot); if (!addr_to_func) printf("%-34lx", pack_info->location); - else { + else + { struct SymbolEntry data = findfunc(pack_info->location); char result[40]; sprintf(result, "%s+0x%lx", data.name, pack_info->location - data.addr); @@ -1174,13 +1273,15 @@ static int print_kfree(void *ctx, void *packet_info, size_t size) { printf("%s\n", SKB_Drop_Reason_Strings[pack_info->drop_reason]); return 0; } -static int print_icmptime(void *ctx, void *packet_info, size_t size) { +static int print_icmptime(void *ctx, void *packet_info, size_t size) +{ if (!icmp_info) return 0; char d_str[INET_ADDRSTRLEN]; char s_str[INET_ADDRSTRLEN]; const struct icmptime *pack_info = packet_info; - if (pack_info->icmp_tran_time > MAXTIME) { + if (pack_info->icmp_tran_time > MAXTIME) + { return 0; } unsigned int saddr = pack_info->saddr; @@ -1189,23 +1290,28 @@ static int print_icmptime(void *ctx, void *packet_info, size_t size) { inet_ntop(AF_INET, &saddr, s_str, sizeof(s_str)), inet_ntop(AF_INET, &daddr, d_str, sizeof(d_str)), pack_info->icmp_tran_time, pack_info->flag); - if (time_load) { + if (time_load) + { int icmp_data = process_delay(pack_info->icmp_tran_time, 9); - if (icmp_data) { + if (icmp_data) + { printf("%-15s\n", "abnormal data"); } } printf("\n"); return 0; } -static int print_rst(void *ctx, void *packet_info, size_t size) { - if (!rst_info) { +static int print_rst(void *ctx, void *packet_info, size_t size) +{ + if (!rst_info) + { return 0; } struct reset_event_t *event = packet_info; // 将事件存储到全局存储中 - if (event_count < MAX_EVENTS) { + if (event_count < MAX_EVENTS) + { memcpy(&event_store[event_count], event, sizeof(struct reset_event_t)); event_count++; } @@ -1213,53 +1319,67 @@ static int print_rst(void *ctx, void *packet_info, size_t size) { rst_count++; return 0; } -static void print_stored_events() { +static void print_stored_events() +{ char s_str[INET_ADDRSTRLEN]; char d_str[INET_ADDRSTRLEN]; - - for (int i = 0; i < event_count; i++) { + char saddr_v6[INET6_ADDRSTRLEN]; + char daddr_v6[INET6_ADDRSTRLEN]; + + for (int i = 0; i < event_count; i++) + { struct reset_event_t *event = &event_store[i]; unsigned int saddr = event->saddr; unsigned int daddr = event->daddr; - if (event->family == AF_INET) { + if (event->family == AF_INET) + { inet_ntop(AF_INET, &saddr, s_str, sizeof(s_str)); inet_ntop(AF_INET, &daddr, d_str, sizeof(d_str)); - printf("%-20llu %-20s %-20s %-20s %-20u %-20u %-20llu\n", - (unsigned long long)event->pid, event->comm, s_str, d_str, + printf("%-10d %-10s %-10s %-10s %-10u %-10u %-20llu", + event->pid, event->comm, s_str, d_str, event->sport, event->dport, - (unsigned long long)event->timestamp); - } else if (event->family == AF_INET6) { - char saddr_v6[INET6_ADDRSTRLEN]; - char daddr_v6[INET6_ADDRSTRLEN]; + event->timestamp); + } + else if (event->family == AF_INET6) + { + inet_ntop(AF_INET6, &event->saddr_v6, saddr_v6, sizeof(saddr_v6)); inet_ntop(AF_INET6, &event->daddr_v6, daddr_v6, sizeof(daddr_v6)); - printf("%-10llu %-16s %-16s %-16s %-8u %-8u %-20llu\n", - (unsigned long long)event->pid, event->comm, saddr_v6, + printf("%-10d %10s %-10s %-10s %-10u %-10u %-20llu\n", + event->pid, event->comm, saddr_v6, daddr_v6, event->sport, event->dport, - (unsigned long long)event->timestamp); + event->timestamp); } + printf("\n"); } } -static void print_domain_name(const unsigned char *data, char *output) { +static void print_domain_name(const unsigned char *data, char *output) +{ const unsigned char *next = data; int pos = 0, first = 1; // 循环到尾部,标志0 - while (*next != 0) { - if (!first) { + while (*next != 0) + { + if (!first) + { output[pos++] = '.'; // 在每个段之前添加点号 - } else { + } + else + { first = 0; // 第一个段后清除标志 } int len = *next++; // 下一个段长度 - for (int i = 0; i < len; ++i) { + for (int i = 0; i < len; ++i) + { output[pos++] = *next++; } } output[pos] = '\0'; // 确保字符串正确结束 } -static int print_dns(void *ctx, void *packet_info, size_t size) { +static int print_dns(void *ctx, void *packet_info, size_t size) +{ if (!packet_info) return 0; char d_str[INET_ADDRSTRLEN]; @@ -1274,7 +1394,8 @@ static int print_dns(void *ctx, void *packet_info, size_t size) { inet_ntop(AF_INET, &daddr, d_str, sizeof(d_str)); print_domain_name((const unsigned char *)pack_info->data, domain_name); - if (pack_info->daddr == 0) { + if (pack_info->daddr == 0) + { return 0; } printf("%-20s %-20s %-#12x %-#12x %-5x %-5x %-5x %-5x %-47s %-10d %-10d " @@ -1285,27 +1406,34 @@ static int print_dns(void *ctx, void *packet_info, size_t size) { pack_info->rx); return 0; } -static int print_mysql(void *ctx, void *packet_info, size_t size) { - if (!mysql_info) { +static int print_mysql(void *ctx, void *packet_info, size_t size) +{ + if (!mysql_info) + { return 0; } const mysql_query *pack_info = packet_info; printf("%-20d %-20d %-20s %-20u %-41s", pack_info->pid, pack_info->tid, pack_info->comm, pack_info->size, pack_info->msql); - if (pack_info->duratime > count_info) { + if (pack_info->duratime > count_info) + { printf("%-21llu", pack_info->duratime); - } else { + } + else + { printf("%-21s", ""); } printf("%-20d\n", pack_info->count); return 0; } -static int print_redis(void *ctx, void *packet_info, size_t size) { +static int print_redis(void *ctx, void *packet_info, size_t size) +{ const struct redis_query *pack_info = packet_info; int i = 0; char redis[64]; - for (i = 0; i < pack_info->argc; i++) { + for (i = 0; i < pack_info->argc; i++) + { strcat(redis, pack_info->redis[i]); strcat(redis, " "); } @@ -1314,74 +1442,85 @@ static int print_redis(void *ctx, void *packet_info, size_t size) { strcpy(redis, ""); return 0; } -static int process_redis_first(char flag,char *message) { - if(flag=='+') +static int process_redis_first(char flag, char *message) +{ + if (flag == '+') { strcpy(message, "Status Reply"); } - else if (flag=='-') + else if (flag == '-') { strcpy(message, "Error Reply"); } - else if (flag==':') + else if (flag == ':') { strcpy(message, "Integer Reply"); } - else if (flag=='$') + else if (flag == '$') { strcpy(message, "Bulk String Reply"); } - else if (flag=='*') + else if (flag == '*') { strcpy(message, "Array Reply"); } - else{ + else + { strcpy(message, "Unknown Type"); } return 0; } -static int print_redis_stat(void *ctx, void *packet_info, size_t size) { - if (!redis_stat) { +static int print_redis_stat(void *ctx, void *packet_info, size_t size) +{ + if (!redis_stat) + { return 0; } - char message[20]={}; + char message[20] = {}; const struct redis_stat_query *pack_info = packet_info; - if(pack_info->key_count) + if (pack_info->key_count) { printf("%-20d %-20s %-20s %-20d %-20s %-20s\n", pack_info->pid, pack_info->comm, - pack_info->key,pack_info->key_count,"-","-"); + pack_info->key, pack_info->key_count, "-", "-"); } else { - process_redis_first(pack_info->value[0],message); + process_redis_first(pack_info->value[0], message); printf("%-20d %-20s %-20s %-20s %-20s %-20s\n", pack_info->pid, pack_info->comm, - "-","-",message,pack_info->value); + "-", "-", message, pack_info->value); } - + return 0; } static int libbpf_print_fn(enum libbpf_print_level level, const char *format, - va_list args) { + va_list args) +{ return vfprintf(stderr, format, args); } -static void show_stack_trace(__u64 *stack, int stack_sz, pid_t pid) { +static void show_stack_trace(__u64 *stack, int stack_sz, pid_t pid) +{ int i; printf("-----------------------------------\n"); - for (i = 1; i < stack_sz; i++) { - if (addr_to_func) { + for (i = 1; i < stack_sz; i++) + { + if (addr_to_func) + { struct SymbolEntry data = findfunc(stack[i]); char result[40]; sprintf(result, "%s+0x%llx", data.name, stack[i] - data.addr); printf("%-10d [<%016llx>]=%s\n", i, stack[i], result); - } else { + } + else + { printf("%-10d [<%016llx>]\n", i, stack[i]); } } printf("-----------------------------------\n"); } -static int print_trace(void *_ctx, void *data, size_t size) { +static int print_trace(void *_ctx, void *data, size_t size) +{ struct stacktrace_event *event = data; if (event->kstack_sz <= 0 && event->ustack_sz <= 0) @@ -1390,16 +1529,20 @@ static int print_trace(void *_ctx, void *data, size_t size) { printf("COMM: %s (pid=%d) @ CPU %d\n", event->comm, event->pid, event->cpu_id); - if (event->kstack_sz > 0) { + if (event->kstack_sz > 0) + { printf("Kernel:\n"); show_stack_trace(event->kstack, event->kstack_sz / sizeof(__u64), 0); - } else { + } + else + { printf("No Kernel Stack\n"); } printf("\n"); return 0; } -static int print_rtt(void *ctx, void *data, size_t size) { +static int print_rtt(void *ctx, void *data, size_t size) +{ if (!rtt_info) return 0; struct RTT *rtt_tuple = data; @@ -1412,7 +1555,8 @@ static int print_rtt(void *ctx, void *data, size_t size) { if ((rtt_tuple->saddr & 0x0000FFFF) == 0x0000007F || (rtt_tuple->daddr & 0x0000FFFF) == 0x0000007F || rtt_tuple->saddr == htonl(0xC0A83C01) || - rtt_tuple->daddr == htonl(0xC0A83C01)) { + rtt_tuple->daddr == htonl(0xC0A83C01)) + { return 0; // 如果匹配任一过滤条件,放弃处理这些数据包 } // 打印源地址和目的地址 @@ -1431,25 +1575,28 @@ static int print_rtt(void *ctx, void *data, size_t size) { // 计算和打印RTT分布图 printf(" usecs : count distribution\n"); int bucket_size = 1; - for (int i = 0; i < MAX_SLOTS; i++) { + for (int i = 0; i < MAX_SLOTS; i++) + { int start_range = bucket_size == 1 ? 0 : bucket_size; int end_range = bucket_size * 2 - 1; printf("%8d -> %-8d : %-8llu |", start_range, end_range, rtt_tuple->slots[i]); int bar_length = rtt_tuple->slots[i] / - 10; //计算该延迟范围内的计数对应的直方图条形长度,每个'*' - //表示 10 个计数 - for (int j = 0; j < bar_length; j++) { + 10; // 计算该延迟范围内的计数对应的直方图条形长度,每个'*' + // 表示 10 个计数 + for (int j = 0; j < bar_length; j++) + { printf("*"); } printf("\n"); - bucket_size *= 2; //以对数方式扩展 + bucket_size *= 2; // 以对数方式扩展 } printf("===============================================================\n"); return 0; } -int attach_uprobe_mysql(struct net_watcher_bpf *skel) { +int attach_uprobe_mysql(struct net_watcher_bpf *skel) +{ ATTACH_UPROBE_CHECKED( skel, _Z16dispatch_commandP3THDPK8COM_DATA19enum_server_command, @@ -1459,48 +1606,58 @@ int attach_uprobe_mysql(struct net_watcher_bpf *skel) { query__end); return 0; } -int attach_uprobe_redis(struct net_watcher_bpf *skel) { - if(redis_info){ +int attach_uprobe_redis(struct net_watcher_bpf *skel) +{ + if (redis_info) + { ATTACH_UPROBE_CHECKED(skel, call, redis_call); ATTACH_UPROBE_CHECKED(skel, processCommand, redis_processCommand); } - if(redis_stat){ + if (redis_stat) + { ATTACH_UPROBE_CHECKED(skel, lookupKey, redis_lookupKey); ATTACH_UPROBE_CHECKED(skel, addReply, redis_addReply); } return 0; } -void print_top_5_keys() { +void print_top_5_keys() +{ kv_pair *pairs; pairs = malloc(sizeof(kv_pair) * 1024); - if (!pairs) { + if (!pairs) + { perror("Failed to allocate memory"); exit(EXIT_FAILURE); } int index = 0; char *key = NULL; - while (bpf_map_get_next_key(map_fd, &key, &key) == 0) { + while (bpf_map_get_next_key(map_fd, &key, &key) == 0) + { // fprintf(stdout, "next_sk: (%p)\n", sk); int count; int err = bpf_map_lookup_elem(map_fd, &key, &count); - if (err) { + if (err) + { fprintf(stderr, "Failed to read value from the conns map: (%s)\n", strerror(errno)); - return ; + return; } memcpy(pairs[index].key, &key, 256); pairs[index].value = count; - //printf("Key: %s, Count: %u\n", pairs[index].key, pairs[index].value); + // printf("Key: %s, Count: %u\n", pairs[index].key, pairs[index].value); index++; - } + } // 获取所有键值对 // 排序前 5 个元素 // 简单选择排序(可替换为其他高效排序算法) - for (int i = 0; i < index - 1; i++) { - for (int j = i + 1; j < index; j++) { - if (pairs[j].value > pairs[i].value) { + for (int i = 0; i < index - 1; i++) + { + for (int j = i + 1; j < index; j++) + { + if (pairs[j].value > pairs[i].value) + { kv_pair temp = pairs[i]; pairs[i] = pairs[j]; pairs[j] = temp; @@ -1510,28 +1667,31 @@ void print_top_5_keys() { printf("----------------------------\n"); // 打印前 5 个元素 printf("Top 5 Keys:\n"); - for (int i = 0; i < 5 && i < index; i++) { + for (int i = 0; i < 5 && i < index; i++) + { printf("Key: %s, Count: %u\n", pairs[i].key, pairs[i].value); } free(pairs); } -int main(int argc, char **argv) { - char *last_slash = strrchr(argv[0], '/'); - if (last_slash) { - *(last_slash + 1) = '\0'; - } - strcpy(connects_file_path, argv[0]); - strcpy(err_file_path, argv[0]); - strcpy(packets_file_path, argv[0]); - strcpy(udp_file_path, argv[0]); - if (connects_file_path[strlen(connects_file_path) - 1] != '/') - strcat(connects_file_path, "/connects.log"); - else - strcat(connects_file_path, "connects.log"); +int main(int argc, char **argv) +{ + // char *last_slash = strrchr(argv[0], '/'); + // if (last_slash) + // { + // *(last_slash + 1) = '\0'; + // } + // strcpy(connects_file_path, argv[0]); + // strcpy(err_file_path, argv[0]); + // strcpy(packets_file_path, argv[0]); + // strcpy(udp_file_path, argv[0]); + // if (connects_file_path[strlen(connects_file_path) - 1] != '/') + // strcat(connects_file_path, "/connects.log"); + // else + // strcat(connects_file_path, "connects.log"); // strcat(connects_file_path, "./connects.log"); - strcat(err_file_path, "./err.log"); - strcat(packets_file_path, "./packets.log"); - strcat(udp_file_path, "./udp.log"); + // strcat(err_file_path, "./err.log"); + // strcat(packets_file_path, "./packets.log"); + // strcat(udp_file_path, "./udp.log"); struct ring_buffer *rb = NULL; struct ring_buffer *udp_rb = NULL; struct ring_buffer *netfilter_rb = NULL; @@ -1549,7 +1709,8 @@ int main(int argc, char **argv) { struct net_watcher_bpf *skel; int err; /* Parse command line arguments */ - if (argc > 1) { + if (argc > 1) + { err = argp_parse(&argp, argc, argv, 0, NULL, NULL); if (err) return err; @@ -1560,7 +1721,8 @@ int main(int argc, char **argv) { signal(SIGTERM, sig_handler); /* Open load and verify BPF application */ skel = net_watcher_bpf__open(); - if (!skel) { + if (!skel) + { fprintf(stderr, "Failed to open BPF skeleton\n"); return 1; } @@ -1571,120 +1733,141 @@ int main(int argc, char **argv) { if (addr_to_func) readallsym(); err = net_watcher_bpf__load(skel); - if (err) { + if (err) + { fprintf(stderr, "Failed to load and verify BPF skeleton\n"); goto cleanup; } /* Attach tracepoint handler */ - if (mysql_info) { + if (mysql_info) + { strcpy(binary_path, "/usr/sbin/mysqld"); err = attach_uprobe_mysql(skel); - if (err) { + if (err) + { fprintf(stderr, "failed to attach uprobes\n"); goto cleanup; } - } else if (redis_info||redis_stat) { + } + else if (redis_info || redis_stat) + { strcpy(binary_path, "/usr/bin/redis-server"); err = attach_uprobe_redis(skel); - if (err) { + if (err) + { fprintf(stderr, "failed to attach uprobes\n"); goto cleanup; } - } else { + } + else + { err = net_watcher_bpf__attach(skel); - if (err) { + if (err) + { fprintf(stderr, "Failed to attach BPF skeleton\n"); goto cleanup; } } enum MonitorMode mode = get_monitor_mode(); - // print_logo(); + print_logo(); print_header(mode); udp_rb = ring_buffer__new(bpf_map__fd(skel->maps.udp_rb), print_udp, NULL, NULL); - if (!udp_rb) { + if (!udp_rb) + { err = -1; fprintf(stderr, "Failed to create ring buffer(udp)\n"); goto cleanup; } netfilter_rb = ring_buffer__new(bpf_map__fd(skel->maps.netfilter_rb), print_netfilter, NULL, NULL); - if (!netfilter_rb) { + if (!netfilter_rb) + { err = -1; fprintf(stderr, "Failed to create ring buffer(netfilter)\n"); goto cleanup; } kfree_rb = ring_buffer__new(bpf_map__fd(skel->maps.kfree_rb), print_kfree, NULL, NULL); - if (!kfree_rb) { + if (!kfree_rb) + { err = -1; fprintf(stderr, "Failed to create ring buffer(kfree)\n"); goto cleanup; } icmp_rb = ring_buffer__new(bpf_map__fd(skel->maps.icmp_rb), print_icmptime, NULL, NULL); - if (!icmp_rb) { + if (!icmp_rb) + { err = -1; fprintf(stderr, "Failed to create ring buffer(icmp)\n"); goto cleanup; } tcp_rb = ring_buffer__new(bpf_map__fd(skel->maps.tcp_rb), print_tcpstate, NULL, NULL); - if (!tcp_rb) { + if (!tcp_rb) + { err = -1; fprintf(stderr, "Failed to create ring buffer(tcp)\n"); goto cleanup; } dns_rb = ring_buffer__new(bpf_map__fd(skel->maps.dns_rb), print_dns, NULL, NULL); - if (!dns_rb) { + if (!dns_rb) + { err = -1; fprintf(stderr, "Failed to create ring buffer(dns)\n"); goto cleanup; } trace_rb = ring_buffer__new(bpf_map__fd(skel->maps.trace_rb), print_trace, NULL, NULL); - if (!trace_rb) { + if (!trace_rb) + { err = -1; fprintf(stderr, "Failed to create ring buffer(trace)\n"); goto cleanup; } mysql_rb = ring_buffer__new(bpf_map__fd(skel->maps.mysql_rb), print_mysql, NULL, NULL); - if (!mysql_rb) { + if (!mysql_rb) + { err = -1; fprintf(stderr, "Failed to create ring buffer(trace)\n"); goto cleanup; } redis_rb = ring_buffer__new(bpf_map__fd(skel->maps.redis_rb), print_redis, NULL, NULL); - if (!redis_rb) { + if (!redis_rb) + { err = -1; fprintf(stderr, "Failed to create ring buffer(trace)\n"); goto cleanup; } redis_stat_rb = ring_buffer__new(bpf_map__fd(skel->maps.redis_stat_rb), print_redis_stat, - NULL, NULL); - if (!redis_stat_rb) { + NULL, NULL); + if (!redis_stat_rb) + { err = -1; fprintf(stderr, "Failed to create ring buffer(trace)\n"); goto cleanup; } rtt_rb = ring_buffer__new(bpf_map__fd(skel->maps.rtt_rb), print_rtt, NULL, NULL); - if (!rtt_rb) { + if (!rtt_rb) + { err = -1; fprintf(stderr, "Failed to create ring buffer(connect_rb)\n"); goto cleanup; } events = ring_buffer__new(bpf_map__fd(skel->maps.events), print_rst, NULL, NULL); - if (!events) { + if (!events) + { err = -1; fprintf(stderr, "Failed to create ring buffer(rst_rb)\n"); goto cleanup; @@ -1692,24 +1875,27 @@ int main(int argc, char **argv) { port_rb = ring_buffer__new(bpf_map__fd(skel->maps.port_rb), print_protocol_count, NULL, NULL); - if (!port_rb) { + if (!port_rb) + { err = -1; fprintf(stderr, "Failed to create ring buffer(trace)\n"); goto cleanup; } /* Set up ring buffer polling */ rb = ring_buffer__new(bpf_map__fd(skel->maps.rb), print_packet, NULL, NULL); - if (!rb) { + if (!rb) + { err = -1; fprintf(stderr, "Failed to create ring buffer(packet)\n"); goto cleanup; } - //open_log_files(); + // open_log_files(); struct timeval start, end; gettimeofday(&start, NULL); /* Process events */ - while (!exiting) { + while (!exiting) + { err = ring_buffer__poll(rb, 100 /* timeout, ms */); err = ring_buffer__poll(udp_rb, 100 /* timeout, ms */); err = ring_buffer__poll(netfilter_rb, 100 /* timeout, ms */); @@ -1727,37 +1913,59 @@ int main(int argc, char **argv) { print_conns(skel); sleep(1); /* Ctrl-C will cause -EINTR */ - if (err == -EINTR) { + if (err == -EINTR) + { err = 0; break; } - if (err < 0) { + if (err < 0) + { printf("Error polling perf buffer: %d\n", err); break; } gettimeofday(&end, NULL); - if ((end.tv_sec - start.tv_sec) >= 5) { - if (rst_info) { + if ((end.tv_sec - start.tv_sec) >= 5) + { + if (rst_info) + { print_stored_events(); - printf("Total RSTs in the last 5 seconds: %llu\n\n",rst_count); - rst_count = 0; - event_count = 0; - }else if (protocol_count) { - calculate_protocol_usage(proto_stats, 256, 5); - }else if(redis_stat) + printf("Total RSTs in the last 5 seconds: %llu\n\n", rst_count); + rst_count = 0; + event_count = 0; + } + else if (protocol_count) + { + calculate_protocol_usage(proto_stats, 256, 5); + } + else if (redis_stat) + { + map_fd = bpf_map__fd(skel->maps.key_count); + if (map_fd < 0) { - map_fd = bpf_map__fd(skel->maps.key_count); - if (map_fd < 0) { - perror("Failed to get map FD"); - return 1; - } - print_top_5_keys(); + perror("Failed to get map FD"); + return 1; } - gettimeofday(&start, NULL); + print_top_5_keys(); } + gettimeofday(&start, NULL); + } } cleanup: + ring_buffer__free(rb); + ring_buffer__free(udp_rb); + ring_buffer__free(netfilter_rb); + ring_buffer__free(kfree_rb); + ring_buffer__free(icmp_rb); + ring_buffer__free(tcp_rb); + ring_buffer__free(dns_rb); + ring_buffer__free(trace_rb); + ring_buffer__free(mysql_rb); + ring_buffer__free(redis_rb); + ring_buffer__free(rtt_rb); + ring_buffer__free(events); + ring_buffer__free(port_rb); + ring_buffer__free(redis_stat_rb); net_watcher_bpf__destroy(skel); return err < 0 ? -err : 0; } From ec51608f53af08a3f38fb891a1293db1efa733f8 Mon Sep 17 00:00:00 2001 From: wynyibo Date: Thu, 10 Oct 2024 20:34:04 +0800 Subject: [PATCH 09/13] fix bug --- MagicEyes/src/backend/net/net_watcher/bpf/mysql.bpf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MagicEyes/src/backend/net/net_watcher/bpf/mysql.bpf.h b/MagicEyes/src/backend/net/net_watcher/bpf/mysql.bpf.h index 93af7d4cb..9f250b96a 100644 --- a/MagicEyes/src/backend/net/net_watcher/bpf/mysql.bpf.h +++ b/MagicEyes/src/backend/net/net_watcher/bpf/mysql.bpf.h @@ -35,7 +35,7 @@ static __always_inline int __handle_mysql_start(struct pt_regs *ctx) { bpf_probe_read(&info.size, sizeof(info.size), &com_data->com_query.length); bpf_probe_read(&sql, sizeof(sql), &com_data->com_query.query); bpf_probe_read(&info.msql, sizeof(info.msql), sql); - bpf_printk("sql1==%s size1==%lu", info.msql,info.size); + // bpf_printk("sql1==%s size1==%lu", info.msql,info.size); info.start_time = bpf_ktime_get_ns() / 1000; bpf_map_update_elem(&queries, &tid, &info, BPF_ANY); From 33932f05023fd433f08aeac34e35509e3aa139ba Mon Sep 17 00:00:00 2001 From: wynyibo Date: Thu, 10 Oct 2024 20:46:00 +0800 Subject: [PATCH 10/13] fix bug --- .../backend/net/net_watcher/src/net_watcher.c | 37 +++---------------- 1 file changed, 5 insertions(+), 32 deletions(-) diff --git a/MagicEyes/src/backend/net/net_watcher/src/net_watcher.c b/MagicEyes/src/backend/net/net_watcher/src/net_watcher.c index bf139e05e..96645fdd7 100644 --- a/MagicEyes/src/backend/net/net_watcher/src/net_watcher.c +++ b/MagicEyes/src/backend/net/net_watcher/src/net_watcher.c @@ -1028,17 +1028,12 @@ static int print_udp(void *ctx, void *packet_info, size_t size) { if (!udp_info) return 0; - // FILE *file = fopen(udp_file_path, "a+"); // 追加 - // if (file == NULL) - // { - // fprintf(stderr, "Failed to open udp.log: (%s)\n", strerror(errno)); - // return 0; - // } char d_str[INET_ADDRSTRLEN]; char s_str[INET_ADDRSTRLEN]; const struct udp_message *pack_info = packet_info; unsigned int saddr = pack_info->saddr; unsigned int daddr = pack_info->daddr; + if (pack_info->tran_time > MAXTIME || (daddr & 0x0000FFFF) == 0x0000007F || (saddr & 0x0000FFFF) == 0x0000007F) return 0; @@ -1047,14 +1042,7 @@ static int print_udp(void *ctx, void *packet_info, size_t size) inet_ntop(AF_INET, &daddr, d_str, sizeof(d_str)), pack_info->sport, pack_info->dport, pack_info->tran_time, pack_info->rx, pack_info->len); - // fprintf(file, - // "packet{saddr=\"%s\",daddr=\"%s\",sport=\"%u\"," - // "dport=\"%u\",udp_time=\"%llu\",rx=\"%d\",len=\"%d\"} \n", - // inet_ntop(AF_INET, &saddr, s_str, sizeof(s_str)), - // inet_ntop(AF_INET, &daddr, d_str, sizeof(d_str)), pack_info->sport, - // pack_info->dport, pack_info->tran_time, pack_info->rx, - // pack_info->len); - // fclose(file); + if (time_load) { int flag = process_delay(pack_info->tran_time, 3); @@ -1376,7 +1364,7 @@ static void print_domain_name(const unsigned char *data, char *output) output[pos++] = *next++; } } - output[pos] = '\0'; // 确保字符串正确结束 + output[pos] = '\0'; } static int print_dns(void *ctx, void *packet_info, size_t size) { @@ -1673,25 +1661,10 @@ void print_top_5_keys() } free(pairs); } + int main(int argc, char **argv) { - // char *last_slash = strrchr(argv[0], '/'); - // if (last_slash) - // { - // *(last_slash + 1) = '\0'; - // } - // strcpy(connects_file_path, argv[0]); - // strcpy(err_file_path, argv[0]); - // strcpy(packets_file_path, argv[0]); - // strcpy(udp_file_path, argv[0]); - // if (connects_file_path[strlen(connects_file_path) - 1] != '/') - // strcat(connects_file_path, "/connects.log"); - // else - // strcat(connects_file_path, "connects.log"); - // strcat(connects_file_path, "./connects.log"); - // strcat(err_file_path, "./err.log"); - // strcat(packets_file_path, "./packets.log"); - // strcat(udp_file_path, "./udp.log"); + struct ring_buffer *rb = NULL; struct ring_buffer *udp_rb = NULL; struct ring_buffer *netfilter_rb = NULL; From ccfe543cc3cda6013595b490e7daf8708f8ec90b Mon Sep 17 00:00:00 2001 From: wynyibo Date: Thu, 10 Oct 2024 20:50:20 +0800 Subject: [PATCH 11/13] fix bug --- MagicEyes/src/backend/net/net_watcher/src/net_watcher.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MagicEyes/src/backend/net/net_watcher/src/net_watcher.c b/MagicEyes/src/backend/net/net_watcher/src/net_watcher.c index 96645fdd7..b8c5f0c6b 100644 --- a/MagicEyes/src/backend/net/net_watcher/src/net_watcher.c +++ b/MagicEyes/src/backend/net/net_watcher/src/net_watcher.c @@ -1653,7 +1653,7 @@ void print_top_5_keys() } } printf("----------------------------\n"); - // 打印前 5 个元素 + printf("Top 5 Keys:\n"); for (int i = 0; i < 5 && i < index; i++) { From 8375e5c8f9cffe6e9553696a32182d2b631a7a95 Mon Sep 17 00:00:00 2001 From: wynyibo Date: Fri, 11 Oct 2024 20:16:07 +0800 Subject: [PATCH 12/13] update --- MagicEyes/src/backend/net/net_watcher/src/net_watcher.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/MagicEyes/src/backend/net/net_watcher/src/net_watcher.c b/MagicEyes/src/backend/net/net_watcher/src/net_watcher.c index b8c5f0c6b..701c82a96 100644 --- a/MagicEyes/src/backend/net/net_watcher/src/net_watcher.c +++ b/MagicEyes/src/backend/net/net_watcher/src/net_watcher.c @@ -1688,7 +1688,9 @@ int main(int argc, char **argv) if (err) return err; } - libbpf_set_print(libbpf_print_fn); + + // libbpf_set_print(libbpf_print_fn); + /* Cleaner handling of Ctrl-C */ signal(SIGINT, sig_handler); signal(SIGTERM, sig_handler); From 294e38c16bbb378d7487644859df5348ffb6104f Mon Sep 17 00:00:00 2001 From: wynyibo Date: Sun, 13 Oct 2024 22:18:29 +0800 Subject: [PATCH 13/13] fix mysql --- .../src/backend/net/net_watcher/bpf/mysql.bpf.h | 6 +----- .../Network_Subsystem/net_watcher/mysql.bpf.h | 12 +++--------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/MagicEyes/src/backend/net/net_watcher/bpf/mysql.bpf.h b/MagicEyes/src/backend/net/net_watcher/bpf/mysql.bpf.h index 9f250b96a..e046338ce 100644 --- a/MagicEyes/src/backend/net/net_watcher/bpf/mysql.bpf.h +++ b/MagicEyes/src/backend/net/net_watcher/bpf/mysql.bpf.h @@ -28,14 +28,10 @@ static __always_inline int __handle_mysql_start(struct pt_regs *ctx) { u32 size = 0; char *sql; - if (command != COM_QUERY) { - return 0; - } - bpf_probe_read(&info.size, sizeof(info.size), &com_data->com_query.length); bpf_probe_read(&sql, sizeof(sql), &com_data->com_query.query); bpf_probe_read(&info.msql, sizeof(info.msql), sql); - // bpf_printk("sql1==%s size1==%lu", info.msql,info.size); + //bpf_printk("sql==%s size1==%lu", info.msql,info.size); info.start_time = bpf_ktime_get_ns() / 1000; bpf_map_update_elem(&queries, &tid, &info, BPF_ANY); diff --git a/eBPF_Supermarket/Network_Subsystem/net_watcher/mysql.bpf.h b/eBPF_Supermarket/Network_Subsystem/net_watcher/mysql.bpf.h index 13e802887..1ba2474db 100644 --- a/eBPF_Supermarket/Network_Subsystem/net_watcher/mysql.bpf.h +++ b/eBPF_Supermarket/Network_Subsystem/net_watcher/mysql.bpf.h @@ -28,14 +28,10 @@ static __always_inline int __handle_mysql_start(struct pt_regs *ctx) { u32 size = 0; char *sql; - if (command != COM_QUERY) { - return 0; - } - bpf_probe_read(&info.size, sizeof(info.size), &com_data->com_query.length); - bpf_probe_read_str(&sql, sizeof(sql), &com_data->com_query.query); - bpf_probe_read_str(&info.msql, sizeof(info.msql), sql); - // bpf_printk("sql1==%s size1==%lu", info.msql,info.size); + bpf_probe_read(&sql, sizeof(sql), &com_data->com_query.query); + bpf_probe_read(&info.msql, sizeof(info.msql), sql); + // bpf_printk("sql1==%s size1==%lu", sql,info.size); info.start_time = bpf_ktime_get_ns() / 1000; bpf_map_update_elem(&queries, &tid, &info, BPF_ANY); @@ -70,8 +66,6 @@ static __always_inline int __handle_mysql_end(struct pt_regs *ctx) { bpf_get_current_comm(&message->comm, sizeof(comm)); message->size = info->size; bpf_probe_read_str(&message->msql, sizeof(message->msql), info->msql); - // bpf_printk("C==%d D==%lu S==%lu SQL==%s",count, - // message->duratime,message->size,message->msql); bpf_ringbuf_submit(message, 0); return 0;