]> git.ipfire.org Git - people/ms/suricata.git/blame - rust/src/ntp/ntp.rs
detect/analyzer: Add missing http_accept_enc handling
[people/ms/suricata.git] / rust / src / ntp / ntp.rs
CommitLineData
efe11dc3
PC
1/* Copyright (C) 2017 Open Information Security Foundation
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::*;
22use core;
f5b27ae7 23use core::{AppProto,Flow,ALPROTO_UNKNOWN,ALPROTO_FAILED};
efe11dc3 24use applayer;
83808bbd 25use parser::*;
efe11dc3 26use std;
83808bbd 27use std::ffi::{CStr,CString};
efe11dc3
PC
28
29use log::*;
30
13b73997 31use nom;
efe11dc3
PC
32
33#[repr(u32)]
34pub enum NTPEvent {
35 UnsolicitedResponse = 0,
36 MalformedData,
37 NotRequest,
38 NotResponse,
39}
40
7560b755
JL
41impl NTPEvent {
42 fn from_i32(value: i32) -> Option<NTPEvent> {
43 match value {
44 0 => Some(NTPEvent::UnsolicitedResponse),
45 1 => Some(NTPEvent::MalformedData),
46 2 => Some(NTPEvent::NotRequest),
47 3 => Some(NTPEvent::NotResponse),
48 _ => None,
49 }
50 }
51}
efe11dc3
PC
52
53pub struct NTPState {
54 /// List of transactions for this session
55 transactions: Vec<NTPTransaction>,
56
efe11dc3
PC
57 /// Events counter
58 events: u16,
59
60 /// tx counter for assigning incrementing id's to tx's
61 tx_id: u64,
62}
63
64#[derive(Debug)]
65pub struct NTPTransaction {
66 /// The NTP reference ID
67 pub xid: u32,
68
69 /// The internal transaction id
70 id: u64,
71
72 /// The detection engine state, if present
73 de_state: Option<*mut core::DetectEngineState>,
74
75 /// The events associated with this transaction
76 events: *mut core::AppLayerDecoderEvents,
77
78 logged: applayer::LoggerFlags,
79}
80
81
82
83impl NTPState {
84 pub fn new() -> NTPState {
85 NTPState{
86 transactions: Vec::new(),
efe11dc3
PC
87 events: 0,
88 tx_id: 0,
89 }
90 }
91}
92
93impl NTPState {
8a0549c4
PC
94 /// Parse an NTP request message
95 ///
96 /// Returns The number of messages parsed, or -1 on error
ae10a92b 97 fn parse(&mut self, i: &[u8], _direction: u8) -> i32 {
efe11dc3 98 match parse_ntp(i) {
13b73997 99 Ok((_,ref msg)) => {
efe11dc3 100 // SCLogDebug!("parse_ntp: {:?}",msg);
2d1c4420 101 if msg.mode == NtpMode::SymmetricActive || msg.mode == NtpMode::Client {
efe11dc3
PC
102 let mut tx = self.new_tx();
103 // use the reference id as identifier
104 tx.xid = msg.ref_id;
105 self.transactions.push(tx);
106 }
8a0549c4 107 1
efe11dc3 108 },
13b73997 109 Err(nom::Err::Incomplete(_)) => {
efe11dc3
PC
110 SCLogDebug!("Insufficient data while parsing NTP data");
111 self.set_event(NTPEvent::MalformedData);
112 -1
113 },
13b73997 114 Err(_) => {
efe11dc3
PC
115 SCLogDebug!("Error while parsing NTP data");
116 self.set_event(NTPEvent::MalformedData);
117 -1
118 },
119 }
120 }
121
122 fn free(&mut self) {
123 // All transactions are freed when the `transactions` object is freed.
124 // But let's be explicit
125 self.transactions.clear();
126 }
127
128 fn new_tx(&mut self) -> NTPTransaction {
129 self.tx_id += 1;
130 NTPTransaction::new(self.tx_id)
131 }
132
133 pub fn get_tx_by_id(&mut self, tx_id: u64) -> Option<&NTPTransaction> {
134 self.transactions.iter().find(|&tx| tx.id == tx_id + 1)
135 }
136
137 fn free_tx(&mut self, tx_id: u64) {
138 let tx = self.transactions.iter().position(|ref tx| tx.id == tx_id + 1);
139 debug_assert!(tx != None);
140 if let Some(idx) = tx {
141 let _ = self.transactions.remove(idx);
142 }
143 }
144
145 /// Set an event. The event is set on the most recent transaction.
146 pub fn set_event(&mut self, event: NTPEvent) {
147 if let Some(tx) = self.transactions.last_mut() {
148 let ev = event as u8;
149 core::sc_app_layer_decoder_events_set_event_raw(&mut tx.events, ev);
150 self.events += 1;
151 }
152 }
153}
154
155impl NTPTransaction {
156 pub fn new(id: u64) -> NTPTransaction {
157 NTPTransaction {
158 xid: 0,
159 id: id,
160 de_state: None,
161 events: std::ptr::null_mut(),
162 logged: applayer::LoggerFlags::new(),
163 }
164 }
165
166 fn free(&mut self) {
167 if self.events != std::ptr::null_mut() {
168 core::sc_app_layer_decoder_events_free_events(&mut self.events);
169 }
170 }
171}
172
173impl Drop for NTPTransaction {
174 fn drop(&mut self) {
175 self.free();
176 }
177}
178
179
efe11dc3
PC
180
181
182
183
184/// Returns *mut NTPState
185#[no_mangle]
3f6624bf 186pub extern "C" fn rs_ntp_state_new() -> *mut std::os::raw::c_void {
efe11dc3
PC
187 let state = NTPState::new();
188 let boxed = Box::new(state);
189 return unsafe{std::mem::transmute(boxed)};
190}
191
192/// Params:
193/// - state: *mut NTPState as void pointer
194#[no_mangle]
3f6624bf 195pub extern "C" fn rs_ntp_state_free(state: *mut std::os::raw::c_void) {
efe11dc3
PC
196 // Just unbox...
197 let mut ntp_state: Box<NTPState> = unsafe{std::mem::transmute(state)};
198 ntp_state.free();
199}
200
201#[no_mangle]
202pub extern "C" fn rs_ntp_parse_request(_flow: *const core::Flow,
3f6624bf
VJ
203 state: *mut std::os::raw::c_void,
204 _pstate: *mut std::os::raw::c_void,
bf1bd407 205 input: *const u8,
efe11dc3 206 input_len: u32,
3f6624bf 207 _data: *const std::os::raw::c_void,
ae10a92b 208 _flags: u8) -> i32 {
83808bbd
PC
209 let buf = build_slice!(input,input_len as usize);
210 let state = cast_pointer!(state,NTPState);
efe11dc3
PC
211 state.parse(buf, 0)
212}
213
214#[no_mangle]
215pub extern "C" fn rs_ntp_parse_response(_flow: *const core::Flow,
3f6624bf
VJ
216 state: *mut std::os::raw::c_void,
217 _pstate: *mut std::os::raw::c_void,
bf1bd407 218 input: *const u8,
efe11dc3 219 input_len: u32,
3f6624bf 220 _data: *const std::os::raw::c_void,
ae10a92b 221 _flags: u8) -> i32 {
83808bbd
PC
222 let buf = build_slice!(input,input_len as usize);
223 let state = cast_pointer!(state,NTPState);
efe11dc3
PC
224 state.parse(buf, 1)
225}
226
227#[no_mangle]
3f6624bf 228pub extern "C" fn rs_ntp_state_get_tx(state: *mut std::os::raw::c_void,
bf1bd407 229 tx_id: u64)
3f6624bf 230 -> *mut std::os::raw::c_void
efe11dc3 231{
83808bbd 232 let state = cast_pointer!(state,NTPState);
efe11dc3
PC
233 match state.get_tx_by_id(tx_id) {
234 Some(tx) => unsafe{std::mem::transmute(tx)},
235 None => std::ptr::null_mut(),
236 }
237}
238
239#[no_mangle]
3f6624bf 240pub extern "C" fn rs_ntp_state_get_tx_count(state: *mut std::os::raw::c_void)
bf1bd407 241 -> u64
efe11dc3 242{
83808bbd 243 let state = cast_pointer!(state,NTPState);
efe11dc3
PC
244 state.tx_id
245}
246
247#[no_mangle]
3f6624bf 248pub extern "C" fn rs_ntp_state_tx_free(state: *mut std::os::raw::c_void,
bf1bd407 249 tx_id: u64)
efe11dc3 250{
83808bbd 251 let state = cast_pointer!(state,NTPState);
efe11dc3
PC
252 state.free_tx(tx_id);
253}
254
255#[no_mangle]
256pub extern "C" fn rs_ntp_state_progress_completion_status(
bf1bd407 257 _direction: u8)
3f6624bf 258 -> std::os::raw::c_int
efe11dc3
PC
259{
260 return 1;
261}
262
263#[no_mangle]
3f6624bf 264pub extern "C" fn rs_ntp_tx_get_alstate_progress(_tx: *mut std::os::raw::c_void,
bf1bd407 265 _direction: u8)
3f6624bf 266 -> std::os::raw::c_int
efe11dc3
PC
267{
268 1
269}
270
271
272
273
274
275#[no_mangle]
276pub extern "C" fn rs_ntp_tx_set_logged(_state: &mut NTPState,
277 tx: &mut NTPTransaction,
bf1bd407 278 logged: u32)
efe11dc3 279{
5c6868b3 280 tx.logged.set(logged);
efe11dc3
PC
281}
282
283#[no_mangle]
284pub extern "C" fn rs_ntp_tx_get_logged(_state: &mut NTPState,
5c6868b3
PC
285 tx: &mut NTPTransaction)
286 -> u32
efe11dc3 287{
5c6868b3 288 return tx.logged.get();
efe11dc3
PC
289}
290
291
292#[no_mangle]
293pub extern "C" fn rs_ntp_state_set_tx_detect_state(
3f6624bf
VJ
294 tx: *mut std::os::raw::c_void,
295 de_state: &mut core::DetectEngineState) -> std::os::raw::c_int
efe11dc3 296{
83808bbd 297 let tx = cast_pointer!(tx,NTPTransaction);
efe11dc3 298 tx.de_state = Some(de_state);
83808bbd 299 0
efe11dc3
PC
300}
301
302#[no_mangle]
303pub extern "C" fn rs_ntp_state_get_tx_detect_state(
3f6624bf 304 tx: *mut std::os::raw::c_void)
efe11dc3
PC
305 -> *mut core::DetectEngineState
306{
83808bbd 307 let tx = cast_pointer!(tx,NTPTransaction);
efe11dc3
PC
308 match tx.de_state {
309 Some(ds) => ds,
310 None => std::ptr::null_mut(),
311 }
312}
313
7560b755
JL
314#[no_mangle]
315pub extern "C" fn rs_ntp_state_get_event_info_by_id(event_id: std::os::raw::c_int,
316 event_name: *mut *const std::os::raw::c_char,
317 event_type: *mut core::AppLayerEventType)
318 -> i8
319{
320 if let Some(e) = NTPEvent::from_i32(event_id as i32) {
321 let estr = match e {
322 NTPEvent::UnsolicitedResponse => { "unsolicited_response\0" },
323 NTPEvent::MalformedData => { "malformed_data\0" },
324 NTPEvent::NotRequest => { "not_request\0" },
325 NTPEvent::NotResponse => { "not_response\0" },
326 };
327 unsafe{
328 *event_name = estr.as_ptr() as *const std::os::raw::c_char;
329 *event_type = core::APP_LAYER_EVENT_TYPE_TRANSACTION;
330 };
331 0
332 } else {
333 -1
334 }
335}
efe11dc3 336
efe11dc3 337#[no_mangle]
3f6624bf 338pub extern "C" fn rs_ntp_state_get_events(tx: *mut std::os::raw::c_void)
efe11dc3
PC
339 -> *mut core::AppLayerDecoderEvents
340{
d568e7fa
JL
341 let tx = cast_pointer!(tx, NTPTransaction);
342 return tx.events;
efe11dc3
PC
343}
344
345#[no_mangle]
3f6624bf
VJ
346pub extern "C" fn rs_ntp_state_get_event_info(event_name: *const std::os::raw::c_char,
347 event_id: *mut std::os::raw::c_int,
efe11dc3 348 event_type: *mut core::AppLayerEventType)
3f6624bf 349 -> std::os::raw::c_int
efe11dc3
PC
350{
351 if event_name == std::ptr::null() { return -1; }
352 let c_event_name: &CStr = unsafe { CStr::from_ptr(event_name) };
353 let event = match c_event_name.to_str() {
354 Ok(s) => {
355 match s {
356 "malformed_data" => NTPEvent::MalformedData as i32,
357 _ => -1, // unknown event
358 }
359 },
360 Err(_) => -1, // UTF-8 conversion failed
361 };
362 unsafe{
363 *event_type = core::APP_LAYER_EVENT_TYPE_TRANSACTION;
3f6624bf 364 *event_id = event as std::os::raw::c_int;
efe11dc3
PC
365 };
366 0
367}
8a0549c4 368
83808bbd
PC
369
370static mut ALPROTO_NTP : AppProto = ALPROTO_UNKNOWN;
371
372#[no_mangle]
422e4892
VJ
373pub extern "C" fn ntp_probing_parser(_flow: *const Flow,
374 _direction: u8,
375 input:*const u8, input_len: u32,
376 _rdir: *mut u8) -> AppProto
377{
83808bbd
PC
378 let slice: &[u8] = unsafe { std::slice::from_raw_parts(input as *mut u8, input_len as usize) };
379 let alproto = unsafe{ ALPROTO_NTP };
380 match parse_ntp(slice) {
13b73997 381 Ok((_, ref msg)) => {
83808bbd
PC
382 if msg.version == 3 || msg.version == 4 {
383 return alproto;
384 } else {
385 return unsafe{ALPROTO_FAILED};
386 }
387 },
13b73997 388 Err(nom::Err::Incomplete(_)) => {
83808bbd
PC
389 return ALPROTO_UNKNOWN;
390 },
13b73997 391 Err(_) => {
83808bbd
PC
392 return unsafe{ALPROTO_FAILED};
393 },
394 }
395}
396
4b655558
PC
397const PARSER_NAME : &'static [u8] = b"ntp\0";
398
83808bbd
PC
399#[no_mangle]
400pub unsafe extern "C" fn rs_register_ntp_parser() {
83808bbd
PC
401 let default_port = CString::new("123").unwrap();
402 let parser = RustParser {
7560b755
JL
403 name : PARSER_NAME.as_ptr() as *const std::os::raw::c_char,
404 default_port : default_port.as_ptr(),
405 ipproto : core::IPPROTO_UDP,
406 probe_ts : ntp_probing_parser,
407 probe_tc : ntp_probing_parser,
408 min_depth : 0,
409 max_depth : 16,
410 state_new : rs_ntp_state_new,
411 state_free : rs_ntp_state_free,
412 tx_free : rs_ntp_state_tx_free,
413 parse_ts : rs_ntp_parse_request,
414 parse_tc : rs_ntp_parse_response,
415 get_tx_count : rs_ntp_state_get_tx_count,
416 get_tx : rs_ntp_state_get_tx,
417 tx_get_comp_st : rs_ntp_state_progress_completion_status,
418 tx_get_progress : rs_ntp_tx_get_alstate_progress,
419 get_tx_logged : None,
420 set_tx_logged : None,
421 get_de_state : rs_ntp_state_get_tx_detect_state,
422 set_de_state : rs_ntp_state_set_tx_detect_state,
423 get_events : Some(rs_ntp_state_get_events),
424 get_eventinfo : Some(rs_ntp_state_get_event_info),
425 get_eventinfo_byid : Some(rs_ntp_state_get_event_info_by_id),
426 localstorage_new : None,
427 localstorage_free : None,
428 get_tx_mpm_id : None,
429 set_tx_mpm_id : None,
430 get_files : None,
431 get_tx_iterator : None,
83808bbd
PC
432 };
433
434 let ip_proto_str = CString::new("udp").unwrap();
435 if AppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
436 let alproto = AppLayerRegisterProtocolDetection(&parser, 1);
437 // store the allocated ID for the probe function
438 ALPROTO_NTP = alproto;
439 if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
440 let _ = AppLayerRegisterParser(&parser, alproto);
441 }
442 } else {
7560b755 443 SCLogDebug!("Protocol detector and parser disabled for NTP.");
83808bbd
PC
444 }
445}
446
447
8a0549c4
PC
448#[cfg(test)]
449mod tests {
450 use super::NTPState;
451
452 #[test]
453 fn test_ntp_parse_request_valid() {
454 // A UDP NTP v4 request, in client mode
455 const REQ : &[u8] = &[
456 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
457 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
458 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
459 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
460 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
461 0x18, 0x57, 0xab, 0xc3, 0x4a, 0x5f, 0x2c, 0xfe
462 ];
463
464 let mut state = NTPState::new();
465 assert_eq!(1, state.parse(REQ, 0));
466 }
467}