mirror of https://github.com/OISF/suricata
DNP3: Application layer decoder.
Decodes TCP DNP3 and raises some DNP3 decoder alerts.pull/2391/head
parent
240d789c40
commit
bbaa79b80e
@ -0,0 +1,26 @@
|
||||
# DNP3 application decoder event rules.
|
||||
#
|
||||
# This SIDs fall in the 2270000+ range. See:
|
||||
# http://doc.emergingthreats.net/bin/view/Main/SidAllocation
|
||||
|
||||
# Flooded.
|
||||
alert dnp3 any any -> any any (msg:"SURICATA DNP3 Request flood detected"; \
|
||||
app-layer-event:dnp3.flooded; sid:2270000; rev:1;)
|
||||
|
||||
# Length to small for PDU type. For example, link specifies the type
|
||||
# as user data, but the length field is not large enough for user
|
||||
# data.
|
||||
alert dnp3 any any -> any any (msg:"SURICATA DNP3 Length too small"; \
|
||||
app-layer-event:dnp3.len_too_small; sid:2270001; rev:2;)
|
||||
|
||||
# Bad link layer CRC.
|
||||
alert dnp3 any any -> any any (msg:"SURICATA DNP3 Bad link CRC"; \
|
||||
app-layer-event:dnp3.bad_link_crc; sid:2270002; rev:1;)
|
||||
|
||||
# Bad transport layer CRC.
|
||||
alert dnp3 any any -> any any (msg:"SURICATA DNP3 Bad transport CRC"; \
|
||||
app-layer-event:dnp3.bad_transport_crc; sid:2270003; rev:1;)
|
||||
|
||||
# Unknown object.
|
||||
alert dnp3 any any -> any any (msg:"SURICATA DNP3 Unknown object"; \
|
||||
app-layer-event:dnp3.unknown_object; sid:2270004; rev:1;)
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,277 @@
|
||||
/* Copyright (C) 2015 Open Information Security Foundation
|
||||
*
|
||||
* You can copy, redistribute or modify this Program under the terms of
|
||||
* the GNU General Public License version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* version 2 along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __APP_LAYER_DNP3_H__
|
||||
#define __APP_LAYER_DNP3_H__
|
||||
|
||||
#include "detect-engine-state.h"
|
||||
#include "util-hashlist.h"
|
||||
#include "util-byte.h"
|
||||
|
||||
/**
|
||||
* The maximum size of a DNP3 link PDU.
|
||||
*/
|
||||
#define DNP3_MAX_LINK_PDU_LEN 292
|
||||
|
||||
/* DNP3 application request function codes. */
|
||||
#define DNP3_APP_FC_CONFIRM 0x00
|
||||
#define DNP3_APP_FC_READ 0x01
|
||||
#define DNP3_APP_FC_WRITE 0x02
|
||||
#define DNP3_APP_FC_SELECT 0x03
|
||||
#define DNP3_APP_FC_OPERATE 0x04
|
||||
#define DNP3_APP_FC_DIR_OPERATE 0x05
|
||||
#define DNP3_APP_FC_DIR_OPERATE_NR 0x06
|
||||
#define DNP3_APP_FC_FREEZE 0x07
|
||||
#define DNP3_APP_FC_FREEZE_NR 0x08
|
||||
#define DNP3_APP_FC_FREEZE_CLEAR 0x09
|
||||
#define DNP3_APP_FC_FREEZE_CLEAR_NR 0x0a
|
||||
#define DNP3_APP_FC_FREEZE_AT_TIME 0x0b
|
||||
#define DNP3_APP_FC_FREEZE_AT_TIME_NR 0x0c
|
||||
#define DNP3_APP_FC_COLD_RESTART 0x0d
|
||||
#define DNP3_APP_FC_WARM_RESTART 0x0e
|
||||
#define DNP3_APP_FC_INITIALIZE_DATA 0x0f
|
||||
#define DNP3_APP_FC_INITIALIZE_APPLICATION 0x10
|
||||
#define DNP3_APP_FC_START_APPLICATION 0x11
|
||||
#define DNP3_APP_FC_STOP_APPLICATION 0x12
|
||||
#define DNP3_APP_FC_SAVE_CONFIGURATION 0x13
|
||||
#define DNP3_APP_FC_ENABLE_UNSOLICITED 0x14
|
||||
#define DNP3_APP_FC_DISABLE_UNSOLICTED 0x15
|
||||
#define DNP3_APP_FC_ASSIGN_CLASS 0x16
|
||||
#define DNP3_APP_FC_DELAY_MEASUREMENT 0x17
|
||||
#define DNP3_APP_FC_RECORD_CURRENT_TIME 0x18
|
||||
#define DNP3_APP_FC_OPEN_TIME 0x19
|
||||
#define DNP3_APP_FC_CLOSE_FILE 0x1a
|
||||
#define DNP3_APP_FC_DELETE_FILE 0x1b
|
||||
#define DNP3_APP_FC_GET_FILE_INFO 0x1c
|
||||
#define DNP3_APP_FC_AUTHENTICATE_FILE 0x1d
|
||||
#define DNP3_APP_FC_ABORT_FILE 0x1e
|
||||
#define DNP3_APP_FC_ACTIVATE_CONFIG 0x1f
|
||||
#define DNP3_APP_FC_AUTH_REQ 0x20
|
||||
#define DNP3_APP_FC_AUTH_REQ_NR 0x21
|
||||
|
||||
/* DNP3 application response function codes. */
|
||||
#define DNP3_APP_FC_RESPONSE 0x81
|
||||
#define DNP3_APP_FC_UNSOLICITED_RESP 0x82
|
||||
#define DNP3_APP_FC_AUTH_RESP 0x83
|
||||
|
||||
/* Extract fields from the link control octet. */
|
||||
#define DNP3_LINK_DIR(control) (control & 0x80)
|
||||
#define DNP3_LINK_PRI(control) (control & 0x40)
|
||||
#define DNP3_LINK_FCB(control) (control & 0x20)
|
||||
#define DNP3_LINK_FCV(control) (control & 0x10)
|
||||
#define DNP3_LINK_FC(control) (control & 0x0f)
|
||||
|
||||
/* Extract fields from transport layer header octet. */
|
||||
#define DNP3_TH_FIN(x) (x & 0x80)
|
||||
#define DNP3_TH_FIR(x) (x & 0x40)
|
||||
#define DNP3_TH_SEQ(x) (x & 0x3f)
|
||||
|
||||
/* Extract fields from the application control octet. */
|
||||
#define DNP3_APP_FIR(x) (x & 0x80)
|
||||
#define DNP3_APP_FIN(x) (x & 0x40)
|
||||
#define DNP3_APP_CON(x) (x & 0x20)
|
||||
#define DNP3_APP_UNS(x) (x & 0x10)
|
||||
#define DNP3_APP_SEQ(x) (x & 0x0f)
|
||||
|
||||
/* DNP3 values are stored in little endian on the wire, so swapping will be
|
||||
* needed on big endian architectures. */
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
#define DNP3_SWAP16(x) SCByteSwap16(x)
|
||||
#define DNP3_SWAP32(x) SCByteSwap32(x)
|
||||
#define DNP3_SWAP64(x) SCByteSwap64(x)
|
||||
#elif __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define DNP3_SWAP16(x) x
|
||||
#define DNP3_SWAP32(x) x
|
||||
#define DNP3_SWAP64(x) x
|
||||
#endif
|
||||
|
||||
/* DNP3 decoder events. */
|
||||
enum {
|
||||
DNP3_DECODER_EVENT_FLOODED = 1,
|
||||
DNP3_DECODER_EVENT_LEN_TOO_SMALL,
|
||||
DNP3_DECODER_EVENT_BAD_LINK_CRC,
|
||||
DNP3_DECODER_EVENT_BAD_TRANSPORT_CRC,
|
||||
DNP3_DECODER_EVENT_MALFORMED,
|
||||
DNP3_DECODER_EVENT_UNKNOWN_OBJECT,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief DNP3 link header.
|
||||
*/
|
||||
typedef struct DNP3LinkHeader_ {
|
||||
uint8_t start_byte0; /**< First check byte. */
|
||||
uint8_t start_byte1; /**< Second check byte. */
|
||||
uint8_t len; /**< Length of PDU without CRCs. */
|
||||
uint8_t control; /**< Control flags. */
|
||||
uint16_t dst; /**< DNP3 destination address. */
|
||||
uint16_t src; /**< DNP3 source address. */
|
||||
uint16_t crc; /**< Link header CRC. */
|
||||
} __attribute__((__packed__)) DNP3LinkHeader;
|
||||
|
||||
/**
|
||||
* \brief DNP3 transport header.
|
||||
*/
|
||||
typedef uint8_t DNP3TransportHeader;
|
||||
|
||||
/**
|
||||
* \brief DNP3 application header.
|
||||
*/
|
||||
typedef struct DNP3ApplicationHeader_ {
|
||||
uint8_t control; /**< Control flags. */
|
||||
uint8_t function_code; /**< Application function code. */
|
||||
} __attribute__((__packed__)) DNP3ApplicationHeader;
|
||||
|
||||
/**
|
||||
* \brief DNP3 internal indicators.
|
||||
*
|
||||
* Part of the application header for responses only.
|
||||
*/
|
||||
typedef struct DNP3InternalInd_ {
|
||||
uint8_t iin1;
|
||||
uint8_t iin2;
|
||||
} __attribute__((__packed__)) DNP3InternalInd;
|
||||
|
||||
/**
|
||||
* \brief A struct used for buffering incoming data prior to reassembly.
|
||||
*/
|
||||
typedef struct DNP3Buffer_ {
|
||||
uint8_t *buffer;
|
||||
size_t size;
|
||||
int len;
|
||||
int offset;
|
||||
} DNP3Buffer;
|
||||
|
||||
/**
|
||||
* \brief DNP3 application object header.
|
||||
*/
|
||||
typedef struct DNP3ObjHeader_ {
|
||||
uint8_t group;
|
||||
uint8_t variation;
|
||||
uint8_t qualifier;
|
||||
} __attribute__((packed)) DNP3ObjHeader;
|
||||
|
||||
/**
|
||||
* \brief DNP3 object point.
|
||||
*
|
||||
* Each DNP3 object can have 0 or more points representing the values
|
||||
* of the object.
|
||||
*/
|
||||
typedef struct DNP3Point_ {
|
||||
uint32_t prefix; /**< Prefix value for point. */
|
||||
uint32_t index; /**< Index of point. If the object is prefixed
|
||||
* with an index then this will be that
|
||||
* value. Otherwise this is the place the point
|
||||
* was in the list of points (starting at 0). */
|
||||
uint32_t size; /**< Size of point if the object prefix was a
|
||||
* size. */
|
||||
void *data; /**< Data for this point. */
|
||||
TAILQ_ENTRY(DNP3Point_) next;
|
||||
} DNP3Point;
|
||||
|
||||
typedef TAILQ_HEAD(DNP3PointList_, DNP3Point_) DNP3PointList;
|
||||
|
||||
/**
|
||||
* \brief Struct to hold the list of decoded objects.
|
||||
*/
|
||||
typedef struct DNP3Object_ {
|
||||
uint8_t group;
|
||||
uint8_t variation;
|
||||
uint8_t qualifier;
|
||||
uint8_t prefix_code;
|
||||
uint8_t range_code;
|
||||
uint32_t start;
|
||||
uint32_t stop;
|
||||
uint32_t count;
|
||||
DNP3PointList *points; /**< List of points for this object. */
|
||||
|
||||
TAILQ_ENTRY(DNP3Object_) next;
|
||||
} DNP3Object;
|
||||
|
||||
typedef TAILQ_HEAD(DNP3ObjectList_, DNP3Object_) DNP3ObjectList;
|
||||
|
||||
/**
|
||||
* \brief DNP3 transaction.
|
||||
*/
|
||||
typedef struct DNP3Transaction_ {
|
||||
uint64_t tx_num; /**< Internal transaction ID. */
|
||||
uint32_t logged; /**< Flags indicating which loggers have logged this tx. */
|
||||
|
||||
struct DNP3State_ *dnp3;
|
||||
|
||||
uint8_t has_request;
|
||||
uint8_t request_done;
|
||||
DNP3LinkHeader request_lh;
|
||||
DNP3TransportHeader request_th;
|
||||
DNP3ApplicationHeader request_ah;
|
||||
uint8_t *request_buffer; /**< Reassembled request
|
||||
* buffer. */
|
||||
uint32_t request_buffer_len;
|
||||
uint8_t request_complete; /**< Was the decode
|
||||
* complete. It will not be
|
||||
* complete if we hit objects
|
||||
* we do not know. */
|
||||
DNP3ObjectList request_objects;
|
||||
|
||||
uint8_t has_response;
|
||||
uint8_t response_done;
|
||||
DNP3LinkHeader response_lh;
|
||||
DNP3TransportHeader response_th;
|
||||
DNP3ApplicationHeader response_ah;
|
||||
DNP3InternalInd response_iin;
|
||||
uint8_t *response_buffer; /**< Reassembed response
|
||||
* buffer. */
|
||||
uint32_t response_buffer_len;
|
||||
uint8_t response_complete; /**< Was the decode
|
||||
* complete. It will not be
|
||||
* complete if we hit objects
|
||||
* we do not know. */
|
||||
DNP3ObjectList response_objects;
|
||||
|
||||
AppLayerDecoderEvents *decoder_events; /**< Per transcation
|
||||
* decoder events. */
|
||||
DetectEngineState *de_state;
|
||||
|
||||
TAILQ_ENTRY(DNP3Transaction_) next;
|
||||
} DNP3Transaction;
|
||||
|
||||
TAILQ_HEAD(TxListHead, DNP3Transaction_);
|
||||
|
||||
/**
|
||||
* \brief Per flow DNP3 state.
|
||||
*/
|
||||
typedef struct DNP3State_ {
|
||||
TAILQ_HEAD(, DNP3Transaction_) tx_list;
|
||||
DNP3Transaction *curr; /**< Current transaction. */
|
||||
uint64_t transaction_max;
|
||||
uint16_t events;
|
||||
uint32_t unreplied; /**< Number of unreplied requests. */
|
||||
uint8_t flooded; /**< Flag indicating flood. */
|
||||
|
||||
DNP3Buffer request_buffer; /**< Request buffer for buffering
|
||||
* incomplete request PDUs received
|
||||
* over TCP. */
|
||||
DNP3Buffer response_buffer; /**< Response buffer for buffering
|
||||
* incomplete response PDUs received
|
||||
* over TCP. */
|
||||
|
||||
} DNP3State;
|
||||
|
||||
void RegisterDNP3Parsers(void);
|
||||
void DNP3ParserRegisterTests(void);
|
||||
int DNP3PrefixIsSize(uint8_t);
|
||||
|
||||
#endif /* __APP_LAYER_DNP3_H__ */
|
Loading…
Reference in New Issue