dnp3: preserve events when no current tx

Create a TX to carry the event if needed. Requires passing if the event is
created on the request or response, for the tx allocation.

Ticket: 8979
(cherry picked from commit d53344f103)
pull/16211/head
Jason Ish 2 months ago
parent 0f9deb9fc3
commit 431a88133f

@ -151,12 +151,13 @@ static const uint16_t crc_table[256] = {
0x91af, 0xa7f1, 0xfd13, 0xcb4d, 0x48d7, 0x7e89, 0x246b, 0x1235 0x91af, 0xa7f1, 0xfd13, 0xcb4d, 0x48d7, 0x7e89, 0x246b, 0x1235
}; };
static DNP3Transaction *DNP3TxAlloc(DNP3State *dnp3, bool request);
/** /**
* \brief Compute the CRC for a buffer. * \brief Compute the CRC for a buffer.
* *
* \param buf Buffer to create CRC from. * \param buf Buffer to create CRC from.
* \param len Length of buffer (number of bytes to use for CRC). * \param len Length of buffer (number of bytes to use for CRC).
*/ */
static uint16_t DNP3ComputeCRC(const uint8_t *buf, uint32_t len) static uint16_t DNP3ComputeCRC(const uint8_t *buf, uint32_t len)
{ {
@ -468,31 +469,37 @@ static void *DNP3StateAlloc(void *orig_state, AppProto proto_orig)
SCReturnPtr(dnp3, "void"); SCReturnPtr(dnp3, "void");
} }
/**
* \brief Set a DNP3 application layer event on a transaction.
*/
static void DNP3SetEventTx(DNP3Transaction *tx, uint8_t event)
{
AppLayerDecoderEventsSetEventRaw(&tx->tx_data.events, event);
tx->dnp3->events++;
}
/** /**
* \brief Set a DNP3 application layer event. * \brief Set a DNP3 application layer event.
* *
* Sets an event on the current transaction object. * Sets an event on the current transaction object, allocating an event carrier
* transaction if necessary.
*/ */
static void DNP3SetEvent(DNP3State *dnp3, uint8_t event) static void DNP3SetEvent(DNP3State *dnp3, bool request, uint8_t event)
{ {
if (dnp3 != NULL && dnp3->curr == NULL) {
DNP3Transaction *tx = DNP3TxAlloc(dnp3, request);
if (tx != NULL) {
tx->done = 1;
}
}
if (dnp3 && dnp3->curr) { if (dnp3 && dnp3->curr) {
AppLayerDecoderEventsSetEventRaw(&dnp3->curr->tx_data.events, event); DNP3SetEventTx(dnp3->curr, event);
dnp3->events++;
} }
else { else {
SCLogWarning("Failed to set event, state or tx pointer was NULL."); SCLogWarning("Failed to set event, state or tx pointer was NULL.");
} }
} }
/**
* \brief Set a DNP3 application layer event on a transaction.
*/
static void DNP3SetEventTx(DNP3Transaction *tx, uint8_t event)
{
AppLayerDecoderEventsSetEventRaw(&tx->tx_data.events, event);
tx->dnp3->events++;
}
/** /**
* \brief Allocation a DNP3 transaction. * \brief Allocation a DNP3 transaction.
*/ */
@ -518,7 +525,7 @@ static DNP3Transaction *DNP3TxAlloc(DNP3State *dnp3, bool request)
/* Check for flood state. */ /* Check for flood state. */
if (dnp3->unreplied > dnp3_max_tx && !dnp3->flooded) { if (dnp3->unreplied > dnp3_max_tx && !dnp3->flooded) {
DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_FLOODED); DNP3SetEvent(dnp3, request, DNP3_DECODER_EVENT_FLOODED);
dnp3->flooded = 1; dnp3->flooded = 1;
} }
@ -962,14 +969,14 @@ static void DNP3HandleUserDataRequest(
input_len - sizeof(DNP3LinkHeader), &tx->buffer, &tx->buffer_len)) { input_len - sizeof(DNP3LinkHeader), &tx->buffer, &tx->buffer_len)) {
/* Malformed, set event and mark as done. */ /* Malformed, set event and mark as done. */
DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_MALFORMED); DNP3SetEvent(dnp3, true, DNP3_DECODER_EVENT_MALFORMED);
tx->done = 1; tx->done = 1;
return; return;
} }
// a data link frame has its size on one byte, // a data link frame has its size on one byte,
// and transport layer has sequence in 0-63 // and transport layer has sequence in 0-63
if (tx->buffer_len > 63 * 0xff) { if (tx->buffer_len > 63 * 0xff) {
DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_TOO_LONG_REASS); DNP3SetEvent(dnp3, true, DNP3_DECODER_EVENT_TOO_LONG_REASS);
tx->done = 1; tx->done = 1;
return; return;
} }
@ -1047,13 +1054,13 @@ static void DNP3HandleUserDataResponse(
if (!DNP3ReassembleApplicationLayer(input + sizeof(DNP3LinkHeader), if (!DNP3ReassembleApplicationLayer(input + sizeof(DNP3LinkHeader),
input_len - sizeof(DNP3LinkHeader), &tx->buffer, &tx->buffer_len)) { input_len - sizeof(DNP3LinkHeader), &tx->buffer, &tx->buffer_len)) {
DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_MALFORMED); DNP3SetEvent(dnp3, false, DNP3_DECODER_EVENT_MALFORMED);
return; return;
} }
// a data link frame has its size on one byte, // a data link frame has its size on one byte,
// and transport layer has sequence in 0-63 // and transport layer has sequence in 0-63
if (tx->buffer_len > 63 * 0xff) { if (tx->buffer_len > 63 * 0xff) {
DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_TOO_LONG_REASS); DNP3SetEvent(dnp3, false, DNP3_DECODER_EVENT_TOO_LONG_REASS);
tx->done = 1; tx->done = 1;
return; return;
} }
@ -1101,14 +1108,14 @@ static int DNP3HandleRequestLinkLayer(
} }
if (!DNP3CheckLinkHeaderCRC(header)) { if (!DNP3CheckLinkHeaderCRC(header)) {
DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_BAD_LINK_CRC); DNP3SetEvent(dnp3, true, DNP3_DECODER_EVENT_BAD_LINK_CRC);
DNP3Resync(&input, &input_len, &processed); DNP3Resync(&input, &input_len, &processed);
continue; continue;
} }
uint32_t frame_len = DNP3CalculateLinkLength(header->len); uint32_t frame_len = DNP3CalculateLinkLength(header->len);
if (frame_len == 0) { if (frame_len == 0) {
DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_LEN_TOO_SMALL); DNP3SetEvent(dnp3, true, DNP3_DECODER_EVENT_LEN_TOO_SMALL);
DNP3Resync(&input, &input_len, &processed); DNP3Resync(&input, &input_len, &processed);
continue; continue;
} }
@ -1125,13 +1132,13 @@ static int DNP3HandleRequestLinkLayer(
/* Make sure the header length is large enough for transport and /* Make sure the header length is large enough for transport and
* application headers. */ * application headers. */
if (!DNP3HasUserData(header, STREAM_TOSERVER)) { if (!DNP3HasUserData(header, STREAM_TOSERVER)) {
DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_LEN_TOO_SMALL); DNP3SetEvent(dnp3, true, DNP3_DECODER_EVENT_LEN_TOO_SMALL);
goto next; goto next;
} }
if (!DNP3CheckUserDataCRCs(input + sizeof(DNP3LinkHeader), if (!DNP3CheckUserDataCRCs(input + sizeof(DNP3LinkHeader),
frame_len - sizeof(DNP3LinkHeader))) { frame_len - sizeof(DNP3LinkHeader))) {
DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_BAD_TRANSPORT_CRC); DNP3SetEvent(dnp3, true, DNP3_DECODER_EVENT_BAD_TRANSPORT_CRC);
goto next; goto next;
} }
@ -1235,7 +1242,7 @@ static int DNP3HandleResponseLinkLayer(
} }
if (!DNP3CheckLinkHeaderCRC(header)) { if (!DNP3CheckLinkHeaderCRC(header)) {
DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_BAD_LINK_CRC); DNP3SetEvent(dnp3, false, DNP3_DECODER_EVENT_BAD_LINK_CRC);
DNP3Resync(&input, &input_len, &processed); DNP3Resync(&input, &input_len, &processed);
continue; continue;
} }
@ -1243,7 +1250,7 @@ static int DNP3HandleResponseLinkLayer(
/* Calculate the number of bytes needed to for this frame. */ /* Calculate the number of bytes needed to for this frame. */
uint32_t frame_len = DNP3CalculateLinkLength(header->len); uint32_t frame_len = DNP3CalculateLinkLength(header->len);
if (frame_len == 0) { if (frame_len == 0) {
DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_LEN_TOO_SMALL); DNP3SetEvent(dnp3, false, DNP3_DECODER_EVENT_LEN_TOO_SMALL);
DNP3Resync(&input, &input_len, &processed); DNP3Resync(&input, &input_len, &processed);
continue; continue;
} }
@ -1260,13 +1267,13 @@ static int DNP3HandleResponseLinkLayer(
/* Make sure the header length is large enough for transport and /* Make sure the header length is large enough for transport and
* application headers. */ * application headers. */
if (!DNP3HasUserData(header, STREAM_TOCLIENT)) { if (!DNP3HasUserData(header, STREAM_TOCLIENT)) {
DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_LEN_TOO_SMALL); DNP3SetEvent(dnp3, false, DNP3_DECODER_EVENT_LEN_TOO_SMALL);
goto next; goto next;
} }
if (!DNP3CheckUserDataCRCs(input + sizeof(DNP3LinkHeader), if (!DNP3CheckUserDataCRCs(input + sizeof(DNP3LinkHeader),
frame_len - sizeof(DNP3LinkHeader))) { frame_len - sizeof(DNP3LinkHeader))) {
DNP3SetEvent(dnp3, DNP3_DECODER_EVENT_BAD_TRANSPORT_CRC); DNP3SetEvent(dnp3, false, DNP3_DECODER_EVENT_BAD_TRANSPORT_CRC);
goto next; goto next;
} }

