Skip to content

Commit

Permalink
Switch DNS-over-HTTPS to use routes
Browse files Browse the repository at this point in the history
  • Loading branch information
akonradi-signal authored Jan 17, 2025
1 parent 0b5650f commit 19506e0
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 155 deletions.
38 changes: 23 additions & 15 deletions rust/net/examples/dns_custom_lookup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ use libsignal_net::infra::dns::dns_transport_doh::DohTransport;
use libsignal_net::infra::dns::dns_transport_udp::UdpTransport;
use libsignal_net::infra::host::Host;
use libsignal_net::infra::utils::ObservableEvent;
use libsignal_net::infra::{
ConnectionParams, HttpRequestDecoratorSeq, RouteType, TransportConnectionParams,
use libsignal_net_infra::route::{
HttpRouteFragment, HttpsTlsRoute, TcpRoute, TlsRoute, TlsRouteFragment,
};
use libsignal_net_infra::Alpn;
use nonzero_ext::nonzero;
use tokio::time::Instant;

Expand Down Expand Up @@ -46,31 +47,38 @@ async fn main() {
.try_init();

let args = Args::parse();
const HOST_IP: IpAddr = ip_addr!("1.1.1.1");

let custom_resolver = match args.transport {
Transport::Udp => {
let ns_address = (IpAddr::V4(ip_addr!(v4, "1.1.1.1")), 53);
let ns_address = (HOST_IP, 53);
Either::Left(CustomDnsResolver::<UdpTransport>::new(
ns_address,
&ObservableEvent::default(),
))
}
Transport::Doh => {
let host = "1.1.1.1".into();
let connection_params = ConnectionParams {
route_type: RouteType::Direct,
http_request_decorator: HttpRequestDecoratorSeq::default(),
connection_confirmation_header: None,
transport: TransportConnectionParams {
sni: Arc::clone(&host),
tcp_host: Host::Ip(ip_addr!("1.1.1.1")),
port: nonzero!(443u16),
certs: RootCertificates::Native,
let host: Arc<str> = HOST_IP.to_string().into();
let target = HttpsTlsRoute {
fragment: HttpRouteFragment {
host_header: host.clone(),
path_prefix: "".into(),
front_name: None,
},
inner: TlsRoute {
fragment: TlsRouteFragment {
root_certs: RootCertificates::Native,
sni: Host::Domain(host.clone()),
alpn: Some(Alpn::Http2),
},
inner: TcpRoute {
address: HOST_IP,
port: nonzero!(443u16),
},
},
http_host: host,
};
Either::Right(CustomDnsResolver::<DohTransport>::new(
connection_params,
target,
&ObservableEvent::default(),
))
}
Expand Down
53 changes: 27 additions & 26 deletions rust/net/examples/dns_over_https.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Copyright 2024 Signal Messenger, LLC.
// SPDX-License-Identifier: AGPL-3.0-only
//
use std::convert::Infallible;
use std::net::IpAddr;
use std::num::NonZeroU16;
use std::sync::Arc;

Expand All @@ -13,9 +13,10 @@ use libsignal_net::infra::dns::custom_resolver::DnsTransport;
use libsignal_net::infra::dns::dns_lookup::DnsLookupRequest;
use libsignal_net::infra::dns::dns_transport_doh::DohTransport;
use libsignal_net::infra::host::Host;
use libsignal_net::infra::{
ConnectionParams, HttpRequestDecoratorSeq, RouteType, TransportConnectionParams,
use libsignal_net_infra::route::{
HttpRouteFragment, HttpsTlsRoute, TcpRoute, TlsRoute, TlsRouteFragment,
};
use libsignal_net_infra::Alpn;

#[derive(Parser, Debug)]
struct Args {
Expand All @@ -26,15 +27,11 @@ struct Args {
#[arg(long, default_value = "chat.signal.org")]
domain: String,
/// address of the name server
#[arg(long, default_value = "1.1.1.1", value_parser=parse_host)]
ns_address: Host<Arc<str>>,
#[arg(long, default_value = "1.1.1.1")]
ns_address: IpAddr,
/// port of the name server
#[arg(long, default_value = "443")]
ns_port: u16,
}

fn parse_host(s: &str) -> Result<Host<Arc<str>>, Infallible> {
Ok(Host::parse_as_ip_or_domain(s))
ns_port: NonZeroU16,
}

#[tokio::main]
Expand All @@ -44,28 +41,32 @@ async fn main() {
.try_init();

let args = Args::parse();
let address = args.ns_address;

let host = args.ns_address.to_string().into();
let connection_params = ConnectionParams {
route_type: RouteType::Direct,
http_request_decorator: HttpRequestDecoratorSeq::default(),
transport: TransportConnectionParams {
sni: Arc::clone(&host),
tcp_host: args.ns_address,
port: NonZeroU16::try_from(args.ns_port).expect("valid port value"),
certs: RootCertificates::Native,
let host: Arc<str> = address.to_string().into();
let route = HttpsTlsRoute {
fragment: HttpRouteFragment {
host_header: host.clone(),
path_prefix: "".into(),
front_name: None,
},
inner: TlsRoute {
fragment: TlsRouteFragment {
root_certs: RootCertificates::Native,
sni: Host::Domain(host),
alpn: Some(Alpn::Http2),
},
inner: TcpRoute {
address,
port: args.ns_port,
},
},
http_host: host,
connection_confirmation_header: None,
};

let doh_transport = DohTransport::connect(connection_params.clone(), !args.no_ipv6)
let doh_transport = DohTransport::connect(route.clone(), !args.no_ipv6)
.await
.expect("connected to the DNS server");
log::info!(
"successfully connected to the DNS server at {:?}",
connection_params
);
log::info!("successfully connected to the DNS server at {:?}", route);

let request = DnsLookupRequest {
hostname: Arc::from(args.domain),
Expand Down
37 changes: 22 additions & 15 deletions rust/net/infra/src/dns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ use crate::certs::RootCertificates;
use crate::dns::custom_resolver::CustomDnsResolver;
use crate::dns::dns_errors::Error;
use crate::dns::dns_lookup::{DnsLookup, DnsLookupRequest, StaticDnsMap, SystemDnsLookup};
use crate::dns::dns_transport_doh::{DohTransport, CLOUDFLARE_NS};
use crate::dns::dns_transport_doh::{DohTransport, CLOUDFLARE_IP};
use crate::dns::dns_types::ResourceType;
use crate::dns::dns_utils::oneshot_broadcast::Receiver;
use crate::dns::dns_utils::{log_safe_domain, oneshot_broadcast};
use crate::dns::lookup_result::LookupResult;
use crate::host::Host;
use crate::route::{HttpRouteFragment, HttpsTlsRoute, TcpRoute, TlsRoute, TlsRouteFragment};
use crate::timeouts::{DNS_FALLBACK_LOOKUP_TIMEOUTS, DNS_SYSTEM_LOOKUP_TIMEOUT};
use crate::utils::{self, ObservableEvent};
use crate::{ConnectionParams, HttpRequestDecoratorSeq, RouteType, TransportConnectionParams};
use crate::Alpn;

pub mod custom_resolver;
mod dns_errors;
Expand Down Expand Up @@ -81,20 +81,27 @@ struct LookupOption {
pub fn build_custom_resolver_cloudflare_doh(
network_change_event: &ObservableEvent,
) -> CustomDnsResolver<DohTransport> {
let host: Arc<str> = Arc::from(CLOUDFLARE_NS);
let connection_params = ConnectionParams {
route_type: RouteType::Direct,
http_host: host.clone(),
transport: TransportConnectionParams {
port: nonzero!(443u16),
tcp_host: Host::Domain(host.clone()),
sni: host.clone(),
certs: RootCertificates::Native,
let ip_addr = CLOUDFLARE_IP;
let host: Arc<str> = Arc::from(ip_addr.to_string());
let target = HttpsTlsRoute {
fragment: HttpRouteFragment {
path_prefix: "".into(),
front_name: None,
host_header: host.clone(),
},
inner: TlsRoute {
fragment: TlsRouteFragment {
sni: ip_addr.into(),
root_certs: RootCertificates::Native,
alpn: Some(Alpn::Http2),
},
inner: TcpRoute {
address: ip_addr,
port: nonzero!(443u16),
},
},
http_request_decorator: HttpRequestDecoratorSeq::default(),
connection_confirmation_header: None,
};
CustomDnsResolver::<DohTransport>::new(connection_params, network_change_event)
CustomDnsResolver::<DohTransport>::new(target, network_change_event)
}

impl DnsResolver {
Expand Down
51 changes: 11 additions & 40 deletions rust/net/infra/src/dns/dns_transport_doh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
// Copyright 2024 Signal Messenger, LLC.
// SPDX-License-Identifier: AGPL-3.0-only
//
use std::collections::HashMap;
use std::net::{Ipv4Addr, Ipv6Addr};
use std::net::IpAddr;
use std::sync::Arc;

use async_trait::async_trait;
Expand All @@ -16,43 +15,15 @@ use http::{HeaderValue, Method};
use crate::dns::custom_resolver::{DnsQueryResult, DnsTransport};
use crate::dns::dns_errors::Error;
use crate::dns::dns_lookup::DnsLookupRequest;
use crate::dns::dns_message;
use crate::dns::dns_message::{parse_a_record, parse_aaaa_record};
use crate::dns::dns_types::ResourceType;
use crate::dns::lookup_result::LookupResult;
use crate::dns::{dns_message, DnsResolver};
use crate::http_client::{http2_client, AggregatingHttp2Client};
use crate::tcp_ssl::DirectConnector;
use crate::{dns, ConnectionParams, DnsSource};
use crate::route::{HttpsTlsRoute, TcpRoute, TlsRoute};
use crate::{dns, DnsSource};

pub const CLOUDFLARE_NS: &str = "1.1.1.1";
pub const MAX_RESPONSE_SIZE: usize = 10240;
pub const KNOWN_NAMESERVERS: &[(&str, Ipv4Addr, Ipv6Addr)] = &[
(
CLOUDFLARE_NS,
ip_addr!(v4, "1.1.1.1"),
ip_addr!(v6, "2606:4700:4700::1111"),
),
(
"dns.google",
ip_addr!(v4, "8.8.8.8"),
ip_addr!(v6, "2001:4860:4860::8888"),
),
];

fn dns_resolver_for_known_ns(ipv6_enabled: bool) -> DnsResolver {
let map: HashMap<_, _> = KNOWN_NAMESERVERS
.iter()
.map(|(name, ipv4, ipv6)| {
(
*name,
LookupResult::new(DnsSource::Static, vec![*ipv4], vec![*ipv6]),
)
})
.collect();
let result = DnsResolver::new_from_static_map(map);
result.set_ipv6_enabled(ipv6_enabled);
result
}
pub(crate) const CLOUDFLARE_IP: IpAddr = ip_addr!("1.1.1.1");
const MAX_RESPONSE_SIZE: usize = 10240;

/// DNS transport that sends queries over HTTPS
#[derive(Clone, Debug)]
Expand All @@ -62,21 +33,21 @@ pub struct DohTransport {

#[async_trait]
impl DnsTransport for DohTransport {
type ConnectionParameters = ConnectionParams;
type ConnectionParameters = HttpsTlsRoute<TlsRoute<TcpRoute<IpAddr>>>;

fn dns_source() -> DnsSource {
DnsSource::DnsOverHttpsLookup
}

async fn connect(
connection_params: Self::ConnectionParameters,
ipv6_enabled: bool,
_ipv6_enabled: bool,
) -> dns::Result<Self> {
let connector = DirectConnector::new(dns_resolver_for_known_ns(ipv6_enabled));
match http2_client(&connector, connection_params, MAX_RESPONSE_SIZE).await {
let log_tag = "DNS-over-HTTPS".into();
match http2_client(connection_params, MAX_RESPONSE_SIZE, &log_tag).await {
Ok(http_client) => Ok(Self { http_client }),
Err(error) => {
log::error!("Failed to create HTTP2 client: {}", error);
log::error!("[{log_tag}] Failed to create HTTP2 client: {error}");
Err(Error::TransportFailure)
}
}
Expand Down
Loading

0 comments on commit 19506e0

Please sign in to comment.