"c_void": "void",
"std::os::raw::c_char": "char",
+ "c_char": "char",
"std::os::raw::c_int": "int",
"c_int": "int",
"std::os::raw::int8_t": "int8_t",
"CLuaState": "lua_State",
"Store": "Store",
"AppProto": "AppProto",
+ "DetectDnsOpcode": "void *",
}
def convert_type(rs_type):
--- /dev/null
+/* 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.
+ */
+
+use super::dns::DNSTransaction;
+use crate::core;
+use std::ffi::CStr;
+use std::os::raw::{c_char, c_void};
+
+#[derive(Debug, PartialEq)]
+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().or_else(|_| Err(()))?;
+ return Ok(DetectDnsOpcode {
+ negate: negated,
+ opcode: code,
+ });
+ }
+ }
+ }
+ Err(())
+}
+
+/// 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,
+) -> u8 {
+ let header_flags = if flags & core::STREAM_TOSERVER != 0 {
+ if let Some(request) = &tx.request {
+ request.header.flags
+ } else {
+ return 0;
+ }
+ } else if flags & core::STREAM_TOCLIENT != 0 {
+ if let Some(response) = &tx.response {
+ response.header.flags
+ } else {
+ return 0;
+ }
+ } else {
+ // Not to server or to client??
+ return 0;
+ };
+
+ if match_opcode(detect, header_flags) {
+ 1
+ } else {
+ 0
+ }
+}
+
+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) => std::mem::transmute(Box::new(detect)),
+ Err(_) => std::ptr::null_mut(),
+ }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn rs_dns_detect_opcode_free(ptr: *mut c_void) {
+ if ptr != std::ptr::null_mut() {
+ let _: Box<DetectDnsOpcode> = std::mem::transmute(ptr);
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[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
+ })
+ );
+ assert_eq!(
+ parse_opcode("!123"),
+ Ok(DetectDnsOpcode {
+ negate: true,
+ opcode: 123
+ })
+ );
+ assert_eq!(
+ parse_opcode("!123"),
+ Ok(DetectDnsOpcode {
+ negate: true,
+ opcode: 123
+ })
+ );
+ assert_eq!(parse_opcode(""), Err(()));
+ assert_eq!(parse_opcode("!"), Err(()));
+ assert_eq!(parse_opcode("! "), Err(()));
+ assert_eq!(parse_opcode("!asdf"), Err(()));
+ }
+
+ #[test]
+ fn test_match_opcode() {
+ assert_eq!(
+ match_opcode(
+ &DetectDnsOpcode {
+ negate: false,
+ opcode: 0,
+ },
+ 0b0000_0000_0000_0000,
+ ),
+ true
+ );
+
+ assert_eq!(
+ match_opcode(
+ &DetectDnsOpcode {
+ negate: true,
+ opcode: 0,
+ },
+ 0b0000_0000_0000_0000,
+ ),
+ false
+ );
+
+ assert_eq!(
+ match_opcode(
+ &DetectDnsOpcode {
+ negate: false,
+ opcode: 4,
+ },
+ 0b0010_0000_0000_0000,
+ ),
+ true
+ );
+
+ assert_eq!(
+ match_opcode(
+ &DetectDnsOpcode {
+ negate: true,
+ opcode: 4,
+ },
+ 0b0010_0000_0000_0000,
+ ),
+ false
+ );
+ }
+}
pub mod parser;
pub mod dns;
pub mod log;
+pub mod detect;
#[cfg(feature = "lua")]
pub mod lua;
detect-detection-filter.c detect-detection-filter.h \
detect-distance.c detect-distance.h \
detect-dnp3.c detect-dnp3.h \
+detect-dns-opcode.c detect-dns-opcode.h \
detect-dns-query.c detect-dns-query.h \
detect-tls-ja3-hash.c detect-tls-ja3-hash.h \
detect-tls-ja3-string.c detect-tls-ja3-string.h \
--- /dev/null
+/* 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-dns-opcode.h"
+#include "app-layer-dns-common.h"
+#include "rust-dns-detect-gen.h"
+
+static int dns_opcode_list_id = 0;
+
+static void DetectDnsOpcodeFree(void *ptr);
+
+static int DetectDnsOpcodeSetup(DetectEngineCtx *de_ctx, Signature *s,
+ const char *str)
+{
+ SCEnter();
+
+ if (DetectSignatureSetAppProto(s, ALPROTO_DNS) != 0) {
+ return -1;
+ }
+
+ void *detect = rs_detect_dns_opcode_parse(str);
+ if (detect == NULL) {
+ SCLogNotice("Failed to parse dns.opcode: %s", str);
+ return -1;
+ }
+
+ SigMatch *sm = SigMatchAlloc();
+ if (unlikely(sm == NULL)) {
+ goto error;
+ }
+
+ sm->type = DETECT_AL_DNS_OPCODE;
+ sm->ctx = (void *)detect;
+ SigMatchAppendSMToList(s, sm, dns_opcode_list_id);
+
+ SCReturnInt(0);
+
+error:
+ DetectDnsOpcodeFree(detect);
+ SCReturnInt(-1);
+}
+
+static void DetectDnsOpcodeFree(void *ptr)
+{
+ SCEnter();
+ if (ptr != NULL) {
+ rs_dns_detect_opcode_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 rs_dns_opcode_match(txv, (void *)ctx, flags);
+}
+
+static int DetectEngineInspectRequestGenericDnsOpcode(ThreadVars *tv,
+ DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx,
+ const Signature *s, const SigMatchData *smd,
+ Flow *f, uint8_t flags, void *alstate,
+ void *txv, uint64_t tx_id)
+{
+ return DetectEngineInspectGenericList(tv, de_ctx, det_ctx, s, smd,
+ f, flags, alstate, txv, tx_id);
+}
+
+void DetectDnsOpcodeRegister(void)
+{
+ sigmatch_table[DETECT_AL_DNS_OPCODE].name = "dns.opcode";
+ sigmatch_table[DETECT_AL_DNS_OPCODE].desc = "Match the DNS header opcode flag.";
+ sigmatch_table[DETECT_AL_DNS_OPCODE].Setup = DetectDnsOpcodeSetup;
+ sigmatch_table[DETECT_AL_DNS_OPCODE].Free = DetectDnsOpcodeFree;
+ sigmatch_table[DETECT_AL_DNS_OPCODE].Match = NULL;
+ sigmatch_table[DETECT_AL_DNS_OPCODE].AppLayerTxMatch =
+ DetectDnsOpcodeMatch;
+
+ DetectAppLayerInspectEngineRegister("dns.opcode",
+ ALPROTO_DNS, SIG_FLAG_TOSERVER, 0,
+ DetectEngineInspectRequestGenericDnsOpcode);
+
+ DetectAppLayerInspectEngineRegister("dns.opcode",
+ ALPROTO_DNS, SIG_FLAG_TOCLIENT, 0,
+ DetectEngineInspectRequestGenericDnsOpcode);
+
+ dns_opcode_list_id = DetectBufferTypeGetByName("dns.opcode");
+}
--- /dev/null
+/* 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 __DETECT_DNS_OPCODE_H__
+#define __DETECT_DNS_OPCODE_H__
+
+void DetectDnsOpcodeRegister(void);
+
+#endif /* __DETECT_DNS_OPCODE_H__ */
#include "detect-engine-payload.h"
#include "detect-engine-dcepayload.h"
+#include "detect-dns-opcode.h"
#include "detect-dns-query.h"
#include "detect-tls-sni.h"
#include "detect-tls-certs.h"
DetectHttpStatCodeRegister();
DetectDnsQueryRegister();
+ DetectDnsOpcodeRegister();
DetectModbusRegister();
DetectCipServiceRegister();
DetectEnipCommandRegister();
DETECT_IPREP,
DETECT_AL_DNS_QUERY,
+ DETECT_AL_DNS_OPCODE,
DETECT_AL_TLS_SNI,
DETECT_AL_TLS_CERTS,
DETECT_AL_TLS_CERT_ISSUER,