From ac9d385fb60c1d7f47bc77da5f11059df96936cc Mon Sep 17 00:00:00 2001 From: cosminperram Date: Thu, 27 Oct 2022 11:09:59 +0300 Subject: [PATCH] Fixed multipacket response when protocol = 7 with certain apps --- CHANGELOG.md | 3 ++- GAMES.md | 2 +- src/protocols/valve/protocol.rs | 34 ++++++++++++++++++--------------- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 464fe93..3e65158 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,8 @@ It is now an enum of: [Counter-Strike: Condition Zero](https://store.steampowered.com/app/80/CounterStrike_Condition_Zero/) implementation. [Day of Defeat](https://store.steampowered.com/app/30/Day_of_Defeat/) implementation. -Games besides CSGO and TS now have the same response structure. +Games besides CSGO and TS now have the same response structure. +Fixed Source multipacket response crash due to when a certain app with a certain protocol doesnt have the Size field. # 0.0.4 - 23/10/2022 Queries now support DNS resolve. diff --git a/GAMES.md b/GAMES.md index f8c2657..37af31e 100644 --- a/GAMES.md +++ b/GAMES.md @@ -5,7 +5,7 @@ | TF2 | Team Fortress 2 | Valve Protocol | | | TS | The Ship | Valve Protocol | | | CSGO | Counter-Strike: Global Offensive | Valve Protocol | The server wouldn't respond the to Rules query since the 21 Feb 2014 update. | -| CSS | Counter-Strike: Source | Valve Protocol | If protocol is 7, queries with multi-packet responses will crash. | +| CSS | Counter-Strike: Source | Valve Protocol | | | DODS | Day of Defeat: Source | Valve Protocol | | | L4D | Left 4 Dead | Valve Protocol | | | L4D2 | Left 4 Dead 2 | Valve Protocol | | diff --git a/src/protocols/valve/protocol.rs b/src/protocols/valve/protocol.rs index 4589848..8ac9c14 100644 --- a/src/protocols/valve/protocol.rs +++ b/src/protocols/valve/protocol.rs @@ -74,7 +74,7 @@ struct SplitPacket { } impl SplitPacket { - fn new(app: &App, buf: &[u8]) -> GDResult { + fn new(app: &App, protocol: u8, buf: &[u8]) -> GDResult { let mut pos = 0; let header = buffer::get_u32_le(&buf, &mut pos)?; @@ -87,7 +87,10 @@ impl SplitPacket { App::Source(_) => { let total = buffer::get_u8(&buf, &mut pos)?; let number = buffer::get_u8(&buf, &mut pos)?; - let size = buffer::get_u16_le(&buf, &mut pos)?; //if game is CSS and if protocol is 7, queries with multi-packet responses will crash + let size = match protocol == 7 && (*app == SteamID::CSS.app()) { //certain apps with protocol = 7 doesnt have this field + false => buffer::get_u16_le(&buf, &mut pos)?, + true => 1248 + }; let compressed = ((id >> 31) & 1) == 1; let (decompressed_size, uncompressed_crc32) = match compressed { false => (None, None), @@ -166,15 +169,15 @@ impl ValveProtocol { Ok(buf[..amt].to_vec()) } - fn receive(&self, app: &App, buffer_size: usize) -> GDResult { + fn receive(&self, app: &App, protocol: u8, buffer_size: usize) -> GDResult { let mut buf = self.receive_raw(buffer_size)?; if buf[0] == 0xFE { //the packet is split - let mut main_packet = SplitPacket::new(&app, &buf)?; + let mut main_packet = SplitPacket::new(&app, protocol, &buf)?; for _ in 1..main_packet.total { buf = self.receive_raw(buffer_size)?; - let chunk_packet = SplitPacket::new(&app, &buf)?; + let chunk_packet = SplitPacket::new(&app, protocol, &buf)?; main_packet.payload.extend(chunk_packet.payload); } @@ -186,11 +189,11 @@ impl ValveProtocol { } /// Ask for a specific request only. - fn get_request_data(&self, app: &App, kind: Request) -> GDResult> { + fn get_request_data(&self, app: &App, protocol: u8, kind: Request) -> GDResult> { let request_initial_packet = Packet::initial(kind.clone()).to_bytes(); self.send(&request_initial_packet)?; - let packet = self.receive(app, DEFAULT_PACKET_SIZE)?; + let packet = self.receive(app, protocol, DEFAULT_PACKET_SIZE)?; if packet.kind != 0x41 { //'A' return Ok(packet.payload.clone()); @@ -200,7 +203,7 @@ impl ValveProtocol { let challenge_packet = Packet::challenge(kind.clone(), challenge).to_bytes(); self.send(&challenge_packet)?; - Ok(self.receive(app, DEFAULT_PACKET_SIZE)?.payload) + Ok(self.receive(app, protocol, DEFAULT_PACKET_SIZE)?.payload) } fn get_goldsrc_server_info(buf: &[u8]) -> GDResult { @@ -266,7 +269,7 @@ impl ValveProtocol { /// Get the server information's. fn get_server_info(&self, app: &App) -> GDResult { - let buf = self.get_request_data(&app, Request::INFO)?; + let buf = self.get_request_data(&app, 0, Request::INFO)?; if let App::GoldSrc(force) = app { if *force { return ValveProtocol::get_goldsrc_server_info(&buf); @@ -365,8 +368,8 @@ impl ValveProtocol { } /// Get the server player's. - fn get_server_players(&self, app: &App) -> GDResult> { - let buf = self.get_request_data(&app, Request::PLAYERS)?; + fn get_server_players(&self, app: &App, protocol: u8) -> GDResult> { + let buf = self.get_request_data(&app, protocol, Request::PLAYERS)?; let mut pos = 0; let count = buffer::get_u8(&buf, &mut pos)?; @@ -393,12 +396,12 @@ impl ValveProtocol { } /// Get the server rules's. - fn get_server_rules(&self, app: &App) -> GDResult>> { + fn get_server_rules(&self, app: &App, protocol: u8) -> GDResult>> { if *app == SteamID::CSGO.app() { //cause csgo wont respond to this since feb 21 2014 update return Ok(None); } - let buf = self.get_request_data(&app, Request::RULES)?; + let buf = self.get_request_data(&app, protocol, Request::RULES)?; let mut pos = 0; let count = buffer::get_u16_le(&buf, &mut pos)?; @@ -421,6 +424,7 @@ pub fn query(address: &str, port: u16, app: App, gather_settings: Option None, - true => Some(client.get_server_players(&app)?) + true => Some(client.get_server_players(&app, protocol)?) }, rules: match gather_rules { false => None, - true => client.get_server_rules(&app)? + true => client.get_server_rules(&app, protocol)? } }) }