Coverage Report

Created: 2026-05-16 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/PcapPlusPlus/Packet++/header/MySqlLayer.h
Line
Count
Source
1
#pragma once
2
3
#include "Layer.h"
4
#include "PointerVector.h"
5
#include <memory>
6
#include <ostream>
7
#include <unordered_map>
8
9
/// @file
10
11
/// @namespace pcpp
12
/// @brief The main namespace for the PcapPlusPlus lib
13
namespace pcpp
14
{
15
16
  /// @enum MySqlMessageOrigin
17
  /// Indicates whether the message is from the client or server
18
  enum class MySqlMessageOrigin
19
  {
20
    /// Message is from the MySQL client
21
    Client,
22
    /// Message is from the MySQL server
23
    Server
24
  };
25
26
  /// @class MySqlMessageType
27
  /// Represents MySQL message types
28
  class MySqlMessageType
29
  {
30
  public:
31
    /// Define enum types for MySQL message types
32
    enum Value : uint8_t
33
    {
34
      /// Handshake response
35
      Client_HandshakeResponse,
36
      /// COM_SLEEP command
37
      Client_Sleep,
38
      /// COM_QUIT command - close connection
39
      Client_Quit,
40
      /// COM_INIT_DB command - change default database
41
      Client_InitDb,
42
      /// COM_QUERY command - execute SQL query
43
      Client_Query,
44
      /// COM_FIELD_LIST command - get field information for a table
45
      Client_FieldList,
46
      /// COM_CREATE_DB command
47
      Client_CreateDb,
48
      /// COM_DROP_DB command
49
      Client_DropDb,
50
      /// COM_REFRESH command - flush tables, caches, or logs
51
      Client_Refresh,
52
      /// COM_SHUTDOWN command - shutdown the server
53
      Client_Shutdown,
54
      /// COM_STATISTICS command - get server status information
55
      Client_Statistics,
56
      /// COM_PROCESS_INFO command - get list of active threads
57
      Client_ProcessInfo,
58
      /// COM_CONNECT command - connect to server (internal use)
59
      Client_Connect,
60
      /// COM_PROCESS_KILL command - kill a server thread
61
      Client_ProcessKill,
62
      /// COM_DEBUG command - send debug info to server
63
      Client_Debug,
64
      /// COM_PING command - check server availability
65
      Client_Ping,
66
      /// COM_TIME command
67
      Client_Time,
68
      /// COM_DELAYED_INSERT command
69
      Client_DelayedInsert,
70
      /// COM_CHANGE_USER command - change user and database
71
      Client_ChangeUser,
72
      /// COM_BINLOG_DUMP command - start binary log dump (slave replication)
73
      Client_BinlogDump,
74
      /// COM_TABLE_DUMP command - dump table data (slave replication)
75
      Client_TableDump,
76
      /// COM_CONNECT_OUT command - slave connecting to master (internal use)
77
      Client_ConnectOut,
78
      /// COM_REGISTER_SLAVE command - register slave with master
79
      Client_RegisterSlave,
80
      /// COM_STMT_PREPARE command - prepare statement
81
      Client_StmtPrepare,
82
      /// COM_STMT_EXECUTE command - execute prepared statement
83
      Client_StmtExecute,
84
      /// COM_STMT_FETCH command - fetch rows from prepared statement
85
      Client_StmtFetch,
86
      /// COM_STMT_CLOSE command - close prepared statement
87
      Client_StmtClose,
88
      /// COM_STMT_RESET command - reset prepared statement data
89
      Client_StmtReset,
90
      /// COM_SET_OPTION command - set option (e.g., multi-statements)
91
      Client_SetOption,
92
      /// COM_STMT_SEND_LONG_DATA command - send long data for prepared statement
93
      Client_StmtSendLongData,
94
      /// COM_DAEMON command
95
      Client_Daemon,
96
      /// COM_BINLOG_DUMP_GTID command - start GTID-based binary log dump
97
      Client_BinlogDumpGtid,
98
      /// COM_RESET_CONNECTION command - reset connection without re-authentication
99
      Client_ResetConnection,
100
      /// COM_CLONE command
101
      Client_Clone,
102
103
      /// Initial handshake
104
      Server_Handshake,
105
      /// OK packet - successful response from server
106
      Server_Ok,
107
      /// AuthSwitchRequest packet - server requests authentication method switch
108
      Server_AuthSwitchRequest,
109
      /// EOF message
110
      Server_EOF,
111
      /// Error packet - error response from server
112
      Server_Error,
113
      /// Server message that contains data (could be column definition, row data, result set header, etc.)
114
      Server_Data,
115
116
      /// Unknown message
117
      Unknown
118
    };
119
120
    constexpr MySqlMessageType() : m_Value(Unknown)
121
0
    {}
122
123
    // cppcheck-suppress noExplicitConstructor
124
    /// @brief Constructs a MySqlMessageType object from a Value enum
125
    /// @param[in] value The Value enum value
126
52
    constexpr MySqlMessageType(Value value) : m_Value(value)
127
52
    {}
128
129
    /// @brief Returns a string representation of the message type
130
    /// @return A string representation of the message type
131
    std::string toString() const;
132
133
    /// @brief Stream operator for MySqlMessageType
134
    /// @param[in] os The output stream
135
    /// @param[in] messageType The message type to print
136
    /// @return The output stream
137
    friend std::ostream& operator<<(std::ostream& os, const MySqlMessageType& messageType)
138
0
    {
139
0
      os << messageType.toString();
140
0
      return os;
141
0
    }
142
143
    /// @brief Converts the message type to a string
144
    /// @return The message type as a string
145
    explicit operator std::string() const
146
0
    {
147
0
      return toString();
148
0
    }
149
150
    /// @brief Returns the origin of the message (client or server)
151
    /// @return The message origin
152
    MySqlMessageOrigin getOrigin() const;
153
154
    // Allow switch and comparisons
155
    constexpr operator Value() const
156
0
    {
157
0
      return m_Value;
158
0
    }
159
160
    // Prevent usage: if(MySqlMessageType)
161
    explicit operator bool() const = delete;
162
163
  private:
164
    Value m_Value;
165
  };
166
167
  /// @class MySqlMessage
168
  /// Represents a MySQL message (base class)
169
  class MySqlMessage
170
  {
171
  public:
172
26
    virtual ~MySqlMessage() = default;
173
174
    /// @brief Parse a MySQL message from raw data
175
    /// @param[in] data A pointer to the raw data
176
    /// @param[in] dataLen Size of the data in bytes
177
    /// @param[in] origin The message origin (client or server)
178
    /// @return A unique pointer to the parsed MySqlMessage, or nullptr if parsing fails
179
    static std::unique_ptr<MySqlMessage> parseMySqlMessage(const uint8_t* data, size_t dataLen,
180
                                                           MySqlMessageOrigin origin);
181
182
    /// @return The message type
183
    MySqlMessageType getMessageType() const
184
0
    {
185
0
      return m_MessageType;
186
0
    }
187
188
    /// @return The message origin (client or server)
189
    MySqlMessageOrigin getMessageOrigin() const
190
0
    {
191
0
      return m_MessageOrigin;
192
0
    }
193
194
    /// @brief Returns the length of the message payload
195
    /// @return The message length
196
    virtual uint32_t getMessageLength() const;
197
198
    /// @brief Returns the packet number
199
    /// @return The packet number
200
    uint8_t getPacketNumber() const;
201
202
    /// @brief Returns the total length of the message including the length field
203
    /// @return The total message length in bytes
204
    size_t getTotalMessageLength() const
205
52
    {
206
52
      return m_DataLen;
207
52
    }
208
209
    /// @brief Returns the raw payload bytes of the message
210
    /// @return The raw payload bytes of the message
211
    virtual std::vector<uint8_t> getRawPayload() const;
212
213
  protected:
214
    MySqlMessage(const uint8_t* data, size_t dataLen, const MySqlMessageType& messageType,
215
                 MySqlMessageOrigin origin)
216
26
        : m_Data(data), m_DataLen(dataLen), m_MessageType(messageType), m_MessageOrigin(origin)
217
26
    {}
218
219
    static constexpr int basicMessageLength = 4;
220
    static constexpr int commandLength = 1;
221
    static constexpr int packetNumberIndex = 3;
222
    static constexpr int commandIndex = packetNumberIndex + 1;
223
224
    const uint8_t* m_Data;
225
    size_t m_DataLen;
226
    MySqlMessageType m_MessageType;
227
    MySqlMessageOrigin m_MessageOrigin;
228
  };
229
230
  /// @class MySqlCommandMessage
231
  /// Represents a MySQL messages that are commands such as Query (3), StatementPrepare (22), etc.
232
  /// Or that messages that have response code such as Ok (0), Error (0xFF)
233
  class MySqlCommandMessage : public MySqlMessage
234
  {
235
    friend class MySqlMessage;
236
237
  public:
238
    uint32_t getMessageLength() const override;
239
    std::vector<uint8_t> getRawPayload() const override;
240
241
  protected:
242
    MySqlCommandMessage(const uint8_t* data, size_t dataLen, const MySqlMessageType& messageType,
243
                        MySqlMessageOrigin origin)
244
15
        : MySqlMessage(data, dataLen, messageType, origin)
245
15
    {}
246
  };
247
248
  /// @class MySqlQueryMessage
249
  /// Represents a MySQL query command message
250
  class MySqlQueryMessage : public MySqlCommandMessage
251
  {
252
    friend class MySqlMessage;
253
254
  public:
255
    /// @return The SQL query string
256
    std::string getQuery() const;
257
258
  protected:
259
    MySqlQueryMessage(const uint8_t* data, size_t dataLen)
260
0
        : MySqlCommandMessage(data, dataLen, MySqlMessageType::Client_Query, MySqlMessageOrigin::Client)
261
0
    {}
262
263
  private:
264
    static constexpr int statementIndex = commandIndex + 3;
265
  };
266
267
  /// @class MySqlErrorMessage
268
  /// Represents a MySQL error message from the server
269
  class MySqlErrorMessage : public MySqlCommandMessage
270
  {
271
    friend class MySqlMessage;
272
273
  public:
274
    /// @return The MySQL error code
275
    uint16_t getErrorCode() const;
276
277
    /// @return The SQL state string (5 characters)
278
    std::string getSqlState() const;
279
280
    /// @return The error message string
281
    std::string getErrorMessage() const;
282
283
  protected:
284
    MySqlErrorMessage(const uint8_t* data, size_t dataLen)
285
0
        : MySqlCommandMessage(data, dataLen, MySqlMessageType::Server_Error, MySqlMessageOrigin::Server)
286
0
    {}
287
288
  private:
289
    static constexpr int errorCodeIndex = commandIndex + 1;
290
    static constexpr int sqlStateIndex = errorCodeIndex + sizeof(uint16_t) + 1;
291
    static constexpr int sqlStateSize = 5;
292
    static constexpr int errorMessageIndex = sqlStateIndex + sqlStateSize;
293
  };
294
295
  /// @class MySqlLayer
296
  /// Represents a MySQL protocol layer
297
  class MySqlLayer : public Layer
298
  {
299
  public:
300
    /// @brief Destructor for this layer
301
291
    ~MySqlLayer() override = default;
302
303
    /// @brief Check whether the port is considered as MySQL
304
    /// @param[in] port The port number to be checked
305
    /// @return True if the port is 3306 (MySQL default port), false otherwise
306
    static bool isMySqlPort(uint16_t port)
307
378k
    {
308
378k
      return port == 3306;
309
378k
    }
310
311
    /// @brief Parse a MySQL client message
312
    /// @param[in] data A pointer to the raw data
313
    /// @param[in] dataLen Size of the data in bytes
314
    /// @param[in] prevLayer The previous layer
315
    /// @param[in] packet The packet being parsed
316
    /// @return A pointer to the parsed MySqlLayer, or nullptr if parsing fails
317
    static MySqlLayer* parseMySqlClientMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet);
318
319
    /// @brief Parse a MySQL server message
320
    /// @param[in] data A pointer to the raw data
321
    /// @param[in] dataLen Size of the data in bytes
322
    /// @param[in] prevLayer The previous layer
323
    /// @param[in] packet The packet being parsed
324
    /// @return A pointer to the parsed MySqlLayer, or nullptr if parsing fails
325
    static MySqlLayer* parseMySqlServerMessage(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet);
326
327
    /// @return The message origin (client or server)
328
    MySqlMessageOrigin getMySqlOrigin() const
329
0
    {
330
0
      return m_MessageOrigin;
331
0
    }
332
333
    /// @return A vector of all MySQL messages in this layer
334
    const PointerVector<MySqlMessage>& getMySqlMessages() const;
335
336
    /// @brief Get a MySQL message by its type
337
    /// @param[in] messageType The type of message to retrieve
338
    /// @return A pointer to the message, or nullptr if not found
339
    const MySqlMessage* getMySqlMessage(const MySqlMessageType& messageType) const;
340
341
    /// @brief Get a MySQL message by its type (template version)
342
    /// @tparam TMessage The message type to retrieve (must derive from MySqlMessage)
343
    /// @return A pointer to the message of the specified type, or nullptr if not found
344
    template <class TMessage, std::enable_if_t<std::is_base_of<MySqlMessage, TMessage>::value, bool> = nullptr>
345
    const TMessage* getMySqlMessage() const
346
    {
347
      const auto& messages = getMySqlMessages();
348
      for (const auto& msg : messages)
349
      {
350
        auto result = dynamic_cast<const TMessage*>(msg);
351
        if (result != nullptr)
352
        {
353
          return result;
354
        }
355
      }
356
      return nullptr;
357
    }
358
359
    // Overridden methods
360
361
    /// @return The size of the MySQL layer header in bytes
362
    size_t getHeaderLen() const override
363
58
    {
364
58
      return m_DataLen;
365
58
    }
366
367
    /// Does nothing for this layer, MySQL is always last
368
    void parseNextLayer() override
369
291
    {}
370
371
    /// Does nothing for this layer
372
    void computeCalculateFields() override
373
58
    {}
374
375
    /// @return The OSI layer level of MySQL (Application Layer).
376
    OsiModelLayer getOsiModelLayer() const override
377
58
    {
378
58
      return OsiModelApplicationLayer;
379
58
    }
380
381
    /// @return Returns the protocol info as readable string
382
    std::string toString() const override;
383
384
  private:
385
    MySqlMessageOrigin m_MessageOrigin;
386
    mutable PointerVector<MySqlMessage> m_Messages;
387
    mutable bool m_MessagesInitialized = false;
388
389
    MySqlLayer(uint8_t* data, size_t dataLen, Layer* prevLayer, Packet* packet, MySqlMessageOrigin origin)
390
291
        : Layer(data, dataLen, prevLayer, packet, MySQL), m_MessageOrigin(origin)
391
291
    {}
392
  };
393
394
}  // namespace pcpp