The modbus keyword can be used for matching on various properties of
Modbus requests.
-There are two ways of using this keyword:
+There are three ways of using this keyword:
* matching on functions properties with the setting "function";
-* matching on directly on data access with the setting "access".
+* matching on directly on data access with the setting "access";
+* matching on unit identifier with the setting "unit" only or with the previous setting "function" or "access".
With the setting **function**, you can match on:
modbus: access read discretes, address <100 # Read access at address smaller than 100 of Discretes Input table
modbus: access write holding, address 500, value >200 # Write value greather than 200 at address 500 of Holding Registers table
+With the setting **unit**, you can match on:
+
+* a MODBUS slave address of a remote device connected on the sub-network behind a bridge or a gateway. The destination IP address identifies the bridge itself and the bridge uses the MODBUS unit identifier to forward the request to the right slave device.
+
+Syntax::
+
+ modbus: unit <value>
+ modbus: unit <value>, function <value>
+ modbus: unit <value>, function <value>, subfunction <value>
+ modbus: unit <value>, function [!] <assigned | unassigned | public | user | reserved | all>
+ modbus: unit <value>, access <read | write>
+ modbus: unit <value>, access read <discretes | coils | input | holding>
+ modbus: unit <value>, access read <discretes | coils | input | holding>, address <value>
+ modbus: unit <value>, access write < coils | holding>
+ modbus: unit <value>, access write < coils | holding>, address <value>
+ modbus: unit <value>, access write < coils | holding>, address <value>, value <value>
+
+With _<value>_ setting matches on the address or value as it is being
+accessed or written as follows::
+
+ unit 10 # exactly unit identifier 10
+ unit 10<>20 # greater than unit identifier 10 and smaller than unit identifier 20
+ unit >10 # greater than unit identifier 10
+ unit <10 # smaller than unit identifier 10
+
+Examples::
+
+ modbus: unit 10 # Unit identifier 10
+ modbus: unit 10, function 21 # Unit identifier 10 and write File record function
+ modbus: unit 10, function 4, subfunction 4 # Unit identifier 10 and force Listen Only Mode (Diagnostics) function
+ modbus: unit 10, function assigned # Unit identifier 10 and assigned function
+ modbus: unit 10, function !reserved # Unit identifier 10 and every function but reserved function
+ modbus: unit 10, access read # Unit identifier 10 and Read access
+ modbus: unit 10, access write coils # Unit identifier 10 and Write access to Coils table
+ modbus: unit >10, access read discretes, address <100 # Greater than unit identifier 10 and Read access at address smaller than 100 of Discretes Input table
+ modbus: unit 10<>20, access write holding, address 500, value >200 # Greater than unit identifier 10 and smaller than unit identifier 20 and Write value greather than 200 at address 500 of Holding Registers table
+
(cf. http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf)
**Note:** Address of read and write are starting at 1. So if your system
transaction. In that case, it is important to set the depth of the
stream reassembling as unlimited (stream.reassembly.depth: 0)
+**Note:** According to MODBUS Messaging on TCP/IP Implementation Guide
+V1.0b, the MODBUS slave device addresses on serial line are assigned from 1 to
+247 (decimal). Address 0 is used as broadcast address.
+
(cf. http://www.modbus.org/docs/Modbus_Messaging_Implementation_Guide_V1_0b.pdf)
Paper and presentation (in french) on Modbus support are available :
#define MODBUS_MAX_COUNT 250
/* Modbus Function Code. */
-#define MODBUS_FUNC_NONE 0x00
#define MODBUS_FUNC_READCOILS 0x01
#define MODBUS_FUNC_READDISCINPUTS 0x02
#define MODBUS_FUNC_READHOLDREGS 0x03
/* Check MODBUS Header */
ModbusCheckHeader(modbus, &header);
- /* Store Transaction ID & PDU length */
+ /* Store Unit ID, Transaction ID & PDU length */
+ tx->unit_id = header.unitId;
tx->transactionId = header.transactionId;
tx->length = header.length;
#include "stream-tcp.h"
#include "stream-tcp-private.h"
+/* Modbus Application Protocol Specification V1.1b3 6.1: Read Coils */
+static uint8_t invalidFunctionCode[] = {/* Transaction ID */ 0x00, 0x00,
+ /* Protocol ID */ 0x00, 0x01,
+ /* Length */ 0x00, 0x02,
+ /* Unit ID */ 0x00,
+ /* Function code */ 0x00};
+
/* Modbus Application Protocol Specification V1.1b3 6.1: Read Coils */
/* Example of a request to read discrete outputs 20-38 */
static uint8_t readCoilsReq[] = {/* Transaction ID */ 0x00, 0x00,
Flow f;
TcpSession ssn;
- int result = 0;
+ FAIL_IF_NULL(alp_tctx);
memset(&f, 0, sizeof(f));
memset(&ssn, 0, sizeof(ssn));
int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
STREAM_TOSERVER, readCoilsReq,
sizeof(readCoilsReq));
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
ModbusState *modbus_state = f.alstate;
- if (modbus_state == NULL) {
- printf("no modbus state: ");
- goto end;
- }
+ FAIL_IF_NULL(modbus_state);
ModbusTransaction *tx = ModbusGetTx(modbus_state, 0);
- if ((tx->function != 1) || (tx->read.address != 0x7890) || (tx->read.quantity != 19)) {
- printf("expected function %d, got %" PRIu8 ": ", 1, tx->function);
- printf("expected address %d, got %" PRIu16 ": ", 0x7890, tx->read.address);
- printf("expected quantity %d, got %" PRIu16 ": ", 19, tx->read.quantity);
- goto end;
- }
+ FAIL_IF_NOT(tx->function == 1);
+ FAIL_IF_NOT(tx->read.address == 0x7890);
+ FAIL_IF_NOT(tx->read.quantity == 19);
FLOWLOCK_WRLOCK(&f);
r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
STREAM_TOCLIENT, readCoilsRsp,
sizeof(readCoilsRsp));
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
- if (modbus_state->transaction_max !=1) {
- printf("expected transaction_max %d, got %" PRIu64 ": ", 1, modbus_state->transaction_max);
- goto end;
- }
+ FAIL_IF_NOT(modbus_state->transaction_max == 1);
- result = 1;
-end:
- if (alp_tctx != NULL)
- AppLayerParserThreadCtxFree(alp_tctx);
+ AppLayerParserThreadCtxFree(alp_tctx);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
- return result;
+ PASS;
}
/** \test Send Modbus Write Multiple registers request/response. */
Flow f;
TcpSession ssn;
- int result = 0;
+ FAIL_IF_NULL(alp_tctx);
memset(&f, 0, sizeof(f));
memset(&ssn, 0, sizeof(ssn));
int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
STREAM_TOSERVER, writeMultipleRegistersReq,
sizeof(writeMultipleRegistersReq));
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
ModbusState *modbus_state = f.alstate;
- if (modbus_state == NULL) {
- printf("no modbus state: ");
- goto end;
- }
+ FAIL_IF_NULL(modbus_state);
ModbusTransaction *tx = ModbusGetTx(modbus_state, 0);
- if ((tx->function != 16) || (tx->write.address != 0x01) || (tx->write.quantity != 2) ||
- (tx->write.count != 4) || (tx->data[0] != 0x000A) || (tx->data[1] != 0x0102)) {
- printf("expected function %d, got %" PRIu8 ": ", 16, tx->function);
- printf("expected write address %d, got %" PRIu16 ": ", 0x01, tx->write.address);
- printf("expected write quantity %d, got %" PRIu16 ": ", 2, tx->write.quantity);
- printf("expected write count %d, got %" PRIu8 ": ", 4, tx->write.count);
- printf("expected data %d, got %" PRIu16 ": ", 0x000A, tx->data[0]);
- printf("expected data %d, got %" PRIu16 ": ", 0x0102, tx->data[1]);
- goto end;
- }
+ FAIL_IF_NOT(tx->function == 16);
+ FAIL_IF_NOT(tx->write.address == 0x01);
+ FAIL_IF_NOT(tx->write.quantity == 2);
+ FAIL_IF_NOT(tx->write.count == 4);
+ FAIL_IF_NOT(tx->data[0] == 0x000A);
+ FAIL_IF_NOT(tx->data[1] == 0x0102);
FLOWLOCK_WRLOCK(&f);
r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
STREAM_TOCLIENT, writeMultipleRegistersRsp,
sizeof(writeMultipleRegistersRsp));
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
- if (modbus_state->transaction_max !=1) {
- printf("expected transaction_max %d, got %" PRIu64 ": ", 1, modbus_state->transaction_max);
- goto end;
- }
+ FAIL_IF_NOT(modbus_state->transaction_max == 1);
- result = 1;
-end:
- if (alp_tctx != NULL)
- AppLayerParserThreadCtxFree(alp_tctx);
+ AppLayerParserThreadCtxFree(alp_tctx);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
- return result;
+ PASS;
}
/** \test Send Modbus Read/Write Multiple registers request/response with mismatch value. */
TcpSession ssn;
ThreadVars tv;
- int result = 0;
+ FAIL_IF_NULL(alp_tctx);
memset(&tv, 0, sizeof(ThreadVars));
memset(&f, 0, sizeof(Flow));
StreamTcpInitConfig(TRUE);
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
- if (de_ctx == NULL)
- goto end;
+ FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
"app-layer-event: "
"modbus.value_mismatch; "
"sid:1;)");
- if (s == NULL)
- goto end;
+ FAIL_IF_NULL(s);
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
STREAM_TOSERVER,
readWriteMultipleRegistersReq,
sizeof(readWriteMultipleRegistersReq));
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
ModbusState *modbus_state = f.alstate;
- if (modbus_state == NULL) {
- printf("no modbus state: ");
- goto end;
- }
+ FAIL_IF_NULL(modbus_state);
ModbusTransaction *tx = ModbusGetTx(modbus_state, 0);
- if ((tx->function != 23) || (tx->read.address != 0x03) || (tx->read.quantity != 6) ||
- (tx->write.address != 0x0E) || (tx->write.quantity != 3) || (tx->write.count != 6) ||
- (tx->data[0] != 0x1234) || (tx->data[1] != 0x5678) || (tx->data[2] != 0x9ABC)) {
- printf("expected function %d, got %" PRIu8 ": ", 23, tx->function);
- printf("expected read address %d, got %" PRIu16 ": ", 0x03, tx->read.address);
- printf("expected read quantity %d, got %" PRIu16 ": ", 6, tx->read.quantity);
- printf("expected write address %d, got %" PRIu16 ": ", 0x0E, tx->write.address);
- printf("expected write quantity %d, got %" PRIu16 ": ", 3, tx->write.quantity);
- printf("expected write count %d, got %" PRIu8 ": ", 6, tx->write.count);
- printf("expected data %d, got %" PRIu16 ": ", 0x1234, tx->data[0]);
- printf("expected data %d, got %" PRIu16 ": ", 0x5678, tx->data[1]);
- printf("expected data %d, got %" PRIu16 ": ", 0x9ABC, tx->data[2]);
- goto end;
- }
+ FAIL_IF_NOT(tx->function == 23);
+ FAIL_IF_NOT(tx->read.address == 0x03);
+ FAIL_IF_NOT(tx->read.quantity == 6);
+ FAIL_IF_NOT(tx->write.address == 0x0E);
+ FAIL_IF_NOT(tx->write.quantity == 3);
+ FAIL_IF_NOT(tx->write.count == 6);
+ FAIL_IF_NOT(tx->data[0] == 0x1234);
+ FAIL_IF_NOT(tx->data[1] == 0x5678);
+ FAIL_IF_NOT(tx->data[2] == 0x9ABC);
FLOWLOCK_WRLOCK(&f);
r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
STREAM_TOCLIENT, readWriteMultipleRegistersRsp,
sizeof(readWriteMultipleRegistersRsp));
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
- if (modbus_state->transaction_max !=1) {
- printf("expected transaction_max %d, got %" PRIu64 ": ", 1, modbus_state->transaction_max);
- goto end;
- }
+ FAIL_IF_NOT(modbus_state->transaction_max == 1);
/* do detect */
SigMatchSignatures(&tv, de_ctx, det_ctx, p);
- if (!PacketAlertCheck(p, 1)) {
- printf("sid 1 didn't match. Should have matched: ");
- goto end;
- }
+ FAIL_IF_NOT(PacketAlertCheck(p, 1));
- result = 1;
-end:
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
DetectEngineCtxFree(de_ctx);
- if (alp_tctx != NULL)
- AppLayerParserThreadCtxFree(alp_tctx);
+ AppLayerParserThreadCtxFree(alp_tctx);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
UTHFreePackets(&p, 1);
- return result;
+ PASS;
}
/** \test Send Modbus Force Listen Only Mode request. */
Flow f;
TcpSession ssn;
- int result = 0;
+ FAIL_IF_NULL(alp_tctx);
memset(&f, 0, sizeof(f));
memset(&ssn, 0, sizeof(ssn));
int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
STREAM_TOSERVER, forceListenOnlyMode,
sizeof(forceListenOnlyMode));
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
ModbusState *modbus_state = f.alstate;
- if (modbus_state == NULL) {
- printf("no modbus state: ");
- goto end;
- }
+ FAIL_IF_NULL(modbus_state);
ModbusTransaction *tx = ModbusGetTx(modbus_state, 0);
- if ((tx->function != 8) || (tx->subFunction != 4)) {
- printf("expected function %d, got %" PRIu8 ": ", 8, tx->function);
- printf("expected sub-function %d, got %" PRIu16 ": ", 0x04, tx->subFunction);
- goto end;
- }
+ FAIL_IF_NOT(tx->function == 8);
+ FAIL_IF_NOT(tx->subFunction == 4);
- result = 1;
-end:
- if (alp_tctx != NULL)
- AppLayerParserThreadCtxFree(alp_tctx);
+ AppLayerParserThreadCtxFree(alp_tctx);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
- return result;
+ PASS;
}
/** \test Send Modbus invalid Protocol version in request. */
TcpSession ssn;
ThreadVars tv;
- int result = 0;
+ FAIL_IF_NULL(alp_tctx);
memset(&tv, 0, sizeof(ThreadVars));
memset(&f, 0, sizeof(Flow));
StreamTcpInitConfig(TRUE);
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
- if (de_ctx == NULL)
- goto end;
+ FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
"app-layer-event: "
"modbus.invalid_protocol_id; "
"sid:1;)");
- if (s == NULL)
- goto end;
+ FAIL_IF_NULL(s);
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
STREAM_TOSERVER, invalidProtocolIdReq,
sizeof(invalidProtocolIdReq));
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
ModbusState *modbus_state = f.alstate;
- if (modbus_state == NULL) {
- printf("no modbus state: ");
- goto end;
- }
+ FAIL_IF_NULL(modbus_state);
/* do detect */
SigMatchSignatures(&tv, de_ctx, det_ctx, p);
- if (!PacketAlertCheck(p, 1)) {
- printf("sid 1 didn't match. Should have matched: ");
- goto end;
- }
+ FAIL_IF_NOT(PacketAlertCheck(p, 1));
- result = 1;
-end:
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
DetectEngineCtxFree(de_ctx);
- if (alp_tctx != NULL)
- AppLayerParserThreadCtxFree(alp_tctx);
+ AppLayerParserThreadCtxFree(alp_tctx);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
UTHFreePackets(&p, 1);
- return result;
+ PASS;
}
/** \test Send Modbus unsolicited response. */
TcpSession ssn;
ThreadVars tv;
- int result = 0;
+ FAIL_IF_NULL(alp_tctx);
memset(&tv, 0, sizeof(ThreadVars));
memset(&f, 0, sizeof(Flow));
StreamTcpInitConfig(TRUE);
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
- if (de_ctx == NULL)
- goto end;
+ FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
"app-layer-event: "
"modbus.unsolicited_response; "
"sid:1;)");
- if (s == NULL)
- goto end;
+ FAIL_IF_NULL(s);
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
STREAM_TOCLIENT, readCoilsRsp,
sizeof(readCoilsRsp));
- if (r != 0) {
- printf("toclient chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
ModbusState *modbus_state = f.alstate;
- if (modbus_state == NULL) {
- printf("no modbus state: ");
- goto end;
- }
+ FAIL_IF_NULL(modbus_state);
/* do detect */
SigMatchSignatures(&tv, de_ctx, det_ctx, p);
- if (!PacketAlertCheck(p, 1)) {
- printf("sid 1 didn't match. Should have matched: ");
- goto end;
- }
+ FAIL_IF_NOT(PacketAlertCheck(p, 1));
- result = 1;
-end:
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
DetectEngineCtxFree(de_ctx);
- if (alp_tctx != NULL)
- AppLayerParserThreadCtxFree(alp_tctx);
+ AppLayerParserThreadCtxFree(alp_tctx);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
UTHFreePackets(&p, 1);
- return result;
+ PASS;
}
/** \test Send Modbus invalid Length request. */
TcpSession ssn;
ThreadVars tv;
- int result = 0;
+ FAIL_IF_NULL(alp_tctx);
memset(&tv, 0, sizeof(ThreadVars));
memset(&f, 0, sizeof(Flow));
StreamTcpInitConfig(TRUE);
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
- if (de_ctx == NULL)
- goto end;
+ FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
"app-layer-event: "
"modbus.invalid_length; "
"sid:1;)");
- if (s == NULL)
- goto end;
+ FAIL_IF_NULL(s);
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
STREAM_TOSERVER,
invalidLengthWriteMultipleRegistersReq,
sizeof(invalidLengthWriteMultipleRegistersReq));
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
ModbusState *modbus_state = f.alstate;
- if (modbus_state == NULL) {
- printf("no modbus state: ");
- goto end;
- }
+ FAIL_IF_NULL(modbus_state);
/* do detect */
SigMatchSignatures(&tv, de_ctx, det_ctx, p);
- if (!PacketAlertCheck(p, 1)) {
- printf("sid 1 didn't match. Should have matched: ");
- goto end;
- }
+ FAIL_IF_NOT(PacketAlertCheck(p, 1));
- result = 1;
-end:
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
DetectEngineCtxFree(de_ctx);
- if (alp_tctx != NULL)
- AppLayerParserThreadCtxFree(alp_tctx);
+ AppLayerParserThreadCtxFree(alp_tctx);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
UTHFreePackets(&p, 1);
- return result;
+ PASS;
}
/** \test Send Modbus Read Coils request and error response with Exception code invalid. */
TcpSession ssn;
ThreadVars tv;
- int result = 0;
+ FAIL_IF_NULL(alp_tctx);
memset(&tv, 0, sizeof(ThreadVars));
memset(&f, 0, sizeof(Flow));
StreamTcpInitConfig(TRUE);
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
- if (de_ctx == NULL)
- goto end;
+ FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
"app-layer-event: "
"modbus.invalid_exception_code; "
"sid:1;)");
- if (s == NULL)
- goto end;
+ FAIL_IF_NULL(s);
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
STREAM_TOSERVER, readCoilsReq,
sizeof(readCoilsReq));
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
ModbusState *modbus_state = f.alstate;
- if (modbus_state == NULL) {
- printf("no modbus state: ");
- goto end;
- }
+ FAIL_IF_NULL(modbus_state);
ModbusTransaction *tx = ModbusGetTx(modbus_state, 0);
- if ((tx->function != 1) || (tx->read.address != 0x7890) || (tx->read.quantity != 19)) {
- printf("expected function %d, got %" PRIu8 ": ", 1, tx->function);
- printf("expected address %d, got %" PRIu16 ": ", 0x7890, tx->read.address);
- printf("expected quantity %d, got %" PRIu16 ": ", 19, tx->read.quantity);
- goto end;
- }
+ FAIL_IF_NOT(tx->function == 1);
+ FAIL_IF_NOT(tx->read.address == 0x7890);
+ FAIL_IF_NOT(tx->read.quantity == 19);
FLOWLOCK_WRLOCK(&f);
r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
STREAM_TOCLIENT, readCoilsErrorRsp,
sizeof(readCoilsErrorRsp));
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
- if (modbus_state->transaction_max !=1) {
- printf("expected transaction_max %d, got %" PRIu64 ": ", 1, modbus_state->transaction_max);
- goto end;
- }
+ FAIL_IF_NOT(modbus_state->transaction_max == 1);
/* do detect */
SigMatchSignatures(&tv, de_ctx, det_ctx, p);
- if (!PacketAlertCheck(p, 1)) {
- printf("sid 1 didn't match. Should have matched: ");
- goto end;
- }
+ FAIL_IF_NOT(PacketAlertCheck(p, 1));
- result = 1;
-end:
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
DetectEngineCtxFree(de_ctx);
- if (alp_tctx != NULL)
- AppLayerParserThreadCtxFree(alp_tctx);
+ AppLayerParserThreadCtxFree(alp_tctx);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
UTHFreePackets(&p, 1);
- return result;
+ PASS;
}
/** \test Modbus fragmentation - 1 ADU over 2 TCP packets. */
uint32_t input_len = sizeof(readCoilsReq), part2_len = 3;
uint8_t *input = readCoilsReq;
- int result = 0;
+ FAIL_IF_NULL(alp_tctx);
memset(&f, 0, sizeof(f));
memset(&ssn, 0, sizeof(ssn));
FLOWLOCK_WRLOCK(&f);
int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
STREAM_TOSERVER, input, input_len - part2_len);
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
STREAM_TOSERVER, input, input_len);
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
ModbusState *modbus_state = f.alstate;
- if (modbus_state == NULL) {
- printf("no modbus state: ");
- goto end;
- }
+ FAIL_IF_NULL(modbus_state);
ModbusTransaction *tx = ModbusGetTx(modbus_state, 0);
- if ((tx->function != 1) || (tx->read.address != 0x7890) || (tx->read.quantity != 19)) {
- printf("expected function %d, got %" PRIu8 ": ", 1, tx->function);
- printf("expected address %d, got %" PRIu16 ": ", 0x7890, tx->read.address);
- printf("expected quantity %d, got %" PRIu16 ": ", 19, tx->read.quantity);
- goto end;
- }
+ FAIL_IF_NOT(tx->function == 1);
+ FAIL_IF_NOT(tx->read.address == 0x7890);
+ FAIL_IF_NOT(tx->read.quantity == 19);
input_len = sizeof(readCoilsRsp);
part2_len = 10;
FLOWLOCK_WRLOCK(&f);
r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
STREAM_TOCLIENT, input, input_len - part2_len);
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
STREAM_TOCLIENT, input, input_len);
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
- if (modbus_state->transaction_max !=1) {
- printf("expected transaction_max %d, got %" PRIu64 ": ", 1, modbus_state->transaction_max);
- goto end;
- }
+ FAIL_IF_NOT(modbus_state->transaction_max ==1);
- result = 1;
-end:
- if (alp_tctx != NULL)
- AppLayerParserThreadCtxFree(alp_tctx);
+ AppLayerParserThreadCtxFree(alp_tctx);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
- return result;
+ PASS;
}
/** \test Modbus fragmentation - 2 ADU in 1 TCP packet. */
Flow f;
TcpSession ssn;
- int result = 0;
+ FAIL_IF_NULL(alp_tctx);
input = (uint8_t *) SCMalloc (input_len * sizeof(uint8_t));
- if (unlikely(input == NULL))
- goto end;
+ FAIL_IF_NULL(input);
memcpy(input, readCoilsReq, sizeof(readCoilsReq));
memcpy(input + sizeof(readCoilsReq), writeMultipleRegistersReq, sizeof(writeMultipleRegistersReq));
FLOWLOCK_WRLOCK(&f);
int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
STREAM_TOSERVER, input, input_len);
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
ModbusState *modbus_state = f.alstate;
- if (modbus_state == NULL) {
- printf("no modbus state: ");
- goto end;
- }
+ FAIL_IF_NULL(modbus_state);
- if (modbus_state->transaction_max !=2) {
- printf("expected transaction_max %d, got %" PRIu64 ": ", 2, modbus_state->transaction_max);
- goto end;
- }
+ FAIL_IF_NOT(modbus_state->transaction_max == 2);
ModbusTransaction *tx = ModbusGetTx(modbus_state, 1);
- if ((tx->function != 16) || (tx->write.address != 0x01) || (tx->write.quantity != 2) ||
- (tx->write.count != 4) || (tx->data[0] != 0x000A) || (tx->data[1] != 0x0102)) {
- printf("expected function %d, got %" PRIu8 ": ", 16, tx->function);
- printf("expected write address %d, got %" PRIu16 ": ", 0x01, tx->write.address);
- printf("expected write quantity %d, got %" PRIu16 ": ", 2, tx->write.quantity);
- printf("expected write count %d, got %" PRIu8 ": ", 4, tx->write.count);
- printf("expected data %d, got %" PRIu16 ": ", 0x000A, tx->data[0]);
- printf("expected data %d, got %" PRIu16 ": ", 0x0102, tx->data[1]);
- goto end;
- }
+ FAIL_IF_NOT(tx->function == 16);
+ FAIL_IF_NOT(tx->write.address == 0x01);
+ FAIL_IF_NOT(tx->write.quantity == 2);
+ FAIL_IF_NOT(tx->write.count == 4);
+ FAIL_IF_NOT(tx->data[0] == 0x000A);
+ FAIL_IF_NOT(tx->data[1] == 0x0102);
input_len = sizeof(readCoilsRsp) + sizeof(writeMultipleRegistersRsp);
ptr = (uint8_t *) SCRealloc (input, input_len * sizeof(uint8_t));
- if (unlikely(ptr == NULL))
- goto end;
+ FAIL_IF_NULL(ptr);
input = ptr;
memcpy(input, readCoilsRsp, sizeof(readCoilsRsp));
FLOWLOCK_WRLOCK(&f);
r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
STREAM_TOCLIENT, input, sizeof(input_len));
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
- result = 1;
-end:
- if (input != NULL)
- SCFree(input);
- if (alp_tctx != NULL)
- AppLayerParserThreadCtxFree(alp_tctx);
+ SCFree(input);
+ AppLayerParserThreadCtxFree(alp_tctx);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
- return result;
+ PASS;
}
/** \test Send Modbus exceed Length request. */
TcpSession ssn;
ThreadVars tv;
- int result = 0;
+ FAIL_IF(alp_tctx == NULL);
memset(&tv, 0, sizeof(ThreadVars));
memset(&f, 0, sizeof(Flow));
StreamTcpInitConfig(TRUE);
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
- if (de_ctx == NULL)
- goto end;
+ FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
"app-layer-event: "
"modbus.invalid_length; "
"sid:1;)");
- if (s == NULL)
- goto end;
+ FAIL_IF_NULL(s);
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
STREAM_TOSERVER,
exceededLengthWriteMultipleRegistersReq,
sizeof(exceededLengthWriteMultipleRegistersReq) + 65523 * sizeof(uint8_t));
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
ModbusState *modbus_state = f.alstate;
- if (modbus_state == NULL) {
- printf("no modbus state: ");
- goto end;
- }
+ FAIL_IF_NULL(modbus_state);
/* do detect */
SigMatchSignatures(&tv, de_ctx, det_ctx, p);
- if (!PacketAlertCheck(p, 1)) {
- printf("sid 1 didn't match. Should have matched: ");
- goto end;
- }
+ FAIL_IF_NOT(PacketAlertCheck(p, 1));
- result = 1;
-end:
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
DetectEngineCtxFree(de_ctx);
- if (alp_tctx != NULL)
- AppLayerParserThreadCtxFree(alp_tctx);
+ AppLayerParserThreadCtxFree(alp_tctx);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
UTHFreePackets(&p, 1);
- return result;
+ PASS;
}
/** \test Send Modbus invalid PDU Length. */
TcpSession ssn;
ThreadVars tv;
- int result = 0;
+ FAIL_IF_NULL(alp_tctx);
memset(&tv, 0, sizeof(ThreadVars));
memset(&f, 0, sizeof(Flow));
StreamTcpInitConfig(TRUE);
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
- if (de_ctx == NULL)
- goto end;
+ FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
"app-layer-event: "
"modbus.invalid_length; "
"sid:1;)");
- if (s == NULL)
- goto end;
+ FAIL_IF_NULL(s);
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
STREAM_TOSERVER,
invalidLengthPDUWriteMultipleRegistersReq,
sizeof(invalidLengthPDUWriteMultipleRegistersReq));
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
ModbusState *modbus_state = f.alstate;
- if (modbus_state == NULL) {
- printf("no modbus state: ");
- goto end;
- }
+ FAIL_IF_NULL(modbus_state);
/* do detect */
SigMatchSignatures(&tv, de_ctx, det_ctx, p);
- if (!PacketAlertCheck(p, 1)) {
- printf("sid 1 didn't match. Should have matched: ");
- goto end;
- }
+ FAIL_IF_NOT(PacketAlertCheck(p, 1));
- result = 1;
-end:
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
DetectEngineCtxFree(de_ctx);
- if (alp_tctx != NULL)
- AppLayerParserThreadCtxFree(alp_tctx);
+ AppLayerParserThreadCtxFree(alp_tctx);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
UTHFreePackets(&p, 1);
- return result;
+ PASS;
}
/** \test Send Modbus Mask Write register request/response. */
Flow f;
TcpSession ssn;
- int result = 0;
+ FAIL_IF_NULL(alp_tctx);
memset(&f, 0, sizeof(f));
memset(&ssn, 0, sizeof(ssn));
int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
STREAM_TOSERVER, maskWriteRegisterReq,
sizeof(maskWriteRegisterReq));
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
ModbusState *modbus_state = f.alstate;
- if (modbus_state == NULL) {
- printf("no modbus state: ");
- goto end;
- }
+ FAIL_IF_NULL(modbus_state);
ModbusTransaction *tx = ModbusGetTx(modbus_state, 0);
- if ((tx->function != 22) || (tx->data[0] != 0x00F2) || (tx->data[1] != 0x0025)) {
- printf("expected function %d, got %" PRIu8 ": ", 16, tx->function);
- printf("expected And_Mask %d, got %" PRIu16 ": ", 0x00F2, tx->data[0]);
- printf("expected Or_Mask %d, got %" PRIu16 ": ", 0x0025, tx->data[1]);
- goto end;
- }
+ FAIL_IF_NOT(tx->function == 22);
+ FAIL_IF_NOT(tx->data[0] == 0x00F2);
+ FAIL_IF_NOT(tx->data[1] == 0x0025);
FLOWLOCK_WRLOCK(&f);
r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
STREAM_TOCLIENT, maskWriteRegisterRsp,
sizeof(maskWriteRegisterRsp));
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
- if (modbus_state->transaction_max !=1) {
- printf("expected transaction_max %d, got %" PRIu64 ": ", 1, modbus_state->transaction_max);
- goto end;
- }
+ FAIL_IF_NOT(modbus_state->transaction_max == 1);
- result = 1;
-end:
- if (alp_tctx != NULL)
- AppLayerParserThreadCtxFree(alp_tctx);
+ AppLayerParserThreadCtxFree(alp_tctx);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
- return result;
+ PASS;
}
/** \test Send Modbus Write single register request/response. */
Flow f;
TcpSession ssn;
- int result = 0;
+ FAIL_IF_NULL(alp_tctx);
memset(&f, 0, sizeof(f));
memset(&ssn, 0, sizeof(ssn));
int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
STREAM_TOSERVER, writeSingleRegisterReq,
sizeof(writeSingleRegisterReq));
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
ModbusState *modbus_state = f.alstate;
- if (modbus_state == NULL) {
- printf("no modbus state: ");
- goto end;
- }
+ FAIL_IF_NULL(modbus_state);
ModbusTransaction *tx = ModbusGetTx(modbus_state, 0);
- if ((tx->function != 6) || (tx->write.address != 0x0001) || (tx->data[0] != 0x0003)) {
- printf("expected function %d, got %" PRIu8 ": ", 16, tx->function);
- printf("expected write address %d, got %" PRIu16 ": ", 0x01, tx->write.address);
- printf("expected data %d, got %" PRIu16 ": ", 0x03, tx->data[0]);
- goto end;
- }
+ FAIL_IF_NOT(tx->function == 6);
+ FAIL_IF_NOT(tx->write.address == 0x0001);
+ FAIL_IF_NOT(tx->data[0] == 0x0003);
FLOWLOCK_WRLOCK(&f);
r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
STREAM_TOCLIENT, writeSingleRegisterRsp,
sizeof(writeSingleRegisterRsp));
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
- if (modbus_state->transaction_max !=1) {
- printf("expected transaction_max %d, got %" PRIu64 ": ", 1, modbus_state->transaction_max);
- goto end;
- }
+ FAIL_IF_NOT(modbus_state->transaction_max == 1);
- result = 1;
-end:
- if (alp_tctx != NULL)
- AppLayerParserThreadCtxFree(alp_tctx);
+ AppLayerParserThreadCtxFree(alp_tctx);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
- return result;
+ PASS;
}
/** \test Send invalid Modbus Mask Write register request. */
TcpSession ssn;
ThreadVars tv;
- int result = 0;
+ FAIL_IF_NULL(alp_tctx);
memset(&tv, 0, sizeof(ThreadVars));
memset(&f, 0, sizeof(f));
StreamTcpInitConfig(TRUE);
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
- if (de_ctx == NULL)
- goto end;
+ FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
"app-layer-event: "
"modbus.invalid_length; "
"sid:1;)");
- if (s == NULL)
- goto end;
+ FAIL_IF_NULL(s);
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
STREAM_TOSERVER, invalidMaskWriteRegisterReq,
sizeof(invalidMaskWriteRegisterReq));
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
ModbusState *modbus_state = f.alstate;
- if (modbus_state == NULL) {
- printf("no modbus state: ");
- goto end;
- }
+ FAIL_IF_NULL(modbus_state);
ModbusTransaction *tx = ModbusGetTx(modbus_state, 0);
- if (tx->function != 22) {
- printf("expected function %d, got %" PRIu8 ": ", 16, tx->function);
- goto end;
- }
+ FAIL_IF_NOT(tx->function == 22);
/* do detect */
SigMatchSignatures(&tv, de_ctx, det_ctx, p);
- if (!PacketAlertCheck(p, 1)) {
- printf("sid 1 didn't match. Should have matched: ");
- goto end;
- }
+ FAIL_IF_NOT(PacketAlertCheck(p, 1));
FLOWLOCK_WRLOCK(&f);
r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
STREAM_TOCLIENT, maskWriteRegisterRsp,
sizeof(maskWriteRegisterRsp));
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
- if (modbus_state->transaction_max !=1) {
- printf("expected transaction_max %d, got %" PRIu64 ": ", 1, modbus_state->transaction_max);
- goto end;
- }
+ FAIL_IF_NOT(modbus_state->transaction_max == 1);
- result = 1;
-end:
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
DetectEngineCtxFree(de_ctx);
- if (alp_tctx != NULL)
- AppLayerParserThreadCtxFree(alp_tctx);
+ AppLayerParserThreadCtxFree(alp_tctx);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
UTHFreePackets(&p, 1);
- return result;
+ PASS;
}
/** \test Send invalid Modbus Mask Write register request. */
TcpSession ssn;
ThreadVars tv;
- int result = 0;
+ FAIL_IF_NULL(alp_tctx);
memset(&tv, 0, sizeof(ThreadVars));
memset(&f, 0, sizeof(f));
StreamTcpInitConfig(TRUE);
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
- if (de_ctx == NULL)
- goto end;
+ FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
"app-layer-event: "
"modbus.invalid_length; "
"sid:1;)");
- if (s == NULL)
- goto end;
+ FAIL_IF_NULL(s);
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
STREAM_TOSERVER,
invalidWriteSingleRegisterReq,
sizeof(invalidWriteSingleRegisterReq));
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
ModbusState *modbus_state = f.alstate;
- if (modbus_state == NULL) {
- printf("no modbus state: ");
- goto end;
- }
+ FAIL_IF_NULL(modbus_state);
ModbusTransaction *tx = ModbusGetTx(modbus_state, 0);
- if ((tx->function != 6) || (tx->write.address != 0x0001)) {
- printf("expected function %d, got %" PRIu8 ": ", 16, tx->function);
- printf("expected write address %d, got %" PRIu16 ": ", 0x01, tx->write.address);
- goto end;
- }
+ FAIL_IF_NOT(tx->function == 6);
+ FAIL_IF_NOT(tx->write.address == 0x0001);
/* do detect */
SigMatchSignatures(&tv, de_ctx, det_ctx, p);
- if (!PacketAlertCheck(p, 1)) {
- printf("sid 1 didn't match. Should have matched: ");
- goto end;
- }
+ FAIL_IF_NOT(PacketAlertCheck(p, 1));
FLOWLOCK_WRLOCK(&f);
r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
STREAM_TOCLIENT, writeSingleRegisterRsp,
sizeof(writeSingleRegisterRsp));
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
- if (modbus_state->transaction_max !=1) {
- printf("expected transaction_max %d, got %" PRIu64 ": ", 1, modbus_state->transaction_max);
- goto end;
- }
+ FAIL_IF_NOT(modbus_state->transaction_max == 1);
- result = 1;
-end:
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
DetectEngineCtxFree(de_ctx);
- if (alp_tctx != NULL)
- AppLayerParserThreadCtxFree(alp_tctx);
+ AppLayerParserThreadCtxFree(alp_tctx);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
UTHFreePackets(&p, 1);
- return result;
-}
+ PASS;}
/** \test Checks if stream_depth is correct */
static int ModbusParserTest17(void) {
Flow f;
TcpSession ssn;
- FAIL_IF(alp_tctx == NULL);
+ FAIL_IF_NULL(alp_tctx);
memset(&f, 0, sizeof(f));
memset(&ssn, 0, sizeof(ssn));
uint32_t input_len = sizeof(readCoilsReq), part2_len = 3;
uint8_t *input = readCoilsReq;
- FAIL_IF(alp_tctx == NULL);
+ FAIL_IF_NULL(alp_tctx);
memset(&f, 0, sizeof(f));
memset(&ssn, 0, sizeof(ssn));
FLOW_DESTROY(&f);
PASS;
}
+
+/** \test Send Modbus invalid function. */
+static int ModbusParserTest19(void) {
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+ DetectEngineThreadCtx *det_ctx = NULL;
+ Flow f;
+ Packet *p = NULL;
+ Signature *s = NULL;
+ TcpSession ssn;
+ ThreadVars tv;
+
+ FAIL_IF_NULL(alp_tctx);
+
+ memset(&tv, 0, sizeof(ThreadVars));
+ memset(&f, 0, sizeof(Flow));
+ memset(&ssn, 0, sizeof(TcpSession));
+
+ p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
+
+ FLOW_INITIALIZE(&f);
+ f.alproto = ALPROTO_MODBUS;
+ f.protoctx = (void *)&ssn;
+ f.proto = IPPROTO_TCP;
+ f.alproto = ALPROTO_MODBUS;
+ f.flags |= FLOW_IPV4;
+
+ p->flow = &f;
+ p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
+ p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED;
+
+ StreamTcpInitConfig(TRUE);
+
+ DetectEngineCtx *de_ctx = DetectEngineCtxInit();
+ FAIL_IF_NULL(de_ctx);
+
+ de_ctx->flags |= DE_QUIET;
+ s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
+ "(msg:\"Modbus invalid Function code\"; "
+ "app-layer-event: "
+ "modbus.invalid_function_code; "
+ "sid:1;)");
+ FAIL_IF_NULL(s);
+
+ SigGroupBuild(de_ctx);
+ DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
+
+ FLOWLOCK_WRLOCK(&f);
+ int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
+ STREAM_TOSERVER,
+ invalidFunctionCode,
+ sizeof(invalidFunctionCode));
+ FAIL_IF_NOT(r == 0);
+ FLOWLOCK_UNLOCK(&f);
+
+ ModbusState *modbus_state = f.alstate;
+ FAIL_IF_NULL(modbus_state);
+
+ /* do detect */
+ SigMatchSignatures(&tv, de_ctx, det_ctx, p);
+
+ FAIL_IF_NOT(PacketAlertCheck(p, 1));
+
+ SigGroupCleanup(de_ctx);
+ SigCleanSignatures(de_ctx);
+
+ DetectEngineThreadCtxDeinit(&tv, (void *)det_ctx);
+ DetectEngineCtxFree(de_ctx);
+
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ FLOW_DESTROY(&f);
+ UTHFreePackets(&p, 1);
+ PASS;
+}
#endif /* UNITTESTS */
void ModbusParserRegisterTests(void) {
ModbusParserTest17);
UtRegisterTest("ModbusParserTest18 - Modbus stream depth in 2 TCP packets",
ModbusParserTest18);
+ UtRegisterTest("ModbusParserTest19 - Modbus invalid Function code",
+ ModbusParserTest19);
#endif /* UNITTESTS */
}
#define MODBUS_TYP_WRITE_MULTIPLE (MODBUS_TYP_WRITE | MODBUS_TYP_MULTIPLE)
#define MODBUS_TYP_READ_WRITE_MULTIPLE (MODBUS_TYP_READ | MODBUS_TYP_WRITE | MODBUS_TYP_MULTIPLE)
+/* Modbus Function Code. */
+#define MODBUS_FUNC_NONE 0x00
+
/* Modbus Transaction Structure, request/response. */
typedef struct ModbusTransaction_ {
struct ModbusState_ *modbus;
uint32_t logged; /**< flags indicating which loggers have logged */
uint16_t transactionId;
uint16_t length;
+ uint8_t unit_id;
uint8_t function;
uint8_t category;
uint8_t type;
SCReturnInt(0);
}
+ if (modbus->unit_id != NULL) {
+ if (DetectEngineInspectModbusValueMatch(modbus->unit_id, tx->unit_id, 0) == 0) {
+ SCReturnInt(0);
+ } else {
+ ret = 1;
+ }
+ }
+
if (modbus->type == MODBUS_TYP_NONE) {
if (modbus->category == MODBUS_CAT_NONE) {
- if (modbus->function == tx->function) {
- if (modbus->subfunction != NULL) {
- SCLogDebug("looking for Modbus server function %d and subfunction %d",
- modbus->function, *(modbus->subfunction));
- ret = (*(modbus->subfunction) == (tx->subFunction))? 1 : 0;
+ if (modbus->function != MODBUS_FUNC_NONE) {
+ if (modbus->function == tx->function) {
+ if (modbus->subfunction != NULL) {
+ SCLogDebug("looking for Modbus server function %d and subfunction %d",
+ modbus->function, *(modbus->subfunction));
+ ret = (*(modbus->subfunction) == (tx->subFunction))? 1 : 0;
+ } else {
+ SCLogDebug("looking for Modbus server function %d", modbus->function);
+ ret = 1;
+ }
} else {
- SCLogDebug("looking for Modbus server function %d", modbus->function);
- ret = 1;
+ ret = 0;
}
}
} else {
uint8_t access = modbus->type & MODBUS_TYP_ACCESS_MASK;
uint8_t function = modbus->type & MODBUS_TYP_ACCESS_FUNCTION_MASK;
- if ((access & tx->type) && ((function == MODBUS_TYP_NONE) || (function & tx->type))) {
- if (modbus->address != NULL) {
- ret = DetectEngineInspectModbusAddress(tx, modbus->address, access);
+ if (access != MODBUS_TYP_NONE) {
+ if ((access & tx->type) && ((function == MODBUS_TYP_NONE) || (function & tx->type))) {
+ if (modbus->address != NULL) {
+ ret = DetectEngineInspectModbusAddress(tx, modbus->address, access);
- if (ret && (modbus->data != NULL)) {
- ret = DetectEngineInspectModbusData(tx, modbus->address->min, modbus->data);
+ if (ret && (modbus->data != NULL)) {
+ ret = DetectEngineInspectModbusData(tx, modbus->address->min, modbus->data);
+ }
+ } else {
+ SCLogDebug("looking for Modbus access type %d and function type %d", access, function);
+ ret = 1;
}
} else {
- SCLogDebug("looking for Modbus access type %d and function type %d", access, function);
- ret = 1;
+ ret = 0;
}
}
}
static uint8_t readCoilsReq[] = {/* Transaction ID */ 0x00, 0x00,
/* Protocol ID */ 0x00, 0x00,
/* Length */ 0x00, 0x06,
- /* Unit ID */ 0x00,
+ /* Unit ID */ 0x0a,
/* Function code */ 0x01,
/* Starting Address */ 0x78, 0x90,
/* Quantity of coils */ 0x00, 0x13 };
static uint8_t readWriteMultipleRegistersReq[] = {/* Transaction ID */ 0x12, 0x34,
/* Protocol ID */ 0x00, 0x00,
/* Length */ 0x00, 0x11,
- /* Unit ID */ 0x00,
+ /* Unit ID */ 0x0a,
/* Function code */ 0x17,
/* Read Starting Address */ 0x00, 0x03,
/* Quantity to Read */ 0x00, 0x06,
TcpSession ssn;
ThreadVars tv;
- int result = 0;
+ FAIL_IF_NULL(alp_tctx);
memset(&tv, 0, sizeof(ThreadVars));
memset(&f, 0, sizeof(Flow));
StreamTcpInitConfig(TRUE);
de_ctx = DetectEngineCtxInit();
- if (de_ctx == NULL)
- goto end;
+ FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
"(msg:\"Testing modbus code function\"; "
"modbus: function 23; sid:1;)");
-
- if (s == NULL)
- goto end;
+ FAIL_IF_NULL(s);
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
STREAM_TOSERVER,
readWriteMultipleRegistersReq,
sizeof(readWriteMultipleRegistersReq));
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
ModbusState *modbus_state = f.alstate;
- if (modbus_state == NULL) {
- printf("no modbus state: ");
- goto end;
- }
+ FAIL_IF_NULL(modbus_state);
/* do detect */
SigMatchSignatures(&tv, de_ctx, det_ctx, p);
- if (!(PacketAlertCheck(p, 1))) {
- printf("sid 1 didn't match but should have: ");
- goto end;
- }
+ FAIL_IF_NOT(PacketAlertCheck(p, 1));
- result = 1;
-
-end:
- if (alp_tctx != NULL)
- AppLayerParserThreadCtxFree(alp_tctx);
- if (det_ctx != NULL)
- DetectEngineThreadCtxDeinit(&tv, det_ctx);
- if (de_ctx != NULL)
- SigGroupCleanup(de_ctx);
- if (de_ctx != NULL)
- DetectEngineCtxFree(de_ctx);
+ AppLayerParserThreadCtxFree(alp_tctx);
+ DetectEngineThreadCtxDeinit(&tv, det_ctx);
+ SigGroupCleanup(de_ctx);
+ DetectEngineCtxFree(de_ctx);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
UTHFreePacket(p);
- return result;
+ PASS;
}
/** \test code function and code subfunction. */
TcpSession ssn;
ThreadVars tv;
- int result = 0;
+ FAIL_IF_NULL(alp_tctx);
memset(&tv, 0, sizeof(ThreadVars));
memset(&f, 0, sizeof(Flow));
StreamTcpInitConfig(TRUE);
de_ctx = DetectEngineCtxInit();
- if (de_ctx == NULL)
- goto end;
+ FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
"(msg:\"Testing modbus function and subfunction\"; "
"modbus: function 8, subfunction 4; sid:1;)");
-
- if (s == NULL)
- goto end;
+ FAIL_IF_NULL(s);
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
STREAM_TOSERVER, forceListenOnlyMode,
sizeof(forceListenOnlyMode));
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
ModbusState *modbus_state = f.alstate;
- if (modbus_state == NULL) {
- printf("no modbus state: ");
- goto end;
- }
+ FAIL_IF_NULL(modbus_state);
/* do detect */
SigMatchSignatures(&tv, de_ctx, det_ctx, p);
- if (!(PacketAlertCheck(p, 1))) {
- printf("sid 1 didn't match but should have: ");
- goto end;
- }
-
- result = 1;
+ FAIL_IF_NOT(PacketAlertCheck(p, 1));
-end:
- if (alp_tctx != NULL)
- AppLayerParserThreadCtxFree(alp_tctx);
- if (det_ctx != NULL)
- DetectEngineThreadCtxDeinit(&tv, det_ctx);
- if (de_ctx != NULL)
- SigGroupCleanup(de_ctx);
- if (de_ctx != NULL)
- DetectEngineCtxFree(de_ctx);
+ AppLayerParserThreadCtxFree(alp_tctx);
+ DetectEngineThreadCtxDeinit(&tv, det_ctx);
+ SigGroupCleanup(de_ctx);
+ DetectEngineCtxFree(de_ctx);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
UTHFreePacket(p);
- return result;
+ PASS;
}
/** \test function category. */
TcpSession ssn;
ThreadVars tv;
- int result = 0;
+ FAIL_IF_NULL(alp_tctx);
memset(&tv, 0, sizeof(ThreadVars));
memset(&f, 0, sizeof(Flow));
StreamTcpInitConfig(TRUE);
de_ctx = DetectEngineCtxInit();
- if (de_ctx == NULL)
- goto end;
+ FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
"(msg:\"Testing modbus category function\"; "
"modbus: function reserved; sid:1;)");
-
- if (s == NULL)
- goto end;
+ FAIL_IF_NULL(s);
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
STREAM_TOSERVER,
encapsulatedInterfaceTransport,
sizeof(encapsulatedInterfaceTransport));
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
ModbusState *modbus_state = f.alstate;
- if (modbus_state == NULL) {
- printf("no modbus state: ");
- goto end;
- }
+ FAIL_IF_NULL(modbus_state);
/* do detect */
SigMatchSignatures(&tv, de_ctx, det_ctx, p);
- if (!(PacketAlertCheck(p, 1))) {
- printf("sid 1 didn't match but should have: ");
- goto end;
- }
-
- result = 1;
+ FAIL_IF_NOT(PacketAlertCheck(p, 1));
-end:
- if (alp_tctx != NULL)
- AppLayerParserThreadCtxFree(alp_tctx);
- if (det_ctx != NULL)
- DetectEngineThreadCtxDeinit(&tv, det_ctx);
- if (de_ctx != NULL)
- SigGroupCleanup(de_ctx);
- if (de_ctx != NULL)
- DetectEngineCtxFree(de_ctx);
+ AppLayerParserThreadCtxFree(alp_tctx);
+ DetectEngineThreadCtxDeinit(&tv, det_ctx);
+ SigGroupCleanup(de_ctx);
+ DetectEngineCtxFree(de_ctx);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
UTHFreePacket(p);
- return result;
+ PASS;
}
/** \test negative function category. */
TcpSession ssn;
ThreadVars tv;
- int result = 0;
+ FAIL_IF_NULL(alp_tctx);
memset(&tv, 0, sizeof(ThreadVars));
memset(&f, 0, sizeof(Flow));
StreamTcpInitConfig(TRUE);
de_ctx = DetectEngineCtxInit();
- if (de_ctx == NULL)
- goto end;
+ FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
"(msg:\"Testing modbus category function\"; "
"modbus: function !assigned; sid:1;)");
-
- if (s == NULL)
- goto end;
+ FAIL_IF_NULL(s);
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
STREAM_TOSERVER, unassigned,
sizeof(unassigned));
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
ModbusState *modbus_state = f.alstate;
- if (modbus_state == NULL) {
- printf("no modbus state: ");
- goto end;
- }
+ FAIL_IF_NULL(modbus_state);
/* do detect */
SigMatchSignatures(&tv, de_ctx, det_ctx, p);
- if (!(PacketAlertCheck(p, 1))) {
- printf("sid 1 didn't match but should have: ");
- goto end;
- }
-
- result = 1;
+ FAIL_IF_NOT(PacketAlertCheck(p, 1));
-end:
- if (alp_tctx != NULL)
- AppLayerParserThreadCtxFree(alp_tctx);
- if (det_ctx != NULL)
- DetectEngineThreadCtxDeinit(&tv, det_ctx);
- if (de_ctx != NULL)
- SigGroupCleanup(de_ctx);
- if (de_ctx != NULL)
- DetectEngineCtxFree(de_ctx);
+ AppLayerParserThreadCtxFree(alp_tctx);
+ DetectEngineThreadCtxDeinit(&tv, det_ctx);
+ SigGroupCleanup(de_ctx);
+ DetectEngineCtxFree(de_ctx);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
UTHFreePacket(p);
- return result;
+ PASS;
}
/** \test access type. */
TcpSession ssn;
ThreadVars tv;
- int result = 0;
+ FAIL_IF_NULL(alp_tctx);
memset(&tv, 0, sizeof(ThreadVars));
memset(&f, 0, sizeof(Flow));
StreamTcpInitConfig(TRUE);
de_ctx = DetectEngineCtxInit();
- if (de_ctx == NULL)
- goto end;
+ FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
"(msg:\"Testing modbus access type\"; "
"modbus: access read; sid:1;)");
-
- if (s == NULL)
- goto end;
+ FAIL_IF_NULL(s);
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
STREAM_TOSERVER, readCoilsReq,
sizeof(readCoilsReq));
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
ModbusState *modbus_state = f.alstate;
- if (modbus_state == NULL) {
- printf("no modbus state: ");
- goto end;
- }
+ FAIL_IF_NULL(modbus_state);
/* do detect */
SigMatchSignatures(&tv, de_ctx, det_ctx, p);
- if (!(PacketAlertCheck(p, 1))) {
- printf("sid 1 didn't match but should have: ");
- goto end;
- }
+ FAIL_IF_NOT(PacketAlertCheck(p, 1));
- result = 1;
-
-end:
- if (alp_tctx != NULL)
- AppLayerParserThreadCtxFree(alp_tctx);
- if (det_ctx != NULL)
- DetectEngineThreadCtxDeinit(&tv, det_ctx);
- if (de_ctx != NULL)
- SigGroupCleanup(de_ctx);
- if (de_ctx != NULL)
- DetectEngineCtxFree(de_ctx);
+ AppLayerParserThreadCtxFree(alp_tctx);
+ DetectEngineThreadCtxDeinit(&tv, det_ctx);
+ SigGroupCleanup(de_ctx);
+ DetectEngineCtxFree(de_ctx);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
UTHFreePacket(p);
- return result;
+ PASS;
}
/** \test access function. */
TcpSession ssn;
ThreadVars tv;
- int result = 0;
+ FAIL_IF_NULL(alp_tctx);
memset(&tv, 0, sizeof(ThreadVars));
memset(&f, 0, sizeof(Flow));
StreamTcpInitConfig(TRUE);
de_ctx = DetectEngineCtxInit();
- if (de_ctx == NULL)
- goto end;
+ FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
"(msg:\"Testing modbus access type\"; "
"modbus: access read input; sid:1;)");
-
- if (s == NULL)
- goto end;
+ FAIL_IF_NULL(s);
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
STREAM_TOSERVER, readInputsRegistersReq,
sizeof(readInputsRegistersReq));
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
ModbusState *modbus_state = f.alstate;
- if (modbus_state == NULL) {
- printf("no modbus state: ");
- goto end;
- }
+ FAIL_IF_NULL(modbus_state);
/* do detect */
SigMatchSignatures(&tv, de_ctx, det_ctx, p);
- if (!(PacketAlertCheck(p, 1))) {
- printf("sid 1 didn't match but should have: ");
- goto end;
- }
-
- result = 1;
+ FAIL_IF_NOT(PacketAlertCheck(p, 1));
-end:
- if (alp_tctx != NULL)
- AppLayerParserThreadCtxFree(alp_tctx);
- if (det_ctx != NULL)
- DetectEngineThreadCtxDeinit(&tv, det_ctx);
- if (de_ctx != NULL)
- SigGroupCleanup(de_ctx);
- if (de_ctx != NULL)
- DetectEngineCtxFree(de_ctx);
+ AppLayerParserThreadCtxFree(alp_tctx);
+ DetectEngineThreadCtxDeinit(&tv, det_ctx);
+ SigGroupCleanup(de_ctx);
+ DetectEngineCtxFree(de_ctx);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
UTHFreePacket(p);
- return result;
+ PASS;
}
/** \test read access at an address. */
TcpSession ssn;
ThreadVars tv;
- int result = 0;
+ FAIL_IF_NULL(alp_tctx);
memset(&tv, 0, sizeof(ThreadVars));
memset(&f, 0, sizeof(Flow));
StreamTcpInitConfig(TRUE);
de_ctx = DetectEngineCtxInit();
- if (de_ctx == NULL)
- goto end;
+ FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
s = de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
"(msg:\"Testing modbus address access\"; "
"modbus: access read, address 30870; sid:1;)");
-
- if (s == NULL)
- goto end;
+ FAIL_IF_NULL(s);
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
STREAM_TOSERVER, readCoilsReq,
sizeof(readCoilsReq));
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
ModbusState *modbus_state = f.alstate;
- if (modbus_state == NULL) {
- printf("no modbus state: ");
- goto end;
- }
+ FAIL_IF_NULL(modbus_state);
/* do detect */
SigMatchSignatures(&tv, de_ctx, det_ctx, p);
- if (!(PacketAlertCheck(p, 1))) {
- printf("sid 1 didn't match but should have: ");
- goto end;
- }
-
- result = 1;
+ FAIL_IF_NOT(PacketAlertCheck(p, 1));
-end:
- if (alp_tctx != NULL)
- AppLayerParserThreadCtxFree(alp_tctx);
- if (det_ctx != NULL)
- DetectEngineThreadCtxDeinit(&tv, det_ctx);
- if (de_ctx != NULL)
- SigGroupCleanup(de_ctx);
- if (de_ctx != NULL)
- DetectEngineCtxFree(de_ctx);
+ AppLayerParserThreadCtxFree(alp_tctx);
+ DetectEngineThreadCtxDeinit(&tv, det_ctx);
+ SigGroupCleanup(de_ctx);
+ DetectEngineCtxFree(de_ctx);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
UTHFreePacket(p);
- return result;
+ PASS;
}
/** \test read access at a range of address. */
TcpSession ssn;
ThreadVars tv;
- int result = 0;
+ FAIL_IF_NULL(alp_tctx);
memset(&tv, 0, sizeof(ThreadVars));
memset(&f, 0, sizeof(Flow));
StreamTcpInitConfig(TRUE);
de_ctx = DetectEngineCtxInit();
- if (de_ctx == NULL)
- goto end;
+ FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
"(msg:\"Testing modbus access\"; "
"modbus: access read input, "
"address 104<>110; sid:10;)");
-
- if (s == NULL)
- goto end;
+ FAIL_IF_NULL(s);
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
STREAM_TOSERVER, readInputsRegistersReq,
sizeof(readInputsRegistersReq));
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
ModbusState *modbus_state = f.alstate;
- if (modbus_state == NULL) {
- printf("no modbus state: ");
- goto end;
- }
+ FAIL_IF_NULL(modbus_state);
/* do detect */
SigMatchSignatures(&tv, de_ctx, det_ctx, p);
- if (PacketAlertCheck(p, 1)) {
- printf("sid 1 did match but should not have: ");
- goto end;
- }
+ FAIL_IF(PacketAlertCheck(p, 1));
+ FAIL_IF(PacketAlertCheck(p, 3));
+ FAIL_IF(PacketAlertCheck(p, 9));
+ FAIL_IF(PacketAlertCheck(p, 10));
- if (!(PacketAlertCheck(p, 2))) {
- printf("sid 2 didn't match but should have: ");
- goto end;
- }
+ FAIL_IF_NOT(PacketAlertCheck(p, 2));
+ FAIL_IF_NOT(PacketAlertCheck(p, 4));
+ FAIL_IF_NOT(PacketAlertCheck(p, 5));
+ FAIL_IF_NOT(PacketAlertCheck(p, 6));
+ FAIL_IF_NOT(PacketAlertCheck(p, 7));
+ FAIL_IF_NOT(PacketAlertCheck(p, 8));
- if (PacketAlertCheck(p, 3)) {
- printf("sid 3 did match but should not have: ");
- goto end;
- }
-
- if (!(PacketAlertCheck(p, 4))) {
- printf("sid 4 didn't match but should have: ");
- goto end;
- }
-
- if (!(PacketAlertCheck(p, 5))) {
- printf("sid 5 didn't match but should have: ");
- goto end;
- }
-
- if (!(PacketAlertCheck(p, 6))) {
- printf("sid 6 didn't match but should have: ");
- goto end;
- }
-
- if (!(PacketAlertCheck(p, 7))) {
- printf("sid 7 didn't match but should have: ");
- goto end;
- }
-
- if (!(PacketAlertCheck(p, 8))) {
- printf("sid 8 didn't match but should have: ");
- goto end;
- }
-
- if (PacketAlertCheck(p, 9)) {
- printf("sid 9 did match but should not have: ");
- goto end;
- }
-
- if (PacketAlertCheck(p, 10)) {
- printf("sid 10 did match but should not have: ");
- goto end;
- }
-
- result = 1;
-
-end:
- if (alp_tctx != NULL)
- AppLayerParserThreadCtxFree(alp_tctx);
- if (det_ctx != NULL)
- DetectEngineThreadCtxDeinit(&tv, det_ctx);
- if (de_ctx != NULL)
- SigGroupCleanup(de_ctx);
- if (de_ctx != NULL)
- DetectEngineCtxFree(de_ctx);
+ AppLayerParserThreadCtxFree(alp_tctx);
+ DetectEngineThreadCtxDeinit(&tv, det_ctx);
+ SigGroupCleanup(de_ctx);
+ DetectEngineCtxFree(de_ctx);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
UTHFreePacket(p);
- return result;
+ PASS;
}
/** \test write access at a address in a range of value. */
TcpSession ssn;
ThreadVars tv;
- int result = 0;
+ FAIL_IF_NULL(alp_tctx);
memset(&tv, 0, sizeof(ThreadVars));
memset(&f, 0, sizeof(Flow));
StreamTcpInitConfig(TRUE);
de_ctx = DetectEngineCtxInit();
- if (de_ctx == NULL)
- goto end;
+ FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
"(msg:\"Testing modbus write access\"; "
"modbus: access write holding, "
"address 15, value >4660; sid:10;)");
+ FAIL_IF_NULL(s);
+
+ SigGroupBuild(de_ctx);
+ DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
+
+ FLOWLOCK_WRLOCK(&f);
+ int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
+ STREAM_TOSERVER,
+ readWriteMultipleRegistersReq,
+ sizeof(readWriteMultipleRegistersReq));
+ FAIL_IF_NOT(r == 0);
+ FLOWLOCK_UNLOCK(&f);
+
+ ModbusState *modbus_state = f.alstate;
+ FAIL_IF_NULL(modbus_state);
+
+ /* do detect */
+ SigMatchSignatures(&tv, de_ctx, det_ctx, p);
+
+ FAIL_IF(PacketAlertCheck(p, 1));
+ FAIL_IF(PacketAlertCheck(p, 4));
+ FAIL_IF(PacketAlertCheck(p, 5));
+ FAIL_IF(PacketAlertCheck(p, 8));
+ FAIL_IF(PacketAlertCheck(p, 10));
+
+ FAIL_IF_NOT(PacketAlertCheck(p, 2));
+ FAIL_IF_NOT(PacketAlertCheck(p, 3));
+ FAIL_IF_NOT(PacketAlertCheck(p, 6));
+ FAIL_IF_NOT(PacketAlertCheck(p, 7));
+ FAIL_IF_NOT(PacketAlertCheck(p, 9));
+
+ AppLayerParserThreadCtxFree(alp_tctx);
+ DetectEngineThreadCtxDeinit(&tv, det_ctx);
+ SigGroupCleanup(de_ctx);
+ DetectEngineCtxFree(de_ctx);
+
+ StreamTcpFreeConfig(TRUE);
+ FLOW_DESTROY(&f);
+ UTHFreePacket(p);
+ PASS;
+}
+
+/** \test Test code unit_id. */
+static int DetectEngineInspectModbusTest10(void)
+{
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+ DetectEngineThreadCtx *det_ctx = NULL;
+ DetectEngineCtx *de_ctx = NULL;
+ Flow f;
+ Packet *p = NULL;
+ Signature *s = NULL;
+ TcpSession ssn;
+ ThreadVars tv;
- if (s == NULL)
- goto end;
+ FAIL_IF_NULL(alp_tctx);
+
+ memset(&tv, 0, sizeof(ThreadVars));
+ memset(&f, 0, sizeof(Flow));
+ memset(&ssn, 0, sizeof(TcpSession));
+
+ p = UTHBuildPacket(readWriteMultipleRegistersReq,
+ sizeof(readWriteMultipleRegistersReq),
+ IPPROTO_TCP);
+
+ FLOW_INITIALIZE(&f);
+ f.alproto = ALPROTO_MODBUS;
+ f.protoctx = (void *)&ssn;
+ f.proto = IPPROTO_TCP;
+ f.flags |= FLOW_IPV4;
+
+ p->flow = &f;
+ p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
+ p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED;
+
+ StreamTcpInitConfig(TRUE);
+
+ de_ctx = DetectEngineCtxInit();
+ FAIL_IF_NULL(de_ctx);
+
+ de_ctx->flags |= DE_QUIET;
+
+ /* readWriteMultipleRegistersReq, Write Starting Address = 0x0E, Quantity to Write = 0x03 */
+ /* Unit ID = 0x0a (10) */
+ /* Function code = 0x17 (23) */
+ /* Write access register address 15 = 0x1234 (4660) */
+ /* Write access register address 16 = 0x5678 (22136) */
+ /* Write access register address 17 = 0x9ABC (39612) */
+ s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
+ "(msg:\"Testing modbus code unit_id\"; "
+ "modbus: unit 10; sid:1;)");
+
+ s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
+ "(msg:\"Testing modbus code unit_id\"; "
+ "modbus: unit 12; sid:2;)");
+
+ s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
+ "(msg:\"Testing modbus code unit_id\"; "
+ "modbus: unit 5<>15; sid:3;)");
+
+ s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
+ "(msg:\"Testing modbus code unit_id\"; "
+ "modbus: unit 5<>9; sid:4;)");
+
+ s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
+ "(msg:\"Testing modbus code unit_id\"; "
+ "modbus: unit 11<>15; sid:5;)");
+
+ s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
+ "(msg:\"Testing modbus code unit_id\"; "
+ "modbus: unit >9; sid:6;)");
+
+ s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
+ "(msg:\"Testing modbus code unit_id\"; "
+ "modbus: unit >11; sid:7;)");
+
+ s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
+ "(msg:\"Testing modbus code unit_id\"; "
+ "modbus: unit <11; sid:8;)");
+
+ s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
+ "(msg:\"Testing modbus code unit_id\"; "
+ "modbus: unit <9; sid:9;)");
+ FAIL_IF_NULL(s);
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
STREAM_TOSERVER,
readWriteMultipleRegistersReq,
sizeof(readWriteMultipleRegistersReq));
- if (r != 0) {
- printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- FLOWLOCK_UNLOCK(&f);
- goto end;
- }
+ FAIL_IF_NOT(r == 0);
FLOWLOCK_UNLOCK(&f);
ModbusState *modbus_state = f.alstate;
- if (modbus_state == NULL) {
- printf("no modbus state: ");
- goto end;
- }
+ FAIL_IF_NULL(modbus_state);
/* do detect */
SigMatchSignatures(&tv, de_ctx, det_ctx, p);
- if (PacketAlertCheck(p, 1)) {
- printf("sid 1 did match but should not have: ");
- goto end;
- }
+ FAIL_IF(PacketAlertCheck(p, 2));
+ FAIL_IF(PacketAlertCheck(p, 4));
+ FAIL_IF(PacketAlertCheck(p, 5));
+ FAIL_IF(PacketAlertCheck(p, 7));
+ FAIL_IF(PacketAlertCheck(p, 9));
- if (!(PacketAlertCheck(p, 2))) {
- printf("sid 2 didn't match but should have: ");
- goto end;
- }
+ FAIL_IF_NOT(PacketAlertCheck(p, 1));
+ FAIL_IF_NOT(PacketAlertCheck(p, 3));
+ FAIL_IF_NOT(PacketAlertCheck(p, 6));
+ FAIL_IF_NOT(PacketAlertCheck(p, 8));
- if (!(PacketAlertCheck(p, 3))) {
- printf("sid 3 didn't match but should have: ");
- goto end;
- }
+ AppLayerParserThreadCtxFree(alp_tctx);
+ DetectEngineThreadCtxDeinit(&tv, det_ctx);
+ SigGroupCleanup(de_ctx);
+ DetectEngineCtxFree(de_ctx);
- if (PacketAlertCheck(p, 4)) {
- printf("sid 4 did match but should not have: ");
- goto end;
- }
+ StreamTcpFreeConfig(TRUE);
+ FLOW_DESTROY(&f);
+ UTHFreePacket(p);
+ PASS;
+}
- if (PacketAlertCheck(p, 5)) {
- printf("sid 5 did match but should not have: ");
- goto end;
- }
+/** \test Test code unit_id and code function. */
+static int DetectEngineInspectModbusTest11(void)
+{
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+ DetectEngineThreadCtx *det_ctx = NULL;
+ DetectEngineCtx *de_ctx = NULL;
+ Flow f;
+ Packet *p = NULL;
+ Signature *s = NULL;
+ TcpSession ssn;
+ ThreadVars tv;
- if (!(PacketAlertCheck(p, 6))) {
- printf("sid 6 didn't match but should have: ");
- goto end;
- }
+ FAIL_IF_NULL(alp_tctx);
- if (!(PacketAlertCheck(p, 7))) {
- printf("sid 7 didn't match but should have: ");
- goto end;
- }
+ memset(&tv, 0, sizeof(ThreadVars));
+ memset(&f, 0, sizeof(Flow));
+ memset(&ssn, 0, sizeof(TcpSession));
- if (PacketAlertCheck(p, 8)) {
- printf("sid 8 did match but should not have: ");
- goto end;
- }
+ p = UTHBuildPacket(readWriteMultipleRegistersReq,
+ sizeof(readWriteMultipleRegistersReq),
+ IPPROTO_TCP);
- if (!(PacketAlertCheck(p, 9))) {
- printf("sid 9 didn't match but should have: ");
- goto end;
- }
+ FLOW_INITIALIZE(&f);
+ f.alproto = ALPROTO_MODBUS;
+ f.protoctx = (void *)&ssn;
+ f.proto = IPPROTO_TCP;
+ f.flags |= FLOW_IPV4;
- if (PacketAlertCheck(p, 10)) {
- printf("sid 10 did match but should not have: ");
- goto end;
- }
+ p->flow = &f;
+ p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
+ p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED;
+
+ StreamTcpInitConfig(TRUE);
+
+ de_ctx = DetectEngineCtxInit();
+ FAIL_IF_NULL(de_ctx);
+
+ de_ctx->flags |= DE_QUIET;
+
+ /* readWriteMultipleRegistersReq, Write Starting Address = 0x0E, Quantity to Write = 0x03 */
+ /* Unit ID = 0x0a (10) */
+ /* Function code = 0x17 (23) */
+ /* Write access register address 15 = 0x1234 (4660) */
+ /* Write access register address 16 = 0x5678 (22136) */
+ /* Write access register address 17 = 0x9ABC (39612) */
+ s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
+ "(msg:\"Testing modbus code unit_id\"; "
+ "modbus: unit 10, function 20; sid:1;)");
+
+ s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
+ "(msg:\"Testing modbus code unit_id\"; "
+ "modbus: unit 10, function 23; sid:2;)");
+
+ s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
+ "(msg:\"Testing modbus code unit_id\"; "
+ "modbus: unit 11, function 20; sid:3;)");
+
+ s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
+ "(msg:\"Testing modbus code unit_id\"; "
+ "modbus: unit 11, function 23; sid:4;)");
+
+ s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
+ "(msg:\"Testing modbus code unit_id\"; "
+ "modbus: unit 10, function public; sid:5;)");
+
+ s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
+ "(msg:\"Testing modbus code unit_id\"; "
+ "modbus: unit 11, function public; sid:6;)");
+
+ s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
+ "(msg:\"Testing modbus code unit_id\"; "
+ "modbus: unit 10, function user; sid:7;)");
+
+ s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
+ "(msg:\"Testing modbus code unit_id\"; "
+ "modbus: unit 10, function !user; sid:8;)");
+ FAIL_IF_NULL(s);
+
+ SigGroupBuild(de_ctx);
+ DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
+
+ FLOWLOCK_WRLOCK(&f);
+ int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
+ STREAM_TOSERVER,
+ readWriteMultipleRegistersReq,
+ sizeof(readWriteMultipleRegistersReq));
+ FAIL_IF_NOT(r == 0);
+ FLOWLOCK_UNLOCK(&f);
+
+ ModbusState *modbus_state = f.alstate;
+ FAIL_IF_NULL(modbus_state);
+
+ /* do detect */
+ SigMatchSignatures(&tv, de_ctx, det_ctx, p);
+
+ FAIL_IF(PacketAlertCheck(p, 1));
+ FAIL_IF(PacketAlertCheck(p, 3));
+ FAIL_IF(PacketAlertCheck(p, 4));
+ FAIL_IF(PacketAlertCheck(p, 6));
+ FAIL_IF(PacketAlertCheck(p, 7));
+
+ FAIL_IF_NOT(PacketAlertCheck(p, 2));
+ FAIL_IF_NOT(PacketAlertCheck(p, 5));
+ FAIL_IF_NOT(PacketAlertCheck(p, 8));
+
+ AppLayerParserThreadCtxFree(alp_tctx);
+ DetectEngineThreadCtxDeinit(&tv, det_ctx);
+ SigGroupCleanup(de_ctx);
+ DetectEngineCtxFree(de_ctx);
+
+ StreamTcpFreeConfig(TRUE);
+ FLOW_DESTROY(&f);
+ UTHFreePacket(p);
+ PASS;
+}
+
+/** \test unit_id and read access at an address. */
+static int DetectEngineInspectModbusTest12(void)
+{
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+ DetectEngineThreadCtx *det_ctx = NULL;
+ DetectEngineCtx *de_ctx = NULL;
+ Flow f;
+ Packet *p = NULL;
+ Signature *s = NULL;
+ TcpSession ssn;
+ ThreadVars tv;
+
+ FAIL_IF_NULL(alp_tctx);
+
+ memset(&tv, 0, sizeof(ThreadVars));
+ memset(&f, 0, sizeof(Flow));
+ memset(&ssn, 0, sizeof(TcpSession));
+
+ p = UTHBuildPacket(readCoilsReq, sizeof(readCoilsReq), IPPROTO_TCP);
+
+ FLOW_INITIALIZE(&f);
+ f.alproto = ALPROTO_MODBUS;
+ f.protoctx = (void *)&ssn;
+ f.proto = IPPROTO_TCP;
+ f.flags |= FLOW_IPV4;
+
+ p->flow = &f;
+ p->flags |= PKT_HAS_FLOW | PKT_STREAM_EST;
+ p->flowflags |= FLOW_PKT_TOSERVER | FLOW_PKT_ESTABLISHED;
+
+ StreamTcpInitConfig(TRUE);
+
+ de_ctx = DetectEngineCtxInit();
+ FAIL_IF_NULL(de_ctx);
+
+ de_ctx->flags |= DE_QUIET;
+
+ /* readCoilsReq, Read coils Starting Address = 0x7890 (30864), Quantity of coils = 0x13 (19) */
+ /* Unit ID = 0x0a (10) */
+ /* Function code = 0x01 (01) */
+ s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
+ "(msg:\"Testing modbus address access\"; "
+ "modbus: unit 10, access read, address 30870; sid:1;)");
+
+ s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
+ "(msg:\"Testing modbus address access\"; "
+ "modbus: unit 10, access read, address 30863; sid:2;)");
+
+ s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
+ "(msg:\"Testing modbus address access\"; "
+ "modbus: unit 11, access read, address 30870; sid:3;)");
+
+ s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
+ "(msg:\"Testing modbus address access\"; "
+ "modbus: unit 11, access read, address 30863; sid:4;)");
+
+ s = DetectEngineAppendSig(de_ctx, "alert modbus any any -> any any "
+ "(msg:\"Testing modbus address access\"; "
+ "modbus: unit 10, access write; sid:5;)");
+ FAIL_IF_NULL(s);
+
+ SigGroupBuild(de_ctx);
+ DetectEngineThreadCtxInit(&tv, (void *)de_ctx, (void *)&det_ctx);
+
+ FLOWLOCK_WRLOCK(&f);
+ int r = AppLayerParserParse(NULL, alp_tctx, &f, ALPROTO_MODBUS,
+ STREAM_TOSERVER, readCoilsReq,
+ sizeof(readCoilsReq));
+ FAIL_IF_NOT(r == 0);
+ FLOWLOCK_UNLOCK(&f);
+
+ ModbusState *modbus_state = f.alstate;
+ FAIL_IF_NULL(modbus_state);
+
+ /* do detect */
+ SigMatchSignatures(&tv, de_ctx, det_ctx, p);
+
+ FAIL_IF(PacketAlertCheck(p, 2));
+ FAIL_IF(PacketAlertCheck(p, 3));
+ FAIL_IF(PacketAlertCheck(p, 4));
+ FAIL_IF(PacketAlertCheck(p, 5));
- result = 1;
+ FAIL_IF_NOT(PacketAlertCheck(p, 1));
-end:
- if (alp_tctx != NULL)
- AppLayerParserThreadCtxFree(alp_tctx);
- if (det_ctx != NULL)
- DetectEngineThreadCtxDeinit(&tv, det_ctx);
- if (de_ctx != NULL)
- SigGroupCleanup(de_ctx);
- if (de_ctx != NULL)
- DetectEngineCtxFree(de_ctx);
+ AppLayerParserThreadCtxFree(alp_tctx);
+ DetectEngineThreadCtxDeinit(&tv, det_ctx);
+ SigGroupCleanup(de_ctx);
+ DetectEngineCtxFree(de_ctx);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
UTHFreePacket(p);
- return result;
+ PASS;
}
#endif /* UNITTESTS */
DetectEngineInspectModbusTest08);
UtRegisterTest("DetectEngineInspectModbusTest09 - Write access at an address a range of value",
DetectEngineInspectModbusTest09);
+ UtRegisterTest("DetectEngineInspectModbusTest10 - Code unit_id",
+ DetectEngineInspectModbusTest10);
+ UtRegisterTest("DetectEngineInspectModbusTest11 - Code unit_id and code function",
+ DetectEngineInspectModbusTest11);
+ UtRegisterTest("DetectEngineInspectModbusTest12 - Code unit_id and acces function",
+ DetectEngineInspectModbusTest12);
#endif /* UNITTESTS */
return;
}
#include "stream-tcp.h"
+/**
+ * \brief Regex for parsing the Modbus unit id string
+ */
+#define PARSE_REGEX_UNIT_ID "^\\s*\"?\\s*unit\\s+([<>]?\\d+)(<>\\d+)?(,\\s*(.*))?\\s*\"?\\s*$"
+static pcre *unit_id_parse_regex;
+static pcre_extra *unit_id_parse_regex_study;
+
/**
* \brief Regex for parsing the Modbus function string
*/
if (modbus->subfunction)
SCFree(modbus->subfunction);
+ if (modbus->unit_id)
+ SCFree(modbus->unit_id);
+
if (modbus->address)
SCFree(modbus->address);
if (isdigit((unsigned char)ptr[0])) {
modbus->function = atoi((const char*) ptr);
+ /* Function code 0 is managed by decoder_event INVALID_FUNCTION_CODE */
+ if (modbus->function == MODBUS_FUNC_NONE) {
+ SCLogError(SC_ERR_INVALID_SIGNATURE,
+ "Invalid argument \"%d\" supplied to modbus function keyword.",
+ modbus->function);
+ goto error;
+ }
+
SCLogDebug("will look for modbus function %d", modbus->function);
if (ret > 2) {
SCReturnPtr(NULL, "DetectModbus");
}
+/** \internal
+ *
+ * \brief This function is used to parse Modbus parameters in unit id mode
+ *
+ * \param str Pointer to the user provided id option
+ *
+ * \retval Pointer to DetectModbusUnit on success or NULL on failure
+ */
+static DetectModbus *DetectModbusUnitIdParse(const char *str)
+{
+ SCEnter();
+ DetectModbus *modbus = NULL;
+
+ char arg[MAX_SUBSTRINGS];
+ int ov[MAX_SUBSTRINGS], ret, res;
+
+ ret = pcre_exec(unit_id_parse_regex, unit_id_parse_regex_study, str, strlen(str), 0, 0, ov, MAX_SUBSTRINGS);
+
+ if (ret < 1)
+ goto error;
+
+ res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 1, arg, MAX_SUBSTRINGS);
+ if (res < 0) {
+ SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
+ goto error;
+ }
+
+ if (ret > 3) {
+ /* We have more Modbus option */
+ const char *str_ptr;
+
+ res = pcre_get_substring((char *)str, ov, MAX_SUBSTRINGS, 4, &str_ptr);
+ if (res < 0) {
+ SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
+ goto error;
+ }
+
+ if ((modbus = DetectModbusFunctionParse(str_ptr)) == NULL) {
+ if ((modbus = DetectModbusAccessParse(str_ptr)) == NULL) {
+ SCLogError(SC_ERR_PCRE_MATCH, "invalid modbus option");
+ goto error;
+ }
+ }
+ } else {
+ /* We have only unit id Modbus option */
+ modbus = (DetectModbus *) SCCalloc(1, sizeof(DetectModbus));
+ if (unlikely(modbus == NULL))
+ goto error;
+ }
+
+ /* We have a correct unit id option */
+ modbus->unit_id = (DetectModbusValue *) SCCalloc(1, sizeof(DetectModbusValue));
+ if (unlikely(modbus->unit_id == NULL))
+ goto error;
+
+ if (arg[0] == '>') {
+ modbus->unit_id->min = atoi((const char*) (arg+1));
+ modbus->unit_id->mode = DETECT_MODBUS_GT;
+ } else if (arg[0] == '<') {
+ modbus->unit_id->min = atoi((const char*) (arg+1));
+ modbus->unit_id->mode = DETECT_MODBUS_LT;
+ } else {
+ modbus->unit_id->min = atoi((const char*) arg);
+ }
+ SCLogDebug("and min/equal unit id %d", modbus->unit_id->min);
+
+ if (ret > 2) {
+ res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 2, arg, MAX_SUBSTRINGS);
+ if (res < 0) {
+ SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
+ goto error;
+ }
+
+ if (*arg != '\0') {
+ modbus->unit_id->max = atoi((const char*) (arg+2));
+ modbus->unit_id->mode = DETECT_MODBUS_RA;
+ SCLogDebug("and max unit id %d", modbus->unit_id->max);
+ }
+ }
+
+ SCReturnPtr(modbus, "DetectModbusUnitId");
+
+error:
+ if (modbus != NULL)
+ DetectModbusFree(modbus);
+
+ SCReturnPtr(NULL, "DetectModbus");
+}
+
+
/** \internal
*
* \brief this function is used to add the parsed "id" option into the current signature
if (DetectSignatureSetAppProto(s, ALPROTO_MODBUS) != 0)
return -1;
- if ((modbus = DetectModbusFunctionParse(str)) == NULL) {
- if ((modbus = DetectModbusAccessParse(str)) == NULL) {
- SCLogError(SC_ERR_PCRE_MATCH, "invalid modbus option");
- goto error;
+ if ((modbus = DetectModbusUnitIdParse(str)) == NULL) {
+ if ((modbus = DetectModbusFunctionParse(str)) == NULL) {
+ if ((modbus = DetectModbusAccessParse(str)) == NULL) {
+ SCLogError(SC_ERR_PCRE_MATCH, "invalid modbus option");
+ goto error;
+ }
}
}
sigmatch_table[DETECT_AL_MODBUS].Free = DetectModbusFree;
sigmatch_table[DETECT_AL_MODBUS].RegisterTests = DetectModbusRegisterTests;
+ DetectSetupParseRegexes(PARSE_REGEX_UNIT_ID,
+ &unit_id_parse_regex, &unit_id_parse_regex_study);
DetectSetupParseRegexes(PARSE_REGEX_FUNCTION,
&function_parse_regex, &function_parse_regex_study);
DetectSetupParseRegexes(PARSE_REGEX_ACCESS,
DetectEngineCtx *de_ctx = NULL;
DetectModbus *modbus = NULL;
- int result = 0;
-
de_ctx = DetectEngineCtxInit();
- if (de_ctx == NULL)
- goto end;
+ FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
"(msg:\"Testing modbus function\"; "
"modbus: function 1; sid:1;)");
-
- if (de_ctx->sig_list == NULL)
- goto end;
-
- if ((de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id] == NULL) ||
- (de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx == NULL)) {
- printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: ");
- goto end;
- }
+ FAIL_IF_NULL(de_ctx->sig_list);
+ FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]);
+ FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx;
- if (modbus->function != 1) {
- printf("expected function %d, got %" PRIu8 ": ", 1, modbus->function);
- goto end;
- }
-
- result = 1;
+ FAIL_IF_NOT(modbus->function == 1);
- end:
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineCtxFree(de_ctx);
-
- return result;
+ PASS;
}
/** \test Signature containing a function and a subfunction. */
DetectEngineCtx *de_ctx = NULL;
DetectModbus *modbus = NULL;
- int result = 0;
-
de_ctx = DetectEngineCtxInit();
- if (de_ctx == NULL)
- goto end;
+ FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
"(msg:\"Testing modbus function and subfunction\"; "
"modbus: function 8, subfunction 4; sid:1;)");
-
- if (de_ctx->sig_list == NULL)
- goto end;
-
- if ((de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id] == NULL) ||
- (de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx == NULL)) {
- printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: ");
- goto end;
- }
+ FAIL_IF_NULL(de_ctx->sig_list);
+ FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]);
+ FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx;
- if ((modbus->function != 8) || (*modbus->subfunction != 4)) {
- printf("expected function %d, got %" PRIu8 ": ", 1, modbus->function);
- printf("expected subfunction %d, got %" PRIu16 ": ", 4, *modbus->subfunction);
- goto end;
- }
-
- result = 1;
+ FAIL_IF_NOT(modbus->function == 8);
+ FAIL_IF_NOT(*modbus->subfunction == 4);
- end:
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineCtxFree(de_ctx);
-
- return result;
+ PASS;
}
/** \test Signature containing a function category. */
DetectEngineCtx *de_ctx = NULL;
DetectModbus *modbus = NULL;
- int result = 0;
-
de_ctx = DetectEngineCtxInit();
- if (de_ctx == NULL)
- goto end;
+ FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
"(msg:\"Testing modbus.function\"; "
"modbus: function reserved; sid:1;)");
-
- if (de_ctx->sig_list == NULL)
- goto end;
-
- if ((de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id] == NULL) ||
- (de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx == NULL)) {
- printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: ");
- goto end;
- }
+ FAIL_IF_NULL(de_ctx->sig_list);
+ FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]);
+ FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx;
- if (modbus->category != MODBUS_CAT_RESERVED) {
- printf("expected function %d, got %" PRIu8 ": ", MODBUS_CAT_RESERVED, modbus->category);
- goto end;
- }
-
- result = 1;
+ FAIL_IF_NOT(modbus->category == MODBUS_CAT_RESERVED);
- end:
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineCtxFree(de_ctx);
-
- return result;
+ PASS;
}
/** \test Signature containing a negative function category. */
uint8_t category = ~MODBUS_CAT_PUBLIC_ASSIGNED;
- int result = 0;
-
de_ctx = DetectEngineCtxInit();
- if (de_ctx == NULL)
- goto end;
+ FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
"(msg:\"Testing modbus function\"; "
"modbus: function !assigned; sid:1;)");
-
- if (de_ctx->sig_list == NULL)
- goto end;
-
- if ((de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id] == NULL) ||
- (de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx == NULL)) {
- printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: ");
- goto end;
- }
+ FAIL_IF_NULL(de_ctx->sig_list);
+ FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]);
+ FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx;
- if (modbus->category != category) {
- printf("expected function %u, got %" PRIu8 ": ", ~MODBUS_CAT_PUBLIC_ASSIGNED, modbus->category);
- goto end;
- }
-
- result = 1;
+ FAIL_IF_NOT(modbus->category == category);
- end:
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineCtxFree(de_ctx);
-
- return result;
+ PASS;
}
/** \test Signature containing a access type. */
DetectEngineCtx *de_ctx = NULL;
DetectModbus *modbus = NULL;
- int result = 0;
-
de_ctx = DetectEngineCtxInit();
- if (de_ctx == NULL)
- goto end;
+ FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
"(msg:\"Testing modbus.access\"; "
"modbus: access read; sid:1;)");
-
- if (de_ctx->sig_list == NULL)
- goto end;
-
- if ((de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id] == NULL) ||
- (de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx == NULL)) {
- printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: ");
- goto end;
- }
+ FAIL_IF_NULL(de_ctx->sig_list);
+ FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]);
+ FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx;
- if (modbus->type != MODBUS_TYP_READ) {
- printf("expected function %d, got %" PRIu8 ": ", MODBUS_TYP_READ, modbus->type);
- goto end;
- }
+ FAIL_IF_NOT(modbus->type == MODBUS_TYP_READ);
- result = 1;
-
- end:
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineCtxFree(de_ctx);
-
- return result;
+ PASS;
}
/** \test Signature containing a access function. */
uint8_t type = (MODBUS_TYP_READ | MODBUS_TYP_DISCRETES);
- int result = 0;
-
de_ctx = DetectEngineCtxInit();
- if (de_ctx == NULL)
- goto end;
+ FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
"(msg:\"Testing modbus.access\"; "
"modbus: access read discretes; sid:1;)");
-
- if (de_ctx->sig_list == NULL)
- goto end;
-
- if ((de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id] == NULL) ||
- (de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx == NULL)) {
- printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: ");
- goto end;
- }
+ FAIL_IF_NULL(de_ctx->sig_list);
+ FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]);
+ FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx;
- if (modbus->type != type) {
- printf("expected function %" PRIu8 ", got %" PRIu8 ": ", type, modbus->type);
- goto end;
- }
-
- result = 1;
+ FAIL_IF_NOT(modbus->type == type);
- end:
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineCtxFree(de_ctx);
-
- return result;
+ PASS;
}
/** \test Signature containing a read access at an address. */
DetectModbusMode mode = DETECT_MODBUS_EQ;
uint8_t type = MODBUS_TYP_READ;
- int result = 0;
de_ctx = DetectEngineCtxInit();
- if (de_ctx == NULL)
- goto end;
+ FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
"(msg:\"Testing modbus.access\"; "
"modbus: access read, address 1000; sid:1;)");
-
- if (de_ctx->sig_list == NULL)
- goto end;
-
- if ((de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id] == NULL) ||
- (de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx == NULL)) {
- printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: ");
- goto end;
- }
+ FAIL_IF_NULL(de_ctx->sig_list);
+ FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]);
+ FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx;
- if ((modbus->type != type) ||
- ((*modbus->address).mode != mode) ||
- ((*modbus->address).min != 1000)) {
- printf("expected function %" PRIu8 ", got %" PRIu8 ": ", type, modbus->type);
- printf("expected mode %u, got %u: ", mode, (*modbus->address).mode);
- printf("expected address %d, got %" PRIu16 ": ", 1000, (*modbus->address).min);
- goto end;
- }
-
- result = 1;
+ FAIL_IF_NOT(modbus->type == type);
+ FAIL_IF_NOT((*modbus->address).mode == mode);
+ FAIL_IF_NOT((*modbus->address).min == 1000);
- end:
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineCtxFree(de_ctx);
-
- return result;
+ PASS;
}
/** \test Signature containing a write access at a range of address. */
DetectModbusMode mode = DETECT_MODBUS_GT;
uint8_t type = (MODBUS_TYP_WRITE | MODBUS_TYP_COILS);
- int result = 0;
de_ctx = DetectEngineCtxInit();
- if (de_ctx == NULL)
- goto end;
+ FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
"(msg:\"Testing modbus.access\"; "
"modbus: access write coils, address >500; sid:1;)");
-
- if (de_ctx->sig_list == NULL)
- goto end;
-
- if ((de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id] == NULL) ||
- (de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx == NULL)) {
- printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: ");
- goto end;
- }
+ FAIL_IF_NULL(de_ctx->sig_list);
+ FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]);
+ FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx;
- if ((modbus->type != type) ||
- ((*modbus->address).mode != mode) ||
- ((*modbus->address).min != 500)) {
- printf("expected function %" PRIu8 ", got %" PRIu8 ": ", type, modbus->type);
- printf("expected mode %d, got %u: ", mode, (*modbus->address).mode);
- printf("expected address %u, got %" PRIu16 ": ", 500, (*modbus->address).min);
- goto end;
- }
-
- result = 1;
+ FAIL_IF_NOT(modbus->type == type);
+ FAIL_IF_NOT((*modbus->address).mode == mode);
+ FAIL_IF_NOT((*modbus->address).min == 500);
- end:
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineCtxFree(de_ctx);
-
- return result;
+ PASS;
}
/** \test Signature containing a write access at a address a range of value. */
DetectModbusMode valueMode = DETECT_MODBUS_RA;
uint8_t type = (MODBUS_TYP_WRITE | MODBUS_TYP_HOLDING);
- int result = 0;
de_ctx = DetectEngineCtxInit();
- if (de_ctx == NULL)
- goto end;
+ FAIL_IF_NULL(de_ctx);
de_ctx->flags |= DE_QUIET;
de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
"(msg:\"Testing modbus.access\"; "
"modbus: access write holding, address 100, value 500<>1000; sid:1;)");
+ FAIL_IF_NULL(de_ctx->sig_list);
+ FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]);
+ FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
- if (de_ctx->sig_list == NULL)
- goto end;
+ modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx;
- if ((de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id] == NULL) ||
- (de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx == NULL)) {
- printf("de_ctx->pmatch_tail == NULL && de_ctx->pmatch_tail->ctx == NULL: ");
- goto end;
- }
+ FAIL_IF_NOT(modbus->type == type);
+ FAIL_IF_NOT((*modbus->address).mode == addressMode);
+ FAIL_IF_NOT((*modbus->address).min == 100);
+ FAIL_IF_NOT((*modbus->data).mode == valueMode);
+ FAIL_IF_NOT((*modbus->data).min == 500);
+ FAIL_IF_NOT((*modbus->data).max == 1000);
+
+ SigGroupCleanup(de_ctx);
+ SigCleanSignatures(de_ctx);
+ DetectEngineCtxFree(de_ctx);
+ PASS;
+}
+
+/** \test Signature containing a unit_id. */
+static int DetectModbusTest10(void)
+{
+ DetectEngineCtx *de_ctx = NULL;
+ DetectModbus *modbus = NULL;
+ DetectModbusMode mode = DETECT_MODBUS_EQ;
+
+ de_ctx = DetectEngineCtxInit();
+ FAIL_IF_NULL(de_ctx);
+
+ de_ctx->flags |= DE_QUIET;
+
+ de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
+ "(msg:\"Testing modbus unit_id\"; "
+ "modbus: unit 10; sid:1;)");
+ FAIL_IF_NULL(de_ctx->sig_list);
+ FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]);
+ FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx;
- if ((modbus->type != type) ||
- ((*modbus->address).mode != addressMode) ||
- ((*modbus->address).min != 100) ||
- ((*modbus->data).mode != valueMode) ||
- ((*modbus->data).min != 500) ||
- ((*modbus->data).max != 1000)) {
- printf("expected function %" PRIu8 ", got %" PRIu8 ": ", type, modbus->type);
- printf("expected address mode %u, got %u: ", addressMode, (*modbus->address).mode);
- printf("expected address %d, got %" PRIu16 ": ", 500, (*modbus->address).min);
- printf("expected value mode %u, got %u: ", valueMode, (*modbus->data).mode);
- printf("expected min value %d, got %" PRIu16 ": ", 500, (*modbus->data).min);
- printf("expected max value %d, got %" PRIu16 ": ", 1000, (*modbus->data).max);
- goto end;
- }
+ FAIL_IF_NOT((*modbus->unit_id).min == 10);
+ FAIL_IF_NOT((*modbus->unit_id).mode == mode);
+
+ SigGroupCleanup(de_ctx);
+ SigCleanSignatures(de_ctx);
+ DetectEngineCtxFree(de_ctx);
+ PASS;
+}
- result = 1;
+/** \test Signature containing a unit_id, a function and a subfunction. */
+static int DetectModbusTest11(void)
+{
+ DetectEngineCtx *de_ctx = NULL;
+ DetectModbus *modbus = NULL;
+ DetectModbusMode mode = DETECT_MODBUS_EQ;
+
+ de_ctx = DetectEngineCtxInit();
+ FAIL_IF_NULL(de_ctx);
+
+ de_ctx->flags |= DE_QUIET;
+
+ de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
+ "(msg:\"Testing modbus function and subfunction\"; "
+ "modbus: unit 10, function 8, subfunction 4; sid:1;)");
+ FAIL_IF_NULL(de_ctx->sig_list);
+ FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]);
+ FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
+
+ modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx;
+
+ FAIL_IF_NOT((*modbus->unit_id).min == 10);
+ FAIL_IF_NOT((*modbus->unit_id).mode == mode);
+ FAIL_IF_NOT(modbus->function == 8);
+ FAIL_IF_NOT((*modbus->subfunction) == 4);
- end:
SigGroupCleanup(de_ctx);
SigCleanSignatures(de_ctx);
DetectEngineCtxFree(de_ctx);
+ PASS;
+}
- return result;
+/** \test Signature containing an unit_id and a read access at an address. */
+static int DetectModbusTest12(void)
+{
+ DetectEngineCtx *de_ctx = NULL;
+ DetectModbus *modbus = NULL;
+ DetectModbusMode mode = DETECT_MODBUS_EQ;
+
+ uint8_t type = MODBUS_TYP_READ;
+
+ de_ctx = DetectEngineCtxInit();
+ FAIL_IF_NULL(de_ctx);
+
+ de_ctx->flags |= DE_QUIET;
+
+ de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
+ "(msg:\"Testing modbus.access\"; "
+ "modbus: unit 10, access read, address 1000; sid:1;)");
+ FAIL_IF_NULL(de_ctx->sig_list);
+ FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]);
+ FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
+
+ modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx;
+
+ FAIL_IF_NOT((*modbus->unit_id).min == 10);
+ FAIL_IF_NOT((*modbus->unit_id).mode == mode);
+ FAIL_IF_NOT(modbus->type == type);
+ FAIL_IF_NOT((*modbus->address).mode == mode);
+ FAIL_IF_NOT((*modbus->address).min == 1000);
+
+ SigGroupCleanup(de_ctx);
+ SigCleanSignatures(de_ctx);
+ DetectEngineCtxFree(de_ctx);
+ PASS;
+}
+
+/** \test Signature containing a range of unit_id. */
+static int DetectModbusTest13(void)
+{
+ DetectEngineCtx *de_ctx = NULL;
+ DetectModbus *modbus = NULL;
+ DetectModbusMode mode = DETECT_MODBUS_RA;
+
+ de_ctx = DetectEngineCtxInit();
+ FAIL_IF_NULL(de_ctx);
+
+ de_ctx->flags |= DE_QUIET;
+
+ de_ctx->sig_list = SigInit(de_ctx, "alert modbus any any -> any any "
+ "(msg:\"Testing modbus.access\"; "
+ "modbus: unit 10<>500; sid:1;)");
+ FAIL_IF_NULL(de_ctx->sig_list);
+ FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]);
+ FAIL_IF_NULL(de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx);
+
+ modbus = (DetectModbus *) de_ctx->sig_list->sm_lists_tail[g_modbus_buffer_id]->ctx;
+
+ FAIL_IF_NOT((*modbus->unit_id).min == 10);
+ FAIL_IF_NOT((*modbus->unit_id).max == 500);
+ FAIL_IF_NOT((*modbus->unit_id).mode == mode);
+
+ SigGroupCleanup(de_ctx);
+ SigCleanSignatures(de_ctx);
+ DetectEngineCtxFree(de_ctx);
+ PASS;
}
#endif /* UNITTESTS */
DetectModbusTest08);
UtRegisterTest("DetectModbusTest09 - Testing write a range of value",
DetectModbusTest09);
+ UtRegisterTest("DetectModbusTest10 - Testing unit_id",
+ DetectModbusTest10);
+ UtRegisterTest("DetectModbusTest11 - Testing unit_id, function and subfunction",
+ DetectModbusTest11);
+ UtRegisterTest("DetectModbusTest12 - Testing unit_id and access at address",
+ DetectModbusTest12);
+ UtRegisterTest("DetectModbusTest13 - Testing a range of unit_id",
+ DetectModbusTest13);
#endif /* UNITTESTS */
}
uint8_t function; /** < Modbus function code to match */
uint16_t *subfunction; /** < Modbus subfunction to match */
uint8_t type; /** < Modbus access type to match */
+ DetectModbusValue *unit_id; /** < Modbus unit id to match */
DetectModbusValue *address; /** < Modbus address to match */
DetectModbusValue *data; /** < Modbus data to match */
} DetectModbus;