Coverage Report

Created: 2026-01-16 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/suricata7/src/app-layer-enip.c
Line
Count
Source
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
57
SCEnumCharMap enip_decoder_event_table[ ] = {
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
1.30M
{
67
1.30M
    return 1;
68
1.30M
}
69
70
static AppLayerTxData *ENIPGetTxData(void *vtx)
71
682k
{
72
682k
    ENIPTransaction *tx = (ENIPTransaction *)vtx;
73
682k
    return &tx->tx_data;
74
682k
}
75
76
static AppLayerStateData *ENIPGetStateData(void *vstate)
77
356
{
78
356
    ENIPState *state = (ENIPState *)vstate;
79
356
    return &state->state_data;
80
356
}
81
82
static void *ENIPGetTx(void *alstate, uint64_t tx_id)
83
2.20k
{
84
2.20k
    ENIPState         *enip = (ENIPState *) alstate;
85
2.20k
    ENIPTransaction   *tx = NULL;
86
87
2.20k
    if (enip->curr && enip->curr->tx_num == tx_id + 1)
88
75
        return enip->curr;
89
90
3.38k
    TAILQ_FOREACH(tx, &enip->tx_list, next) {
91
3.38k
        if (tx->tx_num != (tx_id+1))
92
1.25k
            continue;
93
94
2.12k
        SCLogDebug("returning tx %p", tx);
95
2.12k
        return tx;
96
3.38k
    }
97
98
0
    return NULL;
99
2.12k
}
100
101
static uint64_t ENIPGetTxCnt(void *alstate)
102
1.64M
{
103
1.64M
    return ((ENIPState *)alstate)->transaction_max;
104
1.64M
}
105
106
static int ENIPStateGetEventInfo(const char *event_name, int *event_id, AppLayerEventType *event_type)
107
1
{
108
1
    *event_id = SCMapEnumNameToValue(event_name, enip_decoder_event_table);
109
110
1
    if (*event_id == -1) {
111
1
        SCLogError("event \"%s\" not present in "
112
1
                   "enip's enum map table.",
113
1
                event_name);
114
        /* yes this is fatal */
115
1
        return -1;
116
1
    }
117
118
0
    *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
119
120
0
    return 0;
121
1
}
122
123
static int ENIPStateGetEventInfoById(int event_id, const char **event_name,
124
                                     AppLayerEventType *event_type)
125
0
{
126
0
    *event_name = SCMapEnumValueToName(event_id, enip_decoder_event_table);
127
0
    if (*event_name == NULL) {
128
0
        SCLogError("event \"%d\" not present in "
129
0
                   "enip's enum map table.",
130
0
                event_id);
131
        /* yes this is fatal */
132
0
        return -1;
133
0
    }
134
135
0
    *event_type = APP_LAYER_EVENT_TYPE_TRANSACTION;
136
137
0
    return 0;
138
0
}
139
140
/** \brief Allocate enip state
141
 *
142
 *  return state
143
 */
144
static void *ENIPStateAlloc(void *orig_state, AppProto proto_orig)
145
2.51k
{
146
2.51k
    SCLogDebug("ENIPStateAlloc");
147
2.51k
    void *s = SCMalloc(sizeof(ENIPState));
148
2.51k
    if (unlikely(s == NULL))
149
0
        return NULL;
150
151
2.51k
    memset(s, 0, sizeof(ENIPState));
152
153
2.51k
    ENIPState *enip_state = (ENIPState *) s;
154
155
2.51k
    TAILQ_INIT(&enip_state->tx_list);
156
2.51k
    return s;
157
2.51k
}
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
891k
{
164
891k
    SCEnter();
165
891k
    SCLogDebug("ENIPTransactionFree");
166
891k
    CIPServiceEntry *svc = NULL;
167
981k
    while ((svc = TAILQ_FIRST(&tx->service_list)))
168
90.1k
    {
169
90.1k
        TAILQ_REMOVE(&tx->service_list, svc, next);
170
171
90.1k
        SegmentEntry *seg = NULL;
172
184k
        while ((seg = TAILQ_FIRST(&svc->segment_list)))
173
94.3k
        {
174
94.3k
            TAILQ_REMOVE(&svc->segment_list, seg, next);
175
94.3k
            SCFree(seg);
176
94.3k
        }
177
178
90.1k
        AttributeEntry *attr = NULL;
179
4.21M
        while ((attr = TAILQ_FIRST(&svc->attrib_list)))
180
4.12M
        {
181
4.12M
            TAILQ_REMOVE(&svc->attrib_list, attr, next);
182
4.12M
            SCFree(attr);
183
4.12M
        }
184
185
90.1k
        SCFree(svc);
186
90.1k
    }
187
188
891k
    AppLayerDecoderEventsFreeEvents(&tx->tx_data.events);
189
190
891k
    if (tx->tx_data.de_state != NULL) {
191
3.03k
        DetectEngineStateFree(tx->tx_data.de_state);
192
193
3.03k
        state->tx_with_detect_state_cnt--;
194
3.03k
    }
195
196
891k
    if (state->iter == tx)
197
0
        state->iter = NULL;
198
199
891k
    SCFree(tx);
200
891k
    SCReturn;
201
891k
}
202
203
/** \brief Free enip state
204
 *
205
 */
206
static void ENIPStateFree(void *s)
207
2.51k
{
208
2.51k
    SCEnter();
209
2.51k
    SCLogDebug("ENIPStateFree");
210
2.51k
    if (s)
211
2.51k
    {
212
2.51k
        ENIPState *enip_state = (ENIPState *) s;
213
214
2.51k
        ENIPTransaction *tx = NULL;
215
271k
        while ((tx = TAILQ_FIRST(&enip_state->tx_list)))
216
268k
        {
217
268k
            TAILQ_REMOVE(&enip_state->tx_list, tx, next);
218
268k
            ENIPTransactionFree(tx, enip_state);
219
268k
        }
220
221
2.51k
        if (enip_state->buffer != NULL)
222
0
        {
223
0
            SCFree(enip_state->buffer);
224
0
        }
225
226
2.51k
        SCFree(s);
227
2.51k
    }
228
2.51k
    SCReturn;
229
2.51k
}
230
231
/** \internal
232
 *  \brief Allocate a ENIP TX
233
 *  \retval tx or NULL */
234
static ENIPTransaction *ENIPTransactionAlloc(ENIPState *state)
235
891k
{
236
891k
    SCLogDebug("ENIPStateTransactionAlloc");
237
891k
    ENIPTransaction *tx = (ENIPTransaction *) SCCalloc(1,
238
891k
            sizeof(ENIPTransaction));
239
891k
    if (unlikely(tx == NULL))
240
0
        return NULL;
241
242
891k
    state->curr = tx;
243
891k
    state->transaction_max++;
244
245
891k
    memset(tx, 0x00, sizeof(ENIPTransaction));
246
891k
    TAILQ_INIT(&tx->service_list);
247
248
891k
    tx->enip  = state;
249
891k
    tx->tx_num  = state->transaction_max;
250
891k
    tx->service_count = 0;
251
252
891k
    TAILQ_INSERT_TAIL(&state->tx_list, tx, next);
253
254
891k
    return tx;
255
891k
}
256
257
/**
258
 *  \brief enip transaction cleanup callback
259
 */
260
static void ENIPStateTransactionFree(void *state, uint64_t tx_id)
261
623k
{
262
623k
    SCEnter();
263
623k
    SCLogDebug("ENIPStateTransactionFree");
264
623k
    ENIPState *enip_state = state;
265
623k
    ENIPTransaction *tx = NULL;
266
623k
    TAILQ_FOREACH(tx, &enip_state->tx_list, next)
267
623k
    {
268
269
623k
        if ((tx_id+1) < tx->tx_num)
270
0
        break;
271
623k
        else if ((tx_id+1) > tx->tx_num)
272
3
        continue;
273
274
623k
        if (tx == enip_state->curr)
275
530k
        enip_state->curr = NULL;
276
277
623k
        if (tx->tx_data.events != NULL) {
278
0
            if (tx->tx_data.events->cnt <= enip_state->events)
279
0
                enip_state->events -= tx->tx_data.events->cnt;
280
0
            else
281
0
                enip_state->events = 0;
282
0
        }
283
284
623k
        TAILQ_REMOVE(&enip_state->tx_list, tx, next);
285
623k
        ENIPTransactionFree(tx, state);
286
623k
        break;
287
623k
    }
288
623k
    SCReturn;
289
623k
}
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
542k
{
304
542k
    SCEnter();
305
542k
    ENIPState *enip = (ENIPState *) state;
306
542k
    ENIPTransaction *tx;
307
308
542k
    const uint8_t *input = StreamSliceGetData(&stream_slice);
309
542k
    uint32_t input_len = StreamSliceGetDataLen(&stream_slice);
310
311
542k
    if (input == NULL && AppLayerParserStateIssetFlag(pstate,
312
108
            APP_LAYER_PARSER_EOF_TS|APP_LAYER_PARSER_EOF_TC))
313
8
    {
314
8
        SCReturnStruct(APP_LAYER_OK);
315
542k
    } else if (input == NULL && input_len != 0) {
316
        // GAP
317
100
        SCReturnStruct(APP_LAYER_OK);
318
541k
    } else if (input == NULL || input_len == 0)
319
0
    {
320
0
        SCReturnStruct(APP_LAYER_ERROR);
321
0
    }
322
323
891k
    while (input_len > 0)
324
891k
    {
325
891k
        tx = ENIPTransactionAlloc(enip);
326
891k
        if (tx == NULL)
327
0
            SCReturnStruct(APP_LAYER_OK);
328
329
891k
        if (direction == STREAM_TOCLIENT)
330
290k
            tx->tx_data.detect_flags_ts |= APP_LAYER_TX_SKIP_INSPECT_FLAG;
331
601k
        else
332
601k
            tx->tx_data.detect_flags_tc |= APP_LAYER_TX_SKIP_INSPECT_FLAG;
333
334
891k
        SCLogDebug("ENIPParse input len %d", input_len);
335
891k
        DecodeENIPPDU(input, input_len, tx);
336
891k
        uint32_t pkt_len = tx->header.length + sizeof(ENIPEncapHdr);
337
891k
        SCLogDebug("ENIPParse packet len %d", pkt_len);
338
891k
        if (pkt_len > input_len)
339
534k
        {
340
534k
            SCLogDebug("Invalid packet length");
341
534k
            break;
342
534k
        }
343
344
356k
        input += pkt_len;
345
356k
        input_len -= pkt_len;
346
        //SCLogDebug("remaining %d", input_len);
347
348
356k
        if (input_len < sizeof(ENIPEncapHdr))
349
7.00k
        {
350
            //SCLogDebug("Not enough data"); //not enough data for ENIP
351
7.00k
            break;
352
7.00k
        }
353
356k
    }
354
355
541k
    SCReturnStruct(APP_LAYER_OK);
356
541k
}
357
358
static AppLayerResult ENIPParseRequest(Flow *f, void *state, AppLayerParserState *pstate,
359
        StreamSlice stream_slice, void *local_data)
360
270k
{
361
270k
    return ENIPParse(f, state, pstate, stream_slice, local_data, STREAM_TOSERVER);
362
270k
}
363
364
static AppLayerResult ENIPParseResponse(Flow *f, void *state, AppLayerParserState *pstate,
365
        StreamSlice stream_slice, void *local_data)
366
271k
{
367
271k
    return ENIPParse(f, state, pstate, stream_slice, local_data, STREAM_TOCLIENT);
368
271k
}
369
370
1.00k
#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
12.0k
{
375
    // SCLogDebug("ENIPProbingParser %d", input_len);
376
12.0k
    if (input_len < sizeof(ENIPEncapHdr))
377
4.75k
    {
378
4.75k
        SCLogDebug("length too small to be a ENIP header");
379
4.75k
        return ALPROTO_UNKNOWN;
380
4.75k
    }
381
7.24k
    uint16_t cmd;
382
7.24k
    uint16_t enip_len;
383
7.24k
    uint32_t status;
384
7.24k
    uint32_t option;
385
7.24k
    uint16_t nbitems;
386
387
7.24k
    int ret = ByteExtractUint32(
388
7.24k
            &status, BYTE_LITTLE_ENDIAN, sizeof(uint32_t), (const uint8_t *)(input + 8));
389
7.24k
    if (ret < 0) {
390
0
        return ALPROTO_FAILED;
391
0
    }
392
7.24k
    switch (status) {
393
3.62k
        case SUCCESS:
394
3.92k
        case INVALID_CMD:
395
4.29k
        case NO_RESOURCES:
396
4.68k
        case INCORRECT_DATA:
397
5.36k
        case INVALID_SESSION:
398
6.11k
        case INVALID_LENGTH:
399
6.32k
        case UNSUPPORTED_PROT_REV:
400
6.75k
        case ENCAP_HEADER_ERROR:
401
6.75k
            break;
402
495
        default:
403
495
            return ALPROTO_FAILED;
404
7.24k
    }
405
6.75k
    ret = ByteExtractUint16(&cmd, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), (const uint8_t *)(input));
406
6.75k
    if(ret < 0) {
407
0
        return ALPROTO_FAILED;
408
0
    }
409
6.75k
    ret = ByteExtractUint32(
410
6.75k
            &option, BYTE_LITTLE_ENDIAN, sizeof(uint32_t), (const uint8_t *)(input + 20));
411
6.75k
    if (ret < 0) {
412
0
        return ALPROTO_FAILED;
413
0
    }
414
6.75k
    ret = ByteExtractUint16(
415
6.75k
            &enip_len, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), (const uint8_t *)(input + 2));
416
6.75k
    if (ret < 0) {
417
0
        return ALPROTO_FAILED;
418
0
    }
419
420
    //ok for all the known commands
421
6.75k
    switch(cmd) {
422
1.41k
        case NOP:
423
1.41k
            if (option != 0) {
424
59
                return ALPROTO_FAILED;
425
59
            }
426
1.35k
            break;
427
1.35k
        case REGISTER_SESSION:
428
204
            if (enip_len != ENIP_LEN_REGISTER_SESSION) {
429
10
                return ALPROTO_FAILED;
430
10
            }
431
194
            break;
432
402
        case UNREGISTER_SESSION:
433
402
            if (enip_len != ENIP_LEN_REGISTER_SESSION && enip_len != 0) {
434
                // 0 for request and 4 for response
435
14
                return ALPROTO_FAILED;
436
14
            }
437
388
            break;
438
388
        case LIST_SERVICES:
439
509
        case LIST_IDENTITY:
440
785
        case SEND_RR_DATA:
441
1.18k
        case SEND_UNIT_DATA:
442
1.38k
        case INDICATE_STATUS:
443
1.57k
        case CANCEL:
444
1.57k
            break;
445
3.11k
        case LIST_INTERFACES:
446
3.11k
            if (input_len < sizeof(ENIPEncapHdr) + 2) {
447
59
                SCLogDebug("length too small to be a ENIP LIST_INTERFACES");
448
59
                return ALPROTO_UNKNOWN;
449
59
            }
450
3.05k
            ret = ByteExtractUint16(
451
3.05k
                    &nbitems, BYTE_LITTLE_ENDIAN, sizeof(uint16_t), (const uint8_t *)(input));
452
3.05k
            if(ret < 0) {
453
0
                return ALPROTO_FAILED;
454
0
            }
455
3.05k
            if (enip_len < sizeof(ENIPEncapHdr) + 2 * (size_t)nbitems) {
456
7
                return ALPROTO_FAILED;
457
7
            }
458
3.05k
            break;
459
3.05k
        default:
460
38
            return ALPROTO_FAILED;
461
6.75k
    }
