]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
nfs: Add rust registration function
authorShivani Bhardwaj <shivanib134@gmail.com>
Thu, 24 Jun 2021 10:42:55 +0000 (16:12 +0530)
committerShivani Bhardwaj <shivanib134@gmail.com>
Thu, 5 Aug 2021 15:43:31 +0000 (21:13 +0530)
Get rid of the C glue code and move registration completely to Rust.

rust/src/nfs/nfs.rs
src/app-layer-nfs-tcp.c
src/app-layer-nfs-udp.c

index acd6a137845f7400a4d545e06b7dffb93275a9b4..49c022a041ddc47e974e40b5080896bac7fade15 100644 (file)
@@ -21,13 +21,14 @@ use std;
 use std::cmp;
 use std::mem::transmute;
 use std::collections::{HashMap};
-use std::ffi::CStr;
+use std::ffi::{CStr, CString};
 
 use nom;
 
 use crate::applayer;
-use crate::applayer::{AppLayerResult, AppLayerTxData};
+use crate::applayer::*;
 use crate::core::*;
+use crate::conf::*;
 use crate::filetracker::*;
 use crate::filecontainer::*;
 
@@ -39,6 +40,8 @@ use crate::nfs::nfs3_records::*;
 
 pub static mut SURICATA_NFS_FILE_CONFIG: Option<&'static SuricataFileContext> = None;
 
+pub const NFS_MIN_FRAME_LEN: u16 = 32;
+
 static mut ALPROTO_NFS: AppProto = ALPROTO_UNKNOWN;
 /*
  * Record parsing.
@@ -1926,3 +1929,155 @@ pub extern "C" fn rs_nfs_setfileflags(direction: u8, ptr: *mut NFSState, flags:
     parser.setfileflags(direction, flags)
 }
 
+// Parser name as a C style string.
+const PARSER_NAME: &'static [u8] = b"nfs\0";
+
+#[no_mangle]
+pub unsafe extern "C" fn rs_nfs_register_parser() {
+    let default_port = CString::new("[2049]").unwrap();
+    let parser = RustParser {
+        name: PARSER_NAME.as_ptr() as *const std::os::raw::c_char,
+        default_port: default_port.as_ptr(),
+        ipproto: IPPROTO_TCP,
+        probe_ts: None,
+        probe_tc: None,
+        min_depth: 0,
+        max_depth: 16,
+        state_new: rs_nfs_state_new,
+        state_free: rs_nfs_state_free,
+        tx_free: rs_nfs_state_tx_free,
+        parse_ts: rs_nfs_parse_request,
+        parse_tc: rs_nfs_parse_response,
+        get_tx_count: rs_nfs_state_get_tx_count,
+        get_tx: rs_nfs_state_get_tx,
+        tx_comp_st_ts: 1,
+        tx_comp_st_tc: 1,
+        tx_get_progress: rs_nfs_tx_get_alstate_progress,
+        get_de_state: rs_nfs_state_get_tx_detect_state,
+        set_de_state: rs_nfs_state_set_tx_detect_state,
+        get_events: Some(rs_nfs_state_get_events),
+        get_eventinfo: Some(rs_nfs_state_get_event_info),
+        get_eventinfo_byid : Some(rs_nfs_state_get_event_info_by_id),
+        localstorage_new: None,
+        localstorage_free: None,
+        get_files: Some(rs_nfs_getfiles),
+        get_tx_iterator: Some(rs_nfs_state_get_tx_iterator),
+        get_tx_data: rs_nfs_get_tx_data,
+        apply_tx_config: None,
+        flags: APP_LAYER_PARSER_OPT_ACCEPT_GAPS,
+        truncate: None,
+    };
+
+    let ip_proto_str = CString::new("tcp").unwrap();
+
+    if AppLayerProtoDetectConfProtoDetectionEnabled(
+        ip_proto_str.as_ptr(),
+        parser.name,
+    ) != 0
+    {
+        let alproto = AppLayerRegisterProtocolDetection(&parser, 1);
+        ALPROTO_NFS = alproto;
+
+        let midstream = conf_get_bool("stream.midstream");
+        if midstream == true {
+            if AppLayerProtoDetectPPParseConfPorts(ip_proto_str.as_ptr(), IPPROTO_TCP as u8,
+                    parser.name, ALPROTO_NFS, 0, NFS_MIN_FRAME_LEN,
+                    rs_nfs_probe_ms, rs_nfs_probe_ms) == 0 {
+                SCLogDebug!("No NFSTCP app-layer configuration, enabling NFSTCP
+                            detection TCP detection on port {:?}.",
+                            default_port);
+                /* register 'midstream' probing parsers if midstream is enabled. */
+                AppLayerProtoDetectPPRegister(IPPROTO_TCP as u8,
+                    default_port.as_ptr(), ALPROTO_NFS, 0,
+                    NFS_MIN_FRAME_LEN, STREAM_TOSERVER,
+                    rs_nfs_probe_ms, rs_nfs_probe_ms);
+            }
+        } else {
+            AppLayerProtoDetectPPRegister(IPPROTO_TCP as u8,
+                default_port.as_ptr(), ALPROTO_NFS, 0,
+                NFS_MIN_FRAME_LEN, STREAM_TOSERVER,
+                rs_nfs_probe, rs_nfs_probe);
+        }
+        if AppLayerParserConfParserEnabled(
+            ip_proto_str.as_ptr(),
+            parser.name,
+        ) != 0
+        {
+            let _ = AppLayerRegisterParser(&parser, alproto);
+        }
+        SCLogDebug!("Rust nfs parser registered.");
+    } else {
+        SCLogDebug!("Protocol detector and parser disabled for nfs.");
+    }
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn rs_nfs_udp_register_parser() {
+    let default_port = CString::new("[2049]").unwrap();
+    let parser = RustParser {
+        name: PARSER_NAME.as_ptr() as *const std::os::raw::c_char,
+        default_port: default_port.as_ptr(),
+        ipproto: IPPROTO_UDP,
+        probe_ts: None,
+        probe_tc: None,
+        min_depth: 0,
+        max_depth: 16,
+        state_new: rs_nfs_state_new,
+        state_free: rs_nfs_state_free,
+        tx_free: rs_nfs_state_tx_free,
+        parse_ts: rs_nfs_parse_request_udp,
+        parse_tc: rs_nfs_parse_response_udp,
+        get_tx_count: rs_nfs_state_get_tx_count,
+        get_tx: rs_nfs_state_get_tx,
+        tx_comp_st_ts: 1,
+        tx_comp_st_tc: 1,
+        tx_get_progress: rs_nfs_tx_get_alstate_progress,
+        get_de_state: rs_nfs_state_get_tx_detect_state,
+        set_de_state: rs_nfs_state_set_tx_detect_state,
+        get_events: Some(rs_nfs_state_get_events),
+        get_eventinfo: Some(rs_nfs_state_get_event_info),
+        get_eventinfo_byid : None,
+        localstorage_new: None,
+        localstorage_free: None,
+        get_files: Some(rs_nfs_getfiles),
+        get_tx_iterator: Some(rs_nfs_state_get_tx_iterator),
+        get_tx_data: rs_nfs_get_tx_data,
+        apply_tx_config: None,
+        flags: APP_LAYER_PARSER_OPT_UNIDIR_TXS,
+        truncate: None,
+    };
+
+    let ip_proto_str = CString::new("udp").unwrap();
+
+    if AppLayerProtoDetectConfProtoDetectionEnabled(
+        ip_proto_str.as_ptr(),
+        parser.name,
+    ) != 0
+    {
+        let alproto = AppLayerRegisterProtocolDetection(&parser, 1);
+        ALPROTO_NFS = alproto;
+
+        if AppLayerProtoDetectPPParseConfPorts(ip_proto_str.as_ptr(), IPPROTO_UDP as u8,
+                parser.name, ALPROTO_NFS, 0, NFS_MIN_FRAME_LEN,
+                rs_nfs_probe_udp_ts, rs_nfs_probe_udp_tc) == 0 {
+            SCLogDebug!("No NFSUDP app-layer configuration, enabling NFSUDP
+                        detection UDP detection on port {:?}.",
+                        default_port);
+            AppLayerProtoDetectPPRegister(IPPROTO_UDP as u8,
+                default_port.as_ptr(), ALPROTO_NFS, 0,
+                NFS_MIN_FRAME_LEN, STREAM_TOSERVER,
+                rs_nfs_probe_udp_ts, rs_nfs_probe_udp_tc);
+        }
+        if AppLayerParserConfParserEnabled(
+            ip_proto_str.as_ptr(),
+            parser.name,
+        ) != 0
+        {
+            let _ = AppLayerRegisterParser(&parser, alproto);
+        }
+        SCLogDebug!("Rust nfs parser registered.");
+    } else {
+        SCLogDebug!("Protocol detector and parser disabled for nfs.");
+    }
+}
+
index 8599e04922878dca91cb59dc672c8b9b8ad2c9ec..657db59c705640f88154fac521a5bcd3aeb1b37e 100644 (file)
 
 #include "rust.h"
 
-/* The default port to probe for echo traffic if not provided in the
- * configuration file. */
-#define NFSTCP_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 NFSTCP_MIN_FRAME_LEN 32
-
-static void *NFSTCPStateAlloc(void *orig_state, AppProto proto_orig)
-{
-    return rs_nfs_state_new(orig_state, proto_orig);
-}
-
-static void NFSTCPStateFree(void *state)
-{
-    rs_nfs_state_free(state);
-}
-
-/**
- * \brief Callback from the application layer to have a transaction freed.
- *
- * \param state a void pointer to the NFSTCPState object.
- * \param tx_id the transaction ID to free.
- */
-static void NFSTCPStateTxFree(void *state, uint64_t tx_id)
-{
-    rs_nfs_state_tx_free(state, tx_id);
-}
-
-static int NFSTCPStateGetEventInfo(const char *event_name, int *event_id,
-    AppLayerEventType *event_type)
-{
-    return rs_nfs_state_get_event_info(event_name, event_id, event_type);
-}
-
-static int NFSTCPStateGetEventInfoById(int event_id, const char **event_name,
-    AppLayerEventType *event_type)
-{
-    return rs_nfs_state_get_event_info_by_id(event_id, event_name, event_type);
-}
-
-static AppLayerDecoderEvents *NFSTCPGetEvents(void *tx)
-{
-    return rs_nfs_state_get_events(tx);
-}
-
-/**
- * \brief Probe the input to see if it looks like echo.
- *
- * \retval ALPROTO_NFS if it looks like echo, otherwise
- *     ALPROTO_UNKNOWN.
- */
-static AppProto NFSTCPProbingParserMidstream(Flow *f,
-        uint8_t direction,
-        const uint8_t *input, uint32_t input_len,
-        uint8_t *rdir)
-{
-    if (input_len < NFSTCP_MIN_FRAME_LEN) {
-        return ALPROTO_UNKNOWN;
-    }
-
-    int8_t r = rs_nfs_probe_ms(f, direction, input, input_len, rdir);
-    if (r == 1) {
-        return ALPROTO_NFS;
-    } else if (r == -1) {
-        return ALPROTO_FAILED;
-    }
-
-    SCLogDebug("Protocol not detected as ALPROTO_NFS.");
-    return ALPROTO_UNKNOWN;
-}
-
-/**
- * \brief Probe the input to see if it looks like echo.
- *
- * \retval ALPROTO_NFS if it looks like echo, otherwise
- *     ALPROTO_UNKNOWN.
- */
-static AppProto NFSTCPProbingParser(Flow *f,
-        uint8_t direction,
-        const uint8_t *input, uint32_t input_len,
-        uint8_t *rdir)
-{
-    if (input_len < NFSTCP_MIN_FRAME_LEN) {
-        return ALPROTO_UNKNOWN;
-    }
-
-    int8_t r = rs_nfs_probe(f, direction, input, input_len, rdir);
-    if (r == 1) {
-        return ALPROTO_NFS;
-    } else if (r == -1) {
-        return ALPROTO_FAILED;
-    }
-
-    SCLogDebug("Protocol not detected as ALPROTO_NFS.");
-    return ALPROTO_UNKNOWN;
-}
-
-static AppLayerResult NFSTCPParseRequest(Flow *f, void *state,
-    AppLayerParserState *pstate, const uint8_t *input, uint32_t input_len,
-    void *local_data, const uint8_t flags)
-{
-    uint16_t file_flags = FileFlowToFlags(f, STREAM_TOSERVER);
-    rs_nfs_setfileflags(0, state, file_flags);
-
-    if (input == NULL && input_len > 0) {
-        AppLayerResult res = rs_nfs_parse_request_tcp_gap(state, input_len);
-        SCReturnStruct(res);
-    } else {
-        AppLayerResult res =
-                rs_nfs_parse_request(f, state, pstate, input, input_len, local_data, flags);
-        SCReturnStruct(res);
-    }
-}
-
-static AppLayerResult NFSTCPParseResponse(Flow *f, void *state, AppLayerParserState *pstate,
-    const uint8_t *input, uint32_t input_len, void *local_data,
-    const uint8_t flags)
-{
-    uint16_t file_flags = FileFlowToFlags(f, STREAM_TOCLIENT);
-    rs_nfs_setfileflags(1, state, file_flags);
-
-    if (input == NULL && input_len > 0) {
-        AppLayerResult res = rs_nfs_parse_response_tcp_gap(state, input_len);
-        SCReturnStruct(res);
-    } else {
-        AppLayerResult res =
-                rs_nfs_parse_response(f, state, pstate, input, input_len, local_data, flags);
-        SCReturnStruct(res);
-    }
-}
-
-static uint64_t NFSTCPGetTxCnt(void *state)
-{
-    return rs_nfs_state_get_tx_count(state);
-}
-
-static void *NFSTCPGetTx(void *state, uint64_t tx_id)
-{
-    return rs_nfs_state_get_tx(state, tx_id);
-}
-
-static AppLayerGetTxIterTuple RustNFSTCPGetTxIterator(
-        const uint8_t ipproto, const AppProto alproto,
-        void *alstate, uint64_t min_tx_id, uint64_t max_tx_id,
-        AppLayerGetTxIterState *istate)
-{
-    return rs_nfs_state_get_tx_iterator(
-            ipproto, alproto, alstate, min_tx_id, max_tx_id, (uint64_t *)istate);
-}
-
-/**
- * \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 NFSTCPGetStateProgress(void *tx, uint8_t direction)
-{
-    return rs_nfs_tx_get_alstate_progress(tx, direction);
-}
-
-/**
- * \brief get stored tx detect state
- */
-static DetectEngineState *NFSTCPGetTxDetectState(void *vtx)
-{
-    return rs_nfs_state_get_tx_detect_state(vtx);
-}
-
-/**
- * \brief set store tx detect state
- */
-static int NFSTCPSetTxDetectState(void *vtx, DetectEngineState *s)
-{
-    rs_nfs_state_set_tx_detect_state(vtx, s);
-    return 0;
-}
-
-static FileContainer *NFSTCPGetFiles(void *state, uint8_t direction)
-{
-    return rs_nfs_getfiles(state, direction);
-}
 
 static StreamingBufferConfig sbcfg = STREAMING_BUFFER_CONFIG_INITIALIZER;
 static SuricataFileContext sfc = { &sbcfg };
