suricata
app-layer-enip.c
Go to the documentation of this file.
1 /* Copyright (C) 2015-2024 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 = SCCalloc(1, sizeof(ENIPState));
148  if (unlikely(s == NULL))
149  return NULL;
150 
151  ENIPState *enip_state = (ENIPState *) s;
152 
153  TAILQ_INIT(&enip_state->tx_list);
154  return s;
155 }
156 
157 /** \internal
158  * \brief Free a ENIP TX
159  * \param tx ENIP TX to free */
160 static void ENIPTransactionFree(ENIPTransaction *tx, ENIPState *state)
161 {
162  SCEnter();
163  SCLogDebug("ENIPTransactionFree");
164  CIPServiceEntry *svc = NULL;
165  while ((svc = TAILQ_FIRST(&tx->service_list)))
166  {
167  TAILQ_REMOVE(&tx->service_list, svc, next);
168 
169  SegmentEntry *seg = NULL;
170  while ((seg = TAILQ_FIRST(&svc->segment_list)))
171  {
172  TAILQ_REMOVE(&svc->segment_list, seg, next);
173  SCFree(seg);
174  }
175 
176  AttributeEntry *attr = NULL;
177  while ((attr = TAILQ_FIRST(&svc->attrib_list)))
178  {
179  TAILQ_REMOVE(&svc->attrib_list, attr, next);
180  SCFree(attr);
181  }
182 
183  SCFree(svc);
184  }
185 
187 
188  if (tx->tx_data.de_state != NULL) {
189  DetectEngineStateFree(tx->tx_data.de_state);
190 
191  state->tx_with_detect_state_cnt--;
192  }
193 
194  if (state->iter == tx)
195  state->iter = NULL;
196 
197  SCFree(tx);
198  SCReturn;
199 }
200 
201 /** \brief Free enip state
202  *
203  */
204 static void ENIPStateFree(void *s)
205 {
206  SCEnter();
207  SCLogDebug("ENIPStateFree");
208  if (s)
209  {
210  ENIPState *enip_state = (ENIPState *) s;
211 
212  ENIPTransaction *tx = NULL;
213  while ((tx = TAILQ_FIRST(&enip_state->tx_list)))
214  {
215  TAILQ_REMOVE(&enip_state->tx_list, tx, next);
216  ENIPTransactionFree(tx, enip_state);
217  }
218 
219  if (enip_state->buffer != NULL)
220  {
221  SCFree(enip_state->buffer);
222  }
223 
224  SCFree(s);
225  }
226  SCReturn;
227 }
228 
229 /** \internal
230  * \brief Allocate a ENIP TX
231  * \retval tx or NULL */
232 static ENIPTransaction *ENIPTransactionAlloc(ENIPState *state)
233 {
234  SCLogDebug("ENIPStateTransactionAlloc");
236  sizeof(ENIPTransaction));
237  if (unlikely(tx == NULL))
238  return NULL;
239 
240  state->curr = tx;
241  state->transaction_max++;
242 
243  TAILQ_INIT(&tx->service_list);
244 
245  tx->enip = state;
246  tx->tx_num = state->transaction_max;
247  tx->service_count = 0;
248 
249  TAILQ_INSERT_TAIL(&state->tx_list, tx, next);
250 
251  return tx;
252 }
253 
254 /**
255  * \brief enip transaction cleanup callback
256  */
257 static void ENIPStateTransactionFree(void *state, uint64_t tx_id)
258 {
259  SCEnter();
260  SCLogDebug("ENIPStateTransactionFree");
261  ENIPState *enip_state = state;
262  ENIPTransaction *tx = NULL;
263  TAILQ_FOREACH(tx, &enip_state->tx_list, next)
264  {
265 
266  if ((tx_id+1) < tx->tx_num)
267  break;
268  else if ((tx_id+1) > tx->tx_num)
269  continue;
270 
271  if (tx == enip_state->curr)
272  enip_state->curr = NULL;
273 
274  if (tx->tx_data.events != NULL) {
275  if (tx->tx_data.events->cnt <= enip_state->events)
276  enip_state->events -= tx->tx_data.events->cnt;
277  else
278  enip_state->events = 0;
279  }
280 
281  TAILQ_REMOVE(&enip_state->tx_list, tx, next);
282  ENIPTransactionFree(tx, state);
283  break;
284  }
285  SCReturn;
286 }
287 
288 /** \internal
289  *
290  * \brief This function is called to retrieve a ENIP
291  *
292  * \param state ENIP state structure for the parser
293  * \param input Input line of the command
294  * \param input_len Length of the request
295  *
296  * \retval 1 when the command is parsed, 0 otherwise
297  */
298 static AppLayerResult ENIPParse(Flow *f, void *state, AppLayerParserState *pstate,
299  StreamSlice stream_slice, void *local_data, uint8_t direction)
300 {
301  SCEnter();
302  ENIPState *enip = (ENIPState *) state;
303  ENIPTransaction *tx;
304 
305  const uint8_t *input = StreamSliceGetData(&stream_slice);
306  uint32_t input_len = StreamSliceGetDataLen(&stream_slice);
307 
308  if (input == NULL && AppLayerParserStateIssetFlag(pstate,
310  {
312  } else if (input == NULL && input_len != 0) {
313  // GAP
315  } else if (input == NULL || input_len == 0)
316  {
318  }
319 
320  while (input_len > 0)
321  {
322  tx = ENIPTransactionAlloc(enip);
323  if (tx == NULL)
325 
326  if (direction == STREAM_TOCLIENT)
327  tx->tx_data.detect_flags_ts |= APP_LAYER_TX_SKIP_INSPECT_FLAG;
328  else
329  tx->tx_data.detect_flags_tc |= APP_LAYER_TX_SKIP_INSPECT_FLAG;
330 
331  SCLogDebug("ENIPParse input len %d", input_len);
332  DecodeENIPPDU(input, input_len, tx);
333  uint32_t pkt_len = tx->header.length + sizeof(ENIPEncapHdr);
334  SCLogDebug("ENIPParse packet len %d", pkt_len);
335  if (pkt_len > input_len)
336  {
337  SCLogDebug("Invalid packet length");
338  break;
339  }
340 
341  input += pkt_len;
342  input_len -= pkt_len;
343  //SCLogDebug("remaining %d", input_len);
344 
345  if (input_len < sizeof(ENIPEncapHdr))
346  {
347  //SCLogDebug("Not enough data"); //not enough data for ENIP
348  break;
349  }
350  }
351 
353 }
354 
355 static AppLayerResult ENIPParseRequest(Flow *f, void *state, AppLayerParserState *pstate,
356  StreamSlice stream_slice, void *local_data)
357 {
358  return ENIPParse(f, state, pstate, stream_slice, local_data, STREAM_TOSERVER);
359 }
360 
361 static AppLayerResult ENIPParseResponse(Flow *f, void *state, AppLayerParserState *pstate,
362  StreamSlice stream_slice, void *local_data)
363 {
364  return ENIPParse(f, state, pstate, stream_slice, local_data, STREAM_TOCLIENT);
365 }
366 
367 #define ENIP_LEN_REGISTER_SESSION 4 // protocol u16, options u16
368 
369 static uint16_t ENIPProbingParser(Flow *f, uint8_t direction,
370  const uint8_t *input, uint32_t input_len, uint8_t *rdir)
371 {
372  // SCLogDebug("ENIPProbingParser %d", input_len);
373  if (input_len < sizeof(ENIPEncapHdr))
374  {
375  SCLogDebug("length too small to be a ENIP header");
376  return ALPROTO_UNKNOWN;
377  }
378  uint16_t cmd;
379  uint16_t enip_len;
380  uint32_t status;
381  uint32_t option;
382  uint16_t nbitems;
383 
384  int ret = ByteExtractUint32(
385  &status, BYTE_LITTLE_ENDIAN, sizeof(uint32_t), (const uint8_t *)(input + 8));
386  if (ret < 0) {
387  return ALPROTO_FAILED;
388  }
389  switch (status) {
390  case SUCCESS:
391  case INVALID_CMD:
392  case NO_RESOURCES:
393  case INCORRECT_DATA:
394  case INVALID_SESSION:
395  case INVALID_LENGTH:
397  case ENCAP_HEADER_ERROR:
398  break;
399  default:
400  return ALPROTO_FAILED;
401  }
402  ret = ByteExtractUint16(&cmd, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), (const uint8_t *)(input));
403  if(ret < 0) {
404  return ALPROTO_FAILED;
405  }
406  ret = ByteExtractUint32(
407  &option, BYTE_LITTLE_ENDIAN, sizeof(uint32_t), (const uint8_t *)(input + 20));
408  if (ret < 0) {
409  return ALPROTO_FAILED;
410  }
411  ret = ByteExtractUint16(
412  &enip_len, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), (const uint8_t *)(input + 2));
413  if (ret < 0) {
414  return ALPROTO_FAILED;
415  }
416 
417  //ok for all the known commands
418  switch(cmd) {
419  case NOP:
420  if (option != 0) {
421  return ALPROTO_FAILED;
422  }
423  break;
424  case REGISTER_SESSION:
425  if (enip_len != ENIP_LEN_REGISTER_SESSION) {
426  return ALPROTO_FAILED;
427  }
428  break;
429  case UNREGISTER_SESSION:
430  if (enip_len != ENIP_LEN_REGISTER_SESSION && enip_len != 0) {
431  // 0 for request and 4 for response
432  return ALPROTO_FAILED;
433  }
434  break;
435  case LIST_SERVICES:
436  case LIST_IDENTITY:
437  case SEND_RR_DATA:
438  case SEND_UNIT_DATA:
439  case INDICATE_STATUS:
440  case CANCEL:
441  break;
442  case LIST_INTERFACES:
443  if (input_len < sizeof(ENIPEncapHdr) + 2) {
444  SCLogDebug("length too small to be a ENIP LIST_INTERFACES");
445  return ALPROTO_UNKNOWN;
446  }
447  ret = ByteExtractUint16(
448  &nbitems, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), (const uint8_t *)(input));
449  if(ret < 0) {
450  return ALPROTO_FAILED;
451  }
452  if (enip_len < sizeof(ENIPEncapHdr) + 2 * (size_t)nbitems) {
453  return ALPROTO_FAILED;
454  }
455  break;
456  default:
457  return ALPROTO_FAILED;
458  }
459  return ALPROTO_ENIP;
460 }
461 
462 static AppLayerGetTxIterTuple ENIPGetTxIterator(const uint8_t ipproto, const AppProto alproto,
463  void *alstate, uint64_t min_tx_id, uint64_t max_tx_id, AppLayerGetTxIterState *state)
464 {
465  ENIPState *enip_state = (ENIPState *)alstate;
466  AppLayerGetTxIterTuple no_tuple = { NULL, 0, false };
467  if (enip_state) {
468  ENIPTransaction *tx_ptr;
469  if (state->un.ptr == NULL) {
470  tx_ptr = TAILQ_FIRST(&enip_state->tx_list);
471  } else {
472  tx_ptr = (ENIPTransaction *)state->un.ptr;
473  }
474  if (tx_ptr) {
475  while (tx_ptr->tx_num < min_tx_id + 1) {
476  tx_ptr = TAILQ_NEXT(tx_ptr, next);
477  if (!tx_ptr) {
478  return no_tuple;
479  }
480  }
481  if (tx_ptr->tx_num >= max_tx_id + 1) {
482  return no_tuple;
483  }
484  state->un.ptr = TAILQ_NEXT(tx_ptr, next);
485  AppLayerGetTxIterTuple tuple = {
486  .tx_ptr = tx_ptr,
487  .tx_id = tx_ptr->tx_num - 1,
488  .has_next = (state->un.ptr != NULL),
489  };
490  return tuple;
491  }
492  }
493  return no_tuple;
494 }
495 
496 /**
497  * \brief Function to register the ENIP protocol parsers and other functions
498  */
500 {
501  SCEnter();
502  const char *proto_name = "enip";
503 
504  if (AppLayerProtoDetectConfProtoDetectionEnabledDefault("udp", proto_name, false)) {
506 
507  if (RunmodeIsUnittests())
508  {
509  AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818", ALPROTO_ENIP,
510  0, sizeof(ENIPEncapHdr), STREAM_TOSERVER, ENIPProbingParser, NULL);
511 
512  AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818", ALPROTO_ENIP,
513  0, sizeof(ENIPEncapHdr), STREAM_TOCLIENT, ENIPProbingParser, NULL);
514 
515  } else
516  {
517  if (!AppLayerProtoDetectPPParseConfPorts("udp", IPPROTO_UDP,
518  proto_name, ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr),
519  ENIPProbingParser, ENIPProbingParser))
520  {
521  SCLogDebug(
522  "no ENIP UDP config found enabling ENIP detection on port 44818.");
523 
524  AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818",
525  ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr), STREAM_TOSERVER,
526  ENIPProbingParser, NULL);
527 
528  AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818",
529  ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr), STREAM_TOCLIENT,
530  ENIPProbingParser, NULL);
531  }
532  }
533 
534  } else {
535  SCLogConfig("Protocol detection and parser disabled for %s protocol.",
536  proto_name);
537  return;
538  }
539 
540  if (AppLayerParserConfParserEnabled("udp", proto_name))
541  {
542  AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_ENIP, STREAM_TOSERVER, ENIPParseRequest);
543  AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_ENIP, STREAM_TOCLIENT, ENIPParseResponse);
544 
546  ENIPStateAlloc, ENIPStateFree);
547 
548  AppLayerParserRegisterGetTx(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetTx);
549  AppLayerParserRegisterGetTxIterator(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetTxIterator);
550  AppLayerParserRegisterTxDataFunc(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetTxData);
551  AppLayerParserRegisterStateDataFunc(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetStateData);
552  AppLayerParserRegisterGetTxCnt(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetTxCnt);
553  AppLayerParserRegisterTxFreeFunc(IPPROTO_UDP, ALPROTO_ENIP, ENIPStateTransactionFree);
554 
555  AppLayerParserRegisterGetStateProgressFunc(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetAlstateProgress);
557 
558  AppLayerParserRegisterGetEventInfo(IPPROTO_UDP, ALPROTO_ENIP, ENIPStateGetEventInfo);
559  AppLayerParserRegisterGetEventInfoById(IPPROTO_UDP, ALPROTO_ENIP, ENIPStateGetEventInfoById);
560 
562  IPPROTO_UDP, ALPROTO_ENIP, STREAM_TOSERVER | STREAM_TOCLIENT);
563  } else
564  {
565  SCLogInfo("Parser disabled for %s protocol. Protocol detection still on.", proto_name);
566  }
567 
568 #ifdef UNITTESTS
570 #endif
571 
572  SCReturn;
573 }
574 
575 /**
576  * \brief Function to register the ENIP protocol parsers and other functions
577  */
579 {
580  SCEnter();
581  const char *proto_name = "enip";
582 
583  if (AppLayerProtoDetectConfProtoDetectionEnabledDefault("tcp", proto_name, false)) {
585 
586  if (RunmodeIsUnittests())
587  {
588  AppLayerProtoDetectPPRegister(IPPROTO_TCP, "44818", ALPROTO_ENIP,
589  0, sizeof(ENIPEncapHdr), STREAM_TOSERVER, ENIPProbingParser, NULL);
590 
591  AppLayerProtoDetectPPRegister(IPPROTO_TCP, "44818", ALPROTO_ENIP,
592  0, sizeof(ENIPEncapHdr), STREAM_TOCLIENT, ENIPProbingParser, NULL);
593 
594  } else
595  {
596  if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP,
597  proto_name, ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr),
598  ENIPProbingParser, ENIPProbingParser))
599  {
600  SCLogDebug("no ENIP TCP config found enabling ENIP detection on port 44818.");
601 
602  AppLayerProtoDetectPPRegister(IPPROTO_TCP, "44818", ALPROTO_ENIP, 0,
603  sizeof(ENIPEncapHdr), STREAM_TOSERVER, ENIPProbingParser, NULL);
604 
605  AppLayerProtoDetectPPRegister(IPPROTO_TCP, "44818", ALPROTO_ENIP, 0,
606  sizeof(ENIPEncapHdr), STREAM_TOCLIENT, ENIPProbingParser, NULL);
607 
608  return;
609  }
610  }
611 
612  } else {
613  SCLogDebug("Protocol detection and parser disabled for %s protocol.",
614  proto_name);
615  return;
616  }
617 
618  if (AppLayerParserConfParserEnabled("tcp", proto_name))
619  {
620  AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_ENIP, STREAM_TOSERVER, ENIPParseRequest);
621  AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_ENIP, STREAM_TOCLIENT, ENIPParseResponse);
623  ENIPStateAlloc, ENIPStateFree);
624 
625  AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetTx);
626  AppLayerParserRegisterGetTxIterator(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetTxIterator);
627  AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetTxData);
628  AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetStateData);
629  AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetTxCnt);
630  AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_ENIP, ENIPStateTransactionFree);
631 
632  AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetAlstateProgress);
634 
635  AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_ENIP, ENIPStateGetEventInfo);
636 
638  ALPROTO_ENIP, STREAM_TOSERVER | STREAM_TOCLIENT);
639 
640  /* This parser accepts gaps. */
643 
645  } else
646  {
647  SCLogConfig("Parser disabled for %s protocol. Protocol detection still on.",
648  proto_name);
649  }
650 
651 #ifdef UNITTESTS
653 #endif
654 
655  SCReturn;
656 }
657 
658 /* UNITTESTS */
659 #ifdef UNITTESTS
660 #include "flow-util.h"
661 #include "stream-tcp.h"
662 
663 static uint8_t listIdentity[] = {/* List ID */ 0x63, 0x00,
664  /* Length */ 0x00, 0x00,
665  /* Session */ 0x00, 0x00, 0x00, 0x00,
666  /* Status */ 0x00, 0x00, 0x00, 0x00,
667  /* Delay*/ 0x00,
668  /* Context */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
669  /* Quantity of coils */ 0x00, 0x00, 0x00, 0x00, 0x00};
670 
671 /**
672  * \brief Test if ENIP Packet matches signature
673  */
674 static int ALDecodeENIPTest(void)
675 {
677  Flow f;
678  TcpSession ssn;
679 
680  memset(&f, 0, sizeof(f));
681  memset(&ssn, 0, sizeof(ssn));
682 
683  f.protoctx = (void *)&ssn;
684  f.proto = IPPROTO_TCP;
685  f.alproto = ALPROTO_ENIP;
686 
687  StreamTcpInitConfig(true);
688 
689  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_ENIP, STREAM_TOSERVER,
690  listIdentity, sizeof(listIdentity));
691  FAIL_IF(r != 0);
692 
693  ENIPState *enip_state = f.alstate;
694  FAIL_IF_NULL(enip_state);
695 
696  ENIPTransaction *tx = ENIPGetTx(enip_state, 0);
697  FAIL_IF_NULL(tx);
698 
699  FAIL_IF(tx->header.command != 99);
700 
702  StreamTcpFreeConfig(true);
703  FLOW_DESTROY(&f);
704 
705  PASS;
706 }
707 
708 #endif /* UNITTESTS */
709 
711 {
712 #ifdef UNITTESTS
713  UtRegisterTest("ALDecodeENIPTest", ALDecodeENIPTest);
714 #endif /* UNITTESTS */
715 }
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:488
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:1583
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:413
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:191
Flow_::proto
uint8_t proto
Definition: flow.h:373
AppProto
uint16_t AppProto
Definition: app-layer-protos.h:81
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:332
Flow_
Flow data structure.
Definition: flow.h:351
AppLayerParserRegisterStateProgressCompletionStatus
void AppLayerParserRegisterStateProgressCompletionStatus(AppProto alproto, const int ts, const int tc)
Definition: app-layer-parser.c:540
ENIP_LEN_REGISTER_SESSION
#define ENIP_LEN_REGISTER_SESSION
Definition: app-layer-enip.c:367
AppLayerParserRegisterParserAcceptableDataDirection
void AppLayerParserRegisterParserAcceptableDataDirection(uint8_t ipproto, AppProto alproto, uint8_t direction)
Definition: app-layer-parser.c:402
AppLayerParserRegisterTxFreeFunc
void AppLayerParserRegisterTxFreeFunc(uint8_t ipproto, AppProto alproto, void(*StateTransactionFree)(void *, uint64_t))
Definition: app-layer-parser.c:499
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:312
INVALID_CMD
#define INVALID_CMD
Definition: app-layer-enip-common.h:50
AppLayerDecoderEventsFreeEvents
void AppLayerDecoderEventsFreeEvents(AppLayerDecoderEvents **events)
Definition: app-layer-events.c:133
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:441
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:1543
app-layer-detect-proto.h
StreamTcpInitConfig
void StreamTcpInitConfig(bool)
To initialize the stream global configuration data.
Definition: stream-tcp.c:463
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:138
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:578
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:423
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:1877
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:577
AppLayerProtoDetectRegisterProtocol
void AppLayerProtoDetectRegisterProtocol(AppProto alproto, const char *alproto_name)
Registers a protocol for protocol detection phase.
Definition: app-layer-detect-proto.c:1761
ENIPParserRegisterTests
void ENIPParserRegisterTests(void)
Definition: app-layer-enip.c:710
RunmodeIsUnittests
int RunmodeIsUnittests(void)
Definition: suricata.c:257
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:390
DetectEngineStateFree
void DetectEngineStateFree(DetectEngineState *state)
Frees a DetectEngineState object.
Definition: detect-engine-state.c:172
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:291
AppLayerParserRegisterGetTx
void AppLayerParserRegisterGetTx(uint8_t ipproto, AppProto alproto, void *(StateGetTx)(void *alstate, uint64_t tx_id))
Definition: app-layer-parser.c:521
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:1358
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:794
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:1292
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:499
AppLayerParserRegisterStateDataFunc
void AppLayerParserRegisterStateDataFunc(uint8_t ipproto, AppProto alproto, AppLayerStateData *(*GetStateData)(void *state))
Definition: app-layer-parser.c:599
AppLayerParserRegisterTxDataFunc
void AppLayerParserRegisterTxDataFunc(uint8_t ipproto, AppProto alproto, AppLayerTxData *(*GetTxData)(void *tx))
Definition: app-layer-parser.c:589
ENIPState_::curr
ENIPTransaction * curr
Definition: app-layer-enip-common.h:214
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:532
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:476
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:555
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:71
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:510
APP_LAYER_ERROR
#define APP_LAYER_ERROR
Definition: app-layer-parser.h:92
AppLayerParserThreadCtx_
Definition: app-layer-parser.c:65
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:1866
TcpSession_
Definition: stream-tcp-private.h:283
util-misc.h
AppLayerParserStateIssetFlag
uint16_t AppLayerParserStateIssetFlag(AppLayerParserState *pstate, uint16_t flag)
Definition: app-layer-parser.c:1794
Flow_::alproto
AppProto alproto
application level protocol
Definition: flow.h:450
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:121
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