1 /*
2  *    Use this file as a template to create a C plug-in for use with
3  *    the SiLK tools rwfilter, rwcut, rwgroup, rwsort, rwstats, or
4  *    rwuniq.
5  */
6 
7 #include <silk/silk.h>
8 #include <silk/rwrec.h>
9 #include <silk/skipaddr.h>
10 #include <silk/skplugin.h>
11 #include <silk/utils.h>
12 
13 
14 /* DEFINES AND TYPEDEFS */
15 
16 /*
17  *    These variables specify the version of the SiLK plug-in API.
18  *    They are used in the call to skpinSimpleCheckVersion() below.
19  *    See the description of that function for their meaning.
20  */
21 #define PLUGIN_API_VERSION_MAJOR 1
22 #define PLUGIN_API_VERSION_MINOR 0
23 
24 
25 /* LOCAL FUNCTION PROTOTYPES */
26 
27 /* a convenience structure to define command line options.  you don't
28  * have to use this. */
29 typedef struct option_info_st {
30     /* this is mask specifying the applications for which this option
31      * should be available.  use SKPLUGIN_FN_ANY for the option to be
32      * available on all applications. */
33     skplugin_fn_mask_t  apps;
34     /* the name of the option (the command line switch) */
35     const char         *name;
36     /* whether it requires an argument, one of REQUIRED_ARG,
37      * OPTIONAL_ARG, or NO_ARG */
38     int                 has_arg;
39     /* a unique value for this option */
40     int                 val;
41     /* the option's help string; printed when --help is given */
42     char               *help;
43 } option_info_t;
44 
45 
46 /* LOCAL VARIABLES */
47 
48 /*
49  *    In this sample, we have the plug-in create two switches --one
50  *    and --two, but --two is only available on rwfilter.  For their
51  *    IDs, we define an enumeration.
52  */
53 typedef enum options_enum_en {
54     OPT_ONE, OPT_TWO
55 } options_enum;
56 
57 static const option_info_t my_options[] = {
58     {SKPLUGIN_FN_ANY,     "one", REQUIRED_ARG, OPT_ONE,
59      "my first option"},
60     {SKPLUGIN_FN_FILTER,  "two", REQUIRED_ARG, OPT_TWO,
61      "my second option"},
62     {0, 0, 0, 0, 0}             /* sentinel */
63 };
64 
65 
66 
67 
68 /* LOCAL FUNCTION PROTOTYPES */
69 
70 static skplugin_err_t
71 optionsHandler(
72     const char         *opt_arg,
73     void               *reg_data);
74 static skplugin_err_t
75 initialize(
76     void               *reg_data);
77 static skplugin_err_t
78 cleanup(
79     void               *reg_data);
80 static skplugin_err_t
81 recToText(
82     const rwRec        *rwrec,
83     char               *text_value,
84     size_t              text_size,
85     void               *reg_data,
86     void              **extra);
87 static skplugin_err_t
88 recToBin(
89     const rwRec        *rwrec,
90     uint8_t            *bin_value,
91     void               *reg_data,
92     void              **extra);
93 static skplugin_err_t
94 binToText(
95     const uint8_t      *bin_value,
96     char               *text_value,
97     size_t              text_size,
98     void               *reg_data);
99 static skplugin_err_t
100 addRecToBin(
101     const rwRec        *rwrec,
102     uint8_t            *bin_value,
103     void               *reg_data,
104     void              **extra);
105 static skplugin_err_t
106 binMerge(
107     uint8_t            *dst_bin_value,
108     const uint8_t      *src_bin_value,
109     void               *reg_data);
110 static skplugin_err_t
111 binCompare(
112     int                *cmp_result,
113     const uint8_t      *value_a,
114     const uint8_t      *value_b,
115     void               *reg_data);
116 static skplugin_err_t
117 filter(
118     const rwRec        *rwrec,
119     void               *reg_data,
120     void              **extra);
121 static skplugin_err_t
122 transform(
123     rwRec              *rwrec,
124     void               *reg_data,
125     void              **extra);
126 
127 
128 
129 /* FUNCTION DEFINITIONS */
130 
131 /*
132  *    This is the registration function.
133  *
134  *    When you provide "--plugin=my-plugin.so" on the command line to
135  *    an application, the application calls this function to determine
136  *    the new switches and/or fields that "my-plugin" provides.
137  *
138  *    This function is called with three arguments: the first two
139  *    describe the version of the plug-in API, and the third is a
140  *    pointer that is currently unused.
141  */
142 skplugin_err_t
SKPLUGIN_SETUP_FN(uint16_t major_version,uint16_t minor_version,void * plug_in_data)143 SKPLUGIN_SETUP_FN(
144     uint16_t            major_version,
145     uint16_t            minor_version,
146     void               *plug_in_data)
147 {
148     int i;
149     skplugin_field_t *field;
150     skplugin_err_t rv;
151     skplugin_callbacks_t regdata;
152 
153     /* Check the plug-in API version */
154     rv = skpinSimpleCheckVersion(major_version, minor_version,
155                                  PLUGIN_API_VERSION_MAJOR,
156                                  PLUGIN_API_VERSION_MINOR,
157                                  skAppPrintErr);
158     if (rv != SKPLUGIN_OK) {
159         return rv;
160     }
161 
162     /*
163      *  Register the options.  Note that we pass the option identifier
164      *  in the cddata field as a void*.
165      */
166     for (i = 0; my_options[i].name; ++i) {
167         rv = skpinRegOption2(my_options[i].name,
168                              my_options[i].has_arg,
169                              my_options[i].help,
170                              &optionsHandler, NULL,
171                              (void*)&my_options[i].val,
172                              1, my_options[i].apps);
173         /* it's (probably) not an error if the option was not
174          * registered.  in our example, option "two" is only
175          * registered when the plug-in is loaded by rwfilter. */
176         if (SKPLUGIN_OK != rv && SKPLUGIN_ERR_DID_NOT_REGISTER != rv) {
177             return rv;
178         }
179     }
180 
181 
182     /*
183      *    All of the skplugin registration functions take a pointer to
184      *    an skplugin_callbacks_t structure.  If the structure has
185      *    valid values for the fields that an application requires,
186      *    the application will register the field, the filter
187      *    function, or the transform function.  If the structure does
188      *    not have valid values for fields, the application ignores
189      *    the registration call.
190      *
191      *    When defining multiple fields or filters within a single
192      *    plug-in, there approaches:
193      *
194      *    1. You can create functions that operate on each field
195      *    individually.  In this approach, you may have recToText1()
196      *    and recToText2().
197      *
198      *    2. You can create a function that computes the value for
199      *    multiple fields.  In this approach, the 'reg_data' field is
200      *    often used to tell the function which field to compute.
201      *
202      *    Either approach is fine.  The first approach can be easier,
203      *    but it can lead to a lot of duplicate code.
204      */
205 
206 
207 
208     memset(&regdata, 0, sizeof(regdata));
209     /* set the fields on the skplugin_callbacks_t structure.  This
210      * example shows a value for each field, but you only need to set
211      * the values that you require. */
212 
213     /* when special initialization is required by the 'filter' or
214      * 'transform' functions or for the field in rwcut, rwgroup,
215      * rwsort, rwstats, or rwuniq, specify a function that should be
216      * called just before the application begins to process
217      * records. */
218     regdata.init           = &initialize;
219     /* when special clean-up is required by the 'filter' or
220      * 'transform' functions or for the field in rwcut, rwgroup,
221      * rwsort, rwstats, or rwuniq, specify a function that
222      * should be during shutdown. */
223     regdata.cleanup        = &cleanup;
224     /* when defining a field for rwcut, rwstats, or rwuniq, specify
225      * the desired width of the output column to use for the textual
226      * output. */
227     regdata.column_width   = 0;
228     /* when defining a field for rwgroup, rwsort, rwstats, or rwuniq,
229      * specify the number of byte required to hold the binary
230      * representation of the field. */
231     regdata.bin_bytes      = 0;
232     /* when defining a key field for rwcut, specify a function to
233      * convert the rwRec to a textual field. */
234     regdata.rec_to_text    = &recToText;
235     /* when defining a key field for rwgroup, rwsort, rwstats, or
236      * rwuniq, specify a function to convert the rwRec to a binary
237      * value.  The length of the returned value should be exactly
238      * bin_bytes. */
239     regdata.rec_to_bin     = &recToBin;
240     /* when defining an aggregate value field for rwstats or rwuniq,
241      * specify a function to update a binary value with a value based
242      * on the current rwRec. */
243     regdata.add_rec_to_bin = &addRecToBin;
244     /* when defining a key field or an aggregate value field for
245      * rwstats or rwuniq, specify a function to convert the binary
246      * value created by rec_to_bin (for keys) or add_rec_to_bin (for
247      * aggregate values) to a textual field. */
248     regdata.bin_to_text    = &binToText;
249     /* when defining an aggregate value field for rwstats or rwuniq,
250      * specify a function to merge two binary values created by
251      * add_rec_to_bin. */
252     regdata.bin_merge      = &binMerge;
253     /* when defining an aggregate value field for rwstats, specify a
254      * function to compare two the binary values created by
255      * add_rec_to_bin.  This is required to sort the output in
256      * rwstats. */
257     regdata.bin_compare    = &binCompare;
258     /* when defining an aggregate value field for rwstats or rwuniq,
259      * specify the value to use to initialize the aggregate value.
260      * This value should be exactly 'bin_bytes' long.  If not
261      * specified, the value is zeroed. */
262     regdata.initial        = NULL;
263     /* when defining a partioning rule for use in rwfilter, specify a
264      * function that determines whether a record passes or fails. */
265     regdata.filter         = &filter;
266     /* when defining a function that modifies SiLK records (for
267      * example, in rwptoflow), specify a function that transforms the
268      * SiLK record. */
269     regdata.transform      = &transform;
270     /* this will only be required for complicated plug-ins and is not
271      * described here. */
272     regdata.extra          = NULL;
273 
274 
275     rv = skpinRegField(&field,              /* handle to new field */
276                        "field_name",        /* field name */
277                        "field description", /* field description */
278                        &regdata,            /* skplugin_callbacks_t */
279                        NULL);               /* reg_data */
280     if (SKPLUGIN_OK != rv) {
281         return rv;
282     }
283 
284     /* return one of the following */
285     return SKPLUGIN_OK;
286     return SKPLUGIN_ERR;
287 }
288 
289 
290 /*
291  *  status = optionsHandler(opt_arg, reg_data);
292  *
293  *    Handles options for the plug-in.  Note that the skpinRegOption()
294  *    function call above contains a pointer to this function.
295  *
296  *    This function is called when the application sees an option that
297  *    the plug-in has registered.  'opt_arg' is the argument to the
298  *    option (for example, if the user specifies --foo=23, then
299  *    'opt_arg' will be the character buffer "23") or NULL if no
300  *    argument was given.
301  *
302  *    The 'reg_data' will be the value you specified when you
303  *    registered the option.
304  *
305  *    Returns SKPLUGIN_OK on success, or SKPLUGIN_ERR if there was a
306  *    problem.
307  */
308 static skplugin_err_t
optionsHandler(const char * opt_arg,void * reg_data)309 optionsHandler(
310     const char         *opt_arg,
311     void               *reg_data)
312 {
313     options_enum opt_index = *((options_enum*)reg_data);
314     skplugin_callbacks_t regdata;
315 
316     switch (opt_index) {
317       case OPT_ONE:
318         /* handle option "one" */
319         break;
320 
321       case OPT_TWO:
322         /* part of handling option "two" is to register a filter.
323          * This is one way to write a plug-in that allows the user to
324          * choose from among multiple filters */
325         memset(&regdata, 0, sizeof(regdata));
326         regdata.filter = &filter;
327         return skpinRegFilter(NULL, &regdata, NULL);
328     }
329 
330     /* return one of the following */
331     return SKPLUGIN_OK;
332     return SKPLUGIN_ERR;
333 }
334 
335 
336 /*
337  *  status = initialize(reg_data);
338  *
339  *    This function only needs to be specified when special
340  *    initialization code is required.  You do not have to have an
341  *    initialize function.
342  *
343  *    The 'reg_data' will be the value you specified when you
344  *    registered the field.  You do not have to use that value.
345  */
346 static skplugin_err_t
initialize(void * reg_data)347 initialize(
348     void               *reg_data)
349 {
350     /* return one of the following */
351     return SKPLUGIN_OK;
352     return SKPLUGIN_ERR_FATAL;
353 }
354 
355 
356 /*
357  *  status = cleanup(reg_data);
358  *
359  *    This function only needs to be specified when special cleanup
360  *    code is required.  You do not have to have an cleanup function.
361  *
362  *    The 'reg_data' will be the value you specified when you
363  *    registered the field.  You do not have to use that value.
364  */
365 static skplugin_err_t
cleanup(void * reg_data)366 cleanup(
367     void               *reg_data)
368 {
369     /* return one of the following */
370     return SKPLUGIN_OK;
371     return SKPLUGIN_ERR_FATAL;
372 }
373 
374 
375 /*
376  *  status = recToText(rwrec, text_value, text_size, reg_data, extra);
377  *
378  *    A function similar to this is required when the plug-in will be
379  *    used to create a key field for use by rwcut.
380  *
381  *    The function should use the SiLK flow record 'rwrec' to create a
382  *    textual field.  The function should then write that textual
383  *    value into the 'text_value' character buffer, writing no more
384  *    than 'text_size' characters to it---including the final NUL.
385  *    The value of 'text_size' will be at least one more than the
386  *    'column_width' that was specified when the field was registered.
387  *
388  *    The 'reg_data' will be the value you specified when you
389  *    registered the field.  You do not have to use that value.
390  *
391  *    You will most likely not use the 'extra' parameter.
392  */
393 static skplugin_err_t
recToText(const rwRec * rwrec,char * text_value,size_t text_size,void * reg_data,void ** extra)394 recToText(
395     const rwRec        *rwrec,
396     char               *text_value,
397     size_t              text_size,
398     void               *reg_data,
399     void              **extra)
400 {
401     /* return one of the following */
402     return SKPLUGIN_OK;
403     return SKPLUGIN_ERR_FATAL;
404 
405 #if 0
406     /* key example: print lower of sPort or dPort */
407     if (rwRecGetSPort(rwrec) < rwRecGetDPort(rwrec)) {
408         snprintf(text_value, text_size, rwRecGetSPort(rwrec));
409     } else {
410         snprintf(text_value, text_size, rwRecGetDPort(rwrec));
411     }
412     return SKPLUGIN_OK;
413 #endif  /* 0 */
414 }
415 
416 
417 /*
418  *  status = recToBin(rwrec, bin_value, reg_data, extra);
419  *
420  *    A function similar to this is required when the plug-in will be
421  *    used to create a key field for use by rwgroup, rwsort, rwstats,
422  *    or rwuniq.  (For rwstats and rwuniq, a binToText() function is
423  *    also required.)
424  *
425  *    The function should use the SiLK flow record 'rwrec' to create a
426  *    binary value.  The function should then write that binary value
427  *    into the 'bin_value' buffer.  Since this value will be used for
428  *    sorting, the binary value should be written in network byte
429  *    order (big endian).
430  *
431  *    The function should write the same number of bytes as were
432  *    specified in the 'bin_bytes' field when the field was
433  *    registered.
434  *
435  *    The 'reg_data' will be the value you specified when you
436  *    registered the field.  You do not have to use that value.
437  *
438  *    You will most likely not use the 'extra' parameter.
439  */
440 static skplugin_err_t
recToBin(const rwRec * rwrec,uint8_t * bin_value,void * reg_data,void ** extra)441 recToBin(
442     const rwRec        *rwrec,
443     uint8_t            *bin_value,
444     void               *reg_data,
445     void              **extra)
446 {
447     /* return one of the following */
448     return SKPLUGIN_OK;
449     return SKPLUGIN_ERR_FATAL;
450 
451 #if 0
452     /* key example: encode lower of sPort or dPort */
453     uint16_t port;
454 
455     if (rwRecGetSPort(rwrec) < rwRecGetDPort(rwrec)) {
456         port = htons(rwRecGetSPort(rwrec));
457     } else {
458         port = htons(rwRecGetDPort(rwrec));
459     }
460     memcpy(bin_value, &port, sizeof(port));
461     return SKPLUGIN_OK;
462 #endif  /* 0 */
463 }
464 
465 
466 /*
467  *  status = binToText(bin_value, text_value, text_size, reg_data);
468  *
469  *    A function similar to this is required when the plug-in will be
470  *    used to create a key field or an aggregate value for use by
471  *    rwstats or rwuniq.
472  *
473  *    The function should use the 'bin_value' buffer to create a
474  *    textual value.  This function should write the textual value
475  *    into the 'text_value' character buffer, writing no more than
476  *    'text_size' characters to it---including the final NUL.  The
477  *    value of 'text_size' will be at least one more than the
478  *    'column_width' that was specified when the field was registered.
479  *
480  *    For key fields, the contents of 'bin_value' will be the result
481  *    of a prior call to the recToBin() function.
482  *
483  *    For aggregate value fields, the contents of 'bin_value' will be
484  *    the result of calls to addRecToBin() and binMerge().
485  *
486  *    The 'reg_data' will be the value you specified when you
487  *    registered the field.  You do not have to use that value.
488  */
489 static skplugin_err_t
binToText(const uint8_t * bin_value,char * text_value,size_t text_size,void * reg_data)490 binToText(
491     const uint8_t      *bin_value,
492     char               *text_value,
493     size_t              text_size,
494     void               *reg_data)
495 {
496     /* return one of the following */
497     return SKPLUGIN_OK;
498     return SKPLUGIN_ERR_FATAL;
499 
500 #if 0
501     /* key example: print lower port encoded by recToBin */
502     uint16_t port;
503 
504     memcpy(&port, bin_value, sizeof(port));
505     snprintf(text_value, text_size, ntohs(port));
506     return SKPLUGIN_OK;
507 
508     /* value example:  sum of durations */
509     uint32_t dur;
510 
511     memcpy(&dur, bin_value, sizeof(dur));
512     snprintf(text_value, text_size, dur);
513     return SKPLUGIN_OK;
514 #endif  /* 0 */
515 }
516 
517 
518 /*
519  *  status = addRecToBin(rwrec, bin_value, reg_data, extra);
520  *
521  *    A function similar to this is required when the plug-in will be
522  *    used to create an aggregate value field for use by rwstats or or
523  *    rwuniq.  The binToText() and binMerge() functions are also
524  *    required.
525  *
526  *    The function should use the SiLK flow record 'rwrec' to create a
527  *    binary value.  The function should then  ADD or MERGE that binary
528  *    value into the value currently in the 'bin_value' buffer.  For
529  *    example, if your plug-in is counting bytes, it should add the
530  *    bytes from the current 'rwRec' into the value in 'bin_value'.
531  *
532  *    The length of 'bin_value' is determined by the 'bin_bytes' field
533  *    when the field was registered.
534  *
535  *    The 'reg_data' will be the value you specified when you
536  *    registered the field.  You do not have to use that value.
537  *
538  *    You will most likely not use the 'extra' parameter.
539  */
540 static skplugin_err_t
addRecToBin(const rwRec * rwrec,uint8_t * bin_value,void * reg_data,void ** extra)541 addRecToBin(
542     const rwRec        *rwrec,
543     uint8_t            *bin_value,
544     void               *reg_data,
545     void              **extra)
546 {
547     /* return one of the following */
548     return SKPLUGIN_OK;
549     return SKPLUGIN_ERR_FATAL;
550 
551 #if 0
552     /* value example:  sum of duration for all flows matching key */
553     uint32_t dur;
554 
555     memcpy(&dur, bin_value, sizeof(dur));
556     dur += rwRecGetElapsed(rwrec);
557     memcpy(bin_value, &dur, sizeof(dur));
558     return SKPLUGIN_OK;
559 #endif  /* 0 */
560 }
561 
562 
563 /*
564  *  status = binMerge(dst_bin_value, src_bin_value, reg_data);
565  *
566  *    A function similar to this is required when the plug-in will be
567  *    used to create an aggregate value field for use by rwstats or or
568  *    rwuniq.  The binToText() and addRecToBin() functions are also
569  *    required.
570  *
571  *    This function is used to combine two binary aggregate values,
572  *    created by prior calls to addRecToBin(), into a single binary
573  *    value.  When called, both 'dst_bin_value' and 'src_bin_value'
574  *    will have valid binary values.  This function should combine the
575  *    values (by adding or merging them as appropriate) and put the
576  *    resulting value into 'dst_bin_value'.
577  *
578  *    The length of 'bin_value' is determined by the 'bin_bytes' field
579  *    when the field was registered.
580  *
581  *    The 'reg_data' will be the value you specified when you
582  *    registered the field.  You do not have to use that value.
583  *
584  *    When rwstats or rwuniq run out of RAM, they write their current
585  *    (key,value) pair to temporary files disk; once all records have
586  *    been processed, the (key,value) pairs in the temporary files
587  *    must be merged.  This function will be called to merge values
588  *    for entries with identical keys.
589  */
590 static skplugin_err_t
binMerge(uint8_t * dst_bin_value,const uint8_t * src_bin_value,void * reg_data)591 binMerge(
592     uint8_t            *dst_bin_value,
593     const uint8_t      *src_bin_value,
594     void               *reg_data)
595 {
596     /* return one of the following */
597     return SKPLUGIN_OK;
598     return SKPLUGIN_ERR_FATAL;
599 
600 #if 0
601     /* value example:  sum of duration for all flows matching key */
602     uint32_t dst_dur;
603     uint32_t src_dur;
604 
605     memcpy(&dst_dur, dst_bin_value, sizeof(dst_dur));
606     memcpy(&src_dur, src_bin_value, sizeof(src_dur));
607     dst_dur += src_dur;
608     memcpy(dst_bin_value, &dst_dur, sizeof(dst_dur));
609     return SKPLUGIN_OK;
610 #endif  /* 0 */
611 }
612 
613 
614 /*
615  *  status = binCompare(cmp_result, bin_value_a, bin_value_b, reg_data);
616  *
617  *    A function similar to this is required when the plug-in will be
618  *    used to create an aggregate value field for use by rwstats.  The
619  *    binToText(), addRecToBin(), and binMerge() functions are also
620  *    required.
621  *
622  *    This function is used to compare two binary aggregate values,
623  *    created by prior calls to addRecToBin().  This is required to
624  *    sort the value fields in rwstats to produce a Top-N list.  The
625  *    function should set 'cmp_result' to a value less than 0, equal
626  *    to 0, or greater than 0 when 'bin_value_a' is less then, equal
627  *    to, or greater than 'bin_value_b', respectively.
628  *
629  *    The length of 'bin_value' is determined by the 'bin_bytes' field
630  *    when the field was registered.
631  *
632  *    The 'reg_data' will be the value you specified when you
633  *    registered the field.  You do not have to use that value.
634  */
635 static skplugin_err_t
binCompare(int * cmp_result,const uint8_t * bin_value_a,const uint8_t * bin_value_b,void * reg_data)636 binCompare(
637     int                *cmp_result,
638     const uint8_t      *bin_value_a,
639     const uint8_t      *bin_value_b,
640     void               *reg_data)
641 {
642     /* return one of the following */
643     return SKPLUGIN_OK;
644     return SKPLUGIN_ERR_FATAL;
645 
646 #if 0
647     /* value example:  sum of duration for all flows matching key */
648     uint32_t dur_a;
649     uint32_t dur_b;
650 
651     memcpy(&dur_a, bin_value_a, sizeof(dur_a));
652     memcpy(&dur_b, bin_value_b, sizeof(dur_b));
653     if (dur_a < dur_b) {
654         *cmp_result = -1;
655     } else if (dur_a > dur_b) {
656         *cmp_result = 1;
657     } else {
658         *cmp_result = 0;
659     }
660     return SKPLUGIN_OK;
661 #endif  /* 0 */
662 }
663 
664 
665 /*
666  *  status = filter(rwrec, reg_data, extra);
667  *
668  *    A function similar to this is required when the plug-in will be
669  *    used to partition fields into PASS and FAIL streams in rwfilter.
670  *
671  *    The function should examine the SiLK flow record and return
672  *    SKPLUGIN_FILTER_PASS to write the rwRec to the
673  *    pass-destination(s) or SKPLUGIN_FILTER_FAIL to write it to the
674  *    fail-destination(s).
675  *
676  *    The 'reg_data' will be the value you specified when you
677  *    registered the field.  You do not have to use that value.
678  *
679  *    You will most likely not use the 'extra' parameter.
680  */
681 static skplugin_err_t
filter(const rwRec * rwrec,void * reg_data,void ** extra)682 filter(
683     const rwRec        *rwrec,
684     void               *reg_data,
685     void              **extra)
686 {
687     /* return one of the following */
688     return SKPLUGIN_FILTER_FAIL;
689     return SKPLUGIN_FILTER_PASS;
690 
691 #if 0
692     /* example: pass ICMP or ICMPv6 flows */
693     if (IPPROTO_ICMP == rwRecGetProto(rwrec)
694         || IPPROTO_ICMPV6 == rwRecGetProto(rwrec))
695     {
696         return SKPLUGIN_FILTER_PASS;
697     }
698     return SKPLUGIN_FILTER_FAIL;
699 #endif  /* 0 */
700 }
701 
702 
703 /*
704  *  status = transform(rwrec, reg_data, extra);
705  *
706  *    A function similar to this is required when the plug-in will be
707  *    used to modify the SiLK Flow records.
708  *
709  *    The function can modify the SiLK flow record in place.  One use
710  *    for this is to modify records during their creation by the
711  *    rwptoflow application.
712  *
713  *    The 'reg_data' will be the value you specified when you
714  *    registered the field.  You do not have to use that value.
715  *
716  *    You will most likely not use the 'extra' parameter.
717  */
718 static skplugin_err_t
transform(rwRec * rwrec,void * reg_data,void ** extra)719 transform(
720     rwRec              *rwrec,
721     void               *reg_data,
722     void              **extra)
723 {
724     /* return one of the following */
725     return SKPLUGIN_OK;
726     return SKPLUGIN_ERR_FATAL;
727 }
728 
729 
730 /*
731 ** Local Variables:
732 ** mode:c
733 ** indent-tabs-mode:nil
734 ** c-basic-offset:4
735 ** End:
736 */
737