Address only specific type of columns when masking
Only columns that are of string kind are now subject to masking. With a textual resultset it would be possible to mask anything the same way, but with a binary resultset it is not. Thus, so that the result is not dependent upon whether the resultset happens to be textual or not, only string fields are accessed. Documentation to be updated in a separate change. The utility classes have now also been rearranged somewhat.
This commit is contained in:
@ -197,23 +197,23 @@ void MaskingFilterSession::handle_row(GWBUF* pPacket)
|
||||
{
|
||||
case MYSQL_COM_QUERY:
|
||||
{
|
||||
ComQueryResponse::Row row(response);
|
||||
ComQueryResponse::TextResultsetRow row(response, m_res.types());
|
||||
|
||||
ComQueryResponse::Row::iterator i = row.begin();
|
||||
ComQueryResponse::TextResultsetRow::iterator i = row.begin();
|
||||
while (i != row.end())
|
||||
{
|
||||
const MaskingRules::Rule* pRule = m_res.get_rule();
|
||||
|
||||
if (pRule)
|
||||
{
|
||||
LEncString s = *i;
|
||||
ComQueryResponse::TextResultsetRow::Value value = *i;
|
||||
|
||||
if (!s.is_null())
|
||||
if (value.is_string())
|
||||
{
|
||||
LEncString s = value.as_string();
|
||||
pRule->rewrite(s);
|
||||
}
|
||||
|
||||
MXS_NOTICE("String: %s", (*i).to_string().c_str());
|
||||
}
|
||||
++i;
|
||||
}
|
||||
@ -222,16 +222,16 @@ void MaskingFilterSession::handle_row(GWBUF* pPacket)
|
||||
|
||||
case MYSQL_COM_STMT_EXECUTE:
|
||||
{
|
||||
ComQueryResponse::BinaryRow row(response, m_res.types());
|
||||
ComQueryResponse::BinaryResultsetRow row(response, m_res.types());
|
||||
|
||||
ComQueryResponse::BinaryRow::iterator i = row.begin();
|
||||
ComQueryResponse::BinaryResultsetRow::iterator i = row.begin();
|
||||
while (i != row.end())
|
||||
{
|
||||
const MaskingRules::Rule* pRule = m_res.get_rule();
|
||||
|
||||
if (pRule)
|
||||
{
|
||||
ComQueryResponse::BinaryRow::Value value = *i;
|
||||
ComQueryResponse::BinaryResultsetRow::Value value = *i;
|
||||
|
||||
if (value.is_string())
|
||||
{
|
||||
|
@ -473,7 +473,11 @@ inline LEncString::iterator operator - (const LEncString::iterator& it, ptrdiff_
|
||||
return it;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @class ComPacket
|
||||
*
|
||||
* Base-class of all packet classes.
|
||||
*/
|
||||
class ComPacket
|
||||
{
|
||||
public:
|
||||
@ -490,45 +494,51 @@ public:
|
||||
protected:
|
||||
ComPacket(GWBUF* pPacket)
|
||||
: m_pPacket(pPacket)
|
||||
, m_pI(GWBUF_DATA(pPacket))
|
||||
, m_packet_len(MYSQL_GET_PAYLOAD_LEN(m_pI))
|
||||
, m_packet_no(MYSQL_GET_PACKET_NO(m_pI))
|
||||
, m_pData(GWBUF_DATA(pPacket))
|
||||
, m_packet_len(MYSQL_GET_PAYLOAD_LEN(m_pData))
|
||||
, m_packet_no(MYSQL_GET_PACKET_NO(m_pData))
|
||||
{
|
||||
m_pI += MYSQL_HEADER_LEN;
|
||||
m_pData += MYSQL_HEADER_LEN;
|
||||
}
|
||||
|
||||
ComPacket(const ComPacket& packet)
|
||||
: m_pPacket(packet.m_pPacket)
|
||||
, m_pI(GWBUF_DATA(m_pPacket))
|
||||
, m_pData(GWBUF_DATA(m_pPacket))
|
||||
, m_packet_len(packet.m_packet_len)
|
||||
, m_packet_no(packet.m_packet_no)
|
||||
{
|
||||
m_pI += MYSQL_HEADER_LEN;
|
||||
m_pData += MYSQL_HEADER_LEN;
|
||||
}
|
||||
|
||||
GWBUF* m_pPacket;
|
||||
uint8_t* m_pI;
|
||||
uint8_t* m_pData;
|
||||
|
||||
private:
|
||||
uint32_t m_packet_len;
|
||||
uint8_t m_packet_no;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @class ComResponse
|
||||
*
|
||||
* Base-class of all response packet classes.
|
||||
*/
|
||||
class ComResponse : public ComPacket
|
||||
{
|
||||
public:
|
||||
ComResponse(GWBUF* pPacket)
|
||||
: ComPacket(pPacket)
|
||||
, m_type(*m_pI)
|
||||
, m_type(*m_pData)
|
||||
{
|
||||
++m_pI;
|
||||
++m_pData;
|
||||
}
|
||||
|
||||
ComResponse(const ComResponse& packet)
|
||||
: ComPacket(packet)
|
||||
, m_type(packet.m_type)
|
||||
{
|
||||
++m_pI;
|
||||
++m_pData;
|
||||
}
|
||||
|
||||
uint8_t type() const
|
||||
@ -555,14 +565,19 @@ protected:
|
||||
uint8_t m_type;
|
||||
};
|
||||
|
||||
/**
|
||||
* @class ComRequest
|
||||
*
|
||||
* Base-class of all request packet classes.
|
||||
*/
|
||||
class ComRequest : public ComPacket
|
||||
{
|
||||
public:
|
||||
ComRequest(GWBUF* pPacket)
|
||||
: ComPacket(pPacket)
|
||||
, m_command(*m_pI)
|
||||
, m_command(*m_pData)
|
||||
{
|
||||
++m_pI;
|
||||
++m_pData;
|
||||
}
|
||||
|
||||
uint8_t command() const { return m_command; }
|
||||
@ -571,33 +586,41 @@ protected:
|
||||
uint8_t m_command;
|
||||
};
|
||||
|
||||
class ComQueryResponseColumnDef : public ComPacket
|
||||
/**
|
||||
* @class CQRColumnDef
|
||||
*
|
||||
* The column definition of the response of a @c ComQuery.
|
||||
*
|
||||
* @attention The name should not be used as such, but always using the
|
||||
* typedef @c ComQueryResponse::ColumnDef.
|
||||
*/
|
||||
class CQRColumnDef : public ComPacket
|
||||
{
|
||||
public:
|
||||
ComQueryResponseColumnDef(GWBUF* pPacket)
|
||||
CQRColumnDef(GWBUF* pPacket)
|
||||
: ComPacket(pPacket)
|
||||
, m_catalog(&m_pI)
|
||||
, m_schema(&m_pI)
|
||||
, m_table(&m_pI)
|
||||
, m_org_table(&m_pI)
|
||||
, m_name(&m_pI)
|
||||
, m_org_name(&m_pI)
|
||||
, m_length_fixed_fields(&m_pI)
|
||||
, m_catalog(&m_pData)
|
||||
, m_schema(&m_pData)
|
||||
, m_table(&m_pData)
|
||||
, m_org_table(&m_pData)
|
||||
, m_name(&m_pData)
|
||||
, m_org_name(&m_pData)
|
||||
, m_length_fixed_fields(&m_pData)
|
||||
{
|
||||
m_character_set = *reinterpret_cast<const uint16_t*>(m_pI);
|
||||
m_pI += 2;
|
||||
m_character_set = *reinterpret_cast<const uint16_t*>(m_pData);
|
||||
m_pData += 2;
|
||||
|
||||
m_column_length = *reinterpret_cast<const uint32_t*>(m_pI);
|
||||
m_pI += 4;
|
||||
m_column_length = *reinterpret_cast<const uint32_t*>(m_pData);
|
||||
m_pData += 4;
|
||||
|
||||
m_type = static_cast<enum_field_types>(*m_pI);
|
||||
m_pI += 1;
|
||||
m_type = static_cast<enum_field_types>(*m_pData);
|
||||
m_pData += 1;
|
||||
|
||||
m_flags = *reinterpret_cast<const uint16_t*>(m_pI);
|
||||
m_pI += 2;
|
||||
m_flags = *reinterpret_cast<const uint16_t*>(m_pData);
|
||||
m_pData += 2;
|
||||
|
||||
m_decimals = *m_pI;
|
||||
m_pI += 1;
|
||||
m_decimals = *m_pData;
|
||||
m_pData += 1;
|
||||
}
|
||||
|
||||
const LEncString& catalog() const { return m_catalog; }
|
||||
@ -641,106 +664,43 @@ private:
|
||||
uint8_t m_decimals;
|
||||
};
|
||||
|
||||
class ComQueryResponseRow : public ComPacket
|
||||
{
|
||||
public:
|
||||
class iterator : public std::iterator<std::forward_iterator_tag,
|
||||
LEncString,
|
||||
std::ptrdiff_t,
|
||||
LEncString*,
|
||||
LEncString>
|
||||
{
|
||||
public:
|
||||
iterator(uint8_t* pI = NULL)
|
||||
: m_pI(pI)
|
||||
{}
|
||||
|
||||
iterator& operator++()
|
||||
{
|
||||
LEncString s(&m_pI);
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator++(int)
|
||||
{
|
||||
iterator rv(*this);
|
||||
++(*this);
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool operator == (const iterator& rhs) const
|
||||
{
|
||||
return m_pI == rhs.m_pI;
|
||||
}
|
||||
|
||||
bool operator != (const iterator& rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
reference operator*()
|
||||
{
|
||||
return LEncString(m_pI);
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t* m_pI;
|
||||
};
|
||||
|
||||
ComQueryResponseRow(GWBUF* pPacket)
|
||||
: ComPacket(pPacket)
|
||||
{
|
||||
}
|
||||
|
||||
ComQueryResponseRow(const ComResponse& packet)
|
||||
: ComPacket(packet)
|
||||
{
|
||||
}
|
||||
|
||||
iterator begin()
|
||||
{
|
||||
return iterator(m_pI);
|
||||
}
|
||||
|
||||
iterator end()
|
||||
{
|
||||
uint8_t* pEnd = GWBUF_DATA(m_pPacket) + GWBUF_LENGTH(m_pPacket);
|
||||
return iterator(pEnd);
|
||||
}
|
||||
};
|
||||
|
||||
class ComQueryResponseBinaryRow : public ComPacket
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* An instance of Value represents a value in a binary resultset.
|
||||
* @class CQRResultsetValue
|
||||
*
|
||||
* An instance of this class represents a value in a resultset row. As this
|
||||
* currently is for the purpose of the masking filter, it effectively is useful
|
||||
* for accessing NULL and string values.
|
||||
*
|
||||
* @attention The name should not be used as such, but instead either
|
||||
* @c ComQueryResponse::TextResultsetRow::Value or
|
||||
* @c ComQueryResponse::TextResultsetRow::Value.
|
||||
*/
|
||||
class Value
|
||||
class CQRResultsetValue
|
||||
{
|
||||
public:
|
||||
Value()
|
||||
CQRResultsetValue()
|
||||
: m_type(MYSQL_TYPE_NULL)
|
||||
, m_pData(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
Value(enum_field_types type, uint8_t* pData)
|
||||
CQRResultsetValue(enum_field_types type, uint8_t* pData)
|
||||
: m_type(type)
|
||||
, m_pData(pData)
|
||||
{
|
||||
}
|
||||
|
||||
enum_field_types type() const
|
||||
{
|
||||
return m_type;
|
||||
}
|
||||
|
||||
LEncString as_string()
|
||||
{
|
||||
ss_dassert(is_string(m_type));
|
||||
ss_dassert(is_string());
|
||||
return LEncString(m_pData);
|
||||
}
|
||||
|
||||
bool is_null() const
|
||||
{
|
||||
return m_type == MYSQL_TYPE_NULL;
|
||||
}
|
||||
|
||||
bool is_string() const
|
||||
{
|
||||
return is_string(m_type);
|
||||
@ -750,45 +710,147 @@ public:
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case MYSQL_TYPE_BLOB:
|
||||
case MYSQL_TYPE_LONG_BLOB:
|
||||
case MYSQL_TYPE_MEDIUM_BLOB:
|
||||
case MYSQL_TYPE_STRING:
|
||||
case MYSQL_TYPE_TINY_BLOB:
|
||||
case MYSQL_TYPE_VARCHAR:
|
||||
case MYSQL_TYPE_VAR_STRING:
|
||||
return true;
|
||||
|
||||
// These, although returned as length-encoded strings are not considered
|
||||
// to be strings from the perspective of masking.
|
||||
// These, although returned as length-encoded strings, also in the case of
|
||||
// a binary resultset row, are not are not considered to be strings from the
|
||||
// perspective of masking.
|
||||
case MYSQL_TYPE_BIT:
|
||||
case MYSQL_TYPE_BLOB:
|
||||
case MYSQL_TYPE_DECIMAL:
|
||||
case MYSQL_TYPE_ENUM:
|
||||
case MYSQL_TYPE_GEOMETRY:
|
||||
case MYSQL_TYPE_LONG_BLOB:
|
||||
case MYSQL_TYPE_MEDIUM_BLOB:
|
||||
case MYSQL_TYPE_NEWDECIMAL:
|
||||
case MYSQL_TYPE_SET:
|
||||
case MYSQL_TYPE_TINY_BLOB:
|
||||
return false;
|
||||
|
||||
default:
|
||||
// Nothing else is considered to be strings even though, in the case of
|
||||
// a textual resultset, that's what they all are.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
protected:
|
||||
enum_field_types m_type;
|
||||
uint8_t* m_pData;
|
||||
};
|
||||
|
||||
/**
|
||||
* iterator is an iterator to values in a binary resultset.
|
||||
* @class CQRTextResultsetValue
|
||||
*
|
||||
* An instance of this class represents a value in a textual resultset row.
|
||||
*
|
||||
* @attention The name should not be used as such, but always using the
|
||||
* typedef @c ComQueryResponse::TextResultsetRow::Value.
|
||||
*/
|
||||
class iterator : public std::iterator<std::forward_iterator_tag,
|
||||
Value,
|
||||
std::ptrdiff_t,
|
||||
Value*,
|
||||
Value>
|
||||
class CQRTextResultsetValue : public CQRResultsetValue
|
||||
{
|
||||
public:
|
||||
CQRTextResultsetValue(enum_field_types type, uint8_t* pData)
|
||||
: CQRResultsetValue(type, pData)
|
||||
{
|
||||
if (*pData == 0xfb)
|
||||
{
|
||||
m_type = MYSQL_TYPE_NULL;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @class CQRBinaryResultsetValue
|
||||
*
|
||||
* An instance of this class represents a value in a binary resultset row.
|
||||
*
|
||||
* @attention The name should not be used as such, but always using the
|
||||
* typedef @c ComQueryResponse::BinaryResultsetRow::Value.
|
||||
*/
|
||||
typedef CQRResultsetValue CQRBinaryResultsetValue;
|
||||
|
||||
/**
|
||||
* @class CQRTextResultsetRowIterator
|
||||
*
|
||||
* An STL compatible iterator that iterates over the values in a textual resultset.
|
||||
*
|
||||
* @attention The name should not be used as such, but always using the
|
||||
* typedef @c ComQueryResponse::TextResultset::iterator.
|
||||
*/
|
||||
class CQRTextResultsetRowIterator : public std::iterator<std::forward_iterator_tag,
|
||||
CQRTextResultsetValue,
|
||||
std::ptrdiff_t,
|
||||
CQRTextResultsetValue*,
|
||||
CQRTextResultsetValue>
|
||||
{
|
||||
public:
|
||||
typedef CQRTextResultsetValue Value;
|
||||
|
||||
CQRTextResultsetRowIterator(uint8_t* pData, const std::vector<enum_field_types>& types)
|
||||
: m_pData(pData)
|
||||
, m_iTypes(types.begin())
|
||||
{}
|
||||
|
||||
CQRTextResultsetRowIterator(uint8_t* pData)
|
||||
: m_pData(pData)
|
||||
{}
|
||||
|
||||
CQRTextResultsetRowIterator& operator++()
|
||||
{
|
||||
// In the textual protocol, every value is a length encoded string.
|
||||
LEncString s(&m_pData);
|
||||
++m_iTypes;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CQRTextResultsetRowIterator operator++(int)
|
||||
{
|
||||
CQRTextResultsetRowIterator rv(*this);
|
||||
++(*this);
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool operator == (const CQRTextResultsetRowIterator& rhs) const
|
||||
{
|
||||
return m_pData == rhs.m_pData;
|
||||
}
|
||||
|
||||
bool operator != (const CQRTextResultsetRowIterator& rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
CQRTextResultsetValue operator*()
|
||||
{
|
||||
return Value(*m_iTypes, m_pData);
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t* m_pData;
|
||||
std::vector<enum_field_types>::const_iterator m_iTypes;
|
||||
};
|
||||
|
||||
/**
|
||||
* @class CQRBinaryResultsetRowIterator
|
||||
*
|
||||
* An STL compatible iterator that iterates over the values in a binary resultset.
|
||||
*
|
||||
* @attention The name should not be used as such, but always using the
|
||||
* typedef @c ComQueryResponse::BinaryResultset::iterator.
|
||||
*/
|
||||
class CQRBinaryResultsetRowIterator : public std::iterator<std::forward_iterator_tag,
|
||||
CQRBinaryResultsetValue,
|
||||
std::ptrdiff_t,
|
||||
CQRBinaryResultsetValue*,
|
||||
CQRBinaryResultsetValue>
|
||||
{
|
||||
public:
|
||||
typedef CQRBinaryResultsetValue Value;
|
||||
|
||||
/**
|
||||
* A bit_iterator is an iterator to bits in an array of bytes.
|
||||
*
|
||||
@ -838,7 +900,7 @@ public:
|
||||
uint8_t m_mask; /*< Mask representing the current bit of the current byte. */
|
||||
};
|
||||
|
||||
iterator(uint8_t* pData, const std::vector<enum_field_types>& types)
|
||||
CQRBinaryResultsetRowIterator(uint8_t* pData, const std::vector<enum_field_types>& types)
|
||||
: m_pData(pData)
|
||||
, m_iTypes(types.begin())
|
||||
, m_iNulls(pData + 1)
|
||||
@ -852,12 +914,12 @@ public:
|
||||
m_pData += nNull_bytes;
|
||||
}
|
||||
|
||||
iterator(uint8_t* pData)
|
||||
CQRBinaryResultsetRowIterator(uint8_t* pData)
|
||||
: m_pData(pData)
|
||||
{
|
||||
}
|
||||
|
||||
iterator& operator++()
|
||||
CQRBinaryResultsetRowIterator& operator++()
|
||||
{
|
||||
// See https://dev.mysql.com/doc/internals/en/binary-protocol-value.html
|
||||
switch (*m_iTypes)
|
||||
@ -941,19 +1003,19 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator++(int)
|
||||
CQRBinaryResultsetRowIterator operator++(int)
|
||||
{
|
||||
iterator rv(*this);
|
||||
CQRBinaryResultsetRowIterator rv(*this);
|
||||
++(*this);
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool operator == (const iterator& rhs) const
|
||||
bool operator == (const CQRBinaryResultsetRowIterator& rhs) const
|
||||
{
|
||||
return m_pData == rhs.m_pData;
|
||||
}
|
||||
|
||||
bool operator != (const iterator& rhs) const
|
||||
bool operator != (const CQRBinaryResultsetRowIterator& rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
@ -976,14 +1038,27 @@ public:
|
||||
bit_iterator m_iNulls;
|
||||
};
|
||||
|
||||
ComQueryResponseBinaryRow(GWBUF* pPacket,
|
||||
/**
|
||||
* @template CQRResultsetRow
|
||||
*
|
||||
* A template that when instantiated either represents a textual or a
|
||||
* binary resultset row.
|
||||
*/
|
||||
template<class Iterator>
|
||||
class CQRResultsetRow : public ComPacket
|
||||
{
|
||||
public:
|
||||
typedef typename Iterator::Value Value;
|
||||
typedef Iterator iterator;
|
||||
|
||||
CQRResultsetRow(GWBUF* pPacket,
|
||||
const std::vector<enum_field_types>& types)
|
||||
: ComPacket(pPacket)
|
||||
, m_types(types)
|
||||
{
|
||||
}
|
||||
|
||||
ComQueryResponseBinaryRow(const ComResponse& packet,
|
||||
CQRResultsetRow(const ComResponse& packet,
|
||||
const std::vector<enum_field_types>& types)
|
||||
: ComPacket(packet)
|
||||
, m_types(types)
|
||||
@ -992,7 +1067,7 @@ public:
|
||||
|
||||
iterator begin()
|
||||
{
|
||||
return iterator(m_pI, m_types);
|
||||
return iterator(m_pData, m_types);
|
||||
}
|
||||
|
||||
iterator end()
|
||||
@ -1005,22 +1080,41 @@ private:
|
||||
const std::vector<enum_field_types>& m_types;
|
||||
};
|
||||
|
||||
/**
|
||||
* @class CQRTextResultsetRow
|
||||
*
|
||||
* An instance of this class represents a textual resultset row.
|
||||
*/
|
||||
typedef CQRResultsetRow<CQRTextResultsetRowIterator> CQRTextResultsetRow;
|
||||
|
||||
/**
|
||||
* @class CQRBinaryResultsetRow
|
||||
*
|
||||
* An instance of this class represents a binary resultset row.
|
||||
*/
|
||||
typedef CQRResultsetRow<CQRBinaryResultsetRowIterator> CQRBinaryResultsetRow;
|
||||
|
||||
/**
|
||||
* @class ComQueryResponse
|
||||
*
|
||||
* An instance of this class represents the response to a @c ComQuery.
|
||||
*/
|
||||
class ComQueryResponse : public ComPacket
|
||||
{
|
||||
public:
|
||||
typedef ComQueryResponseColumnDef ColumnDef;
|
||||
typedef ComQueryResponseRow Row;
|
||||
typedef ComQueryResponseBinaryRow BinaryRow;
|
||||
typedef CQRColumnDef ColumnDef;
|
||||
typedef CQRTextResultsetRow TextResultsetRow;
|
||||
typedef CQRBinaryResultsetRow BinaryResultsetRow;
|
||||
|
||||
ComQueryResponse(GWBUF* pPacket)
|
||||
: ComPacket(pPacket)
|
||||
, m_nFields(&m_pI)
|
||||
, m_nFields(&m_pData)
|
||||
{
|
||||
}
|
||||
|
||||
ComQueryResponse(const ComResponse& packet)
|
||||
: ComPacket(packet)
|
||||
, m_nFields(&m_pI)
|
||||
, m_nFields(&m_pData)
|
||||
{
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user