From f60d1cd6b179954718f714ec2513341cd939bec2 Mon Sep 17 00:00:00 2001 From: Marko Date: Wed, 22 Aug 2018 12:44:11 +0300 Subject: [PATCH] Handle ipv6 mapped ipv4 addresses. In default case MaxScale uses ipv6 for all addresses also mapping ipv4 connections to ipv6. This caused NamedServerFilter to never match these addresses to the ones defined in source parameter in ipv4 form. These ipv6-mapped addresses are now transformed to ipv4 so they can be checked against source parameter list. --- .../namedserverfilter/namedserverfilter.cc | 57 ++++++++++++++++--- .../namedserverfilter/namedserverfilter.hh | 2 + 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/server/modules/filter/namedserverfilter/namedserverfilter.cc b/server/modules/filter/namedserverfilter/namedserverfilter.cc index 0b48977bc..d50a29b29 100644 --- a/server/modules/filter/namedserverfilter/namedserverfilter.cc +++ b/server/modules/filter/namedserverfilter/namedserverfilter.cc @@ -669,13 +669,27 @@ void RegexHintFilter::form_regex_server_mapping(MXS_CONFIG_PARAMETER* params, in */ bool RegexHintFilter::check_source_host(const char* remote, const struct sockaddr_storage *ip) { - int rval = false; + bool rval = false; + struct sockaddr_storage addr; + memcpy(&addr, ip, sizeof(addr)); for (const auto& source : m_sources) { - struct sockaddr_in check_ipv4; + if (addr.ss_family == AF_INET6) + { + struct sockaddr_in6* addr6 = (struct sockaddr_in6*)&addr; - memcpy(&check_ipv4, ip, sizeof(check_ipv4)); + if (IN6_IS_ADDR_V4MAPPED(&addr6->sin6_addr)) + { + mapped_ipv6_to_ipv4(&addr); + } + else + { + // TODO handle ipv6 address + return false; + } + } + struct sockaddr_in *check_ipv4 = (struct sockaddr_in*)&addr; switch (source.m_netmask) { @@ -684,15 +698,15 @@ bool RegexHintFilter::check_source_host(const char* remote, const struct sockadd break; case 24: /* Class C check */ - check_ipv4.sin_addr.s_addr &= 0x00FFFFFF; + check_ipv4->sin_addr.s_addr &= 0x00FFFFFF; break; case 16: /* Class B check */ - check_ipv4.sin_addr.s_addr &= 0x0000FFFF; + check_ipv4->sin_addr.s_addr &= 0x0000FFFF; break; case 8: /* Class A check */ - check_ipv4.sin_addr.s_addr &= 0x000000FF; + check_ipv4->sin_addr.s_addr &= 0x000000FF; break; default: break; @@ -700,7 +714,7 @@ bool RegexHintFilter::check_source_host(const char* remote, const struct sockadd if (source.m_netmask < 32) { - rval = (check_ipv4.sin_addr.s_addr == source.m_ipv4.sin_addr.s_addr); + rval = (check_ipv4->sin_addr.s_addr == source.m_ipv4.sin_addr.s_addr); } if (rval) @@ -722,6 +736,21 @@ bool RegexHintFilter::check_source_hostnames(const char* remote, const struct so memcpy(&addr, ip, sizeof(addr)); char hbuf[NI_MAXHOST]; + if (addr.ss_family == AF_INET6) + { + struct sockaddr_in6* addr6 = (struct sockaddr_in6*)&addr; + + if (IN6_IS_ADDR_V4MAPPED(&addr6->sin6_addr)) + { + mapped_ipv6_to_ipv4(&addr); + } + else + { + // TODO handle ipv6 address + return false; + } + } + if (int rc = (getnameinfo((struct sockaddr *)&addr, sizeof(sockaddr), hbuf, sizeof(hbuf), 0, 0, NI_NAMEREQD)) != 0) { MXS_INFO("Failed to resolve hostname due to %s", gai_strerror(rc)); @@ -741,6 +770,20 @@ bool RegexHintFilter::check_source_hostnames(const char* remote, const struct so return false; } +void RegexHintFilter::mapped_ipv6_to_ipv4(struct sockaddr_storage* addr) +{ + struct sockaddr_in6* addr6 = (struct sockaddr_in6*)addr; + struct sockaddr_in addr4; + memset(&addr4, 0, sizeof(addr4)); + addr4.sin_family = AF_INET; + addr4.sin_port = addr6->sin6_port; + + /* When mapped to ipv6, ipv4 addresses are prepended with prefix of length 12. + * Lets ignore the prefix and only copy the actual ipv4 address. */ + memcpy(&addr4.sin_addr.s_addr, addr6->sin6_addr.s6_addr + 12, sizeof(addr4.sin_addr.s_addr)); + memcpy(addr, &addr4, sizeof(addr4)); +} + /** * Validate IP address string againt three dots * and last char not being a dot. diff --git a/server/modules/filter/namedserverfilter/namedserverfilter.hh b/server/modules/filter/namedserverfilter/namedserverfilter.hh index e6163c44d..7d6accebf 100644 --- a/server/modules/filter/namedserverfilter/namedserverfilter.hh +++ b/server/modules/filter/namedserverfilter/namedserverfilter.hh @@ -47,6 +47,8 @@ private: bool check_source_host(const char *remote, const struct sockaddr_storage *ip); bool check_source_hostnames(const char *remote, const struct sockaddr_storage *ip); + /* Change ipv6 mapped ipv4 address to actual ipv4 address*/ + void mapped_ipv6_to_ipv4(struct sockaddr_storage* ip); public: /* Total statements diverted statistics. Unreliable due to lockless yet * shared access. */