Commit 58cd69fc authored by Vladislav Vaintroub's avatar Vladislav Vaintroub

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.
parent d258a2bd
......@@ -112,6 +112,8 @@ extern void vio_set_wait_callback(void (*before_wait)(void),
my_bool vio_socket_connect(Vio *vio, struct sockaddr *addr, socklen_t len,
int timeout);
void vio_get_normalized_ip(const struct sockaddr *src, int src_length, struct sockaddr *dst, int *dst_length);
my_bool vio_get_normalized_ip_string(const struct sockaddr *addr, int addr_length,
char *ip_string, size_t ip_string_size);
......
......@@ -117,6 +117,7 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc
../sql/ha_sequence.cc ../sql/ha_sequence.h
../sql/temporary_tables.cc
../sql/session_tracker.cc
../sql/proxy_protocol.cc
${GEN_SOURCES}
${MYSYS_LIBWRAP_SOURCE}
)
......
SET @old_general_log= @@global.general_log;
SET @old_slow_query_log= @@global.slow_query_log;
call mtr.add_suppression(" Error reading file './client_test_db/test_frm_bug.frm'");
call mtr.add_suppression(" IP address .* could not be resolved");
ok
# cat MYSQL_TMP_DIR/test_wl4435.out.log
......
SET @old_slow_query_log= @@global.slow_query_log;
call mtr.add_suppression(" Error reading file './client_test_db/test_frm_bug.frm'");
call mtr.add_suppression(" IP address .* could not be resolved");
ok
SET @@global.slow_query_log= @old_slow_query_log;
SET @old_general_log= @@global.general_log;
SET @old_slow_query_log= @@global.slow_query_log;
call mtr.add_suppression(" Error reading file './client_test_db/test_frm_bug.frm'");
call mtr.add_suppression(" IP address .* could not be resolved");
ok
SET @@global.general_log= @old_general_log;
SET @@global.slow_query_log= @old_slow_query_log;
......@@ -783,6 +783,14 @@ The following options may be given as the first argument:
Seconds between sending progress reports to the client
for time-consuming statements. Set to 0 to disable
progress reporting.
--proxy-protocol-networks=name
Enable proxy protocol for these source networks. The
syntax is a comma separated list of IPv4 and IPv6
networks. If the network doesn't contain mask, it is
considered to be a single host. "*" represents all
networks and must the only directive on the line. String
"localhost" represents non-TCP local connections (Unix
domain socket, Windows named pipe or shared memory).
--query-alloc-block-size=#
Allocation block size for query parsing and execution
--query-cache-limit=#
......@@ -1437,6 +1445,7 @@ preload-buffer-size 32768
profiling-history-size 15
progress-report-time 5
protocol-version 10
proxy-protocol-networks
query-alloc-block-size 16384
query-cache-limit 1048576
query-cache-min-res-unit 4096
......
......@@ -3369,6 +3369,20 @@ NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY YES
COMMAND_LINE_ARGUMENT NULL
VARIABLE_NAME PROXY_PROTOCOL_NETWORKS
SESSION_VALUE NULL
GLOBAL_VALUE
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE VARCHAR
VARIABLE_COMMENT Enable proxy protocol for these source networks. The syntax is a comma separated list of IPv4 and IPv6 networks. If the network doesn't contain mask, it is considered to be a single host. "*" represents all networks and must the only directive on the line.
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST NULL
READ_ONLY YES
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME PROXY_USER
SESSION_VALUE
GLOBAL_VALUE NULL
......
......@@ -2,3 +2,4 @@
--general-log-file=$MYSQLTEST_VARDIR/log/master.log
--log-output=FILE,TABLE
--max-allowed-packet=32000000
--proxy-protocol-networks=*
......@@ -7,6 +7,7 @@ SET @old_general_log= @@global.general_log;
SET @old_slow_query_log= @@global.slow_query_log;
call mtr.add_suppression(" Error reading file './client_test_db/test_frm_bug.frm'");
call mtr.add_suppression(" IP address .* could not be resolved");
# We run with different binaries for normal and --embedded-server
#
......
--loose-enable-performance-schema
--max-allowed-packet=32000000
--proxy-protocol-networks=::1/32,127.0.0.0/8,localhost
......@@ -9,7 +9,7 @@
SET @old_slow_query_log= @@global.slow_query_log;
call mtr.add_suppression(" Error reading file './client_test_db/test_frm_bug.frm'");
call mtr.add_suppression(" IP address .* could not be resolved");
--exec echo "$MYSQL_CLIENT_TEST" > $MYSQLTEST_VARDIR/log/mysql_client_test_comp.out.log 2>&1
--exec $MYSQL_CLIENT_TEST --getopt-ll-test=25600M >> $MYSQLTEST_VARDIR/log/mysql_client_test_comp.out.log 2>&1
......
--general-log --general-log-file=$MYSQLTEST_VARDIR/log/master.log --log-output=FILE,TABLE
--max-allowed-packet=32000000
--proxy-protocol-networks=::1,::ffff:127.0.0.1/97,localhost
......@@ -6,6 +6,7 @@
SET @old_general_log= @@global.general_log;
SET @old_slow_query_log= @@global.slow_query_log;
call mtr.add_suppression(" Error reading file './client_test_db/test_frm_bug.frm'");
call mtr.add_suppression(" IP address .* could not be resolved");
# We run with different binaries for normal and --embedded-server
#
......
......@@ -154,6 +154,7 @@ SET (SQL_SOURCE
sql_sequence.cc sql_sequence.h ha_sequence.h
${WSREP_SOURCES}
table_cache.cc encryption.cc temporary_tables.cc
proxy_protocol.cc
${CMAKE_CURRENT_BINARY_DIR}/sql_builtin.cc
${GEN_SOURCES}
${GEN_DIGEST_SOURCES}
......
......@@ -75,6 +75,7 @@
#include "wsrep_var.h"
#include "wsrep_thd.h"
#include "wsrep_sst.h"
#include "proxy_protocol.h"
#include "sql_callback.h"
#include "threadpool.h"
......@@ -2286,6 +2287,7 @@ void clean_up(bool print_message)
my_free(const_cast<char*>(relay_log_index));
#endif
free_list(opt_plugin_load_list_ptr);
cleanup_proxy_protocol_networks();
/*
The following lines may never be executed as the main thread may have
......@@ -2682,6 +2684,9 @@ static void network_init(void)
if (MYSQL_CALLBACK_ELSE(thread_scheduler, init, (), 0))
unireg_abort(1); /* purecov: inspected */
if (set_proxy_protocol_networks(my_proxy_protocol_networks))
unireg_abort(1);
set_ports();
if (report_port == 0)
......
......@@ -558,6 +558,7 @@ extern MYSQL_PLUGIN_IMPORT char mysql_real_data_home[];
extern char mysql_unpacked_real_data_home[];
extern MYSQL_PLUGIN_IMPORT struct system_variables global_system_variables;
extern char default_logfile_name[FN_REFLEN];
extern char *my_proxy_protocol_networks;
#define mysql_tmpdir (my_tmpdir(&mysql_tmpdir_list))
......
......@@ -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);
......@@ -828,6 +824,57 @@ static my_bool my_net_skip_rest(NET *net, uint32 remain, thr_alarm_t *alarmed,
#endif /* NO_ALARM */
/**
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().
......@@ -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 @@ my_real_read(NET *net, size_t *complen,
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)
{
......
This diff is collapsed.
#include "my_net.h"
struct proxy_peer_info
{
struct sockaddr_storage peer_addr;
int port;
bool is_local_command;
};
extern bool has_proxy_protocol_header(NET *net);
extern int parse_proxy_protocol_header(NET *net, proxy_peer_info *peer_info);
extern bool is_proxy_protocol_allowed(const sockaddr *remote_addr);
extern int set_proxy_protocol_networks(const char *spec);
extern void cleanup_proxy_protocol_networks();
......@@ -37,6 +37,7 @@
#include "sql_acl.h" // acl_getroot, NO_ACCESS, SUPER_ACL
#include "sql_callback.h"
#include "wsrep_mysqld.h"
#include "proxy_protocol.h"
HASH global_user_stats, global_client_stats, global_table_stats;
HASH global_index_stats;
......@@ -836,6 +837,89 @@ bool init_new_connection_handler_thread()
return 0;
}
int thd_set_peer_addr(THD *thd, sockaddr_storage *addr, const char *ip,uint port, bool check_proxy_networks)
{
uint connect_errors;
thd->peer_port = port;
char ip_string[128];
if (!ip)
{
void *addr_data;
if (addr->ss_family == AF_UNIX)
{
/* local connection */
my_free((void *)thd->main_security_ctx.ip);
thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host = my_localhost;
thd->main_security_ctx.ip= 0;
return 0;
}
else if (addr->ss_family == AF_INET)
addr_data= &((struct sockaddr_in *)addr)->sin_addr;
else
addr_data= &((struct sockaddr_in6 *)addr)->sin6_addr;
if (!inet_ntop(addr->ss_family,addr_data, ip_string, sizeof(ip_string)))
{
DBUG_ASSERT(0);
return 1;
}
ip= ip_string;
}
my_free((void *)thd->main_security_ctx.ip);
if (!(thd->main_security_ctx.ip = my_strdup(ip, MYF(MY_WME))))
{
/*
No error accounting per IP in host_cache,
this is treated as a global server OOM error.
TODO: remove the need for my_strdup.
*/
statistic_increment(aborted_connects, &LOCK_status);
statistic_increment(connection_errors_internal, &LOCK_status);
return 1; /* The error is set by my_strdup(). */
}
thd->main_security_ctx.host_or_ip = thd->main_security_ctx.ip;
if (!(specialflag & SPECIAL_NO_RESOLVE))
{
int rc;
rc = ip_to_hostname(addr,
thd->main_security_ctx.ip,
&thd->main_security_ctx.host,
&connect_errors);
/* Cut very long hostnames to avoid possible overflows */
if (thd->main_security_ctx.host)
{
if (thd->main_security_ctx.host != my_localhost)
((char*)thd->main_security_ctx.host)[MY_MIN(strlen(thd->main_security_ctx.host),
HOSTNAME_LENGTH)] = 0;
thd->main_security_ctx.host_or_ip = thd->main_security_ctx.host;
}
if (rc == RC_BLOCKED_HOST)
{
/* HOST_CACHE stats updated by ip_to_hostname(). */
my_error(ER_HOST_IS_BLOCKED, MYF(0), thd->main_security_ctx.host_or_ip);
return 1;
}
}
DBUG_PRINT("info", ("Host: %s ip: %s",
(thd->main_security_ctx.host ?
thd->main_security_ctx.host : "unknown host"),
(thd->main_security_ctx.ip ?
thd->main_security_ctx.ip : "unknown ip")));
if ((!check_proxy_networks || !is_proxy_protocol_allowed((struct sockaddr *) addr))
&& acl_check_host(thd->main_security_ctx.host, thd->main_security_ctx.ip))
{
/* HOST_CACHE stats updated by acl_check_host(). */
my_error(ER_HOST_NOT_PRIVILEGED, MYF(0),
thd->main_security_ctx.host_or_ip);
return 1;
}
return 0;
}
/*
Perform handshake, authorize client and update thd ACL variables.
......@@ -865,8 +949,9 @@ static int check_connection(THD *thd)
{
my_bool peer_rc;
char ip[NI_MAXHOST];
uint16 peer_port;
peer_rc= vio_peer_addr(net->vio, ip, &thd->peer_port, NI_MAXHOST);
peer_rc= vio_peer_addr(net->vio, ip, &peer_port, NI_MAXHOST);
/*
===========================================================================
......@@ -941,56 +1026,10 @@ static int check_connection(THD *thd)
my_error(ER_BAD_HOST_ERROR, MYF(0));
return 1;
}
if (!(thd->main_security_ctx.ip= my_strdup(ip,MYF(MY_WME))))
{
/*
No error accounting per IP in host_cache,
this is treated as a global server OOM error.
TODO: remove the need for my_strdup.
*/
statistic_increment(aborted_connects,&LOCK_status);
statistic_increment(connection_errors_internal, &LOCK_status);
return 1; /* The error is set by my_strdup(). */
}
thd->main_security_ctx.host_or_ip= thd->main_security_ctx.ip;
if (!(specialflag & SPECIAL_NO_RESOLVE))
{
int rc;
rc= ip_to_hostname(&net->vio->remote,
thd->main_security_ctx.ip,
&thd->main_security_ctx.host,
&connect_errors);
/* Cut very long hostnames to avoid possible overflows */
if (thd->main_security_ctx.host)
{
if (thd->main_security_ctx.host != my_localhost)
((char*) thd->main_security_ctx.host)[MY_MIN(strlen(thd->main_security_ctx.host),
HOSTNAME_LENGTH)]= 0;
thd->main_security_ctx.host_or_ip= thd->main_security_ctx.host;
}
if (rc == RC_BLOCKED_HOST)
{
/* HOST_CACHE stats updated by ip_to_hostname(). */
my_error(ER_HOST_IS_BLOCKED, MYF(0), thd->main_security_ctx.host_or_ip);
if (thd_set_peer_addr(thd, &net->vio->remote, ip, peer_port, true))
return 1;
}
}
DBUG_PRINT("info",("Host: %s ip: %s",
(thd->main_security_ctx.host ?
thd->main_security_ctx.host : "unknown host"),
(thd->main_security_ctx.ip ?
thd->main_security_ctx.ip : "unknown ip")));
if (acl_check_host(thd->main_security_ctx.host, thd->main_security_ctx.ip))
{
/* HOST_CACHE stats updated by acl_check_host(). */
my_error(ER_HOST_NOT_PRIVILEGED, MYF(0),
thd->main_security_ctx.host_or_ip);
return 1;
}
}
else /* Hostname given means that the connection was on a socket */
{
DBUG_PRINT("info",("Host: %s", thd->main_security_ctx.host));
......
......@@ -85,6 +85,7 @@ bool thd_init_client_charset(THD *thd, uint cs_number);
bool setup_connection_thread_globals(THD *thd);
bool thd_prepare_connection(THD *thd);
bool thd_is_connection_alive(THD *thd);
int thd_set_peer_addr(THD *thd, sockaddr_storage *addr, const char *ip, uint port, bool check_proxy_networks);
bool login_connection(THD *thd);
void prepare_new_connection_state(THD* thd);
......
......@@ -4126,6 +4126,17 @@ static Sys_var_charptr Sys_license(
READ_ONLY GLOBAL_VAR(license), NO_CMD_LINE, IN_SYSTEM_CHARSET,
DEFAULT(STRINGIFY_ARG(LICENSE)));
char *my_proxy_protocol_networks;
static Sys_var_charptr Sys_proxy_protocol_networks(
"proxy_protocol_networks", "Enable proxy protocol for these source "
"networks. The syntax is a comma separated list of IPv4 and IPv6 "
"networks. If the network doesn't contain mask, it is considered to be "
"a single host. \"*\" represents all networks and must the only "
"directive on the line. String \"localhost\" represents non-TCP "
"local connections (Unix domain socket, Windows named pipe or shared memory).",
READ_ONLY GLOBAL_VAR(my_proxy_protocol_networks),
CMD_LINE(REQUIRED_ARG), IN_FS_CHARSET, DEFAULT(""));
static bool check_log_path(sys_var *self, THD *thd, set_var *var)
{
if (!var->value)
......
......@@ -33,6 +33,9 @@
*/
#include "mysql_client_fw.c"
#ifndef _WIN32
#include <arpa/inet.h>
#endif
static const my_bool my_true= 1;
......@@ -19635,6 +19638,181 @@ static void test_mdev12579()
}
typedef struct {
char sig[12];
char ver_cmd;
char fam;
short len;
union {
struct { /* for TCP/UDP over IPv4, len = 12 */
int src_addr;
int dst_addr;
short src_port;
short dst_port;
} ip4;
struct { /* for TCP/UDP over IPv6, len = 36 */
char src_addr[16];
char dst_addr[16];
short src_port;
short dst_port;
} ip6;
struct { /* for AF_UNIX sockets, len = 216 */
char src_addr[108];
char dst_addr[108];
} unx;
} addr;
} v2_proxy_header;
#ifndef EMBEDDED_LIBRARY
static void test_proxy_header_tcp(const char *ipaddr, int port)
{
int rc;
MYSQL_RES *result;
int family = (strchr(ipaddr,':') == NULL)?AF_INET:AF_INET6;
char query[256];
char text_header[256];
char addr_bin[16];
v2_proxy_header v2_header;
void *header_data[2];
size_t header_lengths[2];
int i;
// normalize IPv4-mapped IPv6 addresses, e.g ::ffff:192.168.0.1 to 192.168.0.1
char *normalized_addr= strncmp(ipaddr, "::ffff:", 7)?ipaddr : ipaddr + 7;
memset(&v2_header, 0, sizeof(v2_header));
sprintf(text_header,"PROXY %s %s %s %d 3306\r\n",family == AF_INET?"TCP4":"TCP6", ipaddr, ipaddr, port);
inet_pton(family,ipaddr,addr_bin);
memcpy(v2_header.sig, "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A", 12);
v2_header.ver_cmd = (0x2 << 4) | 0x1; /* Version (0x2) , Command = PROXY (0x1) */
if(family == AF_INET)
{
v2_header.fam= 0x11;
v2_header.len= htons(12);
v2_header.addr.ip4.src_port= htons(port);
v2_header.addr.ip4.dst_port= htons(3306);
memcpy(&v2_header.addr.ip4.src_addr,addr_bin, sizeof (v2_header.addr.ip4.src_addr));
memcpy(&v2_header.addr.ip4.dst_addr,addr_bin, sizeof (v2_header.addr.ip4.dst_addr));
}
else
{
v2_header.fam= 0x21;
v2_header.len= htons(36);
v2_header.addr.ip6.src_port= htons(port);
v2_header.addr.ip6.dst_port= htons(3306);
memcpy(v2_header.addr.ip6.src_addr,addr_bin, sizeof (v2_header.addr.ip6.src_addr));
memcpy(v2_header.addr.ip6.dst_addr,addr_bin, sizeof (v2_header.addr.ip6.dst_addr));
}
sprintf(query,"CREATE USER 'u'@'%s' IDENTIFIED BY 'password'",normalized_addr);
rc= mysql_query(mysql, query);
myquery(rc);
header_data[0]= text_header;
header_data[1]= &v2_header;
header_lengths[0]= strlen(text_header);
header_lengths[1]= family == AF_INET ? 28 : 52;
for (i = 0; i < 2; i++)
{
MYSQL *m;
size_t addrlen;
MYSQL_ROW row;
m = mysql_client_init(NULL);
DIE_UNLESS(m);
mysql_optionsv(m, MARIADB_OPT_PROXY_HEADER, header_data[i], header_lengths[i]);
if (!mysql_real_connect(m, opt_host, "u", "password", NULL, opt_port, opt_unix_socket, 0))
{
DIE_UNLESS(0);
}
rc= mysql_query(m, "select host from information_schema.processlist WHERE ID = connection_id()");
myquery(rc);
/* get the result */
result= mysql_store_result(m);
mytest(result);
row = mysql_fetch_row(result);
addrlen = strlen(normalized_addr);
DIE_UNLESS(strncmp(row[0], normalized_addr, addrlen) == 0);
DIE_UNLESS(atoi(row[0] + addrlen+1) == port);
mysql_close(m);
}
sprintf(query,"DROP USER 'u'@'%s'",normalized_addr);
rc = mysql_query(mysql, query);
myquery(rc);
}
/* Test proxy protocol with AF_UNIX (localhost) */
static void test_proxy_header_localhost()
{
v2_proxy_header v2_header;
void *header_data = &v2_header;
size_t header_length= 216 + 16;
MYSQL *m;
MYSQL_RES *result;
MYSQL_ROW row;
int rc;
memset(&v2_header, 0, sizeof(v2_header));
memcpy(v2_header.sig, "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A", 12);
v2_header.ver_cmd = (0x2 << 4) | 0x1; /* Version (0x2) , Command = PROXY (0x1) */
v2_header.fam= 0x31;
v2_header.len= htons(216);
strcpy(v2_header.addr.unx.src_addr,"/tmp/mysql.sock");
strcpy(v2_header.addr.unx.dst_addr,"/tmp/mysql.sock");
rc = mysql_query(mysql, "CREATE USER 'u'@'localhost' IDENTIFIED BY 'password'");
myquery(rc);
m = mysql_client_init(NULL);
DIE_UNLESS(m != NULL);
mysql_optionsv(m, MARIADB_OPT_PROXY_HEADER, header_data, header_length);
DIE_UNLESS(mysql_real_connect(m, opt_host, "u", "password", NULL, opt_port, opt_unix_socket, 0) == m);
DIE_UNLESS(mysql_query(m, "select host from information_schema.processlist WHERE ID = connection_id()") == 0);
/* get the result */
result= mysql_store_result(m);
mytest(result);
row = mysql_fetch_row(result);
DIE_UNLESS(strcmp(row[0], "localhost") == 0);
mysql_close(m);
rc = mysql_query(mysql, "DROP USER 'u'@'localhost'");
myquery(rc);
}
/* Proxy header ignoring */
static void test_proxy_header_ignore()
{
MYSQL *m = mysql_client_init(NULL);
v2_proxy_header v2_header;
DIE_UNLESS(m != NULL);
mysql_optionsv(m, MARIADB_OPT_PROXY_HEADER, "PROXY UNKNOWN\r\n",15);
DIE_UNLESS(mysql_real_connect(m, opt_host, "root", "", NULL, opt_port, opt_unix_socket, 0) == m);
mysql_close(m);
memcpy(v2_header.sig, "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A", 12);
v2_header.ver_cmd = (0x2 << 4) | 0x0; /* Version (0x2) , Command = LOCAL (0x0) */
v2_header.fam= 0x0; /* AF_UNSPEC*/
v2_header.len= htons(0);
m = mysql_client_init(NULL);
mysql_optionsv(m, MARIADB_OPT_PROXY_HEADER, &v2_header,16);
DIE_UNLESS(mysql_real_connect(m, opt_host, "root", "", NULL, opt_port, opt_unix_socket, 0) == m);
mysql_close(m);
}
static void test_proxy_header()
{
test_proxy_header_tcp("192.168.0.1",3333);
test_proxy_header_tcp("2001:db8:85a3::8a2e:370:7334",2222);
test_proxy_header_tcp("::ffff:192.168.0.1",2222);
test_proxy_header_localhost();
test_proxy_header_ignore();
}
#endif
static struct my_tests_st my_tests[]= {
{ "disable_query_logs", disable_query_logs },
{ "test_view_sp_list_fields", test_view_sp_list_fields },
......@@ -19914,6 +20092,9 @@ static struct my_tests_st my_tests[]= {
{ "test_big_packet", test_big_packet },
{ "test_prepare_analyze", test_prepare_analyze },
{ "test_mdev12579", test_mdev12579 },
#ifndef EMBEDDED_LIBRARY
{ "test_proxy_header", test_proxy_header},
#endif
{ 0, 0 }
};
......
......@@ -627,7 +627,7 @@ my_socket vio_fd(Vio* vio)
@param dst_length [out] actual length of the normalized IP address.
*/
static void vio_get_normalized_ip(const struct sockaddr *src,
void vio_get_normalized_ip(const struct sockaddr *src,
int src_length,
struct sockaddr *dst,
int *dst_length)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment