|
|
|
|
@ -39,196 +39,6 @@
|
|
|
|
|
|
|
|
|
|
#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();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|