From d01acbb9316027273f60354e60475db0d7b5562d Mon Sep 17 00:00:00 2001 From: DJMrTV Date: Tue, 4 Feb 2025 22:07:22 +0100 Subject: [PATCH] feat(secure): add get_playing_session and start working on auto_matchmake_with_param_postpone with RmcSerialize macro --- Cargo.lock | 10 ++ Cargo.toml | 2 + src/endianness.rs | 10 +- src/kerberos/mod.rs | 10 ++ src/main.rs | 17 +++- src/protocols/matchmake_common/mod.rs | 4 + ...thod_auto_matchmake_with_param_postpone.rs | 9 ++ .../method_get_playing_session.rs | 32 +++++++ src/protocols/matchmake_extension/mod.rs | 14 +++ src/protocols/mod.rs | 12 ++- src/rmc/structures/buffer.rs | 16 ---- src/rmc/structures/matchmake.rs | 54 +++++++++++ src/rmc/structures/mod.rs | 11 ++- src/rmc/structures/primitives.rs | 94 +++++++++++++++++++ src/rmc/structures/rmc_struct.rs | 3 +- src/rmc/structures/variant.rs | 63 +++++++++++++ 16 files changed, 338 insertions(+), 23 deletions(-) create mode 100644 src/protocols/matchmake_common/mod.rs create mode 100644 src/protocols/matchmake_extension/method_auto_matchmake_with_param_postpone.rs create mode 100644 src/protocols/matchmake_extension/method_get_playing_session.rs create mode 100644 src/protocols/matchmake_extension/mod.rs create mode 100644 src/rmc/structures/matchmake.rs create mode 100644 src/rmc/structures/primitives.rs create mode 100644 src/rmc/structures/variant.rs diff --git a/Cargo.lock b/Cargo.lock index 6a6450c..0fbdcee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -798,6 +798,15 @@ version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" +[[package]] +name = "macros" +version = "0.0.0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "matchit" version = "0.7.3" @@ -1313,6 +1322,7 @@ dependencies = [ "hex", "hmac", "log", + "macros", "md-5", "once_cell", "prost", diff --git a/Cargo.toml b/Cargo.toml index 6af8066..60d636d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,5 +24,7 @@ tonic = "0.12.3" prost = "0.13.4" hex = "0.4.3" +macros = { path = "macros" } + [build-dependencies] tonic-build = "0.12.3" \ No newline at end of file diff --git a/src/endianness.rs b/src/endianness.rs index a1f48d3..160b1a1 100644 --- a/src/endianness.rs +++ b/src/endianness.rs @@ -1,4 +1,4 @@ -use std::io; +use std::{io, mem}; use std::io::Read; use std::marker::PhantomData; use bytemuck::Pod; @@ -162,6 +162,14 @@ impl SwapEndian for u64{ } } +impl SwapEndian for f64{ + #[inline] + fn swap_endian(self) -> Self { + //trust me this is safe + unsafe{ mem::transmute::<_, f64>(mem::transmute::<_, u64>(self).swap_bytes()) } + } +} + impl SwapEndian for i8{ #[inline] fn swap_endian(self) -> Self { diff --git a/src/kerberos/mod.rs b/src/kerberos/mod.rs index 83fb89f..dac31fb 100644 --- a/src/kerberos/mod.rs +++ b/src/kerberos/mod.rs @@ -82,6 +82,16 @@ impl KerberosDateTime{ } } +impl RmcSerialize for KerberosDateTime{ + fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + Ok(self.0.serialize(writer)?) + } + + fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + Ok(Self(u64::deserialize(reader)?)) + } +} + #[derive(Pod, Zeroable, Copy, Clone)] #[repr(C, packed)] pub struct TicketInternalData{ diff --git a/src/main.rs b/src/main.rs index aa0d0b4..d893311 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,14 +6,17 @@ use std::net::{Ipv4Addr, SocketAddrV4}; use std::sync::Arc; use chrono::Local; use log::info; +use macros::RmcSerialize; use once_cell::sync::Lazy; use rc4::{KeyInit, Rc4, StreamCipher}; use rc4::consts::U5; use simplelog::{ColorChoice, CombinedLogger, Config, LevelFilter, TerminalMode, TermLogger, WriteLogger}; +use tokio::sync::Mutex; use tokio::task::JoinHandle; use crate::nex::account::Account; use crate::protocols::auth; use crate::protocols::auth::AuthProtocolConfig; +use crate::protocols::matchmake_common::MatchmakeData; use crate::protocols::server::RMCProtocolServer; use crate::prudp::socket::{ActiveSecureConnectionData, EncryptionPair, Socket}; use crate::prudp::packet::{PRUDPPacket, VirtualPort}; @@ -21,6 +24,7 @@ use crate::prudp::router::Router; use crate::prudp::secure::{generate_secure_encryption_pairs, read_secure_connection_data}; use crate::rmc::message::RMCMessage; use crate::rmc::structures::RmcSerialize; +use crate::rmc::structures::variant::Variant; mod endianness; mod prudp; @@ -166,8 +170,13 @@ async fn start_secure_server() -> SecureServer{ info!("setting up endpoints"); + let matchmake_data = Arc::new(Mutex::new( + MatchmakeData{} + )); + let rmcserver = RMCProtocolServer::new(Box::new([ - Box::new(protocols::secure::bound_protocol()) + Box::new(protocols::secure::bound_protocol()), + Box::new(protocols::matchmake_extension::bound_protocol(matchmake_data)) ])); let mut socket = @@ -274,4 +283,10 @@ mod test{ println!("packet: {:?}", packet); } +} + +#[derive(RmcSerialize)] +#[rmc_struct(0)] +struct MatchmakeParam{ + params: Vec<(String, Variant)> } \ No newline at end of file diff --git a/src/protocols/matchmake_common/mod.rs b/src/protocols/matchmake_common/mod.rs new file mode 100644 index 0000000..ed88475 --- /dev/null +++ b/src/protocols/matchmake_common/mod.rs @@ -0,0 +1,4 @@ +pub struct MatchmakeData{ + +} + diff --git a/src/protocols/matchmake_extension/method_auto_matchmake_with_param_postpone.rs b/src/protocols/matchmake_extension/method_auto_matchmake_with_param_postpone.rs new file mode 100644 index 0000000..fd90c5c --- /dev/null +++ b/src/protocols/matchmake_extension/method_auto_matchmake_with_param_postpone.rs @@ -0,0 +1,9 @@ +use std::sync::Arc; +use tokio::sync::Mutex; +use crate::protocols::matchmake_common::MatchmakeData; +use crate::prudp::socket::ConnectionData; +use crate::rmc::message::RMCMessage; + +pub async fn auto_matchmake_with_param_postpone_raw_params(rmcmessage: &RMCMessage, _: &mut ConnectionData, data: Arc>){ + +} \ No newline at end of file diff --git a/src/protocols/matchmake_extension/method_get_playing_session.rs b/src/protocols/matchmake_extension/method_get_playing_session.rs new file mode 100644 index 0000000..c82f730 --- /dev/null +++ b/src/protocols/matchmake_extension/method_get_playing_session.rs @@ -0,0 +1,32 @@ +use std::io::Cursor; +use std::sync::Arc; +use tokio::sync::Mutex; +use crate::protocols::matchmake_common::MatchmakeData; +use crate::prudp::socket::ConnectionData; +use crate::rmc::message::RMCMessage; +use crate::rmc::response::{ErrorCode, RMCResponseResult}; +use crate::rmc::structures::RmcSerialize; + +type PIDList = Vec; + +async fn get_playing_session(rmcmessage: &RMCMessage, data: Arc>) -> RMCResponseResult { + //todo: propperly implement this + + let cheeseburger = PIDList::new(); + + let mut vec = Vec::new(); + + cheeseburger.serialize(&mut vec).expect("somehow unable to write cheeseburger"); + + rmcmessage.success_with_data(vec) +} + +pub async fn get_playing_session_raw_params(rmcmessage: &RMCMessage, _: &mut ConnectionData, data: Arc>) -> RMCResponseResult{ + let mut reader = Cursor::new(&rmcmessage.rest_of_data); + + let Ok(list) = PIDList::deserialize(&mut reader) else { + return rmcmessage.error_result_with_code(ErrorCode::FPD_FriendNotExists); + }; + + get_playing_session(rmcmessage, data).await +} \ No newline at end of file diff --git a/src/protocols/matchmake_extension/mod.rs b/src/protocols/matchmake_extension/mod.rs new file mode 100644 index 0000000..47dbc31 --- /dev/null +++ b/src/protocols/matchmake_extension/mod.rs @@ -0,0 +1,14 @@ +mod method_get_playing_session; +mod method_auto_matchmake_with_param_postpone; + +use std::sync::Arc; +use tokio::sync::Mutex; +use crate::define_protocol; +use crate::protocols::matchmake_common::MatchmakeData; +use method_get_playing_session::get_playing_session_raw_params; + +define_protocol!{ + 109(matchmake_data: Arc>) => { + 16 => get_playing_session_raw_params + } +} \ No newline at end of file diff --git a/src/protocols/mod.rs b/src/protocols/mod.rs index 68a8327..48ca1a6 100644 --- a/src/protocols/mod.rs +++ b/src/protocols/mod.rs @@ -3,6 +3,8 @@ use crate::prudp::socket::ConnectionData; pub mod auth; pub mod server; pub mod secure; +pub mod matchmake_extension; +pub mod matchmake_common; #[macro_export] macro_rules! define_protocol { @@ -40,11 +42,17 @@ macro_rules! define_protocol { -> ::std::pin::Pin> + Send + 'message_lifetime>> + Send + Sync>{ Box::new( move |v, cd| { - Box::pin(async move { + Box::pin({ $( let $varname = $varname.clone(); )* - protocol(v, cd, $($varname,)*).await + + async move { + $( + let $varname = $varname.clone(); + )* + protocol(v, cd, $($varname,)*).await + } }) } ) diff --git a/src/rmc/structures/buffer.rs b/src/rmc/structures/buffer.rs index 9f58556..19639fc 100644 --- a/src/rmc/structures/buffer.rs +++ b/src/rmc/structures/buffer.rs @@ -17,22 +17,6 @@ impl<'a> RmcSerialize for &'a [u8]{ } } -impl<'a> RmcSerialize for Vec{ - fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { - (&self[..]).serialize(writer) - } - - fn deserialize(mut reader: &mut dyn Read) -> crate::rmc::structures::Result { - let len: u32 = reader.read_struct(IS_BIG_ENDIAN)?; - - let mut data = vec![0; len as usize]; - - reader.read_exact(&mut data)?; - - Ok(data) - } -} - impl<'a> RmcSerialize for Box<[u8]>{ fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { (&self[..]).serialize(writer) diff --git a/src/rmc/structures/matchmake.rs b/src/rmc/structures/matchmake.rs new file mode 100644 index 0000000..a63107b --- /dev/null +++ b/src/rmc/structures/matchmake.rs @@ -0,0 +1,54 @@ +use macros::RmcSerialize; +use crate::kerberos::KerberosDateTime; +use crate::rmc::structures::RmcSerialize; +use crate::rmc::structures::variant::Variant; + +// rmc structure +#[derive(RmcSerialize)] +#[rmc_struct(0)] +struct Gathering{ + self_gid: u32, + owner_pid: u32, + host_pid: u32, + minimum_participants: u16, + maximum_participants: u16, + participant_policy: u32, + policy_argument: u32, + flags: u32, + state: u32, + description: String +} + +// rmc structure +#[derive(RmcSerialize)] +#[rmc_struct(0)] +struct MatchmakeParam{ + params: Vec<(String, Variant)> +} + + +// rmc structure +#[derive(RmcSerialize)] +#[rmc_struct(3)] +struct MatchmakeSession{ + //inherits from + #[extends] + gathering: Gathering, + + gamemode: u32, + attributes: Vec, + open_participation: bool, + matchmake_system_type: u32, + application_buffer: Vec, + participation_count: u32, + progress_score: u8, + session_key: Vec, + option0: u32, + matchmake_param: MatchmakeParam, + datetime: KerberosDateTime, + user_password: String, + refer_gid: u32, + user_password_enabled: bool, + system_password_enabled: bool +} + diff --git a/src/rmc/structures/mod.rs b/src/rmc/structures/mod.rs index cf6ac13..fc4e9d9 100644 --- a/src/rmc/structures/mod.rs +++ b/src/rmc/structures/mod.rs @@ -10,10 +10,14 @@ pub enum Error{ #[error("Io Error: {0}")] Io(#[from] io::Error), #[error("UTF8 conversion Error: {0}")] - Utf8(#[from] FromUtf8Error) + Utf8(#[from] FromUtf8Error), + #[error("unexpected value: {0}")] + UnexpectedValue(u64), + #[error("version mismatch: {0}")] + VersionMismatch(u8), } -type Result = std::result::Result; +pub(crate) type Result = std::result::Result; pub mod string; pub mod any; @@ -23,6 +27,9 @@ pub mod connection_data; pub mod rmc_struct; pub mod list; pub mod qbuffer; +pub mod primitives; +pub mod matchmake; +pub mod variant; pub trait RmcSerialize: Sized{ fn serialize(&self, writer: &mut dyn Write) -> Result<()>; diff --git a/src/rmc/structures/primitives.rs b/src/rmc/structures/primitives.rs new file mode 100644 index 0000000..8de5458 --- /dev/null +++ b/src/rmc/structures/primitives.rs @@ -0,0 +1,94 @@ +use std::io::{Read, Write}; +use bytemuck::bytes_of; +use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions}; +use crate::rmc::structures::RmcSerialize; + +impl RmcSerialize for u8{ + fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + Ok(writer.write_all(bytes_of(self))?) + } + + fn deserialize(mut reader: &mut dyn Read) -> crate::rmc::structures::Result { + Ok(reader.read_struct(IS_BIG_ENDIAN)?) + } +} + +impl RmcSerialize for u16{ + fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + Ok(writer.write_all(bytes_of(self))?) + } + + fn deserialize(mut reader: &mut dyn Read) -> crate::rmc::structures::Result { + Ok(reader.read_struct(IS_BIG_ENDIAN)?) + } +} + +impl RmcSerialize for u32{ + fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + Ok(writer.write_all(bytes_of(self))?) + } + + fn deserialize(mut reader: &mut dyn Read) -> crate::rmc::structures::Result { + Ok(reader.read_struct(IS_BIG_ENDIAN)?) + } +} + +impl RmcSerialize for u64{ + fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + Ok(writer.write_all(bytes_of(self))?) + } + + fn deserialize(mut reader: &mut dyn Read) -> crate::rmc::structures::Result { + Ok(reader.read_struct(IS_BIG_ENDIAN)?) + } +} + +impl RmcSerialize for i64{ + fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + Ok(writer.write_all(bytes_of(self))?) + } + + fn deserialize(mut reader: &mut dyn Read) -> crate::rmc::structures::Result { + Ok(reader.read_struct(IS_BIG_ENDIAN)?) + } +} + +impl RmcSerialize for f64{ + fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + Ok(writer.write_all(bytes_of(self))?) + } + + fn deserialize(mut reader: &mut dyn Read) -> crate::rmc::structures::Result { + Ok(reader.read_struct(IS_BIG_ENDIAN)?) + } +} + +impl RmcSerialize for bool{ + fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + match self{ + true => writer.write_all(&[1])?, + false => writer.write_all(&[0])?, + } + Ok(()) + } + + fn deserialize(mut reader: &mut dyn Read) -> crate::rmc::structures::Result { + Ok(u8::deserialize(reader)? != 0) + } +} + + +impl RmcSerialize for (T, U){ + fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + self.0.serialize(writer)?; + self.1.serialize(writer)?; + Ok(()) + } + + fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + let first = T::deserialize(reader)?; + let second = U::deserialize(reader)?; + + Ok((first, second)) + } +} \ No newline at end of file diff --git a/src/rmc/structures/rmc_struct.rs b/src/rmc/structures/rmc_struct.rs index a665a9a..165a10e 100644 --- a/src/rmc/structures/rmc_struct.rs +++ b/src/rmc/structures/rmc_struct.rs @@ -21,4 +21,5 @@ pub fn write_struct(mut writer: &mut dyn Write, version: u8, pred: impl Fn(&mut writer.write_all(&scratch_space)?; Ok(()) -} \ No newline at end of file +} + diff --git a/src/rmc/structures/variant.rs b/src/rmc/structures/variant.rs new file mode 100644 index 0000000..04e9981 --- /dev/null +++ b/src/rmc/structures/variant.rs @@ -0,0 +1,63 @@ +use std::io::{Read, Write}; +use crate::kerberos::KerberosDateTime; +use crate::rmc::structures; +use crate::rmc::structures::RmcSerialize; + +pub enum Variant{ + None, + SInt64(i64), + Double(f64), + Bool(bool), + String(String), + DateTime(KerberosDateTime), + UInt64(u64), +} + +impl RmcSerialize for Variant{ + fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + match self{ + Variant::None => { + writer.write_all(&[0])?; + } + Variant::SInt64(v) => { + writer.write_all(&[1])?; + v.serialize(writer)?; + } + Variant::Double(v) => { + writer.write_all(&[2])?; + v.serialize(writer)?; + } + Variant::Bool(v) => { + writer.write_all(&[3])?; + v.serialize(writer)?; + } + Variant::String(v) => { + writer.write_all(&[4])?; + v.serialize(writer)?; + } + Variant::DateTime(v) => { + writer.write_all(&[5])?; + v.serialize(writer)?; + } + Variant::UInt64(v) => { + writer.write_all(&[6])?; + v.serialize(writer)?; + } + } + + Ok(()) + } + + fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + match u8::deserialize(reader)?{ + 0 => Ok(Variant::None), + 1 => Ok(Variant::SInt64(i64::deserialize(reader)?)), + 2 => Ok(Variant::Double(f64::deserialize(reader)?)), + 3 => Ok(Variant::Bool(bool::deserialize(reader)?)), + 4 => Ok(Variant::String(String::deserialize(reader)?)), + 5 => Ok(Variant::DateTime(KerberosDateTime::deserialize(reader)?)), + 6 => Ok(Variant::UInt64(u64::deserialize(reader)?)), + v => Err(structures::Error::UnexpectedValue(v as u64)) + } + } +} \ No newline at end of file