work on packet processing

This commit is contained in:
c0repwn3r 2023-01-28 15:04:39 -05:00
parent b769fa69ea
commit 8ba56fb712
Signed by: core
GPG Key ID: FDBF740DADDCEECF
1 changed files with 140 additions and 9 deletions

View File

@ -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
}