How Iroh's Address Lookup Service Works: DNS, PKARR, and Pluggable Endpoint Discovery

Iroh's address lookup service resolves remote endpoint identifiers through a pluggable trait system that supports DNS, PKARR, and in-memory backends, automatically publishing and resolving addressing information via the AddressLookup trait defined in iroh/src/lib.rs.

The n0-computer/iroh repository implements a flexible endpoint discovery mechanism through its address_lookup module. This system abstracts address resolution behind the AddressLookup trait, allowing applications to discover peers via DNS TXT records, PKARR signed packets, or custom in-memory stores. The Iroh address lookup service seamlessly integrates with the socket layer to handle background publishing and asynchronous resolution.

The AddressLookup Trait Interface

At the core of the Iroh address lookup service is the AddressLookup trait exposed from iroh/src/lib.rs. This trait defines two optional behaviors that implementations provide:

  • publish(&self, data: &EndpointData): Publishes the local endpoint's addressing information for remote peers to discover. Only services that advertise addresses implement this method.
  • resolve(&self, endpoint_id: EndpointId) -> Option<BoxStream<Result<Item, Error>>>: Resolves a remote EndpointId into a stream of Item objects containing EndpointInfo (relay URLs, direct IPs, and user data).

The trait uses BoxStream to support asynchronous, multi-item resolution, allowing lookup services to return multiple candidate addresses or update addresses over time.

Built-in Lookup Implementations

The repository provides three concrete implementations of the AddressLookup trait, each serving different network discovery requirements.

DNS Resolution via TXT Records

The DnsAddressLookup implementation in iroh/src/address_lookup/dns.rs resolves endpoints by querying DNS TXT records. It constructs queries using the format _iroh.<z-base-32-id>.<origin>, where the endpoint ID is encoded in z-base-32. The parser extracts attributes such as relay= to construct EndpointInfo objects containing relay URLs and direct connection hints.

PKARR Publishing and Resolution

The PKARR implementation in iroh/src/address_lookup/pkarr.rs provides public-key addressable resource records through HTTP relays. This module contains two primary components:

  • PkarrPublisher: Signs endpoint data with the local secret key and pushes records to PKARR relays. An internal PublisherService background task periodically republishes information and retries on failure, ensuring remote peers can always discover the latest address.
  • PkarrResolver: Fetches and verifies signed PKARR records from relays to resolve remote endpoint IDs.

The publisher supports configurable TTL values and address filtering via AddrFilter to control which addressing information gets advertised.

In-Memory Lookup for Testing

The MemoryLookup struct in iroh/src/address_lookup/memory.rs provides a simple mutable map for manual endpoint injection. This implementation stores EndpointInfo objects supplied directly by the application, making it ideal for testing scenarios or out-of-band discovery mechanisms where network-based lookup is unnecessary.

Socket Layer Integration and Remote Mapping

The AddressLookupServices struct combines publisher and resolver implementations into a unified service used by Endpoint::address_lookup. This structure holds an optional publisher and an optional resolver, allowing endpoints to resolve addresses without publishing their own, or publish without performing lookups.

When the socket layer needs to contact a remote endpoint, it:

  1. Calls address_lookup.resolve(id) to obtain a stream of Items.
  2. Processes the stream to extract EndpointInfo containing relay URLs and direct IPs.
  3. Selects the best address based on AddrFilter constraints and connection preferences.

The remote-map component in iroh/src/socket/remote_map/*.rs tracks pending connection attempts and drives the lookup process through trigger_address_lookup and handle_address_lookup_item. This tight integration means address discovery is transparent to the rest of the library—an Endpoint simply declares which lookup services it wants, and the socket layer automatically performs the necessary DNS or PKARR queries.

Practical Implementation Examples

The following examples demonstrate how to configure different lookup services in an Iroh application.

Building a DNS lookup for the production iroh DNS zone:

let dns_lookup = iroh::address_lookup::DnsAddressLookup::n0_dns()
    .build(); // builder → DnsAddressLookup

Configuring a PKARR publisher with custom TTL and address filtering:

let pkarr_pub = iroh::address_lookup::PkarrPublisher::n0_dns()
    .ttl(60)                      // optional custom TTL
    .addr_filter(iroh::address_lookup::AddrFilter::unfiltered())
    .build(secret_key, tls_config);

Combining services into an AddressLookupServices and attaching to an endpoint:

let services = iroh::address_lookup::AddressLookupServices::builder()
    .resolver(dns_lookup)   // discover other peers via DNS
    .publisher(pkarr_pub)   // publish our own address via PKARR
    .build();

let endpoint = iroh::Endpoint::builder(presets::N0)
    .address_lookup(services)
    .bind()
    .await?;

Using the in-memory lookup for testing or manual endpoint injection:

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()?),
));

Resolving a remote endpoint ID after receiving a connection ticket:

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

Summary

  • Pluggable Architecture: The AddressLookup trait in iroh/src/lib.rs abstracts endpoint discovery behind publish and resolve methods, enabling custom lookup implementations.
  • Multiple Backends: The framework provides DNS-based resolution (iroh/src/address_lookup/dns.rs), PKARR signed records (iroh/src/address_lookup/pkarr.rs), and in-memory storage (iroh/src/address_lookup/memory.rs).
  • Automatic Publishing: The PkarrPublisher uses a background PublisherService to periodically republish endpoint information and retry on network failures.
  • Socket Integration: The AddressLookupServices struct combines publishers and resolvers, while the remote-map component in iroh/src/socket/remote_map/*.rs handles trigger_address_lookup and handle_address_lookup_item to automate address discovery during connection establishment.

Frequently Asked Questions

What is the difference between the publisher and resolver in Iroh's address lookup service?

The publisher advertises the local endpoint's addressing information (relay URLs, IPs) to the network, while the resolver queries the network to discover addressing information for remote endpoints. An AddressLookupServices instance can configure either one or both, allowing nodes to resolve addresses without publishing their own, or publish without performing lookups.

How does PKARR address resolution work in Iroh?

PKARR resolution uses the PkarrResolver to fetch signed resource records from PKARR HTTP relays. The PkarrPublisher signs endpoint data with the node's secret key and pushes it to relays, where the PublisherService background task handles periodic republishing and failure retries. Remote nodes resolve these records to obtain verified EndpointInfo containing relay URLs and direct addresses.

Can I use custom address lookup implementations with Iroh?

Yes, you can implement the AddressLookup trait from iroh/src/lib.rs to create custom lookup mechanisms. The trait only requires implementing publish and/or resolve methods, allowing integration with proprietary discovery services, distributed hash tables, or other naming systems beyond the built-in DNS and PKARR options.

How does Iroh handle address changes and updates?

When the local endpoint's address changes (such as when a new relay URL becomes reachable), the publisher side pushes a fresh signed packet or DNS record immediately. The PublisherService in pkarr.rs maintains a background task that periodically republishes this information and retries on failure, ensuring that remote peers can always discover the latest address through subsequent resolve calls.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →