Skip to content

Commit

Permalink
feat(iroh-relay)!: add a QUIC server for QUIC address discovery to th…
Browse files Browse the repository at this point in the history
…e iroh relay. (#2965)

## Description

This PR adds a QUIC endpoint to the relay server that can do QUIC
address discovery. It also contains structs/functions for properly doing
the Client side interaction for this process.

Also, this adjust the `RelayNode` to include configuration on how to
speak to the QUIC endpoint on the relay server.

QUIC is disabled by default and requires a `TlsConfig` to be configured
in order to work.

closes #2964 

## Breaking Changes

- `iroh_base::relay_map::RelayNode` now has field `quic` that takes a
`Option<iroh_base::relay_map::QuicConfig>`
- `iroh::test_utils::run_relay_server_with(stun: Option<StunConfig>)` =>
`iroh::test_utils::run_relay_server_with(stun: Option<StunConfig>, quic:
bool)`
- when `quic` is `true`, it will start a quic server for QUIC address
discovery, that has self signed tls certs for testing.
- `iroh_relay::server::ServerConfig` has field `quic` that takes a
`Option<iroh_relay::server::QuicConfig>`
- `iroh_relay::server::TlsConfig.quic_bind_addr` is a new field that
takes a `SocketAddr`
- `iroh_relay::server::TlsConfig.server_config` is a new field that
takes a `rustls::ServerConfig`
- field `config` has been removed from variant
`iroh_relay::server::CertConfig::LetsEncrypt`
- variant `iroh_relay::server::CertConfig::LetsEncrypt` has a new field
`state` that takes a `tokio_rustls_acme::AcmeState<EC, EA>`
- variant `iroh_relay::server::CertConfig::Manual` no longer has field
`private_key`

## Change checklist

- [x] Self-review.
- [x] Documentation updates following the [style
guide](https://rust-lang.github.io/rfcs/1574-more-api-documentation-conventions.html#appendix-a-full-conventions-text),
if relevant.
- [x] Tests if relevant.
- [x] All breaking changes documented.

---------

Co-authored-by: “ramfox” <“[email protected]”>
  • Loading branch information
ramfox and “ramfox” authored Dec 2, 2024
1 parent fbcaaa5 commit b2cb0ca
Show file tree
Hide file tree
Showing 16 changed files with 860 additions and 220 deletions.
190 changes: 95 additions & 95 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion example.config.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[[derp_nodes]]
[[relay_nodes]]
url = "https://foo.bar"
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.
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

0 comments on commit b2cb0ca

Please sign in to comment.