imap: implement sticky buffers

This implements the following sticky buffers for IMAP protocol:
- imap.request
- imap.response

Both match on the request/response lines as sent on the wire and
support firewall rules.

Ticket #8276
pull/16515/head
Giuseppe Longo 9 months ago
parent c3d583349b
commit 295e96a4df

@ -2842,6 +2842,11 @@
"description": "Array of IMAP request lines in this transaction",
"items": {
"type": "string"
},
"suricata": {
"keywords": [
"imap.request"
]
}
},
"responses": {
@ -2849,6 +2854,11 @@
"description": "Array of IMAP response lines in this transaction",
"items": {
"type": "string"
},
"suricata": {
"keywords": [
"imap.response"
]
}
}
}

@ -0,0 +1,153 @@
/* Copyright (C) 2026 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
* Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* version 2 along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
// Author: Giuseppe Longo <glongo@oisf.net>
use crate::core::{STREAM_TOCLIENT, STREAM_TOSERVER};
use crate::detect::{
SIGMATCH_INFO_MULTI_BUFFER, SIGMATCH_INFO_STICKY_BUFFER, SIGMATCH_NOOPT,
SIGMATCH_SUPPORT_FIREWALL,
};
use crate::imap::imap::{ImapTransaction, ALPROTO_IMAP};
use std::ffi::CString;
use std::os::raw::{c_int, c_void};
use suricata_sys::sys::{
DetectEngineCtx, DetectEngineThreadCtx, SCDetectBufferSetActiveList,
SCDetectHelperKeywordRegister, SCDetectHelperKeywordSetCleanCString,
SCDetectHelperMultiBufferProgressMpmRegister, SCDetectSignatureSetAppProto,
SCSigTableAppLiteElmt, Signature,
};
static mut G_IMAP_REQUEST_BUFFER_ID: c_int = 0;
static mut G_IMAP_RESPONSE_BUFFER_ID: c_int = 0;
unsafe extern "C" fn imap_detect_request_setup(
de: *mut DetectEngineCtx, s: *mut Signature, _raw: *const std::os::raw::c_char,
) -> c_int {
if SCDetectSignatureSetAppProto(s, ALPROTO_IMAP) != 0 {
return -1;
}
if SCDetectBufferSetActiveList(de, s, G_IMAP_REQUEST_BUFFER_ID) < 0 {
return -1;
}
0
}
unsafe extern "C" fn imap_tx_get_request(
_de: *mut DetectEngineThreadCtx, tx: *const c_void, _flags: u8, local_id: u32,
buffer: *mut *const u8, buffer_len: *mut u32,
) -> bool {
let tx = cast_pointer!(tx, ImapTransaction);
let Some(request) = tx.requests.get(local_id as usize) else {
return false;
};
*buffer = request.raw_line.as_ptr();
*buffer_len = request.raw_line.len() as u32;
true
}
unsafe extern "C" fn imap_detect_response_setup(
de: *mut DetectEngineCtx, s: *mut Signature, _raw: *const std::os::raw::c_char,
) -> c_int {
if SCDetectSignatureSetAppProto(s, ALPROTO_IMAP) != 0 {
return -1;
}
if SCDetectBufferSetActiveList(de, s, G_IMAP_RESPONSE_BUFFER_ID) < 0 {
return -1;
}
0
}
unsafe extern "C" fn imap_tx_get_response(
_de: *mut DetectEngineThreadCtx, tx: *const c_void, _flags: u8, local_id: u32,
buffer: *mut *const u8, buffer_len: *mut u32,
) -> bool {
let tx = cast_pointer!(tx, ImapTransaction);
let Some(line) = tx.response_lines.get(local_id as usize) else {
return false;
};
*buffer = line.as_ptr();
*buffer_len = line.len() as u32;
true
}
#[no_mangle]
pub unsafe extern "C" fn SCDetectImapRegister() {
let name = CString::new("imap.request").unwrap().into_raw();
let desc = CString::new("match on IMAP request line")
.unwrap()
.into_raw();
let url = CString::new("/rules/imap-keywords.html#imap-request")
.unwrap()
.into_raw();
let kw = SCSigTableAppLiteElmt {
name,
desc,
url,
Setup: Some(imap_detect_request_setup),
flags: SIGMATCH_NOOPT
| SIGMATCH_INFO_STICKY_BUFFER
| SIGMATCH_INFO_MULTI_BUFFER
| SIGMATCH_SUPPORT_FIREWALL,
AppLayerTxMatch: None,
Free: None,
};
let r = SCDetectHelperKeywordRegister(&kw);
SCDetectHelperKeywordSetCleanCString(r);
G_IMAP_REQUEST_BUFFER_ID = SCDetectHelperMultiBufferProgressMpmRegister(
b"imap.request\0".as_ptr() as *const libc::c_char,
b"IMAP REQUEST LINE\0".as_ptr() as *const libc::c_char,
ALPROTO_IMAP,
STREAM_TOSERVER,
Some(imap_tx_get_request),
0,
);
let name = CString::new("imap.response").unwrap().into_raw();
let desc = CString::new("match on IMAP response line")
.unwrap()
.into_raw();
let url = CString::new("/rules/imap-keywords.html#imap-response")
.unwrap()
.into_raw();
let kw = SCSigTableAppLiteElmt {
name,
desc,
url,
Setup: Some(imap_detect_response_setup),
flags: SIGMATCH_NOOPT
| SIGMATCH_INFO_STICKY_BUFFER
| SIGMATCH_INFO_MULTI_BUFFER
| SIGMATCH_SUPPORT_FIREWALL,
AppLayerTxMatch: None,
Free: None,
};
let r = SCDetectHelperKeywordRegister(&kw);
SCDetectHelperKeywordSetCleanCString(r);
G_IMAP_RESPONSE_BUFFER_ID = SCDetectHelperMultiBufferProgressMpmRegister(
b"imap.response\0".as_ptr() as *const libc::c_char,
b"IMAP RESPONSE LINE\0".as_ptr() as *const libc::c_char,
ALPROTO_IMAP,
STREAM_TOCLIENT,
Some(imap_tx_get_response),
1,
);
}

@ -17,6 +17,7 @@
// Author: Giuseppe Longo <glongo@oisf.net>
pub mod detect;
pub mod imap;
pub mod logger;
pub mod parser;

@ -861,6 +861,7 @@ void SigTableSetup(void)
SCDetectSipRegister();
SCDetectTemplateRegister();
SCDetectLdapRegister();
SCDetectImapRegister();
SCDetectSdpRegister();
SCDetectDNSRegister();
SCDetectPgsqlRegister();

Loading…
Cancel
Save