1 /*
2  ** @internal
3  **
4  ** yafhooks.c
5  ** YAF Active Flow Table Plugin Interface
6  **
7  ** ------------------------------------------------------------------------
8  ** Copyright (C) 2007-2015 Carnegie Mellon University. All Rights Reserved.
9  ** ------------------------------------------------------------------------
10  ** Authors: Brian Trammell
11  ** ------------------------------------------------------------------------
12  ** @OPENSOURCE_HEADER_START@
13  ** Use of the YAF system and related source code is subject to the terms
14  ** of the following licenses:
15  **
16  ** GNU Public License (GPL) Rights pursuant to Version 2, June 1991
17  ** Government Purpose License Rights (GPLR) pursuant to DFARS 252.227.7013
18  **
19  ** NO WARRANTY
20  **
21  ** ANY INFORMATION, MATERIALS, SERVICES, INTELLECTUAL PROPERTY OR OTHER
22  ** PROPERTY OR RIGHTS GRANTED OR PROVIDED BY CARNEGIE MELLON UNIVERSITY
23  ** PURSUANT TO THIS LICENSE (HEREINAFTER THE "DELIVERABLES") ARE ON AN
24  ** "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY
25  ** KIND, EITHER EXPRESS OR IMPLIED AS TO ANY MATTER INCLUDING, BUT NOT
26  ** LIMITED TO, WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE,
27  ** MERCHANTABILITY, INFORMATIONAL CONTENT, NONINFRINGEMENT, OR ERROR-FREE
28  ** OPERATION. CARNEGIE MELLON UNIVERSITY SHALL NOT BE LIABLE FOR INDIRECT,
29  ** SPECIAL OR CONSEQUENTIAL DAMAGES, SUCH AS LOSS OF PROFITS OR INABILITY
30  ** TO USE SAID INTELLECTUAL PROPERTY, UNDER THIS LICENSE, REGARDLESS OF
31  ** WHETHER SUCH PARTY WAS AWARE OF THE POSSIBILITY OF SUCH DAMAGES.
32  ** LICENSEE AGREES THAT IT WILL NOT MAKE ANY WARRANTY ON BEHALF OF
33  ** CARNEGIE MELLON UNIVERSITY, EXPRESS OR IMPLIED, TO ANY PERSON
34  ** CONCERNING THE APPLICATION OF OR THE RESULTS TO BE OBTAINED WITH THE
35  ** DELIVERABLES UNDER THIS LICENSE.
36  **
37  ** Licensee hereby agrees to defend, indemnify, and hold harmless Carnegie
38  ** Mellon University, its trustees, officers, employees, and agents from
39  ** all claims or demands made against them (and any related losses,
40  ** expenses, or attorney's fees) arising out of, or relating to Licensee's
41  ** and/or its sub licensees' negligent use or willful misuse of or
42  ** negligent conduct or willful misconduct regarding the Software,
43  ** facilities, or other rights or assistance granted by Carnegie Mellon
44  ** University under this License, including, but not limited to, any
45  ** claims of product liability, personal injury, death, damage to
46  ** property, or violation of any laws or regulations.
47  **
48  ** Carnegie Mellon University Software Engineering Institute authored
49  ** documents are sponsored by the U.S. Department of Defense under
50  ** Contract FA8721-05-C-0003. Carnegie Mellon University retains
51  ** copyrights in all material produced under this contract. The U.S.
52  ** Government retains a non-exclusive, royalty-free license to publish or
53  ** reproduce these documents, or allow others to do so, for U.S.
54  ** Government purposes only pursuant to the copyright license under the
55  ** contract clause at 252.227.7013.
56  **
57  ** @OPENSOURCE_HEADER_END@
58  ** ------------------------------------------------------------------------
59  */
60 
61 #define _YAF_SOURCE_
62 #include <yaf/yafhooks.h>
63 #include <ltdl.h>
64 #if YAF_ENABLE_HOOKS
65 /* define a quick variable argument number macro to simply sending an error back to the yaf "core" */
66 #define gerr(e, ...) {if (NULL == e) { *e = g_error_new(__VA_ARGS__); } else { g_set_error(e, __VA_ARGS__); }}
67 
68 #define YAF_SEARCH_LIB "/usr/local/lib/yaf"
69 
70 /** this flag contains the number of plugins that have been hooked in */
71 unsigned int yaf_hooked = 0;
72 
73 static const char *pluginFunctionNames[] = {
74     "ypGetMetaData",
75     "ypHookPacket",
76     "ypFlowPacket",
77     "ypFlowClose",
78     "ypFlowAlloc",
79     "ypFlowFree",
80     "ypFlowWrite",
81     "ypGetInfoModel",
82     "ypGetTemplate",
83     "ypSetPluginOpt",
84     "ypSetPluginConf",
85 #if YAF_ENABLE_APPLABEL
86     "ypScanPayload",
87 #endif
88     "ypValidateFlowTab",
89     "ypGetTemplateCount",
90     "ypFreeLists"
91 };
92 
93 typedef const struct yfHookMetaData* (*yfHookGetMetaData_fn)(void);
94 typedef gboolean (*yfHookPacket_fn)(yfFlowKey_t *key, const uint8_t *pkt,
95                     size_t caplen, uint16_t iplen,
96                     yfTCPInfo_t *tcpinfo, yfL2Info_t *l2info);
97 typedef void (*yfHookFlowPacket_fn)(void * yfHookConext, yfFlow_t *flow,
98                     yfFlowVal_t *val, const uint8_t *pkt,
99                     size_t caplen, uint16_t iplen,
100                     yfTCPInfo_t *tcpinfo, yfL2Info_t *l2info);
101 typedef gboolean (*yfHookFlowClose_fn)(void * yfHookConext, yfFlow_t *flow);
102 typedef void (*yfHookFlowAlloc_fn)(void ** yfHookConext, yfFlow_t *flow, void *yfctx);
103 typedef void (*yfHookFlowFree_fn)(void * yfHookConext, yfFlow_t *flow);
104 typedef gboolean (*yfWriteFlowHook_fn)(void * yfHookConext,
105                                        fbSubTemplateMultiList_t *rec,
106                                        fbSubTemplateMultiListEntry_t *stml,
107                                        yfFlow_t *flow, GError **err);
108 typedef fbInfoElement_t * (*yfHookGetInfoModel_fn)(void);
109 typedef gboolean (*yfHookGetTemplate_fn)(fbSession_t *session);
110 typedef void (*yfHookSetPluginOpt_fn)(const char * pluginOpt, void *yfctx);
111 typedef void (*yfHookSetPluginConf_fn)(const char * pluginConf, void **yfctx);
112 #if YAF_ENABLE_APPLABEL
113 typedef void (*yfHookScanPayload_fn)(void *yfHookConext, yfFlow_t *flow,
114                      const uint8_t *pkt, size_t caplen,
115                      pcre *expression, uint16_t offset,
116                      uint16_t elementID, uint16_t applabel);
117 #endif
118 typedef gboolean (*yfHookValidateFlowTab_fn)(void *yfctx,
119                                              uint32_t max_payload,
120                                              gboolean uniflow,
121                                              gboolean silkmode,
122                                              gboolean applabelmode,
123                                              gboolean entropymode,
124                                              gboolean fingerprintmode,
125                                              gboolean fpExportMode,
126                                              gboolean udp_max_payload,
127                                              uint16_t udp_uniflow_port,
128                                              GError **err);
129 typedef uint8_t (*yfHookGetTemplateCount_fn)(void *yfHookConext, yfFlow_t *flow);
130 typedef void (*yfHookFreeLists_fn)(void * yfHookConext, yfFlow_t *flow);
131 
132 typedef struct yfHooksFuncs_st {
133     yfHookGetMetaData_fn    getMetaData;
134     yfHookPacket_fn         hookPacket;
135     yfHookFlowPacket_fn     flowPacket;
136     yfHookFlowClose_fn      flowClose;
137     yfHookFlowAlloc_fn      flowAlloc;
138     yfHookFlowFree_fn       flowFree;
139     yfWriteFlowHook_fn      flowWrite;
140     yfHookGetInfoModel_fn   modelGet;
141     yfHookGetTemplate_fn    templateGet;
142     yfHookSetPluginOpt_fn   setPluginOpt;
143     yfHookSetPluginConf_fn  setPluginConf;
144 #if YAF_ENABLE_APPLABEL
145     yfHookScanPayload_fn    scanPayload;
146 #endif
147     yfHookValidateFlowTab_fn validateFlowTab;
148     yfHookGetTemplateCount_fn getTemplateCount;
149     yfHookFreeLists_fn       freeLists;
150 } yfHooksFuncs_t;
151 
152 typedef struct yfHookPlugin_st {
153     lt_dlhandle         pluginHandle;
154     union {
155         lt_ptr              genPtr[sizeof (pluginFunctionNames) /
156                                    sizeof (char *)];
157         yfHooksFuncs_t          funcPtrs;
158     } ufptr;
159     struct yfHookPlugin_st *next;
160 } yfHookPlugin_t;
161 
162 
163 /** pointer to a _simple_ linked list of plugins registered
164     for this program run
165   */
166 static yfHookPlugin_t *headPlugin = NULL;
167 
168 /** keeps a running sum of the total amount of data exported
169     by the plugins, so that there isn't an overrun in the fixed
170     size output buffer
171   */
172 static uint32_t totalPluginExportData = 0;
173 
174 /** need to remember the export data size of each hooked plugin, and
175     advance the data array pointer an appropriate amount for each
176     write call
177   */
178 static uint32_t pluginExportSize[YAF_MAX_HOOKS];
179 
180 /**
181  * yfHookPacket
182  *
183  *
184  *
185  */
186 gboolean
yfHookPacket(yfFlowKey_t * key,const uint8_t * pkt,size_t caplen,uint16_t iplen,yfTCPInfo_t * tcpinfo,yfL2Info_t * l2info)187 yfHookPacket (
188     yfFlowKey_t * key,
189     const uint8_t * pkt,
190     size_t caplen,
191     uint16_t iplen,
192     yfTCPInfo_t * tcpinfo,
193     yfL2Info_t * l2info)
194 {
195     yfHookPlugin_t      *pluginIndex;
196     unsigned int         loop;
197 
198     pluginIndex = headPlugin;
199 
200     for (loop = 0; loop < yaf_hooked; loop++) {
201         if (NULL == pluginIndex) {
202             break;
203         }
204         if (FALSE == (pluginIndex->ufptr.funcPtrs.hookPacket) (key, pkt,
205                                                        caplen, iplen, tcpinfo,
206                                                                l2info))
207         {
208             return FALSE;
209         }
210         pluginIndex = pluginIndex->next;
211     }
212 
213     return TRUE;
214 }
215 
216 /**
217  * yfHookFlowPacket
218  *
219  *
220  *
221  */
222 void
yfHookFlowPacket(yfFlow_t * flow,yfFlowVal_t * val,const uint8_t * pkt,size_t caplen,uint16_t iplen,yfTCPInfo_t * tcpinfo,yfL2Info_t * l2info)223 yfHookFlowPacket (
224     yfFlow_t * flow,
225     yfFlowVal_t *val,
226     const uint8_t *pkt,
227     size_t caplen,
228     uint16_t iplen,
229     yfTCPInfo_t * tcpinfo,
230     yfL2Info_t * l2info)
231 {
232     yfHookPlugin_t      *pluginIndex;
233     unsigned int        loop = 0;
234 
235     pluginIndex = headPlugin;
236 
237     for (loop=0; loop < yaf_hooked; loop++) {
238         if (NULL == pluginIndex) {
239             break;
240         }
241         (pluginIndex->ufptr.funcPtrs.flowPacket)((flow->hfctx)[loop],
242                                                  flow, val, pkt, caplen, iplen,
243                                                  tcpinfo, l2info);
244         pluginIndex = pluginIndex->next;
245 }
246     return;
247 }
248 
249 /**
250  * yfHookValidateFlowTab
251  *
252  * Check to make sure plugin can operate with flowtable options
253  *
254  */
255 void
yfHookValidateFlowTab(void ** yfctx,uint32_t max_payload,gboolean uniflow,gboolean silkmode,gboolean applabelmode,gboolean entropymode,gboolean fingerprintmode,gboolean fpExportMode,gboolean udp_max_payload,uint16_t udp_uniflow_port)256 yfHookValidateFlowTab(
257     void            **yfctx,
258     uint32_t        max_payload,
259     gboolean        uniflow,
260     gboolean        silkmode,
261     gboolean        applabelmode,
262     gboolean        entropymode,
263     gboolean        fingerprintmode,
264     gboolean        fpExportMode,
265     gboolean        udp_max_payload,
266     uint16_t        udp_uniflow_port)
267 {
268 
269     yfHookPlugin_t    *pluginIndex;
270     yfHookPlugin_t    *currentIndex;
271     yfHookPlugin_t    *lastIndex;
272     int               loop = 0;
273     GError            *err = NULL;
274     int               hooked = yaf_hooked;
275 
276     pluginIndex = headPlugin;
277     lastIndex = headPlugin;
278 
279     for (loop = 0; loop < hooked; loop++) {
280        if (NULL == pluginIndex) {
281            break;
282        }
283        if (FALSE == pluginIndex->ufptr.funcPtrs.validateFlowTab(yfctx[loop],
284                                                         max_payload,
285                                                         uniflow,
286                                                         silkmode,
287                                                         applabelmode,
288                                                         entropymode,
289                                                         fingerprintmode,
290                                                         fpExportMode,
291                                                         udp_max_payload,
292                                                         udp_uniflow_port,
293                                                         &err))
294        {
295            g_warning("Plugin: %s", err->message);
296            currentIndex = pluginIndex;
297            pluginIndex = pluginIndex->next;
298            if (currentIndex == headPlugin) {
299                headPlugin = pluginIndex;
300            } else {
301                lastIndex->next = pluginIndex->next;
302            }
303            free(currentIndex);
304            yaf_hooked--;
305            g_clear_error(&err);
306        } else {
307            pluginIndex = pluginIndex->next;
308        }
309 
310     }
311     return;
312 }
313 
314 
315 /**
316  *
317  *
318  *
319  *
320  */
321 gboolean
yfHookFlowClose(yfFlow_t * flow)322 yfHookFlowClose (
323     yfFlow_t * flow)
324 {
325     yfHookPlugin_t      *pluginIndex;
326     unsigned int        loop = 0;
327 
328     pluginIndex = headPlugin;
329 
330     for (loop=0; loop < yaf_hooked; loop++) {
331         if (NULL == pluginIndex) {
332             break;
333         }
334         if (FALSE == pluginIndex->ufptr.funcPtrs.flowClose((flow->hfctx)[loop],
335                                                            flow))
336         {
337             return FALSE;
338         }
339         pluginIndex = pluginIndex->next;
340     }
341 
342     return TRUE;
343 }
344 
345 /**
346  * yfHookFlowAlloc
347  *
348  * this is called to give the plugins a chance to allocate flow state information
349  * for each flow captured by yaf
350  *
351  * @param flow the pointer to the flow context state structure, but more importantly
352  *        in this case, it contains the array of pointers (hfctx) which hold the
353  *        plugin context state
354  *
355  */
356 void
yfHookFlowAlloc(yfFlow_t * flow,void ** yfctx)357 yfHookFlowAlloc (
358     yfFlow_t * flow,
359     void     **yfctx)
360 {
361     yfHookPlugin_t      *pluginIndex;
362     unsigned int        loop = 0;
363 
364     pluginIndex = headPlugin;
365 
366     for (loop=0; loop < yaf_hooked; loop++) {
367         if (NULL == pluginIndex) {
368             break;
369         }
370         (pluginIndex->ufptr.funcPtrs.flowAlloc) (&((flow->hfctx)[loop]),
371                                                  flow, yfctx[loop]);
372         pluginIndex = pluginIndex->next;
373     }
374     return;
375 }
376 
377 /**
378  * yfHookFlowFree
379  *
380  * this frees all memory associated with the flow state in all of the attached
381  * plugins
382  *
383  * @param flow a pointer to the flow context structure
384  *
385  */
386 void
yfHookFlowFree(yfFlow_t * flow)387 yfHookFlowFree (
388     yfFlow_t * flow)
389 {
390     yfHookPlugin_t      *pluginIndex;
391     unsigned int        loop = 0;
392 
393     pluginIndex = headPlugin;
394 
395     for (loop=0; loop < yaf_hooked; loop++) {
396         if (NULL == pluginIndex) {
397             break;
398         }
399         (pluginIndex->ufptr.funcPtrs.flowFree) ((flow->hfctx)[loop], flow);
400         pluginIndex = pluginIndex->next;
401     }
402 
403     return;
404 }
405 
406 /**
407  * yfHookGetInfoModel
408  *
409  * returns the IPFIX info model aggregated for all plugins
410  *
411  * @bug it permanently caches an aggregate of all the info model
412  *      information from each plugin; some might call this a leak
413  *
414  * @return pointer to an array of fbInfoElement_t that contains
415  *         the sum of the IPFIX IE's from all active plugins
416  *
417  */
418 fbInfoElement_t    *
yfHookGetInfoModel()419 yfHookGetInfoModel (
420   )
421 {
422     static unsigned int cached = 0;
423     yfHookPlugin_t      *pluginIndex;
424     static fbInfoElement_t     *cachedIM = NULL;
425     fbInfoElement_t     *tempIM = NULL;
426     unsigned int        totalIMSize = 0;
427     unsigned int        partialIMSize = 0;
428     unsigned int        imIndex;
429     unsigned int        loop;
430 
431     if (0 == yaf_hooked) {
432         return NULL;
433     }
434 
435     if (yaf_hooked == cached && 0 != cached) {
436         return cachedIM;
437     } else if (0 != cached ) {
438         g_free(cachedIM);
439         cachedIM = NULL;
440     }
441 
442 
443     /* iterate through the plugins and on the first pass simply count the
444        number of info model enteries each one has
445      */
446     pluginIndex = headPlugin;
447     for (loop=0; loop < yaf_hooked; loop++) {
448         if (NULL == pluginIndex) {
449             g_error("internal error iterating plugins, cannot continue");
450             break;
451         }
452         tempIM = (pluginIndex->ufptr.funcPtrs.modelGet) ();
453         if (NULL != tempIM) {
454             partialIMSize = 0;
455             for (partialIMSize = 0; (tempIM+partialIMSize)->ref.name != NULL ; partialIMSize++) {
456             }
457             totalIMSize += partialIMSize;
458         }
459         pluginIndex = pluginIndex->next;
460     }
461 
462     /* allocate an array of info element enteries to hold the sum total of all
463        IE's from all the plugins.  Add 1 to add a NULL entry at the end
464     */
465     cachedIM = g_new(fbInfoElement_t, totalIMSize+1);
466 
467     /* now iterate through each plugin and copy each info model entry from
468        the returned array into the local cache copy that was just allocated
469     */
470     pluginIndex = headPlugin;
471     imIndex = 0;
472     for (loop=0; loop < yaf_hooked; loop++) {
473         if (NULL == pluginIndex) {
474             g_error("internal error iterating plugins, cannot continue");
475             break;
476         }
477         tempIM = (pluginIndex->ufptr.funcPtrs.modelGet) ();
478         if (NULL != tempIM) {
479             for (partialIMSize = 0; (tempIM+partialIMSize)->ref.name != NULL; partialIMSize++) {
480                 memcpy(cachedIM+imIndex, tempIM+partialIMSize,
481                        sizeof(fbInfoElement_t));
482                 imIndex++;
483             }
484         }
485         pluginIndex = pluginIndex->next;
486     }
487 
488 
489     /* copy the NULL element field into the end of the combined $ array, this
490        works because at the end of the previous for loop, partialIMSize should
491        always be pointing to a NULL field, based on the for loop test */
492     memcpy(cachedIM+totalIMSize, tempIM+partialIMSize,
493            sizeof(fbInfoElement_t));
494 
495 
496     cached = yaf_hooked;
497     return cachedIM;
498 }
499 
500 /**
501  * yfHookGetTemplate
502  *
503  * gets the IPFIX info model template for the export data from _all_ the
504  * plugins and turns it into a single template to return.  It caches the
505  * results so that future queries are a lot faster.  It can invalidate the
506  * cached result if the number of plugins registered changes.
507  *
508  * @return pointer to an array of fbInfoElementSpec_t structures that describe
509  * the info model template
510  *
511  */
512 gboolean
yfHookGetTemplate(fbSession_t * session)513 yfHookGetTemplate (
514     fbSession_t *session)
515 {
516     yfHookPlugin_t      *pluginIndex = NULL;
517     int                 loop;
518     int                 hooked = yaf_hooked;
519 
520     /* first check if we've cached any results yet, if not, do the work
521        then check to see if this result was cached before (good chance it was,
522        but make sure it is up to date)
523        if it's not up to date, through it away and recompute the result
524      */
525 
526     if (0 == yaf_hooked) {
527         return TRUE;
528     }
529 
530     pluginIndex = headPlugin;
531 
532     for (loop = 0; loop < hooked; loop++) {
533         if (NULL == pluginIndex) {
534             g_error("internal error iterating plugins, cannot continue");
535             return FALSE;
536         }
537         if (!(pluginIndex->ufptr.funcPtrs.templateGet) (session)){
538             g_debug("Error Getting Template for Hooks: "
539                     "Plugin can not be used");
540             yaf_hooked--;
541         }
542         pluginIndex = pluginIndex->next;
543     }
544 
545     return TRUE;
546 }
547 
548 /**
549  *
550  *
551  *
552  *
553  */
554 gboolean
yfWriteFlowHook(fbSubTemplateMultiList_t * rec,fbSubTemplateMultiListEntry_t * stml,yfFlow_t * flow,GError ** err)555 yfWriteFlowHook (
556     fbSubTemplateMultiList_t *rec,
557     fbSubTemplateMultiListEntry_t *stml,
558     yfFlow_t * flow,
559     GError ** err)
560 {
561     yfHookPlugin_t      *pluginIndex;
562     unsigned int        loop;
563 
564     pluginIndex = headPlugin;
565 
566     for (loop = 0; loop < yaf_hooked; loop++) {
567         if (NULL == pluginIndex) {
568             break;
569         }
570 
571         if (FALSE == pluginIndex->ufptr.funcPtrs.flowWrite((flow->hfctx)[loop],
572                                 rec, stml, flow, err))
573         {
574             return FALSE;
575         }
576         pluginIndex = pluginIndex->next;
577     }
578 
579     return TRUE;
580 }
581 
582 
583 
584 /**
585  *yfHookAddNewHook
586  *
587  * adds another hook (plugin) into yaf
588  *
589  * @param hookName the file name of the plugin to load
590  * @param hookOpts a string of command line options for the plugin to process
591  * @param hookConf the filename of the configuration file to load
592  * @param hfctx context for yaf plugins
593  * @param err the error value that gets set if this call didn't work
594  *
595  * @return TRUE if plugin loaded fine, other FALSE
596  *
597  */
598 gboolean
yfHookAddNewHook(const char * hookName,const char * hookOpts,const char * hookConf,void ** yfctx,GError ** err)599 yfHookAddNewHook (
600     const char *hookName,
601     const char *hookOpts,
602     const char *hookConf,
603     void       **yfctx,
604     GError ** err)
605 {
606     int             rc;
607     lt_dlhandle     libHandle;
608     lt_ptr          genericLtPtr;
609     unsigned int    loop;
610     yfHookPlugin_t  *newPlugin = NULL;
611     yfHookPlugin_t  *pluginIndex;
612     const struct yfHookMetaData *md;
613 
614     /* check to make sure we aren't exceeding the number of allowed hooks */
615     if (YAF_MAX_HOOKS == yaf_hooked) {
616         gerr(err, YAF_ERROR_DOMAIN, YAF_ERROR_IMPL,
617              "Maximum number of plugins exceeded, limit is %d",
618              YAF_MAX_HOOKS);
619         return FALSE;
620     }
621 
622     /*  initialize the dynamic loader library before we ty to use it, it is
623         harmless to call this one than once */
624     if ((rc = lt_dlinit ())) {
625         gerr(err, YAF_ERROR_DOMAIN, YAF_ERROR_IMPL,
626              "Couldn't initialize LTDL library loader: %s",
627              lt_dlerror ());
628         return FALSE;
629     }
630 
631 
632     /* load the plugin by name, the library will try platform appropriate
633        extensions */
634     libHandle = lt_dlopenext(hookName);
635     if (NULL == libHandle) {
636         gerr(err, YAF_ERROR_DOMAIN, YAF_ERROR_ARGUMENT,
637              "failed to load plugin \"%s\" with reason: %s", hookName,
638              lt_dlerror ());
639         return FALSE;
640     }
641 
642 
643     /* build a new handle for the plugin and initialize it */
644     newPlugin = (yfHookPlugin_t *) malloc (sizeof (yfHookPlugin_t));
645     if (NULL == newPlugin) {
646         lt_dlclose(libHandle);
647         gerr(err, YAF_ERROR_DOMAIN, YAF_ERROR_IMPL,
648              "couldn't allocate memory to load plugin\n");
649         return FALSE;
650     }
651     newPlugin->pluginHandle = libHandle;
652     newPlugin->next = NULL;
653 
654      /* load in all the function pointers from the library, search by name */
655     for (loop = 0; loop < sizeof (pluginFunctionNames)/sizeof (char *); loop++)
656     {
657         genericLtPtr = lt_dlsym (libHandle, pluginFunctionNames[loop]);
658         if (NULL == genericLtPtr) {
659             break;
660         }
661         newPlugin->ufptr.genPtr[loop] = genericLtPtr;
662     }
663 
664     /* make sure all the functions were loaded correctly */
665     if (loop < sizeof (pluginFunctionNames) / sizeof (char *)) {
666         gerr(err, YAF_ERROR_DOMAIN, YAF_ERROR_ARGUMENT,
667              "missing function \"%s\" in %s plugin",
668              pluginFunctionNames[loop], hookName);
669         return FALSE;
670     }
671 
672      /* insert this plugin into an empty plugin list */
673     if (NULL == headPlugin) {
674         headPlugin = newPlugin;
675     } else {
676         /*if there is alredy a plugin installed, add this plugin to the list */
677          pluginIndex = headPlugin;
678          while (pluginIndex->next) {
679              pluginIndex = pluginIndex->next;
680          }
681 
682          pluginIndex->next = newPlugin;
683     }
684 
685 
686     /** get the metadata information from the plugin, and make sure that
687         yaf can still operate with it installed */
688     md = newPlugin->ufptr.funcPtrs.getMetaData();
689     if (YAF_HOOK_INTERFACE_VERSION < md->version)
690     {
691         gerr(err, YAF_ERROR_DOMAIN, YAF_ERROR_IMPL,
692              "incompatible plugin version, max supported is %d, plugin is %d",
693              YAF_HOOK_INTERFACE_VERSION, md->version);
694         return FALSE;
695     } else if (YAF_HOOK_INTERFACE_VERSION != md->version) {
696         g_warning("Incompatible plugin version.");
697         g_warning("YAF uses version %d, Plugin is version: %d",
698                   YAF_HOOK_INTERFACE_VERSION, md->version);
699         g_warning("Make sure you set LTDL_LIBRARY_PATH to correct location.");
700         g_warning("yaf continuing...some functionality may not be available.");
701     }
702 
703     if (YAF_HOOKS_MAX_EXPORT < totalPluginExportData + md->exportDataSize) {
704         gerr(err, YAF_ERROR_DOMAIN, YAF_ERROR_IMPL,
705              "maximum plugin export data limit exceeded");
706         return FALSE;
707     }
708 #ifndef YAF_ENABLE_APPLABEL
709     if (md->requireAppLabel == 1) {
710         gerr(err, YAF_ERROR_DOMAIN, YAF_ERROR_IMPL,
711              "this plugin requires --enable-applabel");
712         return FALSE;
713     }
714 #endif
715 
716     /* record the export size for this plugin, and update the running total */
717     pluginExportSize[yaf_hooked] = md->exportDataSize;
718     totalPluginExportData += md->exportDataSize;
719 
720     /* pass hookConf to plugin */
721     newPlugin->ufptr.funcPtrs.setPluginConf(hookConf, &(yfctx[yaf_hooked]));
722 
723     /* pass hookOpts to plugin */
724     newPlugin->ufptr.funcPtrs.setPluginOpt(hookOpts, yfctx[yaf_hooked]);
725 
726     /** mark that another plugin has been hooked */
727     yaf_hooked++;
728 
729     return TRUE;
730 }
731 
732 #if YAF_ENABLE_APPLABEL
733 /**
734  * yfHookScanPayload
735  *
736  *
737  */
738 void
yfHookScanPayload(yfFlow_t * flow,const uint8_t * pkt,size_t caplen,pcre * expression,uint16_t offset,uint16_t elementID,uint16_t applabel)739 yfHookScanPayload (
740     yfFlow_t *flow,
741     const uint8_t *pkt,
742     size_t caplen,
743     pcre *expression,
744     uint16_t offset,
745     uint16_t elementID,
746     uint16_t applabel)
747 
748 {
749     yfHookPlugin_t     *pluginIndex;
750     unsigned int       loop = 0;
751 
752     pluginIndex = headPlugin;
753 
754     for (loop = 0; loop < yaf_hooked; loop++) {
755         if (NULL == pluginIndex) {
756             break;
757         }
758         (pluginIndex->ufptr.funcPtrs.scanPayload)((flow->hfctx)[loop], flow,
759                                                   pkt, caplen, expression,
760                                                   offset, elementID, applabel);
761 
762         pluginIndex = pluginIndex->next;
763     }
764     return;
765 }
766 
767 #endif
768 
769 /**
770  *yfHookGetTemplateCount
771  *
772  *
773  */
774 uint8_t
yfHookGetTemplateCount(yfFlow_t * flow)775 yfHookGetTemplateCount(
776     yfFlow_t *flow)
777 {
778 
779     uint8_t count = 0;
780     unsigned int loop;
781     yfHookPlugin_t   *pluginIndex;
782 
783     pluginIndex = headPlugin;
784 
785     for (loop = 0; loop < yaf_hooked; loop++) {
786         if (NULL == pluginIndex) {
787             break;
788         }
789         count += ((pluginIndex->ufptr.funcPtrs.getTemplateCount)((flow->hfctx)[loop], flow));
790         pluginIndex = pluginIndex->next;
791     }
792     return count;
793 }
794 
795 /**
796  * yfHookFreeLists
797  *
798  *
799  */
800 void
yfHookFreeLists(yfFlow_t * flow)801 yfHookFreeLists(
802     yfFlow_t *flow)
803 {
804     unsigned int loop;
805     yfHookPlugin_t *pluginIndex;
806 
807     pluginIndex = headPlugin;
808 
809     for (loop = 0; loop < yaf_hooked; loop++) {
810         if (NULL == pluginIndex) {
811             break;
812         }
813         (pluginIndex->ufptr.funcPtrs.freeLists)((flow->hfctx)[loop], flow);
814         pluginIndex = pluginIndex->next;
815     }
816 }
817 
818 #endif
819