From 7a892ba8c584ab4535b2749611ef498f5289ce3e Mon Sep 17 00:00:00 2001 From: bitcoffee Date: Tue, 24 Dec 2024 22:54:46 +0800 Subject: [PATCH 1/4] add sockmap dump function --- oncn-mda/cli_src/CMakeLists.txt | 3 + oncn-mda/cli_src/func/dump.c | 214 ++++++++++++++++++++++++++++++ oncn-mda/cli_src/func/global.c | 2 +- oncn-mda/cli_src/mdadump.c | 7 + oncn-mda/ebpf_src/sock_redirect.c | 96 +++++++++++++- oncn-mda/include/data.h | 3 + oncn-mda/include/dump.h | 6 + oncn-mda/include/macli.h | 12 ++ oncn-mda/include/writecap.h | 80 +++++++++++ 9 files changed, 421 insertions(+), 2 deletions(-) create mode 100644 oncn-mda/cli_src/func/dump.c create mode 100644 oncn-mda/cli_src/mdadump.c create mode 100644 oncn-mda/include/dump.h create mode 100644 oncn-mda/include/writecap.h diff --git a/oncn-mda/cli_src/CMakeLists.txt b/oncn-mda/cli_src/CMakeLists.txt index 5bf849f..7c710b3 100644 --- a/oncn-mda/cli_src/CMakeLists.txt +++ b/oncn-mda/cli_src/CMakeLists.txt @@ -16,4 +16,7 @@ endif($ENV{HS_COVERAGE_ENABLE}) add_executable(mdacore mdacore.c ${SRC_LIST}) target_link_libraries(mdacore -lbpf -lelf -lz -lm) +add_executable(mdadump mdadump.c ${SRC_LIST}) +target_link_libraries(mdadump -lbpf -lelf -lz -lm) + MESSAGE("======================Leave cli folder=======================") diff --git a/oncn-mda/cli_src/func/dump.c b/oncn-mda/cli_src/func/dump.c new file mode 100644 index 0000000..72a4916 --- /dev/null +++ b/oncn-mda/cli_src/func/dump.c @@ -0,0 +1,214 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +/* Copyright Authors of Kmesh */ + +#include +#include "macli.h" +#include "writecap.h" +volatile sig_atomic_t g_keep_running = TRUE; + +static void init_filter_rule(struct sock_param *input) +{ + (void)memset(input, 0x0, sizeof(struct sock_param)); +} + +void dump_usage(void) +{ + printf("Usage: dump {OPTIONS}\n"); + printf(" OPTIONS: -i|--ip: filter ip,eg:1.1.1.1/24\n"); + printf(" OPTIONS: -p|--ports: filter ports,eg:15001~15006\n"); + printf(" OPTIONS: -w|--write: output file\n"); +} + +static const struct option g_dump_optionsp[] = { + {"ip", required_argument, NULL, 'i'}, + {"ports", required_argument, NULL, 'p'}, + {"writes", required_argument, NULL, 'w'}, + {NULL} +}; + +int get_input_dump_ip(const char* src, struct sock_param* filter_rules) +{ + if (filter_rules->dump_params.current_cidr_num >= MAX_PARAM_LENGTH) { + printf("over the max cidrs set num, max is %d\n", MAX_PARAM_LENGTH); + return FAILED; + } + char tmp_arg[MAX_CIDR_LENGTH] = {0}; + (void)strncpy(tmp_arg, src, MAX_IP_LENGTH); + (void)strncat(tmp_arg, "/32", sizeof(tmp_arg) - strlen(tmp_arg)); + __u32 ip; + __u32 mask; + if (check_cidr(tmp_arg, &ip, &mask) != SUCCESS) + return FAILED; + int current_param_num = filter_rules->dump_params.current_cidr_num++; + filter_rules->dump_params.dump_cidr[current_param_num].ip4 = ip; + filter_rules->dump_params.dump_cidr[current_param_num].mask = mask; + return SUCCESS; +} + +int get_input_dump_port(const char* src, struct sock_param *filter_rules) +{ + if (strlen(src) > MAX_PORT_RANGE_LENGTH - 1) { + printf("input ports is too long! your input: %s\n", src); + return FAILED; + } + if (filter_rules->dump_params.current_port_num >= MAX_PARAM_LENGTH) { + printf("over the max ports set num, max is %d\n", MAX_PARAM_LENGTH); + return FAILED; + } + __u32 begin_port; + __u32 end_port; + if (check_port(src, &begin_port, &end_port) != SUCCESS) { + return FAILED; + } + int current_param_num = filter_rules->dump_params.current_port_num++; + filter_rules->dump_params.dump_port[current_param_num].begin_port = begin_port; + filter_rules->dump_params.dump_port[current_param_num].end_port = end_port; + return SUCCESS; +} + +int dump_get_opt(int argc, char **argv, struct sock_param *input_dump_filter_rules, char *output_file) +{ + int opt; + optind = 1; + while ((opt = getopt_long(argc, argv, "i:p:w:", g_dump_optionsp, NULL)) >= 0) { + switch (opt) { + case 'i': + if (get_input_dump_ip(optarg, input_dump_filter_rules) != SUCCESS) + return FAILED; + break; + case 'p': + if (get_input_dump_port(optarg, input_dump_filter_rules) != SUCCESS) + return FAILED; + break; + case 'w': { + char dirBuff[PATH_MAX] = {0}; + (void)strncpy(dirBuff, optarg, PATH_MAX - 1); + char *baseName = basename(optarg); + char *tmpPath = dirname(dirBuff); + + if (realpath(tmpPath, output_file) == NULL) { + printf("input file path %s error! errno:%d\n", tmpPath, errno); + return FAILED; + } + (void)strncat(output_file, "/", PATH_MAX - strlen(output_file) - 1); + (void)strncat(output_file, baseName, PATH_MAX - strlen(output_file) - 1); + break; + } + case '?': + default: + dump_usage(); + return FAILED; + } + } + if (optind != argc) { + printf("unknown param!\n"); + dump_usage(); + return FAILED; + } + return SUCCESS; +} + + +void sig_handler(int sig) +{ + if (sig == SIGINT) { + g_keep_running = FALSE; + } +} + +int update_dump_param(struct mesh_map_info *param_map_info, struct sock_param *param_list) +{ + int key = 0; + if (bpf_map_update_elem(param_map_info->fd, &key, param_list, BPF_EXIST)) { + printf("update key ip failed! errno:%d\n", errno); + return FAILED; + } + return SUCCESS; +} + +int init_dump(struct sock_param *param_list, struct mesh_map_info *dump_map_info, struct mesh_map_info *param_map_info) +{ + init_filter_rule(param_list); + init_mesh_map(dump_map_info, pinmap_file_path[MESH_MAP_OPS_DUMP_I_MAP], + to_str(SOCK_DUMP_MAP_I_NAME), NULL); + init_mesh_map(param_map_info, pinmap_file_path[MESH_MAP_OPS_PARAM_MAP], + to_str(SOCK_PARAM_MAP_NAME), NULL); + + if (dump_map_info->fd < 0 || param_map_info->fd < 0) { + printf("can not found the pin file %s, %s, is the serviceMesh on?\n", + dump_map_info->pin_file_path, param_map_info->pin_file_path); + return FAILED; + } + + if (get_map_filter_rule(param_map_info, param_list) != SUCCESS) + return FAILED; + return SUCCESS; +} + +void get_next_dump_data(int output_file, struct mesh_map_info *dump_map_info) +{ + struct dump_data dump_datas = {0}; + if (bpf_map_lookup_and_delete_elem(dump_map_info->fd, NULL, &dump_datas) == 0) { + write_console(&dump_datas); + } else if (errno == ENOENT) + return; + else { + printf("get next dump message failed, errno:%d\n", errno); + g_keep_running = FALSE; + } +} + +void close_dump_fd(struct mesh_map_info *dump_map_info, struct mesh_map_info *param_map_info) +{ + if (dump_map_info->fd > 0) + close((*dump_map_info).fd); + if (param_map_info->fd > 0) + close((*param_map_info).fd); +} + +int do_dump(int argc, char **argv) +{ + int ret = FAILED; + g_keep_running = TRUE; + char output_file_name[PATH_MAX] = {0}; + int output_file = FALSE; + if (signal(SIGINT, sig_handler) == SIG_ERR) { + printf("create the signal failed!\n"); + return ERROR; + } + + struct sock_param param_list; + struct mesh_map_info dump_map_info; + struct mesh_map_info param_map_info; + if (init_dump(¶m_list, &dump_map_info, ¶m_map_info) != SUCCESS) + goto err; + + if (dump_get_opt(argc, argv, ¶m_list, output_file_name) != SUCCESS) + goto err; + + if (strcmp(output_file_name, "") != 0) { + printf("can not open the cap file\n"); + goto err; + } + + param_list.dump_params.switch_on = TRUE; + if (update_dump_param(¶m_map_info, ¶m_list) != SUCCESS) { + printf("start dump failed!\n"); + goto err; + } + + while(g_keep_running == TRUE) + get_next_dump_data(output_file, &dump_map_info); + + param_list.dump_params.switch_on = FALSE; + param_list.dump_params.current_cidr_num = 0; + param_list.dump_params.current_port_num = 0; + if (update_dump_param(¶m_map_info, ¶m_list)) { + printf("stop dump failed!\n"); + goto err; + } + ret = SUCCESS; +err: + close_dump_fd(&dump_map_info, ¶m_map_info); + return ret; +} \ No newline at end of file diff --git a/oncn-mda/cli_src/func/global.c b/oncn-mda/cli_src/func/global.c index fc0a2b7..949a00d 100644 --- a/oncn-mda/cli_src/func/global.c +++ b/oncn-mda/cli_src/func/global.c @@ -177,7 +177,7 @@ static int get_map_fd(const char *const map_name, int *const fd) return SUCCESS; } -static int init_mesh_map( +int init_mesh_map( struct mesh_map_info *const fds_map, const char *const pin_file_path, const char *const map_name, diff --git a/oncn-mda/cli_src/mdadump.c b/oncn-mda/cli_src/mdadump.c new file mode 100644 index 0000000..0b27bf6 --- /dev/null +++ b/oncn-mda/cli_src/mdadump.c @@ -0,0 +1,7 @@ +#include +#include "dump.h" + +int main(int argc, char *argv[]) +{ + return do_dump(argc, argv); +} diff --git a/oncn-mda/ebpf_src/sock_redirect.c b/oncn-mda/ebpf_src/sock_redirect.c index 456afeb..78af95e 100644 --- a/oncn-mda/ebpf_src/sock_redirect.c +++ b/oncn-mda/ebpf_src/sock_redirect.c @@ -3,6 +3,100 @@ #include "mesh_accelerate.h" +static int filter_dump_ip(const struct sk_msg_md *const msg, const struct sock_param *const param) +{ + if (param->dump_params.current_cidr_num == 0) + return FILTER_PASS; + + bpf_log(DEBUG, "filter param:sip:%u, dip:%u\n", msg->local_ip4, msg->remote_ip4); + __u32 local_ip4 = bpf_ntohl(msg->local_ip4); + __u32 remote_ip4 = bpf_ntohl(msg->remote_ip4); + + for (int i = 0; i < MAX_PARAM_LENGTH; ++i) { + if (i >= param->dump_params.current_cidr_num) + break; + if (param->dump_params.dump_cidr[i].ip4 == local_ip4 || + param->dump_params.dump_cidr[i].ip4 == remote_ip4) + return FILTER_PASS; + } + return FILTER_RETURN; +} + +static int adj_filter_dump_port(const struct port_range *const param, __u32 msg_sport, __u32 msg_dport) +{ + __u32 begin_port = param->begin_port; + __u32 end_port = param->end_port; + bpf_log(DEBUG, "filter param need:begin ports: %u, end ports:%u\n", begin_port, end_port); + if ((msg_sport >= begin_port && msg_sport <= end_port) || + (msg_dport >= begin_port && msg_dport <= end_port)) + return FILTER_PASS; + return FILTER_RETURN; +} + +static int filter_dump_port(const struct sk_msg_md *const msg, const struct sock_param *const param) +{ + if (param->dump_params.current_port_num == 0) + return FILTER_PASS; + + __u32 msg_sport = msg->local_port; + __u32 msg_dport = bpf_ntohl(msg->remote_port); + + for (int i = 0; i < MAX_PARAM_LENGTH; ++i) { + if (i >= param->dump_params.current_port_num) + break; + if (adj_filter_dump_port(&(param->dump_params.dump_port[i]), msg_sport, msg_dport) == FILTER_PASS) + return FILTER_PASS; + } + return FILTER_RETURN; +} + +static void get_dump_data(const struct sk_msg_md *const msg, struct dump_data *const data) +{ + __u64 current_timestamp = bpf_ktime_get_ns(); + data->timestamp = current_timestamp; + data->sip = msg->local_ip4; + data->sport = (bpf_htonl(msg->local_port) >> FORMAT_IP_LENGTH); + data->dip = msg->remote_ip4; + data->dport = (force_read(msg->remote_port) >> FORMAT_IP_LENGTH); + data->data_length = msg->size; + bpf_probe_read_kernel(data->data, 4096, (void *)(long)msg->data); +} + +static void dump_msg(const struct sk_msg_md *const msg) +{ + bpf_log(DEBUG, "begin dump\n"); + int index = 0; + struct sock_param *param = bpf_map_lookup_elem(&SOCK_PARAM_MAP_NAME, &index); + if (param == NULL) + return; + + if (param->dump_params.switch_on == FALSE) + return; + + bpf_log(DEBUG, "dump"); + + if (filter_dump_ip(msg, param) != FILTER_PASS) { + bpf_log(DEBUG, "ip:%u, ports:%u filtered by ip\n", msg->local_ip4, msg->local_port); + return; + } + + if (filter_dump_port(msg, param) != FILTER_PASS) { + bpf_log(DEBUG, "ip:%u, ports:%u filtered by port\n", msg->local_ip4, msg->local_port); + return; + } + + struct dump_data *data = NULL; + data = bpf_map_lookup_elem(&SOCK_DUMP_CPU_ARRAY_NAME, &index); + if (data == NULL) + return; + + get_dump_data(msg, data); + + if (bpf_map_push_elem(&SOCK_DUMP_MAP_I_NAME, data, BPF_EXIST)) + bpf_log(ERROR, "push the element failed!\n"); + bpf_log(DEBUG, "dump success\n"); +} + SEC("sk_msg") int SOCK_REDIRECT_NAME(struct sk_msg_md *const msg) { @@ -23,7 +117,7 @@ int SOCK_REDIRECT_NAME(struct sk_msg_md *const msg) ret = bpf_msg_redirect_hash(msg, &SOCK_OPS_MAP_NAME, redir_key, BPF_F_INGRESS); if (ret != SK_DROP) { bpf_log(DEBUG, "redirect the sk success\n"); - + dump_msg(msg); } else { // If you connect to the peer machine, you do end up in this branch bpf_log(INFO, "no such socket, may be peer socket on another machine\n"); diff --git a/oncn-mda/include/data.h b/oncn-mda/include/data.h index 951a3ab..7098ef5 100644 --- a/oncn-mda/include/data.h +++ b/oncn-mda/include/data.h @@ -15,6 +15,8 @@ #define SK_BPF_GID_UID 18000 #define BPF_SO_ORIGINAL_DST 800 +#define MAX_DUMP_DATA_LENGTH 4096 + #define SUCCESS 0 #define FAILED 1 @@ -139,6 +141,7 @@ struct dump_data { __u32 dip; __u32 dport; __u32 data_length; + __u8 data[MAX_DUMP_DATA_LENGTH]; }; #pragma pack() diff --git a/oncn-mda/include/dump.h b/oncn-mda/include/dump.h new file mode 100644 index 0000000..b76f474 --- /dev/null +++ b/oncn-mda/include/dump.h @@ -0,0 +1,6 @@ +#ifndef __DUMP_H__ +#define __DUMP_H__ + +int do_dump(int argc, char *argv[]); + +#endif \ No newline at end of file diff --git a/oncn-mda/include/macli.h b/oncn-mda/include/macli.h index 1db7e7a..cd0dcd7 100644 --- a/oncn-mda/include/macli.h +++ b/oncn-mda/include/macli.h @@ -101,6 +101,9 @@ struct mesh_service_info { struct mesh_prog_info prog_fds[MESH_PROG_NUM]; }; +extern const char pinmap_file_path[][PATH_MAX]; +extern const char pinprog_file_path[][PATH_MAX]; + // global.c int check_cidr(const char *const src, __u32 *const ip, __u32 *const mask); int check_port(const char *const src, __u32 *const begin_port, __u32 *const end_port); @@ -120,4 +123,13 @@ void close_fds(int cgroup_fd, const struct mesh_service_info *const fds); // chain.c int do_chain(int argc, char *const *argv, struct sock_param *const filter_rules); +int init_mesh_map( + struct mesh_map_info *const fds_map, + const char *const pin_file_path, + const char *const map_name, +#if LIBBPF_HIGHER_0_6_0_VERSION + struct create_map_attr *const map_attr); +#else + struct bpf_create_map_attr *const map_attr); +#endif #endif diff --git a/oncn-mda/include/writecap.h b/oncn-mda/include/writecap.h new file mode 100644 index 0000000..2aabc82 --- /dev/null +++ b/oncn-mda/include/writecap.h @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* Copyright Authors of Kmesh */ + +#include "data.h" +#include +#include +#include + +#include +#include +#include +#include +#include + +#define MAC_LENGTH 6 +#define MAX_IP_PORT_LENGTH 32 +#define MAX_IP_LENGTH 16 +const int NANO_2_SECOND_RATE = 1000000000; + +int get_sys_time(__u64 ktime, time_t *dataTime) +{ + struct sysinfo info; + time_t boot_time; + if (sysinfo(&info)) { + return FAILED; + } + time_t cur_time = time(NULL); + if (cur_time > info.uptime) + boot_time = cur_time - info.uptime; + else + boot_time = info.uptime - cur_time; + *dataTime = boot_time + ktime / NANO_2_SECOND_RATE; + return SUCCESS; +} + +int format_ip(__u32 ip4, char *ip, int ipSize) +{ + struct in_addr src; + src.s_addr = ip4; + if (inet_ntop(AF_INET, &src, ip, ipSize) == NULL) { + printf("can not convert the ip:%d\n", ip4); + return FAILED; + } + return SUCCESS; +} + +int format_ip_port(__u32 ip4, __u32 port, char *ip, int ipSize) +{ + char tmp_ip[MAX_IP_LENGTH] = {0}; + + if (format_ip(ip4, tmp_ip, MAX_IP_LENGTH) != SUCCESS) + return FAILED; + (void)snprintf(ip, ipSize - 1, "%s:%u", tmp_ip, port); + return SUCCESS; +} + +void write_console(const struct dump_data *data) +{ + time_t print_time; + + char srcIP[MAX_IP_PORT_LENGTH] = {0}; + char dstIP[MAX_IP_PORT_LENGTH] = {0}; + format_ip_port(data->sip, ntohl(data->sport << 16), srcIP, sizeof(srcIP)); + format_ip_port(data->dip, ntohl(data->dport << 16), dstIP, sizeof(dstIP)); + if (get_sys_time(data->timestamp, &print_time) == FAILED) + printf("[%llu],ip:%s > %s\n", data->timestamp, srcIP, dstIP); + else { + struct tm print_tm; + localtime_r(&print_time, &print_tm); + printf("[%d-%d-%d %d:%d:%d],ip:%s > %s, data length:%d\n", + print_tm.tm_year + 1900, print_tm.tm_mon + 1, print_tm.tm_mday, + print_tm.tm_hour, print_tm.tm_min, print_tm.tm_sec, + srcIP, dstIP, data->data_length); + int print_length = data->data_length <= MAX_DUMP_DATA_LENGTH ? data->data_length : MAX_DUMP_DATA_LENGTH; + for (int i = 0; i < print_length; i++) { + printf("%c", data->data[i]); + } + printf("\n"); + } +} -- 2.33.0