dns: add dns.rrtype keyword

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
pull/10536/head
Hadiqa Alamdar Bukhari 2 years ago committed by Victor Julien
parent 5f0853599b
commit 4b81851097

@ -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
---------

@ -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,
));
}
}

@ -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 \

@ -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");
}

@ -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__ */

@ -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();

@ -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,

Loading…
Cancel
Save