Example #1
0
/**
 * \brief this funciton prints an error message and exits.
 * \param tv pointer to ThreadVars
 * \param initdata pointer to the interface passed from the user
 * \param data pointer gets populated with PfringThreadVars
 */
TmEcode NoPfringSupportExit(ThreadVars *tv, const void *initdata, void **data)
{
    SCLogError(SC_ERR_NO_PF_RING,"Error creating thread %s: you do not have support for pfring "
               "enabled please recompile with --enable-pfring", tv->name);
    exit(EXIT_FAILURE);
}
Example #2
0
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;
}
Example #3
0
/**
 * \brief This function is used to parse IPV4 ip_id passed via keyword: "id"
 *
 * \param idstr Pointer to the user provided id option
 *
 * \retval id_d pointer to DetectIdData on success
 * \retval NULL on failure
 */
DetectIdData *DetectIdParse (char *idstr)
{
    uint32_t temp;
    DetectIdData *id_d = NULL;
	#define MAX_SUBSTRINGS 30
    int ret = 0, res = 0;
    int ov[MAX_SUBSTRINGS];


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

    if (ret < 1 || ret > 3) {
        SCLogError(SC_ERR_PCRE_MATCH, "invalid id option. The id option value must be"
                    " in the range %u - %u",
                    DETECT_IPID_MIN, DETECT_IPID_MAX);
        goto error;
    }


    if (ret > 1) {
        const char *str_ptr;
        char *orig;
        char *tmp_str;
        res = pcre_get_substring((char *)idstr, ov, MAX_SUBSTRINGS, 1,
                                    &str_ptr);
        if (res < 0) {
            SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
            goto error;
        }

        /* We have a correct id option */
        id_d = SCMalloc(sizeof(DetectIdData));
        if (id_d == NULL)
            goto error;

        orig = SCStrdup((char*)str_ptr);
        tmp_str=orig;
        if (tmp_str == NULL) {
            goto error;
        }

        /* Let's see if we need to scape "'s */
        if (tmp_str[0] == '"')
        {
            tmp_str[strlen(tmp_str) - 1] = '\0';
            tmp_str += 1;
        }

        /* ok, fill the id data */
        temp = atoi((char *)tmp_str);

        if (temp > DETECT_IPID_MAX) {
            SCLogError(SC_ERR_INVALID_VALUE, "\"id\" option  must be in "
                        "the range %u - %u",
                        DETECT_IPID_MIN, DETECT_IPID_MAX);

            SCFree(orig);
            goto error;
        }
        id_d->id = temp;

        SCFree(orig);

        SCLogDebug("detect-id: will look for ip_id: %u\n", id_d->id);
    }

    return id_d;

error:
    if (id_d != NULL) DetectIdFree(id_d);
    return NULL;

}
/**
 *  \retval 2 silent match (no alert but apply actions)
 *  \retval 1 normal match
 *  \retval 0 no match
 */
int ThresholdHandlePacketHost(Host *h, Packet *p, DetectThresholdData *td, uint32_t sid, uint32_t gid) {
    int ret = 0;

    DetectThresholdEntry *lookup_tsh = ThresholdHostLookupEntry(h, sid, gid);
    SCLogDebug("lookup_tsh %p sid %u gid %u", lookup_tsh, sid, gid);

    switch(td->type)   {
        case TYPE_LIMIT:
        {
            SCLogDebug("limit");

            if (lookup_tsh != NULL)  {
                if ((p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) {
                    lookup_tsh->current_count++;

                    if (lookup_tsh->current_count <= td->count) {
                        ret = 1;
                    } else {
                        ret = 2;
                    }
                } else    {
                    lookup_tsh->tv_sec1 = p->ts.tv_sec;
                    lookup_tsh->current_count = 1;

                    ret = 1;
                }
            } else {
                DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid);
                if (e == NULL) {
                    break;
                }

                e->tv_sec1 = p->ts.tv_sec;
                e->current_count = 1;

                ret = 1;

                e->next = HostGetStorageById(h, threshold_id);
                HostSetStorageById(h, threshold_id, e);
            }
            break;
        }
        case TYPE_THRESHOLD:
        {
            SCLogDebug("threshold");

            if (lookup_tsh != NULL)  {
                if ((p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) {
                    lookup_tsh->current_count++;

                    if (lookup_tsh->current_count >= td->count) {
                        ret = 1;
                        lookup_tsh->current_count = 0;
                    }
                } else {
                    lookup_tsh->tv_sec1 = p->ts.tv_sec;
                    lookup_tsh->current_count = 1;
                }
            } else {
                if (td->count == 1)  {
                    ret = 1;
                } else {
                    DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid);
                    if (e == NULL) {
                        break;
                    }

                    e->current_count = 1;
                    e->tv_sec1 = p->ts.tv_sec;

                    e->next = HostGetStorageById(h, threshold_id);
                    HostSetStorageById(h, threshold_id, e);
                }
            }
            break;
        }
        case TYPE_BOTH:
        {
            SCLogDebug("both");

            if (lookup_tsh != NULL) {
                if ((p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) {
                    /* within time limit */

                    lookup_tsh->current_count++;
                    if (lookup_tsh->current_count == td->count) {
                        ret = 1;
                    } else if (lookup_tsh->current_count > td->count) {
                        /* silent match */
                        ret = 2;
                    }
                } else {
                    /* expired, so reset */
                    lookup_tsh->tv_sec1 = p->ts.tv_sec;
                    lookup_tsh->current_count = 1;

                    /* if we have a limit of 1, this is a match */
                    if (lookup_tsh->current_count == td->count) {
                        ret = 1;
                    }
                }
            } else {
                DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid);
                if (e == NULL) {
                    break;
                }

                e->current_count = 1;
                e->tv_sec1 = p->ts.tv_sec;

                e->next = HostGetStorageById(h, threshold_id);
                HostSetStorageById(h, threshold_id, e);

                /* for the first match we return 1 to
                 * indicate we should alert */
                if (td->count == 1)  {
                    ret = 1;
                }
            }
            break;
        }
        /* detection_filter */
        case TYPE_DETECTION:
        {
            SCLogDebug("detection_filter");

            if (lookup_tsh != NULL) {
                long double time_diff = ((p->ts.tv_sec + p->ts.tv_usec/1000000.0) -
                                         (lookup_tsh->tv_sec1 + lookup_tsh->tv_usec1/1000000.0));

                if (time_diff < td->seconds) {
                    /* within timeout */

                    lookup_tsh->current_count++;
                    if (lookup_tsh->current_count > td->count) {
                        ret = 1;
                    }
                } else {
                    /* expired, reset */

                    lookup_tsh->tv_sec1 = p->ts.tv_sec;
                    lookup_tsh->tv_usec1 = p->ts.tv_usec;
                    lookup_tsh->current_count = 1;
                }
            } else {
                DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid);
                if (e == NULL) {
                    break;
                }

                e->current_count = 1;
                e->tv_sec1 = p->ts.tv_sec;
                e->tv_usec1 = p->ts.tv_usec;

                e->next = HostGetStorageById(h, threshold_id);
                HostSetStorageById(h, threshold_id, e);
            }
            break;
        }
        /* rate_filter */
        case TYPE_RATE:
        {
            SCLogDebug("rate_filter");

            ret = 1;

            if (lookup_tsh != NULL) {
                /* Check if we have a timeout enabled, if so,
                 * we still matching (and enabling the new_action) */
                if (lookup_tsh->tv_timeout != 0) {
                    if ((p->ts.tv_sec - lookup_tsh->tv_timeout) > td->timeout) {
                        /* Ok, we are done, timeout reached */
                        lookup_tsh->tv_timeout = 0;
                    } else {
                        /* Already matching */
                        /* Take the action to perform */
                        switch (td->new_action) {
                            case TH_ACTION_ALERT:
                                PACKET_ALERT(p);
                                break;
                            case TH_ACTION_DROP:
                                PACKET_DROP(p);
                                break;
                            case TH_ACTION_REJECT:
                                PACKET_REJECT(p);
                                break;
                            case TH_ACTION_PASS:
                                PACKET_PASS(p);
                                break;
                            default:
                                /* Weird, leave the default action */
                                break;
                        }
                        ret = 1;
                    } /* else - if ((p->ts.tv_sec - lookup_tsh->tv_timeout) > td->timeout) */

                } else {
                    /* Update the matching state with the timeout interval */
                    if ( (p->ts.tv_sec - lookup_tsh->tv_sec1) < td->seconds) {
                        lookup_tsh->current_count++;
                        if (lookup_tsh->current_count > td->count) {
                            /* Then we must enable the new action by setting a
                             * timeout */
                            lookup_tsh->tv_timeout = p->ts.tv_sec;
                            /* Take the action to perform */
                            switch (td->new_action) {
                                case TH_ACTION_ALERT:
                                    PACKET_ALERT(p);
                                    break;
                                case TH_ACTION_DROP:
                                    PACKET_DROP(p);
                                    break;
                                case TH_ACTION_REJECT:
                                    PACKET_REJECT(p);
                                    break;
                                case TH_ACTION_PASS:
                                    PACKET_PASS(p);
                                    break;
                                default:
                                    /* Weird, leave the default action */
                                    break;
                            }
                            ret = 1;
                        }
                    } else {
                        lookup_tsh->tv_sec1 = p->ts.tv_sec;
                        lookup_tsh->current_count = 1;
                    }
                } /* else - if (lookup_tsh->tv_timeout != 0) */
            } else {
                if (td->count == 1) {
                    ret = 1;
                }

                DetectThresholdEntry *e = DetectThresholdEntryAlloc(td, p, sid, gid);
                if (e == NULL) {
                    break;
                }

                e->current_count = 1;
                e->tv_sec1 = p->ts.tv_sec;
                e->tv_timeout = 0;

                e->next = HostGetStorageById(h, threshold_id);
                HostSetStorageById(h, threshold_id, e);
            }
            break;
        }
        case TYPE_SUPPRESS:
        {
            int res = 0;
            switch (td->track) {
                case TRACK_DST:
                    res = DetectAddressMatch(td->addr, &p->dst);
                    break;
                case TRACK_SRC:
                    res = DetectAddressMatch(td->addr, &p->src);
                    break;
                case TRACK_RULE:
                default:
                    SCLogError(SC_ERR_INVALID_VALUE,
                               "track mode %d is not supported", td->track);
                    break;
            }
            if (res == 0)
                ret = 1;
            else
                ret = 2; /* suppressed but still need actions */
            break;
        }
        default:
            SCLogError(SC_ERR_INVALID_VALUE, "type %d is not supported", td->type);
    }

    return ret;
}
Example #5
0
int NetmapRunModeIsIPS()
{
    int nlive = LiveGetDeviceCount();
    int ldev;
    ConfNode *if_root;
    ConfNode *if_default = NULL;
    ConfNode *netmap_node;
    int has_ips = 0;
    int has_ids = 0;

    /* Find initial node */
    netmap_node = ConfGetNode("netmap");
    if (netmap_node == NULL) {
        return 0;
    }

    if_default = ConfNodeLookupKeyValue(netmap_node, "interface", "default");

    for (ldev = 0; ldev < nlive; ldev++) {
        const char *live_dev = LiveGetDeviceName(ldev);
        if (live_dev == NULL) {
            SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file");
            return 0;
        }
        char *copymodestr = NULL;
        if_root = ConfNodeLookupKeyValue(netmap_node, "interface", live_dev);

        if (if_root == NULL) {
            if (if_default == NULL) {
                SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file");
                return 0;
            }
            if_root = if_default;
        }

        if (ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", &copymodestr) == 1) {
            if (strcmp(copymodestr, "ips") == 0) {
                has_ips = 1;
            } else {
                has_ids = 1;
            }
        } else {
            has_ids = 1;
        }
    }

    if (has_ids && has_ips) {
        SCLogInfo("Netmap mode using IPS and IDS mode");
        for (ldev = 0; ldev < nlive; ldev++) {
            const char *live_dev = LiveGetDeviceName(ldev);
            if (live_dev == NULL) {
                SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file");
                return 0;
            }
            if_root = ConfNodeLookupKeyValue(netmap_node, "interface", live_dev);
            char *copymodestr = NULL;

            if (if_root == NULL) {
                if (if_default == NULL) {
                    SCLogError(SC_ERR_INVALID_VALUE, "Problem with config file");
                    return 0;
                }
                if_root = if_default;
            }

            if (! ((ConfGetChildValueWithDefault(if_root, if_default, "copy-mode", &copymodestr) == 1) &&
                    (strcmp(copymodestr, "ips") == 0))) {
                SCLogError(SC_ERR_INVALID_ARGUMENT,
                        "Netmap IPS mode used and interface '%s' is in IDS or TAP mode. "
                                "Sniffing '%s' but expect bad result as stream-inline is activated.",
                        live_dev, live_dev);
            }
        }
    }

    return has_ips;
}
/**
 * \brief This function is used to parse ssl_version data passed via
 *        keyword: "ssl_version"
 *
 * \param str Pointer to the user provided options
 *
 * \retval ssl pointer to DetectSslVersionData on success
 * \retval NULL on failure
 */
