From e2afd077449130ea528b9f04ae0c757022c4ff62 Mon Sep 17 00:00:00 2001 From: Matt Klein Date: Thu, 16 Jun 2022 20:48:17 +0000 Subject: [PATCH 1/5] tmp: always use v6 on android Signed-off-by: Matt Klein --- .../common/network/io_socket_handle_impl.cc | 26 ++++++++++++++++++- source/common/network/io_socket_handle_impl.h | 6 +++++ .../common/network/socket_interface_impl.cc | 5 ++-- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/source/common/network/io_socket_handle_impl.cc b/source/common/network/io_socket_handle_impl.cc index c3d87dcf5edf0..6cec6eaf85705 100644 --- a/source/common/network/io_socket_handle_impl.cc +++ b/source/common/network/io_socket_handle_impl.cc @@ -63,6 +63,15 @@ constexpr int messageTruncatedOption() { namespace Network { +bool IoSocketHandleImpl::alwaysUseV6OnAndroid() { +#ifndef __ANDROID_API__ + return false; +#else + // TODO(mattklein123): Check runtime. + return true; +#endif +} + IoSocketHandleImpl::~IoSocketHandleImpl() { if (SOCKET_VALID(fd_)) { IoSocketHandleImpl::close(); @@ -466,7 +475,22 @@ IoHandlePtr IoSocketHandleImpl::accept(struct sockaddr* addr, socklen_t* addrlen } Api::SysCallIntResult IoSocketHandleImpl::connect(Address::InstanceConstSharedPtr address) { - return Api::OsSysCallsSingleton::get().connect(fd_, address->sockAddr(), address->sockAddrLen()); + auto sockaddr_to_use = address->sockAddr(); +#ifdef __ANDROID_API__ + sockaddr_storage ss; + if (sockaddr_to_use->sa_family == AF_INET && alwaysUseV6OnAndroid()) { + const sockaddr_in& sin4 = reinterpret_cast(*sockaddr_to_use); + + memset(&ss, 0, sizeof(ss)); + sockaddr_in6& sin6 = reinterpret_cast(ss); + sin6.sin6_family = AF_INET6; + sin6.sin6_port = sin4.sin_port; + sin6.sin6_addr.s6_addr32[3] = sin4.sin_addr.s_addr; + sockaddr_to_use = reinterpret_cast(&ss); + } +#endif + + return Api::OsSysCallsSingleton::get().connect(fd_, sockaddr_to_use, address->sockAddrLen()); } Api::SysCallIntResult IoSocketHandleImpl::setOption(int level, int optname, const void* optval, diff --git a/source/common/network/io_socket_handle_impl.h b/source/common/network/io_socket_handle_impl.h index 7bc007a2e7ed0..58e9d0ebd160b 100644 --- a/source/common/network/io_socket_handle_impl.h +++ b/source/common/network/io_socket_handle_impl.h @@ -17,6 +17,12 @@ namespace Network { */ class IoSocketHandleImpl : public IoHandle, protected Logger::Loggable { public: + /** + * Check whether we are a) on Android and b) configured via runtime to always use v6 sockets. + * This appears to be what Android OS does for all platform sockets. + */ + static bool alwaysUseV6OnAndroid(); + explicit IoSocketHandleImpl(os_fd_t fd = INVALID_SOCKET, bool socket_v6only = false, absl::optional domain = absl::nullopt) : fd_(fd), socket_v6only_(socket_v6only), domain_(domain) {} diff --git a/source/common/network/socket_interface_impl.cc b/source/common/network/socket_interface_impl.cc index ce38b5d7e70f0..220ccccbe6b34 100644 --- a/source/common/network/socket_interface_impl.cc +++ b/source/common/network/socket_interface_impl.cc @@ -50,7 +50,7 @@ IoHandlePtr SocketInterfaceImpl::socket(Socket::Type socket_type, Address::Type int domain; if (addr_type == Address::Type::Ip) { - if (version == Address::IpVersion::v6) { + if (version == Address::IpVersion::v6 || IoSocketHandleImpl::alwaysUseV6OnAndroid()) { domain = AF_INET6; } else { ASSERT(version == Address::IpVersion::v4); @@ -91,7 +91,8 @@ IoHandlePtr SocketInterfaceImpl::socket(Socket::Type socket_type, IoHandlePtr io_handle = SocketInterfaceImpl::socket(socket_type, addr->type(), ip_version, v6only, options); - if (addr->type() == Address::Type::Ip && ip_version == Address::IpVersion::v6) { + if (addr->type() == Address::Type::Ip && ip_version == Address::IpVersion::v6 && + !IoSocketHandleImpl::alwaysUseV6OnAndroid()) { // Setting IPV6_V6ONLY restricts the IPv6 socket to IPv6 connections only. const Api::SysCallIntResult result = io_handle->setOption( IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast(&v6only), sizeof(v6only)); From 5d32db83fb2272d777aa4d36f5f4049e6232a2d4 Mon Sep 17 00:00:00 2001 From: Matt Klein Date: Fri, 17 Jun 2022 15:39:24 +0000 Subject: [PATCH 2/5] fix Signed-off-by: Matt Klein --- source/common/network/io_socket_handle_impl.cc | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/source/common/network/io_socket_handle_impl.cc b/source/common/network/io_socket_handle_impl.cc index 6cec6eaf85705..cf7f547911498 100644 --- a/source/common/network/io_socket_handle_impl.cc +++ b/source/common/network/io_socket_handle_impl.cc @@ -476,21 +476,27 @@ IoHandlePtr IoSocketHandleImpl::accept(struct sockaddr* addr, socklen_t* addrlen Api::SysCallIntResult IoSocketHandleImpl::connect(Address::InstanceConstSharedPtr address) { auto sockaddr_to_use = address->sockAddr(); + auto sockaddr_len_to_use = address->sockAddrLen(); #ifdef __ANDROID_API__ - sockaddr_storage ss; + sockaddr_in6 sin6; if (sockaddr_to_use->sa_family == AF_INET && alwaysUseV6OnAndroid()) { const sockaddr_in& sin4 = reinterpret_cast(*sockaddr_to_use); - memset(&ss, 0, sizeof(ss)); - sockaddr_in6& sin6 = reinterpret_cast(ss); + // Android always uses IPv6 dual stack. Convert IPv4 to the IPv6 mapped address when + // connecting. + memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; sin6.sin6_port = sin4.sin_port; + sin6.sin6_addr.s6_addr32[2] = htonl(0xffff); sin6.sin6_addr.s6_addr32[3] = sin4.sin_addr.s_addr; - sockaddr_to_use = reinterpret_cast(&ss); + ASSERT(IN6_IS_ADDR_V4MAPPED(&sin6.sin6_addr)); + + sockaddr_to_use = reinterpret_cast(&sin6); + sockaddr_len_to_use = sizeof(sin6); } #endif - return Api::OsSysCallsSingleton::get().connect(fd_, sockaddr_to_use, address->sockAddrLen()); + return Api::OsSysCallsSingleton::get().connect(fd_, sockaddr_to_use, sockaddr_len_to_use); } Api::SysCallIntResult IoSocketHandleImpl::setOption(int level, int optname, const void* optval, From 6f2721f36983d0d2e790ca8a07fff2ae719d7d4a Mon Sep 17 00:00:00 2001 From: Matt Klein Date: Tue, 21 Jun 2022 15:59:17 +0000 Subject: [PATCH 3/5] add runtime Signed-off-by: Matt Klein --- source/common/network/io_socket_handle_impl.cc | 4 ++-- source/common/runtime/runtime_features.cc | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/source/common/network/io_socket_handle_impl.cc b/source/common/network/io_socket_handle_impl.cc index cf7f547911498..ef097530ee9f8 100644 --- a/source/common/network/io_socket_handle_impl.cc +++ b/source/common/network/io_socket_handle_impl.cc @@ -7,6 +7,7 @@ #include "source/common/event/file_event_impl.h" #include "source/common/network/address_impl.h" #include "source/common/network/socket_interface_impl.h" +#include "source/common/runtime/runtime_features.h" #include "absl/container/fixed_array.h" #include "absl/types/optional.h" @@ -67,8 +68,7 @@ bool IoSocketHandleImpl::alwaysUseV6OnAndroid() { #ifndef __ANDROID_API__ return false; #else - // TODO(mattklein123): Check runtime. - return true; + return Runtime::runtimeFeatureEnabled("envoy.reloadable_features.android_always_use_v6"); #endif } diff --git a/source/common/runtime/runtime_features.cc b/source/common/runtime/runtime_features.cc index 1c4629bfc3c3e..3358de89b06dd 100644 --- a/source/common/runtime/runtime_features.cc +++ b/source/common/runtime/runtime_features.cc @@ -93,6 +93,8 @@ FALSE_RUNTIME_GUARD(envoy_reloadable_features_thrift_connection_draining); FALSE_RUNTIME_GUARD(envoy_reloadable_features_http2_use_oghttp2); // Used to track if runtime is initialized. FALSE_RUNTIME_GUARD(envoy_reloadable_features_runtime_initialized); +// TODO(mattklein123): Flip this to true and/or remove completely once verified by Envoy Mobile. +FALSE_RUNTIME_GUARD(envoy_reloadable_features_android_always_use_v6); // Block of non-boolean flags. These are deprecated. Do not add more. ABSL_FLAG(uint64_t, envoy_headermap_lazy_map_min_size, 3, ""); // NOLINT From 1f1588c88478b7a4a8fd89873bb99e3276108203 Mon Sep 17 00:00:00 2001 From: Matt Klein Date: Tue, 21 Jun 2022 17:06:29 +0000 Subject: [PATCH 4/5] comments Signed-off-by: Matt Klein --- source/common/network/io_socket_handle_impl.cc | 7 +++++-- source/common/network/io_socket_handle_impl.h | 2 +- source/common/network/socket_interface_impl.cc | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/source/common/network/io_socket_handle_impl.cc b/source/common/network/io_socket_handle_impl.cc index ef097530ee9f8..afc2f95921256 100644 --- a/source/common/network/io_socket_handle_impl.cc +++ b/source/common/network/io_socket_handle_impl.cc @@ -64,7 +64,7 @@ constexpr int messageTruncatedOption() { namespace Network { -bool IoSocketHandleImpl::alwaysUseV6OnAndroid() { +bool IoSocketHandleImpl::forceV6ForAndroid() { #ifndef __ANDROID_API__ return false; #else @@ -479,7 +479,7 @@ Api::SysCallIntResult IoSocketHandleImpl::connect(Address::InstanceConstSharedPt auto sockaddr_len_to_use = address->sockAddrLen(); #ifdef __ANDROID_API__ sockaddr_in6 sin6; - if (sockaddr_to_use->sa_family == AF_INET && alwaysUseV6OnAndroid()) { + if (sockaddr_to_use->sa_family == AF_INET && forceV6ForAndroid()) { const sockaddr_in& sin4 = reinterpret_cast(*sockaddr_to_use); // Android always uses IPv6 dual stack. Convert IPv4 to the IPv6 mapped address when @@ -569,6 +569,9 @@ Address::InstanceConstSharedPtr IoSocketHandleImpl::peerAddress() { fmt::format("getsockname failed for '{}': {}", fd_, errorDetails(result.errno_))); } } + // TODO(mattklein123): If forceV6ForAndroid() is true, we should probably remap back to IPv4 from + // the mapped IPv6 address. Currently though it doesn't look like we use this function in the + // client path so this probably doesn't matter. If it turns out to matter we can fix this. return Address::addressFromSockAddrOrThrow(ss, ss_len, socket_v6only_); } diff --git a/source/common/network/io_socket_handle_impl.h b/source/common/network/io_socket_handle_impl.h index 58e9d0ebd160b..08b839f8def92 100644 --- a/source/common/network/io_socket_handle_impl.h +++ b/source/common/network/io_socket_handle_impl.h @@ -21,7 +21,7 @@ class IoSocketHandleImpl : public IoHandle, protected Logger::Loggable domain = absl::nullopt) diff --git a/source/common/network/socket_interface_impl.cc b/source/common/network/socket_interface_impl.cc index 220ccccbe6b34..9e6b44fe06a5e 100644 --- a/source/common/network/socket_interface_impl.cc +++ b/source/common/network/socket_interface_impl.cc @@ -50,7 +50,7 @@ IoHandlePtr SocketInterfaceImpl::socket(Socket::Type socket_type, Address::Type int domain; if (addr_type == Address::Type::Ip) { - if (version == Address::IpVersion::v6 || IoSocketHandleImpl::alwaysUseV6OnAndroid()) { + if (version == Address::IpVersion::v6 || IoSocketHandleImpl::forceV6ForAndroid()) { domain = AF_INET6; } else { ASSERT(version == Address::IpVersion::v4); @@ -92,7 +92,7 @@ IoHandlePtr SocketInterfaceImpl::socket(Socket::Type socket_type, IoHandlePtr io_handle = SocketInterfaceImpl::socket(socket_type, addr->type(), ip_version, v6only, options); if (addr->type() == Address::Type::Ip && ip_version == Address::IpVersion::v6 && - !IoSocketHandleImpl::alwaysUseV6OnAndroid()) { + !IoSocketHandleImpl::forceV6ForAndroid()) { // Setting IPV6_V6ONLY restricts the IPv6 socket to IPv6 connections only. const Api::SysCallIntResult result = io_handle->setOption( IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast(&v6only), sizeof(v6only)); From 10ff94869b7c66a9a56c8c225a1c96488c9a6aa5 Mon Sep 17 00:00:00 2001 From: Matt Klein Date: Tue, 21 Jun 2022 21:33:37 +0000 Subject: [PATCH 5/5] comment Signed-off-by: Matt Klein --- source/common/runtime/runtime_features.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/source/common/runtime/runtime_features.cc b/source/common/runtime/runtime_features.cc index 3358de89b06dd..c86363f727aeb 100644 --- a/source/common/runtime/runtime_features.cc +++ b/source/common/runtime/runtime_features.cc @@ -94,6 +94,7 @@ FALSE_RUNTIME_GUARD(envoy_reloadable_features_http2_use_oghttp2); // Used to track if runtime is initialized. FALSE_RUNTIME_GUARD(envoy_reloadable_features_runtime_initialized); // TODO(mattklein123): Flip this to true and/or remove completely once verified by Envoy Mobile. +// TODO(mattklein123): Also unit test this if this sticks and this becomes the default for Android. FALSE_RUNTIME_GUARD(envoy_reloadable_features_android_always_use_v6); // Block of non-boolean flags. These are deprecated. Do not add more.