Exemple #1
0
/**
 * \internal
 * \brief this function is used to add the seq option into the signature
 *
 * \param de_ctx pointer to the Detection Engine Context
 * \param s pointer to the Current Signature
 * \param optstr pointer to the user provided options
 *
 * \retval 0 on Success
 * \retval -1 on Failure
 */
static int DetectSeqSetup (DetectEngineCtx *de_ctx, Signature *s, char *optstr)
{
    DetectSeqData *data;
    SigMatch *sm = NULL;

    data = SCMalloc(sizeof(DetectSeqData));
    if (data == NULL)
        goto error;

    sm = SigMatchAlloc();
    if (sm == NULL) {
        goto error;
    }

    sm->type = DETECT_SEQ;

    if (-1 == ByteExtractStringUint32(&data->seq, 10, 0, optstr)) {
        goto error;
    }
    sm->ctx = data;

    SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH);
    s->flags |= SIG_FLAG_REQUIRE_PACKET;

    return 0;

error:
    if (data) SCFree(data);
    return -1;

}
/** \brief Create a new LogFileCtx for unified alert logging.
 *  \param conf The ConfNode for this output.
 *  \return NULL if failure, LogFileCtx* to the file_ctx if succesful
 * */
OutputCtx *AlertUnifiedAlertInitCtx(ConfNode *conf)
{
    int ret = 0;
    LogFileCtx *file_ctx = NULL;

    file_ctx = LogFileNewCtx();
    if (file_ctx == NULL) {
        SCLogError(SC_ERR_UNIFIED_ALERT_GENERIC, "Couldn't create new file_ctx");
        goto error;
    }

    const char *filename = NULL;
    if (conf != NULL)
        filename = ConfNodeLookupChildValue(conf, "filename");
    if (filename == NULL)
        filename = DEFAULT_LOG_FILENAME;
    file_ctx->prefix = SCStrdup(filename);

    const char *s_limit = NULL;
    uint32_t limit = DEFAULT_LIMIT;
    if (conf != NULL) {
        s_limit = ConfNodeLookupChildValue(conf, "limit");
        if (s_limit != NULL) {
            if (ByteExtractStringUint32(&limit, 10, 0, s_limit) == -1) {
                SCLogError(SC_ERR_INVALID_ARGUMENT,
                    "Fail to initialize unified alert output, invalid limit: %s",
                    s_limit);
                exit(EXIT_FAILURE);
            }
            if (limit < MIN_LIMIT) {
                SCLogError(SC_ERR_INVALID_ARGUMENT,
                    "Fail to initialize unified alert output, limit less than "
                    "allowed minimum: %d.", MIN_LIMIT);
                exit(EXIT_FAILURE);
            }
        }
    }
    file_ctx->size_limit = limit * 1024 * 1024;

    ret = AlertUnifiedAlertOpenFileCtx(file_ctx, filename);
    if (ret < 0)
        goto error;

    OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx));
    if (output_ctx == NULL)
        goto error;
    output_ctx->data = file_ctx;
    output_ctx->DeInit = AlertUnifiedAlertDeInitCtx;

    SCLogInfo("Unified-alert initialized: filename %s, limit %"PRIu32" MB",
       filename, limit);

    return output_ctx;

error:
    if (file_ctx != NULL) {
        LogFileFreeCtx(file_ctx);
    }
    return NULL;
}
Exemple #3
0
/** \test max u32 value + 1 */
static int ByteTest16 (void) {
    const char *str = "4294967296";
    uint32_t u32 = 0;

    int ret = ByteExtractStringUint32(&u32, 10, strlen(str), str);
    if (ret != 0) {
        return 1;
    }

    return 0;
}
Exemple #4
0
static int ByteTest08 (void) {
    const char *str = "1234567890";
    uint32_t val = 1234567890;
    uint32_t i32 = 0xbfbfbfbf;
    int ret = ByteExtractStringUint32(&i32, 10, strlen(str), str);

    if ((ret == 10) && (i32 == val)) {
        return 1;
    }

    return 0;
}
Exemple #5
0
/** \test max u32 value */
static int ByteTest15 (void) {
    const char *str = "4294967295";
    uint32_t val = 4294967295UL;
    uint32_t u32 = 0xffffffff;

    int ret = ByteExtractStringUint32(&u32, 10, strlen(str), str);
    if ((ret == 10) && (u32 == val)) {
        return 1;
    }

    return 0;
}
Exemple #6
0
/**
 * \internal
 * \brief This function is used to parse threshold options passed via threshold: keyword
 *
 * \param rawstr Pointer to the user provided threshold options
 *
 * \retval de pointer to DetectThresholdData on success
 * \retval NULL on failure
 */
static DetectThresholdData *DetectThresholdParse (char *rawstr)
{
    DetectThresholdData *de = NULL;
#define MAX_SUBSTRINGS 30
    int ret = 0, res = 0;
    int ov[MAX_SUBSTRINGS];
    const char *str_ptr = NULL;
    char *args[9] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
    char *copy_str = NULL, *threshold_opt = NULL;
    int second_found = 0, count_found = 0;
    int type_found = 0, track_found = 0;
    int second_pos = 0, count_pos = 0;
    uint16_t pos = 0;
    int i = 0;

    copy_str = SCStrdup(rawstr);

    for(pos = 0, threshold_opt = strtok(copy_str,",");  pos < strlen(copy_str) &&  threshold_opt != NULL;  pos++, threshold_opt = strtok(NULL,",")) {

        if(strstr(threshold_opt,"count"))
            count_found++;
        if(strstr(threshold_opt,"second"))
            second_found++;
        if(strstr(threshold_opt,"type"))
            type_found++;
        if(strstr(threshold_opt,"track"))
            track_found++;
    }

    if(copy_str)
        SCFree(copy_str);

    if(count_found != 1 || second_found != 1 || type_found != 1 || track_found != 1)
        goto error;

    ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS);

    if (ret < 5) {
        SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, rawstr);
        goto error;
    }

    de = SCMalloc(sizeof(DetectThresholdData));
    if (de == NULL)
        goto error;

    memset(de,0,sizeof(DetectThresholdData));

    for (i = 0; i < (ret - 1); i++) {

        res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS,i + 1, &str_ptr);

        if (res < 0) {
            SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
            goto error;
        }

        args[i] = (char *)str_ptr;

        if (strncasecmp(args[i],"limit",strlen("limit")) == 0)
            de->type = TYPE_LIMIT;
        if (strncasecmp(args[i],"both",strlen("both")) == 0)
            de->type = TYPE_BOTH;
        if (strncasecmp(args[i],"threshold",strlen("threshold")) == 0)
            de->type = TYPE_THRESHOLD;
        if (strncasecmp(args[i],"by_dst",strlen("by_dst")) == 0)
            de->track = TRACK_DST;
        if (strncasecmp(args[i],"by_src",strlen("by_src")) == 0)
            de->track = TRACK_SRC;
        if (strncasecmp(args[i],"count",strlen("seconds")) == 0)
            count_pos = i+1;
        if (strncasecmp(args[i],"seconds",strlen("seconds")) == 0)
            second_pos = i+1;
    }

    if (args[count_pos] == NULL || args[second_pos] == NULL) {
        goto error;
    }

    if (ByteExtractStringUint32(&de->count, 10, strlen(args[count_pos]),
                args[count_pos]) <= 0) {
        goto error;
    }

    if (ByteExtractStringUint32(&de->seconds, 10, strlen(args[second_pos]),
                args[second_pos]) <= 0) {
        goto error;
    }

    for (i = 0; i < (ret - 1); i++){
        if (args[i] != NULL) SCFree(args[i]);
    }
    return de;

