# How to Use Address Lookup Services (DNS and Pkarr) to Discover Peer Addresses in iroh

> Learn how to use iroh's AddressLookup with DNS and PKARR for efficient peer discovery. Resolve peer public keys into routable transport addresses effortlessly.

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

---

**iroh resolves peer `EndpointId` public keys into routable `EndpointAddr` transport addresses by implementing the `AddressLookup` trait, which supports both DNS TXT record queries and PKARR HTTP relay requests for decentralized peer discovery.**

iroh is a peer-to-peer networking library that eliminates the need for manual address exchange by integrating address lookup services directly into the connection flow. By leveraging DNS-based resolution and the PKARR (Public Key Address Resource Record) protocol, applications can publish their network endpoints to distributed or centralized registries and resolve peer addresses dynamically. This guide explores how to configure and use these services according to the n0-computer/iroh source code.

## Understanding the Address Lookup Architecture

At the core of iroh’s discovery mechanism is the **`AddressLookup`** trait defined in [`iroh/src/address_lookup.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup.rs). This trait abstracts the conversion of an `EndpointId` (a peer’s public key) into a full `EndpointAddr` containing transport addresses, relay URLs, and metadata.

The library provides two primary implementations:

- **`DnsAddressLookup`** – Resolves signed PKARR packets stored in DNS zones via TXT record queries.
- **`PkarrResolver`** – Communicates directly with PKARR HTTP relays (such as pkarr.org) to fetch mutable address records.

Both services operate concurrently. When an endpoint attempts to connect to a peer, iroh calls `resolve` on all registered lookup services simultaneously, merging the resulting streams so the first successful response is used immediately while slower services continue in the background (see `AddressLookupServices::resolve` in [`iroh/src/address_lookup.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup.rs), lines 534–566).

## Configuring DNS and Pkarr Resolution

Configure an endpoint to publish its own address and resolve others via both DNS and PKARR using the `Builder` pattern. The `PkarrPublisher` publishes your endpoint’s information, while `DnsAddressLookup` enables resolving peers via DNS.

```rust
use iroh::{
    address_lookup::{self, AddrFilter, PkarrPublisher},
    endpoint::{Builder, presets},
};

async fn configure_endpoint() -> iroh::Result<()> {
    let ep = Builder::new(presets::Minimal)
        .addr_filter(AddrFilter::relay_only())          // Optional: restrict published addresses
        .address_lookup(PkarrPublisher::n0_dns())       // Publish to pkarr.org relay
        .address_lookup(address_lookup::DnsAddressLookup::n0_dns()) // Resolve via DNS
        .bind()
        .await?;
    
    println!("Endpoint ID: {}", ep.id().fmt_short());
    Ok(())
}

```

In this configuration, `PkarrPublisher::n0_dns()` (defined in [`iroh-dns/src/pkarr.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/pkarr.rs), line 104) creates a publisher targeting the default pkarr.org relay, while `DnsAddressLookup::n0_dns()` (defined in [`iroh/src/address_lookup.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup.rs), line 94) configures resolution via standard DNS infrastructure.

## The Address Resolution Workflow

The discovery process follows a publish-store-resolve pipeline involving signed cryptographic packets:

1. **Publish:** When the endpoint’s addressing information changes (e.g., new relay URLs), the `PkarrPublisher` creates a signed PKARR packet containing the `EndpointInfo` (relay URLs, direct IPs, and user data). This packet is signed with the endpoint’s secret key (see [`iroh-dns/src/pkarr.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/pkarr.rs), lines 37–84).

2. **Store:** The signed packet is distributed via either:
   - **PKARR HTTP Relay:** Posted to an HTTP endpoint where it is stored in a mutable DHT.
   - **DNS TXT Record:** Base64-encoded and placed under a DNS name derived from the public key (using `SignedPacket::from_txt_strings` in [`iroh-dns/src/pkarr.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/pkarr.rs), lines 41–70).