DetectSslVersionData *DetectSslVersionParse(char *str)
{
    DetectSslVersionData *ssl = NULL;
	#define MAX_SUBSTRINGS 30
    int ret = 0, res = 0;
    int ov[MAX_SUBSTRINGS];

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

    if (ret < 1 || ret > 5) {
        SCLogError(SC_ERR_PCRE_MATCH, "invalid ssl_version option");
        goto error;
    }

    if (ret > 1) {
        const char *str_ptr[5];
        char *orig;
        uint8_t found = 0, neg = 0;
        char *tmp_str;

        /* We have a correct ssl_version options */
        ssl = SCCalloc(1, sizeof (DetectSslVersionData));
        if (unlikely(ssl == NULL))
            goto error;

        int i;
        for (i = 1; i < ret; i++) {
            res = pcre_get_substring((char *) str, ov, MAX_SUBSTRINGS, i, &str_ptr[i]);
            if (res < 0) {
                SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
                if (found == 0)
                    goto error;
                break;
            }

            orig = SCStrdup((char*) str_ptr[i]);
            if (unlikely(orig == NULL)) {
                goto error;
            }
            tmp_str = orig;

            /* Let's see if we need to scape "'s */
            if (tmp_str[0] == '"') {
                tmp_str[strlen(tmp_str) - 1] = '\0';
                tmp_str += 1;
            }


            if (tmp_str[0] == '!') {
                neg = 1;
                tmp_str++;
            }

            if (strncasecmp("sslv2", tmp_str, 5) == 0) {
                ssl->data[SSLv2].ver = SSL_VERSION_2;
                if (neg == 1)
                    ssl->data[SSLv2].flags |= DETECT_SSL_VERSION_NEGATED;
            } else if (strncasecmp("sslv3", tmp_str, 5) == 0) {
                ssl->data[SSLv3].ver = SSL_VERSION_3;
                if (neg == 1)
                    ssl->data[SSLv3].flags |= DETECT_SSL_VERSION_NEGATED;
            } else if (strncasecmp("tls1.0", tmp_str, 6) == 0) {
                ssl->data[TLS10].ver = TLS_VERSION_10;
                if (neg == 1)
                    ssl->data[TLS10].flags |= DETECT_SSL_VERSION_NEGATED;
            } else if (strncasecmp("tls1.1", tmp_str, 6) == 0) {
                ssl->data[TLS11].ver = TLS_VERSION_11;
                if (neg == 1)
                    ssl->data[TLS11].flags |= DETECT_SSL_VERSION_NEGATED;
            } else if (strncasecmp("tls1.2", tmp_str, 6) == 0) {
                ssl->data[TLS12].ver = TLS_VERSION_12;
                if (neg == 1)
                    ssl->data[TLS12].flags |= DETECT_SSL_VERSION_NEGATED;
            }  else if (strcmp(tmp_str, "") == 0) {
                SCFree(orig);
                if (found == 0)
                    goto error;
                break;
            } else {
                SCLogError(SC_ERR_INVALID_VALUE, "Invalid value");
                SCFree(orig);
                goto error;
            }

            found = 1;
            neg = 0;
            SCFree(orig);
        }
    }

    return ssl;

error:
    if (ssl != NULL)
        DetectSslVersionFree(ssl);
    return NULL;

}
/**
 *  \brief Main PCAP file reading Loop function
 */
TmEcode ReceivePcapFileLoop(ThreadVars *tv, void *data, void *slot)
{
    SCEnter();

    int packet_q_len = 64;
    PcapFileThreadVars *ptv = (PcapFileThreadVars *)data;
    int r;
    TmSlot *s = (TmSlot *)slot;

    ptv->slot = s->slot_next;
    ptv->cb_result = TM_ECODE_OK;

    while (1) {
        if (suricata_ctl_flags & (SURICATA_STOP | SURICATA_KILL)) {
            SCReturnInt(TM_ECODE_OK);
        }

        /* make sure we have at least one packet in the packet pool, to prevent
         * us from alloc'ing packets at line rate */
        PacketPoolWait();

        /* Right now we just support reading packets one at a time. */
        r = pcap_dispatch(pcap_g.pcap_handle, packet_q_len,
                          (pcap_handler)PcapFileCallbackLoop, (u_char *)ptv);
        if (unlikely(r == -1)) {
            SCLogError(SC_ERR_PCAP_DISPATCH, "error code %" PRId32 " %s",
                       r, pcap_geterr(pcap_g.pcap_handle));
            if (! RunModeUnixSocketIsActive()) {
                /* in the error state we just kill the engine */
                EngineKill();
                SCReturnInt(TM_ECODE_FAILED);
            } else {
                pcap_close(pcap_g.pcap_handle);
                pcap_g.pcap_handle = NULL;
                UnixSocketPcapFile(TM_ECODE_DONE);
                SCReturnInt(TM_ECODE_DONE);
            }
        } else if (unlikely(r == 0)) {
            SCLogInfo("pcap file end of file reached (pcap err code %" PRId32 ")", r);
            if (! RunModeUnixSocketIsActive()) {
                EngineStop();
            } else {
                pcap_close(pcap_g.pcap_handle);
                pcap_g.pcap_handle = NULL;
                UnixSocketPcapFile(TM_ECODE_DONE);
                SCReturnInt(TM_ECODE_DONE);
            }
            break;
        } else if (ptv->cb_result == TM_ECODE_FAILED) {
            SCLogError(SC_ERR_PCAP_DISPATCH, "Pcap callback PcapFileCallbackLoop failed");
            if (! RunModeUnixSocketIsActive()) {
                EngineKill();
                SCReturnInt(TM_ECODE_FAILED);
            } else {
                pcap_close(pcap_g.pcap_handle);
                pcap_g.pcap_handle = NULL;
                UnixSocketPcapFile(TM_ECODE_DONE);
                SCReturnInt(TM_ECODE_DONE);
            }
        }
        StatsSyncCountersIfSignalled(tv);
    }

    SCReturnInt(TM_ECODE_OK);
}
/**
 * \brief Parses a line from the classification file and adds it to Classtype
 *        hash table in DetectEngineCtx, i.e. DetectEngineCtx->class_conf_ht.
 *
 * \param rawstr Pointer to the string to be parsed.
 * \param index  Relative index of the string to be parsed.
 * \param de_ctx Pointer to the Detection Engine Context.
 *
 * \retval  0 On success.
 * \retval -1 On failure.
 */
int SCClassConfAddClasstype(char *rawstr, uint8_t index, DetectEngineCtx *de_ctx)
{
    const char *ct_name = NULL;
    const char *ct_desc = NULL;
    const char *ct_priority_str = NULL;
    int ct_priority = 0;
    uint8_t ct_id = index;

    SCClassConfClasstype *ct_new = NULL;
    SCClassConfClasstype *ct_lookup = NULL;

#define MAX_SUBSTRINGS 30
    int ret = 0;
    int ov[MAX_SUBSTRINGS];

    ret = pcre_exec(regex, regex_study, rawstr, strlen(rawstr), 0, 0, ov, 30);
    if (ret < 0) {
        SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid Classtype in "
                   "classification.config file");
        goto error;
    }

    /* retrieve the classtype name */
    ret = pcre_get_substring((char *)rawstr, ov, 30, 1, &ct_name);
    if (ret < 0) {
        SCLogInfo("pcre_get_substring() failed");
        goto error;
    }

    /* retrieve the classtype description */
    ret = pcre_get_substring((char *)rawstr, ov, 30, 2, &ct_desc);
    if (ret < 0) {
        SCLogInfo("pcre_get_substring() failed");
        goto error;
    }

    /* retrieve the classtype priority */
    ret = pcre_get_substring((char *)rawstr, ov, 30, 3, &ct_priority_str);
    if (ret < 0) {
        SCLogInfo("pcre_get_substring() failed");
        goto error;
    }
    if (ct_priority_str == NULL) {
        goto error;
    }

    ct_priority = atoi(ct_priority_str);

    /* Create a new instance of the parsed Classtype string */
    ct_new = SCClassConfAllocClasstype(ct_id, ct_name, ct_desc, ct_priority);
    if (ct_new == NULL)
        goto error;

    /* Check if the Classtype is present in the HashTable.  In case it's present
     * ignore it, as it is a duplicate.  If not present, add it to the table */
    ct_lookup = HashTableLookup(de_ctx->class_conf_ht, ct_new, 0);
    if (ct_lookup == NULL) {
        if (HashTableAdd(de_ctx->class_conf_ht, ct_new, 0) < 0)
            SCLogDebug("HashTable Add failed");
    } else {
        SCLogDebug("Duplicate classtype found inside classification.config");
        if (ct_new->classtype_desc) SCFree(ct_new->classtype_desc);
        if (ct_new->classtype) SCFree(ct_new->classtype);
        SCFree(ct_new);
    }

    if (ct_name) SCFree((char *)ct_name);
    if (ct_desc) SCFree((char *)ct_desc);
    if (ct_priority_str) SCFree((char *)ct_priority_str);
    return 0;

error:
    if (ct_name) SCFree((char *)ct_name);
    if (ct_desc) SCFree((char *)ct_desc);
    if (ct_priority_str) SCFree((char *)ct_priority_str);

    return -1;
}
/**
 * \brief Inits the context to be used by the Classification Config parsing API.
 *
 *        This function initializes the hash table to be used by the Detection
 *        Engine Context to hold the data from the classification.config file,
 *        obtains the file desc to parse the classification.config file, and
 *        inits the regex used to parse the lines from classification.config
 *        file.
 *
 * \param de_ctx Pointer to the Detection Engine Context.
 *
 * \retval  0 On success.
 * \retval -1 On failure.
 */
int SCClassConfInitContextAndLocalResources(DetectEngineCtx *de_ctx)
{
    char *filename = NULL;
    const char *eb = NULL;
    int eo;
    int opts = 0;

    /* init the hash table to be used by the classification config Classtypes */
    de_ctx->class_conf_ht = HashTableInit(4096, SCClassConfClasstypeHashFunc,
                                          SCClassConfClasstypeHashCompareFunc,
                                          SCClassConfClasstypeHashFree);
    if (de_ctx->class_conf_ht == NULL) {
        SCLogError(SC_ERR_HASH_TABLE_INIT, "Error initializing the hash "
                   "table");
        goto error;
    }

    /* if it is not NULL, use the file descriptor.  The hack so that we can
     * avoid using a dummy classification file for testing purposes and
     * instead use an input stream against a buffer containing the
     * classification strings */
    if (fd == NULL) {
        filename = SCClassConfGetConfFilename();
        if ( (fd = fopen(filename, "r")) == NULL) {
            SCLogError(SC_ERR_FOPEN, "Error opening file: \"%s\": %s", filename, strerror(errno));
            goto error;
        }
    }

    regex = pcre_compile(DETECT_CLASSCONFIG_REGEX, opts, &eb, &eo, NULL);
    if (regex == NULL) {
        SCLogDebug("Compile of \"%s\" failed at offset %" PRId32 ": %s",
                   DETECT_CLASSCONFIG_REGEX, eo, eb);
        goto error;
    }

    regex_study = pcre_study(regex, 0, &eb);
    if (eb != NULL) {
        SCLogDebug("pcre study failed: %s", eb);
        goto error;
    }

    return 0;

error:
    if (de_ctx->class_conf_ht != NULL) {
        HashTableFree(de_ctx->class_conf_ht);
        de_ctx->class_conf_ht = NULL;
    }
    if (fd != NULL) {
        fclose(fd);
        fd = NULL;
    }

    if (regex != NULL) {
        pcre_free(regex);
        regex = NULL;
    }
    if (regex_study != NULL) {
        pcre_free(regex_study);
        regex_study = NULL;
    }

    return -1;
}
Example #10
0
/** \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;
}
Example #11
0
/**
 *  \internal
 *  \brief Apply the nocase keyword to the last pattern match, either content or uricontent
 *  \param det_ctx detection engine ctx
 *  \param s signature
 *  \param nullstr should be null
 *  \retval 0 ok
 *  \retval -1 failure
 */
static int DetectNocaseSetup (DetectEngineCtx *de_ctx, Signature *s, char *nullstr)
{
    SCEnter();

    SigMatch *pm = NULL;
    int ret = -1;

    if (nullstr != NULL) {
        SCLogError(SC_ERR_INVALID_VALUE, "nocase has value");
        goto end;
    }

    /* retrive the sm to apply the depth against */
    if (s->list != DETECT_SM_LIST_NOTSET) {
        pm = SigMatchGetLastSMFromLists(s, 2, DETECT_CONTENT, s->sm_lists_tail[s->list]);
    } else {
        pm =  SigMatchGetLastSMFromLists(s, 28,
                                         DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH],
                                         DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_UMATCH],
                                         DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRUDMATCH],
                                         DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCBDMATCH],
                                         DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_FILEDATA],
                                         DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHDMATCH],
                                         DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHDMATCH],
                                         DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HMDMATCH],
                                         DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HCDMATCH],
                                         DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSCDMATCH],
                                         DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH],
                                         DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HUADMATCH],
                                         DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HHHDMATCH],
                                         DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HRHHDMATCH]);
    }
    if (pm == NULL) {
        SCLogError(SC_ERR_NOCASE_MISSING_PATTERN, "nocase needs "
                   "preceding content, uricontent option, http_client_body, "
                   "http_server_body, http_header option, http_raw_header option, "
                   "http_method option, http_cookie, http_raw_uri, "
                   "http_stat_msg, http_stat_code, http_user_agent or "
                   "file_data/dce_stub_data sticky buffer options");
        goto end;
    }


    /* verify other conditions. */
    DetectContentData *cd = (DetectContentData *)pm->ctx;;

    if (cd->flags & DETECT_CONTENT_NOCASE) {
        SCLogError(SC_ERR_INVALID_SIGNATURE, "can't use multiple nocase modifiers with the same content");
        goto end;
    }

    /* for consistency in later use (e.g. by MPM construction and hashing),
     * coerce the content string to lower-case. */
    for (uint8_t *c = cd->content; c < cd->content + cd->content_len; c++) {
        *c = u8_tolower(*c);
    }

    cd->flags |= DETECT_CONTENT_NOCASE;
    /* Recreate the context with nocase chars */
    SpmDestroyCtx(cd->spm_ctx);
    cd->spm_ctx = SpmInitCtx(cd->content, cd->content_len, 1,
                             de_ctx->spm_global_thread_ctx);
    if (cd->spm_ctx == NULL) {
        goto end;
    }

    ret = 0;
 end:
    SCReturnInt(ret);
}
Example #12
0
/**
 *  \brief Function to fill unified2 ipv6 ids type format into the file.
 *
 *  \param t Thread Variable containing  input/output queue, cpu affinity etc.
 *  \param p Packet struct used to decide for ipv4 or ipv6
 *  \param data Unified2 thread data.
 *  \param pq Packet queue
 *
 *  \retval 0 on succces
 *  \retval -1 on failure
 */
int Unified2IPv6TypeAlert (ThreadVars *t, Packet *p, void *data, PacketQueue *pq)
{
    Unified2AlertThread *aun = (Unified2AlertThread *)data;
    Unified2AlertFileHeader hdr;
    AlertIPv6Unified2 *phdr = (AlertIPv6Unified2 *)(aun->data +
                                sizeof(Unified2AlertFileHeader));
    AlertIPv6Unified2 gphdr;
    PacketAlert *pa;
    int offset, length;
    int ret;
    unsigned int event_id;

    if (p->alerts.cnt == 0)
        return 0;

    length = (sizeof(Unified2AlertFileHeader) + sizeof(AlertIPv6Unified2));
    offset = length;

    memset(aun->data, 0, aun->datalen);

    hdr.type = htonl(UNIFIED2_IDS_EVENT_IPV6_TYPE);
    hdr.length = htonl(sizeof(AlertIPv6Unified2));

    /* fill the gphdr structure with the data of the packet */
    memset(&gphdr, 0, sizeof(gphdr));
    /* FIXME this need to be copied for each alert */
    gphdr.sensor_id = htonl(sensor_id);
    gphdr.event_second =  htonl(p->ts.tv_sec);
    gphdr.event_microsecond = htonl(p->ts.tv_usec);
    gphdr.src_ip = *(struct in6_addr*)GET_IPV6_SRC_ADDR(p);
    gphdr.dst_ip = *(struct in6_addr*)GET_IPV6_DST_ADDR(p);
    gphdr.protocol = p->proto;

    if(p->action & ACTION_DROP)
        gphdr.packet_action = UNIFIED2_BLOCKED_FLAG;
    else
        gphdr.packet_action = 0;

    switch(gphdr.protocol)  {
        case IPPROTO_ICMPV6:
            if(p->icmpv6h)  {
                gphdr.sp = htons(p->icmpv6h->type);
                gphdr.dp = htons(p->icmpv6h->code);
            } else {
                gphdr.sp = 0;
                gphdr.dp = 0;
            }
            break;
        case IPPROTO_ICMP:
            if(p->icmpv4h)  {
                gphdr.sp = htons(p->icmpv4h->type);
                gphdr.dp = htons(p->icmpv4h->code);
            } else {
                gphdr.sp = 0;
                gphdr.dp = 0;
            }
            break;
        case IPPROTO_UDP:
        case IPPROTO_TCP:
        case IPPROTO_SCTP:
            gphdr.sp = htons(p->sp);
            gphdr.dp = htons(p->dp);
            break;
        default:
            gphdr.sp = 0;
            gphdr.dp = 0;
            break;
    }

    uint16_t i = 0;
    for (; i < p->alerts.cnt + 1; i++) {
        if (i < p->alerts.cnt)
            pa = &p->alerts.alerts[i];
        else {
            if (!(p->flags & PKT_HAS_TAG))
                break;
            pa = PacketAlertGetTag();
        }

        if (unlikely(pa->s == NULL))
            continue;

        /* reset length and offset */
        aun->offset = offset;
        aun->length = length;
        memset(aun->data + aun->offset, 0, aun->datalen - aun->offset);

        /* copy the part common to all alerts */
        memcpy(aun->data, &hdr, sizeof(hdr));
        memcpy(phdr, &gphdr, sizeof(gphdr));

        /* fill the header structure with the data of the alert */
        event_id = htonl(SC_ATOMIC_ADD(unified2_event_id, 1));
        phdr->event_id = event_id;
        phdr->generator_id = htonl(pa->s->gid);
        phdr->signature_id = htonl(pa->s->id);
        phdr->signature_revision = htonl(pa->s->rev);
        phdr->classification_id = htonl(pa->s->class);
        phdr->priority_id = htonl(pa->s->prio);

        SCMutexLock(&aun->file_ctx->fp_mutex);
        if ((aun->file_ctx->size_current + length) > aun->file_ctx->size_limit) {
            if (Unified2AlertRotateFile(t,aun) < 0) {
                aun->file_ctx->alerts += i;
                SCMutexUnlock(&aun->file_ctx->fp_mutex);
                return -1;
            }
        }

        if (Unified2Write(aun) != 1) {
            aun->file_ctx->alerts += i;
            SCMutexUnlock(&aun->file_ctx->fp_mutex);
            return -1;
        }

        memset(aun->data, 0, aun->length);
        aun->length = 0;
        aun->offset = 0;

        ret = Unified2PacketTypeAlert(aun, p, phdr->event_id,
                pa->flags & (PACKET_ALERT_FLAG_STATE_MATCH|PACKET_ALERT_FLAG_STREAM_MATCH) ? 1 : 0);
        if (ret != 1) {
            SCLogError(SC_ERR_FWRITE, "Error: fwrite failed: %s", strerror(errno));
            aun->file_ctx->alerts += i;
            SCMutexUnlock(&aun->file_ctx->fp_mutex);
            return -1;
        }
        fflush(aun->file_ctx->fp);
        aun->file_ctx->alerts++;
        SCMutexUnlock(&aun->file_ctx->fp_mutex);
    }

    return 0;
}
Example #13
0
/**
 *  \brief Function to fill unified2 packet format into the file. If the alert
 *         was generated based on a stream chunk we call the stream function
 *         to generate the record.
 *
 *  Barnyard2 doesn't like DLT_RAW + IPv6, so if we don't have an ethernet
 *  header, we create a fake one.
 *
 *  No need to lock here, since it's already locked.
 *
 *  \param aun thread local data
 *  \param p Packet
 *  \param stream pointer to stream chunk
 *  \param event_id unique event id
 *  \param stream state/stream match, try logging stream segments
 *
 *  \retval 0 on succces
 *  \retval -1 on failure
 */
int Unified2PacketTypeAlert (Unified2AlertThread *aun, Packet *p, uint32_t event_id, int stream)
{
    int ret = 0;

    /* try stream logging first */
    if (stream) {
        SCLogDebug("logging the state");
        uint8_t flag;

        if (p->flowflags & FLOW_PKT_TOSERVER) {
            flag = FLOW_PKT_TOCLIENT;
        } else {
            flag = FLOW_PKT_TOSERVER;
        }

        /* make event id available to callback */
        aun->event_id = event_id;

        /* run callback for all segments in the stream */
        ret = StreamSegmentForEach(p, flag, Unified2PrintStreamSegmentCallback, (void *)aun);
    }

    /* or no segment could been logged or no segment have been logged */
    if (ret == 0) {
        SCLogDebug("no stream, no state: falling back to payload logging");

        Unified2AlertFileHeader *hdr = (Unified2AlertFileHeader*)(aun->data);
        Unified2Packet *phdr = (Unified2Packet *)(hdr + 1);
        int len = (sizeof(Unified2AlertFileHeader) + UNIFIED2_PACKET_SIZE);
        int datalink = p->datalink;
#ifdef HAVE_OLD_BARNYARD2
        int ethh_offset = 0;
        EthernetHdr ethhdr = { {0,0,0,0,0,0}, {0,0,0,0,0,0}, htons(ETHERNET_TYPE_IPV6) };
#endif
        memset(hdr, 0, sizeof(Unified2AlertFileHeader));
        memset(phdr, 0, sizeof(Unified2Packet));

        hdr->type = htonl(UNIFIED2_PACKET_TYPE);
        aun->hdr = hdr;

        phdr->sensor_id = htonl(sensor_id);
        phdr->linktype = htonl(datalink);
        phdr->event_id =  event_id;
        phdr->event_second = phdr->packet_second = htonl(p->ts.tv_sec);
        phdr->packet_microsecond = htonl(p->ts.tv_usec);
        aun->phdr = phdr;

        /* we need to reset offset and length which could
         * have been modified by the segment logging */
        aun->offset = len;
        len += GET_PKT_LEN(p);
        aun->length = len;

        /* Unified 2 packet header is the one of the packet. */
        phdr->linktype = htonl(p->datalink);
#ifdef HAVE_OLD_BARNYARD2
        /* Fake datalink to avoid bug with old barnyard2 */
        if (PKT_IS_IPV6(p) && (!p->ethh)) {
            /* Fake this */
            ethh_offset = 14;
            datalink = DLT_EN10MB;
            phdr->linktype = htonl(datalink);
            aun->length += ethh_offset;
            if (aun->length > aun->datalen) {
                SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data: %d vs %d",
                        len, aun->datalen - aun->offset);
                return -1;
            }
            ethhdr.eth_type = htons(ETHERNET_TYPE_IPV6);

            memcpy(aun->data + aun->offset, &ethhdr, 14);
            aun->offset += ethh_offset;
        }
#endif

        if (len > aun->datalen) {
            SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data: %d vs %d",
                    len, aun->datalen - aun->offset);
            return -1;
        }
        hdr->length = htonl(UNIFIED2_PACKET_SIZE + GET_PKT_LEN(p));
        phdr->packet_length = htonl(GET_PKT_LEN(p));
        memcpy(aun->data + aun->offset, GET_PKT_DATA(p), GET_PKT_LEN(p));

        ret = Unified2Write(aun);
    }

    if (ret < 1) {
        return -1;
    }

    return 1;
}
Example #14
0
/**
 * \brief Write a faked Packet in unified2 file for each stream segment.
 */
