pgsql: allow multi-request transactions

Important for CopyIn mode/ subprotocol, where the frontend is the one
sending 0 or more messages to the backend as part of a transaction.

Related to
Task #7645
pull/13366/head
Juliana Fajardini 3 months ago
parent b3b0bbd1c3
commit decbb0ba5f

@ -46,10 +46,12 @@ unsafe extern "C" fn pgsql_detect_query_get_data(
) -> bool {
let tx = cast_pointer!(tx, PgsqlTransaction);
if let Some(PgsqlFEMessage::SimpleQuery(ref query)) = &tx.request {
*buffer = query.payload.as_ptr();
*buffer_len = query.payload.len() as u32;
return true;
for request in &tx.requests {
if let PgsqlFEMessage::SimpleQuery(ref query) = request {
*buffer = query.payload.as_ptr();
*buffer_len = query.payload.len() as u32;
return true;
}
}
*buffer = std::ptr::null();

@ -29,8 +29,15 @@ pub const PGSQL_LOG_PASSWORDS: u32 = BIT_U32!(0);
fn log_pgsql(tx: &PgsqlTransaction, flags: u32, js: &mut JsonBuilder) -> Result<(), JsonError> {
js.open_object("pgsql")?;
js.set_uint("tx_id", tx.tx_id)?;
if let Some(request) = &tx.request {
js.set_object("request", &log_request(request, flags)?)?;
if !tx.requests.is_empty() {
// For now, even if 'requests' is an array, we don't need to log it as such, as
// there are no duplicated messages
js.open_object("request")?;
for request in &tx.requests {
SCLogNotice!("Suricata requests length: {}", tx.requests.len());
log_request(request, flags, js)?;
}
js.close()?;
} else if tx.responses.is_empty() {
SCLogDebug!("Suricata created an empty PGSQL transaction");
// TODO Log anomaly event?
@ -48,8 +55,7 @@ fn log_pgsql(tx: &PgsqlTransaction, flags: u32, js: &mut JsonBuilder) -> Result<
Ok(())
}
fn log_request(req: &PgsqlFEMessage, flags: u32) -> Result<JsonBuilder, JsonError> {
let mut js = JsonBuilder::try_new_object()?;
fn log_request(req: &PgsqlFEMessage, flags: u32, js: &mut JsonBuilder) -> Result<(), JsonError> {
match req {
PgsqlFEMessage::StartupMessage(StartupPacket {
length: _,
@ -118,8 +124,7 @@ fn log_request(req: &PgsqlFEMessage, flags: u32) -> Result<JsonBuilder, JsonErro
// We don't want to log these, for now. Cf redmine: #6576
}
}
js.close()?;
Ok(js)
Ok(())
}
fn log_response_object(tx: &PgsqlTransaction) -> Result<JsonBuilder, JsonError> {

@ -60,7 +60,7 @@ pub struct PgsqlTransaction {
pub tx_id: u64,
pub tx_req_state: PgsqlTxProgress,
pub tx_res_state: PgsqlTxProgress,
pub request: Option<PgsqlFEMessage>,
pub requests: Vec<PgsqlFEMessage>,
pub responses: Vec<PgsqlBEMessage>,
pub data_row_cnt: u64,
@ -87,7 +87,7 @@ impl PgsqlTransaction {
tx_id: 0,
tx_req_state: PgsqlTxProgress::TxInit,
tx_res_state: PgsqlTxProgress::TxInit,
request: None,
requests: Vec::<PgsqlFEMessage>::new(),
responses: Vec::<PgsqlBEMessage>::new(),
data_row_cnt: 0,
data_size: 0,
@ -380,7 +380,7 @@ impl PgsqlState {
// https://samadhiweb.com/blog/2013.04.28.graphviz.postgresv3.html
if let Some(tx) = self.find_or_create_tx() {
tx.tx_data.updated_ts = true;
tx.request = Some(request);
tx.requests.push(request);
if let Some(state) = new_state {
if Self::request_is_complete(state) {
// The request is always complete at this point

Loading…
Cancel
Save