Understanding the iroh Node Data Model: PKARR Zones and DNS Authority

The iroh node data model centers on NodeZoneHandler, a struct that combines static DNS records with mutable PKARR zones to serve as a DNS authority for public-key-based naming.

In the n0-computer/iroh repository, the node's data model defines how the system stores, retrieves, and serves DNS records. Rather than a traditional file-based zone configuration, the iroh node implements a hybrid approach that merges immutable static records with dynamic public-key addressable records stored in a ZoneStore.

Core Components of the iroh Node Data Model

The data model is implemented primarily in the iroh-dns-server crate, where the NodeZoneHandler struct acts as the single source of truth for DNS resolution.

NodeZoneHandler as the Central Authority

The NodeZoneHandler struct in iroh-dns-server/src/dns/node_zone_handler.rs defines the complete state of an iroh node. It implements the hickory_server::zone_handler::ZoneHandler trait, allowing it to plug directly into a DNS server.

The struct contains five critical fields:

  • serial: u32 — The DNS serial number incremented on every change to signal resolvers that zone data has updated.
  • origins: Vec<Name> — The list of DNS zones (origins) the node is authoritative for. At least one origin must be supplied during instantiation.
  • static_zone_handler: InMemoryZoneHandler — A read-only handler providing the static portion of the zone, including SOA and NS records.
  • zones: ZoneStore — The mutable storage for PKARR records, mapping public keys to their associated record sets.
  • first_origin: LowerName — A cached lower-cased version of the first origin, used for the ZoneHandler::origin implementation.

The ZoneStore for PKARR Records

The ZoneStore (defined in iroh-dns-server/src/store.rs) persists the dynamic portion of the iroh node data model. Unlike traditional DNS zones that require manual editing, PKARR zones are generated dynamically from public keys. The store resolves names formatted as <pubkey>.<origin> to their corresponding record sets, enabling cryptographic addressability without centralized registration.

Static Zone Handling

The static zone provides the foundational DNS infrastructure that rarely changes. This includes the Start of Authority (SOA) record and Name Server (NS) records. The InMemoryZoneHandler manages these entries separately from the mutable PKARR data, ensuring that core DNS metadata remains stable while user records update.

How NodeZoneHandler Manages DNS Lookups

The lookup method in iroh-dns-server/src/dns/node_zone_handler.rs (lines 94-138) implements the resolution logic that distinguishes between static and dynamic records:

  1. SOA and NS queries — Delegated immediately to the static_zone_handler.
  2. PKARR resolution — For other record types, the method attempts to parse the queried name as a PKARR identifier using parse_name_as_pkarr_with_origin (from iroh-dns-server/src/util.rs).
  3. Record construction — If successful, resolve_pkarr builds a DNS record set that includes the node's current serial, ensuring cache consistency across distributed resolvers.
  4. Fallback — Names that cannot be parsed as PKARR identifiers fall back to the static zone handler.

This architecture allows the iroh node to serve as a standards-compliant DNS server while supporting the flexible, key-based addressing scheme that defines the iroh network.

Creating and Configuring a Node

To instantiate a node with the iroh node data model, you combine a ZoneStore with static records and origin definitions:

use hickory_server::authority::ZoneHandler;
use iroh_dns_server::dns::NodeZoneHandler;
use iroh_dns_server::store::ZoneStore;
use hickory_server::store::in_memory::InMemoryZoneHandler;
use hickory_proto::rr::Name;

// Define the DNS origins this node will serve
let origins = vec![
    Name::from_ascii("example.com.")?,
    Name::from_ascii("iroh.example.")?,
];

// Create the static zone with SOA/NS records
let static_zone = InMemoryZoneHandler::new(/* pre-populated static records */)?;

// Initialize the mutable PKARR storage
let zone_store = ZoneStore::new();

// Construct the node with serial starting at 1
let node = NodeZoneHandler::new(zone_store, static_zone, origins, 1)?;

Performing a DNS lookup against the node:

use hickory_proto::rr::{LowerName, RecordType};
use hickory_server::authority::LookupOptions;

let request_name = LowerName::from_ascii("mykey.example.com.")?;
let result = node
    .lookup(&request_name, RecordType::A, None, LookupOptions::default())
    .await;

Inserting PKARR records into the dynamic store:

use iroh_dns_server::util::PublicKeyBytes;

let pubkey = PublicKeyBytes::from_z32("mypublickeyz32")?;
let pkarr_set = /* build a RecordSet for the pubkey */;
node.zones.insert(pubkey, pkarr_set).await?;

Key Source Files and Implementation Details

File Path Purpose
iroh-dns-server/src/dns/node_zone_handler.rs Contains the NodeZoneHandler struct definition and its ZoneHandler trait implementation.
iroh-dns-server/src/store.rs Defines the ZoneStore for persisting mutable PKARR zones.
iroh-dns-server/src/util.rs Provides helper functions including PublicKeyBytes and record_set_append_origin for PKARR name parsing.

Summary

  • The iroh node data model is implemented by the NodeZoneHandler struct, which implements the DNS ZoneHandler trait.
  • It combines static zones (SOA/NS records via InMemoryZoneHandler) with dynamic PKARR zones (stored in ZoneStore).
  • The serial field ensures DNS cache consistency across the distributed network.
  • Origins define the DNS domains the node controls, with at least one required for operation.
  • Resolution logic prioritizes static records for infrastructure queries while dynamically generating PKARR responses for public-key-based lookups.

Frequently Asked Questions

What is the difference between static zones and PKARR zones in iroh?

Static zones contain traditional DNS records like SOA and NS that define the node's authority and are immutable during runtime. PKARR zones are dynamic mappings between public keys and DNS record sets, stored in the ZoneStore, that enable cryptographic addressability without requiring changes to the static zone configuration.

How does the iroh node handle DNS serial numbers?

The NodeZoneHandler maintains a u32 serial field that increments whenever the zone data changes. This value is included in PKARR record responses and SOA records, allowing DNS resolvers to detect when cached data has become stale and needs refreshing from the authoritative iroh node.

Where is PKARR data stored in the iroh node?

PKARR data resides in the ZoneStore instance, defined in iroh-dns-server/src/store.rs. This store is held as the zones field within NodeZoneHandler and provides the mutable backing for public-key-to-record mappings that power the iroh naming system.

Can an iroh node serve multiple DNS origins?

Yes. The NodeZoneHandler accepts a Vec<Name> of origins during construction, allowing a single node to be authoritative for multiple DNS domains simultaneously. The first origin in the vector is cached as first_origin and used as the default origin in the ZoneHandler implementation.

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 →