static int Unified2PrintStreamSegmentCallback(Packet *p, void *data, uint8_t *buf, uint32_t buflen)
{
    int ret = 1;
    Unified2AlertThread *aun = (Unified2AlertThread *)data;
    Unified2AlertFileHeader *hdr = (Unified2AlertFileHeader*)(aun->data);
    Unified2Packet *phdr = (Unified2Packet *)(hdr + 1);
    int ethh_offset = 0;
    EthernetHdr ethhdr = { {0,0,0,0,0,0}, {0,0,0,0,0,0}, htons(ETHERNET_TYPE_IPV6) };
    uint32_t hdr_length = 0;
    int datalink = p->datalink;

    memset(hdr, 0, sizeof(Unified2AlertFileHeader));
    memset(phdr, 0, sizeof(Unified2Packet));

    hdr->type = htonl(UNIFIED2_PACKET_TYPE);
    aun->hdr = hdr;

    phdr->sensor_id = htonl(sensor_id);
    phdr->linktype = htonl(datalink);
    phdr->event_id = aun->event_id;
    phdr->event_second = phdr->packet_second = htonl(p->ts.tv_sec);
    phdr->packet_microsecond = htonl(p->ts.tv_usec);
    aun->phdr = phdr;

    if (p->datalink != DLT_EN10MB) {
        /* We have raw data here */
        phdr->linktype = htonl(DLT_RAW);
        datalink = DLT_RAW;
    }

    aun->length = sizeof(Unified2AlertFileHeader) + UNIFIED2_PACKET_SIZE;
    aun->offset = sizeof(Unified2AlertFileHeader) + UNIFIED2_PACKET_SIZE;

    /* Include Packet header */
    if (PKT_IS_IPV4(p)) {
        FakeIPv4Hdr fakehdr;
        hdr_length = sizeof(FakeIPv4Hdr);

        if (p->datalink == DLT_EN10MB) {
            /* Fake this */
            ethh_offset = 14;
            datalink = DLT_EN10MB;
            phdr->linktype = htonl(datalink);
            aun->length += ethh_offset;

            if (aun->length > aun->datalen) {
                SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data");
                goto error;
            }
            ethhdr.eth_type = htons(ETHERNET_TYPE_IP);

            memcpy(aun->data + aun->offset, &ethhdr, 14);
            aun->offset += ethh_offset;
        }

        memset(&fakehdr, 0, hdr_length);
        aun->length += hdr_length;
        Unified2ForgeFakeIPv4Header(&fakehdr, p, hdr_length + buflen, 0);
        if (aun->length > aun->datalen) {
            SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data");
            goto error;
        }
        memcpy(aun->data + aun->offset, &fakehdr, hdr_length);
        aun->iphdr = (void *)(aun->data + aun->offset);
        aun->offset += hdr_length;

    } else if (PKT_IS_IPV6(p)) {
        FakeIPv6Hdr fakehdr;
        hdr_length = sizeof(FakeIPv6Hdr);

        if (p->datalink == DLT_EN10MB) {
            /* Fake this */
            ethh_offset = 14;
            datalink = DLT_EN10MB;
            phdr->linktype = htonl(datalink);
            aun->length += ethh_offset;
            if (aun->length > aun->datalen) {
                SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data");
                goto error;
            }
            ethhdr.eth_type = htons(ETHERNET_TYPE_IPV6);

            memcpy(aun->data + aun->offset, &ethhdr, 14);
            aun->offset += ethh_offset;
        }

        memset(&fakehdr, 0, hdr_length);
        Unified2ForgeFakeIPv6Header(&fakehdr, p, buflen, 1);

        aun->length += hdr_length;
        if (aun->length > aun->datalen) {
            SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread data");
            goto error;
        }
        memcpy(aun->data + aun->offset, &fakehdr, hdr_length);
        aun->iphdr = (void *)(aun->data + aun->offset);
        aun->offset += hdr_length;
    } else {
        goto error;
    }

    /* update unified2 headers for length */
    aun->hdr->length = htonl(UNIFIED2_PACKET_SIZE + ethh_offset +
            hdr_length + buflen);
    aun->phdr->packet_length = htonl(ethh_offset + hdr_length + buflen);

    /* copy stream segment payload in */
    aun->length += buflen;

    if (aun->length > aun->datalen) {
        SCLogError(SC_ERR_INVALID_VALUE, "len is too big for thread"
                   " data: %d vs %d", aun->length, aun->datalen);
        goto error;
    }

    memcpy(aun->data + aun->offset, buf, buflen);
    aun->offset += buflen;

    /* rebuild checksum */
    if (PKT_IS_IPV6(p)) {
        FakeIPv6Hdr *fakehdr = (FakeIPv6Hdr *)aun->iphdr;

        fakehdr->tcph.th_sum = TCPV6CalculateChecksum(fakehdr->ip6h.s_ip6_addrs,
                (uint16_t *)&fakehdr->tcph, buflen + sizeof(TCPHdr));
    } else {
        FakeIPv4Hdr *fakehdr = (FakeIPv4Hdr *)aun->iphdr;

        fakehdr->tcph.th_sum = TCPCalculateChecksum(fakehdr->ip4h.s_ip_addrs,
                (uint16_t *)&fakehdr->tcph, buflen + sizeof(TCPHdr));
        fakehdr->ip4h.ip_csum = IPV4CalculateChecksum((uint16_t *)&fakehdr->ip4h,
                IPV4_GET_RAW_HLEN(&fakehdr->ip4h));
    }

    /* write out */
    ret = Unified2Write(aun);
    if (ret != 1) {
        goto error;
    }
    return 1;

error:
    aun->length = 0;
    aun->offset = 0;
    return -1;
}
Example #15
0
TmEcode NFQInitThread(NFQThreadVars *nfq_t, uint32_t queue_maxlen)
{
#ifndef OS_WIN32
    struct timeval tv;
    int opt;
#endif
    NFQQueueVars *nfq_q = NFQGetQueue(nfq_t->nfq_index);
    if (nfq_q == NULL) {
        SCLogError(SC_ERR_NFQ_OPEN, "no queue for given index");
        return TM_ECODE_FAILED;
    }
    SCLogDebug("opening library handle");
    nfq_q->h = nfq_open();
    if (!nfq_q->h) {
        SCLogError(SC_ERR_NFQ_OPEN, "nfq_open() failed");
        return TM_ECODE_FAILED;
    }

    if (nfq_g.unbind == 0)
    {
        /* VJ: on my Ubuntu Hardy system this fails the first time it's
         * run. Ignoring the error seems to have no bad effects. */
        SCLogDebug("unbinding existing nf_queue handler for AF_INET (if any)");
        if (nfq_unbind_pf(nfq_q->h, AF_INET) < 0) {
            SCLogError(SC_ERR_NFQ_UNBIND, "nfq_unbind_pf() for AF_INET failed");
            exit(EXIT_FAILURE);
        }
        if (nfq_unbind_pf(nfq_q->h, AF_INET6) < 0) {
            SCLogError(SC_ERR_NFQ_UNBIND, "nfq_unbind_pf() for AF_INET6 failed");
            exit(EXIT_FAILURE);
        }
        nfq_g.unbind = 1;

        SCLogDebug("binding nfnetlink_queue as nf_queue handler for AF_INET and AF_INET6");

        if (nfq_bind_pf(nfq_q->h, AF_INET) < 0) {
            SCLogError(SC_ERR_NFQ_BIND, "nfq_bind_pf() for AF_INET failed");
            exit(EXIT_FAILURE);
        }
        if (nfq_bind_pf(nfq_q->h, AF_INET6) < 0) {
            SCLogError(SC_ERR_NFQ_BIND, "nfq_bind_pf() for AF_INET6 failed");
            exit(EXIT_FAILURE);
        }
    }

    SCLogInfo("binding this thread %d to queue '%" PRIu32 "'", nfq_t->nfq_index, nfq_q->queue_num);

    /* pass the thread memory as a void ptr so the
     * callback function has access to it. */
    nfq_q->qh = nfq_create_queue(nfq_q->h, nfq_q->queue_num, &NFQCallBack, (void *)nfq_t);
    if (nfq_q->qh == NULL)
    {
        SCLogError(SC_ERR_NFQ_CREATE_QUEUE, "nfq_create_queue failed");
        return TM_ECODE_FAILED;
    }

    SCLogDebug("setting copy_packet mode");

    /* 05DC = 1500 */
    //if (nfq_set_mode(nfq_t->qh, NFQNL_COPY_PACKET, 0x05DC) < 0) {
    if (nfq_set_mode(nfq_q->qh, NFQNL_COPY_PACKET, 0xFFFF) < 0) {
        SCLogError(SC_ERR_NFQ_SET_MODE, "can't set packet_copy mode");
        return TM_ECODE_FAILED;
    }

#ifdef HAVE_NFQ_MAXLEN
    if (queue_maxlen > 0) {
        SCLogInfo("setting queue length to %" PRId32 "", queue_maxlen);

        /* non-fatal if it fails */
        if (nfq_set_queue_maxlen(nfq_q->qh, queue_maxlen) < 0) {
            SCLogWarning(SC_ERR_NFQ_MAXLEN, "can't set queue maxlen: your kernel probably "
                    "doesn't support setting the queue length");
        }
    }
#endif /* HAVE_NFQ_MAXLEN */

#ifndef OS_WIN32
    /* set netlink buffer size to a decent value */
    nfnl_rcvbufsiz(nfq_nfnlh(nfq_q->h), queue_maxlen * 1500);
    SCLogInfo("setting nfnl bufsize to %" PRId32 "", queue_maxlen * 1500);

    nfq_q->nh = nfq_nfnlh(nfq_q->h);
    nfq_q->fd = nfnl_fd(nfq_q->nh);
    NFQMutexInit(nfq_q);

    /* Set some netlink specific option on the socket to increase
	performance */
    opt = 1;
#ifdef NETLINK_BROADCAST_SEND_ERROR
    if (setsockopt(nfq_q->fd, SOL_NETLINK,
                   NETLINK_BROADCAST_SEND_ERROR, &opt, sizeof(int)) == -1) {
        SCLogWarning(SC_ERR_NFQ_SETSOCKOPT,
                     "can't set netlink broadcast error: %s",
                     strerror(errno));
    }
#endif
    /* Don't send error about no buffer space available but drop the
	packets instead */
#ifdef NETLINK_NO_ENOBUFS
    if (setsockopt(nfq_q->fd, SOL_NETLINK,
                   NETLINK_NO_ENOBUFS, &opt, sizeof(int)) == -1) {
        SCLogWarning(SC_ERR_NFQ_SETSOCKOPT,
                     "can't set netlink enobufs: %s",
                     strerror(errno));
    }
#endif

#ifdef HAVE_NFQ_SET_QUEUE_FLAGS
    if (nfq_config.flags & NFQ_FLAG_FAIL_OPEN) {
        uint32_t flags = NFQA_CFG_F_FAIL_OPEN;
        uint32_t mask = NFQA_CFG_F_FAIL_OPEN;
        int r = nfq_set_queue_flags(nfq_q->qh, mask, flags);

        if (r == -1) {
            SCLogWarning(SC_ERR_NFQ_SET_MODE, "can't set fail-open mode: %s",
                         strerror(errno));
        } else {
            SCLogInfo("fail-open mode should be set on queue");
        }
    }
#endif

#ifdef HAVE_NFQ_SET_VERDICT_BATCH
    if (runmode_workers) {
        nfq_q->verdict_cache.maxlen = nfq_config.batchcount;
    } else if (nfq_config.batchcount) {
        SCLogError(SC_ERR_INVALID_ARGUMENT, "nfq.batchcount is only valid in workers runmode.");
    }
#endif

    /* set a timeout to the socket so we can check for a signal
     * in case we don't get packets for a longer period. */
    tv.tv_sec = 1;
    tv.tv_usec = 0;

    if(setsockopt(nfq_q->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
        SCLogWarning(SC_ERR_NFQ_SETSOCKOPT, "can't set socket timeout: %s", strerror(errno));
    }

    SCLogDebug("nfq_q->h %p, nfq_q->nh %p, nfq_q->qh %p, nfq_q->fd %" PRId32 "",
            nfq_q->h, nfq_q->nh, nfq_q->qh, nfq_q->fd);
#else /* OS_WIN32 */
    NFQMutexInit(nfq_q);
    nfq_q->ovr.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    nfq_q->fd = nfq_fd(nfq_q->h);
    SCLogDebug("nfq_q->h %p, nfq_q->qh %p, nfq_q->fd %p", nfq_q->h, nfq_q->qh, nfq_q->fd);
#endif /* OS_WIN32 */

    return TM_ECODE_OK;
}
Example #16
0
int OutputRegisterTxLogger(LoggerId id, const char *name, AppProto alproto,
                           TxLogger LogFunc,
                           OutputCtx *output_ctx, int tc_log_progress,
                           int ts_log_progress, TxLoggerCondition LogCondition,
                           ThreadInitFunc ThreadInit,
                           ThreadDeinitFunc ThreadDeinit,
                           void (*ThreadExitPrintStats)(ThreadVars *, void *))
{
    if (!(AppLayerParserIsTxAware(alproto))) {
        SCLogNotice("%s logger not enabled: protocol %s is disabled",
            name, AppProtoToString(alproto));
        return -1;
    }

    OutputTxLogger *op = SCMalloc(sizeof(*op));
    if (op == NULL)
        return -1;
    memset(op, 0x00, sizeof(*op));

    op->alproto = alproto;
    op->LogFunc = LogFunc;
    op->LogCondition = LogCondition;
    op->output_ctx = output_ctx;
    op->name = name;
    op->logger_id = id;
    op->ThreadInit = ThreadInit;
    op->ThreadDeinit = ThreadDeinit;
    op->ThreadExitPrintStats = ThreadExitPrintStats;

    if (tc_log_progress < 0) {
        op->tc_log_progress =
            AppLayerParserGetStateProgressCompletionStatus(alproto,
                                                           STREAM_TOCLIENT);
    } else {
        op->tc_log_progress = tc_log_progress;
    }

    if (ts_log_progress < 0) {
        op->ts_log_progress =
            AppLayerParserGetStateProgressCompletionStatus(alproto,
                                                           STREAM_TOSERVER);
    } else {
        op->ts_log_progress = ts_log_progress;
    }

    if (list == NULL) {
        op->id = 1;
        list = op;
    } else {
        OutputTxLogger *t = list;
        while (t->next)
            t = t->next;
        if (t->id * 2 > UINT32_MAX) {
            SCLogError(SC_ERR_FATAL, "Too many loggers registered.");
            exit(EXIT_FAILURE);
        }
        op->id = t->id * 2;
        t->next = op;
    }

    SCLogDebug("OutputRegisterTxLogger happy");
    return 0;
}
Example #17
0
TmEcode NoNFQSupportExit(ThreadVars *tv, void *initdata, void **data)
{
    SCLogError(SC_ERR_NFQ_NOSUPPORT,"Error creating thread %s: you do not have support for nfqueue "
           "enabled please recompile with --enable-nfqueue", tv->name);
    exit(EXIT_FAILURE);
}
Example #18
0
static int DetectHttpStatMsgSetup (DetectEngineCtx *de_ctx, Signature *s, char *arg)
{
    DetectContentData *cd = NULL;
    SigMatch *sm = NULL;

    if (arg != NULL && strcmp(arg, "") != 0) {
        SCLogError(SC_ERR_INVALID_ARGUMENT, "http_stat_msg supplied with args");
        return -1;
    }

    sm =  SigMatchGetLastSMFromLists(s, 2,
                                     DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_PMATCH]);
    /* if still we are unable to find any content previous keywords, it is an
     * invalid rule */
    if (sm == NULL) {
        SCLogError(SC_ERR_INVALID_SIGNATURE, "\"http_stat_msg\" keyword "
                   "found inside the rule without a content context.  "
                   "Please use a \"content\" keyword before using the "
                   "\"http_stat_msg\" keyword");
        return -1;
    }

    cd = (DetectContentData *)sm->ctx;

    /* http_stat_msg should not be used with the rawbytes rule */
    if (cd->flags & DETECT_CONTENT_RAWBYTES) {
        SCLogError(SC_ERR_INVALID_SIGNATURE, "http_stat_msg rule can not "
                   "be used with the rawbytes rule keyword");
        return -1;
    }

    if (s->alproto != ALPROTO_UNKNOWN && s->alproto != ALPROTO_HTTP) {
        SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains a non http "
                   "alproto set");
        goto error;
    }

    if (cd->flags & DETECT_CONTENT_WITHIN || cd->flags & DETECT_CONTENT_DISTANCE) {
        SigMatch *pm =  SigMatchGetLastSMFromLists(s, 4,
                                                   DETECT_CONTENT, sm->prev,
                                                   DETECT_PCRE, sm->prev);
        /* pm can be NULL now.  To accomodate parsing sigs like -
         * content:one; http_modifier; content:two; distance:0; http_modifier */
        if (pm != NULL) {
            if (pm->type == DETECT_CONTENT) {
                DetectContentData *tmp_cd = (DetectContentData *)pm->ctx;
                tmp_cd->flags &= ~DETECT_CONTENT_RELATIVE_NEXT;
            } else {
                DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx;
                tmp_pd->flags &= ~ DETECT_PCRE_RELATIVE_NEXT;
            }

        } /* if (pm != NULL) */

        /* reassigning pm */
        pm = SigMatchGetLastSMFromLists(s, 4,
                                        DETECT_CONTENT, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH],
                                        DETECT_PCRE, s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]);
        if (pm == NULL) {
            SCLogError(SC_ERR_INVALID_SIGNATURE, "http_stat_msg seen with a "
                       "distance or within without a previous http_stat_msg "
                       "content.  Invalidating signature.");
            goto error;
        }
        if (pm->type == DETECT_PCRE) {
            DetectPcreData *tmp_pd = (DetectPcreData *)pm->ctx;
            tmp_pd->flags |= DETECT_PCRE_RELATIVE_NEXT;
        } else {
            DetectContentData *tmp_cd = (DetectContentData *)pm->ctx;
            tmp_cd->flags |= DETECT_CONTENT_RELATIVE_NEXT;
        }
    }
    cd->id = DetectPatternGetId(de_ctx->mpm_pattern_id_store, cd, DETECT_SM_LIST_HSMDMATCH);
    sm->type = DETECT_CONTENT;

    /* transfer the sm from the pmatch list to hcbdmatch list */
    SigMatchTransferSigMatchAcrossLists(sm,
                                        &s->sm_lists[DETECT_SM_LIST_PMATCH],
                                        &s->sm_lists_tail[DETECT_SM_LIST_PMATCH],
                                        &s->sm_lists[DETECT_SM_LIST_HSMDMATCH],
                                        &s->sm_lists_tail[DETECT_SM_LIST_HSMDMATCH]);

    /* flag the signature to indicate that we scan the app layer data */
    s->flags |= SIG_FLAG_APPLAYER;
    s->alproto = ALPROTO_HTTP;

    return 0;

