# How Iroh Handles Address Lookup: DNS, PKARR, and the Pluggable Discovery System

> Discover how Iroh handles address lookup using its pluggable discovery system. Explore DNS, PKARR, and in-memory backends for efficient endpoint discovery.

- Repository: [number zero/iroh](https://github.com/n0-computer/iroh)
- Tags: deep-dive
- Published: 2026-07-07

---

**Iroh resolves remote endpoint addresses through a pluggable subsystem centered on the `AddressLookup` trait, supporting DNS, PKARR, and in-memory backends that publish and resolve `EndpointData` through asynchronous streams.**

In the n0-computer/iroh repository, establishing connectivity between peers depends on a flexible address lookup architecture that adapts to diverse network environments. The system abstracts address discovery behind a unified trait, allowing applications to resolve `EndpointId` values into actionable network coordinates via DNS records, PKARR packets, or custom in-memory stores.

## The AddressLookup Trait: Core Abstraction

At the heart of Iroh's discovery mechanism lies the `AddressLookup` trait, exposed from [`iroh/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/lib.rs). This interface defines two primary behaviors that implementations can provide:

- **`publish(&self, data: &EndpointData)`** – Advertises the local endpoint's addressing information for remote peers to discover.
- **`resolve(&self, endpoint_id: EndpointId)`** – Resolves a remote identifier into a `BoxStream` of `Result<Item, Error>` containing addressing details.

The `resolve` method returns an asynchronous stream of `Item` objects, each encapsulating `EndpointInfo` with relay URLs, direct IP addresses, and user data. This streaming approach accommodates scenarios where multiple address options exist or discovery occurs incrementally.

## Built-in Lookup Services

The Iroh codebase provides three concrete implementations of the `AddressLookup` trait, each optimized for different discovery scenarios.

### DNS Lookup

The **DNS lookup** implementation queries TXT records under the `_iroh.<z-base-32-id>.<origin>` namespace. It parses attributes such as `relay=` to extract relay server URLs. The implementation resides in [`iroh/src/address_lookup/dns.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup/dns.rs) and provides a `DnsAddressLookup` builder for easy configuration.

### PKARR Lookup

For decentralized discovery, Iroh implements the **PKARR protocol** (public-key addressable resource records) via [`iroh/src/address_lookup/pkarr.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup/pkarr.rs). This module contains two distinct components:

- **`PkarrPublisher`** – Signs and pushes resource records to an HTTP relay, periodically republishing via a background `PublisherService` task that retries on failure.
- **`PkarrResolver`** – Fetches and verifies signed records from the PKARR relay network.

The PKARR implementation supports additional configuration such as custom TTL values and address filtering through `AddrFilter`.

### In-Memory Lookup

For testing scenarios or out-of-band discovery, [`iroh/src/address_lookup/memory.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup/memory.rs) provides a **`MemoryLookup`** type. This mutable map stores `EndpointInfo` objects supplied directly by the application, bypassing network-based resolution entirely.

## The Resolution Flow

When the socket layer initiates a connection to a remote peer, Iroh's address lookup follows a specific sequence:

1. The system calls `address_lookup.resolve(id)`, returning a stream of `Item` objects.
2. Each `Item` yields `EndpointInfo` containing relay URLs, direct IPs, and metadata.
3. The socket layer selects the optimal address (preferring relays, respecting `AddrFilter` constraints) and attempts the connection.

This process is orchestrated through the `AddressLookupServices` struct, created via `Endpoint::address_lookup`. This structure holds an optional **publisher** and **resolver**, allowing asymmetric configurations where a node might resolve addresses via DNS while publishing via PKARR.

## Publishing Endpoint Information

When local addressing information changes—such as when a new relay URL becomes reachable—the publisher side activates. In `PkarrPublisher`, a background task periodically constructs fresh signed packets and pushes them to the configured relay. Similarly, DNS-based publishing updates TXT records to reflect current reachability. This ensures remote peers can always discover the latest valid addresses without manual intervention.

## Integration with the Socket Layer

The lookup service integrates tightly with Iroh's connection management through the **remote-map** component located in `iroh/src/socket/remote_map/*.rs`. This subsystem:

- Tracks pending connection attempts awaiting address resolution.
- Triggers lookups via `trigger_address_lookup` when connection establishment begins.
- Processes incoming lookup items through `handle_address_lookup_item`, updating the routing table with new addressing information.

This integration makes address discovery transparent to the rest of the library. An `Endpoint` simply declares its preferred lookup services, and [`iroh/src/socket.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/socket.rs) automatically manages the background DNS or PKARR queries required to maintain connectivity.

## Practical Examples

Configure a DNS resolver combined with a PKARR publisher:

```rust
// Build a DNS lookup that queries the production iroh DNS zone.
let dns_lookup = iroh::address_lookup::DnsAddressLookup::n0_dns()
    .build();

// Build a PKARR publisher that signs records with our secret key.
let pkarr_pub = iroh::address_lookup::PkarrPublisher::n0_dns()
    .ttl(60)
    .addr_filter(iroh::address_lookup::AddrFilter::unfiltered())
    .build(secret_key, tls_config);

// Combine them into a service used by an Endpoint.
let services = iroh::address_lookup::AddressLookupServices::builder()
    .resolver(dns_lookup)
    .publisher(pkarr_pub)
    .build();

// Attach the service to an endpoint.
let endpoint = iroh::Endpoint::builder(presets::N0)
    .address_lookup(services)
    .bind()
    .await?;

```

Use the in-memory lookup for testing:

```rust
let mem_lookup = iroh::address_lookup::memory::MemoryLookup::new();
mem_lookup.add_endpoint_info(iroh::EndpointInfo::from_parts(
    secret_key.public(),
    iroh::EndpointData::default()
        .add_relay("https://relay.example.com".parse()?),
));

```

Resolve a remote endpoint manually:

```rust
if let Some(mut stream) = endpoint.address_lookup().resolve(remote_id) {
    while let Some(item) = stream.next().await {
        let info = item?.info();
        // Use `info` to open a connection.
    }
}

```

## Summary

- **Pluggable architecture**: The `AddressLookup` trait in [`iroh/src/lib.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/lib.rs) abstracts address discovery, supporting DNS, PKARR, and custom implementations.
- **Dual-mode operation**: Services can act as **resolvers** (fetching remote addresses), **publishers** (advertising local addresses), or both.
- **Key source files**: [`dns.rs`](https://github.com/n0-computer/iroh/blob/main/dns.rs) for TXT record queries, [`pkarr.rs`](https://github.com/n0-computer/iroh/blob/main/pkarr.rs) for decentralized signed records, and [`memory.rs`](https://github.com/n0-computer/iroh/blob/main/memory.rs) for manual injection.
- **Socket integration**: The remote-map component in `iroh/src/socket/remote_map/*.rs` transparently drives lookups during connection establishment.
- **Streaming resolution**: The `resolve` method returns asynchronous streams, enabling incremental discovery and multiple address candidates.

## Frequently Asked Questions

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

**DNS lookup** queries centralized DNS zones for TXT records containing relay URLs, suitable for traditional infrastructure. **PKARR lookup** uses the decentralized PKARR protocol with cryptographically signed records, allowing nodes to publish addresses without centralized DNS control. Both implement the same `AddressLookup` trait and can be used interchangeably or combined.

### How does Iroh handle address changes when my IP or relay changes?

The **publisher** side of the lookup service detects addressing changes and pushes updates automatically. In `PkarrPublisher`, a background `PublisherService` task periodically republishes signed packets with fresh `EndpointData`. Similarly, DNS publishers update TXT records. Remote peers receive these updates through subsequent `resolve` calls.

### Can I use Iroh's address lookup without publishing my own address?

Yes. The `AddressLookupServices` builder allows you to configure only a **resolver** without a **publisher**. This creates a "read-only" configuration where your node can discover others via DNS or PKARR but does not advertise its own addressing information, which is useful for clients that only initiate connections.

### Where does the actual connection logic use the resolved addresses?

The socket layer in [`iroh/src/socket.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/socket.rs) and the remote-map subsystem in `iroh/src/socket/remote_map/*.rs` consume lookup results. When you call `resolve`, the remote-map tracks pending attempts via `trigger_address_lookup` and processes results through `handle_address_lookup_item`, selecting optimal paths and updating connection state without requiring manual intervention.