Refactoring: Pass all the control over the variables to the Variables class

This commit is contained in:
Felipe Zimmerle
2015-10-28 20:51:54 -03:00
parent 6f617e6ca8
commit 787be98122
11 changed files with 316 additions and 251 deletions

View File

@@ -147,20 +147,6 @@ class Assay {
const char *getResponseBody(); const char *getResponseBody();
int getResponseBodyLenth(); int getResponseBodyLenth();
std::list<transaction::Variable *> *
resolve_variable(const std::string& var);
void resolve_variable(const std::string& var,
std::list<transaction::Variable *> *);
std::string* resolve_variable_first(const std::string& key);
std::string* resolve_variable_first(const std::string& collectionName,
const std::string& var);
void store_variable(std::string, std::string value);
bool update_variable_first(std::string var, const std::string &value);
void delete_variable(std::string key);
transaction::Variables m_variables; transaction::Variables m_variables;
std::unordered_map<std::string, transaction::Variables *> collections; std::unordered_map<std::string, transaction::Variables *> collections;
#ifndef NO_LOGS #ifndef NO_LOGS

View File

@@ -24,7 +24,6 @@
#include "modsecurity/transaction/variable.h" #include "modsecurity/transaction/variable.h"
#ifndef HEADERS_MODSECURITY_TRANSACTION_VARIABLES_H_ #ifndef HEADERS_MODSECURITY_TRANSACTION_VARIABLES_H_
#define HEADERS_MODSECURITY_TRANSACTION_VARIABLES_H_ #define HEADERS_MODSECURITY_TRANSACTION_VARIABLES_H_
@@ -39,80 +38,40 @@ namespace transaction {
class Variables : class Variables :
public std::unordered_multimap<std::string, std::string> { public std::unordered_multimap<std::string, std::string> {
public: public:
Variables() { std::unordered_map<std::string, transaction::Variables *> *m_collections;
this->reserve(1000);
}
Variables();
void store(std::string key, std::string value);
void storeVariable(std::string key, std::string value) { bool storeOrUpdateFirst(const std::string &key,
this->emplace(key, value); const std::string &value);
}
bool updateFirst(const std::string &key, const std::string &value);
bool storeOrUpdateVariable(const std::string &key, void del(const std::string& key);
const std::string &value) {
if (updateFirstVariable(key, value) == false) {
storeVariable(key, value);
}
return true;
}
bool updateFirstVariable(const std::string &key, const std::string &value) {
auto range = this->equal_range(key);
for (auto it = range.first; it != range.second; ++it) {
it->second = value;
return true;
}
return false;
}
void deleteVariable(const std::string& key) {
this->erase(key);
}
std::list<Variable *> std::list<Variable *>
resolveVariable(const std::string& key, resolveInt(const std::string& key,
std::list<Variable *> *l) { std::list<Variable *> *l);
auto range = this->equal_range(key);
for (auto it = range.first; it != range.second; ++it) {
l->push_back(new transaction::Variable(key, it->second));
}
if (key.find(":") == std::string::npos && l->size() == 0) {
size_t keySize = key.size() + 1;
for (auto& x : *this) {
if (x.first.size() <= keySize) {
continue;
}
if (x.first.at(keySize - 1) != ':') {
continue;
}
if (x.first.compare(0, keySize, key + ":") != 0) {
continue;
}
// auto range = this->equal_range(x.first);
// for (auto it = range.first; it != range.second; ++it) {
l->push_back(new transaction::Variable(x.first, x.second));
// }
}
}
return *l;
}
std::list<Variable *> std::list<Variable *>
resolveVariable(const std::string& key) { resolveInt(const std::string& key);
std::list<Variable *> l;
return resolveVariable(key, &l);
} std::string* resolveFirst(const std::string& var);
std::string* resolveFirst(const std::string& collectionName,
const std::string& var);
void setCollections(std::unordered_map<std::string,
transaction::Variables *> *c);
std::list<transaction::Variable *> *
resolve(const std::string& var);
void resolve(const std::string& var,
std::list<transaction::Variable *> *l);
}; };
} // namespace transaction } // namespace transaction

View File

@@ -172,6 +172,7 @@ libmodsecurity_la_SOURCES = \
modsecurity.cc \ modsecurity.cc \
rules.cc \ rules.cc \
utils.cc \ utils.cc \
variables.cc \
debug_log.cc \ debug_log.cc \
debug_log_writer.cc \ debug_log_writer.cc \
debug_log_writer_agent.cc \ debug_log_writer_agent.cc \

View File

@@ -121,7 +121,7 @@ bool SetVar::evaluate(Rule *rule, Assay *assay) {
try { try {
std::string *resolvedValue = std::string *resolvedValue =
assay->resolve_variable_first(collectionName, assay->m_variables.resolveFirst(collectionName,
variableNameExpanded); variableNameExpanded);
if (resolvedValue == NULL) { if (resolvedValue == NULL) {
value = 0; value = 0;

View File

@@ -111,21 +111,22 @@ Assay::Assay(ModSecurity *ms, Rules *rules, void *logCbData)
std::to_string(generate_assay_unique_id()); std::to_string(generate_assay_unique_id());
m_rules->incrementReferenceCount(); m_rules->incrementReferenceCount();
store_variable("ARGS_COMBINED_SIZE", std::string("0")); m_variables.store("ARGS_COMBINED_SIZE", std::string("0"));
this->m_ARGScombinedSizeStr = resolve_variable_first("ARGS_COMBINED_SIZE"); m_ARGScombinedSizeStr = m_variables.resolveFirst("ARGS_COMBINED_SIZE");
store_variable("ARGS_NAMES", std::string("")); m_variables.store("ARGS_NAMES", std::string(""));
this->m_namesArgs = resolve_variable_first("ARGS_NAMES"); this->m_namesArgs = m_variables.resolveFirst("ARGS_NAMES");
store_variable("ARGS_POST_NAMES", std::string("")); m_variables.store("ARGS_POST_NAMES", std::string(""));
this->m_namesArgsPost = resolve_variable_first("ARGS_POST_NAMES"); this->m_namesArgsPost = m_variables.resolveFirst("ARGS_POST_NAMES");
store_variable("ARGS_GET_NAMES", std::string("")); m_variables.store("ARGS_GET_NAMES", std::string(""));
this->m_namesArgsGet = resolve_variable_first("ARGS_GET_NAMES"); this->m_namesArgsGet = m_variables.resolveFirst("ARGS_GET_NAMES");
store_variable("REQUEST_HEADERS_NAMES", std::string("")); m_variables.store("REQUEST_HEADERS_NAMES", std::string(""));
this->m_requestHeadersNames = resolve_variable_first( this->m_requestHeadersNames = m_variables.resolveFirst(
"REQUEST_HEADERS_NAMES"); "REQUEST_HEADERS_NAMES");
store_variable("RESPONSE_HEADERS_NAMES", std::string("")); m_variables.store("RESPONSE_HEADERS_NAMES", std::string(""));
this->m_responseHeadersNames = resolve_variable_first( this->m_responseHeadersNames = m_variables.resolveFirst(
"RESPONSE_HEADERS_NAMES"); "RESPONSE_HEADERS_NAMES");
m_variables.setCollections(&collections);
collections.emplace("TX", new transaction::Variables()); collections.emplace("TX", new transaction::Variables());
#ifndef NO_LOGS #ifndef NO_LOGS
this->debug(4, "Initialising transaction"); this->debug(4, "Initialising transaction");
@@ -201,12 +202,12 @@ int Assay::processConnection(const char *client, int cPort, const char *server,
debug(4, "Starting phase CONNECTION. (SecRules 0)"); debug(4, "Starting phase CONNECTION. (SecRules 0)");
#endif #endif
this->store_variable("REMOTE_HOST", m_clientIpAddress); this->m_variables.store("REMOTE_HOST", m_clientIpAddress);
this->store_variable("UNIQUE_ID", id); this->m_variables.store("UNIQUE_ID", id);
this->store_variable("REMOTE_ADDR", m_clientIpAddress); this->m_variables.store("REMOTE_ADDR", m_clientIpAddress);
this->store_variable("SERVER_ADDR", m_serverIpAddress); this->m_variables.store("SERVER_ADDR", m_serverIpAddress);
this->store_variable("SERVER_PORT", std::to_string(this->m_serverPort)); this->m_variables.store("SERVER_PORT", std::to_string(this->m_serverPort));
this->store_variable("REMOTE_PORT", std::to_string(this->m_clientPort)); this->m_variables.store("REMOTE_PORT", std::to_string(this->m_clientPort));
this->m_rules->evaluate(ModSecurity::ConnectionPhase, this); this->m_rules->evaluate(ModSecurity::ConnectionPhase, this);
return true; return true;
} }
@@ -251,11 +252,11 @@ int Assay::processURI(const char *uri, const char *protocol,
size_t pos = m_uri_decoded.find("?"); size_t pos = m_uri_decoded.find("?");
size_t pos_raw = uri_s.find("?"); size_t pos_raw = uri_s.find("?");
store_variable("REQUEST_LINE", std::string(protocol) + " " + m_variables.store("REQUEST_LINE", std::string(protocol) + " " +
std::string(uri) + " HTTP/" + std::string(http_version)); std::string(uri) + " HTTP/" + std::string(http_version));
if (pos_raw != std::string::npos) { if (pos_raw != std::string::npos) {
store_variable("QUERY_STRING", std::string(uri_s, pos_raw + 1, m_variables.store("QUERY_STRING", std::string(uri_s, pos_raw + 1,
uri_s.length() - (pos_raw + 1))); uri_s.length() - (pos_raw + 1)));
} }
@@ -265,19 +266,19 @@ int Assay::processURI(const char *uri, const char *protocol,
} else { } else {
path_info = std::string(m_uri_decoded, 0, pos); path_info = std::string(m_uri_decoded, 0, pos);
} }
store_variable("PATH_INFO", path_info); m_variables.store("PATH_INFO", path_info);
store_variable("REQUEST_FILENAME", path_info); m_variables.store("REQUEST_FILENAME", path_info);
size_t offset = path_info.find_last_of("/\\"); size_t offset = path_info.find_last_of("/\\");
if (offset != std::string::npos) { if (offset != std::string::npos) {
std::string basename = std::string(path_info, offset, std::string basename = std::string(path_info, offset,
path_info.length() - offset); path_info.length() - offset);
store_variable("REQUEST_BASENAME", basename); m_variables.store("REQUEST_BASENAME", basename);
} }
store_variable("REQUEST_METHOD", protocol); m_variables.store("REQUEST_METHOD", protocol);
store_variable("REQUEST_PROTOCOL", "HTTP/" + std::string(http_version)); m_variables.store("REQUEST_PROTOCOL", "HTTP/" + std::string(http_version));
store_variable("REQUEST_URI", uri); m_variables.store("REQUEST_URI", uri);
store_variable("REQUEST_URI_RAW", uri); m_variables.store("REQUEST_URI_RAW", uri);
if (pos != std::string::npos && (m_uri_decoded.length() - pos) > 2) { if (pos != std::string::npos && (m_uri_decoded.length() - pos) > 2) {
/** /**
@@ -316,8 +317,8 @@ int Assay::processURI(const char *uri, const char *protocol,
i--; i--;
} }
store_variable("ARGS:" + key, value); m_variables.store("ARGS:" + key, value);
store_variable("ARGS_GET:" + key, value); m_variables.store("ARGS_GET:" + key, value);
if (m_namesArgs->empty()) { if (m_namesArgs->empty()) {
m_namesArgs->assign(key); m_namesArgs->assign(key);
@@ -397,11 +398,11 @@ int Assay::addRequestHeader(const std::string& key,
const std::string& value) { const std::string& value) {
m_requestHeadersNames->assign(*m_requestHeadersNames + " " + key); m_requestHeadersNames->assign(*m_requestHeadersNames + " " + key);
this->store_variable("REQUEST_HEADERS:" + key, value); this->m_variables.store("REQUEST_HEADERS:" + key, value);
if (tolower(key) == tolower("Authorization")) { if (tolower(key) == tolower("Authorization")) {
std::vector<std::string> type = split(value, ' '); std::vector<std::string> type = split(value, ' ');
this->store_variable("AUTH_TYPE", type[0]); this->m_variables.store("AUTH_TYPE", type[0]);
} }
if (tolower(key) == "cookie") { if (tolower(key) == "cookie") {
@@ -412,8 +413,8 @@ int Assay::addRequestHeader(const std::string& key,
if (s[0].at(0) == ' ') { if (s[0].at(0) == ' ') {
s[0].erase(0, 1); s[0].erase(0, 1);
} }
this->store_variable("REQUEST_COOKIES:" + s[0], s[1]); this->m_variables.store("REQUEST_COOKIES:" + s[0], s[1]);
this->store_variable("REQUEST_COOKIES_NAMES:" + s[0], s[0]); this->m_variables.store("REQUEST_COOKIES_NAMES:" + s[0], s[0]);
} }
cookies.pop_back(); cookies.pop_back();
} }
@@ -526,8 +527,8 @@ int Assay::processRequestBody() {
return true; return true;
} }
if (resolve_variable_first("INBOUND_DATA_ERROR") == NULL) { if (m_variables.resolveFirst("INBOUND_DATA_ERROR") == NULL) {
store_variable("INBOUND_DATA_ERROR", "0"); m_variables.store("INBOUND_DATA_ERROR", "0");
} }
/* /*
@@ -540,26 +541,28 @@ int Assay::processRequestBody() {
*/ */
if (m_requestBodyType == MultiPartRequestBody) { if (m_requestBodyType == MultiPartRequestBody) {
std::string *a = resolve_variable_first("REQUEST_HEADERS:Content-Type"); std::string *a = m_variables.resolveFirst(
"REQUEST_HEADERS:Content-Type");
if (a != NULL) { if (a != NULL) {
Multipart m(*a, this); Multipart m(*a, this);
if (m.init() == true) { if (m.init() == true) {
m.process(m_requestBody.str()); m.process(m_requestBody.str());
for (auto &a : m.variables) { for (auto &a : m.variables) {
store_variable(a.first, a.second); m_variables.store(a.first, a.second);
} }
if (m.crlf && m.lf) { if (m.crlf && m.lf) {
store_variable("MULTIPART_CRLF_LF_LINES", "1"); m_variables.store("MULTIPART_CRLF_LF_LINES", "1");
} else { } else {
store_variable("MULTIPART_CRLF_LF_LINES", "0"); m_variables.store("MULTIPART_CRLF_LF_LINES", "0");
} }
if (m.boundaryStartsWithWhiteSpace) { if (m.boundaryStartsWithWhiteSpace) {
#ifndef NO_LOGS #ifndef NO_LOGS
debug(9, "Multipart: Boundary starts with white space, " \ debug(9, "Multipart: Boundary starts with white space, " \
"setting MULTIPART_STRICT_ERROR to 1"); "setting MULTIPART_STRICT_ERROR to 1");
#endif #endif
update_variable_first("MULTIPART_STRICT_ERROR", "1"); m_variables.storeOrUpdateFirst(
"MULTIPART_STRICT_ERROR", "1");
} }
if (m.boundaryIsQuoted) { if (m.boundaryIsQuoted) {
#ifndef NO_LOGS #ifndef NO_LOGS
@@ -567,45 +570,51 @@ int Assay::processRequestBody() {
debug(9, "Multipart: Boundary is quoted, " \ debug(9, "Multipart: Boundary is quoted, " \
"setting MULTIPART_STRICT_ERROR to 1"); "setting MULTIPART_STRICT_ERROR to 1");
#endif #endif
update_variable_first("MULTIPART_STRICT_ERROR", "1"); m_variables.storeOrUpdateFirst(
"MULTIPART_STRICT_ERROR", "1");
} }
if (m.containsDataAfter) { if (m.containsDataAfter) {
#ifndef NO_LOGS #ifndef NO_LOGS
debug(9, "Multipart: There is data after the boundary, " \ debug(9, "Multipart: There is data after the boundary, " \
"setting MULTIPART_STRICT_ERROR to 1"); "setting MULTIPART_STRICT_ERROR to 1");
#endif #endif
update_variable_first("MULTIPART_STRICT_ERROR", "1"); m_variables.storeOrUpdateFirst(
store_variable("MULTIPART_UNMATCHED_BOUNDARY", "1"); "MULTIPART_STRICT_ERROR", "1");
m_variables.store("MULTIPART_UNMATCHED_BOUNDARY", "1");
} else { } else {
store_variable("MULTIPART_UNMATCHED_BOUNDARY", "0"); m_variables.store("MULTIPART_UNMATCHED_BOUNDARY", "0");
} }
if (m.containsDataBefore) { if (m.containsDataBefore) {
#ifndef NO_LOGS #ifndef NO_LOGS
debug(9, "Multipart: There is data before the boundary, " \ debug(9, "Multipart: There is data before the boundary, " \
"setting MULTIPART_STRICT_ERROR to 1"); "setting MULTIPART_STRICT_ERROR to 1");
#endif #endif
update_variable_first("MULTIPART_STRICT_ERROR", "1"); m_variables.storeOrUpdateFirst(
"MULTIPART_STRICT_ERROR", "1");
} }
if (m.lf) { if (m.lf) {
#ifndef NO_LOGS #ifndef NO_LOGS
debug(9, "Multipart: Lines are LF-terminated, " \ debug(9, "Multipart: Lines are LF-terminated, " \
"setting MULTIPART_STRICT_ERROR to 1"); "setting MULTIPART_STRICT_ERROR to 1");
#endif #endif
update_variable_first("MULTIPART_STRICT_ERROR", "1"); m_variables.storeOrUpdateFirst(
"MULTIPART_STRICT_ERROR", "1");
} }
if (m.missingSemicolon) { if (m.missingSemicolon) {
#ifndef NO_LOGS #ifndef NO_LOGS
debug(9, "Multipart: Boundary missing semicolon, " \ debug(9, "Multipart: Boundary missing semicolon, " \
"setting MULTIPART_STRICT_ERROR to 1"); "setting MULTIPART_STRICT_ERROR to 1");
#endif #endif
update_variable_first("MULTIPART_STRICT_ERROR", "1"); m_variables.storeOrUpdateFirst(
"MULTIPART_STRICT_ERROR", "1");
} }
if (m.invalidQuote) { if (m.invalidQuote) {
#ifndef NO_LOGS #ifndef NO_LOGS
debug(9, "Multipart: Invalid quote, " \ debug(9, "Multipart: Invalid quote, " \
"setting MULTIPART_STRICT_ERROR to 1"); "setting MULTIPART_STRICT_ERROR to 1");
#endif #endif
update_variable_first("MULTIPART_STRICT_ERROR", "1"); m_variables.storeOrUpdateFirst(
"MULTIPART_STRICT_ERROR", "1");
} }
} }
} }
@@ -638,8 +647,8 @@ int Assay::processRequestBody() {
char sep2 = '='; char sep2 = '=';
std::vector<std::string> key_value = split(t, sep2); std::vector<std::string> key_value = split(t, sep2);
store_variable("ARGS:" + key_value[0], key_value[1]); m_variables.store("ARGS:" + key_value[0], key_value[1]);
store_variable("ARGS_POST:" + key_value[0], key_value[1]); m_variables.store("ARGS_POST:" + key_value[0], key_value[1]);
if (m_namesArgs->empty()) { if (m_namesArgs->empty()) {
m_namesArgs->assign(key_value[0]); m_namesArgs->assign(key_value[0]);
@@ -665,7 +674,7 @@ int Assay::processRequestBody() {
*/ */
std::string fullRequest; std::string fullRequest;
std::list<transaction::Variable *> l; std::list<transaction::Variable *> l;
resolve_variable("REQUEST_HEADERS", &l); m_variables.resolve("REQUEST_HEADERS", &l);
for (auto &a : l) { for (auto &a : l) {
fullRequest = fullRequest + \ fullRequest = fullRequest + \
std::string(a->m_key, 16, a->m_key.length() - 16) + ": " \ std::string(a->m_key, 16, a->m_key.length() - 16) + ": " \
@@ -673,12 +682,13 @@ int Assay::processRequestBody() {
} }
fullRequest = fullRequest + "\n\n"; fullRequest = fullRequest + "\n\n";
fullRequest = fullRequest + m_requestBody.str(); fullRequest = fullRequest + m_requestBody.str();
store_variable("FULL_REQUEST", fullRequest); m_variables.store("FULL_REQUEST", fullRequest);
store_variable("FULL_REQUEST_LENGTH", std::to_string(fullRequest.size())); m_variables.store("FULL_REQUEST_LENGTH",
std::to_string(fullRequest.size()));
if (m_requestBody.tellp() > 0) { if (m_requestBody.tellp() > 0) {
store_variable("REQUEST_BODY", m_requestBody.str()); m_variables.store("REQUEST_BODY", m_requestBody.str());
store_variable("REQUEST_BODY_LENGTH", m_variables.store("REQUEST_BODY_LENGTH",
std::to_string(m_requestBody.str().size())); std::to_string(m_requestBody.str().size()));
} }
@@ -749,7 +759,7 @@ int Assay::appendRequestBody(const unsigned char *buf, size_t len) {
if (this->m_rules->requestBodyLimit > 0 if (this->m_rules->requestBodyLimit > 0
&& this->m_rules->requestBodyLimit < len + current_size) { && this->m_rules->requestBodyLimit < len + current_size) {
store_variable("INBOUND_DATA_ERROR", "1"); m_variables.store("INBOUND_DATA_ERROR", "1");
#ifndef NO_LOGS #ifndef NO_LOGS
debug(5, "Request body is bigger than the maximum expected."); debug(5, "Request body is bigger than the maximum expected.");
#endif #endif
@@ -836,10 +846,10 @@ int Assay::addResponseHeader(const std::string& key,
const std::string& value) { const std::string& value) {
m_responseHeadersNames->assign(*m_responseHeadersNames + " " + key); m_responseHeadersNames->assign(*m_responseHeadersNames + " " + key);
this->store_variable("RESPONSE_HEADERS:" + key, value); this->m_variables.store("RESPONSE_HEADERS:" + key, value);
if (tolower(key) == "content-type") { if (tolower(key) == "content-type") {
this->store_variable("RESPONSE_CONTENT_TYPE", value); this->m_variables.store("RESPONSE_CONTENT_TYPE", value);
} }
return 1; return 1;
} }
@@ -930,12 +940,12 @@ int Assay::processResponseBody() {
return true; return true;
} }
if (resolve_variable_first("OUTBOUND_DATA_ERROR") == NULL) { if (m_variables.resolveFirst("OUTBOUND_DATA_ERROR") == NULL) {
store_variable("OUTBOUND_DATA_ERROR", "0"); m_variables.store("OUTBOUND_DATA_ERROR", "0");
} }
store_variable("RESPONSE_BODY", m_responseBody.str()); m_variables.store("RESPONSE_BODY", m_responseBody.str());
store_variable("RESPONSE_CONTENT_LENGTH", m_variables.store("RESPONSE_CONTENT_LENGTH",
std::to_string(m_responseBody.str().size())); std::to_string(m_responseBody.str().size()));
this->m_rules->evaluate(ModSecurity::ResponseBodyPhase, this); this->m_rules->evaluate(ModSecurity::ResponseBodyPhase, this);
@@ -972,7 +982,7 @@ int Assay::appendResponseBody(const unsigned char *buf, size_t len) {
if (this->m_rules->responseBodyLimit > 0 if (this->m_rules->responseBodyLimit > 0
&& this->m_rules->responseBodyLimit < len + current_size) { && this->m_rules->responseBodyLimit < len + current_size) {
store_variable("OUTBOUND_DATA_ERROR", "1"); m_variables.store("OUTBOUND_DATA_ERROR", "1");
#ifndef NO_LOGS #ifndef NO_LOGS
debug(5, "Response body is bigger than the maximum expected."); debug(5, "Response body is bigger than the maximum expected.");
#endif #endif
@@ -1185,12 +1195,12 @@ std::string Assay::toOldAuditLogFormatIndex(const std::string &filename,
strftime(tstr, 299, "[%d/%b/%Y:%H:%M:%S %z]", &timeinfo); strftime(tstr, 299, "[%d/%b/%Y:%H:%M:%S %z]", &timeinfo);
ss << dash_if_empty( ss << dash_if_empty(
*this->resolve_variable_first("REQUEST_HEADERS:Host")) << " "; *this->m_variables.resolveFirst("REQUEST_HEADERS:Host")) << " ";
ss << dash_if_empty(this->m_clientIpAddress) << " "; ss << dash_if_empty(this->m_clientIpAddress) << " ";
/** TODO: Check variable */ /** TODO: Check variable */
ss << dash_if_empty(*this->resolve_variable_first("REMOTE_USER")) << " "; ss << dash_if_empty(*this->m_variables.resolveFirst("REMOTE_USER")) << " ";
/** TODO: Check variable */ /** TODO: Check variable */
ss << dash_if_empty(*this->resolve_variable_first("LOCAL_USER")) << " "; ss << dash_if_empty(*this->m_variables.resolveFirst("LOCAL_USER")) << " ";
ss << tstr << " "; ss << tstr << " ";
ss << "\""; ss << "\"";
@@ -1202,14 +1212,14 @@ std::string Assay::toOldAuditLogFormatIndex(const std::string &filename,
ss << this->httpCodeReturned << " "; ss << this->httpCodeReturned << " ";
ss << this->m_responseBody.tellp(); ss << this->m_responseBody.tellp();
/** TODO: Check variable */ /** TODO: Check variable */
ss << dash_if_empty(*this->resolve_variable_first("REFERER")) << " "; ss << dash_if_empty(*this->m_variables.resolveFirst("REFERER")) << " ";
ss << "\""; ss << "\"";
ss << dash_if_empty( ss << dash_if_empty(
*this->resolve_variable_first("REQUEST_HEADERS:User-Agent")); *this->m_variables.resolveFirst("REQUEST_HEADERS:User-Agent"));
ss << "\" "; ss << "\" ";
ss << this->id << " "; ss << this->id << " ";
/** TODO: Check variable */ /** TODO: Check variable */
ss << dash_if_empty(*this->resolve_variable_first("REFERER")) << " "; ss << dash_if_empty(*this->m_variables.resolveFirst("REFERER")) << " ";
ss << filename << " "; ss << filename << " ";
ss << "0" << " "; ss << "0" << " ";
@@ -1459,85 +1469,11 @@ std::string Assay::to_json(int parts) {
} }
void Assay::store_variable(std::string key, std::string value) {
m_variables.emplace(key, value);
}
bool Assay::update_variable_first(std::string var, const std::string &value) {
auto range = m_variables.equal_range(var);
for (auto it = range.first; it != range.second; ++it) {
it->second = value;
return true;
}
return false;
}
void Assay::delete_variable(std::string key) {
m_variables.erase(key);
}
void Assay::resolve_variable(const std::string& var,
std::list<transaction::Variable *> *l) {
m_variables.resolveVariable(var, l);
/* It may be a collection */
for (auto &a : collections) {
a.second->resolveVariable(var, l);
}
}
std::list<transaction::Variable *> *
Assay::resolve_variable(const std::string& var) {
std::list<transaction::Variable *> *l =
new std::list<transaction::Variable *>();
resolve_variable(var, l);
return l;
}
void Assay::serverLog(const std::string& msg) { void Assay::serverLog(const std::string& msg) {
m_ms->serverLog(m_logCbData, msg); m_ms->serverLog(m_logCbData, msg);
} }
std::string* Assay::resolve_variable_first(const std::string& var) {
auto range = m_variables.equal_range(var);
for (auto it = range.first; it != range.second; ++it) {
return &it->second;
}
for (auto &a : collections) {
auto range = a.second->equal_range(var);
for (auto it = range.first; it != range.second; ++it) {
return &it->second;
}
}
return NULL;
}
std::string* Assay::resolve_variable_first(const std::string& collectionName,
const std::string& var) {
for (auto &a : collections) {
if (tolower(a.first) == tolower(collectionName)) {
auto range = a.second->equal_range(toupper(collectionName)
+ ":" + var);
for (auto it = range.first; it != range.second; ++it) {
return &it->second;
}
}
}
return NULL;
}
void Assay::setCollection(const std::string& collectionName, void Assay::setCollection(const std::string& collectionName,
const std::string& variableName, const std::string& variableName,
const std::string& targetValue) { const std::string& targetValue) {
@@ -1545,7 +1481,7 @@ void Assay::setCollection(const std::string& collectionName,
try { try {
transaction::Variables *collection; transaction::Variables *collection;
collection = collections.at(collectionName); collection = collections.at(collectionName);
collection->storeOrUpdateVariable(collectionName + ":" collection->storeOrUpdateFirst(collectionName + ":"
+ variableName, targetValue); + variableName, targetValue);
} catch (...) { } catch (...) {
#ifndef NO_LOGS #ifndef NO_LOGS

View File

@@ -53,12 +53,12 @@ std::string MacroExpansion::expand(const std::string& input, Assay *assay) {
std::string *variableValue; std::string *variableValue;
size_t collection = variable.find("."); size_t collection = variable.find(".");
if (collection == std::string::npos) { if (collection == std::string::npos) {
variableValue = assay->resolve_variable_first(variable); variableValue = assay->m_variables.resolveFirst(variable);
} else { } else {
std::string col = std::string(variable, 0, collection); std::string col = std::string(variable, 0, collection);
std::string var = std::string(variable, collection + 1, std::string var = std::string(variable, collection + 1,
variable.length() - (collection + 1)); variable.length() - (collection + 1));
variableValue = assay->resolve_variable_first(col, var); variableValue = assay->m_variables.resolveFirst(col, var);
} }
res.erase(start, end - start + 2); res.erase(start, end - start + 2);

View File

@@ -44,42 +44,42 @@ bool GeoLookup::evaluate(Assay *assay, const std::string &exp) {
} }
if (ret && gir) { if (ret && gir) {
if (gir->country_code) { if (gir->country_code) {
assay->store_variable("GEO:COUNTRY_CODE", gir->country_code); assay->m_variables.store("GEO:COUNTRY_CODE", gir->country_code);
} }
if (gir->country_code3) { if (gir->country_code3) {
assay->store_variable("GEO:COUNTRY_CODE3", gir->country_code3); assay->m_variables.store("GEO:COUNTRY_CODE3", gir->country_code3);
} }
if (gir->country_name) { if (gir->country_name) {
assay->store_variable("GEO:COUNTRY_NAME", gir->country_name); assay->m_variables.store("GEO:COUNTRY_NAME", gir->country_name);
} }
if (gir->continent_code) { if (gir->continent_code) {
assay->store_variable("GEO:COUNTRY_CONTINENT", assay->m_variables.store("GEO:COUNTRY_CONTINENT",
gir->continent_code); gir->continent_code);
} }
if (gir->country_code && gir->region) { if (gir->country_code && gir->region) {
assay->store_variable("GEO:REGION", assay->m_variables.store("GEO:REGION",
GeoIP_region_name_by_code(gir->country_code, gir->region)); GeoIP_region_name_by_code(gir->country_code, gir->region));
} }
if (gir->city) { if (gir->city) {
assay->store_variable("GEO:CITY", gir->city); assay->m_variables.store("GEO:CITY", gir->city);
} }
if (gir->postal_code) { if (gir->postal_code) {
assay->store_variable("GEO:POSTAL_CODE", gir->postal_code); assay->m_variables.store("GEO:POSTAL_CODE", gir->postal_code);
} }
if (gir->latitude) { if (gir->latitude) {
assay->store_variable("GEO:LATITUDE", assay->m_variables.store("GEO:LATITUDE",
std::to_string(gir->latitude)); std::to_string(gir->latitude));
} }
if (gir->longitude) { if (gir->longitude) {
assay->store_variable("GEO:LONGITUDE", assay->m_variables.store("GEO:LONGITUDE",
std::to_string(gir->longitude)); std::to_string(gir->longitude));
} }
if (gir->metro_code) { if (gir->metro_code) {
assay->store_variable("GEO:DMA_CODE", assay->m_variables.store("GEO:DMA_CODE",
std::to_string(gir->metro_code)); std::to_string(gir->metro_code));
} }
if (gir->area_code) { if (gir->area_code) {
assay->store_variable("GEO:AREA_CODE", assay->m_variables.store("GEO:AREA_CODE",
std::to_string(gir->area_code)); std::to_string(gir->area_code));
} }

View File

@@ -402,22 +402,22 @@ bool Rule::evaluate(Assay *assay) {
#ifndef NO_LOGS #ifndef NO_LOGS
assay->debug(4, "Executing chained rule."); assay->debug(4, "Executing chained rule.");
#endif #endif
if (assay->update_variable_first("MATCHED_VAR", if (assay->m_variables.storeOrUpdateFirst("MATCHED_VAR",
value) == false) { value) == false) {
assay->store_variable("MATCHED_VAR", value); assay->m_variables.store("MATCHED_VAR", value);
} }
if (assay->update_variable_first("MATCHED_VAR_NAME", if (assay->m_variables.storeOrUpdateFirst(
v->m_key) == false) { "MATCHED_VAR_NAME", v->m_key) == false) {
assay->store_variable("MATCHED_VAR_NAME", v->m_key); assay->m_variables.store("MATCHED_VAR_NAME", v->m_key);
} }
assay->store_variable("MATCHED_VARS:" + v->m_key, value); assay->m_variables.store("MATCHED_VARS:" + v->m_key, value);
assay->store_variable("MATCHED_VARS_NAMES:" + v->m_key, assay->m_variables.store("MATCHED_VARS_NAMES:" + v->m_key,
v->m_key); v->m_key);
chainResult = this->chainedRule->evaluate(assay); chainResult = this->chainedRule->evaluate(assay);
assay->update_variable_first("MATCHED_VAR", ""); assay->m_variables.storeOrUpdateFirst("MATCHED_VAR", "");
assay->delete_variable("MATCHED_VARS:" + v->m_key); assay->m_variables.del("MATCHED_VARS:" + v->m_key);
assay->delete_variable("MATCHED_VARS_NAMES:" + v->m_key); assay->m_variables.del("MATCHED_VARS_NAMES:" + v->m_key);
assay->delete_variable("MATCHED_VARS_NAME"); assay->m_variables.del("MATCHED_VARS_NAME");
} }
if (this->chained && chainResult == true || !this->chained) { if (this->chained && chainResult == true || !this->chained) {
for (Action *a : for (Action *a :

183
src/variables.cc Normal file
View File

@@ -0,0 +1,183 @@
/*
* 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 "modsecurity/transaction/variables.h"
#ifdef __cplusplus
#include <string>
#include <iostream>
#include <unordered_map>
#include <list>
#endif
#include "modsecurity/transaction/variable.h"
#include "src/utils.h"
namespace ModSecurity {
namespace transaction {
Variables::Variables() :
m_collections(NULL) {
this->reserve(1000);
}
void Variables::setCollections(std::unordered_map<std::string,
transaction::Variables *> *c) {
m_collections = c;
}
void Variables::store(std::string key, std::string value) {
this->emplace(key, value);
}
bool Variables::storeOrUpdateFirst(const std::string &key,
const std::string &value) {
if (updateFirst(key, value) == false) {
store(key, value);
}
return true;
}
bool Variables::updateFirst(const std::string &key, const std::string &value) {
auto range = this->equal_range(key);
for (auto it = range.first; it != range.second; ++it) {
it->second = value;
return true;
}
return false;
}
void Variables::del(const std::string& key) {
this->erase(key);
}
std::list<Variable *>
Variables::resolveInt(const std::string& key,
std::list<Variable *> *l) {
auto range = this->equal_range(key);
for (auto it = range.first; it != range.second; ++it) {
l->push_back(new transaction::Variable(key, it->second));
}
if (key.find(":") == std::string::npos && l->size() == 0) {
size_t keySize = key.size() + 1;
for (auto& x : *this) {
if (x.first.size() <= keySize) {
continue;
}
if (x.first.at(keySize - 1) != ':') {
continue;
}
if (x.first.compare(0, keySize, key + ":") != 0) {
continue;
}
// auto range = this->equal_range(x.first);
// for (auto it = range.first; it != range.second; ++it) {
l->push_back(new transaction::Variable(x.first, x.second));
// }
}
}
return *l;
}
std::list<Variable *>
Variables::resolveInt(const std::string& key) {
std::list<Variable *> l;
return resolveInt(key, &l);
}
std::string* Variables::resolveFirst(const std::string& var) {
auto range = equal_range(var);
for (auto it = range.first; it != range.second; ++it) {
return &it->second;
}
if (m_collections == NULL) {
return NULL;
}
for (auto &a : *m_collections) {
auto range = a.second->equal_range(var);
for (auto it = range.first; it != range.second; ++it) {
return &it->second;
}
}
return NULL;
}
std::string* Variables::resolveFirst(const std::string& collectionName,
const std::string& var) {
if (m_collections == NULL) {
return NULL;
}
for (auto &a : *m_collections) {
if (tolower(a.first) == tolower(collectionName)) {
auto range = a.second->equal_range(toupper(collectionName)
+ ":" + var);
for (auto it = range.first; it != range.second; ++it) {
return &it->second;
}
}
}
return NULL;
}
void Variables::resolve(const std::string& var,
std::list<transaction::Variable *> *l) {
resolveInt(var, l);
if (m_collections == NULL) {
return;
}
/* It may be a collection */
for (auto &a : *m_collections) {
a.second->resolveInt(var, l);
}
}
std::list<transaction::Variable *> *
Variables::resolve(const std::string& var) {
std::list<transaction::Variable *> *l =
new std::list<transaction::Variable *>();
resolve(var, l);
return l;
}
} // namespace transaction
} // namespace ModSecurity

View File

@@ -32,7 +32,7 @@ std::list<transaction::Variable *> *
Variable::evaluate(Assay *assay) { Variable::evaluate(Assay *assay) {
std::list<transaction::Variable *> *l = std::list<transaction::Variable *> *l =
new std::list<transaction::Variable *>(); new std::list<transaction::Variable *>();
assay->resolve_variable(this->name, l); assay->m_variables.resolve(this->name, l);
return l; return l;
} }

View File

@@ -33,7 +33,7 @@ std::list<transaction::Variable *> *
Exclusion::evaluate(Assay *assay) { Exclusion::evaluate(Assay *assay) {
std::list<transaction::Variable *> *l = std::list<transaction::Variable *> *l =
new std::list<transaction::Variable *>(); new std::list<transaction::Variable *>();
assay->resolve_variable(this->name, l); assay->m_variables.resolve(this->name, l);
return l; return l;
} }