sfackler / rust-postgres

Native PostgreSQL driver for the Rust programming language
Apache License 2.0
3.44k stars 436 forks source link

WIP add backend messages serialization and frontend messages deserialization #946

Open prx0 opened 2 years ago

prx0 commented 2 years ago

PR related to https://github.com/sfackler/rust-postgres/issues/942

The goal is to allow serialization of backend message into bytes and deserialization of frontend message into rust object that we can handle. It could be useful for making a proxy or a fake postgresql server. (honeypot)

I've still lot of work to do here. My approach for backend message serialization is to implement TryFrom for Message in order to convert them into bytes. I'm open to suggestions if you know a better way to do this of course.

Postgresql message flow documentation: https://www.postgresql.org/docs/current/protocol-message-formats.html

Thank you!

prx0 commented 2 years ago

Hi Max, I actually wanted to implement the same thing as I was inspired by https://github.com/jackc/pgproto3. You can get a lot of pointers for parsing the messages there

Hello!

Thank you. I use already pgproto3 in my company but I still want to continue this PR because I would like to work with Rust.

I'll check out the source code of pgproto3 to get some help.

Backend serialization is quite easy. But frontend deserialization is not.

I need some motivations and time, but I promess I'll finish this PR. ^^'

zain-kabani commented 2 years ago

Hi I've been working on a project to make creating postgres proxies easier in rust. I've just gotten started on it and welcome any contributions to it! https://github.com/zain-kabani/postgres-proto-rs

prx0 commented 2 years ago

@zain-kabani that's great! I noticed that you've started to implement deserialization for frontend messages. That's what I try to do here. (also be careful you didn't specify any license in your project)

I don't know if it's a good idea to create another crate to add postgres protocol parsing because the rust-postgres crate made by @sfackler do this already. rust-postgres is a dependency of the postgres crate which is massively used. It would be great to add deserialization and serialization into rust-postgres in order to add functionnalities for existing projects based on this crate.

I think it would be awesome to create a framework for making progresql proxies with rust-postgres as dependency. pgcat is another inspiring project. https://github.com/levkk/pgcat Not a framework but a tool to manage sharding avec load balancing for postgres databases.

EDIT: your frontend messages are mainly struct with a ByteMut attribute called message_byte. That's a simple approach I like. In my case I would like to implement something more like the structs from jackc/pgproto3. The idea is to be able to modify each parameter of a frontend message.

Example for a BindBody

#[non_exaustive]
pub enum Message {
    Bind(BindBody),
    Close(CloseBody),
    CopyFail(CopyFailBody),
    Descibe(DescribeBody),
    Execute(ExecuteBody),
    Flush(FlushBody),
    FunctionCall(FunctionCall),
    GSSENCRequest(GSSENCRequestBody),
    GSSResponse(GSSResponseBody),
    Parse(ParseBody),
    PasswordMessage(PasswordMessageBody),
    Query(QueryBody),
    SASLInitialResponse(SASLInitialResponseBody),
    SASLResponse(SASLResponseBody),
    SSLRequest(SSLRequestBody),
    StartupMessage(StartupMessageBody),
    Sync(SyncBody),
    Terminate(TerminateBody),
}

// highly based on https://github.com/jackc/pgproto3/blob/master/bind.go
pub struct BindBody {
    pub destination_portal: String,
    pub prepared_statement: String,
    pub parameter_format_codes: Vec<u16>,
    pub parameters: Vec<Vec<Bytes>>,
    pub result_format_codes: Vec<u16>,
}

I don't know if it's a good idea to go into such details than using a simple attribute which do the job.

zain-kabani commented 2 years ago

Hi Max, yeah I considered adding to this repo too but didn't want to rock the boat too much here and decided to just create a separate project. Fun fact I'm actually an active contributor to the pgcat project, and built this with pgcat in mind.

Yes those are there temporarily as I still have to implement the logic of encoding/decoding them. (contributions are welcome!)