1 /*
2 ** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved.
3 ** Copyright (C) 2010-2013 Sourcefire, Inc.
4 ** Author: Michael R. Altizer <mialtize@cisco.com>
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU General Public License Version 2 as
8 ** published by the Free Software Foundation.  You may not use, modify or
9 ** distribute this program under any other version of the GNU General
10 ** Public License.
11 **
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 ** GNU General Public License for more details.
16 **
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program; if not, write to the Free Software
19 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20 */
21 
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 
26 #ifndef WIN32
27 #include <dirent.h>
28 #include <dlfcn.h>
29 #include <inttypes.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35 #include <unistd.h>
36 #if defined(HPUX)
37 #define MODULE_EXT ".sl"
38 #else
39 #define MODULE_EXT ".so"
40 #endif
41 
42 #define dlclose_func "dlclose"
43 #define dlopen_func_name "dlopen"
44 #define dlsym_func_name "dlsym"
45 
46 #else /* !WIN32 */
47 #include <windows.h>
48 #include <inttypes.h>
49 #include <unistd.h>
50 #include <sys/types.h>
51 #include <sys/stat.h>
52 #define MODULE_EXT "dll"
53 
54 #define dlclose(args) FreeLibrary(args)
55 #define dlclose_func_name "FreeLibrary"
56 #define dlopen(path, arg2) LoadLibrary(path)
57 #define dlopen_func_name "LoadLibrary"
58 #define dlsym(handle, func) GetProcAddress(handle, func)
59 #define dlsym_func_name "GetProcAddress"
60 #define dlerror() GetLastError()
61 
62 #define getcwd _getcwd
63 #ifndef PATH_MAX
64 #define PATH_MAX MAX_PATH
65 #endif
66 
67 #endif
68 
69 #include "daq.h"
70 #include "daq_api.h"
71 #include "daq_version.h"
72 
73 #define NAME_SIZE       512
74 
75 #ifdef STATIC_MODULE_LIST
76 extern const DAQ_Module_t *static_modules[];
77 extern const int num_static_modules;
78 #endif
79 
80 static int daq_verbosity = 0;
81 
82 #ifdef WIN32
DEBUG(char * fmt,...)83 inline void DEBUG(char *fmt, ...)
84 {
85 
86     if (daq_verbosity > 0)
87     {
88         va_list ap;
89         va_start(ap, fmt);
90 
91         printf(fmt, ap);
92 
93         va_end(ap);
94     }
95 }
96 #else
97 #define DEBUG(...) do { if (daq_verbosity > 0) { printf(__VA_ARGS__); } } while (0)
98 #endif
99 
100 typedef struct _daq_list_node
101 {
102     const DAQ_Module_t *module;
103     void *dl_handle;
104     struct _daq_list_node *next;
105 } DAQ_ListNode_t;
106 
107 static DAQ_ListNode_t *module_list = NULL;
108 static int num_modules = 0;
109 
110 static const char *daq_verdict_strings[MAX_DAQ_VERDICT] = {
111     "pass",         // DAQ_VERDICT_PASS
112     "block",        // DAQ_VERDICT_BLOCK
113     "replace",      // DAQ_VERDICT_REPLACE
114     "whitelist",    // DAQ_VERDICT_WHITELIST
115     "blacklist",    // DAQ_VERDICT_BLACKLIST
116     "ignore",       // DAQ_VERDICT_IGNORE
117     "retry"         // DAQ_VERDICT_RETRY
118 };
119 
120 static const char *daq_mode_strings[MAX_DAQ_MODE] = {
121     "passive",      // DAQ_MODE_PASSIVE
122     "inline",       // DAQ_MODE_INLINE
123     "read-file"     // DAQ_MODE_READ_FILE
124 };
125 
126 static const char *daq_state_strings[MAX_DAQ_STATE] = {
127     "uninitialized",    // DAQ_STATE_UNINITIALIZED
128     "initialized",      // DAQ_STATE_INITIALIZED
129     "started",          // DAQ_STATE_STARTED
130     "stopped",          // DAQ_STATE_STOPPED
131     "unknown"           // DAQ_STATE_UNKNOWN
132 };
133 
daq_verdict_string(DAQ_Verdict verdict)134 DAQ_LINKAGE const char *daq_verdict_string(DAQ_Verdict verdict)
135 {
136     if (verdict >= MAX_DAQ_VERDICT)
137         return NULL;
138 
139     return daq_verdict_strings[verdict];
140 }
141 
daq_mode_string(DAQ_Mode mode)142 DAQ_LINKAGE const char *daq_mode_string(DAQ_Mode mode)
143 {
144     if (mode >= MAX_DAQ_MODE)
145         return NULL;
146 
147     return daq_mode_strings[mode];
148 }
149 
daq_state_string(DAQ_State state)150 DAQ_LINKAGE const char *daq_state_string(DAQ_State state)
151 {
152     if (state >= MAX_DAQ_STATE)
153         return NULL;
154 
155     return daq_state_strings[state];
156 }
157 
daq_find_module(const char * name)158 DAQ_LINKAGE const DAQ_Module_t *daq_find_module(const char *name)
159 {
160     DAQ_ListNode_t *node;
161 
162     for (node = module_list; node; node = node->next)
163     {
164         if (!strcmp(name, node->module->name))
165             return node->module;
166     }
167 
168     return NULL;
169 }
170 
register_module(const DAQ_Module_t * dm,void * dl_handle)171 static int register_module(const DAQ_Module_t *dm, void *dl_handle)
172 {
173     DAQ_ListNode_t *node;
174 
175     /* Check to make sure the module's API version matches ours. */
176     if (dm->api_version != DAQ_API_VERSION)
177     {
178         fprintf(stderr, "%s: Module API version (0x%x) differs from expected version (0x%x)\n",
179                 dm->name, dm->api_version, DAQ_API_VERSION);
180         return DAQ_ERROR;
181     }
182 
183     /* Check to make sure that ALL of the function pointers are populated. */
184     if (!dm->initialize || !dm->set_filter || !dm->start || !dm->acquire || !dm->inject || !dm->breakloop ||
185         !dm->stop || !dm->shutdown || !dm->check_status || !dm->get_stats || !dm->reset_stats ||
186         !dm->get_snaplen || !dm->get_capabilities || !dm->get_errbuf || !dm->set_errbuf || !dm->get_device_index)
187     {
188         fprintf(stderr, "%s: Module definition is missing function pointer(s)!\n", dm->name);
189         return DAQ_ERROR;
190     }
191 
192     /* Do we already have a module with the same name loaded? */
193     for (node = module_list; node; node = node->next)
194     {
195         if (!strcmp(node->module->name, dm->name))
196             break;
197     }
198 
199     /* If so, and this version is newer, use it instead.  Otherwise, create a new node. */
200     if (node)
201     {
202         if (node->module->module_version >= dm->module_version)
203         {
204             DEBUG("DAQ module with name '%s' was already loaded with version %u (versus %u)!\n",
205                     node->module->name, node->module->module_version, dm->module_version);
206             return DAQ_ERROR_EXISTS;
207         }
208         if (node->dl_handle)
209         {
210             dlclose(node->dl_handle);
211         }
212     }
213     else
214     {
215         node = calloc(1, sizeof(DAQ_ListNode_t));
216         if (!node)
217             return DAQ_ERROR_NOMEM;
218         node->next = module_list;
219         module_list = node;
220         num_modules++;
221     }
222 
223     DEBUG("Registered daq module: %s\n", dm->name);
224     node->module = dm;
225     node->dl_handle = dl_handle;
226 
227     return DAQ_SUCCESS;
228 }
229 
daq_load_module(const char * filename)230 static int daq_load_module(const char *filename)
231 {
232     const DAQ_Module_t *dm;
233     struct stat fs;
234     void *dl_handle;
235     int rval;
236 
237     if (filename == NULL)
238         return DAQ_ERROR_INVAL;
239 
240     if ((stat(filename, &fs)) != 0 || !(fs.st_mode & S_IFREG))
241     {
242         fprintf(stderr, "%s: File does not exist.\n", filename);
243         return DAQ_ERROR;
244     }
245 
246     if ((dl_handle = dlopen(filename, RTLD_NOW)) == NULL)
247     {
248         fprintf(stderr, "%s: %s: %s\n", filename, dlopen_func_name, dlerror());
249         return DAQ_ERROR;
250     }
251 
252     if ((dm = (const DAQ_Module_t*)dlsym(dl_handle, "DAQ_MODULE_DATA")) == NULL)
253     {
254         fprintf(stderr, "%s: %s: %s\n", filename, dlsym_func_name, dlerror());
255         dlclose(dl_handle);
256         return DAQ_ERROR;
257     }
258 
259     if ((rval = register_module(dm, dl_handle)) != DAQ_SUCCESS)
260     {
261         if (rval != DAQ_ERROR_EXISTS)
262             fprintf(stderr, "%s: Failed to register DAQ module.\n", filename);
263         dlclose(dl_handle);
264         return DAQ_ERROR;
265     }
266 
267     return DAQ_SUCCESS;
268 }
269 
270 #ifdef STATIC_MODULE_LIST
load_static_modules(void)271 static void load_static_modules(void)
272 {
273     const DAQ_Module_t *dm;
274     int i;
275 
276     DEBUG("Static modules: %d\n", num_static_modules);
277     for (i = 0; i < num_static_modules; i++)
278     {
279         dm = static_modules[i];
280         if (register_module(dm, NULL) != DAQ_SUCCESS)
281             fprintf(stderr, "%s (%d): Failed to register static DAQ module.\n", dm->name, i);
282     }
283 }
284 #endif
285 
daq_load_modules(const char * directory_list[])286 DAQ_LINKAGE int daq_load_modules(const char *directory_list[])
287 {
288     static const char *extension = MODULE_EXT;
289 #ifndef WIN32
290     char dirpath[NAME_SIZE];
291     DIR *dirp;
292     struct dirent *de;
293     char *p;
294     int ret;
295 
296 #ifdef STATIC_MODULE_LIST
297     load_static_modules();
298 #endif
299 
300     for (; directory_list && *directory_list; directory_list++)
301     {
302         if (!(**directory_list))
303             continue;
304         if ((dirp = opendir(*directory_list)) == NULL)
305         {
306             fprintf(stderr,"Unable to open directory \"%s\"\n", *directory_list);
307             continue;
308         }
309 
310         DEBUG("Loading modules in: %s\n", *directory_list);
311 
312         while((de = readdir(dirp)) != NULL)
313         {
314             p = strrchr(de->d_name, '.');
315             if (!p || strcmp(p, extension))
316                 continue;
317             snprintf(dirpath, sizeof(dirpath), "%s/%s", *directory_list, de->d_name);
318 
319             ret = daq_load_module(dirpath);
320             if (ret == DAQ_SUCCESS)
321             {
322                 DEBUG("Found module %s\n", de->d_name);
323             }
324             else if (ret == DAQ_ERROR_NOMEM)
325             {
326                 closedir(dirp);
327                 return DAQ_ERROR_NOMEM;
328             }
329         }
330         closedir(dirp);
331     }
332 #else
333     /* Find all shared library files in path */
334     char path_buf[PATH_MAX];
335     char dyn_lib_name[PATH_MAX];
336     char drive[_MAX_DRIVE];
337     char dir[_MAX_DIR];
338     char fname[_MAX_FNAME];
339     char ext[_MAX_EXT];
340     HANDLE fSearch;
341     WIN32_FIND_DATA FindFileData;
342     int pathLen = 0;
343     const char *directory;
344     int useDrive = 0;
345 
346 #ifdef STATIC_MODULE_LIST
347     load_static_modules();
348 #endif
349 
350     for (; directory_list && *directory_list; directory_list++)
351     {
352         if (!(**directory_list))
353             continue;
354 
355         if ((strncpy(path_buf, *directory_list, PATH_MAX) == NULL) ||
356             (strlen(path_buf) != strlen(*directory_list)))
357         {
358             fprintf(stderr, "Path is too long: %s\n", *directory_list);
359             continue;
360         }
361 
362         pathLen = strlen(path_buf);
363         if ((path_buf[pathLen - 1] == '\\') ||
364             (path_buf[pathLen - 1] == '/'))
365         {
366             /* A directory was specified with trailing dir character */
367             _splitpath(path_buf, drive, dir, fname, ext);
368             _makepath(path_buf, drive, dir, "*", MODULE_EXT);
369             directory = &dir[0];
370             useDrive = 1;
371         }
372         else /* A directory was specified */
373         {
374             _splitpath(path_buf, drive, dir, fname, ext);
375             if (strcmp(extension, ""))
376             {
377                 fprintf(stderr, "Improperly formatted directory name: %s\n", *directory_list);
378                 continue;
379             }
380 
381             _makepath(path_buf, "", path_buf, "*", MODULE_EXT);
382             directory = *directory_list;
383         }
384 
385         fSearch = FindFirstFile(path_buf, &FindFileData);
386         while (fSearch != NULL && fSearch != (HANDLE)-1)
387         {
388             if (useDrive)
389                 _makepath(dyn_lib_name, drive, directory, FindFileData.cFileName, NULL);
390             else
391                 _makepath(dyn_lib_name, NULL, directory, FindFileData.cFileName, NULL);
392 
393             daq_load_module(dyn_lib_name);
394 
395             if (!FindNextFile(fSearch, &FindFileData))
396             {
397                 break;
398             }
399         }
400         FindClose(fSearch);
401     }
402 #endif
403     return DAQ_SUCCESS;
404 }
405 
daq_unload_modules(void)406 DAQ_LINKAGE void daq_unload_modules(void)
407 {
408     DAQ_ListNode_t *node;
409 
410     while (module_list)
411     {
412         node = module_list;
413         module_list = node->next;
414         if (node->dl_handle)
415         {
416             dlclose(node->dl_handle);
417         }
418         free(node);
419         num_modules--;
420     }
421 }
422 
daq_print_stats(DAQ_Stats_t * stats,FILE * fp)423 DAQ_LINKAGE void daq_print_stats(DAQ_Stats_t *stats, FILE *fp)
424 {
425     if (!stats)
426         return;
427 
428     if (!fp)
429         fp = stdout;
430 
431     fprintf(fp, "*DAQ Module Statistics*\n");
432     fprintf(fp, "  Hardware Packets Received:  %" PRIu64 "\n", stats->hw_packets_received);
433     fprintf(fp, "  Hardware Packets Dropped:   %" PRIu64 "\n", stats->hw_packets_dropped);
434     fprintf(fp, "  Packets Received:   %" PRIu64 "\n", stats->packets_received);
435     fprintf(fp, "  Packets Filtered:   %" PRIu64 "\n", stats->packets_filtered);
436     fprintf(fp, "  Packets Passed:     %" PRIu64 "\n", stats->verdicts[DAQ_VERDICT_PASS]);
437     fprintf(fp, "  Packets Replaced:   %" PRIu64 "\n", stats->verdicts[DAQ_VERDICT_REPLACE]);
438     fprintf(fp, "  Packets Blocked:    %" PRIu64 "\n", stats->verdicts[DAQ_VERDICT_BLOCK]);
439     fprintf(fp, "  Packets Injected:   %" PRIu64 "\n", stats->packets_injected);
440     fprintf(fp, "  Flows Whitelisted:  %" PRIu64 "\n", stats->verdicts[DAQ_VERDICT_WHITELIST]);
441     fprintf(fp, "  Flows Blacklisted:  %" PRIu64 "\n", stats->verdicts[DAQ_VERDICT_BLACKLIST]);
442     fprintf(fp, "  Flows Ignored:      %" PRIu64 "\n", stats->verdicts[DAQ_VERDICT_IGNORE]);
443 }
444 
daq_get_module_list(DAQ_Module_Info_t * list[])445 DAQ_LINKAGE int daq_get_module_list(DAQ_Module_Info_t *list[])
446 {
447     DAQ_Module_Info_t *info;
448     DAQ_ListNode_t *node;
449     int idx;
450 
451     if (!list)
452         return DAQ_ERROR_INVAL;
453 
454     info = calloc(num_modules, sizeof(DAQ_Module_Info_t));
455     if (!info)
456         return DAQ_ERROR_NOMEM;
457 
458     idx = 0;
459     for (node = module_list; node; node = node->next)
460     {
461         info[idx].name = strdup(node->module->name);
462         if (info[idx].name == NULL)
463         {
464             daq_free_module_list(info, idx);
465             return DAQ_ERROR_NOMEM;
466         }
467         info[idx].version = node->module->module_version;
468         info[idx].type = node->module->type;
469         idx++;
470     }
471 
472     *list = info;
473 
474     return num_modules;
475 }
476 
daq_free_module_list(DAQ_Module_Info_t * list,int size)477 DAQ_LINKAGE void daq_free_module_list(DAQ_Module_Info_t *list, int size)
478 {
479     int idx;
480 
481     if (!list || size < 0)
482         return;
483 
484     for (idx = 0; idx < size; idx++)
485     {
486         if (list[idx].name)
487             free(list[idx].name);
488     }
489 
490     free(list);
491 }
492 
daq_set_verbosity(int level)493 DAQ_LINKAGE void daq_set_verbosity(int level)
494 {
495     daq_verbosity = level;
496     DEBUG("DAQ verbosity level is set to %d.\n", daq_verbosity);
497 }
498 
daq_config_get_value(DAQ_Config_t * config,const char * key)499 DAQ_LINKAGE const char *daq_config_get_value(DAQ_Config_t *config, const char *key)
500 {
501     DAQ_Dict *entry;
502 
503     if (!config || !key)
504         return NULL;
505 
506     for (entry = config->values; entry; entry = entry->next)
507     {
508         if (!strcmp(entry->key, key))
509             return entry->value;
510     }
511 
512     return NULL;
513 }
514 
daq_config_set_value(DAQ_Config_t * config,const char * key,const char * value)515 DAQ_LINKAGE void daq_config_set_value(DAQ_Config_t *config, const char *key, const char *value)
516 {
517     DAQ_Dict *entry, *new_entry;
518     char *new_value;
519 
520     if (!config || !key)
521         return;
522 
523     for (entry = config->values; entry; entry = entry->next)
524     {
525         if (!strcmp(entry->key, key))
526             break;
527     }
528 
529     if (!entry)
530     {
531         new_entry = calloc(1, sizeof(struct _daq_dict_entry));
532         if (!new_entry)
533         {
534             fprintf(stderr, "%s: Could not allocate %lu bytes for a dictionary entry!\n",
535                     __func__, (unsigned long) sizeof(struct _daq_dict_entry));
536             return;
537         }
538         new_entry->key = strdup(key);
539         if (!new_entry->key)
540         {
541             fprintf(stderr, "%s: Could not allocate %lu bytes for a dictionary entry key!\n",
542                     __func__, (unsigned long) (strlen(key) + 1));
543             free(new_entry);
544             return;
545         }
546         entry = new_entry;
547     }
548     else
549         new_entry = NULL;
550 
551     if (value)
552     {
553         new_value = strdup(value);
554         if (!new_value)
555         {
556             fprintf(stderr, "%s: Could not allocate %lu bytes for a dictionary entry value!\n",
557                     __func__, (unsigned long) (strlen(value) + 1));
558             if (new_entry)
559                 free(new_entry);
560             return;
561         }
562         if (entry->value)
563             free(entry->value);
564         entry->value = new_value;
565     }
566     else if (entry->value)
567     {
568         free(entry->value);
569         entry->value = NULL;
570     }
571 
572     if (new_entry)
573     {
574         new_entry->next = config->values;
575         config->values = new_entry;
576     }
577 
578     DEBUG("Set config dictionary entry '%s' => '%s'.\n", entry->key, entry->value);
579 }
580 
daq_config_clear_value(DAQ_Config_t * config,const char * key)581 DAQ_LINKAGE void daq_config_clear_value(DAQ_Config_t *config, const char *key)
582 {
583     DAQ_Dict *entry, *prev = NULL;
584 
585     if (!config || !key)
586         return;
587 
588     for (entry = config->values; entry; entry = entry->next)
589     {
590         if (!strcmp(entry->key, key))
591         {
592             if (prev)
593                 prev->next = entry->next;
594             else
595                 config->values = entry->next;
596             free(entry->key);
597             free(entry->value);
598             free(entry);
599             return;
600         }
601         prev = entry;
602     }
603 }
604 
daq_config_clear_values(DAQ_Config_t * config)605 DAQ_LINKAGE void daq_config_clear_values(DAQ_Config_t *config)
606 {
607     DAQ_Dict *entry;
608 
609     if (!config)
610         return;
611 
612     while (config->values)
613     {
614         entry = config->values;
615         config->values = entry->next;
616         free(entry->key);
617         free(entry->value);
618         free(entry);
619     }
620 }
621 
daq_version_number(void)622 DAQ_LINKAGE uint32_t daq_version_number(void)
623 {
624     return DAQ_VERSION_NUMERIC;
625 }
626 
daq_version_string(void)627 DAQ_LINKAGE const char *daq_version_string(void)
628 {
629     return DAQ_VERSION_STRING;
630 }
631