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