sharksforarms / deku

Declarative binary reading and writing: bit-level, symmetric, serialization/deserialization
Apache License 2.0
1.11k stars 54 forks source link

Reading from a tokio stream #456

Open adamski234 opened 2 months ago

adamski234 commented 2 months ago

I have a message format that looks like this:

struct ApplicationPacket {
    header: PacketHeader,
    message: Message,
}

pub struct PacketHeader {
    pub buffer_size: u32, // contains length of Message in bytes
}

pub enum Message {
    NoOperation,
    RegisterDevice(RegisterDevicePacket), // 54 bytes long
    UnregisterDevice(UnregisterDevicePacket), // 1 byte long
    InitiateConnection(InitiateConnectionPacket), // 32 bytes long
}

Reading this from a std::net::TcpStream is trivial: ApplicationPacket::from_reader((&mut stream, 0)); However, when combined with async streams, this becomes much more involved. First I read the header, which contains the size of the rest of the message. Then I read PacketHeader::buffer_size bytes, concat that with the header, and parse the whole thing with ApplicationPacket::from_bytes.

This works, but is susceptible to attacks and dumb mistakes. buffer_size can be incorrectly specified in either direction, leading to either not having enough data to parse the full message, or halting the process until enough additional data has been passed to the TCP stream. I can protect against the latter case by comparing the buffer size with a predefined max size, and aborting the process before it finishes, but that's not a reliable solution.

Is there a way to not have to rely on the stated buffer size for decoding without a compatible reader?