int SCConfLogOpenRedis(ConfNode *redis_node, LogFileCtx *log_ctx) { const char *redis_server = NULL; const char *redis_port = NULL; const char *redis_mode = NULL; const char *redis_key = NULL; if (redis_node) { redis_server = ConfNodeLookupChildValue(redis_node, "server"); redis_port = ConfNodeLookupChildValue(redis_node, "port"); redis_mode = ConfNodeLookupChildValue(redis_node, "mode"); redis_key = ConfNodeLookupChildValue(redis_node, "key"); } if (!redis_server) { redis_server = "127.0.0.1"; SCLogInfo("Using default redis server (127.0.0.1)"); } if (!redis_port) redis_port = "6379"; if (!redis_mode) redis_mode = "list"; if (!redis_key) redis_key = "suricata"; log_ctx->redis_setup.key = SCStrdup(redis_key); if (!log_ctx->redis_setup.key) { SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate redis key name"); exit(EXIT_FAILURE); } log_ctx->redis_setup.batch_size = 0; ConfNode *pipelining = ConfNodeLookupChild(redis_node, "pipelining"); if (pipelining) { int enabled = 0; int ret; intmax_t val; ret = ConfGetChildValueBool(pipelining, "enabled", &enabled); if (ret && enabled) { ret = ConfGetChildValueInt(pipelining, "batch-size", &val); if (ret) { log_ctx->redis_setup.batch_size = val; } else { log_ctx->redis_setup.batch_size = 10; } } } if (!strcmp(redis_mode, "list")) { log_ctx->redis_setup.command = redis_push_cmd; if (!log_ctx->redis_setup.command) { SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate redis key command"); exit(EXIT_FAILURE); } } else { log_ctx->redis_setup.command = redis_publish_cmd; if (!log_ctx->redis_setup.command) { SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate redis key command"); exit(EXIT_FAILURE); } } redisContext *c = redisConnect(redis_server, atoi(redis_port)); if (c != NULL && c->err) { SCLogError(SC_ERR_SOCKET, "Error connecting to redis server: %s", c->errstr); exit(EXIT_FAILURE); } /* store server params for reconnection */ log_ctx->redis_setup.server = SCStrdup(redis_server); if (!log_ctx->redis_setup.server) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating redis server string"); exit(EXIT_FAILURE); } log_ctx->redis_setup.port = atoi(redis_port); log_ctx->redis_setup.tried = 0; log_ctx->redis = c; log_ctx->Close = SCLogFileCloseRedis; return 0; }
/** * \brief extract information from config file * * The returned structure will be freed by the thread init function. * This is thus necessary to or copy the structure before giving it * to thread or to reparse the file for each thread (and thus have * new structure. * * \return a AFPIfaceConfig corresponding to the interface name */ void *ParseAFPConfig(const char *iface) { char *threadsstr = NULL; ConfNode *if_root; ConfNode *af_packet_node; AFPIfaceConfig *aconf = SCMalloc(sizeof(*aconf)); char *tmpclusterid; char *tmpctype; char *copymodestr; intmax_t value; int boolval; char *bpf_filter = NULL; char *out_iface = NULL; if (unlikely(aconf == NULL)) { return NULL; } if (iface == NULL) { SCFree(aconf); return NULL; } strlcpy(aconf->iface, iface, sizeof(aconf->iface)); aconf->threads = 1; SC_ATOMIC_INIT(aconf->ref); (void) SC_ATOMIC_ADD(aconf->ref, 1); aconf->buffer_size = 0; aconf->cluster_id = 1; aconf->cluster_type = PACKET_FANOUT_HASH; aconf->promisc = 1; aconf->checksum_mode = CHECKSUM_VALIDATION_KERNEL; aconf->DerefFunc = AFPDerefConfig; aconf->flags = 0; aconf->bpf_filter = NULL; aconf->out_iface = NULL; if (ConfGet("bpf-filter", &bpf_filter) == 1) { if (strlen(bpf_filter) > 0) { aconf->bpf_filter = bpf_filter; SCLogInfo("Going to use command-line provided bpf filter '%s'", aconf->bpf_filter); } } /* Find initial node */ af_packet_node = ConfGetNode("af-packet"); if (af_packet_node == NULL) { SCLogInfo("Unable to find af-packet config using default value"); return aconf; } if_root = ConfNodeLookupKeyValue(af_packet_node, "interface", iface); if (if_root == NULL) { SCLogInfo("Unable to find af-packet config for " "interface %s, using default value", iface); return aconf; } if (ConfGetChildValue(if_root, "threads", &threadsstr) != 1) { aconf->threads = 1; } else { if (threadsstr != NULL) { aconf->threads = (uint8_t)atoi(threadsstr); } } if (aconf->threads == 0) { aconf->threads = 1; } if (ConfGetChildValue(if_root, "copy-iface", &out_iface) == 1) { if (strlen(out_iface) > 0) { aconf->out_iface = out_iface; } } (void)ConfGetChildValueBool(if_root, "use-mmap", (int *)&boolval); if (boolval) { SCLogInfo("Enabling mmaped capture on iface %s", aconf->iface); aconf->flags |= AFP_RING_MODE; } (void)ConfGetChildValueBool(if_root, "use-emergency-flush", (int *)&boolval); if (boolval) { SCLogInfo("Enabling ring emergency flush on iface %s", aconf->iface); aconf->flags |= AFP_EMERGENCY_MODE; } aconf->copy_mode = AFP_COPY_MODE_NONE; if (ConfGetChildValue(if_root, "copy-mode", ©modestr) == 1) { if (aconf->out_iface == NULL) { SCLogInfo("Copy mode activated but no destination" " iface. Disabling feature"); } else if (!(aconf->flags & AFP_RING_MODE)) { SCLogInfo("Copy mode activated but use-mmap " "set to no. Disabling feature"); } else if (strlen(copymodestr) <= 0) { aconf->out_iface = NULL; } else if (strcmp(copymodestr, "ips") == 0) { SCLogInfo("AF_PACKET IPS mode activated %s->%s", iface, aconf->out_iface); aconf->copy_mode = AFP_COPY_MODE_IPS; } else if (strcmp(copymodestr, "tap") == 0) { SCLogInfo("AF_PACKET TAP mode activated %s->%s", iface, aconf->out_iface); aconf->copy_mode = AFP_COPY_MODE_TAP; } else { SCLogInfo("Invalid mode (not in tap, ips)"); } } SC_ATOMIC_RESET(aconf->ref); (void) SC_ATOMIC_ADD(aconf->ref, aconf->threads); if (ConfGetChildValue(if_root, "cluster-id", &tmpclusterid) != 1) { SCLogError(SC_ERR_INVALID_ARGUMENT,"Could not get cluster-id from config"); } else { aconf->cluster_id = (uint16_t)atoi(tmpclusterid); SCLogDebug("Going to use cluster-id %" PRId32, aconf->cluster_id); } if (ConfGetChildValue(if_root, "cluster-type", &tmpctype) != 1) { SCLogError(SC_ERR_GET_CLUSTER_TYPE_FAILED,"Could not get cluster-type from config"); } else if (strcmp(tmpctype, "cluster_round_robin") == 0) { SCLogInfo("Using round-robin cluster mode for AF_PACKET (iface %s)", aconf->iface); aconf->cluster_type = PACKET_FANOUT_LB; } else if (strcmp(tmpctype, "cluster_flow") == 0) { /* In hash mode, we also ask for defragmentation needed to * compute the hash */ uint16_t defrag = 0; SCLogInfo("Using flow cluster mode for AF_PACKET (iface %s)", aconf->iface); ConfGetChildValueBool(if_root, "defrag", (int *)&defrag); if (defrag) { SCLogInfo("Using defrag kernel functionality for AF_PACKET (iface %s)", aconf->iface); defrag = PACKET_FANOUT_FLAG_DEFRAG; } aconf->cluster_type = PACKET_FANOUT_HASH | defrag; } else if (strcmp(tmpctype, "cluster_cpu") == 0) { SCLogInfo("Using cpu cluster mode for AF_PACKET (iface %s)", aconf->iface); aconf->cluster_type = PACKET_FANOUT_CPU; } else { SCLogError(SC_ERR_INVALID_CLUSTER_TYPE,"invalid cluster-type %s",tmpctype); SCFree(aconf); return NULL; } /*load af_packet bpf filter*/ /* command line value has precedence */ if (ConfGet("bpf-filter", &bpf_filter) != 1) { if (ConfGetChildValue(if_root, "bpf-filter", &bpf_filter) == 1) { if (strlen(bpf_filter) > 0) { aconf->bpf_filter = bpf_filter; SCLogInfo("Going to use bpf filter %s", aconf->bpf_filter); } } } if ((ConfGetChildValueInt(if_root, "buffer-size", &value)) == 1) { aconf->buffer_size = value; } else { aconf->buffer_size = 0; } if ((ConfGetChildValueInt(if_root, "ring-size", &value)) == 1) { aconf->ring_size = value; if (value * aconf->threads < max_pending_packets) { aconf->ring_size = max_pending_packets / aconf->threads + 1; SCLogWarning(SC_ERR_AFP_CREATE, "Inefficient setup: ring-size < max_pending_packets. " "Resetting to decent value %d.", aconf->ring_size); /* We want at least that max_pending_packets packets can be handled by the * interface. This is generous if we have multiple interfaces listening. */ } } else { /* We want that max_pending_packets packets can be handled by suricata * for this interface. To take burst into account we multiply the obtained * size by 2. */ aconf->ring_size = max_pending_packets * 2 / aconf->threads; } (void)ConfGetChildValueBool(if_root, "disable-promisc", (int *)&boolval); if (boolval) { SCLogInfo("Disabling promiscuous mode on iface %s", aconf->iface); aconf->promisc = 0; } if (ConfGetChildValue(if_root, "checksum-checks", &tmpctype) == 1) { if (strcmp(tmpctype, "auto") == 0) { aconf->checksum_mode = CHECKSUM_VALIDATION_AUTO; } else if (strcmp(tmpctype, "yes") == 0) { aconf->checksum_mode = CHECKSUM_VALIDATION_ENABLE; } else if (strcmp(tmpctype, "no") == 0) { aconf->checksum_mode = CHECKSUM_VALIDATION_DISABLE; } else if (strcmp(tmpctype, "kernel") == 0) { aconf->checksum_mode = CHECKSUM_VALIDATION_KERNEL; } else { SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid value for checksum-checks for %s", aconf->iface); } } return aconf; }
/** * \brief extract information from config file * * The returned structure will be freed by the thread init function. * This is thus necessary to or copy the structure before giving it * to thread or to reparse the file for each thread (and thus have * new structure. * * \return a AFPIfaceConfig corresponding to the interface name */ void *ParseAFPConfig(const char *iface) { char *threadsstr = NULL; ConfNode *if_root; ConfNode *af_packet_node; AFPIfaceConfig *aconf = SCMalloc(sizeof(*aconf)); char *tmpclusterid; char *tmpctype; intmax_t value; int boolval; char *bpf_filter = NULL; if (aconf == NULL) { return NULL; } if (iface == NULL) { SCFree(aconf); return NULL; } strlcpy(aconf->iface, iface, sizeof(aconf->iface)); aconf->threads = 1; SC_ATOMIC_INIT(aconf->ref); (void) SC_ATOMIC_ADD(aconf->ref, 1); aconf->buffer_size = 0; aconf->cluster_id = 1; aconf->cluster_type = PACKET_FANOUT_HASH; aconf->promisc = 1; aconf->checksum_mode = CHECKSUM_VALIDATION_KERNEL; aconf->DerefFunc = AFPDerefConfig; aconf->flags = 0; aconf->bpf_filter = NULL; if (ConfGet("bpf-filter", &bpf_filter) == 1) { if (strlen(bpf_filter) > 0) { aconf->bpf_filter = bpf_filter; SCLogInfo("Going to use command-line provided bpf filter '%s'", aconf->bpf_filter); } } /* Find initial node */ af_packet_node = ConfGetNode("af-packet"); if (af_packet_node == NULL) { SCLogInfo("Unable to find af-packet config using default value"); return aconf; } if_root = ConfNodeLookupKeyValue(af_packet_node, "interface", iface); if (if_root == NULL) { SCLogInfo("Unable to find af-packet config for " "interface %s, using default value", iface); return aconf; } if (ConfGetChildValue(if_root, "threads", &threadsstr) != 1) { aconf->threads = 1; } else { if (threadsstr != NULL) { aconf->threads = (uint8_t)atoi(threadsstr); } } if (aconf->threads == 0) { aconf->threads = 1; } SC_ATOMIC_RESET(aconf->ref); (void) SC_ATOMIC_ADD(aconf->ref, aconf->threads); if (ConfGetChildValue(if_root, "cluster-id", &tmpclusterid) != 1) { SCLogError(SC_ERR_INVALID_ARGUMENT,"Could not get cluster-id from config"); } else { aconf->cluster_id = (uint16_t)atoi(tmpclusterid); SCLogDebug("Going to use cluster-id %" PRId32, aconf->cluster_id); } if (ConfGetChildValue(if_root, "cluster-type", &tmpctype) != 1) { SCLogError(SC_ERR_GET_CLUSTER_TYPE_FAILED,"Could not get cluster-type from config"); } else if (strcmp(tmpctype, "cluster_round_robin") == 0) { SCLogInfo("Using round-robin cluster mode for AF_PACKET (iface %s)", aconf->iface); aconf->cluster_type = PACKET_FANOUT_LB; } else if (strcmp(tmpctype, "cluster_flow") == 0) { /* In hash mode, we also ask for defragmentation needed to * compute the hash */ uint16_t defrag = 0; SCLogInfo("Using flow cluster mode for AF_PACKET (iface %s)", aconf->iface); ConfGetChildValueBool(if_root, "defrag", (int *)&defrag); if (defrag) { SCLogInfo("Using defrag kernel functionnality for AF_PACKET (iface %s)", aconf->iface); defrag = PACKET_FANOUT_FLAG_DEFRAG; } aconf->cluster_type = PACKET_FANOUT_HASH | defrag; } else if (strcmp(tmpctype, "cluster_cpu") == 0) { SCLogInfo("Using cpu cluster mode for AF_PACKET (iface %s)", aconf->iface); aconf->cluster_type = PACKET_FANOUT_CPU; } else { SCLogError(SC_ERR_INVALID_CLUSTER_TYPE,"invalid cluster-type %s",tmpctype); SCFree(aconf); return NULL; } /*load af_packet bpf filter*/ /* command line value has precedence */ if (ConfGet("bpf-filter", &bpf_filter) != 1) { if (ConfGetChildValue(if_root, "bpf-filter", &bpf_filter) == 1) { if (strlen(bpf_filter) > 0) { aconf->bpf_filter = bpf_filter; SCLogInfo("Going to use bpf filter %s", aconf->bpf_filter); } } } if ((ConfGetChildValueInt(if_root, "buffer-size", &value)) == 1) { aconf->buffer_size = value; } else { aconf->buffer_size = 0; } (void)ConfGetChildValueBool(if_root, "disable-promisc", (int *)&boolval); if (boolval) { SCLogInfo("Disabling promiscuous mode on iface %s", aconf->iface); aconf->promisc = 0; } (void)ConfGetChildValueBool(if_root, "use-mmap", (int *)&boolval); if (boolval) { SCLogInfo("Enabling mmaped capture on iface %s", aconf->iface); aconf->flags |= AFP_RING_MODE; } if (ConfGetChildValue(if_root, "checksum-checks", &tmpctype) == 1) { if (strcmp(tmpctype, "auto") == 0) { aconf->checksum_mode = CHECKSUM_VALIDATION_AUTO; } else if (strcmp(tmpctype, "yes") == 0) { aconf->checksum_mode = CHECKSUM_VALIDATION_ENABLE; } else if (strcmp(tmpctype, "no") == 0) { aconf->checksum_mode = CHECKSUM_VALIDATION_DISABLE; } else if (strcmp(tmpctype, "kernel") == 0) { aconf->checksum_mode = CHECKSUM_VALIDATION_KERNEL; } else { SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid value for checksum-checks for %s", aconf->iface); } } return aconf; }
/** \brief configure and initializes redis output logging * \param conf ConfNode structure for the output section in question * \param log_ctx Log file context allocated by caller * \retval 0 on success */ int SCConfLogOpenRedis(ConfNode *redis_node, void *lf_ctx) { LogFileCtx *log_ctx = lf_ctx; const char *redis_port = NULL; const char *redis_mode = NULL; int is_async = 0; if (redis_node) { log_ctx->redis_setup.server = ConfNodeLookupChildValue(redis_node, "server"); log_ctx->redis_setup.key = ConfNodeLookupChildValue(redis_node, "key"); redis_port = ConfNodeLookupChildValue(redis_node, "port"); redis_mode = ConfNodeLookupChildValue(redis_node, "mode"); (void)ConfGetChildValueBool(redis_node, "async", &is_async); } if (!log_ctx->redis_setup.server) { log_ctx->redis_setup.server = redis_default_server; SCLogInfo("Using default redis server (127.0.0.1)"); } if (!redis_port) redis_port = "6379"; if (!redis_mode) redis_mode = "list"; if (!log_ctx->redis_setup.key) { log_ctx->redis_setup.key = redis_default_key; } #ifndef HAVE_LIBEVENT if (is_async) { SCLogWarning(SC_ERR_NO_REDIS_ASYNC, "async option not available."); } is_async = 0; #endif //ifndef HAVE_LIBEVENT log_ctx->redis_setup.is_async = is_async; log_ctx->redis_setup.batch_size = 0; if (redis_node) { ConfNode *pipelining = ConfNodeLookupChild(redis_node, "pipelining"); if (pipelining) { int enabled = 0; int ret; intmax_t val; ret = ConfGetChildValueBool(pipelining, "enabled", &enabled); if (ret && enabled) { ret = ConfGetChildValueInt(pipelining, "batch-size", &val); if (ret) { log_ctx->redis_setup.batch_size = val; } else { log_ctx->redis_setup.batch_size = 10; } } } } else { log_ctx->redis_setup.batch_size = 0; } if (!strcmp(redis_mode, "list") || !strcmp(redis_mode,"lpush")) { log_ctx->redis_setup.command = redis_lpush_cmd; } else if(!strcmp(redis_mode, "rpush")){ log_ctx->redis_setup.command = redis_rpush_cmd; } else if(!strcmp(redis_mode,"channel") || !strcmp(redis_mode,"publish")) { log_ctx->redis_setup.command = redis_publish_cmd; } else { SCLogError(SC_ERR_REDIS_CONFIG,"Invalid redis mode"); exit(EXIT_FAILURE); } /* store server params for reconnection */ if (!log_ctx->redis_setup.server) { SCLogError(SC_ERR_MEM_ALLOC, "Error allocating redis server string"); exit(EXIT_FAILURE); } log_ctx->redis_setup.port = atoi(redis_port); log_ctx->Close = SCLogFileCloseRedis; #ifdef HAVE_LIBEVENT if (is_async) { log_ctx->redis = SCLogRedisContextAsyncAlloc(); } #endif /*HAVE_LIBEVENT*/ if (! is_async) { log_ctx->redis = SCLogRedisContextAlloc(); SCConfLogReopenSyncRedis(log_ctx); } return 0; }