detect: dns.opcode as first-class integer

Ticket: 5446

That means it can accept ranges
pull/10321/head
Philippe Antoine 2 years ago committed by Victor Julien
parent 8fc0faf5c2
commit f6e1a20215

@ -28,12 +28,15 @@ dns.opcode
This keyword matches on the **opcode** found in the DNS header flags. This keyword matches on the **opcode** found in the DNS header flags.
dns.opcode uses an :ref:`unsigned 8-bit integer <rules-integer-keywords>`.
Syntax Syntax
~~~~~~ ~~~~~~
:: ::
dns.opcode:[!]<number> dns.opcode:[!]<number>
dns.opcode:[!]<number1>-<number2>
Examples Examples
~~~~~~~~ ~~~~~~~~
@ -46,6 +49,14 @@ Match on DNS requests where the **opcode** is NOT 0::
dns.opcode:!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 dns.query
--------- ---------

@ -42,7 +42,7 @@ pub enum DetectUintMode {
DetectUintModeNegBitmask, DetectUintModeNegBitmask,
} }
#[derive(Debug)] #[derive(Debug, PartialEq)]
#[repr(C)] #[repr(C)]
pub struct DetectUintData<T> { pub struct DetectUintData<T> {
pub arg1: T, pub arg1: T,

@ -16,49 +16,15 @@
*/ */
use super::dns::DNSTransaction; use super::dns::DNSTransaction;
use crate::core::*; use crate::core::Direction;
use std::ffi::CStr; use crate::detect::uint::{detect_match_uint, DetectUintData};
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<DetectDnsOpcode, ()> {
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(())
}
/// Perform the DNS opcode match. /// Perform the DNS opcode match.
/// ///
/// 1 will be returned on match, otherwise 0 will be returned. /// 1 will be returned on match, otherwise 0 will be returned.
#[no_mangle] #[no_mangle]
pub extern "C" fn rs_dns_opcode_match( pub extern "C" fn rs_dns_opcode_match(
tx: &mut DNSTransaction, detect: &mut DetectDnsOpcode, flags: u8, tx: &mut DNSTransaction, detect: &mut DetectUintData<u8>, flags: u8,
) -> u8 { ) -> u8 {
let header_flags = if flags & Direction::ToServer as u8 != 0 { let header_flags = if flags & Direction::ToServer as u8 != 0 {
if let Some(request) = &tx.request { if let Some(request) = &tx.request {
@ -76,116 +42,87 @@ pub extern "C" fn rs_dns_opcode_match(
// Not to server or to client?? // Not to server or to client??
return 0; return 0;
}; };
let opcode = ((header_flags >> 11) & 0xf) as u8;
match_opcode(detect, header_flags).into() if detect_match_uint(detect, opcode) {
} return 1;
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));
} }
return 0;
} }
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::*;
use crate::detect::uint::{detect_parse_uint, DetectUintMode};
#[test] #[test]
fn parse_opcode_good() { fn parse_opcode_good() {
assert_eq!( assert_eq!(
parse_opcode("1"), detect_parse_uint::<u8>("1").unwrap().1,
Ok(DetectDnsOpcode { DetectUintData {
negate: false, mode: DetectUintMode::DetectUintModeEqual,
opcode: 1 arg1: 1,
}) arg2: 0,
); }
assert_eq!(
parse_opcode("123"),
Ok(DetectDnsOpcode {
negate: false,
opcode: 123
})
); );
assert_eq!( assert_eq!(
parse_opcode("!123"), detect_parse_uint::<u8>("123").unwrap().1,
Ok(DetectDnsOpcode { DetectUintData {
negate: true, mode: DetectUintMode::DetectUintModeEqual,
opcode: 123 arg1: 123,
}) arg2: 0,
}
); );
assert_eq!( assert_eq!(
parse_opcode("!123"), detect_parse_uint::<u8>("!123").unwrap().1,
Ok(DetectDnsOpcode { DetectUintData {
negate: true, mode: DetectUintMode::DetectUintModeNe,
opcode: 123 arg1: 123,
}) arg2: 0,
}
); );
assert_eq!(parse_opcode(""), Err(())); assert!(detect_parse_uint::<u8>("").is_err());
assert_eq!(parse_opcode("!"), Err(())); assert!(detect_parse_uint::<u8>("!").is_err());
assert_eq!(parse_opcode("! "), Err(())); assert!(detect_parse_uint::<u8>("! ").is_err());
assert_eq!(parse_opcode("!asdf"), Err(())); assert!(detect_parse_uint::<u8>("!asdf").is_err());
} }
#[test] #[test]
fn test_match_opcode() { fn test_match_opcode() {
assert!(match_opcode( assert!(detect_match_uint(
&DetectDnsOpcode { &DetectUintData {
negate: false, mode: DetectUintMode::DetectUintModeEqual,
opcode: 0, arg1: 0,
arg2: 0,
}, },
0b0000_0000_0000_0000, 0b0000_0000_0000_0000,
)); ));
assert!(!match_opcode( assert!(!detect_match_uint(
&DetectDnsOpcode { &DetectUintData {
negate: true, mode: DetectUintMode::DetectUintModeNe,
opcode: 0, arg1: 0,
arg2: 0,
}, },
0b0000_0000_0000_0000, 0b0000_0000_0000_0000,
)); ));
assert!(match_opcode( assert!(detect_match_uint(
&DetectDnsOpcode { &DetectUintData {
negate: false, mode: DetectUintMode::DetectUintModeEqual,
opcode: 4, arg1: 4,
arg2: 0,
}, },
0b0010_0000_0000_0000, ((0b0010_0000_0000_0000 >> 11) & 0xf) as u8,
)); ));
assert!(!match_opcode( assert!(!detect_match_uint(
&DetectDnsOpcode { &DetectUintData {
negate: true, mode: DetectUintMode::DetectUintModeNe,
opcode: 4, arg1: 4,
arg2: 0,
}, },
0b0010_0000_0000_0000, ((0b0010_0000_0000_0000 >> 11) & 0xf) as u8,
)); ));
} }
} }

@ -19,6 +19,7 @@
#include "detect-parse.h" #include "detect-parse.h"
#include "detect-engine.h" #include "detect-engine.h"
#include "detect-engine-uint.h"
#include "detect-dns-opcode.h" #include "detect-dns-opcode.h"
#include "rust.h" #include "rust.h"
@ -35,7 +36,7 @@ static int DetectDnsOpcodeSetup(DetectEngineCtx *de_ctx, Signature *s,
return -1; return -1;
} }
void *detect = rs_detect_dns_opcode_parse(str); void *detect = DetectU8Parse(str);
if (detect == NULL) { if (detect == NULL) {
SCLogError("failed to parse dns.opcode: %s", str); SCLogError("failed to parse dns.opcode: %s", str);
return -1; return -1;
@ -57,7 +58,7 @@ static void DetectDnsOpcodeFree(DetectEngineCtx *de_ctx, void *ptr)
{ {
SCEnter(); SCEnter();
if (ptr != NULL) { if (ptr != NULL) {
rs_dns_detect_opcode_free(ptr); rs_detect_u8_free(ptr);
} }
SCReturn; SCReturn;
} }

Loading…
Cancel
Save