From: Philippe Antoine Date: Sun, 26 Jan 2025 14:35:24 +0000 (+0100) Subject: detect/dns: support string for dns.rcode X-Git-Tag: suricata-8.0.0-rc1~446 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=44a6f7f8ca31ac3ef08f6bbe64fdd8bcd48549ad;p=thirdparty%2Fsuricata.git detect/dns: support string for dns.rcode Ticket: 6723 --- diff --git a/doc/userguide/rules/dns-keywords.rst b/doc/userguide/rules/dns-keywords.rst index f7dcc19410..e343517742 100644 --- a/doc/userguide/rules/dns-keywords.rst +++ b/doc/userguide/rules/dns-keywords.rst @@ -47,6 +47,7 @@ dns.rcode This keyword matches on the **rcode** field found in the DNS header flags. dns.rcode uses an :ref:`unsigned 8-bit integer `. +It can also be specified by text from the enumeration. Currently, Suricata only supports rcode values in the range [0-15], while the current DNS version supports rcode values from [0-23] as specified in diff --git a/rust/src/dns/detect.rs b/rust/src/dns/detect.rs index 0c07296f4e..bfbc9b95df 100644 --- a/rust/src/dns/detect.rs +++ b/rust/src/dns/detect.rs @@ -15,10 +15,10 @@ * 02110-1301, USA. */ -use super::dns::{DNSTransaction, ALPROTO_DNS}; +use super::dns::{DNSRcode, DNSTransaction, ALPROTO_DNS}; use crate::detect::uint::{ - detect_match_uint, DetectUintData, SCDetectU16Free, SCDetectU16Parse, SCDetectU8Free, - SCDetectU8Parse, + detect_match_uint, detect_parse_uint_enum, SCDetectU16Free, SCDetectU16Parse, + SCDetectU8Free, SCDetectU8Parse, DetectUintData, }; use crate::detect::{ DetectBufferSetActiveList, DetectHelperBufferRegister, DetectHelperGetMultiData, @@ -27,6 +27,7 @@ use crate::detect::{ SigMatchAppendSMToList, SIGMATCH_INFO_STICKY_BUFFER, SIGMATCH_NOOPT, }; use crate::direction::Direction; +use std::ffi::CStr; use std::os::raw::{c_int, c_void}; /// Perform the DNS opcode match. @@ -70,7 +71,7 @@ unsafe extern "C" fn dns_rcode_match( _sig: *const c_void, ctx: *const c_void, ) -> c_int { let tx = cast_pointer!(tx, DNSTransaction); - let ctx = cast_pointer!(ctx, DetectUintData); + let ctx = cast_pointer!(ctx, DetectUintData); let header_flags = if flags & Direction::ToServer as u8 != 0 { if let Some(request) = &tx.request { request.header.flags @@ -83,7 +84,7 @@ unsafe extern "C" fn dns_rcode_match( return 0; }; - let rcode = (header_flags & 0xf) as u8; + let rcode = header_flags & 0xf; if detect_match_uint(ctx, rcode) { return 1; @@ -153,13 +154,24 @@ unsafe extern "C" fn dns_opcode_free(_de: *mut c_void, ctx: *mut c_void) { SCDetectU8Free(ctx); } +unsafe extern "C" fn dns_rcode_parse(ustr: *const std::os::raw::c_char) -> *mut DetectUintData { + let ft_name: &CStr = CStr::from_ptr(ustr); //unsafe + if let Ok(s) = ft_name.to_str() { + if let Some(ctx) = detect_parse_uint_enum::(s) { + let boxed = Box::new(ctx); + return Box::into_raw(boxed) as *mut _; + } + } + return std::ptr::null_mut(); +} + unsafe extern "C" fn dns_rcode_setup( de: *mut c_void, s: *mut c_void, raw: *const libc::c_char, ) -> c_int { if DetectSignatureSetAppProto(s, ALPROTO_DNS) != 0 { return -1; } - let ctx = SCDetectU8Parse(raw) as *mut c_void; + let ctx = dns_rcode_parse(raw) as *mut c_void; if ctx.is_null() { return -1; } @@ -172,8 +184,8 @@ unsafe extern "C" fn dns_rcode_setup( unsafe extern "C" fn dns_rcode_free(_de: *mut c_void, ctx: *mut c_void) { // Just unbox... - let ctx = cast_pointer!(ctx, DetectUintData); - SCDetectU8Free(ctx); + let ctx = cast_pointer!(ctx, DetectUintData); + SCDetectU16Free(ctx); } unsafe extern "C" fn dns_rrtype_setup( @@ -535,7 +547,7 @@ mod test { #[test] fn parse_rcode_good() { assert_eq!( - detect_parse_uint::("1").unwrap().1, + detect_parse_uint_enum::("1").unwrap(), DetectUintData { mode: DetectUintMode::DetectUintModeEqual, arg1: 1, @@ -543,7 +555,7 @@ mod test { } ); assert_eq!( - detect_parse_uint::("123").unwrap().1, + detect_parse_uint_enum::("123").unwrap(), DetectUintData { mode: DetectUintMode::DetectUintModeEqual, arg1: 123, @@ -551,7 +563,7 @@ mod test { } ); assert_eq!( - detect_parse_uint::("!123").unwrap().1, + detect_parse_uint_enum::("!123").unwrap(), DetectUintData { mode: DetectUintMode::DetectUintModeNe, arg1: 123, @@ -559,17 +571,25 @@ mod test { } ); assert_eq!( - detect_parse_uint::("7-15").unwrap().1, + detect_parse_uint_enum::("7-15").unwrap(), DetectUintData { mode: DetectUintMode::DetectUintModeRange, arg1: 7, arg2: 15, } ); - assert!(detect_parse_uint::("").is_err()); - assert!(detect_parse_uint::("!").is_err()); - assert!(detect_parse_uint::("! ").is_err()); - assert!(detect_parse_uint::("!asdf").is_err()); + assert_eq!( + detect_parse_uint_enum::("nxdomain").unwrap(), + DetectUintData { + mode: DetectUintMode::DetectUintModeEqual, + arg1: DNSRcode::NXDOMAIN as u16, + arg2: 0, + } + ); + assert!(detect_parse_uint_enum::("").is_none()); + assert!(detect_parse_uint_enum::("!").is_none()); + assert!(detect_parse_uint_enum::("! ").is_none()); + assert!(detect_parse_uint_enum::("!asdf").is_none()); } #[test] diff --git a/rust/src/dns/dns.rs b/rust/src/dns/dns.rs index 05603bd2a9..ab10bd15a7 100644 --- a/rust/src/dns/dns.rs +++ b/rust/src/dns/dns.rs @@ -94,27 +94,30 @@ pub const DNS_RECORD_TYPE_ANY: u16 = 255; pub const DNS_RECORD_TYPE_URI: u16 = 256; /// DNS error codes. -pub const DNS_RCODE_NOERROR: u16 = 0; -pub const DNS_RCODE_FORMERR: u16 = 1; -pub const DNS_RCODE_SERVFAIL: u16 = 2; -pub const DNS_RCODE_NXDOMAIN: u16 = 3; -pub const DNS_RCODE_NOTIMP: u16 = 4; -pub const DNS_RCODE_REFUSED: u16 = 5; -pub const DNS_RCODE_YXDOMAIN: u16 = 6; -pub const DNS_RCODE_YXRRSET: u16 = 7; -pub const DNS_RCODE_NXRRSET: u16 = 8; -pub const DNS_RCODE_NOTAUTH: u16 = 9; -pub const DNS_RCODE_NOTZONE: u16 = 10; -// Support for OPT RR from RFC6891 will be needed to -// parse RCODE values over 15 -pub const DNS_RCODE_BADVERS: u16 = 16; -//also pub const DNS_RCODE_BADSIG: u16 = 16; -pub const DNS_RCODE_BADKEY: u16 = 17; -pub const DNS_RCODE_BADTIME: u16 = 18; -pub const DNS_RCODE_BADMODE: u16 = 19; -pub const DNS_RCODE_BADNAME: u16 = 20; -pub const DNS_RCODE_BADALG: u16 = 21; -pub const DNS_RCODE_BADTRUNC: u16 = 22; +#[derive(Clone, Debug, EnumStringU16)] +pub enum DNSRcode { + NOERROR = 0, + FORMERR = 1, + SERVFAIL = 2, + NXDOMAIN = 3, + NOTIMP = 4, + REFUSED = 5, + YXDOMAIN = 6, + YXRRSET = 7, + NXRRSET = 8, + NOTAUTH = 9, + NOTZONE = 10, + // Support for OPT RR from RFC6891 will be needed to + // parse RCODE values over 15 + BADVERS = 16, + //also pub const DNS_RCODE_BADSIG: u16 = 16; + BADKEY = 17, + BADTIME = 18, + BADMODE = 19, + BADNAME = 20, + BADALG = 21, + BADTRUNC = 22, +} pub(super) static mut ALPROTO_DNS: AppProto = ALPROTO_UNKNOWN; diff --git a/rust/src/dns/log.rs b/rust/src/dns/log.rs index 7003e70c19..6647ac88e6 100644 --- a/rust/src/dns/log.rs +++ b/rust/src/dns/log.rs @@ -19,6 +19,7 @@ use std; use std::collections::HashMap; use std::string::String; +use crate::detect::EnumString; use crate::dns::dns::*; use crate::jsonbuilder::{JsonBuilder, JsonError}; @@ -346,30 +347,13 @@ pub fn dns_rrtype_string(rrtype: u16) -> String { } pub fn dns_rcode_string(flags: u16) -> String { - match flags & 0x000f { - DNS_RCODE_NOERROR => "NOERROR", - DNS_RCODE_FORMERR => "FORMERR", - DNS_RCODE_SERVFAIL => "SERVFAIL", - DNS_RCODE_NXDOMAIN => "NXDOMAIN", - DNS_RCODE_NOTIMP => "NOTIMP", - DNS_RCODE_REFUSED => "REFUSED", - DNS_RCODE_YXDOMAIN => "YXDOMAIN", - DNS_RCODE_YXRRSET => "YXRRSET", - DNS_RCODE_NXRRSET => "NXRRSET", - DNS_RCODE_NOTAUTH => "NOTAUTH", - DNS_RCODE_NOTZONE => "NOTZONE", - DNS_RCODE_BADVERS => "BADVERS/BADSIG", - DNS_RCODE_BADKEY => "BADKEY", - DNS_RCODE_BADTIME => "BADTIME", - DNS_RCODE_BADMODE => "BADMODE", - DNS_RCODE_BADNAME => "BADNAME", - DNS_RCODE_BADALG => "BADALG", - DNS_RCODE_BADTRUNC => "BADTRUNC", - _ => { - return (flags & 0x000f).to_string(); - } + if flags & 0x000f == DNSRcode::BADVERS as u16 { + return "BADVERS/BADSIG".to_string(); } - .to_string() + if let Some(rc) = DNSRcode::from_u(flags & 0x000f) { + return rc.to_str().to_uppercase(); + } + return (flags & 0x000f).to_string(); } /// Format bytes as an IP address string.