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