From: Philippe Antoine Date: Thu, 28 Mar 2024 15:55:10 +0000 (+0100) Subject: doh2: handle dns message in POST requests X-Git-Tag: suricata-8.0.0-beta1~985 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6e12475f48269860b8cd57050e18e421a5ae5c5f;p=thirdparty%2Fsuricata.git doh2: handle dns message in POST requests Ticket: 5773 Handles both directions the same way for data if content type is application/dns-message --- diff --git a/rust/src/core.rs b/rust/src/core.rs index abb27ea578..bca2281311 100644 --- a/rust/src/core.rs +++ b/rust/src/core.rs @@ -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 { diff --git a/rust/src/http2/http2.rs b/rust/src/http2/http2.rs index 6620c040de..2c561c70d4 100644 --- a/rust/src/http2/http2.rs +++ b/rust/src/http2/http2.rs @@ -151,9 +151,9 @@ pub struct HTTP2Transaction { pub req_line: Vec, pub resp_line: Vec, - is_doh_response: bool, + is_doh_data: [bool; 2], // dns response buffer - pub doh_response_buf: Vec, + pub doh_data_buf: [Vec; 2], pub dns_request_tx: Option, pub dns_response_tx: Option, } @@ -187,8 +187,8 @@ impl HTTP2Transaction { escaped: Vec::with_capacity(16), req_line: Vec::new(), resp_line: Vec::new(), - is_doh_response: false, - doh_response_buf: Vec::new(), + is_doh_data: [false; 2], + doh_data_buf: Default::default(), dns_request_tx: None, dns_response_tx: None, } @@ -235,7 +235,7 @@ impl HTTP2Transaction { } } else if block.name.as_ref() == b"content-type" { if block.value.as_ref() == b"application/dns-message" { - self.is_doh_response = true; + self.is_doh_data[dir.index()] = true; } } else if block.name.as_ref() == b":path" { path = Some(&block.value); @@ -260,7 +260,7 @@ impl HTTP2Transaction { } } } - if doh && unsafe {ALPROTO_DOH2} != ALPROTO_UNKNOWN { + if doh && unsafe { ALPROTO_DOH2 } != ALPROTO_UNKNOWN { if let Some(p) = path { if let Ok((_, dns_req)) = parser::doh_extract_request(p) { return Some(dns_req); @@ -345,11 +345,11 @@ impl HTTP2Transaction { &xid, ); }; - if unsafe {ALPROTO_DOH2} != ALPROTO_UNKNOWN { + if unsafe { ALPROTO_DOH2 } != ALPROTO_UNKNOWN { // we store DNS response, and process it when complete - if self.is_doh_response && self.doh_response_buf.len() < 0xFFFF { + if self.is_doh_data[dir.index()] && self.doh_data_buf[dir.index()].len() < 0xFFFF { // a DNS message is U16_MAX - self.doh_response_buf.extend_from_slice(decompressed); + self.doh_data_buf[dir.index()].extend_from_slice(decompressed); } } return Ok(()); @@ -432,6 +432,26 @@ impl HTTP2Transaction { } return r; } + + fn handle_dns_data(&mut self, over: bool, dir: Direction, flow: *const Flow) { + if !self.doh_data_buf[dir.index()].is_empty() && over { + if dir.is_to_client() { + if let Ok(mut dtx) = dns_parse_response(&self.doh_data_buf[dir.index()]) { + dtx.id = 1; + self.dns_response_tx = Some(dtx); + unsafe { + AppLayerForceProtocolChange(flow, ALPROTO_DOH2); + } + } + } else if let Ok(mut dtx) = dns_parse_request(&self.doh_data_buf[dir.index()]) { + dtx.id = 1; + self.dns_request_tx = Some(dtx); + unsafe { + AppLayerForceProtocolChange(flow, ALPROTO_DOH2); + } + } + } + } } impl Drop for HTTP2Transaction { @@ -1165,20 +1185,7 @@ impl HTTP2State { flow, ) { Ok(_) => { - if !tx_same.doh_response_buf.is_empty() && over { - if let Ok(mut dtx) = - dns_parse_response(&tx_same.doh_response_buf) - { - dtx.id = 1; - tx_same.dns_response_tx = Some(dtx); - unsafe { - AppLayerForceProtocolChange( - flow, - ALPROTO_DOH2, - ); - } - } - } + tx_same.handle_dns_data(over, dir, flow); } _ => { self.set_event(HTTP2Event::FailedDecompression);