mirror of
https://github.com/ntop/ntopng.git
synced 2026-05-06 03:45:26 +00:00
268 lines
7.1 KiB
C++
268 lines
7.1 KiB
C++
/*
|
|
*
|
|
* (C) 2019-25 - ntop.org
|
|
*
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
*/
|
|
|
|
#include "ntop_includes.h"
|
|
|
|
#ifndef HAVE_NEDGE
|
|
|
|
// #define SYSLOG_DEBUG
|
|
|
|
/* **************************************************** */
|
|
|
|
SyslogParserInterface::SyslogParserInterface(const char *endpoint,
|
|
const char *custom_interface_type)
|
|
: ParserInterface(endpoint, custom_interface_type) {
|
|
if(trace_new_delete) ntop->getTrace()->traceEvent(TRACE_NORMAL, "[new] %s", __FILE__);
|
|
le = NULL;
|
|
producers_reload_requested = true;
|
|
}
|
|
|
|
/* **************************************************** */
|
|
|
|
void SyslogParserInterface::startPacketPolling() {
|
|
/* Allocate the SyslogLuaEngine only after the scripts have been loaded */
|
|
le = new (std::nothrow) SyslogLuaEngine(this);
|
|
|
|
ParserInterface::
|
|
startPacketPolling(); /* -> NetworkInterface::startPacketPolling(); */
|
|
}
|
|
|
|
/* **************************************************** */
|
|
|
|
SyslogParserInterface::~SyslogParserInterface() {
|
|
if (le) delete le;
|
|
}
|
|
|
|
/* **************************************************** */
|
|
|
|
u_int8_t SyslogParserInterface::parseLog(char *log_line, char *client_ip) {
|
|
const char *producer_name = NULL;
|
|
char *prio = NULL, *parsed_client_ip = NULL, *device = NULL,
|
|
*application = NULL, *content = NULL;
|
|
char *tmp;
|
|
u_int32_t num_total_events = 0, num_malformed = 0;
|
|
|
|
if (producers_reload_requested) {
|
|
doProducersMappingUpdate();
|
|
producers_reload_requested = false;
|
|
}
|
|
|
|
/* Event parsing */
|
|
|
|
if (log_line == NULL || strlen(log_line) == 0) goto exit;
|
|
|
|
#ifdef SYSLOG_DEBUG
|
|
ntop->getTrace()->traceEvent(TRACE_NORMAL, "[SYSLOG] Raw message: %s",
|
|
log_line);
|
|
#endif
|
|
|
|
/* Check if this is a clean JSON (no Syslog header) */
|
|
if (log_line[0] == '{') {
|
|
content = log_line;
|
|
goto detect_producer;
|
|
}
|
|
|
|
/*
|
|
* Supported Log Format ({} are used to indicate optional items)
|
|
* {TIMESTAMP;HOST; }<PRIO>{TIMESTAMP DEVICE} APPLICATION{[PID]}{: }CONTENT
|
|
*/
|
|
|
|
/* Look for <PRIO> */
|
|
prio = strchr(log_line, '<');
|
|
if (prio == NULL) {
|
|
num_malformed++;
|
|
goto exit;
|
|
}
|
|
|
|
if (prio != log_line) { /* Parse TIMESTAMP;HOST; <PRIO> */
|
|
prio[0] = '\0';
|
|
|
|
parsed_client_ip = strchr(log_line, ';');
|
|
if (parsed_client_ip != NULL) {
|
|
parsed_client_ip++;
|
|
tmp = strchr(parsed_client_ip, ';');
|
|
if (tmp != NULL) tmp[0] = '\0';
|
|
}
|
|
}
|
|
|
|
prio++;
|
|
log_line = strchr(prio, '>');
|
|
if (log_line == NULL) {
|
|
num_malformed++;
|
|
goto exit;
|
|
}
|
|
|
|
log_line[0] = '\0';
|
|
log_line++;
|
|
|
|
if (strncmp(log_line, "date=", 5) == 0) { /* Parse custom Fortinet format */
|
|
producer_name = "fortinet"; /* fortinet detected */
|
|
content = log_line;
|
|
} else if ((tmp = strstr(log_line, "]: ")) !=
|
|
NULL) { /* Parse APPLICATION[PID]: */
|
|
content = &tmp[3];
|
|
tmp[1] = '\0';
|
|
tmp = strrchr(log_line, '[');
|
|
if (tmp != NULL) {
|
|
tmp[0] = '\0';
|
|
|
|
/* Parse APPLICATION */
|
|
tmp = strrchr(log_line, ' ');
|
|
if (tmp != NULL) {
|
|
tmp[0] = '\0';
|
|
application = &tmp[1];
|
|
|
|
/* Parse DEVICE */
|
|
tmp = strrchr(log_line, ' ');
|
|
if (tmp != NULL) device = &tmp[1];
|
|
}
|
|
}
|
|
} else if ((tmp = strstr(log_line, ": ")) != NULL) { /* Parse APPLICATION: */
|
|
content = &tmp[2];
|
|
tmp[0] = '\0';
|
|
|
|
tmp = strrchr(log_line, ' ');
|
|
if (tmp != NULL) {
|
|
tmp[0] = '\0';
|
|
|
|
/* Parse DEVICE */
|
|
tmp = strrchr(log_line, ' ');
|
|
if (tmp != NULL) device = &tmp[1];
|
|
}
|
|
} else { /* Ignore ':' as last resort */
|
|
content = log_line;
|
|
}
|
|
|
|
num_total_events++;
|
|
|
|
/* Producer Lookup */
|
|
|
|
detect_producer:
|
|
|
|
if (producer_name == NULL && parsed_client_ip != NULL) {
|
|
Utils::stringtolower(parsed_client_ip); /* normalize */
|
|
producer_name = getProducerName(parsed_client_ip);
|
|
}
|
|
|
|
if (producer_name == NULL && device != NULL) {
|
|
Utils::stringtolower(device); /* normalize */
|
|
producer_name = getProducerName(device);
|
|
}
|
|
|
|
if (producer_name == NULL && client_ip != NULL) {
|
|
producer_name = getProducerName(client_ip);
|
|
}
|
|
|
|
if (producer_name == NULL && application != NULL) {
|
|
Utils::stringtolower(application); /* normalize */
|
|
producer_name = application;
|
|
}
|
|
|
|
if (producer_name == NULL) {
|
|
producer_name = getProducerName("*");
|
|
}
|
|
|
|
if (producer_name == NULL) goto exit;
|
|
|
|
#ifdef SYSLOG_DEBUG
|
|
ntop->getTrace()->traceEvent(TRACE_NORMAL,
|
|
"[SYSLOG] Application: %s Message: %s",
|
|
producer_name, content);
|
|
#endif
|
|
|
|
/* Dispatching */
|
|
|
|
if (le)
|
|
le->handleEvent(producer_name, content,
|
|
parsed_client_ip ? parsed_client_ip : client_ip,
|
|
prio ? atoi(prio) : 0);
|
|
|
|
exit:
|
|
incSyslogStats(num_total_events, num_malformed, 0, 0, 0, 0, 0);
|
|
return 0;
|
|
}
|
|
|
|
/* **************************************************** */
|
|
|
|
void SyslogParserInterface::lua(lua_State *vm, bool fullStats) {
|
|
NetworkInterface::lua(vm, fullStats);
|
|
}
|
|
|
|
/* **************************************************** */
|
|
|
|
void SyslogParserInterface::addProducerMapping(const char *host,
|
|
const char *producer) {
|
|
string host_ip(host);
|
|
string producer_name(producer);
|
|
producers_map_t::iterator it;
|
|
|
|
if ((it = producers_map.find(host_ip)) == producers_map.end())
|
|
producers_map.insert(make_pair(host_ip, producer_name));
|
|
else
|
|
it->second = producer_name;
|
|
}
|
|
|
|
/* **************************************************** */
|
|
|
|
void SyslogParserInterface::doProducersMappingUpdate() {
|
|
char key[64];
|
|
char **keys, **values;
|
|
int rc;
|
|
|
|
producers_map.clear();
|
|
|
|
snprintf(key, sizeof(key), SYSLOG_PRODUCERS_MAP_KEY, get_id());
|
|
|
|
rc = ntop->getRedis()->hashGetAll(key, &keys, &values);
|
|
|
|
if (rc > 0) {
|
|
for (int i = 0; i < rc; i++) {
|
|
if (keys[i] && values[i]) {
|
|
ntop->getTrace()->traceEvent(
|
|
TRACE_INFO, "Adding syslog producer %s (%s)", keys[i], values[i]);
|
|
Utils::stringtolower(keys[i]); /* normalize */
|
|
addProducerMapping(keys[i], values[i]);
|
|
}
|
|
|
|
if (values[i]) free(values[i]);
|
|
if (keys[i]) free(keys[i]);
|
|
}
|
|
|
|
free(keys);
|
|
free(values);
|
|
}
|
|
}
|
|
|
|
/* **************************************************** */
|
|
|
|
const char *SyslogParserInterface::getProducerName(const char *host) {
|
|
string host_ip(host);
|
|
producers_map_t::const_iterator it;
|
|
|
|
if ((it = producers_map.find(host_ip)) != producers_map.end())
|
|
return it->second.c_str();
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/* **************************************************** */
|
|
|
|
#endif
|