462
6.56k
    return ALPROTO_ENIP;
463
6.75k
}
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
676k
{
468
676k
    ENIPState *enip_state = (ENIPState *)alstate;
469
676k
    AppLayerGetTxIterTuple no_tuple = { NULL, 0, false };
470
676k
    if (enip_state) {
471
676k
        ENIPTransaction *tx_ptr;
472
676k
        if (state->un.ptr == NULL) {
473
563k
            tx_ptr = TAILQ_FIRST(&enip_state->tx_list);
474
563k
        } else {
475
113k
            tx_ptr = (ENIPTransaction *)state->un.ptr;
476
113k
        }
477
676k
        if (tx_ptr) {
478
676k
            while (tx_ptr->tx_num < min_tx_id + 1) {
479
59
                tx_ptr = TAILQ_NEXT(tx_ptr, next);
480
59
                if (!tx_ptr) {
481
29
                    return no_tuple;
482
29
                }
483
59
            }
484
676k
            if (tx_ptr->tx_num >= max_tx_id + 1) {
485
0
                return no_tuple;
486
0
            }
487
676k
            state->un.ptr = TAILQ_NEXT(tx_ptr, next);
488
676k
            AppLayerGetTxIterTuple tuple = {
489
676k
                .tx_ptr = tx_ptr,
490
676k
                .tx_id = tx_ptr->tx_num - 1,
491
676k
                .has_next = (state->un.ptr != NULL),
492
676k
            };
493
676k
            return tuple;
494
676k
        }
495
676k
    }
496
840
    return no_tuple;
497
676k
}
498
499
/**
500
 * \brief Function to register the ENIP protocol parsers and other functions
501
 */
