42 #define DNP3_DEFAULT_PORT "20000"
45 #define DNP3_START_BYTE0 0x05
46 #define DNP3_START_BYTE1 0x64
49 #define DNP3_MIN_LEN 5
52 #define DNP3_CRC_LEN 2
56 #define DNP3_BLOCK_SIZE 16
59 #define DNP3_MAX_TRAN_SEQNO 64
66 #define DNP3_LINK_HDR_LEN 5
82 #define DNP3_OBJ_PREFIX(x) ((x >> 4) & 0x7)
85 #define DNP3_OBJ_RANGE(x) (x & 0xf)
93 static uint64_t dnp3_max_tx = 32;
96 static uint64_t max_points = 16384;
99 static uint64_t dnp3_max_objects = 2048;
116 #define NEXT_TH_SEQNO(current) ((current + 1) % DNP3_MAX_TRAN_SEQNO)
120 static const uint16_t crc_table[256] = {
121 0x0000, 0x365e, 0x6cbc, 0x5ae2, 0xd978, 0xef26, 0xb5c4, 0x839a,
122 0xff89, 0xc9d7, 0x9335, 0xa56b, 0x26f1, 0x10af, 0x4a4d, 0x7c13,
123 0xb26b, 0x8435, 0xded7, 0xe889, 0x6b13, 0x5d4d, 0x07af, 0x31f1,
124 0x4de2, 0x7bbc, 0x215e, 0x1700, 0x949a, 0xa2c4, 0xf826, 0xce78,
125 0x29af, 0x1ff1, 0x4513, 0x734d, 0xf0d7, 0xc689, 0x9c6b, 0xaa35,
126 0xd626, 0xe078, 0xba9a, 0x8cc4, 0x0f5e, 0x3900, 0x63e2, 0x55bc,
127 0x9bc4, 0xad9a, 0xf778, 0xc126, 0x42bc, 0x74e2, 0x2e00, 0x185e,
128 0x644d, 0x5213, 0x08f1, 0x3eaf, 0xbd35, 0x8b6b, 0xd189, 0xe7d7,
129 0x535e, 0x6500, 0x3fe2, 0x09bc, 0x8a26, 0xbc78, 0xe69a, 0xd0c4,
130 0xacd7, 0x9a89, 0xc06b, 0xf635, 0x75af, 0x43f1, 0x1913, 0x2f4d,
131 0xe135, 0xd76b, 0x8d89, 0xbbd7, 0x384d, 0x0e13, 0x54f1, 0x62af,
132 0x1ebc, 0x28e2, 0x7200, 0x445e, 0xc7c4, 0xf19a, 0xab78, 0x9d26,
133 0x7af1, 0x4caf, 0x164d, 0x2013, 0xa389, 0x95d7, 0xcf35, 0xf96b,
134 0x8578, 0xb326, 0xe9c4, 0xdf9a, 0x5c00, 0x6a5e, 0x30bc, 0x06e2,
135 0xc89a, 0xfec4, 0xa426, 0x9278, 0x11e2, 0x27bc, 0x7d5e, 0x4b00,
136 0x3713, 0x014d, 0x5baf, 0x6df1, 0xee6b, 0xd835, 0x82d7, 0xb489,
137 0xa6bc, 0x90e2, 0xca00, 0xfc5e, 0x7fc4, 0x499a, 0x1378, 0x2526,
138 0x5935, 0x6f6b, 0x3589, 0x03d7, 0x804d, 0xb613, 0xecf1, 0xdaaf,
139 0x14d7, 0x2289, 0x786b, 0x4e35, 0xcdaf, 0xfbf1, 0xa113, 0x974d,
140 0xeb5e, 0xdd00, 0x87e2, 0xb1bc, 0x3226, 0x0478, 0x5e9a, 0x68c4,
141 0x8f13, 0xb94d, 0xe3af, 0xd5f1, 0x566b, 0x6035, 0x3ad7, 0x0c89,
142 0x709a, 0x46c4, 0x1c26, 0x2a78, 0xa9e2, 0x9fbc, 0xc55e, 0xf300,
143 0x3d78, 0x0b26, 0x51c4, 0x679a, 0xe400, 0xd25e, 0x88bc, 0xbee2,
144 0xc2f1, 0xf4af, 0xae4d, 0x9813, 0x1b89, 0x2dd7, 0x7735, 0x416b,
145 0xf5e2, 0xc3bc, 0x995e, 0xaf00, 0x2c9a, 0x1ac4, 0x4026, 0x7678,
146 0x0a6b, 0x3c35, 0x66d7, 0x5089, 0xd313, 0xe54d, 0xbfaf, 0x89f1,
147 0x4789, 0x71d7, 0x2b35, 0x1d6b, 0x9ef1, 0xa8af, 0xf24d, 0xc413,
148 0xb800, 0x8e5e, 0xd4bc, 0xe2e2, 0x6178, 0x5726, 0x0dc4, 0x3b9a,
149 0xdc4d, 0xea13, 0xb0f1, 0x86af, 0x0535, 0x336b, 0x6989, 0x5fd7,
150 0x23c4, 0x159a, 0x4f78, 0x7926, 0xfabc, 0xcce2, 0x9600, 0xa05e,
151 0x6e26, 0x5878, 0x029a, 0x34c4, 0xb75e, 0x8100, 0xdbe2, 0xedbc,
152 0x91af, 0xa7f1, 0xfd13, 0xcb4d, 0x48d7, 0x7e89, 0x246b, 0x1235
163 static uint16_t DNP3ComputeCRC(
const uint8_t *buf, uint32_t
len)
165 const uint8_t *
byte = buf;
170 idx = (
crc ^ *byte) & 0xff;
171 crc = (crc_table[idx] ^ (
crc >> 8)) & 0xffff;
175 return ~
crc & 0xffff;
186 static int DNP3CheckCRC(
const uint8_t *block, uint16_t
len)
188 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
201 if (((
crc & 0xff) == block[crc_offset]) &&
202 ((
crc >> 8) == block[crc_offset + 1])) {
216 static int DNP3CheckLinkHeaderCRC(
const DNP3LinkHeader *header)
218 return DNP3CheckCRC((uint8_t *)header,
sizeof(DNP3LinkHeader));
229 static int DNP3CheckUserDataCRCs(
const uint8_t *data, uint16_t
len)
242 if (!DNP3CheckCRC(data +
offset, block_size)) {
258 static int DNP3CheckStartBytes(
const DNP3LinkHeader *header)
265 #define DNP3_BANNER "DNP3"
275 static int DNP3ContainsBanner(
const uint8_t *input, uint32_t
len)
283 static uint16_t DNP3ProbingParser(
284 const Flow *
f, uint8_t direction,
const uint8_t *input, uint32_t
len, uint8_t *rdir)
286 const DNP3LinkHeader *
const hdr = (
const DNP3LinkHeader *)input;
287 const bool toserver = (direction & STREAM_TOSERVER) != 0;
290 if (DNP3ContainsBanner(input,
len)) {
292 bool is_banner =
true;
294 for (uint32_t i = 0; i <
len && i < 0x100; i++) {
295 if (!isprint(input[i])) {
302 *rdir = STREAM_TOCLIENT;
309 if (
len <
sizeof(DNP3LinkHeader)) {
310 SCLogDebug(
"Length too small to be a DNP3 header.");
315 if (!DNP3CheckStartBytes(hdr)) {
322 SCLogDebug(
"Packet too small to be a valid DNP3 fragment.");
328 *rdir = toserver ? STREAM_TOCLIENT : STREAM_TOSERVER;
341 static int DNP3CalculateTransportLengthWithoutCRCs(uint16_t input_len)
384 static int DNP3ReassembleApplicationLayer(
385 const uint8_t *input, uint16_t input_len, uint8_t **output, uint16_t *output_len)
387 int len = DNP3CalculateTransportLengthWithoutCRCs(input_len);
399 if (*output == NULL) {
406 uint8_t *ptr =
SCRealloc(*output, (
size_t)(*output_len +
len));
413 uint16_t
offset = 0, block_size;
414 while (
offset < input_len) {
419 block_size = input_len -
offset;
444 memcpy(*output + *output_len, input +
offset,
459 static void *DNP3StateAlloc(
void *orig_state,
AppProto proto_orig)
488 static void DNP3SetEvent(
DNP3State *dnp3,
bool request, uint8_t event)
490 if (dnp3 != NULL && dnp3->
curr == NULL) {
496 if (dnp3 && dnp3->
curr) {
497 DNP3SetEventTx(dnp3->
curr, event);
500 SCLogWarning(
"Failed to set event, state or tx pointer was NULL.");
547 static uint16_t DNP3CalculateLinkLength(uint8_t
length)
549 uint16_t frame_len = 0;
567 return frame_len +
sizeof(DNP3LinkHeader);
577 static int DNP3IsUserData(
const DNP3LinkHeader *header)
596 static int DNP3HasUserData(
const DNP3LinkHeader *header, uint8_t direction)
598 if (direction == STREAM_TOSERVER) {
600 sizeof(DNP3ApplicationHeader);
604 sizeof(DNP3ApplicationHeader) +
sizeof(DNP3InternalInd);
611 static void DNP3Resync(
const uint8_t **input, uint32_t *input_len, uint32_t *processed)
615 while (skip + 1 < *input_len) {
635 static void DNP3BufferReset(
DNP3Buffer *buffer)
650 static int DNP3BufferAdd(
DNP3Buffer *buffer,
const uint8_t *data, uint32_t
len)
652 if (buffer->
size == 0) {
681 static void DNP3BufferTrim(
DNP3Buffer *buffer)
684 DNP3BufferReset(buffer);
686 else if (buffer->
offset > 0) {
697 static void DNP3ObjectFree(
DNP3Object *
object)
699 if (object->
points != NULL) {
716 if (object->
points == NULL) {
717 DNP3ObjectFree(
object);
738 static int DNP3DecodeApplicationObjects(
742 uint64_t point_count = 0;
743 uint64_t object_count = 0;
745 if (buf == NULL ||
len == 0) {
752 if (
len <
sizeof(DNP3ObjHeader)) {
755 DNP3ObjHeader *header = (DNP3ObjHeader *)buf;
756 offset +=
sizeof(DNP3ObjHeader);
759 if (++object_count > dnp3_max_objects) {
770 object->group = header->group;
771 object->variation = header->variation;
772 object->qualifier = header->qualifier;
782 if (
offset + (
sizeof(uint8_t) * 2) >
len) {
785 goto not_enough_data;
787 object->start = buf[
offset++];
788 object->stop = buf[
offset++];
789 object->count =
object->stop -
object->start + 1;
796 if (
offset + (
sizeof(uint16_t) * 2) >
len) {
799 goto not_enough_data;
802 offset +=
sizeof(uint16_t);
804 offset +=
sizeof(uint16_t);
805 object->count =
object->stop -
object->start + 1;
812 if (
offset + (
sizeof(uint32_t) * 2) >
len) {
815 goto not_enough_data;
818 offset +=
sizeof(uint32_t);
820 offset +=
sizeof(uint32_t);
821 object->count =
object->stop -
object->start + 1;
832 goto not_enough_data;
834 object->count = buf[
offset];
835 offset +=
sizeof(uint8_t);
841 goto not_enough_data;
844 offset +=
sizeof(uint16_t);
851 goto not_enough_data;
854 offset +=
sizeof(uint32_t);
861 goto not_enough_data;
863 object->count = *(uint8_t *)(buf +
offset);
864 offset +=
sizeof(uint8_t);
881 point_count +=
object->count;
882 if (point_count > max_points) {
914 static void DNP3HandleUserDataRequest(
915 Flow *
f,
DNP3State *dnp3,
const uint8_t *input, uint16_t input_len)
919 DNP3ApplicationHeader *ah;
922 lh = (DNP3LinkHeader *)input;
924 if (!DNP3CheckUserDataCRCs(input +
sizeof(DNP3LinkHeader),
925 input_len -
sizeof(DNP3LinkHeader))) {
929 th = input[
sizeof(DNP3LinkHeader)];
933 if (ttx->lh.src == lh->src && ttx->lh.dst == lh->dst && ttx->is_request && !ttx->done &&
950 ah = (DNP3ApplicationHeader *)(input +
sizeof(DNP3LinkHeader) +
959 tx = DNP3TxAlloc(dnp3,
true);
969 if (!DNP3ReassembleApplicationLayer(input +
sizeof(DNP3LinkHeader),
992 if (DNP3DecodeApplicationObjects(tx, tx->
buffer +
sizeof(DNP3ApplicationHeader),
1001 static void DNP3HandleUserDataResponse(
1002 Flow *
f,
DNP3State *dnp3,
const uint8_t *input, uint16_t input_len)
1006 DNP3ApplicationHeader *ah;
1007 DNP3InternalInd *iin;
1011 lh = (DNP3LinkHeader *)input;
1012 offset +=
sizeof(DNP3LinkHeader);
1014 if (!DNP3CheckUserDataCRCs(input +
offset, input_len -
offset)) {
1022 if (ttx->lh.src == lh->src && ttx->lh.dst == lh->dst && !ttx->is_request &&
1039 ah = (DNP3ApplicationHeader *)(input +
offset);
1040 offset +=
sizeof(DNP3ApplicationHeader);
1041 iin = (DNP3InternalInd *)(input +
offset);
1043 tx = DNP3TxAlloc(dnp3,
false);
1056 if (!DNP3ReassembleApplicationLayer(input +
sizeof(DNP3LinkHeader),
1075 offset =
sizeof(DNP3ApplicationHeader) +
sizeof(DNP3InternalInd);
1076 if (DNP3DecodeApplicationObjects(
1091 static int DNP3HandleRequestLinkLayer(
1092 Flow *
f,
DNP3State *dnp3,
const uint8_t *input, uint32_t input_len)
1095 uint32_t processed = 0;
1100 if (input_len <
sizeof(DNP3LinkHeader)) {
1104 DNP3LinkHeader *header = (DNP3LinkHeader *)input;
1106 if (!DNP3CheckStartBytes(header)) {
1111 if (!DNP3CheckLinkHeaderCRC(header)) {
1113 DNP3Resync(&input, &input_len, &processed);
1117 uint16_t frame_len = DNP3CalculateLinkLength(header->len);
1118 if (frame_len == 0) {
1120 DNP3Resync(&input, &input_len, &processed);
1123 if (input_len < frame_len) {
1129 if (!DNP3IsUserData(header)) {
1135 if (!DNP3HasUserData(header, STREAM_TOSERVER)) {
1140 if (!DNP3CheckUserDataCRCs(input +
sizeof(DNP3LinkHeader),
1141 frame_len -
sizeof(DNP3LinkHeader))) {
1146 DNP3HandleUserDataRequest(
f, dnp3, input, frame_len);
1151 input_len -= frame_len;
1152 processed += frame_len;
1174 const uint8_t *input = StreamSliceGetData(&stream_slice);
1175 uint32_t input_len = StreamSliceGetDataLen(&stream_slice);
1177 if (input_len == 0) {
1182 if (!DNP3BufferAdd(buffer, input, input_len)) {
1185 processed = DNP3HandleRequestLinkLayer(
1187 if (processed < 0) {
1190 buffer->
offset += processed;
1191 DNP3BufferTrim(buffer);
1194 processed = DNP3HandleRequestLinkLayer(
f, dnp3, input, input_len);
1195 if (processed < 0) {
1196 SCLogDebug(
"Failed to process request link layer.");
1201 input_len -= processed;
1205 if (!DNP3BufferAdd(buffer, input, input_len)) {
1215 DNP3BufferReset(buffer);
1225 static int DNP3HandleResponseLinkLayer(
1226 Flow *
f,
DNP3State *dnp3,
const uint8_t *input, uint32_t input_len)
1229 uint32_t processed = 0;
1234 if (input_len <
sizeof(DNP3LinkHeader)) {
1238 DNP3LinkHeader *header = (DNP3LinkHeader *)input;
1240 if (!DNP3CheckStartBytes(header)) {
1245 if (!DNP3CheckLinkHeaderCRC(header)) {
1247 DNP3Resync(&input, &input_len, &processed);
1252 uint16_t frame_len = DNP3CalculateLinkLength(header->len);
1253 if (frame_len == 0) {
1255 DNP3Resync(&input, &input_len, &processed);
1258 if (input_len < frame_len) {
1264 if (!DNP3IsUserData(header)) {
1270 if (!DNP3HasUserData(header, STREAM_TOCLIENT)) {
1275 if (!DNP3CheckUserDataCRCs(input +
sizeof(DNP3LinkHeader),
1276 frame_len -
sizeof(DNP3LinkHeader))) {
1281 DNP3HandleUserDataResponse(
f, dnp3, input, frame_len);
1286 input_len -= frame_len;
1287 processed += frame_len;
1311 const uint8_t *input = StreamSliceGetData(&stream_slice);
1312 uint32_t input_len = StreamSliceGetDataLen(&stream_slice);
1315 if (!DNP3BufferAdd(buffer, input, input_len)) {
1318 processed = DNP3HandleResponseLinkLayer(
1320 if (processed < 0) {
1323 buffer->
offset += processed;
1324 DNP3BufferTrim(buffer);
1329 if (DNP3ContainsBanner(input, input_len)) {
1333 processed = DNP3HandleResponseLinkLayer(
f, dnp3, input, input_len);
1334 if (processed < 0) {
1338 input_len -= processed;
1342 if (!DNP3BufferAdd(buffer, input, input_len)) {
1354 DNP3BufferReset(buffer);
1358 static void *DNP3GetTx(
void *alstate, uint64_t tx_id)
1363 uint64_t tx_num = tx_id + 1;
1370 if (tx_num != tx->
tx_num) {
1379 static uint64_t DNP3GetTxCnt(
void *state)
1382 uint64_t count = ((uint64_t)((
DNP3State *)state)->transaction_max);
1389 static void DNP3TxFreeObjectList(DNP3ObjectList *objects)
1395 DNP3ObjectFree(
object);
1406 if (tx->
buffer != NULL) {
1412 DNP3TxFreeObjectList(&tx->
objects);
1424 static void DNP3StateTxFree(
void *state, uint64_t tx_id)
1429 uint64_t tx_num = tx_id + 1;
1433 if (tx->
tx_num != tx_num) {
1437 if (tx == dnp3->
curr) {
1466 static void DNP3StateFree(
void *state)
1471 if (state != NULL) {
1472 while ((tx =
TAILQ_FIRST(&dnp3->tx_list)) != NULL) {
1490 static int DNP3GetAlstateProgress(
void *tx, uint8_t direction)
1498 SCLogDebug(
"flooded: returning tx as done.");
1511 static int DNP3StateGetEventInfo(
1524 static int DNP3StateGetEventInfoById(
1528 if (*event_name == NULL) {
1530 "the DNP3 enum event map table.",
1559 switch (prefix_code) {
1577 if (state->
un.
ptr == NULL) {
1583 while (tx_ptr->
tx_num < min_tx_id + 1) {
1589 if (tx_ptr->
tx_num >= max_tx_id + 1) {
1595 .tx_id = tx_ptr->
tx_num - 1,
1596 .has_next = (state->
un.
ptr != NULL),
1611 const char *proto_name =
"dnp3";
1618 sizeof(DNP3LinkHeader), STREAM_TOSERVER, DNP3ProbingParser, DNP3ProbingParser);
1622 0,
sizeof(DNP3LinkHeader), DNP3ProbingParser, DNP3ProbingParser)) {
1628 SCLogConfig(
"Protocol detection and parser disabled for DNP3.");
1641 DNP3StateAlloc, DNP3StateFree);
1650 DNP3GetAlstateProgress);
1654 DNP3StateGetEventInfo);
1656 DNP3StateGetEventInfoById);
1664 if (
SCConfGetInt(
"app-layer.protocols.dnp3.max-tx", &value)) {
1665 dnp3_max_tx = (uint64_t)value;
1669 if (
SCConfGetInt(
"app-layer.protocols.dnp3.max-points", &value)) {
1671 max_points = (uint64_t)value;
1676 if (
SCConfGetInt(
"app-layer.protocols.dnp3.max-objects", &value)) {
1678 dnp3_max_objects = (uint64_t)value;
1683 "Protocol detection still on.", proto_name);
1704 static void DNP3FixCrc(uint8_t *data, uint32_t
len)
1706 uint32_t block_size;
1714 uint16_t
crc = DNP3ComputeCRC(data, block_size);
1715 data[block_size + 1] = (
crc >> 8) & 0xff;
1716 data[block_size] =
crc & 0xff;
1725 static int DNP3ParserTestCheckCRC(
void)
1727 uint8_t request[] = {
1729 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00,
1736 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00,
1737 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72,
1741 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff
1745 FAIL_IF(!DNP3CheckCRC(request,
sizeof(DNP3LinkHeader)));
1748 FAIL_IF(!DNP3CheckCRC(request +
sizeof(DNP3LinkHeader),
1751 #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1754 FAIL_IF(DNP3CheckCRC(request,
sizeof(DNP3LinkHeader)));
1758 request[
sizeof(DNP3LinkHeader) + 3]++;
1759 FAIL_IF(DNP3CheckCRC(request +
sizeof(DNP3LinkHeader),
1769 static int DNP3CheckUserDataCRCsTest(
void)
1772 uint8_t data_valid[] = {
1773 0xff, 0xc9, 0x05, 0x0c,
1774 0x01, 0x28, 0x01, 0x00,
1775 0x00, 0x00, 0x01, 0x01,
1776 0x01, 0x00, 0x00, 0x00,
1779 0xff, 0xc9, 0x05, 0x0c,
1780 0x01, 0x28, 0x01, 0x00,
1781 0x00, 0x00, 0x01, 0x01,
1782 0x01, 0x00, 0x00, 0x00,
1785 0xff, 0xc9, 0x05, 0x0c,
1786 0x01, 0x28, 0x01, 0x00,
1787 0x00, 0x00, 0x01, 0x01,
1788 0x01, 0x00, 0x00, 0x00,
1791 0x00, 0x00, 0x00, 0x00,
1795 FAIL_IF(!DNP3CheckUserDataCRCs(data_valid,
sizeof(data_valid)));
1797 #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1799 uint8_t data_invalid[] = {
1800 0xff, 0xc9, 0x05, 0x0c,
1801 0x01, 0x28, 0x01, 0x00,
1802 0x00, 0x00, 0x01, 0x01,
1803 0x01, 0x00, 0x00, 0x00,
1806 0xff, 0xc9, 0x05, 0x0c,
1807 0x01, 0x28, 0x01, 0x00,
1808 0x00, 0x00, 0x01, 0x01,
1809 0x01, 0x00, 0x00, 0x00,
1812 0xff, 0xc9, 0x05, 0x0c,
1813 0x01, 0x28, 0x01, 0x00,
1814 0x00, 0x00, 0x01, 0x01,
1815 0x01, 0x00, 0x00, 0x00,
1818 0x00, 0x00, 0x00, 0x00,
1822 FAIL_IF(DNP3CheckUserDataCRCs(data_invalid,
sizeof(data_invalid)));
1825 uint8_t one_byte_nocrc[] = { 0x01 };
1826 FAIL_IF(DNP3CheckUserDataCRCs(one_byte_nocrc,
sizeof(one_byte_nocrc)));
1829 uint8_t two_byte_nocrc[] = { 0x01, 0x02 };
1830 FAIL_IF(DNP3CheckUserDataCRCs(two_byte_nocrc,
sizeof(two_byte_nocrc)));
1834 uint8_t three_bytes_good_crc[] = { 0x00, 0x00, 0x00 };
1835 *(uint16_t *)(three_bytes_good_crc + 1) = DNP3ComputeCRC(
1836 three_bytes_good_crc, 1);
1837 FAIL_IF(!DNP3CheckUserDataCRCs(three_bytes_good_crc,
1838 sizeof(three_bytes_good_crc)));
1850 static int DNP3CalculateLinkLengthTest(
void)
1853 FAIL_IF(DNP3CalculateLinkLength(0) != 0);
1854 FAIL_IF(DNP3CalculateLinkLength(1) != 0);
1855 FAIL_IF(DNP3CalculateLinkLength(2) != 0);
1856 FAIL_IF(DNP3CalculateLinkLength(3) != 0);
1857 FAIL_IF(DNP3CalculateLinkLength(4) != 0);
1860 FAIL_IF(DNP3CalculateLinkLength(5) != 10);
1863 FAIL_IF(DNP3CalculateLinkLength(21) != 28);
1866 FAIL_IF(DNP3CalculateLinkLength(37) != 46);
1870 FAIL_IF(DNP3CalculateLinkLength(38) != 49);
1873 FAIL_IF(DNP3CalculateLinkLength(255) != 292);
1882 static int DNP3CalculateTransportLengthWithoutCRCsTest(
void)
1884 FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(0) != -1);
1885 FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(1) != -1);
1886 FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(2) != 0);
1887 FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(3) != 1);
1888 FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(16) != 14);
1889 FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(17) != 15);
1890 FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(18) != 16);
1893 FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(19) != -1);
1897 FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(20) != 16);
1899 FAIL_IF(DNP3CalculateTransportLengthWithoutCRCs(21) != 17);
1907 static int DNP3ParserCheckLinkHeaderCRC(
void)
1910 uint8_t request[] = {
1912 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00,
1919 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00,
1920 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72,
1921 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff
1924 DNP3LinkHeader *header = (DNP3LinkHeader *)request;
1925 FAIL_IF(!DNP3CheckLinkHeaderCRC(header));
1927 #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1930 FAIL_IF(DNP3CheckLinkHeaderCRC(header));
1939 static int DNP3ReassembleApplicationLayerTest01(
void)
1941 uint16_t reassembled_len = 0;
1942 uint8_t *output = NULL;
1944 uint8_t payload[] = {
1946 0xff, 0xc9, 0x05, 0x0c,
1947 0x01, 0x28, 0x01, 0x00,
1948 0x00, 0x00, 0x01, 0x01,
1949 0x01, 0x00, 0x00, 0x00,
1952 0xff, 0xc9, 0x05, 0x0c,
1953 0x01, 0x28, 0x01, 0x00,
1954 0x00, 0x00, 0x01, 0x01,
1955 0x01, 0x00, 0x00, 0x00,
1958 0xff, 0xc9, 0x05, 0x0c,
1959 0x01, 0x28, 0x01, 0x00,
1960 0x00, 0x00, 0x01, 0x01,
1961 0x01, 0x00, 0x00, 0x00,
1964 0x00, 0x00, 0x00, 0x00,
1969 uint8_t expected[] = {
1971 0x01, 0x28, 0x01, 0x00,
1972 0x00, 0x00, 0x01, 0x01,
1973 0x01, 0x00, 0x00, 0x00,
1975 0xff, 0xc9, 0x05, 0x0c,
1976 0x01, 0x28, 0x01, 0x00,
1977 0x00, 0x00, 0x01, 0x01,
1978 0x01, 0x00, 0x00, 0x00,
1980 0xff, 0xc9, 0x05, 0x0c,
1981 0x01, 0x28, 0x01, 0x00,
1982 0x00, 0x00, 0x01, 0x01,
1983 0x01, 0x00, 0x00, 0x00,
1985 0x00, 0x00, 0x00, 0x00,
1991 FAIL_IF(!DNP3ReassembleApplicationLayer(payload,
1992 sizeof(payload), &output, &reassembled_len));
1994 FAIL_IF(reassembled_len !=
sizeof(expected));
1995 FAIL_IF(memcmp(expected, output, reassembled_len));
1999 reassembled_len = 0;
2001 FAIL_IF(DNP3ReassembleApplicationLayer(payload, 1, &output,
2004 FAIL_IF(reassembled_len != 0);
2007 reassembled_len = 0;
2009 FAIL_IF(DNP3ReassembleApplicationLayer(payload, 2, &output,
2012 FAIL_IF(reassembled_len != 0);
2016 reassembled_len = 0;
2018 FAIL_IF(DNP3ReassembleApplicationLayer(payload, 3, &output,
2021 FAIL_IF(reassembled_len != 0);
2024 reassembled_len = 0;
2026 FAIL_IF(!DNP3ReassembleApplicationLayer(payload, 4, &output,
2029 FAIL_IF(reassembled_len != 1);
2032 uint8_t short_payload1[] = {
2034 0xff, 0xc9, 0x05, 0x0c,
2035 0x01, 0x28, 0x01, 0x00,
2036 0x00, 0x00, 0x01, 0x01,
2037 0x01, 0x00, 0x00, 0x00,
2040 0xff, 0xc9, 0x05, 0x0c,
2041 0x01, 0x28, 0x01, 0x00,
2042 0x00, 0x00, 0x01, 0x01,
2043 0x01, 0x00, 0x00, 0x00,
2046 0xff, 0xc9, 0x05, 0x0c,
2047 0x01, 0x28, 0x01, 0x00,
2048 0x00, 0x00, 0x01, 0x01,
2049 0x01, 0x00, 0x00, 0x00,
2054 reassembled_len = 0;
2055 FAIL_IF(DNP3ReassembleApplicationLayer(short_payload1,
2056 sizeof(short_payload1), &output, &reassembled_len));
2059 uint8_t short_payload2[] = {
2061 0xff, 0xc9, 0x05, 0x0c,
2062 0x01, 0x28, 0x01, 0x00,
2063 0x00, 0x00, 0x01, 0x01,
2064 0x01, 0x00, 0x00, 0x00,
2067 0xff, 0xc9, 0x05, 0x0c,
2068 0x01, 0x28, 0x01, 0x00,
2069 0x00, 0x00, 0x01, 0x01,
2070 0x01, 0x00, 0x00, 0x00,
2073 0xff, 0xc9, 0x05, 0x0c,
2074 0x01, 0x28, 0x01, 0x00,
2075 0x00, 0x00, 0x01, 0x01,
2076 0x01, 0x00, 0x00, 0x00,
2081 reassembled_len = 0;
2082 FAIL_IF(DNP3ReassembleApplicationLayer(short_payload2,
2083 sizeof(short_payload2), &output, &reassembled_len));
2093 static int DNP3ProbingParserTest(
void)
2096 0x05, 0x64, 0x05, 0xc9, 0x03, 0x00, 0x04, 0x00,
2102 FAIL_IF(DNP3ProbingParser(NULL, STREAM_TOSERVER, pkt,
sizeof(pkt), &rdir) !=
ALPROTO_DNP3);
2105 FAIL_IF(DNP3ProbingParser(NULL, STREAM_TOSERVER, pkt,
sizeof(DNP3LinkHeader) - 1, &rdir) !=
ALPROTO_UNKNOWN);
2119 char mybanner[] =
"Welcome to DNP3 SCADA.";
2120 FAIL_IF(DNP3ProbingParser(NULL, STREAM_TOSERVER, (uint8_t *)mybanner,
sizeof(mybanner) - 1,
2122 FAIL_IF(rdir != STREAM_TOCLIENT);
2130 static int DNP3ParserTestRequestResponse(
void)
2134 uint8_t request[] = {
2136 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00,
2143 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00,
2144 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72,
2145 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff
2148 uint8_t response[] = {
2150 0x05, 0x64, 0x1c, 0x44, 0x01, 0x00, 0x02, 0x00,
2157 0xc9, 0x81, 0x00, 0x00, 0x0c, 0x01, 0x28, 0x01,
2158 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x7a,
2159 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2167 memset(&flow, 0,
sizeof(flow));
2168 memset(&
ssn, 0,
sizeof(
ssn));
2171 flow.
proto = IPPROTO_TCP;
2178 STREAM_TOSERVER, request,
sizeof(request)));
2194 STREAM_TOCLIENT, response,
sizeof(response)));
2213 static int DNP3ParserTestUnsolicitedResponseConfirm(
void)
2218 uint8_t response[] = {
2219 0x05, 0x64, 0x16, 0x44, 0x01, 0x00, 0x02, 0x00,
2220 0x89, 0xe5, 0xc4, 0xfa, 0x82, 0x00, 0x00, 0x02,
2221 0x02, 0x17, 0x01, 0x01, 0x81, 0xa7, 0x75, 0xd8,
2222 0x32, 0x4c, 0x81, 0x3e, 0x01, 0xa1, 0xc9
2226 uint8_t confirm[] = {
2227 0x05, 0x64, 0x08, 0xc4, 0x02, 0x00,
2228 0x01, 0x00, 0xd3, 0xb7, 0xc0, 0xda, 0x00, 0x6a,
2236 memset(&flow, 0,
sizeof(flow));
2237 memset(&
ssn, 0,
sizeof(
ssn));
2240 flow.
proto = IPPROTO_TCP;
2247 STREAM_TOCLIENT, response,
sizeof(response)));
2262 STREAM_TOSERVER, confirm,
sizeof(confirm)));
2283 static int DNP3ParserTestFlooded(
void)
2287 uint8_t request[] = {
2289 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00,
2296 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00,
2297 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72,
2298 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff
2305 memset(&flow, 0,
sizeof(flow));
2306 memset(&
ssn, 0,
sizeof(
ssn));
2309 flow.
proto = IPPROTO_TCP;
2316 STREAM_TOSERVER, request,
sizeof(request)));
2330 FAIL_IF_NOT(DNP3GetAlstateProgress(tx, STREAM_TOSERVER));
2332 for (uint64_t i = 0; i < dnp3_max_tx - 1; i++) {
2335 STREAM_TOSERVER, request,
sizeof(request)));
2339 FAIL_IF_NOT(DNP3GetAlstateProgress(tx, STREAM_TOSERVER));
2344 STREAM_TOSERVER, request,
sizeof(request)));
2349 FAIL_IF(!DNP3GetAlstateProgress(tx, 0));
2364 static int DNP3ParserTestPartialFrame(
void)
2370 uint8_t request_partial1[] = {
2372 0x05, 0x64, 0x1a, 0xc4, 0x02, 0x00, 0x01, 0x00,
2379 0xc9, 0x05, 0x0c, 0x01, 0x28, 0x01, 0x00, 0x00,
2382 uint8_t request_partial2[] = {
2384 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x72,
2385 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff
2388 uint8_t response_partial1[] = {
2390 0x05, 0x64, 0x1c, 0x44, 0x01, 0x00, 0x02, 0x00,
2397 0xc9, 0x81, 0x00, 0x00, 0x0c, 0x01, 0x28, 0x01,
2400 uint8_t response_partial2[] = {
2401 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x7a,
2402 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2410 memset(&flow, 0,
sizeof(flow));
2411 memset(&
ssn, 0,
sizeof(
ssn));
2413 flow.
proto = IPPROTO_TCP;
2421 STREAM_TOSERVER, request_partial1,
sizeof(request_partial1));
2431 sizeof(request_partial1)));
2435 FAIL_IF(DNP3GetTx(state, 0) != NULL);
2440 STREAM_TOSERVER, request_partial2,
sizeof(request_partial2));
2450 tx = DNP3GetTx(state, 0);
2461 STREAM_TOCLIENT, response_partial1,
sizeof(response_partial1));
2466 tx = DNP3GetTx(state, 1);
2472 STREAM_TOCLIENT, response_partial2,
sizeof(response_partial2));
2481 tx = DNP3GetTx(state, 1);
2495 static int DNP3ParserTestMultiFrame(
void)
2500 uint8_t unsol_response1[] = {
2501 0x05, 0x64, 0x16, 0x44, 0x01, 0x00, 0x02, 0x00,
2502 0x89, 0xe5, 0xc4, 0xfa, 0x82, 0x00, 0x00, 0x02,
2503 0x02, 0x17, 0x01, 0x01, 0x81, 0xa7, 0x75, 0xd8,
2504 0x32, 0x4c, 0x81, 0x3e, 0x01, 0xa1, 0xc9,
2508 uint8_t unsol_response2[] = {
2509 0x05, 0x64, 0x16, 0x44, 0x01, 0x00, 0x02, 0x00,
2510 0x89, 0xe5, 0xc5, 0xfb, 0x82, 0x00, 0x00, 0x02,
2511 0x02, 0x17, 0x01, 0x0c, 0x01, 0xd8, 0x75, 0xd8,
2512 0x32, 0x4c, 0xc9, 0x3c, 0x01, 0xa1, 0xc9,
2515 uint8_t combined[
sizeof(unsol_response1) +
sizeof(unsol_response2)];
2516 memcpy(combined, unsol_response1,
sizeof(unsol_response1));
2517 memcpy(combined +
sizeof(unsol_response1), unsol_response2,
2518 sizeof(unsol_response2));
2525 memset(&flow, 0,
sizeof(flow));
2526 memset(&
ssn, 0,
sizeof(
ssn));
2528 flow.
proto = IPPROTO_TCP;
2534 STREAM_TOCLIENT, combined,
sizeof(combined));
2556 static int DNP3ParserTestParsePDU01(
void)
2560 const uint8_t pkt[] = {
2562 0x0b, 0xc4, 0x17, 0x00, 0xef, 0xff, 0xc4, 0x8f,
2563 0xe1, 0xc8, 0x01, 0x01, 0x00, 0x06, 0x77, 0x6e
2567 int pdus = DNP3HandleRequestLinkLayer(NULL, dnp3state, pkt,
sizeof(pkt));
2577 DNP3StateFree(dnp3state);
2584 static int DNP3ParserObjectStructSizeTest(
void)
2586 const size_t max_point_size = 1024;
2603 static int DNP3ParserDecodeG70V2Test(
void)
2605 const uint8_t input[] = {
2628 const uint8_t *buf = input;
2629 uint16_t
len =
sizeof(input);
2651 static int DNP3ParserDecodeG70V2TruncatedTest(
void)
2653 const uint8_t input[] = {
2673 const uint8_t *buf = input;
2674 uint16_t
len =
sizeof(input);
2689 static int DNP3ParserDecodeG70V3Test(
void)
2691 const uint8_t pkt[] = {
2693 0x63, 0xc4, 0x04, 0x00, 0x03, 0x00, 0xc7, 0xee,
2694 0xc7, 0xc9, 0x1b, 0x46, 0x03, 0x5b, 0x01, 0x55,
2695 0x00, 0x1a, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00,
2696 0x9e, 0xc7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2697 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2698 0x00, 0x00, 0xff, 0xff, 0x00, 0x1e, 0x00, 0x43,
2699 0x3a, 0x2f, 0x74, 0x65, 0x6d, 0x70, 0x2f, 0x44,
2700 0x4e, 0x50, 0x44, 0x65, 0x67, 0x7d, 0x76, 0x69,
2701 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
2702 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x93, 0x0c,
2703 0x6e, 0x20, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65,
2704 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x52, 0x65, 0x6d,
2705 0x35, 0x20, 0x6f, 0x74, 0x65, 0x20, 0x44, 0x65,
2706 0x76, 0x69, 0x63, 0x65, 0x2e, 0x78, 0x6d, 0x6c,
2712 int bytes = DNP3HandleRequestLinkLayer(NULL, dnp3state, pkt,
sizeof(pkt));
2713 FAIL_IF(bytes !=
sizeof(pkt));
2732 "C:/temp/DNPDeviceConfiguration written to Remote Device.xml") == 0);
2733 DNP3StateFree(dnp3state);
2740 static int DNP3ParserUnknownEventAlertTest(
void)
2744 0x05, 0x64, 0x63, 0xc4, 0x04, 0x00, 0x03, 0x00,
2754 0x00, 0x1a, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00,
2755 0x9e, 0xc7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2756 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
2757 0x00, 0x00, 0xff, 0xff, 0x00, 0x1e, 0x00, 0x43,
2758 0x3a, 0x2f, 0x74, 0x65, 0x6d, 0x70, 0x2f, 0x44,
2759 0x4e, 0x50, 0x44, 0x65, 0x67, 0x7d, 0x76, 0x69,
2760 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
2761 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x93, 0x0c,
2762 0x6e, 0x20, 0x77, 0x72, 0x69, 0x74, 0x74, 0x65,
2763 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x52, 0x65, 0x6d,
2764 0x35, 0x20, 0x6f, 0x74, 0x65, 0x20, 0x44, 0x65,
2765 0x76, 0x69, 0x63, 0x65, 0x2e, 0x78, 0x6d, 0x6c,
2769 DNP3FixCrc(pkt + 10,
sizeof(pkt) - 10);
2773 int bytes = DNP3HandleRequestLinkLayer(NULL, dnp3state, pkt,
sizeof(pkt));
2774 FAIL_IF(bytes !=
sizeof(pkt));
2776 DNP3StateFree(dnp3state);
2783 static int DNP3ParserIncorrectUserData(
void)
2785 uint8_t packet_bytes[] = {
2786 0x05, 0x64, 0x08, 0xc4, 0x03, 0x00, 0x04, 0x00,
2787 0xbf, 0xe9, 0xc1, 0xc1, 0x82, 0xc5, 0xee
2793 memset(&flow, 0,
sizeof(flow));
2794 memset(&
ssn, 0,
sizeof(
ssn));
2796 flow.
proto = IPPROTO_TCP;
2801 STREAM_TOCLIENT, packet_bytes,
sizeof(packet_bytes));
2816 UtRegisterTest(
"DNP3ParserTestCheckCRC", DNP3ParserTestCheckCRC);
2818 DNP3ParserCheckLinkHeaderCRC);
2819 UtRegisterTest(
"DNP3CheckUserDataCRCsTest", DNP3CheckUserDataCRCsTest);
2820 UtRegisterTest(
"DNP3CalculateLinkLengthTest", DNP3CalculateLinkLengthTest);
2822 DNP3CalculateTransportLengthWithoutCRCsTest);
2824 DNP3ReassembleApplicationLayerTest01);
2827 DNP3ParserTestRequestResponse);
2829 DNP3ParserTestUnsolicitedResponseConfirm);
2830 UtRegisterTest(
"DNP3ParserTestPartialFrame", DNP3ParserTestPartialFrame);
2831 UtRegisterTest(
"DNP3ParserTestMultiFrame", DNP3ParserTestMultiFrame);
2833 UtRegisterTest(
"DNP3ParserTestParsePDU01", DNP3ParserTestParsePDU01);
2834 UtRegisterTest(
"DNP3ParserObjectStructSizeTest", DNP3ParserObjectStructSizeTest);
2835 UtRegisterTest(
"DNP3ParserDecodeG70V2Test", DNP3ParserDecodeG70V2Test);
2836 UtRegisterTest(
"DNP3ParserDecodeG70V2TruncatedTest", DNP3ParserDecodeG70V2TruncatedTest);
2837 UtRegisterTest(
"DNP3ParserDecodeG70V3Test", DNP3ParserDecodeG70V3Test);
2839 DNP3ParserUnknownEventAlertTest);
2840 UtRegisterTest(
"DNP3ParserIncorrectUserData", DNP3ParserIncorrectUserData);