1 /* Copyright (c) 2011, 2021, Oracle and/or its affiliates.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
23 #include "binary_log_types.h"
24
25 #include "statement_events.h"
26
27 #include <algorithm>
28 #include <stdint.h>
29
30 const unsigned char checksum_version_split[3]= {5, 6, 1};
31 const unsigned long checksum_version_product=
32 (checksum_version_split[0] * 256 + checksum_version_split[1]) * 256 +
33 checksum_version_split[2];
34
35
36 namespace binary_log_debug
37 {
38 bool debug_query_mts_corrupt_db_names= false;
39 bool debug_checksum_test= false;
40 bool debug_simulate_invalid_address= false;
41 bool debug_pretend_version_50034_in_binlog= false;
42 }
43
44 namespace binary_log
45 {
46 /**
47 The method returns the checksum algorithm used to checksum the binary log.
48 For MySQL server versions < 5.6, the algorithm is undefined. For the higher
49 versions, the type is decoded from the FORMAT_DESCRIPTION_EVENT.
50
51 @param buf buffer holding serialized FD event
52 @param len netto (possible checksum is stripped off) length of the event buf
53
54 @return the version-safe checksum alg descriptor where zero
55 designates no checksum, 255 - the orginator is
56 checksum-unaware (effectively no checksum) and the actuall
57 [1-254] range alg descriptor.
58 */
59 enum_binlog_checksum_alg
get_checksum_alg(const char * buf,unsigned long len)60 Log_event_footer::get_checksum_alg(const char* buf, unsigned long len)
61 {
62 enum_binlog_checksum_alg ret;
63 char version[ST_SERVER_VER_LEN];
64 unsigned char version_split[3];
65 BAPI_ASSERT(buf[EVENT_TYPE_OFFSET] == FORMAT_DESCRIPTION_EVENT);
66 memcpy(version, buf +
67 buf[LOG_EVENT_MINIMAL_HEADER_LEN + ST_COMMON_HEADER_LEN_OFFSET]
68 + ST_SERVER_VER_OFFSET, ST_SERVER_VER_LEN);
69 version[ST_SERVER_VER_LEN - 1]= 0;
70
71 do_server_version_split(version, version_split);
72 if (version_product(version_split) < checksum_version_product)
73 ret= BINLOG_CHECKSUM_ALG_UNDEF;
74 else
75 ret= static_cast<enum_binlog_checksum_alg>(*(buf + len -
76 BINLOG_CHECKSUM_LEN -
77 BINLOG_CHECKSUM_ALG_DESC_LEN));
78 BAPI_ASSERT(ret == BINLOG_CHECKSUM_ALG_OFF ||
79 ret == BINLOG_CHECKSUM_ALG_UNDEF ||
80 ret == BINLOG_CHECKSUM_ALG_CRC32);
81 return ret;
82 }
83
84 /**
85 Log_event_header constructor
86
87 @param buf the buffer containing the complete information
88 including the event and the header data
89
90 @param description_event first constructor of Format_description_event,
91 used to extract the binlog_version
92 */
93 Log_event_header::
Log_event_header(const char * buf,uint16_t binlog_version)94 Log_event_header(const char* buf, uint16_t binlog_version)
95 : data_written(0), log_pos(0)
96 {
97 uint32_t tmp_sec;
98 memcpy(&tmp_sec, buf, sizeof(tmp_sec));
99 when.tv_sec= le32toh(tmp_sec);
100 when.tv_usec= 0;
101 type_code= static_cast<Log_event_type>(buf[EVENT_TYPE_OFFSET]);
102 memcpy(&unmasked_server_id,
103 buf + SERVER_ID_OFFSET, sizeof(unmasked_server_id));
104
105 unmasked_server_id= le32toh(unmasked_server_id);
106
107 /**
108 @verbatim
109 The first 13 bytes in the header is as follows:
110 +============================================+
111 | member_variable offset : len |
112 +============================================+
113 | when.tv_sec 0 : 4 |
114 +--------------------------------------------+
115 | type_code EVENT_TYPE_OFFSET(4) : 1 |
116 +--------------------------------------------+
117 | server_id SERVER_ID_OFFSET(5) : 4 |
118 +--------------------------------------------+
119 | data_written EVENT_LEN_OFFSET(9) : 4 |
120 +============================================+
121 @endverbatim
122 */
123 memcpy(&data_written, buf + EVENT_LEN_OFFSET, 4);
124 data_written= le64toh(data_written);
125
126 memcpy(&log_pos, buf + LOG_POS_OFFSET, 4);
127 log_pos= le64toh(log_pos);
128
129 switch (binlog_version)
130 {
131 case 1:
132 log_pos= 0;
133 flags= 0;
134 break;
135
136 case 3:
137 /*
138 If the log is 4.0 (so here it can only be a 4.0 relay log read by
139 the SQL thread or a 4.0 master binlog read by the I/O thread),
140 log_pos is the beginning of the event: we transform it into the end
141 of the event, which is more useful.
142 But how do you know that the log is 4.0: you know it if
143 description_event is version 3 *and* you are not reading a
144 Format_desc (remember that mysqlbinlog starts by assuming that 5.0
145 logs are in 4.0 format, until it finds a Format_desc).
146 */
147 if (buf[EVENT_TYPE_OFFSET] < FORMAT_DESCRIPTION_EVENT && log_pos)
148 {
149 /*
150 If log_pos=0, don't change it. log_pos==0 is a marker to mean
151 "don't change rli->group_master_log_pos" (see
152 inc_group_relay_log_pos()). As it is unreal log_pos, adding the
153 event len's is not correct. For example, a fake Rotate event should
154 not have its log_pos (which is 0) changed or it will modify
155 Exec_master_log_pos in SHOW SLAVE STATUS, displaying a wrong
156 value of (a non-zero offset which does not exist in the master's
157 binlog, so which will cause problems if the user uses this value
158 in CHANGE MASTER).
159 */
160 log_pos+= data_written; /* purecov: inspected */
161 }
162
163 /* 4.0 or newer */
164 /**
165 @verbatim
166 Additional header fields include:
167 +=============================================+
168 | member_variable offset : len |
169 +=============================================+
170 | log_pos LOG_POS_OFFSET(13) : 4 |
171 +---------------------------------------------+
172 | flags FLAGS_OFFSET(17) : 1 |
173 +---------------------------------------------+
174 | extra_headers 19 : x-19 |
175 +=============================================+
176 extra_headers are not used in the current version.
177 @endverbatim
178 */
179 // Fall through.
180 default:
181 memcpy(&flags, buf + FLAGS_OFFSET, sizeof(flags));
182 flags= le16toh(flags);
183
184 if ((buf[EVENT_TYPE_OFFSET] == FORMAT_DESCRIPTION_EVENT) ||
185 (buf[EVENT_TYPE_OFFSET] == ROTATE_EVENT))
186 {
187 /*
188 These events always have a header which stops here (i.e. their
189 header is FROZEN).
190 */
191 /*
192 Initialization to zero of all other Log_event members as they're
193 not specified. Currently there are no such members; in the future
194 there will be an event UID (but Format_description and Rotate
195 don't need this UID, as they are not propagated through
196 --log-slave-updates (remember the UID is used to not play a query
197 twice when you have two masters which are slaves of a 3rd master).
198 Then we are done with decoding the header.
199 */
200 break;
201 }
202 /* otherwise, go on with reading the header from buf (nothing now) */
203 } //end switch (binlog_version)
204 BAPI_ASSERT(type_code < ENUM_END_EVENT || flags & LOG_EVENT_IGNORABLE_F);
205 }
206
207
208 /**
209 Tests the checksum algorithm used for the binary log, and asserts in case
210 if the checksum algorithm is invalid.
211
212 @param event_buf point to the buffer containing serialized event
213 @param event_len length of the event accounting possible
214 checksum alg
215 @param alg checksum algorithm used for the binary log
216
217 @retval true if test fails
218 @retval false as success
219 */
event_checksum_test(unsigned char * event_buf,unsigned long event_len,enum_binlog_checksum_alg alg)220 bool Log_event_footer::event_checksum_test(unsigned char *event_buf,
221 unsigned long event_len,
222 enum_binlog_checksum_alg alg)
223 {
224 bool res= false;
225 unsigned short flags= 0; // to store in FD's buffer flags orig value
226
227 if (alg != BINLOG_CHECKSUM_ALG_OFF && alg != BINLOG_CHECKSUM_ALG_UNDEF)
228 {
229 uint32_t incoming;
230 uint32_t computed;
231
232 if (event_buf[EVENT_TYPE_OFFSET] == FORMAT_DESCRIPTION_EVENT)
233 {
234 #ifndef NDEBUG
235 unsigned char fd_alg= event_buf[event_len - BINLOG_CHECKSUM_LEN -
236 BINLOG_CHECKSUM_ALG_DESC_LEN];
237 #endif
238 /*
239 FD event is checksummed and therefore verified w/o
240 the binlog-in-use flag.
241 */
242 memcpy(&flags, event_buf + FLAGS_OFFSET, sizeof(flags));
243 flags= le16toh(flags);
244 if (flags & LOG_EVENT_BINLOG_IN_USE_F)
245 event_buf[FLAGS_OFFSET] &= ~LOG_EVENT_BINLOG_IN_USE_F;
246 /*
247 The only algorithm currently is CRC32. Zero indicates
248 the binlog file is checksum-free *except* the FD-event.
249 */
250 #ifndef NDEBUG
251 BAPI_ASSERT(fd_alg == BINLOG_CHECKSUM_ALG_CRC32 || fd_alg == 0);
252 #endif
253 BAPI_ASSERT(alg == BINLOG_CHECKSUM_ALG_CRC32);
254 /*
255 Complile time guard to watch over the max number of alg
256 */
257 do_compile_time_assert(BINLOG_CHECKSUM_ALG_ENUM_END <= 0x80);
258 }
259 memcpy(&incoming,
260 event_buf + event_len - BINLOG_CHECKSUM_LEN, sizeof(incoming));
261 incoming= le32toh(incoming);
262
263 computed= checksum_crc32(0L, NULL, 0);
264 /* checksum the event content but not the checksum part itself */
265 computed= binary_log::checksum_crc32(computed,
266 (const unsigned char*) event_buf,
267 event_len - BINLOG_CHECKSUM_LEN);
268
269 if (flags != 0)
270 {
271 /* restoring the orig value of flags of FD */
272 BAPI_ASSERT(event_buf[EVENT_TYPE_OFFSET] == FORMAT_DESCRIPTION_EVENT);
273 event_buf[FLAGS_OFFSET]= static_cast<unsigned char>(flags);
274 }
275
276 res= !(computed == incoming);
277 }
278 #ifndef NDEBUG
279 if (binary_log_debug::debug_checksum_test)
280 return true;
281 #endif
282 return res;
283 }
284
285
286 /**
287 This ctor will create a new object of Log_event_header, and initialize
288 the variable m_header, which in turn will be used to initialize Log_event's
289 member common_header.
290 It will also advance the buffer after decoding the header(it is done through
291 the constructor of Log_event_header) and
292 will be pointing to the start of event data
293 */
Binary_log_event(const char ** buf,uint16_t binlog_version,const char * server_version)294 Binary_log_event::Binary_log_event(const char **buf, uint16_t binlog_version,
295 const char *server_version)
296 : m_header(*buf, binlog_version)
297 {
298 m_footer= Log_event_footer();
299 //buf is advanced in Binary_log_event constructor to point to beginning of
300 //post-header
301 (*buf)+= LOG_EVENT_HEADER_LEN;
302 }
303
304 /*
305 The destructor is pure virtual to prevent instantiation of the class.
306 */
~Binary_log_event()307 Binary_log_event::~Binary_log_event()
308 {
309 }
310
311 /**
312 This event type should never occur. It is never written to a binary log.
313 If an event is read from a binary log that cannot be recognized as something
314 else, it is treated as Unknown_event.
315
316 @param buf Contains the serialized event.
317 @param description_event An FDE event, used to get the following information
318 -binlog_version
319 -server_version
320 -post_header_len
321 -common_header_len
322 The content of this object
323 depends on the binlog-version currently in use.
324 */
Unknown_event(const char * buf,const Format_description_event * description_event)325 Unknown_event::Unknown_event(const char* buf,
326 const Format_description_event *description_event)
327 : Binary_log_event(&buf,
328 description_event->binlog_version,
329 description_event->server_version)
330 {
331 }
332 #ifndef HAVE_MYSYS
print_event_info(std::ostream & info)333 void Binary_log_event::print_event_info(std::ostream& info) {}
print_long_info(std::ostream & info)334 void Binary_log_event::print_long_info(std::ostream& info) {}
335 /**
336 This method is used by the binlog_browser to print short and long
337 information about the event. Since the body of Stop_event is empty
338 the relevant information contains only the timestamp.
339 Please note this is different from the print_event_info methods
340 used by mysqlbinlog.cc.
341
342 @param std output stream to which the event data is appended.
343 */
print_long_info(std::ostream & info)344 void Stop_event::print_long_info(std::ostream& info)
345 {
346 info << "Timestamp: " << header()->when.tv_sec;
347 this->print_event_info(info);
348 }
349
print_event_info(std::ostream & info)350 void Unknown_event::print_event_info(std::ostream& info)
351 {
352 info << "Unhandled event";
353 }
354
print_long_info(std::ostream & info)355 void Unknown_event::print_long_info(std::ostream& info)
356 {
357 info << "Timestamp: " << header()->when.tv_sec;
358 this->print_event_info(info);
359 }
360
361 #endif
362 } // end namespace binary_log
363