1 /*
2 ** Copyright (C) 2005-2020 by Carnegie Mellon University.
3 **
4 ** @OPENSOURCE_LICENSE_START@
5 ** See license information in ../../LICENSE.txt
6 ** @OPENSOURCE_LICENSE_END@
7 */
8 
9 /*
10 **  Support file for probeconf.c
11 **
12 */
13 
14 #include <silk/silk.h>
15 
16 RCSIDENT("$SiLK: packlogic-generic.c ef14e54179be 2020-04-14 21:57:45Z mthomas $");
17 
18 #include <silk/rwflowpack.h>
19 #include <silk/rwrec.h>
20 #include <silk/silk_files.h>
21 #include <silk/sksite.h>
22 #include <silk/skvector.h>
23 #include <silk/utils.h>
24 
25 
26 /* TYPEDEFS AND MACROS */
27 
28 /*
29  *    Define integers to stand-in for each of the possible flowtypes
30  *    that are defined in the silk.conf file.  These must match.
31  */
32 #define RW_IN       0
33 #define RW_OUT      1
34 #define RW_IN_WEB   2
35 #define RW_OUT_WEB  3
36 #define RW_IN_NULL  4
37 #define RW_OUT_NULL 5
38 
39 
40 /*
41  *    These are the IDs of the networks that should be defined in the
42  *    sensor.conf file.  We are in trouble if someone redefines these
43  *    values.
44  */
45 #define NUM_NETWORKS        3
46 
47 #define NETWORK_NULL        ((skpc_network_id_t)0)
48 /* The SNMP interface on the probe to which non-routed traffic is
49  * sent.  This is 0 on Cisco routers. */
50 
51 #define NETWORK_EXTERNAL    ((skpc_network_id_t)1)
52 /* A bitmap where an ON bit represents an SNMP interface on the
53  * probe that faces the external world.  Traffic entering the
54  * router on this interface will be considered incoming. */
55 
56 #define NETWORK_INTERNAL    ((skpc_network_id_t)2)
57 /* A bitmap where an ON bit represents an SNMP interface on the
58  * probe that faces the internal world.  Traffic entering the
59  * router on this interface will be considered outgoing. */
60 
61 
62 /* LOCAL VARIABLES */
63 
64 /* the names that correspond to each network */
65 static const char *net_names[NUM_NETWORKS] = {
66     "null",
67     "external",
68     "internal"
69 };
70 
71 /*
72  *    Define the file formats used to pack each flowtype.  If these do
73  *    not line up with the type IDs defined in the config file, there
74  *    will be problems.  Use the more compact formats for flows from
75  *    NetFlow v5 based sources, and the expanded formats for flows
76  *    from other sources.
77  */
78 static struct filetypeFormats_st {
79     sk_file_format_t    netflow_v5;
80     sk_file_format_t    other;
81 } filetypeFormats[] = {
82     /* in      */  {FT_RWSPLIT, FT_RWAUGMENTED},
83     /* out     */  {FT_RWSPLIT, FT_RWAUGMENTED},
84     /* inweb   */  {FT_RWWWW,   FT_RWAUGWEB},
85     /* outweb  */  {FT_RWWWW,   FT_RWAUGWEB},
86     /* innull  */  {FT_RWSPLIT, FT_RWAUGMENTED},
87     /* outnull */  {FT_RWSPLIT, FT_RWAUGMENTED}
88 };
89 
90 
91 static const char plugin_source[] = __FILE__;
92 static const char *plugin_path = plugin_source;
93 
94 
95 /* LOCAL FUNCTION PROTOTYPES */
96 
97 static int  packLogicSetup(void);
98 static void packLogicTeardown(void);
99 static int  packLogicVerifySensor(skpc_sensor_t *sensor);
100 static int
101 packLogicDetermineFlowtype(
102     const skpc_probe_t *probe,
103     const rwRec        *rwrec,
104     sk_flowtype_id_t   *ftypes,
105     sk_sensor_id_t     *sensorids);
106 static sk_file_format_t
107 packLogicDetermineFileFormat(
108     const skpc_probe_t *probe,
109     sk_flowtype_id_t    ftype);
110 
111 
112 /* FUNCTION DEFINITIONS */
113 
114 /*
115  *    Fill in 'packlogic' with pointers to the functions defined in
116  *    this file.
117  */
118 int
packLogicInitialize(packlogic_plugin_t * packlogic)119 packLogicInitialize(
120     packlogic_plugin_t *packlogic)
121 {
122     assert(packlogic);
123 
124     if (packlogic->path) {
125         plugin_path = packlogic->path;
126     }
127 
128     packlogic->setup_fn =                &packLogicSetup;
129     packlogic->teardown_fn =             &packLogicTeardown;
130     packlogic->verify_sensor_fn =        &packLogicVerifySensor;
131     packlogic->determine_flowtype_fn =   &packLogicDetermineFlowtype;
132     packlogic->determine_fileformat_fn = &packLogicDetermineFileFormat;
133     return 0;
134 }
135 
136 
137 /*
138  *    Verify contents of silk.conf file matches the values we set here
139  *    and set any globals we require.
140  *
141  *    Invoked from rwflowpack by packlogic->setup_fn
142  */
143 static int
packLogicSetup(void)144 packLogicSetup(
145     void)
146 {
147     const size_t count = (sizeof(filetypeFormats)/sizeof(filetypeFormats[0]));
148     uint32_t i;
149 
150 #define FT_ASSERT(flowtype_id, flowtype_name)                           \
151     sksiteFlowtypeAssert(plugin_path, (flowtype_id), "all", (flowtype_name))
152 
153     /* Make sure flowtype definitions match config file */
154     FT_ASSERT(RW_IN,       "in");
155     FT_ASSERT(RW_OUT,      "out");
156     FT_ASSERT(RW_IN_WEB,   "inweb");
157     FT_ASSERT(RW_OUT_WEB,  "outweb");
158     FT_ASSERT(RW_IN_NULL,  "innull");
159     FT_ASSERT(RW_OUT_NULL, "outnull");
160 
161     /* Confirm that number of flowtypes is not greater than the size
162      * of the filetypeFormats[] array; abort if it is.  Complain if
163      * the array is too large, but continue processing.  */
164     if (count <= sksiteFlowtypeGetMaxID()) {
165         skAppPrintErr(("File formats not specified for some flowtypes.\n"
166                        "\tModify filetypeFormats[] in %s,\n"
167                        "\trecompile and try running again."),
168                       plugin_path);
169         skAbort();
170     } else if (count != (1u + sksiteFlowtypeGetMaxID())) {
171         skAppPrintErr(("Warning: Number of flowtypes does not equal number\n"
172                        "\tof file formats in filetypeFormats[] in %s"),
173                       plugin_path);
174     }
175 
176     /* Define all of our networks */
177     for (i = 0; i < NUM_NETWORKS; ++i) {
178         if (skpcNetworkAdd(i, net_names[i])) {
179             skAppPrintErr("Unable to add network %" PRIu32 "->%s",
180                           i, net_names[i]);
181             return -1;
182         }
183     }
184 
185     return 0;
186 }
187 
188 
189 /*
190  *    Clean up any memory we allocated.
191  *
192  *    Invoked from rwflowpack by packlogic->teardown_fn
193  */
194 static void
packLogicTeardown(void)195 packLogicTeardown(
196     void)
197 {
198     return;
199 }
200 
201 
202 /*
203  *    Verify sensor by its class.  Verify that the sensor supports the
204  *    type(s) of its probe(s).  Verify that enough information is
205  *    present on the sensor to categorize a flow record.
206  *
207  *    Invoked from rwflowpack by packlogic->verify_sensor_fn
208  */
209 static int
packLogicVerifySensor(skpc_sensor_t * sensor)210 packLogicVerifySensor(
211     skpc_sensor_t      *sensor)
212 {
213     skpc_probe_t *probe;
214     sk_vector_t *probe_vec;
215     uint32_t count;
216 
217     /* There is a single class, so no per-class verification is
218      * necessary.  Make certain we have either snmp interface values
219      * or ip-blocks depending on the type of probe(s) associated with
220      * this sensor. */
221 
222     /* get the probes for the sensor */
223     probe_vec = skVectorNew(sizeof(skpc_probe_t*));
224     if (probe_vec == NULL) {
225         return -1;
226     }
227     count = skpcSensorGetProbes(sensor, probe_vec);
228 
229     /* this packing logic only supports a single probe per sensor */
230     if (count != 1) {
231         skAppPrintErr(("Cannot verify sensor '%s':\n"
232                        "\tOnly one probe per sensor is supported"
233                        " by the packing-logic\n\tfile '%s'"),
234                       sensor->sensor_name,
235                       plugin_path);
236         skVectorDestroy(probe_vec);
237         return -1;
238     }
239     skVectorGetValue(&probe, probe_vec, 0);
240     skVectorDestroy(probe_vec);
241 
242     /* make certain the probe's type is valid */
243     switch (probe->probe_type) {
244       case PROBE_ENUM_NETFLOW_V5:
245       case PROBE_ENUM_NETFLOW_V9:
246       case PROBE_ENUM_IPFIX:
247         /* expected probe types */
248         break;
249 
250       default:
251         assert(skpcProbetypeEnumtoName(probe->probe_type));
252         skAppPrintErr(("Cannot verify sensor '%s':\n"
253                        "\tThe probe type '%s' is not supported in the"
254                        " packing-logic\n\tfile '%s'"),
255                       sensor->sensor_name,
256                       skpcProbetypeEnumtoName(probe->probe_type),
257                       plugin_path);
258         return -1;
259     }
260 
261 
262     /* Verify that we have enough information to determine the
263      * flowtype for every flow.  These are the rules:
264      *
265      * 1. One of external-interface, external-ipblock, or
266      * external-ipset must be specified.
267      *
268      * 2. You cannot mix interfaces, ipblocks, and ipsets, with the
269      * excption that a null-interface which is always allowed.
270      *
271      * 3. Only one network may claim the remainder.
272      *
273      * 4. Using remainder for an ipblock or ipset requires that
274      * another interface has set an IPblock or an IPset.
275      */
276     switch (sensor->decider[NETWORK_EXTERNAL].nd_type) {
277       case SKPC_UNSET:
278         /* It is an error when neither SNMP interfaces nor IP-blocks
279          * were specified for the external network. */
280         skAppPrintErr(("Cannot verify sensor '%s':\n"
281                        "\tMust specify %s-interface, %s-ipblock, or %s-ipset"),
282                       sensor->sensor_name,
283                       net_names[NETWORK_EXTERNAL],
284                       net_names[NETWORK_EXTERNAL],
285                       net_names[NETWORK_EXTERNAL]);
286         return -1;
287 
288       case SKPC_NEG_IPBLOCK:
289         skAppPrintErr("Negated IPblock logic not implemented");
290         exit(EXIT_FAILURE);
291       case SKPC_NEG_IPSET:
292         skAppPrintErr("Negated IPset logic not implemented");
293         exit(EXIT_FAILURE);
294 
295       case SKPC_IPBLOCK:
296         /* Fine as long as INTERNAL is either empty or also contains
297          * IPblocks */
298         switch (sensor->decider[NETWORK_INTERNAL].nd_type) {
299           case SKPC_UNSET:
300           case SKPC_IPBLOCK:
301           case SKPC_REMAIN_IPBLOCK:
302             /* These are fine */
303             break;
304 
305           case SKPC_NEG_IPBLOCK:
306             skAppPrintErr("Negated IPblock logic not implemented");
307             exit(EXIT_FAILURE);
308           case SKPC_NEG_IPSET:
309             skAppPrintErr("Negated IPset logic not implemented");
310             exit(EXIT_FAILURE);
311 
312           case SKPC_INTERFACE:
313           case SKPC_REMAIN_INTERFACE:
314             /* Bad mix */
315             skAppPrintErr(("Cannot verify sensor '%s':\n"
316                            "\tCannot mix %s-ipblock and %s-interface"),
317                           sensor->sensor_name,
318                           net_names[NETWORK_EXTERNAL],
319                           net_names[NETWORK_INTERNAL]);
320             return -1;
321 
322           case SKPC_IPSET:
323           case SKPC_REMAIN_IPSET:
324             /* Bad mix */
325             skAppPrintErr(("Cannot verify sensor '%s':\n"
326                            "\tCannot mix %s-ipblock and %s-ipset"),
327                           sensor->sensor_name,
328                           net_names[NETWORK_EXTERNAL],
329                           net_names[NETWORK_INTERNAL]);
330             return -1;
331         }
332         break;
333 
334       case SKPC_REMAIN_IPBLOCK:
335         switch (sensor->decider[NETWORK_INTERNAL].nd_type) {
336           case SKPC_UNSET:
337             /* Accept for now, though this will be an error if
338              * NETWORK_NULL does not define an IPblock */
339             break;
340 
341           case SKPC_NEG_IPBLOCK:
342             skAppPrintErr("Negated IPblock logic not implemented");
343             exit(EXIT_FAILURE);
344           case SKPC_NEG_IPSET:
345             skAppPrintErr("Negated IPset logic not implemented");
346             exit(EXIT_FAILURE);
347 
348           case SKPC_REMAIN_IPBLOCK:
349             /* Cannot have multiple things requesting "remainder" */
350             skAppPrintErr(("Cannot verify sensor '%s':\n"
351                            "\tOnly one network value may use 'remainder'"),
352                           sensor->sensor_name);
353             return -1;
354 
355           case SKPC_IPBLOCK:
356             /* This is fine */
357             break;
358 
359           case SKPC_INTERFACE:
360           case SKPC_REMAIN_INTERFACE:
361             /* Bad mix */
362             skAppPrintErr(("Cannot verify sensor '%s':\n"
363                            "\tCannot mix %s-ipblock and %s-interface"),
364                           sensor->sensor_name,
365                           net_names[NETWORK_EXTERNAL],
366                           net_names[NETWORK_INTERNAL]);
367             return -1;
368 
369           case SKPC_IPSET:
370           case SKPC_REMAIN_IPSET:
371             /* Bad mix */
372             skAppPrintErr(("Cannot verify sensor '%s':\n"
373                            "\tCannot mix %s-ipblock and %s-ipset"),
374                           sensor->sensor_name,
375                           net_names[NETWORK_EXTERNAL],
376                           net_names[NETWORK_INTERNAL]);
377             return -1;
378         }
379         break;
380 
381       case SKPC_INTERFACE:
382       case SKPC_REMAIN_INTERFACE:
383         /* Fine as long as INTERNAL and NULL are either empty or also
384          * contain interfaces */
385         switch (sensor->decider[NETWORK_INTERNAL].nd_type) {
386           case SKPC_UNSET:
387           case SKPC_INTERFACE:
388           case SKPC_REMAIN_INTERFACE:
389             switch (sensor->decider[NETWORK_NULL].nd_type) {
390               case SKPC_IPBLOCK:
391               case SKPC_NEG_IPBLOCK:
392               case SKPC_REMAIN_IPBLOCK:
393                 /* Bad mix */
394                 skAppPrintErr(("Cannot verify sensor '%s':\n"
395                                "\tCannot mix %s-interface and %s-ipblock"),
396                               sensor->sensor_name,
397                               net_names[NETWORK_EXTERNAL],
398                               net_names[NETWORK_NULL]);
399                 return -1;
400               case SKPC_IPSET:
401               case SKPC_NEG_IPSET:
402               case SKPC_REMAIN_IPSET:
403                 /* Bad mix */
404                 skAppPrintErr(("Cannot verify sensor '%s':\n"
405                                "\tCannot mix %s-interface and %s-ipset"),
406                               sensor->sensor_name,
407                               net_names[NETWORK_EXTERNAL],
408                               net_names[NETWORK_NULL]);
409                 return -1;
410               default:
411                 break;
412             }
413             break;
414 
415           case SKPC_IPBLOCK:
416           case SKPC_NEG_IPBLOCK:
417           case SKPC_REMAIN_IPBLOCK:
418             /* Bad mix */
419             skAppPrintErr(("Cannot verify sensor '%s':\n"
420                            "\tCannot mix %s-interface and %s-ipblock"),
421                           sensor->sensor_name,
422                           net_names[NETWORK_EXTERNAL],
423                           net_names[NETWORK_INTERNAL]);
424             return -1;
425 
426           case SKPC_IPSET:
427           case SKPC_NEG_IPSET:
428           case SKPC_REMAIN_IPSET:
429             /* Bad mix */
430             skAppPrintErr(("Cannot verify sensor '%s':\n"
431                            "\tCannot mix %s-interface and %s-ipset"),
432                           sensor->sensor_name,
433                           net_names[NETWORK_EXTERNAL],
434                           net_names[NETWORK_INTERNAL]);
435             return -1;
436         }
437         break;
438 
439       case SKPC_IPSET:
440         /* Fine as long as INTERNAL is either empty or also contains
441          * IPsets */
442         switch (sensor->decider[NETWORK_INTERNAL].nd_type) {
443           case SKPC_UNSET:
444           case SKPC_IPSET:
445           case SKPC_REMAIN_IPSET:
446             /* These are fine */
447             break;
448 
449           case SKPC_NEG_IPSET:
450             skAppPrintErr("Negated IPset logic not implemented");
451             exit(EXIT_FAILURE);
452           case SKPC_NEG_IPBLOCK:
453             skAppPrintErr("Negated IPblock logic not implemented");
454             exit(EXIT_FAILURE);
455 
456           case SKPC_INTERFACE:
457           case SKPC_REMAIN_INTERFACE:
458             /* Bad mix */
459             skAppPrintErr(("Cannot verify sensor '%s':\n"
460                            "\tCannot mix %s-ipset and %s-interface"),
461                           sensor->sensor_name,
462                           net_names[NETWORK_EXTERNAL],
463                           net_names[NETWORK_INTERNAL]);
464             return -1;
465 
466           case SKPC_IPBLOCK:
467           case SKPC_REMAIN_IPBLOCK:
468             /* Bad mix */
469             skAppPrintErr(("Cannot verify sensor '%s':\n"
470                            "\tCannot mix %s-ipset and %s-ipblock"),
471                           sensor->sensor_name,
472                           net_names[NETWORK_EXTERNAL],
473                           net_names[NETWORK_INTERNAL]);
474             return -1;
475         }
476         break;
477 
478       case SKPC_REMAIN_IPSET:
479         switch (sensor->decider[NETWORK_INTERNAL].nd_type) {
480           case SKPC_UNSET:
481             /* Accept for now, though this will be an error if
482              * NETWORK_NULL does not define an IPset */
483             break;
484 
485           case SKPC_NEG_IPSET:
486             skAppPrintErr("Negated IPset logic not implemented");
487             exit(EXIT_FAILURE);
488           case SKPC_NEG_IPBLOCK:
489             skAppPrintErr("Negated IPblock logic not implemented");
490             exit(EXIT_FAILURE);
491 
492           case SKPC_REMAIN_IPSET:
493             /* Cannot have multiple things requesting "remainder" */
494             skAppPrintErr(("Cannot verify sensor '%s':\n"
495                            "\tOnly one network value may use 'remainder'"),
496                           sensor->sensor_name);
497             return -1;
498 
499           case SKPC_IPSET:
500             /* This is fine */
501             break;
502 
503           case SKPC_INTERFACE:
504           case SKPC_REMAIN_INTERFACE:
505             /* Bad mix */
506             skAppPrintErr(("Cannot verify sensor '%s':\n"
507                            "\tCannot mix %s-ipset and %s-interface"),
508                           sensor->sensor_name,
509                           net_names[NETWORK_EXTERNAL],
510                           net_names[NETWORK_INTERNAL]);
511             return -1;
512 
513           case SKPC_IPBLOCK:
514           case SKPC_REMAIN_IPBLOCK:
515             /* Bad mix */
516             skAppPrintErr(("Cannot verify sensor '%s':\n"
517                            "\tCannot mix %s-ipset and %s-ipblock"),
518                           sensor->sensor_name,
519                           net_names[NETWORK_EXTERNAL],
520                           net_names[NETWORK_INTERNAL]);
521             return -1;
522         }
523         break;
524     }
525 
526     return 0;
527 }
528 
529 
530 /*
531  *  count = packLogicDetermineFlowtype(probe, &rwrec, ftypes[], sensorids[]);
532  *
533  *    Fill the 'ftypes' and 'sensorids' arrays with the list of
534  *    flow_types and sensors to which the 'rwrec' probe, collected
535  *    from the 'probe' sensor, should be packed.  Return the number of
536  *    elements added to each array or -1 on error.
537  *
538  *    Invoked from rwflowpack by packlogic->determine_flowtype_fn
539  */
540 static int
packLogicDetermineFlowtype(const skpc_probe_t * probe,const rwRec * rwrec,sk_flowtype_id_t * ftypes,sk_sensor_id_t * sensorids)541 packLogicDetermineFlowtype(
542     const skpc_probe_t *probe,
543     const rwRec        *rwrec,
544     sk_flowtype_id_t   *ftypes,
545     sk_sensor_id_t     *sensorids)
546 {
547     skpc_sensor_t *sensor;
548     uint16_t memo;
549 
550     /* index into output arrays and count to be returned */
551     size_t sensor_count;
552 
553     assert(ftypes);
554     assert(sensorids);
555 
556     memo = rwRecGetMemo(rwrec);
557 
558     /* loop over all sensors that use the 'probe' */
559     for (sensor_count = 0; sensor_count < probe->sensor_count; ++sensor_count) {
560         sensor = probe->sensor_list[sensor_count];
561         sensorids[sensor_count] = sensor->sensor_id;
562 
563         if (1 == skpcSensorTestFlowInterfaces(sensor, rwrec,
564                                               NETWORK_EXTERNAL, SKPC_DIR_SRC))
565         {
566             /* Flow came from the outside */
567 
568             if (1 == skpcSensorTestFlowInterfaces(sensor, rwrec,
569                                                   NETWORK_NULL, SKPC_DIR_DST))
570             {
571                 /* Flow went to the null destination */
572                 ftypes[sensor_count] = RW_IN_NULL;
573             } else {
574                 /* Assume flow went to the inside: incoming */
575                 if (rwRecIsWeb(rwrec)) {
576                     ftypes[sensor_count] = RW_IN_WEB;
577                 } else {
578                     ftypes[sensor_count] = RW_IN;
579                 }
580             }
581         } else {
582             /* Flow came from the inside */
583 
584             if (1 == skpcSensorTestFlowInterfaces(sensor, rwrec,
585                                                   NETWORK_NULL, SKPC_DIR_DST))
586             {
587                 /* Flow went to the null destination */
588                 ftypes[sensor_count] = RW_OUT_NULL;
589             } else {
590 
591                 /* Assume flow went to the outside: outgoing */
592                 if (rwRecIsWeb(rwrec)) {
593                     ftypes[sensor_count] = RW_OUT_WEB;
594                 } else {
595                     ftypes[sensor_count] = RW_OUT;
596                 }
597             }
598         }
599 
600         if (skpcProbeGetQuirks(probe) & SKPC_QUIRK_FW_EVENT) {
601             /* Check whether libskipfix stored a "flow denied"
602              * firewallEvent, NF_F_FW_EVENT, or NF_F_FW_EXT_EVENT.  If so,
603              * make certain flowtype is NULL */
604             switch (memo) {
605               case 0:
606                 break;
607               case SKIPFIX_FW_EVENT_DENIED_INGRESS:
608                 ftypes[sensor_count] = RW_IN_NULL;
609                 break;
610               case SKIPFIX_FW_EVENT_DENIED_EGRESS:
611                 ftypes[sensor_count] = RW_OUT_NULL;
612                 break;
613               case SKIPFIX_FW_EVENT_DENIED:
614               case SKIPFIX_FW_EVENT_DENIED_SERV_PORT:
615               case SKIPFIX_FW_EVENT_DENIED_NOT_SYN:
616                 switch (ftypes[sensor_count]) {
617                   case RW_IN_NULL:
618                   case RW_OUT_NULL:
619                     /* type is already null */
620                     break;
621                   case RW_IN:
622                   case RW_IN_WEB:
623                     /* arrived from the outside */
624                     ftypes[sensor_count] = RW_IN_NULL;
625                     break;
626                   case RW_OUT:
627                   case RW_OUT_WEB:
628                     /* arrived from the inside */
629                     ftypes[sensor_count] = RW_OUT_NULL;
630                     break;
631                   default:
632                     skAbortBadCase(ftypes[sensor_count]);
633                 }
634                 break;
635             }
636         }
637     }
638 
639     return probe->sensor_count;
640 }
641 
642 
643 /*
644  *    Determine the file output format to use.
645  *
646  *    Invoked from rwflowpack by packlogic->determine_fileformat_fn
647  */
648 #if  SK_ENABLE_IPV6
649 
650 static sk_file_format_t
packLogicDetermineFileFormat(const skpc_probe_t UNUSED (* probe),sk_flowtype_id_t UNUSED (ftype))651 packLogicDetermineFileFormat(
652     const skpc_probe_t  UNUSED(*probe),
653     sk_flowtype_id_t     UNUSED(ftype))
654 {
655     return FT_RWIPV6;
656 }
657 
658 #else
659 
660 static sk_file_format_t
packLogicDetermineFileFormat(const skpc_probe_t * probe,sk_flowtype_id_t ftype)661 packLogicDetermineFileFormat(
662     const skpc_probe_t *probe,
663     sk_flowtype_id_t    ftype)
664 {
665     assert(ftype < (sizeof(filetypeFormats)/sizeof(filetypeFormats[0])));
666 
667     if (skpcProbeGetQuirks(probe) & SKPC_QUIRK_ZERO_PACKETS) {
668         /* Use a format that does not use bytes/packet ratio */
669         return FT_RWGENERIC;
670     }
671 
672     switch (probe->probe_type) {
673       case PROBE_ENUM_NETFLOW_V5:
674         return filetypeFormats[ftype].netflow_v5;
675 
676       default:
677         return filetypeFormats[ftype].other;
678     }
679 }
680 
681 #endif  /* #else of #if SK_ENABLE_IPV6 */
682 
683 
684 /*
685 ** Local Variables:
686 ** mode:c
687 ** indent-tabs-mode:nil
688 ** c-basic-offset:4
689 ** End:
690 */
691