work on packet processing
This commit is contained in:
parent
b769fa69ea
commit
8ba56fb712
|
@ -1,12 +1,92 @@
|
|||
use std::error::Error;
|
||||
use std::net::SocketAddr;
|
||||
use rand::rngs::OsRng;
|
||||
use x25519_dalek::{EphemeralSecret, PublicKey};
|
||||
use crate::cryptography::HASH;
|
||||
use crate::packets::clientbound::{ChannelInUsePacket, ChannelNotReadyPacket, ChannelReadyPacket};
|
||||
use crate::packets::initbound::HandshakeStartPacket;
|
||||
use crate::packets::recvbound::{EncryptedDataPacket, HandshakeResponsePacket};
|
||||
use crate::packets::relaybound::RelayDataPacket;
|
||||
use crate::packets::SRTPacket;
|
||||
|
||||
// so we should have a method to handle each of the different types of packets
|
||||
|
||||
// lets plan out the state machine?
|
||||
|
||||
// State = NotConnected
|
||||
// ... => Ignore // we should not be receiving packets if we are not connected to the relay
|
||||
// <connect to relay> => State = Connected
|
||||
|
||||
// State = Connected
|
||||
// ... => Ignore // even if we are connected to the relay, we havent sent init yet so shouldnt be recv anything
|
||||
// <send ChannelWait> => State = SentChannelWait
|
||||
|
||||
// State = SentChannelWait
|
||||
// ChannelReady(init) => State = TunnelSendInit
|
||||
// ChannelReady(recv) => State = TunnelWaitForInit
|
||||
// ChannelNotReady => Wait for ChannelReady
|
||||
// ... => Ignore
|
||||
|
||||
// State = TunnelSentInit
|
||||
// ChannelNotReady => State = Connected // receiving a ChannelNotReady while a tunnel is active indicates the other side disconnected
|
||||
// ... => Ignore
|
||||
// <send HandshakeStart> => State = TunnelWaitForResp
|
||||
|
||||
// State = TunnelWaitForInit
|
||||
// HandshakeStart => State = TunnelSendHandshakeResponse
|
||||
// ChannelNotReady => State = Connected
|
||||
// ... => Ignore
|
||||
|
||||
// State = TunnelWaitForResp
|
||||
// HandshakeResponse => State = Active
|
||||
// ChannelNotReady => State = Connected
|
||||
// ... => Ignore
|
||||
|
||||
// State => TunnelSendHandshakeResponse
|
||||
// ChannelNotReady => State = Connected
|
||||
// ... => Ignore
|
||||
// <send HandshakeResponse> => State = Active
|
||||
|
||||
// State => Active
|
||||
// EncryptedData => <process>
|
||||
// ChannelNotReady => State = Connected
|
||||
// ... => Ignore
|
||||
|
||||
// something like this?
|
||||
// i think this covers every possible situation that the system could be in
|
||||
// i cannot think of others so good enough
|
||||
pub enum SPTunnelState {
|
||||
TunnelNeedToSendChannelWait,
|
||||
TunnelInUse,
|
||||
TunnelSentChannelWaitWaitingForPartner,
|
||||
|
||||
TunnelNeedToSendInit,
|
||||
TunnelSentInit,
|
||||
TunnelWaitForResp,
|
||||
|
||||
TunnelWaitForInit,
|
||||
TunnelNeedToSendHandshakeResponse,
|
||||
TunnelSentHandshakeResponse,
|
||||
|
||||
Active
|
||||
}
|
||||
|
||||
// keeping this for reference
|
||||
|
||||
// so i guess we should go through each of these and make a function that implements that logic
|
||||
// we should make a function to handle every packet type we could receive, and then match the current state to figure out what to do
|
||||
// (arbitrary decision) match type then handle based on state, or check state then analyse packet?
|
||||
|
||||
// like, say the recv loop parses a RelayData packet
|
||||
// it would then call .recv_relay_data() on the SPTunnel, which will decide what to do with that packet based on the current internal state of the tunnel
|
||||
// ok, so check pkt type first
|
||||
// then we need one big switch-case
|
||||
// each packet type gets its own function; parsing it from bytes into the struct form is done in the receive loop
|
||||
// so we should make .recv_relay_data(), .recv_encrypted_data(), etc
|
||||
// right
|
||||
|
||||
/// The main tunnel state machine container
|
||||
pub struct SPTunnel {
|
||||
relay: SocketAddr,
|
||||
channel_name: String,
|
||||
pmk: [u8; 32],
|
||||
cid: [u8; 32],
|
||||
|
||||
|
@ -14,10 +94,13 @@ pub struct SPTunnel {
|
|||
ee: PublicKey,
|
||||
eer: PublicKey,
|
||||
|
||||
state: SPTunnelState
|
||||
state: SPTunnelState,
|
||||
|
||||
we_are_initializer: bool
|
||||
}
|
||||
impl SPTunnel {
|
||||
fn new(relay: SocketAddr, channel_name: String) -> Self {
|
||||
fn new(channel_name: String) -> Self {
|
||||
let state = SPTunnelState::TunnelNeedToSendChannelWait;
|
||||
// calculate the pmk and cid (various hashes of the channel name)
|
||||
let pmk = HASH(&channel_name);
|
||||
let cid = HASH(&pmk);
|
||||
|
@ -27,18 +110,66 @@ impl SPTunnel {
|
|||
let ee = PublicKey::from(&e);
|
||||
|
||||
SPTunnel {
|
||||
relay,
|
||||
channel_name,
|
||||
pmk,
|
||||
cid,
|
||||
e,
|
||||
ee,
|
||||
we_are_initializer: false,
|
||||
eer: PublicKey::from([0u8; 32]),
|
||||
state: SPTunnelState::NotConnected,
|
||||
}
|
||||
}
|
||||
|
||||
/** FROM-RELAY Packets (us <- relay) **/
|
||||
fn recv_channel_not_ready(&mut self, pkt: &ChannelNotReadyPacket) {
|
||||
if pkt.channel != self.cid {
|
||||
return; // ignore this packet, it isnt for us
|
||||
}
|
||||
|
||||
// regenerate eph keys
|
||||
self.e = EphemeralSecret::new(OsRng);
|
||||
self.ee = PublicKey::from(&self.e);
|
||||
|
||||
self.state = SPTunnelState::TunnelSentChannelWaitWaitingForPartner;
|
||||
}
|
||||
fn recv_channel_ready(&mut self, pkt: &ChannelReadyPacket) {
|
||||
if pkt.channel != self.cid {
|
||||
return; // ignore this packet, it isnt for us
|
||||
}
|
||||
if pkt.you_are_initializer {
|
||||
self.we_are_initializer = true;
|
||||
self.state = SPTunnelState::TunnelNeedToSendInit;
|
||||
} else {
|
||||
self.we_are_initializer = false;
|
||||
self.state = SPTunnelState::TunnelWaitForInit;
|
||||
}
|
||||
}
|
||||
fn recv_channel_in_use(&mut self, pkt: &ChannelInUsePacket) {
|
||||
if pkt.channel != self.cid {
|
||||
return; // ignore this packet, it isnt for us
|
||||
}
|
||||
// we cant use this channel right now; set our state to reflect that
|
||||
self.state = SPTunnelState::TunnelInUse;
|
||||
}
|
||||
fn recv_channel_relay_data(&mut self, pkt: &RelayDataPacket) {
|
||||
if pkt.channel != self.cid {
|
||||
return;
|
||||
}
|
||||
// we need to deencapsulate the packet and hand it BACK to the packet parse loop to be sent back to us and parse
|
||||
|
||||
}
|
||||
|
||||
/** VIA-RELAY Packets (us <--relay--< them) **/
|
||||
fn recv_handshake_start(&mut self, pkt: &HandshakeStartPacket) {
|
||||
}
|
||||
fn recv_handshake_response(&mut self, pkt: &HandshakeResponsePacket) {
|
||||
}
|
||||
fn recv_encrypted_data(&mut self, pkt: &EncryptedDataPacket) {
|
||||
}
|
||||
|
||||
// State = Connected
|
||||
// ... => Ignore // even if we are connected to the relay, we havent sent init yet so shouldnt be recv anything
|
||||
// <send ChannelWait> => State = SentChannelWait
|
||||
|
||||
}
|
||||
|
||||
pub enum SPTunnelState {
|
||||
NotConnected
|
||||
}
|
Loading…
Reference in New Issue