detect/nfs: move nfs_procedure to rust

Make it able to use strings on the way

Ticket: 6723
pull/13892/head
Philippe Antoine 7 months ago committed by Victor Julien
parent 9869fb776b
commit 3641b4eda1

@ -16,4 +16,21 @@ Signature Example:
:example-rule-options:`file.name; content:"file.txt";` \
classtype:bad-unknown; sid:1; rev:1;)
For additional information on the ``file.name`` keyword, see :doc:`file-keywords`.
For additional information on the ``file.name`` keyword, see :doc:`file-keywords`.
nfs_procedure
-------------
This keyword allows to match the nfs procedure by its type (integer).
nfs_procedure uses :ref:`unsigned 32-bit integer <rules-integer-keywords>`.
It is also possible to specify the string values for NFSv3 or NFSv4 procedures.
``nfs_procedure: getattr`` will match like ``nfs_procedure: 1; nfs.version: <4;``
or ``nfs_procedure: 9; nfs.version: >=4;``
Unlike the other keywords, the usage of range is inclusive.
Syntax::
nfs_procedure:(mode) <number or string>

@ -0,0 +1,258 @@
/* Copyright (C) 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.
*/
// written by Pierre Chifflier <chifflier@wzdftpd.net>
use suricata_sys::sys::AppProtoEnum::ALPROTO_NFS;
use suricata_sys::sys::{
AppProto, DetectEngineCtx, DetectEngineThreadCtx, Flow, SCDetectHelperBufferRegister,
SCDetectHelperKeywordRegister, SCDetectSignatureSetAppProto, SCSigMatchAppendSMToList,
SCSigTableAppLiteElmt, SigMatchCtx, Signature,
};
use super::nfs::{NFSTransaction, NFSTransactionTypeData};
use super::types::{NfsProc3, NfsProc4};
use crate::core::STREAM_TOSERVER;
use crate::detect::uint::{
detect_match_uint, detect_parse_uint_enum, detect_parse_uint_inclusive, DetectUintData,
SCDetectU32Free,
};
use crate::detect::{SIGMATCH_INFO_ENUM_UINT, SIGMATCH_INFO_MULTI_UINT, SIGMATCH_INFO_UINT32};
use std::ffi::{c_int, CStr};
use std::os::raw::c_void;
static mut G_NFS_PROCEDURE_KW_ID: u16 = 0;
static mut G_NFS_PROCEDURE_BUFFER_ID: c_int = 0;
struct DetectNfsProcedureDataVersion {
v3: Option<DetectUintData<u32>>,
v4: Option<DetectUintData<u32>>,
}
enum DetectNfsProcedureData {
VersionLiteral(DetectNfsProcedureDataVersion),
Num(DetectUintData<u32>),
}
fn nfs_procedure_parse_aux(s: &str) -> Option<DetectNfsProcedureData> {
if let Ok((_, ctx)) = detect_parse_uint_inclusive::<u32>(s) {
return Some(DetectNfsProcedureData::Num(ctx));
}
let v3 = detect_parse_uint_enum::<u32, NfsProc3>(s);
let v4 = detect_parse_uint_enum::<u32, NfsProc4>(s);
if v3.is_none() && v4.is_none() {
return None;
}
return Some(DetectNfsProcedureData::VersionLiteral(
DetectNfsProcedureDataVersion { v3, v4 },
));
}
unsafe extern "C" fn nfs_procedure_parse(
ustr: *const std::os::raw::c_char,
) -> *mut DetectUintData<u32> {
let ft_name: &CStr = CStr::from_ptr(ustr); //unsafe
if let Ok(s) = ft_name.to_str() {
// TODO big composite type
if let Some(ctx) = nfs_procedure_parse_aux(s) {
let boxed = Box::new(ctx);
return Box::into_raw(boxed) as *mut _;
}
}
return std::ptr::null_mut();
}
unsafe extern "C" fn nfs_procedure_setup(
de: *mut DetectEngineCtx, s: *mut Signature, raw: *const libc::c_char,
) -> c_int {
if SCDetectSignatureSetAppProto(s, ALPROTO_NFS as AppProto) != 0 {
return -1;
}
let ctx = nfs_procedure_parse(raw) as *mut c_void;
if ctx.is_null() {
return -1;
}
if SCSigMatchAppendSMToList(
de,
s,
G_NFS_PROCEDURE_KW_ID,
ctx as *mut SigMatchCtx,
G_NFS_PROCEDURE_BUFFER_ID,
)
.is_null()
{
nfs_procedure_free(std::ptr::null_mut(), ctx);
return -1;
}
return 0;
}
fn nfs_procedure_match_val(proc: u32, nfs_version: u16, ctx: &DetectNfsProcedureData) -> bool {
match ctx {
DetectNfsProcedureData::VersionLiteral(ver) => {
if nfs_version < 4 {
if let Some(du32v3) = &ver.v3 {
return detect_match_uint(du32v3, proc);
}
} else if let Some(du32v4) = &ver.v4 {
return detect_match_uint(du32v4, proc);
}
return false;
}
DetectNfsProcedureData::Num(du32) => {
return detect_match_uint(du32, proc);
}
}
}
fn nfs_procedure_match_aux(tx: &NFSTransaction, ctx: &DetectNfsProcedureData) -> c_int {
// first try tx.procedure
if nfs_procedure_match_val(tx.procedure, tx.nfs_version, ctx) {
return 1;
}
if !tx.is_file_tx {
return 0;
}
/* file tx handling follows */
if let Some(NFSTransactionTypeData::FILE(ref tdf)) = tx.type_data {
for proc in &tdf.file_additional_procs {
if nfs_procedure_match_val(*proc, tx.nfs_version, ctx) {
return 1;
}
}
}
return 0;
}
unsafe extern "C" fn nfs_procedure_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, NFSTransaction);
let ctx = cast_pointer!(ctx, DetectNfsProcedureData);
return nfs_procedure_match_aux(tx, ctx);
}
unsafe extern "C" fn nfs_procedure_free(_de: *mut DetectEngineCtx, ctx: *mut c_void) {
let ctx = cast_pointer!(ctx, DetectUintData<u32>);
SCDetectU32Free(ctx);
}
#[no_mangle]
pub unsafe extern "C" fn SCDetectNfsProcedureRegister() {
let kw = SCSigTableAppLiteElmt {
name: b"nfs_procedure\0".as_ptr() as *const libc::c_char,
desc: b"match NFS procedure\0".as_ptr() as *const libc::c_char,
url: b"/rules/nfs-keywords.html#procedure\0".as_ptr() as *const libc::c_char,
AppLayerTxMatch: Some(nfs_procedure_match),
Setup: Some(nfs_procedure_setup),
Free: Some(nfs_procedure_free),
flags: SIGMATCH_INFO_UINT32 | SIGMATCH_INFO_MULTI_UINT | SIGMATCH_INFO_ENUM_UINT,
};
G_NFS_PROCEDURE_KW_ID = SCDetectHelperKeywordRegister(&kw);
G_NFS_PROCEDURE_BUFFER_ID = SCDetectHelperBufferRegister(
b"nfs_procedure\0".as_ptr() as *const libc::c_char,
ALPROTO_NFS as AppProto,
STREAM_TOSERVER,
);
}
#[cfg(test)]
mod test {
use super::*;
use crate::detect::uint::DetectUintMode;
#[test]
fn nfs_procedure_parse_test() {
let ctx = nfs_procedure_parse_aux("1430000000").unwrap();
if let DetectNfsProcedureData::Num(ctx) = ctx {
assert_eq!(ctx.arg1, 1430000000);
assert_eq!(ctx.mode, DetectUintMode::DetectUintModeEqual);
} else {
panic!("not right enum");
}
let ctx = nfs_procedure_parse_aux(">1430000000").unwrap();
if let DetectNfsProcedureData::Num(ctx) = ctx {
assert_eq!(ctx.arg1, 1430000000);
assert_eq!(ctx.mode, DetectUintMode::DetectUintModeGt);
} else {
panic!("not right enum");
}
let ctx = nfs_procedure_parse_aux("<1430000000").unwrap();
if let DetectNfsProcedureData::Num(ctx) = ctx {
assert_eq!(ctx.arg1, 1430000000);
assert_eq!(ctx.mode, DetectUintMode::DetectUintModeLt);
} else {
panic!("not right enum");
}
let ctx = nfs_procedure_parse_aux("1430000001<>1470000000").unwrap();
if let DetectNfsProcedureData::Num(ctx) = ctx {
assert_eq!(ctx.arg1, 1430000000);
assert_eq!(ctx.arg2, 1470000001);
assert_eq!(ctx.mode, DetectUintMode::DetectUintModeRange);
} else {
panic!("not right enum");
}
assert!(nfs_procedure_parse_aux("A").is_none());
assert!(nfs_procedure_parse_aux(">1430000000<>1470000000").is_none());
assert!(nfs_procedure_parse_aux("1430000000<>").is_none());
assert!(nfs_procedure_parse_aux("<>1430000000").is_none());
assert!(nfs_procedure_parse_aux("").is_none());
assert!(nfs_procedure_parse_aux(" ").is_none());
assert!(nfs_procedure_parse_aux("1490000000<>1430000000").is_none());
let ctx = nfs_procedure_parse_aux("1430000001 <> 1490000000").unwrap();
if let DetectNfsProcedureData::Num(ctx) = ctx {
assert_eq!(ctx.arg1, 1430000000);
assert_eq!(ctx.arg2, 1490000001);
assert_eq!(ctx.mode, DetectUintMode::DetectUintModeRange);
} else {
panic!("not right enum");
}
let ctx = nfs_procedure_parse_aux("> 1430000000 ").unwrap();
if let DetectNfsProcedureData::Num(ctx) = ctx {
assert_eq!(ctx.arg1, 1430000000);
assert_eq!(ctx.mode, DetectUintMode::DetectUintModeGt);
} else {
panic!("not right enum");
}
let ctx = nfs_procedure_parse_aux("< 1490000000 ").unwrap();
if let DetectNfsProcedureData::Num(ctx) = ctx {
assert_eq!(ctx.arg1, 1490000000);
assert_eq!(ctx.mode, DetectUintMode::DetectUintModeLt);
} else {
panic!("not right enum");
}
let ctx = nfs_procedure_parse_aux(" 1490000000 ").unwrap();
if let DetectNfsProcedureData::Num(ctx) = ctx {
assert_eq!(ctx.arg1, 1490000000);
assert_eq!(ctx.mode, DetectUintMode::DetectUintModeEqual);
} else {
panic!("not right enum");
}
}
}

