From cbe29429cadc9506250ab237eef292ced421bef6 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Fri, 4 Oct 2024 14:45:59 +0200 Subject: [PATCH 01/19] sdp: log media's encryption key The encryption key subfield of the media description field is not logged when it should be. Ticket #7305 --- etc/schema.json | 6 ++++++ rust/src/sdp/logger.rs | 3 +++ 2 files changed, 9 insertions(+) diff --git a/etc/schema.json b/etc/schema.json index 9decf4c42bf9..92884677e78e 100644 --- a/etc/schema.json +++ b/etc/schema.json @@ -4112,6 +4112,12 @@ "optional": true, "description": "Connection data per media description" }, + "encryption_key": { + "type": "string", + "optional": true, + "description": + "Field used to convey encryption keys if SDP is used over a secure channel" + }, "attributes": { "type": "array", "description": diff --git a/rust/src/sdp/logger.rs b/rust/src/sdp/logger.rs index 43e16049ab59..f5d3b6fdd0f6 100644 --- a/rust/src/sdp/logger.rs +++ b/rust/src/sdp/logger.rs @@ -102,6 +102,9 @@ fn log_media_description( if let Some(conn_data) = &m.connection_data { log_connection_data(conn_data, js)?; } + if let Some(enc_key) = &m.encryption_key { + js.set_string("encryption_key", enc_key)?; + } if let Some(attrs) = &m.attributes { log_attributes(attrs, js)?; } From 3d9ce6b3e554506b63e1e148cd0a7699f393847d Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Fri, 4 Oct 2024 08:56:24 +0200 Subject: [PATCH 02/19] sdp: stringify structured fields The current parser implementations take a field, such as connection data, and split it into subfields for a specific structure (e.g., struct ConnectionData). However, following this approach requires several sticky buffers to match the whole field, which can make a rule a bit verbose and doesn't offer any advantage for matching specific parts of a field. With this patch, a single line is still split into pieces if it makes sense for parsing purposes, but these pieces are then reassembled into a single string. This way, only one sticky buffer is needed to match the entire field. Ticket #7291 --- rust/src/sdp/logger.rs | 48 ++------------ rust/src/sdp/parser.rs | 146 +++++++++++++---------------------------- 2 files changed, 51 insertions(+), 143 deletions(-) diff --git a/rust/src/sdp/logger.rs b/rust/src/sdp/logger.rs index f5d3b6fdd0f6..2951d772f852 100644 --- a/rust/src/sdp/logger.rs +++ b/rust/src/sdp/logger.rs @@ -19,22 +19,12 @@ use crate::jsonbuilder::{JsonBuilder, JsonError}; -use super::parser::{ConnectionData, MediaDescription, SdpMessage}; +use super::parser::{MediaDescription, SdpMessage}; pub fn sdp_log(msg: &SdpMessage, js: &mut JsonBuilder) -> Result<(), JsonError> { js.open_object("sdp")?; - let origin = format!( - "{} {} {} {} {} {}", - &msg.origin.username, - &msg.origin.sess_id, - &msg.origin.sess_version, - &msg.origin.nettype, - &msg.origin.addrtype, - &msg.origin.unicast_address - ); - - js.set_string("origin", &origin)?; + js.set_string("origin", &msg.origin)?; js.set_string("session_name", &msg.session_name)?; if let Some(session_info) = &msg.session_info { @@ -50,7 +40,7 @@ pub fn sdp_log(msg: &SdpMessage, js: &mut JsonBuilder) -> Result<(), JsonError> js.set_string("phone_number", phone_number)?; } if let Some(conn_data) = &msg.connection_data { - log_connection_data(conn_data, js)?; + js.set_string("connection_data", conn_data)?; } if let Some(bws) = &msg.bandwidths { log_bandwidth(bws, js)?; @@ -82,17 +72,7 @@ fn log_media_description( js.open_array("media_descriptions")?; for m in media { js.start_object()?; - let port = if let Some(num_ports) = m.number_of_ports { - format!("{}/{}", m.port, num_ports) - } else { - format!("{}", m.port) - }; - let mut media = format!("{} {} {}", &m.media, &port, &m.proto); - for f in &m.fmt { - media = format!("{} {}", media, f); - } - js.set_string("media", &media)?; - + js.set_string("media", &m.media)?; if let Some(session_info) = &m.session_info { js.set_string("media_info", session_info)?; }; @@ -100,7 +80,7 @@ fn log_media_description( log_bandwidth(bws, js)?; } if let Some(conn_data) = &m.connection_data { - log_connection_data(conn_data, js)?; + js.set_string("connection_data", conn_data)?; } if let Some(enc_key) = &m.encryption_key { js.set_string("encryption_key", enc_key)?; @@ -127,24 +107,6 @@ fn log_bandwidth(bws: &Vec, js: &mut JsonBuilder) -> Result<(), JsonErro Ok(()) } -fn log_connection_data(conn_data: &ConnectionData, js: &mut JsonBuilder) -> Result<(), JsonError> { - let mut conn = format!( - "{} {} {}", - &conn_data.nettype, - &conn_data.addrtype, - &conn_data.connection_address.to_string() - ); - if let Some(ttl) = conn_data.ttl { - conn = format!("{}/{}", conn, ttl); - js.set_uint("ttl", ttl as u64)?; - } - if let Some(num_addrs) = conn_data.number_of_addresses { - conn = format!("{}/{}", conn, num_addrs); - } - js.set_string("connection_data", &conn)?; - Ok(()) -} - fn log_attributes(attrs: &Vec, js: &mut JsonBuilder) -> Result<(), JsonError> { if !attrs.is_empty() { js.open_array("attributes")?; diff --git a/rust/src/sdp/parser.rs b/rust/src/sdp/parser.rs index 2a501b4a3216..2f2baed9fc3d 100644 --- a/rust/src/sdp/parser.rs +++ b/rust/src/sdp/parser.rs @@ -40,13 +40,13 @@ use std::str::FromStr; #[derive(Debug)] pub struct SdpMessage { pub version: u32, - pub origin: OriginField, + pub origin: String, pub session_name: String, pub session_info: Option, pub uri: Option, pub email: Option, pub phone_number: Option, - pub connection_data: Option, + pub connection_data: Option, pub bandwidths: Option>, pub time: String, pub repeat_time: Option, @@ -56,34 +56,11 @@ pub struct SdpMessage { pub media_description: Option>, } -#[derive(Debug)] -pub struct OriginField { - pub username: String, - pub sess_id: String, - pub sess_version: String, - pub nettype: String, - pub addrtype: String, - pub unicast_address: String, -} - -#[derive(Debug)] -pub struct ConnectionData { - pub nettype: String, - pub addrtype: String, - pub connection_address: IpAddr, - pub ttl: Option, - pub number_of_addresses: Option, -} - #[derive(Debug)] pub struct MediaDescription { pub media: String, - pub port: u16, - pub number_of_ports: Option, - pub proto: String, - pub fmt: Vec, pub session_info: Option, - pub connection_data: Option, + pub connection_data: Option, pub bandwidths: Option>, pub encryption_key: Option, pub attributes: Option>, @@ -208,7 +185,7 @@ fn parse_version_line(i: &[u8]) -> IResult<&[u8], u32> { Ok((i, 0)) } -fn parse_origin_line(i: &[u8]) -> IResult<&[u8], OriginField> { +fn parse_origin_line(i: &[u8]) -> IResult<&[u8], String> { let (i, _) = tag("o=")(i)?; let (i, username) = map_res(take_while(is_token_char), std::str::from_utf8)(i)?; let (i, _) = space1(i)?; @@ -223,17 +200,12 @@ fn parse_origin_line(i: &[u8]) -> IResult<&[u8], OriginField> { let (i, unicast_address) = map_res(take_till(is_line_ending), std::str::from_utf8)(i)?; let (i, _) = line_ending(i)?; - Ok(( - i, - OriginField { - username: username.to_string(), - sess_id: sess_id.to_string(), - sess_version: sess_version.to_string(), - nettype: nettype.to_string(), - addrtype: addrtype.to_string(), - unicast_address: unicast_address.to_string(), - }, - )) + let origin_line = format!( + "{} {} {} {} {} {}", + username, sess_id, sess_version, nettype, addrtype, unicast_address + ); + + Ok((i, origin_line)) } fn parse_session_name(i: &[u8]) -> IResult<&[u8], String> { @@ -257,7 +229,7 @@ fn parse_uri(i: &[u8]) -> IResult<&[u8], String> { Ok((i, uri.to_string())) } -fn parse_connection_data(i: &[u8]) -> IResult<&[u8], ConnectionData> { +fn parse_connection_data(i: &[u8]) -> IResult<&[u8], String> { let (i, _) = tag("c=")(i)?; let (i, nettype) = map_res(take_while(is_alphabetic), std::str::from_utf8)(i)?; let (i, _) = space1(i)?; @@ -286,16 +258,20 @@ fn parse_connection_data(i: &[u8]) -> IResult<&[u8], ConnectionData> { _ => (None, None), }; - Ok(( - i, - ConnectionData { - nettype: nettype.to_string(), - addrtype: addrtype.to_string(), - connection_address, - ttl, - number_of_addresses, - }, - )) + let mut connection_data = format!( + "{} {} {}", + &nettype, + &addrtype, + &connection_address.to_string() + ); + if let Some(ttl) = ttl { + connection_data = format!("{}/{}", connection_data, ttl); + } + if let Some(num_addrs) = number_of_addresses { + connection_data = format!("{}/{}", connection_data, num_addrs); + } + + Ok((i, connection_data)) } fn parse_email(i: &[u8]) -> IResult<&[u8], String> { @@ -464,23 +440,29 @@ fn parse_media_description(i: &[u8]) -> IResult<&[u8], MediaDescription> { let (i, encryption_key) = opt(parse_encryption_key)(i)?; let (i, attributes) = opt(parse_attributes)(i)?; - let port = match port.parse::() { + let port: u16 = match port.parse::() { Ok(p) => p, - Err(_) => return Err(Err::Error(make_error(i, ErrorKind::HexDigit))) + Err(_) => return Err(Err::Error(make_error(i, ErrorKind::HexDigit))), }; - let number_of_ports = match number_of_ports { + let number_of_ports: Option = match number_of_ports { Some(num_str) => num_str.parse().ok(), None => None, }; + let port = if let Some(num_ports) = number_of_ports { + format!("{}/{}", port, num_ports) + } else { + format!("{}", port) + }; + let mut media_str = format!("{} {} {}", &media, &port, &proto); + let fmt: Vec = fmt.into_iter().map(String::from).collect(); + for f in &fmt { + media_str = format!("{} {}", media_str, f); + } Ok(( i, MediaDescription { - media, - port, - number_of_ports, - proto, - fmt: fmt.into_iter().map(String::from).collect(), + media: media_str, session_info, connection_data, bandwidths, @@ -506,12 +488,7 @@ mod tests { let buf: &[u8] = "o=Clarent 120386 120387 IN IP4 200.57.7.196\r\n".as_bytes(); let (_, o) = parse_origin_line(buf).expect("parsing failed"); - assert_eq!(o.username, "Clarent"); - assert_eq!(o.sess_id, "120386"); - assert_eq!(o.sess_version, "120387"); - assert_eq!(o.nettype, "IN"); - assert_eq!(o.addrtype, "IP4"); - assert_eq!(o.unicast_address, "200.57.7.196"); + assert_eq!(o, "Clarent 120386 120387 IN IP4 200.57.7.196"); } #[test] @@ -543,14 +520,7 @@ mod tests { let buf: &[u8] = "c=IN IP4 224.2.36.42/127\r\n".as_bytes(); let (_, c) = parse_connection_data(buf).expect("parsing failed"); - assert_eq!(c.nettype, "IN"); - assert_eq!(c.addrtype, "IP4"); - assert_eq!( - c.connection_address, - IpAddr::from_str("224.2.36.42").unwrap() - ); - assert_eq!(c.ttl, Some(127)); - assert_eq!(c.number_of_addresses, None); + assert_eq!(c, "IN IP4 224.2.36.42/127"); } #[test] @@ -558,11 +528,7 @@ mod tests { let buf: &[u8] = "c=IN IP6 FF15::101/3\r\n".as_bytes(); let (_, c) = parse_connection_data(buf).expect("parsing failed"); - assert_eq!(c.nettype, "IN"); - assert_eq!(c.addrtype, "IP6"); - assert_eq!(c.connection_address, IpAddr::from_str("FF15::101").unwrap()); - assert_eq!(c.ttl, None); - assert_eq!(c.number_of_addresses, Some(3)); + assert_eq!(c, "IN IP6 ff15::101/3"); } #[test] @@ -570,14 +536,7 @@ mod tests { let buf: &[u8] = "c=IN IP4 224.2.36.42/127/2\r\n".as_bytes(); let (_, c) = parse_connection_data(buf).expect("parsing failed"); - assert_eq!(c.nettype, "IN"); - assert_eq!(c.addrtype, "IP4"); - assert_eq!( - c.connection_address, - IpAddr::from_str("224.2.36.42").unwrap() - ); - assert_eq!(c.ttl, Some(127)); - assert_eq!(c.number_of_addresses, Some(2)); + assert_eq!(c, "IN IP4 224.2.36.42/127/2"); } #[test] @@ -593,11 +552,7 @@ mod tests { let buf: &[u8] = "c=IN IP4 8.8.8.8\r\n".as_bytes(); let (_, c) = parse_connection_data(buf).expect("parsing failed"); - assert_eq!(c.nettype, "IN"); - assert_eq!(c.addrtype, "IP4"); - assert_eq!(c.connection_address, IpAddr::from_str("8.8.8.8").unwrap()); - assert_eq!(c.ttl, None); - assert_eq!(c.number_of_addresses, None); + assert_eq!(c, "IN IP4 8.8.8.8"); } #[test] @@ -605,11 +560,7 @@ mod tests { let buf: &[u8] = "c=IN IP6 FF15::101\r\n".as_bytes(); let (_, c) = parse_connection_data(buf).expect("parsing failed"); - assert_eq!(c.nettype, "IN"); - assert_eq!(c.addrtype, "IP6"); - assert_eq!(c.connection_address, IpAddr::from_str("FF15::101").unwrap()); - assert_eq!(c.ttl, None); - assert_eq!(c.number_of_addresses, None); + assert_eq!(c, "IN IP6 ff15::101"); } #[test] @@ -682,12 +633,7 @@ mod tests { fn test_media_line() { let buf: &[u8] = "m=audio 40392 RTP/AVP 8 0\r\n".as_bytes(); let (_, m) = parse_media_description(buf).expect("parsing failed"); - assert_eq!(m.media, "audio"); - assert_eq!(m.port, 40392); - assert_eq!(m.number_of_ports, None); - assert_eq!(m.proto, "RTP/AVP"); - assert_eq!(m.fmt.first().unwrap(), "8"); - assert_eq!(m.fmt.get(1).unwrap(), "0"); + assert_eq!(m.media, "audio 40392 RTP/AVP 8 0"); } #[test] From bc816454a07b26e3c6ccff5e9db55127172cb686 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Mon, 30 Sep 2024 09:55:33 +0200 Subject: [PATCH 03/19] sdp: add sdp.session_name sticky buffer This adds a sticky buffer to match the "Session name" field in both requests and responses. Ticket #7291 --- rust/src/sdp/detect.rs | 100 +++++++++++++++++++++++++++++++++++ rust/src/sdp/mod.rs | 20 +++++++ src/detect-engine-register.c | 1 + 3 files changed, 121 insertions(+) create mode 100644 rust/src/sdp/detect.rs diff --git a/rust/src/sdp/detect.rs b/rust/src/sdp/detect.rs new file mode 100644 index 000000000000..6cf2a3d3415e --- /dev/null +++ b/rust/src/sdp/detect.rs @@ -0,0 +1,100 @@ +/* Copyright (C) 2024 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. + */ + +// written by Giuseppe Longo + +use crate::core::Direction; +use crate::detect::{ + DetectBufferSetActiveList, DetectHelperBufferMpmRegister, DetectHelperGetData, + DetectHelperKeywordRegister, DetectSignatureSetAppProto, SCSigTableElmt, SIGMATCH_NOOPT, +}; +use crate::sip::sip::{SIPTransaction, ALPROTO_SIP}; +use std::os::raw::{c_int, c_void}; +use std::ptr; + +static mut G_SDP_SESSION_NAME_BUFFER_ID: c_int = 0; + +unsafe extern "C" fn sdp_session_name_setup( + de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_SIP) != 0 { + return -1; + } + if DetectBufferSetActiveList(de, s, G_SDP_SESSION_NAME_BUFFER_ID) < 0 { + return -1; + } + return 0; +} + +unsafe extern "C" fn sdp_session_name_get( + de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8, + tx: *const c_void, list_id: c_int, +) -> *mut c_void { + return DetectHelperGetData( + de, + transforms, + flow, + flow_flags, + tx, + list_id, + sdp_session_name_get_data, + ); +} + +unsafe extern "C" fn sdp_session_name_get_data( + tx: *const c_void, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, SIPTransaction); + let sdp_message = match direction.into() { + Direction::ToServer => tx.request.as_ref().and_then(|req| req.body.as_ref()), + Direction::ToClient => tx.response.as_ref().and_then(|resp| resp.body.as_ref()), + }; + if let Some(sdp) = sdp_message { + let session_name = &sdp.session_name; + if !session_name.is_empty() { + *buffer = session_name.as_ptr(); + *buffer_len = session_name.len() as u32; + return true; + } + } + *buffer = ptr::null(); + *buffer_len = 0; + false +} + +#[no_mangle] +pub unsafe extern "C" fn ScDetectSdpRegister() { + let kw = SCSigTableElmt { + name: b"sdp.session_name\0".as_ptr() as *const libc::c_char, + desc: b"sticky buffer to match on the SDP session name field\0".as_ptr() + as *const libc::c_char, + url: b"/rules/sdp-keywords.html#sdp-session-name\0".as_ptr() as *const libc::c_char, + Setup: sdp_session_name_setup, + flags: SIGMATCH_NOOPT, + AppLayerTxMatch: None, + Free: None, + }; + let _ = DetectHelperKeywordRegister(&kw); + G_SDP_SESSION_NAME_BUFFER_ID = DetectHelperBufferMpmRegister( + b"sdp.session_name\0".as_ptr() as *const libc::c_char, + b"sdp.session_name\0".as_ptr() as *const libc::c_char, + ALPROTO_SIP, + true, + true, + sdp_session_name_get, + ); +} diff --git a/rust/src/sdp/mod.rs b/rust/src/sdp/mod.rs index 7f87c8b7e2f0..6aa7861d4996 100644 --- a/rust/src/sdp/mod.rs +++ b/rust/src/sdp/mod.rs @@ -1,2 +1,22 @@ +/* Copyright (C) 2024 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. + */ + +// written by Giuseppe Longo + +pub mod detect; pub mod logger; pub mod parser; diff --git a/src/detect-engine-register.c b/src/detect-engine-register.c index 794f680dd46f..724b67298321 100644 --- a/src/detect-engine-register.c +++ b/src/detect-engine-register.c @@ -695,6 +695,7 @@ void SigTableSetup(void) ScDetectMqttRegister(); ScDetectRfbRegister(); ScDetectSipRegister(); + ScDetectSdpRegister(); /* close keyword registration */ DetectBufferTypeCloseRegistration(); From 1d022e6b72863b664184be10932336a4bdbade85 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Mon, 30 Sep 2024 09:57:36 +0200 Subject: [PATCH 04/19] sdp: add sdp.session_info sticky buffer This adds a sticky buffer to match the "Session information" field in both requests and responses. Ticket #7291 --- rust/src/sdp/detect.rs | 69 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/rust/src/sdp/detect.rs b/rust/src/sdp/detect.rs index 6cf2a3d3415e..322b71710688 100644 --- a/rust/src/sdp/detect.rs +++ b/rust/src/sdp/detect.rs @@ -27,6 +27,7 @@ use std::os::raw::{c_int, c_void}; use std::ptr; static mut G_SDP_SESSION_NAME_BUFFER_ID: c_int = 0; +static mut G_SDP_SESSION_INFO_BUFFER_ID: c_int = 0; unsafe extern "C" fn sdp_session_name_setup( de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, @@ -76,6 +77,55 @@ unsafe extern "C" fn sdp_session_name_get_data( false } +unsafe extern "C" fn sdp_session_info_setup( + de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_SIP) != 0 { + return -1; + } + if DetectBufferSetActiveList(de, s, G_SDP_SESSION_INFO_BUFFER_ID) < 0 { + return -1; + } + return 0; +} + +unsafe extern "C" fn sdp_session_info_get( + de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8, + tx: *const c_void, list_id: c_int, +) -> *mut c_void { + return DetectHelperGetData( + de, + transforms, + flow, + flow_flags, + tx, + list_id, + sdp_session_info_get_data, + ); +} + +unsafe extern "C" fn sdp_session_info_get_data( + tx: *const c_void, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, SIPTransaction); + let sdp_message = match direction.into() { + Direction::ToServer => tx.request.as_ref().and_then(|req| req.body.as_ref()), + Direction::ToClient => tx.response.as_ref().and_then(|resp| resp.body.as_ref()), + }; + if let Some(sdp) = sdp_message { + if let Some(ref s) = sdp.session_info { + if !s.is_empty() { + *buffer = s.as_ptr(); + *buffer_len = s.len() as u32; + return true; + } + } + } + *buffer = ptr::null(); + *buffer_len = 0; + false +} + #[no_mangle] pub unsafe extern "C" fn ScDetectSdpRegister() { let kw = SCSigTableElmt { @@ -97,4 +147,23 @@ pub unsafe extern "C" fn ScDetectSdpRegister() { true, sdp_session_name_get, ); + let kw = SCSigTableElmt { + name: b"sdp.session_info\0".as_ptr() as *const libc::c_char, + desc: b"sticky buffer to match on the SDP session info field\0".as_ptr() + as *const libc::c_char, + url: b"/rules/sdp-keywords.html#sdp-session-info\0".as_ptr() as *const libc::c_char, + Setup: sdp_session_info_setup, + flags: SIGMATCH_NOOPT, + AppLayerTxMatch: None, + Free: None, + }; + let _ = DetectHelperKeywordRegister(&kw); + G_SDP_SESSION_INFO_BUFFER_ID = DetectHelperBufferMpmRegister( + b"sdp.session_info\0".as_ptr() as *const libc::c_char, + b"sdp.session_info\0".as_ptr() as *const libc::c_char, + ALPROTO_SIP, + true, + true, + sdp_session_info_get, + ); } From 85e2291e9b991bb4dbe8aad667a39614e610a98b Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Mon, 30 Sep 2024 10:44:42 +0200 Subject: [PATCH 05/19] sdp: add sdp.origin sticky buffer This adds a sticky buffer to match the "Origin" field in both requests and responses. Ticket #7291 --- rust/src/sdp/detect.rs | 67 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/rust/src/sdp/detect.rs b/rust/src/sdp/detect.rs index 322b71710688..bbe29cd6c9f6 100644 --- a/rust/src/sdp/detect.rs +++ b/rust/src/sdp/detect.rs @@ -26,6 +26,7 @@ use crate::sip::sip::{SIPTransaction, ALPROTO_SIP}; use std::os::raw::{c_int, c_void}; use std::ptr; +static mut G_SDP_ORIGIN_BUFFER_ID: c_int = 0; static mut G_SDP_SESSION_NAME_BUFFER_ID: c_int = 0; static mut G_SDP_SESSION_INFO_BUFFER_ID: c_int = 0; @@ -126,6 +127,54 @@ unsafe extern "C" fn sdp_session_info_get_data( false } +unsafe extern "C" fn sdp_origin_setup( + de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_SIP) != 0 { + return -1; + } + if DetectBufferSetActiveList(de, s, G_SDP_ORIGIN_BUFFER_ID) < 0 { + return -1; + } + return 0; +} + +unsafe extern "C" fn sdp_origin_get( + de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8, + tx: *const c_void, list_id: c_int, +) -> *mut c_void { + return DetectHelperGetData( + de, + transforms, + flow, + flow_flags, + tx, + list_id, + sdp_origin_get_data, + ); +} + +unsafe extern "C" fn sdp_origin_get_data( + tx: *const c_void, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, SIPTransaction); + let sdp_option = match direction.into() { + Direction::ToServer => tx.request.as_ref().and_then(|req| req.body.as_ref()), + Direction::ToClient => tx.response.as_ref().and_then(|resp| resp.body.as_ref()), + }; + if let Some(sdp) = sdp_option { + let origin = &sdp.origin; + if !origin.is_empty() { + *buffer = origin.as_ptr(); + *buffer_len = origin.len() as u32; + return true; + } + } + *buffer = ptr::null(); + *buffer_len = 0; + false +} + #[no_mangle] pub unsafe extern "C" fn ScDetectSdpRegister() { let kw = SCSigTableElmt { @@ -166,4 +215,22 @@ pub unsafe extern "C" fn ScDetectSdpRegister() { true, sdp_session_info_get, ); + let kw = SCSigTableElmt { + name: b"sdp.origin\0".as_ptr() as *const libc::c_char, + desc: b"sticky buffer to match on the SDP origin field\0".as_ptr() as *const libc::c_char, + url: b"/rules/sdp-keywords.html#sdp-origin\0".as_ptr() as *const libc::c_char, + Setup: sdp_origin_setup, + flags: SIGMATCH_NOOPT, + AppLayerTxMatch: None, + Free: None, + }; + let _ = DetectHelperKeywordRegister(&kw); + G_SDP_ORIGIN_BUFFER_ID = DetectHelperBufferMpmRegister( + b"sdp.origin\0".as_ptr() as *const libc::c_char, + b"sdp.origin\0".as_ptr() as *const libc::c_char, + ALPROTO_SIP, + true, + true, + sdp_origin_get, + ); } From 7f8b708eeb9fba098b2ddeb6aa9e51c0f67dae95 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Mon, 30 Sep 2024 10:51:17 +0200 Subject: [PATCH 06/19] sdp: add sdp.uri sticky buffer This adds a sticky buffer to match the "Uri" field in both requests and responses. Ticket #7291 --- rust/src/sdp/detect.rs | 68 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/rust/src/sdp/detect.rs b/rust/src/sdp/detect.rs index bbe29cd6c9f6..97fbaaf9022d 100644 --- a/rust/src/sdp/detect.rs +++ b/rust/src/sdp/detect.rs @@ -29,6 +29,7 @@ use std::ptr; static mut G_SDP_ORIGIN_BUFFER_ID: c_int = 0; static mut G_SDP_SESSION_NAME_BUFFER_ID: c_int = 0; static mut G_SDP_SESSION_INFO_BUFFER_ID: c_int = 0; +static mut G_SDP_URI_BUFFER_ID: c_int = 0; unsafe extern "C" fn sdp_session_name_setup( de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, @@ -175,6 +176,55 @@ unsafe extern "C" fn sdp_origin_get_data( false } +unsafe extern "C" fn sdp_uri_setup( + de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_SIP) != 0 { + return -1; + } + if DetectBufferSetActiveList(de, s, G_SDP_URI_BUFFER_ID) < 0 { + return -1; + } + return 0; +} + +unsafe extern "C" fn sdp_uri_get( + de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8, + tx: *const c_void, list_id: c_int, +) -> *mut c_void { + return DetectHelperGetData( + de, + transforms, + flow, + flow_flags, + tx, + list_id, + sdp_uri_get_data, + ); +} + +unsafe extern "C" fn sdp_uri_get_data( + tx: *const c_void, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, SIPTransaction); + let sdp_option = match direction.into() { + Direction::ToServer => tx.request.as_ref().and_then(|req| req.body.as_ref()), + Direction::ToClient => tx.response.as_ref().and_then(|resp| resp.body.as_ref()), + }; + if let Some(sdp) = sdp_option { + if let Some(ref u) = sdp.uri { + if !u.is_empty() { + *buffer = u.as_ptr(); + *buffer_len = u.len() as u32; + return true; + } + } + } + *buffer = ptr::null(); + *buffer_len = 0; + false +} + #[no_mangle] pub unsafe extern "C" fn ScDetectSdpRegister() { let kw = SCSigTableElmt { @@ -233,4 +283,22 @@ pub unsafe extern "C" fn ScDetectSdpRegister() { true, sdp_origin_get, ); + let kw = SCSigTableElmt { + name: b"sdp.uri\0".as_ptr() as *const libc::c_char, + desc: b"sticky buffer to match on the SDP uri field\0".as_ptr() as *const libc::c_char, + url: b"/rules/sdp-keywords.html#sdp-uri\0".as_ptr() as *const libc::c_char, + Setup: sdp_uri_setup, + flags: SIGMATCH_NOOPT, + AppLayerTxMatch: None, + Free: None, + }; + let _ = DetectHelperKeywordRegister(&kw); + G_SDP_URI_BUFFER_ID = DetectHelperBufferMpmRegister( + b"sdp.uri\0".as_ptr() as *const libc::c_char, + b"sdp.uri\0".as_ptr() as *const libc::c_char, + ALPROTO_SIP, + true, + true, + sdp_uri_get, + ); } From 04a70b60bf001f3312514fdc6ac1f42262c57fde Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Mon, 30 Sep 2024 15:04:10 +0200 Subject: [PATCH 07/19] sdp: add sdp.email sticky buffer This adds a sticky buffer to match the "Email" field in both requests and responses. Ticket #7291 --- rust/src/sdp/detect.rs | 68 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/rust/src/sdp/detect.rs b/rust/src/sdp/detect.rs index 97fbaaf9022d..eb102798a17c 100644 --- a/rust/src/sdp/detect.rs +++ b/rust/src/sdp/detect.rs @@ -30,6 +30,7 @@ static mut G_SDP_ORIGIN_BUFFER_ID: c_int = 0; static mut G_SDP_SESSION_NAME_BUFFER_ID: c_int = 0; static mut G_SDP_SESSION_INFO_BUFFER_ID: c_int = 0; static mut G_SDP_URI_BUFFER_ID: c_int = 0; +static mut G_SDP_EMAIL_BUFFER_ID: c_int = 0; unsafe extern "C" fn sdp_session_name_setup( de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, @@ -225,6 +226,55 @@ unsafe extern "C" fn sdp_uri_get_data( false } +unsafe extern "C" fn sdp_email_setup( + de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_SIP) != 0 { + return -1; + } + if DetectBufferSetActiveList(de, s, G_SDP_EMAIL_BUFFER_ID) < 0 { + return -1; + } + return 0; +} + +unsafe extern "C" fn sdp_email_get( + de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8, + tx: *const c_void, list_id: c_int, +) -> *mut c_void { + return DetectHelperGetData( + de, + transforms, + flow, + flow_flags, + tx, + list_id, + sdp_email_get_data, + ); +} + +unsafe extern "C" fn sdp_email_get_data( + tx: *const c_void, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, SIPTransaction); + let sdp_option = match direction.into() { + Direction::ToServer => tx.request.as_ref().and_then(|req| req.body.as_ref()), + Direction::ToClient => tx.response.as_ref().and_then(|resp| resp.body.as_ref()), + }; + if let Some(sdp) = sdp_option { + if let Some(ref e) = sdp.email { + if !e.is_empty() { + *buffer = e.as_ptr(); + *buffer_len = e.len() as u32; + return true; + } + } + } + *buffer = ptr::null(); + *buffer_len = 0; + false +} + #[no_mangle] pub unsafe extern "C" fn ScDetectSdpRegister() { let kw = SCSigTableElmt { @@ -301,4 +351,22 @@ pub unsafe extern "C" fn ScDetectSdpRegister() { true, sdp_uri_get, ); + let kw = SCSigTableElmt { + name: b"sdp.email\0".as_ptr() as *const libc::c_char, + desc: b"sticky buffer to match on the SDP email field\0".as_ptr() as *const libc::c_char, + url: b"/rules/sdp-keywords.html#sdp-email\0".as_ptr() as *const libc::c_char, + Setup: sdp_email_setup, + flags: SIGMATCH_NOOPT, + AppLayerTxMatch: None, + Free: None, + }; + let _ = DetectHelperKeywordRegister(&kw); + G_SDP_EMAIL_BUFFER_ID = DetectHelperBufferMpmRegister( + b"sdp.email\0".as_ptr() as *const libc::c_char, + b"sdp.email\0".as_ptr() as *const libc::c_char, + ALPROTO_SIP, + true, + true, + sdp_email_get, + ); } From 393cf78394ed7b6b625918048d684cbb4679a107 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Mon, 30 Sep 2024 15:05:35 +0200 Subject: [PATCH 08/19] sdp: add sdp.phone_number sticky buffer This adds a sticky buffer to match the "Phone number" field in both requests and responses. Ticket #7291 --- rust/src/sdp/detect.rs | 69 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/rust/src/sdp/detect.rs b/rust/src/sdp/detect.rs index eb102798a17c..75e990cedfce 100644 --- a/rust/src/sdp/detect.rs +++ b/rust/src/sdp/detect.rs @@ -31,6 +31,7 @@ static mut G_SDP_SESSION_NAME_BUFFER_ID: c_int = 0; static mut G_SDP_SESSION_INFO_BUFFER_ID: c_int = 0; static mut G_SDP_URI_BUFFER_ID: c_int = 0; static mut G_SDP_EMAIL_BUFFER_ID: c_int = 0; +static mut G_SDP_PHONE_NUMBER_BUFFER_ID: c_int = 0; unsafe extern "C" fn sdp_session_name_setup( de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, @@ -275,6 +276,55 @@ unsafe extern "C" fn sdp_email_get_data( false } +unsafe extern "C" fn sdp_phone_number_setup( + de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_SIP) != 0 { + return -1; + } + if DetectBufferSetActiveList(de, s, G_SDP_PHONE_NUMBER_BUFFER_ID) < 0 { + return -1; + } + return 0; +} + +unsafe extern "C" fn sdp_phone_number_get( + de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8, + tx: *const c_void, list_id: c_int, +) -> *mut c_void { + return DetectHelperGetData( + de, + transforms, + flow, + flow_flags, + tx, + list_id, + sdp_phone_number_get_data, + ); +} + +unsafe extern "C" fn sdp_phone_number_get_data( + tx: *const c_void, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, SIPTransaction); + let sdp_option = match direction.into() { + Direction::ToServer => tx.request.as_ref().and_then(|req| req.body.as_ref()), + Direction::ToClient => tx.response.as_ref().and_then(|resp| resp.body.as_ref()), + }; + if let Some(sdp) = sdp_option { + if let Some(ref p) = sdp.phone_number { + if !p.is_empty() { + *buffer = p.as_ptr(); + *buffer_len = p.len() as u32; + return true; + } + } + } + *buffer = ptr::null(); + *buffer_len = 0; + false +} + #[no_mangle] pub unsafe extern "C" fn ScDetectSdpRegister() { let kw = SCSigTableElmt { @@ -369,4 +419,23 @@ pub unsafe extern "C" fn ScDetectSdpRegister() { true, sdp_email_get, ); + let kw = SCSigTableElmt { + name: b"sdp.phone_number\0".as_ptr() as *const libc::c_char, + desc: b"sticky buffer to match on the SDP phone number field\0".as_ptr() + as *const libc::c_char, + url: b"/rules/sdp-keywords.html#sdp-phone-number\0".as_ptr() as *const libc::c_char, + Setup: sdp_phone_number_setup, + flags: SIGMATCH_NOOPT, + AppLayerTxMatch: None, + Free: None, + }; + let _ = DetectHelperKeywordRegister(&kw); + G_SDP_PHONE_NUMBER_BUFFER_ID = DetectHelperBufferMpmRegister( + b"sdp.phone_number\0".as_ptr() as *const libc::c_char, + b"sdp.phone_number\0".as_ptr() as *const libc::c_char, + ALPROTO_SIP, + true, + true, + sdp_phone_number_get, + ); } From 1b2940c14e425bdcc9017a1f69b35d48ffda49e2 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Mon, 30 Sep 2024 15:12:44 +0200 Subject: [PATCH 09/19] sdp: add sdp.connection_data sticky buffer This adds a sticky buffer to match the "Connection data" field in both requests and responses. Ticket #7291 --- rust/src/sdp/detect.rs | 69 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/rust/src/sdp/detect.rs b/rust/src/sdp/detect.rs index 75e990cedfce..9e06ec1e1895 100644 --- a/rust/src/sdp/detect.rs +++ b/rust/src/sdp/detect.rs @@ -32,6 +32,7 @@ static mut G_SDP_SESSION_INFO_BUFFER_ID: c_int = 0; static mut G_SDP_URI_BUFFER_ID: c_int = 0; static mut G_SDP_EMAIL_BUFFER_ID: c_int = 0; static mut G_SDP_PHONE_NUMBER_BUFFER_ID: c_int = 0; +static mut G_SDP_CONNECTION_DATA_BUFFER_ID: c_int = 0; unsafe extern "C" fn sdp_session_name_setup( de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, @@ -325,6 +326,55 @@ unsafe extern "C" fn sdp_phone_number_get_data( false } +unsafe extern "C" fn sdp_conn_data_setup( + de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_SIP) != 0 { + return -1; + } + if DetectBufferSetActiveList(de, s, G_SDP_CONNECTION_DATA_BUFFER_ID) < 0 { + return -1; + } + return 0; +} + +unsafe extern "C" fn sdp_conn_data_get( + de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8, + tx: *const c_void, list_id: c_int, +) -> *mut c_void { + return DetectHelperGetData( + de, + transforms, + flow, + flow_flags, + tx, + list_id, + sdp_conn_data_get_data, + ); +} + +unsafe extern "C" fn sdp_conn_data_get_data( + tx: *const c_void, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, SIPTransaction); + let sdp_option = match direction.into() { + Direction::ToServer => tx.request.as_ref().and_then(|req| req.body.as_ref()), + Direction::ToClient => tx.response.as_ref().and_then(|resp| resp.body.as_ref()), + }; + if let Some(sdp) = sdp_option { + if let Some(ref c) = sdp.connection_data { + if !c.is_empty() { + *buffer = c.as_ptr(); + *buffer_len = c.len() as u32; + return true; + } + } + } + *buffer = ptr::null(); + *buffer_len = 0; + false +} + #[no_mangle] pub unsafe extern "C" fn ScDetectSdpRegister() { let kw = SCSigTableElmt { @@ -438,4 +488,23 @@ pub unsafe extern "C" fn ScDetectSdpRegister() { true, sdp_phone_number_get, ); + let kw = SCSigTableElmt { + name: b"sdp.connection_data\0".as_ptr() as *const libc::c_char, + desc: b"sticky buffer to match on the SDP connection data field\0".as_ptr() + as *const libc::c_char, + url: b"/rules/sdp-keywords.html#sdp-connection-data\0".as_ptr() as *const libc::c_char, + Setup: sdp_conn_data_setup, + flags: SIGMATCH_NOOPT, + AppLayerTxMatch: None, + Free: None, + }; + let _ = DetectHelperKeywordRegister(&kw); + G_SDP_CONNECTION_DATA_BUFFER_ID = DetectHelperBufferMpmRegister( + b"sdp.connection_data\0".as_ptr() as *const libc::c_char, + b"sdp.connection_data\0".as_ptr() as *const libc::c_char, + ALPROTO_SIP, + true, + true, + sdp_conn_data_get, + ); } From 7bf483f91ca32357755cae1f3058ef3c7352e4a3 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Mon, 30 Sep 2024 15:30:07 +0200 Subject: [PATCH 10/19] sdp: add sdp.bandwidth sticky buffer This adds a sticky (multi) buffer to match the "Bandwidth" field in both requests and responses. Ticket #7291 --- rust/src/sdp/detect.rs | 75 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/rust/src/sdp/detect.rs b/rust/src/sdp/detect.rs index 9e06ec1e1895..0a318401eefa 100644 --- a/rust/src/sdp/detect.rs +++ b/rust/src/sdp/detect.rs @@ -20,7 +20,8 @@ use crate::core::Direction; use crate::detect::{ DetectBufferSetActiveList, DetectHelperBufferMpmRegister, DetectHelperGetData, - DetectHelperKeywordRegister, DetectSignatureSetAppProto, SCSigTableElmt, SIGMATCH_NOOPT, + DetectHelperGetMultiData, DetectHelperKeywordRegister, DetectHelperMultiBufferMpmRegister, + DetectSignatureSetAppProto, SCSigTableElmt, SIGMATCH_NOOPT, }; use crate::sip::sip::{SIPTransaction, ALPROTO_SIP}; use std::os::raw::{c_int, c_void}; @@ -33,6 +34,7 @@ static mut G_SDP_URI_BUFFER_ID: c_int = 0; static mut G_SDP_EMAIL_BUFFER_ID: c_int = 0; static mut G_SDP_PHONE_NUMBER_BUFFER_ID: c_int = 0; static mut G_SDP_CONNECTION_DATA_BUFFER_ID: c_int = 0; +static mut G_SDP_BANDWIDTH_BUFFER_ID: c_int = 0; unsafe extern "C" fn sdp_session_name_setup( de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, @@ -375,6 +377,58 @@ unsafe extern "C" fn sdp_conn_data_get_data( false } +unsafe extern "C" fn sdp_bandwidth_setup( + de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_SIP) != 0 { + return -1; + } + if DetectBufferSetActiveList(de, s, G_SDP_BANDWIDTH_BUFFER_ID) < 0 { + return -1; + } + return 0; +} + +unsafe extern "C" fn sdp_bandwidth_get( + de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8, + tx: *const c_void, list_id: c_int, local_id: u32, +) -> *mut c_void { + return DetectHelperGetMultiData( + de, + transforms, + flow, + flow_flags, + tx, + list_id, + local_id, + sip_bandwidth_get_data, + ); +} + +unsafe extern "C" fn sip_bandwidth_get_data( + tx: *const c_void, flow_flags: u8, local_id: u32, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, SIPTransaction); + let direction = flow_flags.into(); + let sdp_option = match direction { + Direction::ToServer => tx.request.as_ref().and_then(|req| req.body.as_ref()), + Direction::ToClient => tx.response.as_ref().and_then(|resp| resp.body.as_ref()), + }; + if let Some(sdp) = sdp_option { + if let Some(ref b) = sdp.bandwidths { + if (local_id as usize) < b.len() { + let val = &b[local_id as usize]; + *buffer = val.as_ptr(); + *buffer_len = val.len() as u32; + return true; + } + } + } + *buffer = ptr::null(); + *buffer_len = 0; + false +} + #[no_mangle] pub unsafe extern "C" fn ScDetectSdpRegister() { let kw = SCSigTableElmt { @@ -507,4 +561,23 @@ pub unsafe extern "C" fn ScDetectSdpRegister() { true, sdp_conn_data_get, ); + let kw = SCSigTableElmt { + name: b"sdp.bandwidth\0".as_ptr() as *const libc::c_char, + desc: b"sticky buffer to match on the SDP bandwidth field\0".as_ptr() + as *const libc::c_char, + url: b"/rules/sdp-keywords.html#sdp-bandwidth\0".as_ptr() as *const libc::c_char, + Setup: sdp_bandwidth_setup, + flags: SIGMATCH_NOOPT, + AppLayerTxMatch: None, + Free: None, + }; + let _ = DetectHelperKeywordRegister(&kw); + G_SDP_BANDWIDTH_BUFFER_ID = DetectHelperMultiBufferMpmRegister( + b"sdp.bandwidth\0".as_ptr() as *const libc::c_char, + b"sdp.bandwidth\0".as_ptr() as *const libc::c_char, + ALPROTO_SIP, + true, + true, + sdp_bandwidth_get, + ); } From 038615daa696d898d6c17fa87a640af5f1aab8e0 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Mon, 30 Sep 2024 15:36:32 +0200 Subject: [PATCH 11/19] sdp: add sdp.time sticky buffer This adds a sticky buffer to match the "Time" field in both requests and responses. Ticket #7291 --- rust/src/sdp/detect.rs | 67 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/rust/src/sdp/detect.rs b/rust/src/sdp/detect.rs index 0a318401eefa..0f21f225eac3 100644 --- a/rust/src/sdp/detect.rs +++ b/rust/src/sdp/detect.rs @@ -35,6 +35,7 @@ static mut G_SDP_EMAIL_BUFFER_ID: c_int = 0; static mut G_SDP_PHONE_NUMBER_BUFFER_ID: c_int = 0; static mut G_SDP_CONNECTION_DATA_BUFFER_ID: c_int = 0; static mut G_SDP_BANDWIDTH_BUFFER_ID: c_int = 0; +static mut G_SDP_TIME_BUFFER_ID: c_int = 0; unsafe extern "C" fn sdp_session_name_setup( de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, @@ -429,6 +430,54 @@ unsafe extern "C" fn sip_bandwidth_get_data( false } +unsafe extern "C" fn sdp_time_setup( + de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_SIP) != 0 { + return -1; + } + if DetectBufferSetActiveList(de, s, G_SDP_TIME_BUFFER_ID) < 0 { + return -1; + } + return 0; +} + +unsafe extern "C" fn sdp_time_get( + de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8, + tx: *const c_void, list_id: c_int, +) -> *mut c_void { + return DetectHelperGetData( + de, + transforms, + flow, + flow_flags, + tx, + list_id, + sdp_time_get_data, + ); +} + +unsafe extern "C" fn sdp_time_get_data( + tx: *const c_void, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, SIPTransaction); + let sdp_option = match direction.into() { + Direction::ToServer => tx.request.as_ref().and_then(|req| req.body.as_ref()), + Direction::ToClient => tx.response.as_ref().and_then(|resp| resp.body.as_ref()), + }; + if let Some(sdp) = sdp_option { + let time = &sdp.time; + if !time.is_empty() { + *buffer = time.as_ptr(); + *buffer_len = time.len() as u32; + return true; + } + } + *buffer = ptr::null(); + *buffer_len = 0; + false +} + #[no_mangle] pub unsafe extern "C" fn ScDetectSdpRegister() { let kw = SCSigTableElmt { @@ -580,4 +629,22 @@ pub unsafe extern "C" fn ScDetectSdpRegister() { true, sdp_bandwidth_get, ); + let kw = SCSigTableElmt { + name: b"sdp.time\0".as_ptr() as *const libc::c_char, + desc: b"sticky buffer to match on the SDP time field\0".as_ptr() as *const libc::c_char, + url: b"/rules/sdp-keywords.html#time\0".as_ptr() as *const libc::c_char, + Setup: sdp_time_setup, + flags: SIGMATCH_NOOPT, + AppLayerTxMatch: None, + Free: None, + }; + let _ = DetectHelperKeywordRegister(&kw); + G_SDP_TIME_BUFFER_ID = DetectHelperBufferMpmRegister( + b"sdp.time\0".as_ptr() as *const libc::c_char, + b"sdp.time\0".as_ptr() as *const libc::c_char, + ALPROTO_SIP, + true, + true, + sdp_time_get, + ); } From 22a2ee768a3c6c01255a72bb92f57b99d9530efe Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Mon, 30 Sep 2024 15:40:40 +0200 Subject: [PATCH 12/19] sdp: add sdp.repeat_time sticky buffer This adds a sticky buffer to match the "Repeat time" field in both requests and responses. Ticket #7291 --- rust/src/sdp/detect.rs | 69 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/rust/src/sdp/detect.rs b/rust/src/sdp/detect.rs index 0f21f225eac3..d104bdb0d64c 100644 --- a/rust/src/sdp/detect.rs +++ b/rust/src/sdp/detect.rs @@ -36,6 +36,7 @@ static mut G_SDP_PHONE_NUMBER_BUFFER_ID: c_int = 0; static mut G_SDP_CONNECTION_DATA_BUFFER_ID: c_int = 0; static mut G_SDP_BANDWIDTH_BUFFER_ID: c_int = 0; static mut G_SDP_TIME_BUFFER_ID: c_int = 0; +static mut G_SDP_REPEAT_TIME_BUFFER_ID: c_int = 0; unsafe extern "C" fn sdp_session_name_setup( de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, @@ -478,6 +479,55 @@ unsafe extern "C" fn sdp_time_get_data( false } +unsafe extern "C" fn sdp_repeat_time_setup( + de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_SIP) != 0 { + return -1; + } + if DetectBufferSetActiveList(de, s, G_SDP_REPEAT_TIME_BUFFER_ID) < 0 { + return -1; + } + return 0; +} + +unsafe extern "C" fn sdp_repeat_time_get( + de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8, + tx: *const c_void, list_id: c_int, +) -> *mut c_void { + return DetectHelperGetData( + de, + transforms, + flow, + flow_flags, + tx, + list_id, + sdp_repeat_time_get_data, + ); +} + +unsafe extern "C" fn sdp_repeat_time_get_data( + tx: *const c_void, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, SIPTransaction); + let sdp_option = match direction.into() { + Direction::ToServer => tx.request.as_ref().and_then(|req| req.body.as_ref()), + Direction::ToClient => tx.response.as_ref().and_then(|resp| resp.body.as_ref()), + }; + if let Some(sdp) = sdp_option { + if let Some(r) = &sdp.repeat_time { + if !r.is_empty() { + *buffer = r.as_ptr(); + *buffer_len = r.len() as u32; + return true; + } + } + } + *buffer = ptr::null(); + *buffer_len = 0; + false +} + #[no_mangle] pub unsafe extern "C" fn ScDetectSdpRegister() { let kw = SCSigTableElmt { @@ -647,4 +697,23 @@ pub unsafe extern "C" fn ScDetectSdpRegister() { true, sdp_time_get, ); + let kw = SCSigTableElmt { + name: b"sdp.repeat_time\0".as_ptr() as *const libc::c_char, + desc: b"sticky buffer to match on the SDP repeat time field\0".as_ptr() + as *const libc::c_char, + url: b"/rules/sdp-keywords.html#repeat-time\0".as_ptr() as *const libc::c_char, + Setup: sdp_repeat_time_setup, + flags: SIGMATCH_NOOPT, + AppLayerTxMatch: None, + Free: None, + }; + let _ = DetectHelperKeywordRegister(&kw); + G_SDP_REPEAT_TIME_BUFFER_ID = DetectHelperBufferMpmRegister( + b"sdp.repeat_time\0".as_ptr() as *const libc::c_char, + b"sdp.repeat_time\0".as_ptr() as *const libc::c_char, + ALPROTO_SIP, + true, + true, + sdp_repeat_time_get, + ); } From af790586703739a941e1b5c913b5197ce24498f8 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Mon, 30 Sep 2024 15:44:59 +0200 Subject: [PATCH 13/19] sdp: add sdp.timezone sticky buffer This adds a sticky bufffer to match the "Timezone" field in both requests and responses. Ticket #7291 --- rust/src/sdp/detect.rs | 68 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/rust/src/sdp/detect.rs b/rust/src/sdp/detect.rs index d104bdb0d64c..b499c25f890c 100644 --- a/rust/src/sdp/detect.rs +++ b/rust/src/sdp/detect.rs @@ -37,6 +37,7 @@ static mut G_SDP_CONNECTION_DATA_BUFFER_ID: c_int = 0; static mut G_SDP_BANDWIDTH_BUFFER_ID: c_int = 0; static mut G_SDP_TIME_BUFFER_ID: c_int = 0; static mut G_SDP_REPEAT_TIME_BUFFER_ID: c_int = 0; +static mut G_SDP_TIMEZONE_BUFFER_ID: c_int = 0; unsafe extern "C" fn sdp_session_name_setup( de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, @@ -528,6 +529,55 @@ unsafe extern "C" fn sdp_repeat_time_get_data( false } +unsafe extern "C" fn sdp_timezone_setup( + de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_SIP) != 0 { + return -1; + } + if DetectBufferSetActiveList(de, s, G_SDP_TIMEZONE_BUFFER_ID) < 0 { + return -1; + } + return 0; +} + +unsafe extern "C" fn sdp_timezone_get( + de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8, + tx: *const c_void, list_id: c_int, +) -> *mut c_void { + return DetectHelperGetData( + de, + transforms, + flow, + flow_flags, + tx, + list_id, + sdp_timezone_get_data, + ); +} + +unsafe extern "C" fn sdp_timezone_get_data( + tx: *const c_void, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, SIPTransaction); + let sdp_option = match direction.into() { + Direction::ToServer => tx.request.as_ref().and_then(|req| req.body.as_ref()), + Direction::ToClient => tx.response.as_ref().and_then(|resp| resp.body.as_ref()), + }; + if let Some(sdp) = sdp_option { + if let Some(z) = &sdp.time_zone { + if !z.is_empty() { + *buffer = z.as_ptr(); + *buffer_len = z.len() as u32; + return true; + } + } + } + *buffer = ptr::null(); + *buffer_len = 0; + false +} + #[no_mangle] pub unsafe extern "C" fn ScDetectSdpRegister() { let kw = SCSigTableElmt { @@ -716,4 +766,22 @@ pub unsafe extern "C" fn ScDetectSdpRegister() { true, sdp_repeat_time_get, ); + let kw = SCSigTableElmt { + name: b"sdp.timezone\0".as_ptr() as *const libc::c_char, + desc: b"sticky buffer to match on the SDP timezone field\0".as_ptr() as *const libc::c_char, + url: b"/rules/sdp-keywords.html#timezone\0".as_ptr() as *const libc::c_char, + Setup: sdp_timezone_setup, + flags: SIGMATCH_NOOPT, + AppLayerTxMatch: None, + Free: None, + }; + let _ = DetectHelperKeywordRegister(&kw); + G_SDP_TIMEZONE_BUFFER_ID = DetectHelperBufferMpmRegister( + b"sdp.timezone\0".as_ptr() as *const libc::c_char, + b"sdp.timezone\0".as_ptr() as *const libc::c_char, + ALPROTO_SIP, + true, + true, + sdp_timezone_get, + ); } From dcf92f97db6cac014b33ff4a776c1bcf17ddbf54 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Mon, 30 Sep 2024 17:49:00 +0200 Subject: [PATCH 14/19] sdp: add sdp.encryption_key sticky buffer This adds a sticky buffer to match the "Encryption key" field in both requests and responses. Ticket #7291 --- rust/src/sdp/detect.rs | 69 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/rust/src/sdp/detect.rs b/rust/src/sdp/detect.rs index b499c25f890c..995d4ab3f1f8 100644 --- a/rust/src/sdp/detect.rs +++ b/rust/src/sdp/detect.rs @@ -38,6 +38,7 @@ static mut G_SDP_BANDWIDTH_BUFFER_ID: c_int = 0; static mut G_SDP_TIME_BUFFER_ID: c_int = 0; static mut G_SDP_REPEAT_TIME_BUFFER_ID: c_int = 0; static mut G_SDP_TIMEZONE_BUFFER_ID: c_int = 0; +static mut G_SDP_ENCRYPTION_KEY_BUFFER_ID: c_int = 0; unsafe extern "C" fn sdp_session_name_setup( de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, @@ -578,6 +579,55 @@ unsafe extern "C" fn sdp_timezone_get_data( false } +unsafe extern "C" fn sdp_encryption_key_setup( + de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_SIP) != 0 { + return -1; + } + if DetectBufferSetActiveList(de, s, G_SDP_ENCRYPTION_KEY_BUFFER_ID) < 0 { + return -1; + } + return 0; +} + +unsafe extern "C" fn sdp_encryption_key_get( + de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8, + tx: *const c_void, list_id: c_int, +) -> *mut c_void { + return DetectHelperGetData( + de, + transforms, + flow, + flow_flags, + tx, + list_id, + sdp_encryption_key_get_data, + ); +} + +unsafe extern "C" fn sdp_encryption_key_get_data( + tx: *const c_void, direction: u8, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, SIPTransaction); + let sdp_option = match direction.into() { + Direction::ToServer => tx.request.as_ref().and_then(|req| req.body.as_ref()), + Direction::ToClient => tx.response.as_ref().and_then(|resp| resp.body.as_ref()), + }; + if let Some(sdp) = sdp_option { + if let Some(k) = &sdp.encryption_key { + if !k.is_empty() { + *buffer = k.as_ptr(); + *buffer_len = k.len() as u32; + return true; + } + } + } + *buffer = ptr::null(); + *buffer_len = 0; + false +} + #[no_mangle] pub unsafe extern "C" fn ScDetectSdpRegister() { let kw = SCSigTableElmt { @@ -784,4 +834,23 @@ pub unsafe extern "C" fn ScDetectSdpRegister() { true, sdp_timezone_get, ); + let kw = SCSigTableElmt { + name: b"sdp.encryption_key\0".as_ptr() as *const libc::c_char, + desc: b"sticky buffer to match on the SDP encryption key field\0".as_ptr() + as *const libc::c_char, + url: b"/rules/sdp-keywords.html#encryption-key\0".as_ptr() as *const libc::c_char, + Setup: sdp_encryption_key_setup, + flags: SIGMATCH_NOOPT, + AppLayerTxMatch: None, + Free: None, + }; + let _ = DetectHelperKeywordRegister(&kw); + G_SDP_ENCRYPTION_KEY_BUFFER_ID = DetectHelperBufferMpmRegister( + b"sdp.encryption_key\0".as_ptr() as *const libc::c_char, + b"sdp.encription_key\0".as_ptr() as *const libc::c_char, + ALPROTO_SIP, + true, + true, + sdp_encryption_key_get, + ); } From 1c32f1b272caf2f1ca1ffefc6a086c2e2fd10218 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Mon, 30 Sep 2024 21:26:30 +0200 Subject: [PATCH 15/19] sdp: add sdp.attribute sticky buffer This adds a sticky (multi) buffer to match the "Attribute" field in both requests and responses. Ticket #7291 --- rust/src/sdp/detect.rs | 72 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/rust/src/sdp/detect.rs b/rust/src/sdp/detect.rs index 995d4ab3f1f8..ccadd0d9321f 100644 --- a/rust/src/sdp/detect.rs +++ b/rust/src/sdp/detect.rs @@ -39,6 +39,7 @@ static mut G_SDP_TIME_BUFFER_ID: c_int = 0; static mut G_SDP_REPEAT_TIME_BUFFER_ID: c_int = 0; static mut G_SDP_TIMEZONE_BUFFER_ID: c_int = 0; static mut G_SDP_ENCRYPTION_KEY_BUFFER_ID: c_int = 0; +static mut G_SDP_ATTRIBUTE_BUFFER_ID: c_int = 0; unsafe extern "C" fn sdp_session_name_setup( de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, @@ -628,6 +629,58 @@ unsafe extern "C" fn sdp_encryption_key_get_data( false } +unsafe extern "C" fn sdp_attribute_setup( + de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_SIP) != 0 { + return -1; + } + if DetectBufferSetActiveList(de, s, G_SDP_ATTRIBUTE_BUFFER_ID) < 0 { + return -1; + } + return 0; +} + +unsafe extern "C" fn sdp_attribute_get( + de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8, + tx: *const c_void, list_id: c_int, local_id: u32, +) -> *mut c_void { + return DetectHelperGetMultiData( + de, + transforms, + flow, + flow_flags, + tx, + list_id, + local_id, + sip_attribute_get_data, + ); +} + +unsafe extern "C" fn sip_attribute_get_data( + tx: *const c_void, flow_flags: u8, local_id: u32, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, SIPTransaction); + let direction = flow_flags.into(); + let sdp_option = match direction { + Direction::ToServer => tx.request.as_ref().and_then(|req| req.body.as_ref()), + Direction::ToClient => tx.response.as_ref().and_then(|resp| resp.body.as_ref()), + }; + if let Some(sdp) = sdp_option { + if let Some(ref a) = sdp.attributes { + if (local_id as usize) < a.len() { + let val = &a[local_id as usize]; + *buffer = val.as_ptr(); + *buffer_len = val.len() as u32; + return true; + } + } + } + *buffer = ptr::null(); + *buffer_len = 0; + false +} + #[no_mangle] pub unsafe extern "C" fn ScDetectSdpRegister() { let kw = SCSigTableElmt { @@ -853,4 +906,23 @@ pub unsafe extern "C" fn ScDetectSdpRegister() { true, sdp_encryption_key_get, ); + let kw = SCSigTableElmt { + name: b"sdp.attribute\0".as_ptr() as *const libc::c_char, + desc: b"sticky buffer to match on the SDP attribute field\0".as_ptr() + as *const libc::c_char, + url: b"/rules/sdp-keywords.html#sdp-attribute\0".as_ptr() as *const libc::c_char, + Setup: sdp_attribute_setup, + flags: SIGMATCH_NOOPT, + AppLayerTxMatch: None, + Free: None, + }; + let _ = DetectHelperKeywordRegister(&kw); + G_SDP_ATTRIBUTE_BUFFER_ID = DetectHelperMultiBufferMpmRegister( + b"sdp.attribute\0".as_ptr() as *const libc::c_char, + b"sdp.attribute\0".as_ptr() as *const libc::c_char, + ALPROTO_SIP, + true, + true, + sdp_attribute_get, + ); } From f9a9ee752b828f6cfbcac1eade6fdb2dccff4416 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Wed, 2 Oct 2024 10:10:39 +0200 Subject: [PATCH 16/19] sdp: add sdp.media.media sticky buffer This adds a sticky (multi) buffer to match the "Media" subfield of the "Media description" field in both requests and responses. Ticket #7291 --- rust/src/sdp/detect.rs | 72 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/rust/src/sdp/detect.rs b/rust/src/sdp/detect.rs index ccadd0d9321f..7bbcafc2de3f 100644 --- a/rust/src/sdp/detect.rs +++ b/rust/src/sdp/detect.rs @@ -40,6 +40,7 @@ static mut G_SDP_REPEAT_TIME_BUFFER_ID: c_int = 0; static mut G_SDP_TIMEZONE_BUFFER_ID: c_int = 0; static mut G_SDP_ENCRYPTION_KEY_BUFFER_ID: c_int = 0; static mut G_SDP_ATTRIBUTE_BUFFER_ID: c_int = 0; +static mut G_SDP_MEDIA_DESC_MEDIA_BUFFER_ID: c_int = 0; unsafe extern "C" fn sdp_session_name_setup( de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, @@ -681,6 +682,58 @@ unsafe extern "C" fn sip_attribute_get_data( false } +unsafe extern "C" fn sdp_media_desc_media_setup( + de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_SIP) != 0 { + return -1; + } + if DetectBufferSetActiveList(de, s, G_SDP_MEDIA_DESC_MEDIA_BUFFER_ID) < 0 { + return -1; + } + return 0; +} + +unsafe extern "C" fn sdp_media_desc_media_get( + de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8, + tx: *const c_void, list_id: c_int, local_id: u32, +) -> *mut c_void { + return DetectHelperGetMultiData( + de, + transforms, + flow, + flow_flags, + tx, + list_id, + local_id, + sip_media_desc_media_get_data, + ); +} + +unsafe extern "C" fn sip_media_desc_media_get_data( + tx: *const c_void, flow_flags: u8, local_id: u32, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, SIPTransaction); + let direction = flow_flags.into(); + let sdp_option = match direction { + Direction::ToServer => tx.request.as_ref().and_then(|req| req.body.as_ref()), + Direction::ToClient => tx.response.as_ref().and_then(|resp| resp.body.as_ref()), + }; + if let Some(sdp) = sdp_option { + if let Some(ref m) = sdp.media_description { + if (local_id as usize) < m.len() { + let val = &m[local_id as usize].media; + *buffer = val.as_ptr(); + *buffer_len = val.len() as u32; + return true; + } + } + } + *buffer = ptr::null(); + *buffer_len = 0; + false +} + #[no_mangle] pub unsafe extern "C" fn ScDetectSdpRegister() { let kw = SCSigTableElmt { @@ -925,4 +978,23 @@ pub unsafe extern "C" fn ScDetectSdpRegister() { true, sdp_attribute_get, ); + let kw = SCSigTableElmt { + name: b"sdp.media.media\0".as_ptr() as *const libc::c_char, + desc: b"sticky buffer to match on the SDP media subfield of the media_description field\0" + .as_ptr() as *const libc::c_char, + url: b"/rules/sdp-keywords.html#media-description-media\0".as_ptr() as *const libc::c_char, + Setup: sdp_media_desc_media_setup, + flags: SIGMATCH_NOOPT, + AppLayerTxMatch: None, + Free: None, + }; + let _ = DetectHelperKeywordRegister(&kw); + G_SDP_MEDIA_DESC_MEDIA_BUFFER_ID = DetectHelperMultiBufferMpmRegister( + b"sdp.media.media\0".as_ptr() as *const libc::c_char, + b"sdp.media.media\0".as_ptr() as *const libc::c_char, + ALPROTO_SIP, + true, + true, + sdp_media_desc_media_get, + ); } From adf25a8b0dbe225d0c5791469dfb5d2e89748521 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Wed, 2 Oct 2024 10:19:44 +0200 Subject: [PATCH 17/19] sdp: add sdp.media.media_info sticky buffer This adds a stick (multi) buffer to match the "Session information" subfield of the "Media description" field in both requests and responses. Ticket #7291 --- rust/src/sdp/detect.rs | 73 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/rust/src/sdp/detect.rs b/rust/src/sdp/detect.rs index 7bbcafc2de3f..7d9b62829539 100644 --- a/rust/src/sdp/detect.rs +++ b/rust/src/sdp/detect.rs @@ -41,6 +41,7 @@ static mut G_SDP_TIMEZONE_BUFFER_ID: c_int = 0; static mut G_SDP_ENCRYPTION_KEY_BUFFER_ID: c_int = 0; static mut G_SDP_ATTRIBUTE_BUFFER_ID: c_int = 0; static mut G_SDP_MEDIA_DESC_MEDIA_BUFFER_ID: c_int = 0; +static mut G_SDP_MEDIA_DESC_SESSION_INFO_BUFFER_ID: c_int = 0; unsafe extern "C" fn sdp_session_name_setup( de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, @@ -734,6 +735,59 @@ unsafe extern "C" fn sip_media_desc_media_get_data( false } +unsafe extern "C" fn sdp_media_desc_session_info_setup( + de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_SIP) != 0 { + return -1; + } + if DetectBufferSetActiveList(de, s, G_SDP_MEDIA_DESC_SESSION_INFO_BUFFER_ID) < 0 { + return -1; + } + return 0; +} + +unsafe extern "C" fn sdp_media_desc_session_info_get( + de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8, + tx: *const c_void, list_id: c_int, local_id: u32, +) -> *mut c_void { + return DetectHelperGetMultiData( + de, + transforms, + flow, + flow_flags, + tx, + list_id, + local_id, + sip_media_desc_session_info_get_data, + ); +} + +unsafe extern "C" fn sip_media_desc_session_info_get_data( + tx: *const c_void, flow_flags: u8, local_id: u32, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, SIPTransaction); + let direction = flow_flags.into(); + let sdp_option = match direction { + Direction::ToServer => tx.request.as_ref().and_then(|req| req.body.as_ref()), + Direction::ToClient => tx.response.as_ref().and_then(|resp| resp.body.as_ref()), + }; + if let Some(sdp) = sdp_option { + if let Some(ref m) = sdp.media_description { + if (local_id as usize) < m.len() { + if let Some(i) = &m[local_id as usize].session_info { + *buffer = i.as_ptr(); + *buffer_len = i.len() as u32; + return true; + } + } + } + } + *buffer = ptr::null(); + *buffer_len = 0; + false +} + #[no_mangle] pub unsafe extern "C" fn ScDetectSdpRegister() { let kw = SCSigTableElmt { @@ -997,4 +1051,23 @@ pub unsafe extern "C" fn ScDetectSdpRegister() { true, sdp_media_desc_media_get, ); + let kw = SCSigTableElmt { + name: b"sdp.media.media_info\0".as_ptr() as *const libc::c_char, + desc: b"sticky buffer to match on the SDP session info subfield of the media_description field\0".as_ptr() + as *const libc::c_char, + url: b"/rules/sdp-keywords.html#sdp-media-description-session-info\0".as_ptr() as *const libc::c_char, + Setup: sdp_media_desc_session_info_setup, + flags: SIGMATCH_NOOPT, + AppLayerTxMatch: None, + Free: None, + }; + let _ = DetectHelperKeywordRegister(&kw); + G_SDP_MEDIA_DESC_SESSION_INFO_BUFFER_ID = DetectHelperMultiBufferMpmRegister( + b"sdp.media.media_info\0".as_ptr() as *const libc::c_char, + b"sdp.media.media_info\0".as_ptr() as *const libc::c_char, + ALPROTO_SIP, + true, + true, + sdp_media_desc_session_info_get, + ); } From 7513966e552d6a9d40142f5652a5bba246f26771 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Wed, 2 Oct 2024 10:25:59 +0200 Subject: [PATCH 18/19] sdp: add sdp.media.connection_data sticky buffer This adds a sticky (multi) buffer to match the "Connection data" subfield of the "Media description" field in both requests and responses. Ticket #7291 --- rust/src/sdp/detect.rs | 73 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/rust/src/sdp/detect.rs b/rust/src/sdp/detect.rs index 7d9b62829539..c32c00ef595c 100644 --- a/rust/src/sdp/detect.rs +++ b/rust/src/sdp/detect.rs @@ -42,6 +42,7 @@ static mut G_SDP_ENCRYPTION_KEY_BUFFER_ID: c_int = 0; static mut G_SDP_ATTRIBUTE_BUFFER_ID: c_int = 0; static mut G_SDP_MEDIA_DESC_MEDIA_BUFFER_ID: c_int = 0; static mut G_SDP_MEDIA_DESC_SESSION_INFO_BUFFER_ID: c_int = 0; +static mut G_SDP_MEDIA_DESC_CONNECTION_DATA_BUFFER_ID: c_int = 0; unsafe extern "C" fn sdp_session_name_setup( de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, @@ -788,6 +789,59 @@ unsafe extern "C" fn sip_media_desc_session_info_get_data( false } +unsafe extern "C" fn sdp_media_desc_connection_data_setup( + de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_SIP) != 0 { + return -1; + } + if DetectBufferSetActiveList(de, s, G_SDP_MEDIA_DESC_CONNECTION_DATA_BUFFER_ID) < 0 { + return -1; + } + return 0; +} + +unsafe extern "C" fn sdp_media_desc_connection_data_get( + de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8, + tx: *const c_void, list_id: c_int, local_id: u32, +) -> *mut c_void { + return DetectHelperGetMultiData( + de, + transforms, + flow, + flow_flags, + tx, + list_id, + local_id, + sip_media_desc_connection_data_get_data, + ); +} + +unsafe extern "C" fn sip_media_desc_connection_data_get_data( + tx: *const c_void, flow_flags: u8, local_id: u32, buffer: *mut *const u8, buffer_len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, SIPTransaction); + let direction = flow_flags.into(); + let sdp_option = match direction { + Direction::ToServer => tx.request.as_ref().and_then(|req| req.body.as_ref()), + Direction::ToClient => tx.response.as_ref().and_then(|resp| resp.body.as_ref()), + }; + if let Some(sdp) = sdp_option { + if let Some(ref m) = sdp.media_description { + if (local_id as usize) < m.len() { + if let Some(c) = &m[local_id as usize].connection_data { + *buffer = c.as_ptr(); + *buffer_len = c.len() as u32; + return true; + } + } + } + } + *buffer = ptr::null(); + *buffer_len = 0; + false +} + #[no_mangle] pub unsafe extern "C" fn ScDetectSdpRegister() { let kw = SCSigTableElmt { @@ -1070,4 +1124,23 @@ pub unsafe extern "C" fn ScDetectSdpRegister() { true, sdp_media_desc_session_info_get, ); + let kw = SCSigTableElmt { + name: b"sdp.media.connection_data\0".as_ptr() as *const libc::c_char, + desc: b"sticky buffer to match on the SDP connection data subfield of the media_description field\0".as_ptr() + as *const libc::c_char, + url: b"/rules/sdp-keywords.html#sdp-media-description-connection-data\0".as_ptr() as *const libc::c_char, + Setup: sdp_media_desc_connection_data_setup, + flags: SIGMATCH_NOOPT, + AppLayerTxMatch: None, + Free: None, + }; + let _ = DetectHelperKeywordRegister(&kw); + G_SDP_MEDIA_DESC_CONNECTION_DATA_BUFFER_ID = DetectHelperMultiBufferMpmRegister( + b"sdp.media.connection_data\0".as_ptr() as *const libc::c_char, + b"sdp.media.connection_data\0".as_ptr() as *const libc::c_char, + ALPROTO_SIP, + true, + true, + sdp_media_desc_connection_data_get, + ); } From 43dafab4fc9c2421bd4ade3dcb261c114f83bda9 Mon Sep 17 00:00:00 2001 From: Giuseppe Longo Date: Wed, 2 Oct 2024 10:31:16 +0200 Subject: [PATCH 19/19] sdp: add sdp.media.encryption_key sticky buffer This adds a sticky (multi) buffer to match the "Encryption key" subfield of the "Media description" field in both requests and responses. Ticket #7291 --- doc/userguide/rules/index.rst | 1 + doc/userguide/rules/sdp-keywords.rst | 382 +++++++++++++++++++++++++++ doc/userguide/upgrade.rst | 1 + rust/src/sdp/detect.rs | 73 +++++ 4 files changed, 457 insertions(+) create mode 100644 doc/userguide/rules/sdp-keywords.rst diff --git a/doc/userguide/rules/index.rst b/doc/userguide/rules/index.rst index c8b586fecaa7..1cff79a178fd 100644 --- a/doc/userguide/rules/index.rst +++ b/doc/userguide/rules/index.rst @@ -29,6 +29,7 @@ Suricata Rules snmp-keywords base64-keywords sip-keywords + sdp-keywords rfb-keywords mqtt-keywords ike-keywords diff --git a/doc/userguide/rules/sdp-keywords.rst b/doc/userguide/rules/sdp-keywords.rst new file mode 100644 index 000000000000..aaee99c90129 --- /dev/null +++ b/doc/userguide/rules/sdp-keywords.rst @@ -0,0 +1,382 @@ +SDP Keywords +============ + +The SDP keywords are implemented as sticky buffers and can be used to match on fields in SDP messages. + +======================================== ================== +Keyword Direction +======================================== ================== +sdp.origin Both +sdp.session_name Both +sdp.session_info Both +sdp.uri Both +sdp.email Both +sdp.connection_data Both +sdp.bandwidth Both +sdp.time Both +sdp.repeat_time Both +sdp.timezone Both +sdp.encryption_key Both +sdp.attribute Both +sdp.media_description.media Both +sdp.media_description.session_info Both +sdp.media_description.connection_data Both +sdp.media_description.encryption_key Both +======================================== ================== + +sdp.origin +---------- + +This keyword matches on the originator found in an SDP request or response. + +Syntax +~~~~~~ + +:: + + sdp.origin; content:; + +Where is an originator that follows the SDP Origin (o=) scheme. + +Examples +~~~~~~~~ + +:: + + sdp.origin; content:"SIPPS 105015165 105015162 IN IP4 192.168.1.2"; + +sdp.session_name +---------------- + +This keyword matches on the session name found in an SDP request or response. + +Syntax +~~~~~~ + +:: + + sdp.session_name; content:; + +Where is a name that follows the SDP Session name (s=) scheme. + +Examples +~~~~~~~~ + +:: + + sdp.session_name; content:"SIP call"; + +sdp.session_info +---------------- + +This keyword matches on the session information found in an SDP request or response. + +Syntax +~~~~~~ + +:: + + sdp.session_info; content:; + +Where is a description that follows the SDP Session information (i=) scheme. + +Examples +~~~~~~~~ + +:: + + sdp.session_info; content:"Session Description Protocol"; + +sdp.uri +------- + +This keyword matches on the URI found in an SDP request or response. + +Syntax +~~~~~~ + +:: + + sdp.uri; content:; + +Where is a URI (u=) that the follows the SDP scheme. + +Examples +~~~~~~~~ + +:: + + sdp.uri; content:"https://www.sdp.proto" + +sdp.email +--------- + +This keyword matches on the email found in an SDP request or response. + +Syntax +~~~~~~ + +:: + + sdp.email; content: + +Where is an email address (e=) that follows the SDP scheme. + +Examples +~~~~~~~~ + +:: + + sdp.email; content:"j.doe@example.com (Jane Doe)"; + +sdp.phone_number +---------------- + +This keyword matches on the phone number found in an SDP request or response. + +Syntax +~~~~~~ + +:: + + sdp.phone_number; content: + +Where is a phone number (p=) that follows the SDP scheme. + +Examples +~~~~~~~~ + +:: + + sdp.phone_number; content:"+1 617 555-6011 (Jane Doe)"; + +sdp.connection_data +------------------- + +This keyword matches on the connection found in an SDP request or response. + +Syntax +~~~~~~ + +:: + + sdp.connection_data; content:; + +Where is a connection (c=) that follows the SDP scheme. + +Examples +~~~~~~~~ + +:: + + sdp.connection_data; content:"IN IP4 192.168.1.2" + +sdp.bandwidth +------------- + +This keyword matches on the bandwidths found in an SDP request or response. + +Syntax +~~~~~~ + +:: + + sdp.bandwidth; content: + +Where is a bandwidth (b=) that follows the SDP scheme. + +Example +~~~~~~~ + +:: + + sdp.bandwidth; content:"AS:64" + +sdp.time +-------- + +This keyword matches on the time found in an SDP request or response. + +Syntax +~~~~~~ + +:: + + sdp.time; content: