Пример #1
0
int log_unbind(struct log *self, int af_family)
{
    if (nflog_unbind_pf(self->_h, af_family)) {
        throw_exception("error during nflog_unbind_pf()");
        return -1;
    }
    return 0;
}
Пример #2
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;
    }
}