detect/ike: move ike.ike.chosen_sa_attribute keyword to rust

Ticket: 8310

And increases expressivity on the way by supporting other modes
than equality
pull/14856/head
Philippe Antoine 6 months ago committed by Victor Julien
parent 55333a6ca0
commit d5ea973791

@ -48,6 +48,7 @@ Match on an attribute value of the chosen Security Association (SA) by the Respo
IKEv2 supports ``alg_enc``, ``alg_auth``, ``alg_prf`` and ``alg_dh``.
If there is more than one chosen SA the event ``MultipleServerProposal`` is set. The attributes of the first SA are used for this keyword.
You can also use other modes than equality, as in :ref:`integer keywords <rules-integer-keywords>`.
Examples::

@ -19,16 +19,20 @@
use super::ike::ALPROTO_IKE;
use super::ipsec_parser::IkeV2Transform;
use super::parser::AttributeType;
use crate::core::{STREAM_TOCLIENT, STREAM_TOSERVER};
use crate::detect::uint::{
detect_match_uint, DetectUintData, SCDetectU32Free, SCDetectU32Parse, SCDetectU8Free,
SCDetectU8Parse,
detect_match_uint, detect_parse_uint, DetectUintData, SCDetectU32Free, SCDetectU32Parse,
SCDetectU8Free, SCDetectU8Parse,
};
use crate::detect::{
helper_keyword_register_multi_buffer, helper_keyword_register_sticky_buffer,
helper_keyword_register_multi_buffer, helper_keyword_register_sticky_buffer, EnumString,
SigTableElmtStickyBuffer, SIGMATCH_INFO_UINT32, SIGMATCH_INFO_UINT8,
};
use crate::ike::ike::*;
use nom8::bytes::complete::take_while;
use nom8::combinator::map_opt;
use nom8::{AsChar, Parser};
use std::ffi::CStr;
use std::os::raw::{c_char, c_int, c_void};
use std::ptr;
@ -88,93 +92,148 @@ unsafe extern "C" fn ike_tx_get_vendor(
return false;
}
#[no_mangle]
pub extern "C" fn SCIkeStateGetSaAttribute(
tx: &IKETransaction, sa_type: *const std::os::raw::c_char, value: *mut u32,
) -> u8 {
debug_validate_bug_on!(value.is_null());
let mut ret_val = 0;
let mut ret_code = 0;
let sa_type_s: Result<_, _>;
unsafe { sa_type_s = CStr::from_ptr(sa_type).to_str() }
SCLogDebug!("{:#?}", sa_type_s);
if let Ok(sa) = sa_type_s {
if tx.ike_version == 1 {
if !tx.hdr.ikev1_transforms.is_empty() {
// there should be only one chosen server_transform, check event
if let Some(server_transform) = tx.hdr.ikev1_transforms.first() {
for attr in server_transform {
if attr.attribute_type.to_string() == sa {
if let Some(numeric_value) = attr.numeric_value {
ret_val = numeric_value;
ret_code = 1;
break;
unsafe extern "C" fn ike_tx_get_spi_initiator(
tx: *const c_void, _flags: u8, buffer: *mut *const u8, buffer_len: *mut u32,
) -> bool {
let tx = cast_pointer!(tx, IKETransaction);
*buffer = tx.hdr.spi_initiator.as_ptr();
*buffer_len = tx.hdr.spi_initiator.len() as u32;
return true;
}
unsafe extern "C" fn ike_tx_get_spi_responder(
tx: *const c_void, _flags: u8, buffer: *mut *const u8, buffer_len: *mut u32,
) -> bool {
let tx = cast_pointer!(tx, IKETransaction);
*buffer = tx.hdr.spi_responder.as_ptr();
*buffer_len = tx.hdr.spi_responder.len() as u32;
return true;
}
#[derive(Debug, PartialEq)]
struct DetectIkeChosenSa {
attribute: AttributeType,
value: DetectUintData<u32>,
}
fn ike_detect_chosen_sa_parse_aux(i: &str) -> Option<DetectIkeChosenSa> {
let (i, attribute) = map_opt(
take_while::<_, &str, nom8::error::Error<_>>(|c: char| c.is_alpha() || c == '_'),
|s: &str| AttributeType::from_str(s),
)
.parse(i)
.ok()?;
let (_i, value) = detect_parse_uint(i).ok()?;
Some(DetectIkeChosenSa { attribute, value })
}
unsafe fn ike_detect_chosen_sa_parse(
str: *const std::os::raw::c_char,
) -> *mut std::os::raw::c_void {
let ft_name: &CStr = CStr::from_ptr(str); //unsafe
if let Ok(s) = ft_name.to_str() {
if let Some(ctx) = ike_detect_chosen_sa_parse_aux(s) {
let boxed = Box::new(ctx);
return Box::into_raw(boxed) as *mut _;
}
}
return std::ptr::null_mut();
}
unsafe extern "C" fn ike_detect_chosen_sa_setup(
de: *mut DetectEngineCtx, s: *mut Signature, raw: *const libc::c_char,
) -> c_int {
if SCDetectSignatureSetAppProto(s, ALPROTO_IKE) != 0 {
return -1;
}
let ctx = ike_detect_chosen_sa_parse(raw);
if ctx.is_null() {
return -1;
}
if SCSigMatchAppendSMToList(
de,
s,
G_IKE_CHOSEN_SA_KW_ID,
ctx as *mut SigMatchCtx,
G_IKE_CHOSEN_SA_BUFFER_ID,
)
.is_null()
{
ike_detect_chosen_sa_free(std::ptr::null_mut(), ctx);
return -1;
}
return 0;
}
unsafe extern "C" fn ike_detect_chosen_sa_match(
_de: *mut DetectEngineThreadCtx, _f: *mut crate::flow::Flow, _flags: u8, _state: *mut c_void,
tx: *mut c_void, _sig: *const Signature, ctx: *const SigMatchCtx,
) -> c_int {
let tx = cast_pointer!(tx, IKETransaction);
let ctx = cast_pointer!(ctx, DetectIkeChosenSa);
if tx.ike_version == 1 {
if !tx.hdr.ikev1_transforms.is_empty() {
// there should be only one chosen server_transform, check event
if let Some(server_transform) = tx.hdr.ikev1_transforms.first() {
for attr in server_transform {
if attr.attribute_type == ctx.attribute {
if let Some(numeric_value) = attr.numeric_value {
if detect_match_uint(&ctx.value, numeric_value) {
return 1;
}
return 0;
}
}
}
}
} else if tx.ike_version == 2 {
for attr in tx.hdr.ikev2_transforms.iter() {
match attr {
IkeV2Transform::Encryption(e) => {
if sa == "alg_enc" {
ret_val = e.0 as u32;
ret_code = 1;
break;
}
} else if tx.ike_version == 2 {
for attr in tx.hdr.ikev2_transforms.iter() {
match attr {
IkeV2Transform::Encryption(e) => {
if ctx.attribute == AttributeType::AlgEnc {
if detect_match_uint(&ctx.value, e.0.into()) {
return 1;
}
return 0;
}
IkeV2Transform::Auth(e) => {
if sa == "alg_auth" {
ret_val = e.0 as u32;
ret_code = 1;
break;
}
IkeV2Transform::Auth(e) => {
if ctx.attribute == AttributeType::AlgAuth {
if detect_match_uint(&ctx.value, e.0.into()) {
return 1;
}
return 0;
}
IkeV2Transform::PRF(ref e) => {
if sa == "alg_prf" {
ret_val = e.0 as u32;
ret_code = 1;
break;
}
IkeV2Transform::PRF(ref e) => {
if ctx.attribute == AttributeType::AlgPrf {
if detect_match_uint(&ctx.value, e.0.into()) {
return 1;
}
return 0;
}
IkeV2Transform::DH(ref e) => {
if sa == "alg_dh" {
ret_val = e.0 as u32;
ret_code = 1;
break;
}
IkeV2Transform::DH(ref e) => {
if ctx.attribute == AttributeType::AlgDh {
if detect_match_uint(&ctx.value, e.0.into()) {
return 1;
}
return 0;
}
_ => (),
}
_ => (),
}
}
}
unsafe {
*value = ret_val;
}
return ret_code;
}
unsafe extern "C" fn ike_tx_get_spi_initiator(
tx: *const c_void, _flags: u8, buffer: *mut *const u8, buffer_len: *mut u32,
) -> bool {
let tx = cast_pointer!(tx, IKETransaction);
*buffer = tx.hdr.spi_initiator.as_ptr();
*buffer_len = tx.hdr.spi_initiator.len() as u32;
return true;
return 0;
}
unsafe extern "C" fn ike_tx_get_spi_responder(
tx: *const c_void, _flags: u8, buffer: *mut *const u8, buffer_len: *mut u32,
) -> bool {
let tx = cast_pointer!(tx, IKETransaction);
*buffer = tx.hdr.spi_responder.as_ptr();
*buffer_len = tx.hdr.spi_responder.len() as u32;
return true;
unsafe extern "C" fn ike_detect_chosen_sa_free(_de: *mut DetectEngineCtx, ctx: *mut c_void) {
let ctx = cast_pointer!(ctx, DetectIkeChosenSa);
std::mem::drop(Box::from_raw(ctx));
}
unsafe extern "C" fn ike_detect_exchtype_setup(
@ -345,6 +404,8 @@ static mut G_IKE_EXCHTYPE_BUFFER_ID: c_int = 0;
static mut G_IKE_PAYLOAD_LEN_KW_ID: u16 = 0;
static mut G_IKE_PAYLOAD_LEN_BUFFER_ID: c_int = 0;
static mut G_IKE_NONCE_PAYLOAD_BUFFER_ID: c_int = 0;
static mut G_IKE_CHOSEN_SA_KW_ID: u16 = 0;
static mut G_IKE_CHOSEN_SA_BUFFER_ID: c_int = 0;
#[no_mangle]
pub unsafe extern "C" fn SCDetectIkeRegister() {
@ -396,6 +457,21 @@ pub unsafe extern "C" fn SCDetectIkeRegister() {
ALPROTO_IKE,
STREAM_TOSERVER | STREAM_TOCLIENT,
);
let kw = SCSigTableAppLiteElmt {
name: b"ike.chosen_sa_attribute\0".as_ptr() as *const libc::c_char,
desc: b"match IKE chosen SA Attribute\0".as_ptr() as *const libc::c_char,
url: b"/rules/ike-keywords.html#ike-chosen_sa_attribute\0".as_ptr() as *const libc::c_char,
AppLayerTxMatch: Some(ike_detect_chosen_sa_match),
Setup: Some(ike_detect_chosen_sa_setup),
Free: Some(ike_detect_chosen_sa_free),
flags: 0,
};
G_IKE_CHOSEN_SA_KW_ID = SCDetectHelperKeywordRegister(&kw);
G_IKE_CHOSEN_SA_BUFFER_ID = SCDetectHelperBufferRegister(
b"ike.chosen_sa_attribute\0".as_ptr() as *const libc::c_char,
ALPROTO_IKE,
STREAM_TOCLIENT,
);
let kw = SCSigTableAppLiteElmt {
name: b"ike.key_exchange_payload_length\0".as_ptr() as *const libc::c_char,
desc: b"match IKE key exchange payload length\0".as_ptr() as *const libc::c_char,
@ -523,3 +599,38 @@ unsafe extern "C" fn ike_vendor_setup(
}
return 0;
}
#[cfg(test)]
mod tests {
use super::*;
use crate::detect::uint::DetectUintMode;
#[test]
fn test_ike_detect_chosen_sa_parse_aux() {
let r0 = ike_detect_chosen_sa_parse_aux("alg_hash=2").unwrap();
assert_eq!(
r0,
DetectIkeChosenSa {
attribute: AttributeType::AlgHash,
value: DetectUintData::<u32> {
mode: DetectUintMode::DetectUintModeEqual,
arg1: 2,
arg2: 0,
},
}
);
let r1 = ike_detect_chosen_sa_parse_aux("alg_hash!=2").unwrap();
assert_eq!(
r1,
DetectIkeChosenSa {
attribute: AttributeType::AlgHash,
value: DetectUintData::<u32> {
mode: DetectUintMode::DetectUintModeNe,
arg1: 2,
arg2: 0,
},
}
);
}
}

@ -17,6 +17,7 @@
use super::ike::{IKEState, IKETransaction};
use super::ipsec_parser::IKEV2_FLAG_INITIATOR;
use crate::detect::EnumString;
use crate::direction::Direction;
use crate::ike::parser::{ExchangeType, IsakmpPayloadType, SaAttribute};
use crate::jsonbuilder::{JsonBuilder, JsonError};
@ -37,7 +38,7 @@ const IKE_LOG_VERSION: u8 = 2;
fn add_attributes(transform: &Vec<SaAttribute>, js: &mut JsonBuilder) -> Result<(), JsonError> {
for attribute in transform {
js.start_object()?;
js.set_string("key", &attribute.attribute_type.to_string())?;
js.set_string("key", attribute.attribute_type.to_str())?;
js.set_string("value", &attribute.attribute_value.to_string())?;
if let Some(v) = attribute.numeric_value {

@ -16,6 +16,7 @@
*/
use crate::common::to_hex;
use crate::detect::EnumString;
use core::fmt;
use nom8::bytes::streaming::take;
use nom8::combinator::{complete, cond, map};
@ -129,49 +130,25 @@ pub struct VendorPayload<'a> {
}
// Attributes inside Transform
#[derive(Debug, Clone)]
#[derive(Debug, Clone, EnumStringU16, PartialEq)]
pub enum AttributeType {
Unknown = 0,
EncryptionAlgorithm = 1,
HashAlgorithm = 2,
AuthenticationMethod = 3,
GroupDescription = 4,
GroupType = 5,
GroupPrime = 6,
GroupGeneratorOne = 7,
GroupGeneratorTwo = 8,
GroupCurveA = 9,
GroupCurveB = 10,
LifeType = 11,
LifeDuration = 12,
Prf = 13,
KeyLength = 14,
FieldSize = 15,
GroupOrder = 16,
}
impl fmt::Display for AttributeType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
AttributeType::EncryptionAlgorithm => write!(f, "alg_enc"),
AttributeType::HashAlgorithm => write!(f, "alg_hash"),
AttributeType::AuthenticationMethod => write!(f, "alg_auth"),
AttributeType::GroupDescription => write!(f, "alg_dh"),
AttributeType::GroupType => write!(f, "sa_group_type"),
AttributeType::GroupPrime => write!(f, "sa_group_prime"),
AttributeType::GroupGeneratorOne => write!(f, "sa_group_generator_one"),
AttributeType::GroupGeneratorTwo => write!(f, "sa_group_generator_two"),
AttributeType::GroupCurveA => write!(f, "sa_group_curve_a"),
AttributeType::GroupCurveB => write!(f, "sa_group_curve_b"),
AttributeType::LifeType => write!(f, "sa_life_type"),
AttributeType::LifeDuration => write!(f, "sa_life_duration"),
AttributeType::Prf => write!(f, "alg_prf"),
AttributeType::KeyLength => write!(f, "sa_key_length"),
AttributeType::FieldSize => write!(f, "sa_field_size"),
AttributeType::GroupOrder => write!(f, "sa_group_order"),
_ => write!(f, "unknown"),
}
}
AlgEnc = 1,
AlgHash = 2,
AlgAuth = 3,
AlgDh = 4,
SaGroupType = 5,
SaGroupPrime = 6,
SaGroupGeneratorOne = 7,
SaGroupGeneratorTwo = 8,
SaGroupCurveA = 9,
SaGroupCurveB = 10,
SaLifeType = 11,
SaLifeDuration = 12,
AlgPrf = 13,
SaKeyLength = 14,
SaFieldSize = 15,
SaGroupOrder = 16,
}
#[derive(Debug, Clone)]
@ -337,28 +314,6 @@ pub fn parse_vendor_id(i: &[u8], length: u16) -> IResult<&[u8], VendorPayload<'_
map(take(length), |v| VendorPayload { vendor_id: v }).parse(i)
}
fn get_attribute_type(v: u16) -> AttributeType {
match v {
1 => AttributeType::EncryptionAlgorithm,
2 => AttributeType::HashAlgorithm,
3 => AttributeType::AuthenticationMethod,
4 => AttributeType::GroupDescription,
5 => AttributeType::GroupType,
6 => AttributeType::GroupPrime,
7 => AttributeType::GroupGeneratorOne,
8 => AttributeType::GroupGeneratorTwo,
9 => AttributeType::GroupCurveA,
10 => AttributeType::GroupCurveB,
11 => AttributeType::LifeType,
12 => AttributeType::LifeDuration,
13 => AttributeType::Prf,
14 => AttributeType::KeyLength,
15 => AttributeType::FieldSize,
16 => AttributeType::GroupOrder,
_ => AttributeType::Unknown,
}
}
fn get_encryption_algorithm(v: u16) -> AttributeValue {
match v {
1 => AttributeValue::EncDesCbc,
@ -449,9 +404,15 @@ pub fn parse_sa_attribute(i: &[u8]) -> IResult<&[u8], Vec<SaAttribute>> {
format.0 == 0 && attribute_length_or_value != 4,
take(attribute_length_or_value),
).parse(i)?;
let at = AttributeType::from_u(format.1);
let attribute_type = if let Some(a) = at {
a
} else {
AttributeType::Unknown
};
let attr = SaAttribute {
attribute_format: format.0,
attribute_type: get_attribute_type(format.1),
attribute_type,
attribute_value: match format.1 {
1 => get_encryption_algorithm(attribute_length_or_value),
2 => get_hash_algorithm(attribute_length_or_value),

@ -227,7 +227,6 @@ noinst_HEADERS = \
detect-icmpv6hdr.h \
detect-icode.h \
detect-id.h \
detect-ike-chosen-sa.h \
detect-ipaddr.h \
detect-ipopts.h \
detect-ipproto.h \
@ -805,7 +804,6 @@ libsuricata_c_a_SOURCES = \
detect-icmpv6hdr.c \
detect-icode.c \
detect-id.c \
detect-ike-chosen-sa.c \
detect-ipaddr.c \
detect-ipopts.c \
detect-ipproto.c \

@ -231,7 +231,6 @@
#include "detect-ssl-state.h"
#include "detect-modbus.h"
#include "detect-dnp3.h"
#include "detect-ike-chosen-sa.h"
#include "detect-vlan.h"
#include "detect-email.h"
@ -583,8 +582,6 @@ void SigTableSetup(void)
DetectModbusRegister();
DetectDNP3Register();
DetectIkeChosenSaRegister();
DetectTlsSniRegister();
DetectTlsIssuerRegister();
DetectTlsSubjectRegister();

@ -281,8 +281,6 @@ enum DetectKeywordId {
DETECT_TRANSFORM_PCREXFORM,
DETECT_TRANSFORM_LUAXFORM,
DETECT_IKE_CHOSEN_SA,
DETECT_JA4_HASH,
DETECT_FTP_COMMAND,

@ -1,274 +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.
*/
/**
*
* \author Frank Honza <frank.honza@dcso.de>
*/
#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-ike-chosen-sa.h"
#include "app-layer-parser.h"
#include "util-byte.h"
#include "util-unittest.h"
#include "rust.h"
/**
* [ike.chosen_sa_attribute]:<sa_attribute>=<type>;
*/
// support the basic attributes, which are parsed as integer and life_duration, if variable length
// is 4 it is stored as integer too
#define PARSE_REGEX \
"^\\s*(alg_enc|alg_hash|alg_auth|alg_dh|\
sa_group_type|sa_life_type|sa_life_duration|alg_prf|sa_key_length|sa_field_size)\
\\s*=\\s*([0-9]+)\\s*$"
static DetectParseRegex parse_regex;
typedef struct {
char *sa_type;
uint32_t sa_value;
} DetectIkeChosenSaData;
static DetectIkeChosenSaData *DetectIkeChosenSaParse(const char *);
static int DetectIkeChosenSaSetup(DetectEngineCtx *, Signature *s, const char *str);
static void DetectIkeChosenSaFree(DetectEngineCtx *, void *);
static int g_ike_chosen_sa_buffer_id = 0;
static int DetectIkeChosenSaMatch(DetectEngineThreadCtx *, Flow *, uint8_t, void *, void *,
const Signature *, const SigMatchCtx *);
void IKEChosenSaRegisterTests(void);
/**
* \brief Registration function for ike.ChosenSa keyword.
*/
void DetectIkeChosenSaRegister(void)
{
sigmatch_table[DETECT_IKE_CHOSEN_SA].name = "ike.chosen_sa_attribute";
sigmatch_table[DETECT_IKE_CHOSEN_SA].desc = "match IKE chosen SA Attribute";
sigmatch_table[DETECT_IKE_CHOSEN_SA].url = "/rules/ike-keywords.html#ike-chosen_sa_attribute";
sigmatch_table[DETECT_IKE_CHOSEN_SA].AppLayerTxMatch = DetectIkeChosenSaMatch;
sigmatch_table[DETECT_IKE_CHOSEN_SA].Setup = DetectIkeChosenSaSetup;
sigmatch_table[DETECT_IKE_CHOSEN_SA].Free = DetectIkeChosenSaFree;
#ifdef UNITTESTS
sigmatch_table[DETECT_IKE_CHOSEN_SA].RegisterTests = IKEChosenSaRegisterTests;
#endif
DetectSetupParseRegexes(PARSE_REGEX, &parse_regex);
DetectAppLayerInspectEngineRegister("ike.chosen_sa_attribute", ALPROTO_IKE, SIG_FLAG_TOCLIENT,
1, DetectEngineInspectGenericList, NULL);
g_ike_chosen_sa_buffer_id = DetectBufferTypeGetByName("ike.chosen_sa_attribute");
}
/**
* \internal
* \brief Function to match SA attributes of a IKE state
*
* \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 txv Pointer to the Ike Transaction.
* \param s Pointer to the Signature.
* \param ctx Pointer to the sigmatch that we will cast into DetectIkeChosenSaData.
*
* \retval 0 no match.
* \retval 1 match.
*/
static int DetectIkeChosenSaMatch(DetectEngineThreadCtx *det_ctx, Flow *f, uint8_t flags,
void *state, void *txv, const Signature *s, const SigMatchCtx *ctx)
{
SCEnter();
const DetectIkeChosenSaData *dd = (const DetectIkeChosenSaData *)ctx;
uint32_t value;
if (!SCIkeStateGetSaAttribute(txv, dd->sa_type, &value))
SCReturnInt(0);
if (value == dd->sa_value)
SCReturnInt(1);
SCReturnInt(0);
}
/**
* \internal
* \brief Function to parse options passed via ike.chosen_sa_attribute keywords.
*
* \param rawstr Pointer to the user provided options.
*
* \retval dd pointer to DetectIkeChosenSaData on success.
* \retval NULL on failure.
*/
static DetectIkeChosenSaData *DetectIkeChosenSaParse(const char *rawstr)
{
/*
* idea: do not implement one c file per type, invent an own syntax:
* ike.chosen_sa_attribute:"encryption_algorithm=4"
* ike.chosen_sa_attribute:"hash_algorithm=8"
*/
DetectIkeChosenSaData *dd = NULL;
int res = 0;
size_t pcre2len;
char attribute[100];
char value[100];
pcre2_match_data *match = NULL;
int ret = DetectParsePcreExec(&parse_regex, &match, rawstr, 0, 0);
if (ret < 3 || ret > 5) {
SCLogError(
"pcre match for ike.chosen_sa_attribute failed, should be: <sa_attribute>=<type>, "
"but was: %s; error code %d",
rawstr, ret);
goto error;
}
pcre2len = sizeof(attribute);
res = pcre2_substring_copy_bynumber(match, 1, (PCRE2_UCHAR8 *)attribute, &pcre2len);
if (res < 0) {
SCLogError("pcre2_substring_copy_bynumber failed");
goto error;
}
pcre2len = sizeof(value);
res = pcre2_substring_copy_bynumber(match, 2, (PCRE2_UCHAR8 *)value, &pcre2len);
if (res < 0) {
SCLogError("pcre2_substring_copy_bynumber failed");
goto error;
}
dd = SCCalloc(1, sizeof(DetectIkeChosenSaData));
if (unlikely(dd == NULL))
goto error;
dd->sa_type = SCStrdup(attribute);
if (dd->sa_type == NULL)
goto error;
if (ByteExtractStringUint32(&dd->sa_value, 10, strlen(value), value) <= 0) {
SCLogError("invalid input as arg "
"to ike.chosen_sa_attribute keyword");
goto error;
}
pcre2_match_data_free(match);
return dd;
error:
if (match) {
pcre2_match_data_free(match);
}
if (dd) {
if (dd->sa_type != NULL)
SCFree(dd->sa_type);
SCFree(dd);
}
return NULL;
}
/**
* \brief Function to add the parsed IKE SA attribute query 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.
*
* \retval 0 on Success.
* \retval -1 on Failure.
*/
static int DetectIkeChosenSaSetup(DetectEngineCtx *de_ctx, Signature *s, const char *rawstr)
{
if (SCDetectSignatureSetAppProto(s, ALPROTO_IKE) != 0)
return -1;
DetectIkeChosenSaData *dd = DetectIkeChosenSaParse(rawstr);
if (dd == NULL) {
SCLogError("Parsing \'%s\' failed", rawstr);
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_IKE_CHOSEN_SA, (SigMatchCtx *)dd,
g_ike_chosen_sa_buffer_id) == NULL) {
goto error;
}
return 0;
error:
DetectIkeChosenSaFree(de_ctx, dd);
return -1;
}
/**
* \internal
* \brief Function to free memory associated with DetectIkeChosenSaData.
*
* \param de_ptr Pointer to DetectIkeChosenSaData.
*/
static void DetectIkeChosenSaFree(DetectEngineCtx *de_ctx, void *ptr)
{
DetectIkeChosenSaData *dd = (DetectIkeChosenSaData *)ptr;
if (dd == NULL)
return;
if (dd->sa_type != NULL)
SCFree(dd->sa_type);
SCFree(ptr);
}
/*
* ONLY TESTS BELOW THIS COMMENT
*/
#ifdef UNITTESTS
/**
* \test IKEChosenSaParserTest is a test for valid values
*
* \retval 1 on success
* \retval 0 on failure
*/
static int IKEChosenSaParserTest(void)
{
DetectIkeChosenSaData *de = NULL;
de = DetectIkeChosenSaParse("alg_hash=2");
FAIL_IF_NULL(de);
FAIL_IF(de->sa_value != 2);
FAIL_IF(strcmp(de->sa_type, "alg_hash") != 0);
DetectIkeChosenSaFree(NULL, de);
PASS;
}
#endif /* UNITTESTS */
void IKEChosenSaRegisterTests(void)
{
#ifdef UNITTESTS
UtRegisterTest("IKEChosenSaParserTest", IKEChosenSaParserTest);
#endif /* UNITTESTS */
}

@ -1,29 +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 Frank Honza <frank.honza@dcso.de>
*/
#ifndef SURICATA_DETECT_IKE_CHOSEN_SA_H
#define SURICATA_DETECT_IKE_CHOSEN_SA_H
void DetectIkeChosenSaRegister(void);
#endif /* SURICATA_DETECT_IKE_CHOSEN_SA_H */

@ -66,7 +66,7 @@ bool EveIKEAddMetadata(const Flow *f, uint64_t tx_id, SCJsonBuilder *js)
{
IKEState *state = FlowGetAppState(f);
if (state) {
IKETransaction *tx = AppLayerParserGetTx(f->proto, ALPROTO_IKE, state, tx_id);
void *tx = AppLayerParserGetTx(f->proto, ALPROTO_IKE, state, tx_id);
if (tx) {
return SCIkeLoggerLog(state, tx, LOG_IKE_EXTENDED, js);
}

Loading…
Cancel
Save