diff --git a/prototypes/quic_demo/README.md b/prototypes/quic_demo/README.md index a20c4a6..e28d8f4 100644 --- a/prototypes/quic_demo/README.md +++ b/prototypes/quic_demo/README.md @@ -29,68 +29,31 @@ start of bidirectional streams. Unused bytes are always "0". -## QUIC client connection +Messages are sent in request-response pairs, like HTTP. -When P2 or P4 connects to P3 over QUIC, it opens a bi stream and identifies -itself with a 4-byte request. The bytes are: +Requests look like this: -1. Client type -2. Client ID +1. Command type +2. Extra data, or unused, depending on command type 3. Unused 4. Unused -The type is "2" or "4" to identify the client as a P2 or a P4. The IDs are -hard-coded as "42" and "43" for now. +Responses look like this: -P3 responds with these 4 bytes: - -1. Status code -2. Unused +1. Status code (Always "20" for now, meaning "OK") +2. Command type of the request that we're responding to 3. Unused 4. Unused -The status code is always "20" to mean "OK". If authorization or authentication -had failed, it would be something else, and P3 would close the connection. +The command types are: -## PTTH connection - -When P1 connects to P2's TCP listener, P2 opens a bi stream to P3 and sends -this request: - -1. "1" to mean "Open a PTTH connection" -2. Server ID, hard-coded as "43" for the only P4 server instance we have -3. Unused -4. Unused - -The first 4 bytes are interpreted by P3. If everything is okay, P3 responds -with: - -1. "20" to mean "OK". -2. Unused -3. Unused -4. Unused - -Then P3 opens a bi stream to P4 and begins relaying from P2 to P4. - -P2 reads that response and sends another request, which will be forwarded -to P4: - -1. "1" to mean "Open a PTTH connection" -2. Unused (Reserved for choosing port) -3. Unused -4. Unused - -P4 parses the last 4 bytes. If everything is okay, P4 (via P3) responds to P2 with: - -1. "20" to mean "OK". -2. Unused -3. Unused -4. Unused - -And then P4 begins relaying between P2 and P5. - -P2 reads the 4 byte response from P3 and the 4 byte response from P4. -If everything is okay, it completes the relaying from P1 to P5. +| Type | Sender | Receiver | Meaning | +| ---- | ------ | ----------- | ------------------------------------------------- | +| 2 | P2 | P3 | Client proxy wants to connect to the relay | +| 4 | P4 | P3 | Server proxy wants to connect to the relay | +| 10 | P2 | P3 | Client wants relay to connect it to a server | +| 11 | P3 | P4 | Relay tells server that a client wants to connect | +| 12 | P2 | P4 (via P3) | Client wants a port forwarded from the server | # Plan diff --git a/prototypes/quic_demo/src/bin/quic_demo_client.rs b/prototypes/quic_demo/src/bin/quic_demo_client.rs index 3f5022b..e32bd92 100644 --- a/prototypes/quic_demo/src/bin/quic_demo_client.rs +++ b/prototypes/quic_demo/src/bin/quic_demo_client.rs @@ -21,11 +21,24 @@ async fn main () -> anyhow::Result <()> { let (mut send, mut recv) = connection.open_bi ().await?; - let req_buf = [2u8, 42, 0, 0]; + let our_id = 42; + + let req_buf = [ + Command::CONNECT_P2_TO_P3.0, + our_id, + 0, + 0, + ]; send.write_all (&req_buf).await?; - let mut resp_buf = [0u8, 0, 0, 0]; + let mut resp_buf = [0, 0, 0, 0]; recv.read_exact (&mut resp_buf).await?; + assert_eq! (resp_buf, [ + Command::OKAY.0, + Command::CONNECT_P2_TO_P3.0, + 0, + 0, + ]); let listener = TcpListener::bind ("127.0.0.1:30381").await?; @@ -44,23 +57,42 @@ async fn main () -> anyhow::Result <()> { // Ask P3 if we can connect to P4 - let req_buf = [1, 43, 0, 0]; + let server_id = 43; + let req_buf = [ + Command::CONNECT_P2_TO_P4.0, + server_id, + 0, + 0, + ]; relay_send.write_all (&req_buf).await?; let mut resp_buf = [0; 4]; relay_recv.read_exact (&mut resp_buf).await?; - - debug! ("Status code from P3: {}", resp_buf [0]); + assert_eq! (resp_buf, [ + Command::OKAY.0, + Command::CONNECT_P2_TO_P4.0, + 0, + 0, + ]); // Ask P4 if we can connect to P5 - let req_buf = [1, 0, 0, 0]; + let req_buf = [ + Command::CONNECT_P2_TO_P5.0, + 0, + 0, + 0, + ]; relay_send.write_all (&req_buf).await?; let mut resp_buf = [0; 4]; relay_recv.read_exact (&mut resp_buf).await?; - - debug! ("Status code from P4: {}", resp_buf [0]); + assert_eq! (resp_buf, [ + Command::OKAY.0, + Command::CONNECT_P2_TO_P5.0, + 0, + 0, + ]); trace! ("Relaying bytes..."); @@ -116,7 +148,7 @@ impl PtthNewConnection { relay_send.write_all (buf_slice).await?; } - debug! ("Uplink closed"); + trace! ("Uplink closed"); Ok::<_, anyhow::Error> (()) }); @@ -131,7 +163,7 @@ impl PtthNewConnection { local_send.write_all (buf_slice).await?; } - debug! ("Downlink closed"); + trace! ("Downlink closed"); Ok::<_, anyhow::Error> (()) }); diff --git a/prototypes/quic_demo/src/bin/quic_demo_end_server.rs b/prototypes/quic_demo/src/bin/quic_demo_end_server.rs index 316fb56..f598656 100644 --- a/prototypes/quic_demo/src/bin/quic_demo_end_server.rs +++ b/prototypes/quic_demo/src/bin/quic_demo_end_server.rs @@ -20,11 +20,23 @@ async fn main () -> anyhow::Result <()> { let (mut send, mut recv) = connection.open_bi ().await?; - let req_buf = [4u8, 43, 0, 0]; + let our_id = 43; + let req_buf = [ + Command::CONNECT_P4_TO_P3.0, + our_id, + 0, + 0, + ]; send.write_all (&req_buf).await?; - let mut resp_buf = [0u8, 0, 0, 0]; + let mut resp_buf = [0, 0, 0, 0]; recv.read_exact (&mut resp_buf).await?; + assert_eq! (resp_buf, [ + Command::OKAY.0, + Command::CONNECT_P4_TO_P3.0, + 0, + 0, + ]); trace! ("Accepting bi streams from P3"); @@ -34,18 +46,37 @@ async fn main () -> anyhow::Result <()> { tokio::spawn (async move { let mut req_buf = [0, 0, 0, 0]; relay_recv.read_exact (&mut req_buf).await?; + assert_eq! (req_buf [0], Command::CONNECT_P2_TO_P4_STEP_2.0); - // TODO: Auth stuff + // TODO: Authorize P2 to connect to us + + let resp_buf = [ + Command::OKAY.0, + Command::CONNECT_P2_TO_P4_STEP_2.0, + 0, + 0, + ]; + relay_send.write_all (&resp_buf).await?; + + let mut req_buf = [0, 0, 0, 0]; + relay_recv.read_exact (&mut req_buf).await?; + assert_eq! (req_buf [0], Command::CONNECT_P2_TO_P5.0); + + // TODO: Authorize P2 to connect to P5 + + let resp_buf = [ + Command::OKAY.0, + Command::CONNECT_P2_TO_P5.0, + 0, + 0, + ]; + relay_send.write_all (&resp_buf).await?; debug! ("Started PTTH connection"); let stream = TcpStream::connect ("127.0.0.1:30382").await?; let (local_recv, local_send) = stream.into_split (); - let resp_buf = [20, 0, 0, 0]; - relay_send.write_all (&resp_buf).await?; - relay_send.write_all (&resp_buf).await?; - trace! ("Relaying bytes..."); let ptth_conn = PtthNewConnection { @@ -94,7 +125,7 @@ impl PtthNewConnection { local_send.write_all (buf_slice).await?; } - debug! ("Downlink closed"); + trace! ("Downlink closed"); Ok::<_, anyhow::Error> (()) }); @@ -113,7 +144,7 @@ impl PtthNewConnection { relay_send.write_all (buf_slice).await?; } - debug! ("Uplink closed"); + trace! ("Uplink closed"); Ok::<_, anyhow::Error> (()) }); diff --git a/prototypes/quic_demo/src/bin/quic_demo_relay_server.rs b/prototypes/quic_demo/src/bin/quic_demo_relay_server.rs index 62be5d3..1fa0411 100644 --- a/prototypes/quic_demo/src/bin/quic_demo_relay_server.rs +++ b/prototypes/quic_demo/src/bin/quic_demo_relay_server.rs @@ -158,7 +158,7 @@ async fn handle_quic_connection ( let (mut send, mut recv) = conn.bi_streams.next ().await.ok_or_else (|| anyhow::anyhow! ("QUIC client didn't identify itself"))??; - let mut req_buf = [0u8; 4]; + let mut req_buf = [0, 0, 0, 0]; recv.read_exact (&mut req_buf).await?; let peer_type = req_buf [0]; @@ -170,7 +170,12 @@ async fn handle_quic_connection ( _ => bail! ("Unknown QUIC client type"), } - let resp_buf = [20u8, 0, 0, 0]; + let resp_buf = [ + Command::OKAY.0, + peer_type, + 0, + 0, + ]; send.write_all (&resp_buf).await?; match peer_type { @@ -205,12 +210,12 @@ async fn handle_p2_connection ( tokio::spawn (async move { debug! ("Request started for P2"); - let mut req_buf = [0u8; 4]; + let mut req_buf = [0, 0, 0, 0]; client_recv.read_exact (&mut req_buf).await?; let cmd_type = req_buf [0]; - match cmd_type { - 1 => { + match Command (cmd_type) { + Command::CONNECT_P2_TO_P4 => { let server_id = req_buf [1]; handle_request_p2_to_p4 (relay_state, client_id, server_id, client_send, client_recv).await?; }, @@ -239,7 +244,12 @@ async fn handle_request_p2_to_p4 ( // TODO: Auth checks - let resp_buf = [20, 0, 0, 0]; + let resp_buf = [ + Command::OKAY.0, + Command::CONNECT_P2_TO_P4.0, + 0, + 0, + ]; client_send.write_all (&resp_buf).await?; { @@ -294,16 +304,22 @@ async fn handle_p4_connection ( let (mut server_send, mut server_recv) = connection.open_bi ().await?; - let req_buf = [2u8, client_id, 0, 0]; + let req_buf = [ + Command::CONNECT_P2_TO_P4_STEP_2.0, + client_id, + 0, + 0, + ]; server_send.write_all (&req_buf).await?; - let mut resp_buf = [0u8, 0, 0, 0]; + let mut resp_buf = [0, 0, 0, 0]; server_recv.read_exact (&mut resp_buf).await?; - - let status_code = resp_buf [0]; - if status_code != 20 { - bail! ("P4 rejected request from {}", client_id); - } + assert_eq! (resp_buf, [ + Command::OKAY.0, + Command::CONNECT_P2_TO_P4_STEP_2.0, + 0, + 0, + ]); trace! ("Relaying bytes..."); diff --git a/prototypes/quic_demo/src/prelude.rs b/prototypes/quic_demo/src/prelude.rs index d09500a..f8b3dda 100644 --- a/prototypes/quic_demo/src/prelude.rs +++ b/prototypes/quic_demo/src/prelude.rs @@ -32,3 +32,15 @@ pub use tracing::{ }; pub use crate::quinn_utils::*; + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Command (pub u8); + +impl Command { + pub const CONNECT_P2_TO_P3: Command = Command (2); + pub const CONNECT_P4_TO_P3: Command = Command (4); + pub const CONNECT_P2_TO_P4: Command = Command (10); + pub const CONNECT_P2_TO_P4_STEP_2: Command = Command (11); + pub const CONNECT_P2_TO_P5: Command = Command (12); + pub const OKAY: Command = Command (20); +}