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));
382  memset(&f, 0, sizeof(Flow));
383  memset(&ssn, 0, sizeof(TcpSession));
384 
385  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
386 
387  FLOW_INITIALIZE(&f);
389  f.protoctx = (void *)&ssn;
390  f.proto = IPPROTO_TCP;
392  f.flags |= FLOW_IPV4;
393 
394  p->flow = &f;
397 
398  StreamTcpInitConfig(true);
399 
402 
403  de_ctx->flags |= DE_QUIET;
404  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
405  "(msg:\"Modbus Data mismatch\"; "
406  "app-layer-event: "
407  "modbus.value_mismatch; "
408  "sid:1;)");
409  FAIL_IF_NULL(s);
410 
412  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
413 
414  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
415  STREAM_TOSERVER,
416  readWriteMultipleRegistersReq,
417  sizeof(readWriteMultipleRegistersReq));
418  FAIL_IF_NOT(r == 0);
419 
420  ModbusState *modbus_state = f.alstate;
421  FAIL_IF_NULL(modbus_state);
422 
423  ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
424  FAIL_IF_NULL(request._0);
425 
426  FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 23);
427  FAIL_IF_NOT(SCModbusMessageGetRwMultreqReadAddress(&request) == 0x03);
428  FAIL_IF_NOT(SCModbusMessageGetRwMultreqReadQuantity(&request) == 6);
429  FAIL_IF_NOT(SCModbusMessageGetRwMultreqWriteAddress(&request) == 0x0E);
430  FAIL_IF_NOT(SCModbusMessageGetRwMultreqWriteQuantity(&request) == 3);
431 
432  size_t data_len;
433  uint8_t const *data = SCModbusMessageGetRwMultreqWriteData(&request, &data_len);
434  FAIL_IF_NOT(data_len == 6);
435  FAIL_IF_NOT(data[0] == 0x12);
436  FAIL_IF_NOT(data[1] == 0x34);
437  FAIL_IF_NOT(data[2] == 0x56);
438  FAIL_IF_NOT(data[3] == 0x78);
439  FAIL_IF_NOT(data[4] == 0x9A);
440  FAIL_IF_NOT(data[5] == 0xBC);
441 
443  STREAM_TOCLIENT, readWriteMultipleRegistersRsp,
444  sizeof(readWriteMultipleRegistersRsp));
445  FAIL_IF_NOT(r == 0);
446  FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
447 
448  /* do detect */
449  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
451 
452  UTHFreePackets(&p, 1);
453  FLOW_DESTROY(&f);
454 
456  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
458  StreamTcpFreeConfig(true);
460  PASS;
461 }
462 
463 /** \test Send Modbus Force Listen Only Mode request. */
464 static int ModbusParserTest04(void)
465 {
466  Flow f;
467  TcpSession ssn;
468 
471 
472  memset(&f, 0, sizeof(f));
473  memset(&ssn, 0, sizeof(ssn));
474 
475  FLOW_INITIALIZE(&f);
476  f.protoctx = (void *)&ssn;
477  f.proto = IPPROTO_TCP;
479 
480  StreamTcpInitConfig(true);
481 
482  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
483  STREAM_TOSERVER, forceListenOnlyMode,
484  sizeof(forceListenOnlyMode));
485  FAIL_IF_NOT(r == 0);
486 
487  ModbusState *modbus_state = f.alstate;
488  FAIL_IF_NULL(modbus_state);
489 
490  ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
491  FAIL_IF_NULL(request._0);
492  FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 8);
493  FAIL_IF_NOT(SCModbusMessageGetSubfunction(&request) == 4);
494 
496  StreamTcpFreeConfig(true);
497  FLOW_DESTROY(&f);
498  PASS;
499 }
500 
501 /** \test Send Modbus invalid Protocol version in request. */
502 static int ModbusParserTest05(void)
503 {
504  DetectEngineThreadCtx *det_ctx = NULL;
505  Flow f;
506  Packet *p = NULL;
507  Signature *s = NULL;
508  TcpSession ssn;
509  ThreadVars tv;
510 
513 
514  memset(&tv, 0, sizeof(ThreadVars));
515  memset(&f, 0, sizeof(Flow));
516  memset(&ssn, 0, sizeof(TcpSession));
517 
518  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
519 
520  FLOW_INITIALIZE(&f);
522  f.protoctx = (void *)&ssn;
523  f.proto = IPPROTO_TCP;
525  f.flags |= FLOW_IPV4;
526 
527  p->flow = &f;
530 
531  StreamTcpInitConfig(true);
532 
535 
536  de_ctx->flags |= DE_QUIET;
537  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
538  "(msg:\"Modbus invalid Protocol version\"; "
539  "app-layer-event: "
540  "modbus.invalid_protocol_id; "
541  "sid:1;)");
542  FAIL_IF_NULL(s);
543 
545  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
546 
547  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
548  STREAM_TOSERVER, invalidProtocolIdReq,
549  sizeof(invalidProtocolIdReq));
550  FAIL_IF_NOT(r == 0);
551 
552  ModbusState *modbus_state = f.alstate;
553  FAIL_IF_NULL(modbus_state);
554 
555  /* do detect */
556  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
558 
559  UTHFreePackets(&p, 1);
560  FLOW_DESTROY(&f);
561 
563  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
565  StreamTcpFreeConfig(true);
567  PASS;
568 }
569 
570 /** \test Send Modbus unsolicited response. */
571 static int ModbusParserTest06(void)
572 {
573  DetectEngineThreadCtx *det_ctx = NULL;
574  Flow f;
575  Packet *p = NULL;
576  Signature *s = NULL;
577  TcpSession ssn;
578  ThreadVars tv;
579 
582 
583  memset(&tv, 0, sizeof(ThreadVars));
584  memset(&f, 0, sizeof(Flow));
585  memset(&ssn, 0, sizeof(TcpSession));
586 
587  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
588 
589  FLOW_INITIALIZE(&f);
591  f.protoctx = (void *)&ssn;
592  f.proto = IPPROTO_TCP;
594  f.flags |= FLOW_IPV4;
595 
596  p->flow = &f;
599 
600  StreamTcpInitConfig(true);
601 
604 
605  de_ctx->flags |= DE_QUIET;
606  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
607  "(msg:\"Modbus unsolicited response\"; "
608  "app-layer-event: "
609  "modbus.unsolicited_response; "
610  "sid:1;)");
611  FAIL_IF_NULL(s);
612 
614  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
615 
616  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
617  STREAM_TOCLIENT, readCoilsRsp,
618  sizeof(readCoilsRsp));
619  FAIL_IF_NOT(r == 0);
620 
621  ModbusState *modbus_state = f.alstate;
622  FAIL_IF_NULL(modbus_state);
623 
624  /* do detect */
625  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
627 
628  UTHFreePackets(&p, 1);
629  FLOW_DESTROY(&f);
630 
632  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
634  StreamTcpFreeConfig(true);
636  PASS;
637 }
638 
639 /** \test Send Modbus invalid Length request. */
640 static int ModbusParserTest07(void)
641 {
642  DetectEngineThreadCtx *det_ctx = NULL;
643  Flow f;
644  Packet *p = NULL;
645  Signature *s = NULL;
646  TcpSession ssn;
647  ThreadVars tv;
648 
651 
652  memset(&tv, 0, sizeof(ThreadVars));
653  memset(&f, 0, sizeof(Flow));
654  memset(&ssn, 0, sizeof(TcpSession));
655 
656  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
657 
658  FLOW_INITIALIZE(&f);
660  f.protoctx = (void *)&ssn;
661  f.proto = IPPROTO_TCP;
663  f.flags |= FLOW_IPV4;
664 
665  p->flow = &f;
668 
669  StreamTcpInitConfig(true);
670 
673 
674  de_ctx->flags |= DE_QUIET;
675  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
676  "(msg:\"Modbus invalid Length\"; "
677  "app-layer-event: "
678  "modbus.invalid_length; "
679  "sid:1;)");
680  FAIL_IF_NULL(s);
681 
683  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
684 
685  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
686  STREAM_TOSERVER,
687  invalidLengthWriteMultipleRegistersReq,
688  sizeof(invalidLengthWriteMultipleRegistersReq));
689  FAIL_IF_NOT(r == 1);
690 
691  ModbusState *modbus_state = f.alstate;
692  FAIL_IF_NULL(modbus_state);
693 
694  /* do detect */
695  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
697 
698  UTHFreePackets(&p, 1);
699  FLOW_DESTROY(&f);
700 
702  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
704  StreamTcpFreeConfig(true);
706  PASS;
707 }
708 
709 /** \test Send Modbus Read Coils request and error response with Exception code invalid. */
710 static int ModbusParserTest08(void)
711 {
712  DetectEngineThreadCtx *det_ctx = NULL;
713  Flow f;
714  Packet *p = NULL;
715  Signature *s = NULL;
716  TcpSession ssn;
717  ThreadVars tv;
718 
721 
722  memset(&tv, 0, sizeof(ThreadVars));
723  memset(&f, 0, sizeof(Flow));
724  memset(&ssn, 0, sizeof(TcpSession));
725 
726  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
727 
728  FLOW_INITIALIZE(&f);
730  f.protoctx = (void *)&ssn;
731  f.proto = IPPROTO_TCP;
733  f.flags |= FLOW_IPV4;
734 
735  p->flow = &f;
738 
739  StreamTcpInitConfig(true);
740 
743 
744  de_ctx->flags |= DE_QUIET;
745  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
746  "(msg:\"Modbus Exception code invalid\"; "
747  "app-layer-event: "
748  "modbus.invalid_exception_code; "
749  "sid:1;)");
750  FAIL_IF_NULL(s);
751 
753  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
754 
755  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
756  STREAM_TOSERVER, readCoilsReq,
757  sizeof(readCoilsReq));
758  FAIL_IF_NOT(r == 0);
759 
760  ModbusState *modbus_state = f.alstate;
761  FAIL_IF_NULL(modbus_state);
762 
763  ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
764  FAIL_IF_NULL(request._0);
765  FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 1);
766  FAIL_IF_NOT(SCModbusMessageGetReadRequestAddress(&request) == 0x7890);
767  FAIL_IF_NOT(SCModbusMessageGetReadRequestQuantity(&request) == 19);
768 
770  STREAM_TOCLIENT, readCoilsErrorRsp,
771  sizeof(readCoilsErrorRsp));
772  FAIL_IF_NOT(r == 0);
773  FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
774 
775  /* do detect */
776  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
778 
779  UTHFreePackets(&p, 1);
780  FLOW_DESTROY(&f);
781 
783  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
785  StreamTcpFreeConfig(true);
787  PASS;
788 }
789 
790 /** \test Modbus fragmentation - 1 ADU over 2 TCP packets. */
791 static int ModbusParserTest09(void) {
793  Flow f;
794  TcpSession ssn;
795 
796  uint32_t input_len = sizeof(readCoilsReq), part2_len = 3;
797  uint8_t *input = readCoilsReq;
798 
800 
801  memset(&f, 0, sizeof(f));
802  memset(&ssn, 0, sizeof(ssn));
803 
804  FLOW_INITIALIZE(&f);
805  f.protoctx = (void *)&ssn;
806  f.proto = IPPROTO_TCP;
808 
809  StreamTcpInitConfig(true);
810 
811  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
812  STREAM_TOSERVER, input, input_len - part2_len);
813  FAIL_IF_NOT(r == 1);
814 
816  STREAM_TOSERVER, input, input_len);
817  FAIL_IF_NOT(r == 0);
818 
819  ModbusState *modbus_state = f.alstate;
820  FAIL_IF_NULL(modbus_state);
821 
822  ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
823  FAIL_IF_NULL(request._0);
824  FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 1);
825  FAIL_IF_NOT(SCModbusMessageGetReadRequestAddress(&request) == 0x7890);
826  FAIL_IF_NOT(SCModbusMessageGetReadRequestQuantity(&request) == 19);
827 
828  input_len = sizeof(readCoilsRsp);
829  part2_len = 10;
830  input = readCoilsRsp;
831 
833  STREAM_TOCLIENT, input, input_len - part2_len);
834  FAIL_IF_NOT(r == 1);
835 
837  STREAM_TOCLIENT, input, input_len);
838  FAIL_IF_NOT(r == 0);
839  FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
840 
842  StreamTcpFreeConfig(true);
843  FLOW_DESTROY(&f);
844  PASS;
845 }
846 
847 /** \test Modbus fragmentation - 2 ADU in 1 TCP packet. */
848 static int ModbusParserTest10(void) {
849  uint32_t input_len = sizeof(readCoilsReq) + sizeof(writeMultipleRegistersReq);
850  uint8_t *input, *ptr;
851 
852  Flow f;
853  TcpSession ssn;
854 
857 
858  input = (uint8_t *) SCMalloc (input_len * sizeof(uint8_t));
859  FAIL_IF_NULL(input);
860 
861  memcpy(input, readCoilsReq, sizeof(readCoilsReq));
862  memcpy(input + sizeof(readCoilsReq), writeMultipleRegistersReq, sizeof(writeMultipleRegistersReq));
863 
864  memset(&f, 0, sizeof(f));
865  memset(&ssn, 0, sizeof(ssn));
866 
867  FLOW_INITIALIZE(&f);
868  f.protoctx = (void *)&ssn;
869  f.proto = IPPROTO_TCP;
871 
872  StreamTcpInitConfig(true);
873 
874  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
875  STREAM_TOSERVER, input, input_len);
876  FAIL_IF_NOT(r == 0);
877 
878  ModbusState *modbus_state = f.alstate;
879  FAIL_IF_NULL(modbus_state);
880  FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 2);
881 
882  ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 1);
883  FAIL_IF_NULL(request._0);
884  FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 16);
885  FAIL_IF_NOT(SCModbusMessageGetWriteMultreqAddress(&request) == 0x01);
886  FAIL_IF_NOT(SCModbusMessageGetWriteMultreqQuantity(&request) == 2);
887 
888  size_t data_len;
889  uint8_t const *data = SCModbusMessageGetWriteMultreqData(&request, &data_len);
890  FAIL_IF_NOT(data_len == 4);
891  FAIL_IF_NOT(data[0] == 0x00);
892  FAIL_IF_NOT(data[1] == 0x0A);
893  FAIL_IF_NOT(data[2] == 0x01);
894  FAIL_IF_NOT(data[3] == 0x02);
895 
896  input_len = sizeof(readCoilsRsp) + sizeof(writeMultipleRegistersRsp);
897 
898  ptr = (uint8_t *) SCRealloc (input, input_len * sizeof(uint8_t));
899  FAIL_IF_NULL(ptr);
900  input = ptr;
901 
902  memcpy(input, readCoilsRsp, sizeof(readCoilsRsp));
903  memcpy(input + sizeof(readCoilsRsp), writeMultipleRegistersRsp, sizeof(writeMultipleRegistersRsp));
904 
905  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, input, input_len);
906  FAIL_IF_NOT(r == 0);
907 
908  FLOW_DESTROY(&f);
909  SCFree(input);
911  StreamTcpFreeConfig(true);
912  PASS;
913 }
914 
915 /** \test Send Modbus exceed Length request. */
916 static int ModbusParserTest11(void)
917 {
918  DetectEngineThreadCtx *det_ctx = NULL;
919  Flow f;
920  TcpSession ssn;
921  ThreadVars tv;
922 
923  size_t input_len = 65536;
924  uint8_t *input = SCCalloc(1, input_len);
925  FAIL_IF(input == NULL);
926 
927  memcpy(input, exceededLengthWriteMultipleRegistersReq,
928  sizeof(exceededLengthWriteMultipleRegistersReq));
929 
931  FAIL_IF(alp_tctx == NULL);
932 
933  memset(&tv, 0, sizeof(ThreadVars));
934  memset(&f, 0, sizeof(Flow));
935  memset(&ssn, 0, sizeof(TcpSession));
936 
937  Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
938 
939  FLOW_INITIALIZE(&f);
941  f.protoctx = (void *)&ssn;
942  f.proto = IPPROTO_TCP;
944  f.flags |= FLOW_IPV4;
945 
946  p->flow = &f;
949 
950  StreamTcpInitConfig(true);
951 
954 
955  de_ctx->flags |= DE_QUIET;
956  Signature *s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
957  "(msg:\"Modbus invalid Length\"; "
958  "app-layer-event: "
959  "modbus.invalid_length; "
960  "sid:1;)");
961  FAIL_IF_NULL(s);
962 
964  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
965 
966  int r = AppLayerParserParse(
967  NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, input, input_len);
968  FAIL_IF_NOT(r == 0);
969 
970  ModbusState *modbus_state = f.alstate;
971  FAIL_IF_NULL(modbus_state);
972 
973  /* do detect */
974  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
976 
977  UTHFreePackets(&p, 1);
978  FLOW_DESTROY(&f);
979 
981  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
983  StreamTcpFreeConfig(true);
985  SCFree(input);
986  PASS;
987 }
988 
989 /** \test Send Modbus invalid PDU Length. */
990 static int ModbusParserTest12(void)
991 {
992  DetectEngineThreadCtx *det_ctx = NULL;
993  Flow f;
994  Packet *p = NULL;
995  TcpSession ssn;
996  ThreadVars tv;
997 
1000 
1001  memset(&tv, 0, sizeof(ThreadVars));
1002  memset(&f, 0, sizeof(Flow));
1003  memset(&ssn, 0, sizeof(TcpSession));
1004 
1005  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1006 
1007  FLOW_INITIALIZE(&f);
1008  f.alproto = ALPROTO_MODBUS;
1009  f.protoctx = (void *)&ssn;
1010  f.proto = IPPROTO_TCP;
1011  f.alproto = ALPROTO_MODBUS;
1012  f.flags |= FLOW_IPV4;
1013 
1014  p->flow = &f;
1017 
1018  StreamTcpInitConfig(true);
1019 
1022 
1023  de_ctx->flags |= DE_QUIET;
1024  Signature *s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1025  "(msg:\"Modbus invalid Length\"; "
1026  "app-layer-event: "
1027  "modbus.invalid_length; "
1028  "sid:1;)");
1029  FAIL_IF_NULL(s);
1030 
1032  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
1033 
1034  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1035  STREAM_TOSERVER,
1036  invalidLengthPDUWriteMultipleRegistersReq,
1037  sizeof(invalidLengthPDUWriteMultipleRegistersReq));
1038  FAIL_IF_NOT(r == 0);
1039 
1040  ModbusState *modbus_state = f.alstate;
1041  FAIL_IF_NULL(modbus_state);
1042 
1043  /* do detect */
1044  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
1046 
1047  UTHFreePackets(&p, 1);
1048  FLOW_DESTROY(&f);
1049 
1051  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
1053  StreamTcpFreeConfig(true);
1055  PASS;
1056 }
1057 
1058 /** \test Send Modbus Mask Write register request/response. */
1059 static int ModbusParserTest13(void)
1060 {
1061  Flow f;
1062  TcpSession ssn;
1063 
1066 
1067  memset(&f, 0, sizeof(f));
1068  memset(&ssn, 0, sizeof(ssn));
1069 
1070  FLOW_INITIALIZE(&f);
1071  f.protoctx = (void *)&ssn;
1072  f.proto = IPPROTO_TCP;
1073  f.alproto = ALPROTO_MODBUS;
1074 
1075  StreamTcpInitConfig(true);
1076 
1077  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1078  STREAM_TOSERVER, maskWriteRegisterReq,
1079  sizeof(maskWriteRegisterReq));
1080  FAIL_IF_NOT(r == 0);
1081 
1082  ModbusState *modbus_state = f.alstate;
1083  FAIL_IF_NULL(modbus_state);
1084 
1085  ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
1086  FAIL_IF_NULL(request._0);
1087  FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 22);
1088  FAIL_IF_NOT(SCModbusMessageGetAndMask(&request) == 0x00F2);
1089  FAIL_IF_NOT(SCModbusMessageGetOrMask(&request) == 0x0025);
1090 
1092  STREAM_TOCLIENT, maskWriteRegisterRsp,
1093  sizeof(maskWriteRegisterRsp));
1094  FAIL_IF_NOT(r == 0);
1095  FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
1096 
1098  StreamTcpFreeConfig(true);
1099  FLOW_DESTROY(&f);
1100  PASS;
1101 }
1102 
1103 /** \test Send Modbus Write single register request/response. */
1104 static int ModbusParserTest14(void)
1105 {
1106  Flow f;
1107  TcpSession ssn;
1108 
1111 
1112  memset(&f, 0, sizeof(f));
1113  memset(&ssn, 0, sizeof(ssn));
1114 
1115  FLOW_INITIALIZE(&f);
1116  f.protoctx = (void *)&ssn;
1117  f.proto = IPPROTO_TCP;
1118  f.alproto = ALPROTO_MODBUS;
1119 
1120  StreamTcpInitConfig(true);
1121 
1122  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1123  STREAM_TOSERVER, writeSingleRegisterReq,
1124  sizeof(writeSingleRegisterReq));
1125  FAIL_IF_NOT(r == 0);
1126 
1127  ModbusState *modbus_state = f.alstate;
1128  FAIL_IF_NULL(modbus_state);
1129 
1130  ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
1131  FAIL_IF_NULL(request._0);
1132  FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 6);
1133  FAIL_IF_NOT(SCModbusMessageGetWriteAddress(&request) == 0x0001);
1134  FAIL_IF_NOT(SCModbusMessageGetWriteData(&request) == 0x0003);
1135 
1137  STREAM_TOCLIENT, writeSingleRegisterRsp,
1138  sizeof(writeSingleRegisterRsp));
1139  FAIL_IF_NOT(r == 0);
1140  FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
1141 
1142  FLOW_DESTROY(&f);
1144  StreamTcpFreeConfig(true);
1145  PASS;
1146 }
1147 
1148 /** \test Send invalid Modbus Mask Write register request. */
1149 static int ModbusParserTest15(void)
1150 {
1151  DetectEngineThreadCtx *det_ctx = NULL;
1152  Flow f;
1153  Packet *p = NULL;
1154  Signature *s = NULL;
1155  TcpSession ssn;
1156  ThreadVars tv;
1157 
1160 
1161  memset(&tv, 0, sizeof(ThreadVars));
1162  memset(&f, 0, sizeof(f));
1163  memset(&ssn, 0, sizeof(ssn));
1164 
1165  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1166 
1167  FLOW_INITIALIZE(&f);
1168  f.alproto = ALPROTO_MODBUS;
1169  f.protoctx = (void *)&ssn;
1170  f.proto = IPPROTO_TCP;
1171  f.alproto = ALPROTO_MODBUS;
1172  f.flags |= FLOW_IPV4;
1173 
1174  p->flow = &f;
1177 
1178  StreamTcpInitConfig(true);
1179 
1182 
1183  de_ctx->flags |= DE_QUIET;
1184  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1185  "(msg:\"Modbus invalid Length\"; "
1186  "app-layer-event: "
1187  "modbus.invalid_length; "
1188  "sid:1;)");
1189  FAIL_IF_NULL(s);
1190 
1192  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
1193 
1194  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1195  STREAM_TOSERVER, invalidMaskWriteRegisterReq,
1196  sizeof(invalidMaskWriteRegisterReq));
1197  FAIL_IF_NOT(r == 0);
1198 
1199  ModbusState *modbus_state = f.alstate;
1200  FAIL_IF_NULL(modbus_state);
1201 
1202  ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
1203  FAIL_IF_NULL(request._0);
1204  FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 22);
1205 
1206  /* do detect */
1207  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
1209 
1211  STREAM_TOCLIENT, maskWriteRegisterRsp,
1212  sizeof(maskWriteRegisterRsp));
1213  FAIL_IF_NOT(r == 0);
1214  FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
1215  ModbusMessage response = SCModbusStateGetTxResponse(modbus_state, 0);
1216  FAIL_IF_NULL(response._0);
1217  FAIL_IF_NOT(SCModbusMessageGetFunction(&response) == 22);
1218 
1219  UTHFreePackets(&p, 1);
1220  FLOW_DESTROY(&f);
1221 
1223  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
1225  StreamTcpFreeConfig(true);
1227  PASS;
1228 }
1229 
1230 /** \test Send invalid Modbus Mask Write register request. */
1231 static int ModbusParserTest16(void)
1232 {
1233  DetectEngineThreadCtx *det_ctx = NULL;
1234  Flow f;
1235  Packet *p = NULL;
1236  Signature *s = NULL;
1237  TcpSession ssn;
1238  ThreadVars tv;
1239 
1242 
1243  memset(&tv, 0, sizeof(ThreadVars));
1244  memset(&f, 0, sizeof(f));
1245  memset(&ssn, 0, sizeof(ssn));
1246 
1247  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1248 
1249  FLOW_INITIALIZE(&f);
1250  f.alproto = ALPROTO_MODBUS;
1251  f.protoctx = (void *)&ssn;
1252  f.proto = IPPROTO_TCP;
1253  f.alproto = ALPROTO_MODBUS;
1254  f.flags |= FLOW_IPV4;
1255 
1256  p->flow = &f;
1259 
1260  StreamTcpInitConfig(true);
1261 
1264 
1265  de_ctx->flags |= DE_QUIET;
1266  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1267  "(msg:\"Modbus invalid Length\"; "
1268  "app-layer-event: "
1269  "modbus.invalid_length; "
1270  "sid:1;)");
1271  FAIL_IF_NULL(s);
1272 
1274  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
1275 
1276  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1277  STREAM_TOSERVER,
1278  invalidWriteSingleRegisterReq,
1279  sizeof(invalidWriteSingleRegisterReq));
1280  FAIL_IF_NOT(r == 0);
1281 
1282  ModbusState *modbus_state = f.alstate;
1283  FAIL_IF_NULL(modbus_state);
1284 
1285  ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
1286  FAIL_IF_NULL(request._0);
1287  FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 6);
1288  size_t data_len;
1289  const uint8_t *data = SCModbusMessageGetBytevecData(&request, &data_len);
1290  FAIL_IF_NOT(data_len == 2);
1291  FAIL_IF_NOT(data[0] == 0x00);
1292  FAIL_IF_NOT(data[1] == 0x01);
1293 
1294  /* do detect */
1295  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
1297 
1299  STREAM_TOCLIENT, writeSingleRegisterRsp,
1300  sizeof(writeSingleRegisterRsp));
1301  FAIL_IF_NOT(r == 0);
1302 
1303  FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
1304  ModbusMessage response = SCModbusStateGetTxResponse(modbus_state, 0);
1305  FAIL_IF_NULL(response._0);
1306  FAIL_IF_NOT(SCModbusMessageGetFunction(&response) == 6);
1307  FAIL_IF_NOT(SCModbusMessageGetWriteAddress(&response) == 0x0001);
1308 
1309  UTHFreePackets(&p, 1);
1310  FLOW_DESTROY(&f);
1311 
1313  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
1315  StreamTcpFreeConfig(true);
1317  PASS;
1318 }
1319 
1320 /** \test Checks if stream_depth is correct */
1321 static int ModbusParserTest17(void)
1322 {
1323  Flow f;
1324  TcpSession ssn;
1325 
1328 
1329  memset(&f, 0, sizeof(f));
1330  memset(&ssn, 0, sizeof(ssn));
1331 
1332  FLOW_INITIALIZE(&f);
1333  f.protoctx = (void *)&ssn;
1334  f.proto = IPPROTO_TCP;
1335  f.alproto = ALPROTO_MODBUS;
1336 
1337  StreamTcpInitConfig(true);
1338 
1339  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER,
1340  readCoilsReq, sizeof(readCoilsReq));
1341  FAIL_IF(r != 0);
1342  FAIL_IF(f.alstate == NULL);
1343  FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH);
1344 
1345  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT,
1346  readCoilsRsp, sizeof(readCoilsRsp));
1347  FAIL_IF(r != 0);
1348  FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH);
1349 
1350  FLOW_DESTROY(&f);
1352  StreamTcpFreeConfig(true);
1353  PASS;
1354 }
1355 
1356 /*/ \test Checks if stream depth is correct over 2 TCP packets */
1357 static int ModbusParserTest18(void)
1358 {
1359  Flow f;
1360  TcpSession ssn;
1361 
1362  uint32_t input_len = sizeof(readCoilsReq), part2_len = 3;
1363  uint8_t *input = readCoilsReq;
1364 
1367 
1368  memset(&f, 0, sizeof(f));
1369  memset(&ssn, 0, sizeof(ssn));
1370 
1371  FLOW_INITIALIZE(&f);
1372  f.protoctx = (void *)&ssn;
1373  f.proto = IPPROTO_TCP;
1374  f.alproto = ALPROTO_MODBUS;
1375 
1376  StreamTcpInitConfig(true);
1377 
1378  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER,
1379  input, input_len - part2_len);
1380  FAIL_IF(r != 1);
1381  FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH);
1382 
1383  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER,
1384  input, input_len);
1385  FAIL_IF(r != 0);
1386  FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH);
1387  FAIL_IF(f.alstate == NULL);
1388 
1389  input_len = sizeof(readCoilsRsp);
1390  part2_len = 10;
1391  input = readCoilsRsp;
1392 
1393  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT,
1394  input, input_len - part2_len);
1395  FAIL_IF(r != 1);
1396  FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH);
1397 
1398  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT,
1399  input, input_len);
1400  FAIL_IF(r != 0);
1401  FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH);
1402 
1403  FLOW_DESTROY(&f);
1405  StreamTcpFreeConfig(true);
1406  PASS;
1407 }
1408 
1409 /** \test Send Modbus invalid function. */
1410 static int ModbusParserTest19(void)
1411 {
1412  DetectEngineThreadCtx *det_ctx = NULL;
1413  Flow f;
1414  Packet *p = NULL;
1415  Signature *s = NULL;
1416  TcpSession ssn;
1417  ThreadVars tv;
1418 
1421 
1422  memset(&tv, 0, sizeof(ThreadVars));
1423  memset(&f, 0, sizeof(Flow));
1424  memset(&ssn, 0, sizeof(TcpSession));
1425 
1426  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1427 
1428  FLOW_INITIALIZE(&f);
1429  f.alproto = ALPROTO_MODBUS;
1430  f.protoctx = (void *)&ssn;
1431  f.proto = IPPROTO_TCP;
1432  f.alproto = ALPROTO_MODBUS;
1433  f.flags |= FLOW_IPV4;
1434 
1435  p->flow = &f;
1438 
1439  StreamTcpInitConfig(true);
1440 
1443 
1444  de_ctx->flags |= DE_QUIET;
1445  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1446  "(msg:\"Modbus invalid Function code\"; "
1447  "app-layer-event: "
1448  "modbus.invalid_function_code; "
1449  "sid:1;)");
1450  FAIL_IF_NULL(s);
1451 
1453  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
1454 
1455  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1456  STREAM_TOSERVER,
1457  invalidFunctionCode,
1458  sizeof(invalidFunctionCode));
1459  FAIL_IF_NOT(r == 0);
1460 
1461  ModbusState *modbus_state = f.alstate;
1462  FAIL_IF_NULL(modbus_state);
1463 
1464  /* do detect */
1465  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
1467 
1468  UTHFreePackets(&p, 1);
1469  FLOW_DESTROY(&f);
1470 
1472  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
1474  StreamTcpFreeConfig(true);
1476  PASS;
1477 }
1478 #endif /* UNITTESTS */
1479 
1481 #ifdef UNITTESTS
1482  UtRegisterTest("ModbusParserTest01 - Modbus Read Coils request",
1483  ModbusParserTest01);
1484  UtRegisterTest("ModbusParserTest02 - Modbus Write Multiple registers request",
1485  ModbusParserTest02);
1486  UtRegisterTest("ModbusParserTest03 - Modbus Read/Write Multiple registers request",
1487  ModbusParserTest03);
1488  UtRegisterTest("ModbusParserTest04 - Modbus Force Listen Only Mode request",
1489  ModbusParserTest04);
1490  UtRegisterTest("ModbusParserTest05 - Modbus invalid Protocol version",
1491  ModbusParserTest05);
1492  UtRegisterTest("ModbusParserTest06 - Modbus unsolicited response",
1493  ModbusParserTest06);
1494  UtRegisterTest("ModbusParserTest07 - Modbus invalid Length request",
1495  ModbusParserTest07);
1496  UtRegisterTest("ModbusParserTest08 - Modbus Exception code invalid",
1497  ModbusParserTest08);
1498  UtRegisterTest("ModbusParserTest09 - Modbus fragmentation - 1 ADU in 2 TCP packets",
1499  ModbusParserTest09);
1500  UtRegisterTest("ModbusParserTest10 - Modbus fragmentation - 2 ADU in 1 TCP packet",
1501  ModbusParserTest10);
1502  UtRegisterTest("ModbusParserTest11 - Modbus exceeded Length request",
1503  ModbusParserTest11);
1504  UtRegisterTest("ModbusParserTest12 - Modbus invalid PDU Length",
1505  ModbusParserTest12);
1506  UtRegisterTest("ModbusParserTest13 - Modbus Mask Write register request",
1507  ModbusParserTest13);
1508  UtRegisterTest("ModbusParserTest14 - Modbus Write single register request",
1509  ModbusParserTest14);
1510  UtRegisterTest("ModbusParserTest15 - Modbus invalid Mask Write register request",
1511  ModbusParserTest15);
1512  UtRegisterTest("ModbusParserTest16 - Modbus invalid Write single register request",
1513  ModbusParserTest16);
1514  UtRegisterTest("ModbusParserTest17 - Modbus stream depth",
1515  ModbusParserTest17);
1516  UtRegisterTest("ModbusParserTest18 - Modbus stream depth in 2 TCP packets",
1517  ModbusParserTest18);
1518  UtRegisterTest("ModbusParserTest19 - Modbus invalid Function code",
1519  ModbusParserTest19);
1520 #endif /* UNITTESTS */
1521 }
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:932
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:2416
DetectEngineAppendSig
Signature * DetectEngineAppendSig(DetectEngineCtx *, const char *)
Parse and append a Signature into the Detection Engine Context signature list.
Definition: detect-parse.c:3439
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: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: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: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:1480
SigGroupBuild
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
Definition: detect-engine-build.c:2194
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
HTPCfgRec_::request
HTPCfgDir request
Definition: app-layer-htp.h:115
DetectEngineThreadCtxDeinit
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data)
Definition: detect-engine.c:3596
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: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:442
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
StatsThreadCleanup
void StatsThreadCleanup(ThreadVars *tv)
Definition: counters.c:1324
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