Compare commits

..

2 Commits

Author SHA1 Message Date
_ e6cf9e2b72 💄 change it to just pick a client port automatically.
This is a lot less thinking for the user. (such as me)
2021-10-10 21:20:35 +00:00
_ 34873dff43 allow `0` to mean "The OS should pick an available TCP port for us to listen to" 2021-10-10 20:42:17 +00:00
4 changed files with 124 additions and 25 deletions

5
Cargo.lock generated
View File

@ -1216,10 +1216,15 @@ name = "ptth_quic_client_gui"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"blake3",
"fltk", "fltk",
"quic_demo", "quic_demo",
"quinn", "quinn",
"rand",
"rand_chacha",
"reqwest", "reqwest",
"rmp-serde",
"serde",
"structopt", "structopt",
"tokio", "tokio",
"tracing", "tracing",

View File

@ -9,10 +9,15 @@ license = "AGPL-3.0"
[dependencies] [dependencies]
anyhow = "1.0.38" anyhow = "1.0.38"
blake3 = "1.0.0"
fltk = "1.2.7" fltk = "1.2.7"
quic_demo = { path = "../quic_demo" } quic_demo = { path = "../quic_demo" }
quinn = "0.7.2" quinn = "0.7.2"
rand = "0.8.4"
rand_chacha = "0.3.1"
reqwest = "0.11.4" reqwest = "0.11.4"
rmp-serde = "0.15.5"
serde = "1.0.130"
structopt = "0.3.20" structopt = "0.3.20"
tokio = { version = "1.8.1", features = ["full"] } tokio = { version = "1.8.1", features = ["full"] }
tracing-subscriber = "0.2.16" tracing-subscriber = "0.2.16"

View File

