Hello, As you might now, we are currently doing MySQL checks using the old authentication packets which work with old MySQL servers. This was fine until MySQL 5.6 decided to send warnings about old clients accessing the servers which cannot be silenced.
There is even a bug report about it, but that one is not likely to get resolved in the near future [1]. Although this technically is not a HAproxy problem, we might as well add v4.1+ support as Oracle will eventually drop support for older clients in new MySQL versions. I have attached the patch to support basic post 4.1 checks in HAproxy and have tested it on a couple of MySQL setups with success. Let me know if you have any comments and I will be happy to rework the patch. [1] http://bugs.mysql.com/bug.php?id=72543 Best regards, -- Nenad Merdanovic | PGP: 0x423edcb2 | Web: http://nimzo.info Linkedin: http://www.linkedin.com/in/nenadmerdanovic
>From 2d7c2a566c7043b5233a7f1b529b1a3aedb9dd6e Mon Sep 17 00:00:00 2001 From: Nenad Merdanovic <[email protected]> Date: Fri, 30 May 2014 14:26:32 +0200 Subject: [PATCH 1/1] mysql-check: Add support for v4.1+ authentication MySQL will in stop supporting pre-4.1 authentication packets in the future and is already giving us a hard time regarding non-silencable warnings which are logged on each health check. Warnings look like the following: "[Warning] Client failed to provide its character set. 'latin1' will be used as client character set." This patch adds basic support for post-4.1 authentication by sending the proper authentication packet with the character set, along with the QUIT command. --- doc/configuration.txt | 3 +- src/cfgparse.c | 85 +++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 68 insertions(+), 20 deletions(-) diff --git a/doc/configuration.txt b/doc/configuration.txt index d7ba2f8..d28c91a 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -4458,13 +4458,14 @@ no option logasap logging. -option mysql-check [ user <username> ] +option mysql-check [ user <username> [ post-41 ] ] Use MySQL health checks for server testing May be used in sections : defaults | frontend | listen | backend yes | no | yes | yes Arguments : <username> This is the username which will be used when connecting to MySQL server. + post-41 Send post v4.1 client compatible checks If you specify a username, the check consists of sending two MySQL packet, one Client Authentication packet, and one QUIT packet, to correctly close diff --git a/src/cfgparse.c b/src/cfgparse.c index 0a32df4..f62526a 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -3869,7 +3869,7 @@ stats_error_parsing: curproxy->options2 &= ~PR_O2_CHK_ANY; curproxy->options2 |= PR_O2_MYSQL_CHK; - /* This is an exemple of an MySQL >=4.0 client Authentication packet kindly provided by Cyril Bonte. + /* This is an example of a MySQL >=4.0 client Authentication packet kindly provided by Cyril Bonte. * const char mysql40_client_auth_pkt[] = { * "\x0e\x00\x00" // packet length * "\x01" // packet number @@ -3883,6 +3883,23 @@ stats_error_parsing: * }; */ + /* This is an example of a MySQL >=4.1 client Authentication packet provided by Nenad Merdanovic. + * const char mysql41_client_auth_pkt[] = { + * "\x0e\x00\x00\" // packet length + * "\x01" // packet number + * "\x00\x00\x00\x00" // client capabilities + * "\x00\x00\x00\x01" // max packet + * "\x21" // character set (UTF-8) + * char[23] // All zeroes + * "haproxy\x00" // username (null terminated string) + * "\x00" // filler (always 0x00) + * "\x01\x00\x00" // packet length + * "\x00" // packet number + * "\x01" // COM_QUIT command + * }; + */ + + if (*(args[2])) { int cur_arg = 2; @@ -3900,25 +3917,55 @@ stats_error_parsing: } mysqluser = args[cur_arg + 1]; userlen = strlen(mysqluser); - packetlen = userlen + 7; - reqlen = packetlen + 9; - free(curproxy->check_req); - curproxy->check_req = (char *)calloc(1, reqlen); - curproxy->check_len = reqlen; - - snprintf(curproxy->check_req, 4, "%c%c%c", - ((unsigned char) packetlen & 0xff), - ((unsigned char) (packetlen >> 8) & 0xff), - ((unsigned char) (packetlen >> 16) & 0xff)); - - curproxy->check_req[3] = 1; - curproxy->check_req[5] = 128; - curproxy->check_req[8] = 1; - memcpy(&curproxy->check_req[9], mysqluser, userlen); - curproxy->check_req[9 + userlen + 1 + 1] = 1; - curproxy->check_req[9 + userlen + 1 + 1 + 4] = 1; - cur_arg += 2; + if (*(args[cur_arg+2])) { + if (!strcmp(args[cur_arg+2], "post-41")) { + packetlen = userlen + 7 + 27; + reqlen = packetlen + 9; + + free(curproxy->check_req); + curproxy->check_req = (char *)calloc(1, reqlen); + curproxy->check_len = reqlen; + + snprintf(curproxy->check_req, 4, "%c%c%c", + ((unsigned char) packetlen & 0xff), + ((unsigned char) (packetlen >> 8) & 0xff), + ((unsigned char) (packetlen >> 16) & 0xff)); + + curproxy->check_req[3] = 1; + curproxy->check_req[5] = 130; + curproxy->check_req[11] = 1; + curproxy->check_req[12] = 33; + memcpy(&curproxy->check_req[36], mysqluser, userlen); + curproxy->check_req[36 + userlen + 1 + 1] = 1; + curproxy->check_req[36 + userlen + 1 + 1 + 4] = 1; + cur_arg += 3; + } else { + Alert("parsing [%s:%d] : keyword '%s' only supports option 'post-41'.\n", file, linenum, args[cur_arg+2]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + } else { + packetlen = userlen + 7; + reqlen = packetlen + 9; + + free(curproxy->check_req); + curproxy->check_req = (char *)calloc(1, reqlen); + curproxy->check_len = reqlen; + + snprintf(curproxy->check_req, 4, "%c%c%c", + ((unsigned char) packetlen & 0xff), + ((unsigned char) (packetlen >> 8) & 0xff), + ((unsigned char) (packetlen >> 16) & 0xff)); + + curproxy->check_req[3] = 1; + curproxy->check_req[5] = 128; + curproxy->check_req[8] = 1; + memcpy(&curproxy->check_req[9], mysqluser, userlen); + curproxy->check_req[9 + userlen + 1 + 1] = 1; + curproxy->check_req[9 + userlen + 1 + 1 + 4] = 1; + cur_arg += 2; + } } else { /* unknown suboption - catchall */ Alert("parsing [%s:%d] : '%s %s' only supports optional values: 'user'.\n", -- 1.8.5.2

