diff options
author | Vladislav Vaintroub <wlad@mariadb.com> | 2017-08-22 21:08:38 +0200 |
---|---|---|
committer | Vladislav Vaintroub <wlad@mariadb.com> | 2017-08-22 21:08:38 +0200 |
commit | 58cd69fc808cade5ec3183a56b9d16957f0da02c (patch) | |
tree | 4ba0d41e6ad569efa3826162ac3505b103c90dc4 /sql/net_serv.cc | |
parent | d258a2bd1f8548bafc155d0ac1ed06c236d3fca2 (diff) | |
download | mariadb-git-58cd69fc808cade5ec3183a56b9d16957f0da02c.tar.gz |
MDEV-11159 Server proxy protocol support
accept proxy protocol header from client connections.
The new server variable 'proxy_protocol_networks' contains list
of networks from which proxy header is accepted.
Diffstat (limited to 'sql/net_serv.cc')
-rw-r--r-- | sql/net_serv.cc | 81 |
1 files changed, 74 insertions, 7 deletions
diff --git a/sql/net_serv.cc b/sql/net_serv.cc index f9635689e63..765491dc40e 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -45,12 +45,9 @@ #include <violite.h> #include <signal.h> #include "probes_mysql.h" - -#ifdef EMBEDDED_LIBRARY -#undef MYSQL_SERVER -#undef MYSQL_CLIENT -#define MYSQL_CLIENT -#endif /*EMBEDDED_LIBRARY */ +#include "proxy_protocol.h" +#include <sql_class.h> +#include <sql_connect.h> /* to reduce the number of ifdef's in the code @@ -118,7 +115,6 @@ extern my_bool thd_net_is_killed(); #define thd_net_is_killed() 0 #endif -#define TEST_BLOCKING 8 static my_bool net_write_buff(NET *, const uchar *, ulong); @@ -829,6 +825,57 @@ static my_bool my_net_skip_rest(NET *net, uint32 remain, thr_alarm_t *alarmed, /** + Try to parse and process proxy protocol header. + + This function is called in case MySQL packet header cannot be parsed. + It checks if proxy header was sent, and that it was send from allowed remote + host, as defined by proxy-protocol-networks parameter. + + If proxy header is parsed, then THD and ACL structures and changed to indicate + the new peer address and port. + + Note, that proxy header can only be sent either when the connection is established, + or as the client reply packet to +*/ +static int handle_proxy_header(NET *net) +{ + proxy_peer_info peer_info; + THD *thd= (THD *)net->thd; + + if (!thd || !thd->net.vio) + { + DBUG_ASSERT(0); + return 1; + } + + if (!is_proxy_protocol_allowed((sockaddr *)&(thd->net.vio->remote))) + { + /* proxy-protocol-networks variable needs to be set to allow this remote address */ + my_printf_error(ER_HOST_NOT_PRIVILEGED, "Proxy header is not accepted from %s", + MYF(0), thd->main_security_ctx.ip); + return 1; + } + + if (parse_proxy_protocol_header(net, &peer_info)) + { + /* Failed to parse proxy header*/ + my_printf_error(ER_UNKNOWN_ERROR, "Failed to parse proxy header", MYF(0)); + return 1; + } + + if (peer_info.is_local_command) + /* proxy header indicates LOCAL connection, no action necessary */ + return 0; +#ifdef EMBEDDED_LIBRARY + DBUG_ASSERT(0); + return 1; +#else + /* Change peer address in THD and ACL structures.*/ + return thd_set_peer_addr(thd, &(peer_info.peer_addr), NULL, peer_info.port, false); +#endif +} + +/** Reads one packet to net->buff + net->where_b. Long packets are handled by my_net_read(). This function reallocates the net->buff buffer if necessary. @@ -850,6 +897,9 @@ my_real_read(NET *net, size_t *complen, #ifndef NO_ALARM ALARM alarm_buff; #endif + +retry: + my_bool net_blocking=vio_is_blocking(net->vio); uint32 remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE : NET_HEADER_SIZE); @@ -1081,6 +1131,22 @@ end: packets_out_of_order: { + if (has_proxy_protocol_header(net) + && net->thd && + ((THD *)net->thd)->get_command() == COM_CONNECT) + { + /* Proxy information found in the first 4 bytes received so far. + Read and parse proxy header , change peer ip address and port in THD. + */ + if (handle_proxy_header(net)) + { + /* error happened, message is already written. */ + len= packet_error; + goto end; + } + goto retry; + } + DBUG_PRINT("error", ("Packets out of order (Found: %d, expected %u)", (int) net->buff[net->where_b + 3], @@ -1171,6 +1237,7 @@ my_net_read_packet_reallen(NET *net, my_bool read_from_server, ulong* reallen) len+= total_length; net->where_b = save_pos; } + net->read_pos = net->buff + net->where_b; if (len != packet_error) { |