add debug logging to ticket generation for debugging

This commit is contained in:
Maple 2026-03-24 23:17:22 +01:00
commit 4ad883a54d
10 changed files with 223 additions and 127 deletions

View file

@ -17,7 +17,7 @@ rand = "0.8.5"
cfg-if = "1.0.4" cfg-if = "1.0.4"
hmac = "0.12.1" hmac = "0.12.1"
md-5 = "^0.10.6" 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" hex = "0.4.3"
macros = { path = "../macros" } macros = { path = "../macros" }

View file

@ -161,7 +161,7 @@ impl TicketInternalData {
} }
} }
#[derive(Pod, Zeroable, Copy, Clone)] #[derive(Pod, Zeroable, Debug, Copy, Clone)]
#[repr(C, packed)] #[repr(C, packed)]
pub struct Ticket { pub struct Ticket {
pub session_key: [u8; SESSION_KEY_LENGTH], pub session_key: [u8; SESSION_KEY_LENGTH],

View file

@ -134,6 +134,7 @@ impl AuthHandler {
}; };
let source_login_data = (pid, &passwd[..]); let source_login_data = (pid, &passwd[..]);
println!("{}, {:?}", pid, passwd);
let destination_login_data = self.destination_server_acct.get_login_data(); let destination_login_data = self.destination_server_acct.get_login_data();
Ok(( Ok((
@ -336,3 +337,82 @@ impl Auth for AuthHandler {
Err(ErrorCode::Core_Exception) 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<u8>, 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::<kerberos::Ticket>()]);
let remainder = &data.2[size_of::<kerberos::Ticket>()..];
println!("tick: {:?}", tick);
let data = <Vec<u8> as RmcSerialize>::deserialize(&mut Cursor::new(remainder)).unwrap();
println!("inner ticket raw: {:?}", data);
println!("{:?}", data);
}
}

View file

@ -2,17 +2,18 @@
// attributes but this gets it to not complain anymore // attributes but this gets it to not complain anymore
#![allow(unused_parens)] #![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::response::ErrorCode::Core_Exception;
use crate::rmc::structures::qresult::ERROR_MASK; use crate::rmc::structures::qresult::ERROR_MASK;
use crate::util::SendingBufferConnection; 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 { pub enum RMCResponseResult {
Success { Success {
call_id: u32, call_id: u32,
@ -25,6 +26,7 @@ pub enum RMCResponseResult {
}, },
} }
#[derive(Debug, Clone)]
pub struct RMCResponse { pub struct RMCResponse {
pub protocol_id: u8, pub protocol_id: u8,
pub response_result: RMCResponseResult, pub response_result: RMCResponseResult,
@ -55,11 +57,10 @@ impl RMCResponse {
stream.read(&mut data)?; stream.read(&mut data)?;
RMCResponseResult::Success { RMCResponseResult::Success {
call_id, call_id,
method_id, method_id,
data data,
} }
} else { } else {
let error_code: u32 = stream.read_struct(IS_BIG_ENDIAN)?; let error_code: u32 = stream.read_struct(IS_BIG_ENDIAN)?;
@ -77,34 +78,33 @@ impl RMCResponse {
} }
}, },
call_id, call_id,
} }
}; };
Ok(Self { Ok(Self {
protocol_id, protocol_id,
response_result response_result,
}) })
} }
pub fn get_call_id(&self) -> u32 { pub fn get_call_id(&self) -> u32 {
match &self.response_result { match &self.response_result {
RMCResponseResult::Success { call_id, .. } => *call_id, RMCResponseResult::Success { call_id, .. } => *call_id,
RMCResponseResult::Error { call_id, .. } => *call_id RMCResponseResult::Error { call_id, .. } => *call_id,
} }
} }
pub fn to_data(self) -> Vec<u8> { pub fn to_data(self) -> Vec<u8> {
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<Vec<u8>> { pub fn generate_response(protocol_id: u8, response: RMCResponseResult) -> io::Result<Vec<u8>> {
let size = 1 + 1 + match &response { let size = 1
RMCResponseResult::Success { + 1
data, + match &response {
.. RMCResponseResult::Success { data, .. } => 4 + 4 + data.len(),
} => 4 + 4 + data.len(),
RMCResponseResult::Error { .. } => 4 + 4, RMCResponseResult::Error { .. } => 4 + 4,
}; };
@ -119,7 +119,7 @@ pub fn generate_response(protocol_id: u8, response: RMCResponseResult) -> io::Re
RMCResponseResult::Success { RMCResponseResult::Success {
call_id, call_id,
method_id, method_id,
data data,
} => { } => {
data_out.push(1); data_out.push(1);
data_out.write_all(bytes_of(&call_id))?; 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 { RMCResponseResult::Error {
call_id, call_id,
error_code error_code,
} => { } => {
data_out.push(0); data_out.push(0);
let error_code_val: u32 = error_code.into(); let error_code_val: u32 = error_code.into();
@ -151,23 +151,21 @@ pub async fn send_result(
method_id: u32, method_id: u32,
call_id: u32, call_id: u32,
) { ) {
let response_result = match result { let response_result = match result {
Ok(v) => RMCResponseResult::Success { Ok(v) => RMCResponseResult::Success {
call_id, call_id,
method_id, method_id,
data: v data: v,
}, },
Err(e) => Err(e) => RMCResponseResult::Error {
RMCResponseResult::Error {
call_id, call_id,
error_code: e.into() error_code: e.into(),
} },
}; };
let response = RMCResponse { let response = RMCResponse {
response_result, response_result,
protocol_id protocol_id,
}; };
send_response(connection, response).await send_response(connection, response).await
@ -177,7 +175,6 @@ pub async fn send_response(connection: &SendingBufferConnection, rmcresponse: RM
connection.send(rmcresponse.to_data()).await; connection.send(rmcresponse.to_data()).await;
} }
//taken from kinnays error list directly //taken from kinnays error list directly
#[allow(nonstandard_style)] #[allow(nonstandard_style)]
#[repr(u32)] #[repr(u32)]
@ -464,25 +461,23 @@ impl Into<u32> for ErrorCode {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use hmac::digest::consts::U5;
use hmac::digest::KeyInit;
use rc4::{Rc4, StreamCipher};
use crate::rmc::response::ErrorCode; use crate::rmc::response::ErrorCode;
use hmac::digest::KeyInit;
use hmac::digest::consts::U5;
use rc4::{Rc4, StreamCipher};
#[test] #[test]
fn test() { fn test() {
let data_orig = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 69, 4, 20]; let data_orig = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 69, 4, 20];
let mut data = data_orig; let mut data = data_orig;
let mut rc4: Rc4<U5> = let mut rc4: Rc4<U5> = Rc4::new_from_slice("FUCKE".as_bytes().into()).expect("invalid key");
Rc4::new_from_slice("FUCKE".as_bytes().into()).expect("invalid key");
rc4.apply_keystream(&mut data); rc4.apply_keystream(&mut data);
assert_ne!(data_orig, data); assert_ne!(data_orig, data);
let mut rc4: Rc4<U5> = let mut rc4: Rc4<U5> = Rc4::new_from_slice("FUCKE".as_bytes().into()).expect("invalid key");
Rc4::new_from_slice("FUCKE".as_bytes().into()).expect("invalid key");
rc4.apply_keystream(&mut data); rc4.apply_keystream(&mut data);

View file

@ -1,10 +1,8 @@
use crate::rmc::structures::RmcSerialize;
use bytemuck::bytes_of;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::mem::MaybeUninit; use std::mem::MaybeUninit;
use bytemuck::bytes_of;
use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; 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 // probably but as it has the same mapping it doesn't matter and simplifies things
@ -21,11 +19,15 @@ impl<T: RmcSerialize> RmcSerialize for Vec<T>{
} }
fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result<Self> { fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result<Self> {
println!("reading list");
let len: u32 = reader.read_struct(IS_BIG_ENDIAN)?; let len: u32 = reader.read_struct(IS_BIG_ENDIAN)?;
println!("readijg list: {:?}", len);
//let mut vec = Vec::with_capacity(len as usize); //let mut vec = Vec::with_capacity(len as usize);
let vec = (0..len).map(|_| T::deserialize(reader)).collect::<Result<Vec<_>, _>>()?; let vec: Vec<T> = (0..len)
.map(|_| T::deserialize(reader))
.collect::<Result<Vec<_>, _>>()?;
Ok(vec) Ok(vec)
} }

View file

@ -1,8 +1,8 @@
use std::{fmt, io}; use crate::rmc::structures::helpers::DummyWriter;
use std::io::{Read, Write}; use std::io::{Read, Write};
use std::string::FromUtf8Error; use std::string::FromUtf8Error;
use std::{fmt, io};
use thiserror::Error; use thiserror::Error;
use crate::rmc::structures::helpers::DummyWriter;
//ideas for the future: make a proc macro library which allows generation of struct reads //ideas for the future: make a proc macro library which allows generation of struct reads
#[derive(Error, Debug)] #[derive(Error, Debug)]
@ -18,25 +18,25 @@ pub enum Error{
#[error("an error occurred reading the station url")] #[error("an error occurred reading the station url")]
StationUrlInvalid, StationUrlInvalid,
#[error("error formatting text: {0}")] #[error("error formatting text: {0}")]
FormatError(#[from] fmt::Error) FormatError(#[from] fmt::Error),
} }
pub type Result<T> = std::result::Result<T, Error>; pub type Result<T> = std::result::Result<T, Error>;
pub mod string;
pub mod any; pub mod any;
pub mod qresult;
pub mod buffer; pub mod buffer;
pub mod connection_data; 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 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(&self, writer: &mut impl Write) -> Result<()>;
@ -47,16 +47,17 @@ pub trait RmcSerialize{
Ok(dummy.get_total_len()) Ok(dummy.get_total_len())
} }
fn deserialize(reader: &mut impl Read) -> Result<Self> where Self: Sized; fn deserialize(reader: &mut impl Read) -> Result<Self>
where
Self: Sized;
fn to_data(&self) -> Result<Vec<u8>> { fn to_data(&self) -> Result<Vec<u8>> {
let mut data = Vec::with_capacity( let expected_size = self.serialize_write_size()?;
self.serialize_write_size()? as usize let mut data = Vec::with_capacity(expected_size as usize);
);
self.serialize(&mut data)?; 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) Ok(data)
} }
@ -72,6 +73,4 @@ impl RmcSerialize for (){
fn serialize_write_size(&self) -> Result<u32> { fn serialize_write_size(&self) -> Result<u32> {
Ok(0) Ok(0)
} }
} }

View file

@ -280,8 +280,8 @@ impl<T: RmcSerialize, U: RmcSerialize, V: RmcSerialize, W: RmcSerialize, X: RmcS
Ok(self.0.serialize_write_size()? Ok(self.0.serialize_write_size()?
+ self.1.serialize_write_size()? + self.1.serialize_write_size()?
+ self.2.serialize_write_size()? + self.2.serialize_write_size()?
+ self.2.serialize_write_size()? + self.3.serialize_write_size()?
+ self.3.serialize_write_size()?) + self.4.serialize_write_size()?)
} }
} }

View file

@ -1,9 +1,9 @@
use crate::rmc::response::ErrorCode;
use crate::rmc::structures::{Result, RmcSerialize};
use bytemuck::{Pod, Zeroable, bytes_of};
use std::io::{Read, Write}; use std::io::{Read, Write};
use bytemuck::{bytes_of, Pod, Zeroable};
use v_byte_helpers::SwapEndian; use v_byte_helpers::SwapEndian;
use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions};
use crate::rmc::response::ErrorCode;
use crate::rmc::structures::{RmcSerialize, Result};
pub const ERROR_MASK: u32 = 1 << 31; pub const ERROR_MASK: u32 = 1 << 31;
@ -32,6 +32,11 @@ impl RmcSerialize for QResult{
} }
fn deserialize(reader: &mut impl Read) -> Result<Self> { fn deserialize(reader: &mut impl Read) -> Result<Self> {
Ok(reader.read_struct(IS_BIG_ENDIAN)?) let result: Self = reader.read_struct(IS_BIG_ENDIAN)?;
println!("reading qresult: {:x}", result.0);
Ok(result)
}
fn serialize_write_size(&self) -> Result<u32> {
Ok(4)
} }
} }

