Skip to content

Commit ca847d1

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 95e3ac3 commit ca847d1

6 files changed

Lines changed: 142 additions & 13 deletions

File tree

doc/userguide/output/eve/eve-json-output.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,17 @@ YAML::
315315
# Default: all.
316316
#types: [a, aaaa, cname, mx, ns, ptr, txt]
317317

318+
IKE
319+
~~~
320+
321+
YAML::
322+
323+
- ike:
324+
# Enable logging attributes as objects instead of
325+
# giving duplicates an index suffix. This will be
326+
# the default in Suricata 9.0.
327+
#object-attributes: false
328+
318329
TLS
319330
~~~
320331

doc/userguide/upgrade.rst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,21 @@ also check all the new features that have been added but are not covered by
3434
this guide. Those features are either not enabled by default or require
3535
dedicated new configuration.
3636

37+
Upgrading to 8.0.2
38+
------------------
39+
40+
Logging Changes
41+
~~~~~~~~~~~~~~~
42+
43+
- Duplicate field names in IKE attributes has been removed. Before 8.0
44+
it was possible to see duplicate field names like
45+
``sa_life_duration``, while some parsers ignore the duplicates,
46+
strict parsers will fail on duplicates. To address this, duplicates
47+
will now be given an index suffix, for example: `sa_life_duration`,
48+
`sa_life_duration_1`. See
49+
https://redmine.openinfosecfoundation.org/issues/7902 for more
50+
information.
51+
3752
Upgrading to 8.0.1
3853
------------------
3954

etc/schema.json

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2473,6 +2473,38 @@
24732473
"alg_hash_raw": {
24742474
"type": "integer"
24752475
},
2476+
"attributes": {
2477+
"description": "When object-attributes = true",
2478+
"type": "array",
2479+
"minItems": 1,
2480+
"items": {
2481+
"type": "object",
2482+
"additionalProperties": false,
2483+
"properties": {
2484+
"key": {
2485+
"type": "string",
2486+
"enum": [
2487+
"alg_auth",
2488+
"alg_dh",
2489+
"alg_enc",
2490+
"alg_hash",
2491+
"sa_key_length",
2492+
"sa_life_duration",
2493+
"sa_life_type"
2494+
]
2495+
},
2496+
"raw": {
2497+
"type": [
2498+
"string",
2499+
"number"
2500+
]
2501+
},
2502+
"value": {
2503+
"type": "string"
2504+
}
2505+
}
2506+
}
2507+
},
24762508
"exchange_type": {
24772509
"type": "integer",
24782510
"suricata": {
@@ -2545,6 +2577,26 @@
25452577
"alg_hash_raw": {
25462578
"type": "integer"
25472579
},
2580+
"key": {
2581+
"description": "When object-attributes = true",
2582+
"type": "string",
2583+
"enum": [
2584+
"alg_auth",
2585+
"alg_dh",
2586+
"alg_enc",
2587+
"alg_hash",
2588+
"sa_key_length",
2589+
"sa_life_duration",
2590+
"sa_life_type"
2591+
]
2592+
},
2593+
"raw": {
2594+
"description": "When object-attributes = true",
2595+
"type": [
2596+
"string",
2597+
"number"
2598+
]
2599+
},
25482600
"sa_key_length": {
25492601
"type": "string"
25502602
},
@@ -2562,6 +2614,10 @@
25622614
},
25632615
"sa_life_type_raw": {
25642616
"type": "integer"
2617+
},
2618+
"value": {
2619+
"description": "When object-attributes = true",
2620+
"type": "string"
25652621
}
25662622
},
25672623
"patternProperties": {

rust/src/ike/logger.rs

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ use std;
2525
use std::collections::HashMap;
2626
use std::convert::TryFrom;
2727

28-
const LOG_EXTENDED: u32 = 0x01;
28+
const LOG_EXTENDED: u32 = BIT_U32!(1);
29+
const LOG_IKE_ATTRIBUTE_OBJECTS: u32 = BIT_U32!(2);
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

suricata.yaml.in

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,9 @@ outputs:
326326
#types: [file, tree_connect, negotiate, dcerpc, create,
327327
# session_setup, ioctl, rename, set_file_path_info, generic]
328328
- tftp
329-
- ike
329+
- ike:
330+
# Log attributes as object (future Suricata 9.0 behavior)
331+
#object-attributes: false
330332
- dcerpc
331333
- krb5
332334
- bittorrent-dht

0 commit comments

Comments
 (0)