Skip to content
Closed
Show file tree
Hide file tree
Changes from 6 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
9 changes: 9 additions & 0 deletions etc/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -4591,6 +4591,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 @@ -4753,6 +4756,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 @@ -4922,6 +4928,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 @@ -471,6 +471,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
253 changes: 150 additions & 103 deletions rust/src/dns/dns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,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 @@ -338,18 +343,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(crate) 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 @@ -382,63 +485,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 @@ -469,59 +543,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
20 changes: 9 additions & 11 deletions rust/src/http2/detect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,7 @@ fn http2_tx_get_resp_line(tx: &mut HTTP2Transaction) {
return;
}
let empty = Vec::new();
let mut resp_line : Vec<u8> = Vec::new();
let mut resp_line: Vec<u8> = Vec::new();

let status =
if let Ok(value) = http2_frames_get_header_firstvalue(tx, Direction::ToClient, ":status") {
Expand Down Expand Up @@ -617,7 +617,7 @@ fn http2_lower(value: &[u8]) -> Option<Vec<u8>> {
fn http2_normalize_host(value: &[u8]) -> &[u8] {
match value.iter().position(|&x| x == b'@') {
Some(i) => {
let value = &value[i+1..];
let value = &value[i + 1..];
match value.iter().position(|&x| x == b':') {
Some(i) => {
return &value[..i];
Expand All @@ -627,16 +627,14 @@ fn http2_normalize_host(value: &[u8]) -> &[u8] {
}
}
}
None => {
match value.iter().position(|&x| x == b':') {
Some(i) => {
return &value[..i];
}
None => {
return value;
}
None => match value.iter().position(|&x| x == b':') {
Some(i) => {
return &value[..i];
}
}
None => {
return value;
}
},
}
}

Expand Down
Loading