/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 |