template: move detect keywords to pure rust

Ticket: 3195

Also remove unused src/tests/detect-template-buffer.c

Completes commit 4a7567b3f0
to remove references to template-rust
pull/11948/head
Philippe Antoine 1 year ago committed by Victor Julien
parent 87e6e9374f
commit 96c8470cdd

@ -0,0 +1,111 @@
/* 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::template::{TemplateTransaction, ALPROTO_TEMPLATE};
/* TEMPLATE_START_REMOVE */
use crate::conf::conf_get_node;
/* TEMPLATE_END_REMOVE */
use crate::core::Direction;
use crate::detect::{
DetectBufferSetActiveList, DetectHelperBufferMpmRegister, DetectHelperGetData,
DetectHelperKeywordRegister, DetectSignatureSetAppProto, SCSigTableElmt,
SIGMATCH_INFO_STICKY_BUFFER, SIGMATCH_NOOPT,
};
use std::os::raw::{c_int, c_void};
static mut G_TEMPLATE_BUFFER_BUFFER_ID: c_int = 0;
unsafe extern "C" fn template_buffer_setup(
de: *mut c_void, s: *mut c_void, _raw: *const std::os::raw::c_char,
) -> c_int {
if DetectSignatureSetAppProto(s, ALPROTO_TEMPLATE) != 0 {
return -1;
}
if DetectBufferSetActiveList(de, s, G_TEMPLATE_BUFFER_BUFFER_ID) < 0 {
return -1;
}
return 0;
}
/// Get the request/response buffer for a transaction from C.
unsafe extern "C" fn template_buffer_get_data(
tx: *const c_void, flags: u8, buf: *mut *const u8, len: *mut u32,
) -> bool {
let tx = cast_pointer!(tx, TemplateTransaction);
if flags & Direction::ToClient as u8 != 0 {
if let Some(ref response) = tx.response {
if !response.is_empty() {
*len = response.len() as u32;
*buf = response.as_ptr();
return true;
}
}
} else if let Some(ref request) = tx.request {
if !request.is_empty() {
*len = request.len() as u32;
*buf = request.as_ptr();
return true;
}
}
return false;
}
unsafe extern "C" fn template_buffer_get(
de: *mut c_void, transforms: *const c_void, flow: *const c_void, flow_flags: u8,
tx: *const c_void, list_id: c_int,
) -> *mut c_void {
return DetectHelperGetData(
de,
transforms,
flow,
flow_flags,
tx,
list_id,
template_buffer_get_data,
);
}
#[no_mangle]
pub unsafe extern "C" fn ScDetectTemplateRegister() {
/* TEMPLATE_START_REMOVE */
if conf_get_node("app-layer.protocols.template").is_none() {
return;
}
/* TEMPLATE_END_REMOVE */
// TODO create a suricata-verify test
// Setup a keyword structure and register it
let kw = SCSigTableElmt {
name: b"template.buffer\0".as_ptr() as *const libc::c_char,
desc: b"Template content modifier to match on the template buffer\0".as_ptr()
as *const libc::c_char,
// TODO use the right anchor for url and write doc
url: b"/rules/template-keywords.html#buffer\0".as_ptr() as *const libc::c_char,
Setup: template_buffer_setup,
flags: SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER,
AppLayerTxMatch: None,
Free: None,
};
let _g_template_buffer_kw_id = DetectHelperKeywordRegister(&kw);
G_TEMPLATE_BUFFER_BUFFER_ID = DetectHelperBufferMpmRegister(
b"template.buffer\0".as_ptr() as *const libc::c_char,
b"template.buffer intern description\0".as_ptr() as *const libc::c_char,
ALPROTO_TEMPLATE,
true, //toclient
true, //toserver
template_buffer_get,
);
}

@ -21,4 +21,5 @@ mod parser;
pub mod template;
/* TEMPLATE_START_REMOVE */
pub mod logger;
pub mod detect;
/* TEMPLATE_END_REMOVE */

