Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dns over http2 5773 v12 #11292

Closed
wants to merge 7 commits into from
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
9 changes: 9 additions & 0 deletions etc/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -4174,6 +4174,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 @@ -4332,6 +4335,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 @@ -4497,6 +4503,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 @@ -452,6 +452,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
Loading