Skip to content

Commit ba16202

Browse files
MDEV-24377: Accept comma separated addresses as --bind-address value (#2009)
* MDEV-24377: Accept comma separated addresses as --bind-address value When bind address form the basis of wsrep based variables, the first address in the comma separated list is used. The test uses the IP address 192.168.0.1 as we need to include multiple address. This will include failures without the following commit. The tests for bind_multiple_address_resolution could return addresses that we cannot bind too. Windows and FreeBSD, and probably other OSs will terminate the service if addresses are unavailable. We use the WSAEADDRNOTAVAIL / POSIX EADDRNOTAVAIL codes to continue to bind to other interfaces. If at the end of the bind list, if no binds are successful, the we terminate but still leaving the error messages in the log. Co-authored-by: Daniel Black <daniel@mariadb.org>
1 parent fd0dcad commit ba16202

9 files changed

+121
-15
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--bind-address=localhost,192.168.0.1
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
call mtr.add_suppression("Can't start server: Bind on TCP/IP port.");
2+
CREATE TABLE t (a TEXT);
3+
connect con1,localhost,root,,test;
4+
SELECT * FROM t;
5+
a
6+
connect con2,127.0.0.1,root,,test;
7+
SELECT * FROM t;
8+
a
9+
connection default;
10+
DROP TABLE t;
11+
disconnect con1;
12+
disconnect con2;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
--source include/check_ipv6.inc
2+
--source include/not_embedded.inc
3+
4+
call mtr.add_suppression("Can't start server: Bind on TCP/IP port.");
5+
# The server is started with --bind-address=localhost,192.168.0.1, and should
6+
# listen on all addresses 'localhost' resolves to and 192.168.0.1. With at least
7+
# 127.0.0.1 and ::1 amongst them.
8+
9+
CREATE TABLE t (a TEXT);
10+
--connect(con1,localhost,root,,test)
11+
SELECT * FROM t;
12+
--connect(con2,127.0.0.1,root,,test)
13+
SELECT * FROM t;
14+
# Temporary disable.
15+
# Some cloud-init services don't resolve localhost->::1
16+
# bb - kvm-asan, kvm-deb-focal-amd64, kvm-deb-groovy-amd64
17+
#--connect(con3,::1,root,,test)
18+
#SELECT * FROM t;
19+
--connection default
20+
DROP TABLE t;
21+
--disconnect con1
22+
--disconnect con2
23+
#--disconnect con3

mysql-test/main/mysqld--help.result

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ The following specify which files/extra groups are read (specified before remain
4242
by saving all temporary sets to disk, avoiding 'table
4343
full' errors. No longer needed, as the server now handles
4444
this automatically.
45-
--bind-address=name IP address to bind to.
45+
--bind-address=name IP address to bind to. Several addresses may be
46+
specified, separated by a comma (,).
4647
--binlog-alter-two-phase
4748
When set, split ALTER at binary logging into 2
4849
statements: START ALTER and COMMIT/ROLLBACK ALTER

mysql-test/suite/sys_vars/r/sysvars_server_embedded.result

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ COMMAND_LINE_ARGUMENT OPTIONAL
325325
VARIABLE_NAME BIND_ADDRESS
326326
VARIABLE_SCOPE GLOBAL
327327
VARIABLE_TYPE VARCHAR
328-
VARIABLE_COMMENT IP address to bind to.
328+
VARIABLE_COMMENT IP address to bind to. Several addresses may be specified, separated by a comma (,).
329329
NUMERIC_MIN_VALUE NULL
330330
NUMERIC_MAX_VALUE NULL
331331
NUMERIC_BLOCK_SIZE NULL

mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ COMMAND_LINE_ARGUMENT OPTIONAL
325325
VARIABLE_NAME BIND_ADDRESS
326326
VARIABLE_SCOPE GLOBAL
327327
VARIABLE_TYPE VARCHAR
328-
VARIABLE_COMMENT IP address to bind to.
328+
VARIABLE_COMMENT IP address to bind to. Several addresses may be specified, separated by a comma (,).
329329
NUMERIC_MIN_VALUE NULL
330330
NUMERIC_MAX_VALUE NULL
331331
NUMERIC_BLOCK_SIZE NULL

sql/mysqld.cc

Lines changed: 72 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,6 @@
135135

136136
#define mysqld_charset &my_charset_latin1
137137

138-
139138
extern "C" {// Because of SCO 3.2V4.2
140139
#include <sys/stat.h>
141140
#ifndef __GNU_LIBRARY__
@@ -2291,7 +2290,7 @@ static void activate_tcp_port(uint port,
22912290
Dynamic_array<MYSQL_SOCKET> *sockets,
22922291
bool is_extra_port= false)
22932292
{
2294-
struct addrinfo *ai, *a;
2293+
struct addrinfo *ai, *a = NULL, *head = NULL;
22952294
struct addrinfo hints;
22962295
int error;
22972296
intarg;
@@ -2312,16 +2311,52 @@ static void activate_tcp_port(uint port,
23122311
real_bind_addr_str= my_bind_addr_str;
23132312

23142313
my_snprintf(port_buf, NI_MAXSERV, "%d", port);
2315-
error= getaddrinfo(real_bind_addr_str, port_buf, &hints, &ai);
2316-
if (unlikely(error != 0))
2314+
2315+
if (real_bind_addr_str && *real_bind_addr_str)
23172316
{
2318-
DBUG_PRINT("error",("Got error: %d from getaddrinfo()", error));
23192317

2320-
sql_print_error("%s: %s", ER_DEFAULT(ER_IPSOCK_ERROR), gai_strerror(error));
2321-
unireg_abort(1);/* purecov: tested */
2318+
char *end;
2319+
char address[FN_REFLEN];
2320+
2321+
do
2322+
{
2323+
end= strcend(real_bind_addr_str, ',');
2324+
strmake(address, real_bind_addr_str, (uint) (end - real_bind_addr_str));
2325+
2326+
error= getaddrinfo(address, port_buf, &hints, &ai);
2327+
if (unlikely(error != 0))
2328+
{
2329+
DBUG_PRINT("error", ("Got error: %d from getaddrinfo()", error));
2330+
2331+
sql_print_error("%s: %s", ER_DEFAULT(ER_IPSOCK_ERROR),
2332+
gai_strerror(error));
2333+
unireg_abort(1); /* purecov: tested */
2334+
}
2335+
2336+
if (!head)
2337+
{
2338+
head= ai;
2339+
}
2340+
if (a)
2341+
{
2342+
a->ai_next= ai;
2343+
}
2344+
a= ai;
2345+
while (a->ai_next)
2346+
{
2347+
a= a->ai_next;
2348+
}
2349+
2350+
real_bind_addr_str= end + 1;
2351+
} while (*end);
2352+
}
2353+
else
2354+
{
2355+
error= getaddrinfo(real_bind_addr_str, port_buf, &hints, &ai);
2356+
head= ai;
23222357
}
23232358

2324-
for (a= ai; a != NULL; a= a->ai_next)
2359+
for (a= head; a != NULL; a= a->ai_next)
23252360
{
23262361
ip_sock= mysql_socket_socket(key_socket_tcpip, a->ai_family,
23272362
a->ai_socktype, a->ai_protocol);
@@ -2410,9 +2445,31 @@ static void activate_tcp_port(uint port,
24102445
if (ret < 0)
24112446
{
24122447
char buff[100];
2448+
int s_errno= socket_errno;
24132449
sprintf(buff, "Can't start server: Bind on TCP/IP port. Got error: %d",
2414-
(int) socket_errno);
2450+
(int) s_errno);
24152451
sql_perror(buff);
2452+
/*
2453+
Linux will quite happily bind to addresses not present. The
2454+
mtr test main.bind_multiple_addresses_resolution relies on this.
2455+
For Windows, this is fatal and generates the error:
2456+
WSAEADDRNOTAVAIL: The requested address is not valid in its context
2457+
In this case, where multiple addresses where specified, maybe
2458+
we can live with an error in the log and hope the other addresses
2459+
are successful. We catch if no successful bindings occur at the
2460+
end of this function.
2461+
2462+
FreeBSD returns EADDRNOTAVAIL, and EADDRNOTAVAIL is even in Linux
2463+
manual pages. So may was well apply uniform behaviour.
2464+
*/
2465+
#ifdef _WIN32
2466+
if (s_errno == WSAEADDRNOTAVAIL)
2467+
continue;
2468+
#endif
2469+
#ifdef EADDRNOTAVAIL
2470+
if (s_errno == EADDRNOTAVAIL)
2471+
continue;
2472+
#endif
24162473
sql_print_error("Do you already have another server running on "
24172474
"port: %u ?", port);
24182475
unireg_abort(1);
@@ -2433,7 +2490,12 @@ static void activate_tcp_port(uint port,
24332490
}
24342491
}
24352492

2436-
freeaddrinfo(ai);
2493+
freeaddrinfo(head);
2494+
if (head && sockets->size() == 0)
2495+
{
2496+
sql_print_error("No TCP address could be bound to");
2497+
unireg_abort(1);
2498+
}
24372499
DBUG_VOID_RETURN;
24382500
}
24392501

sql/sys_vars.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,8 @@ static Sys_var_charptr_fscs Sys_basedir(
511511
DEFAULT(0));
512512

513513
static Sys_var_charptr_fscs Sys_my_bind_addr(
514-
"bind_address", "IP address to bind to.",
514+
"bind_address", "IP address to bind to. Several addresses may be "
515+
"specified, separated by a comma (,).",
515516
READ_ONLY GLOBAL_VAR(my_bind_addr_str), CMD_LINE(REQUIRED_ARG),
516517
DEFAULT(0));
517518

sql/wsrep_utils.cc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,13 @@ unsigned int wsrep_check_ip (const char* const addr, bool *is_ipv6)
457457

458458
*is_ipv6= false;
459459

460-
int gai_ret= getaddrinfo(addr, NULL, &hints, &res);
460+
char *end;
461+
char address[INET6_ADDRSTRLEN];
462+
463+
end= strcend(addr, ',');
464+
strmake(address, addr, (uint) (end - addr));
465+
466+
int gai_ret= getaddrinfo(address, NULL, &hints, &res);
461467
if (0 == gai_ret)
462468
{
463469
if (AF_INET == res->ai_family) /* IPv4 */

0 commit comments

Comments
 (0)