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 std::net::SocketAddr;
|
||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
use x25519_dalek::{EphemeralSecret, PublicKey};
|
use x25519_dalek::{EphemeralSecret, PublicKey};
|
||||||
use crate::cryptography::HASH;
|
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
|
/// The main tunnel state machine container
|
||||||
pub struct SPTunnel {
|
pub struct SPTunnel {
|
||||||
relay: SocketAddr,
|
|
||||||
channel_name: String,
|
|
||||||
pmk: [u8; 32],
|
pmk: [u8; 32],
|
||||||
cid: [u8; 32],
|
cid: [u8; 32],
|
||||||
|
|
||||||
|
@ -14,10 +94,13 @@ pub struct SPTunnel {
|
||||||
ee: PublicKey,
|
ee: PublicKey,
|
||||||
eer: PublicKey,
|
eer: PublicKey,
|
||||||
|
|
||||||
state: SPTunnelState
|
state: SPTunnelState,
|
||||||
|
|
||||||
|
we_are_initializer: bool
|
||||||
}
|
}
|
||||||
impl SPTunnel {
|
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)
|
// calculate the pmk and cid (various hashes of the channel name)
|
||||||
let pmk = HASH(&channel_name);
|
let pmk = HASH(&channel_name);
|
||||||
let cid = HASH(&pmk);
|
let cid = HASH(&pmk);
|
||||||
|
@ -27,18 +110,66 @@ impl SPTunnel {
|
||||||
let ee = PublicKey::from(&e);
|
let ee = PublicKey::from(&e);
|
||||||
|
|
||||||
SPTunnel {
|
SPTunnel {
|
||||||
relay,
|
|
||||||
channel_name,
|
|
||||||
pmk,
|
pmk,
|
||||||
cid,
|
cid,
|
||||||
e,
|
e,
|
||||||
ee,
|
ee,
|
||||||
|
we_are_initializer: false,
|
||||||
eer: PublicKey::from([0u8; 32]),
|
eer: PublicKey::from([0u8; 32]),
|
||||||
state: SPTunnelState::NotConnected,
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum SPTunnelState {
|
// regenerate eph keys
|
||||||
NotConnected
|
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
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue