diff --git a/Cargo.lock b/Cargo.lock index bf1cfa89..0dc5b42c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1782,6 +1782,8 @@ dependencies = [ "futures-io", "futures-util", "h2", + "h3", + "h3-quinn", "http", "idna", "ipnet", @@ -1790,6 +1792,7 @@ dependencies = [ "rand", "ring", "rustls", + "rustls-native-certs", "rustls-pemfile", "thiserror", "tinyvec", diff --git a/g3bench/CHANGELOG b/g3bench/CHANGELOG index 460465b6..42616f5a 100644 --- a/g3bench/CHANGELOG +++ b/g3bench/CHANGELOG @@ -1,4 +1,7 @@ +v0.8.4: + - Feature: support dns over http/3 in dns target + v0.8.3: - BUG FIX: fix the load of x509 cert in keyless target diff --git a/g3bench/Cargo.toml b/g3bench/Cargo.toml index aaa0152e..b76178c7 100644 --- a/g3bench/Cargo.toml +++ b/g3bench/Cargo.toml @@ -35,8 +35,8 @@ ahash.workspace = true rustc-hash.workspace = true concurrent-queue = "2.2" hex.workspace = true -hickory-client = { workspace = true, features = ["dns-over-rustls", "dns-over-https-rustls", "dns-over-quic"] } -hickory-proto.workspace = true +hickory-client = { workspace = true, features = ["dns-over-rustls", "dns-over-https-rustls", "dns-over-quic", "native-certs"] } +hickory-proto = { workspace = true, features = ["dns-over-h3"] } g3-runtime = { workspace = true, features = ["openssl"] } g3-signal.workspace = true g3-types = { workspace = true, features = ["proxy", "openssl", "rustls"] } diff --git a/g3bench/README.md b/g3bench/README.md index 0c7cebd3..c38cc124 100644 --- a/g3bench/README.md +++ b/g3bench/README.md @@ -43,6 +43,7 @@ Benchmark tool for HTTP 1.x / HTTP 2 / HTTP 3 / TLS Handshake / DNS / Cloudflare * DNS over TCP * DNS over TLS * DNS over HTTPS + * DNS over HTTP/3 * DNS over QUIC - *Cloudflare Keyless* diff --git a/g3bench/src/target/dns/opts.rs b/g3bench/src/target/dns/opts.rs index 2381a90c..9d746045 100644 --- a/g3bench/src/target/dns/opts.rs +++ b/g3bench/src/target/dns/opts.rs @@ -46,7 +46,7 @@ const DNS_ARG_QUERY_REQUESTS: &str = "query-requests"; const DNS_ARG_DUMP_RESULT: &str = "dump-result"; const DNS_ARG_ITER_GLOBAL: &str = "iter-global"; -const DNS_ENCRYPTION_PROTOCOLS: [&str; 3] = ["dot", "doh", "doq"]; +const DNS_ENCRYPTION_PROTOCOLS: [&str; 4] = ["dot", "doh", "doh3", "doq"]; #[derive(Default)] pub(super) struct GlobalRequestPicker { @@ -134,7 +134,11 @@ impl BenchDnsArgs { .await } DnsEncryptionProtocol::Https => { - self.new_dns_over_https_client(tls_client.driver.clone(), tls_name) + self.new_dns_over_h2_client(tls_client.driver.clone(), tls_name) + .await + } + DnsEncryptionProtocol::H3 => { + self.new_dns_over_h3_client(tls_client.driver.as_ref(), tls_name) .await } DnsEncryptionProtocol::Quic => { @@ -196,7 +200,7 @@ impl BenchDnsArgs { Ok(client) } - async fn new_dns_over_https_client( + async fn new_dns_over_h2_client( &self, tls_client: Arc, tls_name: String, @@ -210,7 +214,26 @@ impl BenchDnsArgs { let (client, bg) = AsyncClient::connect(client_connect) .await - .map_err(|e| anyhow!("failed to create udp async client: {e}"))?; + .map_err(|e| anyhow!("failed to create h2 async client: {e}"))?; + tokio::spawn(bg); + Ok(client) + } + + async fn new_dns_over_h3_client( + &self, + tls_client: &ClientConfig, + tls_name: String, + ) -> anyhow::Result { + let mut builder = hickory_proto::h3::H3ClientStream::builder(); + builder.crypto_config(tls_client.clone()); + if let Some(addr) = self.bind { + builder.bind_addr(addr); + } + let client_connect = builder.build(self.target, tls_name); + + let (client, bg) = AsyncClient::connect(client_connect) + .await + .map_err(|e| anyhow!("failed to create h3 async client: {e}"))?; tokio::spawn(bg); Ok(client) } diff --git a/g3proxy/CHANGELOG b/g3proxy/CHANGELOG index 433eabd8..210dcdb9 100644 --- a/g3proxy/CHANGELOG +++ b/g3proxy/CHANGELOG @@ -1,6 +1,8 @@ v1.7.27: - Optimization: set default c-ares init options as c-ares 1.20.1 default values + - Feature: rename trust-dns resolver type to hickory to be sync with upstream + - Feature: add dns over http/3 support in hickory resolver v1.7.26: - BUG FIX: fix deb and rpm build scripts diff --git a/g3proxy/README.md b/g3proxy/README.md index 9abeeb6e..4288b19d 100644 --- a/g3proxy/README.md +++ b/g3proxy/README.md @@ -156,6 +156,7 @@ tcp streaming / tls streaming / transparent proxy / reverse proxy. * UDP / TCP * DNS over TLS * DNS over HTTPS + * DNS over HTTP/3 * DNS over QUIC - fail-over diff --git a/g3proxy/doc/configuration/values/network.rst b/g3proxy/doc/configuration/values/network.rst index e00fc4fd..bf4c7181 100644 --- a/g3proxy/doc/configuration/values/network.rst +++ b/g3proxy/doc/configuration/values/network.rst @@ -763,6 +763,10 @@ The followings values are supported: .. _dns over https: https://datatracker.ietf.org/doc/html/rfc8484 +* dns-over-http/3 | doh3 | h3 + + If *dns over http/3* should be used. + * dns-over-quic | doq | quic If `dns over quic`_ should be used. @@ -771,6 +775,8 @@ The followings values are supported: .. versionchanged:: added dns over quic support since version 1.7.15 +.. versionchanged:: added dns over http/3 support since version 1.7.27 + .. _conf_value_dns_encryption_config: dns encryption config diff --git a/lib/g3-resolver/Cargo.toml b/lib/g3-resolver/Cargo.toml index e782a0e0..85bea55b 100644 --- a/lib/g3-resolver/Cargo.toml +++ b/lib/g3-resolver/Cargo.toml @@ -16,7 +16,7 @@ indexmap.workspace = true ahash.workspace = true c-ares = { package = "mini-c-ares", version = "0.2.1", optional = true } c-ares-resolver = { package = "mini-c-ares-resolver", version = "0.2", optional = true } -hickory-resolver = { workspace = true, optional = true, features = ["tokio-runtime", "dns-over-rustls", "dns-over-https-rustls", "dns-over-quic"] } +hickory-resolver = { workspace = true, optional = true, features = ["tokio-runtime", "dns-over-rustls", "dns-over-https-rustls", "dns-over-quic", "dns-over-h3"] } hickory-proto = { workspace = true, optional = true } rustls = { workspace = true, optional = true } g3-types = { workspace = true, optional = true } diff --git a/lib/g3-resolver/src/driver/hickory/config.rs b/lib/g3-resolver/src/driver/hickory/config.rs index 374cbb6b..c7188d0d 100644 --- a/lib/g3-resolver/src/driver/hickory/config.rs +++ b/lib/g3-resolver/src/driver/hickory/config.rs @@ -100,6 +100,12 @@ impl TryFrom<&HickoryDriverConfig> for NameServerConfigGroup { tls_name, false, ), + DnsEncryptionProtocol::H3 => NameServerConfigGroup::from_ips_h3( + &c.servers, + c.server_port.unwrap_or(443), + tls_name, + false, + ), DnsEncryptionProtocol::Quic => NameServerConfigGroup::from_ips_quic( &c.servers, c.server_port.unwrap_or(853), diff --git a/lib/g3-types/src/net/dns/encryption.rs b/lib/g3-types/src/net/dns/encryption.rs index c5f97b69..86dde71c 100644 --- a/lib/g3-types/src/net/dns/encryption.rs +++ b/lib/g3-types/src/net/dns/encryption.rs @@ -25,6 +25,7 @@ use crate::net::{RustlsClientConfig, RustlsClientConfigBuilder}; pub enum DnsEncryptionProtocol { Tls, Https, + H3, Quic, } @@ -34,7 +35,12 @@ impl FromStr for DnsEncryptionProtocol { fn from_str(s: &str) -> Result { match s.to_ascii_lowercase().replace('-', "_").as_str() { "tls" | "dns_over_tls" | "dnsovertls" | "dot" => Ok(DnsEncryptionProtocol::Tls), - "https" | "dns_over_https" | "dnsoverhttps" | "doh" => Ok(DnsEncryptionProtocol::Https), + "https" | "h2" | "dns_over_https" | "dnsoverhttps" | "doh" => { + Ok(DnsEncryptionProtocol::Https) + } + "h3" | "http/3" | "dns_over_http/3" | "dnsoverhttp/3" | "doh3" => { + Ok(DnsEncryptionProtocol::H3) + } "quic" | "dns_over_quic" | "dnsoverquic" | "doq" => Ok(DnsEncryptionProtocol::Quic), _ => Err(anyhow!("unknown protocol {}", s)), } @@ -46,6 +52,7 @@ impl DnsEncryptionProtocol { match self { DnsEncryptionProtocol::Tls => "DnsOverTls", DnsEncryptionProtocol::Https => "DnsOverHttps", + DnsEncryptionProtocol::H3 => "DnsOverHttp/3", DnsEncryptionProtocol::Quic => "DnsOverQuic", } } @@ -54,6 +61,7 @@ impl DnsEncryptionProtocol { match self { DnsEncryptionProtocol::Tls => 853, DnsEncryptionProtocol::Https => 443, + DnsEncryptionProtocol::H3 => 443, DnsEncryptionProtocol::Quic => 853, } }