This commit is contained in:
Maple 2026-01-27 14:44:10 +01:00
commit 1b802ff33f
15 changed files with 379 additions and 74 deletions

View file

@ -2,7 +2,10 @@ use std::rc::Rc;
use hmac::Mac;
use rc4::{KeyInit, Rc4, StreamCipher};
use rnex_core::prudp::encryption::{DEFAULT_KEY, EncryptionPair};
use rnex_core::prudp::{
encryption::{DEFAULT_KEY, EncryptionPair},
types_flags::{TypesFlags, types::DATA},
};
use typenum::U5;
use crate::crypto::{
@ -13,6 +16,8 @@ use crate::crypto::{
pub struct InsecureInstance {
pair: EncryptionPair<Rc4<U5>>,
self_signat: [u8; 4],
remote_signat: [u8; 4],
}
impl CryptoInstance for InsecureInstance {
@ -25,11 +30,19 @@ impl CryptoInstance for InsecureInstance {
fn get_user_id(&self) -> u32 {
0
}
fn generate_signature(&self, data: &[u8]) -> [u8; 4] {
let mut hmac = <HmacMd5 as Mac>::new_from_slice(ACCESS_KEY.as_bytes())
.expect("unable to create hmac md5");
hmac.update(data);
hmac.finalize().into_bytes()[0..4].try_into().unwrap()
fn generate_signature(&self, types_flags: TypesFlags, data: &[u8]) -> [u8; 4] {
if types_flags.get_types() == DATA {
if data.len() == 0 {
[0x12, 0x34, 0x56, 0x78]
} else {
let mut hmac = <HmacMd5 as Mac>::new_from_slice(ACCESS_KEY.as_bytes())
.expect("unable to create hmac md5");
hmac.update(data);
hmac.finalize().into_bytes()[0..4].try_into().unwrap()
}
} else {
self.self_signat
}
}
}
@ -44,9 +57,16 @@ impl Crypto for Insecure {
common_checksum(ACCESS_KEY, data)
}
fn instantiate(&self, packet_data: &[u8]) -> Self::Instance {
fn instantiate(
&self,
packet_data: &[u8],
self_signat: [u8; 4],
remote_signat: [u8; 4],
) -> Self::Instance {
InsecureInstance {
pair: EncryptionPair::init_both(|| Rc4::new(&DEFAULT_KEY)),
self_signat,
remote_signat,
}
}
}

View file

@ -1,6 +1,6 @@
use hmac::Mac;
use rc4::Rc4;
use rnex_core::prudp::encryption::EncryptionPair;
use rnex_core::prudp::{encryption::EncryptionPair, types_flags::TypesFlags};
use typenum::U32;
use crate::crypto::{
@ -23,7 +23,7 @@ impl CryptoInstance for SecureInstance {
fn get_user_id(&self) -> u32 {
todo!()
}
fn generate_signature(&self, data: &[u8]) -> [u8; 4] {
fn generate_signature(&self, types_flags: TypesFlags, data: &[u8]) -> [u8; 4] {
let mut hmac = <HmacMd5 as Mac>::new_from_slice(ACCESS_KEY.as_bytes())
.expect("unable to create hmac md5");
hmac.update(data);
@ -41,7 +41,12 @@ impl Crypto for Secure {
fn calculate_checksum(&self, data: &[u8]) -> u8 {
common_checksum(ACCESS_KEY, data)
}
fn instantiate(&self, data: &[u8]) -> Self::Instance {
fn instantiate(
&self,
data: &[u8],
self_signat: [u8; 4],
remote_signat: [u8; 4],
) -> Self::Instance {
todo!()
}
}

View file

@ -1,11 +1,12 @@
use cfg_if::cfg_if;
use rnex_core::prudp::types_flags::TypesFlags;
mod common_crypto;
pub trait CryptoInstance: Send + 'static {
fn decrypt_incoming(&mut self, data: &mut [u8]);
fn encrypt_outgoing(&mut self, data: &mut [u8]);
fn generate_signature(&self, data: &[u8]) -> [u8; 4];
fn generate_signature(&self, types_flags: TypesFlags, data: &[u8]) -> [u8; 4];
fn get_user_id(&self) -> u32;
}
@ -13,7 +14,12 @@ pub trait Crypto: Send + Sync + 'static {
type Instance: CryptoInstance;
fn new() -> Self;
fn calculate_checksum(&self, data: &[u8]) -> u8;
fn instantiate(&self, data: &[u8]) -> Self::Instance;
fn instantiate(
&self,
data: &[u8],
self_signat: [u8; 4],
remote_signat: [u8; 4],
) -> Self::Instance;
}
cfg_if! {

View file

@ -47,7 +47,7 @@ async fn start_proxy<T: Crypto>(param: ProxyStartupParam) {
let mut crypto = Arc::new(T::new());
info!("binding to socket");
let server: Arc<Server<T>> = Arc::new(Server::new().await);
let server: Arc<Server<T>> = Arc::new(Server::new(param).await);
info!("waiting on packets");
server.run_task().await;

View file

@ -1,10 +1,10 @@
use std::mem::transmute;
use bytemuck::{Pod, Zeroable, try_from_bytes, try_from_bytes_mut};
use log::error;
use log::{error, info};
use rnex_core::prudp::{
types_flags::{
TypesFlags,
self, TypesFlags,
flags::{HAS_SIZE, NEED_ACK},
types::{CONNECT, DATA, SYN},
},
@ -65,6 +65,40 @@ impl<T: AsRef<[u8]>> PRUDPV0Packet<T> {
.ok()?,
)
}
#[inline(always)]
pub fn size_mut(&mut self) -> Option<&mut u16>
where
T: AsMut<[u8]>,
{
if self.header()?.type_flags.get_flags() & HAS_SIZE == 0 {
return None;
}
let offset = size_of::<PRUDPV0Header>() + get_type_specific_size(self.header()?.type_flags);
Some(bytemuck::from_bytes_mut(
self.0.as_mut().get_mut(offset..offset + 2)?,
))
}
#[inline(always)]
pub fn fragment_id_mut(&mut self) -> Option<&mut u8>
where
T: AsMut<[u8]>,
{
if self.header()?.type_flags.get_types() != DATA {
return None;
}
let offset = size_of::<PRUDPV0Header>();
Some(self.0.as_mut().get_mut(offset)?)
}
#[inline(always)]
pub fn fragment_id(&self) -> Option<&u8> {
if self.header()?.type_flags.get_types() != DATA {
return None;
}
let offset = size_of::<PRUDPV0Header>();
Some(self.0.as_ref().get(offset)?)
}
#[inline(always)]
fn get_payload_offset(&self) -> Option<usize> {
@ -136,7 +170,7 @@ const fn get_size_offset(tf: TypesFlags) -> usize {
}
#[inline(always)]
const fn get_type_specific_size(tf: TypesFlags) -> usize {
if tf.get_types() & (SYN | CONNECT) != 0 {
if tf.get_types() == SYN || tf.get_types() == CONNECT {
4
} else if tf.get_types() & DATA != 0 {
1
@ -185,3 +219,94 @@ pub fn new_syn_packet(
packet.0
}
pub fn new_connect_packet(
flags: u16,
source: VirtualPort,
destination: VirtualPort,
signat: [u8; 4],
crypto: &impl Crypto,
) -> Vec<u8> {
let type_flags = TypesFlags::default().types(CONNECT).flags(flags);
let vec = vec![0; precalc_size(type_flags, 0)];
let mut packet = PRUDPV0Packet::new(vec);
let header = packet.header_mut().expect("packet malformed in creation");
*header = PRUDPV0Header {
destination,
source,
packet_signature: DEFAULT_SIGNAT,
sequence_id: 0,
session_id: 0,
type_flags,
};
*packet
.connection_signature_mut()
.expect("packet malformed in creation") = signat;
*packet.checksum_mut().expect("packet malformed in creation") = crypto.calculate_checksum(
packet
.checksummed_data()
.expect("packet malformed in creation"),
);
packet.0
}
pub fn new_data_packet(
flags: u16,
source: VirtualPort,
destination: VirtualPort,
data: &[u8],
sequence_id: u16,
session_id: u8,
frag_id: u8,
crypto_instance: &mut impl CryptoInstance,
crypto: &impl Crypto,
) -> Vec<u8> {
let type_flags = TypesFlags::default().types(DATA).flags(flags);
let vec = vec![0; precalc_size(type_flags, data.len())];
let mut packet = PRUDPV0Packet::new(vec);
packet
.header_mut()
.expect("packet malformed in creation")
.type_flags = type_flags;
packet
.payload_mut()
.expect("packet malformed in creation")
.copy_from_slice(data);
if let Some(size) = packet.size_mut() {
*size = data.len() as u16;
}
*packet
.fragment_id_mut()
.expect("packet malformed in creation") = frag_id;
let packet_signature = crypto_instance.generate_signature(
type_flags,
packet.payload().expect("packet malformed in creation"),
);
let header = packet.header_mut().expect("packet malformed in creation");
*header = PRUDPV0Header {
destination,
source,
packet_signature,
sequence_id,
session_id,
type_flags,
};
*packet.checksum_mut().expect("packet malformed in creation") = crypto.calculate_checksum(
packet
.checksummed_data()
.expect("packet malformed in creation"),
);
info!("header: {:?}", packet.header());
packet.0
}

View file

@ -6,6 +6,8 @@ use std::{
Arc, LazyLock,
atomic::{AtomicBool, AtomicU32},
},
thread::sleep,
time::Duration,
};
use log::{error, info, warn};
@ -16,7 +18,7 @@ use rnex_core::{
socket_addr::PRUDPSockAddr,
types_flags::{
TypesFlags,
flags::{ACK, HAS_SIZE, NEED_ACK},
flags::{ACK, HAS_SIZE, NEED_ACK, RELIABLE},
types::{CONNECT, DATA, SYN},
},
virtual_port::VirtualPort,
@ -33,7 +35,10 @@ use tokio::{
use crate::{
crypto::{Crypto, CryptoInstance},
packet::{PRUDPV0Header, PRUDPV0Packet, new_syn_packet, precalc_size},
packet::{
PRUDPV0Header, PRUDPV0Packet, new_connect_packet, new_data_packet, new_syn_packet,
precalc_size,
},
};
pub struct InternalConnection<C: CryptoInstance> {
@ -42,6 +47,7 @@ pub struct InternalConnection<C: CryptoInstance> {
server_packet_counter: u16,
client_packet_counter: u16,
unacknowledged_packets: HashMap<u16, Arc<Vec<u8>>>,
packet_queue: HashMap<u16, (Instant, PRUDPV0Packet<Vec<u8>>)>,
}
pub struct Connection<C: CryptoInstance> {
alive: AtomicBool,
@ -71,8 +77,8 @@ pub struct Server<C: Crypto> {
}
impl<C: Crypto> Server<C> {
async fn send_data_packet(&self, conn: &Connection<C::Instance>, data: &[u8]) {
let type_flags = TypesFlags::default().types(DATA).flags(HAS_SIZE | NEED_ACK);
async fn send_data_packet(self: Arc<Self>, conn: Arc<Connection<C::Instance>>, data: &[u8]) {
/*let type_flags = TypesFlags::default().types(DATA).flags(HAS_SIZE | NEED_ACK);
let vec = vec![0; precalc_size(type_flags, data.len())];
let mut packet = PRUDPV0Packet::new(vec);
@ -99,13 +105,26 @@ impl<C: Crypto> Server<C> {
packet
.checksummed_data()
.expect("packet malformed in creation"),
);
let packet_raw = packet.0;
let packet = Arc::new(packet_raw);
);*/
let mut inner = conn.inner.lock().await;
let seq = inner.server_packet_counter;
let packet = new_data_packet(
HAS_SIZE | NEED_ACK | RELIABLE,
self.param.virtual_port,
conn.addr.virtual_port,
data,
inner.server_packet_counter,
conn.session_id,
0,
&mut inner.crypto_instance,
&self.crypto,
);
inner.server_packet_counter += 1;
let packet = Arc::new(packet);
let packet_ref = Arc::downgrade(&packet);
let conn = Arc::downgrade(&conn);
let this = Arc::downgrade(&self);
inner.unacknowledged_packets.insert(seq, packet);
@ -116,7 +135,19 @@ impl<C: Crypto> Server<C> {
let Some(data) = packet_ref.upgrade() else {
return;
};
let Some(conn) = conn.upgrade() else {
return;
};
let Some(this) = this.upgrade() else {
return;
};
info!("send attempt {}", n);
self.socket
.send_to(&data, conn.addr.regular_socket_addr)
.await;
break;
}
});
}
@ -125,14 +156,21 @@ impl<C: Crypto> Server<C> {
conn: Arc<Connection<C::Instance>>,
mut recv: SplittableBufferConnection,
) {
while let Some(data) = recv.recv().await {}
while let Some(data) = recv.recv().await {
if &data[..] == &[0, 0, 0, 0, 0] {
info!("got keepalive");
continue;
}
info!("got data from server: {:?}", data);
self.clone().send_data_packet(conn.clone(), &data).await;
}
}
async fn timeout_thread(self: Arc<Self>, conn: Arc<Connection<C::Instance>>) {
loop {
conn
sleep(Duration::from_secs(5));
}
}
async fn handle_syn(self: Arc<Self>, packet: PRUDPV0Packet<&[u8]>, addr: PRUDPSockAddr) {
async fn handle_syn(self: Arc<Self>, packet: PRUDPV0Packet<Vec<u8>>, addr: PRUDPSockAddr) {
info!("got syn");
let header = packet.header().unwrap();
@ -142,8 +180,7 @@ impl<C: Crypto> Server<C> {
let packet = new_syn_packet(ACK, header.destination, header.source, signat, &self.crypto);
self.socket.send_to(&packet, addr.regular_socket_addr).await;
}
async fn handle_connect(self: Arc<Self>, packet: PRUDPV0Packet<&[u8]>, addr: PRUDPSockAddr) {
let conn = self.connections.write().await;
async fn handle_connect(self: Arc<Self>, packet: PRUDPV0Packet<Vec<u8>>, addr: PRUDPSockAddr) {
let Some(data) = packet.payload() else {
warn!("malformed packet from: {:?}", addr.regular_socket_addr);
return;
@ -155,16 +192,6 @@ impl<C: Crypto> Server<C> {
);
return;
};
let ci = self.crypto.instantiate(data);
let pid = ci.get_user_id();
let conn = new_backend_connection(&self.param, addr, pid).await;
let Some(conn) = conn else {
error!("unable to connect to backend");
return;
};
let remote_signat = addr.calculate_connection_signature();
let remote_signat = [
remote_signat[0],
@ -173,10 +200,19 @@ impl<C: Crypto> Server<C> {
remote_signat[3],
];
let ci = self.crypto.instantiate(data, self_signat, remote_signat);
let pid = ci.get_user_id();
let buf_conn = new_backend_connection(&self.param, addr, pid).await;
let Some(buf_conn) = buf_conn else {
error!("unable to connect to backend");
return;
};
let header = packet.header().expect("header should be validated by now");
let conn = Arc::new(Connection {
target: conn.duplicate_sender(),
target: buf_conn.duplicate_sender(),
remote_signat,
self_signat,
addr,
@ -188,10 +224,95 @@ impl<C: Crypto> Server<C> {
client_packet_counter: 2,
server_packet_counter: 1,
unacknowledged_packets: HashMap::new(),
packet_queue: HashMap::new(),
}),
});
let mut conns = self.connections.write().await;
conns.insert(addr, conn.clone());
drop(conns);
spawn({
let this = self.clone();
let conn = conn.clone();
this.connection_thread(conn, buf_conn)
});
spawn({
let this = self.clone();
let conn = conn.clone();
this.timeout_thread(conn)
});
let packet = new_connect_packet(
ACK,
header.destination,
header.source,
remote_signat,
&self.crypto,
);
info!("sending back connection accept");
self.socket.send_to(&packet, addr.regular_socket_addr).await;
}
async fn process_packet<'a>(self: Arc<Self>, packet: PRUDPV0Packet<&[u8]>, addr: SocketAddrV4) {
async fn handle_data(self: Arc<Self>, mut packet: PRUDPV0Packet<Vec<u8>>, addr: PRUDPSockAddr) {
let Some(frag_id) = packet.fragment_id() else {
warn!("invalid packet from: {:?}", addr);
return;
};
let Some(header) = packet.header() else {
warn!("invalid packet from: {:?}", addr);
return;
};
let rd = self.connections.read().await;
let res = rd.get(&addr).cloned();
drop(rd);
let Some(res) = res else {
warn!("data packet on inactive connection from: {:?}", addr);
return;
};
info!("frag: {}", frag_id);
let mut conn = res.inner.lock().await;
let ack = new_data_packet(
ACK | HAS_SIZE,
self.param.virtual_port,
res.addr.virtual_port,
&[],
header.sequence_id,
header.session_id,
*frag_id,
&mut conn.crypto_instance,
&self.crypto,
);
self.socket.send_to(&ack, addr.regular_socket_addr).await;
conn.last_action = Instant::now();
conn.packet_queue.insert(
packet.header().unwrap().sequence_id,
(Instant::now(), packet),
);
while let Some((_, mut packet)) = {
let ctr = conn.client_packet_counter;
conn.packet_queue.remove(&ctr)
} {
info!("processing packet: {}", conn.client_packet_counter);
let Some(payload) = packet.payload_mut() else {
//todo: at this point the stream would have been broken, we should probably disconnect the client
warn!("invalid packet from: {:?}", addr);
return;
};
conn.crypto_instance.decrypt_incoming(payload);
res.target.send(payload.to_owned()).await;
conn.client_packet_counter += 1;
}
drop(conn);
}
async fn process_packet<'a>(
self: Arc<Self>,
packet: PRUDPV0Packet<Vec<u8>>,
addr: SocketAddrV4,
) {
if !packet.check_checksum(&self.crypto) {
warn!("invalid checksum from: {}", addr);
return;
@ -211,6 +332,9 @@ impl<C: Crypto> Server<C> {
CONNECT => {
self.handle_connect(packet, addr).await;
}
DATA => {
self.handle_data(packet, addr).await;
}
v => {
println!("unimplemented packed type: {}", v);
}
@ -231,8 +355,8 @@ impl<C: Crypto> Server<C> {
};
let this = self.clone();
tokio::spawn(async move {
let data = vec;
let packet = PRUDPV0Packet::new(&data[..]);
let mut data = vec;
let packet = PRUDPV0Packet::new(data);
let SocketAddr::V4(addr) = addr else {
unreachable!()