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 "detect-engine-build.h"
44 
45 void ModbusParserRegisterTests(void);
46 
47 /**
48  * \brief Function to register the Modbus protocol parser
49  */
51 {
52  rs_modbus_register_parser();
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 
66 #include "flow-util.h"
67 
68 #include "util-unittest.h"
69 #include "util-unittest-helper.h"
70 
71 #include "stream-tcp.h"
72 #include "stream-tcp-private.h"
73 
74 #include "rust.h"
75 
76 /* Modbus default stream reassembly depth */
77 #define MODBUS_CONFIG_DEFAULT_STREAM_DEPTH 0
78 
79 /* Modbus Application Protocol Specification V1.1b3 6.1: Read Coils */
80 static uint8_t invalidFunctionCode[] = {
81  /* Transaction ID */ 0x00, 0x00,
82  /* Protocol ID */ 0x00, 0x00,
83  /* Length */ 0x00, 0x02,
84  /* Unit ID */ 0x00,
85  /* Function code */ 0x00
86 };
87 
88 /* Modbus Application Protocol Specification V1.1b3 6.1: Read Coils */
89 /* Example of a request to read discrete outputs 20-38 */
90 static uint8_t readCoilsReq[] = {/* Transaction ID */ 0x00, 0x00,
91  /* Protocol ID */ 0x00, 0x00,
92  /* Length */ 0x00, 0x06,
93  /* Unit ID */ 0x00,
94  /* Function code */ 0x01,
95  /* Starting Address */ 0x78, 0x90,
96  /* Quantity of coils */ 0x00, 0x13 };
97 
98 static uint8_t readCoilsRsp[] = {/* Transaction ID */ 0x00, 0x00,
99  /* Protocol ID */ 0x00, 0x00,
100  /* Length */ 0x00, 0x06,
101  /* Unit ID */ 0x00,
102  /* Function code */ 0x01,
103  /* Byte count */ 0x03,
104  /* Coil Status */ 0xCD, 0x6B, 0x05 };
105 
106 static uint8_t readCoilsErrorRsp[] = {
107  /* Transaction ID */ 0x00, 0x00,
108  /* Protocol ID */ 0x00, 0x00,
109  /* Length */ 0x00, 0x03,
110  /* Unit ID */ 0x00,
111  /* Function code */ 0x81,
112  /* Invalid Exception code: should trigger the InvalidExceptionCode ModbusEvent */
113  0xFF
114 };
115 
116 /* Modbus Application Protocol Specification V1.1b3 6.6: Write Single register */
117 /* Example of a request to write register 2 to 00 03 hex */
118 static uint8_t writeSingleRegisterReq[] = {/* Transaction ID */ 0x00, 0x0A,
119  /* Protocol ID */ 0x00, 0x00,
120  /* Length */ 0x00, 0x06,
121  /* Unit ID */ 0x00,
122  /* Function code */ 0x06,
123  /* Register Address */ 0x00, 0x01,
124  /* Register Value */ 0x00, 0x03};
125 
126 static uint8_t invalidWriteSingleRegisterReq[] = {/* Transaction ID */ 0x00, 0x0A,
127  /* Protocol ID */ 0x00, 0x00,
128  /* Length */ 0x00, 0x04,
129  /* Unit ID */ 0x00,
130  /* Function code */ 0x06,
131  /* Register Address */ 0x00, 0x01};
132 
133 static uint8_t writeSingleRegisterRsp[] = {/* Transaction ID */ 0x00, 0x0A,
134  /* Protocol ID */ 0x00, 0x00,
135  /* Length */ 0x00, 0x06,
136  /* Unit ID */ 0x00,
137  /* Function code */ 0x06,
138  /* Register Address */ 0x00, 0x01,
139  /* Register Value */ 0x00, 0x03};
140 
141 /* Modbus Application Protocol Specification V1.1b3 6.12: Write Multiple registers */
142 /* Example of a request to write two registers starting at 2 to 00 0A and 01 02 hex */
143 static uint8_t writeMultipleRegistersReq[] = {/* Transaction ID */ 0x00, 0x0A,
144  /* Protocol ID */ 0x00, 0x00,
145  /* Length */ 0x00, 0x0B,
146  /* Unit ID */ 0x00,
147  /* Function code */ 0x10,
148  /* Starting Address */ 0x00, 0x01,
149  /* Quantity of Registers */ 0x00, 0x02,
150  /* Byte count */ 0x04,
151  /* Registers Value */ 0x00, 0x0A,
152  0x01, 0x02};
153 
154 static uint8_t writeMultipleRegistersRsp[] = {/* Transaction ID */ 0x00, 0x0A,
155  /* Protocol ID */ 0x00, 0x00,
156  /* Length */ 0x00, 0x06,
157  /* Unit ID */ 0x00,
158  /* Function code */ 0x10,
159  /* Starting Address */ 0x00, 0x01,
160  /* Quantity of Registers */ 0x00, 0x02};
161 
162 /* Modbus Application Protocol Specification V1.1b3 6.16: Mask Write Register */
163 /* Example of a request to mask write to register 5 */
164 static uint8_t maskWriteRegisterReq[] = {/* Transaction ID */ 0x00, 0x0A,
165  /* Protocol ID */ 0x00, 0x00,
166  /* Length */ 0x00, 0x08,
167  /* Unit ID */ 0x00,
168  /* Function code */ 0x16,
169  /* Reference Address */ 0x00, 0x04,
170  /* And_Mask */ 0x00, 0xF2,
171  /* Or_Mask */ 0x00, 0x25};
172 
173 static uint8_t invalidMaskWriteRegisterReq[] = {/* Transaction ID */ 0x00, 0x0A,
174  /* Protocol ID */ 0x00, 0x00,
175  /* Length */ 0x00, 0x06,
176  /* Unit ID */ 0x00,
177  /* Function code */ 0x16,
178  /* Reference Address */ 0x00, 0x04,
179  /* And_Mask */ 0x00, 0xF2};
180 
181 static uint8_t maskWriteRegisterRsp[] = {/* Transaction ID */ 0x00, 0x0A,
182  /* Protocol ID */ 0x00, 0x00,
183  /* Length */ 0x00, 0x08,
184  /* Unit ID */ 0x00,
185  /* Function code */ 0x16,
186  /* Reference Address */ 0x00, 0x04,
187  /* And_Mask */ 0x00, 0xF2,
188  /* Or_Mask */ 0x00, 0x25};
189 
190 /* Modbus Application Protocol Specification V1.1b3 6.17: Read/Write Multiple registers */
191 /* Example of a request to read six registers starting at register 4, */
192 /* and to write three registers starting at register 15 */
193 static uint8_t readWriteMultipleRegistersReq[] = {/* Transaction ID */ 0x12, 0x34,
194  /* Protocol ID */ 0x00, 0x00,
195  /* Length */ 0x00, 0x11,
196  /* Unit ID */ 0x00,
197  /* Function code */ 0x17,
198  /* Read Starting Address */ 0x00, 0x03,
199  /* Quantity to Read */ 0x00, 0x06,
200  /* Write Starting Address */ 0x00, 0x0E,
201  /* Quantity to Write */ 0x00, 0x03,
202  /* Write Byte count */ 0x06,
203  /* Write Registers Value */ 0x12, 0x34,
204  0x56, 0x78,
205  0x9A, 0xBC};
206 
207 /* Mismatch value in Byte count 0x0B instead of 0x0C */
208 static uint8_t readWriteMultipleRegistersRsp[] = {/* Transaction ID */ 0x12, 0x34,
209  /* Protocol ID */ 0x00, 0x00,
210  /* Length */ 0x00, 0x0E,
211  /* Unit ID */ 0x00,
212  /* Function code */ 0x17,
213  /* Byte count */ 0x0B,
214  /* Read Registers Value */ 0x00, 0xFE,
215  0x0A, 0xCD,
216  0x00, 0x01,
217  0x00, 0x03,
218  0x00, 0x0D,
219  0x00};
220 
221 /* Modbus Application Protocol Specification V1.1b3 6.8.1: 04 Force Listen Only Mode */
222 /* Example of a request to to remote device to its Listen Only Mode for Modbus Communications. */
223 static uint8_t forceListenOnlyMode[] = {/* Transaction ID */ 0x0A, 0x00,
224  /* Protocol ID */ 0x00, 0x00,
225  /* Length */ 0x00, 0x06,
226  /* Unit ID */ 0x00,
227  /* Function code */ 0x08,
228  /* Sub-function code */ 0x00, 0x04,
229  /* Data */ 0x00, 0x00};
230 
231 static uint8_t invalidProtocolIdReq[] = {/* Transaction ID */ 0x00, 0x00,
232  /* Protocol ID */ 0x00, 0x01,
233  /* Length */ 0x00, 0x06,
234  /* Unit ID */ 0x00,
235  /* Function code */ 0x01,
236  /* Starting Address */ 0x78, 0x90,
237  /* Quantity of coils */ 0x00, 0x13 };
238 
239 static uint8_t invalidLengthWriteMultipleRegistersReq[] = {
240  /* Transaction ID */ 0x00, 0x0A,
241  /* Protocol ID */ 0x00, 0x00,
242  /* Length */ 0x00, 0x09,
243  /* Unit ID */ 0x00,
244  /* Function code */ 0x10,
245  /* Starting Address */ 0x00, 0x01,
246  /* Quantity of Registers */ 0x00, 0x02,
247  /* Byte count */ 0x04,
248  /* Registers Value */ 0x00, 0x0A,
249  0x01, 0x02};
250 
251 static uint8_t exceededLengthWriteMultipleRegistersReq[] = {
252  /* Transaction ID */ 0x00, 0x0A,
253  /* Protocol ID */ 0x00, 0x00,
254  /* Length */ 0xff, 0xfa,
255  /* Unit ID */ 0x00,
256  /* Function code */ 0x10,
257  /* Starting Address */ 0x00, 0x01,
258  /* Quantity of Registers */ 0x7f, 0xf9,
259  /* Byte count */ 0xff};
260 
261 static uint8_t invalidLengthPDUWriteMultipleRegistersReq[] = {
262  /* Transaction ID */ 0x00, 0x0A,
263  /* Protocol ID */ 0x00, 0x00,
264  /* Length */ 0x00, 0x02,
265  /* Unit ID */ 0x00,
266  /* Function code */ 0x10};
267 
268 /** \test Send Modbus Read Coils request/response. */
269 static int ModbusParserTest01(void) {
271  Flow f;
272  TcpSession ssn;
273 
275 
276  memset(&f, 0, sizeof(f));
277  memset(&ssn, 0, sizeof(ssn));
278 
279  FLOW_INITIALIZE(&f);
280  f.protoctx = (void *)&ssn;
281  f.proto = IPPROTO_TCP;
283 
284  StreamTcpInitConfig(true);
285 
286  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
287  STREAM_TOSERVER, readCoilsReq,
288  sizeof(readCoilsReq));
289  FAIL_IF_NOT(r == 0);
290 
291  ModbusState *modbus_state = f.alstate;
292  FAIL_IF_NULL(modbus_state);
293 
294  ModbusMessage request = rs_modbus_state_get_tx_request(modbus_state, 0);
295  FAIL_IF_NULL(request._0);
296  FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 1);
297  FAIL_IF_NOT(rs_modbus_message_get_read_request_address(&request) == 0x7890);
298  FAIL_IF_NOT(rs_modbus_message_get_read_request_quantity(&request) == 19);
299 
301  STREAM_TOCLIENT, readCoilsRsp,
302  sizeof(readCoilsRsp));
303  FAIL_IF_NOT(r == 0);
304 
305  FAIL_IF_NOT(rs_modbus_state_get_tx_count(modbus_state) == 1);
306 
308  StreamTcpFreeConfig(true);
309  FLOW_DESTROY(&f);
310  PASS;
311 }
312 
313 /** \test Send Modbus Write Multiple registers request/response. */
314 static int ModbusParserTest02(void) {
316  Flow f;
317  TcpSession ssn;
318 
320 
321  memset(&f, 0, sizeof(f));
322  memset(&ssn, 0, sizeof(ssn));
323 
324  FLOW_INITIALIZE(&f);
325  f.protoctx = (void *)&ssn;
326  f.proto = IPPROTO_TCP;
328 
329  StreamTcpInitConfig(true);
330 
331  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
332  STREAM_TOSERVER, writeMultipleRegistersReq,
333  sizeof(writeMultipleRegistersReq));
334  FAIL_IF_NOT(r == 0);
335 
336  ModbusState *modbus_state = f.alstate;
337  FAIL_IF_NULL(modbus_state);
338 
339  ModbusMessage request = rs_modbus_state_get_tx_request(modbus_state, 0);
340  FAIL_IF_NULL(request._0);
341  FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 16);
342  FAIL_IF_NOT(rs_modbus_message_get_write_multreq_address(&request) == 0x01);
343  FAIL_IF_NOT(rs_modbus_message_get_write_multreq_quantity(&request) == 2);
344 
345  size_t data_len;
346  const uint8_t *data = rs_modbus_message_get_write_multreq_data(&request, &data_len);
347  FAIL_IF_NOT(data_len == 4);
348  FAIL_IF_NOT(data[0] == 0x00);
349  FAIL_IF_NOT(data[1] == 0x0A);
350  FAIL_IF_NOT(data[2] == 0x01);
351  FAIL_IF_NOT(data[3] == 0x02);
352 
354  STREAM_TOCLIENT, writeMultipleRegistersRsp,
355  sizeof(writeMultipleRegistersRsp));
356  FAIL_IF_NOT(r == 0);
357 
358  FAIL_IF_NOT(rs_modbus_state_get_tx_count(modbus_state) == 1);
359 
361  StreamTcpFreeConfig(true);
362  FLOW_DESTROY(&f);
363  PASS;
364 }
365 
366 /** \test Send Modbus Read/Write Multiple registers request/response with mismatch value. */
367 static int ModbusParserTest03(void) {
369  DetectEngineThreadCtx *det_ctx = NULL;
370  Flow f;
371  Packet *p = NULL;
372  Signature *s = NULL;
373  TcpSession ssn;
374  ThreadVars tv;
375 
377 
378  memset(&tv, 0, sizeof(ThreadVars));
379  memset(&f, 0, sizeof(Flow));
380  memset(&ssn, 0, sizeof(TcpSession));
381 
382  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
383 
384  FLOW_INITIALIZE(&f);
386  f.protoctx = (void *)&ssn;
387  f.proto = IPPROTO_TCP;
389  f.flags |= FLOW_IPV4;
390 
391  p->flow = &f;
394 
395  StreamTcpInitConfig(true);
396 
399 
400  de_ctx->flags |= DE_QUIET;
401  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
402  "(msg:\"Modbus Data mismatch\"; "
403  "app-layer-event: "
404  "modbus.value_mismatch; "
405  "sid:1;)");
406  FAIL_IF_NULL(s);
407 
409  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
410 
411  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
412  STREAM_TOSERVER,
413  readWriteMultipleRegistersReq,
414  sizeof(readWriteMultipleRegistersReq));
415  FAIL_IF_NOT(r == 0);
416 
417  ModbusState *modbus_state = f.alstate;
418  FAIL_IF_NULL(modbus_state);
419 
420  ModbusMessage request = rs_modbus_state_get_tx_request(modbus_state, 0);
421  FAIL_IF_NULL(request._0);
422 
423  FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 23);
424  FAIL_IF_NOT(rs_modbus_message_get_rw_multreq_read_address(&request) == 0x03);
425  FAIL_IF_NOT(rs_modbus_message_get_rw_multreq_read_quantity(&request) == 6);
426  FAIL_IF_NOT(rs_modbus_message_get_rw_multreq_write_address(&request) == 0x0E);
427  FAIL_IF_NOT(rs_modbus_message_get_rw_multreq_write_quantity(&request) == 3);
428 
429  size_t data_len;
430  uint8_t const *data = rs_modbus_message_get_rw_multreq_write_data(&request, &data_len);
431  FAIL_IF_NOT(data_len == 6);
432  FAIL_IF_NOT(data[0] == 0x12);
433  FAIL_IF_NOT(data[1] == 0x34);
434  FAIL_IF_NOT(data[2] == 0x56);
435  FAIL_IF_NOT(data[3] == 0x78);
436  FAIL_IF_NOT(data[4] == 0x9A);
437  FAIL_IF_NOT(data[5] == 0xBC);
438 
440  STREAM_TOCLIENT, readWriteMultipleRegistersRsp,
441  sizeof(readWriteMultipleRegistersRsp));
442  FAIL_IF_NOT(r == 0);
443 
444  FAIL_IF_NOT(rs_modbus_state_get_tx_count(modbus_state) == 1);
445 
446  /* do detect */
447  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
448 
450 
453 
454  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
456 
458  StreamTcpFreeConfig(true);
459  FLOW_DESTROY(&f);
460  UTHFreePackets(&p, 1);
461  PASS;
462 }
463 
464 /** \test Send Modbus Force Listen Only Mode request. */
465 static int ModbusParserTest04(void) {
467  Flow f;
468  TcpSession ssn;
469 
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 = rs_modbus_state_get_tx_request(modbus_state, 0);
491  FAIL_IF_NULL(request._0);
492 
493  FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 8);
494  FAIL_IF_NOT(rs_modbus_message_get_subfunction(&request) == 4);
495 
497  StreamTcpFreeConfig(true);
498  FLOW_DESTROY(&f);
499  PASS;
500 }
501 
502 /** \test Send Modbus invalid Protocol version in request. */
503 static int ModbusParserTest05(void) {
505  DetectEngineThreadCtx *det_ctx = NULL;
506  Flow f;
507  Packet *p = NULL;
508  Signature *s = NULL;
509  TcpSession ssn;
510  ThreadVars tv;
511 
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);
557 
559 
562 
563  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
565 
567  StreamTcpFreeConfig(true);
568  FLOW_DESTROY(&f);
569  UTHFreePackets(&p, 1);
570  PASS;
571 }
572 
573 /** \test Send Modbus unsolicited response. */
574 static int ModbusParserTest06(void) {
576  DetectEngineThreadCtx *det_ctx = NULL;
577  Flow f;
578  Packet *p = NULL;
579  Signature *s = NULL;
580  TcpSession ssn;
581  ThreadVars tv;
582 
584 
585  memset(&tv, 0, sizeof(ThreadVars));
586  memset(&f, 0, sizeof(Flow));
587  memset(&ssn, 0, sizeof(TcpSession));
588 
589  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
590 
591  FLOW_INITIALIZE(&f);
593  f.protoctx = (void *)&ssn;
594  f.proto = IPPROTO_TCP;
596  f.flags |= FLOW_IPV4;
597 
598  p->flow = &f;
601 
602  StreamTcpInitConfig(true);
603 
606 
607  de_ctx->flags |= DE_QUIET;
608  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
609  "(msg:\"Modbus unsolicited response\"; "
610  "app-layer-event: "
611  "modbus.unsolicited_response; "
612  "sid:1;)");
613  FAIL_IF_NULL(s);
614 
616  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
617 
618  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
619  STREAM_TOCLIENT, readCoilsRsp,
620  sizeof(readCoilsRsp));
621  FAIL_IF_NOT(r == 0);
622 
623  ModbusState *modbus_state = f.alstate;
624  FAIL_IF_NULL(modbus_state);
625 
626  /* do detect */
627  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
628 
630 
633 
634  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
636 
638  StreamTcpFreeConfig(true);
639  FLOW_DESTROY(&f);
640  UTHFreePackets(&p, 1);
641  PASS;
642 }
643 
644 /** \test Send Modbus invalid Length request. */
645 static int ModbusParserTest07(void) {
647  DetectEngineThreadCtx *det_ctx = NULL;
648  Flow f;
649  Packet *p = NULL;
650  Signature *s = NULL;
651  TcpSession ssn;
652  ThreadVars tv;
653 
655 
656  memset(&tv, 0, sizeof(ThreadVars));
657  memset(&f, 0, sizeof(Flow));
658  memset(&ssn, 0, sizeof(TcpSession));
659 
660  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
661 
662  FLOW_INITIALIZE(&f);
664  f.protoctx = (void *)&ssn;
665  f.proto = IPPROTO_TCP;
667  f.flags |= FLOW_IPV4;
668 
669  p->flow = &f;
672 
673  StreamTcpInitConfig(true);
674 
677 
678  de_ctx->flags |= DE_QUIET;
679  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
680  "(msg:\"Modbus invalid Length\"; "
681  "app-layer-event: "
682  "modbus.invalid_length; "
683  "sid:1;)");
684  FAIL_IF_NULL(s);
685 
687  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
688 
689  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
690  STREAM_TOSERVER,
691  invalidLengthWriteMultipleRegistersReq,
692  sizeof(invalidLengthWriteMultipleRegistersReq));
693  FAIL_IF_NOT(r == 1);
694 
695  ModbusState *modbus_state = f.alstate;
696  FAIL_IF_NULL(modbus_state);
697 
698  /* do detect */
699  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
700 
702 
705 
706  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
708 
710  StreamTcpFreeConfig(true);
711  FLOW_DESTROY(&f);
712  UTHFreePackets(&p, 1);
713  PASS;
714 }
715 
716 /** \test Send Modbus Read Coils request and error response with Exception code invalid. */
717 static int ModbusParserTest08(void) {
719  DetectEngineThreadCtx *det_ctx = NULL;
720  Flow f;
721  Packet *p = NULL;
722  Signature *s = NULL;
723  TcpSession ssn;
724  ThreadVars tv;
725 
727 
728  memset(&tv, 0, sizeof(ThreadVars));
729  memset(&f, 0, sizeof(Flow));
730  memset(&ssn, 0, sizeof(TcpSession));
731 
732  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
733 
734  FLOW_INITIALIZE(&f);
736  f.protoctx = (void *)&ssn;
737  f.proto = IPPROTO_TCP;
739  f.flags |= FLOW_IPV4;
740 
741  p->flow = &f;
744 
745  StreamTcpInitConfig(true);
746 
749 
750  de_ctx->flags |= DE_QUIET;
751  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
752  "(msg:\"Modbus Exception code invalid\"; "
753  "app-layer-event: "
754  "modbus.invalid_exception_code; "
755  "sid:1;)");
756  FAIL_IF_NULL(s);
757 
759  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
760 
761  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
762  STREAM_TOSERVER, readCoilsReq,
763  sizeof(readCoilsReq));
764  FAIL_IF_NOT(r == 0);
765 
766  ModbusState *modbus_state = f.alstate;
767  FAIL_IF_NULL(modbus_state);
768 
769  ModbusMessage request = rs_modbus_state_get_tx_request(modbus_state, 0);
770  FAIL_IF_NULL(request._0);
771 
772  FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 1);
773  FAIL_IF_NOT(rs_modbus_message_get_read_request_address(&request) == 0x7890);
774  FAIL_IF_NOT(rs_modbus_message_get_read_request_quantity(&request) == 19);
775 
777  STREAM_TOCLIENT, readCoilsErrorRsp,
778  sizeof(readCoilsErrorRsp));
779  FAIL_IF_NOT(r == 0);
780 
781  FAIL_IF_NOT(rs_modbus_state_get_tx_count(modbus_state) == 1);
782 
783  /* do detect */
784  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
785 
787 
790 
791  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
793 
795  StreamTcpFreeConfig(true);
796  FLOW_DESTROY(&f);
797  UTHFreePackets(&p, 1);
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 = rs_modbus_state_get_tx_request(modbus_state, 0);
834  FAIL_IF_NULL(request._0);
835 
836  FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 1);
837  FAIL_IF_NOT(rs_modbus_message_get_read_request_address(&request) == 0x7890);
838  FAIL_IF_NOT(rs_modbus_message_get_read_request_quantity(&request) == 19);
839 
840  input_len = sizeof(readCoilsRsp);
841  part2_len = 10;
842  input = readCoilsRsp;
843 
845  STREAM_TOCLIENT, input, input_len - part2_len);
846  FAIL_IF_NOT(r == 1);
847 
849  STREAM_TOCLIENT, input, input_len);
850  FAIL_IF_NOT(r == 0);
851 
852  FAIL_IF_NOT(rs_modbus_state_get_tx_count(modbus_state) == 1);
853 
855  StreamTcpFreeConfig(true);
856  FLOW_DESTROY(&f);
857  PASS;
858 }
859 
860 /** \test Modbus fragmentation - 2 ADU in 1 TCP packet. */
861 static int ModbusParserTest10(void) {
862  uint32_t input_len = sizeof(readCoilsReq) + sizeof(writeMultipleRegistersReq);
863  uint8_t *input, *ptr;
864 
866  Flow f;
867  TcpSession ssn;
868 
870 
871  input = (uint8_t *) SCMalloc (input_len * sizeof(uint8_t));
872  FAIL_IF_NULL(input);
873 
874  memcpy(input, readCoilsReq, sizeof(readCoilsReq));
875  memcpy(input + sizeof(readCoilsReq), writeMultipleRegistersReq, sizeof(writeMultipleRegistersReq));
876 
877  memset(&f, 0, sizeof(f));
878  memset(&ssn, 0, sizeof(ssn));
879 
880  FLOW_INITIALIZE(&f);
881  f.protoctx = (void *)&ssn;
882  f.proto = IPPROTO_TCP;
884 
885  StreamTcpInitConfig(true);
886 
887  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
888  STREAM_TOSERVER, input, input_len);
889  FAIL_IF_NOT(r == 0);
890 
891  ModbusState *modbus_state = f.alstate;
892  FAIL_IF_NULL(modbus_state);
893 
894  FAIL_IF_NOT(rs_modbus_state_get_tx_count(modbus_state) == 2);
895 
896  ModbusMessage request = rs_modbus_state_get_tx_request(modbus_state, 1);
897  FAIL_IF_NULL(request._0);
898 
899  FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 16);
900  FAIL_IF_NOT(rs_modbus_message_get_write_multreq_address(&request) == 0x01);
901  FAIL_IF_NOT(rs_modbus_message_get_write_multreq_quantity(&request) == 2);
902 
903  size_t data_len;
904  uint8_t const *data = rs_modbus_message_get_write_multreq_data(&request, &data_len);
905  FAIL_IF_NOT(data_len == 4);
906  FAIL_IF_NOT(data[0] == 0x00);
907  FAIL_IF_NOT(data[1] == 0x0A);
908  FAIL_IF_NOT(data[2] == 0x01);
909  FAIL_IF_NOT(data[3] == 0x02);
910 
911  input_len = sizeof(readCoilsRsp) + sizeof(writeMultipleRegistersRsp);
912 
913  ptr = (uint8_t *) SCRealloc (input, input_len * sizeof(uint8_t));
914  FAIL_IF_NULL(ptr);
915  input = ptr;
916 
917  memcpy(input, readCoilsRsp, sizeof(readCoilsRsp));
918  memcpy(input + sizeof(readCoilsRsp), writeMultipleRegistersRsp, sizeof(writeMultipleRegistersRsp));
919 
920  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT, input, input_len);
921  FAIL_IF_NOT(r == 0);
922 
923  SCFree(input);
925  StreamTcpFreeConfig(true);
926  FLOW_DESTROY(&f);
927  PASS;
928 }
929 
930 /** \test Send Modbus exceed Length request. */
931 static int ModbusParserTest11(void) {
933  DetectEngineThreadCtx *det_ctx = NULL;
934  Flow f;
935  Packet *p = NULL;
936  Signature *s = NULL;
937  TcpSession ssn;
938  ThreadVars tv;
939 
940  size_t input_len = 65536;
941  uint8_t *input = SCCalloc(1, input_len);
942 
943  FAIL_IF(input == NULL);
944 
945  memcpy(input, exceededLengthWriteMultipleRegistersReq,
946  sizeof(exceededLengthWriteMultipleRegistersReq));
947 
948  FAIL_IF(alp_tctx == NULL);
949 
950  memset(&tv, 0, sizeof(ThreadVars));
951  memset(&f, 0, sizeof(Flow));
952  memset(&ssn, 0, sizeof(TcpSession));
953 
954  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
955 
956  FLOW_INITIALIZE(&f);
958  f.protoctx = (void *)&ssn;
959  f.proto = IPPROTO_TCP;
961  f.flags |= FLOW_IPV4;
962 
963  p->flow = &f;
966 
967  StreamTcpInitConfig(true);
968 
971 
972  de_ctx->flags |= DE_QUIET;
973  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
974  "(msg:\"Modbus invalid Length\"; "
975  "app-layer-event: "
976  "modbus.invalid_length; "
977  "sid:1;)");
978  FAIL_IF_NULL(s);
979 
981  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
982 
983  int r = AppLayerParserParse(
984  NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER, input, input_len);
985  FAIL_IF_NOT(r == 0);
986 
987  ModbusState *modbus_state = f.alstate;
988  FAIL_IF_NULL(modbus_state);
989 
990  /* do detect */
991  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
992 
994 
997 
998  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
1000 
1002  StreamTcpFreeConfig(true);
1003  FLOW_DESTROY(&f);
1004  UTHFreePackets(&p, 1);
1005  PASS;
1006 }
1007 
1008 /** \test Send Modbus invalid PDU Length. */
1009 static int ModbusParserTest12(void) {
1011  DetectEngineThreadCtx *det_ctx = NULL;
1012  Flow f;
1013  Packet *p = NULL;
1014  Signature *s = NULL;
1015  TcpSession ssn;
1016  ThreadVars tv;
1017 
1019 
1020  memset(&tv, 0, sizeof(ThreadVars));
1021  memset(&f, 0, sizeof(Flow));
1022  memset(&ssn, 0, sizeof(TcpSession));
1023 
1024  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1025 
1026  FLOW_INITIALIZE(&f);
1027  f.alproto = ALPROTO_MODBUS;
1028  f.protoctx = (void *)&ssn;
1029  f.proto = IPPROTO_TCP;
1030  f.alproto = ALPROTO_MODBUS;
1031  f.flags |= FLOW_IPV4;
1032 
1033  p->flow = &f;
1036 
1037  StreamTcpInitConfig(true);
1038 
1041 
1042  de_ctx->flags |= DE_QUIET;
1043  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1044  "(msg:\"Modbus invalid Length\"; "
1045  "app-layer-event: "
1046  "modbus.invalid_length; "
1047  "sid:1;)");
1048  FAIL_IF_NULL(s);
1049 
1051  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
1052 
1053  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1054  STREAM_TOSERVER,
1055  invalidLengthPDUWriteMultipleRegistersReq,
1056  sizeof(invalidLengthPDUWriteMultipleRegistersReq));
1057  FAIL_IF_NOT(r == 0);
1058 
1059  ModbusState *modbus_state = f.alstate;
1060  FAIL_IF_NULL(modbus_state);
1061 
1062  /* do detect */
1063  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
1064 
1066 
1069 
1070  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
1072 
1074  StreamTcpFreeConfig(true);
1075  FLOW_DESTROY(&f);
1076  UTHFreePackets(&p, 1);
1077  PASS;
1078 }
1079 
1080 /** \test Send Modbus Mask Write register request/response. */
1081 static int ModbusParserTest13(void) {
1083  Flow f;
1084  TcpSession ssn;
1085 
1087 
1088  memset(&f, 0, sizeof(f));
1089  memset(&ssn, 0, sizeof(ssn));
1090 
1091  FLOW_INITIALIZE(&f);
1092  f.protoctx = (void *)&ssn;
1093  f.proto = IPPROTO_TCP;
1094  f.alproto = ALPROTO_MODBUS;
1095 
1096  StreamTcpInitConfig(true);
1097 
1098  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1099  STREAM_TOSERVER, maskWriteRegisterReq,
1100  sizeof(maskWriteRegisterReq));
1101  FAIL_IF_NOT(r == 0);
1102 
1103  ModbusState *modbus_state = f.alstate;
1104  FAIL_IF_NULL(modbus_state);
1105 
1106  ModbusMessage request = rs_modbus_state_get_tx_request(modbus_state, 0);
1107  FAIL_IF_NULL(request._0);
1108 
1109  FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 22);
1110  FAIL_IF_NOT(rs_modbus_message_get_and_mask(&request) == 0x00F2);
1111  FAIL_IF_NOT(rs_modbus_message_get_or_mask(&request) == 0x0025);
1112 
1114  STREAM_TOCLIENT, maskWriteRegisterRsp,
1115  sizeof(maskWriteRegisterRsp));
1116  FAIL_IF_NOT(r == 0);
1117 
1118  FAIL_IF_NOT(rs_modbus_state_get_tx_count(modbus_state) == 1);
1119 
1121  StreamTcpFreeConfig(true);
1122  FLOW_DESTROY(&f);
1123  PASS;
1124 }
1125 
1126 /** \test Send Modbus Write single register request/response. */
1127 static int ModbusParserTest14(void) {
1129  Flow f;
1130  TcpSession ssn;
1131 
1133 
1134  memset(&f, 0, sizeof(f));
1135  memset(&ssn, 0, sizeof(ssn));
1136 
1137  FLOW_INITIALIZE(&f);
1138  f.protoctx = (void *)&ssn;
1139  f.proto = IPPROTO_TCP;
1140  f.alproto = ALPROTO_MODBUS;
1141 
1142  StreamTcpInitConfig(true);
1143 
1144  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1145  STREAM_TOSERVER, writeSingleRegisterReq,
1146  sizeof(writeSingleRegisterReq));
1147  FAIL_IF_NOT(r == 0);
1148 
1149  ModbusState *modbus_state = f.alstate;
1150  FAIL_IF_NULL(modbus_state);
1151 
1152  ModbusMessage request = rs_modbus_state_get_tx_request(modbus_state, 0);
1153  FAIL_IF_NULL(request._0);
1154 
1155  FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 6);
1156  FAIL_IF_NOT(rs_modbus_message_get_write_address(&request) == 0x0001);
1157  FAIL_IF_NOT(rs_modbus_message_get_write_data(&request) == 0x0003);
1158 
1160  STREAM_TOCLIENT, writeSingleRegisterRsp,
1161  sizeof(writeSingleRegisterRsp));
1162  FAIL_IF_NOT(r == 0);
1163 
1164  FAIL_IF_NOT(rs_modbus_state_get_tx_count(modbus_state) == 1);
1165 
1167  StreamTcpFreeConfig(true);
1168  FLOW_DESTROY(&f);
1169  PASS;
1170 }
1171 
1172 /** \test Send invalid Modbus Mask Write register request. */
1173 static int ModbusParserTest15(void) {
1175  DetectEngineThreadCtx *det_ctx = NULL;
1176  Flow f;
1177  Packet *p = NULL;
1178  Signature *s = NULL;
1179  TcpSession ssn;
1180  ThreadVars tv;
1181 
1183 
1184  memset(&tv, 0, sizeof(ThreadVars));
1185  memset(&f, 0, sizeof(f));
1186  memset(&ssn, 0, sizeof(ssn));
1187 
1188  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1189 
1190  FLOW_INITIALIZE(&f);
1191  f.alproto = ALPROTO_MODBUS;
1192  f.protoctx = (void *)&ssn;
1193  f.proto = IPPROTO_TCP;
1194  f.alproto = ALPROTO_MODBUS;
1195  f.flags |= FLOW_IPV4;
1196 
1197  p->flow = &f;
1200 
1201  StreamTcpInitConfig(true);
1202 
1205 
1206  de_ctx->flags |= DE_QUIET;
1207  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1208  "(msg:\"Modbus invalid Length\"; "
1209  "app-layer-event: "
1210  "modbus.invalid_length; "
1211  "sid:1;)");
1212  FAIL_IF_NULL(s);
1213 
1215  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
1216 
1217  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1218  STREAM_TOSERVER, invalidMaskWriteRegisterReq,
1219  sizeof(invalidMaskWriteRegisterReq));
1220  FAIL_IF_NOT(r == 0);
1221 
1222  ModbusState *modbus_state = f.alstate;
1223  FAIL_IF_NULL(modbus_state);
1224 
1225  ModbusMessage request = rs_modbus_state_get_tx_request(modbus_state, 0);
1226  FAIL_IF_NULL(request._0);
1227 
1228  FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 22);
1229 
1230  /* do detect */
1231  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
1232 
1234 
1236  STREAM_TOCLIENT, maskWriteRegisterRsp,
1237  sizeof(maskWriteRegisterRsp));
1238  FAIL_IF_NOT(r == 0);
1239 
1240  FAIL_IF_NOT(rs_modbus_state_get_tx_count(modbus_state) == 1);
1241  ModbusMessage response = rs_modbus_state_get_tx_response(modbus_state, 0);
1242  FAIL_IF_NULL(response._0);
1243 
1244  FAIL_IF_NOT(rs_modbus_message_get_function(&response) == 22);
1245 
1248 
1249  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
1251 
1253  StreamTcpFreeConfig(true);
1254  FLOW_DESTROY(&f);
1255  UTHFreePackets(&p, 1);
1256  PASS;
1257 }
1258 
1259 /** \test Send invalid Modbus Mask Write register request. */
1260 static int ModbusParserTest16(void) {
1262  DetectEngineThreadCtx *det_ctx = NULL;
1263  Flow f;
1264  Packet *p = NULL;
1265  Signature *s = NULL;
1266  TcpSession ssn;
1267  ThreadVars tv;
1268 
1270 
1271  memset(&tv, 0, sizeof(ThreadVars));
1272  memset(&f, 0, sizeof(f));
1273  memset(&ssn, 0, sizeof(ssn));
1274 
1275  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1276 
1277  FLOW_INITIALIZE(&f);
1278  f.alproto = ALPROTO_MODBUS;
1279  f.protoctx = (void *)&ssn;
1280  f.proto = IPPROTO_TCP;
1281  f.alproto = ALPROTO_MODBUS;
1282  f.flags |= FLOW_IPV4;
1283 
1284  p->flow = &f;
1287 
1288  StreamTcpInitConfig(true);
1289 
1292 
1293  de_ctx->flags |= DE_QUIET;
1294  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1295  "(msg:\"Modbus invalid Length\"; "
1296  "app-layer-event: "
1297  "modbus.invalid_length; "
1298  "sid:1;)");
1299  FAIL_IF_NULL(s);
1300 
1302  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
1303 
1304  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1305  STREAM_TOSERVER,
1306  invalidWriteSingleRegisterReq,
1307  sizeof(invalidWriteSingleRegisterReq));
1308  FAIL_IF_NOT(r == 0);
1309 
1310  ModbusState *modbus_state = f.alstate;
1311  FAIL_IF_NULL(modbus_state);
1312 
1313  ModbusMessage request = rs_modbus_state_get_tx_request(modbus_state, 0);
1314  FAIL_IF_NULL(request._0);
1315 
1316  FAIL_IF_NOT(rs_modbus_message_get_function(&request) == 6);
1317  size_t data_len;
1318  const uint8_t *data = rs_modbus_message_get_bytevec_data(&request, &data_len);
1319  FAIL_IF_NOT(data_len == 2);
1320  FAIL_IF_NOT(data[0] == 0x00);
1321  FAIL_IF_NOT(data[1] == 0x01);
1322 
1323  /* do detect */
1324  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
1325 
1327 
1329  STREAM_TOCLIENT, writeSingleRegisterRsp,
1330  sizeof(writeSingleRegisterRsp));
1331  FAIL_IF_NOT(r == 0);
1332 
1333  FAIL_IF_NOT(rs_modbus_state_get_tx_count(modbus_state) == 1);
1334  ModbusMessage response = rs_modbus_state_get_tx_response(modbus_state, 0);
1335  FAIL_IF_NULL(response._0);
1336 
1337  FAIL_IF_NOT(rs_modbus_message_get_function(&response) == 6);
1338  FAIL_IF_NOT(rs_modbus_message_get_write_address(&response) == 0x0001);
1339 
1342 
1343  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
1345 
1347  StreamTcpFreeConfig(true);
1348  FLOW_DESTROY(&f);
1349  UTHFreePackets(&p, 1);
1350  PASS;}
1351 
1352 /** \test Checks if stream_depth is correct */
1353 static int ModbusParserTest17(void) {
1355  Flow f;
1356  TcpSession ssn;
1357 
1359 
1360  memset(&f, 0, sizeof(f));
1361  memset(&ssn, 0, sizeof(ssn));
1362 
1363  FLOW_INITIALIZE(&f);
1364  f.protoctx = (void *)&ssn;
1365  f.proto = IPPROTO_TCP;
1366  f.alproto = ALPROTO_MODBUS;
1367 
1368  StreamTcpInitConfig(true);
1369 
1370  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER,
1371  readCoilsReq, sizeof(readCoilsReq));
1372  FAIL_IF(r != 0);
1373 
1374  FAIL_IF(f.alstate == NULL);
1375 
1376  FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH);
1377 
1378  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT,
1379  readCoilsRsp, sizeof(readCoilsRsp));
1380  FAIL_IF(r != 0);
1381 
1382  FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH);
1383 
1385  StreamTcpFreeConfig(true);
1386  FLOW_DESTROY(&f);
1387  PASS;
1388 }
1389 
1390 /*/ \test Checks if stream depth is correct over 2 TCP packets */
1391 static int ModbusParserTest18(void) {
1393  Flow f;
1394  TcpSession ssn;
1395 
1396  uint32_t input_len = sizeof(readCoilsReq), part2_len = 3;
1397  uint8_t *input = readCoilsReq;
1398 
1400 
1401  memset(&f, 0, sizeof(f));
1402  memset(&ssn, 0, sizeof(ssn));
1403 
1404  FLOW_INITIALIZE(&f);
1405  f.protoctx = (void *)&ssn;
1406  f.proto = IPPROTO_TCP;
1407  f.alproto = ALPROTO_MODBUS;
1408 
1409  StreamTcpInitConfig(true);
1410 
1411  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER,
1412  input, input_len - part2_len);
1413  FAIL_IF(r != 1);
1414 
1415  FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH);
1416 
1417  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOSERVER,
1418  input, input_len);
1419  FAIL_IF(r != 0);
1420 
1421  FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH);
1422 
1423  FAIL_IF(f.alstate == NULL);
1424 
1425  input_len = sizeof(readCoilsRsp);
1426  part2_len = 10;
1427  input = readCoilsRsp;
1428 
1429  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT,
1430  input, input_len - part2_len);
1431  FAIL_IF(r != 1);
1432 
1433  FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH);
1434 
1435  r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS, STREAM_TOCLIENT,
1436  input, input_len);
1437  FAIL_IF(r != 0);
1438 
1439  FAIL_IF(((TcpSession *)(f.protoctx))->reassembly_depth != MODBUS_CONFIG_DEFAULT_STREAM_DEPTH);
1440 
1442  StreamTcpFreeConfig(true);
1443  FLOW_DESTROY(&f);
1444  PASS;
1445 }
1446 
1447 /** \test Send Modbus invalid function. */
1448 static int ModbusParserTest19(void) {
1450  DetectEngineThreadCtx *det_ctx = NULL;
1451  Flow f;
1452  Packet *p = NULL;
1453  Signature *s = NULL;
1454  TcpSession ssn;
1455  ThreadVars tv;
1456 
1458 
1459  memset(&tv, 0, sizeof(ThreadVars));
1460  memset(&f, 0, sizeof(Flow));
1461  memset(&ssn, 0, sizeof(TcpSession));
1462 
1463  p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
1464 
1465  FLOW_INITIALIZE(&f);
1466  f.alproto = ALPROTO_MODBUS;
1467  f.protoctx = (void *)&ssn;
1468  f.proto = IPPROTO_TCP;
1469  f.alproto = ALPROTO_MODBUS;
1470  f.flags |= FLOW_IPV4;
1471 
1472  p->flow = &f;
1475 
1476  StreamTcpInitConfig(true);
1477 
1480 
1481  de_ctx->flags |= DE_QUIET;
1482  s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
1483  "(msg:\"Modbus invalid Function code\"; "
1484  "app-layer-event: "
1485  "modbus.invalid_function_code; "
1486  "sid:1;)");
1487  FAIL_IF_NULL(s);
1488 
1490  DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
1491 
1492  int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
1493  STREAM_TOSERVER,
1494  invalidFunctionCode,
1495  sizeof(invalidFunctionCode));
1496  FAIL_IF_NOT(r == 0);
1497 
1498  ModbusState *modbus_state = f.alstate;
1499  FAIL_IF_NULL(modbus_state);
1500 
1501  /* do detect */
1502  SigMatchSignatures(&tv, de_ctx, det_ctx, p);
1503 
1505 
1508 
1509  DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
1511 
1513  StreamTcpFreeConfig(true);
1514  FLOW_DESTROY(&f);
1515  UTHFreePackets(&p, 1);
1516  PASS;
1517 }
1518 #endif /* UNITTESTS */
1519 
1521 #ifdef UNITTESTS
1522  UtRegisterTest("ModbusParserTest01 - Modbus Read Coils request",
1523  ModbusParserTest01);
1524  UtRegisterTest("ModbusParserTest02 - Modbus Write Multiple registers request",
1525  ModbusParserTest02);
1526  UtRegisterTest("ModbusParserTest03 - Modbus Read/Write Multiple registers request",
1527  ModbusParserTest03);
1528  UtRegisterTest("ModbusParserTest04 - Modbus Force Listen Only Mode request",
1529  ModbusParserTest04);
1530  UtRegisterTest("ModbusParserTest05 - Modbus invalid Protocol version",
1531  ModbusParserTest05);
1532  UtRegisterTest("ModbusParserTest06 - Modbus unsolicited response",
1533  ModbusParserTest06);
1534  UtRegisterTest("ModbusParserTest07 - Modbus invalid Length request",
1535  ModbusParserTest07);
1536  UtRegisterTest("ModbusParserTest08 - Modbus Exception code invalid",
1537  ModbusParserTest08);
1538  UtRegisterTest("ModbusParserTest09 - Modbus fragmentation - 1 ADU in 2 TCP packets",
1539  ModbusParserTest09);
1540  UtRegisterTest("ModbusParserTest10 - Modbus fragmentation - 2 ADU in 1 TCP packet",
1541  ModbusParserTest10);
1542  UtRegisterTest("ModbusParserTest11 - Modbus exceeded Length request",
1543  ModbusParserTest11);
1544  UtRegisterTest("ModbusParserTest12 - Modbus invalid PDU Length",
1545  ModbusParserTest12);
1546  UtRegisterTest("ModbusParserTest13 - Modbus Mask Write register request",
1547  ModbusParserTest13);
1548  UtRegisterTest("ModbusParserTest14 - Modbus Write single register request",
1549  ModbusParserTest14);
1550  UtRegisterTest("ModbusParserTest15 - Modbus invalid Mask Write register request",
1551  ModbusParserTest15);
1552  UtRegisterTest("ModbusParserTest16 - Modbus invalid Write single register request",
1553  ModbusParserTest16);
1554  UtRegisterTest("ModbusParserTest17 - Modbus stream depth",
1555  ModbusParserTest17);
1556  UtRegisterTest("ModbusParserTest18 - Modbus stream depth in 2 TCP packets",
1557  ModbusParserTest18);
1558  UtRegisterTest("ModbusParserTest19 - Modbus invalid Function code",
1559  ModbusParserTest19);
1560 #endif /* UNITTESTS */
1561 }
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:1176
flow-util.h
stream-tcp.h
UtRegisterTest
void UtRegisterTest(const char *name, int(*TestFn)(void))
Register unit test.
Definition: util-unittest.c:103
RegisterModbusParsers
void RegisterModbusParsers(void)
Function to register the Modbus protocol parser.
Definition: app-layer-modbus.c:50
ALPROTO_MODBUS
@ ALPROTO_MODBUS
Definition: app-layer-protos.h:42
Flow_::proto
uint8_t proto
Definition: flow.h:375
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:141
Packet_::flags
uint32_t flags
Definition: decode.h:468
Flow_
Flow data structure.
Definition: flow.h:353
DetectEngineCtx_
main detection engine ctx
Definition: detect.h:785
DetectEngineCtxFree
void DetectEngineCtxFree(DetectEngineCtx *)
Free a DetectEngineCtx::
Definition: detect-engine.c:2446
MODBUS_CONFIG_DEFAULT_STREAM_DEPTH
#define MODBUS_CONFIG_DEFAULT_STREAM_DEPTH
Definition: app-layer-modbus.c:77
AppLayerParserThreadCtxFree
void AppLayerParserThreadCtxFree(AppLayerParserThreadCtx *tctx)
Destroys the app layer parser thread context obtained using AppLayerParserThreadCtxAlloc().
Definition: app-layer-parser.c:328
FLOW_PKT_TOSERVER
#define FLOW_PKT_TOSERVER
Definition: flow.h:223
rust.h
DE_QUIET
#define DE_QUIET
Definition: detect.h:288
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:338
SigMatchSignatures
void SigMatchSignatures(ThreadVars *tv, DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, Packet *p)
wrapper for old tests
Definition: detect.c:1786
SigCleanSignatures
void SigCleanSignatures(DetectEngineCtx *de_ctx)
Definition: detect-engine-build.c:45
Packet_::flowflags
uint8_t flowflags
Definition: decode.h:464
Flow_::protoctx
void * protoctx
Definition: flow.h:451
FLOW_IPV4
#define FLOW_IPV4
Definition: flow.h:96
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:360
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:17
DetectEngineThreadCtx_
Definition: detect.h:1034
alp_tctx
AppLayerParserThreadCtx * alp_tctx
Definition: fuzz_applayerparserparse.c:21
detect.h
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:56
app-layer-parser.h
SigGroupCleanup
int SigGroupCleanup(DetectEngineCtx *de_ctx)
Definition: detect-engine-build.c:2025
SCReturn
#define SCReturn
Definition: util-debug.h:300
AppLayerParserRegisterProtocolUnittests
void AppLayerParserRegisterProtocolUnittests(uint8_t ipproto, AppProto alproto, void(*RegisterUnittests)(void))
Definition: app-layer-parser.c:1824
Packet_
Definition: decode.h:433
detect-engine-build.h
stream-tcp-private.h
ModbusParserRegisterTests
void ModbusParserRegisterTests(void)
Definition: app-layer-modbus.c:1520
SigGroupBuild
int SigGroupBuild(DetectEngineCtx *de_ctx)
Convert the signature list into the runtime match structure.
Definition: detect-engine-build.c:1957
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:307
app-layer-modbus.h
DetectEngineAppendSig
Signature * DetectEngineAppendSig(DetectEngineCtx *de_ctx, const char *sigstr)
Parse and append a Signature into the Detection Engine Context signature list.
Definition: detect-parse.c:2422
Packet_::flow
struct Flow_ * flow
Definition: decode.h:470
DetectEngineThreadCtxInit
TmEcode DetectEngineThreadCtxInit(ThreadVars *, void *, void **)
initialize thread specific detection engine context
Definition: detect-engine.c:3155
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:667
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:1245
suricata-common.h
DetectEngineThreadCtxDeinit
TmEcode DetectEngineThreadCtxDeinit(ThreadVars *, void *)
Definition: detect-engine.c:3369
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:31
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:486
Flow_::flags
uint32_t flags
Definition: flow.h:431
detect-parse.h
Signature_
Signature container.
Definition: detect.h:540
FLOW_PKT_ESTABLISHED
#define FLOW_PKT_ESTABLISHED
Definition: flow.h:225
DetectEngineCtxInit
DetectEngineCtx * DetectEngineCtxInit(void)
Definition: detect-engine.c:2407
DetectEngineCtx_::flags
uint8_t flags
Definition: detect.h:786
AppLayerParserThreadCtx_
Definition: app-layer-parser.c:87
TcpSession_
Definition: stream-tcp-private.h:271
Flow_::alproto
AppProto alproto
application level protocol
Definition: flow.h:460
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
FLOW_DESTROY
#define FLOW_DESTROY(f)
Definition: flow-util.h:129
PKT_STREAM_EST
#define PKT_STREAM_EST
Definition: decode.h:1173
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:469