@ -20,6 +20,7 @@ use crate::nfs::nfs::*;
use crate::nfs::types::*;
use crc::crc32;
use std::string::String;
use crate::detect::EnumString;
#[no_mangle]
pub extern "C" fn SCNfsTxLoggingIsFiltered(state: &mut NFSState, tx: &NFSTransaction) -> u8 {
@ -81,12 +82,17 @@ fn nfs_common_header(
state: &NFSState, tx: &NFSTransaction, js: &mut JsonBuilder,
) -> Result<(), JsonError> {
js.set_uint("version", state.nfs_version as u64)?;
let proc_string = if state.nfs_version < 4 {
nfs3_procedure_string(tx.procedure)
if state.nfs_version < 4 {
if let Some(proc) = NfsProc3::from_u(tx.procedure) {
js.set_string("procedure", &proc.to_str().to_uppercase())?;
} else {
js.set_string("procedure", &format!("{}", tx.procedure))?;
}
} else if let Some(proc) = NfsProc4::from_u(tx.procedure) {
js.set_string("procedure", &proc.to_str().to_uppercase())?;
} else {
nfs4_procedure_string(tx.procedure)
};
js.set_string("procedure", &proc_string)?;
js.set_string("procedure", &format!("{}", tx.procedure))?;
}
let file_name = String::from_utf8_lossy(&tx.file_name);
js.set_string("filename", &file_name)?;

@ -17,6 +17,7 @@
//! NFS application layer, parser, logger module.
pub mod detect;
pub mod log;
pub mod nfs;
pub mod nfs2;

@ -2045,35 +2045,6 @@ unsafe extern "C" fn nfs_get_tx_data(tx: *mut std::os::raw::c_void) -> *mut AppL
export_state_data_get!(nfs_get_state_data, NFSState);
/// return procedure(s) in the tx. At 0 return the main proc,
/// otherwise get procs from the 'file_additional_procs'.
/// Keep calling until 0 is returned.
#[no_mangle]
pub unsafe extern "C" fn SCNfsTxGetProcedures(
tx: &mut NFSTransaction, i: u16, procedure: *mut u32,
) -> u8 {
if i == 0 {
*procedure = tx.procedure;
return 1;
}
if !tx.is_file_tx {
return 0;
}
/* file tx handling follows */
if let Some(NFSTransactionTypeData::FILE(ref mut tdf)) = tx.type_data {
let idx = i as usize - 1;
if idx < tdf.file_additional_procs.len() {
let p = tdf.file_additional_procs[idx];
*procedure = p;
return 1;
}
}
return 0;
}
#[no_mangle]
pub unsafe extern "C" fn SCNfsTxGetVersion(tx: &mut NFSTransaction, version: *mut u32) {
*version = tx.nfs_version as u32;

@ -39,35 +39,32 @@ pub const NFSPROC3_FSINFO: u32 = 19;
pub const NFSPROC3_PATHCONF: u32 = 20;
pub const NFSPROC3_COMMIT: u32 = 21;
pub fn nfs3_procedure_string(procedure: u32) -> String {
match procedure {
NFSPROC3_NULL => "NULL",
NFSPROC3_GETATTR => "GETATTR",
NFSPROC3_SETATTR => "SETATTR",
NFSPROC3_LOOKUP => "LOOKUP",
NFSPROC3_ACCESS => "ACCESS",
NFSPROC3_READLINK => "READLINK",
NFSPROC3_READ => "READ",
NFSPROC3_WRITE => "WRITE",
NFSPROC3_CREATE => "CREATE",
NFSPROC3_MKDIR => "MKDIR",
NFSPROC3_SYMLINK => "SYMLINK",
NFSPROC3_MKNOD => "MKNOD",
NFSPROC3_REMOVE => "REMOVE",
NFSPROC3_RMDIR => "RMDIR",
NFSPROC3_RENAME => "RENAME",
NFSPROC3_LINK => "LINK",
NFSPROC3_READDIR => "READDIR",
NFSPROC3_READDIRPLUS => "READDIRPLUS",
NFSPROC3_FSSTAT => "FSSTAT",
NFSPROC3_FSINFO => "FSINFO",
NFSPROC3_PATHCONF => "PATHCONF",
NFSPROC3_COMMIT => "COMMIT",
_ => {
return (procedure).to_string();
}
}
.to_string()
#[repr(u32)]
#[derive(EnumStringU32)]
#[allow(non_camel_case_types)]
pub enum NfsProc3 {
NULL = 0,
GETATTR = 1,
SETATTR = 2,
LOOKUP = 3,
ACCESS = 4,
READLINK = 5,
READ = 6,
WRITE = 7,
CREATE = 8,
MKDIR = 9,
SYMLINK = 10,
MKNOD = 11,
REMOVE = 12,
RMDIR = 13,
RENAME = 14,
LINK = 15,
READDIR = 16,
READDIRPLUS = 17,
FSSTAT = 18,
FSINFO = 19,
PATHCONF = 20,
COMMIT = 21,
}
/* RFC 1813, section '2.6 Defined Error Numbers' */
@ -242,54 +239,60 @@ pub const NFSPROC4_RECLAIM_COMPLETE: u32 = 58;
pub const NFSPROC4_ILLEGAL: u32 = 10044;
pub fn nfs4_procedure_string(procedure: u32) -> String {
match procedure {
NFSPROC4_COMPOUND => "COMPOUND",
NFSPROC4_NULL => "NULL",
// ops
NFSPROC4_ACCESS => "ACCESS",
NFSPROC4_CLOSE => "CLOSE",
NFSPROC4_COMMIT => "COMMIT",
NFSPROC4_CREATE => "CREATE",
NFSPROC4_DELEGPURGE => "DELEGPURGE",
NFSPROC4_DELEGRETURN => "DELEGRETURN",
NFSPROC4_GETATTR => "GETATTR",
NFSPROC4_GETFH => "GETFH",
NFSPROC4_LINK => "LINK",
NFSPROC4_LOCK => "LOCK",
NFSPROC4_LOCKT => "LOCKT",
NFSPROC4_LOCKU => "LOCKU",
NFSPROC4_LOOKUP => "LOOKUP",
NFSPROC4_LOOKUPP => "LOOKUPP",
NFSPROC4_NVERIFY => "NVERIFY",
NFSPROC4_OPEN => "OPEN",
NFSPROC4_OPENATTR => "OPENATTR",
NFSPROC4_OPEN_CONFIRM => "OPEN_CONFIRM",
NFSPROC4_OPEN_DOWNGRADE => "OPEN_DOWNGRADE",
NFSPROC4_PUTFH => "PUTFH",
NFSPROC4_PUTPUBFH => "PUTPUBFH",
NFSPROC4_PUTROOTFH => "PUTROOTFH",
NFSPROC4_READ => "READ",
NFSPROC4_READDIR => "READDIR",
NFSPROC4_READLINK => "READLINK",
NFSPROC4_REMOVE => "REMOVE",
NFSPROC4_RENAME => "RENAME",
NFSPROC4_RENEW => "RENEW",
NFSPROC4_RESTOREFH => "RESTOREFH",
NFSPROC4_SAVEFH => "SAVEFH",
NFSPROC4_SECINFO => "SECINFO",
NFSPROC4_SETATTR => "SETATTR",
NFSPROC4_SETCLIENTID => "SETCLIENTID",
NFSPROC4_SETCLIENTID_CONFIRM => "SETCLIENTID_CONFIRM",
NFSPROC4_VERIFY => "VERIFY",
NFSPROC4_WRITE => "WRITE",
NFSPROC4_RELEASE_LOCKOWNER => "RELEASE_LOCKOWNER",
NFSPROC4_ILLEGAL => "ILLEGAL",
_ => {
return (procedure).to_string();
}
}
.to_string()
#[repr(u32)]
#[derive(EnumStringU32)]
#[allow(non_camel_case_types)]
pub enum NfsProc4 {
NULL = 0,
COMPOUND = 1,
ACCESS = 3,
CLOSE = 4,
COMMIT = 5,
CREATE = 6,
DELEGPURGE = 7,
DELEGRETURN = 8,
GETATTR = 9,
GETFH = 10,
LINK = 11,
LOCK = 12,
LOCKT = 13,
LOCKU = 14,
LOOKUP = 15,
LOOKUPP = 16,
NVERIFY = 17,
OPEN = 18,
OPENATTR = 19,
OPEN_CONFIRM = 20,
OPEN_DOWNGRADE = 21,
PUTFH = 22,
PUTPUBFH = 23,
PUTROOTFH = 24,
READ = 25,
READDIR = 26,
READLINK = 27,
REMOVE = 28,
RENAME = 29,
RENEW = 30,
RESTOREFH = 31,
SAVEFH = 32,
SECINFO = 33,
SETATTR = 34,
SETCLIENTID = 35,
SETCLIENTID_CONFIRM = 36,
VERIFY = 37,
WRITE = 38,
RELEASE_LOCKOWNER = 39,
EXCHANGE_ID = 42,
CREATE_SESSION = 43,
DESTROY_SESSION = 44,
GETDEVINFO = 47,
LAYOUTGET = 50,
LAYOUTRETURN = 51,
SECINFO_NO_NAME = 52,
SEQUENCE = 53,
DESTROY_CLIENTID = 57,
RECLAIM_COMPLETE = 58,
ILLEGAL = 10044,
}
pub const NFS4_OK: u32 = 0;

@ -253,7 +253,6 @@ noinst_HEADERS = \
detect-metadata.h \
detect-modbus.h \
detect-msg.h \
detect-nfs-procedure.h \
detect-nfs-version.h \
detect-noalert.h \
detect-nocase.h \
@ -853,7 +852,6 @@ libsuricata_c_a_SOURCES = \
detect-metadata.c \
detect-modbus.c \
detect-msg.c \
detect-nfs-procedure.c \
detect-nfs-version.c \
detect-noalert.c \
detect-nocase.c \

@ -71,7 +71,6 @@
#include "detect-http-host.h"
#include "detect-mark.h"
#include "detect-nfs-procedure.h"
#include "detect-nfs-version.h"
#include "detect-engine-event.h"
@ -704,7 +703,7 @@ void SigTableSetup(void)
DetectTlsRegister();
DetectTlsValidityRegister();
DetectTlsVersionRegister();
DetectNfsProcedureRegister();
SCDetectNfsProcedureRegister();
DetectNfsVersionRegister();
DetectUrilenRegister();
DetectBsizeRegister();

@ -187,7 +187,6 @@ enum DetectKeywordId {
DETECT_HTTP_HOST_RAW,
DETECT_HTTP_REQUEST_LINE,
DETECT_HTTP_RESPONSE_LINE,
DETECT_NFS_PROCEDURE,
DETECT_NFS_VERSION,
DETECT_SSH_PROTOCOL,
DETECT_SSH_PROTOVERSION,

@ -1,441 +0,0 @@
/* Copyright (C) 2017-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 <victor@inliniac.net>
*/
#include "suricata-common.h"
#include "threads.h"
#include "decode.h"
#include "detect.h"
#include "detect-parse.h"
#include "detect-engine.h"
#include "detect-engine-mpm.h"
#include "detect-content.h"
#include "detect-pcre.h"
#include "detect-nfs-procedure.h"
#include "detect-engine-uint.h"
#include "app-layer-parser.h"
#include "flow.h"
#include "flow-util.h"
#include "flow-var.h"
#include "util-unittest.h"
#include "util-unittest-helper.h"
#include "util-byte.h"
#include "app-layer-nfs-tcp.h"
#include "rust.h"
static int DetectNfsProcedureSetup (DetectEngineCtx *, Signature *s, const char *str);
static void DetectNfsProcedureFree(DetectEngineCtx *, void *);
#ifdef UNITTESTS
static void DetectNfsProcedureRegisterTests(void);
#endif
static int g_nfs_request_buffer_id = 0;
static int DetectNfsProcedureMatch (DetectEngineThreadCtx *, Flow *,
uint8_t, void *, void *, const Signature *,
const SigMatchCtx *);
/**
* \brief Registration function for nfs_procedure keyword.
*/
void DetectNfsProcedureRegister (void)
{
sigmatch_table[DETECT_NFS_PROCEDURE].name = "nfs_procedure";
sigmatch_table[DETECT_NFS_PROCEDURE].desc = "match NFS procedure";
sigmatch_table[DETECT_NFS_PROCEDURE].url = "/rules/nfs-keywords.html#procedure";
sigmatch_table[DETECT_NFS_PROCEDURE].Match = NULL;
sigmatch_table[DETECT_NFS_PROCEDURE].AppLayerTxMatch = DetectNfsProcedureMatch;
sigmatch_table[DETECT_NFS_PROCEDURE].Setup = DetectNfsProcedureSetup;
sigmatch_table[DETECT_NFS_PROCEDURE].Free = DetectNfsProcedureFree;
sigmatch_table[DETECT_NFS_PROCEDURE].flags = SIGMATCH_INFO_UINT32 | SIGMATCH_INFO_MULTI_UINT;
#ifdef UNITTESTS
sigmatch_table[DETECT_NFS_PROCEDURE].RegisterTests = DetectNfsProcedureRegisterTests;
#endif
DetectAppLayerInspectEngineRegister(
"nfs_request", ALPROTO_NFS, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL);
g_nfs_request_buffer_id = DetectBufferTypeGetByName("nfs_request");
SCLogDebug("g_nfs_request_buffer_id %d", g_nfs_request_buffer_id);
}
/**
* \internal
* \brief Function to match procedure of a TX
*
* For 'file txs'
*
* \param t Pointer to thread vars.
* \param det_ctx Pointer to the pattern matcher thread.
* \param f Pointer to the current flow.
* \param flags Flags.
* \param state App layer state.
* \param s Pointer to the Signature.
* \param m Pointer to the sigmatch that we will cast into
* DetectU32Data.
*
* \retval 0 no match.
* \retval 1 match.
*/
static int DetectNfsProcedureMatch (DetectEngineThreadCtx *det_ctx,
Flow *f, uint8_t flags, void *state,
void *txv, const Signature *s,
const SigMatchCtx *ctx)
{
SCEnter();
const DetectU32Data *dd = (const DetectU32Data *)ctx;
uint16_t i;
for (i = 0; i < 256; i++) {
uint32_t procedure;
if (SCNfsTxGetProcedures(txv, i, &procedure) == 1) {
SCLogDebug("proc %u mode %u lo %u hi %u", procedure, dd->mode, dd->arg1, dd->arg2);
if (DetectU32Match(procedure, dd))
SCReturnInt(1);
continue;
}
break;
}
SCReturnInt(0);
}
/**
* \internal
* \brief Function to parse options passed via tls validity keywords.
*
* \param rawstr Pointer to the user provided options.
*
* \retval dd pointer to DetectU32Data on success.
* \retval NULL on failure.
*/
static DetectU32Data *DetectNfsProcedureParse(const char *rawstr)
{
return SCDetectU32ParseInclusive(rawstr);
}
/**
* \brief Function to add the parsed tls validity field into the current signature.
*
* \param de_ctx Pointer to the Detection Engine Context.
* \param s Pointer to the Current Signature.
* \param rawstr Pointer to the user provided flags options.
* \param type Defines if this is notBefore or notAfter.
*
* \retval 0 on Success.
* \retval -1 on Failure.
*/
static int DetectNfsProcedureSetup (DetectEngineCtx *de_ctx, Signature *s,
const char *rawstr)
{
DetectU32Data *dd = NULL;
SCLogDebug("\'%s\'", rawstr);
if (SCDetectSignatureSetAppProto(s, ALPROTO_NFS) != 0)
return -1;
dd = DetectNfsProcedureParse(rawstr);
if (dd == NULL) {
SCLogError("Parsing \'%s\' failed", rawstr);
return -1;
}
/* okay so far so good, lets get this into a SigMatch
* and put it in the Signature. */
SCLogDebug("low %u hi %u", dd->arg1, dd->arg2);
if (SCSigMatchAppendSMToList(de_ctx, s, DETECT_NFS_PROCEDURE, (SigMatchCtx *)dd,
g_nfs_request_buffer_id) == NULL) {
DetectNfsProcedureFree(de_ctx, dd);
return -1;
}
return 0;
}
/**
* \internal
* \brief Function to free memory associated with DetectU32Data.
*
* \param de_ptr Pointer to DetectU32Data.
*/
void DetectNfsProcedureFree(DetectEngineCtx *de_ctx, void *ptr)
{
SCDetectU32Free(ptr);
}
#ifdef UNITTESTS
/**
* \test This is a test for a valid value 1430000000.
*
* \retval 1 on success.
* \retval 0 on failure.
*/
static int ValidityTestParse01 (void)
{
DetectU32Data *dd = NULL;
dd = DetectNfsProcedureParse("1430000000");
FAIL_IF_NULL(dd);
FAIL_IF_NOT(dd->arg1 == 1430000000 && dd->mode == DETECT_UINT_EQ);
DetectNfsProcedureFree(NULL, dd);
PASS;
}
/**
* \test This is a test for a valid value >1430000000.
*
* \retval 1 on success.
* \retval 0 on failure.
*/
static int ValidityTestParse02 (void)
{
DetectU32Data *dd = NULL;
dd = DetectNfsProcedureParse(">1430000000");
FAIL_IF_NULL(dd);
FAIL_IF_NOT(dd->arg1 == 1430000000 && dd->mode == DETECT_UINT_GT);
DetectNfsProcedureFree(NULL, dd);
PASS;
}
/**
* \test This is a test for a valid value <1430000000.
*
* \retval 1 on success.
* \retval 0 on failure.
*/
static int ValidityTestParse03 (void)
{
DetectU32Data *dd = NULL;
dd = DetectNfsProcedureParse("<1430000000");
FAIL_IF_NULL(dd);
FAIL_IF_NOT(dd->arg1 == 1430000000 && dd->mode == DETECT_UINT_LT);
DetectNfsProcedureFree(NULL, dd);
PASS;
}
/**
* \test This is a test for a valid value 1430000000<>1470000000.
*
* \retval 1 on success.
* \retval 0 on failure.
*/
static int ValidityTestParse04 (void)
{
DetectU32Data *dd = NULL;
dd = DetectNfsProcedureParse("1430000001<>1470000000");
FAIL_IF_NULL(dd);
FAIL_IF_NOT(dd->arg1 == 1430000000 && dd->arg2 == 1470000001 && dd->mode == DETECT_UINT_RA);
DetectNfsProcedureFree(NULL, dd);
PASS;
}
/**
* \test This is a test for a invalid value A.
*
* \retval 1 on success.
* \retval 0 on failure.
*/
static int ValidityTestParse05 (void)
{
DetectU32Data *dd = NULL;
dd = DetectNfsProcedureParse("A");
FAIL_IF_NOT_NULL(dd);
PASS;
}
/**
* \test This is a test for a invalid value >1430000000<>1470000000.
*
* \retval 1 on success.
* \retval 0 on failure.
*/
static int ValidityTestParse06 (void)
{
DetectU32Data *dd = NULL;
dd = DetectNfsProcedureParse(">1430000000<>1470000000");
FAIL_IF_NOT_NULL(dd);
PASS;
}
/**
* \test This is a test for a invalid value 1430000000<>.
*
* \retval 1 on success.
* \retval 0 on failure.
*/
static int ValidityTestParse07 (void)
{
DetectU32Data *dd = NULL;
dd = DetectNfsProcedureParse("1430000000<>");
FAIL_IF_NOT_NULL(dd);
PASS;
}
/**
* \test This is a test for a invalid value <>1430000000.
*
* \retval 1 on success.
* \retval 0 on failure.
*/
static int ValidityTestParse08 (void)
{
DetectU32Data *dd = NULL;
dd = DetectNfsProcedureParse("<>1430000000");
FAIL_IF_NOT_NULL(dd);
PASS;
}
/**
* \test This is a test for a invalid value "".
*
* \retval 1 on success.
* \retval 0 on failure.
*/
static int ValidityTestParse09 (void)
{
DetectU32Data *dd = NULL;
dd = DetectNfsProcedureParse("");
FAIL_IF_NOT_NULL(dd);
PASS;
}
/**
* \test This is a test for a invalid value " ".
*
* \retval 1 on success.
* \retval 0 on failure.
*/
static int ValidityTestParse10 (void)
{
DetectU32Data *dd = NULL;
dd = DetectNfsProcedureParse(" ");
FAIL_IF_NOT_NULL(dd);
PASS;
}
/**
* \test This is a test for a invalid value 1490000000<>1430000000.
*
* \retval 1 on success.
* \retval 0 on failure.
*/
static int ValidityTestParse11 (void)
{
DetectU32Data *dd = NULL;
dd = DetectNfsProcedureParse("1490000000<>1430000000");
FAIL_IF_NOT_NULL(dd);
PASS;
}
/**
* \test This is a test for a valid value 1430000000 <> 1490000000.
*
* \retval 1 on success.
* \retval 0 on failure.
*/
static int ValidityTestParse12 (void)
{
DetectU32Data *dd = NULL;
dd = DetectNfsProcedureParse("1430000001 <> 1490000000");
FAIL_IF_NULL(dd);
FAIL_IF_NOT(dd->arg1 == 1430000000 && dd->arg2 == 1490000001 && dd->mode == DETECT_UINT_RA);
DetectNfsProcedureFree(NULL, dd);
PASS;
}
/**
* \test This is a test for a valid value > 1430000000.
*
* \retval 1 on success.
* \retval 0 on failure.
*/
static int ValidityTestParse13 (void)
{
DetectU32Data *dd = NULL;
dd = DetectNfsProcedureParse("> 1430000000 ");
FAIL_IF_NULL(dd);
FAIL_IF_NOT(dd->arg1 == 1430000000 && dd->mode == DETECT_UINT_GT);
DetectNfsProcedureFree(NULL, dd);
PASS;
}
/**
* \test This is a test for a valid value < 1490000000.
*
* \retval 1 on success.
* \retval 0 on failure.
*/
static int ValidityTestParse14 (void)
{
DetectU32Data *dd = NULL;
dd = DetectNfsProcedureParse("< 1490000000 ");
FAIL_IF_NULL(dd);
FAIL_IF_NOT(dd->arg1 == 1490000000 && dd->mode == DETECT_UINT_LT);
DetectNfsProcedureFree(NULL, dd);
PASS;
}
/**
* \test This is a test for a valid value 1490000000.
*
* \retval 1 on success.
* \retval 0 on failure.
*/
static int ValidityTestParse15 (void)
{
DetectU32Data *dd = NULL;
dd = DetectNfsProcedureParse(" 1490000000 ");
FAIL_IF_NULL(dd);
FAIL_IF_NOT(dd->arg1 == 1490000000 && dd->mode == DETECT_UINT_EQ);
DetectNfsProcedureFree(NULL, dd);
PASS;
}
/**
* \brief Register unit tests for nfs_procedure.
*/
void DetectNfsProcedureRegisterTests(void)
{
UtRegisterTest("ValidityTestParse01", ValidityTestParse01);
UtRegisterTest("ValidityTestParse02", ValidityTestParse02);
UtRegisterTest("ValidityTestParse03", ValidityTestParse03);
UtRegisterTest("ValidityTestParse04", ValidityTestParse04);
UtRegisterTest("ValidityTestParse05", ValidityTestParse05);
UtRegisterTest("ValidityTestParse06", ValidityTestParse06);
UtRegisterTest("ValidityTestParse07", ValidityTestParse07);
UtRegisterTest("ValidityTestParse08", ValidityTestParse08);
UtRegisterTest("ValidityTestParse09", ValidityTestParse09);
UtRegisterTest("ValidityTestParse10", ValidityTestParse10);
UtRegisterTest("ValidityTestParse11", ValidityTestParse11);
UtRegisterTest("ValidityTestParse12", ValidityTestParse12);
UtRegisterTest("ValidityTestParse13", ValidityTestParse13);
UtRegisterTest("ValidityTestParse14", ValidityTestParse14);
UtRegisterTest("ValidityTestParse15", ValidityTestParse15);
}
#endif /* UNITTESTS */

@ -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 <victor@inliniac.net>
*/
#ifndef SURICATA_DETECT_NFS_PROCEDURE_H
#define SURICATA_DETECT_NFS_PROCEDURE_H
/* prototypes */
void DetectNfsProcedureRegister (void);
#endif /* SURICATA_DETECT_NFS_PROCEDURE_H */

@ -71,6 +71,8 @@ void DetectNfsVersionRegister (void)
sigmatch_table[DETECT_NFS_VERSION].flags = SIGMATCH_INFO_UINT32;
// unit tests were the same as DetectNfsProcedureRegisterTests
DetectAppLayerInspectEngineRegister(
"nfs_request", ALPROTO_NFS, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL);
g_nfs_request_buffer_id = DetectBufferTypeGetByName("nfs_request");
SCLogDebug("g_nfs_request_buffer_id %d", g_nfs_request_buffer_id);

Loading…
Cancel
Save