3. **Resolve:** Peers locate the endpoint using:
   - **DNS Resolution:** `DnsAddressLookup` queries TXT records for `<public-key>.example.com`, parses the signed packet using `SignedPacket::from_bytes`, verifies the signature, and extracts the `EndpointInfo` (handled by `DnsResolver::lookup_endpoint_by_id` in [`iroh-dns/src/dns.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/dns.rs), lines 112–124).
   - **PKARR Resolution:** `PkarrResolver` fetches the mutable item from the HTTP relay and performs the same signature verification.

Both resolvers return a `BoxStream<Result<Item, Error>>` where `Item` contains the discovered `EndpointInfo` and provenance metadata (`"dns"` or `"pkarr"`).

## Filtering Published Addresses

Restrict which transport addresses get published by supplying an `AddrFilter` to the `PkarrPublisher`. The filter receives the complete set of candidate addresses and returns an ordered `Vec<TransportAddr>` that the service will actually publish.

```rust
use iroh::{
    address_lookup::AddrFilter,
    dns::PkarrPublisher,
    base::TransportAddr,
};
use std::sync::Arc;

fn create_filtered_publisher(secret_key: iroh_base::SecretKey) -> PkarrPublisher {
    let filter = AddrFilter::custom(|addrs| {
        addrs
            .into_iter()
            .filter(|addr| matches!(addr, TransportAddr::Ip(_)))
            .collect()
    });

    PkarrPublisher::builder("https://pkarr.org".parse().unwrap())
        .addr_filter(filter)
        .build(secret_key, Default::default())
}

```

The filter is applied once before data is handed to each service (see `AddressLookupServices::publish` in [`iroh/src/address_lookup.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup.rs), lines 516–525).

## Manual Resolution and Custom Relays

For scenarios requiring explicit control, resolve peer addresses manually or integrate custom PKARR relays at runtime.

Resolve via DNS using `DnsResolver`:

```rust
use iroh::{
    dns::DnsResolver,
    base::EndpointId,
};

async fn resolve_via_dns(peer_id: EndpointId) -> iroh::Result<iroh::base::EndpointInfo> {
    let resolver = DnsResolver::with_nameserver("127.0.0.1:53".parse()?);
    let info = resolver.lookup_endpoint_by_id(&peer_id, "example.org").await?;
    Ok(info)
}

```

Add a custom PKARR resolver to an existing endpoint:

```rust
use iroh::{address_lookup::PkarrResolver, endpoint::Endpoint};

fn add_custom_relay(ep: &Endpoint) -> iroh::Result<()> {
    let resolver = PkarrResolver::new("https://my-relay.example".parse().unwrap());
    ep.address_lookup()
        .expect("endpoint is still open")
        .add(resolver);
    Ok(())
}

```

The `PkarrResolver` implementation resides in [`iroh/src/address_lookup.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup.rs) (module `pkarr`, lines 118–135), while signature verification occurs in [`iroh-dns/src/pkarr.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/pkarr.rs) (lines 90–115).

## Summary

- **Address lookup services** bridge the gap between cryptographic identities (`EndpointId`) and network addresses (`EndpointAddr`) in iroh.
- The **`AddressLookup`** trait in [`iroh/src/address_lookup.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup.rs) enables pluggable resolution via DNS or PKARR relays.
- **`PkarrPublisher`** signs and publishes endpoint data, while **`DnsAddressLookup`** and **`PkarrResolver`** query these records.
- **`AddrFilter`** controls which addresses are published, allowing fine-grained control over network exposure.
- Resolution calls are **concurrent and merged**, ensuring fast discovery without waiting for slow services.

## Frequently Asked Questions

### What is the difference between DNS and PKARR address lookup in iroh?

**DNS lookup** queries traditional DNS infrastructure for TXT records containing base64-encoded PKARR packets, making it compatible with existing DNS servers and domain-based discovery. **PKARR lookup** communicates directly with specialized HTTP relays (like pkarr.org) that store mutable items in a DHT-like structure. Both methods verify the same signed packet format, but DNS offers broader infrastructure compatibility while PKARR provides direct DHT semantics.

### How do I publish my endpoint information to a custom PKARR relay?

Use `PkarrPublisher::builder()` with a custom URL instead of the `n0_dns()` convenience method. Provide your secret key and optional TLS configuration, then register it via the endpoint builder’s `.address_lookup()` method. The publisher will automatically push updates whenever your endpoint’s addressing information changes.

### Can I use multiple address lookup services simultaneously?

Yes. The `Builder` accepts multiple `.address_lookup()` calls, and the `Endpoint` maintains a registry of all services. When resolving a peer, iroh queries all registered services concurrently and merges the results, using the first successful response while allowing slower services to complete in the background. This is handled by `AddressLookupServices::resolve` in [`iroh/src/address_lookup.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup.rs).

### How does iroh verify the integrity of address lookup results?

All address records are transmitted as **signed PKARR packets**. Upon resolution, iroh reconstructs the packet from DNS TXT strings or HTTP response bytes and verifies the cryptographic signature against the `EndpointId` (public key) using `SignedPacket::from_bytes` (see [`iroh-dns/src/pkarr.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/pkarr.rs), lines 90–115). This ensures that only the holder of the corresponding private key could have published the address information, preventing man-in-the-middle attacks during discovery.