View file

@ -1,15 +1,13 @@
use crate::rmc::structures::Result;
use std::cmp::max; use std::cmp::max;
use std::fmt::Arguments; use std::fmt::Arguments;
use std::io; use std::io;
use std::io::{ErrorKind, IoSlice, Read, Write}; use std::io::{ErrorKind, IoSlice, Read, Write};
use crate::rmc::structures::Result;
#[repr(C, packed)] #[repr(C, packed)]
struct StructureHeader { struct StructureHeader {
version: u8, version: u8,
length: u32 length: u32,
} }
#[cfg(feature = "rmc_struct_header")] #[cfg(feature = "rmc_struct_header")]
@ -38,7 +36,12 @@ impl Write for OnlyWriteVec<'_> {
} }
#[cfg(feature = "rmc_struct_header")] #[cfg(feature = "rmc_struct_header")]
pub fn write_struct<T: Write>(writer: &mut T, version: u8, inner_size: u32, pred: impl FnOnce(&mut T) -> Result<()> ) -> Result<()> { pub fn write_struct<T: Write>(
writer: &mut T,
version: u8,
inner_size: u32,
pred: impl FnOnce(&mut T) -> Result<()>,
) -> Result<()> {
use bytemuck::bytes_of; use bytemuck::bytes_of;
writer.write_all(&[version])?; writer.write_all(&[version])?;
@ -50,24 +53,26 @@ pub fn write_struct<T: Write>(writer: &mut T, version: u8, inner_size: u32, pred
Ok(()) Ok(())
} }
#[cfg(not(feature = "rmc_struct_header"))] #[cfg(not(feature = "rmc_struct_header"))]
pub fn write_struct<T: Write>(writer: &mut T, _version: u8, _inner_size: u32, pred: impl FnOnce(&mut T) -> Result<()> ) -> Result<()> { pub fn write_struct<T: Write>(
writer: &mut T,
_version: u8,
_inner_size: u32,
pred: impl FnOnce(&mut T) -> Result<()>,
) -> Result<()> {
pred(writer) pred(writer)
} }
pub struct SubRead<'a, T: Read> { pub struct SubRead<'a, T: Read> {
left_to_read: usize, left_to_read: usize,
origin: &'a mut T origin: &'a mut T,
} }
impl<'a, T: Read> SubRead<'a, T> { impl<'a, T: Read> SubRead<'a, T> {
pub const fn new(origin: &'a mut T, left_to_read: usize) -> Self { pub const fn new(origin: &'a mut T, left_to_read: usize) -> Self {
Self { Self {
left_to_read, left_to_read,
origin origin,
} }
} }
} }
@ -84,7 +89,10 @@ impl<T: Read> Read for SubRead<'_, T>{
#[inline(always)] #[inline(always)]
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> { fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
if buf.len() > self.left_to_read { if buf.len() > self.left_to_read {
return Err(io::Error::new(ErrorKind::UnexpectedEof, "Would run over end of SubRead")); return Err(io::Error::new(
ErrorKind::UnexpectedEof,
"Would run over end of SubRead",
));
} }
self.left_to_read -= buf.len(); self.left_to_read -= buf.len();
self.origin.read_exact(buf) self.origin.read_exact(buf)
@ -92,10 +100,14 @@ impl<T: Read> Read for SubRead<'_, T>{
} }
#[cfg(feature = "rmc_struct_header")] #[cfg(feature = "rmc_struct_header")]
pub fn read_struct<T: Sized, R: Read>(reader: &mut R, version: u8, pred: impl FnOnce(&mut SubRead<R>) -> Result<T>) -> Result<T> { pub fn read_struct<T: Sized, R: Read>(
reader: &mut R,
version: u8,
pred: impl FnOnce(&mut SubRead<R>) -> Result<T>,
) -> Result<T> {
use crate::rmc::structures::Error::VersionMismatch; use crate::rmc::structures::Error::VersionMismatch;
use v_byte_helpers::ReadExtensions;
use v_byte_helpers::IS_BIG_ENDIAN; use v_byte_helpers::IS_BIG_ENDIAN;
use v_byte_helpers::ReadExtensions;
let ver: u8 = reader.read_struct(IS_BIG_ENDIAN)?; let ver: u8 = reader.read_struct(IS_BIG_ENDIAN)?;
if ver != version { if ver != version {
@ -108,6 +120,10 @@ pub fn read_struct<T: Sized, R: Read>(reader: &mut R, version: u8, pred: impl Fn
} }
#[cfg(not(feature = "rmc_struct_header"))] #[cfg(not(feature = "rmc_struct_header"))]
pub fn read_struct<T: Sized, R: Read>(mut reader: &mut R, _version: u8, pred: impl FnOnce(&mut R) -> Result<T>) -> Result<T> { pub fn read_struct<T: Sized, R: Read>(
mut reader: &mut R,
_version: u8,
pred: impl FnOnce(&mut R) -> Result<T>,
) -> Result<T> {
Ok(pred(&mut reader)?) Ok(pred(&mut reader)?)
} }

View file

@ -1,8 +1,8 @@
use std::io::{Read, Write}; use super::{Result, RmcSerialize};
use bytemuck::bytes_of; use bytemuck::bytes_of;
use log::error; use log::error;
use std::io::{Read, Write};
use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; 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<Self> { fn deserialize(reader: &mut impl Read) -> Result<Self> {
@ -45,4 +45,3 @@ impl RmcSerialize for &str{
Ok(2 + self.as_bytes().len() as u32 + 1) Ok(2 + self.as_bytes().len() as u32 + 1)
} }
} }