/** * \brief This function is used to parse fragoffset option passed via fragoffset: keyword * * \param fragoffsetstr Pointer to the user provided fragoffset options * * \retval fragoff pointer to DetectFragOffsetData on success * \retval NULL on failure */ DetectFragOffsetData *DetectFragOffsetParse (char *fragoffsetstr) { DetectFragOffsetData *fragoff = NULL; char *substr[3] = {NULL, NULL, NULL}; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; int i; const char *str_ptr; char *mode = NULL; ret = pcre_exec(parse_regex, parse_regex_study, fragoffsetstr, strlen(fragoffsetstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 1 || ret > 4) { SCLogError(SC_ERR_PCRE_MATCH,"Parse error %s", fragoffsetstr); goto error; } for (i = 1; i < ret; i++) { res = pcre_get_substring((char *)fragoffsetstr, ov, MAX_SUBSTRINGS, i, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING,"pcre_get_substring failed"); goto error; } substr[i-1] = (char *)str_ptr; } fragoff = SCMalloc(sizeof(DetectFragOffsetData)); if (unlikely(fragoff == NULL)) goto error; fragoff->frag_off = 0; fragoff->mode = 0; mode = substr[0]; if(mode != NULL) { while(*mode != '\0') { switch(*mode) { case '>': fragoff->mode = FRAG_MORE; break; case '<': fragoff->mode = FRAG_LESS; break; } mode++; } } if (ByteExtractStringUint16(&fragoff->frag_off, 10, 0, substr[1]) < 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "specified frag offset %s is not " "valid", substr[1]); goto error; } for (i = 0; i < 3; i++) { if (substr[i] != NULL) SCFree(substr[i]); } return fragoff; error: for (i = 0; i < 3; i++) { if (substr[i] != NULL) SCFree(substr[i]); } if (fragoff != NULL) DetectFragOffsetFree(fragoff); return NULL; }
/** * \brief This function is used to parse icmp_id option passed via icmp_id: keyword * * \param icmpidstr Pointer to the user provided icmp_id options * * \retval iid pointer to DetectIcmpIdData on success * \retval NULL on failure */ DetectIcmpIdData *DetectIcmpIdParse (char *icmpidstr) { DetectIcmpIdData *iid = NULL; char *substr[3] = {NULL, NULL, NULL}; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; ret = pcre_exec(parse_regex, parse_regex_study, icmpidstr, strlen(icmpidstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 1 || ret > 4) { SCLogError(SC_ERR_PCRE_MATCH, "Parse error %s", icmpidstr); goto error; } int i; const char *str_ptr; for (i = 1; i < ret; i++) { res = pcre_get_substring((char *)icmpidstr, ov, MAX_SUBSTRINGS, i, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } substr[i-1] = (char *)str_ptr; } iid = SCMalloc(sizeof(DetectIcmpIdData)); if (unlikely(iid == NULL)) goto error; iid->id = 0; if (substr[0]!= NULL && strlen(substr[0]) != 0) { if (substr[2] == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Missing close quote in input"); goto error; } } else { if (substr[2] != NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Missing open quote in input"); goto error; } } /** \todo can ByteExtractStringUint16 do this? */ uint16_t id = 0; if (ByteExtractStringUint16(&id, 10, 0, substr[1]) < 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "specified icmp id %s is not " "valid", substr[1]); goto error; } iid->id = htons(id); for (i = 0; i < 3; i++) { if (substr[i] != NULL) SCFree(substr[i]); } return iid; error: for (i = 0; i < 3; i++) { if (substr[i] != NULL) SCFree(substr[i]); } if (iid != NULL) DetectIcmpIdFree(iid); return NULL; }
/** * \brief This function is used to parse isdataat options passed via isdataat: keyword * * \param isdataatstr Pointer to the user provided isdataat options * * \retval idad pointer to DetectIsdataatData on success * \retval NULL on failure */ DetectIsdataatData *DetectIsdataatParse (char *isdataatstr, char **offset) { DetectIsdataatData *idad = NULL; char *args[3] = {NULL,NULL,NULL}; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; int i=0; ret = pcre_exec(parse_regex, parse_regex_study, isdataatstr, strlen(isdataatstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 1 || ret > 4) { SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, isdataatstr); goto error; } if (ret > 1) { const char *str_ptr; res = pcre_get_substring((char *)isdataatstr, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } args[0] = (char *)str_ptr; if (ret > 2) { res = pcre_get_substring((char *)isdataatstr, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } args[1] = (char *)str_ptr; } if (ret > 3) { res = pcre_get_substring((char *)isdataatstr, ov, MAX_SUBSTRINGS, 3, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } args[2] = (char *)str_ptr; } idad = SCMalloc(sizeof(DetectIsdataatData)); if (unlikely(idad == NULL)) goto error; idad->flags = 0; idad->dataat = 0; if (args[0][0] != '-' && isalpha((unsigned char)args[0][0])) { if (offset == NULL) { SCLogError(SC_ERR_INVALID_ARGUMENT, "isdataat supplied with " "var name for offset. \"offset\" argument supplied to " "this function has to be non-NULL"); goto error; } *offset = SCStrdup(args[0]); if (*offset == NULL) goto error; } else { if (ByteExtractStringUint16(&idad->dataat, 10, strlen(args[0]), args[0]) < 0 ) { SCLogError(SC_ERR_INVALID_VALUE, "isdataat out of range"); SCFree(idad); idad = NULL; goto error; } } if (args[1] !=NULL) { idad->flags |= ISDATAAT_RELATIVE; if(args[2] !=NULL) idad->flags |= ISDATAAT_RAWBYTES; } if (isdataatstr[0] == '!') { idad->flags |= ISDATAAT_NEGATED; } for (i = 0; i < (ret -1); i++) { if (args[i] != NULL) SCFree(args[i]); } return idad; } error: for (i = 0; i < (ret -1) && i < 3; i++){ if (args[i] != NULL) SCFree(args[i]); } if (idad != NULL) DetectIsdataatFree(idad); return NULL; }
DetectUrilenData *DetectUrilenParse (char *urilenstr) { DetectUrilenData *urilend = NULL; char *arg1 = NULL; char *arg2 = NULL; char *arg3 = NULL; char *arg4 = NULL; char *arg5 = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; ret = pcre_exec(parse_regex, parse_regex_study, urilenstr, strlen(urilenstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 3 || ret > 6) { SCLogError(SC_ERR_PCRE_PARSE, "urilen option pcre parse error: \"%s\"", urilenstr); goto error; } const char *str_ptr; SCLogDebug("ret %d", ret); res = pcre_get_substring((char *)urilenstr, ov, MAX_SUBSTRINGS, 1, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } arg1 = (char *) str_ptr; SCLogDebug("Arg1 \"%s\"", arg1); res = pcre_get_substring((char *)urilenstr, ov, MAX_SUBSTRINGS, 2, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } arg2 = (char *) str_ptr; SCLogDebug("Arg2 \"%s\"", arg2); if (ret > 3) { res = pcre_get_substring((char *)urilenstr, ov, MAX_SUBSTRINGS, 3, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } arg3 = (char *) str_ptr; SCLogDebug("Arg3 \"%s\"", arg3); if (ret > 4) { res = pcre_get_substring((char *)urilenstr, ov, MAX_SUBSTRINGS, 4, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } arg4 = (char *) str_ptr; SCLogDebug("Arg4 \"%s\"", arg4); } if (ret > 5) { res = pcre_get_substring((char *)urilenstr, ov, MAX_SUBSTRINGS, 5, &str_ptr); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed"); goto error; } arg5 = (char *) str_ptr; SCLogDebug("Arg5 \"%s\"", arg5); } } urilend = SCMalloc(sizeof (DetectUrilenData)); if (unlikely(urilend == NULL)) goto error; memset(urilend, 0, sizeof(DetectUrilenData)); if (arg1[0] == '<') urilend->mode = DETECT_URILEN_LT; else if (arg1[0] == '>') urilend->mode = DETECT_URILEN_GT; else urilend->mode = DETECT_URILEN_EQ; if (arg3 != NULL && strcmp("<>", arg3) == 0) { if (strlen(arg1) != 0) { SCLogError(SC_ERR_INVALID_ARGUMENT,"Range specified but mode also set"); goto error; } urilend->mode = DETECT_URILEN_RA; } /** set the first urilen value */ if (ByteExtractStringUint16(&urilend->urilen1,10,strlen(arg2),arg2) <= 0){ SCLogError(SC_ERR_INVALID_ARGUMENT,"Invalid size :\"%s\"",arg2); goto error; } /** set the second urilen value if specified */ if (arg4 != NULL && strlen(arg4) > 0) { if (urilend->mode != DETECT_URILEN_RA) { SCLogError(SC_ERR_INVALID_ARGUMENT,"Multiple urilen values specified" " but mode is not range"); goto error; } if(ByteExtractStringUint16(&urilend->urilen2,10,strlen(arg4),arg4) <= 0) { SCLogError(SC_ERR_INVALID_ARGUMENT,"Invalid size :\"%s\"",arg4); goto error; } if (urilend->urilen2 <= urilend->urilen1){ SCLogError(SC_ERR_INVALID_ARGUMENT,"urilen2:%"PRIu16" <= urilen:" "%"PRIu16"",urilend->urilen2,urilend->urilen1); goto error; } } if (arg5 != NULL) { if (strcasecmp("raw", arg5) == 0) { urilend->raw_buffer = 1; } } pcre_free_substring(arg1); pcre_free_substring(arg2); if (arg3 != NULL) pcre_free_substring(arg3); if (arg4 != NULL) pcre_free_substring(arg4); if (arg5 != NULL) pcre_free_substring(arg5); return urilend; error: if (urilend) SCFree(urilend); if (arg1 != NULL) SCFree(arg1); if (arg2 != NULL) SCFree(arg2); if (arg3 != NULL) SCFree(arg3); if (arg4 != NULL) SCFree(arg4); return NULL; }
/** * \internal * \brief This function is used to parse dsize options passed via dsize: keyword * * \param rawstr Pointer to the user provided dsize options * * \retval dd pointer to DetectDsizeData on success * \retval NULL on failure */ DetectDsizeData *DetectDsizeParse (char *rawstr) { DetectDsizeData *dd = NULL; #define MAX_SUBSTRINGS 30 int ret = 0, res = 0; int ov[MAX_SUBSTRINGS]; char mode[2] = ""; char value1[6] = ""; char value2[6] = ""; char range[3] = ""; ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS); if (ret < 3 || ret > 5) { SCLogError(SC_ERR_PCRE_MATCH,"Parse error %s", rawstr); goto error; } res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, mode, sizeof(mode)); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING,"pcre_copy_substring failed"); goto error; } SCLogDebug("mode \"%s\"", mode); res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, value1, sizeof(value1)); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING,"pcre_copy_substring failed"); goto error; } SCLogDebug("value1 \"%s\"", value1); if (ret > 3) { res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 3, range, sizeof(range)); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING,"pcre_copy_substring failed"); goto error; } SCLogDebug("range \"%s\"", range); if (ret > 4) { res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 4, value2, sizeof(value2)); if (res < 0) { SCLogError(SC_ERR_PCRE_GET_SUBSTRING,"pcre_copy_substring failed"); goto error; } SCLogDebug("value2 \"%s\"", value2); } } dd = SCMalloc(sizeof(DetectDsizeData)); if (unlikely(dd == NULL)) goto error; dd->dsize = 0; dd->dsize2 = 0; dd->mode = DETECTDSIZE_EQ; // default if (strlen(mode) > 0) { if (mode[0] == '<') dd->mode = DETECTDSIZE_LT; else if (mode[0] == '>') dd->mode = DETECTDSIZE_GT; else dd->mode = DETECTDSIZE_EQ; } if (strcmp("<>", range) == 0) { if (strlen(mode) != 0) { SCLogError(SC_ERR_INVALID_ARGUMENT,"Range specified but mode also set"); goto error; } dd->mode = DETECTDSIZE_RA; } /** set the first dsize value */ if (ByteExtractStringUint16(&dd->dsize,10,strlen(value1),value1) <= 0) { SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid size value1:\"%s\"", value1); goto error; } /** set the second dsize value if specified */ if (strlen(value2) > 0) { if (dd->mode != DETECTDSIZE_RA) { SCLogError(SC_ERR_INVALID_ARGUMENT,"Multiple dsize values specified but mode is not range"); goto error; } if (ByteExtractStringUint16(&dd->dsize2,10,strlen(value2),value2) <= 0) { SCLogError(SC_ERR_INVALID_ARGUMENT,"Invalid size value2:\"%s\"",value2); goto error; } if (dd->dsize2 <= dd->dsize) { SCLogError(SC_ERR_INVALID_ARGUMENT,"dsize2:%"PRIu16" <= dsize:%"PRIu16"",dd->dsize2,dd->dsize); goto error; } } SCLogDebug("dsize parsed successfully dsize: %"PRIu16" dsize2: %"PRIu16"",dd->dsize,dd->dsize2); return dd; error: if (dd) SCFree(dd); return NULL; }
/** * \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; }