proxy: Honor TTLs for DNS responses (#974)

Closes #711. Depends on #967.

This PR changes the proxy's `destination` module to honor the TTLs associated
with DNS lookups, now that bluejekyll/trust-dns#444 has been merged and we can
access this information from the Trust-DNS Resolver API. 

The `destination::background::DestinationSet` type has been modified so that, 
when a successful result is received for a DNS query, the DNS server will be 
polled again after the deadline associated with that query, rather than after
a fixed deadline. The fixed deadline is still used to determine when to poll
again for negative DNS responses or for errors.

Furthermore, Conduit now accepts an optional CONDUIT_PROXY_DNS_MIN_TTL 
environment variable that will configure a minimum TTL for DNS results. If the
deadline of a DNS response gives it a TTL shorter than the configured minimum,
Conduit will not poll DNS again until after that minimum TTL is elapsed. By
default, there is no minimum value set, as this feature is intended primarily
for when Conduit is run locally for development purposes.

Signed-off-by: Eliza Weisman <eliza@buoyant.io>
This commit is contained in:
Eliza Weisman 2018-06-01 12:17:48 -07:00 committed by GitHub
parent fbbe28d032
commit 0e29e2f5cf
6 changed files with 146 additions and 73 deletions

108
Cargo.lock generated
View File

@ -29,20 +29,6 @@ dependencies = [
"winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "backtrace"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "backtrace"
version = "0.3.5"
@ -167,7 +153,7 @@ dependencies = [
"tower-reconnect 0.1.0 (git+https://github.com/tower-rs/tower)",
"tower-service 0.1.0 (git+https://github.com/tower-rs/tower)",
"tower-util 0.1.0 (git+https://github.com/tower-rs/tower)",
"trust-dns-resolver 0.8.1 (git+https://github.com/bluejekyll/trust-dns)",
"trust-dns-resolver 0.9.0 (git+https://github.com/bluejekyll/trust-dns?rev=5c966b86e7d847ad14344e494237e162dc635de0)",
"untrusted 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"webpki 0.18.0-alpha3 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -241,15 +227,6 @@ dependencies = [
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "dbghelp-sys"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "deflate"
version = "0.7.18"
@ -284,14 +261,6 @@ dependencies = [
"termcolor 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "error-chain"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "error-chain"
version = "0.8.1"
@ -306,6 +275,17 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "failure_derive"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
"synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -763,6 +743,11 @@ dependencies = [
"rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quote"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "quote"
version = "0.4.2"
@ -904,6 +889,16 @@ name = "string"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "syn"
version = "0.11.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syn"
version = "0.12.10"
@ -914,6 +909,23 @@ dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "synom"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "synstructure"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "tempdir"
version = "0.3.7"
@ -1209,11 +1221,11 @@ dependencies = [
[[package]]
name = "trust-dns-proto"
version = "0.3.2"
source = "git+https://github.com/bluejekyll/trust-dns#849453207c16e4f5639e321d213ac77595728981"
version = "0.4.0"
source = "git+https://github.com/bluejekyll/trust-dns?rev=5c966b86e7d847ad14344e494237e162dc635de0#5c966b86e7d847ad14344e494237e162dc635de0"
dependencies = [
"byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1232,11 +1244,11 @@ dependencies = [
[[package]]
name = "trust-dns-resolver"
version = "0.8.1"
source = "git+https://github.com/bluejekyll/trust-dns#849453207c16e4f5639e321d213ac77595728981"
version = "0.9.0"
source = "git+https://github.com/bluejekyll/trust-dns?rev=5c966b86e7d847ad14344e494237e162dc635de0#5c966b86e7d847ad14344e494237e162dc635de0"
dependencies = [
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)",
"ipconfig 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1245,7 +1257,7 @@ dependencies = [
"resolv-conf 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"trust-dns-proto 0.3.2 (git+https://github.com/bluejekyll/trust-dns)",
"trust-dns-proto 0.4.0 (git+https://github.com/bluejekyll/trust-dns?rev=5c966b86e7d847ad14344e494237e162dc635de0)",
]
[[package]]
@ -1276,6 +1288,11 @@ name = "unicode-segmentation"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-xid"
version = "0.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-xid"
version = "0.1.0"
@ -1405,7 +1422,6 @@ dependencies = [
"checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4"
"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
"checksum atty 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8352656fd42c30a0c3c89d26dea01e3b77c0ab2af18230835c15e2e13cd51859"
"checksum backtrace 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "346d7644f0b5f9bc73082d3b2236b69a05fd35cce0cfa3724e184e6a5c9e2a2f"
"checksum backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbbf59b1c43eefa8c3ede390fcc36820b4999f7914104015be25025e0d62af2"
"checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661"
"checksum base64 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9263aa6a38da271eec5c91a83ce1e800f093c8535788d403d626d8d5c3f8f007"
@ -1421,14 +1437,13 @@ dependencies = [
"checksum crossbeam-deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fe8153ef04a7594ded05b427ffad46ddeaf22e63fd48d42b3e1e3bb4db07cae7"
"checksum crossbeam-epoch 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9b4e2817eb773f770dcb294127c011e22771899c21d18fce7dd739c0b9832e81"
"checksum crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d636a8b3bcc1b409d7ffd3facef8f21dcb4009626adbd0c5e6c4305c07253c7b"
"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850"
"checksum deflate 0.7.18 (registry+https://github.com/rust-lang/crates.io-index)" = "32c8120d981901a9970a3a1c97cf8b630e0fa8c3ca31e75b6fd6fd5f9f427b31"
"checksum either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "740178ddf48b1a9e878e6d6509a1442a2d42fd2928aae8e7a6f8a36fb01981b3"
"checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180"
"checksum env_logger 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f15f0b172cb4f52ed5dbf47f774a387cd2315d1bf7894ab5af9b083ae27efa5a"
"checksum error-chain 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faa976b4fd2e4c2b2f3f486874b19e61944d3de3de8b61c9fcf835d583871bcc"
"checksum error-chain 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6930e04918388a9a2e41d518c25cf679ccafe26733fb4127dbf21993f2575d46"
"checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82"
"checksum failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cdda555bb90c9bb67a3b670a0f42de8e73f5981524123ad8578aafec8ddb8b"
"checksum fixedbitset 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "85cb8fec437468d86dc7c83ca7cfc933341d561873275f22dd5eedefa63a6478"
"checksum flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fac2277e84e5e858483756647a9d0aa8d9a2b7cba517fd84325a0aaa69a0909"
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
@ -1482,6 +1497,7 @@ dependencies = [
"checksum prost-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "49b4fc1adae913fff99daa455ca43750f90cbec6846369fb78b7ed8d3e727758"
"checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4"
"checksum quickcheck 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "13f4460d3daa06eb1c4b9a3c55dffe65cb030dd70cf1bfdd482532f48ab24f74"
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
"checksum quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eca14c727ad12702eb4b6bfb5a232287dcf8385cb8ca83a3eeaf6519c44c408"
"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5"
"checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd"
@ -1500,7 +1516,10 @@ dependencies = [
"checksum smallvec 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03dab98ab5ded3a8b43b2c80751194608d0b2aa0f1d46cf95d1c35e192844aa7"
"checksum socket2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ff606e0486e88f5fc6cfeb3966e434fb409abbc7a3ab495238f70a1ca97f789d"
"checksum string 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "31f98b200e7caca9efca50fc0aa69cd58a5ec81d5f6e75b2f3ecaad2e998972a"
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
"checksum syn 0.12.10 (registry+https://github.com/rust-lang/crates.io-index)" = "7d12ebcea3f1027a817b98e91cfe30805634ea1f63e36015f765960a7782494d"
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
"checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd"
"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
"checksum termcolor 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "56c456352e44f9f91f774ddeeed27c1ec60a2455ed66d692059acfb1d731bda1"
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
@ -1528,13 +1547,14 @@ dependencies = [
"checksum tower-reconnect 0.1.0 (git+https://github.com/tower-rs/tower)" = "<none>"
"checksum tower-service 0.1.0 (git+https://github.com/tower-rs/tower)" = "<none>"
"checksum tower-util 0.1.0 (git+https://github.com/tower-rs/tower)" = "<none>"
"checksum trust-dns-proto 0.3.2 (git+https://github.com/bluejekyll/trust-dns)" = "<none>"
"checksum trust-dns-resolver 0.8.1 (git+https://github.com/bluejekyll/trust-dns)" = "<none>"
"checksum trust-dns-proto 0.4.0 (git+https://github.com/bluejekyll/trust-dns?rev=5c966b86e7d847ad14344e494237e162dc635de0)" = "<none>"
"checksum trust-dns-resolver 0.9.0 (git+https://github.com/bluejekyll/trust-dns?rev=5c966b86e7d847ad14344e494237e162dc635de0)" = "<none>"
"checksum try-lock 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee2aa4715743892880f70885373966c83d73ef1b0838a664ef0c76fffd35e7c2"
"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d"
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
"checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f"
"checksum unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8083c594e02b8ae1654ae26f0ade5158b119bd88ad0e8227a5d8fcd72407946"
"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
"checksum untrusted 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70afa43c8c5d23a53a3c39ec9b56232c5badc19f6bb5ad529c1d6448a7241365"

View File

@ -37,7 +37,7 @@ tokio-signal = "0.2"
prost = "0.3.0"
prost-types = "0.3.0"
trust-dns-resolver = { default-features = false, git = "https://github.com/bluejekyll/trust-dns", branch = "master" }
trust-dns-resolver = { default-features = false, git = "https://github.com/bluejekyll/trust-dns", rev = "5c966b86e7d847ad14344e494237e162dc635de0" }
tokio-connect = { git = "https://github.com/carllerche/tokio-connect" }
tower-service = { git = "https://github.com/tower-rs/tower" }

View File

@ -8,6 +8,8 @@ use std::time::Duration;
use http;
use indexmap::IndexSet;
use trust_dns_resolver::config::ResolverOpts;
use transport::{Host, HostAndPort, HostAndPortError, tls};
use convert::TryFrom;
@ -69,6 +71,12 @@ pub struct Config {
pub bind_timeout: Duration,
pub pod_namespace: String,
/// Optional minimum TTL for DNS lookups.
pub dns_min_ttl: Option<Duration>,
/// Optional maximum TTL for DNS lookups.
pub dns_max_ttl: Option<Duration>,
}
/// Configuration settings for binding a listener.
@ -169,6 +177,15 @@ pub const ENV_POD_NAMESPACE: &str = "CONDUIT_PROXY_POD_NAMESPACE";
pub const ENV_CONTROL_URL: &str = "CONDUIT_PROXY_CONTROL_URL";
const ENV_RESOLV_CONF: &str = "CONDUIT_RESOLV_CONF";
/// Configures a minimum value for the TTL of DNS lookups.
///
/// Lookups with TTLs below this value will use this value instead.
const ENV_DNS_MIN_TTL: &str = "CONDUIT_PROXY_DNS_MIN_TTL";
/// Configures a maximum value for the TTL of DNS lookups.
///
/// Lookups with TTLs above this value will use this value instead.
const ENV_DNS_MAX_TTL: &str = "CONDUIT_PROXY_DNS_MAX_TTL";
// Default values for various configuration fields
const DEFAULT_EVENT_BUFFER_CAPACITY: usize = 10_000; // FIXME
const DEFAULT_PRIVATE_LISTENER: &str = "tcp://127.0.0.1:4140";
@ -199,6 +216,20 @@ const DEFAULT_PORTS_DISABLE_PROTOCOL_DETECTION: &[u16] = &[
// ===== impl Config =====
impl Config {
/// Modify a `trust-dns-resolver::config::ResolverOpts` to reflect
/// the configured minimum and maximum DNS TTL values.
pub fn configure_resolver_opts(&self, mut opts: ResolverOpts) -> ResolverOpts {
opts.positive_min_ttl = self.dns_min_ttl;
opts.positive_max_ttl = self.dns_max_ttl;
// TODO: Do we want to allow the positive and negative TTLs to be
// configured separately?
opts.negative_min_ttl = self.dns_min_ttl;
opts.negative_max_ttl = self.dns_max_ttl;
opts
}
}
impl<'a> TryFrom<&'a Strings> for Config {
type Err = Error;
/// Load a `Config` by reading ENV variables.
@ -226,6 +257,8 @@ impl<'a> TryFrom<&'a Strings> for Config {
let resolv_conf_path = strings.get(ENV_RESOLV_CONF);
let event_buffer_capacity = parse(strings, ENV_EVENT_BUFFER_CAPACITY, parse_number);
let metrics_retain_idle = parse(strings, ENV_METRICS_RETAIN_IDLE, parse_duration);
let dns_min_ttl = parse(strings, ENV_DNS_MIN_TTL, parse_duration);
let dns_max_ttl = parse(strings, ENV_DNS_MAX_TTL, parse_duration);
let pod_namespace = strings.get(ENV_POD_NAMESPACE).and_then(|maybe_value| {
// There cannot be a default pod namespace, and the pod namespace is required.
maybe_value.ok_or_else(|| {
@ -322,6 +355,10 @@ impl<'a> TryFrom<&'a Strings> for Config {
bind_timeout: bind_timeout?.unwrap_or(DEFAULT_BIND_TIMEOUT),
pod_namespace: pod_namespace?,
dns_min_ttl: dns_min_ttl?,
dns_max_ttl: dns_max_ttl?,
})
}
}

View File

@ -5,7 +5,7 @@ use std::collections::{
use std::fmt;
use std::iter::IntoIterator;
use std::net::SocketAddr;
use std::time::Duration;
use std::time::{Instant, Duration};
use bytes::Bytes;
use futures::{
@ -210,7 +210,7 @@ where
if set.query.is_none() {
set.reset_dns_query(
&self.dns_resolver,
Duration::from_secs(0),
Instant::now(),
vac.key(),
);
}
@ -290,7 +290,7 @@ where
},
Exists::No => {
// Fall back to DNS.
set.reset_dns_query(&self.dns_resolver, Duration::from_secs(0), auth);
set.reset_dns_query(&self.dns_resolver, Instant::now(), auth);
},
Exists::Unknown => (), // No change from Destination service's perspective.
}
@ -339,16 +339,16 @@ where
fn reset_dns_query(
&mut self,
dns_resolver: &dns::Resolver,
delay: Duration,
deadline: Instant,
authority: &DnsNameAndPort,
) {
trace!(
"resetting DNS query for {} with delay {:?}",
"resetting DNS query for {} at {:?}",
authority.host,
delay
deadline
);
self.reset_on_next_modification();
self.dns_query = Some(dns_resolver.resolve_all_ips(delay, &authority.host));
self.dns_query = Some(dns_resolver.resolve_all_ips(deadline, &authority.host));
}
// Processes Destination service updates from `request_rx`, returning the new query
@ -412,10 +412,14 @@ where
}
fn poll_dns(&mut self, dns_resolver: &dns::Resolver, authority: &DnsNameAndPort) {
// Duration to wait before polling DNS again after an error
// (or a NXDOMAIN response with no TTL).
const DNS_ERROR_TTL: Duration = Duration::from_secs(5);
trace!("checking DNS for {:?}", authority);
while let Some(mut query) = self.dns_query.take() {
trace!("polling DNS for {:?}", authority);
match query.poll() {
let deadline = match query.poll() {
Ok(Async::NotReady) => {
trace!("DNS query not ready {:?}", authority);
self.dns_query = Some(query);
@ -436,23 +440,30 @@ where
)
}),
);
// Poll again after the deadline on the DNS response.
ips.valid_until()
},
Ok(Async::Ready(dns::Response::DoesNotExist)) => {
Ok(Async::Ready(dns::Response::DoesNotExist { retry_after })) => {
trace!(
"negative result (NXDOMAIN) of DNS query for {:?}",
authority
);
self.no_endpoints(authority, false);
// Poll again after the deadline on the DNS response, if
// there is one.
retry_after.unwrap_or_else(|| Instant::now() + DNS_ERROR_TTL)
},
Err(e) => {
trace!("DNS resolution failed for {}: {}", &authority.host, e);
// Do nothing so that the most recent non-error response is used until a
// non-error response is received.
// non-error response is received
trace!("DNS resolution failed for {}: {}", &authority.host, e);
// Poll again after the default wait time.
Instant::now() + DNS_ERROR_TTL
},
};
// TODO: When we have a TTL to use, we should use that TTL instead of hard-coding this
// delay.
self.reset_dns_query(dns_resolver, Duration::from_secs(5), &authority)
self.reset_dns_query(dns_resolver, deadline, &authority)
}
}
}

View File

@ -1,7 +1,7 @@
use futures::prelude::*;
use std::fmt;
use std::net::IpAddr;
use std::time::{Instant, Duration};
use std::time::Instant;
use tokio::timer::Delay;
use transport;
use trust_dns_resolver;
@ -10,6 +10,8 @@ use trust_dns_resolver::error::{ResolveError, ResolveErrorKind};
use trust_dns_resolver::ResolverFuture;
use trust_dns_resolver::lookup_ip::LookupIp;
use config::Config;
#[derive(Clone, Debug)]
pub struct Resolver {
config: ResolverConfig,
@ -28,7 +30,7 @@ pub enum Error {
pub enum Response {
Exists(LookupIp),
DoesNotExist,
DoesNotExist { retry_after: Option<Instant> },
}
// `Box<Future>` implements `Future` so it doesn't need to be implemented manually.
@ -59,19 +61,22 @@ impl AsRef<str> for Name {
}
impl Resolver {
/// Construct a new `Resolver` from the system configuration and Conduit's
/// environment variables.
///
/// TODO: Make this infallible, like it is in the `domain` crate.
pub fn from_system_config() -> Result<Self, ResolveError> {
pub fn new(env_config: &Config) -> Result<Self, ResolveError> {
let (config, opts) = trust_dns_resolver::system_conf::read_system_conf()?;
let mut opts = env_config.configure_resolver_opts(opts);
// Disable Trust-DNS's caching.
opts.cache_size = 0;
trace!("DNS config: {:?}", &config);
trace!("DNS opts: {:?}", &opts);
Ok(Self::new(config, opts))
}
pub fn new(config: ResolverConfig, opts: ResolverOpts) -> Self {
Resolver {
Ok(Resolver {
config,
opts,
}
})
}
pub fn resolve_one_ip(&self, host: &transport::Host) -> IpAddrFuture {
@ -84,12 +89,12 @@ impl Resolver {
}
}
pub fn resolve_all_ips(&self, delay: Duration, host: &Name) -> IpAddrListFuture {
pub fn resolve_all_ips(&self, deadline: Instant, host: &Name) -> IpAddrListFuture {
let name = host.clone();
let name_clone = name.clone();
trace!("resolve_all_ips {}", &name);
let resolver = self.clone();
let f = Delay::new(Instant::now() + delay)
let f = Delay::new(deadline)
.then(move |_| {
trace!("resolve_all_ips {} after delay", &name);
resolver.lookup_ip(&name)
@ -99,8 +104,8 @@ impl Resolver {
match result {
Ok(ips) => Ok(Response::Exists(ips)),
Err(e) => {
if let &ResolveErrorKind::NoRecordsFound(_) = e.kind() {
Ok(Response::DoesNotExist)
if let &ResolveErrorKind::NoRecordsFound { valid_until, .. } = e.kind() {
Ok(Response::DoesNotExist { retry_after: valid_until })
} else {
Err(e)
}

View File

@ -213,7 +213,7 @@ where
&taps,
);
let dns_resolver = dns::Resolver::from_system_config()
let dns_resolver = dns::Resolver::new(&config)
.unwrap_or_else(|e| {
// TODO: Make DNS configuration infallible.
panic!("invalid DNS configuration: {:?}", e);