♻️ 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".
|
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
|
Requests look like this:
|
||||||
itself with a 4-byte request. The bytes are:
|
|
||||||
|
|
||||||
1. Client type
|
1. Command type
|
||||||
2. Client ID
|
2. Extra data, or unused, depending on command type
|
||||||
3. Unused
|
3. Unused
|
||||||
4. Unused
|
4. Unused
|
||||||
|
|
||||||
The type is "2" or "4" to identify the client as a P2 or a P4. The IDs are
|
Responses look like this:
|
||||||
hard-coded as "42" and "43" for now.
|
|
||||||
|
|
||||||
P3 responds with these 4 bytes:
|
1. Status code (Always "20" for now, meaning "OK")
|
||||||
|
2. Command type of the request that we're responding to
|
||||||
1. Status code
|
|
||||||
2. Unused
|
|
||||||
3. Unused
|
3. Unused
|
||||||
4. Unused
|
4. Unused
|
||||||
|
|
||||||
The status code is always "20" to mean "OK". If authorization or authentication
|
The command types are:
|
||||||
had failed, it would be something else, and P3 would close the connection.
|
|
||||||
|
|
||||||
## PTTH connection
|
| Type | Sender | Receiver | Meaning |
|
||||||
|
| ---- | ------ | ----------- | ------------------------------------------------- |
|
||||||
When P1 connects to P2's TCP listener, P2 opens a bi stream to P3 and sends
|
| 2 | P2 | P3 | Client proxy wants to connect to the relay |
|
||||||
this request:
|
| 4 | P4 | P3 | Server proxy wants to connect to the relay |
|
||||||
|
| 10 | P2 | P3 | Client wants relay to connect it to a server |
|
||||||
1. "1" to mean "Open a PTTH connection"
|
| 11 | P3 | P4 | Relay tells server that a client wants to connect |
|
||||||
2. Server ID, hard-coded as "43" for the only P4 server instance we have
|
| 12 | P2 | P4 (via P3) | Client wants a port forwarded from the server |
|
||||||
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.
|
|
||||||
|
|
||||||
# Plan
|
# Plan
|
||||||
|
|
||||||
|
|
|
@ -21,11 +21,24 @@ async fn main () -> anyhow::Result <()> {
|
||||||
|
|
||||||
let (mut send, mut recv) = connection.open_bi ().await?;
|
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?;
|
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?;
|
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?;
|
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
|
// 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?;
|
relay_send.write_all (&req_buf).await?;
|
||||||
|
|
||||||
let mut resp_buf = [0; 4];
|
let mut resp_buf = [0; 4];
|
||||||
relay_recv.read_exact (&mut resp_buf).await?;
|
relay_recv.read_exact (&mut resp_buf).await?;
|
||||||
|
assert_eq! (resp_buf, [
|
||||||
debug! ("Status code from P3: {}", resp_buf [0]);
|
Command::OKAY.0,
|
||||||
|
Command::CONNECT_P2_TO_P4.0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
]);
|
||||||
|
|
||||||
// Ask P4 if we can connect to P5
|
// 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?;
|
relay_send.write_all (&req_buf).await?;
|
||||||
|
|
||||||
let mut resp_buf = [0; 4];
|
let mut resp_buf = [0; 4];
|
||||||
relay_recv.read_exact (&mut resp_buf).await?;
|
relay_recv.read_exact (&mut resp_buf).await?;
|
||||||
|
assert_eq! (resp_buf, [
|
||||||
debug! ("Status code from P4: {}", resp_buf [0]);
|
Command::OKAY.0,
|
||||||
|
Command::CONNECT_P2_TO_P5.0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
]);
|
||||||
|
|
||||||
trace! ("Relaying bytes...");
|
trace! ("Relaying bytes...");
|
||||||
|
|
||||||
|
@ -116,7 +148,7 @@ impl PtthNewConnection {
|
||||||
relay_send.write_all (buf_slice).await?;
|
relay_send.write_all (buf_slice).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug! ("Uplink closed");
|
trace! ("Uplink closed");
|
||||||
|
|
||||||
Ok::<_, anyhow::Error> (())
|
Ok::<_, anyhow::Error> (())
|
||||||
});
|
});
|
||||||
|
@ -131,7 +163,7 @@ impl PtthNewConnection {
|
||||||
local_send.write_all (buf_slice).await?;
|
local_send.write_all (buf_slice).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug! ("Downlink closed");
|
trace! ("Downlink closed");
|
||||||
|
|
||||||
Ok::<_, anyhow::Error> (())
|
Ok::<_, anyhow::Error> (())
|
||||||
});
|
});
|
||||||
|
|
|
@ -20,11 +20,23 @@ async fn main () -> anyhow::Result <()> {
|
||||||
|
|
||||||
let (mut send, mut recv) = connection.open_bi ().await?;
|
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?;
|
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?;
|
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");
|
trace! ("Accepting bi streams from P3");
|
||||||
|
|
||||||
|
@ -34,18 +46,37 @@ async fn main () -> anyhow::Result <()> {
|
||||||
tokio::spawn (async move {
|
tokio::spawn (async move {
|
||||||
let mut req_buf = [0, 0, 0, 0];
|
let mut req_buf = [0, 0, 0, 0];
|
||||||
relay_recv.read_exact (&mut req_buf).await?;
|
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");
|
debug! ("Started PTTH connection");
|
||||||
|
|
||||||
let stream = TcpStream::connect ("127.0.0.1:30382").await?;
|
let stream = TcpStream::connect ("127.0.0.1:30382").await?;
|
||||||
let (local_recv, local_send) = stream.into_split ();
|
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...");
|
trace! ("Relaying bytes...");
|
||||||
|
|
||||||
let ptth_conn = PtthNewConnection {
|
let ptth_conn = PtthNewConnection {
|
||||||
|
@ -94,7 +125,7 @@ impl PtthNewConnection {
|
||||||
local_send.write_all (buf_slice).await?;
|
local_send.write_all (buf_slice).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug! ("Downlink closed");
|
trace! ("Downlink closed");
|
||||||
|
|
||||||
Ok::<_, anyhow::Error> (())
|
Ok::<_, anyhow::Error> (())
|
||||||
});
|
});
|
||||||
|
@ -113,7 +144,7 @@ impl PtthNewConnection {
|
||||||
relay_send.write_all (buf_slice).await?;
|
relay_send.write_all (buf_slice).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug! ("Uplink closed");
|
trace! ("Uplink closed");
|
||||||
|
|
||||||
Ok::<_, anyhow::Error> (())
|
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 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?;
|
recv.read_exact (&mut req_buf).await?;
|
||||||
|
|
||||||
let peer_type = req_buf [0];
|
let peer_type = req_buf [0];
|
||||||
|
@ -170,7 +170,12 @@ async fn handle_quic_connection (
|
||||||
_ => bail! ("Unknown QUIC client type"),
|
_ => 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?;
|
send.write_all (&resp_buf).await?;
|
||||||
|
|
||||||
match peer_type {
|
match peer_type {
|
||||||
|
@ -205,12 +210,12 @@ async fn handle_p2_connection (
|
||||||
tokio::spawn (async move {
|
tokio::spawn (async move {
|
||||||
debug! ("Request started for P2");
|
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?;
|
client_recv.read_exact (&mut req_buf).await?;
|
||||||
|
|
||||||
let cmd_type = req_buf [0];
|
let cmd_type = req_buf [0];
|
||||||
match cmd_type {
|
match Command (cmd_type) {
|
||||||
1 => {
|
Command::CONNECT_P2_TO_P4 => {
|
||||||
let server_id = req_buf [1];
|
let server_id = req_buf [1];
|
||||||
handle_request_p2_to_p4 (relay_state, client_id, server_id, client_send, client_recv).await?;
|
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
|
// 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?;
|
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 (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?;
|
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?;
|
server_recv.read_exact (&mut resp_buf).await?;
|
||||||
|
assert_eq! (resp_buf, [
|
||||||
let status_code = resp_buf [0];
|
Command::OKAY.0,
|
||||||
if status_code != 20 {
|
Command::CONNECT_P2_TO_P4_STEP_2.0,
|
||||||
bail! ("P4 rejected request from {}", client_id);
|
0,
|
||||||
}
|
0,
|
||||||
|
]);
|
||||||
|
|
||||||
trace! ("Relaying bytes...");
|
trace! ("Relaying bytes...");
|
||||||
|
|
||||||
|
|
|
@ -32,3 +32,15 @@ pub use tracing::{
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use crate::quinn_utils::*;
|
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