1
1
/* *
2
2
* \file src/plugins/output/fds/src/Storage.cpp
3
3
* \author Lukas Hutak <[email protected] >
4
+ * \author Michal Sedlak <[email protected] >
4
5
* \brief FDS file storage (source file)
5
6
* \date June 2019
6
7
*
13
14
#include < cstdio>
14
15
#include < cstring>
15
16
#include < sys/stat.h>
17
+ #include < netinet/in.h>
16
18
#include < ipfixcol2.h>
17
19
#include < libgen.h>
18
20
#include " Storage.hpp"
19
21
20
22
const std::string TMP_SUFFIX = " .tmp" ;
21
23
22
- Storage::Storage (ipx_ctx_t *ctx, const Config &cfg) : m_ctx(ctx), m_path(cfg.m_path)
24
+ static void
25
+ buf_write (std::vector<uint8_t > &buffer, const uint8_t *data, std::size_t data_len)
26
+ {
27
+ if (data_len == 0 ) {
28
+ return ;
29
+ }
30
+ std::size_t idx = buffer.size ();
31
+ buffer.resize (idx + data_len);
32
+ std::memcpy (&buffer[idx], data, data_len);
33
+ }
34
+
35
+ template <typename T>
36
+ static void
37
+ buf_write (std::vector<uint8_t > &buffer, T &&value)
38
+ {
39
+ buf_write (buffer, reinterpret_cast <const uint8_t *>(&value), sizeof (value));
40
+ }
41
+
42
+ static bool
43
+ contains_element (const std::vector<Config::element> &elements, const fds_tfield &field)
44
+ {
45
+ auto it = std::find_if (elements.begin (), elements.end (),
46
+ [&](const Config::element &elem) { return elem.id == field.id && elem.pen == field.en ; });
47
+ return it != elements.end ();
48
+ }
49
+
50
+ void
51
+ create_modified_template (const fds_template *tmplt,
52
+ const std::vector<Config::element> &selected_elements,
53
+ std::vector<uint8_t > &out_buffer)
54
+ {
55
+ out_buffer.clear ();
56
+
57
+ // Collect the fields we want in the resulting template
58
+ std::vector<const fds_tfield *> fields;
59
+ for (uint16_t i = 0 ; i < tmplt->fields_cnt_total ; i++) {
60
+ const fds_tfield &field = tmplt->fields [i];
61
+ if (contains_element (selected_elements, field)) {
62
+ fields.push_back (&field);
63
+ }
64
+ }
65
+
66
+
67
+ /* *
68
+ * Build the template definition...
69
+ *
70
+ * Template:
71
+ * [Template Record Header]
72
+ * [Field Specifier]
73
+ * [Field Specifier]
74
+ * ...
75
+ * [Field Specifier]
76
+ *
77
+ * Template Record Header:
78
+ * [Template ID : 16 bit] [Field Count : 16 bit]
79
+ *
80
+ * Example:
81
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
82
+ * | Template ID = 256 | Field Count = N |
83
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
84
+ * |1| Information Element id. 1.1 | Field Length 1.1 |
85
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
86
+ * | Enterprise Number 1.1 |
87
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
88
+ * |0| Information Element id. 1.2 | Field Length 1.2 |
89
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
90
+ * | ... | ... |
91
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
92
+ * |1| Information Element id. 1.N | Field Length 1.N |
93
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
94
+ * | Enterprise Number 1.N |
95
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
96
+ * | Template ID = 257 | Field Count = M |
97
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
98
+ * |0| Information Element id. 2.1 | Field Length 2.1 |
99
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
100
+ * |1| Information Element id. 2.2 | Field Length 2.2 |
101
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
102
+ * | Enterprise Number 2.2 |
103
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
104
+ * | ... | ... |
105
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
106
+ * |1| Information Element id. 2.M | Field Length 2.M |
107
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
108
+ * | Enterprise Number 2.M |
109
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
110
+ * | Padding (opt) |
111
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
112
+ */
113
+
114
+ // Write the header
115
+ buf_write (out_buffer, htons (tmplt->id ));
116
+ buf_write (out_buffer, htons (fields.size ()));
117
+
118
+ // Write the template fields
119
+ for (const fds_tfield *field : fields) {
120
+ if (field->en == 0 ) {
121
+ buf_write (out_buffer, htons (field->id ));
122
+ buf_write (out_buffer, htons (field->length ));
123
+ } else {
124
+ // If PEN is specified, MSB of element ID is set to 1
125
+ buf_write (out_buffer, htons (field->id | 0x8000 ));
126
+ buf_write (out_buffer, htons (field->length ));
127
+ buf_write (out_buffer, htonl (field->en ));
128
+ }
129
+ }
130
+ }
131
+
132
+ static void
133
+ create_modified_data_record (fds_drec &drec,
134
+ const std::vector<Config::element> &selected_elements,
135
+ std::vector<uint8_t > &out_buffer)
136
+ {
137
+ out_buffer.clear ();
138
+
139
+ /* *
140
+ * Data record consists of a sequence of field values.
141
+ *
142
+ * Data Record:
143
+ * +--------------------------------------------------+
144
+ * | Field Value |
145
+ * +--------------------------------------------------+
146
+ * | Field Value |
147
+ * +--------------------------------------------------+
148
+ * ...
149
+ * +--------------------------------------------------+
150
+ * | Field Value |
151
+ * +--------------------------------------------------+
152
+ */
153
+
154
+ fds_drec_iter iter;
155
+ fds_drec_iter_init (&iter, &drec, 0 );
156
+ while (fds_drec_iter_next (&iter) != FDS_EOC) {
157
+ if (contains_element (selected_elements, *iter.field .info )) {
158
+ if (iter.field .info ->length == FDS_IPFIX_VAR_IE_LEN) {
159
+ /* *
160
+ * Variable length fields are specified with 65535 in their
161
+ * template field length. In this case, the first octet of the
162
+ * field value in the data record specifies its length (of the
163
+ * data only, the extra octet is not included in this length).
164
+ *
165
+ * If the data were to be longer than 254, the octet is 255 and the
166
+ * next 2 octets are uint16 of the length.
167
+ */
168
+ if (iter.field .size < 255 ) {
169
+ buf_write (out_buffer, uint8_t (iter.field .size ));
170
+ } else {
171
+ buf_write (out_buffer, uint8_t (255 ));
172
+ buf_write (out_buffer, htons (uint16_t (iter.field .size )));
173
+ }
174
+ buf_write (out_buffer, iter.field .data , iter.field .size );
175
+ } else {
176
+ buf_write (out_buffer, iter.field .data , iter.field .size );
177
+ }
178
+ }
179
+ }
180
+ }
181
+
182
+ Storage::Storage (ipx_ctx_t *ctx, const Config &cfg) :
183
+ m_ctx(ctx),
184
+ m_path(cfg.m_path),
185
+ m_selection_used(cfg.m_selection_used),
186
+ m_selection(cfg.m_selection)
23
187
{
24
188
// Check if the directory exists
25
189
struct stat file_info;
@@ -142,6 +306,16 @@ Storage::process_msg(ipx_msg_ipfix_t *msg)
142
306
uint16_t rec_size = rec_ptr->rec .size ;
143
307
uint16_t tmplt_id = rec_ptr->rec .tmplt ->id ;
144
308
309
+ if (m_selection_used) {
310
+ create_modified_data_record (rec_ptr->rec , m_selection, m_buffer);
311
+ rec_data = m_buffer.data ();
312
+ rec_size = m_buffer.size ();
313
+ if (rec_size == 0 ) {
314
+ // No record fields were selected -> the record is empty, skip
315
+ continue ;
316
+ }
317
+ }
318
+
145
319
if (fds_file_write_rec (m_file.get (), tmplt_id, rec_data, rec_size) != FDS_OK) {
146
320
const char *err_msg = fds_file_error (m_file.get ());
147
321
throw FDS_exception (" Failed to add a Data Record: " + std::string (err_msg));
@@ -160,6 +334,12 @@ struct tmplt_update_data {
160
334
fds_file_t *file;
161
335
// / Set of processed Templates in the snapshot
162
336
std::set<uint16_t > ids;
337
+ // / Whether selection is used
338
+ bool selection_used;
339
+ // / The selection
340
+ std::vector<Config::element> *selection;
341
+ // / Buffer for building modified templates
342
+ std::vector<uint8_t > *buffer;
163
343
};
164
344
165
345
/* *
@@ -175,21 +355,40 @@ struct tmplt_update_data {
175
355
static bool
176
356
tmplt_update_cb (const struct fds_template *tmplt, void *data)
177
357
{
178
- // Template type, raw data and size
179
- enum fds_template_type t_type;
180
- const uint8_t *t_data;
181
- uint16_t t_size;
182
-
183
358
auto info = reinterpret_cast <tmplt_update_data *>(data);
184
359
185
360
// No exceptions can be thrown in the C callback!
186
361
try {
187
- uint16_t t_id = tmplt->id ;
188
- info->ids .emplace (t_id);
362
+ if (info->selection_used && tmplt->type != FDS_TYPE_TEMPLATE) {
363
+ // Skip Option Templates in case field selection is used
364
+ return info->is_ok ;
365
+ }
366
+
367
+ // Get definition of the template we want to store
368
+ fds_template_type new_t_type = tmplt->type ;
369
+ const uint8_t *new_t_data = tmplt->raw .data ;
370
+ uint16_t new_t_size = tmplt->raw .length ;
371
+
372
+ if (info->selection_used ) {
373
+ create_modified_template (tmplt, *info->selection , *info->buffer );
374
+ new_t_data = info->buffer ->data ();
375
+ new_t_size = info->buffer ->size ();
376
+
377
+ if (new_t_size == 0 ) {
378
+ // None of the template fields have been selected -> skip this template
379
+ return info->is_ok ;
380
+ }
381
+ }
382
+
383
+ // Only now store the template ID as we're now sure that this is an active template
384
+ info->ids .emplace (tmplt->id );
189
385
190
386
// Get definition of the Template specified in the file
191
- int res = fds_file_write_tmplt_get (info->file , t_id, &t_type, &t_data, &t_size);
387
+ fds_template_type old_t_type;
388
+ const uint8_t *old_t_data;
389
+ uint16_t old_t_size;
192
390
391
+ int res = fds_file_write_tmplt_get (info->file , tmplt->id , &old_t_type, &old_t_data, &old_t_size);
193
392
if (res != FDS_OK && res != FDS_ERR_NOTFOUND) {
194
393
// Something bad happened
195
394
const char *err_msg = fds_file_error (info->file );
@@ -198,21 +397,17 @@ tmplt_update_cb(const struct fds_template *tmplt, void *data)
198
397
199
398
// Should we add/redefine the definition of the Template
200
399
if (res == FDS_OK
201
- && tmplt-> type == t_type
202
- && tmplt-> raw . length == t_size
203
- && memcmp (tmplt-> raw . data , t_data, t_size ) == 0 ) {
400
+ && old_t_type == new_t_type
401
+ && old_t_size == new_t_size
402
+ && memcmp (old_t_data, new_t_data, new_t_size ) == 0 ) {
204
403
// The same -> nothing to do
205
404
return info->is_ok ;
206
405
}
207
406
208
407
// Add the definition (i.e. templates are different or the template hasn't been defined)
209
- IPX_CTX_DEBUG (info->ctx , " Adding/updating definition of Template ID %" PRIu16, t_id );
408
+ IPX_CTX_DEBUG (info->ctx , " Adding/updating definition of Template ID %" PRIu16, tmplt-> id );
210
409
211
- t_type = tmplt->type ;
212
- t_data = tmplt->raw .data ;
213
- t_size = tmplt->raw .length ;
214
-
215
- if (fds_file_write_tmplt_add (info->file , t_type, t_data, t_size) != FDS_OK) {
410
+ if (fds_file_write_tmplt_add (info->file , new_t_type, new_t_data, new_t_size) != FDS_OK) {
216
411
const char *err_msg = fds_file_error (info->file );
217
412
throw FDS_exception (" fds_file_write_tmplt_add() failed: " + std::string (err_msg));
218
413
}
@@ -258,6 +453,9 @@ Storage::tmplts_update(struct snap_info &info, const fds_tsnapshot_t *snap)
258
453
data.ctx = m_ctx;
259
454
data.file = m_file.get ();
260
455
data.ids .clear ();
456
+ data.selection_used = m_selection_used;
457
+ data.selection = &m_selection;
458
+ data.buffer = &m_buffer;
261
459
262
460
// Update templates
263
461
fds_tsnapshot_for (snap, &tmplt_update_cb, &data);
@@ -436,4 +634,3 @@ Storage::session_ipx2fds(const struct ipx_session *ipx_desc, struct fds_file_ses
436
634
memcpy (&fds_desc->ip_dst , &net_desc->addr_dst .ipv6 , sizeof fds_desc->ip_dst );
437
635
}
438
636
}
439
-
0 commit comments