error:

    return -1;
}
Example #19
0
/**
 * \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;
}
Example #20
0
static int DetectFlowvarSetup (DetectEngineCtx *de_ctx, Signature *s, char *rawstr)
{
    DetectFlowvarData *cd = NULL;
    SigMatch *sm = NULL;
    char *str = rawstr;
    char dubbed = 0;
    uint16_t len;
    char *varname = NULL, *varcontent = NULL;
#define MAX_SUBSTRINGS 30
    int ret = 0, res = 0;
    int ov[MAX_SUBSTRINGS];

    ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr), 0, 0, ov, MAX_SUBSTRINGS);
    if (ret != 3) {
        SCLogError(SC_ERR_PCRE_MATCH, "\"%s\" is not a valid setting for flowvar.", rawstr);
        return -1;
    }

    const char *str_ptr;
    res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, &str_ptr);
    if (res < 0) {
        SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
        return -1;
    }
    varname = (char *)str_ptr;

    if (ret > 2) {
        res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, &str_ptr);
        if (res < 0) {
            SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
            return -1;
        }
        varcontent = (char *)str_ptr;
    }

    if (varcontent[0] == '\"' && varcontent[strlen(varcontent)-1] == '\"') {
        str = SCStrdup(varcontent+1);
        str[strlen(varcontent)-2] = '\0';
        dubbed = 1;
    }

    len = strlen(str);
    if (len == 0) {
        if (dubbed) SCFree(str);
        return -1;
    }

    cd = SCMalloc(sizeof(DetectFlowvarData));
    if (cd == NULL)
        goto error;

    char converted = 0;

    {
        uint16_t i, x;
        uint8_t bin = 0, binstr[3] = "", binpos = 0;
        for (i = 0, x = 0; i < len; i++) {
            // printf("str[%02u]: %c\n", i, str[i]);
            if (str[i] == '|') {
                if (bin) {
                    bin = 0;
                } else {
                    bin = 1;
                }
            } else {
                if (bin) {
                    if (isdigit(str[i]) ||
                        str[i] == 'A' || str[i] == 'a' ||
                        str[i] == 'B' || str[i] == 'b' ||
                        str[i] == 'C' || str[i] == 'c' ||
                        str[i] == 'D' || str[i] == 'd' ||
                        str[i] == 'E' || str[i] == 'e' ||
                        str[i] == 'F' || str[i] == 'f') {
                        // printf("part of binary: %c\n", str[i]);

                        binstr[binpos] = (char)str[i];
                        binpos++;

                        if (binpos == 2) {
                            uint8_t c = strtol((char *)binstr, (char **) NULL, 16) & 0xFF;
                            binpos = 0;
                            str[x] = c;
                            x++;
                            converted = 1;
                        }
                    } else if (str[i] == ' ') {
                        // printf("space as part of binary string\n");
                    }
                } else {
                    str[x] = str[i];
                    x++;
                }
            }
        }
#ifdef DEBUG
        if (SCLogDebugEnabled()) {
            for (i = 0; i < x; i++) {
                if (isprint(str[i])) printf("%c", str[i]);
                else                 printf("\\x%02u", str[i]);
            }
            printf("\n");
        }
#endif

        if (converted)
            len = x;
    }

    cd->content = SCMalloc(len);
    if (cd->content == NULL) {
        if (dubbed) SCFree(str);
        SCFree(cd);
        return -1;
    }

    cd->name = SCStrdup(varname);
    cd->idx = VariableNameGetIdx(varname,DETECT_FLOWVAR);
    memcpy(cd->content, str, len);
    cd->content_len = len;
    cd->flags = 0;

    /* Okay so far so good, lets get this into a SigMatch
     * and put it in the Signature. */
    sm = SigMatchAlloc();
    if (sm == NULL)
        goto error;

    sm->type = DETECT_FLOWVAR;
    sm->ctx = (void *)cd;

    SigMatchAppendPacket(s, sm);

    if (dubbed) SCFree(str);
    return 0;

