]> git.ipfire.org Git - people/ms/suricata.git/blame - src/app-layer-enip.c
enip: fix int warnings
[people/ms/suricata.git] / src / app-layer-enip.c
CommitLineData
a3ffebd8 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
29#include "util-debug.h"
30#include "util-byte.h"
31#include "util-enum.h"
32#include "util-mem.h"
33#include "util-misc.h"
34
35#include "stream.h"
36
37#include "app-layer-protos.h"
38#include "app-layer-parser.h"
39#include "app-layer-enip.h"
40#include "app-layer-enip-common.h"
41
42#include "app-layer-detect-proto.h"
43
44#include "conf.h"
45#include "decode.h"
46
47#include "detect-parse.h"
48#include "detect-engine.h"
49#include "util-byte.h"
50#include "util-unittest.h"
51#include "util-unittest-helper.h"
52#include "pkt-var.h"
53#include "util-profiling.h"
54
55
56SCEnumCharMap enip_decoder_event_table[ ] = {
57 { NULL, -1 },
58};
59
60/** \brief get value for 'complete' status in ENIP
61 *
62 * For ENIP we use a simple bool.
63 */
ab1200fb 64static int ENIPGetAlstateProgress(void *tx, uint8_t direction)
a3ffebd8 65{
66 return 1;
67}
68
7d663ed5 69static AppLayerTxData *ENIPGetTxData(void *vtx)
706558d4
JI
70{
71 ENIPTransaction *tx = (ENIPTransaction *)vtx;
7d663ed5 72 return &tx->tx_data;
706558d4
JI
73}
74
ab1200fb
VJ
75static void *ENIPGetTx(void *alstate, uint64_t tx_id)
76{
a3ffebd8 77 ENIPState *enip = (ENIPState *) alstate;
78 ENIPTransaction *tx = NULL;
79
80 if (enip->curr && enip->curr->tx_num == tx_id + 1)
81 return enip->curr;
82
83 TAILQ_FOREACH(tx, &enip->tx_list, next) {
84 if (tx->tx_num != (tx_id+1))
85 continue;
86
87 SCLogDebug("returning tx %p", tx);
88 return tx;
89 }
90
91 return NULL;
92}
93
ab1200fb
VJ
94static uint64_t ENIPGetTxCnt(void *alstate)
95{
86f5d33f 96 return ((ENIPState *)alstate)->transaction_max;
a3ffebd8 97}
98
d568e7fa 99static AppLayerDecoderEvents *ENIPGetEvents(void *tx)
ab1200fb 100{
d568e7fa 101 return ((ENIPTransaction *)tx)->decoder_events;
a3ffebd8 102}
103
ab1200fb
VJ
104static int ENIPStateGetEventInfo(const char *event_name, int *event_id, AppLayerEventType *event_type)
105{
a3ffebd8 106 *event_id = SCMapEnumNameToValue(event_name, enip_decoder_event_table);
107
108 if (*event_id == -1) {
109 SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%s\" not present in "
110 "enip's enum map table.", event_name);
111 /* yes this is fatal */
112 return -1;
113 }
114
115 *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
116
117 return 0;
118}
119
f7b934f8
JL
120static int ENIPStateGetEventInfoById(int event_id, const char **event_name,
121 AppLayerEventType *event_type)
122{
123 *event_name = SCMapEnumValueToName(event_id, enip_decoder_event_table);
124 if (*event_name == NULL) {
125 SCLogError(SC_ERR_INVALID_ENUM_MAP, "event \"%d\" not present in "
126 "enip's enum map table.", event_id);
127 /* yes this is fatal */
128 return -1;
129 }
130
131 *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
132
133 return 0;
134}
135
a3ffebd8 136/** \brief Allocate enip state
137 *
138 * return state
139 */
547d6c2d 140static void *ENIPStateAlloc(void *orig_state, AppProto proto_orig)
a3ffebd8 141{
72b5da43 142 SCLogDebug("ENIPStateAlloc");
a3ffebd8 143 void *s = SCMalloc(sizeof(ENIPState));
144 if (unlikely(s == NULL))
145 return NULL;
146
147 memset(s, 0, sizeof(ENIPState));
148
149 ENIPState *enip_state = (ENIPState *) s;
150
151 TAILQ_INIT(&enip_state->tx_list);
152 return s;
153}
154
155/** \internal
156 * \brief Free a ENIP TX
157 * \param tx ENIP TX to free */
158static void ENIPTransactionFree(ENIPTransaction *tx, ENIPState *state)
159{
160 SCEnter();
72b5da43 161 SCLogDebug("ENIPTransactionFree");
a3ffebd8 162 CIPServiceEntry *svc = NULL;
163 while ((svc = TAILQ_FIRST(&tx->service_list)))
164 {
165 TAILQ_REMOVE(&tx->service_list, svc, next);
166
167 SegmentEntry *seg = NULL;
168 while ((seg = TAILQ_FIRST(&svc->segment_list)))
169 {
170 TAILQ_REMOVE(&svc->segment_list, seg, next);
171 SCFree(seg);
172 }
173
174 AttributeEntry *attr = NULL;
175 while ((attr = TAILQ_FIRST(&svc->attrib_list)))
176 {
177 TAILQ_REMOVE(&svc->attrib_list, attr, next);
178 SCFree(attr);
179 }
180
181 SCFree(svc);
182 }
183
184 AppLayerDecoderEventsFreeEvents(&tx->decoder_events);
185
9c67c634
JI
186 if (tx->tx_data.de_state != NULL) {
187 DetectEngineStateFree(tx->tx_data.de_state);
a3ffebd8 188
189 state->tx_with_detect_state_cnt--;
190 }
191
192 if (state->iter == tx)
193 state->iter = NULL;
194
195 SCFree(tx);
196 SCReturn;
197}
198
199/** \brief Free enip state
200 *
201 */
ab1200fb 202static void ENIPStateFree(void *s)
a3ffebd8 203{
204 SCEnter();
72b5da43 205 SCLogDebug("ENIPStateFree");
a3ffebd8 206 if (s)
207 {
208 ENIPState *enip_state = (ENIPState *) s;
209
210 ENIPTransaction *tx = NULL;
211 while ((tx = TAILQ_FIRST(&enip_state->tx_list)))
212 {
213 TAILQ_REMOVE(&enip_state->tx_list, tx, next);
214 ENIPTransactionFree(tx, enip_state);
215 }
216
217 if (enip_state->buffer != NULL)
218 {
219 SCFree(enip_state->buffer);
220 }
221
222 SCFree(s);
223 }
224 SCReturn;
225}
226
227/** \internal
228 * \brief Allocate a ENIP TX
229 * \retval tx or NULL */
230static ENIPTransaction *ENIPTransactionAlloc(ENIPState *state)
231{
72b5da43 232 SCLogDebug("ENIPStateTransactionAlloc");
a3ffebd8 233 ENIPTransaction *tx = (ENIPTransaction *) SCCalloc(1,
234 sizeof(ENIPTransaction));
235 if (unlikely(tx == NULL))
236 return NULL;
237
238 state->curr = tx;
239 state->transaction_max++;
240
241 memset(tx, 0x00, sizeof(ENIPTransaction));
242 TAILQ_INIT(&tx->service_list);
243
244 tx->enip = state;
245 tx->tx_num = state->transaction_max;
246 tx->service_count = 0;
247
248 TAILQ_INSERT_TAIL(&state->tx_list, tx, next);
249
250 return tx;
251}
252
253/**
254 * \brief enip transaction cleanup callback
255 */
ab1200fb 256static void ENIPStateTransactionFree(void *state, uint64_t tx_id)
a3ffebd8 257{
258 SCEnter();
72b5da43 259 SCLogDebug("ENIPStateTransactionFree");
a3ffebd8 260 ENIPState *enip_state = state;
261 ENIPTransaction *tx = NULL;
262 TAILQ_FOREACH(tx, &enip_state->tx_list, next)
263 {
264
265 if ((tx_id+1) < tx->tx_num)
266 break;
267 else if ((tx_id+1) > tx->tx_num)
268 continue;
269
270 if (tx == enip_state->curr)
271 enip_state->curr = NULL;
272
273 if (tx->decoder_events != NULL)
274 {
275 if (tx->decoder_events->cnt <= enip_state->events)
276 enip_state->events -= tx->decoder_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 */
44d3f264 298static AppLayerResult ENIPParse(Flow *f, void *state, AppLayerParserState *pstate,
579cc9f0 299 const uint8_t *input, uint32_t input_len, void *local_data,
7bc3c3ac 300 const uint8_t flags)
a3ffebd8 301{
302 SCEnter();
303 ENIPState *enip = (ENIPState *) state;
304 ENIPTransaction *tx;
305
306 if (input == NULL && AppLayerParserStateIssetFlag(pstate,
4f73943d 307 APP_LAYER_PARSER_EOF_TS|APP_LAYER_PARSER_EOF_TC))
a3ffebd8 308 {
44d3f264 309 SCReturnStruct(APP_LAYER_OK);
700781c5
VJ
310 } else if (input == NULL && input_len != 0) {
311 // GAP
44d3f264 312 SCReturnStruct(APP_LAYER_OK);
a3ffebd8 313 } else if (input == NULL || input_len == 0)
314 {
44d3f264 315 SCReturnStruct(APP_LAYER_ERROR);
a3ffebd8 316 }
317
318 while (input_len > 0)
319 {
320 tx = ENIPTransactionAlloc(enip);
321 if (tx == NULL)
44d3f264 322 SCReturnStruct(APP_LAYER_OK);
a3ffebd8 323
72b5da43 324 SCLogDebug("ENIPParse input len %d", input_len);
a3ffebd8 325 DecodeENIPPDU(input, input_len, tx);
326 uint32_t pkt_len = tx->header.length + sizeof(ENIPEncapHdr);
72b5da43 327 SCLogDebug("ENIPParse packet len %d", pkt_len);
a3ffebd8 328 if (pkt_len > input_len)
329 {
72b5da43 330 SCLogDebug("Invalid packet length");
a3ffebd8 331 break;
332 }
333
334 input += pkt_len;
335 input_len -= pkt_len;
72b5da43 336 //SCLogDebug("remaining %d", input_len);
a3ffebd8 337
338 if (input_len < sizeof(ENIPEncapHdr))
339 {
72b5da43 340 //SCLogDebug("Not enough data"); //not enough data for ENIP
a3ffebd8 341 break;
342 }
343 }
344
44d3f264 345 SCReturnStruct(APP_LAYER_OK);
a3ffebd8 346}
347
0c948142 348#define ENIP_LEN_REGISTER_SESSION 4 // protocol u16, options u16
a3ffebd8 349
422e4892 350static uint16_t ENIPProbingParser(Flow *f, uint8_t direction,
579cc9f0 351 const uint8_t *input, uint32_t input_len, uint8_t *rdir)
a3ffebd8 352{
72b5da43 353 // SCLogDebug("ENIPProbingParser %d", input_len);
a3ffebd8 354 if (input_len < sizeof(ENIPEncapHdr))
355 {
72b5da43 356 SCLogDebug("length too small to be a ENIP header");
a3ffebd8 357 return ALPROTO_UNKNOWN;
358 }
a15e503b 359 uint16_t cmd;
0c948142 360 uint16_t enip_len;
0da4dc0d 361 uint32_t status;
0c948142
PA
362 uint32_t option;
363 uint16_t nbitems;
364
365 int ret = ByteExtractUint16(
366 &enip_len, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), (const uint8_t *)(input + 2));
367 if (ret < 0) {
368 return ALPROTO_FAILED;
369 }
370 if (enip_len < sizeof(ENIPEncapHdr)) {
371 return ALPROTO_FAILED;
372 }
373 ret = ByteExtractUint32(
374 &status, BYTE_LITTLE_ENDIAN, sizeof(uint32_t), (const uint8_t *)(input + 8));
375 if (ret < 0) {
376 return ALPROTO_FAILED;
377 }
378 switch (status) {
379 case SUCCESS:
380 case INVALID_CMD:
381 case NO_RESOURCES:
382 case INCORRECT_DATA:
383 case INVALID_SESSION:
384 case INVALID_LENGTH:
385 case UNSUPPORTED_PROT_REV:
386 case ENCAP_HEADER_ERROR:
387 break;
388 default:
389 return ALPROTO_FAILED;
390 }
391 ret = ByteExtractUint16(&cmd, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), (const uint8_t *)(input));
a15e503b
PA
392 if(ret < 0) {
393 return ALPROTO_FAILED;
394 }
0c948142
PA
395 ret = ByteExtractUint32(
396 &option, BYTE_LITTLE_ENDIAN, sizeof(uint32_t), (const uint8_t *)(input + 20));
397 if (ret < 0) {
398 return ALPROTO_FAILED;
399 }
400
a15e503b
PA
401 //ok for all the known commands
402 switch(cmd) {
403 case NOP:
0c948142
PA
404 if (option != 0) {
405 return ALPROTO_FAILED;
406 }
407 break;
a15e503b 408 case REGISTER_SESSION:
0c948142
PA
409 if (enip_len != ENIP_LEN_REGISTER_SESSION) {
410 return ALPROTO_FAILED;
411 }
412 break;
a15e503b 413 case UNREGISTER_SESSION:
0c948142
PA
414 if (enip_len != ENIP_LEN_REGISTER_SESSION && enip_len != 0) {
415 // 0 for request and 4 for response
416 return ALPROTO_FAILED;
417 }
418 break;
419 case LIST_SERVICES:
420 case LIST_IDENTITY:
a15e503b
PA
421 case SEND_RR_DATA:
422 case SEND_UNIT_DATA:
423 case INDICATE_STATUS:
424 case CANCEL:
0c948142
PA
425 break;
426 case LIST_INTERFACES:
427 if (input_len < sizeof(ENIPEncapHdr) + 2) {
428 SCLogDebug("length too small to be a ENIP LIST_INTERFACES");
429 return ALPROTO_UNKNOWN;
430 }
431 ret = ByteExtractUint16(
432 &nbitems, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), (const uint8_t *)(input));
0da4dc0d
PA
433 if(ret < 0) {
434 return ALPROTO_FAILED;
435 }
0c948142
PA
436 if (enip_len < sizeof(ENIPEncapHdr) + 2 * (size_t)nbitems) {
437 return ALPROTO_FAILED;
0da4dc0d 438 }
0c948142
PA
439 break;
440 default:
441 return ALPROTO_FAILED;
a15e503b 442 }
0c948142 443 return ALPROTO_ENIP;
a3ffebd8 444}
445
446/**
447 * \brief Function to register the ENIP protocol parsers and other functions
448 */
449void RegisterENIPUDPParsers(void)
450{
451 SCEnter();
ab1200fb 452 const char *proto_name = "enip";
a3ffebd8 453
ea4a509a 454 if (AppLayerProtoDetectConfProtoDetectionEnabledDefault("udp", proto_name, false)) {
a3ffebd8 455 AppLayerProtoDetectRegisterProtocol(ALPROTO_ENIP, proto_name);
456
457 if (RunmodeIsUnittests())
458 {
459 AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818", ALPROTO_ENIP,
c35c18a7 460 0, sizeof(ENIPEncapHdr), STREAM_TOSERVER, ENIPProbingParser, NULL);
a3ffebd8 461
462 AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818", ALPROTO_ENIP,
c35c18a7 463 0, sizeof(ENIPEncapHdr), STREAM_TOCLIENT, ENIPProbingParser, NULL);
a3ffebd8 464
465 } else
466 {
467 if (!AppLayerProtoDetectPPParseConfPorts("udp", IPPROTO_UDP,
468 proto_name, ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr),
c35c18a7 469 ENIPProbingParser, ENIPProbingParser))
a3ffebd8 470 {
471 SCLogDebug(
472 "no ENIP UDP config found enabling ENIP detection on port 44818.");
473
474 AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818",
475 ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr), STREAM_TOSERVER,
c35c18a7 476 ENIPProbingParser, NULL);
a3ffebd8 477
478 AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818",
479 ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr), STREAM_TOCLIENT,
c35c18a7 480 ENIPProbingParser, NULL);
a3ffebd8 481 }
482 }
483
ea4a509a 484 } else {
72b5da43 485 SCLogConfig("Protocol detection and parser disabled for %s protocol.",
a3ffebd8 486 proto_name);
487 return;
488 }
489
490 if (AppLayerParserConfParserEnabled("udp", proto_name))
491 {
492 AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_ENIP,
493 STREAM_TOSERVER, ENIPParse);
494 AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_ENIP,
495 STREAM_TOCLIENT, ENIPParse);
496
497 AppLayerParserRegisterStateFuncs(IPPROTO_UDP, ALPROTO_ENIP,
498 ENIPStateAlloc, ENIPStateFree);
499
500 AppLayerParserRegisterGetEventsFunc(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetEvents);
a3ffebd8 501
a3ffebd8 502 AppLayerParserRegisterGetTx(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetTx);
7d663ed5 503 AppLayerParserRegisterTxDataFunc(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetTxData);
a3ffebd8 504 AppLayerParserRegisterGetTxCnt(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetTxCnt);
505 AppLayerParserRegisterTxFreeFunc(IPPROTO_UDP, ALPROTO_ENIP, ENIPStateTransactionFree);
506
507 AppLayerParserRegisterGetStateProgressFunc(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetAlstateProgress);
efc9a7a3 508 AppLayerParserRegisterStateProgressCompletionStatus(ALPROTO_ENIP, 1, 1);
a3ffebd8 509
510 AppLayerParserRegisterGetEventInfo(IPPROTO_UDP, ALPROTO_ENIP, ENIPStateGetEventInfo);
f7b934f8 511 AppLayerParserRegisterGetEventInfoById(IPPROTO_UDP, ALPROTO_ENIP, ENIPStateGetEventInfoById);
a3ffebd8 512
513 AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_UDP,
514 ALPROTO_ENIP, STREAM_TOSERVER | STREAM_TOCLIENT);
2b215a45
JI
515 AppLayerParserRegisterOptionFlags(
516 IPPROTO_UDP, ALPROTO_ENIP, APP_LAYER_PARSER_OPT_UNIDIR_TXS);
a3ffebd8 517 } else
518 {
519 SCLogInfo(
520 "Parsed disabled for %s protocol. Protocol detection" "still on.",
521 proto_name);
522 }
523
524#ifdef UNITTESTS
525 AppLayerParserRegisterProtocolUnittests(IPPROTO_UDP, ALPROTO_ENIP, ENIPParserRegisterTests);
526#endif
527
528 SCReturn;
529}
530
531/**
532 * \brief Function to register the ENIP protocol parsers and other functions
533 */
534void RegisterENIPTCPParsers(void)
535{
536 SCEnter();
ab1200fb 537 const char *proto_name = "enip";
a3ffebd8 538
ea4a509a 539 if (AppLayerProtoDetectConfProtoDetectionEnabledDefault("tcp", proto_name, false)) {
a3ffebd8 540 AppLayerProtoDetectRegisterProtocol(ALPROTO_ENIP, proto_name);
541
542 if (RunmodeIsUnittests())
543 {
544 AppLayerProtoDetectPPRegister(IPPROTO_TCP, "44818", ALPROTO_ENIP,
c35c18a7 545 0, sizeof(ENIPEncapHdr), STREAM_TOSERVER, ENIPProbingParser, NULL);
a3ffebd8 546
547 AppLayerProtoDetectPPRegister(IPPROTO_TCP, "44818", ALPROTO_ENIP,
c35c18a7 548 0, sizeof(ENIPEncapHdr), STREAM_TOCLIENT, ENIPProbingParser, NULL);
a3ffebd8 549
550 } else
551 {
552 if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP,
553 proto_name, ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr),
c35c18a7 554 ENIPProbingParser, ENIPProbingParser))
a3ffebd8 555 {
238163bc 556 return;
a3ffebd8 557 }
558 }
559
ea4a509a 560 } else {
a3ffebd8 561 SCLogDebug("Protocol detection and parser disabled for %s protocol.",
562 proto_name);
563 return;
564 }
565
566 if (AppLayerParserConfParserEnabled("tcp", proto_name))
567 {
568 AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_ENIP,
569 STREAM_TOSERVER, ENIPParse);
570 AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_ENIP,
571 STREAM_TOCLIENT, ENIPParse);
572 AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_ENIP,
573 ENIPStateAlloc, ENIPStateFree);
574
575 AppLayerParserRegisterGetEventsFunc(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetEvents);
a3ffebd8 576
a3ffebd8 577 AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetTx);
7d663ed5 578 AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetTxData);
a3ffebd8 579 AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetTxCnt);
580 AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_ENIP, ENIPStateTransactionFree);
581
582 AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetAlstateProgress);
efc9a7a3 583 AppLayerParserRegisterStateProgressCompletionStatus(ALPROTO_ENIP, 1, 1);
a3ffebd8 584
585 AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_ENIP, ENIPStateGetEventInfo);
586
587 AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP,
588 ALPROTO_ENIP, STREAM_TOSERVER | STREAM_TOCLIENT);
700781c5
VJ
589
590 /* This parser accepts gaps. */
591 AppLayerParserRegisterOptionFlags(IPPROTO_TCP, ALPROTO_ENIP,
592 APP_LAYER_PARSER_OPT_ACCEPT_GAPS);
593
2b215a45
JI
594 AppLayerParserRegisterOptionFlags(
595 IPPROTO_TCP, ALPROTO_ENIP, APP_LAYER_PARSER_OPT_UNIDIR_TXS);
a3ffebd8 596 } else
597 {
238163bc 598 SCLogConfig("Parser disabled for %s protocol. Protocol detection still on.",
a3ffebd8 599 proto_name);
600 }
601
602#ifdef UNITTESTS
603 AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_ENIP, ENIPParserRegisterTests);
604#endif
605
606 SCReturn;
607}
608
609/* UNITTESTS */
610#ifdef UNITTESTS
611#include "app-layer-parser.h"
612#include "detect-parse.h"
613#include "detect-engine.h"
614#include "flow-util.h"
615#include "stream-tcp.h"
616#include "util-unittest.h"
617#include "util-unittest-helper.h"
618
619static uint8_t listIdentity[] = {/* List ID */ 0x63, 0x00,
620 /* Length */ 0x00, 0x00,
621 /* Session */ 0x00, 0x00, 0x00, 0x00,
622 /* Status */ 0x00, 0x00, 0x00, 0x00,
623 /* Delay*/ 0x00,
624 /* Context */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
625 /* Quantity of coils */ 0x00, 0x00, 0x00, 0x00, 0x00};
626
627/**
628 * \brief Test if ENIP Packet matches signature
629 */
ab1200fb 630static int ALDecodeENIPTest(void)
a3ffebd8 631{
632 AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
633 Flow f;
634 TcpSession ssn;
635
636 memset(&f, 0, sizeof(f));
637 memset(&ssn, 0, sizeof(ssn));
638
639 f.protoctx = (void *)&ssn;
640 f.proto = IPPROTO_TCP;
5c01b409 641 f.alproto = ALPROTO_ENIP;
a3ffebd8 642
1eeb9669 643 StreamTcpInitConfig(true);
a3ffebd8 644
645 int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_ENIP, STREAM_TOSERVER,
646 listIdentity, sizeof(listIdentity));
647 FAIL_IF(r != 0);
648
649 ENIPState *enip_state = f.alstate;
650 FAIL_IF_NULL(enip_state);
651
652 ENIPTransaction *tx = ENIPGetTx(enip_state, 0);
653 FAIL_IF_NULL(tx);
654
655 FAIL_IF(tx->header.command != 99);
656
657 AppLayerParserThreadCtxFree(alp_tctx);
1eeb9669 658 StreamTcpFreeConfig(true);
a3ffebd8 659 FLOW_DESTROY(&f);
660
661 PASS;
662}
663
664#endif /* UNITTESTS */
665
666void ENIPParserRegisterTests(void)
667{
668#ifdef UNITTESTS
669 UtRegisterTest("ALDecodeENIPTest", ALDecodeENIPTest);
670#endif /* UNITTESTS */
671}