Key Modules in the iroh Repository: A Complete Architectural Breakdown
The iroh repository is organized around the endpoint module for peer-to-peer connectivity, address_lookup for DNS and PKARR-based discovery, tls and protocol for QUIC encryption, with supporting infrastructure in iroh-relay, iroh-dns-server, and shared primitives in iroh-base.
The iroh networking stack provides a Rust-based framework for building peer-to-peer applications over QUIC. Understanding the key modules in the iroh repository is essential for developers integrating custom protocols, running infrastructure, or optimizing connection performance. This guide maps the crate structure to specific source files in the n0-computer/iroh codebase and demonstrates how the modules interact during a typical connection lifecycle.
Core Client-Side Modules
Endpoint (iroh/src/endpoint/mod.rs)
The endpoint module forms the primary public API. It exposes the Endpoint struct, which manages node identity, connection establishment, and stream multiplexing. In iroh/src/endpoint/mod.rs, the Endpoint::builder() method configures relay selection via RelayMode and initializes the QUIC stack with custom TLS handlers. The Connection type, returned by Endpoint::connect(), provides open_bi() and open_uni() methods for stream creation.
Address Resolution (iroh/src/address_lookup/)
Before connecting, an EndpointId must resolve to reachable addresses. The address_lookup directory contains multiple strategies:
DnsAddressLookup: Resolves endpoints via DNS TXT records (defined iniroh/src/address_lookup/dns.rs)PkarrAddressLookup: Uses the PKARR protocol for decentralized discovery (defined iniroh/src/address_lookup/pkarr.rs)
Both implement the AddressLookup trait, returning a relay URL and direct addresses.
TLS and Protocol Handlers
QUIC connections rely on the tls module (iroh/src/tls/mod.rs) for certificate verification, providing TlsConnector and TlsAcceptor wrappers. The protocol module (iroh/src/protocol/mod.rs) defines the custom iroh relaying protocol through the Protocol and Message types, handling frame encoding for relayed traffic.
Observability and Diagnostics
Metrics (iroh/src/metrics.rs)
Runtime observability is handled by the metrics module, exposing Prometheus-compatible counters through the Metrics and ConnectionMetrics structs. These track connection establishment latency, throughput, and relay utilization as implemented in iroh/src/metrics.rs.
Network Reporting (iroh/src/net_report/mod.rs)
The optional net_report feature provides path quality analysis. NetReportConfig configures probe behavior, while the Probe struct measures relay latency and NAT traversal success rates, enabling dynamic path selection. The implementation resides in iroh/src/net_report/mod.rs.
Infrastructure and Server Components
Relay Server (iroh-relay/)
The iroh-relay crate contains the server-side implementation for traffic forwarding. In iroh-relay/src/server/http_server.rs, the RelayServer type accepts TLS-protected QUIC sessions and routes encrypted payloads between peers. Client-side relay configuration uses RelayMap and RelayConfig from iroh/src/relay_map.rs.
DNS Services (iroh-dns-server/ and iroh-dns/)
Discovery infrastructure includes the iroh-dns crate, which provides DnsResolver utilities in iroh-dns/src/dns.rs for client-side queries. The iroh-dns-server crate implements the publishing side, with DnsServer and HttpApi defined in iroh-dns-server/src/server.rs, serving TXT records for endpoint discovery.
Shared Primitives and Testing
iroh-base (iroh-base/src/lib.rs)
Cryptographic primitives and identifiers live in iroh-base. This crate defines EndpointId, PublicKey, SecretKey, and RelayUrl types used across the entire ecosystem, ensuring type safety between crates without circular dependencies. The definitions are centralized in iroh-base/src/lib.rs.
Benchmarking (iroh/bench/src/lib.rs)
Performance validation occurs in iroh-bench, located at iroh/bench/src/lib.rs, which implements throughput and latency benchmarks for connection setup and data transfer.
How the Modules Interact During Connection
When Endpoint::connect() is invoked, the following sequence executes:
- Resolution: The endpoint queries its configured
AddressLookup(defaulting toDnsAddressLookup) to resolve the targetEndpointIdto aRelayUrland direct addresses. - Relay Negotiation: If direct connection fails, the endpoint establishes a QUIC connection to the relay using
TlsConnectorfrom thetlsmodule, negotiating the customProtocoldefined iniroh/src/protocol/mod.rs. - Hole Punching: Simultaneously, the endpoint attempts NAT traversal for direct peer-to-peer connectivity.
- Stream Establishment: Once connected, the
Connectiontype exposesopen_bi()andopen_uni()methods for application data. - Telemetry: Throughout the lifecycle,
Metricscounters update, and optionalNetReportprobes collect path quality data.
Practical Code Examples
Creating a Client Endpoint
#[cfg(with_crypto_provider)]
async fn simple_client() -> n0_error::Result<()> {
// Create an endpoint bound to the default "number 0" preset.
let ep = iroh::Endpoint::bind(iroh::endpoint::presets::N0).await?;
// Connect to a remote endpoint (replace with a real EndpointId).
let remote_id = "VQ6X...".parse::<iroh::EndpointId>()?;
let conn = ep.connect(remote_id, b"my-alpn").await?;
// Open a bi-directional stream and exchange a hello message.
let (mut send, mut recv) = conn.open_bi().await?;
send.write_all(b"hello").await?;
send.finish().await?;
let reply = recv.read_to_end(usize::MAX).await?;
println!("remote said: {}", String::from_utf8_lossy(&reply));
Ok(())
}
This example uses the endpoint, address_lookup (via defaults), tls, and protocol modules as defined in iroh/src/lib.rs.
Configuring Custom DNS Lookup
use iroh::address_lookup::DnsAddressLookup;
use iroh::endpoint::Builder;
#[cfg(with_crypto_provider)]
async fn custom_dns_lookup() -> n0_error::Result<()> {
// Build a DNS lookup that uses the staging domain.
let dns_lookup = DnsAddressLookup::builder("iroh-staging.example".into()).build();
// Attach the lookup to the endpoint builder.
let ep = Builder::new()
.address_lookup(dns_lookup)
.bind()
.await?;
Ok(())
}
The lookup implementation lives in iroh/src/address_lookup/dns.rs.
Running a Relay Server
use iroh_relay::RelayServer;
use std::net::SocketAddr;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
// Listen on a UDP port for QUIC connections.
let addr: SocketAddr = "[::]:443".parse()?;
let server = RelayServer::bind(addr).await?;
println!("Relay listening on {}", addr);
server.serve().await?;
Ok(())
}
Core server logic is located in iroh-relay/src/server/http_server.rs.
Summary
endpoint(iroh/src/endpoint/mod.rs): Core public API managing QUIC connections and stream multiplexing.address_lookup(iroh/src/address_lookup/): Pluggable discovery via DNS or PKARR, resolvingEndpointIdto network addresses.tls(iroh/src/tls/mod.rs) andprotocol(iroh/src/protocol/mod.rs): Handle encrypted QUIC communication and custom relay framing.metrics(iroh/src/metrics.rs) andnet_report(iroh/src/net_report/mod.rs): Provide runtime observability and network quality diagnostics.iroh-relay(iroh-relay/src/server/http_server.rs): Server-side traffic forwarding and relay infrastructure.iroh-dns-server(iroh-dns-server/src/server.rs) andiroh-dns: DNS publishing and resolution services for endpoint discovery.iroh-base(iroh-base/src/lib.rs): Shared cryptographic primitives includingEndpointId,PublicKey, andSecretKey.
Frequently Asked Questions
What is the entry point for creating connections in iroh?
The Endpoint struct in iroh/src/endpoint/mod.rs serves as the primary entry point. Use Endpoint::bind() or Endpoint::builder() to configure a node, then call Endpoint::connect() with a target EndpointId and ALPN protocol identifier to establish peer-to-peer sessions.
How does iroh resolve peer addresses without a central coordinator?
The address_lookup module supports decentralized discovery. By default, it uses DnsAddressLookup to query DNS TXT records, but can be configured to use PkarrAddressLookup for PKARR-based resolution. Both strategies are implemented in iroh/src/address_lookup/dns.rs and iroh/src/address_lookup/pkarr.rs respectively.
Can I run my own relay server instead of using the default infrastructure?
Yes. The iroh-relay crate provides the RelayServer type, which you can bind to a UDP socket using RelayServer::bind() as shown in iroh-relay/src/server/http_server.rs. This allows complete control over traffic forwarding while maintaining compatibility with iroh clients.
Where are the cryptographic types like EndpointId and PublicKey defined?
These primitives reside in the iroh-base crate, specifically in iroh-base/src/lib.rs. This separation prevents circular dependencies between the client, relay, and DNS components while ensuring type consistency across the networking stack.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →