-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
filters: http original src filter #6790
Conversation
We'll want to use this option for both the http and the listener filter. Bring it out into a common library. Signed-off-by: Kyle Larose <kyle@agilicus.com>
Signed-off-by: Kyle Larose <kyle@agilicus.com>
The original source filter is now all hooked up, but it has some problems -- namely, it sets options on the downstream connection's socket, which is wrong. Signed-off-by: Kyle Larose <kyle@agilicus.com>
We need these to configure per-request socket options from the http filters. Signed-off-by: Kyle Larose <kyle@agilicus.com>
- Hook in to new callback options mechanism - add ut Signed-off-by: Kyle Larose <kyle@agilicus.com>
Signed-off-by: Kyle Larose <kyle@agilicus.com>
We use the existing mechanism used to pass socket options to the connection pool creation logic to pass the upstream socket options. We do this by creating a new socket options object, then placing both sets of socket options into it. Signed-off-by: Kyle Larose <kyle@agilicus.com>
The active stream is what's shared between the various filters. Push the options up to it so they're actually shared! Signed-off-by: Kyle Larose <kyle@agilicus.com>
Signed-off-by: Kyle Larose <kyle@agilicus.com>
Signed-off-by: Kyle Larose <kyle@agilicus.com>
- build - docs Signed-off-by: Kyle Larose <kyle@agilicus.com>
Signed-off-by: Kyle Larose <kyle@agilicus.com>
Signed-off-by: Kyle Larose <kyle@agilicus.com>
@snowp can you have a look? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looked over the source/ bits, looks good for the most part.
I think it would be good to split up the changes made to the core code (ie the new filter callbacks) and the changes made to extensions if possible, should make this a bit easier to review
@snowp Thanks for the review. Would you suggest I close this, then post two new ones broken up as you suggested? The extension code will depend on the new filter code. I'm guessing for things to work out I'll likely need to wait for the first PR (the new filter code) to finish before posting the second (the extension code)? |
Given the dependency it might make sense to keep this up and just put up a smaller PR with the router changes. You can then merge in the changes once they land on master into this PR (this is how changes were split out and merged back into #6228 for example). |
Got it. I'll do that. Thanks for the suggestion. |
🔨 rebuilding |
Signed-off-by: Kyle Larose <kyle@agilicus.com>
Cleaned up docs and a comment Signed-off-by: Kyle Larose <kyle@agilicus.com>
Signed-off-by: Kyle Larose <kyle@agilicus.com>
@snowp I've merged in the changes we split out, and addressed your remaining comments. |
Signed-off-by: Kyle Larose <kyle@agilicus.com>
The test didn't like tests being named the same across modules. Signed-off-by: Kyle Larose <kyle@agilicus.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks solid, just a few minor comments
Have these original src destinations got a maintainer sponsor sorted out as per https://github.com/envoyproxy/envoy/blob/3573b07af1ab5c4cf687ced0f80e2ccc0a0b7ec2/EXTENSION_POLICY.md#adding-new-extensions ? If not I don't mind taking it. Make sure to encode this into CODEOWNERS as outlined in the doc I linked
Comments + style issues Signed-off-by: Kyle Larose <kyle@agilicus.com>
Sorry -- I didn't notice the extension policy! We definitely don't have a maintainer sorted out. Whoever does may also want to take on |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made another pass, looks pretty good. Feel free to put me down as the sponsor for this and the other original src filter
source/extensions/filters/common/original_src/socket_option_factory.cc
Outdated
Show resolved
Hide resolved
source/extensions/filters/common/original_src/socket_option_factory.cc
Outdated
Show resolved
Hide resolved
test/extensions/filters/http/original_src/original_src_config_factory_test.cc
Outdated
Show resolved
Hide resolved
ASSERT_FALSE(mark_option.has_value()); | ||
} | ||
|
||
TEST_F(OriginalSrcHttpTest, DecodeDataDoesNothing) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These tests that just verify nothing seem a bit strange to me because they're exercising call orders that will never happen: decodeData
will never be called before decodeHeaders
, so normally I see tests run through the expected order of of decode*
calls.
It's common to maintain state between the callbacks, e.g. for decodeHeaders
to decide whether something happens in decodeData
, which means that calling decodeData
on its own often doesn't prove much. This test in particular that calls decodeData(, true)
followed by decodeData(, false)
especially stands out as a bit strange.
I don't feel super strongly about it in the context of this filter due to its simplicity, just wanted to point it out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm actually implicitly asserting on nothing being invoked on callbacks -- it's a strict mock with no expectations set.
Any thoughts on how to make that more obvious? Some way of telling the mock that it should expect no calls at all (without needing to enumerate the disallowed calls)? I agree that it does look odd.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I've done in the past is run through the entire filter lifecycle in a single test: decodeHeaders/decodeData/decodeTrailers, using strict mocks to verify that nothing happens on data/trailers. I don't really feel strongly about this so up to you if you want to change this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's reasonable. I'll do that.
Signed-off-by: Kyle Larose <kyle@agilicus.com>
- const nits - explicit constructor - capitalization - simplified a few tests Also added myself as a reviewer. Signed-off-by: Kyle Larose <kyle@agilicus.com>
Signed-off-by: Kyle Larose <kyle@agilicus.com>
I think I got the sponsorship right -- the extension policy didn't explicitly call out what it meant to be a sponsor, only how to add reviewers for an extension. :) Either way, I added you as the first reviewer, then figured that since two are required, and contributors are allowed, I could take that on as well. Let me know if I misinterpreted something there. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM just one unresolved question on one of the comments (wether to rework the unit tests a bit)
ASSERT_FALSE(mark_option.has_value()); | ||
} | ||
|
||
TEST_F(OriginalSrcHttpTest, DecodeDataDoesNothing) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What I've done in the past is run through the entire filter lifecycle in a single test: decodeHeaders/decodeData/decodeTrailers, using strict mocks to verify that nothing happens on data/trailers. I don't really feel strongly about this so up to you if you want to change this
Signed-off-by: Kyle Larose <kyle@agilicus.com>
For the trailers and decodedata tests, run through the normal flow taken by an http filter. Signed-off-by: Kyle Larose <kyle@agilicus.com>
/retest |
🔨 rebuilding |
Signed-off-by: Kyle Larose <kyle@agilicus.com>
/retest |
🔨 rebuilding |
@snowp What's next on this? (Aside from fixing the merge conflict). I think I've addressed all your issues. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the delay. This LGTM but it seems like you have a merge conflict, could you resolve and then we'll merge?
Signed-off-by: Kyle Larose <kyle@agilicus.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks!
Description: Add an http filter to extract the original source on a per-http-request basis
A while back I added the original src listener filter. That filter would use the downstream connection's source address to build a socket option that would then be applied to upstream connections, thereby forcing their source address to mirror that of the downstream connection.
This works fine for cases where Envoy is directly exposed to the internet, or a device in front of it is placing a proxy protocol header on it. However, if proxy protocol is not an option and something (e.g. another Envoy) is between Envoy and the client, then the listener filter is insufficient for two reasons:
The http original_src filter solves these two problems by using the http stack's knowledge of the request to determine the source address (e.g. via the XFF), and by setting the options on a per-request basis. It reuses the vast majority of the work done for the listener filter -- the connection pooling, etc, as well as some of the code build to create the options.
In short, this PR carries the entirety of the work to enable the http original src filter, which can be summarized as:
StreamDecoderFilterCallbacks
and theLoadBalancerContext
downstreamRemoteAddress
Risk Level: Medium
Testing: UT + Manual. I tried writing an integration test, but it needs a bit of infrastructure work to support running it, since it needs CAP_NET_ADMIN permissions. I started that a while back, but I didn't have time to complete it.
Docs Changes: Added docs for the filter
Release Notes: Will add
Other Notes:
This is quite large. Let me know if you want me to split it up somehow.