diff --git a/configure.ac b/configure.ac index 2da602a5..bd23c30e 100644 --- a/configure.ac +++ b/configure.ac @@ -323,6 +323,7 @@ AM_COND_IF([EXAMPLES], examples/simple_example_using_c/Makefile \ examples/multiprocess_c/Makefile \ examples/reading_logs_with_offset/Makefile \ + examples/reading_logs_via_rule_message/Makefile \ ])]) AM_COND_IF([AFL_FUZZER], diff --git a/examples/Makefile.am b/examples/Makefile.am index 54e99384..ac41dc65 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -5,7 +5,8 @@ ACLOCAL_AMFLAGS = -I build SUBDIRS = \ simple_example_using_c \ multiprocess_c \ - reading_logs_with_offset + reading_logs_with_offset \ + reading_logs_via_rule_message # make clean CLEANFILES = diff --git a/examples/reading_logs_via_rule_message/Makefile.am b/examples/reading_logs_via_rule_message/Makefile.am new file mode 100644 index 00000000..f3740fcf --- /dev/null +++ b/examples/reading_logs_via_rule_message/Makefile.am @@ -0,0 +1,40 @@ + + +noinst_PROGRAMS = simple_request + +simple_request_SOURCES = \ + simple_request.cc + +simple_request_LDADD = \ + $(top_builddir)/src/.libs/libmodsecurity.a \ + $(CURL_LDADD) \ + $(GEOIP_LDFLAGS) $(GEOIP_LDADD) \ + $(PCRE_LDADD) \ + $(YAJL_LDFLAGS) $(YAJL_LDADD) \ + $(LMDB_LDFLAGS) $(LMDB_LDADD) \ + $(LIBXML2_LDADD) \ + $(GLOBAL_LDADD) + + +simple_request_CPPFLAGS = \ + $(GLOBAL_CFLAGS) \ + -std=c++11 \ + -I$(top_builddir)/headers \ + -I$(top_builddir) \ + -g \ + -I../others \ + -fPIC \ + -O3 \ + $(GEOIP_CFLAGS) \ + $(GLOBAL_CPPFLAGS) \ + $(MODSEC_NO_LOGS) \ + $(YAJL_CFLAGS) \ + $(LMDB_CFLAGS) \ + $(PCRE_CFLAGS) \ + $(LIBXML2_CFLAGS) + + +MAINTAINERCLEANFILES = \ + Makefile.in + + diff --git a/examples/reading_logs_via_rule_message/blocked_request.conf b/examples/reading_logs_via_rule_message/blocked_request.conf new file mode 100644 index 00000000..596b5640 --- /dev/null +++ b/examples/reading_logs_via_rule_message/blocked_request.conf @@ -0,0 +1,3 @@ +SecRule ARGS:param1 "test" "id:1,deny,phase:2,chain,msg:'test'" +SecRule ARGS:param1 "test" "log" + diff --git a/examples/reading_logs_via_rule_message/blocked_request_engine_on.conf b/examples/reading_logs_via_rule_message/blocked_request_engine_on.conf new file mode 100644 index 00000000..af376c89 --- /dev/null +++ b/examples/reading_logs_via_rule_message/blocked_request_engine_on.conf @@ -0,0 +1,2 @@ +SecRuleEngine On +SecRule ARGS:param1 "test" "id:1,deny" diff --git a/examples/reading_logs_via_rule_message/match.conf b/examples/reading_logs_via_rule_message/match.conf new file mode 100644 index 00000000..471c484a --- /dev/null +++ b/examples/reading_logs_via_rule_message/match.conf @@ -0,0 +1 @@ +SecRule ARGS:param1 "test" "id:1,deny,msg:'this',msg:'is',msg:'a',msg:'test'" diff --git a/examples/reading_logs_via_rule_message/no_match.conf b/examples/reading_logs_via_rule_message/no_match.conf new file mode 100644 index 00000000..51f239fb --- /dev/null +++ b/examples/reading_logs_via_rule_message/no_match.conf @@ -0,0 +1 @@ +SecRule ARGS:param1 "WHEEE" "id:1,phase:2,deny,msg:'this',msg:'is',msg:'a',msg:'test'" diff --git a/examples/reading_logs_via_rule_message/reading_logs_via_rule_message.h b/examples/reading_logs_via_rule_message/reading_logs_via_rule_message.h new file mode 100644 index 00000000..0ce86303 --- /dev/null +++ b/examples/reading_logs_via_rule_message/reading_logs_via_rule_message.h @@ -0,0 +1,123 @@ +/* + * ModSecurity, http://www.modsecurity.org/ + * Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/) + * + * You may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Trustwave Holdings, Inc. + * directly using the email address security@modsecurity.org. + * + */ + +#include +#include + +#include "modsecurity/rule_message.h" + +#ifndef EXAMPLES_READING_LOGS_VIA_RULE_MESSAGE_READING_LOGS_VIA_RULE_MESSAGE_H_ +#define EXAMPLES_READING_LOGS_VIA_RULE_MESSAGE_READING_LOGS_VIA_RULE_MESSAGE_H_ + + +class ReadingLogsViaRuleMessage { + public: + ReadingLogsViaRuleMessage(char *request_header, + char *request_uri, + char *request_body, + char *response_headers, + char *response_body, + char *ip, + std::string rules) : + m_request_header(request_header), + m_request_uri(request_uri), + m_request_body(request_body), + m_response_headers(response_headers), + m_response_body(response_body), + m_ip(ip), + m_rules(rules) + { } + + int process() { + modsecurity::ModSecurity *modsec; + modsecurity::Rules *rules; + modsecurity::ModSecurityIntervention it; + + modsec = new modsecurity::ModSecurity(); + modsec->setConnectorInformation("ModSecurity-test v0.0.1-alpha" \ + " (ModSecurity test)"); + modsec->setServerLogCb(logCb, modsecurity::RuleMessageLogProperty + | modsecurity::IncludeFullHighlightLogProperty); + + rules = new modsecurity::Rules(); + if (rules->loadFromUri(m_rules.c_str()) < 0) { + std::cout << "Problems loading the rules..." << std::endl; + std::cout << rules->m_parserError.str() << std::endl; + return -1; + } + + modsecurity::Transaction *modsecTransaction = \ + new modsecurity::Transaction(modsec, rules, NULL); + modsecTransaction->processConnection(m_ip, 12345, "127.0.0.1", 80); + modsecTransaction->processURI(m_request_uri, "GET", "1.1"); + + modsecTransaction->addRequestHeader("Host", + "net.tutsplus.com"); + modsecTransaction->processRequestHeaders(); + modsecTransaction->processRequestBody(); + modsecTransaction->addResponseHeader("HTTP/1.1", + "200 OK"); + modsecTransaction->processResponseHeaders(200, "HTTP 1.2"); + modsecTransaction->appendResponseBody( + (const unsigned char*)m_response_body, + strlen((const char*)m_response_body)); + modsecTransaction->processResponseBody(); + modsecTransaction->processLogging(); + + delete modsecTransaction; + delete rules; + delete modsec; + return 0; +end: + return -1; + } + + static void logCb(void *data, const void *ruleMessagev) { + if (ruleMessagev == NULL) { + std::cout << "I've got a call but the message was null ;("; + std::cout << std::endl; + return; + } + + const modsecurity::RuleMessage *ruleMessage = \ + reinterpret_cast(ruleMessagev); + + std::cout << "Rule Id: " << std::to_string(ruleMessage->m_ruleId); + std::cout << " phase: " << std::to_string(ruleMessage->m_phase); + std::cout << std::endl; + if (ruleMessage->m_isDisruptive) { + std::cout << " * Disruptive action: "; + std::cout << modsecurity::RuleMessage::log(ruleMessage); + std::cout << std::endl; + std::cout << " ** %d is meant to be informed by the webserver."; + std::cout << std::endl; + } else { + std::cout << " * Match, but no disruptive action: "; + std::cout << modsecurity::RuleMessage::log(ruleMessage); + std::cout << std::endl; + } + } + + protected: + char *m_request_header; + char *m_request_uri; + char *m_request_body; + char *m_response_headers; + char *m_response_body; + char *m_ip; + std::string m_rules; +}; + +#endif // EXAMPLES_READING_LOGS_VIA_RULE_MESSAGE_READING_LOGS_VIA_RULE_MESSAGE_H_ diff --git a/examples/reading_logs_via_rule_message/simple_request.cc b/examples/reading_logs_via_rule_message/simple_request.cc new file mode 100644 index 00000000..23826f77 --- /dev/null +++ b/examples/reading_logs_via_rule_message/simple_request.cc @@ -0,0 +1,77 @@ +/* + * ModSecurity, http://www.modsecurity.org/ + * Copyright (c) 2015 Trustwave Holdings, Inc. (http://www.trustwave.com/) + * + * You may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Trustwave Holdings, Inc. + * directly using the email address security@modsecurity.org. + * + */ + +#include +#include + +#include +#include + +#include "examples/reading_logs_via_rule_message/reading_logs_via_rule_message.h" + +char request_header[] = "" \ + "GET /tutorials/other/top-20-mysql-best-practices/ HTTP/1.1\n\r" \ + "Host: net.tutsplus.com\n\r" \ + "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)\n\r" \ + "Accept: text/html,application/xhtml+xml,application/xml; " \ + "q=0.9,*/*;q=0.8\n\r" \ + "Accept-Language: en-us,en;q=0.5\n\r" \ + "Accept-Encoding: gzip,deflate\n\r" \ + "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\n\r" \ + "Keep-Alive: 300\n\r" \ + "Connection: keep-alive\n\r" \ + "Cookie: PHPSESSID=r2t5uvjq435r4q7ib3vtdjq120\n\r" \ + "Pragma: no-cache\n\r" \ + "Cache-Control: no-cache\n\r"; + +char request_uri[] = "/test.pl?param1=test¶2=test2"; + +char request_body[] = ""; + +char response_headers[] = "" \ + "HTTP/1.1 200 OK\n\r" \ + "Content-Type: text/xml; charset=utf-8\n\r" \ + "Content-Length: length\n\r"; + +char response_body[] = "" \ + "\n\r" \ + "\n\r" \ + " \n\r" \ + " \n\r" \ + " string\n\r" \ + " \n\r" \ + " \n\r" \ + "\n\r"; + +char ip[] = "200.249.12.31"; + + +int main(int argc, char **argv) { + (*argv)++; + if (*argv == NULL) { + (*argv)--; + std::cout << "Use " << *argv << " test-case-file.conf"; + std::cout << std::endl << std::endl; + return -1; + } + std::string rules(*argv); + ReadingLogsViaRuleMessage rlvrm(request_header, request_uri, request_body, + response_headers, response_body, ip, rules); + rlvrm.process(); + return 0; +} diff --git a/headers/modsecurity/actions/action.h b/headers/modsecurity/actions/action.h index d28fd75d..96f5921b 100644 --- a/headers/modsecurity/actions/action.h +++ b/headers/modsecurity/actions/action.h @@ -17,6 +17,7 @@ #include #include +#include #endif @@ -62,7 +63,7 @@ class Action { Transaction *transaction); virtual bool evaluate(Rule *rule, Transaction *transaction); virtual bool evaluate(Rule *rule, Transaction *transaction, - RuleMessage *ruleMessage) { + std::shared_ptr ruleMessage) { return evaluate(rule, transaction); } virtual bool init(std::string *error) { return true; } diff --git a/headers/modsecurity/modsecurity.h b/headers/modsecurity/modsecurity.h index 43250358..8ca2aa45 100644 --- a/headers/modsecurity/modsecurity.h +++ b/headers/modsecurity/modsecurity.h @@ -77,6 +77,7 @@ #include #include #include +#include #endif @@ -163,6 +164,8 @@ namespace modsecurity { */ NUMBER_OF_PHASES, }; + + } // namespace modsecurity #endif @@ -198,17 +201,77 @@ namespace modsecurity { #define MODSECURITY_VERSION_NUM MODSECURITY_MAJOR \ MODSECURITY_MINOR MODSECURITY_PATCHLEVEL MODSECURITY_TAG_NUM -typedef void (*LogCb) (void *, const char *); + +/* + * @name ModSecLogCb + * @brief Callback to be function on every log generation + * + * + * The callback is going to be called on every log request. + * + * + * void * Internal reference to be used by the API consumer. Whatever + * is set here will be passed on every call. + * void * Pointer to a const char * or RuleMessage class. The returned + * data is selected on the log register property. + * + * @note Vide LogProperty enum to learn more about Log Properties. + * + */ +typedef void (*ModSecLogCb) (void *, const void *); + #ifdef __cplusplus namespace modsecurity { + /* few forwarded declarations */ namespace actions { class Action; } class Rule; +#ifdef __cplusplus +extern "C" { +#endif + /** + * + * Properties used to configure the general log callback. + * + */ + enum LogProperty { + /** + * + * Original ModSecurity text log entry. The same entry that can be found + * within the Apache error_log (in the 2.x family) + * + */ + TextLogProperty = 1, + /** + * + * Instead of return the text log entry an instance of the class + * RuleMessages is returned. + * + */ + RuleMessageLogProperty = 2, + /** + * This property only makes sense with the utilization of the + * RuleMessageLogProperty. Without this property set the RuleMessage + * structure will not be filled with the information of the hightlight. + * + * Notice that the highlight can be calculate post-analisys. Calculate it + * during the analisys may delay the analisys process. + * + */ + IncludeFullHighlightLogProperty = 4, + }; + + +#ifdef __cplusplus +} +#endif + + /** @ingroup ModSecurity_CPP_API */ class ModSecurity { public: @@ -217,8 +280,17 @@ class ModSecurity { static const std::string whoAmI(); void setConnectorInformation(std::string connector); - void setServerLogCb(LogCb cb); - void serverLog(void *data, const std::string& msg); + void setServerLogCb(ModSecLogCb cb); + /** + * + * properties Properties to inform ModSecurity what kind of infornation + * is expected be returned. + * + */ + void setServerLogCb(ModSecLogCb cb, int properties); + + void serverLog(void *data, std::shared_ptr rm); + const std::string& getConnectorInformation(); int processContentOffset(const char *content, size_t len, @@ -232,7 +304,8 @@ class ModSecurity { private: std::string m_connector; - LogCb m_logCb; + ModSecLogCb m_logCb; + int m_logProperties; }; @@ -249,7 +322,7 @@ const char *msc_who_am_i(ModSecurity *msc); /** @ingroup ModSecurity_C_API */ void msc_set_connector_info(ModSecurity *msc, const char *connector); /** @ingroup ModSecurity_C_API */ -void msc_set_log_cb(ModSecurity *msc, LogCb cb); +void msc_set_log_cb(ModSecurity *msc, ModSecLogCb cb); /** @ingroup ModSecurity_C_API */ void msc_cleanup(ModSecurity *msc); diff --git a/headers/modsecurity/rule.h b/headers/modsecurity/rule.h index c4c53269..38476817 100644 --- a/headers/modsecurity/rule.h +++ b/headers/modsecurity/rule.h @@ -52,21 +52,21 @@ class Rule { explicit Rule(std::string marker); ~Rule(); - bool evaluate(Transaction *transaction); + bool evaluate(Transaction *transaction, std::shared_ptr rm); bool evaluateActions(Transaction *transaction); std::vector> getFinalVars(Transaction *trasn); void executeActionsAfterFullMatch(Transaction *trasn, - bool containsDisruptive, RuleMessage *ruleMessage); + bool containsDisruptive, std::shared_ptr ruleMessage); std::list, std::shared_ptr>> executeDefaultTransformations( Transaction *trasn, const std::string &value, bool multiMatch); bool executeOperatorAt(Transaction *trasn, std::string key, - std::string value, RuleMessage *rm); + std::string value, std::shared_ptr rm); void executeActionsIndependentOfChainedRuleResult(Transaction *trasn, - bool *b, RuleMessage *ruleMessage); + bool *b, std::shared_ptr ruleMessage); std::string resolveMatchMessage(std::string key, std::string value); void updateMatchedVars(Transaction *trasn, std::string key, std::string value); diff --git a/headers/modsecurity/rule_message.h b/headers/modsecurity/rule_message.h index 6d6c5485..450534d7 100644 --- a/headers/modsecurity/rule_message.h +++ b/headers/modsecurity/rule_message.h @@ -34,47 +34,76 @@ namespace modsecurity { class RuleMessage { public: - explicit RuleMessage(Rule *rule) : - m_ruleFile(rule->m_fileName), - m_ruleLine(rule->m_lineNumber), - m_ruleId(rule->m_ruleId), - m_rev(rule->m_rev), + explicit RuleMessage(Rule *rule, Transaction *trans) : m_accuracy(rule->m_accuracy), - m_message(std::string("")), - m_data(std::string("")), - m_severity(0), - m_ver(rule->m_ver), + m_clientIpAddress(trans->m_clientIpAddress), + m_data(""), + m_disruptiveMessage(""), + m_id(trans->m_id), + m_isDisruptive(false), + m_match(""), m_maturity(rule->m_maturity), - m_rule(rule), - m_saveMessage(false), + m_message(""), m_noAuditLog(false), - m_match(std::string("")) + m_phase(rule->m_phase - 1), + m_reference(""), + m_rev(rule->m_rev), + m_rule(rule), + m_ruleFile(rule->m_fileName), + m_ruleId(rule->m_ruleId), + m_ruleLine(rule->m_lineNumber), + m_saveMessage(false), + m_serverIpAddress(trans->m_serverIpAddress), + m_severity(0), + m_uriNoQueryStringDecoded(trans->m_uri_no_query_string_decoded), + m_ver(rule->m_ver) { } - std::string errorLog(Transaction *trans); - std::string disruptiveErrorLog(Transaction *trans, std::string log2); - std::string noClientErrorLog(Transaction *trans); - std::string errorLogTail(Transaction *trans); + std::string errorLog() { + return RuleMessage::errorLog(this); + } + std::string disruptiveErrorLog() { + return RuleMessage::disruptiveErrorLog(this); + } + std::string noClientErrorLog() { + return RuleMessage::noClientErrorLog(this); + } + std::string errorLogTail() { + return RuleMessage::errorLogTail(this); + } + std::string log() { + return RuleMessage::log(this); + } + static std::string disruptiveErrorLog(const RuleMessage *rm); + static std::string noClientErrorLog(const RuleMessage *rm); + static std::string errorLogTail(const RuleMessage *rm); + static std::string errorLog(const RuleMessage *rm); + static std::string log(const RuleMessage *rm); - std::string m_match; - std::string m_ruleFile; - int m_ruleLine; - int m_ruleId; - std::string m_message; - std::string m_data; - int m_severity; - std::string m_ver; - std::string m_rev; - int m_maturity; int m_accuracy; + std::string m_clientIpAddress; + std::string m_data; + std::string m_disruptiveMessage; + std::string m_id; + bool m_isDisruptive; + std::string m_match; + int m_maturity; + std::string m_message; + bool m_noAuditLog; + int m_phase; std::string m_reference; + std::string m_rev; + Rule *m_rule; + std::string m_ruleFile; + int m_ruleId; + int m_ruleLine; + bool m_saveMessage; + std::string m_serverIpAddress; + int m_severity; + std::string m_uriNoQueryStringDecoded; + std::string m_ver; std::list m_tags; - std::list m_server_logs; - - bool m_noAuditLog; - Rule *m_rule; - bool m_saveMessage; }; diff --git a/headers/modsecurity/transaction.h b/headers/modsecurity/transaction.h index 68f1337a..5043fa63 100644 --- a/headers/modsecurity/transaction.h +++ b/headers/modsecurity/transaction.h @@ -323,7 +323,7 @@ class Transaction : public TransactionAnchoredVariables { #ifndef NO_LOGS void debug(int, std::string); #endif - void serverLog(const std::string& msg); + void serverLog(std::shared_ptr rm); std::string toJSON(int parts); std::string toOldAuditLogFormat(int parts, const std::string &trailer); diff --git a/src/actions/audit_log.cc b/src/actions/audit_log.cc index 2c46c832..02afe9cb 100644 --- a/src/actions/audit_log.cc +++ b/src/actions/audit_log.cc @@ -17,6 +17,7 @@ #include #include +#include #include "modsecurity/transaction.h" #include "modsecurity/rule_message.h" @@ -26,7 +27,7 @@ namespace actions { bool AuditLog::evaluate(Rule *rule, Transaction *transaction, - RuleMessage *rm) { + std::shared_ptr rm) { rm->m_noAuditLog = false; return true; } diff --git a/src/actions/audit_log.h b/src/actions/audit_log.h index 6dd0d676..f63198f0 100644 --- a/src/actions/audit_log.h +++ b/src/actions/audit_log.h @@ -14,6 +14,7 @@ */ #include +#include #include "modsecurity/actions/action.h" @@ -35,7 +36,7 @@ class AuditLog : public Action { : Action(action, RunTimeOnlyIfMatchKind) { } bool evaluate(Rule *rule, Transaction *transaction, - RuleMessage *rm) override; + std::shared_ptr rm) override; }; diff --git a/src/actions/data/status.cc b/src/actions/data/status.cc index 3621f8b8..65764c38 100644 --- a/src/actions/data/status.cc +++ b/src/actions/data/status.cc @@ -17,6 +17,7 @@ #include #include +#include #include "modsecurity/transaction.h" @@ -37,7 +38,8 @@ bool Status::init(std::string *error) { } -bool Status::evaluate(Rule *rule, Transaction *transaction, RuleMessage *rm) { +bool Status::evaluate(Rule *rule, Transaction *transaction, + std::shared_ptr rm) { transaction->m_it.status = m_status; return true; } diff --git a/src/actions/data/status.h b/src/actions/data/status.h index 556212c2..8a0232fd 100644 --- a/src/actions/data/status.h +++ b/src/actions/data/status.h @@ -14,6 +14,7 @@ */ #include +#include #include "modsecurity/actions/action.h" #include "modsecurity/rule_message.h" @@ -36,8 +37,8 @@ class Status : public Action { m_status(0) { } bool init(std::string *error) override; - bool evaluate(Rule *rule, Transaction *transaction, RuleMessage *rm) - override; + bool evaluate(Rule *rule, Transaction *transaction, + std::shared_ptr rm) override; int m_status; }; diff --git a/src/actions/disruptive/block.cc b/src/actions/disruptive/block.cc index 49939260..632f5cee 100644 --- a/src/actions/disruptive/block.cc +++ b/src/actions/disruptive/block.cc @@ -17,6 +17,7 @@ #include #include +#include #include "modsecurity/transaction.h" #include "modsecurity/rule.h" @@ -29,7 +30,8 @@ namespace actions { namespace disruptive { -bool Block::evaluate(Rule *rule, Transaction *transaction, RuleMessage *rm) { +bool Block::evaluate(Rule *rule, Transaction *transaction, + std::shared_ptr rm) { transaction->debug(8, "Marking request as disruptive."); for (Action *a : transaction->m_rules->m_defaultActions[rule->m_phase]) { diff --git a/src/actions/disruptive/block.h b/src/actions/disruptive/block.h index 44359a10..f26ffbec 100644 --- a/src/actions/disruptive/block.h +++ b/src/actions/disruptive/block.h @@ -14,6 +14,7 @@ */ #include +#include #include "modsecurity/actions/action.h" #include "modsecurity/rule_message.h" @@ -36,7 +37,7 @@ class Block : public Action { explicit Block(std::string action) : Action(action) { } bool evaluate(Rule *rule, Transaction *transaction, - RuleMessage *rm) override; + std::shared_ptr rm) override; bool isDisruptive() override { return true; } }; diff --git a/src/actions/disruptive/deny.cc b/src/actions/disruptive/deny.cc index 1aee87c7..8d845696 100644 --- a/src/actions/disruptive/deny.cc +++ b/src/actions/disruptive/deny.cc @@ -19,6 +19,7 @@ #include #include #include +#include #include "modsecurity/transaction.h" @@ -27,7 +28,8 @@ namespace actions { namespace disruptive { -bool Deny::evaluate(Rule *rule, Transaction *transaction, RuleMessage *rm) { +bool Deny::evaluate(Rule *rule, Transaction *transaction, + std::shared_ptr rm) { #ifndef NO_LOGS transaction->debug(8, "Running action deny"); #endif @@ -41,11 +43,13 @@ bool Deny::evaluate(Rule *rule, Transaction *transaction, RuleMessage *rm) { log.append(" (phase "); log.append(std::to_string(rm->m_rule->m_phase - 1) + "). "); + rm->m_disruptiveMessage.assign(log); transaction->m_it.disruptive = true; intervention::freeLog(&transaction->m_it); transaction->m_it.log = strdup( - rm->disruptiveErrorLog(transaction, log).c_str()); + rm->disruptiveErrorLog().c_str()); + rm->m_isDisruptive = true; return true; } diff --git a/src/actions/disruptive/deny.h b/src/actions/disruptive/deny.h index 6b64f93b..6f3bad64 100644 --- a/src/actions/disruptive/deny.h +++ b/src/actions/disruptive/deny.h @@ -14,6 +14,7 @@ */ #include +#include #include "modsecurity/actions/action.h" #include "modsecurity/transaction.h" @@ -32,7 +33,7 @@ class Deny : public Action { explicit Deny(std::string action) : Action(action) { } bool evaluate(Rule *rule, Transaction *transaction, - RuleMessage *rm) override; + std::shared_ptr rm) override; bool isDisruptive() override { return true; } }; diff --git a/src/actions/disruptive/pass.cc b/src/actions/disruptive/pass.cc index b4638272..d10b9b1a 100644 --- a/src/actions/disruptive/pass.cc +++ b/src/actions/disruptive/pass.cc @@ -17,6 +17,7 @@ #include #include +#include #include "modsecurity/transaction.h" #include "modsecurity/rule.h" @@ -27,7 +28,8 @@ namespace actions { namespace disruptive { -bool Pass::evaluate(Rule *rule, Transaction *transaction, RuleMessage *rm) { +bool Pass::evaluate(Rule *rule, Transaction *transaction, + std::shared_ptr rm) { intervention::free(&transaction->m_it); intervention::reset(&transaction->m_it); diff --git a/src/actions/disruptive/pass.h b/src/actions/disruptive/pass.h index 172d1aef..50f8fd53 100644 --- a/src/actions/disruptive/pass.h +++ b/src/actions/disruptive/pass.h @@ -14,6 +14,7 @@ */ #include +#include #include "modsecurity/actions/action.h" #include "modsecurity/transaction.h" @@ -30,8 +31,8 @@ class Pass : public Action { public: explicit Pass(std::string action) : Action(action) { } - bool evaluate(Rule *rule, Transaction *transaction, RuleMessage *rm) - override; + bool evaluate(Rule *rule, Transaction *transaction, + std::shared_ptr rm) override; bool isDisruptive() override { return true; } }; diff --git a/src/actions/disruptive/redirect.cc b/src/actions/disruptive/redirect.cc index a138fdf1..323fab08 100644 --- a/src/actions/disruptive/redirect.cc +++ b/src/actions/disruptive/redirect.cc @@ -18,7 +18,7 @@ #include #include #include - +#include #include "modsecurity/transaction.h" #include "src/macro_expansion.h" @@ -36,7 +36,7 @@ bool Redirect::init(std::string *error) { bool Redirect::evaluate(Rule *rule, Transaction *transaction, - RuleMessage *rm) { + std::shared_ptr rm) { m_urlExpanded = MacroExpansion::expand(m_url, transaction); std::string log; @@ -48,13 +48,15 @@ bool Redirect::evaluate(Rule *rule, Transaction *transaction, log.append(" (phase "); log.append(std::to_string(rm->m_rule->m_phase - 1) + "). "); + rm->m_disruptiveMessage.assign(log); intervention::freeUrl(&transaction->m_it); transaction->m_it.url = strdup(m_urlExpanded.c_str()); transaction->m_it.disruptive = true; intervention::freeLog(&transaction->m_it); transaction->m_it.log = strdup( - rm->disruptiveErrorLog(transaction, log).c_str()); + rm->disruptiveErrorLog().c_str()); + rm->m_isDisruptive = true; return true; } diff --git a/src/actions/disruptive/redirect.h b/src/actions/disruptive/redirect.h index 3773593b..df1c8d65 100644 --- a/src/actions/disruptive/redirect.h +++ b/src/actions/disruptive/redirect.h @@ -14,6 +14,7 @@ */ #include +#include #include "modsecurity/actions/action.h" #include "modsecurity/rule_message.h" @@ -39,8 +40,8 @@ class Redirect : public Action { m_urlExpanded(""), m_url("") { } - bool evaluate(Rule *rule, Transaction *transaction, RuleMessage *rm) - override; + bool evaluate(Rule *rule, Transaction *transaction, + std::shared_ptr rm) override; bool init(std::string *error) override; bool isDisruptive() override { return true; } diff --git a/src/actions/log.cc b/src/actions/log.cc index 27ac247b..48f00ac5 100644 --- a/src/actions/log.cc +++ b/src/actions/log.cc @@ -17,6 +17,7 @@ #include #include +#include #include "modsecurity/actions/action.h" #include "modsecurity/transaction.h" @@ -27,7 +28,8 @@ namespace modsecurity { namespace actions { -bool Log::evaluate(Rule *rule, Transaction *transaction, RuleMessage *rm) { +bool Log::evaluate(Rule *rule, Transaction *transaction, + std::shared_ptr rm) { transaction->debug(9, "Saving transaction to logs"); rm->m_saveMessage = true; return true; diff --git a/src/actions/log.h b/src/actions/log.h index d97f9d2f..1d7262f0 100644 --- a/src/actions/log.h +++ b/src/actions/log.h @@ -14,6 +14,7 @@ */ #include +#include #include "modsecurity/actions/action.h" @@ -32,8 +33,8 @@ class Log : public Action { explicit Log(std::string action) : Action(action, RunTimeOnlyIfMatchKind) { } - bool evaluate(Rule *rule, Transaction *transaction, RuleMessage *rm) - override; + bool evaluate(Rule *rule, Transaction *transaction, + std::shared_ptr rm) override; }; } // namespace actions diff --git a/src/actions/log_data.cc b/src/actions/log_data.cc index 19e2fe49..9c02046d 100644 --- a/src/actions/log_data.cc +++ b/src/actions/log_data.cc @@ -17,6 +17,7 @@ #include #include +#include #include "modsecurity/actions/action.h" #include "modsecurity/transaction.h" @@ -29,7 +30,8 @@ namespace modsecurity { namespace actions { -bool LogData::evaluate(Rule *rule, Transaction *transaction, RuleMessage *rm) { +bool LogData::evaluate(Rule *rule, Transaction *transaction, + std::shared_ptr rm) { rm->m_data = data(transaction); transaction->m_collections.storeOrUpdateFirst("RULE:logdata", rm->m_data); diff --git a/src/actions/log_data.h b/src/actions/log_data.h index a30002bb..8b608733 100644 --- a/src/actions/log_data.h +++ b/src/actions/log_data.h @@ -14,6 +14,7 @@ */ #include +#include #include "modsecurity/actions/action.h" @@ -33,7 +34,7 @@ class LogData : public Action { : Action(action, RunTimeOnlyIfMatchKind) { } bool evaluate(Rule *rule, Transaction *transaction, - RuleMessage *rm) override; + std::shared_ptr rm) override; std::string data(Transaction *Transaction); }; diff --git a/src/actions/msg.cc b/src/actions/msg.cc index 0da24a8d..938f7a55 100644 --- a/src/actions/msg.cc +++ b/src/actions/msg.cc @@ -17,6 +17,7 @@ #include #include +#include #include "modsecurity/actions/action.h" #include "modsecurity/transaction.h" @@ -46,14 +47,14 @@ namespace modsecurity { namespace actions { -bool Msg::evaluate(Rule *rule, Transaction *transaction, RuleMessage *rm) { +bool Msg::evaluate(Rule *rule, Transaction *transaction, + std::shared_ptr rm) { std::string msg = data(transaction); rm->m_message = msg; transaction->debug(9, "Saving msg: " + msg); transaction->m_collections.storeOrUpdateFirst("RULE:msg", msg); - rm->m_server_logs.push_back(rm->errorLog(transaction)); return true; } diff --git a/src/actions/msg.h b/src/actions/msg.h index 20d65f1d..faa3d181 100644 --- a/src/actions/msg.h +++ b/src/actions/msg.h @@ -14,6 +14,7 @@ */ #include +#include #include "modsecurity/actions/action.h" #include "modsecurity/rule_message.h" @@ -33,8 +34,8 @@ class Msg : public Action { explicit Msg(std::string action) : Action(action, RunTimeOnlyIfMatchKind) { } - bool evaluate(Rule *rule, Transaction *transaction, RuleMessage *rm) - override; + bool evaluate(Rule *rule, Transaction *transaction, + std::shared_ptr rm) override; std::string data(Transaction *Transaction); }; diff --git a/src/actions/no_audit_log.cc b/src/actions/no_audit_log.cc index 2f27c638..1a729204 100644 --- a/src/actions/no_audit_log.cc +++ b/src/actions/no_audit_log.cc @@ -27,7 +27,7 @@ namespace actions { bool NoAuditLog::evaluate(Rule *rule, Transaction *transaction, - RuleMessage *rm) { + std::shared_ptr rm) { rm->m_noAuditLog = true; return true; } diff --git a/src/actions/no_audit_log.h b/src/actions/no_audit_log.h index 1ec3362d..d0543a9f 100644 --- a/src/actions/no_audit_log.h +++ b/src/actions/no_audit_log.h @@ -14,6 +14,7 @@ */ #include +#include #include "modsecurity/actions/action.h" @@ -35,7 +36,7 @@ class NoAuditLog : public Action { : Action(action, RunTimeOnlyIfMatchKind) { } bool evaluate(Rule *rule, Transaction *transaction, - RuleMessage *rm) override; + std::shared_ptr rm) override; }; } // namespace actions diff --git a/src/actions/no_log.cc b/src/actions/no_log.cc index 576f8b60..8d0a71a5 100644 --- a/src/actions/no_log.cc +++ b/src/actions/no_log.cc @@ -17,6 +17,7 @@ #include #include +#include #include "modsecurity/actions/action.h" #include "modsecurity/transaction.h" @@ -28,7 +29,8 @@ namespace modsecurity { namespace actions { -bool NoLog::evaluate(Rule *rule, Transaction *transaction, RuleMessage *rm) { +bool NoLog::evaluate(Rule *rule, Transaction *transaction, + std::shared_ptr rm) { rm->m_saveMessage = false; return true; } diff --git a/src/actions/no_log.h b/src/actions/no_log.h index 2ebcf586..9d4878be 100644 --- a/src/actions/no_log.h +++ b/src/actions/no_log.h @@ -14,6 +14,7 @@ */ #include +#include #include "modsecurity/actions/action.h" @@ -32,8 +33,8 @@ class NoLog : public Action { explicit NoLog(std::string action) : Action(action, RunTimeOnlyIfMatchKind) { } - bool evaluate(Rule *rule, Transaction *transaction, RuleMessage *rm) - override; + bool evaluate(Rule *rule, Transaction *transaction, + std::shared_ptr rm) override; }; } // namespace actions diff --git a/src/actions/severity.cc b/src/actions/severity.cc index 3b9af4d5..4192227b 100644 --- a/src/actions/severity.cc +++ b/src/actions/severity.cc @@ -17,6 +17,7 @@ #include #include +#include #include "modsecurity/actions/action.h" #include "modsecurity/transaction.h" @@ -70,7 +71,7 @@ bool Severity::init(std::string *error) { bool Severity::evaluate(Rule *rule, Transaction *transaction, - RuleMessage *rm) { + std::shared_ptr rm) { #ifndef NO_LOGS transaction->debug(9, "This rule severity is: " + \ std::to_string(this->m_severity) + " current transaction is: " + \ diff --git a/src/actions/severity.h b/src/actions/severity.h index 0fe1ac1d..e67633d6 100644 --- a/src/actions/severity.h +++ b/src/actions/severity.h @@ -14,6 +14,7 @@ */ #include +#include #include "modsecurity/actions/action.h" @@ -35,7 +36,7 @@ class Severity : public Action { m_severity(0) { } bool evaluate(Rule *rule, Transaction *transaction, - RuleMessage *rm) override; + std::shared_ptr rm) override; bool init(std::string *error) override; int m_severity; diff --git a/src/actions/tag.cc b/src/actions/tag.cc index 4db832a8..30076df2 100644 --- a/src/actions/tag.cc +++ b/src/actions/tag.cc @@ -17,6 +17,7 @@ #include #include +#include #include "modsecurity/actions/action.h" #include "modsecurity/transaction.h" @@ -56,7 +57,8 @@ std::string Tag::getName(Transaction *transaction) { } -bool Tag::evaluate(Rule *rule, Transaction *transaction, RuleMessage *rm) { +bool Tag::evaluate(Rule *rule, Transaction *transaction, + std::shared_ptr rm) { std::string tag = getName(transaction); #ifndef NO_LOGS diff --git a/src/actions/tag.h b/src/actions/tag.h index a32fbfc4..204cde46 100644 --- a/src/actions/tag.h +++ b/src/actions/tag.h @@ -14,6 +14,7 @@ */ #include +#include #include "modsecurity/actions/action.h" @@ -35,7 +36,7 @@ class Tag : public Action { std::string getName(Transaction *transaction); bool evaluate(Rule *rule, Transaction *transaction, - RuleMessage *rm) override; + std::shared_ptr rm) override; }; diff --git a/src/actions/transformations/transformation.h b/src/actions/transformations/transformation.h index c6a7d1b0..8741cf7e 100644 --- a/src/actions/transformations/transformation.h +++ b/src/actions/transformations/transformation.h @@ -39,7 +39,6 @@ class Transformation : public Action { Transaction *transaction) override; static Transformation* instantiate(std::string a); - }; } // namespace transformations diff --git a/src/modsecurity.cc b/src/modsecurity.cc index e4b2ba6d..d18a5d04 100644 --- a/src/modsecurity.cc +++ b/src/modsecurity.cc @@ -18,6 +18,7 @@ #include "modsecurity/modsecurity.h" #include "modsecurity/rule.h" +#include "modsecurity/rule_message.h" #include "src/collection/backend/in_memory-per_process.h" #include "src/collection/backend/lmdb.h" #include "src/config.h" @@ -166,12 +167,33 @@ const std::string& ModSecurity::getConnectorInformation() { return m_connector; } - -void ModSecurity::serverLog(void *data, const std::string& msg) { +void ModSecurity::serverLog(void *data, std::shared_ptr rm) { if (m_logCb == NULL) { - std::cout << "Server log callback is not set -- " << msg << std::endl; - } else { - m_logCb(data, msg.c_str()); + std::cerr << "Server log callback is not set -- " << rm->errorLog(); + std::cerr << std::endl; + return; + } + + if (rm == NULL) { + return; + } + + if (m_logProperties & TextLogProperty) { + char *d = strdup(rm->log().c_str()); + const void *a = static_cast(d); + m_logCb(data, a); + free(d); + return; + } + + if (m_logProperties & RuleMessageLogProperty) { + const void *a = static_cast(rm.get()); + if (m_logProperties & IncludeFullHighlightLogProperty) { + m_logCb(data, a); + return; + } + m_logCb(data, a); + return; } } @@ -355,8 +377,14 @@ int ModSecurity::processContentOffset(const char *content, size_t len, } -void ModSecurity::setServerLogCb(LogCb cb) { - m_logCb = (LogCb) cb; +void ModSecurity::setServerLogCb(ModSecLogCb cb) { + setServerLogCb(cb, TextLogProperty); +} + + +void ModSecurity::setServerLogCb(ModSecLogCb cb, int properties) { + m_logCb = (ModSecLogCb) cb; + m_logProperties = properties; } /** @@ -367,11 +395,11 @@ void ModSecurity::setServerLogCb(LogCb cb) { * connector should be called when logging is required. * * @oarm msc The current ModSecurity instance - * @param LogCB The callback function to which a reference to the log msgs + * @param ModSecLogCb The callback function to which a reference to the log msgs * will be passed. * */ -extern "C" void msc_set_log_cb(ModSecurity *msc, LogCb cb) { +extern "C" void msc_set_log_cb(ModSecurity *msc, ModSecLogCb cb) { msc->setServerLogCb(cb); } diff --git a/src/operators/begins_with.cc b/src/operators/begins_with.cc index 396a9fc0..0e068aaf 100644 --- a/src/operators/begins_with.cc +++ b/src/operators/begins_with.cc @@ -25,7 +25,7 @@ namespace operators { bool BeginsWith::evaluate(Transaction *transaction, Rule *rule, - const std::string &str, RuleMessage *ruleMessage) { + const std::string &str, std::shared_ptr ruleMessage) { bool ret = false; std::string p = MacroExpansion::expand(m_param, transaction); diff --git a/src/operators/begins_with.h b/src/operators/begins_with.h index 1b2bb206..73790372 100644 --- a/src/operators/begins_with.h +++ b/src/operators/begins_with.h @@ -17,6 +17,7 @@ #define SRC_OPERATORS_BEGINS_WITH_H_ #include +#include #include "src/operators/operator.h" @@ -33,7 +34,7 @@ class BeginsWith : public Operator { : Operator("BeginsWith", param) { } bool evaluate(Transaction *transaction, Rule *rule, const std::string &str, - RuleMessage *ruleMessage) override; + std::shared_ptr ruleMessage) override; }; } // namespace operators diff --git a/src/operators/contains.cc b/src/operators/contains.cc index f5e8ff42..99d4fddd 100644 --- a/src/operators/contains.cc +++ b/src/operators/contains.cc @@ -23,7 +23,7 @@ namespace modsecurity { namespace operators { bool Contains::evaluate(Transaction *transaction, Rule *rule, - const std::string &input, RuleMessage *ruleMessage) { + const std::string &input, std::shared_ptr ruleMessage) { std::string p = MacroExpansion::expand(m_param, transaction); size_t offset = input.find(p); diff --git a/src/operators/contains.h b/src/operators/contains.h index 1e4d46a5..e30f309d 100644 --- a/src/operators/contains.h +++ b/src/operators/contains.h @@ -18,6 +18,7 @@ #include #include +#include #include "modsecurity/transaction.h" #include "modsecurity/rule_message.h" @@ -35,7 +36,8 @@ class Contains : public Operator { explicit Contains(std::string param) : Operator("Contains", param) { } bool evaluate(Transaction *transaction, Rule *rule, - const std::string &str, RuleMessage *ruleMessage) override; + const std::string &str, + std::shared_ptr ruleMessage) override; }; } // namespace operators diff --git a/src/operators/contains_word.cc b/src/operators/contains_word.cc index c06b8e64..18474034 100644 --- a/src/operators/contains_word.cc +++ b/src/operators/contains_word.cc @@ -38,7 +38,7 @@ bool ContainsWord::acceptableChar(const std::string& a, size_t pos) { } bool ContainsWord::evaluate(Transaction *transaction, Rule *rule, - const std::string &input, RuleMessage *ruleMessage) { + const std::string &input, std::shared_ptr ruleMessage) { std::string paramTarget = MacroExpansion::expand(m_param, transaction); if (paramTarget.empty()) { diff --git a/src/operators/contains_word.h b/src/operators/contains_word.h index 7d71aa8a..f4a8a6e1 100644 --- a/src/operators/contains_word.h +++ b/src/operators/contains_word.h @@ -17,6 +17,7 @@ #define SRC_OPERATORS_CONTAINS_WORD_H_ #include +#include #include "src/operators/operator.h" #include "modsecurity/rule_message.h" @@ -32,7 +33,8 @@ class ContainsWord : public Operator { explicit ContainsWord(std::string param) : Operator("ContainsWord", param) { } bool evaluate(Transaction *transaction, Rule *rule, - const std::string &str, RuleMessage *ruleMessage) override; + const std::string &str, + std::shared_ptr ruleMessage) override; bool acceptableChar(const std::string& a, size_t pos); }; diff --git a/src/operators/ends_with.cc b/src/operators/ends_with.cc index 3aa8a9d7..144ec4df 100644 --- a/src/operators/ends_with.cc +++ b/src/operators/ends_with.cc @@ -25,7 +25,7 @@ namespace operators { bool EndsWith::evaluate(Transaction *transaction, Rule *rule, - const std::string &input, RuleMessage *ruleMessage) { + const std::string &input, std::shared_ptr ruleMessage) { bool ret = false; std::string p = MacroExpansion::expand(m_param, transaction); diff --git a/src/operators/ends_with.h b/src/operators/ends_with.h index 37294d68..ab79b848 100644 --- a/src/operators/ends_with.h +++ b/src/operators/ends_with.h @@ -17,6 +17,7 @@ #define SRC_OPERATORS_ENDS_WITH_H_ #include +#include #include "src/operators/operator.h" @@ -32,7 +33,8 @@ class EndsWith : public Operator { explicit EndsWith(std::string param) : Operator("EndsWith", param) { } bool evaluate(Transaction *transaction, Rule *rule, - const std::string &str, RuleMessage *ruleMessage) override; + const std::string &str, + std::shared_ptr ruleMessage) override; }; diff --git a/src/operators/operator.cc b/src/operators/operator.cc index 5d952067..0c9966e3 100644 --- a/src/operators/operator.cc +++ b/src/operators/operator.cc @@ -16,7 +16,7 @@ #include "src/operators/operator.h" #include - +#include #include #include "modsecurity/transaction.h" @@ -76,7 +76,7 @@ bool Operator::debug(Transaction *transaction, int x, std::string a) { } bool Operator::evaluateInternal(Transaction *transaction, - Rule *rule, const std::string& a, RuleMessage *rm) { + Rule *rule, const std::string& a, std::shared_ptr rm) { bool res = evaluate(transaction, rule, a, rm); if (m_negation) { diff --git a/src/operators/operator.h b/src/operators/operator.h index dac8c0c8..8658fcf0 100644 --- a/src/operators/operator.h +++ b/src/operators/operator.h @@ -14,6 +14,7 @@ */ #include +#include #ifndef SRC_OPERATORS_OPERATOR_H__ #define SRC_OPERATORS_OPERATOR_H__ @@ -63,7 +64,7 @@ class Operator { bool evaluateInternal(Transaction *t, Rule *rule, const std::string& a); bool evaluateInternal(Transaction *t, Rule *rule, - const std::string& a, RuleMessage *ruleMessage); + const std::string& a, std::shared_ptr ruleMessage); virtual bool evaluate(Transaction *transaction, const std::string &str); @@ -72,11 +73,12 @@ class Operator { return evaluate(transaction, str); } virtual bool evaluate(Transaction *transaction, Rule *rule, - const std::string &str, RuleMessage *ruleMessage) { + const std::string &str, std::shared_ptr ruleMessage) { return evaluate(transaction, str); } - static void logOffset(RuleMessage *ruleMessage, int offset, int len) { + static void logOffset(std::shared_ptr ruleMessage, + int offset, int len) { if (ruleMessage) { ruleMessage->m_reference.append("o" + std::to_string(offset) + "," diff --git a/src/operators/pm.cc b/src/operators/pm.cc index 4ef75477..08e89d98 100644 --- a/src/operators/pm.cc +++ b/src/operators/pm.cc @@ -23,6 +23,7 @@ #include #include #include +#include #include "src/operators/operator.h" #include "src/utils/acmp.h" @@ -79,7 +80,7 @@ void Pm::postOrderTraversal(acmp_btree_node_t *node) { bool Pm::evaluate(Transaction *transaction, Rule *rule, - const std::string &input, RuleMessage *ruleMessage) { + const std::string &input, std::shared_ptr ruleMessage) { int rc = 0; ACMPT pt; pt.parser = m_p; diff --git a/src/operators/pm.h b/src/operators/pm.h index 09439b3a..dbdd3aa5 100644 --- a/src/operators/pm.h +++ b/src/operators/pm.h @@ -18,6 +18,7 @@ #include #include +#include #include "src/operators/operator.h" #include "src/utils/acmp.h" @@ -44,7 +45,8 @@ class Pm : public Operator { } ~Pm(); bool evaluate(Transaction *transaction, Rule *rule, - const std::string &str, RuleMessage *ruleMessage) override; + const std::string &str, + std::shared_ptr ruleMessage) override; bool init(const std::string &file, std::string *error) override; diff --git a/src/operators/rx.cc b/src/operators/rx.cc index c7cb949a..9ed07cb9 100644 --- a/src/operators/rx.cc +++ b/src/operators/rx.cc @@ -17,6 +17,7 @@ #include #include +#include #include "src/operators/operator.h" #include "src/macro_expansion.h" @@ -29,7 +30,7 @@ namespace operators { bool Rx::evaluate(Transaction *transaction, Rule *rule, - const std::string& input, RuleMessage *ruleMessage) { + const std::string& input, std::shared_ptr ruleMessage) { SMatch match; std::list matches; diff --git a/src/operators/rx.h b/src/operators/rx.h index c19a242f..713aed22 100644 --- a/src/operators/rx.h +++ b/src/operators/rx.h @@ -18,6 +18,7 @@ #include #include +#include #include "src/operators/operator.h" #include "src/utils/regex.h" @@ -59,7 +60,8 @@ class Rx : public Operator { return evaluate(transaction, NULL, input); } bool evaluate(Transaction *transaction, Rule *rule, - const std::string& input, RuleMessage *ruleMessage) override; + const std::string& input, + std::shared_ptr ruleMessage) override; private: Regex *m_re; diff --git a/src/operators/validate_byte_range.cc b/src/operators/validate_byte_range.cc index a0c97871..8388081b 100644 --- a/src/operators/validate_byte_range.cc +++ b/src/operators/validate_byte_range.cc @@ -16,6 +16,7 @@ #include "src/operators/validate_byte_range.h" #include +#include #include "src/operators/operator.h" @@ -110,7 +111,7 @@ bool ValidateByteRange::init(const std::string &file, bool ValidateByteRange::evaluate(Transaction *transaction, Rule *rule, - const std::string &input, RuleMessage *ruleMessage) { + const std::string &input, std::shared_ptr ruleMessage) { bool ret = true; size_t count = 0; diff --git a/src/operators/validate_byte_range.h b/src/operators/validate_byte_range.h index a2039bc9..49f294bf 100644 --- a/src/operators/validate_byte_range.h +++ b/src/operators/validate_byte_range.h @@ -19,6 +19,7 @@ #include #include #include +#include #include "src/operators/operator.h" @@ -40,7 +41,8 @@ class ValidateByteRange : public Operator { ~ValidateByteRange() override { } bool evaluate(Transaction *transaction, Rule *rule, - const std::string &input, RuleMessage *ruleMessage) override; + const std::string &input, + std::shared_ptr ruleMessage) override; bool getRange(const std::string &rangeRepresentation, std::string *error); bool init(const std::string& file, std::string *error) override; private: diff --git a/src/operators/validate_url_encoding.cc b/src/operators/validate_url_encoding.cc index fe4ca1a6..ff8bc20c 100644 --- a/src/operators/validate_url_encoding.cc +++ b/src/operators/validate_url_encoding.cc @@ -69,7 +69,7 @@ int ValidateUrlEncoding::validate_url_encoding(const char *input, bool ValidateUrlEncoding::evaluate(Transaction *transaction, Rule *rule, - const std::string &input, RuleMessage *ruleMessage) { + const std::string &input, std::shared_ptr ruleMessage) { size_t offset = 0; bool res = false; diff --git a/src/operators/validate_url_encoding.h b/src/operators/validate_url_encoding.h index f9942c62..5d192f0a 100644 --- a/src/operators/validate_url_encoding.h +++ b/src/operators/validate_url_encoding.h @@ -17,6 +17,7 @@ #define SRC_OPERATORS_VALIDATE_URL_ENCODING_H_ #include +#include #include "src/operators/operator.h" @@ -33,7 +34,8 @@ class ValidateUrlEncoding : public Operator { : Operator("ValidateUrlEncoding") { } bool evaluate(Transaction *transaction, Rule *rule, - const std::string &input, RuleMessage *ruleMessage) override; + const std::string &input, + std::shared_ptr ruleMessage) override; int validate_url_encoding(const char *input, uint64_t input_length, size_t *offset); }; diff --git a/src/operators/validate_utf8_encoding.cc b/src/operators/validate_utf8_encoding.cc index e2100e41..c3b7896a 100644 --- a/src/operators/validate_utf8_encoding.cc +++ b/src/operators/validate_utf8_encoding.cc @@ -114,7 +114,7 @@ int ValidateUtf8Encoding::detect_utf8_character( } bool ValidateUtf8Encoding::evaluate(Transaction *transaction, Rule *rule, - const std::string &str, RuleMessage *ruleMessage) { + const std::string &str, std::shared_ptr ruleMessage) { unsigned int i, bytes_left; const char *str_c = str.c_str(); diff --git a/src/operators/validate_utf8_encoding.h b/src/operators/validate_utf8_encoding.h index c40d94e0..937bfda6 100644 --- a/src/operators/validate_utf8_encoding.h +++ b/src/operators/validate_utf8_encoding.h @@ -17,6 +17,7 @@ #define SRC_OPERATORS_VALIDATE_UTF8_ENCODING_H_ #include +#include #include "src/operators/operator.h" @@ -40,7 +41,8 @@ class ValidateUtf8Encoding : public Operator { : Operator("ValidateUtf8Encoding") { } bool evaluate(Transaction *transaction, Rule *rule, - const std::string &str, RuleMessage *ruleMessage) override; + const std::string &str, + std::shared_ptr ruleMessage) override; int detect_utf8_character(const unsigned char *p_read, unsigned int length); diff --git a/src/operators/within.cc b/src/operators/within.cc index 83eea973..69a5f6f3 100644 --- a/src/operators/within.cc +++ b/src/operators/within.cc @@ -25,7 +25,7 @@ namespace operators { bool Within::evaluate(Transaction *transaction, Rule *rule, - const std::string &str, RuleMessage *ruleMessage) { + const std::string &str, std::shared_ptr ruleMessage) { bool res = false; std::string paramTarget = MacroExpansion::expand(m_param, transaction); size_t pos = 0; diff --git a/src/operators/within.h b/src/operators/within.h index 9940b0fe..bfe58c49 100644 --- a/src/operators/within.h +++ b/src/operators/within.h @@ -17,6 +17,7 @@ #define SRC_OPERATORS_WITHIN_H_ #include +#include #include "src/operators/operator.h" @@ -32,7 +33,7 @@ class Within : public Operator { explicit Within(std::string param) : Operator("Within", param) { } bool evaluate(Transaction *transaction, Rule *rule, - const std::string &str, RuleMessage *ruleMessage); + const std::string &str, std::shared_ptr ruleMessage); }; } // namespace operators diff --git a/src/rule.cc b/src/rule.cc index 106341e2..198ceeab 100644 --- a/src/rule.cc +++ b/src/rule.cc @@ -242,7 +242,7 @@ std::string Rule::resolveMatchMessage(std::string key, std::string value) { utils::string::limitTo(200, this->m_op->m_param) + "' against variable `" + key + "' (Value: `" + utils::string::limitTo(100, utils::string::toHexIfNeeded(value)) + - "' ) \" at " + key; + "' )"; } return ret; @@ -250,7 +250,7 @@ std::string Rule::resolveMatchMessage(std::string key, std::string value) { void Rule::executeActionsIndependentOfChainedRuleResult(Transaction *trans, - bool *containsDisruptive, RuleMessage *ruleMessage) { + bool *containsDisruptive, std::shared_ptr ruleMessage) { for (Action *a : this->m_actionsRuntimePos) { if (a->isDisruptive() == true) { if (a->m_name == "pass") { @@ -272,7 +272,7 @@ void Rule::executeActionsIndependentOfChainedRuleResult(Transaction *trans, bool Rule::executeOperatorAt(Transaction *trans, std::string key, - std::string value, RuleMessage *ruleMessage) { + std::string value, std::shared_ptr ruleMessage) { #if MSC_EXEC_CLOCK_ENABLED clock_t begin = clock(); clock_t end; @@ -524,7 +524,7 @@ std::vector> Rule::getFinalVars( void Rule::executeActionsAfterFullMatch(Transaction *trans, - bool containsDisruptive, RuleMessage *ruleMessage) { + bool containsDisruptive, std::shared_ptr ruleMessage) { for (Action *a : trans->m_rules->m_defaultActions[this->m_phase]) { if (a->action_kind != actions::Action::RunTimeOnlyIfMatchKind) { @@ -581,15 +581,20 @@ void Rule::executeActionsAfterFullMatch(Transaction *trans, } -bool Rule::evaluate(Transaction *trans) { +bool Rule::evaluate(Transaction *trans, + std::shared_ptr ruleMessage) { bool globalRet = false; std::vector *variables = this->m_variables; bool recursiveGlobalRet; bool containsDisruptive = false; - RuleMessage ruleMessage(this); std::vector> finalVars; std::string eparam; + if (ruleMessage == NULL) { + ruleMessage = std::shared_ptr( + new RuleMessage(this, trans)); + } + trans->m_matched.clear(); if (m_secMarker == true) { @@ -599,7 +604,7 @@ bool Rule::evaluate(Transaction *trans) { trans->debug(4, "(Rule: " + std::to_string(m_ruleId) \ + ") Executing unconditional rule..."); executeActionsIndependentOfChainedRuleResult(trans, - &containsDisruptive, &ruleMessage); + &containsDisruptive, ruleMessage); goto end_exec; } @@ -646,17 +651,17 @@ bool Rule::evaluate(Transaction *trans) { bool ret; std::string valueAfterTrans = std::move(*valueTemp.first); - ret = executeOperatorAt(trans, key, valueAfterTrans, &ruleMessage); + ret = executeOperatorAt(trans, key, valueAfterTrans, ruleMessage); if (ret == true) { - ruleMessage.m_match = resolveMatchMessage(key, value); + ruleMessage->m_match = resolveMatchMessage(key, value); for (auto &i : v->m_orign) { - ruleMessage.m_reference.append(i->toText()); + ruleMessage->m_reference.append(i->toText()); } - ruleMessage.m_reference.append(*valueTemp.second); + ruleMessage->m_reference.append(*valueTemp.second); updateMatchedVars(trans, key, value); executeActionsIndependentOfChainedRuleResult(trans, - &containsDisruptive, &ruleMessage); + &containsDisruptive, ruleMessage); globalRet = true; } } @@ -681,7 +686,7 @@ bool Rule::evaluate(Transaction *trans) { } trans->debug(4, "Executing chained rule."); - recursiveGlobalRet = this->m_chainedRule->evaluate(trans); + recursiveGlobalRet = this->m_chainedRule->evaluate(trans, ruleMessage); if (recursiveGlobalRet == true) { goto end_exec; @@ -691,13 +696,10 @@ end_clean: return false; end_exec: - executeActionsAfterFullMatch(trans, containsDisruptive, &ruleMessage); - for (const auto &u : ruleMessage.m_server_logs) { - trans->serverLog(u); - } - - if (ruleMessage.m_server_logs.size() > 0) { - trans->m_rulesMessages.push_back(ruleMessage); + executeActionsAfterFullMatch(trans, containsDisruptive, ruleMessage); + if (this->m_chained == false) { + trans->serverLog(ruleMessage); + trans->m_rulesMessages.push_back(*ruleMessage); } return true; diff --git a/src/rule_message.cc b/src/rule_message.cc index 0ead453d..8c1ae7bc 100644 --- a/src/rule_message.cc +++ b/src/rule_message.cc @@ -23,79 +23,90 @@ namespace modsecurity { -std::string RuleMessage::disruptiveErrorLog(Transaction *trans, - std::string msg2) { +std::string RuleMessage::disruptiveErrorLog(const RuleMessage *rm) { std::string msg; - msg.append("[client " + std::string(trans->m_clientIpAddress) + "]"); + msg.append("[client " + std::string(rm->m_clientIpAddress) + "]"); msg.append(" ModSecurity: "); - msg.append(msg2); - msg.append(m_match); - msg.append(" [file \"" + std::string(m_ruleFile) + "\"]"); - msg.append(" [line \"" + std::to_string(m_ruleLine) + "\"]"); - msg.append(" [id \"" + std::to_string(m_ruleId) + "\"]"); - msg.append(" [rev \"" + m_rev + "\"]"); - msg.append(" [msg \"" + m_message + "\"]"); - msg.append(" [data \"" + m_data + "\"]"); + msg.append(rm->m_disruptiveMessage); + msg.append(rm->m_match); + msg.append(" [file \"" + std::string(rm->m_ruleFile) + "\"]"); + msg.append(" [line \"" + std::to_string(rm->m_ruleLine) + "\"]"); + msg.append(" [id \"" + std::to_string(rm->m_ruleId) + "\"]"); + msg.append(" [rev \"" + rm->m_rev + "\"]"); + msg.append(" [msg \"" + rm->m_message + "\"]"); + msg.append(" [data \"" + rm->m_data + "\"]"); msg.append(" [severity \"" + - std::to_string(m_severity) + "\"]"); - msg.append(" [ver \"" + m_ver + "\"]"); - msg.append(" [maturity \"" + std::to_string(m_maturity) + "\"]"); - msg.append(" [accuracy \"" + std::to_string(m_accuracy) + "\"]"); - for (auto &a : m_tags) { + std::to_string(rm->m_severity) + "\"]"); + msg.append(" [ver \"" + rm->m_ver + "\"]"); + msg.append(" [maturity \"" + std::to_string(rm->m_maturity) + "\"]"); + msg.append(" [accuracy \"" + std::to_string(rm->m_accuracy) + "\"]"); + for (auto &a : rm->m_tags) { msg.append(" [tag \"" + a + "\"]"); } - msg.append(" [hostname \"" + std::string(trans->m_serverIpAddress) \ + msg.append(" [hostname \"" + std::string(rm->m_serverIpAddress) \ + "\"]"); - msg.append(" [uri \"" + trans->m_uri_no_query_string_decoded + "\"]"); - msg.append(" [unique_id \"" + trans->m_id + "\"]"); - msg.append(" [ref \"" + m_reference + "\"]"); + msg.append(" [uri \"" + rm->m_uriNoQueryStringDecoded + "\"]"); + msg.append(" [unique_id \"" + rm->m_id + "\"]"); + msg.append(" [ref \"" + rm->m_reference + "\"]"); return modsecurity::utils::string::toHexIfNeeded(msg); } -std::string RuleMessage::noClientErrorLog(Transaction *trans) { +std::string RuleMessage::noClientErrorLog(const RuleMessage *rm) { std::string msg; msg.append("ModSecurity: Warning. "); - msg.append(m_match); - msg.append(" [file \"" + std::string(m_ruleFile) + "\"]"); - msg.append(" [line \"" + std::to_string(m_ruleLine) + "\"]"); - msg.append(" [id \"" + std::to_string(m_ruleId) + "\"]"); - msg.append(" [rev \"" + m_rev + "\"]"); - msg.append(" [msg \"" + m_message + "\"]"); - msg.append(" [data \"" + m_data + "\"]"); + msg.append(rm->m_match); + msg.append(" [file \"" + std::string(rm->m_ruleFile) + "\"]"); + msg.append(" [line \"" + std::to_string(rm->m_ruleLine) + "\"]"); + msg.append(" [id \"" + std::to_string(rm->m_ruleId) + "\"]"); + msg.append(" [rev \"" + rm->m_rev + "\"]"); + msg.append(" [msg \"" + rm->m_message + "\"]"); + msg.append(" [data \"" + rm->m_data + "\"]"); msg.append(" [severity \"" + - std::to_string(m_severity) + "\"]"); - msg.append(" [ver \"" + m_ver + "\"]"); - msg.append(" [maturity \"" + std::to_string(m_maturity) + "\"]"); - msg.append(" [accuracy \"" + std::to_string(m_accuracy) + "\"]"); - for (auto &a : m_tags) { + std::to_string(rm->m_severity) + "\"]"); + msg.append(" [ver \"" + rm->m_ver + "\"]"); + msg.append(" [maturity \"" + std::to_string(rm->m_maturity) + "\"]"); + msg.append(" [accuracy \"" + std::to_string(rm->m_accuracy) + "\"]"); + for (auto &a : rm->m_tags) { msg.append(" [tag \"" + a + "\"]"); } - msg.append(" [ref \"" + m_reference + "\"]"); + msg.append(" [ref \"" + rm->m_reference + "\"]"); return modsecurity::utils::string::toHexIfNeeded(msg); } -std::string RuleMessage::errorLogTail(Transaction *trans) { +std::string RuleMessage::errorLogTail(const RuleMessage *rm) { std::string msg; - msg.append("[hostname \"" + std::string(trans->m_serverIpAddress) \ + msg.append("[hostname \"" + std::string(rm->m_serverIpAddress) \ + "\"]"); - msg.append(" [uri \"" + trans->m_uri_no_query_string_decoded + "\"]"); - msg.append(" [unique_id \"" + trans->m_id + "\"]"); + msg.append(" [uri \"" + rm->m_uriNoQueryStringDecoded + "\"]"); + msg.append(" [unique_id \"" + rm->m_id + "\"]"); return modsecurity::utils::string::toHexIfNeeded(msg); } -std::string RuleMessage::errorLog(Transaction *trans) { +std::string RuleMessage::errorLog(const RuleMessage *rm) { std::string msg; - msg.append("[client " + std::string(trans->m_clientIpAddress) + "] "); - msg.append(noClientErrorLog(trans)); - msg.append(" " + errorLogTail(trans)); + msg.append("[client " + std::string(rm->m_clientIpAddress) + "] "); + msg.append(noClientErrorLog(rm)); + msg.append(" " + errorLogTail(rm)); + + return msg; +} + +std::string RuleMessage::log(const RuleMessage *rm) { + std::string msg; + + if (rm->m_isDisruptive) { + msg.append(disruptiveErrorLog(rm)); + } else { + msg.append(errorLog(rm)); + } return msg; } diff --git a/src/rules.cc b/src/rules.cc index b72abfcc..0e406d9b 100644 --- a/src/rules.cc +++ b/src/rules.cc @@ -209,7 +209,7 @@ int Rules::evaluate(int phase, Transaction *transaction) { debug(9, "Skipped rule id '" + std::to_string(rule->m_ruleId) \ + "'. Removed by an SecRuleRemove directive."); } else { - rule->evaluate(transaction); + rule->evaluate(transaction, NULL); if (transaction->m_it.disruptive == true) { debug(8, "Skipping this phase as this " \ "request was already intercepted."); diff --git a/src/transaction.cc b/src/transaction.cc index 63f27208..88e82c9c 100644 --- a/src/transaction.cc +++ b/src/transaction.cc @@ -1441,7 +1441,7 @@ std::string Transaction::toOldAuditLogFormat(int parts, if (parts & audit_log::AuditLog::HAuditLogPart) { audit_log << "--" << trailer << "-" << "H--" << std::endl; for (auto a : m_rulesMessages) { - audit_log << a.noClientErrorLog(this) << std::endl; + audit_log << a.noClientErrorLog() << std::endl; } audit_log << std::endl; /** TODO: write audit_log H part. */ @@ -1658,8 +1658,8 @@ std::string Transaction::toJSON(int parts) { } -void Transaction::serverLog(const std::string& msg) { - m_ms->serverLog(m_logCbData, msg); +void Transaction::serverLog(std::shared_ptr rm) { + m_ms->serverLog(m_logCbData, rm); } diff --git a/test/benchmark/benchmark.cc b/test/benchmark/benchmark.cc index 6966ce3b..f4636892 100644 --- a/test/benchmark/benchmark.cc +++ b/test/benchmark/benchmark.cc @@ -68,6 +68,7 @@ char rules_file[] = "basic_rules.conf"; #define NUM_REQUESTS 10000 + int main(int argc, char *argv[]) { int i = 0; modsecurity::ModSecurity *modsec; diff --git a/test/regression/regression.cc b/test/regression/regression.cc index 667409cd..575ebfbb 100644 --- a/test/regression/regression.cc +++ b/test/regression/regression.cc @@ -80,7 +80,8 @@ void actions(ModSecurityTestResults *r, } } -void logCb(void *data, const char *msg) { +void logCb(void *data, const void *msgv) { + const char *msg = reinterpret_cast(msgv); std::stringstream *ss = (std::stringstream *) data; *ss << msg << std::endl; }