Skip to content

Commit

Permalink
test: iroh-dns-server mainline resolution
Browse files Browse the repository at this point in the history
  • Loading branch information
Frando committed Apr 29, 2024
1 parent 749c389 commit 19fb463
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 17 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions iroh-dns-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,4 @@ z32 = "1.1.1"
hickory-resolver = "0.24.0"
iroh-net = { version = "0.14.0", path = "../iroh-net" }
iroh-test = { path = "../iroh-test" }
mainline = "<1.5.0"
17 changes: 11 additions & 6 deletions iroh-dns-server/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,16 @@ impl MetricsConfig {
pub struct MainlineConfig {
/// Set to true to enable the mainline lookup.
pub enabled: bool,
/// Set custom bootstrap nodes.
///
/// If empty this will use the default bittorrent mainline bootstrap nodes as defined by pkarr.
pub bootstrap: Vec<SocketAddr>,
}

#[allow(clippy::derivable_impls)]
impl Default for MainlineConfig {
fn default() -> Self {
Self { enabled: false }
Self { enabled: false, bootstrap: vec![]}
}
}

Expand Down Expand Up @@ -121,11 +125,12 @@ impl Config {
}
}

pub(crate) fn mainline_enabled(&self) -> bool {
self.mainline
.as_ref()
.map(|x| x.enabled)
.unwrap_or_default()
pub(crate) fn mainline_enabled(&self) -> Option<&Vec<SocketAddr>> {
match self.mainline.as_ref() {
None => None,
Some(config) if !config.enabled => None,
Some(config) => Some(&config.bootstrap),
}
}
}

Expand Down
46 changes: 44 additions & 2 deletions iroh-dns-server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ mod util;

#[cfg(test)]
mod tests {
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr};
use std::{net::{Ipv4Addr, Ipv6Addr, SocketAddr}, str::FromStr};

use anyhow::Result;
use hickory_resolver::{
Expand All @@ -28,7 +28,7 @@ mod tests {
},
key::SecretKey,
};
use pkarr::SignedPacket;
use pkarr::{PkarrClient, SignedPacket};
use url::Url;

use crate::server::Server;
Expand Down Expand Up @@ -177,6 +177,48 @@ mod tests {
Ok(())
}

#[tokio::test]
async fn integration_mainline() -> Result<()> {
iroh_test::logging::setup_multithreaded();

// run a mainline testnet
let testnet = mainline::dht::Testnet::new(5);
let bootstrap = testnet
.bootstrap
.iter()
.map(|addr| SocketAddr::from_str(addr).unwrap())
.collect::<Vec<_>>();

// spawn our server with mainline support
let (server, nameserver, _http_url) = Server::spawn_for_tests_with_mainline(Some(bootstrap)).await?;

let origin = "irohdns.example.";

// create a signed packet
let secret_key = SecretKey::generate();
let node_id = secret_key.public();
let relay_url: Url = "https://relay.example.".parse()?;
let node_info = NodeInfo::new(node_id, Some(relay_url.clone()));
let signed_packet = node_info.to_pkarr_signed_packet(&secret_key, 30)?;

// publish the signed packet to our DHT
let pkarr = PkarrClient::builder().bootstrap(&testnet.bootstrap).build();
pkarr.publish(&signed_packet).await?;

// resolve via DNS from our server, which will lookup from our DHT
let resolver = test_resolver(nameserver);
let res = lookup_by_id(&resolver, &node_id, origin).await?;

assert_eq!(res.node_id, node_id);
assert_eq!(res.info.relay_url.map(Url::from), Some(relay_url));

server.shutdown().await?;
for node in testnet.nodes {
node.shutdown();
}
Ok(())
}

