1 /* Copyright (C) 2020 Open Information Security Foundation
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
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.
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
18 // Author: Frank Honza <frank.honza@dcso.de>
20 extern crate ipsec_parser;
21 use self::ipsec_parser::*;
24 use crate::applayer::*;
25 use crate::core::{self, *};
26 use crate::ike::ikev1::{handle_ikev1, IkeV1Header, Ikev1Container};
27 use crate::ike::ikev2::{handle_ikev2, Ikev2Container};
28 use crate::ike::parser::*;
31 use std::collections::HashSet;
32 use std::ffi::CString;
34 #[derive(AppLayerEvent)]
47 MultipleServerProposal,
50 pub struct IkeHeaderWrapper {
51 pub spi_initiator: String,
52 pub spi_responder: String,
57 pub ikev1_transforms: Vec<Vec<SaAttribute>>,
58 pub ikev2_transforms: Vec<IkeV2Transform>,
59 pub ikev1_header: IkeV1Header,
60 pub ikev2_header: IkeV2Header,
63 impl IkeHeaderWrapper {
64 pub fn new() -> IkeHeaderWrapper {
66 spi_initiator: String::new(),
67 spi_responder: String::new(),
72 ikev1_transforms: Vec::new(),
73 ikev2_transforms: Vec::new(),
74 ikev1_header: IkeV1Header::default(),
75 ikev2_header: IkeV2Header {
78 next_payload: IkePayloadType::NoNextPayload,
81 exch_type: IkeExchangeType(0),
91 pub struct IkePayloadWrapper {
92 pub ikev1_payload_types: Option<HashSet<u8>>,
93 pub ikev2_payload_types: Vec<IkePayloadType>,
96 pub struct IKETransaction {
100 pub hdr: IkeHeaderWrapper,
101 pub payload_types: IkePayloadWrapper,
102 pub notify_types: Vec<NotifyType>,
104 /// errors seen during exchange
108 de_state: Option<*mut core::DetectEngineState>,
109 events: *mut core::AppLayerDecoderEvents,
110 tx_data: applayer::AppLayerTxData,
113 impl IKETransaction {
114 pub fn new() -> IKETransaction {
118 hdr: IkeHeaderWrapper::new(),
119 payload_types: Default::default(),
120 notify_types: vec![],
121 logged: LoggerFlags::new(),
123 events: std::ptr::null_mut(),
124 tx_data: applayer::AppLayerTxData::new(),
129 pub fn free(&mut self) {
130 if !self.events.is_null() {
131 core::sc_app_layer_decoder_events_free_events(&mut self.events);
133 if let Some(state) = self.de_state {
134 core::sc_detect_engine_state_free(state);
139 pub fn set_event(&mut self, event: IkeEvent) {
140 let ev = event as u8;
141 core::sc_app_layer_decoder_events_set_event_raw(&mut self.events, ev);
145 impl Drop for IKETransaction {
152 pub struct IKEState {
154 pub transactions: Vec<IKETransaction>,
156 pub ikev1_container: Ikev1Container,
157 pub ikev2_container: Ikev2Container,
161 // Free a transaction by ID.
162 fn free_tx(&mut self, tx_id: u64) {
166 .position(|tx| tx.tx_id == tx_id + 1);
167 debug_assert!(tx != None);
168 if let Some(idx) = tx {
169 let _ = self.transactions.remove(idx);
173 pub fn get_tx(&mut self, tx_id: u64) -> Option<&mut IKETransaction> {
174 for tx in &mut self.transactions {
175 if tx.tx_id == tx_id + 1 {
182 pub fn new_tx(&mut self) -> IKETransaction {
183 let mut tx = IKETransaction::new();
185 tx.tx_id = self.tx_id;
189 /// Set an event. The event is set on the most recent transaction.
190 pub fn set_event(&mut self, event: IkeEvent) {
191 if let Some(tx) = self.transactions.last_mut() {
192 let ev = event as u8;
193 core::sc_app_layer_decoder_events_set_event_raw(&mut tx.events, ev);
196 "IKE: trying to set event {} on non-existing transaction",
202 fn handle_input(&mut self, input: &[u8], direction: Direction) -> AppLayerResult {
203 // We're not interested in empty requests.
204 if input.len() == 0 {
205 return AppLayerResult::ok();
208 let mut current = input;
209 match parse_isakmp_header(current) {
210 Ok((rem, isakmp_header)) => {
213 if isakmp_header.maj_ver != 1 && isakmp_header.maj_ver != 2 {
214 SCLogDebug!("Unsupported ISAKMP major_version");
215 return AppLayerResult::err();
218 if isakmp_header.maj_ver == 1 {
219 handle_ikev1(self, current, isakmp_header, direction);
220 } else if isakmp_header.maj_ver == 2 {
221 handle_ikev2(self, current, isakmp_header, direction);
223 return AppLayerResult::err();
225 return AppLayerResult::ok(); // todo either remove outer loop or check header length-field if we have completely read everything
227 Err(nom::Err::Incomplete(_)) => {
228 SCLogDebug!("Insufficient data while parsing IKE");
229 return AppLayerResult::err();
232 SCLogDebug!("Error while parsing IKE packet");
233 return AppLayerResult::err();
239 &mut self, min_tx_id: u64, state: &mut u64,
240 ) -> Option<(&IKETransaction, u64, bool)> {
241 let mut index = *state as usize;
242 let len = self.transactions.len();
245 let tx = &self.transactions[index];
246 if tx.tx_id < min_tx_id + 1 {
250 *state = index as u64;
252 return Some((tx, tx.tx_id - 1, (len - index) > 1));
259 /// Probe to see if this input looks like a request or response.
260 fn probe(input: &[u8], direction: Direction, rdir: *mut u8) -> bool {
261 match parse_isakmp_header(input) {
262 Ok((_, isakmp_header)) => {
263 if isakmp_header.maj_ver == 1 {
264 if isakmp_header.resp_spi == 0 && direction != Direction::ToServer {
266 *rdir = Direction::ToServer.into();
270 } else if isakmp_header.maj_ver == 2 {
271 if isakmp_header.min_ver != 0 {
273 "ipsec_probe: could be ipsec, but with unsupported/invalid version {}.{}",
274 isakmp_header.maj_ver,
275 isakmp_header.min_ver
279 if isakmp_header.exch_type < 34 || isakmp_header.exch_type > 37 {
280 SCLogDebug!("ipsec_probe: could be ipsec, but with unsupported/invalid exchange type {}",
281 isakmp_header.exch_type);
284 if isakmp_header.length as usize != input.len() {
285 SCLogDebug!("ipsec_probe: could be ipsec, but length does not match");
289 if isakmp_header.resp_spi == 0 && direction != Direction::ToServer {
291 *rdir = Direction::ToServer.into();
299 Err(_) => return false,
304 export_tx_get_detect_state!(rs_ike_tx_get_detect_state, IKETransaction);
305 export_tx_set_detect_state!(rs_ike_tx_set_detect_state, IKETransaction);
307 /// C entry point for a probing parser.
309 pub unsafe extern "C" fn rs_ike_probing_parser(
310 _flow: *const Flow, direction: u8, input: *const u8, input_len: u32, rdir: *mut u8,
313 // at least the ISAKMP_HEADER must be there, not ALPROTO_UNKNOWN because over UDP
314 return ALPROTO_FAILED;
317 if !input.is_null() {
318 let slice = build_slice!(input, input_len as usize);
319 if probe(slice, direction.into(), rdir) {
323 return ALPROTO_FAILED;
327 pub extern "C" fn rs_ike_state_new(
328 _orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto,
329 ) -> *mut std::os::raw::c_void {
330 let state = IKEState::default();
331 let boxed = Box::new(state);
332 return Box::into_raw(boxed) as *mut _;
336 pub unsafe extern "C" fn rs_ike_state_free(state: *mut std::os::raw::c_void) {
338 std::mem::drop(Box::from_raw(state as *mut IKEState));
342 pub unsafe extern "C" fn rs_ike_state_tx_free(state: *mut std::os::raw::c_void, tx_id: u64) {
343 let state = cast_pointer!(state, IKEState);
344 state.free_tx(tx_id);
348 pub unsafe extern "C" fn rs_ike_parse_request(
349 _flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void,
350 input: *const u8, input_len: u32, _data: *const std::os::raw::c_void, _flags: u8,
351 ) -> AppLayerResult {
352 let state = cast_pointer!(state, IKEState);
353 let buf = build_slice!(input, input_len as usize);
355 return state.handle_input(buf, Direction::ToServer);
359 pub unsafe extern "C" fn rs_ike_parse_response(
360 _flow: *const Flow, state: *mut std::os::raw::c_void, _pstate: *mut std::os::raw::c_void,
361 input: *const u8, input_len: u32, _data: *const std::os::raw::c_void, _flags: u8,
362 ) -> AppLayerResult {
363 let state = cast_pointer!(state, IKEState);
364 let buf = build_slice!(input, input_len as usize);
365 return state.handle_input(buf, Direction::ToClient);
369 pub unsafe extern "C" fn rs_ike_state_get_tx(
370 state: *mut std::os::raw::c_void, tx_id: u64,
371 ) -> *mut std::os::raw::c_void {
372 let state = cast_pointer!(state, IKEState);
373 match state.get_tx(tx_id) {
375 return tx as *const _ as *mut _;
378 return std::ptr::null_mut();
384 pub unsafe extern "C" fn rs_ike_state_get_tx_count(state: *mut std::os::raw::c_void) -> u64 {
385 let state = cast_pointer!(state, IKEState);
390 pub extern "C" fn rs_ike_state_progress_completion_status(_direction: u8) -> std::os::raw::c_int {
391 // This parser uses 1 to signal transaction completion status.
396 pub extern "C" fn rs_ike_tx_get_alstate_progress(
397 _tx: *mut std::os::raw::c_void, _direction: u8,
398 ) -> std::os::raw::c_int {
403 pub unsafe extern "C" fn rs_ike_tx_get_logged(
404 _state: *mut std::os::raw::c_void, tx: *mut std::os::raw::c_void,
406 let tx = cast_pointer!(tx, IKETransaction);
407 return tx.logged.get();
411 pub unsafe extern "C" fn rs_ike_tx_set_logged(
412 _state: *mut std::os::raw::c_void, tx: *mut std::os::raw::c_void, logged: u32,
414 let tx = cast_pointer!(tx, IKETransaction);
415 tx.logged.set(logged);
419 pub unsafe extern "C" fn rs_ike_state_get_events(
420 tx: *mut std::os::raw::c_void,
421 ) -> *mut core::AppLayerDecoderEvents {
422 let tx = cast_pointer!(tx, IKETransaction);
426 static mut ALPROTO_IKE : AppProto = ALPROTO_UNKNOWN;
429 pub unsafe extern "C" fn rs_ike_state_get_tx_iterator(
430 _ipproto: u8, _alproto: AppProto, state: *mut std::os::raw::c_void, min_tx_id: u64,
431 _max_tx_id: u64, istate: &mut u64,
432 ) -> applayer::AppLayerGetTxIterTuple {
433 let state = cast_pointer!(state, IKEState);
434 match state.tx_iterator(min_tx_id, istate) {
435 Some((tx, out_tx_id, has_next)) => {
436 let c_tx = tx as *const _ as *mut _;
437 let ires = applayer::AppLayerGetTxIterTuple::with_values(c_tx, out_tx_id, has_next);
441 return applayer::AppLayerGetTxIterTuple::not_found();
446 // Parser name as a C style string.
447 const PARSER_NAME: &'static [u8] = b"ike\0";
448 const PARSER_ALIAS: &'static [u8] = b"ikev2\0";
450 export_tx_data_get!(rs_ike_get_tx_data, IKETransaction);
453 pub unsafe extern "C" fn rs_ike_register_parser() {
454 let default_port = CString::new("500").unwrap();
455 let parser = RustParser {
456 name : PARSER_NAME.as_ptr() as *const std::os::raw::c_char,
457 default_port : default_port.as_ptr(),
458 ipproto : core::IPPROTO_UDP,
459 probe_ts : Some(rs_ike_probing_parser),
460 probe_tc : Some(rs_ike_probing_parser),
463 state_new : rs_ike_state_new,
464 state_free : rs_ike_state_free,
465 tx_free : rs_ike_state_tx_free,
466 parse_ts : rs_ike_parse_request,
467 parse_tc : rs_ike_parse_response,
468 get_tx_count : rs_ike_state_get_tx_count,
469 get_tx : rs_ike_state_get_tx,
472 tx_get_progress : rs_ike_tx_get_alstate_progress,
473 get_de_state : rs_ike_tx_get_detect_state,
474 set_de_state : rs_ike_tx_set_detect_state,
475 get_events : Some(rs_ike_state_get_events),
476 get_eventinfo : Some(IkeEvent::get_event_info),
477 get_eventinfo_byid : Some(IkeEvent::get_event_info_by_id),
478 localstorage_new : None,
479 localstorage_free : None,
481 get_tx_iterator : None,
482 get_tx_data : rs_ike_get_tx_data,
483 apply_tx_config : None,
484 flags : APP_LAYER_PARSER_OPT_UNIDIR_TXS,
488 let ip_proto_str = CString::new("udp").unwrap();
490 if AppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
491 let alproto = AppLayerRegisterProtocolDetection(&parser, 1);
492 ALPROTO_IKE = alproto;
493 if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
494 let _ = AppLayerRegisterParser(&parser, alproto);
497 AppLayerRegisterParserAlias(
498 PARSER_NAME.as_ptr() as *const std::os::raw::c_char,
499 PARSER_ALIAS.as_ptr() as *const std::os::raw::c_char,
501 SCLogDebug!("Rust IKE parser registered.");
503 SCLogDebug!("Protocol detector and parser disabled for IKE.");