error:
    for (i = 0; i < (ret - 1); i++){
        if (args[i] != NULL) SCFree(args[i]);
    }
    if (de) SCFree(de);
    return NULL;
}
Exemple #7
0
/** \brief initialize the configuration
 *  \warning Not thread safe */
void HostInitConfig(char quiet)
{
    SCLogDebug("initializing host engine...");

    memset(&host_config,  0, sizeof(host_config));
    //SC_ATOMIC_INIT(flow_flags);
    SC_ATOMIC_INIT(host_counter);
    SC_ATOMIC_INIT(host_memuse);
    SC_ATOMIC_INIT(host_prune_idx);
    HostQueueInit(&host_spare_q);

    unsigned int seed = RandomTimePreseed();
    /* set defaults */
    host_config.hash_rand   = (int)( HOST_DEFAULT_HASHSIZE * (rand_r(&seed) / RAND_MAX + 1.0));

    host_config.hash_size   = HOST_DEFAULT_HASHSIZE;
    host_config.memcap      = HOST_DEFAULT_MEMCAP;
    host_config.prealloc    = HOST_DEFAULT_PREALLOC;

    /* Check if we have memcap and hash_size defined at config */
    char *conf_val;
    uint32_t configval = 0;

    /** set config values for memcap, prealloc and hash_size */
    if ((ConfGet("host.memcap", &conf_val)) == 1)
    {
        if (ParseSizeStringU64(conf_val, &host_config.memcap) < 0) {
            SCLogError(SC_ERR_SIZE_PARSE, "Error parsing host.memcap "
                       "from conf file - %s.  Killing engine",
                       conf_val);
            exit(EXIT_FAILURE);
        }
    }
    if ((ConfGet("host.hash-size", &conf_val)) == 1)
    {
        if (ByteExtractStringUint32(&configval, 10, strlen(conf_val),
                                    conf_val) > 0) {
            host_config.hash_size = configval;
        }
    }

    if ((ConfGet("host.prealloc", &conf_val)) == 1)
    {
        if (ByteExtractStringUint32(&configval, 10, strlen(conf_val),
                                    conf_val) > 0) {
            host_config.prealloc = configval;
        }
    }
    SCLogDebug("Host config from suricata.yaml: memcap: %"PRIu64", hash-size: "
               "%"PRIu32", prealloc: %"PRIu32, host_config.memcap,
               host_config.hash_size, host_config.prealloc);

    /* alloc hash memory */
    uint64_t hash_size = host_config.hash_size * sizeof(HostHashRow);
    if (!(HOST_CHECK_MEMCAP(hash_size))) {
        SCLogError(SC_ERR_HOST_INIT, "allocating host hash failed: "
                "max host memcap is smaller than projected hash size. "
                "Memcap: %"PRIu64", Hash table size %"PRIu64". Calculate "
                "total hash size by multiplying \"host.hash-size\" with %"PRIuMAX", "
                "which is the hash bucket size.", host_config.memcap, hash_size,
                (uintmax_t)sizeof(HostHashRow));
        exit(EXIT_FAILURE);
    }
    host_hash = SCCalloc(host_config.hash_size, sizeof(HostHashRow));
    if (unlikely(host_hash == NULL)) {
        SCLogError(SC_ERR_FATAL, "Fatal error encountered in HostInitConfig. Exiting...");
        exit(EXIT_FAILURE);
    }
    memset(host_hash, 0, host_config.hash_size * sizeof(HostHashRow));

    uint32_t i = 0;
    for (i = 0; i < host_config.hash_size; i++) {
        HRLOCK_INIT(&host_hash[i]);
    }
    (void) SC_ATOMIC_ADD(host_memuse, (host_config.hash_size * sizeof(HostHashRow)));

    if (quiet == FALSE) {
        SCLogInfo("allocated %llu bytes of memory for the host hash... "
                  "%" PRIu32 " buckets of size %" PRIuMAX "",
                  SC_ATOMIC_GET(host_memuse), host_config.hash_size,
                  (uintmax_t)sizeof(HostHashRow));
    }

    /* pre allocate hosts */
    for (i = 0; i < host_config.prealloc; i++) {
        if (!(HOST_CHECK_MEMCAP(sizeof(Host)))) {
            SCLogError(SC_ERR_HOST_INIT, "preallocating hosts failed: "
                    "max host memcap reached. Memcap %"PRIu64", "
                    "Memuse %"PRIu64".", host_config.memcap,
                    ((uint64_t)SC_ATOMIC_GET(host_memuse) + (uint64_t)sizeof(Host)));
            exit(EXIT_FAILURE);
        }

        Host *h = HostAlloc();
        if (h == NULL) {
            SCLogError(SC_ERR_HOST_INIT, "preallocating host failed: %s", strerror(errno));
            exit(EXIT_FAILURE);
        }
        HostEnqueue(&host_spare_q,h);
    }

    if (quiet == FALSE) {
        SCLogInfo("preallocated %" PRIu32 " hosts of size %" PRIuMAX "",
                host_spare_q.len, (uintmax_t)sizeof(Host));
        SCLogInfo("host memory usage: %llu bytes, maximum: %"PRIu64,
                SC_ATOMIC_GET(host_memuse), host_config.memcap);
    }

    return;
}
Exemple #8
0
/** \brief initialize the configuration
 *  \warning Not thread safe */
void DefragInitConfig(char quiet)
{
    SCLogDebug("initializing defrag engine...");

    memset(&defrag_config,  0, sizeof(defrag_config));
    //SC_ATOMIC_INIT(flow_flags);
    SC_ATOMIC_INIT(defragtracker_counter);
    SC_ATOMIC_INIT(defrag_memuse);
    SC_ATOMIC_INIT(defragtracker_prune_idx);
    DefragTrackerQueueInit(&defragtracker_spare_q);

    /* set defaults */
    defrag_config.hash_rand   = (uint32_t)RandomGet();
    defrag_config.hash_size   = DEFRAG_DEFAULT_HASHSIZE;
    defrag_config.memcap      = DEFRAG_DEFAULT_MEMCAP;
    defrag_config.prealloc    = DEFRAG_DEFAULT_PREALLOC;

    /* Check if we have memcap and hash_size defined at config */
    const char *conf_val;
    uint32_t configval = 0;

    /** set config values for memcap, prealloc and hash_size */
    if ((ConfGet("defrag.memcap", &conf_val)) == 1)
    {
        if (ParseSizeStringU64(conf_val, &defrag_config.memcap) < 0) {
            SCLogError(SC_ERR_SIZE_PARSE, "Error parsing defrag.memcap "
                       "from conf file - %s.  Killing engine",
                       conf_val);
            exit(EXIT_FAILURE);
        }
    }
    if ((ConfGet("defrag.hash-size", &conf_val)) == 1)
    {
        if (ByteExtractStringUint32(&configval, 10, strlen(conf_val),
                                    conf_val) > 0) {
            defrag_config.hash_size = configval;
        } else {
            WarnInvalidConfEntry("defrag.hash-size", "%"PRIu32, defrag_config.hash_size);
        }
    }


    if ((ConfGet("defrag.trackers", &conf_val)) == 1)
    {
        if (ByteExtractStringUint32(&configval, 10, strlen(conf_val),
                                    conf_val) > 0) {
            defrag_config.prealloc = configval;
        } else {
            WarnInvalidConfEntry("defrag.trackers", "%"PRIu32, defrag_config.prealloc);
        }
    }
    SCLogDebug("DefragTracker config from suricata.yaml: memcap: %"PRIu64", hash-size: "
               "%"PRIu32", prealloc: %"PRIu32, defrag_config.memcap,
               defrag_config.hash_size, defrag_config.prealloc);

    /* alloc hash memory */
    uint64_t hash_size = defrag_config.hash_size * sizeof(DefragTrackerHashRow);
    if (!(DEFRAG_CHECK_MEMCAP(hash_size))) {
        SCLogError(SC_ERR_DEFRAG_INIT, "allocating defrag hash failed: "
                "max defrag memcap is smaller than projected hash size. "
                "Memcap: %"PRIu64", Hash table size %"PRIu64". Calculate "
                "total hash size by multiplying \"defrag.hash-size\" with %"PRIuMAX", "
                "which is the hash bucket size.", defrag_config.memcap, hash_size,
                (uintmax_t)sizeof(DefragTrackerHashRow));
        exit(EXIT_FAILURE);
    }
    defragtracker_hash = SCCalloc(defrag_config.hash_size, sizeof(DefragTrackerHashRow));
    if (unlikely(defragtracker_hash == NULL)) {
        SCLogError(SC_ERR_FATAL, "Fatal error encountered in DefragTrackerInitConfig. Exiting...");
        exit(EXIT_FAILURE);
    }
    memset(defragtracker_hash, 0, defrag_config.hash_size * sizeof(DefragTrackerHashRow));

    uint32_t i = 0;
    for (i = 0; i < defrag_config.hash_size; i++) {
        DRLOCK_INIT(&defragtracker_hash[i]);
    }
    (void) SC_ATOMIC_ADD(defrag_memuse, (defrag_config.hash_size * sizeof(DefragTrackerHashRow)));

    if (quiet == FALSE) {
        SCLogConfig("allocated %"PRIu64" bytes of memory for the defrag hash... "
                  "%" PRIu32 " buckets of size %" PRIuMAX "",
                  SC_ATOMIC_GET(defrag_memuse), defrag_config.hash_size,
                  (uintmax_t)sizeof(DefragTrackerHashRow));
    }

    if ((ConfGet("defrag.prealloc", &conf_val)) == 1)
    {
        if (ConfValIsTrue(conf_val)) {
            /* pre allocate defrag trackers */
            for (i = 0; i < defrag_config.prealloc; i++) {
                if (!(DEFRAG_CHECK_MEMCAP(sizeof(DefragTracker)))) {
                    SCLogError(SC_ERR_DEFRAG_INIT, "preallocating defrag trackers failed: "
                            "max defrag memcap reached. Memcap %"PRIu64", "
                            "Memuse %"PRIu64".", defrag_config.memcap,
                            ((uint64_t)SC_ATOMIC_GET(defrag_memuse) + (uint64_t)sizeof(DefragTracker)));
                    exit(EXIT_FAILURE);
                }

                DefragTracker *h = DefragTrackerAlloc();
                if (h == NULL) {
                    SCLogError(SC_ERR_DEFRAG_INIT, "preallocating defrag failed: %s", strerror(errno));
                    exit(EXIT_FAILURE);
                }
                DefragTrackerEnqueue(&defragtracker_spare_q,h);
            }
            if (quiet == FALSE) {
                SCLogConfig("preallocated %" PRIu32 " defrag trackers of size %" PRIuMAX "",
                        defragtracker_spare_q.len, (uintmax_t)sizeof(DefragTracker));
            }
        }
    }

    if (quiet == FALSE) {
        SCLogConfig("defrag memory usage: %"PRIu64" bytes, maximum: %"PRIu64,
                SC_ATOMIC_GET(defrag_memuse), defrag_config.memcap);
    }

    return;
}
void SCProfilingRulesGlobalInit(void) {
    ConfNode *conf;
    const char *val;

    conf = ConfGetNode("profiling.rules");
    if (conf != NULL) {
        if (ConfNodeChildValueIsTrue(conf, "enabled")) {
            profiling_rules_enabled = 1;

            val = ConfNodeLookupChildValue(conf, "sort");
            if (val != NULL) {
                if (strcmp(val, "ticks") == 0) {
                    profiling_rules_sort_order =
                        SC_PROFILING_RULES_SORT_BY_TICKS;
                }
                else if (strcmp(val, "avgticks") == 0) {
                    profiling_rules_sort_order =
                        SC_PROFILING_RULES_SORT_BY_AVG_TICKS;
                }
                else if (strcmp(val, "avgticks_match") == 0) {
                    profiling_rules_sort_order =
                        SC_PROFILING_RULES_SORT_BY_AVG_TICKS_MATCH;
                }
                else if (strcmp(val, "avgticks_no_match") == 0) {
                    profiling_rules_sort_order =
                        SC_PROFILING_RULES_SORT_BY_AVG_TICKS_NO_MATCH;
                }
                else if (strcmp(val, "checks") == 0) {
                    profiling_rules_sort_order =
                        SC_PROFILING_RULES_SORT_BY_CHECKS;
                }
                else if (strcmp(val, "matches") == 0) {
                    profiling_rules_sort_order =
                        SC_PROFILING_RULES_SORT_BY_MATCHES;
                }
                else if (strcmp(val, "maxticks") == 0) {
                    profiling_rules_sort_order =
                        SC_PROFILING_RULES_SORT_BY_MAX_TICKS;
                }
                else {
                    SCLogError(SC_ERR_INVALID_ARGUMENT,
                            "Invalid profiling sort order: %s", val);
                    exit(EXIT_FAILURE);
                }
            }

            val = ConfNodeLookupChildValue(conf, "limit");
            if (val != NULL) {
                if (ByteExtractStringUint32(&profiling_rules_limit, 10,
                            (uint16_t)strlen(val), val) <= 0) {
                    SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid limit: %s", val);
                    exit(EXIT_FAILURE);
                }
            }
            const char *filename = ConfNodeLookupChildValue(conf, "filename");
            if (filename != NULL) {

                char *log_dir;
                log_dir = ConfigGetLogDirectory();

                profiling_file_name = SCMalloc(PATH_MAX);
                if (unlikely(profiling_file_name == NULL)) {
                    SCLogError(SC_ERR_MEM_ALLOC, "can't duplicate file name");
                    exit(EXIT_FAILURE);
                }
                snprintf(profiling_file_name, PATH_MAX, "%s/%s", log_dir, filename);

                const char *v = ConfNodeLookupChildValue(conf, "append");
                if (v == NULL || ConfValIsTrue(v)) {
                    profiling_file_mode = "a";
                } else {
                    profiling_file_mode = "w";
                }

                profiling_output_to_file = 1;
            }
        }
    }
}
Exemple #10
0
DetectBytejumpData *DetectBytejumpParse(char *optstr, char **offset)
{
    DetectBytejumpData *data = NULL;
    char *args[10] = {
        NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
        NULL, NULL
    };
#define MAX_SUBSTRINGS 30
    int ret = 0, res = 0;
    int ov[MAX_SUBSTRINGS];
    int numargs = 0;
    int i = 0;
    uint32_t nbytes;
    char *str_ptr;
    char *end_ptr;

    /* Execute the regex and populate args with captures. */
    ret = pcre_exec(parse_regex, parse_regex_study, optstr,
                    strlen(optstr), 0, 0, ov, MAX_SUBSTRINGS);
    if (ret < 2 || ret > 10) {
        SCLogError(SC_ERR_PCRE_PARSE,"parse error, ret %" PRId32
               ", string \"%s\"", ret, optstr);
        goto error;
    }

    /* The first two arguments are stashed in the first PCRE substring.
     * This is because byte_jump can take 10 arguments, but PCRE only
     * supports 9 substrings, sigh.
     */
    res = pcre_get_substring((char *)optstr, ov,
                             MAX_SUBSTRINGS, 1, (const char **)&str_ptr);
    if (res < 0) {
        SCLogError(SC_ERR_PCRE_GET_SUBSTRING,"pcre_get_substring failed "
               "for arg 1");
        goto error;
    }

    /* Break up first substring into two parameters
     *
     * NOTE: Because of this, we cannot free args[1] as it is part of args[0],
     * and *yes* this *is* ugly.
     */
    end_ptr = str_ptr;
    while (!(isspace((unsigned char)*end_ptr) || (*end_ptr == ','))) end_ptr++;
    *(end_ptr++) = '\0';
    args[0] = str_ptr;
    numargs++;

    str_ptr = end_ptr;
    while (isspace((unsigned char)*str_ptr) || (*str_ptr == ',')) str_ptr++;
    end_ptr = str_ptr;
    while (!(isspace((unsigned char)*end_ptr) || (*end_ptr == ',')) && (*end_ptr != '\0'))
        end_ptr++;
    *(end_ptr++) = '\0';
    args[1] = str_ptr;
    numargs++;

    /* The remaining args are directly from PCRE substrings */
    for (i = 1; i < (ret - 1); i++) {
        res = pcre_get_substring((char *)optstr, ov, MAX_SUBSTRINGS, i + 1, (const char **)&str_ptr);
        if (res < 0) {
            SCLogError(SC_ERR_PCRE_GET_SUBSTRING,"pcre_get_substring failed for arg %d", i + 1);
            goto error;
        }
        args[i+1] = str_ptr;
        numargs++;
    }

    /* Initialize the data */
    data = SCMalloc(sizeof(DetectBytejumpData));
    if (unlikely(data == NULL))
        goto error;
    data->base = DETECT_BYTEJUMP_BASE_UNSET;
    data->flags = 0;
    data->multiplier = 1;
    data->post_offset = 0;

    /*
     * The first two options are required and positional.  The
     * remaining arguments are flags and are not positional.
     */

    /* Number of bytes */
    if (ByteExtractStringUint32(&nbytes, 10, strlen(args[0]), args[0]) <= 0) {
        SCLogError(SC_ERR_INVALID_VALUE, "Malformed number of bytes: %s", optstr);
        goto error;
    }

    /* Offset */
    if (args[1][0] != '-' && isalpha((unsigned char)args[1][0])) {
        if (offset == NULL) {
            SCLogError(SC_ERR_INVALID_ARGUMENT, "byte_jump supplied with "
                       "var name for offset.  \"value\" argument supplied to "
                       "this function has to be non-NULL");
            goto error;
        }
        *offset = SCStrdup(args[1]);
        if (*offset == NULL)
            goto error;
    } else {
        if (ByteExtractStringInt32(&data->offset, 0, strlen(args[1]), args[1]) <= 0) {
            SCLogError(SC_ERR_INVALID_VALUE, "Malformed offset: %s", optstr);
            goto error;
        }
    }

    /* The remaining options are flags. */
    /** \todo Error on dups? */
    for (i = 2; i < numargs; i++) {
        if (strcmp("relative", args[i]) == 0) {
            data->flags |= DETECT_BYTEJUMP_RELATIVE;
        } else if (strcasecmp("string", args[i]) == 0) {
            data->flags |= DETECT_BYTEJUMP_STRING;
        } else if (strcasecmp("dec", args[i]) == 0) {
            data->base |= DETECT_BYTEJUMP_BASE_DEC;
        } else if (strcasecmp("hex", args[i]) == 0) {
            data->base |= DETECT_BYTEJUMP_BASE_HEX;
        } else if (strcasecmp("oct", args[i]) == 0) {
            data->base |= DETECT_BYTEJUMP_BASE_OCT;
        } else if (strcasecmp("big", args[i]) == 0) {
            if (data->flags & DETECT_BYTEJUMP_LITTLE) {
                data->flags ^= DETECT_BYTEJUMP_LITTLE;
            }
            data->flags |= DETECT_BYTEJUMP_BIG;
        } else if (strcasecmp("little", args[i]) == 0) {
            data->flags |= DETECT_BYTEJUMP_LITTLE;
        } else if (strcasecmp("from_beginning", args[i]) == 0) {
            data->flags |= DETECT_BYTEJUMP_BEGIN;
        } else if (strcasecmp("align", args[i]) == 0) {
            data->flags |= DETECT_BYTEJUMP_ALIGN;
        } else if (strncasecmp("multiplier ", args[i], 11) == 0) {
            if (ByteExtractStringUint32(&data->multiplier, 10,
                                        strlen(args[i]) - 11,
                                        args[i] + 11) <= 0)
            {
                SCLogError(SC_ERR_INVALID_VALUE, "Malformed multiplier: %s", optstr);
                goto error;
            }
        } else if (strncasecmp("post_offset ", args[i], 12) == 0) {
            if (ByteExtractStringInt32(&data->post_offset, 10,
                                       strlen(args[i]) - 12,
                                       args[i] + 12) <= 0)
            {
                SCLogError(SC_ERR_INVALID_VALUE, "Malformed post_offset: %s", optstr);
                goto error;
            }
        } else if (strcasecmp("dce", args[i]) == 0) {
            data->flags |= DETECT_BYTEJUMP_DCE;
        } else {
            SCLogError(SC_ERR_INVALID_VALUE, "Unknown option: \"%s\"", args[i]);
            goto error;
        }
    }

    if (data->flags & DETECT_BYTEJUMP_STRING) {
        /* 23 - This is the largest string (octal, with a zero prefix) that
         *      will not overflow uint64_t.  The only way this length
         *      could be over 23 and still not overflow is if it were zero
         *      prefixed and we only support 1 byte of zero prefix for octal.
         *
         * "01777777777777777777777" = 0xffffffffffffffff
         */
        if (nbytes > 23) {
            SCLogError(SC_ERR_INVALID_VALUE, "Cannot test more than 23 bytes "
                   "with \"string\": %s", optstr);
            goto error;
        }
    } else {
        if (nbytes > 8) {
            SCLogError(SC_ERR_INVALID_VALUE, "Cannot test more than 8 bytes "
                   "without \"string\": %s\n", optstr);
            goto error;
        }
        if (data->base != DETECT_BYTEJUMP_BASE_UNSET) {
            SCLogError(SC_ERR_INVALID_VALUE, "Cannot use a base "
                   "without \"string\": %s", optstr);
            goto error;
        }
    }

    /* This is max 23 so it will fit in a byte (see above) */
    data->nbytes = (uint8_t)nbytes;

    for (i = 0; i < numargs; i++){
        if (i == 1) continue; /* args[1] is part of args[0] */
        if (args[i] != NULL) SCFree(args[i]);
    }
    return data;

error:
    for (i = 0; i < numargs; i++){
        if (i == 1) continue; /* args[1] is part of args[0] */
        if (args[i] != NULL) SCFree(args[i]);
    }
    if (data != NULL) DetectBytejumpFree(data);
    return NULL;
}
Exemple #11
0
/**
 * \brief This function is used to parse rpc options passed via rpc keyword
 *
 * \param rpcstr Pointer to the user provided rpc options
 *
 * \retval rd pointer to DetectRpcData on success
 * \retval NULL on failure
 */
static DetectRpcData *DetectRpcParse (const char *rpcstr)
{
    DetectRpcData *rd = NULL;
    char *args[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, rpcstr, strlen(rpcstr), 0, 0, ov, MAX_SUBSTRINGS);
    if (ret < 1 || ret > 4) {
        SCLogError(SC_ERR_PCRE_MATCH, "parse error, ret %" PRId32 ", string %s", ret, rpcstr);
        goto error;
    }

    if (ret > 1) {
        const char *str_ptr;
        res = pcre_get_substring((char *)rpcstr, 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 *)rpcstr, 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 *)rpcstr, 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;
        }
    }

    rd = SCMalloc(sizeof(DetectRpcData));
    if (unlikely(rd == NULL))
        goto error;
    rd->flags = 0;
    rd->program = 0;
    rd->program_version = 0;
    rd->procedure = 0;

    int i;
    for (i = 0; i < (ret - 1); i++) {
        if (args[i]) {
            switch (i) {
                case 0:
                    if (ByteExtractStringUint32(&rd->program, 10, strlen(args[i]), args[i]) <= 0) {
                        SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid size specified for the rpc program:\"%s\"", args[i]);
                        goto error;
                    }
                    rd->flags |= DETECT_RPC_CHECK_PROGRAM;
                    break;
                case 1:
                    if (args[i][0] != '*') {
                        if (ByteExtractStringUint32(&rd->program_version, 10, strlen(args[i]), args[i]) <= 0) {
                            SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid size specified for the rpc version:\"%s\"", args[i]);
                            goto error;
                        }
                        rd->flags |= DETECT_RPC_CHECK_VERSION;
                    }
                    break;
                case 2:
                    if (args[i][0] != '*') {
                        if (ByteExtractStringUint32(&rd->procedure, 10, strlen(args[i]), args[i]) <= 0) {
                            SCLogError(SC_ERR_INVALID_ARGUMENT, "Invalid size specified for the rpc procedure:\"%s\"", args[i]);
                            goto error;
                        }
                        rd->flags |= DETECT_RPC_CHECK_PROCEDURE;
                    }
                break;
            }
        } else {
            SCLogError(SC_ERR_INVALID_VALUE, "invalid rpc option %s",rpcstr);
            goto error;
        }
    }
    for (i = 0; i < (ret -1); i++){
        if (args[i] != NULL)
            SCFree(args[i]);
    }
    return rd;

error:
    for (i = 0; i < (ret -1) && i < 3; i++){
        if (args[i] != NULL)
            SCFree(args[i]);
    }
    if (rd != NULL)
        DetectRpcFree(rd);
    return NULL;

}
static int DetectBase64DecodeParse(const char *str, uint32_t *bytes,
                                   uint32_t *offset, uint8_t *relative)
{
    static const int max = 30;
    int ov[max];
    int pcre_rc;
    const char *bytes_str = NULL;
    const char *offset_str = NULL;
    const char *relative_str = NULL;
    int retval = 0;

    *bytes = 0;
    *offset = 0;
    *relative = 0;

    pcre_rc = pcre_exec(decode_pcre, decode_pcre_study, str, strlen(str), 0, 0,
                        ov, max);
    if (pcre_rc < 3) {
        goto error;
    }

    if (pcre_rc >= 3) {
        if (pcre_get_substring((char *)str, ov, max, 2, &bytes_str) > 0) {
            if (ByteExtractStringUint32(bytes, 10, 0, bytes_str) <= 0) {
                SCLogError(SC_ERR_INVALID_RULE_ARGUMENT,
                           "Bad value for bytes: \"%s\"", bytes_str);
                goto error;
            }
        }
    }

    if (pcre_rc >= 5) {
        if (pcre_get_substring((char *)str, ov, max, 4, &offset_str)) {
            if (ByteExtractStringUint32(offset, 10, 0, offset_str) <= 0) {
                SCLogError(SC_ERR_INVALID_RULE_ARGUMENT,
                           "Bad value for offset: \"%s\"", offset_str);
                goto error;
            }
        }
    }

    if (pcre_rc >= 6) {
        if (pcre_get_substring((char *)str, ov, max, 5, &relative_str)) {
            if (strcmp(relative_str, "relative") == 0) {
                *relative = 1;
            }
            else {
                SCLogError(SC_ERR_INVALID_RULE_ARGUMENT,
                           "Invalid argument: \"%s\"", relative_str);
                goto error;
            }
        }
    }

    retval = 1;
error:
    if (bytes_str != NULL) {
        pcre_free_substring(bytes_str);
    }
    if (offset_str != NULL) {
        pcre_free_substring(offset_str);
    }
    if (relative_str != NULL) {
        pcre_free_substring(relative_str);
    }
    return retval;
}
Exemple #13
0
/** \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;
}
Exemple #14
0
static DetectBytetestData *DetectBytetestParse(const char *optstr, char **value, char **offset)
{
    DetectBytetestData *data = NULL;
    char *args[9] = {
        NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
        NULL
    };
#define MAX_SUBSTRINGS 30
    int ret = 0, res = 0;
    int ov[MAX_SUBSTRINGS];
    int i;
    uint32_t nbytes;
    const char *str_ptr = NULL;

    /* Execute the regex and populate args with captures. */
    ret = pcre_exec(parse_regex, parse_regex_study, optstr,
                    strlen(optstr), 0, 0, ov, MAX_SUBSTRINGS);
    if (ret < 6 || ret > 10) {
        SCLogError(SC_ERR_PCRE_PARSE, "parse error, ret %" PRId32
               ", string %s", ret, optstr);
        goto error;
    }
    for (i = 0; i < (ret - 1); i++) {
        res = pcre_get_substring((char *)optstr, ov, MAX_SUBSTRINGS,
                                 i + 1, &str_ptr);
        if (res < 0) {
            SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed "
                   "for arg %d", i + 1);
            goto error;
        }
        args[i] = (char *)str_ptr;
    }

    /* Initialize the data */
    data = SCMalloc(sizeof(DetectBytetestData));
    if (unlikely(data == NULL))
        goto error;
    data->base = DETECT_BYTETEST_BASE_UNSET;
    data->flags = 0;


    /*
     * The first four options are required and positional.  The
     * remaining arguments are flags and are not positional.
     */

    /* Number of bytes */
    if (ByteExtractStringUint32(&nbytes, 10, 0, args[0]) <= 0) {
        SCLogError(SC_ERR_INVALID_VALUE, "Malformed number of bytes: %s", str_ptr);
        goto error;
    }

    /* Operator is next two args: neg + op */
    data->op = 0;
    if (args[1] != NULL && *args[1] == '!') {
        data->flags |= DETECT_BYTETEST_NEGOP;
    }

    if (args[2] != NULL) {
        if ((strcmp("=", args[2]) == 0) || ((data->flags & DETECT_BYTETEST_NEGOP)
                && strcmp("", args[2]) == 0)) {
            data->op |= DETECT_BYTETEST_OP_EQ;
        } else if (strcmp("<", args[2]) == 0) {
            data->op |= DETECT_BYTETEST_OP_LT;
        } else if (strcmp(">", args[2]) == 0) {
            data->op |= DETECT_BYTETEST_OP_GT;
        } else if (strcmp("&", args[2]) == 0) {
            data->op |= DETECT_BYTETEST_OP_AND;
        } else if (strcmp("^", args[2]) == 0) {
            data->op |= DETECT_BYTETEST_OP_OR;
        } else if (strcmp(">=", args[2]) == 0) {
            data->op |= DETECT_BYTETEST_OP_GE;
        } else if (strcmp("<=", args[2]) == 0) {
            data->op |= DETECT_BYTETEST_OP_LE;
        } else {
            SCLogError(SC_ERR_INVALID_OPERATOR, "Invalid operator");
            goto error;
        }
    }

    /* Value */
    if (args[3][0] != '-' && isalpha((unsigned char)args[3][0])) {
        if (value == NULL) {
            SCLogError(SC_ERR_INVALID_ARGUMENT, "byte_test supplied with "
                       "var name for value.  \"value\" argument supplied to "
                       "this function has to be non-NULL");
            goto error;
        }
        *value = SCStrdup(args[3]);
        if (*value == NULL)
            goto error;
    } else {
        if (ByteExtractStringUint64(&data->value, 0, 0, args[3]) <= 0) {
            SCLogError(SC_ERR_INVALID_VALUE, "Malformed value: %s", str_ptr);
            goto error;
        }
    }

    /* Offset */
    if (args[4][0] != '-' && isalpha((unsigned char)args[4][0])) {
        if (offset == NULL) {
            SCLogError(SC_ERR_INVALID_ARGUMENT, "byte_test supplied with "
                       "var name for offset.  \"offset\" argument supplied to "
                       "this function has to be non-NULL");
            goto error;
        }
        *offset = SCStrdup(args[4]);
        if (*offset == NULL)
            goto error;
    } else {
        if (ByteExtractStringInt32(&data->offset, 0, 0, args[4]) <= 0) {
            SCLogError(SC_ERR_INVALID_VALUE, " Malformed offset: %s", str_ptr);
            goto error;
        }
    }

    /* The remaining options are flags. */
    /** \todo Error on dups? */
    for (i = 5; i < (ret - 1); i++) {
        if (args[i] != NULL) {
            if (strcmp("relative", args[i]) == 0) {
                data->flags |= DETECT_BYTETEST_RELATIVE;
            } else if (strcasecmp("string", args[i]) == 0) {
                data->flags |= DETECT_BYTETEST_STRING;
            } else if (strcasecmp("dec", args[i]) == 0) {
                data->base |= DETECT_BYTETEST_BASE_DEC;
            } else if (strcasecmp("hex", args[i]) == 0) {
                data->base |= DETECT_BYTETEST_BASE_HEX;
            } else if (strcasecmp("oct", args[i]) == 0) {
                data->base |= DETECT_BYTETEST_BASE_OCT;
            } else if (strcasecmp("big", args[i]) == 0) {
                if (data->flags & DETECT_BYTETEST_LITTLE) {
                    data->flags ^= DETECT_BYTETEST_LITTLE;
                }
                data->flags |= DETECT_BYTETEST_BIG;
            } else if (strcasecmp("little", args[i]) == 0) {
                data->flags |= DETECT_BYTETEST_LITTLE;
            } else if (strcasecmp("dce", args[i]) == 0) {
                data->flags |= DETECT_BYTETEST_DCE;
            } else {
                SCLogError(SC_ERR_UNKNOWN_VALUE, "Unknown value: \"%s\"",
                        args[i]);
                goto error;
            }
        }
    }

    if (data->flags & DETECT_BYTETEST_STRING) {
        /* 23 - This is the largest string (octal, with a zero prefix) that
         *      will not overflow uint64_t.  The only way this length
         *      could be over 23 and still not overflow is if it were zero
         *      prefixed and we only support 1 byte of zero prefix for octal.
         *
         * "01777777777777777777777" = 0xffffffffffffffff
         */
        if (nbytes > 23) {
            SCLogError(SC_ERR_INVALID_VALUE, "Cannot test more than 23 bytes with \"string\": %s",
                        optstr);
            goto error;
        }
    } else {
        if (nbytes > 8) {
            SCLogError(SC_ERR_INVALID_VALUE, "Cannot test more than 8 bytes without \"string\": %s",
                        optstr);
            goto error;
        }
        if (data->base != DETECT_BYTETEST_BASE_UNSET) {
            SCLogError(SC_ERR_INVALID_VALUE, "Cannot use a base without \"string\": %s", optstr);
            goto error;
        }
    }

    /* This is max 23 so it will fit in a byte (see above) */
    data->nbytes = (uint8_t)nbytes;

    for (i = 0; i < (ret - 1); i++){
        if (args[i] != NULL) SCFree(args[i]);
    }
    return data;

error:
    for (i = 0; i < (ret - 1); i++){
        if (args[i] != NULL) SCFree(args[i]);
    }
    if (data != NULL) DetectBytetestFree(data);
    return NULL;
}
/**
 * \internal
 * \brief This function is used to parse detection_filter options passed via detection_filter: keyword
 *
 * \param rawstr Pointer to the user provided detection_filter options
 *
 * \retval df pointer to DetectThresholdData on success
 * \retval NULL on failure
 */
DetectThresholdData *DetectDetectionFilterParse (char *rawstr)
{
    DetectThresholdData *df = NULL;
#define MAX_SUBSTRINGS 30
    int ret = 0, res = 0;
    int ov[MAX_SUBSTRINGS];
    const char *str_ptr = NULL;
    char *args[6] = { NULL, NULL, NULL, NULL, NULL, NULL};
    char *copy_str = NULL, *df_opt = NULL;
    int seconds_found = 0, count_found = 0, track_found = 0;
    int seconds_pos = 0, count_pos = 0;
    uint16_t pos = 0;
    int i = 0;

    copy_str = SCStrdup(rawstr);
    if (unlikely(copy_str == NULL)) {
        goto error;
    }

    for(pos = 0, df_opt = strtok(copy_str,",");  pos < strlen(copy_str) &&  df_opt != NULL;  pos++, df_opt = strtok(NULL,",")) {

        if(strstr(df_opt,"count"))
            count_found++;
        if(strstr(df_opt,"second"))
            seconds_found++;
        if(strstr(df_opt,"track"))
            track_found++;
    }
    SCFree(copy_str);
    copy_str = NULL;

    if (count_found != 1 || seconds_found != 1 || track_found != 1)
        goto error;

    ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS);
    if (ret < 5) {
        SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, rawstr);
        goto error;
    }

    df = SCMalloc(sizeof(DetectThresholdData));
    if (unlikely(df == NULL))
        goto error;

    memset(df,0,sizeof(DetectThresholdData));

    df->type = TYPE_DETECTION;

    for (i = 0; i < (ret - 1); i++) {
        res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, i + 1, &str_ptr);
        if (res < 0) {
            SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
            goto error;
        }

        args[i] = (char *)str_ptr;

        if (strncasecmp(args[i],"by_dst",strlen("by_dst")) == 0)
            df->track = TRACK_DST;
        if (strncasecmp(args[i],"by_src",strlen("by_src")) == 0)
            df->track = TRACK_SRC;
        if (strncasecmp(args[i],"count",strlen("count")) == 0)
            count_pos = i+1;
        if (strncasecmp(args[i],"seconds",strlen("seconds")) == 0)
            seconds_pos = i+1;
    }

    if (args[count_pos] == NULL || args[seconds_pos] == NULL) {
        goto error;
    }

    if (ByteExtractStringUint32(&df->count, 10, strlen(args[count_pos]),
                args[count_pos]) <= 0) {
        goto error;
    }

    if (ByteExtractStringUint32(&df->seconds, 10, strlen(args[seconds_pos]),
                args[seconds_pos]) <= 0) {
        goto error;
    }

    if (df->count == 0 || df->seconds == 0) {
        SCLogError(SC_ERR_INVALID_VALUE, "found an invalid value");
        goto error;
    }

    for (i = 0; i < 6; i++){
        if (args[i] != NULL)
            SCFree(args[i]);
    }
    return df;

error:
    for (i = 0; i < 6; i++){
        if (args[i] != NULL)
            SCFree(args[i]);
    }
    if (df != NULL)
        SCFree(df);
    return NULL;
}
/** \brief Create a new LogFileCtx from the provided ConfNode.
 *  \param conf The configuration node for this output.
 *  \return NULL if failure, LogFileCtx* to the file_ctx if succesful
 * */
OutputCtx *Unified2AlertInitCtx(ConfNode *conf)
{
    int ret = 0;
    LogFileCtx* file_ctx = NULL;

    file_ctx = LogFileNewCtx();
    if (file_ctx == NULL) {
        SCLogError(SC_ERR_UNIFIED2_ALERT_GENERIC, "Couldn't create new file_ctx");
        goto error;
    }

    const char *filename = NULL;
    if (conf != NULL) { /* To faciliate unit tests. */
        filename = ConfNodeLookupChildValue(conf, "filename");
    }
    if (filename == NULL)
        filename = DEFAULT_LOG_FILENAME;
    file_ctx->prefix = SCStrdup(filename);

    const char *s_limit = NULL;
    file_ctx->size_limit = DEFAULT_LIMIT;
    if (conf != NULL) {
        s_limit = ConfNodeLookupChildValue(conf, "limit");
        if (s_limit != NULL) {
            if (ParseSizeStringU64(s_limit, &file_ctx->size_limit) < 0) {
                SCLogError(SC_ERR_INVALID_ARGUMENT,
                    "Failed to initialize unified2 output, invalid limit: %s",
                    s_limit);
                exit(EXIT_FAILURE);
            }
            if (file_ctx->size_limit < 4096) {
                SCLogInfo("unified2-alert \"limit\" value of %"PRIu64" assumed to be pre-1.2 "
                        "style: setting limit to %"PRIu64"mb", file_ctx->size_limit, file_ctx->size_limit);
                uint64_t size = file_ctx->size_limit * 1024 * 1024;
                file_ctx->size_limit = size;
            } else if (file_ctx->size_limit < MIN_LIMIT) {
                SCLogError(SC_ERR_INVALID_ARGUMENT,
                    "Failed to initialize unified2 output, limit less than "
                    "allowed minimum: %d.", MIN_LIMIT);
                exit(EXIT_FAILURE);
            }
        }
    }

    if (conf != NULL) {
        const char *sensor_id_s = NULL;
        sensor_id_s = ConfNodeLookupChildValue(conf, "sensor-id");
        if (sensor_id_s != NULL) {
            if (ByteExtractStringUint32(&sensor_id, 10, 0, sensor_id_s) == -1) {
                SCLogError(SC_ERR_INVALID_ARGUMENT, "Failed to initialize unified2 output, invalid sensor-id: %s", sensor_id_s);
                exit(EXIT_FAILURE);
            }
        }
    }

    ret = Unified2AlertOpenFileCtx(file_ctx, filename);
    if (ret < 0)
        goto error;

    OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx));
    if (unlikely(output_ctx == NULL))
        goto error;
    output_ctx->data = file_ctx;
    output_ctx->DeInit = Unified2AlertDeInitCtx;

    SCLogInfo("Unified2-alert initialized: filename %s, limit %"PRIu64" MB",
              filename, file_ctx->size_limit / (1024*1024));

    SC_ATOMIC_INIT(unified2_event_id);

    return output_ctx;

error:
    if (file_ctx != NULL) {
        LogFileFreeCtx(file_ctx);
    }

    return NULL;
}
Exemple #17
0
/** \brief initialize the configuration
 *  \warning Not thread safe */
void IPPairInitConfig(char quiet)
{
    SCLogDebug("initializing ippair engine...");
    if (IPPairStorageSize() > 0)
        g_ippair_size = sizeof(IPPair) + IPPairStorageSize();

    memset(&ippair_config,  0, sizeof(ippair_config));
    //SC_ATOMIC_INIT(flow_flags);
    SC_ATOMIC_INIT(ippair_counter);
    SC_ATOMIC_INIT(ippair_memuse);
    SC_ATOMIC_INIT(ippair_prune_idx);
    SC_ATOMIC_INIT(ippair_config.memcap);
    IPPairQueueInit(&ippair_spare_q);

    /* set defaults */
    ippair_config.hash_rand   = (uint32_t)RandomGet();
    ippair_config.hash_size   = IPPAIR_DEFAULT_HASHSIZE;
    ippair_config.prealloc    = IPPAIR_DEFAULT_PREALLOC;
    SC_ATOMIC_SET(ippair_config.memcap, IPPAIR_DEFAULT_MEMCAP);

    /* Check if we have memcap and hash_size defined at config */
    const char *conf_val;
    uint32_t configval = 0;

    /** set config values for memcap, prealloc and hash_size */
    uint64_t ippair_memcap;
    if ((ConfGet("ippair.memcap", &conf_val)) == 1)
    {
        if (ParseSizeStringU64(conf_val, &ippair_memcap) < 0) {
            SCLogError(SC_ERR_SIZE_PARSE, "Error parsing ippair.memcap "
                       "from conf file - %s.  Killing engine",
                       conf_val);
            exit(EXIT_FAILURE);
        } else {
            SC_ATOMIC_SET(ippair_config.memcap, ippair_memcap);
        }
    }
    if ((ConfGet("ippair.hash-size", &conf_val)) == 1)
    {
        if (ByteExtractStringUint32(&configval, 10, strlen(conf_val),
                                    conf_val) > 0) {
            ippair_config.hash_size = configval;
        }
    }

    if ((ConfGet("ippair.prealloc", &conf_val)) == 1)
    {
        if (ByteExtractStringUint32(&configval, 10, strlen(conf_val),
                                    conf_val) > 0) {
            ippair_config.prealloc = configval;
        } else {
            WarnInvalidConfEntry("ippair.prealloc", "%"PRIu32, ippair_config.prealloc);
        }
    }
    SCLogDebug("IPPair config from suricata.yaml: memcap: %"PRIu64", hash-size: "
               "%"PRIu32", prealloc: %"PRIu32, SC_ATOMIC_GET(ippair_config.memcap),
               ippair_config.hash_size, ippair_config.prealloc);

    /* alloc hash memory */
    uint64_t hash_size = ippair_config.hash_size * sizeof(IPPairHashRow);
    if (!(IPPAIR_CHECK_MEMCAP(hash_size))) {
        SCLogError(SC_ERR_IPPAIR_INIT, "allocating ippair hash failed: "
                "max ippair memcap is smaller than projected hash size. "
                "Memcap: %"PRIu64", Hash table size %"PRIu64". Calculate "
                "total hash size by multiplying \"ippair.hash-size\" with %"PRIuMAX", "
                "which is the hash bucket size.", SC_ATOMIC_GET(ippair_config.memcap), hash_size,
                (uintmax_t)sizeof(IPPairHashRow));
        exit(EXIT_FAILURE);
    }
    ippair_hash = SCMallocAligned(ippair_config.hash_size * sizeof(IPPairHashRow), CLS);
    if (unlikely(ippair_hash == NULL)) {
        SCLogError(SC_ERR_FATAL, "Fatal error encountered in IPPairInitConfig. Exiting...");
        exit(EXIT_FAILURE);
    }
    memset(ippair_hash, 0, ippair_config.hash_size * sizeof(IPPairHashRow));

    uint32_t i = 0;
    for (i = 0; i < ippair_config.hash_size; i++) {
        HRLOCK_INIT(&ippair_hash[i]);
    }
    (void) SC_ATOMIC_ADD(ippair_memuse, (ippair_config.hash_size * sizeof(IPPairHashRow)));

    if (quiet == FALSE) {
        SCLogConfig("allocated %"PRIu64" bytes of memory for the ippair hash... "
                  "%" PRIu32 " buckets of size %" PRIuMAX "",
                  SC_ATOMIC_GET(ippair_memuse), ippair_config.hash_size,
                  (uintmax_t)sizeof(IPPairHashRow));
    }

    /* pre allocate ippairs */
    for (i = 0; i < ippair_config.prealloc; i++) {
        if (!(IPPAIR_CHECK_MEMCAP(g_ippair_size))) {
            SCLogError(SC_ERR_IPPAIR_INIT, "preallocating ippairs failed: "
                    "max ippair memcap reached. Memcap %"PRIu64", "
                    "Memuse %"PRIu64".", SC_ATOMIC_GET(ippair_config.memcap),
                    ((uint64_t)SC_ATOMIC_GET(ippair_memuse) + g_ippair_size));
            exit(EXIT_FAILURE);
        }

        IPPair *h = IPPairAlloc();
        if (h == NULL) {
            SCLogError(SC_ERR_IPPAIR_INIT, "preallocating ippair failed: %s", strerror(errno));
            exit(EXIT_FAILURE);
        }
        IPPairEnqueue(&ippair_spare_q,h);
    }

    if (quiet == FALSE) {
        SCLogConfig("preallocated %" PRIu32 " ippairs of size %" PRIu16 "",
                ippair_spare_q.len, g_ippair_size);
        SCLogConfig("ippair memory usage: %"PRIu64" bytes, maximum: %"PRIu64,
                SC_ATOMIC_GET(ippair_memuse), SC_ATOMIC_GET(ippair_config.memcap));
    }

    return;
}