♻️ refactor: change up the protocol so that everything has a distinct 4-byte message
parent
d3675473ed
commit
57091ddaab
|
@ -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
|
||||
|
||||
|
|
|
@ -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> (())
|
||||
});
|
||||
|
|
|
@ -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> (())
|
||||
});
|
||||
|
|
|
@ -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...");
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue