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