How to Configure iroh Endpoint to Listen on Multiple Addresses
To configure an iroh Endpoint to listen on multiple addresses, use the Builder::bind_addr() or Builder::bind_addr_with_opts() methods repeatedly before calling bind(), and call clear_ip_transports() first to remove default unspecified sockets.
The iroh networking library provides a flexible Endpoint builder pattern that allows precise control over socket binding. When you need to configure an iroh Endpoint to listen on multiple addresses, you modify the transport configuration before the endpoint initializes. This guide covers the specific builder methods and options available in the n0-computer/iroh repository.
Understanding the Default Listening Behavior
By default, the iroh Endpoint builder creates sockets bound to unspecified addresses: IPv4 on 0.0.0.0 and IPv6 on [::]. This automatic configuration occurs in iroh/src/endpoint.rs (lines 318-333) unless you explicitly override it with custom transport settings. The builder stores these configurations as TransportConfig::Ip entries that determine which sockets the endpoint will open during the bind() call.
Configuring Multiple Bind Addresses
To listen on specific interfaces rather than all available network interfaces, you must clear the defaults and add explicit bind addresses using the builder API.
Clearing Default Transports
Call Builder::clear_ip_transports() to remove the default "listen-on-all-interfaces" behavior. This method ensures the endpoint only listens on the specific addresses you define, preventing unintended exposure on all network interfaces.
Simple Address Binding
Use Builder::bind_addr() as a convenience wrapper that applies default BindOpts. This method accepts a socket address string and returns the builder for method chaining, making it ideal for straightforward multi-address configurations.
Advanced Binding with Options
For fine-grained control over routing and network topology, use Builder::bind_addr_with_opts(). This method accepts a BindOpts struct (defined in iroh/src/bind.rs) that allows you to:
- Set subnet prefix lengths for address validation
- Mark addresses as required or optional for endpoint operation
- Designate specific addresses as default routes
Each call to these methods inserts a new TransportConfig::Ip entry into the builder's internal configuration, as implemented in iroh/src/endpoint.rs (lines 313-368).
Adding External Addresses After Binding
Once the endpoint is active, you can advertise additional reachable addresses using Endpoint::add_external_addr(). This method affects the advertised EndpointAddr without creating new listening sockets, allowing you to inform peers of NAT-mapped or relay addresses that differ from your local bind addresses.
Implementation Examples
The following example demonstrates binding to specific IPv4 and IPv6 addresses with custom subnet prefixes, clearing the default transports first:
use iroh::{Endpoint, endpoint::{BindOpts, presets}};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 1️⃣ Start from a preset (e.g. the “N0” preset).
let builder = Endpoint::builder(presets::N0)
// 2️⃣ Remove the default unspecified IPv4/IPv6 sockets.
.clear_ip_transports()
// 3️⃣ Bind to an IPv4 address on a random port, with a /24 subnet prefix.
.bind_addr_with_opts(
"192.168.1.10:0",
BindOpts::default().set_prefix_len(24),
)?
// 4️⃣ Bind to an IPv6 address on a random port, with a /48 subnet prefix.
.bind_addr_with_opts(
"[fd00::1]:0",
BindOpts::default().set_prefix_len(48),
)?;
// 5️⃣ Finish the construction – this creates the listening sockets.
let endpoint = builder.bind().await?;
// 6️⃣ (Optional) Advertise an additional external address after the endpoint is alive.
endpoint.add_external_addr("203.0.113.5:0".parse()?).await;
println!("Endpoint ready – listening on {:?}", endpoint.addr());
Ok(())
}
The two bind_addr_with_opts calls add distinct transport entries; the builder now listens on both the IPv4 and IPv6 addresses, as stored in the ip_bind_addrs collection in iroh/src/socket.rs (lines 364-422).
For simpler use cases using default options:
let endpoint = Endpoint::builder(presets::N0)
.clear_ip_transports()
.bind_addr("0.0.0.0:0")? // IPv4
.bind_addr("[::1]:0")? // IPv6
.bind()
.await?;
The iroh/examples/transfer.rs file (lines 540-560) provides a real-world example showing how a CLI parses multiple IPv4/IPv6 bind arguments and calls the builder repeatedly.
Summary
- Default behavior: The
Endpointbuilder automatically binds to0.0.0.0and[::]on all interfaces unless modified. - Clear defaults: Use
clear_ip_transports()to remove unspecified address bindings before adding custom ones. - Add addresses: Call
bind_addr()for simple binding orbind_addr_with_opts()for advanced control over subnet prefixes and routing. - External addresses: Use
add_external_addr()post-binding to advertise additional reachable addresses without creating new sockets. - Source locations: Implementation details reside in
iroh/src/endpoint.rs,iroh/src/socket/transports/ip.rs, andiroh/src/bind.rs.
Frequently Asked Questions
What is the default binding behavior of iroh Endpoint?
By default, the Endpoint builder in iroh/src/endpoint.rs creates an IPv4 socket bound to 0.0.0.0 and an IPv6 socket bound to [::] (the unspecified addresses). This allows the endpoint to accept connections on any available network interface unless you explicitly configure specific bind addresses.
How do I remove default unspecified address bindings?
Call Builder::clear_ip_transports() before adding your custom addresses. This method removes the pre-configured IPv4 and IPv6 unspecified entries, ensuring the endpoint only listens on the specific interfaces you define with subsequent bind_addr() or bind_addr_with_opts() calls.
What is the difference between bind_addr and bind_addr_with_opts?
bind_addr() is a convenience wrapper that accepts a socket address and uses default BindOpts for simple configuration. bind_addr_with_opts() accepts both a socket address and a BindOpts struct, allowing you to specify subnet prefix lengths, mark addresses as required or optional, and set default route flags for advanced network topology control.
Can I add listening addresses after the endpoint is bound?
No, you cannot add new listening sockets after calling bind(). However, you can use Endpoint::add_external_addr() to advertise additional reachable addresses to peers. This updates the EndpointAddr metadata without creating new listening sockets, useful for informing peers of NAT-mapped or relay addresses.
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 →