]> git.ipfire.org Git - people/ms/suricata.git/blame - rust/src/ntp/ntp.rs
ntp: add tx iterator
[people/ms/suricata.git] / rust / src / ntp / ntp.rs
CommitLineData
2f5834cd 1/* Copyright (C) 2017-2020 Open Information Security Foundation
efe11dc3
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
20extern crate ntp_parser;
21use self::ntp_parser::*;
42e5065a
JI
22use crate::core;
23use crate::core::{AppProto,Flow,ALPROTO_UNKNOWN,ALPROTO_FAILED};
2f5834cd 24use crate::applayer::{self, *};
efe11dc3 25use std;
92561837 26use std::ffi::CString;
efe11dc3 27
13b73997 28use nom;
efe11dc3 29
92561837 30#[derive(AppLayerEvent)]
efe11dc3 31pub enum NTPEvent {
92561837 32 UnsolicitedResponse ,
efe11dc3
PC
33 MalformedData,
34 NotRequest,
35 NotResponse,
36}
37
efe11dc3
PC
38pub struct NTPState {
39 /// List of transactions for this session
40 transactions: Vec<NTPTransaction>,
41
efe11dc3
PC
42 /// Events counter
43 events: u16,
44
45 /// tx counter for assigning incrementing id's to tx's
46 tx_id: u64,
47}
48
49#[derive(Debug)]
50pub struct NTPTransaction {
51 /// The NTP reference ID
52 pub xid: u32,
53
54 /// The internal transaction id
55 id: u64,
56
57 /// The detection engine state, if present
58 de_state: Option<*mut core::DetectEngineState>,
59
60 /// The events associated with this transaction
61 events: *mut core::AppLayerDecoderEvents,
62
cc1210c9 63 tx_data: applayer::AppLayerTxData,
efe11dc3
PC
64}
65
ef0c3519
JI
66impl Transaction for NTPTransaction {
67 fn id(&self) -> u64 {
68 self.id
69 }
70}
efe11dc3
PC
71
72impl NTPState {
73 pub fn new() -> NTPState {
74 NTPState{
75 transactions: Vec::new(),
efe11dc3
PC
76 events: 0,
77 tx_id: 0,
78 }
79 }
80}
81
ef0c3519
JI
82impl State<NTPTransaction> for NTPState {
83 fn get_transactions(&self) -> &[NTPTransaction] {
84 &self.transactions
85 }
86}
87
efe11dc3 88impl NTPState {
8a0549c4
PC
89 /// Parse an NTP request message
90 ///
44d3f264 91 /// Returns 0 if successful, or -1 on error
ae10a92b 92 fn parse(&mut self, i: &[u8], _direction: u8) -> i32 {
efe11dc3 93 match parse_ntp(i) {
13b73997 94 Ok((_,ref msg)) => {
efe11dc3 95 // SCLogDebug!("parse_ntp: {:?}",msg);
2d1c4420 96 if msg.mode == NtpMode::SymmetricActive || msg.mode == NtpMode::Client {
efe11dc3
PC
97 let mut tx = self.new_tx();
98 // use the reference id as identifier
99 tx.xid = msg.ref_id;
100 self.transactions.push(tx);
101 }
3bcf948a 102 0
efe11dc3 103 },
13b73997 104 Err(nom::Err::Incomplete(_)) => {
efe11dc3
PC
105 SCLogDebug!("Insufficient data while parsing NTP data");
106 self.set_event(NTPEvent::MalformedData);
107 -1
108 },
13b73997 109 Err(_) => {
efe11dc3
PC
110 SCLogDebug!("Error while parsing NTP data");
111 self.set_event(NTPEvent::MalformedData);
112 -1
113 },
114 }
115 }
116
117 fn free(&mut self) {
118 // All transactions are freed when the `transactions` object is freed.
119 // But let's be explicit
120 self.transactions.clear();
121 }
122
123 fn new_tx(&mut self) -> NTPTransaction {
124 self.tx_id += 1;
125 NTPTransaction::new(self.tx_id)
126 }
127
128 pub fn get_tx_by_id(&mut self, tx_id: u64) -> Option<&NTPTransaction> {
129 self.transactions.iter().find(|&tx| tx.id == tx_id + 1)
130 }
131
132 fn free_tx(&mut self, tx_id: u64) {
69cf5c9e 133 let tx = self.transactions.iter().position(|tx| tx.id == tx_id + 1);
efe11dc3
PC
134 debug_assert!(tx != None);
135 if let Some(idx) = tx {
136 let _ = self.transactions.remove(idx);
137 }
138 }
139
140 /// Set an event. The event is set on the most recent transaction.
141 pub fn set_event(&mut self, event: NTPEvent) {
142 if let Some(tx) = self.transactions.last_mut() {
143 let ev = event as u8;
144 core::sc_app_layer_decoder_events_set_event_raw(&mut tx.events, ev);
145 self.events += 1;
146 }
147 }
148}
149
150impl NTPTransaction {
151 pub fn new(id: u64) -> NTPTransaction {
152 NTPTransaction {
153 xid: 0,
154 id: id,
155 de_state: None,
156 events: std::ptr::null_mut(),
cc1210c9 157 tx_data: applayer::AppLayerTxData::new(),
efe11dc3
PC
158 }
159 }
160
161 fn free(&mut self) {
922a453d 162 if !self.events.is_null() {
efe11dc3
PC
163 core::sc_app_layer_decoder_events_free_events(&mut self.events);
164 }
3212fa7d
PA
165 if let Some(de_state) = self.de_state {
166 core::sc_detect_engine_state_free(de_state);
167 }
efe11dc3
PC
168 }
169}
170
171impl Drop for NTPTransaction {
172 fn drop(&mut self) {
173 self.free();
174 }
175}
176
efe11dc3
PC
177/// Returns *mut NTPState
178#[no_mangle]
547d6c2d 179pub extern "C" fn rs_ntp_state_new(_orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto) -> *mut std::os::raw::c_void {
efe11dc3
PC
180 let state = NTPState::new();
181 let boxed = Box::new(state);
53413f2d 182 return Box::into_raw(boxed) as *mut _;
efe11dc3
PC
183}
184
185/// Params:
186/// - state: *mut NTPState as void pointer
187#[no_mangle]
3f6624bf 188pub extern "C" fn rs_ntp_state_free(state: *mut std::os::raw::c_void) {
53413f2d 189 let mut ntp_state = unsafe{ Box::from_raw(state as *mut NTPState) };
efe11dc3
PC
190 ntp_state.free();
191}
192
193#[no_mangle]
363b5f99 194pub unsafe extern "C" fn rs_ntp_parse_request(_flow: *const core::Flow,
3f6624bf
VJ
195 state: *mut std::os::raw::c_void,
196 _pstate: *mut std::os::raw::c_void,
bf1bd407 197 input: *const u8,
efe11dc3 198 input_len: u32,
3f6624bf 199 _data: *const std::os::raw::c_void,
44d3f264 200 _flags: u8) -> AppLayerResult {
83808bbd
PC
201 let buf = build_slice!(input,input_len as usize);
202 let state = cast_pointer!(state,NTPState);
44d3f264
VJ
203 if state.parse(buf, 0) < 0 {
204 return AppLayerResult::err();
205 }
206 AppLayerResult::ok()
efe11dc3
PC
207}
208
209#[no_mangle]
363b5f99 210pub unsafe extern "C" fn rs_ntp_parse_response(_flow: *const core::Flow,
3f6624bf
VJ
211 state: *mut std::os::raw::c_void,
212 _pstate: *mut std::os::raw::c_void,
bf1bd407 213 input: *const u8,
efe11dc3 214 input_len: u32,
3f6624bf 215 _data: *const std::os::raw::c_void,
44d3f264 216 _flags: u8) -> AppLayerResult {
83808bbd
PC
217 let buf = build_slice!(input,input_len as usize);
218 let state = cast_pointer!(state,NTPState);
44d3f264
VJ
219 if state.parse(buf, 1) < 0 {
220 return AppLayerResult::err();
221 }
222 AppLayerResult::ok()
efe11dc3
PC
223}
224
225#[no_mangle]
363b5f99 226pub unsafe extern "C" fn rs_ntp_state_get_tx(state: *mut std::os::raw::c_void,
bf1bd407 227 tx_id: u64)
3f6624bf 228 -> *mut std::os::raw::c_void
efe11dc3 229{
83808bbd 230 let state = cast_pointer!(state,NTPState);
efe11dc3 231 match state.get_tx_by_id(tx_id) {
53413f2d 232 Some(tx) => tx as *const _ as *mut _,
efe11dc3
PC
233 None => std::ptr::null_mut(),
234 }
235}
236
237#[no_mangle]
363b5f99 238pub unsafe extern "C" fn rs_ntp_state_get_tx_count(state: *mut std::os::raw::c_void)
bf1bd407 239 -> u64
efe11dc3 240{
83808bbd 241 let state = cast_pointer!(state,NTPState);
efe11dc3
PC
242 state.tx_id
243}
244
245#[no_mangle]
363b5f99 246pub unsafe extern "C" fn rs_ntp_state_tx_free(state: *mut std::os::raw::c_void,
bf1bd407 247 tx_id: u64)
efe11dc3 248{
83808bbd 249 let state = cast_pointer!(state,NTPState);
efe11dc3
PC
250 state.free_tx(tx_id);
251}
252
efe11dc3 253#[no_mangle]
3f6624bf 254pub extern "C" fn rs_ntp_tx_get_alstate_progress(_tx: *mut std::os::raw::c_void,
bf1bd407 255 _direction: u8)
3f6624bf 256 -> std::os::raw::c_int
efe11dc3
PC
257{
258 1
259}
260
efe11dc3 261#[no_mangle]
363b5f99 262pub unsafe extern "C" fn rs_ntp_state_set_tx_detect_state(
3f6624bf
VJ
263 tx: *mut std::os::raw::c_void,
264 de_state: &mut core::DetectEngineState) -> std::os::raw::c_int
efe11dc3 265{
83808bbd 266 let tx = cast_pointer!(tx,NTPTransaction);
efe11dc3 267 tx.de_state = Some(de_state);
83808bbd 268 0
efe11dc3
PC
269}
270
271#[no_mangle]
363b5f99 272pub unsafe extern "C" fn rs_ntp_state_get_tx_detect_state(
3f6624bf 273 tx: *mut std::os::raw::c_void)
efe11dc3
PC
274 -> *mut core::DetectEngineState
275{
83808bbd 276 let tx = cast_pointer!(tx,NTPTransaction);
efe11dc3
PC
277 match tx.de_state {
278 Some(ds) => ds,
279 None => std::ptr::null_mut(),
280 }
281}
282
efe11dc3 283#[no_mangle]
363b5f99 284pub unsafe extern "C" fn rs_ntp_state_get_events(tx: *mut std::os::raw::c_void)
efe11dc3
PC
285 -> *mut core::AppLayerDecoderEvents
286{
d568e7fa
JL
287 let tx = cast_pointer!(tx, NTPTransaction);
288 return tx.events;
efe11dc3
PC
289}
290
83808bbd
PC
291static mut ALPROTO_NTP : AppProto = ALPROTO_UNKNOWN;
292
293#[no_mangle]
422e4892
VJ
294pub extern "C" fn ntp_probing_parser(_flow: *const Flow,
295 _direction: u8,
296 input:*const u8, input_len: u32,
297 _rdir: *mut u8) -> AppProto
298{
83808bbd
PC
299 let slice: &[u8] = unsafe { std::slice::from_raw_parts(input as *mut u8, input_len as usize) };
300 let alproto = unsafe{ ALPROTO_NTP };
301 match parse_ntp(slice) {
13b73997 302 Ok((_, ref msg)) => {
83808bbd
PC
303 if msg.version == 3 || msg.version == 4 {
304 return alproto;
305 } else {
306 return unsafe{ALPROTO_FAILED};
307 }
308 },
13b73997 309 Err(nom::Err::Incomplete(_)) => {
83808bbd
PC
310 return ALPROTO_UNKNOWN;
311 },
13b73997 312 Err(_) => {
83808bbd
PC
313 return unsafe{ALPROTO_FAILED};
314 },
315 }
316}
317
cc1210c9
VJ
318export_tx_data_get!(rs_ntp_get_tx_data, NTPTransaction);
319
4b655558
PC
320const PARSER_NAME : &'static [u8] = b"ntp\0";
321
83808bbd
PC
322#[no_mangle]
323pub unsafe extern "C" fn rs_register_ntp_parser() {
83808bbd
PC
324 let default_port = CString::new("123").unwrap();
325 let parser = RustParser {
7560b755
JL
326 name : PARSER_NAME.as_ptr() as *const std::os::raw::c_char,
327 default_port : default_port.as_ptr(),
328 ipproto : core::IPPROTO_UDP,
66632465
PA
329 probe_ts : Some(ntp_probing_parser),
330 probe_tc : Some(ntp_probing_parser),
7560b755
JL
331 min_depth : 0,
332 max_depth : 16,
333 state_new : rs_ntp_state_new,
334 state_free : rs_ntp_state_free,
335 tx_free : rs_ntp_state_tx_free,
336 parse_ts : rs_ntp_parse_request,
337 parse_tc : rs_ntp_parse_response,
338 get_tx_count : rs_ntp_state_get_tx_count,
339 get_tx : rs_ntp_state_get_tx,
efc9a7a3
VJ
340 tx_comp_st_ts : 1,
341 tx_comp_st_tc : 1,
7560b755 342 tx_get_progress : rs_ntp_tx_get_alstate_progress,
7560b755
JL
343 get_de_state : rs_ntp_state_get_tx_detect_state,
344 set_de_state : rs_ntp_state_set_tx_detect_state,
345 get_events : Some(rs_ntp_state_get_events),
92561837
JI
346 get_eventinfo : Some(NTPEvent::get_event_info),
347 get_eventinfo_byid : Some(NTPEvent::get_event_info_by_id),
7560b755
JL
348 localstorage_new : None,
349 localstorage_free : None,
7560b755 350 get_files : None,
ef0c3519 351 get_tx_iterator : Some(applayer::state_get_tx_iterator::<NTPState, NTPTransaction>),
c94a5e63 352 get_tx_data : rs_ntp_get_tx_data,
5665fc83 353 apply_tx_config : None,
984d3c7f 354 flags : APP_LAYER_PARSER_OPT_UNIDIR_TXS,
4da0d9bd 355 truncate : None,
83808bbd
PC
356 };
357
358 let ip_proto_str = CString::new("udp").unwrap();
359 if AppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
360 let alproto = AppLayerRegisterProtocolDetection(&parser, 1);
361 // store the allocated ID for the probe function
362 ALPROTO_NTP = alproto;
363 if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
364 let _ = AppLayerRegisterParser(&parser, alproto);
365 }
366 } else {
7560b755 367 SCLogDebug!("Protocol detector and parser disabled for NTP.");
83808bbd
PC
368 }
369}
370
371
8a0549c4
PC
372#[cfg(test)]
373mod tests {
374 use super::NTPState;
375
376 #[test]
377 fn test_ntp_parse_request_valid() {
378 // A UDP NTP v4 request, in client mode
379 const REQ : &[u8] = &[
380 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
381 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
382 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
383 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
384 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
385 0x18, 0x57, 0xab, 0xc3, 0x4a, 0x5f, 0x2c, 0xfe
386 ];
387
388 let mut state = NTPState::new();
3bcf948a 389 assert_eq!(0, state.parse(REQ, 0));
8a0549c4
PC
390 }
391}