This repository has been archived on 2025-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
zhaoyijun-nat-format/src/nat_format.cpp
2024-08-26 18:31:05 +08:00

173 lines
7.9 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <time.h>
#include <unistd.h>
#include "nat_format.h"
#define 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(NAT_FORMAT_CONFIG_FILE, "NAT_FORMAT_LOG", "run_log_path", g_nat_format_info.log_path, sizeof(g_nat_format_info.log_path), "./log/nat_format.log");
MESA_load_profile_uint_def(NAT_FORMAT_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_nat_format_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;
nat_payload.fw_ip = a_udp->addr.tuple4_v4->saddr; // 防火墙ip为源ip本身为二进制格式
// 根据数据来源的端口采取不同的处理策略
// 华为syslog格式防火墙日志生成时间需要转换为时间戳、动作字符串需要转换为序号、点分十进制格式ip需要转换为二进制
if (udp_port == 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;
}
} 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) {
return APP_STATE_GIVEME;
} else if (udp_port == g_nat_format_info.h3_binary_port) {
return APP_STATE_GIVEME;
} else if (udp_port == g_nat_format_info.dp_syslog_port) {
return APP_STATE_GIVEME;
} else if (udp_port == g_nat_format_info.dp_binary_port) {
return APP_STATE_GIVEME;
}
// 将提取出来的信息写进组播载荷
memcpy(multicast_payload + cur_pkt*PAYLOAD_LEN, &nat_payload, PAYLOAD_LEN);
cur_pkt++;
// 攒够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));
}
cur_pkt = 0;
}
return APP_STATE_GIVEME;
}