# How iroh’s PkarrResolver Enables Public‑Key‑Only Connections

> Discover how irohs PkarrResolver connects devices securely using only public keys. Learn about verified network addresses and cryptographically signed packets.

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

---

**The PkarrResolver resolves an EndpointId (public key) into verified network addresses by fetching a cryptographically signed packet from a pkarr relay and verifying it against the known public key, enabling connections without prior address configuration.**

The PkarrResolver in the n0-computer/iroh repository provides a decentralized address lookup mechanism that allows peers to connect using only a public key. By querying a pkarr relay for signed endpoint information and cryptographically verifying the returned packet, this component eliminates the need for out-of-band address distribution, making public-key-only connectivity possible in the iroh networking stack.

## How PkarrResolver Works Under the Hood

The resolution process follows a strict three-phase pattern that bridges the gap between cryptographic identity and network reachability.

### Step 1: Building the Resolver with PkarrResolverBuilder

In [`iroh/src/address_lookup/pkarr.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup/pkarr.rs), the `PkarrResolverBuilder::new` function (line 442) constructs the resolver with the URL of a pkarr relay, such as the production relay at `https://dns.iroh.link/pkarr`. The builder accepts optional configurations including a custom DNS-over-HTTPS resolver, TLS settings, and an `AddrFilter` that restricts which addresses the resolver exposes to the application. Once configured, the builder produces a `PkarrResolver` instance ready to perform lookups.

### Step 2: Querying the Public Key via HTTP

When the application calls `PkarrResolver::resolve` (line 499 in [`pkarr.rs`](https://github.com/n0-computer/iroh/blob/main/pkarr.rs)), the resolver performs an HTTP **GET** request to the endpoint `{relay}/pkarr/{endpoint_id}`. The `endpoint_id` is the target peer’s public key. The relay returns a **SignedPacket** containing the public key, a TTL, and a list of `EndpointInfo` entries that hold the actual socket addresses (IP and port combinations) and optional QUIC or relay information.

### Step 3: Cryptographic Verification and Address Extraction

Before returning any addresses, the resolver must verify the packet’s authenticity. According to the implementation in [`iroh-dns/src/pkarr.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/pkarr.rs), the resolver calls `SignedPacket::verify` to validate the signature against the public key provided in the `EndpointId`. If verification succeeds, the payload is decoded into `EndpointInfo` structures. The resolver then applies any configured address filters and returns the verified list of reachable network addresses to the caller.

## Key Design Features of PkarrResolver

The PkarrResolver implements several architectural decisions that make it suitable for decentralized networking.

**Stateless HTTP Transport.** Each lookup is a single, stateless request to the relay, making the resolver NAT-friendly and easy to cache without maintaining persistent connections.

**TTL-based Caching.** The `SignedPacket` includes its own TTL; the resolver respects this expiration and can cache results until the packet becomes stale, reducing redundant network requests.

**Pluggable DNS Resolution.** The resolver can be configured with a custom DNS resolver, allowing it to function in environments with restrictive DNS policies or requiring DNS-over-HTTPS.

**Address Filtering.** The optional `AddrFilter` trait enables applications to hide private or undesired addresses before they are handed to the transport layer, providing security and routing control.

## Code Example: Connecting by Public Key Only

The following Rust example demonstrates how to instantiate a `PkarrResolver` and resolve a peer’s address using only their public key.

```rust
use iroh::{
    address_lookup::{pkarr::{PkarrResolver, PkarrResolverBuilder}, AddressLookup},
    endpoint::EndpointId,
};
use url::Url;

// 1. Build the resolver targeting the production pkarr relay
let resolver: PkarrResolver = PkarrResolverBuilder::new(
    Url::parse("https://dns.iroh.link/pkarr").unwrap(),
)
    // Optional: configure custom DNS-over-HTTPS resolver
    // .dns_resolver(my_dns_resolver)
    .build()
    .await
    .expect("failed to build PkarrResolver");

// 2. Resolve the remote endpoint using only its public key
let remote_pubkey: EndpointId = // obtain from your protocol
let endpoint_infos = resolver
    .resolve(remote_pubkey)
    .await
    .expect("pkarr lookup failed");

// 3. Use the verified addresses to establish a connection
if let Some(info) = endpoint_infos.first() {
    // EndpointInfo implements ToSocketAddrs for direct use
    println!("Connecting to: {:?}", info);
    // Proceed with transport.connect(info).await?;
}

```

For higher-level integration, supply the resolver to an `EndpointBuilder` via `EndpointBuilder::address_lookup(resolver)` to enable automatic address resolution for all outgoing connections.

## Summary

- **PkarrResolver** bridges public keys to network addresses via signed packets stored on pkarr relays.
- **Resolution workflow**: Build resolver → HTTP GET to relay → Verify `SignedPacket` → Return `EndpointInfo` addresses.
- **Security guarantee**: Cryptographic verification in [`iroh-dns/src/pkarr.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/pkarr.rs) ensures only the private key holder can publish valid addresses for a given public key.
- **Configuration options**: Custom relays, DNS resolvers, and address filters allow deployment in diverse network environments.
- **Entry points**: `PkarrResolverBuilder::new` (line 442) and `PkarrResolver::resolve` (line 499) in [`iroh/src/address_lookup/pkarr.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup/pkarr.rs).

## Frequently Asked Questions

### What is a pkarr relay and why is it needed?

A pkarr relay is a server that stores signed DNS records indexed by public key. It acts as a decentralized directory service, allowing peers to publish their network addresses under their cryptographic identity. When you only know a peer’s public key, the relay provides the signed packet containing their current addresses without requiring a centralized authority.

### How does PkarrResolver ensure the returned addresses are authentic?

The resolver verifies the signature inside the `SignedPacket` using the `SignedPacket::verify` method implemented in [`iroh-dns/src/pkarr.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/pkarr.rs). Because the packet is signed by the private key corresponding to the public key you queried, verified addresses are cryptographically guaranteed to belong to the key holder, preventing man-in-the-middle attacks during the lookup phase.

### Can I use a custom or private pkarr relay instead of the default?

Yes. The `PkarrResolverBuilder` accepts any valid URL when calling `PkarrResolverBuilder::new`. You can point the resolver to a private relay, a staging environment, or a self-hosted instance, making the resolution infrastructure configurable for private networks or testing scenarios.

### What happens if the pkarr relay is unavailable or the public key is not found?

If the relay is unreachable or returns a 404 for the given `EndpointId`, `PkarrResolver::resolve` returns an error indicating the lookup failure. The application must handle this case by retrying with exponential backoff, falling back to alternative address sources, or reporting the connectivity issue to the user.