suricata
app-layer-nfs-tcp.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  * This implements a application layer for the NFS protocol
26  * running on port 2049.
27  */
28 
29 #include "suricata-common.h"
30 #include "stream.h"
31 #include "conf.h"
32 
33 #include "util-unittest.h"
34 
35 #include "app-layer-detect-proto.h"
36 #include "app-layer-parser.h"
37 
38 #include "app-layer-nfs-tcp.h"
39 
40 #ifndef HAVE_RUST
42 {
43 }
44 
45 #else
46 
47 #include "rust.h"
48 #include "rust-nfs-nfs-gen.h"
49 
50 /* The default port to probe for echo traffic if not provided in the
51  * configuration file. */
52 #define NFSTCP_DEFAULT_PORT "2049"
53 
54 /* The minimum size for a RFC message. For some protocols this might
55  * be the size of a header. TODO actual min size is likely larger */
56 #define NFSTCP_MIN_FRAME_LEN 32
57 
58 /* Enum of app-layer events for an echo protocol. Normally you might
59  * have events for errors in parsing data, like unexpected data being
60  * received. For echo we'll make something up, and log an app-layer
61  * level alert if an empty message is received.
62  *
63  * Example rule:
64  *
65  * alert nfs any any -> any any (msg:"SURICATA NFS empty message"; \
66  * app-layer-event:nfs.empty_message; sid:X; rev:Y;)
67  */
68 enum {
69  NFSTCP_DECODER_EVENT_EMPTY_MESSAGE,
70 };
71 
72 SCEnumCharMap nfs_decoder_event_table[] = {
73  {"EMPTY_MESSAGE", NFSTCP_DECODER_EVENT_EMPTY_MESSAGE},
74  { NULL, 0 }
75 };
76 
77 static void *NFSTCPStateAlloc(void)
78 {
79  return rs_nfs_state_new();
80 }
81 
82 static void NFSTCPStateFree(void *state)
83 {
84  rs_nfs_state_free(state);
85 }
86 
87 /**
88  * \brief Callback from the application layer to have a transaction freed.
89  *
90  * \param state a void pointer to the NFSTCPState object.
91  * \param tx_id the transaction ID to free.
92  */
93 static void NFSTCPStateTxFree(void *state, uint64_t tx_id)
94 {
95  rs_nfs_state_tx_free(state, tx_id);
96 }
97 
98 static int NFSTCPStateGetEventInfo(const char *event_name, int *event_id,
100 {
101  return rs_nfs_state_get_event_info(event_name, event_id, event_type);
102 }
103 
104 static AppLayerDecoderEvents *NFSTCPGetEvents(void *state, uint64_t id)
105 {
106  return rs_nfs_state_get_events(state, id);
107 }
108 
109 /**
110  * \brief Probe the input to see if it looks like echo.
111  *
112  * \retval ALPROTO_NFS if it looks like echo, otherwise
113  * ALPROTO_UNKNOWN.
114  */
115 static AppProto NFSTCPProbingParserTS(Flow *f, uint8_t *input, uint32_t input_len)
116 {
117  if (input_len < NFSTCP_MIN_FRAME_LEN) {
118  return ALPROTO_UNKNOWN;
119  }
120 
121  int8_t r = rs_nfs_probe_ts(input, input_len);
122  if (r == 1) {
123  return ALPROTO_NFS;
124  } else if (r == -1) {
125  return ALPROTO_FAILED;
126  }
127 
128  SCLogDebug("Protocol not detected as ALPROTO_NFS.");
129  return ALPROTO_UNKNOWN;
130 }
131 
132 static AppProto NFSTCPProbingParserTC(Flow *f, uint8_t *input, uint32_t input_len)
133 {
134  if (input_len < NFSTCP_MIN_FRAME_LEN) {
135  return ALPROTO_UNKNOWN;
136  }
137 
138  int8_t r = rs_nfs_probe_tc(input, input_len);
139  if (r == 1) {
140  return ALPROTO_NFS;
141  } else if (r == -1) {
142  return ALPROTO_FAILED;
143  }
144 
145  SCLogDebug("Protocol not detected as ALPROTO_NFS.");
146  return ALPROTO_UNKNOWN;
147 }
148 
149 static int NFSTCPParseRequest(Flow *f, void *state,
150  AppLayerParserState *pstate, uint8_t *input, uint32_t input_len,
151  void *local_data, const uint8_t flags)
152 {
153  uint16_t file_flags = FileFlowToFlags(f, STREAM_TOSERVER);
154  rs_nfs_setfileflags(0, state, file_flags);
155 
156  int res;
157  if (input == NULL && input_len > 0) {
158  res = rs_nfs_parse_request_tcp_gap(state, input_len);
159  } else {
160  res = rs_nfs_parse_request(f, state, pstate, input, input_len, local_data);
161  }
162  return res;
163 }
164 
165 static int NFSTCPParseResponse(Flow *f, void *state, AppLayerParserState *pstate,
166  uint8_t *input, uint32_t input_len, void *local_data,
167  const uint8_t flags)
168 {
169  uint16_t file_flags = FileFlowToFlags(f, STREAM_TOCLIENT);
170  rs_nfs_setfileflags(1, state, file_flags);
171 
172  int res;
173  if (input == NULL && input_len > 0) {
174  res = rs_nfs_parse_response_tcp_gap(state, input_len);
175  } else {
176  res = rs_nfs_parse_response(f, state, pstate, input, input_len, local_data);
177  }
178  return res;
179 }
180 
181 static uint64_t NFSTCPGetTxCnt(void *state)
182 {
183  return rs_nfs_state_get_tx_count(state);
184 }
185 
186 static void *NFSTCPGetTx(void *state, uint64_t tx_id)
187 {
188  return rs_nfs_state_get_tx(state, tx_id);
189 }
190 
191 static AppLayerGetTxIterTuple RustNFSTCPGetTxIterator(
192  const uint8_t ipproto, const AppProto alproto,
193  void *alstate, uint64_t min_tx_id, uint64_t max_tx_id,
194  AppLayerGetTxIterState *istate)
195 {
196  return rs_nfs_state_get_tx_iterator(alstate, min_tx_id, (uint64_t *)istate);
197 }
198 
199 static void NFSTCPSetTxLogged(void *state, void *vtx, LoggerId logged)
200 {
201  rs_nfs_tx_set_logged(state, vtx, logged);
202 }
203 
204 static LoggerId NFSTCPGetTxLogged(void *state, void *vtx)
205 {
206  return rs_nfs_tx_get_logged(state, vtx);
207 }
208 
209 /**
210  * \brief Called by the application layer.
211  *
212  * In most cases 1 can be returned here.
213  */
214 static int NFSTCPGetAlstateProgressCompletionStatus(uint8_t direction) {
215  return rs_nfs_state_progress_completion_status(direction);
216 }
217 
218 /**
219  * \brief Return the state of a transaction in a given direction.
220  *
221  * In the case of the echo protocol, the existence of a transaction
222  * means that the request is done. However, some protocols that may
223  * need multiple chunks of data to complete the request may need more
224  * than just the existence of a transaction for the request to be
225  * considered complete.
226  *
227  * For the response to be considered done, the response for a request
228  * needs to be seen. The response_done flag is set on response for
229  * checking here.
230  */
231 static int NFSTCPGetStateProgress(void *tx, uint8_t direction)
232 {
233  return rs_nfs_tx_get_alstate_progress(tx, direction);
234 }
235 
236 /**
237  * \brief get stored tx detect state
238  */
239 static DetectEngineState *NFSTCPGetTxDetectState(void *vtx)
240 {
241  return rs_nfs_state_get_tx_detect_state(vtx);
242 }
243 
244 /**
245  * \brief set store tx detect state
246  */
247 static int NFSTCPSetTxDetectState(void *vtx, DetectEngineState *s)
248 {
249  rs_nfs_state_set_tx_detect_state(vtx, s);
250  return 0;
251 }
252 
253 static FileContainer *NFSTCPGetFiles(void *state, uint8_t direction)
254 {
255  return rs_nfs_getfiles(direction, state);
256 }
257 
258 static void NFSTCPSetDetectFlags(void *tx, uint8_t dir, uint64_t flags)
259 {
260  rs_nfs_tx_set_detect_flags(tx, dir, flags);
261 }
262 
263 static uint64_t NFSTCPGetDetectFlags(void *tx, uint8_t dir)
264 {
265  return rs_nfs_tx_get_detect_flags(tx, dir);
266 }
267 
269 static SuricataFileContext sfc = { &sbcfg };
270 
271 void RegisterNFSTCPParsers(void)
272 {
273  const char *proto_name = "nfs";
274 
275  /* Check if NFSTCP TCP detection is enabled. If it does not exist in
276  * the configuration file then it will be enabled by default. */
277  if (AppLayerProtoDetectConfProtoDetectionEnabled("tcp", proto_name)) {
278 
279  rs_nfs_init(&sfc);
280 
281  SCLogDebug("NFSTCP TCP protocol detection enabled.");
282 
284 
285  if (RunmodeIsUnittests()) {
286 
287  SCLogDebug("Unittest mode, registering default configuration.");
288  AppLayerProtoDetectPPRegister(IPPROTO_TCP, NFSTCP_DEFAULT_PORT,
289  ALPROTO_NFS, 0, NFSTCP_MIN_FRAME_LEN, STREAM_TOSERVER,
290  NFSTCPProbingParserTS, NFSTCPProbingParserTC);
291 
292  }
293  else {
294 
295  if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP,
296  proto_name, ALPROTO_NFS, 0, NFSTCP_MIN_FRAME_LEN,
297  NFSTCPProbingParserTS, NFSTCPProbingParserTC)) {
298  SCLogDebug("No NFSTCP app-layer configuration, enabling NFSTCP"
299  " detection TCP detection on port %s.",
300  NFSTCP_DEFAULT_PORT);
301  AppLayerProtoDetectPPRegister(IPPROTO_TCP,
302  NFSTCP_DEFAULT_PORT, ALPROTO_NFS, 0,
303  NFSTCP_MIN_FRAME_LEN, STREAM_TOSERVER,
304  NFSTCPProbingParserTS, NFSTCPProbingParserTC);
305  }
306 
307  }
308 
309  }
310 
311  else {
312  SCLogDebug("Protocol detecter and parser disabled for NFSTCP.");
313  return;
314  }
315 
316  if (AppLayerParserConfParserEnabled("tcp", proto_name))
317  {
318  SCLogDebug("Registering NFSTCP protocol parser.");
319 
320  /* Register functions for state allocation and freeing. A
321  * state is allocated for every new NFSTCP flow. */
323  NFSTCPStateAlloc, NFSTCPStateFree);
324 
325  /* Register request parser for parsing frame from server to client. */
327  STREAM_TOSERVER, NFSTCPParseRequest);
328 
329  /* Register response parser for parsing frames from server to client. */
331  STREAM_TOCLIENT, NFSTCPParseResponse);
332 
333  /* Register a function to be called by the application layer
334  * when a transaction is to be freed. */
336  NFSTCPStateTxFree);
337 
339  NFSTCPGetTxLogged, NFSTCPSetTxLogged);
340 
341  /* Register a function to return the current transaction count. */
343  NFSTCPGetTxCnt);
344 
345  /* Transaction handling. */
347  NFSTCPGetAlstateProgressCompletionStatus);
349  ALPROTO_NFS, NFSTCPGetStateProgress);
351  NFSTCPGetTx);
353  RustNFSTCPGetTxIterator);
354 
355  AppLayerParserRegisterGetFilesFunc(IPPROTO_TCP, ALPROTO_NFS, NFSTCPGetFiles);
356 
357  /* What is this being registered for? */
359  NFSTCPGetTxDetectState, NFSTCPSetTxDetectState);
360 
362  NFSTCPStateGetEventInfo);
364  NFSTCPGetEvents);
365 
367  NFSTCPGetDetectFlags, NFSTCPSetDetectFlags);
368 
369  /* This parser accepts gaps. */
372  }
373  else {
374  SCLogDebug("NFSTCP protocol parsing disabled.");
375  }
376 
377 #ifdef UNITTESTS
380 #endif
381 }
382 
383 #ifdef UNITTESTS
384 #endif
385 
386 void NFSTCPParserRegisterTests(void)
387 {
388 #ifdef UNITTESTS
389 #endif
390 }
391 
392 #endif /* HAVE_RUST */
#define STREAMING_BUFFER_CONFIG_INITIALIZER
enum AppLayerEventType_ AppLayerEventType
uint16_t flags
#define SCLogDebug(...)
Definition: util-debug.h:335
void AppLayerParserRegisterOptionFlags(uint8_t ipproto, AppProto alproto, uint32_t flags)
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 RegisterNFSTCPParsers(void)
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 AppLayerParserRegisterLoggerFuncs(uint8_t ipproto, AppProto alproto, LoggerId(*StateGetTxLogged)(void *, void *), void(*StateSetTxLogged)(void *, void *, LoggerId))
uint16_t AppProto
void NFSTCPParserRegisterTests(void)
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))
#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.
PoolThreadReserved res
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
#define APP_LAYER_PARSER_OPT_ACCEPT_GAPS
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))