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