MDEV-8034 : wsrep_node_address can't be IPV6
Updated address parsing logic to include IPv6 format.
This commit is contained in:
parent
31cf362c21
commit
bb52905432
@ -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 };
|
||||
|
@ -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)
|
||||
wsp::Address addr(wsrep_node_address);
|
||||
|
||||
if (!addr.is_valid())
|
||||
{
|
||||
ptrdiff_t const len= colon - wsrep_node_address;
|
||||
strncpy (ip_buf, wsrep_node_address, len);
|
||||
ip_buf[len]= '\0';
|
||||
addr_in= ip_buf;
|
||||
}
|
||||
else
|
||||
{
|
||||
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)
|
||||
if (!address.is_valid())
|
||||
{
|
||||
port += 1;
|
||||
host_len = port - addr;
|
||||
}
|
||||
else
|
||||
{
|
||||
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 "
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user