MDEV-15501 : Make proxy_protocol_networks
variable read-write.
This commit is contained in:
parent
865cec928a
commit
96ecf3ff23
@ -2322,7 +2322,7 @@ void clean_up(bool print_message)
|
|||||||
my_free(const_cast<char*>(relay_log_index));
|
my_free(const_cast<char*>(relay_log_index));
|
||||||
#endif
|
#endif
|
||||||
free_list(opt_plugin_load_list_ptr);
|
free_list(opt_plugin_load_list_ptr);
|
||||||
cleanup_proxy_protocol_networks();
|
destroy_proxy_protocol_networks();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The following lines may never be executed as the main thread may have
|
The following lines may never be executed as the main thread may have
|
||||||
@ -2718,7 +2718,7 @@ static void network_init(void)
|
|||||||
if (MYSQL_CALLBACK_ELSE(thread_scheduler, init, (), 0))
|
if (MYSQL_CALLBACK_ELSE(thread_scheduler, init, (), 0))
|
||||||
unireg_abort(1); /* purecov: inspected */
|
unireg_abort(1); /* purecov: inspected */
|
||||||
|
|
||||||
if (set_proxy_protocol_networks(my_proxy_protocol_networks))
|
if (init_proxy_protocol_networks(my_proxy_protocol_networks))
|
||||||
unireg_abort(1);
|
unireg_abort(1);
|
||||||
|
|
||||||
set_ports();
|
set_ports();
|
||||||
|
@ -23,11 +23,14 @@
|
|||||||
#include <violite.h>
|
#include <violite.h>
|
||||||
#include <proxy_protocol.h>
|
#include <proxy_protocol.h>
|
||||||
#include <log.h>
|
#include <log.h>
|
||||||
|
#include <my_pthread.h>
|
||||||
|
|
||||||
#define PROXY_PROTOCOL_V1_SIGNATURE "PROXY"
|
#define PROXY_PROTOCOL_V1_SIGNATURE "PROXY"
|
||||||
#define PROXY_PROTOCOL_V2_SIGNATURE "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A"
|
#define PROXY_PROTOCOL_V2_SIGNATURE "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A"
|
||||||
#define MAX_PROXY_HEADER_LEN 256
|
#define MAX_PROXY_HEADER_LEN 256
|
||||||
|
|
||||||
|
static mysql_rwlock_t lock;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Parse proxy protocol version 1 header (text)
|
Parse proxy protocol version 1 header (text)
|
||||||
*/
|
*/
|
||||||
@ -341,31 +344,41 @@ static int parse_subnet(char *addr_str, struct subnet *subnet)
|
|||||||
|
|
||||||
@param[in] subnets_str : networks in CIDR format,
|
@param[in] subnets_str : networks in CIDR format,
|
||||||
separated by comma and/or space
|
separated by comma and/or space
|
||||||
|
@param[out] out_subnets : parsed subnets;
|
||||||
|
@param[out] out_count : number of parsed subnets
|
||||||
|
|
||||||
@return 0 if success, otherwise -1
|
@return 0 if success, otherwise -1
|
||||||
*/
|
*/
|
||||||
int set_proxy_protocol_networks(const char *subnets_str)
|
static int parse_networks(const char *subnets_str, subnet **out_subnets, size_t *out_count)
|
||||||
{
|
{
|
||||||
if (!subnets_str || !*subnets_str)
|
int ret= -1;
|
||||||
return 0;
|
subnet *subnets= 0;
|
||||||
|
size_t count= 0;
|
||||||
|
const char *p= subnets_str;
|
||||||
|
size_t max_subnets;
|
||||||
|
|
||||||
size_t max_subnets= MY_MAX(3,strlen(subnets_str)/2);
|
if (!subnets_str || !*subnets_str)
|
||||||
proxy_protocol_subnets= (subnet *)my_malloc(max_subnets * sizeof(subnet),MY_ZEROFILL);
|
{
|
||||||
|
ret= 0;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
max_subnets= MY_MAX(3,strlen(subnets_str)/2);
|
||||||
|
subnets= (subnet *)my_malloc(max_subnets * sizeof(subnet),MY_ZEROFILL);
|
||||||
|
|
||||||
/* Check for special case '*'. */
|
/* Check for special case '*'. */
|
||||||
if (strcmp(subnets_str, "*") == 0)
|
if (strcmp(subnets_str, "*") == 0)
|
||||||
{
|
{
|
||||||
|
subnets[0].family= AF_INET;
|
||||||
proxy_protocol_subnets[0].family= AF_INET;
|
subnets[1].family= AF_INET6;
|
||||||
proxy_protocol_subnets[1].family= AF_INET6;
|
subnets[2].family= AF_UNIX;
|
||||||
proxy_protocol_subnets[2].family= AF_UNIX;
|
count= 3;
|
||||||
proxy_protocol_subnet_count= 3;
|
ret= 0;
|
||||||
return 0;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
char token[256];
|
char token[256];
|
||||||
const char *p= subnets_str;
|
for(count= 0;; count++)
|
||||||
for(proxy_protocol_subnet_count= 0;; proxy_protocol_subnet_count++)
|
|
||||||
{
|
{
|
||||||
while(*p && (*p ==',' || *p == ' '))
|
while(*p && (*p ==',' || *p == ' '))
|
||||||
p++;
|
p++;
|
||||||
@ -377,18 +390,75 @@ int set_proxy_protocol_networks(const char *subnets_str)
|
|||||||
token[cnt++]= *p++;
|
token[cnt++]= *p++;
|
||||||
|
|
||||||
token[cnt++]=0;
|
token[cnt++]=0;
|
||||||
if (cnt == sizeof(token))
|
if (cnt == sizeof(token))
|
||||||
return -1;
|
goto end;
|
||||||
|
|
||||||
if (parse_subnet(token, &proxy_protocol_subnets[proxy_protocol_subnet_count]))
|
if (parse_subnet(token, &subnets[count]))
|
||||||
{
|
{
|
||||||
sql_print_error("Error parsing proxy_protocol_networks parameter, near '%s'",token);
|
my_printf_error(ER_PARSE_ERROR,"Error parsing proxy_protocol_networks parameter, near '%s'",MYF(0),token);
|
||||||
return -1;
|
goto end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
my_free(subnets);
|
||||||
|
*out_subnets= NULL;
|
||||||
|
*out_count= 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
*out_subnets = subnets;
|
||||||
|
*out_count= count;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Check validity of proxy_protocol_networks parameter
|
||||||
|
@param[in] in - input string
|
||||||
|
@return : true, if input is list of CIDR-style networks
|
||||||
|
separated by command or space
|
||||||
|
*/
|
||||||
|
bool proxy_protocol_networks_valid(const char *in)
|
||||||
|
{
|
||||||
|
subnet *new_subnets;
|
||||||
|
size_t new_count;
|
||||||
|
int ret= parse_networks(in, &new_subnets, &new_count);
|
||||||
|
my_free(new_subnets);
|
||||||
|
return !ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Set 'proxy_protocol_networks' parameter.
|
||||||
|
|
||||||
|
@param[in] spec : networks in CIDR format,
|
||||||
|
separated by comma and/or space
|
||||||
|
|
||||||
|
@return 0 if success, otherwise -1
|
||||||
|
*/
|
||||||
|
int set_proxy_protocol_networks(const char *spec)
|
||||||
|
{
|
||||||
|
subnet *new_subnets;
|
||||||
|
subnet *old_subnet = 0;
|
||||||
|
size_t new_count;
|
||||||
|
|
||||||
|
int ret= parse_networks(spec, &new_subnets, &new_count);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
mysql_rwlock_wrlock(&lock);
|
||||||
|
old_subnet = proxy_protocol_subnets;
|
||||||
|
proxy_protocol_subnets = new_subnets;
|
||||||
|
proxy_protocol_subnet_count = new_count;
|
||||||
|
mysql_rwlock_unlock(&lock);
|
||||||
|
my_free(old_subnet);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Compare memory areas, in memcmp().similar fashion.
|
Compare memory areas, in memcmp().similar fashion.
|
||||||
The difference to memcmp() is that size parameter is the
|
The difference to memcmp() is that size parameter is the
|
||||||
@ -475,20 +545,39 @@ bool is_proxy_protocol_allowed(const sockaddr *addr)
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
DBUG_ASSERT(0);
|
DBUG_ASSERT(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ret= false;
|
||||||
|
mysql_rwlock_rdlock(&lock);
|
||||||
for (size_t i= 0; i < proxy_protocol_subnet_count; i++)
|
for (size_t i= 0; i < proxy_protocol_subnet_count; i++)
|
||||||
|
{
|
||||||
if (addr_matches_subnet(normalized_addr, &proxy_protocol_subnets[i]))
|
if (addr_matches_subnet(normalized_addr, &proxy_protocol_subnets[i]))
|
||||||
return true;
|
{
|
||||||
|
ret= true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mysql_rwlock_unlock(&lock);
|
||||||
|
|
||||||
return false;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void cleanup_proxy_protocol_networks()
|
int init_proxy_protocol_networks(const char *spec)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_PSI_INTERFACE
|
||||||
|
static PSI_rwlock_key psi_rwlock_key;
|
||||||
|
static PSI_rwlock_info psi_rwlock_info={ &psi_rwlock_key, "rwlock", 0 };
|
||||||
|
mysql_rwlock_register("proxy_protocol", &psi_rwlock_info, 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mysql_rwlock_init(psi_rwlock_key, &lock);
|
||||||
|
return set_proxy_protocol_networks(spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void destroy_proxy_protocol_networks()
|
||||||
{
|
{
|
||||||
my_free(proxy_protocol_subnets);
|
my_free(proxy_protocol_subnets);
|
||||||
proxy_protocol_subnets= 0;
|
mysql_rwlock_destroy(&lock);
|
||||||
proxy_protocol_subnet_count= 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,5 +11,9 @@ extern bool has_proxy_protocol_header(NET *net);
|
|||||||
extern int parse_proxy_protocol_header(NET *net, proxy_peer_info *peer_info);
|
extern int parse_proxy_protocol_header(NET *net, proxy_peer_info *peer_info);
|
||||||
extern bool is_proxy_protocol_allowed(const sockaddr *remote_addr);
|
extern bool is_proxy_protocol_allowed(const sockaddr *remote_addr);
|
||||||
|
|
||||||
|
extern int init_proxy_protocol_networks(const char *spec);
|
||||||
|
extern void destroy_proxy_protocol_networks();
|
||||||
|
|
||||||
extern int set_proxy_protocol_networks(const char *spec);
|
extern int set_proxy_protocol_networks(const char *spec);
|
||||||
extern void cleanup_proxy_protocol_networks();
|
extern bool proxy_protocol_networks_valid(const char *spec);
|
||||||
|
|
||||||
|
@ -4416,7 +4416,22 @@ static Sys_var_charptr Sys_license(
|
|||||||
READ_ONLY GLOBAL_VAR(license), NO_CMD_LINE, IN_SYSTEM_CHARSET,
|
READ_ONLY GLOBAL_VAR(license), NO_CMD_LINE, IN_SYSTEM_CHARSET,
|
||||||
DEFAULT(STRINGIFY_ARG(LICENSE)));
|
DEFAULT(STRINGIFY_ARG(LICENSE)));
|
||||||
|
|
||||||
|
#include <proxy_protocol.h>
|
||||||
char *my_proxy_protocol_networks;
|
char *my_proxy_protocol_networks;
|
||||||
|
static bool check_proxy_protocol_networks(sys_var *, THD *, set_var *var)
|
||||||
|
{
|
||||||
|
if (!var->value)
|
||||||
|
return false;
|
||||||
|
return !proxy_protocol_networks_valid(var->save_result.string_value.str);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool fix_proxy_protocol_networks(sys_var *, THD *, enum_var_type)
|
||||||
|
{
|
||||||
|
return (bool)set_proxy_protocol_networks(my_proxy_protocol_networks);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static Sys_var_charptr Sys_proxy_protocol_networks(
|
static Sys_var_charptr Sys_proxy_protocol_networks(
|
||||||
"proxy_protocol_networks", "Enable proxy protocol for these source "
|
"proxy_protocol_networks", "Enable proxy protocol for these source "
|
||||||
"networks. The syntax is a comma separated list of IPv4 and IPv6 "
|
"networks. The syntax is a comma separated list of IPv4 and IPv6 "
|
||||||
@ -4424,8 +4439,10 @@ static Sys_var_charptr Sys_proxy_protocol_networks(
|
|||||||
"a single host. \"*\" represents all networks and must the only "
|
"a single host. \"*\" represents all networks and must the only "
|
||||||
"directive on the line. String \"localhost\" represents non-TCP "
|
"directive on the line. String \"localhost\" represents non-TCP "
|
||||||
"local connections (Unix domain socket, Windows named pipe or shared memory).",
|
"local connections (Unix domain socket, Windows named pipe or shared memory).",
|
||||||
READ_ONLY GLOBAL_VAR(my_proxy_protocol_networks),
|
GLOBAL_VAR(my_proxy_protocol_networks), CMD_LINE(REQUIRED_ARG),
|
||||||
CMD_LINE(REQUIRED_ARG), IN_FS_CHARSET, DEFAULT(""));
|
IN_FS_CHARSET, DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG,
|
||||||
|
ON_CHECK(check_proxy_protocol_networks), ON_UPDATE(fix_proxy_protocol_networks));
|
||||||
|
|
||||||
|
|
||||||
static bool check_log_path(sys_var *self, THD *thd, set_var *var)
|
static bool check_log_path(sys_var *self, THD *thd, set_var *var)
|
||||||
{
|
{
|
||||||
|
@ -20220,6 +20220,18 @@ static void test_proxy_header_ignore()
|
|||||||
mysql_optionsv(m, MARIADB_OPT_PROXY_HEADER, &v2_header,16);
|
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);
|
DIE_UNLESS(mysql_real_connect(m, opt_host, "root", "", NULL, opt_port, opt_unix_socket, 0) == m);
|
||||||
mysql_close(m);
|
mysql_close(m);
|
||||||
|
|
||||||
|
/* test for connection denied with empty proxy_protocol_networks */
|
||||||
|
int rc = mysql_query(mysql, "select @@proxy_protocol_networks into @sv_proxy_protocol_networks");
|
||||||
|
myquery(rc);
|
||||||
|
mysql_query(mysql, "set global proxy_protocol_networks=default");
|
||||||
|
myquery(rc);
|
||||||
|
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) == 0);
|
||||||
|
mysql_close(m);
|
||||||
|
mysql_query(mysql, "set global proxy_protocol_networks= @sv_proxy_protocol_networks");
|
||||||
|
myquery(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user