]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
sip: add frames support
authorVictor Julien <vjulien@oisf.net>
Tue, 8 Feb 2022 08:52:35 +0000 (09:52 +0100)
committerVictor Julien <vjulien@oisf.net>
Tue, 8 Feb 2022 08:55:38 +0000 (09:55 +0100)
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.

rust/src/sip/parser.rs
rust/src/sip/sip.rs

index 3babf7005d26310e182e7725052caa64358f5ace..29a7e69a308577f43e93bc00085e96599ab28be1 100644 (file)
@@ -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<String, String>,
+
+    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: <sip:voi18063@sip.cybercity.dk>;tag=903df0a\r\n\
                           To: <sip:voi18063@sip.cybercity.dk>\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]
index f7dfc3df43db9d19e4660ae9980dd38d76a954ce..98d61f50c62b0169023a1e72c57a055efb1cab9f 100755 (executable)
@@ -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 <giuseppe@glongo.it>
 
+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();