From 91862e3953b83d69a6e8074faece98be5bd91b56 Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Wed, 2 Oct 2024 15:28:56 +0200 Subject: [PATCH 1/3] transforms: move strip_whitespace to rust Ticket: 7229 --- rust/cbindgen.toml | 1 + rust/src/detect/mod.rs | 1 + rust/src/detect/transforms/mod.rs | 49 ++++ .../src/detect/transforms/strip_whitespace.rs | 136 ++++++++++++ src/Makefile.am | 2 - src/detect-engine-helper.c | 37 ++++ src/detect-engine-helper.h | 4 + src/detect-engine-register.c | 1 - src/detect-engine.c | 16 +- src/detect-engine.h | 3 +- src/detect-transform-strip-whitespace.c | 209 ------------------ src/detect-transform-strip-whitespace.h | 30 --- 12 files changed, 244 insertions(+), 245 deletions(-) create mode 100644 rust/src/detect/transforms/mod.rs create mode 100644 rust/src/detect/transforms/strip_whitespace.rs delete mode 100644 src/detect-transform-strip-whitespace.c delete mode 100644 src/detect-transform-strip-whitespace.h diff --git a/rust/cbindgen.toml b/rust/cbindgen.toml index b277e00506d8..eac6aa737760 100644 --- a/rust/cbindgen.toml +++ b/rust/cbindgen.toml @@ -83,6 +83,7 @@ include = [ "QuicTransaction", "FtpEvent", "SCSigTableElmt", + "SCTransformTableElmt", ] # A list of items to not include in the generated bindings diff --git a/rust/src/detect/mod.rs b/rust/src/detect/mod.rs index b09af4fb98ed..276094eb3f6d 100644 --- a/rust/src/detect/mod.rs +++ b/rust/src/detect/mod.rs @@ -25,6 +25,7 @@ pub mod parser; pub mod requires; pub mod stream_size; pub mod transform_base64; +pub mod transforms; pub mod uint; pub mod uri; pub mod tojson; diff --git a/rust/src/detect/transforms/mod.rs b/rust/src/detect/transforms/mod.rs new file mode 100644 index 000000000000..9e997f6b4674 --- /dev/null +++ b/rust/src/detect/transforms/mod.rs @@ -0,0 +1,49 @@ +/* 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. + */ + +//! Module for transforms + +use std::os::raw::{c_char, c_int, c_void}; + +pub mod strip_whitespace; + +#[repr(C)] +#[allow(non_snake_case)] +pub struct SCTransformTableElmt { + pub name: *const c_char, + pub desc: *const c_char, + pub url: *const c_char, + pub flags: u16, + pub Setup: unsafe extern "C" fn(de: *mut c_void, s: *mut c_void, raw: *const c_char) -> c_int, + pub Free: Option, + pub Transform: unsafe extern "C" fn(inspect_buf: *mut c_void, options: *mut c_void), + pub TransformValidate: + Option bool>, +} + +/// cbindgen:ignore +extern "C" { + pub fn DetectSignatureAddTransform( + s: *mut c_void, transform_id: c_int, ctx: *mut c_void, + ) -> c_int; + pub fn InspectionBufferPtr(buf: *const c_void) -> *const u8; + pub fn InspectionBufferLength(buf: *const c_void) -> u32; + pub fn InspectionBufferCopy(ibuf: *const c_void, buf: *const u8, buf_len: u32); + pub fn DetectHelperTransformRegister(kw: *const SCTransformTableElmt) -> c_int; + pub fn InspectionBufferCheckAndExpand(ibuf: *const c_void, buf_len: u32) -> *mut u8; + pub fn InspectionBufferTruncate(ibuf: *const c_void, buf_len: u32); +} diff --git a/rust/src/detect/transforms/strip_whitespace.rs b/rust/src/detect/transforms/strip_whitespace.rs new file mode 100644 index 000000000000..2fb8599a5365 --- /dev/null +++ b/rust/src/detect/transforms/strip_whitespace.rs @@ -0,0 +1,136 @@ +/* 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. + */ + +use super::{ + DetectHelperTransformRegister, DetectSignatureAddTransform, InspectionBufferCheckAndExpand, + InspectionBufferLength, InspectionBufferPtr, InspectionBufferTruncate, SCTransformTableElmt, +}; +use crate::detect::SIGMATCH_NOOPT; + +use std::os::raw::{c_int, c_void}; +use std::ptr; + +static mut G_TRANSFORM_STRIP_WHITESPACE_ID: c_int = 0; + +#[no_mangle] +unsafe extern "C" fn strip_whitespace_setup( + _de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + return DetectSignatureAddTransform(s, G_TRANSFORM_STRIP_WHITESPACE_ID, ptr::null_mut()); +} + +fn strip_whitespace_transform_do(input: &[u8], output: &mut [u8]) -> u32 { + let mut nb = 0; + // seems faster than writing one byte at a time via + // for (i, o) in input.iter().filter(|c| !matches!(*c, b'\t' | b'\n' | b'\x0B' | b'\x0C' | b'\r' | b' ')).zip(output) + for subslice in input.split(|c| matches!(*c, b'\t' | b'\n' | b'\x0B' | b'\x0C' | b'\r' | b' ')) + { + output[nb..nb + subslice.len()].copy_from_slice(subslice); + nb += subslice.len(); + } + return nb as u32; +} + +#[no_mangle] +unsafe extern "C" fn strip_whitespace_transform(buffer: *mut c_void, _ctx: *mut c_void) { + let input = InspectionBufferPtr(buffer); + let input_len = InspectionBufferLength(buffer); + if input.is_null() || input_len == 0 { + return; + } + let input = build_slice!(input, input_len as usize); + + let output = InspectionBufferCheckAndExpand(buffer, input_len); + if output.is_null() { + // allocation failure + return; + } + let output = std::slice::from_raw_parts_mut(output, input_len as usize); + + let output_len = strip_whitespace_transform_do(input, output); + + InspectionBufferTruncate(buffer, output_len); +} + +#[no_mangle] +unsafe extern "C" fn strip_whitespace_validate( + content: *const u8, len: u16, _ctx: *mut c_void, +) -> bool { + let input = build_slice!(content, len as usize); + for &c in input { + if matches!(c, b'\t' | b'\n' | b'\x0B' | b'\x0C' | b'\r' | b' ') { + return false; + } + } + return true; +} + +#[no_mangle] +pub unsafe extern "C" fn DetectTransformStripWhitespaceRegister() { + let kw = SCTransformTableElmt { + name: b"strip_whitespace\0".as_ptr() as *const libc::c_char, + desc: b"modify buffer to strip whitespace before inspection\0".as_ptr() + as *const libc::c_char, + url: b"/rules/transforms.html#strip-whitespace\0".as_ptr() as *const libc::c_char, + Setup: strip_whitespace_setup, + flags: SIGMATCH_NOOPT, + Transform: strip_whitespace_transform, + Free: None, + TransformValidate: Some(strip_whitespace_validate), + }; + unsafe { + G_TRANSFORM_STRIP_WHITESPACE_ID = DetectHelperTransformRegister(&kw); + if G_TRANSFORM_STRIP_WHITESPACE_ID < 0 { + SCLogWarning!("Failed registering transform strip_whitespace"); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_strip_whitespace_transform() { + let buf = b" A B C D "; + let mut out = vec![0; buf.len()]; + let exp = b"ABCD"; + assert_eq!( + strip_whitespace_transform_do(buf, &mut out), + exp.len() as u32 + ); + assert_eq!(&out[..exp.len()], exp); + + let buf = b"EFGH"; + let mut out = vec![0; buf.len()]; + let exp = b"EFGH"; + assert_eq!( + strip_whitespace_transform_do(buf, &mut out), + exp.len() as u32 + ); + assert_eq!(&out[..exp.len()], exp); + + let buf = b"I \t J"; + let mut out = vec![0; buf.len()]; + let exp = b"IJ"; + assert_eq!( + strip_whitespace_transform_do(buf, &mut out), + exp.len() as u32 + ); + assert_eq!(&out[..exp.len()], exp); + } +} diff --git a/src/Makefile.am b/src/Makefile.am index e409ce492ca4..0fb15e413564 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -316,7 +316,6 @@ noinst_HEADERS = \ detect-transform-sha1.h \ detect-transform-sha256.h \ detect-transform-strip-pseudo-headers.h \ - detect-transform-strip-whitespace.h \ detect-transform-urldecode.h \ detect-transform-xor.h \ detect-ttl.h \ @@ -889,7 +888,6 @@ libsuricata_c_a_SOURCES = \ detect-transform-sha1.c \ detect-transform-sha256.c \ detect-transform-strip-pseudo-headers.c \ - detect-transform-strip-whitespace.c \ detect-transform-urldecode.c \ detect-transform-xor.c \ detect-ttl.c \ diff --git a/src/detect-engine-helper.c b/src/detect-engine-helper.c index 740fec7618c8..07ffb8177057 100644 --- a/src/detect-engine-helper.c +++ b/src/detect-engine-helper.c @@ -121,6 +121,33 @@ int DetectHelperKeywordRegister(const SCSigTableElmt *kw) return DETECT_TBLSIZE_IDX - 1; } +int DetectHelperTransformRegister(const SCTransformTableElmt *kw) +{ + if (DETECT_TBLSIZE_IDX >= DETECT_TBLSIZE) { + void *tmp = SCRealloc( + sigmatch_table, (DETECT_TBLSIZE + DETECT_TBLSIZE_STEP) * sizeof(SigTableElmt)); + if (unlikely(tmp == NULL)) { + return -1; + } + sigmatch_table = tmp; + DETECT_TBLSIZE += DETECT_TBLSIZE_STEP; + } + + sigmatch_table[DETECT_TBLSIZE_IDX].name = kw->name; + sigmatch_table[DETECT_TBLSIZE_IDX].desc = kw->desc; + sigmatch_table[DETECT_TBLSIZE_IDX].url = kw->url; + sigmatch_table[DETECT_TBLSIZE_IDX].flags = kw->flags; + sigmatch_table[DETECT_TBLSIZE_IDX].Transform = + (void (*)(InspectionBuffer * buffer, void *options)) kw->Transform; + sigmatch_table[DETECT_TBLSIZE_IDX].TransformValidate = (bool (*)( + const uint8_t *content, uint16_t content_len, void *context))kw->TransformValidate; + sigmatch_table[DETECT_TBLSIZE_IDX].Setup = + (int (*)(DetectEngineCtx * de, Signature * s, const char *raw)) kw->Setup; + sigmatch_table[DETECT_TBLSIZE_IDX].Free = (void (*)(DetectEngineCtx * de, void *ptr)) kw->Free; + DETECT_TBLSIZE_IDX++; + return DETECT_TBLSIZE_IDX - 1; +} + InspectionBuffer *DetectHelperGetMultiData(struct DetectEngineThreadCtx_ *det_ctx, const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, const int list_id, uint32_t index, MultiGetTxBuffer GetBuf) @@ -144,3 +171,13 @@ InspectionBuffer *DetectHelperGetMultiData(struct DetectEngineThreadCtx_ *det_ct buffer->flags = DETECT_CI_FLAGS_SINGLE; return buffer; } + +const uint8_t *InspectionBufferPtr(InspectionBuffer *buf) +{ + return buf->inspect; +} + +uint32_t InspectionBufferLength(InspectionBuffer *buf) +{ + return buf->inspect_len; +} diff --git a/src/detect-engine-helper.h b/src/detect-engine-helper.h index 76e27dee7ce5..39fa632ed28c 100644 --- a/src/detect-engine-helper.h +++ b/src/detect-engine-helper.h @@ -46,4 +46,8 @@ InspectionBuffer *DetectHelperGetMultiData(struct DetectEngineThreadCtx_ *det_ct const DetectEngineTransforms *transforms, Flow *f, const uint8_t flow_flags, void *txv, const int list_id, uint32_t index, MultiGetTxBuffer GetBuf); +int DetectHelperTransformRegister(const SCTransformTableElmt *kw); +const uint8_t *InspectionBufferPtr(InspectionBuffer *buf); +uint32_t InspectionBufferLength(InspectionBuffer *buf); + #endif /* SURICATA_DETECT_ENGINE_HELPER_H */ diff --git a/src/detect-engine-register.c b/src/detect-engine-register.c index 794f680dd46f..ce3aff637639 100644 --- a/src/detect-engine-register.c +++ b/src/detect-engine-register.c @@ -217,7 +217,6 @@ #include "detect-engine-content-inspection.h" #include "detect-transform-compress-whitespace.h" -#include "detect-transform-strip-whitespace.h" #include "detect-transform-strip-pseudo-headers.h" #include "detect-transform-md5.h" #include "detect-transform-sha1.h" diff --git a/src/detect-engine.c b/src/detect-engine.c index be2f5b462aba..27e3cddb3558 100644 --- a/src/detect-engine.c +++ b/src/detect-engine.c @@ -1621,10 +1621,10 @@ void InspectionBufferFree(InspectionBuffer *buffer) * \brief make sure that the buffer has at least 'min_size' bytes * Expand the buffer if necessary */ -void InspectionBufferCheckAndExpand(InspectionBuffer *buffer, uint32_t min_size) +void *InspectionBufferCheckAndExpand(InspectionBuffer *buffer, uint32_t min_size) { if (likely(buffer->size >= min_size)) - return; + return buffer->buf; uint32_t new_size = (buffer->size == 0) ? 4096 : buffer->size; while (new_size < min_size) { @@ -1635,7 +1635,19 @@ void InspectionBufferCheckAndExpand(InspectionBuffer *buffer, uint32_t min_size) if (ptr != NULL) { buffer->buf = ptr; buffer->size = new_size; + } else { + return NULL; } + return buffer->buf; +} + +void InspectionBufferTruncate(InspectionBuffer *buffer, uint32_t buf_len) +{ + DEBUG_VALIDATE_BUG_ON(buffer->buf == NULL); + DEBUG_VALIDATE_BUG_ON(buf_len > buffer->size); + buffer->inspect = buffer->buf; + buffer->inspect_len = buf_len; + buffer->initialized = true; } void InspectionBufferCopy(InspectionBuffer *buffer, uint8_t *buf, uint32_t buf_len) diff --git a/src/detect-engine.h b/src/detect-engine.h index 11d747537f1e..9564af0c2712 100644 --- a/src/detect-engine.h +++ b/src/detect-engine.h @@ -31,7 +31,8 @@ void InspectionBufferInit(InspectionBuffer *buffer, uint32_t initial_size); void InspectionBufferSetup(DetectEngineThreadCtx *det_ctx, const int list_id, InspectionBuffer *buffer, const uint8_t *data, const uint32_t data_len); void InspectionBufferFree(InspectionBuffer *buffer); -void InspectionBufferCheckAndExpand(InspectionBuffer *buffer, uint32_t min_size); +void *InspectionBufferCheckAndExpand(InspectionBuffer *buffer, uint32_t min_size); +void InspectionBufferTruncate(InspectionBuffer *buffer, uint32_t buf_len); void InspectionBufferCopy(InspectionBuffer *buffer, uint8_t *buf, uint32_t buf_len); void InspectionBufferApplyTransforms(InspectionBuffer *buffer, const DetectEngineTransforms *transforms); diff --git a/src/detect-transform-strip-whitespace.c b/src/detect-transform-strip-whitespace.c deleted file mode 100644 index 32fb96f06ea0..000000000000 --- a/src/detect-transform-strip-whitespace.c +++ /dev/null @@ -1,209 +0,0 @@ -/* Copyright (C) 2007-2020 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 - * - * Implements the nocase keyword - */ - -#include "suricata-common.h" - -#include "detect.h" -#include "detect-engine.h" -#include "detect-engine-prefilter.h" -#include "detect-engine-build.h" -#include "detect-parse.h" -#include "detect-transform-strip-whitespace.h" - -#include "util-unittest.h" -#include "util-print.h" - -static int DetectTransformStripWhitespaceSetup (DetectEngineCtx *, Signature *, const char *); -#ifdef UNITTESTS -static void DetectTransformStripWhitespaceRegisterTests(void); -#endif -static void TransformStripWhitespace(InspectionBuffer *buffer, void *options); -static bool TransformStripWhitespaceValidate(const uint8_t *content, uint16_t content_len, void *options); - -void DetectTransformStripWhitespaceRegister(void) -{ - sigmatch_table[DETECT_TRANSFORM_STRIP_WHITESPACE].name = "strip_whitespace"; - sigmatch_table[DETECT_TRANSFORM_STRIP_WHITESPACE].desc = - "modify buffer to strip whitespace before inspection"; - sigmatch_table[DETECT_TRANSFORM_STRIP_WHITESPACE].url = - "/rules/transforms.html#strip-whitespace"; - sigmatch_table[DETECT_TRANSFORM_STRIP_WHITESPACE].Transform = - TransformStripWhitespace; - sigmatch_table[DETECT_TRANSFORM_STRIP_WHITESPACE].TransformValidate = - TransformStripWhitespaceValidate; - sigmatch_table[DETECT_TRANSFORM_STRIP_WHITESPACE].Setup = - DetectTransformStripWhitespaceSetup; -#ifdef UNITTESTS - sigmatch_table[DETECT_TRANSFORM_STRIP_WHITESPACE].RegisterTests = - DetectTransformStripWhitespaceRegisterTests; -#endif - sigmatch_table[DETECT_TRANSFORM_STRIP_WHITESPACE].flags |= SIGMATCH_NOOPT; -} - -/** - * \internal - * \brief Apply the nocase keyword to the last pattern match, either content or uricontent - * \param det_ctx detection engine ctx - * \param s signature - * \param nullstr should be null - * \retval 0 ok - * \retval -1 failure - */ -static int DetectTransformStripWhitespaceSetup (DetectEngineCtx *de_ctx, Signature *s, const char *nullstr) -{ - SCEnter(); - int r = DetectSignatureAddTransform(s, DETECT_TRANSFORM_STRIP_WHITESPACE, NULL); - SCReturnInt(r); -} - -/* - * \brief Validate content bytes to see if it's compatible with this transform - * \param content Byte array to check for compatibility - * \param content_len Number of bytes to check - * \param options Ignored - * \retval false If the string contains spaces - * \retval true Otherwise. - */ -static bool TransformStripWhitespaceValidate(const uint8_t *content, - uint16_t content_len, void *options) -{ - if (content) { - for (uint32_t i = 0; i < content_len; i++) { - if (isspace(*content++)) { - return false; - } - } - } - return true; -} - -static void TransformStripWhitespace(InspectionBuffer *buffer, void *options) -{ - const uint8_t *input = buffer->inspect; - const uint32_t input_len = buffer->inspect_len; - if (input_len == 0) { - return; - } - uint8_t output[input_len]; // we can only shrink - uint8_t *oi = output, *os = output; - - //PrintRawDataFp(stdout, input, input_len); - for (uint32_t i = 0; i < input_len; i++) { - if (!isspace(*input)) { - *oi++ = *input; - } - input++; - } - uint32_t output_size = oi - os; - //PrintRawDataFp(stdout, output, output_size); - - InspectionBufferCopy(buffer, os, output_size); -} - -#ifdef UNITTESTS -static int TransformDoubleWhitespace(InspectionBuffer *buffer) -{ - const uint8_t *input = buffer->inspect; - const uint32_t input_len = buffer->inspect_len; - uint8_t output[input_len * 2]; // if all chars are whitespace this fits - uint8_t *oi = output, *os = output; - - PrintRawDataFp(stdout, input, input_len); - for (uint32_t i = 0; i < input_len; i++) { - if (isspace(*input)) { - *oi++ = *input; - } - *oi++ = *input; - input++; - } - uint32_t output_size = oi - os; - PrintRawDataFp(stdout, output, output_size); - - InspectionBufferCopy(buffer, os, output_size); - return 0; -} - -static int DetectTransformStripWhitespaceTest01(void) -{ - const uint8_t *input = (const uint8_t *)" A B C D "; - uint32_t input_len = strlen((char *)input); - - InspectionBuffer buffer; - InspectionBufferInit(&buffer, 8); - InspectionBufferSetup(NULL, -1, &buffer, input, input_len); - PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); - TransformStripWhitespace(&buffer, NULL); - PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); - InspectionBufferFree(&buffer); - PASS; -} - -static int DetectTransformStripWhitespaceTest02(void) -{ - const uint8_t *input = (const uint8_t *)" A B C D "; - uint32_t input_len = strlen((char *)input); - - InspectionBuffer buffer; - InspectionBufferInit(&buffer, 8); - InspectionBufferSetup(NULL, -1, &buffer, input, input_len); - PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); - TransformDoubleWhitespace(&buffer); - PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); - TransformDoubleWhitespace(&buffer); - PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); - TransformStripWhitespace(&buffer, NULL); - PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); - InspectionBufferFree(&buffer); - PASS; -} - -static int DetectTransformStripWhitespaceTest03(void) -{ - const char rule[] = "alert http any any -> any any (http_request_line; strip_whitespace; content:\"GET/HTTP\"; sid:1;)"; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - memset(&th_v, 0, sizeof(th_v)); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - Signature *s = DetectEngineAppendSig(de_ctx, rule); - FAIL_IF_NULL(s); - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - PASS; -} - -static void DetectTransformStripWhitespaceRegisterTests(void) -{ - UtRegisterTest("DetectTransformStripWhitespaceTest01", - DetectTransformStripWhitespaceTest01); - UtRegisterTest("DetectTransformStripWhitespaceTest02", - DetectTransformStripWhitespaceTest02); - UtRegisterTest("DetectTransformStripWhitespaceTest03", - DetectTransformStripWhitespaceTest03); -} -#endif diff --git a/src/detect-transform-strip-whitespace.h b/src/detect-transform-strip-whitespace.h deleted file mode 100644 index 53b2922e8dbd..000000000000 --- a/src/detect-transform-strip-whitespace.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (C) 2017 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_TRANSFORM_STRIPWHITESPACE_H -#define SURICATA_DETECT_TRANSFORM_STRIPWHITESPACE_H - -/* prototypes */ -void DetectTransformStripWhitespaceRegister (void); - -#endif /* SURICATA_DETECT_TRANSFORM_STRIPWHITESPACE_H */ From 66dc788cacf08075018c8b74d7d135954c9c7bda Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Wed, 2 Oct 2024 21:20:04 +0200 Subject: [PATCH 2/3] transforms: move compress_whitespace to rust Ticket: 7229 --- .../detect/transforms/compress_whitespace.rs | 160 ++++++++++++ rust/src/detect/transforms/mod.rs | 1 + src/Makefile.am | 2 - src/detect-engine-register.c | 1 - src/detect-transform-compress-whitespace.c | 233 ------------------ src/detect-transform-compress-whitespace.h | 30 --- 6 files changed, 161 insertions(+), 266 deletions(-) create mode 100644 rust/src/detect/transforms/compress_whitespace.rs delete mode 100644 src/detect-transform-compress-whitespace.c delete mode 100644 src/detect-transform-compress-whitespace.h diff --git a/rust/src/detect/transforms/compress_whitespace.rs b/rust/src/detect/transforms/compress_whitespace.rs new file mode 100644 index 000000000000..5e96be1f10d0 --- /dev/null +++ b/rust/src/detect/transforms/compress_whitespace.rs @@ -0,0 +1,160 @@ +/* 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. + */ + +use super::{ + DetectHelperTransformRegister, DetectSignatureAddTransform, InspectionBufferCheckAndExpand, + InspectionBufferLength, InspectionBufferPtr, InspectionBufferTruncate, SCTransformTableElmt, +}; +use crate::detect::SIGMATCH_NOOPT; + +use std::os::raw::{c_int, c_void}; +use std::ptr; + +static mut G_TRANSFORM_COMPRESS_WHITESPACE_ID: c_int = 0; + +#[no_mangle] +unsafe extern "C" fn compress_whitespace_setup( + _de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + return DetectSignatureAddTransform(s, G_TRANSFORM_COMPRESS_WHITESPACE_ID, ptr::null_mut()); +} + +fn compress_whitespace_transform_do(input: &[u8], output: &mut [u8]) -> u32 { + let mut nb = 0; + // seems faster than writing one byte at a time via + // for (i, o) in input.iter().filter(|c| !matches!(*c, b'\t' | b'\n' | b'\x0B' | b'\x0C' | b'\r' | b' ')).zip(output) + for subslice in + input.split_inclusive(|c| matches!(*c, b'\t' | b'\n' | b'\x0B' | b'\x0C' | b'\r' | b' ')) + { + // a subslice of length 1 not at the beginning is a space following another space + if nb == 0 + || subslice.len() > 1 + || !matches!( + subslice[0], + b'\t' | b'\n' | b'\x0B' | b'\x0C' | b'\r' | b' ' + ) + { + output[nb..nb + subslice.len()].copy_from_slice(subslice); + nb += subslice.len(); + } + } + return nb as u32; +} + +#[no_mangle] +unsafe extern "C" fn compress_whitespace_transform(buffer: *mut c_void, _ctx: *mut c_void) { + let input = InspectionBufferPtr(buffer); + let input_len = InspectionBufferLength(buffer); + if input.is_null() || input_len == 0 { + return; + } + let input = build_slice!(input, input_len as usize); + + let output = InspectionBufferCheckAndExpand(buffer, input_len); + if output.is_null() { + // allocation failure + return; + } + let output = std::slice::from_raw_parts_mut(output, input_len as usize); + + let output_len = compress_whitespace_transform_do(input, output); + + InspectionBufferTruncate(buffer, output_len); +} + +fn compress_whitespace_validate_do(input: &[u8]) -> bool { + let mut space = false; + for &c in input { + if space { + if matches!(c, b'\t' | b'\n' | b'\x0B' | b'\x0C' | b'\r' | b' ') { + return false; + } + space = false; + } else if matches!(c, b'\t' | b'\n' | b'\x0B' | b'\x0C' | b'\r' | b' ') { + space = true; + } + } + return true; +} + +#[no_mangle] +unsafe extern "C" fn compress_whitespace_validate( + content: *const u8, len: u16, _ctx: *mut c_void, +) -> bool { + let input = build_slice!(content, len as usize); + return compress_whitespace_validate_do(input); +} + +#[no_mangle] +pub unsafe extern "C" fn DetectTransformCompressWhitespaceRegister() { + let kw = SCTransformTableElmt { + name: b"compress_whitespace\0".as_ptr() as *const libc::c_char, + desc: b"modify buffer to compress consecutive whitespace characters into a single one before inspection\0".as_ptr() + as *const libc::c_char, + url: b"/rules/transforms.html#compress-whitespace\0".as_ptr() as *const libc::c_char, + Setup: compress_whitespace_setup, + flags: SIGMATCH_NOOPT, + Transform: compress_whitespace_transform, + Free: None, + TransformValidate: Some(compress_whitespace_validate), + }; + unsafe { + G_TRANSFORM_COMPRESS_WHITESPACE_ID = DetectHelperTransformRegister(&kw); + if G_TRANSFORM_COMPRESS_WHITESPACE_ID < 0 { + SCLogWarning!("Failed registering transform compress_whitespace"); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_compress_whitespace_transform() { + let buf = b" A B C D "; + let mut out = vec![0; buf.len()]; + let exp = b" A B C D "; + assert_eq!( + compress_whitespace_transform_do(buf, &mut out), + exp.len() as u32 + ); + assert_eq!(&out[..exp.len()], exp); + let buf = b"EFGH"; + let mut out = vec![0; buf.len()]; + let exp = b"EFGH"; + assert_eq!( + compress_whitespace_transform_do(buf, &mut out), + exp.len() as u32 + ); + assert_eq!(&out[..exp.len()], exp); + let buf = b"I \t J"; + let mut out = vec![0; buf.len()]; + let exp = b"I J"; + assert_eq!( + compress_whitespace_transform_do(buf, &mut out), + exp.len() as u32 + ); + assert_eq!(&out[..exp.len()], exp); + } + + #[test] + fn test_compress_whitespace_validate() { + assert!(compress_whitespace_validate_do(b" A B C D ")); + assert!(!compress_whitespace_validate_do(b" A B C D ")); + } +} diff --git a/rust/src/detect/transforms/mod.rs b/rust/src/detect/transforms/mod.rs index 9e997f6b4674..99c929a9dff8 100644 --- a/rust/src/detect/transforms/mod.rs +++ b/rust/src/detect/transforms/mod.rs @@ -19,6 +19,7 @@ use std::os::raw::{c_char, c_int, c_void}; +pub mod compress_whitespace; pub mod strip_whitespace; #[repr(C)] diff --git a/src/Makefile.am b/src/Makefile.am index 0fb15e413564..4995df6eff5f 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -308,7 +308,6 @@ noinst_HEADERS = \ detect-tos.h \ detect-transform-base64.h \ detect-transform-casechange.h \ - detect-transform-compress-whitespace.h \ detect-transform-dotprefix.h \ detect-transform-header-lowercase.h \ detect-transform-md5.h \ @@ -880,7 +879,6 @@ libsuricata_c_a_SOURCES = \ detect-tos.c \ detect-transform-base64.c \ detect-transform-casechange.c \ - detect-transform-compress-whitespace.c \ detect-transform-dotprefix.c \ detect-transform-header-lowercase.c \ detect-transform-md5.c \ diff --git a/src/detect-engine-register.c b/src/detect-engine-register.c index ce3aff637639..264db901a470 100644 --- a/src/detect-engine-register.c +++ b/src/detect-engine-register.c @@ -216,7 +216,6 @@ #include "detect-ftpdata.h" #include "detect-engine-content-inspection.h" -#include "detect-transform-compress-whitespace.h" #include "detect-transform-strip-pseudo-headers.h" #include "detect-transform-md5.h" #include "detect-transform-sha1.h" diff --git a/src/detect-transform-compress-whitespace.c b/src/detect-transform-compress-whitespace.c deleted file mode 100644 index 5cbf0fd896f5..000000000000 --- a/src/detect-transform-compress-whitespace.c +++ /dev/null @@ -1,233 +0,0 @@ -/* Copyright (C) 2007-2020 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 - * - * Implements the compress_whitespace transform keyword - */ - -#include "suricata-common.h" - -#include "detect.h" -#include "detect-engine.h" -#include "detect-engine-prefilter.h" -#include "detect-parse.h" -#include "detect-transform-compress-whitespace.h" - -#include "util-unittest.h" -#include "util-print.h" - -static int DetectTransformCompressWhitespaceSetup (DetectEngineCtx *, Signature *, const char *); -#ifdef UNITTESTS -static void DetectTransformCompressWhitespaceRegisterTests(void); -#endif -static void TransformCompressWhitespace(InspectionBuffer *buffer, void *options); -static bool TransformCompressWhitespaceValidate( - const uint8_t *content, uint16_t content_len, void *options); - -void DetectTransformCompressWhitespaceRegister(void) -{ - sigmatch_table[DETECT_TRANSFORM_COMPRESS_WHITESPACE].name = "compress_whitespace"; - sigmatch_table[DETECT_TRANSFORM_COMPRESS_WHITESPACE].desc = - "modify buffer to compress consecutive whitespace characters " - "into a single one before inspection"; - sigmatch_table[DETECT_TRANSFORM_COMPRESS_WHITESPACE].url = - "/rules/transforms.html#compress-whitespace"; - sigmatch_table[DETECT_TRANSFORM_COMPRESS_WHITESPACE].Transform = - TransformCompressWhitespace; - sigmatch_table[DETECT_TRANSFORM_COMPRESS_WHITESPACE].TransformValidate = - TransformCompressWhitespaceValidate; - sigmatch_table[DETECT_TRANSFORM_COMPRESS_WHITESPACE].Setup = - DetectTransformCompressWhitespaceSetup; -#ifdef UNITTESTS - sigmatch_table[DETECT_TRANSFORM_COMPRESS_WHITESPACE].RegisterTests = - DetectTransformCompressWhitespaceRegisterTests; -#endif - sigmatch_table[DETECT_TRANSFORM_COMPRESS_WHITESPACE].flags |= SIGMATCH_NOOPT; -} - -/** - * \internal - * \brief Apply the compress_whitespace keyword to the last pattern match - * \param det_ctx detection engine ctx - * \param s signature - * \param nullstr should be null - * \retval 0 ok - * \retval -1 failure - */ -static int DetectTransformCompressWhitespaceSetup (DetectEngineCtx *de_ctx, Signature *s, const char *nullstr) -{ - SCEnter(); - int r = DetectSignatureAddTransform(s, DETECT_TRANSFORM_COMPRESS_WHITESPACE, NULL); - SCReturnInt(r); -} - -/* - * \brief Validate content bytes to see if it's compatible with this transform - * \param content Byte array to check for compatibility - * \param content_len Number of bytes to check - * \param options Ignored - * \retval false If the string contains spaces - * \retval true Otherwise. - */ -static bool TransformCompressWhitespaceValidate( - const uint8_t *content, uint16_t content_len, void *options) -{ - if (content) { - for (uint32_t i = 0; i < content_len; i++) { - if (!isspace(*content++)) { - continue; - } - if ((i + 1) < content_len && isspace(*content)) { - return false; - } - } - } - return true; -} - -static void TransformCompressWhitespace(InspectionBuffer *buffer, void *options) -{ - const uint8_t *input = buffer->inspect; - const uint32_t input_len = buffer->inspect_len; - if (input_len == 0) { - return; - } - - uint8_t output[input_len]; // we can only shrink - uint8_t *oi = output, *os = output; - - //PrintRawDataFp(stdout, input, input_len); - for (uint32_t i = 0; i < input_len; ) { - if (!(isspace(*input))) { - *oi++ = *input++; - i++; - } else { - *oi++ = *input++; - i++; - - while (i < input_len && isspace(*input)) { - input++; - i++; - } - } - } - uint32_t output_size = oi - os; - //PrintRawDataFp(stdout, output, output_size); - - InspectionBufferCopy(buffer, os, output_size); -} - -#ifdef UNITTESTS -static int TransformDoubleWhitespace(InspectionBuffer *buffer) -{ - const uint8_t *input = buffer->inspect; - const uint32_t input_len = buffer->inspect_len; - uint8_t output[input_len * 2]; // if all chars are whitespace this fits - uint8_t *oi = output, *os = output; - - PrintRawDataFp(stdout, input, input_len); - for (uint32_t i = 0; i < input_len; i++) { - if (isspace(*input)) { - *oi++ = *input; - } - *oi++ = *input; - input++; - } - uint32_t output_size = oi - os; - PrintRawDataFp(stdout, output, output_size); - - InspectionBufferCopy(buffer, os, output_size); - return 0; -} - -static int DetectTransformCompressWhitespaceTest01(void) -{ - const uint8_t *input = (const uint8_t *)" A B C D "; - uint32_t input_len = strlen((char *)input); - - InspectionBuffer buffer; - InspectionBufferInit(&buffer, 9); - InspectionBufferSetup(NULL, -1, &buffer, input, input_len); - PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); - TransformCompressWhitespace(&buffer, NULL); - PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); - InspectionBufferFree(&buffer); - PASS; -} - -static int DetectTransformCompressWhitespaceTest02(void) -{ - const uint8_t *input = (const uint8_t *)" A B C D "; - uint32_t input_len = strlen((char *)input); - - InspectionBuffer buffer; - InspectionBufferInit(&buffer, 9); - InspectionBufferSetup(NULL, -1, &buffer, input, input_len); - PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); - TransformDoubleWhitespace(&buffer); - PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); - TransformDoubleWhitespace(&buffer); - PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); - TransformCompressWhitespace(&buffer, NULL); - PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); - InspectionBufferFree(&buffer); - PASS; -} - -static int DetectTransformCompressWhitespaceTest03(void) -{ - const uint8_t *input = (const uint8_t *)" A B C D "; - uint32_t input_len = strlen((char *)input); - - InspectionBuffer buffer; - InspectionBufferInit(&buffer, 10); - InspectionBufferSetup(NULL, -1, &buffer, input, input_len); - PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); - FAIL_IF(TransformCompressWhitespaceValidate(buffer.inspect, buffer.inspect_len, NULL)); - PASS; -} - -static int DetectTransformCompressWhitespaceTest04(void) -{ - const uint8_t *input = (const uint8_t *)" A B C D "; - uint32_t input_len = strlen((char *)input); - - InspectionBuffer buffer; - InspectionBufferInit(&buffer, 9); - InspectionBufferSetup(NULL, -1, &buffer, input, input_len); - TransformDoubleWhitespace(&buffer); - PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); - FAIL_IF(TransformCompressWhitespaceValidate(buffer.inspect, buffer.inspect_len, NULL)); - PASS; -} - -static void DetectTransformCompressWhitespaceRegisterTests(void) -{ - UtRegisterTest("DetectTransformCompressWhitespaceTest01", - DetectTransformCompressWhitespaceTest01); - UtRegisterTest("DetectTransformCompressWhitespaceTest02", - DetectTransformCompressWhitespaceTest02); - UtRegisterTest( - "DetectTransformCompressWhitespaceTest03", DetectTransformCompressWhitespaceTest03); - UtRegisterTest( - "DetectTransformCompressWhitespaceTest04", DetectTransformCompressWhitespaceTest04); -} -#endif diff --git a/src/detect-transform-compress-whitespace.h b/src/detect-transform-compress-whitespace.h deleted file mode 100644 index f7824bde4399..000000000000 --- a/src/detect-transform-compress-whitespace.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright (C) 2017 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_TRANSFORM_COMPRESS_WHITESPACE_H -#define SURICATA_DETECT_TRANSFORM_COMPRESS_WHITESPACE_H - -/* prototypes */ -void DetectTransformCompressWhitespaceRegister (void); - -#endif /* SURICATA_DETECT_TRANSFORM_COMPRESS_WHITESPACE_H */ From 431529aea3d6668443603c0468a3bb457e9f29f5 Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Wed, 2 Oct 2024 21:41:06 +0200 Subject: [PATCH 3/3] transforms: move dotprefix to rust Ticket: 7229 --- rust/src/detect/transforms/dotprefix.rs | 97 ++++++++++++ rust/src/detect/transforms/mod.rs | 1 + src/Makefile.am | 2 - src/detect-engine-register.c | 1 - src/detect-transform-dotprefix.c | 186 ------------------------ src/detect-transform-dotprefix.h | 30 ---- 6 files changed, 98 insertions(+), 219 deletions(-) create mode 100644 rust/src/detect/transforms/dotprefix.rs delete mode 100644 src/detect-transform-dotprefix.c delete mode 100644 src/detect-transform-dotprefix.h diff --git a/rust/src/detect/transforms/dotprefix.rs b/rust/src/detect/transforms/dotprefix.rs new file mode 100644 index 000000000000..eef6d048bd08 --- /dev/null +++ b/rust/src/detect/transforms/dotprefix.rs @@ -0,0 +1,97 @@ +/* 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. + */ + +use super::{ + DetectHelperTransformRegister, DetectSignatureAddTransform, InspectionBufferCheckAndExpand, + InspectionBufferLength, InspectionBufferPtr, InspectionBufferTruncate, SCTransformTableElmt, +}; +use crate::detect::SIGMATCH_NOOPT; + +use std::os::raw::{c_int, c_void}; +use std::ptr; + +static mut G_TRANSFORM_DOT_PREFIX_ID: c_int = 0; + +#[no_mangle] +unsafe extern "C" fn dot_prefix_setup( + _de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char, +) -> c_int { + return DetectSignatureAddTransform(s, G_TRANSFORM_DOT_PREFIX_ID, ptr::null_mut()); +} + +fn dot_prefix_transform_do(input: &[u8], output: &mut [u8]) { + output[0] = b'.'; + output[1..].copy_from_slice(input); +} + +#[no_mangle] +unsafe extern "C" fn dot_prefix_transform(buffer: *mut c_void, _ctx: *mut c_void) { + let input = InspectionBufferPtr(buffer); + let input_len = InspectionBufferLength(buffer); + if input.is_null() || input_len == 0 { + return; + } + let input = build_slice!(input, input_len as usize); + + let output = InspectionBufferCheckAndExpand(buffer, input_len + 1); + if output.is_null() { + // allocation failure + return; + } + let output = std::slice::from_raw_parts_mut(output, (input_len + 1) as usize); + + dot_prefix_transform_do(input, output); + + InspectionBufferTruncate(buffer, input_len + 1); +} + +#[no_mangle] +pub unsafe extern "C" fn DetectTransformDotPrefixRegister() { + let kw = SCTransformTableElmt { + name: b"dotprefix\0".as_ptr() as *const libc::c_char, + desc: b"modify buffer to extract the dotprefix\0".as_ptr() as *const libc::c_char, + url: b"/rules/transforms.html#dotprefix\0".as_ptr() as *const libc::c_char, + Setup: dot_prefix_setup, + flags: SIGMATCH_NOOPT, + Transform: dot_prefix_transform, + Free: None, + TransformValidate: None, + }; + unsafe { + G_TRANSFORM_DOT_PREFIX_ID = DetectHelperTransformRegister(&kw); + if G_TRANSFORM_DOT_PREFIX_ID < 0 { + SCLogWarning!("Failed registering transform dot_prefix"); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_dot_prefix_transform() { + let buf = b"example.com"; + let mut out = vec![0; b"example.com".len() + 1]; + dot_prefix_transform_do(buf, &mut out); + assert_eq!(out, b".example.com"); + let buf = b"hello.example.com"; + let mut out = vec![0; b"hello.example.com".len() + 1]; + dot_prefix_transform_do(buf, &mut out); + assert_eq!(out, b".hello.example.com"); + } +} diff --git a/rust/src/detect/transforms/mod.rs b/rust/src/detect/transforms/mod.rs index 99c929a9dff8..120a8ff54e16 100644 --- a/rust/src/detect/transforms/mod.rs +++ b/rust/src/detect/transforms/mod.rs @@ -20,6 +20,7 @@ use std::os::raw::{c_char, c_int, c_void}; pub mod compress_whitespace; +pub mod dotprefix; pub mod strip_whitespace; #[repr(C)] diff --git a/src/Makefile.am b/src/Makefile.am index 4995df6eff5f..d7c2dfbdd7a5 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -308,7 +308,6 @@ noinst_HEADERS = \ detect-tos.h \ detect-transform-base64.h \ detect-transform-casechange.h \ - detect-transform-dotprefix.h \ detect-transform-header-lowercase.h \ detect-transform-md5.h \ detect-transform-pcrexform.h \ @@ -879,7 +878,6 @@ libsuricata_c_a_SOURCES = \ detect-tos.c \ detect-transform-base64.c \ detect-transform-casechange.c \ - detect-transform-dotprefix.c \ detect-transform-header-lowercase.c \ detect-transform-md5.c \ detect-transform-pcrexform.c \ diff --git a/src/detect-engine-register.c b/src/detect-engine-register.c index 264db901a470..37d45371aad5 100644 --- a/src/detect-engine-register.c +++ b/src/detect-engine-register.c @@ -220,7 +220,6 @@ #include "detect-transform-md5.h" #include "detect-transform-sha1.h" #include "detect-transform-sha256.h" -#include "detect-transform-dotprefix.h" #include "detect-transform-pcrexform.h" #include "detect-transform-urldecode.h" #include "detect-transform-xor.h" diff --git a/src/detect-transform-dotprefix.c b/src/detect-transform-dotprefix.c deleted file mode 100644 index 52a263372b43..000000000000 --- a/src/detect-transform-dotprefix.c +++ /dev/null @@ -1,186 +0,0 @@ -/* Copyright (C) 2020 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 Jeff Lucovsky - * - * Implements the dotprefix transformation - */ - -#include "suricata-common.h" - -#include "detect.h" -#include "detect-engine.h" -#include "detect-engine-prefilter.h" -#include "detect-parse.h" -#include "detect-transform-dotprefix.h" -#include "detect-engine-build.h" - -#include "util-unittest.h" -#include "util-print.h" -#include "util-memrchr.h" -#include "util-memcpy.h" - -static int DetectTransformDotPrefixSetup (DetectEngineCtx *, Signature *, const char *); -#ifdef UNITTESTS -static void DetectTransformDotPrefixRegisterTests(void); -#endif -static void TransformDotPrefix(InspectionBuffer *buffer, void *options); - -void DetectTransformDotPrefixRegister(void) -{ - sigmatch_table[DETECT_TRANSFORM_DOTPREFIX].name = "dotprefix"; - sigmatch_table[DETECT_TRANSFORM_DOTPREFIX].desc = - "modify buffer to extract the dotprefix"; - sigmatch_table[DETECT_TRANSFORM_DOTPREFIX].url = - "/rules/transforms.html#dotprefix"; - sigmatch_table[DETECT_TRANSFORM_DOTPREFIX].Transform = TransformDotPrefix; - sigmatch_table[DETECT_TRANSFORM_DOTPREFIX].Setup = DetectTransformDotPrefixSetup; -#ifdef UNITTESTS - sigmatch_table[DETECT_TRANSFORM_DOTPREFIX].RegisterTests = - DetectTransformDotPrefixRegisterTests; -#endif - sigmatch_table[DETECT_TRANSFORM_DOTPREFIX].flags |= SIGMATCH_NOOPT; -} - -/** - * \internal - * \brief Extract the dotprefix, if any, the last pattern match, either content or uricontent - * \param det_ctx detection engine ctx - * \param s signature - * \param nullstr should be null - * \retval 0 ok - * \retval -1 failure - */ -static int DetectTransformDotPrefixSetup (DetectEngineCtx *de_ctx, Signature *s, const char *nullstr) -{ - SCEnter(); - int r = DetectSignatureAddTransform(s, DETECT_TRANSFORM_DOTPREFIX, NULL); - SCReturnInt(r); -} - -/** - * \brief Return the dotprefix, if any, in the last pattern match. - * - * Input values are modified by prefixing with a ".". - * - * Rule: "alert dns any any -> any any (dns_query; dotprefix; content:".google.com"; sid:1;)" - * 1. hello.google.com --> match - * 2. hey.agoogle.com --> no match - * 3. agoogle.com --> no match - * 4. something.google.com.au --> match - * 5. google.com --> match - * - * To match on the dotprefix only: - * Rule: "alert dns any any -> any any (dns_query; dotprefix; content:".google.com"; endswith; sid:1;)" - * - * 1. hello.google.com --> match - * 2. hey.agoogle.com --> no match - * 3. agoogle.com --> no match - * 4. something.google.com.au --> no match - * 5. google.com --> match - * - * To match on a TLD: - * Rule: "alert dns any any -> any any (dns_query; dotprefix; content:".co.uk"; endswith; sid:1;)" - * - * 1. hello.google.com --> no match - * 2. hey.agoogle.com --> no match - * 3. agoogle.com --> no match - * 4. something.google.co.uk --> match - * 5. google.com --> no match - */ -static void TransformDotPrefix(InspectionBuffer *buffer, void *options) -{ - const size_t input_len = buffer->inspect_len; - - if (input_len) { - uint8_t output[input_len + 1]; // For the leading '.' - - output[0] = '.'; - memcpy(&output[1], buffer->inspect, input_len); - InspectionBufferCopy(buffer, output, input_len + 1); - } -} - -#ifdef UNITTESTS -static int DetectTransformDotPrefixTest01(void) -{ - const uint8_t *input = (const uint8_t *)"example.com"; - uint32_t input_len = strlen((char *)input); - - const char *result = ".example.com"; - uint32_t result_len = strlen((char *)result); - - InspectionBuffer buffer; - InspectionBufferInit(&buffer, input_len); - InspectionBufferSetup(NULL, -1, &buffer, input, input_len); - PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); - TransformDotPrefix(&buffer, NULL); - PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); - FAIL_IF_NOT(buffer.inspect_len == result_len); - FAIL_IF_NOT(strncmp(result, (const char *)buffer.inspect, result_len) == 0); - InspectionBufferFree(&buffer); - PASS; -} - -static int DetectTransformDotPrefixTest02(void) -{ - const uint8_t *input = (const uint8_t *)"hello.example.com"; - uint32_t input_len = strlen((char *)input); - - const char *result = ".hello.example.com"; - uint32_t result_len = strlen((char *)result); - - InspectionBuffer buffer; - InspectionBufferInit(&buffer, input_len); - InspectionBufferSetup(NULL, -1, &buffer, input, input_len); - PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); - TransformDotPrefix(&buffer, NULL); - PrintRawDataFp(stdout, buffer.inspect, buffer.inspect_len); - FAIL_IF_NOT(buffer.inspect_len == result_len); - FAIL_IF_NOT(strncmp(result, (const char *)buffer.inspect, result_len) == 0); - InspectionBufferFree(&buffer); - PASS; -} - -static int DetectTransformDotPrefixTest03(void) -{ - const char rule[] = "alert dns any any -> any any (dns.query; dotprefix; content:\".google.com\"; sid:1;)"; - ThreadVars th_v; - DetectEngineThreadCtx *det_ctx = NULL; - memset(&th_v, 0, sizeof(th_v)); - - DetectEngineCtx *de_ctx = DetectEngineCtxInit(); - FAIL_IF_NULL(de_ctx); - Signature *s = DetectEngineAppendSig(de_ctx, rule); - FAIL_IF_NULL(s); - SigGroupBuild(de_ctx); - DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx); - DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx); - DetectEngineCtxFree(de_ctx); - PASS; -} - -static void DetectTransformDotPrefixRegisterTests(void) -{ - UtRegisterTest("DetectTransformDotPrefixTest01", DetectTransformDotPrefixTest01); - UtRegisterTest("DetectTransformDotPrefixTest02", DetectTransformDotPrefixTest02); - UtRegisterTest("DetectTransformDotPrefixTest03", DetectTransformDotPrefixTest03); -} -#endif diff --git a/src/detect-transform-dotprefix.h b/src/detect-transform-dotprefix.h deleted file mode 100644 index 2062055d8d0f..000000000000 --- a/src/detect-transform-dotprefix.h +++ /dev/null @@ -1,30 +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. - */ - -/** - * \file - * - * \author Jeff Lucovsky - */ - -#ifndef SURICATA_DETECT_TRANSFORM_DOTPREFIX_H -#define SURICATA_DETECT_TRANSFORM_DOTPREFIX_H - -/* prototypes */ -void DetectTransformDotPrefixRegister (void); - -#endif /* SURICATA_DETECT_TRANSFORM_DOTPREFIX_H */