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