]>
Commit | Line | Data |
---|---|---|
e2dbdd7f | 1 | /* Copyright (C) 2020 Open Information Security Foundation |
c99b9462 PC |
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 | ||
e2dbdd7f | 18 | // Author: Frank Honza <frank.honza@dcso.de> |
c99b9462 | 19 | |
e2dbdd7f SS |
20 | extern crate ipsec_parser; |
21 | use self::ipsec_parser::*; | |
c99b9462 | 22 | |
e2dbdd7f SS |
23 | use crate::applayer; |
24 | use crate::applayer::*; | |
25 | use crate::core::{ | |
26 | self, AppProto, Flow, ALPROTO_FAILED, ALPROTO_UNKNOWN, STREAM_TOCLIENT, STREAM_TOSERVER, | |
27 | }; | |
28 | use crate::ike::ikev1::{handle_ikev1, IkeV1Header, Ikev1Container}; | |
29 | use crate::ike::ikev2::{handle_ikev2, Ikev2Container}; | |
30 | use crate::ike::parser::*; | |
13b73997 | 31 | use nom; |
e2dbdd7f SS |
32 | use std; |
33 | use std::collections::HashSet; | |
34 | use std::ffi::{CStr, CString}; | |
c99b9462 PC |
35 | |
36 | #[repr(u32)] | |
ecdf9f6b | 37 | pub enum IkeEvent { |
c99b9462 PC |
38 | MalformedData = 0, |
39 | NoEncryption, | |
40 | WeakCryptoEnc, | |
41 | WeakCryptoPRF, | |
42 | WeakCryptoDH, | |
43 | WeakCryptoAuth, | |
44 | WeakCryptoNoDH, | |
45 | WeakCryptoNoAuth, | |
46 | InvalidProposal, | |
47 | UnknownProposal, | |
e2dbdd7f | 48 | PayloadExtraData, |
f83d51d0 | 49 | MultipleServerProposal, |
c99b9462 PC |
50 | } |
51 | ||
ecdf9f6b | 52 | impl IkeEvent { |
e2dbdd7f | 53 | pub fn from_i32(value: i32) -> Option<IkeEvent> { |
fb016416 | 54 | match value { |
ecdf9f6b | 55 | 0 => Some(IkeEvent::MalformedData), |
56 | 1 => Some(IkeEvent::NoEncryption), | |
57 | 2 => Some(IkeEvent::WeakCryptoEnc), | |
58 | 3 => Some(IkeEvent::WeakCryptoPRF), | |
59 | 4 => Some(IkeEvent::WeakCryptoDH), | |
60 | 5 => Some(IkeEvent::WeakCryptoAuth), | |
61 | 6 => Some(IkeEvent::WeakCryptoNoDH), | |
62 | 7 => Some(IkeEvent::WeakCryptoNoAuth), | |
63 | 8 => Some(IkeEvent::InvalidProposal), | |
64 | 9 => Some(IkeEvent::UnknownProposal), | |
e2dbdd7f | 65 | 10 => Some(IkeEvent::PayloadExtraData), |
f83d51d0 | 66 | 11 => Some(IkeEvent::MultipleServerProposal), |
fb016416 JL |
67 | _ => None, |
68 | } | |
69 | } | |
70 | } | |
71 | ||
e2dbdd7f SS |
72 | pub struct IkeHeaderWrapper { |
73 | pub spi_initiator: String, | |
74 | pub spi_responder: String, | |
75 | pub maj_ver: u8, | |
76 | pub min_ver: u8, | |
77 | pub msg_id: u32, | |
78 | pub flags: u8, | |
79 | pub ikev1_transforms: Vec<Vec<SaAttribute>>, | |
80 | pub ikev2_transforms: Vec<Vec<IkeV2Transform>>, | |
81 | pub ikev1_header: IkeV1Header, | |
82 | pub ikev2_header: IkeV2Header, | |
83 | } | |
c99b9462 | 84 | |
e2dbdd7f SS |
85 | impl IkeHeaderWrapper { |
86 | pub fn new() -> IkeHeaderWrapper { | |
87 | IkeHeaderWrapper { | |
88 | spi_initiator: String::new(), | |
89 | spi_responder: String::new(), | |
90 | maj_ver: 0, | |
91 | min_ver: 0, | |
92 | msg_id: 0, | |
93 | flags: 0, | |
94 | ikev1_transforms: Vec::new(), | |
95 | ikev2_transforms: Vec::new(), | |
96 | ikev1_header: IkeV1Header::default(), | |
97 | ikev2_header: IkeV2Header { | |
98 | init_spi: 0, | |
99 | resp_spi: 0, | |
100 | next_payload: IkePayloadType::NoNextPayload, | |
101 | maj_ver: 0, | |
102 | min_ver: 0, | |
103 | exch_type: IkeExchangeType(0), | |
104 | flags: 0, | |
105 | msg_id: 0, | |
106 | length: 0, | |
107 | }, | |
108 | } | |
109 | } | |
110 | } | |
c99b9462 | 111 | |
e2dbdd7f SS |
112 | #[derive(Default)] |
113 | pub struct IkePayloadWrapper { | |
114 | pub ikev1_payload_types: Option<HashSet<u8>>, | |
115 | pub ikev2_payload_types: Vec<IkePayloadType>, | |
c99b9462 PC |
116 | } |
117 | ||
ecdf9f6b | 118 | pub struct IKETransaction { |
e2dbdd7f | 119 | tx_id: u64, |
c99b9462 | 120 | |
e2dbdd7f SS |
121 | pub ike_version: u8, |
122 | pub hdr: IkeHeaderWrapper, | |
123 | pub payload_types: IkePayloadWrapper, | |
d9434628 PC |
124 | pub notify_types: Vec<NotifyType>, |
125 | ||
e2dbdd7f | 126 | /// errors seen during exchange |
d9434628 PC |
127 | pub errors: u32, |
128 | ||
e2dbdd7f | 129 | logged: LoggerFlags, |
c99b9462 | 130 | de_state: Option<*mut core::DetectEngineState>, |
c99b9462 | 131 | events: *mut core::AppLayerDecoderEvents, |
e0f75157 | 132 | tx_data: applayer::AppLayerTxData, |
c99b9462 PC |
133 | } |
134 | ||
e2dbdd7f SS |
135 | impl IKETransaction { |
136 | pub fn new() -> IKETransaction { | |
137 | IKETransaction { | |
c99b9462 | 138 | tx_id: 0, |
e2dbdd7f SS |
139 | ike_version: 0, |
140 | hdr: IkeHeaderWrapper::new(), | |
141 | payload_types: Default::default(), | |
142 | notify_types: vec![], | |
143 | logged: LoggerFlags::new(), | |
144 | de_state: None, | |
145 | events: std::ptr::null_mut(), | |
146 | tx_data: applayer::AppLayerTxData::new(), | |
147 | errors: 0, | |
c99b9462 PC |
148 | } |
149 | } | |
c99b9462 | 150 | |
e2dbdd7f SS |
151 | pub fn free(&mut self) { |
152 | if self.events != std::ptr::null_mut() { | |
153 | core::sc_app_layer_decoder_events_free_events(&mut self.events); | |
154 | } | |
155 | if let Some(state) = self.de_state { | |
156 | core::sc_detect_engine_state_free(state); | |
c99b9462 PC |
157 | } |
158 | } | |
e2dbdd7f | 159 | } |
c99b9462 | 160 | |
e2dbdd7f SS |
161 | impl Drop for IKETransaction { |
162 | fn drop(&mut self) { | |
163 | self.free(); | |
c99b9462 | 164 | } |
e2dbdd7f | 165 | } |
c99b9462 | 166 | |
e2dbdd7f SS |
167 | #[derive(Default)] |
168 | pub struct IKEState { | |
169 | tx_id: u64, | |
170 | pub transactions: Vec<IKETransaction>, | |
c99b9462 | 171 | |
e2dbdd7f SS |
172 | pub ikev1_container: Ikev1Container, |
173 | pub ikev2_container: Ikev2Container, | |
174 | } | |
c99b9462 | 175 | |
e2dbdd7f SS |
176 | impl IKEState { |
177 | // Free a transaction by ID. | |
c99b9462 | 178 | fn free_tx(&mut self, tx_id: u64) { |
e2dbdd7f SS |
179 | let tx = self |
180 | .transactions | |
181 | .iter() | |
182 | .position(|ref tx| tx.tx_id == tx_id + 1); | |
c99b9462 PC |
183 | debug_assert!(tx != None); |
184 | if let Some(idx) = tx { | |
185 | let _ = self.transactions.remove(idx); | |
186 | } | |
187 | } | |
188 | ||
e2dbdd7f SS |
189 | pub fn get_tx(&mut self, tx_id: u64) -> Option<&mut IKETransaction> { |
190 | for tx in &mut self.transactions { | |
191 | if tx.tx_id == tx_id + 1 { | |
192 | return Some(tx); | |
193 | } | |
194 | } | |
195 | return None; | |
196 | } | |
197 | ||
198 | pub fn new_tx(&mut self) -> IKETransaction { | |
199 | let mut tx = IKETransaction::new(); | |
200 | self.tx_id += 1; | |
201 | tx.tx_id = self.tx_id; | |
202 | return tx; | |
203 | } | |
204 | ||
c99b9462 | 205 | /// Set an event. The event is set on the most recent transaction. |
e2dbdd7f | 206 | pub fn set_event(&mut self, event: IkeEvent) { |
c99b9462 PC |
207 | if let Some(tx) = self.transactions.last_mut() { |
208 | let ev = event as u8; | |
209 | core::sc_app_layer_decoder_events_set_event_raw(&mut tx.events, ev); | |
f90733fe | 210 | } else { |
e2dbdd7f SS |
211 | SCLogDebug!( |
212 | "IKE: trying to set event {} on non-existing transaction", | |
213 | event as u32 | |
214 | ); | |
c99b9462 PC |
215 | } |
216 | } | |
217 | ||
e2dbdd7f SS |
218 | fn handle_input(&mut self, input: &[u8], direction: u8) -> AppLayerResult { |
219 | // We're not interested in empty requests. | |
220 | if input.len() == 0 { | |
221 | return AppLayerResult::ok(); | |
222 | } | |
223 | ||
224 | let mut current = input; | |
225 | match parse_isakmp_header(current) { | |
226 | Ok((rem, isakmp_header)) => { | |
227 | current = rem; | |
228 | ||
229 | if isakmp_header.maj_ver != 1 && isakmp_header.maj_ver != 2 { | |
230 | SCLogDebug!("Unsupported ISAKMP major_version"); | |
231 | return AppLayerResult::err(); | |
c99b9462 | 232 | } |
e2dbdd7f SS |
233 | |
234 | if isakmp_header.maj_ver == 1 { | |
235 | handle_ikev1(self, current, isakmp_header, direction); | |
236 | } else if isakmp_header.maj_ver == 2 { | |
237 | handle_ikev2(self, current, isakmp_header, direction); | |
238 | } else { | |
239 | return AppLayerResult::err(); | |
c99b9462 | 240 | } |
e2dbdd7f | 241 | return AppLayerResult::ok(); // todo either remove outer loop or check header length-field if we have completely read everything |
c99b9462 | 242 | } |
e2dbdd7f SS |
243 | Err(nom::Err::Incomplete(_)) => { |
244 | SCLogDebug!("Insufficient data while parsing IKE"); | |
245 | return AppLayerResult::err(); | |
c99b9462 | 246 | } |
e2dbdd7f SS |
247 | Err(_) => { |
248 | SCLogDebug!("Error while parsing IKE packet"); | |
249 | return AppLayerResult::err(); | |
c99b9462 PC |
250 | } |
251 | } | |
252 | } | |
c99b9462 | 253 | |
e2dbdd7f SS |
254 | fn tx_iterator( |
255 | &mut self, min_tx_id: u64, state: &mut u64, | |
256 | ) -> Option<(&IKETransaction, u64, bool)> { | |
257 | let mut index = *state as usize; | |
258 | let len = self.transactions.len(); | |
259 | ||
260 | while index < len { | |
261 | let tx = &self.transactions[index]; | |
262 | if tx.tx_id < min_tx_id + 1 { | |
263 | index += 1; | |
264 | continue; | |
265 | } | |
266 | *state = index as u64; | |
267 | ||
268 | return Some((tx, tx.tx_id - 1, (len - index) > 1)); | |
c99b9462 | 269 | } |
e2dbdd7f SS |
270 | |
271 | return None; | |
c99b9462 | 272 | } |
e2dbdd7f | 273 | } |
c99b9462 | 274 | |
e2dbdd7f SS |
275 | /// Probe to see if this input looks like a request or response. |
276 | fn probe(input: &[u8], direction: u8, rdir: *mut u8) -> bool { | |
277 | match parse_isakmp_header(input) { | |
278 | Ok((_, isakmp_header)) => { | |
279 | if isakmp_header.maj_ver == 1 { | |
280 | if isakmp_header.resp_spi == 0 && direction != STREAM_TOSERVER { | |
281 | unsafe { | |
282 | *rdir = STREAM_TOSERVER; | |
283 | } | |
284 | } | |
285 | return true; | |
286 | } else if isakmp_header.maj_ver == 2 { | |
287 | if isakmp_header.min_ver != 0 { | |
288 | SCLogDebug!( | |
289 | "ipsec_probe: could be ipsec, but with unsupported/invalid version {}.{}", | |
290 | isakmp_header.maj_ver, | |
291 | isakmp_header.min_ver | |
292 | ); | |
293 | return false; | |
294 | } | |
295 | if isakmp_header.exch_type < 34 || isakmp_header.exch_type > 37 { | |
296 | SCLogDebug!("ipsec_probe: could be ipsec, but with unsupported/invalid exchange type {}", | |
297 | isakmp_header.exch_type); | |
298 | return false; | |
299 | } | |
300 | if isakmp_header.length as usize != input.len() { | |
301 | SCLogDebug!("ipsec_probe: could be ipsec, but length does not match"); | |
302 | return false; | |
303 | } | |
304 | ||
305 | if isakmp_header.resp_spi == 0 && direction != STREAM_TOSERVER { | |
306 | unsafe { | |
307 | *rdir = STREAM_TOSERVER; | |
308 | } | |
309 | } | |
310 | return true; | |
311 | } | |
312 | ||
313 | return false; | |
083908f3 | 314 | } |
e2dbdd7f | 315 | Err(_) => return false, |
c99b9462 PC |
316 | } |
317 | } | |
318 | ||
e2dbdd7f SS |
319 | // C exports. |
320 | export_tx_get_detect_state!(rs_ike_tx_get_detect_state, IKETransaction); | |
321 | export_tx_set_detect_state!(rs_ike_tx_set_detect_state, IKETransaction); | |
322 | ||
323 | /// C entry point for a probing parser. | |
324 | #[no_mangle] | |
325 | pub extern "C" fn rs_ike_probing_parser( | |
326 | _flow: *const Flow, direction: u8, input: *const u8, input_len: u32, rdir: *mut u8, | |
327 | ) -> AppProto { | |
328 | if input_len < 28 { | |
329 | // at least the ISAKMP_HEADER must be there, not ALPROTO_UNKNOWN because over UDP | |
330 | return unsafe { ALPROTO_FAILED }; | |
331 | } | |
332 | ||
333 | if input != std::ptr::null_mut() { | |
334 | let slice = build_slice!(input, input_len as usize); | |
335 | if probe(slice, direction, rdir) { | |
336 | return unsafe { ALPROTO_IKE }; | |
337 | } | |
c99b9462 | 338 | } |
e2dbdd7f | 339 | return unsafe { ALPROTO_FAILED }; |
c99b9462 PC |
340 | } |
341 | ||
c99b9462 | 342 | #[no_mangle] |
e2dbdd7f SS |
343 | pub extern "C" fn rs_ike_state_new( |
344 | _orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto, | |
345 | ) -> *mut std::os::raw::c_void { | |
346 | let state = IKEState::default(); | |
c99b9462 | 347 | let boxed = Box::new(state); |
53413f2d | 348 | return Box::into_raw(boxed) as *mut _; |
c99b9462 PC |
349 | } |
350 | ||
c99b9462 | 351 | #[no_mangle] |
ecdf9f6b | 352 | pub extern "C" fn rs_ike_state_free(state: *mut std::os::raw::c_void) { |
c99b9462 | 353 | // Just unbox... |
53413f2d | 354 | std::mem::drop(unsafe { Box::from_raw(state as *mut IKEState) }); |
c99b9462 PC |
355 | } |
356 | ||
357 | #[no_mangle] | |
e2dbdd7f SS |
358 | pub extern "C" fn rs_ike_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) { |
359 | let state = cast_pointer!(state, IKEState); | |
360 | state.free_tx(tx_id); | |
c99b9462 PC |
361 | } |
362 | ||
363 | #[no_mangle] | |
e2dbdd7f SS |
364 | pub extern "C" fn rs_ike_parse_request( |
365 | _flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, | |
366 | input: *const u8, input_len: u32, _data: *const std::os::raw::c_void, _flags: u8, | |
367 | ) -> AppLayerResult { | |
368 | let state = cast_pointer!(state, IKEState); | |
369 | let buf = build_slice!(input, input_len as usize); | |
370 | ||
371 | return state.handle_input(buf, STREAM_TOSERVER); | |
c99b9462 PC |
372 | } |
373 | ||
374 | #[no_mangle] | |
e2dbdd7f SS |
375 | pub extern "C" fn rs_ike_parse_response( |
376 | _flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, | |
377 | input: *const u8, input_len: u32, _data: *const std::os::raw::c_void, _flags: u8, | |
378 | ) -> AppLayerResult { | |
379 | let state = cast_pointer!(state, IKEState); | |
380 | let buf = build_slice!(input, input_len as usize); | |
381 | return state.handle_input(buf, STREAM_TOCLIENT); | |
c99b9462 PC |
382 | } |
383 | ||
384 | #[no_mangle] | |
e2dbdd7f SS |
385 | pub extern "C" fn rs_ike_state_get_tx( |
386 | state: *mut std::os::raw::c_void, tx_id: u64, | |
387 | ) -> *mut std::os::raw::c_void { | |
388 | let state = cast_pointer!(state, IKEState); | |
389 | match state.get_tx(tx_id) { | |
390 | Some(tx) => { | |
53413f2d | 391 | return tx as *const _ as *mut _; |
e2dbdd7f SS |
392 | } |
393 | None => { | |
394 | return std::ptr::null_mut(); | |
395 | } | |
396 | } | |
c99b9462 PC |
397 | } |
398 | ||
399 | #[no_mangle] | |
e2dbdd7f SS |
400 | pub extern "C" fn rs_ike_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 { |
401 | let state = cast_pointer!(state, IKEState); | |
402 | return state.tx_id; | |
c99b9462 PC |
403 | } |
404 | ||
c99b9462 | 405 | #[no_mangle] |
e2dbdd7f SS |
406 | pub extern "C" fn rs_ike_state_progress_completion_status(_direction: u8) -> std::os::raw::c_int { |
407 | // This parser uses 1 to signal transaction completion status. | |
ecdf9f6b | 408 | return 1; |
409 | } | |
410 | ||
411 | #[no_mangle] | |
e2dbdd7f SS |
412 | pub extern "C" fn rs_ike_tx_get_alstate_progress( |
413 | _tx: *mut std::os::raw::c_void, _direction: u8, | |
414 | ) -> std::os::raw::c_int { | |
415 | return 1; | |
c99b9462 PC |
416 | } |
417 | ||
c99b9462 | 418 | #[no_mangle] |
e2dbdd7f SS |
419 | pub extern "C" fn rs_ike_tx_get_logged( |
420 | _state: *mut std::os::raw::c_void, tx: *mut std::os::raw::c_void, | |
421 | ) -> u32 { | |
422 | let tx = cast_pointer!(tx, IKETransaction); | |
423 | return tx.logged.get(); | |
c99b9462 PC |
424 | } |
425 | ||
426 | #[no_mangle] | |
e2dbdd7f SS |
427 | pub extern "C" fn rs_ike_tx_set_logged( |
428 | _state: *mut std::os::raw::c_void, tx: *mut std::os::raw::c_void, logged: u32, | |
429 | ) { | |
430 | let tx = cast_pointer!(tx, IKETransaction); | |
431 | tx.logged.set(logged); | |
c99b9462 PC |
432 | } |
433 | ||
c99b9462 | 434 | #[no_mangle] |
e2dbdd7f SS |
435 | pub extern "C" fn rs_ike_state_get_events( |
436 | tx: *mut std::os::raw::c_void, | |
437 | ) -> *mut core::AppLayerDecoderEvents { | |
ecdf9f6b | 438 | let tx = cast_pointer!(tx, IKETransaction); |
d568e7fa | 439 | return tx.events; |
c99b9462 PC |
440 | } |
441 | ||
fb016416 | 442 | #[no_mangle] |
e2dbdd7f SS |
443 | pub extern "C" fn rs_ike_state_get_event_info_by_id( |
444 | event_id: std::os::raw::c_int, event_name: *mut *const std::os::raw::c_char, | |
445 | event_type: *mut core::AppLayerEventType, | |
446 | ) -> i8 { | |
ecdf9f6b | 447 | if let Some(e) = IkeEvent::from_i32(event_id as i32) { |
fb016416 | 448 | let estr = match e { |
e2dbdd7f SS |
449 | IkeEvent::MalformedData => "malformed_data\0", |
450 | IkeEvent::NoEncryption => "no_encryption\0", | |
451 | IkeEvent::WeakCryptoEnc => "weak_crypto_enc\0", | |
452 | IkeEvent::WeakCryptoPRF => "weak_crypto_prf\0", | |
453 | IkeEvent::WeakCryptoDH => "weak_crypto_dh\0", | |
454 | IkeEvent::WeakCryptoAuth => "weak_crypto_auth\0", | |
455 | IkeEvent::WeakCryptoNoDH => "weak_crypto_nodh\0", | |
456 | IkeEvent::WeakCryptoNoAuth => "weak_crypto_noauth\0", | |
457 | IkeEvent::InvalidProposal => "invalid_proposal\0", | |
458 | IkeEvent::UnknownProposal => "unknown_proposal\0", | |
459 | IkeEvent::PayloadExtraData => "payload_extra_data\0", | |
f83d51d0 | 460 | IkeEvent::MultipleServerProposal => "multiple_server_proposal\0", |
fb016416 | 461 | }; |
e2dbdd7f | 462 | unsafe { |
fb016416 JL |
463 | *event_name = estr.as_ptr() as *const std::os::raw::c_char; |
464 | *event_type = core::APP_LAYER_EVENT_TYPE_TRANSACTION; | |
465 | }; | |
466 | 0 | |
467 | } else { | |
468 | -1 | |
469 | } | |
470 | } | |
471 | ||
c99b9462 | 472 | #[no_mangle] |
e2dbdd7f SS |
473 | pub extern "C" fn rs_ike_state_get_event_info( |
474 | event_name: *const std::os::raw::c_char, event_id: *mut std::os::raw::c_int, | |
475 | event_type: *mut core::AppLayerEventType, | |
476 | ) -> std::os::raw::c_int { | |
477 | if event_name == std::ptr::null() { | |
478 | return -1; | |
479 | } | |
c99b9462 PC |
480 | let c_event_name: &CStr = unsafe { CStr::from_ptr(event_name) }; |
481 | let event = match c_event_name.to_str() { | |
482 | Ok(s) => { | |
483 | match s { | |
e2dbdd7f SS |
484 | "malformed_data" => IkeEvent::MalformedData as i32, |
485 | "no_encryption" => IkeEvent::NoEncryption as i32, | |
486 | "weak_crypto_enc" => IkeEvent::WeakCryptoEnc as i32, | |
487 | "weak_crypto_prf" => IkeEvent::WeakCryptoPRF as i32, | |
488 | "weak_crypto_auth" => IkeEvent::WeakCryptoAuth as i32, | |
489 | "weak_crypto_dh" => IkeEvent::WeakCryptoDH as i32, | |
490 | "weak_crypto_nodh" => IkeEvent::WeakCryptoNoDH as i32, | |
ecdf9f6b | 491 | "weak_crypto_noauth" => IkeEvent::WeakCryptoNoAuth as i32, |
e2dbdd7f SS |
492 | "invalid_proposal" => IkeEvent::InvalidProposal as i32, |
493 | "unknown_proposal" => IkeEvent::UnknownProposal as i32, | |
494 | "payload_extra_data" => IkeEvent::PayloadExtraData as i32, | |
f83d51d0 | 495 | "multiple_server_proposal" => IkeEvent::MultipleServerProposal as i32, |
e2dbdd7f | 496 | _ => -1, // unknown event |
c99b9462 | 497 | } |
e2dbdd7f | 498 | } |
c99b9462 PC |
499 | Err(_) => -1, // UTF-8 conversion failed |
500 | }; | |
e2dbdd7f | 501 | unsafe { |
c99b9462 | 502 | *event_type = core::APP_LAYER_EVENT_TYPE_TRANSACTION; |
3f6624bf | 503 | *event_id = event as std::os::raw::c_int; |
c99b9462 PC |
504 | }; |
505 | 0 | |
506 | } | |
507 | ||
ecdf9f6b | 508 | static mut ALPROTO_IKE : AppProto = ALPROTO_UNKNOWN; |
c99b9462 PC |
509 | |
510 | #[no_mangle] | |
e2dbdd7f SS |
511 | pub extern "C" fn rs_ike_state_get_tx_iterator( |
512 | _ipproto: u8, _alproto: AppProto, state: *mut std::os::raw::c_void, min_tx_id: u64, | |
513 | _max_tx_id: u64, istate: &mut u64, | |
514 | ) -> applayer::AppLayerGetTxIterTuple { | |
515 | let state = cast_pointer!(state, IKEState); | |
516 | match state.tx_iterator(min_tx_id, istate) { | |
517 | Some((tx, out_tx_id, has_next)) => { | |
53413f2d | 518 | let c_tx = tx as *const _ as *mut _; |
e2dbdd7f SS |
519 | let ires = applayer::AppLayerGetTxIterTuple::with_values(c_tx, out_tx_id, has_next); |
520 | return ires; | |
521 | } | |
522 | None => { | |
523 | return applayer::AppLayerGetTxIterTuple::not_found(); | |
524 | } | |
c99b9462 PC |
525 | } |
526 | } | |
527 | ||
e2dbdd7f SS |
528 | // Parser name as a C style string. |
529 | const PARSER_NAME: &'static [u8] = b"ike\0"; | |
530 | const PARSER_ALIAS: &'static [u8] = b"ikev2\0"; | |
e0f75157 | 531 | |
e2dbdd7f | 532 | export_tx_data_get!(rs_ike_get_tx_data, IKETransaction); |
c99b9462 PC |
533 | |
534 | #[no_mangle] | |
e2dbdd7f | 535 | pub unsafe extern "C" fn rs_ike_register_parser() { |
c99b9462 PC |
536 | let default_port = CString::new("500").unwrap(); |
537 | let parser = RustParser { | |
fb016416 JL |
538 | name : PARSER_NAME.as_ptr() as *const std::os::raw::c_char, |
539 | default_port : default_port.as_ptr(), | |
540 | ipproto : core::IPPROTO_UDP, | |
ecdf9f6b | 541 | probe_ts : Some(rs_ike_probing_parser), |
542 | probe_tc : Some(rs_ike_probing_parser), | |
fb016416 JL |
543 | min_depth : 0, |
544 | max_depth : 16, | |
ecdf9f6b | 545 | state_new : rs_ike_state_new, |
546 | state_free : rs_ike_state_free, | |
547 | tx_free : rs_ike_state_tx_free, | |
548 | parse_ts : rs_ike_parse_request, | |
549 | parse_tc : rs_ike_parse_response, | |
550 | get_tx_count : rs_ike_state_get_tx_count, | |
551 | get_tx : rs_ike_state_get_tx, | |
efc9a7a3 VJ |
552 | tx_comp_st_ts : 1, |
553 | tx_comp_st_tc : 1, | |
ecdf9f6b | 554 | tx_get_progress : rs_ike_tx_get_alstate_progress, |
e2dbdd7f SS |
555 | get_de_state : rs_ike_tx_get_detect_state, |
556 | set_de_state : rs_ike_tx_set_detect_state, | |
ecdf9f6b | 557 | get_events : Some(rs_ike_state_get_events), |
558 | get_eventinfo : Some(rs_ike_state_get_event_info), | |
559 | get_eventinfo_byid : Some(rs_ike_state_get_event_info_by_id), | |
fb016416 JL |
560 | localstorage_new : None, |
561 | localstorage_free : None, | |
fb016416 JL |
562 | get_files : None, |
563 | get_tx_iterator : None, | |
ecdf9f6b | 564 | get_tx_data : rs_ike_get_tx_data, |
5665fc83 | 565 | apply_tx_config : None, |
3036ec4d | 566 | flags : APP_LAYER_PARSER_OPT_UNIDIR_TXS, |
4da0d9bd | 567 | truncate : None, |
c99b9462 PC |
568 | }; |
569 | ||
570 | let ip_proto_str = CString::new("udp").unwrap(); | |
e2dbdd7f | 571 | |
c99b9462 PC |
572 | if AppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 { |
573 | let alproto = AppLayerRegisterProtocolDetection(&parser, 1); | |
ecdf9f6b | 574 | ALPROTO_IKE = alproto; |
c99b9462 PC |
575 | if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 { |
576 | let _ = AppLayerRegisterParser(&parser, alproto); | |
577 | } | |
e2dbdd7f SS |
578 | |
579 | AppLayerRegisterParserAlias( | |
580 | PARSER_NAME.as_ptr() as *const std::os::raw::c_char, | |
581 | PARSER_ALIAS.as_ptr() as *const std::os::raw::c_char, | |
582 | ); | |
583 | SCLogDebug!("Rust IKE parser registered."); | |
c99b9462 | 584 | } else { |
ecdf9f6b | 585 | SCLogDebug!("Protocol detector and parser disabled for IKE."); |
c99b9462 PC |
586 | } |
587 | } |