From 6ecdae840c218d06f2ccfa326dd85ef41cc25758 Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Sat, 28 Jun 2025 08:48:59 -0400 Subject: [PATCH] Continue parsing when encountering unknown packets This reads the unknown packet data, just throwing it in a byte buffer. This allows us to read the rest of the segmenets in the packet, and fixes parsing. Note that this still log spams with "wrong size" as we can't determine the size of the unknown packet ahead of time. This is easy to fix, but it's not a high priority yet. Fixes #73 --- build.rs | 6 +++--- src/bin/kawari-world.rs | 4 +++- src/ipc/chat/mod.rs | 2 +- src/ipc/kawari/mod.rs | 2 +- src/ipc/lobby/mod.rs | 4 ++-- src/ipc/zone/mod.rs | 9 ++++++--- src/packet/encryption.rs | 4 ++-- src/packet/ipc.rs | 7 ++++--- src/packet/parsing.rs | 5 ++++- 9 files changed, 26 insertions(+), 17 deletions(-) diff --git a/build.rs b/build.rs index 1a9a0bc..cc805ce 100644 --- a/build.rs +++ b/build.rs @@ -36,7 +36,7 @@ fn main() { output_str.push_str(&format!("{name},\n")); } - output_str.push_str(&format!("Unknown,\n")); + output_str.push_str(&format!("Unknown(u16),\n")); // end output_str.push_str("}\n\n"); @@ -56,7 +56,7 @@ fn main() { output_str.push_str(&format!("{key}::{name} => {size},\n")); } - output_str.push_str(&format!("{key}::Unknown => 0,\n")); + output_str.push_str(&format!("{key}::Unknown(_) => 0,\n")); output_str.push_str("}\n\n"); output_str.push_str("}\n\n"); @@ -73,7 +73,7 @@ fn main() { output_str.push_str(&format!("{key}::{name} => \"{name}\",\n")); } - output_str.push_str(&format!("{key}::Unknown => \"Unknown\",\n")); + output_str.push_str(&format!("{key}::Unknown(_) => \"Unknown\",\n")); output_str.push_str("}\n\n"); output_str.push_str("}\n\n"); diff --git a/src/bin/kawari-world.rs b/src/bin/kawari-world.rs index b7ee68e..c4156f1 100644 --- a/src/bin/kawari-world.rs +++ b/src/bin/kawari-world.rs @@ -939,7 +939,9 @@ async fn client_loop( }) .await; } - _ => {}, + ClientZoneIpcData::Unknown { .. } => { + tracing::warn!("Unknown packet {:?} recieved, this should be handled!", data.op_code); + } } } SegmentData::KeepAliveRequest { id, timestamp } => { diff --git a/src/ipc/chat/mod.rs b/src/ipc/chat/mod.rs index a57ff82..f4c7369 100644 --- a/src/ipc/chat/mod.rs +++ b/src/ipc/chat/mod.rs @@ -36,7 +36,7 @@ impl Default for ServerChatIpcSegment { } #[binrw] -#[br(import(magic: &ServerChatIpcType))] +#[br(import(magic: &ServerChatIpcType, _size: &u32))] #[derive(Debug, Clone)] pub enum ServerChatIpcData { /// Sent by the server to Initialize something chat-related? diff --git a/src/ipc/kawari/mod.rs b/src/ipc/kawari/mod.rs index 82057ad..6d15e17 100644 --- a/src/ipc/kawari/mod.rs +++ b/src/ipc/kawari/mod.rs @@ -80,7 +80,7 @@ pub enum CustomIpcType { } #[binrw] -#[br(import(magic: &CustomIpcType))] +#[br(import(magic: &CustomIpcType, _size: &u32))] #[derive(Debug, Clone)] pub enum CustomIpcData { #[br(pre_assert(*magic == CustomIpcType::RequestCreateCharacter))] diff --git a/src/ipc/lobby/mod.rs b/src/ipc/lobby/mod.rs index 814cce7..0d5640d 100644 --- a/src/ipc/lobby/mod.rs +++ b/src/ipc/lobby/mod.rs @@ -83,7 +83,7 @@ impl Default for ServerLobbyIpcSegment { } #[binrw] -#[br(import(magic: &ClientLobbyIpcType))] +#[br(import(magic: &ClientLobbyIpcType, _size: &u32))] #[derive(Debug, Clone)] pub enum ClientLobbyIpcData { /// Sent by the client when it requests the character list in the lobby. @@ -131,7 +131,7 @@ pub enum ClientLobbyIpcData { } #[binrw] -#[br(import(magic: &ServerLobbyIpcType))] +#[br(import(magic: &ServerLobbyIpcType, _size: &u32))] #[derive(Debug, Clone)] pub enum ServerLobbyIpcData { /// Sent by the server to indicate an lobby error occured. diff --git a/src/ipc/zone/mod.rs b/src/ipc/zone/mod.rs index 0ac104d..88d505e 100644 --- a/src/ipc/zone/mod.rs +++ b/src/ipc/zone/mod.rs @@ -167,7 +167,7 @@ pub enum GameMasterCommandType { } #[binrw] -#[br(import(magic: &ServerZoneIpcType))] +#[br(import(magic: &ServerZoneIpcType, _size: &u32))] #[derive(Debug, Clone)] pub enum ServerZoneIpcData { /// Sent by the server as response to ZoneInitRequest. @@ -330,7 +330,7 @@ pub enum ServerZoneIpcData { } #[binrw] -#[br(import(magic: &ClientZoneIpcType))] +#[br(import(magic: &ClientZoneIpcType, size: &u32))] #[derive(Debug, Clone)] pub enum ClientZoneIpcData { /// Sent by the client when they successfully initialize with the server, and they need several bits of information (e.g. what zone to load) @@ -476,7 +476,10 @@ pub enum ClientZoneIpcData { #[brw(pad_after = 8)] unk3: u8, }, - Unknown, + Unknown { + #[br(count = size - 32)] + unk: Vec, + }, } #[cfg(test)] diff --git a/src/packet/encryption.rs b/src/packet/encryption.rs index b0e43d0..ba3860a 100644 --- a/src/packet/encryption.rs +++ b/src/packet/encryption.rs @@ -31,9 +31,9 @@ pub(crate) fn decrypt( blowfish.decrypt(&mut data); let mut cursor = Cursor::new(&data); - T::read_options(&mut cursor, endian, ()) + T::read_options(&mut cursor, endian, (&size,)) } else { - T::read_options(reader, endian, ()) + T::read_options(reader, endian, (&size,)) } } diff --git a/src/packet/ipc.rs b/src/packet/ipc.rs index 0463d21..2fb9efe 100644 --- a/src/packet/ipc.rs +++ b/src/packet/ipc.rs @@ -2,7 +2,7 @@ use binrw::{BinRead, BinWrite, binrw}; /// Required to implement for specializations of `IpcSegment`. These should be read/writeable, however for client packets you can leave calc_size() unimplemented. pub trait ReadWriteIpcSegment: - for<'a> BinRead = ()> + for<'a> BinWrite = ()> + std::fmt::Debug + 'static + for<'a> BinRead = (&'a u32,)> + for<'a> BinWrite = ()> + std::fmt::Debug + 'static { /// Calculate the size of this Ipc segment *including* the 16 byte header. /// When implementing this, please use the size seen in retail instead of guessing. @@ -36,11 +36,12 @@ pub trait ReadWriteIpcSegment: /// ``` #[binrw] #[derive(Debug, Clone)] +#[br(import(size: &u32))] pub struct IpcSegment where for<'a> OpCode: BinRead = ()> + 'a + std::fmt::Debug, for<'a> OpCode: BinWrite = ()> + 'a + std::fmt::Debug, - for<'a> Data: BinRead = (&'a OpCode,)> + 'a + std::fmt::Debug, + for<'a> Data: BinRead = (&'a OpCode, &'a u32)> + 'a + std::fmt::Debug, for<'a> Data: BinWrite = ()> + 'a + std::fmt::Debug, { /// Unknown purpose, but usually 20. @@ -56,6 +57,6 @@ where pub timestamp: u32, /// The data associated with the opcode. #[brw(pad_before = 4)] - #[br(args(&op_code))] + #[br(args(&op_code, size))] pub data: Data, } diff --git a/src/packet/parsing.rs b/src/packet/parsing.rs index d053828..ead260a 100644 --- a/src/packet/parsing.rs +++ b/src/packet/parsing.rs @@ -96,7 +96,10 @@ pub enum SegmentData { KeepAliveResponse { id: u32, timestamp: u32 }, #[br(pre_assert(kind == SegmentType::KawariIpc))] - KawariIpc { data: CustomIpcSegment }, + KawariIpc { + #[br(args(&0))] // this being zero is okay, custom ipc segments don't use the size arg + data: CustomIpcSegment, + }, } impl Default for SegmentData {