From 47330ebcade881a1da7a26ee219869427e11e4bf Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Tue, 31 Jan 2023 00:00:21 +0100 Subject: [PATCH 01/41] Update deps --- src/libdoh/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libdoh/Cargo.toml b/src/libdoh/Cargo.toml index b0c2757..909f861 100644 --- a/src/libdoh/Cargo.toml +++ b/src/libdoh/Cargo.toml @@ -20,11 +20,11 @@ arc-swap = "1.6.0" base64 = "0.20.0" byteorder = "1.4.3" bytes = "1.3.0" -futures = "0.3.25" +futures = "0.3.26" hyper = { version = "0.14.23", default-features = false, features = ["server", "http1", "http2", "stream"] } -odoh-rs = "1.0.0" +odoh-rs = "1.0.1" rand = "0.8.5" -tokio = { version = "1.24.1", features = ["net", "rt-multi-thread", "time", "sync"] } +tokio = { version = "1.25.0", features = ["net", "rt-multi-thread", "time", "sync"] } tokio-rustls = { version = "0.23.4", features = ["early-data"], optional = true } rustls-pemfile = "1.0.2" From 11d8f4cb31ae0f2eaa9ba7841d4068509e066517 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Wed, 1 Feb 2023 20:28:37 +0100 Subject: [PATCH 02/41] Add a logo --- README.md | 2 +- logo.png | Bin 0 -> 59408 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 logo.png diff --git a/README.md b/README.md index 2542d56..971fdc2 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# DoH Server (and ODoH server) +# ![DoH server (and ODoH - Oblivious DoH server)](logo.png) A fast and secure DoH (DNS-over-HTTPS) and ODoH (Oblivious DoH) server. diff --git a/logo.png b/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..21e85fda91ef3ecd99154959ad386a4cd7af1e6c GIT binary patch literal 59408 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 DMnP+? literal 0 HcmV?d00001 From b5d525abcd871b3522239b38efcd571089be17c3 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 9 Feb 2023 16:58:31 +0100 Subject: [PATCH 03/41] Update deps --- src/libdoh/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libdoh/Cargo.toml b/src/libdoh/Cargo.toml index 909f861..50a1841 100644 --- a/src/libdoh/Cargo.toml +++ b/src/libdoh/Cargo.toml @@ -15,13 +15,13 @@ default = ["tls"] tls = ["tokio-rustls"] [dependencies] -anyhow = "1.0.68" +anyhow = "1.0.69" arc-swap = "1.6.0" base64 = "0.20.0" byteorder = "1.4.3" -bytes = "1.3.0" +bytes = "1.4.0" futures = "0.3.26" -hyper = { version = "0.14.23", default-features = false, features = ["server", "http1", "http2", "stream"] } +hyper = { version = "0.14.24", default-features = false, features = ["server", "http1", "http2", "stream"] } odoh-rs = "1.0.1" rand = "0.8.5" tokio = { version = "1.25.0", features = ["net", "rt-multi-thread", "time", "sync"] } From 651224d900d600ea7d0e07e6767d0e48709e3d8e Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 9 Feb 2023 16:58:58 +0100 Subject: [PATCH 04/41] Format --- src/libdoh/src/lib.rs | 3 ++- src/libdoh/src/tls.rs | 8 ++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/libdoh/src/lib.rs b/src/libdoh/src/lib.rs index 3022a7b..06ee661 100644 --- a/src/libdoh/src/lib.rs +++ b/src/libdoh/src/lib.rs @@ -433,7 +433,8 @@ impl DoH { .header( hyper::header::CACHE_CONTROL, format!( - "max-age={ttl}, stale-if-error={STALE_IF_ERROR_SECS}, stale-while-revalidate={STALE_WHILE_REVALIDATE_SECS}" + "max-age={ttl}, stale-if-error={STALE_IF_ERROR_SECS}, \ + stale-while-revalidate={STALE_WHILE_REVALIDATE_SECS}" ) .as_str(), ); diff --git a/src/libdoh/src/tls.rs b/src/libdoh/src/tls.rs index ccc4585..7047f99 100644 --- a/src/libdoh/src/tls.rs +++ b/src/libdoh/src/tls.rs @@ -29,9 +29,7 @@ where let mut reader = BufReader::new(File::open(certs_path).map_err(|e| { io::Error::new( e.kind(), - format!( - "Unable to load the certificates [{certs_path_str}]: {e}" - ), + format!("Unable to load the certificates [{certs_path_str}]: {e}"), ) })?); rustls_pemfile::certs(&mut reader).map_err(|_| { @@ -52,9 +50,7 @@ where .map_err(|e| { io::Error::new( e.kind(), - format!( - "Unable to load the certificate keys [{certs_keys_path_str}]: {e}" - ), + format!("Unable to load the certificate keys [{certs_keys_path_str}]: {e}"), ) })? .read_to_end(&mut encoded_keys)?; From 920d31b5027b6ad2fc66a053d99b6e3c9c3c0bab Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 9 Feb 2023 17:16:34 +0100 Subject: [PATCH 05/41] Update relayd URL --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 971fdc2..625eac8 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ Here, `doh.example.com` is the host name (which should match a name included in ## HTTP/2 termination -The recommended way to use `doh-proxy` is to use a TLS termination proxy (such as [hitch](https://github.com/varnish/hitch) or [relayd](https://bsd.plumbing/about.html)), a CDN or a web server with proxying abilities as a front-end. +The recommended way to use `doh-proxy` is to use a TLS termination proxy (such as [hitch](https://github.com/varnish/hitch) or [relayd](https://man.openbsd.org/relayd.8)), a CDN or a web server with proxying abilities as a front-end. That way, the DoH service can be exposed as a virtual host, sharing the same IP addresses as existing websites. From 1386b7d13a8381da1d8c8d450a29ae05f757a378 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 9 Feb 2023 17:18:27 +0100 Subject: [PATCH 06/41] Mention HTTP/3 --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 625eac8..801902d 100644 --- a/README.md +++ b/README.md @@ -68,13 +68,13 @@ doh-proxy -H 'doh.example.com' -u 127.0.0.1:53 -g 233.252.0.5 Here, `doh.example.com` is the host name (which should match a name included in the TLS certificate), `127.0.0.1:53` is the address of the DNS resolver, and `233.252.0.5` is the public IP address of the DoH server. -## HTTP/2 termination +## HTTP/2 and HTTP/3 termination The recommended way to use `doh-proxy` is to use a TLS termination proxy (such as [hitch](https://github.com/varnish/hitch) or [relayd](https://man.openbsd.org/relayd.8)), a CDN or a web server with proxying abilities as a front-end. That way, the DoH service can be exposed as a virtual host, sharing the same IP addresses as existing websites. -If `doh-proxy` and the HTTP/2 front-end run on the same host, using the HTTP protocol to communicate between both is fine. +If `doh-proxy` and the HTTP/2 (/ HTTP/3) front-end run on the same host, using the HTTP protocol to communicate between both is fine. If both are on distinct networks, such as when using a CDN, `doh-proxy` can handle HTTPS requests, provided that it was compiled with the `tls` feature. @@ -136,7 +136,7 @@ This can be achieved with the `--allow-odoh-post` command-line switch. * When using DoH, DNS stamps should include a resolver IP address in order to remove a dependency on non-encrypted, non-authenticated, easy-to-block resolvers. * Unlike DNSCrypt where users must explicitly trust a DNS server's public key, the security of DoH relies on traditional public Certificate Authorities. Additional root certificates (required by governments, security software, enterprise gateways) installed on a client immediately make DoH vulnerable to MITM. In order to prevent this, DNS stamps should include the hash of the parent certificate. * TLS certificates are tied to host names. But domains expire, get reassigned and switch hands all the time. If a domain originally used for a DoH service gets a new, possibly malicious owner, clients still configured to use the service will blindly keep trusting it if the CA is the same. As a mitigation, the CA should sign an intermediate certificate (the only one present in the stamp), itself used to sign the name used by the DoH server. While commercial CAs offer this, Let's Encrypt currently doesn't. -* Make sure that the front-end supports HTTP/2 and TLS 1.3. +* Make sure that the front-end supports HTTP/2 and TLS 1.3, and optionally HTTP/3. * Internal DoH servers still require TLS certificates. So, if you are planning to deploy an internal server, you need to set up an internal CA, or add self-signed certificates to every single client. ## Example usage with `encrypted-dns-server` From 1c5c83803a325d8fececa77ea20b2a1d45f0bee9 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 9 Feb 2023 17:21:29 +0100 Subject: [PATCH 07/41] Remove optional requirement --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 801902d..52b45df 100644 --- a/README.md +++ b/README.md @@ -136,7 +136,7 @@ This can be achieved with the `--allow-odoh-post` command-line switch. * When using DoH, DNS stamps should include a resolver IP address in order to remove a dependency on non-encrypted, non-authenticated, easy-to-block resolvers. * Unlike DNSCrypt where users must explicitly trust a DNS server's public key, the security of DoH relies on traditional public Certificate Authorities. Additional root certificates (required by governments, security software, enterprise gateways) installed on a client immediately make DoH vulnerable to MITM. In order to prevent this, DNS stamps should include the hash of the parent certificate. * TLS certificates are tied to host names. But domains expire, get reassigned and switch hands all the time. If a domain originally used for a DoH service gets a new, possibly malicious owner, clients still configured to use the service will blindly keep trusting it if the CA is the same. As a mitigation, the CA should sign an intermediate certificate (the only one present in the stamp), itself used to sign the name used by the DoH server. While commercial CAs offer this, Let's Encrypt currently doesn't. -* Make sure that the front-end supports HTTP/2 and TLS 1.3, and optionally HTTP/3. +* Make sure that the front-end supports HTTP/2 and TLS 1.3. * Internal DoH servers still require TLS certificates. So, if you are planning to deploy an internal server, you need to set up an internal CA, or add self-signed certificates to every single client. ## Example usage with `encrypted-dns-server` From c54b3303fc739bc3d451ca2d214557512883a329 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Sun, 19 Feb 2023 21:02:28 +0100 Subject: [PATCH 08/41] Update base64, accept padding on decoding --- src/libdoh/src/lib.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/libdoh/src/lib.rs b/src/libdoh/src/lib.rs index 06ee661..4b6eea8 100644 --- a/src/libdoh/src/lib.rs +++ b/src/libdoh/src/lib.rs @@ -11,6 +11,7 @@ use std::pin::Pin; use std::sync::Arc; use std::time::Duration; +use base64::engine::Engine; use byteorder::{BigEndian, ByteOrder}; use futures::prelude::*; use futures::task::{Context, Poll}; @@ -29,10 +30,12 @@ pub mod reexports { pub use tokio; } -const BASE64_URL_SAFE_NO_PAD: base64::engine::fast_portable::FastPortable = - base64::engine::fast_portable::FastPortable::from( +const BASE64_URL_SAFE_NO_PAD: base64::engine::GeneralPurpose = + base64::engine::general_purpose::GeneralPurpose::new( &base64::alphabet::URL_SAFE, - base64::engine::fast_portable::NO_PAD, + base64::engine::general_purpose::GeneralPurposeConfig::new() + .with_encode_padding(false) + .with_decode_padding_mode(base64::engine::DecodePaddingMode::Indifferent), ); #[derive(Clone, Debug)] @@ -167,9 +170,9 @@ impl DoH { return None; } } - let query = match question_str.and_then(|question_str| { - base64::decode_engine(question_str, &BASE64_URL_SAFE_NO_PAD).ok() - }) { + let query = match question_str + .and_then(|question_str| BASE64_URL_SAFE_NO_PAD.decode(question_str).ok()) + { Some(query) => query, _ => return None, }; From 908e7d64dba40fdc32ef2be34a92bba07b6673a2 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Sun, 19 Feb 2023 21:05:34 +0100 Subject: [PATCH 09/41] Update base64 --- src/libdoh/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libdoh/Cargo.toml b/src/libdoh/Cargo.toml index 50a1841..8c6fece 100644 --- a/src/libdoh/Cargo.toml +++ b/src/libdoh/Cargo.toml @@ -17,7 +17,7 @@ tls = ["tokio-rustls"] [dependencies] anyhow = "1.0.69" arc-swap = "1.6.0" -base64 = "0.20.0" +base64 = "0.21.0" byteorder = "1.4.3" bytes = "1.4.0" futures = "0.3.26" From 18297228c74ef8cf0aec5cc0edb01377445b9964 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Sun, 19 Feb 2023 21:10:14 +0100 Subject: [PATCH 10/41] Bump --- Cargo.toml | 4 ++-- src/libdoh/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index af348d8..3c13e6f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "doh-proxy" -version = "0.9.7" +version = "0.9.8" authors = ["Frank Denis "] description = "A DNS-over-HTTPS (DoH) and ODoH (Oblivious DoH) proxy" keywords = ["dns", "https", "doh", "odoh", "proxy"] @@ -16,7 +16,7 @@ default = ["tls"] tls = ["libdoh/tls"] [dependencies] -libdoh = { path = "src/libdoh", version = "0.9.7", default-features = false } +libdoh = { path = "src/libdoh", version = "0.9.8", default-features = false } clap = { version = "4", features = ["std", "cargo", "wrap_help", "string"] } dnsstamps = "0.1.9" mimalloc = { version = "0.1.34", default-features = false } diff --git a/src/libdoh/Cargo.toml b/src/libdoh/Cargo.toml index 8c6fece..63ce489 100644 --- a/src/libdoh/Cargo.toml +++ b/src/libdoh/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libdoh" -version = "0.9.7" +version = "0.9.8" authors = ["Frank Denis "] description = "DoH and Oblivious DoH library for the rust-doh app" keywords = ["dns","https","doh","odoh","proxy"] From f64770bdd7132b38d546a5f9328afe7fbb3f74ea Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Sun, 19 Feb 2023 21:44:31 +0100 Subject: [PATCH 11/41] Install zig 0.10.1 --- .github/workflows/release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f07e45d..dcf2991 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,6 +17,7 @@ jobs: - uses: actions/checkout@v3 - uses: goto-bus-stop/setup-zig@v2 + version: 0.10.1 - uses: hecrj/setup-rust-action@master with: From 6580f6ffb52ff3452bee6f5b596a59cc350fb14d Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Sun, 19 Feb 2023 21:50:08 +0100 Subject: [PATCH 12/41] Fix CI --- .github/workflows/release.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index dcf2991..a3c8be0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,7 +17,8 @@ jobs: - uses: actions/checkout@v3 - uses: goto-bus-stop/setup-zig@v2 - version: 0.10.1 + with: + version: 0.10.1 - uses: hecrj/setup-rust-action@master with: From ffa082851576f518625b7174b437bc05af9ada52 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 2 Mar 2023 19:05:11 +0100 Subject: [PATCH 13/41] Update tokio --- src/libdoh/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libdoh/Cargo.toml b/src/libdoh/Cargo.toml index 63ce489..f60a1c4 100644 --- a/src/libdoh/Cargo.toml +++ b/src/libdoh/Cargo.toml @@ -24,7 +24,7 @@ futures = "0.3.26" hyper = { version = "0.14.24", default-features = false, features = ["server", "http1", "http2", "stream"] } odoh-rs = "1.0.1" rand = "0.8.5" -tokio = { version = "1.25.0", features = ["net", "rt-multi-thread", "time", "sync"] } +tokio = { version = "1.26.0", features = ["net", "rt-multi-thread", "time", "sync"] } tokio-rustls = { version = "0.23.4", features = ["early-data"], optional = true } rustls-pemfile = "1.0.2" From 678bd04bed08dcf097f7eeef3b0172fd27018d26 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 13 Apr 2023 17:12:29 +0200 Subject: [PATCH 14/41] Update deps --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3c13e6f..0f880cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ tls = ["libdoh/tls"] libdoh = { path = "src/libdoh", version = "0.9.8", default-features = false } clap = { version = "4", features = ["std", "cargo", "wrap_help", "string"] } dnsstamps = "0.1.9" -mimalloc = { version = "0.1.34", default-features = false } +mimalloc = { version = "0.1.36", default-features = false } [package.metadata.deb] extended-description = """\ From 6f9f63e754dd700ed8215c2cb45d43ffad96f097 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 13 Apr 2023 17:13:03 +0200 Subject: [PATCH 15/41] Update deps, especially hyper --- src/libdoh/Cargo.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libdoh/Cargo.toml b/src/libdoh/Cargo.toml index f60a1c4..0ee20e8 100644 --- a/src/libdoh/Cargo.toml +++ b/src/libdoh/Cargo.toml @@ -15,16 +15,16 @@ default = ["tls"] tls = ["tokio-rustls"] [dependencies] -anyhow = "1.0.69" +anyhow = "1.0.70" arc-swap = "1.6.0" base64 = "0.21.0" byteorder = "1.4.3" bytes = "1.4.0" -futures = "0.3.26" -hyper = { version = "0.14.24", default-features = false, features = ["server", "http1", "http2", "stream"] } +futures = "0.3.28" +hyper = { version = "0.14.25", default-features = false, features = ["server", "http1", "http2", "stream"] } odoh-rs = "1.0.1" rand = "0.8.5" -tokio = { version = "1.26.0", features = ["net", "rt-multi-thread", "time", "sync"] } +tokio = { version = "1.27.0", features = ["net", "rt-multi-thread", "time", "sync"] } tokio-rustls = { version = "0.23.4", features = ["early-data"], optional = true } rustls-pemfile = "1.0.2" From 19040f1e884e4b9c381f79bcd189ad71c03675c7 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Fri, 14 Apr 2023 09:45:20 +0200 Subject: [PATCH 16/41] Nits --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 52b45df..91e0783 100644 --- a/README.md +++ b/README.md @@ -136,7 +136,7 @@ This can be achieved with the `--allow-odoh-post` command-line switch. * When using DoH, DNS stamps should include a resolver IP address in order to remove a dependency on non-encrypted, non-authenticated, easy-to-block resolvers. * Unlike DNSCrypt where users must explicitly trust a DNS server's public key, the security of DoH relies on traditional public Certificate Authorities. Additional root certificates (required by governments, security software, enterprise gateways) installed on a client immediately make DoH vulnerable to MITM. In order to prevent this, DNS stamps should include the hash of the parent certificate. * TLS certificates are tied to host names. But domains expire, get reassigned and switch hands all the time. If a domain originally used for a DoH service gets a new, possibly malicious owner, clients still configured to use the service will blindly keep trusting it if the CA is the same. As a mitigation, the CA should sign an intermediate certificate (the only one present in the stamp), itself used to sign the name used by the DoH server. While commercial CAs offer this, Let's Encrypt currently doesn't. -* Make sure that the front-end supports HTTP/2 and TLS 1.3. +* Make sure that the front-end supports at least HTTP/2 and TLS 1.3. * Internal DoH servers still require TLS certificates. So, if you are planning to deploy an internal server, you need to set up an internal CA, or add self-signed certificates to every single client. ## Example usage with `encrypted-dns-server` From e8df0458ac79b2b1d72c974b66641931c891b1d2 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Fri, 14 Apr 2023 12:38:08 +0200 Subject: [PATCH 17/41] Bump hyper. Again. --- src/libdoh/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libdoh/Cargo.toml b/src/libdoh/Cargo.toml index 0ee20e8..603218b 100644 --- a/src/libdoh/Cargo.toml +++ b/src/libdoh/Cargo.toml @@ -21,7 +21,7 @@ base64 = "0.21.0" byteorder = "1.4.3" bytes = "1.4.0" futures = "0.3.28" -hyper = { version = "0.14.25", default-features = false, features = ["server", "http1", "http2", "stream"] } +hyper = { version = "0.14.26", default-features = false, features = ["server", "http1", "http2", "stream"] } odoh-rs = "1.0.1" rand = "0.8.5" tokio = { version = "1.27.0", features = ["net", "rt-multi-thread", "time", "sync"] } From e5f6f2a5d65f29af0e97597041ce6f8604e01d87 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Fri, 14 Apr 2023 12:44:12 +0200 Subject: [PATCH 18/41] Bump --- Cargo.toml | 4 ++-- src/libdoh/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0f880cc..e37d98a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "doh-proxy" -version = "0.9.8" +version = "0.9.9" authors = ["Frank Denis "] description = "A DNS-over-HTTPS (DoH) and ODoH (Oblivious DoH) proxy" keywords = ["dns", "https", "doh", "odoh", "proxy"] @@ -16,7 +16,7 @@ default = ["tls"] tls = ["libdoh/tls"] [dependencies] -libdoh = { path = "src/libdoh", version = "0.9.8", default-features = false } +libdoh = { path = "src/libdoh", version = "0.9.9", default-features = false } clap = { version = "4", features = ["std", "cargo", "wrap_help", "string"] } dnsstamps = "0.1.9" mimalloc = { version = "0.1.36", default-features = false } diff --git a/src/libdoh/Cargo.toml b/src/libdoh/Cargo.toml index 603218b..ef65f30 100644 --- a/src/libdoh/Cargo.toml +++ b/src/libdoh/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libdoh" -version = "0.9.8" +version = "0.9.9" authors = ["Frank Denis "] description = "DoH and Oblivious DoH library for the rust-doh app" keywords = ["dns","https","doh","odoh","proxy"] From 9e2853da86990d782a50e2fe882eda79626a8891 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Wed, 3 May 2023 17:35:23 +0200 Subject: [PATCH 19/41] Update deps --- Cargo.toml | 2 +- src/libdoh/Cargo.toml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e37d98a..2772885 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ tls = ["libdoh/tls"] libdoh = { path = "src/libdoh", version = "0.9.9", default-features = false } clap = { version = "4", features = ["std", "cargo", "wrap_help", "string"] } dnsstamps = "0.1.9" -mimalloc = { version = "0.1.36", default-features = false } +mimalloc = { version = "0.1.37", default-features = false } [package.metadata.deb] extended-description = """\ diff --git a/src/libdoh/Cargo.toml b/src/libdoh/Cargo.toml index ef65f30..5c85b08 100644 --- a/src/libdoh/Cargo.toml +++ b/src/libdoh/Cargo.toml @@ -15,7 +15,7 @@ default = ["tls"] tls = ["tokio-rustls"] [dependencies] -anyhow = "1.0.70" +anyhow = "1.0.71" arc-swap = "1.6.0" base64 = "0.21.0" byteorder = "1.4.3" @@ -24,8 +24,8 @@ futures = "0.3.28" hyper = { version = "0.14.26", default-features = false, features = ["server", "http1", "http2", "stream"] } odoh-rs = "1.0.1" rand = "0.8.5" -tokio = { version = "1.27.0", features = ["net", "rt-multi-thread", "time", "sync"] } -tokio-rustls = { version = "0.23.4", features = ["early-data"], optional = true } +tokio = { version = "1.28.0", features = ["net", "rt-multi-thread", "time", "sync"] } +tokio-rustls = { version = "0.24.0", features = ["early-data"], optional = true } rustls-pemfile = "1.0.2" [profile.release] From 78c47830ff15e31d99810ea3478da9ce82fe60d2 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Sat, 15 Jul 2023 21:18:46 +0200 Subject: [PATCH 20/41] Update deps --- Cargo.toml | 2 +- src/libdoh/Cargo.toml | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2772885..1ac4cb5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "doh-proxy" -version = "0.9.9" +version = "0.9.10" authors = ["Frank Denis "] description = "A DNS-over-HTTPS (DoH) and ODoH (Oblivious DoH) proxy" keywords = ["dns", "https", "doh", "odoh", "proxy"] diff --git a/src/libdoh/Cargo.toml b/src/libdoh/Cargo.toml index 5c85b08..66fc1c3 100644 --- a/src/libdoh/Cargo.toml +++ b/src/libdoh/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libdoh" -version = "0.9.9" +version = "0.9.10" authors = ["Frank Denis "] description = "DoH and Oblivious DoH library for the rust-doh app" keywords = ["dns","https","doh","odoh","proxy"] @@ -17,16 +17,16 @@ tls = ["tokio-rustls"] [dependencies] anyhow = "1.0.71" arc-swap = "1.6.0" -base64 = "0.21.0" +base64 = "0.21.2" byteorder = "1.4.3" bytes = "1.4.0" futures = "0.3.28" -hyper = { version = "0.14.26", default-features = false, features = ["server", "http1", "http2", "stream"] } -odoh-rs = "1.0.1" +hyper = { version = "0.14.27", default-features = false, features = ["server", "http1", "http2", "stream"] } +odoh-rs = "1.0.2" rand = "0.8.5" -tokio = { version = "1.28.0", features = ["net", "rt-multi-thread", "time", "sync"] } -tokio-rustls = { version = "0.24.0", features = ["early-data"], optional = true } -rustls-pemfile = "1.0.2" +tokio = { version = "1.29.1", features = ["net", "rt-multi-thread", "time", "sync"] } +tokio-rustls = { version = "0.24.1", features = ["early-data"], optional = true } +rustls-pemfile = "1.0.3" [profile.release] codegen-units = 1 From c92308ccbb48ebea146da4fd83800d0d4d6d5315 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Sat, 2 Sep 2023 00:20:06 +0200 Subject: [PATCH 21/41] Update deps --- Cargo.toml | 2 +- src/libdoh/Cargo.toml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1ac4cb5..c7c46ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ tls = ["libdoh/tls"] libdoh = { path = "src/libdoh", version = "0.9.9", default-features = false } clap = { version = "4", features = ["std", "cargo", "wrap_help", "string"] } dnsstamps = "0.1.9" -mimalloc = { version = "0.1.37", default-features = false } +mimalloc = { version = "0.1.38", default-features = false } [package.metadata.deb] extended-description = """\ diff --git a/src/libdoh/Cargo.toml b/src/libdoh/Cargo.toml index 66fc1c3..55a26b6 100644 --- a/src/libdoh/Cargo.toml +++ b/src/libdoh/Cargo.toml @@ -15,16 +15,16 @@ default = ["tls"] tls = ["tokio-rustls"] [dependencies] -anyhow = "1.0.71" +anyhow = "1.0.75" arc-swap = "1.6.0" -base64 = "0.21.2" +base64 = "0.21.3" byteorder = "1.4.3" bytes = "1.4.0" futures = "0.3.28" hyper = { version = "0.14.27", default-features = false, features = ["server", "http1", "http2", "stream"] } odoh-rs = "1.0.2" rand = "0.8.5" -tokio = { version = "1.29.1", features = ["net", "rt-multi-thread", "time", "sync"] } +tokio = { version = "1.32.0", features = ["net", "rt-multi-thread", "time", "sync"] } tokio-rustls = { version = "0.24.1", features = ["early-data"], optional = true } rustls-pemfile = "1.0.3" From 1165fab90c0f0beee93e82e8bd019e090d97908b Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Wed, 6 Mar 2024 18:25:38 +0100 Subject: [PATCH 22/41] Update a few deps --- Cargo.toml | 2 +- src/libdoh/Cargo.toml | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c7c46ff..d38b674 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ tls = ["libdoh/tls"] libdoh = { path = "src/libdoh", version = "0.9.9", default-features = false } clap = { version = "4", features = ["std", "cargo", "wrap_help", "string"] } dnsstamps = "0.1.9" -mimalloc = { version = "0.1.38", default-features = false } +mimalloc = { version = "0.1.39", default-features = false } [package.metadata.deb] extended-description = """\ diff --git a/src/libdoh/Cargo.toml b/src/libdoh/Cargo.toml index 55a26b6..f7c2b46 100644 --- a/src/libdoh/Cargo.toml +++ b/src/libdoh/Cargo.toml @@ -15,18 +15,18 @@ default = ["tls"] tls = ["tokio-rustls"] [dependencies] -anyhow = "1.0.75" -arc-swap = "1.6.0" -base64 = "0.21.3" -byteorder = "1.4.3" -bytes = "1.4.0" -futures = "0.3.28" -hyper = { version = "0.14.27", default-features = false, features = ["server", "http1", "http2", "stream"] } +anyhow = "1.0.80" +arc-swap = "1.7.0" +base64 = "0.22.0" +byteorder = "1.5.0" +bytes = "1.5.0" +futures = "0.3.30" +hyper = { version = "^0.14.27", default-features = false, features = ["server", "http1", "http2", "stream"] } odoh-rs = "1.0.2" rand = "0.8.5" -tokio = { version = "1.32.0", features = ["net", "rt-multi-thread", "time", "sync"] } -tokio-rustls = { version = "0.24.1", features = ["early-data"], optional = true } -rustls-pemfile = "1.0.3" +tokio = { version = "1.36.0", features = ["net", "rt-multi-thread", "time", "sync"] } +tokio-rustls = { version = "^0.24.1", features = ["early-data"], optional = true } +rustls-pemfile = "^1.0.4" [profile.release] codegen-units = 1 From 66c66c7a28c4f1f7596cd697619c2482822458cb Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Sun, 5 May 2024 18:01:19 +0200 Subject: [PATCH 23/41] Update mimalloc --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d38b674..9d4cfde 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ tls = ["libdoh/tls"] libdoh = { path = "src/libdoh", version = "0.9.9", default-features = false } clap = { version = "4", features = ["std", "cargo", "wrap_help", "string"] } dnsstamps = "0.1.9" -mimalloc = { version = "0.1.39", default-features = false } +mimalloc = { version = "0.1.41", default-features = false } [package.metadata.deb] extended-description = """\ From 02b3a67a0087131dc95c71a4cc33426b914b4a2d Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Mon, 6 May 2024 12:22:21 +0200 Subject: [PATCH 24/41] Update hyper to 0.14.28 --- src/libdoh/Cargo.toml | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/libdoh/Cargo.toml b/src/libdoh/Cargo.toml index f7c2b46..b84c89c 100644 --- a/src/libdoh/Cargo.toml +++ b/src/libdoh/Cargo.toml @@ -3,11 +3,11 @@ name = "libdoh" version = "0.9.10" authors = ["Frank Denis "] description = "DoH and Oblivious DoH library for the rust-doh app" -keywords = ["dns","https","doh","odoh","proxy"] +keywords = ["dns", "https", "doh", "odoh", "proxy"] license = "MIT" homepage = "https://github.com/jedisct1/rust-doh" repository = "https://github.com/jedisct1/rust-doh" -categories = ["asynchronous", "network-programming","command-line-utilities"] +categories = ["asynchronous", "network-programming", "command-line-utilities"] edition = "2018" [features] @@ -21,11 +21,24 @@ base64 = "0.22.0" byteorder = "1.5.0" bytes = "1.5.0" futures = "0.3.30" -hyper = { version = "^0.14.27", default-features = false, features = ["server", "http1", "http2", "stream"] } +hyper = { version = "^0.14.28", default-features = false, features = [ + "server", + "http1", + "http2", + "stream", + "runtime", +] } odoh-rs = "1.0.2" rand = "0.8.5" -tokio = { version = "1.36.0", features = ["net", "rt-multi-thread", "time", "sync"] } -tokio-rustls = { version = "^0.24.1", features = ["early-data"], optional = true } +tokio = { version = "1.36.0", features = [ + "net", + "rt-multi-thread", + "time", + "sync", +] } +tokio-rustls = { version = "^0.24.1", features = [ + "early-data", +], optional = true } rustls-pemfile = "^1.0.4" [profile.release] From bd85572368859bfbeec3517c488f6feb24cafe76 Mon Sep 17 00:00:00 2001 From: demarcush <146051763+demarcush@users.noreply.github.com> Date: Tue, 14 May 2024 03:44:17 +0000 Subject: [PATCH 25/41] Update common hashes --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 91e0783..21fe75a 100644 --- a/README.md +++ b/README.md @@ -199,6 +199,8 @@ This [Go code snippet](https://gist.github.com/d6cb41742a1ceb54d48cc286f3d5c5fa) * `444ebd67bb83f8807b3921e938ac9178b882bd50aadb11231f044cf5f08df7ce` * Let's Encrypt E1: * `cc1060d39c8329b62b6fbc7d0d6df9309869b981e7e6392d5cd8fa408f4d80e6` +* ZeroSSL: + * `9a3a34f727deb9bca51003d9ce9c39f8f27dd9c5242901c2bab1a44e635a0219` ## Clients From 3511672d499551e4de8a76c91fbf1bd2b316eba1 Mon Sep 17 00:00:00 2001 From: demarcush <146051763+demarcush@users.noreply.github.com> Date: Tue, 2 Jul 2024 20:47:53 +0000 Subject: [PATCH 26/41] Add Let's Encrypt R10 --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 21fe75a..6b0c9f6 100644 --- a/README.md +++ b/README.md @@ -195,10 +195,12 @@ This [Go code snippet](https://gist.github.com/d6cb41742a1ceb54d48cc286f3d5c5fa) ### Common certificate hashes -* Let's Encrypt R3: - * `444ebd67bb83f8807b3921e938ac9178b882bd50aadb11231f044cf5f08df7ce` * Let's Encrypt E1: * `cc1060d39c8329b62b6fbc7d0d6df9309869b981e7e6392d5cd8fa408f4d80e6` +* Let's Encrypt R3: + * `444ebd67bb83f8807b3921e938ac9178b882bd50aadb11231f044cf5f08df7ce` +* Let's Encrypt R10: + * `e644ba6963e335fe765cb9976b12b10eb54294b42477764ccb3a3acca3acb2fc` * ZeroSSL: * `9a3a34f727deb9bca51003d9ce9c39f8f27dd9c5242901c2bab1a44e635a0219` From 7bb8293c2873488fcc2add905c4cb9cb2e9b7522 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Wed, 3 Jul 2024 12:33:29 +0200 Subject: [PATCH 27/41] package.metadata.generate-rpm --- Cargo.toml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 9d4cfde..5ba2356 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,12 @@ clap = { version = "4", features = ["std", "cargo", "wrap_help", "string"] } dnsstamps = "0.1.9" mimalloc = { version = "0.1.41", default-features = false } +[package.metadata.generate-rpm] +assets = [ + { source = "target/release/doh-proxy", dest = "/usr/bin/doh-proxy", mode = "755" }, + { source = "README.md", dest = "/usr/share/doc/doh-proxy/README.md", mode = "644", doc = true }, +] + [package.metadata.deb] extended-description = """\ A fast and secure DoH (DNS-over-HTTPS) and ODoH server written in Rust.""" From bafbdc0926e2f8246b90226faff0dcac62c004d9 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Wed, 3 Jul 2024 13:27:29 +0200 Subject: [PATCH 28/41] Try creating RPM packages Fixes #98 --- .github/workflows/release.yml | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a3c8be0..811b41d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,6 +33,9 @@ jobs: - name: Install cargo-deb run: cargo install cargo-deb + - name: Install cargo-generate-rpm + run: cargo install cargo-generate-rpm + - name: Install cargo-zigbuild run: cargo install cargo-zigbuild @@ -73,6 +76,16 @@ jobs: rustup target add aarch64-unknown-linux-musl env RUSTFLAGS="-C strip=symbols" cargo deb --no-strip --cargo-build=zigbuild --target=aarch64-unknown-linux-musl + - name: RPM packages + run: | + rustup target add x86_64-unknown-linux-gnu + env RUSTFLAGS="-C strip=symbols" cargo-zigbuild build --target=x86_64-unknown-linux-gnu.2.17 --release + mv target/x86_64-unknown-linux-musl/release/doh-proxy target/release/ + cargo generate-rpm --target x86_64-unknown-linux-gnu + rustup target add aarch64-unknown-linux-gnu + env RUSTFLAGS="-C strip=symbols" cargo-zigbuild build --target=aarch64-unknown-linux-gnu.2.17 --release + cargo generate-rpm --target aarch64-unknown-linux-gnu + - name: Create release id: create_release uses: actions/create-release@v1 @@ -95,6 +108,28 @@ jobs: asset_path: "target/x86_64-unknown-linux-musl/debian/doh-proxy_${{ steps.get_version.outputs.VERSION }}_amd64.deb" asset_content_type: application/x-debian-package + - name: Upload RPM package for x86_64 + id: upload-release-asset-rpm-x86_64 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_name: "doh-proxy-${{ steps.get_version.outputs.VERSION }}-1.x86_64.rpm" + asset_path: "target/x86_64-unknown-linux-gnu/generate-rpm/doh-proxy-${{ steps.get_version.outputs.VERSION }}-1.x86_64.rpm" + asset_content_type: application/x-redhat-package-manager + + - name: Upload RPM package for aarch64 + id: upload-release-asset-rpm-aarch64 + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_name: "doh-proxy-${{ steps.get_version.outputs.VERSION }}-1.aarch64.rpm" + asset_path: "target/aarch64-unknown-linux-gnu/generate-rpm/doh-proxy-${{ steps.get_version.outputs.VERSION }}-1.aarch64.rpm" + asset_content_type: application/x-redhat-package-manager + - name: Upload tarball for linux-x86_64 id: upload-release-asset-tarball-linux-x86_64 uses: actions/upload-release-asset@v1 From e73964fa1df37c616ad349b39ea5037d4e8adfd2 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Wed, 3 Jul 2024 13:52:56 +0200 Subject: [PATCH 29/41] Update deps --- Cargo.toml | 4 ++-- src/libdoh/Cargo.toml | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5ba2356..d7e7ca0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "doh-proxy" -version = "0.9.10" +version = "0.9.11" authors = ["Frank Denis "] description = "A DNS-over-HTTPS (DoH) and ODoH (Oblivious DoH) proxy" keywords = ["dns", "https", "doh", "odoh", "proxy"] @@ -19,7 +19,7 @@ tls = ["libdoh/tls"] libdoh = { path = "src/libdoh", version = "0.9.9", default-features = false } clap = { version = "4", features = ["std", "cargo", "wrap_help", "string"] } dnsstamps = "0.1.9" -mimalloc = { version = "0.1.41", default-features = false } +mimalloc = { version = "0.1.43", default-features = false } [package.metadata.generate-rpm] assets = [ diff --git a/src/libdoh/Cargo.toml b/src/libdoh/Cargo.toml index b84c89c..7b72764 100644 --- a/src/libdoh/Cargo.toml +++ b/src/libdoh/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "libdoh" -version = "0.9.10" +version = "0.9.11" authors = ["Frank Denis "] description = "DoH and Oblivious DoH library for the rust-doh app" keywords = ["dns", "https", "doh", "odoh", "proxy"] @@ -15,22 +15,22 @@ default = ["tls"] tls = ["tokio-rustls"] [dependencies] -anyhow = "1.0.80" -arc-swap = "1.7.0" -base64 = "0.22.0" +anyhow = "1.0.86" +arc-swap = "1.7.1" +base64 = "0.22.1" byteorder = "1.5.0" -bytes = "1.5.0" +bytes = "1.6.0" futures = "0.3.30" -hyper = { version = "^0.14.28", default-features = false, features = [ +hyper = { version = "^0.14.29", default-features = false, features = [ "server", "http1", "http2", "stream", "runtime", ] } -odoh-rs = "1.0.2" +odoh-rs = "1.0.3" rand = "0.8.5" -tokio = { version = "1.36.0", features = [ +tokio = { version = "1.38.0", features = [ "net", "rt-multi-thread", "time", From c79501aea30bbfe4780c91599a1361bb67f81614 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Wed, 3 Jul 2024 14:03:51 +0200 Subject: [PATCH 30/41] Use Zig 0.13 --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 811b41d..3e6c4ce 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,7 +18,7 @@ jobs: - uses: goto-bus-stop/setup-zig@v2 with: - version: 0.10.1 + version: 0.13 - uses: hecrj/setup-rust-action@master with: From d6635eebb717798529f73bb94b566b6cfd7e5282 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Wed, 3 Jul 2024 14:16:01 +0200 Subject: [PATCH 31/41] up --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3e6c4ce..5716724 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -104,8 +104,8 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.create_release.outputs.upload_url }} - asset_name: "doh-proxy_${{ steps.get_version.outputs.VERSION }}_amd64.deb" - asset_path: "target/x86_64-unknown-linux-musl/debian/doh-proxy_${{ steps.get_version.outputs.VERSION }}_amd64.deb" + asset_name: "doh-proxy_${{ steps.get_version.outputs.VERSION }}-1_amd64.deb" + asset_path: "target/x86_64-unknown-linux-musl/debian/doh-proxy_${{ steps.get_version.outputs.VERSION }}-1_amd64.deb" asset_content_type: application/x-debian-package - name: Upload RPM package for x86_64 From 34f614e938587a8576fa7392e6f96d40eeacd06c Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Wed, 3 Jul 2024 14:17:17 +0200 Subject: [PATCH 32/41] 0.13 -> 0.13.0 --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5716724..e71dd32 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,7 +18,7 @@ jobs: - uses: goto-bus-stop/setup-zig@v2 with: - version: 0.13 + version: 0.13.0 - uses: hecrj/setup-rust-action@master with: From 890a74276f33e380c513d56aa3b90d4b6157a2d7 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Wed, 3 Jul 2024 14:26:44 +0200 Subject: [PATCH 33/41] Downgrade to Zig 0.12.0 --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e71dd32..c226877 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,7 +18,7 @@ jobs: - uses: goto-bus-stop/setup-zig@v2 with: - version: 0.13.0 + version: 0.12.0 - uses: hecrj/setup-rust-action@master with: From 1a0a0566c4e9e93b73ecdc8d400949d8f7a94635 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Wed, 3 Jul 2024 14:38:16 +0200 Subject: [PATCH 34/41] Back to Zig 0.10.1 --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c226877..df1c604 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,7 +18,7 @@ jobs: - uses: goto-bus-stop/setup-zig@v2 with: - version: 0.12.0 + version: 0.10.1 - uses: hecrj/setup-rust-action@master with: From bf443c33b965619866c52300f4383d00d75d6248 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Mon, 4 Nov 2024 00:11:49 +0100 Subject: [PATCH 35/41] Switch to mlugg/setup-zig@v1 --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index df1c604..48f03a0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,7 +16,7 @@ jobs: - uses: actions/checkout@v3 - - uses: goto-bus-stop/setup-zig@v2 + - uses: mlugg/setup-zig@v1 with: version: 0.10.1 From 40b0b029729ca23b54a80870f49b04c908f69026 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Tue, 31 Dec 2024 14:54:55 +0100 Subject: [PATCH 36/41] Add issues.yml --- .github/workflows/issues.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/workflows/issues.yml diff --git a/.github/workflows/issues.yml b/.github/workflows/issues.yml new file mode 100644 index 0000000..c5bf530 --- /dev/null +++ b/.github/workflows/issues.yml @@ -0,0 +1,17 @@ +name: Close inactive issues +on: + schedule: + - cron: "30 1 * * *" + +jobs: + close-issues: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: actions/stale@v9 + with: + stale-issue-message: "This issue is stale because it has been open for 30 days with no activity." + close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale." + repo-token: ${{ secrets.GITHUB_TOKEN }} From 9e4a931bceff7d794f1fb341599ae48ea2cae2a6 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 20 Feb 2025 20:32:42 +0100 Subject: [PATCH 37/41] Nits --- src/config.rs | 61 ++++++++++++++++++++++-------------------- src/libdoh/src/lib.rs | 5 +--- src/libdoh/src/odoh.rs | 2 +- src/libdoh/src/tls.rs | 9 +++---- 4 files changed, 37 insertions(+), 40 deletions(-) diff --git a/src/config.rs b/src/config.rs index 287cf8a..6d69671 100644 --- a/src/config.rs +++ b/src/config.rs @@ -240,39 +240,42 @@ pub fn parse_opts(globals: &mut Globals) { .or_else(|| globals.tls_cert_path.clone()); } - if let Some(hostname) = matches.get_one::("hostname") { - let mut builder = - dnsstamps::DoHBuilder::new(hostname.to_string(), globals.path.to_string()); - if let Some(public_address) = matches.get_one::("public_address") { - builder = builder.with_address(public_address.to_string()); - } - if let Some(public_port) = matches.get_one::("public_port") { - let public_port = public_port.parse().expect("Invalid public port"); - builder = builder.with_port(public_port); - } - println!( - "Test DNS stamp to reach [{}] over DoH: [{}]\n", - hostname, - builder.serialize().unwrap() - ); + match matches.get_one::("hostname") { + Some(hostname) => { + let mut builder = + dnsstamps::DoHBuilder::new(hostname.to_string(), globals.path.to_string()); + if let Some(public_address) = matches.get_one::("public_address") { + builder = builder.with_address(public_address.to_string()); + } + if let Some(public_port) = matches.get_one::("public_port") { + let public_port = public_port.parse().expect("Invalid public port"); + builder = builder.with_port(public_port); + } + println!( + "Test DNS stamp to reach [{}] over DoH: [{}]\n", + hostname, + builder.serialize().unwrap() + ); - let mut builder = - dnsstamps::ODoHTargetBuilder::new(hostname.to_string(), globals.path.to_string()); - if let Some(public_port) = matches.get_one::("public_port") { - let public_port = public_port.parse().expect("Invalid public port"); - builder = builder.with_port(public_port); - } - println!( - "Test DNS stamp to reach [{}] over Oblivious DoH: [{}]\n", - hostname, - builder.serialize().unwrap() - ); + let mut builder = + dnsstamps::ODoHTargetBuilder::new(hostname.to_string(), globals.path.to_string()); + if let Some(public_port) = matches.get_one::("public_port") { + let public_port = public_port.parse().expect("Invalid public port"); + builder = builder.with_port(public_port); + } + println!( + "Test DNS stamp to reach [{}] over Oblivious DoH: [{}]\n", + hostname, + builder.serialize().unwrap() + ); - println!("Check out https://dnscrypt.info/stamps/ to compute the actual stamps.\n") - } else { - println!( + println!("Check out https://dnscrypt.info/stamps/ to compute the actual stamps.\n") + } + _ => { + println!( "Please provide a fully qualified hostname (-H command-line option) to get \ test DNS stamps for your server.\n" ); + } } } diff --git a/src/libdoh/src/lib.rs b/src/libdoh/src/lib.rs index 4b6eea8..e6dd729 100644 --- a/src/libdoh/src/lib.rs +++ b/src/libdoh/src/lib.rs @@ -257,10 +257,7 @@ impl DoH { content_types: &[&'static str], ) -> Option<&'static str> { let accept = headers.get(hyper::header::ACCEPT); - let accept = match accept { - None => return None, - Some(accept) => accept, - }; + let accept = accept?; for part in accept.to_str().unwrap_or("").split(',').map(|s| s.trim()) { if let Some(found) = part .split(';') diff --git a/src/libdoh/src/odoh.rs b/src/libdoh/src/odoh.rs index 00bb95f..3f2c29e 100644 --- a/src/libdoh/src/odoh.rs +++ b/src/libdoh/src/odoh.rs @@ -77,7 +77,7 @@ impl ODoHPublicKey { impl ODoHQueryContext { pub fn encrypt_response(self, response_body: Vec) -> Result, DoHError> { - let response_nonce = rand::thread_rng().gen::(); + let response_nonce = rand::thread_rng().r#gen::(); let response_body_ = ObliviousDoHMessagePlaintext::new(response_body, 0); let encrypted_response = odoh_rs::encrypt_response( &self.query, diff --git a/src/libdoh/src/tls.rs b/src/libdoh/src/tls.rs index 7047f99..7c5509f 100644 --- a/src/libdoh/src/tls.rs +++ b/src/libdoh/src/tls.rs @@ -87,12 +87,9 @@ where let server_config_builder = ServerConfig::builder() .with_safe_defaults() .with_no_client_auth(); - if let Ok(found_config) = - server_config_builder.with_single_cert(certs.clone(), certs_key) - { - Some(found_config) - } else { - None + match server_config_builder.with_single_cert(certs.clone(), certs_key) { + Ok(found_config) => Some(found_config), + _ => None, } }) .ok_or_else(|| { From 672d1a11f18b078e83be9c317777427aeb6158cc Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 20 Feb 2025 20:33:01 +0100 Subject: [PATCH 38/41] 2025 --- LICENSE | 2 +- src/libdoh/LICENSE | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE b/LICENSE index 06c6cdb..fe0d515 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2018-2023 Frank Denis +Copyright (c) 2018-2025 Frank Denis Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/libdoh/LICENSE b/src/libdoh/LICENSE index 06c6cdb..fe0d515 100644 --- a/src/libdoh/LICENSE +++ b/src/libdoh/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2018-2023 Frank Denis +Copyright (c) 2018-2025 Frank Denis Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 2254632d3373ace147527dc333ecdbb5aba3e660 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 20 Feb 2025 20:37:23 +0100 Subject: [PATCH 39/41] Update deps --- Cargo.toml | 2 +- src/libdoh/Cargo.toml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d7e7ca0..d82bfbf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ tls = ["libdoh/tls"] [dependencies] libdoh = { path = "src/libdoh", version = "0.9.9", default-features = false } clap = { version = "4", features = ["std", "cargo", "wrap_help", "string"] } -dnsstamps = "0.1.9" +dnsstamps = "0.1.10" mimalloc = { version = "0.1.43", default-features = false } [package.metadata.generate-rpm] diff --git a/src/libdoh/Cargo.toml b/src/libdoh/Cargo.toml index 7b72764..503a52d 100644 --- a/src/libdoh/Cargo.toml +++ b/src/libdoh/Cargo.toml @@ -15,12 +15,12 @@ default = ["tls"] tls = ["tokio-rustls"] [dependencies] -anyhow = "1.0.86" +anyhow = "1.0.96" arc-swap = "1.7.1" base64 = "0.22.1" byteorder = "1.5.0" -bytes = "1.6.0" -futures = "0.3.30" +bytes = "1.10.0" +futures = "0.3.31" hyper = { version = "^0.14.29", default-features = false, features = [ "server", "http1", @@ -29,8 +29,8 @@ hyper = { version = "^0.14.29", default-features = false, features = [ "runtime", ] } odoh-rs = "1.0.3" -rand = "0.8.5" -tokio = { version = "1.38.0", features = [ +rand = "^0.8.5" +tokio = { version = "1.43.0", features = [ "net", "rt-multi-thread", "time", From 25fa6946e69ec8d36e98b598be11be3b1a777d3e Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 20 Mar 2025 00:37:34 +0100 Subject: [PATCH 40/41] tar cJpf -> tar cjpf in order to build bz2 archives Fixes #103 --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 48f03a0..0a91737 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -46,7 +46,7 @@ jobs: mkdir doh-proxy mv target/x86_64-unknown-linux-musl/release/doh-proxy doh-proxy/ cp README.md localhost.pem doh-proxy/ - tar cJpf doh-proxy_${{ steps.get_version.outputs.VERSION }}_linux-x86_64.tar.bz2 doh-proxy + tar cjpf doh-proxy_${{ steps.get_version.outputs.VERSION }}_linux-x86_64.tar.bz2 doh-proxy rm -fr doh-proxy - name: Release build Linux-aarch64 @@ -56,7 +56,7 @@ jobs: mkdir doh-proxy mv target/aarch64-unknown-linux-musl/release/doh-proxy doh-proxy/ cp README.md localhost.pem doh-proxy/ - tar cJpf doh-proxy_${{ steps.get_version.outputs.VERSION }}_linux-aarch64.tar.bz2 doh-proxy + tar cjpf doh-proxy_${{ steps.get_version.outputs.VERSION }}_linux-aarch64.tar.bz2 doh-proxy rm -fr doh-proxy - name: Release build Windows-x86_64 From f0242354d39445891160244a58f740ed99a98a8d Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Thu, 20 Mar 2025 00:41:43 +0100 Subject: [PATCH 41/41] Update deps --- Cargo.toml | 2 +- src/libdoh/Cargo.toml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d82bfbf..2be4b3d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ tls = ["libdoh/tls"] libdoh = { path = "src/libdoh", version = "0.9.9", default-features = false } clap = { version = "4", features = ["std", "cargo", "wrap_help", "string"] } dnsstamps = "0.1.10" -mimalloc = { version = "0.1.43", default-features = false } +mimalloc = { version = "0.1.44", default-features = false } [package.metadata.generate-rpm] assets = [ diff --git a/src/libdoh/Cargo.toml b/src/libdoh/Cargo.toml index 503a52d..69fe04d 100644 --- a/src/libdoh/Cargo.toml +++ b/src/libdoh/Cargo.toml @@ -15,13 +15,13 @@ default = ["tls"] tls = ["tokio-rustls"] [dependencies] -anyhow = "1.0.96" +anyhow = "1.0.97" arc-swap = "1.7.1" base64 = "0.22.1" byteorder = "1.5.0" -bytes = "1.10.0" +bytes = "1.10.1" futures = "0.3.31" -hyper = { version = "^0.14.29", default-features = false, features = [ +hyper = { version = "^0.14.32", default-features = false, features = [ "server", "http1", "http2", @@ -30,7 +30,7 @@ hyper = { version = "^0.14.29", default-features = false, features = [ ] } odoh-rs = "1.0.3" rand = "^0.8.5" -tokio = { version = "1.43.0", features = [ +tokio = { version = "1.44.1", features = [ "net", "rt-multi-thread", "time",