Skip to content

Commit 737a1f4

Browse files
authored
Merge pull request #4 from bennySim/devel
JSON output: added option to print detailed info about ipfix packet header
2 parents 224421d + a799295 commit 737a1f4

File tree

6 files changed

+53
-7
lines changed

6 files changed

+53
-7
lines changed

doc/data/configs/tcp2anon2json.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
<ignoreUnknown>true</ignoreUnknown>
4141
<ignoreOptions>false</ignoreOptions>
4242
<nonPrintableChar>true</nonPrintableChar>
43+
<detailedInfo>true</detailedInfo>
4344

4445
<!-- Output methods -->
4546
<outputs>

src/plugins/output/json/README.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ Don't forget to remove (or comment) outputs that you don't want to use!
7070
<nonPrintableChar>true</nonPrintableChar>
7171
<numericNames>false</numericNames>
7272
<splitBiflow>false</splitBiflow>
73+
<detailedInfo>true</detailedInfo>
7374
7475
<outputs>
7576
<server>
@@ -142,6 +143,10 @@ Formatting parameters:
142143
In case of Biflow records, split the record to two unidirectional flow records. Non-biflow
143144
records are unaffected. [values: true/false, default: false]
144145

146+
:``detailedInfo``:
147+
Add detailed info about the IPFIX message (export time, sequence number, ...) to each record
148+
under "ipfix:" prefix. [values: true/false, default: false]
149+
145150
----
146151

147152
Output types: At least one of the following output must be configured. Multiple server/send/file

