Skip to content

Commit 96ecf3f

Browse files
committed
MDEV-15501 : Make proxy_protocol_networks variable read-write.
1 parent 865cec9 commit 96ecf3f

File tree

5 files changed

+151
-29
lines changed

5 files changed

+151
-29
lines changed

sql/mysqld.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2322,7 +2322,7 @@ void clean_up(bool print_message)
23222322
my_free(const_cast<char*>(relay_log_index));
23232323
#endif
23242324
free_list(opt_plugin_load_list_ptr);
2325-
cleanup_proxy_protocol_networks();
2325+
destroy_proxy_protocol_networks();
23262326

23272327
/*
23282328
The following lines may never be executed as the main thread may have
@@ -2718,7 +2718,7 @@ static void network_init(void)
27182718
if (MYSQL_CALLBACK_ELSE(thread_scheduler, init, (), 0))
27192719
unireg_abort(1); /* purecov: inspected */
27202720

2721-
if (set_proxy_protocol_networks(my_proxy_protocol_networks))
2721+
if (init_proxy_protocol_networks(my_proxy_protocol_networks))
27222722
unireg_abort(1);
27232723

27242724
set_ports();

sql/proxy_protocol.cc

Lines changed: 113 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,14 @@
2323
#include <violite.h>
2424
#include <proxy_protocol.h>
2525
#include <log.h>
26+
#include <my_pthread.h>
2627

2728
#define PROXY_PROTOCOL_V1_SIGNATURE "PROXY"
2829
#define PROXY_PROTOCOL_V2_SIGNATURE "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A"
2930
#define MAX_PROXY_HEADER_LEN 256
3031

32+
static mysql_rwlock_t lock;
33+
3134
/*
3235
Parse proxy protocol version 1 header (text)
3336
*/
@@ -341,31 +344,41 @@ static int parse_subnet(char *addr_str, struct subnet *subnet)
341344
342345
@param[in] subnets_str : networks in CIDR format,
343346
separated by comma and/or space
347+
@param[out] out_subnets : parsed subnets;
348+
@param[out] out_count : number of parsed subnets
344349
345350
@return 0 if success, otherwise -1
346351
*/
347-
int set_proxy_protocol_networks(const char *subnets_str)
352+
static int parse_networks(const char *subnets_str, subnet **out_subnets, size_t *out_count)
348353
{
354+
int ret= -1;
355+
subnet *subnets= 0;
356+
size_t count= 0;
357+
const char *p= subnets_str;
358+
size_t max_subnets;
359+
349360
if (!subnets_str || !*subnets_str)
350-
return 0;
361+
{
362+
ret= 0;
363+
goto end;
364+
}
351365

352-
size_t max_subnets= MY_MAX(3,strlen(subnets_str)/2);
353-
proxy_protocol_subnets= (subnet *)my_malloc(max_subnets * sizeof(subnet),MY_ZEROFILL);
366+
max_subnets= MY_MAX(3,strlen(subnets_str)/2);
367+
subnets= (subnet *)my_malloc(max_subnets * sizeof(subnet),MY_ZEROFILL);
354368

355369
/* Check for special case '*'. */
356370
if (strcmp(subnets_str, "*") == 0)
357371
{
358-
359-
proxy_protocol_subnets[0].family= AF_INET;
360-
proxy_protocol_subnets[1].family= AF_INET6;
361-
proxy_protocol_subnets[2].family= AF_UNIX;
362-
proxy_protocol_subnet_count= 3;
363-
return 0;
372+
subnets[0].family= AF_INET;
373+
subnets[1].family= AF_INET6;
374+
subnets[2].family= AF_UNIX;
375+
count= 3;
376+
ret= 0;
377+
goto end;
364378
}
365379

366380
char token[256];
367-
const char *p= subnets_str;
368-
for(proxy_protocol_subnet_count= 0;; proxy_protocol_subnet_count++)
381+
for(count= 0;; count++)
369382
{
370383
while(*p && (*p ==',' || *p == ' '))
371384
p++;
@@ -377,18 +390,75 @@ int set_proxy_protocol_networks(const char *subnets_str)
377390
token[cnt++]= *p++;
378391

379392
token[cnt++]=0;
380-
if (cnt == sizeof(token))
381-
return -1;
393+
if (cnt == sizeof(token))
394+
goto end;
382395

383-
if (parse_subnet(token, &proxy_protocol_subnets[proxy_protocol_subnet_count]))
396+
if (parse_subnet(token, &subnets[count]))
384397
{
385-
sql_print_error("Error parsing proxy_protocol_networks parameter, near '%s'",token);
386-
return -1;
398+
my_printf_error(ER_PARSE_ERROR,"Error parsing proxy_protocol_networks parameter, near '%s'",MYF(0),token);
399+
goto end;
387400
}
388401
}
402+
403+
ret = 0;
404+
405+
end:
406+
if (ret)
407+
{
408+
my_free(subnets);
409+
*out_subnets= NULL;
410+
*out_count= 0;
411+
return ret;
412+
}
413+
*out_subnets = subnets;
414+
*out_count= count;
389415
return 0;
390416
}
391417

