suricata
app-layer-nfs-udp.c
Go to the documentation of this file.
1 /* Copyright (C) 2015 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 #ifndef HAVE_RUST
39 {
40 }
41 
42 #else
43 
44 #include "rust.h"
45 #include "rust-nfs-nfs-gen.h"
46 
47 /* The default port to probe for echo traffic if not provided in the
48  * configuration file. */
49 #define NFS_DEFAULT_PORT "2049"
50 
51 /* The minimum size for a RFC message. For some protocols this might
52  * be the size of a header. TODO actual min size is likely larger */
53 #define NFS_MIN_FRAME_LEN 32
54 
55 /* Enum of app-layer events for an echo protocol. Normally you might
56  * have events for errors in parsing data, like unexpected data being
57  * received. For echo we'll make something up, and log an app-layer
58  * level alert if an empty message is received.
59  *
60  * Example rule:
61  *
62  * alert nfs any any -> any any (msg:"SURICATA NFS empty message"; \
63  * app-layer-event:nfs.empty_message; sid:X; rev:Y;)
64  */
65 enum {
66  NFS_DECODER_EVENT_EMPTY_MESSAGE,
67 };
68 
69 SCEnumCharMap nfs_udp_decoder_event_table[] = {
70  {"EMPTY_MESSAGE", NFS_DECODER_EVENT_EMPTY_MESSAGE},
71  { NULL, 0 }
72 };
73 
74 static void *NFSStateAlloc(void)
75 {
76  return rs_nfs_state_new();
77 }
78 
79 static void NFSStateFree(void *state)
80 {
81  rs_nfs_state_free(state);
82 }
83 
84 /**
85  * \brief Callback from the application layer to have a transaction freed.
86  *
87  * \param state a void pointer to the NFSState object.
88  * \param tx_id the transaction ID to free.
89  */
90 static void NFSStateTxFree(void *state, uint64_t tx_id)
91 {
92  rs_nfs_state_tx_free(state, tx_id);
93 }
94 
95 static int NFSStateGetEventInfo(const char *event_name, int *event_id,
97 {
98  return rs_nfs_state_get_event_info(event_name, event_id, event_type);
99 }
100 
101 static AppLayerDecoderEvents *NFSGetEvents(void *state, uint64_t id)
102 {
103  return rs_nfs_state_get_events(state, id);
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 NFSProbingParserTS(Flow *f, uint8_t *input, uint32_t input_len)
113 {
114  SCLogDebug("probing");
115  if (input_len < NFS_MIN_FRAME_LEN) {
116  SCLogDebug("unknown");
117  return ALPROTO_UNKNOWN;
118  }
119 
120  int8_t r = rs_nfs_probe_udp_ts(input, input_len);
121  if (r == 1) {
122  SCLogDebug("nfs");
123  return ALPROTO_NFS;
124  } else if (r == -1) {
125  SCLogDebug("failed");
126  return ALPROTO_FAILED;
127  }
128 
129  SCLogDebug("Protocol not detected as ALPROTO_NFS.");
130  return ALPROTO_UNKNOWN;
131 }
132 
133 static AppProto NFSProbingParserTC(Flow *f, uint8_t *input, uint32_t input_len)
134 {
135  SCLogDebug("probing");
136  if (input_len < NFS_MIN_FRAME_LEN) {
137  SCLogDebug("unknown");
138  return ALPROTO_UNKNOWN;
139  }
140 
141  int8_t r = rs_nfs_probe_tc(input, input_len);
142  if (r == 1) {
143  SCLogDebug("nfs");
144  return ALPROTO_NFS;
145  } else if (r == -1) {
146  SCLogDebug("failed");
147  return ALPROTO_FAILED;
148  }
149 
150  SCLogDebug("Protocol not detected as ALPROTO_NFS.");
151  return ALPROTO_UNKNOWN;
152 }
153 
154 static int NFSParseRequest(Flow *f, void *state,
155  AppLayerParserState *pstate, uint8_t *input, uint32_t input_len,
156  void *local_data, const uint8_t flags)
157 {
158  uint16_t file_flags = FileFlowToFlags(f, STREAM_TOSERVER);
159  rs_nfs_setfileflags(0, state, file_flags);
160 
161  return rs_nfs_parse_request_udp(f, state, pstate, input, input_len, local_data);
162 }
163 
164 static int NFSParseResponse(Flow *f, void *state, AppLayerParserState *pstate,
165  uint8_t *input, uint32_t input_len, void *local_data,
166  const uint8_t flags)
167 {
168  uint16_t file_flags = FileFlowToFlags(f, STREAM_TOCLIENT);
169  rs_nfs_setfileflags(1, state, file_flags);
170 
171  return rs_nfs_parse_response_udp(f, state, pstate, input, input_len, local_data);
172 }
173 
174 static uint64_t NFSGetTxCnt(void *state)
175 {
176  return rs_nfs_state_get_tx_count(state);
177 }
178 
179 static void *NFSGetTx(void *state, uint64_t tx_id)
180 {
181  return rs_nfs_state_get_tx(state, tx_id);
182 }
183 
184 static AppLayerGetTxIterTuple RustNFSGetTxIterator(
185  const uint8_t ipproto, const AppProto alproto,
186  void *alstate, uint64_t min_tx_id, uint64_t max_tx_id,
187  AppLayerGetTxIterState *istate)
188 {
189  return rs_nfs_state_get_tx_iterator(alstate, min_tx_id, (uint64_t *)istate);
190 }
191 
192 static void NFSSetTxLogged(void *state, void *vtx, LoggerId logged)
193 {
194  rs_nfs_tx_set_logged(state, vtx, logged);
195 }
196 
197 static LoggerId NFSGetTxLogged(void *state, void *vtx)
198 {
199  return rs_nfs_tx_get_logged(state, vtx);
200 }
201 
202 /**
203  * \brief Called by the application layer.
204  *
205  * In most cases 1 can be returned here.
206  */
207 static int NFSGetAlstateProgressCompletionStatus(uint8_t direction) {
208  return rs_nfs_state_progress_completion_status(direction);
209 }
210 
211 /**
212  * \brief Return the state of a transaction in a given direction.
213  *
214  * In the case of the echo protocol, the existence of a transaction
215  * means that the request is done. However, some protocols that may
216  * need multiple chunks of data to complete the request may need more
217  * than just the existence of a transaction for the request to be
218  * considered complete.
219  *
220  * For the response to be considered done, the response for a request
221  * needs to be seen. The response_done flag is set on response for
222  * checking here.
223  */
224 static int NFSGetStateProgress(void *tx, uint8_t direction)
225 {
226  return rs_nfs_tx_get_alstate_progress(tx, direction);
227 }
228 
229 /**
230  * \brief get stored tx detect state
231  */
232 static DetectEngineState *NFSGetTxDetectState(void *vtx)
233 {
234  return rs_nfs_state_get_tx_detect_state(vtx);
235 }
236 
237 /**
238  * \brief set store tx detect state
239  */
240 static int NFSSetTxDetectState(void *vtx, DetectEngineState *s)
241 {
242  rs_nfs_state_set_tx_detect_state(vtx, s);
243  return 0;
244 }
245 
246 static FileContainer *NFSGetFiles(void *state, uint8_t direction)
247 {
248  return rs_nfs_getfiles(direction, state);
249 }
250 
251 static void NFSSetDetectFlags(void *tx, uint8_t dir, uint64_t flags)
252 {
253  rs_nfs_tx_set_detect_flags(tx, dir, flags);
254 }
255 
256 static uint64_t NFSGetDetectFlags(void *tx, uint8_t dir)
257 {
258  return rs_nfs_tx_get_detect_flags(tx, dir);
259 }
260 
262 static SuricataFileContext sfc = { &sbcfg };
263 
264 void RegisterNFSUDPParsers(void)
265 {
266  const char *proto_name = "nfs";
267 
268  /* Check if NFS TCP detection is enabled. If it does not exist in
269  * the configuration file then it will be enabled by default. */
270  if (AppLayerProtoDetectConfProtoDetectionEnabled("udp", proto_name)) {
271 
272  rs_nfs_init(&sfc);
273 
274  SCLogDebug("NFS UDP protocol detection enabled.");
275 
277 
278  if (RunmodeIsUnittests()) {
279 
280  SCLogDebug("Unittest mode, registering default configuration.");
281  AppLayerProtoDetectPPRegister(IPPROTO_UDP, NFS_DEFAULT_PORT,
282  ALPROTO_NFS, 0, NFS_MIN_FRAME_LEN, STREAM_TOSERVER,
283  NFSProbingParserTS, NFSProbingParserTC);
284 
285  }
286  else {
287 
288  if (!AppLayerProtoDetectPPParseConfPorts("udp", IPPROTO_UDP,
289  proto_name, ALPROTO_NFS, 0, NFS_MIN_FRAME_LEN,
290  NFSProbingParserTS, NFSProbingParserTC)) {
291  SCLogDebug("No NFS app-layer configuration, enabling NFS"
292  " detection TCP detection on port %s.",
293  NFS_DEFAULT_PORT);
294  AppLayerProtoDetectPPRegister(IPPROTO_UDP,
295  NFS_DEFAULT_PORT, ALPROTO_NFS, 0,
296  NFS_MIN_FRAME_LEN, STREAM_TOSERVER,
297  NFSProbingParserTS, NFSProbingParserTC);
298  }
299 
300  }
301 
302  }
303 
304  else {
305  SCLogDebug("Protocol detecter and parser disabled for NFS.");
306  return;
307  }
308 
309  if (AppLayerParserConfParserEnabled("udp", proto_name))
310  {
311  SCLogDebug("Registering NFS protocol parser.");
312 
313  /* Register functions for state allocation and freeing. A
314  * state is allocated for every new NFS flow. */
316  NFSStateAlloc, NFSStateFree);
317 
318  /* Register request parser for parsing frame from server to client. */
320  STREAM_TOSERVER, NFSParseRequest);
321 
322  /* Register response parser for parsing frames from server to client. */
324  STREAM_TOCLIENT, NFSParseResponse);
325 
326  /* Register a function to be called by the application layer
327  * when a transaction is to be freed. */
329  NFSStateTxFree);
330 
332  NFSGetTxLogged, NFSSetTxLogged);
333 
334  /* Register a function to return the current transaction count. */
336  NFSGetTxCnt);
337 
338  /* Transaction handling. */
340  NFSGetAlstateProgressCompletionStatus);
342  ALPROTO_NFS, NFSGetStateProgress);
344  NFSGetTx);
346  RustNFSGetTxIterator);
347 
348  AppLayerParserRegisterGetFilesFunc(IPPROTO_UDP, ALPROTO_NFS, NFSGetFiles);
349 
350  /* What is this being registered for? */
352  NFSGetTxDetectState, NFSSetTxDetectState);
353 
355  NFSStateGetEventInfo);
357  NFSGetEvents);
358 
360  NFSGetDetectFlags, NFSSetDetectFlags);
361 
362  }
363  else {
364  SCLogNotice("NFS protocol parsing disabled.");
365  }
366 
367 #ifdef UNITTESTS
370 #endif
371 }
372 
373 #ifdef UNITTESTS
374 #endif
375 
376 void NFSUDPParserRegisterTests(void)
377 {
378 #ifdef UNITTESTS
379 #endif
380 }
381 
382 #endif /* HAVE_RUST */
#define STREAMING_BUFFER_CONFIG_INITIALIZER
enum AppLayerEventType_ AppLayerEventType
uint16_t flags
#define SCLogDebug(...)
Definition: util-debug.h:335
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
void AppLayerParserRegisterGetStateProgressFunc(uint8_t ipproto, AppProto alproto, int(*StateGetProgress)(void *alstate, uint8_t direction))
uint32_t event_type
LoggerId
int logged
int AppLayerProtoDetectConfProtoDetectionEnabled(const char *ipproto, const char *alproto)
Given a protocol name, checks if proto detection is enabled in the conf file.
void AppLayerParserRegisterDetectFlagsFuncs(uint8_t ipproto, AppProto alproto, uint64_t(*GetTxDetectFlags)(void *tx, uint8_t dir), void(*SetTxDetectFlags)(void *tx, uint8_t dir, uint64_t))
void AppLayerParserRegisterDetectStateFuncs(uint8_t ipproto, AppProto alproto, DetectEngineState *(*GetTxDetectState)(void *tx), int(*SetTxDetectState)(void *tx, DetectEngineState *))
void RegisterNFSUDPParsers(void)
void AppLayerParserRegisterLoggerFuncs(uint8_t ipproto, AppProto alproto, LoggerId(*StateGetTxLogged)(void *, void *), void(*StateSetTxLogged)(void *, void *, LoggerId))
uint16_t AppProto
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 and when...
Data structure to store app layer decoder events.
int AppLayerParserRegisterParser(uint8_t ipproto, AppProto alproto, uint8_t direction, AppLayerParserFPtr Parser)
Register app layer parser for the protocol.
void AppLayerParserRegisterGetTx(uint8_t ipproto, AppProto alproto, void *(StateGetTx)(void *alstate, uint64_t tx_id))
void AppLayerParserRegisterGetFilesFunc(uint8_t ipproto, AppProto alproto, FileContainer *(*StateGetFiles)(void *, uint8_t))
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)
void AppLayerParserRegisterGetEventInfo(uint8_t ipproto, AppProto alproto, int(*StateGetEventInfo)(const char *event_name, int *event_id, AppLayerEventType *event_type))
void NFSUDPParserRegisterTests(void)
#define STREAM_TOCLIENT
Definition: stream.h:32
void AppLayerParserRegisterGetStateProgressCompletionStatus(AppProto alproto, int(*StateGetProgressCompletionStatus)(uint8_t direction))
int RunmodeIsUnittests(void)
Definition: suricata.c:261
void AppLayerProtoDetectRegisterProtocol(AppProto alproto, const char *alproto_name)
Registers a protocol for protocol detection phase.
#define SCLogNotice(...)
Macro used to log NOTICE messages.
Definition: util-debug.h:269
uint16_t tx_id
void AppLayerParserRegisterGetEventsFunc(uint8_t ipproto, AppProto alproto, AppLayerDecoderEvents *(*StateGetEvents)(void *, uint64_t))
void AppLayerParserRegisterProtocolUnittests(uint8_t ipproto, AppProto alproto, void(*RegisterUnittests)(void))
#define STREAM_TOSERVER
Definition: stream.h:31
void AppLayerParserRegisterGetTxIterator(uint8_t ipproto, AppProto alproto, AppLayerGetTxIteratorFunc Func)
uint16_t FileFlowToFlags(const Flow *flow, uint8_t direction)
Definition: util-file.c:217
void AppLayerParserRegisterGetTxCnt(uint8_t ipproto, AppProto alproto, uint64_t(*StateGetTxCnt)(void *alstate))
void AppLayerParserRegisterStateFuncs(uint8_t ipproto, AppProto alproto, void *(*StateAlloc)(void), void(*StateFree)(void *))
Flow data structure.
Definition: flow.h:327
void AppLayerParserRegisterTxFreeFunc(uint8_t ipproto, AppProto alproto, void(*StateTransactionFree)(void *, uint64_t))