]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
Add NTP parser (rust-experimental)
authorPierre Chifflier <chifflier@wzdftpd.net>
Mon, 19 Jun 2017 11:19:23 +0000 (13:19 +0200)
committerVictor Julien <victor@inliniac.net>
Tue, 27 Jun 2017 14:52:23 +0000 (16:52 +0200)
14 files changed:
rust/Cargo.toml.in
rust/gen-c-headers.py
rust/src/core.rs
rust/src/lib.rs
rust/src/ntp/mod.rs [new file with mode: 0644]
rust/src/ntp/ntp.rs [new file with mode: 0644]
src/Makefile.am
src/app-layer-detect-proto.c
src/app-layer-ntp.c [new file with mode: 0644]
src/app-layer-ntp.h [new file with mode: 0644]
src/app-layer-parser.c
src/app-layer-protos.c
src/app-layer-protos.h
suricata.yaml.in

index a04b0b0d6a04c6c811074b270514d769efa7cb87..f10cd3c3e9d3c1a2d5f970a63185d8b41687aa44 100644 (file)
@@ -10,8 +10,11 @@ debug = true
 
 [features]
 lua = []
+experimental = ["ntp-parser"]
 
 [dependencies]
 nom = "~3.0"
 libc = "~0.2.0"
 crc = "~1.4.0"
