iroh_net/lib.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
//! Peer-to-peer QUIC connections.
//!
//! iroh-net is a library to establish direct connectivity between peers. It exposes an
//! interface to [QUIC] connections and streams to the user, while implementing direct
//! connectivity using [hole punching] complemented by relay servers under the hood.
//!
//! An iroh-net node is created and controlled by the [`Endpoint`], e.g. connecting to
//! another node:
//!
//! ```no_run
//! # use iroh_net::{Endpoint, NodeAddr};
//! # async fn wrapper() -> testresult::TestResult {
//! let addr: NodeAddr = todo!();
//! let ep = Endpoint::builder().bind().await?;
//! let conn = ep.connect(addr, b"my-alpn").await?;
//! let mut send_stream = conn.open_uni().await?;
//! send_stream.write_all(b"msg").await?;
//! # Ok(())
//! # }
//! ```
//!
//! The other node can accept incoming connections using the [`Endpoint`] as well:
//!
//! ```no_run
//! # use iroh_net::{Endpoint, NodeAddr};
//! # async fn wrapper() -> testresult::TestResult {
//! let ep = Endpoint::builder()
//! .alpns(vec![b"my-alpn".to_vec()])
//! .bind()
//! .await?;
//! let conn = ep.accept().await.ok_or("err")?.await?;
//! let mut recv_stream = conn.accept_uni().await?;
//! let mut buf = [0u8; 3];
//! recv_stream.read_exact(&mut buf).await?;
//! # Ok(())
//! # }
//! ```
//!
//! Of course you can also use [bi-directional streams] or any other features from QUIC.
//!
//! For more elaborate examples, see [below](#examples) or the examples directory in
//! the source repository.
//!
//!
//! # Connection Establishment
//!
//! An iroh-net connection between two iroh-net nodes is usually established with the help
//! of a Relay server. When creating the [`Endpoint`] it connects to the closest Relay
//! server and designates this as the *home relay*. When other nodes want to connect they
//! first establish connection via this home relay. As soon as connection between the two
//! nodes is established they will attempt to create a direct connection, using [hole
//! punching] if needed. Once the direct connection is established the relay server is no
//! longer involved in the connection.
//!
//! If one of the iroh-net nodes can be reached directly, connectivity can also be
//! established without involving a Relay server. This is done by using the node's
//! listening addresses in the connection establishement instead of the [`RelayUrl`] which
//! is used to identify a Relay server. Of course it is also possible to use both a
//! [`RelayUrl`] and direct addresses at the same time to connect.
//!
//!
//! # Encryption
//!
//! The connection is encrypted using TLS, like standard QUIC connections. Unlike standard
//! QUIC there is no client, server or server TLS key and certificate chain. Instead each iroh-net node has a
//! unique [`SecretKey`] used to authenticate and encrypt the connection. When an iroh-net
//! node connects, it uses the corresponding [`PublicKey`] to ensure the connection is only
//! established with the intended peer.
//!
//! Since the [`PublicKey`] is also used to identify the iroh-net node it is also known as
//! the [`NodeId`]. As encryption is an integral part of TLS as used in QUIC this
//! [`NodeId`] is always a required parameter to establish a connection.
//!
//! When accepting connections the peer's [`NodeId`] is authenticated. However it is up to
//! the application to decide if a particular peer is allowed to connect or not.
//!
//!
//! # Relay Servers
//!
//! Relay servers exist to ensure all iroh-net nodes are always reachable. They accept
//! **encrypted** traffic for iroh-net nodes which are connected to them, forwarding it to
//! the correct destination based on the [`NodeId`] only. Since nodes only send encrypted
//! traffic, the Relay servers can not decode any traffic for other iroh-net nodes and only
//! forward it.
//!
//! The connections to the Relay server are initiated as normal HTTP 1.1 connections using
//! TLS. Once connected the transport is upgraded to a plain TCP connection using a custom
//! protocol. All further data is then sent using this custom relaying protocol. Usually
//! soon after the connection is established via the Relay it will migrate to a direct
//! connection. However if this is not possible the connection will keep flowing over the
//! relay server as a fallback.
//!
//! Additionally to providing reliable connectivity between iroh-net nodes, Relay servers
//! provide some functions to assist in [hole punching]. They have various services to help
//! nodes understand their own network situation. This includes offering a [STUN] server,
//! but also a few HTTP extra endpoints as well as responding to ICMP echo requests.
//!
//! By default the [number 0] relay servers are used, see [`RelayMode::Default`].
//!
//!
//! # Connections and Streams
//!
//! An iroh-net node is managed using the [`Endpoint`] and this is used to create or accept
//! connections to other nodes. To establish a connection to an iroh-net node you need to
//! know three pieces of information:
//!
//! - The [`NodeId`] of the peer to connect to.
//! - Some addressing information:
//! - Usually the [`RelayUrl`] identifying the Relay server.
//! - Sometimes, or usually additionally, any direct addresses which might be known.
//! - The QUIC/TLS Application-Layer Protocol Negotiation, or [ALPN], name to use.
//!
//! The ALPN is used by both sides to agree on which application-specific protocol will be
//! used over the resulting QUIC connection. These can be protocols like `h3` used for
//! [HTTP/3][HTTP3], but more commonly will be a custom identifier for the application.
//!
//! Once connected the API exposes QUIC streams. These are very cheap to create so can be
//! created at any time and can be used to create very many short-lived stream as well as
//! long-lived streams. There are two stream types to choose from:
//!
//! - **Uni-directional** which only allows the peer which initiated the stream to send
//! data.
//!
//! - **Bi-directional** which allows both peers to send and receive data. However, the
//! initiator of this stream has to send data before the peer will be aware of this
//! stream.
//!
//! Additionally to being extremely light-weight, streams can be interleaved and will not
//! block each other. Allowing many streams to co-exist, regardless of how long they last.
//!
//! <div class="warning">
//!
//! To keep streams cheap, they are lazily created on the network: only once a sender starts
//! sending data on the stream will the receiver become aware of a stream. This means only
//! calling [`Connection::open_bi`] is not sufficient for the corresponding call to
//! [`Connection::accept_bi`] to return. The sender **must** send data on the stream before
//! the receiver's [`Connection::accept_bi`] call will return.
//!
//! </div>
//!
//! ## Node Discovery
//!
//! The need to know the [`RelayUrl`] *or* some direct addresses in addition to the
//! [`NodeId`] to connect to an iroh-net node can be an obstacle. To address this the
//! [`endpoint::Builder`] allows to configure a [`discovery`] service.
//!
//! The [`DnsDiscovery`] service is a discovery service which will publish the [`RelayUrl`]
//! and direct addresses to a service publishing those as DNS records. To connect it looks
//! up the [`NodeId`] in the DNS system to find the addressing details. This enables
//! connecting using only the [`NodeId`] which is often more convenient and resilient.
//!
//! See [the discovery module] for more details.
//!
//!
//! # Examples
//!
//! The central struct is the [`Endpoint`], which allows you to connect to other nodes:
//!
//! ```no_run
//! use anyhow::Result;
//! use iroh_net::{Endpoint, NodeAddr};
//!
//! async fn connect(addr: NodeAddr) -> Result<()> {
//! // The Endpoint is the central object that manages an iroh-net node.
//! let ep = Endpoint::builder().bind().await?;
//!
//! // Establish a QUIC connection, open a bi-directional stream, exchange messages.
//! let conn = ep.connect(addr, b"hello-world").await?;
//! let (mut send_stream, mut recv_stream) = conn.open_bi().await?;
//! send_stream.write_all(b"hello").await?;
//! send_stream.finish()?;
//! let _msg = recv_stream.read_to_end(10).await?;
//!
//! // Gracefully close the connection and endpoint.
//! conn.close(1u8.into(), b"done");
//! ep.close(0u8.into(), b"ep closing").await?;
//! println!("Client closed");
//! Ok(())
//! }
//! ```
//!
//! Every [`Endpoint`] can also accept connections:
//!
//! ```no_run
//! use anyhow::{Context, Result};
//! use futures_lite::StreamExt;
//! use iroh_net::ticket::NodeTicket;
//! use iroh_net::{Endpoint, NodeAddr};
//!
//! async fn accept() -> Result<()> {
//! // To accept connections at least one ALPN must be configured.
//! let ep = Endpoint::builder()
//! .alpns(vec![b"hello-world".to_vec()])
//! .bind()
//! .await?;
//!
//! // Accept a QUIC connection, accept a bi-directional stream, exchange messages.
//! let conn = ep.accept().await.context("no incoming connection")?.await?;
//! let (mut send_stream, mut recv_stream) = conn.accept_bi().await?;
//! let _msg = recv_stream.read_to_end(10).await?;
//! send_stream.write_all(b"world").await?;
//! send_stream.finish()?;
//!
//! // Wait for the client to close the connection and gracefully close the endpoint.
//! conn.closed().await;
//! ep.close(0u8.into(), b"ep closing").await?;
//! Ok(())
//! }
//! ```
//!
//! Please see the examples directory for more nuanced examples.
//!
//!
//! [QUIC]: https://quickwg.org
//! [bi-directional streams]: crate::endpoint::Connection::open_bi
//! [`NodeTicket`]: crate::ticket::NodeTicket
//! [hole punching]: https://en.wikipedia.org/wiki/Hole_punching_(networking)
//! [socket addresses]: https://doc.rust-lang.org/stable/std/net/enum.SocketAddr.html
//! [STUN]: https://en.wikipedia.org/wiki/STUN
//! [ALPN]: https://en.wikipedia.org/wiki/Application-Layer_Protocol_Negotiation
//! [HTTP3]: https://en.wikipedia.org/wiki/HTTP/3
//! [`SecretKey`]: crate::key::SecretKey
//! [`PublicKey`]: crate::key::PublicKey
//! [`RelayUrl`]: crate::relay::RelayUrl
//! [`discovery`]: crate::endpoint::Builder::discovery
//! [`DnsDiscovery`]: crate::discovery::dns::DnsDiscovery
//! [number 0]: https://n0.computer
//! [`RelayMode::Default`]: crate::relay::RelayMode::Default
//! [the discovery module]: crate::discovery
//! [`Connection::open_bi`]: crate::endpoint::Connection::open_bi
//! [`Connection::accept_bi`]: crate::endpoint::Connection::accept_bi
#![recursion_limit = "256"]
#![deny(missing_docs, rustdoc::broken_intra_doc_links)]
#![cfg_attr(iroh_docsrs, feature(doc_cfg))]
pub mod defaults;
pub mod dialer;
mod disco;
pub mod discovery;
pub mod dns;
pub mod endpoint;
mod magicsock;
pub mod metrics;
pub mod netcheck;
pub mod ping;
pub mod relay;
pub mod stun;
pub mod ticket;
pub mod tls;
pub(crate) mod util;
pub use endpoint::{AddrInfo, Endpoint, NodeAddr};
pub use iroh_base::{key, key::NodeId};
#[cfg(any(test, feature = "test-utils"))]
#[cfg_attr(iroh_docsrs, doc(cfg(any(test, feature = "test-utils"))))]
pub mod test_utils;