📝 document the fixed-length control protocol that I need to replace soon

main
_ 2021-07-17 22:27:05 +00:00
parent 26135471cb
commit d3675473ed
3 changed files with 87 additions and 3 deletions

View File

@ -22,6 +22,76 @@ The end-to-end testing above is the happy path. Try these sadder cases:
- After Step 2, restart the relay server P3 - After Step 2, restart the relay server P3
- After Step 3, restart the relay server P3 - After Step 3, restart the relay server P3
# Network protocol
For the prototype, all control messages are fixed 4-byte messages at the
start of bidirectional streams.
Unused bytes are always "0".
## QUIC client connection
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:
1. Client type
2. Client ID
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.
P3 responds with these 4 bytes:
1. Status code
2. Unused
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.
## 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.
# Plan # Plan
This is a TCP port forwarding system, like SSH has, but better. This is a TCP port forwarding system, like SSH has, but better.

View File

@ -42,12 +42,26 @@ async fn main () -> anyhow::Result <()> {
let (mut relay_send, mut relay_recv) = connection.open_bi ().await?; let (mut relay_send, mut relay_recv) = connection.open_bi ().await?;
let req_buf = [1, 43, 0, 0, 1, 0, 0, 0]; // Ask P3 if we can connect to P4
let req_buf = [1, 43, 0, 0];
relay_send.write_all (&req_buf).await?; relay_send.write_all (&req_buf).await?;
let mut resp_buf = [0; 8]; let mut resp_buf = [0; 4];
relay_recv.read_exact (&mut resp_buf).await?; relay_recv.read_exact (&mut resp_buf).await?;
debug! ("Status code from P3: {}", resp_buf [0]);
// Ask P4 if we can connect to P5
let req_buf = [1, 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]);
trace! ("Relaying bytes..."); trace! ("Relaying bytes...");
let ptth_conn = PtthNewConnection { let ptth_conn = PtthNewConnection {

View File

@ -239,7 +239,7 @@ async fn handle_request_p2_to_p4 (
// TODO: Auth checks // TODO: Auth checks
let resp_buf = [0, 0, 0, 0]; let resp_buf = [20, 0, 0, 0];
client_send.write_all (&resp_buf).await?; client_send.write_all (&resp_buf).await?;
{ {