From 38bcad37bda1d04efaab2eaa16ea35871c13ff79 Mon Sep 17 00:00:00 2001 From: DJMrTV Date: Sun, 26 Jan 2025 23:21:35 +0100 Subject: [PATCH] cleaned up code, condensed code and fixed a couple of things --- src/main.rs | 37 +++++++---------------- src/protocols/auth/method_login_ex.rs | 9 +++--- src/protocols/auth/mod.rs | 21 ++++---------- src/protocols/mod.rs | 28 +++++++++++++++++- src/protocols/server.rs | 42 +++++++++++++++++++++++++++ src/prudp/socket.rs | 35 ++++++++++++++++++++-- src/rmc/response.rs | 25 ++++------------ src/rmc/structures/any.rs | 35 ++++++++++++---------- src/rmc/structures/mod.rs | 9 +++++- src/rmc/structures/string.rs | 32 +++++++++++++------- 10 files changed, 178 insertions(+), 95 deletions(-) create mode 100644 src/protocols/server.rs diff --git a/src/main.rs b/src/main.rs index 3ae92d8..c20cc5e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,12 +10,14 @@ use once_cell::sync::Lazy; use rc4::{KeyInit, Rc4, StreamCipher}; use rc4::consts::U5; use simplelog::{ColorChoice, CombinedLogger, Config, LevelFilter, TerminalMode, TermLogger, WriteLogger}; +use crate::protocols::auth; +use crate::protocols::server::RMCProtocolServer; use crate::prudp::socket::{Socket, SocketData}; use crate::prudp::packet::{PRUDPPacket, VirtualPort}; use crate::prudp::router::Router; use crate::rmc::message::RMCMessage; use crate::rmc::response::{RMCResponse, RMCResponseResult, send_response}; -use crate::rmc::response::ErrorCode::Core_InvalidIndex; +use crate::rmc::response::ErrorCode::{Core_InvalidIndex, Core_NotImplemented}; mod endianness; mod prudp; @@ -67,6 +69,10 @@ async fn start_servers(){ info!("setting up endpoints"); // dont assign it to the name _ as that will make it drop right here and now + let rmcserver = RMCProtocolServer::new(Box::new([ + Box::new(auth::protocol) + ])); + let mut _socket = Socket::new( auth_server_router.clone(), @@ -87,30 +93,9 @@ async fn start_servers(){ } ) }), - Box::new(|p, socket, connection|{ - Box::pin( - async move { - println!("{:?}",p); - let Ok(rmc) = RMCMessage::new(&mut Cursor::new(&p.payload)) else { - error!("error reading rmc message"); - return; - }; - - println!("recieved rmc message: {{ protocol: {}, method: {}}}", rmc.protocol_id, rmc.method_id); - - if let Some(response) = protocols::auth::try_process_via_protocol(&rmc){ - send_response(&p, &socket, connection, response).await; - } - - send_response(&p, &socket, connection, RMCResponse{ - protocol_id: rmc.protocol_id as u8, - response_result: RMCResponseResult::Error { - call_id: rmc.call_id, - error_code: Core_InvalidIndex - } - }).await; - } - ) + Box::new(move |packet, socket, connection|{ + let rmcserver = rmcserver.clone(); + Box::pin(async move { rmcserver.process_message(packet, &socket, connection).await; }) }) ).await.expect("unable to create socket"); @@ -155,7 +140,7 @@ mod test{ let mut a = Cursor::new(&rmc_packet.rest_of_data); - let pid = rmc::structures::string::read(&mut a).expect("unable to read pid"); + //let pid = rmc::structures::string::read(&mut a).expect("unable to read pid"); } #[tokio::test] diff --git a/src/protocols/auth/method_login_ex.rs b/src/protocols/auth/method_login_ex.rs index 25e17f2..9f087fc 100644 --- a/src/protocols/auth/method_login_ex.rs +++ b/src/protocols/auth/method_login_ex.rs @@ -2,7 +2,8 @@ use std::io::Cursor; use log::{error, info}; use crate::rmc::message::RMCMessage; use crate::rmc::response::{ErrorCode, RMCResponse, RMCResponseResult}; -use crate::rmc::structures::{string, any}; +use crate::rmc::structures::{string, any, RmcSerialize}; +use crate::rmc::structures::any::Any; pub fn login_ex(name: &str) -> RMCResponseResult{ // todo: figure out how the AuthenticationInfo struct works, parse it and validate login info @@ -14,12 +15,12 @@ pub fn login_ex(name: &str) -> RMCResponseResult{ pub fn login_ex_raw_params(rmcmessage: &RMCMessage) -> RMCResponseResult{ let mut reader = Cursor::new(&rmcmessage.rest_of_data); - let Ok(str) = string::read(&mut reader) else { + let Ok(str) = String::deserialize(&mut reader) else { error!("error reading packet"); return rmcmessage.error_result_with_code(ErrorCode::Core_InvalidArgument); }; - let Ok(any) = any::read(&mut reader) else { + let Ok(any) = Any::deserialize(&mut reader) else { error!("error reading packet"); return rmcmessage.error_result_with_code(ErrorCode::Core_InvalidArgument); }; @@ -35,5 +36,5 @@ pub fn login_ex_raw_params(rmcmessage: &RMCMessage) -> RMCResponseResult{ } //login_ex(&str) - rmcmessage.error_result_with_code(ErrorCode::Core_AccessDenied) + rmcmessage.error_result_with_code(ErrorCode::Authentication_UnderMaintenance) } \ No newline at end of file diff --git a/src/protocols/auth/mod.rs b/src/protocols/auth/mod.rs index 439445e..3611d0c 100644 --- a/src/protocols/auth/mod.rs +++ b/src/protocols/auth/mod.rs @@ -1,25 +1,14 @@ mod method_login_ex; use log::{error, info}; +use crate::define_protocol; use crate::protocols::auth::method_login_ex::{login_ex, login_ex_raw_params}; use crate::rmc::message::RMCMessage; use crate::rmc::response::{ErrorCode, RMCResponse, RMCResponseResult}; -pub fn try_process_via_protocol(rmcmessage: &RMCMessage) -> Option{ - if rmcmessage.protocol_id != 10{ - return None; + +define_protocol!{ + 10 => { + 0x02 => login_ex_raw_params } - - let response_result = match rmcmessage.method_id{ - 0x02 => login_ex_raw_params(rmcmessage), - _ => { - error!("invalid method id sent to ticket-granting protocol: {:?}", rmcmessage.method_id); - rmcmessage.error_result_with_code(ErrorCode::Core_Exception) - } - }; - - Some(RMCResponse{ - protocol_id: 10, - response_result - }) } \ No newline at end of file diff --git a/src/protocols/mod.rs b/src/protocols/mod.rs index 5696e21..36d749b 100644 --- a/src/protocols/mod.rs +++ b/src/protocols/mod.rs @@ -1 +1,27 @@ -pub mod auth; \ No newline at end of file +pub mod auth; +pub mod server; +#[macro_export] +macro_rules! define_protocol { + ($id:literal => {$($func_id:literal => $func:path),*} ) => { + pub fn protocol(rmcmessage: &RMCMessage) -> Option{ + if rmcmessage.protocol_id != $id{ + return None; + } + + let response_result = match rmcmessage.method_id{ + $( + $func_id => $func(rmcmessage), + ),* + _ => { + error!("invalid method id sent to protocol {}: {:?}", $id, rmcmessage.method_id); + rmcmessage.error_result_with_code(ErrorCode::Core_NotImplemented) + } + }; + + Some(RMCResponse{ + protocol_id: $id, + response_result + }) + } + }; +} \ No newline at end of file diff --git a/src/protocols/server.rs b/src/protocols/server.rs new file mode 100644 index 0000000..15fadaa --- /dev/null +++ b/src/protocols/server.rs @@ -0,0 +1,42 @@ +use std::io::Cursor; +use std::sync::Arc; +use log::error; +use crate::prudp::packet::PRUDPPacket; +use crate::prudp::socket::{ConnectionData, SocketData}; +use crate::rmc::message::RMCMessage; +use crate::rmc::response::{RMCResponse, RMCResponseResult, send_response}; +use crate::rmc::response::ErrorCode::Core_NotImplemented; + +type ContainedProtocolList = Box<[Box Option + Send + Sync>]>; + +pub struct RMCProtocolServer(ContainedProtocolList); + +impl RMCProtocolServer{ + pub fn new(protocols: ContainedProtocolList) -> Arc{ + Arc::new(Self(protocols)) + } + + pub async fn process_message(&self, packet: PRUDPPacket, socket: &SocketData, connection: &mut ConnectionData){ + let Ok(rmc) = RMCMessage::new(&mut Cursor::new(&packet.payload)) else { + error!("error reading rmc message"); + return; + }; + + println!("recieved rmc message: {{ protocol: {}, method: {}}}", rmc.protocol_id, rmc.method_id); + + for proto in &self.0 { + if let Some(response) = proto(&rmc) { + send_response(&packet, &socket, connection, response).await; + return; + } + } + + send_response(&packet, &socket, connection, RMCResponse{ + protocol_id: rmc.protocol_id as u8, + response_result: RMCResponseResult::Error { + call_id: rmc.call_id, + error_code: Core_NotImplemented + } + }).await; + } +} \ No newline at end of file diff --git a/src/prudp/socket.rs b/src/prudp/socket.rs index ec28e01..2eeb7e7 100644 --- a/src/prudp/socket.rs +++ b/src/prudp/socket.rs @@ -54,8 +54,8 @@ pub struct ActiveConnectionData { pub reliable_server_counter: u16, pub reliable_client_queue: VecDeque, pub connection_data_channel: Sender>, - pub server_encryption: Box, - pub client_decryption: Box, + server_encryption: Box, + client_decryption: Box, pub server_session_id: u8, } @@ -383,6 +383,37 @@ impl SocketData { } } +impl ConnectionData{ + pub async fn finish_and_send_packet_to(&mut self, socket: &SocketData, mut packet: PRUDPPacket){ + if (packet.header.types_and_flags.get_flags() & RELIABLE) != 0{ + let Some(active_connection) = self.active_connection_data.as_mut() else { + error!("tried to send a secure packet to an inactive connection"); + return; + }; + + packet.header.sequence_id = active_connection.reliable_server_counter; + active_connection.reliable_server_counter += 1; + + active_connection.server_encryption.apply_keystream(&mut packet.payload); + } + + packet.header.source_port = socket.virtual_port; + packet.header.destination_port = self.sock_addr.virtual_port; + + packet.set_sizes(); + + packet.calculate_and_assign_signature(socket.access_key, None, Some(self.server_signature)); + + let mut vec = Vec::new(); + + packet.write_to(&mut vec).expect("somehow failed to convert backet to bytes"); + + if let Err(e) = socket.socket.send_to(&vec, self.sock_addr.regular_socket_addr).await{ + error!("unable to send packet to destination: {}", e); + } + } +} + #[cfg(test)] mod test { use std::io::Cursor; diff --git a/src/rmc/response.rs b/src/rmc/response.rs index 8506e5d..e6b86ac 100644 --- a/src/rmc/response.rs +++ b/src/rmc/response.rs @@ -49,7 +49,7 @@ pub fn generate_response(protocol_id: u8, response: RMCResponseResult) -> io::Re let u32_size: u32 = size as _; data_out.write_all(bytes_of(&u32_size))?; - data_out.push(protocol_id | 0x80); + data_out.push(protocol_id); match response{ RMCResponseResult::Success { @@ -59,7 +59,8 @@ pub fn generate_response(protocol_id: u8, response: RMCResponseResult) -> io::Re } => { data_out.push(1); data_out.write_all(bytes_of(&call_id))?; - data_out.write_all(bytes_of(&method_id))?; + let ored_method_id = method_id | 0x8000; + data_out.write_all(bytes_of(&ored_method_id))?; data_out.write_all(&data)?; }, RMCResponseResult::Error { @@ -81,8 +82,6 @@ pub async fn send_response(original_packet: &PRUDPPacket, socket: &SocketData, c let ConnectionData{ active_connection_data, - sock_addr, - server_signature, .. } = connection; @@ -90,15 +89,12 @@ pub async fn send_response(original_packet: &PRUDPPacket, socket: &SocketData, c return; }; - let mut packet = original_packet.base_response_packet(); packet.header.types_and_flags.set_types(DATA); - packet.header.types_and_flags.set_flag(RELIABLE | HAS_SIZE | NEED_ACK); + packet.header.types_and_flags.set_flag((original_packet.header.types_and_flags.get_flags() & RELIABLE) | NEED_ACK); - packet.header.sequence_id = active_connection.reliable_server_counter; - active_connection.reliable_server_counter += 1; packet.header.session_id = active_connection.server_session_id; packet.header.substream_id = 0; @@ -106,18 +102,7 @@ pub async fn send_response(original_packet: &PRUDPPacket, socket: &SocketData, c packet.payload = rmcresponse.to_data(); - - active_connection.server_encryption.apply_keystream(&mut packet.payload); - - packet.set_sizes(); - packet.calculate_and_assign_signature(socket.access_key, None, Some(*server_signature)); - - let mut vec = Vec::new(); - - packet.write_to(&mut vec).expect("somehow failed to convert backet to bytes"); - - socket.socket.send_to(&vec, sock_addr.regular_socket_addr).await.expect("failed to send data back"); - + connection.finish_and_send_packet_to(socket, packet).await; } //taken from kinnays error list directly diff --git a/src/rmc/structures/any.rs b/src/rmc/structures/any.rs index b4fe71f..24d79ae 100644 --- a/src/rmc/structures/any.rs +++ b/src/rmc/structures/any.rs @@ -1,6 +1,6 @@ -use std::io::{Read, Seek}; +use std::io::{Read, Seek, Write}; use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions}; -use super::{string, Result}; +use super::{string, Result, RmcSerialize}; #[derive(Debug)] pub struct Any{ @@ -8,21 +8,26 @@ pub struct Any{ pub data: Vec } -pub fn read(reader: &mut (impl Read + Seek)) -> Result{ - let name = string::read(reader)?; +impl RmcSerialize for Any{ + fn serialize(&self, writer: &mut dyn Write) -> Result<()> { + todo!() + } + fn deserialize(mut reader: &mut dyn Read) -> Result { + let name = String::deserialize(reader)?; - // also length ? - let len2: u32 = reader.read_struct(IS_BIG_ENDIAN)?; - let length: u32 = reader.read_struct(IS_BIG_ENDIAN)?; + // also length ? + let len2: u32 = reader.read_struct(IS_BIG_ENDIAN)?; + let length: u32 = reader.read_struct(IS_BIG_ENDIAN)?; - let mut data = vec![0; length as usize]; + let mut data = vec![0; length as usize]; - reader.read_exact(&mut data)?; + reader.read_exact(&mut data)?; - Ok( - Any{ - name, - data - } - ) + Ok( + Any{ + name, + data + } + ) + } } \ No newline at end of file diff --git a/src/rmc/structures/mod.rs b/src/rmc/structures/mod.rs index 8f1fab7..c0c1e20 100644 --- a/src/rmc/structures/mod.rs +++ b/src/rmc/structures/mod.rs @@ -1,6 +1,8 @@ use std::io; +use std::io::{Read, Seek, Write}; use std::str::Utf8Error; use std::string::FromUtf8Error; +use md5::digest::impl_oid_carrier; use thiserror::Error; //ideas for the future: make a proc macro library which allows generation of struct reads @@ -16,4 +18,9 @@ pub enum Error{ type Result = std::result::Result; pub mod string; -pub mod any; \ No newline at end of file +pub mod any; + +pub trait RmcSerialize: Sized{ + fn serialize(&self, writer: &mut dyn Write) -> Result<()>; + fn deserialize(reader: &mut dyn Read) -> Result; +} \ No newline at end of file diff --git a/src/rmc/structures/string.rs b/src/rmc/structures/string.rs index bf646ec..da0930e 100644 --- a/src/rmc/structures/string.rs +++ b/src/rmc/structures/string.rs @@ -1,18 +1,30 @@ use std::ffi::CString; -use std::io::{Read, Seek}; +use std::io::{Read, Seek, Write}; +use bytemuck::bytes_of; use log::error; use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions}; -use super::Result; +use super::{Result, RmcSerialize}; -pub fn read(reader: &mut (impl Read + Seek)) -> Result{ - let len: u16 = reader.read_struct(IS_BIG_ENDIAN)?; - let mut data = vec![0; len as usize - 1]; - reader.read_exact(&mut data)?; +impl RmcSerialize for String{ + fn deserialize(mut reader: &mut dyn Read) -> Result { + let len: u16 = reader.read_struct(IS_BIG_ENDIAN)?; + let mut data = vec![0; len as usize - 1]; + reader.read_exact(&mut data)?; - let null: u8 = reader.read_struct(IS_BIG_ENDIAN)?; - if null != 0{ - error!("unable to find null terminator... continuing anyways"); + let null: u8 = reader.read_struct(IS_BIG_ENDIAN)?; + if null != 0{ + error!("unable to find null terminator... continuing anyways"); + } + + Ok(String::from_utf8(data)?) } + fn serialize(&self, writer: &mut dyn Write) -> Result<()> { + let u16_len: u16 = self.len() as u16; + writer.write(bytes_of(&u16_len))?; - Ok(String::from_utf8(data)?) + writer.write(self.as_bytes())?; + writer.write(&[0])?; + + Ok(()) + } } \ No newline at end of file