Skip to content

Commit b2cb0ca

Browse files
ramfox“ramfox”
and
“ramfox”
authored
feat(iroh-relay)!: add a QUIC server for QUIC address discovery to the 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” <“kasey@n0.computer”>
1 parent fbcaaa5 commit b2cb0ca

16 files changed

+860
-220
lines changed

Cargo.lock

+95-95
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

example.config.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
[[derp_nodes]]
1+
[[relay_nodes]]
22
url = "https://foo.bar"
33
stun_only = false
44
stun_port = 1244

iroh-base/src/relay_map.rs

+38-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,13 @@ pub use crate::relay_url::RelayUrl;
1010
/// The default STUN port used by the Relay server.
1111
///
1212
/// The STUN port as defined by [RFC 8489](<https://www.rfc-editor.org/rfc/rfc8489#section-18.6>)
13-
const DEFAULT_STUN_PORT: u16 = 3478;
13+
pub const DEFAULT_STUN_PORT: u16 = 3478;
14+
15+
/// The default QUIC port used by the Relay server to accept QUIC connections
16+
/// for QUIC address discovery
17+
///
18+
/// The port is "QUIC" typed on a phone keypad.
19+
pub const DEFAULT_RELAY_QUIC_PORT: u16 = 7842;
1420

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

8190
/// Returns a [`RelayMap`] from a [`RelayUrl`].
8291
///
83-
/// This will use the default STUN port and IP addresses resolved from the URL's host name via DNS.
92+
/// This will use the default STUN port, the default QUIC port
93+
/// (as defined by the `iroh-relay` crate) and IP addresses
94+
/// resolved from the URL's host name via DNS.
8495
/// relay nodes are specified at <../../docs/relay_nodes.md>
8596
pub fn from_url(url: RelayUrl) -> Self {
8697
Self::default_from_node(url, DEFAULT_STUN_PORT)
@@ -122,6 +133,31 @@ pub struct RelayNode {
122133
///
123134
/// Setting this to `0` means the default STUN port is used.
124135
pub stun_port: u16,
136+
/// Configuration to speak to the QUIC endpoint on the relay server.
137+
///
138+
/// When `None`, we will not attempt to do QUIC address discovery
139+
/// with this relay server.
140+
#[serde(default = "quic_config")]
141+
pub quic: Option<QuicConfig>,
142+
}
143+
144+
fn quic_config() -> Option<QuicConfig> {
145+
Some(QuicConfig::default())
146+
}
147+
148+
/// Configuration for speaking to the QUIC endpoint on the relay
149+
/// server to do QUIC address discovery.
150+
#[derive(Debug, Deserialize, Serialize, Clone, Eq, PartialEq, PartialOrd, Ord)]
151+
pub struct QuicConfig {
152+
pub port: u16,
153+
}
154+
155+
impl Default for QuicConfig {
156+
fn default() -> Self {
157+
Self {
158+
port: DEFAULT_RELAY_QUIC_PORT,
159+
}
160+
}
125161
}
126162

127163
impl fmt::Display for RelayNode {

iroh-net-report/src/lib.rs

+6
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,7 @@ mod test_utils {
783783
784784
use std::sync::Arc;
785785

786+
use iroh_base::relay_map::QuicConfig;
786787
use iroh_relay::server;
787788

788789
use crate::RelayNode;
@@ -791,10 +792,14 @@ mod test_utils {
791792
let server = server::Server::spawn(server::testing::server_config())
792793
.await
793794
.expect("should serve relay");
795+
let quic = Some(QuicConfig {
796+
port: server.quic_addr().expect("server should run quic").port(),
797+
});
794798
let node_desc = RelayNode {
795799
url: server.https_url().expect("should work as relay"),
796800
stun_only: false, // the checks above and below guarantee both stun and relay
797801
stun_port: server.stun_addr().expect("server should serve stun").port(),
802+
quic,
798803
};
799804

800805
(server, Arc::new(node_desc))
@@ -879,6 +884,7 @@ mod tests {
879884
url,
880885
stun_port: port,
881886
stun_only,
887+
quic: None,
882888
}
883889
});
884890
RelayMap::from_nodes(nodes).expect("generated invalid nodes")

iroh-relay/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ postcard = { version = "1", default-features = false, features = [
5050
"use-std",
5151
"experimental-derive",
5252
] }
53+
quinn = { package = "iroh-quinn", version = "0.12.0" }
54+
quinn-proto = { package = "iroh-quinn-proto", version = "0.12.0" }
5355
rand = "0.8"
5456
rcgen = { version = "0.13", optional = true }
5557
regex = { version = "1.7.1", optional = true }

iroh-relay/README.md

+39
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,45 @@ relays, including:
2323

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

26+
## Local testing
27+
28+
Advice for testing your application that uses `iroh` with a locally running `iroh-relay` server
29+
30+
### dev mode
31+
When running the relay server using the `--dev` flag, you will:
32+
- only run the server over http, not https
33+
- will NOT run the QUIC endpoint that enables QUIC address discovery
34+
35+
The relay can be contacted at "http://localhost:3340".
36+
37+
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.
38+
39+
### dev mode with QUIC address discovery
40+
41+
So you want to test out QUIC address discovery locally?
42+
43+
In order to do that you need TLS certificates.
44+
45+
The easiest get that is to generate self-signed certificates using `rcgen`
46+
- get rcgen (`git clone https://github.com/rustls/rcgen`)
47+
- cd to the `rcgen` directory
48+
- generate local certs using `cargo run -- -o path/to/certs`
49+
50+
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.
51+
```toml
52+
[tlsconfig]
53+
cert_mode = "Manual"
54+
manual_cert_path = "/path/to/certs/cert.pem"
55+
manual_key_path = "/path/to/certs/cert.key.pem"
56+
```
57+
58+
Then run the server with the `--dev-quic` flag:
59+
`cargo run --bin iroh-relay -- --config-path=/path/to/config.toml --dev-quic`
60+
61+
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.
62+
63+
The relay will use the configured TLS certificates for the QUIC connection, but use http (rather than https) for the server.
64+
2665
# License
2766

2867
This project is licensed under either of

iroh-relay/src/client.rs

+19-1
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,24 @@ impl ClientBuilder {
377377
}
378378
}
379379

380+
#[cfg(test)]
381+
/// Creates a client config that trusts any servers without verifying their TLS certificate.
382+
///
383+
/// Should be used for testing local relay setups only.
384+
pub(crate) fn make_dangerous_client_config() -> rustls::ClientConfig {
385+
warn!(
386+
"Insecure config: SSL certificates from relay servers will be trusted without verification"
387+
);
388+
rustls::client::ClientConfig::builder_with_provider(Arc::new(
389+
rustls::crypto::ring::default_provider(),
390+
))
391+
.with_protocol_versions(&[&rustls::version::TLS13])
392+
.expect("protocols supported by ring")
393+
.dangerous()
394+
.with_custom_certificate_verifier(Arc::new(NoCertVerifier))
395+
.with_no_client_auth()
396+
}
397+
380398
impl ClientReceiver {
381399
/// Reads a message from the server.
382400
pub async fn recv(&mut self) -> Option<Result<ReceivedMessage, ClientError>> {
@@ -620,7 +638,7 @@ impl Actor {
620638
}
621639

622640
event!(
623-
target: "iroh::_events::relay::connected",
641+
target: "events.net.relay.connected",
624642
Level::DEBUG,
625643
home = self.is_preferred,
626644
url = %self.url,

iroh-relay/src/defaults.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
//! Default values used in the relay.
22
3-
/// The efault STUN port used by the Relay server.
4-
///
5-
/// The STUN port as defined by [RFC
6-
/// 8489](<https://www.rfc-editor.org/rfc/rfc8489#section-18.6>)
7-
pub const DEFAULT_STUN_PORT: u16 = 3478;
3+
pub use iroh_base::relay_map::{DEFAULT_RELAY_QUIC_PORT, DEFAULT_STUN_PORT};
84

95
/// The default HTTP port used by the Relay server.
106
pub const DEFAULT_HTTP_PORT: u16 = 80;

iroh-relay/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub mod client;
2525
pub mod defaults;
2626
pub mod http;
2727
pub mod protos;
28+
pub mod quic;
2829
#[cfg(feature = "server")]
2930
#[cfg_attr(iroh_docsrs, doc(cfg(feature = "server")))]
3031
pub mod server;

0 commit comments

Comments
 (0)