detect/dns: support string for dns.rcode

Ticket: 6723
pull/13053/head
Philippe Antoine 2 years ago committed by Victor Julien
parent 9814b698c8
commit 44a6f7f8ca

@ -47,6 +47,7 @@ dns.rcode
This keyword matches on the **rcode** field found in the DNS header flags. This keyword matches on the **rcode** field found in the DNS header flags.
dns.rcode uses an :ref:`unsigned 8-bit integer <rules-integer-keywords>`. dns.rcode uses an :ref:`unsigned 8-bit integer <rules-integer-keywords>`.
It can also be specified by text from the enumeration.
Currently, Suricata only supports rcode values in the range [0-15], while 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 the current DNS version supports rcode values from [0-23] as specified in

@ -15,10 +15,10 @@
* 02110-1301, USA. * 02110-1301, USA.
*/ */
use super::dns::{DNSTransaction, ALPROTO_DNS}; use super::dns::{DNSRcode, DNSTransaction, ALPROTO_DNS};
use crate::detect::uint::{ use crate::detect::uint::{
detect_match_uint, DetectUintData, SCDetectU16Free, SCDetectU16Parse, SCDetectU8Free, detect_match_uint, detect_parse_uint_enum, SCDetectU16Free, SCDetectU16Parse,
SCDetectU8Parse, SCDetectU8Free, SCDetectU8Parse, DetectUintData,
}; };
use crate::detect::{ use crate::detect::{
DetectBufferSetActiveList, DetectHelperBufferRegister, DetectHelperGetMultiData, DetectBufferSetActiveList, DetectHelperBufferRegister, DetectHelperGetMultiData,
@ -27,6 +27,7 @@ use crate::detect::{
SigMatchAppendSMToList, SIGMATCH_INFO_STICKY_BUFFER, SIGMATCH_NOOPT, SigMatchAppendSMToList, SIGMATCH_INFO_STICKY_BUFFER, SIGMATCH_NOOPT,
}; };
use crate::direction::Direction; use crate::direction::Direction;
use std::ffi::CStr;
use std::os::raw::{c_int, c_void}; use std::os::raw::{c_int, c_void};
/// Perform the DNS opcode match. /// Perform the DNS opcode match.
@ -70,7 +71,7 @@ unsafe extern "C" fn dns_rcode_match(
_sig: *const c_void, ctx: *const c_void, _sig: *const c_void, ctx: *const c_void,
) -> c_int { ) -> c_int {
let tx = cast_pointer!(tx, DNSTransaction); let tx = cast_pointer!(tx, DNSTransaction);
let ctx = cast_pointer!(ctx, DetectUintData<u8>); let ctx = cast_pointer!(ctx, DetectUintData<u16>);
let header_flags = if flags & Direction::ToServer as u8 != 0 { let header_flags = if flags & Direction::ToServer as u8 != 0 {
if let Some(request) = &tx.request { if let Some(request) = &tx.request {
request.header.flags request.header.flags
@ -83,7 +84,7 @@ unsafe extern "C" fn dns_rcode_match(
return 0; return 0;
}; };
let rcode = (header_flags & 0xf) as u8; let rcode = header_flags & 0xf;
if detect_match_uint(ctx, rcode) { if detect_match_uint(ctx, rcode) {
return 1; return 1;
@ -153,13 +154,24 @@ unsafe extern "C" fn dns_opcode_free(_de: *mut c_void, ctx: *mut c_void) {
SCDetectU8Free(ctx); SCDetectU8Free(ctx);
} }
unsafe extern "C" fn dns_rcode_parse(ustr: *const std::os::raw::c_char) -> *mut DetectUintData<u8> {
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::<u16, DNSRcode>(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( unsafe extern "C" fn dns_rcode_setup(
de: *mut c_void, s: *mut c_void, raw: *const libc::c_char, de: *mut c_void, s: *mut c_void, raw: *const libc::c_char,
) -> c_int { ) -> c_int {
if DetectSignatureSetAppProto(s, ALPROTO_DNS) != 0 { if DetectSignatureSetAppProto(s, ALPROTO_DNS) != 0 {
return -1; return -1;
} }
let ctx = SCDetectU8Parse(raw) as *mut c_void; let ctx = dns_rcode_parse(raw) as *mut c_void;
if ctx.is_null() { if ctx.is_null() {
return -1; 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) { unsafe extern "C" fn dns_rcode_free(_de: *mut c_void, ctx: *mut c_void) {
// Just unbox... // Just unbox...
let ctx = cast_pointer!(ctx, DetectUintData<u8>); let ctx = cast_pointer!(ctx, DetectUintData<u16>);
SCDetectU8Free(ctx); SCDetectU16Free(ctx);
} }
unsafe extern "C" fn dns_rrtype_setup( unsafe extern "C" fn dns_rrtype_setup(
@ -535,7 +547,7 @@ mod test {
#[test] #[test]
fn parse_rcode_good() { fn parse_rcode_good() {
assert_eq!( assert_eq!(
detect_parse_uint::<u8>("1").unwrap().1, detect_parse_uint_enum::<u16, DNSRcode>("1").unwrap(),
DetectUintData { DetectUintData {
mode: DetectUintMode::DetectUintModeEqual, mode: DetectUintMode::DetectUintModeEqual,
arg1: 1, arg1: 1,
@ -543,7 +555,7 @@ mod test {
} }
); );
assert_eq!( assert_eq!(
detect_parse_uint::<u8>("123").unwrap().1, detect_parse_uint_enum::<u16, DNSRcode>("123").unwrap(),
DetectUintData { DetectUintData {
mode: DetectUintMode::DetectUintModeEqual, mode: DetectUintMode::DetectUintModeEqual,
arg1: 123, arg1: 123,
@ -551,7 +563,7 @@ mod test {
} }
); );
assert_eq!( assert_eq!(
detect_parse_uint::<u8>("!123").unwrap().1, detect_parse_uint_enum::<u16, DNSRcode>("!123").unwrap(),
DetectUintData { DetectUintData {
mode: DetectUintMode::DetectUintModeNe, mode: DetectUintMode::DetectUintModeNe,
arg1: 123, arg1: 123,
@ -559,17 +571,25 @@ mod test {
} }
); );
assert_eq!( assert_eq!(
detect_parse_uint::<u8>("7-15").unwrap().1, detect_parse_uint_enum::<u16, DNSRcode>("7-15").unwrap(),
DetectUintData { DetectUintData {
mode: DetectUintMode::DetectUintModeRange, mode: DetectUintMode::DetectUintModeRange,
arg1: 7, arg1: 7,
arg2: 15, arg2: 15,
} }
); );
assert!(detect_parse_uint::<u16>("").is_err()); assert_eq!(
assert!(detect_parse_uint::<u16>("!").is_err()); detect_parse_uint_enum::<u16, DNSRcode>("nxdomain").unwrap(),
assert!(detect_parse_uint::<u16>("! ").is_err()); DetectUintData {
assert!(detect_parse_uint::<u16>("!asdf").is_err()); mode: DetectUintMode::DetectUintModeEqual,
arg1: DNSRcode::NXDOMAIN as u16,
arg2: 0,
}
);
assert!(detect_parse_uint_enum::<u16, DNSRcode>("").is_none());
assert!(detect_parse_uint_enum::<u16, DNSRcode>("!").is_none());
assert!(detect_parse_uint_enum::<u16, DNSRcode>("! ").is_none());
assert!(detect_parse_uint_enum::<u16, DNSRcode>("!asdf").is_none());
} }
#[test] #[test]

@ -94,27 +94,30 @@ pub const DNS_RECORD_TYPE_ANY: u16 = 255;
pub const DNS_RECORD_TYPE_URI: u16 = 256; pub const DNS_RECORD_TYPE_URI: u16 = 256;
/// DNS error codes. /// DNS error codes.
pub const DNS_RCODE_NOERROR: u16 = 0; #[derive(Clone, Debug, EnumStringU16)]
pub const DNS_RCODE_FORMERR: u16 = 1; pub enum DNSRcode {
pub const DNS_RCODE_SERVFAIL: u16 = 2; NOERROR = 0,
pub const DNS_RCODE_NXDOMAIN: u16 = 3; FORMERR = 1,
pub const DNS_RCODE_NOTIMP: u16 = 4; SERVFAIL = 2,
pub const DNS_RCODE_REFUSED: u16 = 5; NXDOMAIN = 3,
pub const DNS_RCODE_YXDOMAIN: u16 = 6; NOTIMP = 4,
pub const DNS_RCODE_YXRRSET: u16 = 7; REFUSED = 5,
pub const DNS_RCODE_NXRRSET: u16 = 8; YXDOMAIN = 6,
pub const DNS_RCODE_NOTAUTH: u16 = 9; YXRRSET = 7,
pub const DNS_RCODE_NOTZONE: u16 = 10; NXRRSET = 8,
// Support for OPT RR from RFC6891 will be needed to NOTAUTH = 9,
// parse RCODE values over 15 NOTZONE = 10,
pub const DNS_RCODE_BADVERS: u16 = 16; // Support for OPT RR from RFC6891 will be needed to
//also pub const DNS_RCODE_BADSIG: u16 = 16; // parse RCODE values over 15
pub const DNS_RCODE_BADKEY: u16 = 17; BADVERS = 16,
pub const DNS_RCODE_BADTIME: u16 = 18; //also pub const DNS_RCODE_BADSIG: u16 = 16;
pub const DNS_RCODE_BADMODE: u16 = 19; BADKEY = 17,
pub const DNS_RCODE_BADNAME: u16 = 20; BADTIME = 18,
pub const DNS_RCODE_BADALG: u16 = 21; BADMODE = 19,
pub const DNS_RCODE_BADTRUNC: u16 = 22; BADNAME = 20,
BADALG = 21,
BADTRUNC = 22,
}
pub(super) static mut ALPROTO_DNS: AppProto = ALPROTO_UNKNOWN; pub(super) static mut ALPROTO_DNS: AppProto = ALPROTO_UNKNOWN;

@ -19,6 +19,7 @@ use std;
use std::collections::HashMap; use std::collections::HashMap;
use std::string::String; use std::string::String;
use crate::detect::EnumString;
use crate::dns::dns::*; use crate::dns::dns::*;
use crate::jsonbuilder::{JsonBuilder, JsonError}; 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 { pub fn dns_rcode_string(flags: u16) -> String {
match flags & 0x000f { if flags & 0x000f == DNSRcode::BADVERS as u16 {
DNS_RCODE_NOERROR => "NOERROR", return "BADVERS/BADSIG".to_string();
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();
}
} }
.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. /// Format bytes as an IP address string.

Loading…
Cancel
Save