detect/dns: support string for dns.rcode

Ticket: 6723
pull/13053/head
Philippe Antoine 1 year 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.
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
the current DNS version supports rcode values from [0-23] as specified in

@ -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<u8>);
let ctx = cast_pointer!(ctx, DetectUintData<u16>);
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<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(
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<u8>);
SCDetectU8Free(ctx);
let ctx = cast_pointer!(ctx, DetectUintData<u16>);
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::<u8>("1").unwrap().1,
detect_parse_uint_enum::<u16, DNSRcode>("1").unwrap(),
DetectUintData {
mode: DetectUintMode::DetectUintModeEqual,
arg1: 1,
@ -543,7 +555,7 @@ mod test {
}
);
assert_eq!(
detect_parse_uint::<u8>("123").unwrap().1,
detect_parse_uint_enum::<u16, DNSRcode>("123").unwrap(),
DetectUintData {
mode: DetectUintMode::DetectUintModeEqual,
arg1: 123,
@ -551,7 +563,7 @@ mod test {
}
);
assert_eq!(
detect_parse_uint::<u8>("!123").unwrap().1,
detect_parse_uint_enum::<u16, DNSRcode>("!123").unwrap(),
DetectUintData {
mode: DetectUintMode::DetectUintModeNe,
arg1: 123,
@ -559,17 +571,25 @@ mod test {
}
);
assert_eq!(
detect_parse_uint::<u8>("7-15").unwrap().1,
detect_parse_uint_enum::<u16, DNSRcode>("7-15").unwrap(),
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());
assert_eq!(
detect_parse_uint_enum::<u16, DNSRcode>("nxdomain").unwrap(),
DetectUintData {
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]

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

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

Loading…
Cancel
Save