Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stream info: cleanup address handling #14432

Merged
merged 17 commits into from
Jan 7, 2021
Merged

Conversation

mattklein123
Copy link
Member

Consolidate all downstream address handling setting into a single
function. Also remove duplicate setting in the connection handler.
This should make this logic less error prone than it was previously.

Fixes #14133

Risk Level: Low
Testing: Existing tests
Docs Changes: N/A
Release Notes: N/A
Platform Specific Features: N/A

Consolidate all downstream address handling setting into a single
function. Also remove duplicate setting in the connection handler.
This should make this logic less error prone than it was previously.

Fixes #14133

Signed-off-by: Matt Klein <mklein@lyft.com>
@mattklein123
Copy link
Member Author

/retest

@repokitteh-read-only
Copy link

Retrying Azure Pipelines:
Retried failed jobs in: envoy-presubmit

🐱

Caused by: a #14432 (comment) was created by @mattklein123.

see: more, trace.

Copy link
Contributor

@ggreenway ggreenway left a comment

Choose a reason for hiding this comment

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

I really like the approach. This cleans things up quite a bit.

source/common/stream_info/stream_info_impl.h Outdated Show resolved Hide resolved
source/server/connection_handler_impl.h Show resolved Hide resolved
Signed-off-by: Matt Klein <mklein@lyft.com>
Signed-off-by: Matt Klein <mklein@lyft.com>
Signed-off-by: Matt Klein <mklein@lyft.com>
@mattklein123
Copy link
Member Author

@ggreenway I pushed a partial change which implements a variant of your suggestion which is to fundamentally fix the problem by having an address provider that we pass around via shared_ptr so it's not possible for anything to get out of date. I like this solution, but it's a lot of work so I don't want to spend more time on fixing all the tests and various pieces of code unless you agree with the direction. Also, there is a small downside of an extra shared_ptr allocation per connection, and there will be another one on top of that for HTTP connections that change remote address due to XFF (to have a provider that wraps the original). IMO this is worth it given the severity of possible bugs in this area, but let me know what you think!

@mattklein123 mattklein123 added the no stalebot Disables stalebot from closing an issue label Dec 21, 2020
@ggreenway
Copy link
Contributor

I like that the connection and streaminfo addresses are combined.

I'm not sure I like that the http streaminfo and connection streaminfo sometimes share an address. If XFF has a different address than the connection remoteAddress, the http streaminfo will need to replace it's addressprovider.

Given that the http and connection addresses aren't necessarily the same, I think it may make sense for the http streaminfo to get a one-time copy of the addresses in the connection streaminfo when it is constructed, and from there are be separate/uncoupled.

@mattklein123
Copy link
Member Author

We discussed ^ offline and my plan is to make a special version of StreamInfo, OverridableAddressStrreamInfo, or whatever, that implements SocketAddressProvider and also has a setDownstreamAddress function. Then, the overriding will happen in that stream info and pass through otherwise. I think it will be pretty clean. It can be self contained to the HCM code.

Signed-off-by: Matt Klein <mklein@lyft.com>
Signed-off-by: Matt Klein <mklein@lyft.com>
@mattklein123
Copy link
Member Author

@ggreenway I need to take another pass over this but I think this should be ready for review. Sorry for the size of the change but I think it's the right thing to do. It should mostly be a mechanical review.

@mattklein123
Copy link
Member Author

@ggreenway I went over the change again and I'm happy with it. I don't think tidy is doing to pass given the size of the change. No rush on reviewing.

Copy link
Contributor

@ggreenway ggreenway 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 great overall! A couple minor nits, but the approach looks good, and this cleaned up the source of bugs.

source/common/http/filter_manager.h Outdated Show resolved Hide resolved
include/envoy/network/socket.h Outdated Show resolved Hide resolved
Signed-off-by: Matt Klein <mklein@lyft.com>
@mattklein123
Copy link
Member Author

@ggreenway updated PTAL

ggreenway
ggreenway previously approved these changes Jan 6, 2021
Copy link
Contributor

@ggreenway ggreenway left a comment

Choose a reason for hiding this comment

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

LGTM.

This will give your github stats a nice boost.

Signed-off-by: Matt Klein <mklein@lyft.com>
@mattklein123
Copy link
Member Author

@ggreenway I had to fix a merge conflict so I will need another review. cc @KBaichoo see last commit.

