Skip to content

Commit 1c8bc6a

Browse files
committed
ike: add support to log attributes as objects
This is an opt-in feature to log IKE attributes as objects for better handling of duplicate key values. Added as an option, as this breaks the Suricata 7 and 8 log format for IKE, but is the default in Suricata 9. Ticket: OISF#7923
1 parent ca8916c commit 1c8bc6a

2 files changed

Lines changed: 56 additions & 11 deletions

File tree

rust/src/ike/logger.rs

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use std::collections::HashMap;
2626
use std::convert::TryFrom;
2727

2828
const LOG_EXTENDED: u32 = 0x01;
29+
const LOG_IKE_ATTRIBUTE_OBJECTS: u32 = 0x02;
2930

3031
fn add_attributes(transform: &Vec<SaAttribute>, js: &mut JsonBuilder) -> Result<(), JsonError> {
3132
let mut logged: HashMap<String, usize> = HashMap::new();
@@ -52,6 +53,30 @@ fn add_attributes(transform: &Vec<SaAttribute>, js: &mut JsonBuilder) -> Result<
5253
Ok(())
5354
}
5455

56+
/// Add IKE attributes as objects.
57+
///
58+
/// This function does not open the array, it should be opened by the
59+
/// caller.
60+
///
61+
/// This is the default add_attributes function in Suricata 9.
62+
fn add_attributes_as_objects(transform: &Vec<SaAttribute>, js: &mut JsonBuilder) -> Result<(), JsonError> {
63+
for attribute in transform {
64+
js.start_object()?;
65+
js.set_string("key", &attribute.attribute_type.to_string())?;
66+
js.set_string("value", &attribute.attribute_value.to_string())?;
67+
68+
if let Some(v) = attribute.numeric_value {
69+
js.set_uint("raw", v as u64)?;
70+
} else if let Some(v) = &attribute.hex_value {
71+
js.set_string("raw", v)?;
72+
}
73+
74+
js.close()?;
75+
}
76+
77+
Ok(())
78+
}
79+
5580
fn log_ike(
5681
state: &IKEState, tx: &IKETransaction, flags: u32, jb: &mut JsonBuilder,
5782
) -> Result<(), JsonError> {
@@ -79,15 +104,25 @@ fn log_ike(
79104
if tx.ike_version == 1 {
80105
if state.ikev1_container.server.nb_transforms > 0 {
81106
// log the first transform as the chosen one
82-
add_attributes(&state.ikev1_container.server.transform, jb)?;
107+
if flags & LOG_IKE_ATTRIBUTE_OBJECTS == LOG_IKE_ATTRIBUTE_OBJECTS {
108+
jb.open_array("attributes")?;
109+
add_attributes_as_objects(&state.ikev1_container.server.transform, jb)?;
110+
jb.close()?;
111+
} else {
112+
add_attributes(&state.ikev1_container.server.transform, jb)?;
113+
}
83114
}
84115
if tx.direction == Direction::ToClient && tx.hdr.ikev1_transforms.len() > 1 {
85116
// in case we have multiple server transforms log them in a list
86117
jb.open_array("server_proposals")?;
87118
for server_transform in &tx.hdr.ikev1_transforms {
88-
jb.start_object()?;
89-
add_attributes(server_transform, jb)?;
90-
jb.close()?;
119+
if flags & LOG_IKE_ATTRIBUTE_OBJECTS == LOG_IKE_ATTRIBUTE_OBJECTS {
120+
add_attributes_as_objects(server_transform, jb)?;
121+
} else {
122+
jb.start_object()?;
123+
add_attributes(server_transform, jb)?;
124+
jb.close()?;
125+
}
91126
}
92127
jb.close()?;
93128
}
@@ -120,15 +155,15 @@ fn log_ike(
120155
jb.close()?;
121156

122157
if tx.ike_version == 1 {
123-
log_ikev1(state, tx, jb)?;
158+
log_ikev1(state, tx, flags, jb)?;
124159
} else if tx.ike_version == 2 {
125160
log_ikev2(tx, jb)?;
126161
}
127162
jb.close()?;
128163
return Ok(());
129164
}
130165

131-
fn log_ikev1(state: &IKEState, tx: &IKETransaction, jb: &mut JsonBuilder) -> Result<(), JsonError> {
166+
fn log_ikev1(state: &IKEState, tx: &IKETransaction, flags: u32, jb: &mut JsonBuilder) -> Result<(), JsonError> {
132167
jb.open_object("ikev1")?;
133168

134169
if let Some(doi) = state.ikev1_container.domain_of_interpretation {
@@ -163,9 +198,13 @@ fn log_ikev1(state: &IKEState, tx: &IKETransaction, jb: &mut JsonBuilder) -> Res
163198
if tx.direction == Direction::ToServer && !tx.hdr.ikev1_transforms.is_empty() {
164199
jb.open_array("proposals")?;
165200
for client_transform in &tx.hdr.ikev1_transforms {
166-
jb.start_object()?;
167-
add_attributes(client_transform, jb)?;
168-
jb.close()?;
201+
if flags & LOG_IKE_ATTRIBUTE_OBJECTS == LOG_IKE_ATTRIBUTE_OBJECTS {
202+
add_attributes_as_objects(client_transform, jb)?;
203+
} else {
204+
jb.start_object()?;
205+
add_attributes(client_transform, jb)?;
206+
jb.close()?;
207+
}
169208
}
170209
jb.close()?; // proposals
171210
}

src/output-json-ike.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,9 @@
4949

5050
#include "rust.h"
5151

52-
#define LOG_IKE_DEFAULT 0
53-
#define LOG_IKE_EXTENDED (1 << 0)
52+
#define LOG_IKE_DEFAULT BIT_U32(0)
53+
#define LOG_IKE_EXTENDED BIT_U32(1)
54+
#define LOG_IKE_ATTRIBUTE_OBJECTS BIT_U32(2)
5455

5556
typedef struct LogIKEFileCtx_ {
5657
uint32_t flags;
@@ -132,6 +133,11 @@ static OutputInitResult OutputIKELogInitSub(SCConfNode *conf, OutputCtx *parent_
132133
}
133134
}
134135

136+
const char *objects = SCConfNodeLookupChildValue(conf, "object-attributes");
137+
if (objects && SCConfValIsTrue(objects)) {
138+
ikelog_ctx->flags |= LOG_IKE_ATTRIBUTE_OBJECTS;
139+
}
140+
135141
output_ctx->data = ikelog_ctx;
136142
output_ctx->DeInit = OutputIKELogDeInitCtxSub;
137143

0 commit comments

Comments
 (0)