+
+ntp-parser = { version = "^0", optional = true }
index 3200ad3309a8cfb5d7b83cdface650af3b199fd5..cb46f783dfa96eeafcecaac43ce5f67ca984aec2 100755 (executable)
@@ -59,6 +59,7 @@ type_map = {
 
     "libc::c_void": "void",
 
+    "libc::c_char": "char",
     "libc::c_int": "int",
     "c_int": "int",
     "libc::int8_t": "int8_t",
@@ -77,10 +78,13 @@ type_map = {
     "DNSTransaction": "RSDNSTransaction",
     "NFSState": "NFSState",
     "NFSTransaction": "NFSTransaction",
+    "NTPState": "NTPState",
+    "NTPTransaction": "NTPTransaction",
     "JsonT": "json_t",
     "DetectEngineState": "DetectEngineState",
     "core::DetectEngineState": "DetectEngineState",
     "core::AppLayerDecoderEvents": "AppLayerDecoderEvents",
+    "core::AppLayerEventType": "AppLayerEventType",
     "CLuaState": "lua_State",
     "Store": "Store",
 }
index 98d37afcdcfd43fae3cba9ee017121cb07f8dc4c..975f28010842349915e2dcba9ec9ca9eafc0e390 100644 (file)
@@ -26,6 +26,11 @@ pub enum Flow {}
 pub enum DetectEngineState {}
 pub enum AppLayerDecoderEvents {}
 
+// From app-layer-events.h
+pub type AppLayerEventType = libc::c_int;
+pub const APP_LAYER_EVENT_TYPE_TRANSACTION : i32 = 1;
+pub const APP_LAYER_EVENT_TYPE_PACKET      : i32 = 2;
+
 // From stream.h.
 pub const STREAM_TOSERVER: u8 = 0x04;
 pub const STREAM_TOCLIENT: u8 = 0x08;
index 8e086bae6d39b304e5daed8ca57d7b806519706e..08e891ffba309789e8a3d7ddd0e972dced8afaa3 100644 (file)
@@ -39,3 +39,6 @@ pub mod lua;
 
 pub mod dns;
 pub mod nfs;
+
+#[cfg(feature = "experimental")]
+pub mod ntp;
diff --git a/rust/src/ntp/mod.rs b/rust/src/ntp/mod.rs
new file mode 100644 (file)
index 0000000..35f1a70
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (C) 2017 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+// written by Pierre Chifflier  <chifflier@wzdftpd.net>
+
+pub mod ntp;
diff --git a/rust/src/ntp/ntp.rs b/rust/src/ntp/ntp.rs
new file mode 100644 (file)
index 0000000..de65449
--- /dev/null
@@ -0,0 +1,369 @@
+/* Copyright (C) 2017 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+// written by Pierre Chifflier  <chifflier@wzdftpd.net>
+
+extern crate ntp_parser;
+use self::ntp_parser::*;
+use core;
+use applayer;
+use libc;
+use std;
+use std::ffi::CStr;
+
+use log::*;
+
+use nom::IResult;
+
+#[repr(u32)]
+pub enum NTPEvent {
+    UnsolicitedResponse = 0,
+    MalformedData,
+    NotRequest,
+    NotResponse,
+}
+
+
+
+pub struct NTPState {
+    /// List of transactions for this session
+    transactions: Vec<NTPTransaction>,
+
+    /// Detection engine states counter
+    de_state_count: u64,
+
+    /// Events counter
+    events: u16,
+
+    /// tx counter for assigning incrementing id's to tx's
+    tx_id: u64,
+}
+
+#[derive(Debug)]
+pub struct NTPTransaction {
+    /// The NTP reference ID
+    pub xid: u32,
+
+    /// The internal transaction id
+    id: u64,
+
+    /// The detection engine state, if present
+    de_state: Option<*mut core::DetectEngineState>,
+
+    /// The events associated with this transaction
+    events: *mut core::AppLayerDecoderEvents,
+
+    logged: applayer::LoggerFlags,
+}
+
+
+
+impl NTPState {
+    pub fn new() -> NTPState {
+        NTPState{
+            transactions: Vec::new(),
+            de_state_count: 0,
+            events: 0,
+            tx_id: 0,
+        }
+    }
+}
+
+impl NTPState {
+    fn parse(&mut self, i: &[u8], _direction: u8) -> i8 {
+        match parse_ntp(i) {
+            IResult::Done(_,ref msg) => {
+                // SCLogDebug!("parse_ntp: {:?}",msg);
+                if msg.mode == 1 || msg.mode == 3 {
+                    let mut tx = self.new_tx();
+                    // use the reference id as identifier
+                    tx.xid = msg.ref_id;
+                    self.transactions.push(tx);
+                }
+                0
+            },
+            IResult::Incomplete(_) => {
+                SCLogDebug!("Insufficient data while parsing NTP data");
+                self.set_event(NTPEvent::MalformedData);
+                -1
+            },
+            IResult::Error(_) => {
+                SCLogDebug!("Error while parsing NTP data");
+                self.set_event(NTPEvent::MalformedData);
+                -1
+            },
+        }
+    }
+
+    fn free(&mut self) {
+        // All transactions are freed when the `transactions` object is freed.
+        // But let's be explicit
+        self.transactions.clear();
+    }
+
+    fn new_tx(&mut self) -> NTPTransaction {
+        self.tx_id += 1;
+        NTPTransaction::new(self.tx_id)
+    }
+
+    pub fn get_tx_by_id(&mut self, tx_id: u64) -> Option<&NTPTransaction> {
+        self.transactions.iter().find(|&tx| tx.id == tx_id + 1)
+    }
+
+    fn free_tx(&mut self, tx_id: u64) {
+        let tx = self.transactions.iter().position(|ref tx| tx.id == tx_id + 1);
+        debug_assert!(tx != None);
+        if let Some(idx) = tx {
+            let _ = self.transactions.remove(idx);
+        }
+    }
+
+    /// Set an event. The event is set on the most recent transaction.
+    pub fn set_event(&mut self, event: NTPEvent) {
+        if let Some(tx) = self.transactions.last_mut() {
+            let ev = event as u8;
+            core::sc_app_layer_decoder_events_set_event_raw(&mut tx.events, ev);
+            self.events += 1;
+        }
+    }
+}
+
+impl NTPTransaction {
+    pub fn new(id: u64) -> NTPTransaction {
+        NTPTransaction {
+            xid: 0,
+            id: id,
+            de_state: None,
+            events: std::ptr::null_mut(),
+            logged: applayer::LoggerFlags::new(),
+        }
+    }
+
+    fn free(&mut self) {
+        if self.events != std::ptr::null_mut() {
+            core::sc_app_layer_decoder_events_free_events(&mut self.events);
+        }
+    }
+}
+
+impl Drop for NTPTransaction {
+    fn drop(&mut self) {
+        self.free();
+    }
+}
+
+
+/// TOSERVER probe function
+#[no_mangle]
+pub extern "C" fn rs_ntp_probe(input: *const libc::uint8_t, len: libc::uint32_t)
+                               -> libc::int8_t
+{
+    let slice: &[u8] = unsafe {
+        std::slice::from_raw_parts(input as *mut u8, len as usize)
+    };
+    match parse_ntp(slice) {
+        IResult::Done(_, ref msg) => {
+            if msg.version == 3 || msg.version == 4 {
+                return 1;
+            } else {
+                return -1;
+            }
+        },
+        IResult::Incomplete(_) => {
+            return 0;
+        },
+        IResult::Error(_) => {
+            return -1;
+        },
+    }
+}
+
+
+
+
+
+
+
+/// Returns *mut NTPState
+#[no_mangle]
+pub extern "C" fn rs_ntp_state_new() -> *mut libc::c_void {
+    let state = NTPState::new();
+    let boxed = Box::new(state);
+    return unsafe{std::mem::transmute(boxed)};
+}
+
+/// Params:
+/// - state: *mut NTPState as void pointer
+#[no_mangle]
+pub extern "C" fn rs_ntp_state_free(state: *mut libc::c_void) {
+    // Just unbox...
+    let mut ntp_state: Box<NTPState> = unsafe{std::mem::transmute(state)};
+    ntp_state.free();
+}
+
+#[no_mangle]
+pub extern "C" fn rs_ntp_parse_request(_flow: *const core::Flow,
+                                       state: &mut NTPState,
+                                       _pstate: *const libc::c_void,
+                                       input: *const libc::uint8_t,
+                                       input_len: u32,
+                                       _data: *const libc::c_void) -> i8 {
+    let buf = unsafe{std::slice::from_raw_parts(input, input_len as usize)};
+    state.parse(buf, 0)
+}
+
+#[no_mangle]
+pub extern "C" fn rs_ntp_parse_response(_flow: *const core::Flow,
+                                       state: &mut NTPState,
+                                       _pstate: *const libc::c_void,
+                                       input: *const libc::uint8_t,
+                                       input_len: u32,
+                                       _data: *const libc::c_void) -> i8 {
+    let buf = unsafe{std::slice::from_raw_parts(input, input_len as usize)};
+    state.parse(buf, 1)
+}
+
+#[no_mangle]
+pub extern "C" fn rs_ntp_state_get_tx(state: &mut NTPState,
+                                      tx_id: libc::uint64_t)
+                                      -> *mut NTPTransaction
+{
+    match state.get_tx_by_id(tx_id) {
+        Some(tx) => unsafe{std::mem::transmute(tx)},
+        None     => std::ptr::null_mut(),
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn rs_ntp_state_get_tx_count(state: &mut NTPState)
+                                            -> libc::uint64_t
+{
+    state.tx_id
+}
+
+#[no_mangle]
+pub extern "C" fn rs_ntp_state_tx_free(state: &mut NTPState,
+                                       tx_id: libc::uint64_t)
+{
+    state.free_tx(tx_id);
+}
+
+#[no_mangle]
+pub extern "C" fn rs_ntp_state_progress_completion_status(
+    _direction: libc::uint8_t)
+    -> libc::c_int
+{
+    return 1;
+}
+
+#[no_mangle]
+pub extern "C" fn rs_ntp_tx_get_alstate_progress(_tx: &mut NTPTransaction,
+                                                 _direction: libc::uint8_t)
+                                                 -> libc::uint8_t
+{
+    1
+}
+
+
+
+
+
+#[no_mangle]
+pub extern "C" fn rs_ntp_tx_set_logged(_state: &mut NTPState,
+                                       tx: &mut NTPTransaction,
+                                       logger: libc::uint32_t)
+{
+    tx.logged.set_logged(logger);
+}
+
+#[no_mangle]
+pub extern "C" fn rs_ntp_tx_get_logged(_state: &mut NTPState,
+                                       tx: &mut NTPTransaction,
+                                       logger: libc::uint32_t)
+                                       -> i8
+{
+    if tx.logged.is_logged(logger) {
+        return 1;
+    }
+    return 0;
+}
+
+
+#[no_mangle]
+pub extern "C" fn rs_ntp_state_set_tx_detect_state(
+    state: &mut NTPState,
+    tx: &mut NTPTransaction,
+    de_state: &mut core::DetectEngineState)
+{
+    state.de_state_count += 1;
+    tx.de_state = Some(de_state);
+}
+
+#[no_mangle]
+pub extern "C" fn rs_ntp_state_get_tx_detect_state(
+    tx: &mut NTPTransaction)
+    -> *mut core::DetectEngineState
+{
+    match tx.de_state {
+        Some(ds) => ds,
+        None => std::ptr::null_mut(),
+    }
+}
+
+
+#[no_mangle]
+pub extern "C" fn rs_ntp_state_has_events(state: &mut NTPState) -> u8 {
+    if state.events > 0 {
+        return 1;
+    }
+    return 0;
+}
+
+#[no_mangle]
+pub extern "C" fn rs_ntp_state_get_events(state: &mut NTPState,
+                                          tx_id: libc::uint64_t)
+                                          -> *mut core::AppLayerDecoderEvents
+{
+    match state.get_tx_by_id(tx_id) {
+        Some(tx) => tx.events,
+        _        => std::ptr::null_mut(),
+    }
+}
+
+#[no_mangle]
+pub extern "C" fn rs_ntp_state_get_event_info(event_name: *const libc::c_char,
+                                              event_id: *mut libc::c_int,
+                                              event_type: *mut core::AppLayerEventType)
+                                              -> i8
+{
+    if event_name == std::ptr::null() { return -1; }
+    let c_event_name: &CStr = unsafe { CStr::from_ptr(event_name) };
+    let event = match c_event_name.to_str() {
+        Ok(s) => {
+            match s {
+                "malformed_data" => NTPEvent::MalformedData as i32,
+                _ => -1, // unknown event
+            }
+        },
+        Err(_) => -1, // UTF-8 conversion failed
+    };
+    unsafe{
+        *event_type = core::APP_LAYER_EVENT_TYPE_TRANSACTION;
+        *event_id = event as libc::c_int;
+    };
+    0
+}
index 1769b3b0ca7fb450cc865990bb90bc7b93ea5bd0..09fcafae2d67a75ff895cc7d6fc80baf2172c1e9 100644 (file)
@@ -41,6 +41,7 @@ app-layer-smb.c app-layer-smb.h \
 app-layer-smtp.c app-layer-smtp.h \
 app-layer-nfs-tcp.c app-layer-nfs-tcp.h \
 app-layer-nfs-udp.c app-layer-nfs-udp.h \
+app-layer-ntp.c app-layer-ntp.h \
 app-layer-template.c app-layer-template.h \
 app-layer-ssh.c app-layer-ssh.h \
 app-layer-ssl.c app-layer-ssl.h \
index 1a0abdfb7c43fcc4495ed392edda7c91b0568a89..c0c0d21678d013620d5074d8d48a99777abb3dd5 100644 (file)
@@ -698,6 +698,8 @@ static void AppLayerProtoDetectPrintProbingParsers(AppLayerProtoDetectProbingPar
                         printf("            alproto: ALPROTO_ENIP\n");
                     else if (pp_pe->alproto == ALPROTO_NFS)
                         printf("            alproto: ALPROTO_NFS\n");
+                    else if (pp_pe->alproto == ALPROTO_NTP)
+                        printf("            alproto: ALPROTO_NTP\n");
                     else if (pp_pe->alproto == ALPROTO_TEMPLATE)
                         printf("            alproto: ALPROTO_TEMPLATE\n");
                     else if (pp_pe->alproto == ALPROTO_DNP3)
@@ -757,6 +759,8 @@ static void AppLayerProtoDetectPrintProbingParsers(AppLayerProtoDetectProbingPar
                     printf("            alproto: ALPROTO_ENIP\n");
                 else if (pp_pe->alproto == ALPROTO_NFS)
                     printf("            alproto: ALPROTO_NFS\n");
+                else if (pp_pe->alproto == ALPROTO_NTP)
+                    printf("            alproto: ALPROTO_NTP\n");
                 else if (pp_pe->alproto == ALPROTO_TEMPLATE)
                     printf("            alproto: ALPROTO_TEMPLATE\n");
                 else if (pp_pe->alproto == ALPROTO_DNP3)
diff --git a/src/app-layer-ntp.c b/src/app-layer-ntp.c
new file mode 100644 (file)
index 0000000..3ffc6b5
--- /dev/null
@@ -0,0 +1,307 @@
+/* Copyright (C) 2017 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/**
+ * \file
+ *
+ * \author Pierre Chifflier <chifflier@wzdftpd.net>
+ *
+ * Parser for NTP application layer running on UDP port 123.
+ */
+
+#include "suricata-common.h"
+#include "stream.h"
+#include "conf.h"
+
+#include "util-unittest.h"
+
+#include "app-layer-detect-proto.h"
+#include "app-layer-parser.h"
+
+#include "app-layer-ntp.h"
+
+#if defined(HAVE_RUST) && defined(HAVE_RUST_EXTERNAL)
+
+#include "rust-ntp-ntp-gen.h"
+
+/* The default port to probe for NTP traffic if not provided in the
+ * configuration file. */
+#define NTP_DEFAULT_PORT "123"
+
+/* The minimum size for an NTP message. */
+#define NTP_MIN_FRAME_LEN 2
+
+
+static void *NTPStateAlloc(void)
+{
+    return rs_ntp_state_new();
+}
+
+static void NTPStateFree(void *state)
+{
+    rs_ntp_state_free(state);
+}
+
+/**
+ * \brief Callback from the application layer to have a transaction freed.
+ *
+ * \param state a void pointer to the NTPState object.
+ * \param tx_id the transaction ID to free.
+ */
+static void NTPStateTxFree(void *state, uint64_t tx_id)
+{
+    rs_ntp_state_tx_free(state, tx_id);
+}
+
+static int NTPStateGetEventInfo(const char *event_name, int *event_id,
+    AppLayerEventType *event_type)
+{
+    return rs_ntp_state_get_event_info(event_name, event_id, event_type);
+}
+
+static AppLayerDecoderEvents *NTPGetEvents(void *state, uint64_t tx_id)
+{
+    return rs_ntp_state_get_events(state, tx_id);
+}
+
+static int NTPHasEvents(void *state)
+{
+    return rs_ntp_state_has_events(state);
+}
+
+/**
+ * \brief Probe the input to see if it looks like NTP.
+ *
+ * \retval ALPROTO_NTP if it looks like NTP, otherwise
+ *     ALPROTO_UNKNOWN.
+ */
+static AppProto NTPProbingParser(uint8_t *input, uint32_t input_len,
+    uint32_t *offset)
+{
+    if (input_len < NTP_MIN_FRAME_LEN) {
+        return ALPROTO_UNKNOWN;
+    }
+
+    int8_t r = rs_ntp_probe(input, input_len);
+    if (r == 1) {
+        return ALPROTO_NTP;
+    } else if (r == -1) {
+        return ALPROTO_FAILED;
+    }
+
+    SCLogDebug("Protocol not detected as ALPROTO_NTP.");
+    return ALPROTO_UNKNOWN;
+}
+
+static int RustNTPParseRequest(Flow *f, void *state,
+    AppLayerParserState *pstate, uint8_t *input, uint32_t input_len,
+    void *local_data)
+{
+    SCLogDebug("RustNTPParseRequest");
+    return rs_ntp_parse_request(f, state, pstate, input, input_len,
+            local_data);
+}
+
+static int RustNTPParseResponse(Flow *f, void *state,
+    AppLayerParserState *pstate, uint8_t *input, uint32_t input_len,
+    void *local_data)
+{
+    SCLogDebug("RustNTPParseResponse");
+    return rs_ntp_parse_response(f, state, pstate, input, input_len,
+            local_data);
+}
+
+static uint64_t NTPGetTxCnt(void *state)
+{
+    return rs_ntp_state_get_tx_count(state);
+}
+
+static void *NTPGetTx(void *state, uint64_t tx_id)
+{
+    return rs_ntp_state_get_tx(state, tx_id);
+}
+
+// static void NTPSetTxLogged(void *state, void *vtx, uint32_t logger)
+// {
+//     rs_ntp_tx_set_logged(state, vtx, logger);
+// }
+//
+// static int NTPGetTxLogged(void *state, void *vtx, uint32_t logger)
+// {
+//     return rs_ntp_tx_get_logged(state, vtx, logger);
+// }
+
+
+
+
+
+
+
+/**
+ * \brief Called by the application layer.
+ *
+ * In most cases 1 can be returned here.
+ */
+static int NTPGetAlstateProgressCompletionStatus(uint8_t direction) {
+    return rs_ntp_state_progress_completion_status(direction);
+}
+
+/**
+ * \brief Return the state of a transaction in a given direction.
+ */
+static int NTPGetStateProgress(void *tx, uint8_t direction)
+{
+    return rs_ntp_tx_get_alstate_progress(tx, direction);
+}
+
+/**
+ * \brief Get stored Tx detect state
+ */
+static DetectEngineState *NTPGetTxDetectState(void *vtx)
+{
+    return rs_ntp_state_get_tx_detect_state(vtx);
+}
+
+/**
+ * \brief Set stored Tx detect state
+ */
+static int NTPSetTxDetectState(void *state, void *vtx,
+    DetectEngineState *s)
+{
+    rs_ntp_state_set_tx_detect_state(state, vtx, s);
+    return 0;
+}
+
+void RegisterNTPParsers(void)
+{
+    const char *proto_name = "ntp";
+
+    /* Check if NTP UDP detection is enabled. If it does not exist in
+     * the configuration file then it will be enabled by default. */
+    if (AppLayerProtoDetectConfProtoDetectionEnabled("udp", proto_name)) {
+
+        SCLogDebug("NTP UDP protocol detection enabled.");
+
+        AppLayerProtoDetectRegisterProtocol(ALPROTO_NTP, proto_name);
+
+        if (RunmodeIsUnittests()) {
+
+            SCLogDebug("Unittest mode, registeringd default configuration.");
+            AppLayerProtoDetectPPRegister(IPPROTO_UDP, NTP_DEFAULT_PORT,
+                ALPROTO_NTP, 0, NTP_MIN_FRAME_LEN, STREAM_TOSERVER,
+                NTPProbingParser, NULL);
+
+        }
+        else {
+
+            if (!AppLayerProtoDetectPPParseConfPorts("udp", IPPROTO_UDP,
+                    proto_name, ALPROTO_NTP, 0, NTP_MIN_FRAME_LEN,
+                    NTPProbingParser, NULL)) {
+                SCLogDebug("No NTP app-layer configuration, enabling NTP"
+                    " detection UDP detection on port %s.",
+                    NTP_DEFAULT_PORT);
+                AppLayerProtoDetectPPRegister(IPPROTO_UDP,
+                    NTP_DEFAULT_PORT, ALPROTO_NTP, 0,
+                    NTP_MIN_FRAME_LEN, STREAM_TOSERVER,
+                    NTPProbingParser, NULL);
+            }
+
+        }
+
+    }
+
+    else {
+        SCLogDebug("Protocol detecter and parser disabled for NTP.");
+        return;
+    }
+
+    if (AppLayerParserConfParserEnabled("udp", proto_name)) {
+
+        SCLogDebug("Registering NTP protocol parser.");
+
+        /* Register functions for state allocation and freeing. A
+         * state is allocated for every new NTP flow. */
+        AppLayerParserRegisterStateFuncs(IPPROTO_UDP, ALPROTO_NTP,
+            NTPStateAlloc, NTPStateFree);
+
+        /* Register request parser for parsing frame from server to client. */
+        AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_NTP,
+            STREAM_TOSERVER, RustNTPParseRequest);
+
+        /* Register response parser for parsing frames from server to client. */
+        AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_NTP,
+            STREAM_TOCLIENT, RustNTPParseResponse);
+
+        /* Register a function to be called by the application layer
+         * when a transaction is to be freed. */
+        AppLayerParserRegisterTxFreeFunc(IPPROTO_UDP, ALPROTO_NTP,
+            NTPStateTxFree);
+
+        // AppLayerParserRegisterLoggerFuncs(IPPROTO_UDP, ALPROTO_NTP,
+        //     NTPGetTxLogged, NTPSetTxLogged);
+
+        /* Register a function to return the current transaction count. */
+        AppLayerParserRegisterGetTxCnt(IPPROTO_UDP, ALPROTO_NTP,
+            NTPGetTxCnt);
+
+        /* Transaction handling. */
+        AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_NTP,
+            NTPGetAlstateProgressCompletionStatus);
+        AppLayerParserRegisterGetStateProgressFunc(IPPROTO_UDP,
+            ALPROTO_NTP, NTPGetStateProgress);
+        AppLayerParserRegisterGetTx(IPPROTO_UDP, ALPROTO_NTP,
+            NTPGetTx);
+
+        /* Application layer event handling. */
+        AppLayerParserRegisterHasEventsFunc(IPPROTO_UDP, ALPROTO_NTP,
+            NTPHasEvents);
+
+        /* What is this being registered for? */
+        AppLayerParserRegisterDetectStateFuncs(IPPROTO_UDP, ALPROTO_NTP,
+            NULL, NTPGetTxDetectState, NTPSetTxDetectState);
+
+        AppLayerParserRegisterGetEventInfo(IPPROTO_UDP, ALPROTO_NTP,
+            NTPStateGetEventInfo);
+        AppLayerParserRegisterGetEventsFunc(IPPROTO_UDP, ALPROTO_NTP,
+            NTPGetEvents);
+    }
+    else {
+        SCLogDebug("NTP protocol parsing disabled.");
+    }
+
+#ifdef UNITTESTS
+    AppLayerParserRegisterProtocolUnittests(IPPROTO_UDP, ALPROTO_NTP,
+        NTPParserRegisterTests);
+#endif
+}
+
+#ifdef UNITTESTS
+#endif
+
+void NTPParserRegisterTests(void)
+{
+#ifdef UNITTESTS
+#endif
+}
+
+#else /* HAVE_RUST */
+
+void RegisterNTPParsers(void)
+{
+}
+
+#endif /* HAVE_RUST */
diff --git a/src/app-layer-ntp.h b/src/app-layer-ntp.h
new file mode 100644 (file)
index 0000000..2160639
--- /dev/null
@@ -0,0 +1,34 @@
+/* Copyright (C) 2017 Open Information Security Foundation
+ *
+ * You can copy, redistribute or modify this Program under the terms of
+ * the GNU General Public License version 2 as published by the Free
+ * Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+/**
+ * \file
+ *
+ * \author Pierre Chifflier <chifflier@wzdftpd.net>
+ */
+
+#ifndef __APP_LAYER_NTP_H__
+#define __APP_LAYER_NTP_H__
+
+void RegisterNTPParsers(void);
+void NTPParserRegisterTests(void);
+
+/** Opaque Rust types. */
+typedef struct NTPState_ NTPState;
+typedef struct NTPTransaction_ NTPTransaction;
+
+#endif /* __APP_LAYER_NTP_H__ */
index 27f35555e4991683ffe220b3f5c847120e48ef67..925fea84d69f6d571a5ea8421f5d3b8fe9f36737 100644 (file)
@@ -62,6 +62,7 @@
 #include "app-layer-dnp3.h"
 #include "app-layer-nfs-tcp.h"
 #include "app-layer-nfs-udp.h"