@ -27,7 +27,7 @@ use std::os::raw::{c_char, c_int, c_void};
static mut TEMPLATE_MAX_TX: usize = 256;
static mut ALPROTO_TEMPLATE: AppProto = ALPROTO_UNKNOWN;
pub(super) static mut ALPROTO_TEMPLATE: AppProto = ALPROTO_UNKNOWN;
#[derive(AppLayerEvent)]
enum TemplateEvent {
@ -347,41 +347,6 @@ unsafe extern "C" fn rs_template_tx_get_alstate_progress(tx: *mut c_void, _direc
return 0;
}
/// Get the request buffer for a transaction from C.
///
/// No required for parsing, but an example function for retrieving a
/// pointer to the request buffer from C for detection.
#[no_mangle]
pub unsafe extern "C" fn rs_template_get_request_buffer(
tx: *mut c_void, buf: *mut *const u8, len: *mut u32,
) -> u8 {
let tx = cast_pointer!(tx, TemplateTransaction);
if let Some(ref request) = tx.request {
if !request.is_empty() {
*len = request.len() as u32;
*buf = request.as_ptr();
return 1;
}
}
return 0;
}
/// Get the response buffer for a transaction from C.
#[no_mangle]
pub unsafe extern "C" fn rs_template_get_response_buffer(
tx: *mut c_void, buf: *mut *const u8, len: *mut u32,
) -> u8 {
let tx = cast_pointer!(tx, TemplateTransaction);
if let Some(ref response) = tx.response {
if !response.is_empty() {
*len = response.len() as u32;
*buf = response.as_ptr();
return 1;
}
}
return 0;
}
export_tx_data_get!(rs_template_get_tx_data, TemplateTransaction);
export_state_data_get!(rs_template_get_state_data, TemplateState);

@ -101,7 +101,8 @@ def patch_rust_lib_rs(protoname):
output.write(line)
open(filename, "w").write(output.getvalue())
def patch_rust_applayer_mod_rs(protoname):
# arg is the name of the new module to add
def patch_rust_applayer_mod_rs(protoname, arg):
lower = protoname.lower()
filename = "rust/src/applayer%s/mod.rs" % (lower)
print("Patching %s." % (filename))
@ -110,7 +111,7 @@ def patch_rust_applayer_mod_rs(protoname):
with open(filename) as infile:
for line in infile:
if not done and line.find("mod parser") > -1:
output.write("pub mod logger;\n")
output.write("pub mod %s;\n" % arg)
done = True
output.write(line)
open(filename, "w").write(output.getvalue())
@ -234,68 +235,32 @@ def detect_copy_templates(proto, buffername):
buffername_lower = buffername.lower()
pairs = (
("src/detect-template-rust-buffer.h",
"src/detect-%s-%s.h" % (lower, buffername_lower)),
("src/detect-template-rust-buffer.c",
"src/detect-%s-%s.c" % (lower, buffername_lower)),
("rust/src/applayertemplate/detect.rs",
"rust/src/applayer%s/detect.rs" % (lower)),
)
replacements = (
("TEMPLATE_RUST_BUFFER", "%s_%s" % (
("TEMPLATE_BUFFER", "%s_%s" % (
proto.upper(), buffername.upper())),
("template-rust-buffer", "%s-%s" % (
("template.buffer", "%s.%s" % (
proto.lower(), buffername.lower())),
("template_rust_buffer", "%s_%s" % (
("template_buffer", "%s_%s" % (
proto.lower(), buffername.lower())),
("TemplateRustBuffer", "%s%s" % (proto, buffername)),
)
common_copy_templates(proto, pairs, replacements)
def detect_patch_makefile_am(protoname, buffername):
filename = "src/Makefile.am"
print("Patching %s." % (filename))
output = io.StringIO()
with open(filename) as infile:
for line in infile:
if line.lstrip().startswith("detect-template-buffer."):
new = line.replace("template-buffer", "%s-%s" % (
protoname.lower(), buffername.lower()))
output.write(new)
output.write(line)
open(filename, "w").write(output.getvalue())
def detect_patch_detect_engine_register_c(protoname, buffername):
def detect_patch_detect_engine_register_c(protoname):
filename = "src/detect-engine-register.c"
print("Patching %s." % (filename))
output = io.StringIO()
with open(filename) as infile:
for line in infile:
if line.find("detect-template-buffer.h") > -1:
new = line.replace("template-buffer", "%s-%s" % (
protoname.lower(), buffername.lower()))
output.write(new)
if line.find("DetectTemplateBufferRegister") > -1:
new = line.replace("TemplateBuffer", "%s%s" % (
protoname, buffername))
output.write(new)
output.write(line)
open(filename, "w").write(output.getvalue())
def detect_patch_detect_engine_register_h(protoname, buffername):
filename = "src/detect-engine-register.h"
print("Patching %s." % (filename))
output = io.StringIO()
with open(filename) as infile:
for line in infile:
if line.find("DETECT_AL_TEMPLATE_BUFFER") > -1:
new = line.replace("TEMPLATE_BUFFER", "%s_%s" % (
protoname.upper(), buffername.upper()))
if line.find("ScDetect%sRegister" % protoname) > -1:
# patch already applied
return
if line.find("ScDetectTemplateRegister") > -1:
new = line.replace("Template", "%s" % protoname)
output.write(new)
output.write(line)
open(filename, "w").write(output.getvalue())
@ -388,7 +353,7 @@ def main():
if not proto_exists(proto):
raise SetupError("no app-layer parser exists for %s" % (proto))
logger_copy_templates(proto)
patch_rust_applayer_mod_rs(proto)
patch_rust_applayer_mod_rs(proto, "logger")
logger_patch_output_c(proto)
logger_patch_suricata_yaml_in(proto)
@ -396,9 +361,8 @@ def main():
if not proto_exists(proto):
raise SetupError("no app-layer parser exists for %s" % (proto))
detect_copy_templates(proto, args.buffer)
detect_patch_makefile_am(proto, args.buffer)
detect_patch_detect_engine_register_c(proto, args.buffer)
detect_patch_detect_engine_register_h(proto, args.buffer)
detect_patch_detect_engine_register_c(proto)
patch_rust_applayer_mod_rs(proto, "detect")
if parser:
print("""

@ -287,7 +287,6 @@ noinst_HEADERS = \
detect-tcp-window.h \
detect-template2.h \
detect-template.h \
detect-template-rust-buffer.h \
detect-threshold.h \
detect-tls-alpn.h \
detect-tls-cert-fingerprint.h \
@ -857,7 +856,6 @@ libsuricata_c_a_SOURCES = \
detect-tcp-window.c \
detect-template2.c \
detect-template.c \
detect-template-rust-buffer.c \
detect-threshold.c \
detect-tls.c \
detect-tls-alpn.c \
@ -1176,7 +1174,6 @@ EXTRA_DIST = \
tests/detect-http-user-agent.c \
tests/detect-ssl-state.c \
tests/detect-ssl-version.c \
tests/detect-template-buffer.c \
tests/detect-tls-cert-fingerprint.c \
tests/detect-tls-cert-issuer.c \
tests/detect-tls-cert-serial.c \

@ -204,7 +204,6 @@
#include "detect-sip-method.h"
#include "detect-sip-uri.h"
#include "detect-target.h"
#include "detect-template-rust-buffer.h"
#include "detect-quic-sni.h"
#include "detect-quic-ua.h"
#include "detect-quic-version.h"
@ -660,7 +659,6 @@ void SigTableSetup(void)
DetectSipMethodRegister();
DetectSipUriRegister();
DetectTargetRegister();
DetectTemplateRustBufferRegister();
DetectQuicSniRegister();
DetectQuicUaRegister();
DetectQuicVersionRegister();
@ -695,6 +693,7 @@ void SigTableSetup(void)
ScDetectMqttRegister();
ScDetectRfbRegister();
ScDetectSipRegister();
ScDetectTemplateRegister();
/* close keyword registration */
DetectBufferTypeCloseRegistration();

@ -291,7 +291,6 @@ enum DetectKeywordId {
DETECT_TCPMSS,
DETECT_FTPDATA,
DETECT_TARGET,
DETECT_AL_TEMPLATE_BUFFER,
DETECT_AL_QUIC_VERSION,
DETECT_AL_QUIC_SNI,
DETECT_AL_QUIC_UA,

@ -1,192 +0,0 @@
/* Copyright (C) 2015-2022 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.
*/
/*
* TODO: Update the \author in this file and detect-template.h.
* TODO: Update description in the \file section below.
* TODO: Remove SCLogNotice statements or convert to debug.
*/
/**
* \file
*
* \author FirstName LastName <yourname@domain>
*
* Set up of the "template_rust" keyword to allow content
* inspections on the decoded template application layer buffers.
*/
#include "suricata-common.h"
#include "conf.h"
#include "detect.h"
#include "detect-parse.h"
#include "detect-engine.h"
#include "detect-engine-content-inspection.h"
#include "detect-template-rust-buffer.h"
#include "app-layer-parser.h"
#include "detect-engine-build.h"
#include "rust.h"
#ifdef UNITTESTS
static void DetectTemplateRustBufferRegisterTests(void);
#endif
static int g_template_rust_id = 0;
static int DetectTemplateRustBufferSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str)
{
s->init_data->list = g_template_rust_id;
if (DetectSignatureSetAppProto(s, ALPROTO_TEMPLATE) != 0)
return -1;
return 0;
}
static InspectionBuffer *GetData(DetectEngineThreadCtx *det_ctx,
const DetectEngineTransforms *transforms, Flow *_f, const uint8_t flags, void *txv,
const int list_id)
{
InspectionBuffer *buffer = InspectionBufferGet(det_ctx, list_id);
if (!buffer->initialized) {
uint32_t data_len = 0;
const uint8_t *data = NULL;
if (flags & STREAM_TOSERVER) {
rs_template_get_request_buffer(txv, &data, &data_len);
} else {
rs_template_get_response_buffer(txv, &data, &data_len);
}
InspectionBufferSetup(det_ctx, list_id, buffer, data, data_len);
InspectionBufferApplyTransforms(buffer, transforms);
}
return buffer;
}
void DetectTemplateRustBufferRegister(void)
{
/* TEMPLATE_START_REMOVE */
if (ConfGetNode("app-layer.protocols.template") == NULL) {
return;
}
/* TEMPLATE_END_REMOVE */
sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].name = "template.buffer";
sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].desc =
"Template content modifier to match on the template buffers";
sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].Setup = DetectTemplateRustBufferSetup;
#ifdef UNITTESTS
sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].RegisterTests = DetectTemplateRustBufferRegisterTests;
#endif
sigmatch_table[DETECT_AL_TEMPLATE_BUFFER].flags |= SIGMATCH_NOOPT;
/* register inspect engines */
DetectAppLayerInspectEngineRegister("template_buffer", ALPROTO_TEMPLATE, SIG_FLAG_TOSERVER, 0,
DetectEngineInspectBufferGeneric, GetData);
DetectAppLayerInspectEngineRegister("template_buffer", ALPROTO_TEMPLATE, SIG_FLAG_TOCLIENT, 0,
DetectEngineInspectBufferGeneric, GetData);
g_template_rust_id = DetectBufferTypeGetByName("template_buffer");
SCLogNotice("Template application layer detect registered.");
}
#ifdef UNITTESTS
#include "util-unittest.h"
#include "util-unittest-helper.h"
#include "flow-util.h"
#include "stream-tcp.h"
#include "detect-engine-alert.h"
static int DetectTemplateRustBufferTest(void)
{
AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
DetectEngineThreadCtx *det_ctx = NULL;
DetectEngineCtx *de_ctx = NULL;
Flow f;
Packet *p;
TcpSession tcp;
ThreadVars tv;
Signature *s;
uint8_t request[] = "12:Hello World!";
/* Setup flow. */
memset(&f, 0, sizeof(Flow));
memset(&tcp, 0, sizeof(TcpSession));
memset(&tv, 0, sizeof(ThreadVars));
p = UTHBuildPacket(request, sizeof(request), IPPROTO_TCP);
FLOW_INITIALIZE(&f);
f.alproto = ALPROTO_TEMPLATE;
f.protoctx = (void *)&tcp;
f.proto = IPPROTO_TCP;
f.flags |= FLOW_IPV4;
p->flow = &f;
p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED;
StreamTcpInitConfig(true);
de_ctx = DetectEngineCtxInit();
FAIL_IF_NULL(de_ctx);
/* This rule should match. */
s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any ("
"msg:\"TEMPLATE Test Rule\"; "
"template.buffer; content:\"World!\"; "
"sid:1; rev:1;)");
FAIL_IF_NULL(s);
/* This rule should not match. */
s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any ("
"msg:\"TEMPLATE Test Rule\"; "
"template.buffer; content:\"W0rld!\"; "
"sid:2; rev:1;)");
FAIL_IF_NULL(s);
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
AppLayerParserParse(
NULL, alp_tctx, &f, ALPROTO_TEMPLATE, STREAM_TOSERVER, request, sizeof(request));
/* Check that we have app-layer state. */
FAIL_IF_NULL(f.alstate);
SigMatchSignatures(&tv, de_ctx, det_ctx, p);
FAIL_IF(!PacketAlertCheck(p, 1));
FAIL_IF(PacketAlertCheck(p, 2));
/* Cleanup. */
if (alp_tctx != NULL)
AppLayerParserThreadCtxFree(alp_tctx);
if (det_ctx != NULL)
DetectEngineThreadCtxDeinit(&tv, det_ctx);
if (de_ctx != NULL)
SigGroupCleanup(de_ctx);
if (de_ctx != NULL)
DetectEngineCtxFree(de_ctx);
StreamTcpFreeConfig(true);
FLOW_DESTROY(&f);
UTHFreePacket(p);
PASS;
}
static void DetectTemplateRustBufferRegisterTests(void)
{
UtRegisterTest("DetectTemplateRustBufferTest",
DetectTemplateRustBufferTest);
}
#endif /* UNITTESTS */

@ -1,29 +0,0 @@
/* Copyright (C) 2015-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 FirstName LastName <yourname@domain>
*/
#ifndef SURICATA_DETECT_TEMPLATE_RUST_BUFFER_H
#define SURICATA_DETECT_TEMPLATE_RUST_BUFFER_H
void DetectTemplateRustBufferRegister(void);
#endif /* SURICATA_DETECT_TEMPLATE_RUST_BUFFER_H */

@ -1,104 +0,0 @@
/* Copyright (C) 2015-2018 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 "../util-unittest.h"
#include "../util-unittest-helper.h"
#include "../app-layer-parser.h"
#include "../detect-engine.h"
#include "../detect-parse.h"
#include "../flow-util.h"
#include "../stream-tcp.h"
#include "../detect-engine-build.h"
static int DetectTemplateBufferTest(void)
{
AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
FAIL_IF_NULL(alp_tctx);
Flow f;
Packet *p;
TcpSession tcp;
ThreadVars tv;
Signature *s;
uint8_t request[] = "Hello World!";
/* Setup flow. */
memset(&f, 0, sizeof(Flow));
memset(&tcp, 0, sizeof(TcpSession));
memset(&tv, 0, sizeof(ThreadVars));
p = UTHBuildPacket(request, sizeof(request), IPPROTO_TCP);
FLOW_INITIALIZE(&f);
f.alproto = ALPROTO_TEMPLATE;
f.protoctx = (void *)&tcp;
f.proto = IPPROTO_TCP;
f.flags |= FLOW_IPV4;
p->flow = &f;
p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED;
StreamTcpInitConfig(true);
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
FAIL_IF_NULL(de_ctx);
/* This rule should match. */
s = DetectEngineAppendSig(de_ctx,
"alert tcp any any -> any any ("
"msg:\"TEMPLATE Test Rule\"; "
"template_buffer; content:\"World!\"; "
"sid:1; rev:1;)");
FAIL_IF_NULL(s);
/* This rule should not match. */
s = DetectEngineAppendSig(de_ctx,
"alert tcp any any -> any any ("
"msg:\"TEMPLATE Test Rule\"; "
"template_buffer; content:\"W0rld!\"; "
"sid:2; rev:1;)");
FAIL_IF_NULL(s);
SigGroupBuild(de_ctx);
DetectEngineThreadCtx *det_ctx = NULL;
DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
FAIL_IF_NULL(det_ctx);
AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_TEMPLATE,
STREAM_TOSERVER, request, sizeof(request));
/* Check that we have app-layer state. */
FAIL_IF_NULL(f.alstate);
SigMatchSignatures(&tv, de_ctx, det_ctx, p);
FAIL_IF(!PacketAlertCheck(p, 1));
FAIL_IF(PacketAlertCheck(p, 2));
/* Cleanup. */
AppLayerParserThreadCtxFree(alp_tctx);
DetectEngineThreadCtxDeinit(&tv, det_ctx);
DetectEngineCtxFree(de_ctx);
StreamTcpFreeConfig(true);
FLOW_DESTROY(&f);
UTHFreePacket(p);
PASS;
}
static void DetectTemplateBufferRegisterTests(void)
{
UtRegisterTest("DetectTemplateBufferTest", DetectTemplateBufferTest);
}
Loading…
Cancel
Save