fn test_resolver(nameserver: SocketAddr) -> DnsResolver {
let mut config = ResolverConfig::new();
let nameserver_config = NameServerConfig::new(nameserver, Protocol::Udp);
Expand Down
26 changes: 22 additions & 4 deletions iroh-dns-server/src/server.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//! The main server which combines the DNS and HTTP(S) servers.
use anyhow::Result;
use iroh_metrics::metrics::start_metrics_server;
use tracing::info;
Expand All @@ -14,9 +15,9 @@ use crate::{
/// Spawn the server and run until the `Ctrl-C` signal is received, then shutdown.
pub async fn run_with_config_until_ctrl_c(config: Config) -> Result<()> {
let mut store = ZoneStore::persistent(Config::signed_packet_store_path()?)?;
if config.mainline_enabled() {
if let Some(bootstrap) = config.mainline_enabled() {
info!("mainline fallback enabled");
store = store.with_pkarr(Default::default());
store = store.with_mainline_fallback(Some(bootstrap));
};
let server = Server::spawn(config, store).await?;
tokio::signal::ctrl_c().await?;
Expand Down Expand Up @@ -89,7 +90,16 @@ impl Server {
/// HTTP server.
#[cfg(test)]
pub async fn spawn_for_tests() -> Result<(Self, std::net::SocketAddr, url::Url)> {
use crate::config::MetricsConfig;
Self::spawn_for_tests_with_mainline(None).await
}

/// Spawn a server suitable for testing, while optionally enabling mainline with custom
/// bootstrap addresses.
#[cfg(test)]
pub async fn spawn_for_tests_with_mainline(
bootstrap: Option<Vec<std::net::SocketAddr>>,
) -> Result<(Self, std::net::SocketAddr, url::Url)> {
use crate::config::{MainlineConfig, MetricsConfig};
use std::net::{IpAddr, Ipv4Addr};

let mut config = Config::default();
Expand All @@ -99,8 +109,16 @@ impl Server {
config.http.as_mut().unwrap().bind_addr = Some(IpAddr::V4(Ipv4Addr::LOCALHOST));
config.https = None;
config.metrics = Some(MetricsConfig::disabled());
config.mainline = bootstrap.map(|bootstrap| MainlineConfig {
enabled: true,
bootstrap,
});

let store = ZoneStore::in_memory()?;
let mut store = ZoneStore::in_memory()?;
if let Some(bootstrap) = config.mainline_enabled() {
info!("mainline fallback enabled");
store = store.with_mainline_fallback(Some(bootstrap));
};
let server = Self::spawn(config, store).await?;
let dns_addr = server.dns_server.local_addr();
let http_addr = server.http_server.http_addr().expect("http is set");
Expand Down
30 changes: 25 additions & 5 deletions iroh-dns-server/src/store.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
//! Pkarr packet store used to resolve DNS queries.
use std::{collections::BTreeMap, num::NonZeroUsize, path::Path, sync::Arc, time::Duration};
use std::{
collections::BTreeMap, net::SocketAddr, num::NonZeroUsize, path::Path, sync::Arc,
time::Duration,
};

use anyhow::Result;
use hickory_proto::rr::{Name, RecordSet, RecordType, RrKey};
Expand Down Expand Up @@ -55,12 +58,29 @@ impl ZoneStore {
Ok(Self::new(packet_store))
}

/// Configure a pkarr client for resolution of packets from the bittorrent
/// mainline DHT.
/// Configure a pkarr client for resolution of packets from the bittorent mainline DHT.
///
/// This will be used only as a fallback if there is no local info available.
pub fn with_pkarr(self, pkarr: Option<Arc<PkarrClient>>) -> Self {
Self { pkarr, ..self }
///
/// Optionally set custom bootstrap nodes. If `bootstrap` is empty it will use the default
/// mainline bootstrap nodes.
pub fn with_mainline_fallback(self, bootstrap: Option<&Vec<SocketAddr>>) -> Self {
let pkarr_client = match bootstrap {
None => PkarrClient::default(),
Some(addrs) if addrs.is_empty() => PkarrClient::default(),
Some(addrs) => PkarrClient::builder()
.bootstrap(
&addrs
.iter()
.map(|addr| addr.to_string())
.collect::<Vec<_>>(),
)
.build(),
};
Self {
pkarr: Some(Arc::new(pkarr_client)),
..self
}
}

/// Create a new zone store.
Expand Down

0 comments on commit 19fb463

Please sign in to comment.