+#include "app-layer-ntp.h"
 #include "app-layer-template.h"
 
 #include "conf.h"
@@ -1386,6 +1387,7 @@ void AppLayerParserRegisterProtocolParsers(void)
     RegisterDNP3Parsers();
     RegisterNFSTCPParsers();
     RegisterNFSUDPParsers();
+    RegisterNTPParsers();
     RegisterTemplateParsers();
 
     /** IMAP */
index 945d34f58c2c0e56b43471088877feadc8a26475..fdcaff298ac08211e04afae4fb5b7a7ab905958c 100644 (file)
@@ -84,6 +84,9 @@ const char *AppProtoToString(AppProto alproto)
         case ALPROTO_NFS:
             proto_name = "nfs";
             break;
+        case ALPROTO_NTP:
+            proto_name = "ntp";
+            break;
         case ALPROTO_TEMPLATE:
             proto_name = "template";
             break;
index dac94cc9ff153a900b1d73f290222fbb392019f0..b765aab7d83459632c54ad81240c0b2e295b0771 100644 (file)
@@ -45,6 +45,7 @@ enum AppProtoEnum {
     ALPROTO_ENIP,
     ALPROTO_DNP3,
     ALPROTO_NFS,
+    ALPROTO_NTP,
     ALPROTO_TEMPLATE,
 
     /* used by the probing parser when alproto detection fails
index 7b2b679c893885db824e71adbf2a2c1a5abcdef7..7ccd767d7e3037c36d2604d486e9b609692e8dce 100644 (file)
@@ -680,6 +680,8 @@ pcap-file:
 # "detection-only" enables protocol detection only (parser disabled).
 app-layer:
   protocols:
+    ntp:
+      enabled: yes
     nfs:
       enabled: yes
     tls: