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-modbus.h"
42 #include "rust.h"
43 
44 #ifdef UNITTESTS
45 
46 #include "app-layer-parser.h"
47 #include "app-layer-protos.h"
48 #include "counters.h"
49 #include "decode.h"
50 #include "flow.h"
51 #include "threadvars.h"
52 #include "detect.h"
53 #include "detect-engine.h"
54 #include "detect-parse.h"
55 #include "detect-engine-build.h"
56 #include "detect-engine-alert.h"
57 
58 #include "flow-util.h"
59 
60 #include "util-unittest-helper.h"
61 
62 #include "stream-tcp.h"
63 #include "stream-tcp-private.h"
64 #endif
65 
66 void ModbusParserRegisterTests(void);
67 
68 /**
69  * \brief Function to register the Modbus protocol parser
70  */
72 {
73  SCRegisterModbusParser();
74 #ifdef UNITTESTS
76 #endif
77 
78  SCReturn;
79 }
80 
81 /* UNITTESTS */
82 #ifdef UNITTESTS
83 
84 /* Modbus default stream reassembly depth */
85 #define MODBUS_CONFIG_DEFAULT_STREAM_DEPTH 0
86 
87 /* Modbus Application Protocol Specification V1.1b3 6.1: Read Coils */
88 static uint8_t invalidFunctionCode[] = {
89  /* Transaction ID */ 0x00, 0x00,
90  /* Protocol ID */ 0x00, 0x00,
91  /* Length */ 0x00, 0x02,
92  /* Unit ID */ 0x00,
93  /* Function code */ 0x00
94 };
95 
96 /* Modbus Application Protocol Specification V1.1b3 6.1: Read Coils */
97 /* Example of a request to read discrete outputs 20-38 */
98 static uint8_t readCoilsReq[] = {/* Transaction ID */ 0x00, 0x00,
99  /* Protocol ID */ 0x00, 0x00,
100  /* Length */ 0x00, 0x06,
101  /* Unit ID */ 0x00,
102  /* Function code */ 0x01,
103  /* Starting Address */ 0x78, 0x90,
104  /* Quantity of coils */ 0x00, 0x13 };
105 
106 static uint8_t readCoilsRsp[] = {/* Transaction ID */ 0x00, 0x00,
107  /* Protocol ID */ 0x00, 0x00,
108  /* Length */ 0x00, 0x06,
109  /* Unit ID */ 0x00,
110  /* Function code */ 0x01,
111  /* Byte count */ 0x03,
112  /* Coil Status */ 0xCD, 0x6B, 0x05 };
113 
114 static uint8_t readCoilsErrorRsp[] = {
115  /* Transaction ID */ 0x00, 0x00,
116  /* Protocol ID */ 0x00, 0x00,
117  /* Length */ 0x00, 0x03,
118  /* Unit ID */ 0x00,
119  /* Function code */ 0x81,
120  /* Invalid Exception code: should trigger the InvalidExceptionCode ModbusEvent */
121  0xFF
122 };
123 
124 /* Modbus Application Protocol Specification V1.1b3 6.6: Write Single register */
125 /* Example of a request to write register 2 to 00 03 hex */
126 static uint8_t writeSingleRegisterReq[] = {/* Transaction ID */ 0x00, 0x0A,
127  /* Protocol ID */ 0x00, 0x00,
128  /* Length */ 0x00, 0x06,
129  /* Unit ID */ 0x00,
130  /* Function code */ 0x06,
131  /* Register Address */ 0x00, 0x01,
132  /* Register Value */ 0x00, 0x03};
133 
134 static uint8_t invalidWriteSingleRegisterReq[] = {/* Transaction ID */ 0x00, 0x0A,
135  /* Protocol ID */ 0x00, 0x00,
136  /* Length */ 0x00, 0x04,
137  /* Unit ID */ 0x00,
138  /* Function code */ 0x06,
139  /* Register Address */ 0x00, 0x01};
140 
141 static uint8_t writeSingleRegisterRsp[] = {/* Transaction ID */ 0x00, 0x0A,
142  /* Protocol ID */ 0x00, 0x00,
143  /* Length */ 0x00, 0x06,
144  /* Unit ID */ 0x00,
145  /* Function code */ 0x06,
146  /* Register Address */ 0x00, 0x01,
147  /* Register Value */ 0x00, 0x03};
148 
149 /* Modbus Application Protocol Specification V1.1b3 6.12: Write Multiple registers */
150 /* Example of a request to write two registers starting at 2 to 00 0A and 01 02 hex */
151 static uint8_t writeMultipleRegistersReq[] = {/* Transaction ID */ 0x00, 0x0A,
152  /* Protocol ID */ 0x00, 0x00,
153  /* Length */ 0x00, 0x0B,
154  /* Unit ID */ 0x00,
155  /* Function code */ 0x10,
156  /* Starting Address */ 0x00, 0x01,
157  /* Quantity of Registers */ 0x00, 0x02,
158  /* Byte count */ 0x04,
159  /* Registers Value */ 0x00, 0x0A,
160  0x01, 0x02};
161 
162 static uint8_t writeMultipleRegistersRsp[] = {/* Transaction ID */ 0x00, 0x0A,
163  /* Protocol ID */ 0x00, 0x00,
164  /* Length */ 0x00, 0x06,
165  /* Unit ID */ 0x00,
166  /* Function code */ 0x10,
167  /* Starting Address */ 0x00, 0x01,
168  /* Quantity of Registers */ 0x00, 0x02};
169 
170 /* Modbus Application Protocol Specification V1.1b3 6.16: Mask Write Register */
171 /* Example of a request to mask write to register 5 */
172 static uint8_t maskWriteRegisterReq[] = {/* Transaction ID */ 0x00, 0x0A,
173  /* Protocol ID */ 0x00, 0x00,
174  /* Length */ 0x00, 0x08,
175  /* Unit ID */ 0x00,
176  /* Function code */ 0x16,
177  /* Reference Address */ 0x00, 0x04,
178  /* And_Mask */ 0x00, 0xF2,
179  /* Or_Mask */ 0x00, 0x25};
180 
181 static uint8_t invalidMaskWriteRegisterReq[] = {/* Transaction ID */ 0x00, 0x0A,
182  /* Protocol ID */ 0x00, 0x00,
183  /* Length */ 0x00, 0x06,
184  /* Unit ID */ 0x00,
185  /* Function code */ 0x16,
186  /* Reference Address */ 0x00, 0x04,
187  /* And_Mask */ 0x00, 0xF2};
188 
189 static uint8_t maskWriteRegisterRsp[] = {/* Transaction ID */ 0x00, 0x0A,
190  /* Protocol ID */ 0x00, 0x00,
191  /* Length */ 0x00, 0x08,
192  /* Unit ID */ 0x00,
193  /* Function code */ 0x16,
194  /* Reference Address */ 0x00, 0x04,
195  /* And_Mask */ 0x00, 0xF2,
196  /* Or_Mask */ 0x00, 0x25};
197 
198 /* Modbus Application Protocol Specification V1.1b3 6.17: Read/Write Multiple registers */
199 /* Example of a request to read six registers starting at register 4, */
200 /* and to write three registers starting at register 15 */
201 static uint8_t readWriteMultipleRegistersReq[] = {/* Transaction ID */ 0x12, 0x34,
202  /* Protocol ID */ 0x00, 0x00,
203  /* Length */ 0x00, 0x11,
204  /* Unit ID */ 0x00,
205  /* Function code */ 0x17,
206  /* Read Starting Address */ 0x00, 0x03,
207  /* Quantity to Read */ 0x00, 0x06,
208  /* Write Starting Address */ 0x00, 0x0E,
209  /* Quantity to Write */ 0x00, 0x03,
210  /* Write Byte count */ 0x06,
211  /* Write Registers Value */ 0x12, 0x34,
212  0x56, 0x78,
213  0x9A, 0xBC};
214 
215 /* Mismatch value in Byte count 0x0B instead of 0x0C */
216 static uint8_t readWriteMultipleRegistersRsp[] = {/* Transaction ID */ 0x12, 0x34,
217  /* Protocol ID */ 0x00, 0x00,
218  /* Length */ 0x00, 0x0E,
219  /* Unit ID */ 0x00,
220  /* Function code */ 0x17,
221  /* Byte count */ 0x0B,
222  /* Read Registers Value */ 0x00, 0xFE,
223  0x0A, 0xCD,
224  0x00, 0x01,
225  0x00, 0x03,
226  0x00, 0x0D,
227  0x00};
228 
229 /* Modbus Application Protocol Specification V1.1b3 6.8.1: 04 Force Listen Only Mode */
230 /* Example of a request to to remote device to its Listen Only Mode for Modbus Communications. */
231 static uint8_t forceListenOnlyMode[] = {/* Transaction ID */ 0x0A, 0x00,
232  /* Protocol ID */ 0x00, 0x00,
233  /* Length */ 0x00, 0x06,
234  /* Unit ID */ 0x00,
235  /* Function code */ 0x08,
236  /* Sub-function code */ 0x00, 0x04,
237  /* Data */ 0x00, 0x00};
238 
239 static uint8_t invalidProtocolIdReq[] = {/* Transaction ID */ 0x00, 0x00,
240  /* Protocol ID */ 0x00, 0x01,
241  /* Length */ 0x00, 0x06,
242  /* Unit ID */ 0x00,
243  /* Function code */ 0x01,
244  /* Starting Address */ 0x78, 0x90,
245  /* Quantity of coils */ 0x00, 0x13 };
246 
247 static uint8_t invalidLengthWriteMultipleRegistersReq[] = {
248  /* Transaction ID */ 0x00, 0x0A,
249  /* Protocol ID */ 0x00, 0x00,
250  /* Length */ 0x00, 0x09,
251  /* Unit ID */ 0x00,
252  /* Function code */ 0x10,
253  /* Starting Address */ 0x00, 0x01,
254  /* Quantity of Registers */ 0x00, 0x02,
255  /* Byte count */ 0x04,
256  /* Registers Value */ 0x00, 0x0A,
257  0x01, 0x02};
258 
259 static uint8_t exceededLengthWriteMultipleRegistersReq[] = {
260  /* Transaction ID */ 0x00, 0x0A,
261  /* Protocol ID */ 0x00, 0x00,
262  /* Length */ 0xff, 0xfa,
263  /* Unit ID */ 0x00,
264  /* Function code */ 0x10,
265  /* Starting Address */ 0x00, 0x01,
266  /* Quantity of Registers */ 0x7f, 0xf9,
267  /* Byte count */ 0xff};
268 
269 static uint8_t invalidLengthPDUWriteMultipleRegistersReq[] = {
270  /* Transaction ID */ 0x00, 0x0A,
271  /* Protocol ID */ 0x00, 0x00,
272  /* Length */ 0x00, 0x02,
273  /* Unit ID */ 0x00,
274  /* Function code */ 0x10};
275 
276 /** \test Send Modbus Read Coils request/response. */
277 static int ModbusParserTest01(void)
278 {
279  Flow f;
280  TcpSession ssn;
281 
284 
285  memset(&f, 0, sizeof(f));
286  memset(&ssn, 0, sizeof(ssn));
287 
288  FLOW_INITIALIZE(&f);
289  f.protoctx = (void *)&ssn;
290  f.proto = IPPROTO_TCP;
292 
293  StreamTcpInitConfig(true);
294 
295  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
296  STREAM_TOSERVER, readCoilsReq,
297  sizeof(readCoilsReq));
298  FAIL_IF_NOT(r == 0);
299 
300  ModbusState *modbus_state = f.alstate;
301  FAIL_IF_NULL(modbus_state);
302 
303  ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
304  FAIL_IF_NULL(request._0);
305  FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 1);
306  FAIL_IF_NOT(SCModbusMessageGetReadRequestAddress(&request) == 0x7890);
307  FAIL_IF_NOT(SCModbusMessageGetReadRequestQuantity(&request) == 19);
308 
310  STREAM_TOCLIENT, readCoilsRsp,
311  sizeof(readCoilsRsp));
312  FAIL_IF_NOT(r == 0);
313  FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
314 
315  FLOW_DESTROY(&f);
317  StreamTcpFreeConfig(true);
318  PASS;
319 }
320 
321 /** \test Send Modbus Write Multiple registers request/response. */
322 static int ModbusParserTest02(void)
323 {
324  Flow f;
325  TcpSession ssn;
326 
329 
330  memset(&f, 0, sizeof(f));
331  memset(&ssn, 0, sizeof(ssn));
332 
333  FLOW_INITIALIZE(&f);
334  f.protoctx = (void *)&ssn;
335  f.proto = IPPROTO_TCP;
337 
338  StreamTcpInitConfig(true);
339 
340  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
341  STREAM_TOSERVER, writeMultipleRegistersReq,
342  sizeof(writeMultipleRegistersReq));
343  FAIL_IF_NOT(r == 0);
344 
345  ModbusState *modbus_state = f.alstate;
346  FAIL_IF_NULL(modbus_state);
347 
348  ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
349  FAIL_IF_NULL(request._0);
350  FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 16);
351  FAIL_IF_NOT(SCModbusMessageGetWriteMultreqAddress(&request) == 0x01);
352  FAIL_IF_NOT(SCModbusMessageGetWriteMultreqQuantity(&request) == 2);
353 
354  size_t data_len;
355  const uint8_t *data = SCModbusMessageGetWriteMultreqData(&request, &data_len);
356  FAIL_IF_NOT(data_len == 4);
357  FAIL_IF_NOT(data[0] == 0x00);
358  FAIL_IF_NOT(data[1] == 0x0A);
359  FAIL_IF_NOT(data[2] == 0x01);
360  FAIL_IF_NOT(data[3] == 0x02);
361 
363  STREAM_TOCLIENT, writeMultipleRegistersRsp,
364  sizeof(writeMultipleRegistersRsp));
365  FAIL_IF_NOT(r == 0);
366  FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
367 
368  FLOW_DESTROY(&f);
370  StreamTcpFreeConfig(true);
371  PASS;
372 }
373 
374 /** \test Send Modbus Read/Write Multiple registers request/response with mismatch value. */
375 static int ModbusParserTest03(void)
376 {
377  DetectEngineThreadCtx *det_ctx = NULL;
378  Flow f;
379  Packet *p = NULL;
380  Signature *s = NULL;
381  TcpSession ssn;
382  ThreadVars tv;
383 
386 
387  memset(&tv, 0, sizeof(ThreadVars));
389  memset(&f, 0, sizeof(Flow));
390  memset(&ssn, 0, sizeof(TcpSession));
391 
392  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
393 
394  FLOW_INITIALIZE(&f);
396  f.protoctx = (void *)&ssn;
397  f.proto = IPPROTO_TCP;
399  f.flags |= FLOW_IPV4;
400 
401  p->flow = &f;
404 
405  StreamTcpInitConfig(true);
406 
409 
410  de_ctx->flags |= DE_QUIET;
411  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
412  "(msg:\"Modbus Data mismatch\"; "
413  "app-layer-event: "
414  "modbus.value_mismatch; "
415  "sid:1;)");
416  FAIL_IF_NULL(s);
417 
419  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
420 
421  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
422  STREAM_TOSERVER,
423  readWriteMultipleRegistersReq,
424  sizeof(readWriteMultipleRegistersReq));
425  FAIL_IF_NOT(r == 0);
426 
427  ModbusState *modbus_state = f.alstate;
428  FAIL_IF_NULL(modbus_state);
429 
430  ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
431  FAIL_IF_NULL(request._0);
432 
433  FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 23);
434  FAIL_IF_NOT(SCModbusMessageGetRwMultreqReadAddress(&request) == 0x03);
435  FAIL_IF_NOT(SCModbusMessageGetRwMultreqReadQuantity(&request) == 6);
436  FAIL_IF_NOT(SCModbusMessageGetRwMultreqWriteAddress(&request) == 0x0E);
437  FAIL_IF_NOT(SCModbusMessageGetRwMultreqWriteQuantity(&request) == 3);
438 
439  size_t data_len;
440  uint8_t const *data = SCModbusMessageGetRwMultreqWriteData(&request, &data_len);
441  FAIL_IF_NOT(data_len == 6);
442  FAIL_IF_NOT(data[0] == 0x12);
443  FAIL_IF_NOT(data[1] == 0x34);
444  FAIL_IF_NOT(data[2] == 0x56);
445  FAIL_IF_NOT(data[3] == 0x78);
446  FAIL_IF_NOT(data[4] == 0x9A);
447  FAIL_IF_NOT(data[5] == 0xBC);
448 
450  STREAM_TOCLIENT, readWriteMultipleRegistersRsp,
451  sizeof(readWriteMultipleRegistersRsp));
452  FAIL_IF_NOT(r == 0);
453  FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
454 
455  /* do detect */
456  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
458 
459  UTHFreePackets(&p, 1);
460  FLOW_DESTROY(&f);
461 
463  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
465  StreamTcpFreeConfig(true);
467  PASS;
468 }
469 
470 /** \test Send Modbus Force Listen Only Mode request. */
471 static int ModbusParserTest04(void)
472 {
473  Flow f;
474  TcpSession ssn;
475 
478 
479  memset(&f, 0, sizeof(f));
480  memset(&ssn, 0, sizeof(ssn));
481 
482  FLOW_INITIALIZE(&f);
483  f.protoctx = (void *)&ssn;
484  f.proto = IPPROTO_TCP;
486 
487  StreamTcpInitConfig(true);
488 
489  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
490  STREAM_TOSERVER, forceListenOnlyMode,
491  sizeof(forceListenOnlyMode));
492  FAIL_IF_NOT(r == 0);
493 
494  ModbusState *modbus_state = f.alstate;
495  FAIL_IF_NULL(modbus_state);
496 
497  ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
498  FAIL_IF_NULL(request._0);
499  FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 8);
500  FAIL_IF_NOT(SCModbusMessageGetSubfunction(&request) == 4);
501 
503  StreamTcpFreeConfig(true);
504  FLOW_DESTROY(&f);
505  PASS;
506 }
507 
508 /** \test Send Modbus invalid Protocol version in request. */
509 static int ModbusParserTest05(void)
510 {
511  DetectEngineThreadCtx *det_ctx = NULL;
512  Flow f;
513  Packet *p = NULL;
514  Signature *s = NULL;
515  TcpSession ssn;
516  ThreadVars tv;
517 
520 
521  memset(&tv, 0, sizeof(ThreadVars));
523  memset(&f, 0, sizeof(Flow));
524  memset(&ssn, 0, sizeof(TcpSession));
525 
526  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
527 
528  FLOW_INITIALIZE(&f);
530  f.protoctx = (void *)&ssn;
531  f.proto = IPPROTO_TCP;
533  f.flags |= FLOW_IPV4;
534 
535  p->flow = &f;
538 
539  StreamTcpInitConfig(true);
540 
543 
544  de_ctx->flags |= DE_QUIET;
545  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
546  "(msg:\"Modbus invalid Protocol version\"; "
547  "app-layer-event: "
548  "modbus.invalid_protocol_id; "
549  "sid:1;)");
550  FAIL_IF_NULL(s);
551 
553  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
554 
555  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
556  STREAM_TOSERVER, invalidProtocolIdReq,
557  sizeof(invalidProtocolIdReq));
558  FAIL_IF_NOT(r == 0);
559 
560  ModbusState *modbus_state = f.alstate;
561  FAIL_IF_NULL(modbus_state);
562 
563  /* do detect */
564  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
566 
567  UTHFreePackets(&p, 1);
568  FLOW_DESTROY(&f);
569 
571  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
573  StreamTcpFreeConfig(true);
575  PASS;
576 }
577 
578 /** \test Send Modbus unsolicited response. */
579 static int ModbusParserTest06(void)
580 {
581  DetectEngineThreadCtx *det_ctx = NULL;
582  Flow f;
583  Packet *p = NULL;
584  Signature *s = NULL;
585  TcpSession ssn;
586  ThreadVars tv;
587 
590 
591  memset(&tv, 0, sizeof(ThreadVars));
593  memset(&f, 0, sizeof(Flow));
594  memset(&ssn, 0, sizeof(TcpSession));
595 
596  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
597 
598  FLOW_INITIALIZE(&f);
600  f.protoctx = (void *)&ssn;
601  f.proto = IPPROTO_TCP;
603  f.flags |= FLOW_IPV4;
604 
605  p->flow = &f;
608 
609  StreamTcpInitConfig(true);
610 
613 
614  de_ctx->flags |= DE_QUIET;
615  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
616  "(msg:\"Modbus unsolicited response\"; "
617  "app-layer-event: "
618  "modbus.unsolicited_response; "
619  "sid:1;)");
620  FAIL_IF_NULL(s);
621 
623  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
624 
625  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
626  STREAM_TOCLIENT, readCoilsRsp,
627  sizeof(readCoilsRsp));
628  FAIL_IF_NOT(r == 0);
629 
630  ModbusState *modbus_state = f.alstate;
631  FAIL_IF_NULL(modbus_state);
632 
633  /* do detect */
634  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
636 
637  UTHFreePackets(&p, 1);
638  FLOW_DESTROY(&f);
639 
641  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
643  StreamTcpFreeConfig(true);
645  PASS;
646 }
647 
648 /** \test Send Modbus invalid Length request. */
649 static int ModbusParserTest07(void)
650 {
651  DetectEngineThreadCtx *det_ctx = NULL;
652  Flow f;
653  Packet *p = NULL;
654  Signature *s = NULL;
655  TcpSession ssn;
656  ThreadVars tv;
657 
660 
661  memset(&tv, 0, sizeof(ThreadVars));
663  memset(&f, 0, sizeof(Flow));
664  memset(&ssn, 0, sizeof(TcpSession));
665 
666  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
667 
668  FLOW_INITIALIZE(&f);
670  f.protoctx = (void *)&ssn;
671  f.proto = IPPROTO_TCP;
673  f.flags |= FLOW_IPV4;
674 
675  p->flow = &f;
678 
679  StreamTcpInitConfig(true);
680 
683 
684  de_ctx->flags |= DE_QUIET;
685  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
686  "(msg:\"Modbus invalid Length\"; "
687  "app-layer-event: "
688  "modbus.invalid_length; "
689  "sid:1;)");
690  FAIL_IF_NULL(s);
691 
693  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
694 
695  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
696  STREAM_TOSERVER,
697  invalidLengthWriteMultipleRegistersReq,
698  sizeof(invalidLengthWriteMultipleRegistersReq));
699  FAIL_IF_NOT(r == 1);
700 
701  ModbusState *modbus_state = f.alstate;
702  FAIL_IF_NULL(modbus_state);
703 
704  /* do detect */
705  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
707 
708  UTHFreePackets(&p, 1);
709  FLOW_DESTROY(&f);
710 
712  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
714  StreamTcpFreeConfig(true);
716  PASS;
717 }
718 
719 /** \test Send Modbus Read Coils request and error response with Exception code invalid. */
720 static int ModbusParserTest08(void)
721 {
722  DetectEngineThreadCtx *det_ctx = NULL;
723  Flow f;
724  Packet *p = NULL;
725  Signature *s = NULL;
726  TcpSession ssn;
727  ThreadVars tv;
728 
731 
732  memset(&tv, 0, sizeof(ThreadVars));
734  memset(&f, 0, sizeof(Flow));
735  memset(&ssn, 0, sizeof(TcpSession));
736 
737  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
738 
739  FLOW_INITIALIZE(&f);
741  f.protoctx = (void *)&ssn;
742  f.proto = IPPROTO_TCP;
744  f.flags |= FLOW_IPV4;
745 
746  p->flow = &f;
749 
750  StreamTcpInitConfig(true);
751 
754 
755  de_ctx->flags |= DE_QUIET;
756  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
757  "(msg:\"Modbus Exception code invalid\"; "
758  "app-layer-event: "
759  "modbus.invalid_exception_code; "
760  "sid:1;)");
761  FAIL_IF_NULL(s);
762 
764  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
765 
766  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
767  STREAM_TOSERVER, readCoilsReq,
768  sizeof(readCoilsReq));
769  FAIL_IF_NOT(r == 0);
770 
771  ModbusState *modbus_state = f.alstate;
772  FAIL_IF_NULL(modbus_state);
773 
774  ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
775  FAIL_IF_NULL(request._0);
776  FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 1);
777  FAIL_IF_NOT(SCModbusMessageGetReadRequestAddress(&request) == 0x7890);
778  FAIL_IF_NOT(SCModbusMessageGetReadRequestQuantity(&request) == 19);
779 
781  STREAM_TOCLIENT, readCoilsErrorRsp,
782  sizeof(readCoilsErrorRsp));
783  FAIL_IF_NOT(r == 0);
784  FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
785 
786  /* do detect */
787  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
789 
790  UTHFreePackets(&p, 1);
791  FLOW_DESTROY(&f);
792 
794  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
796  StreamTcpFreeConfig(true);
798  PASS;
799 }
800 
801 /** \test Modbus fragmentation - 1 ADU over 2 TCP packets. */
802 static int ModbusParserTest09(void) {
804  Flow f;
805  TcpSession ssn;
806 
807  uint32_t input_len = sizeof(readCoilsReq), part2_len = 3;
808  uint8_t *input = readCoilsReq;
809 
811 
812  memset(&f, 0, sizeof(f));
813  memset(&ssn, 0, sizeof(ssn));
814 
815  FLOW_INITIALIZE(&f);
816  f.protoctx = (void *)&ssn;
817  f.proto = IPPROTO_TCP;
819 
820  StreamTcpInitConfig(true);
821 
822  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
823  STREAM_TOSERVER, input, input_len - part2_len);
824  FAIL_IF_NOT(r == 1);
825 
827  STREAM_TOSERVER, input, input_len);
828  FAIL_IF_NOT(r == 0);
829 
830  ModbusState *modbus_state = f.alstate;
831  FAIL_IF_NULL(modbus_state);
832 
833  ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
834  FAIL_IF_NULL(request._0);
835  FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 1);
836  FAIL_IF_NOT(SCModbusMessageGetReadRequestAddress(&request) == 0x7890);
837  FAIL_IF_NOT(SCModbusMessageGetReadRequestQuantity(&request) == 19);
838 
839  input_len = sizeof(readCoilsRsp);
840  part2_len = 10;
841  input = readCoilsRsp;
842 
844  STREAM_TOCLIENT, input, input_len - part2_len);
845  FAIL_IF_NOT(r == 1);
846 
848  STREAM_TOCLIENT, input, input_len);
849  FAIL_IF_NOT(r == 0);
850  FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
851 
853  StreamTcpFreeConfig(true);
854  FLOW_DESTROY(&f);
855  PASS;
856 }
857 
858 /** \test Modbus fragmentation - 2 ADU in 1 TCP packet. */
859 static int ModbusParserTest10(void) {
860  uint32_t input_len = sizeof(readCoilsReq) + sizeof(writeMultipleRegistersReq);
861  uint8_t *input, *ptr;
862 
863  Flow f;
864  TcpSession ssn;
865 
868 
869  input = (uint8_t *) SCMalloc (input_len * sizeof(uint8_t));
870  FAIL_IF_NULL(input);
871 
872  memcpy(input, readCoilsReq, sizeof(readCoilsReq));
873  memcpy(input + sizeof(readCoilsReq), writeMultipleRegistersReq, sizeof(writeMultipleRegistersReq));
874 
875  memset(&f, 0, sizeof(f));
876  memset(&ssn, 0, sizeof(ssn));
877 
878  FLOW_INITIALIZE(&f);
879  f.protoctx = (void *)&ssn;
880  f.proto = IPPROTO_TCP;
882 
883  StreamTcpInitConfig(true);
884 
885  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
886  STREAM_TOSERVER, input, input_len);
887  FAIL_IF_NOT(r == 0);
888 
889  ModbusState *modbus_state = f.alstate;
890  FAIL_IF_NULL(modbus_state);
891  FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 2);
892 
893  ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 1);
894  FAIL_IF_NULL(request._0);
895  FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 16);
896  FAIL_IF_NOT(SCModbusMessageGetWriteMultreqAddress(&request) == 0x01);
897  FAIL_IF_NOT(SCModbusMessageGetWriteMultreqQuantity(&request) == 2);
898 
899  size_t data_len;
900  uint8_t const *data = SCModbusMessageGetWriteMultreqData(&request, &data_len);
901  FAIL_IF_NOT(data_len == 4);
902  FAIL_IF_NOT(data[0] == 0x00);
903  FAIL_IF_NOT(data[1] == 0x0A);
904  FAIL_IF_NOT(data[2] == 0x01);
905  FAIL_IF_NOT(data[3] == 0x02);
906 
907  input_len = sizeof(readCoilsRsp) + sizeof(writeMultipleRegistersRsp);
908 
909  ptr = (uint8_t *) SCRealloc (input, input_len * sizeof(uint8_t));
910  FAIL_IF_NULL(ptr);
911  input = ptr;
912 
913  memcpy(input, readCoilsRsp, sizeof(readCoilsRsp));
914  memcpy(input + sizeof(readCoilsRsp), writeMultipleRegistersRsp, sizeof(writeMultipleRegistersRsp));
915 
916  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, input, input_len);
917  FAIL_IF_NOT(r == 0);
918 
919  FLOW_DESTROY(&f);
920  SCFree(input);
922  StreamTcpFreeConfig(true);
923  PASS;
924 }
925 
926 /** \test Send Modbus exceed Length request. */
927 static int ModbusParserTest11(void)
928 {
929  DetectEngineThreadCtx *det_ctx = NULL;
930  Flow f;
931  TcpSession ssn;
932  ThreadVars tv;
933 
934  size_t input_len = 65536;
935  uint8_t *input = SCCalloc(1, input_len);
936  FAIL_IF(input == NULL);
937 
938  memcpy(input, exceededLengthWriteMultipleRegistersReq,
939  sizeof(exceededLengthWriteMultipleRegistersReq));
940 
942  FAIL_IF(alp_tctx == NULL);
943 
944  memset(&tv, 0, sizeof(ThreadVars));
946  memset(&f, 0, sizeof(Flow));
947  memset(&ssn, 0, sizeof(TcpSession));
948 
949  Packet *p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
950 
951  FLOW_INITIALIZE(&f);
953  f.protoctx = (void *)&ssn;
954  f.proto = IPPROTO_TCP;
956  f.flags |= FLOW_IPV4;
957 
958  p->flow = &f;
961 
962  StreamTcpInitConfig(true);
963 
966 
967  de_ctx->flags |= DE_QUIET;
968  Signature *s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
969  "(msg:\"Modbus invalid Length\"; "
970  "app-layer-event: "
971  "modbus.invalid_length; "
972  "sid:1;)");
973  FAIL_IF_NULL(s);
974 
976  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
977 
978  int r = AppLayerParserParse(
979  NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, input, input_len);
980  FAIL_IF_NOT(r == 0);
981 
982  ModbusState *modbus_state = f.alstate;
983  FAIL_IF_NULL(modbus_state);
984 
985  /* do detect */
986  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
988 
989  UTHFreePackets(&p, 1);
990  FLOW_DESTROY(&f);
991 
993  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
995  StreamTcpFreeConfig(true);
997  SCFree(input);
998  PASS;
999 }
1000 
1001 /** \test Send Modbus invalid PDU Length. */
1002 static int ModbusParserTest12(void)
1003 {
1004  DetectEngineThreadCtx *det_ctx = NULL;
1005  Flow f;
1006  Packet *p = NULL;
1007  TcpSession ssn;
1008  ThreadVars tv;
1009 
1012 
1013  memset(&tv, 0, sizeof(ThreadVars));
1015  memset(&f, 0, sizeof(Flow));
1016  memset(&ssn, 0, sizeof(TcpSession));
1017 
1018  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1019 
1020  FLOW_INITIALIZE(&f);
1022  f.protoctx = (void *)&ssn;
1023  f.proto = IPPROTO_TCP;
1025  f.flags |= FLOW_IPV4;
1026 
1027  p->flow = &f;
1030 
1031  StreamTcpInitConfig(true);
1032 
1035 
1036  de_ctx->flags |= DE_QUIET;
1037  Signature *s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1038  "(msg:\"Modbus invalid Length\"; "
1039  "app-layer-event: "
1040  "modbus.invalid_length; "
1041  "sid:1;)");
1042  FAIL_IF_NULL(s);
1043 
1045  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
1046 
1047  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1048  STREAM_TOSERVER,
1049  invalidLengthPDUWriteMultipleRegistersReq,
1050  sizeof(invalidLengthPDUWriteMultipleRegistersReq));
1051  FAIL_IF_NOT(r == 0);
1052 
1053  ModbusState *modbus_state = f.alstate;
1054  FAIL_IF_NULL(modbus_state);
1055 
1056  /* do detect */
1057  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
1059 
1060  UTHFreePackets(&p, 1);
1061  FLOW_DESTROY(&f);
1062 
1064  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
1066  StreamTcpFreeConfig(true);
1068  PASS;
1069 }
1070 
1071 /** \test Send Modbus Mask Write register request/response. */
1072 static int ModbusParserTest13(void)
1073 {
1074  Flow f;
1075  TcpSession ssn;
1076 
1079 
1080  memset(&f, 0, sizeof(f));
1081  memset(&ssn, 0, sizeof(ssn));
1082 
1083  FLOW_INITIALIZE(&f);
1084  f.protoctx = (void *)&ssn;
1085  f.proto = IPPROTO_TCP;
1087 
1088  StreamTcpInitConfig(true);
1089 
1090  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1091  STREAM_TOSERVER, maskWriteRegisterReq,
1092  sizeof(maskWriteRegisterReq));
1093  FAIL_IF_NOT(r == 0);
1094 
1095  ModbusState *modbus_state = f.alstate;
1096  FAIL_IF_NULL(modbus_state);
1097 
1098  ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
1099  FAIL_IF_NULL(request._0);
1100  FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 22);
1101  FAIL_IF_NOT(SCModbusMessageGetAndMask(&request) == 0x00F2);
1102  FAIL_IF_NOT(SCModbusMessageGetOrMask(&request) == 0x0025);
1103 
1105  STREAM_TOCLIENT, maskWriteRegisterRsp,
1106  sizeof(maskWriteRegisterRsp));
1107  FAIL_IF_NOT(r == 0);
1108  FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
1109 
1111  StreamTcpFreeConfig(true);
1112  FLOW_DESTROY(&f);
1113  PASS;
1114 }
1115 
1116 /** \test Send Modbus Write single register request/response. */
1117 static int ModbusParserTest14(void)
1118 {
1119  Flow f;
1120  TcpSession ssn;
1121 
1124 
1125  memset(&f, 0, sizeof(f));
1126  memset(&ssn, 0, sizeof(ssn));
1127 
1128  FLOW_INITIALIZE(&f);
1129  f.protoctx = (void *)&ssn;
1130  f.proto = IPPROTO_TCP;
1132 
1133  StreamTcpInitConfig(true);
1134 
1135  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1136  STREAM_TOSERVER, writeSingleRegisterReq,
1137  sizeof(writeSingleRegisterReq));
1138  FAIL_IF_NOT(r == 0);
1139 
1140  ModbusState *modbus_state = f.alstate;
1141  FAIL_IF_NULL(modbus_state);
1142 
1143  ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
1144  FAIL_IF_NULL(request._0);
1145  FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 6);
1146  FAIL_IF_NOT(SCModbusMessageGetWriteAddress(&request) == 0x0001);
1147  FAIL_IF_NOT(SCModbusMessageGetWriteData(&request) == 0x0003);
1148 
1150  STREAM_TOCLIENT, writeSingleRegisterRsp,
1151  sizeof(writeSingleRegisterRsp));
1152  FAIL_IF_NOT(r == 0);
1153  FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
1154 
1155  FLOW_DESTROY(&f);
1157  StreamTcpFreeConfig(true);
1158  PASS;
1159 }
1160 
1161 /** \test Send invalid Modbus Mask Write register request. */
1162 static int ModbusParserTest15(void)
1163 {
1164  DetectEngineThreadCtx *det_ctx = NULL;
1165  Flow f;
1166  Packet *p = NULL;
1167  Signature *s = NULL;
1168  TcpSession ssn;
1169  ThreadVars tv;
1170 
1173 
1174  memset(&tv, 0, sizeof(ThreadVars));
1176  memset(&f, 0, sizeof(f));
1177  memset(&ssn, 0, sizeof(ssn));
1178 
1179  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1180 
1181  FLOW_INITIALIZE(&f);
1183  f.protoctx = (void *)&ssn;
1184  f.proto = IPPROTO_TCP;
1186  f.flags |= FLOW_IPV4;
1187 
1188  p->flow = &f;
1191 
1192  StreamTcpInitConfig(true);
1193 
1196 
1197  de_ctx->flags |= DE_QUIET;
1198  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1199  "(msg:\"Modbus invalid Length\"; "
1200  "app-layer-event: "
1201  "modbus.invalid_length; "
1202  "sid:1;)");
1203  FAIL_IF_NULL(s);
1204 
1206  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
1207 
1208  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1209  STREAM_TOSERVER, invalidMaskWriteRegisterReq,
1210  sizeof(invalidMaskWriteRegisterReq));
1211  FAIL_IF_NOT(r == 0);
1212 
1213  ModbusState *modbus_state = f.alstate;
1214  FAIL_IF_NULL(modbus_state);
1215 
1216  ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
1217  FAIL_IF_NULL(request._0);
1218  FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 22);
1219 
1220  /* do detect */
1221  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
1223 
1225  STREAM_TOCLIENT, maskWriteRegisterRsp,
1226  sizeof(maskWriteRegisterRsp));
1227  FAIL_IF_NOT(r == 0);
1228  FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
1229  ModbusMessage response = SCModbusStateGetTxResponse(modbus_state, 0);
1230  FAIL_IF_NULL(response._0);
1231  FAIL_IF_NOT(SCModbusMessageGetFunction(&response) == 22);
1232 
1233  UTHFreePackets(&p, 1);
1234  FLOW_DESTROY(&f);
1235 
1237  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
1239  StreamTcpFreeConfig(true);
1241  PASS;
1242 }
1243 
1244 /** \test Send invalid Modbus Mask Write register request. */
1245 static int ModbusParserTest16(void)
1246 {
1247  DetectEngineThreadCtx *det_ctx = NULL;
1248  Flow f;
1249  Packet *p = NULL;
1250  Signature *s = NULL;
1251  TcpSession ssn;
1252  ThreadVars tv;
1253 
1256 
1257  memset(&tv, 0, sizeof(ThreadVars));
1259  memset(&f, 0, sizeof(f));
1260  memset(&ssn, 0, sizeof(ssn));
1261 
1262  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1263 
1264  FLOW_INITIALIZE(&f);
1266  f.protoctx = (void *)&ssn;
1267  f.proto = IPPROTO_TCP;
1269  f.flags |= FLOW_IPV4;
1270 
1271  p->flow = &f;
1274 
1275  StreamTcpInitConfig(true);
1276 
1279 
1280  de_ctx->flags |= DE_QUIET;
1281  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1282  "(msg:\"Modbus invalid Length\"; "
1283  "app-layer-event: "
1284  "modbus.invalid_length; "
1285  "sid:1;)");
1286  FAIL_IF_NULL(s);
1287 
1289  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
1290 
1291  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1292  STREAM_TOSERVER,
1293  invalidWriteSingleRegisterReq,
1294  sizeof(invalidWriteSingleRegisterReq));
1295  FAIL_IF_NOT(r == 0);
1296 
1297  ModbusState *modbus_state = f.alstate;
1298  FAIL_IF_NULL(modbus_state);
1299 
1300  ModbusMessage request = SCModbusStateGetTxRequest(modbus_state, 0);
1301  FAIL_IF_NULL(request._0);
1302  FAIL_IF_NOT(SCModbusMessageGetFunction(&request) == 6);
1303  size_t data_len;
1304  const uint8_t *data = SCModbusMessageGetBytevecData(&request, &data_len);
1305  FAIL_IF_NOT(data_len == 2);
1306  FAIL_IF_NOT(data[0] == 0x00);
1307  FAIL_IF_NOT(data[1] == 0x01);
1308 
1309  /* do detect */
1310  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
1312 
1314  STREAM_TOCLIENT, writeSingleRegisterRsp,
1315  sizeof(writeSingleRegisterRsp));
1316  FAIL_IF_NOT(r == 0);
1317 
1318  FAIL_IF_NOT(SCModbusStateGetTxCount(modbus_state) == 1);
1319  ModbusMessage response = SCModbusStateGetTxResponse(modbus_state, 0);
1320  FAIL_IF_NULL(response._0);
1321  FAIL_IF_NOT(SCModbusMessageGetFunction(&response) == 6);
1322  FAIL_IF_NOT(SCModbusMessageGetWriteAddress(&response) == 0x0001);
1323 
1324  UTHFreePackets(&p, 1);
1325  FLOW_DESTROY(&f);
1326 
1328  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
1330  StreamTcpFreeConfig(true);
1332  PASS;
1333 }
1334 
1335 /** \test Checks if stream_depth is correct */
1336 static int ModbusParserTest17(void)
1337 {
1338  Flow f;
1339  TcpSession ssn;
1340 
1343 
1344  memset(&f, 0, sizeof(f));
1345  memset(&ssn, 0, sizeof(ssn));
1346 
1347  FLOW_INITIALIZE(&f);
1348  f.protoctx = (void *)&ssn;
1349  f.proto = IPPROTO_TCP;
1351 
1352  StreamTcpInitConfig(true);
1353 
1354  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER,
1355  readCoilsReq, sizeof(readCoilsReq));
1356  FAIL_IF(r != 0);
1357  FAIL_IF(f.alstate == NULL);
1358  FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH);
1359 
1360  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT,
1361  readCoilsRsp, sizeof(readCoilsRsp));
1362  FAIL_IF(r != 0);
1363  FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH);
1364 
1365  FLOW_DESTROY(&f);
1367  StreamTcpFreeConfig(true);
1368  PASS;
1369 }
1370 
1371 /*/ \test Checks if stream depth is correct over 2 TCP packets */
1372 static int ModbusParserTest18(void)
1373 {
1374  Flow f;
1375  TcpSession ssn;
1376 
1377  uint32_t input_len = sizeof(readCoilsReq), part2_len = 3;
1378  uint8_t *input = readCoilsReq;
1379 
1382 
1383  memset(&f, 0, sizeof(f));
1384  memset(&ssn, 0, sizeof(ssn));
1385 
1386  FLOW_INITIALIZE(&f);
1387  f.protoctx = (void *)&ssn;
1388  f.proto = IPPROTO_TCP;
1390 
1391  StreamTcpInitConfig(true);
1392 
1393  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER,
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_TOSERVER,
1399  input, input_len);
1400  FAIL_IF(r != 0);
1401  FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH);
1402  FAIL_IF(f.alstate == NULL);
1403 
1404  input_len = sizeof(readCoilsRsp);
1405  part2_len = 10;
1406  input = readCoilsRsp;
1407 
1408  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT,
1409  input, input_len - part2_len);
1410  FAIL_IF(r != 1);
1411  FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH);
1412 
1413  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT,
1414  input, input_len);
1415  FAIL_IF(r != 0);
1416  FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH);
1417 
1418  FLOW_DESTROY(&f);
1420  StreamTcpFreeConfig(true);
1421  PASS;
1422 }
1423 
1424 /** \test Send Modbus invalid function. */
1425 static int ModbusParserTest19(void)
1426 {
1427  DetectEngineThreadCtx *det_ctx = NULL;
1428  Flow f;
1429  Packet *p = NULL;
1430  Signature *s = NULL;
1431  TcpSession ssn;
1432  ThreadVars tv;
1433 
1436 
1437  memset(&tv, 0, sizeof(ThreadVars));
1439  memset(&f, 0, sizeof(Flow));
1440  memset(&ssn, 0, sizeof(TcpSession));
1441 
1442  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1443 
1444  FLOW_INITIALIZE(&f);
1446  f.protoctx = (void *)&ssn;
1447  f.proto = IPPROTO_TCP;
1449  f.flags |= FLOW_IPV4;
1450 
1451  p->flow = &f;
1454 
1455  StreamTcpInitConfig(true);
1456 
1459 
1460  de_ctx->flags |= DE_QUIET;
1461  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1462  "(msg:\"Modbus invalid Function code\"; "
1463  "app-layer-event: "
1464  "modbus.invalid_function_code; "
1465  "sid:1;)");
1466  FAIL_IF_NULL(s);
1467 
1469  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
1470 
1471  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1472  STREAM_TOSERVER,
1473  invalidFunctionCode,
1474  sizeof(invalidFunctionCode));
1475  FAIL_IF_NOT(r == 0);
1476 
1477  ModbusState *modbus_state = f.alstate;
1478  FAIL_IF_NULL(modbus_state);
1479 
1480  /* do detect */
1481  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
1483 
1484  UTHFreePackets(&p, 1);
1485  FLOW_DESTROY(&f);
1486 
1488  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
1490  StreamTcpFreeConfig(true);
1492  PASS;
1493 }
1494 #endif /* UNITTESTS */
1495 
1497 #ifdef UNITTESTS
1498  UtRegisterTest("ModbusParserTest01 - Modbus Read Coils request",
1499  ModbusParserTest01);
1500  UtRegisterTest("ModbusParserTest02 - Modbus Write Multiple registers request",
1501  ModbusParserTest02);
1502  UtRegisterTest("ModbusParserTest03 - Modbus Read/Write Multiple registers request",
1503  ModbusParserTest03);
1504  UtRegisterTest("ModbusParserTest04 - Modbus Force Listen Only Mode request",
1505  ModbusParserTest04);
1506  UtRegisterTest("ModbusParserTest05 - Modbus invalid Protocol version",
1507  ModbusParserTest05);
1508  UtRegisterTest("ModbusParserTest06 - Modbus unsolicited response",
1509  ModbusParserTest06);
1510  UtRegisterTest("ModbusParserTest07 - Modbus invalid Length request",
1511  ModbusParserTest07);
1512  UtRegisterTest("ModbusParserTest08 - Modbus Exception code invalid",
1513  ModbusParserTest08);
1514  UtRegisterTest("ModbusParserTest09 - Modbus fragmentation - 1 ADU in 2 TCP packets",
1515  ModbusParserTest09);
1516  UtRegisterTest("ModbusParserTest10 - Modbus fragmentation - 2 ADU in 1 TCP packet",
1517  ModbusParserTest10);
1518  UtRegisterTest("ModbusParserTest11 - Modbus exceeded Length request",
1519  ModbusParserTest11);
1520  UtRegisterTest("ModbusParserTest12 - Modbus invalid PDU Length",
1521  ModbusParserTest12);
1522  UtRegisterTest("ModbusParserTest13 - Modbus Mask Write register request",
1523  ModbusParserTest13);
1524  UtRegisterTest("ModbusParserTest14 - Modbus Write single register request",
1525  ModbusParserTest14);
1526  UtRegisterTest("ModbusParserTest15 - Modbus invalid Mask Write register request",
1527  ModbusParserTest15);
1528  UtRegisterTest("ModbusParserTest16 - Modbus invalid Write single register request",
1529  ModbusParserTest16);
1530  UtRegisterTest("ModbusParserTest17 - Modbus stream depth",
1531  ModbusParserTest17);
1532  UtRegisterTest("ModbusParserTest18 - Modbus stream depth in 2 TCP packets",
1533  ModbusParserTest18);
1534  UtRegisterTest("ModbusParserTest19 - Modbus invalid Function code",
1535  ModbusParserTest19);
1536 #endif /* UNITTESTS */
1537 }
detect-engine.h
FAIL_IF_NULL
#define FAIL_IF_NULL(expr)
Fail a test if expression evaluates to NULL.
Definition: util-unittest.h:89
Flow_::flags
uint64_t flags
Definition: flow.h:408
PKT_HAS_FLOW
#define PKT_HAS_FLOW
Definition: decode.h:1311
flow-util.h
stream-tcp.h
HTPCfgRec_::response
HTPCfgDir response
Definition: app-layer-htp.h:117
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:101
RegisterModbusParsers
void RegisterModbusParsers(void)
Function to register the Modbus protocol parser.
Definition: app-layer-modbus.c:71
ALPROTO_MODBUS
@ ALPROTO_MODBUS
Definition: app-layer-protos.h:48
Flow_::proto
uint8_t proto
Definition: flow.h:381
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:144
Packet_::flags
uint32_t flags
Definition: decode.h:562
ssn
TcpSession ssn
Definition: fuzz_dataset.c:31
Flow_
Flow data structure.
Definition: flow.h:359
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:995
DetectEngineCtxFree
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Definition: detect-engine.c:2912
MODBUS_CONFIG_DEFAULT_STREAM_DEPTH
#define MODBUS_CONFIG_DEFAULT_STREAM_DEPTH
Definition: app-layer-modbus.c:85
AppLayerParserThreadCtxFree
void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
Destroys the app layer parser thread context obtained using AppLayerParserThreadCtxAlloc().
Definition: app-layer-parser.c:364
FLOW_PKT_TOSERVER
#define FLOW_PKT_TOSERVER
Definition: flow.h:236
rust.h
DE_QUIET
#define DE_QUIET
Definition: detect.h:334
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:241
SigMatchSignatures
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition: detect.c:3305
p
Packet * p
Definition: fuzz_dataset.c:30
DetectEngineAppendSig
Signature * DetectEngineAppendSig(DetectEngineCtx *, const char *)
Parse and append a Signature into the Detection Engine Context signature list.
Definition: detect-parse.c:3965
Packet_::flowflags
uint8_t flowflags
Definition: decode.h:547
Flow_::protoctx
void * protoctx
Definition: flow.h:438
FLOW_IPV4
#define FLOW_IPV4
Definition: flow.h:99
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
counters.h
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
decode.h
util-debug.h
PASS
#define PASS
Pass the test.
Definition: util-unittest.h:105
de_ctx
DetectEngineCtx * de_ctx
Definition: fuzz_siginit.c:22
DetectEngineThreadCtx_
Definition: detect.h:1316
alp_tctx
AppLayerParserThreadCtx * alp_tctx
Definition: fuzz_applayerparserparse.c:24
detect.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:57
DetectEngineThreadCtxInit
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
initialize thread specific detection engine context
Definition: detect-engine.c:3660
app-layer-parser.h
SCReturn
#define SCReturn
Definition: util-debug.h:286
AppLayerParserRegisterProtocolUnittests
void AppLayerParserRegisterProtocolUnittests(uint8_t ipproto, AppProto alproto, void(*RegisterUnittests)(void))
Definition: app-layer-parser.c:2090
Packet_
Definition: decode.h:516
detect-engine-build.h
stream-tcp-private.h
detect-engine-alert.h
ModbusParserRegisterTests
void ModbusParserRegisterTests(void)
Definition: app-layer-modbus.c:1496
SigGroupBuild
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
Definition: detect-engine-build.c:2300
StatsThreadInit
void StatsThreadInit(StatsThreadContext *stats)
Definition: counters.c:1332
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:337
app-layer-modbus.h
Packet_::flow
struct Flow_ * flow
Definition: decode.h:564
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:864
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:1528
suricata-common.h
HTPCfgRec_::request
HTPCfgDir request
Definition: app-layer-htp.h:116
DetectEngineThreadCtxDeinit
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *tv, void *data)
Definition: detect-engine.c:3905
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:34
threadvars.h
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:484
detect-parse.h
Signature_
Signature container.
Definition: detect.h:692
FLOW_PKT_ESTABLISHED
#define FLOW_PKT_ESTABLISHED
Definition: flow.h:238
DetectEngineCtxInit
DetectEngineCtx * DetectEngineCtxInit(void)
Definition: detect-engine.c:2873
app-layer-protos.h
DetectEngineCtx_::flags
uint8_t flags
Definition: detect.h:997
AppLayerParserThreadCtx_
Definition: app-layer-parser.c:72
TcpSession_
Definition: stream-tcp-private.h:283
flow.h
Flow_::alproto
AppProto alproto
application level protocol
Definition: flow.h:455
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
ThreadVars_::stats
StatsThreadContext stats
Definition: threadvars.h:120
StatsThreadCleanup
void StatsThreadCleanup(StatsThreadContext *stats)
Definition: counters.c:1428
FLOW_DESTROY
#define FLOW_DESTROY(f)
Definition: flow-util.h:119
PKT_STREAM_EST
#define PKT_STREAM_EST
Definition: decode.h:1307
f
Flow f
Definition: fuzz_dataset.c:32
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:453