@@ -242,106 +52,6 @@ void RegisterNFSTCPParsers(void)
     if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
 
         rs_nfs_init(&sfc);
-
-        SCLogDebug("NFSTCP TCP protocol detection enabled.");
-
-        AppLayerProtoDetectRegisterProtocol(ALPROTO_NFS, proto_name);
-
-        if (RunmodeIsUnittests()) {
-
-            SCLogDebug("Unittest mode, registering default configuration.");
-            AppLayerProtoDetectPPRegister(IPPROTO_TCP, NFSTCP_DEFAULT_PORT,
-                ALPROTO_NFS, 0, NFSTCP_MIN_FRAME_LEN, STREAM_TOSERVER,
-                NFSTCPProbingParser, NFSTCPProbingParser);
-
-        }
-        else {
-            int midstream = 0;
-            ConfGetBool("stream.midstream", &midstream);
-            ProbingParserFPtr FuncPtr = NFSTCPProbingParser;
-            if (midstream)
-                FuncPtr = NFSTCPProbingParserMidstream;
-
-            if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP,
-                    proto_name, ALPROTO_NFS, 0, NFSTCP_MIN_FRAME_LEN,
-                    FuncPtr, FuncPtr)) {
-                SCLogDebug("No NFSTCP app-layer configuration, enabling NFSTCP"
-                    " detection TCP detection on port %s.",
-                    NFSTCP_DEFAULT_PORT);
-                /* register 'midstream' probing parsers if midstream is enabled. */
-                AppLayerProtoDetectPPRegister(IPPROTO_TCP,
-                    NFSTCP_DEFAULT_PORT, ALPROTO_NFS, 0,
-                    NFSTCP_MIN_FRAME_LEN, STREAM_TOSERVER,
-                    FuncPtr, FuncPtr);
-            }
-
-        }
-
-    }
-
-    else {
-        SCLogDebug("Protocol detecter and parser disabled for NFSTCP.");
-        return;
-    }
-
-    if (AppLayerParserConfParserEnabled("tcp", proto_name))
-    {
-        SCLogDebug("Registering NFSTCP protocol parser.");
-
-        /* Register functions for state allocation and freeing. A
-         * state is allocated for every new NFSTCP flow. */
-        AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_NFS,
-            NFSTCPStateAlloc, NFSTCPStateFree);
-
-        /* Register request parser for parsing frame from server to client. */
-        AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_NFS,
-            STREAM_TOSERVER, NFSTCPParseRequest);
-
-        /* Register response parser for parsing frames from server to client. */
-        AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_NFS,
-            STREAM_TOCLIENT, NFSTCPParseResponse);
-
-        /* Register a function to be called by the application layer
-         * when a transaction is to be freed. */
-        AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_NFS,
-            NFSTCPStateTxFree);
-
-        /* Register a function to return the current transaction count. */
-        AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_NFS,
-            NFSTCPGetTxCnt);
-
-        /* Transaction handling. */
-        AppLayerParserRegisterStateProgressCompletionStatus(ALPROTO_NFS, 1, 1);
-        AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP,
-            ALPROTO_NFS, NFSTCPGetStateProgress);
-        AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_NFS,
-            NFSTCPGetTx);
-        AppLayerParserRegisterGetTxIterator(IPPROTO_TCP, ALPROTO_NFS,
-                RustNFSTCPGetTxIterator);
-
-        AppLayerParserRegisterGetFilesFunc(IPPROTO_TCP, ALPROTO_NFS, NFSTCPGetFiles);
-
-        /* What is this being registered for? */
-        AppLayerParserRegisterDetectStateFuncs(IPPROTO_TCP, ALPROTO_NFS,
-            NFSTCPGetTxDetectState, NFSTCPSetTxDetectState);
-
-        AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_NFS,
-                NFSTCPStateGetEventInfo);
-
-        AppLayerParserRegisterGetEventInfoById(IPPROTO_TCP, ALPROTO_NFS,
-                NFSTCPStateGetEventInfoById);
-
-        AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_NFS,
-                NFSTCPGetEvents);
-
-        AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_NFS,
-                                         rs_nfs_get_tx_data);
-
-        /* This parser accepts gaps. */
-        AppLayerParserRegisterOptionFlags(IPPROTO_TCP, ALPROTO_NFS,
-                APP_LAYER_PARSER_OPT_ACCEPT_GAPS);
-    }
-    else {
-        SCLogDebug("NFSTCP protocol parsing disabled.");
+        rs_nfs_register_parser();
     }
 }
