]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
dns: add dns.rrtype keyword
authorHadiqa Alamdar Bukhari <hadiqaalamdar@gmail.com>
Wed, 31 Jan 2024 12:56:33 +0000 (17:56 +0500)
committerVictor Julien <victor@inliniac.net>
Thu, 29 Feb 2024 15:47:11 +0000 (16:47 +0100)
It matches the rrtype field in DNS
It's an unsigned integer match
valid ranges = [0-65535]
Does not support prefilter
Supports flow in both directions
Feature #6666

doc/userguide/rules/dns-keywords.rst
rust/src/dns/detect.rs
src/Makefile.am
src/detect-dns-rrtype.c [new file with mode: 0644]
src/detect-dns-rrtype.h [new file with mode: 0644]
src/detect-engine-register.c
src/detect-engine-register.h

index 005164dfd159f68daae20e0c70817da0473117ec..bb232e39f09341380e85a7b73dd00ab83ec16b63 100644 (file)
@@ -57,6 +57,31 @@ Match on DNS requests where the **opcode** is not between 7 and 15:
 
   dns.opcode:!7-15;
 
+dns.rrtype
+----------
+
+This keyword matches on the **rrtype** (integer) found in the DNS message.
+
+dns.rrtype uses an :ref:`unsigned 16-bit integer <rules-integer-keywords>`.
+
+Syntax
+~~~~~~
+
+::
+
+   dns.rrtype:[!]<number>
+
+Examples
+~~~~~~~~
+
+Match on DNS requests and responses with **rrtype** 4::
+
+  dns.rrtype:4;
+
+Match on DNS requests and responses where the **rrtype** is NOT 0::
+
+  dns.rrtype:!0;
+
 dns.query
 ---------
 