@ -12,6 +12,10 @@ use fltk::{
prelude::*, prelude::*,
window::Window window::Window
}; };
use rand::{
Rng,
SeedableRng,
};
use structopt::StructOpt; use structopt::StructOpt;
use tokio::runtime::Runtime; use tokio::runtime::Runtime;
@ -51,6 +55,27 @@ struct Port {
forwarding_instance: Option <ForwardingInstance>, forwarding_instance: Option <ForwardingInstance>,
} }
impl Port {
pub fn open_port (&mut self, rt: &Runtime, connection_p2_p3: quinn::Connection)
-> anyhow::Result <()>
{
let params = self.gui.get_params ()?;
let _guard = rt.enter ();
let forwarding_instance = rt.block_on (ForwardingInstance::new (
connection_p2_p3,
params,
))?;
self.gui.input_client_port.set_value (&forwarding_instance.local_port ().to_string ());
self.forwarding_instance.replace (forwarding_instance);
self.gui.set_forwarding (true);
Ok (())
}
}
struct GuiPort { struct GuiPort {
row: fltk::group::Flex, row: fltk::group::Flex,
input_client_port: Input, input_client_port: Input,
@ -67,17 +92,7 @@ impl GuiClient <'_> {
port_idx: usize, port_idx: usize,
) -> anyhow::Result <()> ) -> anyhow::Result <()>
{ {
let params = self.ports [port_idx].gui.get_params ()?; self.ports [port_idx].open_port (&self.rt, connection_p2_p3)?;
let _guard = self.rt.enter ();
let forwarding_instance = self.rt.block_on (ForwardingInstance::new (
connection_p2_p3,
params,
))?;
self.ports [port_idx].forwarding_instance.replace (forwarding_instance);
self.ports [port_idx].gui.set_forwarding (true);
self.sync_status (); self.sync_status ();
Ok (()) Ok (())
@ -152,12 +167,12 @@ fn main () -> anyhow::Result <()> {
{ {
let mut row = Flex::default ().row (); let mut row = Flex::default ().row ();
let mut l = Frame::default ().with_label ("Local port");
row.set_size (&mut l, 80);
let mut l = Frame::default ().with_label ("Server ID"); let mut l = Frame::default ().with_label ("Server ID");
row.set_size (&mut l, 120); row.set_size (&mut l, 120);
let mut l = Frame::default ().with_label ("Server port"); let mut l = Frame::default ().with_label ("Server port");
row.set_size (&mut l, 80); row.set_size (&mut l, 80);
let mut l = Frame::default ().with_label ("Local port");
row.set_size (&mut l, 80);
row.end (); row.end ();
col.set_size (&mut row, 30); col.set_size (&mut row, 30);
@ -249,19 +264,20 @@ impl GuiPort {
let mut row = Flex::default ().row (); let mut row = Flex::default ().row ();
let mut input_client_port = Input::default ();
let mut input_server_id = Input::default (); let mut input_server_id = Input::default ();
let mut input_server_port = Input::default (); let mut input_server_port = Input::default ();
let mut input_client_port = Input::default ();
let mut but_open = Button::default ().with_label ("Open"); let mut but_open = Button::default ().with_label ("Open");
let mut but_close = Button::default ().with_label ("Close"); let mut but_close = Button::default ().with_label ("Close");
row.set_size (&mut input_client_port, 80);
row.set_size (&mut input_server_id, 120); row.set_size (&mut input_server_id, 120);
row.set_size (&mut input_server_port, 80); row.set_size (&mut input_server_port, 80);
row.set_size (&mut input_client_port, 80);
row.set_size (&mut but_open, 80); row.set_size (&mut but_open, 80);
row.set_size (&mut but_close, 80); row.set_size (&mut but_close, 80);
input_client_port.set_value ("5901"); input_client_port.set_value ("");
input_client_port.set_readonly (true);
input_server_id.set_value ("bogus_server"); input_server_id.set_value ("bogus_server");
input_server_port.set_value ("5900"); input_server_port.set_value ("5900");
@ -270,26 +286,32 @@ impl GuiPort {
but_close.set_trigger (CallbackTrigger::Release); but_close.set_trigger (CallbackTrigger::Release);
but_close.emit (fltk_tx, Message::ClosePort (port_idx)); but_close.emit (fltk_tx, Message::ClosePort (port_idx));
set_active (&mut but_open, true);
set_active (&mut but_close, false);
row.end (); row.end ();
Self { let mut output = Self {
row, row,
input_client_port, input_client_port,
input_server_id, input_server_id,
input_server_port, input_server_port,
but_open, but_open,
but_close, but_close,
} };
output.set_forwarding (false);
output
} }
fn get_params (&self) -> anyhow::Result <ForwardingParams> fn get_params (&self) -> anyhow::Result <ForwardingParams>
{ {
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_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 { Ok (ForwardingParams {
client_tcp_port, client_tcp_port,
@ -299,7 +321,7 @@ impl GuiPort {
} }
fn set_forwarding (&mut self, x: bool) { 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_id, !x);
set_active (&mut self.input_server_port, !x); set_active (&mut self.input_server_port, !x);
set_active (&mut self.but_open, !x); set_active (&mut self.but_open, !x);
@ -309,3 +331,63 @@ impl GuiPort {
self.but_close.set (!x); 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);
}
}
}

View File

@ -9,6 +9,7 @@ use crate::prelude::*;
pub struct ForwardingInstance { pub struct ForwardingInstance {
task: JoinHandle <anyhow::Result <()>>, task: JoinHandle <anyhow::Result <()>>,
shutdown_flag: watch::Sender <bool>, shutdown_flag: watch::Sender <bool>,
local_port: u16,
} }
impl ForwardingInstance { impl ForwardingInstance {
@ -20,7 +21,8 @@ impl ForwardingInstance {
let (shutdown_flag, shutdown_flag_rx) = tokio::sync::watch::channel (true); let (shutdown_flag, shutdown_flag_rx) = tokio::sync::watch::channel (true);
let listener = TcpListener::bind (("127.0.0.1", params.client_tcp_port)).await?; let listener = TcpListener::bind (("127.0.0.1", params.client_tcp_port)).await?;
trace! ("Accepting local TCP connections from P1 on {}", params.client_tcp_port); let local_port = listener.local_addr ()?.port ();
trace! ("Accepting local TCP connections from P1 on {}", local_port);
let task = tokio::spawn (forward_port ( let task = tokio::spawn (forward_port (
listener, listener,
@ -32,6 +34,7 @@ impl ForwardingInstance {
Ok (Self { Ok (Self {
task, task,
shutdown_flag, shutdown_flag,
local_port,
}) })
} }
@ -44,6 +47,10 @@ impl ForwardingInstance {
.context ("inside ForwardingInstance task")?; .context ("inside ForwardingInstance task")?;
Ok (()) Ok (())
} }
pub fn local_port (&self) -> u16 {
self.local_port
}
} }
pub struct ForwardingParams { pub struct ForwardingParams {