Skip to content

http conn man: add an option to strip trailing host dot.#15568

Merged
snowp merged 23 commits intoenvoyproxy:mainfrom
maheshkurund:remove_trailing_host_dot
May 25, 2021
Merged

http conn man: add an option to strip trailing host dot.#15568
snowp merged 23 commits intoenvoyproxy:mainfrom
maheshkurund:remove_trailing_host_dot

Conversation

@maheshkurund
Copy link
Copy Markdown
Contributor

Signed-off-by: maheshkurund mahesh.kurund@oneconvergence.com

Commit Message:
Add an option in connection manager which allow to strip trailing host dot from Host/authority header. (e.g transforms "example.com." to "example.com").

Additional Description:
This change would eliminate the need of specifying domain entry with dot (e.g example.com.) while matching it with domain's inside the virtual host. For example, if the request has a host header "example.com." and strip_trailing_host_dot flag is set then it transforms into "example.com" by stripping the trailing dot and matches "domains" configured in VirtualHost.
Fixes #14748

Risk Level: Low
Testing: Unit, integration and manual.
Docs Changes: Inline in proto file.
Release Notes:
Platform Specific Features:
[Optional Runtime guard:]
[Optional Fixes #Issue]
[Optional Deprecated:]
[Optional API Considerations:]

Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
@repokitteh-read-only
Copy link
Copy Markdown

Hi @maheshkurund, welcome and thank you for your contribution.

We will try to review your Pull Request as quickly as possible.

In the meantime, please take a look at the contribution guidelines if you have not done so already.

🐱

Caused by: #15568 was opened by maheshkurund.

see: more, trace.

@repokitteh-read-only
Copy link
Copy Markdown

CC @envoyproxy/api-shepherds: Your approval is needed for changes made to api/envoy/.
API shepherd assignee is @markdroth
CC @envoyproxy/api-watchers: FYI only for changes made to api/envoy/.

🐱

Caused by: #15568 was opened by maheshkurund.

see: more, trace.

Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
filter_callbacks_.connection_.raiseEvent(Network::ConnectionEvent::RemoteClose);
}

// Filters observe host header w/o trailing dot in host when trailing dot removal is configured
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do you think dot stripping could be tested more directly? Instantiate ConnectionManagerImpl, create a RequestDecoder by invoking ConnectionManagerImpl::newStream(), then invoke RequestDecoder::decodeHeaders() and verify the contents of the "host" header. WDYT?

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.

yes, added test for this, please check and let me know. Thank you.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ultimately, I'm not sure why three tests that very closely resemble each other are needed (they all verify that a) header map is updated, and b) that filters in the filter chain see that change. Perhaps just RemoveTrailingHostDot or FilterShouldUseHostWithoutTrailingDot is sufficient?

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.

Agree, will remove RemoveTrailingHostDot test and add check to verify host header after RequestDecoder::decodeHeaders() in FilterShouldUseHostWithoutTrailingDot and RouteShouldUseHostWithoutTrailingDot.

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.

Addressed.

…ders().

Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
// This affects the upstream host header.
// Without setting this option, incoming requests with host `example.com.` will not match against
// route with :ref:`domains<envoy_api_field_config.route.v3.VirtualHost.domains>` match set to `example.com`. Defaults to `false`.
bool strip_trailing_host_dot = 44;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Drive by question for mdroth, do we think it's worth moving this and strip_matching_host_port together in a host mutation proto or just and wait and see if we get more?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

At this point, there are a whole bunch of options here related to URI normalization, not just the host ones but also the path ones. I'd be open to moving all of those options to a separate UriNormalizationOptions message, but I'd also be okay with keeping them here, since they're unlikely to ever be used anywhere else.

Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
@maheshkurund
Copy link
Copy Markdown
Contributor Author

/retest

@repokitteh-read-only
Copy link
Copy Markdown

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

🐱

Caused by: a #15568 (comment) was created by @maheshkurund.

see: more, trace.

@maheshkurund maheshkurund requested a review from dmitri-d April 9, 2021 11:30
EXPECT_CALL(*filter, setDecoderFilterCallbacks(_));

EXPECT_CALL(*codec_, dispatch(_)).WillOnce(Invoke([&](Buffer::Instance&) -> Http::Status {
decoder_ = &conn_manager_->newStream(response_encoder_);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Couldn't you reduce the test to setup and lines 854-857? Then verify the contents of authority in headers...

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.

Is it ok to verify host header after RequestDecoder::decodeHeaders() in existing tests? Or should I keep only single test which just verifies host header after RequestDecoder::decodeHeaders() as you mentioned above?

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.

Addressed.

…t_dot

Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
@maheshkurund
Copy link
Copy Markdown
Contributor Author

/retest

@repokitteh-read-only
Copy link
Copy Markdown

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

🐱

Caused by: a #15568 (comment) was created by @maheshkurund.

see: more, trace.

@maheshkurund maheshkurund requested a review from dmitri-d April 28, 2021 04:01
return Http::okStatus();
}));
Buffer::OwnedImpl fake_input("1234");
conn_manager_->onData(fake_input, false);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't think you need to call onData callback (and set the expectation above), instead you should be able to do

conn_manager_->createCodec(fake_input);

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.

thank you. Updated the code with suggestion.

@dmitri-d
Copy link
Copy Markdown
Contributor

dmitri-d commented Apr 29, 2021

The tests look good, with one minor suggestion for a change. Also, please merge in the latest changes from main.

Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
@maheshkurund
Copy link
Copy Markdown
Contributor Author

/retest

@repokitteh-read-only
Copy link
Copy Markdown

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

🐱

Caused by: a #15568 (comment) was created by @maheshkurund.

see: more, trace.

@maheshkurund
Copy link
Copy Markdown
Contributor Author

/retest

@repokitteh-read-only
Copy link
Copy Markdown

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

🐱

Caused by: a #15568 (comment) was created by @maheshkurund.

see: more, trace.

Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
@maheshkurund
Copy link
Copy Markdown
Contributor Author

/retest

@repokitteh-read-only
Copy link
Copy Markdown

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

🐱

Caused by: a #15568 (comment) was created by @maheshkurund.

see: more, trace.

Copy link
Copy Markdown
Contributor

@snowp snowp left a comment

Choose a reason for hiding this comment

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

Thanks for working on this!


void HeaderUtility::stripTrailingHostDot(RequestHeaderMap& headers) {
auto host = headers.getHostValue();
// Find last dot and return if not found or take off end if last
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Maybe just // If the host ends in a period, remove it.

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.

Yes fits well here, will update.

Comment on lines +241 to +245
// Check if the dot is just before a colon, which means it must be the port
// because although the host may contain a colon via an IPv6 bracketed
// address, and although that IPv6 address may also contain dots when
// embedding an address per RFC 4291 2.2.3, the dot will never directly
// precede the colon like it would in foo.com.:123
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Maybe split this sentence up? It's very long

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.

yah, will fix it.

headers.setHost(host);
return;
}
// Check if the dot is just before a colon, which means it must be the port
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If the dot is just before a colon, it must be preceding the port number.

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.

Will change.

Comment on lines +676 to +680
// Determines if trailing dot of the host should be removed from host/authority header before any
// processing of request by HTTP filters or routing.
// This affects the upstream host header.
// Without setting this option, incoming requests with host `example.com.` will not match against
// route with :ref:`domains<envoy_v3_api_field_config.route.v3.VirtualHost.domains>` match set to `example.com`. Defaults to `false`.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This should probably include something about how this handles the host:port case

Copy link
Copy Markdown
Contributor Author

@maheshkurund maheshkurund May 15, 2021

Choose a reason for hiding this comment

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

Will following comment helps here in case of host:port?

In case host/authority header value has port part with host, on setting this option it removes trailing dot from host keeping port value as is i.e host example.com.:443 will become example.com:443.

