Skip to content

Commit

Permalink
mysql: implement logger
Browse files Browse the repository at this point in the history
Task #3446
  • Loading branch information
QianKaiLin committed Sep 20, 2024
1 parent 38ddc06 commit 5083bc9
Show file tree
Hide file tree
Showing 7 changed files with 328 additions and 0 deletions.
117 changes: 117 additions & 0 deletions rust/src/mysql/logger.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/* Copyright (C) 2022 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* 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
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/

// written by linqiankai <[email protected]>
//
use crate::jsonbuilder::{JsonBuilder, JsonError};
use crate::mysql::mysql::*;

fn log_mysql(tx: &MysqlTransaction, _flags: u32, js: &mut JsonBuilder) -> Result<(), JsonError> {
js.open_object("mysql")?;
js.set_uint("tx_id", tx.tx_id)?;
if let Some(version) = &tx.version {
js.set_string("version", version)?;
}
if let Some(tls) = &tx.tls {
js.set_bool("tls", *tls)?;
} else {
js.set_bool("tls", false)?;
}

if tx.command.is_some() {
let command = tx.command.clone().unwrap();
js.set_string("command", &command)?;
}
if tx.affected_rows.is_some() {
let affected_rows = tx.affected_rows.unwrap();
js.set_uint("affected_rows", affected_rows)?;
}

js.close()?;

Ok(())
}

fn log_mysql_alert(
tx: &MysqlTransaction, _flags: u32, js: &mut JsonBuilder,
) -> Result<(), JsonError> {
js.open_object("mysql")?;
js.set_uint("tx_id", tx.tx_id)?;
if let Some(version) = &tx.version {
js.set_string("version", version)?;
}
if let Some(tls) = &tx.tls {
js.set_bool("tls", *tls)?;
} else {
js.set_bool("tls", false)?;
}

if tx.command.is_some() {
let command = tx.command.clone().unwrap();
js.set_string("command", &command)?;
}
if tx.affected_rows.is_some() {
let affected_rows = tx.affected_rows.unwrap();
js.set_uint("affected_rows", affected_rows)?;
}
if let Some(rows) = &tx.rows {
js.open_array("rows")?;
for row in rows {
js.append_string(row)?;
}
js.close()?;
}

js.close()?;

Ok(())
}

#[no_mangle]
pub unsafe extern "C" fn rs_mysql_logger(
tx: *mut std::os::raw::c_void, flags: u32, js: &mut JsonBuilder,
) -> bool {
let tx_mysql = cast_pointer!(tx, MysqlTransaction);
SCLogDebug!(
"----------- MySQL rs_mysql_logger call. Tx is {:?}",
tx_mysql
);
let result = log_mysql(tx_mysql, flags, js);
if let Err(ref err) = result {
SCLogError!("----------- MySQL rs_mysql_logger failed. err is {:?}", err);
}
return result.is_ok();
}

#[no_mangle]
pub unsafe extern "C" fn rs_mysql_logger_alert(
tx: *mut std::os::raw::c_void, flags: u32, js: &mut JsonBuilder,
) -> bool {
let tx_mysql = cast_pointer!(tx, MysqlTransaction);
SCLogDebug!(
"----------- MySQL rs_mysql_logger_alert call. Tx is {:?}",
tx_mysql
);
let result = log_mysql_alert(tx_mysql, flags, js);
if let Err(ref err) = result {
SCLogError!(
"----------- MySQL rs_mysql_logger_alert failed. err is {:?}",
err
);
}
return result.is_ok();
}
1 change: 1 addition & 0 deletions rust/src/mysql/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@
//! MySQL parser, logger and application layer module.
//!
//! written by Kotodian <[email protected]>
pub mod logger;
pub mod mysql;
pub mod parser;
2 changes: 2 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,7 @@ noinst_HEADERS = \
output-json-smtp.h \
output-json-stats.h \
output-json-tls.h \
output-json-mysql.h \
output-eve-syslog.h \
output-lua.h \
output-packet.h \
Expand Down Expand Up @@ -973,6 +974,7 @@ libsuricata_c_a_SOURCES = \
output-json-smtp.c \
output-json-stats.c \
output-json-tls.c \
output-json-mysql.c \
output-eve.c \
output-eve-syslog.c \
output-eve-null.c \
Expand Down
175 changes: 175 additions & 0 deletions src/output-json-mysql.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
/* Copyright (C) 2022-2024 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* 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
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/

/**
* \file
*
* \author linqiankai <[email protected]>
*
* Implement JSON/eve logging for app-layer MySQL.
*/

#include "suricata-common.h"
#include "detect.h"
#include "pkt-var.h"
#include "conf.h"

#include "threads.h"
#include "threadvars.h"
#include "tm-threads.h"

#include "util-unittest.h"
#include "util-buffer.h"
#include "util-debug.h"
#include "util-byte.h"

#include "output.h"
#include "output-json.h"

#include "app-layer.h"
#include "app-layer-parser.h"

#include "output-json-mysql.h"
#include "rust.h"

#define MYSQL_LOG_NULL BIT_U32(0)
#define MYSQL_DEFAULTS (MYSQL_LOG_NULL)

typedef struct OutputMysqlCtx_ {
uint32_t flags;
OutputJsonCtx *eve_ctx;
} OutputMysqlCtx;