error:
    if (dubbed) SCFree(str);
    if (cd) SCFree(cd);
    if (sm) SCFree(sm);
    return -1;
}
TmEcode ReceivePcapFileThreadInit(ThreadVars *tv, void *initdata, void **data)
{
    SCEnter();

    char *tmpbpfstring = NULL;
    char *tmpstring = NULL;

    if (initdata == NULL) {
        SCLogError(SC_ERR_INVALID_ARGUMENT, "error: initdata == NULL");
        SCReturnInt(TM_ECODE_FAILED);
    }

    SCLogInfo("reading pcap file %s", (char *)initdata);

    PcapFileThreadVars *ptv = SCMalloc(sizeof(PcapFileThreadVars));
    if (unlikely(ptv == NULL))
        SCReturnInt(TM_ECODE_FAILED);
    memset(ptv, 0, sizeof(PcapFileThreadVars));

    intmax_t tenant = 0;
    if (ConfGetInt("pcap-file.tenant-id", &tenant) == 1) {
        if (tenant > 0 && tenant < UINT_MAX) {
            ptv->tenant_id = (uint32_t)tenant;
            SCLogInfo("tenant %u", ptv->tenant_id);
        } else {
            SCLogError(SC_ERR_INVALID_ARGUMENT, "tenant out of range");
        }
    }

    char errbuf[PCAP_ERRBUF_SIZE] = "";
    pcap_g.pcap_handle = pcap_open_offline((char *)initdata, errbuf);
    if (pcap_g.pcap_handle == NULL) {
        SCLogError(SC_ERR_FOPEN, "%s\n", errbuf);
        SCFree(ptv);
        if (! RunModeUnixSocketIsActive()) {
            return TM_ECODE_FAILED;
        } else {
            UnixSocketPcapFile(TM_ECODE_FAILED);
            SCReturnInt(TM_ECODE_DONE);
        }
    }

    if (ConfGet("bpf-filter", &tmpbpfstring) != 1) {
        SCLogDebug("could not get bpf or none specified");
    } else {
        SCLogInfo("using bpf-filter \"%s\"", tmpbpfstring);

        if (pcap_compile(pcap_g.pcap_handle, &pcap_g.filter, tmpbpfstring, 1, 0) < 0) {
            SCLogError(SC_ERR_BPF,"bpf compilation error %s",
                    pcap_geterr(pcap_g.pcap_handle));
            SCFree(ptv);
            return TM_ECODE_FAILED;
        }

        if (pcap_setfilter(pcap_g.pcap_handle, &pcap_g.filter) < 0) {
            SCLogError(SC_ERR_BPF,"could not set bpf filter %s", pcap_geterr(pcap_g.pcap_handle));
            SCFree(ptv);
            return TM_ECODE_FAILED;
        }
    }

    pcap_g.datalink = pcap_datalink(pcap_g.pcap_handle);
    SCLogDebug("datalink %" PRId32 "", pcap_g.datalink);

    switch (pcap_g.datalink) {
        case LINKTYPE_LINUX_SLL:
            pcap_g.Decoder = DecodeSll;
            break;
        case LINKTYPE_ETHERNET:
            pcap_g.Decoder = DecodeEthernet;
            break;
        case LINKTYPE_PPP:
            pcap_g.Decoder = DecodePPP;
            break;
        case LINKTYPE_RAW:
            pcap_g.Decoder = DecodeRaw;
            break;
        case LINKTYPE_NULL:
            pcap_g.Decoder = DecodeNull;
            break;

        default:
            SCLogError(SC_ERR_UNIMPLEMENTED, "datalink type %" PRId32 " not "
                      "(yet) supported in module PcapFile.\n", pcap_g.datalink);
            SCFree(ptv);
            if (! RunModeUnixSocketIsActive()) {
                SCReturnInt(TM_ECODE_FAILED);
            } else {
                pcap_close(pcap_g.pcap_handle);
                pcap_g.pcap_handle = NULL;
                UnixSocketPcapFile(TM_ECODE_DONE);
                SCReturnInt(TM_ECODE_DONE);
            }
    }

    if (ConfGet("pcap-file.checksum-checks", &tmpstring) != 1) {
        pcap_g.conf_checksum_mode = CHECKSUM_VALIDATION_AUTO;
    } else {
        if (strcmp(tmpstring, "auto") == 0) {
            pcap_g.conf_checksum_mode = CHECKSUM_VALIDATION_AUTO;
        } else if (strcmp(tmpstring, "yes") == 0) {
            pcap_g.conf_checksum_mode = CHECKSUM_VALIDATION_ENABLE;
        } else if (strcmp(tmpstring, "no") == 0) {
            pcap_g.conf_checksum_mode = CHECKSUM_VALIDATION_DISABLE;
        }
    }
    pcap_g.checksum_mode = pcap_g.conf_checksum_mode;

    ptv->tv = tv;
    *data = (void *)ptv;

    SCReturnInt(TM_ECODE_OK);
}
Example #22
0
/* JSON format logging */
static void JsonFlowLogJSON(JsonFlowLogThread *aft, json_t *js, Flow *f)
{
#if 0
    LogJsonFileCtx *flow_ctx = aft->flowlog_ctx;
#endif
    json_t *hjs = json_object();
    if (hjs == NULL) {
        return;
    }

    json_object_set_new(js, "app_proto",
            json_string(AppProtoToString(f->alproto)));
    if (f->alproto_ts != f->alproto) {
        json_object_set_new(js, "app_proto_ts",
                json_string(AppProtoToString(f->alproto_ts)));
    }
    if (f->alproto_tc != f->alproto) {
        json_object_set_new(js, "app_proto_tc",
                json_string(AppProtoToString(f->alproto_tc)));
    }

    json_object_set_new(hjs, "pkts_toserver",
            json_integer(f->todstpktcnt));
    json_object_set_new(hjs, "pkts_toclient",
            json_integer(f->tosrcpktcnt));
    json_object_set_new(hjs, "bytes_toserver",
            json_integer(f->todstbytecnt));
    json_object_set_new(hjs, "bytes_toclient",
            json_integer(f->tosrcbytecnt));

    char timebuf1[64], timebuf2[64];

    CreateIsoTimeString(&f->startts, timebuf1, sizeof(timebuf1));
    CreateIsoTimeString(&f->lastts, timebuf2, sizeof(timebuf2));

    json_object_set_new(hjs, "start", json_string(timebuf1));
    json_object_set_new(hjs, "end", json_string(timebuf2));

    int32_t age = f->lastts.tv_sec - f->startts.tv_sec;
    json_object_set_new(hjs, "age",
            json_integer(age));

    if (f->flow_end_flags & FLOW_END_FLAG_EMERGENCY)
        json_object_set_new(hjs, "emergency", json_true());
    const char *state = NULL;
    if (f->flow_end_flags & FLOW_END_FLAG_STATE_NEW)
        state = "new";
    else if (f->flow_end_flags & FLOW_END_FLAG_STATE_ESTABLISHED)
        state = "established";
    else if (f->flow_end_flags & FLOW_END_FLAG_STATE_CLOSED)
        state = "closed";
    else if (f->flow_end_flags & FLOW_END_FLAG_STATE_BYPASSED) {
        state = "bypassed";
        int flow_state = SC_ATOMIC_GET(f->flow_state);
        switch (flow_state) {
            case FLOW_STATE_LOCAL_BYPASSED:
                json_object_set_new(hjs, "bypass",
                        json_string("local"));
                break;
            case FLOW_STATE_CAPTURE_BYPASSED:
                json_object_set_new(hjs, "bypass",
                        json_string("capture"));
                break;
            default:
                SCLogError(SC_ERR_INVALID_VALUE,
                           "Invalid flow state: %d, contact developers",
                           flow_state);
        }
    }

    json_object_set_new(hjs, "state",
            json_string(state));

    const char *reason = NULL;
    if (f->flow_end_flags & FLOW_END_FLAG_TIMEOUT)
        reason = "timeout";
    else if (f->flow_end_flags & FLOW_END_FLAG_FORCED)
        reason = "forced";
    else if (f->flow_end_flags & FLOW_END_FLAG_SHUTDOWN)
        reason = "shutdown";

    json_object_set_new(hjs, "reason",
            json_string(reason));

    json_object_set_new(js, "flow", hjs);


    /* TCP */
    if (f->proto == IPPROTO_TCP) {
        json_t *tjs = json_object();
        if (tjs == NULL) {
            return;
        }

        TcpSession *ssn = f->protoctx;

        char hexflags[3];
        snprintf(hexflags, sizeof(hexflags), "%02x",
                ssn ? ssn->tcp_packet_flags : 0);
        json_object_set_new(tjs, "tcp_flags", json_string(hexflags));

        snprintf(hexflags, sizeof(hexflags), "%02x",
                ssn ? ssn->client.tcp_flags : 0);
        json_object_set_new(tjs, "tcp_flags_ts", json_string(hexflags));

        snprintf(hexflags, sizeof(hexflags), "%02x",
                ssn ? ssn->server.tcp_flags : 0);
        json_object_set_new(tjs, "tcp_flags_tc", json_string(hexflags));

        JsonTcpFlags(ssn ? ssn->tcp_packet_flags : 0, tjs);

        if (ssn) {
            char *tcp_state = NULL;
            switch (ssn->state) {
                case TCP_NONE:
                    tcp_state = "none";
                    break;
                case TCP_LISTEN:
                    tcp_state = "listen";
                    break;
                case TCP_SYN_SENT:
                    tcp_state = "syn_sent";
                    break;
                case TCP_SYN_RECV:
                    tcp_state = "syn_recv";
                    break;
                case TCP_ESTABLISHED:
                    tcp_state = "established";
                    break;
                case TCP_FIN_WAIT1:
                    tcp_state = "fin_wait1";
                    break;
                case TCP_FIN_WAIT2:
                    tcp_state = "fin_wait2";
                    break;
                case TCP_TIME_WAIT:
                    tcp_state = "time_wait";
                    break;
                case TCP_LAST_ACK:
                    tcp_state = "last_ack";
                    break;
                case TCP_CLOSE_WAIT:
                    tcp_state = "close_wait";
                    break;
                case TCP_CLOSING:
                    tcp_state = "closing";
                    break;
                case TCP_CLOSED:
                    tcp_state = "closed";
                    break;
            }
            json_object_set_new(tjs, "state", json_string(tcp_state));
        }

        json_object_set_new(js, "tcp", tjs);
    }
}
Example #23
0
/**
* \brief extract information from config file
*
* The returned structure will be freed by the thread init function.
* This is thus necessary to or copy the structure before giving it
* to thread or to reparse the file for each thread (and thus have
* new structure.
*
* \return a 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;
    char *tmpctype;
    char *copymodestr;
    int boolval;
    char *bpf_filter = NULL;
    char *out_iface = NULL;

    if (iface_name == NULL) {
        return NULL;
    }

    NetmapIfaceConfig *aconf = SCMalloc(sizeof(*aconf));
    if (unlikely(aconf == NULL)) {
        return NULL;
    }

    memset(aconf, 0, sizeof(*aconf));
    aconf->DerefFunc = NetmapDerefConfig;
    aconf->threads = 0;
    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");
        goto finalize;
    }

    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);
        goto finalize;
    }

    /* 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 = 0;
    } else {
        if (strcmp(threadsstr, "auto") == 0) {
            aconf->threads = 0;
        } else {
            aconf->threads = (uint8_t)atoi(threadsstr);
        }
    }

    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", &copymodestr) == 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;
        }
    }

    /* 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);
        }
    }

finalize:

    if (aconf->iface_sw) {
        /* just one thread per interface supported */
        aconf->threads = 1;
    } else if (aconf->threads == 0) {
        /* As NetmapGetRSSCount is broken on Linux, first run
         * GetIfaceRSSQueuesNum. If that fails, run NetmapGetRSSCount */
        aconf->threads = GetIfaceRSSQueuesNum(aconf->iface);
        if (aconf->threads == 0) {
            aconf->threads = NetmapGetRSSCount(aconf->iface);
        }
    }
    if (aconf->threads <= 0) {
        aconf->threads = 1;
    }
    SC_ATOMIC_RESET(aconf->ref);
    (void) SC_ATOMIC_ADD(aconf->ref, aconf->threads);
    SCLogPerf("Using %d threads for interface %s", aconf->threads,
            aconf->iface_name);

    return aconf;
}
Example #24
0
/**
 * \brief This function is used to parse icode options passed via icode: keyword
 *
 * \param icodestr Pointer to the user provided icode options
 *
 * \retval icd pointer to DetectICodeData on success
 * \retval NULL on failure
 */
