1 /*
2 pmacct (Promiscuous mode IP Accounting package)
3 pmacct is Copyright (C) 2003-2020 by Paolo Lucente
4 */
5
6 /*
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */
21
22 /* includes */
23 #include "pmacct.h"
24 #include "pmacct-data.h"
25 #include "pmacct-dlt.h"
26 #include "pretag_handlers.h"
27 #include "plugin_hooks.h"
28 #include "pkt_handlers.h"
29 #include "ip_frag.h"
30 #include "ip_flow.h"
31 #include "net_aggr.h"
32 #include "thread_pool.h"
33 #include "bgp/bgp.h"
34 #include "classifier.h"
35 #include "isis/isis.h"
36 #include "bmp/bmp.h"
37 #if defined (WITH_NDPI)
38 #include "ndpi/ndpi.h"
39 #include "ndpi/ndpi_util.h"
40 #endif
41 #include "jhash.h"
42
43 /* variables to be exported away */
44 extern struct channels_list_entry channels_list[MAX_N_PLUGINS]; /* communication channels: core <-> plugins */
45
46 /* Functions */
usage_daemon(char * prog_name)47 void usage_daemon(char *prog_name)
48 {
49 printf("%s %s (%s)\n", PMACCTD_USAGE_HEADER, PMACCT_VERSION, PMACCT_BUILD);
50 printf("Usage: %s [ -D | -d ] [ -i interface ] [ -c primitive [ , ... ] ] [ -P plugin [ , ... ] ] [ filter ]\n", prog_name);
51 printf(" %s [ -f config_file ]\n", prog_name);
52 printf(" %s [ -h ]\n", prog_name);
53 printf("\nGeneral options:\n");
54 printf(" -h \tShow this page\n");
55 printf(" -V \tShow version and compile-time options and exit\n");
56 printf(" -f \tLoad configuration from the specified file\n");
57 printf(" -a \tPrint list of supported aggregation primitives\n");
58 printf(" -c \tAggregation method, see full list of primitives with -a (DEFAULT: src_host)\n");
59 printf(" -D \tDaemonize\n");
60 printf(" -N \tDisable promiscuous mode\n");
61 printf(" -z \tAllow to run with non root privileges (ie. setcap in use)\n");
62 printf(" -n \tPath to a file containing networks and/or ASNs definitions\n");
63 printf(" -t \tPath to a file containing ports definitions\n");
64 printf(" -P \t[ memory | print | mysql | pgsql | sqlite3 | amqp | kafka | nfprobe | sfprobe ] \n\tActivate plugin\n");
65 printf(" -d \tEnable debug\n");
66 printf(" -i \tListen on the specified interface\n");
67 printf(" -I \tRead packets from the specified savefile\n");
68 printf(" -S \t[ auth | mail | daemon | kern | user | local[0-7] ] \n\tLog to the specified syslog facility\n");
69 printf(" -F \tWrite Core Process PID into the specified file\n");
70 printf(" -w \tWait for the listening interface to become available\n");
71 printf(" -Z \tReading from a savefile, sleep the given amount of seconds at startup and between replays\n");
72 printf(" -W \tReading from a savefile, don't exit but sleep when finished\n");
73 printf(" -Y \tReading from a savefile, replay the number of times specified\n");
74 printf(" -R \tRenormalize sampled data\n");
75 printf(" -L \tSet snapshot length\n");
76 printf(" -u \tLeave IP protocols in numerical format\n");
77 printf("\nMemory plugin (-P memory) options:\n");
78 printf(" -p \tSocket for client-server communication (DEFAULT: /tmp/collect.pipe)\n");
79 printf(" -b \tNumber of buckets\n");
80 printf(" -m \tNumber of memory pools\n");
81 printf(" -s \tMemory pool size\n");
82 printf("\nPrint plugin (-P print) plugin options:\n");
83 printf(" -r \tRefresh time (in seconds)\n");
84 printf(" -O \t[ formatted | csv | json | avro ] \n\tOutput format\n");
85 printf(" -o \tPath to output file\n");
86 printf(" -M \tPrint event init/close marker messages\n");
87 printf(" -A \tAppend output (applies to -o)\n");
88 printf(" -E \tCSV format separator (applies to -O csv, DEFAULT: ',')\n");
89 printf("\n");
90 printf("For examples, see:\n");
91 printf(" https://github.com/pmacct/pmacct/blob/master/QUICKSTART or\n");
92 printf(" https://github.com/pmacct/pmacct/wiki\n");
93 printf("\n");
94 printf("For suggestions, critics, bugs, contact me: %s.\n", MANTAINER);
95 }
96
pm_pcap_device_copy_all(struct pm_pcap_devices * dst,struct pm_pcap_devices * src)97 void pm_pcap_device_copy_all(struct pm_pcap_devices *dst, struct pm_pcap_devices *src)
98 {
99 memcpy(dst, src, sizeof(struct pm_pcap_devices));
100 }
101
pm_pcap_device_copy_entry(struct pm_pcap_devices * dst,struct pm_pcap_devices * src,int src_idx)102 void pm_pcap_device_copy_entry(struct pm_pcap_devices *dst, struct pm_pcap_devices *src, int src_idx)
103 {
104 memcpy(&dst->list[dst->num], &src->list[src_idx], sizeof(struct pm_pcap_device));
105 dst->num++;
106 }
107
pm_pcap_device_getindex_byifname(struct pm_pcap_devices * map,char * ifname)108 int pm_pcap_device_getindex_byifname(struct pm_pcap_devices *map, char *ifname)
109 {
110 int loc_idx;
111 for (loc_idx = 0; loc_idx < map->num; loc_idx++) {
112 if (strlen(map->list[loc_idx].str) == strlen(ifname) && !strncmp(map->list[loc_idx].str, ifname, strlen(ifname))) {
113 return loc_idx;
114 }
115 }
116
117 return ERR;
118 }
119
pm_pcap_open(const char * dev_ptr,int snaplen,int promisc,int to_ms,int protocol,int direction,char * errbuf)120 pcap_t *pm_pcap_open(const char *dev_ptr, int snaplen, int promisc,
121 int to_ms, int protocol, int direction, char *errbuf)
122 {
123 pcap_t *p;
124 int ret;
125
126 p = pcap_create(dev_ptr, errbuf);
127 if (p == NULL) return NULL;
128
129 ret = pcap_set_snaplen(p, snaplen);
130 if (ret < 0) goto err;
131
132 ret = pcap_set_promisc(p, promisc);
133 if (ret < 0) goto err;
134
135 ret = pcap_set_timeout(p, to_ms);
136 if (ret < 0) goto err;
137
138 #ifdef PCAP_SET_PROTOCOL
139 ret = pcap_set_protocol(p, protocol);
140 if (ret < 0) goto err;
141 #else
142 if (protocol) {
143 Log(LOG_WARNING, "WARN ( %s/core ): pcap_protocol specified but linked against a version of libpcap that does not support pcap_set_protocol().\n", config.name);
144 }
145 #endif
146
147 ret = pcap_activate(p);
148 if (ret < 0) goto err;
149
150 #ifdef PCAP_SET_DIRECTION
151 ret = pcap_setdirection(p, direction);
152 if (ret < 0) goto err;
153 #endif
154
155 return p;
156
157 err:
158 if (ret == PCAP_ERROR) {
159 snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", dev_ptr, pcap_geterr(p));
160 }
161 else if (ret == PCAP_ERROR_NO_SUCH_DEVICE ||
162 ret == PCAP_ERROR_PERM_DENIED ||
163 ret == PCAP_ERROR_PROMISC_PERM_DENIED) {
164 snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s (%s)", dev_ptr, pcap_statustostr(ret), pcap_geterr(p));
165 }
166 else {
167 snprintf(errbuf, PCAP_ERRBUF_SIZE, "%s: %s", dev_ptr, pcap_statustostr(ret));
168 }
169
170 pcap_close(p);
171
172 return NULL;
173 }
174
pm_pcap_add_interface(struct pm_pcap_device * dev_ptr,char * ifname,struct pm_pcap_interface * pm_pcap_if_entry,int psize)175 int pm_pcap_add_interface(struct pm_pcap_device *dev_ptr, char *ifname, struct pm_pcap_interface *pm_pcap_if_entry, int psize)
176 {
177 /* pcap library stuff */
178 char errbuf[PCAP_ERRBUF_SIZE];
179
180 struct plugins_list_entry *list;
181 int ret = SUCCESS, attempts = FALSE, index;
182 int direction;
183
184 if (pm_pcap_if_entry && pm_pcap_if_entry->direction) direction = pm_pcap_if_entry->direction;
185 else direction = config.pcap_direction;
186
187 throttle_startup:
188 if (attempts < PCAP_MAX_ATTEMPTS) {
189 if ((dev_ptr->dev_desc = pm_pcap_open(ifname, psize, config.promisc, 1000, config.pcap_protocol, direction, errbuf)) == NULL) {
190 if (!config.pcap_if_wait) {
191 Log(LOG_ERR, "ERROR ( %s/core ): [%s] pm_pcap_open(): %s. Exiting.\n", config.name, ifname, errbuf);
192 exit_gracefully(1);
193 }
194 else {
195 sleep(PCAP_RETRY_PERIOD); /* XXX: User defined value? */
196 attempts++;
197 goto throttle_startup;
198 }
199 }
200
201 dev_ptr->active = TRUE;
202 dev_ptr->pcap_if = pm_pcap_if_entry;
203 strncpy(dev_ptr->str, ifname, (sizeof(dev_ptr->str) - 1));
204
205 if (config.pcap_ifindex == PCAP_IFINDEX_SYS)
206 dev_ptr->id = if_nametoindex(dev_ptr->str);
207 else if (config.pcap_ifindex == PCAP_IFINDEX_HASH)
208 dev_ptr->id = jhash(dev_ptr->str, strlen(dev_ptr->str), 0);
209 else if (config.pcap_ifindex == PCAP_IFINDEX_MAP) {
210 if (config.pcap_interfaces_map) {
211 dev_ptr->id = pm_pcap_interfaces_map_lookup_ifname(&pm_pcap_if_map, dev_ptr->str);
212 }
213 else {
214 Log(LOG_ERR, "ERROR ( %s/core ): pcap_ifindex set to 'map' but no pcap_interface_map is defined. Exiting.\n", config.name);
215 exit_gracefully(1);
216 }
217 }
218 else dev_ptr->id = 0;
219
220 dev_ptr->fd = pcap_fileno(dev_ptr->dev_desc);
221
222 if (config.nfacctd_pipe_size) {
223 #if defined (PCAP_TYPE_linux) || (PCAP_TYPE_snoop)
224 socklen_t slen = sizeof(config.nfacctd_pipe_size);
225 int x;
226
227 Setsocksize(pcap_fileno(dev_ptr->dev_desc), SOL_SOCKET, SO_RCVBUF, &config.nfacctd_pipe_size, slen);
228 getsockopt(pcap_fileno(dev_ptr->dev_desc), SOL_SOCKET, SO_RCVBUF, &x, &slen);
229 Log(LOG_DEBUG, "DEBUG ( %s/core ): pmacctd_pipe_size: obtained=%d target=%d.\n", config.name, x, config.nfacctd_pipe_size);
230 #endif
231 }
232
233 dev_ptr->link_type = pcap_datalink(dev_ptr->dev_desc);
234 for (index = 0; _devices[index].link_type != -1; index++) {
235 if (dev_ptr->link_type == _devices[index].link_type)
236 dev_ptr->data = &_devices[index];
237 }
238
239 load_plugin_filters(dev_ptr->link_type);
240
241 /* we need to solve some link constraints */
242 if (dev_ptr->data == NULL) {
243 Log(LOG_ERR, "ERROR ( %s/core ): data link not supported: %d\n", config.name, dev_ptr->link_type);
244 exit_gracefully(1);
245 }
246 else Log(LOG_INFO, "INFO ( %s/core ): [%s,%u] link type is: %d\n", config.name, dev_ptr->str, dev_ptr->id, dev_ptr->link_type);
247
248 if (dev_ptr->link_type != DLT_EN10MB && dev_ptr->link_type != DLT_IEEE802 && dev_ptr->link_type != DLT_LINUX_SLL) {
249 list = plugins_list;
250 while (list) {
251 if ((list->cfg.what_to_count & COUNT_SRC_MAC) || (list->cfg.what_to_count & COUNT_DST_MAC)) {
252 Log(LOG_ERR, "ERROR ( %s/core ): MAC aggregation not available for link type: %d\n", config.name, dev_ptr->link_type);
253 exit_gracefully(1);
254 }
255 list = list->next;
256 }
257 }
258
259 pm_pcap_add_filter(dev_ptr);
260 }
261 else {
262 Log(LOG_WARNING, "WARN ( %s/core ): [%s] pm_pcap_open(): giving up after too many attempts.\n", config.name, ifname);
263 ret = ERR;
264 }
265
266 return ret;
267 }
268
main(int argc,char ** argv,char ** envp)269 int main(int argc,char **argv, char **envp)
270 {
271 /* pcap library stuff */
272 struct pcap_pkthdr pkt_hdr;
273 const u_char *pkt_body;
274 pcap_if_t *pm_pcap_ifs = NULL;
275
276 int index, index_rr = 0, logf, ret;
277 int pm_pcap_savefile_round = 0;
278
279 struct plugins_list_entry *list;
280 struct plugin_requests req;
281 char config_file[SRVBUFLEN];
282 int psize = DEFAULT_SNAPLEN;
283
284 struct id_table bpas_table;
285 struct id_table blp_table;
286 struct id_table bmed_table;
287 struct id_table biss_table;
288 struct id_table bta_table;
289
290 struct pm_pcap_device *dev_ptr;
291 struct pm_pcap_callback_data cb_data;
292
293 /* select() stuff */
294 fd_set read_descs, bkp_read_descs;
295 int select_fd, bkp_select_fd;
296
297 /* getopt() stuff */
298 extern char *optarg;
299 extern int optind, opterr, optopt;
300 int errflag, cp;
301
302 struct sockaddr_storage client;
303
304 #ifdef WITH_REDIS
305 struct p_redis_host redis_host;
306 #endif
307
308 #if defined HAVE_MALLOPT
309 mallopt(M_CHECK_ACTION, 0);
310 #endif
311
312 umask(077);
313 compute_once();
314
315 /* a bunch of default definitions */
316 reload_map = FALSE;
317 reload_map_pmacctd = FALSE;
318 print_stats = FALSE;
319 reload_geoipv2_file = FALSE;
320 bpas_map_allocated = FALSE;
321 blp_map_allocated = FALSE;
322 bmed_map_allocated = FALSE;
323 biss_map_allocated = FALSE;
324 bta_map_caching = FALSE;
325 sampling_map_caching = FALSE;
326 custom_primitives_allocated = FALSE;
327 find_id_func = PM_find_id;
328 plugins_list = NULL;
329
330 errflag = 0;
331
332 memset(cfg_cmdline, 0, sizeof(cfg_cmdline));
333 memset(&config, 0, sizeof(struct configuration));
334 memset(&config_file, 0, sizeof(config_file));
335 memset(&failed_plugins, 0, sizeof(failed_plugins));
336 memset(&req, 0, sizeof(req));
337 memset(dummy_tlhdr, 0, sizeof(dummy_tlhdr));
338 memset(sll_mac, 0, sizeof(sll_mac));
339 memset(&bpas_table, 0, sizeof(bpas_table));
340 memset(&blp_table, 0, sizeof(blp_table));
341 memset(&bmed_table, 0, sizeof(bmed_table));
342 memset(&biss_table, 0, sizeof(biss_table));
343 memset(&bta_table, 0, sizeof(bta_table));
344 memset(&client, 0, sizeof(client));
345 memset(&cb_data, 0, sizeof(cb_data));
346 memset(&tunnel_registry, 0, sizeof(tunnel_registry));
347 memset(&reload_map_tstamp, 0, sizeof(reload_map_tstamp));
348 memset(&device, 0, sizeof(device));
349 memset(empty_mem_area_256b, 0, sizeof(empty_mem_area_256b));
350 pm_pcap_device_initialize(&devices);
351 pm_pcap_device_initialize(&bkp_devices);
352 log_notifications_init(&log_notifications);
353 config.acct_type = ACCT_PM;
354
355 rows = 0;
356
357 /* getting commandline values */
358 while (!errflag && ((cp = getopt(argc, argv, ARGS_PMACCTD)) != -1)) {
359 if (!cfg_cmdline[rows]) cfg_cmdline[rows] = malloc(SRVBUFLEN);
360 memset(cfg_cmdline[rows], 0, SRVBUFLEN);
361 switch (cp) {
362 case 'P':
363 strlcpy(cfg_cmdline[rows], "plugins: ", SRVBUFLEN);
364 strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows]));
365 rows++;
366 break;
367 case 'D':
368 strlcpy(cfg_cmdline[rows], "daemonize: true", SRVBUFLEN);
369 rows++;
370 break;
371 case 'z':
372 strlcpy(cfg_cmdline[rows], "pmacctd_nonroot: true", SRVBUFLEN);
373 rows++;
374 break;
375 case 'd':
376 debug = TRUE;
377 strlcpy(cfg_cmdline[rows], "debug: true", SRVBUFLEN);
378 rows++;
379 break;
380 case 'n':
381 strlcpy(cfg_cmdline[rows], "networks_file: ", SRVBUFLEN);
382 strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows]));
383 rows++;
384 break;
385 case 't':
386 strlcpy(cfg_cmdline[rows], "ports_file: ", SRVBUFLEN);
387 strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows]));
388 rows++;
389 break;
390 case 'O':
391 strlcpy(cfg_cmdline[rows], "print_output: ", SRVBUFLEN);
392 strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows]));
393 rows++;
394 break;
395 case 'o':
396 strlcpy(cfg_cmdline[rows], "print_output_file: ", SRVBUFLEN);
397 strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows]));
398 rows++;
399 break;
400 case 'M':
401 strlcpy(cfg_cmdline[rows], "print_markers: true", SRVBUFLEN);
402 rows++;
403 break;
404 case 'A':
405 strlcpy(cfg_cmdline[rows], "print_output_file_append: true", SRVBUFLEN);
406 rows++;
407 break;
408 case 'E':
409 strlcpy(cfg_cmdline[rows], "print_output_separator: ", SRVBUFLEN);
410 strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows]));
411 rows++;
412 break;
413 case 'u':
414 strlcpy(cfg_cmdline[rows], "print_num_protos: true", SRVBUFLEN);
415 rows++;
416 break;
417 case 'N':
418 strlcpy(cfg_cmdline[rows], "promisc: false", SRVBUFLEN);
419 rows++;
420 break;
421 case 'f':
422 strlcpy(config_file, optarg, sizeof(config_file));
423 free(cfg_cmdline[rows]);
424 cfg_cmdline[rows] = NULL;
425 break;
426 case 'F':
427 strlcpy(cfg_cmdline[rows], "pidfile: ", SRVBUFLEN);
428 strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows]));
429 rows++;
430 break;
431 case 'c':
432 strlcpy(cfg_cmdline[rows], "aggregate: ", SRVBUFLEN);
433 strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows]));
434 rows++;
435 break;
436 case 'b':
437 strlcpy(cfg_cmdline[rows], "imt_buckets: ", SRVBUFLEN);
438 strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows]));
439 rows++;
440 break;
441 case 'm':
442 strlcpy(cfg_cmdline[rows], "imt_mem_pools_number: ", SRVBUFLEN);
443 strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows]));
444 rows++;
445 break;
446 case 'p':
447 strlcpy(cfg_cmdline[rows], "imt_path: ", SRVBUFLEN);
448 strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows]));
449 rows++;
450 break;
451 case 'r':
452 strlcpy(cfg_cmdline[rows], "sql_refresh_time: ", SRVBUFLEN);
453 strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows]));
454 rows++;
455 break;
456 case 's':
457 strlcpy(cfg_cmdline[rows], "imt_mem_pools_size: ", SRVBUFLEN);
458 strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows]));
459 rows++;
460 break;
461 case 'S':
462 strlcpy(cfg_cmdline[rows], "syslog: ", SRVBUFLEN);
463 strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows]));
464 rows++;
465 break;
466 case 'i':
467 strlcpy(cfg_cmdline[rows], "pcap_interface: ", SRVBUFLEN);
468 strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows]));
469 rows++;
470 break;
471 case 'I':
472 strlcpy(cfg_cmdline[rows], "pcap_savefile: ", SRVBUFLEN);
473 strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows]));
474 rows++;
475 break;
476 case 'w':
477 strlcpy(cfg_cmdline[rows], "pcap_interface_wait: true", SRVBUFLEN);
478 rows++;
479 break;
480 case 'W':
481 strlcpy(cfg_cmdline[rows], "pcap_savefile_wait: true", SRVBUFLEN);
482 rows++;
483 break;
484 case 'Z':
485 strlcpy(cfg_cmdline[rows], "pcap_savefile_delay: ", SRVBUFLEN);
486 strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows]));
487 rows++;
488 break;
489 case 'Y':
490 strlcpy(cfg_cmdline[rows], "pcap_savefile_replay: ", SRVBUFLEN);
491 strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows]));
492 rows++;
493 break;
494 case 'L':
495 strlcpy(cfg_cmdline[rows], "snaplen: ", SRVBUFLEN);
496 strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows]));
497 rows++;
498 break;
499 case 'R':
500 strlcpy(cfg_cmdline[rows], "sfacctd_renormalize: true", SRVBUFLEN);
501 rows++;
502 break;
503 case 'h':
504 usage_daemon(argv[0]);
505 exit(0);
506 break;
507 case 'V':
508 version_daemon(PMACCTD_USAGE_HEADER);
509 exit(0);
510 break;
511 case 'a':
512 print_primitives(config.acct_type, PMACCTD_USAGE_HEADER);
513 exit(0);
514 break;
515 default:
516 usage_daemon(argv[0]);
517 exit(1);
518 break;
519 }
520 }
521
522 /* post-checks and resolving conflicts */
523 if (strlen(config_file)) {
524 if (parse_configuration_file(config_file) != SUCCESS)
525 exit(1);
526 }
527 else {
528 if (parse_configuration_file(NULL) != SUCCESS)
529 exit(1);
530 }
531
532 /* XXX: glue; i'm conscious it's a dirty solution from an engineering viewpoint;
533 someday later i'll fix this */
534 list = plugins_list;
535 while(list) {
536 list->cfg.acct_type = ACCT_PM;
537 set_default_preferences(&list->cfg);
538 if (!strcmp(list->type.string, "core")) {
539 memcpy(&config, &list->cfg, sizeof(struct configuration));
540 config.name = list->name;
541 config.type = list->type.string;
542 }
543 list = list->next;
544 }
545
546 if (config.files_umask) umask(config.files_umask);
547
548 /* Let's check whether we need superuser privileges */
549 if (config.snaplen) psize = config.snaplen;
550 else config.snaplen = psize;
551
552 if (!config.pcap_savefile) {
553 if (getuid() != 0 && !config.pmacctd_nonroot) {
554 printf("%s %s (%s)\n\n", PMACCTD_USAGE_HEADER, PMACCT_VERSION, PMACCT_BUILD);
555 printf("ERROR ( %s/core ): You need superuser privileges to run this command.\nExiting ...\n\n", config.name);
556 exit_gracefully(1);
557 }
558 }
559
560 initsetproctitle(argc, argv, envp);
561 if (config.syslog) {
562 logf = parse_log_facility(config.syslog);
563 if (logf == ERR) {
564 config.syslog = NULL;
565 printf("WARN ( %s/core ): specified syslog facility is not supported. Logging to standard error (stderr).\n", config.name);
566 }
567 else openlog(NULL, LOG_PID, logf);
568 Log(LOG_INFO, "INFO ( %s/core ): Start logging ...\n", config.name);
569 }
570
571 if (config.logfile) {
572 config.logfile_fd = open_output_file(config.logfile, "a", FALSE);
573 list = plugins_list;
574 while (list) {
575 list->cfg.logfile_fd = config.logfile_fd ;
576 list = list->next;
577 }
578 }
579
580 if (config.daemon) {
581 list = plugins_list;
582 while (list) {
583 if (!strcmp(list->type.string, "print") && !list->cfg.print_output_file)
584 printf("INFO ( %s/%s ): Daemonizing. Bye bye screen.\n", list->name, list->type.string);
585 list = list->next;
586 }
587
588 if (!config.syslog && !config.logfile) {
589 if (debug || config.debug) {
590 printf("WARN ( %s/core ): debug is enabled; forking in background. Logging to standard error (stderr) will get lost.\n", config.name);
591 }
592 }
593
594 daemonize();
595 }
596
597 if (config.proc_priority) {
598 int ret;
599
600 ret = setpriority(PRIO_PROCESS, 0, config.proc_priority);
601 if (ret) Log(LOG_WARNING, "WARN ( %s/core ): proc_priority failed (errno: %d)\n", config.name, errno);
602 else Log(LOG_INFO, "INFO ( %s/core ): proc_priority set to %d\n", config.name, getpriority(PRIO_PROCESS, 0));
603 }
604
605 Log(LOG_INFO, "INFO ( %s/core ): %s %s (%s)\n", config.name, PMACCTD_USAGE_HEADER, PMACCT_VERSION, PMACCT_BUILD);
606 Log(LOG_INFO, "INFO ( %s/core ): %s\n", config.name, PMACCT_COMPILE_ARGS);
607
608 if (strlen(config_file)) {
609 char canonical_path[PATH_MAX], *canonical_path_ptr;
610
611 canonical_path_ptr = realpath(config_file, canonical_path);
612 if (canonical_path_ptr) Log(LOG_INFO, "INFO ( %s/core ): Reading configuration file '%s'.\n", config.name, canonical_path);
613 }
614 else Log(LOG_INFO, "INFO ( %s/core ): Reading configuration from cmdline.\n", config.name);
615
616 /* Enforcing policies over aggregation methods */
617 list = plugins_list;
618 while (list) {
619 if (list->type.id != PLUGIN_ID_CORE) {
620 /* applies to all plugins */
621 plugin_pipe_check(&list->cfg);
622
623 if (config.classifiers_path && (list->cfg.sampling_rate || config.ext_sampling_rate)) {
624 Log(LOG_ERR, "ERROR ( %s/core ): Packet sampling and classification are mutual exclusive.\n", config.name);
625 exit_gracefully(1);
626 }
627
628 if (list->cfg.sampling_rate && config.ext_sampling_rate) {
629 Log(LOG_ERR, "ERROR ( %s/core ): Internal packet sampling and external packet sampling are mutual exclusive.\n", config.name);
630 exit_gracefully(1);
631 }
632
633 /* applies to specific plugins */
634 if (list->type.id == PLUGIN_ID_TEE) {
635 Log(LOG_ERR, "ERROR ( %s/core ): 'tee' plugin not supported in 'pmacctd'.\n", config.name);
636 exit_gracefully(1);
637 }
638 else if (list->type.id == PLUGIN_ID_NFPROBE) {
639 /* If we already renormalizing an external sampling rate,
640 we cancel the sampling information from the probe plugin */
641 if (config.sfacctd_renormalize && list->cfg.ext_sampling_rate) list->cfg.ext_sampling_rate = 0;
642
643 config.handle_fragments = TRUE;
644 list->cfg.nfprobe_what_to_count = list->cfg.what_to_count;
645 list->cfg.nfprobe_what_to_count_2 = list->cfg.what_to_count_2;
646 list->cfg.what_to_count = 0;
647 list->cfg.what_to_count_2 = 0;
648 #if defined (HAVE_L2)
649 if (list->cfg.nfprobe_version == 9 || list->cfg.nfprobe_version == 10) {
650 list->cfg.what_to_count |= COUNT_SRC_MAC;
651 list->cfg.what_to_count |= COUNT_DST_MAC;
652 list->cfg.what_to_count |= COUNT_VLAN;
653 }
654 #endif
655 list->cfg.what_to_count |= COUNT_SRC_HOST;
656 list->cfg.what_to_count |= COUNT_DST_HOST;
657
658 if (list->cfg.networks_file || list->cfg.networks_mask || list->cfg.nfacctd_net) {
659 list->cfg.what_to_count |= COUNT_SRC_NMASK;
660 list->cfg.what_to_count |= COUNT_DST_NMASK;
661 }
662
663 list->cfg.what_to_count |= COUNT_SRC_PORT;
664 list->cfg.what_to_count |= COUNT_DST_PORT;
665 list->cfg.what_to_count |= COUNT_IP_TOS;
666 list->cfg.what_to_count |= COUNT_IP_PROTO;
667 if (list->cfg.networks_file ||
668 ((list->cfg.bgp_daemon || list->cfg.bmp_daemon) && list->cfg.nfacctd_as == NF_AS_BGP)) {
669 list->cfg.what_to_count |= COUNT_SRC_AS;
670 list->cfg.what_to_count |= COUNT_DST_AS;
671 list->cfg.what_to_count |= COUNT_PEER_DST_IP;
672 }
673 if (list->cfg.nfprobe_version == 9 || list->cfg.nfprobe_version == 10) {
674 if (list->cfg.classifiers_path) {
675 list->cfg.what_to_count |= COUNT_CLASS;
676 config.handle_flows = TRUE;
677 }
678
679 if (list->cfg.nfprobe_what_to_count_2 & COUNT_NDPI_CLASS)
680 list->cfg.what_to_count_2 |= COUNT_NDPI_CLASS;
681
682 if (list->cfg.nfprobe_what_to_count_2 & COUNT_MPLS_LABEL_TOP)
683 list->cfg.what_to_count_2 |= COUNT_MPLS_LABEL_TOP;
684 }
685 if (list->cfg.pre_tag_map) {
686 list->cfg.what_to_count |= COUNT_TAG;
687 list->cfg.what_to_count |= COUNT_TAG2;
688 list->cfg.what_to_count_2 |= COUNT_LABEL;
689 }
690 list->cfg.what_to_count |= COUNT_IN_IFACE;
691 list->cfg.what_to_count |= COUNT_OUT_IFACE;
692 if ((list->cfg.what_to_count & (COUNT_STD_COMM|COUNT_EXT_COMM|COUNT_LOCAL_PREF|COUNT_MED|COUNT_AS_PATH|
693 COUNT_PEER_SRC_AS|COUNT_PEER_DST_AS|COUNT_PEER_SRC_IP|COUNT_SRC_STD_COMM|
694 COUNT_SRC_EXT_COMM|COUNT_SRC_AS_PATH|COUNT_SRC_MED|COUNT_SRC_LOCAL_PREF|
695 COUNT_MPLS_VPN_RD)) ||
696 (list->cfg.what_to_count_2 & (COUNT_LRG_COMM|COUNT_SRC_LRG_COMM|COUNT_SRC_ROA|COUNT_DST_ROA))) {
697 Log(LOG_ERR, "ERROR ( %s/core ): 'src_as', 'dst_as' and 'peer_dst_ip' are currently the only BGP-related primitives supported within the 'nfprobe' plugin.\n", config.name);
698 exit_gracefully(1);
699 }
700 list->cfg.what_to_count |= COUNT_COUNTERS;
701
702 if (list->cfg.nfacctd_as & NF_AS_FALLBACK && list->cfg.networks_file)
703 list->cfg.nfacctd_as |= NF_AS_NEW;
704
705 if (list->cfg.nfacctd_net & NF_NET_FALLBACK && list->cfg.networks_file)
706 list->cfg.nfacctd_net |= NF_NET_NEW;
707
708 list->cfg.data_type = PIPE_TYPE_METADATA;
709 list->cfg.data_type |= PIPE_TYPE_EXTRAS;
710
711 if (list->cfg.what_to_count & (COUNT_PEER_DST_IP))
712 list->cfg.data_type |= PIPE_TYPE_BGP;
713
714 if (list->cfg.what_to_count_2 & (COUNT_MPLS_LABEL_TOP))
715 list->cfg.data_type |= PIPE_TYPE_MPLS;
716
717 if (list->cfg.what_to_count_2 & (COUNT_LABEL))
718 list->cfg.data_type |= PIPE_TYPE_VLEN;
719 }
720 else if (list->type.id == PLUGIN_ID_SFPROBE) {
721 /* If we already renormalizing an external sampling rate,
722 we cancel the sampling information from the probe plugin */
723 if (config.sfacctd_renormalize && list->cfg.ext_sampling_rate) list->cfg.ext_sampling_rate = 0;
724
725 if (psize < 128) psize = config.snaplen = 128; /* SFL_DEFAULT_HEADER_SIZE */
726 list->cfg.what_to_count = COUNT_PAYLOAD;
727 list->cfg.what_to_count_2 = 0;
728 if (list->cfg.classifiers_path) {
729 list->cfg.what_to_count |= COUNT_CLASS;
730 config.handle_fragments = TRUE;
731 config.handle_flows = TRUE;
732 }
733 #if defined (WITH_NDPI)
734 if (list->cfg.ndpi_num_roots) list->cfg.what_to_count_2 |= COUNT_NDPI_CLASS;
735 #endif
736 if (list->cfg.networks_file ||
737 ((list->cfg.bgp_daemon || list->cfg.bmp_daemon) && list->cfg.nfacctd_as == NF_AS_BGP)) {
738 list->cfg.what_to_count |= COUNT_SRC_AS;
739 list->cfg.what_to_count |= COUNT_DST_AS;
740 list->cfg.what_to_count |= COUNT_PEER_DST_IP;
741 }
742 if (list->cfg.networks_file || list->cfg.networks_mask || list->cfg.nfacctd_net) {
743 list->cfg.what_to_count |= COUNT_SRC_NMASK;
744 list->cfg.what_to_count |= COUNT_DST_NMASK;
745 }
746 if (list->cfg.pre_tag_map) {
747 list->cfg.what_to_count |= COUNT_TAG;
748 list->cfg.what_to_count |= COUNT_TAG2;
749 }
750 if ((list->cfg.what_to_count & (COUNT_STD_COMM|COUNT_EXT_COMM|COUNT_LOCAL_PREF|COUNT_MED|COUNT_AS_PATH|
751 COUNT_PEER_SRC_AS|COUNT_PEER_DST_AS|COUNT_PEER_SRC_IP|COUNT_SRC_STD_COMM|
752 COUNT_SRC_EXT_COMM|COUNT_SRC_AS_PATH|COUNT_SRC_MED|COUNT_SRC_LOCAL_PREF|
753 COUNT_MPLS_VPN_RD)) ||
754 (list->cfg.what_to_count_2 & (COUNT_LRG_COMM|COUNT_SRC_LRG_COMM|COUNT_SRC_ROA|COUNT_DST_ROA))) {
755 Log(LOG_ERR, "ERROR ( %s/core ): 'src_as', 'dst_as' and 'peer_dst_ip' are currently the only BGP-related primitives supported within the 'sfprobe' plugin.\n", config.name);
756 exit_gracefully(1);
757 }
758
759 #if defined (HAVE_L2)
760 list->cfg.what_to_count |= COUNT_VLAN;
761 list->cfg.what_to_count |= COUNT_COS;
762 #endif
763
764 if (list->cfg.nfacctd_as & NF_AS_FALLBACK && list->cfg.networks_file)
765 list->cfg.nfacctd_as |= NF_AS_NEW;
766
767 if (list->cfg.nfacctd_net & NF_NET_FALLBACK && list->cfg.networks_file)
768 list->cfg.nfacctd_net |= NF_NET_NEW;
769
770 list->cfg.data_type = PIPE_TYPE_PAYLOAD;
771 }
772 else {
773 if (list->cfg.what_to_count_2 & (COUNT_POST_NAT_SRC_HOST|COUNT_POST_NAT_DST_HOST|
774 COUNT_POST_NAT_SRC_PORT|COUNT_POST_NAT_DST_PORT|COUNT_NAT_EVENT|
775 COUNT_TIMESTAMP_START|COUNT_TIMESTAMP_END|COUNT_TIMESTAMP_ARRIVAL))
776 list->cfg.data_type |= PIPE_TYPE_NAT;
777
778 if (list->cfg.what_to_count_2 & (COUNT_MPLS_LABEL_TOP|COUNT_MPLS_LABEL_BOTTOM|
779 COUNT_MPLS_STACK_DEPTH))
780 list->cfg.data_type |= PIPE_TYPE_MPLS;
781
782 if (list->cfg.what_to_count_2 & (COUNT_TUNNEL_SRC_MAC|COUNT_TUNNEL_DST_MAC|
783 COUNT_TUNNEL_SRC_HOST|COUNT_TUNNEL_DST_HOST|COUNT_TUNNEL_IP_PROTO|
784 COUNT_TUNNEL_IP_TOS|COUNT_TUNNEL_SRC_PORT|COUNT_TUNNEL_DST_PORT|
785 COUNT_VXLAN)) {
786 list->cfg.data_type |= PIPE_TYPE_TUN;
787 cb_data.has_tun_prims = TRUE;
788 }
789
790 if (list->cfg.what_to_count_2 & (COUNT_LABEL))
791 list->cfg.data_type |= PIPE_TYPE_VLEN;
792
793 evaluate_sums(&list->cfg.what_to_count, &list->cfg.what_to_count_2, list->name, list->type.string);
794 if (list->cfg.what_to_count & (COUNT_SRC_PORT|COUNT_DST_PORT|COUNT_SUM_PORT|COUNT_TCPFLAGS))
795 config.handle_fragments = TRUE;
796 if (list->cfg.what_to_count & COUNT_FLOWS) {
797 config.handle_fragments = TRUE;
798 config.handle_flows = TRUE;
799 }
800 if (list->cfg.what_to_count & COUNT_CLASS) {
801 config.handle_fragments = TRUE;
802 config.handle_flows = TRUE;
803 }
804 if (!list->cfg.what_to_count && !list->cfg.what_to_count_2 && !list->cfg.cpptrs.num) {
805 Log(LOG_WARNING, "WARN ( %s/%s ): defaulting to SRC HOST aggregation.\n", list->name, list->type.string);
806 list->cfg.what_to_count |= COUNT_SRC_HOST;
807 }
808 if (list->cfg.what_to_count & (COUNT_SRC_AS|COUNT_DST_AS|COUNT_SUM_AS)) {
809 if (!list->cfg.networks_file && list->cfg.nfacctd_as != NF_AS_BGP) {
810 Log(LOG_ERR, "ERROR ( %s/%s ): AS aggregation selected but NO 'networks_file' or 'pmacctd_as' are specified. Exiting...\n\n", list->name, list->type.string);
811 exit_gracefully(1);
812 }
813 if (list->cfg.nfacctd_as & NF_AS_FALLBACK && list->cfg.networks_file)
814 list->cfg.nfacctd_as |= NF_AS_NEW;
815 }
816 if (list->cfg.what_to_count & (COUNT_SRC_NET|COUNT_DST_NET|COUNT_SUM_NET|COUNT_SRC_NMASK|COUNT_DST_NMASK|COUNT_PEER_DST_IP)) {
817 if (!list->cfg.nfacctd_net) {
818 if (list->cfg.networks_file) list->cfg.nfacctd_net |= NF_NET_NEW;
819 if (list->cfg.networks_mask) list->cfg.nfacctd_net |= NF_NET_STATIC;
820 if (!list->cfg.nfacctd_net) {
821 Log(LOG_ERR, "ERROR ( %s/%s ): network aggregation selected but none of 'pmacctd_net', 'networks_file', 'networks_mask' is specified. Exiting ...\n\n", list->name, list->type.string);
822 exit_gracefully(1);
823 }
824 }
825 else {
826 if ((list->cfg.nfacctd_net == NF_NET_NEW && !list->cfg.networks_file) ||
827 (list->cfg.nfacctd_net == NF_NET_STATIC && !list->cfg.networks_mask) ||
828 (list->cfg.nfacctd_net == NF_NET_BGP && !list->cfg.bgp_daemon && !list->cfg.bmp_daemon) ||
829 (list->cfg.nfacctd_net == NF_NET_IGP && !list->cfg.nfacctd_isis) ||
830 (list->cfg.nfacctd_net == NF_NET_KEEP)) {
831 Log(LOG_ERR, "ERROR ( %s/%s ): network aggregation selected but none of 'bgp_daemon', 'bmp_daemon', 'isis_daemon', 'networks_file', 'networks_mask' is specified. Exiting ...\n\n", list->name, list->type.string);
832 exit_gracefully(1);
833 }
834 if (list->cfg.nfacctd_net & NF_NET_FALLBACK && list->cfg.networks_file)
835 list->cfg.nfacctd_net |= NF_NET_NEW;
836 }
837 }
838
839 if (list->cfg.what_to_count & COUNT_CLASS && !list->cfg.classifiers_path) {
840 Log(LOG_ERR, "ERROR ( %s/%s ): 'class' aggregation selected but NO 'classifiers' key specified. Exiting...\n\n", list->name, list->type.string);
841 exit_gracefully(1);
842 }
843
844 list->cfg.type_id = list->type.id;
845 bgp_config_checks(&list->cfg);
846
847 list->cfg.what_to_count |= COUNT_COUNTERS;
848 list->cfg.data_type |= PIPE_TYPE_METADATA;
849 }
850
851 /* applies to all plugins */
852 if ((list->cfg.what_to_count_2 & COUNT_NDPI_CLASS) ||
853 (list->cfg.nfprobe_what_to_count_2 & COUNT_NDPI_CLASS)) {
854 config.handle_fragments = TRUE;
855 config.classifier_ndpi = TRUE;
856 }
857
858 if ((list->cfg.what_to_count & COUNT_CLASS) && (list->cfg.what_to_count_2 & COUNT_NDPI_CLASS)) {
859 Log(LOG_ERR, "ERROR ( %s/%s ): 'class_legacy' and 'class' primitives are mutual exclusive. Exiting...\n\n", list->name, list->type.string);
860 exit_gracefully(1);
861 }
862 }
863 list = list->next;
864 }
865
866 /* plugins glue: creation (since 094) */
867 if (config.classifiers_path) {
868 init_classifiers(config.classifiers_path);
869 init_conntrack_table();
870 }
871
872 #if defined (WITH_NDPI)
873 if (config.classifier_ndpi) {
874 config.handle_fragments = TRUE;
875 pm_ndpi_wfl = pm_ndpi_workflow_init();
876 pm_ndpi_export_proto_to_class(pm_ndpi_wfl);
877 }
878 else pm_ndpi_wfl = NULL;
879 #endif
880
881 if (config.aggregate_primitives) {
882 req.key_value_table = (void *) &custom_primitives_registry;
883 load_id_file(MAP_CUSTOM_PRIMITIVES, config.aggregate_primitives, NULL, &req, &custom_primitives_allocated);
884 }
885 else memset(&custom_primitives_registry, 0, sizeof(custom_primitives_registry));
886
887 /* fixing per plugin custom primitives pointers, offsets and lengths */
888 list = plugins_list;
889 while(list) {
890 custom_primitives_reconcile(&list->cfg.cpptrs, &custom_primitives_registry);
891 if (custom_primitives_vlen(&list->cfg.cpptrs)) list->cfg.data_type |= PIPE_TYPE_VLEN;
892 list = list->next;
893 }
894
895 load_plugins(&req);
896
897 if (config.handle_fragments) init_ip_fragment_handler();
898 if (config.handle_flows) init_ip_flow_handler();
899 load_networks(config.networks_file, &nt, &nc);
900
901 if (config.pcap_interfaces_map) {
902 pm_pcap_interfaces_map_initialize(&pm_pcap_if_map);
903 pm_pcap_interfaces_map_initialize(&pm_bkp_pcap_if_map);
904 pm_pcap_interfaces_map_load(&pm_pcap_if_map);
905 }
906 else {
907 pm_pcap_if_map.list = NULL;
908 pm_pcap_if_map.num = 0;
909 }
910
911 if (!config.pcap_direction) config.pcap_direction = PCAP_D_INOUT;
912
913 /* If any device/savefile have been specified, choose a suitable device
914 where to listen for traffic */
915 if (!config.pcap_if && !config.pcap_savefile && !config.pcap_interfaces_map) {
916 char errbuf[PCAP_ERRBUF_SIZE];
917
918 Log(LOG_WARNING, "WARN ( %s/core ): Selecting a suitable devices.\n", config.name);
919
920 ret = pcap_findalldevs(&pm_pcap_ifs, errbuf);
921 if (ret == ERR || !pm_pcap_ifs) {
922 Log(LOG_ERR, "ERROR ( %s/core ): Unable to get interfaces list: %s. Exiting.\n", config.name, errbuf);
923 exit_gracefully(1);
924 }
925
926 config.pcap_if = pm_pcap_ifs[0].name;
927 Log(LOG_DEBUG, "DEBUG ( %s/core ): device is %s\n", config.name, config.pcap_if);
928 }
929
930 /* reading filter; if it exists, we'll take an action later */
931 if (!strlen(config_file)) config.clbuf = copy_argv(&argv[optind]);
932
933 if ((config.pcap_if || config.pcap_interfaces_map) && config.pcap_savefile) {
934 Log(LOG_ERR, "ERROR ( %s/core ): interface (-i), pcap_interfaces_map and pcap_savefile (-I) directives are mutually exclusive. Exiting.\n", config.name);
935 exit_gracefully(1);
936 }
937
938 if (config.pcap_if && config.pcap_interfaces_map) {
939 Log(LOG_ERR, "ERROR ( %s/core ): interface (-i) and pcap_interfaces_map directives are mutually exclusive. Exiting.\n", config.name);
940 exit_gracefully(1);
941 }
942
943 bkp_select_fd = 0;
944 FD_ZERO(&bkp_read_descs);
945
946 if (config.pcap_if) {
947 ret = pm_pcap_add_interface(&devices.list[0], config.pcap_if, NULL, psize);
948 if (!ret) {
949 cb_data.device = &devices.list[0];
950 devices.num = 1;
951 }
952 }
953 else if (config.pcap_interfaces_map) {
954 struct pm_pcap_interface *pm_pcap_if_entry;
955 int pm_pcap_if_idx = 0;
956 char *ifname;
957
958 while ((ifname = pm_pcap_interfaces_map_getnext_ifname(&pm_pcap_if_map, &pm_pcap_if_idx))) {
959 if (devices.num == PCAP_MAX_INTERFACES) {
960 Log(LOG_ERR, "ERROR ( %s/core ): Maximum number of interfaces reached (%u). Exiting.\n", config.name, PCAP_MAX_INTERFACES);
961 exit_gracefully(1);
962 }
963
964 pm_pcap_if_entry = pm_pcap_interfaces_map_getentry_by_ifname(&pm_pcap_if_map, ifname);
965 ret = pm_pcap_add_interface(&devices.list[devices.num], ifname, pm_pcap_if_entry, psize);
966 if (!ret) {
967 if (bkp_select_fd <= devices.list[devices.num].fd) {
968 bkp_select_fd = devices.list[devices.num].fd;
969 bkp_select_fd++;
970 }
971
972 if (devices.list[devices.num].fd) FD_SET(devices.list[devices.num].fd, &bkp_read_descs);
973 devices.num++;
974 }
975 }
976 }
977 else if (config.pcap_savefile) {
978 open_pcap_savefile(&devices.list[0], config.pcap_savefile);
979 pm_pcap_add_filter(&devices.list[0]);
980 cb_data.device = &devices.list[0];
981 devices.num = 1;
982 pm_pcap_savefile_round = 1;
983 }
984
985 /* signal handling we want to inherit to plugins (when not re-defined elsewhere) */
986 memset(&sighandler_action, 0, sizeof(sighandler_action)); /* To ensure the struct holds no garbage values */
987 sigemptyset(&sighandler_action.sa_mask); /* Within a signal handler all the signals are enabled */
988 sighandler_action.sa_flags = SA_RESTART; /* To enable re-entering a system call afer done with signal handling */
989
990 sighandler_action.sa_handler = startup_handle_falling_child;
991 sigaction(SIGCHLD, &sighandler_action, NULL);
992
993 /* handles reopening of syslog channel */
994 sighandler_action.sa_handler = reload;
995 sigaction(SIGHUP, &sighandler_action, NULL);
996
997 /* logs various statistics via Log() calls */
998 sighandler_action.sa_handler = push_stats;
999 sigaction(SIGUSR1, &sighandler_action, NULL);
1000
1001 /* sets to true the reload_maps flag */
1002 sighandler_action.sa_handler = reload_maps;
1003 sigaction(SIGUSR2, &sighandler_action, NULL);
1004
1005 /* we want to exit gracefully when a pipe is broken */
1006 sighandler_action.sa_handler = SIG_IGN;
1007 sigaction(SIGPIPE, &sighandler_action, NULL);
1008
1009 sighandler_action.sa_handler = PM_sigalrm_noop_handler;
1010 sigaction(SIGALRM, &sighandler_action, NULL);
1011
1012 if (config.bgp_daemon && config.bmp_daemon) {
1013 Log(LOG_ERR, "ERROR ( %s/core ): bgp_daemon and bmp_daemon are currently mutual exclusive. Exiting.\n", config.name);
1014 exit_gracefully(1);
1015 }
1016
1017 /* starting the ISIS threa */
1018 if (config.nfacctd_isis) {
1019 req.bpf_filter = TRUE;
1020
1021 nfacctd_isis_wrapper();
1022
1023 /* Let's give the ISIS thread some advantage to create its structures */
1024 sleep(DEFAULT_SLOTH_SLEEP_TIME);
1025 }
1026
1027 /* starting the BGP thread */
1028 if (config.bgp_daemon) {
1029 int sleep_time = DEFAULT_SLOTH_SLEEP_TIME;
1030
1031 req.bpf_filter = TRUE;
1032
1033 if (config.bgp_daemon_stdcomm_pattern_to_asn && config.bgp_daemon_lrgcomm_pattern_to_asn) {
1034 Log(LOG_ERR, "ERROR ( %s/core ): bgp_stdcomm_pattern_to_asn and bgp_lrgcomm_pattern_to_asn are mutual exclusive. Exiting.\n", config.name);
1035 exit_gracefully(1);
1036 }
1037
1038 load_comm_patterns(&config.bgp_daemon_stdcomm_pattern, &config.bgp_daemon_extcomm_pattern,
1039 &config.bgp_daemon_lrgcomm_pattern, &config.bgp_daemon_stdcomm_pattern_to_asn,
1040 &config.bgp_daemon_lrgcomm_pattern_to_asn);
1041
1042 if (config.bgp_daemon_peer_as_src_type == BGP_SRC_PRIMITIVES_MAP) {
1043 if (config.bgp_daemon_peer_as_src_map) {
1044 load_id_file(MAP_BGP_PEER_AS_SRC, config.bgp_daemon_peer_as_src_map, &bpas_table, &req, &bpas_map_allocated);
1045 cb_data.bpas_table = (u_char *) &bpas_table;
1046 }
1047 else {
1048 Log(LOG_ERR, "ERROR ( %s/core ): bgp_peer_as_src_type set to 'map' but no map defined. Exiting.\n", config.name);
1049 exit_gracefully(1);
1050 }
1051 }
1052 else cb_data.bpas_table = NULL;
1053
1054 if (config.bgp_daemon_src_local_pref_type == BGP_SRC_PRIMITIVES_MAP) {
1055 if (config.bgp_daemon_src_local_pref_map) {
1056 load_id_file(MAP_BGP_SRC_LOCAL_PREF, config.bgp_daemon_src_local_pref_map, &blp_table, &req, &blp_map_allocated);
1057 cb_data.blp_table = (u_char *) &blp_table;
1058 }
1059 else {
1060 Log(LOG_ERR, "ERROR ( %s/core ): bgp_src_local_pref_type set to 'map' but no map defined. Exiting.\n", config.name);
1061 exit_gracefully(1);
1062 }
1063 }
1064 else cb_data.blp_table = NULL;
1065
1066 if (config.bgp_daemon_src_med_type == BGP_SRC_PRIMITIVES_MAP) {
1067 if (config.bgp_daemon_src_med_map) {
1068 load_id_file(MAP_BGP_SRC_MED, config.bgp_daemon_src_med_map, &bmed_table, &req, &bmed_map_allocated);
1069 cb_data.bmed_table = (u_char *) &bmed_table;
1070 }
1071 else {
1072 Log(LOG_ERR, "ERROR ( %s/core ): bgp_src_med_type set to 'map' but no map defined. Exiting.\n", config.name);
1073 exit_gracefully(1);
1074 }
1075 }
1076 else cb_data.bmed_table = NULL;
1077
1078 if (config.bgp_daemon_to_xflow_agent_map) {
1079 load_id_file(MAP_BGP_TO_XFLOW_AGENT, config.bgp_daemon_to_xflow_agent_map, &bta_table, &req, &bta_map_allocated);
1080 cb_data.bta_table = (u_char *) &bta_table;
1081 }
1082 else {
1083 Log(LOG_ERR, "ERROR ( %s/core ): 'bgp_daemon' configured but no 'bgp_agent_map' has been specified. Exiting.\n", config.name);
1084 exit_gracefully(1);
1085 }
1086
1087 /* Limiting BGP peers to only two: one would suffice in pmacctd
1088 but in case maps are reloadable (ie. bta), it could be handy
1089 to keep a backup feed in memory */
1090 config.bgp_daemon_max_peers = 2;
1091
1092 cb_data.f_agent = (u_char *) &client;
1093 bgp_daemon_wrapper();
1094
1095 /* Let's give the BGP thread some advantage to create its structures */
1096 if (config.rpki_roas_file || config.rpki_rtr_cache) sleep_time += DEFAULT_SLOTH_SLEEP_TIME;
1097 sleep(sleep_time);
1098 }
1099
1100 /* starting the BMP thread */
1101 if (config.bmp_daemon) {
1102 int sleep_time = DEFAULT_SLOTH_SLEEP_TIME;
1103
1104 req.bpf_filter = TRUE;
1105
1106 bmp_daemon_wrapper();
1107
1108 /* Let's give the BMP thread some advantage to create its structures */
1109 if (config.rpki_roas_file || config.rpki_rtr_cache) sleep_time += DEFAULT_SLOTH_SLEEP_TIME;
1110 sleep(sleep_time);
1111 }
1112
1113 #if defined WITH_GEOIP
1114 if (config.geoip_ipv4_file || config.geoip_ipv6_file) {
1115 req.bpf_filter = TRUE;
1116 }
1117 #endif
1118
1119 #if defined WITH_GEOIPV2
1120 if (config.geoipv2_file) {
1121 req.bpf_filter = TRUE;
1122 }
1123 #endif
1124
1125 if (config.nfacctd_flow_to_rd_map) {
1126 Log(LOG_ERR, "ERROR ( %s/core ): 'flow_to_rd_map' is not supported by this daemon. Exiting.\n", config.name);
1127 exit_gracefully(1);
1128 }
1129
1130 /* Init tunnel handlers */
1131 tunnel_registry_init();
1132
1133 /* plugins glue: creation (until 093) */
1134 evaluate_packet_handlers();
1135 pm_setproctitle("%s [%s]", "Core Process", config.proc_name);
1136 if (config.pidfile) write_pid_file(config.pidfile);
1137
1138 /* signals to be handled only by the core process;
1139 we set proper handlers after plugin creation */
1140 sighandler_action.sa_handler = PM_sigint_handler;
1141 sigaction(SIGINT, &sighandler_action, NULL);
1142
1143 sighandler_action.sa_handler = PM_sigint_handler;
1144 sigaction(SIGTERM, &sighandler_action, NULL);
1145
1146 sighandler_action.sa_handler = handle_falling_child;
1147 sigaction(SIGCHLD, &sighandler_action, NULL);
1148
1149 kill(getpid(), SIGCHLD);
1150
1151 /* When reading packets from a savefile, things are lightning fast; we will sit
1152 here just few seconds, thus allowing plugins to complete their startup operations */
1153 if (config.pcap_savefile) {
1154 if (!config.pcap_sf_delay) {
1155 Log(LOG_INFO, "INFO ( %s/core ): PCAP capture file, sleeping for 2 seconds\n", config.name);
1156 sleep(2);
1157 }
1158 else sleep(config.pcap_sf_delay);
1159 }
1160
1161 #ifdef WITH_REDIS
1162 if (config.redis_host) {
1163 char log_id[SHORTBUFLEN];
1164
1165 snprintf(log_id, sizeof(log_id), "%s/%s", config.name, config.type);
1166 p_redis_init(&redis_host, log_id, p_redis_thread_produce_common_core_handler);
1167 }
1168 #endif
1169
1170 sigemptyset(&cb_data.sig.set);
1171 sigaddset(&cb_data.sig.set, SIGCHLD);
1172 sigaddset(&cb_data.sig.set, SIGHUP);
1173 sigaddset(&cb_data.sig.set, SIGUSR1);
1174 sigaddset(&cb_data.sig.set, SIGUSR2);
1175 sigaddset(&cb_data.sig.set, SIGTERM);
1176 if (config.daemon) {
1177 sigaddset(&cb_data.sig.set, SIGINT);
1178 }
1179 cb_data.sig.is_set = TRUE;
1180
1181 /* Main loop (for the case of a single interface): if pcap_loop() exits
1182 maybe an error occurred; we will try closing and reopening again our
1183 listening device */
1184 if (!config.pcap_interfaces_map) {
1185 for (;;) {
1186 if (!devices.list[0].active) {
1187 Log(LOG_WARNING, "WARN ( %s/core ): [%s] has become unavailable; throttling ...\n", config.name, config.pcap_if);
1188 ret = pm_pcap_add_interface(&devices.list[0], config.pcap_if, NULL, psize);
1189 if (!ret) {
1190 cb_data.device = &devices.list[0];
1191 devices.num = 1;
1192 }
1193 }
1194
1195 read_packet:
1196 pcap_loop(devices.list[0].dev_desc, -1, pm_pcap_cb, (u_char *) &cb_data);
1197 pcap_close(devices.list[0].dev_desc);
1198
1199 if (config.pcap_savefile) {
1200 if (config.pcap_sf_replay < 0 ||
1201 (config.pcap_sf_replay > 0 && pm_pcap_savefile_round < config.pcap_sf_replay)) {
1202 pm_pcap_savefile_round++;
1203 open_pcap_savefile(&devices.list[0], config.pcap_savefile);
1204 if (config.pcap_sf_delay) sleep(config.pcap_sf_delay);
1205
1206 goto read_packet;
1207 }
1208
1209 if (config.pcap_sf_wait) {
1210 fill_pipe_buffer();
1211 Log(LOG_INFO, "INFO ( %s/core ): finished reading PCAP capture file\n", config.name);
1212 wait(NULL);
1213 }
1214 stop_all_childs();
1215 }
1216 devices.list[0].active = FALSE;
1217 }
1218 }
1219 else {
1220 for (;;) {
1221 select_fd = bkp_select_fd;
1222 memcpy(&read_descs, &bkp_read_descs, sizeof(bkp_read_descs));
1223
1224 select(select_fd, &read_descs, NULL, NULL, NULL);
1225
1226 if (reload_map_pmacctd) {
1227 struct pm_pcap_interface *pm_pcap_if_entry;
1228 int pm_pcap_if_idx = 0;
1229 char *ifname;
1230
1231 pm_pcap_interfaces_map_copy(&pm_bkp_pcap_if_map, &pm_pcap_if_map);
1232 pm_pcap_interfaces_map_destroy(&pm_pcap_if_map);
1233 pm_pcap_interfaces_map_load(&pm_pcap_if_map);
1234
1235 pm_pcap_device_copy_all(&bkp_devices, &devices);
1236 pm_pcap_device_initialize(&devices);
1237
1238 /* Add interfaces and re-build relevant structs */
1239 while ((ifname = pm_pcap_interfaces_map_getnext_ifname(&pm_pcap_if_map, &pm_pcap_if_idx))) {
1240 if (!pm_pcap_interfaces_map_lookup_ifname(&pm_bkp_pcap_if_map, ifname)) {
1241 if (devices.num == PCAP_MAX_INTERFACES) {
1242 Log(LOG_WARNING, "WARN ( %s/core ): Maximum number of interfaces reached (%u). Ignoring '%s'.\n", config.name, PCAP_MAX_INTERFACES, ifname);
1243 }
1244 else {
1245 pm_pcap_if_entry = pm_pcap_interfaces_map_getentry_by_ifname(&pm_pcap_if_map, ifname);
1246 if (!pm_pcap_add_interface(&devices.list[devices.num], ifname, pm_pcap_if_entry, psize)) {
1247 if (bkp_select_fd <= devices.list[devices.num].fd) {
1248 bkp_select_fd = devices.list[devices.num].fd;
1249 bkp_select_fd++;
1250 }
1251
1252 if (devices.list[devices.num].fd && !FD_ISSET(devices.list[devices.num].fd, &bkp_read_descs)) {
1253 FD_SET(devices.list[devices.num].fd, &bkp_read_descs);
1254 }
1255
1256 devices.num++;
1257 }
1258 }
1259 }
1260 else {
1261 int device_idx;
1262
1263 device_idx = pm_pcap_device_getindex_byifname(&bkp_devices, ifname);
1264 if (device_idx >= 0) {
1265 Log(LOG_INFO, "INFO ( %s/core ): [%s,%u] link type is: %d\n", config.name, bkp_devices.list[device_idx].str,
1266 bkp_devices.list[device_idx].id, bkp_devices.list[device_idx].link_type);
1267 pm_pcap_device_copy_entry(&devices, &bkp_devices, device_idx);
1268 }
1269 else Log(LOG_WARNING, "WARN ( %s/core ): Mayday. Interface '%s' went lost.\n", config.name, ifname);
1270 }
1271 }
1272
1273 /* Remove unlisted interfaces */
1274 pm_pcap_if_idx = 0;
1275 while ((ifname = pm_pcap_interfaces_map_getnext_ifname(&pm_bkp_pcap_if_map, &pm_pcap_if_idx))) {
1276 if (!pm_pcap_interfaces_map_lookup_ifname(&pm_pcap_if_map, ifname)) {
1277 int device_idx;
1278
1279 device_idx = pm_pcap_device_getindex_byifname(&bkp_devices, ifname);
1280 if (device_idx >= 0) {
1281 Log(LOG_INFO, "INFO ( %s/core ): [%s,%u] removed.\n", config.name, bkp_devices.list[device_idx].str, bkp_devices.list[device_idx].id);
1282 FD_CLR(bkp_devices.list[device_idx].fd, &bkp_read_descs);
1283 pcap_close(bkp_devices.list[device_idx].dev_desc);
1284 }
1285 else Log(LOG_WARNING, "WARN ( %s/core ): Mayday. Interface '%s' went lost (2).\n", config.name, ifname);
1286 }
1287 }
1288
1289 reload_map_pmacctd = FALSE;
1290 }
1291
1292 for (dev_ptr = NULL, index = 0; index < devices.num; index++) {
1293 int loc_idx = (index + index_rr) % devices.num;
1294
1295 if (devices.list[loc_idx].fd && FD_ISSET(devices.list[loc_idx].fd, &read_descs)) {
1296 dev_ptr = &devices.list[loc_idx];
1297 index_rr = (index_rr + 1) % devices.num;
1298 break;
1299 }
1300 }
1301
1302 if (dev_ptr) {
1303 pkt_body = pcap_next(dev_ptr->dev_desc, &pkt_hdr);
1304 if (pkt_body) {
1305 cb_data.device = dev_ptr;
1306 pm_pcap_cb((u_char *) &cb_data, &pkt_hdr, pkt_body);
1307 }
1308 }
1309 }
1310 }
1311 }
1312