1 /**
2  ** @internal
3  ** yafcore.c
4  ** YAF core I/O routines
5  **
6  ** ------------------------------------------------------------------------
7  ** Copyright (C) 2006-2019 Carnegie Mellon University. All Rights Reserved.
8  ** ------------------------------------------------------------------------
9  ** Authors: Brian Trammell, Chris Inacio, Emily Ecoff <ecoff@cert.org>
10  ** ------------------------------------------------------------------------
11  ** @OPENSOURCE_HEADER_START@
12  ** Use of the YAF system and related source code is subject to the terms
13  ** of the following licenses:
14  **
15  ** GNU Public License (GPL) Rights pursuant to Version 2, June 1991
16  ** Government Purpose License Rights (GPLR) pursuant to DFARS 252.227.7013
17  **
18  ** NO WARRANTY
19  **
20  ** ANY INFORMATION, MATERIALS, SERVICES, INTELLECTUAL PROPERTY OR OTHER
21  ** PROPERTY OR RIGHTS GRANTED OR PROVIDED BY CARNEGIE MELLON UNIVERSITY
22  ** PURSUANT TO THIS LICENSE (HEREINAFTER THE "DELIVERABLES") ARE ON AN
23  ** "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY
24  ** KIND, EITHER EXPRESS OR IMPLIED AS TO ANY MATTER INCLUDING, BUT NOT
25  ** LIMITED TO, WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE,
26  ** MERCHANTABILITY, INFORMATIONAL CONTENT, NONINFRINGEMENT, OR ERROR-FREE
27  ** OPERATION. CARNEGIE MELLON UNIVERSITY SHALL NOT BE LIABLE FOR INDIRECT,
28  ** SPECIAL OR CONSEQUENTIAL DAMAGES, SUCH AS LOSS OF PROFITS OR INABILITY
29  ** TO USE SAID INTELLECTUAL PROPERTY, UNDER THIS LICENSE, REGARDLESS OF
30  ** WHETHER SUCH PARTY WAS AWARE OF THE POSSIBILITY OF SUCH DAMAGES.
31  ** LICENSEE AGREES THAT IT WILL NOT MAKE ANY WARRANTY ON BEHALF OF
32  ** CARNEGIE MELLON UNIVERSITY, EXPRESS OR IMPLIED, TO ANY PERSON
33  ** CONCERNING THE APPLICATION OF OR THE RESULTS TO BE OBTAINED WITH THE
34  ** DELIVERABLES UNDER THIS LICENSE.
35  **
36  ** Licensee hereby agrees to defend, indemnify, and hold harmless Carnegie
37  ** Mellon University, its trustees, officers, employees, and agents from
38  ** all claims or demands made against them (and any related losses,
39  ** expenses, or attorney's fees) arising out of, or relating to Licensee's
40  ** and/or its sub licensees' negligent use or willful misuse of or
41  ** negligent conduct or willful misconduct regarding the Software,
42  ** facilities, or other rights or assistance granted by Carnegie Mellon
43  ** University under this License, including, but not limited to, any
44  ** claims of product liability, personal injury, death, damage to
45  ** property, or violation of any laws or regulations.
46  **
47  ** Carnegie Mellon University Software Engineering Institute authored
48  ** documents are sponsored by the U.S. Department of Defense under
49  ** Contract FA8721-05-C-0003. Carnegie Mellon University retains
50  ** copyrights in all material produced under this contract. The U.S.
51  ** Government retains a non-exclusive, royalty-free license to publish or
52  ** reproduce these documents, or allow others to do so, for U.S.
53  ** Government purposes only pursuant to the copyright license under the
54  ** contract clause at 252.227.7013.
55  **
56  ** @OPENSOURCE_HEADER_END@
57  ** ------------------------------------------------------------------------
58  */
59 
60 #define _YAF_SOURCE_
61 #include "yafctx.h"
62 #include <yaf/yafcore.h>
63 #include <yaf/decode.h>
64 #include <airframe/airutil.h>
65 #include <yaf/yafrag.h>
66 
67 #define INFOMODEL_EXCLUDE_yaf_dpi 1
68 #define INFOMODEL_EXCLUDE_yaf_dhcp 1
69 #include "infomodel.h"
70 
71 #ifdef YAF_ENABLE_HOOKS
72 #include <yaf/yafhooks.h>
73 #endif
74 
75 #define FBSTMLINIT(s, i, t) fbSubTemplateMultiListEntryInit(s, i, t, 1)
76 #define FBSTMLNEXT(p, s) fbSubTemplateMultiListGetNextEntry(p, s)
77 
78 /** These are the template ID's for the templates that YAF uses to
79     select the output. Template ID's are maintained for a set of
80     basic flow types data
81     * BASE which gets various additions added as the flow requires,
82     * FULL base plus the internal fields are added
83     * EXT (extended) which has the additional records in the
84       yaf_extime_spec (extended time specification)
85 
86     WARNING: these need to be adjusted according to changes in the
87     general & special dimensions */
88 #define YAF_FLOW_BASE_TID   0xB000 /* no general or special definitions */
89 #define YAF_FLOW_FULL_TID   0xB800 /* base no internal*/
90 #define YAF_FLOW_EXT_TID    0xB7FF /* everything except internal */
91 
92 #define YAF_PROCESS_STATS_TID     0xD003
93 #define YAF_TOMBSTONE_TID         0xD004
94 #define YAF_TOMBSTONE_ACCESS_TID  0xD005
95 #define YAF_TYPE_METADATA_TID     0xD006
96 #define YAF_TEMPLATE_METADATA_TID 0xD007
97 
98 
99 #define YAF_FLOW_BASE_NAME "yaf_flow_base"
100 #define YAF_FLOW_FULL_NAME "yaf_flow_full"
101 #define YAF_FLOW_EXT_NAME  "yaf_flow_ext"
102 
103 #define YAF_PROCESS_STATS_NAME      "yaf_process_stats"
104 #define YAF_TOMBSTONE_NAME          "tombstone_record"
105 #define YAF_TOMBSTONE_ACCESS_NAME   "tombstone_access"
106 
107 /* 49154 - 49160 */
108 #define YAF_APP_FLOW_TID       0xC001 /* not used */
109 #define YAF_ENTROPY_FLOW_TID   0xC002
110 #define YAF_TCP_FLOW_TID       0xC003
111 #define YAF_MAC_FLOW_TID       0xC004
112 #define YAF_STATS_FLOW_TID     0xC005
113 #define YAF_P0F_FLOW_TID       0xC006
114 #define YAF_FPEXPORT_FLOW_TID  0xC007
115 #define YAF_PAYLOAD_FLOW_TID   0xC008
116 #define YAF_MPTCP_FLOW_TID     0xC009
117 
118 #define YAF_APP_FLOW_NAME           "UNUSED" /* not used */
119 #define YAF_ENTROPY_FLOW_NAME       "yaf_entropy"
120 #define YAF_ENTROPY_FLOW_REV_NAME   "yaf_entropy_rev"
121 #define YAF_TCP_FLOW_NAME           "yaf_tcp"
122 #define YAF_TCP_FLOW_REV_NAME       "yaf_tcp_rev"
123 #define YAF_MAC_FLOW_NAME           "yaf_mac"
124 #define YAF_STATS_FLOW_NAME         "yaf_flow_stats"
125 #define YAF_STATS_FLOW_REV_NAME     "yaf_flow_stats_rev"
126 #define YAF_P0F_FLOW_NAME           "yaf_p0f"
127 #define YAF_P0F_FLOW_REV_NAME       "yaf_p0f_rev"
128 #define YAF_FPEXPORT_FLOW_NAME      "yaf_fpexport"
129 #define YAF_FPEXPORT_FLOW_REV_NAME  "yaf_fpexport_rev"
130 #define YAF_PAYLOAD_FLOW_NAME       "yaf_payload"
131 #define YAF_PAYLOAD_FLOW_REV_NAME   "yaf_payload_rev"
132 #define YAF_MPTCP_FLOW_NAME         "yaf_mptcp"
133 #define YAF_MPTCP_FLOW_REV_NAME     "yaf_mptcp_rev"
134 
135 /** The dimensions are flags which determine which sets of fields will
136     be exported out to an IPFIX record.  They are entries in a bitmap
137     used to control the template. e.g. TCP flow information (seq num,
138     tcp flags, etc.) only get added to the output record when the
139     YTF_SILK flag is set; it only gets set when the transport protocol
140     is set to 0x06 and YAF is ran with --silk. */
141 
142 /** General dimensions */
143 #define YTF_BIF         0x0010
144 /* Special dimensions */
145 #define YTF_TOTAL       0x0001
146 #define YTF_DELTA       0x0002
147 #define YTF_MPLS        0x0004
148 #define YTF_SILK        0x0020
149 #define YTF_DAGIF       0x0040
150 #define YTF_FLE         0x0080
151 #define YTF_RLE         0x0100
152 #define YTF_IP4         0x0200
153 #define YTF_IP6         0x0400
154 #define YTF_INTERNAL    0x0800
155 #define YTF_ALL         0x0EFF /* this has to be everything _except_ RLE enabled */
156 #define YTF_REV         0xFF0F
157 
158 #define YTF_BIF_NAME         "bif"
159 #define YTF_TOTAL_NAME       "total"
160 #define YTF_DELTA_NAME       "delta"
161 #define YTF_MPLS_NAME        "mpls"
162 #define YTF_SILK_NAME        "silk"
163 #define YTF_DAGIF_NAME       "dagif"
164 #define YTF_FLE_NAME         "fle"
165 #define YTF_RLE_NAME         "rle"
166 #define YTF_IP4_NAME         "ip4"
167 #define YTF_IP6_NAME         "ip6"
168 #define YTF_INTERNAL_NAME    "internal"
169 #define YTF_ALL_NAME         "all"
170 #define YTF_REV_NAME         "rev"
171 
172 /** If any of the FLE/RLE values are larger than this constant
173     then we have to use FLE, otherwise, we choose RLE to
174     conserve space/bandwidth etc.*/
175 #define YAF_RLEMAX      (1L << 31)
176 
177 #define YF_PRINT_DELIM  "|"
178 
179 /** include the CERT IE extensions for YAF */
180 #define INFOMODEL_EXCLUDE_yaf_dpi 1
181 #define INFOMODEL_EXCLUDE_yaf_dhcp 1
182 #include "infomodel.h"
183 
184 /* IPFIX definition of the full YAF flow record */
185 static fbInfoElementSpec_t yaf_flow_spec[] = {
186     /* Millisecond start and end (epoch) (native time) */
187     { "flowStartMilliseconds",              8, 0 },
188     { "flowEndMilliseconds",                8, 0 },
189     /* Counters */
190     { "octetTotalCount",                    8, YTF_FLE | YTF_TOTAL },
191     { "reverseOctetTotalCount",             8, YTF_FLE | YTF_TOTAL | YTF_BIF },
192     { "packetTotalCount",                   8, YTF_FLE | YTF_TOTAL },
193     { "reversePacketTotalCount",            8, YTF_FLE | YTF_TOTAL | YTF_BIF },
194     /* delta Counters */
195     { "octetDeltaCount",                    8, YTF_FLE | YTF_DELTA },
196     { "reverseOctetDeltaCount",             8, YTF_FLE | YTF_DELTA | YTF_BIF },
197     { "packetDeltaCount",                   8, YTF_FLE | YTF_DELTA },
198     { "reversePacketDeltaCount",            8, YTF_FLE | YTF_DELTA | YTF_BIF },
199     /* Reduced-length counters */
200     { "octetTotalCount",                    4, YTF_RLE | YTF_TOTAL },
201     { "reverseOctetTotalCount",             4, YTF_RLE | YTF_TOTAL| YTF_BIF },
202     { "packetTotalCount",                   4, YTF_RLE | YTF_TOTAL },
203     { "reversePacketTotalCount",            4, YTF_RLE | YTF_TOTAL | YTF_BIF },
204     /* Reduced-length delta counters */
205     { "octetDeltaCount",                    4, YTF_RLE | YTF_DELTA },
206     { "reverseOctetDeltaCount",             4, YTF_RLE | YTF_DELTA | YTF_BIF },
207     { "packetDeltaCount",                   4, YTF_RLE | YTF_DELTA },
208     { "reversePacketDeltaCount",            4, YTF_RLE | YTF_DELTA | YTF_BIF },
209     /* 5-tuple and flow status */
210     { "sourceIPv6Address",                  16, YTF_IP6 },
211     { "destinationIPv6Address",             16, YTF_IP6 },
212     { "sourceIPv4Address",                  4, YTF_IP4 },
213     { "destinationIPv4Address",             4, YTF_IP4 },
214     { "sourceTransportPort",                2, 0 },
215     { "destinationTransportPort",           2, 0 },
216     { "flowAttributes",                     2, 0 },
217     { "reverseFlowAttributes",              2, YTF_BIF },
218     { "protocolIdentifier",                 1, 0 },
219     { "flowEndReason",                      1, 0 },
220 #if defined(YAF_ENABLE_APPLABEL)
221     { "silkAppLabel",                       2, 0 },
222 #else
223     { "paddingOctets",                      2, YTF_INTERNAL },
224 #endif
225     /* Round-trip time */
226     { "reverseFlowDeltaMilliseconds",       4, YTF_BIF }, /*  32-bit */
227     /*TCP Info would need to go here 4 SiLK & 4b padding*/
228     { "tcpSequenceNumber",                  4, YTF_SILK },
229     { "reverseTcpSequenceNumber",           4, YTF_SILK | YTF_BIF },
230     { "initialTCPFlags",                    1, YTF_SILK },
231     { "unionTCPFlags",                      1, YTF_SILK },
232     { "reverseInitialTCPFlags",             1, YTF_SILK | YTF_BIF },
233     { "reverseUnionTCPFlags",               1, YTF_SILK | YTF_BIF },
234     { "vlanId",                             2, 0 },
235     { "reverseVlanId",                      2, YTF_BIF },
236     { "ingressInterface",                   4, YTF_DAGIF },
237     { "egressInterface",                    4, YTF_DAGIF },
238     { "ipClassOfService",                   1, 0 },
239     { "reverseIpClassOfService",            1, YTF_BIF },
240     { "mplsTopLabelStackSection",           3, YTF_MPLS },
241     { "mplsLabelStackSection2",             3, YTF_MPLS },
242     { "mplsLabelStackSection3",             3, YTF_MPLS },
243 #if defined(YAF_ENABLE_NDPI)
244     { "paddingOctets",                      1, YTF_INTERNAL },
245     { "nDPIL7Protocol",                     2, 0 },
246     { "nDPIL7SubProtocol",                  2, 0 },
247 #else
248     { "paddingOctets",                      5, YTF_INTERNAL },
249 #endif
250     { "subTemplateMultiList",               FB_IE_VARLEN, 0 },
251     FB_IESPEC_NULL
252 };
253 
254 
255 #   if defined(YAF_ENABLE_ENTROPY)
256     /* entropy fields */
257 static fbInfoElementSpec_t yaf_entropy_spec[] = {
258     { "payloadEntropy",                     1, 0 },
259     { "reversePayloadEntropy",              1, YTF_BIF },
260     FB_IESPEC_NULL
261 };
262 #endif
263 
264 static fbInfoElementSpec_t yaf_tcp_spec[] = {
265     /* TCP-specific information */
266     { "tcpSequenceNumber",                  4, 0 },
267     { "initialTCPFlags",                    1, 0 },
268     { "unionTCPFlags",                      1, 0 },
269     { "reverseInitialTCPFlags",             1, YTF_BIF },
270     { "reverseUnionTCPFlags",               1, YTF_BIF },
271     { "reverseTcpSequenceNumber",           4, YTF_BIF },
272     FB_IESPEC_NULL
273 };
274 
275 /* MAC-specific information */
276 static fbInfoElementSpec_t yaf_mac_spec[] = {
277     { "sourceMacAddress",                   6, 0 },
278     { "destinationMacAddress",              6, 0 },
279     FB_IESPEC_NULL
280 };
281 
282 static fbInfoElementSpec_t yaf_mptcp_spec[] = {
283     { "mptcpInitialDataSequenceNumber",     8, 0 },
284     { "mptcpReceiverToken",                 4, 0 },
285     { "mptcpMaximumSegmentSize",            2, 0 },
286     { "mptcpAddressID",                     1, 0 },
287     { "mptcpFlags",                         1, 0 },
288     FB_IESPEC_NULL
289 };
290 
291 
292 #   if YAF_ENABLE_P0F
293 static fbInfoElementSpec_t yaf_p0f_spec[] = {
294     { "osName",                             FB_IE_VARLEN, 0 },
295     { "osVersion",                          FB_IE_VARLEN, 0 },
296     { "osFingerPrint",                      FB_IE_VARLEN, 0 },
297     { "reverseOsName",                      FB_IE_VARLEN, YTF_BIF },
298     { "reverseOsVersion",                   FB_IE_VARLEN, YTF_BIF },
299     { "reverseOsFingerPrint",               FB_IE_VARLEN, YTF_BIF },
300     FB_IESPEC_NULL
301 };
302 #   endif
303 
304 #   if YAF_ENABLE_FPEXPORT
305 static fbInfoElementSpec_t yaf_fpexport_spec[] = {
306     { "firstPacketBanner",                  FB_IE_VARLEN, 0 },
307     { "secondPacketBanner",                 FB_IE_VARLEN, 0 },
308     { "reverseFirstPacketBanner",           FB_IE_VARLEN, YTF_BIF },
309     FB_IESPEC_NULL
310 };
311 #   endif
312 
313 #   if YAF_ENABLE_PAYLOAD
314     /* Variable-length payload fields */
315 static fbInfoElementSpec_t yaf_payload_spec[] = {
316     { "payload",                            FB_IE_VARLEN, 0 },
317     { "reversePayload",                     FB_IE_VARLEN, YTF_BIF },
318     FB_IESPEC_NULL
319 };
320 #   endif
321 
322 /* IPFIX definition of the YAF flow record time extension */
323 static fbInfoElementSpec_t yaf_extime_spec[] = {
324     /* Microsecond start and end (RFC1305-style) (extended time) */
325     { "flowStartMicroseconds",              8, 0 },
326     { "flowEndMicroseconds",                8, 0 },
327     /* Second start, end, and duration (extended time) */
328     { "flowStartSeconds",                   4, 0 },
329     { "flowEndSeconds",                     4, 0 },
330     /* Flow durations (extended time) */
331     { "flowDurationMicroseconds",           4, 0 },
332     { "flowDurationMilliseconds",           4, 0 },
333     /* Microsecond delta start and end (extended time) */
334     { "flowStartDeltaMicroseconds",         4, 0 },
335     { "flowEndDeltaMicroseconds",           4, 0 },
336     FB_IESPEC_NULL
337 };
338 
339 static fbInfoElementSpec_t yaf_process_stats_spec[] = {
340     { "observationDomainId",                4, 0 },
341     { "exportingProcessId",                 4, 0 },
342     { "exporterIPv4Address",                4, 0 },
343     { "observationTimeSeconds",             4, 0 },
344     { "systemInitTimeMilliseconds",         8, 0 },
345     { "exportedFlowRecordTotalCount",       8, 0 },
346     { "packetTotalCount",                   8, 0 },
347     { "droppedPacketTotalCount",            8, 0 },
348     { "ignoredPacketTotalCount",            8, 0 },
349     { "notSentPacketTotalCount",            8, 0 },
350     { "expiredFragmentCount",               4, 0 },
351     { "assembledFragmentCount",             4, 0 },
352     { "flowTableFlushEventCount",           4, 0 },
353     { "flowTablePeakCount",                 4, 0 },
354     { "meanFlowRate",                       4, 0 },
355     { "meanPacketRate",                     4, 0 },
356     FB_IESPEC_NULL
357 };
358 
359 static fbInfoElementSpec_t yaf_tombstone_spec[] = {
360     { "observationDomainId",                4, 0 },
361     { "exportingProcessId",                 4, 0 },
362     { "exporterConfiguredId",               2, 0 },
363     { "paddingOctets",                      6, 0 },
364     { "tombstoneId",                        4, 0 },
365     { "observationTimeSeconds",             4, 0 },
366     { "tombstoneAccessList",                FB_IE_VARLEN, 0 },
367     FB_IESPEC_NULL
368 };
369 
370 static fbInfoElementSpec_t yaf_tombstone_access_spec[] = {
371     { "certToolId",                         4, 0 },
372     { "observationTimeSeconds",             4, 0 },
373     FB_IESPEC_NULL
374 };
375 
376 static fbInfoElementSpec_t yaf_flow_stats_spec[] = {
377     { "dataByteCount",                      8, 0 },
378     { "averageInterarrivalTime",            8, 0 },
379     { "standardDeviationInterarrivalTime",  8, 0 },
380     { "tcpUrgTotalCount",                   4, 0 },
381     { "smallPacketCount",                   4, 0 },
382     { "nonEmptyPacketCount",                4, 0 },
383     { "largePacketCount",                   4, 0 },
384     { "firstNonEmptyPacketSize",            2, 0 },
385     { "maxPacketSize",                      2, 0 },
386     { "standardDeviationPayloadLength",     2, 0 },
387     { "firstEightNonEmptyPacketDirections", 1, 0 },
388     { "paddingOctets",                      1, 1 },
389     { "reverseDataByteCount",               8, YTF_BIF },
390     { "reverseAverageInterarrivalTime",     8, YTF_BIF },
391     { "reverseStandardDeviationInterarrivalTime", 8, YTF_BIF },
392     { "reverseTcpUrgTotalCount",            4, YTF_BIF },
393     { "reverseSmallPacketCount",            4, YTF_BIF },
394     { "reverseNonEmptyPacketCount",         4, YTF_BIF },
395     { "reverseLargePacketCount",            4, YTF_BIF },
396     { "reverseFirstNonEmptyPacketSize",     2, YTF_BIF },
397     { "reverseMaxPacketSize",               2, YTF_BIF },
398     { "reverseStandardDeviationPayloadLength", 2, YTF_BIF },
399     { "paddingOctets",                      2, 1 },
400     FB_IESPEC_NULL
401 };
402 
403 
404 typedef struct yfFlowStatsRecord_st {
405     uint64_t dataByteCount;
406     uint64_t averageInterarrivalTime;
407     uint64_t standardDeviationInterarrivalTime;
408     uint32_t tcpUrgTotalCount;
409     uint32_t smallPacketCount;
410     uint32_t nonEmptyPacketCount;
411     uint32_t largePacketCount;
412     uint16_t firstNonEmptyPacketSize;
413     uint16_t maxPacketSize;
414     uint16_t standardDeviationPayloadLength;
415     uint8_t  firstEightNonEmptyPacketDirections;
416     uint8_t  padding[1];
417     /* reverse Fields */
418     uint64_t reverseDataByteCount;
419     uint64_t reverseAverageInterarrivalTime;
420     uint64_t reverseStandardDeviationInterarrivalTime;
421     uint32_t reverseTcpUrgTotalCount;
422     uint32_t reverseSmallPacketCount;
423     uint32_t reverseNonEmptyPacketCount;
424     uint32_t reverseLargePacketCount;
425     uint16_t reverseFirstNonEmptyPacketSize;
426     uint16_t reverseMaxPacketSize;
427     uint16_t reverseStandardDeviationPayloadLength;
428     uint8_t  padding2[2];
429 } yfFlowStatsRecord_t;
430 
431 typedef struct yfTemplates_st {
432     fbTemplate_t *ipfixStatsTemplate;
433     fbTemplate_t *tombstoneRecordTemplate;
434     fbTemplate_t *tombstoneAccessTemplate;
435     fbTemplate_t *fstatsTemplate;
436     fbTemplate_t *revfstatsTemplate;
437 #if YAF_ENABLE_ENTROPY
438     fbTemplate_t *entropyTemplate;
439     fbTemplate_t *revEntropyTemplate;
440 #endif
441     fbTemplate_t *tcpTemplate;
442     fbTemplate_t *revTcpTemplate;
443     fbTemplate_t *macTemplate;
444     fbTemplate_t *mptcpTemplate;
445 #if YAF_ENABLE_P0F
446     fbTemplate_t *p0fTemplate;
447     fbTemplate_t *revP0fTemplate;
448 #endif
449 #if YAF_ENABLE_FPEXPORT
450     fbTemplate_t *fpexportTemplate;
451     fbTemplate_t *revFpexportTemplate;
452 #endif
453 #if YAF_ENABLE_PAYLOAD
454     fbTemplate_t *payloadTemplate;
455     fbTemplate_t *revPayloadTemplate;
456 #endif
457 } yfTemplates_t;
458 
459 static yfTemplates_t yaf_tmpl;
460 
461 /* IPv6-mapped IPv4 address prefix */
462 static uint8_t yaf_ip6map_pfx[12] =
463     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF };
464 
465 /* Full YAF flow record. */
466 typedef struct yfIpfixFlow_st {
467     uint64_t    flowStartMilliseconds;
468     uint64_t    flowEndMilliseconds;
469     uint64_t    octetTotalCount;
470     uint64_t    reverseOctetTotalCount;
471     uint64_t    packetTotalCount;
472     uint64_t    reversePacketTotalCount;
473     uint64_t    octetDeltaCount;
474     uint64_t    reverseOctetDeltaCount;
475     uint64_t    packetDeltaCount;
476     uint64_t    reversePacketDeltaCount;
477     uint8_t     sourceIPv6Address[16];
478     uint8_t     destinationIPv6Address[16];
479     uint32_t    sourceIPv4Address;
480     uint32_t    destinationIPv4Address;
481     uint16_t    sourceTransportPort;
482     uint16_t    destinationTransportPort;
483     uint16_t    flowAttributes;
484     uint16_t    reverseFlowAttributes;
485     uint8_t     protocolIdentifier;
486     uint8_t     flowEndReason;
487 #if YAF_ENABLE_APPLABEL
488     uint16_t    silkAppLabel;
489 #else
490     uint8_t     paddingOctets[2];
491 #endif
492     int32_t     reverseFlowDeltaMilliseconds;
493     /* TCP stuff for SiLK */
494     uint32_t    tcpSequenceNumber;
495     uint32_t    reverseTcpSequenceNumber;
496     uint8_t     initialTCPFlags;
497     uint8_t     unionTCPFlags;
498     uint8_t     reverseInitialTCPFlags;
499     uint8_t     reverseUnionTCPFlags;
500     /* MAC Specific Info */
501     uint16_t    vlanId;
502     uint16_t    reverseVlanId;
503     uint32_t    ingressInterface;
504     uint32_t    egressInterface;
505     /* MPLS! */
506     uint8_t     ipClassOfService;
507     uint8_t     reverseIpClassOfService;
508     uint8_t     mpls_label1[3];
509     uint8_t     mpls_label2[3];
510     uint8_t     mpls_label3[3];
511 #if YAF_ENABLE_NDPI
512     uint8_t     paddingOctets2[1];
513     uint16_t    ndpi_master;
514     uint16_t    ndpi_sub;
515 #else
516     uint8_t     paddingOctets3[5];
517 #endif
518     fbSubTemplateMultiList_t subTemplateMultiList;
519 } yfIpfixFlow_t;
520 
521 
522 #if YAF_ENABLE_ENTROPY
523 typedef struct yfEntropyFlow_st {
524     uint8_t     entropy;
525     uint8_t     reverseEntropy;
526 } yfEntropyFlow_t;
527 #endif
528 
529 typedef struct yfTcpFlow_st {
530     uint32_t    tcpSequenceNumber;
531     uint8_t     initialTCPFlags;
532     uint8_t     unionTCPFlags;
533     uint8_t     reverseInitialTCPFlags;
534     uint8_t     reverseUnionTCPFlags;
535     uint32_t    reverseTcpSequenceNumber;
536 } yfTcpFlow_t;
537 
538 typedef struct yfMacFlow_st {
539     uint8_t     sourceMacAddress[6];
540     uint8_t     destinationMacAddress[6];
541 } yfMacFlow_t;
542 
543 #   if YAF_ENABLE_P0F
544 typedef struct yfP0fFlow_st {
545     fbVarfield_t    osName;
546     fbVarfield_t    osVersion;
547     fbVarfield_t    osFingerPrint;
548     fbVarfield_t    reverseOsName;
549     fbVarfield_t    reverseOsVersion;
550     fbVarfield_t    reverseOsFingerPrint;
551 } yfP0fFlow_t;
552 #   endif
553 
554 #   if YAF_ENABLE_FPEXPORT
555 typedef struct yfFPExportFlow_st {
556     fbVarfield_t    firstPacketBanner;
557     fbVarfield_t    secondPacketBanner;
558     fbVarfield_t    reverseFirstPacketBanner;
559 } yfFPExportFlow_t;
560 #   endif
561 
562 #   if YAF_ENABLE_PAYLOAD
563 typedef struct yfPayloadFlow_st {
564     fbVarfield_t payload;
565     fbVarfield_t reversePayload;
566 } yfPayloadFlow_t;
567 #   endif
568 
569 typedef struct yfIpfixExtFlow_st {
570     yfIpfixFlow_t   f;
571     uint64_t    flowStartMicroseconds;
572     uint64_t    flowEndMicroseconds;
573     uint32_t    flowStartSeconds;
574     uint32_t    flowEndSeconds;
575     uint32_t    flowDurationMicroseconds;
576     uint32_t    flowDurationMilliseconds;
577     uint32_t    flowStartDeltaMicroseconds;
578     uint32_t    flowEndDeltaMicroseconds;
579 } yfIpfixExtFlow_t;
580 
581 typedef struct yfIpfixStats_st {
582     uint32_t    observationDomainId;
583     uint32_t    exportingProcessId;
584     uint32_t    exporterIPv4Address;
585     uint32_t    observationTimeSeconds;
586     uint64_t    systemInitTimeMilliseconds;
587     uint64_t    exportedFlowTotalCount;
588     uint64_t    packetTotalCount;
589     uint64_t    droppedPacketTotalCount;
590     uint64_t    ignoredPacketTotalCount;
591     uint64_t    notSentPacketTotalCount;
592     uint32_t    expiredFragmentCount;
593     uint32_t    assembledFragmentCount;
594     uint32_t    flowTableFlushEvents;
595     uint32_t    flowTablePeakCount;
596     uint32_t    meanFlowRate;
597     uint32_t    meanPacketRate;
598 } yfIpfixStats_t;
599 
600 typedef struct yfTombstoneRecord_st {
601     uint32_t            observationDomainId;
602     uint32_t            exportingProcessId;
603     uint16_t            exporterConfiguredId;
604     uint8_t             paddingOctets[6];
605     uint32_t            tombstoneId;
606     uint32_t            observationTimeSeconds;
607     fbSubTemplateList_t accessList;
608 } yfTombstoneRecord_t;
609 
610 typedef struct yfTombstoneAccess_st {
611     uint32_t    certToolId;
612     uint32_t    observationTimeSeconds;
613 } yfTombstoneAccess_t;
614 
615 /* Core library configuration variables */
616 static int yaf_core_export_payload = 0;
617 static gboolean yaf_core_map_ipv6 = FALSE;
618 
619 /**
620  * yfAlignmentCheck
621  *
622  * this checks the alignment of the template and corresponding record
623  * ideally, all this magic would happen at compile time, but it
624  * doesn't currently, (can't really do it in C,) so we do it at
625  * run time
626  *
627  *
628  * @param err a Glib error structure pointer initialized with an
629  *        empty error on input, if an alignment error is detected
630  *        then a new error will be put into the pointer.
631  *
632  */
yfAlignmentCheck()633 void yfAlignmentCheck()
634 {
635     size_t prevOffset = 0;
636     size_t prevSize = 0;
637 
638 #define DO_SIZE(S_,F_) (SIZE_T_CAST)sizeof(((S_ *)(0))->F_)
639 #define EA_STRING(S_,F_) "alignment error in struct " #S_ " for element "   \
640                          #F_ " offset %#"SIZE_T_FORMATX" size %"            \
641                          SIZE_T_FORMAT" (pad %"SIZE_T_FORMAT")",            \
642                          (SIZE_T_CAST)offsetof(S_,F_), DO_SIZE(S_,F_),      \
643                          (SIZE_T_CAST)(offsetof(S_,F_) % DO_SIZE(S_,F_))
644 #define EG_STRING(S_,F_) "gap error in struct " #S_ " for element " #F_     \
645                          " offset %#"SIZE_T_FORMATX" size %"SIZE_T_FORMAT,  \
646                          (SIZE_T_CAST)offsetof(S_,F_),                      \
647                          DO_SIZE(S_,F_)
648 #define RUN_CHECKS(S_,F_,A_) {                                          \
649         if (((offsetof(S_,F_) % DO_SIZE(S_,F_)) != 0) && A_) {          \
650             g_error(EA_STRING(S_,F_));                                  \
651         }                                                               \
652         if (offsetof(S_,F_) != (prevOffset+prevSize)) {                 \
653             g_error(EG_STRING(S_,F_));                                  \
654             return;                                                     \
655         }                                                               \
656         prevOffset = offsetof(S_,F_);                                   \
657         prevSize = DO_SIZE(S_,F_);                                      \
658 /*        fprintf(stderr, "%17s %40s %#5lx %3d %#5lx\n", #S_, #F_,      \
659                 offsetof(S_,F_), DO_SIZE(S_,F_),                        \
660                 offsetof(S_,F_)+DO_SIZE(S_,F_));*/                      \
661     }
662 
663     RUN_CHECKS(yfIpfixFlow_t,flowStartMilliseconds,1);
664     RUN_CHECKS(yfIpfixFlow_t,flowEndMilliseconds,1);
665     RUN_CHECKS(yfIpfixFlow_t,octetTotalCount,1);
666     RUN_CHECKS(yfIpfixFlow_t,reverseOctetTotalCount,1);
667     RUN_CHECKS(yfIpfixFlow_t,packetTotalCount,1);
668     RUN_CHECKS(yfIpfixFlow_t,reversePacketTotalCount,1);
669     RUN_CHECKS(yfIpfixFlow_t,octetDeltaCount,1);
670     RUN_CHECKS(yfIpfixFlow_t,reverseOctetDeltaCount,1);
671     RUN_CHECKS(yfIpfixFlow_t,packetDeltaCount,1);
672     RUN_CHECKS(yfIpfixFlow_t,reversePacketDeltaCount,1);
673     RUN_CHECKS(yfIpfixFlow_t,sourceIPv6Address,1);
674     RUN_CHECKS(yfIpfixFlow_t,destinationIPv6Address,1);
675     RUN_CHECKS(yfIpfixFlow_t,sourceIPv4Address,1);
676     RUN_CHECKS(yfIpfixFlow_t,destinationIPv4Address,1);
677     RUN_CHECKS(yfIpfixFlow_t,sourceTransportPort,1);
678     RUN_CHECKS(yfIpfixFlow_t,destinationTransportPort,1);
679     RUN_CHECKS(yfIpfixFlow_t,flowAttributes,1);
680     RUN_CHECKS(yfIpfixFlow_t,reverseFlowAttributes,1);
681     RUN_CHECKS(yfIpfixFlow_t,protocolIdentifier,1);
682     RUN_CHECKS(yfIpfixFlow_t,flowEndReason,1);
683 #if YAF_ENABLE_APPLABEL
684     RUN_CHECKS(yfIpfixFlow_t,silkAppLabel,1);
685 #else
686     RUN_CHECKS(yfIpfixFlow_t,paddingOctets,0);
687 #endif
688     RUN_CHECKS(yfIpfixFlow_t,reverseFlowDeltaMilliseconds,1);
689 
690     /* TCP stuff for SiLK only! */
691     RUN_CHECKS(yfIpfixFlow_t,tcpSequenceNumber,1);
692     RUN_CHECKS(yfIpfixFlow_t,reverseTcpSequenceNumber,1);
693     RUN_CHECKS(yfIpfixFlow_t,initialTCPFlags,1);
694     RUN_CHECKS(yfIpfixFlow_t,unionTCPFlags,1);
695     RUN_CHECKS(yfIpfixFlow_t,reverseInitialTCPFlags,1);
696     RUN_CHECKS(yfIpfixFlow_t,reverseUnionTCPFlags,1);
697 
698     RUN_CHECKS(yfIpfixFlow_t,vlanId,1);
699     RUN_CHECKS(yfIpfixFlow_t,reverseVlanId,1);
700 
701     RUN_CHECKS(yfIpfixFlow_t,ingressInterface,1);
702     RUN_CHECKS(yfIpfixFlow_t,egressInterface,1);
703 
704     RUN_CHECKS(yfIpfixFlow_t,ipClassOfService,1);
705     RUN_CHECKS(yfIpfixFlow_t,reverseIpClassOfService,1);
706     RUN_CHECKS(yfIpfixFlow_t,mpls_label1,1);
707     RUN_CHECKS(yfIpfixFlow_t,mpls_label2,1);
708     RUN_CHECKS(yfIpfixFlow_t,mpls_label3,1);
709 #if YAF_ENABLE_NDPI
710     RUN_CHECKS(yfIpfixFlow_t,paddingOctets2,0);
711     RUN_CHECKS(yfIpfixFlow_t,ndpi_master,1);
712     RUN_CHECKS(yfIpfixFlow_t,ndpi_sub,1);
713 #else
714     RUN_CHECKS(yfIpfixFlow_t,paddingOctets3,0);
715 #endif
716     RUN_CHECKS(yfIpfixFlow_t,subTemplateMultiList,0);
717     prevOffset = 0;
718     prevSize = 0;
719 
720     RUN_CHECKS(yfIpfixExtFlow_t,f,1);
721     RUN_CHECKS(yfIpfixExtFlow_t,flowStartMicroseconds,1);
722     RUN_CHECKS(yfIpfixExtFlow_t,flowEndMicroseconds,1);
723     RUN_CHECKS(yfIpfixExtFlow_t,flowStartSeconds,1);
724     RUN_CHECKS(yfIpfixExtFlow_t,flowEndSeconds,1);
725     RUN_CHECKS(yfIpfixExtFlow_t,flowDurationMicroseconds,1);
726     RUN_CHECKS(yfIpfixExtFlow_t,flowDurationMilliseconds,1);
727     RUN_CHECKS(yfIpfixExtFlow_t,flowStartDeltaMicroseconds,1);
728     RUN_CHECKS(yfIpfixExtFlow_t,flowEndDeltaMicroseconds,1);
729     prevOffset = 0;
730     prevSize = 0;
731 
732     RUN_CHECKS(yfIpfixStats_t, observationDomainId, 1);
733     RUN_CHECKS(yfIpfixStats_t, exportingProcessId, 1);
734     RUN_CHECKS(yfIpfixStats_t, exporterIPv4Address,1);
735     RUN_CHECKS(yfIpfixStats_t, observationTimeSeconds, 1);
736     RUN_CHECKS(yfIpfixStats_t, systemInitTimeMilliseconds,1);
737     RUN_CHECKS(yfIpfixStats_t, exportedFlowTotalCount,1);
738     RUN_CHECKS(yfIpfixStats_t, packetTotalCount, 1);
739     RUN_CHECKS(yfIpfixStats_t, droppedPacketTotalCount,1);
740     RUN_CHECKS(yfIpfixStats_t, ignoredPacketTotalCount, 1);
741     RUN_CHECKS(yfIpfixStats_t, notSentPacketTotalCount, 1);
742     RUN_CHECKS(yfIpfixStats_t, expiredFragmentCount,1);
743     RUN_CHECKS(yfIpfixStats_t, assembledFragmentCount,1);
744     RUN_CHECKS(yfIpfixStats_t, flowTableFlushEvents,1);
745     RUN_CHECKS(yfIpfixStats_t, flowTablePeakCount,1);
746     RUN_CHECKS(yfIpfixStats_t, meanFlowRate, 1);
747     RUN_CHECKS(yfIpfixStats_t, meanPacketRate, 1);
748 
749     prevOffset = 0;
750     prevSize = 0;
751 
752     RUN_CHECKS(yfTombstoneRecord_t, observationDomainId, 1);
753     RUN_CHECKS(yfTombstoneRecord_t, exportingProcessId, 1);
754     RUN_CHECKS(yfTombstoneRecord_t, exporterConfiguredId, 1);
755     RUN_CHECKS(yfTombstoneRecord_t, paddingOctets, 0);
756     RUN_CHECKS(yfTombstoneRecord_t, tombstoneId, 1);
757     RUN_CHECKS(yfTombstoneRecord_t, observationTimeSeconds, 1);
758 
759     prevOffset = 0;
760     prevSize = 0;
761 
762     RUN_CHECKS(yfTombstoneAccess_t, certToolId, 1);
763     RUN_CHECKS(yfTombstoneAccess_t, observationTimeSeconds, 1);
764 
765     prevOffset = 0;
766     prevSize = 0;
767 
768     RUN_CHECKS(yfFlowStatsRecord_t, dataByteCount, 1);
769     RUN_CHECKS(yfFlowStatsRecord_t, averageInterarrivalTime, 1);
770     RUN_CHECKS(yfFlowStatsRecord_t, standardDeviationInterarrivalTime, 1);
771     RUN_CHECKS(yfFlowStatsRecord_t, tcpUrgTotalCount, 1);
772     RUN_CHECKS(yfFlowStatsRecord_t, smallPacketCount, 1);
773     RUN_CHECKS(yfFlowStatsRecord_t, nonEmptyPacketCount, 1);
774     RUN_CHECKS(yfFlowStatsRecord_t, largePacketCount, 1);
775     RUN_CHECKS(yfFlowStatsRecord_t, firstNonEmptyPacketSize, 1);
776     RUN_CHECKS(yfFlowStatsRecord_t, maxPacketSize, 1);
777     RUN_CHECKS(yfFlowStatsRecord_t, standardDeviationPayloadLength, 1);
778     RUN_CHECKS(yfFlowStatsRecord_t, firstEightNonEmptyPacketDirections, 1);
779     RUN_CHECKS(yfFlowStatsRecord_t, padding, 0);
780     RUN_CHECKS(yfFlowStatsRecord_t, reverseDataByteCount, 1);
781     RUN_CHECKS(yfFlowStatsRecord_t, reverseAverageInterarrivalTime, 1);
782     RUN_CHECKS(yfFlowStatsRecord_t,reverseStandardDeviationInterarrivalTime,1);
783     RUN_CHECKS(yfFlowStatsRecord_t, reverseTcpUrgTotalCount, 1);
784     RUN_CHECKS(yfFlowStatsRecord_t, reverseSmallPacketCount, 1);
785     RUN_CHECKS(yfFlowStatsRecord_t, reverseNonEmptyPacketCount, 1);
786     RUN_CHECKS(yfFlowStatsRecord_t, reverseLargePacketCount, 1);
787     RUN_CHECKS(yfFlowStatsRecord_t, reverseFirstNonEmptyPacketSize, 1);
788     RUN_CHECKS(yfFlowStatsRecord_t, reverseMaxPacketSize, 1);
789     RUN_CHECKS(yfFlowStatsRecord_t, reverseStandardDeviationPayloadLength,1);
790     RUN_CHECKS(yfFlowStatsRecord_t, padding2, 0);
791 
792 #undef DO_SIZE
793 #undef EA_STRING
794 #undef EG_STRING
795 #undef RUN_CHECKS
796 
797 }
798 
yfWriterExportPayload(int max_payload)799 void yfWriterExportPayload(
800     int                 max_payload)
801 {
802     yaf_core_export_payload = max_payload;
803 }
804 
yfWriterExportMappedV6(gboolean map_mode)805 void yfWriterExportMappedV6(
806     gboolean            map_mode)
807 {
808     yaf_core_map_ipv6 = map_mode;
809 }
810 
811 
812 /**
813  * yfFlowPrepare
814  *
815  * initialize the state of a flow to be "clean" so that they
816  * can be reused
817  *
818  */
yfFlowPrepare(yfFlow_t * flow)819 void yfFlowPrepare(
820     yfFlow_t          *flow)
821 {
822 
823 #if YAF_ENABLE_HOOKS
824     unsigned int loop;
825 #endif
826 
827 #   if YAF_ENABLE_PAYLOAD
828     flow->val.paylen = 0;
829     flow->val.payload = NULL;
830     flow->rval.paylen = 0;
831     flow->rval.payload = NULL;
832 #   endif
833 
834 
835 #   ifdef YAF_ENABLE_HOOKS
836     for (loop = 0; loop < YAF_MAX_HOOKS; loop++) {
837         flow->hfctx[loop] = 0x0;
838     }
839 #   endif
840 
841     memset(flow->sourceMacAddr, 0, ETHERNET_MAC_ADDR_LENGTH);
842     memset(flow->destinationMacAddr, 0, ETHERNET_MAC_ADDR_LENGTH);
843 
844 }
845 
846 
847 /**
848  *yfFlowCleanup
849  *
850  * cleans up after a flow is no longer needed by deallocating
851  * the dynamic memory allocated to the flow (think payload)
852  *
853  */
yfFlowCleanup(yfFlow_t * flow)854 void yfFlowCleanup(
855     yfFlow_t          *flow)
856 {
857 #if YAF_ENABLE_PAYLOAD
858     if (flow->val.payload) {
859         g_free(flow->val.payload);
860         flow->val.payload = NULL;
861     }
862 
863     if (flow->rval.payload) {
864         g_free(flow->rval.payload);
865         flow->rval.payload = NULL;
866     }
867 #endif
868 }
869 
870 /**
871  *yfPayloadCopyIn
872  *
873  *
874  *
875  *
876  */
yfPayloadCopyIn(fbVarfield_t * payvar,yfFlowVal_t * val)877 static void yfPayloadCopyIn(
878     fbVarfield_t     *payvar,
879     yfFlowVal_t       *val)
880 {
881 #   if YAF_ENABLE_PAYLOAD
882     if (payvar->len) {
883         if (!val->payload) {
884             val->payload = g_malloc0(payvar->len);
885         } else {
886             val->payload = g_realloc(val->payload, payvar->len);
887         }
888         val->paylen = payvar->len;
889         memcpy(val->payload, payvar->buf, payvar->len);
890     } else {
891         if (val->payload) g_free(val->payload);
892         val->payload = NULL;
893         val->paylen = 0;
894     }
895 #   endif
896 }
897 
898 /**
899  * yfInfoModel
900  *
901  *
902  */
yfInfoModel()903 static fbInfoModel_t *yfInfoModel()
904 {
905     static fbInfoModel_t *yaf_model = NULL;
906 #if YAF_ENABLE_HOOKS
907     fbInfoElement_t *yaf_hook_elements = NULL;
908 #endif
909     if (!yaf_model) {
910         yaf_model = fbInfoModelAlloc();
911 
912         infomodelAddGlobalElements(yaf_model);
913 
914 #if YAF_ENABLE_HOOKS
915         yaf_hook_elements = yfHookGetInfoModel();
916         if (yaf_hook_elements) {
917             fbInfoModelAddElementArray(yaf_model, yaf_hook_elements);
918         }
919 #endif
920     }
921 
922     return yaf_model;
923 }
924 
925 /**
926  * yfAddTemplate
927  *
928  */
yfAddTemplate(fbSession_t * session,fbInfoElementSpec_t * spec,uint16_t tid,const gchar * name,const gchar * description,gboolean reverse,GError ** err)929 static fbTemplate_t *yfAddTemplate(
930     fbSession_t           *session,
931     fbInfoElementSpec_t   *spec,
932     uint16_t              tid,
933     const gchar           *name,
934     const gchar           *description,
935     gboolean              reverse,
936     GError                **err)
937 {
938     fbInfoModel_t   *model = yfInfoModel();
939     fbTemplate_t    *tmpl = fbTemplateAlloc(model);
940     uint32_t        flags = 0;
941     uint16_t        rtid = tid;
942 
943     if (reverse) {
944         flags = 0xffffffff;
945         rtid = tid | YTF_BIF;
946     }
947 
948     g_debug("yaf: %x (%s), %d (%x)", tid, name, reverse, tid | (reverse ? YTF_BIF : 0));
949 
950     if (!fbTemplateAppendSpecArray(tmpl, spec, flags, err)) {
951         return NULL;
952     }
953 
954 #if YAF_ENABLE_METADATA_EXPORT
955     if (!fbSessionAddTemplateWithMetadata(session, FALSE, rtid,
956                                           tmpl, name, description, err))
957     {
958         return NULL;
959     }
960 #else
961     if (!fbSessionAddTemplate(session, FALSE, rtid, tmpl, err))
962     {
963         return NULL;
964     }
965 #endif
966 
967     if (reverse) {
968         if (!fbSessionAddTemplate(session, TRUE, tid, tmpl, err))
969         {
970             return NULL;
971         }
972     }
973 
974     return tmpl;
975 }
976 
977 /**
978  * yfInitExporterSession
979  *
980  *
981  */
yfInitExporterSession(uint32_t domain,gboolean export_meta,GError ** err)982 static fbSession_t *yfInitExporterSession(
983     uint32_t        domain,
984     gboolean        export_meta,
985     GError          **err)
986 {
987     fbInfoModel_t   *model = yfInfoModel();
988     fbTemplate_t    *tmpl = NULL;
989     fbSession_t     *session = NULL;
990 
991     /* Allocate the session */
992     session = fbSessionAlloc(model);
993 
994    /* set observation domain */
995     fbSessionSetDomain(session, domain);
996 
997    /* Create the full record template */
998     tmpl = fbTemplateAlloc(model);
999     if (!fbTemplateAppendSpecArray(tmpl, yaf_flow_spec, YTF_ALL, err)) {
1000         return NULL;
1001     }
1002 
1003     if (export_meta) {
1004 #if YAF_ENABLE_METADATA_EXPORT
1005         if (!fbSessionSetMetadataExportElements(
1006                 session, TRUE, YAF_TYPE_METADATA_TID, err))
1007         {
1008             return NULL;
1009         }
1010 
1011         if (!fbSessionSetMetadataExportTemplates(
1012                 session, TRUE, YAF_TEMPLATE_METADATA_TID, err))
1013         {
1014             return NULL;
1015         }
1016 #endif
1017     }
1018 
1019 #if YAF_ENABLE_METADATA_EXPORT
1020     if (!fbSessionAddTemplateWithMetadata(session, FALSE, YAF_FLOW_FULL_TID,
1021                                           tmpl, YAF_FLOW_FULL_NAME, NULL, err))
1022     {
1023         return NULL;
1024     }
1025 #else
1026     /* Add the full record template to the session */
1027     if (!fbSessionAddTemplate(session, FALSE, YAF_FLOW_FULL_TID, tmpl, err)) {
1028         return NULL;
1029     }
1030 
1031 #endif
1032     if (!fbSessionAddTemplate(session, TRUE, YAF_FLOW_FULL_TID, tmpl, err)) {
1033         return NULL;
1034     }
1035 
1036 
1037     /* Create the Options Template */
1038     yaf_tmpl.ipfixStatsTemplate = fbTemplateAlloc(model);
1039     if (!fbTemplateAppendSpecArray(yaf_tmpl.ipfixStatsTemplate,
1040                                    yaf_process_stats_spec, 0, err))
1041     {
1042         return NULL;
1043     }
1044 
1045     /* Scope fields are exporterIPv4Address, observationDomainId,
1046        and exportingProcessID */
1047     fbTemplateSetOptionsScope(yaf_tmpl.ipfixStatsTemplate, 3);
1048 #if YAF_ENABLE_METADATA_EXPORT
1049     if (!fbSessionAddTemplateWithMetadata(session, FALSE, YAF_PROCESS_STATS_TID,
1050                                           yaf_tmpl.ipfixStatsTemplate,
1051                                           YAF_PROCESS_STATS_NAME, NULL, err))
1052     {
1053         return NULL;
1054     }
1055 #else
1056     if (!fbSessionAddTemplate(session, FALSE, YAF_PROCESS_STATS_TID,
1057                               yaf_tmpl.ipfixStatsTemplate, err))
1058     {
1059         return NULL;
1060     }
1061 #endif
1062     if (!fbSessionAddTemplate(session, TRUE, YAF_PROCESS_STATS_TID,
1063                               yaf_tmpl.ipfixStatsTemplate, err))
1064     {
1065         return NULL;
1066     }
1067 
1068     /* Create the Tombstone record Template */
1069     yaf_tmpl.tombstoneRecordTemplate = fbTemplateAlloc(model);
1070     if (!fbTemplateAppendSpecArray(yaf_tmpl.tombstoneRecordTemplate,
1071                                    yaf_tombstone_spec, 0, err))
1072     {
1073         return NULL;
1074     }
1075     /* Scope fields are exportingProcessID, observationDomainId,
1076        and exporterConfiguredId */
1077     fbTemplateSetOptionsScope(yaf_tmpl.tombstoneRecordTemplate, 3);
1078 #if YAF_ENABLE_METADATA_EXPORT
1079     if (!fbSessionAddTemplateWithMetadata(session, FALSE, YAF_TOMBSTONE_TID,
1080                                           yaf_tmpl.tombstoneRecordTemplate,
1081                                           YAF_TOMBSTONE_NAME, NULL, err))
1082     {
1083         return NULL;
1084     }
1085 #else
1086     if (!fbSessionAddTemplate(session, FALSE, YAF_TOMBSTONE_TID,
1087                               yaf_tmpl.tombstoneRecordTemplate, err))
1088     {
1089         return NULL;
1090     }
1091 #endif
1092     if (!fbSessionAddTemplate(session, TRUE, YAF_TOMBSTONE_TID,
1093                               yaf_tmpl.tombstoneRecordTemplate, err))
1094     {
1095         return NULL;
1096     }
1097 
1098     /* Create the Tombstone Access SubTemplate */
1099     yaf_tmpl.tombstoneAccessTemplate = fbTemplateAlloc(model);
1100     if (!fbTemplateAppendSpecArray(yaf_tmpl.tombstoneAccessTemplate,
1101                                    yaf_tombstone_access_spec, 0, err))
1102     {
1103         return NULL;
1104     }
1105 #if YAF_ENABLE_METADATA_EXPORT
1106     if (!fbSessionAddTemplateWithMetadata(session, FALSE, YAF_TOMBSTONE_ACCESS_TID,
1107                                           yaf_tmpl.tombstoneAccessTemplate,
1108                                           YAF_TOMBSTONE_ACCESS_NAME, NULL, err))
1109     {
1110         return NULL;
1111     }
1112 #else
1113     if (!fbSessionAddTemplate(session, FALSE, YAF_TOMBSTONE_ACCESS_TID,
1114                               yaf_tmpl.tombstoneAccessTemplate, err))
1115     {
1116         return NULL;
1117     }
1118 #endif
1119     if (!fbSessionAddTemplate(session, TRUE, YAF_TOMBSTONE_ACCESS_TID,
1120                               yaf_tmpl.tombstoneAccessTemplate, err))
1121     {
1122         return NULL;
1123     }
1124 
1125 
1126     /* Flow Stats Template */
1127     yaf_tmpl.fstatsTemplate = yfAddTemplate(session, yaf_flow_stats_spec,
1128                                             YAF_STATS_FLOW_TID,
1129                                             YAF_STATS_FLOW_NAME, NULL,
1130                                             FALSE, err);
1131     if (!yaf_tmpl.fstatsTemplate) {
1132         return NULL;
1133     }
1134 
1135     yaf_tmpl.revfstatsTemplate = yfAddTemplate(session, yaf_flow_stats_spec,
1136                                                YAF_STATS_FLOW_TID,
1137                                                YAF_STATS_FLOW_REV_NAME, NULL,
1138                                                TRUE, err);
1139     if (!yaf_tmpl.revfstatsTemplate) {
1140         return NULL;
1141     }
1142 
1143 #if YAF_ENABLE_ENTROPY
1144     yaf_tmpl.entropyTemplate = yfAddTemplate(session, yaf_entropy_spec,
1145                                              YAF_ENTROPY_FLOW_TID,
1146                                              YAF_ENTROPY_FLOW_NAME, NULL,
1147                                              FALSE, err);
1148 
1149     if (!yaf_tmpl.entropyTemplate) {
1150         return NULL;
1151     }
1152 
1153     yaf_tmpl.revEntropyTemplate = yfAddTemplate(session, yaf_entropy_spec,
1154                                                 YAF_ENTROPY_FLOW_TID,
1155                                                 YAF_ENTROPY_FLOW_REV_NAME,
1156                                                 NULL, TRUE, err);
1157     if (!yaf_tmpl.revEntropyTemplate) {
1158         return NULL;
1159     }
1160 
1161 #endif
1162 
1163     yaf_tmpl.tcpTemplate = yfAddTemplate(session, yaf_tcp_spec,
1164                                          YAF_TCP_FLOW_TID, YAF_TCP_FLOW_NAME,
1165                                          NULL, FALSE, err);
1166 
1167     if (!yaf_tmpl.tcpTemplate) {
1168         return NULL;
1169     }
1170 
1171     yaf_tmpl.revTcpTemplate = yfAddTemplate(session, yaf_tcp_spec,
1172                                             YAF_TCP_FLOW_TID,
1173                                             YAF_TCP_FLOW_REV_NAME, NULL,
1174                                             TRUE, err);
1175 
1176     if (!yaf_tmpl.revTcpTemplate) {
1177         return NULL;
1178     }
1179 
1180     yaf_tmpl.macTemplate = yfAddTemplate(session, yaf_mac_spec,
1181                                          YAF_MAC_FLOW_TID, YAF_MAC_FLOW_NAME,
1182                                          NULL, FALSE, err);
1183 
1184     if (!yaf_tmpl.macTemplate) {
1185         return NULL;
1186     }
1187 
1188     yaf_tmpl.mptcpTemplate = yfAddTemplate(session, yaf_mptcp_spec,
1189                                            YAF_MPTCP_FLOW_TID,
1190                                            YAF_MPTCP_FLOW_NAME, NULL,
1191                                            FALSE, err);
1192     if (!yaf_tmpl.mptcpTemplate) {
1193         return NULL;
1194     }
1195 
1196 #if YAF_ENABLE_P0F
1197     yaf_tmpl.p0fTemplate = yfAddTemplate(session, yaf_p0f_spec,
1198                                          YAF_P0F_FLOW_TID, YAF_P0F_FLOW_NAME,
1199                                          NULL, FALSE, err);
1200 
1201     if (!yaf_tmpl.p0fTemplate) {
1202         return NULL;
1203     }
1204 
1205     yaf_tmpl.revP0fTemplate = yfAddTemplate(session, yaf_p0f_spec,
1206                                             YAF_P0F_FLOW_TID,
1207                                             YAF_P0F_FLOW_REV_NAME,
1208                                             NULL, TRUE, err);
1209 
1210     if (!yaf_tmpl.revP0fTemplate) {
1211         return NULL;
1212     }
1213 #endif
1214 
1215 #if YAF_ENABLE_FPEXPORT
1216     yaf_tmpl.fpexportTemplate = yfAddTemplate(session, yaf_fpexport_spec,
1217                                               YAF_FPEXPORT_FLOW_TID,
1218                                               YAF_FPEXPORT_FLOW_NAME, NULL,
1219                                               FALSE, err);
1220 
1221     if (!yaf_tmpl.fpexportTemplate) {
1222         return NULL;
1223     }
1224 
1225     yaf_tmpl.revFpexportTemplate = yfAddTemplate(session, yaf_fpexport_spec,
1226                                                  YAF_FPEXPORT_FLOW_TID,
1227                                                  YAF_FPEXPORT_FLOW_REV_NAME,
1228                                                  NULL, TRUE, err);
1229     if (!yaf_tmpl.revFpexportTemplate) {
1230         return NULL;
1231     }
1232 #endif
1233 
1234 #if YAF_ENABLE_PAYLOAD
1235     yaf_tmpl.payloadTemplate = yfAddTemplate(session, yaf_payload_spec,
1236                                              YAF_PAYLOAD_FLOW_TID,
1237                                              YAF_PAYLOAD_FLOW_NAME, NULL,
1238                                              FALSE, err);
1239 
1240     if (!yaf_tmpl.payloadTemplate) {
1241         return NULL;
1242     }
1243 
1244     yaf_tmpl.revPayloadTemplate = yfAddTemplate(session, yaf_payload_spec,
1245                                                 YAF_PAYLOAD_FLOW_TID,
1246                                                 YAF_PAYLOAD_FLOW_REV_NAME,
1247                                                 NULL, TRUE, err);
1248 
1249     if (!yaf_tmpl.revPayloadTemplate) {
1250         return NULL;
1251     }
1252 #endif
1253 
1254 #if YAF_ENABLE_HOOKS
1255     /*  Add the hook template fields if available  */
1256 
1257     if (!yfHookGetTemplate(session)) {
1258         g_debug("Hook Templates could not be added to the session");
1259     }
1260 
1261 #endif
1262 
1263     /* Done. Return the session. */
1264     return session;
1265 }
1266 
1267 
1268 #ifdef HAVE_SPREAD
1269 /**
1270  * yfAddTemplateSpread
1271  *
1272  *
1273  */
yfAddTemplateSpread(fbSession_t * session,fbInfoElementSpec_t * spec,char ** groups,uint16_t tid,const gchar * name,const gchar * description,gboolean reverse,GError ** err)1274 static fbTemplate_t *yfAddTemplateSpread(
1275     fbSession_t           *session,
1276     fbInfoElementSpec_t   *spec,
1277     char                  **groups,
1278     uint16_t              tid,
1279     const gchar           *name,
1280     const gchar           *description,
1281     gboolean              reverse,
1282     GError                **err)
1283 {
1284     fbInfoModel_t   *model = yfInfoModel();
1285     fbTemplate_t    *tmpl = fbTemplateAlloc(model);
1286     uint32_t        flags = 0;
1287     uint16_t        rtid = tid;
1288 
1289     if (reverse) {
1290         flags = 0xffffffff;
1291         rtid = tid | YTF_BIF;
1292     }
1293 
1294     g_debug("yaf spread: %x (%s), %d (%x)", tid, name, reverse, tid | (reverse ? YTF_BIF : 0));
1295     if (!fbTemplateAppendSpecArray(tmpl, spec, flags, err))
1296     {
1297         return NULL;
1298     }
1299 
1300 #if YAF_ENABLE_METADATA_EXPORT
1301     if (!fbSessionAddTemplatesMulticastWithMetadata(session, groups, FALSE, rtid,
1302                                                     tmpl, name, description, err))
1303     {
1304         return NULL;
1305     }
1306 #else
1307     if (!fbSessionAddTemplatesMulticast(session, groups, FALSE,
1308                                         rtid, tmpl, err))
1309     {
1310         return NULL;
1311     }
1312 #endif
1313 
1314     if (reverse) {
1315 
1316         if (!fbSessionAddTemplate(session, TRUE, tid, tmpl, err))
1317         {
1318             return NULL;
1319         }
1320 
1321     }
1322 
1323     return tmpl;
1324 }
1325 
1326 
1327 
1328 
1329 /**
1330  * yfInitExporterSpreadSession
1331  *
1332  *
1333  */
yfInitExporterSpreadSession(fBuf_t * fbuf,fbSession_t * session,fbSpreadParams_t * spread,uint32_t domain,uint16_t * spreadIndex,gboolean export_meta,GError ** err)1334 static fbSession_t *yfInitExporterSpreadSession(
1335     fBuf_t      *fbuf,
1336     fbSession_t *session,
1337     fbSpreadParams_t *spread,
1338     uint32_t domain,
1339     uint16_t *spreadIndex,
1340     gboolean export_meta,
1341     GError **err)
1342 {
1343 
1344     fbInfoModel_t  *model = yfInfoModel();
1345     fbTemplate_t   *tmpl = NULL;
1346 #if YAF_ENABLE_HOOKS
1347     int             n = 0;
1348 #endif
1349 
1350     if (export_meta) {
1351 #if YAF_ENABLE_METADATA_EXPORT
1352         if (!fbSessionSpreadSetMetadataExportElements(
1353                 session, spread->groups, TRUE, YAF_TYPE_METADATA_TID, err))
1354         {
1355             return NULL;
1356         }
1357 
1358         if (!fbSessionSpreadSetMetadataExportTemplates(
1359                 session, spread->groups, TRUE, YAF_TEMPLATE_METADATA_TID, err))
1360         {
1361             return NULL;
1362         }
1363 #endif
1364     }
1365 
1366     /*Create the full record template */
1367     tmpl = fbTemplateAlloc(model);
1368 
1369     if (!fbTemplateAppendSpecArray(tmpl, yaf_flow_spec, YTF_ALL, err))
1370         return NULL;
1371     /* Add the full record template to the session */
1372     if (!fbSessionAddTemplate(session, TRUE, YAF_FLOW_FULL_TID, tmpl, err)) {
1373         return NULL;
1374     }
1375 #if YAF_ENABLE_METADATA_EXPORT
1376     if (!fbSessionAddTemplatesMulticastWithMetadata(
1377             session, spread->groups, FALSE, YAF_FLOW_FULL_TID, tmpl,
1378             YAF_FLOW_FULL_NAME, NULL, err))
1379     {
1380         return NULL;
1381     }
1382 #else
1383     if (!fbSessionAddTemplatesMulticast(
1384             session, spread->groups, FALSE, YAF_FLOW_FULL_TID, tmpl, err))
1385     {
1386         return NULL;
1387     }
1388 #endif
1389 
1390     /* Create the Options Template */
1391     yaf_tmpl.ipfixStatsTemplate = fbTemplateAlloc(model);
1392     if (!fbTemplateAppendSpecArray(yaf_tmpl.ipfixStatsTemplate,
1393                                    yaf_process_stats_spec, 0, err))
1394     {
1395         return NULL;
1396     }
1397 
1398     /* Scope fields are exporterIPv4Address, observationDomainId,
1399        and exportingProcessID */
1400     fbTemplateSetOptionsScope(yaf_tmpl.ipfixStatsTemplate, 3);
1401     if (!fbSessionAddTemplate(session, TRUE, YAF_PROCESS_STATS_TID,
1402                               yaf_tmpl.ipfixStatsTemplate, err))
1403     {
1404         return NULL;
1405     }
1406 
1407 #if YAF_ENABLE_METADATA_EXPORT
1408     if (!fbSessionAddTemplatesMulticastWithMetadata(session, spread->groups, FALSE,
1409                                         YAF_PROCESS_STATS_TID,
1410                                         yaf_tmpl.ipfixStatsTemplate,
1411                                         YAF_PROCESS_STATS_NAME, NULL, err))
1412     {
1413         return NULL;
1414     }
1415 #else
1416     if (!fbSessionAddTemplatesMulticast(session, spread->groups, FALSE,
1417                                         YAF_PROCESS_STATS_TID,
1418                                         yaf_tmpl.ipfixStatsTemplate, err))
1419     {
1420         return NULL;
1421     }
1422 #endif
1423 
1424     /* Create the Tombstone Record Template */
1425     yaf_tmpl.tombstoneRecordTemplate = fbTemplateAlloc(model);
1426     if (!fbTemplateAppendSpecArray(yaf_tmpl.tombstoneRecordTemplate,
1427                                    yaf_tombstone_spec, 0, err))
1428     {
1429         return NULL;
1430     }
1431 
1432     /* Scope fields are exportingProcessID, observationDomainId,
1433        and exporterConfiguredId */
1434     fbTemplateSetOptionsScope(yaf_tmpl.tombstoneRecordTemplate, 3);
1435     if (!fbSessionAddTemplate(session, TRUE, YAF_TOMBSTONE_TID,
1436                               yaf_tmpl.tombstoneRecordTemplate, err))
1437     {
1438         return NULL;
1439     }
1440 
1441 #if YAF_ENABLE_METADATA_EXPORT
1442     if (!fbSessionAddTemplatesMulticastWithMetadata(session, spread->groups, FALSE,
1443                                         YAF_TOMBSTONE_TID,
1444                                         yaf_tmpl.tombstoneRecordTemplate,
1445                                         YAF_TOMBSTONE_NAME, NULL, err))
1446     {
1447         return NULL;
1448     }
1449 #else
1450     if (!fbSessionAddTemplatesMulticast(session, spread->groups, FALSE,
1451                                         YAF_TOMBSTONE_TID,
1452                                         yaf_tmpl.tombstoneRecordTemplate, err))
1453     {
1454         return NULL;
1455     }
1456 #endif
1457 
1458 
1459     /* Create the Tombstone Access SubTemplate */
1460     yaf_tmpl.tombstoneAccessTemplate = fbTemplateAlloc(model);
1461     if (!fbTemplateAppendSpecArray(yaf_tmpl.tombstoneAccessTemplate,
1462                                    yaf_tombstone_access_spec, 0, err))
1463     {
1464         return NULL;
1465     }
1466     if (!fbSessionAddTemplate(session, TRUE, YAF_TOMBSTONE_ACCESS_TID,
1467                               yaf_tmpl.tombstoneAccessTemplate, err))
1468     {
1469         return NULL;
1470     }
1471 #if YAF_ENABLE_METADATA_EXPORT
1472     if (!fbSessionAddTemplatesMulticastWithMetadata(session, spread->groups, FALSE,
1473                                         YAF_TOMBSTONE_ACCESS_TID,
1474                                         yaf_tmpl.tombstoneAccessTemplate,
1475                                         YAF_TOMBSTONE_ACCESS_NAME, NULL, err))
1476     {
1477         return NULL;
1478     }
1479 #else
1480     if (!fbSessionAddTemplatesMulticast(session, spread->groups, FALSE,
1481                                         YAF_TOMBSTONE_ACCESS_TID,
1482                                         yaf_tmpl.tombstoneAccessTemplate, err))
1483     {
1484         return NULL;
1485     }
1486 #endif
1487 
1488 
1489 
1490 
1491     /* Flow Stats Template */
1492     yaf_tmpl.fstatsTemplate = yfAddTemplateSpread(session, yaf_flow_stats_spec,
1493                                                   spread->groups,
1494                                                   YAF_STATS_FLOW_TID,
1495                                                   YAF_STATS_FLOW_NAME, NULL,
1496                                                   FALSE, err);
1497     if (!yaf_tmpl.fstatsTemplate) {
1498         return NULL;
1499     }
1500 
1501     yaf_tmpl.revfstatsTemplate = yfAddTemplateSpread(session, yaf_flow_stats_spec,
1502                                                      spread->groups,
1503                                                      YAF_STATS_FLOW_TID,
1504                                                      YAF_STATS_FLOW_REV_NAME, NULL,
1505                                                      TRUE, err);
1506     if (!yaf_tmpl.revfstatsTemplate) {
1507         return NULL;
1508     }
1509 
1510 #if YAF_ENABLE_ENTROPY
1511     yaf_tmpl.entropyTemplate = yfAddTemplateSpread(session, yaf_entropy_spec,
1512                                                    spread->groups,
1513                                                    YAF_ENTROPY_FLOW_TID,
1514                                                    YAF_ENTROPY_FLOW_NAME, NULL,
1515                                                    FALSE, err);
1516 
1517     if (!yaf_tmpl.entropyTemplate) {
1518         return NULL;
1519     }
1520 
1521     yaf_tmpl.revEntropyTemplate = yfAddTemplateSpread(session, yaf_entropy_spec,
1522                                                       spread->groups,
1523                                                       YAF_ENTROPY_FLOW_TID,
1524                                                       YAF_ENTROPY_FLOW_REV_NAME,
1525                                                       NULL, TRUE, err);
1526     if (!yaf_tmpl.revEntropyTemplate) {
1527         return NULL;
1528     }
1529 
1530 #endif
1531 
1532     yaf_tmpl.tcpTemplate = yfAddTemplateSpread(session, yaf_tcp_spec,
1533                                                spread->groups,
1534                                                YAF_TCP_FLOW_TID, YAF_TCP_FLOW_NAME,
1535                                                NULL, FALSE, err);
1536 
1537     if (!yaf_tmpl.tcpTemplate) {
1538         return NULL;
1539     }
1540 
1541     yaf_tmpl.revTcpTemplate = yfAddTemplateSpread(session, yaf_tcp_spec,
1542                                                   spread->groups,
1543                                                   YAF_TCP_FLOW_TID,
1544                                                   YAF_TCP_FLOW_REV_NAME, NULL,
1545                                                   TRUE, err);
1546 
1547     if (!yaf_tmpl.revTcpTemplate) {
1548         return NULL;
1549     }
1550 
1551     yaf_tmpl.macTemplate = yfAddTemplateSpread(session, yaf_mac_spec,
1552                                                spread->groups,
1553                                                YAF_MAC_FLOW_TID, YAF_MAC_FLOW_NAME,
1554                                                NULL, FALSE, err);
1555 
1556     if (!yaf_tmpl.macTemplate) {
1557         return NULL;
1558     }
1559 
1560     yaf_tmpl.mptcpTemplate = yfAddTemplateSpread(session, yaf_mptcp_spec,
1561                                                  spread->groups,
1562                                                  YAF_MPTCP_FLOW_TID,
1563                                                  YAF_MPTCP_FLOW_NAME, NULL,
1564                                                  FALSE, err);
1565     if (!yaf_tmpl.mptcpTemplate) {
1566         return NULL;
1567     }
1568 
1569 #if YAF_ENABLE_P0F
1570     yaf_tmpl.p0fTemplate = yfAddTemplateSpread(session, yaf_p0f_spec,
1571                                                spread->groups,
1572                                                YAF_P0F_FLOW_TID, YAF_P0F_FLOW_NAME,
1573                                                NULL, FALSE, err);
1574 
1575     if (!yaf_tmpl.p0fTemplate) {
1576         return NULL;
1577     }
1578 
1579     yaf_tmpl.revP0fTemplate = yfAddTemplateSpread(session, yaf_p0f_spec,
1580                                                   spread->groups,
1581                                                   YAF_P0F_FLOW_TID,
1582                                                   YAF_P0F_FLOW_REV_NAME,
1583                                                   NULL, TRUE, err);
1584 
1585     if (!yaf_tmpl.revP0fTemplate) {
1586         return NULL;
1587     }
1588 #endif
1589 
1590 #if YAF_ENABLE_FPEXPORT
1591     yaf_tmpl.fpexportTemplate = yfAddTemplateSpread(session, yaf_fpexport_spec,
1592                                                     spread->groups,
1593                                                     YAF_FPEXPORT_FLOW_TID,
1594                                                     YAF_FPEXPORT_FLOW_NAME, NULL,
1595                                                     FALSE, err);
1596 
1597     if (!yaf_tmpl.fpexportTemplate) {
1598         return NULL;
1599     }
1600 
1601     yaf_tmpl.revFpexportTemplate = yfAddTemplateSpread(session, yaf_fpexport_spec,
1602                                                        spread->groups,
1603                                                        YAF_FPEXPORT_FLOW_TID,
1604                                                        YAF_FPEXPORT_FLOW_REV_NAME,
1605                                                        NULL, TRUE, err);
1606     if (!yaf_tmpl.revFpexportTemplate) {
1607         return NULL;
1608     }
1609 #endif
1610 
1611 #if YAF_ENABLE_PAYLOAD
1612     yaf_tmpl.payloadTemplate = yfAddTemplateSpread(session, yaf_payload_spec,
1613                                                    spread->groups,
1614                                                    YAF_PAYLOAD_FLOW_TID,
1615                                                    YAF_PAYLOAD_FLOW_NAME, NULL,
1616                                                    FALSE, err);
1617 
1618     if (!yaf_tmpl.payloadTemplate) {
1619         return NULL;
1620     }
1621 
1622     yaf_tmpl.revPayloadTemplate = yfAddTemplateSpread(session, yaf_payload_spec,
1623                                                       spread->groups,
1624                                                       YAF_PAYLOAD_FLOW_TID,
1625                                                       YAF_PAYLOAD_FLOW_REV_NAME,
1626                                                       NULL, TRUE, err);
1627 
1628     if (!yaf_tmpl.revPayloadTemplate) {
1629         return NULL;
1630     }
1631 #endif
1632 
1633 #if YAF_ENABLE_HOOKS
1634     /*  Add the hook template fields if available  */
1635     while (spread->groups[n]) {
1636         fBufSetSpreadExportGroup(fbuf, &(spread->groups[n]), 1, err);
1637         if (!yfHookGetTemplate(session)) {
1638             g_warning("Hook Templates could not be added to the session");
1639             return NULL;
1640         }
1641         n++;
1642     }
1643 #endif
1644     /* Done. Return the session. */
1645     return session;
1646 }
1647 
1648 /**
1649  * yfSpreadGroupby
1650  *
1651  *
1652  */
yfSpreadGroupby(uint8_t spreadGroupByType,uint16_t silkAppLabel,uint16_t vlanId,uint16_t destinationTransportPort,uint8_t protocolIdentifier,uint8_t ipVersion)1653 static uint16_t yfSpreadGroupby(
1654     uint8_t spreadGroupByType,
1655     uint16_t silkAppLabel,
1656     uint16_t vlanId,
1657     uint16_t destinationTransportPort,
1658     uint8_t protocolIdentifier,
1659     uint8_t  ipVersion)
1660 {
1661     switch (spreadGroupByType) {
1662     case 1:
1663         return destinationTransportPort;
1664     case 2:
1665         return vlanId;
1666     case 3:
1667         return silkAppLabel;
1668     case 4:
1669         return (uint16_t)protocolIdentifier;
1670     case 5:
1671         return (uint16_t)ipVersion;
1672     default:
1673         return 0;
1674     }
1675 }
1676 
1677 
1678 /**
1679  * yfWriterForSpread
1680  *
1681  *
1682  *
1683  */
yfWriterForSpread(fbSpreadParams_t * spread,uint32_t domain,uint16_t * spreadGroupIndex,gboolean export_metadata,GError ** err)1684 fBuf_t *yfWriterForSpread(
1685      fbSpreadParams_t *spread,
1686      uint32_t domain,
1687      uint16_t *spreadGroupIndex,
1688      gboolean export_metadata,
1689      GError **err)
1690 {
1691      fBuf_t            *fbuf = NULL;
1692      fbSession_t       *session ;
1693      fbExporter_t      *exporter;
1694      fbInfoModel_t *model = yfInfoModel();
1695 
1696      session = fbSessionAlloc(model);
1697 
1698      spread->session = session;
1699 
1700      fbSessionSetDomain(session, domain);
1701 
1702      exporter = fbExporterAllocSpread(spread);
1703 
1704      fbuf = fBufAllocForExport(session, exporter);
1705 
1706      /* If we are using spread group by - we need to multicast templates */
1707      if (spreadGroupIndex) {
1708          if (!(session = yfInitExporterSpreadSession(fbuf, session, spread,
1709                                                      domain, spreadGroupIndex,
1710                                                      export_metadata,
1711                                                      err)))
1712          {
1713              goto err;
1714          }
1715      } else {
1716          /* initialize session and exporter */
1717          if (!(session = yfInitExporterSession(domain, export_metadata, err)))
1718          {
1719              goto err;
1720          }
1721      }
1722 
1723      /* set observation domain */
1724      fbSessionSetDomain(session, domain);
1725 
1726      /* write YAF flow templates */
1727 
1728      if (!fbSessionExportTemplates(session, err)) goto err;
1729      /* set internal template */
1730      if (!fBufSetInternalTemplate(fbuf, YAF_FLOW_FULL_TID, err)) {
1731          goto err;
1732      }
1733 
1734      /* all done */
1735      return fbuf;
1736 
1737    err:
1738      if (fbuf) fBufFree(fbuf);
1739 
1740      return NULL;
1741 
1742 }
1743 
1744 /**
1745  *yfSetSpreadExportTemplate
1746  *
1747  *
1748  *
1749  */
yfSetSpreadExportTemplate(fBuf_t * fbuf,fbSpreadParams_t * spread,uint16_t tid,char ** groups,int num_groups,GError ** err)1750 static gboolean yfSetSpreadExportTemplate(
1751     fBuf_t              *fbuf,
1752     fbSpreadParams_t    *spread,
1753     uint16_t            tid,
1754     char                **groups,
1755     int                 num_groups,
1756     GError              **err)
1757 {
1758     fbSession_t         *session = NULL;
1759     fbTemplate_t        *tmpl = NULL;
1760 
1761     /* Try to set export template */
1762 
1763     if (fBufSetExportTemplate(fbuf, tid, err)) {
1764         return TRUE;
1765     }
1766 
1767     /* Check for error other than missing template */
1768     if (!g_error_matches(*err, FB_ERROR_DOMAIN, FB_ERROR_TMPL)) {
1769         return FALSE;
1770     }
1771 
1772     /* Okay. We have a missing template. Clear the error and try to load it. */
1773     g_clear_error(err);
1774     session = fBufGetSession(fbuf);
1775     tmpl = fbTemplateAlloc(yfInfoModel());
1776 
1777     if (!fbTemplateAppendSpecArray(tmpl, yaf_flow_spec,
1778                                    (tid & (~YAF_FLOW_BASE_TID)), err))
1779     {
1780         return FALSE;
1781     }
1782     /* Multicast templates to all groups */
1783     if (!(fbSessionAddTemplatesMulticast(session, spread->groups, FALSE,
1784                                          tid, tmpl, err)))
1785     {
1786         return FALSE;
1787     }
1788 
1789     /* Now reset groups on the buffer */
1790     fBufSetSpreadExportGroup(fbuf, groups, num_groups, err);
1791     /* Template should be loaded. Try setting the template again. */
1792     return fBufSetExportTemplate(fbuf, tid, err);
1793 }
1794 
1795 
1796 #endif /* HAVE SPREAD */
1797 
1798 
1799 
1800 /**
1801  *yfSetExportTemplate
1802  *
1803  *
1804  *
1805  */
1806 
1807 #define TEMPLATE_NAME_INIT_LEN 32
1808 
yfSetExportTemplate(fBuf_t * fbuf,uint16_t tid,GError ** err)1809 static gboolean yfSetExportTemplate(
1810     fBuf_t              *fbuf,
1811     uint16_t            tid,
1812     GError              **err)
1813 {
1814     fbSession_t         *session = NULL;
1815     fbTemplate_t        *tmpl = NULL;
1816     GString             *template_name = NULL;
1817 
1818     /* Try to set export template */
1819     if (fBufSetExportTemplate(fbuf, tid, err)) {
1820         return TRUE;
1821     }
1822 
1823     /* Check for error other than missing template */
1824     if (!g_error_matches(*err, FB_ERROR_DOMAIN, FB_ERROR_TMPL)) {
1825         return FALSE;
1826     }
1827 
1828     /* Okay. We have a missing template. Clear the error and try to load it. */
1829     g_clear_error(err);
1830 
1831     template_name = g_string_sized_new(TEMPLATE_NAME_INIT_LEN);
1832 
1833     session = fBufGetSession(fbuf);
1834     tmpl = fbTemplateAlloc(yfInfoModel());
1835 
1836 
1837     if ( (tid & YAF_FLOW_BASE_TID) == YAF_FLOW_BASE_TID )
1838     {
1839         g_string_append_printf(template_name, "yaf_flow");
1840 
1841         if ( tid & YTF_DELTA ) {
1842             g_string_append_printf(template_name, "_%s", YTF_DELTA_NAME);
1843         } else {
1844             g_string_append_printf(template_name, "_%s", YTF_TOTAL_NAME);
1845         }
1846 
1847         if (tid & YTF_BIF) {
1848             g_string_append_printf(template_name, "_%s", YTF_BIF_NAME);
1849         }
1850 
1851         if (tid & YTF_SILK) {
1852             g_string_append_printf(template_name, "_%s", YTF_SILK_NAME);
1853         }
1854 
1855         if (tid & YTF_MPLS) {
1856             g_string_append_printf(template_name, "_%s", YTF_MPLS_NAME);
1857         }
1858 
1859         if (tid & YTF_RLE) {
1860             g_string_append_printf(template_name, "_%s", YTF_RLE_NAME);
1861         } else {
1862             g_string_append_printf(template_name, "_%s", YTF_FLE_NAME);
1863         }
1864 
1865         if (tid & YTF_IP6) {
1866             g_string_append_printf(template_name, "_%s", YTF_IP6_NAME);
1867         } else {
1868             g_string_append_printf(template_name, "_%s", YTF_IP4_NAME);
1869         }
1870 
1871         if (tid & YTF_DAGIF) {
1872             g_string_append_printf(template_name, "_%s", YTF_DAGIF_NAME);
1873         }
1874 
1875     }
1876 
1877     if (!fbTemplateAppendSpecArray(tmpl, yaf_flow_spec,
1878                                    (tid & (~YAF_FLOW_BASE_TID)), err))    {
1879         return FALSE;
1880     }
1881 
1882     /*  printf("yfSetExportTemplate: %x, %s\n", tid, template_name->str); */
1883 #if YAF_ENABLE_METADATA_EXPORT
1884     if (!fbSessionAddTemplateWithMetadata(session, FALSE, tid, tmpl,
1885                                           template_name->str, NULL, err))
1886     {
1887         g_error("error setting template metadata: tid: %x, name: %s\n",
1888                 tid, template_name->str);
1889         g_string_free(template_name, TRUE);
1890         return FALSE;
1891     }
1892 #else
1893     if (!fbSessionAddTemplate(session, FALSE, tid, tmpl, err)) {
1894         g_string_free(template_name, TRUE);
1895         return FALSE;
1896     }
1897 #endif
1898 
1899     /*g_debug("adding new template %02x", tid);*/
1900     g_string_free(template_name, TRUE);
1901 
1902     /* Template should be loaded. Try setting the template again. */
1903     return fBufSetExportTemplate(fbuf, tid, err);
1904 }
1905 
1906 /**
1907  *yfWriterForFile
1908  *
1909  *
1910  */
yfWriterForFile(const char * path,uint32_t domain,gboolean export_meta,GError ** err)1911 fBuf_t *yfWriterForFile(
1912     const char              *path,
1913     uint32_t                domain,
1914     gboolean                export_meta,
1915     GError                  **err)
1916 {
1917     fBuf_t                  *fbuf = NULL;
1918     fbExporter_t            *exporter;
1919     fbSession_t             *session;
1920 
1921     /* Allocate an exporter for the file */
1922     exporter = fbExporterAllocFile(path);
1923 
1924     /* Create a new buffer */
1925     if (!(session = yfInitExporterSession(domain, export_meta, err))) goto err;
1926 
1927     fbuf = fBufAllocForExport(session, exporter);
1928 
1929     /* write YAF flow templates */
1930     if (!fbSessionExportTemplates(session, err)) goto err;
1931 
1932     /* set internal template */
1933     if (!fBufSetInternalTemplate(fbuf, YAF_FLOW_FULL_TID, err)) goto err;
1934 
1935     /* all done */
1936     return fbuf;
1937 
1938   err:
1939     /* free buffer if necessary */
1940     if (fbuf) fBufFree(fbuf);
1941     return NULL;
1942 }
1943 
1944 
1945 /**
1946  *yfWriterForFP
1947  *
1948  *
1949  *
1950  */
yfWriterForFP(FILE * fp,uint32_t domain,gboolean export_meta,GError ** err)1951 fBuf_t *yfWriterForFP(
1952     FILE                    *fp,
1953     uint32_t                domain,
1954     gboolean                export_meta,
1955     GError                  **err)
1956 {
1957     fBuf_t                  *fbuf = NULL;
1958     fbExporter_t            *exporter;
1959     fbSession_t             *session;
1960 
1961     /* Allocate an exporter for the file */
1962     exporter = fbExporterAllocFP(fp);
1963     /* Create a new buffer */
1964     if (!(session = yfInitExporterSession(domain, export_meta, err))) goto err;
1965 
1966     fbuf = fBufAllocForExport(session, exporter);
1967 
1968     /* write YAF flow templates */
1969 
1970     if (!fbSessionExportTemplates(session, err)) goto err;
1971 
1972     /* set internal template */
1973     if (!fBufSetInternalTemplate(fbuf, YAF_FLOW_FULL_TID, err)) goto err;
1974 
1975     /* all done */
1976     return fbuf;
1977 
1978   err:
1979     /* free buffer if necessary */
1980     if (fbuf) fBufFree(fbuf);
1981     return NULL;
1982 }
1983 
1984 
1985 /**
1986  *yfWriterForSpec
1987  *
1988  *
1989  *
1990  */
yfWriterForSpec(fbConnSpec_t * spec,uint32_t domain,gboolean export_meta,GError ** err)1991 fBuf_t *yfWriterForSpec(
1992     fbConnSpec_t            *spec,
1993     uint32_t                domain,
1994     gboolean                export_meta,
1995     GError                  **err)
1996 {
1997     fBuf_t                  *fbuf = NULL;
1998     fbSession_t             *session;
1999     fbExporter_t            *exporter;
2000 
2001     /* initialize session and exporter */
2002     if (!(session = yfInitExporterSession(domain, export_meta, err))) goto err;
2003 
2004     exporter = fbExporterAllocNet(spec);
2005     fbuf = fBufAllocForExport(session, exporter);
2006 
2007     /* set observation domain */
2008     fbSessionSetDomain(session, domain);
2009 
2010     /* write YAF flow templates */
2011     if (!fbSessionExportTemplates(session, err)) goto err;
2012 
2013     /* set internal template */
2014     if (!fBufSetInternalTemplate(fbuf, YAF_FLOW_FULL_TID, err)) goto err;
2015 
2016     /* all done */
2017     return fbuf;
2018 
2019   err:
2020     /* free buffer if necessary */
2021     if (fbuf) fBufFree(fbuf);
2022     return NULL;
2023 }
2024 
2025 /**
2026  *yfWriteOptionsDataFlows
2027  *
2028  *
2029  */
yfWriteOptionsDataFlows(void * yfContext,uint32_t pcap_drop,GTimer * timer,GError ** err)2030 gboolean yfWriteOptionsDataFlows(
2031     void               *yfContext,
2032     uint32_t           pcap_drop,
2033     GTimer             *timer,
2034     GError             **err)
2035 {
2036     yfContext_t         *ctx = (yfContext_t *)yfContext;
2037 
2038     if(!yfWriteStatsFlow(yfContext, pcap_drop, timer, err)){
2039         return FALSE;
2040     }
2041     if(!ctx->cfg->no_tombstone){
2042         if(!yfWriteTombstoneFlow(yfContext, err)){
2043             return FALSE;
2044         }
2045     }
2046     return TRUE;
2047 }
2048 
2049 /**
2050  *yfWriteStatsFlow
2051  *
2052  *
2053  */
yfWriteStatsFlow(void * yfContext,uint32_t pcap_drop,GTimer * timer,GError ** err)2054 gboolean yfWriteStatsFlow(
2055     void               *yfContext,
2056     uint32_t           pcap_drop,
2057     GTimer             *timer,
2058     GError             **err)
2059 {
2060     yfIpfixStats_t      rec;
2061     yfContext_t         *ctx = (yfContext_t *)yfContext;
2062     fBuf_t              *fbuf = ctx->fbuf;
2063     uint32_t            mask = 0x000000FF;
2064     char                buf[200];
2065     uint32_t            total_frags = 0;
2066     static struct hostent *host;
2067     static uint32_t     host_ip = 0;
2068 
2069 #if HAVE_SPREAD
2070     fbSpreadParams_t    *spParam = &(ctx->cfg->spreadparams);
2071 #endif
2072 
2073     yfGetFlowTabStats(ctx->flowtab, &(rec.packetTotalCount),
2074                       &(rec.exportedFlowTotalCount),
2075                       &(rec.notSentPacketTotalCount),
2076                       &(rec.flowTablePeakCount), &(rec.flowTableFlushEvents));
2077     if (ctx->fragtab) {
2078         yfGetFragTabStats(ctx->fragtab, &(rec.expiredFragmentCount),
2079                           &(rec.assembledFragmentCount), &total_frags);
2080     } else {
2081         rec.expiredFragmentCount = 0;
2082         rec.assembledFragmentCount = 0;
2083     }
2084 
2085     if (!fbuf) {
2086         g_set_error(err, YAF_ERROR_DOMAIN, YAF_ERROR_IO,
2087                     "Error Writing Stats Message: No fbuf [output] Available");
2088         return FALSE;
2089     }
2090 
2091     /* Get IP of sensor for scope */
2092     if (!host) {
2093         gethostname(buf, 200);
2094         host = (struct hostent *)gethostbyname(buf);
2095         if (host) {
2096             host_ip = (host->h_addr[0] & mask)  << 24;
2097             host_ip |= (host->h_addr[1] & mask) << 16;
2098             host_ip |= (host->h_addr[2] & mask) << 8;
2099             host_ip |= (host->h_addr[3] & mask);
2100         }
2101     }
2102 
2103     /* Rejected/Ignored Packet Total Count from decode.c */
2104     rec.ignoredPacketTotalCount = yfGetDecodeStats(ctx->dectx);
2105 
2106     /* Dropped packets - from yafcap.c & libpcap */
2107     rec.droppedPacketTotalCount = pcap_drop;
2108     rec.exporterIPv4Address = host_ip;
2109 
2110     rec.observationDomainId = ctx->cfg->odid;
2111     rec.exportingProcessId = getpid();
2112     rec.observationTimeSeconds = (int)time(NULL);
2113 
2114     rec.meanFlowRate = rec.exportedFlowTotalCount/g_timer_elapsed(timer, NULL);
2115     rec.meanPacketRate = rec.packetTotalCount / g_timer_elapsed(timer, NULL);
2116 
2117     rec.systemInitTimeMilliseconds = ctx->yaf_start_time;
2118 
2119     g_debug("YAF statistics: Flows: %llu Packets: %llu Dropped: %lu Ignored: %lu "
2120             "Out of Sequence: %"PRIu64" Expired Frags: %u Assembled Frags: %u",
2121             (long long unsigned int)rec.exportedFlowTotalCount,
2122             (long long unsigned int)rec.packetTotalCount,
2123             rec.droppedPacketTotalCount, rec.ignoredPacketTotalCount,
2124             rec.notSentPacketTotalCount, rec.expiredFragmentCount,
2125             rec.assembledFragmentCount);
2126 
2127     /* Set Internal Template for Buffer to Options TID */
2128     if (!fBufSetInternalTemplate(fbuf, YAF_PROCESS_STATS_TID, err))
2129         return FALSE;
2130 
2131 #if HAVE_SPREAD
2132     if (ctx->cfg->spreadGroupIndex) {
2133         fBufSetSpreadExportGroup(fbuf, spParam->groups,
2134                                  ctx->cfg->numSpreadGroups, err);
2135     }
2136 #endif
2137 
2138     /* Set Export Template for Buffer to Options TMPL */
2139     if (!yfSetExportTemplate(fbuf, YAF_PROCESS_STATS_TID, err)) {
2140         return FALSE;
2141     }
2142 
2143     /* Append Record */
2144     if (!fBufAppend(fbuf, (uint8_t *)&rec, sizeof(rec), err)) {
2145         return FALSE;
2146     }
2147 
2148     /* emit buffer */
2149     if (!fBufEmit(fbuf, err)) {
2150         return FALSE;
2151     }
2152 
2153     /* Set Internal TID Back to Flow Record */
2154     if (!fBufSetInternalTemplate(fbuf, YAF_FLOW_FULL_TID, err)) {
2155         return FALSE;
2156     }
2157 
2158     return TRUE;
2159 }
2160 
2161 /**
2162  *yfWriteTombstoneFlow
2163  *
2164  *
2165  */
yfWriteTombstoneFlow(void * yfContext,GError ** err)2166 gboolean yfWriteTombstoneFlow(
2167     void               *yfContext,
2168     GError             **err)
2169 {
2170     yfTombstoneRecord_t     rec;
2171     yfContext_t             *ctx = (yfContext_t *)yfContext;
2172     fBuf_t                  *fbuf = ctx->fbuf;
2173     static uint32_t         tombstoneId = 0;
2174     uint32_t                currentTime;
2175     yfTombstoneAccess_t     *accessListPtr;
2176 
2177 
2178 #if HAVE_SPREAD
2179     fbSpreadParams_t    *spParam = &(ctx->cfg->spreadparams);
2180 #endif
2181 
2182     if (!fbuf) {
2183         g_set_error(err, YAF_ERROR_DOMAIN, YAF_ERROR_IO,
2184                     "Error Writing Stats Message: No fbuf [output] Available");
2185         return FALSE;
2186     }
2187 
2188     /* Set Internal Template for Buffer to Options TID */
2189     if (!fBufSetInternalTemplate(fbuf, YAF_TOMBSTONE_TID, err))
2190         return FALSE;
2191 
2192 #if HAVE_SPREAD
2193     if (ctx->cfg->spreadGroupIndex) {
2194         fBufSetSpreadExportGroup(fbuf, spParam->groups,
2195                                  ctx->cfg->numSpreadGroups, err);
2196     }
2197 #endif
2198 
2199     /* Set Export Template for Buffer to Options TMPL */
2200     if (!yfSetExportTemplate(fbuf, YAF_TOMBSTONE_TID, err)) {
2201         return FALSE;
2202     }
2203 
2204     memset(rec.paddingOctets, 0, sizeof(rec.paddingOctets));
2205     currentTime = (uint32_t)time(NULL);
2206     rec.tombstoneId = tombstoneId++;
2207     rec.exporterConfiguredId = ctx->cfg->tombstone_configured_id;
2208     rec.exportingProcessId = getpid();
2209     rec.observationTimeSeconds = currentTime;
2210     rec.observationDomainId = ctx->cfg->odid;
2211     accessListPtr = (yfTombstoneAccess_t *)fbSubTemplateListInit(
2212                                     &(rec.accessList), 0,
2213                                     YAF_TOMBSTONE_ACCESS_TID,
2214                                     yaf_tmpl.tombstoneAccessTemplate, 1);
2215 
2216     accessListPtr->certToolId = 1;
2217     accessListPtr->observationTimeSeconds = currentTime;
2218 
2219     /* Append Record */
2220     if (!fBufAppend(fbuf, (uint8_t *)&rec, sizeof(rec), err)) {
2221         return FALSE;
2222     }
2223 
2224     /* emit buffer */
2225     if (!fBufEmit(fbuf, err)) {
2226         return FALSE;
2227     }
2228 
2229     g_message("Sent Tombstone record: observationDomain:%d, "
2230             "exporterId:%d:%d, tombstoneId: %d",
2231             rec.observationDomainId, rec.exporterConfiguredId,
2232             rec.exportingProcessId, rec.tombstoneId);
2233 
2234     fbSubTemplateListClear(&(rec.accessList));
2235 
2236     /* Set Internal TID Back to Flow Record */
2237     if (!fBufSetInternalTemplate(fbuf, YAF_FLOW_FULL_TID, err)) {
2238         return FALSE;
2239     }
2240 
2241     return TRUE;
2242 }
2243 
2244 /**
2245  *yfWriteFlow
2246  *
2247  *
2248  *
2249  */
yfWriteFlow(void * yfContext,yfFlow_t * flow,GError ** err)2250 gboolean yfWriteFlow(
2251     void                *yfContext,
2252     yfFlow_t            *flow,
2253     GError              **err)
2254 {
2255     yfIpfixFlow_t       rec;
2256     uint16_t            wtid;
2257     uint16_t            etid = 0; /* extra templates */
2258     fbSubTemplateMultiListEntry_t *stml = NULL;
2259     yfTcpFlow_t         *tcprec = NULL;
2260     yfMacFlow_t         *macrec = NULL;
2261     yfMPTCPFlow_t       *mptcprec = NULL;
2262     int                 tmplcount = 0;
2263     gboolean            ok;
2264     gboolean            stats = FALSE;
2265     int32_t             temp = 0;
2266     int                 loop, count;
2267 #if YAF_ENABLE_ENTROPY
2268     yfEntropyFlow_t     *entropyrec;
2269 #endif
2270 #if YAF_ENABLE_P0F
2271     yfP0fFlow_t         *p0frec;
2272 #endif
2273 #if YAF_ENABLE_FPEXPORT
2274     yfFPExportFlow_t    *fpexportrec;
2275 #endif
2276 #if YAF_ENABLE_PAYLOAD
2277     yfPayloadFlow_t     *payrec;
2278 #endif
2279     yfContext_t         *ctx = (yfContext_t *)yfContext;
2280     fBuf_t              *fbuf = ctx->fbuf;
2281     yfFlowStatsRecord_t *statsflow = NULL;
2282 #if HAVE_SPREAD
2283     char                *spgroups[25];
2284     int                 i = 0, k = 0;
2285     fbSpreadParams_t    *spParam = &(ctx->cfg->spreadparams);
2286     uint16_t            spGroupBy = 0;
2287 #endif
2288 
2289     if (ctx->cfg->no_output) {
2290         return TRUE;
2291     }
2292 
2293      /* copy time */
2294     rec.flowStartMilliseconds = flow->stime;
2295     rec.flowEndMilliseconds = flow->etime;
2296     rec.reverseFlowDeltaMilliseconds = flow->rdtime;
2297 
2298     /* copy addresses */
2299     if (yaf_core_map_ipv6 && (flow->key.version == 4)) {
2300         memcpy(rec.sourceIPv6Address, yaf_ip6map_pfx,
2301                sizeof(yaf_ip6map_pfx));
2302         *(uint32_t *)(&(rec.sourceIPv6Address[sizeof(yaf_ip6map_pfx)])) =
2303             g_htonl(flow->key.addr.v4.sip);
2304         memcpy(rec.destinationIPv6Address, yaf_ip6map_pfx,
2305                sizeof(yaf_ip6map_pfx));
2306         *(uint32_t *)(&(rec.destinationIPv6Address[sizeof(yaf_ip6map_pfx)])) =
2307             g_htonl(flow->key.addr.v4.dip);
2308     } else if (flow->key.version == 4) {
2309         rec.sourceIPv4Address = flow->key.addr.v4.sip;
2310         rec.destinationIPv4Address = flow->key.addr.v4.dip;
2311     } else if (flow->key.version == 6) {
2312         memcpy(rec.sourceIPv6Address, flow->key.addr.v6.sip,
2313                sizeof(rec.sourceIPv6Address));
2314         memcpy(rec.destinationIPv6Address, flow->key.addr.v6.dip,
2315                sizeof(rec.destinationIPv6Address));
2316     } else {
2317         g_set_error(err, YAF_ERROR_DOMAIN, YAF_ERROR_ARGUMENT,
2318                     "Illegal IP version %u", flow->key.version);
2319     }
2320 
2321 
2322     /* choose options for basic template */
2323     wtid = YAF_FLOW_BASE_TID;
2324     rec.vlanId = flow->val.vlan;
2325     /* right? */
2326     rec.reverseVlanId = flow->rval.vlan;
2327 
2328     /* copy key and counters */
2329     rec.sourceTransportPort = flow->key.sp;
2330     rec.destinationTransportPort = flow->key.dp;
2331     rec.flowAttributes = flow->val.attributes;
2332     rec.reverseFlowAttributes = flow->rval.attributes;
2333     rec.protocolIdentifier = flow->key.proto;
2334     rec.flowEndReason = flow->reason;
2335 
2336     if (ctx->cfg->deltaMode) {
2337         rec.octetDeltaCount = flow->val.oct;
2338         rec.reverseOctetDeltaCount = flow->rval.oct;
2339         rec.packetDeltaCount = flow->val.pkt;
2340         rec.reversePacketDeltaCount = flow->rval.pkt;
2341         wtid |= YTF_DELTA;
2342     } else {
2343         rec.octetTotalCount = flow->val.oct;
2344         rec.reverseOctetTotalCount = flow->rval.oct;
2345         rec.packetTotalCount = flow->val.pkt;
2346         rec.reversePacketTotalCount = flow->rval.pkt;
2347         wtid |= YTF_TOTAL;
2348     }
2349 
2350     rec.ingressInterface = ctx->cfg->ingressInt;
2351     rec.egressInterface = ctx->cfg->egressInt;
2352 
2353     /* Type Of Service */
2354     rec.ipClassOfService = flow->key.tos;
2355     rec.reverseIpClassOfService = flow->rtos;
2356 
2357 #if YAF_ENABLE_DAG_SEPARATE_INTERFACES
2358     rec.ingressInterface = flow->key.netIf;
2359     rec.egressInterface  = flow->key.netIf | 0x100;
2360 #endif
2361 
2362 #if YAF_ENABLE_SEPARATE_INTERFACES
2363     rec.ingressInterface = flow->val.netIf;
2364     if (flow->rval.pkt) {
2365         rec.egressInterface = flow->rval.netIf;
2366     } else {
2367         rec.egressInterface = flow->val.netIf | 0x100;
2368     }
2369 #endif
2370 
2371 #if YAF_ENABLE_APPLABEL
2372     rec.silkAppLabel = flow->appLabel;
2373 
2374 #if HAVE_SPREAD
2375     spGroupBy = yfSpreadGroupby(ctx->cfg->spreadGroupby, rec.silkAppLabel,
2376                                 rec.vlanId, rec.destinationTransportPort,
2377                                 rec.protocolIdentifier, flow->key.version);
2378 #endif
2379 #else
2380 #if HAVE_SPREAD
2381     spGroupBy = yfSpreadGroupby(ctx->cfg->spreadGroupby, 0, rec.vlanId,
2382                                 rec.destinationTransportPort,
2383                                 rec.protocolIdentifier, flow->key.version);
2384 #endif
2385 #endif
2386 
2387 #if YAF_ENABLE_NDPI
2388     rec.ndpi_master = flow->ndpi_master;
2389     rec.ndpi_sub = flow->ndpi_sub;
2390 #endif
2391 
2392 #if YAF_MPLS
2393     /* since the mpls label isn't defined as an integer in fixbuf, it's
2394        not endian-converted on transcode, so we fix that here */
2395     /*    temp = htonl(flow->mpls->mpls_label[0]) >> 8;*/
2396     memcpy(rec.mpls_label1, &(flow->mpls->mpls_label[0]), 3);
2397     /*temp = htonl(flow->mpls->mpls_label[1]) >> 8;*/
2398     memcpy(rec.mpls_label2, &(flow->mpls->mpls_label[1]), 3);
2399     /*temp = htonl(flow->mpls->mpls_label[2]) >> 8;*/
2400     memcpy(rec.mpls_label3, &(flow->mpls->mpls_label[2]), 3);
2401 #endif
2402 
2403 #if HAVE_SPREAD
2404     /* Find out which groups we need to send this flow to */
2405     for (i = 0; i < ctx->cfg->numSpreadGroups; i++) {
2406         if (ctx->cfg->spreadGroupIndex[i] == spGroupBy ||
2407             ctx->cfg->spreadGroupIndex[i] == 0) {
2408             spgroups[k] = (spParam->groups[i]);
2409             k++;
2410         }
2411     }
2412 #endif
2413 
2414     if (flow->rval.pkt) {
2415         wtid |= YTF_BIF;
2416         etid = YTF_BIF;
2417     }
2418 
2419     if (rec.protocolIdentifier == YF_PROTO_TCP) {
2420         if (ctx->cfg->silkmode) {
2421             rec.tcpSequenceNumber = flow->val.isn;
2422             rec.reverseTcpSequenceNumber = flow->rval.isn;
2423             rec.initialTCPFlags = flow->val.iflags;
2424             rec.reverseInitialTCPFlags = flow->rval.iflags;
2425             rec.unionTCPFlags = flow->val.uflags;
2426             rec.reverseUnionTCPFlags = flow->rval.uflags;
2427             wtid |= YTF_SILK;
2428         } else {
2429             tmplcount++;
2430         }
2431     }
2432 
2433 #if YAF_MPLS
2434     wtid |= YTF_MPLS;
2435 #endif
2436 
2437     if (flow->val.oct < YAF_RLEMAX && flow->rval.oct < YAF_RLEMAX &&
2438         flow->val.pkt < YAF_RLEMAX && flow->rval.pkt < YAF_RLEMAX)
2439     {
2440         wtid |= YTF_RLE;
2441     } else {
2442         wtid |= YTF_FLE;
2443     }
2444 
2445     if (yaf_core_map_ipv6 || (flow->key.version == 6)) {
2446         wtid |= YTF_IP6;
2447     } else {
2448         wtid |= YTF_IP4;
2449     }
2450 
2451     if (rec.ingressInterface || rec.egressInterface) {
2452         wtid |= YTF_DAGIF;
2453     }
2454 
2455 #if YAF_ENABLE_DAG_SEPARATE_INTERFACES || YAF_ENABLE_SEPARATE_INTERFACES
2456     if (ctx->cfg->exportInterface) {
2457         wtid |= YTF_DAGIF;
2458     }
2459 #endif
2460 
2461 
2462 
2463 #if HAVE_SPREAD
2464     /* If we are selectively setting groups to send this to - set groups
2465        on the export buffer */
2466     if (ctx->cfg->spreadGroupIndex) {
2467         if (k) {
2468             fBufSetSpreadExportGroup(fbuf, spgroups, k, err);
2469         } else {
2470             return TRUE;
2471         }
2472         /* Now make sure the groups have those templates */
2473         if (!yfSetSpreadExportTemplate(fbuf, spParam, wtid, spgroups, k, err)){
2474             return FALSE;
2475         }
2476     } else {
2477         /* we are sending to all groups */
2478         if (!yfSetExportTemplate(fbuf, wtid, err)) {
2479             return FALSE;
2480         }
2481     }
2482 #else
2483 
2484     if (!yfSetExportTemplate(fbuf, wtid, err)) {
2485         return FALSE;
2486     }
2487 #endif
2488 
2489     if (ctx->cfg->macmode) {
2490         tmplcount++;
2491     }
2492 
2493     if (ctx->cfg->statsmode && flow->val.stats) {
2494         if (flow->val.stats->payoct || flow->rval.stats) {
2495             tmplcount++;
2496             stats = TRUE;
2497         }
2498     }
2499 
2500     if ((flow->mptcp.token)) {
2501         tmplcount++;
2502     }
2503 
2504 #if YAF_ENABLE_PAYLOAD
2505     /* point to payload */
2506     if ((0 < yaf_core_export_payload) &&
2507         (flow->val.paylen || flow->rval.paylen))
2508     {
2509         tmplcount++;
2510     }
2511     /* copy payload-derived information */
2512 
2513 #if YAF_ENABLE_HOOKS
2514     tmplcount += yfHookGetTemplateCount(flow);
2515 #endif
2516 
2517 #if YAF_ENABLE_ENTROPY
2518     if (flow->val.entropy || flow->rval.entropy) {
2519         tmplcount++;
2520     }
2521 #endif
2522 
2523 
2524 #if YAF_ENABLE_P0F
2525     if (flow->val.osname || flow->val.osver ||
2526         flow->rval.osname || flow->rval.osver ||
2527         flow->val.osFingerPrint || flow->rval.osFingerPrint)
2528     {
2529         tmplcount++;
2530     }
2531 #endif
2532 
2533 #if YAF_ENABLE_FPEXPORT
2534     if (flow->val.firstPacket || flow->rval.firstPacket ||
2535         flow->val.secondPacket)
2536     {
2537         tmplcount++;
2538     }
2539 #endif
2540 
2541 #endif
2542 
2543     /* Initialize SubTemplateMultiList with number of templates we are to add*/
2544     fbSubTemplateMultiListInit(&(rec.subTemplateMultiList), 3, tmplcount);
2545 
2546     /* Add TCP Template - IF TCP Flow and SiLK Mode is OFF */
2547     if (flow->key.proto == YF_PROTO_TCP && !ctx->cfg->silkmode) {
2548         stml = FBSTMLNEXT(&(rec.subTemplateMultiList), stml);
2549         if (etid) {
2550             tcprec = (yfTcpFlow_t *)FBSTMLINIT(stml,
2551                                                (YAF_TCP_FLOW_TID | etid),
2552                                                yaf_tmpl.revTcpTemplate);
2553             tcprec->reverseTcpSequenceNumber = flow->rval.isn;
2554             tcprec->reverseInitialTCPFlags = flow->rval.iflags;
2555             tcprec->reverseUnionTCPFlags = flow->rval.uflags;
2556         } else {
2557             tcprec = (yfTcpFlow_t *)FBSTMLINIT(stml, YAF_TCP_FLOW_TID,
2558                                                yaf_tmpl.tcpTemplate);
2559         }
2560         tcprec->tcpSequenceNumber = flow->val.isn;
2561         tcprec->initialTCPFlags = flow->val.iflags;
2562         tcprec->unionTCPFlags = flow->val.uflags;
2563         tmplcount--;
2564     }
2565 
2566     /* Add MAC Addresses */
2567     if (ctx->cfg->macmode) {
2568         stml = FBSTMLNEXT(&(rec.subTemplateMultiList), stml);
2569         macrec = (yfMacFlow_t *)FBSTMLINIT(stml, YAF_MAC_FLOW_TID,
2570                                            yaf_tmpl.macTemplate);
2571         memcpy(macrec->sourceMacAddress, flow->sourceMacAddr,
2572                ETHERNET_MAC_ADDR_LENGTH);
2573         memcpy(macrec->destinationMacAddress, flow->destinationMacAddr,
2574                ETHERNET_MAC_ADDR_LENGTH);
2575         tmplcount--;
2576     }
2577 
2578     if (flow->mptcp.token) {
2579         stml = FBSTMLNEXT(&(rec.subTemplateMultiList), stml);
2580         mptcprec = (yfMPTCPFlow_t *)FBSTMLINIT(stml, YAF_MPTCP_FLOW_TID,
2581                                                yaf_tmpl.mptcpTemplate);
2582         memcpy(mptcprec, &(flow->mptcp), sizeof(yfMPTCPFlow_t));
2583         tmplcount --;
2584     }
2585 
2586 #if YAF_ENABLE_PAYLOAD
2587     /* Add Payload Template */
2588     if ((0 < yaf_core_export_payload) &&
2589         (flow->val.paylen || flow->rval.paylen))
2590     {
2591         stml = FBSTMLNEXT(&(rec.subTemplateMultiList), stml);
2592         if (etid) {
2593             payrec = (yfPayloadFlow_t *)FBSTMLINIT(stml,
2594                                                    YAF_PAYLOAD_FLOW_TID | etid,
2595                                                   yaf_tmpl.revPayloadTemplate);
2596             if (flow->rval.paylen > yaf_core_export_payload) {
2597                 payrec->reversePayload.len = yaf_core_export_payload;
2598             } else {
2599                 payrec->reversePayload.len = flow->rval.paylen;
2600             }
2601             payrec->reversePayload.buf = flow->rval.payload;
2602         } else {
2603             payrec = (yfPayloadFlow_t *)FBSTMLINIT(stml,
2604                                                    YAF_PAYLOAD_FLOW_TID,
2605                                                    yaf_tmpl.payloadTemplate);
2606         }
2607         payrec->payload.buf = flow->val.payload;
2608         if (flow->val.paylen > yaf_core_export_payload) {
2609             payrec->payload.len = yaf_core_export_payload;
2610         } else {
2611             payrec->payload.len = flow->val.paylen;
2612         }
2613         tmplcount--;
2614     }
2615 #endif
2616 
2617 
2618 #if YAF_ENABLE_ENTROPY
2619     /* Add Entropy Template */
2620     if (flow->val.entropy || flow->rval.entropy) {
2621         stml = FBSTMLNEXT(&(rec.subTemplateMultiList), stml);
2622         if (etid) {
2623             entropyrec = (yfEntropyFlow_t *)FBSTMLINIT(stml,
2624                                                   YAF_ENTROPY_FLOW_TID | etid,
2625                                                   yaf_tmpl.revEntropyTemplate);
2626             entropyrec->reverseEntropy = flow->rval.entropy;
2627         } else {
2628             entropyrec = (yfEntropyFlow_t *)FBSTMLINIT(stml,
2629                                                        YAF_ENTROPY_FLOW_TID,
2630                                                      yaf_tmpl.entropyTemplate);
2631         }
2632         entropyrec->entropy = flow->val.entropy;
2633         tmplcount--;
2634     }
2635 #endif
2636 
2637 #if YAF_ENABLE_P0F
2638     /* Add P0F Template */
2639     if (flow->val.osname || flow->val.osver || flow->rval.osname ||
2640         flow->rval.osver || flow->val.osFingerPrint ||flow->rval.osFingerPrint)
2641     {
2642         stml = FBSTMLNEXT(&(rec.subTemplateMultiList), stml);
2643         if (etid) {
2644             p0frec = (yfP0fFlow_t *)FBSTMLINIT(stml,
2645                                                YAF_P0F_FLOW_TID | etid,
2646                                                yaf_tmpl.revP0fTemplate);
2647             if (NULL != flow->rval.osname) {
2648                 p0frec->reverseOsName.buf = (uint8_t *)flow->rval.osname;
2649                 p0frec->reverseOsName.len = strlen(flow->rval.osname);
2650             } else {
2651                 p0frec->reverseOsName.len = 0;
2652             }
2653             if (NULL != flow->rval.osver) {
2654                 p0frec->reverseOsVersion.buf = (uint8_t *)flow->rval.osver;
2655                 p0frec->reverseOsVersion.len = strlen(flow->rval.osver);
2656             } else {
2657                 p0frec->reverseOsVersion.len = 0;
2658             }
2659             if (NULL != flow->rval.osFingerPrint) {
2660                 p0frec->reverseOsFingerPrint.buf = (uint8_t *)
2661                                                    flow->rval.osFingerPrint;
2662                 p0frec->reverseOsFingerPrint.len =
2663                     strlen(flow->rval.osFingerPrint);
2664             } else {
2665                 p0frec->reverseOsFingerPrint.len = 0;
2666             }
2667         } else {
2668             p0frec = (yfP0fFlow_t *)FBSTMLINIT(stml, YAF_P0F_FLOW_TID,
2669                                                yaf_tmpl.p0fTemplate);
2670         }
2671         if (NULL != flow->val.osname) {
2672             p0frec->osName.buf  = (uint8_t *)flow->val.osname;
2673             p0frec->osName.len  = strlen(flow->val.osname);
2674         } else {
2675             p0frec->osName.len = 0;
2676         }
2677 
2678         if (NULL != flow->val.osver) {
2679             p0frec->osVersion.buf = (uint8_t *)flow->val.osver;
2680             p0frec->osVersion.len = strlen(flow->val.osver);
2681         } else {
2682             p0frec->osVersion.len = 0;
2683         }
2684 
2685         if (NULL != flow->val.osFingerPrint) {
2686             p0frec->osFingerPrint.buf = (uint8_t *) flow->val.osFingerPrint;
2687             p0frec->osFingerPrint.len = strlen(flow->val.osFingerPrint);
2688         } else {
2689             p0frec->osFingerPrint.len = 0;
2690         }
2691         tmplcount--;
2692     }
2693 #endif
2694 
2695 #if YAF_ENABLE_FPEXPORT
2696     /* Add FingerPrint Template */
2697     if (flow->val.firstPacket || flow->rval.firstPacket ||
2698         flow->val.secondPacket)
2699     {
2700         stml = FBSTMLNEXT(&(rec.subTemplateMultiList), stml);
2701 
2702         if (etid) {
2703             fpexportrec = (yfFPExportFlow_t *)FBSTMLINIT(stml,
2704                                                 (YAF_FPEXPORT_FLOW_TID | etid),
2705                                                  yaf_tmpl.revFpexportTemplate);
2706             fpexportrec->reverseFirstPacketBanner.buf = flow->rval.firstPacket;
2707             fpexportrec->reverseFirstPacketBanner.len =
2708                 flow->rval.firstPacketLen;
2709         } else {
2710             fpexportrec = (yfFPExportFlow_t *)FBSTMLINIT(stml,
2711                                                          YAF_FPEXPORT_FLOW_TID,
2712                                                     yaf_tmpl.fpexportTemplate);
2713         }
2714         fpexportrec->firstPacketBanner.buf = flow->val.firstPacket;
2715         fpexportrec->firstPacketBanner.len = flow->val.firstPacketLen;
2716         fpexportrec->secondPacketBanner.buf = flow->val.secondPacket;
2717         fpexportrec->secondPacketBanner.len = flow->val.secondPacketLen;
2718         tmplcount--;
2719         }
2720 #endif
2721 
2722     if (stats) {
2723         uint16_t pktavg = 0;
2724         stml = FBSTMLNEXT(&(rec.subTemplateMultiList), stml);
2725         if (etid) {
2726             statsflow =
2727                 (yfFlowStatsRecord_t *)FBSTMLINIT(stml,
2728                                                   (YAF_STATS_FLOW_TID | etid),
2729                                                   yaf_tmpl.revfstatsTemplate);
2730             statsflow->reverseTcpUrgTotalCount = flow->rval.stats->tcpurgct;
2731             statsflow->reverseSmallPacketCount = flow->rval.stats->smallpktct;
2732             statsflow->reverseFirstNonEmptyPacketSize =
2733                 flow->rval.stats->firstpktsize;
2734             statsflow->reverseNonEmptyPacketCount =
2735                 flow->rval.stats->nonemptypktct;
2736             statsflow->reverseLargePacketCount =
2737                 flow->rval.stats->largepktct;
2738             statsflow->reverseDataByteCount = flow->rval.stats->payoct;
2739             count = (statsflow->reverseNonEmptyPacketCount > 10) ? 10 : statsflow->reverseNonEmptyPacketCount;
2740             if (flow->rval.stats->nonemptypktct) {
2741                 pktavg =flow->rval.stats->payoct/flow->rval.stats->nonemptypktct;
2742             }
2743             for (loop = 0; loop < count; loop++) {
2744                 temp += (pow(abs(flow->rval.stats->pktsize[loop] - pktavg), 2));
2745             }
2746             if (count) {
2747                 statsflow->reverseStandardDeviationPayloadLength =
2748                     sqrt(temp / count);
2749             }
2750             if (flow->rval.pkt > 1) {
2751                 uint64_t time_temp = 0;
2752                 statsflow->reverseAverageInterarrivalTime =
2753                     flow->rval.stats->aitime /(flow->rval.pkt - 1);
2754                 count = (flow->rval.pkt > 11) ? 10 : (flow->rval.pkt - 1);
2755                 for (loop = 0; loop < count; loop++) {
2756                     time_temp += (pow(labs(flow->rval.stats->iaarray[loop] -
2757                                           statsflow->reverseAverageInterarrivalTime), 2));
2758                 }
2759                 statsflow->reverseStandardDeviationInterarrivalTime =
2760                     sqrt(time_temp / count);
2761             }
2762             statsflow->reverseMaxPacketSize = flow->rval.stats->maxpktsize;
2763         } else {
2764             statsflow = (yfFlowStatsRecord_t *)FBSTMLINIT(stml,
2765                                                           YAF_STATS_FLOW_TID,
2766                                                       yaf_tmpl.fstatsTemplate);
2767         }
2768         pktavg = 0;
2769         statsflow->tcpUrgTotalCount = flow->val.stats->tcpurgct;
2770         statsflow->smallPacketCount = flow->val.stats->smallpktct;
2771         statsflow->firstNonEmptyPacketSize = flow->val.stats->firstpktsize;
2772         statsflow->nonEmptyPacketCount = flow->val.stats->nonemptypktct;
2773         statsflow->dataByteCount = flow->val.stats->payoct;
2774         statsflow->maxPacketSize = flow->val.stats->maxpktsize;
2775         statsflow->firstEightNonEmptyPacketDirections = flow->pktdir;
2776         statsflow->largePacketCount = flow->val.stats->largepktct;
2777         temp = 0;
2778         count = (statsflow->nonEmptyPacketCount < 10) ? statsflow->nonEmptyPacketCount : 10;
2779         if (flow->val.stats->nonemptypktct) {
2780             pktavg = flow->val.stats->payoct / flow->val.stats->nonemptypktct;
2781         }
2782         for (loop = 0; loop < count; loop++) {
2783             temp += (pow(abs(flow->val.stats->pktsize[loop] - pktavg), 2));
2784         }
2785         if (count) {
2786             statsflow->standardDeviationPayloadLength =
2787                 sqrt(temp / count);
2788         }
2789         if (flow->val.pkt > 1) {
2790             uint64_t time_temp = 0;
2791             statsflow->averageInterarrivalTime = flow->val.stats->aitime /
2792                                                  (flow->val.pkt - 1);
2793             count = (flow->val.pkt > 11) ? 10 : (flow->val.pkt - 1);
2794             for (loop = 0; loop < count; loop++) {
2795                 time_temp += (pow(labs(flow->val.stats->iaarray[loop] -
2796                                        statsflow->averageInterarrivalTime),2));
2797             }
2798             statsflow->standardDeviationInterarrivalTime=sqrt(time_temp/count);
2799         }
2800         tmplcount--;
2801     }
2802 
2803 #if YAF_ENABLE_HOOKS
2804     /* write hook record - only add if there are some available in list*/
2805     if (!yfWriteFlowHook(&(rec.subTemplateMultiList), stml, flow, err)) {
2806         return FALSE;
2807     }
2808 # endif
2809 
2810     /* IF UDP - Check to see if we need to re-export templates */
2811     /* We do not advise in using UDP (nicer than saying you're stupid) */
2812     if ((ctx->cfg->connspec.transport == FB_UDP) ||
2813         (ctx->cfg->connspec.transport == FB_DTLS_UDP))
2814     {
2815         /* 3 is the factor from RFC 5101 as a recommendation of how often
2816            between timeouts to resend */
2817         if ((flow->etime > ctx->lastUdpTempTime) &&
2818             ((flow->etime - ctx->lastUdpTempTime) >
2819              ((ctx->cfg->yaf_udp_template_timeout)/3)))
2820         {
2821             /* resend templates */
2822             ok = fbSessionExportTemplates(fBufGetSession(ctx->fbuf), err);
2823             ctx->lastUdpTempTime = flow->etime;
2824             if (!ok) {
2825                 g_warning("Failed to renew UDP Templates: %s",
2826                           (*err)->message);
2827                 g_clear_error(err);
2828             }
2829         }
2830         if (!(ctx->cfg->livetype)) {
2831             /* slow down UDP export if reading from a file */
2832             usleep(2);
2833         }
2834     }
2835 
2836     /* Now append the record to the buffer */
2837     if (!fBufAppend(fbuf, (uint8_t *)&rec, sizeof(rec), err)) {
2838         return FALSE;
2839     }
2840 
2841 #if YAF_ENABLE_HOOKS
2842     /* clear basic lists */
2843     yfHookFreeLists(flow);
2844 #endif
2845     /* Clear MultiList */
2846     fbSubTemplateMultiListClear(&(rec.subTemplateMultiList));
2847 
2848     return TRUE;
2849 }
2850 
2851 /**
2852  *yfWriterClose
2853  *
2854  *
2855  *
2856  */
yfWriterClose(fBuf_t * fbuf,gboolean flush,GError ** err)2857 gboolean yfWriterClose(
2858     fBuf_t          *fbuf,
2859     gboolean        flush,
2860     GError          **err)
2861 {
2862     gboolean        ok = TRUE;
2863 
2864     if (flush) {
2865         ok = fBufEmit(fbuf, err);
2866     }
2867 
2868     fBufFree(fbuf);
2869 
2870     return ok;
2871 }
2872 
2873 /**
2874  * yfTemplateCallback
2875  *
2876  *
2877  */
yfTemplateCallback(fbSession_t * session,uint16_t tid,fbTemplate_t * tmpl,void * app_ctx,void ** tmpl_ctx,fbTemplateCtxFree_fn * fn)2878 static void yfTemplateCallback(
2879     fbSession_t           *session,
2880     uint16_t               tid,
2881     fbTemplate_t          *tmpl,
2882     void                  *app_ctx,
2883     void                 **tmpl_ctx,
2884     fbTemplateCtxFree_fn  *fn)
2885 {
2886     uint16_t ntid;
2887 
2888     ntid = tid & YTF_REV;
2889 
2890     if (YAF_FLOW_BASE_TID == (tid & 0xF000)) {
2891         fbSessionAddTemplatePair(session, tid, tid);
2892     }
2893 
2894     if (ntid == YAF_ENTROPY_FLOW_TID) {
2895         fbSessionAddTemplatePair(session, tid, tid);
2896     } else if (ntid == YAF_TCP_FLOW_TID) {
2897         fbSessionAddTemplatePair(session, tid, tid);
2898     } else if (ntid == YAF_MAC_FLOW_TID) {
2899         fbSessionAddTemplatePair(session, tid, tid);
2900     } else if (ntid == YAF_PAYLOAD_FLOW_TID) {
2901         fbSessionAddTemplatePair(session, tid, tid);
2902     } else {
2903         /* Dont decode templates yafscii doesn't care about */
2904         fbSessionAddTemplatePair(session, tid, 0);
2905     }
2906 
2907 }
2908 
2909 /**
2910  *yfInitCollectorSession
2911  *
2912  *
2913  *
2914  */
yfInitCollectorSession(GError ** err)2915 static fbSession_t *yfInitCollectorSession(
2916     GError          **err)
2917 {
2918     fbInfoModel_t   *model = yfInfoModel();
2919     fbTemplate_t    *tmpl = NULL;
2920     fbSession_t     *session = NULL;
2921 
2922     /* Allocate the session */
2923     session = fbSessionAlloc(model);
2924 
2925     /* Add the full record template */
2926     tmpl = fbTemplateAlloc(model);
2927 
2928     if (!fbTemplateAppendSpecArray(tmpl, yaf_flow_spec, YTF_ALL, err))
2929         return NULL;
2930     if (!fbSessionAddTemplate(session, TRUE, YAF_FLOW_FULL_TID, tmpl, err))
2931         return NULL;
2932 
2933 #if YAF_ENABLE_ENTROPY
2934     yaf_tmpl.entropyTemplate = fbTemplateAlloc(model);
2935     if (!fbTemplateAppendSpecArray(yaf_tmpl.entropyTemplate, yaf_entropy_spec,
2936                                    0xffffffff, err)){
2937         return NULL;
2938     }
2939     if (!fbSessionAddTemplate(session, TRUE, YAF_ENTROPY_FLOW_TID,
2940                               yaf_tmpl.entropyTemplate, err))
2941     {
2942         return NULL;
2943     }
2944 #endif
2945     yaf_tmpl.tcpTemplate = fbTemplateAlloc(model);
2946     if (!fbTemplateAppendSpecArray(yaf_tmpl.tcpTemplate, yaf_tcp_spec,
2947                                    0xffffffff, err))
2948     {
2949         return NULL;
2950     }
2951     if (!fbSessionAddTemplate(session, TRUE, YAF_TCP_FLOW_TID,
2952                               yaf_tmpl.tcpTemplate, err))
2953     {
2954         return NULL;
2955     }
2956 
2957     yaf_tmpl.macTemplate = fbTemplateAlloc(model);
2958     if (!fbTemplateAppendSpecArray(yaf_tmpl.macTemplate, yaf_mac_spec,
2959                                    0xffffffff, err))
2960     {
2961         return NULL;
2962     }
2963     if (!fbSessionAddTemplate(session, TRUE, YAF_MAC_FLOW_TID,
2964                               yaf_tmpl.macTemplate, err))
2965     {
2966         return NULL;
2967     }
2968 
2969 #if YAF_ENABLE_P0F
2970     yaf_tmpl.p0fTemplate = fbTemplateAlloc(model);
2971     if (!fbTemplateAppendSpecArray(yaf_tmpl.p0fTemplate, yaf_p0f_spec,
2972                                    0xffffffff, err))
2973     {
2974         return NULL;
2975     }
2976     if (!fbSessionAddTemplate(session, TRUE, YAF_P0F_FLOW_TID,
2977                               yaf_tmpl.p0fTemplate, err))
2978     {
2979         return NULL;
2980     }
2981 #endif
2982 
2983 #if YAF_ENABLE_FPEXPORT
2984     yaf_tmpl.fpexportTemplate = fbTemplateAlloc(model);
2985     if (!fbTemplateAppendSpecArray(yaf_tmpl.fpexportTemplate,
2986                                    yaf_fpexport_spec, 0xffffffff, err))
2987     {
2988         return NULL;
2989     }
2990     if (!fbSessionAddTemplate(session, TRUE, YAF_FPEXPORT_FLOW_TID,
2991                               yaf_tmpl.fpexportTemplate, err))
2992     {
2993         return NULL;
2994     }
2995 #endif
2996 
2997 #if YAF_ENABLE_PAYLOAD
2998     yaf_tmpl.payloadTemplate = fbTemplateAlloc(model);
2999     if(!fbTemplateAppendSpecArray(yaf_tmpl.payloadTemplate, yaf_payload_spec,
3000                                   0xffffffff, err))
3001     {
3002         return NULL;
3003     }
3004     if (!fbSessionAddTemplate(session, TRUE, YAF_PAYLOAD_FLOW_TID,
3005                               yaf_tmpl.payloadTemplate, err))
3006     {
3007         return NULL;
3008     }
3009 #endif
3010 
3011     /* Add the extended record template */
3012     tmpl = fbTemplateAlloc(model);
3013     if (!fbTemplateAppendSpecArray(tmpl, yaf_flow_spec, YTF_ALL, err))
3014         return NULL;
3015     if (!fbTemplateAppendSpecArray(tmpl, yaf_extime_spec, YTF_ALL, err))
3016         return NULL;
3017     if (!fbSessionAddTemplate(session, TRUE, YAF_FLOW_EXT_TID, tmpl, err))
3018         return NULL;
3019 
3020     /* Done. Return the session. */
3021 
3022     /** Add the template callback so we don't try to decode DPI */
3023     fbSessionAddNewTemplateCallback(session, yfTemplateCallback, NULL);
3024 
3025     return session;
3026 }
3027 
3028 /**
3029  *yfReaderForFP
3030  *
3031  *
3032  *
3033  */
yfReaderForFP(fBuf_t * fbuf,FILE * fp,GError ** err)3034 fBuf_t *yfReaderForFP(
3035     fBuf_t          *fbuf,
3036     FILE            *fp,
3037     GError          **err)
3038 {
3039     fbSession_t     *session;
3040     fbCollector_t   *collector;
3041 
3042     /* Allocate a collector for the file */
3043     collector = fbCollectorAllocFP(NULL, fp);
3044 
3045     /* Allocate a buffer, or reset the collector */
3046     if (fbuf) {
3047         fBufSetCollector(fbuf, collector);
3048     } else {
3049         if (!(session = yfInitCollectorSession(err))) goto err;
3050         fbuf = fBufAllocForCollection(session, collector);
3051     }
3052 
3053     /* FIXME do a preread? */
3054 
3055     return fbuf;
3056 
3057   err:
3058     /* free buffer if necessary */
3059     if (fbuf) fBufFree(fbuf);
3060     return NULL;
3061 }
3062 
3063 /**
3064  *yfListenerForSpec
3065  *
3066  *
3067  *
3068  */
yfListenerForSpec(fbConnSpec_t * spec,fbListenerAppInit_fn appinit,fbListenerAppFree_fn appfree,GError ** err)3069 fbListener_t *yfListenerForSpec(
3070     fbConnSpec_t            *spec,
3071     fbListenerAppInit_fn    appinit,
3072     fbListenerAppFree_fn    appfree,
3073     GError                  **err)
3074 {
3075     fbSession_t     *session;
3076 
3077     if (!(session = yfInitCollectorSession(err))) return NULL;
3078 
3079     return fbListenerAlloc(spec, session, appinit, appfree, err);
3080 }
3081 
3082 
3083 /**
3084  *yfReadFlow
3085  *
3086  * read an IPFIX record in, with respect to fields YAF cares about
3087  *
3088  */
yfReadFlow(fBuf_t * fbuf,yfFlow_t * flow,GError ** err)3089 gboolean yfReadFlow(
3090     fBuf_t          *fbuf,
3091     yfFlow_t        *flow,
3092     GError          **err)
3093 {
3094     yfIpfixFlow_t       rec;
3095     size_t              len;
3096     fbSubTemplateMultiListEntry_t *stml = NULL;
3097     yfTcpFlow_t         *tcprec = NULL;
3098     fbTemplate_t        *next_tmpl = NULL;
3099     yfMacFlow_t         *macrec = NULL;
3100 #if YAF_ENABLE_ENTROPY
3101     yfEntropyFlow_t     *entropyrec = NULL;
3102 #endif
3103 #if YAF_ENABLE_PAYLOAD
3104     yfPayloadFlow_t     *payrec = NULL;
3105 #endif
3106 
3107     len = sizeof(yfIpfixFlow_t);
3108 
3109     /* Check if Options Template - if so - ignore */
3110     next_tmpl = fBufNextCollectionTemplate(fbuf, NULL, err);
3111     if (next_tmpl) {
3112         if (fbTemplateGetOptionsScope(next_tmpl)) {
3113             /* Stats Msg - Don't actually Decode */
3114             if (!fBufNext(fbuf, (uint8_t *)&rec, &len, err)) {
3115                 return FALSE;
3116             }
3117             return TRUE;
3118         }
3119     } else {
3120         return FALSE;
3121     }
3122 
3123     /* read next YAF record */
3124     if (!fBufSetInternalTemplate(fbuf, YAF_FLOW_FULL_TID, err))
3125         return FALSE;
3126     if (!fBufNext(fbuf, (uint8_t *)&rec, &len, err))
3127         return FALSE;
3128 
3129     /* copy time */
3130     flow->stime = rec.flowStartMilliseconds;
3131     flow->etime = rec.flowEndMilliseconds;
3132     flow->rdtime = rec.reverseFlowDeltaMilliseconds;
3133     /* copy addresses */
3134     if (rec.sourceIPv4Address || rec.destinationIPv4Address) {
3135         flow->key.version = 4;
3136         flow->key.addr.v4.sip = rec.sourceIPv4Address;
3137         flow->key.addr.v4.dip = rec.destinationIPv4Address;
3138     } else {
3139         flow->key.version = 6;
3140         memcpy(flow->key.addr.v6.sip, rec.sourceIPv6Address,
3141                sizeof(flow->key.addr.v6.sip));
3142         memcpy(flow->key.addr.v6.dip, rec.destinationIPv6Address,
3143                sizeof(flow->key.addr.v6.dip));
3144     }
3145 
3146     /* copy key and counters */
3147     flow->key.sp = rec.sourceTransportPort;
3148     flow->key.dp = rec.destinationTransportPort;
3149     flow->key.proto = rec.protocolIdentifier;
3150     flow->val.oct = rec.octetTotalCount;
3151     flow->val.pkt = rec.packetTotalCount;
3152     if (flow->val.oct == 0 && flow->val.pkt == 0) {
3153         flow->val.oct = rec.octetDeltaCount;
3154         flow->val.pkt = rec.packetDeltaCount;
3155     }
3156     flow->key.vlanId = rec.vlanId;
3157     flow->val.vlan = rec.vlanId;
3158     flow->rval.vlan = rec.reverseVlanId;
3159     flow->rval.oct = rec.reverseOctetTotalCount;
3160     flow->rval.pkt = rec.reversePacketTotalCount;
3161     flow->reason = rec.flowEndReason;
3162 
3163 #if YAF_ENABLE_APPLABEL
3164     flow->appLabel = rec.silkAppLabel;
3165 #endif
3166 #if YAF_ENABLE_ENTROPY
3167     flow->val.entropy = 0;
3168     flow->rval.entropy = 0;
3169 #endif
3170     flow->val.isn = rec.tcpSequenceNumber;
3171     flow->val.iflags = rec.initialTCPFlags;
3172     flow->val.uflags = rec.unionTCPFlags;
3173     flow->rval.isn = rec.reverseTcpSequenceNumber;
3174     flow->rval.iflags = rec.reverseInitialTCPFlags;
3175     flow->rval.uflags = rec.reverseUnionTCPFlags;
3176 
3177     /* Get subTemplateMultiList Entry */
3178     while ((stml = FBSTMLNEXT(&(rec.subTemplateMultiList), stml)))
3179     {
3180         switch ((stml->tmplID & YTF_REV)) {
3181 
3182 #if YAF_ENABLE_ENTROPY
3183         case YAF_ENTROPY_FLOW_TID:
3184             entropyrec = (yfEntropyFlow_t *)fbSubTemplateMultiListEntryNextDataPtr(stml, entropyrec);
3185             flow->val.entropy = entropyrec->entropy;
3186             if ((stml->tmplID & YTF_BIF)) {
3187                 flow->rval.entropy = entropyrec->reverseEntropy;
3188             }
3189             break;
3190 #endif
3191         case YAF_TCP_FLOW_TID:
3192             tcprec = (yfTcpFlow_t *)fbSubTemplateMultiListEntryNextDataPtr(stml, tcprec);
3193             flow->val.isn = tcprec->tcpSequenceNumber;
3194             flow->val.iflags = tcprec->initialTCPFlags;
3195             flow->val.uflags = tcprec->unionTCPFlags;
3196             if ((stml->tmplID & YTF_BIF)) {
3197                 flow->rval.isn = tcprec->reverseTcpSequenceNumber;
3198                 flow->rval.iflags = tcprec->reverseInitialTCPFlags;
3199                 flow->rval.uflags = tcprec->reverseUnionTCPFlags;
3200             }
3201             break;
3202         case YAF_MAC_FLOW_TID:
3203             macrec = (yfMacFlow_t *)fbSubTemplateMultiListEntryNextDataPtr(stml, macrec);
3204             memcpy(flow->sourceMacAddr, macrec->sourceMacAddress,
3205                    ETHERNET_MAC_ADDR_LENGTH);
3206             memcpy(flow->destinationMacAddr, macrec->destinationMacAddress,
3207                    ETHERNET_MAC_ADDR_LENGTH);
3208             break;
3209 #if YAF_ENABLE_PAYLOAD
3210         case YAF_PAYLOAD_FLOW_TID:
3211             /* copy payload */
3212             payrec = (yfPayloadFlow_t *)fbSubTemplateMultiListEntryNextDataPtr(stml, payrec);
3213             yfPayloadCopyIn(&payrec->payload, &flow->val);
3214             if ((stml->tmplID & YTF_BIF)) {
3215                 yfPayloadCopyIn(&payrec->reversePayload, &flow->rval);
3216             }
3217             break;
3218 #   endif
3219         default:
3220             /* don't know about this template */
3221             break;
3222         }
3223     }
3224 
3225     fbSubTemplateMultiListClear(&(rec.subTemplateMultiList));
3226 
3227     return TRUE;
3228 }
3229 
3230 /**
3231  *yfNTPDecode
3232  *
3233  * decodes a 64-bit NTP time variable and returns it in terms of
3234  * milliseconds
3235  *
3236  *
3237  */
yfNTPDecode(uint64_t ntp)3238 static uint64_t yfNTPDecode(
3239     uint64_t        ntp)
3240 {
3241     double          dntp;
3242     uint64_t        millis;
3243 
3244     if (!ntp) return 0;
3245 
3246     dntp = (ntp & 0xFFFFFFFF00000000LL) >> 32;
3247     dntp += ((ntp & 0x00000000FFFFFFFFLL) * 1.0) / (2LL << 32);
3248     millis = dntp * 1000;
3249     return millis;
3250 }
3251 
3252 
3253 /**
3254  *yfReadFlowExtended
3255  *
3256  * read an IPFIX flow record in (with respect to fields YAF cares about)
3257  * using YAF's extended precision time recording
3258  *
3259  */
yfReadFlowExtended(fBuf_t * fbuf,yfFlow_t * flow,GError ** err)3260 gboolean yfReadFlowExtended(
3261     fBuf_t                  *fbuf,
3262     yfFlow_t                *flow,
3263     GError                  **err)
3264 {
3265     yfIpfixExtFlow_t        rec;
3266     fbTemplate_t            *next_tmpl = NULL;
3267     size_t                  len;
3268     fbSubTemplateMultiListEntry_t *stml = NULL;
3269     yfTcpFlow_t         *tcprec = NULL;
3270     yfMacFlow_t         *macrec = NULL;
3271 #if YAF_ENABLE_ENTROPY
3272     yfEntropyFlow_t     *entropyrec = NULL;
3273 #endif
3274 #if YAF_ENABLE_PAYLOAD
3275     yfPayloadFlow_t     *payrec = NULL;
3276 #endif
3277 
3278     /* read next YAF record; retrying on missing template or EOF. */
3279     len = sizeof(yfIpfixExtFlow_t);
3280     if (!fBufSetInternalTemplate(fbuf, YAF_FLOW_EXT_TID, err))
3281         return FALSE;
3282 
3283     while (1) {
3284 
3285         /* Check if Options Template - if so - ignore */
3286         next_tmpl = fBufNextCollectionTemplate(fbuf, NULL, err);
3287         if (next_tmpl) {
3288             if (fbTemplateGetOptionsScope(next_tmpl)) {
3289                 if (!(fBufNext(fbuf, (uint8_t *)&rec, &len, err))) {
3290                     return FALSE;
3291                 }
3292                 continue;
3293             }
3294         } else {
3295             return FALSE;
3296         }
3297         if (fBufNext(fbuf, (uint8_t *)&rec, &len, err)) {
3298             break;
3299         } else {
3300             if (g_error_matches(*err, FB_ERROR_DOMAIN, FB_ERROR_TMPL)) {
3301                 /* try again on missing template */
3302                 g_debug("skipping IPFIX data set: %s", (*err)->message);
3303                 g_clear_error(err);
3304                 continue;
3305             } else {
3306                 /* real, actual error */
3307                 return FALSE;
3308             }
3309         }
3310     }
3311 
3312     /* Run the Gauntlet of Time. */
3313     if (rec.f.flowStartMilliseconds) {
3314         flow->stime = rec.f.flowStartMilliseconds;
3315         if (rec.f.flowEndMilliseconds >= rec.f.flowStartMilliseconds) {
3316             flow->etime = rec.f.flowEndMilliseconds;
3317         } else {
3318             flow->etime = flow->stime + rec.flowDurationMilliseconds;
3319         }
3320     } else if (rec.flowStartMicroseconds) {
3321         /* Decode NTP-format microseconds */
3322         flow->stime = yfNTPDecode(rec.flowStartMicroseconds);
3323         if (rec.flowEndMicroseconds >= rec.flowStartMicroseconds) {
3324             flow->etime = yfNTPDecode(rec.flowEndMicroseconds);
3325         } else {
3326             flow->etime = flow->stime + (rec.flowDurationMicroseconds / 1000);
3327         }
3328     } else if (rec.flowStartSeconds) {
3329         /* Seconds? Well. Okay... */
3330         flow->stime = rec.flowStartSeconds * 1000;
3331         flow->etime = rec.flowEndSeconds * 1000;
3332     } else if (rec.flowStartDeltaMicroseconds) {
3333         /* Handle delta microseconds. */
3334         flow->stime = fBufGetExportTime(fbuf) * 1000 -
3335                       rec.flowStartDeltaMicroseconds / 1000;
3336         if (rec.flowEndDeltaMicroseconds &&
3337             rec.flowEndDeltaMicroseconds <= rec.flowStartDeltaMicroseconds) {
3338             flow->etime = fBufGetExportTime(fbuf) * 1000 -
3339                           rec.flowEndDeltaMicroseconds / 1000;
3340         } else {
3341             flow->etime = flow->stime + (rec.flowDurationMicroseconds / 1000);
3342         }
3343     } else {
3344         /* Out of time. Use current timestamp, zero duration */
3345         struct timeval ct;
3346         g_assert(!gettimeofday(&ct, NULL));
3347         flow->stime = ((uint64_t)ct.tv_sec * 1000) +
3348                       ((uint64_t)ct.tv_usec / 1000);
3349         flow->etime = flow->stime;
3350     }
3351 
3352     /* copy private time field - reverse delta */
3353     flow->rdtime = rec.f.reverseFlowDeltaMilliseconds;
3354 
3355     /* copy addresses */
3356     if (rec.f.sourceIPv4Address || rec.f.destinationIPv4Address) {
3357         flow->key.version = 4;
3358         flow->key.addr.v4.sip = rec.f.sourceIPv4Address;
3359         flow->key.addr.v4.dip = rec.f.destinationIPv4Address;
3360     } else {
3361         flow->key.version = 6;
3362         memcpy(flow->key.addr.v6.sip, rec.f.sourceIPv6Address,
3363                sizeof(flow->key.addr.v6.sip));
3364         memcpy(flow->key.addr.v6.dip, rec.f.destinationIPv6Address,
3365                sizeof(flow->key.addr.v6.dip));
3366     }
3367 
3368     /* copy key and counters */
3369     flow->key.sp = rec.f.sourceTransportPort;
3370     flow->key.dp = rec.f.destinationTransportPort;
3371     flow->key.proto = rec.f.protocolIdentifier;
3372     flow->val.oct = rec.f.octetTotalCount;
3373     flow->val.pkt = rec.f.packetTotalCount;
3374     flow->rval.oct = rec.f.reverseOctetTotalCount;
3375     flow->rval.pkt = rec.f.reversePacketTotalCount;
3376     flow->key.vlanId = rec.f.vlanId;
3377     flow->val.vlan = rec.f.vlanId;
3378     flow->rval.vlan = rec.f.reverseVlanId;
3379     flow->reason = rec.f.flowEndReason;
3380     /* Handle delta counters */
3381     if (!(flow->val.oct)) {
3382         flow->val.oct = rec.f.octetDeltaCount;
3383         flow->rval.oct = rec.f.reverseOctetDeltaCount;
3384     }
3385     if (!(flow->val.pkt)) {
3386         flow->val.pkt = rec.f.packetDeltaCount;
3387         flow->rval.pkt = rec.f.reversePacketDeltaCount;
3388     }
3389 
3390 #if YAF_ENABLE_APPLABEL
3391     flow->appLabel = rec.f.silkAppLabel;
3392 #endif
3393 #if YAF_ENABLE_NDPI
3394     flow->ndpi_master = rec.f.ndpi_master;
3395     flow->ndpi_sub = rec.f.ndpi_sub;
3396 #endif
3397 
3398 #if YAF_ENABLE_ENTROPY
3399     flow->val.entropy = 0;
3400     flow->rval.entropy = 0;
3401 #endif
3402     flow->val.isn = rec.f.tcpSequenceNumber;
3403     flow->val.iflags = rec.f.initialTCPFlags;
3404     flow->val.uflags = rec.f.unionTCPFlags;
3405     flow->rval.isn = rec.f.reverseTcpSequenceNumber;
3406     flow->rval.iflags = rec.f.reverseInitialTCPFlags;
3407     flow->rval.uflags = rec.f.reverseUnionTCPFlags;
3408 
3409     while ((stml = FBSTMLNEXT(&(rec.f.subTemplateMultiList), stml)))
3410     {
3411         switch ((stml->tmplID & YTF_REV)) {
3412 #if YAF_ENABLE_ENTROPY
3413         case YAF_ENTROPY_FLOW_TID:
3414             entropyrec = (yfEntropyFlow_t *)fbSubTemplateMultiListEntryNextDataPtr(stml, entropyrec);
3415             flow->val.entropy = entropyrec->entropy;
3416             if ((stml->tmplID & YTF_BIF)) {
3417                 flow->rval.entropy = entropyrec->reverseEntropy;
3418             }
3419             break;
3420 #endif
3421         case YAF_TCP_FLOW_TID:
3422             tcprec = (yfTcpFlow_t *)fbSubTemplateMultiListEntryNextDataPtr(stml, tcprec);
3423             flow->val.isn = tcprec->tcpSequenceNumber;
3424             flow->val.iflags = tcprec->initialTCPFlags;
3425             flow->val.uflags = tcprec->unionTCPFlags;
3426             if ((stml->tmplID & YTF_BIF)) {
3427                 flow->rval.isn = tcprec->reverseTcpSequenceNumber;
3428                 flow->rval.iflags = tcprec->reverseInitialTCPFlags;
3429                 flow->rval.uflags = tcprec->reverseUnionTCPFlags;
3430             }
3431             break;
3432         case YAF_MAC_FLOW_TID:
3433             macrec = (yfMacFlow_t *)fbSubTemplateMultiListEntryNextDataPtr(stml, macrec);
3434             memcpy(flow->sourceMacAddr, macrec->sourceMacAddress,
3435                    ETHERNET_MAC_ADDR_LENGTH);
3436             memcpy(flow->destinationMacAddr, macrec->destinationMacAddress,
3437                    ETHERNET_MAC_ADDR_LENGTH);
3438             break;
3439 #if YAF_ENABLE_PAYLOAD
3440         case YAF_PAYLOAD_FLOW_TID:
3441             /* copy payload */
3442             payrec = (yfPayloadFlow_t *)fbSubTemplateMultiListEntryNextDataPtr(stml, payrec);
3443             yfPayloadCopyIn(&payrec->payload, &flow->val);
3444             if ((stml->tmplID & YTF_BIF)) {
3445                 yfPayloadCopyIn(&payrec->reversePayload, &flow->rval);
3446             }
3447             break;
3448 #   endif
3449         default:
3450             fbSubTemplateMultiListEntryNextDataPtr(stml, NULL);
3451             break;
3452         }
3453     }
3454 
3455     fbSubTemplateMultiListClear(&(rec.f.subTemplateMultiList));
3456 
3457     return TRUE;
3458 }
3459 
3460 /**
3461  *yfPrintFlags
3462  *
3463  *
3464  *
3465  */
yfPrintFlags(GString * str,uint8_t flags)3466 static void yfPrintFlags(
3467     GString             *str,
3468     uint8_t             flags)
3469 {
3470     if (flags & YF_TF_ECE) g_string_append_c(str, 'E');
3471     if (flags & YF_TF_CWR) g_string_append_c(str, 'C');
3472     if (flags & YF_TF_URG) g_string_append_c(str, 'U');
3473     if (flags & YF_TF_ACK) g_string_append_c(str, 'A');
3474     if (flags & YF_TF_PSH) g_string_append_c(str, 'P');
3475     if (flags & YF_TF_RST) g_string_append_c(str, 'R');
3476     if (flags & YF_TF_SYN) g_string_append_c(str, 'S');
3477     if (flags & YF_TF_FIN) g_string_append_c(str, 'F');
3478     if (!flags) g_string_append_c(str, '0');
3479 }
3480 
3481 /**
3482  *yfPrintString
3483  *
3484  *
3485  *
3486  */
yfPrintString(GString * rstr,yfFlow_t * flow)3487 void yfPrintString(
3488     GString             *rstr,
3489     yfFlow_t            *flow)
3490 {
3491     char                sabuf[AIR_IP6ADDR_BUF_MINSZ],
3492                         dabuf[AIR_IP6ADDR_BUF_MINSZ];
3493 
3494     /* print start as date and time */
3495     air_mstime_g_string_append(rstr, flow->stime, AIR_TIME_ISO8601);
3496 
3497     /* print end as time and duration if not zero-duration */
3498     if (flow->stime != flow->etime) {
3499         g_string_append_printf(rstr, " - ");
3500         air_mstime_g_string_append(rstr, flow->etime, AIR_TIME_ISO8601_HMS);
3501         g_string_append_printf(rstr, " (%.3f sec)",
3502             (flow->etime - flow->stime) / 1000.0);
3503     }
3504 
3505     /* print protocol and addresses */
3506     if (flow->key.version == 4) {
3507         air_ipaddr_buf_print(sabuf, flow->key.addr.v4.sip);
3508         air_ipaddr_buf_print(dabuf, flow->key.addr.v4.dip);
3509     } else if (flow->key.version == 6) {
3510         air_ip6addr_buf_print(sabuf, flow->key.addr.v6.sip);
3511         air_ip6addr_buf_print(dabuf, flow->key.addr.v6.dip);
3512     } else {
3513         sabuf[0] = (char)0;
3514         dabuf[0] = (char)0;
3515     }
3516 
3517     switch (flow->key.proto) {
3518     case YF_PROTO_TCP:
3519         if (flow->rval.oct) {
3520             g_string_append_printf(rstr, " tcp %s:%u => %s:%u %08x:%08x ",
3521                                    sabuf, flow->key.sp, dabuf, flow->key.dp,
3522                                    flow->val.isn, flow->rval.isn);
3523         } else {
3524             g_string_append_printf(rstr, " tcp %s:%u => %s:%u %08x ",
3525                                    sabuf, flow->key.sp, dabuf, flow->key.dp,
3526                                    flow->val.isn);
3527         }
3528 
3529         yfPrintFlags(rstr, flow->val.iflags);
3530         g_string_append_c(rstr,'/');
3531         yfPrintFlags(rstr, flow->val.uflags);
3532         if (flow->rval.oct) {
3533             g_string_append_c(rstr,':');
3534             yfPrintFlags(rstr, flow->rval.iflags);
3535             g_string_append_c(rstr,'/');
3536             yfPrintFlags(rstr, flow->rval.uflags);
3537         }
3538         break;
3539     case YF_PROTO_UDP:
3540         g_string_append_printf(rstr, " udp %s:%u => %s:%u",
3541                                sabuf, flow->key.sp, dabuf, flow->key.dp);
3542         break;
3543     case YF_PROTO_ICMP:
3544         g_string_append_printf(rstr, " icmp [%u:%u] %s => %s",
3545                                (flow->key.dp >> 8), (flow->key.dp & 0xFF),
3546                                sabuf, dabuf);
3547         break;
3548     case YF_PROTO_ICMP6:
3549         g_string_append_printf(rstr, " icmp6 [%u:%u] %s => %s",
3550                                (flow->key.dp >> 8), (flow->key.dp & 0xFF),
3551                                sabuf, dabuf);
3552         break;
3553     default:
3554         g_string_append_printf(rstr, " ip %u %s => %s",
3555                                flow->key.proto, sabuf, dabuf);
3556         break;
3557     }
3558 
3559 
3560     /* print vlan tags */
3561     if (flow->key.vlanId) {
3562         if (flow->rval.oct) {
3563             g_string_append_printf(rstr, " vlan %03hx:%03hx",
3564                 flow->val.vlan, flow->rval.vlan);
3565         } else {
3566             g_string_append_printf(rstr, " vlan %03hx",
3567                 flow->val.vlan);
3568         }
3569     }
3570 
3571     /* print flow counters and round-trip time */
3572     if (flow->rval.pkt) {
3573         g_string_append_printf(rstr, " (%llu/%llu <-> %llu/%llu) rtt %u ms",
3574                                (long long unsigned int)flow->val.pkt,
3575                                (long long unsigned int)flow->val.oct,
3576                                (long long unsigned int)flow->rval.pkt,
3577                                (long long unsigned int)flow->rval.oct,
3578                                flow->rdtime);
3579     } else {
3580         g_string_append_printf(rstr, " (%llu/%llu ->)",
3581                                (long long unsigned int)flow->val.pkt,
3582                                (long long unsigned int)flow->val.oct);
3583     }
3584 
3585     /* end reason flags */
3586     if ((flow->reason & YAF_END_MASK) == YAF_END_IDLE)
3587         g_string_append(rstr," idle");
3588     if ((flow->reason & YAF_END_MASK) == YAF_END_ACTIVE)
3589         g_string_append(rstr," active");
3590     if ((flow->reason & YAF_END_MASK) == YAF_END_FORCED)
3591         g_string_append(rstr," eof");
3592     if ((flow->reason & YAF_END_MASK) == YAF_END_RESOURCE)
3593         g_string_append(rstr," rsrc");
3594     if ((flow->reason & YAF_END_MASK) == YAF_END_UDPFORCE)
3595         g_string_append(rstr, " force");
3596 
3597     /* if app label is enabled, print the label */
3598 #   ifdef YAF_ENABLE_APPLABEL
3599     if (0 != flow->appLabel) {
3600         g_string_append_printf(rstr, " applabel: %u", flow->appLabel);
3601     }
3602 #   endif
3603 #   ifdef YAF_ENABLE_NDPI
3604     if (0 != flow->ndpi_master) {
3605         if (flow->ndpi_sub) {
3606             g_string_append_printf(rstr, " ndpi: %u[%u]", flow->ndpi_master, flow->ndpi_sub);
3607         } else {
3608             g_string_append_printf(rstr, " ndpi: %u", flow->ndpi_master);
3609         }
3610     }
3611 #   endif
3612 
3613     /* if entropy is enabled, print the entropy values */
3614 #   ifdef YAF_ENABLE_ENTROPY
3615     if (0 != flow->val.entropy || 0 != flow->rval.entropy) {
3616         g_string_append_printf(rstr, " entropy: %u rev entropy: %u",
3617             flow->val.entropy, flow->rval.entropy);
3618     }
3619 #   endif
3620 
3621     /* finish line */
3622     g_string_append(rstr,"\n");
3623 
3624     /* print payload if necessary */
3625 #   if YAF_ENABLE_PAYLOAD
3626     if (flow->val.payload) {
3627         air_hexdump_g_string_append(rstr, "  -> ",
3628             flow->val.payload, flow->val.paylen);
3629         g_free(flow->val.payload);
3630         flow->val.payload = NULL;
3631         flow->val.paylen = 0;
3632     }
3633     if (flow->rval.payload) {
3634         air_hexdump_g_string_append(rstr, " <-  ",
3635             flow->rval.payload, flow->rval.paylen);
3636         g_free(flow->rval.payload);
3637         flow->rval.payload = NULL;
3638         flow->rval.paylen = 0;
3639 
3640     }
3641 #   endif
3642 }
3643 
3644 /**
3645  *yfPrintDelimitedString
3646  *
3647  *
3648  *
3649  */
yfPrintDelimitedString(GString * rstr,yfFlow_t * flow,gboolean yaft_mac)3650 void yfPrintDelimitedString(
3651     GString                 *rstr,
3652     yfFlow_t                *flow,
3653     gboolean                yaft_mac)
3654 {
3655     char                sabuf[AIR_IP6ADDR_BUF_MINSZ],
3656                         dabuf[AIR_IP6ADDR_BUF_MINSZ];
3657     GString             *fstr = NULL;
3658     int                 loop = 0;
3659     unsigned short      rvlan = 0;
3660 
3661     /* print time and duration */
3662     air_mstime_g_string_append(rstr, flow->stime, AIR_TIME_ISO8601);
3663     g_string_append_printf(rstr, "%s", YF_PRINT_DELIM);
3664     air_mstime_g_string_append(rstr, flow->etime, AIR_TIME_ISO8601);
3665     g_string_append_printf(rstr, "%s%8.3f%s",
3666         YF_PRINT_DELIM, (flow->etime - flow->stime) / 1000.0, YF_PRINT_DELIM);
3667 
3668     /* print initial RTT */
3669     g_string_append_printf(rstr, "%8.3f%s",
3670         flow->rdtime / 1000.0, YF_PRINT_DELIM);
3671 
3672     /* print five tuple */
3673     if (flow->key.version == 4) {
3674         air_ipaddr_buf_print(sabuf, flow->key.addr.v4.sip);
3675         air_ipaddr_buf_print(dabuf, flow->key.addr.v4.dip);
3676     } else if (flow->key.version == 6) {
3677         air_ip6addr_buf_print(sabuf, flow->key.addr.v6.sip);
3678         air_ip6addr_buf_print(dabuf, flow->key.addr.v6.dip);
3679     } else {
3680         sabuf[0] = (char)0;
3681         dabuf[0] = (char)0;
3682 
3683     }
3684     g_string_append_printf(rstr, "%3u%s%40s%s%5u%s%40s%s%5u%s",
3685         flow->key.proto, YF_PRINT_DELIM,
3686         sabuf, YF_PRINT_DELIM, flow->key.sp, YF_PRINT_DELIM,
3687         dabuf, YF_PRINT_DELIM, flow->key.dp, YF_PRINT_DELIM);
3688 
3689     if (yaft_mac) {
3690         for (loop = 0; loop < 6; loop++) {
3691             g_string_append_printf(rstr, "%02x", flow->sourceMacAddr[loop]);
3692             if (loop < 5) {
3693                 g_string_append_printf(rstr, ":");
3694             }
3695             /* clear out mac addr for next flow */
3696             flow->sourceMacAddr[loop] = 0;
3697         }
3698         g_string_append_printf(rstr, "%s", YF_PRINT_DELIM);
3699         for(loop =0; loop< 6; loop++) {
3700             g_string_append_printf(rstr, "%02x", flow->destinationMacAddr[loop]);
3701             if (loop < 5) {
3702                 g_string_append_printf(rstr, ":");
3703             }
3704             /* clear out mac addr for next flow */
3705             flow->destinationMacAddr[loop] = 0;
3706         }
3707         g_string_append_printf(rstr, "%s", YF_PRINT_DELIM);
3708     }
3709 
3710     /* print tcp flags */
3711     fstr = g_string_new("");
3712     yfPrintFlags(fstr, flow->val.iflags);
3713     g_string_append_printf(rstr, "%8s%s", fstr->str, YF_PRINT_DELIM);
3714     g_string_truncate(fstr, 0);
3715     yfPrintFlags(fstr, flow->val.uflags);
3716     g_string_append_printf(rstr, "%8s%s", fstr->str, YF_PRINT_DELIM);
3717     g_string_truncate(fstr, 0);
3718     yfPrintFlags(fstr, flow->rval.iflags);
3719     g_string_append_printf(rstr, "%8s%s", fstr->str, YF_PRINT_DELIM);
3720     g_string_truncate(fstr, 0);
3721     yfPrintFlags(fstr, flow->rval.uflags);
3722     g_string_append_printf(rstr, "%8s%s", fstr->str, YF_PRINT_DELIM);
3723     g_string_free(fstr, TRUE);
3724 
3725     /* print tcp sequence numbers */
3726     g_string_append_printf(rstr, "%08x%s%08x%s", flow->val.isn, YF_PRINT_DELIM,
3727                            flow->rval.isn, YF_PRINT_DELIM);
3728 
3729     /* print vlan tags */
3730     if (flow->rval.oct) {
3731         g_string_append_printf(rstr, "%03hx%s%03hx%s", flow->val.vlan,
3732                                YF_PRINT_DELIM, flow->rval.vlan,
3733                                YF_PRINT_DELIM);
3734     } else {
3735         g_string_append_printf(rstr, "%03hx%s%03hx%s", flow->key.vlanId,
3736                                YF_PRINT_DELIM, rvlan, YF_PRINT_DELIM);
3737     }
3738 
3739 
3740     /* print flow counters */
3741     g_string_append_printf(rstr, "%8llu%s%8llu%s%8llu%s%8llu%s",
3742         (long long unsigned int)flow->val.pkt, YF_PRINT_DELIM,
3743         (long long unsigned int)flow->val.oct, YF_PRINT_DELIM,
3744         (long long unsigned int)flow->rval.pkt, YF_PRINT_DELIM,
3745         (long long unsigned int)flow->rval.oct, YF_PRINT_DELIM);
3746 
3747     /* if app label is enabled, print the label */
3748 #   ifdef YAF_ENABLE_APPLABEL
3749     g_string_append_printf(rstr, "%5u%s", flow->appLabel, YF_PRINT_DELIM);
3750 #   endif
3751 
3752     /* if entropy is enabled, print the entropy values */
3753 #   ifdef YAF_ENABLE_ENTROPY
3754     g_string_append_printf(rstr, "%3u%s%3u%s",
3755                            flow->val.entropy, YF_PRINT_DELIM,
3756                            flow->rval.entropy, YF_PRINT_DELIM);
3757 #   endif
3758 
3759 
3760     /* end reason flags */
3761     if ((flow->reason & YAF_END_MASK) == YAF_END_IDLE)
3762         g_string_append(rstr,"idle ");
3763     if ((flow->reason & YAF_END_MASK) == YAF_END_ACTIVE)
3764         g_string_append(rstr,"active ");
3765     if ((flow->reason & YAF_END_MASK) == YAF_END_FORCED)
3766         g_string_append(rstr,"eof ");
3767     if ((flow->reason & YAF_END_MASK) == YAF_END_RESOURCE)
3768         g_string_append(rstr,"rsrc ");
3769     if ((flow->reason & YAF_END_MASK) == YAF_END_UDPFORCE)
3770         g_string_append(rstr, "force ");
3771 
3772 
3773     /* finish line */
3774     g_string_append(rstr,"\n");
3775 
3776     /* not printing payload - but need to free */
3777 #   if YAF_ENABLE_PAYLOAD
3778     if (flow->val.payload) {
3779         g_free(flow->val.payload);
3780         flow->val.payload = NULL;
3781         flow->val.paylen = 0;
3782     }
3783     if (flow->rval.payload) {
3784         g_free(flow->rval.payload);
3785         flow->rval.payload = NULL;
3786         flow->rval.paylen = 0;
3787     }
3788 #   endif
3789 
3790 }
3791 
3792 /**
3793  *yfPrint
3794  *
3795  *
3796  *
3797  */
yfPrint(FILE * out,yfFlow_t * flow,GError ** err)3798 gboolean yfPrint(
3799     FILE                *out,
3800     yfFlow_t            *flow,
3801     GError              **err)
3802 {
3803     GString             *rstr = NULL;
3804     int                 rc = 0;
3805 
3806     rstr = g_string_new("");
3807 
3808     yfPrintString(rstr, flow);
3809 
3810     rc = fwrite(rstr->str, rstr->len, 1, out);
3811 
3812     if (rc != 1) {
3813         g_set_error(err, YAF_ERROR_DOMAIN, YAF_ERROR_IO,
3814                     "error printing flow: %s", strerror(errno));
3815     }
3816 
3817     g_string_free(rstr, TRUE);
3818 
3819     return (rc == 1);
3820 
3821 }
3822 
3823 /**
3824  *yfPrintDelimited
3825  *
3826  *
3827  *
3828  */
yfPrintDelimited(FILE * out,yfFlow_t * flow,gboolean yaft_mac,GError ** err)3829 gboolean yfPrintDelimited(
3830     FILE                *out,
3831     yfFlow_t            *flow,
3832     gboolean            yaft_mac,
3833     GError              **err)
3834 {
3835     GString             *rstr = NULL;
3836     int                 rc = 0;
3837 
3838     rstr = g_string_new("");
3839 
3840     yfPrintDelimitedString(rstr, flow, yaft_mac);
3841 
3842     rc = fwrite(rstr->str, rstr->len, 1, out);
3843 
3844     if (rc != 1) {
3845         g_set_error(err, YAF_ERROR_DOMAIN, YAF_ERROR_IO,
3846                     "error printing delimited flow: %s", strerror(errno));
3847     }
3848 
3849     g_string_free(rstr, TRUE);
3850 
3851     return (rc == 1);
3852 
3853 }
3854 
3855 /**
3856  * yfPrintColumnHeaders
3857  *
3858  *
3859  */
yfPrintColumnHeaders(FILE * out,gboolean yaft_mac,GError ** err)3860 void yfPrintColumnHeaders(
3861     FILE           *out,
3862     gboolean       yaft_mac,
3863     GError         **err)
3864 {
3865 
3866     GString        *rstr = NULL;
3867 
3868     rstr = g_string_new("");
3869 
3870     g_string_append_printf(rstr, "start-time%14s", YF_PRINT_DELIM);
3871     g_string_append_printf(rstr, "end-time%16s", YF_PRINT_DELIM);
3872     g_string_append_printf(rstr, "duration%s", YF_PRINT_DELIM);
3873     g_string_append_printf(rstr, "rtt%6s", YF_PRINT_DELIM);
3874     g_string_append_printf(rstr, "proto%s", YF_PRINT_DELIM);
3875     g_string_append_printf(rstr, "sip%36s", YF_PRINT_DELIM);
3876     g_string_append_printf(rstr, "sp%4s", YF_PRINT_DELIM);
3877     g_string_append_printf(rstr, "dip%38s", YF_PRINT_DELIM);
3878     g_string_append_printf(rstr, "dp%4s", YF_PRINT_DELIM);
3879     if (yaft_mac) {
3880         g_string_append_printf(rstr, "srcMacAddress%5s", YF_PRINT_DELIM);
3881         g_string_append_printf(rstr, "destMacAddress%4s", YF_PRINT_DELIM);
3882     }
3883     g_string_append_printf(rstr, "iflags%3s", YF_PRINT_DELIM);
3884     g_string_append_printf(rstr, "uflags%3s", YF_PRINT_DELIM);
3885     g_string_append_printf(rstr, "riflags%2s", YF_PRINT_DELIM);
3886     g_string_append_printf(rstr, "ruflags%2s", YF_PRINT_DELIM);
3887     g_string_append_printf(rstr, "isn%6s", YF_PRINT_DELIM);
3888     g_string_append_printf(rstr, "risn%5s", YF_PRINT_DELIM);
3889     g_string_append_printf(rstr, "tag%s", YF_PRINT_DELIM);
3890     g_string_append_printf(rstr, "rtag%s", YF_PRINT_DELIM);
3891     g_string_append_printf(rstr, "pkt%5s", YF_PRINT_DELIM);
3892     g_string_append_printf(rstr, "oct%6s", YF_PRINT_DELIM);
3893     g_string_append_printf(rstr, "rpkt%5s", YF_PRINT_DELIM);
3894     g_string_append_printf(rstr, "roct%5s", YF_PRINT_DELIM);
3895 
3896 #if YAF_ENABLE_APPLABEL
3897     g_string_append_printf(rstr, "app%3s", YF_PRINT_DELIM);
3898 #endif
3899 #if YAF_ENABLE_ENTROPY
3900     g_string_append_printf(rstr, "entropy%s", YF_PRINT_DELIM);
3901     g_string_append_printf(rstr, "rentropy%s", YF_PRINT_DELIM);
3902 #endif
3903 
3904     g_string_append_printf(rstr, "end-reason");
3905     g_string_append(rstr,"\n");
3906 
3907     fwrite(rstr->str, rstr->len, 1, out);
3908 
3909     g_string_free(rstr, TRUE);
3910 
3911 }
3912