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)
272 {
273  Flow f;
274  TcpSession ssn;
275 
278 
279  memset(&f, 0, sizeof(f));
280  memset(&ssn, 0, sizeof(ssn));
281 
282  FLOW_INITIALIZE(&f);
283  f.protoctx = (void *)&ssn;
284  f.proto = IPPROTO_TCP;
286 
287  StreamTcpInitConfig(true);
288 
289  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
290  STREAM_TOSERVER, readCoilsReq,
291  sizeof(readCoilsReq));
292  FAIL_IF_NOT(r == 0);
293 
294  ModbusState *modbus_state = f.alstate;
295  FAIL_IF_NULL(modbus_state);
296 
297  ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
298  FAIL_IF_NULL(request._0);
299  FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 1);
300  FAIL_IF_NOT(SCModbusMessageGetReadRequestAddress(&request) == 0x7890);
301  FAIL_IF_NOT(SCModbusMessageGetReadRequestQuantity(&request) == 19);
302 
304  STREAM_TOCLIENT, readCoilsRsp,
305  sizeof(readCoilsRsp));
306  FAIL_IF_NOT(r == 0);
307  FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
308 
309  FLOW_DESTROY(&f);
311  StreamTcpFreeConfig(true);
312  PASS;
313 }
314 
315 /** \test Send Modbus Write Multiple registers request/response. */
316 static int ModbusParserTest02(void)
317 {
318  Flow f;
319  TcpSession ssn;
320 
323 
324  memset(&f, 0, sizeof(f));
325  memset(&ssn, 0, sizeof(ssn));
326 
327  FLOW_INITIALIZE(&f);
328  f.protoctx = (void *)&ssn;
329  f.proto = IPPROTO_TCP;
331 
332  StreamTcpInitConfig(true);
333 
334  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
335  STREAM_TOSERVER, writeMultipleRegistersReq,
336  sizeof(writeMultipleRegistersReq));
337  FAIL_IF_NOT(r == 0);
338 
339  ModbusState *modbus_state = f.alstate;
340  FAIL_IF_NULL(modbus_state);
341 
342  ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
343  FAIL_IF_NULL(request._0);
344  FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 16);
345  FAIL_IF_NOT(SCModbusMessageGetWriteMultreqAddress(&request) == 0x01);
346  FAIL_IF_NOT(SCModbusMessageGetWriteMultreqQuantity(&request) == 2);
347 
348  size_t data_len;
349  const uint8_t *data = SCModbusMessageGetWriteMultreqData(&request, &data_len);
350  FAIL_IF_NOT(data_len == 4);
351  FAIL_IF_NOT(data[0] == 0x00);
352  FAIL_IF_NOT(data[1] == 0x0A);
353  FAIL_IF_NOT(data[2] == 0x01);
354  FAIL_IF_NOT(data[3] == 0x02);
355 
357  STREAM_TOCLIENT, writeMultipleRegistersRsp,
358  sizeof(writeMultipleRegistersRsp));
359  FAIL_IF_NOT(r == 0);
360  FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
361 
362  FLOW_DESTROY(&f);
364  StreamTcpFreeConfig(true);
365  PASS;
366 }
367 
368 /** \test Send Modbus Read/Write Multiple registers request/response with mismatch value. */
369 static int ModbusParserTest03(void)
370 {
371  DetectEngineThreadCtx *det_ctx = NULL;
372  Flow f;
373  Packet *p = NULL;
374  Signature *s = NULL;
375  TcpSession ssn;
376  ThreadVars tv;
377 
380 
381  memset(&tv, 0, sizeof(ThreadVars));
383  memset(&f, 0, sizeof(Flow));
384  memset(&ssn, 0, sizeof(TcpSession));
385 
386  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
387 
388  FLOW_INITIALIZE(&f);
390  f.protoctx = (void *)&ssn;
391  f.proto = IPPROTO_TCP;
393  f.flags |= FLOW_IPV4;
394 
395  p->flow = &f;
398 
399  StreamTcpInitConfig(true);
400 
403 
404  de_ctx->flags |= DE_QUIET;
405  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
406  "(msg:\"Modbus Data mismatch\"; "
407  "app-layer-event: "
408  "modbus.value_mismatch; "
409  "sid:1;)");
410  FAIL_IF_NULL(s);
411 
413  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
414 
415  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
416  STREAM_TOSERVER,
417  readWriteMultipleRegistersReq,
418  sizeof(readWriteMultipleRegistersReq));
419  FAIL_IF_NOT(r == 0);
420 
421  ModbusState *modbus_state = f.alstate;
422  FAIL_IF_NULL(modbus_state);
423 
424  ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
425  FAIL_IF_NULL(request._0);
426 
427  FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 23);
428  FAIL_IF_NOT(SCModbusMessageGetRwMultreqReadAddress(&request) == 0x03);
429  FAIL_IF_NOT(SCModbusMessageGetRwMultreqReadQuantity(&request) == 6);
430  FAIL_IF_NOT(SCModbusMessageGetRwMultreqWriteAddress(&request) == 0x0E);
431  FAIL_IF_NOT(SCModbusMessageGetRwMultreqWriteQuantity(&request) == 3);
432 
433  size_t data_len;
434  uint8_t const *data = SCModbusMessageGetRwMultreqWriteData(&request, &data_len);
435  FAIL_IF_NOT(data_len == 6);
436  FAIL_IF_NOT(data[0] == 0x12);
437  FAIL_IF_NOT(data[1] == 0x34);
438  FAIL_IF_NOT(data[2] == 0x56);
439  FAIL_IF_NOT(data[3] == 0x78);
440  FAIL_IF_NOT(data[4] == 0x9A);
441  FAIL_IF_NOT(data[5] == 0xBC);
442 
444  STREAM_TOCLIENT, readWriteMultipleRegistersRsp,
445  sizeof(readWriteMultipleRegistersRsp));
446  FAIL_IF_NOT(r == 0);
447  FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
448 
449  /* do detect */
450  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
452 
453  UTHFreePackets(&p, 1);
454  FLOW_DESTROY(&f);
455 
457  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
459  StreamTcpFreeConfig(true);
461  PASS;
462 }
463 
464 /** \test Send Modbus Force Listen Only Mode request. */
465 static int ModbusParserTest04(void)
466 {
467  Flow f;
468  TcpSession ssn;
469 
472 
473  memset(&f, 0, sizeof(f));
474  memset(&ssn, 0, sizeof(ssn));
475 
476  FLOW_INITIALIZE(&f);
477  f.protoctx = (void *)&ssn;
478  f.proto = IPPROTO_TCP;
480 
481  StreamTcpInitConfig(true);
482 
483  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
484  STREAM_TOSERVER, forceListenOnlyMode,
485  sizeof(forceListenOnlyMode));
486  FAIL_IF_NOT(r == 0);
487 
488  ModbusState *modbus_state = f.alstate;
489  FAIL_IF_NULL(modbus_state);
490 
491  ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
492  FAIL_IF_NULL(request._0);
493  FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 8);
494  FAIL_IF_NOT(SCModbusMessageGetSubfunction(&request) == 4);
495 
497  StreamTcpFreeConfig(true);
498  FLOW_DESTROY(&f);
499  PASS;
500 }
501 
502 /** \test Send Modbus invalid Protocol version in request. */
503 static int ModbusParserTest05(void)
504 {
505  DetectEngineThreadCtx *det_ctx = NULL;
506  Flow f;
507  Packet *p = NULL;
508  Signature *s = NULL;
509  TcpSession ssn;
510  ThreadVars tv;
511 
514 
515  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);
560 
561  UTHFreePackets(&p, 1);
562  FLOW_DESTROY(&f);
563 
565  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
567  StreamTcpFreeConfig(true);
569  PASS;
570 }
571 
572 /** \test Send Modbus unsolicited response. */
573 static int ModbusParserTest06(void)
574 {
575  DetectEngineThreadCtx *det_ctx = NULL;
576  Flow f;
577  Packet *p = NULL;
578  Signature *s = NULL;
579  TcpSession ssn;
580  ThreadVars tv;
581 
584 
585  memset(&tv, 0, sizeof(ThreadVars));
587  memset(&f, 0, sizeof(Flow));
588  memset(&ssn, 0, sizeof(TcpSession));
589 
590  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
591 
592  FLOW_INITIALIZE(&f);
594  f.protoctx = (void *)&ssn;
595  f.proto = IPPROTO_TCP;
597  f.flags |= FLOW_IPV4;
598 
599  p->flow = &f;
602 
603  StreamTcpInitConfig(true);
604 
607 
608  de_ctx->flags |= DE_QUIET;
609  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
610  "(msg:\"Modbus unsolicited response\"; "
611  "app-layer-event: "
612  "modbus.unsolicited_response; "
613  "sid:1;)");
614  FAIL_IF_NULL(s);
615 
617  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
618 
619  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
620  STREAM_TOCLIENT, readCoilsRsp,
621  sizeof(readCoilsRsp));
622  FAIL_IF_NOT(r == 0);
623 
624  ModbusState *modbus_state = f.alstate;
625  FAIL_IF_NULL(modbus_state);
626 
627  /* do detect */
628  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
630 
631  UTHFreePackets(&p, 1);
632  FLOW_DESTROY(&f);
633 
635  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
637  StreamTcpFreeConfig(true);
639  PASS;
640 }
641 
642 /** \test Send Modbus invalid Length request. */
643 static int ModbusParserTest07(void)
644 {
645  DetectEngineThreadCtx *det_ctx = NULL;
646  Flow f;
647  Packet *p = NULL;
648  Signature *s = NULL;
649  TcpSession ssn;
650  ThreadVars tv;
651 
654 
655  memset(&tv, 0, sizeof(ThreadVars));
657  memset(&f, 0, sizeof(Flow));
658  memset(&ssn, 0, sizeof(TcpSession));
659 
660  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
661 
662  FLOW_INITIALIZE(&f);
664  f.protoctx = (void *)&ssn;
665  f.proto = IPPROTO_TCP;
667  f.flags |= FLOW_IPV4;
668 
669  p->flow = &f;
672 
673  StreamTcpInitConfig(true);
674 
677 
678  de_ctx->flags |= DE_QUIET;
679  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
680  "(msg:\"Modbus invalid Length\"; "
681  "app-layer-event: "
682  "modbus.invalid_length; "
683  "sid:1;)");
684  FAIL_IF_NULL(s);
685 
687  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
688 
689  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
690  STREAM_TOSERVER,
691  invalidLengthWriteMultipleRegistersReq,
692  sizeof(invalidLengthWriteMultipleRegistersReq));
693  FAIL_IF_NOT(r == 1);
694 
695  ModbusState *modbus_state = f.alstate;
696  FAIL_IF_NULL(modbus_state);
697 
698  /* do detect */
699  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
701 
702  UTHFreePackets(&p, 1);
703  FLOW_DESTROY(&f);
704 
706  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
708  StreamTcpFreeConfig(true);
710  PASS;
711 }
712 
713 /** \test Send Modbus Read Coils request and error response with Exception code invalid. */
714 static int ModbusParserTest08(void)
715 {
716  DetectEngineThreadCtx *det_ctx = NULL;
717  Flow f;
718  Packet *p = NULL;
719  Signature *s = NULL;
720  TcpSession ssn;
721  ThreadVars tv;
722 
725 
726  memset(&tv, 0, sizeof(ThreadVars));
728  memset(&f, 0, sizeof(Flow));
729  memset(&ssn, 0, sizeof(TcpSession));
730 
731  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
732 
733  FLOW_INITIALIZE(&f);
735  f.protoctx = (void *)&ssn;
736  f.proto = IPPROTO_TCP;
738  f.flags |= FLOW_IPV4;
739 
740  p->flow = &f;
743 
744  StreamTcpInitConfig(true);
745 
748 
749  de_ctx->flags |= DE_QUIET;
750  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
751  "(msg:\"Modbus Exception code invalid\"; "
752  "app-layer-event: "
753  "modbus.invalid_exception_code; "
754  "sid:1;)");
755  FAIL_IF_NULL(s);
756 
758  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
759 
760  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
761  STREAM_TOSERVER, readCoilsReq,
762  sizeof(readCoilsReq));
763  FAIL_IF_NOT(r == 0);
764 
765  ModbusState *modbus_state = f.alstate;
766  FAIL_IF_NULL(modbus_state);
767 
768  ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
769  FAIL_IF_NULL(request._0);
770  FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 1);
771  FAIL_IF_NOT(SCModbusMessageGetReadRequestAddress(&request) == 0x7890);
772  FAIL_IF_NOT(SCModbusMessageGetReadRequestQuantity(&request) == 19);
773 
775  STREAM_TOCLIENT, readCoilsErrorRsp,
776  sizeof(readCoilsErrorRsp));
777  FAIL_IF_NOT(r == 0);
778  FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
779 
780  /* do detect */
781  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
783 
784  UTHFreePackets(&p, 1);
785  FLOW_DESTROY(&f);
786 
788  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
790  StreamTcpFreeConfig(true);
792  PASS;
793 }
794 
795 /** \test Modbus fragmentation - 1 ADU over 2 TCP packets. */
796 static int ModbusParserTest09(void) {
798  Flow f;
799  TcpSession ssn;
800 
801  uint32_t input_len = sizeof(readCoilsReq), part2_len = 3;
802  uint8_t *input = readCoilsReq;
803 
805 
806  memset(&f, 0, sizeof(f));
807  memset(&ssn, 0, sizeof(ssn));
808 
809  FLOW_INITIALIZE(&f);
810  f.protoctx = (void *)&ssn;
811  f.proto = IPPROTO_TCP;
813 
814  StreamTcpInitConfig(true);
815 
816  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
817  STREAM_TOSERVER, input, input_len - part2_len);
818  FAIL_IF_NOT(r == 1);
819 
821  STREAM_TOSERVER, input, input_len);
822  FAIL_IF_NOT(r == 0);
823 
824  ModbusState *modbus_state = f.alstate;
825  FAIL_IF_NULL(modbus_state);
826 
827  ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
828  FAIL_IF_NULL(request._0);
829  FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 1);
830  FAIL_IF_NOT(SCModbusMessageGetReadRequestAddress(&request) == 0x7890);
831  FAIL_IF_NOT(SCModbusMessageGetReadRequestQuantity(&request) == 19);
832 
833  input_len = sizeof(readCoilsRsp);
834  part2_len = 10;
835  input = readCoilsRsp;
836 
838  STREAM_TOCLIENT, input, input_len - part2_len);
839  FAIL_IF_NOT(r == 1);
840 
842  STREAM_TOCLIENT, input, input_len);
843  FAIL_IF_NOT(r == 0);
844  FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
845 
847  StreamTcpFreeConfig(true);
848  FLOW_DESTROY(&f);
849  PASS;
850 }
851 
852 /** \test Modbus fragmentation - 2 ADU in 1 TCP packet. */
853 static int ModbusParserTest10(void) {
854  uint32_t input_len = sizeof(readCoilsReq) + sizeof(writeMultipleRegistersReq);
855  uint8_t *input, *ptr;
856 
857  Flow f;
858  TcpSession ssn;
859 
862 
863  input = (uint8_t *) SCMalloc (input_len * sizeof(uint8_t));
864  FAIL_IF_NULL(input);
865 
866  memcpy(input, readCoilsReq, sizeof(readCoilsReq));
867  memcpy(input + sizeof(readCoilsReq), writeMultipleRegistersReq, sizeof(writeMultipleRegistersReq));
868 
869  memset(&f, 0, sizeof(f));
870  memset(&ssn, 0, sizeof(ssn));
871 
872  FLOW_INITIALIZE(&f);
873  f.protoctx = (void *)&ssn;
874  f.proto = IPPROTO_TCP;
876 
877  StreamTcpInitConfig(true);
878 
879  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
880  STREAM_TOSERVER, input, input_len);
881  FAIL_IF_NOT(r == 0);
882 
883  ModbusState *modbus_state = f.alstate;
884  FAIL_IF_NULL(modbus_state);
885  FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 2);
886 
887  ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 1);
888  FAIL_IF_NULL(request._0);
889  FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 16);
890  FAIL_IF_NOT(SCModbusMessageGetWriteMultreqAddress(&request) == 0x01);
891  FAIL_IF_NOT(SCModbusMessageGetWriteMultreqQuantity(&request) == 2);
892 
893  size_t data_len;
894  uint8_t const *data = SCModbusMessageGetWriteMultreqData(&request, &data_len);
895  FAIL_IF_NOT(data_len == 4);
896  FAIL_IF_NOT(data[0] == 0x00);
897  FAIL_IF_NOT(data[1] == 0x0A);
898  FAIL_IF_NOT(data[2] == 0x01);
899  FAIL_IF_NOT(data[3] == 0x02);
900 
901  input_len = sizeof(readCoilsRsp) + sizeof(writeMultipleRegistersRsp);
902 
903  ptr = (uint8_t *) SCRealloc (input, input_len * sizeof(uint8_t));
904  FAIL_IF_NULL(ptr);
905  input = ptr;
906 
907  memcpy(input, readCoilsRsp, sizeof(readCoilsRsp));
908  memcpy(input + sizeof(readCoilsRsp), writeMultipleRegistersRsp, sizeof(writeMultipleRegistersRsp));
909 
910  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, input, input_len);
911  FAIL_IF_NOT(r == 0);
912 
913  FLOW_DESTROY(&f);
914  SCFree(input);
916  StreamTcpFreeConfig(true);
917  PASS;
918 }
919 
920 /** \test Send Modbus exceed Length request. */
921 static int ModbusParserTest11(void)
922 {
923  DetectEngineThreadCtx *det_ctx = NULL;
924  Flow f;
925  TcpSession ssn;
926  ThreadVars tv;
927 
928  size_t input_len = 65536;
929  uint8_t *input = SCCalloc(1, input_len);
930  FAIL_IF(input == NULL);
931 
932  memcpy(input, exceededLengthWriteMultipleRegistersReq,
933  sizeof(exceededLengthWriteMultipleRegistersReq));
934 
936  FAIL_IF(alp_tctx == NULL);
937 
938  memset(&tv, 0, sizeof(ThreadVars));
940  memset(&f, 0, sizeof(Flow));
941  memset(&ssn, 0, sizeof(TcpSession));
942 
943  Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
944 
945  FLOW_INITIALIZE(&f);
947  f.protoctx = (void *)&ssn;
948  f.proto = IPPROTO_TCP;
950  f.flags |= FLOW_IPV4;
951 
952  p->flow = &f;
955 
956  StreamTcpInitConfig(true);
957 
960 
961  de_ctx->flags |= DE_QUIET;
962  Signature *s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
963  "(msg:\"Modbus invalid Length\"; "
964  "app-layer-event: "
965  "modbus.invalid_length; "
966  "sid:1;)");
967  FAIL_IF_NULL(s);
968 
970  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
971 
972  int r = AppLayerParserParse(
973  NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, input, input_len);
974  FAIL_IF_NOT(r == 0);
975 
976  ModbusState *modbus_state = f.alstate;
977  FAIL_IF_NULL(modbus_state);
978 
979  /* do detect */
980  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
982 
983  UTHFreePackets(&p, 1);
984  FLOW_DESTROY(&f);
985 
987  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
989  StreamTcpFreeConfig(true);
991  SCFree(input);
992  PASS;
993 }
994 
995 /** \test Send Modbus invalid PDU Length. */
996 static int ModbusParserTest12(void)
997 {
998  DetectEngineThreadCtx *det_ctx = NULL;
999  Flow f;
1000  Packet *p = NULL;
1001  TcpSession ssn;
1002  ThreadVars tv;
1003 
1006 
1007  memset(&tv, 0, sizeof(ThreadVars));
1009  memset(&f, 0, sizeof(Flow));
1010  memset(&ssn, 0, sizeof(TcpSession));
1011 
1012  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1013 
1014  FLOW_INITIALIZE(&f);
1015  f.alproto = ALPROTO_MODBUS;
1016  f.protoctx = (void *)&ssn;
1017  f.proto = IPPROTO_TCP;
1018  f.alproto = ALPROTO_MODBUS;
1019  f.flags |= FLOW_IPV4;
1020 
1021  p->flow = &f;
1024 
1025  StreamTcpInitConfig(true);
1026 
1029 
1030  de_ctx->flags |= DE_QUIET;
1031  Signature *s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1032  "(msg:\"Modbus invalid Length\"; "
1033  "app-layer-event: "
1034  "modbus.invalid_length; "
1035  "sid:1;)");
1036  FAIL_IF_NULL(s);
1037 
1039  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
1040 
1041  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1042  STREAM_TOSERVER,
1043  invalidLengthPDUWriteMultipleRegistersReq,
1044  sizeof(invalidLengthPDUWriteMultipleRegistersReq));
1045  FAIL_IF_NOT(r == 0);
1046 
1047  ModbusState *modbus_state = f.alstate;
1048  FAIL_IF_NULL(modbus_state);
1049 
1050  /* do detect */
1051  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
1053 
1054  UTHFreePackets(&p, 1);
1055  FLOW_DESTROY(&f);
1056 
1058  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
1060  StreamTcpFreeConfig(true);
1062  PASS;
1063 }
1064 
1065 /** \test Send Modbus Mask Write register request/response. */
1066 static int ModbusParserTest13(void)
1067 {
1068  Flow f;
1069  TcpSession ssn;
1070 
1073 
1074  memset(&f, 0, sizeof(f));
1075  memset(&ssn, 0, sizeof(ssn));
1076 
1077  FLOW_INITIALIZE(&f);
1078  f.protoctx = (void *)&ssn;
1079  f.proto = IPPROTO_TCP;
1080  f.alproto = ALPROTO_MODBUS;
1081 
1082  StreamTcpInitConfig(true);
1083 
1084  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1085  STREAM_TOSERVER, maskWriteRegisterReq,
1086  sizeof(maskWriteRegisterReq));
1087  FAIL_IF_NOT(r == 0);
1088 
1089  ModbusState *modbus_state = f.alstate;
1090  FAIL_IF_NULL(modbus_state);
1091 
1092  ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
1093  FAIL_IF_NULL(request._0);
1094  FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 22);
1095  FAIL_IF_NOT(SCModbusMessageGetAndMask(&request) == 0x00F2);
1096  FAIL_IF_NOT(SCModbusMessageGetOrMask(&request) == 0x0025);
1097 
1099  STREAM_TOCLIENT, maskWriteRegisterRsp,
1100  sizeof(maskWriteRegisterRsp));
1101  FAIL_IF_NOT(r == 0);
1102  FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
1103 
1105  StreamTcpFreeConfig(true);
1106  FLOW_DESTROY(&f);
1107  PASS;
1108 }
1109 
1110 /** \test Send Modbus Write single register request/response. */
1111 static int ModbusParserTest14(void)
1112 {
1113  Flow f;
1114  TcpSession ssn;
1115 
1118 
1119  memset(&f, 0, sizeof(f));
1120  memset(&ssn, 0, sizeof(ssn));
1121 
1122  FLOW_INITIALIZE(&f);
1123  f.protoctx = (void *)&ssn;
1124  f.proto = IPPROTO_TCP;
1125  f.alproto = ALPROTO_MODBUS;
1126 
1127  StreamTcpInitConfig(true);
1128 
1129  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1130  STREAM_TOSERVER, writeSingleRegisterReq,
1131  sizeof(writeSingleRegisterReq));
1132  FAIL_IF_NOT(r == 0);
1133 
1134  ModbusState *modbus_state = f.alstate;
1135  FAIL_IF_NULL(modbus_state);
1136 
1137  ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
1138  FAIL_IF_NULL(request._0);
1139  FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 6);
1140  FAIL_IF_NOT(SCModbusMessageGetWriteAddress(&request) == 0x0001);
1141  FAIL_IF_NOT(SCModbusMessageGetWriteData(&request) == 0x0003);
1142 
1144  STREAM_TOCLIENT, writeSingleRegisterRsp,
1145  sizeof(writeSingleRegisterRsp));
1146  FAIL_IF_NOT(r == 0);
1147  FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
1148 
1149  FLOW_DESTROY(&f);
1151  StreamTcpFreeConfig(true);
1152  PASS;
1153 }
1154 
1155 /** \test Send invalid Modbus Mask Write register request. */
1156 static int ModbusParserTest15(void)
1157 {
1158  DetectEngineThreadCtx *det_ctx = NULL;
1159  Flow f;
1160  Packet *p = NULL;
1161  Signature *s = NULL;
1162  TcpSession ssn;
1163  ThreadVars tv;
1164 
1167 
1168  memset(&tv, 0, sizeof(ThreadVars));
1170  memset(&f, 0, sizeof(f));
1171  memset(&ssn, 0, sizeof(ssn));
1172 
1173  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1174 
1175  FLOW_INITIALIZE(&f);
1176  f.alproto = ALPROTO_MODBUS;
1177  f.protoctx = (void *)&ssn;
1178  f.proto = IPPROTO_TCP;
1179  f.alproto = ALPROTO_MODBUS;
1180  f.flags |= FLOW_IPV4;
1181 
1182  p->flow = &f;
1185 
1186  StreamTcpInitConfig(true);
1187 
1190 
1191  de_ctx->flags |= DE_QUIET;
1192  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1193  "(msg:\"Modbus invalid Length\"; "
1194  "app-layer-event: "
1195  "modbus.invalid_length; "
1196  "sid:1;)");
1197  FAIL_IF_NULL(s);
1198 
1200  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
1201 
1202  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1203  STREAM_TOSERVER, invalidMaskWriteRegisterReq,
1204  sizeof(invalidMaskWriteRegisterReq));
1205  FAIL_IF_NOT(r == 0);
1206 
1207  ModbusState *modbus_state = f.alstate;
1208  FAIL_IF_NULL(modbus_state);
1209 
1210  ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
1211  FAIL_IF_NULL(request._0);
1212  FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 22);
1213 
1214  /* do detect */
1215  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
1217 
1219  STREAM_TOCLIENT, maskWriteRegisterRsp,
1220  sizeof(maskWriteRegisterRsp));
1221  FAIL_IF_NOT(r == 0);
1222  FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
1223  ModbusMessage response = SCModbusStateGetTxResponse(modbus_state, 0);
1224  FAIL_IF_NULL(response._0);
1225  FAIL_IF_NOT(SCModbusMessageGetFunction(&response) == 22);
1226 
1227  UTHFreePackets(&p, 1);
1228  FLOW_DESTROY(&f);
1229 
1231  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
1233  StreamTcpFreeConfig(true);
1235  PASS;
1236 }
1237 
1238 /** \test Send invalid Modbus Mask Write register request. */
1239 static int ModbusParserTest16(void)
1240 {
1241  DetectEngineThreadCtx *det_ctx = NULL;
1242  Flow f;
1243  Packet *p = NULL;
1244  Signature *s = NULL;
1245  TcpSession ssn;
1246  ThreadVars tv;
1247 
1250 
1251  memset(&tv, 0, sizeof(ThreadVars));
1253  memset(&f, 0, sizeof(f));
1254  memset(&ssn, 0, sizeof(ssn));
1255 
1256  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1257 
1258  FLOW_INITIALIZE(&f);
1259  f.alproto = ALPROTO_MODBUS;
1260  f.protoctx = (void *)&ssn;
1261  f.proto = IPPROTO_TCP;
1262  f.alproto = ALPROTO_MODBUS;
1263  f.flags |= FLOW_IPV4;
1264 
1265  p->flow = &f;
1268 
1269  StreamTcpInitConfig(true);
1270 
1273 
1274  de_ctx->flags |= DE_QUIET;
1275  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1276  "(msg:\"Modbus invalid Length\"; "
1277  "app-layer-event: "
1278  "modbus.invalid_length; "
1279  "sid:1;)");
1280  FAIL_IF_NULL(s);
1281 
1283  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
1284 
1285  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1286  STREAM_TOSERVER,
1287  invalidWriteSingleRegisterReq,
1288  sizeof(invalidWriteSingleRegisterReq));
1289  FAIL_IF_NOT(r == 0);
1290 
1291  ModbusState *modbus_state = f.alstate;
1292  FAIL_IF_NULL(modbus_state);
1293 
1294  ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
1295  FAIL_IF_NULL(request._0);
1296  FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 6);
1297  size_t data_len;
1298  const uint8_t *data = SCModbusMessageGetBytevecData(&request, &data_len);
1299  FAIL_IF_NOT(data_len == 2);
1300  FAIL_IF_NOT(data[0] == 0x00);
1301  FAIL_IF_NOT(data[1] == 0x01);
1302 
1303  /* do detect */
1304  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
1306 
1308  STREAM_TOCLIENT, writeSingleRegisterRsp,
1309  sizeof(writeSingleRegisterRsp));
1310  FAIL_IF_NOT(r == 0);
1311 
1312  FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
1313  ModbusMessage response = SCModbusStateGetTxResponse(modbus_state, 0);
1314  FAIL_IF_NULL(response._0);
1315  FAIL_IF_NOT(SCModbusMessageGetFunction(&response) == 6);
1316  FAIL_IF_NOT(SCModbusMessageGetWriteAddress(&response) == 0x0001);
1317 
1318  UTHFreePackets(&p, 1);
1319  FLOW_DESTROY(&f);
1320 
1322  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
1324  StreamTcpFreeConfig(true);
1326  PASS;
1327 }
1328 
1329 /** \test Checks if stream_depth is correct */
1330 static int ModbusParserTest17(void)
1331 {
1332  Flow f;
1333  TcpSession ssn;
1334 
1337 
1338  memset(&f, 0, sizeof(f));
1339  memset(&ssn, 0, sizeof(ssn));
1340 
1341  FLOW_INITIALIZE(&f);
1342  f.protoctx = (void *)&ssn;
1343  f.proto = IPPROTO_TCP;
1344  f.alproto = ALPROTO_MODBUS;
1345 
1346  StreamTcpInitConfig(true);
1347 
1348  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER,
1349  readCoilsReq, sizeof(readCoilsReq));
1350  FAIL_IF(r != 0);
1351  FAIL_IF(f.alstate == NULL);
1352  FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH);
1353 
1354  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT,
1355  readCoilsRsp, sizeof(readCoilsRsp));
1356  FAIL_IF(r != 0);
1357  FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH);
1358 
1359  FLOW_DESTROY(&f);
1361  StreamTcpFreeConfig(true);
1362  PASS;
1363 }
1364 
1365 /*/ \test Checks if stream depth is correct over 2 TCP packets */
1366 static int ModbusParserTest18(void)
1367 {
1368  Flow f;
1369  TcpSession ssn;
1370 
1371  uint32_t input_len = sizeof(readCoilsReq), part2_len = 3;
1372  uint8_t *input = readCoilsReq;
1373 
1376 
1377  memset(&f, 0, sizeof(f));
1378  memset(&ssn, 0, sizeof(ssn));
1379 
1380  FLOW_INITIALIZE(&f);
1381  f.protoctx = (void *)&ssn;
1382  f.proto = IPPROTO_TCP;
1383  f.alproto = ALPROTO_MODBUS;
1384 
1385  StreamTcpInitConfig(true);
1386 
1387  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER,
1388  input, input_len - part2_len);
1389  FAIL_IF(r != 1);
1390  FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH);
1391 
1392  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER,
1393  input, input_len);
1394  FAIL_IF(r != 0);
1395  FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH);
1396  FAIL_IF(f.alstate == NULL);
1397 
1398  input_len = sizeof(readCoilsRsp);
1399  part2_len = 10;
1400  input = readCoilsRsp;
1401 
1402  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT,
1403  input, input_len - part2_len);
1404  FAIL_IF(r != 1);
1405  FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH);
1406 
1407  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT,
1408  input, input_len);
1409  FAIL_IF(r != 0);
1410  FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH);
1411 
1412  FLOW_DESTROY(&f);
1414  StreamTcpFreeConfig(true);
1415  PASS;
1416 }
1417 
1418 /** \test Send Modbus invalid function. */
1419 static int ModbusParserTest19(void)
1420 {
1421  DetectEngineThreadCtx *det_ctx = NULL;
1422  Flow f;
1423  Packet *p = NULL;
1424  Signature *s = NULL;
1425  TcpSession ssn;
1426  ThreadVars tv;
1427 
1430 
1431  memset(&tv, 0, sizeof(ThreadVars));
1433  memset(&f, 0, sizeof(Flow));
1434  memset(&ssn, 0, sizeof(TcpSession));
1435 
1436  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1437 
1438  FLOW_INITIALIZE(&f);
1439  f.alproto = ALPROTO_MODBUS;
1440  f.protoctx = (void *)&ssn;
1441  f.proto = IPPROTO_TCP;
1442  f.alproto = ALPROTO_MODBUS;
1443  f.flags |= FLOW_IPV4;
1444 
1445  p->flow = &f;
1448 
1449  StreamTcpInitConfig(true);
1450 
1453 
1454  de_ctx->flags |= DE_QUIET;
1455  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1456  "(msg:\"Modbus invalid Function code\"; "
1457  "app-layer-event: "
1458  "modbus.invalid_function_code; "
1459  "sid:1;)");
1460  FAIL_IF_NULL(s);
1461 
1463  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
1464 
1465  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1466  STREAM_TOSERVER,
1467  invalidFunctionCode,
1468  sizeof(invalidFunctionCode));
1469  FAIL_IF_NOT(r == 0);
1470 
1471  ModbusState *modbus_state = f.alstate;
1472  FAIL_IF_NULL(modbus_state);
1473 
1474  /* do detect */
1475  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
1477 
1478  UTHFreePackets(&p, 1);
1479  FLOW_DESTROY(&f);
1480 
1482  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
1484  StreamTcpFreeConfig(true);
1486  PASS;
1487 }
1488 #endif /* UNITTESTS */
1489 
1491 #ifdef UNITTESTS
1492  UtRegisterTest("ModbusParserTest01 - Modbus Read Coils request",
1493  ModbusParserTest01);
1494  UtRegisterTest("ModbusParserTest02 - Modbus Write Multiple registers request",
1495  ModbusParserTest02);
1496  UtRegisterTest("ModbusParserTest03 - Modbus Read/Write Multiple registers request",
1497  ModbusParserTest03);
1498  UtRegisterTest("ModbusParserTest04 - Modbus Force Listen Only Mode request",
1499  ModbusParserTest04);
1500  UtRegisterTest("ModbusParserTest05 - Modbus invalid Protocol version",
1501  ModbusParserTest05);
1502  UtRegisterTest("ModbusParserTest06 - Modbus unsolicited response",
1503  ModbusParserTest06);
1504  UtRegisterTest("ModbusParserTest07 - Modbus invalid Length request",
1505  ModbusParserTest07);
1506  UtRegisterTest("ModbusParserTest08 - Modbus Exception code invalid",
1507  ModbusParserTest08);
1508  UtRegisterTest("ModbusParserTest09 - Modbus fragmentation - 1 ADU in 2 TCP packets",
1509  ModbusParserTest09);
1510  UtRegisterTest("ModbusParserTest10 - Modbus fragmentation - 2 ADU in 1 TCP packet",
1511  ModbusParserTest10);
1512  UtRegisterTest("ModbusParserTest11 - Modbus exceeded Length request",
1513  ModbusParserTest11);
1514  UtRegisterTest("ModbusParserTest12 - Modbus invalid PDU Length",
1515  ModbusParserTest12);
1516  UtRegisterTest("ModbusParserTest13 - Modbus Mask Write register request",
1517  ModbusParserTest13);
1518  UtRegisterTest("ModbusParserTest14 - Modbus Write single register request",
1519  ModbusParserTest14);
1520  UtRegisterTest("ModbusParserTest15 - Modbus invalid Mask Write register request",
1521  ModbusParserTest15);
1522  UtRegisterTest("ModbusParserTest16 - Modbus invalid Write single register request",
1523  ModbusParserTest16);
1524  UtRegisterTest("ModbusParserTest17 - Modbus stream depth",
1525  ModbusParserTest17);
1526  UtRegisterTest("ModbusParserTest18 - Modbus stream depth in 2 TCP packets",
1527  ModbusParserTest18);
1528  UtRegisterTest("ModbusParserTest19 - Modbus invalid Function code",
1529  ModbusParserTest19);
1530 #endif /* UNITTESTS */
1531 }
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:1268
flow-util.h
stream-tcp.h
HTPCfgRec_::response
HTPCfgDir response
Definition: app-layer-htp.h:116
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:370
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:348
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:933
DetectEngineCtxFree
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Definition: detect-engine.c:2634
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:225
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:2418
DetectEngineAppendSig
Signature * DetectEngineAppendSig(DetectEngineCtx *, const char *)
Parse and append a Signature into the Detection Engine Context signature list.
Definition: detect-parse.c:3447
Packet_::flowflags
uint8_t flowflags
Definition: decode.h:532
Flow_::protoctx
void * protoctx
Definition: flow.h:433
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:496
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:1245
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:3364
app-layer-parser.h
SCReturn
#define SCReturn
Definition: util-debug.h:283
AppLayerParserRegisterProtocolUnittests
void AppLayerParserRegisterProtocolUnittests(uint8_t ipproto, AppProto alproto, void(*RegisterUnittests)(void))
Definition: app-layer-parser.c:1844
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:1490
SigGroupBuild
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
Definition: detect-engine-build.c:2194
StatsThreadInit
void StatsThreadInit(StatsThreadContext *stats)
Definition: counters.c:1258
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:867
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:1277
suricata-common.h
HTPCfgRec_::request
HTPCfgDir request
Definition: app-layer-htp.h:115
DetectEngineThreadCtxDeinit
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data)
Definition: detect-engine.c:3601
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:471
Flow_::flags
uint32_t flags
Definition: flow.h:413
detect-parse.h
Signature_
Signature container.
Definition: detect.h:668
FLOW_PKT_ESTABLISHED
#define FLOW_PKT_ESTABLISHED
Definition: flow.h:227
DetectEngineCtxInit
DetectEngineCtx * DetectEngineCtxInit(void)
Definition: detect-engine.c:2595
DetectEngineCtx_::flags
uint8_t flags
Definition: detect.h:935
AppLayerParserThreadCtx_
Definition: app-layer-parser.c:60
TcpSession_
Definition: stream-tcp-private.h:283
Flow_::alproto
AppProto alproto
application level protocol
Definition: flow.h:442
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
ThreadVars_::stats
StatsThreadContext stats
Definition: threadvars.h:121
StatsThreadCleanup
void StatsThreadCleanup(StatsThreadContext *stats)
Definition: counters.c:1354
FLOW_DESTROY
#define FLOW_DESTROY(f)
Definition: flow-util.h:119
PKT_STREAM_EST
#define PKT_STREAM_EST
Definition: decode.h:1264
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