transforms: move http headers transforms to rust

Ticket: 7229
pull/12094/head
Philippe Antoine 1 year ago committed by Victor Julien
parent f0414570d2
commit 45e0acf772

@ -0,0 +1,187 @@
/* 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_HEADER_LOWER_ID: c_int = 0;
static mut G_TRANSFORM_STRIP_PSEUDO_ID: c_int = 0;
#[no_mangle]
unsafe extern "C" fn header_lowersetup(
_de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char,
) -> c_int {
return DetectSignatureAddTransform(s, G_TRANSFORM_HEADER_LOWER_ID, ptr::null_mut());
}
fn header_lowertransform_do(input: &[u8], output: &mut [u8]) {
let mut state_value = false; // false in name, true in value
for (i, o) in input.iter().zip(output.iter_mut()) {
if !state_value {
if (*i) == b':' {
state_value = true;
*o = *i;
} else {
*o = (*i).to_ascii_lowercase();
}
} else {
*o = *i;
if (*i) == b'\n' {
state_value = false;
}
}
}
}
#[no_mangle]
unsafe extern "C" fn header_lowertransform(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);
header_lowertransform_do(input, output);
InspectionBufferTruncate(buffer, input_len);
}
#[no_mangle]
pub unsafe extern "C" fn DetectTransformHeaderLowercaseRegister() {
let kw = SCTransformTableElmt {
name: b"header_lowercase\0".as_ptr() as *const libc::c_char,
desc: b"modify buffer via lowercaseing header names\0".as_ptr() as *const libc::c_char,
url: b"/rules/transforms.html#header_lowercase\0".as_ptr() as *const libc::c_char,
Setup: header_lowersetup,
flags: SIGMATCH_NOOPT,
Transform: header_lowertransform,
Free: None,
TransformValidate: None,
};
unsafe {
G_TRANSFORM_HEADER_LOWER_ID = DetectHelperTransformRegister(&kw);
if G_TRANSFORM_HEADER_LOWER_ID < 0 {
SCLogWarning!("Failed registering transform tolower");
}
}
}
#[no_mangle]
unsafe extern "C" fn strip_pseudo_setup(
_de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char,
) -> c_int {
return DetectSignatureAddTransform(s, G_TRANSFORM_STRIP_PSEUDO_ID, ptr::null_mut());
}
fn strip_pseudo_transform_do(input: &[u8], output: &mut [u8]) -> u32 {
let mut nb = 0;
for subslice in input.split_inclusive(|c| *c == b'\n') {
if !subslice.is_empty() && subslice[0] != b':' {
output[nb..nb + subslice.len()].copy_from_slice(subslice);
nb += subslice.len();
}
}
return nb as u32;
}
#[no_mangle]
unsafe extern "C" fn strip_pseudo_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 out_len = strip_pseudo_transform_do(input, output);
InspectionBufferTruncate(buffer, out_len);
}
#[no_mangle]
pub unsafe extern "C" fn DetectTransformStripPseudoHeadersRegister() {
let kw = SCTransformTableElmt {
name: b"strip_pseudo_headers\0".as_ptr() as *const libc::c_char,
desc: b"modify buffer via stripping pseudo headers\0".as_ptr() as *const libc::c_char,
url: b"/rules/transforms.html#strip_pseudo_headers\0".as_ptr() as *const libc::c_char,
Setup: strip_pseudo_setup,
flags: SIGMATCH_NOOPT,
Transform: strip_pseudo_transform,
Free: None,
TransformValidate: None,
};
unsafe {
G_TRANSFORM_STRIP_PSEUDO_ID = DetectHelperTransformRegister(&kw);
if G_TRANSFORM_STRIP_PSEUDO_ID < 0 {
SCLogWarning!("Failed registering transform toupper");
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_header_lowertransform() {
let buf = b"Header1: Value1\nheader2:Value2\n";
let mut out = vec![0; buf.len()];
header_lowertransform_do(buf, &mut out);
assert_eq!(out, b"header1: Value1\nheader2:Value2\n");
}
#[test]
fn test_strip_pseudo_transform() {
let buf = b"Header1: Value1\n:method:get\nheader2:Value2\n";
let mut out = vec![0; buf.len()];
let nb = strip_pseudo_transform_do(buf, &mut out);
assert_eq!(&out[..nb as usize], b"Header1: Value1\nheader2:Value2\n");
let buf = b":method:get";
let mut out = vec![0; buf.len()];
let nb = strip_pseudo_transform_do(buf, &mut out);
assert_eq!(nb, 0);
let buf = b"Header1: Value1\n:method:get";
let mut out = vec![0; buf.len()];
let nb = strip_pseudo_transform_do(buf, &mut out);
assert_eq!(&out[..nb as usize], b"Header1: Value1\n");
let buf = b":method:get\nheader2:Value2";
let mut out = vec![0; buf.len()];
let nb = strip_pseudo_transform_do(buf, &mut out);
assert_eq!(&out[..nb as usize], b"header2:Value2");
}
}

@ -23,6 +23,7 @@ pub mod casechange;
pub mod compress_whitespace; pub mod compress_whitespace;
pub mod dotprefix; pub mod dotprefix;
pub mod hash; pub mod hash;
pub mod http_headers;
pub mod strip_whitespace; pub mod strip_whitespace;
#[repr(C)] #[repr(C)]

@ -306,9 +306,7 @@ noinst_HEADERS = \
detect-tls-random.h \ detect-tls-random.h \
detect-tos.h \ detect-tos.h \
detect-transform-base64.h \ detect-transform-base64.h \
detect-transform-header-lowercase.h \
detect-transform-pcrexform.h \ detect-transform-pcrexform.h \
detect-transform-strip-pseudo-headers.h \
detect-transform-urldecode.h \ detect-transform-urldecode.h \
detect-transform-xor.h \ detect-transform-xor.h \
detect-ttl.h \ detect-ttl.h \
@ -868,9 +866,7 @@ libsuricata_c_a_SOURCES = \
detect-tls-random.c \ detect-tls-random.c \
detect-tos.c \ detect-tos.c \
detect-transform-base64.c \ detect-transform-base64.c \
detect-transform-header-lowercase.c \
detect-transform-pcrexform.c \ detect-transform-pcrexform.c \
detect-transform-strip-pseudo-headers.c \
detect-transform-urldecode.c \ detect-transform-urldecode.c \
detect-transform-xor.c \ detect-transform-xor.c \
detect-ttl.c \ detect-ttl.c \

@ -215,11 +215,9 @@
#include "detect-ftpdata.h" #include "detect-ftpdata.h"
#include "detect-engine-content-inspection.h" #include "detect-engine-content-inspection.h"
#include "detect-transform-strip-pseudo-headers.h"
#include "detect-transform-pcrexform.h" #include "detect-transform-pcrexform.h"
#include "detect-transform-urldecode.h" #include "detect-transform-urldecode.h"
#include "detect-transform-xor.h" #include "detect-transform-xor.h"
#include "detect-transform-header-lowercase.h"
#include "detect-transform-base64.h" #include "detect-transform-base64.h"
#include "util-rule-vars.h" #include "util-rule-vars.h"

@ -1,88 +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
*
* \author Philippe Antoine <contact@catenacyber.fr>
*
* Implements the header_lowercase transform keyword with option support
*/
#include "suricata-common.h"
#include "detect.h"
#include "detect-engine.h"
#include "detect-parse.h"
#include "detect-transform-header-lowercase.h"
/**
* \internal
* \brief Apply the header_lowercase keyword to the last pattern match
* \param det_ctx detection engine ctx
* \param s signature
* \param optstr options string
* \retval 0 ok
* \retval -1 failure
*/
static int DetectTransformHeaderLowercaseSetup(
DetectEngineCtx *de_ctx, Signature *s, const char *optstr)
{
SCEnter();
int r = DetectSignatureAddTransform(s, DETECT_TRANSFORM_HEADER_LOWERCASE, NULL);
SCReturnInt(r);
}
static void DetectTransformHeaderLowercase(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];
// state 0 is header name, 1 is header value
int state = 0;
for (uint32_t i = 0; i < input_len; i++) {
if (state == 0) {
if (input[i] == ':') {
output[i] = input[i];
state = 1;
} else {
output[i] = u8_tolower(input[i]);
}
} else {
output[i] = input[i];
if (input[i] == '\n') {
state = 0;
}
}
}
InspectionBufferCopy(buffer, output, input_len);
}
void DetectTransformHeaderLowercaseRegister(void)
{
sigmatch_table[DETECT_TRANSFORM_HEADER_LOWERCASE].name = "header_lowercase";
sigmatch_table[DETECT_TRANSFORM_HEADER_LOWERCASE].desc =
"modify buffer via lowercaseing header names";
sigmatch_table[DETECT_TRANSFORM_HEADER_LOWERCASE].url =
"/rules/transforms.html#header_lowercase";
sigmatch_table[DETECT_TRANSFORM_HEADER_LOWERCASE].Transform = DetectTransformHeaderLowercase;
sigmatch_table[DETECT_TRANSFORM_HEADER_LOWERCASE].Setup = DetectTransformHeaderLowercaseSetup;
sigmatch_table[DETECT_TRANSFORM_HEADER_LOWERCASE].flags |= SIGMATCH_NOOPT;
}

