applayer template (rust): better gap handling example

In the request parser, show checking if a gap was received
and what one example of trying to continue might look like.
pull/5184/head
Jason Ish 5 years ago
parent b91bb92b7d
commit abc71dc4a5

@ -67,6 +67,8 @@ impl Drop for TemplateTransaction {
pub struct TemplateState {
tx_id: u64,
transactions: Vec<TemplateTransaction>,
request_gap: bool,
response_gap: bool,
}
impl TemplateState {
@ -74,6 +76,8 @@ impl TemplateState {
Self {
tx_id: 0,
transactions: Vec::new(),
request_gap: false,
response_gap: false,
}
}
@ -126,6 +130,19 @@ impl TemplateState {
return AppLayerResult::ok();
}
// If there was gap, check we can sync up again.
if self.request_gap {
if probe(input).is_err() {
// The parser now needs to decide what to do as we are not in sync.
// For this template, we'll just try again next time.
return AppLayerResult::ok();
}
// It looks like we're in sync with a message header, clear gap
// state and keep parsing.
self.request_gap = false;
}
let mut start = input;
while start.len() > 0 {
match parser::parse_message(start) {
@ -214,23 +231,27 @@ impl TemplateState {
}
fn on_request_gap(&mut self, _size: u32) {
self.request_gap = true;
}
fn on_response_gap(&mut self, _size: u32) {
self.response_gap = true;
}
}
/// Probe to see if this input looks like a request or response.
/// Probe for a valid header.
///
/// For the purposes of this template things will be kept simple. The
/// protocol is text based with the leading text being the length of
/// the message in bytes. So simply make sure the first character is
/// between "1" and "9".
fn probe(input: &[u8]) -> bool {
if input.len() > 1 && input[0] >= 49 && input[0] <= 57 {
return true;
}
return false;
/// As this template protocol uses messages prefixed with the size
/// as a string followed by a ':', we look at up to the first 10
/// characters for that pattern.
fn probe(input: &[u8]) -> nom::IResult<&[u8], ()> {
let size = std::cmp::min(10, input.len());
let (rem, prefix) = nom::bytes::complete::take(size)(input)?;
nom::sequence::terminated(
nom::bytes::complete::take_while1(nom::character::is_digit),
nom::bytes::complete::tag(":"),
)(prefix)?;
Ok((rem, ()))
}
// C exports.
@ -256,7 +277,7 @@ pub extern "C" fn rs_template_probing_parser(
// Need at least 2 bytes.
if input_len > 1 && input != std::ptr::null_mut() {
let slice = build_slice!(input, input_len as usize);
if probe(slice) {
if probe(slice).is_ok() {
return unsafe { ALPROTO_TEMPLATE };
}
}
@ -557,6 +578,14 @@ pub unsafe extern "C" fn rs_template_register_parser() {
mod test {
use super::*;
#[test]
fn test_probe() {
assert!(probe(b"1").is_err());
assert!(probe(b"1:").is_ok());
assert!(probe(b"123456789:").is_ok());
assert!(probe(b"0123456789:").is_err());
}
#[test]
fn test_incomplete() {
let mut state = TemplateState::new();

Loading…
Cancel
Save