How to Publish and Resolve Addresses Using PkarrPublisher and DnsAddressLookup in iroh

Use PkarrPublisher to sign and HTTP PUT endpoint data to a Pkarr relay, then use DnsAddressLookup (via PkarrResolver) to query DNS TXT records and verify the signed payload into an EndpointInfo struct.

The iroh crate provides a decentralized address discovery mechanism using Pkarr (Public-Key Addressable Resource Records) to publish endpoint information and DNS-based lookups to resolve peer addresses. By combining PkarrPublisher for publishing signed packets and DnsAddressLookup (implemented via PkarrResolver) for resolution, you can achieve stateless, cryptographically secure peer discovery without central registries. This article explores the implementation details found in iroh/src/address_lookup/pkarr.rs and demonstrates how to use these components with practical examples from the iroh-dns-server examples.

Architecture of Pkarr Publishing and Resolution

The system separates concerns into two distinct operations: publishing endpoint data via HTTP and resolving it via DNS TXT queries.

Core Components

The implementation relies on several key types across the iroh and iroh-dns crates:

  • PkarrPublisherBuilder and PkarrPublisher – Found in iroh/src/address_lookup/pkarr.rs, these construct and execute the publishing workflow.
  • PkarrResolverBuilder and PkarrResolver – Also in iroh/src/address_lookup/pkarr.rs, these handle DNS-based resolution and signature verification.
  • EndpointInfo – Defined in iroh-dns/src/pkarr.rs, this struct encapsulates endpoint IDs, relay URLs, IP addresses, and user data.
  • SignedPacket – A cryptographically signed Pkarr packet that can be validated without trusting the relay.

Data Flow

  1. Publishing: The publisher constructs an EndpointInfo, converts it to a SignedPacket, and sends it via HTTP PUT to a Pkarr relay (e.g., https://dns.iroh.link/pkarr).
  2. Resolution: The resolver queries DNS TXT records at iroh.<z-base-32-id>.<origin> and validates the returned SignedPacket against the endpoint's public key.

Publishing Endpoint Information with PkarrPublisher

Publishing requires creating a cryptographically signed packet that contains your endpoint's addressing information and transmitting it to a Pkarr relay.

Building the Publisher

First, instantiate a PkarrRelayClient that knows the relay URL and optional TLS configuration. This client handles the HTTP transport to the relay.

// From iroh-dns-server/examples/publish.rs
let pkarr = PkarrRelayClient::new(pkarr_relay_url, tls_config, DnsResolver::default());

Creating and Publishing Signed Packets

Construct an EndpointInfo with your endpoint ID, relay URL, IP addresses, and optional user data. Then convert this to a signed Pkarr packet using EndpointInfo::to_pkarr_signed_packet, which cryptographically signs the payload with your secret key.

// From iroh-dns-server/examples/publish.rs
let mut endpoint_info = EndpointInfo::new(endpoint_id);
if let Some(relay_url) = relay_url {
    endpoint_info = endpoint_info.with_relay_url(relay_url.into());
}
endpoint_info = endpoint_info
    .with_ip_addrs(args.addr.into_iter().collect())
    .with_user_data(args.user_data);

let signed_packet = endpoint_info.to_pkarr_signed_packet(&secret_key, 30)?;
pkarr.publish(&signed_packet).await?;

The 30 parameter specifies the TTL (time-to-live) in seconds. The relay automatically expires stale records based on this value.

Resolving Addresses with DnsAddressLookup

Resolution uses standard DNS infrastructure to retrieve the signed packet, allowing compatibility with existing DNS tools while maintaining end-to-end cryptographic verification.

DNS Query Construction

The resolver constructs a TXT query for the domain iroh.<z32-id>.<origin>, where <z32-id> is the Z-base-32 encoded public key of the endpoint. The DnsResolver (or PkarrResolver wrapper) issues this query to the configured DNS server.

// From iroh-dns-server/examples/resolve.rs
let resolver = DnsResolver::new(dns_server_url)?;
let lookup = resolver.lookup_endpoint(&endpoint_id).await?;

Signature Verification

Upon receiving the TXT record, the resolver parses the payload into a SignedPacket and validates the signature using the endpoint's public key. This verification happens in the verify method, ensuring the data hasn't been tampered with by the relay or network intermediaries.

// From iroh-dns-server/examples/resolve.rs
let endpoint_info = lookup
    .verify(&endpoint_id.public_key())?;   // validates the signature
println!("Endpoint info: {endpoint_info:#?}");

The verification succeeds only if the signature matches the public key embedded in the DNS name, providing end-to-end authenticity.

Practical Implementation Examples

The iroh-dns-server crate provides complete CLI examples demonstrating both sides of the workflow.

Publishing a Record (CLI)

The publish.rs example in iroh-dns-server/examples/publish.rs demonstrates the complete publishing flow:


# Set the secret for the endpoint (once)

export IROH_SECRET=$(openssl rand -hex 32)

# Publish to the staging relay

cargo run --example publish -- --env staging \
    --addr 192.0.2.10:4000 --user-data "my-service"

This command prints the DNS name you can query:

dig iroh.<z32-id>.irohdns.staging TXT

Resolving a Record (CLI)

The resolve.rs example in iroh-dns-server/examples/resolve.rs demonstrates resolution:

cargo run --example resolve -- --env staging endpoint \
    <z32-id>

The resolver contacts the same relay (or any DoH server configured in the example) and prints the recovered EndpointInfo.

Summary

  • Stateless publishing – The Pkarr relay stores only signed packets without maintaining private state, making the system resilient and easy to replicate.
  • End-to-end security – All endpoint data is signed with the secret key and verified using the public key, preventing tampering even if the relay is compromised.
  • DNS compatibility – The same SignedPacket can be served via standard DNS TXT records or the dedicated Pkarr HTTP endpoint, allowing flexible deployment strategies.
  • Automatic expiration – Packets include a TTL (default 30 seconds in the examples), ensuring stale endpoint information is automatically purged from the relay.

Frequently Asked Questions

What is the relationship between PkarrPublisher and DnsAddressLookup?

PkarrPublisher handles the publishing side by creating signed packets and sending them via HTTP PUT to a Pkarr relay. DnsAddressLookup refers to the resolution side, which is implemented by PkarrResolver (and DnsResolver) to query DNS TXT records and verify the returned signatures. Together, they form a complete publish-subscribe address discovery system.

How does the TTL parameter affect published records?

The TTL (time-to-live) parameter in to_pkarr_signed_packet specifies how long the relay should store the packet before expiration. According to the implementation in iroh-dns-server/src/http/pkarr.rs, the relay automatically removes expired records, and DNS resolvers can use this value for caching. A TTL of 30 seconds provides a balance between freshness and query efficiency.

Yes. The PkarrResolver accepts any DNS server URL that can resolve the TXT records. The DNS server must either be a Pkarr relay itself (like https://dns.iroh.link) or a standard DNS server that forwards queries to the Pkarr relay. The resolution code in iroh/src/address_lookup/pkarr.rs is agnostic to the specific DNS backend as long as it returns the correctly formatted TXT records.

How is the endpoint ID encoded in the DNS query?

The endpoint ID (a public key) is encoded using Z-base-32 encoding and prepended with iroh. to form the subdomain. For example, an endpoint with public key <key> becomes iroh.<z32-encoded-key>.<origin>. This encoding is handled automatically by the EndpointInfo and PkarrResolver types in iroh-dns/src/pkarr.rs.

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 →