/* 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. */ /** * \file * * DNP3 application layer protocol header file */ #ifndef __APP_LAYER_DNP3_H__ #define __APP_LAYER_DNP3_H__ #include "rust.h" #if __BYTE_ORDER == __BIG_ENDIAN #include "util-byte.h" #endif /* 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_UNSOLICITED 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_ { AppLayerTxData tx_data; uint64_t tx_num; /**< Internal transaction ID. */ bool is_request; /**< Is this tx a request? */ struct DNP3State_ *dnp3; uint8_t *buffer; /**< Reassembled request buffer. */ uint32_t buffer_len; DNP3ObjectList objects; DNP3LinkHeader lh; DNP3TransportHeader th; DNP3ApplicationHeader ah; DNP3InternalInd iin; uint8_t done; uint8_t complete; /**< Was the decode complete. It will not be complete if we hit objects we do not know. */ TAILQ_ENTRY(DNP3Transaction_) next; } DNP3Transaction; TAILQ_HEAD(TxListHead, DNP3Transaction_); /** * \brief Per flow DNP3 state. */ typedef struct DNP3State_ { AppLayerStateData state_data; 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__ */