diff options
author | Praveenkumar Hulakund <praveenkumar.hulakund@oracle.com> | 2012-04-04 11:13:42 +0530 |
---|---|---|
committer | Praveenkumar Hulakund <praveenkumar.hulakund@oracle.com> | 2012-04-04 11:13:42 +0530 |
commit | aab9623a8dce2c19c1cb1af90ff5967e2977a240 (patch) | |
tree | a0576493506eec72eab509adf349c9227714e583 | |
parent | 42a84acbf0b5749ce0bf71706fdb239e2b2baa7c (diff) | |
download | mariadb-git-aab9623a8dce2c19c1cb1af90ff5967e2977a240.tar.gz |
Bug#12762885: 61713: MYSQL WILL NOT BIND TO "LOCALHOST" IF LOCALHOST IS BOTH
IPV4/IPV6 ENABLED
Analysis:
----------------------
The problem was that if a hostname resolves to more than one IP-address,
the server (5.5) does not start due to an error. In 5.1 the server used to
take some IP-address and start.
It's a regression and should be fixed.
5.5 supports IPv6, while 5.1 does not. However, that should not
prevent the server from start -- if a hostname has both IPv4 and IPv6 addresses,
the server should choose some IPv4-address and start.
It's been decided to prefer IPv4-address to be backward compatible with 5.1.
Another problem was that the 5.6 server did not report proper error message
when the specified hostname could not be resolved. So, the code has been
changed to report proper error message.
Testing
================================
5.5
=============================
invalid hostname (localhos):
=> Following error message reported.
120308 15:52:09 [ERROR] Can't start server: cannot resolve hostname!
120308 15:52:09 [ERROR] Aborting
invalid ip_address:
=> Following error message reported.
120308 15:56:06 [Note] Server hostname (bind-address): '123.123.123.123'; port: 3306
120308 15:56:06 [Note] - '123.123.123.123' resolves to '123.123.123.123';
120308 15:56:06 [Note] Server socket created on IP: '123.123.123.123'.
120308 15:56:06 [ERROR] Can't start server: Bind on TCP/IP port: Cannot assign requested address
Only ipv4 host configured:
=> Following message logged
120308 16:02:50 [Note] Server hostname (bind-address): 'localhost'; port: 3306
120308 16:02:50 [Note] - 'localhost' resolves to '127.0.0.1';
120308 16:02:50 [Note] Server socket created on IP: '127.0.0.1'
Only ipv6 host configured:
=> Following message logged
120308 16:04:03 [Note] Server hostname (bind-address): 'localhost'; port: 3306
120308 16:04:03 [Note] - 'localhost' resolves to '::1';
120308 16:04:03 [Note] Server socket created on IP: '::1'.
ipv4 and ipv6 host configured:
=> Following message logged
120308 16:05:02 [Note] Server hostname (bind-address): 'localhost'; port: 3306
120308 16:05:02 [Note] - 'localhost' resolves to '::1';
120308 16:05:02 [Note] - 'localhost' resolves to '127.0.0.1';
120308 16:05:02 [Note] Server socket created on IP: '127.0.0.1'.
=> Non localhost address
120308 16:08:20 [Note] Server hostname (bind-address): 'mysql_addr'; port: 3306
120308 16:08:20 [Note] - 'mysql_addr' resolves to '10.178.58.216';
120308 16:08:20 [Note] - 'mysql_addr' resolves to 'fe80::120b:a9ff:fe69:59ec';
120308 16:08:20 [Note] Server socket created on IP: '10.178.58.216'.
More than one entry for ipv4 and ipv6 address:
=> Following message logged
120308 16:06:19 [Note] Server hostname (bind-address): 'localhost'; port: 3306
120308 16:06:19 [Note] - 'localhost' resolves to '::1';
120308 16:06:19 [Note] - 'localhost' resolves to '::1';
120308 16:06:19 [Note] - 'localhost' resolves to '127.0.0.1';
120308 16:06:19 [Note] - 'localhost' resolves to '127.0.0.1';
120308 16:06:19 [Note] Server socket created on IP: '127.0.0.1'.
-rw-r--r-- | sql/mysqld.cc | 111 |
1 files changed, 77 insertions, 34 deletions
diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 33dd94d99f2..69045affee4 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1765,6 +1765,48 @@ static void set_root(const char *path) } +static my_socket create_socket(const struct addrinfo *addrinfo_list, + int addr_family, + struct addrinfo **use_addrinfo) +{ + my_socket sock= INVALID_SOCKET; + + for (const struct addrinfo *cur_ai= addrinfo_list; cur_ai != NULL; + cur_ai= cur_ai->ai_next) + { + if (cur_ai->ai_family != addr_family) + continue; + + sock= socket(cur_ai->ai_family, cur_ai->ai_socktype, cur_ai->ai_protocol); + + char ip_addr[INET6_ADDRSTRLEN]; + + if (vio_get_normalized_ip_string(cur_ai->ai_addr, cur_ai->ai_addrlen, + ip_addr, sizeof (ip_addr))) + { + ip_addr[0]= 0; + } + + if (sock == INVALID_SOCKET) + { + sql_print_error("Failed to create a socket for %s '%s': errno: %d.", + (addr_family == AF_INET) ? "IPv4" : "IPv6", + (const char *) ip_addr, + (int) socket_errno); + continue; + } + + sql_print_information("Server socket created on IP: '%s'.", + (const char *) ip_addr); + + *use_addrinfo= (struct addrinfo *)cur_ai; + return sock; + } + + return INVALID_SOCKET; +} + + static void network_init(void) { #ifdef HAVE_SYS_UN_H @@ -1793,37 +1835,60 @@ static void network_init(void) { struct addrinfo *ai, *a; struct addrinfo hints; - int error; - DBUG_PRINT("general",("IP Socket is %d",mysqld_port)); + sql_print_information("Server hostname (bind-address): '%s'; port: %d", + my_bind_addr_str, mysqld_port); + + // Get list of IP-addresses associated with the server hostname. bzero(&hints, sizeof (hints)); hints.ai_flags= AI_PASSIVE; hints.ai_socktype= SOCK_STREAM; hints.ai_family= AF_UNSPEC; my_snprintf(port_buf, NI_MAXSERV, "%d", mysqld_port); - error= getaddrinfo(my_bind_addr_str, port_buf, &hints, &ai); - if (error != 0) + if (getaddrinfo(my_bind_addr_str, port_buf, &hints, &ai)) { - DBUG_PRINT("error",("Got error: %d from getaddrinfo()", error)); sql_perror(ER_DEFAULT(ER_IPSOCK_ERROR)); /* purecov: tested */ + sql_print_error("Can't start server: cannot resolve hostname!"); unireg_abort(1); /* purecov: tested */ } - for (a= ai; a != NULL; a= a->ai_next) + // Log all the IP-addresses. + for (struct addrinfo *cur_ai= ai; cur_ai != NULL; cur_ai= cur_ai->ai_next) { - ip_sock= socket(a->ai_family, a->ai_socktype, a->ai_protocol); - if (ip_sock != INVALID_SOCKET) - break; + char ip_addr[INET6_ADDRSTRLEN]; + + if (vio_get_normalized_ip_string(cur_ai->ai_addr, cur_ai->ai_addrlen, + ip_addr, sizeof (ip_addr))) + { + sql_print_error("Fails to print out IP-address."); + continue; + } + + sql_print_information(" - '%s' resolves to '%s';", + my_bind_addr_str, ip_addr); } + /* + If the 'bind-address' option specifies the hostname, which resolves to + multiple IP-address, use the following rule: + - if there are IPv4-addresses, use the first IPv4-address + returned by getaddrinfo(); + - if there are IPv6-addresses, use the first IPv6-address + returned by getaddrinfo(); + */ + + ip_sock= create_socket(ai, AF_INET, &a); + + if (ip_sock == INVALID_SOCKET) + ip_sock= create_socket(ai, AF_INET6, &a); + + // Report user-error if we failed to create a socket. if (ip_sock == INVALID_SOCKET) { - DBUG_PRINT("error",("Got error: %d from socket()",socket_errno)); sql_perror(ER_DEFAULT(ER_IPSOCK_ERROR)); /* purecov: tested */ - unireg_abort(1); /* purecov: tested */ + unireg_abort(1); /* purecov: tested */ } - #ifndef __WIN__ /* We should not use SO_REUSEADDR on windows as this would enable a @@ -7027,28 +7092,6 @@ mysqld_get_one_option(int optid, case (int) OPT_SKIP_STACK_TRACE: test_flags|=TEST_NO_STACKTRACE; break; - case (int) OPT_BIND_ADDRESS: - { - struct addrinfo *res_lst, hints; - - bzero(&hints, sizeof(struct addrinfo)); - hints.ai_socktype= SOCK_STREAM; - hints.ai_protocol= IPPROTO_TCP; - - if (getaddrinfo(argument, NULL, &hints, &res_lst) != 0) - { - sql_print_error("Can't start server: cannot resolve hostname!"); - return 1; - } - - if (res_lst->ai_next) - { - sql_print_error("Can't start server: bind-address refers to multiple interfaces!"); - return 1; - } - freeaddrinfo(res_lst); - } - break; case OPT_CONSOLE: if (opt_console) opt_error_log= 0; // Force logs to stdout |