mirror of https://github.com/sysown/proxysql
Merge pull request #4236 from sysown/v2.x_ssl_keylog_support
Added support for SSLKEYLOGFILEpull/4247/head
commit
0acf5bd94f
@ -0,0 +1,14 @@
|
||||
@@ -78,12 +78,13 @@
|
||||
my_bool (*set_option)(MYSQL *mysql, const char *config_option, const char *config_value);
|
||||
HASH userdata;
|
||||
char *server_public_key;
|
||||
char *proxy_header;
|
||||
size_t proxy_header_len;
|
||||
int (*io_wait)(my_socket handle, my_bool is_read, int timeout);
|
||||
+ void (*ssl_keylog_callback)(const void *ssl, const char *line);
|
||||
};
|
||||
|
||||
typedef struct st_connection_handler
|
||||
{
|
||||
struct st_ma_connection_plugin *plugin;
|
||||
void *data;
|
||||
@ -0,0 +1,32 @@
|
||||
@@ -3277,12 +3277,15 @@
|
||||
case MYSQL_OPT_SSL_CRL:
|
||||
OPT_SET_EXTENDED_VALUE_STR(&mysql->options, ssl_crl, (char *)arg1);
|
||||
break;
|
||||
case MYSQL_OPT_SSL_CRLPATH:
|
||||
OPT_SET_EXTENDED_VALUE_STR(&mysql->options, ssl_crlpath, (char *)arg1);
|
||||
break;
|
||||
+ case MARIADB_OPT_SSL_KEYLOG_CALLBACK:
|
||||
+ OPT_SET_EXTENDED_VALUE(&mysql->options, ssl_keylog_callback, arg1);
|
||||
+ break;
|
||||
case MYSQL_OPT_CONNECT_ATTR_DELETE:
|
||||
{
|
||||
uchar *h;
|
||||
CHECK_OPT_EXTENSION_SET(&mysql->options);
|
||||
if (hash_inited(&mysql->options.extension->connect_attrs) &&
|
||||
(h= (uchar *)hash_search(&mysql->options.extension->connect_attrs, (uchar *)arg1,
|
||||
@@ -3614,12 +3617,15 @@
|
||||
case MYSQL_OPT_SSL_CRL:
|
||||
*((char **)arg)= mysql->options.extension ? mysql->options.ssl_cipher : NULL;
|
||||
break;
|
||||
case MYSQL_OPT_SSL_CRLPATH:
|
||||
*((char **)arg)= mysql->options.extension ? mysql->options.extension->ssl_crlpath : NULL;
|
||||
break;
|
||||
+ case MARIADB_OPT_SSL_KEYLOG_CALLBACK:
|
||||
+ *((void(**)(const void *, const char *))arg)= mysql->options.extension ? mysql->options.extension->ssl_keylog_callback : NULL;
|
||||
+ break;
|
||||
case MYSQL_OPT_CONNECT_ATTRS:
|
||||
/* mysql_get_optionsv(mysql, MYSQL_OPT_CONNECT_ATTRS, keys, vals, elements) */
|
||||
{
|
||||
unsigned int i, *elements;
|
||||
char **key= NULL;
|
||||
void *arg1;
|
||||
@ -0,0 +1,16 @@
|
||||
@@ -242,13 +242,14 @@
|
||||
MARIADB_OPT_DEBUG,
|
||||
MARIADB_OPT_FOUND_ROWS,
|
||||
MARIADB_OPT_MULTI_RESULTS,
|
||||
MARIADB_OPT_MULTI_STATEMENTS,
|
||||
MARIADB_OPT_INTERACTIVE,
|
||||
MARIADB_OPT_PROXY_HEADER,
|
||||
- MARIADB_OPT_IO_WAIT
|
||||
+ MARIADB_OPT_IO_WAIT,
|
||||
+ MARIADB_OPT_SSL_KEYLOG_CALLBACK
|
||||
};
|
||||
|
||||
enum mariadb_value {
|
||||
MARIADB_CHARSET_ID,
|
||||
MARIADB_CHARSET_NAME,
|
||||
MARIADB_CLIENT_ERRORS,
|
||||
@ -0,0 +1,34 @@
|
||||
@@ -526,12 +526,19 @@
|
||||
memset(buf, 0, size);
|
||||
if (userdata)
|
||||
strncpy(buf, (char *)userdata, size);
|
||||
return (int)strlen(buf);
|
||||
}
|
||||
|
||||
+static void ma_tls_set_sslkeylog_callback(MYSQL *mysql, SSL_CTX *ssl_ctx)
|
||||
+{
|
||||
+ if (mysql->options.extension && mysql->options.extension->ssl_keylog_callback)
|
||||
+ {
|
||||
+ SSL_CTX_set_keylog_callback(ssl_ctx, (void(*)(const SSL*, const char*))mysql->options.extension->ssl_keylog_callback);
|
||||
+ }
|
||||
+}
|
||||
|
||||
static int ma_tls_set_certs(MYSQL *mysql, SSL *ssl)
|
||||
{
|
||||
char *certfile= mysql->options.ssl_cert,
|
||||
*keyfile= mysql->options.ssl_key;
|
||||
char *pw= (mysql->options.extension) ?
|
||||
@@ -653,12 +660,13 @@
|
||||
if (!(ctx= SSL_CTX_new(SSLv23_client_method())))
|
||||
#endif
|
||||
goto error;
|
||||
if (mysql->options.extension)
|
||||
options|= ma_tls_version_options(mysql->options.extension->tls_version);
|
||||
SSL_CTX_set_options(ctx, options);
|
||||
+ ma_tls_set_sslkeylog_callback(mysql, ctx);
|
||||
#ifdef HAVE_TLS_SESSION_CACHE
|
||||
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_CLIENT);
|
||||
ma_tls_sessions= (MA_SSL_SESSION *)calloc(1, sizeof(struct st_ma_tls_session) * ma_tls_session_cache_size);
|
||||
SSL_CTX_sess_set_new_cb(ctx, ma_tls_session_cb);
|
||||
SSL_CTX_sess_set_remove_cb(ctx, ma_tls_remove_session_cb);
|
||||
#endif
|
||||
@ -0,0 +1,11 @@
|
||||
#ifndef __PROXYSQL_SSLKEYLOG_H
|
||||
#define __PROXYSQL_SSLKEYLOG_H
|
||||
#include "proxysql.h"
|
||||
|
||||
void proxysql_keylog_init();
|
||||
bool proxysql_keylog_open(const char* keylog_file);
|
||||
void proxysql_keylog_close(bool lock = true);
|
||||
void proxysql_keylog_attach_callback(SSL_CTX* ssl_ctx);
|
||||
void proxysql_keylog_write_line_callback(const SSL* ssl, const char* line);
|
||||
|
||||
#endif // __PROXYSQL_SSLKEYLOG_H
|
||||
@ -0,0 +1,102 @@
|
||||
#include "proxysql_sslkeylog.h"
|
||||
|
||||
// http://udn.realityripple.com/docs/Mozilla/Projects/NSS/Key_Log_Format
|
||||
|
||||
#define KEYLOG_LABEL_MAXLEN (sizeof("CLIENT_HANDSHAKE_TRAFFIC_SECRET") - 1)
|
||||
|
||||
#define CLIENT_RANDOM_SIZE 32
|
||||
|
||||
/*
|
||||
* The master secret in TLS 1.2 and before is always 48 bytes. In TLS 1.3, the
|
||||
* secret size depends on the cipher suite's hash function which is 32 bytes
|
||||
* for SHA-256 and 48 bytes for SHA-384.
|
||||
*/
|
||||
#define SECRET_MAXLEN 48
|
||||
|
||||
static pthread_rwlock_t keylog_file_rwlock;
|
||||
|
||||
/* The fp for the open SSLKEYLOGFILE, or NULL if not open */
|
||||
static FILE *keylog_file_fp = NULL;
|
||||
|
||||
FILE* proxysql_open_file(const char* file) {
|
||||
FILE *file_tmp = fopen(file, "a+");
|
||||
if (file_tmp) {
|
||||
if (setvbuf(file_tmp, NULL, _IOLBF, 4096)) {
|
||||
fclose(file_tmp);
|
||||
file_tmp = NULL;
|
||||
goto __exit;
|
||||
}
|
||||
}
|
||||
__exit:
|
||||
return file_tmp;
|
||||
}
|
||||
|
||||
void proxysql_keylog_init() {
|
||||
pthread_rwlock_init(&keylog_file_rwlock, nullptr);
|
||||
keylog_file_fp = NULL;
|
||||
}
|
||||
|
||||
bool proxysql_keylog_open(const char* keylog_file)
|
||||
{
|
||||
assert(keylog_file);
|
||||
FILE* keylog_file_tmp = proxysql_open_file(keylog_file);
|
||||
if (!keylog_file_tmp) return false;
|
||||
pthread_rwlock_wrlock(&keylog_file_rwlock);
|
||||
proxysql_keylog_close(false);
|
||||
keylog_file_fp = keylog_file_tmp;
|
||||
pthread_rwlock_unlock(&keylog_file_rwlock);
|
||||
return true;
|
||||
}
|
||||
|
||||
void proxysql_keylog_close(bool lock)
|
||||
{
|
||||
if (lock)
|
||||
pthread_rwlock_wrlock(&keylog_file_rwlock);
|
||||
if(keylog_file_fp) {
|
||||
fclose(keylog_file_fp);
|
||||
keylog_file_fp = NULL;
|
||||
}
|
||||
if (lock)
|
||||
pthread_rwlock_unlock(&keylog_file_rwlock);
|
||||
}
|
||||
|
||||
void proxysql_keylog_write_line_callback(const SSL *ssl, const char *line)
|
||||
{
|
||||
(void)ssl; // to fix warning
|
||||
|
||||
// checking keylog_file_fp without acquiring a lock is safe, as it is checked again after acquring lock
|
||||
if (!keylog_file_fp) return;
|
||||
|
||||
/* The current maximum valid keylog line length LF and NUL is 195. */
|
||||
size_t linelen;
|
||||
char buf[256];
|
||||
|
||||
pthread_rwlock_rdlock(&keylog_file_rwlock);
|
||||
if(!keylog_file_fp || !line) {
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
linelen = strlen(line);
|
||||
if(linelen == 0 || linelen > sizeof(buf) - 2) {
|
||||
/* Empty line or too big to fit in a LF and NUL. */
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
memcpy(buf, line, linelen);
|
||||
if(line[linelen - 1] != '\n') {
|
||||
buf[linelen++] = '\n';
|
||||
}
|
||||
buf[linelen] = '\0';
|
||||
|
||||
/* as we are using rwlock, using fputs as it's thread-safe*/
|
||||
fputs(buf, keylog_file_fp);
|
||||
|
||||
__exit:
|
||||
pthread_rwlock_unlock(&keylog_file_rwlock);
|
||||
}
|
||||
|
||||
void proxysql_keylog_attach_callback(SSL_CTX* ssl_ctx) {
|
||||
if (ssl_ctx && (SSL_CTX_get_keylog_callback(ssl_ctx) == (SSL_CTX_keylog_cb_func)NULL)) {
|
||||
SSL_CTX_set_keylog_callback(ssl_ctx, proxysql_keylog_write_line_callback);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in new issue