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 
45 void ModbusParserRegisterTests(void);
46 
47 /**
48  * \brief Function to register the Modbus protocol parser
49  */
51 {
52  SCRegisterModbusParser();
53 #ifdef UNITTESTS
55 #endif
56 
57  SCReturn;
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"
71 #include "util-unittest-helper.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 */
82 static 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 */
92 static 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 
100 static 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 
108 static 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 */
120 static 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 
128 static 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 
135 static 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 */
145 static 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 
156 static 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 */
166 static 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 
175 static 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 
183 static 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 */
195 static 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 */
210 static 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. */
225 static 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 
233 static 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 
241 static 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 
253 static 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 
263 static 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. */
271 static 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 
286  StreamTcpInitConfig(true);
287 
288  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
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 
310  StreamTcpFreeConfig(true);
311  FLOW_DESTROY(&f);
312  PASS;
313 }
314 
315 /** \test Send Modbus Write Multiple registers request/response. */
316 static 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 
331  StreamTcpInitConfig(true);
332 
333  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
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 
363  StreamTcpFreeConfig(true);
364  FLOW_DESTROY(&f);
365  PASS;
366 }
367 
368 /** \test Send Modbus Read/Write Multiple registers request/response with mismatch value. */
369 static int ModbusParserTest03(void) {
371  DetectEngineThreadCtx *det_ctx = NULL;
372  Flow f;
373  Packet *p = NULL;
374  Signature *s = NULL;
375  TcpSession ssn;
376  ThreadVars tv;
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 
397  StreamTcpInitConfig(true);
398 
401 
402  de_ctx->flags |= DE_QUIET;
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 
413  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
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 
460  StreamTcpFreeConfig(true);
461  FLOW_DESTROY(&f);
462  UTHFreePackets(&p, 1);
463  PASS;
464 }
465 
466 /** \test Send Modbus Force Listen Only Mode request. */
467 static 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 
482  StreamTcpInitConfig(true);
483 
484  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
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 
499  StreamTcpFreeConfig(true);
500  FLOW_DESTROY(&f);
501  PASS;
502 }
503 
504 /** \test Send Modbus invalid Protocol version in request. */
505 static int ModbusParserTest05(void) {
507  DetectEngineThreadCtx *det_ctx = NULL;
508  Flow f;
509  Packet *p = NULL;
510  Signature *s = NULL;
511  TcpSession ssn;
512  ThreadVars tv;
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 
533  StreamTcpInitConfig(true);
534 
537 
538  de_ctx->flags |= DE_QUIET;
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 
549  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
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 
569  StreamTcpFreeConfig(true);
570  FLOW_DESTROY(&f);
571  UTHFreePackets(&p, 1);
572  PASS;
573 }
574 
575 /** \test Send Modbus unsolicited response. */
576 static int ModbusParserTest06(void) {
578  DetectEngineThreadCtx *det_ctx = NULL;
579  Flow f;
580  Packet *p = NULL;
581  Signature *s = NULL;
582  TcpSession ssn;
583  ThreadVars tv;
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 
604  StreamTcpInitConfig(true);
605 
608 
609  de_ctx->flags |= DE_QUIET;
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 
620  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
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 
640  StreamTcpFreeConfig(true);
641  FLOW_DESTROY(&f);
642  UTHFreePackets(&p, 1);
643  PASS;
644 }
645 
646 /** \test Send Modbus invalid Length request. */
647 static int ModbusParserTest07(void) {
649  DetectEngineThreadCtx *det_ctx = NULL;
650  Flow f;
651  Packet *p = NULL;
652  Signature *s = NULL;
653  TcpSession ssn;
654  ThreadVars tv;
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 
675  StreamTcpInitConfig(true);
676 
679 
680  de_ctx->flags |= DE_QUIET;
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 
691  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
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 
712  StreamTcpFreeConfig(true);
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. */
719 static int ModbusParserTest08(void) {
721  DetectEngineThreadCtx *det_ctx = NULL;
722  Flow f;
723  Packet *p = NULL;
724  Signature *s = NULL;
725  TcpSession ssn;
726  ThreadVars tv;
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 
747  StreamTcpInitConfig(true);
748 
751 
752  de_ctx->flags |= DE_QUIET;
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 
763  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
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 
797  StreamTcpFreeConfig(true);
798  FLOW_DESTROY(&f);
799  UTHFreePackets(&p, 1);
800  PASS;
801 }
802 
803 /** \test Modbus fragmentation - 1 ADU over 2 TCP packets. */
804 static 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 
822  StreamTcpInitConfig(true);
823 
824  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
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 
857  StreamTcpFreeConfig(true);
858  FLOW_DESTROY(&f);
859  PASS;
860 }
861 
862 /** \test Modbus fragmentation - 2 ADU in 1 TCP packet. */
863 static 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 
887  StreamTcpInitConfig(true);
888 
889  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
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);
927  StreamTcpFreeConfig(true);
928  FLOW_DESTROY(&f);
929  PASS;
930 }
931 
932 /** \test Send Modbus exceed Length request. */
933 static int ModbusParserTest11(void) {
935  DetectEngineThreadCtx *det_ctx = NULL;
936  Flow f;
937  Packet *p = NULL;
938  Signature *s = NULL;
939  TcpSession ssn;
940  ThreadVars tv;
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 
969  StreamTcpInitConfig(true);
970 
973 
974  de_ctx->flags |= DE_QUIET;
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. */
1011 static 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);
1029  f.alproto = ALPROTO_MODBUS;
1030  f.protoctx = (void *)&ssn;
1031  f.proto = IPPROTO_TCP;
1032  f.alproto = ALPROTO_MODBUS;
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. */
1083 static 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;
1096  f.alproto = ALPROTO_MODBUS;
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. */
1129 static 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;
1142  f.alproto = ALPROTO_MODBUS;
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. */
1175 static 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);
1193  f.alproto = ALPROTO_MODBUS;
1194  f.protoctx = (void *)&ssn;
1195  f.proto = IPPROTO_TCP;
1196  f.alproto = ALPROTO_MODBUS;
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. */
1262 static 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);
1280  f.alproto = ALPROTO_MODBUS;
1281  f.protoctx = (void *)&ssn;
1282  f.proto = IPPROTO_TCP;
1283  f.alproto = ALPROTO_MODBUS;
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 */
1355 static 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;
1368  f.alproto = ALPROTO_MODBUS;
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 */
1393 static 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;
1409  f.alproto = ALPROTO_MODBUS;
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. */
1450 static 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);
1468  f.alproto = ALPROTO_MODBUS;
1469  f.protoctx = (void *)&ssn;
1470  f.proto = IPPROTO_TCP;
1471  f.alproto = ALPROTO_MODBUS;
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 }
detect-engine.h
FAIL_IF_NULL
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
PKT_HAS_FLOW
#define PKT_HAS_FLOW
Definition: decode.h:1264
flow-util.h
stream-tcp.h
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
RegisterModbusParsers
void RegisterModbusParsers(void)
Function to register the Modbus protocol parser.
Definition: app-layer-modbus.c:50
ALPROTO_MODBUS
@ ALPROTO_MODBUS
Definition: app-layer-protos.h:48
Flow_::proto
uint8_t proto
Definition: flow.h:378
PacketAlertCheck
int PacketAlertCheck(Packet *p, uint32_t sid)
Check if a certain sid alerted, this is used in the test functions.
Definition: detect-engine-alert.c:142
Packet_::flags
uint32_t flags
Definition: decode.h:544
Flow_
Flow data structure.
Definition: flow.h:356
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:932
DetectEngineCtxFree
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Definition: detect-engine.c:2643
MODBUS_CONFIG_DEFAULT_STREAM_DEPTH
#define MODBUS_CONFIG_DEFAULT_STREAM_DEPTH
Definition: app-layer-modbus.c:79
AppLayerParserThreadCtxFree
void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
Destroys the app layer parser thread context obtained using AppLayerParserThreadCtxAlloc().
Definition: app-layer-parser.c:324
FLOW_PKT_TOSERVER
#define FLOW_PKT_TOSERVER
Definition: flow.h:233
rust.h
DE_QUIET
#define DE_QUIET
Definition: detect.h:330
UTHBuildPacket
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.
Definition: util-unittest-helper.c:365
SigMatchSignatures
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition: detect.c:2420
SigCleanSignatures
void SigCleanSignatures(DetectEngineCtx *de_ctx)
Definition: detect-engine-build.c:56
DetectEngineAppendSig
Signature * DetectEngineAppendSig(DetectEngineCtx *, const char *)
Parse and append a Signature into the Detection Engine Context signature list.
Definition: detect-parse.c:3437
Packet_::flowflags
uint8_t flowflags
Definition: decode.h:532
Flow_::protoctx
void * protoctx
Definition: flow.h:441
FLOW_IPV4
#define FLOW_IPV4
Definition: flow.h:100
util-unittest.h
util-unittest-helper.h
FAIL_IF_NOT
#define FAIL_IF_NOT(expr)
Fail a test if expression evaluates to false.
Definition: util-unittest.h:82
StreamTcpInitConfig
void StreamTcpInitConfig(bool)
To initialize the stream global configuration data.
Definition: stream-tcp.c:488
FLOW_INITIALIZE
#define FLOW_INITIALIZE(f)
Definition: flow-util.h:38
util-debug.h
PASS
#define PASS
Pass the test.
Definition: util-unittest.h:105
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:18
DetectEngineThreadCtx_
Definition: detect.h:1244
alp_tctx
AppLayerParserThreadCtx * alp_tctx
Definition: fuzz_applayerparserparse.c:23
detect.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
DetectEngineThreadCtxInit
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
initialize thread specific detection engine context
Definition: detect-engine.c:3369
app-layer-parser.h
SigGroupCleanup
int SigGroupCleanup(DetectEngineCtx *de_ctx)
Definition: detect-engine-build.c:2275
SCReturn
#define SCReturn
Definition: util-debug.h:279
AppLayerParserRegisterProtocolUnittests
void AppLayerParserRegisterProtocolUnittests(uint8_t ipproto, AppProto alproto, void(*RegisterUnittests)(void))
Definition: app-layer-parser.c:1840
Packet_
Definition: decode.h:501
detect-engine-build.h
stream-tcp-private.h
detect-engine-alert.h
ModbusParserRegisterTests
void ModbusParserRegisterTests(void)
Definition: app-layer-modbus.c:1522
SigGroupBuild
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
Definition: detect-engine-build.c:2204
SCRealloc
#define SCRealloc(ptr, sz)
Definition: util-mem.h:50
AppLayerParserThreadCtxAlloc
AppLayerParserThreadCtx * AppLayerParserThreadCtxAlloc(void)
Gets a new app layer protocol's parser thread context.
Definition: app-layer-parser.c:297
app-layer-modbus.h
Packet_::flow
struct Flow_ * flow
Definition: decode.h:546
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:859
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:1291
suricata-common.h
DetectEngineThreadCtxDeinit
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data)
Definition: detect-engine.c:3605
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:32
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
SCFree
#define SCFree(p)
Definition: util-mem.h:61
Flow_::alstate
void * alstate
Definition: flow.h:479
Flow_::flags
uint32_t flags
Definition: flow.h:421
detect-parse.h
Signature_
Signature container.
Definition: detect.h:668
FLOW_PKT_ESTABLISHED
#define FLOW_PKT_ESTABLISHED
Definition: flow.h:235
DetectEngineCtxInit
DetectEngineCtx * DetectEngineCtxInit(void)
Definition: detect-engine.c:2604
DetectEngineCtx_::flags
uint8_t flags
Definition: detect.h:934
AppLayerParserThreadCtx_
Definition: app-layer-parser.c:60
TcpSession_
Definition: stream-tcp-private.h:283
Flow_::alproto
AppProto alproto
application level protocol
Definition: flow.h:450
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
FLOW_DESTROY
#define FLOW_DESTROY(f)
Definition: flow-util.h:119
PKT_STREAM_EST
#define PKT_STREAM_EST
Definition: decode.h:1260
UTHFreePackets
void UTHFreePackets(Packet **p, int numpkts)
UTHFreePackets: function to release the allocated data from UTHBuildPacket and the packet itself.
Definition: util-unittest-helper.c:456