From 7918e54487ed75f6298d414c0f92d382979da3d3 Mon Sep 17 00:00:00 2001 From: Maple Date: Sat, 31 Jan 2026 13:48:06 +0100 Subject: [PATCH] more progress on friends --- Cargo.lock | 2 + editions.yaml | 9 +- proxy/Cargo.toml | 1 + prudpv0/Cargo.toml | 3 +- prudpv0/src/crypto/friends_insecure.rs | 2 +- prudpv0/src/crypto/friends_secure.rs | 32 +++++-- prudpv0/src/lib.rs | 111 +++++++++++----------- prudpv0/src/packet.rs | 25 ++--- prudpv0/src/server.rs | 13 ++- prudpv1/Cargo.toml | 11 +-- prudpv1/src/executables/mod.rs | 4 +- prudpv1/src/executables/proxy_insecure.rs | 9 +- prudpv1/src/executables/proxy_secure.rs | 84 +++++++++------- prudpv1/src/lib.rs | 16 +++- prudpv1/src/prudp/secure.rs | 2 +- rnex-core/Cargo.toml | 2 + rnex-core/src/kerberos/mod.rs | 103 ++++++++++++-------- rnex-core/src/nex/account.rs | 27 +++--- rnex-core/src/nex/auth_handler.rs | 81 +++++++++++----- 19 files changed, 326 insertions(+), 211 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b6cac8f..a8b4dd5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -580,10 +580,12 @@ version = "0.1.0" dependencies = [ "async-trait", "bytemuck", + "cfg-if", "hmac", "log", "md-5", "once_cell", + "proxy-common", "rc4", "rnex-core", "thiserror", diff --git a/editions.yaml b/editions.yaml index f20da91..6b83a15 100644 --- a/editions.yaml +++ b/editions.yaml @@ -1,10 +1,17 @@ splatoon: features: - rmc_struct_header + - prudpv1 settings: AUTH_REPORT_VERSION: "branch:origin/project/wup-agmj build:3_8_15_2004_0" + RNEX_VIRTUAL_PORT_INSECURE: "1:16" + RNEX_VIRTUAL_PORT_SECURE: "0:0" + RNEX_DEFAULT_PORT: 6000 friends: features: - friends settings: - RNEX_VIRTUAL_PORT: 1:10 + AUTH_REPORT_VERSION: "branch:origin/project/wup-agmj build:3_8_15_2004_0" + RNEX_VIRTUAL_PORT_INSECURE: "1:16" + RNEX_VIRTUAL_PORT_SECURE: "0:0" + RNEX_DEFAULT_PORT: 6000 diff --git a/proxy/Cargo.toml b/proxy/Cargo.toml index b1cfd0d..f2a5974 100644 --- a/proxy/Cargo.toml +++ b/proxy/Cargo.toml @@ -15,6 +15,7 @@ rnex-core = { path = "../rnex-core", version = "0.1.1" } prudpv0 = ["dep:prudpv0"] prudpv1 = ["dep:prudpv1"] friends = ["prudpv0", "prudpv0/friends"] +splatoon = ["prudpv1"] [[bin]] diff --git a/prudpv0/Cargo.toml b/prudpv0/Cargo.toml index dbdb1db..447436d 100644 --- a/prudpv0/Cargo.toml +++ b/prudpv0/Cargo.toml @@ -16,4 +16,5 @@ hmac = "0.12.1" md-5 = "^0.10.6" [features] -friends = [] +prudpv0 = [] +friends = ["prudpv0"] diff --git a/prudpv0/src/crypto/friends_insecure.rs b/prudpv0/src/crypto/friends_insecure.rs index 9e27233..d1575e8 100644 --- a/prudpv0/src/crypto/friends_insecure.rs +++ b/prudpv0/src/crypto/friends_insecure.rs @@ -33,7 +33,7 @@ impl CryptoInstance for InsecureInstance { 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] + [0x78, 0x56, 0x34, 0x12] } else { let mut hmac = ::new_from_slice(ACCESS_KEY.as_bytes()) .expect("unable to create hmac md5"); diff --git a/prudpv0/src/crypto/friends_secure.rs b/prudpv0/src/crypto/friends_secure.rs index 86d7bdc..206efec 100644 --- a/prudpv0/src/crypto/friends_secure.rs +++ b/prudpv0/src/crypto/friends_secure.rs @@ -1,6 +1,9 @@ use hmac::Mac; -use rc4::Rc4; -use rnex_core::prudp::{encryption::EncryptionPair, types_flags::TypesFlags}; +use rc4::{Rc4, StreamCipher}; +use rnex_core::prudp::{ + encryption::EncryptionPair, + types_flags::{TypesFlags, types::DATA}, +}; use typenum::U32; use crate::crypto::{ @@ -11,23 +14,34 @@ use crate::crypto::{ pub struct SecureInstance { pair: EncryptionPair>, + uid: u32, + self_signat: [u8; 4], + remote_signat: [u8; 4], } impl CryptoInstance for SecureInstance { fn decrypt_incoming(&mut self, data: &mut [u8]) { - todo!() + self.pair.recv.apply_keystream(data); } fn encrypt_outgoing(&mut self, data: &mut [u8]) { - todo!() + self.pair.send.apply_keystream(data); } fn get_user_id(&self) -> u32 { - todo!() + self.uid } fn generate_signature(&self, types_flags: TypesFlags, data: &[u8]) -> [u8; 4] { - let mut hmac = ::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() + if types_flags.get_types() == DATA { + if data.len() == 0 { + [0x78, 0x56, 0x34, 0x12] + } else { + let mut hmac = ::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 + } } } diff --git a/prudpv0/src/lib.rs b/prudpv0/src/lib.rs index 99014aa..0df222a 100644 --- a/prudpv0/src/lib.rs +++ b/prudpv0/src/lib.rs @@ -1,62 +1,67 @@ -use bytemuck::{Pod, Zeroable}; -use log::{error, info, warn}; -use proxy_common::{ProxyStartupParam, setup_edge_node_connection}; -use rnex_core::executables::common::{OWN_IP_PRIVATE, OWN_IP_PUBLIC, SERVER_PORT}; -use rnex_core::prudp::types_flags::TypesFlags; -use rnex_core::prudp::types_flags::types::SYN; -use rnex_core::prudp::virtual_port::VirtualPort; -use rnex_core::reggie::EdgeNodeHolderConnectOption::Register; -use rnex_core::reggie::RemoteEdgeNodeHolder; -use rnex_core::rmc::protocols::{OnlyRemote, new_rmc_gateway_connection}; -use rnex_core::rmc::structures::RmcSerialize; -use rnex_core::util::SplittableBufferConnection; -use std::env; -use std::net::SocketAddrV4; -use std::process::abort; -use std::sync::{Arc, LazyLock}; -use tokio::net::UdpSocket; +cfg_if::cfg_if! { + if #[cfg(feature = "prudpv0")] { + use bytemuck::{Pod, Zeroable}; + use cfg_if::cfg_if; + use log::{error, info, warn}; + use proxy_common::{ProxyStartupParam, setup_edge_node_connection}; + use rnex_core::executables::common::{OWN_IP_PRIVATE, OWN_IP_PUBLIC, SERVER_PORT}; + use rnex_core::prudp::types_flags::TypesFlags; + use rnex_core::prudp::types_flags::types::SYN; + use rnex_core::prudp::virtual_port::VirtualPort; + use rnex_core::reggie::EdgeNodeHolderConnectOption::Register; + use rnex_core::reggie::RemoteEdgeNodeHolder; + use rnex_core::rmc::protocols::{OnlyRemote, new_rmc_gateway_connection}; + use rnex_core::rmc::structures::RmcSerialize; + use rnex_core::util::SplittableBufferConnection; + use std::env; + use std::net::SocketAddrV4; + use std::process::abort; + use std::sync::{Arc, LazyLock}; + use tokio::net::UdpSocket; -use crate::crypto::{Crypto, Insecure, Secure}; -use crate::packet::PRUDPV0Packet; -use crate::server::Server; + use crate::crypto::{Crypto, Insecure, Secure}; + use crate::packet::PRUDPV0Packet; + use crate::server::Server; -mod crypto; -mod packet; -mod server; + mod crypto; + mod packet; + mod server; -pub static EDGE_NODE_HOLDER: LazyLock = LazyLock::new(|| { - env::var("EDGE_NODE_HOLDER") - .ok() - .and_then(|s| s.parse().ok()) - .expect("EDGE_NODE_HOLDER not set") -}); + pub static EDGE_NODE_HOLDER: LazyLock = LazyLock::new(|| { + env::var("EDGE_NODE_HOLDER") + .ok() + .and_then(|s| s.parse().ok()) + .expect("EDGE_NODE_HOLDER not set") + }); -pub static FORWARD_DESTINATION: LazyLock = LazyLock::new(|| { - env::var("FORWARD_DESTINATION") - .ok() - .and_then(|s| s.parse().ok()) - .expect("FORWARD_DESTINATION not set") -}); -//same as with prudpv1 this is responsible for handeling the different cryptography -//implementations, e.g. secure and insecure(this also includes special cases like friends) + pub static FORWARD_DESTINATION: LazyLock = LazyLock::new(|| { + env::var("FORWARD_DESTINATION") + .ok() + .and_then(|s| s.parse().ok()) + .expect("FORWARD_DESTINATION not set") + }); + //same as with prudpv1 this is responsible for handeling the different cryptography + //implementations, e.g. secure and insecure(this also includes special cases like friends) -async fn start_proxy(param: ProxyStartupParam) { - setup_edge_node_connection(¶m, || abort()); + async fn start_proxy(param: ProxyStartupParam) { + setup_edge_node_connection(¶m, || abort()); - info!("creating cryptography instance"); - let mut crypto = Arc::new(T::new()); - info!("binding to socket"); + info!("creating cryptography instance"); + let mut crypto = Arc::new(T::new()); + info!("binding to socket"); - let server: Arc> = Arc::new(Server::new(param).await); + let server: Arc> = Arc::new(Server::new(param).await); - info!("waiting on packets"); - server.run_task().await; -} - -pub async fn start_secure(param: ProxyStartupParam) { - start_proxy::(param).await; -} - -pub async fn start_insecure(param: ProxyStartupParam) { - start_proxy::(param).await; + info!("waiting on packets"); + server.run_task().await; + } + + pub async fn start_secure(param: ProxyStartupParam) { + start_proxy::(param).await; + } + + pub async fn start_insecure(param: ProxyStartupParam) { + start_proxy::(param).await; + } + } } diff --git a/prudpv0/src/packet.rs b/prudpv0/src/packet.rs index 3536ded..d7b6705 100644 --- a/prudpv0/src/packet.rs +++ b/prudpv0/src/packet.rs @@ -66,7 +66,7 @@ impl> PRUDPV0Packet { ) } #[inline(always)] - pub fn size_mut(&mut self) -> Option<&mut u16> + pub fn size_mut(&mut self) -> Option<&mut [u8]> where T: AsMut<[u8]>, { @@ -74,9 +74,7 @@ impl> PRUDPV0Packet { return None; } let offset = size_of::() + get_type_specific_size(self.header()?.type_flags); - Some(bytemuck::from_bytes_mut( - self.0.as_mut().get_mut(offset..offset + 2)?, - )) + Some(self.0.as_mut().get_mut(offset..offset + 2)?) } #[inline(always)] @@ -224,7 +222,10 @@ pub fn new_connect_packet( flags: u16, source: VirtualPort, destination: VirtualPort, - signat: [u8; 4], + self_signat: [u8; 4], + remote_signat: [u8; 4], + session_id: u8, + data: &[u8], crypto: &impl Crypto, ) -> Vec { let type_flags = TypesFlags::default().types(CONNECT).flags(flags); @@ -236,15 +237,17 @@ pub fn new_connect_packet( *header = PRUDPV0Header { destination, source, - packet_signature: DEFAULT_SIGNAT, - sequence_id: 0, - session_id: 0, + packet_signature: self_signat, + sequence_id: 1, + session_id, type_flags, }; *packet .connection_signature_mut() - .expect("packet malformed in creation") = signat; - + .expect("packet malformed in creation") = remote_signat; + if let Some(size) = packet.size_mut() { + size.copy_from_slice(&(data.len() as u16).to_le_bytes()); + } *packet.checksum_mut().expect("packet malformed in creation") = crypto.calculate_checksum( packet .checksummed_data() @@ -279,7 +282,7 @@ pub fn new_data_packet( .copy_from_slice(data); if let Some(size) = packet.size_mut() { - *size = data.len() as u16; + size.copy_from_slice(&(data.len() as u16).to_le_bytes()); } *packet .fragment_id_mut() diff --git a/prudpv0/src/server.rs b/prudpv0/src/server.rs index 6d7f55a..bd4b492 100644 --- a/prudpv0/src/server.rs +++ b/prudpv0/src/server.rs @@ -244,10 +244,13 @@ impl Server { }); let packet = new_connect_packet( - ACK, + ACK | HAS_SIZE, header.destination, header.source, + self_signat, remote_signat, + packet.header().unwrap().session_id, + &[], &self.crypto, ); @@ -274,7 +277,7 @@ impl Server { info!("frag: {}", frag_id); let mut conn = res.inner.lock().await; let ack = new_data_packet( - ACK | HAS_SIZE, + ACK, self.param.virtual_port, res.addr.virtual_port, &[], @@ -324,6 +327,12 @@ impl Server { }; let addr = PRUDPSockAddr::new(addr, header.source); + + if header.type_flags.get_flags() & ACK != 0 { + info!("got ack(acks are ignored for now)"); + return; + } + println!("{:?}", header); match header.type_flags.get_types() { SYN => { diff --git a/prudpv1/Cargo.toml b/prudpv1/Cargo.toml index efeaf0a..b8346bf 100644 --- a/prudpv1/Cargo.toml +++ b/prudpv1/Cargo.toml @@ -16,11 +16,8 @@ async-trait = "0.1.88" typenum = "1.18.0" once_cell = "1.21.3" rnex-core = { path = "../rnex-core", version = "0.1.1" } +proxy-common = {path = "../proxy-common"} +cfg-if = "1.0.4" -[[bin]] -name = "proxy_insecure" -path = "src/executables/proxy_insecure.rs" - -[[bin]] -name = "proxy_secure" -path = "src/executables/proxy_secure.rs" +[features] +prudpv1 = [] diff --git a/prudpv1/src/executables/mod.rs b/prudpv1/src/executables/mod.rs index ffac467..2c0d6cf 100644 --- a/prudpv1/src/executables/mod.rs +++ b/prudpv1/src/executables/mod.rs @@ -1 +1,3 @@ -pub mod common; \ No newline at end of file +pub mod common; +pub mod proxy_insecure; +pub mod proxy_secure; diff --git a/prudpv1/src/executables/proxy_insecure.rs b/prudpv1/src/executables/proxy_insecure.rs index 350018d..a6d9453 100644 --- a/prudpv1/src/executables/proxy_insecure.rs +++ b/prudpv1/src/executables/proxy_insecure.rs @@ -1,7 +1,7 @@ +use crate::executables::common::{EDGE_NODE_HOLDER, FORWARD_DESTINATION}; +use crate::prudp::router::Router; +use crate::prudp::unsecure::Unsecure; use log::error; -use prudpv1::executables::common::{EDGE_NODE_HOLDER, FORWARD_DESTINATION}; -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; @@ -20,8 +20,7 @@ use tokio::net::TcpStream; use tokio::task; use tokio::time::sleep; -#[tokio::main] -async fn main() { +pub async fn start() { setup(); let conn = tokio::net::TcpStream::connect(&*EDGE_NODE_HOLDER) diff --git a/prudpv1/src/executables/proxy_secure.rs b/prudpv1/src/executables/proxy_secure.rs index d11b944..b18de8c 100644 --- a/prudpv1/src/executables/proxy_secure.rs +++ b/prudpv1/src/executables/proxy_secure.rs @@ -1,48 +1,56 @@ -use rnex_core::reggie::UnitPacketRead; -use rnex_core::reggie::UnitPacketWrite; -use rnex_core::rmc::structures::RmcSerialize; -use std::net::SocketAddrV4; -use std::sync::Arc; -use std::time::Duration; +use crate::executables::common::{EDGE_NODE_HOLDER, FORWARD_DESTINATION}; +use crate::prudp::router::Router; +use crate::prudp::secure::Secure; use log::error; -use tokio::net::TcpStream; -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 rnex_core::common::setup; -use rnex_core::executables::common::{OWN_IP_PRIVATE, OWN_IP_PUBLIC, SECURE_SERVER_ACCOUNT, SERVER_PORT}; +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::reggie::UnitPacketRead; +use rnex_core::reggie::UnitPacketWrite; +use rnex_core::rmc::protocols::{OnlyRemote, new_rmc_gateway_connection}; +use rnex_core::rmc::structures::RmcSerialize; use rnex_core::rnex_proxy_common::ConnectionInitData; use rnex_core::util::SplittableBufferConnection; +use std::net::SocketAddrV4; +use std::sync::Arc; +use std::time::Duration; +use tokio::net::TcpStream; +use tokio::task; +use tokio::time::sleep; -#[tokio::main] -async fn main() { +pub async fn start() { setup(); - let conn = tokio::net::TcpStream::connect(&*EDGE_NODE_HOLDER).await.unwrap(); + 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().unwrap()).await; - - let conn = new_rmc_gateway_connection(conn, |r| Arc::new(OnlyRemote::::new(r))); - + conn.send( + Register(SocketAddrV4::new(*OWN_IP_PUBLIC, *SERVER_PORT)) + .to_data() + .unwrap(), + ) + .await; + let conn = new_rmc_gateway_connection(conn, |r| { + Arc::new(OnlyRemote::::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() - )) + .add_socket( + VirtualPort::new(1, 10), + Secure("6f599f81", SECURE_SERVER_ACCOUNT.clone()), + ) .await .expect("unable to add socket"); @@ -55,8 +63,7 @@ async fn main() { }; task::spawn(async move { - let mut stream - = match TcpStream::connect(*FORWARD_DESTINATION).await { + let mut stream = match TcpStream::connect(*FORWARD_DESTINATION).await { Ok(v) => v, Err(e) => { error!("unable to connect: {}", e); @@ -64,16 +71,21 @@ async fn main() { } }; - if let Err(e) = stream.send_buffer(&ConnectionInitData{ - prudpsock_addr: conn.socket_addr, - pid: conn.user_id - }.to_data().unwrap()).await{ + if let Err(e) = stream + .send_buffer( + &ConnectionInitData { + prudpsock_addr: conn.socket_addr, + pid: conn.user_id, + } + .to_data() + .unwrap(), + ) + .await + { error!("error connecting to backend: {}", e); return; }; - - loop { tokio::select! { data = conn.recv() => { @@ -94,7 +106,7 @@ async fn main() { return; } }; - + if conn.send(data).await == None{ return; } @@ -106,6 +118,6 @@ async fn main() { } }); } - + drop(conn); -} \ No newline at end of file +} diff --git a/prudpv1/src/lib.rs b/prudpv1/src/lib.rs index ed53644..40a46c7 100644 --- a/prudpv1/src/lib.rs +++ b/prudpv1/src/lib.rs @@ -1,2 +1,14 @@ -pub mod prudp; -pub mod executables; \ No newline at end of file +cfg_if::cfg_if! { + if #[cfg(feature = "prudpv1")]{ + use proxy_common::{ProxyStartupParam, setup_edge_node_connection}; + pub mod executables; + pub mod prudp; + pub async fn start_secure(param: ProxyStartupParam) { + executables::proxy_secure::start(); + } + + pub async fn start_insecure(param: ProxyStartupParam) { + executables::proxy_insecure::start(); + } + } +} diff --git a/prudpv1/src/prudp/secure.rs b/prudpv1/src/prudp/secure.rs index a9f7960..604ca58 100644 --- a/prudpv1/src/prudp/secure.rs +++ b/prudpv1/src/prudp/secure.rs @@ -23,7 +23,7 @@ pub fn read_secure_connection_data(data: &[u8], act: &Account) -> Option<([u8; 3 let ticket_data = &mut ticket_data[0..ticket_data_size - 0x10]; - let server_key = derive_key(act.pid, act.kerbros_password); + let server_key = derive_key(act.pid, &act.kerbros_password[..]); let mut rc4: StreamCipherCoreWrapper> = Rc4::new_from_slice(&server_key).expect("unable to init rc4 keystream"); diff --git a/rnex-core/Cargo.toml b/rnex-core/Cargo.toml index eaf0f5f..34034d9 100644 --- a/rnex-core/Cargo.toml +++ b/rnex-core/Cargo.toml @@ -32,6 +32,8 @@ ureq = "3.1.4" [features] rmc_struct_header = [] +guest_login = [] +friends = ["guest_login"] [[bench]] name = "rmc_serialization" diff --git a/rnex-core/src/kerberos/mod.rs b/rnex-core/src/kerberos/mod.rs index b118651..a5963d8 100644 --- a/rnex-core/src/kerberos/mod.rs +++ b/rnex-core/src/kerberos/mod.rs @@ -1,21 +1,26 @@ -use std::io::{Read, Write}; -use bytemuck::{bytes_of, Pod, Zeroable}; +use crate::rmc::structures::RmcSerialize; +use bytemuck::{Pod, Zeroable, bytes_of}; use chrono::{Datelike, NaiveDate, NaiveDateTime, NaiveTime, Timelike, Utc}; use hmac::Hmac; +use hmac::Mac; use md5::{Digest, Md5}; -use rc4::{Rc4, Rc4Core, StreamCipher}; +use rc4::KeyInit; use rc4::cipher::StreamCipherCoreWrapper; use rc4::consts::U16; -use hmac::Mac; -use rc4::KeyInit; -use crate::rmc::structures::RmcSerialize; +use rc4::{Rc4, Rc4Core, StreamCipher}; +use std::io::{Read, Write}; type Md5Hmac = Hmac; -pub fn derive_key(pid: u32, password: [u8; 16]) -> [u8; 16]{ - let iteration_count = 65000 + pid%1024; +pub fn derive_key(pid: u32, password: &[u8]) -> [u8; 16] { + let iteration_count = 65000 + pid % 1024 - 1; + // we do one iteration out here to ensure the key is always 16 bytes - let mut key = password; + let mut key: [u8; 16] = { + let mut md5 = Md5::new(); + md5.update(password); + md5.finalize().try_into().unwrap() + }; for _ in 0..iteration_count { let mut md5 = Md5::new(); @@ -29,12 +34,12 @@ pub fn derive_key(pid: u32, password: [u8; 16]) -> [u8; 16]{ #[repr(transparent)] pub struct KerberosDateTime(pub u64); -impl KerberosDateTime{ - pub fn new(second: u64, minute: u64, hour: u64, day: u64, month: u64, year:u64 ) -> Self { +impl KerberosDateTime { + pub fn new(second: u64, minute: u64, hour: u64, day: u64, month: u64, year: u64) -> Self { Self(second | (minute << 6) | (hour << 12) | (day << 17) | (month << 22) | (year << 26)) } - pub fn now() -> Self{ + pub fn now() -> Self { let now = chrono::Utc::now(); Self::new( now.second() as u64, @@ -47,42 +52,53 @@ impl KerberosDateTime{ } #[inline] - pub fn get_seconds(&self) -> u8{ + pub fn get_seconds(&self) -> u8 { (self.0 & 0b111111) as u8 } #[inline] - pub fn get_minutes(&self) -> u8{ + pub fn get_minutes(&self) -> u8 { ((self.0 >> 6) & 0b111111) as u8 } #[inline] - pub fn get_hours(&self) -> u8{ + pub fn get_hours(&self) -> u8 { ((self.0 >> 12) & 0b111111) as u8 } #[inline] - pub fn get_days(&self) -> u8{ + pub fn get_days(&self) -> u8 { ((self.0 >> 17) & 0b111111) as u8 } #[inline] - pub fn get_month(&self) -> u8{ + pub fn get_month(&self) -> u8 { ((self.0 >> 22) & 0b1111) as u8 } #[inline] - pub fn get_year(&self) -> u64{ + pub fn get_year(&self) -> u64 { (self.0 >> 26) & 0xFFFFFFFF } - pub fn to_regular_time(&self) -> chrono::DateTime{ + pub fn to_regular_time(&self) -> chrono::DateTime { NaiveDateTime::new( - NaiveDate::from_ymd_opt(self.get_year() as i32, self.get_month() as u32, self.get_days() as u32).unwrap(), - NaiveTime::from_hms_opt(self.get_hours() as u32, self.get_minutes() as u32, self.get_seconds() as u32).unwrap() - ).and_utc() + NaiveDate::from_ymd_opt( + self.get_year() as i32, + self.get_month() as u32, + self.get_days() as u32, + ) + .unwrap(), + NaiveTime::from_hms_opt( + self.get_hours() as u32, + self.get_minutes() as u32, + self.get_seconds() as u32, + ) + .unwrap(), + ) + .and_utc() } } -impl RmcSerialize for KerberosDateTime{ +impl RmcSerialize for KerberosDateTime { fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(self.0.serialize(writer)?) } @@ -94,22 +110,22 @@ impl RmcSerialize for KerberosDateTime{ #[derive(Pod, Zeroable, Copy, Clone)] #[repr(C, packed)] -pub struct TicketInternalData{ +pub struct TicketInternalData { pub issued_time: KerberosDateTime, pub pid: u32, pub session_key: [u8; 32], } -impl TicketInternalData{ - pub(crate) fn new(pid: u32) -> Self{ - Self{ +impl TicketInternalData { + pub(crate) fn new(pid: u32) -> Self { + Self { issued_time: KerberosDateTime::now(), pid, - session_key: rand::random() + session_key: rand::random(), } } - pub(crate) fn encrypt(&self, key: [u8; 16]) -> Box<[u8]>{ + pub(crate) fn encrypt(&self, key: [u8; 16]) -> Box<[u8]> { let mut data = bytes_of(self).to_vec(); let mut rc4: StreamCipherCoreWrapper> = Rc4::new_from_slice(&key).unwrap(); @@ -117,11 +133,13 @@ impl TicketInternalData{ let mut hmac = ::new_from_slice(&key).unwrap(); - hmac.write_all(&data[..]).expect("failed to write data to hmac"); + hmac.write_all(&data[..]) + .expect("failed to write data to hmac"); let hmac_result = &hmac.finalize().into_bytes()[..]; - data.write_all(&hmac_result).expect("failed to write data to vec"); + data.write_all(&hmac_result) + .expect("failed to write data to vec"); data.into_boxed_slice() } @@ -129,41 +147,44 @@ impl TicketInternalData{ #[derive(Pod, Zeroable, Copy, Clone)] #[repr(C, packed)] -pub struct Ticket{ +pub struct Ticket { pub session_key: [u8; 32], pub pid: u32, } -impl Ticket{ - pub fn encrypt(&self, key: [u8; 16], internal_data: &[u8]) -> Box<[u8]>{ +impl Ticket { + pub fn encrypt(&self, key: [u8; 16], internal_data: &[u8]) -> Box<[u8]> { let mut data = bytes_of(self).to_vec(); - internal_data.serialize(&mut data).expect("unable to write to vec"); + internal_data + .serialize(&mut data) + .expect("unable to write to vec"); let mut rc4: StreamCipherCoreWrapper> = Rc4::new_from_slice(&key).unwrap(); rc4.apply_keystream(&mut data); let mut hmac = ::new_from_slice(&key).unwrap(); - hmac.write_all(&data[..]).expect("failed to write data to hmac"); + hmac.write_all(&data[..]) + .expect("failed to write data to hmac"); let hmac_result = &hmac.finalize().into_bytes()[..]; - data.write_all(&hmac_result).expect("failed to write data to vec"); + data.write_all(&hmac_result) + .expect("failed to write data to vec"); data.into_boxed_slice() } } - #[cfg(test)] -mod test{ +mod test { use crate::kerberos::KerberosDateTime; #[test] - fn kerberos_time_convert_test(){ + fn kerberos_time_convert_test() { let time = KerberosDateTime(135904948834); println!("{}", time.to_regular_time().to_rfc2822()); } -} \ No newline at end of file +} diff --git a/rnex-core/src/nex/account.rs b/rnex-core/src/nex/account.rs index 75c53ce..0c7a6f0 100644 --- a/rnex-core/src/nex/account.rs +++ b/rnex-core/src/nex/account.rs @@ -1,39 +1,38 @@ use macros::RmcSerialize; -#[derive(RmcSerialize)] -#[derive(Clone)] -pub struct Account{ +#[derive(RmcSerialize, Clone)] +pub struct Account { pub pid: u32, pub username: String, pub kerbros_password: [u8; 16], } -impl Account{ - pub fn new(pid: u32, username: &str, passwd: &str) -> Self{ +impl Account { + pub fn new(pid: u32, username: &str, passwd: &str) -> Self { let passwd_data = passwd.as_bytes(); let mut passwd = [0u8; 16]; - for (idx, byte) in passwd_data.iter().enumerate(){ + for (idx, byte) in passwd_data.iter().enumerate() { passwd[idx] = *byte; } - Self{ + Self { kerbros_password: passwd, username: username.into(), - pid + pid, } } - pub fn new_raw_password(pid: u32, username: &str, passwd: [u8; 16]) -> Self{ - Self{ + pub fn new_raw_password(pid: u32, username: &str, passwd: [u8; 16]) -> Self { + Self { kerbros_password: passwd, username: username.into(), - pid + pid, } } - pub fn get_login_data(&self) -> (u32, [u8; 16]){ - (self.pid, self.kerbros_password) + pub fn get_login_data(&self) -> (u32, &[u8]) { + (self.pid, &self.kerbros_password) } -} \ No newline at end of file +} diff --git a/rnex-core/src/nex/auth_handler.rs b/rnex-core/src/nex/auth_handler.rs index 30b4fce..89afd7f 100644 --- a/rnex-core/src/nex/auth_handler.rs +++ b/rnex-core/src/nex/auth_handler.rs @@ -1,6 +1,7 @@ use crate::grpc::account; use crate::reggie::{RemoteEdgeNodeHolder, RemoteEdgeNodeManagement}; use crate::{define_rmc_proto, kerberos}; +use log::warn; use macros::rmc_struct; use rnex_core::kerberos::{KerberosDateTime, Ticket, derive_key}; use rnex_core::nex::account::Account; @@ -13,7 +14,7 @@ use rnex_core::rmc::structures::connection_data::ConnectionData; use rnex_core::rmc::structures::qresult::QResult; use std::hash::{DefaultHasher, Hasher}; use std::net::SocketAddrV4; -use std::sync::Arc; +use std::sync::{Arc, LazyLock, OnceLock}; define_rmc_proto!( proto AuthClientProtocol{ @@ -30,8 +31,8 @@ pub struct AuthHandler { } pub fn generate_ticket( - source_act_login_data: (u32, [u8; 16]), - dest_act_login_data: (u32, [u8; 16]), + source_act_login_data: (u32, &[u8]), + dest_act_login_data: (u32, &[u8]), ) -> Box<[u8]> { let source_key = derive_key(source_act_login_data.0, source_act_login_data.1); let dest_key = derive_key(dest_act_login_data.0, dest_act_login_data.1); @@ -68,27 +69,57 @@ fn station_url_from_sock_addr(sock_addr: SocketAddrV4) -> String { ) } +static GUEST_ACCOUNT: LazyLock = + LazyLock::new(|| Account::new(100, "guest", "MMQea3n!fsik")); + +impl AuthHandler { + pub async fn generate_ticket_from_name( + &self, + name: &str, + ) -> Result<(u32, Box<[u8]>), ErrorCode> { + #[cfg(feature = "guest_login")] + { + if name == GUEST_ACCOUNT.username { + let source_login_data = GUEST_ACCOUNT.get_login_data(); + let destination_login_data = self.destination_server_acct.get_login_data(); + + return Ok(( + source_login_data.0, + generate_ticket(source_login_data, destination_login_data), + )); + } + } + let Ok(pid) = name.parse() else { + warn!("unable to connect to parse pid: {}", name); + return Err(ErrorCode::Core_InvalidArgument); + }; + + let Ok(mut client) = account::Client::new().await else { + warn!("unable to connect to grpc"); + return Err(ErrorCode::Core_Exception); + }; + + let Ok(passwd) = client.get_nex_password(pid).await else { + warn!("unable to get nex password"); + return Err(ErrorCode::Core_Exception); + }; + + let source_login_data = (pid, &passwd[..]); + let destination_login_data = self.destination_server_acct.get_login_data(); + + Ok(( + pid, + generate_ticket(source_login_data, destination_login_data), + )) + } +} + impl Auth for AuthHandler { async fn login( &self, name: String, ) -> Result<(QResult, u32, Vec, ConnectionData, String), ErrorCode> { - let Ok(pid) = name.parse() else { - return Err(ErrorCode::Core_InvalidArgument); - }; - - let Ok(mut client) = account::Client::new().await else { - return Err(ErrorCode::Core_Exception); - }; - - let Ok(passwd) = client.get_nex_password(pid).await else { - return Err(ErrorCode::Core_Exception); - }; - - let source_login_data = (pid, passwd); - let destination_login_data = self.destination_server_acct.get_login_data(); - - let ticket = generate_ticket(source_login_data, destination_login_data); + let (pid, ticket) = self.generate_ticket_from_name(&name).await?; let result = QResult::success(Core_Unknown); @@ -97,6 +128,7 @@ impl Auth for AuthHandler { hasher.write(name.as_bytes()); let Ok(addr) = self.control_server.get_url(hasher.finish()).await else { + warn!("no secure proxies"); return Err(ErrorCode::Core_Exception); }; @@ -110,7 +142,7 @@ impl Auth for AuthHandler { Ok(( result, - source_login_data.0, + pid, ticket.into(), connection_data, self.build_name.to_string(), //format!("{}; Rust NEX Version {} by DJMrTV", self.build_name, env!("CARGO_PKG_VERSION")), @@ -130,22 +162,19 @@ impl Auth for AuthHandler { source_pid: u32, destination_pid: u32, ) -> Result<(QResult, Vec), ErrorCode> { - let Some(source_login_data) = get_login_data_by_pid(source_pid).await else { + let Some((pid, passwd)) = get_login_data_by_pid(source_pid).await else { return Err(ErrorCode::Core_Exception); }; let desgination_login_data = if destination_pid == self.destination_server_acct.pid { self.destination_server_acct.get_login_data() } else { - let Some(login) = get_login_data_by_pid(destination_pid).await else { - return Err(ErrorCode::Core_Exception); - }; - login + return Err(ErrorCode::RendezVous_InvalidOperation); }; let result = QResult::success(Core_Unknown); - let ticket = generate_ticket(source_login_data, desgination_login_data); + let ticket = generate_ticket((pid, &passwd[..]), desgination_login_data); Ok((result, ticket.into())) }