mirror of
https://github.com/DNSCrypt/doh-server.git
synced 2025-03-31 11:47:36 +03:00
Replace native-tls with rust-tls, switch to PEM format
This commit is contained in:
parent
4914572894
commit
16cb57c1e1
10 changed files with 137 additions and 62 deletions
|
@ -12,11 +12,11 @@ edition = "2018"
|
|||
readme = "README.md"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
default = ["tls"]
|
||||
tls = ["libdoh/tls"]
|
||||
|
||||
[dependencies]
|
||||
libdoh = { path = "src/libdoh", version = "0.2" }
|
||||
libdoh = { path = "src/libdoh", version = "0.3" }
|
||||
clap = "2"
|
||||
jemallocator = "0"
|
||||
tokio = { version = "0.2", features = ["rt-threaded", "time", "tcp", "udp", "stream"] }
|
||||
|
|
28
README.md
28
README.md
|
@ -22,14 +22,12 @@ cargo install doh-proxy
|
|||
With built-in support for HTTPS (requires openssl-dev):
|
||||
|
||||
```sh
|
||||
cargo install doh-proxy --features=tls
|
||||
cargo install doh-proxy
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```text
|
||||
A DNS-over-HTTP server proxy
|
||||
|
||||
USAGE:
|
||||
doh-proxy [FLAGS] [OPTIONS]
|
||||
|
||||
|
@ -42,17 +40,17 @@ FLAGS:
|
|||
OPTIONS:
|
||||
-E, --err-ttl <err_ttl> TTL for errors, in seconds [default: 2]
|
||||
-l, --listen-address <listen_address> Address to listen to [default: 127.0.0.1:3000]
|
||||
-b, --local-bind-address <local_bind_address> Address to connect from [default: 0.0.0.0:0]
|
||||
-b, --local-bind-address <local_bind_address> Address to connect from
|
||||
-c, --max-clients <max_clients> Maximum number of simultaneous clients [default: 512]
|
||||
-X, --max-ttl <max_ttl> Maximum TTL, in seconds [default: 604800]
|
||||
-T, --min-ttl <min_ttl> Minimum TTL, in seconds [default: 10]
|
||||
-p, --path <path> URI path [default: /dns-query]
|
||||
-u, --server-address <server_address> Address to connect to [default: 9.9.9.9:53]
|
||||
-t, --timeout <timeout> Timeout, in seconds [default: 10]
|
||||
-I, --tls-cert-password <tls_cert_password>
|
||||
Password for the PKCS12-encoded identity (only required for built-in TLS)
|
||||
-I, --tls-cert-key-path <tls_cert_key_path>
|
||||
Path to the PEM-encoded secret keys (only required for built-in TLS)
|
||||
|
||||
-i, --tls-cert-path <tls_cert_path> Path to a PKCS12-encoded identity (only required for built-in TLS)
|
||||
-i, --tls-cert-path <tls_cert_path> Path to a PEM-encoded identity (only required for built-in TLS)
|
||||
```
|
||||
|
||||
## HTTP/2 termination
|
||||
|
@ -65,22 +63,14 @@ If `doh-proxy` and the HTTP/2 front-end run on the same host, using the HTTP pro
|
|||
|
||||
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.
|
||||
|
||||
The identity must be encoded in PKCS12 format. Given an existing certificate `cert.pem` and its secret key `cert.key`, this can be achieved using the `openssl` command-line tool:
|
||||
The certificates and private keys must be encoded in PEM format. They can be stored in the same file.
|
||||
|
||||
```sh
|
||||
openssl pkcs12 -export -out cert.p12 -in cert.pem -inkey cert.key
|
||||
```
|
||||
|
||||
A password will be interactive asked for, but the `-passout` command-line option can be added to provide it non-interactively.
|
||||
|
||||
Once done, check that the permissions on `cert.p12` are reasonable.
|
||||
|
||||
In order to enable built-in HTTPS support, add the `--tls-cert-path` option to specify the location of the `cert.p12` file, as well as the password using `--tls-cert-password`.
|
||||
In order to enable built-in HTTPS support, add the `--tls-cert-path` option to specify the location of the certificates file, as well as the private keys file using `--tls-cert-key-path`.
|
||||
|
||||
Once HTTPS is enabled, HTTP connections will not be accepted.
|
||||
|
||||
A sample self-signed certificate [`localhost.p12`](https://github.com/jedisct1/rust-doh/raw/master/localhost.p12) can be used for testing.
|
||||
The password is `test`.
|
||||
A sample self-signed certificate [`localhost.pem`](https://github.com/jedisct1/rust-doh/raw/master/localhost.pem) can be used for testing.
|
||||
The file also includes the private key.
|
||||
|
||||
## Accepting both DNSCrypt and DoH connections on port 443
|
||||
|
||||
|
|
BIN
localhost.p12
BIN
localhost.p12
Binary file not shown.
47
localhost.pem
Normal file
47
localhost.pem
Normal file
|
@ -0,0 +1,47 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDb7g6EQhbfby97
|
||||
k4oMbZTzdi2TWFBs7qK/QwgOu+L6EhNHPO1ZEU29v0APFBFJO5zyyAk9bZ9k9tPB
|
||||
bCuVVI9jEUfLH3UCjEQPG6XI2w++uVh0yALvc/uurCvRHVlle/V7cAoikndc2SjE
|
||||
RQUALbACIqwD5g0F77BYwcsreB4GH253/R6Q2/CJZ4jNHPjkocOJiVr3ejA0kkoN
|
||||
MXpGUXWcrVVk20M2A1CeO7HAulLRcklEdoHE3v46pjp0iZK0F9LyZX1U1ql+4QL3
|
||||
iQttoZ4tMg83lFHSt4G9PrpIhzXr9W4NW822faSvrIwwN/JbItUmRa7n/3+MkuJQ
|
||||
IGGNDayXAgMBAAECggEBANs0fmGSocuXvYL1Pi4+9qxnCOwIpTi97Zam0BwnZwcL
|
||||
Bw4FCyiwV4UdX1LoFIailT9i49rHLYzre4oZL6OKgdQjQCSTuQOOHLPWQbpdpWba
|
||||
w/C5/jr+pkemMZIfJ6BAGiArPt7Qj4oKpFhj1qUj5H9sYXkNTcOx8Fm25rLv6TT9
|
||||
O7wg0oCpyG+iBSbCYBp9mDMz8pfo4P3BhcFiyKCKeiAC6KuHU81dvuKeFB4XQK+X
|
||||
no2NqDqe6MBkmTqjNNy+wi1COR7lu34LPiWU5Hq5PdIEqBBUMjlMI6oYlhlgNTdx
|
||||
SvsqFz3Xs6kpAhJTrSiAqscPYosgaMQxo+LI26PJnikCgYEA9n0OERkm0wSBHnHY
|
||||
Kx8jaxNYg93jEzVnEgI/MBTJZqEyCs9fF6Imv737VawEN/BhesZZX7bGZQfDo8AT
|
||||
aiSa5upkkSGXEqTu5ytyoKFTb+dJ/qmx3+zP6dPVzDnc8WPYMoUg7vvjZkXXJgZX
|
||||
+oMlMUW1wWiDNI3wP19W9Is6xssCgYEA5GqkUBEns6eTFJV0JKqbEORJJ7lx5NZe
|
||||
cIx+jPpLkILG4mOKOg1TBx0wkxa9cELtsNsM+bPtu9OqRMhsfPBmsXDHhJwg0Z6G
|
||||
eDTfYYPkpRhwZvl6jBZn9sLVR9wfg2hE+n0lfV3mceg336KOkwAehDU84SWZ2e0S
|
||||
esqkpbHJa+UCgYA7PY0O8POSzcdWkNf6bS5vAqRIdSCpMjGGc4HKRYSuJNnJHVPm
|
||||
czNK7Bcm3QPaiexzvI4oYd5G09niVjyUSx3rl7P56Y/MjFVau+d90agjAfyXtyMo
|
||||
BVtnAGGnBtUiMvP4GGT06xcZMnnmCqpEbBaZQ/7N8Bdwnxh5sqlMdtX2hwKBgAhL
|
||||
hyQRO2vezgyVUN50A6WdZLq4lVZGIq/bqkzcWhopZaebDc4F5doASV9OGBsXkyI1
|
||||
EkePLTcA/NH6pVX0NQaEnfpG4To7k46R/PrBm3ATbyGONdEYjzX65VvytoJDKx4d
|
||||
pVrkKhZA5KaOdLcJ7hHHDSrv/qJXZbBn44rQ5guxAoGBAJ6oeUsUUETakxlmIhmK
|
||||
xuQmWqLf97BKt8r6Z8CqHKWK7vpG2OmgFYCQGaR7angQ8hmAOv6jM56XhoagDBoc
|
||||
UoaoEyo9/uCk6NRUkUMj7Tk/5UQSiWLceVH27w+icMFhf1b7EmmNfk+APsiathO5
|
||||
j4edf1AinVCPwRVVu1dtLL5P
|
||||
-----END PRIVATE KEY-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDAjCCAeoCCQCptj0+TjjIJjANBgkqhkiG9w0BAQsFADBDMREwDwYDVQQKDAhE
|
||||
TlNDcnlwdDEaMBgGA1UECwwRTG9jYWwgdGVzdCBzZXJ2ZXIxEjAQBgNVBAMMCWxv
|
||||
Y2FsaG9zdDAeFw0xOTExMTgxNDA2MzBaFw0zMzA3MjcxNDA2MzBaMEMxETAPBgNV
|
||||
BAoMCEROU0NyeXB0MRowGAYDVQQLDBFMb2NhbCB0ZXN0IHNlcnZlcjESMBAGA1UE
|
||||
AwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2+4O
|
||||
hEIW328ve5OKDG2U83Ytk1hQbO6iv0MIDrvi+hITRzztWRFNvb9ADxQRSTuc8sgJ
|
||||
PW2fZPbTwWwrlVSPYxFHyx91AoxEDxulyNsPvrlYdMgC73P7rqwr0R1ZZXv1e3AK
|
||||
IpJ3XNkoxEUFAC2wAiKsA+YNBe+wWMHLK3geBh9ud/0ekNvwiWeIzRz45KHDiYla
|
||||
93owNJJKDTF6RlF1nK1VZNtDNgNQnjuxwLpS0XJJRHaBxN7+OqY6dImStBfS8mV9
|
||||
VNapfuEC94kLbaGeLTIPN5RR0reBvT66SIc16/VuDVvNtn2kr6yMMDfyWyLVJkWu
|
||||
5/9/jJLiUCBhjQ2slwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQA6Vz5HnGuy8jZz
|
||||
5i8ipbcDMCZNdpYYnxgD53hEKOfoSv7LaF0ztD8Kmg3s5LHv9EHlkK3+G6FWRGiP
|
||||
9f6IbtRITaiVQP3M13T78hpN5Qq5jgsqjR7ZcN7Etr6ZFd7G/0+mzqbyBuW/3szt
|
||||
RdX/YLy1csvjbZoNNuXGWRohXjg0Mjko2tRLmARvxA/gZV5zWycv3BD2BPzyCdS9
|
||||
MDMYSF0RPiL8+alfwLNqLcqMA5liHlmZa85uapQyoUI3ksKJkEgU53aD8cYhH9Yn
|
||||
6mVpsrvrcRLBiHlbi24QBolhFkCSRK8bXes8XDIPuD8iYRwlrVBwOakMFQWMqNfI
|
||||
IMOKJomU
|
||||
-----END CERTIFICATE-----
|
|
@ -114,14 +114,14 @@ pub fn parse_opts(globals: &mut Globals) {
|
|||
.short("i")
|
||||
.long("tls-cert-path")
|
||||
.takes_value(true)
|
||||
.help("Path to a PKCS12-encoded identity (only required for built-in TLS)"),
|
||||
.help("Path to a PEM-encoded certificates (only required for built-in TLS)"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("tls_cert_password")
|
||||
Arg::with_name("tls_cert_key_path")
|
||||
.short("I")
|
||||
.long("tls-cert-password")
|
||||
.long("tls-cert-key-path")
|
||||
.takes_value(true)
|
||||
.help("Password for the PKCS12-encoded identity (only required for built-in TLS)"),
|
||||
.help("Path to the PEM-encoded secret keys (only required for built-in TLS)"),
|
||||
);
|
||||
|
||||
let matches = options.get_matches();
|
||||
|
@ -160,9 +160,7 @@ pub fn parse_opts(globals: &mut Globals) {
|
|||
|
||||
#[cfg(feature = "tls")]
|
||||
{
|
||||
globals.tls_cert_path = matches.value_of("tls_cert_path").map(PathBuf::from);
|
||||
globals.tls_cert_password = matches
|
||||
.value_of("tls_cert_password")
|
||||
.map(ToString::to_string);
|
||||
globals.tls_cert_path = matches.value_of("tls_cert_key_path").map(PathBuf::from);
|
||||
globals.tls_cert_key_path = matches.value_of("tls_cert_key_path").map(PathBuf::from);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "libdoh"
|
||||
version = "0.2.2"
|
||||
version = "0.3.0"
|
||||
authors = ["Frank Denis <github@pureftpd.org>"]
|
||||
description = "DoH library for the rust-doh app"
|
||||
keywords = ["dns","https","doh","proxy"]
|
||||
|
@ -12,7 +12,7 @@ edition = "2018"
|
|||
|
||||
[features]
|
||||
default = []
|
||||
tls = ["native-tls", "tokio-tls"]
|
||||
tls = ["tokio-rustls"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
|
@ -20,9 +20,8 @@ byteorder = "1.3"
|
|||
base64 = "0.11"
|
||||
futures = "0.3"
|
||||
hyper = { version = "0.13", default-features = false, features = ["stream"] }
|
||||
native-tls = { version = "0.2.3", optional = true }
|
||||
tokio = { version = "0.2", features = ["rt-threaded", "time", "tcp", "udp", "stream"] }
|
||||
tokio-tls = { version = "0.3", optional = true }
|
||||
tokio-rustls = { version = "0.12", optional = true }
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
|
|
|
@ -13,7 +13,7 @@ pub struct Globals {
|
|||
pub tls_cert_path: Option<PathBuf>,
|
||||
|
||||
#[cfg(feature = "tls")]
|
||||
pub tls_cert_password: Option<String>,
|
||||
pub tls_cert_key_path: Option<PathBuf>,
|
||||
|
||||
pub listen_address: SocketAddr,
|
||||
pub local_bind_address: SocketAddr,
|
||||
|
|
|
@ -266,9 +266,9 @@ impl DoH {
|
|||
let path = &self.globals.path;
|
||||
|
||||
#[cfg(feature = "tls")]
|
||||
let tls_acceptor = match (&self.globals.tls_cert_path, &self.globals.tls_cert_password) {
|
||||
(Some(tls_cert_path), Some(tls_cert_password)) => {
|
||||
Some(create_tls_acceptor(tls_cert_path, tls_cert_password).unwrap())
|
||||
let tls_acceptor = match (&self.globals.tls_cert_path, &self.globals.tls_cert_key_path) {
|
||||
(Some(tls_cert_path), Some(tls_cert_key_path)) => {
|
||||
Some(create_tls_acceptor(tls_cert_path, tls_cert_key_path).unwrap())
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
|
|
@ -2,39 +2,80 @@ use crate::errors::*;
|
|||
use crate::{DoH, LocalExecutor};
|
||||
|
||||
use hyper::server::conn::Http;
|
||||
use native_tls::{self, Identity};
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::io::Read;
|
||||
use std::io::{self, BufReader};
|
||||
use std::path::Path;
|
||||
use tokio::stream::StreamExt;
|
||||
pub use tokio_tls::TlsAcceptor;
|
||||
|
||||
use std::sync::Arc;
|
||||
use tokio::net::TcpListener;
|
||||
use tokio::stream::StreamExt;
|
||||
use tokio_rustls::{
|
||||
rustls::{internal::pemfile, NoClientAuth, ServerConfig},
|
||||
TlsAcceptor,
|
||||
};
|
||||
|
||||
pub fn create_tls_acceptor<P>(path: P, password: &str) -> io::Result<TlsAcceptor>
|
||||
pub fn create_tls_acceptor<P, P2>(certs_path: P, certs_keys_path: P2) -> io::Result<TlsAcceptor>
|
||||
where
|
||||
P: AsRef<Path>,
|
||||
P2: AsRef<Path>,
|
||||
{
|
||||
let identity_bin = {
|
||||
let mut fp = File::open(path)?;
|
||||
let mut identity_bin = vec![];
|
||||
fp.read_to_end(&mut identity_bin)?;
|
||||
identity_bin
|
||||
let certs = {
|
||||
let certs_path_str = certs_path.as_ref().display().to_string();
|
||||
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.to_string()
|
||||
),
|
||||
)
|
||||
})?);
|
||||
pemfile::certs(&mut reader).map_err(|_| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"Unable to parse the certificates",
|
||||
)
|
||||
})?
|
||||
};
|
||||
let identity = Identity::from_pkcs12(&identity_bin, password).map_err(|_| {
|
||||
io::Error::new(
|
||||
let certs_keys = {
|
||||
let certs_keys_path_str = certs_keys_path.as_ref().display().to_string();
|
||||
let mut reader = BufReader::new(File::open(certs_keys_path).map_err(|e| {
|
||||
io::Error::new(
|
||||
e.kind(),
|
||||
format!(
|
||||
"Unable to load the certificate keys [{}]: {}",
|
||||
certs_keys_path_str,
|
||||
e.to_string()
|
||||
),
|
||||
)
|
||||
})?);
|
||||
let keys = pemfile::pkcs8_private_keys(&mut reader).map_err(|_| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"Unable to parse the certificates private keys",
|
||||
)
|
||||
})?;
|
||||
if keys.is_empty() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"No private keys found",
|
||||
));
|
||||
}
|
||||
keys
|
||||
};
|
||||
let mut server_config = ServerConfig::new(NoClientAuth::new());
|
||||
let has_valid_cert_and_key = certs_keys.into_iter().any(|certs_key| {
|
||||
server_config
|
||||
.set_single_cert(certs.clone(), certs_key)
|
||||
.is_ok()
|
||||
});
|
||||
if !has_valid_cert_and_key {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"Unusable PKCS12-encoded identity. The encoding and/or the password may be wrong",
|
||||
)
|
||||
})?;
|
||||
let native_acceptor = native_tls::TlsAcceptor::new(identity).map_err(|_| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"Unable to use the provided PKCS12-encoded identity",
|
||||
)
|
||||
})?;
|
||||
Ok(TlsAcceptor::from(native_acceptor))
|
||||
"Invalid private key for the given certificate",
|
||||
));
|
||||
}
|
||||
Ok(TlsAcceptor::from(Arc::new(server_config)))
|
||||
}
|
||||
|
||||
impl DoH {
|
||||
|
|
|
@ -28,7 +28,7 @@ fn main() {
|
|||
#[cfg(feature = "tls")]
|
||||
tls_cert_path: None,
|
||||
#[cfg(feature = "tls")]
|
||||
tls_cert_password: None,
|
||||
tls_cert_key_path: None,
|
||||
|
||||
listen_address: LISTEN_ADDRESS.parse().unwrap(),
|
||||
local_bind_address: SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue