Skip to content
Closed
9 changes: 9 additions & 0 deletions etc/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -4177,6 +4177,9 @@
"description": "Errors encountered parsing DNS/UDP protocol",
"$ref": "#/$defs/stats_applayer_error"
},
"doh2": {
"$ref": "#/$defs/stats_applayer_error"
},
"enip_tcp": {
"description": "Errors encounterd parsing ENIP/TCP",
"$ref": "#/$defs/stats_applayer_error"
Expand Down Expand Up @@ -4335,6 +4338,9 @@
"description": "Number of flows for DNS/UDP protocol",
"type": "integer"
},
"doh2": {
"type": "integer"
},
"enip_tcp": {
"description": "Number of flows for ENIP/TCP",
"type": "integer"
Expand Down Expand Up @@ -4500,6 +4506,9 @@
"description": "Number of transactions for DNS/UDP protocol",
"type": "integer"
},
"doh2": {
"type": "integer"
},
"enip_tcp": {
"description": "Number of transactions for ENIP/TCP",
"type": "integer"
Expand Down
1 change: 1 addition & 0 deletions rust/src/applayer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,7 @@ pub unsafe fn AppLayerRegisterParser(parser: *const RustParser, alproto: AppProt

// Defined in app-layer-detect-proto.h
extern {
pub fn AppLayerForceProtocolChange(f: *const Flow, new_proto: AppProto);
pub fn AppLayerProtoDetectPPRegister(ipproto: u8, portstr: *const c_char, alproto: AppProto,
min_depth: u16, max_depth: u16, dir: u8,
pparser1: ProbeFn, pparser2: ProbeFn);
Expand Down
7 changes: 7 additions & 0 deletions rust/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ impl Direction {
pub fn is_to_client(&self) -> bool {
matches!(self, Self::ToClient)
}

pub fn index(&self) -> usize {
match self {
Self::ToClient => 0,
_ => 1,
}
}
}

impl Default for Direction {
Expand Down
253 changes: 150 additions & 103 deletions rust/src/dns/dns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,11 @@ impl DNSTransaction {
}
return 0;
}

/// Set an event. The event is set on the most recent transaction.
pub fn set_event(&mut self, event: DNSEvent) {
self.tx_data.set_event(event as u8);
}
}

struct ConfigTracker {
Expand Down Expand Up @@ -328,18 +333,116 @@ impl State<DNSTransaction> for DNSState {
}
}

fn dns_validate_header(input: &[u8]) -> Option<(&[u8], DNSHeader)> {
if let Ok((body, header)) = parser::dns_parse_header(input) {
if probe_header_validity(&header, input.len()).0 {
return Some((body, header));
}
}
None
}

#[derive(Debug, PartialEq, Eq)]
pub enum DNSParseError {
HeaderValidation,
NotRequest,
Incomplete,
OtherError,
}

pub(crate) fn dns_parse_request(input: &[u8]) -> Result<DNSTransaction, DNSParseError> {
let (body, header) = if let Some((body, header)) = dns_validate_header(input) {
(body, header)
} else {
return Err(DNSParseError::HeaderValidation);
};

match parser::dns_parse_body(body, input, header) {
Ok((_, request)) => {
if request.header.flags & 0x8000 != 0 {
SCLogDebug!("DNS message is not a request");
return Err(DNSParseError::NotRequest);
}

let z_flag = request.header.flags & 0x0040 != 0;
let opcode = ((request.header.flags >> 11) & 0xf) as u8;

let mut tx = DNSTransaction::new(Direction::ToServer);
tx.request = Some(request);

if z_flag {
SCLogDebug!("Z-flag set on DNS request");
tx.set_event(DNSEvent::ZFlagSet);
}
if opcode >= 7 {
tx.set_event(DNSEvent::InvalidOpcode);
}

return Ok(tx);
}
Err(Err::Incomplete(_)) => {
// Insufficient data.
SCLogDebug!("Insufficient data while parsing DNS request");
return Err(DNSParseError::Incomplete);
}
Err(_) => {
// Error, probably malformed data.
SCLogDebug!("An error occurred while parsing DNS request");
return Err(DNSParseError::OtherError);
}
}
}

pub(crate) fn dns_parse_response(input: &[u8]) -> Result<DNSTransaction, DNSParseError> {
let (body, header) = if let Some((body, header)) = dns_validate_header(input) {
(body, header)
} else {
return Err(DNSParseError::HeaderValidation);
};

match parser::dns_parse_body(body, input, header) {
Ok((_, response)) => {
SCLogDebug!("Response header flags: {}", response.header.flags);
let z_flag = response.header.flags & 0x0040 != 0;
let opcode = ((response.header.flags >> 11) & 0xf) as u8;
let flags = response.header.flags;

let mut tx = DNSTransaction::new(Direction::ToClient);
tx.response = Some(response);

if flags & 0x8000 == 0 {
SCLogDebug!("DNS message is not a response");
tx.set_event(DNSEvent::NotResponse);
}

if z_flag {
SCLogDebug!("Z-flag set on DNS response");
tx.set_event(DNSEvent::ZFlagSet);
}
if opcode >= 7 {
tx.set_event(DNSEvent::InvalidOpcode);
}

return Ok(tx);
}
Err(Err::Incomplete(_)) => {
// Insufficient data.
SCLogDebug!("Insufficient data while parsing DNS request");
return Err(DNSParseError::Incomplete);
}
Err(_) => {
// Error, probably malformed data.
SCLogDebug!("An error occurred while parsing DNS request");
return Err(DNSParseError::OtherError);
}
}
}

impl DNSState {
fn new() -> Self {
Default::default()
}

fn new_tx(&mut self, direction: Direction) -> DNSTransaction {
let mut tx = DNSTransaction::new(direction);
self.tx_id += 1;
tx.id = self.tx_id;
return tx;
}

fn free_tx(&mut self, tx_id: u64) {
let len = self.transactions.len();
let mut found = false;
Expand Down Expand Up @@ -372,63 +475,34 @@ impl DNSState {
tx.tx_data.set_event(event as u8);
}

fn validate_header<'a>(&self, input: &'a [u8]) -> Option<(&'a [u8], DNSHeader)> {
if let Ok((body, header)) = parser::dns_parse_header(input) {
if probe_header_validity(&header, input.len()).0 {
return Some((body, header));
}
}
None
}

fn parse_request(&mut self, input: &[u8], is_tcp: bool, frame: Option<Frame>, flow: *const core::Flow,) -> bool {
let (body, header) = if let Some((body, header)) = self.validate_header(input) {
(body, header)
} else {
return !is_tcp;
};

match parser::dns_parse_body(body, input, header) {
Ok((_, request)) => {
if request.header.flags & 0x8000 != 0 {
SCLogDebug!("DNS message is not a request");
self.set_event(DNSEvent::NotRequest);
return false;
}

let z_flag = request.header.flags & 0x0040 != 0;
let opcode = ((request.header.flags >> 11) & 0xf) as u8;

let mut tx = self.new_tx(Direction::ToServer);
match dns_parse_request(input) {
Ok(mut tx) => {
self.tx_id += 1;
tx.id = self.tx_id;
if let Some(frame) = frame {
frame.set_tx(flow, tx.id);
}
tx.request = Some(request);
self.transactions.push_back(tx);

if z_flag {
SCLogDebug!("Z-flag set on DNS response");
self.set_event(DNSEvent::ZFlagSet);
}

if opcode >= 7 {
self.set_event(DNSEvent::InvalidOpcode);
}

return true;
}
Err(Err::Incomplete(_)) => {
// Insufficient data.
SCLogDebug!("Insufficient data while parsing DNS request");
self.set_event(DNSEvent::MalformedData);
return false;
}
Err(_) => {
// Error, probably malformed data.
SCLogDebug!("An error occurred while parsing DNS request");
self.set_event(DNSEvent::MalformedData);
return false;
}
Err(e) => match e {
DNSParseError::HeaderValidation => {
return !is_tcp;
}
DNSParseError::NotRequest => {
self.set_event(DNSEvent::NotRequest);
return false;
}
DNSParseError::Incomplete => {
self.set_event(DNSEvent::MalformedData);
return false;
}
DNSParseError::OtherError => {
self.set_event(DNSEvent::MalformedData);
return false;
}
},
}
}

Expand Down Expand Up @@ -459,59 +533,32 @@ impl DNSState {
}

fn parse_response(&mut self, input: &[u8], is_tcp: bool, frame: Option<Frame>, flow: *const core::Flow) -> bool {
let (body, header) = if let Some((body, header)) = self.validate_header(input) {
(body, header)
} else {
return !is_tcp;
};

match parser::dns_parse_body(body, input, header) {
Ok((_, response)) => {
SCLogDebug!("Response header flags: {}", response.header.flags);

if response.header.flags & 0x8000 == 0 {
SCLogDebug!("DNS message is not a response");
self.set_event(DNSEvent::NotResponse);
match dns_parse_response(input) {
Ok(mut tx) => {
self.tx_id += 1;
tx.id = self.tx_id;
if let Some(ref mut config) = &mut self.config {
if let Some(response) = &tx.response {
if let Some(config) = config.remove(&response.header.tx_id) {
tx.tx_data.config = config;
}
}
}

let z_flag = response.header.flags & 0x0040 != 0;
let opcode = ((response.header.flags >> 11) & 0xf) as u8;

let mut tx = self.new_tx(Direction::ToClient);
if let Some(frame) = frame {
frame.set_tx(flow, tx.id);
}
if let Some(ref mut config) = &mut self.config {
if let Some(config) = config.remove(&response.header.tx_id) {
tx.tx_data.config = config;
}
}
tx.response = Some(response);
self.transactions.push_back(tx);

if z_flag {
SCLogDebug!("Z-flag set on DNS response");
self.set_event(DNSEvent::ZFlagSet);
}

if opcode >= 7 {
self.set_event(DNSEvent::InvalidOpcode);
}

return true;
}
Err(Err::Incomplete(_)) => {
// Insufficient data.
SCLogDebug!("Insufficient data while parsing DNS response");
self.set_event(DNSEvent::MalformedData);
return false;
}
Err(_) => {
// Error, probably malformed data.
SCLogDebug!("An error occurred while parsing DNS response");
self.set_event(DNSEvent::MalformedData);
return false;
}
Err(e) => match e {
DNSParseError::HeaderValidation => {
return !is_tcp;
}
_ => {
self.set_event(DNSEvent::MalformedData);
return false;
}
},
}
}

Expand Down
6 changes: 4 additions & 2 deletions rust/src/http2/decompression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,10 +178,12 @@ impl HTTP2DecoderHalf {
if self.encoding == HTTP2ContentEncoding::Unknown {
if input == b"gzip" {
self.encoding = HTTP2ContentEncoding::Gzip;
self.decoder = HTTP2Decompresser::Gzip(Box::new(GzDecoder::new(HTTP2cursor::new())));
self.decoder =
HTTP2Decompresser::Gzip(Box::new(GzDecoder::new(HTTP2cursor::new())));
} else if input == b"deflate" {
self.encoding = HTTP2ContentEncoding::Deflate;
self.decoder = HTTP2Decompresser::Deflate(Box::new(DeflateDecoder::new(HTTP2cursor::new())));
self.decoder =
HTTP2Decompresser::Deflate(Box::new(DeflateDecoder::new(HTTP2cursor::new())));
} else if input == b"br" {
self.encoding = HTTP2ContentEncoding::Br;
self.decoder = HTTP2Decompresser::Brotli(Box::new(brotli::Decompressor::new(
Expand Down
Loading