502
void RegisterENIPUDPParsers(void)
503
34
{
504
34
    SCEnter();
505
34
    const char *proto_name = "enip";
506
507
34
    if (AppLayerProtoDetectConfProtoDetectionEnabledDefault("udp", proto_name, false)) {
508
34
        AppLayerProtoDetectRegisterProtocol(ALPROTO_ENIP, proto_name);
509
510
34
        if (RunmodeIsUnittests())
511
0
        {
512
0
            AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818", ALPROTO_ENIP,
513
0
                    0, sizeof(ENIPEncapHdr), STREAM_TOSERVER, ENIPProbingParser, NULL);
514
515
0
            AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818", ALPROTO_ENIP,
516
0
                    0, sizeof(ENIPEncapHdr), STREAM_TOCLIENT, ENIPProbingParser, NULL);
517
518
0
        } else
519
34
        {
520
34
            if (!AppLayerProtoDetectPPParseConfPorts("udp", IPPROTO_UDP,
521
34
                    proto_name, ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr),
522
34
                    ENIPProbingParser, ENIPProbingParser))
523
1
            {
524
1
                SCLogDebug(
525
1
                        "no ENIP UDP config found enabling ENIP detection on port 44818.");
526
527
1
                AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818",
528
1
                        ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr), STREAM_TOSERVER,
