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

> Learn to publish and resolve addresses with iroh's PkarrPublisher and DnsAddressLookup. Sign, PUT data to a relay, and query DNS TXT records for secure endpoint information.

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

---

**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`](https://github.com/n0-computer/iroh/blob/main/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`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup/pkarr.rs), these construct and execute the publishing workflow.
- **`PkarrResolverBuilder`** and **`PkarrResolver`** – Also in [`iroh/src/address_lookup/pkarr.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup/pkarr.rs), these handle DNS-based resolution and signature verification.
- **`EndpointInfo`** – Defined in [`iroh-dns/src/pkarr.rs`](https://github.com/n0-computer/iroh/blob/main/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.

```rust
// 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.

```rust
// 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.

```rust
// 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.

```rust
// 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`](https://github.com/n0-computer/iroh/blob/main/publish.rs) example in [`iroh-dns-server/examples/publish.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns-server/examples/publish.rs) demonstrates the complete publishing flow:

```bash

# 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:

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

```

### Resolving a Record (CLI)

The [`resolve.rs`](https://github.com/n0-computer/iroh/blob/main/resolve.rs) example in [`iroh-dns-server/examples/resolve.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns-server/examples/resolve.rs) demonstrates resolution:

```bash
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`](https://github.com/n0-computer/iroh/blob/main/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.

### Can I use my own DNS server instead of the iroh.link relay?

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`](https://github.com/n0-computer/iroh/blob/main/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`](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/pkarr.rs).