This change allows users to bypass the selected DNS resolver for specific domains. The allows, for example, to make calls to a local TLS server by rerouting a given domain to 127.0.0.1. The approach I've taken for the design is to wrap the resolver in an outer service. This leads to a fair amount of boilerplate code mainly to be able to explain the typing to the compiler. The actual business logic is very simple for the number of lines involved. Closes #561
This commit is contained in:
		| @@ -1,9 +1,9 @@ | ||||
| #[cfg(any(feature = "native-tls", feature = "__rustls",))] | ||||
| use std::any::Any; | ||||
| use std::convert::TryInto; | ||||
| use std::net::IpAddr; | ||||
| use std::sync::Arc; | ||||
| use std::time::Duration; | ||||
| use std::{collections::HashMap, convert::TryInto, net::SocketAddr}; | ||||
| use std::{fmt, str}; | ||||
|  | ||||
| use bytes::Bytes; | ||||
| @@ -107,6 +107,7 @@ struct Config { | ||||
|     trust_dns: bool, | ||||
|     error: Option<crate::Error>, | ||||
|     https_only: bool, | ||||
|     dns_overrides: HashMap<String, SocketAddr>, | ||||
| } | ||||
|  | ||||
| impl Default for ClientBuilder { | ||||
| @@ -164,6 +165,7 @@ impl ClientBuilder { | ||||
|                 #[cfg(feature = "cookies")] | ||||
|                 cookie_store: None, | ||||
|                 https_only: false, | ||||
|                 dns_overrides: HashMap::new(), | ||||
|             }, | ||||
|         } | ||||
|     } | ||||
| @@ -194,9 +196,21 @@ impl ClientBuilder { | ||||
|             } | ||||
|  | ||||
|             let http = match config.trust_dns { | ||||
|                 false => HttpConnector::new_gai(), | ||||
|                 false => { | ||||
|                     if config.dns_overrides.is_empty() { | ||||
|                         HttpConnector::new_gai() | ||||
|                     } else { | ||||
|                         HttpConnector::new_gai_with_overrides(config.dns_overrides) | ||||
|                     } | ||||
|                 } | ||||
|                 #[cfg(feature = "trust-dns")] | ||||
|                 true => HttpConnector::new_trust_dns()?, | ||||
|                 true => { | ||||
|                     if config.dns_overrides.is_empty() { | ||||
|                         HttpConnector::new_trust_dns()? | ||||
|                     } else { | ||||
|                         HttpConnector::new_trust_dns_with_overrides(config.dns_overrides)? | ||||
|                     } | ||||
|                 } | ||||
|                 #[cfg(not(feature = "trust-dns"))] | ||||
|                 true => unreachable!("trust-dns shouldn't be enabled unless the feature is"), | ||||
|             }; | ||||
| @@ -1037,6 +1051,19 @@ impl ClientBuilder { | ||||
|         self.config.https_only = enabled; | ||||
|         self | ||||
|     } | ||||
|  | ||||
|     /// Override DNS resolution for specific domains to particular IP addresses. | ||||
|     /// | ||||
|     /// Warning | ||||
|     /// | ||||
|     /// Since the DNS protocol has no notion of ports, if you wish to send | ||||
|     /// traffic to a particular port you must include this port in the URL | ||||
|     /// itself, any port in the overridden addr will be ignored and traffic sent | ||||
|     /// to the conventional port for the given scheme (e.g. 80 for http). | ||||
|     pub fn resolve(mut self, domain: &str, addr: SocketAddr) -> ClientBuilder { | ||||
|         self.config.dns_overrides.insert(domain.to_string(), addr); | ||||
|         self | ||||
|     } | ||||
| } | ||||
|  | ||||
| type HyperClient = hyper::Client<Connector, super::body::ImplStream>; | ||||
| @@ -1350,6 +1377,10 @@ impl Config { | ||||
|         { | ||||
|             f.field("tls_backend", &self.tls); | ||||
|         } | ||||
|  | ||||
|         if !self.dns_overrides.is_empty() { | ||||
|             f.field("dns_overrides", &self.dns_overrides); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user