suricata
app-layer-modbus.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2014 ANSSI
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
17 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
18 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
19 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28/**
29 * \file
30 *
31 * \author David DIALLO <diallo@et.esiea.fr>
32 *
33 * App-layer parser for Modbus protocol
34 *
35 */
36
37#include "suricata-common.h"
38
39#include "util-debug.h"
40
41#include "app-layer-parser.h"
42#include "app-layer-modbus.h"
43#include "rust.h"
44
46
47/**
48 * \brief Function to register the Modbus protocol parser
49 */
51{
52 SCRegisterModbusParser();
53#ifdef UNITTESTS
55#endif
56
58}
59
60/* UNITTESTS */
61#ifdef UNITTESTS
62#include "detect.h"
63#include "detect-engine.h"
64#include "detect-parse.h"
65#include "detect-engine-build.h"
66#include "detect-engine-alert.h"
67
68#include "flow-util.h"
69
70#include "util-unittest.h"
72
73#include "stream-tcp.h"
74#include "stream-tcp-private.h"
75
76#include "rust.h"
77
78/* Modbus default stream reassembly depth */
79#define MODBUS_CONFIG_DEFAULT_STREAM_DEPTH 0
80
81/* Modbus Application Protocol Specification V1.1b3 6.1: Read Coils */
82static uint8_t invalidFunctionCode[] = {
83 /* Transaction ID */ 0x00, 0x00,
84 /* Protocol ID */ 0x00, 0x00,
85 /* Length */ 0x00, 0x02,
86 /* Unit ID */ 0x00,
87 /* Function code */ 0x00
88};
89
90/* Modbus Application Protocol Specification V1.1b3 6.1: Read Coils */
91/* Example of a request to read discrete outputs 20-38 */
92static uint8_t readCoilsReq[] = {/* Transaction ID */ 0x00, 0x00,
93 /* Protocol ID */ 0x00, 0x00,
94 /* Length */ 0x00, 0x06,
95 /* Unit ID */ 0x00,
96 /* Function code */ 0x01,
97 /* Starting Address */ 0x78, 0x90,
98 /* Quantity of coils */ 0x00, 0x13 };
99
100static uint8_t readCoilsRsp[] = {/* Transaction ID */ 0x00, 0x00,
101 /* Protocol ID */ 0x00, 0x00,
102 /* Length */ 0x00, 0x06,
103 /* Unit ID */ 0x00,
104 /* Function code */ 0x01,
105 /* Byte count */ 0x03,
106 /* Coil Status */ 0xCD, 0x6B, 0x05 };
107
108static uint8_t readCoilsErrorRsp[] = {
109 /* Transaction ID */ 0x00, 0x00,
110 /* Protocol ID */ 0x00, 0x00,
111 /* Length */ 0x00, 0x03,
112 /* Unit ID */ 0x00,
113 /* Function code */ 0x81,
114 /* Invalid Exception code: should trigger the InvalidExceptionCode ModbusEvent */
115 0xFF
116};
117
118/* Modbus Application Protocol Specification V1.1b3 6.6: Write Single register */
119/* Example of a request to write register 2 to 00 03 hex */
120static uint8_t writeSingleRegisterReq[] = {/* Transaction ID */ 0x00, 0x0A,
121 /* Protocol ID */ 0x00, 0x00,
122 /* Length */ 0x00, 0x06,
123 /* Unit ID */ 0x00,
124 /* Function code */ 0x06,
125 /* Register Address */ 0x00, 0x01,
126 /* Register Value */ 0x00, 0x03};
127
128static uint8_t invalidWriteSingleRegisterReq[] = {/* Transaction ID */ 0x00, 0x0A,
129 /* Protocol ID */ 0x00, 0x00,
130 /* Length */ 0x00, 0x04,
131 /* Unit ID */ 0x00,
132 /* Function code */ 0x06,
133 /* Register Address */ 0x00, 0x01};
134
135static uint8_t writeSingleRegisterRsp[] = {/* Transaction ID */ 0x00, 0x0A,
136 /* Protocol ID */ 0x00, 0x00,
137 /* Length */ 0x00, 0x06,
138 /* Unit ID */ 0x00,
139 /* Function code */ 0x06,
140 /* Register Address */ 0x00, 0x01,
141 /* Register Value */ 0x00, 0x03};
142
143/* Modbus Application Protocol Specification V1.1b3 6.12: Write Multiple registers */
144/* Example of a request to write two registers starting at 2 to 00 0A and 01 02 hex */
145static uint8_t writeMultipleRegistersReq[] = {/* Transaction ID */ 0x00, 0x0A,
146 /* Protocol ID */ 0x00, 0x00,
147 /* Length */ 0x00, 0x0B,
148 /* Unit ID */ 0x00,
149 /* Function code */ 0x10,
150 /* Starting Address */ 0x00, 0x01,
151 /* Quantity of Registers */ 0x00, 0x02,
152 /* Byte count */ 0x04,
153 /* Registers Value */ 0x00, 0x0A,
154 0x01, 0x02};
155
156static uint8_t writeMultipleRegistersRsp[] = {/* Transaction ID */ 0x00, 0x0A,
157 /* Protocol ID */ 0x00, 0x00,
158 /* Length */ 0x00, 0x06,
159 /* Unit ID */ 0x00,
160 /* Function code */ 0x10,
161 /* Starting Address */ 0x00, 0x01,
162 /* Quantity of Registers */ 0x00, 0x02};
163
164/* Modbus Application Protocol Specification V1.1b3 6.16: Mask Write Register */
165/* Example of a request to mask write to register 5 */
166static uint8_t maskWriteRegisterReq[] = {/* Transaction ID */ 0x00, 0x0A,
167 /* Protocol ID */ 0x00, 0x00,
168 /* Length */ 0x00, 0x08,
169 /* Unit ID */ 0x00,
170 /* Function code */ 0x16,
171 /* Reference Address */ 0x00, 0x04,
172 /* And_Mask */ 0x00, 0xF2,
173 /* Or_Mask */ 0x00, 0x25};
174
175static uint8_t invalidMaskWriteRegisterReq[] = {/* Transaction ID */ 0x00, 0x0A,
176 /* Protocol ID */ 0x00, 0x00,
177 /* Length */ 0x00, 0x06,
178 /* Unit ID */ 0x00,
179 /* Function code */ 0x16,
180 /* Reference Address */ 0x00, 0x04,
181 /* And_Mask */ 0x00, 0xF2};
182
183static uint8_t maskWriteRegisterRsp[] = {/* Transaction ID */ 0x00, 0x0A,
184 /* Protocol ID */ 0x00, 0x00,
185 /* Length */ 0x00, 0x08,
186 /* Unit ID */ 0x00,
187 /* Function code */ 0x16,
188 /* Reference Address */ 0x00, 0x04,
189 /* And_Mask */ 0x00, 0xF2,
190 /* Or_Mask */ 0x00, 0x25};
191
192/* Modbus Application Protocol Specification V1.1b3 6.17: Read/Write Multiple registers */
193/* Example of a request to read six registers starting at register 4, */
194/* and to write three registers starting at register 15 */
195static uint8_t readWriteMultipleRegistersReq[] = {/* Transaction ID */ 0x12, 0x34,
196 /* Protocol ID */ 0x00, 0x00,
197 /* Length */ 0x00, 0x11,
198 /* Unit ID */ 0x00,
199 /* Function code */ 0x17,
200 /* Read Starting Address */ 0x00, 0x03,
201 /* Quantity to Read */ 0x00, 0x06,
202 /* Write Starting Address */ 0x00, 0x0E,
203 /* Quantity to Write */ 0x00, 0x03,
204 /* Write Byte count */ 0x06,
205 /* Write Registers Value */ 0x12, 0x34,
206 0x56, 0x78,
207 0x9A, 0xBC};
208
209/* Mismatch value in Byte count 0x0B instead of 0x0C */
210static uint8_t readWriteMultipleRegistersRsp[] = {/* Transaction ID */ 0x12, 0x34,
211 /* Protocol ID */ 0x00, 0x00,
212 /* Length */ 0x00, 0x0E,
213 /* Unit ID */ 0x00,
214 /* Function code */ 0x17,
215 /* Byte count */ 0x0B,
216 /* Read Registers Value */ 0x00, 0xFE,
217 0x0A, 0xCD,
218 0x00, 0x01,
219 0x00, 0x03,
220 0x00, 0x0D,
221 0x00};
222
223/* Modbus Application Protocol Specification V1.1b3 6.8.1: 04 Force Listen Only Mode */
224/* Example of a request to to remote device to its Listen Only Mode for Modbus Communications. */
225static uint8_t forceListenOnlyMode[] = {/* Transaction ID */ 0x0A, 0x00,
226 /* Protocol ID */ 0x00, 0x00,
227 /* Length */ 0x00, 0x06,
228 /* Unit ID */ 0x00,
229 /* Function code */ 0x08,
230 /* Sub-function code */ 0x00, 0x04,
231 /* Data */ 0x00, 0x00};
232
233static uint8_t invalidProtocolIdReq[] = {/* Transaction ID */ 0x00, 0x00,
234 /* Protocol ID */ 0x00, 0x01,
235 /* Length */ 0x00, 0x06,
236 /* Unit ID */ 0x00,
237 /* Function code */ 0x01,
238 /* Starting Address */ 0x78, 0x90,
239 /* Quantity of coils */ 0x00, 0x13 };
240
241static uint8_t invalidLengthWriteMultipleRegistersReq[] = {
242 /* Transaction ID */ 0x00, 0x0A,
243 /* Protocol ID */ 0x00, 0x00,
244 /* Length */ 0x00, 0x09,
245 /* Unit ID */ 0x00,
246 /* Function code */ 0x10,
247 /* Starting Address */ 0x00, 0x01,
248 /* Quantity of Registers */ 0x00, 0x02,
249 /* Byte count */ 0x04,
250 /* Registers Value */ 0x00, 0x0A,
251 0x01, 0x02};
252
253static uint8_t exceededLengthWriteMultipleRegistersReq[] = {
254 /* Transaction ID */ 0x00, 0x0A,
255 /* Protocol ID */ 0x00, 0x00,
256 /* Length */ 0xff, 0xfa,
257 /* Unit ID */ 0x00,
258 /* Function code */ 0x10,
259 /* Starting Address */ 0x00, 0x01,
260 /* Quantity of Registers */ 0x7f, 0xf9,
261 /* Byte count */ 0xff};
262
263static uint8_t invalidLengthPDUWriteMultipleRegistersReq[] = {
264 /* Transaction ID */ 0x00, 0x0A,
265 /* Protocol ID */ 0x00, 0x00,
266 /* Length */ 0x00, 0x02,
267 /* Unit ID */ 0x00,
268 /* Function code */ 0x10};
269
270/** \test Send Modbus Read Coils request/response. */
271static int ModbusParserTest01(void) {
273 Flow f;
274 TcpSession ssn;
275
277
278 memset(&f, 0, sizeof(f));
279 memset(&ssn, 0, sizeof(ssn));
280
281 FLOW_INITIALIZE(&f);
282 f.protoctx = (void *)&ssn;
283 f.proto = IPPROTO_TCP;
285
287
289 STREAM_TOSERVER, readCoilsReq,
290 sizeof(readCoilsReq));
291 FAIL_IF_NOT(r == 0);
292
293 ModbusState *modbus_state = f.alstate;
294 FAIL_IF_NULL(modbus_state);
295
296 ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
297 FAIL_IF_NULL(request._0);
298 FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 1);
299 FAIL_IF_NOT(SCModbusMessageGetReadRequestAddress(&request) == 0x7890);
300 FAIL_IF_NOT(SCModbusMessageGetReadRequestQuantity(&request) == 19);
301
303 STREAM_TOCLIENT, readCoilsRsp,
304 sizeof(readCoilsRsp));
305 FAIL_IF_NOT(r == 0);
306
307 FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
308
311 FLOW_DESTROY(&f);
312 PASS;
313}
314
315/** \test Send Modbus Write Multiple registers request/response. */
316static int ModbusParserTest02(void) {
318 Flow f;
319 TcpSession ssn;
320
322
323 memset(&f, 0, sizeof(f));
324 memset(&ssn, 0, sizeof(ssn));
325
326 FLOW_INITIALIZE(&f);
327 f.protoctx = (void *)&ssn;
328 f.proto = IPPROTO_TCP;
330
332
334 STREAM_TOSERVER, writeMultipleRegistersReq,
335 sizeof(writeMultipleRegistersReq));
336 FAIL_IF_NOT(r == 0);
337
338 ModbusState *modbus_state = f.alstate;
339 FAIL_IF_NULL(modbus_state);
340
341 ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
342 FAIL_IF_NULL(request._0);
343 FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 16);
344 FAIL_IF_NOT(SCModbusMessageGetWriteMultreqAddress(&request) == 0x01);
345 FAIL_IF_NOT(SCModbusMessageGetWriteMultreqQuantity(&request) == 2);
346
347 size_t data_len;
348 const uint8_t *data = SCModbusMessageGetWriteMultreqData(&request, &data_len);
349 FAIL_IF_NOT(data_len == 4);
350 FAIL_IF_NOT(data[0] == 0x00);
351 FAIL_IF_NOT(data[1] == 0x0A);
352 FAIL_IF_NOT(data[2] == 0x01);
353 FAIL_IF_NOT(data[3] == 0x02);
354
356 STREAM_TOCLIENT, writeMultipleRegistersRsp,
357 sizeof(writeMultipleRegistersRsp));
358 FAIL_IF_NOT(r == 0);
359
360 FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
361
364 FLOW_DESTROY(&f);
365 PASS;
366}
367
368/** \test Send Modbus Read/Write Multiple registers request/response with mismatch value. */
369static int ModbusParserTest03(void) {
371 DetectEngineThreadCtx *det_ctx = NULL;
372 Flow f;
373 Packet *p = NULL;
374 Signature *s = NULL;
375 TcpSession ssn;
377
379
380 memset(&tv, 0, sizeof(ThreadVars));
381 memset(&f, 0, sizeof(Flow));
382 memset(&ssn, 0, sizeof(TcpSession));
383
384 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
385
386 FLOW_INITIALIZE(&f);
388 f.protoctx = (void *)&ssn;
389 f.proto = IPPROTO_TCP;
391 f.flags |= FLOW_IPV4;
392
393 p->flow = &f;
396
398
401
403 s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
404 "(msg:\"Modbus Data mismatch\"; "
405 "app-layer-event: "
406 "modbus.value_mismatch; "
407 "sid:1;)");
408 FAIL_IF_NULL(s);
409
411 DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
412
414 STREAM_TOSERVER,
415 readWriteMultipleRegistersReq,
416 sizeof(readWriteMultipleRegistersReq));
417 FAIL_IF_NOT(r == 0);
418
419 ModbusState *modbus_state = f.alstate;
420 FAIL_IF_NULL(modbus_state);
421
422 ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
423 FAIL_IF_NULL(request._0);
424
425 FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 23);
426 FAIL_IF_NOT(SCModbusMessageGetRwMultreqReadAddress(&request) == 0x03);
427 FAIL_IF_NOT(SCModbusMessageGetRwMultreqReadQuantity(&request) == 6);
428 FAIL_IF_NOT(SCModbusMessageGetRwMultreqWriteAddress(&request) == 0x0E);
429 FAIL_IF_NOT(SCModbusMessageGetRwMultreqWriteQuantity(&request) == 3);
430
431 size_t data_len;
432 uint8_t const *data = SCModbusMessageGetRwMultreqWriteData(&request, &data_len);
433 FAIL_IF_NOT(data_len == 6);
434 FAIL_IF_NOT(data[0] == 0x12);
435 FAIL_IF_NOT(data[1] == 0x34);
436 FAIL_IF_NOT(data[2] == 0x56);
437 FAIL_IF_NOT(data[3] == 0x78);
438 FAIL_IF_NOT(data[4] == 0x9A);
439 FAIL_IF_NOT(data[5] == 0xBC);
440
442 STREAM_TOCLIENT, readWriteMultipleRegistersRsp,
443 sizeof(readWriteMultipleRegistersRsp));
444 FAIL_IF_NOT(r == 0);
445
446 FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
447
448 /* do detect */
449 SigMatchSignatures(&tv, de_ctx, det_ctx, p);
450
452
455
456 DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
458
461 FLOW_DESTROY(&f);
462 UTHFreePackets(&p, 1);
463 PASS;
464}
465
466/** \test Send Modbus Force Listen Only Mode request. */
467static int ModbusParserTest04(void) {
469 Flow f;
470 TcpSession ssn;
471
473
474 memset(&f, 0, sizeof(f));
475 memset(&ssn, 0, sizeof(ssn));
476
477 FLOW_INITIALIZE(&f);
478 f.protoctx = (void *)&ssn;
479 f.proto = IPPROTO_TCP;
481
483
485 STREAM_TOSERVER, forceListenOnlyMode,
486 sizeof(forceListenOnlyMode));
487 FAIL_IF_NOT(r == 0);
488
489 ModbusState *modbus_state = f.alstate;
490 FAIL_IF_NULL(modbus_state);
491
492 ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
493 FAIL_IF_NULL(request._0);
494
495 FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 8);
496 FAIL_IF_NOT(SCModbusMessageGetSubfunction(&request) == 4);
497
500 FLOW_DESTROY(&f);
501 PASS;
502}
503
504/** \test Send Modbus invalid Protocol version in request. */
505static int ModbusParserTest05(void) {
507 DetectEngineThreadCtx *det_ctx = NULL;
508 Flow f;
509 Packet *p = NULL;
510 Signature *s = NULL;
511 TcpSession ssn;
513
515
516 memset(&tv, 0, sizeof(ThreadVars));
517 memset(&f, 0, sizeof(Flow));
518 memset(&ssn, 0, sizeof(TcpSession));
519
520 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
521
522 FLOW_INITIALIZE(&f);
524 f.protoctx = (void *)&ssn;
525 f.proto = IPPROTO_TCP;
527 f.flags |= FLOW_IPV4;
528
529 p->flow = &f;
532
534
537
539 s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
540 "(msg:\"Modbus invalid Protocol version\"; "
541 "app-layer-event: "
542 "modbus.invalid_protocol_id; "
543 "sid:1;)");
544 FAIL_IF_NULL(s);
545
547 DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
548
550 STREAM_TOSERVER, invalidProtocolIdReq,
551 sizeof(invalidProtocolIdReq));
552 FAIL_IF_NOT(r == 0);
553
554 ModbusState *modbus_state = f.alstate;
555 FAIL_IF_NULL(modbus_state);
556
557 /* do detect */
558 SigMatchSignatures(&tv, de_ctx, det_ctx, p);
559
561
564
565 DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
567
570 FLOW_DESTROY(&f);
571 UTHFreePackets(&p, 1);
572 PASS;
573}
574
575/** \test Send Modbus unsolicited response. */
576static int ModbusParserTest06(void) {
578 DetectEngineThreadCtx *det_ctx = NULL;
579 Flow f;
580 Packet *p = NULL;
581 Signature *s = NULL;
582 TcpSession ssn;
584
586
587 memset(&tv, 0, sizeof(ThreadVars));
588 memset(&f, 0, sizeof(Flow));
589 memset(&ssn, 0, sizeof(TcpSession));
590
591 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
592
593 FLOW_INITIALIZE(&f);
595 f.protoctx = (void *)&ssn;
596 f.proto = IPPROTO_TCP;
598 f.flags |= FLOW_IPV4;
599
600 p->flow = &f;
603
605
608
610 s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
611 "(msg:\"Modbus unsolicited response\"; "
612 "app-layer-event: "
613 "modbus.unsolicited_response; "
614 "sid:1;)");
615 FAIL_IF_NULL(s);
616
618 DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
619
621 STREAM_TOCLIENT, readCoilsRsp,
622 sizeof(readCoilsRsp));
623 FAIL_IF_NOT(r == 0);
624
625 ModbusState *modbus_state = f.alstate;
626 FAIL_IF_NULL(modbus_state);
627
628 /* do detect */
629 SigMatchSignatures(&tv, de_ctx, det_ctx, p);
630
632
635
636 DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
638
641 FLOW_DESTROY(&f);
642 UTHFreePackets(&p, 1);
643 PASS;
644}
645
646/** \test Send Modbus invalid Length request. */
647static int ModbusParserTest07(void) {
649 DetectEngineThreadCtx *det_ctx = NULL;
650 Flow f;
651 Packet *p = NULL;
652 Signature *s = NULL;
653 TcpSession ssn;
655
657
658 memset(&tv, 0, sizeof(ThreadVars));
659 memset(&f, 0, sizeof(Flow));
660 memset(&ssn, 0, sizeof(TcpSession));
661
662 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
663
664 FLOW_INITIALIZE(&f);
666 f.protoctx = (void *)&ssn;
667 f.proto = IPPROTO_TCP;
669 f.flags |= FLOW_IPV4;
670
671 p->flow = &f;
674
676
679
681 s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
682 "(msg:\"Modbus invalid Length\"; "
683 "app-layer-event: "
684 "modbus.invalid_length; "
685 "sid:1;)");
686 FAIL_IF_NULL(s);
687
689 DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
690
692 STREAM_TOSERVER,
693 invalidLengthWriteMultipleRegistersReq,
694 sizeof(invalidLengthWriteMultipleRegistersReq));
695 FAIL_IF_NOT(r == 1);
696
697 ModbusState *modbus_state = f.alstate;
698 FAIL_IF_NULL(modbus_state);
699
700 /* do detect */
701 SigMatchSignatures(&tv, de_ctx, det_ctx, p);
702
704
707
708 DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
710
713 FLOW_DESTROY(&f);
714 UTHFreePackets(&p, 1);
715 PASS;
716}
717
718/** \test Send Modbus Read Coils request and error response with Exception code invalid. */
719static int ModbusParserTest08(void) {
721 DetectEngineThreadCtx *det_ctx = NULL;
722 Flow f;
723 Packet *p = NULL;
724 Signature *s = NULL;
725 TcpSession ssn;
727
729
730 memset(&tv, 0, sizeof(ThreadVars));
731 memset(&f, 0, sizeof(Flow));
732 memset(&ssn, 0, sizeof(TcpSession));
733
734 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
735
736 FLOW_INITIALIZE(&f);
738 f.protoctx = (void *)&ssn;
739 f.proto = IPPROTO_TCP;
741 f.flags |= FLOW_IPV4;
742
743 p->flow = &f;
746
748
751
753 s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
754 "(msg:\"Modbus Exception code invalid\"; "
755 "app-layer-event: "
756 "modbus.invalid_exception_code; "
757 "sid:1;)");
758 FAIL_IF_NULL(s);
759
761 DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
762
764 STREAM_TOSERVER, readCoilsReq,
765 sizeof(readCoilsReq));
766 FAIL_IF_NOT(r == 0);
767
768 ModbusState *modbus_state = f.alstate;
769 FAIL_IF_NULL(modbus_state);
770
771 ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
772 FAIL_IF_NULL(request._0);
773
774 FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 1);
775 FAIL_IF_NOT(SCModbusMessageGetReadRequestAddress(&request) == 0x7890);
776 FAIL_IF_NOT(SCModbusMessageGetReadRequestQuantity(&request) == 19);
777
779 STREAM_TOCLIENT, readCoilsErrorRsp,
780 sizeof(readCoilsErrorRsp));
781 FAIL_IF_NOT(r == 0);
782
783 FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
784
785 /* do detect */
786 SigMatchSignatures(&tv, de_ctx, det_ctx, p);
787
789
792
793 DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
795
798 FLOW_DESTROY(&f);
799 UTHFreePackets(&p, 1);
800 PASS;
801}
802
803/** \test Modbus fragmentation - 1 ADU over 2 TCP packets. */
804static int ModbusParserTest09(void) {
806 Flow f;
807 TcpSession ssn;
808
809 uint32_t input_len = sizeof(readCoilsReq), part2_len = 3;
810 uint8_t *input = readCoilsReq;
811
813
814 memset(&f, 0, sizeof(f));
815 memset(&ssn, 0, sizeof(ssn));
816
817 FLOW_INITIALIZE(&f);
818 f.protoctx = (void *)&ssn;
819 f.proto = IPPROTO_TCP;
821
823
825 STREAM_TOSERVER, input, input_len - part2_len);
826 FAIL_IF_NOT(r == 1);
827
829 STREAM_TOSERVER, input, input_len);
830 FAIL_IF_NOT(r == 0);
831
832 ModbusState *modbus_state = f.alstate;
833 FAIL_IF_NULL(modbus_state);
834
835 ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
836 FAIL_IF_NULL(request._0);
837
838 FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 1);
839 FAIL_IF_NOT(SCModbusMessageGetReadRequestAddress(&request) == 0x7890);
840 FAIL_IF_NOT(SCModbusMessageGetReadRequestQuantity(&request) == 19);
841
842 input_len = sizeof(readCoilsRsp);
843 part2_len = 10;
844 input = readCoilsRsp;
845
847 STREAM_TOCLIENT, input, input_len - part2_len);
848 FAIL_IF_NOT(r == 1);
849
851 STREAM_TOCLIENT, input, input_len);
852 FAIL_IF_NOT(r == 0);
853
854 FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
855
858 FLOW_DESTROY(&f);
859 PASS;
860}
861
862/** \test Modbus fragmentation - 2 ADU in 1 TCP packet. */
863static int ModbusParserTest10(void) {
864 uint32_t input_len = sizeof(readCoilsReq) + sizeof(writeMultipleRegistersReq);
865 uint8_t *input, *ptr;
866
868 Flow f;
869 TcpSession ssn;
870
872
873 input = (uint8_t *) SCMalloc (input_len * sizeof(uint8_t));
874 FAIL_IF_NULL(input);
875
876 memcpy(input, readCoilsReq, sizeof(readCoilsReq));
877 memcpy(input + sizeof(readCoilsReq), writeMultipleRegistersReq, sizeof(writeMultipleRegistersReq));
878
879 memset(&f, 0, sizeof(f));
880 memset(&ssn, 0, sizeof(ssn));
881
882 FLOW_INITIALIZE(&f);
883 f.protoctx = (void *)&ssn;
884 f.proto = IPPROTO_TCP;
886
888
890 STREAM_TOSERVER, input, input_len);
891 FAIL_IF_NOT(r == 0);
892
893 ModbusState *modbus_state = f.alstate;
894 FAIL_IF_NULL(modbus_state);
895
896 FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 2);
897
898 ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 1);
899 FAIL_IF_NULL(request._0);
900
901 FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 16);
902 FAIL_IF_NOT(SCModbusMessageGetWriteMultreqAddress(&request) == 0x01);
903 FAIL_IF_NOT(SCModbusMessageGetWriteMultreqQuantity(&request) == 2);
904
905 size_t data_len;
906 uint8_t const *data = SCModbusMessageGetWriteMultreqData(&request, &data_len);
907 FAIL_IF_NOT(data_len == 4);
908 FAIL_IF_NOT(data[0] == 0x00);
909 FAIL_IF_NOT(data[1] == 0x0A);
910 FAIL_IF_NOT(data[2] == 0x01);
911 FAIL_IF_NOT(data[3] == 0x02);
912
913 input_len = sizeof(readCoilsRsp) + sizeof(writeMultipleRegistersRsp);
914
915 ptr = (uint8_t *) SCRealloc (input, input_len * sizeof(uint8_t));
916 FAIL_IF_NULL(ptr);
917 input = ptr;
918
919 memcpy(input, readCoilsRsp, sizeof(readCoilsRsp));
920 memcpy(input + sizeof(readCoilsRsp), writeMultipleRegistersRsp, sizeof(writeMultipleRegistersRsp));
921
922 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, input, input_len);
923 FAIL_IF_NOT(r == 0);
924
925 SCFree(input);
928 FLOW_DESTROY(&f);
929 PASS;
930}
931
932/** \test Send Modbus exceed Length request. */
933static int ModbusParserTest11(void) {
935 DetectEngineThreadCtx *det_ctx = NULL;
936 Flow f;
937 Packet *p = NULL;
938 Signature *s = NULL;
939 TcpSession ssn;
941
942 size_t input_len = 65536;
943 uint8_t *input = SCCalloc(1, input_len);
944
945 FAIL_IF(input == NULL);
946
947 memcpy(input, exceededLengthWriteMultipleRegistersReq,
948 sizeof(exceededLengthWriteMultipleRegistersReq));
949
950 FAIL_IF(alp_tctx == NULL);
951
952 memset(&tv, 0, sizeof(ThreadVars));
953 memset(&f, 0, sizeof(Flow));
954 memset(&ssn, 0, sizeof(TcpSession));
955
956 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
957
958 FLOW_INITIALIZE(&f);
960 f.protoctx = (void *)&ssn;
961 f.proto = IPPROTO_TCP;
963 f.flags |= FLOW_IPV4;
964
965 p->flow = &f;
968
970
973
975 s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
976 "(msg:\"Modbus invalid Length\"; "
977 "app-layer-event: "
978 "modbus.invalid_length; "
979 "sid:1;)");
980 FAIL_IF_NULL(s);
981
983 DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
984
985 int r = AppLayerParserParse(
986 NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, input, input_len);
987 FAIL_IF_NOT(r == 0);
988
989 ModbusState *modbus_state = f.alstate;
990 FAIL_IF_NULL(modbus_state);
991
992 /* do detect */
993 SigMatchSignatures(&tv, de_ctx, det_ctx, p);
994
996
999
1000 DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
1002
1004 StreamTcpFreeConfig(true);
1005 FLOW_DESTROY(&f);
1006 UTHFreePackets(&p, 1);
1007 PASS;
1008}
1009
1010/** \test Send Modbus invalid PDU Length. */
1011static int ModbusParserTest12(void) {
1013 DetectEngineThreadCtx *det_ctx = NULL;
1014 Flow f;
1015 Packet *p = NULL;
1016 Signature *s = NULL;
1017 TcpSession ssn;
1018 ThreadVars tv;
1019
1021
1022 memset(&tv, 0, sizeof(ThreadVars));
1023 memset(&f, 0, sizeof(Flow));
1024 memset(&ssn, 0, sizeof(TcpSession));
1025
1026 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1027
1028 FLOW_INITIALIZE(&f);
1030 f.protoctx = (void *)&ssn;
1031 f.proto = IPPROTO_TCP;
1033 f.flags |= FLOW_IPV4;
1034
1035 p->flow = &f;
1038
1039 StreamTcpInitConfig(true);
1040
1043
1044 de_ctx->flags |= DE_QUIET;
1045 s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1046 "(msg:\"Modbus invalid Length\"; "
1047 "app-layer-event: "
1048 "modbus.invalid_length; "
1049 "sid:1;)");
1050 FAIL_IF_NULL(s);
1051
1053 DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
1054
1055 int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1056 STREAM_TOSERVER,
1057 invalidLengthPDUWriteMultipleRegistersReq,
1058 sizeof(invalidLengthPDUWriteMultipleRegistersReq));
1059 FAIL_IF_NOT(r == 0);
1060
1061 ModbusState *modbus_state = f.alstate;
1062 FAIL_IF_NULL(modbus_state);
1063
1064 /* do detect */
1065 SigMatchSignatures(&tv, de_ctx, det_ctx, p);
1066
1068
1071
1072 DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
1074
1076 StreamTcpFreeConfig(true);
1077 FLOW_DESTROY(&f);
1078 UTHFreePackets(&p, 1);
1079 PASS;
1080}
1081
1082/** \test Send Modbus Mask Write register request/response. */
1083static int ModbusParserTest13(void) {
1085 Flow f;
1086 TcpSession ssn;
1087
1089
1090 memset(&f, 0, sizeof(f));
1091 memset(&ssn, 0, sizeof(ssn));
1092
1093 FLOW_INITIALIZE(&f);
1094 f.protoctx = (void *)&ssn;
1095 f.proto = IPPROTO_TCP;
1097
1098 StreamTcpInitConfig(true);
1099
1100 int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1101 STREAM_TOSERVER, maskWriteRegisterReq,
1102 sizeof(maskWriteRegisterReq));
1103 FAIL_IF_NOT(r == 0);
1104
1105 ModbusState *modbus_state = f.alstate;
1106 FAIL_IF_NULL(modbus_state);
1107
1108 ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
1109 FAIL_IF_NULL(request._0);
1110
1111 FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 22);
1112 FAIL_IF_NOT(SCModbusMessageGetAndMask(&request) == 0x00F2);
1113 FAIL_IF_NOT(SCModbusMessageGetOrMask(&request) == 0x0025);
1114
1116 STREAM_TOCLIENT, maskWriteRegisterRsp,
1117 sizeof(maskWriteRegisterRsp));
1118 FAIL_IF_NOT(r == 0);
1119
1120 FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
1121
1123 StreamTcpFreeConfig(true);
1124 FLOW_DESTROY(&f);
1125 PASS;
1126}
1127
1128/** \test Send Modbus Write single register request/response. */
1129static int ModbusParserTest14(void) {
1131 Flow f;
1132 TcpSession ssn;
1133
1135
1136 memset(&f, 0, sizeof(f));
1137 memset(&ssn, 0, sizeof(ssn));
1138
1139 FLOW_INITIALIZE(&f);
1140 f.protoctx = (void *)&ssn;
1141 f.proto = IPPROTO_TCP;
1143
1144 StreamTcpInitConfig(true);
1145
1146 int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1147 STREAM_TOSERVER, writeSingleRegisterReq,
1148 sizeof(writeSingleRegisterReq));
1149 FAIL_IF_NOT(r == 0);
1150
1151 ModbusState *modbus_state = f.alstate;
1152 FAIL_IF_NULL(modbus_state);
1153
1154 ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
1155 FAIL_IF_NULL(request._0);
1156
1157 FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 6);
1158 FAIL_IF_NOT(SCModbusMessageGetWriteAddress(&request) == 0x0001);
1159 FAIL_IF_NOT(SCModbusMessageGetWriteData(&request) == 0x0003);
1160
1162 STREAM_TOCLIENT, writeSingleRegisterRsp,
1163 sizeof(writeSingleRegisterRsp));
1164 FAIL_IF_NOT(r == 0);
1165
1166 FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
1167
1169 StreamTcpFreeConfig(true);
1170 FLOW_DESTROY(&f);
1171 PASS;
1172}
1173
1174/** \test Send invalid Modbus Mask Write register request. */
1175static int ModbusParserTest15(void) {
1177 DetectEngineThreadCtx *det_ctx = NULL;
1178 Flow f;
1179 Packet *p = NULL;
1180 Signature *s = NULL;
1181 TcpSession ssn;
1182 ThreadVars tv;
1183
1185
1186 memset(&tv, 0, sizeof(ThreadVars));
1187 memset(&f, 0, sizeof(f));
1188 memset(&ssn, 0, sizeof(ssn));
1189
1190 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1191
1192 FLOW_INITIALIZE(&f);
1194 f.protoctx = (void *)&ssn;
1195 f.proto = IPPROTO_TCP;
1197 f.flags |= FLOW_IPV4;
1198
1199 p->flow = &f;
1202
1203 StreamTcpInitConfig(true);
1204
1207
1208 de_ctx->flags |= DE_QUIET;
1209 s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1210 "(msg:\"Modbus invalid Length\"; "
1211 "app-layer-event: "
1212 "modbus.invalid_length; "
1213 "sid:1;)");
1214 FAIL_IF_NULL(s);
1215
1217 DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
1218
1219 int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1220 STREAM_TOSERVER, invalidMaskWriteRegisterReq,
1221 sizeof(invalidMaskWriteRegisterReq));
1222 FAIL_IF_NOT(r == 0);
1223
1224 ModbusState *modbus_state = f.alstate;
1225 FAIL_IF_NULL(modbus_state);
1226
1227 ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
1228 FAIL_IF_NULL(request._0);
1229
1230 FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 22);
1231
1232 /* do detect */
1233 SigMatchSignatures(&tv, de_ctx, det_ctx, p);
1234
1236
1238 STREAM_TOCLIENT, maskWriteRegisterRsp,
1239 sizeof(maskWriteRegisterRsp));
1240 FAIL_IF_NOT(r == 0);
1241
1242 FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
1243 ModbusMessage response = SCModbusStateGetTxResponse(modbus_state, 0);
1244 FAIL_IF_NULL(response._0);
1245
1246 FAIL_IF_NOT(SCModbusMessageGetFunction(&response) == 22);
1247
1250
1251 DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
1253
1255 StreamTcpFreeConfig(true);
1256 FLOW_DESTROY(&f);
1257 UTHFreePackets(&p, 1);
1258 PASS;
1259}
1260
1261/** \test Send invalid Modbus Mask Write register request. */
1262static int ModbusParserTest16(void) {
1264 DetectEngineThreadCtx *det_ctx = NULL;
1265 Flow f;
1266 Packet *p = NULL;
1267 Signature *s = NULL;
1268 TcpSession ssn;
1269 ThreadVars tv;
1270
1272
1273 memset(&tv, 0, sizeof(ThreadVars));
1274 memset(&f, 0, sizeof(f));
1275 memset(&ssn, 0, sizeof(ssn));
1276
1277 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1278
1279 FLOW_INITIALIZE(&f);
1281 f.protoctx = (void *)&ssn;
1282 f.proto = IPPROTO_TCP;
1284 f.flags |= FLOW_IPV4;
1285
1286 p->flow = &f;
1289
1290 StreamTcpInitConfig(true);
1291
1294
1295 de_ctx->flags |= DE_QUIET;
1296 s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1297 "(msg:\"Modbus invalid Length\"; "
1298 "app-layer-event: "
1299 "modbus.invalid_length; "
1300 "sid:1;)");
1301 FAIL_IF_NULL(s);
1302
1304 DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
1305
1306 int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1307 STREAM_TOSERVER,
1308 invalidWriteSingleRegisterReq,
1309 sizeof(invalidWriteSingleRegisterReq));
1310 FAIL_IF_NOT(r == 0);
1311
1312 ModbusState *modbus_state = f.alstate;
1313 FAIL_IF_NULL(modbus_state);
1314
1315 ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
1316 FAIL_IF_NULL(request._0);
1317
1318 FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 6);
1319 size_t data_len;
1320 const uint8_t *data = SCModbusMessageGetBytevecData(&request, &data_len);
1321 FAIL_IF_NOT(data_len == 2);
1322 FAIL_IF_NOT(data[0] == 0x00);
1323 FAIL_IF_NOT(data[1] == 0x01);
1324
1325 /* do detect */
1326 SigMatchSignatures(&tv, de_ctx, det_ctx, p);
1327
1329
1331 STREAM_TOCLIENT, writeSingleRegisterRsp,
1332 sizeof(writeSingleRegisterRsp));
1333 FAIL_IF_NOT(r == 0);
1334
1335 FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
1336 ModbusMessage response = SCModbusStateGetTxResponse(modbus_state, 0);
1337 FAIL_IF_NULL(response._0);
1338
1339 FAIL_IF_NOT(SCModbusMessageGetFunction(&response) == 6);
1340 FAIL_IF_NOT(SCModbusMessageGetWriteAddress(&response) == 0x0001);
1341
1344
1345 DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
1347
1349 StreamTcpFreeConfig(true);
1350 FLOW_DESTROY(&f);
1351 UTHFreePackets(&p, 1);
1352 PASS;}
1353
1354/** \test Checks if stream_depth is correct */
1355static int ModbusParserTest17(void) {
1357 Flow f;
1358 TcpSession ssn;
1359
1361
1362 memset(&f, 0, sizeof(f));
1363 memset(&ssn, 0, sizeof(ssn));
1364
1365 FLOW_INITIALIZE(&f);
1366 f.protoctx = (void *)&ssn;
1367 f.proto = IPPROTO_TCP;
1369
1370 StreamTcpInitConfig(true);
1371
1372 int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER,
1373 readCoilsReq, sizeof(readCoilsReq));
1374 FAIL_IF(r != 0);
1375
1376 FAIL_IF(f.alstate == NULL);
1377
1378 FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH);
1379
1380 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT,
1381 readCoilsRsp, sizeof(readCoilsRsp));
1382 FAIL_IF(r != 0);
1383
1384 FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH);
1385
1387 StreamTcpFreeConfig(true);
1388 FLOW_DESTROY(&f);
1389 PASS;
1390}
1391
1392/*/ \test Checks if stream depth is correct over 2 TCP packets */
1393static int ModbusParserTest18(void) {
1395 Flow f;
1396 TcpSession ssn;
1397
1398 uint32_t input_len = sizeof(readCoilsReq), part2_len = 3;
1399 uint8_t *input = readCoilsReq;
1400
1402
1403 memset(&f, 0, sizeof(f));
1404 memset(&ssn, 0, sizeof(ssn));
1405
1406 FLOW_INITIALIZE(&f);
1407 f.protoctx = (void *)&ssn;
1408 f.proto = IPPROTO_TCP;
1410
1411 StreamTcpInitConfig(true);
1412
1413 int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER,
1414 input, input_len - part2_len);
1415 FAIL_IF(r != 1);
1416
1417 FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH);
1418
1419 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER,
1420 input, input_len);
1421 FAIL_IF(r != 0);
1422
1423 FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH);
1424
1425 FAIL_IF(f.alstate == NULL);
1426
1427 input_len = sizeof(readCoilsRsp);
1428 part2_len = 10;
1429 input = readCoilsRsp;
1430
1431 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT,
1432 input, input_len - part2_len);
1433 FAIL_IF(r != 1);
1434
1435 FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH);
1436
1437 r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT,
1438 input, input_len);
1439 FAIL_IF(r != 0);
1440
1441 FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH);
1442
1444 StreamTcpFreeConfig(true);
1445 FLOW_DESTROY(&f);
1446 PASS;
1447}
1448
1449/** \test Send Modbus invalid function. */
1450static int ModbusParserTest19(void) {
1452 DetectEngineThreadCtx *det_ctx = NULL;
1453 Flow f;
1454 Packet *p = NULL;
1455 Signature *s = NULL;
1456 TcpSession ssn;
1457 ThreadVars tv;
1458
1460
1461 memset(&tv, 0, sizeof(ThreadVars));
1462 memset(&f, 0, sizeof(Flow));
1463 memset(&ssn, 0, sizeof(TcpSession));
1464
1465 p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1466
1467 FLOW_INITIALIZE(&f);
1469 f.protoctx = (void *)&ssn;
1470 f.proto = IPPROTO_TCP;
1472 f.flags |= FLOW_IPV4;
1473
1474 p->flow = &f;
1477
1478 StreamTcpInitConfig(true);
1479
1482
1483 de_ctx->flags |= DE_QUIET;
1484 s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1485 "(msg:\"Modbus invalid Function code\"; "
1486 "app-layer-event: "
1487 "modbus.invalid_function_code; "
1488 "sid:1;)");
1489 FAIL_IF_NULL(s);
1490
1492 DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
1493
1494 int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1495 STREAM_TOSERVER,
1496 invalidFunctionCode,
1497 sizeof(invalidFunctionCode));
1498 FAIL_IF_NOT(r == 0);
1499
1500 ModbusState *modbus_state = f.alstate;
1501 FAIL_IF_NULL(modbus_state);
1502
1503 /* do detect */
1504 SigMatchSignatures(&tv, de_ctx, det_ctx, p);
1505
1507
1510
1511 DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
1513
1515 StreamTcpFreeConfig(true);
1516 FLOW_DESTROY(&f);
1517 UTHFreePackets(&p, 1);
1518 PASS;
1519}
1520#endif /* UNITTESTS */
1521
1523#ifdef UNITTESTS
1524 UtRegisterTest("ModbusParserTest01 - Modbus Read Coils request",
1525 ModbusParserTest01);
1526 UtRegisterTest("ModbusParserTest02 - Modbus Write Multiple registers request",
1527 ModbusParserTest02);
1528 UtRegisterTest("ModbusParserTest03 - Modbus Read/Write Multiple registers request",
1529 ModbusParserTest03);
1530 UtRegisterTest("ModbusParserTest04 - Modbus Force Listen Only Mode request",
1531 ModbusParserTest04);
1532 UtRegisterTest("ModbusParserTest05 - Modbus invalid Protocol version",
1533 ModbusParserTest05);
1534 UtRegisterTest("ModbusParserTest06 - Modbus unsolicited response",
1535 ModbusParserTest06);
1536 UtRegisterTest("ModbusParserTest07 - Modbus invalid Length request",
1537 ModbusParserTest07);
1538 UtRegisterTest("ModbusParserTest08 - Modbus Exception code invalid",
1539 ModbusParserTest08);
1540 UtRegisterTest("ModbusParserTest09 - Modbus fragmentation - 1 ADU in 2 TCP packets",
1541 ModbusParserTest09);
1542 UtRegisterTest("ModbusParserTest10 - Modbus fragmentation - 2 ADU in 1 TCP packet",
1543 ModbusParserTest10);
1544 UtRegisterTest("ModbusParserTest11 - Modbus exceeded Length request",
1545 ModbusParserTest11);
1546 UtRegisterTest("ModbusParserTest12 - Modbus invalid PDU Length",
1547 ModbusParserTest12);
1548 UtRegisterTest("ModbusParserTest13 - Modbus Mask Write register request",
1549 ModbusParserTest13);
1550 UtRegisterTest("ModbusParserTest14 - Modbus Write single register request",
1551 ModbusParserTest14);
1552 UtRegisterTest("ModbusParserTest15 - Modbus invalid Mask Write register request",
1553 ModbusParserTest15);
1554 UtRegisterTest("ModbusParserTest16 - Modbus invalid Write single register request",
1555 ModbusParserTest16);
1556 UtRegisterTest("ModbusParserTest17 - Modbus stream depth",
1557 ModbusParserTest17);
1558 UtRegisterTest("ModbusParserTest18 - Modbus stream depth in 2 TCP packets",
1559 ModbusParserTest18);
1560 UtRegisterTest("ModbusParserTest19 - Modbus invalid Function code",
1561 ModbusParserTest19);
1562#endif /* UNITTESTS */
1563}
#define MODBUS_CONFIG_DEFAULT_STREAM_DEPTH
void ModbusParserRegisterTests(void)
void RegisterModbusParsers(void)
Function to register the Modbus protocol parser.
void AppLayerParserRegisterProtocolUnittests(uint8_t ipproto, AppProto alproto, void(*RegisterUnittests)(void))
AppLayerParserThreadCtx * AppLayerParserThreadCtxAlloc(void)
Gets a new app layer protocol's parser thread context.
void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
Destroys the app layer parser thread context obtained using AppLayerParserThreadCtxAlloc().
int AppLayerParserParse(ThreadVars *tv, AppLayerParserThreadCtx *alp_tctx, Flow *f, AppProto alproto, uint8_t flags, const uint8_t *input, uint32_t input_len)
@ ALPROTO_MODBUS
#define PKT_HAS_FLOW
Definition decode.h:1266
#define PKT_STREAM_EST
Definition decode.h:1262
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
void SigCleanSignatures(DetectEngineCtx *de_ctx)
int SigGroupCleanup(DetectEngineCtx *de_ctx)
DetectEngineCtx * DetectEngineCtxInit(void)
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Signature * DetectEngineAppendSig(DetectEngineCtx *, const char *)
Parse and append a Signature into the Detection Engine Context signature list.
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
initialize thread specific detection engine context
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data)
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition detect.c:2420
#define DE_QUIET
Definition detect.h:330
#define FLOW_INITIALIZE(f)
Definition flow-util.h:38
#define FLOW_DESTROY(f)
Definition flow-util.h:119
#define FLOW_PKT_TOSERVER
Definition flow.h:233
#define FLOW_PKT_ESTABLISHED
Definition flow.h:235
#define FLOW_IPV4
Definition flow.h:100
AppLayerParserThreadCtx * alp_tctx
ThreadVars * tv
DetectEngineCtx * de_ctx
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
#define PASS
Pass the test.
#define FAIL_IF(expr)
Fail a test if expression evaluates to true.
void StreamTcpFreeConfig(bool quiet)
Definition stream-tcp.c:859
void StreamTcpInitConfig(bool)
To initialize the stream global configuration data.
Definition stream-tcp.c:488
main detection engine ctx
Definition detect.h:932
uint8_t flags
Definition detect.h:934
Flow data structure.
Definition flow.h:356
uint8_t proto
Definition flow.h:378
uint32_t flags
Definition flow.h:421
AppProto alproto
application level protocol
Definition flow.h:450
void * alstate
Definition flow.h:479
void * protoctx
Definition flow.h:441
uint8_t flowflags
Definition decode.h:532
struct Flow_ * flow
Definition decode.h:546
uint32_t flags
Definition decode.h:544
Signature container.
Definition detect.h:668
Per thread variable structure.
Definition threadvars.h:58
#define SCReturn
Definition util-debug.h:279
#define SCMalloc(sz)
Definition util-mem.h:47
#define SCFree(p)
Definition util-mem.h:61
#define SCRealloc(ptr, sz)
Definition util-mem.h:50
#define SCCalloc(nm, sz)
Definition util-mem.h:53
void UTHFreePackets(Packet **p, int numpkts)
UTHFreePackets: function to release the allocated data from UTHBuildPacket and the packet itself.
Packet * UTHBuildPacket(uint8_t *payload, uint16_t payload_len, uint8_t ipproto)
UTHBuildPacket is a wrapper that build packets with default ip and port fields.