diff options
author | Nirbhay Choubey <nirbhay@mariadb.com> | 2015-09-15 18:58:08 -0400 |
---|---|---|
committer | Nirbhay Choubey <nirbhay@mariadb.com> | 2015-09-15 18:58:08 -0400 |
commit | bb52905432779d1648241baa5945c61617f2d58f (patch) | |
tree | 369b6c90366e3c8add210d0367e2d0cc05fcff7e /sql/wsrep_utils.h | |
parent | 31cf362c21b24ebda9d3997a401750ec94a19d5c (diff) | |
download | mariadb-git-bb52905432779d1648241baa5945c61617f2d58f.tar.gz |
MDEV-8034 : wsrep_node_address can't be IPV6
Updated address parsing logic to include IPv6 format.
Diffstat (limited to 'sql/wsrep_utils.h')
-rw-r--r-- | sql/wsrep_utils.h | 144 |
1 files changed, 143 insertions, 1 deletions
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: |