]>
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::*; | |
243960a5 | 25 | use crate::core::{self, *}; |
e2dbdd7f SS |
26 | use crate::ike::ikev1::{handle_ikev1, IkeV1Header, Ikev1Container}; |
27 | use crate::ike::ikev2::{handle_ikev2, Ikev2Container}; | |
28 | use crate::ike::parser::*; | |
13b73997 | 29 | use nom; |
e2dbdd7f SS |
30 | use std; |
31 | use std::collections::HashSet; | |
71679c6a | 32 | use std::ffi::CString; |
c99b9462 | 33 | |
71679c6a | 34 | #[derive(AppLayerEvent)] |
ecdf9f6b | 35 | pub enum IkeEvent { |
71679c6a | 36 | MalformedData, |
c99b9462 PC |
37 | NoEncryption, |
38 | WeakCryptoEnc, | |
71679c6a JI |
39 | WeakCryptoPrf, |
40 | WeakCryptoDh, | |
c99b9462 | 41 | WeakCryptoAuth, |
71679c6a | 42 | WeakCryptoNoDh, |
c99b9462 PC |
43 | WeakCryptoNoAuth, |
44 | InvalidProposal, | |
45 | UnknownProposal, | |
e2dbdd7f | 46 | PayloadExtraData, |
f83d51d0 | 47 | MultipleServerProposal, |
c99b9462 PC |
48 | } |
49 | ||
e2dbdd7f SS |
50 | pub struct IkeHeaderWrapper { |
51 | pub spi_initiator: String, | |
52 | pub spi_responder: String, | |
53 | pub maj_ver: u8, | |
54 | pub min_ver: u8, | |
55 | pub msg_id: u32, | |
56 | pub flags: u8, | |
57 | pub ikev1_transforms: Vec<Vec<SaAttribute>>, | |
accdad78 | 58 | pub ikev2_transforms: Vec<IkeV2Transform>, |
e2dbdd7f SS |
59 | pub ikev1_header: IkeV1Header, |
60 | pub ikev2_header: IkeV2Header, | |
61 | } | |
c99b9462 | 62 | |
e2dbdd7f SS |
63 | impl IkeHeaderWrapper { |
64 | pub fn new() -> IkeHeaderWrapper { | |
65 | IkeHeaderWrapper { | |
66 | spi_initiator: String::new(), | |
67 | spi_responder: String::new(), | |
68 | maj_ver: 0, | |
69 | min_ver: 0, | |
70 | msg_id: 0, | |
71 | flags: 0, | |
72 | ikev1_transforms: Vec::new(), | |
73 | ikev2_transforms: Vec::new(), | |
74 | ikev1_header: IkeV1Header::default(), | |
75 | ikev2_header: IkeV2Header { | |
76 | init_spi: 0, | |
77 | resp_spi: 0, | |
78 | next_payload: IkePayloadType::NoNextPayload, | |
79 | maj_ver: 0, | |
80 | min_ver: 0, | |
81 | exch_type: IkeExchangeType(0), | |
82 | flags: 0, | |
83 | msg_id: 0, | |
84 | length: 0, | |
85 | }, | |
86 | } | |
87 | } | |
88 | } | |
c99b9462 | 89 | |
e2dbdd7f SS |
90 | #[derive(Default)] |
91 | pub struct IkePayloadWrapper { | |
92 | pub ikev1_payload_types: Option<HashSet<u8>>, | |
93 | pub ikev2_payload_types: Vec<IkePayloadType>, | |
c99b9462 PC |
94 | } |
95 | ||
ecdf9f6b | 96 | pub struct IKETransaction { |
e2dbdd7f | 97 | tx_id: u64, |
c99b9462 | 98 | |
e2dbdd7f SS |
99 | pub ike_version: u8, |
100 | pub hdr: IkeHeaderWrapper, | |
101 | pub payload_types: IkePayloadWrapper, | |
d9434628 PC |
102 | pub notify_types: Vec<NotifyType>, |
103 | ||
e2dbdd7f | 104 | /// errors seen during exchange |
d9434628 PC |
105 | pub errors: u32, |
106 | ||
e2dbdd7f | 107 | logged: LoggerFlags, |
c99b9462 | 108 | de_state: Option<*mut core::DetectEngineState>, |
c99b9462 | 109 | events: *mut core::AppLayerDecoderEvents, |
e0f75157 | 110 | tx_data: applayer::AppLayerTxData, |
c99b9462 PC |
111 | } |
112 | ||
d6b2d7e1 JI |
113 | impl Transaction for IKETransaction { |
114 | fn id(&self) -> u64 { | |
115 | self.tx_id | |
116 | } | |
117 | } | |
118 | ||
e2dbdd7f SS |
119 | impl IKETransaction { |
120 | pub fn new() -> IKETransaction { | |
121 | IKETransaction { | |
c99b9462 | 122 | tx_id: 0, |
e2dbdd7f SS |
123 | ike_version: 0, |
124 | hdr: IkeHeaderWrapper::new(), | |
125 | payload_types: Default::default(), | |
126 | notify_types: vec![], | |
127 | logged: LoggerFlags::new(), | |
128 | de_state: None, | |
129 | events: std::ptr::null_mut(), | |
130 | tx_data: applayer::AppLayerTxData::new(), | |
131 | errors: 0, | |
c99b9462 PC |
132 | } |
133 | } | |
c99b9462 | 134 | |
e2dbdd7f | 135 | pub fn free(&mut self) { |
922a453d | 136 | if !self.events.is_null() { |
e2dbdd7f SS |
137 | core::sc_app_layer_decoder_events_free_events(&mut self.events); |
138 | } | |
139 | if let Some(state) = self.de_state { | |
140 | core::sc_detect_engine_state_free(state); | |
c99b9462 PC |
141 | } |
142 | } | |
accdad78 PA |
143 | |
144 | /// Set an event. | |
145 | pub fn set_event(&mut self, event: IkeEvent) { | |
146 | let ev = event as u8; | |
147 | core::sc_app_layer_decoder_events_set_event_raw(&mut self.events, ev); | |
148 | } | |
e2dbdd7f | 149 | } |
c99b9462 | 150 | |
e2dbdd7f SS |
151 | impl Drop for IKETransaction { |
152 | fn drop(&mut self) { | |
153 | self.free(); | |
c99b9462 | 154 | } |
e2dbdd7f | 155 | } |
c99b9462 | 156 | |
e2dbdd7f SS |
157 | #[derive(Default)] |
158 | pub struct IKEState { | |
159 | tx_id: u64, | |
160 | pub transactions: Vec<IKETransaction>, | |
c99b9462 | 161 | |
e2dbdd7f SS |
162 | pub ikev1_container: Ikev1Container, |
163 | pub ikev2_container: Ikev2Container, | |
164 | } | |
c99b9462 | 165 | |
d6b2d7e1 JI |
166 | impl State<IKETransaction> for IKEState { |
167 | fn get_transactions(&self) -> &[IKETransaction] { | |
168 | &self.transactions | |
169 | } | |
170 | } | |
171 | ||
e2dbdd7f SS |
172 | impl IKEState { |
173 | // Free a transaction by ID. | |
c99b9462 | 174 | fn free_tx(&mut self, tx_id: u64) { |
e2dbdd7f SS |
175 | let tx = self |
176 | .transactions | |
177 | .iter() | |
69cf5c9e | 178 | .position(|tx| tx.tx_id == tx_id + 1); |
c99b9462 PC |
179 | debug_assert!(tx != None); |
180 | if let Some(idx) = tx { | |
181 | let _ = self.transactions.remove(idx); | |
182 | } | |
183 | } | |
184 | ||
e2dbdd7f SS |
185 | pub fn get_tx(&mut self, tx_id: u64) -> Option<&mut IKETransaction> { |
186 | for tx in &mut self.transactions { | |
187 | if tx.tx_id == tx_id + 1 { | |
188 | return Some(tx); | |
189 | } | |
190 | } | |
191 | return None; | |
192 | } | |
193 | ||
194 | pub fn new_tx(&mut self) -> IKETransaction { | |
195 | let mut tx = IKETransaction::new(); | |
196 | self.tx_id += 1; | |
197 | tx.tx_id = self.tx_id; | |
198 | return tx; | |
199 | } | |
200 | ||
c99b9462 | 201 | /// Set an event. The event is set on the most recent transaction. |
e2dbdd7f | 202 | pub fn set_event(&mut self, event: IkeEvent) { |
c99b9462 PC |
203 | if let Some(tx) = self.transactions.last_mut() { |
204 | let ev = event as u8; | |
205 | core::sc_app_layer_decoder_events_set_event_raw(&mut tx.events, ev); | |
f90733fe | 206 | } else { |
e2dbdd7f SS |
207 | SCLogDebug!( |
208 | "IKE: trying to set event {} on non-existing transaction", | |
209 | event as u32 | |
210 | ); | |
c99b9462 PC |
211 | } |
212 | } | |
213 | ||
243960a5 | 214 | fn handle_input(&mut self, input: &[u8], direction: Direction) -> AppLayerResult { |
e2dbdd7f SS |
215 | // We're not interested in empty requests. |
216 | if input.len() == 0 { | |
217 | return AppLayerResult::ok(); | |
218 | } | |
219 | ||
220 | let mut current = input; | |
221 | match parse_isakmp_header(current) { | |
222 | Ok((rem, isakmp_header)) => { | |
223 | current = rem; | |
224 | ||
225 | if isakmp_header.maj_ver != 1 && isakmp_header.maj_ver != 2 { | |
226 | SCLogDebug!("Unsupported ISAKMP major_version"); | |
227 | return AppLayerResult::err(); | |
c99b9462 | 228 | } |
e2dbdd7f SS |
229 | |
230 | if isakmp_header.maj_ver == 1 { | |
231 | handle_ikev1(self, current, isakmp_header, direction); | |
232 | } else if isakmp_header.maj_ver == 2 { | |
233 | handle_ikev2(self, current, isakmp_header, direction); | |
234 | } else { | |
235 | return AppLayerResult::err(); | |
c99b9462 | 236 | } |
e2dbdd7f | 237 | return AppLayerResult::ok(); // todo either remove outer loop or check header length-field if we have completely read everything |
c99b9462 | 238 | } |
e2dbdd7f SS |
239 | Err(nom::Err::Incomplete(_)) => { |
240 | SCLogDebug!("Insufficient data while parsing IKE"); | |
241 | return AppLayerResult::err(); | |
c99b9462 | 242 | } |
e2dbdd7f SS |
243 | Err(_) => { |
244 | SCLogDebug!("Error while parsing IKE packet"); | |
245 | return AppLayerResult::err(); | |
c99b9462 PC |
246 | } |
247 | } | |
248 | } | |
e2dbdd7f | 249 | } |
c99b9462 | 250 | |
e2dbdd7f | 251 | /// Probe to see if this input looks like a request or response. |
243960a5 | 252 | fn probe(input: &[u8], direction: Direction, rdir: *mut u8) -> bool { |
e2dbdd7f SS |
253 | match parse_isakmp_header(input) { |
254 | Ok((_, isakmp_header)) => { | |
255 | if isakmp_header.maj_ver == 1 { | |
243960a5 | 256 | if isakmp_header.resp_spi == 0 && direction != Direction::ToServer { |
e2dbdd7f | 257 | unsafe { |
243960a5 | 258 | *rdir = Direction::ToServer.into(); |
e2dbdd7f SS |
259 | } |
260 | } | |
261 | return true; | |
262 | } else if isakmp_header.maj_ver == 2 { | |
263 | if isakmp_header.min_ver != 0 { | |
264 | SCLogDebug!( | |
265 | "ipsec_probe: could be ipsec, but with unsupported/invalid version {}.{}", | |
266 | isakmp_header.maj_ver, | |
267 | isakmp_header.min_ver | |
268 | ); | |
269 | return false; | |
270 | } | |
271 | if isakmp_header.exch_type < 34 || isakmp_header.exch_type > 37 { | |
272 | SCLogDebug!("ipsec_probe: could be ipsec, but with unsupported/invalid exchange type {}", | |
273 | isakmp_header.exch_type); | |
274 | return false; | |
275 | } | |
276 | if isakmp_header.length as usize != input.len() { | |
277 | SCLogDebug!("ipsec_probe: could be ipsec, but length does not match"); | |
278 | return false; | |
279 | } | |
280 | ||
243960a5 | 281 | if isakmp_header.resp_spi == 0 && direction != Direction::ToServer { |
e2dbdd7f | 282 | unsafe { |
243960a5 | 283 | *rdir = Direction::ToServer.into(); |
e2dbdd7f SS |
284 | } |
285 | } | |
286 | return true; | |
287 | } | |
288 | ||
289 | return false; | |
083908f3 | 290 | } |
e2dbdd7f | 291 | Err(_) => return false, |
c99b9462 PC |
292 | } |
293 | } | |
294 | ||
e2dbdd7f SS |
295 | // C exports. |
296 | export_tx_get_detect_state!(rs_ike_tx_get_detect_state, IKETransaction); | |
297 | export_tx_set_detect_state!(rs_ike_tx_set_detect_state, IKETransaction); | |
298 | ||
299 | /// C entry point for a probing parser. | |
300 | #[no_mangle] | |
363b5f99 | 301 | pub unsafe extern "C" fn rs_ike_probing_parser( |
e2dbdd7f SS |
302 | _flow: *const Flow, direction: u8, input: *const u8, input_len: u32, rdir: *mut u8, |
303 | ) -> AppProto { | |
304 | if input_len < 28 { | |
305 | // at least the ISAKMP_HEADER must be there, not ALPROTO_UNKNOWN because over UDP | |
363b5f99 | 306 | return ALPROTO_FAILED; |
e2dbdd7f SS |
307 | } |
308 | ||
922a453d | 309 | if !input.is_null() { |
e2dbdd7f | 310 | let slice = build_slice!(input, input_len as usize); |
243960a5 SB |
311 | if probe(slice, direction.into(), rdir) { |
312 | return ALPROTO_IKE; | |
e2dbdd7f | 313 | } |
c99b9462 | 314 | } |
363b5f99 | 315 | return ALPROTO_FAILED; |
c99b9462 PC |
316 | } |
317 | ||
c99b9462 | 318 | #[no_mangle] |
e2dbdd7f SS |
319 | pub extern "C" fn rs_ike_state_new( |
320 | _orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto, | |
321 | ) -> *mut std::os::raw::c_void { | |
322 | let state = IKEState::default(); | |
c99b9462 | 323 | let boxed = Box::new(state); |
53413f2d | 324 | return Box::into_raw(boxed) as *mut _; |
c99b9462 PC |
325 | } |
326 | ||
c99b9462 | 327 | #[no_mangle] |
363b5f99 | 328 | pub unsafe extern "C" fn rs_ike_state_free(state: *mut std::os::raw::c_void) { |
c99b9462 | 329 | // Just unbox... |
363b5f99 | 330 | std::mem::drop(Box::from_raw(state as *mut IKEState)); |
c99b9462 PC |
331 | } |
332 | ||
333 | #[no_mangle] | |
363b5f99 | 334 | pub unsafe extern "C" fn rs_ike_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) { |
e2dbdd7f SS |
335 | let state = cast_pointer!(state, IKEState); |
336 | state.free_tx(tx_id); | |
c99b9462 PC |
337 | } |
338 | ||
339 | #[no_mangle] | |
363b5f99 | 340 | pub unsafe extern "C" fn rs_ike_parse_request( |
e2dbdd7f SS |
341 | _flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, |
342 | input: *const u8, input_len: u32, _data: *const std::os::raw::c_void, _flags: u8, | |
343 | ) -> AppLayerResult { | |
344 | let state = cast_pointer!(state, IKEState); | |
345 | let buf = build_slice!(input, input_len as usize); | |
346 | ||
243960a5 | 347 | return state.handle_input(buf, Direction::ToServer); |
c99b9462 PC |
348 | } |
349 | ||
350 | #[no_mangle] | |
363b5f99 | 351 | pub unsafe extern "C" fn rs_ike_parse_response( |
e2dbdd7f SS |
352 | _flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void, |
353 | input: *const u8, input_len: u32, _data: *const std::os::raw::c_void, _flags: u8, | |
354 | ) -> AppLayerResult { | |
355 | let state = cast_pointer!(state, IKEState); | |
356 | let buf = build_slice!(input, input_len as usize); | |
243960a5 | 357 | return state.handle_input(buf, Direction::ToClient); |
c99b9462 PC |
358 | } |
359 | ||
360 | #[no_mangle] | |
363b5f99 | 361 | pub unsafe extern "C" fn rs_ike_state_get_tx( |
e2dbdd7f SS |
362 | state: *mut std::os::raw::c_void, tx_id: u64, |
363 | ) -> *mut std::os::raw::c_void { | |
364 | let state = cast_pointer!(state, IKEState); | |
365 | match state.get_tx(tx_id) { | |
366 | Some(tx) => { | |
53413f2d | 367 | return tx as *const _ as *mut _; |
e2dbdd7f SS |
368 | } |
369 | None => { | |
370 | return std::ptr::null_mut(); | |
371 | } | |
372 | } | |
c99b9462 PC |
373 | } |
374 | ||
375 | #[no_mangle] | |
363b5f99 | 376 | pub unsafe extern "C" fn rs_ike_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 { |
e2dbdd7f SS |
377 | let state = cast_pointer!(state, IKEState); |
378 | return state.tx_id; | |
c99b9462 PC |
379 | } |
380 | ||
c99b9462 | 381 | #[no_mangle] |
e2dbdd7f SS |
382 | pub extern "C" fn rs_ike_state_progress_completion_status(_direction: u8) -> std::os::raw::c_int { |
383 | // This parser uses 1 to signal transaction completion status. | |
ecdf9f6b | 384 | return 1; |
385 | } | |
386 | ||
387 | #[no_mangle] | |
e2dbdd7f SS |
388 | pub extern "C" fn rs_ike_tx_get_alstate_progress( |
389 | _tx: *mut std::os::raw::c_void, _direction: u8, | |
390 | ) -> std::os::raw::c_int { | |
391 | return 1; | |
c99b9462 PC |
392 | } |
393 | ||
c99b9462 | 394 | #[no_mangle] |
363b5f99 | 395 | pub unsafe extern "C" fn rs_ike_tx_get_logged( |
e2dbdd7f SS |
396 | _state: *mut std::os::raw::c_void, tx: *mut std::os::raw::c_void, |
397 | ) -> u32 { | |
398 | let tx = cast_pointer!(tx, IKETransaction); | |
399 | return tx.logged.get(); | |
c99b9462 PC |
400 | } |
401 | ||
402 | #[no_mangle] | |
363b5f99 | 403 | pub unsafe extern "C" fn rs_ike_tx_set_logged( |
e2dbdd7f SS |
404 | _state: *mut std::os::raw::c_void, tx: *mut std::os::raw::c_void, logged: u32, |
405 | ) { | |
406 | let tx = cast_pointer!(tx, IKETransaction); | |
407 | tx.logged.set(logged); | |
c99b9462 PC |
408 | } |
409 | ||
c99b9462 | 410 | #[no_mangle] |
363b5f99 | 411 | pub unsafe extern "C" fn rs_ike_state_get_events( |
e2dbdd7f SS |
412 | tx: *mut std::os::raw::c_void, |
413 | ) -> *mut core::AppLayerDecoderEvents { | |
ecdf9f6b | 414 | let tx = cast_pointer!(tx, IKETransaction); |
d568e7fa | 415 | return tx.events; |
c99b9462 PC |
416 | } |
417 | ||
ecdf9f6b | 418 | static mut ALPROTO_IKE : AppProto = ALPROTO_UNKNOWN; |
c99b9462 | 419 | |
e2dbdd7f SS |
420 | // Parser name as a C style string. |
421 | const PARSER_NAME: &'static [u8] = b"ike\0"; | |
422 | const PARSER_ALIAS: &'static [u8] = b"ikev2\0"; | |
e0f75157 | 423 | |
e2dbdd7f | 424 | export_tx_data_get!(rs_ike_get_tx_data, IKETransaction); |
c99b9462 PC |
425 | |
426 | #[no_mangle] | |
e2dbdd7f | 427 | pub unsafe extern "C" fn rs_ike_register_parser() { |
c99b9462 PC |
428 | let default_port = CString::new("500").unwrap(); |
429 | let parser = RustParser { | |
fb016416 JL |
430 | name : PARSER_NAME.as_ptr() as *const std::os::raw::c_char, |
431 | default_port : default_port.as_ptr(), | |
432 | ipproto : core::IPPROTO_UDP, | |
ecdf9f6b | 433 | probe_ts : Some(rs_ike_probing_parser), |
434 | probe_tc : Some(rs_ike_probing_parser), | |
fb016416 JL |
435 | min_depth : 0, |
436 | max_depth : 16, | |
ecdf9f6b | 437 | state_new : rs_ike_state_new, |
438 | state_free : rs_ike_state_free, | |
439 | tx_free : rs_ike_state_tx_free, | |
440 | parse_ts : rs_ike_parse_request, | |
441 | parse_tc : rs_ike_parse_response, | |
442 | get_tx_count : rs_ike_state_get_tx_count, | |
443 | get_tx : rs_ike_state_get_tx, | |
efc9a7a3 VJ |
444 | tx_comp_st_ts : 1, |
445 | tx_comp_st_tc : 1, | |
ecdf9f6b | 446 | tx_get_progress : rs_ike_tx_get_alstate_progress, |
e2dbdd7f SS |
447 | get_de_state : rs_ike_tx_get_detect_state, |
448 | set_de_state : rs_ike_tx_set_detect_state, | |
ecdf9f6b | 449 | get_events : Some(rs_ike_state_get_events), |
71679c6a JI |
450 | get_eventinfo : Some(IkeEvent::get_event_info), |
451 | get_eventinfo_byid : Some(IkeEvent::get_event_info_by_id), | |
fb016416 JL |
452 | localstorage_new : None, |
453 | localstorage_free : None, | |
fb016416 | 454 | get_files : None, |
d6b2d7e1 | 455 | get_tx_iterator : Some(applayer::state_get_tx_iterator::<IKEState, IKETransaction>), |
ecdf9f6b | 456 | get_tx_data : rs_ike_get_tx_data, |
5665fc83 | 457 | apply_tx_config : None, |
3036ec4d | 458 | flags : APP_LAYER_PARSER_OPT_UNIDIR_TXS, |
4da0d9bd | 459 | truncate : None, |
c99b9462 PC |
460 | }; |
461 | ||
462 | let ip_proto_str = CString::new("udp").unwrap(); | |
e2dbdd7f | 463 | |
c99b9462 PC |
464 | if AppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 { |
465 | let alproto = AppLayerRegisterProtocolDetection(&parser, 1); | |
ecdf9f6b | 466 | ALPROTO_IKE = alproto; |
c99b9462 PC |
467 | if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 { |
468 | let _ = AppLayerRegisterParser(&parser, alproto); | |
469 | } | |
e2dbdd7f SS |
470 | |
471 | AppLayerRegisterParserAlias( | |
472 | PARSER_NAME.as_ptr() as *const std::os::raw::c_char, | |
473 | PARSER_ALIAS.as_ptr() as *const std::os::raw::c_char, | |
474 | ); | |
475 | SCLogDebug!("Rust IKE parser registered."); | |
c99b9462 | 476 | } else { |
ecdf9f6b | 477 | SCLogDebug!("Protocol detector and parser disabled for IKE."); |
c99b9462 PC |
478 | } |
479 | } |