Skip to content

Commit

Permalink
Add support for TLS. (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
Philip-NLnetLabs committed Jun 20, 2024
1 parent 10817c6 commit 8f0fa3b
Show file tree
Hide file tree
Showing 5 changed files with 205 additions and 5 deletions.
93 changes: 93 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,7 @@ chrono = { version = "0.4.38", features = [ "alloc", "clock" ] }
domain = { version = "0.10", features = ["resolv", "unstable-client-transport"]}
tempfile = "3.1.0"
tokio = { version = "1.33", features = ["rt-multi-thread"] }
tokio-rustls = { version = "0.26.0", default-features = false, features = [ "ring", "logging", "tls12" ] }
webpki-roots = "0.26.3"


16 changes: 16 additions & 0 deletions doc/dnsi-query.1
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,22 @@ Specifies that only TCP should be used.
Specifies that only UDP should be used and the resulting answer be printed
even if it had to be truncated.

.TP
.B --tls
Specifies that TLS should be used. In this case a server name or address
must be explicitly given via the
.B --server
option.

.TP
.B --tls-hostname
Specifies the hostname to be used for server certificate validation when
.B --tls
is used. By default the name given to the
.B --server
option is used. The option is mandatory, however, if an address is used as
for the server.

.TP
.BI --timeout \ seconds
Sets the time after sending a query before a server is considered
Expand Down
46 changes: 46 additions & 0 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ use domain::net::client::{dgram, stream};
use domain::resolv::stub::conf;
use std::fmt;
use std::net::SocketAddr;
use std::sync::Arc;
use std::time::Duration;
use tokio::net::TcpStream;
use tokio_rustls::rustls::{ClientConfig, RootCertStore};

//------------ Client --------------------------------------------------------

Expand All @@ -38,6 +40,7 @@ impl Client {
timeout: server.request_timeout,
retries: u8::try_from(conf.options.attempts).unwrap_or(2),
udp_payload_size: server.udp_payload_size,
tls_hostname: None,
})
.collect(),
}
Expand Down Expand Up @@ -90,6 +93,7 @@ impl Client {
Transport::Udp => self.request_udp(request, server).await,
Transport::UdpTcp => self.request_udptcp(request, server).await,
Transport::Tcp => self.request_tcp(request, server).await,
Transport::Tls => self.request_tls(request, server).await,
}
}

Expand Down Expand Up @@ -138,6 +142,44 @@ impl Client {
Ok(Answer { message, stats })
}

pub async fn request_tls(
&self,
request: RequestMessage<Vec<u8>>,
server: &Server,
) -> Result<Answer, Error> {
let root_store = RootCertStore {
roots: webpki_roots::TLS_SERVER_ROOTS.into(),
};
let client_config = Arc::new(
ClientConfig::builder()
.with_root_certificates(root_store)
.with_no_client_auth(),
);

let mut stats = Stats::new(server.addr, Protocol::Tls);
let tcp_socket = TcpStream::connect(server.addr).await?;
let tls_connector = tokio_rustls::TlsConnector::from(client_config);
let server_name = server
.tls_hostname
.clone()
.expect("tls_hostname must be set for tls")
.try_into()
.map_err(|_| {
let s = "Invalid DNS name";
<&str as Into<Error>>::into(s)
})?;
let tls_socket =
tls_connector.connect(server_name, tcp_socket).await?;
let (conn, tran) = stream::Connection::with_config(
tls_socket,
Self::stream_config(server),
);
tokio::spawn(tran.run());
let message = conn.send_request(request).get_response().await?;
stats.finalize();
Ok(Answer { message, stats })
}

fn dgram_config(server: &Server) -> dgram::Config {
let mut res = dgram::Config::new();
res.set_read_timeout(server.timeout);
Expand All @@ -162,6 +204,7 @@ pub struct Server {
pub timeout: Duration,
pub retries: u8,
pub udp_payload_size: u16,
pub tls_hostname: Option<String>,
}

//------------ Transport -----------------------------------------------------
Expand All @@ -171,6 +214,7 @@ pub enum Transport {
Udp,
UdpTcp,
Tcp,
Tls,
}

impl From<conf::Transport> for Transport {
Expand Down Expand Up @@ -241,13 +285,15 @@ impl Stats {
pub enum Protocol {
Udp,
Tcp,
Tls,
}

impl fmt::Display for Protocol {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(match *self {
Protocol::Udp => "UDP",
Protocol::Tcp => "TCP",
Protocol::Tls => "TLS",
})
}
}
Loading

0 comments on commit 8f0fa3b

Please sign in to comment.