// precede the colon like it would in foo.com.:123
if (host[dot_index + 1] == ':') {
// Does a memcpy internally, but since we only have access to a string_view
// anyways, this is acceptable compared to a string::erase of a copy
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: end comments with period

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.

Will change.

// embedding an address per RFC 4291 2.2.3, the dot will never directly
// precede the colon like it would in foo.com.:123
if (host[dot_index + 1] == ':') {
// Does a memcpy internally, but since we only have access to a string_view
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What does a memcpy? If you're talking about it copying data to a new string we do that on L238 as well, so this call out seems to be a bit unnecessary

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.

Will remove it.

filter_callbacks_.connection_.raiseEvent(Network::ConnectionEvent::RemoteClose);
}

// Observe host header w/o trailing dot in host when trailing dot removal is configured
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: here and below, end comments with period as comments should use proper grammar (even if other tests don't do this, no reason to not do it for new code :) )

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.

agree, will fix this.

{"abc.com.", "abc.com"}, // dns w/ dot
{"abc.com:443", "abc.com:443"}, // dns port w/o dot
{"abc.com.:443", "abc.com:443"}, // dns port w/ dot
{"[fc00::1].:443", "[fc00::1]:443"}, // ipv6 w/ dot
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

qq is this a valid input? Not sure when we'd get a . after an IP?

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.

Yah, its not valid input, its added by mistake and will remove it.

Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
@maheshkurund
Copy link
Copy Markdown
Contributor Author

/retest

@repokitteh-read-only
Copy link
Copy Markdown

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

🐱

Caused by: a #15568 (comment) was created by @maheshkurund.

see: more, trace.

@maheshkurund maheshkurund requested a review from snowp May 19, 2021 04:19
Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
Copy link
Copy Markdown
Contributor

@snowp snowp left a 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 here, got some for comments for you. Thanks for iterating on this!

// This affects the upstream host header.
// Without setting this option, incoming requests with host `example.com.` will not match against
// route with :ref:`domains<envoy_v3_api_field_config.route.v3.VirtualHost.domains>` match set to `example.com`. Defaults to `false`.
// When incoming requests with host/authority header has port part with host, on setting this option it removes trailing dot from host keeping port
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Maybe When the incoming request contains a host/authority header includes a port number, setting this option will strip trailing dots from the host section, leaving the port as is (e.g. ...?

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, will update.


New Features
------------

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

remove this newline

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.

will remove.

Comment on lines +231 to +233
// Because although the host may contain a colon via an IPv6 bracketed
// address, and although that IPv6 address may also contain dots when
// embedding an address per RFC 4291 2.2.3. In this case the dot will never
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is a bit tricky to read, maybe something like IPv6 addresses may contain colons or dots, but the dot will never directly precede the colon, so this check should be sufficient to detect a trailing port number.?

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.

sure, will update it.

filter_callbacks_.connection_.raiseEvent(Network::ConnectionEvent::RemoteClose);
}

// Observe host header w/o trailing dot in host when trailing dot removal is configured.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This makes it sound like the input doesn't have a trailing dot, maybe Observe tat we strip the trailing dot ...?

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, will change.

}

// Observe host header w/o trailing dot in host when trailing dot removal is configured.
TEST_F(HttpConnectionManagerImplTest, StripTrailingHostDot) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Mind adding a test where we set this config option but pass through a header without a trailing dot?

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.

Sure. will add.

Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
Copy link
Copy Markdown
Contributor

@snowp snowp left a comment

Choose a reason for hiding this comment

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

Some more nits, thanks for iterating!

// route with :ref:`domains<envoy_v3_api_field_config.route.v3.VirtualHost.domains>` match set to `example.com`. Defaults to `false`.
// When incoming requests with host/authority header has port part with host, on setting this option it removes trailing dot from host keeping port
// value as is (e.g. host value `example.com.:443` will be updated to `example.com:443`).
// When the incoming request contains a host/authority header includes a port number, setting this option will strip trailing dots
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

that includes

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, addressed.

// route with :ref:`domains<envoy_v3_api_field_config.route.v3.VirtualHost.domains>` match set to `example.com`. Defaults to `false`.
// When incoming requests with host/authority header has port part with host, on setting this option it removes trailing dot from host keeping port
// value as is (e.g. host value `example.com.:443` will be updated to `example.com:443`).
// When the incoming request contains a host/authority header includes a port number, setting this option will strip trailing dots
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

a trailing dot, if present, from the host section

otherwise this sounds like we strip multiple dots? I think we only do one right?

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.

Yes, we do remove only one dot, updated in latest commit.

Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.com>
@maheshkurund
Copy link
Copy Markdown
Contributor Author

/retest

@repokitteh-read-only
Copy link
Copy Markdown

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

🐱

Caused by: a #15568 (comment) was created by @maheshkurund.

see: more, trace.

@maheshkurund maheshkurund requested a review from snowp May 24, 2021 12:02
Copy link
Copy Markdown
Contributor

@snowp snowp left a comment

Choose a reason for hiding this comment

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

LGTM, thanks!

@markdroth mind giving the API a look? Thanks

@markdroth
Copy link
Copy Markdown
Contributor

/lgtm api

@maheshkurund
Copy link
Copy Markdown
Contributor Author

Thanks @dmitri-d @snowp @markdroth for reviewing this change.

@snowp snowp merged commit 7cc10b0 into envoyproxy:main May 25, 2021
Copy link
Copy Markdown
Contributor

@howardjohn howardjohn left a comment

Choose a reason for hiding this comment

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

This is a bit late but it would be great if this, and the other strip_ options supported stripping only internally and preserving the original when forwarding upstream. Otherwise its not super usable for a transparent proxy

leyao-daily pushed a commit to leyao-daily/envoy that referenced this pull request Sep 30, 2021
…15568)

Add an option in connection manager which allow to strip trailing host dot from Host/authority header
(e.g transforms "example.com." to "example.com").

Signed-off-by: maheshkurund <mahesh.kurund@oneconvergence.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.

Account for possible trailing dot in domain name matching

7 participants