Coverage Report

Created: 2026-02-14 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/rust/src/ike/logger.rs
Line
Count
Source
1
/* Copyright (C) 2020 Open Information Security Foundation
2
 *
3
 * You can copy, redistribute or modify this Program under the terms of
4
 * the GNU General Public License version 2 as published by the Free
5
 * Software Foundation.
6
 *
7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
11
 *
12
 * You should have received a copy of the GNU General Public License
13
 * version 2 along with this program; if not, write to the Free Software
14
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
 * 02110-1301, USA.
16
 */
17
18
use super::ike::{IKEState, IKETransaction};
19
use super::ipsec_parser::IKEV2_FLAG_INITIATOR;
20
use crate::core::Direction;
21
use crate::ike::parser::{ExchangeType, IsakmpPayloadType, SaAttribute};
22
use crate::jsonbuilder::{JsonBuilder, JsonError};
23
use num_traits::FromPrimitive;
24
use std;
25
use std::collections::HashSet;
26
use std::convert::TryFrom;
27
28
const LOG_EXTENDED: u32 = 0x01;
29
30
3.24k
fn add_attributes(transform: &Vec<SaAttribute>, js: &mut JsonBuilder) -> Result<(), JsonError> {
31
3.24k
    let mut logged: HashSet<String> = HashSet::new();
32
33
19.1k
    for attribute in transform {
34
15.9k
        let key = attribute.attribute_type.to_string();
35
36
15.9k
        if logged.contains(&key) {
37
78
            continue;
38
15.8k
        }
39
15.8k
        logged.insert(key.clone());
40
41
15.8k
        js.set_string(
42
15.8k
            &key,
43
15.8k
            attribute.attribute_value.to_string().as_str(),
44
0
        )?;
45
46
15.8k
        if let Some(numeric_value) = attribute.numeric_value {
47
14.8k
            js.set_uint(
48
14.8k
                format!("{}_raw", attribute.attribute_type).as_str(),
49
14.8k
                numeric_value as u64,
50
0
            )?;
51
991
        } else if let Some(hex_value) = &attribute.hex_value {
52
991
            js.set_string(
53
991
                format!("{}_raw", attribute.attribute_type).as_str(),
54
991
                hex_value,
55
0
            )?;
56
0
        }
57
    }
58
59
3.24k
    return Ok(());
60
3.24k
}
61
62
10.4k
fn log_ike(
63
10.4k
    state: &IKEState, tx: &IKETransaction, flags: u32, jb: &mut JsonBuilder,
64
10.4k
) -> Result<(), JsonError> {
65
10.4k
    jb.open_object("ike")?;
66
67
10.4k
    jb.set_uint("version_major", tx.hdr.maj_ver as u64)?;
68
10.4k
    jb.set_uint("version_minor", tx.hdr.min_ver as u64)?;
69
10.4k
    jb.set_string("init_spi", &tx.hdr.spi_initiator)?;
70
10.4k
    jb.set_string("resp_spi", &tx.hdr.spi_responder)?;
71
10.4k
    jb.set_uint("message_id", tx.hdr.msg_id as u64)?;
72
73
10.4k
    if tx.ike_version == 1 {
74
7.68k
        if let Some(exchange_type) = tx.hdr.ikev1_header.exchange_type {
75
7.68k
            jb.set_uint("exchange_type", exchange_type as u64)?;
76
7.68k
            if (flags & LOG_EXTENDED) == LOG_EXTENDED {
77
1.06k
                if let Some(etype) = ExchangeType::from_u8(exchange_type) {
78
1.01k
                    jb.set_string("exchange_type_verbose", etype.to_string().as_str())?;
79
56
                };
80
6.62k
            }
81
0
        }
82
2.78k
    } else if tx.ike_version == 2 {
83
2.78k
        jb.set_uint("exchange_type", tx.hdr.ikev2_header.exch_type.0 as u64)?;
84
0
    }
85
86
10.4k
    if tx.ike_version == 1 {
87
7.68k
        if state.ikev1_container.server.nb_transforms > 0 {
88
            // log the first transform as the chosen one
89
938
            add_attributes(&state.ikev1_container.server.transform, jb)?;
90
6.74k
        }
91
7.68k
        if tx.direction == Direction::ToClient && tx.hdr.ikev1_transforms.len() > 1 {
92
            // in case we have multiple server transforms log them in a list
93
2
            jb.open_array("server_proposals")?;
94
6
            for server_transform in &tx.hdr.ikev1_transforms {
95
4
                jb.start_object()?;
96
4
                add_attributes(server_transform, jb)?;
97
4
                jb.close()?;
98
            }
99
2
            jb.close()?;
100
7.68k
        }
101
2.78k
    } else if tx.ike_version == 2 {
102
2.78k
        if tx.hdr.flags & IKEV2_FLAG_INITIATOR != 0 {
103
179
            jb.set_string("role", "initiator")?;
104
        } else {
105
2.60k
            jb.set_string("role", "responder")?;
106
2.60k
            jb.set_string("alg_enc", &format!("{:?}", state.ikev2_container.alg_enc))?;
107
2.60k
            jb.set_string("alg_auth", &format!("{:?}", state.ikev2_container.alg_auth))?;
108
2.60k
            jb.set_string("alg_prf", &format!("{:?}", state.ikev2_container.alg_prf))?;
109
2.60k
            jb.set_string("alg_dh", &format!("{:?}", state.ikev2_container.alg_dh))?;
110
2.60k
            jb.set_string("alg_esn", &format!("{:?}", state.ikev2_container.alg_esn))?;
111
        }
112
0
    }
113
114
    // payloads in packet
115
10.4k
    jb.open_array("payload")?;
116
10.4k
    if tx.ike_version == 1 {
117
7.68k
        if let Some(payload_types) = &tx.payload_types.ikev1_payload_types {
118
27.5k
            for pt in payload_types {
119
19.8k
                append_payload_type_extended(jb, pt)?;
120
            }
121
0
        }
122
2.78k
    } else if tx.ike_version == 2 {
123
2.78k
        for payload in tx.payload_types.ikev2_payload_types.iter() {
124
16
            jb.append_string(&format!("{:?}", payload))?;
125
        }
126
0
    }
127
10.4k
    jb.close()?;
128
129
10.4k
    if tx.ike_version == 1 {
130
7.68k
        log_ikev1(state, tx, jb)?;
131
2.78k
    } else if tx.ike_version == 2 {
132
2.78k
        log_ikev2(tx, jb)?;
133
0
    }
134
10.4k
    jb.close()?;
135
10.4k
    return Ok(());
136
10.4k
}
137
138
7.68k
fn log_ikev1(state: &IKEState, tx: &IKETransaction, jb: &mut JsonBuilder) -> Result<(), JsonError> {
139
7.68k
    jb.open_object("ikev1")?;
140
141
7.68k
    if let Some(doi) = state.ikev1_container.domain_of_interpretation {
142
4.35k
        jb.set_uint("doi", doi as u64)?;
143
3.33k
    }
144
7.68k
    jb.set_bool("encrypted_payloads", tx.hdr.ikev1_header.encrypted_payloads)?;
145
146
7.68k
    if !tx.hdr.ikev1_header.encrypted_payloads {
147
        // enable logging of collected state if not-encrypted payloads
148
149
        // client data
150
6.25k
        jb.open_object("client")?;
151
6.25k
        if !state.ikev1_container.client.key_exchange.is_empty() {
152
725
            jb.set_string(
153
725
                "key_exchange_payload",
154
725
                &state.ikev1_container.client.key_exchange,
155
0
            )?;
156
725
            if let Ok(client_key_length) =
157
725
                u64::try_from(state.ikev1_container.client.key_exchange.len())
158
            {
159
725
                jb.set_uint("key_exchange_payload_length", client_key_length / 2)?;
160
0
            }
161
5.52k
        }
162
6.25k
        if !state.ikev1_container.client.nonce.is_empty() {
163
623
            jb.set_string("nonce_payload", &state.ikev1_container.client.nonce)?;
164
623
            if let Ok(client_nonce_length) = u64::try_from(state.ikev1_container.client.nonce.len())
165
            {
166
623
                jb.set_uint("nonce_payload_length", client_nonce_length / 2)?;
167
0
            }
168
5.63k
        }
169
170
6.25k
        if tx.direction == Direction::ToServer && !tx.hdr.ikev1_transforms.is_empty() {
171
2.30k
            jb.open_array("proposals")?;
172
4.60k
            for client_transform in &tx.hdr.ikev1_transforms {
173
2.30k
                jb.start_object()?;
174
2.30k
                add_attributes(client_transform, jb)?;
175
2.30k
                jb.close()?;
176
            }
177
2.30k
            jb.close()?; // proposals
178
3.95k
        }
179
6.25k
        jb.close()?; // client
180
181
        // server data
182
6.25k
        jb.open_object("server")?;
183
6.25k
        if !state.ikev1_container.server.key_exchange.is_empty() {
184
1.90k
            jb.set_string(
185
1.90k
                "key_exchange_payload",
186
1.90k
                &state.ikev1_container.server.key_exchange,
187
0
            )?;
188
1.90k
            if let Ok(server_key_length) =
189
1.90k
                u64::try_from(state.ikev1_container.server.key_exchange.len())
190
            {
191
1.90k
                jb.set_uint("key_exchange_payload_length", server_key_length / 2)?;
192
0
            }
193
4.34k
        }
194
6.25k
        if !state.ikev1_container.server.nonce.is_empty() {
195
1.65k
            jb.set_string("nonce_payload", &state.ikev1_container.server.nonce)?;
196
1.65k
            if let Ok(server_nonce_length) = u64::try_from(state.ikev1_container.server.nonce.len())
197
            {
198
1.65k
                jb.set_uint("nonce_payload_length", server_nonce_length / 2)?;
199
0
            }
200
4.60k
        }
201
6.25k
        jb.close()?; // server
202
203
6.25k
        if !tx.hdr.ikev1_header.vendor_ids.is_empty() {
204
1.82k
            jb.open_array("vendor_ids")?;
205
6.49k
            for vendor in &tx.hdr.ikev1_header.vendor_ids {
206
4.66k
                jb.append_string(vendor)?;
207
            }
208
1.82k
            jb.close()?; // vendor_ids
209
4.43k
        }
210
1.43k
    }
211
7.68k
    jb.close()?;
212
213
7.68k
    return Ok(());
214
7.68k
}
215
216
19.8k
fn append_payload_type_extended(js: &mut JsonBuilder, pt: &u8) -> Result<(), JsonError> {
217
19.8k
    if let Some(v) = IsakmpPayloadType::from_u8(*pt) {
218
18.2k
        js.append_string(&format!("{:?}", v))?;
219
1.56k
    }
220
19.8k
    Ok(())
221
19.8k
}
222
223
2.78k
fn log_ikev2(tx: &IKETransaction, jb: &mut JsonBuilder) -> Result<(), JsonError> {
224
2.78k
    jb.open_object("ikev2")?;
225
226
2.78k
    jb.set_uint("errors", tx.errors as u64)?;
227
2.78k
    if !tx.notify_types.is_empty() {
228
0
        jb.open_array("notify")?;
229
0
        for notify in tx.notify_types.iter() {
230
0
            jb.append_string(&format!("{:?}", notify))?;
231
        }
232
0
        jb.close()?;
233
2.78k
    }
234
2.78k
    jb.close()?;
235
2.78k
    Ok(())
236
2.78k
}
237
238
#[no_mangle]
239
10.4k
pub unsafe extern "C" fn rs_ike_logger_log(
240
10.4k
    state: &mut IKEState, tx: *mut std::os::raw::c_void, flags: u32, js: &mut JsonBuilder,
241
10.4k
) -> bool {
242
10.4k
    let tx = cast_pointer!(tx, IKETransaction);
243
10.4k
    log_ike(state, tx, flags, js).is_ok()
244
10.4k
}