Binlog files have 15 bytes of header XORed with IV
Events saved and read have 15 bytes of header XORed with IV. Partial events are still not handled. Next implementation will encrypt the whole event instead of 15 bytes XOR
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016 MariaDB Corporation Ab
|
||||
* Copyright (c) 201nMariaDB Corporation Ab
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
@ -97,6 +97,7 @@ extern int blr_file_new_binlog(ROUTER_INSTANCE *router, char *file);
|
||||
extern int blr_file_write_master_config(ROUTER_INSTANCE *router, char *error);
|
||||
extern char *blr_extract_column(GWBUF *buf, int col);
|
||||
extern uint32_t extract_field(uint8_t *src, int bits);
|
||||
void blr_extract_header(register uint8_t *ptr, register REP_HEADER *hdr);
|
||||
int blr_file_get_next_binlogname(ROUTER_INSTANCE *router);
|
||||
static void encode_value(unsigned char *data, unsigned int value, int len);
|
||||
static int blr_slave_query(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, GWBUF *queue);
|
||||
@ -109,7 +110,7 @@ int blr_slave_catchup(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, bool large);
|
||||
uint8_t *blr_build_header(GWBUF *pkt, REP_HEADER *hdr);
|
||||
int blr_slave_callback(DCB *dcb, DCB_REASON reason, void *data);
|
||||
static int blr_slave_fake_rotate(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, BLFILE** filep);
|
||||
static void blr_slave_send_fde(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave);
|
||||
static uint32_t blr_slave_send_fde(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, GWBUF *fde);
|
||||
static int blr_slave_send_maxscale_version(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave);
|
||||
static int blr_slave_send_server_id(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave);
|
||||
static int blr_slave_send_maxscale_variables(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave);
|
||||
@ -164,6 +165,8 @@ static int blr_slave_send_columndef_with_status_schema(ROUTER_INSTANCE *router,
|
||||
static void blr_send_slave_heartbeat(void *inst);
|
||||
static int blr_slave_send_heartbeat(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave);
|
||||
static int blr_set_master_ssl(ROUTER_INSTANCE *router, CHANGE_MASTER_OPTIONS config, char *error_message);
|
||||
static int blr_slave_read_ste(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, uint32_t fde_end_pos);
|
||||
static GWBUF *blr_slave_read_fde(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave);
|
||||
|
||||
void poll_fake_write_event(DCB *dcb);
|
||||
|
||||
@ -1965,6 +1968,7 @@ blr_slave_binlog_dump(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, GWBUF *queue
|
||||
int len, rval, binlognamelen;
|
||||
REP_HEADER hdr;
|
||||
uint32_t chksum;
|
||||
uint32_t fde_end_pos;
|
||||
|
||||
ptr = GWBUF_DATA(queue);
|
||||
len = extract_field(ptr, 24);
|
||||
@ -2093,15 +2097,40 @@ blr_slave_binlog_dump(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, GWBUF *queue
|
||||
slave->lastReply = time(0);
|
||||
}
|
||||
|
||||
GWBUF *fde = blr_slave_read_fde(router, slave);
|
||||
if (fde == NULL)
|
||||
{
|
||||
// ERROR
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* FDE ends at pos 4 + FDE size */
|
||||
fde_end_pos = 4 + GWBUF_LENGTH(fde);
|
||||
|
||||
/* Send the FORMAT_DESCRIPTION_EVENT */
|
||||
if (slave->binlog_pos != 4)
|
||||
{
|
||||
blr_slave_send_fde(router, slave);
|
||||
blr_slave_send_fde(router, slave, fde);
|
||||
}
|
||||
|
||||
/* set lastEventReceived */
|
||||
slave->lastEventReceived = FORMAT_DESCRIPTION_EVENT;
|
||||
|
||||
/**
|
||||
* Check for START_ENCRYPTION_EVENT (after FDE) if
|
||||
* client request pos is greater than 4
|
||||
*
|
||||
* TODO: If router has binlog encryption take it
|
||||
* otherwise error
|
||||
* If no encryption and event found return error
|
||||
*
|
||||
* If event is found the contest is set into slave struct
|
||||
*/
|
||||
if (slave->binlog_pos != 4)
|
||||
{
|
||||
blr_slave_read_ste(router, slave, fde_end_pos);
|
||||
}
|
||||
|
||||
slave->dcb->low_water = router->low_water;
|
||||
slave->dcb->high_water = router->high_water;
|
||||
|
||||
@ -2298,22 +2327,82 @@ blr_slave_catchup(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, bool large)
|
||||
#endif
|
||||
int events_before = slave->stats.n_events;
|
||||
|
||||
/* Set file encryption context from slave pointer */
|
||||
spinlock_acquire(&slave->catch_lock);
|
||||
if (slave->encryption_ctx)
|
||||
{
|
||||
file->encryption_ctx = slave->encryption_ctx;
|
||||
}
|
||||
else
|
||||
{
|
||||
file->encryption_ctx = NULL;
|
||||
}
|
||||
spinlock_release(&slave->catch_lock);
|
||||
|
||||
while (burst-- && burst_size > 0 &&
|
||||
(record = blr_read_binlog(router, file, slave->binlog_pos, &hdr, read_errmsg)) != NULL)
|
||||
{
|
||||
char binlog_name[BINLOG_FNAMELEN + 1];
|
||||
uint32_t binlog_pos;
|
||||
uint32_t event_size;
|
||||
|
||||
strcpy(binlog_name, slave->binlogfile);
|
||||
binlog_pos = slave->binlog_pos;
|
||||
|
||||
/* Don't sent special events generated by MaxScale */
|
||||
if (hdr.event_type == MARIADB10_START_ENCRYPTION_EVENT || hdr.event_type == IGNORABLE_EVENT || (hdr.flags & LOG_EVENT_IGNORABLE_F))
|
||||
if (hdr.event_type == MARIADB10_START_ENCRYPTION_EVENT ||
|
||||
hdr.event_type == IGNORABLE_EVENT ||
|
||||
(hdr.flags & LOG_EVENT_IGNORABLE_F))
|
||||
{
|
||||
/* In case of file rotation or pos = 4 the events are sent from position 4.
|
||||
* new FDE at pos 4 is read.
|
||||
* We need to check whether the first event after FDE
|
||||
* is the MARIADB10_START_ENCRYPTION_EVENT of the new file.
|
||||
*
|
||||
* Read it if slave->encryption_ctx is NULL and set the slave->encryption_ctx accordingly
|
||||
*/
|
||||
spinlock_acquire(&slave->catch_lock);
|
||||
|
||||
if (hdr.event_type == MARIADB10_START_ENCRYPTION_EVENT && !slave->encryption_ctx)
|
||||
{
|
||||
/* read it, set slave & file context */
|
||||
uint8_t *record_ptr = GWBUF_DATA(record);
|
||||
SLAVE_ENCRYPTION_CTX *new_encryption_ctx = MXS_CALLOC(1, sizeof(SLAVE_ENCRYPTION_CTX));
|
||||
record_ptr += BINLOG_EVENT_HDR_LEN;
|
||||
new_encryption_ctx->binlog_crypto_scheme = record_ptr[0];
|
||||
memcpy(&new_encryption_ctx->binlog_key_version, record_ptr + 1, BLRM_KEY_VERSION_LENGTH);
|
||||
memcpy(new_encryption_ctx->nonce, record_ptr + 1 + BLRM_KEY_VERSION_LENGTH, BLRM_NONCE_LENGTH);
|
||||
|
||||
/* Save current first_enc_event_pos */
|
||||
if (slave->encryption_ctx)
|
||||
{
|
||||
SLAVE_ENCRYPTION_CTX *slave_enc_ctx = (SLAVE_ENCRYPTION_CTX *)slave->encryption_ctx;
|
||||
new_encryption_ctx->first_enc_event_pos = slave_enc_ctx->first_enc_event_pos;
|
||||
}
|
||||
|
||||
/* set the encryption ctx into slave */
|
||||
slave->encryption_ctx = new_encryption_ctx;
|
||||
|
||||
MXS_INFO("Start Encryption event found while reading. Binlog %s is encrypted. First event at %lu",
|
||||
slave->binlogfile,
|
||||
(unsigned long) hdr.next_pos);
|
||||
}
|
||||
|
||||
MXS_INFO("Found ignorable event [%s] of size %lu while reading binlog %s at %lu",
|
||||
blr_get_event_description(router, hdr.event_type),
|
||||
(unsigned long)hdr.event_size,
|
||||
slave->binlogfile,
|
||||
(unsigned long) slave->binlog_pos);
|
||||
|
||||
/* set next pos */
|
||||
slave->binlog_pos = hdr.next_pos;
|
||||
|
||||
spinlock_release(&slave->catch_lock);
|
||||
|
||||
gwbuf_free(record);
|
||||
record = NULL;
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (hdr.event_type == ROTATE_EVENT)
|
||||
@ -2325,6 +2414,11 @@ blr_slave_catchup(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, bool large)
|
||||
MXS_ERROR("blr_close_binlog took %lu maxscale beats", hkheartbeat - beat1);
|
||||
}
|
||||
blr_slave_rotate(router, slave, GWBUF_DATA(record));
|
||||
|
||||
/* reset the encryption context */
|
||||
MXS_FREE(slave->encryption_ctx);
|
||||
slave->encryption_ctx = NULL;
|
||||
|
||||
beat1 = hkheartbeat;
|
||||
#ifdef BLFILE_IN_SLAVE
|
||||
if ((slave->file = blr_open_binlog(router, slave->binlogfile)) == NULL)
|
||||
@ -2558,6 +2652,10 @@ blr_slave_catchup(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, bool large)
|
||||
slave->binlogfile, (unsigned long)slave->binlog_pos,
|
||||
router->binlog_name, router->binlog_position);
|
||||
|
||||
/* Reset encryption context */
|
||||
MXS_FREE(slave->encryption_ctx);
|
||||
slave->encryption_ctx = NULL;
|
||||
|
||||
#ifdef BLFILE_IN_SLAVE
|
||||
if (blr_slave_fake_rotate(router, slave, &slave->file))
|
||||
#else
|
||||
@ -2763,13 +2861,14 @@ blr_slave_fake_rotate(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, BLFILE** fil
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a "fake" format description event to the newly connected slave
|
||||
* Read the format description event FDE from current slave logfile
|
||||
*
|
||||
* @param router The router instance
|
||||
* @param slave The slave to send the event to
|
||||
* @return The read FDE event on success or NULL on error
|
||||
*/
|
||||
static void
|
||||
blr_slave_send_fde(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave)
|
||||
static GWBUF *
|
||||
blr_slave_read_fde(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave)
|
||||
{
|
||||
BLFILE *file;
|
||||
REP_HEADER hdr;
|
||||
@ -2784,7 +2883,7 @@ blr_slave_send_fde(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave)
|
||||
|
||||
if ((file = blr_open_binlog(router, slave->binlogfile)) == NULL)
|
||||
{
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
if ((record = blr_read_binlog(router, file, 4, &hdr, err_msg)) == NULL)
|
||||
{
|
||||
@ -2799,20 +2898,56 @@ blr_slave_send_fde(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave)
|
||||
}
|
||||
|
||||
blr_close_binlog(router, file);
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
blr_close_binlog(router, file);
|
||||
|
||||
return record;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a "fake" format description event to the newly connected slave
|
||||
*
|
||||
* @param router The router instance
|
||||
* @param slave The slave to send the event to
|
||||
* @return The FDE event size on success or 0 on error
|
||||
*/
|
||||
static uint32_t
|
||||
blr_slave_send_fde(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, GWBUF *fde)
|
||||
{
|
||||
BLFILE *file;
|
||||
REP_HEADER hdr;
|
||||
GWBUF *head;
|
||||
uint8_t *ptr;
|
||||
uint32_t chksum;
|
||||
char err_msg[BINLOG_ERROR_MSG_LEN + 1];
|
||||
uint32_t event_size;
|
||||
uint8_t *event_ptr;
|
||||
|
||||
if (fde == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
err_msg[BINLOG_ERROR_MSG_LEN] = '\0';
|
||||
event_ptr = GWBUF_DATA(fde);
|
||||
head = gwbuf_alloc(5);
|
||||
ptr = GWBUF_DATA(head);
|
||||
encode_value(ptr, hdr.event_size + 1, 24); // Payload length
|
||||
|
||||
event_size = GWBUF_LENGTH(fde);
|
||||
|
||||
/* Set payload to event_size + 1 (the ok/err byte) */
|
||||
encode_value(ptr, event_size + 1, 32);
|
||||
ptr += 3;
|
||||
*ptr++ = slave->seqno++;
|
||||
*ptr++ = 0; // OK
|
||||
head = gwbuf_append(head, record);
|
||||
ptr = GWBUF_DATA(record);
|
||||
encode_value(ptr, time(0), 32); // Overwrite timestamp
|
||||
ptr += 13;
|
||||
encode_value(ptr, 0, 32); // Set next position to 0
|
||||
*ptr++ = 0; // OK/ERR byte
|
||||
head = gwbuf_append(head, fde);
|
||||
event_ptr = GWBUF_DATA(fde);
|
||||
encode_value(event_ptr, time(0), 32); // Overwrite timestamp
|
||||
event_ptr += 13; // 4 time + 1 type + 4 server_id + 4 event_size
|
||||
/* event_ptr points to position of the next event */
|
||||
encode_value(event_ptr, 0, 32); // Set next position to 0
|
||||
|
||||
/*
|
||||
* Since we have changed the timestamp we must recalculate the CRC
|
||||
*
|
||||
@ -2820,16 +2955,15 @@ blr_slave_send_fde(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave)
|
||||
* calculate a new checksum
|
||||
* and write it into the header
|
||||
*/
|
||||
ptr = GWBUF_DATA(record) + hdr.event_size - 4;
|
||||
ptr = GWBUF_DATA(fde) + event_size - BINLOG_EVENT_CRC_SIZE;
|
||||
chksum = crc32(0L, NULL, 0);
|
||||
chksum = crc32(chksum, GWBUF_DATA(record), hdr.event_size - 4);
|
||||
chksum = crc32(chksum, GWBUF_DATA(fde), event_size - BINLOG_EVENT_CRC_SIZE);
|
||||
encode_value(ptr, chksum, 32);
|
||||
|
||||
slave->dcb->func.write(slave->dcb, head);
|
||||
return slave->dcb->func.write(slave->dcb, head);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Send the field count packet in a response packet sequence.
|
||||
*
|
||||
@ -5577,3 +5711,69 @@ bool blr_notify_waiting_slave(ROUTER_SLAVE *slave)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read START_ENCRYPTION_EVENT, after FDE
|
||||
*/
|
||||
static int
|
||||
blr_slave_read_ste(ROUTER_INSTANCE *router, ROUTER_SLAVE *slave, uint32_t fde_end_pos)
|
||||
{
|
||||
BLFILE *file;
|
||||
REP_HEADER hdr;
|
||||
GWBUF *record, *head;
|
||||
uint8_t *ptr;
|
||||
uint32_t chksum;
|
||||
char err_msg[BINLOG_ERROR_MSG_LEN + 1];
|
||||
|
||||
err_msg[BINLOG_ERROR_MSG_LEN] = '\0';
|
||||
|
||||
memset(&hdr, 0, BINLOG_EVENT_HDR_LEN);
|
||||
|
||||
if ((file = blr_open_binlog(router, slave->binlogfile)) == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if ((record = blr_read_binlog(router, file, fde_end_pos, &hdr, err_msg)) == NULL)
|
||||
{
|
||||
if (hdr.ok != SLAVE_POS_READ_OK)
|
||||
{
|
||||
MXS_ERROR("Slave %s:%i, server-id %d, binlog '%s', blr_read_binlog failure: %s",
|
||||
slave->dcb->remote,
|
||||
ntohs((slave->dcb->ipv4).sin_port),
|
||||
slave->serverid,
|
||||
slave->binlogfile,
|
||||
err_msg);
|
||||
}
|
||||
|
||||
blr_close_binlog(router, file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
blr_close_binlog(router, file);
|
||||
|
||||
/* check for START_ENCRYPTION_EVENT */
|
||||
if (hdr.event_type == MARIADB10_START_ENCRYPTION_EVENT)
|
||||
{
|
||||
uint8_t *record_ptr = GWBUF_DATA(record);
|
||||
SLAVE_ENCRYPTION_CTX *new_encryption_ctx = MXS_CALLOC(1, sizeof(SLAVE_ENCRYPTION_CTX));
|
||||
record_ptr += BINLOG_EVENT_HDR_LEN;
|
||||
new_encryption_ctx->binlog_crypto_scheme = record_ptr[0]; // 1 Byte
|
||||
memcpy(&new_encryption_ctx->binlog_key_version, record_ptr + 1, BLRM_KEY_VERSION_LENGTH);
|
||||
memcpy(new_encryption_ctx->nonce, record_ptr + 1 + BLRM_KEY_VERSION_LENGTH, BLRM_NONCE_LENGTH);
|
||||
/* Set the pos of first encrypted event */
|
||||
new_encryption_ctx->first_enc_event_pos = fde_end_pos + hdr.event_size;
|
||||
|
||||
spinlock_acquire(&slave->catch_lock);
|
||||
/* set the encryption ctx into slave */
|
||||
MXS_FREE(slave->encryption_ctx);
|
||||
slave->encryption_ctx = new_encryption_ctx;
|
||||
spinlock_release(&slave->catch_lock);
|
||||
|
||||
MXS_INFO("Start Encryption event found. Binlog %s is encrypted. First event at %lu",
|
||||
slave->binlogfile,
|
||||
(unsigned long)fde_end_pos + hdr.event_size);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user