diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d49c5fa..cb4dd37 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,8 +30,6 @@ jobs: key: ${{ runner.os }}-cargo-${{ matrix.rust-toolchain }} - name: Test code with default features run: cargo test - - name: Test code with all features - run: cargo test --all-features - name: Check code with only `tokio-dns-resolver` and `google` features enabled. run: cargo check --no-default-features --features tokio-dns-resolver,google - name: Check code with only `tokio-http-resolver` and `google` features enabled. diff --git a/Cargo.toml b/Cargo.toml index 5352329..2b0da8d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ include = ["src/**/*", "examples/**/*", "README.md", "LICENSE", "Cargo.toml"] keywords = ["public", "external", "ip", "async"] [features] -default = ["all-providers", "tokio-dns-resolver", "tokio-http-resolver"] +default = ["all-providers", "tokio-dns-resolver", "tokio-http-resolver", "https-openssl"] dns-resolver = ["trust-dns-proto"] http-resolver = ["http", "hyper", "hyper-system-resolver", "dns-lookup"] tokio-dns-resolver = ["dns-resolver", "tokio", "trust-dns-client", "trust-dns-proto/tokio-runtime"] @@ -24,8 +24,9 @@ https-openssl = ["hyper-openssl", "openssl", "tower-layer"] https-rustls-webpki = ["hyper-rustls/webpki-roots"] https-rustls-native = ["hyper-rustls/rustls-native-certs"] -all-providers = ["google", "opendns", "ipify-org", "my-ip-io", "myip-com", "seeip-org"] +all-providers = ["cloudflare", "google", "opendns", "ipify-org", "my-ip-io", "myip-com", "seeip-org"] +cloudflare = [] google = [] opendns = [] myip-com = [] diff --git a/src/dns.rs b/src/dns.rs index bdcbdf2..4e5ded8 100644 --- a/src/dns.rs +++ b/src/dns.rs @@ -9,6 +9,7 @@ use futures_util::{future, ready, stream, StreamExt}; use pin_project_lite::pin_project; use tracing::trace_span; use tracing_futures::Instrument; +use trust_dns_client::rr::DNSClass; use trust_dns_proto::{ error::{ProtoError, ProtoErrorKind}, op::Query, @@ -35,6 +36,8 @@ pub const ALL: &dyn crate::Resolver<'static> = &&[ OPENDNS, #[cfg(feature = "google")] GOOGLE, + #[cfg(feature = "cloudflare")] + CLOUDFLARE, ]; /// Combined OpenDNS IPv4 and IPv6 options. @@ -55,6 +58,7 @@ pub const OPENDNS_V4: &dyn crate::Resolver<'static> = &Resolver::new_static( ], DEFAULT_DNS_PORT, QueryMethod::A, + DNSClass::IN, ); /// OpenDNS IPv6 DNS resolver options. @@ -70,6 +74,7 @@ pub const OPENDNS_V6: &dyn crate::Resolver<'static> = &Resolver::new_static( ], DEFAULT_DNS_PORT, QueryMethod::AAAA, + DNSClass::IN, ); /// Combined Google DNS IPv4 and IPv6 options @@ -90,6 +95,7 @@ pub const GOOGLE_V4: &dyn crate::Resolver<'static> = &Resolver::new_static( ], DEFAULT_DNS_PORT, QueryMethod::TXT, + DNSClass::IN, ); /// Google DNS IPv6 DNS resolver options @@ -109,6 +115,42 @@ pub const GOOGLE_V6: &dyn crate::Resolver<'static> = &Resolver::new_static( ], DEFAULT_DNS_PORT, QueryMethod::TXT, + DNSClass::IN, +); + +/// Combined Cloudflare DNS IPv4 and IPv6 options +#[cfg(feature = "cloudflare")] +#[cfg_attr(docsrs, doc(cfg(feature = "cloudflare")))] +pub const CLOUDFLARE: &dyn crate::Resolver<'static> = &&[CLOUDFLARE_V4, CLOUDFLARE_V6]; + +/// Cloudflare DNS IPv4 DNS resolver options +#[cfg(feature = "cloudflare")] +#[cfg_attr(docsrs, doc(cfg(feature = "cloudflare")))] +pub const CLOUDFLARE_V4: &dyn crate::Resolver<'static> = &Resolver::new_static( + "whoami.cloudflare", + &[ + IpAddr::V4(Ipv4Addr::new(1, 1, 1, 1)), + IpAddr::V4(Ipv4Addr::new(1, 0, 0, 1)), + ], + DEFAULT_DNS_PORT, + QueryMethod::TXT, + DNSClass::CH, +); + +/// Cloudflare DNS IPv6 DNS resolver options +#[cfg(feature = "cloudflare")] +#[cfg_attr(docsrs, doc(cfg(feature = "cloudflare")))] +pub const CLOUDFLARE_V6: &dyn crate::Resolver<'static> = &Resolver::new_static( + "whoami.cloudflare", + &[ + // 2606:4700:4700::1111 + IpAddr::V6(Ipv6Addr::new(9734, 18176, 18176, 0, 0, 0, 0, 4369)), + // 2606:4700:4700::1001 + IpAddr::V6(Ipv6Addr::new(9734, 18176, 18176, 0, 0, 0, 0, 4097)), + ], + DEFAULT_DNS_PORT, + QueryMethod::TXT, + DNSClass::CH, ); /////////////////////////////////////////////////////////////////////////////// @@ -170,11 +212,12 @@ pub struct Resolver<'r> { name: Cow<'r, str>, servers: Cow<'r, [IpAddr]>, method: QueryMethod, + class: DNSClass, } impl<'r> Resolver<'r> { /// Create a new DNS resolver. - pub fn new(name: N, servers: S, port: u16, method: QueryMethod) -> Self + pub fn new(name: N, servers: S, port: u16, method: QueryMethod, class: DNSClass) -> Self where N: Into>, S: Into>, @@ -184,6 +227,7 @@ impl<'r> Resolver<'r> { name: name.into(), servers: servers.into(), method, + class, } } } @@ -196,12 +240,14 @@ impl Resolver<'static> { servers: &'static [IpAddr], port: u16, method: QueryMethod, + class: DNSClass, ) -> Self { Self { port, name: Cow::Borrowed(name), servers: Cow::Borrowed(servers), method, + class, } } } @@ -230,7 +276,8 @@ impl<'r> crate::Resolver<'r> for Resolver<'r> { QueryMethod::TXT => RecordType::TXT, }; let span = trace_span!("dns resolver", ?version, ?method, %name, %port); - let query = Query::query(name, record_type); + let mut query = Query::query(name, record_type); + query.set_query_class(self.class); let stream = resolve(first_server, port, query.clone(), method); let resolutions = DnsResolutions { port, diff --git a/src/lib.rs b/src/lib.rs index 8aea61c..4d1c971 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,6 +38,13 @@ mod error; ))] compile_error!("tokio is not enabled and is the only supported runtime currently - consider creating a PR or issue"); +#[cfg(any( + all(feature = "https-openssl", feature = "https-rustls-native"), + all(feature = "https-openssl", feature = "https-rustls-webpki"), + all(feature = "https-rustls-native", feature = "https-rustls-webpki") +))] +compile_error!("only one of https-openssl/https-rustls-native/https-rustls-webpki can be enabled"); + /// DNS resolver support. #[cfg(feature = "dns-resolver")] #[cfg_attr(docsrs, doc(cfg(feature = "dns-resolver")))]