src/plugins/output/json/src/Config.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ enum params_xml_nodes {
5959
FMT_NONPRINT, /**< Non-printable chars */
6060
FMT_NUMERIC, /**< Use numeric names */
6161
FMT_BFSPLIT, /**< Split biflow */
62+
FMT_DETAILEDINFO, /**< Detailed information */
6263
// Common output
6364
OUTPUT_LIST, /**< List of output types */
6465
OUTPUT_PRINT, /**< Print to standard output */
@@ -139,6 +140,7 @@ static const struct fds_xml_args args_params[] = {
139140
FDS_OPTS_ELEM(FMT_NONPRINT, "nonPrintableChar", FDS_OPTS_T_BOOL, FDS_OPTS_P_OPT),
140141
FDS_OPTS_ELEM(FMT_NUMERIC, "numericNames", FDS_OPTS_T_BOOL, FDS_OPTS_P_OPT),
141142
FDS_OPTS_ELEM(FMT_BFSPLIT, "splitBiflow", FDS_OPTS_T_BOOL, FDS_OPTS_P_OPT),
143+
FDS_OPTS_ELEM(FMT_DETAILEDINFO, "detailedInfo", FDS_OPTS_T_BOOL, FDS_OPTS_P_OPT),
142144
FDS_OPTS_NESTED(OUTPUT_LIST, "outputs", args_outputs, 0),
143145
FDS_OPTS_END
144146
};
@@ -457,6 +459,10 @@ Config::parse_params(fds_xml_ctx_t *params)
457459
assert(content->type == FDS_OPTS_T_BOOL);
458460
format.split_biflow = content->val_bool;
459461
break;
462+
case FMT_DETAILEDINFO: //Add detailed information about each record
463+
assert(content->type == FDS_OPTS_T_BOOL);
464+
format.detailed_info = content->val_bool;
465+
break;
460466
case OUTPUT_LIST: // List of output plugin
461467
assert(content->type == FDS_OPTS_T_CONTEXT);
462468
parse_outputs(content->ptr_ctx);
@@ -481,6 +487,7 @@ Config::default_set()
481487
format.ignore_options = true;
482488
format.numeric_names = false;
483489
format.split_biflow = false;
490+
format.detailed_info = false;
484491

485492
outputs.prints.clear();
486493
outputs.files.clear();

src/plugins/output/json/src/Config.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ struct cfg_format {
5858
bool ignore_unknown;
5959
/** Convert white spaces in string (do not skip) */
6060
bool white_spaces;
61+
/** Add detailed information about each record */
62+
bool detailed_info;
6163
/** Ignore Options Template records */
6264
bool ignore_options;
6365
/** Use only numeric identifiers of Information Elements */

src/plugins/output/json/src/Storage.cpp

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ Storage::Storage(const ipx_ctx_t *ctx, const struct cfg_format &fmt)
8181
if (m_format.split_biflow) {
8282
m_flags |= FDS_CD2J_REVERSE_SKIP;
8383
}
84+
8485
}
8586

8687
Storage::~Storage()
@@ -149,6 +150,9 @@ Storage::records_store(ipx_msg_ipfix_t *msg, const fds_iemgr_t *iemgr)
149150
// Process all data records
150151
const uint32_t rec_cnt = ipx_msg_ipfix_get_drec_cnt(msg);
151152

153+
// Message header
154+
auto hdr = (fds_ipfix_msg_hdr*) ipx_msg_ipfix_get_packet(msg);
155+
152156
for (uint32_t i = 0; i < rec_cnt; ++i) {
153157
ipx_ipfix_record *ipfix_rec = ipx_msg_ipfix_get_drec(msg, i);
154158

@@ -159,7 +163,7 @@ Storage::records_store(ipx_msg_ipfix_t *msg, const fds_iemgr_t *iemgr)
159163
}
160164

161165
// Convert the record
162-
convert(ipfix_rec->rec, iemgr, false);
166+
convert(ipfix_rec->rec, iemgr, hdr, false);
163167

164168
// Store it
165169
for (Output *output : m_outputs) {
@@ -174,7 +178,7 @@ Storage::records_store(ipx_msg_ipfix_t *msg, const fds_iemgr_t *iemgr)
174178
}
175179

176180
// Convert the record from reverse point of view
177-
convert(ipfix_rec->rec, iemgr, true);
181+
convert(ipfix_rec->rec, iemgr, hdr, true);
178182

179183
// Store it
180184
for (Output *output : m_outputs) {
@@ -198,20 +202,47 @@ Storage::records_store(ipx_msg_ipfix_t *msg, const fds_iemgr_t *iemgr)
198202
* \throw runtime_error if the JSON converter fails
199203
*/
200204
void
201-
Storage::convert(struct fds_drec &rec, const fds_iemgr_t *iemgr, bool reverse)
205+
Storage::convert(struct fds_drec &rec, const fds_iemgr_t *iemgr, fds_ipfix_msg_hdr *hdr, bool reverse)
202206
{
203207
// Convert the record
204208
uint32_t flags = m_flags;
205209
flags |= reverse ? FDS_CD2J_BIFLOW_REVERSE : 0;
206210

207211
int rc = fds_drec2json(&rec, flags, iemgr, &m_record.buffer, &m_record.size_alloc);
208212
if (rc < 0) {
209-
throw std::runtime_error("Conversion to JSON failed (probably a memory allocation error!");
213+
throw std::runtime_error("Conversion to JSON failed (probably a memory allocation error)!");
210214
}
211215

212216
m_record.size_used = size_t(rc);
213-
// Append the record with end of line character
214-
buffer_append("\n");
217+
218+
if (m_format.detailed_info) {
219+
220+
// Remove '}' parenthesis at the end of the record
221+
m_record.size_used--;
222+
223+
// Array for formatting detailed info fields
224+
char field[64];
225+
snprintf(field, 64, ",\"ipfix:exportTime\":\"%" PRIu32 "\"", ntohl(hdr->export_time));
226+
buffer_append(field);
227+
228+
snprintf(field, 64, ",\"ipfix:seqNumber\":\"%" PRIu32 "\"", ntohl(hdr->seq_num));
229+
buffer_append(field);
230+
231+
snprintf(field, 64, ",\"ipfix:odid\":\"%" PRIu32 "\"", ntohl(hdr->odid));
232+
buffer_append(field);
233+
234+
snprintf(field, 32, ",\"ipfix:msgLength\":\"%" PRIu16 "\"", ntohs(hdr->length));
235+
buffer_append(field);
236+
237+
snprintf(field, 32, ",\"ipfix:templateId\":\"%" PRIu16 "\"", rec.tmplt->id);
238+
buffer_append(field);
239+
240+
// Append the record with '}' parenthesis removed before
241+
buffer_append("}");
242+
}
243+
244+
// Append the record with end of line character
245+
buffer_append("\n");
215246

216247
/* Note: additional information (e.g. ODID, Export Time, etc.) can be added here,
217248
* just use buffer_append() and buffer_reserve() to append and extend buffer, respectively.

src/plugins/output/json/src/Storage.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ class Storage {
9595
} m_record; /**< Converted JSON record */
9696

9797
// Convert an IPFIX record to a JSON string
98-
void convert(struct fds_drec &rec, const fds_iemgr_t *iemgr, bool reverse = false);
98+
void convert(struct fds_drec &rec, const fds_iemgr_t *iemgr, struct fds_ipfix_msg_hdr *hdr, bool reverse = false);
9999

100100
// Remaining buffer size
101101
size_t buffer_remain() const {return m_record.size_alloc - m_record.size_used;};

0 commit comments

Comments
 (0)