Skip to content

Commit

Permalink
proxy: add android proxy monitor (#2416)
Browse files Browse the repository at this point in the history
Description: Integrate existing upstream Envoy support for proxies (#21942) with Android APIs that are responsible for getting the information about the configured proxy settings from user's device. There are a few things that we will need to address before we fully productionize this - they are listed in envoyproxy/envoy-mobile#2533.
Risk Level: Medium, it's supposed to be a no-op if not enabled explicitly.
Testing: Manual and integration
Docs Changes: Done
Release Notes: Done

Signed-off-by: Rafal Augustyniak <[email protected]>
Signed-off-by: JP Simard <[email protected]>
  • Loading branch information
Augustyniak authored and jpsim committed Nov 29, 2022
1 parent 7112399 commit 871e6ca
Show file tree
Hide file tree
Showing 34 changed files with 890 additions and 26 deletions.
12 changes: 12 additions & 0 deletions mobile/docs/root/api/starting_envoy.rst
Original file line number Diff line number Diff line change
Expand Up @@ -514,6 +514,18 @@ to use IPv6. Note this is an experimental option and should be enabled with caut
builder.forceIPv6(true)


~~~~~~~~~~~~~~~~~~~~~~~~~~
``enableProxying``
~~~~~~~~~~~~~~~~~~~~~~~~~~
Specify whether to respect system Proxy settings when establishing connections.
Available on Andorid only.

**Example**::

// Kotlin
builder.enableProxying(true)


----------------------
Advanced configuration
----------------------
Expand Down
2 changes: 1 addition & 1 deletion mobile/docs/root/intro/version_history.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Bugfixes:

Features:

-
- kotlin: add a way to tell Envoy Mobile to respect system proxy settings by calling an ``enableProxying(true)`` method on the engine builder. (:issue:`#2416 <2416>`)


0.5.0 (September 2, 2022)
Expand Down
1 change: 1 addition & 0 deletions mobile/envoy_build_config/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ envoy_cc_library(
"@envoy//source/extensions/http/header_formatters/preserve_case:config",
"@envoy//source/extensions/stat_sinks/metrics_service:config",
"@envoy//source/extensions/stat_sinks/statsd:config",
"@envoy//source/extensions/transport_sockets/http_11_proxy:upstream_config",
"@envoy//source/extensions/transport_sockets/raw_buffer:config",
"@envoy//source/extensions/transport_sockets/tls:config",
"@envoy//source/extensions/transport_sockets/tls/cert_validator:cert_validator_lib",
Expand Down
3 changes: 3 additions & 0 deletions mobile/envoy_build_config/extension_registry.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "source/extensions/http/header_formatters/preserve_case/config.h"
#include "source/extensions/http/original_ip_detection/xff/config.h"
#include "source/extensions/stat_sinks/metrics_service/config.h"
#include "source/extensions/transport_sockets/http_11_proxy/config.h"
#include "source/extensions/transport_sockets/raw_buffer/config.h"
#include "source/extensions/transport_sockets/tls/cert_validator/default_validator.h"
#include "source/extensions/transport_sockets/tls/config.h"
Expand Down Expand Up @@ -59,6 +60,8 @@ void ExtensionRegistry::registerFactories() {
Envoy::Extensions::StatSinks::MetricsService::forceRegisterMetricsServiceSinkFactory();
Envoy::Extensions::TransportSockets::RawBuffer::forceRegisterUpstreamRawBufferSocketFactory();
Envoy::Extensions::TransportSockets::Tls::forceRegisterUpstreamSslSocketFactory();
Envoy::Extensions::TransportSockets::Http11Connect::
forceRegisterUpstreamHttp11ConnectSocketConfigFactory();
Envoy::Extensions::TransportSockets::Tls::forceRegisterDefaultCertValidatorFactory();
Envoy::Extensions::Upstreams::Http::Generic::forceRegisterGenericGenericConnPoolFactory();
Envoy::Upstream::forceRegisterLogicalDnsClusterFactory();
Expand Down
1 change: 1 addition & 0 deletions mobile/envoy_build_config/extensions_build_config.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ EXTENSIONS = {
"envoy.network.dns_resolver.getaddrinfo": "//source/extensions/network/dns_resolver/getaddrinfo:config",
"envoy.retry.options.network_configuration": "@envoy_mobile//library/common/extensions/retry/options/network_configuration:config",
"envoy.stat_sinks.metrics_service": "//source/extensions/stat_sinks/metrics_service:config",
"envoy.transport_sockets.http_11_proxy": "//source/extensions/transport_sockets/http_11_proxy:upstream_config",
"envoy.transport_sockets.raw_buffer": "//source/extensions/transport_sockets/raw_buffer:config",
"envoy.transport_sockets.tls": "//source/extensions/transport_sockets/tls:config",
"envoy.http.stateful_header_formatters.preserve_case": "//source/extensions/http/header_formatters/preserve_case:config",
Expand Down
1 change: 1 addition & 0 deletions mobile/examples/kotlin/hello_world/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class MainActivity : Activity() {

engine = AndroidEngineBuilder(application)
.addLogLevel(LogLevel.DEBUG)
.enableProxying(true)
.addPlatformFilter(::DemoFilter)
.addPlatformFilter(::BufferDemoFilter)
.addPlatformFilter(::AsyncDemoFilter)
Expand Down
52 changes: 32 additions & 20 deletions mobile/library/common/config/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -153,15 +153,19 @@ R"(
!ignore tls_socket_defs:
- &base_tls_socket
name: envoy.transport_sockets.tls
name: envoy.transport_sockets.http_11_proxy
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
common_tls_context:
tls_params:
tls_maximum_protocol_version: TLSv1_3
validation_context:
trusted_ca:
inline_string: *tls_root_certs
"@type": type.googleapis.com/envoy.extensions.transport_sockets.http_11_proxy.v3.Http11ProxyUpstreamTransport
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
common_tls_context:
tls_params:
tls_maximum_protocol_version: TLSv1_3
validation_context:
trusted_ca:
inline_string: *tls_root_certs
)";

const char* config_template = R"(
Expand Down Expand Up @@ -406,9 +410,13 @@ const char* config_template = R"(
lb_policy: CLUSTER_PROVIDED
cluster_type: *base_cluster_type
transport_socket:
name: envoy.transport_sockets.raw_buffer
name: envoy.transport_sockets.http_11_proxy
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.raw_buffer.v3.RawBuffer
"@type": type.googleapis.com/envoy.extensions.transport_sockets.http_11_proxy.v3.Http11ProxyUpstreamTransport
transport_socket:
name: envoy.transport_sockets.raw_buffer
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.raw_buffer.v3.RawBuffer
upstream_connection_options: *upstream_opts
circuit_breakers: *circuit_breakers_settings
typed_extension_protocol_options: *h1_protocol_options
Expand All @@ -422,17 +430,21 @@ const char* config_template = R"(
lb_policy: CLUSTER_PROVIDED
cluster_type: *base_cluster_type
transport_socket:
name: envoy.transport_sockets.tls
name: envoy.transport_sockets.http_11_proxy
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
common_tls_context:
alpn_protocols: [h2]
tls_params:
tls_maximum_protocol_version: TLSv1_3
validation_context:
trusted_ca:
inline_string: *tls_root_certs
trust_chain_verification: *trust_chain_verification
"@type": type.googleapis.com/envoy.extensions.transport_sockets.http_11_proxy.v3.Http11ProxyUpstreamTransport
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
common_tls_context:
alpn_protocols: [h2]
tls_params:
tls_maximum_protocol_version: TLSv1_3
validation_context:
trusted_ca:
inline_string: *tls_root_certs
trust_chain_verification: *trust_chain_verification
upstream_connection_options: *upstream_opts
circuit_breakers: *circuit_breakers_settings
typed_extension_protocol_options: *h2_protocol_options
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ envoy_cc_extension(
"@envoy//source/common/http:header_map_lib",
"@envoy//source/common/http:headers_lib",
"@envoy//source/common/http:utility_lib",
"@envoy//source/common/network:filter_state_proxy_info_lib",
"@envoy//source/extensions/filters/http/common:pass_through_filter_lib",
],
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@

#include "envoy/server/filter_config.h"

#include "source/common/network/filter_state_proxy_info.h"

namespace Envoy {
namespace Extensions {
namespace HttpFilters {
namespace NetworkConfiguration {

const Http::LowerCaseString AuthorityHeaderName{":authority"};

void NetworkConfigurationFilter::setDecoderFilterCallbacks(
Http::StreamDecoderFilterCallbacks& callbacks) {
ENVOY_LOG(debug, "NetworkConfigurationFilter::setDecoderFilterCallbacks");
Expand All @@ -26,6 +30,36 @@ void NetworkConfigurationFilter::setDecoderFilterCallbacks(
decoder_callbacks_->addUpstreamSocketOptions(options);
}

Http::FilterHeadersStatus
NetworkConfigurationFilter::decodeHeaders(Http::RequestHeaderMap& request_headers, bool) {
const auto proxy_settings = connectivity_manager_->getProxySettings();

ENVOY_LOG(trace, "NetworkConfigurationFilter::decodeHeaders", request_headers);
if (proxy_settings == nullptr) {
return Http::FilterHeadersStatus::Continue;
}

const auto proxy_address = proxy_settings->address();

if (proxy_address != nullptr) {
const auto authorityHeader = request_headers.get(AuthorityHeaderName);
if (authorityHeader.empty()) {
return Http::FilterHeadersStatus::Continue;
}

const auto authority = authorityHeader[0]->value().getStringView();

ENVOY_LOG(trace, "netconf_filter_set_proxy_for_request", proxy_settings->asString());
decoder_callbacks_->streamInfo().filterState()->setData(
Network::Http11ProxyInfoFilterState::key(),
std::make_unique<Network::Http11ProxyInfoFilterState>(authority, proxy_address),
StreamInfo::FilterState::StateType::ReadOnly,
StreamInfo::FilterState::LifeSpan::FilterChain);
}

return Http::FilterHeadersStatus::Continue;
}

Http::FilterHeadersStatus NetworkConfigurationFilter::encodeHeaders(Http::ResponseHeaderMap&,
bool) {
ENVOY_LOG(debug, "NetworkConfigurationFilter::encodeHeaders");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class NetworkConfigurationFilter final : public Http::PassThroughFilter,

// Http::StreamDecoderFilter
void setDecoderFilterCallbacks(Http::StreamDecoderFilterCallbacks& callbacks) override;
Http::FilterHeadersStatus decodeHeaders(Http::RequestHeaderMap& request_headers, bool) override;
// Http::StreamEncoderFilter
Http::FilterHeadersStatus encodeHeaders(Http::ResponseHeaderMap&, bool) override;
// Http::StreamFilterBase
Expand Down
16 changes: 16 additions & 0 deletions mobile/library/common/jni/jni_interface.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1132,6 +1132,22 @@ Java_io_envoyproxy_envoymobile_engine_JniLibrary_setPreferredNetwork(JNIEnv* env
static_cast<envoy_network_t>(network));
}

extern "C" JNIEXPORT jint JNICALL Java_io_envoyproxy_envoymobile_engine_JniLibrary_setProxySettings(
JNIEnv* env,
jclass, // class
jlong engine, jstring host, jint port) {
jni_log("[Envoy]", "setProxySettings");

const char* native_host = env->GetStringUTFChars(host, nullptr);
const uint16_t native_port = static_cast<uint16_t>(port);

envoy_status_t result =
set_proxy_settings(static_cast<envoy_engine_t>(engine), native_host, native_port);

env->ReleaseStringUTFChars(host, native_host);
return result;
}

bool jvm_cert_is_issued_by_known_root(JNIEnv* env, jobject result) {
jclass jcls_AndroidCertVerifyResult = env->FindClass("org/chromium/net/AndroidCertVerifyResult");
jmethodID jmid_isIssuedByKnownRoot =
Expand Down
7 changes: 7 additions & 0 deletions mobile/library/common/main_interface.cc
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ envoy_status_t set_preferred_network(envoy_engine_t engine, envoy_network_t netw
return ENVOY_SUCCESS;
}

envoy_status_t set_proxy_settings(envoy_engine_t e, const char* host, const uint16_t port) {
return Envoy::EngineHandle::runOnEngineDispatcher(
e,
[proxy_settings = Envoy::Network::ProxySettings::parseHostAndPort(host, port)](auto& engine)
-> void { engine.networkConnectivityManager().setProxySettings(proxy_settings); });
}

envoy_status_t record_counter_inc(envoy_engine_t e, const char* elements, envoy_stats_tags tags,
uint64_t count) {
return Envoy::EngineHandle::runOnEngineDispatcher(
Expand Down
10 changes: 10 additions & 0 deletions mobile/library/common/main_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,16 @@ envoy_status_t reset_stream(envoy_engine_t engine, envoy_stream_t stream);
*/
envoy_status_t set_preferred_network(envoy_engine_t engine, envoy_network_t network);

/**
* @brief Update the currently active proxy settings.
*
* @param engine, the engine whose proxy settings should be updated.
* @param host, the proxy host.
* @param port, the proxy port.
* @return envoy_status_t, the resulting status of the operation.
*/
envoy_status_t set_proxy_settings(envoy_engine_t engine, const char* host, const uint16_t port);

/**
* Increment a counter with the given elements and by the given count.
* @param engine, the engine that owns the counter.
Expand Down
1 change: 1 addition & 0 deletions mobile/library/common/network/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ envoy_cc_library(
hdrs = [
"android.h",
"connectivity_manager.h",
"proxy_settings.h",
],
copts = select({
"//bazel:include_ifaddrs": ["-DINCLUDE_IFADDRS"],
Expand Down
18 changes: 18 additions & 0 deletions mobile/library/common/network/connectivity_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,24 @@ envoy_netconf_t ConnectivityManager::setPreferredNetwork(envoy_network_t network
return network_state_.configuration_key_;
}

void ConnectivityManager::setProxySettings(ProxySettingsConstSharedPtr new_proxy_settings) {
if (proxy_settings_ == nullptr && new_proxy_settings != nullptr) {
ENVOY_LOG_EVENT(info, "netconf_proxy_change", new_proxy_settings->asString());
proxy_settings_ = new_proxy_settings;
} else if (proxy_settings_ != nullptr && new_proxy_settings == nullptr) {
ENVOY_LOG_EVENT(info, "netconf_proxy_change", "no_proxy_configured");
proxy_settings_ = new_proxy_settings;
} else if (proxy_settings_ != nullptr && new_proxy_settings != nullptr &&
*proxy_settings_ != *new_proxy_settings) {
ENVOY_LOG_EVENT(info, "netconf_proxy_change", new_proxy_settings->asString());
proxy_settings_ = new_proxy_settings;
}

return;
}

ProxySettingsConstSharedPtr ConnectivityManager::getProxySettings() { return proxy_settings_; }

envoy_network_t ConnectivityManager::getPreferredNetwork() {
Thread::LockGuard lock{network_state_.mutex_};
return network_state_.network_;
Expand Down
15 changes: 15 additions & 0 deletions mobile/library/common/network/connectivity_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "source/extensions/common/dynamic_forward_proxy/dns_cache.h"
#include "source/extensions/common/dynamic_forward_proxy/dns_cache_impl.h"

#include "library/common/network/proxy_settings.h"
#include "library/common/types/c_types.h"

/**
Expand Down Expand Up @@ -128,6 +129,12 @@ class ConnectivityManager
*/
envoy_netconf_t getConfigurationKey();

/**
*
* @return the current proxy settings.
*/
Envoy::Network::ProxySettingsConstSharedPtr getProxySettings();

/**
* Call to report on the current viability of the passed network configuration after an attempt
* at transmission (e.g., an HTTP request).
Expand All @@ -143,6 +150,13 @@ class ConnectivityManager
*/
static envoy_netconf_t setPreferredNetwork(envoy_network_t network);

/**
* @brief Sets the current proxy settings.
*
* @param host The proxy settings. `nullptr` if there is no proxy configured on a device.
*/
void setProxySettings(ProxySettingsConstSharedPtr proxy_settings);

/**
* Configure whether connections should be drained after a triggered DNS refresh. Currently this
* may happen either due to an external call to refreshConnectivityState or an update to
Expand Down Expand Up @@ -211,6 +225,7 @@ class ConnectivityManager
dns_callbacks_handle_{nullptr};
Upstream::ClusterManager& cluster_manager_;
DnsCacheManagerSharedPtr dns_cache_manager_;
ProxySettingsConstSharedPtr proxy_settings_;
static NetworkState network_state_;
};

Expand Down
Loading

0 comments on commit 871e6ca

Please sign in to comment.