# How to Use DnsAddressLookup with Iroh: A Complete Guide to Distributed Naming

> Learn how to use DnsAddressLookup with Iroh in this comprehensive guide. Discover asynchronous DNS resolution for various record types with configurable options.

- Repository: [number zero/iroh](https://github.com/n0-computer/iroh)
- Tags: how-to-guide
- Published: 2026-07-15

---

**Iroh's `DnsResolver` provides asynchronous DNS resolution for IPv4, IPv6, TXT records, and specialized Iroh endpoint lookups, featuring configurable timeouts, staggered retries, and runtime-swappable resolver implementations.**

Iroh (n0-computer/iroh) is a Rust library for building distributed systems that relies on robust peer discovery mechanisms. The `DnsAddressLookup` functionality enables your application to resolve hostnames and cryptographic node identities via DNS, including custom `_iroh.` endpoint records that bridge public keys to network addresses. This guide covers the implementation details found in [`iroh-dns/src/dns.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/dns.rs) and demonstrates practical usage patterns.

## Understanding the DnsResolver Architecture

At the core of Iroh's DNS functionality is a flexible resolver system designed for production distributed workloads.

### The Resolver Trait

The **`Resolver`** trait defines the contract for all DNS operations in Iroh. Located at [lines 52-64 in [`iroh-dns/src/dns.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/dns.rs)](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/dns.rs#L52-L64), this trait specifies async methods for resolving IPv4 addresses, IPv6 addresses, and TXT records. By programming against this trait rather than concrete implementations, you can swap resolver backends at runtime for testing or specialized network environments.

### The DnsResolver Struct

The **`DnsResolver`** struct serves as the primary entry point for DNS operations. As implemented at [lines 40-55](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/dns.rs#L40-L55), it maintains an `Arc<Inner>` containing an `ArcSwap<Box<dyn Resolver>>`. This architecture allows Iroh to atomically swap resolver implementations without interrupting in-flight queries—critical for handling network configuration changes in long-running applications.

All lookup operations flow through `Inner::op`, which handles timeout enforcement, error translation, and cache coordination.

## Creating a DNS Resolver

### Using the Builder API

For applications requiring custom nameservers or DNS-over-TLS/HTTPS, Iroh exposes a builder pattern at [lines 29-61](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/dns.rs#L29-L61). The builder supports system default resolution, custom upstream servers, or fallback to public resolvers like Google DNS.

```rust
use iroh_dns::dns::{DnsResolver, N0_DNS_ENDPOINT_ORIGIN_PROD};
use std::time::Duration;

// Create resolver with system defaults
let resolver = DnsResolver::new();

// The resolver is now ready for async DNS operations

```

## Performing DNS Address Lookups

### Standard IP Resolution

Resolve standard hostnames to IPv4 or IPv6 addresses using `lookup_ipv4` and `lookup_ipv6`. Both methods accept a hostname string and a `Duration` timeout, returning async iterators over `IpAddr` values.

```rust
// IPv4 lookup with 3-second timeout
let ipv4_iter = resolver
    .lookup_ipv4("example.com", Duration::from_secs(3))
    .await?;
    
for ip in ipv4_iter {
    println!("Resolved IPv4: {}", ip);
}

```

### Iroh Endpoint Resolution

Iroh extends standard DNS with **endpoint records** that map `EndpointId` values (Z-base-32 encoded public keys) to connection information. The `lookup_endpoint_by_id` method, found at [lines 49-57](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/dns.rs#L49-L57), constructs the proper DNS name format `_iroh.<z32encoded-pubkey>.<origin>` and queries the TXT record for `EndpointInfo`.

```rust
use iroh_base::EndpointId;

// EndpointId from a Z-base-32 encoded public key
let endpoint_id = EndpointId::from_z32("z32encodedpubkey...")?;

// Lookup against the production Iroh DNS origin
let info = resolver
    .lookup_endpoint_by_id(&endpoint_id, N0_DNS_ENDPOINT_ORIGIN_PROD)
    .await?;
    
println!("Relay URL: {:?}", info.relay_url);

```

## Resilient Lookup Patterns

### Staggered Lookups for Network Resilience

When operating over flaky networks, the **`stagger_call`** implementation at [lines 333-369](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/dns.rs#L333-L369) provides retry logic with configurable delays. Staggered methods like `lookup_ipv6_staggered` and `lookup_endpoint_by_domain_name_staggered` issue multiple requests with specified millisecond intervals, returning the first successful result.

```rust
// IPv6 lookup with staggered retries at 200ms and 500ms
let ipv6_iter = resolver
    .lookup_ipv6_staggered("example.com", Duration::from_secs(3), &[200, 500])
    .await?;

// Staggered endpoint lookup by domain name
let endpoint_info = resolver
    .lookup_endpoint_by_domain_name_staggered("_iroh.myexample.com", &[100, 300])
    .await?;

```

## Managing Resolver State

### Cache Handling and Reset

Long-running applications must handle network changes such as VPN connections or Wi-Fi roaming. The `DnsResolver` provides two state management methods:

- **`clear_cache()`** ([lines 73-77](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/dns.rs#L73-L77)): Empties the internal DNS cache while preserving the current resolver configuration.
- **`reset()`** ([lines 78-85](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/dns.rs#L78-L85)): Rebuilds the underlying Hickory DNS client with fresh system configuration, useful after network interface changes.

```rust
// Clear cached entries without rebuilding the client
resolver.clear_cache();

// Rebuild resolver with updated system DNS settings
resolver.reset();

```

## Complete Working Example

```rust
use iroh_dns::dns::{DnsResolver, DnsError, LookupError, N0_DNS_ENDPOINT_ORIGIN_PROD};
use iroh_base::EndpointId;
use std::time::Duration;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Build a resolver with the system defaults
    let resolver = DnsResolver::new();

    // Simple IPv4 lookup
    let host = "example.com";
    let ipv4_iter = resolver
        .lookup_ipv4(host, Duration::from_secs(3))
        .await?;
    for ip in ipv4_iter {
        println!("IPv4 for {}: {}", host, ip);
    }

    // IPv6 lookup with staggered retry delays
    let ipv6_iter = resolver
        .lookup_ipv6_staggered(host, Duration::from_secs(3), &[200, 500])
        .await?;
    for ip in ipv6_iter {
        println!("IPv6 for {}: {}", host, ip);
    }

    // Resolve a TXT record for generic service discovery
    let txt_iter = resolver
        .lookup_txt("_myservice.example", Duration::from_secs(3))
        .await?;
    for txt in txt_iter {
        println!("TXT: {}", txt);
    }

    // Iroh endpoint lookup by EndpointId
    let endpoint_id = EndpointId::from_z32("z32encodedpubkey...")?;
    let info = resolver
        .lookup_endpoint_by_id(&endpoint_id, N0_DNS_ENDPOINT_ORIGIN_PROD)
        .await?;
    println!("Endpoint info: {:#?}", info);

    // Staggered endpoint lookup by domain name for extra resilience
    let endpoint_info = resolver
        .lookup_endpoint_by_domain_name_staggered("_iroh.myexample.com", &[100, 300])
        .await?;
    println!("Staggered endpoint info: {:#?}", endpoint_info);

    // Reset the resolver after a network change
    resolver.reset();
    Ok(())
}

```

## Summary

- **`DnsResolver`** in [`iroh-dns/src/dns.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/dns.rs) serves as the primary interface for all DNS operations in Iroh, wrapping a Hickory DNS client with超时 and caching logic.
- The **`Resolver`** trait (lines 52-64) abstracts lookup operations, enabling runtime swapping of resolver implementations via `ArcSwap`.
- **Endpoint lookups** translate `EndpointId` values into DNS queries against `_iroh.<z32id>.<origin>` TXT records, bridging cryptographic identities with network addresses.
- **Staggered lookups** (lines 333-369) improve reliability on unstable networks by retrying with configurable delays until the first success.
- Use **`reset()`** (lines 78-85) to rebuild the resolver after network configuration changes, and **`clear_cache()`** (lines 73-77) to invalidate stale DNS entries.

## Frequently Asked Questions

### How do I configure custom DNS servers instead of system defaults?

Use the **Builder API** in [`iroh-dns/src/dns.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/dns.rs) (lines 29-61) to specify custom nameservers, DNS-over-TLS, or DNS-over-HTTPS endpoints before constructing the `DnsResolver`. If no custom configuration is provided, `DnsResolver::new()` automatically falls back to system settings with Google DNS as a backup.

### What is the format of an Iroh DNS endpoint record?

Iroh endpoint records follow the pattern **`_iroh.<z32encoded-pubkey>.<origin>`**, where the public key is encoded using Z-base-32. The `lookup_endpoint_by_id` method automatically constructs this name from an `EndpointId` and queries the corresponding TXT record, parsing the result into an `EndpointInfo` struct containing relay URLs and direct connection addresses.

### How do staggered lookups improve DNS reliability?

**Staggered lookups** implement a race-with-retry pattern defined at lines 333-369. Instead of failing immediately on timeout, the resolver issues multiple queries with specified millisecond delays (e.g., `[200, 500]`), returning the first successful response. This pattern is particularly effective for IPv6 resolution or endpoint discovery in mobile environments with intermittent connectivity.

### When should I call reset() versus clear_cache() on the resolver?

Call **`clear_cache()`** when you suspect cached DNS entries are stale but the underlying network configuration remains valid. Call **`reset()`** (lines 78-85) after system network changes—such as switching from Wi-Fi to cellular or connecting to a VPN—to rebuild the Hickory DNS client with updated system nameserver settings.