From 7d24a71f09bd1f08b90e6a3a9c17fb19d971d0ac Mon Sep 17 00:00:00 2001 From: DJMrTV Date: Wed, 12 Feb 2025 18:46:29 +0100 Subject: [PATCH] feat(matchmake): a bunch of things --- src/kerberos/mod.rs | 16 ++- src/main.rs | 9 +- src/protocols/matchmake_common/mod.rs | 1 + ...hod_create_matchmake_session_with_param.rs | 13 +- src/protocols/mod.rs | 1 + .../method_report_nat_properties.rs | 27 ++++ src/protocols/nat_traversal/mod.rs | 10 ++ src/protocols/notification/mod.rs | 136 +++++++++++++++++- src/protocols/server.rs | 4 +- src/prudp/packet.rs | 22 ++- src/prudp/socket.rs | 5 +- src/rmc/message.rs | 6 +- src/rmc/response.rs | 2 +- 13 files changed, 221 insertions(+), 31 deletions(-) create mode 100644 src/protocols/nat_traversal/method_report_nat_properties.rs create mode 100644 src/protocols/nat_traversal/mod.rs diff --git a/src/kerberos/mod.rs b/src/kerberos/mod.rs index 5fafd9e..a40b816 100644 --- a/src/kerberos/mod.rs +++ b/src/kerberos/mod.rs @@ -66,7 +66,7 @@ impl KerberosDateTime{ #[inline] pub fn get_month(&self) -> u8{ - ((self.0 >> 22) & 0b111111) as u8 + ((self.0 >> 22) & 0b1111) as u8 } #[inline] @@ -154,3 +154,17 @@ impl Ticket{ data.into_boxed_slice() } } + + +#[cfg(test)] +mod test{ + use chrono::{Datelike, Utc}; + use crate::kerberos::KerberosDateTime; + + #[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/src/main.rs b/src/main.rs index b2d7765..2b445c7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -64,11 +64,9 @@ static OWN_IP_PRIVATE: Lazy = Lazy::new(||{ .expect("no public ip specified") }); -static OWN_IP_PUBLIC: Lazy = Lazy::new(||{ +static OWN_IP_PUBLIC: Lazy = Lazy::new(||{ env::var("SERVER_IP_PUBLIC") - .ok() - .and_then(|s| s.parse().ok()) - .unwrap_or(*OWN_IP_PRIVATE) + .unwrap_or(OWN_IP_PRIVATE.to_string()) }); static SECURE_STATION_URL: Lazy = Lazy::new(|| @@ -194,7 +192,8 @@ async fn start_secure_server() -> SecureServer{ Box::new(block_if_maintenance), Box::new(protocols::secure::bound_protocol()), Box::new(protocols::matchmake::bound_protocol(matchmake_data.clone())), - Box::new(protocols::matchmake_extension::bound_protocol(matchmake_data)) + Box::new(protocols::matchmake_extension::bound_protocol(matchmake_data)), + Box::new(protocols::nat_traversal::bound_protocol()) ])); let socket = diff --git a/src/protocols/matchmake_common/mod.rs b/src/protocols/matchmake_common/mod.rs index ab904f7..f016457 100644 --- a/src/protocols/matchmake_common/mod.rs +++ b/src/protocols/matchmake_common/mod.rs @@ -57,6 +57,7 @@ impl ExtendedMatchmakeSession{ ("@GIR".to_owned(), Variant::SInt64(3)) ] }, + system_password_enabled: false, ..session }; diff --git a/src/protocols/matchmake_extension/method_create_matchmake_session_with_param.rs b/src/protocols/matchmake_extension/method_create_matchmake_session_with_param.rs index fd31c55..6fa7214 100644 --- a/src/protocols/matchmake_extension/method_create_matchmake_session_with_param.rs +++ b/src/protocols/matchmake_extension/method_create_matchmake_session_with_param.rs @@ -1,5 +1,6 @@ use std::io::Cursor; use std::sync::Arc; +use log::info; use tokio::sync::{Mutex, RwLock}; use crate::protocols::matchmake_common::{add_matchmake_session, ExtendedMatchmakeSession, MatchmakeData}; use crate::protocols::matchmake_extension::method_auto_matchmake_with_param_postpone::auto_matchmake_with_param_postpone; @@ -16,15 +17,6 @@ pub async fn create_matchmake_session_with_param( mm_data: Arc>, create_matchmake_session: CreateMatchmakeSessionParam ) -> RMCResponseResult { - let locked_conn = conn.lock().await; - let Some(secure_conn) = - locked_conn.active_connection_data.as_ref().map(|a| a.active_secure_connection_data.as_ref()).flatten() else { - return rmcmessage.error_result_with_code(ErrorCode::Core_Exception); - }; - - println!("{:?}", create_matchmake_session); - - let pid = secure_conn.pid; let mut session = ExtendedMatchmakeSession::from_matchmake_session(create_matchmake_session.matchmake_session, &conn).await; @@ -37,8 +29,11 @@ pub async fn create_matchmake_session_with_param( session.add_player(&socket, conn.clone(), create_matchmake_session.join_message).await; + println!("{:?}", session); + let mut response = Vec::new(); + session.session.serialize(&mut response).expect("unable to serialize session"); rmcmessage.success_with_data(response) diff --git a/src/protocols/mod.rs b/src/protocols/mod.rs index 89916af..51c37e1 100644 --- a/src/protocols/mod.rs +++ b/src/protocols/mod.rs @@ -18,6 +18,7 @@ pub mod matchmake_extension; pub mod matchmake_common; pub mod matchmake; mod notification; +pub mod nat_traversal; static IS_MAINTENANCE: Lazy = Lazy::new(|| { env::var("IS_MAINTENANCE") diff --git a/src/protocols/nat_traversal/method_report_nat_properties.rs b/src/protocols/nat_traversal/method_report_nat_properties.rs new file mode 100644 index 0000000..32ba30d --- /dev/null +++ b/src/protocols/nat_traversal/method_report_nat_properties.rs @@ -0,0 +1,27 @@ +use std::io::Cursor; +use std::sync::Arc; +use tokio::sync::{Mutex, RwLock}; +use crate::protocols::matchmake_common::MatchmakeData; +use crate::prudp::socket::{ConnectionData, SocketData}; +use crate::rmc::message::RMCMessage; +use crate::rmc::response::{ErrorCode, RMCResponseResult}; +use crate::rmc::structures::matchmake::CreateMatchmakeSessionParam; + +pub async fn report_nat_properties( + rmcmessage: &RMCMessage, + socket: &Arc, + connection_data: &Arc>, +) -> RMCResponseResult{ + rmcmessage.success_with_data(Vec::new()) +} + +pub async fn report_nat_properties_raw_params( + rmcmessage: &RMCMessage, + socket: &Arc, + connection_data: &Arc>, + _: () +) -> RMCResponseResult{ + let mut reader = Cursor::new(&rmcmessage.rest_of_data); + + report_nat_properties(rmcmessage, socket, connection_data).await +} \ No newline at end of file diff --git a/src/protocols/nat_traversal/mod.rs b/src/protocols/nat_traversal/mod.rs new file mode 100644 index 0000000..48e59e6 --- /dev/null +++ b/src/protocols/nat_traversal/mod.rs @@ -0,0 +1,10 @@ +mod method_report_nat_properties; + +use crate::define_protocol; +use crate::protocols::nat_traversal::method_report_nat_properties::report_nat_properties_raw_params; + +define_protocol!{ + 3() => { + 5 => report_nat_properties_raw_params + } +} \ No newline at end of file diff --git a/src/protocols/notification/mod.rs b/src/protocols/notification/mod.rs index daa33ee..87340a7 100644 --- a/src/protocols/notification/mod.rs +++ b/src/protocols/notification/mod.rs @@ -1,13 +1,13 @@ use macros::RmcSerialize; use rand::random; -use crate::prudp::packet::{PRUDPHeader, PRUDPPacket, TypesFlags}; +use crate::prudp::packet::{PRUDPHeader, PRUDPPacket, PacketOption, TypesFlags}; use crate::prudp::packet::flags::{NEED_ACK, RELIABLE}; use crate::prudp::packet::types::DATA; use crate::prudp::socket::{ConnectionData, SocketData}; use crate::rmc::message::RMCMessage; use crate::rmc::structures::RmcSerialize; -#[derive(RmcSerialize)] +#[derive(Debug, Eq, PartialEq, RmcSerialize)] #[rmc_struct(0)] pub struct Notification{ pub pid_source: u32, @@ -18,6 +18,7 @@ pub struct Notification{ pub param_3: u32, } + impl ConnectionData{ pub async fn send_notification(&mut self, socket: &SocketData, notif: Notification){ println!("sending notification"); @@ -33,20 +34,143 @@ impl ConnectionData{ rest_of_data: data }; - let prudp_packet = PRUDPPacket{ + + + let mut prudp_packet = PRUDPPacket{ header: PRUDPHeader{ types_and_flags: TypesFlags::default().types(DATA).flags(NEED_ACK | RELIABLE), source_port: socket.get_virual_port(), destination_port: self.sock_addr.virtual_port, ..Default::default() }, - options: Vec::new(), + options: vec![ + PacketOption::FragmentId(0), + ], payload: message.to_data(), packet_signature: [0;16] }; - - self.finish_and_send_packet_to(socket, prudp_packet).await; + } +} + +#[cfg(test)] +mod test{ + use std::io::Cursor; + use rand::random; + use crate::protocols::notification::Notification; + use crate::prudp::packet::{PRUDPHeader, PRUDPPacket, PacketOption, TypesFlags}; + use crate::prudp::packet::flags::{NEED_ACK, RELIABLE}; + use crate::prudp::packet::types::DATA; + use crate::rmc::message::RMCMessage; + use crate::rmc::structures::RmcSerialize; + + #[test] + fn test(){ + let data = hex::decode("ead001032900a1af62000000000000000000000000000000000000000000020100250000000e57238a6601000000001700000051b39957b90b00003661636851b3995701000001000000").unwrap(); + + + let packet = PRUDPPacket::new(&mut Cursor::new(data)).expect("invalid packet"); + + println!("{:?}", packet); + + let rmc = RMCMessage::new(&mut Cursor::new(packet.payload)).expect("invalid rmc message"); + + println!("{:?}", rmc); + + let notif = Notification::deserialize(&mut Cursor::new(rmc.rest_of_data)).expect("invalid notification"); + + println!("{:?}", notif); + } + #[test] + fn test2(){ + + let data = hex::decode("250000000e57b6801001000000001700000051b39957b90b0000248a5a9851b3995701000001000000").unwrap(); + //let packet = PRUDPPacket::new(&mut Cursor::new(data)).expect("invalid packet"); + + //println!("{:?}", packet); + + let rmc = RMCMessage::new(&mut Cursor::new(data)).expect("invalid rmc message"); + + println!("{:?}", rmc); + + let notif = Notification::deserialize(&mut Cursor::new(rmc.rest_of_data)).expect("invalid notification"); + + println!("{:?}", notif); + } + + #[test] + fn test3(){ + + let data = hex::decode("ead001032900a1af620084000300020100250000008e0100000001000000001700000051b39957b90b00000100000051b399570100000100000000000000000000000000000000000000").unwrap(); + let packet = PRUDPPacket::new(&mut Cursor::new(data)).expect("invalid packet"); + + println!("{:?}", packet); + + let rmc = RMCMessage::new(&mut Cursor::new(packet.payload)).expect("invalid rmc message"); + + println!("{:?}", rmc); + + let notif = Notification::deserialize(&mut Cursor::new(rmc.rest_of_data)).expect("invalid notification"); + + println!("{:?}", notif); + } + + #[test] + fn test_rmc_serialization(){ + let notif = Notification{ + pid_source: random(), + notif_type: random(), + param_1: random(), + param_2: random(), + str_param: "".to_string(), + param_3: random(), + }; + + let mut notif_data = Vec::new(); + + notif.serialize(&mut notif_data).unwrap(); + + let message = RMCMessage{ + protocol_id: 14, + method_id: 1, + call_id: random(), + rest_of_data: notif_data + }; + + let mut prudp_packet = PRUDPPacket{ + header: PRUDPHeader{ + ..Default::default() + }, + options: vec![ + PacketOption::FragmentId(0), + ], + payload: message.to_data(), + packet_signature: [0;16] + }; + + prudp_packet.set_sizes(); + + + + let mut packet_data: Vec = Vec::new(); + + prudp_packet.write_to(&mut packet_data).expect("what"); + + let packet_deserialized = PRUDPPacket::new(&mut Cursor::new(packet_data)).unwrap(); + + assert_eq!(prudp_packet, packet_deserialized); + + let message_deserialized = RMCMessage::new(&mut Cursor::new(packet_deserialized.payload)).unwrap(); + + assert_eq!(message, message_deserialized); + + let notification_deserialized = Notification::deserialize(&mut Cursor::new(message_deserialized.rest_of_data)).unwrap(); + + assert_eq!(notification_deserialized, notif); + + + + } } \ No newline at end of file diff --git a/src/protocols/server.rs b/src/protocols/server.rs index 9927937..68fd7c2 100644 --- a/src/protocols/server.rs +++ b/src/protocols/server.rs @@ -29,7 +29,9 @@ impl RMCProtocolServer{ for proto in &self.0 { if let Some(response) = proto(&rmc, &socket, &connection).await { - + if matches!(response.response_result, RMCResponseResult::Error {..}){ + error!("an rmc error occurred") + } let mut locked = connection.lock().await; send_response(&packet, &socket, &mut locked, response).await; drop(locked); diff --git a/src/prudp/packet.rs b/src/prudp/packet.rs index 434d476..470f6b2 100644 --- a/src/prudp/packet.rs +++ b/src/prudp/packet.rs @@ -40,7 +40,7 @@ pub enum Error { pub type Result = std::result::Result; #[repr(transparent)] -#[derive(Copy, Clone, Pod, Zeroable, SwapEndian, Default)] +#[derive(Copy, Clone, Pod, Zeroable, SwapEndian, Default, Eq, PartialEq)] pub struct TypesFlags(u16); impl TypesFlags { @@ -141,7 +141,7 @@ impl Debug for VirtualPort { } #[repr(C)] -#[derive(Debug, Copy, Clone, Pod, Zeroable, SwapEndian)] +#[derive(Debug, Copy, Clone, Pod, Zeroable, SwapEndian, Eq, PartialEq)] pub struct PRUDPHeader { pub magic: [u8; 2], pub version: u8, @@ -173,7 +173,7 @@ impl Default for PRUDPHeader{ } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Eq, PartialEq)] pub enum PacketOption{ SupportedFunctions(u32), ConnectionSignature([u8; 16]), @@ -236,7 +236,7 @@ impl PacketOption{ } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Eq, PartialEq)] pub struct PRUDPPacket { pub header: PRUDPHeader, pub packet_signature: [u8; 16], @@ -290,9 +290,12 @@ impl PRUDPPacket { let packet_signature: [u8; 16] = reader.read_struct(IS_BIG_ENDIAN)?; + //let packet_signature: [u8; 16] = [0; 16]; assert_eq!(reader.stream_position().ok(), Some(14 + 16)); + + let mut packet_specific_buffer = vec![0u8; header.packet_specific_size as usize]; reader.read_exact(&mut packet_specific_buffer)?; @@ -474,6 +477,8 @@ impl PRUDPPacket { #[cfg(test)] mod test { + use crate::prudp::packet::flags::{NEED_ACK, RELIABLE}; + use crate::prudp::packet::types::DATA; use super::{OptionId, PacketOption, PRUDPHeader, TypesFlags, VirtualPort}; #[test] fn size_test() { @@ -523,4 +528,13 @@ mod test { let header_data: [u8; 8] = bytes.try_into().unwrap(); } + + #[test] + fn test_types_flags(){ + let types = TypesFlags::default().types(DATA).flags(NEED_ACK | RELIABLE); + + assert_ne!((types.0 >> 4) & NEED_ACK, 0); + assert_ne!((types.0 >> 4) & RELIABLE, 0); + assert_ne!((types.0 & 0xFF) as u8 & DATA, 0); + } } \ No newline at end of file diff --git a/src/prudp/socket.rs b/src/prudp/socket.rs index c7b93ee..9068ba2 100644 --- a/src/prudp/socket.rs +++ b/src/prudp/socket.rs @@ -195,7 +195,7 @@ impl SocketData { } if (packet.header.types_and_flags.get_flags() & MULTI_ACK) != 0 { - println!("got ack"); + println!("got multi ack"); return; } @@ -458,6 +458,8 @@ 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"); @@ -491,7 +493,6 @@ impl ConnectionData{ packet.calculate_and_assign_signature(socket.access_key, potential_session_key, Some(self.server_signature)); - let mut vec = Vec::new(); packet.write_to(&mut vec).expect("somehow failed to convert backet to bytes"); diff --git a/src/rmc/message.rs b/src/rmc/message.rs index 68598d2..f45b585 100644 --- a/src/rmc/message.rs +++ b/src/rmc/message.rs @@ -5,7 +5,7 @@ use log::error; use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions}; use crate::rmc::response::{ErrorCode, RMCResponseResult}; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct RMCMessage{ pub protocol_id: u16, pub call_id: u32, @@ -60,13 +60,15 @@ impl RMCMessage{ output.write_all(bytes_of(&size)).expect("unable to write size"); - let proto_id = self.protocol_id as u8; + let proto_id = self.protocol_id as u8 | 0x80; output.write_all(bytes_of(&proto_id)).expect("unable to write size"); output.write_all(bytes_of(&self.call_id)).expect("unable to write size"); output.write_all(bytes_of(&self.method_id)).expect("unable to write size"); + output.write_all(&self.rest_of_data).expect("unable to write data"); + output } diff --git a/src/rmc/response.rs b/src/rmc/response.rs index 7d16ba4..ca02318 100644 --- a/src/rmc/response.rs +++ b/src/rmc/response.rs @@ -93,7 +93,7 @@ pub async fn send_response(original_packet: &PRUDPPacket, socket: &SocketData, c packet.header.types_and_flags.set_types(DATA); packet.header.types_and_flags.set_flag((original_packet.header.types_and_flags.get_flags() & RELIABLE) | NEED_ACK); - packet.header.session_id = active_connection.server_session_id; + //packet.header.session_id = active_connection.server_session_id; packet.header.substream_id = 0; packet.options.push(FragmentId(0));