How to Set Up Address Lookup Services in iroh: Complete Configuration Guide

Configure address lookup services in iroh by registering implementations of the AddressLookup trait—such as PkarrPublisher or DnsAddressLookup—via Endpoint::builder().address_lookup() before binding the endpoint.

When building peer-to-peer applications with iroh, endpoints need to discover how to reach remote peers using only an EndpointId. The address lookup subsystem handles this by publishing local addressing information to external services and resolving remote endpoint data through a unified registry. This guide demonstrates how to configure these services using the actual implementation from the n0-computer/iroh repository.

Core Concepts

The address lookup system is built on several key abstractions defined in iroh/src/address_lookup.rs.

AddressLookup Trait

The AddressLookup trait defines the minimal interface for any lookup service. Located at lines 33-50, it requires two methods: publish to advertise local endpoint data, and resolve to fetch remote endpoint information. This trait enables custom implementations while maintaining a consistent API for the endpoint.

AddressLookupBuilder

The AddressLookupBuilder trait (lines 41-50) allows services to defer final initialization until the endpoint configuration is complete. Builders are converted into AddressLookup instances once the endpoint is fully constructed, enabling services to access the endpoint's own configuration parameters during setup.

AddressLookupServices Registry

Each Endpoint maintains an AddressLookupServices registry (lines 60-89) that manages multiple lookup services simultaneously. This registry stores boxed AddressLookup instances, maintains an optional address filter, and tracks the last published EndpointData. When resolving remote addresses, it merges result streams from all registered services, ensuring that slower successful lookups are not hidden by faster failures.

AddrFilter

The AddrFilter type—re-exported via iroh::address_lookup::AddrFilter from the iroh-dns crate—provides a user-supplied function that can prune or reorder addresses before publication. For example, you can configure a filter to publish only relay URLs while omitting direct socket addresses.

Built-in Service Types

The iroh ecosystem provides several production-ready implementations for common discovery scenarios.

DNS Resolution

The DnsAddressLookup service, implemented in iroh-dns/src/dns.rs, resolves EndpointIds using standard DNS queries. The convenience constructor DnsAddressLookup::n0_dns() configures the resolver to use the public n0.computer DNS zone.

Pkarr Publishing

The PkarrPublisher service, found in iroh-dns/src/pkarr.rs, publishes endpoint addressing information to a pkarr relay and resolves others through HTTP. Use PkarrPublisher::n0_dns() to target the public n0.computer pkarr relay infrastructure.

Memory Lookup

The MemoryLookup service provides an in-process implementation ideal for testing and embedded scenarios. Defined in iroh/src/memory.rs, it maintains a local hash map of endpoint addresses without network dependencies.

Configuration Examples

Configure DNS and Pkarr Services

To enable both DNS resolution and pkarr publishing for a production endpoint, chain the builders before calling bind():

use iroh::{
    Endpoint,
    address_lookup::{self, AddrFilter},
    endpoint::presets,
};

#[tokio::main]
async fn main() -> Result<(), iroh::Error> {
    let ep = Endpoint::builder(presets::Minimal)
        .addr_filter(AddrFilter::relay_only())
        .address_lookup(address_lookup::PkarrPublisher::n0_dns())
        .address_lookup(address_lookup::DnsAddressLookup::n0_dns())
        .bind()
        .await?;

    Ok(())
}

This configuration automatically publishes the local relay URL via pkarr and can resolve remote peers using DNS.

Use Memory Lookup for Testing

For isolated integration tests, use the memory-backed implementation:

use iroh::{
    Endpoint,
    address_lookup::MemoryLookup,
    endpoint::presets,
};

let memory = MemoryLookup::new();
let ep = Endpoint::builder(presets::Minimal)
    .address_lookup(memory)
    .bind()
    .await?;

This avoids external network calls while maintaining full API compatibility.

Filter Published Addresses

Apply filtering after endpoint construction to restrict which addresses are shared:

let ep = Endpoint::builder(presets::Minimal).bind().await?;
let lookup = ep.address_lookup().expect("endpoint still open");

// Only publish relay URLs, discard direct IPs
lookup.set_addr_filter(address_lookup::AddrFilter::relay_only());

The filter applies to all subsequent publish operations.

Implement Custom Resolvers

For specialized discovery protocols, implement the AddressLookup trait directly:

struct MyResolver;

impl iroh::address_lookup::AddressLookup for MyResolver {
    fn resolve(
        &self,
        endpoint_id: iroh_base::EndpointId,
    ) -> Option<BoxStream<
        Result<iroh::address_lookup::Item, iroh::address_lookup::Error>
    >> {
        // Custom resolution logic here
        None
    }
}

let ep = Endpoint::builder(presets::Minimal).bind().await?;
ep.address_lookup().unwrap().add(MyResolver);

Key Source Files

Understanding the implementation requires examining these specific files in the n0-computer/iroh repository:

  • iroh/src/address_lookup.rs – Core traits (AddressLookup, AddressLookupBuilder), the AddressLookupServices registry, and the merge stream implementation.
  • iroh-dns/src/dns.rs – DNS resolver implementation and DnsAddressLookup types.
  • iroh-dns/src/pkarr.rs – Pkarr publisher (PkarrPublisher) and resolver implementations.
  • iroh/src/memory.rs – In-process memory lookup for testing scenarios.
  • iroh/examples/ – Runnable demonstrations of address lookup configuration.
  • iroh/tests/patchbay/util.rs – Test utilities showing multi-service registration and filtering.

Summary

  • Address lookup services enable endpoint discovery via the AddressLookup trait, requiring publish and resolve methods.
  • Registration occurs during the builder phase using Endpoint::builder().address_lookup(), accepting both AddressLookup instances and AddressLookupBuilder implementations.
  • Multiple services coexist within AddressLookupServices, which merges resolve streams and ensures all services receive filtered publish data.
  • Built-in options include PkarrPublisher for pkarr relay integration, DnsAddressLookup for DNS resolution, and MemoryLookup for testing.
  • Address filtering via AddrFilter allows pruning of sensitive addresses before publication to any external service.

Frequently Asked Questions

What is the difference between AddressLookup and AddressLookupBuilder?

AddressLookup is the runtime trait used for publishing and resolving addresses, while AddressLookupBuilder defers construction until the endpoint is fully configured. Use AddressLookupBuilder when your service needs to inspect the finalized endpoint configuration—such as its relay URL or socket addresses—before initializing.

How does iroh merge results from multiple lookup services?

The AddressLookupServices registry creates a merged stream (AddressLookupStream) that yields items from all registered services as soon as they become available. According to the implementation in iroh/src/address_lookup.rs, the merge logic buffers errors and continues polling other services, ensuring that a fast-failing resolver does not hide later successes from slower services, as demonstrated in the test address_lookup_succeeds_after_other_resolver_errors.

Can I restrict which addresses are published to external services?

Yes. Set an AddrFilter on the endpoint builder or via address_lookup().set_addr_filter() after construction. This function intercepts the EndpointData before publication and can prune direct socket addresses, leaving only relay URLs, or reorder addresses based on your network policies.

How do I implement a custom address lookup service for a private discovery protocol?

Implement the AddressLookup trait for your custom type, defining the resolve method to return a stream of Result<Item, Error> and publish to handle your protocol's advertisement mechanism. Register the instance using Endpoint::builder().address_lookup() or address_lookup().add() if the endpoint is already bound.

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 →