diff --git a/doc/userguide/rules/dns-keywords.rst b/doc/userguide/rules/dns-keywords.rst index f729250f706e..3001b7414c7b 100644 --- a/doc/userguide/rules/dns-keywords.rst +++ b/doc/userguide/rules/dns-keywords.rst @@ -63,6 +63,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 @@ -97,6 +98,8 @@ This keyword matches on the **rrtype** (integer) found in the DNS message. dns.rrtype uses an :ref:`unsigned 16-bit integer `. +It can also be specified by text from the enumeration. + Syntax ~~~~~~ diff --git a/rust/src/detect/mod.rs b/rust/src/detect/mod.rs index c00f0dfdeb18..2d1e5c079fa4 100644 --- a/rust/src/detect/mod.rs +++ b/rust/src/detect/mod.rs @@ -32,7 +32,7 @@ pub mod tojson; pub mod vlan; use crate::core::AppProto; -use std::os::raw::{c_int, c_void}; +use std::os::raw::{c_char, c_int, c_void}; /// EnumString trait that will be implemented on enums that /// derive StringEnum. @@ -101,6 +101,7 @@ extern { ) -> *mut c_void, ) -> c_int; pub fn DetectHelperKeywordRegister(kw: *const SCSigTableElmt) -> c_int; + pub fn DetectHelperKeywordAliasRegister(kwid: c_int, alias: *const c_char); pub fn DetectHelperBufferRegister( name: *const libc::c_char, alproto: AppProto, toclient: bool, toserver: bool, ) -> c_int; diff --git a/rust/src/dns/detect.rs b/rust/src/dns/detect.rs index 2eb81c6ba376..7616dd117e37 100644 --- a/rust/src/dns/detect.rs +++ b/rust/src/dns/detect.rs @@ -15,17 +15,30 @@ * 02110-1301, USA. */ -use super::dns::DNSTransaction; +use super::dns::{DNSRcode, DNSRecordType, DNSTransaction, ALPROTO_DNS}; +use crate::detect::uint::{ + detect_match_uint, detect_parse_uint_enum, rs_detect_u16_free, rs_detect_u8_free, + rs_detect_u8_parse, DetectUintData, +}; +use crate::detect::{ + DetectBufferSetActiveList, DetectHelperBufferRegister, DetectHelperGetMultiData, + DetectHelperKeywordAliasRegister, DetectHelperKeywordRegister, + DetectHelperMultiBufferMpmRegister, DetectSignatureSetAppProto, SCSigTableElmt, + SigMatchAppendSMToList, SIGMATCH_INFO_STICKY_BUFFER, SIGMATCH_NOOPT, +}; use crate::direction::Direction; -use crate::detect::uint::{detect_match_uint, DetectUintData}; +use std::ffi::CStr; +use std::os::raw::{c_int, c_void}; /// Perform the DNS opcode match. /// /// 1 will be returned on match, otherwise 0 will be returned. -#[no_mangle] -pub extern "C" fn SCDnsDetectOpcodeMatch( - tx: &mut DNSTransaction, detect: &mut DetectUintData, flags: u8, -) -> u8 { +unsafe extern "C" fn dns_opcode_match( + _de: *mut c_void, _f: *mut c_void, flags: u8, _state: *mut c_void, tx: *mut c_void, + _sig: *const c_void, ctx: *const c_void, +) -> c_int { + let tx = cast_pointer!(tx, DNSTransaction); + 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 @@ -44,7 +57,7 @@ pub extern "C" fn SCDnsDetectOpcodeMatch( }; let opcode = ((header_flags >> 11) & 0xf) as u8; - if detect_match_uint(detect, opcode) { + if detect_match_uint(ctx, opcode) { return 1; } return 0; @@ -53,10 +66,12 @@ pub extern "C" fn SCDnsDetectOpcodeMatch( /// Perform the DNS rcode match. /// /// 1 will be returned on match, otherwise 0 will be returned. -#[no_mangle] -pub extern "C" fn SCDnsDetectRcodeMatch( - tx: &mut DNSTransaction, detect: &mut DetectUintData, flags: u8, -) -> u8 { +unsafe extern "C" fn dns_rcode_match( + _de: *mut c_void, _f: *mut c_void, flags: u8, _state: *mut c_void, tx: *mut c_void, + _sig: *const c_void, ctx: *const c_void, +) -> c_int { + let tx = cast_pointer!(tx, DNSTransaction); + 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 @@ -69,9 +84,9 @@ pub extern "C" fn SCDnsDetectRcodeMatch( return 0; }; - let rcode = (header_flags & 0xf) as u8; + let rcode = header_flags & 0xf; - if detect_match_uint(detect, rcode) { + if detect_match_uint(ctx, rcode) { return 1; } return 0; @@ -79,14 +94,17 @@ pub extern "C" fn SCDnsDetectRcodeMatch( /// Perform the DNS rrtype match. /// 1 will be returned on match, otherwise 0 will be returned. -#[no_mangle] -pub extern "C" fn SCDnsDetectRrtypeMatch( - tx: &mut DNSTransaction, detect: &mut DetectUintData, flags: u8, -) -> u16 { +unsafe extern "C" fn dns_rrtype_match( + _de: *mut c_void, _f: *mut c_void, flags: u8, _state: *mut c_void, tx: *mut c_void, + _sig: *const c_void, ctx: *const c_void, +) -> c_int { + let tx = cast_pointer!(tx, DNSTransaction); + let ctx = cast_pointer!(ctx, DetectUintData); + 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) { + if detect_match_uint(ctx, request.queries[i].rrtype) { return 1; } } @@ -94,7 +112,7 @@ pub extern "C" fn SCDnsDetectRrtypeMatch( } 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) { + if detect_match_uint(ctx, response.answers[i].rrtype) { return 1; } } @@ -103,6 +121,363 @@ pub extern "C" fn SCDnsDetectRrtypeMatch( return 0; } +static mut G_DNS_ANSWER_NAME_BUFFER_ID: c_int = 0; +static mut G_DNS_QUERY_NAME_BUFFER_ID: c_int = 0; +static mut G_DNS_QUERY_BUFFER_ID: c_int = 0; +static mut G_DNS_OPCODE_KW_ID: c_int = 0; +static mut G_DNS_OPCODE_BUFFER_ID: c_int = 0; +static mut G_DNS_RCODE_KW_ID: c_int = 0; +static mut G_DNS_RCODE_BUFFER_ID: c_int = 0; +static mut G_DNS_RRTYPE_KW_ID: c_int = 0; +static mut G_DNS_RRTYPE_BUFFER_ID: c_int = 0; + +unsafe extern "C" fn dns_opcode_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 = rs_detect_u8_parse(raw) as *mut c_void; + if ctx.is_null() { + return -1; + } + if SigMatchAppendSMToList(de, s, G_DNS_OPCODE_KW_ID, ctx, G_DNS_OPCODE_BUFFER_ID).is_null() { + dns_opcode_free(std::ptr::null_mut(), ctx); + return -1; + } + return 0; +} + +unsafe extern "C" fn dns_opcode_free(_de: *mut c_void, ctx: *mut c_void) { + // Just unbox... + let ctx = cast_pointer!(ctx, DetectUintData); + rs_detect_u8_free(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 = dns_rcode_parse(raw) as *mut c_void; + if ctx.is_null() { + return -1; + } + if SigMatchAppendSMToList(de, s, G_DNS_RCODE_KW_ID, ctx, G_DNS_RCODE_BUFFER_ID).is_null() { + dns_rcode_free(std::ptr::null_mut(), ctx); + return -1; + } + return 0; +} + +unsafe extern "C" fn dns_rcode_free(_de: *mut c_void, ctx: *mut c_void) { + // Just unbox... + let ctx = cast_pointer!(ctx, DetectUintData); + rs_detect_u16_free(ctx); +} + +unsafe extern "C" fn dns_rrtype_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_rrtype_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 = dns_rrtype_parse(raw) as *mut c_void; + if ctx.is_null() { + return -1; + } + if SigMatchAppendSMToList(de, s, G_DNS_RRTYPE_KW_ID, ctx, G_DNS_RRTYPE_BUFFER_ID).is_null() { + dns_rrtype_free(std::ptr::null_mut(), ctx); + return -1; + } + return 0; +} + +unsafe extern "C" fn dns_rrtype_free(_de: *mut c_void, ctx: *mut c_void) { + // Just unbox... + let ctx = cast_pointer!(ctx, DetectUintData); + rs_detect_u16_free(ctx); +} + +unsafe extern "C" fn dns_detect_answer_name_setup( + de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_DNS) != 0 { + return -1; + } + if DetectBufferSetActiveList(de, s, G_DNS_ANSWER_NAME_BUFFER_ID) < 0 { + return -1; + } + return 0; +} + +/// Get the DNS response answer name and index i. +unsafe extern "C" fn dns_tx_get_answer_name( + tx: *const c_void, flags: u8, i: u32, buf: *mut *const u8, len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, DNSTransaction); + let answers = if flags & Direction::ToClient as u8 != 0 { + tx.response.as_ref().map(|response| &response.answers) + } else { + tx.request.as_ref().map(|request| &request.answers) + }; + let index = i as usize; + + if let Some(answers) = answers { + if let Some(answer) = answers.get(index) { + if !answer.name.value.is_empty() { + *buf = answer.name.value.as_ptr(); + *len = answer.name.value.len() as u32; + return true; + } + } + } + + false +} + +unsafe extern "C" fn dns_answer_name_get_data_wrapper( + de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8, + tx: *const c_void, list_id: c_int, local_id: u32, +) -> *mut c_void { + return DetectHelperGetMultiData( + de, + transforms, + flow, + flow_flags, + tx, + list_id, + local_id, + dns_tx_get_answer_name, + ); +} + +unsafe extern "C" fn dns_detect_query_name_setup( + de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_DNS) != 0 { + return -1; + } + if DetectBufferSetActiveList(de, s, G_DNS_QUERY_NAME_BUFFER_ID) < 0 { + return -1; + } + return 0; +} + +/// Get the DNS response answer name and index i. +unsafe extern "C" fn dns_tx_get_query_name( + tx: *const c_void, flags: u8, i: u32, buf: *mut *const u8, len: *mut u32, +) -> bool { + let tx = cast_pointer!(tx, DNSTransaction); + let queries = if flags & Direction::ToClient as u8 != 0 { + tx.response.as_ref().map(|response| &response.queries) + } else { + tx.request.as_ref().map(|request| &request.queries) + }; + let index = i as usize; + + if let Some(queries) = queries { + if let Some(query) = queries.get(index) { + if !query.name.value.is_empty() { + *buf = query.name.value.as_ptr(); + *len = query.name.value.len() as u32; + return true; + } + } + } + + false +} + +unsafe extern "C" fn dns_tx_get_query( + tx: *const c_void, _flags: u8, i: u32, buf: *mut *const u8, len: *mut u32, +) -> bool { + return dns_tx_get_query_name(tx, Direction::ToServer as u8, i, buf, len); +} + +unsafe extern "C" fn dns_detect_query_setup( + de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + if DetectSignatureSetAppProto(s, ALPROTO_DNS) != 0 { + return -1; + } + if DetectBufferSetActiveList(de, s, G_DNS_QUERY_BUFFER_ID) < 0 { + return -1; + } + return 0; +} + +unsafe extern "C" fn dns_query_name_get_data_wrapper( + de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8, + tx: *const c_void, list_id: c_int, local_id: u32, +) -> *mut c_void { + return DetectHelperGetMultiData( + de, + transforms, + flow, + flow_flags, + tx, + list_id, + local_id, + dns_tx_get_query_name, + ); +} + +unsafe extern "C" fn dns_query_get_data_wrapper( + de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8, + tx: *const c_void, list_id: c_int, local_id: u32, +) -> *mut c_void { + return DetectHelperGetMultiData( + de, + transforms, + flow, + flow_flags, + tx, + list_id, + local_id, + dns_tx_get_query, + ); +} + +#[no_mangle] +pub unsafe extern "C" fn SCDetectDNSRegister() { + let kw = SCSigTableElmt { + name: b"dns.answer.name\0".as_ptr() as *const libc::c_char, + desc: b"DNS answer name sticky buffer\0".as_ptr() as *const libc::c_char, + url: b"/rules/dns-keywords.html#dns-answer-name\0".as_ptr() as *const libc::c_char, + Setup: dns_detect_answer_name_setup, + flags: SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER, + AppLayerTxMatch: None, + Free: None, + }; + let _g_dns_answer_name_kw_id = DetectHelperKeywordRegister(&kw); + G_DNS_ANSWER_NAME_BUFFER_ID = DetectHelperMultiBufferMpmRegister( + b"dns.answer.name\0".as_ptr() as *const libc::c_char, + b"dns answer name\0".as_ptr() as *const libc::c_char, + ALPROTO_DNS, + true, + /* Register also in the TO_SERVER direction, even though this is not + normal, it could be provided as part of a request. */ + true, + dns_answer_name_get_data_wrapper, + ); + let kw = SCSigTableElmt { + name: b"dns.opcode\0".as_ptr() as *const libc::c_char, + desc: b"Match the DNS header opcode flag.\0".as_ptr() as *const libc::c_char, + url: b"rules/dns-keywords.html#dns-opcode\0".as_ptr() as *const libc::c_char, + AppLayerTxMatch: Some(dns_opcode_match), + Setup: dns_opcode_setup, + Free: Some(dns_opcode_free), + flags: 0, + }; + G_DNS_OPCODE_KW_ID = DetectHelperKeywordRegister(&kw); + G_DNS_OPCODE_BUFFER_ID = DetectHelperBufferRegister( + b"dns.opcode\0".as_ptr() as *const libc::c_char, + ALPROTO_DNS, + true, + true, + ); + let kw = SCSigTableElmt { + name: b"dns.query.name\0".as_ptr() as *const libc::c_char, + desc: b"DNS query name sticky buffer\0".as_ptr() as *const libc::c_char, + url: b"/rules/dns-keywords.html#dns-query-name\0".as_ptr() as *const libc::c_char, + Setup: dns_detect_query_name_setup, + flags: SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER, + AppLayerTxMatch: None, + Free: None, + }; + let _g_dns_query_name_kw_id = DetectHelperKeywordRegister(&kw); + G_DNS_QUERY_NAME_BUFFER_ID = DetectHelperMultiBufferMpmRegister( + b"dns.query.name\0".as_ptr() as *const libc::c_char, + b"dns query name\0".as_ptr() as *const libc::c_char, + ALPROTO_DNS, + true, + /* Register in both directions as the query is usually echoed back + in the response. */ + true, + dns_query_name_get_data_wrapper, + ); + let kw = SCSigTableElmt { + name: b"dns.rcode\0".as_ptr() as *const libc::c_char, + desc: b"Match the DNS header rcode flag.\0".as_ptr() as *const libc::c_char, + url: b"rules/dns-keywords.html#dns-rcode\0".as_ptr() as *const libc::c_char, + AppLayerTxMatch: Some(dns_rcode_match), + Setup: dns_rcode_setup, + Free: Some(dns_rcode_free), + flags: 0, + }; + G_DNS_RCODE_KW_ID = DetectHelperKeywordRegister(&kw); + G_DNS_RCODE_BUFFER_ID = DetectHelperBufferRegister( + b"dns.rcode\0".as_ptr() as *const libc::c_char, + ALPROTO_DNS, + true, + true, + ); + let kw = SCSigTableElmt { + name: b"dns.rrtype\0".as_ptr() as *const libc::c_char, + desc: b"Match the DNS rrtype in message body.\0".as_ptr() as *const libc::c_char, + url: b"rules/dns-keywords.html#dns-rrtype\0".as_ptr() as *const libc::c_char, + AppLayerTxMatch: Some(dns_rrtype_match), + Setup: dns_rrtype_setup, + Free: Some(dns_rrtype_free), + flags: 0, + }; + G_DNS_RRTYPE_KW_ID = DetectHelperKeywordRegister(&kw); + G_DNS_RRTYPE_BUFFER_ID = DetectHelperBufferRegister( + b"dns.rrtype\0".as_ptr() as *const libc::c_char, + ALPROTO_DNS, + true, + true, + ); + let kw = SCSigTableElmt { + name: b"dns.query\0".as_ptr() as *const libc::c_char, + desc: b"sticky buffer to match DNS query-buffer\0".as_ptr() as *const libc::c_char, + url: b"/rules/dns-keywords.html#dns-query\0".as_ptr() as *const libc::c_char, + Setup: dns_detect_query_setup, + flags: SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER, + AppLayerTxMatch: None, + Free: None, + }; + let g_dns_query_name_kw_id = DetectHelperKeywordRegister(&kw); + DetectHelperKeywordAliasRegister( + g_dns_query_name_kw_id, + b"dns_query\0".as_ptr() as *const libc::c_char, + ); + G_DNS_QUERY_BUFFER_ID = DetectHelperMultiBufferMpmRegister( + b"dns_query\0".as_ptr() as *const libc::c_char, + b"dns request query\0".as_ptr() as *const libc::c_char, + ALPROTO_DNS, + false, // only toserver + true, + dns_query_get_data_wrapper, // reuse, will be called only toserver + ); +} + #[cfg(test)] mod test { use super::*; @@ -182,7 +557,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, @@ -190,7 +565,7 @@ mod test { } ); assert_eq!( - detect_parse_uint::("123").unwrap().1, + detect_parse_uint_enum::("123").unwrap(), DetectUintData { mode: DetectUintMode::DetectUintModeEqual, arg1: 123, @@ -198,7 +573,7 @@ mod test { } ); assert_eq!( - detect_parse_uint::("!123").unwrap().1, + detect_parse_uint_enum::("!123").unwrap(), DetectUintData { mode: DetectUintMode::DetectUintModeNe, arg1: 123, @@ -206,17 +581,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] @@ -261,7 +644,7 @@ mod test { #[test] fn parse_rrtype_good() { assert_eq!( - detect_parse_uint::("1").unwrap().1, + detect_parse_uint_enum::("1").unwrap(), DetectUintData { mode: DetectUintMode::DetectUintModeEqual, arg1: 1, @@ -269,7 +652,7 @@ mod test { } ); assert_eq!( - detect_parse_uint::("123").unwrap().1, + detect_parse_uint_enum::("123").unwrap(), DetectUintData { mode: DetectUintMode::DetectUintModeEqual, arg1: 123, @@ -277,7 +660,7 @@ mod test { } ); assert_eq!( - detect_parse_uint::("!123").unwrap().1, + detect_parse_uint_enum::("!123").unwrap(), DetectUintData { mode: DetectUintMode::DetectUintModeNe, arg1: 123, @@ -285,17 +668,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::("a").unwrap(), + DetectUintData { + mode: DetectUintMode::DetectUintModeEqual, + arg1: DNSRecordType::A 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 30c1254274b8..462499909a13 100644 --- a/rust/src/dns/dns.rs +++ b/rust/src/dns/dns.rs @@ -32,90 +32,97 @@ use nom7::number::streaming::be_u16; use nom7::{Err, IResult}; /// DNS record types. -pub const DNS_RECORD_TYPE_A: u16 = 1; -pub const DNS_RECORD_TYPE_NS: u16 = 2; -pub const DNS_RECORD_TYPE_MD: u16 = 3; // Obsolete -pub const DNS_RECORD_TYPE_MF: u16 = 4; // Obsolete -pub const DNS_RECORD_TYPE_CNAME: u16 = 5; -pub const DNS_RECORD_TYPE_SOA: u16 = 6; -pub const DNS_RECORD_TYPE_MB: u16 = 7; // Experimental -pub const DNS_RECORD_TYPE_MG: u16 = 8; // Experimental -pub const DNS_RECORD_TYPE_MR: u16 = 9; // Experimental -pub const DNS_RECORD_TYPE_NULL: u16 = 10; // Experimental -pub const DNS_RECORD_TYPE_WKS: u16 = 11; -pub const DNS_RECORD_TYPE_PTR: u16 = 12; -pub const DNS_RECORD_TYPE_HINFO: u16 = 13; -pub const DNS_RECORD_TYPE_MINFO: u16 = 14; -pub const DNS_RECORD_TYPE_MX: u16 = 15; -pub const DNS_RECORD_TYPE_TXT: u16 = 16; -pub const DNS_RECORD_TYPE_RP: u16 = 17; -pub const DNS_RECORD_TYPE_AFSDB: u16 = 18; -pub const DNS_RECORD_TYPE_X25: u16 = 19; -pub const DNS_RECORD_TYPE_ISDN: u16 = 20; -pub const DNS_RECORD_TYPE_RT: u16 = 21; -pub const DNS_RECORD_TYPE_NSAP: u16 = 22; -pub const DNS_RECORD_TYPE_NSAPPTR: u16 = 23; -pub const DNS_RECORD_TYPE_SIG: u16 = 24; -pub const DNS_RECORD_TYPE_KEY: u16 = 25; -pub const DNS_RECORD_TYPE_PX: u16 = 26; -pub const DNS_RECORD_TYPE_GPOS: u16 = 27; -pub const DNS_RECORD_TYPE_AAAA: u16 = 28; -pub const DNS_RECORD_TYPE_LOC: u16 = 29; -pub const DNS_RECORD_TYPE_NXT: u16 = 30; // Obsolete -pub const DNS_RECORD_TYPE_SRV: u16 = 33; -pub const DNS_RECORD_TYPE_ATMA: u16 = 34; -pub const DNS_RECORD_TYPE_NAPTR: u16 = 35; -pub const DNS_RECORD_TYPE_KX: u16 = 36; -pub const DNS_RECORD_TYPE_CERT: u16 = 37; -pub const DNS_RECORD_TYPE_A6: u16 = 38; // Obsolete -pub const DNS_RECORD_TYPE_DNAME: u16 = 39; -pub const DNS_RECORD_TYPE_OPT: u16 = 41; -pub const DNS_RECORD_TYPE_APL: u16 = 42; -pub const DNS_RECORD_TYPE_DS: u16 = 43; -pub const DNS_RECORD_TYPE_SSHFP: u16 = 44; -pub const DNS_RECORD_TYPE_IPSECKEY: u16 = 45; -pub const DNS_RECORD_TYPE_RRSIG: u16 = 46; -pub const DNS_RECORD_TYPE_NSEC: u16 = 47; -pub const DNS_RECORD_TYPE_DNSKEY: u16 = 48; -pub const DNS_RECORD_TYPE_DHCID: u16 = 49; -pub const DNS_RECORD_TYPE_NSEC3: u16 = 50; -pub const DNS_RECORD_TYPE_NSEC3PARAM: u16 = 51; -pub const DNS_RECORD_TYPE_TLSA: u16 = 52; -pub const DNS_RECORD_TYPE_HIP: u16 = 55; -pub const DNS_RECORD_TYPE_CDS: u16 = 59; -pub const DNS_RECORD_TYPE_CDNSKEY: u16 = 60; -pub const DNS_RECORD_TYPE_HTTPS: u16 = 65; -pub const DNS_RECORD_TYPE_SPF: u16 = 99; // Obsolete -pub const DNS_RECORD_TYPE_TKEY: u16 = 249; -pub const DNS_RECORD_TYPE_TSIG: u16 = 250; -pub const DNS_RECORD_TYPE_MAILA: u16 = 254; // Obsolete -pub const DNS_RECORD_TYPE_ANY: u16 = 255; -pub const DNS_RECORD_TYPE_URI: u16 = 256; +/// DNS error codes. +#[derive(Clone, Debug, EnumStringU16)] +pub enum DNSRecordType { + A = 1, + NS = 2, + MD = 3, // Obsolete + MF = 4, // Obsolete + CNAME = 5, + SOA = 6, + MB = 7, // Experimental + MG = 8, // Experimental + MR = 9, // Experimental + NULL = 10, // Experimental + WKS = 11, + PTR = 12, + HINFO = 13, + MINFO = 14, + MX = 15, + TXT = 16, + RP = 17, + AFSDB = 18, + X25 = 19, + ISDN = 20, + RT = 21, + NSAP = 22, + NSAPPTR = 23, + SIG = 24, + KEY = 25, + PX = 26, + GPOS = 27, + AAAA = 28, + LOC = 29, + NXT = 30, // Obsolete + SRV = 33, + ATMA = 34, + NAPTR = 35, + KX = 36, + CERT = 37, + A6 = 38, // Obsolete + DNAME = 39, + OPT = 41, + APL = 42, + DS = 43, + SSHFP = 44, + IPSECKEY = 45, + RRSIG = 46, + NSEC = 47, + DNSKEY = 48, + DHCID = 49, + NSEC3 = 50, + NSEC3PARAM = 51, + TLSA = 52, + HIP = 55, + CDS = 59, + CDNSKEY = 60, + HTTPS = 65, + SPF = 99, // Obsolete + TKEY = 249, + TSIG = 250, + MAILA = 254, // Obsolete + ANY = 255, + URI = 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; - -static mut ALPROTO_DNS: AppProto = ALPROTO_UNKNOWN; +#[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; #[derive(AppLayerFrameType)] enum DnsFrameType { @@ -972,56 +979,6 @@ unsafe extern "C" fn state_get_tx_data(tx: *mut std::os::raw::c_void) -> *mut Ap export_state_data_get!(rs_dns_get_state_data, DNSState); -/// Get the DNS query name at index i. -#[no_mangle] -pub unsafe extern "C" fn SCDnsTxGetQueryName( - tx: &mut DNSTransaction, to_client: bool, i: u32, buf: *mut *const u8, len: *mut u32, -) -> bool { - let queries = if to_client { - tx.response.as_ref().map(|response| &response.queries) - } else { - tx.request.as_ref().map(|request| &request.queries) - }; - let index = i as usize; - - if let Some(queries) = queries { - if let Some(query) = queries.get(index) { - if !query.name.value.is_empty() { - *buf = query.name.value.as_ptr(); - *len = query.name.value.len() as u32; - return true; - } - } - } - - false -} - -/// Get the DNS response answer name and index i. -#[no_mangle] -pub unsafe extern "C" fn SCDnsTxGetAnswerName( - tx: &mut DNSTransaction, to_client: bool, i: u32, buf: *mut *const u8, len: *mut u32, -) -> bool { - let answers = if to_client { - tx.response.as_ref().map(|response| &response.answers) - } else { - tx.request.as_ref().map(|request| &request.answers) - }; - let index = i as usize; - - if let Some(answers) = answers { - if let Some(answer) = answers.get(index) { - if !answer.name.value.is_empty() { - *buf = answer.name.value.as_ptr(); - *len = answer.name.value.len() as u32; - return true; - } - } - } - - false -} - /// Get the DNS response flags for a transaction. /// /// extern uint16_t SCDnsTxGetResponseFlags(RSDNSTransaction *); diff --git a/rust/src/dns/log.rs b/rust/src/dns/log.rs index 7003e70c1949..447dda1b23f2 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}; @@ -95,180 +96,180 @@ fn dns_log_rrtype_enabled(rtype: u16, flags: u64) -> bool { return true; } - match rtype { - DNS_RECORD_TYPE_A => { + match DNSRecordType::from_u(rtype) { + Some(DNSRecordType::A) => { return flags & LOG_A != 0; } - DNS_RECORD_TYPE_NS => { + Some(DNSRecordType::NS) => { return flags & LOG_NS != 0; } - DNS_RECORD_TYPE_MD => { + Some(DNSRecordType::MD) => { return flags & LOG_MD != 0; } - DNS_RECORD_TYPE_MF => { + Some(DNSRecordType::MF) => { return flags & LOG_MF != 0; } - DNS_RECORD_TYPE_CNAME => { + Some(DNSRecordType::CNAME) => { return flags & LOG_CNAME != 0; } - DNS_RECORD_TYPE_SOA => { + Some(DNSRecordType::SOA) => { return flags & LOG_SOA != 0; } - DNS_RECORD_TYPE_MB => { + Some(DNSRecordType::MB) => { return flags & LOG_MB != 0; } - DNS_RECORD_TYPE_MG => { + Some(DNSRecordType::MG) => { return flags & LOG_MG != 0; } - DNS_RECORD_TYPE_MR => { + Some(DNSRecordType::MR) => { return flags & LOG_MR != 0; } - DNS_RECORD_TYPE_NULL => { + Some(DNSRecordType::NULL) => { return flags & LOG_NULL != 0; } - DNS_RECORD_TYPE_WKS => { + Some(DNSRecordType::WKS) => { return flags & LOG_WKS != 0; } - DNS_RECORD_TYPE_PTR => { + Some(DNSRecordType::PTR) => { return flags & LOG_PTR != 0; } - DNS_RECORD_TYPE_HINFO => { + Some(DNSRecordType::HINFO) => { return flags & LOG_HINFO != 0; } - DNS_RECORD_TYPE_MINFO => { + Some(DNSRecordType::MINFO) => { return flags & LOG_MINFO != 0; } - DNS_RECORD_TYPE_MX => { + Some(DNSRecordType::MX) => { return flags & LOG_MX != 0; } - DNS_RECORD_TYPE_TXT => { + Some(DNSRecordType::TXT) => { return flags & LOG_TXT != 0; } - DNS_RECORD_TYPE_RP => { + Some(DNSRecordType::RP) => { return flags & LOG_RP != 0; } - DNS_RECORD_TYPE_AFSDB => { + Some(DNSRecordType::AFSDB) => { return flags & LOG_AFSDB != 0; } - DNS_RECORD_TYPE_X25 => { + Some(DNSRecordType::X25) => { return flags & LOG_X25 != 0; } - DNS_RECORD_TYPE_ISDN => { + Some(DNSRecordType::ISDN) => { return flags & LOG_ISDN != 0; } - DNS_RECORD_TYPE_RT => { + Some(DNSRecordType::RT) => { return flags & LOG_RT != 0; } - DNS_RECORD_TYPE_NSAP => { + Some(DNSRecordType::NSAP) => { return flags & LOG_NSAP != 0; } - DNS_RECORD_TYPE_NSAPPTR => { + Some(DNSRecordType::NSAPPTR) => { return flags & LOG_NSAPPTR != 0; } - DNS_RECORD_TYPE_SIG => { + Some(DNSRecordType::SIG) => { return flags & LOG_SIG != 0; } - DNS_RECORD_TYPE_KEY => { + Some(DNSRecordType::KEY) => { return flags & LOG_KEY != 0; } - DNS_RECORD_TYPE_PX => { + Some(DNSRecordType::PX) => { return flags & LOG_PX != 0; } - DNS_RECORD_TYPE_GPOS => { + Some(DNSRecordType::GPOS) => { return flags & LOG_GPOS != 0; } - DNS_RECORD_TYPE_AAAA => { + Some(DNSRecordType::AAAA) => { return flags & LOG_AAAA != 0; } - DNS_RECORD_TYPE_LOC => { + Some(DNSRecordType::LOC) => { return flags & LOG_LOC != 0; } - DNS_RECORD_TYPE_NXT => { + Some(DNSRecordType::NXT) => { return flags & LOG_NXT != 0; } - DNS_RECORD_TYPE_SRV => { + Some(DNSRecordType::SRV) => { return flags & LOG_SRV != 0; } - DNS_RECORD_TYPE_ATMA => { + Some(DNSRecordType::ATMA) => { return flags & LOG_ATMA != 0; } - DNS_RECORD_TYPE_NAPTR => { + Some(DNSRecordType::NAPTR) => { return flags & LOG_NAPTR != 0; } - DNS_RECORD_TYPE_KX => { + Some(DNSRecordType::KX) => { return flags & LOG_KX != 0; } - DNS_RECORD_TYPE_CERT => { + Some(DNSRecordType::CERT) => { return flags & LOG_CERT != 0; } - DNS_RECORD_TYPE_A6 => { + Some(DNSRecordType::A6) => { return flags & LOG_A6 != 0; } - DNS_RECORD_TYPE_DNAME => { + Some(DNSRecordType::DNAME) => { return flags & LOG_DNAME != 0; } - DNS_RECORD_TYPE_OPT => { + Some(DNSRecordType::OPT) => { return flags & LOG_OPT != 0; } - DNS_RECORD_TYPE_APL => { + Some(DNSRecordType::APL) => { return flags & LOG_APL != 0; } - DNS_RECORD_TYPE_DS => { + Some(DNSRecordType::DS) => { return flags & LOG_DS != 0; } - DNS_RECORD_TYPE_SSHFP => { + Some(DNSRecordType::SSHFP) => { return flags & LOG_SSHFP != 0; } - DNS_RECORD_TYPE_IPSECKEY => { + Some(DNSRecordType::IPSECKEY) => { return flags & LOG_IPSECKEY != 0; } - DNS_RECORD_TYPE_RRSIG => { + Some(DNSRecordType::RRSIG) => { return flags & LOG_RRSIG != 0; } - DNS_RECORD_TYPE_NSEC => { + Some(DNSRecordType::NSEC) => { return flags & LOG_NSEC != 0; } - DNS_RECORD_TYPE_DNSKEY => { + Some(DNSRecordType::DNSKEY) => { return flags & LOG_DNSKEY != 0; } - DNS_RECORD_TYPE_DHCID => { + Some(DNSRecordType::DHCID) => { return flags & LOG_DHCID != 0; } - DNS_RECORD_TYPE_NSEC3 => return flags & LOG_NSEC3 != 0, - DNS_RECORD_TYPE_NSEC3PARAM => { + Some(DNSRecordType::NSEC3) => return flags & LOG_NSEC3 != 0, + Some(DNSRecordType::NSEC3PARAM) => { return flags & LOG_NSEC3PARAM != 0; } - DNS_RECORD_TYPE_TLSA => { + Some(DNSRecordType::TLSA) => { return flags & LOG_TLSA != 0; } - DNS_RECORD_TYPE_HIP => { + Some(DNSRecordType::HIP) => { return flags & LOG_HIP != 0; } - DNS_RECORD_TYPE_CDS => { + Some(DNSRecordType::CDS) => { return flags & LOG_CDS != 0; } - DNS_RECORD_TYPE_CDNSKEY => { + Some(DNSRecordType::CDNSKEY) => { return flags & LOG_CDNSKEY != 0; } - DNS_RECORD_TYPE_HTTPS => { + Some(DNSRecordType::HTTPS) => { return flags & LOG_HTTPS != 0; } - DNS_RECORD_TYPE_SPF => { + Some(DNSRecordType::SPF) => { return flags & LOG_SPF != 0; } - DNS_RECORD_TYPE_TKEY => { + Some(DNSRecordType::TKEY) => { return flags & LOG_TKEY != 0; } - DNS_RECORD_TYPE_TSIG => { + Some(DNSRecordType::TSIG) => { return flags & LOG_TSIG != 0; } - DNS_RECORD_TYPE_MAILA => { + Some(DNSRecordType::MAILA) => { return flags & LOG_MAILA != 0; } - DNS_RECORD_TYPE_ANY => { + Some(DNSRecordType::ANY) => { return flags & LOG_ANY != 0; } - DNS_RECORD_TYPE_URI => { + Some(DNSRecordType::URI) => { return flags & LOG_URI != 0; } _ => { @@ -278,98 +279,20 @@ fn dns_log_rrtype_enabled(rtype: u16, flags: u64) -> bool { } pub fn dns_rrtype_string(rrtype: u16) -> String { - match rrtype { - DNS_RECORD_TYPE_A => "A", - DNS_RECORD_TYPE_NS => "NS", - DNS_RECORD_TYPE_AAAA => "AAAA", - DNS_RECORD_TYPE_CNAME => "CNAME", - DNS_RECORD_TYPE_TXT => "TXT", - DNS_RECORD_TYPE_MX => "MX", - DNS_RECORD_TYPE_SOA => "SOA", - DNS_RECORD_TYPE_PTR => "PTR", - DNS_RECORD_TYPE_SIG => "SIG", - DNS_RECORD_TYPE_KEY => "KEY", - DNS_RECORD_TYPE_WKS => "WKS", - DNS_RECORD_TYPE_TKEY => "TKEY", - DNS_RECORD_TYPE_TSIG => "TSIG", - DNS_RECORD_TYPE_ANY => "ANY", - DNS_RECORD_TYPE_RRSIG => "RRSIG", - DNS_RECORD_TYPE_NSEC => "NSEC", - DNS_RECORD_TYPE_DNSKEY => "DNSKEY", - DNS_RECORD_TYPE_HINFO => "HINFO", - DNS_RECORD_TYPE_MINFO => "MINFO", - DNS_RECORD_TYPE_RP => "RP", - DNS_RECORD_TYPE_AFSDB => "AFSDB", - DNS_RECORD_TYPE_X25 => "X25", - DNS_RECORD_TYPE_ISDN => "ISDN", - DNS_RECORD_TYPE_RT => "RT", - DNS_RECORD_TYPE_NSAP => "NSAP", - DNS_RECORD_TYPE_NSAPPTR => "NSAPPT", - DNS_RECORD_TYPE_PX => "PX", - DNS_RECORD_TYPE_GPOS => "GPOS", - DNS_RECORD_TYPE_LOC => "LOC", - DNS_RECORD_TYPE_SRV => "SRV", - DNS_RECORD_TYPE_ATMA => "ATMA", - DNS_RECORD_TYPE_NAPTR => "NAPTR", - DNS_RECORD_TYPE_KX => "KX", - DNS_RECORD_TYPE_CERT => "CERT", - DNS_RECORD_TYPE_A6 => "A6", - DNS_RECORD_TYPE_DNAME => "DNAME", - DNS_RECORD_TYPE_OPT => "OPT", - DNS_RECORD_TYPE_APL => "APL", - DNS_RECORD_TYPE_DS => "DS", - DNS_RECORD_TYPE_SSHFP => "SSHFP", - DNS_RECORD_TYPE_IPSECKEY => "IPSECKEY", - DNS_RECORD_TYPE_DHCID => "DHCID", - DNS_RECORD_TYPE_NSEC3 => "NSEC3", - DNS_RECORD_TYPE_NSEC3PARAM => "NSEC3PARAM", - DNS_RECORD_TYPE_TLSA => "TLSA", - DNS_RECORD_TYPE_HIP => "HIP", - DNS_RECORD_TYPE_CDS => "CDS", - DNS_RECORD_TYPE_CDNSKEY => "CDSNKEY", - DNS_RECORD_TYPE_HTTPS => "HTTPS", - DNS_RECORD_TYPE_MAILA => "MAILA", - DNS_RECORD_TYPE_URI => "URI", - DNS_RECORD_TYPE_MB => "MB", - DNS_RECORD_TYPE_MG => "MG", - DNS_RECORD_TYPE_MR => "MR", - DNS_RECORD_TYPE_NULL => "NULL", - DNS_RECORD_TYPE_SPF => "SPF", - DNS_RECORD_TYPE_NXT => "NXT", - DNS_RECORD_TYPE_MD => "ND", - DNS_RECORD_TYPE_MF => "MF", - _ => { - return rrtype.to_string(); - } + if let Some(rt) = DNSRecordType::from_u(rrtype) { + return rt.to_str().to_uppercase(); } - .to_string() + return rrtype.to_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(); + } + if let Some(rc) = DNSRcode::from_u(flags & 0x000f) { + return rc.to_str().to_uppercase(); } - .to_string() + return (flags & 0x000f).to_string(); } /// Format bytes as an IP address string. diff --git a/rust/src/dns/mod.rs b/rust/src/dns/mod.rs index 3a572a82111f..42063899f2ae 100644 --- a/rust/src/dns/mod.rs +++ b/rust/src/dns/mod.rs @@ -20,5 +20,5 @@ pub mod detect; pub mod dns; pub mod log; -pub mod parser; pub mod lua; +pub mod parser; diff --git a/rust/src/dns/parser.rs b/rust/src/dns/parser.rs index d94daf980402..ee2366137f23 100644 --- a/rust/src/dns/parser.rs +++ b/rust/src/dns/parser.rs @@ -18,6 +18,7 @@ //! Nom parsers for DNS. use crate::dns::dns::*; +use crate::detect::EnumString; use nom7::combinator::{complete, rest}; use nom7::error::ErrorKind; use nom7::multi::{count, length_data, many_m_n}; @@ -205,24 +206,21 @@ fn dns_parse_answer<'a>( for _ in 0..count { match subparser(input, message, flags) { Ok((rem, val)) => { - let n = match val.rrtype { - DNS_RECORD_TYPE_TXT => { - // For TXT records we need to run the parser - // multiple times. Set n high, to the maximum - // value based on a max txt side of 65535, but - // taking into considering that strings need - // to be quoted, so half that. - 32767 - } - _ => { - // For all other types we only want to run the - // parser once, so set n to 1. - 1 - } + let n = if val.rrtype == DNSRecordType::TXT as u16 { + // For TXT records we need to run the parser + // multiple times. Set n high, to the maximum + // value based on a max txt side of 65535, but + // taking into considering that strings need + // to be quoted, so half that. + 32767 + } else { + // For all other types we only want to run the + // parser once, so set n to 1. + 1 }; // edge case for additional section of type=OPT // with empty data (data length = 0x0000) - if val.data.is_empty() && val.rrtype == DNS_RECORD_TYPE_OPT { + if val.data.is_empty() && val.rrtype == DNSRecordType::OPT as u16 { answers.push(DNSAnswerEntry { name: val.name.clone(), rrtype: val.rrtype, @@ -414,19 +412,19 @@ fn dns_parse_rdata_unknown(input: &[u8]) -> IResult<&[u8], DNSRData> { fn dns_parse_rdata<'a>( input: &'a [u8], message: &'a [u8], rrtype: u16, flags: &mut DNSNameFlags, ) -> IResult<&'a [u8], DNSRData> { - match rrtype { - DNS_RECORD_TYPE_A => dns_parse_rdata_a(input), - DNS_RECORD_TYPE_AAAA => dns_parse_rdata_aaaa(input), - DNS_RECORD_TYPE_CNAME => dns_parse_rdata_cname(input, message, flags), - DNS_RECORD_TYPE_PTR => dns_parse_rdata_ptr(input, message, flags), - DNS_RECORD_TYPE_SOA => dns_parse_rdata_soa(input, message, flags), - DNS_RECORD_TYPE_MX => dns_parse_rdata_mx(input, message, flags), - DNS_RECORD_TYPE_NS => dns_parse_rdata_ns(input, message, flags), - DNS_RECORD_TYPE_TXT => dns_parse_rdata_txt(input), - DNS_RECORD_TYPE_NULL => dns_parse_rdata_null(input), - DNS_RECORD_TYPE_SSHFP => dns_parse_rdata_sshfp(input), - DNS_RECORD_TYPE_SRV => dns_parse_rdata_srv(input, message, flags), - DNS_RECORD_TYPE_OPT => dns_parse_rdata_opt(input), + match DNSRecordType::from_u(rrtype) { + Some(DNSRecordType::A) => dns_parse_rdata_a(input), + Some(DNSRecordType::AAAA) => dns_parse_rdata_aaaa(input), + Some(DNSRecordType::CNAME) => dns_parse_rdata_cname(input, message, flags), + Some(DNSRecordType::PTR) => dns_parse_rdata_ptr(input, message, flags), + Some(DNSRecordType::SOA) => dns_parse_rdata_soa(input, message, flags), + Some(DNSRecordType::MX) => dns_parse_rdata_mx(input, message, flags), + Some(DNSRecordType::NS) => dns_parse_rdata_ns(input, message, flags), + Some(DNSRecordType::TXT) => dns_parse_rdata_txt(input), + Some(DNSRecordType::NULL) => dns_parse_rdata_null(input), + Some(DNSRecordType::SSHFP) => dns_parse_rdata_sshfp(input), + Some(DNSRecordType::SRV) => dns_parse_rdata_srv(input, message, flags), + Some(DNSRecordType::OPT) => dns_parse_rdata_opt(input), _ => dns_parse_rdata_unknown(input), } } @@ -705,7 +703,7 @@ mod tests { value: vec![], flags: DNSNameFlags::default() }, - rrtype: DNS_RECORD_TYPE_OPT, + rrtype: DNSRecordType::OPT as u16, rrclass: 0x1000, // for OPT this is UDP payload size ttl: 0, // for OPT this is extended RCODE and flags data: DNSRData::OPT(vec![]), // empty rdata @@ -766,7 +764,7 @@ mod tests { value: vec![], flags: DNSNameFlags::default() }, - rrtype: DNS_RECORD_TYPE_OPT, + rrtype: DNSRecordType::OPT as u16, rrclass: 0x1000, // for OPT this is requestor's UDP payload size ttl: 0, // for OPT this is extended RCODE and flags // verify two options @@ -951,7 +949,7 @@ mod tests { value: vec![], flags: DNSNameFlags::default() }, - rrtype: DNS_RECORD_TYPE_OPT, + rrtype: DNSRecordType::OPT as u16, rrclass: 0x0200, // for OPT this is UDP payload size ttl: 0, // for OPT this is extended RCODE and flags data: DNSRData::OPT(vec![]), // no rdata @@ -997,7 +995,7 @@ mod tests { query.name.value, "vaaaakardli.pirate.sea".as_bytes().to_vec() ); - assert_eq!(query.rrtype, DNS_RECORD_TYPE_NULL); + assert_eq!(query.rrtype, DNSRecordType::NULL as u16); assert_eq!(query.rrclass, 1); assert_eq!(response.answers.len(), 1); @@ -1007,7 +1005,7 @@ mod tests { answer.name.value, "vaaaakardli.pirate.sea".as_bytes().to_vec() ); - assert_eq!(answer.rrtype, DNS_RECORD_TYPE_NULL); + assert_eq!(answer.rrtype, DNSRecordType::NULL as u16); assert_eq!(answer.rrclass, 1); assert_eq!(answer.ttl, 0); assert_eq!( diff --git a/src/Makefile.am b/src/Makefile.am index 1b1d8fca6144..3a3a36997289 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -111,12 +111,6 @@ noinst_HEADERS = \ detect-detection-filter.h \ detect-distance.h \ detect-dnp3.h \ - detect-dns-answer-name.h \ - detect-dns-opcode.h \ - detect-dns-rcode.h \ - detect-dns-rrtype.h \ - detect-dns-query.h \ - detect-dns-query-name.h \ detect-dsize.h \ detect-engine-address.h \ detect-engine-address-ipv4.h \ @@ -682,12 +676,6 @@ libsuricata_c_a_SOURCES = \ detect-detection-filter.c \ detect-distance.c \ detect-dnp3.c \ - detect-dns-answer-name.c \ - detect-dns-opcode.c \ - detect-dns-rcode.c \ - detect-dns-rrtype.c \ - detect-dns-query.c \ - detect-dns-query-name.c \ detect-dsize.c \ detect-engine-address.c \ detect-engine-address-ipv4.c \ diff --git a/src/detect-dns-answer-name.c b/src/detect-dns-answer-name.c deleted file mode 100644 index ccf4746254df..000000000000 --- a/src/detect-dns-answer-name.c +++ /dev/null @@ -1,92 +0,0 @@ -/* Copyright (C) 2023 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. - */ - -/** - * \file - * - * Detect keyword for DNS answer name: dns.answer.name - */ - -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-content-inspection.h" -#include "detect-dns-answer-name.h" -#include "util-profiling.h" -#include "rust.h" - -static int detect_buffer_id = 0; - -static int DetectSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, detect_buffer_id) < 0) { - return -1; - } - if (DetectSignatureSetAppProto(s, ALPROTO_DNS) < 0) { - return -1; - } - - return 0; -} - -static InspectionBuffer *GetBuffer(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, uint8_t flags, void *txv, int list_id, - uint32_t index) -{ - InspectionBuffer *buffer = InspectionBufferMultipleForListGet(det_ctx, list_id, index); - if (buffer == NULL) { - return NULL; - } - if (buffer->initialized) { - return buffer; - } - - bool to_client = (flags & STREAM_TOSERVER) == 0; - const uint8_t *data = NULL; - uint32_t data_len = 0; - - if (!SCDnsTxGetAnswerName(txv, to_client, index, &data, &data_len)) { - InspectionBufferSetupMultiEmpty(buffer); - return NULL; - } - InspectionBufferSetupMulti(buffer, transforms, data, data_len); - buffer->flags = DETECT_CI_FLAGS_SINGLE; - return buffer; -} - -void DetectDnsAnswerNameRegister(void) -{ - static const char *keyword = "dns.answer.name"; - sigmatch_table[DETECT_DNS_ANSWER_NAME].name = keyword; - sigmatch_table[DETECT_DNS_ANSWER_NAME].desc = "DNS answer name sticky buffer"; - sigmatch_table[DETECT_DNS_ANSWER_NAME].url = "/rules/dns-keywords.html#dns-answer-name"; - sigmatch_table[DETECT_DNS_ANSWER_NAME].Setup = DetectSetup; - sigmatch_table[DETECT_DNS_ANSWER_NAME].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_DNS_ANSWER_NAME].flags |= SIGMATCH_INFO_STICKY_BUFFER; - - /* Register in the TO_SERVER direction, even though this is not - normal, it could be provided as part of a request. */ - DetectAppLayerMultiRegister(keyword, ALPROTO_DNS, SIG_FLAG_TOSERVER, 0, GetBuffer, 2, 1); - /* Register in the TO_CLIENT direction. */ - DetectAppLayerMultiRegister(keyword, ALPROTO_DNS, SIG_FLAG_TOCLIENT, 0, GetBuffer, 2, 1); - - DetectBufferTypeSetDescriptionByName(keyword, "dns answer name"); - DetectBufferTypeSupportsMultiInstance(keyword); - - detect_buffer_id = DetectBufferTypeGetByName(keyword); -} diff --git a/src/detect-dns-answer-name.h b/src/detect-dns-answer-name.h deleted file mode 100644 index e259f1a577d4..000000000000 --- a/src/detect-dns-answer-name.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright (C) 2023 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 SURICATA_DETECT_DNS_ANSWER_NAME_H -#define SURICATA_DETECT_DNS_ANSWER_NAME_H - -void DetectDnsAnswerNameRegister(void); - -#endif /* SURICATA_DETECT_DNS_ANSWER_NAME_H */ diff --git a/src/detect-dns-opcode.c b/src/detect-dns-opcode.c deleted file mode 100644 index 6e9f819fc217..000000000000 --- a/src/detect-dns-opcode.c +++ /dev/null @@ -1,89 +0,0 @@ -/* Copyright (C) 2019 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-engine-uint.h" -#include "detect-dns-opcode.h" -#include "rust.h" - -static int dns_opcode_list_id = 0; - -static void DetectDnsOpcodeFree(DetectEngineCtx *, void *ptr); - -static int DetectDnsOpcodeSetup(DetectEngineCtx *de_ctx, Signature *s, - const char *str) -{ - SCEnter(); - - if (DetectSignatureSetAppProto(s, ALPROTO_DNS) != 0) { - return -1; - } - - void *detect = DetectU8Parse(str); - if (detect == NULL) { - SCLogError("failed to parse dns.opcode: %s", str); - return -1; - } - - if (SigMatchAppendSMToList( - de_ctx, s, DETECT_DNS_OPCODE, (SigMatchCtx *)detect, dns_opcode_list_id) == NULL) { - goto error; - } - - SCReturnInt(0); - -error: - DetectDnsOpcodeFree(de_ctx, detect); - SCReturnInt(-1); -} - -static void DetectDnsOpcodeFree(DetectEngineCtx *de_ctx, void *ptr) -{ - SCEnter(); - if (ptr != NULL) { - rs_detect_u8_free(ptr); - } - SCReturn; -} - -static int DetectDnsOpcodeMatch(DetectEngineThreadCtx *det_ctx, - Flow *f, uint8_t flags, void *state, void *txv, const Signature *s, - const SigMatchCtx *ctx) -{ - return SCDnsDetectOpcodeMatch(txv, (void *)ctx, flags); -} - -void DetectDnsOpcodeRegister(void) -{ - sigmatch_table[DETECT_DNS_OPCODE].name = "dns.opcode"; - sigmatch_table[DETECT_DNS_OPCODE].desc = "Match the DNS header opcode flag."; - sigmatch_table[DETECT_DNS_OPCODE].Setup = DetectDnsOpcodeSetup; - sigmatch_table[DETECT_DNS_OPCODE].Free = DetectDnsOpcodeFree; - sigmatch_table[DETECT_DNS_OPCODE].Match = NULL; - sigmatch_table[DETECT_DNS_OPCODE].AppLayerTxMatch = DetectDnsOpcodeMatch; - - DetectAppLayerInspectEngineRegister( - "dns.opcode", ALPROTO_DNS, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL); - - DetectAppLayerInspectEngineRegister( - "dns.opcode", ALPROTO_DNS, SIG_FLAG_TOCLIENT, 0, DetectEngineInspectGenericList, NULL); - - dns_opcode_list_id = DetectBufferTypeGetByName("dns.opcode"); -} diff --git a/src/detect-dns-opcode.h b/src/detect-dns-opcode.h deleted file mode 100644 index a26a39e71107..000000000000 --- a/src/detect-dns-opcode.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright (C) 2019 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 SURICATA_DETECT_DNS_OPCODE_H -#define SURICATA_DETECT_DNS_OPCODE_H - -void DetectDnsOpcodeRegister(void); - -#endif /* SURICATA_DETECT_DNS_OPCODE_H */ diff --git a/src/detect-dns-query-name.c b/src/detect-dns-query-name.c deleted file mode 100644 index dea5c81c7f87..000000000000 --- a/src/detect-dns-query-name.c +++ /dev/null @@ -1,91 +0,0 @@ -/* Copyright (C) 2023 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. - */ - -/** - * \file - * - * Detect keyword for DNS query names: dns.query.name - */ - -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-content-inspection.h" -#include "detect-dns-query-name.h" -#include "util-profiling.h" -#include "rust.h" - -static int detect_buffer_id = 0; - -static int DetectSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, detect_buffer_id) < 0) { - return -1; - } - if (DetectSignatureSetAppProto(s, ALPROTO_DNS) < 0) { - return -1; - } - - return 0; -} - -static InspectionBuffer *GetBuffer(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, const uint8_t flags, void *txv, - int list_id, uint32_t index) -{ - InspectionBuffer *buffer = InspectionBufferMultipleForListGet(det_ctx, list_id, index); - if (buffer == NULL) { - return NULL; - } - if (buffer->initialized) { - return buffer; - } - - bool to_client = (flags & STREAM_TOSERVER) == 0; - const uint8_t *data = NULL; - uint32_t data_len = 0; - - if (!SCDnsTxGetQueryName(txv, to_client, index, &data, &data_len)) { - InspectionBufferSetupMultiEmpty(buffer); - return NULL; - } - InspectionBufferSetupMulti(buffer, transforms, data, data_len); - buffer->flags = DETECT_CI_FLAGS_SINGLE; - return buffer; -} - -void DetectDnsQueryNameRegister(void) -{ - static const char *keyword = "dns.query.name"; - sigmatch_table[DETECT_DNS_QUERY_NAME].name = keyword; - sigmatch_table[DETECT_DNS_QUERY_NAME].desc = "DNS query name sticky buffer"; - sigmatch_table[DETECT_DNS_QUERY_NAME].url = "/rules/dns-keywords.html#dns-query-name"; - sigmatch_table[DETECT_DNS_QUERY_NAME].Setup = DetectSetup; - sigmatch_table[DETECT_DNS_QUERY_NAME].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_DNS_QUERY_NAME].flags |= SIGMATCH_INFO_STICKY_BUFFER; - - /* Register in both directions as the query is usually echoed back - in the response. */ - DetectAppLayerMultiRegister(keyword, ALPROTO_DNS, SIG_FLAG_TOSERVER, 0, GetBuffer, 2, 1); - DetectAppLayerMultiRegister(keyword, ALPROTO_DNS, SIG_FLAG_TOCLIENT, 0, GetBuffer, 2, 1); - - DetectBufferTypeSetDescriptionByName(keyword, "dns query name"); - DetectBufferTypeSupportsMultiInstance(keyword); - - detect_buffer_id = DetectBufferTypeGetByName(keyword); -} diff --git a/src/detect-dns-query-name.h b/src/detect-dns-query-name.h deleted file mode 100644 index 3f5bc03bf72f..000000000000 --- a/src/detect-dns-query-name.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright (C) 2023 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 SURICATA_DETECT_DNS_QUERY_NAME_H -#define SURICATA_DETECT_DNS_QUERY_NAME_H - -void DetectDnsQueryNameRegister(void); - -#endif /* SURICATA_DETECT_DNS_QUERY_NAME_H */ diff --git a/src/detect-dns-query.c b/src/detect-dns-query.c deleted file mode 100644 index f50267566480..000000000000 --- a/src/detect-dns-query.c +++ /dev/null @@ -1,767 +0,0 @@ -/* Copyright (C) 2013-2023 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. - */ - -/** - * \ingroup dnslayer - * - * @{ - */ - - -/** - * \file - * - * \author Victor Julien - */ - -#include "suricata-common.h" -#include "threads.h" -#include "decode.h" -#include "detect.h" - -#include "detect-parse.h" -#include "detect-engine.h" -#include "detect-engine-build.h" -#include "detect-engine-mpm.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-content-inspection.h" -#include "detect-content.h" -#include "detect-pcre.h" - -#include "flow.h" -#include "flow-util.h" -#include "flow-var.h" - -#include "util-debug.h" -#include "util-unittest.h" -#include "util-spm.h" -#include "util-print.h" - -#include "stream-tcp.h" - -#include "app-layer.h" -#include "app-layer-parser.h" -#include "detect-dns-query.h" - -#include "util-profiling.h" -#include "util-unittest-helper.h" -#include "rust.h" - -static int DetectDnsQuerySetup (DetectEngineCtx *, Signature *, const char *); -#ifdef UNITTESTS -static void DetectDnsQueryRegisterTests(void); -#endif -static int g_dns_query_buffer_id = 0; - -static InspectionBuffer *DnsQueryGetData(DetectEngineThreadCtx *det_ctx, - const DetectEngineTransforms *transforms, Flow *f, const uint8_t flags, void *txv, - int list_id, uint32_t local_id) -{ - SCEnter(); - - InspectionBuffer *buffer = InspectionBufferMultipleForListGet(det_ctx, list_id, local_id); - if (buffer == NULL) - return NULL; - if (buffer->initialized) - return buffer; - - const uint8_t *data; - uint32_t data_len; - if (SCDnsTxGetQueryName(txv, false, local_id, &data, &data_len) == 0) { - InspectionBufferSetupMultiEmpty(buffer); - return NULL; - } - InspectionBufferSetupMulti(buffer, transforms, data, data_len); - buffer->flags = DETECT_CI_FLAGS_SINGLE; - - SCReturnPtr(buffer, "InspectionBuffer"); -} - -/** - * \brief Registration function for keyword: dns_query - */ -void DetectDnsQueryRegister (void) -{ - sigmatch_table[DETECT_DNS_QUERY].name = "dns.query"; - sigmatch_table[DETECT_DNS_QUERY].alias = "dns_query"; - sigmatch_table[DETECT_DNS_QUERY].desc = "sticky buffer to match DNS query-buffer"; - sigmatch_table[DETECT_DNS_QUERY].url = "/rules/dns-keywords.html#dns-query"; - sigmatch_table[DETECT_DNS_QUERY].Setup = DetectDnsQuerySetup; -#ifdef UNITTESTS - sigmatch_table[DETECT_DNS_QUERY].RegisterTests = DetectDnsQueryRegisterTests; -#endif - sigmatch_table[DETECT_DNS_QUERY].flags |= SIGMATCH_NOOPT; - sigmatch_table[DETECT_DNS_QUERY].flags |= SIGMATCH_INFO_STICKY_BUFFER; - - DetectAppLayerMultiRegister( - "dns_query", ALPROTO_DNS, SIG_FLAG_TOSERVER, 1, DnsQueryGetData, 2, 1); - - DetectBufferTypeSetDescriptionByName("dns_query", - "dns request query"); - DetectBufferTypeSupportsMultiInstance("dns_query"); - - g_dns_query_buffer_id = DetectBufferTypeGetByName("dns_query"); - - /* register these generic engines from here for now */ - DetectAppLayerInspectEngineRegister( - "dns_request", ALPROTO_DNS, SIG_FLAG_TOSERVER, 1, DetectEngineInspectGenericList, NULL); - DetectAppLayerInspectEngineRegister("dns_response", ALPROTO_DNS, SIG_FLAG_TOCLIENT, 1, - DetectEngineInspectGenericList, NULL); - - DetectBufferTypeSetDescriptionByName("dns_request", - "dns requests"); - DetectBufferTypeSetDescriptionByName("dns_response", "dns responses"); -} - - -/** - * \brief setup the dns_query sticky buffer keyword used in the rule - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Signature to which the current keyword belongs - * \param str Should hold an empty string always - * - * \retval 0 On success - * \retval -1 On failure - */ - -static int DetectDnsQuerySetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - if (DetectBufferSetActiveList(de_ctx, s, g_dns_query_buffer_id) < 0) - return -1; - if (DetectSignatureSetAppProto(s, ALPROTO_DNS) < 0) - return -1; - return 0; -} - -#ifdef UNITTESTS -#include "detect-isdataat.h" -#include "detect-engine-alert.h" - -/** \test simple google.com query matching */ -static int DetectDnsQueryTest01(void) -{ - /* google.com */ - uint8_t buf[] = { 0x10, 0x32, 0x01, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C, - 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, - 0x00, 0x10, 0x00, 0x01, }; - Flow f; - void *dns_state = NULL; - Packet *p = NULL; - Signature *s = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - - p = UTHBuildPacketReal(buf, sizeof(buf), IPPROTO_UDP, - "192.168.1.5", "192.168.1.1", - 41424, 53); - - FLOW_INITIALIZE(&f); - f.flags |= FLOW_IPV4; - f.proto = IPPROTO_UDP; - f.protomap = FlowGetProtoMapping(f.proto); - - p->flow = &f; - p->flags |= PKT_HAS_FLOW; - p->flowflags |= FLOW_PKT_TOSERVER; - f.alproto = ALPROTO_DNS; - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->mpm_matcher = mpm_default_matcher; - de_ctx->flags |= DE_QUIET; - - s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " - "(msg:\"Test dns_query option\"; " - "dns_query; content:\"google\"; nocase; sid:1;)"); - FAIL_IF_NULL(s); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, - STREAM_TOSERVER, buf, sizeof(buf)); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FAIL; - } - - dns_state = f.alstate; - FAIL_IF_NULL(dns_state); - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!(PacketAlertCheck(p, 1))) { - printf("sig 1 didn't alert, but it should have: "); - FAIL; - } - - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - FLOW_DESTROY(&f); - UTHFreePacket(p); - PASS; -} - -/** \test multi tx google.(com|net) query matching */ -static int DetectDnsQueryTest02(void) -{ - /* google.com */ - uint8_t buf1[] = { 0x10, 0x32, 0x01, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C, - 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, - 0x00, 0x01, 0x00, 0x01, }; - - uint8_t buf2[] = { 0x10, 0x32, /* tx id */ - 0x81, 0x80, /* flags: resp, recursion desired, recursion available */ - 0x00, 0x01, /* 1 query */ - 0x00, 0x01, /* 1 answer */ - 0x00, 0x00, 0x00, 0x00, /* no auth rr, additional rr */ - /* query record */ - 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C, /* name */ - 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* name cont */ - 0x00, 0x01, 0x00, 0x01, /* type a, class in */ - /* answer */ - 0xc0, 0x0c, /* ref to name in query above */ - 0x00, 0x01, 0x00, 0x01, /* type a, class in */ - 0x00, 0x01, 0x40, 0xef, /* ttl */ - 0x00, 0x04, /* data len */ - 0x01, 0x02, 0x03, 0x04 }; /* addr */ - - /* google.net */ - uint8_t buf3[] = { 0x11, 0x33, 0x01, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C, - 0x65, 0x03, 0x6E, 0x65, 0x74, 0x00, - 0x00, 0x10, 0x00, 0x01, }; - Flow f; - void *dns_state = NULL; - Packet *p1 = NULL, *p2 = NULL, *p3 = NULL; - Signature *s = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - - p1 = UTHBuildPacketReal(buf1, sizeof(buf1), IPPROTO_UDP, - "192.168.1.5", "192.168.1.1", - 41424, 53); - p2 = UTHBuildPacketReal(buf1, sizeof(buf1), IPPROTO_UDP, - "192.168.1.5", "192.168.1.1", - 41424, 53); - p3 = UTHBuildPacketReal(buf1, sizeof(buf1), IPPROTO_UDP, - "192.168.1.5", "192.168.1.1", - 41424, 53); - - FLOW_INITIALIZE(&f); - f.flags |= FLOW_IPV4; - f.proto = IPPROTO_UDP; - f.protomap = FlowGetProtoMapping(f.proto); - f.alproto = ALPROTO_DNS; - - p1->flow = &f; - p1->flags |= PKT_HAS_FLOW; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->pcap_cnt = 1; - - p2->flow = &f; - p2->flags |= PKT_HAS_FLOW; - p2->flowflags |= FLOW_PKT_TOCLIENT; - p2->pcap_cnt = 2; - - p3->flow = &f; - p3->flags |= PKT_HAS_FLOW; - p3->flowflags |= FLOW_PKT_TOSERVER; - p3->pcap_cnt = 3; - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->mpm_matcher = mpm_default_matcher; - de_ctx->flags |= DE_QUIET; - - s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " - "(msg:\"Test dns_query option\"; " - "dns_query; content:\"google.com\"; nocase; sid:1;)"); - FAIL_IF_NULL(s); - s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " - "(msg:\"Test dns_query option\"; " - "dns_query; content:\"google.net\"; nocase; sid:2;)"); - FAIL_IF_NULL(s); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, - STREAM_TOSERVER, buf1, sizeof(buf1)); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FAIL; - } - - dns_state = f.alstate; - FAIL_IF_NULL(dns_state); - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p1); - - if (!(PacketAlertCheck(p1, 1))) { - printf("(p1) sig 1 didn't alert, but it should have: "); - FAIL; - } - if (PacketAlertCheck(p1, 2)) { - printf("(p1) sig 2 did alert, but it should not have: "); - FAIL; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOCLIENT, - buf2, sizeof(buf2)); - if (r != 0) { - printf("toserver client 1 returned %" PRId32 ", expected 0: ", r); - FAIL; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("(p2) sig 1 alerted, but it should not have: "); - FAIL; - } - if (PacketAlertCheck(p2, 2)) { - printf("(p2) sig 2 alerted, but it should not have: "); - FAIL; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, - buf3, sizeof(buf3)); - if (r != 0) { - printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - FAIL; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p3); - - if (PacketAlertCheck(p3, 1)) { - printf("(p3) sig 1 alerted, but it should not have: "); - FAIL; - } - if (!(PacketAlertCheck(p3, 2))) { - printf("(p3) sig 2 didn't alert, but it should have: "); - FAIL; - } - - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - FLOW_DESTROY(&f); - UTHFreePacket(p1); - UTHFreePacket(p2); - UTHFreePacket(p3); - PASS; -} - -/** \test simple google.com query matching (TCP) */ -static int DetectDnsQueryTest03(void) -{ - /* google.com */ - uint8_t buf[] = { 0x00, 28, - 0x10, 0x32, 0x01, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C, - 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, - 0x00, 0x10, 0x00, 0x01, }; - Flow f; - void *dns_state = NULL; - Packet *p = NULL; - Signature *s = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - TcpSession ssn; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - memset(&ssn, 0, sizeof(TcpSession)); - - p = UTHBuildPacketReal(buf, sizeof(buf), IPPROTO_TCP, - "192.168.1.5", "192.168.1.1", - 41424, 53); - - FLOW_INITIALIZE(&f); - f.protoctx = (void *)&ssn; - f.flags |= FLOW_IPV4; - f.proto = IPPROTO_TCP; - f.protomap = FlowGetProtoMapping(f.proto); - - p->flow = &f; - p->flags |= PKT_HAS_FLOW|PKT_STREAM_EST; - p->flowflags |= FLOW_PKT_TOSERVER|FLOW_PKT_ESTABLISHED; - f.alproto = ALPROTO_DNS; - - StreamTcpInitConfig(true); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->mpm_matcher = mpm_default_matcher; - de_ctx->flags |= DE_QUIET; - - s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " - "(msg:\"Test dns_query option\"; " - "dns_query; content:\"google\"; nocase; sid:1;)"); - FAIL_IF_NULL(s); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, - STREAM_TOSERVER, buf, sizeof(buf)); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FAIL; - } - - dns_state = f.alstate; - FAIL_IF_NULL(dns_state); - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!(PacketAlertCheck(p, 1))) { - printf("sig 1 didn't alert, but it should have: "); - FAIL; - } - - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - StreamTcpFreeConfig(true); - FLOW_DESTROY(&f); - UTHFreePacket(p); - PASS; -} - - -/** \test simple google.com query matching, pcre */ -static int DetectDnsQueryTest04(void) -{ - /* google.com */ - uint8_t buf[] = { 0x10, 0x32, 0x01, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C, - 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, - 0x00, 0x10, 0x00, 0x01, }; - Flow f; - void *dns_state = NULL; - Packet *p = NULL; - Signature *s = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - - p = UTHBuildPacketReal(buf, sizeof(buf), IPPROTO_UDP, - "192.168.1.5", "192.168.1.1", - 41424, 53); - - FLOW_INITIALIZE(&f); - f.flags |= FLOW_IPV4; - f.proto = IPPROTO_UDP; - f.protomap = FlowGetProtoMapping(f.proto); - - p->flow = &f; - p->flags |= PKT_HAS_FLOW; - p->flowflags |= FLOW_PKT_TOSERVER; - f.alproto = ALPROTO_DNS; - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->mpm_matcher = mpm_default_matcher; - de_ctx->flags |= DE_QUIET; - - s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " - "(msg:\"Test dns_query option\"; " - "dns_query; content:\"google\"; nocase; " - "pcre:\"/google\\.com$/i\"; sid:1;)"); - FAIL_IF_NULL(s); - s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " - "(msg:\"Test dns_query option\"; " - "dns_query; content:\"google\"; nocase; " - "pcre:\"/^\\.[a-z]{2,3}$/iR\"; sid:2;)"); - FAIL_IF_NULL(s); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, - STREAM_TOSERVER, buf, sizeof(buf)); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FAIL; - } - - dns_state = f.alstate; - FAIL_IF_NULL(dns_state); - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p); - - if (!(PacketAlertCheck(p, 1))) { - printf("sig 1 didn't alert, but it should have: "); - FAIL; - } - if (!(PacketAlertCheck(p, 2))) { - printf("sig 2 didn't alert, but it should have: "); - FAIL; - } - - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - FLOW_DESTROY(&f); - UTHFreePacket(p); - PASS; -} - -/** \test multi tx google.(com|net) query matching + - * app layer event */ -static int DetectDnsQueryTest05(void) -{ - /* google.com */ - uint8_t buf1[] = { 0x10, 0x32, 0x01, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C, - 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, - 0x00, 0x01, 0x00, 0x01, }; - - uint8_t buf2[] = { 0x10, 0x32, /* tx id */ - 0x81, 0x80|0x40, /* flags: resp, recursion desired, recursion available */ - 0x00, 0x01, /* 1 query */ - 0x00, 0x01, /* 1 answer */ - 0x00, 0x00, 0x00, 0x00, /* no auth rr, additional rr */ - /* query record */ - 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C, /* name */ - 0x65, 0x03, 0x63, 0x6F, 0x6D, 0x00, /* name cont */ - 0x00, 0x01, 0x00, 0x01, /* type a, class in */ - /* answer */ - 0xc0, 0x0c, /* ref to name in query above */ - 0x00, 0x01, 0x00, 0x01, /* type a, class in */ - 0x00, 0x01, 0x40, 0xef, /* ttl */ - 0x00, 0x04, /* data len */ - 0x01, 0x02, 0x03, 0x04 }; /* addr */ - - /* google.net */ - uint8_t buf3[] = { 0x11, 0x33, 0x01, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x06, 0x67, 0x6F, 0x6F, 0x67, 0x6C, - 0x65, 0x03, 0x6E, 0x65, 0x74, 0x00, - 0x00, 0x10, 0x00, 0x01, }; - Flow f; - void *dns_state = NULL; - Packet *p1 = NULL, *p2 = NULL, *p3 = NULL; - Signature *s = NULL; - ThreadVars tv; - DetectEngineThreadCtx *det_ctx = NULL; - AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc(); - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&f, 0, sizeof(Flow)); - - p1 = UTHBuildPacketReal(buf1, sizeof(buf1), IPPROTO_UDP, - "192.168.1.5", "192.168.1.1", - 41424, 53); - p2 = UTHBuildPacketReal(buf2, sizeof(buf2), IPPROTO_UDP, - "192.168.1.5", "192.168.1.1", - 41424, 53); - p3 = UTHBuildPacketReal(buf3, sizeof(buf3), IPPROTO_UDP, - "192.168.1.5", "192.168.1.1", - 41424, 53); - - FLOW_INITIALIZE(&f); - f.flags |= FLOW_IPV4; - f.proto = IPPROTO_UDP; - f.protomap = FlowGetProtoMapping(f.proto); - f.alproto = ALPROTO_DNS; - - p1->flow = &f; - p1->flags |= PKT_HAS_FLOW; - p1->flowflags |= FLOW_PKT_TOSERVER; - p1->pcap_cnt = 1; - - p2->flow = &f; - p2->flags |= PKT_HAS_FLOW; - p2->flowflags |= FLOW_PKT_TOCLIENT; - p2->pcap_cnt = 2; - - p3->flow = &f; - p3->flags |= PKT_HAS_FLOW; - p3->flowflags |= FLOW_PKT_TOSERVER; - p3->pcap_cnt = 3; - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - de_ctx->mpm_matcher = mpm_default_matcher; - de_ctx->flags |= DE_QUIET; - - s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " - "(msg:\"Test dns_query option\"; " - "dns_query; content:\"google.com\"; nocase; sid:1;)"); - FAIL_IF_NULL(s); - s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " - "(msg:\"Test dns_query option\"; " - "dns_query; content:\"google.net\"; nocase; sid:2;)"); - FAIL_IF_NULL(s); - s = DetectEngineAppendSig(de_ctx, "alert dns any any -> any any " - "(msg:\"Test Z flag event\"; " - "app-layer-event:dns.z_flag_set; sid:3;)"); - FAIL_IF_NULL(s); - - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx); - - int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, - STREAM_TOSERVER, buf1, sizeof(buf1)); - if (r != 0) { - printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r); - FAIL; - } - - dns_state = f.alstate; - FAIL_IF_NULL(dns_state); - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p1); - - if (!(PacketAlertCheck(p1, 1))) { - printf("(p1) sig 1 didn't alert, but it should have: "); - FAIL; - } - if (PacketAlertCheck(p1, 2)) { - printf("(p1) sig 2 did alert, but it should not have: "); - FAIL; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOCLIENT, - buf2, sizeof(buf2)); - if (r != 0) { - printf("toserver client 1 returned %" PRId32 ", expected 0\n", r); - FAIL; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p2); - - if (PacketAlertCheck(p2, 1)) { - printf("(p2) sig 1 alerted, but it should not have: "); - FAIL; - } - if (PacketAlertCheck(p2, 2)) { - printf("(p2) sig 2 alerted, but it should not have: "); - FAIL; - } - if (!(PacketAlertCheck(p2, 3))) { - printf("(p2) sig 3 didn't alert, but it should have: "); - FAIL; - } - - r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_DNS, STREAM_TOSERVER, - buf3, sizeof(buf3)); - if (r != 0) { - printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r); - FAIL; - } - - /* do detect */ - SigMatchSignatures(&tv, de_ctx, det_ctx, p3); - - if (PacketAlertCheck(p3, 1)) { - printf("(p3) sig 1 alerted, but it should not have: "); - FAIL; - } - if (!(PacketAlertCheck(p3, 2))) { - printf("(p3) sig 2 didn't alert, but it should have: "); - FAIL; - } - /** \todo should not alert, bug #839 - if (PacketAlertCheck(p3, 3)) { - printf("(p3) sig 3 did alert, but it should not have: "); - goto end; - } - */ - - if (alp_tctx != NULL) - AppLayerParserThreadCtxFree(alp_tctx); - if (det_ctx != NULL) - DetectEngineThreadCtxDeinit(&tv, det_ctx); - if (de_ctx != NULL) - SigGroupCleanup(de_ctx); - if (de_ctx != NULL) - DetectEngineCtxFree(de_ctx); - - FLOW_DESTROY(&f); - UTHFreePacket(p1); - UTHFreePacket(p2); - UTHFreePacket(p3); - PASS; -} - -static void DetectDnsQueryRegisterTests(void) -{ - UtRegisterTest("DetectDnsQueryTest01", DetectDnsQueryTest01); - UtRegisterTest("DetectDnsQueryTest02", DetectDnsQueryTest02); - UtRegisterTest("DetectDnsQueryTest03 -- tcp", DetectDnsQueryTest03); - UtRegisterTest("DetectDnsQueryTest04 -- pcre", DetectDnsQueryTest04); - UtRegisterTest("DetectDnsQueryTest05 -- app layer event", DetectDnsQueryTest05); -} -#endif diff --git a/src/detect-dns-query.h b/src/detect-dns-query.h deleted file mode 100644 index 33270432c2e2..000000000000 --- a/src/detect-dns-query.h +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 2013 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. - */ - -/** - * \file - * - * \author Victor Julien - */ - -#ifndef SURICATA_DETECT_DNS_QUERY_H -#define SURICATA_DETECT_DNS_QUERY_H - -void DetectDnsQueryRegister (void); - -#endif /* SURICATA_DETECT_DNS_QUERY_H */ diff --git a/src/detect-dns-rcode.c b/src/detect-dns-rcode.c deleted file mode 100644 index b6505b7c61be..000000000000 --- a/src/detect-dns-rcode.c +++ /dev/null @@ -1,85 +0,0 @@ -/* 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-rcode.h" -#include "rust.h" -#include "detect-engine-uint.h" - -static int dns_rcode_list_id = 0; - -static void DetectDnsRcodeFree(DetectEngineCtx *, void *ptr); - -static int DetectDnsRcodeSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - SCEnter(); - - if (DetectSignatureSetAppProto(s, ALPROTO_DNS) != 0) { - SCReturnInt(-1); - } - - void *detect = DetectU8Parse(str); - if (detect == NULL) { - SCLogError("failed to parse dns.rcode: %s", str); - SCReturnInt(-1); - } - - if (SigMatchAppendSMToList( - de_ctx, s, DETECT_DNS_RCODE, (SigMatchCtx *)detect, dns_rcode_list_id) == NULL) { - DetectDnsRcodeFree(de_ctx, detect); - SCReturnInt(-1); - } - - SCReturnInt(0); -} - -static void DetectDnsRcodeFree(DetectEngineCtx *de_ctx, void *ptr) -{ - SCEnter(); - if (ptr != NULL) { - rs_detect_u8_free(ptr); - } - SCReturn; -} - -static int DetectDnsRcodeMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, const SigMatchCtx *ctx) -{ - return SCDnsDetectRcodeMatch(txv, (void *)ctx, flags); -} - -void DetectDnsRcodeRegister(void) -{ - sigmatch_table[DETECT_DNS_RCODE].name = "dns.rcode"; - sigmatch_table[DETECT_DNS_RCODE].desc = "Match the DNS header rcode flag."; - sigmatch_table[DETECT_DNS_RCODE].url = "/rules/dns-keywords.html#dns-rcode"; - sigmatch_table[DETECT_DNS_RCODE].Setup = DetectDnsRcodeSetup; - sigmatch_table[DETECT_DNS_RCODE].Free = DetectDnsRcodeFree; - sigmatch_table[DETECT_DNS_RCODE].Match = NULL; - sigmatch_table[DETECT_DNS_RCODE].AppLayerTxMatch = DetectDnsRcodeMatch; - - DetectAppLayerInspectEngineRegister( - "dns.rcode", ALPROTO_DNS, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL); - - DetectAppLayerInspectEngineRegister( - "dns.rcode", ALPROTO_DNS, SIG_FLAG_TOCLIENT, 0, DetectEngineInspectGenericList, NULL); - - dns_rcode_list_id = DetectBufferTypeGetByName("dns.rcode"); -} \ No newline at end of file diff --git a/src/detect-dns-rcode.h b/src/detect-dns-rcode.h deleted file mode 100644 index cd4188eb365f..000000000000 --- a/src/detect-dns-rcode.h +++ /dev/null @@ -1,23 +0,0 @@ -/* 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 SURICATA_DETECT_DNS_RCODE_H -#define SURICATA_DETECT_DNS_RCODE_H - -void DetectDnsRcodeRegister(void); - -#endif /* SURICATA_DETECT_DNS_RCODE_H */ \ No newline at end of file diff --git a/src/detect-dns-rrtype.c b/src/detect-dns-rrtype.c deleted file mode 100644 index abfe9c7d5e73..000000000000 --- a/src/detect-dns-rrtype.c +++ /dev/null @@ -1,85 +0,0 @@ -/* 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_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 SCDnsDetectRrtypeMatch(txv, (void *)ctx, flags); -} - -void DetectDnsRrtypeRegister(void) -{ - sigmatch_table[DETECT_DNS_RRTYPE].name = "dns.rrtype"; - sigmatch_table[DETECT_DNS_RRTYPE].desc = "Match the DNS rrtype in message body."; - sigmatch_table[DETECT_DNS_RRTYPE].url = "/rules/dns-keywords.html#dns-rrtype"; - sigmatch_table[DETECT_DNS_RRTYPE].Setup = DetectDnsRrtypeSetup; - sigmatch_table[DETECT_DNS_RRTYPE].Free = DetectDnsRrtypeFree; - sigmatch_table[DETECT_DNS_RRTYPE].Match = NULL; - sigmatch_table[DETECT_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 deleted file mode 100644 index e2913b4a1c35..000000000000 --- a/src/detect-dns-rrtype.h +++ /dev/null @@ -1,23 +0,0 @@ -/* 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 SURICATA_DETECT_DNS_RRTYPE_H -#define SURICATA_DETECT_DNS_RRTYPE_H - -void DetectDnsRrtypeRegister(void); - -#endif /* SURICATA_DETECT_DNS_RRTYPE_H */ diff --git a/src/detect-engine-helper.c b/src/detect-engine-helper.c index 07ffb8177057..7ff43222dae8 100644 --- a/src/detect-engine-helper.c +++ b/src/detect-engine-helper.c @@ -121,6 +121,11 @@ int DetectHelperKeywordRegister(const SCSigTableElmt *kw) return DETECT_TBLSIZE_IDX - 1; } +void DetectHelperKeywordAliasRegister(int kwid, const char *alias) +{ + sigmatch_table[kwid].alias = alias; +} + int DetectHelperTransformRegister(const SCTransformTableElmt *kw) { if (DETECT_TBLSIZE_IDX >= DETECT_TBLSIZE) { diff --git a/src/detect-engine-helper.h b/src/detect-engine-helper.h index 39fa632ed28c..aaacca51a7e9 100644 --- a/src/detect-engine-helper.h +++ b/src/detect-engine-helper.h @@ -29,6 +29,7 @@ #include "rust.h" int DetectHelperKeywordRegister(const SCSigTableElmt *kw); +void DetectHelperKeywordAliasRegister(int kwid, const char *alias); int DetectHelperBufferRegister(const char *name, AppProto alproto, bool toclient, bool toserver); typedef bool (*SimpleGetTxBuffer)(void *, uint8_t, const uint8_t **, uint32_t *); diff --git a/src/detect-engine-register.c b/src/detect-engine-register.c index 658c17150aec..bfdd32bb4845 100644 --- a/src/detect-engine-register.c +++ b/src/detect-engine-register.c @@ -47,12 +47,6 @@ #include "detect-engine-payload.h" #include "detect-engine-dcepayload.h" -#include "detect-dns-opcode.h" -#include "detect-dns-rcode.h" -#include "detect-dns-rrtype.h" -#include "detect-dns-query.h" -#include "detect-dns-answer-name.h" -#include "detect-dns-query-name.h" #include "detect-tls-sni.h" #include "detect-tls-certs.h" #include "detect-tls-cert-fingerprint.h" @@ -553,12 +547,6 @@ void SigTableSetup(void) DetectHttpStatCodeRegister(); DetectHttp2Register(); - DetectDnsQueryRegister(); - DetectDnsOpcodeRegister(); - DetectDnsRcodeRegister(); - DetectDnsRrtypeRegister(); - DetectDnsAnswerNameRegister(); - DetectDnsQueryNameRegister(); DetectModbusRegister(); DetectDNP3Register(); @@ -743,6 +731,14 @@ void SigTableSetup(void) ScDetectSipRegister(); ScDetectTemplateRegister(); ScDetectLdapRegister(); + SCDetectDNSRegister(); + /* For lua : register these generic engines from here for now */ + DetectAppLayerInspectEngineRegister( + "dns_request", ALPROTO_DNS, SIG_FLAG_TOSERVER, 1, DetectEngineInspectGenericList, NULL); + DetectAppLayerInspectEngineRegister("dns_response", ALPROTO_DNS, SIG_FLAG_TOCLIENT, 1, + DetectEngineInspectGenericList, NULL); + DetectBufferTypeSetDescriptionByName("dns_request", "dns requests"); + DetectBufferTypeSetDescriptionByName("dns_response", "dns responses"); for (size_t i = 0; i < preregistered_callbacks_nb; i++) { PreregisteredCallbacks[i](); diff --git a/src/detect-engine-register.h b/src/detect-engine-register.h index e3a57b4951a9..5e850b825506 100644 --- a/src/detect-engine-register.h +++ b/src/detect-engine-register.h @@ -243,12 +243,6 @@ enum DetectKeywordId { DETECT_L3PROTO, DETECT_IPREP, - DETECT_DNS_QUERY, - DETECT_DNS_OPCODE, - DETECT_DNS_RCODE, - DETECT_DNS_RRTYPE, - DETECT_DNS_ANSWER_NAME, - DETECT_DNS_QUERY_NAME, DETECT_TLS_SNI, DETECT_TLS_CERTS, DETECT_TLS_CERT_ISSUER,