From dee0f03db45bad32fac4ab9c55d07fd9e5bd0acf Mon Sep 17 00:00:00 2001 From: Philippe Antoine Date: Tue, 28 Jul 2026 15:46:17 +0200 Subject: [PATCH] detect/modbus: move modbus keyword to rust Ticket: 3195 --- rust/src/modbus/detect.rs | 202 +++++++++++++++++++++++------------ rust/src/modbus/modbus.rs | 2 +- src/Makefile.am | 2 - src/detect-engine-register.c | 3 +- src/detect-modbus.c | 134 ----------------------- src/detect-modbus.h | 40 ------- 6 files changed, 133 insertions(+), 250 deletions(-) delete mode 100644 src/detect-modbus.c delete mode 100644 src/detect-modbus.h diff --git a/rust/src/modbus/detect.rs b/rust/src/modbus/detect.rs index ec07a57529..203442f65f 100644 --- a/rust/src/modbus/detect.rs +++ b/rust/src/modbus/detect.rs @@ -16,13 +16,20 @@ */ use super::modbus::ModbusTransaction; +use super::modbus::ALPROTO_MODBUS; +use crate::core::STREAM_TOSERVER; use lazy_static::lazy_static; use regex::Regex; use sawp_modbus::{AccessType, CodeCategory, Data, Flags, FunctionCode, Message}; use std::ffi::CStr; use std::ops::{Range, RangeInclusive}; -use std::os::raw::{c_char, c_void}; +use std::os::raw::{c_char, c_int, c_void}; use std::str::FromStr; +use suricata_sys::sys::{ + AppProto, DetectEngineCtx, DetectEngineThreadCtx, Flow, SCDetectHelperBufferProgressRegister, + SCDetectHelperKeywordRegister, SCDetectSignatureSetAppProto, SCSigMatchAppendSMToList, + SCSigTableAppLiteElmt, SigMatchCtx, Signature, +}; lazy_static! { static ref ACCESS_RE: Regex = Regex::new( @@ -133,8 +140,7 @@ fn parse_range(min_str: &str, max_str: &str) -> Result, ()> { } /// Intermediary function between the C code and the parsing functions. -#[no_mangle] -pub unsafe extern "C" fn SCModbusParse(c_arg: *const c_char) -> *mut c_void { +unsafe extern "C" fn modbus_parse(c_arg: *const c_char) -> *mut c_void { if c_arg.is_null() { return std::ptr::null_mut(); } @@ -150,17 +156,9 @@ pub unsafe extern "C" fn SCModbusParse(c_arg: *const c_char) -> *mut c_void { std::ptr::null_mut() } -#[no_mangle] -pub unsafe extern "C" fn SCModbusFree(ptr: *mut c_void) { - if !ptr.is_null() { - let _ = Box::from_raw(ptr as *mut DetectModbusRust); - } -} - /// Compares a transaction to a signature to determine whether the transaction /// matches the signature. If it does, 1 is returned; otherwise 0 is returned. -#[no_mangle] -pub extern "C" fn SCModbusInspect(tx: &ModbusTransaction, modbus: &DetectModbusRust) -> u8 { +fn modbus_inspect(tx: &ModbusTransaction, modbus: &DetectModbusRust) -> c_int { // All necessary information can be found in the request (value inspection currently // only supports write functions, which hold the value in the request). // Only inspect the response in the case where there is no request. @@ -189,18 +187,18 @@ pub extern "C" fn SCModbusInspect(tx: &ModbusTransaction, modbus: &DetectModbusR return 0; } - return inspect_data(msg, modbus) as u8; + return inspect_data(msg, modbus) as c_int; } if let Some(category) = modbus.category { - return u8::from(msg.category.intersects(category)); + return c_int::from(msg.category.intersects(category)); } match &modbus.function { Some(func) if func == &msg.function.code => match modbus.subfunction { Some(subfunc) => { if let Data::Diagnostic { func, data: _ } = &msg.data { - u8::from(subfunc == func.raw) + c_int::from(subfunc == func.raw) } else { 0 } @@ -458,6 +456,68 @@ fn parse_unit_id(unit_str: &str) -> Result { Ok(modbus) } +static mut G_MODBUS_KW_ID: u16 = 0; +static mut G_MODBUS_BUFFER_ID: c_int = 0; + +unsafe extern "C" fn modbus_setup( + de: *mut DetectEngineCtx, s: *mut Signature, raw: *const libc::c_char, +) -> c_int { + if SCDetectSignatureSetAppProto(s, ALPROTO_MODBUS as AppProto) != 0 { + return -1; + } + let ctx = modbus_parse(raw) as *mut c_void; + if ctx.is_null() { + return -1; + } + if SCSigMatchAppendSMToList( + de, + s, + G_MODBUS_KW_ID, + ctx as *mut SigMatchCtx, + G_MODBUS_BUFFER_ID, + ) + .is_null() + { + modbus_free(std::ptr::null_mut(), ctx); + return -1; + } + return 0; +} + +unsafe extern "C" fn modbus_match( + _de: *mut DetectEngineThreadCtx, _f: *mut Flow, _flags: u8, _state: *mut c_void, + tx: *mut c_void, _sig: *const Signature, ctx: *const SigMatchCtx, +) -> c_int { + let tx = cast_pointer!(tx, ModbusTransaction); + let ctx = cast_pointer!(ctx, DetectModbusRust); + return modbus_inspect(tx, ctx); +} + +unsafe extern "C" fn modbus_free(_de: *mut DetectEngineCtx, ctx: *mut c_void) { + let ctx = cast_pointer!(ctx, DetectModbusRust); + std::mem::drop(Box::from_raw(ctx)); +} + +#[no_mangle] +pub unsafe extern "C" fn SCDetectModbusRegister() { + let kw = SCSigTableAppLiteElmt { + name: b"modbus\0".as_ptr() as *const libc::c_char, + desc: b"match on various properties of Modbus requests\0".as_ptr() as *const libc::c_char, + url: b"/rules/modbus-keyword.html#modbus-keyword\0".as_ptr() as *const libc::c_char, + AppLayerTxMatch: Some(modbus_match), + Setup: Some(modbus_setup), + Free: Some(modbus_free), + flags: 0, + }; + G_MODBUS_KW_ID = SCDetectHelperKeywordRegister(&kw); + G_MODBUS_BUFFER_ID = SCDetectHelperBufferProgressRegister( + b"modbus\0".as_ptr() as *const libc::c_char, + ALPROTO_MODBUS as AppProto, + STREAM_TOSERVER, + 0, + ); +} + #[cfg(test)] mod test { use super::super::modbus::ModbusState; @@ -633,7 +693,7 @@ mod test { assert_eq!(modbus.transactions.len(), 1); // function 23 assert_eq!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[0], &DetectModbusRust { function: Some(FunctionCode::RdWrMultRegs), @@ -644,7 +704,7 @@ mod test { ); // access write holding, address 15, value <4660 assert_ne!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[0], &DetectModbusRust { access_type: Some(AccessType::WRITE | AccessType::HOLDING), @@ -657,7 +717,7 @@ mod test { ); // access write holding, address 15, value 4661 assert_ne!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[0], &DetectModbusRust { access_type: Some(AccessType::WRITE | AccessType::HOLDING), @@ -670,7 +730,7 @@ mod test { ); // access write holding, address 16, value 20000<>22136 assert_ne!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[0], &DetectModbusRust { access_type: Some(AccessType::WRITE | AccessType::HOLDING), @@ -683,7 +743,7 @@ mod test { ); // access write holding, address 16, value 22136<>30000 assert_ne!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[0], &DetectModbusRust { access_type: Some(AccessType::WRITE | AccessType::HOLDING), @@ -696,7 +756,7 @@ mod test { ); // access write holding, address 15, value >4660 assert_ne!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[0], &DetectModbusRust { access_type: Some(AccessType::WRITE | AccessType::HOLDING), @@ -709,7 +769,7 @@ mod test { ); // access write holding, address 16, value <22137 assert_eq!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[0], &DetectModbusRust { access_type: Some(AccessType::WRITE | AccessType::HOLDING), @@ -722,7 +782,7 @@ mod test { ); // access write holding, address 16, value <22137 assert_eq!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[0], &DetectModbusRust { access_type: Some(AccessType::WRITE | AccessType::HOLDING), @@ -735,7 +795,7 @@ mod test { ); // access write holding, address 17, value 39612 assert_eq!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[0], &DetectModbusRust { access_type: Some(AccessType::WRITE | AccessType::HOLDING), @@ -748,7 +808,7 @@ mod test { ); // access write holding, address 17, value 30000<>39613 assert_eq!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[0], &DetectModbusRust { access_type: Some(AccessType::WRITE | AccessType::HOLDING), @@ -761,7 +821,7 @@ mod test { ); // access write holding, address 15, value 4659<>5000 assert_eq!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[0], &DetectModbusRust { access_type: Some(AccessType::WRITE | AccessType::HOLDING), @@ -774,7 +834,7 @@ mod test { ); // access write holding, address 17, value >39611 assert_eq!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[0], &DetectModbusRust { access_type: Some(AccessType::WRITE | AccessType::HOLDING), @@ -787,7 +847,7 @@ mod test { ); // unit 12 assert_ne!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[0], &DetectModbusRust { unit_id: Some(12..12), @@ -798,7 +858,7 @@ mod test { ); // unit 5<>9 assert_ne!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[0], &DetectModbusRust { unit_id: Some(5..9), @@ -809,7 +869,7 @@ mod test { ); // unit 11<>15 assert_ne!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[0], &DetectModbusRust { unit_id: Some(11..15), @@ -820,7 +880,7 @@ mod test { ); // unit >11 assert_ne!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[0], &DetectModbusRust { unit_id: Some(11..u16::MAX), @@ -831,7 +891,7 @@ mod test { ); // unit <9 assert_ne!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[0], &DetectModbusRust { unit_id: Some(u16::MIN..9), @@ -842,7 +902,7 @@ mod test { ); // unit 10 assert_eq!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[0], &DetectModbusRust { unit_id: Some(10..10), @@ -853,7 +913,7 @@ mod test { ); // unit 5<>15 assert_eq!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[0], &DetectModbusRust { unit_id: Some(5..15), @@ -864,7 +924,7 @@ mod test { ); // unit >9 assert_eq!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[0], &DetectModbusRust { unit_id: Some(9..u16::MAX), @@ -875,7 +935,7 @@ mod test { ); // unit <11 assert_eq!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[0], &DetectModbusRust { unit_id: Some(u16::MIN..11), @@ -886,7 +946,7 @@ mod test { ); // unit 10, function 20 assert_ne!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[0], &DetectModbusRust { function: Some(FunctionCode::RdFileRec), @@ -898,7 +958,7 @@ mod test { ); // unit 11, function 20 assert_ne!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[0], &DetectModbusRust { function: Some(FunctionCode::RdFileRec), @@ -910,7 +970,7 @@ mod test { ); // unit 11, function 23 assert_ne!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[0], &DetectModbusRust { function: Some(FunctionCode::RdWrMultRegs), @@ -922,7 +982,7 @@ mod test { ); // unit 11, function public assert_ne!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[0], &DetectModbusRust { category: Some(CodeCategory::PUBLIC_ASSIGNED | CodeCategory::PUBLIC_UNASSIGNED), @@ -934,7 +994,7 @@ mod test { ); // unit 10, function user assert_ne!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[0], &DetectModbusRust { category: Some(Flags::from(CodeCategory::USER_DEFINED)), @@ -946,7 +1006,7 @@ mod test { ); // unit 10, function 23 assert_eq!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[0], &DetectModbusRust { function: Some(FunctionCode::RdWrMultRegs), @@ -958,7 +1018,7 @@ mod test { ); // unit 10, function public assert_eq!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[0], &DetectModbusRust { category: Some(CodeCategory::PUBLIC_ASSIGNED | CodeCategory::PUBLIC_UNASSIGNED), @@ -970,7 +1030,7 @@ mod test { ); // unit 10, function !user assert_eq!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[0], &DetectModbusRust { category: Some(!CodeCategory::USER_DEFINED), @@ -1001,7 +1061,7 @@ mod test { assert_eq!(modbus.transactions.len(), 2); // function 8, subfunction 4 assert_eq!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[1], &DetectModbusRust { function: Some(FunctionCode::Diagnostic), @@ -1032,7 +1092,7 @@ mod test { assert_eq!(modbus.transactions.len(), 3); // function reserved assert_eq!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[2], &DetectModbusRust { category: Some(Flags::from(CodeCategory::RESERVED)), @@ -1060,7 +1120,7 @@ mod test { assert_eq!(modbus.transactions.len(), 4); // function !assigned assert_ne!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[3], &DetectModbusRust { category: Some(!CodeCategory::PUBLIC_ASSIGNED), @@ -1090,7 +1150,7 @@ mod test { assert_eq!(modbus.transactions.len(), 5); // access read assert_eq!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[4], &DetectModbusRust { access_type: Some(Flags::from(AccessType::READ)), @@ -1101,7 +1161,7 @@ mod test { ); // access read, address 30870 assert_eq!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[4], &DetectModbusRust { access_type: Some(Flags::from(AccessType::READ)), @@ -1113,7 +1173,7 @@ mod test { ); // unit 10, access read, address 30863 assert_ne!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[4], &DetectModbusRust { access_type: Some(Flags::from(AccessType::READ)), @@ -1126,7 +1186,7 @@ mod test { ); // unit 11, access read, address 30870 assert_ne!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[4], &DetectModbusRust { access_type: Some(Flags::from(AccessType::READ)), @@ -1139,7 +1199,7 @@ mod test { ); // unit 11, access read, address 30863 assert_ne!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[4], &DetectModbusRust { access_type: Some(Flags::from(AccessType::READ)), @@ -1152,7 +1212,7 @@ mod test { ); // unit 10, access write assert_ne!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[4], &DetectModbusRust { access_type: Some(Flags::from(AccessType::WRITE)), @@ -1164,7 +1224,7 @@ mod test { ); // unit 10, access read, address 30870 assert_eq!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[4], &DetectModbusRust { access_type: Some(Flags::from(AccessType::READ)), @@ -1196,7 +1256,7 @@ mod test { assert_eq!(modbus.transactions.len(), 6); // access read input assert_eq!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[5], &DetectModbusRust { access_type: Some(AccessType::READ | AccessType::INPUT), @@ -1207,7 +1267,7 @@ mod test { ); // access read input, address <9 assert_ne!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[5], &DetectModbusRust { access_type: Some(AccessType::READ | AccessType::INPUT), @@ -1219,7 +1279,7 @@ mod test { ); // access read input, address 5<>9 assert_ne!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[5], &DetectModbusRust { access_type: Some(AccessType::READ | AccessType::INPUT), @@ -1231,7 +1291,7 @@ mod test { ); // access read input, address >104 assert_ne!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[5], &DetectModbusRust { access_type: Some(AccessType::READ | AccessType::INPUT), @@ -1243,7 +1303,7 @@ mod test { ); // access read input, address 104<>110 assert_ne!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[5], &DetectModbusRust { access_type: Some(AccessType::READ | AccessType::INPUT), @@ -1255,7 +1315,7 @@ mod test { ); // access read input, address 9 assert_eq!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[5], &DetectModbusRust { access_type: Some(AccessType::READ | AccessType::INPUT), @@ -1267,7 +1327,7 @@ mod test { ); // access read input, address <10 assert_eq!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[5], &DetectModbusRust { access_type: Some(AccessType::READ | AccessType::INPUT), @@ -1279,7 +1339,7 @@ mod test { ); // access read input, address 5<>10 assert_eq!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[5], &DetectModbusRust { access_type: Some(AccessType::READ | AccessType::INPUT), @@ -1291,7 +1351,7 @@ mod test { ); // access read input, address >103 assert_eq!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[5], &DetectModbusRust { access_type: Some(AccessType::READ | AccessType::INPUT), @@ -1303,7 +1363,7 @@ mod test { ); // access read input, address 103<>110 assert_eq!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[5], &DetectModbusRust { access_type: Some(AccessType::READ | AccessType::INPUT), @@ -1315,7 +1375,7 @@ mod test { ); // access read input, address 104 assert_eq!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[5], &DetectModbusRust { access_type: Some(AccessType::READ | AccessType::INPUT), @@ -1347,7 +1407,7 @@ mod test { assert_eq!(modbus.transactions.len(), 7); // function 1 assert_eq!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[6], &DetectModbusRust { function: Some(FunctionCode::RdCoils), @@ -1360,7 +1420,7 @@ mod test { // Fails because there was no request, and the address is not retrievable // from the response. assert_ne!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[6], &DetectModbusRust { access_type: Some(Flags::from(AccessType::READ)), @@ -1392,7 +1452,7 @@ mod test { assert_eq!(modbus.transactions.len(), 8); // function 6 assert_eq!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[7], &DetectModbusRust { function: Some(FunctionCode::WrSingleReg), @@ -1403,7 +1463,7 @@ mod test { ); // access write, address 10 assert_ne!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[7], &DetectModbusRust { access_type: Some(Flags::from(AccessType::WRITE)), @@ -1435,7 +1495,7 @@ mod test { assert_eq!(modbus.transactions.len(), 9); // function 8 assert_eq!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[8], &DetectModbusRust { function: Some(FunctionCode::Diagnostic), @@ -1446,7 +1506,7 @@ mod test { ); // access read assert_ne!( - SCModbusInspect( + modbus_inspect( &modbus.transactions[8], &DetectModbusRust { access_type: Some(Flags::from(AccessType::READ)), diff --git a/rust/src/modbus/modbus.rs b/rust/src/modbus/modbus.rs index c073abb051..18ddf8ce4a 100644 --- a/rust/src/modbus/modbus.rs +++ b/rust/src/modbus/modbus.rs @@ -34,7 +34,7 @@ use suricata_sys::sys::{ pub const REQUEST_FLOOD: usize = 500; // Default unreplied Modbus requests are considered a flood pub const MODBUS_PARSER: sawp_modbus::Modbus = sawp_modbus::Modbus { probe_strict: true }; -static mut ALPROTO_MODBUS: AppProto = ALPROTO_UNKNOWN; +pub(super) static mut ALPROTO_MODBUS: AppProto = ALPROTO_UNKNOWN; #[derive(AppLayerEvent)] enum ModbusEvent { diff --git a/src/Makefile.am b/src/Makefile.am index 5c9baef5d0..b0dbad0ecb 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -247,7 +247,6 @@ noinst_HEADERS = \ detect-lua.h \ detect-mark.h \ detect-metadata.h \ - detect-modbus.h \ detect-msg.h \ detect-noalert.h \ detect-nocase.h \ @@ -823,7 +822,6 @@ libsuricata_c_a_SOURCES = \ detect-lua.c \ detect-mark.c \ detect-metadata.c \ - detect-modbus.c \ detect-msg.c \ detect-noalert.c \ detect-nocase.c \ diff --git a/src/detect-engine-register.c b/src/detect-engine-register.c index 797f08ddae..be3ca64bb6 100644 --- a/src/detect-engine-register.c +++ b/src/detect-engine-register.c @@ -227,7 +227,6 @@ #include "detect-http-stat-code.h" #include "detect-ssl-version.h" #include "detect-ssl-state.h" -#include "detect-modbus.h" #include "detect-dnp3.h" #include "detect-vlan.h" #include "detect-email.h" @@ -589,7 +588,6 @@ void SigTableSetup(void) DetectDnsNameRegister(); DetectDnsResponseRegister(); - DetectModbusRegister(); DetectDNP3Register(); DetectTlsSniRegister(); @@ -769,6 +767,7 @@ void SigTableSetup(void) SCDetectDcerpcRegister(); SCDetectKrb5Register(); SCDetectNfsRegister(); + SCDetectModbusRegister(); for (size_t i = 0; i < preregistered_callbacks_nb; i++) { PreregisteredCallbacks[i](); diff --git a/src/detect-modbus.c b/src/detect-modbus.c deleted file mode 100644 index 866428537b..0000000000 --- a/src/detect-modbus.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) 2014 ANSSI - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * \file - * - * \author David DIALLO - * - * Implements the Modbus function and access keywords - * You can specify a: - * - concrete function like Modbus: - * function 8, subfunction 4 (diagnostic: Force Listen Only Mode) - * - data (in primary table) register access (r/w) like Modbus: - * access read coils, address 1000 (.i.e Read coils: at address 1000) - * - write data value at specific address Modbus: - * access write, address 1500<>2000, value >2000 (Write multiple coils/register: - * at address between 1500 and 2000 value greater than 2000) - */ - -#include "suricata-common.h" - -#include "detect.h" -#include "detect-parse.h" -#include "detect-engine.h" - -#include "detect-modbus.h" - -#include "util-debug.h" -#include "util-byte.h" - -#include "stream-tcp.h" -#include "rust.h" - -static int g_modbus_buffer_id = 0; - -/** \internal - * - * \brief this function will free memory associated with DetectModbus - * - * \param ptr pointer to DetectModbus - */ -static void DetectModbusFree(DetectEngineCtx *de_ctx, void *ptr) { - SCEnter(); - if (ptr != NULL) { - SCModbusFree(ptr); - } - SCReturn; -} - -/** \internal - * - * \brief this function is used to add the parsed "id" option into the current signature - * - * \param de_ctx Pointer to the Detection Engine Context - * \param s Pointer to the Current Signature - * \param str Pointer to the user provided "id" option - * - * \retval 0 on Success or -1 on Failure - */ -static int DetectModbusSetup(DetectEngineCtx *de_ctx, Signature *s, const char *str) -{ - SCEnter(); - DetectModbusRust *modbus = NULL; - - if (SCDetectSignatureSetAppProto(s, ALPROTO_MODBUS) != 0) - return -1; - - if ((modbus = SCModbusParse(str)) == NULL) { - SCLogError("invalid modbus option"); - goto error; - } - - /* Okay so far so good, lets get this into a SigMatch and put it in the Signature. */ - if (SCSigMatchAppendSMToList( - de_ctx, s, DETECT_MODBUS, (SigMatchCtx *)modbus, g_modbus_buffer_id) == NULL) { - goto error; - } - - SCReturnInt(0); - -error: - if (modbus != NULL) - DetectModbusFree(de_ctx, modbus); - SCReturnInt(-1); -} - -static int DetectModbusMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags, void *state, - void *txv, const Signature *s, const SigMatchCtx *ctx) -{ - return SCModbusInspect(txv, (void *)ctx); -} - -/** - * \brief Registration function for Modbus keyword - */ -void DetectModbusRegister(void) -{ - sigmatch_table[DETECT_MODBUS].name = "modbus"; - sigmatch_table[DETECT_MODBUS].desc = "match on various properties of Modbus requests"; - sigmatch_table[DETECT_MODBUS].url = "/rules/modbus-keyword.html#modbus-keyword"; - sigmatch_table[DETECT_MODBUS].Match = NULL; - sigmatch_table[DETECT_MODBUS].Setup = DetectModbusSetup; - sigmatch_table[DETECT_MODBUS].Free = DetectModbusFree; - sigmatch_table[DETECT_MODBUS].AppLayerTxMatch = DetectModbusMatch; - - DetectAppLayerInspectEngineRegister( - "modbus", ALPROTO_MODBUS, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL); - - g_modbus_buffer_id = DetectBufferTypeGetByName("modbus"); -} diff --git a/src/detect-modbus.h b/src/detect-modbus.h deleted file mode 100644 index 5d0f466098..0000000000 --- a/src/detect-modbus.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2014 ANSSI - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * \file - * - * \author David DIALLO - */ - -#ifndef SURICATA_DETECT_MODBUS_H -#define SURICATA_DETECT_MODBUS_H - -/* prototypes */ -void DetectModbusRegister(void); - -#endif /* SURICATA_DETECT_MODBUS_H */