From fbb63f4eb8c9ccefb81a7e5e9b827d5baef014af Mon Sep 17 00:00:00 2001 From: Johan Wikman Date: Thu, 12 Jan 2017 17:36:13 +0200 Subject: [PATCH] Masking: Handle larger than 16MB payloads Larger than 16MB payloads can either be ignored or then they may cause the session to be aborted. --- .../filter/masking/maskingfilterconfig.cc | 1 + .../filter/masking/maskingfiltersession.cc | 195 +++++++++++------- .../filter/masking/maskingfiltersession.hh | 38 +++- server/modules/filter/masking/maskingrules.cc | 1 + server/modules/filter/masking/mysql.hh | 15 +- 5 files changed, 164 insertions(+), 86 deletions(-) diff --git a/server/modules/filter/masking/maskingfilterconfig.cc b/server/modules/filter/masking/maskingfilterconfig.cc index 4cad73dfd..3d1ffe88e 100644 --- a/server/modules/filter/masking/maskingfilterconfig.cc +++ b/server/modules/filter/masking/maskingfilterconfig.cc @@ -11,6 +11,7 @@ * Public License. */ +#define MXS_MODULE_NAME "masking" #include "maskingfilterconfig.hh" namespace diff --git a/server/modules/filter/masking/maskingfiltersession.cc b/server/modules/filter/masking/maskingfiltersession.cc index 1f0695087..58d64ad5d 100644 --- a/server/modules/filter/masking/maskingfiltersession.cc +++ b/server/modules/filter/masking/maskingfiltersession.cc @@ -11,6 +11,7 @@ * Public License. */ +#define MXS_MODULE_NAME "masking" #include "maskingfiltersession.hh" #include #include @@ -98,10 +99,25 @@ int MaskingFilterSession::clientReply(GWBUF* pPacket) case EXPECTING_ROW_EOF: handle_eof(pPacket); break; + + case SUPPRESSING_RESPONSE: + break; } } - return FilterSession::clientReply(pPacket); + // The state may change by the code above, so need to check it again. + int rv; + if (m_state != SUPPRESSING_RESPONSE) + { + rv = FilterSession::clientReply(pPacket); + } + else + { + // TODO: The return value should mean something. + rv = 0; + } + + return rv; } void MaskingFilterSession::handle_response(GWBUF* pPacket) @@ -130,25 +146,32 @@ void MaskingFilterSession::handle_field(GWBUF* pPacket) { ComQueryResponse::ColumnDef column_def(pPacket); - const char *zUser = session_get_user(m_pSession); - const char *zHost = session_get_remote(m_pSession); - - if (!zUser) + if (column_def.payload_len() >= ComPacket::MAX_PAYLOAD_LEN) // Not particularly likely... { - zUser = ""; + handle_large_payload(); } - - if (!zHost) + else { - zHost = ""; - } + const char *zUser = session_get_user(m_pSession); + const char *zHost = session_get_remote(m_pSession); - const MaskingRules::Rule* pRule = m_res.rules()->get_rule_for(column_def, zUser, zHost); + if (!zUser) + { + zUser = ""; + } - if (m_res.append_type_and_rule(column_def.type(), pRule)) - { - // All fields have been read. - m_state = EXPECTING_FIELD_EOF; + if (!zHost) + { + zHost = ""; + } + + const MaskingRules::Rule* pRule = m_res.rules()->get_rule_for(column_def, zUser, zHost); + + if (m_res.append_type_and_rule(column_def.type(), pRule)) + { + // All fields have been read. + m_state = EXPECTING_FIELD_EOF; + } } } @@ -215,67 +238,97 @@ void MaskingFilterSession::handle_row(GWBUF* pPacket) break; default: - switch (m_res.command()) + if (m_res.some_rule_matches()) { - case MYSQL_COM_QUERY: + if (response.payload_len() >= ComPacket::MAX_PAYLOAD_LEN) { - ComQueryResponse::TextResultsetRow row(response, m_res.types()); - - ComQueryResponse::TextResultsetRow::iterator i = row.begin(); - while (i != row.end()) - { - const MaskingRules::Rule* pRule = m_res.get_rule(); - - if (pRule) - { - ComQueryResponse::TextResultsetRow::Value value = *i; - - if (value.is_string()) - { - LEncString s = value.as_string(); - pRule->rewrite(s); - } - else if (m_filter.config().warn_type_mismatch() == Config::WARN_ALWAYS) - { - warn_of_type_mismatch(*pRule); - } - } - ++i; - } + handle_large_payload(); } - break; - - case MYSQL_COM_STMT_EXECUTE: + else { - ComQueryResponse::BinaryResultsetRow row(response, m_res.types()); - - ComQueryResponse::BinaryResultsetRow::iterator i = row.begin(); - while (i != row.end()) - { - const MaskingRules::Rule* pRule = m_res.get_rule(); - - if (pRule) - { - ComQueryResponse::BinaryResultsetRow::Value value = *i; - - if (value.is_string()) - { - LEncString s = value.as_string(); - pRule->rewrite(s); - } - else if (m_filter.config().warn_type_mismatch() == Config::WARN_ALWAYS) - { - warn_of_type_mismatch(*pRule); - } - } - ++i; - } + mask_values(response); } - break; - - default: - MXS_ERROR("Unexpected request: %d", m_res.command()); - ss_dassert(!true); } } } + +void MaskingFilterSession::handle_large_payload() +{ + if (m_filter.config().large_payload() == Config::LARGE_ABORT) + { + MXS_WARNING("Payload > 16MB, closing the connection."); + poll_fake_hangup_event(m_pSession->client_dcb); + m_state = SUPPRESSING_RESPONSE; + } + else + { + MXS_WARNING("Payload > 16MB, no masking is performed."); + m_state = IGNORING_RESPONSE; + } +} + +void MaskingFilterSession::mask_values(ComResponse& response) +{ + switch (m_res.command()) + { + case MYSQL_COM_QUERY: + { + ComQueryResponse::TextResultsetRow row(response, m_res.types()); + + ComQueryResponse::TextResultsetRow::iterator i = row.begin(); + while (i != row.end()) + { + const MaskingRules::Rule* pRule = m_res.get_rule(); + + if (pRule) + { + ComQueryResponse::TextResultsetRow::Value value = *i; + + if (value.is_string()) + { + LEncString s = value.as_string(); + pRule->rewrite(s); + } + else if (m_filter.config().warn_type_mismatch() == Config::WARN_ALWAYS) + { + warn_of_type_mismatch(*pRule); + } + } + ++i; + } + } + break; + + case MYSQL_COM_STMT_EXECUTE: + { + ComQueryResponse::BinaryResultsetRow row(response, m_res.types()); + + ComQueryResponse::BinaryResultsetRow::iterator i = row.begin(); + while (i != row.end()) + { + const MaskingRules::Rule* pRule = m_res.get_rule(); + + if (pRule) + { + ComQueryResponse::BinaryResultsetRow::Value value = *i; + + if (value.is_string()) + { + LEncString s = value.as_string(); + pRule->rewrite(s); + } + else if (m_filter.config().warn_type_mismatch() == Config::WARN_ALWAYS) + { + warn_of_type_mismatch(*pRule); + } + } + ++i; + } + } + break; + + default: + MXS_ERROR("Unexpected request: %d", m_res.command()); + ss_dassert(!true); + } +} diff --git a/server/modules/filter/masking/maskingfiltersession.hh b/server/modules/filter/masking/maskingfiltersession.hh index 0348512d0..45c7804d5 100644 --- a/server/modules/filter/masking/maskingfiltersession.hh +++ b/server/modules/filter/masking/maskingfiltersession.hh @@ -49,13 +49,17 @@ private: EXPECTING_FIELD_EOF, EXPECTING_ROW, EXPECTING_ROW_EOF, - IGNORING_RESPONSE + IGNORING_RESPONSE, + SUPPRESSING_RESPONSE }; void handle_response(GWBUF* pPacket); void handle_field(GWBUF* pPacket); void handle_row(GWBUF* pPacket); void handle_eof(GWBUF* pPacket); + void handle_large_payload(); + + void mask_values(ComResponse& response); private: typedef std::tr1::shared_ptr SMaskingRules; @@ -68,14 +72,17 @@ private: , m_nTotal_fields(0) , m_index(0) , m_multi_result(false) + , m_some_rule_matches(false) {} void reset(uint8_t command, const SMaskingRules& sRules) { + reset_multi(); + m_command = command; m_sRules = sRules; - - reset_multi(); + m_multi_result = false; + m_some_rule_matches = false; } void reset_multi() @@ -97,6 +104,11 @@ private: return m_sRules; } + bool some_rule_matches() const + { + return m_some_rule_matches; + } + bool is_multi_result() const { return m_multi_result; @@ -117,6 +129,11 @@ private: m_types.push_back(type); m_rules.push_back(pRule); + if (pRule) + { + m_some_rule_matches = true; + } + return m_rules.size() == m_nTotal_fields; } @@ -137,13 +154,14 @@ private: } private: - uint8_t m_command; /* m_types; /* m_rules; /* m_types; /* m_rules; /* #include diff --git a/server/modules/filter/masking/mysql.hh b/server/modules/filter/masking/mysql.hh index 72c9b7340..678f5e8ca 100644 --- a/server/modules/filter/masking/mysql.hh +++ b/server/modules/filter/masking/mysql.hh @@ -488,9 +488,14 @@ public: ERR_PACKET = 0xff, }; - uint32_t packet_len() const + enum { - return m_packet_len; + MAX_PAYLOAD_LEN = 0xffffff + }; + + uint32_t payload_len() const + { + return m_payload_len; } uint8_t packet_no() const { @@ -501,7 +506,7 @@ protected: ComPacket(GWBUF* pPacket) : m_pPacket(pPacket) , m_pData(GWBUF_DATA(pPacket)) - , m_packet_len(MYSQL_GET_PAYLOAD_LEN(m_pData)) + , m_payload_len(MYSQL_GET_PAYLOAD_LEN(m_pData)) , m_packet_no(MYSQL_GET_PACKET_NO(m_pData)) { m_pData += MYSQL_HEADER_LEN; @@ -510,7 +515,7 @@ protected: ComPacket(const ComPacket& packet) : m_pPacket(packet.m_pPacket) , m_pData(GWBUF_DATA(m_pPacket)) - , m_packet_len(packet.m_packet_len) + , m_payload_len(packet.m_payload_len) , m_packet_no(packet.m_packet_no) { m_pData += MYSQL_HEADER_LEN; @@ -520,7 +525,7 @@ protected: uint8_t* m_pData; private: - uint32_t m_packet_len; + uint32_t m_payload_len; uint8_t m_packet_no; };