int log_create_queue(struct log *self, int queue_num) { int ret; if (self->_cb == NULL) { throw_exception("Error: no callback set"); return -1; } self->_gh = nflog_bind_group(self->_h, queue_num); if (self->_gh == NULL) { throw_exception("error during nflog_bind_group()"); return -1; } ret = nflog_callback_register(self->_gh, &swig_nflog_callback, (void*)self->_cb); if (ret != 0) { throw_exception("error during nflog_callback_register()"); return -1; } return 0; }
int main(int argc,char **argv, char **envp) { struct pcap_device device; int index, logf, ret; struct plugins_list_entry *list; struct plugin_requests req; char config_file[SRVBUFLEN]; struct id_table bpas_table; struct id_table blp_table; struct id_table bmed_table; struct id_table biss_table; struct id_table bta_table; struct pcap_callback_data cb_data; /* getopt() stuff */ extern char *optarg; extern int optind, opterr, optopt; int errflag, cp; /* NFLOG stuff */ struct nflog_handle *nfh = NULL; struct nflog_g_handle *nfgh = NULL; int one = 1; ssize_t len = 0; unsigned char *nflog_buffer; #if defined ENABLE_IPV6 struct sockaddr_storage client; #else struct sockaddr client; #endif #if defined HAVE_MALLOPT mallopt(M_CHECK_ACTION, 0); #endif umask(077); compute_once(); /* a bunch of default definitions */ reload_map = FALSE; reload_geoipv2_file = FALSE; bpas_map_allocated = FALSE; blp_map_allocated = FALSE; bmed_map_allocated = FALSE; biss_map_allocated = FALSE; bta_map_caching = FALSE; sampling_map_caching = FALSE; custom_primitives_allocated = FALSE; find_id_func = PM_find_id; plugins_list = NULL; errflag = 0; memset(cfg_cmdline, 0, sizeof(cfg_cmdline)); memset(&config, 0, sizeof(struct configuration)); memset(&device, 0, sizeof(struct pcap_device)); memset(&config_file, 0, sizeof(config_file)); memset(&failed_plugins, 0, sizeof(failed_plugins)); memset(&req, 0, sizeof(req)); memset(dummy_tlhdr, 0, sizeof(dummy_tlhdr)); memset(sll_mac, 0, sizeof(sll_mac)); memset(&bpas_table, 0, sizeof(bpas_table)); memset(&blp_table, 0, sizeof(blp_table)); memset(&bmed_table, 0, sizeof(bmed_table)); memset(&biss_table, 0, sizeof(biss_table)); memset(&bta_table, 0, sizeof(bta_table)); memset(&client, 0, sizeof(client)); memset(&cb_data, 0, sizeof(cb_data)); memset(&tunnel_registry, 0, sizeof(tunnel_registry)); memset(&reload_map_tstamp, 0, sizeof(reload_map_tstamp)); log_notifications_init(&log_notifications); config.acct_type = ACCT_PM; rows = 0; glob_pcapt = NULL; /* getting commandline values */ while (!errflag && ((cp = getopt(argc, argv, ARGS_UACCTD)) != -1)) { cfg_cmdline[rows] = malloc(SRVBUFLEN); switch (cp) { case 'P': strlcpy(cfg_cmdline[rows], "plugins: ", SRVBUFLEN); strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows])); rows++; break; case 'D': strlcpy(cfg_cmdline[rows], "daemonize: true", SRVBUFLEN); rows++; break; case 'd': debug = TRUE; strlcpy(cfg_cmdline[rows], "debug: true", SRVBUFLEN); rows++; break; case 'n': strlcpy(cfg_cmdline[rows], "networks_file: ", SRVBUFLEN); strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows])); rows++; break; case 'o': strlcpy(cfg_cmdline[rows], "ports_file: ", SRVBUFLEN); strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows])); rows++; break; case 'O': strlcpy(cfg_cmdline[rows], "print_output: ", SRVBUFLEN); strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows])); rows++; break; case 'u': strlcpy(cfg_cmdline[rows], "print_num_protos: true", SRVBUFLEN); rows++; break; case 'f': strlcpy(config_file, optarg, sizeof(config_file)); break; case 'F': strlcpy(cfg_cmdline[rows], "pidfile: ", SRVBUFLEN); strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows])); rows++; break; case 'c': strlcpy(cfg_cmdline[rows], "aggregate: ", SRVBUFLEN); strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows])); rows++; break; case 'b': strlcpy(cfg_cmdline[rows], "imt_buckets: ", SRVBUFLEN); strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows])); rows++; break; case 'm': strlcpy(cfg_cmdline[rows], "imt_mem_pools_number: ", SRVBUFLEN); strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows])); rows++; break; case 'p': strlcpy(cfg_cmdline[rows], "imt_path: ", SRVBUFLEN); strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows])); rows++; break; case 'r': strlcpy(cfg_cmdline[rows], "sql_refresh_time: ", SRVBUFLEN); strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows])); rows++; break; case 'v': strlcpy(cfg_cmdline[rows], "sql_table_version: ", SRVBUFLEN); strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows])); rows++; break; case 's': strlcpy(cfg_cmdline[rows], "imt_mem_pools_size: ", SRVBUFLEN); strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows])); rows++; break; case 'S': strlcpy(cfg_cmdline[rows], "syslog: ", SRVBUFLEN); strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows])); rows++; break; case 'g': strlcpy(cfg_cmdline[rows], "uacctd_group: ", SRVBUFLEN); strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows])); rows++; break; case 'L': strlcpy(cfg_cmdline[rows], "snaplen: ", SRVBUFLEN); strncat(cfg_cmdline[rows], optarg, CFG_LINE_LEN(cfg_cmdline[rows])); rows++; break; case 'R': strlcpy(cfg_cmdline[rows], "sfacctd_renormalize: true", SRVBUFLEN); rows++; break; case 'h': usage_daemon(argv[0]); exit(0); break; case 'V': version_daemon(UACCTD_USAGE_HEADER); exit(0); break; case 'a': print_primitives(config.acct_type, UACCTD_USAGE_HEADER); exit(0); break; default: usage_daemon(argv[0]); exit(1); break; } } /* post-checks and resolving conflicts */ if (strlen(config_file)) { if (parse_configuration_file(config_file) != SUCCESS) exit(1); } else { if (parse_configuration_file(NULL) != SUCCESS) exit(1); } /* XXX: glue; i'm conscious it's a dirty solution from an engineering viewpoint; someday later i'll fix this */ list = plugins_list; while (list) { list->cfg.acct_type = ACCT_PM; set_default_preferences(&list->cfg); if (!strcmp(list->type.string, "core")) { memcpy(&config, &list->cfg, sizeof(struct configuration)); config.name = list->name; config.type = list->type.string; } list = list->next; } if (config.files_umask) umask(config.files_umask); if (!config.snaplen) config.snaplen = DEFAULT_SNAPLEN; if (!config.uacctd_nl_size) config.uacctd_nl_size = DEFAULT_NFLOG_BUFLEN; if (!config.uacctd_threshold) config.uacctd_threshold = DEFAULT_NFLOG_THRESHOLD; /* Let's check whether we need superuser privileges */ if (getuid() != 0) { printf("%s (%s)\n\n", UACCTD_USAGE_HEADER, PMACCT_BUILD); printf("ERROR ( %s/core ): You need superuser privileges to run this command.\nExiting ...\n\n", config.name); exit(1); } if (!config.uacctd_group) { config.uacctd_group = DEFAULT_NFLOG_GROUP; list = plugins_list; while (list) { list->cfg.uacctd_group = DEFAULT_NFLOG_GROUP; list = list->next; } } if (config.daemon) { list = plugins_list; while (list) { if (!strcmp(list->type.string, "print") && !list->cfg.print_output_file) printf("INFO ( %s/%s ): Daemonizing. Bye bye screen.\n", list->name, list->type.string); list = list->next; } if (debug || config.debug) printf("WARN ( %s/core ): debug is enabled; forking in background. Logging to standard error (stderr) will get lost.\n", config.name); daemonize(); } initsetproctitle(argc, argv, envp); if (config.syslog) { logf = parse_log_facility(config.syslog); if (logf == ERR) { config.syslog = NULL; printf("WARN ( %s/core ): specified syslog facility is not supported. Logging to standard error (stderr).\n", config.name); } else openlog(NULL, LOG_PID, logf); Log(LOG_INFO, "INFO ( %s/core ): Start logging ...\n", config.name); } if (config.logfile) { config.logfile_fd = open_output_file(config.logfile, "a", FALSE); list = plugins_list; while (list) { list->cfg.logfile_fd = config.logfile_fd ; list = list->next; } } if (config.proc_priority) { int ret; ret = setpriority(PRIO_PROCESS, 0, config.proc_priority); if (ret) Log(LOG_WARNING, "WARN ( %s/core ): proc_priority failed (errno: %d)\n", config.name, errno); else Log(LOG_INFO, "INFO ( %s/core ): proc_priority set to %d\n", config.name, getpriority(PRIO_PROCESS, 0)); } if (strlen(config_file)) { char canonical_path[PATH_MAX], *canonical_path_ptr; canonical_path_ptr = realpath(config_file, canonical_path); if (canonical_path_ptr) Log(LOG_INFO, "INFO ( %s/core ): Reading configuration file '%s'.\n", config.name, canonical_path); } else Log(LOG_INFO, "INFO ( %s/core ): Reading configuration from cmdline.\n", config.name); /* Enforcing policies over aggregation methods */ list = plugins_list; while (list) { if (list->type.id != PLUGIN_ID_CORE) { /* applies to all plugins */ plugin_pipe_check(&list->cfg); if (config.classifiers_path && (list->cfg.sampling_rate || config.ext_sampling_rate)) { Log(LOG_ERR, "ERROR ( %s/core ): Packet sampling and classification are mutual exclusive.\n", config.name); exit(1); } if (list->cfg.sampling_rate && config.ext_sampling_rate) { Log(LOG_ERR, "ERROR ( %s/core ): Internal packet sampling and external packet sampling are mutual exclusive.\n", config.name); exit(1); } /* applies to specific plugins */ if (list->type.id == PLUGIN_ID_TEE) { Log(LOG_ERR, "ERROR ( %s/core ): 'tee' plugin not supported in 'uacctd'.\n", config.name); exit(1); } else if (list->type.id == PLUGIN_ID_NFPROBE) { /* If we already renormalizing an external sampling rate, we cancel the sampling information from the probe plugin */ if (config.sfacctd_renormalize && list->cfg.ext_sampling_rate) list->cfg.ext_sampling_rate = 0; config.handle_fragments = TRUE; list->cfg.nfprobe_what_to_count = list->cfg.what_to_count; list->cfg.nfprobe_what_to_count_2 = list->cfg.what_to_count_2; list->cfg.what_to_count = 0; list->cfg.what_to_count_2 = 0; #if defined (HAVE_L2) if (list->cfg.nfprobe_version == 9 || list->cfg.nfprobe_version == 10) { list->cfg.what_to_count |= COUNT_SRC_MAC; list->cfg.what_to_count |= COUNT_DST_MAC; list->cfg.what_to_count |= COUNT_VLAN; } #endif list->cfg.what_to_count |= COUNT_SRC_HOST; list->cfg.what_to_count |= COUNT_DST_HOST; if (list->cfg.networks_file || list->cfg.networks_mask || list->cfg.nfacctd_net) { list->cfg.what_to_count |= COUNT_SRC_NMASK; list->cfg.what_to_count |= COUNT_DST_NMASK; } list->cfg.what_to_count |= COUNT_SRC_PORT; list->cfg.what_to_count |= COUNT_DST_PORT; list->cfg.what_to_count |= COUNT_IP_TOS; list->cfg.what_to_count |= COUNT_IP_PROTO; if (list->cfg.networks_file || (list->cfg.nfacctd_bgp && list->cfg.nfacctd_as == NF_AS_BGP)) { list->cfg.what_to_count |= COUNT_SRC_AS; list->cfg.what_to_count |= COUNT_DST_AS; list->cfg.what_to_count |= COUNT_PEER_DST_IP; } if ((list->cfg.nfprobe_version == 9 || list->cfg.nfprobe_version == 10) && list->cfg.classifiers_path) { list->cfg.what_to_count |= COUNT_CLASS; config.handle_flows = TRUE; } if (list->cfg.pre_tag_map) { list->cfg.what_to_count |= COUNT_TAG; list->cfg.what_to_count |= COUNT_TAG2; list->cfg.what_to_count_2 |= COUNT_LABEL; } list->cfg.what_to_count |= COUNT_IN_IFACE; list->cfg.what_to_count |= COUNT_OUT_IFACE; if (list->cfg.what_to_count & (COUNT_STD_COMM|COUNT_EXT_COMM|COUNT_LOCAL_PREF|COUNT_MED|COUNT_AS_PATH| COUNT_PEER_SRC_AS|COUNT_PEER_DST_AS|COUNT_PEER_SRC_IP|COUNT_SRC_STD_COMM| COUNT_SRC_EXT_COMM|COUNT_SRC_AS_PATH|COUNT_SRC_MED|COUNT_SRC_LOCAL_PREF| COUNT_MPLS_VPN_RD)) { 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); exit(1); } list->cfg.what_to_count |= COUNT_COUNTERS; if (list->cfg.nfacctd_as & NF_AS_FALLBACK && list->cfg.networks_file) list->cfg.nfacctd_as |= NF_AS_NEW; if (list->cfg.nfacctd_net & NF_NET_FALLBACK && list->cfg.networks_file) list->cfg.nfacctd_net |= NF_NET_NEW; list->cfg.data_type = PIPE_TYPE_METADATA; list->cfg.data_type |= PIPE_TYPE_EXTRAS; if (list->cfg.what_to_count_2 & (COUNT_LABEL)) list->cfg.data_type |= PIPE_TYPE_VLEN; } else if (list->type.id == PLUGIN_ID_SFPROBE) { /* If we already renormalizing an external sampling rate, we cancel the sampling information from the probe plugin */ if (config.sfacctd_renormalize && list->cfg.ext_sampling_rate) list->cfg.ext_sampling_rate = 0; if (config.snaplen < 128) config.snaplen = 128; /* SFL_DEFAULT_HEADER_SIZE */ list->cfg.what_to_count = COUNT_PAYLOAD; list->cfg.what_to_count_2 = 0; if (list->cfg.classifiers_path) { list->cfg.what_to_count |= COUNT_CLASS; config.handle_fragments = TRUE; config.handle_flows = TRUE; } if (list->cfg.networks_file || (list->cfg.nfacctd_bgp && list->cfg.nfacctd_as == NF_AS_BGP)) { list->cfg.what_to_count |= COUNT_SRC_AS; list->cfg.what_to_count |= COUNT_DST_AS; list->cfg.what_to_count |= COUNT_PEER_DST_IP; } if (list->cfg.networks_file || list->cfg.networks_mask || list->cfg.nfacctd_net) { list->cfg.what_to_count |= COUNT_SRC_NMASK; list->cfg.what_to_count |= COUNT_DST_NMASK; } if (list->cfg.pre_tag_map) { list->cfg.what_to_count |= COUNT_TAG; list->cfg.what_to_count |= COUNT_TAG2; } if (list->cfg.what_to_count & (COUNT_STD_COMM|COUNT_EXT_COMM|COUNT_LOCAL_PREF|COUNT_MED|COUNT_AS_PATH| COUNT_PEER_SRC_AS|COUNT_PEER_DST_AS|COUNT_PEER_SRC_IP|COUNT_SRC_STD_COMM| COUNT_SRC_EXT_COMM|COUNT_SRC_AS_PATH|COUNT_SRC_MED|COUNT_SRC_LOCAL_PREF| COUNT_MPLS_VPN_RD)) { 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); exit(1); } #if defined (HAVE_L2) list->cfg.what_to_count |= COUNT_VLAN; list->cfg.what_to_count |= COUNT_COS; #endif if (list->cfg.nfacctd_as & NF_AS_FALLBACK && list->cfg.networks_file) list->cfg.nfacctd_as |= NF_AS_NEW; if (list->cfg.nfacctd_net & NF_NET_FALLBACK && list->cfg.networks_file) list->cfg.nfacctd_net |= NF_NET_NEW; list->cfg.data_type = PIPE_TYPE_PAYLOAD; } else { if (list->cfg.what_to_count_2 & (COUNT_POST_NAT_SRC_HOST|COUNT_POST_NAT_DST_HOST| COUNT_POST_NAT_SRC_PORT|COUNT_POST_NAT_DST_PORT|COUNT_NAT_EVENT| COUNT_TIMESTAMP_START|COUNT_TIMESTAMP_END|COUNT_TIMESTAMP_ARRIVAL)) list->cfg.data_type |= PIPE_TYPE_NAT; if (list->cfg.what_to_count_2 & (COUNT_MPLS_LABEL_TOP|COUNT_MPLS_LABEL_BOTTOM| COUNT_MPLS_STACK_DEPTH)) list->cfg.data_type |= PIPE_TYPE_MPLS; if (list->cfg.what_to_count_2 & (COUNT_LABEL)) list->cfg.data_type |= PIPE_TYPE_VLEN; evaluate_sums(&list->cfg.what_to_count, list->name, list->type.string); if (list->cfg.what_to_count & (COUNT_SRC_PORT|COUNT_DST_PORT|COUNT_SUM_PORT|COUNT_TCPFLAGS)) config.handle_fragments = TRUE; if (list->cfg.what_to_count & COUNT_FLOWS) { config.handle_fragments = TRUE; config.handle_flows = TRUE; } if (list->cfg.what_to_count & COUNT_CLASS) { config.handle_fragments = TRUE; config.handle_flows = TRUE; } if (!list->cfg.what_to_count && !list->cfg.what_to_count_2 && !list->cfg.cpptrs.num) { Log(LOG_WARNING, "WARN ( %s/%s ): defaulting to SRC HOST aggregation.\n", list->name, list->type.string); list->cfg.what_to_count |= COUNT_SRC_HOST; } if (((list->cfg.what_to_count & COUNT_SRC_HOST) && (list->cfg.what_to_count & COUNT_SRC_NET)) || ((list->cfg.what_to_count & COUNT_DST_HOST) && (list->cfg.what_to_count & COUNT_DST_NET))) { if (!list->cfg.tmp_net_own_field) { Log(LOG_ERR, "ERROR ( %s/%s ): src_host, src_net and dst_host, dst_net are mutually exclusive: set tmp_net_own_field to true. Exiting...\n\n", list->name, list->type.string); exit(1); } } if (list->cfg.what_to_count & (COUNT_SRC_AS|COUNT_DST_AS|COUNT_SUM_AS)) { if (!list->cfg.networks_file && list->cfg.nfacctd_as != NF_AS_BGP) { Log(LOG_ERR, "ERROR ( %s/%s ): AS aggregation selected but NO 'networks_file' or 'uacctd_as' are specified. Exiting...\n\n", list->name, list->type.string); exit(1); } if (list->cfg.nfacctd_as & NF_AS_FALLBACK && list->cfg.networks_file) list->cfg.nfacctd_as |= NF_AS_NEW; } 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)) { if (!list->cfg.nfacctd_net) { if (list->cfg.networks_file) list->cfg.nfacctd_net |= NF_NET_NEW; if (list->cfg.networks_mask) list->cfg.nfacctd_net |= NF_NET_STATIC; if (!list->cfg.nfacctd_net) { Log(LOG_ERR, "ERROR ( %s/%s ): network aggregation selected but none of 'uacctd_net', 'networks_file', 'networks_mask' is specified. Exiting ...\n\n", list->name, list->type.string); exit(1); } } else { if ((list->cfg.nfacctd_net == NF_NET_NEW && !list->cfg.networks_file) || (list->cfg.nfacctd_net == NF_NET_STATIC && !list->cfg.networks_mask) || (list->cfg.nfacctd_net == NF_NET_BGP && !list->cfg.nfacctd_bgp) || (list->cfg.nfacctd_net == NF_NET_IGP && !list->cfg.nfacctd_isis) || (list->cfg.nfacctd_net == NF_NET_KEEP)) { Log(LOG_ERR, "ERROR ( %s/%s ): network aggregation selected but none of 'bgp_daemon', 'isis_daemon', 'networks_file', 'networks_mask' is specified. Exiting ...\n\n", list->name, list->type.string); exit(1); } if (list->cfg.nfacctd_net & NF_NET_FALLBACK && list->cfg.networks_file) list->cfg.nfacctd_net |= NF_NET_NEW; } } if (list->cfg.what_to_count & COUNT_CLASS && !list->cfg.classifiers_path) { Log(LOG_ERR, "ERROR ( %s/%s ): 'class' aggregation selected but NO 'classifiers' key specified. Exiting...\n\n", list->name, list->type.string); exit(1); } bgp_config_checks(&list->cfg); list->cfg.what_to_count |= COUNT_COUNTERS; list->cfg.data_type |= PIPE_TYPE_METADATA; } } list = list->next; } /* plugins glue: creation (since 094) */ if (config.classifiers_path) { init_classifiers(config.classifiers_path); init_conntrack_table(); } if (config.aggregate_primitives) { req.key_value_table = (void *) &custom_primitives_registry; load_id_file(MAP_CUSTOM_PRIMITIVES, config.aggregate_primitives, NULL, &req, &custom_primitives_allocated); } else memset(&custom_primitives_registry, 0, sizeof(custom_primitives_registry)); /* fixing per plugin custom primitives pointers, offsets and lengths */ list = plugins_list; while(list) { custom_primitives_reconcile(&list->cfg.cpptrs, &custom_primitives_registry); if (custom_primitives_vlen(&list->cfg.cpptrs)) list->cfg.data_type |= PIPE_TYPE_VLEN; list = list->next; } load_plugins(&req); if (config.handle_fragments) init_ip_fragment_handler(); if (config.handle_flows) init_ip_flow_handler(); load_networks(config.networks_file, &nt, &nc); #if defined (HAVE_L2) device.link_type = DLT_EN10MB; #else device.link_type = DLT_RAW; #endif for (index = 0; _devices[index].link_type != -1; index++) { if (device.link_type == _devices[index].link_type) device.data = &_devices[index]; } load_plugin_filters(device.link_type); cb_data.device = &device; /* signal handling we want to inherit to plugins (when not re-defined elsewhere) */ signal(SIGCHLD, startup_handle_falling_child); /* takes note of plugins failed during startup phase */ signal(SIGHUP, reload); /* handles reopening of syslog channel */ signal(SIGUSR1, push_stats); /* logs various statistics via Log() calls */ signal(SIGUSR2, reload_maps); /* sets to true the reload_maps flag */ signal(SIGPIPE, SIG_IGN); /* we want to exit gracefully when a pipe is broken */ nfh = nflog_open(); if (nfh == NULL) { Log(LOG_ERR, "ERROR ( %s/core ): Failed to create Netlink NFLOG socket\n", config.name); nflog_close(nfh); exit_all(1); } Log(LOG_INFO, "INFO ( %s/core ): Successfully connected Netlink NFLOG socket\n", config.name); /* Bind to IPv4 (and IPv6) */ if (nflog_unbind_pf(nfh, AF_INET) < 0) { Log(LOG_ERR, "ERROR ( %s/core ): Failed to unbind Netlink NFLOG socket from IPv4\n", config.name); nflog_close(nfh); exit_all(1); } if (nflog_bind_pf(nfh, AF_INET) < 0) { Log(LOG_ERR, "ERROR ( %s/core ): Failed to bind Netlink NFLOG socket from IPv4\n", config.name); nflog_close(nfh); exit_all(1); } #if defined ENABLE_IPV6 if (nflog_unbind_pf(nfh, AF_INET6) < 0) { Log(LOG_ERR, "ERROR ( %s/core ): Failed to unbind Netlink NFLOG socket from IPv6\n", config.name); nflog_close(nfh); exit_all(1); } if (nflog_bind_pf(nfh, AF_INET6) < 0) { Log(LOG_ERR, "ERROR ( %s/core ): Failed to bind Netlink NFLOG socket from IPv6\n", config.name); nflog_close(nfh); exit_all(1); } #endif /* Bind to group */ if ((nfgh = nflog_bind_group(nfh, config.uacctd_group)) == NULL) { Log(LOG_ERR, "ERROR ( %s/core ): Failed to join NFLOG group %d\n", config.name, config.uacctd_group); nflog_close(nfh); exit_all(1); } /* Set snaplen */ if (nflog_set_mode(nfgh, NFULNL_COPY_PACKET, config.snaplen) < 0) { Log(LOG_ERR, "ERROR ( %s/core ): Failed to set snaplen to %d\n", config.name, config.snaplen); nflog_unbind_group(nfgh); nflog_close(nfh); exit_all(1); } /* Set threshold */ if (nflog_set_qthresh(nfgh, config.uacctd_threshold) < 0) { Log(LOG_ERR, "ERROR ( %s/core ): Failed to set threshold to %d\n", config.name, config.uacctd_threshold); nflog_unbind_group(nfgh); nflog_close(nfh); exit_all(1); } /* Set buffer size */ if (nflog_set_nlbufsiz(nfgh, config.uacctd_nl_size) < 0) { Log(LOG_ERR, "ERROR ( %s/core ): Failed to set receive buffer size to %d\n", config.name, config.uacctd_nl_size); nflog_unbind_group(nfgh); nflog_close(nfh); exit_all(1); } /* Turn off netlink errors from overrun. */ if (setsockopt(nflog_fd(nfh), SOL_NETLINK, NETLINK_NO_ENOBUFS, &one, sizeof(one))) Log(LOG_ERR, "ERROR ( %s/core ): Failed to turn off netlink ENOBUFS\n", config.name); nflog_callback_register(nfgh, &nflog_incoming, &cb_data); nflog_buffer = malloc(config.uacctd_nl_size); if (nflog_buffer == NULL) { Log(LOG_ERR, "ERROR ( %s/core ): NFLOG buffer malloc() failed\n", config.name); nflog_unbind_group(nfgh); nflog_close(nfh); exit_all(1); } #if defined ENABLE_THREADS /* starting the ISIS threa */ if (config.nfacctd_isis) { req.bpf_filter = TRUE; nfacctd_isis_wrapper(); /* Let's give the ISIS thread some advantage to create its structures */ sleep(5); } /* starting the BGP thread */ if (config.nfacctd_bgp) { req.bpf_filter = TRUE; load_comm_patterns(&config.nfacctd_bgp_stdcomm_pattern, &config.nfacctd_bgp_extcomm_pattern, &config.nfacctd_bgp_stdcomm_pattern_to_asn); if (config.nfacctd_bgp_peer_as_src_type == BGP_SRC_PRIMITIVES_MAP) { if (config.nfacctd_bgp_peer_as_src_map) { load_id_file(MAP_BGP_PEER_AS_SRC, config.nfacctd_bgp_peer_as_src_map, &bpas_table, &req, &bpas_map_allocated); cb_data.bpas_table = (u_char *) &bpas_table; } else { Log(LOG_ERR, "ERROR ( %s/core ): bgp_peer_as_src_type set to 'map' but no map defined. Exiting.\n", config.name); exit(1); } } else cb_data.bpas_table = NULL; if (config.nfacctd_bgp_src_local_pref_type == BGP_SRC_PRIMITIVES_MAP) { if (config.nfacctd_bgp_src_local_pref_map) { load_id_file(MAP_BGP_SRC_LOCAL_PREF, config.nfacctd_bgp_src_local_pref_map, &blp_table, &req, &blp_map_allocated); cb_data.blp_table = (u_char *) &blp_table; } else { Log(LOG_ERR, "ERROR ( %s/core ): bgp_src_local_pref_type set to 'map' but no map defined. Exiting.\n", config.name); exit(1); } } else cb_data.bpas_table = NULL; if (config.nfacctd_bgp_src_med_type == BGP_SRC_PRIMITIVES_MAP) { if (config.nfacctd_bgp_src_med_map) { load_id_file(MAP_BGP_SRC_MED, config.nfacctd_bgp_src_med_map, &bmed_table, &req, &bmed_map_allocated); cb_data.bmed_table = (u_char *) &bmed_table; } else { Log(LOG_ERR, "ERROR ( %s/core ): bgp_src_med_type set to 'map' but no map defined. Exiting.\n", config.name); exit(1); } } else cb_data.bmed_table = NULL; if (config.nfacctd_bgp_to_agent_map) { load_id_file(MAP_BGP_TO_XFLOW_AGENT, config.nfacctd_bgp_to_agent_map, &bta_table, &req, &bta_map_allocated); cb_data.bta_table = (u_char *) &bta_table; } else { Log(LOG_ERR, "ERROR ( %s/core ): 'bgp_daemon' configured but no 'bgp_agent_map' has been specified. Exiting.\n", config.name); exit(1); } /* Limiting BGP peers to only two: one would suffice in pmacctd but in case maps are reloadable (ie. bta), it could be handy to keep a backup feed in memory */ config.nfacctd_bgp_max_peers = 2; cb_data.f_agent = (char *)&client; nfacctd_bgp_wrapper(); /* Let's give the BGP thread some advantage to create its structures */ sleep(5); } #else if (config.nfacctd_isis) { Log(LOG_ERR, "ERROR ( %s/core ): 'isis_daemon' is available only with threads (--enable-threads). Exiting.\n", config.name); exit(1); } if (config.nfacctd_bgp) { Log(LOG_ERR, "ERROR ( %s/core ): 'bgp_daemon' is available only with threads (--enable-threads). Exiting.\n", config.name); exit(1); } #endif #if defined WITH_GEOIP if (config.geoip_ipv4_file || config.geoip_ipv6_file) { req.bpf_filter = TRUE; } #endif #if defined WITH_GEOIPV2 if (config.geoipv2_file) { req.bpf_filter = TRUE; } #endif if (config.nfacctd_flow_to_rd_map) { Log(LOG_ERR, "ERROR ( %s/core ): 'flow_to_rd_map' is not supported by this daemon. Exiting.\n", config.name); exit(1); } /* plugins glue: creation (until 093) */ evaluate_packet_handlers(); pm_setproctitle("%s [%s]", "Core Process", config.proc_name); if (config.pidfile) write_pid_file(config.pidfile); /* signals to be handled only by pmacctd; we set proper handlers after plugin creation */ signal(SIGINT, my_sigint_handler); signal(SIGTERM, my_sigint_handler); signal(SIGCHLD, handle_falling_child); kill(getpid(), SIGCHLD); /* Main loop: if pcap_loop() exits maybe an error occurred; we will try closing and reopening again our listening device */ for (;;) { if (len == -1) { if (errno != EAGAIN) { /* We can't deal with permanent errors. * Just sleep a bit. */ Log(LOG_ERR, "ERROR ( %s/core ): Syscall returned %d: %s. Sleeping for 1 sec.\n", config.name, errno, strerror(errno)); sleep(1); } } len = recv(nflog_fd(nfh), nflog_buffer, config.uacctd_nl_size, 0); if (len < 0) continue; if (nflog_handle_packet(nfh, nflog_buffer, len) != 0) continue; } }