diff --git a/source/common/network/address_impl.cc b/source/common/network/address_impl.cc index 240a4ff1ce246..f1b4c31f4b20d 100644 --- a/source/common/network/address_impl.cc +++ b/source/common/network/address_impl.cc @@ -34,7 +34,20 @@ Address::InstanceConstSharedPtr addressFromSockAddr(const sockaddr_storage& ss, RELEASE_ASSERT(ss_len == 0 || ss_len == sizeof(sockaddr_in6)); const struct sockaddr_in6* sin6 = reinterpret_cast(&ss); ASSERT(AF_INET6 == sin6->sin6_family); - return std::make_shared(*sin6, v6only); + if (!v6only && IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { +#ifndef s6_addr32 +#ifdef __APPLE__ +#define s6_addr32 __u6_addr.__u6_addr32 +#endif +#endif + struct sockaddr_in sin = {.sin_family = AF_INET, + .sin_port = sin6->sin6_port, + .sin_addr = {.s_addr = sin6->sin6_addr.s6_addr32[3]}, + .sin_zero = {}}; + return std::make_shared(&sin); + } else { + return std::make_shared(*sin6, v6only); + } } case AF_UNIX: { const struct sockaddr_un* sun = reinterpret_cast(&ss); diff --git a/test/common/network/address_impl_test.cc b/test/common/network/address_impl_test.cc index a905ece52b586..6808c9cf00375 100644 --- a/test/common/network/address_impl_test.cc +++ b/test/common/network/address_impl_test.cc @@ -319,6 +319,15 @@ TEST(AddressFromSockAddr, IPv6) { EXPECT_DEATH(addressFromSockAddr(ss, sizeof(sockaddr_in6) + 1), "ss_len"); EXPECT_EQ("[1:23::ef]:32000", addressFromSockAddr(ss, sizeof(sockaddr_in6))->asString()); + + // Test that IPv4-mapped IPv6 address is returned as an Ipv4Instance when 'v6only' parameter is + // 'false', but not otherwise. + EXPECT_EQ(1, inet_pton(AF_INET6, "::ffff:192.0.2.128", &sin6.sin6_addr)); + EXPECT_EQ(IpVersion::v4, addressFromSockAddr(ss, sizeof(sockaddr_in6), false)->ip()->version()); + EXPECT_EQ("192.0.2.128:32000", addressFromSockAddr(ss, sizeof(sockaddr_in6), false)->asString()); + EXPECT_EQ(IpVersion::v6, addressFromSockAddr(ss, sizeof(sockaddr_in6), true)->ip()->version()); + EXPECT_EQ("[::ffff:192.0.2.128]:32000", + addressFromSockAddr(ss, sizeof(sockaddr_in6), true)->asString()); } TEST(AddressFromSockAddr, Pipe) {