]> git.ipfire.org Git - people/ms/suricata.git/blame - rust/src/ntp/ntp.rs
output/redis: Fix possible segv
[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;
83808bbd 26use std::ffi::{CStr,CString};
efe11dc3 27
13b73997 28use nom;
efe11dc3
PC
29
30#[repr(u32)]
31pub enum NTPEvent {
32 UnsolicitedResponse = 0,
33 MalformedData,
34 NotRequest,
35 NotResponse,
36}
37
7560b755
JL
38impl NTPEvent {
39 fn from_i32(value: i32) -> Option<NTPEvent> {
40 match value {
41 0 => Some(NTPEvent::UnsolicitedResponse),
42 1 => Some(NTPEvent::MalformedData),
43 2 => Some(NTPEvent::NotRequest),
44 3 => Some(NTPEvent::NotResponse),
45 _ => None,
46 }
47 }
48}
efe11dc3
PC
49
50pub struct NTPState {
51 /// List of transactions for this session
52 transactions: Vec<NTPTransaction>,
53
efe11dc3
PC
54 /// Events counter
55 events: u16,
56
57 /// tx counter for assigning incrementing id's to tx's
58 tx_id: u64,
59}
60
61#[derive(Debug)]
62pub struct NTPTransaction {
63 /// The NTP reference ID
64 pub xid: u32,
65
66 /// The internal transaction id
67 id: u64,
68
69 /// The detection engine state, if present
70 de_state: Option<*mut core::DetectEngineState>,
71
72 /// The events associated with this transaction
73 events: *mut core::AppLayerDecoderEvents,
74
cc1210c9 75 tx_data: applayer::AppLayerTxData,
efe11dc3
PC
76}
77
78
79
80impl NTPState {
81 pub fn new() -> NTPState {
82 NTPState{
83 transactions: Vec::new(),
efe11dc3
PC
84 events: 0,
85 tx_id: 0,
86 }
87 }
88}
89
90impl NTPState {
8a0549c4
PC
91 /// Parse an NTP request message
92 ///
44d3f264 93 /// Returns 0 if successful, or -1 on error
ae10a92b 94 fn parse(&mut self, i: &[u8], _direction: u8) -> i32 {
efe11dc3 95 match parse_ntp(i) {
13b73997 96 Ok((_,ref msg)) => {
efe11dc3 97 // SCLogDebug!("parse_ntp: {:?}",msg);
2d1c4420 98 if msg.mode == NtpMode::SymmetricActive || msg.mode == NtpMode::Client {
efe11dc3
PC
99 let mut tx = self.new_tx();
100 // use the reference id as identifier
101 tx.xid = msg.ref_id;
102 self.transactions.push(tx);
103 }
3bcf948a 104 0
efe11dc3 105 },
13b73997 106 Err(nom::Err::Incomplete(_)) => {
efe11dc3
PC
107 SCLogDebug!("Insufficient data while parsing NTP data");
108 self.set_event(NTPEvent::MalformedData);
109 -1
110 },
13b73997 111 Err(_) => {
efe11dc3
PC
112 SCLogDebug!("Error while parsing NTP data");
113 self.set_event(NTPEvent::MalformedData);
114 -1
115 },
116 }
117 }
118
119 fn free(&mut self) {
120 // All transactions are freed when the `transactions` object is freed.
121 // But let's be explicit
122 self.transactions.clear();
123 }
124
125 fn new_tx(&mut self) -> NTPTransaction {
126 self.tx_id += 1;
127 NTPTransaction::new(self.tx_id)
128 }
129
130 pub fn get_tx_by_id(&mut self, tx_id: u64) -> Option<&NTPTransaction> {
131 self.transactions.iter().find(|&tx| tx.id == tx_id + 1)
132 }
133
134 fn free_tx(&mut self, tx_id: u64) {
135 let tx = self.transactions.iter().position(|ref tx| tx.id == tx_id + 1);
136 debug_assert!(tx != None);
137 if let Some(idx) = tx {
138 let _ = self.transactions.remove(idx);
139 }
140 }
141
142 /// Set an event. The event is set on the most recent transaction.
143 pub fn set_event(&mut self, event: NTPEvent) {
144 if let Some(tx) = self.transactions.last_mut() {
145 let ev = event as u8;
146 core::sc_app_layer_decoder_events_set_event_raw(&mut tx.events, ev);
147 self.events += 1;
148 }
149 }
150}
151
152impl NTPTransaction {
153 pub fn new(id: u64) -> NTPTransaction {
154 NTPTransaction {
155 xid: 0,
156 id: id,
157 de_state: None,
158 events: std::ptr::null_mut(),
cc1210c9 159 tx_data: applayer::AppLayerTxData::new(),
efe11dc3
PC
160 }
161 }
162
163 fn free(&mut self) {
164 if self.events != std::ptr::null_mut() {
165 core::sc_app_layer_decoder_events_free_events(&mut self.events);
166 }
167 }
168}
169
170impl Drop for NTPTransaction {
171 fn drop(&mut self) {
172 self.free();
173 }
174}
175
efe11dc3
PC
176/// Returns *mut NTPState
177#[no_mangle]
547d6c2d 178pub 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
179 let state = NTPState::new();
180 let boxed = Box::new(state);
181 return unsafe{std::mem::transmute(boxed)};
182}
183
184/// Params:
185/// - state: *mut NTPState as void pointer
186#[no_mangle]
3f6624bf 187pub extern "C" fn rs_ntp_state_free(state: *mut std::os::raw::c_void) {
efe11dc3
PC
188 // Just unbox...
189 let mut ntp_state: Box<NTPState> = unsafe{std::mem::transmute(state)};
190 ntp_state.free();
191}
192
193#[no_mangle]
194pub 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]
210pub 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]
3f6624bf 226pub 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
PC
231 match state.get_tx_by_id(tx_id) {
232 Some(tx) => unsafe{std::mem::transmute(tx)},
233 None => std::ptr::null_mut(),
234 }
235}
236
237#[no_mangle]
3f6624bf 238pub 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]
3f6624bf 246pub 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
PC
261#[no_mangle]
262pub 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]
272pub 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
7560b755
JL
283#[no_mangle]
284pub extern "C" fn rs_ntp_state_get_event_info_by_id(event_id: std::os::raw::c_int,
285 event_name: *mut *const std::os::raw::c_char,
286 event_type: *mut core::AppLayerEventType)
287 -> i8
288{
289 if let Some(e) = NTPEvent::from_i32(event_id as i32) {
290 let estr = match e {
291 NTPEvent::UnsolicitedResponse => { "unsolicited_response\0" },
292 NTPEvent::MalformedData => { "malformed_data\0" },
293 NTPEvent::NotRequest => { "not_request\0" },
294 NTPEvent::NotResponse => { "not_response\0" },
295 };
296 unsafe{
297 *event_name = estr.as_ptr() as *const std::os::raw::c_char;
298 *event_type = core::APP_LAYER_EVENT_TYPE_TRANSACTION;
299 };
300 0
301 } else {
302 -1
303 }
304}
efe11dc3 305
efe11dc3 306#[no_mangle]
3f6624bf 307pub extern "C" fn rs_ntp_state_get_events(tx: *mut std::os::raw::c_void)
efe11dc3
PC
308 -> *mut core::AppLayerDecoderEvents
309{
d568e7fa
JL
310 let tx = cast_pointer!(tx, NTPTransaction);
311 return tx.events;
efe11dc3
PC
312}
313
314#[no_mangle]
3f6624bf
VJ
315pub extern "C" fn rs_ntp_state_get_event_info(event_name: *const std::os::raw::c_char,
316 event_id: *mut std::os::raw::c_int,
efe11dc3 317 event_type: *mut core::AppLayerEventType)
3f6624bf 318 -> std::os::raw::c_int
efe11dc3
PC
319{
320 if event_name == std::ptr::null() { return -1; }
321 let c_event_name: &CStr = unsafe { CStr::from_ptr(event_name) };
322 let event = match c_event_name.to_str() {
323 Ok(s) => {
324 match s {
325 "malformed_data" => NTPEvent::MalformedData as i32,
326 _ => -1, // unknown event
327 }
328 },
329 Err(_) => -1, // UTF-8 conversion failed
330 };
331 unsafe{
332 *event_type = core::APP_LAYER_EVENT_TYPE_TRANSACTION;
3f6624bf 333 *event_id = event as std::os::raw::c_int;
efe11dc3
PC
334 };
335 0
336}
8a0549c4 337
83808bbd
PC
338
339static mut ALPROTO_NTP : AppProto = ALPROTO_UNKNOWN;
340
341#[no_mangle]
422e4892
VJ
342pub extern "C" fn ntp_probing_parser(_flow: *const Flow,
343 _direction: u8,
344 input:*const u8, input_len: u32,
345 _rdir: *mut u8) -> AppProto
346{
83808bbd
PC
347 let slice: &[u8] = unsafe { std::slice::from_raw_parts(input as *mut u8, input_len as usize) };
348 let alproto = unsafe{ ALPROTO_NTP };
349 match parse_ntp(slice) {
13b73997 350 Ok((_, ref msg)) => {
83808bbd
PC
351 if msg.version == 3 || msg.version == 4 {
352 return alproto;
353 } else {
354 return unsafe{ALPROTO_FAILED};
355 }
356 },
13b73997 357 Err(nom::Err::Incomplete(_)) => {
83808bbd
PC
358 return ALPROTO_UNKNOWN;
359 },
13b73997 360 Err(_) => {
83808bbd
PC
361 return unsafe{ALPROTO_FAILED};
362 },
363 }
364}
365
cc1210c9
VJ
366export_tx_data_get!(rs_ntp_get_tx_data, NTPTransaction);
367
4b655558
PC
368const PARSER_NAME : &'static [u8] = b"ntp\0";
369
83808bbd
PC
370#[no_mangle]
371pub unsafe extern "C" fn rs_register_ntp_parser() {
83808bbd
PC
372 let default_port = CString::new("123").unwrap();
373 let parser = RustParser {
7560b755
JL
374 name : PARSER_NAME.as_ptr() as *const std::os::raw::c_char,
375 default_port : default_port.as_ptr(),
376 ipproto : core::IPPROTO_UDP,
66632465
PA
377 probe_ts : Some(ntp_probing_parser),
378 probe_tc : Some(ntp_probing_parser),
7560b755
JL
379 min_depth : 0,
380 max_depth : 16,
381 state_new : rs_ntp_state_new,
382 state_free : rs_ntp_state_free,
383 tx_free : rs_ntp_state_tx_free,
384 parse_ts : rs_ntp_parse_request,
385 parse_tc : rs_ntp_parse_response,
386 get_tx_count : rs_ntp_state_get_tx_count,
387 get_tx : rs_ntp_state_get_tx,
efc9a7a3
VJ
388 tx_comp_st_ts : 1,
389 tx_comp_st_tc : 1,
7560b755 390 tx_get_progress : rs_ntp_tx_get_alstate_progress,
7560b755
JL
391 get_de_state : rs_ntp_state_get_tx_detect_state,
392 set_de_state : rs_ntp_state_set_tx_detect_state,
393 get_events : Some(rs_ntp_state_get_events),
394 get_eventinfo : Some(rs_ntp_state_get_event_info),
395 get_eventinfo_byid : Some(rs_ntp_state_get_event_info_by_id),
396 localstorage_new : None,
397 localstorage_free : None,
7560b755
JL
398 get_files : None,
399 get_tx_iterator : None,
c94a5e63 400 get_tx_data : rs_ntp_get_tx_data,
5665fc83 401 apply_tx_config : None,
984d3c7f 402 flags : APP_LAYER_PARSER_OPT_UNIDIR_TXS,
4da0d9bd 403 truncate : None,
83808bbd
PC
404 };
405
406 let ip_proto_str = CString::new("udp").unwrap();
407 if AppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
408 let alproto = AppLayerRegisterProtocolDetection(&parser, 1);
409 // store the allocated ID for the probe function
410 ALPROTO_NTP = alproto;
411 if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
412 let _ = AppLayerRegisterParser(&parser, alproto);
413 }
414 } else {
7560b755 415 SCLogDebug!("Protocol detector and parser disabled for NTP.");
83808bbd
PC
416 }
417}
418
419
8a0549c4
PC
420#[cfg(test)]
421mod tests {
422 use super::NTPState;
423
424 #[test]
425 fn test_ntp_parse_request_valid() {
426 // A UDP NTP v4 request, in client mode
427 const REQ : &[u8] = &[
428 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
429 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
430 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
431 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
432 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
433 0x18, 0x57, 0xab, 0xc3, 0x4a, 0x5f, 0x2c, 0xfe
434 ];
435
436 let mut state = NTPState::new();
3bcf948a 437 assert_eq!(0, state.parse(REQ, 0));
8a0549c4
PC
438 }
439}