Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(iroh-relay)!: add a QUIC server for QUIC address discovery to the iroh relay. #2965

Merged
merged 19 commits into from
Dec 2, 2024
Merged
190 changes: 95 additions & 95 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion example.config.toml
ramfox marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[[derp_nodes]]
[[relay_nodes]]
url = "https://foo.bar"
flub marked this conversation as resolved.
Show resolved Hide resolved
stun_only = false
stun_port = 1244
Expand Down
40 changes: 38 additions & 2 deletions iroh-base/src/relay_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,13 @@ pub use crate::relay_url::RelayUrl;
/// The default STUN port used by the Relay server.
///
/// The STUN port as defined by [RFC 8489](<https://www.rfc-editor.org/rfc/rfc8489#section-18.6>)
const DEFAULT_STUN_PORT: u16 = 3478;
pub const DEFAULT_STUN_PORT: u16 = 3478;

/// The default QUIC port used by the Relay server to accept QUIC connections
/// for QUIC address discovery
///
/// The port is "QUIC" typed on a phone keypad.
ramfox marked this conversation as resolved.
Show resolved Hide resolved
pub const DEFAULT_RELAY_QUIC_PORT: u16 = 7842;

/// Configuration of all the relay servers that can be used.
#[derive(Debug, Clone, PartialEq, Eq)]
Expand Down Expand Up @@ -61,6 +67,8 @@ impl RelayMap {
///
/// Allows to set a custom STUN port and different IP addresses for IPv4 and IPv6.
/// If IP addresses are provided, no DNS lookup will be performed.
///
/// Sets the port to the default [`DEFAULT_RELAY_QUIC_PORT`].
pub fn default_from_node(url: RelayUrl, stun_port: u16) -> Self {
let mut nodes = BTreeMap::new();
nodes.insert(
Expand All @@ -69,6 +77,7 @@ impl RelayMap {
url,
stun_only: false,
stun_port,
quic: Some(QuicConfig::default()),
}
.into(),
);
Expand All @@ -80,7 +89,9 @@ impl RelayMap {

/// Returns a [`RelayMap`] from a [`RelayUrl`].
///
/// This will use the default STUN port and IP addresses resolved from the URL's host name via DNS.
/// This will use the default STUN port, the default QUIC port
/// (as defined by the `iroh-relay` crate) and IP addresses
/// resolved from the URL's host name via DNS.
/// relay nodes are specified at <../../docs/relay_nodes.md>
pub fn from_url(url: RelayUrl) -> Self {
Self::default_from_node(url, DEFAULT_STUN_PORT)
Expand Down Expand Up @@ -122,6 +133,31 @@ pub struct RelayNode {
///
/// Setting this to `0` means the default STUN port is used.
pub stun_port: u16,
/// Configuration to speak to the QUIC endpoint on the relay server.
///
/// When `None`, we will not attempt to do QUIC address discovery
/// with this relay server.
#[serde(default = "quic_config")]
pub quic: Option<QuicConfig>,
}

fn quic_config() -> Option<QuicConfig> {
Some(QuicConfig::default())
}

/// Configuration for speaking to the QUIC endpoint on the relay
/// server to do QUIC address discovery.
#[derive(Debug, Deserialize, Serialize, Clone, Eq, PartialEq, PartialOrd, Ord)]
pub struct QuicConfig {
pub port: u16,
}

impl Default for QuicConfig {
fn default() -> Self {
Self {
port: DEFAULT_RELAY_QUIC_PORT,
}
}
}

impl fmt::Display for RelayNode {
Expand Down
6 changes: 6 additions & 0 deletions iroh-net-report/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,7 @@ mod test_utils {

use std::sync::Arc;

use iroh_base::relay_map::QuicConfig;
use iroh_relay::server;

use crate::RelayNode;
Expand All @@ -791,10 +792,14 @@ mod test_utils {
let server = server::Server::spawn(server::testing::server_config())
.await
.expect("should serve relay");
let quic = Some(QuicConfig {
port: server.quic_addr().expect("server should run quic").port(),
});
let node_desc = RelayNode {
url: server.https_url().expect("should work as relay"),
stun_only: false, // the checks above and below guarantee both stun and relay
stun_port: server.stun_addr().expect("server should serve stun").port(),
quic,
};

(server, Arc::new(node_desc))
Expand Down Expand Up @@ -879,6 +884,7 @@ mod tests {
url,
stun_port: port,
stun_only,
quic: None,
}
});
RelayMap::from_nodes(nodes).expect("generated invalid nodes")
Expand Down
2 changes: 2 additions & 0 deletions iroh-relay/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ postcard = { version = "1", default-features = false, features = [
"use-std",
"experimental-derive",
] }
quinn = { package = "iroh-quinn", version = "0.12.0" }
quinn-proto = { package = "iroh-quinn-proto", version = "0.12.0" }
rand = "0.8"
rcgen = { version = "0.13", optional = true }
regex = { version = "1.7.1", optional = true }
Expand Down
39 changes: 39 additions & 0 deletions iroh-relay/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,45 @@ relays, including:

Used in [iroh], created with love by the [n0 team](https://n0.computer/).

## Local testing

Advice for testing your application that uses `iroh` with a locally running `iroh-relay` server

### dev mode
When running the relay server using the `--dev` flag, you will:
- only run the server over http, not https
- will NOT run the QUIC endpoint that enables QUIC address discovery

The relay can be contacted at "http://localhost:3340".

Both https and QUIC address discovery require TLS certificates. It's possible to run QUIC address discovery using locally generated TLS certificates, but it takes a few extra steps and so, is disabled by default for now.

### dev mode with QUIC address discovery

So you want to test out QUIC address discovery locally?

In order to do that you need TLS certificates.

The easiest get that is to generate self-signed certificates using `rcgen`
- get rcgen (`git clone https://github.com/rustls/rcgen`)
- cd to the `rcgen` directory
- generate local certs using `cargo run -- -o path/to/certs`

Next, add the certificate paths to your iroh-relay config, here is an example of a config.toml file that will enable quic address discovery.
```toml
[tlsconfig]
cert_mode = "Manual"
manual_cert_path = "/path/to/certs/cert.pem"
manual_key_path = "/path/to/certs/cert.key.pem"
```

Then run the server with the `--dev-quic` flag:
`cargo run --bin iroh-relay -- --config-path=/path/to/config.toml --dev-quic`

The relay server will run over http on port 3340, as it does using the `--dev` flag, but it will also run a QUIC server on port 7824.

The relay will use the configured TLS certificates for the QUIC connection, but use http (rather than https) for the server.

# License

This project is licensed under either of
Expand Down
20 changes: 19 additions & 1 deletion iroh-relay/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,24 @@ impl ClientBuilder {
}
}

#[cfg(test)]
/// Creates a client config that trusts any servers without verifying their TLS certificate.
///
/// Should be used for testing local relay setups only.
pub(crate) fn make_dangerous_client_config() -> rustls::ClientConfig {
warn!(
"Insecure config: SSL certificates from relay servers will be trusted without verification"
);
rustls::client::ClientConfig::builder_with_provider(Arc::new(
rustls::crypto::ring::default_provider(),
))
.with_protocol_versions(&[&rustls::version::TLS13])
.expect("protocols supported by ring")
.dangerous()
.with_custom_certificate_verifier(Arc::new(NoCertVerifier))
.with_no_client_auth()
}

impl ClientReceiver {
/// Reads a message from the server.
pub async fn recv(&mut self) -> Option<Result<ReceivedMessage, ClientError>> {
Expand Down Expand Up @@ -620,7 +638,7 @@ impl Actor {
}

event!(
target: "iroh::_events::relay::connected",
target: "events.net.relay.connected",
Level::DEBUG,
home = self.is_preferred,
url = %self.url,
Expand Down
6 changes: 1 addition & 5 deletions iroh-relay/src/defaults.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
//! Default values used in the relay.

/// The efault STUN port used by the Relay server.
///
/// The STUN port as defined by [RFC
/// 8489](<https://www.rfc-editor.org/rfc/rfc8489#section-18.6>)
pub const DEFAULT_STUN_PORT: u16 = 3478;
pub use iroh_base::relay_map::{DEFAULT_RELAY_QUIC_PORT, DEFAULT_STUN_PORT};

/// The default HTTP port used by the Relay server.
pub const DEFAULT_HTTP_PORT: u16 = 80;
Expand Down
1 change: 1 addition & 0 deletions iroh-relay/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub mod client;
pub mod defaults;
pub mod http;
pub mod protos;
pub mod quic;
#[cfg(feature = "server")]
#[cfg_attr(iroh_docsrs, doc(cfg(feature = "server")))]
pub mod server;
Expand Down
Loading
Loading