From: Victor Julien Date: Tue, 8 Feb 2022 08:52:35 +0000 (+0100) Subject: sip: add frames support X-Git-Tag: suricata-7.0.0-beta1~920 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=12037503883a3f19f0c4f85832e2b664692bb43e;p=thirdparty%2Fsuricata.git sip: add frames support Frames: - sip.pdu - sip.request_line - sip.response_line - sip.request_headers - sip.response_headers - sip.request_body - sip.response_body The `sip.pdu` frame is always created, the rest only if the record parser succeeded. Ticket: #5036. --- diff --git a/rust/src/sip/parser.rs b/rust/src/sip/parser.rs index 3babf7005d..29a7e69a30 100644 --- a/rust/src/sip/parser.rs +++ b/rust/src/sip/parser.rs @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Open Information Security Foundation +/* Copyright (C) 2019-2022 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 @@ -38,6 +38,11 @@ pub struct Request { pub path: String, pub version: String, pub headers: HashMap, + + pub request_line_len: u16, + pub headers_len: u16, + pub body_offset: u16, + pub body_len: u16, } #[derive(Debug)] @@ -45,6 +50,11 @@ pub struct Response { pub version: String, pub code: String, pub reason: String, + + pub response_line_len: u16, + pub headers_len: u16, + pub body_offset: u16, + pub body_len: u16, } #[derive(PartialEq, Debug, Clone)] @@ -86,39 +96,57 @@ fn is_header_value(b: u8) -> bool { is_alphanumeric(b) || is_token_char(b) || b"\"#$&(),/;:<=>?@[]{}()^|~\\\t\n\r ".contains(&b) } -pub fn sip_parse_request(i: &[u8]) -> IResult<&[u8], Request> { - let (i, method) = parse_method(i)?; +pub fn sip_parse_request(oi: &[u8]) -> IResult<&[u8], Request> { + let (i, method) = parse_method(oi)?; let (i, _) = char(' ')(i)?; let (i, path) = parse_request_uri(i)?; let (i, _) = char(' ')(i)?; let (i, version) = parse_version(i)?; - let (i, _) = crlf(i)?; - let (i, headers) = parse_headers(i)?; - let (i, _) = crlf(i)?; + let (hi, _) = crlf(i)?; + let request_line_len = oi.len() - hi.len(); + let (phi, headers) = parse_headers(hi)?; + let headers_len = hi.len() - phi.len(); + let (bi, _) = crlf(phi)?; + let body_offset = oi.len() - bi.len(); Ok(( - i, + bi, Request { method: method.into(), path: path.into(), version: version.into(), headers, + + request_line_len: request_line_len as u16, + headers_len: headers_len as u16, + body_offset: body_offset as u16, + body_len: bi.len() as u16, }, )) } -pub fn sip_parse_response(i: &[u8]) -> IResult<&[u8], Response> { - let (i, version) = parse_version(i)?; +pub fn sip_parse_response(oi: &[u8]) -> IResult<&[u8], Response> { + let (i, version) = parse_version(oi)?; let (i, _) = char(' ')(i)?; let (i, code) = parse_code(i)?; let (i, _) = char(' ')(i)?; let (i, reason) = parse_reason(i)?; - let (i, _) = crlf(i)?; + let (hi, _) = crlf(i)?; + let response_line_len = oi.len() - hi.len(); + let (phi, _headers) = parse_headers(hi)?; + let headers_len = hi.len() - phi.len(); + let (bi, _) = crlf(phi)?; + let body_offset = oi.len() - bi.len(); Ok(( - i, + bi, Response { version: version.into(), code: code.into(), reason: reason.into(), + + response_line_len: response_line_len as u16, + headers_len: headers_len as u16, + body_offset: body_offset as u16, + body_len: bi.len() as u16, }, )) } @@ -271,15 +299,16 @@ mod tests { let buf: &[u8] = "REGISTER sip:sip.cybercity.dk SIP/2.0\r\n\ From: ;tag=903df0a\r\n\ To: \r\n\ - Content-Length: 0 \r\n\ - \r\n" + Content-Length: 4 \r\n\ + \r\nABCD" .as_bytes(); - let (_, req) = sip_parse_request(buf).expect("parsing failed"); + let (body, req) = sip_parse_request(buf).expect("parsing failed"); assert_eq!(req.method, "REGISTER"); assert_eq!(req.path, "sip:sip.cybercity.dk"); assert_eq!(req.version, "SIP/2.0"); - assert_eq!(req.headers["Content-Length"], "0"); + assert_eq!(req.headers["Content-Length"], "4"); + assert_eq!(body, "ABCD".as_bytes()); } #[test] diff --git a/rust/src/sip/sip.rs b/rust/src/sip/sip.rs index f7dfc3df43..98d61f50c6 100755 --- a/rust/src/sip/sip.rs +++ b/rust/src/sip/sip.rs @@ -1,4 +1,4 @@ -/* Copyright (C) 2019-2020 Open Information Security Foundation +/* Copyright (C) 2019-2022 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 @@ -17,6 +17,7 @@ // written by Giuseppe Longo +use crate::frames::*; use crate::applayer::{self, *}; use crate::core; use crate::core::{AppProto, Flow, ALPROTO_UNKNOWN}; @@ -25,6 +26,17 @@ use nom7::Err; use std; use std::ffi::CString; +#[derive(AppLayerFrameType)] +pub enum SIPFrameType { + Pdu, + RequestLine, + ResponseLine, + RequestHeaders, + ResponseHeaders, + RequestBody, + ResponseBody, +} + #[derive(AppLayerEvent)] pub enum SIPEvent { IncompleteData, @@ -95,9 +107,14 @@ impl SIPState { } } - fn parse_request(&mut self, input: &[u8]) -> bool { + fn parse_request(&mut self, flow: *const core::Flow, stream_slice: StreamSlice) -> bool { + let input = stream_slice.as_slice(); + let _pdu = Frame::new_ts(flow, &stream_slice, input, input.len() as i64, SIPFrameType::Pdu as u8); + SCLogDebug!("ts: pdu {:?}", _pdu); + match sip_parse_request(input) { Ok((_, request)) => { + sip_frames_ts(flow, &stream_slice, &request); let mut tx = self.new_tx(); tx.request = Some(request); if let Ok((_, req_line)) = sip_take_line(input) { @@ -117,9 +134,14 @@ impl SIPState { } } - fn parse_response(&mut self, input: &[u8]) -> bool { + fn parse_response(&mut self, flow: *const core::Flow, stream_slice: StreamSlice) -> bool { + let input = stream_slice.as_slice(); + let _pdu = Frame::new_tc(flow, &stream_slice, input, input.len() as i64, SIPFrameType::Pdu as u8); + SCLogDebug!("tc: pdu {:?}", _pdu); + match sip_parse_response(input) { Ok((_, response)) => { + sip_frames_tc(flow, &stream_slice, &response); let mut tx = self.new_tx(); tx.response = Some(response); if let Ok((_, resp_line)) = sip_take_line(input) { @@ -153,6 +175,35 @@ impl SIPTransaction { } } + +fn sip_frames_ts(flow: *const core::Flow, stream_slice: &StreamSlice, r: &Request) { + let oi = stream_slice.as_slice(); + let _f = Frame::new_ts(flow, stream_slice, oi, r.request_line_len as i64, SIPFrameType::RequestLine as u8); + SCLogDebug!("ts: request_line {:?}", _f); + let hi = &oi[r.request_line_len as usize ..]; + let _f = Frame::new_ts(flow, stream_slice, hi, r.headers_len as i64, SIPFrameType::RequestHeaders as u8); + SCLogDebug!("ts: request_headers {:?}", _f); + if r.body_len > 0 { + let bi = &oi[r.body_offset as usize ..]; + let _f = Frame::new_ts(flow, stream_slice, bi, r.body_len as i64, SIPFrameType::RequestBody as u8); + SCLogDebug!("ts: request_body {:?}", _f); + } +} + +fn sip_frames_tc(flow: *const core::Flow, stream_slice: &StreamSlice, r: &Response) { + let oi = stream_slice.as_slice(); + let _f = Frame::new_tc(flow, stream_slice, oi, r.response_line_len as i64, SIPFrameType::ResponseLine as u8); + let hi = &oi[r.response_line_len as usize ..]; + SCLogDebug!("tc: response_line {:?}", _f); + let _f = Frame::new_tc(flow, stream_slice, hi, r.headers_len as i64, SIPFrameType::ResponseHeaders as u8); + SCLogDebug!("tc: response_headers {:?}", _f); + if r.body_len > 0 { + let bi = &oi[r.body_offset as usize ..]; + let _f = Frame::new_tc(flow, stream_slice, bi, r.body_len as i64, SIPFrameType::ResponseBody as u8); + SCLogDebug!("tc: response_body {:?}", _f); + } +} + #[no_mangle] pub extern "C" fn rs_sip_state_new(_orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto) -> *mut std::os::raw::c_void { let state = SIPState::new(); @@ -232,26 +283,26 @@ pub unsafe extern "C" fn rs_sip_probing_parser_tc( #[no_mangle] pub unsafe extern "C" fn rs_sip_parse_request( - _flow: *const core::Flow, + flow: *const core::Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { let state = cast_pointer!(state, SIPState); - state.parse_request(stream_slice.as_slice()).into() + state.parse_request(flow, stream_slice).into() } #[no_mangle] pub unsafe extern "C" fn rs_sip_parse_response( - _flow: *const core::Flow, + flow: *const core::Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, stream_slice: StreamSlice, _data: *const std::os::raw::c_void, ) -> AppLayerResult { let state = cast_pointer!(state, SIPState); - state.parse_response(stream_slice.as_slice()).into() + state.parse_response(flow, stream_slice).into() } export_tx_data_get!(rs_sip_get_tx_data, SIPTransaction); @@ -289,8 +340,8 @@ pub unsafe extern "C" fn rs_sip_register_parser() { apply_tx_config: None, flags: APP_LAYER_PARSER_OPT_UNIDIR_TXS, truncate: None, - get_frame_id_by_name: None, - get_frame_name_by_id: None, + get_frame_id_by_name: Some(SIPFrameType::ffi_id_from_name), + get_frame_name_by_id: Some(SIPFrameType::ffi_name_from_id), }; let ip_proto_str = CString::new("udp").unwrap();