From 3b5ce18ae27ee1ea248a72defa91b1bf03ed55bc Mon Sep 17 00:00:00 2001 From: Junzy <523909343@qq.com> Date: Wed, 11 Sep 2024 21:03:54 +0800 Subject: [PATCH] change processing logic: scan string for each field. --- bin/conf/nat_format.conf | 4 + src/nat_format.cpp | 158 +++++++++++++++++++++++++++++++++------ src/nat_format.h | 16 ++-- 3 files changed, 147 insertions(+), 31 deletions(-) diff --git a/bin/conf/nat_format.conf b/bin/conf/nat_format.conf index d86921e..4c71369 100644 --- a/bin/conf/nat_format.conf +++ b/bin/conf/nat_format.conf @@ -1,3 +1,7 @@ +[NAT_FORMAT] +magic_num=0x004e4154 +version=0x0200 + [NAT_FORMAT_SEND] batch_size=20 host_ip=127.0.0.1 diff --git a/src/nat_format.cpp b/src/nat_format.cpp index 28d00ee..ecec192 100644 --- a/src/nat_format.cpp +++ b/src/nat_format.cpp @@ -21,17 +21,82 @@ #define HW_EVENT_ADD "SESSION_BUILT" #define HW_EVENT_DEL "SESSION_TEARDOWN" +#define FORMAT_LOG_PROTOCOL_ICMP 0x01 +#define FORMAT_LOG_PROTOCOL_TCP 0x06 +#define FORMAT_LOG_PROTOCOL_UDP 0x17 + struct nat_format_global_info g_nat_format_info; char *multicast_payload; int cur_pkt = 0; int udp_socket; -struct sockaddr_in dst_addr; +struct sockaddr_in dst_addr = {0}; + +// 函数:子串匹配,返回子串结尾+1的位置,即值的起始位置 +int get_value_offset(char *str, int str_len, const char *key) { + int i, j; + int key_len = strlen(key); + + for (i = 0; i <= str_len - key_len - 1; i++) { + for (j = 0; j < key_len; j++) { + if (str[i + j]!= key[j]) + break; + } + if (j == key_len) + return (i + key_len + 1); + } + return -1; +} + +// 函数:从字符串中提取点分十进制ip并转换为二进制数 +int extract_ip(char *data, int data_len, const char *key, unsigned int *dst) { + int offset; + char tmp_ip[20]; + if ((offset = get_value_offset(data, data_len, key)) == -1) { return -1; } + if (sscanf(data+offset, "%19[^,]", tmp_ip) != 1) { return -1; } + if (inet_pton(AF_INET, tmp_ip, dst) <= 0) {return -1; } + return 0; +} +// 函数:从字符串中提取字符串并转为16位数 +int extract_port(char *data, int data_len, const char *key, unsigned short *dst) { + int offset; + if ((offset = get_value_offset(data, data_len, key)) == -1) { return -1; } + if (sscanf(data+offset, "%hu", dst) != 1) { return -1; } + *dst = htons(*dst); + return 0; +} +// 函数:从字符串中提取字符串并转为32位数 +int extract_time(char *data, int data_len, const char *key, unsigned int *dst) { + int offset; + if ((offset = get_value_offset(data, data_len, key)) == -1) { return -1; } + if (sscanf(data+offset, "%u", dst) != 1) { return -1; } + return 0; +} +// 函数:从字符串中提取字符串并转为标识 +int extract_protocol(char *data, int data_len, const char *key, char *dst) { + int offset; + char protocol_str[20]; + if ((offset = get_value_offset(data, data_len, key)) == -1) { return -1; } + if (sscanf(data+offset, "%[^,]", protocol_str) != 1) { return -1; } + if (strcmp(protocol_str, "tcp") == 0) { + *dst = FORMAT_LOG_PROTOCOL_TCP; + } else if (strcmp(protocol_str, "udp") == 0) { + *dst = FORMAT_LOG_PROTOCOL_UDP; + } else if (strcmp(protocol_str, "icmp") == 0) { + *dst = FORMAT_LOG_PROTOCOL_ICMP; + } else { + return -1; + } + return 0; +} // 初始化函数 int nat_format_init(void) { // 读取配置文件 + MESA_load_profile_uint_def(NAT_FORMAT_CONFIG_FILE, "NAT_FORMAT", "magic_num", &g_nat_format_info.magic_num, 0x004e4154); + MESA_load_profile_uint_def(NAT_FORMAT_CONFIG_FILE, "NAT_FORMAT", "version", &g_nat_format_info.version, 0x0200); + MESA_load_profile_uint_def(NAT_FORMAT_CONFIG_FILE, "NAT_FORMAT_SEND", "batch_size", &g_nat_format_info.batch_size, 20); MESA_load_profile_string_def(NAT_FORMAT_CONFIG_FILE, "NAT_FORMAT_SEND", "host_ip", g_nat_format_info.host_ip, 16, "127.0.0.1"); MESA_load_profile_int_def(NAT_FORMAT_CONFIG_FILE, "NAT_FORMAT_SEND", "host_port", &g_nat_format_info.host_port, 5678); @@ -57,15 +122,20 @@ int nat_format_init(void) { multicast_payload = (char *)malloc(PAYLOAD_LEN * g_nat_format_info.batch_size); memset(multicast_payload, 0, PAYLOAD_LEN * g_nat_format_info.batch_size); - // 创建socket用于发包,绑定组播地址和发包端口 + // 创建socket用于发包 udp_socket = socket(AF_INET, SOCK_DGRAM, 0); if (udp_socket == -1) { printf("UDP multicast socket creation failed:%d, %s\n", errno, strerror(errno)); return -1; } + // 绑定组播地址 dst_addr.sin_family = AF_INET; - dst_addr.sin_addr.s_addr = inet_addr(g_nat_format_info.multicast_ip); + dst_addr.sin_addr.s_addr = inet_addr(g_nat_format_info.multicast_ip); dst_addr.sin_port = htons(g_nat_format_info.multicast_port); + struct in_addr multicast_addr; + inet_pton(AF_INET, g_nat_format_info.multicast_ip, &multicast_addr.s_addr); + setsockopt(udp_socket, IPPROTO_IP, IP_MULTICAST_IF, &multicast_addr, sizeof(multicast_addr)); + // 绑定发包端口 struct sockaddr_in src_addr; src_addr.sin_family = AF_INET; src_addr.sin_port = htons(g_nat_format_info.host_port); @@ -104,46 +174,92 @@ char nat_format_entry(struct streaminfo *a_udp, void **pme, int thread_seq, void // 提取udp流信息 char *udp_data = (char *)a_udp->pudpdetail->pdata; - // int32_t upd_data_len = a_udp->pudpdetail->datalen; - unsigned short udp_port = a_udp->addr.tuple4_v4->source; + int32_t udp_data_len = a_udp->pudpdetail->datalen; + unsigned short udp_port = ntohs(a_udp->addr.tuple4_v4->dest); // 提取nat信息 struct nat_payload nat_payload; + nat_payload.magic_num = htonl(g_nat_format_info.magic_num); + nat_payload.version = htons((unsigned short)g_nat_format_info.version); nat_payload.fw_ip = a_udp->addr.tuple4_v4->saddr; // 防火墙ip为源ip,本身为二进制格式 // 根据数据来源的端口采取不同的处理策略 // 华为syslog格式:防火墙日志生成时间需要转换为时间戳、动作字符串需要转换为序号、点分十进制格式ip需要转换为二进制 if (udp_port == g_nat_format_info.hw_syslog_port) { + // <190>2024-01-25 01:41:37 JXNC_LTGC_Eudemon_A %%01SECLOG/6/SESSION_TEARDOWN(l):IPVer=4,Protocol=udp,SourceIP=10.119.25.34,DestinationIP=220.248.192.13,SourcePort=35040,DestinationPort=53,SourceNatIP=118.212.209.248,SourceNatPort=6438,BeginTime=1706147236,EndTime=1706147236,SourceVpnID=0,DestinationVpnID=0,SourceZone=pscenet,DestinationZone=untrust,PolicyName=---,CloseReason=aged-out. + // sscanf(udp_data, "%*[^>]>%20[0-9: -]%*[^/]/%*[0-9]/%19[A-Z_]%*[^:]:IPVer=%*[^,],Protocol=%*[^,],SourceIP=%19[^,],DestinationIP=%19[^,],SourcePort=%hu,DestinationPort=%hu,SourceNatIP=%19[^,],SourceNatPort=%hu,BeginTime=%u,EndTime=%u", fw_log_time, action_str, src_intra_ip, dst_ip, &nat_payload.src_intra_port, &nat_payload.dst_port, src_extra_ip, &nat_payload.src_extra_port, &nat_payload.stream_start_timestamp, &nat_payload.stream_end_timestamp); + + // 字段前的部分:防火墙日志生成时间、动作 char fw_log_time[21]; char action_str[20]; - char src_intra_ip[20]; - char dst_ip[20]; - char src_extra_ip[20]; - int suc_num = sscanf(udp_data, "%*[^>]>%20[0-9: -]%*[^/]/%*[0-9]/%19[A-Z_]%*[^:]:SourceIP=%19[^,],DestinationIP=%19[^,],SourcePort=%hu,DestinationPort=%hu,SourceNatIP=%19[^,],SourceNatPort=%hu,BeginTime=%u,EndTime=%u", - fw_log_time, action_str, src_intra_ip, dst_ip, &nat_payload.src_intra_port, &nat_payload.dst_port, src_extra_ip, &nat_payload.src_extra_port, &nat_payload.stream_start_timestamp, &nat_payload.stream_end_timestamp); - if (suc_num != 10) { - MESA_handle_runtime_log(g_nat_format_info.log, RLOG_LV_FATAL, "nat_format Huawei syslog", "NAT extraction failed: %d/10", suc_num); - return APP_STATE_DROPME; + if (sscanf(udp_data, "%*[^>]>%20[0-9: -]%*[^/]/%*[0-9]/%19[A-Z_]", fw_log_time, action_str) != 2) { + MESA_handle_runtime_log(g_nat_format_info.log, RLOG_LV_INFO, "nat_format Huawei syslog", "NAT extraction fw_log_time or action_str failed"); + return APP_STATE_GIVEME; } struct tm fw_time; if (strptime(fw_log_time, "%Y-%m-%d %H:%M:%S ", &fw_time) == NULL) { - MESA_handle_runtime_log(g_nat_format_info.log, RLOG_LV_FATAL, "nat_format Huawei syslog", "firewall log generation time extraction failed: %s", fw_log_time); + MESA_handle_runtime_log(g_nat_format_info.log, RLOG_LV_INFO, "nat_format Huawei syslog", "firewall log generation time extraction failed: %s", fw_log_time); return APP_STATE_GIVEME; } nat_payload.fw_log_timestamp = (unsigned int)mktime(&fw_time); - inet_pton(AF_INET, src_intra_ip, &nat_payload.src_intra_ip); - inet_pton(AF_INET, dst_ip, &nat_payload.dst_ip); - inet_pton(AF_INET, src_extra_ip, &nat_payload.src_extra_ip); - if (strcmp(action_str, HW_EVENT_ADD) == 0) { nat_payload.action = FORMAT_LOG_ACTION_ADD; } else if (strcmp(action_str, HW_EVENT_DEL) == 0) { nat_payload.action = FORMAT_LOG_ACTION_DEL; } else { - MESA_handle_runtime_log(g_nat_format_info.log, RLOG_LV_FATAL, "nat_format Huawei syslog", "Event field is an undefined value: %s", action_str); + MESA_handle_runtime_log(g_nat_format_info.log, RLOG_LV_INFO, "nat_format Huawei syslog", "Event field is an undefined value: %s", action_str); return APP_STATE_GIVEME; } + + // 字段部分(按顺序排列):SourceIP、DestinationIP、SourcePort、DestinationPort、SourceNatIP、SourceNatPort、BeginTime、EndTime + // 依次对应nat_payload的:src_intra_ip, dst_ip, src_intra_port, &dst_port, src_extra_ip, src_extra_port, stream_start_timestamp, stream_end_timestamp + + if (extract_ip(udp_data, udp_data_len, "SourceIP", &nat_payload.src_intra_ip) < 0) { + MESA_handle_runtime_log(g_nat_format_info.log, RLOG_LV_INFO, "nat_format Huawei syslog", "SourceIP Not Found"); + return APP_STATE_GIVEME; + } + + if (extract_ip(udp_data, udp_data_len, "DestinationIP", &nat_payload.dst_ip) < 0) { + MESA_handle_runtime_log(g_nat_format_info.log, RLOG_LV_INFO, "nat_format Huawei syslog", "DestinationIP Not Found"); + return APP_STATE_GIVEME; + } + + if (extract_port(udp_data, udp_data_len, "SourcePort", &nat_payload.src_intra_port) < 0) { + MESA_handle_runtime_log(g_nat_format_info.log, RLOG_LV_INFO, "nat_format Huawei syslog", "SourcePort Not Found"); + return APP_STATE_GIVEME; + } + + if (extract_port(udp_data, udp_data_len, "DestinationPort", &nat_payload.dst_port) < 0) { + MESA_handle_runtime_log(g_nat_format_info.log, RLOG_LV_INFO, "nat_format Huawei syslog", "DestinationPort Not Found"); + return APP_STATE_GIVEME; + } + + if (extract_ip(udp_data, udp_data_len, "SourceNatIP", &nat_payload.src_extra_ip) < 0) { + MESA_handle_runtime_log(g_nat_format_info.log, RLOG_LV_INFO, "nat_format Huawei syslog", "SourceNatIP Not Found"); + return APP_STATE_GIVEME; + } + + if (extract_port(udp_data, udp_data_len, "SourceNatPort", &nat_payload.src_extra_port) < 0) { + MESA_handle_runtime_log(g_nat_format_info.log, RLOG_LV_INFO, "nat_format Huawei syslog", "SourceNatPort Not Found"); + return APP_STATE_GIVEME; + } + + if (extract_time(udp_data, udp_data_len, "BeginTime", &nat_payload.stream_start_timestamp) < 0) { + MESA_handle_runtime_log(g_nat_format_info.log, RLOG_LV_INFO, "nat_format Huawei syslog", "BeginTime Not Found"); + return APP_STATE_GIVEME; + } + + if (extract_time(udp_data, udp_data_len, "EndTime", &nat_payload.stream_end_timestamp) < 0) { + MESA_handle_runtime_log(g_nat_format_info.log, RLOG_LV_INFO, "nat_format Huawei syslog", "EndTime Not Found"); + return APP_STATE_GIVEME; + } + + if (extract_protocol(udp_data, udp_data_len, "Protocol", &nat_payload.protocol) < 0) { + MESA_handle_runtime_log(g_nat_format_info.log, RLOG_LV_INFO, "nat_format Huawei syslog", "Protocol Not Found"); + return APP_STATE_GIVEME; + } + } else if (udp_port == g_nat_format_info.hw_binary_port) { return APP_STATE_GIVEME; } else if (udp_port == g_nat_format_info.h3_syslog_port) { @@ -162,8 +278,8 @@ char nat_format_entry(struct streaminfo *a_udp, void **pme, int thread_seq, void // 攒够20个进行发送 if (cur_pkt == 20) { - if (sendto(udp_socket, multicast_payload, strlen(multicast_payload), 0, (struct sockaddr *)&dst_addr, sizeof(dst_addr)) < 0) { - MESA_handle_runtime_log(g_nat_format_info.log, RLOG_LV_FATAL, "nat_format Huawei syslog", "Send multicast failed: %s", strerror(errno)); + if (sendto(udp_socket, multicast_payload, PAYLOAD_LEN*g_nat_format_info.batch_size, 0, (struct sockaddr *)&dst_addr, sizeof(dst_addr)) < 0) { + MESA_handle_runtime_log(g_nat_format_info.log, RLOG_LV_INFO, "nat_format Huawei syslog", "Send multicast failed: %s", strerror(errno)); } cur_pkt = 0; } diff --git a/src/nat_format.h b/src/nat_format.h index 6452b99..ec6048f 100644 --- a/src/nat_format.h +++ b/src/nat_format.h @@ -5,15 +5,11 @@ #include #include -#define FORMAT_LOG_MAGIC_NUMBER 0x004e4154 -#define FORMAT_LOG_VERSION 0x0200 - -#define FORMAT_LOG_PROTOCOL_ICMP 0x01 -#define FORMAT_LOG_PROTOCOL_TCP 0x06 -#define FORMAT_LOG_PROTOCOL_UDP 0x17 // 目前均采用UDP传输 - // 全局配置信息 struct nat_format_global_info { + u_int32_t magic_num; + u_int32_t version; + u_int32_t batch_size; char host_ip[64]; int32_t host_port; @@ -34,8 +30,8 @@ struct nat_format_global_info { // 格式化NAT报文载荷 struct nat_payload { - unsigned int magic_num = FORMAT_LOG_MAGIC_NUMBER; - unsigned short version = FORMAT_LOG_VERSION; + unsigned int magic_num; + unsigned short version; unsigned int fw_log_timestamp; unsigned int fw_ip; char action; @@ -47,7 +43,7 @@ struct nat_payload { unsigned short src_extra_port; unsigned int dst_ip; unsigned short dst_port; - char protocol = FORMAT_LOG_PROTOCOL_UDP; + char protocol; }; extern "C" int nat_format_init(void);