DetectICodeData *DetectICodeParse(char *icodestr) {
    DetectICodeData *icd = 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, icodestr, strlen(icodestr), 0, 0, ov, MAX_SUBSTRINGS);
    if (ret < 1 || ret > 4) {
        SCLogError(SC_ERR_PCRE_MATCH, "pcre_exec parse error, ret %" PRId32 ", string %s", ret, icodestr);
        goto error;
    }

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

    icd = SCMalloc(sizeof(DetectICodeData));
    if (icd == NULL)
        goto error;
    icd->code1 = 0;
    icd->code2 = 0;
    icd->mode = 0;

    /* we have either "<" or ">" */
    if (args[0] != NULL && strlen(args[0]) != 0) {
        /* we have a third part ("<> y"), therefore it's invalid */
        if (args[2] != NULL) {
            SCLogError(SC_ERR_INVALID_VALUE, "icode: invalid value");
            goto error;
        }
        /* we have only a comparison ("<", ">") */
        if (ByteExtractStringUint8(&icd->code1, 10, 0, args[1]) < 0) {
            SCLogError(SC_ERR_INVALID_ARGUMENT, "specified icmp code %s is not "
                                        "valid", args[1]);
            goto error;
        }
        if ((strcmp(args[0], ">")) == 0) icd->mode = DETECT_ICODE_GT;
        else icd->mode = DETECT_ICODE_LT;
    } else { /* no "<", ">" */
        /* we have a range ("<>") */
        if (args[2] != NULL) {
            icd->mode = (uint8_t) DETECT_ICODE_RN;
            if (ByteExtractStringUint8(&icd->code1, 10, 0, args[1]) < 0) {
                SCLogError(SC_ERR_INVALID_ARGUMENT, "specified icmp code %s is not "
                                            "valid", args[1]);
                goto error;
            }
            if (ByteExtractStringUint8(&icd->code2, 10, 0, args[2]) < 0) {
                SCLogError(SC_ERR_INVALID_ARGUMENT, "specified icmp code %s is not "
                                            "valid", args[2]);
                goto error;
            }
            /* we check that the first given value in the range is less than
               the second, otherwise we swap them */
            if (icd->code1 > icd->code2) {
                uint8_t temp = icd->code1;
                icd->code1 = icd->code2;
                icd->code2 = temp;
            }
        } else { /* we have an equality */
            icd->mode = DETECT_ICODE_EQ;
            if (ByteExtractStringUint8(&icd->code1, 10, 0, args[1]) < 0) {
                SCLogError(SC_ERR_INVALID_ARGUMENT, "specified icmp code %s is not "
                                                    "valid", args[1]);
                goto error;
            }
        }
    }

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

error:
    for (i = 0; i < (ret-1) && i < 3; i++) {
        if (args[i] != NULL)
            SCFree(args[i]);
    }
    if (icd != NULL)
        DetectICodeFree(icd);
    return NULL;
}
Example #25
0
static int DetectMsgSetup (DetectEngineCtx *de_ctx, Signature *s, char *msgstr)
{
    char *str = NULL;
    uint16_t len;

    if (strlen(msgstr) == 0)
        goto error;

    /* strip "'s */
    if (msgstr[0] == '\"' && msgstr[strlen(msgstr)-1] == '\"') {
        str = SCStrdup(msgstr+1);
        if (unlikely(str == NULL))
            goto error;
        str[strlen(msgstr)-2] = '\0';
    } else if (msgstr[1] == '\"' && msgstr[strlen(msgstr)-1] == '\"') {
        /* XXX do this parsing in a better way */
        str = SCStrdup(msgstr+2);
        if (unlikely(str == NULL))
            goto error;
        str[strlen(msgstr)-3] = '\0';
        //printf("DetectMsgSetup: format hack applied: \'%s\'\n", str);
    } else {
        SCLogError(SC_ERR_INVALID_VALUE, "format error \'%s\'", msgstr);
        goto error;
    }

    len = strlen(str);
    if (len == 0)
        goto error;

    char converted = 0;

    {
        uint16_t i, x;
        uint8_t escape = 0;

        /* it doesn't matter if we need to escape or not we remove the extra "\" to mimic snort */
        for (i = 0, x = 0; i < len; i++) {
            //printf("str[%02u]: %c\n", i, str[i]);
            if(!escape && str[i] == '\\') {
                escape = 1;
            } else if (escape) {
                if (str[i] != ':' &&
                        str[i] != ';' &&
                        str[i] != '\\' &&
                        str[i] != '\"')
                {
                    SCLogDebug("character \"%c\" does not need to be escaped but is" ,str[i]);
                }
                escape = 0;
                converted = 1;

                str[x] = str[i];
                x++;
            }else{
                str[x] = str[i];
                x++;
            }

        }
#if 0 //def DEBUG
        if (SCLogDebugEnabled()) {
            for (i = 0; i < x; i++) {
                printf("%c", str[i]);
            }
            printf("\n");
        }
#endif

        if (converted) {
            len = x;
            str[len] = '\0';
        }
    }

    s->msg = SCMalloc(len + 1);
    if (s->msg == NULL)
        goto error;

    strlcpy(s->msg, str, len + 1);

    SCFree(str);
    return 0;

error:
    SCFree(str);
    return -1;
}
Example #26
0
DetectTtlData *DetectTtlParse (char *ttlstr) {

    DetectTtlData *ttld = NULL;
    char *arg1 = NULL;
    char *arg2 = NULL;
    char *arg3 = NULL;
#define MAX_SUBSTRINGS 30
    int ret = 0, res = 0;
    int ov[MAX_SUBSTRINGS];

    ret = pcre_exec(parse_regex, parse_regex_study, ttlstr, strlen(ttlstr), 0, 0, ov, MAX_SUBSTRINGS);
    if (ret < 2 || ret > 4) {
        SCLogError(SC_ERR_PCRE_MATCH, "parse error, ret %" PRId32 "", ret);
        goto error;
    }
    const char *str_ptr;

    res = pcre_get_substring((char *) ttlstr, 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);

    if (ret >= 3) {
        res = pcre_get_substring((char *) ttlstr, 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 >= 4) {
            res = pcre_get_substring((char *) ttlstr, 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);
        }
    }

    ttld = SCMalloc(sizeof (DetectTtlData));
    if (unlikely(ttld == NULL))
    goto error;
    ttld->ttl1 = 0;
    ttld->ttl2 = 0;

    if (arg2 != NULL) {
        /*set the values*/
        switch(arg2[0]) {
            case '<':
                if (arg3 == NULL)
                    goto error;

                ttld->mode = DETECT_TTL_LT;
                ttld->ttl1 = (uint8_t) atoi(arg3);

                SCLogDebug("ttl is %"PRIu8"",ttld->ttl1);
                if (strlen(arg1) > 0)
                    goto error;

                break;
            case '>':
                if (arg3 == NULL)
                    goto error;

                ttld->mode = DETECT_TTL_GT;
                ttld->ttl1 = (uint8_t) atoi(arg3);

                SCLogDebug("ttl is %"PRIu8"",ttld->ttl1);
                if (strlen(arg1) > 0)
                    goto error;

                break;
            case '-':
                if (arg1 == NULL || strlen(arg1)== 0)
                    goto error;
                if (arg3 == NULL || strlen(arg3)== 0)
                    goto error;

                ttld->mode = DETECT_TTL_RA;
                ttld->ttl1 = (uint8_t) atoi(arg1);

                ttld->ttl2 = (uint8_t) atoi(arg3);
                SCLogDebug("ttl is %"PRIu8" to %"PRIu8"",ttld->ttl1, ttld->ttl2);
                if (ttld->ttl1 >= ttld->ttl2) {
                    SCLogError(SC_ERR_INVALID_SIGNATURE, "Invalid ttl range. ");
                    goto error;
                }
                break;
            default:
                ttld->mode = DETECT_TTL_EQ;

                if ((arg2 != NULL && strlen(arg2) > 0) || (arg3 != NULL && strlen(arg3) > 0) || (arg1 == NULL ||strlen(arg1) == 0))
                    goto error;

                ttld->ttl1 = (uint8_t) atoi(arg1);
                break;
        }
    } else {
        ttld->mode = DETECT_TTL_EQ;

        if ((arg2 != NULL && strlen(arg2) > 0) ||
                (arg3 != NULL && strlen(arg3) > 0) ||
                (arg1 == NULL ||strlen(arg1) == 0))
            goto error;

        ttld->ttl1 = (uint8_t) atoi(arg1);
    }

    SCFree(arg1);
    SCFree(arg2);
    SCFree(arg3);
    return ttld;

error:
    if (ttld) SCFree(ttld);
    if (arg1) SCFree(arg1);
    if (arg2) SCFree(arg2);
    if (arg3) SCFree(arg3);
    return NULL;
}
Example #27
0
/**
 * \internal
 * \brief Function to parse options passed via tls validity keywords.
 *
 * \param rawstr Pointer to the user provided options.
 *
 * \retval dd pointer to DetectNfsVersionData on success.
 * \retval NULL on failure.
 */
static DetectNfsVersionData *DetectNfsVersionParse (const char *rawstr)
{
    DetectNfsVersionData *dd = NULL;
#define MAX_SUBSTRINGS 30
    int ret = 0, res = 0;
    int ov[MAX_SUBSTRINGS];
    char mode[2] = "";
    char value1[20] = "";
    char value2[20] = "";
    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 = SCCalloc(1, sizeof(DetectNfsVersionData));
    if (unlikely(dd == NULL))
        goto error;

    if (strlen(mode) == 1) {
        if (mode[0] == '<')
            dd->mode = PROCEDURE_LT;
        else if (mode[0] == '>')
            dd->mode = PROCEDURE_GT;
    } else if (strlen(mode) == 2) {
        if (strcmp(mode, "<=") == 0)
            dd->mode = PROCEDURE_LE;
        if (strcmp(mode, ">=") == 0)
            dd->mode = PROCEDURE_GE;
    }

    if (strlen(range) > 0) {
        if (strcmp("<>", range) == 0)
            dd->mode = PROCEDURE_RA;
    }

    if (strlen(range) != 0 && strlen(mode) != 0) {
        SCLogError(SC_ERR_INVALID_ARGUMENT,
                   "Range specified but mode also set");
        goto error;
    }

    if (dd->mode == 0) {
        dd->mode = PROCEDURE_EQ;
    }

    /* set the first value */
    dd->lo = atoi(value1); //TODO

    /* set the second value if specified */
    if (strlen(value2) > 0) {
        if (!(dd->mode == PROCEDURE_RA)) {
            SCLogError(SC_ERR_INVALID_ARGUMENT,
                "Multiple tls validity values specified but mode is not range");
            goto error;
        }

        //
        dd->hi = atoi(value2); // TODO

        if (dd->hi <= dd->lo) {
            SCLogError(SC_ERR_INVALID_ARGUMENT,
                "Second value in range must not be smaller than the first");
            goto error;
        }
    }
    return dd;

error:
    if (dd)
        SCFree(dd);
    return NULL;
}
Example #28
0
/** \brief          To initialize the NFQ global configuration data
 *
 *  \param  quiet   It tells the mode of operation, if it is TRUE nothing will
 *                  be get printed.
 */
