Skip to content

Commit

Permalink
fix: use tcp tls backend for peer seed DNS resolution
Browse files Browse the repository at this point in the history
  • Loading branch information
sdbondi committed Nov 8, 2021
1 parent 800686e commit 001e713
Show file tree
Hide file tree
Showing 12 changed files with 5,223 additions and 32 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

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

4 changes: 3 additions & 1 deletion base_layer/p2p/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ tokio = { version = "1.11", features = ["macros"] }
tokio-stream = { version = "0.1.7", default-features = false, features = ["time"] }
tower = "0.3.0-alpha.2"
tower-service = { version = "0.3.0-alpha.2" }
trust-dns-client = { version = "0.21.0-alpha.2", features = ["dns-over-rustls"] }
trust-dns-client = { version = "0.21.0-alpha.4", features = ["dns-over-rustls"] }
rustls = "0.19.1"
webpki = "0.21"

[dev-dependencies]
tari_test_utils = { version = "^0.13", path = "../../infrastructure/test_utils" }
Expand Down
58 changes: 50 additions & 8 deletions base_layer/p2p/src/dns/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,25 @@
use crate::dns::mock::{DefaultOnSend, MockClientHandle};

use super::DnsClientError;
use crate::dns::roots;
use futures::{future, FutureExt};
use std::{net::SocketAddr, sync::Arc};
use rustls::{ClientConfig, ProtocolVersion, RootCertStore};
use std::{net::SocketAddr, sync::Arc, time::Duration};
use tari_shutdown::Shutdown;
use tokio::{net::UdpSocket, task};
use tokio::task;
use trust_dns_client::{
client::{AsyncClient, AsyncDnssecClient, ClientHandle},
op::Query,
proto::{error::ProtoError, rr::dnssec::TrustAnchor, udp::UdpClientStream, xfer::DnsResponse, DnsHandle},
rr::{DNSClass, IntoName, RecordType},
proto::{
error::ProtoError,
iocompat::AsyncIoTokioAsStd,
rr::dnssec::TrustAnchor,
rustls::tls_client_connect,
xfer::DnsResponse,
DnsHandle,
DnsMultiplexer,
},
rr::{dnssec::SigSigner, DNSClass, IntoName, RecordType},
serialize::binary::BinEncoder,
};

Expand Down Expand Up @@ -112,11 +122,21 @@ pub struct Client<C> {
impl Client<AsyncDnssecClient> {
pub async fn connect_secure(name_server: SocketAddr, trust_anchor: TrustAnchor) -> Result<Self, DnsClientError> {
let shutdown = Shutdown::new();
let stream = UdpClientStream::<UdpSocket>::new(name_server);
let (client, background) = AsyncDnssecClient::builder(stream)

// TODO: make configurable
let timeout = Duration::from_secs(5);
let (stream, handle) = tls_client_connect::<AsyncIoTokioAsStd<tokio::net::TcpStream>>(
name_server,
"cloudflare-dns.com".to_string(),
default_client_config(),
);

let dns_muxer = DnsMultiplexer::<_, SigSigner>::with_timeout(stream, handle, timeout, None);
let (client, background) = AsyncDnssecClient::builder(dns_muxer)
.trust_anchor(trust_anchor)
.build()
.await?;

task::spawn(future::select(shutdown.to_signal(), background.fuse()));

Ok(Self {
Expand All @@ -129,8 +149,16 @@ impl Client<AsyncDnssecClient> {
impl Client<AsyncClient> {
pub async fn connect(name_server: SocketAddr) -> Result<Self, DnsClientError> {
let shutdown = Shutdown::new();
let stream = UdpClientStream::<UdpSocket>::new(name_server);
let (client, background) = AsyncClient::connect(stream).await?;

// TODO: make configurable
let timeout = Duration::from_secs(5);
let (stream, handle) = tls_client_connect::<AsyncIoTokioAsStd<tokio::net::TcpStream>>(
name_server,
"cloudflare-dns.com".to_string(),
default_client_config(),
);

let (client, background) = AsyncClient::with_timeout(stream, handle, timeout, None).await?;
task::spawn(future::select(shutdown.to_signal(), background.fuse()));

Ok(Self {
Expand All @@ -148,10 +176,24 @@ where C: DnsHandle<Error = ProtoError>
.inner
.query(query.name().clone(), query.query_class(), query.query_type())
.await?;

Ok(client_resp)
}
}

fn default_client_config() -> Arc<ClientConfig> {
let mut root_store = RootCertStore::empty();
root_store.add_server_trust_anchors(&roots::TLS_SERVER_ROOTS);
let versions = vec![ProtocolVersion::TLSv1_2];

let mut client_config = ClientConfig::new();
client_config.root_store = root_store;
client_config.versions = versions;
client_config.alpn_protocols.push("h2".as_bytes().to_vec());

Arc::new(client_config)
}

#[cfg(test)]
mod mock {
use super::*;
Expand Down
2 changes: 2 additions & 0 deletions base_layer/p2p/src/dns/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,6 @@ pub enum DnsClientError {
ClientError(#[from] ClientError),
#[error("DNS Protocol error: {0}")]
ProtoError(#[from] ProtoError),
#[error("DNS timeout error")]
Timeout,
}
18 changes: 3 additions & 15 deletions base_layer/p2p/src/dns/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,8 @@ pub use client::DnsClient;
mod error;
pub use error::DnsClientError;

mod roots;
pub(crate) use roots::default_trust_anchor;

#[cfg(test)]
pub(crate) mod mock;

use trust_dns_client::proto::rr::dnssec::{public_key::Rsa, TrustAnchor};

#[inline]
pub(crate) fn default_trust_anchor() -> TrustAnchor {
// This was copied from the trust-dns crate.
const ROOT_ANCHOR_ORIG: &[u8] = include_bytes!("roots/19036.rsa");
// This was generated from the `.` root domain in 10/2020.
const ROOT_ANCHOR_CURRENT: &[u8] = include_bytes!("roots/20326.rsa");

let mut anchor = TrustAnchor::new();
anchor.insert_trust_anchor(&Rsa::from_public_bytes(ROOT_ANCHOR_ORIG).expect("Invalid ROOT_ANCHOR_ORIG"));
anchor.insert_trust_anchor(&Rsa::from_public_bytes(ROOT_ANCHOR_CURRENT).expect("Invalid ROOT_ANCHOR_CURRENT"));
anchor
}
39 changes: 39 additions & 0 deletions base_layer/p2p/src/dns/roots/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2021, The Tari Project
//
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
// following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
// disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
// following disclaimer in the documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
// products derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

mod tls;
pub(super) use tls::TLS_SERVER_ROOTS;

use trust_dns_client::proto::rr::dnssec::{public_key::Rsa, TrustAnchor};

#[inline]
pub fn default_trust_anchor() -> TrustAnchor {
// This was copied from the trust-dns crate.
const ROOT_ANCHOR_ORIG: &[u8] = include_bytes!("19036.rsa");
// This was generated from the `.` root domain in 10/2020.
const ROOT_ANCHOR_CURRENT: &[u8] = include_bytes!("20326.rsa");

let mut anchor = TrustAnchor::new();
anchor.insert_trust_anchor(&Rsa::from_public_bytes(ROOT_ANCHOR_ORIG).expect("Invalid ROOT_ANCHOR_ORIG"));
anchor.insert_trust_anchor(&Rsa::from_public_bytes(ROOT_ANCHOR_CURRENT).expect("Invalid ROOT_ANCHOR_CURRENT"));
anchor
}
Loading

0 comments on commit 001e713

Please sign in to comment.