@ -213,6 +213,10 @@ static void JsonDNP3LogResponse(SCJsonBuilder *js, DNP3Transaction *dnp3tx)
bool AlertJsonDnp3(void *vtx, SCJsonBuilder *js) bool AlertJsonDnp3(void *vtx, SCJsonBuilder *js)
{ {
DNP3Transaction *tx = (DNP3Transaction *)vtx; DNP3Transaction *tx = (DNP3Transaction *)vtx;
if (tx->done && tx->buffer == NULL) {
/* Carrier TX for app-layer event, don't log. */
return false;
}
bool logged = false; bool logged = false;
SCJbOpenObject(js, "dnp3"); SCJbOpenObject(js, "dnp3");
if (tx->is_request && tx->done) { if (tx->is_request && tx->done) {
@ -280,6 +284,10 @@ static int JsonDNP3Logger(ThreadVars *tv, void *thread_data, const Packet *p, Fl
{ {
SCEnter(); SCEnter();
DNP3Transaction *tx = vtx; DNP3Transaction *tx = vtx;
if (tx->done && tx->buffer == NULL) {
/* Carrier TX for app-layer event, don't log. */
SCReturnInt(TM_ECODE_OK);
}
if (tx->is_request && tx->done) { if (tx->is_request && tx->done) {
JsonDNP3LoggerToServer(tv, thread_data, p, f, state, vtx, tx_id); JsonDNP3LoggerToServer(tv, thread_data, p, f, state, vtx, tx_id);
} else if (!tx->is_request && tx->done) { } else if (!tx->is_request && tx->done) {

Loading…
Cancel
Save