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.
pull/6947/head
Victor Julien 4 years ago
parent c96d22e8a1
commit 1203750388

@ -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]

@ -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();

Loading…
Cancel
Save