1 /* Copyright (C) 2017-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 // written by Pierre Chifflier <chifflier@wzdftpd.net>
20 extern crate ntp_parser;
21 use self::ntp_parser::*;
23 use crate::core::{AppProto,Flow,ALPROTO_UNKNOWN,ALPROTO_FAILED};
24 use crate::applayer::{self, *};
26 use std::ffi::CString;
30 #[derive(AppLayerEvent)]
39 /// List of transactions for this session
40 transactions: Vec<NTPTransaction>,
45 /// tx counter for assigning incrementing id's to tx's
50 pub struct NTPTransaction {
51 /// The NTP reference ID
54 /// The internal transaction id
57 tx_data: applayer::AppLayerTxData,
60 impl Transaction for NTPTransaction {
67 pub fn new() -> NTPState {
69 transactions: Vec::new(),
76 impl State<NTPTransaction> for NTPState {
77 fn get_transactions(&self) -> &[NTPTransaction] {
83 /// Parse an NTP request message
85 /// Returns 0 if successful, or -1 on error
86 fn parse(&mut self, i: &[u8], _direction: u8) -> i32 {
89 // SCLogDebug!("parse_ntp: {:?}",msg);
90 if msg.mode == NtpMode::SymmetricActive || msg.mode == NtpMode::Client {
91 let mut tx = self.new_tx();
92 // use the reference id as identifier
94 self.transactions.push(tx);
98 Err(nom::Err::Incomplete(_)) => {
99 SCLogDebug!("Insufficient data while parsing NTP data");
100 self.set_event(NTPEvent::MalformedData);
104 SCLogDebug!("Error while parsing NTP data");
105 self.set_event(NTPEvent::MalformedData);
112 // All transactions are freed when the `transactions` object is freed.
113 // But let's be explicit
114 self.transactions.clear();
117 fn new_tx(&mut self) -> NTPTransaction {
119 NTPTransaction::new(self.tx_id)
122 pub fn get_tx_by_id(&mut self, tx_id: u64) -> Option<&NTPTransaction> {
123 self.transactions.iter().find(|&tx| tx.id == tx_id + 1)
126 fn free_tx(&mut self, tx_id: u64) {
127 let tx = self.transactions.iter().position(|tx| tx.id == tx_id + 1);
128 debug_assert!(tx != None);
129 if let Some(idx) = tx {
130 let _ = self.transactions.remove(idx);
134 /// Set an event. The event is set on the most recent transaction.
135 pub fn set_event(&mut self, event: NTPEvent) {
136 if let Some(tx) = self.transactions.last_mut() {
137 tx.tx_data.set_event(event as u8);
143 impl NTPTransaction {
144 pub fn new(id: u64) -> NTPTransaction {
148 tx_data: applayer::AppLayerTxData::new(),
153 /// Returns *mut NTPState
155 pub extern "C" fn rs_ntp_state_new(_orig_state: *mut std::os::raw::c_void, _orig_proto: AppProto) -> *mut std::os::raw::c_void {
156 let state = NTPState::new();
157 let boxed = Box::new(state);
158 return Box::into_raw(boxed) as *mut _;
162 /// - state: *mut NTPState as void pointer
164 pub extern "C" fn rs_ntp_state_free(state: *mut std::os::raw::c_void) {
165 let mut ntp_state = unsafe{ Box::from_raw(state as *mut NTPState) };
170 pub unsafe extern "C" fn rs_ntp_parse_request(_flow: *const core::Flow,
171 state: *mut std::os::raw::c_void,
172 _pstate: *mut std::os::raw::c_void,
175 _data: *const std::os::raw::c_void,
176 _flags: u8) -> AppLayerResult {
177 let buf = build_slice!(input,input_len as usize);
178 let state = cast_pointer!(state,NTPState);
179 if state.parse(buf, 0) < 0 {
180 return AppLayerResult::err();
186 pub unsafe extern "C" fn rs_ntp_parse_response(_flow: *const core::Flow,
187 state: *mut std::os::raw::c_void,
188 _pstate: *mut std::os::raw::c_void,
191 _data: *const std::os::raw::c_void,
192 _flags: u8) -> AppLayerResult {
193 let buf = build_slice!(input,input_len as usize);
194 let state = cast_pointer!(state,NTPState);
195 if state.parse(buf, 1) < 0 {
196 return AppLayerResult::err();
202 pub unsafe extern "C" fn rs_ntp_state_get_tx(state: *mut std::os::raw::c_void,
204 -> *mut std::os::raw::c_void
206 let state = cast_pointer!(state,NTPState);
207 match state.get_tx_by_id(tx_id) {
208 Some(tx) => tx as *const _ as *mut _,
209 None => std::ptr::null_mut(),
214 pub unsafe extern "C" fn rs_ntp_state_get_tx_count(state: *mut std::os::raw::c_void)
217 let state = cast_pointer!(state,NTPState);
222 pub unsafe extern "C" fn rs_ntp_state_tx_free(state: *mut std::os::raw::c_void,
225 let state = cast_pointer!(state,NTPState);
226 state.free_tx(tx_id);
230 pub extern "C" fn rs_ntp_tx_get_alstate_progress(_tx: *mut std::os::raw::c_void,
232 -> std::os::raw::c_int
237 static mut ALPROTO_NTP : AppProto = ALPROTO_UNKNOWN;
240 pub extern "C" fn ntp_probing_parser(_flow: *const Flow,
242 input:*const u8, input_len: u32,
243 _rdir: *mut u8) -> AppProto
245 let slice: &[u8] = unsafe { std::slice::from_raw_parts(input as *mut u8, input_len as usize) };
246 let alproto = unsafe{ ALPROTO_NTP };
247 match parse_ntp(slice) {
248 Ok((_, ref msg)) => {
249 if msg.version == 3 || msg.version == 4 {
252 return unsafe{ALPROTO_FAILED};
255 Err(nom::Err::Incomplete(_)) => {
256 return ALPROTO_UNKNOWN;
259 return unsafe{ALPROTO_FAILED};
264 export_tx_data_get!(rs_ntp_get_tx_data, NTPTransaction);
266 const PARSER_NAME : &'static [u8] = b"ntp\0";
269 pub unsafe extern "C" fn rs_register_ntp_parser() {
270 let default_port = CString::new("123").unwrap();
271 let parser = RustParser {
272 name : PARSER_NAME.as_ptr() as *const std::os::raw::c_char,
273 default_port : default_port.as_ptr(),
274 ipproto : core::IPPROTO_UDP,
275 probe_ts : Some(ntp_probing_parser),
276 probe_tc : Some(ntp_probing_parser),
279 state_new : rs_ntp_state_new,
280 state_free : rs_ntp_state_free,
281 tx_free : rs_ntp_state_tx_free,
282 parse_ts : rs_ntp_parse_request,
283 parse_tc : rs_ntp_parse_response,
284 get_tx_count : rs_ntp_state_get_tx_count,
285 get_tx : rs_ntp_state_get_tx,
288 tx_get_progress : rs_ntp_tx_get_alstate_progress,
289 get_eventinfo : Some(NTPEvent::get_event_info),
290 get_eventinfo_byid : Some(NTPEvent::get_event_info_by_id),
291 localstorage_new : None,
292 localstorage_free : None,
294 get_tx_iterator : Some(applayer::state_get_tx_iterator::<NTPState, NTPTransaction>),
295 get_tx_data : rs_ntp_get_tx_data,
296 apply_tx_config : None,
297 flags : APP_LAYER_PARSER_OPT_UNIDIR_TXS,
301 let ip_proto_str = CString::new("udp").unwrap();
302 if AppLayerProtoDetectConfProtoDetectionEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
303 let alproto = AppLayerRegisterProtocolDetection(&parser, 1);
304 // store the allocated ID for the probe function
305 ALPROTO_NTP = alproto;
306 if AppLayerParserConfParserEnabled(ip_proto_str.as_ptr(), parser.name) != 0 {
307 let _ = AppLayerRegisterParser(&parser, alproto);
310 SCLogDebug!("Protocol detector and parser disabled for NTP.");
320 fn test_ntp_parse_request_valid() {
321 // A UDP NTP v4 request, in client mode
322 const REQ : &[u8] = &[
323 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
324 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
325 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
326 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
327 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
328 0x18, 0x57, 0xab, 0xc3, 0x4a, 0x5f, 0x2c, 0xfe
331 let mut state = NTPState::new();
332 assert_eq!(0, state.parse(REQ, 0));