Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion envoy
Submodule envoy updated 738 files
2 changes: 2 additions & 0 deletions library/common/engine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "library/common/bridge/utility.h"
#include "library/common/config/internal.h"
#include "library/common/data/utility.h"
#include "library/common/network/android.h"
#include "library/common/stats/utility.h"

namespace Envoy {
Expand Down Expand Up @@ -104,6 +105,7 @@ envoy_status_t Engine::main(const std::string config, const std::string log_leve

network_configurator_ =
Network::ConfiguratorFactory{server_->serverFactoryContext()}.get();
Envoy::Network::Android::Utility::setAlternateGetifaddrs();
auto v4_interfaces = network_configurator_->enumerateV4Interfaces();
auto v6_interfaces = network_configurator_->enumerateV6Interfaces();
logInterfaces("netconf_get_v4_interfaces", v4_interfaces);
Expand Down
2 changes: 1 addition & 1 deletion library/common/http/header_utility.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ RequestHeaderMapPtr toRequestHeaders(envoy_headers headers) {
auto transformed_headers = RequestHeaderMapImpl::create();
transformed_headers->setFormatter(
std::make_unique<
Extensions::Http::HeaderFormatters::PreserveCase::PreserveCaseHeaderFormatter>());
Extensions::Http::HeaderFormatters::PreserveCase::PreserveCaseHeaderFormatter>(false));
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To account for envoyproxy/envoy#18997

Considering it's designed to be off by default, I imagine that we can disable it for our use cases until we have reason to do otherwise.

toEnvoyHeaders(*transformed_headers, headers);
return transformed_headers;
}
Expand Down
6 changes: 5 additions & 1 deletion library/common/network/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ envoy_cc_library(
name = "configurator_lib",
srcs = [
"configurator.cc",
"android.cc",
] + select({
"//bazel:include_ifaddrs": [
"//third_party:android/ifaddrs-android.h",
Expand All @@ -16,7 +17,10 @@ envoy_cc_library(
],
"//conditions:default": [],
}),
hdrs = ["configurator.h"],
hdrs = [
"android.h",
"configurator.h",
],
copts = select({
"//bazel:include_ifaddrs": ["-DINCLUDE_IFADDRS"],
"//conditions:default": [],
Expand Down
78 changes: 78 additions & 0 deletions library/common/network/android.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#include "library/common/network/android.h"

#include <net/if.h>

#include "envoy/common/platform.h"

#include "source/common/api/os_sys_calls_impl.h"
#include "source/common/common/assert.h"
#include "source/common/common/scalar_to_byte_vector.h"
#include "source/common/common/utility.h"
#include "source/common/network/addr_family_aware_socket_option_impl.h"
#include "source/common/network/address_impl.h"
#include "source/extensions/common/dynamic_forward_proxy/dns_cache_manager_impl.h"

#include "library/common/network/src_addr_socket_option_impl.h"

namespace Envoy {
namespace Network {
namespace Android {
namespace Utility {

#if defined(INCLUDE_IFADDRS)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wold-style-cast"
namespace {
#include "third_party/android/ifaddrs-android.h"
}
#pragma clang diagnostic pop
#endif

void setAlternateGetifaddrs() {
#if defined(INCLUDE_IFADDRS)
auto& os_syscalls = Api::OsSysCallsSingleton::get();
ENVOY_BUG(!os_syscalls.supportsGetifaddrs(),
"setAlternateGetifaddrs should only be called when supportsGetifaddrs is false");

Api::AlternateGetifaddrs android_getifaddrs =
[](Api::InterfaceAddressVector& interfaces) -> Api::SysCallIntResult {
struct ifaddrs* ifaddr;
struct ifaddrs* ifa;

const int rc = getifaddrs(&ifaddr);
if (rc == -1) {
return {rc, errno};
}

for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == nullptr) {
continue;
}

if (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6) {
const sockaddr_storage* ss = reinterpret_cast<sockaddr_storage*>(ifa->ifa_addr);
size_t ss_len =
ifa->ifa_addr->sa_family == AF_INET ? sizeof(sockaddr_in) : sizeof(sockaddr_in6);
StatusOr<Address::InstanceConstSharedPtr> address =
Address::addressFromSockAddr(*ss, ss_len, ifa->ifa_addr->sa_family == AF_INET6);
if (address.ok()) {
interfaces.emplace_back(ifa->ifa_name, ifa->ifa_flags, *address);
}
}
}

if (ifaddr) {
freeifaddrs(ifaddr);
}

return {rc, 0};
};

os_syscalls.setAlternateGetifaddrs(android_getifaddrs);
#endif
}

} // namespace Utility
} // namespace Android
} // namespace Network
} // namespace Envoy
15 changes: 15 additions & 0 deletions library/common/network/android.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

namespace Envoy {
namespace Network {
namespace Android {
namespace Utility {
/**
* Sets an alternate `getifaddrs` implementation than the one defined
* in Envoy by default.
*/
void setAlternateGetifaddrs();
} // namespace Utility
} // namespace Android
} // namespace Network
} // namespace Envoy
48 changes: 15 additions & 33 deletions library/common/network/configurator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "envoy/common/platform.h"

#include "source/common/api/os_sys_calls_impl.h"
#include "source/common/common/assert.h"
#include "source/common/common/scalar_to_byte_vector.h"
#include "source/common/common/utility.h"
Expand Down Expand Up @@ -49,10 +50,6 @@

#define DEFAULT_IP_TTL 64

#ifdef SUPPORTS_GETIFADDRS
#include <ifaddrs.h>
#endif

// Prefixes used to prefer well-known interface names.
#if defined(__APPLE__)
constexpr absl::string_view WlanPrefix = "en";
Expand All @@ -69,16 +66,6 @@ constexpr absl::string_view WwanPrefix = "";
namespace Envoy {
namespace Network {

#if !defined(SUPPORTS_GETIFADDRS) && defined(INCLUDE_IFADDRS)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my version of this work I had then created a network/android/utility namespace where I created a function that sets the android getifaddrs impl. Then I called that function early in the engine's lifecycle before the network configurator is constructed.

This was my implementation:

#include "library/common/network/utility.h"

#include "source/common/api/os_sys_calls_impl.h"
#include "source/common/network/address_impl.h"

namespace Envoy {
namespace Network {
namespace Android {
namespace Utility {

#if defined(INCLUDE_ANDROID_IFADDRS)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wold-style-cast"
namespace {
#include "third_party/android/ifaddrs-android.h"
}
#pragma clang diagnostic pop
#endif

/**
 */
void setAlternateGetifaddrs() {
#if defined(INCLUDE_ANDROID_IFADDRS)
  auto& os_syscalls = Api::OsSysCallsSingleton::get();
  if (!os_syscalls.supportsGetifaddrs()) {
    Api::AlternateGetifaddrs android_getifaddrs =
        [](Api::InterfaceAddressVector& interfaces) -> Api::SysCallIntResult {
      struct ifaddrs* ifaddr;
      struct ifaddrs* ifa;

      const int rc = getifaddrs(&ifaddr);
      if (rc == -1) {
        return {rc, errno};
      }

      for (ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
        if (ifa->ifa_addr == nullptr) {
          continue;
        }

        if (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6) {
          const sockaddr_storage* ss = reinterpret_cast<sockaddr_storage*>(ifa->ifa_addr);
          size_t ss_len =
              ifa->ifa_addr->sa_family == AF_INET ? sizeof(sockaddr_in) : sizeof(sockaddr_in6);
          StatusOr<Address::InstanceConstSharedPtr> address =
              Address::addressFromSockAddr(*ss, ss_len, ifa->ifa_addr->sa_family == AF_INET6);
          if (address.ok()) {
            interfaces.emplace_back(ifa->ifa_name, ifa->ifa_flags, *address);
          }
        }
      }

      if (ifaddr) {
        freeifaddrs(ifaddr);
      }

      return {rc, 0};
    };

    os_syscalls.setAlternateGetifaddrs(android_getifaddrs);
  } else {
    // FIXME: assert that this function is not called more than once?
  }
#endif
}

} // namespace Utility
} // namespace Android
} // namespace Network
} // namespace Envoy

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for saving me the trouble of writing this 😄

I've pushed it up with minor modifications and addressing the TODO in eb6a57b. I'm working on running the Android sample app locally to confirm this works.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've confirmed that this ifaddrs implementation is used on Android by manually adding logs and confirming they're emitted when running the sample app locally.

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wold-style-cast"
namespace {
#include "third_party/android/ifaddrs-android.h"
}
#pragma clang diagnostic pop
#define SUPPORTS_GETIFADDRS
#endif

SINGLETON_MANAGER_REGISTRATION(network_configurator);

constexpr absl::string_view BaseDnsCache = "base_dns_cache";
Expand Down Expand Up @@ -329,33 +316,28 @@ Configurator::enumerateInterfaces([[maybe_unused]] unsigned short family,
[[maybe_unused]] unsigned int reject_flags) {
std::vector<InterfacePair> pairs{};

#ifdef SUPPORTS_GETIFADDRS
struct ifaddrs* interfaces = nullptr;
struct ifaddrs* ifa = nullptr;
if (!Api::OsSysCallsSingleton::get().supportsGetifaddrs()) {
return pairs;
}

const int rc = getifaddrs(&interfaces);
RELEASE_ASSERT(!rc, "getifaddrs failed");
Api::InterfaceAddressVector interface_addresses{};
const Api::SysCallIntResult rc = Api::OsSysCallsSingleton::get().getifaddrs(interface_addresses);
RELEASE_ASSERT(!rc.return_value_, fmt::format("getiffaddrs error: {}", rc.errno_));

for (ifa = interfaces; ifa != nullptr; ifa = ifa->ifa_next) {
if (!ifa->ifa_addr || ifa->ifa_addr->sa_family != family) {
continue;
}
if ((ifa->ifa_flags & (select_flags ^ reject_flags)) != select_flags) {
for (const auto& interface_address : interface_addresses) {
const auto family_version = family == AF_INET ? Envoy::Network::Address::IpVersion::v4
: Envoy::Network::Address::IpVersion::v6;
if (interface_address.interface_addr_->ip()->version() != family_version) {
continue;
}

const sockaddr_storage* ss = reinterpret_cast<sockaddr_storage*>(ifa->ifa_addr);
size_t ss_len = family == AF_INET ? sizeof(sockaddr_in) : sizeof(sockaddr_in6);
StatusOr<Address::InstanceConstSharedPtr> address =
Address::addressFromSockAddr(*ss, ss_len, family == AF_INET6);
if (!address.ok()) {
if ((interface_address.interface_flags_ & (select_flags ^ reject_flags)) != select_flags) {
continue;
}
pairs.push_back(std::make_pair(std::string{ifa->ifa_name}, *address));
}

freeifaddrs(interfaces);
#endif // SUPPORTS_GETIFADDRS
pairs.push_back(
std::make_pair(interface_address.interface_name_, interface_address.interface_addr_));
}

return pairs;
}
Expand Down
4 changes: 2 additions & 2 deletions test/common/integration/client_integration_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Http::ResponseHeaderMapPtr toResponseHeaders(envoy_headers headers) {
Http::ResponseHeaderMapImpl::create();
transformed_headers->setFormatter(
std::make_unique<
Extensions::Http::HeaderFormatters::PreserveCase::PreserveCaseHeaderFormatter>());
Extensions::Http::HeaderFormatters::PreserveCase::PreserveCaseHeaderFormatter>(false));
Http::Utility::toEnvoyHeaders(*transformed_headers, headers);
return transformed_headers;
}
Expand Down Expand Up @@ -335,7 +335,7 @@ TEST_P(ClientIntegrationTest, CaseSensitive) {
Http::TestRequestHeaderMapImpl headers{{"FoO", "bar"}};
headers.header_map_->setFormatter(
std::make_unique<
Extensions::Http::HeaderFormatters::PreserveCase::PreserveCaseHeaderFormatter>());
Extensions::Http::HeaderFormatters::PreserveCase::PreserveCaseHeaderFormatter>(false));
headers.header_map_->formatter().value().get().processKey("FoO");
HttpTestUtility::addDefaultHeaders(headers);
envoy_headers c_headers = Http::Utility::toBridgeHeaders(headers);
Expand Down
1 change: 1 addition & 0 deletions test/common/network/configurator_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ TEST_F(ConfiguratorTest, ReportNetworkUsageDisregardsCallsWithStaleConfiguration
TEST_F(ConfiguratorTest, EnumerateInterfacesFiltersByFlags) {
// Select loopback.
auto loopbacks = configurator_->enumerateInterfaces(AF_INET, IFF_LOOPBACK, 0);
EXPECT_EQ(loopbacks.size(), 1);
EXPECT_EQ(std::get<const std::string>(loopbacks[0]).rfind("lo", 0), 0);

// Reject loopback.
Expand Down