]> git.ipfire.org Git - people/ms/suricata.git/blame - rust/src/ikev2/ikev2.rs
Add rules for IKEv2 events
[people/ms/suricata.git] / rust / src / ikev2 / ikev2.rs
CommitLineData
c99b9462
PC
1/* Copyright (C) 2017-2018 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// written by Pierre Chifflier <chifflier@wzdftpd.net>
19
20use ikev2::ipsec_parser::*;
21use ikev2::state::IKEV2ConnectionState;
22use core;
23use core::{AppProto,Flow,ALPROTO_UNKNOWN,ALPROTO_FAILED,STREAM_TOSERVER,STREAM_TOCLIENT};
24use applayer;
25use parser::*;
26use libc;
27use std;
28use std::ffi::{CStr,CString};
29
30use log::*;
31
32use nom::IResult;
33
34#[repr(u32)]
35pub enum IKEV2Event {
36 MalformedData = 0,
37 NoEncryption,
38 WeakCryptoEnc,
39 WeakCryptoPRF,
40 WeakCryptoDH,
41 WeakCryptoAuth,
42 WeakCryptoNoDH,
43 WeakCryptoNoAuth,
44 InvalidProposal,
45 UnknownProposal,
46}
47
48pub struct IKEV2State {
49 /// List of transactions for this session
50 transactions: Vec<IKEV2Transaction>,
51
52 /// Events counter
53 events: u16,
54
55 /// tx counter for assigning incrementing id's to tx's
56 tx_id: u64,
57
58 /// The connection state
59 connection_state: IKEV2ConnectionState,
60
61 /// The transforms proposed by the initiator
62 pub client_transforms : Vec<Vec<IkeV2Transform>>,
63
64 /// The transforms selected by the responder
65 pub server_transforms : Vec<Vec<IkeV2Transform>>,
66
67 /// The encryption algorithm selected by the responder
68 pub alg_enc: IkeTransformEncType,
69 /// The authentication algorithm selected by the responder
70 pub alg_auth: IkeTransformAuthType,
71 /// The PRF algorithm selected by the responder
72 pub alg_prf: IkeTransformPRFType,
73 /// The Diffie-Hellman algorithm selected by the responder
74 pub alg_dh: IkeTransformDHType,
75 /// The extended sequence numbers parameter selected by the responder
76 pub alg_esn: IkeTransformESNType,
77
78 /// The Diffie-Hellman group from the server KE message, if present.
79 pub dh_group: IkeTransformDHType,
80
81}
82
83#[derive(Debug)]
84pub struct IKEV2Transaction {
85 /// The IKEV2 reference ID
86 pub xid: u64,
87
88 pub hdr: IkeV2Header,
89
90 /// The internal transaction id
91 id: u64,
92
93 /// The detection engine state, if present
94 de_state: Option<*mut core::DetectEngineState>,
95
96 /// The events associated with this transaction
97 events: *mut core::AppLayerDecoderEvents,
98
99 logged: applayer::LoggerFlags,
100}
101
102
103
104impl IKEV2State {
105 pub fn new() -> IKEV2State {
106 IKEV2State{
107 transactions: Vec::new(),
108 events: 0,
109 tx_id: 0,
110 connection_state: IKEV2ConnectionState::Init,
111 dh_group: IkeTransformDHType::None,
112 client_transforms: Vec::new(),
113 server_transforms: Vec::new(),
114 alg_enc: IkeTransformEncType::ENCR_NULL,
115 alg_auth: IkeTransformAuthType::NONE,
116 alg_prf: IkeTransformPRFType::PRF_NULL,
117 alg_dh: IkeTransformDHType::None,
118 alg_esn: IkeTransformESNType::NoESN,
119 }
120 }
121}
122
123impl IKEV2State {
124 /// Parse an IKEV2 request message
125 ///
126 /// Returns The number of messages parsed, or -1 on error
127 fn parse(&mut self, i: &[u8], direction: u8) -> i8 {
128 match parse_ikev2_header(i) {
129 IResult::Done(rem,ref hdr) => {
130 SCLogDebug!("parse_ikev2: {:?}",hdr);
131 if rem.len() == 0 && hdr.length == 28 {
132 return 1;
133 }
134 // Rule 0: check version
135 if hdr.maj_ver != 2 || hdr.min_ver != 0 {
136 SCLogInfo!("Unknown header version: {}.{}", hdr.maj_ver, hdr.min_ver);
137 }
138 if hdr.init_spi == 0 {
139 SCLogInfo!("Malformed SPI - wrong length");
140 self.set_event(IKEV2Event::MalformedData);
141 return -1;
142 }
143 // only analyse IKE_SA, other payloads are encrypted
144 if hdr.exch_type != IkeExchangeType::IKE_SA_INIT {
145 return 0;
146 }
147 let mut tx = self.new_tx();
148 // use init_spi as transaction identifier
149 tx.xid = hdr.init_spi;
150 tx.hdr = (*hdr).clone();
151 match parse_ikev2_payload_list(rem,hdr.next_payload) {
152 IResult::Done(_,Ok(ref p)) => {
153 for payload in p {
154 match payload.content {
155 IkeV2PayloadContent::Dummy => (),
156 IkeV2PayloadContent::SA(ref prop) => {
157 // if hdr.flags & IKEV2_FLAG_INITIATOR != 0 {
158 self.add_proposals(prop, direction);
159 // }
160 },
161 IkeV2PayloadContent::KE(ref kex) => {
162 SCLogDebug!("KEX {:?}", kex.dh_group);
163 if direction == STREAM_TOCLIENT {
164 self.dh_group = kex.dh_group;
165 }
166 },
167 IkeV2PayloadContent::Nonce(ref n) => {
168 SCLogDebug!("Nonce: {:?}", n);
169 },
170 IkeV2PayloadContent::Notify(ref n) => {
171 SCLogDebug!("Notify: {:?}", n);
172 },
173 // XXX CertificateRequest
174 // XXX Certificate
175 // XXX Authentication
176 // XXX TSi
177 // XXX TSr
178 // XXX IDr
179 _ => {
180 SCLogInfo!("Unknown payload content {:?}", payload.content);
181 },
182 }
183 self.connection_state = self.connection_state.advance(payload);
184 };
185 },
186 e @ _ => SCLogInfo!("parse_ikev2_payload_with_type: {:?}",e),
187 }
188 self.transactions.push(tx);
189 1
190 },
191 IResult::Incomplete(_) => {
192 SCLogDebug!("Insufficient data while parsing IKEV2 data");
193 self.set_event(IKEV2Event::MalformedData);
194 -1
195 },
196 IResult::Error(_) => {
197 SCLogDebug!("Error while parsing IKEV2 data");
198 self.set_event(IKEV2Event::MalformedData);
199 -1
200 },
201 }
202 }
203
204 fn free(&mut self) {
205 // All transactions are freed when the `transactions` object is freed.
206 // But let's be explicit
207 self.transactions.clear();
208 }
209
210 fn new_tx(&mut self) -> IKEV2Transaction {
211 self.tx_id += 1;
212 IKEV2Transaction::new(self.tx_id)
213 }
214
215 fn get_tx_by_id(&mut self, tx_id: u64) -> Option<&IKEV2Transaction> {
216 self.transactions.iter().find(|&tx| tx.id == tx_id + 1)
217 }
218
219 fn free_tx(&mut self, tx_id: u64) {
220 let tx = self.transactions.iter().position(|ref tx| tx.id == tx_id + 1);
221 debug_assert!(tx != None);
222 if let Some(idx) = tx {
223 let _ = self.transactions.remove(idx);
224 }
225 }
226
227 /// Set an event. The event is set on the most recent transaction.
228 fn set_event(&mut self, event: IKEV2Event) {
229 if let Some(tx) = self.transactions.last_mut() {
230 let ev = event as u8;
231 core::sc_app_layer_decoder_events_set_event_raw(&mut tx.events, ev);
232 self.events += 1;
233 }
234 }
235
236 fn add_proposals(&mut self, prop: &Vec<IkeV2Proposal>, direction: u8) {
237 for ref p in prop {
238 let transforms : Vec<IkeV2Transform> = p.transforms.iter().map(|x| x.into()).collect();
239 // Rule 1: warn on weak or unknown transforms
240 for xform in &transforms {
241 match *xform {
242 IkeV2Transform::Encryption(ref enc) => {
243 match *enc {
244 IkeTransformEncType::ENCR_DES_IV64 |
245 IkeTransformEncType::ENCR_DES |
246 IkeTransformEncType::ENCR_3DES |
247 IkeTransformEncType::ENCR_RC5 |
248 IkeTransformEncType::ENCR_IDEA |
249 IkeTransformEncType::ENCR_CAST |
250 IkeTransformEncType::ENCR_BLOWFISH |
251 IkeTransformEncType::ENCR_3IDEA |
252 IkeTransformEncType::ENCR_DES_IV32 |
253 IkeTransformEncType::ENCR_NULL => {
254 SCLogDebug!("Weak Encryption: {:?}", enc);
255 // XXX send event only if direction == STREAM_TOCLIENT ?
256 self.set_event(IKEV2Event::WeakCryptoEnc);
257 },
258 _ => (),
259 }
260 },
261 IkeV2Transform::PRF(ref prf) => {
262 match *prf {
263 IkeTransformPRFType::PRF_NULL => {
264 SCLogDebug!("'Null' PRF transform proposed");
265 self.set_event(IKEV2Event::InvalidProposal);
266 },
267 IkeTransformPRFType::PRF_HMAC_MD5 |
268 IkeTransformPRFType::PRF_HMAC_SHA1 => {
269 SCLogDebug!("Weak PRF: {:?}", prf);
270 self.set_event(IKEV2Event::WeakCryptoPRF);
271 },
272 _ => (),
273 }
274 },
275 IkeV2Transform::Auth(ref auth) => {
276 match *auth {
277 IkeTransformAuthType::NONE => {
278 // Note: this could be expected with an AEAD encription alg.
279 // See rule 4
280 ()
281 },
282 IkeTransformAuthType::AUTH_HMAC_MD5_96 |
283 IkeTransformAuthType::AUTH_HMAC_SHA1_96 |
284 IkeTransformAuthType::AUTH_DES_MAC |
285 IkeTransformAuthType::AUTH_KPDK_MD5 |
286 IkeTransformAuthType::AUTH_AES_XCBC_96 |
287 IkeTransformAuthType::AUTH_HMAC_MD5_128 |
288 IkeTransformAuthType::AUTH_HMAC_SHA1_160 => {
289 SCLogDebug!("Weak auth: {:?}", auth);
290 self.set_event(IKEV2Event::WeakCryptoAuth);
291 },
292 _ => (),
293 }
294 },
295 IkeV2Transform::DH(ref dh) => {
296 match *dh {
297 IkeTransformDHType::None => {
298 SCLogDebug!("'None' DH transform proposed");
299 self.set_event(IKEV2Event::InvalidProposal);
300 },
301 IkeTransformDHType::Modp768 |
302 IkeTransformDHType::Modp1024 |
303 IkeTransformDHType::Modp1024s160 |
304 IkeTransformDHType::Modp1536 => {
305 SCLogDebug!("Weak DH: {:?}", dh);
306 self.set_event(IKEV2Event::WeakCryptoDH);
307 },
308 _ => (),
309 }
310 },
311 IkeV2Transform::Unknown(tx_type,tx_id) => {
312 SCLogDebug!("Unknown proposal: type={:?}, id={}", tx_type, tx_id);
313 self.set_event(IKEV2Event::UnknownProposal);
314 },
315 _ => (),
316 }
317 }
318 // Rule 2: check if no DH was proposed
319 if ! transforms.iter().any(|x| {
320 match *x {
321 IkeV2Transform::DH(_) => true,
322 _ => false
323 }
324 })
325 {
326 SCLogDebug!("No DH transform found");
327 self.set_event(IKEV2Event::WeakCryptoNoDH);
328 }
329 // Rule 3: check if proposing AH ([RFC7296] section 3.3.1)
330 if p.protocol_id == ProtocolID::AH {
331 SCLogDebug!("Proposal uses protocol AH - no confidentiality");
332 self.set_event(IKEV2Event::NoEncryption);
333 }
334 // Rule 4: lack of integrity is accepted only if using an AEAD proposal
335 // Look if no auth was proposed, including if proposal is Auth::None
336 if ! transforms.iter().any(|x| {
337 match *x {
338 IkeV2Transform::Auth(IkeTransformAuthType::NONE) => false,
339 IkeV2Transform::Auth(_) => true,
340 _ => false,
341 }
342 })
343 {
344 if ! transforms.iter().any(|x| {
345 match *x {
346 IkeV2Transform::Encryption(ref enc) => enc.is_aead(),
347 _ => false
348 }
349 }) {
350 SCLogDebug!("No integrity transform found");
351 self.set_event(IKEV2Event::WeakCryptoNoAuth);
352 }
353 }
354 // Finally
355 if direction == STREAM_TOCLIENT {
356 transforms.iter().for_each(|t|
357 match *t {
358 IkeV2Transform::Encryption(ref e) => self.alg_enc = *e,
359 IkeV2Transform::Auth(ref a) => self.alg_auth = *a,
360 IkeV2Transform::PRF(ref p) => self.alg_prf = *p,
361 IkeV2Transform::DH(ref dh) => self.alg_dh = *dh,
362 IkeV2Transform::ESN(ref e) => self.alg_esn = *e,
363 _ => (),
364 });
365 SCLogDebug!("Selected transforms: {:?}", transforms);
366 self.server_transforms.push(transforms);
367 } else {
368 SCLogDebug!("Proposed transforms: {:?}", transforms);
369 self.client_transforms.push(transforms);
370 }
371 }
372 }
373}
374
375impl IKEV2Transaction {
376 pub fn new(id: u64) -> IKEV2Transaction {
377 IKEV2Transaction {
378 xid: 0,
379 hdr: IkeV2Header {
380 init_spi: 0,
381 resp_spi: 0,
382 next_payload: IkePayloadType::NoNextPayload,
383 maj_ver: 0,
384 min_ver: 0,
385 exch_type: IkeExchangeType(0),
386 flags: 0,
387 msg_id: 0,
388 length: 0,
389 },
390 id: id,
391 de_state: None,
392 events: std::ptr::null_mut(),
393 logged: applayer::LoggerFlags::new(),
394 }
395 }
396
397 fn free(&mut self) {
398 if self.events != std::ptr::null_mut() {
399 core::sc_app_layer_decoder_events_free_events(&mut self.events);
400 }
401 }
402}
403
404impl Drop for IKEV2Transaction {
405 fn drop(&mut self) {
406 self.free();
407 }
408}
409
410
411
412
413
414
415/// Returns *mut IKEV2State
416#[no_mangle]
417pub extern "C" fn rs_ikev2_state_new() -> *mut libc::c_void {
418 let state = IKEV2State::new();
419 let boxed = Box::new(state);
420 return unsafe{std::mem::transmute(boxed)};
421}
422
423/// Params:
424/// - state: *mut IKEV2State as void pointer
425#[no_mangle]
426pub extern "C" fn rs_ikev2_state_free(state: *mut libc::c_void) {
427 // Just unbox...
428 let mut ikev2_state: Box<IKEV2State> = unsafe{std::mem::transmute(state)};
429 ikev2_state.free();
430}
431
432#[no_mangle]
433pub extern "C" fn rs_ikev2_parse_request(_flow: *const core::Flow,
434 state: *mut libc::c_void,
435 _pstate: *mut libc::c_void,
436 input: *const libc::uint8_t,
437 input_len: u32,
438 _data: *const libc::c_void) -> i8 {
439 let buf = build_slice!(input,input_len as usize);
440 let state = cast_pointer!(state,IKEV2State);
441 state.parse(buf, STREAM_TOSERVER)
442}
443
444#[no_mangle]
445pub extern "C" fn rs_ikev2_parse_response(_flow: *const core::Flow,
446 state: *mut libc::c_void,
447 pstate: *mut libc::c_void,
448 input: *const libc::uint8_t,
449 input_len: u32,
450 _data: *const libc::c_void) -> i8 {
451 let buf = build_slice!(input,input_len as usize);
452 let state = cast_pointer!(state,IKEV2State);
453 let res = state.parse(buf, STREAM_TOCLIENT);
454 if state.connection_state == IKEV2ConnectionState::ParsingDone {
455 unsafe{
456 AppLayerParserStateSetFlag(pstate, APP_LAYER_PARSER_NO_INSPECTION |
457 APP_LAYER_PARSER_NO_REASSEMBLY |
458 APP_LAYER_PARSER_BYPASS_READY)
459 };
460 }
461 res
462}
463
464#[no_mangle]
465pub extern "C" fn rs_ikev2_state_get_tx(state: *mut libc::c_void,
466 tx_id: libc::uint64_t)
467 -> *mut libc::c_void
468{
469 let state = cast_pointer!(state,IKEV2State);
470 match state.get_tx_by_id(tx_id) {
471 Some(tx) => unsafe{std::mem::transmute(tx)},
472 None => std::ptr::null_mut(),
473 }
474}
475
476#[no_mangle]
477pub extern "C" fn rs_ikev2_state_get_tx_count(state: *mut libc::c_void)
478 -> libc::uint64_t
479{
480 let state = cast_pointer!(state,IKEV2State);
481 state.tx_id
482}
483
484#[no_mangle]
485pub extern "C" fn rs_ikev2_state_tx_free(state: *mut libc::c_void,
486 tx_id: libc::uint64_t)
487{
488 let state = cast_pointer!(state,IKEV2State);
489 state.free_tx(tx_id);
490}
491
492#[no_mangle]
493pub extern "C" fn rs_ikev2_state_progress_completion_status(
494 _direction: libc::uint8_t)
495 -> libc::c_int
496{
497 return 1;
498}
499
500#[no_mangle]
501pub extern "C" fn rs_ikev2_tx_get_alstate_progress(_tx: *mut libc::c_void,
502 _direction: libc::uint8_t)
503 -> libc::c_int
504{
505 1
506}
507
508
509
510
511
512#[no_mangle]
513pub extern "C" fn rs_ikev2_tx_set_logged(_state: *mut libc::c_void,
514 tx: *mut libc::c_void,
515 logged: libc::uint32_t)
516{
517 let tx = cast_pointer!(tx,IKEV2Transaction);
518 tx.logged.set(logged);
519}
520
521#[no_mangle]
522pub extern "C" fn rs_ikev2_tx_get_logged(_state: *mut libc::c_void,
523 tx: *mut libc::c_void)
524 -> u32
525{
526 let tx = cast_pointer!(tx,IKEV2Transaction);
527 return tx.logged.get();
528}
529
530
531#[no_mangle]
532pub extern "C" fn rs_ikev2_state_set_tx_detect_state(
533 tx: *mut libc::c_void,
534 de_state: &mut core::DetectEngineState) -> libc::c_int
535{
536 let tx = cast_pointer!(tx,IKEV2Transaction);
537 tx.de_state = Some(de_state);
538 0
539}
540
541#[no_mangle]
542pub extern "C" fn rs_ikev2_state_get_tx_detect_state(
543 tx: *mut libc::c_void)
544 -> *mut core::DetectEngineState
545{
546 let tx = cast_pointer!(tx,IKEV2Transaction);
547 match tx.de_state {
548 Some(ds) => ds,
549 None => std::ptr::null_mut(),
550 }
551}
552
553
554#[no_mangle]
555pub extern "C" fn rs_ikev2_state_get_events(state: *mut libc::c_void,
556 tx_id: libc::uint64_t)
557 -> *mut core::AppLayerDecoderEvents
558{
559 let state = cast_pointer!(state,IKEV2State);
560 match state.get_tx_by_id(tx_id) {
561 Some(tx) => tx.events,
562 _ => std::ptr::null_mut(),
563 }
564}
565
566#[no_mangle]
567pub extern "C" fn rs_ikev2_state_get_event_info(event_name: *const libc::c_char,
568 event_id: *mut libc::c_int,
569 event_type: *mut core::AppLayerEventType)
570 -> libc::c_int
571{
572 if event_name == std::ptr::null() { return -1; }
573 let c_event_name: &CStr = unsafe { CStr::from_ptr(event_name) };
574 let event = match c_event_name.to_str() {
575 Ok(s) => {
576 match s {
577 "malformed_data" => IKEV2Event::MalformedData as i32,
578 "no_encryption" => IKEV2Event::NoEncryption as i32,
579 "weak_crypto_enc" => IKEV2Event::WeakCryptoEnc as i32,
580 "weak_crypto_prf" => IKEV2Event::WeakCryptoPRF as i32,
581 "weak_crypto_auth" => IKEV2Event::WeakCryptoAuth as i32,
582 "weak_crypto_dh" => IKEV2Event::WeakCryptoDH as i32,
583 "weak_crypto_nodh" => IKEV2Event::WeakCryptoNoDH as i32,
584 "weak_crypto_noauth" => IKEV2Event::WeakCryptoNoAuth as i32,
585 "invalid_proposal" => IKEV2Event::InvalidProposal as i32,
586 "unknown_proposal" => IKEV2Event::UnknownProposal as i32,
587 _ => -1, // unknown event
588 }
589 },
590 Err(_) => -1, // UTF-8 conversion failed
591 };
592 unsafe{
593 *event_type = core::APP_LAYER_EVENT_TYPE_TRANSACTION;
594 *event_id = event as libc::c_int;
595 };
596 0
597}
598
599
600static mut ALPROTO_IKEV2 : AppProto = ALPROTO_UNKNOWN;
601
602#[no_mangle]
603pub extern "C" fn rs_ikev2_probing_parser(_flow: *const Flow, input:*const libc::uint8_t, input_len: u32, _offset: *const u32) -> AppProto {
604 let slice = build_slice!(input,input_len as usize);
605 let alproto = unsafe{ ALPROTO_IKEV2 };
606 match parse_ikev2_header(slice) {
607 IResult::Done(_, ref hdr) => {
608 if hdr.maj_ver != 2 || hdr.min_ver != 0 {
609 SCLogDebug!("ipsec_probe: could be ipsec, but with unsupported/invalid version {}.{}",
610 hdr.maj_ver, hdr.min_ver);
611 return unsafe{ALPROTO_FAILED};
612 }
613 if hdr.exch_type.0 < 34 || hdr.exch_type.0 > 37 {
614 SCLogDebug!("ipsec_probe: could be ipsec, but with unsupported/invalid exchange type {}",
615 hdr.exch_type.0);
616 return unsafe{ALPROTO_FAILED};
617 }
618 if hdr.length as usize != slice.len() {
619 SCLogDebug!("ipsec_probe: could be ipsec, but length does not match");
620 return unsafe{ALPROTO_FAILED};
621 }
622 return alproto;
623 },
624 IResult::Incomplete(_) => {
625 return ALPROTO_UNKNOWN;
626 },
627 IResult::Error(_) => {
628 return unsafe{ALPROTO_FAILED};
629 },
630 }
631}
632
633const PARSER_NAME : &'static [u8] = b"ikev2\0";
634
635#[no_mangle]
636pub unsafe extern "C" fn rs_register_ikev2_parser() {
637 let default_port = CString::new("500").unwrap();
638 let parser = RustParser {
639 name : PARSER_NAME.as_ptr() as *const libc::c_char,
640 default_port : default_port.as_ptr(),
641 ipproto : libc::IPPROTO_UDP,
642 probe_ts : rs_ikev2_probing_parser,
643 probe_tc : rs_ikev2_probing_parser,
644 min_depth : 0,
645 max_depth : 16,
646 state_new : rs_ikev2_state_new,
647 state_free : rs_ikev2_state_free,
648 tx_free : rs_ikev2_state_tx_free,
649 parse_ts : rs_ikev2_parse_request,
650 parse_tc : rs_ikev2_parse_response,
651 get_tx_count : rs_ikev2_state_get_tx_count,
652 get_tx : rs_ikev2_state_get_tx,
653 tx_get_comp_st : rs_ikev2_state_progress_completion_status,
654 tx_get_progress : rs_ikev2_tx_get_alstate_progress,
655 get_tx_logged : Some(rs_ikev2_tx_get_logged),
656 set_tx_logged : Some(rs_ikev2_tx_set_logged),
657 get_de_state : rs_ikev2_state_get_tx_detect_state,
658 set_de_state : rs_ikev2_state_set_tx_detect_state,
659 get_events : Some(rs_ikev2_state_get_events),
660 get_eventinfo : Some(rs_ikev2_state_get_event_info),
661 localstorage_new : None,
662 localstorage_free : None,
663 get_tx_mpm_id : None,
664 set_tx_mpm_id : None,
665 get_files : None,
666 };
667
668 let ip_proto_str = CString::new("udp").unwrap();
669 if AppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
670 let alproto = AppLayerRegisterProtocolDetection(&parser, 1);
671 // store the allocated ID for the probe function
672 ALPROTO_IKEV2 = alproto;
673 if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
674 let _ = AppLayerRegisterParser(&parser, alproto);
675 }
676 } else {
677 SCLogDebug!("Protocol detecter and parser disabled for IKEV2.");
678 }
679}
680
681
682#[cfg(test)]
683mod tests {
684 use super::IKEV2State;
685
686 #[test]
687 fn test_ikev2_parse_request_valid() {
688 // A UDP IKEV2 v4 request, in client mode
689 const REQ : &[u8] = &[
690 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
691 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
692 0x00, 0x20, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00,
693 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
694 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
695 0x18, 0x57, 0xab, 0xc3, 0x4a, 0x5f, 0x2c, 0xfe
696 ];
697
698 let mut state = IKEV2State::new();
699 assert_eq!(1, state.parse(REQ, 0));
700 }
701}