summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNirbhay Choubey <nirbhay@mariadb.com>2015-09-15 18:58:08 -0400
committerNirbhay Choubey <nirbhay@mariadb.com>2015-09-15 18:58:08 -0400
commitbb52905432779d1648241baa5945c61617f2d58f (patch)
tree369b6c90366e3c8add210d0367e2d0cc05fcff7e
parent31cf362c21b24ebda9d3997a401750ec94a19d5c (diff)
downloadmariadb-git-bb52905432779d1648241baa5945c61617f2d58f.tar.gz
MDEV-8034 : wsrep_node_address can't be IPV6
Updated address parsing logic to include IPv6 format.
-rw-r--r--sql/wsrep_mysqld.cc96
-rw-r--r--sql/wsrep_sst.cc64
-rw-r--r--sql/wsrep_utils.cc77
-rw-r--r--sql/wsrep_utils.h144
4 files changed, 268 insertions, 113 deletions
diff --git a/sql/wsrep_mysqld.cc b/sql/wsrep_mysqld.cc
index a785b8764cf..d72d9fdf151 100644
--- a/sql/wsrep_mysqld.cc
+++ b/sql/wsrep_mysqld.cc
@@ -618,6 +618,7 @@ int wsrep_init()
wsrep->provider_vendor, sizeof(provider_vendor) - 1);
}
+ /* Initialize node address */
char node_addr[512]= { 0, };
size_t const node_addr_max= sizeof(node_addr) - 1;
if (!wsrep_node_address || !strcmp(wsrep_node_address, ""))
@@ -635,86 +636,81 @@ int wsrep_init()
strncpy(node_addr, wsrep_node_address, node_addr_max);
}
+ /* Initialize node's incoming address */
char inc_addr[512]= { 0, };
size_t const inc_addr_max= sizeof (inc_addr);
+
+ /*
+ In case wsrep_node_incoming_address is either not set or set to AUTO,
+ we need to use mysqld's my_bind_addr_str:mysqld_port, lastly fallback
+ to wsrep_node_address' value if mysqld's bind-address is not set either.
+ */
if ((!wsrep_node_incoming_address ||
!strcmp (wsrep_node_incoming_address, WSREP_NODE_INCOMING_AUTO)))
{
+ bool is_ipv6= false;
unsigned int my_bind_ip= INADDR_ANY; // default if not set
+
if (my_bind_addr_str && strlen(my_bind_addr_str))
{
- my_bind_ip= wsrep_check_ip(my_bind_addr_str);
+ my_bind_ip= wsrep_check_ip(my_bind_addr_str, &is_ipv6);
}
if (INADDR_ANY != my_bind_ip)
{
+ /*
+ If its a not a valid address, leave inc_addr as empty string. mysqld
+ is not listening for client connections on network interfaces.
+ */
if (INADDR_NONE != my_bind_ip && INADDR_LOOPBACK != my_bind_ip)
{
- snprintf(inc_addr, inc_addr_max, "%s:%u",
- my_bind_addr_str, (int)mysqld_port);
- } // else leave inc_addr an empty string - mysqld is not listening for
- // client connections on network interfaces.
+ const char *fmt= (is_ipv6) ? "[%s]:%u" : "%s:%u";
+ snprintf(inc_addr, inc_addr_max, fmt, my_bind_addr_str, mysqld_port);
+ }
}
- else // mysqld binds to 0.0.0.0, take IP from wsrep_node_address if possible
+ else /* mysqld binds to 0.0.0.0, try taking IP from wsrep_node_address. */
{
size_t const node_addr_len= strlen(node_addr);
if (node_addr_len > 0)
{
- const char* const colon= strrchr(node_addr, ':');
- if (strchr(node_addr, ':') == colon) // 1 or 0 ':'
- {
- size_t const ip_len= colon ? colon - node_addr : node_addr_len;
- if (ip_len + 7 /* :55555\0 */ < inc_addr_max)
- {
- memcpy (inc_addr, node_addr, ip_len);
- snprintf(inc_addr + ip_len, inc_addr_max - ip_len, ":%u",
- (int)mysqld_port);
- }
- else
- {
- WSREP_WARN("Guessing address for incoming client connections: "
- "address too long.");
- inc_addr[0]= '\0';
- }
- }
- else
- {
- WSREP_WARN("Guessing address for incoming client connections: "
- "too many colons :) .");
- inc_addr[0]= '\0';
- }
- }
+ wsp::Address addr(node_addr);
- if (!strlen(inc_addr))
- {
+ if (!addr.is_valid())
+ {
+ WSREP_DEBUG("Could not parse node address : %s", node_addr);
WSREP_WARN("Guessing address for incoming client connections failed. "
"Try setting wsrep_node_incoming_address explicitly.");
+ goto done;
+ }
+
+ const char *fmt= (addr.is_ipv6()) ? "[%s]:%u" : "%s:%u";
+ snprintf(inc_addr, inc_addr_max, fmt, addr.get_address(),
+ (int) mysqld_port);
}
}
}
- else if (!strchr(wsrep_node_incoming_address, ':')) // no port included
- {
- if ((int)inc_addr_max <=
- snprintf(inc_addr, inc_addr_max, "%s:%u",
- wsrep_node_incoming_address,(int)mysqld_port))
- {
- WSREP_WARN("Guessing address for incoming client connections: "
- "address too long.");
- inc_addr[0]= '\0';
- }
- }
else
{
- size_t const need = strlen (wsrep_node_incoming_address);
- if (need >= inc_addr_max) {
- WSREP_WARN("wsrep_node_incoming_address too long: %zu", need);
- inc_addr[0]= '\0';
- }
- else {
- memcpy (inc_addr, wsrep_node_incoming_address, need);
+ wsp::Address addr(wsrep_node_incoming_address);
+
+ if (!addr.is_valid())
+ {
+ WSREP_WARN("Could not parse wsrep_node_incoming_address : %s",
+ wsrep_node_incoming_address);
+ goto done;
}
+
+ /*
+ In case port is not specified in wsrep_node_incoming_address, we use
+ mysqld_port.
+ */
+ int port= (addr.get_port() > 0) ? addr.get_port() : (int) mysqld_port;
+ const char *fmt= (addr.is_ipv6()) ? "[%s]:%u" : "%s:%u";
+
+ snprintf(inc_addr, inc_addr_max, fmt, addr.get_address(), port);
}
+done:
struct wsrep_init_args wsrep_args;
struct wsrep_gtid const state_id = { local_uuid, local_seqno };
diff --git a/sql/wsrep_sst.cc b/sql/wsrep_sst.cc
index 7e6bc2123dc..b31d433de08 100644
--- a/sql/wsrep_sst.cc
+++ b/sql/wsrep_sst.cc
@@ -629,8 +629,6 @@ static bool SE_initialized = false;
ssize_t wsrep_sst_prepare (void** msg)
{
- const ssize_t ip_max= 256;
- char ip_buf[ip_max];
const char* addr_in= NULL;
const char* addr_out= NULL;
@@ -646,27 +644,34 @@ ssize_t wsrep_sst_prepare (void** msg)
return ret;
}
- // Figure out SST address. Common for all SST methods
+ /*
+ Figure out SST receive address. Common for all SST methods.
+ */
+ char ip_buf[256];
+ const ssize_t ip_max= sizeof(ip_buf);
+
+ // Attempt 1: wsrep_sst_receive_address
if (wsrep_sst_receive_address &&
strcmp (wsrep_sst_receive_address, WSREP_SST_ADDRESS_AUTO))
{
addr_in= wsrep_sst_receive_address;
}
+
+ //Attempt 2: wsrep_node_address
else if (wsrep_node_address && strlen(wsrep_node_address))
{
- const char* const colon= strchr (wsrep_node_address, ':');
- if (colon)
- {
- ptrdiff_t const len= colon - wsrep_node_address;
- strncpy (ip_buf, wsrep_node_address, len);
- ip_buf[len]= '\0';
- addr_in= ip_buf;
- }
- else
+ wsp::Address addr(wsrep_node_address);
+
+ if (!addr.is_valid())
{
- addr_in= wsrep_node_address;
+ WSREP_ERROR("Could not parse wsrep_node_address : %s",
+ wsrep_node_address);
+ unireg_abort(1);
}
+ memcpy(ip_buf, addr.get_address(), addr.get_address_len());
+ addr_in= ip_buf;
}
+ // Attempt 3: Try to get the IP from the list of available interfaces.
else
{
ssize_t ret= wsrep_guess_ip (ip_buf, ip_max);
@@ -677,8 +682,7 @@ ssize_t wsrep_sst_prepare (void** msg)
}
else
{
- WSREP_ERROR("Could not prepare state transfer request: "
- "failed to guess address to accept state transfer at. "
+ WSREP_ERROR("Failed to guess address to accept state transfer. "
"wsrep_sst_receive_address must be set manually.");
unireg_abort(1);
}
@@ -778,8 +782,10 @@ static void sst_reject_queries(my_bool close_conn)
if (TRUE == close_conn) wsrep_close_client_connections(FALSE);
}
-static int sst_mysqldump_check_addr (const char* user, const char* pswd,
- const char* host, const char* port)
+static int sst_mysqldump_check_addr (const char* user,
+ const char* pswd,
+ const char* host,
+ int port)
{
return 0;
}
@@ -790,25 +796,17 @@ static int sst_donate_mysqldump (const char* addr,
wsrep_seqno_t seqno,
bool bypass)
{
- size_t host_len;
- const char* port = strchr (addr, ':');
+ char host[256];
+ wsp::Address address(addr);
- if (port)
- {
- port += 1;
- host_len = port - addr;
- }
- else
+ if (!address.is_valid())
{
- port = "";
- host_len = strlen (addr) + 1;
+ WSREP_ERROR("Could not parse SST address : %s", addr);
+ return 0;
}
- char *host= (char *) alloca(host_len);
-
- strncpy (host, addr, host_len - 1);
- host[host_len - 1] = '\0';
-
+ memcpy(host, address.get_address(), address.get_address_len());
+ int port= address.get_port();
const char* auth = sst_auth_real;
const char* pswd = (auth) ? strchr (auth, ':') : NULL;
size_t user_len;
@@ -843,7 +841,7 @@ static int sst_donate_mysqldump (const char* addr,
WSREP_SST_OPT_USER" '%s' "
WSREP_SST_OPT_PSWD" '%s' "
WSREP_SST_OPT_HOST" '%s' "
- WSREP_SST_OPT_PORT" '%s' "
+ WSREP_SST_OPT_PORT" '%d' "
WSREP_SST_OPT_LPORT" '%u' "
WSREP_SST_OPT_SOCKET" '%s' "
" %s "
diff --git a/sql/wsrep_utils.cc b/sql/wsrep_utils.cc
index 7a87d38d430..80f8bd4c7d4 100644
--- a/sql/wsrep_utils.cc
+++ b/sql/wsrep_utils.cc
@@ -352,7 +352,7 @@ thd::~thd ()
} // namespace wsp
/* Returns INADDR_NONE, INADDR_ANY, INADDR_LOOPBACK or something else */
-unsigned int wsrep_check_ip (const char* const addr)
+unsigned int wsrep_check_ip (const char* const addr, bool *is_ipv6)
{
unsigned int ret = INADDR_NONE;
struct addrinfo *res, hints;
@@ -362,6 +362,8 @@ unsigned int wsrep_check_ip (const char* const addr)
hints.ai_socktype= SOCK_STREAM;
hints.ai_family= AF_UNSPEC;
+ *is_ipv6= false;
+
int gai_ret = getaddrinfo(addr, NULL, &hints, &res);
if (0 == gai_ret)
{
@@ -379,6 +381,8 @@ unsigned int wsrep_check_ip (const char* const addr)
ret= INADDR_LOOPBACK;
else
ret= 0xdeadbeef;
+
+ *is_ipv6= true;
}
freeaddrinfo (res);
}
@@ -387,10 +391,6 @@ unsigned int wsrep_check_ip (const char* const addr)
addr, gai_ret, gai_strerror(gai_ret));
}
- // uint8_t* b= (uint8_t*)&ret;
- // fprintf (stderr, "########## wsrep_check_ip returning: %hhu.%hhu.%hhu.%hhu\n",
- // b[0], b[1], b[2], b[3]);
-
return ret;
}
@@ -398,44 +398,47 @@ extern char* my_bind_addr_str;
size_t wsrep_guess_ip (char* buf, size_t buf_len)
{
- size_t ip_len = 0;
+ size_t ret= 0;
+ // Attempt 1: Try to get the IP from bind-address.
if (my_bind_addr_str && my_bind_addr_str[0] != '\0')
{
- unsigned int const ip_type= wsrep_check_ip(my_bind_addr_str);
+ bool unused;
+ unsigned int const ip_type= wsrep_check_ip(my_bind_addr_str, &unused);
if (INADDR_NONE == ip_type) {
WSREP_ERROR("Networking not configured, cannot receive state "
"transfer.");
- return 0;
- }
-
- if (INADDR_ANY != ip_type) {
+ ret= 0;
+ } else if (INADDR_ANY != ip_type) {
strncpy (buf, my_bind_addr_str, buf_len);
- return strlen(buf);
+ ret= strlen(buf);
}
+ goto done;
}
- // mysqld binds to all interfaces - try IP from wsrep_node_address
+ // Attempt 2: mysqld binds to all interfaces, try IP from wsrep_node_address.
if (wsrep_node_address && wsrep_node_address[0] != '\0') {
- const char* const colon_ptr = strchr(wsrep_node_address, ':');
-
- if (colon_ptr)
- ip_len = colon_ptr - wsrep_node_address;
- else
- ip_len = strlen(wsrep_node_address);
-
- if (ip_len >= buf_len) {
- WSREP_WARN("default_ip(): buffer too short: %zu <= %zd", buf_len, ip_len);
- return 0;
+ wsp::Address addr(wsrep_node_address);
+ if (!addr.is_valid())
+ {
+ WSREP_WARN("Could not parse wsrep_node_address : %s",
+ wsrep_node_address);
+ ret= 0;
+ goto done;
}
- memcpy (buf, wsrep_node_address, ip_len);
- buf[ip_len] = '\0';
- return ip_len;
+ /* Safety check: Buffer length should be sufficiently large. */
+ DBUG_ASSERT(buf_len >= addr.get_address_len());
+
+ memcpy(buf, addr.get_address(), addr.get_address_len());
+ ret= addr.get_address_len();
+ goto done;
}
/*
+ Attempt 3: Try to get the IP from the list of available interfaces.
+
getifaddrs() is avaiable at least on Linux since glib 2.3, FreeBSD,
MAC OSX, OpenSolaris, Solaris.
@@ -444,26 +447,42 @@ size_t wsrep_guess_ip (char* buf, size_t buf_len)
*/
#if HAVE_GETIFADDRS
struct ifaddrs *ifaddr, *ifa;
+ int family;
+
if (getifaddrs(&ifaddr) == 0)
{
for (ifa= ifaddr; ifa != NULL; ifa = ifa->ifa_next)
{
- if (!ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET) // TODO AF_INET6
+ if (!ifa->ifa_addr)
+ continue;
+
+ family= ifa->ifa_addr->sa_family;
+
+ if ((family != AF_INET) && (family != AF_INET6))
continue;
// Skip loopback interfaces (like lo:127.0.0.1)
if (ifa->ifa_flags & IFF_LOOPBACK)
continue;
+ /*
+ Get IP address from the socket address. The resulting address may have
+ zone ID appended for IPv6 addresses (<address>%<zone-id>).
+ */
if (vio_getnameinfo(ifa->ifa_addr, buf, buf_len, NULL, 0, NI_NUMERICHOST))
continue;
freeifaddrs(ifaddr);
- return strlen(buf);
+
+ ret= strlen(buf);
+ goto done;
}
freeifaddrs(ifaddr);
}
#endif /* HAVE_GETIFADDRS */
- return 0;
+done:
+ WSREP_DEBUG("wsrep_guess_ip() : %s", (ret > 0) ? buf : "????");
+ return ret;
}
+
diff --git a/sql/wsrep_utils.h b/sql/wsrep_utils.h
index 1cc65578202..32829c605fb 100644
--- a/sql/wsrep_utils.h
+++ b/sql/wsrep_utils.h
@@ -19,11 +19,153 @@
#include "wsrep_priv.h"
#include "wsrep_mysqld.h"
-unsigned int wsrep_check_ip (const char* addr);
+unsigned int wsrep_check_ip (const char* addr, bool *is_ipv6);
size_t wsrep_guess_ip (char* buf, size_t buf_len);
namespace wsp {
+class Address {
+public:
+ Address()
+ : m_address_len(0), m_family(UNSPEC), m_port(0), m_valid(false)
+ {
+ memset(m_address, 0, sizeof(m_address));
+ }
+ Address(const char *addr_in)
+ : m_address_len(0), m_family(UNSPEC), m_port(0), m_valid(false)
+ {
+ memset(m_address, 0, sizeof(m_address));
+ parse_addr(addr_in);
+ }
+ bool is_valid() { return m_valid; }
+ bool is_ipv6() { return (m_family == INET6); }
+
+ const char* get_address() { return m_address; }
+ size_t get_address_len() { return m_address_len; }
+ int get_port() { return m_port; }
+
+private:
+ enum family {
+ UNSPEC= 0,
+ INET, /* IPv4 */
+ INET6, /* IPv6 */
+ };
+
+ char m_address[256];
+ size_t m_address_len;
+ family m_family;
+ int m_port;
+ bool m_valid;
+
+ void parse_addr(const char *addr_in) {
+ const char *start;
+ const char *end;
+ const char *port;
+ const char* open_bracket= strchr(const_cast<char *>(addr_in), '[');
+ const char* close_bracket= strchr(const_cast<char *>(addr_in), ']');
+ const char* colon= strchr(const_cast<char *>(addr_in), ':');
+ const char* dot= strchr(const_cast<char *>(addr_in), '.');
+
+ int cc= colon_count(addr_in);
+
+ if (open_bracket != NULL ||
+ dot == NULL ||
+ (colon != NULL && (dot == NULL || colon < dot)))
+ {
+ // This could be an IPv6 address or a hostname
+ if (open_bracket != NULL) {
+ /* Sanity check: Address with '[' must include ']' */
+ if (close_bracket == NULL &&
+ open_bracket < close_bracket) /* Error: malformed address */
+ {
+ m_valid= false;
+ return;
+ }
+
+ start= open_bracket + 1;
+ end= close_bracket;
+
+ /* Check for port */
+ port= strchr(close_bracket, ':');
+ if ((port != NULL) && parse_port(port + 1))
+ {
+ return; /* Error: invalid port */
+ }
+ m_family= INET6;
+ }
+ else
+ {
+ switch (cc) {
+ case 0:
+ /* Hostname with no port */
+ start= addr_in;
+ end= addr_in + strlen(addr_in);
+ break;
+ case 1:
+ /* Hostname with port (host:port) */
+ start= addr_in;
+ end= colon;
+ parse_port(colon + 1);
+ break;
+ default:
+ /* IPv6 address */
+ start= addr_in;
+ end= addr_in + strlen(addr_in);
+ m_family= INET6;
+ break;
+ }
+ }
+ } else { /* IPv4 address or hostname */
+ start= addr_in;
+ if (colon != NULL) { /* Port */
+ end= colon;
+ if (parse_port(colon + 1))
+ return; /* Error: invalid port */
+ } else {
+ end= addr_in + strlen(addr_in);
+ }
+ }
+
+ size_t len= end - start;
+
+ /* Safety */
+ if (len >= sizeof(m_address))
+ {
+ // The supplied address is too large to fit into the internal buffer.
+ m_valid= false;
+ return;
+ }
+
+ memcpy(m_address, start, len);
+ m_address[len]= '\0';
+ m_address_len= ++ len;
+ m_valid= true;
+ return;
+ }
+
+ int colon_count(const char *addr) {
+ int count= 0, i= 0;
+
+ while(addr[i] != '\0')
+ {
+ if (addr[i] == ':') ++count;
+ ++ i;
+ }
+ return count;
+ }
+
+ bool parse_port(const char *port) {
+ m_port= strtol(port, NULL, 10);
+ if (errno == EINVAL || errno == ERANGE)
+ {
+ m_port= 0; /* Error: invalid port */
+ m_valid= false;
+ return true;
+ }
+ return false;
+ }
+};
+
class Config_state
{
public: