From 37d3039dd12dd588b6038cf6e2e836d332043214 Mon Sep 17 00:00:00 2001 From: Junzy <523909343@qq.com> Date: Fri, 23 Aug 2024 17:53:01 +0800 Subject: [PATCH] first commit --- CMakeLists.txt | 15 ++++ bin/conf/nat_format.conf | 18 ++++ bin/conf/nat_format.inf | 9 ++ src/nat_format.cpp | 175 +++++++++++++++++++++++++++++++++++++++ src/nat_format.h | 53 ++++++++++++ 5 files changed, 270 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 bin/conf/nat_format.conf create mode 100644 bin/conf/nat_format.inf create mode 100644 src/nat_format.cpp create mode 100644 src/nat_format.h diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..b9ed544 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,15 @@ +set (PLUG_NAT_FORMAT_SRC nat_format.cpp) +add_definitions(-fPIC -Wall -g) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__FILENAME__='\"$(subst ${CMAKE_CURRENT_SOURCE_DIR}/,,$(abspath $<))\"'") + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) +include_directories(/opt/MESA/include/) + +set(PLUG_NAT_FORMAT_DEPEND_DYN_LIB MESA_handle_logger MESA_prof_load MESA_field_stat2 avro libevent libevent-openssl libevent-pthreads curl) + +add_library(nat_format SHARED ${PLUG_NAT_FORMAT_SRC}) +target_link_libraries(nat_format ${PLUG_NAT_FORMAT_DEPEND_DYN_LIB}) +set_target_properties(nat_format PROPERTIES PREFIX "") + +install(TARGETS nat_format DESTINATION ${CMAKE_INSTALL_PREFIX}/plug/business/nat_format) +install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/bin/conf/nat_format.conf DESTINATION ${CMAKE_INSTALL_PREFIX}/conf) diff --git a/bin/conf/nat_format.conf b/bin/conf/nat_format.conf new file mode 100644 index 0000000..d86921e --- /dev/null +++ b/bin/conf/nat_format.conf @@ -0,0 +1,18 @@ +[NAT_FORMAT_SEND] +batch_size=20 +host_ip=127.0.0.1 +host_port=5678 +multicast_ip=224.88.88.88 +multicast_port=0 + +[NAT_FORMAT_RECEIVE_PORT] +hw_syslog=514 +hw_binary=515 +h3_syslog=516 +h3_binary=517 +dp_syslog=518 +dp_binary=519 + +[NAT_FORMAT_LOG] +run_log_path=./log/nat_format.log +run_log_level=10 diff --git a/bin/conf/nat_format.inf b/bin/conf/nat_format.inf new file mode 100644 index 0000000..fb02ba5 --- /dev/null +++ b/bin/conf/nat_format.inf @@ -0,0 +1,9 @@ +[PLUGINFO] +PLUGNAME=nat_format +SO_PATH=./plug/business/nat_format/nat_format.so +INIT_FUNC=nat_format_init +DESTROY_FUNC=nat_format_destroy + +[UDP] +FUNC_FLAG=ALL +FUNC_NAME=nat_format_entry \ No newline at end of file diff --git a/src/nat_format.cpp b/src/nat_format.cpp new file mode 100644 index 0000000..20a8465 --- /dev/null +++ b/src/nat_format.cpp @@ -0,0 +1,175 @@ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "nat_format.h" + +#define NAT_FORMAT_NAT_FORMAT_CONFIG_FILE "./conf/nat_format.conf" +#define PAYLOAD_LEN 46 + +#define FORMAT_LOG_ACTION_ADD 0x00 +#define FORMAT_LOG_ACTION_DEL 0x01 + +#define HW_EVENT_ADD "SESSION_BUILT" +#define HW_EVENT_DEL "SESSION_TEARDOWN" + +struct nat_format_global_info g_nat_format_info; + +char *multicast_payload; +int cur_pkt = 0; + +int udp_socket; +struct sockaddr_in dst_addr; + +// 初始化函数 +int nat_format_init(void) { + // 读取配置文件 + 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); + MESA_load_profile_string_def(NAT_FORMAT_CONFIG_FILE, "NAT_FORMAT_SEND", "multicast_ip", g_nat_format_info.multicast_ip, 16, "224.88.88.88"); + MESA_load_profile_int_def(NAT_FORMAT_CONFIG_FILE, "NAT_FORMAT_SEND", "multicast_port", &g_nat_format_info.multicast_port, 0); + + MESA_load_profile_int_def(NAT_FORMAT_CONFIG_FILE, "NAT_FORMAT_RECEIVE_PORT", "hw_syslog", &g_nat_format_info.hw_syslog_port, 514); + MESA_load_profile_int_def(NAT_FORMAT_CONFIG_FILE, "NAT_FORMAT_RECEIVE_PORT", "hw_binary", &g_nat_format_info.hw_binary_port, 515); + MESA_load_profile_int_def(NAT_FORMAT_CONFIG_FILE, "NAT_FORMAT_RECEIVE_PORT", "h3_syslog", &g_nat_format_info.h3_syslog_port, 516); + MESA_load_profile_int_def(NAT_FORMAT_CONFIG_FILE, "NAT_FORMAT_RECEIVE_PORT", "h3_binary", &g_nat_format_info.h3_binary_port, 517); + MESA_load_profile_int_def(NAT_FORMAT_CONFIG_FILE, "NAT_FORMAT_RECEIVE_PORT", "dp_syslog", &g_nat_format_info.dp_syslog_port, 518); + MESA_load_profile_int_def(NAT_FORMAT_CONFIG_FILE, "NAT_FORMAT_RECEIVE_PORT", "dp_binary", &g_nat_format_info.dp_binary_port, 519); + + MESA_load_profile_string_def(config_file, "NAT_FORMAT_LOG", "run_log_path", g_nat_format_info.log_path, sizeof(g_nat_format_info.root_log_path), "./log/nat_format.log"); + MESA_load_profile_uint_def(config_file, "NAT_FORMAT_LOG", "run_log_level", &g_nat_format_info.log_level, 10); + g_nat_format_info.log = MESA_create_runtime_log_handle(g_nat_format_info.log_path, g_nat_format_info.log_level); + if (g_tf_dns_info.log == NULL) { + printf("MESA_create_runtime_log_handle %s failed: %s\n", g_nat_format_info.log_path, strerror(errno)); + return -1; + } + + // 分配并初始化组播报文存储空间,长度为 batch_size*46Bytes + 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用于发包,绑定组播地址和发包端口 + 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_port = htons(g_nat_format_info.multicast_port); + struct sockaddr_in src_addr; + src_addr.sin_family = AF_INET; + src_addr.sin_port = htons(g_nat_format_info.host_port); + src_addr.sin_addr.s_addr = inet_addr(g_nat_format_info.host_ip); + if (bind(udp_socket, (struct sockaddr*)&src_addr, sizeof(src_addr)) < 0) { + printf("socket bind failed\n"); + close(udp_socket); + return -1; + } + + return 0; +} + +// 卸载函数 +void nat_format_destroy(void) { + free(nat_payload); +} + +// 入口函数 +/* + 输入参数: + a_udp: UDP流信息,详见stream.h; + pme: UDP链接上下文信息; + thread_seq: 线程号 + a_packet: 原始IP数据包 + 返回值: + PROT_STATE_GIVEME: 业务插件继续需要给会话后续包; + PROT_STATE_DROPME: 业务插件不再需要该会话后续包; + PROT_STATE_KILLME: 业务插件对此流做FD动作,此流不再给其他插件。 +*/ +char nat_format_entry(struct streaminfo *a_udp, void **pme, int thread_seq, void *a_packet) { + // 不处理空数据包 + if (a_packet == NULL) { + return APP_STATE_GIVEME; + } + + // 提取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; + + // 提取nat信息 + struct nat_payload nat_payload; + inet_pton(AF_INET, a_udp->addr.tuple4_v4->s_addr, nat_payload.fw_ip); // 防火墙ip为源ip,需要进行点分十进制转换 + // 根据数据来源的端口采取不同的处理策略 + switch (udp_port) { + // 华为syslog格式:防火墙日志生成时间需要转换为时间戳、动作字符串需要转换为序号、点分十进制格式ip需要转换为二进制 + case g_nat_format_info.hw_syslog_port: + 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 + } + + 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); + 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); + return APP_STATE_GIVEME; + } + + break; + case g_nat_format_info.hw_binary_port: + break; + case g_nat_format_info.h3_syslog_port: + break; + case g_nat_format_info.h3_binary_port: + break; + case g_nat_format_info.dp_syslog_port: + break; + case g_nat_format_info.dp_binary_port: + break; + default: + break; + } + + // 将提取出来的信息写进组播载荷 + memcpy(multicast_payload + cur_pkt*PAYLOAD_LEN, &nat_payload, PAYLOAD_LEN); + cur_pkt++; + + // 攒够20个进行发送 + if (cur_pkt == 20) { + if (sendto(udp_socket, buf, strlen(buf), 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", "Event field is an undefined value: %s", action_str); + } + cur_pkt = 0; + } + + return APP_STATE_GIVEME; +} diff --git a/src/nat_format.h b/src/nat_format.h new file mode 100644 index 0000000..33c773c --- /dev/null +++ b/src/nat_format.h @@ -0,0 +1,53 @@ +#ifndef NAT_FORMAT_H_ +#define NAT_FORMAT_H_ + +#include +#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 { + int32_t batch_size; + char host_ip[64]; + u_int32_t host_port; + char multicast_ip[64]; + u_int32_t multicast_port; + + int32_t hw_syslog_port; + int32_t hw_binary_port; + int32_t h3_syslog_port; + int32_t h3_binary_port; + int32_t dp_syslog_port; + int32_t dp_binary_port; + + char root_log_path[256]; + u_int32_t log_level; + void *log; +}; + +// 格式化NAT报文载荷 +struct nat_payload { + unsigned int magic_num = FORMAT_LOG_MAGIC_NUMBER; + unsigned short magic_num = FORMAT_LOG_VERSION; + unsigned int fw_log_timestamp; + unsigned int fw_ip; + char action; + unsigned int stream_start_timestamp; + unsigned int stream_end_timestamp; + unsigned int src_intra_ip; + unsigned short src_intra_port; + unsigned int src_extra_ip; + unsigned short src_extra_port; + unsigned int dst_ip; + unsigned short dst_port; + char protocol = FORMAT_LOG_PROTOCOL_UDP; +}; + +#endif // NAT_FORMAT_H_