refactor
This commit is contained in:
parent
a4ccc96ed0
commit
aab4414904
71 changed files with 293 additions and 4316 deletions
18
prudpv1/src/executables/common.rs
Normal file
18
prudpv1/src/executables/common.rs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
use std::env;
|
||||
use std::net::SocketAddrV4;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
pub static EDGE_NODE_HOLDER: Lazy<SocketAddrV4> = Lazy::new(||{
|
||||
env::var("EDGE_NODE_HOLDER")
|
||||
.ok()
|
||||
.and_then(|s| s.parse().ok())
|
||||
.expect("EDGE_NODE_HOLDER not set")
|
||||
});
|
||||
|
||||
pub static FORWARD_DESTINATION: Lazy<SocketAddrV4> =
|
||||
Lazy::new(||
|
||||
env::var("FORWARD_DESTINATION")
|
||||
.ok()
|
||||
.and_then(|s| s.parse().ok())
|
||||
.expect("FORWARD_DESTINATION not set")
|
||||
);
|
||||
1
prudpv1/src/executables/mod.rs
Normal file
1
prudpv1/src/executables/mod.rs
Normal file
|
|
@ -0,0 +1 @@
|
|||
pub mod common;
|
||||
113
prudpv1/src/executables/proxy_insecure.rs
Normal file
113
prudpv1/src/executables/proxy_insecure.rs
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
|
||||
use rnex_core::reggie::UnitPacketRead;
|
||||
use rnex_core::reggie::UnitPacketWrite;
|
||||
use rnex_core::rmc::structures::RmcSerialize;
|
||||
use std::env;
|
||||
use std::ffi::CStr;
|
||||
use std::io::{Read, Write};
|
||||
use std::net::{Ipv4Addr, SocketAddrV4};
|
||||
use std::sync::{Arc, OnceLock};
|
||||
use std::time::Duration;
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use log::{error, warn};
|
||||
use once_cell::sync::Lazy;
|
||||
use tokio::net::{TcpSocket, TcpStream};
|
||||
use tokio::sync::RwLock;
|
||||
use tokio::task;
|
||||
use tokio::time::sleep;
|
||||
use prudpv1::executables::common::{FORWARD_DESTINATION, EDGE_NODE_HOLDER};
|
||||
use prudpv1::prudp::router::Router;
|
||||
use prudpv1::prudp::unsecure::Unsecure;
|
||||
use rnex_core::common::setup;
|
||||
use rnex_core::executables::common::{OWN_IP_PRIVATE, OWN_IP_PUBLIC, SERVER_PORT};
|
||||
use rnex_core::prudp::virtual_port::VirtualPort;
|
||||
use rnex_core::reggie::EdgeNodeHolderConnectOption::Register;
|
||||
use rnex_core::reggie::RemoteEdgeNodeHolder;
|
||||
use rnex_core::rmc::protocols::{new_rmc_gateway_connection, OnlyRemote};
|
||||
use rnex_core::rnex_proxy_common::ConnectionInitData;
|
||||
use rnex_core::util::SplittableBufferConnection;
|
||||
|
||||
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
setup();
|
||||
|
||||
let conn = tokio::net::TcpStream::connect(&*EDGE_NODE_HOLDER).await.unwrap();
|
||||
|
||||
let conn: SplittableBufferConnection = conn.into();
|
||||
|
||||
conn.send(Register(SocketAddrV4::new(*OWN_IP_PUBLIC, *SERVER_PORT)).to_data()).await;
|
||||
|
||||
let conn = new_rmc_gateway_connection(conn, |r| Arc::new(OnlyRemote::<RemoteEdgeNodeHolder>::new(r)));
|
||||
|
||||
let (router_secure, _) = Router::new(SocketAddrV4::new(*OWN_IP_PRIVATE, *SERVER_PORT))
|
||||
.await
|
||||
.expect("unable to start router");
|
||||
|
||||
let mut socket_secure = router_secure
|
||||
.add_socket(VirtualPort::new(1, 10), Unsecure(
|
||||
"6f599f81"
|
||||
))
|
||||
.await
|
||||
.expect("unable to add socket");
|
||||
|
||||
// let conn = socket_secure.connect(auth_sockaddr).await.unwrap();
|
||||
|
||||
loop {
|
||||
let Some(mut conn) = socket_secure.accept().await else {
|
||||
error!("server crashed");
|
||||
return;
|
||||
};
|
||||
|
||||
task::spawn(async move {
|
||||
let mut stream
|
||||
= match TcpStream::connect(*FORWARD_DESTINATION).await {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
error!("unable to connect: {}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(e) = stream.send_buffer(&ConnectionInitData{
|
||||
prudpsock_addr: conn.socket_addr,
|
||||
pid: conn.user_id
|
||||
}.to_data()).await{
|
||||
error!("error connecting to backend: {}", e);
|
||||
return;
|
||||
};
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
data = conn.recv() => {
|
||||
let Some(data) = data else {
|
||||
break;
|
||||
};
|
||||
|
||||
if let Err(e) = stream.send_buffer(&data[..]).await{
|
||||
error!("error sending data to backend: {}", e);
|
||||
break;
|
||||
}
|
||||
},
|
||||
data = stream.read_buffer() => {
|
||||
let data = match data{
|
||||
Ok(d) => d,
|
||||
Err(e) => {
|
||||
error!("error reveiving data from backend: {}", e);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
if conn.send(data).await == None{
|
||||
return;
|
||||
}
|
||||
},
|
||||
_ = sleep(Duration::from_secs(10)) => {
|
||||
conn.send([0,0,0,0,0].to_vec()).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
116
prudpv1/src/executables/proxy_secure.rs
Normal file
116
prudpv1/src/executables/proxy_secure.rs
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
use rnex_core::reggie::UnitPacketRead;
|
||||
use rnex_core::reggie::UnitPacketWrite;
|
||||
use rnex_core::rmc::structures::RmcSerialize;
|
||||
use std::env;
|
||||
use std::ffi::CStr;
|
||||
use std::io::{Read, Write};
|
||||
use std::net::{Ipv4Addr, SocketAddrV4};
|
||||
use std::sync::{Arc, OnceLock};
|
||||
use std::time::Duration;
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use log::{error, warn};
|
||||
use once_cell::sync::Lazy;
|
||||
use tokio::net::{TcpSocket, TcpStream};
|
||||
use tokio::sync::RwLock;
|
||||
use tokio::task;
|
||||
use tokio::time::sleep;
|
||||
use prudpv1::executables::common::{FORWARD_DESTINATION, EDGE_NODE_HOLDER};
|
||||
use prudpv1::prudp::router::Router;
|
||||
use prudpv1::prudp::secure::Secure;
|
||||
use prudpv1::prudp::unsecure::Unsecure;
|
||||
use rnex_core::common::setup;
|
||||
use rnex_core::executables::common::{OWN_IP_PRIVATE, OWN_IP_PUBLIC, SECURE_SERVER_ACCOUNT, SERVER_PORT};
|
||||
use rnex_core::prudp::virtual_port::VirtualPort;
|
||||
use rnex_core::reggie::EdgeNodeHolderConnectOption::Register;
|
||||
use rnex_core::reggie::RemoteEdgeNodeHolder;
|
||||
use rnex_core::rmc::protocols::{new_rmc_gateway_connection, OnlyRemote};
|
||||
use rnex_core::rnex_proxy_common::ConnectionInitData;
|
||||
use rnex_core::util::SplittableBufferConnection;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
setup();
|
||||
|
||||
let conn = tokio::net::TcpStream::connect(&*EDGE_NODE_HOLDER).await.unwrap();
|
||||
|
||||
let conn: SplittableBufferConnection = conn.into();
|
||||
|
||||
conn.send(Register(SocketAddrV4::new(*OWN_IP_PUBLIC, *SERVER_PORT)).to_data()).await;
|
||||
|
||||
let conn = new_rmc_gateway_connection(conn, |r| Arc::new(OnlyRemote::<RemoteEdgeNodeHolder>::new(r)));
|
||||
|
||||
|
||||
|
||||
let (router_secure, _) = Router::new(SocketAddrV4::new(*OWN_IP_PRIVATE, *SERVER_PORT))
|
||||
.await
|
||||
.expect("unable to start router");
|
||||
|
||||
let mut socket_secure = router_secure
|
||||
.add_socket(VirtualPort::new(1, 10), Secure(
|
||||
"6f599f81",
|
||||
SECURE_SERVER_ACCOUNT.clone()
|
||||
))
|
||||
.await
|
||||
.expect("unable to add socket");
|
||||
|
||||
// let conn = socket_secure.connect(auth_sockaddr).await.unwrap();
|
||||
|
||||
loop {
|
||||
let Some(mut conn) = socket_secure.accept().await else {
|
||||
error!("server crashed");
|
||||
return;
|
||||
};
|
||||
|
||||
task::spawn(async move {
|
||||
let mut stream
|
||||
= match TcpStream::connect(*FORWARD_DESTINATION).await {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
error!("unable to connect: {}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(e) = stream.send_buffer(&ConnectionInitData{
|
||||
prudpsock_addr: conn.socket_addr,
|
||||
pid: conn.user_id
|
||||
}.to_data()).await{
|
||||
error!("error connecting to backend: {}", e);
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
data = conn.recv() => {
|
||||
let Some(data) = data else {
|
||||
break;
|
||||
};
|
||||
|
||||
if let Err(e) = stream.send_buffer(&data[..]).await{
|
||||
error!("error sending data to backend: {}", e);
|
||||
break;
|
||||
}
|
||||
},
|
||||
data = stream.read_buffer() => {
|
||||
let data = match data{
|
||||
Ok(d) => d,
|
||||
Err(e) => {
|
||||
error!("error reveiving data from backend: {}", e);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
if conn.send(data).await == None{
|
||||
return;
|
||||
}
|
||||
},
|
||||
_ = sleep(Duration::from_secs(10)) => {
|
||||
conn.send([0,0,0,0,0].to_vec()).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
13
prudpv1/src/prudp/auth_module.rs
Normal file
13
prudpv1/src/prudp/auth_module.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
use std::net::Ipv4Addr;
|
||||
|
||||
pub trait AuthModule{
|
||||
fn get_auth_key(addr: Ipv4Addr) -> [u8; 32];
|
||||
}
|
||||
/*
|
||||
struct AuthServerAuthModule;
|
||||
|
||||
impl AuthModule for AuthServerAuthModule{
|
||||
fn get_auth_key(addr: Ipv4Addr) -> rc4 {
|
||||
|
||||
}
|
||||
}*/
|
||||
6
prudpv1/src/prudp/mod.rs
Normal file
6
prudpv1/src/prudp/mod.rs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
pub mod packet;
|
||||
pub mod router;
|
||||
pub mod socket;
|
||||
mod auth_module;
|
||||
pub mod secure;
|
||||
pub mod unsecure;
|
||||
500
prudpv1/src/prudp/packet.rs
Normal file
500
prudpv1/src/prudp/packet.rs
Normal file
|
|
@ -0,0 +1,500 @@
|
|||
// no clue why this produces a warning where `#[repr(u16)]` is below,
|
||||
// the thing is says to do also breaks the code, so we just
|
||||
// force the compiler to shut up here
|
||||
#![allow(unused_parens)]
|
||||
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::io;
|
||||
use std::io::{Cursor, Read, Seek, Write};
|
||||
use std::net::SocketAddrV4;
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use hmac::{Hmac, Mac};
|
||||
use log::{error, warn};
|
||||
use md5::{Md5, Digest};
|
||||
use thiserror::Error;
|
||||
use v_byte_helpers::{SwapEndian};
|
||||
use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions};
|
||||
use crate::prudp::packet::flags::ACK;
|
||||
use crate::prudp::packet::PacketOption::{ConnectionSignature, FragmentId, InitialSequenceId, MaximumSubstreamId, SupportedFunctions};
|
||||
use rnex_core::prudp::socket_addr::PRUDPSockAddr;
|
||||
use rnex_core::prudp::virtual_port::VirtualPort;
|
||||
|
||||
type Md5Hmac = Hmac<Md5>;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("{0}")]
|
||||
IO(#[from] io::Error),
|
||||
#[error("invalid magic {0:#06x}")]
|
||||
InvalidMagic(u16),
|
||||
#[error("invalid version {0}")]
|
||||
InvalidVersion(u8),
|
||||
#[error("invalid option id {0}")]
|
||||
InvalidOptionId(u8),
|
||||
#[error("option size {size} doesnt match expected option for given option id {id}")]
|
||||
InvalidOptionSize {
|
||||
id: u8,
|
||||
size: u8,
|
||||
},
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Copy, Clone, Pod, Zeroable, SwapEndian, Default, Eq, PartialEq)]
|
||||
pub struct TypesFlags(u16);
|
||||
|
||||
impl TypesFlags {
|
||||
#[inline]
|
||||
pub const fn get_types(self) -> u8 {
|
||||
(self.0 & 0x000F) as u8
|
||||
}
|
||||
#[inline]
|
||||
pub const fn get_flags(self) -> u16 {
|
||||
(self.0 & 0xFFF0) >> 4
|
||||
}
|
||||
#[inline]
|
||||
pub const fn types(self, val: u8) -> Self {
|
||||
Self((self.0 & 0xFFF0) | (val as u16 & 0x000F))
|
||||
}
|
||||
#[inline]
|
||||
pub const fn flags(self, val: u16) -> Self {
|
||||
Self((self.0 & 0x000F) | ((val << 4) & 0xFFF0))
|
||||
}
|
||||
#[inline]
|
||||
pub const fn set_flag(&mut self, val: u16){
|
||||
self.0 |= (val & 0xFFF) << 4;
|
||||
}
|
||||
#[inline]
|
||||
pub const fn set_types(&mut self, val: u8){
|
||||
self.0 |= val as u16 & 0x0F;
|
||||
}
|
||||
}
|
||||
|
||||
pub mod flags {
|
||||
pub const ACK: u16 = 0x001;
|
||||
pub const RELIABLE: u16 = 0x002;
|
||||
pub const NEED_ACK: u16 = 0x004;
|
||||
pub const HAS_SIZE: u16 = 0x008;
|
||||
pub const MULTI_ACK: u16 = 0x200;
|
||||
}
|
||||
|
||||
pub mod types {
|
||||
pub const SYN: u8 = 0x0;
|
||||
pub const CONNECT: u8 = 0x1;
|
||||
pub const DATA: u8 = 0x2;
|
||||
pub const DISCONNECT: u8 = 0x3;
|
||||
pub const PING: u8 = 0x4;
|
||||
/// no idea what user is supposed to mean
|
||||
pub const USER: u8 = 0x5;
|
||||
}
|
||||
|
||||
impl Debug for TypesFlags {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
let stream_type = self.get_types();
|
||||
let port_number = self.get_flags();
|
||||
write!(f, "TypesFlags{{ types: {}, flags: {} }}", stream_type, port_number)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone, Pod, Zeroable, SwapEndian, Eq, PartialEq)]
|
||||
pub struct PRUDPV1Header {
|
||||
pub magic: [u8; 2],
|
||||
pub version: u8,
|
||||
pub packet_specific_size: u8,
|
||||
pub payload_size: u16,
|
||||
pub source_port: VirtualPort,
|
||||
pub destination_port: VirtualPort,
|
||||
pub types_and_flags: TypesFlags,
|
||||
pub session_id: u8,
|
||||
pub substream_id: u8,
|
||||
pub sequence_id: u16,
|
||||
}
|
||||
|
||||
impl Default for PRUDPV1Header {
|
||||
fn default() -> Self {
|
||||
Self{
|
||||
magic: [0xEA, 0xD0],
|
||||
version: 1,
|
||||
session_id: 0,
|
||||
source_port: VirtualPort(0),
|
||||
sequence_id: 0,
|
||||
payload_size: 0,
|
||||
destination_port: VirtualPort(0),
|
||||
types_and_flags: TypesFlags(0),
|
||||
packet_specific_size: 0,
|
||||
substream_id: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub enum PacketOption{
|
||||
SupportedFunctions(u32),
|
||||
ConnectionSignature([u8; 16]),
|
||||
FragmentId(u8),
|
||||
InitialSequenceId(u16),
|
||||
MaximumSubstreamId(u8)
|
||||
}
|
||||
|
||||
impl PacketOption{
|
||||
fn from(option_id: OptionId, option_data: &[u8]) -> io::Result<Self>{
|
||||
|
||||
let mut data_cursor = Cursor::new(option_data);
|
||||
let val = match option_id.into(){
|
||||
0 => SupportedFunctions(data_cursor.read_struct(IS_BIG_ENDIAN)?),
|
||||
1 => ConnectionSignature(data_cursor.read_struct(IS_BIG_ENDIAN)?),
|
||||
2 => FragmentId(data_cursor.read_struct(IS_BIG_ENDIAN)?),
|
||||
3 => InitialSequenceId(data_cursor.read_struct(IS_BIG_ENDIAN)?),
|
||||
4 => MaximumSubstreamId(data_cursor.read_struct(IS_BIG_ENDIAN)?),
|
||||
_ => unreachable!()
|
||||
};
|
||||
|
||||
Ok(val)
|
||||
}
|
||||
|
||||
fn write_to_stream(&self, stream: &mut impl Write) -> io::Result<()> {
|
||||
match self {
|
||||
SupportedFunctions(v) => {
|
||||
stream.write_all(&[0, size_of_val(v) as u8])?;
|
||||
stream.write_all(&v.to_le_bytes())?;
|
||||
}
|
||||
ConnectionSignature(v) => {
|
||||
stream.write_all(&[1, size_of_val(v) as u8])?;
|
||||
stream.write_all(v)?;
|
||||
}
|
||||
FragmentId(v) => {
|
||||
stream.write_all(&[2, size_of_val(v) as u8])?;
|
||||
stream.write_all(&v.to_le_bytes())?;
|
||||
}
|
||||
InitialSequenceId(v) => {
|
||||
stream.write_all(&[3, size_of_val(v) as u8])?;
|
||||
stream.write_all(&v.to_le_bytes())?;
|
||||
}
|
||||
MaximumSubstreamId(v) => {
|
||||
stream.write_all(&[4, size_of_val(v) as u8])?;
|
||||
stream.write_all(&v.to_le_bytes())?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_size(&self) -> u8 {
|
||||
match self {
|
||||
SupportedFunctions(_) => 2 + 4,
|
||||
ConnectionSignature(_) => 2 + 16,
|
||||
FragmentId(_) => 2 + 1,
|
||||
InitialSequenceId(_) => 2 + 2,
|
||||
MaximumSubstreamId(_) => 2 + 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Eq, PartialEq)]
|
||||
pub struct PRUDPV1Packet {
|
||||
pub header: PRUDPV1Header,
|
||||
pub packet_signature: [u8; 16],
|
||||
pub payload: Vec<u8>,
|
||||
pub options: Vec<PacketOption>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
// Invariant: can only contain 0, 1, 2, 3 or 4
|
||||
struct OptionId(u8);
|
||||
|
||||
impl OptionId {
|
||||
fn new(val: u8) -> Result<Self> {
|
||||
// Invariant is upheld because we only create the object if it doesn't violate the invariant
|
||||
match val {
|
||||
0 | 1 | 2 | 3 | 4 => Ok(Self(val)),
|
||||
_ => Err(Error::InvalidOptionId(val))
|
||||
}
|
||||
}
|
||||
|
||||
fn option_type_size(self) -> u8 {
|
||||
match self.0 {
|
||||
0 => 4,
|
||||
1 => 16,
|
||||
2 => 1,
|
||||
3 => 2,
|
||||
4 => 1,
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<u8> for OptionId {
|
||||
fn into(self) -> u8 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl PRUDPV1Packet {
|
||||
pub fn new(reader: &mut (impl Read + Seek)) -> Result<Self> {
|
||||
let header: PRUDPV1Header = reader.read_struct(IS_BIG_ENDIAN)?;
|
||||
|
||||
if header.magic[0] != 0xEA ||
|
||||
header.magic[1] != 0xD0 {
|
||||
return Err(Error::InvalidMagic(u16::from_be_bytes(header.magic)));
|
||||
}
|
||||
|
||||
if header.version != 1 {
|
||||
return Err(Error::InvalidVersion(header.version));
|
||||
}
|
||||
|
||||
|
||||
let packet_signature: [u8; 16] = reader.read_struct(IS_BIG_ENDIAN)?;
|
||||
//let packet_signature: [u8; 16] = [0; 16];
|
||||
|
||||
assert_eq!(reader.stream_position().ok(), Some(14 + 16));
|
||||
|
||||
|
||||
|
||||
let mut packet_specific_buffer = vec![0u8; header.packet_specific_size as usize];
|
||||
|
||||
reader.read_exact(&mut packet_specific_buffer)?;
|
||||
|
||||
|
||||
//no clue whats up with options but they are broken
|
||||
let mut packet_specific_data_cursor = Cursor::new(&packet_specific_buffer);
|
||||
|
||||
let mut options = Vec::new();
|
||||
|
||||
loop {
|
||||
let Ok(option_id): io::Result<u8> = packet_specific_data_cursor.read_struct(IS_BIG_ENDIAN) else {
|
||||
break
|
||||
};
|
||||
|
||||
let Ok(value_size): io::Result<u8> = packet_specific_data_cursor.read_struct(IS_BIG_ENDIAN) else {
|
||||
break
|
||||
};
|
||||
|
||||
if value_size == 0 {
|
||||
// skip it if its 0 and dont check?
|
||||
warn!("reading packets options might be going wrong");
|
||||
continue;
|
||||
}
|
||||
|
||||
let option_id: OptionId = OptionId::new(option_id)?;
|
||||
|
||||
if option_id.option_type_size() != value_size {
|
||||
error!("invalid packet options");
|
||||
return Err(Error::InvalidOptionSize {
|
||||
size: value_size,
|
||||
id: option_id.0,
|
||||
});
|
||||
}
|
||||
|
||||
let mut option_data = vec![0u8; value_size as usize];
|
||||
if packet_specific_data_cursor.read_exact(&mut option_data[..]).is_err() {
|
||||
error!("unable to read options");
|
||||
break;
|
||||
}
|
||||
|
||||
options.push(PacketOption::from(option_id, &option_data)?);
|
||||
}
|
||||
|
||||
let mut payload = vec![0u8; header.payload_size as usize];
|
||||
|
||||
reader.read_exact(&mut payload)?;
|
||||
|
||||
|
||||
|
||||
Ok(Self {
|
||||
header,
|
||||
packet_signature,
|
||||
payload,
|
||||
options,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn base_acknowledgement_packet(&self) -> Self{
|
||||
let base = self.base_response_packet();
|
||||
|
||||
let mut flags = self.header.types_and_flags.flags(0);
|
||||
|
||||
flags.set_flag(ACK);
|
||||
|
||||
let options = self.options
|
||||
.iter()
|
||||
.filter(|o| matches!(o, FragmentId(_)))
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
|
||||
|
||||
Self{
|
||||
header: PRUDPV1Header {
|
||||
types_and_flags: flags,
|
||||
sequence_id: self.header.sequence_id,
|
||||
substream_id: self.header.substream_id,
|
||||
session_id: self.header.session_id,
|
||||
..base.header
|
||||
},
|
||||
options,
|
||||
..base
|
||||
}
|
||||
}
|
||||
|
||||
pub fn source_sockaddr(&self, socket_addr_v4: SocketAddrV4) -> PRUDPSockAddr {
|
||||
PRUDPSockAddr {
|
||||
regular_socket_addr: socket_addr_v4,
|
||||
virtual_port: self.header.source_port,
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_options_bytes(&self) -> Vec<u8>{
|
||||
let mut vec = Vec::new();
|
||||
|
||||
for option in &self.options{
|
||||
option.write_to_stream(&mut vec).expect("vec should always automatically be able to extend");
|
||||
}
|
||||
|
||||
vec
|
||||
}
|
||||
|
||||
pub fn calculate_signature_value(&self, access_key: &str, session_key: Option<[u8; 32]>, connection_signature: Option<[u8; 16]>) -> [u8; 16]{
|
||||
let access_key_bytes = access_key.as_bytes();
|
||||
let access_key_sum: u32 = access_key_bytes.iter().map(|v| *v as u32).sum();
|
||||
let access_key_sum_bytes: [u8; 4] = access_key_sum.to_le_bytes();
|
||||
|
||||
let header_data: [u8; 8] = bytemuck::bytes_of(&self.header)[0x6..].try_into().unwrap();
|
||||
|
||||
let option_bytes = self.generate_options_bytes();
|
||||
|
||||
let mut md5 = md5::Md5::default();
|
||||
|
||||
md5.update(access_key_bytes);
|
||||
let key = md5.finalize();
|
||||
|
||||
let mut hmac = Md5Hmac::new_from_slice(&key).expect("fuck");
|
||||
|
||||
hmac.write(&header_data).expect("error during hmac calculation");
|
||||
if let Some(session_key) = session_key {
|
||||
hmac.write(&session_key).expect("error during hmac calculation");
|
||||
}
|
||||
hmac.write(&access_key_sum_bytes).expect("error during hmac calculation");
|
||||
if let Some(connection_signature) = connection_signature {
|
||||
hmac.write(&connection_signature).expect("error during hmac calculation");
|
||||
}
|
||||
|
||||
hmac.write(&option_bytes).expect("error during hmac calculation");
|
||||
|
||||
hmac.write_all(&self.payload).expect("error during hmac calculation");
|
||||
|
||||
hmac.finalize().into_bytes()[0..16].try_into().expect("invalid hmac size")
|
||||
}
|
||||
|
||||
pub fn calculate_and_assign_signature(&mut self, access_key: &str, session_key: Option<[u8; 32]>, connection_signature: Option<[u8; 16]>){
|
||||
self.packet_signature = self.calculate_signature_value(access_key, session_key, connection_signature);
|
||||
}
|
||||
|
||||
pub fn set_sizes(&mut self){
|
||||
self.header.packet_specific_size = self.options.iter().map(|o| o.write_size()).sum();
|
||||
self.header.payload_size = self.payload.len() as u16;
|
||||
}
|
||||
|
||||
pub fn base_response_packet(&self) -> Self {
|
||||
Self {
|
||||
header: PRUDPV1Header {
|
||||
magic: [0xEA, 0xD0],
|
||||
types_and_flags: TypesFlags(0),
|
||||
destination_port: self.header.source_port,
|
||||
source_port: self.header.destination_port,
|
||||
payload_size: 0,
|
||||
version: 1,
|
||||
packet_specific_size: 0,
|
||||
sequence_id: 0,
|
||||
session_id: 0,
|
||||
substream_id: 0,
|
||||
|
||||
},
|
||||
packet_signature: [0; 16],
|
||||
payload: Default::default(),
|
||||
options: Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_to(&self, writer: &mut impl Write) -> io::Result<()>{
|
||||
writer.write_all(bytemuck::bytes_of(&self.header))?;
|
||||
writer.write_all(&self.packet_signature)?;
|
||||
|
||||
for option in &self.options{
|
||||
option.write_to_stream(writer)?;
|
||||
}
|
||||
|
||||
writer.write_all(&self.payload)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::prudp::packet::flags::{NEED_ACK, RELIABLE};
|
||||
use crate::prudp::packet::types::DATA;
|
||||
use super::{OptionId, PacketOption, PRUDPV1Header, TypesFlags};
|
||||
use rnex_core::prudp::virtual_port::VirtualPort;
|
||||
#[test]
|
||||
fn size_test() {
|
||||
assert_eq!(size_of::<PRUDPV1Header>(), 14);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_options(){
|
||||
let packet_types = [0,1,2,3,4];
|
||||
|
||||
for p_type in packet_types{
|
||||
let option_id = OptionId::new(p_type).unwrap();
|
||||
|
||||
let buf = vec![0; option_id.option_type_size() as usize];
|
||||
|
||||
let opt = PacketOption::from(option_id, &buf).unwrap();
|
||||
{
|
||||
let mut write_buf = vec![];
|
||||
|
||||
opt.write_to_stream(&mut write_buf).unwrap();
|
||||
|
||||
assert_eq!(write_buf.len() as u8, opt.write_size())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn header_read(){
|
||||
let header = PRUDPV1Header {
|
||||
version: 0,
|
||||
destination_port: VirtualPort(0),
|
||||
substream_id: 0,
|
||||
types_and_flags: TypesFlags(0),
|
||||
session_id: 0,
|
||||
packet_specific_size: 0,
|
||||
payload_size: 0,
|
||||
sequence_id: 0,
|
||||
magic: [0xEA,0xD0],
|
||||
source_port: VirtualPort(0)
|
||||
};
|
||||
|
||||
let bytes = bytemuck::bytes_of(&header);
|
||||
|
||||
let bytes = &bytes[0x6..];
|
||||
|
||||
let header_data: [u8; 8] = bytes.try_into().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_types_flags(){
|
||||
let types = TypesFlags::default().types(DATA).flags(NEED_ACK | RELIABLE);
|
||||
|
||||
assert_ne!((types.0 >> 4) & NEED_ACK, 0);
|
||||
assert_ne!((types.0 >> 4) & RELIABLE, 0);
|
||||
assert_ne!((types.0 & 0xFF) as u8 & DATA, 0);
|
||||
}
|
||||
}
|
||||
185
prudpv1/src/prudp/router.rs
Normal file
185
prudpv1/src/prudp/router.rs
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
use std::{env, io};
|
||||
use std::io::Cursor;
|
||||
use std::marker::PhantomData;
|
||||
use tokio::net::UdpSocket;
|
||||
use std::net::{SocketAddr, SocketAddrV4};
|
||||
use std::net::SocketAddr::V4;
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::sync::atomic::{AtomicBool};
|
||||
use std::time::Duration;
|
||||
use tokio::task::JoinHandle;
|
||||
use once_cell::sync::Lazy;
|
||||
use log::{error, info};
|
||||
use thiserror::Error;
|
||||
use tokio::select;
|
||||
use tokio::sync::RwLock;
|
||||
use tokio::time::sleep;
|
||||
use crate::prudp::socket::{new_socket_pair, AnyInternalSocket, CryptoHandler, ExternalSocket};
|
||||
use crate::prudp::packet::{PRUDPV1Packet};
|
||||
use rnex_core::prudp::virtual_port::VirtualPort;
|
||||
use crate::prudp::router::Error::VirtualPortTaken;
|
||||
|
||||
static SERVER_DATAGRAMS: Lazy<u8> = Lazy::new(||{
|
||||
env::var("SERVER_DATAGRAM_COUNT").ok()
|
||||
.and_then(|s| s.parse().ok())
|
||||
.unwrap_or(1)
|
||||
});
|
||||
|
||||
|
||||
pub struct Router {
|
||||
endpoints: RwLock<[Option<Arc<dyn AnyInternalSocket>>; 16]>,
|
||||
running: AtomicBool,
|
||||
socket: Arc<UdpSocket>,
|
||||
_no_outside_construction: PhantomData<()>
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error{
|
||||
#[error("tried to register socket to a port which is already taken (port: {0})")]
|
||||
VirtualPortTaken(u8)
|
||||
}
|
||||
|
||||
|
||||
impl Router {
|
||||
async fn process_prudp_packets<'a>(self: Arc<Self>, _socket: Arc<UdpSocket>, addr: SocketAddrV4, udp_message: Vec<u8>){
|
||||
let mut stream = Cursor::new(&udp_message);
|
||||
|
||||
while stream.position() as usize != udp_message.len() {
|
||||
let packet = match PRUDPV1Packet::new(&mut stream){
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
error!("Somebody({}) is fucking with the servers or their connection is bad (reason: {})", addr, e);
|
||||
break;
|
||||
},
|
||||
};
|
||||
|
||||
let connection = packet.source_sockaddr(addr);
|
||||
|
||||
|
||||
let endpoints = self.endpoints.read().await;
|
||||
|
||||
let Some(endpoint) = endpoints[packet.header.destination_port.get_port_number() as usize].as_ref() else {
|
||||
error!("connection to invalid endpoint({}) attempted by {}", packet.header.destination_port.get_port_number(), connection.regular_socket_addr);
|
||||
continue;
|
||||
};
|
||||
|
||||
let endpoint = endpoint.clone();
|
||||
|
||||
// Dont keep the locked structure for too long
|
||||
drop(endpoints);
|
||||
|
||||
|
||||
tokio::spawn(async move {
|
||||
endpoint.receive_packet(connection, packet).await
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async fn server_thread_send_entry(this: Weak<Self>, socket: Arc<UdpSocket>){
|
||||
info!("starting datagram thread");
|
||||
|
||||
while let Some(this) = this.upgrade() {
|
||||
// yes we actually allow the max udp to be read lol
|
||||
let mut msg_buffer = vec![0u8; 65507];
|
||||
|
||||
let (len, addr) =
|
||||
select! {
|
||||
r = socket.recv_from(&mut msg_buffer) => {
|
||||
r.expect("Datagram thread crashed due to unexpected error from recv_from")
|
||||
}
|
||||
_ = sleep(Duration::from_secs(5)) => {
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
let V4(addr) = addr else {
|
||||
error!("somehow got ipv6 packet...? ignoring");
|
||||
continue;
|
||||
};
|
||||
|
||||
|
||||
let current_msg = &msg_buffer[0..len];
|
||||
|
||||
tokio::spawn(this.process_prudp_packets(socket.clone(), addr, current_msg.to_vec()));
|
||||
}
|
||||
|
||||
println!("exitting datagram")
|
||||
}
|
||||
|
||||
pub async fn new(addr: SocketAddrV4) -> io::Result<(Arc<Self>, JoinHandle<()>)>{
|
||||
// trace!("starting router on {}", addr);
|
||||
|
||||
let socket = Arc::new(UdpSocket::bind(addr).await?);
|
||||
|
||||
let own_impl = Router {
|
||||
endpoints: Default::default(),
|
||||
running: AtomicBool::new(true),
|
||||
socket: socket.clone(),
|
||||
_no_outside_construction: Default::default()
|
||||
};
|
||||
|
||||
let arc = Arc::new(own_impl);
|
||||
|
||||
|
||||
let task = {
|
||||
let socket = socket.clone();
|
||||
let server= Arc::downgrade(&arc);
|
||||
|
||||
tokio::spawn(async {
|
||||
Self::server_thread_send_entry(server, socket).await;
|
||||
})
|
||||
};
|
||||
|
||||
{
|
||||
let _socket = socket.clone();
|
||||
let _server = arc.clone();
|
||||
|
||||
tokio::spawn(async {
|
||||
//server thread sender entry
|
||||
// todo: make this run in the socket cause that makes more sense
|
||||
//server.server_thread_recieve_entry(socket).await;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Ok((arc, task))
|
||||
}
|
||||
|
||||
pub fn get_udp_socket(&self) -> Arc<UdpSocket>{
|
||||
self.socket.clone()
|
||||
}
|
||||
|
||||
// This will remove a socket from the router, this renders all instances of that socket unable
|
||||
// to recieve any more data making the error out on trying to for example recieve connections
|
||||
pub async fn remove_socket(&self, virtual_port: VirtualPort){
|
||||
self.endpoints.write().await[virtual_port.get_port_number() as usize] = None;
|
||||
}
|
||||
|
||||
// returns Some(()) i
|
||||
pub async fn add_socket<E: CryptoHandler>(&self, virtual_port: VirtualPort, encryption: E)
|
||||
-> Result<ExternalSocket, Error>{
|
||||
let mut endpoints = self.endpoints.write().await;
|
||||
|
||||
let idx = virtual_port.get_port_number() as usize;
|
||||
|
||||
// dont create the socket if we dont need to
|
||||
if !endpoints[idx].is_none(){
|
||||
return Err(VirtualPortTaken(idx as u8));
|
||||
}
|
||||
|
||||
let (internal, external) = new_socket_pair(virtual_port, encryption, self.socket.clone());
|
||||
|
||||
endpoints[idx] = Some(internal);
|
||||
|
||||
Ok(external)
|
||||
}
|
||||
|
||||
pub fn get_own_address(&self) -> SocketAddrV4{
|
||||
match self.socket.local_addr().expect("unable to get socket address"){
|
||||
SocketAddr::V4(v4) => v4,
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
191
prudpv1/src/prudp/secure.rs
Normal file
191
prudpv1/src/prudp/secure.rs
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
use std::io::Cursor;
|
||||
use hmac::digest::consts::U32;
|
||||
use log::error;
|
||||
use rc4::cipher::StreamCipherCoreWrapper;
|
||||
use rc4::{KeyInit, Rc4, Rc4Core, StreamCipher};
|
||||
use rc4::consts::U16;
|
||||
use typenum::U5;
|
||||
use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions};
|
||||
use rnex_core::kerberos::{derive_key, TicketInternalData};
|
||||
use rnex_core::nex::account::Account;
|
||||
use crate::prudp::packet::PRUDPV1Packet;
|
||||
use crate::prudp::socket::{CryptoHandler, CryptoHandlerConnectionInstance, EncryptionPair};
|
||||
use rnex_core::rmc::structures::RmcSerialize;
|
||||
|
||||
pub fn read_secure_connection_data(data: &[u8], act: &Account) -> Option<([u8; 32], u32, u32)>{
|
||||
let mut cursor = Cursor::new(data);
|
||||
|
||||
let mut ticket_data: Vec<u8> = Vec::deserialize(&mut cursor).ok()?;
|
||||
let mut request_data: Vec<u8> = Vec::deserialize(&mut cursor).ok()?;
|
||||
|
||||
let ticket_data_size = ticket_data.len();
|
||||
|
||||
let ticket_data = &mut ticket_data[0..ticket_data_size-0x10];
|
||||
|
||||
let server_key = derive_key(act.pid, act.kerbros_password);
|
||||
|
||||
let mut rc4: StreamCipherCoreWrapper<Rc4Core<U16>> =
|
||||
Rc4::new_from_slice(&server_key).expect("unable to init rc4 keystream");
|
||||
|
||||
rc4.apply_keystream(ticket_data);
|
||||
|
||||
let ticket_data: &TicketInternalData = match bytemuck::try_from_bytes(ticket_data){
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
error!("unable to read internal ticket data: {}", e);
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
// todo: add ticket expiration
|
||||
|
||||
let TicketInternalData{
|
||||
session_key,
|
||||
pid: ticket_source_pid,
|
||||
issued_time
|
||||
} = *ticket_data;
|
||||
|
||||
// todo: add checking if tickets are signed with a valid md5-hmac
|
||||
let request_data_length = request_data.len();
|
||||
let request_data = &mut request_data[0.. request_data_length - 0x10];
|
||||
|
||||
let mut rc4: StreamCipherCoreWrapper<Rc4Core<U32>> =
|
||||
Rc4::new_from_slice(&session_key).expect("unable to init rc4 keystream");
|
||||
|
||||
rc4.apply_keystream(request_data);
|
||||
|
||||
let mut reqest_data_cursor = Cursor::new(request_data);
|
||||
|
||||
let pid: u32 = reqest_data_cursor.read_struct(IS_BIG_ENDIAN).ok()?;
|
||||
|
||||
if pid != ticket_source_pid{
|
||||
let ticket_created_on = issued_time.to_regular_time();
|
||||
|
||||
error!("someone tried to spoof their pid, ticket was created on: {}", ticket_created_on.to_rfc2822());
|
||||
return None;
|
||||
}
|
||||
|
||||
let _cid: u32 = reqest_data_cursor.read_struct(IS_BIG_ENDIAN).ok()?;
|
||||
let response_check: u32 = reqest_data_cursor.read_struct(IS_BIG_ENDIAN).ok()?;
|
||||
|
||||
|
||||
|
||||
Some((session_key, pid, response_check))
|
||||
}
|
||||
|
||||
type Rc4U32 = StreamCipherCoreWrapper<Rc4Core<U32>>;
|
||||
|
||||
pub fn generate_secure_encryption_pairs(mut session_key: [u8; 32], count: u8) -> Vec<EncryptionPair<Rc4<U32>>>{
|
||||
let mut vec = Vec::with_capacity(count as usize);
|
||||
|
||||
vec.push(EncryptionPair{
|
||||
send: Rc4U32::new_from_slice(&session_key).expect("unable to create rc4"),
|
||||
recv: Rc4U32::new_from_slice(&session_key).expect("unable to create rc4")
|
||||
});
|
||||
|
||||
for _ in 1..=count{
|
||||
let modifier = session_key.len() + 1;
|
||||
|
||||
let key_length = session_key.len();
|
||||
|
||||
for (position, val) in (&mut session_key[0..key_length/2]).iter_mut().enumerate(){
|
||||
*val = val.wrapping_add((modifier - position) as u8);
|
||||
}
|
||||
|
||||
vec.push(EncryptionPair{
|
||||
send: Rc4U32::new_from_slice(&session_key).expect("unable to create rc4"),
|
||||
recv: Rc4U32::new_from_slice(&session_key).expect("unable to create rc4")
|
||||
});
|
||||
}
|
||||
|
||||
vec
|
||||
}
|
||||
|
||||
|
||||
pub struct Secure(pub &'static str, pub Account);
|
||||
|
||||
|
||||
pub struct SecureInstance {
|
||||
access_key: &'static str,
|
||||
session_key: [u8; 32],
|
||||
streams: Vec<EncryptionPair<Rc4<U32>>>,
|
||||
self_signature: [u8; 16],
|
||||
remote_signature: [u8; 16],
|
||||
pid: u32,
|
||||
}
|
||||
|
||||
impl CryptoHandler for Secure {
|
||||
type CryptoConnectionInstance = SecureInstance;
|
||||
|
||||
fn instantiate(
|
||||
&self,
|
||||
remote_signature: [u8; 16],
|
||||
self_signature: [u8; 16],
|
||||
payload: &[u8],
|
||||
substream_count: u8,
|
||||
) -> Option<(Vec<u8>, Self::CryptoConnectionInstance)> {
|
||||
let (session_key, pid, check_value) = read_secure_connection_data(payload, &self.1)?;
|
||||
|
||||
let check_value_response = check_value + 1;
|
||||
|
||||
let data = bytemuck::bytes_of(&check_value_response);
|
||||
|
||||
let mut response = Vec::new();
|
||||
|
||||
data.serialize(&mut response).ok()?;
|
||||
|
||||
let encryption_pairs = generate_secure_encryption_pairs(session_key, substream_count);
|
||||
|
||||
Some((
|
||||
response,
|
||||
SecureInstance {
|
||||
pid,
|
||||
streams: encryption_pairs,
|
||||
session_key,
|
||||
access_key: self.0,
|
||||
remote_signature,
|
||||
self_signature,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
fn sign_pre_handshake(&self, packet: &mut PRUDPV1Packet) {
|
||||
packet.set_sizes();
|
||||
packet.calculate_and_assign_signature(self.0, None, None);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl CryptoHandlerConnectionInstance for SecureInstance {
|
||||
type Encryption = Rc4<U5>;
|
||||
|
||||
fn decrypt_incoming(&mut self, substream: u8, data: &mut [u8]) {
|
||||
if let Some(crypt_pair) = self.streams.get_mut(substream as usize){
|
||||
crypt_pair.recv.apply_keystream(data);
|
||||
}
|
||||
}
|
||||
|
||||
fn encrypt_outgoing(&mut self, substream: u8, data: &mut [u8]) {
|
||||
if let Some(crypt_pair) = self.streams.get_mut(substream as usize){
|
||||
crypt_pair.send.apply_keystream(data);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_user_id(&self) -> u32 {
|
||||
self.pid
|
||||
}
|
||||
|
||||
fn sign_connect(&self, packet: &mut PRUDPV1Packet) {
|
||||
packet.set_sizes();
|
||||
packet.calculate_and_assign_signature(self.access_key, None, Some(self.self_signature));
|
||||
}
|
||||
|
||||
fn sign_packet(&self, packet: &mut PRUDPV1Packet) {
|
||||
packet.set_sizes();
|
||||
packet.calculate_and_assign_signature(self.access_key, Some(self.session_key), Some(self.self_signature));
|
||||
}
|
||||
|
||||
fn verify_packet(&self, _packet: &PRUDPV1Packet) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
812
prudpv1/src/prudp/socket.rs
Normal file
812
prudpv1/src/prudp/socket.rs
Normal file
|
|
@ -0,0 +1,812 @@
|
|||
use crate::prudp::packet::flags::{ACK, HAS_SIZE, MULTI_ACK, NEED_ACK, RELIABLE};
|
||||
use crate::prudp::packet::types::{CONNECT, DATA, DISCONNECT, PING, SYN};
|
||||
use crate::prudp::packet::PacketOption::{
|
||||
ConnectionSignature, FragmentId, MaximumSubstreamId, SupportedFunctions,
|
||||
};
|
||||
use crate::prudp::packet::{PRUDPV1Header, PRUDPV1Packet, TypesFlags};
|
||||
use rnex_core::prudp::virtual_port::VirtualPort;
|
||||
use rnex_core::prudp::socket_addr::PRUDPSockAddr;
|
||||
use async_trait::async_trait;
|
||||
use log::info;
|
||||
use log::error;
|
||||
use rc4::StreamCipher;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::Deref;
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
use std::time::Duration;
|
||||
use tokio::net::UdpSocket;
|
||||
use tokio::sync::mpsc::{channel, Receiver, Sender};
|
||||
use tokio::sync::Mutex;
|
||||
use tokio::time::{sleep, Instant};
|
||||
// due to the way this is designed crashing the router thread causes deadlock, sorry ;-;
|
||||
// (maybe i will fix that some day)
|
||||
|
||||
/// PRUDP Socket for accepting connections to then send and recieve data from those clients
|
||||
|
||||
pub struct EncryptionPair<T: StreamCipher + Send> {
|
||||
pub send: T,
|
||||
pub recv: T,
|
||||
}
|
||||
|
||||
impl<T: StreamCipher + Send> EncryptionPair<T> {
|
||||
pub fn init_both<F: Fn() -> T>(func: F) -> Self {
|
||||
Self {
|
||||
recv: func(),
|
||||
send: func(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CommonConnection {
|
||||
pub user_id: u32,
|
||||
pub socket_addr: PRUDPSockAddr,
|
||||
pub server_port: VirtualPort,
|
||||
session_id: u8,
|
||||
}
|
||||
|
||||
struct InternalConnection<E: CryptoHandlerConnectionInstance> {
|
||||
common: Arc<CommonConnection>,
|
||||
connections: Weak<Mutex<BTreeMap<PRUDPSockAddr, Arc<Mutex<InternalConnection<E>>>>>>,
|
||||
reliable_server_counter: u16,
|
||||
reliable_client_counter: u16,
|
||||
// maybe add connection id(need to see if its even needed)
|
||||
crypto_handler_instance: E,
|
||||
data_sender: Sender<Vec<u8>>,
|
||||
socket: Arc<UdpSocket>,
|
||||
packet_queue: HashMap<u16, PRUDPV1Packet>,
|
||||
last_packet_time: Instant,
|
||||
}
|
||||
|
||||
impl<E: CryptoHandlerConnectionInstance> Deref for InternalConnection<E> {
|
||||
type Target = CommonConnection;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.common
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: CryptoHandlerConnectionInstance> InternalConnection<E> {
|
||||
fn next_server_count(&mut self) -> u16 {
|
||||
let prev_val = self.reliable_server_counter;
|
||||
let (val, _) = self.reliable_server_counter.overflowing_add(1);
|
||||
self.reliable_server_counter = val;
|
||||
|
||||
prev_val
|
||||
}
|
||||
|
||||
#[inline]
|
||||
async fn send_raw_packet(&self, mut prudp_packet: PRUDPV1Packet) {
|
||||
prudp_packet.set_sizes();
|
||||
|
||||
let mut vec = Vec::new();
|
||||
|
||||
prudp_packet
|
||||
.write_to(&mut vec)
|
||||
.expect("somehow failed to convert backet to bytes");
|
||||
|
||||
self.socket
|
||||
.send_to(&vec, self.socket_addr.regular_socket_addr)
|
||||
.await
|
||||
.expect("failed to send data back");
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ExternalConnection {
|
||||
sending: SendingConnection,
|
||||
data_receiver: Receiver<Vec<u8>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SendingConnection {
|
||||
common: Arc<CommonConnection>,
|
||||
internal: Weak<Mutex<dyn AnyInternalConnection>>,
|
||||
}
|
||||
|
||||
pub struct CommonSocket {
|
||||
pub virtual_port: VirtualPort,
|
||||
_phantom_unconstructible: PhantomData<()>,
|
||||
}
|
||||
|
||||
pub(super) struct InternalSocket<T: CryptoHandler> {
|
||||
common: Arc<CommonSocket>,
|
||||
socket: Arc<UdpSocket>,
|
||||
crypto_handler: T,
|
||||
// perf note: change the code to use RwLock here instead to avoid connections being able to block one another before the data is sent off.
|
||||
internal_connections: Arc<
|
||||
Mutex<BTreeMap<PRUDPSockAddr, Arc<Mutex<InternalConnection<T::CryptoConnectionInstance>>>>>,
|
||||
>,
|
||||
connection_establishment_data_sender: Mutex<Option<Sender<PRUDPV1Packet>>>,
|
||||
connection_sender: Sender<ExternalConnection>,
|
||||
}
|
||||
|
||||
pub struct ExternalSocket {
|
||||
common: Arc<CommonSocket>,
|
||||
connection_receiver: Receiver<ExternalConnection>,
|
||||
internal: Weak<dyn AnyInternalSocket>,
|
||||
}
|
||||
|
||||
impl ExternalSocket {
|
||||
pub async fn connect(&mut self, addr: PRUDPSockAddr) -> Option<ExternalConnection> {
|
||||
let socket = self.internal.upgrade()?;
|
||||
|
||||
socket.connect(addr).await;
|
||||
|
||||
self.connection_receiver.recv().await
|
||||
}
|
||||
|
||||
pub async fn accept(&mut self) -> Option<ExternalConnection> {
|
||||
self.connection_receiver.recv().await
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for ExternalSocket {
|
||||
type Target = CommonSocket;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.common
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: CryptoHandler> Deref for InternalSocket<T> {
|
||||
type Target = CommonSocket;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.common
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub(super) trait AnyInternalSocket:
|
||||
Send + Sync + Deref<Target = CommonSocket> + 'static
|
||||
{
|
||||
async fn receive_packet(&self, address: PRUDPSockAddr, packet: PRUDPV1Packet);
|
||||
async fn connect(&self, address: PRUDPSockAddr) -> Option<()>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub(super) trait AnyInternalConnection:
|
||||
Send + Sync + Deref<Target = CommonConnection> + 'static
|
||||
{
|
||||
async fn send_data_packet(&mut self, data: Vec<u8>);
|
||||
|
||||
async fn close_connection(&mut self);
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T: CryptoHandlerConnectionInstance> AnyInternalConnection for InternalConnection<T> {
|
||||
async fn send_data_packet(&mut self, data: Vec<u8>) {
|
||||
let mut packet = PRUDPV1Packet {
|
||||
header: PRUDPV1Header {
|
||||
sequence_id: self.next_server_count(),
|
||||
substream_id: 0,
|
||||
session_id: self.session_id,
|
||||
types_and_flags: TypesFlags::default().types(DATA).flags(RELIABLE | NEED_ACK),
|
||||
destination_port: self.common.socket_addr.virtual_port,
|
||||
source_port: self.server_port,
|
||||
..Default::default()
|
||||
},
|
||||
payload: data,
|
||||
options: vec![FragmentId(0)],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
self.crypto_handler_instance
|
||||
.encrypt_outgoing(0, &mut packet.payload[..]);
|
||||
|
||||
packet.set_sizes();
|
||||
|
||||
self.crypto_handler_instance.sign_packet(&mut packet);
|
||||
|
||||
self.send_raw_packet(packet).await;
|
||||
}
|
||||
|
||||
async fn close_connection(&mut self) {
|
||||
// jon confirmed that this should be a safe way to dc a client
|
||||
|
||||
let mut packet = PRUDPV1Packet {
|
||||
header: PRUDPV1Header {
|
||||
sequence_id: self.next_server_count(),
|
||||
substream_id: 0,
|
||||
session_id: self.session_id,
|
||||
types_and_flags: TypesFlags::default().types(DISCONNECT),
|
||||
destination_port: self.common.socket_addr.virtual_port,
|
||||
source_port: self.server_port,
|
||||
..Default::default()
|
||||
},
|
||||
payload: Vec::new(),
|
||||
options: vec![FragmentId(0)],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
// no need for encryption the, the payload is empty
|
||||
|
||||
packet.set_sizes();
|
||||
|
||||
self.crypto_handler_instance.sign_packet(&mut packet);
|
||||
|
||||
self.send_raw_packet(packet).await;
|
||||
|
||||
let Some(conns) = self.connections.upgrade() else {
|
||||
// this is fine as it implies the server has already quit, thus meaning that we dont
|
||||
// have to remove ourselves from the server
|
||||
return;
|
||||
};
|
||||
|
||||
let mut conns = conns.lock().await;
|
||||
|
||||
conns.remove(&self.socket_addr);
|
||||
|
||||
// the connection will now drop as soon as we leave this due to no longer having a permanent
|
||||
// reference
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: CryptoHandler> InternalSocket<T> {
|
||||
async fn get_connection(
|
||||
&self,
|
||||
addr: PRUDPSockAddr,
|
||||
) -> Option<Arc<Mutex<InternalConnection<T::CryptoConnectionInstance>>>> {
|
||||
let connections = self.internal_connections.lock().await;
|
||||
let Some(conn) = connections.get(&addr) else {
|
||||
error!("tried to send data on inactive connection!");
|
||||
return None;
|
||||
};
|
||||
|
||||
let conn = conn.clone();
|
||||
drop(connections);
|
||||
|
||||
Some(conn)
|
||||
}
|
||||
|
||||
async fn send_packet_unbuffered(&self, dest: PRUDPSockAddr, mut packet: PRUDPV1Packet) {
|
||||
packet.set_sizes();
|
||||
|
||||
let mut vec = Vec::new();
|
||||
|
||||
packet
|
||||
.write_to(&mut vec)
|
||||
.expect("somehow failed to convert backet to bytes");
|
||||
|
||||
self.socket
|
||||
.send_to(&vec, dest.regular_socket_addr)
|
||||
.await
|
||||
.expect("failed to send data back");
|
||||
}
|
||||
|
||||
async fn handle_syn(&self, address: PRUDPSockAddr, packet: PRUDPV1Packet) {
|
||||
info!("got syn");
|
||||
|
||||
let mut response = packet.base_response_packet();
|
||||
|
||||
response.header.types_and_flags.set_types(SYN);
|
||||
response.header.types_and_flags.set_flag(ACK);
|
||||
response.header.types_and_flags.set_flag(HAS_SIZE);
|
||||
|
||||
let signature = address.calculate_connection_signature();
|
||||
|
||||
response.options.push(ConnectionSignature(signature));
|
||||
|
||||
// todo: refactor this to be more readable(low priority cause it doesnt change anything api wise)
|
||||
for options in &packet.options {
|
||||
match options {
|
||||
SupportedFunctions(functions) => {
|
||||
response.options.push(SupportedFunctions(*functions & 0xFF))
|
||||
}
|
||||
MaximumSubstreamId(max_substream) => {
|
||||
response.options.push(MaximumSubstreamId(*max_substream))
|
||||
}
|
||||
_ => { /* ??? */ }
|
||||
}
|
||||
}
|
||||
|
||||
response.set_sizes();
|
||||
|
||||
self.crypto_handler.sign_pre_handshake(&mut response);
|
||||
|
||||
//println!("got syn: {:?}", response);
|
||||
|
||||
self.send_packet_unbuffered(address, response).await;
|
||||
}
|
||||
|
||||
async fn connection_thread(
|
||||
connection: Weak<Mutex<InternalConnection<T::CryptoConnectionInstance>>>,
|
||||
) {
|
||||
//todo: handle stuff like resending packets if they arent acknowledged in here
|
||||
|
||||
while let Some(conn) = connection.upgrade() {
|
||||
let mut conn = conn.lock().await;
|
||||
|
||||
if conn.last_packet_time < (Instant::now() - Duration::from_secs(5)) {
|
||||
conn.send_raw_packet(PRUDPV1Packet {
|
||||
header: PRUDPV1Header {
|
||||
sequence_id: 0,
|
||||
substream_id: 0,
|
||||
session_id: 0,
|
||||
types_and_flags: TypesFlags::default().types(PING).flags(NEED_ACK),
|
||||
destination_port: conn.common.socket_addr.virtual_port,
|
||||
source_port: conn.server_port,
|
||||
..Default::default()
|
||||
},
|
||||
payload: Vec::new(),
|
||||
options: vec![],
|
||||
..Default::default()
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
if conn.last_packet_time < (Instant::now() - Duration::from_secs(30)) {
|
||||
conn.close_connection().await;
|
||||
}
|
||||
drop(conn);
|
||||
|
||||
sleep(Duration::from_secs(5)).await;
|
||||
}
|
||||
}
|
||||
|
||||
async fn create_connection(
|
||||
&self,
|
||||
crypto_handler_instance: T::CryptoConnectionInstance,
|
||||
socket_addr: PRUDPSockAddr,
|
||||
session_id: u8,
|
||||
is_instantiator: bool,
|
||||
) {
|
||||
let common = Arc::new(CommonConnection {
|
||||
user_id: crypto_handler_instance.get_user_id(),
|
||||
socket_addr,
|
||||
session_id,
|
||||
server_port: self.virtual_port,
|
||||
});
|
||||
|
||||
let (data_sender_from_client, data_receiver_from_client) = channel(16);
|
||||
|
||||
let internal = InternalConnection {
|
||||
common: common.clone(),
|
||||
crypto_handler_instance,
|
||||
connections: Arc::downgrade(&self.internal_connections),
|
||||
reliable_client_counter: if is_instantiator { 1 } else { 2 },
|
||||
reliable_server_counter: if is_instantiator { 2 } else { 1 },
|
||||
data_sender: data_sender_from_client,
|
||||
socket: self.socket.clone(),
|
||||
packet_queue: Default::default(),
|
||||
last_packet_time: Instant::now(),
|
||||
};
|
||||
|
||||
let internal = Arc::new(Mutex::new(internal));
|
||||
|
||||
let dyn_internal: Arc<Mutex<dyn AnyInternalConnection>> = internal.clone();
|
||||
|
||||
let external = ExternalConnection {
|
||||
sending: SendingConnection {
|
||||
common,
|
||||
internal: Arc::downgrade(&dyn_internal),
|
||||
},
|
||||
data_receiver: data_receiver_from_client,
|
||||
};
|
||||
|
||||
let mut connections = self.internal_connections.lock().await;
|
||||
|
||||
connections.insert(socket_addr, internal.clone());
|
||||
|
||||
drop(connections);
|
||||
|
||||
tokio::spawn(Self::connection_thread(Arc::downgrade(&internal)));
|
||||
|
||||
self.connection_sender
|
||||
.send(external)
|
||||
.await
|
||||
.expect("connection to external socket lost");
|
||||
}
|
||||
|
||||
async fn handle_connect(&self, address: PRUDPSockAddr, packet: PRUDPV1Packet) {
|
||||
info!("got connect");
|
||||
let Some(MaximumSubstreamId(max_substream)) = packet
|
||||
.options
|
||||
.iter()
|
||||
.find(|v| matches!(v, MaximumSubstreamId(_)))
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
let remote_signature = address.calculate_connection_signature();
|
||||
|
||||
let Some(ConnectionSignature(own_signature)) = packet
|
||||
.options
|
||||
.iter()
|
||||
.find(|p| matches!(p, ConnectionSignature(_)))
|
||||
else {
|
||||
error!("didnt get connection signature from client");
|
||||
return;
|
||||
};
|
||||
|
||||
let session_id = packet.header.session_id;
|
||||
|
||||
let Some((return_data, crypto)) = self.crypto_handler.instantiate(
|
||||
remote_signature,
|
||||
*own_signature,
|
||||
&packet.payload,
|
||||
1 + *max_substream,
|
||||
) else {
|
||||
error!("someone attempted to connect with invalid data");
|
||||
return;
|
||||
};
|
||||
|
||||
let mut response = packet.base_response_packet();
|
||||
response.header.types_and_flags.set_types(CONNECT);
|
||||
response.header.types_and_flags.set_flag(ACK);
|
||||
response.header.types_and_flags.set_flag(HAS_SIZE);
|
||||
|
||||
response.header.session_id = session_id;
|
||||
response.header.sequence_id = 1;
|
||||
|
||||
response.payload = return_data;
|
||||
|
||||
//let remote_signature = address.calculate_connection_signature();
|
||||
|
||||
response
|
||||
.options
|
||||
.push(ConnectionSignature(Default::default()));
|
||||
|
||||
for option in &packet.options {
|
||||
match option {
|
||||
MaximumSubstreamId(max_substream) => {
|
||||
response.options.push(MaximumSubstreamId(*max_substream))
|
||||
}
|
||||
SupportedFunctions(funcs) => response.options.push(SupportedFunctions(*funcs & 0xFF)),
|
||||
_ => { /* ? */ }
|
||||
}
|
||||
}
|
||||
|
||||
response.set_sizes();
|
||||
|
||||
crypto.sign_connect(&mut response);
|
||||
|
||||
//println!("connect out: {:?}", response);
|
||||
|
||||
self.create_connection(crypto, address, session_id, false)
|
||||
.await;
|
||||
|
||||
self.send_packet_unbuffered(address, response).await;
|
||||
}
|
||||
|
||||
async fn handle_data(&self, address: PRUDPSockAddr, packet: PRUDPV1Packet) {
|
||||
info!("got data");
|
||||
|
||||
if packet.header.types_and_flags.get_flags() & (NEED_ACK | RELIABLE)
|
||||
!= (NEED_ACK | RELIABLE)
|
||||
{
|
||||
error!("invalid or unimplemented packet flags");
|
||||
}
|
||||
|
||||
let connections = self.internal_connections.lock().await;
|
||||
let Some(conn) = connections.get(&address) else {
|
||||
error!("tried to send data on inactive connection!");
|
||||
return;
|
||||
};
|
||||
|
||||
let conn = conn.clone();
|
||||
drop(connections);
|
||||
|
||||
println!("recieved packed id: {}", packet.header.sequence_id);
|
||||
|
||||
let mut conn = conn.lock().await;
|
||||
|
||||
conn.packet_queue.insert(packet.header.sequence_id, packet);
|
||||
|
||||
let mut counter = conn.reliable_client_counter;
|
||||
|
||||
while let Some(mut packet) = conn.packet_queue.remove(&counter) {
|
||||
conn.crypto_handler_instance
|
||||
.decrypt_incoming(packet.header.substream_id, &mut packet.payload[..]);
|
||||
|
||||
let mut response = packet.base_acknowledgement_packet();
|
||||
response.header.types_and_flags.set_flag(HAS_SIZE | ACK);
|
||||
response.header.session_id = conn.session_id;
|
||||
|
||||
conn.crypto_handler_instance.sign_packet(&mut response);
|
||||
|
||||
self.send_packet_unbuffered(address, response).await;
|
||||
|
||||
conn.data_sender.send(packet.payload).await.ok();
|
||||
|
||||
conn.reliable_client_counter = conn.reliable_client_counter.overflowing_add(1).0;
|
||||
counter = conn.reliable_client_counter;
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_ping(&self, address: PRUDPSockAddr, packet: PRUDPV1Packet) {
|
||||
let connections = self.internal_connections.lock().await;
|
||||
let Some(conn) = connections.get(&address) else {
|
||||
error!("tried to send data on inactive connection!");
|
||||
return;
|
||||
};
|
||||
let conn = conn.clone();
|
||||
drop(connections);
|
||||
|
||||
let conn = conn.lock().await;
|
||||
|
||||
let mut response = packet.base_acknowledgement_packet();
|
||||
response.header.types_and_flags.set_flag(HAS_SIZE | ACK);
|
||||
response.header.session_id = conn.session_id;
|
||||
|
||||
conn.crypto_handler_instance.sign_packet(&mut response);
|
||||
|
||||
self.send_packet_unbuffered(address, response).await;
|
||||
}
|
||||
|
||||
async fn handle_disconnect(&self, address: PRUDPSockAddr, packet: PRUDPV1Packet) {
|
||||
let connections = self.internal_connections.lock().await;
|
||||
let Some(conn) = connections.get(&address) else {
|
||||
error!("tried to send data on inactive connection!");
|
||||
return;
|
||||
};
|
||||
let conn = conn.clone();
|
||||
drop(connections);
|
||||
|
||||
let conn = conn.lock().await;
|
||||
|
||||
let mut response = packet.base_acknowledgement_packet();
|
||||
response.header.types_and_flags.set_flag(HAS_SIZE | ACK);
|
||||
response.header.session_id = conn.session_id;
|
||||
|
||||
conn.crypto_handler_instance.sign_packet(&mut response);
|
||||
|
||||
self.send_packet_unbuffered(address, response.clone()).await;
|
||||
self.send_packet_unbuffered(address, response.clone()).await;
|
||||
self.send_packet_unbuffered(address, response).await;
|
||||
|
||||
//self.internal_connections.lock().await;
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T: CryptoHandler> AnyInternalSocket for InternalSocket<T> {
|
||||
async fn receive_packet(&self, address: PRUDPSockAddr, packet: PRUDPV1Packet) {
|
||||
// todo: handle acks and resending
|
||||
|
||||
if let Some(conn) = self.get_connection(address).await {
|
||||
let mut conn = conn.lock().await;
|
||||
|
||||
// reset timeout
|
||||
conn.last_packet_time = Instant::now();
|
||||
}
|
||||
|
||||
if (packet.header.types_and_flags.get_flags() & ACK) != 0 {
|
||||
info!("got ack");
|
||||
|
||||
|
||||
if packet.header.types_and_flags.get_types() == SYN
|
||||
|| packet.header.types_and_flags.get_types() == CONNECT
|
||||
{
|
||||
if packet.header.types_and_flags.get_types() == SYN {
|
||||
println!("Syn: {:?}", packet);
|
||||
}
|
||||
|
||||
if packet.header.types_and_flags.get_types() == CONNECT {
|
||||
println!("Connect: {:?}", packet);
|
||||
}
|
||||
|
||||
let sender = self.connection_establishment_data_sender.lock().await;
|
||||
info!("redirecting ack to active connection establishment code");
|
||||
|
||||
if let Some(conn) = sender.as_ref() {
|
||||
if let Err(e) = conn.send(packet).await {
|
||||
error!(
|
||||
"error whilest sending data to connection establishment: {}",
|
||||
e
|
||||
);
|
||||
}
|
||||
} else {
|
||||
error!("got connection response without the active reciever being present");
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (packet.header.types_and_flags.get_flags() & MULTI_ACK) != 0 {
|
||||
info!("got multi ack");
|
||||
return;
|
||||
}
|
||||
|
||||
match packet.header.types_and_flags.get_types() {
|
||||
SYN => self.handle_syn(address, packet).await,
|
||||
CONNECT => self.handle_connect(address, packet).await,
|
||||
DATA => self.handle_data(address, packet).await,
|
||||
DISCONNECT => self.handle_disconnect(address, packet).await,
|
||||
PING => self.handle_ping(address, packet).await,
|
||||
_ => {
|
||||
error!(
|
||||
"unimplemented packet type: {}",
|
||||
packet.header.types_and_flags.get_types()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn connect(&self, address: PRUDPSockAddr) -> Option<()> {
|
||||
let (send, mut recv) = channel(10);
|
||||
|
||||
let mut sender = self.connection_establishment_data_sender.lock().await;
|
||||
*sender = Some(send);
|
||||
drop(sender);
|
||||
|
||||
let remote_signature = address.calculate_connection_signature();
|
||||
|
||||
let packet = PRUDPV1Packet {
|
||||
header: PRUDPV1Header {
|
||||
source_port: self.virtual_port,
|
||||
destination_port: address.virtual_port,
|
||||
types_and_flags: TypesFlags::default().types(SYN).flags(NEED_ACK),
|
||||
..Default::default()
|
||||
},
|
||||
options: vec![
|
||||
SupportedFunctions(0x104),
|
||||
MaximumSubstreamId(0),
|
||||
ConnectionSignature(remote_signature),
|
||||
],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
self.send_packet_unbuffered(address, packet).await;
|
||||
|
||||
let Some(syn_ack_packet) = recv.recv().await else {
|
||||
error!("what");
|
||||
return None;
|
||||
};
|
||||
|
||||
let Some(ConnectionSignature(own_signature)) = syn_ack_packet
|
||||
.options
|
||||
.iter()
|
||||
.find(|p| matches!(p, ConnectionSignature(_)))
|
||||
else {
|
||||
error!("didnt get connection signature from remote partner");
|
||||
return None;
|
||||
};
|
||||
|
||||
let packet = PRUDPV1Packet {
|
||||
header: PRUDPV1Header {
|
||||
source_port: self.virtual_port,
|
||||
destination_port: address.virtual_port,
|
||||
types_and_flags: TypesFlags::default().types(CONNECT).flags(NEED_ACK),
|
||||
..Default::default()
|
||||
},
|
||||
options: vec![
|
||||
SupportedFunctions(0x04),
|
||||
MaximumSubstreamId(0),
|
||||
ConnectionSignature(remote_signature),
|
||||
],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
self.send_packet_unbuffered(address, packet).await;
|
||||
|
||||
let Some(connect_ack_packet) = recv.recv().await else {
|
||||
error!("what");
|
||||
return None;
|
||||
};
|
||||
|
||||
let (_, crypt) =
|
||||
self.crypto_handler
|
||||
.instantiate(remote_signature, *own_signature, &[], 1)?;
|
||||
|
||||
//todo: make this work for secure servers as well
|
||||
self.create_connection(crypt, address, 0, true).await;
|
||||
|
||||
Some(())
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn new_socket_pair<T: CryptoHandler>(
|
||||
virtual_port: VirtualPort,
|
||||
encryption: T,
|
||||
socket: Arc<UdpSocket>,
|
||||
) -> (Arc<InternalSocket<T>>, ExternalSocket) {
|
||||
let common = Arc::new(CommonSocket {
|
||||
virtual_port,
|
||||
_phantom_unconstructible: Default::default(),
|
||||
});
|
||||
|
||||
let (connection_send, connection_recv) = channel(16);
|
||||
|
||||
let internal = Arc::new(InternalSocket {
|
||||
common: common.clone(),
|
||||
connection_sender: connection_send,
|
||||
crypto_handler: encryption,
|
||||
internal_connections: Default::default(),
|
||||
connection_establishment_data_sender: Default::default(),
|
||||
socket,
|
||||
});
|
||||
|
||||
let dyn_internal: Arc<dyn AnyInternalSocket> = internal.clone();
|
||||
|
||||
let external = ExternalSocket {
|
||||
common,
|
||||
connection_receiver: connection_recv,
|
||||
internal: Arc::downgrade(&dyn_internal),
|
||||
};
|
||||
|
||||
(internal, external)
|
||||
}
|
||||
|
||||
pub trait CryptoHandlerConnectionInstance: Send + Sync + 'static {
|
||||
type Encryption: StreamCipher + Send;
|
||||
|
||||
fn decrypt_incoming(&mut self, substream: u8, data: &mut [u8]);
|
||||
fn encrypt_outgoing(&mut self, substream: u8, data: &mut [u8]);
|
||||
|
||||
fn get_user_id(&self) -> u32;
|
||||
fn sign_connect(&self, packet: &mut PRUDPV1Packet);
|
||||
fn sign_packet(&self, packet: &mut PRUDPV1Packet);
|
||||
fn verify_packet(&self, packet: &PRUDPV1Packet) -> bool;
|
||||
}
|
||||
|
||||
pub trait CryptoHandler: Send + Sync + 'static {
|
||||
type CryptoConnectionInstance: CryptoHandlerConnectionInstance;
|
||||
|
||||
fn instantiate(
|
||||
&self,
|
||||
remote_signature: [u8; 16],
|
||||
own_signature: [u8; 16],
|
||||
_: &[u8],
|
||||
substream_count: u8,
|
||||
) -> Option<(Vec<u8>, Self::CryptoConnectionInstance)>;
|
||||
|
||||
fn sign_pre_handshake(&self, packet: &mut PRUDPV1Packet);
|
||||
}
|
||||
|
||||
impl Deref for ExternalConnection {
|
||||
type Target = SendingConnection;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.sending
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for SendingConnection {
|
||||
type Target = CommonConnection;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.common
|
||||
}
|
||||
}
|
||||
|
||||
impl ExternalConnection {
|
||||
pub async fn recv(&mut self) -> Option<Vec<u8>> {
|
||||
self.data_receiver.recv().await
|
||||
}
|
||||
//todo: make this an actual result instead of an option
|
||||
|
||||
pub fn duplicate_sender(&self) -> SendingConnection {
|
||||
self.sending.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl SendingConnection {
|
||||
pub async fn send(&self, data: Vec<u8>) -> Option<()> {
|
||||
let internal = self.internal.upgrade()?;
|
||||
|
||||
let mut internal = internal.lock().await;
|
||||
|
||||
internal.send_data_packet(data).await;
|
||||
Some(())
|
||||
}
|
||||
|
||||
pub async fn close_connection(&self) {
|
||||
let Some(internal) = self.internal.upgrade() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let mut internal = internal.lock().await;
|
||||
|
||||
internal.close_connection().await;
|
||||
}
|
||||
}
|
||||
|
||||
impl<E: CryptoHandlerConnectionInstance> Drop for InternalConnection<E> {
|
||||
fn drop(&mut self) {
|
||||
println!("yatta(internal conn)");
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for CommonConnection {
|
||||
fn drop(&mut self) {
|
||||
println!("yatta(common conn)");
|
||||
}
|
||||
}
|
||||
84
prudpv1/src/prudp/unsecure.rs
Normal file
84
prudpv1/src/prudp/unsecure.rs
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
use once_cell::sync::Lazy;
|
||||
use rc4::{Key, KeyInit, Rc4, StreamCipher};
|
||||
use typenum::U5;
|
||||
use crate::prudp::packet::PRUDPV1Packet;
|
||||
use crate::prudp::socket::{CryptoHandler, CryptoHandlerConnectionInstance, EncryptionPair};
|
||||
|
||||
pub struct Unsecure(pub &'static str);
|
||||
|
||||
|
||||
|
||||
pub struct UnsecureInstance {
|
||||
key: &'static str,
|
||||
streams: Vec<EncryptionPair<Rc4<U5>>>,
|
||||
self_signature: [u8; 16],
|
||||
remote_signature: [u8; 16],
|
||||
}
|
||||
|
||||
// my hand was forced to use lazy so that we can guarantee this code
|
||||
// only runs once and so that i can put it here as a "constant" (for performance and readability)
|
||||
// since for some reason rust crypto doesn't have any const time key initialization
|
||||
static DEFAULT_KEY: Lazy<Key<U5>> = Lazy::new(|| Key::from(*b"CD&ML"));
|
||||
|
||||
impl CryptoHandler for Unsecure {
|
||||
type CryptoConnectionInstance = UnsecureInstance;
|
||||
|
||||
fn instantiate(
|
||||
&self,
|
||||
remote_signature: [u8; 16],
|
||||
self_signature: [u8; 16],
|
||||
_: &[u8],
|
||||
substream_count: u8,
|
||||
) -> Option<(Vec<u8>, Self::CryptoConnectionInstance)> {
|
||||
Some((
|
||||
Vec::new(),
|
||||
UnsecureInstance {
|
||||
streams: (0..substream_count)
|
||||
.map(|_| EncryptionPair::init_both(|| Rc4::new(&DEFAULT_KEY)))
|
||||
.collect(),
|
||||
key: self.0,
|
||||
remote_signature,
|
||||
self_signature,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
fn sign_pre_handshake(&self, packet: &mut PRUDPV1Packet) {
|
||||
packet.set_sizes();
|
||||
packet.calculate_and_assign_signature(self.0, None, None);
|
||||
}
|
||||
}
|
||||
|
||||
impl CryptoHandlerConnectionInstance for UnsecureInstance {
|
||||
type Encryption = Rc4<U5>;
|
||||
|
||||
fn decrypt_incoming(&mut self, substream: u8, data: &mut [u8]) {
|
||||
if let Some(crypt_pair) = self.streams.get_mut(substream as usize){
|
||||
crypt_pair.recv.apply_keystream(data);
|
||||
}
|
||||
}
|
||||
|
||||
fn encrypt_outgoing(&mut self, substream: u8, data: &mut [u8]) {
|
||||
if let Some(crypt_pair) = self.streams.get_mut(substream as usize){
|
||||
crypt_pair.send.apply_keystream(data);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_user_id(&self) -> u32 {
|
||||
0
|
||||
}
|
||||
|
||||
fn sign_connect(&self, packet: &mut PRUDPV1Packet) {
|
||||
packet.set_sizes();
|
||||
packet.calculate_and_assign_signature(self.key, None, Some(self.self_signature));
|
||||
}
|
||||
|
||||
fn sign_packet(&self, packet: &mut PRUDPV1Packet) {
|
||||
packet.set_sizes();
|
||||
packet.calculate_and_assign_signature(self.key, None, Some(self.self_signature));
|
||||
}
|
||||
|
||||
fn verify_packet(&self, packet: &PRUDPV1Packet) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue