OutputCtx *OutputStatsLogInitSub(ConfNode *conf, OutputCtx *parent_ctx) { AlertJsonThread *ajt = parent_ctx->data; OutputStatsCtx *stats_ctx = SCMalloc(sizeof(OutputStatsCtx)); if (unlikely(stats_ctx == NULL)) return NULL; stats_ctx->flags = JSON_STATS_TOTALS; if (conf != NULL) { const char *totals = ConfNodeLookupChildValue(conf, "totals"); const char *threads = ConfNodeLookupChildValue(conf, "threads"); const char *deltas = ConfNodeLookupChildValue(conf, "deltas"); SCLogDebug("totals %s threads %s deltas %s", totals, threads, deltas); if ((totals != NULL && ConfValIsFalse(totals)) && (threads != NULL && ConfValIsFalse(threads))) { SCFree(stats_ctx); SCLogError(SC_ERR_JSON_STATS_LOG_NEGATED, "Cannot disable both totals and threads in stats logging"); return NULL; } if (totals != NULL && ConfValIsFalse(totals)) { stats_ctx->flags &= ~JSON_STATS_TOTALS; } if (threads != NULL && ConfValIsTrue(threads)) { stats_ctx->flags |= JSON_STATS_THREADS; } if (deltas != NULL && ConfValIsTrue(deltas)) { stats_ctx->flags |= JSON_STATS_DELTAS; } SCLogDebug("stats_ctx->flags %08x", stats_ctx->flags); } OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) { SCFree(stats_ctx); return NULL; } stats_ctx->file_ctx = ajt->file_ctx; output_ctx->data = stats_ctx; output_ctx->DeInit = OutputStatsLogDeinitSub; return output_ctx; }
int AppLayerParserConfParserEnabled(const char *ipproto, const char *alproto_name) { SCEnter(); int enabled = 1; char param[100]; ConfNode *node; int r; if (RunmodeIsUnittests()) goto enabled; r = snprintf(param, sizeof(param), "%s%s%s", "app-layer.protocols.", alproto_name, ".enabled"); if (r < 0) { SCLogError(SC_ERR_FATAL, "snprintf failure."); exit(EXIT_FAILURE); } else if (r > (int)sizeof(param)) { SCLogError(SC_ERR_FATAL, "buffer not big enough to write param."); exit(EXIT_FAILURE); } node = ConfGetNode(param); if (node == NULL) { SCLogDebug("Entry for %s not found.", param); r = snprintf(param, sizeof(param), "%s%s%s%s%s", "app-layer.protocols.", alproto_name, ".", ipproto, ".enabled"); if (r < 0) { SCLogError(SC_ERR_FATAL, "snprintf failure."); exit(EXIT_FAILURE); } else if (r > (int)sizeof(param)) { SCLogError(SC_ERR_FATAL, "buffer not big enough to write param."); exit(EXIT_FAILURE); } node = ConfGetNode(param); if (node == NULL) { SCLogDebug("Entry for %s not found.", param); goto enabled; } } if (ConfValIsTrue(node->val)) { goto enabled; } else if (ConfValIsFalse(node->val)) { goto disabled; } else if (strcasecmp(node->val, "detection-only") == 0) { goto disabled; } else { SCLogError(SC_ERR_FATAL, "Invalid value found for %s.", param); exit(EXIT_FAILURE); } disabled: enabled = 0; enabled: SCReturnInt(enabled); }
/** \brief Create a new http log LogFileCtx. * \param conf Pointer to ConfNode containing this loggers configuration. * \return NULL if failure, LogFileCtx* to the file_ctx if succesful * */ OutputCtx *LogStatsLogInitCtx(ConfNode *conf) { LogFileCtx *file_ctx = LogFileNewCtx(); if (file_ctx == NULL) { SCLogError(SC_ERR_HTTP_LOG_GENERIC, "couldn't create new file_ctx"); return NULL; } if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(file_ctx); return NULL; } LogStatsFileCtx *statslog_ctx = SCMalloc(sizeof(LogStatsFileCtx)); if (unlikely(statslog_ctx == NULL)) { LogFileFreeCtx(file_ctx); return NULL; } memset(statslog_ctx, 0x00, sizeof(LogStatsFileCtx)); statslog_ctx->flags = LOG_STATS_TOTALS; if (conf != NULL) { const char *totals = ConfNodeLookupChildValue(conf, "totals"); const char *threads = ConfNodeLookupChildValue(conf, "threads"); const char *nulls = ConfNodeLookupChildValue(conf, "null-values"); SCLogDebug("totals %s threads %s", totals, threads); if (totals != NULL && ConfValIsFalse(totals)) { statslog_ctx->flags &= ~LOG_STATS_TOTALS; } if (threads != NULL && ConfValIsTrue(threads)) { statslog_ctx->flags |= LOG_STATS_THREADS; } if (nulls != NULL && ConfValIsTrue(nulls)) { statslog_ctx->flags |= LOG_STATS_NULLS; } SCLogDebug("statslog_ctx->flags %08x", statslog_ctx->flags); } statslog_ctx->file_ctx = file_ctx; OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) { LogFileFreeCtx(file_ctx); SCFree(statslog_ctx); return NULL; } output_ctx->data = statslog_ctx; output_ctx->DeInit = LogStatsLogDeInitCtx; SCLogDebug("STATS log output initialized"); return output_ctx; }
OutputCtx *OutputStatsLogInit(ConfNode *conf) { LogFileCtx *file_ctx = LogFileNewCtx(); if(file_ctx == NULL) { SCLogError(SC_ERR_STATS_LOG_GENERIC, "couldn't create new file_ctx"); return NULL; } if (SCConfLogOpenGeneric(conf, file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(file_ctx); return NULL; } OutputStatsCtx *stats_ctx = SCMalloc(sizeof(OutputStatsCtx)); if (unlikely(stats_ctx == NULL)) { LogFileFreeCtx(file_ctx); return NULL; } stats_ctx->flags = JSON_STATS_TOTALS; if (conf != NULL) { const char *totals = ConfNodeLookupChildValue(conf, "totals"); const char *threads = ConfNodeLookupChildValue(conf, "threads"); const char *deltas = ConfNodeLookupChildValue(conf, "deltas"); SCLogDebug("totals %s threads %s deltas %s", totals, threads, deltas); if (totals != NULL && ConfValIsFalse(totals)) { stats_ctx->flags &= ~JSON_STATS_TOTALS; } if (threads != NULL && ConfValIsTrue(threads)) { stats_ctx->flags |= JSON_STATS_THREADS; } if (deltas != NULL && ConfValIsTrue(deltas)) { stats_ctx->flags |= JSON_STATS_DELTAS; } SCLogDebug("stats_ctx->flags %08x", stats_ctx->flags); } OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) { LogFileFreeCtx(file_ctx); SCFree(stats_ctx); return NULL; } stats_ctx->file_ctx = file_ctx; output_ctx->data = stats_ctx; output_ctx->DeInit = OutputStatsLogDeinit; return output_ctx; }
/** * \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 NetmapIfaceConfig corresponding to the interface name */ static void *ParseNetmapConfig(const char *iface_name) { char *threadsstr = NULL; ConfNode *if_root; ConfNode *if_default = NULL; ConfNode *netmap_node; NetmapIfaceConfig *aconf = SCMalloc(sizeof(*aconf)); char *tmpctype; char *copymodestr; int boolval; char *bpf_filter = NULL; char *out_iface = NULL; if (unlikely(aconf == NULL)) { return NULL; } if (iface_name == NULL) { SCFree(aconf); return NULL; } memset(aconf, 0, sizeof(*aconf)); aconf->DerefFunc = NetmapDerefConfig; aconf->threads = 1; aconf->promisc = 1; aconf->checksum_mode = CHECKSUM_VALIDATION_AUTO; aconf->copy_mode = NETMAP_COPY_MODE_NONE; strlcpy(aconf->iface_name, iface_name, sizeof(aconf->iface_name)); SC_ATOMIC_INIT(aconf->ref); (void) SC_ATOMIC_ADD(aconf->ref, 1); strlcpy(aconf->iface, aconf->iface_name, sizeof(aconf->iface)); if (aconf->iface[0]) { size_t len = strlen(aconf->iface); if (aconf->iface[len-1] == '+') { aconf->iface[len-1] = '\0'; aconf->iface_sw = 1; } } 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 */ netmap_node = ConfGetNode("netmap"); if (netmap_node == NULL) { SCLogInfo("Unable to find netmap config using default value"); return aconf; } if_root = ConfFindDeviceConfig(netmap_node, aconf->iface_name); if_default = ConfFindDeviceConfig(netmap_node, "default"); if (if_root == NULL && if_default == NULL) { SCLogInfo("Unable to find netmap config for " "interface \"%s\" or \"default\", using default value", aconf->iface_name); return aconf; } /* If there is no setting for current interface use default one as main iface */ if (if_root == NULL) { if_root = if_default; if_default = NULL; } if (ConfGetChildValueWithDefault(if_root, if_default, "threads", &threadsstr) != 1) { aconf->threads = 1; } else { if (strcmp(threadsstr, "auto") == 0) { aconf->threads = GetIfaceRSSQueuesNum(aconf->iface); } else { aconf->threads = (uint8_t)atoi(threadsstr); } } if (aconf->threads <= 0) { aconf->threads = 1; } if (aconf->threads) { SCLogInfo("Using %d threads for interface %s", aconf->threads, aconf->iface_name); } if (ConfGetChildValueWithDefault(if_root, if_default, "copy-iface", &out_iface) == 1) { if (strlen(out_iface) > 0) { aconf->out_iface_name = out_iface; } } if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", ©modestr) == 1) { if (aconf->out_iface_name == NULL) { SCLogInfo("Copy mode activated but no destination" " iface. Disabling feature"); } else if (strlen(copymodestr) <= 0) { aconf->out_iface_name = NULL; } else if (strcmp(copymodestr, "ips") == 0) { SCLogInfo("Netmap IPS mode activated %s->%s", aconf->iface_name, aconf->out_iface_name); aconf->copy_mode = NETMAP_COPY_MODE_IPS; } else if (strcmp(copymodestr, "tap") == 0) { SCLogInfo("Netmap TAP mode activated %s->%s", aconf->iface_name, aconf->out_iface_name); aconf->copy_mode = NETMAP_COPY_MODE_TAP; } else { SCLogInfo("Invalid mode (not in tap, ips)"); } } if (aconf->out_iface_name && aconf->out_iface_name[0]) { strlcpy(aconf->out_iface, aconf->out_iface_name, sizeof(aconf->out_iface)); size_t len = strlen(aconf->out_iface); if (aconf->out_iface[len-1] == '+') { aconf->out_iface[len-1] = '\0'; aconf->out_iface_sw = 1; } } SC_ATOMIC_RESET(aconf->ref); (void) SC_ATOMIC_ADD(aconf->ref, aconf->threads); /* load netmap bpf filter */ /* command line value has precedence */ if (ConfGet("bpf-filter", &bpf_filter) != 1) { if (ConfGetChildValueWithDefault(if_root, if_default, "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); } } } (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "disable-promisc", (int *)&boolval); if (boolval) { SCLogInfo("Disabling promiscuous mode on iface %s", aconf->iface); aconf->promisc = 0; } if (ConfGetChildValueWithDefault(if_root, if_default, "checksum-checks", &tmpctype) == 1) { if (strcmp(tmpctype, "auto") == 0) { aconf->checksum_mode = CHECKSUM_VALIDATION_AUTO; } else if (ConfValIsTrue(tmpctype)) { aconf->checksum_mode = CHECKSUM_VALIDATION_ENABLE; } else if (ConfValIsFalse(tmpctype)) { aconf->checksum_mode = CHECKSUM_VALIDATION_DISABLE; } else { SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid value for checksum-checks for %s", aconf->iface_name); } } return aconf; }
static int ParseNetmapSettings(NetmapIfaceSettings *ns, const char *iface, ConfNode *if_root, ConfNode *if_default) { ns->threads = 0; ns->promisc = 1; ns->checksum_mode = CHECKSUM_VALIDATION_AUTO; ns->copy_mode = NETMAP_COPY_MODE_NONE; strlcpy(ns->iface, iface, sizeof(ns->iface)); if (ns->iface[0]) { size_t len = strlen(ns->iface); if (ns->iface[len-1] == '+') { ns->iface[len-1] = '\0'; ns->sw_ring = 1; } } char *bpf_filter = NULL; if (ConfGet("bpf-filter", &bpf_filter) == 1) { if (strlen(bpf_filter) > 0) { ns->bpf_filter = bpf_filter; SCLogInfo("Going to use command-line provided bpf filter '%s'", ns->bpf_filter); } } if (if_root == NULL && if_default == NULL) { SCLogInfo("Unable to find netmap config for " "interface \"%s\" or \"default\", using default values", iface); goto finalize; /* If there is no setting for current interface use default one as main iface */ } else if (if_root == NULL) { if_root = if_default; if_default = NULL; } char *threadsstr = NULL; if (ConfGetChildValueWithDefault(if_root, if_default, "threads", &threadsstr) != 1) { ns->threads = 0; } else { if (strcmp(threadsstr, "auto") == 0) { ns->threads = 0; } else { ns->threads = (uint8_t)atoi(threadsstr); } } /* load netmap bpf filter */ /* command line value has precedence */ if (ns->bpf_filter == NULL) { if (ConfGetChildValueWithDefault(if_root, if_default, "bpf-filter", &bpf_filter) == 1) { if (strlen(bpf_filter) > 0) { ns->bpf_filter = bpf_filter; SCLogInfo("Going to use bpf filter %s", ns->bpf_filter); } } } int boolval = 0; (void)ConfGetChildValueBoolWithDefault(if_root, if_default, "disable-promisc", (int *)&boolval); if (boolval) { SCLogInfo("Disabling promiscuous mode on iface %s", ns->iface); ns->promisc = 0; } char *tmpctype; if (ConfGetChildValueWithDefault(if_root, if_default, "checksum-checks", &tmpctype) == 1) { if (strcmp(tmpctype, "auto") == 0) { ns->checksum_mode = CHECKSUM_VALIDATION_AUTO; } else if (ConfValIsTrue(tmpctype)) { ns->checksum_mode = CHECKSUM_VALIDATION_ENABLE; } else if (ConfValIsFalse(tmpctype)) { ns->checksum_mode = CHECKSUM_VALIDATION_DISABLE; } else { SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Invalid value for " "checksum-checks for %s", iface); } } char *copymodestr; if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", ©modestr) == 1) { if (strcmp(copymodestr, "ips") == 0) { ns->copy_mode = NETMAP_COPY_MODE_IPS; } else if (strcmp(copymodestr, "tap") == 0) { ns->copy_mode = NETMAP_COPY_MODE_TAP; } else { SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Invalid copy-mode " "(valid are tap, ips)"); } } finalize: if (ns->sw_ring) { /* just one thread per interface supported */ ns->threads = 1; } else if (ns->threads == 0) { /* As NetmapGetRSSCount is broken on Linux, first run * GetIfaceRSSQueuesNum. If that fails, run NetmapGetRSSCount */ ns->threads = GetIfaceRSSQueuesNum(ns->iface); if (ns->threads == 0) { ns->threads = NetmapGetRSSCount(ns->iface); } } if (ns->threads <= 0) { ns->threads = 1; } 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. * * If old config system is used, then return the smae parameters * value for each interface. * * \return a PfringIfaceConfig corresponding to the interface name */ static void *ParsePfringConfig(const char *iface) { const char *threadsstr = NULL; ConfNode *if_root; ConfNode *if_default = NULL; ConfNode *pf_ring_node; PfringIfaceConfig *pfconf = SCMalloc(sizeof(*pfconf)); const char *tmpclusterid; const char *tmpctype = NULL; cluster_type default_ctype = CLUSTER_ROUND_ROBIN; int getctype = 0; const char *bpf_filter = NULL; if (unlikely(pfconf == NULL)) { return NULL; } if (iface == NULL) { SCFree(pfconf); return NULL; } memset(pfconf, 0, sizeof(PfringIfaceConfig)); strlcpy(pfconf->iface, iface, sizeof(pfconf->iface)); pfconf->threads = 1; pfconf->cluster_id = 1; pfconf->ctype = (cluster_type)default_ctype; pfconf->DerefFunc = PfringDerefConfig; SC_ATOMIC_INIT(pfconf->ref); (void) SC_ATOMIC_ADD(pfconf->ref, 1); /* Find initial node */ pf_ring_node = ConfGetNode("pfring"); if (pf_ring_node == NULL) { SCLogInfo("Unable to find pfring config using default value"); return pfconf; } if_root = ConfFindDeviceConfig(pf_ring_node, iface); if_default = ConfFindDeviceConfig(pf_ring_node, "default"); if (if_root == NULL && if_default == NULL) { SCLogInfo("Unable to find pfring config for " "interface %s, using default value or 1.0 " "configuration system. ", iface); return pfconf; } /* If there is no setting for current interface use default one as main iface */ if (if_root == NULL) { if_root = if_default; if_default = NULL; } if (ConfGetChildValueWithDefault(if_root, if_default, "threads", &threadsstr) != 1) { pfconf->threads = 1; } else { if (threadsstr != NULL) { pfconf->threads = (uint8_t)atoi(threadsstr); } } if (pfconf->threads == 0) { pfconf->threads = 1; } SC_ATOMIC_RESET(pfconf->ref); (void) SC_ATOMIC_ADD(pfconf->ref, pfconf->threads); /* command line value has precedence */ if (ConfGet("pfring.cluster-id", &tmpclusterid) == 1) { pfconf->cluster_id = (uint16_t)atoi(tmpclusterid); pfconf->flags |= PFRING_CONF_FLAGS_CLUSTER; SCLogDebug("Going to use command-line provided cluster-id %" PRId32, pfconf->cluster_id); } else { if (strncmp(pfconf->iface, "zc", 2) == 0) { SCLogInfo("ZC interface detected, not setting cluster-id for PF_RING (iface %s)", pfconf->iface); } else if ((pfconf->threads == 1) && (strncmp(pfconf->iface, "dna", 3) == 0)) { SCLogInfo("DNA interface detected, not setting cluster-id for PF_RING (iface %s)", pfconf->iface); } else if (ConfGetChildValueWithDefault(if_root, if_default, "cluster-id", &tmpclusterid) != 1) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Could not get cluster-id from config"); } else { pfconf->cluster_id = (uint16_t)atoi(tmpclusterid); pfconf->flags |= PFRING_CONF_FLAGS_CLUSTER; SCLogDebug("Going to use cluster-id %" PRId32, pfconf->cluster_id); } } /*load pfring bpf filter*/ /* command line value has precedence */ if (ConfGet("bpf-filter", &bpf_filter) == 1) { if (strlen(bpf_filter) > 0) { pfconf->bpf_filter = SCStrdup(bpf_filter); if (unlikely(pfconf->bpf_filter == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate BPF filter string"); } else { SCLogDebug("Going to use command-line provided bpf filter %s", pfconf->bpf_filter); } } } else { if (ConfGetChildValueWithDefault(if_root, if_default, "bpf-filter", &bpf_filter) == 1) { if (strlen(bpf_filter) > 0) { pfconf->bpf_filter = SCStrdup(bpf_filter); if (unlikely(pfconf->bpf_filter == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Can't allocate BPF filter string"); } else { SCLogDebug("Going to use bpf filter %s", pfconf->bpf_filter); } } } } if (ConfGet("pfring.cluster-type", &tmpctype) == 1) { SCLogDebug("Going to use command-line provided cluster-type"); getctype = 1; } else { if (strncmp(pfconf->iface, "zc", 2) == 0) { SCLogInfo("ZC interface detected, not setting cluster type for PF_RING (iface %s)", pfconf->iface); } else if ((pfconf->threads == 1) && (strncmp(pfconf->iface, "dna", 3) == 0)) { SCLogInfo("DNA interface detected, not setting cluster type for PF_RING (iface %s)", pfconf->iface); } else if (ConfGetChildValueWithDefault(if_root, if_default, "cluster-type", &tmpctype) != 1) { SCLogError(SC_ERR_GET_CLUSTER_TYPE_FAILED, "Could not get cluster-type from config"); } else { getctype = 1; } } if (getctype) { if (strcmp(tmpctype, "cluster_round_robin") == 0) { SCLogInfo("Using round-robin cluster mode for PF_RING (iface %s)", pfconf->iface); pfconf->ctype = CLUSTER_ROUND_ROBIN; } else if (strcmp(tmpctype, "cluster_flow") == 0) { SCLogInfo("Using flow cluster mode for PF_RING (iface %s)", pfconf->iface); pfconf->ctype = CLUSTER_FLOW; } else { SCLogError(SC_ERR_INVALID_CLUSTER_TYPE, "invalid cluster-type %s", tmpctype); SCFree(pfconf); return NULL; } } if (ConfGetChildValueWithDefault(if_root, if_default, "checksum-checks", &tmpctype) == 1) { if (strcmp(tmpctype, "auto") == 0) { pfconf->checksum_mode = CHECKSUM_VALIDATION_AUTO; } else if (ConfValIsTrue(tmpctype)) { pfconf->checksum_mode = CHECKSUM_VALIDATION_ENABLE; } else if (ConfValIsFalse(tmpctype)) { pfconf->checksum_mode = CHECKSUM_VALIDATION_DISABLE; } else if (strcmp(tmpctype, "rx-only") == 0) { pfconf->checksum_mode = CHECKSUM_VALIDATION_RXONLY; } else { SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid value for checksum-checks for %s", pfconf->iface); } } return pfconf; }
/** \brief open a generic output "log file", which may be a regular file or a socket * \param conf ConfNode structure for the output section in question * \param log_ctx Log file context allocated by caller * \param default_filename Default name of file to open, if not specified in ConfNode * \param rotate Register the file for rotation in HUP. * \retval 0 on success * \retval -1 on error */ int SCConfLogOpenGeneric(ConfNode *conf, LogFileCtx *log_ctx, const char *default_filename, int rotate) { char log_path[PATH_MAX]; const char *log_dir; const char *filename, *filetype; // Arg check if (conf == NULL || log_ctx == NULL || default_filename == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "SCConfLogOpenGeneric(conf %p, ctx %p, default %p) " "missing an argument", conf, log_ctx, default_filename); return -1; } if (log_ctx->fp != NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "SCConfLogOpenGeneric: previously initialized Log CTX " "encountered"); return -1; } // Resolve the given config filename = ConfNodeLookupChildValue(conf, "filename"); if (filename == NULL) filename = default_filename; log_dir = ConfigGetLogDirectory(); if (PathIsAbsolute(filename)) { snprintf(log_path, PATH_MAX, "%s", filename); } else { snprintf(log_path, PATH_MAX, "%s/%s", log_dir, filename); } /* Rotate log file based on time */ const char *rotate_int = ConfNodeLookupChildValue(conf, "rotate-interval"); if (rotate_int != NULL) { time_t now = time(NULL); log_ctx->flags |= LOGFILE_ROTATE_INTERVAL; /* Use a specific time */ if (strcmp(rotate_int, "minute") == 0) { log_ctx->rotate_time = now + SCGetSecondsUntil(rotate_int, now); log_ctx->rotate_interval = 60; } else if (strcmp(rotate_int, "hour") == 0) { log_ctx->rotate_time = now + SCGetSecondsUntil(rotate_int, now); log_ctx->rotate_interval = 3600; } else if (strcmp(rotate_int, "day") == 0) { log_ctx->rotate_time = now + SCGetSecondsUntil(rotate_int, now); log_ctx->rotate_interval = 86400; } /* Use a timer */ else { log_ctx->rotate_interval = SCParseTimeSizeString(rotate_int); if (log_ctx->rotate_interval == 0) { SCLogError(SC_ERR_INVALID_NUMERIC_VALUE, "invalid rotate-interval value"); exit(EXIT_FAILURE); } log_ctx->rotate_time = now + log_ctx->rotate_interval; } } filetype = ConfNodeLookupChildValue(conf, "filetype"); if (filetype == NULL) filetype = DEFAULT_LOG_FILETYPE; const char *filemode = ConfNodeLookupChildValue(conf, "filemode"); uint32_t mode = 0; if (filemode != NULL && ByteExtractStringUint32(&mode, 8, strlen(filemode), filemode) > 0) { log_ctx->filemode = mode; } const char *append = ConfNodeLookupChildValue(conf, "append"); if (append == NULL) append = DEFAULT_LOG_MODE_APPEND; /* JSON flags */ #ifdef HAVE_LIBJANSSON log_ctx->json_flags = JSON_PRESERVE_ORDER|JSON_COMPACT| JSON_ENSURE_ASCII|JSON_ESCAPE_SLASH; ConfNode *json_flags = ConfNodeLookupChild(conf, "json"); if (json_flags != 0) { const char *preserve_order = ConfNodeLookupChildValue(json_flags, "preserve-order"); if (preserve_order != NULL && ConfValIsFalse(preserve_order)) log_ctx->json_flags &= ~(JSON_PRESERVE_ORDER); const char *compact = ConfNodeLookupChildValue(json_flags, "compact"); if (compact != NULL && ConfValIsFalse(compact)) log_ctx->json_flags &= ~(JSON_COMPACT); const char *ensure_ascii = ConfNodeLookupChildValue(json_flags, "ensure-ascii"); if (ensure_ascii != NULL && ConfValIsFalse(ensure_ascii)) log_ctx->json_flags &= ~(JSON_ENSURE_ASCII); const char *escape_slash = ConfNodeLookupChildValue(json_flags, "escape-slash"); if (escape_slash != NULL && ConfValIsFalse(escape_slash)) log_ctx->json_flags &= ~(JSON_ESCAPE_SLASH); } #endif /* HAVE_LIBJANSSON */ // Now, what have we been asked to open? if (strcasecmp(filetype, "unix_stream") == 0) { #ifdef BUILD_WITH_UNIXSOCKET /* Don't bail. May be able to connect later. */ log_ctx->is_sock = 1; log_ctx->sock_type = SOCK_STREAM; log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_STREAM, 1); #else return -1; #endif } else if (strcasecmp(filetype, "unix_dgram") == 0) { #ifdef BUILD_WITH_UNIXSOCKET /* Don't bail. May be able to connect later. */ log_ctx->is_sock = 1; log_ctx->sock_type = SOCK_DGRAM; log_ctx->fp = SCLogOpenUnixSocketFp(log_path, SOCK_DGRAM, 1); #else return -1; #endif } else if (strcasecmp(filetype, DEFAULT_LOG_FILETYPE) == 0 || strcasecmp(filetype, "file") == 0) { log_ctx->fp = SCLogOpenFileFp(log_path, append, log_ctx->filemode); if (log_ctx->fp == NULL) return -1; // Error already logged by Open...Fp routine log_ctx->is_regular = 1; if (rotate) { OutputRegisterFileRotationFlag(&log_ctx->rotation_flag); } } else if (strcasecmp(filetype, "pcie") == 0) { log_ctx->pcie_fp = SCLogOpenPcieFp(log_ctx, log_path, append); if (log_ctx->pcie_fp == NULL) return -1; // Error already logged by Open...Fp routine #ifdef HAVE_LIBHIREDIS } else if (strcasecmp(filetype, "redis") == 0) { ConfNode *redis_node = ConfNodeLookupChild(conf, "redis"); if (SCConfLogOpenRedis(redis_node, log_ctx) < 0) { SCLogError(SC_ERR_REDIS, "failed to open redis output"); return -1; } log_ctx->type = LOGFILE_TYPE_REDIS; #endif } else { SCLogError(SC_ERR_INVALID_YAML_CONF_ENTRY, "Invalid entry for " "%s.filetype. Expected \"regular\" (default), \"unix_stream\", " "\"pcie\" " "or \"unix_dgram\"", conf->name); } log_ctx->filename = SCStrdup(log_path); if (unlikely(log_ctx->filename == NULL)) { SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate memory for filename"); return -1; } #ifdef BUILD_WITH_UNIXSOCKET /* If a socket and running live, do non-blocking writes. */ if (log_ctx->is_sock && run_mode_offline == 0) { SCLogInfo("Setting logging socket of non-blocking in live mode."); log_ctx->send_flags |= MSG_DONTWAIT; } #endif SCLogInfo("%s output device (%s) initialized: %s", conf->name, filetype, filename); return 0; }
/** * \brief Create a new LogFileCtx for "fast" output style. * \param conf The configuration node for this output. * \return A LogFileCtx pointer on success, NULL on failure. */ OutputInitResult OutputJsonInitCtx(ConfNode *conf) { OutputInitResult result = { NULL, false }; OutputJsonCtx *json_ctx = SCCalloc(1, sizeof(OutputJsonCtx)); if (unlikely(json_ctx == NULL)) { SCLogDebug("could not create new OutputJsonCtx"); return result; } /* First lookup a sensor-name value in this outputs configuration * node (deprecated). If that fails, lookup the global one. */ const char *sensor_name = ConfNodeLookupChildValue(conf, "sensor-name"); if (sensor_name != NULL) { SCLogWarning(SC_ERR_DEPRECATED_CONF, "Found deprecated eve-log setting \"sensor-name\". " "Please set sensor-name globally."); } else { (void)ConfGet("sensor-name", &sensor_name); } json_ctx->file_ctx = LogFileNewCtx(); if (unlikely(json_ctx->file_ctx == NULL)) { SCLogDebug("AlertJsonInitCtx: Could not create new LogFileCtx"); SCFree(json_ctx); return result; } if (sensor_name) { json_ctx->file_ctx->sensor_name = SCStrdup(sensor_name); if (json_ctx->file_ctx->sensor_name == NULL) { LogFileFreeCtx(json_ctx->file_ctx); SCFree(json_ctx); return result; } } else { json_ctx->file_ctx->sensor_name = NULL; } OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx)); if (unlikely(output_ctx == NULL)) { LogFileFreeCtx(json_ctx->file_ctx); SCFree(json_ctx); return result; } output_ctx->data = json_ctx; output_ctx->DeInit = OutputJsonDeInitCtx; if (conf) { const char *output_s = ConfNodeLookupChildValue(conf, "filetype"); // Backwards compatibility if (output_s == NULL) { output_s = ConfNodeLookupChildValue(conf, "type"); } if (output_s != NULL) { if (strcmp(output_s, "file") == 0 || strcmp(output_s, "regular") == 0) { json_ctx->json_out = LOGFILE_TYPE_FILE; } else if (strcmp(output_s, "syslog") == 0) { json_ctx->json_out = LOGFILE_TYPE_SYSLOG; } else if (strcmp(output_s, "unix_dgram") == 0) { json_ctx->json_out = LOGFILE_TYPE_UNIX_DGRAM; } else if (strcmp(output_s, "unix_stream") == 0) { json_ctx->json_out = LOGFILE_TYPE_UNIX_STREAM; } else if (strcmp(output_s, "redis") == 0) { #ifdef HAVE_LIBHIREDIS SCLogRedisInit(); json_ctx->json_out = LOGFILE_TYPE_REDIS; #else SCLogError(SC_ERR_INVALID_ARGUMENT, "redis JSON output option is not compiled"); exit(EXIT_FAILURE); #endif } else { SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid JSON output option: %s", output_s); exit(EXIT_FAILURE); } } const char *prefix = ConfNodeLookupChildValue(conf, "prefix"); if (prefix != NULL) { SCLogInfo("Using prefix '%s' for JSON messages", prefix); json_ctx->file_ctx->prefix = SCStrdup(prefix); if (json_ctx->file_ctx->prefix == NULL) { SCLogError(SC_ERR_MEM_ALLOC, "Failed to allocate memory for eve-log.prefix setting."); exit(EXIT_FAILURE); } json_ctx->file_ctx->prefix_len = strlen(prefix); } if (json_ctx->json_out == LOGFILE_TYPE_FILE || json_ctx->json_out == LOGFILE_TYPE_UNIX_DGRAM || json_ctx->json_out == LOGFILE_TYPE_UNIX_STREAM) { if (SCConfLogOpenGeneric(conf, json_ctx->file_ctx, DEFAULT_LOG_FILENAME, 1) < 0) { LogFileFreeCtx(json_ctx->file_ctx); SCFree(json_ctx); SCFree(output_ctx); return result; } OutputRegisterFileRotationFlag(&json_ctx->file_ctx->rotation_flag); } #ifndef OS_WIN32 else if (json_ctx->json_out == LOGFILE_TYPE_SYSLOG) { const char *facility_s = ConfNodeLookupChildValue(conf, "facility"); if (facility_s == NULL) { facility_s = DEFAULT_ALERT_SYSLOG_FACILITY_STR; } int facility = SCMapEnumNameToValue(facility_s, SCSyslogGetFacilityMap()); if (facility == -1) { SCLogWarning(SC_ERR_INVALID_ARGUMENT, "Invalid syslog facility: \"%s\"," " now using \"%s\" as syslog facility", facility_s, DEFAULT_ALERT_SYSLOG_FACILITY_STR); facility = DEFAULT_ALERT_SYSLOG_FACILITY; } const char *level_s = ConfNodeLookupChildValue(conf, "level"); if (level_s != NULL) { int level = SCMapEnumNameToValue(level_s, SCSyslogGetLogLevelMap()); if (level != -1) { json_ctx->file_ctx->syslog_setup.alert_syslog_level = level; } } const char *ident = ConfNodeLookupChildValue(conf, "identity"); /* if null we just pass that to openlog, which will then * figure it out by itself. */ openlog(ident, LOG_PID|LOG_NDELAY, facility); } #endif #ifdef HAVE_LIBHIREDIS else if (json_ctx->json_out == LOGFILE_TYPE_REDIS) { ConfNode *redis_node = ConfNodeLookupChild(conf, "redis"); if (!json_ctx->file_ctx->sensor_name) { char hostname[1024]; gethostname(hostname, 1023); json_ctx->file_ctx->sensor_name = SCStrdup(hostname); } if (json_ctx->file_ctx->sensor_name == NULL) { LogFileFreeCtx(json_ctx->file_ctx); SCFree(json_ctx); SCFree(output_ctx); return result; } if (SCConfLogOpenRedis(redis_node, json_ctx->file_ctx) < 0) { LogFileFreeCtx(json_ctx->file_ctx); SCFree(json_ctx); SCFree(output_ctx); return result; } } #endif const char *sensor_id_s = ConfNodeLookupChildValue(conf, "sensor-id"); if (sensor_id_s != NULL) { if (ByteExtractStringUint64((uint64_t *)&sensor_id, 10, 0, sensor_id_s) == -1) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Failed to initialize JSON output, " "invalid sensor-id: %s", sensor_id_s); exit(EXIT_FAILURE); } } /* Check if top-level metadata should be logged. */ const ConfNode *metadata = ConfNodeLookupChild(conf, "metadata"); if (metadata && metadata->val && ConfValIsFalse(metadata->val)) { SCLogConfig("Disabling eve metadata logging."); json_ctx->cfg.include_metadata = false; } else { json_ctx->cfg.include_metadata = true; } /* See if we want to enable the community id */ const ConfNode *community_id = ConfNodeLookupChild(conf, "community-id"); if (community_id && community_id->val && ConfValIsTrue(community_id->val)) { SCLogConfig("Enabling eve community_id logging."); json_ctx->cfg.include_community_id = true; } else { json_ctx->cfg.include_community_id = false; } const char *cid_seed = ConfNodeLookupChildValue(conf, "community-id-seed"); if (cid_seed != NULL) { if (ByteExtractStringUint16(&json_ctx->cfg.community_id_seed, 10, 0, cid_seed) == -1) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Failed to initialize JSON output, " "invalid community-id-seed: %s", cid_seed); exit(EXIT_FAILURE); } } /* Do we have a global eve xff configuration? */ const ConfNode *xff = ConfNodeLookupChild(conf, "xff"); if (xff != NULL) { json_ctx->xff_cfg = SCCalloc(1, sizeof(HttpXFFCfg)); if (likely(json_ctx->xff_cfg != NULL)) { HttpXFFGetCfg(conf, json_ctx->xff_cfg); } } const char *pcapfile_s = ConfNodeLookupChildValue(conf, "pcap-file"); if (pcapfile_s != NULL && ConfValIsTrue(pcapfile_s)) { json_ctx->file_ctx->is_pcap_offline = (RunmodeGetCurrent() == RUNMODE_PCAP_FILE); } json_ctx->file_ctx->type = json_ctx->json_out; } SCLogDebug("returning output_ctx %p", output_ctx); result.ctx = output_ctx; result.ok = true; return result; }