# How Iroh Endpoint Discovery Works Without a Relay Server

> Discover how Iroh's endpoint discovery connects peers directly using public naming services like DNS and PKARR, bypassing the need for a relay server. Learn more about its architecture.

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

---

**Iroh discovers peers directly by publishing socket addresses to public naming services like DNS or PKARR, allowing nodes to connect without relying on a dedicated relay server.**

Iroh is a peer-to-peer networking library that enables direct connections between nodes even without centralized infrastructure. The library achieves this through a modular address-lookup system that publishes and resolves node addresses via globally reachable naming services rather than requiring dedicated relay infrastructure.

## Configuring Address Lookup Services

When building an `Endpoint` in [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs), the library exposes a configurable address-lookup mechanism through the builder API. The `Builder::address_lookup` method (lines 590-608) accepts services that implement the `AddressLookup` trait, allowing the endpoint to publish and resolve addressing information through multiple channels.

### Default DNS Configuration

By default, iroh uses the `N0` preset defined in [`iroh/src/endpoint/presets.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint/presets.rs) (lines 99-106). This preset automatically injects a `DnsAddressLookup` service that queries DNS records for node addresses. Users can override this behavior to use PKARR resolution or in-memory services for testing environments.

```rust
use iroh::{Endpoint, endpoint::presets};

// Configure endpoint with DNS lookup but no relay
let ep = Endpoint::builder(presets::N0)
    .clear_relay_transports()
    .bind()
    .await?;

```

## Publishing Endpoint Information

Each address-lookup service implements the `AddressLookup` trait. When an endpoint goes online, it automatically calls `publish` on every configured service, transmitting an `EndpointInfo` structure defined in [`iroh-dns/src/endpoint_info.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-dns/src/endpoint_info.rs) (lines 7-14).

This structure contains:

- The node's **EndpointId**
- **Direct socket addresses** bound by the node
- Optional **user-defined metadata**
- The **relay URL** (if configured)

The `publish` method pushes this information to the respective naming service, making the node's public addresses discoverable by peers.

## Resolving Remote Endpoints

When initiating a connection via `Endpoint::connect` in [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs) (lines 274-279), the library follows a fallback sequence. First, it attempts any direct addresses supplied in the `EndpointAddr`. If those fail or are absent, the endpoint invokes `self.inner.resolve_remote` to query the configured address-lookup services.

The lookup services return streams of `AddressLookupItem` instances. The remote-state actor aggregates these results, and upon finding at least one reachable address, creates a `MappedAddr` that the underlying QUIC connection can use to establish the direct path.

## Optional QUIC Address Discovery

While not required for relay-free operation, iroh includes an optional **QUIC Address Discovery (QAD)** mechanism. When a relay is configured as a "home relay," the endpoint sends discovery probes carrying the node's public key. The relay responds with the public source address observed from the probe, helping the node learn its own public IP.

This mechanism, configured via `QuicTransportConfig`, only activates when a relay is present. Without a relay, the endpoint skips this step and relies purely on the DNS or PKARR lookup results.

## Constructing the EndpointAddr

After successful resolution, the endpoint's `Watcher` updates the local `EndpointAddr` (accessible via `endpoint.addr()` or `endpoint.watch_addr()`). This address contains the set of direct socket addresses that peers can dial, along with any fallback relay URLs. Because the information originates from globally reachable DNS or PKARR records, peers connect directly without requiring a relay intermediary.

## Practical Implementation

The following example demonstrates building a relay-free endpoint that publishes to and resolves from DNS:

```rust
use iroh::{Endpoint, endpoint::presets};
use iroh::address_lookup::DnsAddressLookup;

// Build endpoint without relays
let ep = Endpoint::builder(presets::N0)
    .clear_relay_transports()
    .bind()
    .await?;

// Publish addresses to DNS
ep.online().await?;

// Connect to remote using only DNS lookup
let remote_id = "0x1234abcd...".parse()?;
let remote_addr = Endpoint::builder(presets::N0)
    .address_lookup(DnsAddressLookup::n0_dns())
    .bind()
    .await?
    .connect(remote_id, b"my-alpn")
    .await?;

```

To use PKARR instead of DNS, substitute `DnsAddressLookup` with `PkarrResolverBuilder` from [`iroh/src/address_lookup/pkarr.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup/pkarr.rs).

## Summary

- **Address lookup services** replace relay servers by publishing node addresses to DNS or PKARR systems
- The `AddressLookup` trait in [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs) enables pluggable discovery mechanisms
- `EndpointInfo` structures contain direct socket addresses and relay URLs for publication
- Resolution occurs via `resolve_remote` in the connection path, falling back from direct addresses to lookup services
- QUIC Address Discovery is optional and only active when relays are configured

## Frequently Asked Questions

### Can iroh connect to peers without any centralized server at all?

Yes. By configuring `DnsAddressLookup` or `PkarrResolver` services and clearing relay transports, iroh nodes publish addresses to decentralized naming systems. The DNS or PKARR infrastructure serves as the discovery mechanism, while the actual connection occurs directly between peers via QUIC.

### What is the difference between DNS and PKARR address lookup in iroh?

DNS lookup (`DnsAddressLookup` in [`iroh/src/address_lookup/dns.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup/dns.rs)) queries traditional DNS records for node addresses, while PKARR lookup (`PkarrResolver` in [`iroh/src/address_lookup/pkarr.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/address_lookup/pkarr.rs)) uses the peer-to-peer PKARR protocol for decentralized name resolution. DNS requires existing DNS infrastructure, whereas PKARR operates entirely peer-to-peer without centralized authorities.

### Does iroh endpoint discovery reveal my IP address publicly?

Yes. When using address lookup services, the `EndpointInfo` structure published to DNS or PKARR includes your node's direct socket addresses. This visible information enables other peers to connect directly to your node, which is necessary for relay-free operation but does expose your public IP address to the lookup service and querying peers.

### What happens if the address lookup service fails?

If DNS or PKARR resolution fails and no direct addresses are provided in the `EndpointAddr`, the `Endpoint::connect` call will timeout. The connection logic in [`iroh/src/endpoint.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/endpoint.rs) attempts direct addresses first, then queries lookup services; if neither source yields reachable addresses, the connection attempt fails with a resolution error.