summaryrefslogtreecommitdiffstats
path: root/src/app-layer-dnp3.h
blob: aae07f9c8095118c9d6f924800ca9bb5d582b053 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
/* 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__ */