From f6e1a202159720adc70e90bc413d3d3ae40cff6e Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Thu, 30 Nov 2023 14:32:08 +0100 Subject: [PATCH] detect: dns.opcode as first-class integer Ticket: 5446 That means it can accept ranges --- doc/userguide/rules/dns-keywords.rst | 11 ++ rust/src/detect/uint.rs | 2 +- rust/src/dns/detect.rs | 167 +++++++++------------------ src/detect-dns-opcode.c | 5 +- 4 files changed, 67 insertions(+), 118 deletions(-) diff --git a/doc/userguide/rules/dns-keywords.rst b/doc/userguide/rules/dns-keywords.rst index a514ae2519..005164dfd1 100644 --- a/doc/userguide/rules/dns-keywords.rst +++ b/doc/userguide/rules/dns-keywords.rst @@ -28,12 +28,15 @@ dns.opcode This keyword matches on the **opcode** found in the DNS header flags. +dns.opcode uses an :ref:`unsigned 8-bit integer `. + Syntax ~~~~~~ :: dns.opcode:[!] + dns.opcode:[!]- Examples ~~~~~~~~ @@ -46,6 +49,14 @@ Match on DNS requests where the **opcode** is NOT 0:: dns.opcode:!0; +Match on DNS requests where the **opcode** is between 7 and 15, exclusively: + + dns.opcode:7-15; + +Match on DNS requests where the **opcode** is not between 7 and 15: + + dns.opcode:!7-15; + dns.query --------- diff --git a/rust/src/detect/uint.rs b/rust/src/detect/uint.rs index 7ce86d57f3..5b28830cea 100644 --- a/rust/src/detect/uint.rs +++ b/rust/src/detect/uint.rs @@ -42,7 +42,7 @@ pub enum DetectUintMode { DetectUintModeNegBitmask, } -#[derive(Debug)] +#[derive(Debug, PartialEq)] #[repr(C)] pub struct DetectUintData { pub arg1: T, diff --git a/rust/src/dns/detect.rs b/rust/src/dns/detect.rs index 5d9d945be0..452d4e8380 100644 --- a/rust/src/dns/detect.rs +++ b/rust/src/dns/detect.rs @@ -16,49 +16,15 @@ */ use super::dns::DNSTransaction; -use crate::core::*; -use std::ffi::CStr; -use std::os::raw::{c_char, c_void}; - -#[derive(Debug, PartialEq, Eq)] -pub struct DetectDnsOpcode { - negate: bool, - opcode: u8, -} - -/// Parse a DNS opcode argument returning the code and if it is to be -/// negated or not. -/// -/// For now only an indication that an error occurred is returned, not -/// the details of the error. -fn parse_opcode(opcode: &str) -> Result { - let mut negated = false; - for (i, c) in opcode.chars().enumerate() { - match c { - ' ' | '\t' => { - continue; - } - '!' => { - negated = true; - } - _ => { - let code: u8 = opcode[i..].parse().map_err(|_| ())?; - return Ok(DetectDnsOpcode { - negate: negated, - opcode: code, - }); - } - } - } - Err(()) -} +use crate::core::Direction; +use crate::detect::uint::{detect_match_uint, DetectUintData}; /// Perform the DNS opcode match. /// /// 1 will be returned on match, otherwise 0 will be returned. #[no_mangle] pub extern "C" fn rs_dns_opcode_match( - tx: &mut DNSTransaction, detect: &mut DetectDnsOpcode, flags: u8, + tx: &mut DNSTransaction, detect: &mut DetectUintData, flags: u8, ) -> u8 { let header_flags = if flags & Direction::ToServer as u8 != 0 { if let Some(request) = &tx.request { @@ -76,116 +42,87 @@ pub extern "C" fn rs_dns_opcode_match( // Not to server or to client?? return 0; }; + let opcode = ((header_flags >> 11) & 0xf) as u8; - match_opcode(detect, header_flags).into() -} - -fn match_opcode(detect: &DetectDnsOpcode, flags: u16) -> bool { - let opcode = ((flags >> 11) & 0xf) as u8; - if detect.negate { - detect.opcode != opcode - } else { - detect.opcode == opcode - } -} - -#[no_mangle] -pub unsafe extern "C" fn rs_detect_dns_opcode_parse(carg: *const c_char) -> *mut c_void { - if carg.is_null() { - return std::ptr::null_mut(); - } - let arg = match CStr::from_ptr(carg).to_str() { - Ok(arg) => arg, - _ => { - return std::ptr::null_mut(); - } - }; - - match parse_opcode(arg) { - Ok(detect) => Box::into_raw(Box::new(detect)) as *mut _, - Err(_) => std::ptr::null_mut(), - } -} - -#[no_mangle] -pub unsafe extern "C" fn rs_dns_detect_opcode_free(ptr: *mut c_void) { - if !ptr.is_null() { - std::mem::drop(Box::from_raw(ptr as *mut DetectDnsOpcode)); + if detect_match_uint(detect, opcode) { + return 1; } + return 0; } #[cfg(test)] mod test { use super::*; + use crate::detect::uint::{detect_parse_uint, DetectUintMode}; #[test] fn parse_opcode_good() { assert_eq!( - parse_opcode("1"), - Ok(DetectDnsOpcode { - negate: false, - opcode: 1 - }) - ); - assert_eq!( - parse_opcode("123"), - Ok(DetectDnsOpcode { - negate: false, - opcode: 123 - }) + detect_parse_uint::("1").unwrap().1, + DetectUintData { + mode: DetectUintMode::DetectUintModeEqual, + arg1: 1, + arg2: 0, + } ); assert_eq!( - parse_opcode("!123"), - Ok(DetectDnsOpcode { - negate: true, - opcode: 123 - }) + detect_parse_uint::("123").unwrap().1, + DetectUintData { + mode: DetectUintMode::DetectUintModeEqual, + arg1: 123, + arg2: 0, + } ); assert_eq!( - parse_opcode("!123"), - Ok(DetectDnsOpcode { - negate: true, - opcode: 123 - }) + detect_parse_uint::("!123").unwrap().1, + DetectUintData { + mode: DetectUintMode::DetectUintModeNe, + arg1: 123, + arg2: 0, + } ); - assert_eq!(parse_opcode(""), Err(())); - assert_eq!(parse_opcode("!"), Err(())); - assert_eq!(parse_opcode("! "), Err(())); - assert_eq!(parse_opcode("!asdf"), Err(())); + 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()); } #[test] fn test_match_opcode() { - assert!(match_opcode( - &DetectDnsOpcode { - negate: false, - opcode: 0, + assert!(detect_match_uint( + &DetectUintData { + mode: DetectUintMode::DetectUintModeEqual, + arg1: 0, + arg2: 0, }, 0b0000_0000_0000_0000, )); - assert!(!match_opcode( - &DetectDnsOpcode { - negate: true, - opcode: 0, + assert!(!detect_match_uint( + &DetectUintData { + mode: DetectUintMode::DetectUintModeNe, + arg1: 0, + arg2: 0, }, 0b0000_0000_0000_0000, )); - assert!(match_opcode( - &DetectDnsOpcode { - negate: false, - opcode: 4, + assert!(detect_match_uint( + &DetectUintData { + mode: DetectUintMode::DetectUintModeEqual, + arg1: 4, + arg2: 0, }, - 0b0010_0000_0000_0000, + ((0b0010_0000_0000_0000 >> 11) & 0xf) as u8, )); - assert!(!match_opcode( - &DetectDnsOpcode { - negate: true, - opcode: 4, + assert!(!detect_match_uint( + &DetectUintData { + mode: DetectUintMode::DetectUintModeNe, + arg1: 4, + arg2: 0, }, - 0b0010_0000_0000_0000, + ((0b0010_0000_0000_0000 >> 11) & 0xf) as u8, )); } } diff --git a/src/detect-dns-opcode.c b/src/detect-dns-opcode.c index 4baee19b8c..f5dcab700f 100644 --- a/src/detect-dns-opcode.c +++ b/src/detect-dns-opcode.c @@ -19,6 +19,7 @@ #include "detect-parse.h" #include "detect-engine.h" +#include "detect-engine-uint.h" #include "detect-dns-opcode.h" #include "rust.h" @@ -35,7 +36,7 @@ static int DetectDnsOpcodeSetup(DetectEngineCtx *de_ctx, Signature *s, return -1; } - void *detect = rs_detect_dns_opcode_parse(str); + void *detect = DetectU8Parse(str); if (detect == NULL) { SCLogError("failed to parse dns.opcode: %s", str); return -1; @@ -57,7 +58,7 @@ static void DetectDnsOpcodeFree(DetectEngineCtx *de_ctx, void *ptr) { SCEnter(); if (ptr != NULL) { - rs_dns_detect_opcode_free(ptr); + rs_detect_u8_free(ptr); } SCReturn; }