@ -1,30 +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
*
* \author Philippe Antoine <contact@catenacyber.fr>
*/
#ifndef SURICATA_DETECT_TRANSFORM_HEADER_LOWERCASE_H
#define SURICATA_DETECT_TRANSFORM_HEADER_LOWERCASE_H
/* prototypes */
void DetectTransformHeaderLowercaseRegister(void);
#endif /* SURICATA_DETECT_TRANSFORM_HEADER_LOWERCASE_H */

@ -1,100 +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
*
* \author Philippe Antoine <contact@catenacyber.fr>
*
* Implements the strip_pseudo_headers transform keyword with option support
*/
#include "suricata-common.h"
#include "detect.h"
#include "detect-engine.h"
#include "detect-parse.h"
#include "detect-transform-strip-pseudo-headers.h"
/**
* \internal
* \brief Apply the strip_pseudo_headers keyword to the last pattern match
* \param det_ctx detection engine ctx
* \param s signature
* \param optstr options string
* \retval 0 ok
* \retval -1 failure
*/
static int DetectTransformStripPseudoHeadersSetup(
DetectEngineCtx *de_ctx, Signature *s, const char *optstr)
{
SCEnter();
int r = DetectSignatureAddTransform(s, DETECT_TRANSFORM_STRIP_PSEUDO_HEADERS, NULL);
SCReturnInt(r);
}
static void DetectTransformStripPseudoHeaders(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];
bool new_line = true;
bool pseudo = false;
uint32_t j = 0;
for (uint32_t i = 0; i < input_len; i++) {
if (new_line) {
if (input[i] == ':') {
pseudo = true;
}
if (input[i] != '\r' && input[i] != '\n') {
new_line = false;
}
} else {
if (input[i] == '\n') {
new_line = true;
if (!pseudo) {
output[j] = input[i];
j++;
}
pseudo = false;
continue;
}
}
if (!pseudo) {
output[j] = input[i];
j++;
}
}
InspectionBufferCopy(buffer, output, j);
}
void DetectTransformStripPseudoHeadersRegister(void)
{
sigmatch_table[DETECT_TRANSFORM_STRIP_PSEUDO_HEADERS].name = "strip_pseudo_headers";
sigmatch_table[DETECT_TRANSFORM_STRIP_PSEUDO_HEADERS].desc =
"modify buffer via stripping pseudo headers";
sigmatch_table[DETECT_TRANSFORM_STRIP_PSEUDO_HEADERS].url =
"/rules/transforms.html#strip_pseudo_headers";
sigmatch_table[DETECT_TRANSFORM_STRIP_PSEUDO_HEADERS].Transform =
DetectTransformStripPseudoHeaders;
sigmatch_table[DETECT_TRANSFORM_STRIP_PSEUDO_HEADERS].Setup =
DetectTransformStripPseudoHeadersSetup;
sigmatch_table[DETECT_TRANSFORM_STRIP_PSEUDO_HEADERS].flags |= SIGMATCH_NOOPT;
}

@ -1,30 +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
*
* \author Philippe Antoine <contact@catenacyber.fr>
*/
#ifndef SURICATA_DETECT_TRANSFORM_STRIP_PSEUDOHEADERS_H
#define SURICATA_DETECT_TRANSFORM_STRIP_PSEUDOHEADERS_H
/* prototypes */
void DetectTransformStripPseudoHeadersRegister(void);
#endif /* SURICATA_DETECT_TRANSFORM_STRIP_PSEUDOHEADERS_H */
Loading…
Cancel
Save