]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
dns: handle mid stream pickup on response packet
authorJason Ish <ish@unx.ca>
Tue, 2 Apr 2019 19:18:53 +0000 (13:18 -0600)
committerVictor Julien <victor@inliniac.net>
Mon, 9 Sep 2019 17:11:12 +0000 (19:11 +0200)
Related Redmine issue:
https://redmine.openinfosecfoundation.org/issues/2146

rust/src/dns/dns.rs
src/app-layer-dns-tcp-rust.c
src/app-layer-dns-udp-rust.c

index 777cb1079376685aa550d660faec33afd8417c2e..c9b688f1ffb877cfc9bc213bdbe30555e3291443 100644 (file)
@@ -431,7 +431,8 @@ impl DNSState {
     /// Returns the number of messages parsed.
     pub fn parse_request_tcp(&mut self, input: &[u8]) -> i8 {
         if self.gap {
-            if probe_tcp(input) {
+            let (is_dns, _) = probe_tcp(input);
+            if is_dns {
                 self.gap = false;
             } else {
                 return 0
@@ -471,7 +472,8 @@ impl DNSState {
     /// Returns the number of messages parsed.
     pub fn parse_response_tcp(&mut self, input: &[u8]) -> i8 {
         if self.gap {
-            if probe_tcp(input) {
+            let (is_dns, _) = probe_tcp(input);
+            if is_dns {
                 self.gap = false;
             } else {
                 return 0
@@ -519,19 +521,25 @@ impl DNSState {
 }
 
 /// Probe input to see if it looks like DNS.
-fn probe(input: &[u8]) -> bool {
-    parser::dns_parse_request(input).is_ok()
+fn probe(input: &[u8]) -> (bool, bool) {
+    match parser::dns_parse_request(input) {
+        Ok((_, request)) => {
+            let is_request = request.header.flags & 0x8000 == 0;
+            return (true, is_request);
+        },
+        Err(_) => (false, false),
+    }
 }
 
 /// Probe TCP input to see if it looks like DNS.
-pub fn probe_tcp(input: &[u8]) -> bool {
+pub fn probe_tcp(input: &[u8]) -> (bool, bool) {
     match nom::be_u16(input) {
         Ok((rem, _)) => {
             return probe(rem);
         },
         _ => {}
     }
-    return false;
+    return (false, false);
 }
 
 /// Returns *mut DNSState
@@ -813,27 +821,46 @@ pub extern "C" fn rs_dns_tx_get_query_rrtype(tx: &mut DNSTransaction,
 }
 
 #[no_mangle]
-pub extern "C" fn rs_dns_probe(input: *const u8, len: u32)
+pub extern "C" fn rs_dns_probe(input: *const u8, len: u32, rdir: *mut u8)
                                -> u8
 {
     let slice: &[u8] = unsafe {
         std::slice::from_raw_parts(input as *mut u8, len as usize)
     };
-    if probe(slice) {
+    let (is_dns, is_request) = probe(slice);
+    if is_dns {
+        let dir = if is_request {
+            core::STREAM_TOSERVER
+        } else {
+            core::STREAM_TOCLIENT
+        };
+        unsafe { *rdir = dir };
+
         return 1;
     }
     return 0;
 }
 
 #[no_mangle]
-pub extern "C" fn rs_dns_probe_tcp(input: *const u8,
-                                   len: u32)
+pub extern "C" fn rs_dns_probe_tcp(direction: u8,
+                                   input: *const u8,
+                                   len: u32,
+                                   rdir: *mut u8)
                                    -> u8
 {
     let slice: &[u8] = unsafe {
         std::slice::from_raw_parts(input as *mut u8, len as usize)
     };
-    if probe_tcp(slice) {
+    let (is_dns, is_request) = probe_tcp(slice);
+    if is_dns {
+        let dir = if is_request {
+            core::STREAM_TOSERVER
+        } else {
+            core::STREAM_TOCLIENT
+        };
+        if direction & (core::STREAM_TOSERVER|core::STREAM_TOCLIENT) != dir {
+            unsafe { *rdir = dir };
+        }
         return 1;
     }
     return 0;
index c58096220c10d5c6ac85c0b8c77da6453a22cd0f..a6d3efb3a335735dd3e2cfcffcfc7374ee10cb93 100644 (file)
@@ -61,7 +61,7 @@ static uint16_t RustDNSTCPProbe(Flow *f, uint8_t direction,
     }
 
     // Validate and return ALPROTO_FAILED if needed.
-    if (!rs_dns_probe_tcp(input, len)) {
+    if (!rs_dns_probe_tcp(direction, input, len, rdir)) {
         return ALPROTO_FAILED;
     }
 
@@ -126,7 +126,7 @@ void RegisterRustDNSTCPParsers(void)
         if (RunmodeIsUnittests()) {
             AppLayerProtoDetectPPRegister(IPPROTO_TCP, "53", ALPROTO_DNS, 0,
                     sizeof(DNSHeader) + 2, STREAM_TOSERVER, RustDNSTCPProbe,
-                    NULL);
+                    RustDNSTCPProbe);
         } else {
             int have_cfg = AppLayerProtoDetectPPParseConfPorts("tcp",
                     IPPROTO_TCP, proto_name, ALPROTO_DNS, 0,
index cd9e84dfb50e97e06f359cfc94d1f5aaea4edc55..734d410a05a3babe9715736ad738d1fd5b5f3db2 100644 (file)
@@ -58,7 +58,7 @@ static uint16_t DNSUDPProbe(Flow *f, uint8_t direction,
     }
 
     // Validate and return ALPROTO_FAILED if needed.
-    if (!rs_dns_probe(input, len)) {
+    if (!rs_dns_probe(input, len, rdir)) {
         return ALPROTO_FAILED;
     }
 
@@ -132,11 +132,11 @@ void RegisterRustDNSUDPParsers(void)
         if (RunmodeIsUnittests()) {
             AppLayerProtoDetectPPRegister(IPPROTO_UDP, "53", ALPROTO_DNS, 0,
                     sizeof(DNSHeader), STREAM_TOSERVER, DNSUDPProbe,
-                    NULL);
+                    DNSUDPProbe);
         } else {
             int have_cfg = AppLayerProtoDetectPPParseConfPorts("udp",
                     IPPROTO_UDP, proto_name, ALPROTO_DNS, 0, sizeof(DNSHeader),
-                    DNSUDPProbe, NULL);
+                    DNSUDPProbe, DNSUDPProbe);
 
             /* If no config, enable on port 53. */
             if (!have_cfg) {
@@ -146,7 +146,7 @@ void RegisterRustDNSUDPParsers(void)
 #endif
                 AppLayerProtoDetectPPRegister(IPPROTO_UDP, "53", ALPROTO_DNS,
                         0, sizeof(DNSHeader), STREAM_TOSERVER,
-                        DNSUDPProbe, NULL);
+                        DNSUDPProbe, DNSUDPProbe);
             }
         }
     } else {