/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 | } |