index 88a72b8579508fc53af3586d54fdb024912a3f06..5bfddeb96364a836c4e8828e7dcb2fa73adb9e72 100644 (file)
 
 #include "rust.h"
 
-/* The default port to probe for echo traffic if not provided in the
- * configuration file. */
-#define NFS_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 NFS_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
@@ -63,266 +55,14 @@ SCEnumCharMap nfs_udp_decoder_event_table[] = {
     { NULL, 0 }
 };
 
-static void *NFSStateAlloc(void *orig_state, AppProto proto_orig)
-{
-    return rs_nfs_state_new(orig_state, proto_orig);
-}
-
-static void NFSStateFree(void *state)
-{
-    rs_nfs_state_free(state);
-}
-
-/**
- * \brief Callback from the application layer to have a transaction freed.
- *
- * \param state a void pointer to the NFSState object.
- * \param tx_id the transaction ID to free.
- */
-static void NFSStateTxFree(void *state, uint64_t tx_id)
-{
-    rs_nfs_state_tx_free(state, tx_id);
-}
-
-static int NFSStateGetEventInfo(const char *event_name, int *event_id,
-    AppLayerEventType *event_type)
-{
-    return rs_nfs_state_get_event_info(event_name, event_id, event_type);
-}
-
-static int NFSStateGetEventInfoById(int event_id, const char **event_name,
-    AppLayerEventType *event_type)
-{
-    *event_name = "NFS UDP event name (generic)";
-    *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
-    return 0;
-}
-
-static AppLayerDecoderEvents *NFSGetEvents(void *tx)
-{
-    return rs_nfs_state_get_events(tx);
-}
-
-/**
- * \brief Probe the input to see if it looks like echo.
- *
- * \retval ALPROTO_NFS if it looks like echo, otherwise
- *     ALPROTO_UNKNOWN.
- */
-static AppProto NFSProbingParser(Flow *f, uint8_t direction,
-        const uint8_t *input, uint32_t input_len, uint8_t *rdir)
-{
-    SCLogDebug("probing");
-    if (input_len < NFS_MIN_FRAME_LEN) {
-        SCLogDebug("unknown");
-        return ALPROTO_UNKNOWN;
-    }
-
-    int8_t r = 0;
-    if (direction & STREAM_TOSERVER)
-        r = rs_nfs_probe_udp_ts(f, direction, input, input_len, rdir);
-    else
-        r = rs_nfs_probe_udp_tc(f, direction, input, input_len, rdir);
-
-    if (r == 1) {
-        SCLogDebug("nfs");
-        return ALPROTO_NFS;
-    } else if (r == -1) {
-        SCLogDebug("failed");
-        return ALPROTO_FAILED;
-    }
-
-    SCLogDebug("Protocol not detected as ALPROTO_NFS.");
-    return ALPROTO_UNKNOWN;
-}
-
-static AppLayerResult NFSParseRequest(Flow *f, void *state,
-    AppLayerParserState *pstate, const uint8_t *input, uint32_t input_len,
-    void *local_data, const uint8_t flags)
-{
-    uint16_t file_flags = FileFlowToFlags(f, STREAM_TOSERVER);
-    rs_nfs_setfileflags(0, state, file_flags);
-
-    AppLayerResult res =
-            rs_nfs_parse_request_udp(f, state, pstate, input, input_len, local_data, flags);
-    SCReturnStruct(res);
-}
-
-static AppLayerResult NFSParseResponse(Flow *f, void *state, AppLayerParserState *pstate,
-    const uint8_t *input, uint32_t input_len, void *local_data,
-    const uint8_t flags)
-{
-    uint16_t file_flags = FileFlowToFlags(f, STREAM_TOCLIENT);
-    rs_nfs_setfileflags(1, state, file_flags);
-
-    AppLayerResult res =
-            rs_nfs_parse_response_udp(f, state, pstate, input, input_len, local_data, flags);
-    SCReturnStruct(res);
-}
-
-static uint64_t NFSGetTxCnt(void *state)
-{
-    return rs_nfs_state_get_tx_count(state);
-}
-
-static void *NFSGetTx(void *state, uint64_t tx_id)
-{
-    return rs_nfs_state_get_tx(state, tx_id);
-}
-
-static AppLayerGetTxIterTuple RustNFSGetTxIterator(
-        const uint8_t ipproto, const AppProto alproto,
-        void *alstate, uint64_t min_tx_id, uint64_t max_tx_id,
-        AppLayerGetTxIterState *istate)
-{
-    return rs_nfs_state_get_tx_iterator(
-            ipproto, alproto, alstate, min_tx_id, max_tx_id, (uint64_t *)istate);
-}
-
-/**
- * \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 NFSGetStateProgress(void *tx, uint8_t direction)
-{
-    return rs_nfs_tx_get_alstate_progress(tx, direction);
-}
-
-/**
- * \brief get stored tx detect state
- */
-static DetectEngineState *NFSGetTxDetectState(void *vtx)
-{
-    return rs_nfs_state_get_tx_detect_state(vtx);
-}
-
-/**
- * \brief set store tx detect state
- */
-static int NFSSetTxDetectState(void *vtx, DetectEngineState *s)
-{
-    rs_nfs_state_set_tx_detect_state(vtx, s);
-    return 0;
-}
-
-static FileContainer *NFSGetFiles(void *state, uint8_t direction)
-{
-    return rs_nfs_getfiles(state, direction);
-}
 
 static StreamingBufferConfig sbcfg = STREAMING_BUFFER_CONFIG_INITIALIZER;
 static SuricataFileContext sfc = { &sbcfg };
 
 void RegisterNFSUDPParsers(void)
 {
-    const char *proto_name = "nfs";
-
-    /* Check if NFS 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_nfs_init(&sfc);
-
-        SCLogDebug("NFS UDP protocol detection enabled.");
-
-        AppLayerProtoDetectRegisterProtocol(ALPROTO_NFS, proto_name);
-
-        if (RunmodeIsUnittests()) {
-
-            SCLogDebug("Unittest mode, registering default configuration.");
-            AppLayerProtoDetectPPRegister(IPPROTO_UDP, NFS_DEFAULT_PORT,
-                ALPROTO_NFS, 0, NFS_MIN_FRAME_LEN, STREAM_TOSERVER,
-                NFSProbingParser, NFSProbingParser);
-
-        }
-        else {
-
-            if (!AppLayerProtoDetectPPParseConfPorts("udp", IPPROTO_UDP,
-                    proto_name, ALPROTO_NFS, 0, NFS_MIN_FRAME_LEN,
-                    NFSProbingParser, NFSProbingParser)) {
-                SCLogDebug("No NFS app-layer configuration, enabling NFS"
-                    " detection TCP detection on port %s.",
-                    NFS_DEFAULT_PORT);
-                AppLayerProtoDetectPPRegister(IPPROTO_UDP,
-                    NFS_DEFAULT_PORT, ALPROTO_NFS, 0,
-                    NFS_MIN_FRAME_LEN, STREAM_TOSERVER,
-                    NFSProbingParser, NFSProbingParser);
-            }
-
-        }
-
-    }
-
-    else {
-        SCLogDebug("Protocol detecter and parser disabled for NFS.");
-        return;
-    }
-
-    if (AppLayerParserConfParserEnabled("udp", proto_name))
-    {
-        SCLogDebug("Registering NFS protocol parser.");
-
-        /* Register functions for state allocation and freeing. A
-         * state is allocated for every new NFS flow. */
-        AppLayerParserRegisterStateFuncs(IPPROTO_UDP, ALPROTO_NFS,
-            NFSStateAlloc, NFSStateFree);
-
-        /* Register request parser for parsing frame from server to client. */
-        AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_NFS,
-            STREAM_TOSERVER, NFSParseRequest);
-
-        /* Register response parser for parsing frames from server to client. */
-        AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_NFS,
-            STREAM_TOCLIENT, NFSParseResponse);
-
-        /* Register a function to be called by the application layer
-         * when a transaction is to be freed. */
-        AppLayerParserRegisterTxFreeFunc(IPPROTO_UDP, ALPROTO_NFS,
-            NFSStateTxFree);
-
-        /* Register a function to return the current transaction count. */
-        AppLayerParserRegisterGetTxCnt(IPPROTO_UDP, ALPROTO_NFS,
-            NFSGetTxCnt);
-
-        /* Transaction handling. */
-        AppLayerParserRegisterStateProgressCompletionStatus(ALPROTO_NFS, 1, 1);
-        AppLayerParserRegisterGetStateProgressFunc(IPPROTO_UDP,
-            ALPROTO_NFS, NFSGetStateProgress);
-        AppLayerParserRegisterGetTx(IPPROTO_UDP, ALPROTO_NFS,
-            NFSGetTx);
-        AppLayerParserRegisterGetTxIterator(IPPROTO_UDP, ALPROTO_NFS,
-                RustNFSGetTxIterator);
-
-        AppLayerParserRegisterGetFilesFunc(IPPROTO_UDP, ALPROTO_NFS, NFSGetFiles);
-
-        /* What is this being registered for? */
-        AppLayerParserRegisterDetectStateFuncs(IPPROTO_UDP, ALPROTO_NFS,
-            NFSGetTxDetectState, NFSSetTxDetectState);
-
-        AppLayerParserRegisterGetEventInfo(IPPROTO_UDP, ALPROTO_NFS,
-            NFSStateGetEventInfo);
-
-        AppLayerParserRegisterGetEventInfoById(IPPROTO_UDP, ALPROTO_NFS,
-            NFSStateGetEventInfoById);
-
-        AppLayerParserRegisterGetEventsFunc(IPPROTO_UDP, ALPROTO_NFS,
-            NFSGetEvents);
-
-        AppLayerParserRegisterTxDataFunc(IPPROTO_UDP, ALPROTO_NFS,
-                rs_nfs_get_tx_data);
-    }
-    else {
-        SCLogNotice("NFS protocol parsing disabled.");
-    }
+    rs_nfs_init(&sfc);
+    rs_nfs_udp_register_parser();
 
 #ifdef UNITTESTS
     AppLayerParserRegisterProtocolUnittests(IPPROTO_UDP, ALPROTO_NFS,