@mattklein123 mattklein123 merged commit 659f2ea into master Jan 7, 2021
@mattklein123 mattklein123 deleted the stream_info_cleanups branch January 7, 2021 17:20
mpuncel added a commit to mpuncel/envoy that referenced this pull request Jan 8, 2021
* master: (48 commits)
  Resolve 14506, avoid libidn2 for our curl dependency (envoyproxy#14601)
  fix new/free mismatch in Mainthread utility (envoyproxy#14596)
  opencensus: deprecate Zipkin configuration. (envoyproxy#14576)
  upstream: clean up code location (envoyproxy#14580)
  configuration impl: add cast for ios compilation (envoyproxy#14590)
  buffer impl: add cast for android compilation (envoyproxy#14589)
  ratelimit: add dynamic metadata to ratelimit response (envoyproxy#14508)
  tcp_proxy: wait for CONNECT response before start streaming data (envoyproxy#14317)
  stream info: cleanup address handling (envoyproxy#14432)
  [deps] update upb to latest commit (envoyproxy#14582)
  Add utility to check whether the execution is in main thread. (envoyproxy#14457)
  listener: undeprecate bind_to_port (envoyproxy#14480)
  Fix data race in overload integration test (envoyproxy#14586)
  deps: update PGV (envoyproxy#14571)
  dependencies: update cve_scan.py for some libcurl 7.74.0 false positives. (envoyproxy#14572)
  Network::Connection: Add L4 crash dumping support (envoyproxy#14509)
  ssl: remember stat names for configured ciphers. (envoyproxy#14534)
  formatter: add custom date formatting to downstream cert start and end dates (envoyproxy#14502)
  feat(lua): allow setting response body when the upstream response body is empty (envoyproxy#14486)
  Generalize the gRPC access logger base classes (envoyproxy#14469)
  ...

Signed-off-by: Michael Puncel <mpuncel@squareup.com>
@rgs1
Copy link
Member

rgs1 commented Jan 8, 2021

@mattklein123 so OverridableRemoteSocketAddressSetterStreamInfo isn't visible to filters? I have a filter where we do decoder_callbacks_->streamInfo().setDownstreamRemoteAddress() so that the ip tagging filter can then do the proper thing (XFF is broken for us)... Was the idea to lock things up so filters can't call setDownstreamoRemoteAddress() anymore?

@mattklein123
Copy link
Member Author

@rgs1 and I just had a really long convo on Slack about ^. @rgs1 after you digest can you circle back with the proposed plan?

@rgs1
Copy link
Member

rgs1 commented Jan 11, 2021

Ok, so circling back.

Our options are:

  1. we can add an extension system or hook for detecting and populating the downstream remote address (in the spirit of request_id_utils: add new extension system #10429). With this, we could push our logic into the early stage of the HCM so that it can happen before the other stuff that relies on IP detection (e.g.: header sanitation).
  2. we can extend the ip tagging filter to have it lookup the remote ip from a header, instead of relying on stream info (ditto for our internal filters). This is somewhat elegant, given that upstream services rely on a header for this already. But requires some juggling to roll this out.
  3. we can accrue some tech debt and reinsert back setDownstreamRemoteAddress() into StreamInfo, while we make 1) or 2) happen.

I really wanted to avoid 3), given the work that's gone into cleaning up StreamInfo but after some thought I think I'd prefer to send a PR to get that going. 1) is the most correct approach, but I don't have the immediate cycles for that. 2) is easier but requires some juggling in terms of rollout so the time doing that is probably better spent doing 1).

So how about:

  • I send a PR for 3) with a big TODO comment that 1) needs to happen
  • I start working on 1) in the background with a goal of getting land somewhere in Q1

Thoughts?

rgs1 pushed a commit to rgs1/envoy that referenced this pull request Jan 11, 2021
This allows us to do a dynamic_cast<Http::OverridableRemoteSocketAddressSetterStreamInfo>
and be able to call setDownstreamRemoteAddress() from our filter.

See:

envoyproxy#14432 (comment)

Signed-off-by: Raul Gutierrez Segales <rgs@pinterest.com>
@rgs1
Copy link
Member

rgs1 commented Jan 11, 2021

Ok with #14633 we can do this from our filter:

+    //
+    // Hack: this is workaround to:
+    //
+    // https://github.com/envoyproxy/envoy/pull/14432#issuecomment-758004199
+    //
+    // We need the dynamic_cast to be able to set the downstream remote address _and_
+    // we need the catch std::bad_cast because the cast fails during tests because
+    // of the mocked decoder callbacks. Sigh.
+    try {
+      auto& stream_info = dynamic_cast<Http::OverridableRemoteSocketAddressSetterStreamInfo&>(
+          decoder_callbacks_->streamInfo());
+      stream_info.setDownstreamRemoteAddress(
+          Network::Utility::parseInternetAddress(trusted_client_ip_));
+    } catch (std::bad_cast&) {
+    }

I am not massively proud, but it probably works.

@mattklein123
Copy link
Member Author

Yeah per offline convo I think that is your best bet until we get something better implemented for you.

rgs1 pushed a commit to rgs1/envoy that referenced this pull request Jan 28, 2021
This is a follow-up to:

envoyproxy#14432 (comment)

After that PR, it's no longer possible (unless you do a dynamic_cast)
to set the remote address from a filter. This is something that we
need to do because we have specialized logic for this (XFF doesn't
work for us).

So this adds an extension point which will allow us to push that logic
down to ConnectionManagerUtility::mutateRequestHeaders() where it
belongs.

Signed-off-by: Raul Gutierrez Segales <rgs@pinterest.com>
htuch pushed a commit that referenced this pull request May 16, 2021
This is a follow-up to:

#14432 (comment)

After that PR, it's no longer possible (unless you do a dynamic_cast)
to set the remote address from a filter. This is something that we
need to do because we have specialized logic for this (XFF doesn't
work for us).

So this adds an extension point which will allow us to push that logic
down to ConnectionManagerUtility::mutateRequestHeaders() where it
belongs.

Signed-off-by: Raul Gutierrez Segales <rgs@pinterest.com>
ntgsx92 pushed a commit to ntgsx92/envoy that referenced this pull request May 18, 2021
This is a follow-up to:

envoyproxy#14432 (comment)

After that PR, it's no longer possible (unless you do a dynamic_cast)
to set the remote address from a filter. This is something that we
need to do because we have specialized logic for this (XFF doesn't
work for us).

So this adds an extension point which will allow us to push that logic
down to ConnectionManagerUtility::mutateRequestHeaders() where it
belongs.

Signed-off-by: Raul Gutierrez Segales <rgs@pinterest.com>
Signed-off-by: Sixiang Gu <sgu@twitter.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
no stalebot Disables stalebot from closing an issue
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Audit handling of addresses when listener filters (proxy protocol, etc) modify it
3 participants