void NFQInitConfig(char quiet)
{
    intmax_t value = 0;
    char* nfq_mode = NULL;
    int boolval;

    SCLogDebug("Initializing NFQ");

    memset(&nfq_config,  0, sizeof(nfq_config));

    if ((ConfGet("nfq.mode", &nfq_mode)) == 0) {
        nfq_config.mode = NFQ_ACCEPT_MODE;
    } else {
        if (!strcmp("accept", nfq_mode)) {
            nfq_config.mode = NFQ_ACCEPT_MODE;
        } else if (!strcmp("repeat", nfq_mode)) {
            nfq_config.mode = NFQ_REPEAT_MODE;
        }  else if (!strcmp("route", nfq_mode)) {
            nfq_config.mode = NFQ_ROUTE_MODE;
        } else {
            SCLogError(SC_ERR_INVALID_ARGUMENT, "Unknown nfq.mode");
            exit(EXIT_FAILURE);
        }
    }

    (void)ConfGetBool("nfq.fail-open", (int *)&boolval);
    if (boolval) {
#ifdef HAVE_NFQ_SET_QUEUE_FLAGS
        SCLogInfo("Enabling fail-open on queue");
        nfq_config.flags |= NFQ_FLAG_FAIL_OPEN;
#else
        SCLogError(SC_ERR_NFQ_NOSUPPORT,
                   "nfq.%s set but NFQ library has no support for it.", "fail-open");
#endif
    }

    if ((ConfGetInt("nfq.repeat-mark", &value)) == 1) {
        nfq_config.mark = (uint32_t)value;
    }

    if ((ConfGetInt("nfq.repeat-mask", &value)) == 1) {
        nfq_config.mask = (uint32_t)value;
    }

    if ((ConfGetInt("nfq.route-queue", &value)) == 1) {
        nfq_config.next_queue = ((uint32_t)value) << 16;
    }

    if ((ConfGetInt("nfq.batchcount", &value)) == 1) {
#ifdef HAVE_NFQ_SET_VERDICT_BATCH
        if (value > 255) {
            SCLogWarning(SC_ERR_INVALID_ARGUMENT, "nfq.batchcount cannot exceed 255.");
            value = 255;
        }
        if (value > 1)
            nfq_config.batchcount = (uint8_t) (value - 1);
#else
        SCLogWarning(SC_ERR_NFQ_NOSUPPORT,
                   "nfq.%s set but NFQ library has no support for it.", "batchcount");
#endif
    }

    if (!quiet) {
        switch (nfq_config.mode) {
            case NFQ_ACCEPT_MODE:
                SCLogInfo("NFQ running in standard ACCEPT/DROP mode");
                break;
            case NFQ_REPEAT_MODE:
                SCLogInfo("NFQ running in REPEAT mode with mark %"PRIu32"/%"PRIu32,
                        nfq_config.mark, nfq_config.mask);
                break;
            case NFQ_ROUTE_MODE:
                SCLogInfo("NFQ running in route mode with next queue %"PRIu32,
                        nfq_config.next_queue);
            break;
        }
    }

}
Example #29
0
int RunModeSetIPSWorker(DetectEngineCtx *de_ctx,
        ConfigIPSParserFunc ConfigParser,
        char *recv_mod_name,
        char *verdict_mod_name,
        char *decode_mod_name)
{
    char tname[16];
    ThreadVars *tv = NULL;
    TmModule *tm_module = NULL;
    char *cur_queue = NULL;

    int nqueue = LiveGetDeviceCount();

    for (int i = 0; i < nqueue; i++) {
        /* create the threads */
        cur_queue = LiveGetDeviceName(i);
        if (cur_queue == NULL) {
            printf("ERROR: Invalid queue number\n");
            exit(EXIT_FAILURE);
        }
        memset(tname, 0, sizeof(tname));
        snprintf(tname, sizeof(tname), "Worker-Q%s", cur_queue);

        char *thread_name = SCStrdup(tname);
        tv = TmThreadCreatePacketHandler(thread_name,
                "packetpool", "packetpool",
                "packetpool", "packetpool",
                "pktacqloop");
        if (tv == NULL) {
            SCLogError(SC_ERR_THREAD_CREATE, "TmThreadsCreate failed");
            exit(EXIT_FAILURE);
        }

        tm_module = TmModuleGetByName(recv_mod_name);
        if (tm_module == NULL) {
            SCLogError(SC_ERR_INVALID_VALUE, "TmModuleGetByName failed for %s", recv_mod_name);
            exit(EXIT_FAILURE);
        }
        TmSlotSetFuncAppend(tv, tm_module, (void *) ConfigParser(i));

        tm_module = TmModuleGetByName(decode_mod_name);
        if (tm_module == NULL) {
            SCLogError(SC_ERR_INVALID_VALUE, "TmModuleGetByName %s failed", decode_mod_name);
            exit(EXIT_FAILURE);
        }
        TmSlotSetFuncAppend(tv, tm_module, NULL);

        tm_module = TmModuleGetByName("StreamTcp");
        if (tm_module == NULL) {
            SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName StreamTcp failed");
            exit(EXIT_FAILURE);
        }
        TmSlotSetFuncAppend(tv, tm_module, NULL);

        tm_module = TmModuleGetByName("Detect");
        if (tm_module == NULL) {
            SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName Detect failed");
            exit(EXIT_FAILURE);
        }
        TmSlotSetFuncAppendDelayed(tv, tm_module,
                                   (void *)de_ctx, de_ctx->delayed_detect);

        tm_module = TmModuleGetByName(verdict_mod_name);
        if (tm_module == NULL) {
            SCLogError(SC_ERR_RUNMODE, "TmModuleGetByName %s failed", verdict_mod_name);
            exit(EXIT_FAILURE);
        }

        TmSlotSetFuncAppend(tv, tm_module, (void *)de_ctx);

        tm_module = TmModuleGetByName("RespondReject");
        if (tm_module == NULL) {
            printf("ERROR: TmModuleGetByName for RespondReject failed\n");
            exit(EXIT_FAILURE);
        }
        TmSlotSetFuncAppend(tv, tm_module, NULL);

        SetupOutputs(tv);

        TmThreadSetCPU(tv, DETECT_CPU_SET);

        if (TmThreadSpawn(tv) != TM_ECODE_OK) {
            SCLogError(SC_ERR_RUNMODE, "TmThreadSpawn failed");
            exit(EXIT_FAILURE);
        }
    }

    return 0;
}
Example #30
0
/**
 * \brief Init function for RecievePfring.
 *
 * This is a setup function for recieving packets
 * via libpfring.
 *
 * \param tv pointer to ThreadVars
 * \param initdata pointer to the interface passed from the user
 * \param data pointer gets populated with PfringThreadVars
 * \todo add a config option for setting cluster id
 * \todo Create a general pfring setup function.
 * \retval TM_ECODE_OK on success
 * \retval TM_ECODE_FAILED on error
 */
TmEcode ReceivePfringThreadInit(ThreadVars *tv, const void *initdata, void **data)
{
    int rc;
    u_int32_t version = 0;
    PfringIfaceConfig *pfconf = (PfringIfaceConfig *) initdata;
    unsigned int opflag;
    char const *active_runmode = RunmodeGetActive();

    if (pfconf == NULL)
        return TM_ECODE_FAILED;

    PfringThreadVars *ptv = SCMalloc(sizeof(PfringThreadVars));
    if (unlikely(ptv == NULL)) {
        pfconf->DerefFunc(pfconf);
        return TM_ECODE_FAILED;
    }
    memset(ptv, 0, sizeof(PfringThreadVars));

    ptv->tv = tv;
    ptv->threads = 1;

    ptv->interface = SCStrdup(pfconf->iface);
    if (unlikely(ptv->interface == NULL)) {
        SCLogError(SC_ERR_MEM_ALLOC, "Unable to allocate device string");
        SCFree(ptv);
        SCReturnInt(TM_ECODE_FAILED);
    }

    ptv->livedev = LiveGetDevice(pfconf->iface);
    if (ptv->livedev == NULL) {
        SCLogError(SC_ERR_INVALID_VALUE, "Unable to find Live device");
        SCFree(ptv);
        SCReturnInt(TM_ECODE_FAILED);
    }

    /* enable zero-copy mode for workers runmode */
    if (active_runmode && strcmp("workers", active_runmode) == 0) {
        ptv->flags |= PFRING_FLAGS_ZERO_COPY;
        SCLogPerf("Enabling zero-copy for %s", ptv->interface);
    }

    ptv->checksum_mode = pfconf->checksum_mode;

    opflag = PF_RING_PROMISC;

    /* if suri uses VLAN and if we have a recent kernel, we need
     * to use parsed_pkt to get VLAN info */
    if ((! ptv->vlan_disabled) && SCKernelVersionIsAtLeast(3, 0)) {
        opflag |= PF_RING_LONG_HEADER;
    }

    if (ptv->checksum_mode == CHECKSUM_VALIDATION_RXONLY) {
        if (strncmp(ptv->interface, "dna", 3) == 0) {
            SCLogWarning(SC_ERR_INVALID_VALUE,
                         "Can't use rxonly checksum-checks on DNA interface,"
                         " resetting to auto");
            ptv->checksum_mode = CHECKSUM_VALIDATION_AUTO;
        } else {
            opflag |= PF_RING_LONG_HEADER;
        }
    }

#ifdef HAVE_PF_RING_FLOW_OFFLOAD
    if (pfconf->flags & PFRING_CONF_FLAGS_BYPASS) {
        opflag |= PF_RING_FLOW_OFFLOAD | PF_RING_FLOW_OFFLOAD_NOUPDATES;
        ptv->flags |= PFRING_FLAGS_BYPASS;
    }
#endif

    ptv->pd = pfring_open(ptv->interface, (uint32_t)default_packet_size, opflag);
    if (ptv->pd == NULL) {
        SCLogError(SC_ERR_PF_RING_OPEN,"Failed to open %s: pfring_open error."
                " Check if %s exists and pf_ring module is loaded.",
                ptv->interface,
                ptv->interface);
        pfconf->DerefFunc(pfconf);
        SCFree(ptv);
        return TM_ECODE_FAILED;
    }

    pfring_set_application_name(ptv->pd, (char *)PROG_NAME);
    pfring_version(ptv->pd, &version);

    /* We only set cluster info if the number of pfring threads is greater than 1 */
    ptv->threads = pfconf->threads;

    ptv->cluster_id = pfconf->cluster_id;

    if ((ptv->threads == 1) && (strncmp(ptv->interface, "dna", 3) == 0)) {
        SCLogInfo("DNA interface detected, not adding thread to cluster");
    } else if (strncmp(ptv->interface, "zc", 2) == 0) {
        SCLogInfo("ZC interface detected, not adding thread to cluster");
    } else {
        ptv->ctype = (cluster_type)pfconf->ctype;
        rc = pfring_set_cluster(ptv->pd, ptv->cluster_id, ptv->ctype);

        if (rc != 0) {
            SCLogError(SC_ERR_PF_RING_SET_CLUSTER_FAILED, "pfring_set_cluster "
                    "returned %d for cluster-id: %d", rc, ptv->cluster_id);
            if (rc != PF_RING_ERROR_NOT_SUPPORTED || (pfconf->flags & PFRING_CONF_FLAGS_CLUSTER)) {
                /* cluster is mandatory as explicitly specified in the configuration */
                pfconf->DerefFunc(pfconf);
                return TM_ECODE_FAILED;
            }
        }
    }

    if (ptv->threads > 1) {
        SCLogPerf("(%s) Using PF_RING v.%d.%d.%d, interface %s, cluster-id %d",
                tv->name, (version & 0xFFFF0000) >> 16, (version & 0x0000FF00) >> 8,
                version & 0x000000FF, ptv->interface, ptv->cluster_id);
    } else {