Skip to content

Commit

Permalink
PR cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
“ramfox” committed Nov 28, 2024
1 parent 79af777 commit 2ba32d3
Show file tree
Hide file tree
Showing 9 changed files with 252 additions and 196 deletions.
2 changes: 1 addition & 1 deletion iroh-net/src/defaults.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use iroh_base::relay_map::QuicConfig;
/// for QUIC address discovery
///
/// The port is "QUIC" typed on a phone keypad.
pub use iroh_base::relay_map::DEFAULT_QUIC_PORT;
pub use iroh_base::relay_map::DEFAULT_QUIC_PORT as DEFAULT_RELAY_QUIC_PORT;
/// The default STUN port used by the Relay server.
///
/// The STUN port as defined by [RFC
Expand Down
31 changes: 16 additions & 15 deletions iroh-net/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use std::net::Ipv4Addr;
use anyhow::Result;
pub use dns_and_pkarr_servers::DnsPkarrServer;
pub use dns_server::create_dns_resolver;
use iroh_base::relay_map::DEFAULT_QUIC_PORT;
use iroh_relay::server::{
CertConfig, QuicConfig, RelayConfig, Server, ServerConfig, StunConfig, TlsConfig,
};
Expand Down Expand Up @@ -55,7 +54,7 @@ pub async fn run_relay_server_with_stun() -> Result<(RelayMap, RelayUrl, Server)
/// `stun` can be set to `None` to disable stun, or set to `Some` `StunConfig`,
/// to enable stun on a specific socket.
///
/// If `quic` is set to `true`, it will make the appropriate [`QuicConfig`] from the generated tls certificates and run the quic server at port [`iroh_relay::defaults::DEFAULT_QUIC_PORT`].
/// If `quic` is set to `true`, it will make the appropriate [`QuicConfig`] from the generated tls certificates and run the quic server at a random free port.
///
///
/// The return value is similar to [`run_relay_server`].
Expand All @@ -64,23 +63,24 @@ pub async fn run_relay_server_with(
quic: bool,
) -> Result<(RelayMap, RelayUrl, Server)> {
let (certs, server_config) = iroh_relay::server::testing::self_signed_tls_certs_and_config();
let tls = TlsConfig {
cert: CertConfig::<(), ()>::Manual { certs },
https_bind_addr: (Ipv4Addr::LOCALHOST, 0).into(),
quic_bind_addr: (Ipv4Addr::LOCALHOST, 0).into(),
server_config,
};
let quic = if quic {
Some(QuicConfig::new(
server_config.clone(),
"127.0.0.1".parse()?,
Some(0),
)?)
Some(QuicConfig {
server_config: tls.server_config.clone(),
bind_addr: tls.quic_bind_addr,
})
} else {
None
};
let config = ServerConfig {
relay: Some(RelayConfig {
http_bind_addr: (Ipv4Addr::LOCALHOST, 0).into(),
tls: Some(TlsConfig {
cert: CertConfig::<(), ()>::Manual { certs },
https_bind_addr: (Ipv4Addr::LOCALHOST, 0).into(),
server_config,
}),
tls: Some(tls),
limits: Default::default(),
}),
quic,
Expand All @@ -92,9 +92,10 @@ pub async fn run_relay_server_with(
let url: RelayUrl = format!("https://{}", server.https_addr().expect("configured"))
.parse()
.unwrap();
let quic = Some(iroh_base::relay_map::QuicConfig {
port: server.quic_addr().map_or(DEFAULT_QUIC_PORT, |s| s.port()),
});
let quic = match server.quic_addr() {
Some(addr) => Some(iroh_base::relay_map::QuicConfig { port: addr.port() }),
None => None,
};
let m = RelayMap::from_nodes([RelayNode {
url: url.clone(),
stun_only: false,
Expand Down
2 changes: 1 addition & 1 deletion iroh-relay/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ dangerous-certs = []
[[bin]]
name = "iroh-relay"
path = "src/main.rs"
required-features = ["server", "dangerous-certs"]
required-features = ["server"]

[package.metadata.docs.rs]
all-features = 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; the local certificates that we generate using `rcgen` may not work properly for the TCP relay connections.

# License

This project is licensed under either of
Expand Down
35 changes: 16 additions & 19 deletions iroh-relay/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,27 +378,21 @@ impl ClientBuilder {
}

#[cfg(any(test, feature = "test-utils", feature = "dangerous-certs"))]
/// Creates a client config that trusts relay servers without verification
/// Creates a client config that trusts any servers without verifying their TLS certificate.
///
/// Should be used for testing local relay setups only.
pub fn make_dangerous_client_config() -> quinn::crypto::rustls::QuicClientConfig {
let roots = rustls::RootCertStore {
roots: webpki_roots::TLS_SERVER_ROOTS.to_vec(),
};
let mut config = rustls::client::ClientConfig::builder_with_provider(Arc::new(
pub 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")
.with_root_certificates(roots)
.with_no_client_auth();
warn!(
"Insecure config: SSL certificates from relay servers will be trusted without verification"
);
config
.dangerous()
.set_certificate_verifier(Arc::new(NoCertVerifier));
quinn::crypto::rustls::QuicClientConfig::try_from(config).expect("Using tls1.3")
.dangerous()
.with_custom_certificate_verifier(Arc::new(NoCertVerifier))
.with_no_client_auth()
}

impl ClientReceiver {
Expand Down Expand Up @@ -1134,12 +1128,15 @@ impl DnsExt for DnsResolver {
}

/// Used to allow self signed certificates in tests
#[cfg(any(test, feature = "test-utils"))]
#[cfg_attr(iroh_docsrs, doc(cfg(any(test, feature = "test-utils"))))]
#[cfg(any(test, feature = "test-utils", feature = "dangerous-certs"))]
#[cfg_attr(
iroh_docsrs,
doc(cfg(any(test, feature = "test-utils", feature = "dangerous-certs")))
)]
#[derive(Debug)]
pub(crate) struct NoCertVerifier;
struct NoCertVerifier;

#[cfg(any(test, feature = "test-utils"))]
#[cfg(any(test, feature = "test-utils", feature = "dangerous-certs"))]
impl rustls::client::danger::ServerCertVerifier for NoCertVerifier {
fn verify_server_cert(
&self,
Expand Down
95 changes: 56 additions & 39 deletions iroh-relay/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use std::{

use anyhow::{bail, Context as _, Result};
use clap::Parser;
use iroh_base::relay_map::DEFAULT_QUIC_PORT;
use iroh_relay::{
defaults::{DEFAULT_HTTPS_PORT, DEFAULT_HTTP_PORT, DEFAULT_METRICS_PORT, DEFAULT_STUN_PORT},
server::{self as relay, ClientConnRateLimit, QuicConfig},
Expand All @@ -33,6 +34,14 @@ struct Cli {
/// Running in dev mode will ignore any config file fields pertaining to TLS.
#[clap(long, default_value_t = false)]
dev: bool,
/// Run in localhost development mode over plain HTTP and the QUIC endpoint for QUIC address discovery.
///
/// Defaults to running the relay server on port 3340 and the QUIC endpoint over 7842.
///
/// Running in dev-quic mode requires tls configuration for the QUIC endpoint. It will ignore
/// any tls configuration for the relay.
#[clap(long, default_value_t = false)]
dev_quic: bool,
/// Path to the configuration file.
///
/// If provided and no configuration file exists the default configuration will be
Expand Down Expand Up @@ -115,13 +124,20 @@ struct Config {
/// `https_bind_addr` of the `tls` configuration section and only the captive portal
/// will be served from the HTTP socket.
http_bind_addr: Option<SocketAddr>,
/// When `true`, will only bind the relay to http.
/// Default is `false`.
///
/// When the `--dev` flag is used on the CLI, it will set `http_only` to `true`.
#[serde(default = "cfg_defaults::http_only")]
http_only: bool,
/// TLS specific configuration.
///
/// TLS is disabled if not present and the Relay server will serve all services over
/// plain HTTP.
///
/// If disabled all services will run on plain HTTP. The `--dev` option disables this,
/// regardless of what is in the configuration file.
/// If disabled all services will run on plain HTTP.
///
/// Must exist if `enable_quic_addr_discovery` is `true`.
tls: Option<TlsConfig>,
/// Whether to run a STUN server. It will bind to the same IP as the `addr` field.
///
Expand All @@ -134,25 +150,11 @@ struct Config {
stun_bind_addr: Option<SocketAddr>,
/// Whether to allow QUIC connections for QUIC address discovery
///
/// If no `tls` is set, this will cause building the server to erorr.
///
/// Defaults to `true`
#[serde(default = "cfg_defaults::enable_quic_addr_discovery")]
enable_quic_addr_discovery: bool,
/// Whether to use self-signed local certificates for the QUIC server.
///
/// Only considered when `enable_quic_addr_discovery` is `true` and should
/// only be used when the relay is run locally in dev mode.
///
/// Will ignore any other tls certificates passed to the relay server.
///
/// Binds the QUIC server to "127.0.0.1".
enable_quic_local_cert: bool,
/// The port to bind the QUIC server on.
///
/// The socket address will use the ip address from the tls config.
///
/// If `None`, then the [`DEFAULT_QUIC_PORT`] will be used. If 0,
/// then the socket will bind to a random unused port.
quic_bind_port: Option<u16>,
/// Rate limiting configuration.
///
/// Disabled if not present.
Expand Down Expand Up @@ -191,12 +193,11 @@ impl Default for Config {
Self {
enable_relay: true,
http_bind_addr: None,
http_only: false,
tls: None,
enable_stun: true,
stun_bind_addr: None,
enable_quic_addr_discovery: true,
enable_quic_local_cert: false,
quic_bind_port: None,
limits: None,
enable_metrics: true,
metrics_bind_addr: None,
Expand All @@ -213,6 +214,10 @@ mod cfg_defaults {
true
}

pub(crate) fn http_only() -> bool {
false
}

pub(crate) fn enable_stun() -> bool {
true
}
Expand All @@ -238,6 +243,14 @@ struct TlsConfig {
///
/// Defaults to the `http_bind_addr` with the port set to `443`.
https_bind_addr: Option<SocketAddr>,
/// The socket address to bind the QUIC server one.
///
/// Defaults to the `https_bind_addr` with the port set to [`iroh_base::relay_map::DEFAULT_QUIC_PORT`].
///
/// If `https_bind_addr` is not set, defaults to `http_bind_addr` with the
/// port set to [`iroh_base::relay_map::DEFAULT_QUIC_PORT`]
quic_bind_addr: Option<SocketAddr>,
///
/// Certificate hostname when using LetsEncrypt.
hostname: Option<String>,
/// Mode for getting a cert.
Expand Down Expand Up @@ -287,6 +300,11 @@ impl TlsConfig {
.unwrap_or_else(|| SocketAddr::new(cfg.http_bind_addr().ip(), DEFAULT_HTTPS_PORT))
}

fn quic_bind_addr(&self, cfg: &Config) -> SocketAddr {
self.quic_bind_addr
.unwrap_or_else(|| SocketAddr::new(self.https_bind_addr(cfg).ip(), DEFAULT_QUIC_PORT))
}

fn cert_dir(&self) -> PathBuf {
self.cert_dir.clone().unwrap_or_else(|| PathBuf::from("."))
}
Expand Down Expand Up @@ -374,13 +392,18 @@ async fn main() -> Result<()> {

let cli = Cli::parse();
let mut cfg = Config::load(&cli).await?;
if cli.dev {
cfg.tls = None;
if cli.dev || cli.dev_quic {
cfg.http_only = true;
if cfg.http_bind_addr.is_none() {
cfg.http_bind_addr = Some((Ipv6Addr::UNSPECIFIED, DEV_MODE_HTTP_PORT).into());
}
cfg.enable_quic_local_cert = true;
}
if cli.dev {
cfg.enable_quic_addr_discovery = false;
}
if cfg.tls.is_none() && cfg.enable_quic_addr_discovery {
bail!("If QUIC address discovery is enabled, TLS must also be configured");
};
let relay_config = build_relay_config(cfg).await?;
debug!("{relay_config:#?}");

Expand All @@ -398,10 +421,10 @@ async fn main() -> Result<()> {
async fn maybe_load_tls(
cfg: &Config,
) -> Result<Option<relay::TlsConfig<std::io::Error, std::io::Error>>> {
if cfg.tls.is_none() {
let Some(ref tls) = cfg.tls else {
println!("no tls, returning none");
return Ok(None);
}
let tls = cfg.tls.as_ref().expect("checked");
};
let server_config = rustls::ServerConfig::builder_with_provider(std::sync::Arc::new(
rustls::crypto::ring::default_provider(),
))
Expand Down Expand Up @@ -445,6 +468,7 @@ async fn maybe_load_tls(
https_bind_addr: tls.https_bind_addr(cfg),
cert: cert_config,
server_config,
quic_bind_addr: tls.quic_bind_addr(cfg),
}))
}

Expand All @@ -455,18 +479,10 @@ async fn build_relay_config(cfg: Config) -> Result<relay::ServerConfig<std::io::
let mut quic_config = None;
if cfg.enable_quic_addr_discovery {
if let Some(ref tls) = relay_tls {
quic_config = Some(QuicConfig::new(
tls.server_config.clone(),
tls.https_bind_addr.ip(),
cfg.quic_bind_port,
)?);
} else if cfg.enable_quic_local_cert {
let (_, server_config) = iroh_relay::server::self_signed_tls_certs_and_config();
quic_config = Some(QuicConfig::new(
server_config,
Ipv6Addr::UNSPECIFIED.into(),
cfg.quic_bind_port,
)?);
quic_config = Some(QuicConfig {
server_config: tls.server_config.clone(),
bind_addr: tls.quic_bind_addr,
});
} else {
bail!("Must have a valid TLS configuration to enable a QUIC server for QUIC address discovery")
}
Expand Down Expand Up @@ -506,7 +522,8 @@ async fn build_relay_config(cfg: Config) -> Result<relay::ServerConfig<std::io::

let relay_config = relay::RelayConfig {
http_bind_addr: cfg.http_bind_addr(),
tls: relay_tls,
// if `http_only` is set, do not pass in any tls configuration
tls: relay_tls.and_then(|tls| if cfg.http_only { None } else { Some(tls) }),
limits,
};
let stun_config = relay::StunConfig {
Expand Down
Loading

0 comments on commit 2ba32d3

Please sign in to comment.