typedef struct LogMysqlLogThread_ {
OutputMysqlCtx *mysqllog_ctx;
OutputJsonThreadCtx *ctx;
} LogMysqlLogThread;

static int JsonMysqlLogger(ThreadVars *tv, void *thread_data, const Packet *p, Flow *f, void *state,
void *txptr, uint64_t tx_id)
{
LogMysqlLogThread *thread = thread_data;
SCLogDebug("Logging mysql transaction %" PRIu64 ".", tx_id);

JsonBuilder *jb =
CreateEveHeader(p, LOG_DIR_FLOW, "mysql", NULL, thread->mysqllog_ctx->eve_ctx);
if (unlikely(jb == NULL)) {
return TM_ECODE_FAILED;
}

if (!rs_mysql_logger(txptr, thread->mysqllog_ctx->flags, jb)) {
goto error;
}

OutputJsonBuilderBuffer(jb, thread->ctx);
jb_free(jb);

return TM_ECODE_OK;

error:
jb_free(jb);
return TM_ECODE_FAILED;
}

static void OutputMysqlLogDeInitCtxSub(OutputCtx *output_ctx)
{
OutputMysqlCtx *mysqllog_ctx = (OutputMysqlCtx *)output_ctx->data;
SCFree(mysqllog_ctx);
SCFree(output_ctx);
}

static OutputInitResult OutputMysqlLogInitSub(ConfNode *conf, OutputCtx *parent_ctx)
{
OutputInitResult result = { NULL, false };
OutputJsonCtx *ojc = parent_ctx->data;

OutputMysqlCtx *mysql_ctx = SCCalloc(1, sizeof(OutputMysqlCtx));
if (unlikely(mysql_ctx == NULL))
return result;

OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx));
if (unlikely(output_ctx == NULL)) {
SCFree(mysql_ctx);
return result;
}

mysql_ctx->eve_ctx = ojc;

output_ctx->data = mysql_ctx;
output_ctx->DeInit = OutputMysqlLogDeInitCtxSub;

AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_MYSQL);

SCLogDebug("MySQL log sub-module initialized.");

result.ctx = output_ctx;
result.ok = true;
return result;
}

static TmEcode JsonMysqlLogThreadInit(ThreadVars *t, const void *initdata, void **data)
{
LogMysqlLogThread *thread = SCCalloc(1, sizeof(LogMysqlLogThread));
if (unlikely(thread == NULL)) {
return TM_ECODE_FAILED;
}

if (initdata == NULL) {
SCLogDebug("Error getting context for EveLogMysql. \"initdata\" is NULL.");
goto error_exit;
}

thread->mysqllog_ctx = ((OutputCtx *)initdata)->data;
thread->ctx = CreateEveThreadCtx(t, thread->mysqllog_ctx->eve_ctx);
if (!thread->ctx) {
goto error_exit;
}
*data = (void *)thread;

return TM_ECODE_OK;

error_exit:
SCFree(thread);
return TM_ECODE_FAILED;
}

static TmEcode JsonMysqlLogThreadDeinit(ThreadVars *t, void *data)
{
LogMysqlLogThread *thread = (LogMysqlLogThread *)data;
if (thread == NULL) {
return TM_ECODE_OK;
}
FreeEveThreadCtx(thread->ctx);
SCFree(thread);
return TM_ECODE_OK;
}

void JsonMysqlLogRegister(void)
{
/* MYSQL_START_REMOVE */
if (ConfGetNode("app-layer.protocols.mysql") == NULL) {
SCLogDebug("Disabling Mysql eve-logger");
return;
}
/* MYSQL_END_REMOVE */
/* Register as an eve sub-module. */
OutputRegisterTxSubModule(LOGGER_JSON_TX, "eve-log", "JsonMysqlLog", "eve-log.mysql",
OutputMysqlLogInitSub, ALPROTO_MYSQL, JsonMysqlLogger, JsonMysqlLogThreadInit,
JsonMysqlLogThreadDeinit);

SCLogDebug("MySQL JSON logger registered.");
}
29 changes: 29 additions & 0 deletions src/output-json-mysql.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/* Copyright (C) 2022-2024 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* 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
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/

/**
* \file
*
* \author linqiankai <[email protected]>
*/

#ifndef SURICATA_OUTPUT_JSON_MYSQL_H
#define SURICATA_OUTPUT_JSON_MYSQL_H

void JsonMysqlLogRegister(void);

#endif // !SURICATA_OUTPUT_JSON_MYSQL_H
3 changes: 3 additions & 0 deletions src/output.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
#include "app-layer-parser.h"
#include "output-filestore.h"
#include "output-json-arp.h"
#include "output-json-mysql.h"

typedef struct RootLogger_ {
OutputLogFunc LogFunc;
Expand Down Expand Up @@ -1105,4 +1106,6 @@ void OutputRegisterLoggers(void)
}
/* ARP JSON logger */
JsonArpLogRegister();
/* MYSQL JSON logger */
JsonMysqlLogRegister();
}
1 change: 1 addition & 0 deletions suricata.yaml.in
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ outputs:
- sip
- quic
- ldap
- mysql
- arp:
enabled: no # Many events can be logged. Disabled by default
- dhcp:
Expand Down

0 comments on commit 5083bc9

Please sign in to comment.