From f13a1bd8802302147f0b2e54f717341db5b5ab1e Mon Sep 17 00:00:00 2001 From: Felipe Zimmerle Date: Mon, 13 Jul 2015 16:48:57 -0300 Subject: [PATCH] Adds support the Parallel audit log index creation The index is now being generated. --- headers/modsecurity/assay.h | 2 + src/Makefile.am | 3 +- src/assay.cc | 45 ++++++++++++++++++ src/audit_log_writer_parallel.cc | 35 ++++++++++++++ src/audit_log_writer_parallel.h | 4 +- src/utils.cc | 9 ++++ src/utils.h | 1 + test/test-cases/regression/auditlog.json | 60 ++++++++++++++++++++++++ 8 files changed, 157 insertions(+), 2 deletions(-) diff --git a/headers/modsecurity/assay.h b/headers/modsecurity/assay.h index 5ed23953..5f22f5f2 100644 --- a/headers/modsecurity/assay.h +++ b/headers/modsecurity/assay.h @@ -153,6 +153,8 @@ class Assay { std::string to_json(int parts); std::string toOldAuditLogFormat(int parts, const std::string &trailer); + std::string toOldAuditLogFormatIndex(const std::string &filename, + double size, const std::string &md5); std::string id; time_t timeStamp; diff --git a/src/Makefile.am b/src/Makefile.am index 66106c34..5768a2c3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -75,7 +75,8 @@ ACTIONS = \ actions/transformations/utf8_to_unicode.cc UTILS = \ - utils/sha1.cc + utils/sha1.cc \ + utils/md5.cc libmodsecurity_la_SOURCES = \ parser/seclang-parser.yy \ diff --git a/src/assay.cc b/src/assay.cc index 83d747d6..b8e94e57 100644 --- a/src/assay.cc +++ b/src/assay.cc @@ -688,6 +688,51 @@ ModSecurityIntervention *Assay::intervention() { } +std::string Assay::toOldAuditLogFormatIndex(const std::string &filename, + double size, const std::string &md5) { + std::stringstream ss; + struct tm timeinfo; + char tstr[300]; + + memset(tstr, '\0', 300); + localtime_r(&this->timeStamp, &timeinfo); + + strftime(tstr, 299, "[%d/%b/%Y:%H:%M:%S %z]", &timeinfo); + + ss << dash_if_empty(this->resolve_variable("REQUEST_HEADERS:Host")) << " "; + ss << dash_if_empty(this->m_clientIpAddress) << " "; + /** TODO: Check variable */ + ss << dash_if_empty(this->resolve_variable("REMOTE_USER")) << " "; + /** TODO: Check variable */ + ss << dash_if_empty(this->resolve_variable("LOCAL_USER")) << " "; + ss << tstr << " "; + + ss << "\""; + ss << this->m_protocol << " "; + ss << this->m_uri << " "; + ss << "HTTP/" << m_httpVersion; + ss << "\" "; + + ss << this->httpCodeReturned << " "; + ss << this->m_responseBody.tellp(); + /** TODO: Check variable */ + ss << dash_if_empty(this->resolve_variable("REFERER")) << " "; + ss << "\""; + ss << dash_if_empty(this->resolve_variable("REQUEST_HEADERS:User-Agent")); + ss << "\" "; + ss << this->id << " "; + /** TODO: Check variable */ + ss << dash_if_empty(this->resolve_variable("REFERER")) << " "; + + ss << filename << " "; + ss << "0" << " "; + ss << std::to_string(size) << " "; + ss << "md5:" << md5 << std::endl; + + return ss.str(); +} + + std::string Assay::toOldAuditLogFormat(int parts, const std::string &trailer) { std::stringstream audit_log; struct tm timeinfo; diff --git a/src/audit_log_writer_parallel.cc b/src/audit_log_writer_parallel.cc index 92695374..08d58671 100644 --- a/src/audit_log_writer_parallel.cc +++ b/src/audit_log_writer_parallel.cc @@ -27,10 +27,22 @@ #include "src/audit_log.h" #include "modsecurity/assay.h" #include "src/utils.h" +#include "utils/md5.h" namespace ModSecurity { +AuditLogWriterParallel::~AuditLogWriterParallel() { + if (log1.is_open()) { + log1.close(); + } + + if (log2.is_open()) { + log2.close(); + } +} + + inline std::string AuditLogWriterParallel::logFilePath(time_t *t, int part) { struct tm timeinfo; @@ -65,6 +77,15 @@ inline std::string AuditLogWriterParallel::logFilePath(time_t *t, bool AuditLogWriterParallel::init() { /** TODO:: Check if the directory exists. */ /** TODO:: Checking if we have permission to write in the target dir */ + + if (!m_audit->m_path1.empty()) { + log1.open(m_audit->m_path1, std::fstream::out | std::fstream::app); + } + + if (!m_audit->m_path2.empty()) { + log2.open(m_audit->m_path2, std::fstream::out | std::fstream::app); + } + return true; } @@ -100,7 +121,21 @@ bool AuditLogWriterParallel::write(Assay *assay, int parts) { fwrite(log.c_str(), log.length(), 1, fp); fclose(fp); + if (log1.is_open() && log2.is_open()) { + log2 << assay->toOldAuditLogFormatIndex(fileName, log.length(), + md5(log)); + } + if (log1.is_open() && !log2.is_open()) { + log1 << assay->toOldAuditLogFormatIndex(fileName, log.length(), + md5(log)); + } + if (!log1.is_open() && log2.is_open()) { + log2 << assay->toOldAuditLogFormatIndex(fileName, log.length(), + md5(log)); + } + return true; } + } // namespace ModSecurity diff --git a/src/audit_log_writer_parallel.h b/src/audit_log_writer_parallel.h index 5f309713..01e437be 100644 --- a/src/audit_log_writer_parallel.h +++ b/src/audit_log_writer_parallel.h @@ -31,7 +31,7 @@ class AuditLogWriterParallel : public AuditLogWriter { explicit AuditLogWriterParallel(AuditLog *audit) : AuditLogWriter(audit) { } - ~AuditLogWriterParallel() { } + ~AuditLogWriterParallel(); bool init() override; bool write(Assay *assay, int parts) override; @@ -69,6 +69,8 @@ class AuditLogWriterParallel : public AuditLogWriter { YearMonthDayAndTimeFileName = 8, }; + std::ofstream log1; + std::ofstream log2; inline std::string logFilePath(time_t *t, int part); }; diff --git a/src/utils.cc b/src/utils.cc index 653e6c75..556a25e0 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -57,6 +57,15 @@ double random_number(const double from, const double to) { } +std::string dash_if_empty(const std::string& str) { + if (str.empty()) { + return "-"; + } + + return str; +} + + double generate_assay_unique_id() { return random_number(0, 100); } diff --git a/src/utils.h b/src/utils.h index 00555181..2967ade6 100644 --- a/src/utils.h +++ b/src/utils.h @@ -28,6 +28,7 @@ namespace ModSecurity { double generate_assay_unique_id(); std::string ascTime(time_t *t); void createDir(std::string dir, int mode); + std::string dash_if_empty(const std::string& str); } // namespace ModSecurity #define SRC_UTILS_H_ diff --git a/test/test-cases/regression/auditlog.json b/test/test-cases/regression/auditlog.json index 59e47e48..bd744794 100644 --- a/test/test-cases/regression/auditlog.json +++ b/test/test-cases/regression/auditlog.json @@ -117,5 +117,65 @@ "SecAuditLogType Serial", "SecAuditLogRelevantStatus \"^(?:5|4(?!04))\"" ] + }, + { + "enabled": 1, + "version_min": 300000, + "version_max": 0, + "title": "auditlog : basic parser test - serial", + "client": { + "ip": "200.249.12.31", + "port": 2313 + }, + "server": { + "ip": "200.249.12.31", + "port": 80 + }, + "request": { + "headers": { + "Host": "www.modsecurity.org", + "User-Agent": "Mozilla\/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko\/20091102 Firefox\/3.5.5 (.NET CLR 3.5.30729)", + "Accept": "text\/html,application\/xhtml+xml,application\/xml;q=0.9,*\/*;q=0.8", + "Accept-Language": "en-us,en;q=0.5", + "Accept-Encoding": "gzip,deflate", + "Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7", + "Keep-Alive": "300", + "Connection": "keep-alive", + "Pragma": "no-cache", + "Cache-Control": "no-cache" + }, + "uri": "\/test.pl?param1= test ¶m2=test2", + "protocol": "GET", + "http_version": 1.1, + "body": "" + }, + "response": { + "headers": { + "Content-Type": "plain\/text\n\r" + }, + "body": [ + "test" + ] + }, + "expected": { + "audit_log": "", + "debug_log": "\\[9\\] T \\(0\\) trim: \"test\"", + "error_log": "", + "http_code": 403 + }, + "rules": [ + "SecRuleEngine On", + "SecDebugLog \/tmp\/modsec_debug.log", + "SecDebugLogLevel 9", + "SecRule ARGS \"@contains test\" \"t:trim,block,auditlog\"", + "SecAuditEngine RelevantOnly", + "SecAuditLogParts ABCFHZ", + "SecAuditLogStorageDir /tmp/test", + "SecAuditLog /tmp/audit_test_parallel.log", + "SecAuditLogDirMode 0766", + "SecAuditLogFileMode 0600", + "SecAuditLogType Parallel", + "SecAuditLogRelevantStatus \"^(?:5|4(?!04))\"" + ] } ]