From: Pierre Chifflier Date: Thu, 2 Sep 2021 08:00:09 +0000 (+0200) Subject: rust/sip: convert parser to nom7 functions X-Git-Tag: suricata-7.0.0-beta1~1270 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d27125d77ac2f2c9177fe76907ec8b5e0e5d7da8;p=thirdparty%2Fsuricata.git rust/sip: convert parser to nom7 functions --- diff --git a/rust/src/sip/parser.rs b/rust/src/sip/parser.rs index 9ce3872b22..3babf7005d 100644 --- a/rust/src/sip/parser.rs +++ b/rust/src/sip/parser.rs @@ -17,10 +17,12 @@ // written by Giuseppe Longo -use nom::*; -use nom::IResult; -use nom::character::{is_alphabetic, is_alphanumeric, is_space}; -use nom::character::streaming::crlf; +use nom7::bytes::streaming::{take, take_while, take_while1}; +use nom7::character::streaming::{char, crlf}; +use nom7::character::{is_alphabetic, is_alphanumeric, is_space}; +use nom7::combinator::map_res; +use nom7::sequence::delimited; +use nom7::{Err, IResult, Needed}; use std; use std::collections::HashMap; @@ -84,84 +86,106 @@ fn is_header_value(b: u8) -> bool { is_alphanumeric(b) || is_token_char(b) || b"\"#$&(),/;:<=>?@[]{}()^|~\\\t\n\r ".contains(&b) } -named!(pub sip_parse_request<&[u8], Request>, - do_parse!( - method: parse_method >> char!(' ') >> - path: parse_request_uri >> char!(' ') >> - version: parse_version >> crlf >> - headers: parse_headers >> - crlf >> - (Request { method: method.into(), path: path.into(), version: version.into(), headers: headers}) - ) -); - -named!(pub sip_parse_response<&[u8], Response>, - do_parse!( - version: parse_version >> char!(' ') >> - code: parse_code >> char!(' ') >> - reason: parse_reason >> crlf >> - (Response { version: version.into(), code: code.into(), reason: reason.into() }) - ) -); - -named!(#[inline], parse_method<&[u8], &str>, - map_res!(take_while!(is_method_char), std::str::from_utf8) -); - -named!(#[inline], parse_request_uri<&[u8], &str>, - map_res!(take_while1!(is_request_uri_char), std::str::from_utf8) -); - -named!(#[inline], parse_version<&[u8], &str>, - map_res!(take_while1!(is_version_char), std::str::from_utf8) -); - -named!(#[inline], parse_code<&[u8], &str>, - map_res!(take!(3), std::str::from_utf8) -); - -named!(#[inline], parse_reason<&[u8], &str>, - map_res!(take_while!(is_reason_phrase), std::str::from_utf8) -); - -named!(#[inline], header_name<&[u8], &str>, - map_res!(take_while!(is_header_name), std::str::from_utf8) -); - -named!(#[inline], header_value<&[u8], &str>, - map_res!(parse_header_value, std::str::from_utf8) -); - -named!( - hcolon, - delimited!(take_while!(is_space), char!(':'), take_while!(is_space)) -); - -named!( - message_header
, - do_parse!( - n: header_name - >> hcolon - >> v: header_value - >> crlf - >> (Header { - name: String::from(n), - value: String::from(v) - }) - ) -); - -named!(pub sip_take_line<&[u8], Option >, - do_parse!( - line: map_res!(take_while1!(is_reason_phrase), std::str::from_utf8) >> - (Some(line.into())) - ) -); +pub fn sip_parse_request(i: &[u8]) -> IResult<&[u8], Request> { + let (i, method) = parse_method(i)?; + 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)?; + Ok(( + i, + Request { + method: method.into(), + path: path.into(), + version: version.into(), + headers, + }, + )) +} + +pub fn sip_parse_response(i: &[u8]) -> IResult<&[u8], Response> { + let (i, version) = parse_version(i)?; + let (i, _) = char(' ')(i)?; + let (i, code) = parse_code(i)?; + let (i, _) = char(' ')(i)?; + let (i, reason) = parse_reason(i)?; + let (i, _) = crlf(i)?; + Ok(( + i, + Response { + version: version.into(), + code: code.into(), + reason: reason.into(), + }, + )) +} + +#[inline] +fn parse_method(i: &[u8]) -> IResult<&[u8], &str> { + map_res(take_while(is_method_char), std::str::from_utf8)(i) +} + +#[inline] +fn parse_request_uri(i: &[u8]) -> IResult<&[u8], &str> { + map_res(take_while1(is_request_uri_char), std::str::from_utf8)(i) +} + +#[inline] +fn parse_version(i: &[u8]) -> IResult<&[u8], &str> { + map_res(take_while1(is_version_char), std::str::from_utf8)(i) +} + +#[inline] +fn parse_code(i: &[u8]) -> IResult<&[u8], &str> { + map_res(take(3_usize), std::str::from_utf8)(i) +} + +#[inline] +fn parse_reason(i: &[u8]) -> IResult<&[u8], &str> { + map_res(take_while(is_reason_phrase), std::str::from_utf8)(i) +} + +#[inline] +fn header_name(i: &[u8]) -> IResult<&[u8], &str> { + map_res(take_while(is_header_name), std::str::from_utf8)(i) +} + +#[inline] +fn header_value(i: &[u8]) -> IResult<&[u8], &str> { + map_res(parse_header_value, std::str::from_utf8)(i) +} + +#[inline] +fn hcolon(i: &[u8]) -> IResult<&[u8], char> { + delimited(take_while(is_space), char(':'), take_while(is_space))(i) +} + +fn message_header(i: &[u8]) -> IResult<&[u8], Header> { + let (i, n) = header_name(i)?; + let (i, _) = hcolon(i)?; + let (i, v) = header_value(i)?; + let (i, _) = crlf(i)?; + Ok(( + i, + Header { + name: String::from(n), + value: String::from(v), + }, + )) +} + +pub fn sip_take_line(i: &[u8]) -> IResult<&[u8], Option> { + let (i, line) = map_res(take_while1(is_reason_phrase), std::str::from_utf8)(i)?; + Ok((i, Some(line.into()))) +} pub fn parse_headers(mut input: &[u8]) -> IResult<&[u8], HashMap> { let mut headers_map: HashMap = HashMap::new(); loop { - match crlf(input) as IResult<&[u8],_> { + match crlf(input) as IResult<&[u8], _> { Ok((_, _)) => { break; } @@ -186,7 +210,7 @@ fn parse_header_value(buf: &[u8]) -> IResult<&[u8], &[u8]> { b'\n' => { idx += 1; if idx >= buf.len() { - return Err(Err::Incomplete(Needed::Size(1))); + return Err(Err::Incomplete(Needed::new(1))); } match buf[idx] { b' ' | b'\t' => { @@ -205,7 +229,7 @@ fn parse_header_value(buf: &[u8]) -> IResult<&[u8], &[u8]> { b => { trail_spaces = 0; if !is_header_value(b) { - return Err(Err::Incomplete(Needed::Size(1))); + return Err(Err::Incomplete(Needed::new(1))); } end_pos = idx + 1; } @@ -251,17 +275,11 @@ mod tests { \r\n" .as_bytes(); - match sip_parse_request(buf) { - Ok((_, req)) => { - 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!(false); - } - } + let (_, 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"); } #[test] diff --git a/rust/src/sip/sip.rs b/rust/src/sip/sip.rs index df31c56b70..f5a86cfc39 100755 --- a/rust/src/sip/sip.rs +++ b/rust/src/sip/sip.rs @@ -17,12 +17,11 @@ // written by Giuseppe Longo -extern crate nom; - use crate::applayer::{self, *}; use crate::core; use crate::core::{sc_detect_engine_state_free, AppProto, Flow, ALPROTO_UNKNOWN}; use crate::sip::parser::*; +use nom7::Err; use std; use std::ffi::CString; @@ -98,7 +97,7 @@ impl SIPState { self.transactions.push(tx); return true; } - Err(nom::Err::Incomplete(_)) => { + Err(Err::Incomplete(_)) => { self.set_event(SIPEvent::IncompleteData); return false; } @@ -120,7 +119,7 @@ impl SIPState { self.transactions.push(tx); return true; } - Err(nom::Err::Incomplete(_)) => { + Err(Err::Incomplete(_)) => { self.set_event(SIPEvent::IncompleteData); return false; } @@ -135,7 +134,7 @@ impl SIPState { impl SIPTransaction { pub fn new(id: u64) -> SIPTransaction { SIPTransaction { - id: id, + id, de_state: None, request: None, response: None,