suricata
app-layer-enip.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 Kevin Wong <kwong@solananetworks.com>
22  *
23  * App-layer parser for ENIP protocol
24  *
25  */
26 
27 #include "suricata-common.h"
28 #include "suricata.h"
29 
30 #include "util-debug.h"
31 #include "util-byte.h"
32 #include "util-enum.h"
33 #include "util-mem.h"
34 #include "util-misc.h"
35 
36 #include "stream.h"
37 
38 #include "app-layer.h"
39 #include "app-layer-protos.h"
40 #include "app-layer-parser.h"
41 #include "app-layer-enip.h"
42 #include "app-layer-enip-common.h"
43 
44 #include "app-layer-detect-proto.h"
45 
46 #include "conf.h"
47 #include "decode.h"
48 
49 #include "detect-parse.h"
50 #include "detect-engine.h"
51 #include "util-unittest.h"
52 #include "util-unittest-helper.h"
53 #include "pkt-var.h"
54 #include "util-profiling.h"
55 
56 
58  { NULL, -1 },
59 };
60 
61 /** \brief get value for 'complete' status in ENIP
62  *
63  * For ENIP we use a simple bool.
64  */
65 static int ENIPGetAlstateProgress(void *tx, uint8_t direction)
66 {
67  return 1;
68 }
69 
70 static AppLayerTxData *ENIPGetTxData(void *vtx)
71 {
72  ENIPTransaction *tx = (ENIPTransaction *)vtx;
73  return &tx->tx_data;
74 }
75 
76 static AppLayerStateData *ENIPGetStateData(void *vstate)
77 {
78  ENIPState *state = (ENIPState *)vstate;
79  return &state->state_data;
80 }
81 
82 static void *ENIPGetTx(void *alstate, uint64_t tx_id)
83 {
84  ENIPState *enip = (ENIPState *) alstate;
85  ENIPTransaction *tx = NULL;
86 
87  if (enip->curr && enip->curr->tx_num == tx_id + 1)
88  return enip->curr;
89 
90  TAILQ_FOREACH(tx, &enip->tx_list, next) {
91  if (tx->tx_num != (tx_id+1))
92  continue;
93 
94  SCLogDebug("returning tx %p", tx);
95  return tx;
96  }
97 
98  return NULL;
99 }
100 
101 static uint64_t ENIPGetTxCnt(void *alstate)
102 {
103  return ((ENIPState *)alstate)->transaction_max;
104 }
105 
106 static int ENIPStateGetEventInfo(const char *event_name, int *event_id, AppLayerEventType *event_type)
107 {
108  *event_id = SCMapEnumNameToValue(event_name, enip_decoder_event_table);
109 
110  if (*event_id == -1) {
111  SCLogError("event \"%s\" not present in "
112  "enip's enum map table.",
113  event_name);
114  /* yes this is fatal */
115  return -1;
116  }
117 
118  *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
119 
120  return 0;
121 }
122 
123 static int ENIPStateGetEventInfoById(int event_id, const char **event_name,
124  AppLayerEventType *event_type)
125 {
126  *event_name = SCMapEnumValueToName(event_id, enip_decoder_event_table);
127  if (*event_name == NULL) {
128  SCLogError("event \"%d\" not present in "
129  "enip's enum map table.",
130  event_id);
131  /* yes this is fatal */
132  return -1;
133  }
134 
135  *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
136 
137  return 0;
138 }
139 
140 /** \brief Allocate enip state
141  *
142  * return state
143  */
144 static void *ENIPStateAlloc(void *orig_state, AppProto proto_orig)
145 {
146  SCLogDebug("ENIPStateAlloc");
147  void *s = SCMalloc(sizeof(ENIPState));
148  if (unlikely(s == NULL))
149  return NULL;
150 
151  memset(s, 0, sizeof(ENIPState));
152 
153  ENIPState *enip_state = (ENIPState *) s;
154 
155  TAILQ_INIT(&enip_state->tx_list);
156  return s;
157 }
158 
159 /** \internal
160  * \brief Free a ENIP TX
161  * \param tx ENIP TX to free */
162 static void ENIPTransactionFree(ENIPTransaction *tx, ENIPState *state)
163 {
164  SCEnter();
165  SCLogDebug("ENIPTransactionFree");
166  CIPServiceEntry *svc = NULL;
167  while ((svc = TAILQ_FIRST(&tx->service_list)))
168  {
169  TAILQ_REMOVE(&tx->service_list, svc, next);
170 
171  SegmentEntry *seg = NULL;
172  while ((seg = TAILQ_FIRST(&svc->segment_list)))
173  {
174  TAILQ_REMOVE(&svc->segment_list, seg, next);
175  SCFree(seg);
176  }
177 
178  AttributeEntry *attr = NULL;
179  while ((attr = TAILQ_FIRST(&svc->attrib_list)))
180  {
181  TAILQ_REMOVE(&svc->attrib_list, attr, next);
182  SCFree(attr);
183  }
184 
185  SCFree(svc);
186  }
187 
189 
190  if (tx->tx_data.de_state != NULL) {
191  DetectEngineStateFree(tx->tx_data.de_state);
192 
193  state->tx_with_detect_state_cnt--;
194  }
195 
196  if (state->iter == tx)
197  state->iter = NULL;
198 
199  SCFree(tx);
200  SCReturn;
201 }
202 
203 /** \brief Free enip state
204  *
205  */
206 static void ENIPStateFree(void *s)
207 {
208  SCEnter();
209  SCLogDebug("ENIPStateFree");
210  if (s)
211  {
212  ENIPState *enip_state = (ENIPState *) s;
213 
214  ENIPTransaction *tx = NULL;
215  while ((tx = TAILQ_FIRST(&enip_state->tx_list)))
216  {
217  TAILQ_REMOVE(&enip_state->tx_list, tx, next);
218  ENIPTransactionFree(tx, enip_state);
219  }
220 
221  if (enip_state->buffer != NULL)
222  {
223  SCFree(enip_state->buffer);
224  }
225 
226  SCFree(s);
227  }
228  SCReturn;
229 }
230 
231 /** \internal
232  * \brief Allocate a ENIP TX
233  * \retval tx or NULL */
234 static ENIPTransaction *ENIPTransactionAlloc(ENIPState *state)
235 {
236  SCLogDebug("ENIPStateTransactionAlloc");
238  sizeof(ENIPTransaction));
239  if (unlikely(tx == NULL))
240  return NULL;
241 
242  state->curr = tx;
243  state->transaction_max++;
244 
245  memset(tx, 0x00, sizeof(ENIPTransaction));
246  TAILQ_INIT(&tx->service_list);
247 
248  tx->enip = state;
249  tx->tx_num = state->transaction_max;
250  tx->service_count = 0;
251 
252  TAILQ_INSERT_TAIL(&state->tx_list, tx, next);
253 
254  return tx;
255 }
256 
257 /**
258  * \brief enip transaction cleanup callback
259  */
260 static void ENIPStateTransactionFree(void *state, uint64_t tx_id)
261 {
262  SCEnter();
263  SCLogDebug("ENIPStateTransactionFree");
264  ENIPState *enip_state = state;
265  ENIPTransaction *tx = NULL;
266  TAILQ_FOREACH(tx, &enip_state->tx_list, next)
267  {
268 
269  if ((tx_id+1) < tx->tx_num)
270  break;
271  else if ((tx_id+1) > tx->tx_num)
272  continue;
273 
274  if (tx == enip_state->curr)
275  enip_state->curr = NULL;
276 
277  if (tx->tx_data.events != NULL) {
278  if (tx->tx_data.events->cnt <= enip_state->events)
279  enip_state->events -= tx->tx_data.events->cnt;
280  else
281  enip_state->events = 0;
282  }
283 
284  TAILQ_REMOVE(&enip_state->tx_list, tx, next);
285  ENIPTransactionFree(tx, state);
286  break;
287  }
288  SCReturn;
289 }
290 
291 /** \internal
292  *
293  * \brief This function is called to retrieve a ENIP
294  *
295  * \param state ENIP state structure for the parser
296  * \param input Input line of the command
297  * \param input_len Length of the request
298  *
299  * \retval 1 when the command is parsed, 0 otherwise
300  */
301 static AppLayerResult ENIPParse(Flow *f, void *state, AppLayerParserState *pstate,
302  StreamSlice stream_slice, void *local_data, uint8_t direction)
303 {
304  SCEnter();
305  ENIPState *enip = (ENIPState *) state;
306  ENIPTransaction *tx;
307 
308  const uint8_t *input = StreamSliceGetData(&stream_slice);
309  uint32_t input_len = StreamSliceGetDataLen(&stream_slice);
310 
311  if (input == NULL && AppLayerParserStateIssetFlag(pstate,
313  {
315  } else if (input == NULL && input_len != 0) {
316  // GAP
318  } else if (input == NULL || input_len == 0)
319  {
321  }
322 
323  while (input_len > 0)
324  {
325  tx = ENIPTransactionAlloc(enip);
326  if (tx == NULL)
328 
329  if (direction == STREAM_TOCLIENT)
330  tx->tx_data.detect_flags_ts |= APP_LAYER_TX_SKIP_INSPECT_FLAG;
331  else
332  tx->tx_data.detect_flags_tc |= APP_LAYER_TX_SKIP_INSPECT_FLAG;
333 
334  SCLogDebug("ENIPParse input len %d", input_len);
335  DecodeENIPPDU(input, input_len, tx);
336  uint32_t pkt_len = tx->header.length + sizeof(ENIPEncapHdr);
337  SCLogDebug("ENIPParse packet len %d", pkt_len);
338  if (pkt_len > input_len)
339  {
340  SCLogDebug("Invalid packet length");
341  break;
342  }
343 
344  input += pkt_len;
345  input_len -= pkt_len;
346  //SCLogDebug("remaining %d", input_len);
347 
348  if (input_len < sizeof(ENIPEncapHdr))
349  {
350  //SCLogDebug("Not enough data"); //not enough data for ENIP
351  break;
352  }
353  }
354 
356 }
357 
358 static AppLayerResult ENIPParseRequest(Flow *f, void *state, AppLayerParserState *pstate,
359  StreamSlice stream_slice, void *local_data)
360 {
361  return ENIPParse(f, state, pstate, stream_slice, local_data, STREAM_TOSERVER);
362 }
363 
364 static AppLayerResult ENIPParseResponse(Flow *f, void *state, AppLayerParserState *pstate,
365  StreamSlice stream_slice, void *local_data)
366 {
367  return ENIPParse(f, state, pstate, stream_slice, local_data, STREAM_TOCLIENT);
368 }
369 
370 #define ENIP_LEN_REGISTER_SESSION 4 // protocol u16, options u16
371 
372 static uint16_t ENIPProbingParser(Flow *f, uint8_t direction,
373  const uint8_t *input, uint32_t input_len, uint8_t *rdir)
374 {
375  // SCLogDebug("ENIPProbingParser %d", input_len);
376  if (input_len < sizeof(ENIPEncapHdr))
377  {
378  SCLogDebug("length too small to be a ENIP header");
379  return ALPROTO_UNKNOWN;
380  }
381  uint16_t cmd;
382  uint16_t enip_len;
383  uint32_t status;
384  uint32_t option;
385  uint16_t nbitems;
386 
387  int ret = ByteExtractUint32(
388  &status, BYTE_LITTLE_ENDIAN, sizeof(uint32_t), (const uint8_t *)(input + 8));
389  if (ret < 0) {
390  return ALPROTO_FAILED;
391  }
392  switch (status) {
393  case SUCCESS:
394  case INVALID_CMD:
395  case NO_RESOURCES:
396  case INCORRECT_DATA:
397  case INVALID_SESSION:
398  case INVALID_LENGTH:
400  case ENCAP_HEADER_ERROR:
401  break;
402  default:
403  return ALPROTO_FAILED;
404  }
405  ret = ByteExtractUint16(&cmd, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), (const uint8_t *)(input));
406  if(ret < 0) {
407  return ALPROTO_FAILED;
408  }
409  ret = ByteExtractUint32(
410  &option, BYTE_LITTLE_ENDIAN, sizeof(uint32_t), (const uint8_t *)(input + 20));
411  if (ret < 0) {
412  return ALPROTO_FAILED;
413  }
414  ret = ByteExtractUint16(
415  &enip_len, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), (const uint8_t *)(input + 2));
416  if (ret < 0) {
417  return ALPROTO_FAILED;
418  }
419 
420  //ok for all the known commands
421  switch(cmd) {
422  case NOP:
423  if (option != 0) {
424  return ALPROTO_FAILED;
425  }
426  break;
427  case REGISTER_SESSION:
428  if (enip_len != ENIP_LEN_REGISTER_SESSION) {
429  return ALPROTO_FAILED;
430  }
431  break;
432  case UNREGISTER_SESSION:
433  if (enip_len != ENIP_LEN_REGISTER_SESSION && enip_len != 0) {
434  // 0 for request and 4 for response
435  return ALPROTO_FAILED;
436  }
437  break;
438  case LIST_SERVICES:
439  case LIST_IDENTITY:
440  case SEND_RR_DATA:
441  case SEND_UNIT_DATA:
442  case INDICATE_STATUS:
443  case CANCEL:
444  break;
445  case LIST_INTERFACES:
446  if (input_len < sizeof(ENIPEncapHdr) + 2) {
447  SCLogDebug("length too small to be a ENIP LIST_INTERFACES");
448  return ALPROTO_UNKNOWN;
449  }
450  ret = ByteExtractUint16(
451  &nbitems, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), (const uint8_t *)(input));
452  if(ret < 0) {
453  return ALPROTO_FAILED;
454  }
455  if (enip_len < sizeof(ENIPEncapHdr) + 2 * (size_t)nbitems) {
456  return ALPROTO_FAILED;
457  }
458  break;
459  default:
460  return ALPROTO_FAILED;
461  }
462  return ALPROTO_ENIP;
463 }
464 
465 static AppLayerGetTxIterTuple ENIPGetTxIterator(const uint8_t ipproto, const AppProto alproto,
466  void *alstate, uint64_t min_tx_id, uint64_t max_tx_id, AppLayerGetTxIterState *state)
467 {
468  ENIPState *enip_state = (ENIPState *)alstate;
469  AppLayerGetTxIterTuple no_tuple = { NULL, 0, false };
470  if (enip_state) {
471  ENIPTransaction *tx_ptr;
472  if (state->un.ptr == NULL) {
473  tx_ptr = TAILQ_FIRST(&enip_state->tx_list);
474  } else {
475  tx_ptr = (ENIPTransaction *)state->un.ptr;
476  }
477  if (tx_ptr) {
478  while (tx_ptr->tx_num < min_tx_id + 1) {
479  tx_ptr = TAILQ_NEXT(tx_ptr, next);
480  if (!tx_ptr) {
481  return no_tuple;
482  }
483  }
484  if (tx_ptr->tx_num >= max_tx_id + 1) {
485  return no_tuple;
486  }
487  state->un.ptr = TAILQ_NEXT(tx_ptr, next);
488  AppLayerGetTxIterTuple tuple = {
489  .tx_ptr = tx_ptr,
490  .tx_id = tx_ptr->tx_num - 1,
491  .has_next = (state->un.ptr != NULL),
492  };
493  return tuple;
494  }
495  }
496  return no_tuple;
497 }
498 
499 /**
500  * \brief Function to register the ENIP protocol parsers and other functions
501  */
503 {
504  SCEnter();
505  const char *proto_name = "enip";
506 
507  if (AppLayerProtoDetectConfProtoDetectionEnabledDefault("udp", proto_name, false)) {
509 
510  if (RunmodeIsUnittests())
511  {
512  AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818", ALPROTO_ENIP,
513  0, sizeof(ENIPEncapHdr), STREAM_TOSERVER, ENIPProbingParser, NULL);
514 
515  AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818", ALPROTO_ENIP,
516  0, sizeof(ENIPEncapHdr), STREAM_TOCLIENT, ENIPProbingParser, NULL);
517 
518  } else
519  {
520  if (!AppLayerProtoDetectPPParseConfPorts("udp", IPPROTO_UDP,
521  proto_name, ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr),
522  ENIPProbingParser, ENIPProbingParser))
523  {
524  SCLogDebug(
525  "no ENIP UDP config found enabling ENIP detection on port 44818.");
526 
527  AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818",
528  ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr), STREAM_TOSERVER,
529  ENIPProbingParser, NULL);
530 
531  AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818",
532  ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr), STREAM_TOCLIENT,
533  ENIPProbingParser, NULL);
534  }
535  }
536 
537  } else {
538  SCLogConfig("Protocol detection and parser disabled for %s protocol.",
539  proto_name);
540  return;
541  }
542 
543  if (AppLayerParserConfParserEnabled("udp", proto_name))
544  {
545  AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_ENIP, STREAM_TOSERVER, ENIPParseRequest);
546  AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_ENIP, STREAM_TOCLIENT, ENIPParseResponse);
547 
549  ENIPStateAlloc, ENIPStateFree);
550 
551  AppLayerParserRegisterGetTx(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetTx);
552  AppLayerParserRegisterGetTxIterator(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetTxIterator);
553  AppLayerParserRegisterTxDataFunc(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetTxData);
554  AppLayerParserRegisterStateDataFunc(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetStateData);
555  AppLayerParserRegisterGetTxCnt(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetTxCnt);
556  AppLayerParserRegisterTxFreeFunc(IPPROTO_UDP, ALPROTO_ENIP, ENIPStateTransactionFree);
557 
558  AppLayerParserRegisterGetStateProgressFunc(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetAlstateProgress);
560 
561  AppLayerParserRegisterGetEventInfo(IPPROTO_UDP, ALPROTO_ENIP, ENIPStateGetEventInfo);
562  AppLayerParserRegisterGetEventInfoById(IPPROTO_UDP, ALPROTO_ENIP, ENIPStateGetEventInfoById);
563 
565  IPPROTO_UDP, ALPROTO_ENIP, STREAM_TOSERVER | STREAM_TOCLIENT);
566  } else
567  {
568  SCLogInfo(
569  "Parsed disabled for %s protocol. Protocol detection" "still on.",
570  proto_name);
571  }
572 
573 #ifdef UNITTESTS
575 #endif
576 
577  SCReturn;
578 }
579 
580 /**
581  * \brief Function to register the ENIP protocol parsers and other functions
582  */
584 {
585  SCEnter();
586  const char *proto_name = "enip";
587 
588  if (AppLayerProtoDetectConfProtoDetectionEnabledDefault("tcp", proto_name, false)) {
590 
591  if (RunmodeIsUnittests())
592  {
593  AppLayerProtoDetectPPRegister(IPPROTO_TCP, "44818", ALPROTO_ENIP,
594  0, sizeof(ENIPEncapHdr), STREAM_TOSERVER, ENIPProbingParser, NULL);
595 
596  AppLayerProtoDetectPPRegister(IPPROTO_TCP, "44818", ALPROTO_ENIP,
597  0, sizeof(ENIPEncapHdr), STREAM_TOCLIENT, ENIPProbingParser, NULL);
598 
599  } else
600  {
601  if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP,
602  proto_name, ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr),
603  ENIPProbingParser, ENIPProbingParser))
604  {
605  return;
606  }
607  }
608 
609  } else {
610  SCLogDebug("Protocol detection and parser disabled for %s protocol.",
611  proto_name);
612  return;
613  }
614 
615  if (AppLayerParserConfParserEnabled("tcp", proto_name))
616  {
617  AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_ENIP, STREAM_TOSERVER, ENIPParseRequest);
618  AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_ENIP, STREAM_TOCLIENT, ENIPParseResponse);
620  ENIPStateAlloc, ENIPStateFree);
621 
622  AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetTx);
623  AppLayerParserRegisterGetTxIterator(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetTxIterator);
624  AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetTxData);
625  AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetStateData);
626  AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetTxCnt);
627  AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_ENIP, ENIPStateTransactionFree);
628 
629  AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetAlstateProgress);
631 
632  AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_ENIP, ENIPStateGetEventInfo);
633 
635  ALPROTO_ENIP, STREAM_TOSERVER | STREAM_TOCLIENT);
636 
637  /* This parser accepts gaps. */
640 
642  } else
643  {
644  SCLogConfig("Parser disabled for %s protocol. Protocol detection still on.",
645  proto_name);
646  }
647 
648 #ifdef UNITTESTS
650 #endif
651 
652  SCReturn;
653 }
654 
655 /* UNITTESTS */
656 #ifdef UNITTESTS
657 #include "flow-util.h"
658 #include "stream-tcp.h"
659 
660 static uint8_t listIdentity[] = {/* List ID */ 0x63, 0x00,
661  /* Length */ 0x00, 0x00,
662  /* Session */ 0x00, 0x00, 0x00, 0x00,
663  /* Status */ 0x00, 0x00, 0x00, 0x00,
664  /* Delay*/ 0x00,
665  /* Context */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
666  /* Quantity of coils */ 0x00, 0x00, 0x00, 0x00, 0x00};
667 
668 /**
669  * \brief Test if ENIP Packet matches signature
670  */
671 static int ALDecodeENIPTest(void)
672 {
674  Flow f;
675  TcpSession ssn;
676 
677  memset(&f, 0, sizeof(f));
678  memset(&ssn, 0, sizeof(ssn));
679 
680  f.protoctx = (void *)&ssn;
681  f.proto = IPPROTO_TCP;
682  f.alproto = ALPROTO_ENIP;
683 
684  StreamTcpInitConfig(true);
685 
686  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_ENIP, STREAM_TOSERVER,
687  listIdentity, sizeof(listIdentity));
688  FAIL_IF(r != 0);
689 
690  ENIPState *enip_state = f.alstate;
691  FAIL_IF_NULL(enip_state);
692 
693  ENIPTransaction *tx = ENIPGetTx(enip_state, 0);
694  FAIL_IF_NULL(tx);
695 
696  FAIL_IF(tx->header.command != 99);
697 
699  StreamTcpFreeConfig(true);
700  FLOW_DESTROY(&f);
701 
702  PASS;
703 }
704 
705 #endif /* UNITTESTS */
706 
708 {
709 #ifdef UNITTESTS
710  UtRegisterTest("ALDecodeENIPTest", ALDecodeENIPTest);
711 #endif /* UNITTESTS */
712 }
util-byte.h
SEND_RR_DATA
#define SEND_RR_DATA
Definition: app-layer-enip-common.h:36
AppLayerParserRegisterGetStateProgressFunc
void AppLayerParserRegisterGetStateProgressFunc(uint8_t ipproto, AppProto alproto, int(*StateGetProgress)(void *alstate, uint8_t direction))
Definition: app-layer-parser.c:496
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:1607
LIST_SERVICES
#define LIST_SERVICES
Definition: app-layer-enip-common.h:31
detect-engine.h
FAIL_IF_NULL
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
SegmentEntry_
Definition: app-layer-enip-common.h:154
AppLayerGetTxIterState::ptr
void * ptr
Definition: app-layer-parser.h:146
AppLayerGetTxIterState::un
union AppLayerGetTxIterState::@15 un
enip_decoder_event_table
SCEnumCharMap enip_decoder_event_table[]
Definition: app-layer-enip.c:57
AppLayerParserRegisterOptionFlags
void AppLayerParserRegisterOptionFlags(uint8_t ipproto, AppProto alproto, uint32_t flags)
Definition: app-layer-parser.c:415
TAILQ_INIT
#define TAILQ_INIT(head)
Definition: queue.h:262
ByteExtractUint16
int ByteExtractUint16(uint16_t *res, int e, uint16_t len, const uint8_t *bytes)
Definition: util-byte.c:164
flow-util.h
INVALID_LENGTH
#define INVALID_LENGTH
Definition: app-layer-enip-common.h:54
stream-tcp.h
ALPROTO_ENIP
@ ALPROTO_ENIP
Definition: app-layer-protos.h:43
unlikely
#define unlikely(expr)
Definition: util-optimize.h:35
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
ENIPState_
Per flow ENIP state container.
Definition: app-layer-enip-common.h:211
ENIPState_::events
uint16_t events
Definition: app-layer-enip-common.h:219
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
ENIPState_::state_data
AppLayerStateData state_data
Definition: app-layer-enip-common.h:212
SEND_UNIT_DATA
#define SEND_UNIT_DATA
Definition: app-layer-enip-common.h:37
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
DecodeENIPPDU
int DecodeENIPPDU(const uint8_t *input, uint32_t input_len, ENIPTransaction *enip_data)
Decode ENIP Encapsulation Header.
Definition: app-layer-enip-common.c:193
Flow_::proto
uint8_t proto
Definition: flow.h:369
AppProto
uint16_t AppProto
Definition: app-layer-protos.h:80
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:334
Flow_
Flow data structure.
Definition: flow.h:347
AppLayerParserRegisterStateProgressCompletionStatus
void AppLayerParserRegisterStateProgressCompletionStatus(AppProto alproto, const int ts, const int tc)
Definition: app-layer-parser.c:548
ENIP_LEN_REGISTER_SESSION
#define ENIP_LEN_REGISTER_SESSION
Definition: app-layer-enip.c:370
AppLayerParserRegisterParserAcceptableDataDirection
void AppLayerParserRegisterParserAcceptableDataDirection(uint8_t ipproto, AppProto alproto, uint8_t direction)
Definition: app-layer-parser.c:404
AppLayerParserRegisterTxFreeFunc
void AppLayerParserRegisterTxFreeFunc(uint8_t ipproto, AppProto alproto, void(*StateTransactionFree)(void *, uint64_t))
Definition: app-layer-parser.c:507
TAILQ_FOREACH
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:252
APP_LAYER_TX_SKIP_INSPECT_FLAG
#define APP_LAYER_TX_SKIP_INSPECT_FLAG
Definition: app-layer-parser.h:79
NOP
#define NOP
Definition: app-layer-enip-common.h:30
AppLayerParserThreadCtxFree
void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
Destroys the app layer parser thread context obtained using AppLayerParserThreadCtxAlloc().
Definition: app-layer-parser.c:314
INVALID_CMD
#define INVALID_CMD
Definition: app-layer-enip-common.h:50
AppLayerDecoderEventsFreeEvents
void AppLayerDecoderEventsFreeEvents(AppLayerDecoderEvents **events)
Definition: app-layer-events.c:134
REGISTER_SESSION
#define REGISTER_SESSION
Definition: app-layer-enip-common.h:34
TAILQ_INSERT_TAIL
#define TAILQ_INSERT_TAIL(head, elm, field)
Definition: queue.h:294
LIST_INTERFACES
#define LIST_INTERFACES
Definition: app-layer-enip-common.h:33
LIST_IDENTITY
#define LIST_IDENTITY
Definition: app-layer-enip-common.h:32
CANCEL
#define CANCEL
Definition: app-layer-enip-common.h:39
APP_LAYER_PARSER_EOF_TS
#define APP_LAYER_PARSER_EOF_TS
Definition: app-layer-parser.h:39
Flow_::protoctx
void * protoctx
Definition: flow.h:437
INCORRECT_DATA
#define INCORRECT_DATA
Definition: app-layer-enip-common.h:52
util-unittest.h
ENIPEncapHdr_::command
uint16_t command
Definition: app-layer-enip-common.h:99
AttributeEntry_
Definition: app-layer-enip-common.h:162
util-unittest-helper.h
CIPServiceEntry_
Definition: app-layer-enip-common.h:169
INVALID_SESSION
#define INVALID_SESSION
Definition: app-layer-enip-common.h:53
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:1568
app-layer-detect-proto.h
StreamTcpInitConfig
void StreamTcpInitConfig(bool)
To initialize the stream global configuration data.
Definition: stream-tcp.c:359
TAILQ_REMOVE
#define TAILQ_REMOVE(head, elm, field)
Definition: queue.h:312
decode.h
util-debug.h
TAILQ_FIRST
#define TAILQ_FIRST(head)
Definition: queue.h:250
AppLayerParserState_
Definition: app-layer-parser.c:139
PASS
#define PASS
Pass the test.
Definition: util-unittest.h:105
ENCAP_HEADER_ERROR
#define ENCAP_HEADER_ERROR
Definition: app-layer-enip-common.h:57
ENIPTransaction_::enip
struct ENIPState_ * enip
Definition: app-layer-enip-common.h:193
alp_tctx
AppLayerParserThreadCtx * alp_tctx
Definition: fuzz_applayerparserparse.c:22
SCEnter
#define SCEnter(...)
Definition: util-debug.h:271
RegisterENIPTCPParsers
void RegisterENIPTCPParsers(void)
Function to register the ENIP protocol parsers and other functions.
Definition: app-layer-enip.c:583
ByteExtractUint32
int ByteExtractUint32(uint32_t *res, int e, uint16_t len, const uint8_t *bytes)
Definition: util-byte.c:143
pkt-var.h
AppLayerParserRegisterStateFuncs
void AppLayerParserRegisterStateFuncs(uint8_t ipproto, AppProto alproto, void *(*StateAlloc)(void *, AppProto), void(*StateFree)(void *))
Definition: app-layer-parser.c:431
ENIPEncapHdr_
Definition: app-layer-enip-common.h:94
app-layer-parser.h
util-profiling.h
SCReturn
#define SCReturn
Definition: util-debug.h:273
stream.h
AppLayerParserRegisterProtocolUnittests
void AppLayerParserRegisterProtocolUnittests(uint8_t ipproto, AppProto alproto, void(*RegisterUnittests)(void))
Definition: app-layer-parser.c:1910
AppLayerGetTxIterState
Definition: app-layer-parser.h:144
ENIPState_::buffer
uint8_t * buffer
Definition: app-layer-enip-common.h:225
APP_LAYER_PARSER_EOF_TC
#define APP_LAYER_PARSER_EOF_TC
Definition: app-layer-parser.h:40
conf.h
ENIPTransaction_::tx_data
AppLayerTxData tx_data
Definition: app-layer-enip-common.h:206
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:585
AppLayerProtoDetectRegisterProtocol
void AppLayerProtoDetectRegisterProtocol(AppProto alproto, const char *alproto_name)
Registers a protocol for protocol detection phase.
Definition: app-layer-detect-proto.c:1785
ENIPParserRegisterTests
void ENIPParserRegisterTests(void)
Definition: app-layer-enip.c:707
RunmodeIsUnittests
int RunmodeIsUnittests(void)
Definition: suricata.c:251
INDICATE_STATUS
#define INDICATE_STATUS
Definition: app-layer-enip-common.h:38
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:224
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:392
DetectEngineStateFree
void DetectEngineStateFree(DetectEngineState *state)
Frees a DetectEngineState object.
Definition: detect-engine-state.c:174
ENIPTransaction_::tx_num
uint64_t tx_num
Definition: app-layer-enip-common.h:194
AppLayerParserThreadCtxAlloc
AppLayerParserThreadCtx * AppLayerParserThreadCtxAlloc(void)
Gets a new app layer protocol's parser thread context.
Definition: app-layer-parser.c:293
AppLayerParserRegisterGetTx
void AppLayerParserRegisterGetTx(uint8_t ipproto, AppProto alproto, void *(StateGetTx)(void *alstate, uint64_t tx_id))
Definition: app-layer-parser.c:529
ENIPState_::iter
ENIPTransaction * iter
Definition: app-layer-enip-common.h:215
ENIPTransaction_
Definition: app-layer-enip-common.h:192
util-mem.h
NO_RESOURCES
#define NO_RESOURCES
Definition: app-layer-enip-common.h:51
APP_LAYER_OK
#define APP_LAYER_OK
Definition: app-layer-parser.h:88
AppLayerTxData
struct AppLayerTxData AppLayerTxData
Definition: detect.h:1346
BYTE_LITTLE_ENDIAN
#define BYTE_LITTLE_ENDIAN
Definition: util-byte.h:30
app-layer-enip.h
SCMapEnumValueToName
const char * SCMapEnumValueToName(int enum_value, SCEnumCharMap *table)
Maps an enum value to a string name, from the supplied table.
Definition: util-enum.c:68
SCReturnStruct
#define SCReturnStruct(x)
Definition: util-debug.h:291
FAIL_IF
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
Definition: util-unittest.h:71
StreamTcpFreeConfig
void StreamTcpFreeConfig(bool quiet)
Definition: stream-tcp.c:690
SCMapEnumNameToValue
int SCMapEnumNameToValue(const char *enum_name, SCEnumCharMap *table)
Maps a string name to an enum value from the supplied table. Please specify the last element of any m...
Definition: util-enum.c:40
AppLayerParserParse
int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto, uint8_t flags, const uint8_t *input, uint32_t input_len)
Definition: app-layer-parser.c:1307
suricata-common.h
ENIPTransaction_::tx_id
uint16_t tx_id
Definition: app-layer-enip-common.h:195
SCEnumCharMap_
Definition: util-enum.h:27
TAILQ_NEXT
#define TAILQ_NEXT(elm, field)
Definition: queue.h:307
RegisterENIPUDPParsers
void RegisterENIPUDPParsers(void)
Function to register the ENIP protocol parsers and other functions.
Definition: app-layer-enip.c:502
AppLayerParserRegisterStateDataFunc
void AppLayerParserRegisterStateDataFunc(uint8_t ipproto, AppProto alproto, AppLayerStateData *(*GetStateData)(void *state))
Definition: app-layer-parser.c:607
AppLayerParserRegisterTxDataFunc
void AppLayerParserRegisterTxDataFunc(uint8_t ipproto, AppProto alproto, AppLayerTxData *(*GetTxData)(void *tx))
Definition: app-layer-parser.c:597
ENIPState_::curr
ENIPTransaction * curr
Definition: app-layer-enip-common.h:214
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
SCLogConfig
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
APP_LAYER_PARSER_OPT_ACCEPT_GAPS
#define APP_LAYER_PARSER_OPT_ACCEPT_GAPS
Definition: app-layer-parser.h:47
AppLayerParserRegisterGetTxIterator
void AppLayerParserRegisterGetTxIterator(uint8_t ipproto, AppProto alproto, AppLayerGetTxIteratorFunc Func)
Definition: app-layer-parser.c:540
UNSUPPORTED_PROT_REV
#define UNSUPPORTED_PROT_REV
Definition: app-layer-enip-common.h:55
SCLogError
#define SCLogError(...)
Macro used to log ERROR messages.
Definition: util-debug.h:261
SCFree
#define SCFree(p)
Definition: util-mem.h:61
ENIPTransaction_::service_count
uint16_t service_count
Definition: app-layer-enip-common.h:196
ENIPEncapHdr
struct ENIPEncapHdr_ ENIPEncapHdr
Flow_::alstate
void * alstate
Definition: flow.h:472
detect-parse.h
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:563
app-layer-enip-common.h
ENIPState_::tx_with_detect_state_cnt
uint64_t tx_with_detect_state_cnt
Definition: app-layer-enip-common.h:217
ALPROTO_UNKNOWN
@ ALPROTO_UNKNOWN
Definition: app-layer-protos.h:29
ALPROTO_FAILED
@ ALPROTO_FAILED
Definition: app-layer-protos.h:70
ENIPEncapHdr_::length
uint16_t length
Definition: app-layer-enip-common.h:100
app-layer-protos.h
ENIPState_::transaction_max
uint64_t transaction_max
Definition: app-layer-enip-common.h:216
suricata.h
AppLayerParserRegisterGetTxCnt
void AppLayerParserRegisterGetTxCnt(uint8_t ipproto, AppProto alproto, uint64_t(*StateGetTxCnt)(void *alstate))
Definition: app-layer-parser.c:518
APP_LAYER_ERROR
#define APP_LAYER_ERROR
Definition: app-layer-parser.h:92
AppLayerParserThreadCtx_
Definition: app-layer-parser.c:66
AppLayerProtoDetectConfProtoDetectionEnabledDefault
int AppLayerProtoDetectConfProtoDetectionEnabledDefault(const char *ipproto, const char *alproto, bool default_enabled)
Given a protocol name, checks if proto detection is enabled in the conf file.
Definition: app-layer-detect-proto.c:1890
TcpSession_
Definition: stream-tcp-private.h:283
util-misc.h
AppLayerParserStateIssetFlag
uint16_t AppLayerParserStateIssetFlag(AppLayerParserState *pstate, uint16_t flag)
Definition: app-layer-parser.c:1806
Flow_::alproto
AppProto alproto
application level protocol
Definition: flow.h:446
ENIPTransaction_::header
ENIPEncapHdr header
Definition: app-layer-enip-common.h:198
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
util-enum.h
FLOW_DESTROY
#define FLOW_DESTROY(f)
Definition: flow-util.h:127
UNREGISTER_SESSION
#define UNREGISTER_SESSION
Definition: app-layer-enip-common.h:35
app-layer.h
SUCCESS
#define SUCCESS
Definition: app-layer-enip-common.h:49