418+
/**
419+
Check validity of proxy_protocol_networks parameter
420+
@param[in] in - input string
421+
@return : true, if input is list of CIDR-style networks
422+
separated by command or space
423+
*/
424+
bool proxy_protocol_networks_valid(const char *in)
425+
{
426+
subnet *new_subnets;
427+
size_t new_count;
428+
int ret= parse_networks(in, &new_subnets, &new_count);
429+
my_free(new_subnets);
430+
return !ret;
431+
}
432+
433+
434+
/**
435+
Set 'proxy_protocol_networks' parameter.
436+
437+
@param[in] spec : networks in CIDR format,
438+
separated by comma and/or space
439+
440+
@return 0 if success, otherwise -1
441+
*/
442+
int set_proxy_protocol_networks(const char *spec)
443+
{
444+
subnet *new_subnets;
445+
subnet *old_subnet = 0;
446+
size_t new_count;
447+
448+
int ret= parse_networks(spec, &new_subnets, &new_count);
449+
if (ret)
450+
return ret;
451+
452+
mysql_rwlock_wrlock(&lock);
453+
old_subnet = proxy_protocol_subnets;
454+
proxy_protocol_subnets = new_subnets;
455+
proxy_protocol_subnet_count = new_count;
456+
mysql_rwlock_unlock(&lock);
457+
my_free(old_subnet);
458+
return ret;
459+
}
460+
461+
392462
/**
393463
Compare memory areas, in memcmp().similar fashion.
394464
The difference to memcmp() is that size parameter is the
@@ -475,20 +545,39 @@ bool is_proxy_protocol_allowed(const sockaddr *addr)
475545
break;
476546
default:
477547
DBUG_ASSERT(0);
478-
}
548+
}
479549

550+
bool ret= false;
551+
mysql_rwlock_rdlock(&lock);
480552
for (size_t i= 0; i < proxy_protocol_subnet_count; i++)
553+
{
481554
if (addr_matches_subnet(normalized_addr, &proxy_protocol_subnets[i]))
482-
return true;
555+
{
556+
ret= true;
557+
break;
558+
}
559+
}
560+
mysql_rwlock_unlock(&lock);
483561

484-
return false;
562+
return ret;
485563
}
486564

487565

488-
void cleanup_proxy_protocol_networks()
566+
int init_proxy_protocol_networks(const char *spec)
489567
{
490-
my_free(proxy_protocol_subnets);
491-
proxy_protocol_subnets= 0;
492-
proxy_protocol_subnet_count= 0;
568+
#ifdef HAVE_PSI_INTERFACE
569+
static PSI_rwlock_key psi_rwlock_key;
570+
static PSI_rwlock_info psi_rwlock_info={ &psi_rwlock_key, "rwlock", 0 };
571+
mysql_rwlock_register("proxy_protocol", &psi_rwlock_info, 1);
572+
#endif
573+
574+
mysql_rwlock_init(psi_rwlock_key, &lock);
575+
return set_proxy_protocol_networks(spec);
493576
}
494577

578+
579+
void destroy_proxy_protocol_networks()
580+
{
581+
my_free(proxy_protocol_subnets);
582+
mysql_rwlock_destroy(&lock);
583+
}

sql/proxy_protocol.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,9 @@ extern bool has_proxy_protocol_header(NET *net);
1111
extern int parse_proxy_protocol_header(NET *net, proxy_peer_info *peer_info);
1212
extern bool is_proxy_protocol_allowed(const sockaddr *remote_addr);
1313

14+
extern int init_proxy_protocol_networks(const char *spec);
15+
extern void destroy_proxy_protocol_networks();
16+
1417
extern int set_proxy_protocol_networks(const char *spec);
15-
extern void cleanup_proxy_protocol_networks();
18+
extern bool proxy_protocol_networks_valid(const char *spec);
19+

sql/sys_vars.cc

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4416,16 +4416,33 @@ static Sys_var_charptr Sys_license(
44164416
READ_ONLY GLOBAL_VAR(license), NO_CMD_LINE, IN_SYSTEM_CHARSET,
44174417
DEFAULT(STRINGIFY_ARG(LICENSE)));
44184418

4419+
#include <proxy_protocol.h>
44194420
char *my_proxy_protocol_networks;
4421+
static bool check_proxy_protocol_networks(sys_var *, THD *, set_var *var)
4422+
{
4423+
if (!var->value)
4424+
return false;
4425+
return !proxy_protocol_networks_valid(var->save_result.string_value.str);
4426+
}
4427+
4428+
4429+
static bool fix_proxy_protocol_networks(sys_var *, THD *, enum_var_type)
4430+
{
4431+
return (bool)set_proxy_protocol_networks(my_proxy_protocol_networks);
4432+
}
4433+
4434+
44204435
static Sys_var_charptr Sys_proxy_protocol_networks(
44214436
"proxy_protocol_networks", "Enable proxy protocol for these source "
44224437
"networks. The syntax is a comma separated list of IPv4 and IPv6 "
44234438
"networks. If the network doesn't contain mask, it is considered to be "
44244439
"a single host. \"*\" represents all networks and must the only "
44254440
"directive on the line. String \"localhost\" represents non-TCP "
44264441
"local connections (Unix domain socket, Windows named pipe or shared memory).",
4427-
READ_ONLY GLOBAL_VAR(my_proxy_protocol_networks),
4428-
CMD_LINE(REQUIRED_ARG), IN_FS_CHARSET, DEFAULT(""));
4442+
GLOBAL_VAR(my_proxy_protocol_networks), CMD_LINE(REQUIRED_ARG),
4443+
IN_FS_CHARSET, DEFAULT(""), NO_MUTEX_GUARD, NOT_IN_BINLOG,
4444+
ON_CHECK(check_proxy_protocol_networks), ON_UPDATE(fix_proxy_protocol_networks));
4445+
44294446

44304447
static bool check_log_path(sys_var *self, THD *thd, set_var *var)
44314448
{

tests/mysql_client_test.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20220,6 +20220,18 @@ static void test_proxy_header_ignore()
2022020220
mysql_optionsv(m, MARIADB_OPT_PROXY_HEADER, &v2_header,16);
2022120221
DIE_UNLESS(mysql_real_connect(m, opt_host, "root", "", NULL, opt_port, opt_unix_socket, 0) == m);
2022220222
mysql_close(m);
20223+
20224+
/* test for connection denied with empty proxy_protocol_networks */
20225+
int rc = mysql_query(mysql, "select @@proxy_protocol_networks into @sv_proxy_protocol_networks");
20226+
myquery(rc);
20227+
mysql_query(mysql, "set global proxy_protocol_networks=default");
20228+
myquery(rc);
20229+
m = mysql_client_init(NULL);
20230+
mysql_optionsv(m, MARIADB_OPT_PROXY_HEADER, &v2_header,16);
20231+
DIE_UNLESS(mysql_real_connect(m, opt_host, "root", "", NULL, opt_port, opt_unix_socket, 0) == 0);
20232+
mysql_close(m);
20233+
mysql_query(mysql, "set global proxy_protocol_networks= @sv_proxy_protocol_networks");
20234+
myquery(rc);
2022320235
}
2022420236

2022520237

0 commit comments

Comments
 (0)