-
Notifications
You must be signed in to change notification settings - Fork 5.5k
DNS: officially (previously only unofficially) allowing null resolutions #19588
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
Changes from 1 commit
d0c2594
c60a27d
86b54b0
e6d7ef6
0a21c0c
9d32ce0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,11 +24,13 @@ void latchTime(Http::StreamDecoderFilterCallbacks* decoder_callbacks, absl::stri | |
| struct ResponseStringValues { | ||
| const std::string DnsCacheOverflow = "DNS cache overflow"; | ||
| const std::string PendingRequestOverflow = "Dynamic forward proxy pending request overflow"; | ||
| const std::string DnsResolutionFailure = "DNS resolution failure"; | ||
| }; | ||
|
|
||
| struct RcDetailsValues { | ||
| const std::string DnsCacheOverflow = "dns_cache_overflow"; | ||
| const std::string PendingRequestOverflow = "dynamic_forward_proxy_pending_request_overflow"; | ||
| const std::string DnsResolutionFailure = "dns_resolution_failure"; | ||
| }; | ||
|
|
||
| using CustomClusterType = envoy::config::cluster::v3::Cluster::CustomClusterType; | ||
|
|
@@ -144,6 +146,12 @@ Http::FilterHeadersStatus ProxyFilter::decodeHeaders(Http::RequestHeaderMap& hea | |
|
|
||
| auto const& host = config_->cache().getHost(headers.Host()->value().getStringView()); | ||
| if (host.has_value()) { | ||
| if (!host.value()->address()) { | ||
| decoder_callbacks_->sendLocalReply(Http::Code::ServiceUnavailable, | ||
| ResponseStrings::get().DnsResolutionFailure, nullptr, | ||
| absl::nullopt, RcDetails::get().DnsResolutionFailure); | ||
| return Http::FilterHeadersStatus::StopIteration; | ||
| } | ||
| addHostAddressToFilterState(host.value()->address()); | ||
| } | ||
|
|
||
|
|
@@ -165,22 +173,13 @@ Http::FilterHeadersStatus ProxyFilter::decodeHeaders(Http::RequestHeaderMap& hea | |
| NOT_REACHED_GCOVR_EXCL_LINE; | ||
| } | ||
|
|
||
| void ProxyFilter::addHostAddressToFilterState( | ||
| const Network::Address::InstanceConstSharedPtr& address) { | ||
| void ProxyFilter::addHostAddressToFilterState(const Network::Address::InstanceConstSharedPtr& address) { | ||
| ASSERT(address); // null pointer checks must be done before calling this function. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was confused for a minute about how a "const T&" could even be null.... then I realized that T is "SharedPtr". Carry on! facepalm |
||
|
|
||
| if (!config_->saveUpstreamAddress()) { | ||
| return; | ||
| } | ||
|
|
||
| // `onLoadDnsCacheComplete` is called by DNS cache on first resolution even if there was a | ||
| // resolution failure (null address). This check makes sure that we do not add null address to | ||
| // FilterState when this happens. | ||
| if (!address) { | ||
| ENVOY_STREAM_LOG(debug, "Cannot add address to filter state: invalid address", | ||
| *decoder_callbacks_); | ||
| return; | ||
| } | ||
|
|
||
| ENVOY_STREAM_LOG(trace, "Adding resolved host {} to filter state", *decoder_callbacks_, | ||
| address->asString()); | ||
|
|
||
|
|
@@ -203,6 +202,15 @@ void ProxyFilter::onLoadDnsCacheComplete( | |
| ASSERT(circuit_breaker_ != nullptr); | ||
| circuit_breaker_.reset(); | ||
|
|
||
| if (!host_info->address()) { | ||
| // Generally in Envoy it is not Ok to send a local reply at 2 code points with the same | ||
| // details, but here we could leak prior queries if we differentiate new failures from | ||
| // cached failures, so intentionally reuse the details. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe we could chat offline, but I'm not sure that I really understand. Is this comment observing that in ProxyFilter::decodeHeaders() we send the same details that we're sending here? And normally that would be verboten. But if we returned a new error code here, we'd leak to the caller that a previous resolution had failed? Is that a privacy leak or some such?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah I was worried this is more confusing than it's worth. Looking at our TODOs I think I also want to add a response flag, then refactored, so I think I can just remove this comment. largely when we sendLocalReply we're supposed to be able to use rc-details to track exactly what went wrong. generally I'd want separate codes for synchronous-dns-fail and async-dns-fail but that leaks prior requests so I'm intentionally not doing it. I don't think anyone else would realize the quandry so removing for clarity :-P
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. SGTM! |
||
| decoder_callbacks_->sendLocalReply(Http::Code::ServiceUnavailable, | ||
| ResponseStrings::get().DnsResolutionFailure, nullptr, | ||
| absl::nullopt, RcDetails::get().DnsResolutionFailure); | ||
| return; | ||
| } | ||
| addHostAddressToFilterState(host_info->address()); | ||
|
|
||
| decoder_callbacks_->continueDecoding(); | ||
|
|
||
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.
Consider calling
latchTime(decoder_callbacks_, DNS_END);before this line (or inonDnsResolutionFail().