diff --git a/include/mysql.h.pp b/include/mysql.h.pp index 065bbb79b8d2..54b81719aef9 100644 --- a/include/mysql.h.pp +++ b/include/mysql.h.pp @@ -155,6 +155,7 @@ char last_error[512]; char sqlstate[5 + 1]; void *extension; + void *tap_commexit_context; } NET; enum mysql_enum_shutdown_level { SHUTDOWN_DEFAULT = 0, @@ -206,6 +207,8 @@ void my_net_set_write_timeout(struct NET *net, unsigned int timeout); void my_net_set_read_timeout(struct NET *net, unsigned int timeout); void my_net_set_retry_count(struct NET *net, unsigned int retry_count); +void my_net_set_tap_commexit_context(struct NET *net, void *context); +void *my_net_get_tap_commexit_context(const struct NET *net); struct rand_struct { unsigned long seed1, seed2, max_value; double max_value_dbl; diff --git a/include/mysql_com.h b/include/mysql_com.h index ab6cf4914e9a..59dbc9ef72ee 100644 --- a/include/mysql_com.h +++ b/include/mysql_com.h @@ -940,6 +940,7 @@ typedef struct NET { to maintain the server internal instrumentation for the connection. */ void *extension; + void *tap_commexit_context; } NET; #define packet_error (~(unsigned long)0) @@ -1101,6 +1102,8 @@ unsigned long my_net_read(struct NET *net); void my_net_set_write_timeout(struct NET *net, unsigned int timeout); void my_net_set_read_timeout(struct NET *net, unsigned int timeout); void my_net_set_retry_count(struct NET *net, unsigned int retry_count); +void my_net_set_tap_commexit_context(struct NET *net, void *context); +void *my_net_get_tap_commexit_context(const struct NET *net); struct rand_struct { unsigned long seed1, seed2, max_value; diff --git a/include/tap_commexit.h b/include/tap_commexit.h new file mode 100644 index 000000000000..175693cac1a2 --- /dev/null +++ b/include/tap_commexit.h @@ -0,0 +1,354 @@ +/*************************************************************************** + * Licensed Materials - Property of IBM + * + * Restricted Materials of IBM + * + * (C) COPYRIGHT International Business Machines Corp. 2016,2017 + * All Rights Reserved. + * + * US Government Users Restricted Rights - + * Use, duplication or disclosure restricted by + * GSA ADP Schedule Contract with IBM Corp + * + */ + +#ifndef _TAPCOMMEXIT_H +#define _TAPCOMMEXIT_H + +#include +#include +#include +#include +#ifdef WIN32 +#include +#include +#include +#else +#include +#include +#include +#include +#include +#endif +#include + +#include +#include + +#include + + +// #include + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define TAPCOMMEXIT_LOG_NONE 0 +#define TAPCOMMEXIT_LOG_CRITICAL 1 +#define TAPCOMMEXIT_LOG_ERROR 2 +#define TAPCOMMEXIT_LOG_WARNING 3 +#define TAPCOMMEXIT_LOG_INFO 4 + +#define TAPCOMMEXIT_LOG_ALWAYS 1 + +#define TAPCOMMEXIT_NONE 0 +#define TAPCOMMEXIT_TRACE 1 +#define TAPCOMMEXIT_DEBUG 2 + +// Return values for TAPCOMMEXIT_RC +#define TAPCOMMEXIT_SUCCESS 0 +#define TAPCOMMEXIT_FAIL 1 +#define TAPCOMMEXIT_SCRUB 2 +#define TAPCOMMEXIT_REWRITE 3 +#define TAPCOMMEXIT_KILL 4 +#define TAPCOMMEXIT_PENDING 5 +#define TAPCOMMEXIT_MORE 6 + +#define TAPCOMMEXIT_FEATURE_NO_SCRUB 0x01 // do not allow scrub at all +#define TAPCOMMEXIT_FEATURE_SCRUB_ALLOC_BUF 0x02 // does not imply scrub is supported, requires allocation +#define TAPCOMMEXIT_FEATURE_NO_QRW 0x04 // do not allow qrw at all (qrw requires allocation) +#define TAPCOMMEXIT_FEATURE_NO_FW 0x08 // do not allow firewall at all +#define TAPCOMMEXIT_FEATURE_SOCKET_PORTS_IN_HOST_ORDER 0x10 // do not need to use ntohs for socket ports +#define TAPCOMMEXIT_FEATURE_NON_BLOCKING_VERDICTS 0x20 + +// Protocol type definitions +#define TAPCOMMEXIT_PROTOCOL_UNKNOWN 0 +#define TAPCOMMEXIT_PROTOCOL_TCPIP4 1 +#define TAPCOMMEXIT_PROTOCOL_TCPIP6 2 +#define TAPCOMMEXIT_PROTOCOL_LOCAL 3 + +#define TAPCOMMEXIT_SESSION_UNENCRYPTED 0 +#define TAPCOMMEXIT_SESSION_ENCRYPTED 1 + +#define TAPCOMMEXIT_LOCAL_TYPE_SHMEM 1 +#define TAPCOMMEXIT_LOCAL_TYPE_OTHER 2 + +typedef int TAPCOMMEXIT_RC; + +#define TAPCOMMEXIT_MAX_FILTER_COUNT 20 +typedef struct tap_commexit_filter_struct { + int filter_count; + struct { + struct sockaddr_storage ip; + struct sockaddr_storage netmask; + } filters[TAPCOMMEXIT_MAX_FILTER_COUNT]; +} tap_commexit_filter_t; + +typedef struct tap_commexit_config_ie_struct { + int port_range_start; + int port_range_end; + int db_type; + tap_commexit_filter_t include_filter; + tap_commexit_filter_t exclude_filter; +} tap_commexit_config_ie_t; + +// Item allocated will have ie_count elements of ies +typedef struct tap_commexit_config_struct { + int ie_count; + tap_commexit_config_ie_t ies[1]; +} tap_commexit_config_t; + +tap_commexit_config_t *tap_commexit_get_config(void); +void tap_commexit_release_config(tap_commexit_config_t *config); + +typedef enum logging_types { + EXTERNAL, // We'll be provided an external logging function of type tapcommexitLogMessage + STRING // We'll pass the log message back in buffers provided +} logging_t; + +// Prototype for an external logging function we can register to the interface +typedef TAPCOMMEXIT_RC (tapcommexitLogMessage) ( + int reserved, + void *pContext, + const void *pCommInfo, + int when, + int32_t level, + char *logmsg, + int32_t logmsglen + ); + +typedef enum { + LOCAL_SOCKET, + REMOTE_SOCKET +} socket_type; + +struct tap_commexit_db_support_fns { + // Returns the PID for a given connection + int (*get_pid)(const void *pContext, const void *pCommInfo); + // Returns the protocol type for a given connection + int (*get_protocol)(const void *pContext, const void *pCommInfo); + // Returns the socket specified by 'which' for a given connection + struct sockaddr_storage *(*get_sockaddr)(const void *pContext, const void *pCommInfo, socket_type which); + // Returns true if debugging is enabled specifically for this connection + int (*get_session_debug)(const void *pContext, const void *pCommInfo); + // Returns true if tracing is enabled specifically for this connection + int (*get_session_trace)(const void *pContext, const void *pCommInfo); + // Used to allocate memory which can be freed by the DB (optional) + void *(*db_malloc)(size_t size); + // Used to free memory internally if it wasn't needed, or is replaced, by the above function (optional) + void (*db_free)(void *p); + // Returns a special marker to differentiate local connection types (optional) + int (*get_local_conn_type)(const void *pContext, const void *pCommInfo); + // Unique address which can be used to differentiate sessions (optional) + void (*get_conn_unique_addr)(const void *pContext, const void *pCommInfo, uint32_t *unique_addr); + // Notify the DB that the config has changed + void (*notify_new_config)(void); + // Check is this session is encrypted + int (*is_encrypted)(const void *pContext, const void *pCommInfo); + // Get the DB thread identifier for this connection (optional) + uint32_t (*get_db_thread_id)(const void *pContext, const void *pCommInfo); + // Get the DB identifier for this connection (optional) + uint64_t (*get_db_conn_id)(const void *pContext, const void *pCommInfo); +}; + +// Register an external logging function to the interface +void +tap_commexit_set_external_log_function(int (*fn)( + int reserved, + void *pContext, + const void *pCommInfo, + int when, + int32_t level, + char *logmsg, + int32_t logmsglen + )); + +// Returns true if we should print to the debug log +int +tap_commexit_should_log(void * pContext, const void *pCommInfo, int level); +// If inside an external logging function, must call the internal call +int +tap_commexit_should_log_internal(int reserved, void * pContext, const void *pCommInfo, int level); + +// Send the UID chain request to STAP for this session +void +tap_commexit_request_uid_chain( + char *logmsg, + uint32_t *logmsglen, + uint32_t *logmsgavail, + void *pContext, + const void *pCommInfo + ); + +// Send the username to STAP for this session +void +tap_commexit_send_username_packet( + char *logmsg, + uint32_t *logmsglen, + uint32_t *logmsgavail, + void *pContext, + const void *pCommInfo, + void *packet, + uint32_t packet_len + ); + +// Returns true if we can send data to STAP +int tap_commexit_should_send_data(void *_pContext); + +// Send S2C traffic to STAP +TAPCOMMEXIT_RC +tap_commexit_send_server_data( + char *logmsg, + uint32_t *logmsglen, + uint32_t *logmsgavail, + void *_pContext, + const void *pCommInfo, + int64_t *pReservedFlags, + const char *pBuffer, + int buffer_len, + char **pNewBuffer, + int *new_buffer_len + ); + +// Send C2S traffic to STAP +TAPCOMMEXIT_RC +tap_commexit_send_client_data( + char *logmsg, + uint32_t *logmsglen, + uint32_t *logmsgavail, + void *_pContext, + const void *pCommInfo, + int64_t *pReservedFlags, + const char *pBuffer, + int buffer_len, + char **pNewBuffer, + int *new_buffer_len + ); + +// Returns true if no room in buffer to send data +int +tap_commexit_full(void); + +// Initialize the shmem channel to STAP +TAPCOMMEXIT_RC +tap_commexit_init_shmem ( + char *errormsg, + uint32_t *errormsglen, + uint32_t *errormsgavail, + const char *db_str, + int force_init + ); + +// Shutdown the shmem channel to STAP +void +tap_commexit_shutdown_shmem( + char *logmsg, + uint32_t *logmsglen, + uint32_t *logmsgavail + ); + +// Allocate a context for a new session +void * +tap_commexit_allocate_context(void); + +// Free a context when the session closes +void +tap_commexit_free_context(void *ptr); + +// Initialize the context +TAPCOMMEXIT_RC +tap_commexit_init_context( + char *logmsg, + uint32_t *logmsglen, + uint32_t *logmsgavail, + void *_pContext, + const void *pCommInfo, + uint64_t feature_flags, + const struct tap_commexit_db_support_fns *support_fns + ); + +// Get a previously saved opaque pointer stored in the context +void * +tap_commexit_get_context_opaque( + const void *_pContext + ); + +// Store an opaque pointer to the context +void +tap_commexit_set_context_opaque( + void *_pContext, + void *opaque + ); + +// Send OPEN marker for session to STAP +void +tap_commexit_send_open( + char *logmsg, + uint32_t *logmsglen, + uint32_t *logmsgavail, + void *_pContext, + const void *pCommInfo + ); + +// Send CLOSE marker for session to STAP +void +tap_commexit_send_close( + char *logmsg, + uint32_t *logmsglen, + uint32_t *logmsgavail, + void *_pContext, + const void *pCommInfo + ); + +// Private implementation specific initialization +void tap_commexit_init( + char *logmsg, + uint32_t *logmsglen, + uint32_t *logmsgavail + ); + +// Get the pointer for the connection info which is stored in the context (stored during init) +const void * +tap_commexit_get_conninfo( + void *context); +void +tap_commexit_log_event( + const char* exit_name, + int id, + int level, + size_t msg_len, + const char* message + ); +uint32_t tap_commexit_has_verdict(void *context); +uint32_t tap_commexit_get_verdict(void *context); +int tap_commexit_verdict_request_expired(void *context); +TAPCOMMEXIT_RC tap_commexit_handle_rewrite_message( + char *logmsg, // Head of log message string + uint32_t *logmsglen, // Current number of bytes in log message string + uint32_t *logmsgavail, // Amount of space left in message string + void *pContext, + const void *pCommInfo, + const char *buffer, + int size, + char **newBuffer, + int *newSize + ); +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/include/tap_commexit_defines.h b/include/tap_commexit_defines.h new file mode 100644 index 000000000000..ba6ee5420e36 --- /dev/null +++ b/include/tap_commexit_defines.h @@ -0,0 +1,25 @@ +/*************************************************************************** + * Licensed Materials - Property of IBM + * + * Restricted Materials of IBM + * + * (C) COPYRIGHT International Business Machines Corp. 2016,2017 + * All Rights Reserved. + * + * US Government Users Restricted Rights - + * Use, duplication or disclosure restricted by + * GSA ADP Schedule Contract with IBM Corp + * + */ + +#define EXIT_TYPE_DB2 0 +#define EXIT_TYPE_INFX 1 +#define EXIT_TYPE_TRD 2 +#define EXIT_TYPE_XGS 3 +#define EXIT_INTERCEPT_SHEM 0x1 +#define EXIT_INTERCEPT_TCP 0x2 +#define EXIT_INTERCEPT_PIPE 0x4 +#define EXIT_INTERCEPT_SOCK 0x8 +#define EXIT_INTERCEPT_LOCAL 0xD +#define EXIT_INTERCEPT_BITS_PER_DB 4 + diff --git a/sql-common/net_serv.cc b/sql-common/net_serv.cc index ecd17936eb14..6c092a5d2f80 100644 --- a/sql-common/net_serv.cc +++ b/sql-common/net_serv.cc @@ -59,6 +59,7 @@ #include "mysql_com.h" #include "mysqld_error.h" #include "violite.h" +#include "sql/tap_commexit_plugin.h" using std::max; using std::min; @@ -143,6 +144,18 @@ static mysql_compress_context *compress_context(NET *net) { return mysql_compress_ctx; } +void my_net_set_tap_commexit_context(struct NET *net, void *context) { + if (net == nullptr) + return; + net->tap_commexit_context = context; +} + +void *my_net_get_tap_commexit_context(const struct NET *net) { + if (net == nullptr) + return nullptr; + return net->tap_commexit_context; +} + /** Init with packet info. */ bool my_net_init(NET *net, Vio *vio) { @@ -179,6 +192,7 @@ bool my_net_init(NET *net, Vio *vio) { ext->compress_ctx.algorithm = enum_compression_algorithm::MYSQL_UNCOMPRESSED; net->extension = ext; #endif + net->tap_commexit_context = NULL; if (vio) { /* For perl DBI/DBD. */ net->fd = vio_fd(vio); @@ -433,6 +447,15 @@ static bool net_should_retry(NET *net, uint *retry_count [[maybe_unused]]) { */ bool my_net_write(NET *net, const uchar *packet, size_t len) { +#ifdef MYSQL_SERVER + char* logmsg = nullptr; + uint32_t logmsglen = 0; + uint32_t logmsgavail = 0; + int64_t flags = 0; + char* tmp_packet = nullptr; + int packet_len = NET_HEADER_SIZE; + TAPCOMMEXIT_RC tap_rc = TAPCOMMEXIT_SUCCESS; +#endif uchar buff[NET_HEADER_SIZE]; DBUG_DUMP("net write", packet, len); @@ -456,23 +479,113 @@ bool my_net_write(NET *net, const uchar *packet, size_t len) { const ulong z_size = MAX_PACKET_LENGTH; int3store(buff, z_size); buff[3] = (uchar)net->pkt_nr++; +#ifdef MYSQL_SERVER + tmp_packet = nullptr; + packet_len = NET_HEADER_SIZE; + tap_rc = tap_commexit::send_server_data(logmsg, &logmsglen, &logmsgavail, net->tap_commexit_context, tap_commexit::get_context_opaque(net->tap_commexit_context), &flags, reinterpret_cast(buff), NET_HEADER_SIZE, &tmp_packet, &packet_len); + if (tap_rc == TAPCOMMEXIT_SCRUB) { + if (net_write_buff(net, const_cast(reinterpret_cast(tmp_packet)), packet_len)) { + free(tmp_packet); + return true; + } + free(tmp_packet); + tmp_packet = nullptr; + } else if (tap_rc == TAPCOMMEXIT_KILL) { + vio_delete(net->vio); + net->error = NET_ERROR_SOCKET_UNUSABLE; + net->last_errno = ER_NET_ERROR_ON_WRITE; + my_error(net->last_errno, MYF(0)); + return true; + } else { + if (net_write_buff(net, buff, NET_HEADER_SIZE)) { + return true; + } + } + tmp_packet = nullptr; + packet_len = z_size; + tap_commexit::send_server_data(logmsg, &logmsglen, &logmsgavail, net->tap_commexit_context, tap_commexit::get_context_opaque(net->tap_commexit_context), &flags, reinterpret_cast(packet), ((int)z_size), &tmp_packet, &packet_len); + if (tap_rc == TAPCOMMEXIT_SCRUB) { + if (net_write_buff(net, const_cast(reinterpret_cast(tmp_packet)), packet_len)) { + free(tmp_packet); + return true; + } + free(tmp_packet); + tmp_packet = nullptr; + } else if (tap_rc == TAPCOMMEXIT_KILL) { + vio_delete(net->vio); + net->error = NET_ERROR_SOCKET_UNUSABLE; + net->last_errno = ER_NET_ERROR_ON_WRITE; + my_error(net->last_errno, MYF(0)); + return true; + } else { + if (net_write_buff(net, packet, z_size)) { + return true; + } + } +#else if (net_write_buff(net, buff, NET_HEADER_SIZE) || net_write_buff(net, packet, z_size)) { return true; } +#endif packet += z_size; len -= z_size; } /* Write last packet */ int3store(buff, static_cast(len)); buff[3] = (uchar)net->pkt_nr++; +#ifdef MYSQL_SERVER + tmp_packet = nullptr; + packet_len = NET_HEADER_SIZE; + tap_commexit::send_server_data(logmsg, &logmsglen, &logmsgavail, net->tap_commexit_context, tap_commexit::get_context_opaque(net->tap_commexit_context), &flags, reinterpret_cast(buff), NET_HEADER_SIZE, &tmp_packet, &packet_len); + if (tap_rc == TAPCOMMEXIT_SCRUB) { + if (net_write_buff(net, const_cast(reinterpret_cast(tmp_packet)), packet_len)) { + free(tmp_packet); + return true; + } + free(tmp_packet); + tmp_packet = nullptr; + } else if (tap_rc == TAPCOMMEXIT_KILL) { + vio_delete(net->vio); + net->error = NET_ERROR_SOCKET_UNUSABLE; + net->last_errno = ER_NET_ERROR_ON_WRITE; + my_error(net->last_errno, MYF(0)); + return true; + } else { + if (net_write_buff(net, buff, NET_HEADER_SIZE)) { + return true; + } + } +#else if (net_write_buff(net, buff, NET_HEADER_SIZE)) { return true; } +#endif #ifdef DEBUG_DATA_PACKETS DBUG_DUMP("packet_header", buff, NET_HEADER_SIZE); #endif +#ifdef MYSQL_SERVER + bool ret = false; + tmp_packet = nullptr; + packet_len = len; + tap_rc = tap_commexit::send_server_data(logmsg, &logmsglen, &logmsgavail, net->tap_commexit_context, tap_commexit::get_context_opaque(net->tap_commexit_context), &flags, reinterpret_cast(packet), ((int)len), &tmp_packet, &packet_len); + if (tap_rc == TAPCOMMEXIT_SCRUB) { + ret = net_write_buff(net, const_cast(reinterpret_cast(tmp_packet)), packet_len); + free(tmp_packet); + tmp_packet = nullptr; + } else if (tap_rc == TAPCOMMEXIT_KILL) { + vio_delete(net->vio); + net->error = NET_ERROR_SOCKET_UNUSABLE; + net->last_errno = ER_NET_ERROR_ON_WRITE; + my_error(net->last_errno, MYF(0)); + return true; + } else { + ret = net_write_buff(net, packet, len); + } + return ret; +#else return net_write_buff(net, packet, len); +#endif } static void reset_packet_write_state(NET *net) { @@ -1340,6 +1453,14 @@ bool net_write_packet(NET *net, const uchar *packet, size_t length) { */ static bool net_read_raw_loop(NET *net, size_t count) { +#ifdef MYSQL_SERVER + char* logmsg = nullptr; + uint32_t logmsglen = 0; + uint32_t logmsgavail = 0; + int64_t flags = 0; + char* tmp_packet = nullptr; + int packet_len = 0; +#endif DBUG_TRACE; bool eof = false; unsigned int retry_count = 0; @@ -1361,6 +1482,11 @@ static bool net_read_raw_loop(NET *net, size_t count) { eof = true; break; } +#ifdef MYSQL_SERVER + tmp_packet = nullptr; + packet_len = recvcnt; + tap_commexit::send_client_data(logmsg, &logmsglen, &logmsgavail, net->tap_commexit_context, tap_commexit::get_context_opaque(net->tap_commexit_context), &flags, reinterpret_cast(buf), recvcnt, &tmp_packet, &packet_len); +#endif count -= recvcnt; buf += recvcnt; @@ -1452,7 +1578,9 @@ static bool net_read_packet_header(NET *net) { rc = net_read_raw_loop(net, count); } - if (rc) return true; + if (rc) { + return true; + } DBUG_DUMP("packet_header", net->buff + net->where_b, NET_HEADER_SIZE); diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt index 0a954c074119..ac16741dfbb0 100644 --- a/sql/CMakeLists.txt +++ b/sql/CMakeLists.txt @@ -610,6 +610,7 @@ SET(SQL_SHARED_SOURCES table_cache.cc table_function.cc table_trigger_dispatcher.cc + tap_commexit_plugin.cc tc_log.cc thr_malloc.cc time_zone_common.cc diff --git a/sql/conn_handler/connection_handler_one_thread.cc b/sql/conn_handler/connection_handler_one_thread.cc index 14c19c31b493..e5622033ccb7 100644 --- a/sql/conn_handler/connection_handler_one_thread.cc +++ b/sql/conn_handler/connection_handler_one_thread.cc @@ -38,6 +38,7 @@ #include "sql/sql_connect.h" // close_connection #include "sql/sql_parse.h" // do_command #include "sql/sql_thd_internal_api.h" // thd_set_thread_stack +#include "sql/tap_commexit_plugin.h" bool One_thread_connection_handler::add_connection(Channel_info *channel_info) { if (my_thread_init()) { @@ -75,6 +76,20 @@ bool One_thread_connection_handler::add_connection(Channel_info *channel_info) { Global_THD_manager *thd_manager = Global_THD_manager::get_instance(); thd_manager->add_thd(thd); + // allocate, init, and add context to thd + char* logmsg = NULL; + uint32_t logmsglen = 0; + uint32_t logmsgavail = 0; + tap_commexit::init_shmem(logmsg, &logmsglen, &logmsgavail, "MYSQL", 0); + void* tap_context = tap_commexit::allocate_context(); + thd->set_tap_context(tap_context); + if (thd->get_protocol_classic() != nullptr) + thd->get_protocol_classic()->set_net_tap_commexit_context(tap_context); + tap_commexit::init_context(logmsg, &logmsglen, &logmsgavail, thd->get_tap_context(), (void*)thd); + tap_commexit::set_context_opaque(thd->get_tap_context(), (void*)thd); + // send an open + tap_commexit::send_open(logmsg, &logmsglen, &logmsgavail, thd->get_tap_context(), (void*)thd); + bool error = false; if (thd_prepare_connection(thd)) error = true; // Returning true causes inc_aborted_connects() to be called. @@ -85,6 +100,10 @@ bool One_thread_connection_handler::add_connection(Channel_info *channel_info) { } end_connection(thd); } + // send a close + tap_commexit::send_close(logmsg, &logmsglen, &logmsgavail, thd->get_tap_context(), (void*)thd); + tap_commexit::free_context(thd->get_tap_context()); + thd->set_tap_context(nullptr); close_connection(thd, 0, false, false); thd->release_resources(); thd_manager->remove_thd(thd); diff --git a/sql/conn_handler/connection_handler_per_thread.cc b/sql/conn_handler/connection_handler_per_thread.cc index b9edd4d5faf4..5e89fb53b130 100644 --- a/sql/conn_handler/connection_handler_per_thread.cc +++ b/sql/conn_handler/connection_handler_per_thread.cc @@ -61,6 +61,7 @@ #include "sql/sql_parse.h" // do_command #include "sql/sql_thd_internal_api.h" // thd_set_thread_stack #include "thr_mutex.h" +#include "sql/tap_commexit_plugin.h" // Initialize static members ulong Per_thread_connection_handler::blocked_pthread_count = 0; @@ -295,6 +296,19 @@ static void *handle_connection(void *arg) { mysql_socket_set_thread_owner(socket); thd_manager->add_thd(thd); + // allocate, init, and add context to thd + char* logmsg = NULL; + uint32_t logmsglen = 0; + uint32_t logmsgavail = 0; + tap_commexit::init_shmem(logmsg, &logmsglen, &logmsgavail, "MYSQL", 0); + void* tap_context = tap_commexit::allocate_context(); + thd->set_tap_context(tap_context); + if (thd->get_protocol_classic() != nullptr) + thd->get_protocol_classic()->set_net_tap_commexit_context(tap_context); + tap_commexit::init_context(logmsg, &logmsglen, &logmsgavail, thd->get_tap_context(), (void*)thd); + tap_commexit::set_context_opaque(thd->get_tap_context(), (void*)thd); + // send an open + tap_commexit::send_open(logmsg, &logmsglen, &logmsgavail, thd->get_tap_context(), (void*)thd); if (thd_prepare_connection(thd)) handler_manager->inc_aborted_connects(); else { @@ -303,6 +317,10 @@ static void *handle_connection(void *arg) { } end_connection(thd); } + // send a close + tap_commexit::send_close(logmsg, &logmsglen, &logmsgavail, thd->get_tap_context(), (void*)thd); + tap_commexit::free_context(thd->get_tap_context()); + thd->set_tap_context(nullptr); close_connection(thd, 0, false, false); thd->get_stmt_da()->reset_diagnostics_area(); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 32c0328a659d..6268b618aaec 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -876,6 +876,7 @@ MySQL clients support the protocol: #include "thr_mutex.h" #include "typelib.h" #include "violite.h" +#include "sql/tap_commexit_plugin.h" #include "my_openssl_fips.h" // OPENSSL_ERROR_LENGTH, set_fips_mode #ifdef WITH_PERFSCHEMA_STORAGE_ENGINE @@ -965,6 +966,7 @@ MySQL clients support the protocol: #include "sql/server_component/mysql_server_keyring_lockable_imp.h" #include "sql/server_component/persistent_dynamic_loader_imp.h" #include "sql/srv_session.h" +#include "sql/tap_commexit_plugin.h" using std::max; using std::min; @@ -7497,6 +7499,12 @@ int mysqld_main(int argc, char **argv) */ set_my_abort(my_server_abort); + tap_commexit::load_plugin(); + char* logmsg = NULL; + uint32_t logmsglen = 0; + uint32_t logmsgavail = 0; + tap_commexit::init(logmsg, &logmsglen, &logmsgavail); + size_t guardize = 0; #ifndef _WIN32 int retval = pthread_attr_getguardsize(&connection_attrib, &guardize); @@ -8857,6 +8865,10 @@ struct my_option my_long_options[] = { "Deprecated. Use --lc-messages-dir instead.", &lc_messages_dir_ptr, &lc_messages_dir_ptr, nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr}, + {"tap-commexit-library", 0, + "Full path to TAP COMMEXIT shared library", + &tap_commexit::config::library_path, &tap_commexit::config::library_path, nullptr, GET_STR, OPT_ARG, + 0, 0, 0, nullptr, 0, nullptr}, {"lc-messages", 0, "Set the language used for the error messages.", &lc_messages, &lc_messages, nullptr, GET_STR, REQUIRED_ARG, 0, 0, 0, nullptr, 0, nullptr}, diff --git a/sql/protocol_classic.cc b/sql/protocol_classic.cc index 5c4c3e7d4022..2f8dcb7c7250 100644 --- a/sql/protocol_classic.cc +++ b/sql/protocol_classic.cc @@ -4108,3 +4108,7 @@ static ulong get_ps_param_len(enum enum_field_types type, uchar *packet, } } } + +void Protocol_classic::set_net_tap_commexit_context(void *context) { + my_net_set_tap_commexit_context(get_net(), context); +} diff --git a/sql/protocol_classic.h b/sql/protocol_classic.h index 776c0b64a70d..b0caf8590393 100644 --- a/sql/protocol_classic.h +++ b/sql/protocol_classic.h @@ -201,6 +201,7 @@ class Protocol_classic : public Protocol { virtual void set_read_timeout(ulong read_timeout); /* Set write timeout */ virtual void set_write_timeout(ulong write_timeout); + void set_net_tap_commexit_context(void *context); /** * Sets the character set expected by the client. This function is for unit diff --git a/sql/sql_class.h b/sql/sql_class.h index 56d11e044710..6dc1ecc4e69e 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -928,6 +928,15 @@ class THD : public MDL_context_owner, */ Thd_mem_cnt m_mem_cnt; + private: + void* tap_context; + public: + void* get_tap_context() const { + return tap_context; + } + void set_tap_context(void* context) { + tap_context = context; + } private: inline bool is_stmt_prepare() const { assert(0); diff --git a/sql/tap_commexit_plugin.cc b/sql/tap_commexit_plugin.cc new file mode 100644 index 000000000000..1cc4a485b7eb --- /dev/null +++ b/sql/tap_commexit_plugin.cc @@ -0,0 +1,449 @@ +#include "sql/tap_commexit_plugin.h" +#include "sql/sql_class.h" +#include "sql/protocol_classic.h" +#include "violite.h" + +#ifndef WIN32 +#include +#endif + +#include + +namespace tap_commexit { +namespace config { +char *library_path = nullptr; +} + +void* plugin_handle = nullptr; +const uint64_t feature_flags = (TAPCOMMEXIT_FEATURE_NO_QRW | TAPCOMMEXIT_FEATURE_SCRUB_ALLOC_BUF); +struct tap_commexit_db_support_fns db_support_functions = { + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr +}; + +namespace func_ptrs { +namespace types { +typedef void* (*allocate_context_t)(void); +typedef void (*free_context_t)(void* context); +typedef TAPCOMMEXIT_RC (*init_context_t)( + char *logmsg, + uint32_t *logmsglen, + uint32_t *logmsgavail, + void *_pContext, + const void *pCommInfo, + uint64_t feature_flags, + const struct tap_commexit_db_support_fns *support_fns + ); +typedef TAPCOMMEXIT_RC (*init_shmem_t)( + char *errormsg, + uint32_t *errormsglen, + uint32_t *errormsgavail, + const char *db_str, + int force_init + ); +typedef void (*shutdown_shmem_t)( + char *logmsg, + uint32_t *logmsglen, + uint32_t *logmsgavail + ); +typedef void (*init_t)( + char *logmsg, + uint32_t *logmsglen, + uint32_t *logmsgavail + ); +typedef TAPCOMMEXIT_RC (*send_server_data_t)( + char *logmsg, + uint32_t *logmsglen, + uint32_t *logmsgavail, + void *_pContext, + const void *pCommInfo, + int64_t *pReservedFlags, + const char *pBuffer, + int buffer_len, + char **pNewBuffer, + int *new_buffer_len + ); +typedef TAPCOMMEXIT_RC (*send_client_data_t)( + char *logmsg, + uint32_t *logmsglen, + uint32_t *logmsgavail, + void *_pContext, + const void *pCommInfo, + int64_t *pReservedFlags, + const char *pBuffer, + int buffer_len, + char **pNewBuffer, + int *new_buffer_len + ); +typedef void (*send_open_t)( + char *logmsg, + uint32_t *logmsglen, + uint32_t *logmsgavail, + void *_pContext, + const void *pCommInfo + ); +typedef void (*send_close_t)( + char *logmsg, + uint32_t *logmsglen, + uint32_t *logmsgavail, + void *_pContext, + const void *pCommInfo + ); +typedef void *(*get_context_opaque_t)( + const void *_pContext + ); +typedef void (*set_context_opaque_t)( + void *_pContext, + void *opaque + ); +} // namespace types +types::allocate_context_t allocate_context = nullptr; +types::free_context_t free_context = nullptr; +types::init_context_t init_context = nullptr; +types::init_shmem_t init_shmem = nullptr; +types::shutdown_shmem_t shutdown_shmem = nullptr; +types::init_t init = nullptr; +types::send_server_data_t send_server_data = nullptr; +types::send_client_data_t send_client_data = nullptr; +types::send_open_t send_open = nullptr; +types::send_close_t send_close = nullptr; +types::get_context_opaque_t get_context_opaque = nullptr; +types::set_context_opaque_t set_context_opaque = nullptr; +} //namespace func_ptrs + +namespace support_funcs { +void* db_malloc(size_t size) { + return malloc(size); +} + +void db_free(void* ptr) { + free(ptr); +} + +int get_pid(const void* context, const void* comm_info) { + (void)context; (void)comm_info; + return getpid(); +} + +int get_protocol(const void* context, const void* comm_info) { + const THD* thd = reinterpret_cast(comm_info); + (void)context; + + if (thd == nullptr || + thd->get_protocol_classic() == nullptr || + thd->get_protocol_classic()->get_vio() == nullptr) { + return TAPCOMMEXIT_PROTOCOL_UNKNOWN; + } + + int conn_fd = vio_fd(const_cast(thd->get_protocol_classic()->get_vio())); + struct sockaddr_storage local_sock = {0, 0, 0}; + socklen_t local_sock_len = sizeof(local_sock); + getsockname(conn_fd, reinterpret_cast(&local_sock), &local_sock_len); + switch(local_sock.ss_family) { + case AF_INET: + return TAPCOMMEXIT_PROTOCOL_TCPIP4; + case AF_INET6: + return TAPCOMMEXIT_PROTOCOL_TCPIP6; + case AF_UNIX: + return TAPCOMMEXIT_PROTOCOL_LOCAL; + default: + return TAPCOMMEXIT_PROTOCOL_UNKNOWN; + } + return TAPCOMMEXIT_PROTOCOL_UNKNOWN; +} + +struct sockaddr_storage* +get_sockaddr( + const void* context, + const void* comm_info, + socket_type which) { + const THD* thd = reinterpret_cast(comm_info); + int protocol = get_protocol(context, comm_info); + + if (protocol == TAPCOMMEXIT_PROTOCOL_LOCAL || + protocol == TAPCOMMEXIT_PROTOCOL_TCPIP4 || + protocol == TAPCOMMEXIT_PROTOCOL_TCPIP6) { + if (which == LOCAL_SOCKET) { + int conn_fd = vio_fd(const_cast(thd->get_protocol_classic()->get_vio())); + struct sockaddr_storage local_sock = {0, 0, 0}; + socklen_t local_sock_len = sizeof(local_sock); + getsockname(conn_fd, reinterpret_cast(&local_sock), &local_sock_len); + memcpy(const_cast(reinterpret_cast(&thd->get_protocol_classic()->get_vio()->local)), &local_sock, sizeof(local_sock)); + return const_cast(&thd->get_protocol_classic()->get_vio()->local); + } else { + int conn_fd = vio_fd(const_cast(thd->get_protocol_classic()->get_vio())); + struct sockaddr_storage remote_sock = {0, 0, 0}; + socklen_t remote_sock_len = sizeof(remote_sock); + getpeername(conn_fd, reinterpret_cast(&remote_sock), &remote_sock_len); + memcpy(const_cast(reinterpret_cast(&thd->get_protocol_classic()->get_vio()->remote)), &remote_sock, sizeof(remote_sock)); + return const_cast(&thd->get_protocol_classic()->get_vio()->remote); + } + } + return NULL; +} + +int is_encrypted(const void* context, const void* comm_info) { + const THD* thd = reinterpret_cast(comm_info); + (void)context; + + if (thd == nullptr) + return TAPCOMMEXIT_SESSION_UNENCRYPTED; + + if (thd->get_ssl() != nullptr) + return TAPCOMMEXIT_SESSION_ENCRYPTED; + + return TAPCOMMEXIT_SESSION_UNENCRYPTED; + +} + +int get_session_debug(const void* context, const void* comm_info) { + (void)context; (void)comm_info; + return 0; +} + +int get_session_trace(const void* context, const void* comm_info) { + (void)context; (void)comm_info; + return 0; +} + +void notify_new_config() { +} +} // namespace support_funcs + +void init_db_functions() { + db_support_functions.get_pid = support_funcs::get_pid; + db_support_functions.get_protocol = support_funcs::get_protocol; + db_support_functions.get_sockaddr = support_funcs::get_sockaddr; + db_support_functions.get_session_debug = support_funcs::get_session_debug; + db_support_functions.get_session_trace = support_funcs::get_session_trace; + db_support_functions.is_encrypted = support_funcs::is_encrypted; + db_support_functions.notify_new_config = support_funcs::notify_new_config; + db_support_functions.db_malloc = support_funcs::db_malloc; + db_support_functions.db_free = support_funcs::db_free; +} + +void load_plugin() { + if (plugin_handle != nullptr || + config::library_path == nullptr) { + return; + } + plugin_handle = dlopen(config::library_path, RTLD_NOW); +} + +bool plugin_loaded() { + return (plugin_handle != nullptr); +} + +void* allocate_context() { + if (!plugin_loaded()) { + return nullptr; + } + if (func_ptrs::allocate_context == nullptr) { + func_ptrs::allocate_context = reinterpret_cast(dlsym(plugin_handle, "tap_commexit_allocate_context")); + } + if (func_ptrs::allocate_context != nullptr) { + return (*func_ptrs::allocate_context)(); + } + return nullptr; +} +void free_context(void* context) { + if (!plugin_loaded()) { + return; + } + if (func_ptrs::free_context == nullptr) { + func_ptrs::free_context = reinterpret_cast(dlsym(plugin_handle, "tap_commexit_free_context")); + } + if (func_ptrs::free_context != nullptr) { + return (*func_ptrs::free_context)(context); + } + return; +} +TAPCOMMEXIT_RC init_context( + char *logmsg, + uint32_t *logmsglen, + uint32_t *logmsgavail, + void *_pContext, + const void *pCommInfo + ) { + if (!plugin_loaded()) { + return TAPCOMMEXIT_FAIL; + } + if (func_ptrs::init_context == nullptr) { + func_ptrs::init_context = reinterpret_cast(dlsym(plugin_handle, "tap_commexit_init_context")); + } + if (func_ptrs::init_context != nullptr) { + return (*func_ptrs::init_context)(logmsg, logmsglen, logmsgavail, _pContext, pCommInfo, feature_flags, &db_support_functions); + } + return TAPCOMMEXIT_FAIL; +} +TAPCOMMEXIT_RC init_shmem( + char *errormsg, + uint32_t *errormsglen, + uint32_t *errormsgavail, + const char *db_str, + int force_init + ) { + if (!plugin_loaded()) { + return TAPCOMMEXIT_FAIL; + } + if (func_ptrs::init_shmem == nullptr) { + func_ptrs::init_shmem = reinterpret_cast(dlsym(plugin_handle, "tap_commexit_init_shmem")); + } + if (func_ptrs::init_shmem != nullptr) { + return (*func_ptrs::init_shmem)(errormsg, errormsglen, errormsgavail, db_str, force_init); + } + return TAPCOMMEXIT_FAIL; +} +void shutdown_shmem( + char *logmsg, + uint32_t *logmsglen, + uint32_t *logmsgavail + ) { + if (!plugin_loaded()) { + return; + } + if (func_ptrs::shutdown_shmem == nullptr) { + func_ptrs::shutdown_shmem = reinterpret_cast(dlsym(plugin_handle, "tap_commexit_shutdown_shmem")); + } + if (func_ptrs::shutdown_shmem != nullptr) { + (*func_ptrs::shutdown_shmem)(logmsg, logmsglen, logmsgavail); + } +} +void init( + char *logmsg, + uint32_t *logmsglen, + uint32_t *logmsgavail + ) { + if (!plugin_loaded()) { + return; + } + if (func_ptrs::init == nullptr) { + func_ptrs::init = reinterpret_cast(dlsym(plugin_handle, "tap_commexit_init")); + } + if (func_ptrs::init != nullptr) { + (*func_ptrs::init)(logmsg, logmsglen, logmsgavail); + } + init_db_functions(); +} +TAPCOMMEXIT_RC send_server_data( + char *logmsg, + uint32_t *logmsglen, + uint32_t *logmsgavail, + void *_pContext, + const void *pCommInfo, + int64_t *pReservedFlags, + const char *pBuffer, + int buffer_len, + char **pNewBuffer, + int *new_buffer_len + ) { + if (!plugin_loaded()) { + return TAPCOMMEXIT_FAIL; + } + if (func_ptrs::send_server_data == nullptr) { + func_ptrs::send_server_data = reinterpret_cast(dlsym(plugin_handle, "tap_commexit_send_server_data")); + } + if (func_ptrs::send_server_data != nullptr) { + return (*func_ptrs::send_server_data)(logmsg, logmsglen, logmsgavail, _pContext, pCommInfo, pReservedFlags, pBuffer, buffer_len, pNewBuffer, new_buffer_len); + } + return TAPCOMMEXIT_FAIL; +} +TAPCOMMEXIT_RC send_client_data( + char *logmsg, + uint32_t *logmsglen, + uint32_t *logmsgavail, + void *_pContext, + const void *pCommInfo, + int64_t *pReservedFlags, + const char *pBuffer, + int buffer_len, + char **pNewBuffer, + int *new_buffer_len + ) { + if (!plugin_loaded()) { + return TAPCOMMEXIT_FAIL; + } + if (func_ptrs::send_client_data == nullptr) { + func_ptrs::send_client_data = reinterpret_cast(dlsym(plugin_handle, "tap_commexit_send_client_data")); + } + if (func_ptrs::send_client_data != nullptr) { + return (*func_ptrs::send_client_data)(logmsg, logmsglen, logmsgavail, _pContext, pCommInfo, pReservedFlags, pBuffer, buffer_len, pNewBuffer, new_buffer_len); + } + return TAPCOMMEXIT_FAIL; +} +void send_open( + char *logmsg, + uint32_t *logmsglen, + uint32_t *logmsgavail, + void *_pContext, + const void *pCommInfo + ) { + if (!plugin_loaded()) { + return; + } + if (func_ptrs::send_open == nullptr) { + func_ptrs::send_open = reinterpret_cast(dlsym(plugin_handle, "tap_commexit_send_open")); + } + if (func_ptrs::send_open != nullptr) { + (*func_ptrs::send_open)(logmsg, logmsglen, logmsgavail, _pContext, pCommInfo); + } +} +void send_close( + char *logmsg, + uint32_t *logmsglen, + uint32_t *logmsgavail, + void *_pContext, + const void *pCommInfo + ) { + if (!plugin_loaded()) { + return; + } + if (func_ptrs::send_close == nullptr) { + func_ptrs::send_close = reinterpret_cast(dlsym(plugin_handle, "tap_commexit_send_close")); + } + if (func_ptrs::send_close != nullptr) { + (*func_ptrs::send_close)(logmsg, logmsglen, logmsgavail, _pContext, pCommInfo); + } +} +void * +get_context_opaque( + const void *_pContext + ) { + if (!plugin_loaded()) { + return nullptr; + } + if (func_ptrs::get_context_opaque == nullptr) { + func_ptrs::get_context_opaque = reinterpret_cast(dlsym(plugin_handle, "tap_commexit_get_context_opaque")); + } + if (func_ptrs::get_context_opaque != nullptr) { + return (*func_ptrs::get_context_opaque)(_pContext); + } + return nullptr; +} +void +set_context_opaque( + void *_pContext, + void *opaque + ) { + if (!plugin_loaded()) { + return; + } + if (func_ptrs::set_context_opaque == nullptr) { + func_ptrs::set_context_opaque = reinterpret_cast(dlsym(plugin_handle, "tap_commexit_set_context_opaque")); + } + if (func_ptrs::set_context_opaque != nullptr) { + (*func_ptrs::set_context_opaque)(_pContext, opaque); + } +} +} // namespace tap_commexit diff --git a/sql/tap_commexit_plugin.h b/sql/tap_commexit_plugin.h new file mode 100644 index 000000000000..5b888a32318e --- /dev/null +++ b/sql/tap_commexit_plugin.h @@ -0,0 +1,92 @@ +#ifndef __TAP_COMMEXIT_PLUGIN_H__ +#define __TAP_COMMEXIT_PLUGIN_H__ + +#include "tap_commexit.h" + +namespace tap_commexit { +namespace config { +extern char *library_path; +} + +void load_plugin(); +bool plugin_loaded(); + +void* allocate_context(); +void free_context(void* context); +TAPCOMMEXIT_RC init_context( + char *logmsg, + uint32_t *logmsglen, + uint32_t *logmsgavail, + void *_pContext, + const void *pCommInfo + ); +TAPCOMMEXIT_RC init_shmem ( + char *errormsg, + uint32_t *errormsglen, + uint32_t *errormsgavail, + const char *db_str, + int force_init + ); +void shutdown_shmem( + char *logmsg, + uint32_t *logmsglen, + uint32_t *logmsgavail + ); +void init( + char *logmsg, + uint32_t *logmsglen, + uint32_t *logmsgavail + ); +TAPCOMMEXIT_RC +send_server_data( + char *logmsg, + uint32_t *logmsglen, + uint32_t *logmsgavail, + void *_pContext, + const void *pCommInfo, + int64_t *pReservedFlags, + const char *pBuffer, + int buffer_len, + char **pNewBuffer, + int *new_buffer_len + ); +TAPCOMMEXIT_RC +send_client_data( + char *logmsg, + uint32_t *logmsglen, + uint32_t *logmsgavail, + void *_pContext, + const void *pCommInfo, + int64_t *pReservedFlags, + const char *pBuffer, + int buffer_len, + char **pNewBuffer, + int *new_buffer_len + ); +void +send_open( + char *logmsg, + uint32_t *logmsglen, + uint32_t *logmsgavail, + void *_pContext, + const void *pCommInfo + ); +void +send_close( + char *logmsg, + uint32_t *logmsglen, + uint32_t *logmsgavail, + void *_pContext, + const void *pCommInfo + ); +void * +get_context_opaque( + const void *_pContext + ); +void +set_context_opaque( + void *_pContext, + void *opaque + ); +} +#endif