Skip to content

Adding direct connect support.#21942

Merged
alyssawilk merged 15 commits intoenvoyproxy:mainfrom
alyssawilk:dfp
Jul 11, 2022
Merged

Adding direct connect support.#21942
alyssawilk merged 15 commits intoenvoyproxy:mainfrom
alyssawilk:dfp

Conversation

@alyssawilk
Copy link
Contributor

Creates a transport socket for HTP/1.1 proxy support.

With the combination of the transport socket, and a filter putting the proxy stream info in place this will

  1. redirect TCP connections to the proxy IP address
  2. prefix TLS connections with cleartext CONECT headers to the destination host, and strip CONNECT response
  3. change cleartext HTTP/1.1 to send fully qualified URLs

Risk Level: medium (intended as a no op but it does have data plane refactory)
Testing: new unit, integration tests
Docs Changes: n/a

Part of envoyproxy/envoy-mobile#1622

Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
@repokitteh-read-only
Copy link

As a reminder, PRs marked as draft will not be automatically assigned reviewers,
or be handled by maintainer-oncall triage.

Please mark your PR as ready when you want it to be reviewed!

🐱

Caused by: #21942 was opened by alyssawilk.

see: more, trace.

@alyssawilk alyssawilk marked this pull request as ready for review June 29, 2022 14:31
@repokitteh-read-only
Copy link

CC @envoyproxy/api-shepherds: Your approval is needed for changes made to (api/envoy/|docs/root/api-docs/).
envoyproxy/api-shepherds assignee is @mattklein123
CC @envoyproxy/api-watchers: FYI only for changes made to (api/envoy/|docs/root/api-docs/).

🐱

Caused by: #21942 was opened by alyssawilk.

see: more, trace.

Copy link
Contributor

@RyanTheOptimist RyanTheOptimist left a comment

Choose a reason for hiding this comment

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

This looks amazing! A couple of legit comments but mostly just nits.

/**
* @return any proxy information if sending to an intermediate proxy over HTTP/1.1.
*/
virtual const std::unique_ptr<const ProxyInfo>& proxyInfo() const PURE;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not keep this private to the extension? E.g. per #21700, would be another private hashable object.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think it can be because Envoy needs to use it for hashing and connection creation.

Copy link
Contributor

Choose a reason for hiding this comment

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

These objects are also hashed in transport options and passed along during connection creation to the upstream connection stream info. Maybe I'm missing something?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I see how I could handle hashing but I don't see how I could handle the createConnection in
source/common/upstream/upstream_impl.cc properly without explicit visibility of the addresses?

Copy link
Contributor

Choose a reason for hiding this comment

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

I see. I suppose we could split the two since address() override seems more generic than CONNECT (you could do passthrough and all sorts of things with it), but it's up to you.

Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
Copy link
Contributor

@RyanTheOptimist RyanTheOptimist left a comment

Choose a reason for hiding this comment

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

LGTM, though it looks like this needs a main merge. I'm also curious if the proxy info should be added to the TransportSocketOption's hashKey() computation?

}