index 452d4e8380e11dc32f41ec143ab209a303241e3b..4e7819513f97d8d0a8a7bc65dd6d69dd3a750811 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2019 Open Information Security Foundation
+/* Copyright (C) 2019-2024 Open Information Security Foundation
  *
  * You can copy, redistribute or modify this Program under the terms of
  * the GNU General Public License version 2 as published by the Free
@@ -50,6 +50,32 @@ pub extern "C" fn rs_dns_opcode_match(
     return 0;
 }
 
+/// Perform the DNS rrtype match.
+/// 1 will be returned on match, otherwise 0 will be returned.
+#[no_mangle]
+pub extern "C" fn rs_dns_rrtype_match(
+    tx: &mut DNSTransaction, detect: &mut DetectUintData<u16>, flags: u8,
+) -> u16 {
+    if flags & Direction::ToServer as u8 != 0 {
+        if let Some(request) = &tx.request {
+            for i in 0..request.queries.len() {
+                if detect_match_uint(detect, request.queries[i].rrtype) {
+                    return 1;
+                }
+            }
+        }
+    } else if flags & Direction::ToClient as u8 != 0 {
+        if let Some(response) = &tx.response {
+            for i in 0..response.answers.len() {
+                if detect_match_uint(detect, response.answers[i].rrtype) {
+                    return 1;
+                }
+            }
+        }
+    }
+    return 0;
+}
+
 #[cfg(test)]
 mod test {
     use super::*;
@@ -125,4 +151,83 @@ mod test {
             ((0b0010_0000_0000_0000 >> 11) & 0xf) as u8,
         ));
     }
+
+    #[test]
+    fn parse_rrtype_good() {
+        assert_eq!(
+            detect_parse_uint::<u16>("1").unwrap().1,
+            DetectUintData {
+                mode: DetectUintMode::DetectUintModeEqual,
+                arg1: 1,
+                arg2: 0,
+            }
+        );
+        assert_eq!(
+            detect_parse_uint::<u16>("123").unwrap().1,
+            DetectUintData {
+                mode: DetectUintMode::DetectUintModeEqual,
+                arg1: 123,
+                arg2: 0,
+            }
+        );
+        assert_eq!(
+            detect_parse_uint::<u16>("!123").unwrap().1,
+            DetectUintData {
+                mode: DetectUintMode::DetectUintModeNe,
+                arg1: 123,
+                arg2: 0,
+            }
+        );
+        assert_eq!(
+            detect_parse_uint::<u16>("7-15").unwrap().1,
+            DetectUintData {
+                mode: DetectUintMode::DetectUintModeRange,
+                arg1: 7,
+                arg2: 15,
+            }
+        );
+        assert!(detect_parse_uint::<u16>("").is_err());
+        assert!(detect_parse_uint::<u16>("!").is_err());
+        assert!(detect_parse_uint::<u16>("!   ").is_err());
+        assert!(detect_parse_uint::<u16>("!asdf").is_err());
+    }
+
+    #[test]
+    fn test_match_rrtype() {
+        assert!(detect_match_uint(
+            &DetectUintData {
+                mode: DetectUintMode::DetectUintModeEqual,
+                arg1: 0,
+                arg2: 0,
+            },
+            0b0000_0000_0000_0000,
+        ));
+
+        assert!(!detect_match_uint(
+            &DetectUintData {
+                mode: DetectUintMode::DetectUintModeNe,
+                arg1: 0,
+                arg2: 0,
+            },
+            0b0000_0000_0000_0000,
+        ));
+
+        assert!(detect_match_uint(
+            &DetectUintData {
+                mode: DetectUintMode::DetectUintModeEqual,
+                arg1: 4,
+                arg2: 0,
+            },
+            4u16,
+        ));
+
+        assert!(!detect_match_uint(
+            &DetectUintData {
+                mode: DetectUintMode::DetectUintModeNe,
+                arg1: 4,
+                arg2: 0,
+            },
+            4u16,
+        ));
+    }
 }
index 661959505476b0d8d5969ec22ad6352ab8f43d9e..24f1a9781e21f42139c7fb7609c350154ccb8339 100755 (executable)
@@ -121,6 +121,7 @@ noinst_HEADERS = \
        detect-dnp3.h \
        detect-dns-answer-name.h \
        detect-dns-opcode.h \
+       detect-dns-rrtype.h \
        detect-dns-query.h \
        detect-dns-query-name.h \
        detect-dsize.h \
@@ -741,6 +742,7 @@ libsuricata_c_a_SOURCES = \
        detect-dnp3.c \
        detect-dns-answer-name.c \
        detect-dns-opcode.c \
+       detect-dns-rrtype.c \
        detect-dns-query.c \
        detect-dns-query-name.c \
        detect-dsize.c \
diff --git a/src/detect-dns-rrtype.c b/src/detect-dns-rrtype.c
new file mode 100644 (file)
index 0000000..6145817
--- /dev/null
@@ -0,0 +1,85 @@
+/* Copyright (C) 2024 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "suricata-common.h"
+
+#include "detect-parse.h"
+#include "detect-engine.h"
+#include "detect-dns-rrtype.h"
+#include "rust.h"
+#include "detect-engine-uint.h"
+
+static int dns_rrtype_list_id = 0;
+
+static void DetectDnsRrtypeFree(DetectEngineCtx *, void *ptr);
+
+static int DetectDnsRrtypeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str)
+{
+    SCEnter();
+
+    if (DetectSignatureSetAppProto(s, ALPROTO_DNS) != 0) {
+        SCReturnInt(-1);
+    }
+
+    void *detect = DetectU16Parse(str);
+    if (detect == NULL) {
+        SCLogError("failed to parse dns.rrtype: %s", str);
+        SCReturnInt(-1);
+    }
+
+    if (SigMatchAppendSMToList(de_ctx, s, DETECT_AL_DNS_RRTYPE, (SigMatchCtx *)detect,
+                dns_rrtype_list_id) == NULL) {
+        DetectDnsRrtypeFree(de_ctx, detect);
+        SCReturnInt(-1);
+    }
+
+    SCReturnInt(0);
+}
+
+static void DetectDnsRrtypeFree(DetectEngineCtx *de_ctx, void *ptr)
+{
+    SCEnter();
+    if (ptr != NULL) {
+        rs_detect_u16_free(ptr);
+    }
+    SCReturn;
+}
+
+static int DetectDnsRrtypeMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state,
+        void *txv, const Signature *s, const SigMatchCtx *ctx)
+{
+    return rs_dns_rrtype_match(txv, (void *)ctx, flags);
+}
+
+void DetectDnsRrtypeRegister(void)
+{
+    sigmatch_table[DETECT_AL_DNS_RRTYPE].name = "dns.rrtype";
+    sigmatch_table[DETECT_AL_DNS_RRTYPE].desc = "Match the DNS rrtype in message body.";
+    sigmatch_table[DETECT_AL_DNS_RRTYPE].url = "/rules/dns-keywords.html#dns-rrtype";
+    sigmatch_table[DETECT_AL_DNS_RRTYPE].Setup = DetectDnsRrtypeSetup;
+    sigmatch_table[DETECT_AL_DNS_RRTYPE].Free = DetectDnsRrtypeFree;
+    sigmatch_table[DETECT_AL_DNS_RRTYPE].Match = NULL;
+    sigmatch_table[DETECT_AL_DNS_RRTYPE].AppLayerTxMatch = DetectDnsRrtypeMatch;
+
+    DetectAppLayerInspectEngineRegister(
+            "dns.rrtype", ALPROTO_DNS, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL);
+
+    DetectAppLayerInspectEngineRegister(
+            "dns.rrtype", ALPROTO_DNS, SIG_FLAG_TOCLIENT, 0, DetectEngineInspectGenericList, NULL);
+
+    dns_rrtype_list_id = DetectBufferTypeGetByName("dns.rrtype");
+}
\ No newline at end of file
diff --git a/src/detect-dns-rrtype.h b/src/detect-dns-rrtype.h
new file mode 100644 (file)
index 0000000..962364f
--- /dev/null
@@ -0,0 +1,23 @@
+/* Copyright (C) 2024 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef __DETECT_DNS_RRTYPE_H__
+#define __DETECT_DNS_RRTYPE_H__
+
+void DetectDnsRrtypeRegister(void);
+
+#endif /* __DETECT_DNS_RRTYPE_H__ */
index 595bffcc5737507e83ea6aaf23b31da4521d0621..94fb303987f8448fca219255f2ce645edd914a6d 100644 (file)
@@ -48,6 +48,7 @@
 #include "detect-engine-payload.h"
 #include "detect-engine-dcepayload.h"
 #include "detect-dns-opcode.h"
+#include "detect-dns-rrtype.h"
 #include "detect-dns-query.h"
 #include "detect-dns-answer-name.h"
 #include "detect-dns-query-name.h"
@@ -522,6 +523,7 @@ void SigTableSetup(void)
 
     DetectDnsQueryRegister();
     DetectDnsOpcodeRegister();
+    DetectDnsRrtypeRegister();
     DetectDnsAnswerNameRegister();
     DetectDnsQueryNameRegister();
     DetectModbusRegister();
index eff9c0ed2572452e0b3cb17faf34cab6f328b332..dc64a4e91789d45c0951579a0ebb70064aab48ed 100644 (file)
@@ -230,6 +230,7 @@ enum DetectKeywordId {
 
     DETECT_AL_DNS_QUERY,
     DETECT_AL_DNS_OPCODE,
+    DETECT_AL_DNS_RRTYPE,
     DETECT_AL_DNS_ANSWER_NAME,
     DETECT_AL_DNS_QUERY_NAME,
     DETECT_AL_TLS_SNI,