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