diff --git a/rnex-core/Cargo.toml b/rnex-core/Cargo.toml index 3a05177..d44c000 100644 --- a/rnex-core/Cargo.toml +++ b/rnex-core/Cargo.toml @@ -17,7 +17,7 @@ rand = "0.8.5" cfg-if = "1.0.4" hmac = "0.12.1" md-5 = "^0.10.6" -tokio = { version = "1.43.0", features = ["macros", "rt-multi-thread", "net", "sync", "fs"] } +tokio = { version = "1.43.0", features = ["full"] } hex = "0.4.3" macros = { path = "../macros" } diff --git a/rnex-core/src/kerberos/mod.rs b/rnex-core/src/kerberos/mod.rs index d02afa1..205c62a 100644 --- a/rnex-core/src/kerberos/mod.rs +++ b/rnex-core/src/kerberos/mod.rs @@ -161,7 +161,7 @@ impl TicketInternalData { } } -#[derive(Pod, Zeroable, Copy, Clone)] +#[derive(Pod, Zeroable, Debug, Copy, Clone)] #[repr(C, packed)] pub struct Ticket { pub session_key: [u8; SESSION_KEY_LENGTH], diff --git a/rnex-core/src/nex/auth_handler.rs b/rnex-core/src/nex/auth_handler.rs index 3fa5485..341dc93 100644 --- a/rnex-core/src/nex/auth_handler.rs +++ b/rnex-core/src/nex/auth_handler.rs @@ -134,6 +134,7 @@ impl AuthHandler { }; let source_login_data = (pid, &passwd[..]); + println!("{}, {:?}", pid, passwd); let destination_login_data = self.destination_server_acct.get_login_data(); Ok(( @@ -336,3 +337,82 @@ impl Auth for AuthHandler { Err(ErrorCode::Core_Exception) } } + +mod test { + use std::io::Cursor; + + use rc4::{KeyInit, Rc4, StreamCipher}; + use rnex_core::PID; + use rnex_core::kerberos::KerberosDateTime; + use rnex_core::rmc::structures::connection_data::ConnectionData; + use rnex_core::rmc::{ + response::ErrorCode, + structures::{RmcSerialize, qresult::QResult}, + }; + + use crate::kerberos::{self, derive_key}; + use crate::rmc; + use crate::rmc::message::RMCMessage; + use crate::rmc::response::{RMCResponse, RMCResponseResult}; + + #[test] + fn test() { + return; + let packet = [ + 26, 1, 0, 0, 10, 1, 30, 0, 0, 0, 1, 128, 0, 0, 1, 0, 1, 0, 86, 4, 0, 0, 116, 0, 0, 0, + 144, 209, 130, 175, 45, 215, 95, 55, 226, 192, 51, 54, 201, 84, 118, 150, 159, 164, 32, + 103, 134, 252, 199, 168, 178, 5, 6, 208, 206, 241, 94, 23, 136, 37, 109, 247, 156, 252, + 189, 233, 142, 115, 206, 72, 180, 57, 106, 223, 37, 59, 144, 208, 250, 197, 51, 202, + 185, 156, 51, 159, 219, 117, 250, 103, 184, 1, 103, 108, 15, 14, 174, 160, 192, 146, + 135, 10, 55, 125, 68, 181, 88, 127, 183, 34, 4, 213, 19, 146, 81, 56, 248, 213, 241, + 168, 205, 253, 29, 10, 123, 198, 177, 157, 247, 209, 113, 167, 231, 42, 214, 15, 12, + 200, 192, 230, 125, 227, 74, 0, 112, 114, 117, 100, 112, 115, 58, 47, 80, 73, 68, 61, + 50, 59, 115, 105, 100, 61, 49, 59, 115, 116, 114, 101, 97, 109, 61, 49, 48, 59, 116, + 121, 112, 101, 61, 50, 59, 97, 100, 100, 114, 101, 115, 115, 61, 57, 49, 46, 57, 56, + 46, 49, 50, 56, 46, 56, 54, 59, 112, 111, 114, 116, 61, 54, 48, 48, 49, 59, 67, 73, 68, + 61, 49, 0, 0, 0, 0, 0, 1, 0, 0, 162, 243, 240, 168, 31, 0, 0, 0, 51, 0, 98, 114, 97, + 110, 99, 104, 58, 111, 114, 105, 103, 105, 110, 47, 112, 114, 111, 106, 101, 99, 116, + 47, 119, 117, 112, 45, 97, 103, 109, 106, 32, 98, 117, 105, 108, 100, 58, 51, 95, 56, + 95, 49, 53, 95, 50, 48, 48, 52, 95, 48, 0, + ]; + let rmc_packet = RMCResponse::new(&mut Cursor::new(&packet)).unwrap(); + println!("{:?}", rmc_packet); + + let RMCResponseResult::Success { + call_id, + method_id, + data, + } = rmc_packet.response_result + else { + panic!(); + }; + + println!("{}", hex::encode(&data)); + + let mut data = + <(QResult, PID, Vec, ConnectionData, String) as RmcSerialize>::deserialize( + &mut Cursor::new(&data[..]), + ) + .unwrap(); + + println!("{:?}", data); + + let key = derive_key(1110, "AAAAAAAAAAAAAAAA".as_bytes()); + + let mut rc4 = Rc4::new((&key).into()); + + rc4.apply_keystream(&mut data.2); + println!("raw tick: {:?}", data.2); + + let tick: &kerberos::Ticket = + bytemuck::from_bytes(&data.2[..size_of::()]); + + let remainder = &data.2[size_of::()..]; + + println!("tick: {:?}", tick); + let data = as RmcSerialize>::deserialize(&mut Cursor::new(remainder)).unwrap(); + println!("inner ticket raw: {:?}", data); + + println!("{:?}", data); + } +} diff --git a/rnex-core/src/rmc/response.rs b/rnex-core/src/rmc/response.rs index c994f8b..b042877 100644 --- a/rnex-core/src/rmc/response.rs +++ b/rnex-core/src/rmc/response.rs @@ -2,17 +2,18 @@ // attributes but this gets it to not complain anymore #![allow(unused_parens)] -use std::io; -use std::io::{Read, Seek, Write}; -use std::mem::transmute; -use bytemuck::bytes_of; -use log::error; -use v_byte_helpers::EnumTryInto; -use v_byte_helpers::{ReadExtensions, IS_BIG_ENDIAN}; use crate::rmc::response::ErrorCode::Core_Exception; use crate::rmc::structures::qresult::ERROR_MASK; use crate::util::SendingBufferConnection; +use bytemuck::bytes_of; +use log::error; +use std::io; +use std::io::{Read, Seek, Write}; +use std::mem::transmute; +use v_byte_helpers::EnumTryInto; +use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; +#[derive(Debug, Clone)] pub enum RMCResponseResult { Success { call_id: u32, @@ -25,13 +26,14 @@ pub enum RMCResponseResult { }, } +#[derive(Debug, Clone)] pub struct RMCResponse { pub protocol_id: u8, pub response_result: RMCResponseResult, } impl RMCResponse { - pub fn new(stream: &mut (impl Seek + Read)) -> io::Result{ + pub fn new(stream: &mut (impl Seek + Read)) -> io::Result { // ignore the size for now this will only be used for checking let size: u32 = stream.read_struct(IS_BIG_ENDIAN)?; @@ -46,7 +48,7 @@ impl RMCResponse { let is_success: u8 = stream.read_struct(IS_BIG_ENDIAN)?; - let response_result = if is_success == 0x01{ + let response_result = if is_success == 0x01 { let call_id: u32 = stream.read_struct(IS_BIG_ENDIAN)?; let method_id: u32 = stream.read_struct(IS_BIG_ENDIAN)?; let method_id = method_id & (!0x8000); @@ -55,11 +57,10 @@ impl RMCResponse { stream.read(&mut data)?; - RMCResponseResult::Success { call_id, method_id, - data + data, } } else { let error_code: u32 = stream.read_struct(IS_BIG_ENDIAN)?; @@ -68,7 +69,7 @@ impl RMCResponse { RMCResponseResult::Error { error_code: { - match ErrorCode::try_from(error_code){ + match ErrorCode::try_from(error_code) { Ok(v) => v, Err(()) => { error!("invalid error code {:#010x}", error_code); @@ -77,36 +78,35 @@ impl RMCResponse { } }, call_id, - } }; - Ok(Self{ + Ok(Self { protocol_id, - response_result + response_result, }) } - pub fn get_call_id(&self) -> u32{ - match &self.response_result{ - RMCResponseResult::Success { call_id, ..} => *call_id, - RMCResponseResult::Error { call_id, .. } => *call_id + pub fn get_call_id(&self) -> u32 { + match &self.response_result { + RMCResponseResult::Success { call_id, .. } => *call_id, + RMCResponseResult::Error { call_id, .. } => *call_id, } } pub fn to_data(self) -> Vec { - generate_response(self.protocol_id, self.response_result).expect("failed to generate response") + generate_response(self.protocol_id, self.response_result) + .expect("failed to generate response") } } pub fn generate_response(protocol_id: u8, response: RMCResponseResult) -> io::Result> { - let size = 1 + 1 + match &response { - RMCResponseResult::Success { - data, - .. - } => 4 + 4 + data.len(), - RMCResponseResult::Error { .. } => 4 + 4, - }; + let size = 1 + + 1 + + match &response { + RMCResponseResult::Success { data, .. } => 4 + 4 + data.len(), + RMCResponseResult::Error { .. } => 4 + 4, + }; let mut data_out = Vec::with_capacity(size + 4); @@ -119,7 +119,7 @@ pub fn generate_response(protocol_id: u8, response: RMCResponseResult) -> io::Re RMCResponseResult::Success { call_id, method_id, - data + data, } => { data_out.push(1); data_out.write_all(bytes_of(&call_id))?; @@ -129,7 +129,7 @@ pub fn generate_response(protocol_id: u8, response: RMCResponseResult) -> io::Re } RMCResponseResult::Error { call_id, - error_code + error_code, } => { data_out.push(0); let error_code_val: u32 = error_code.into(); @@ -151,23 +151,21 @@ pub async fn send_result( method_id: u32, call_id: u32, ) { - let response_result = match result { Ok(v) => RMCResponseResult::Success { call_id, method_id, - data: v + data: v, + }, + Err(e) => RMCResponseResult::Error { + call_id, + error_code: e.into(), }, - Err(e) => - RMCResponseResult::Error { - call_id, - error_code: e.into() - } }; - let response = RMCResponse{ + let response = RMCResponse { response_result, - protocol_id + protocol_id, }; send_response(connection, response).await @@ -177,7 +175,6 @@ pub async fn send_response(connection: &SendingBufferConnection, rmcresponse: RM connection.send(rmcresponse.to_data()).await; } - //taken from kinnays error list directly #[allow(nonstandard_style)] #[repr(u32)] @@ -464,25 +461,23 @@ impl Into for ErrorCode { #[cfg(test)] mod test { - use hmac::digest::consts::U5; - use hmac::digest::KeyInit; - use rc4::{Rc4, StreamCipher}; use crate::rmc::response::ErrorCode; + use hmac::digest::KeyInit; + use hmac::digest::consts::U5; + use rc4::{Rc4, StreamCipher}; #[test] fn test() { let data_orig = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 69, 4, 20]; let mut data = data_orig; - let mut rc4: Rc4 = - Rc4::new_from_slice("FUCKE".as_bytes().into()).expect("invalid key"); + let mut rc4: Rc4 = Rc4::new_from_slice("FUCKE".as_bytes().into()).expect("invalid key"); rc4.apply_keystream(&mut data); assert_ne!(data_orig, data); - let mut rc4: Rc4 = - Rc4::new_from_slice("FUCKE".as_bytes().into()).expect("invalid key"); + let mut rc4: Rc4 = Rc4::new_from_slice("FUCKE".as_bytes().into()).expect("invalid key"); rc4.apply_keystream(&mut data); @@ -494,4 +489,4 @@ mod test { let val: u32 = ErrorCode::Core_Unknown.into(); assert_eq!(val, 0x00010001) } -} \ No newline at end of file +} diff --git a/rnex-core/src/rmc/structures/list.rs b/rnex-core/src/rmc/structures/list.rs index 890be9a..7c7db8e 100644 --- a/rnex-core/src/rmc/structures/list.rs +++ b/rnex-core/src/rmc/structures/list.rs @@ -1,19 +1,17 @@ +use crate::rmc::structures::RmcSerialize; +use bytemuck::bytes_of; use std::io::{Read, Write}; use std::mem::MaybeUninit; -use bytemuck::bytes_of; use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; -use crate::rmc::structures::RmcSerialize; - - -// this is also for implementing `Buffer` this is tecnically not the same as its handled internaly +// this is also for implementing `Buffer` this is tecnically not the same as its handled internaly // probably but as it has the same mapping it doesn't matter and simplifies things -impl RmcSerialize for Vec{ +impl RmcSerialize for Vec { fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { let u32_len = self.len() as u32; writer.write_all(bytes_of(&u32_len))?; - for e in self{ + for e in self { e.serialize(writer)?; } @@ -21,27 +19,31 @@ impl RmcSerialize for Vec{ } fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { + println!("reading list"); let len: u32 = reader.read_struct(IS_BIG_ENDIAN)?; + println!("readijg list: {:?}", len); //let mut vec = Vec::with_capacity(len as usize); - let vec = (0..len).map(|_| T::deserialize(reader)).collect::, _>>()?; + let vec: Vec = (0..len) + .map(|_| T::deserialize(reader)) + .collect::, _>>()?; Ok(vec) } - + fn serialize_write_size(&self) -> crate::rmc::structures::Result { let mut val = 0u32; - for i in self{ + for i in self { val += i.serialize_write_size()?; } Ok(4 + val) } } -impl RmcSerialize for [T; LEN]{ +impl RmcSerialize for [T; LEN] { fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { - for i in 0..LEN{ + for i in 0..LEN { self[i].serialize(writer)?; } @@ -51,20 +53,20 @@ impl RmcSerialize for [T; LEN]{ fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { let mut arr = [const { MaybeUninit::::uninit() }; LEN]; - for i in 0..LEN{ + for i in 0..LEN { arr[i] = MaybeUninit::new(T::deserialize(reader)?); } // all of the elements are now initialized so it is safe to assume they are initialized - let arr = arr.map(|v| unsafe{ v.assume_init() }); + let arr = arr.map(|v| unsafe { v.assume_init() }); Ok(arr) } #[inline(always)] fn serialize_write_size(&self) -> crate::rmc::structures::Result { let mut val = 0u32; - for i in self{ + for i in self { val += i.serialize_write_size()?; } Ok(val) diff --git a/rnex-core/src/rmc/structures/mod.rs b/rnex-core/src/rmc/structures/mod.rs index 7a1610c..996cc4b 100644 --- a/rnex-core/src/rmc/structures/mod.rs +++ b/rnex-core/src/rmc/structures/mod.rs @@ -1,12 +1,12 @@ -use std::{fmt, io}; +use crate::rmc::structures::helpers::DummyWriter; use std::io::{Read, Write}; use std::string::FromUtf8Error; +use std::{fmt, io}; use thiserror::Error; -use crate::rmc::structures::helpers::DummyWriter; //ideas for the future: make a proc macro library which allows generation of struct reads #[derive(Error, Debug)] -pub enum Error{ +pub enum Error { #[error("Io Error: {0}")] Io(#[from] io::Error), #[error("UTF8 conversion Error: {0}")] @@ -18,51 +18,52 @@ pub enum Error{ #[error("an error occurred reading the station url")] StationUrlInvalid, #[error("error formatting text: {0}")] - FormatError(#[from] fmt::Error) + FormatError(#[from] fmt::Error), } pub type Result = std::result::Result; -pub mod string; pub mod any; -pub mod qresult; pub mod buffer; pub mod connection_data; -pub mod rmc_struct; -pub mod list; -pub mod qbuffer; -pub mod primitives; -pub mod matchmake; -pub mod variant; -pub mod ranking; -pub mod networking; pub mod helpers; +pub mod list; +pub mod matchmake; +pub mod networking; +pub mod primitives; +pub mod qbuffer; +pub mod qresult; +pub mod ranking; +pub mod rmc_struct; +pub mod string; +pub mod variant; -pub trait RmcSerialize{ +pub trait RmcSerialize { fn serialize(&self, writer: &mut impl Write) -> Result<()>; - fn serialize_write_size(&self) -> Result{ + fn serialize_write_size(&self) -> Result { let mut dummy = DummyWriter::new(); self.serialize(&mut dummy)?; Ok(dummy.get_total_len()) } - fn deserialize(reader: &mut impl Read) -> Result where Self: Sized; + fn deserialize(reader: &mut impl Read) -> Result + where + Self: Sized; - fn to_data(&self) -> Result>{ - let mut data = Vec::with_capacity( - self.serialize_write_size()? as usize - ); + fn to_data(&self) -> Result> { + let expected_size = self.serialize_write_size()?; + let mut data = Vec::with_capacity(expected_size as usize); self.serialize(&mut data)?; - debug_assert_eq!(self.serialize_write_size().unwrap(), data.len() as u32); + debug_assert_eq!(expected_size, data.len() as u32); Ok(data) } } -impl RmcSerialize for (){ +impl RmcSerialize for () { fn serialize(&self, _writer: &mut impl Write) -> Result<()> { Ok(()) } @@ -72,6 +73,4 @@ impl RmcSerialize for (){ fn serialize_write_size(&self) -> Result { Ok(0) } - - -} \ No newline at end of file +} diff --git a/rnex-core/src/rmc/structures/primitives.rs b/rnex-core/src/rmc/structures/primitives.rs index e3888d4..6ce1c2f 100644 --- a/rnex-core/src/rmc/structures/primitives.rs +++ b/rnex-core/src/rmc/structures/primitives.rs @@ -280,8 +280,8 @@ impl Self{ +impl QResult { + pub fn success(error_code: ErrorCode) -> Self { let val: u32 = error_code.into(); Self(val & (!ERROR_MASK)) } - pub fn error(error_code: ErrorCode) -> Self{ + pub fn error(error_code: ErrorCode) -> Self { let val: u32 = error_code.into(); Self(val | ERROR_MASK) } } -impl RmcSerialize for QResult{ +impl RmcSerialize for QResult { fn serialize(&self, writer: &mut impl Write) -> Result<()> { writer.write(bytes_of(self))?; Ok(()) } fn deserialize(reader: &mut impl Read) -> Result { - Ok(reader.read_struct(IS_BIG_ENDIAN)?) + let result: Self = reader.read_struct(IS_BIG_ENDIAN)?; + println!("reading qresult: {:x}", result.0); + Ok(result) } -} \ No newline at end of file + fn serialize_write_size(&self) -> Result { + Ok(4) + } +} diff --git a/rnex-core/src/rmc/structures/rmc_struct.rs b/rnex-core/src/rmc/structures/rmc_struct.rs index 52184bb..7660f96 100644 --- a/rnex-core/src/rmc/structures/rmc_struct.rs +++ b/rnex-core/src/rmc/structures/rmc_struct.rs @@ -1,15 +1,13 @@ - +use crate::rmc::structures::Result; use std::cmp::max; use std::fmt::Arguments; use std::io; use std::io::{ErrorKind, IoSlice, Read, Write}; -use crate::rmc::structures::Result; - #[repr(C, packed)] -struct StructureHeader{ +struct StructureHeader { version: u8, - length: u32 + length: u32, } #[cfg(feature = "rmc_struct_header")] @@ -38,7 +36,12 @@ impl Write for OnlyWriteVec<'_> { } #[cfg(feature = "rmc_struct_header")] -pub fn write_struct(writer: &mut T, version: u8, inner_size: u32, pred: impl FnOnce(&mut T) -> Result<()> ) -> Result<()> { +pub fn write_struct( + writer: &mut T, + version: u8, + inner_size: u32, + pred: impl FnOnce(&mut T) -> Result<()>, +) -> Result<()> { use bytemuck::bytes_of; writer.write_all(&[version])?; @@ -50,29 +53,31 @@ pub fn write_struct(writer: &mut T, version: u8, inner_size: u32, pred Ok(()) } - - #[cfg(not(feature = "rmc_struct_header"))] -pub fn write_struct(writer: &mut T, _version: u8, _inner_size: u32, pred: impl FnOnce(&mut T) -> Result<()> ) -> Result<()> { +pub fn write_struct( + writer: &mut T, + _version: u8, + _inner_size: u32, + pred: impl FnOnce(&mut T) -> Result<()>, +) -> Result<()> { pred(writer) } - -pub struct SubRead<'a, T: Read>{ +pub struct SubRead<'a, T: Read> { left_to_read: usize, - origin: &'a mut T + origin: &'a mut T, } -impl<'a, T: Read> SubRead<'a, T>{ - pub const fn new(origin: &'a mut T, left_to_read: usize) -> Self{ - Self{ +impl<'a, T: Read> SubRead<'a, T> { + pub const fn new(origin: &'a mut T, left_to_read: usize) -> Self { + Self { left_to_read, - origin + origin, } } } -impl Read for SubRead<'_, T>{ +impl Read for SubRead<'_, T> { #[inline(always)] fn read(&mut self, buf: &mut [u8]) -> io::Result { let max_read = max(self.left_to_read, buf.len()); @@ -83,8 +88,11 @@ impl Read for SubRead<'_, T>{ #[inline(always)] fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { - if buf.len() > self.left_to_read{ - return Err(io::Error::new(ErrorKind::UnexpectedEof, "Would run over end of SubRead")); + if buf.len() > self.left_to_read { + return Err(io::Error::new( + ErrorKind::UnexpectedEof, + "Would run over end of SubRead", + )); } self.left_to_read -= buf.len(); self.origin.read_exact(buf) @@ -92,10 +100,14 @@ impl Read for SubRead<'_, T>{ } #[cfg(feature = "rmc_struct_header")] -pub fn read_struct(reader: &mut R, version: u8, pred: impl FnOnce(&mut SubRead) -> Result) -> Result { +pub fn read_struct( + reader: &mut R, + version: u8, + pred: impl FnOnce(&mut SubRead) -> Result, +) -> Result { use crate::rmc::structures::Error::VersionMismatch; - use v_byte_helpers::ReadExtensions; use v_byte_helpers::IS_BIG_ENDIAN; + use v_byte_helpers::ReadExtensions; let ver: u8 = reader.read_struct(IS_BIG_ENDIAN)?; if ver != version { @@ -108,6 +120,10 @@ pub fn read_struct(reader: &mut R, version: u8, pred: impl Fn } #[cfg(not(feature = "rmc_struct_header"))] -pub fn read_struct(mut reader: &mut R, _version: u8, pred: impl FnOnce(&mut R) -> Result) -> Result { +pub fn read_struct( + mut reader: &mut R, + _version: u8, + pred: impl FnOnce(&mut R) -> Result, +) -> Result { Ok(pred(&mut reader)?) } diff --git a/rnex-core/src/rmc/structures/string.rs b/rnex-core/src/rmc/structures/string.rs index 1231956..8830822 100644 --- a/rnex-core/src/rmc/structures/string.rs +++ b/rnex-core/src/rmc/structures/string.rs @@ -1,18 +1,18 @@ -use std::io::{Read, Write}; +use super::{Result, RmcSerialize}; use bytemuck::bytes_of; use log::error; +use std::io::{Read, Write}; use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; -use super::{Result, RmcSerialize}; -impl RmcSerialize for String{ +impl RmcSerialize for String { fn deserialize(reader: &mut impl Read) -> Result { let len: u16 = reader.read_struct(IS_BIG_ENDIAN)?; - if len == 0{ + if len == 0 { return Ok("".to_string()); } let mut data = vec![0; len as usize]; reader.read_exact(&mut data)?; - if *data.last().unwrap() != 0{ + if *data.last().unwrap() != 0 { error!("unable to find null terminator... continuing anyways"); } data.pop(); @@ -27,7 +27,7 @@ impl RmcSerialize for String{ } } -impl RmcSerialize for &str{ +impl RmcSerialize for &str { fn deserialize(_reader: &mut impl Read) -> Result { panic!("cannot serialize to &str") } @@ -45,4 +45,3 @@ impl RmcSerialize for &str{ Ok(2 + self.as_bytes().len() as u32 + 1) } } -