suricata
app-layer-nfs-udp.c
Go to the documentation of this file.
1 /* Copyright (C) 2015-2020 Open Information Security Foundation
2  *
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
5  * Software Foundation.
6  *
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.
11  *
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
15  * 02110-1301, USA.
16  */
17 
18 /**
19  * \file
20  *
21  * \author Victor Julien <victor@inliniac.net>
22  *
23  * NFS application layer detector and parser
24  */
25 
26 #include "suricata-common.h"
27 #include "stream.h"
28 #include "conf.h"
29 
30 #include "util-unittest.h"
31 
32 #include "app-layer-detect-proto.h"
33 #include "app-layer-parser.h"
34 
35 #include "app-layer-nfs-udp.h"
36 
37 #include "rust.h"
38 
39 /* The default port to probe for echo traffic if not provided in the
40  * configuration file. */
41 #define NFS_DEFAULT_PORT "2049"
42 
43 /* The minimum size for a RFC message. For some protocols this might
44  * be the size of a header. TODO actual min size is likely larger */
45 #define NFS_MIN_FRAME_LEN 32
46 
47 /* Enum of app-layer events for an echo protocol. Normally you might
48  * have events for errors in parsing data, like unexpected data being
49  * received. For echo we'll make something up, and log an app-layer
50  * level alert if an empty message is received.
51  *
52  * Example rule:
53  *
54  * alert nfs any any -> any any (msg:"SURICATA NFS empty message"; \
55  * app-layer-event:nfs.empty_message; sid:X; rev:Y;)
56  */
57 enum {
59 };
60 
62  {"EMPTY_MESSAGE", NFS_DECODER_EVENT_EMPTY_MESSAGE},
63  { NULL, 0 }
64 };
65 
66 static void *NFSStateAlloc(void)
67 {
68  return rs_nfs_state_new();
69 }
70 
71 static void NFSStateFree(void *state)
72 {
73  rs_nfs_state_free(state);
74 }
75 
76 /**
77  * \brief Callback from the application layer to have a transaction freed.
78  *
79  * \param state a void pointer to the NFSState object.
80  * \param tx_id the transaction ID to free.
81  */
82 static void NFSStateTxFree(void *state, uint64_t tx_id)
83 {
84  rs_nfs_state_tx_free(state, tx_id);
85 }
86 
87 static int NFSStateGetEventInfo(const char *event_name, int *event_id,
88  AppLayerEventType *event_type)
89 {
90  return rs_nfs_state_get_event_info(event_name, event_id, event_type);
91 }
92 
93 static int NFSStateGetEventInfoById(int event_id, const char **event_name,
94  AppLayerEventType *event_type)
95 {
96  *event_name = "NFS UDP event name (generic)";
98  return 0;
99 }
100 
101 static AppLayerDecoderEvents *NFSGetEvents(void *tx)
102 {
103  return rs_nfs_state_get_events(tx);
104 }
105 
106 /**
107  * \brief Probe the input to see if it looks like echo.
108  *
109  * \retval ALPROTO_NFS if it looks like echo, otherwise
110  * ALPROTO_UNKNOWN.
111  */
112 static AppProto NFSProbingParser(Flow *f, uint8_t direction,
113  const uint8_t *input, uint32_t input_len, uint8_t *rdir)
114 {
115  SCLogDebug("probing");
116  if (input_len < NFS_MIN_FRAME_LEN) {
117  SCLogDebug("unknown");
118  return ALPROTO_UNKNOWN;
119  }
120 
121  int8_t r = 0;
122  if (direction & STREAM_TOSERVER)
123  r = rs_nfs_probe_udp_ts(input, input_len);
124  else
125  r = rs_nfs_probe_udp_tc(input, input_len);
126 
127  if (r == 1) {
128  SCLogDebug("nfs");
129  return ALPROTO_NFS;
130  } else if (r == -1) {
131  SCLogDebug("failed");
132  return ALPROTO_FAILED;
133  }
134 
135  SCLogDebug("Protocol not detected as ALPROTO_NFS.");
136  return ALPROTO_UNKNOWN;
137 }
138 
139 static AppLayerResult NFSParseRequest(Flow *f, void *state,
140  AppLayerParserState *pstate, const uint8_t *input, uint32_t input_len,
141  void *local_data, const uint8_t flags)
142 {
143  uint16_t file_flags = FileFlowToFlags(f, STREAM_TOSERVER);
144  rs_nfs_setfileflags(0, state, file_flags);
145 
146  AppLayerResult res = rs_nfs_parse_request_udp(f, state, pstate,
147  input, input_len, local_data);
149 }
150 
151 static AppLayerResult NFSParseResponse(Flow *f, void *state, AppLayerParserState *pstate,
152  const uint8_t *input, uint32_t input_len, void *local_data,
153  const uint8_t flags)
154 {
155  uint16_t file_flags = FileFlowToFlags(f, STREAM_TOCLIENT);
156  rs_nfs_setfileflags(1, state, file_flags);
157 
158  AppLayerResult res = rs_nfs_parse_response_udp(f, state, pstate,
159  input, input_len, local_data);
161 }
162 
163 static uint64_t NFSGetTxCnt(void *state)
164 {
165  return rs_nfs_state_get_tx_count(state);
166 }
167 
168 static void *NFSGetTx(void *state, uint64_t tx_id)
169 {
170  return rs_nfs_state_get_tx(state, tx_id);
171 }
172 
173 static AppLayerGetTxIterTuple RustNFSGetTxIterator(
174  const uint8_t ipproto, const AppProto alproto,
175  void *alstate, uint64_t min_tx_id, uint64_t max_tx_id,
176  AppLayerGetTxIterState *istate)
177 {
178  return rs_nfs_state_get_tx_iterator(alstate, min_tx_id, (uint64_t *)istate);
179 }
180 
181 static void NFSSetTxLogged(void *state, void *vtx, LoggerId logged)
182 {
183  rs_nfs_tx_set_logged(state, vtx, logged);
184 }
185 
186 static LoggerId NFSGetTxLogged(void *state, void *vtx)
187 {
188  return rs_nfs_tx_get_logged(state, vtx);
189 }
190 
191 /**
192  * \brief Called by the application layer.
193  *
194  * In most cases 1 can be returned here.
195  */
196 static int NFSGetAlstateProgressCompletionStatus(uint8_t direction) {
197  return rs_nfs_state_progress_completion_status(direction);
198 }
199 
200 /**
201  * \brief Return the state of a transaction in a given direction.
202  *
203  * In the case of the echo protocol, the existence of a transaction
204  * means that the request is done. However, some protocols that may
205  * need multiple chunks of data to complete the request may need more
206  * than just the existence of a transaction for the request to be
207  * considered complete.
208  *
209  * For the response to be considered done, the response for a request
210  * needs to be seen. The response_done flag is set on response for
211  * checking here.
212  */
213 static int NFSGetStateProgress(void *tx, uint8_t direction)
214 {
215  return rs_nfs_tx_get_alstate_progress(tx, direction);
216 }
217 
218 /**
219  * \brief get stored tx detect state
220  */
221 static DetectEngineState *NFSGetTxDetectState(void *vtx)
222 {
223  return rs_nfs_state_get_tx_detect_state(vtx);
224 }
225 
226 /**
227  * \brief set store tx detect state
228  */
229 static int NFSSetTxDetectState(void *vtx, DetectEngineState *s)
230 {
231  rs_nfs_state_set_tx_detect_state(vtx, s);
232  return 0;
233 }
234 
235 static FileContainer *NFSGetFiles(void *state, uint8_t direction)
236 {
237  return rs_nfs_getfiles(direction, state);
238 }
239 
240 static void NFSSetDetectFlags(void *tx, uint8_t dir, uint64_t flags)
241 {
242  rs_nfs_tx_set_detect_flags(tx, dir, flags);
243 }
244 
245 static uint64_t NFSGetDetectFlags(void *tx, uint8_t dir)
246 {
247  return rs_nfs_tx_get_detect_flags(tx, dir);
248 }
249 
251 static SuricataFileContext sfc = { &sbcfg };
252 
254 {
255  const char *proto_name = "nfs";
256 
257  /* Check if NFS TCP detection is enabled. If it does not exist in
258  * the configuration file then it will be enabled by default. */
259  if (AppLayerProtoDetectConfProtoDetectionEnabled("udp", proto_name)) {
260 
261  rs_nfs_init(&sfc);
262 
263  SCLogDebug("NFS UDP protocol detection enabled.");
264 
266 
267  if (RunmodeIsUnittests()) {
268 
269  SCLogDebug("Unittest mode, registering default configuration.");
272  NFSProbingParser, NFSProbingParser);
273 
274  }
275  else {
276 
277  if (!AppLayerProtoDetectPPParseConfPorts("udp", IPPROTO_UDP,
278  proto_name, ALPROTO_NFS, 0, NFS_MIN_FRAME_LEN,
279  NFSProbingParser, NFSProbingParser)) {
280  SCLogDebug("No NFS app-layer configuration, enabling NFS"
281  " detection TCP detection on port %s.",
283  AppLayerProtoDetectPPRegister(IPPROTO_UDP,
286  NFSProbingParser, NFSProbingParser);
287  }
288 
289  }
290 
291  }
292 
293  else {
294  SCLogDebug("Protocol detecter and parser disabled for NFS.");
295  return;
296  }
297 
298  if (AppLayerParserConfParserEnabled("udp", proto_name))
299  {
300  SCLogDebug("Registering NFS protocol parser.");
301 
302  /* Register functions for state allocation and freeing. A
303  * state is allocated for every new NFS flow. */
305  NFSStateAlloc, NFSStateFree);
306 
307  /* Register request parser for parsing frame from server to client. */
309  STREAM_TOSERVER, NFSParseRequest);
310 
311  /* Register response parser for parsing frames from server to client. */
313  STREAM_TOCLIENT, NFSParseResponse);
314 
315  /* Register a function to be called by the application layer
316  * when a transaction is to be freed. */
318  NFSStateTxFree);
319 
321  NFSGetTxLogged, NFSSetTxLogged);
322 
323  /* Register a function to return the current transaction count. */
325  NFSGetTxCnt);
326 
327  /* Transaction handling. */
329  NFSGetAlstateProgressCompletionStatus);
331  ALPROTO_NFS, NFSGetStateProgress);
333  NFSGetTx);
335  RustNFSGetTxIterator);
336 
337  AppLayerParserRegisterGetFilesFunc(IPPROTO_UDP, ALPROTO_NFS, NFSGetFiles);
338 
339  /* What is this being registered for? */
341  NFSGetTxDetectState, NFSSetTxDetectState);
342 
344  NFSStateGetEventInfo);
345 
347  NFSStateGetEventInfoById);
348 
350  NFSGetEvents);
351 
353  NFSGetDetectFlags, NFSSetDetectFlags);
354 
355  }
356  else {
357  SCLogNotice("NFS protocol parsing disabled.");
358  }
359 
360 #ifdef UNITTESTS
363 #endif
364 }
365 
366 #ifdef UNITTESTS
367 #endif
368 
370 {
371 #ifdef UNITTESTS
372 #endif
373 }
app-layer-nfs-udp.h
AppLayerParserRegisterGetStateProgressFunc
void AppLayerParserRegisterGetStateProgressFunc(uint8_t ipproto, AppProto alproto, int(*StateGetProgress)(void *alstate, uint8_t direction))
Definition: app-layer-parser.c:490
AppLayerProtoDetectPPParseConfPorts
int AppLayerProtoDetectPPParseConfPorts(const char *ipproto_name, uint8_t ipproto, const char *alproto_name, AppProto alproto, uint16_t min_depth, uint16_t max_depth, ProbingParserFPtr ProbingParserTs, ProbingParserFPtr ProbingParserTc)
Definition: app-layer-detect-proto.c:1645
FileContainer_
Definition: util-file.h:100
AppLayerParserRegisterStateFuncs
void AppLayerParserRegisterStateFuncs(uint8_t ipproto, AppProto alproto, void *(*StateAlloc)(void), void(*StateFree)(void *))
Definition: app-layer-parser.c:397
DetectEngineState_
Definition: detect-engine-state.h:92
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:298
AppLayerParserRegisterDetectFlagsFuncs
void AppLayerParserRegisterDetectFlagsFuncs(uint8_t ipproto, AppProto alproto, uint64_t(*GetTxDetectFlags)(void *tx, uint8_t dir), void(*SetTxDetectFlags)(void *tx, uint8_t dir, uint64_t))
Definition: app-layer-parser.c:589
AppLayerParserRegisterLoggerFuncs
void AppLayerParserRegisterLoggerFuncs(uint8_t ipproto, AppProto alproto, LoggerId(*StateGetTxLogged)(void *, void *), void(*StateSetTxLogged)(void *, void *, LoggerId))
Definition: app-layer-parser.c:447
AppProto
uint16_t AppProto
Definition: app-layer-protos.h:71
AppLayerParserConfParserEnabled
int AppLayerParserConfParserEnabled(const char *ipproto, const char *alproto_name)
check if a parser is enabled in the config Returns enabled always if: were running unittests
Definition: app-layer-parser.c:302
STREAMING_BUFFER_CONFIG_INITIALIZER
#define STREAMING_BUFFER_CONFIG_INITIALIZER
Definition: util-streaming-buffer.h:77
Flow_
Flow data structure.
Definition: flow.h:343
AppLayerEventType
enum AppLayerEventType_ AppLayerEventType
AppLayerParserRegisterGetEventsFunc
void AppLayerParserRegisterGetEventsFunc(uint8_t ipproto, AppProto alproto, AppLayerDecoderEvents *(*StateGetEvents)(void *))
Definition: app-layer-parser.c:436
LoggerId
LoggerId
Definition: suricata-common.h:439
logged
int logged
Definition: app-layer-htp.h:1
AppLayerParserRegisterTxFreeFunc
void AppLayerParserRegisterTxFreeFunc(uint8_t ipproto, AppProto alproto, void(*StateTransactionFree)(void *, uint64_t))
Definition: app-layer-parser.c:501
rust.h
AppLayerParserRegisterDetectStateFuncs
void AppLayerParserRegisterDetectStateFuncs(uint8_t ipproto, AppProto alproto, DetectEngineState *(*GetTxDetectState)(void *tx), int(*SetTxDetectState)(void *tx, DetectEngineState *))
Definition: app-layer-parser.c:577
AppLayerDecoderEvents_
Data structure to store app layer decoder events.
Definition: app-layer-events.h:34
util-unittest.h
APP_LAYER_EVENT_TYPE_TRANSACTION
@ APP_LAYER_EVENT_TYPE_TRANSACTION
Definition: app-layer-events.h:57
AppLayerProtoDetectPPRegister
void AppLayerProtoDetectPPRegister(uint8_t ipproto, const char *portstr, AppProto alproto, uint16_t min_depth, uint16_t max_depth, uint8_t direction, ProbingParserFPtr ProbingParser1, ProbingParserFPtr ProbingParser2)
register parser at a port
Definition: app-layer-detect-proto.c:1611
app-layer-detect-proto.h
AppLayerParserState_
Definition: app-layer-parser.c:155
FileFlowToFlags
uint16_t FileFlowToFlags(const Flow *flow, uint8_t direction)
Definition: util-file.c:231
STREAM_TOSERVER
#define STREAM_TOSERVER
Definition: stream.h:31
res
PoolThreadReserved res
Definition: stream-tcp-private.h:0
AppLayerParserRegisterGetFilesFunc
void AppLayerParserRegisterGetFilesFunc(uint8_t ipproto, AppProto alproto, FileContainer *(*StateGetFiles)(void *, uint8_t))
Definition: app-layer-parser.c:425
NFS_DECODER_EVENT_EMPTY_MESSAGE
@ NFS_DECODER_EVENT_EMPTY_MESSAGE
Definition: app-layer-nfs-udp.c:58
app-layer-parser.h
stream.h
AppLayerParserRegisterProtocolUnittests
void AppLayerParserRegisterProtocolUnittests(uint8_t ipproto, AppProto alproto, void(*RegisterUnittests)(void))
Definition: app-layer-parser.c:1707
AppLayerGetTxIterState
Definition: app-layer-parser.h:114
conf.h
AppLayerParserRegisterGetEventInfo
void AppLayerParserRegisterGetEventInfo(uint8_t ipproto, AppProto alproto, int(*StateGetEventInfo)(const char *event_name, int *event_id, AppLayerEventType *event_type))
Definition: app-layer-parser.c:565
AppLayerProtoDetectRegisterProtocol
void AppLayerProtoDetectRegisterProtocol(AppProto alproto, const char *alproto_name)
Registers a protocol for protocol detection phase.
Definition: app-layer-detect-proto.c:1826
RunmodeIsUnittests
int RunmodeIsUnittests(void)
Definition: suricata.c:264
AppLayerParserRegisterParser
int AppLayerParserRegisterParser(uint8_t ipproto, AppProto alproto, uint8_t direction, AppLayerParserFPtr Parser)
Register app layer parser for the protocol.
Definition: app-layer-parser.c:364
AppLayerParserRegisterGetStateProgressCompletionStatus
void AppLayerParserRegisterGetStateProgressCompletionStatus(AppProto alproto, int(*StateGetProgressCompletionStatus)(uint8_t direction))
Definition: app-layer-parser.c:542
AppLayerParserRegisterGetTx
void AppLayerParserRegisterGetTx(uint8_t ipproto, AppProto alproto, void *(StateGetTx)(void *alstate, uint64_t tx_id))
Definition: app-layer-parser.c:523
SCReturnStruct
#define SCReturnStruct(x)
Definition: util-debug.h:320
flags
uint8_t flags
Definition: decode-gre.h:0
suricata-common.h
SCEnumCharMap_
Definition: util-enum.h:27
STREAM_TOCLIENT
#define STREAM_TOCLIENT
Definition: stream.h:32
StreamingBufferConfig_
Definition: util-streaming-buffer.h:67
NFS_DEFAULT_PORT
#define NFS_DEFAULT_PORT
Definition: app-layer-nfs-udp.c:41
AppLayerParserRegisterGetTxIterator
void AppLayerParserRegisterGetTxIterator(uint8_t ipproto, AppProto alproto, AppLayerGetTxIteratorFunc Func)
Definition: app-layer-parser.c:534
SuricataFileContext_
Definition: rust-context.h:51
AppLayerParserRegisterGetEventInfoById
void AppLayerParserRegisterGetEventInfoById(uint8_t ipproto, AppProto alproto, int(*StateGetEventInfoById)(int event_id, const char **event_name, AppLayerEventType *event_type))
Definition: app-layer-parser.c:553
ALPROTO_UNKNOWN
@ ALPROTO_UNKNOWN
Definition: app-layer-protos.h:29
ALPROTO_FAILED
@ ALPROTO_FAILED
Definition: app-layer-protos.h:61
nfs_udp_decoder_event_table
SCEnumCharMap nfs_udp_decoder_event_table[]
Definition: app-layer-nfs-udp.c:61
NFS_MIN_FRAME_LEN
#define NFS_MIN_FRAME_LEN
Definition: app-layer-nfs-udp.c:45
AppLayerParserRegisterGetTxCnt
void AppLayerParserRegisterGetTxCnt(uint8_t ipproto, AppProto alproto, uint64_t(*StateGetTxCnt)(void *alstate))
Definition: app-layer-parser.c:512
SCLogNotice
#define SCLogNotice(...)
Macro used to log NOTICE messages.
Definition: util-debug.h:232
RegisterNFSUDPParsers
void RegisterNFSUDPParsers(void)
Definition: app-layer-nfs-udp.c:253
AppLayerProtoDetectConfProtoDetectionEnabled
int AppLayerProtoDetectConfProtoDetectionEnabled(const char *ipproto, const char *alproto)
Given a protocol name, checks if proto detection is enabled in the conf file.
Definition: app-layer-detect-proto.c:1890
ALPROTO_NFS
@ ALPROTO_NFS
Definition: app-layer-protos.h:45
NFSUDPParserRegisterTests
void NFSUDPParserRegisterTests(void)
Definition: app-layer-nfs-udp.c:369