diff --git a/rust/src/nfs/nfs3.rs b/rust/src/nfs/nfs3.rs index 0eb0249db4..0adbc73703 100644 --- a/rust/src/nfs/nfs3.rs +++ b/rust/src/nfs/nfs3.rs @@ -289,6 +289,8 @@ pub struct NFS3State { ts_gap: bool, // last TS update was gap tc_gap: bool, // last TC update was gap + is_udp: bool, + /// tx counter for assigning incrementing id's to tx's tx_id: u64, @@ -318,6 +320,7 @@ impl NFS3State { tc_ssn_gap:false, ts_gap:false, tc_gap:false, + is_udp:false, tx_id:0, de_state_count:0, //ts_txs_updated:false, @@ -686,9 +689,11 @@ impl NFS3State { tx.request_done = true; } } - self.ts_chunk_xid = r.hdr.xid; - let file_data_len = w.file_data.len() as u32 - fill_bytes as u32; - self.ts_chunk_left = w.file_len as u32 - file_data_len as u32; + if !self.is_udp { + self.ts_chunk_xid = r.hdr.xid; + let file_data_len = w.file_data.len() as u32 - fill_bytes as u32; + self.ts_chunk_left = w.file_len as u32 - file_data_len as u32; + } 0 } @@ -994,8 +999,10 @@ impl NFS3State { //if is_last { // self.tc_txs_updated = true; //} - self.tc_chunk_xid = r.hdr.xid; - self.tc_chunk_left = reply.count as u32 - reply.data.len() as u32; + if !self.is_udp { + self.tc_chunk_xid = r.hdr.xid; + self.tc_chunk_left = reply.count as u32 - reply.data.len() as u32; + } SCLogDebug!("REPLY {} to procedure {} blob size {} / {}: chunk_left {}", r.hdr.xid, NFSPROC3_READ, r.prog_data.len(), reply.count, self.tc_chunk_left); @@ -1321,6 +1328,43 @@ impl NFS3State { }; status } + /// Parsing function + pub fn parse_udp_ts<'b>(&mut self, input: &'b[u8]) -> u32 { + let mut status = 0; + SCLogDebug!("parse_udp_ts ({})", input.len()); + if input.len() > 0 { + match parse_rpc_udp_request(input) { + IResult::Done(_, ref rpc_record) => { + self.is_udp = true; + status |= self.process_request_record(rpc_record); + }, + IResult::Incomplete(_) => { + }, + IResult::Error(e) => { panic!("Parsing failed: {:?}",e); //break + }, + } + } + status + } + + /// Parsing function + pub fn parse_udp_tc<'b>(&mut self, input: &'b[u8]) -> u32 { + let mut status = 0; + SCLogDebug!("parse_udp_tc ({})", input.len()); + if input.len() > 0 { + match parse_rpc_udp_reply(input) { + IResult::Done(_, ref rpc_record) => { + self.is_udp = true; + status |= self.process_reply_record(rpc_record); + }, + IResult::Incomplete(_) => { + }, + IResult::Error(e) => { panic!("Parsing failed: {:?}",e); //break + }, + } + }; + status + } fn getfiles(&mut self, direction: u8) -> * mut FileContainer { //SCLogDebug!("direction: {}", direction); if direction == STREAM_TOCLIENT { @@ -1411,6 +1455,45 @@ pub extern "C" fn rs_nfs3_parse_response(_flow: *mut Flow, } } +/// C binding parse a DNS request. Returns 1 on success, -1 on failure. +#[no_mangle] +pub extern "C" fn rs_nfs3_parse_request_udp(_flow: *mut Flow, + state: &mut NFS3State, + _pstate: *mut libc::c_void, + input: *mut libc::uint8_t, + input_len: libc::uint32_t, + _data: *mut libc::c_void) + -> libc::int8_t +{ + let buf = unsafe{std::slice::from_raw_parts(input, input_len as usize)}; + SCLogDebug!("parsing {} bytes of request data", input_len); + + if state.parse_udp_ts(buf) == 0 { + 1 + } else { + -1 + } +} + +#[no_mangle] +pub extern "C" fn rs_nfs3_parse_response_udp(_flow: *mut Flow, + state: &mut NFS3State, + _pstate: *mut libc::c_void, + input: *mut libc::uint8_t, + input_len: libc::uint32_t, + _data: *mut libc::c_void) + -> libc::int8_t +{ + SCLogDebug!("parsing {} bytes of response data", input_len); + let buf = unsafe{std::slice::from_raw_parts(input, input_len as usize)}; + + if state.parse_udp_tc(buf) == 0 { + 1 + } else { + -1 + } +} + #[no_mangle] pub extern "C" fn rs_nfs3_state_get_tx_count(state: &mut NFS3State) -> libc::uint64_t @@ -1643,6 +1726,43 @@ pub fn nfs3_probe(i: &[u8], direction: u8) -> i8 { } } +pub fn nfs3_probe_udp(i: &[u8], direction: u8) -> i8 { + if direction == STREAM_TOCLIENT { + match parse_rpc_udp_reply(i) { + IResult::Done(_, ref rpc) => { + if i.len() >= 32 && rpc.hdr.msgtype == 1 && rpc.reply_state == 0 && rpc.accept_state == 0 { + SCLogNotice!("TC PROBE LEN {} XID {} TYPE {}", rpc.hdr.frag_len, rpc.hdr.xid, rpc.hdr.msgtype); + return 1; + } else { + return -1; + } + }, + IResult::Incomplete(_) => { + return -1; + }, + IResult::Error(_) => { + return -1; + }, + } + } else { + match parse_rpc_udp_request(i) { + IResult::Done(_, ref rpc) => { + if i.len() >= 48 && rpc.hdr.msgtype == 0 && rpc.progver == 3 && rpc.program == 100003 { + return 1; + } else { + return -1; + } + }, + IResult::Incomplete(_) => { + return -1; + }, + IResult::Error(_) => { + return -1; + }, + } + } +} + /// TOSERVER probe function #[no_mangle] pub extern "C" fn rs_nfs_probe_ts(input: *const libc::uint8_t, len: libc::uint32_t) @@ -1664,6 +1784,26 @@ pub extern "C" fn rs_nfs_probe_tc(input: *const libc::uint8_t, len: libc::uint32 return nfs3_probe(slice, STREAM_TOCLIENT); } +/// TOSERVER probe function +#[no_mangle] +pub extern "C" fn rs_nfs_probe_udp_ts(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) + }; + return nfs3_probe_udp(slice, STREAM_TOSERVER); +} +/// TOCLIENT probe function +#[no_mangle] +pub extern "C" fn rs_nfs_probe_udp_tc(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) + }; + return nfs3_probe_udp(slice, STREAM_TOCLIENT); +} #[no_mangle] pub extern "C" fn rs_nfs3_getfiles(direction: u8, ptr: *mut NFS3State) -> * mut FileContainer { diff --git a/rust/src/nfs/parser.rs b/rust/src/nfs/parser.rs index 9eb91685f6..5a8714c329 100644 --- a/rust/src/nfs/parser.rs +++ b/rust/src/nfs/parser.rs @@ -635,3 +635,111 @@ named!(pub parse_rpc_reply, } )) ); + +named!(pub parse_rpc_udp_packet_header, + do_parse!( + xid: be_u32 + >> msgtype: be_u32 + >> ( + RpcPacketHeader { + frag_is_last:false, + frag_len:0, + + xid:xid, + msgtype:msgtype, + } + )) +); + +#[derive(Debug,PartialEq)] +pub struct RpcUdpRequestPacket<'a> { + pub hdr: RpcPacketHeader<>, + + pub rpcver: u32, + pub program: u32, + pub progver: u32, + pub procedure: u32, + + pub creds_flavor: u32, + pub creds_len: u32, + pub creds: Option<&'a[u8]>, + pub creds_unix:Option>, + + pub verifier_flavor: u32, + pub verifier_len: u32, + pub verifier: Option<&'a[u8]>, + + pub prog_data: &'a[u8], +} + +named!(pub parse_rpc_udp_request, + do_parse!( + hdr: parse_rpc_udp_packet_header + + >> rpcver: be_u32 + >> program: be_u32 + >> progver: be_u32 + >> procedure: be_u32 + + >> creds_flavor: be_u32 + >> creds_len: be_u32 + >> creds: cond!(creds_flavor != 1 && creds_len > 0, take!(creds_len as usize)) + >> creds_unix: cond!(creds_len > 0 && creds_flavor == 1, flat_map!(take!((creds_len) as usize),parse_rfc_request_creds_unix)) + + >> verifier_flavor: be_u32 + >> verifier_len: be_u32 + >> verifier: cond!(verifier_len > 0, take!(verifier_len as usize)) + + >> pl: rest + + >> ( + RpcPacket { + hdr:hdr, + + rpcver:rpcver, + program:program, + progver:progver, + procedure:procedure, + + creds_flavor:creds_flavor, + creds_len:creds_len, + creds:creds, + creds_unix:creds_unix, + + verifier_flavor:verifier_flavor, + verifier_len:verifier_len, + verifier:verifier, + + prog_data:pl, + } + )) +); + +named!(pub parse_rpc_udp_reply, + do_parse!( + hdr: parse_rpc_udp_packet_header + + >> verifier_flavor: be_u32 + >> verifier_len: be_u32 + >> verifier: cond!(verifier_len > 0, take!(verifier_len as usize)) + + >> reply_state: be_u32 + >> accept_state: be_u32 + + >> pl: rest + + >> ( + RpcReplyPacket { + hdr:hdr, + + verifier_flavor:verifier_flavor, + verifier_len:verifier_len, + verifier:verifier, + + reply_state:reply_state, + accept_state:accept_state, + + prog_data:pl, + } + )) +); diff --git a/src/Makefile.am b/src/Makefile.am index c2a95c0865..84f517979b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -40,6 +40,7 @@ app-layer-smb2.c app-layer-smb2.h \ app-layer-smb.c app-layer-smb.h \ app-layer-smtp.c app-layer-smtp.h \ app-layer-nfs3.c app-layer-nfs3.h \ +app-layer-nfs3-udp.c app-layer-nfs3-udp.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 \ diff --git a/src/app-layer-nfs3-udp.c b/src/app-layer-nfs3-udp.c new file mode 100644 index 0000000000..bbd3ebe5c2 --- /dev/null +++ b/src/app-layer-nfs3-udp.c @@ -0,0 +1,395 @@ +/* Copyright (C) 2015 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 Victor Julien + * + * NFS3 application layer detector and parser for learning and + * nfs3 pruposes. + * + * This nfs3 implements a simple application layer for something + * like the NFS3 protocol running on port 2049. + */ + +#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-nfs3-udp.h" + +#ifndef HAVE_RUST +void RegisterNFS3UDPParsers(void) +{ +} + +#else + +#include "rust.h" +#include "rust-nfs-nfs3-gen.h" + +/* The default port to probe for echo traffic if not provided in the + * configuration file. */ +#define NFS3_DEFAULT_PORT "2049" + +/* The minimum size for a RFC message. For some protocols this might + * be the size of a header. TODO actual min size is likely larger */ +#define NFS3_MIN_FRAME_LEN 32 + +/* Enum of app-layer events for an echo protocol. Normally you might + * have events for errors in parsing data, like unexpected data being + * received. For echo we'll make something up, and log an app-layer + * level alert if an empty message is received. + * + * Example rule: + * + * alert nfs3 any any -> any any (msg:"SURICATA NFS3 empty message"; \ + * app-layer-event:nfs3.empty_message; sid:X; rev:Y;) + */ +enum { + NFS3_DECODER_EVENT_EMPTY_MESSAGE, +}; + +SCEnumCharMap nfs3_udp_decoder_event_table[] = { + {"EMPTY_MESSAGE", NFS3_DECODER_EVENT_EMPTY_MESSAGE}, + { NULL, 0 } +}; + +static void *NFS3StateAlloc(void) +{ + return rs_nfs3_state_new(); +} + +static void NFS3StateFree(void *state) +{ + rs_nfs3_state_free(state); +} + +/** + * \brief Callback from the application layer to have a transaction freed. + * + * \param state a void pointer to the NFS3State object. + * \param tx_id the transaction ID to free. + */ +static void NFS3StateTxFree(void *state, uint64_t tx_id) +{ + rs_nfs3_state_tx_free(state, tx_id); +} + +#if 0 +static int NFS3StateGetEventInfo(const char *event_name, int *event_id, + AppLayerEventType *event_type) +{ + *event_id = SCMapEnumNameToValue(event_name, nfs3_decoder_event_table); + if (*event_id == -1) { + SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%s\" not present in " + "nfs3 enum map table.", event_name); + /* This should be treated as fatal. */ + return -1; + } + + *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION; + + return 0; +} + +static AppLayerDecoderEvents *NFS3GetEvents(void *state, uint64_t tx_id) +{ + NFS3State *nfs3_state = state; + NFS3Transaction *tx; + + TAILQ_FOREACH(tx, &nfs3_state->tx_list, next) { + if (tx->tx_id == tx_id) { + return tx->decoder_events; + } + } + + return NULL; +} + +static int NFS3HasEvents(void *state) +{ + NFS3State *echo = state; + return echo->events; +} +#endif + +/** + * \brief Probe the input to see if it looks like echo. + * + * \retval ALPROTO_NFS3 if it looks like echo, otherwise + * ALPROTO_UNKNOWN. + */ +static AppProto NFS3ProbingParserTS(uint8_t *input, uint32_t input_len, + uint32_t *offset) +{ + SCLogNotice("probing"); + if (input_len < NFS3_MIN_FRAME_LEN) { + SCLogNotice("unknown"); + return ALPROTO_UNKNOWN; + } + + int8_t r = rs_nfs_probe_udp_ts(input, input_len); + if (r == 1) { + SCLogNotice("nfs3"); + return ALPROTO_NFS3; + } else if (r == -1) { + SCLogNotice("failed"); + return ALPROTO_FAILED; + } + + SCLogNotice("Protocol not detected as ALPROTO_NFS3."); + return ALPROTO_UNKNOWN; +} + +static AppProto NFS3ProbingParserTC(uint8_t *input, uint32_t input_len, + uint32_t *offset) +{ + SCLogNotice("probing"); + if (input_len < NFS3_MIN_FRAME_LEN) { + SCLogNotice("unknown"); + return ALPROTO_UNKNOWN; + } + + int8_t r = rs_nfs_probe_tc(input, input_len); + if (r == 1) { + SCLogNotice("nfs3"); + return ALPROTO_NFS3; + } else if (r == -1) { + SCLogNotice("failed"); + return ALPROTO_FAILED; + } + + SCLogNotice("Protocol not detected as ALPROTO_NFS3."); + return ALPROTO_UNKNOWN; +} + +static int NFS3ParseRequest(Flow *f, void *state, + AppLayerParserState *pstate, uint8_t *input, uint32_t input_len, + void *local_data) +{ + uint16_t file_flags = FileFlowToFlags(f, STREAM_TOSERVER); + rs_nfs3_setfileflags(0, state, file_flags); + + return rs_nfs3_parse_request_udp(f, state, pstate, input, input_len, local_data); +} + +static int NFS3ParseResponse(Flow *f, void *state, AppLayerParserState *pstate, + uint8_t *input, uint32_t input_len, void *local_data) +{ + uint16_t file_flags = FileFlowToFlags(f, STREAM_TOCLIENT); + rs_nfs3_setfileflags(1, state, file_flags); + + return rs_nfs3_parse_response_udp(f, state, pstate, input, input_len, local_data); +} + +static uint64_t NFS3GetTxCnt(void *state) +{ + return rs_nfs3_state_get_tx_count(state); +} + +static void *NFS3GetTx(void *state, uint64_t tx_id) +{ + return rs_nfs3_state_get_tx(state, tx_id); +} + +static void NFS3SetTxLogged(void *state, void *vtx, uint32_t logger) +{ + rs_nfs3_tx_set_logged(state, vtx, logger); +} + +static int NFS3GetTxLogged(void *state, void *vtx, uint32_t logger) +{ + return rs_nfs3_tx_get_logged(state, vtx, logger); +} + +/** + * \brief Called by the application layer. + * + * In most cases 1 can be returned here. + */ +static int NFS3GetAlstateProgressCompletionStatus(uint8_t direction) { + return rs_nfs3_state_progress_completion_status(direction); +} + +/** + * \brief Return the state of a transaction in a given direction. + * + * In the case of the echo protocol, the existence of a transaction + * means that the request is done. However, some protocols that may + * need multiple chunks of data to complete the request may need more + * than just the existence of a transaction for the request to be + * considered complete. + * + * For the response to be considered done, the response for a request + * needs to be seen. The response_done flag is set on response for + * checking here. + */ +static int NFS3GetStateProgress(void *tx, uint8_t direction) +{ + return rs_nfs3_tx_get_alstate_progress(tx, direction); +} + +/** + * \brief get stored tx detect state + */ +static DetectEngineState *NFS3GetTxDetectState(void *vtx) +{ + return rs_nfs3_state_get_tx_detect_state(vtx); +} + +/** + * \brief set store tx detect state + */ +static int NFS3SetTxDetectState(void *state, void *vtx, + DetectEngineState *s) +{ + rs_nfs3_state_set_tx_detect_state(state, vtx, s); + return 0; +} + +static FileContainer *NFS3GetFiles(void *state, uint8_t direction) +{ + return rs_nfs3_getfiles(direction, state); +} + +static StreamingBufferConfig sbcfg = STREAMING_BUFFER_CONFIG_INITIALIZER; +static SuricataFileContext sfc = { &sbcfg }; + +void RegisterNFS3UDPParsers(void) +{ + const char *proto_name = "nfs3"; + + /* Check if NFS3 TCP detection is enabled. If it does not exist in + * the configuration file then it will be enabled by default. */ + if (AppLayerProtoDetectConfProtoDetectionEnabled("udp", proto_name)) { + + rs_nfs3_init(&sfc); + + SCLogNotice("NFS3 UDP protocol detection enabled."); + + AppLayerProtoDetectRegisterProtocol(ALPROTO_NFS3, proto_name); + + if (RunmodeIsUnittests()) { + + SCLogNotice("Unittest mode, registering default configuration."); + AppLayerProtoDetectPPRegister(IPPROTO_UDP, NFS3_DEFAULT_PORT, + ALPROTO_NFS3, 0, NFS3_MIN_FRAME_LEN, STREAM_TOSERVER, + NFS3ProbingParserTS, NFS3ProbingParserTC); + + } + else { + + if (!AppLayerProtoDetectPPParseConfPorts("udp", IPPROTO_UDP, + proto_name, ALPROTO_NFS3, 0, NFS3_MIN_FRAME_LEN, + NFS3ProbingParserTS, NFS3ProbingParserTC)) { + SCLogNotice("No NFS3 app-layer configuration, enabling NFS3" + " detection TCP detection on port %s.", + NFS3_DEFAULT_PORT); + AppLayerProtoDetectPPRegister(IPPROTO_UDP, + NFS3_DEFAULT_PORT, ALPROTO_NFS3, 0, + NFS3_MIN_FRAME_LEN, STREAM_TOSERVER, + NFS3ProbingParserTS, NFS3ProbingParserTC); + } + + } + + } + + else { + SCLogNotice("Protocol detecter and parser disabled for NFS3."); + return; + } + + if (AppLayerParserConfParserEnabled("udp", proto_name)) + { + SCLogNotice("Registering NFS3 protocol parser."); + + /* Register functions for state allocation and freeing. A + * state is allocated for every new NFS3 flow. */ + AppLayerParserRegisterStateFuncs(IPPROTO_UDP, ALPROTO_NFS3, + NFS3StateAlloc, NFS3StateFree); + + /* Register request parser for parsing frame from server to client. */ + AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_NFS3, + STREAM_TOSERVER, NFS3ParseRequest); + + /* Register response parser for parsing frames from server to client. */ + AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_NFS3, + STREAM_TOCLIENT, NFS3ParseResponse); + + /* Register a function to be called by the application layer + * when a transaction is to be freed. */ + AppLayerParserRegisterTxFreeFunc(IPPROTO_UDP, ALPROTO_NFS3, + NFS3StateTxFree); + + AppLayerParserRegisterLoggerFuncs(IPPROTO_UDP, ALPROTO_NFS3, + NFS3GetTxLogged, NFS3SetTxLogged); + + /* Register a function to return the current transaction count. */ + AppLayerParserRegisterGetTxCnt(IPPROTO_UDP, ALPROTO_NFS3, + NFS3GetTxCnt); + + /* Transaction handling. */ + AppLayerParserRegisterGetStateProgressCompletionStatus(ALPROTO_NFS3, + NFS3GetAlstateProgressCompletionStatus); + AppLayerParserRegisterGetStateProgressFunc(IPPROTO_UDP, + ALPROTO_NFS3, NFS3GetStateProgress); + AppLayerParserRegisterGetTx(IPPROTO_UDP, ALPROTO_NFS3, + NFS3GetTx); + + AppLayerParserRegisterGetFilesFunc(IPPROTO_UDP, ALPROTO_NFS3, NFS3GetFiles); + + /* Application layer event handling. */ +// AppLayerParserRegisterHasEventsFunc(IPPROTO_UDP, ALPROTO_NFS3, +// NFS3HasEvents); + + /* What is this being registered for? */ + AppLayerParserRegisterDetectStateFuncs(IPPROTO_UDP, ALPROTO_NFS3, + NULL, NFS3GetTxDetectState, NFS3SetTxDetectState); + +// AppLayerParserRegisterGetEventInfo(IPPROTO_UDP, ALPROTO_NFS3, +// NFS3StateGetEventInfo); +// AppLayerParserRegisterGetEventsFunc(IPPROTO_UDP, ALPROTO_NFS3, +// NFS3GetEvents); + } + else { + SCLogNotice("NFS3 protocol parsing disabled."); + } + +#ifdef UNITTESTS + AppLayerParserRegisterProtocolUnittests(IPPROTO_UDP, ALPROTO_NFS3, + NFS3UDPParserRegisterTests); +#endif +} + +#ifdef UNITTESTS +#endif + +void NFS3UDPParserRegisterTests(void) +{ +#ifdef UNITTESTS +#endif +} + +#endif /* HAVE_RUST */ diff --git a/src/app-layer-nfs3-udp.h b/src/app-layer-nfs3-udp.h new file mode 100644 index 0000000000..5c3be9a204 --- /dev/null +++ b/src/app-layer-nfs3-udp.h @@ -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 Victor Julien + */ + +#ifndef __APP_LAYER_NFS3_UDP_H__ +#define __APP_LAYER_NFS3_UDP_H__ + +void RegisterNFS3UDPParsers(void); +void NFS3UDPParserRegisterTests(void); + +/** Opaque Rust types. */ +typedef struct NFS3tate_ NFS3State; +typedef struct NFS3Transaction_ NFS3Transaction; + +#endif /* __APP_LAYER_NFS3_H__ */ diff --git a/src/app-layer-parser.c b/src/app-layer-parser.c index 066e54bc47..8d91b332ff 100644 --- a/src/app-layer-parser.c +++ b/src/app-layer-parser.c @@ -61,6 +61,7 @@ #include "app-layer-enip.h" #include "app-layer-dnp3.h" #include "app-layer-nfs3.h" +#include "app-layer-nfs3-udp.h" #include "app-layer-template.h" #include "conf.h" @@ -1384,6 +1385,7 @@ void AppLayerParserRegisterProtocolParsers(void) RegisterENIPTCPParsers(); RegisterDNP3Parsers(); RegisterNFS3Parsers(); + RegisterNFS3UDPParsers(); RegisterTemplateParsers(); /** IMAP */ diff --git a/src/output-json-nfs3.c b/src/output-json-nfs3.c index 20f1d4d1d2..ee988141de 100644 --- a/src/output-json-nfs3.c +++ b/src/output-json-nfs3.c @@ -130,6 +130,7 @@ static OutputCtx *OutputNFS3LogInitSub(ConfNode *conf, SCLogDebug("NFS3 log sub-module initialized."); AppLayerParserRegisterLogger(IPPROTO_TCP, ALPROTO_NFS3); + AppLayerParserRegisterLogger(IPPROTO_UDP, ALPROTO_NFS3); return output_ctx; }