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