529
1
                        ENIPProbingParser, NULL);
530
531
1
                AppLayerProtoDetectPPRegister(IPPROTO_UDP, "44818",
532
1
                        ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr), STREAM_TOCLIENT,
533
1
                        ENIPProbingParser, NULL);
534
1
            }
535
34
        }
536
537
34
    } else {
538
0
        SCLogConfig("Protocol detection and parser disabled for %s protocol.",
539
0
                proto_name);
540
0
        return;
541
0
    }
542
543
34
    if (AppLayerParserConfParserEnabled("udp", proto_name))
544
34
    {
545
34
        AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_ENIP, STREAM_TOSERVER, ENIPParseRequest);
546
34
        AppLayerParserRegisterParser(IPPROTO_UDP, ALPROTO_ENIP, STREAM_TOCLIENT, ENIPParseResponse);
547
548
34
        AppLayerParserRegisterStateFuncs(IPPROTO_UDP, ALPROTO_ENIP,
549
34
                ENIPStateAlloc, ENIPStateFree);
550
551
34
        AppLayerParserRegisterGetTx(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetTx);
552
34
        AppLayerParserRegisterGetTxIterator(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetTxIterator);
553
34
        AppLayerParserRegisterTxDataFunc(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetTxData);
554
34
        AppLayerParserRegisterStateDataFunc(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetStateData);
555
34
        AppLayerParserRegisterGetTxCnt(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetTxCnt);
556
34
        AppLayerParserRegisterTxFreeFunc(IPPROTO_UDP, ALPROTO_ENIP, ENIPStateTransactionFree);
557
558
34
        AppLayerParserRegisterGetStateProgressFunc(IPPROTO_UDP, ALPROTO_ENIP, ENIPGetAlstateProgress);
559
34
        AppLayerParserRegisterStateProgressCompletionStatus(ALPROTO_ENIP, 1, 1);
560
561
34
        AppLayerParserRegisterGetEventInfo(IPPROTO_UDP, ALPROTO_ENIP, ENIPStateGetEventInfo);
562
34
        AppLayerParserRegisterGetEventInfoById(IPPROTO_UDP, ALPROTO_ENIP, ENIPStateGetEventInfoById);
563
564
34
        AppLayerParserRegisterParserAcceptableDataDirection(
565
34
                IPPROTO_UDP, ALPROTO_ENIP, STREAM_TOSERVER | STREAM_TOCLIENT);
566
34
    } else
567
0
    {
568
0
        SCLogInfo(
569
0
                "Parsed disabled for %s protocol. Protocol detection" "still on.",
570
0
                proto_name);
571
0
    }
572
573
#ifdef UNITTESTS
574
    AppLayerParserRegisterProtocolUnittests(IPPROTO_UDP, ALPROTO_ENIP, ENIPParserRegisterTests);
575
#endif
576
577
34
    SCReturn;
578
34
}
579
580
/**
581
 * \brief Function to register the ENIP protocol parsers and other functions
582
 */
