diff --git a/agent/plugin/common.bpf.h b/agent/plugin/common.bpf.h index 7e31cb2a4a092229aa64b60804d748eff030baf4..d516c776465524a205507d362dbdcd5776ee1f15 100644 --- a/agent/plugin/common.bpf.h +++ b/agent/plugin/common.bpf.h @@ -42,6 +42,11 @@ struct __uint(max_entries, 1024); } perf_map SEC(".maps"); +struct +{ + __uint(type, BPF_MAP_TYPE_RINGBUF); + __uint(max_entries, 256 * 1024); +} flags_rb SEC(".maps"); /*map helper*/ struct @@ -93,6 +98,33 @@ struct __type(value, struct tid_map_value); } inner_tid_map SEC(".maps"); +// 用于存储 SYN 包计数 +struct +{ + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 65536); + __type(key, struct addr_pair); + __type(value, u64); +} syn_count_map SEC(".maps"); + +// 用于存储 SYN-ACK 包计数 +struct +{ + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 65536); + __type(key, struct addr_pair); + __type(value, u64); +} synack_count_map SEC(".maps"); + +// 用于存储 FIN 包计数 +struct +{ + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 65536); + __type(key, struct addr_pair); + __type(value, u64); +} fin_count_map SEC(".maps"); + /*funcation hepler*/ static __always_inline int get_current_tgid() { @@ -127,14 +159,26 @@ static __always_inline void get_udp_pkt_tuple(struct event *pkt_tuple, pkt_tuple->tran_flag = UDP; } -static void get_tcp_pkt_tuple(struct event *pkt_tuple, struct iphdr *ip, struct tcphdr *tcp) +static void get_tcp_pkt_tuple(void *pkt_tuple, struct iphdr *ip, struct tcphdr *tcp, int type) { - pkt_tuple->client_ip = _R(ip, saddr); - pkt_tuple->server_ip = _R(ip, daddr); - pkt_tuple->client_port = __bpf_ntohs(_R(tcp, source)); - pkt_tuple->server_port = __bpf_ntohs(_R(tcp, dest)); - pkt_tuple->seq = __bpf_ntohl(_R(tcp, seq)); - pkt_tuple->ack = __bpf_ntohl(_R(tcp, ack_seq)); + if (type == 1) + { // struct tuple_key + struct tuple_key *key = (struct tuple_key *)pkt_tuple; + key->saddr = _R(ip, saddr); + key->daddr = _R(ip, daddr); + key->sport = __bpf_ntohs(_R(tcp, source)); + key->dport = __bpf_ntohs(_R(tcp, dest)); + } + else if (type == 2) + { // struct event + struct event *event = (struct event *)pkt_tuple; + event->client_ip = _R(ip, saddr); + event->server_ip = _R(ip, daddr); + event->client_port = __bpf_ntohs(_R(tcp, source)); + event->server_port = __bpf_ntohs(_R(tcp, dest)); + event->seq = __bpf_ntohl(_R(tcp, seq)); + event->ack = __bpf_ntohl(_R(tcp, ack_seq)); + } } static __always_inline void *bmloti(void *map, const void *key, const void *init) @@ -330,4 +374,11 @@ static __always_inline int fill_sk_skb(struct drop_event *event, struct sock *sk } return 0; } +static __always_inline void fill_tcp_packet_type(struct tuple_key *devent, struct sock *sk) +{ + devent->saddr = _R(sk, __sk_common.skc_rcv_saddr); + devent->daddr = _R(sk, __sk_common.skc_daddr); + devent->sport = _R(sk, __sk_common.skc_num); + devent->dport = __bpf_ntohs(_R(sk, __sk_common.skc_dport)); +} #endif // __COMMON_BPF_H \ No newline at end of file diff --git a/agent/plugin/probe.bpf.c b/agent/plugin/probe.bpf.c index f5d6b720cefce889bf01de8f933b03aad5be4f2c..04e31c93b38d338e7baf12cbbbb0c6d3d7358819 100644 --- a/agent/plugin/probe.bpf.c +++ b/agent/plugin/probe.bpf.c @@ -15,7 +15,7 @@ int BPF_KPROBE(__udp_enqueue_schedule_skb, struct sock *sk, return udp_enqueue_schedule_skb(sk, skb); } -//send +// send SEC("kprobe/udp_send_skb") int BPF_KPROBE(udp_send_skb, struct sk_buff *skb) { @@ -28,9 +28,10 @@ int BPF_KPROBE(ip_send_skb, struct net *net, struct sk_buff *skb) return __ip_send_skb(skb); } -//tcp status +// tcp status SEC("tracepoint/sock/inet_sock_set_state") -int handle_tcp_state(struct trace_event_raw_inet_sock_set_state *ctx) { +int handle_tcp_state(struct trace_event_raw_inet_sock_set_state *ctx) +{ return __handle_tcp_state(ctx); } @@ -78,4 +79,37 @@ int handle_kfree_skb(struct trace_event_raw_kfree_skb *ctx) { return __kfree_skb(ctx); } +// SYN-ACK total +// SEC("kprobe/tcp_rcv_state_process ") +// int BPF_KPROBE(tcp_rcv_state_process ,struct sock *sk,struct sk_buff *skb) +// { +// return __tcp_rcv_state_process(sk,skb); +// } + +SEC("kprobe/tcp_connect") +int BPF_KPROBE(tcp_connect, struct sock *sk) +{ + bpf_printk("tcp_connect"); + return __tcp_connect(sk); +} + +SEC("kprobe/tcp_rcv_state_process") +int BPF_KPROBE(tcp_rcv_state_process, struct sock *sk, struct sk_buff *skb) +{ + bpf_printk("tcp_rcv_state_process"); + return __tcp_rcv_state_process(sk, skb); +} + +SEC("kprobe/tcp_send_fin") +int BPF_KPROBE(tcp_send_fin, struct sock *sk) +{ + bpf_printk("tcp_send_fin"); + return __tcp_send_fin(sk); +} + +// SEC("kprobe/tcp_send_reset") +// int handle_send_reset(struct pt_regs *ctx) +// { +// return __tcp_send_reset(ctx); +// } diff --git a/agent/plugin/probe.c b/agent/plugin/probe.c index 7f9ba53072f2701fe48799be701ee33641491f5d..f00e5b640e2c5281893ce1357f557c1fe2d61d70 100755 --- a/agent/plugin/probe.c +++ b/agent/plugin/probe.c @@ -14,13 +14,16 @@ #include "probe.h" #include "probe.skel.h" #include "probe.h" -int stack_map_fd; // 在全局范围内声明 + static volatile bool exiting = false; -static int udp_info = 0, tcp_status_info = 0, tcp_output_info = 0, protocol_info = 0, port_distribution = 0, drop_info = 0, drop_skb = 0; -struct protocol_stats proto_stats[256] = {0}; -static int interval = 5, entry_count = 0; // 每5 秒计算一次 +static int udp_info = 0, tcp_status_info = 0, tcp_output_info = 0, protocol_info = 0, port_distribution = 0, drop_info = 0, drop_skb = 0, num_symbols = 0, cache_size = 0; +static int packet_count = 0; +struct protocol_stats proto_stats[MAX] = {0}; +static int interval = 20, entry_count = 0; struct packet_info entries[MAX_ENTRIES]; -time_t start_time = 0; +struct SymbolEntry symbols[MAXSYMBOLS]; +struct SymbolEntry cache[CACHEMAXSIZE]; +static struct packet_stats hash_map[HASH_MAP_SIZE] = {0}; const char argp_program_doc[] = "Trace time delay in network subsystem \n"; @@ -32,6 +35,7 @@ static const struct argp_option opts[] = { {"port_distribution_info", 'P', 0, 0, "statistical use of top10 destination ports"}, {"drop_info", 'i', 0, 0, "trace the iptables drop"}, {"drop_skb", 'd', 0, 0, "trace the all skb drop"}, + {"packet_count", 'c', 0, 0, "trace the packet include SYN、SYN-ACK、FIN"}, {}, }; @@ -60,6 +64,9 @@ static error_t parse_arg(int key, char *arg, struct argp_state *state) case 'd': drop_skb = 1; break; + case 'c': + packet_count = 1; + break; default: return ARGP_ERR_UNKNOWN; } @@ -177,7 +184,7 @@ static int print_tcp_flow_info(void *ctx, void *packet_info, size_t data_sz) } // function for calculating and printing the proportion of protocols -void calculate_protocol_usage(struct protocol_stats proto_stats[], int num_protocols, int interval) +static void calculate_protocol_usage(struct protocol_stats 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; @@ -243,17 +250,12 @@ void calculate_protocol_usage(struct protocol_stats proto_stats[], int num_proto memset(proto_stats, 0, num_protocols * sizeof(struct protocol_stats)); } -int compare_by_pps(const void *a, const void *b) +static int compare_by_pps(const void *a, const void *b) { return ((struct packet_info *)b)->packet_count - ((struct packet_info *)a)->packet_count; } -void init_start_time() -{ - start_time = time(NULL); -} - -int find_port_entry(int dst_port, int proto) +static int find_port_entry(int dst_port, int proto) { for (int i = 0; i < entry_count; i++) { @@ -294,16 +296,113 @@ static int print_drop(void *ctx, void *packet_info, size_t data_sz) proto_str, type_str); return 0; } +/* Address search kallsyms converts to function name + offset*/ +// 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; +} + +static 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); +} + +static 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]; +}; + static int print_drop_skb(void *ctx, void *packet_info, size_t data_sz) { if (!drop_skb) { return 0; } - const struct event *event = (const struct event *)packet_info; + const struct reasonissue *event = (struct reasonissue *)packet_info; char s_str[INET_ADDRSTRLEN]; char d_str[INET_ADDRSTRLEN]; - char protol[6]; + char protol[6], result[40]; + struct SymbolEntry data = findfunc(event->location); + sprintf(result, "%s+0x%lx", data.name, event->location - data.addr); if (event->client_ip == 0 && event->server_ip == 0) { return 0; @@ -322,8 +421,7 @@ static int print_drop_skb(void *ctx, void *packet_info, size_t data_sz) { strcpy(protol, "other"); } - printf("%-20d %-20s %-20s %-20d %-20d %-20s %-34lx \n", - event->pid, s_str, d_str, event->client_port, event->server_port, protol, event->location); + printf("%-20d %-20s %-20s %-20d %-20d %-20s %-34lx %-34s \n", event->pid, s_str, d_str, event->client_port, event->server_port, protol, event->location, result); return 0; } static int print_count_protocol_use(void *ctx, void *packet_info, size_t data_sz) @@ -375,6 +473,62 @@ static int print_top_5_keys() entry_count = 0; return 0; } + +static int tuple_key_hash(const struct tuple_key *key, u8 packet_type) { + return (key->saddr ^ key->daddr ^ key->sport ^ key->dport ^ packet_type) % HASH_MAP_SIZE; +} + + +static void output_statistics() { + for (int i = 0; i < HASH_MAP_SIZE; i++) { + struct packet_stats *stats = &hash_map[i]; + if (stats->syn_count != 0 || stats->synack_count != 0 || stats->fin_count != 0) { + char s_str[INET_ADDRSTRLEN]; + char d_str[INET_ADDRSTRLEN]; + format_ip_address(stats->key.saddr, s_str, sizeof(s_str)); + format_ip_address(stats->key.daddr, d_str, sizeof(d_str)); + printf("Tuple (Source: %s:%d, Destination: %s:%d): SYN Count: %lld, SYN-ACK Count: %lld, FIN Count: %lld\n", + s_str, stats->key.sport, d_str, stats->key.dport, + stats->syn_count, stats->synack_count, stats->fin_count); + stats->syn_count = 0; + stats->synack_count = 0; + stats->fin_count = 0; + } + } +} +static int print_packet_count(void *ctx, void *packet_info, size_t data_sz) { + if (!packet_info) + { + return 0; + } + const struct tcp_event *event = (struct tcp_event *)packet_info; + + // 创建 4-tuple 作为 key + struct tuple_key key = { + .saddr = event->saddr, + .daddr = event->daddr, + .sport = event->sport, + .dport = event->dport + }; + + // 包含 packet_type 以生成唯一的哈希索引 + int hash_index = tuple_key_hash(&key, event->sum.key.packet_type ); + struct packet_stats *stats = &hash_map[hash_index]; + + // 存储 4-tuple 信息 + stats->key = key; + + // 根据包类型更新对应计数 + if ( event->sum.key.packet_type == 1) { // SYN + stats->syn_count = event->sum.syn_count; + } else if ( event->sum.key.packet_type == 2) { // SYN-ACK + stats->synack_count = event->sum.synack_count; + } else if ( event->sum.key.packet_type == 3) { // FIN + stats->fin_count = event->sum.fin_count; + } + return 0; +} + int main(int argc, char **argv) { @@ -386,6 +540,8 @@ int main(int argc, char **argv) struct ring_buffer *port_events_rb = NULL; struct ring_buffer *perf_map = NULL; struct ring_buffer *trace_all_drop = NULL; + struct ring_buffer *flags_rb = NULL; + /* Parse command line arguments */ err = argp_parse(&argp, argc, argv, 0, NULL, NULL); if (err) @@ -393,7 +549,7 @@ int main(int argc, char **argv) libbpf_set_strict_mode(LIBBPF_STRICT_ALL); /* Set up libbpf errors and debug info callback */ - libbpf_set_print(libbpf_print_fn); + // libbpf_set_print(libbpf_print_fn); /* Cleaner handling of Ctrl-C */ signal(SIGINT, sig_handler); @@ -406,7 +562,10 @@ int main(int argc, char **argv) fprintf(stderr, "Failed to open and load BPF skeleton\n"); return 1; } - + if (drop_skb) + { + readallsym(); + } /* Load & verify BPF programs */ err = probe_bpf__load(skel); if (err) @@ -465,6 +624,13 @@ int main(int argc, char **argv) fprintf(stderr, "Failed to create ring buffer\n"); goto cleanup; } + flags_rb = ring_buffer__new(bpf_map__fd(skel->maps.flags_rb), print_packet_count, NULL, NULL); + if (!flags_rb) + { + err = -1; + fprintf(stderr, "Failed to create ring buffer\n"); + goto cleanup; + } /* Process events */ if (udp_info) @@ -495,7 +661,6 @@ int main(int argc, char **argv) { printf("==========port_distribution==========\n"); } - start_time = time(NULL); struct timeval start, end; gettimeofday(&start, NULL); while (!exiting) @@ -506,17 +671,9 @@ int main(int argc, char **argv) err = ring_buffer__poll(port_events_rb, 100 /* timeout, ms */); err = ring_buffer__poll(perf_map, 100 /* timeout, ms */); err = ring_buffer__poll(trace_all_drop, 100 /* timeout, ms */); + err = ring_buffer__poll(flags_rb, 100 /* timeout, ms */); /* Ctrl-C will cause -EINTR */ // Regularly calculate and print the proportion of agreements - if (protocol_info) - { - if (time(NULL) - start_time >= interval) - { - calculate_protocol_usage(proto_stats, 256, interval); - start_time = time(NULL); // reset time - } - } - if (err == -EINTR) { err = 0; @@ -527,11 +684,16 @@ 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 ((end.tv_sec - start.tv_sec) >= interval) { if (port_distribution) print_top_5_keys(); + else if (protocol_info) + calculate_protocol_usage(proto_stats, 256, interval); + else if (packet_count) + output_statistics(); gettimeofday(&start, NULL); } } @@ -544,6 +706,7 @@ cleanup: ring_buffer__free(port_events_rb); ring_buffer__free(perf_map); ring_buffer__free(trace_all_drop); + ring_buffer__free(flags_rb); probe_bpf__destroy(skel); return err < 0 ? -err : 0; diff --git a/agent/plugin/probe.h b/agent/plugin/probe.h index 15d02d7f322d85f96d3048c75fa3033ad191da0b..48c75566482c1b054287697dce3c5482ff4bb203 100644 --- a/agent/plugin/probe.h +++ b/agent/plugin/probe.h @@ -6,6 +6,9 @@ typedef unsigned short u16; typedef unsigned int u32; typedef unsigned long long u64; +#define ETH_HLEN 14 // 以太网头部的长度 +#define MAXSYMBOLS 300000 +#define CACHEMAXSIZE 5 #define SK(sk) ((const struct sock *)(sk)) #define NS_TIME() (bpf_ktime_get_ns() / 1000) #define _R(dst, src) BPF_CORE_READ(dst, src) @@ -31,6 +34,8 @@ typedef unsigned long long u64; #define TCP_TX_DATA(data, delta) __sync_fetch_and_add(&((data).tx), (__u64)(delta)) #define TCP_RX_DATA(data, delta) __sync_fetch_and_add(&((data).rx), (__u64)(delta)) #define TCP_PROBE_TXRX (u32)(1 << 3) +#define RCV_SHUTDOWN 2 +#define HASH_MAP_SIZE 1024 /* bpf.h struct helper */ struct ktime_info @@ -62,9 +67,18 @@ struct event int oldstate; int newstate; u8 type; - long location; }; +struct reasonissue +{ + u32 client_ip; + u32 server_ip; + u16 client_port; + u16 server_port; + long location; + u16 protocol; + int pid; +}; struct tcp_tx_rx { u64 rx; // FROM tcp_cleanup_rbuf @@ -125,13 +139,13 @@ struct protocol_stats uint64_t tx_count; }; -struct addr_pair -{ - u32 saddr; - u32 daddr; - u16 sport; - u16 dport; +struct addr_pair { + u32 saddr; + u32 daddr; + u16 sport; + u16 dport; }; + static const char *tcp_states[] = { [1] = "ESTABLISHED", [2] = "SYN_SENT", @@ -147,6 +161,7 @@ static const char *tcp_states[] = { [12] = "NEW_SYN_RECV", [13] = "UNKNOWN", }; + static const char *protocol[] = { [0] = "TCP", [1] = "UDP", @@ -202,4 +217,36 @@ static const char *protocol_names[] = { [IPPROTO_UDP] = "UDP", // 17 }; +struct SymbolEntry +{ + unsigned long addr; + char name[30]; +}; +// 4-tuple 结构体定义 +struct tuple_key { + uint32_t saddr; + uint32_t daddr; + uint16_t sport; + uint16_t dport; + u8 packet_type; +}; + +struct packet_stats { + u64 syn_count; + u64 synack_count; + u64 fin_count; + struct tuple_key key; +}; + +struct tcp_event { + u32 saddr; + u32 daddr; + u16 sport; + u16 dport; + struct packet_stats sum; +}; + + + + #endif diff --git a/agent/plugin/traffic.bpf.h b/agent/plugin/traffic.bpf.h index 01e8652d3e12aaf08f3154ab580cfa3045b68073..d750f432d4494f08cf91187fe7498ff88493a942 100644 --- a/agent/plugin/traffic.bpf.h +++ b/agent/plugin/traffic.bpf.h @@ -390,25 +390,109 @@ static __always_inline int __kfree_skb(struct trace_event_raw_kfree_skb *ctx) struct iphdr *ip = extract_iphdr(skb); struct tcphdr *tcp = extract_tcphdr(skb); struct event devent = {0}; - get_tcp_pkt_tuple(&devent, ip, tcp); - struct event *event; + get_tcp_pkt_tuple(&devent, ip, tcp,2); + struct reasonissue *event; event = bpf_ringbuf_reserve(&trace_all_drop, sizeof(*event), 0); if (!event) { return 0; } - event->location = (long)ctx->location; - // event->type == DROP_KFREE_SKB; event->client_ip = devent.client_ip; event->server_ip = devent.server_ip; event->client_port = devent.client_port; event->server_port = devent.server_port; event->pid = get_current_tgid(); + event->location = (long)ctx->location; event->protocol = ctx->protocol; - // bpf_printk("saddr:%u daddr:%u", event->client_ip, event->server_ip); // 丢包调用栈 // event->kstack_sz = // bpf_get_stack(ctx, event->kstack, sizeof(event->kstack), 0); bpf_ringbuf_submit(event, 0); return 0; } + +static __always_inline void update_packet_count(void *map, struct tuple_key *devent, u8 packet_type) +{ + u64 *count = bpf_map_lookup_elem(map, devent); + u64 new_count = 1; + + if (!count) + { + bpf_map_update_elem(map, devent, &new_count, BPF_ANY); + count = &new_count; + } + else + { + __atomic_add_fetch(count, 1, __ATOMIC_RELAXED); + } + + struct tcp_event *event = bpf_ringbuf_reserve(&flags_rb, sizeof(*event), 0); + if (!event) + { + return; + } + __builtin_memset(event, 0, sizeof(*event)); + event->saddr = devent->saddr; + event->daddr = devent->daddr; + event->sport = devent->sport; + event->dport = devent->dport; + event->sum.key.packet_type = packet_type; + switch (event->sum.key.packet_type) + { + case 1: // syn + event->sum.syn_count = *count; + break; + case 2: // syn-ack + event->sum.synack_count = *count; + break; + case 3: // fin + event->sum.fin_count = *count; + break; + default: + break; + } + bpf_ringbuf_submit(event, 0); +} + +static __always_inline int __tcp_connect(struct sock *sk) +{ + if (!sk ) + return 0; + struct tuple_key devent = {0}; + fill_tcp_packet_type(&devent, sk); // SYN packet type + // update SYN + update_packet_count(&syn_count_map, &devent, 1); + return 0; +} + +static __always_inline int __tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) +{ + if (!sk || !skb) + return 0; + struct iphdr *ip = extract_iphdr(skb); + struct tcphdr *tcp = extract_tcphdr(skb); + struct tuple_key devent = {0}; + get_tcp_pkt_tuple(&devent, ip, tcp,1); + + // update SYN-ACK + update_packet_count(&synack_count_map, &devent, 2); + return 0; +} + +static __always_inline int __tcp_send_fin(struct sock *sk) +{ + if (!sk) + return 0; + struct tuple_key devent = {0}; + fill_tcp_packet_type(&devent, sk); // FIN packet type + // update FIN + update_packet_count(&fin_count_map, &devent, 3); + return 0; +} + +// 捕获 RST 包 +// static __always_inline int __tcp_send_reset(struct pt_regs *ctx) { +// // 增加 RST 包计数 +// increment_packet_count(RST); +// return 0; +// } \ No newline at end of file