From 16ae0f7782349efe0a93bfd4d23a0f4560d7d042 Mon Sep 17 00:00:00 2001 From: Phoenix Kahlo Date: Thu, 15 Feb 2024 19:26:45 -0600 Subject: [PATCH] Demonstrate IP blocking in example This commit adds a new --block option to the server example to illustate in a simplified way the general structure one would use to implement IP address blocking with the new accept/reject/retry API. For example: cargo run --example server ./ --listen 127.0.0.1:4433 --stateless-retry --block 127.0.0.1:8065 cargo run --example client https://127.0.0.1:4433/Cargo.toml --host localhost --bind 127.0.0.1:8065 One thing to note is that that example places the reject condition before the retry condition. This expends slightly less effort rejecting connections, but does create a blocked IP address oracle for an attacker who can do address spoofing. --- quinn/examples/client.rs | 8 ++++++-- quinn/examples/server.rs | 8 +++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/quinn/examples/client.rs b/quinn/examples/client.rs index 3e85dd66f8..e189663e20 100644 --- a/quinn/examples/client.rs +++ b/quinn/examples/client.rs @@ -5,7 +5,7 @@ use std::{ fs, io::{self, Write}, - net::ToSocketAddrs, + net::{SocketAddr, ToSocketAddrs}, path::PathBuf, sync::Arc, time::{Duration, Instant}, @@ -39,6 +39,10 @@ struct Opt { /// Simulate NAT rebinding after connecting #[clap(long = "rebind")] rebind: bool, + + /// Address to bind on + #[clap(long = "bind", default_value = "[::]:0")] + bind: SocketAddr, } fn main() { @@ -97,7 +101,7 @@ async fn run(options: Opt) -> Result<()> { } let client_config = quinn::ClientConfig::new(Arc::new(client_crypto)); - let mut endpoint = quinn::Endpoint::client("[::]:0".parse().unwrap())?; + let mut endpoint = quinn::Endpoint::client(options.bind)?; endpoint.set_default_client_config(client_config); let request = format!("GET {}\r\n", url.path()); diff --git a/quinn/examples/server.rs b/quinn/examples/server.rs index db887d99aa..4b02bfea6d 100644 --- a/quinn/examples/server.rs +++ b/quinn/examples/server.rs @@ -37,6 +37,9 @@ struct Opt { /// Address to listen on #[clap(long = "listen", default_value = "[::1]:4433")] listen: SocketAddr, + /// Client address to block + #[clap(long = "block")] + block: Option, } fn main() { @@ -142,7 +145,10 @@ async fn run(options: Opt) -> Result<()> { eprintln!("listening on {}", endpoint.local_addr()?); while let Some(conn) = endpoint.accept().await { - if options.stateless_retry && !conn.remote_address_validated() { + if Some(conn.remote_address()) == options.block { + info!("rejecting blocked client IP address"); + conn.reject(); + } else if options.stateless_retry && !conn.remote_address_validated() { info!("requiring connection to validate its address"); conn.retry().unwrap(); } else {