583
void RegisterENIPTCPParsers(void)
584
34
{
585
34
    SCEnter();
586
34
    const char *proto_name = "enip";
587
588
34
    if (AppLayerProtoDetectConfProtoDetectionEnabledDefault("tcp", proto_name, false)) {
589
34
        AppLayerProtoDetectRegisterProtocol(ALPROTO_ENIP, proto_name);
590
591
34
        if (RunmodeIsUnittests())
592
0
        {
593
0
            AppLayerProtoDetectPPRegister(IPPROTO_TCP, "44818", ALPROTO_ENIP,
594
0
                    0, sizeof(ENIPEncapHdr), STREAM_TOSERVER, ENIPProbingParser, NULL);
595
596
0
            AppLayerProtoDetectPPRegister(IPPROTO_TCP, "44818", ALPROTO_ENIP,
597
0
                    0, sizeof(ENIPEncapHdr), STREAM_TOCLIENT, ENIPProbingParser, NULL);
598
599
0
        } else
600
34
        {
601
34
            if (!AppLayerProtoDetectPPParseConfPorts("tcp", IPPROTO_TCP,
602
34
                    proto_name, ALPROTO_ENIP, 0, sizeof(ENIPEncapHdr),
603
34
                    ENIPProbingParser, ENIPProbingParser))
604
1
            {
605
1
                return;
606
1
            }
607
34
        }
608
609
34
    } else {
610
0
        SCLogDebug("Protocol detection and parser disabled for %s protocol.",
611
0
                proto_name);
612
0
        return;
613
0
    }
614
615
33
    if (AppLayerParserConfParserEnabled("tcp", proto_name))
616
33
    {
617
33
        AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_ENIP, STREAM_TOSERVER, ENIPParseRequest);
618
33
        AppLayerParserRegisterParser(IPPROTO_TCP, ALPROTO_ENIP, STREAM_TOCLIENT, ENIPParseResponse);
619
33
        AppLayerParserRegisterStateFuncs(IPPROTO_TCP, ALPROTO_ENIP,
620
33
                ENIPStateAlloc, ENIPStateFree);
621
622
33
        AppLayerParserRegisterGetTx(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetTx);
623
33
        AppLayerParserRegisterGetTxIterator(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetTxIterator);
624
33
        AppLayerParserRegisterTxDataFunc(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetTxData);
625
33
        AppLayerParserRegisterStateDataFunc(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetStateData);
626
33
        AppLayerParserRegisterGetTxCnt(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetTxCnt);
627
33
        AppLayerParserRegisterTxFreeFunc(IPPROTO_TCP, ALPROTO_ENIP, ENIPStateTransactionFree);
628
629
33
        AppLayerParserRegisterGetStateProgressFunc(IPPROTO_TCP, ALPROTO_ENIP, ENIPGetAlstateProgress);
630
33
        AppLayerParserRegisterStateProgressCompletionStatus(ALPROTO_ENIP, 1, 1);
631
632
33
        AppLayerParserRegisterGetEventInfo(IPPROTO_TCP, ALPROTO_ENIP, ENIPStateGetEventInfo);
633
634
33
        AppLayerParserRegisterParserAcceptableDataDirection(IPPROTO_TCP,
635
33
                ALPROTO_ENIP, STREAM_TOSERVER | STREAM_TOCLIENT);
636
637
        /* This parser accepts gaps. */
638
33
        AppLayerParserRegisterOptionFlags(IPPROTO_TCP, ALPROTO_ENIP,
639
33
                APP_LAYER_PARSER_OPT_ACCEPT_GAPS);
640
641
33
        AppLayerParserRegisterOptionFlags(IPPROTO_TCP, ALPROTO_ENIP, 0);
642
33
    } else
643
0
    {
644
0
        SCLogConfig("Parser disabled for %s protocol. Protocol detection still on.",
645
0
                proto_name);
646
0
    }
647
648
#ifdef UNITTESTS
649
    AppLayerParserRegisterProtocolUnittests(IPPROTO_TCP, ALPROTO_ENIP, ENIPParserRegisterTests);
650
#endif
651
652
33
    SCReturn;
653
34
}
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
{
673
    AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
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
698
    AppLayerParserThreadCtxFree(alp_tctx);
699
    StreamTcpFreeConfig(true);
700
    FLOW_DESTROY(&f);
701
702
    PASS;
703
}
704
705
#endif /* UNITTESTS */
706
707
void ENIPParserRegisterTests(void)
708
0
{
709
#ifdef UNITTESTS
710
      UtRegisterTest("ALDecodeENIPTest", ALDecodeENIPTest);
711
#endif /* UNITTESTS */
712
0
}