diff --git a/Cargo.lock b/Cargo.lock index 8aa8f62..9287c76 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1216,10 +1216,15 @@ name = "ptth_quic_client_gui" version = "0.1.0" dependencies = [ "anyhow", + "blake3", "fltk", "quic_demo", "quinn", + "rand", + "rand_chacha", "reqwest", + "rmp-serde", + "serde", "structopt", "tokio", "tracing", diff --git a/prototypes/ptth_quic_client_gui/Cargo.toml b/prototypes/ptth_quic_client_gui/Cargo.toml index 27f81c1..23b6df2 100644 --- a/prototypes/ptth_quic_client_gui/Cargo.toml +++ b/prototypes/ptth_quic_client_gui/Cargo.toml @@ -9,10 +9,15 @@ license = "AGPL-3.0" [dependencies] anyhow = "1.0.38" +blake3 = "1.0.0" fltk = "1.2.7" quic_demo = { path = "../quic_demo" } quinn = "0.7.2" +rand = "0.8.4" +rand_chacha = "0.3.1" reqwest = "0.11.4" +rmp-serde = "0.15.5" +serde = "1.0.130" structopt = "0.3.20" tokio = { version = "1.8.1", features = ["full"] } tracing-subscriber = "0.2.16" diff --git a/prototypes/ptth_quic_client_gui/src/main.rs b/prototypes/ptth_quic_client_gui/src/main.rs index b83adb5..6ee835b 100644 --- a/prototypes/ptth_quic_client_gui/src/main.rs +++ b/prototypes/ptth_quic_client_gui/src/main.rs @@ -12,6 +12,10 @@ use fltk::{ prelude::*, window::Window }; +use rand::{ + Rng, + SeedableRng, +}; use structopt::StructOpt; use tokio::runtime::Runtime; @@ -272,7 +276,8 @@ impl GuiPort { row.set_size (&mut but_open, 80); row.set_size (&mut but_close, 80); - input_client_port.set_value ("0"); + input_client_port.set_value (""); + input_client_port.set_readonly (true); input_server_id.set_value ("bogus_server"); input_server_port.set_value ("5900"); @@ -281,26 +286,32 @@ impl GuiPort { but_close.set_trigger (CallbackTrigger::Release); but_close.emit (fltk_tx, Message::ClosePort (port_idx)); - set_active (&mut but_open, true); - set_active (&mut but_close, false); - row.end (); - Self { + let mut output = Self { row, input_client_port, input_server_id, input_server_port, but_open, but_close, - } + }; + + output.set_forwarding (false); + + output } fn get_params (&self) -> anyhow::Result { - let client_tcp_port = u16::from_str (&self.input_client_port.value ())?; - let server_id = self.input_server_id.value (); let server_tcp_port = u16::from_str (&self.input_server_port.value ())?; + let server_id = self.input_server_id.value (); + + let client_tcp_port = PortInfo { + relay_addr: "bogus_relay", + server_id: &server_id, + server_tcp_port, + }.random_eph_port (); Ok (ForwardingParams { client_tcp_port, @@ -310,7 +321,7 @@ impl GuiPort { } fn set_forwarding (&mut self, x: bool) { - set_active (&mut self.input_client_port, !x); + set_active (&mut self.input_client_port, x); set_active (&mut self.input_server_id, !x); set_active (&mut self.input_server_port, !x); set_active (&mut self.but_open, !x); @@ -320,3 +331,63 @@ impl GuiPort { self.but_close.set (!x); } } + +// This can collide, but who cares +// It's not secure or anything - It's just supposed to pick a port somewhat +// deterministically based on the server and relay info. + +#[derive (serde::Serialize)] +struct PortInfo <'a> { + relay_addr: &'a str, + server_id: &'a str, + server_tcp_port: u16 +} + +impl PortInfo <'_> { + // https://en.wikipedia.org/wiki/TCP_ports#Dynamic,_private_or_ephemeral_ports + + fn random_eph_port (&self) -> u16 + { + let seed = blake3::hash (&rmp_serde::to_vec (self).expect ("Can't hash PortInfo - impossible error")); + + let mut rng = rand_chacha::ChaCha20Rng::from_seed (*seed.as_bytes ()); + + let tcp_eph_range = 49152..=65535; + rng.gen_range (tcp_eph_range) + } +} + +#[cfg (test)] +mod test { + use blake3::Hasher; + + use super::*; + + #[test] + fn prng () { + let hasher = Hasher::default (); + let seed = hasher.finalize (); + + let mut rng = rand_chacha::ChaCha20Rng::from_seed (*seed.as_bytes ()); + + let tcp_eph_range = 49152..=65535; + let port = rng.gen_range (tcp_eph_range); + assert_eq! (port, 49408); + + for (input, expected) in vec! [ + (("bogus_relay", "bogus_server", 22), 62350), + (("real_relay", "bogus_server", 22), 61081), + (("bogus_relay", "real_server", 22), 50513), + (("bogus_relay", "bogus_server", 5900), 60730), + ] { + let (relay_addr, server_id, server_tcp_port) = input; + let input = PortInfo { + relay_addr, + server_id, + server_tcp_port, + }; + let actual = input.random_eph_port (); + assert_eq! (expected, actual); + } + } +}