Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions rules/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pgsql-events.rules \
pop3-events.rules \
quic-events.rules \
rfb-events.rules \
sip-events.rules \
smb-events.rules \
smtp-events.rules \
snmp-events.rules \
Expand Down
1 change: 1 addition & 0 deletions rules/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,5 @@ signature IDs.
| Bittorent| 2243000 | 2243999 |
| MODBUS | 2250000 | 2250999 |
| DNP3 | 2270000 | 2270999 |
| SIP | 2280000 | 2280999 |
| HTTP2 | 2290000 | 2290999 |
5 changes: 5 additions & 0 deletions rules/sip-events.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# SIP app layer event rules
#
# SID's fall in the 2280000-2280999 range.
#
alert sip any any -> any any (msg:"SURICATA SIP invalid data"; app-layer-event:sip.invalid_data; classtype:protocol-command-decode; sid:2280001; rev:1;)
32 changes: 30 additions & 2 deletions rust/src/sip/parser.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright (C) 2019-2022 Open Information Security Foundation
/* Copyright (C) 2019-2026 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
Expand All @@ -18,9 +18,10 @@
// written by Giuseppe Longo <giuseppe@glongo.it>

use crate::sdp::parser::{sdp_parse_message, SdpMessage};
use nom8::bytes::streaming::{tag, take, take_while, take_while1};
use nom8::bytes::streaming::{tag, take, take_until, take_while, take_while1};
use nom8::character::streaming::{char, crlf};
use nom8::combinator::{map, map_res, opt};
use nom8::error::{Error, ErrorKind};
use nom8::sequence::delimited;
use nom8::{AsChar, Err, IResult, Needed, Parser};
use std;
Expand Down Expand Up @@ -112,6 +113,21 @@ fn expand_header_name(h: &str) -> &str {
}
}

pub fn sip_probe_protocol(input: &[u8]) -> IResult<&[u8], ()> {
let len = std::cmp::min(input.len(), 65536);
let i = &input[..len];

if tag::<_, _, Error<&[u8]>>("SIP/").parse(i).is_ok() {
return Ok((input, ()));
}

if take_until::<_, _, Error<&[u8]>>("SIP/").parse(i).is_ok() {
Ok((input, ()))
} else {
Err(Err::Error(Error::new(i, ErrorKind::Tag)))
}
}

pub fn parse_request(oi: &[u8]) -> IResult<&[u8], Request> {
let (i, method) = parse_method(oi)?;
let (i, _) = char(' ').parse(i)?;
Expand Down Expand Up @@ -364,6 +380,18 @@ mod tests {
assert_eq!(result, "SIP/2.0");
}

#[test]
fn test_probe_sip_request() {
let buf = b"REGISTER sip:sip.example.com SIP/2.0\r\n";
assert!(sip_probe_protocol(buf).is_ok());
}

#[test]
fn test_probe_sip_response() {
let buf = b"SIP/2.0 200 OK\r\n";
assert!(sip_probe_protocol(buf).is_ok());
}

#[test]
fn test_header_multi_value() {
let buf: &[u8] = "REGISTER sip:sip.cybercity.dk SIP/2.0\r\n\
Expand Down
69 changes: 44 additions & 25 deletions rust/src/sip/sip.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Copyright (C) 2019-2022 Open Information Security Foundation
/* Copyright (C) 2019-2026 Open Information Security Foundation
*
* You can copy, redistribute or modify this Program under the terms of
* the GNU General Public License version 2 as published by the Free
Expand All @@ -20,7 +20,8 @@
use crate::applayer::{self, *};
use crate::core;
use crate::core::{
sc_app_layer_parser_trigger_raw_stream_inspection, ALPROTO_UNKNOWN, IPPROTO_TCP, IPPROTO_UDP,
sc_app_layer_parser_trigger_raw_stream_inspection, ALPROTO_FAILED, ALPROTO_UNKNOWN,
IPPROTO_TCP, IPPROTO_UDP,
};
use crate::direction::Direction;
use crate::flow::Flow;
Expand All @@ -34,6 +35,7 @@ use suricata_sys::sys::{
AppLayerParserState, AppProto, SCAppLayerParserConfParserEnabled,
SCAppLayerParserRegisterLogger, SCAppLayerParserStateIssetFlag,
SCAppLayerProtoDetectConfProtoDetectionEnabled, SCAppLayerProtoDetectPMRegisterPatternCS,
SCAppLayerProtoDetectPMRegisterPatternCSwPP,
};

// app-layer-frame-documentation tag start: FrameType enum
Expand All @@ -51,7 +53,6 @@ pub enum SIPFrameType {

#[derive(AppLayerEvent)]
pub enum SIPEvent {
IncompleteData,
InvalidData,
}

Expand Down Expand Up @@ -146,10 +147,6 @@ impl SIPState {
return AppLayerResult::ok();
}
// app-layer-frame-documentation tag end: parse_request
Err(Err::Incomplete(_)) => {
self.set_event(SIPEvent::IncompleteData);
return AppLayerResult::err();
}
Err(_) => {
self.set_event(SIPEvent::InvalidData);
return AppLayerResult::err();
Expand Down Expand Up @@ -243,10 +240,6 @@ impl SIPState {
self.transactions.push_back(tx);
return AppLayerResult::ok();
}
Err(Err::Incomplete(_)) => {
self.set_event(SIPEvent::IncompleteData);
return AppLayerResult::err();
}
Err(_) => {
self.set_event(SIPEvent::InvalidData);
return AppLayerResult::err();
Expand Down Expand Up @@ -492,21 +485,41 @@ unsafe extern "C" fn sip_parse_response_tcp(
state.parse_response_tcp(flow, stream_slice)
}

unsafe extern "C" fn sip_probing_parser(
_f: *const Flow, _direction: u8, input: *const u8, input_len: u32, _rdir: *mut u8,
) -> AppProto {
if input.is_null() || input_len == 0 {
return ALPROTO_UNKNOWN;
}
let buf = std::slice::from_raw_parts(input, input_len as usize);
match sip_probe_protocol(buf) {
Ok(_) => ALPROTO_SIP,
Err(Err::Incomplete(_)) => ALPROTO_UNKNOWN,
Err(_) => ALPROTO_FAILED,
}
}

fn register_pattern_probe(proto: u8) -> i8 {
let methods_with_probe: Vec<&str> = vec![
"ACK\0",
"INFO\0",
"NOTIFY\0",
"SUBSCRIBE\0",
"OPTIONS\0",
"UPDATE\0",
];

let methods: Vec<&str> = vec![
"REGISTER\0",
"INVITE\0",
"ACK\0",
"BYE\0",
"CANCEL\0",
"REFER\0",
"PRACK\0",
"SUBSCRIBE\0",
"NOTIFY\0",
"PUBLISH\0",
"MESSAGE\0",
"INFO\0",
];

let mut r = 0;
unsafe {
for method in methods {
Expand All @@ -520,6 +533,22 @@ fn register_pattern_probe(proto: u8) -> i8 {
Direction::ToServer as u8,
);
}

for method in methods_with_probe {
let depth = (method.len() - 1) as u16;
r |= SCAppLayerProtoDetectPMRegisterPatternCSwPP(
proto,
ALPROTO_SIP,
method.as_ptr() as *const std::os::raw::c_char,
depth,
0,
Direction::ToServer as u8,
Some(sip_probing_parser),
0,
0,
);
}

r |= SCAppLayerProtoDetectPMRegisterPatternCS(
proto,
ALPROTO_SIP,
Expand All @@ -528,16 +557,6 @@ fn register_pattern_probe(proto: u8) -> i8 {
0,
Direction::ToClient as u8,
);
if proto == core::IPPROTO_UDP {
r |= SCAppLayerProtoDetectPMRegisterPatternCS(
proto,
ALPROTO_SIP,
"UPDATE\0".as_ptr() as *const std::os::raw::c_char,
"UPDATE".len() as u16,
0,
Direction::ToServer as u8,
);
}
}

if r == 0 {
Expand Down
2 changes: 1 addition & 1 deletion suricata.yaml.in
Original file line number Diff line number Diff line change
Expand Up @@ -1278,7 +1278,7 @@ app-layer:
enabled: yes

sip:
#enabled: yes
enabled: yes

ldap:
tcp:
Expand Down
Loading