Network::IoResult UpstreamHttp11ConnectSocket::doWrite(Buffer::Instance& buffer, bool end_stream) {
if (header_buffer_.length() > 0) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Oh, whoops. I missed that. Follow up is fine, or leave alone.

Network::IoResult UpstreamHttp11ConnectSocket::doRead(Buffer::Instance& buffer) {
if (!stripped_connect_) {
char peek_buf[200];
auto result = callbacks_->ioHandle().recv(peek_buf, 200, MSG_PEEK);
Copy link
Contributor

Choose a reason for hiding this comment

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

Ah! Looks like it's ABSL_ARRAYSIZE() now. but const is great.

Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
@alyssawilk
Copy link
Contributor Author

/wait on docs

if (!request_headers.get(connect_proxy).empty()) {
std::string address_string(request_headers.get(connect_proxy)[0]->value().getStringView());
auto address = Network::Utility::parseInternetAddressAndPort(address_string);
decoder_callbacks_->streamInfo().filterState()->setData(
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if we could use LbEndpoint itself somehow to determine the proxy address. In our case, each endpoint has an assigned proxy, and the proxy address is inside the endpoint metadata. I'm not sure how we'd make it work with a downstream filter.

Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
RyanTheOptimist
RyanTheOptimist previously approved these changes Jul 6, 2022
Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
@alyssawilk
Copy link
Contributor Author

yeah I was trying to stay quiet until we'd had a chance to test downstream for E-M and work out the kinks, but alpha is enough of a warning I suppose.

Comment on lines +20 to +21
// If this is configured and an intermediate filter adds the data necessary for
// proxying to the stream info then
Copy link
Member

Choose a reason for hiding this comment

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

What filter does this? How do I configure it? I guess from an end user perspective it's not clear to me what I need to do?

Copy link
Contributor Author

@alyssawilk alyssawilk Jul 7, 2022

Choose a reason for hiding this comment

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

yeah this is why I didn't want to do genreal Envoy docs for it for it as it's written for a very narrow use case. I suspect it will get extended to be general purpose over time but right now, the goal is to provide the infrastructure for E-M sending data through the local android proxy (envoyproxy/envoy-mobile#1622) The E-M filter will query Android for the address and port of the proxy, then add that information to the stream info filter state so it can be used to redirect the connection and alter the payload going to the proxy.
I'm super happy to put these details in the proto but I've been repeatedly chided by @markdroth for putting too much Envoy information in what is supposed to be generic protos. Given this one is Envoy-only maybe it's OK to add more detail there? But this really isn't intended for generic Envoy use so much as Envoy Mobile. I could also land the proto and extension in E-M but then I can't test any of the changes to core Envoy required to make it all hang together. And realistically at some point someone's going to add config to make it usable since folks hate the loopback proxy solution. Happy to take your advice on how to proceed here or on slack.

Copy link
Member

Choose a reason for hiding this comment

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

OK I see. I don't know maybe then just make it a bit more clear in the docs that this is EM specific right now and can be extended later?

I get the concern about Envoy specific info in the protos, but IMO 1st priority is documentation. We need to sort out the per client docs separately which is a known issue.

Signed-off-by: Alyssa Wilk <alyssar@chromium.org>
Copy link
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

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

Cool, thanks!

@repokitteh-read-only repokitteh-read-only bot removed the api label Jul 7, 2022
@alyssawilk alyssawilk enabled auto-merge (squash) July 7, 2022 21:00
@alyssawilk
Copy link
Contributor Author

/retest

@repokitteh-read-only
Copy link

Retrying Azure Pipelines:
Check envoy-presubmit isn't fully completed, but will still attempt retrying.
Retried failed jobs in: envoy-presubmit

🐱

Caused by: a #21942 (comment) was created by @alyssawilk.

see: more, trace.

@alyssawilk alyssawilk merged commit 095f4ca into envoyproxy:main Jul 11, 2022
@moderation
Copy link
Contributor

Does this PR mean you can implement something like #11569 (comment) but without the need to use a loopback?

@alyssawilk
Copy link
Contributor Author

Not yet, but it's possible to get there pretty easily. Right now the transport socket will CONNECT encapsulate for https only (HTTP proxies just need fully qualified URLs) and only if some intermediate filter tells it where to proxy to. We could add an optional configuration option so in the absence of said intermediate filter, it would proxy to some hard-coded location pretty easily. If you want it, lmk and I can add it.
For android we don't know the location up front so we want it added by a filter ,and I didn't want to add other use cases without users.

@alyssawilk
Copy link
Contributor Author

Also only works for HTTP/1.1 if not blatantly obvious from naming. H2 is too complicatd to do inline so requires the loopback/internal-listener pass

@kyessenov
Copy link
Contributor

@moderation I think adding some well-known metadata in endpoints would be an alternate way to find a tunnel address. That's what we've been doing for H2 tunneling with the internal listener. I think this is probably the right long term evolution away from internal listeners, but the problem is that transport sockets need to support multiplexing (1 to many for downstream, many to 1 for upstream), and right now they are basically one-to-one with TCP streams.

@moderation
Copy link
Contributor

Thanks @alyssawilk and @kyessenov

mum4k pushed a commit to envoyproxy/nighthawk that referenced this pull request Jul 13, 2022
- Update the ENVOY_COMMIT and ENVOY_SHA in [bazel/repositories.bzl](https://github.com/envoyproxy/nighthawk/blob/main/bazel/repositories.bzl) to the latest Envoy's commit.
- Update the `CodecClientProd` instantiation to accommodate the recent changes introduced by envoyproxy/envoy#21942.
- Temporarily disable `test_gcc` which fails the CI.  See #872 for more details.

Disclaimer: The CI pipeline was blocked due to a machine level breakage. All local tests passed.

Signed-off-by: jiajunye [jiajunye@google.com](mailto:jiajunye@google.com)
Augustyniak added a commit to envoyproxy/envoy-mobile that referenced this pull request Sep 20, 2022
Description: Integrate existing upstream Envoy support for proxies (envoyproxy/envoy#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 #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 <raugustyniak@lyft.com>
colibie pushed a commit to colibie/envoy-mobile that referenced this pull request Sep 21, 2022
Description: Integrate existing upstream Envoy support for proxies (envoyproxy/envoy#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#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 <raugustyniak@lyft.com>
Signed-off-by: Chidera Olibie <colibie@google.com>
jpsim pushed a commit that referenced this pull request Nov 29, 2022
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 <raugustyniak@lyft.com>
Signed-off-by: JP Simard <jp@jpsim.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants