Beispiel #1
0
static StreamMsg *StreamMsgDequeue (StreamMsgQueue *q)
{
    SCEnter();

    /* if the queue is empty there are no packets left.
     * In that case we sleep and try again. */
    if (q->len == 0) {
        SCReturnPtr(NULL, "StreamMsg");
    }

    /* pull the bottom packet from the queue */
    StreamMsg *s = q->bot;

    /* more packets in queue */
    if (q->bot->prev != NULL) {
        q->bot = q->bot->prev;
        q->bot->next = NULL;
        /* just the one we remove, so now empty */
    } else {
        q->top = NULL;
        q->bot = NULL;
    }
    q->len--;

    s->next = NULL;
    s->prev = NULL;
    SCReturnPtr(s, "StreamMsg");
}
Beispiel #2
0
void *PoolGet(Pool *p) {
    SCEnter();

    PoolBucket *pb = p->alloc_list;
    if (pb != NULL) {
        /* pull from the alloc list */
        p->alloc_list = pb->next;
        p->alloc_list_size--;

        /* put in the empty list */
        pb->next = p->empty_list;
        p->empty_list = pb;
        p->empty_list_size++;
    } else {
        if (p->max_buckets == 0 || p->allocated < p->max_buckets) {
            SCLogDebug("max_buckets %"PRIu32"", p->max_buckets);
            p->allocated++;

            p->outstanding++;
            if (p->outstanding > p->max_outstanding)
                p->max_outstanding = p->outstanding;

            SCReturnPtr(p->Alloc(p->AllocData), "void");
        } else {
            SCReturnPtr(NULL, "void");
        }
    }

    void *ptr = pb->data;
    pb->data = NULL;
    p->outstanding++;
    if (p->outstanding > p->max_outstanding)
        p->max_outstanding = p->outstanding;
    SCReturnPtr(ptr,"void");
}
Beispiel #3
0
/**
 *  \brief Setup a pseudo packet (reassembled frags)
 *
 *  Difference with PacketPseudoPktSetup is that this func doesn't increment
 *  the recursion level. It needs to be on the same level as the frags because
 *  we run the flow engine against this and we need to get the same flow.
 *
 *  \param parent parent packet for this pseudo pkt
 *  \param pkt raw packet data
 *  \param len packet data length
 *  \param proto protocol of the tunneled packet
 *
 *  \retval p the pseudo packet or NULL if out of memory
 */
Packet *PacketDefragPktSetup(Packet *parent, uint8_t *pkt, uint16_t len, uint8_t proto)
{
    SCEnter();

    /* get us a packet */
    Packet *p = PacketGetFromQueueOrAlloc();
    if (unlikely(p == NULL)) {
        SCReturnPtr(NULL, "Packet");
    }

    /* set the root ptr to the lowest layer */
    if (parent->root != NULL)
        p->root = parent->root;
    else
        p->root = parent;

    /* copy packet and set lenght, proto */
    PacketCopyData(p, pkt, len);
    p->recursion_level = parent->recursion_level; /* NOT incremented */
    p->ts.tv_sec = parent->ts.tv_sec;
    p->ts.tv_usec = parent->ts.tv_usec;
    p->datalink = DLT_RAW;
    /* tell new packet it's part of a tunnel */
    SET_TUNNEL_PKT(p);
    p->vlan_id[0] = parent->vlan_id[0];
    p->vlan_id[1] = parent->vlan_id[1];
    p->vlan_idx = parent->vlan_idx;

    SCReturnPtr(p, "Packet");
}
static inline DetectThresholdEntry *DetectThresholdEntryAlloc(DetectThresholdData *td, Packet *p, Signature *s) {
    SCEnter();

    DetectThresholdEntry *ste = SCMalloc(sizeof(DetectThresholdEntry));
    if (ste == NULL) {
        SCReturnPtr(NULL, "DetectThresholdEntry");
    }

    if (PKT_IS_IPV4(p))
        ste->ipv = 4;
    else if (PKT_IS_IPV6(p))
        ste->ipv = 6;

    ste->sid = s->id;
    ste->gid = s->gid;

    if (td->track == TRACK_DST) {
        COPY_ADDRESS(&p->dst, &ste->addr);
    } else if (td->track == TRACK_SRC) {
        COPY_ADDRESS(&p->src, &ste->addr);
    }

    ste->track = td->track;
    ste->seconds = td->seconds;
    ste->tv_timeout = 0;

    SCReturnPtr(ste, "DetectThresholdEntry");
}
Beispiel #5
0
/**
 *  \brief Setup a pseudo packet (tunnel)
 *
 *  \param parent parent packet for this pseudo pkt
 *  \param pkt raw packet data
 *  \param len packet data length
 *  \param proto protocol of the tunneled packet
 *
 *  \retval p the pseudo packet or NULL if out of memory
 */
Packet *PacketTunnelPktSetup(ThreadVars *tv, DecodeThreadVars *dtv, Packet *parent,
                             uint8_t *pkt, uint16_t len, enum DecodeTunnelProto proto,
                             PacketQueue *pq)
{
    int ret;

    SCEnter();

    /* get us a packet */
    Packet *p = PacketGetFromQueueOrAlloc();
    if (unlikely(p == NULL)) {
        SCReturnPtr(NULL, "Packet");
    }

    /* copy packet and set lenght, proto */
    PacketCopyData(p, pkt, len);
    p->recursion_level = parent->recursion_level + 1;
    p->ts.tv_sec = parent->ts.tv_sec;
    p->ts.tv_usec = parent->ts.tv_usec;
    p->datalink = DLT_RAW;
    p->tenant_id = parent->tenant_id;

    /* set the root ptr to the lowest layer */
    if (parent->root != NULL)
        p->root = parent->root;
    else
        p->root = parent;

    /* tell new packet it's part of a tunnel */
    SET_TUNNEL_PKT(p);

    ret = DecodeTunnel(tv, dtv, p, GET_PKT_DATA(p),
                       GET_PKT_LEN(p), pq, proto);

    if (unlikely(ret != TM_ECODE_OK)) {
        /* Not a tunnel packet, just a pseudo packet */
        p->root = NULL;
        UNSET_TUNNEL_PKT(p);
        TmqhOutputPacketpool(tv, p);
        SCReturnPtr(NULL, "Packet");
    }


    /* tell parent packet it's part of a tunnel */
    SET_TUNNEL_PKT(parent);

    /* increment tunnel packet refcnt in the root packet */
    TUNNEL_INCR_PKT_TPR(p);

    /* disable payload (not packet) inspection on the parent, as the payload
     * is the packet we will now run through the system separately. We do
     * check it against the ip/port/other header checks though */
    DecodeSetNoPayloadInspectionFlag(parent);
    SCReturnPtr(p, "Packet");
}
void *AppLayerParserGetProtocolParserLocalStorage(uint8_t ipproto, AppProto alproto)
{
    SCEnter();

    if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].
        LocalStorageAlloc != NULL)
    {
        SCReturnPtr(alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].
                    LocalStorageAlloc(), "void *");
    }

    SCReturnPtr(NULL, "void *");
}
/**
 * \brief Search for a threshold data into threshold hash table
 *
 * \param de_ctx Dectection Context
 * \param tsh_ptr Threshold element
 * \param p Packet structure
 *
 * \retval lookup_tsh Return the threshold element
 */
DetectThresholdEntry *ThresholdHashSearch(DetectEngineCtx *de_ctx, DetectThresholdEntry *tsh_ptr, Packet *p)
{
    SCEnter();

    DetectThresholdEntry *lookup_tsh = NULL;

    SCLogDebug("tsh_ptr->track %u", tsh_ptr->track);

    if (tsh_ptr->track == TRACK_DST) {
        if (PKT_IS_IPV4(p)) {
            SCLogDebug("ipv4 dst");
            lookup_tsh = HashListTableLookup(de_ctx->ths_ctx.threshold_hash_table_dst, tsh_ptr, sizeof(DetectThresholdEntry));
        } else if (PKT_IS_IPV6(p)) {
            lookup_tsh = HashListTableLookup(de_ctx->ths_ctx.threshold_hash_table_dst_ipv6, tsh_ptr, sizeof(DetectThresholdEntry));
        }
    } else if (tsh_ptr->track == TRACK_SRC) {
        if (PKT_IS_IPV4(p)) {
            SCLogDebug("ipv4 src");
            lookup_tsh = HashListTableLookup(de_ctx->ths_ctx.threshold_hash_table_src, tsh_ptr, sizeof(DetectThresholdEntry));
        } else if (PKT_IS_IPV6(p))
            lookup_tsh = HashListTableLookup(de_ctx->ths_ctx.threshold_hash_table_src_ipv6, tsh_ptr, sizeof(DetectThresholdEntry));
    } else {
        SCLogDebug("no track, weird");
    }

    SCReturnPtr(lookup_tsh, "DetectThresholdEntry");
}
Beispiel #8
0
DetectEngineState *AppLayerParserGetTxDetectState(uint8_t ipproto, AppProto alproto, void *tx)
{
    SCEnter();
    DetectEngineState *s;
    s = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].GetTxDetectState(tx);
    SCReturnPtr(s, "DetectEngineState");
}
Beispiel #9
0
AppLayerParserThreadCtx *AppLayerParserThreadCtxAlloc(void)
{
    SCEnter();

    AppProto alproto = 0;
    int flow_proto = 0;
    AppLayerParserThreadCtx *tctx;

    tctx = SCMalloc(sizeof(*tctx));
    if (tctx == NULL)
        goto end;
    memset(tctx, 0, sizeof(*tctx));

    for (flow_proto = 0; flow_proto < FLOW_PROTO_DEFAULT; flow_proto++) {
        for (alproto = 0; alproto < ALPROTO_MAX; alproto++) {
            uint8_t ipproto = FlowGetReverseProtoMapping(flow_proto);

            tctx->alproto_local_storage[flow_proto][alproto] =
                AppLayerParserGetProtocolParserLocalStorage(ipproto, alproto);
        }
    }

 end:
    SCReturnPtr(tctx, "void *");
}
AppLayerDecoderEvents *AppLayerParserGetDecoderEvents(AppLayerParserState *pstate)
{
    SCEnter();

    SCReturnPtr(pstate->decoder_events,
                "AppLayerDecoderEvents *");
}
Beispiel #11
0
void *AppLayerParserGetTx(uint8_t ipproto, AppProto alproto, void *alstate, uint64_t tx_id)
{
    SCEnter();
    void * r = NULL;
    r = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].
                StateGetTx(alstate, tx_id);
    SCReturnPtr(r, "void *");
}
static inline DetectThresholdEntry *DetectThresholdEntryAlloc(DetectThresholdData *td, Packet *p, uint32_t sid, uint32_t gid) {
    SCEnter();

    DetectThresholdEntry *ste = SCMalloc(sizeof(DetectThresholdEntry));
    if (unlikely(ste == NULL)) {
        SCReturnPtr(NULL, "DetectThresholdEntry");
    }

    ste->sid = sid;
    ste->gid = gid;

    ste->track = td->track;
    ste->seconds = td->seconds;
    ste->tv_timeout = 0;

    SCReturnPtr(ste, "DetectThresholdEntry");
}
/**
 * \brief Used to lookup a SigGroupHead hash from the detection engine context
 *        SigGroupHead hash table.
 *
 * \param de_ctx Pointer to the detection engine context.
 * \param sgh    Pointer to the SigGroupHead.
 *
 * \retval rsgh On success a pointer to the SigGroupHead if the SigGroupHead is
 *              found in the hash table; NULL on failure.
 */
SigGroupHead *SigGroupHeadHashLookup(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
{
    SCEnter();

    SigGroupHead *rsgh = HashListTableLookup(de_ctx->sgh_hash_table,
                                             (void *)sgh, 0);

    SCReturnPtr(rsgh, "SigGroupHead");
}
/** \brief Function to allocates the Test protocol state memory
 */
static void *TestProtocolStateAlloc(void)
{
    SCEnter();
    void *s = SCMalloc(sizeof(TestState));
    if (unlikely(s == NULL))
        goto end;
    memset(s, 0, sizeof(TestState));
 end:
    SCReturnPtr(s, "TestState");
}
Beispiel #15
0
/**
 * \brief Basic search improved. Limits are better handled, so
 * it doesn't start searches that wont fit in the remaining buffer
 *
 * \param haystack pointer to the buffer to search in
 * \param haystack_len length limit of the buffer
 * \param neddle pointer to the pattern we ar searching for
 * \param needle_len length limit of the needle
 *
 * \retval ptr to start of the match; NULL if no match
 */
uint8_t *BasicSearch(const uint8_t *haystack, uint32_t haystack_len, const uint8_t *needle, uint32_t needle_len) {
    SCEnter();

    const uint8_t *h, *n;
    const uint8_t *hmax = haystack + haystack_len;
    const uint8_t *nmax = needle + needle_len;

    if (needle_len == 0 || needle_len > haystack_len) {
        SCReturnPtr(NULL, "uint8_t");
    }

    //PrintRawDataFp(stdout,needle,needle_len);

    //PrintRawDataFp(stdout,haystack,haystack_len);

    for (n = needle; nmax - n <= hmax - haystack; haystack++) {
        if (*haystack != *n) {
            continue;
        }

        SCLogDebug("*haystack == *n, %c == %c", *haystack, *n);

        /* one byte needles */
        if (needle_len == 1) {
            SCReturnPtr((uint8_t *)haystack, "uint8_t");
        }

        for (h = haystack+1, n++; nmax - n <= hmax - haystack; h++, n++) {
            if (*h != *n) {
                break;
            }
            SCLogDebug("*haystack == *n, %c == %c", *haystack, *n);
            /* if we run out of needle we fully matched */
            if (n == nmax - 1) {
                SCReturnPtr((uint8_t *)haystack, "uint8_t");
            }
        }
        n = needle;
    }

    SCReturnPtr(NULL, "uint8_t");
}
AppLayerParserState *AppLayerParserStateAlloc(void)
{
    SCEnter();

    AppLayerParserState *pstate = (AppLayerParserState *)SCMalloc(sizeof(*pstate));
    if (pstate == NULL)
        goto end;
    memset(pstate, 0, sizeof(*pstate));

 end:
    SCReturnPtr(pstate, "AppLayerParserState");
}
Beispiel #17
0
/** \brief Create a new http log LogFilestoreCtx.
 *  \param conf Pointer to ConfNode containing this loggers configuration.
 *  \return NULL if failure, LogFilestoreCtx* to the file_ctx if succesful
 * */
static OutputCtx *LogFilestoreLogInitCtx(ConfNode *conf)
{
    LogFileCtx *logfile_ctx = LogFileNewCtx();
    if (logfile_ctx == NULL) {
        SCLogDebug("Could not create new LogFilestoreCtx");
        return NULL;
    }

    OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx));
    if (unlikely(output_ctx == NULL))
        return NULL;

    output_ctx->data = NULL;
    output_ctx->DeInit = LogFilestoreLogDeInitCtx;

    char *s_default_log_dir = NULL;
    s_default_log_dir = ConfigGetLogDirectory();

    const char *s_base_dir = NULL;
    s_base_dir = ConfNodeLookupChildValue(conf, "log-dir");
    if (s_base_dir == NULL || strlen(s_base_dir) == 0) {
        strlcpy(g_logfile_base_dir,
                s_default_log_dir, sizeof(g_logfile_base_dir));
    } else {
        if (PathIsAbsolute(s_base_dir)) {
            strlcpy(g_logfile_base_dir,
                    s_base_dir, sizeof(g_logfile_base_dir));
        } else {
            snprintf(g_logfile_base_dir, sizeof(g_logfile_base_dir),
                    "%s/%s", s_default_log_dir, s_base_dir);
        }
    }

    const char *force_magic = ConfNodeLookupChildValue(conf, "force-magic");
    if (force_magic != NULL && ConfValIsTrue(force_magic)) {
        FileForceMagicEnable();
        SCLogInfo("forcing magic lookup for stored files");
    }

    const char *force_md5 = ConfNodeLookupChildValue(conf, "force-md5");
    if (force_md5 != NULL && ConfValIsTrue(force_md5)) {
#ifdef HAVE_NSS
        FileForceMd5Enable();
        SCLogInfo("forcing md5 calculation for stored files");
#else
        SCLogInfo("md5 calculation requires linking against libnss");
#endif
    }
    SCLogInfo("storing files in %s", g_logfile_base_dir);

    SCReturnPtr(output_ctx, "OutputCtx");
}
Beispiel #18
0
/**
 *  \brief Setup a pseudo packet (tunnel)
 *
 *  \param parent parent packet for this pseudo pkt
 *  \param pkt raw packet data
 *  \param len packet data length
 *  \param proto protocol of the tunneled packet
 *
 *  \retval p the pseudo packet or NULL if out of memory
 */
Packet *PacketPseudoPktSetup(Packet *parent, uint8_t *pkt, uint16_t len, uint8_t proto)
{
    SCEnter();

    /* get us a packet */
    Packet *p = PacketGetFromQueueOrAlloc();
    if (p == NULL) {
        SCReturnPtr(NULL, "Packet");
    }

    /* set the root ptr to the lowest layer */
    if (parent->root != NULL)
        p->root = parent->root;
    else
        p->root = parent;

    /* copy packet and set lenght, proto */
    PacketCopyData(p, pkt, len);
    p->recursion_level = parent->recursion_level + 1;
    p->ts.tv_sec = parent->ts.tv_sec;
    p->ts.tv_usec = parent->ts.tv_usec;
    p->datalink = DLT_RAW;

    /* set tunnel flags */

    /* tell new packet it's part of a tunnel */
    SET_TUNNEL_PKT(p);
    /* tell parent packet it's part of a tunnel */
    SET_TUNNEL_PKT(parent);

    /* increment tunnel packet refcnt in the root packet */
    TUNNEL_INCR_PKT_TPR(p);

    /* disable payload (not packet) inspection on the parent, as the payload
     * is the packet we will now run through the system separately. We do
     * check it against the ip/port/other header checks though */
    DecodeSetNoPayloadInspectionFlag(parent);
    SCReturnPtr(p, "Packet");
}
FileContainer *AppLayerParserGetFiles(uint8_t ipproto, AppProto alproto,
                           void *alstate, uint8_t direction)
{
    SCEnter();

    FileContainer *ptr = NULL;

    if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].
        StateGetFiles != NULL)
    {
        ptr = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].
            StateGetFiles(alstate, direction);
    }

    SCReturnPtr(ptr, "FileContainer *");
}
AppLayerDecoderEvents *AppLayerParserGetEventsByTx(uint8_t ipproto, AppProto alproto,
                                        void *alstate, uint64_t tx_id)
{
    SCEnter();

    AppLayerDecoderEvents *ptr = NULL;

    if (alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].
        StateGetEvents != NULL)
    {
        ptr = alp_ctx.ctxs[FlowGetProtoMapping(ipproto)][alproto].
            StateGetEvents(alstate, tx_id);
    }

    SCReturnPtr(ptr, "AppLayerDecoderEvents *");
}
Beispiel #21
0
/**
 *  \brief Find the magic value for a buffer.
 *
 *  \param buf the buffer
 *  \param buflen length of the buffer
 *
 *  \retval result pointer to null terminated string
 */
char *MagicThreadLookup(magic_t *ctx, uint8_t *buf, uint32_t buflen)
{
    const char *result = NULL;
    char *magic = NULL;

    if (buf != NULL && buflen > 0) {
        result = magic_buffer(*ctx, (void *)buf, (size_t)buflen);
        if (result != NULL) {
            magic = SCStrdup(result);
            if (unlikely(magic == NULL)) {
                SCLogError(SC_ERR_MEM_ALLOC, "Unable to dup magic");
            }
        }
    }

    SCReturnPtr(magic, "const char");
}
Beispiel #22
0
/** \brief Create a new http log LogFileCtx.
 *  \param conf Pointer to ConfNode containing this loggers configuration.
 *  \return NULL if failure, LogFileCtx* to the file_ctx if succesful
 * */
static OutputCtx *LogFileLogInitCtx(ConfNode *conf)
{
    LogFileCtx *logfile_ctx = LogFileNewCtx();
    if (logfile_ctx == NULL) {
        SCLogDebug("Could not create new LogFileCtx");
        return NULL;
    }

    if (SCConfLogOpenGeneric(conf, logfile_ctx, DEFAULT_LOG_FILENAME, 1) < 0) {
        LogFileFreeCtx(logfile_ctx);
        return NULL;
    }

    OutputCtx *output_ctx = SCCalloc(1, sizeof(OutputCtx));
    if (unlikely(output_ctx == NULL))
        return NULL;

    output_ctx->data = logfile_ctx;
    output_ctx->DeInit = LogFileLogDeInitCtx;

    const char *force_filestore = ConfNodeLookupChildValue(conf, "force-filestore");
    if (force_filestore != NULL && ConfValIsTrue(force_filestore)) {
        FileForceFilestoreEnable();
        SCLogInfo("forcing filestore of all files");
    }

    const char *force_magic = ConfNodeLookupChildValue(conf, "force-magic");
    if (force_magic != NULL && ConfValIsTrue(force_magic)) {
        FileForceMagicEnable();
        SCLogInfo("forcing magic lookup for logged files");
    }

    const char *force_md5 = ConfNodeLookupChildValue(conf, "force-md5");
    if (force_md5 != NULL && ConfValIsTrue(force_md5)) {
#ifdef HAVE_NSS
        FileForceMd5Enable();
        SCLogInfo("forcing md5 calculation for logged files");
#else
        SCLogInfo("md5 calculation requires linking against libnss");
#endif
    }

    FileForceTrackingEnable();
    SCReturnPtr(output_ctx, "OutputCtx");
}
Beispiel #23
0
/**
 *  \brief Find the magic value for a buffer.
 *
 *  \param buf the buffer
 *  \param buflen length of the buffer
 *
 *  \retval result pointer to null terminated string
 */
char *MagicGlobalLookup(uint8_t *buf, uint32_t buflen)
{
    const char *result = NULL;
    char *magic = NULL;

    SCMutexLock(&g_magic_lock);

    if (buf != NULL && buflen > 0) {
        result = magic_buffer(g_magic_ctx, (void *)buf, (size_t)buflen);
        if (result != NULL) {
            magic = SCStrdup(result);
            if (unlikely(magic == NULL)) {
                SCLogError(SC_ERR_MEM_ALLOC, "Unable to dup magic");
            }
        }
    }

    SCMutexUnlock(&g_magic_lock);
    SCReturnPtr(magic, "const char");
}
AppLayerParserThreadCtx *AppLayerParserThreadCtxAlloc(void)
{
    SCEnter();

    AppProto i = 0;
    int j = 0;
    AppLayerParserThreadCtx *tctx;

    tctx = SCMalloc(sizeof(*tctx));
    if (tctx == NULL)
        goto end;
    memset(tctx, 0, sizeof(*tctx));

    for (i = 0; i < FLOW_PROTO_DEFAULT; i++) {
        for (j = 0; j < ALPROTO_MAX; j++) {
            tctx->alproto_local_storage[i][j] =
                AppLayerParserGetProtocolParserLocalStorage(FlowGetReverseProtoMapping(i), j);
        }
    }

 end:
    SCReturnPtr(tctx, "void *");
}
Beispiel #25
0
static InspectionBuffer *DnsQueryGetData(DetectEngineThreadCtx *det_ctx,
        const DetectEngineTransforms *transforms,
        Flow *f, struct DnsQueryGetDataArgs *cbdata, int list_id, bool first)
{
    SCEnter();

    InspectionBufferMultipleForList *fb = InspectionBufferGetMulti(det_ctx, list_id);
    InspectionBuffer *buffer = InspectionBufferMultipleForListGet(fb, cbdata->local_id);
    if (buffer == NULL)
        return NULL;
    if (!first && buffer->inspect != NULL)
        return buffer;

    const uint8_t *data;
    uint32_t data_len;
    if (rs_dns_tx_get_query_name(cbdata->txv, (uint16_t)cbdata->local_id,
                (uint8_t **)&data, &data_len) == 0) {
        return NULL;
    }
    InspectionBufferSetup(buffer, data, data_len);
    InspectionBufferApplyTransforms(buffer, transforms);

    SCReturnPtr(buffer, "InspectionBuffer");
}
Beispiel #26
0
/** \internal
 *
 * \brief This function is used to parse Modbus parameters in function mode
 *
 * \param str Pointer to the user provided id option
 *
 * \retval id_d pointer to DetectModbusData on success
 * \retval NULL on failure
 */
static DetectModbus *DetectModbusFunctionParse(char *str)
{
    SCEnter();
    DetectModbus *modbus = NULL;

    char    arg[MAX_SUBSTRINGS], *ptr = arg;
    int     ov[MAX_SUBSTRINGS], res, ret;

    ret = pcre_exec(function_parse_regex, function_parse_regex_study, str, strlen(str), 0, 0, ov, MAX_SUBSTRINGS);

    if (ret < 1)
        goto error;

    res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 1, arg, MAX_SUBSTRINGS);
    if (res < 0) {
        SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
        goto error;
    }

    /* We have a correct Modbus function option */
    modbus = (DetectModbus *) SCCalloc(1, sizeof(DetectModbus));
    if (unlikely(modbus == NULL))
        goto error;

    if (isdigit(ptr[0])) {
        modbus->function = atoi((const char*) ptr);
        SCLogDebug("will look for modbus function %d", modbus->function);

        if (ret > 2) {
            res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 3, arg, MAX_SUBSTRINGS);
            if (res < 0) {
                SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
                goto error;
            }

            /* We have a correct address option */
            modbus->subfunction =(uint16_t *) SCCalloc(1, sizeof(uint16_t));
            if (modbus->subfunction == NULL)
                goto error;

            *(modbus->subfunction) = atoi((const char*) arg);
            SCLogDebug("and subfunction %d", *(modbus->subfunction));
        }
    } else {
        uint8_t neg = 0;

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

        if (strcmp("assigned", ptr) == 0)
            modbus->category = MODBUS_CAT_PUBLIC_ASSIGNED;
        else if (strcmp("unassigned", ptr) == 0)
            modbus->category = MODBUS_CAT_PUBLIC_UNASSIGNED;
        else if (strcmp("public", ptr) == 0)
            modbus->category = MODBUS_CAT_PUBLIC_ASSIGNED | MODBUS_CAT_PUBLIC_UNASSIGNED;
        else if (strcmp("user", ptr) == 0)
            modbus->category = MODBUS_CAT_USER_DEFINED;
        else if (strcmp("reserved", ptr) == 0)
            modbus->category = MODBUS_CAT_RESERVED;
        else if (strcmp("all", ptr) == 0)
            modbus->category = MODBUS_CAT_ALL;

        if (neg)
            modbus->category = ~modbus->category;
        SCLogDebug("will look for modbus category function %d", modbus->category);
    }

    SCReturnPtr(modbus, "DetectModbusFunction");

error:
    if (modbus != NULL)
        DetectModbusFree(modbus);

    SCReturnPtr(NULL, "DetectModbus");
}
Beispiel #27
0
/** \internal
 *
 * \brief This function is used to parse Modbus parameters in access mode
 *
 * \param str Pointer to the user provided id option
 *
 * \retval Pointer to DetectModbusData on success or NULL on failure
 */
static DetectModbus *DetectModbusAccessParse(char *str)
{
    SCEnter();
    DetectModbus *modbus = NULL;

    char    arg[MAX_SUBSTRINGS];
    int     ov[MAX_SUBSTRINGS], ret, res;

    ret = pcre_exec(access_parse_regex, access_parse_regex_study, str, strlen(str), 0, 0, ov, MAX_SUBSTRINGS);

    if (ret < 1)
        goto error;

    res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 1, arg, MAX_SUBSTRINGS);
    if (res < 0) {
        SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
        goto error;
    }

    /* We have a correct Modbus option */
    modbus = (DetectModbus *) SCCalloc(1, sizeof(DetectModbus));
    if (unlikely(modbus == NULL))
        goto error;

    if (strcmp(arg, "read") == 0)
        modbus->type = MODBUS_TYP_READ;
    else if (strcmp(arg, "write") == 0)
        modbus->type = MODBUS_TYP_WRITE;
    else
        goto error;

    if (ret > 2) {
        res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 2, arg, MAX_SUBSTRINGS);
        if (res < 0) {
            SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
            goto error;
        }

        if (*arg != '\0') {
            if (strcmp(arg, "discretes") == 0) {
                if (modbus->type == MODBUS_TYP_WRITE)
                    /* Discrete access is only read access. */
                    goto error;

                modbus->type |= MODBUS_TYP_DISCRETES;
            }
            else if (strcmp(arg, "coils") == 0) {
                modbus->type |= MODBUS_TYP_COILS;
            }
            else if (strcmp(arg, "input") == 0) {
                if (modbus->type == MODBUS_TYP_WRITE) {
                    /* Input access is only read access. */
                    goto error;
                }

                modbus->type |= MODBUS_TYP_INPUT;
            }
            else if (strcmp(arg, "holding") == 0) {
                modbus->type |= MODBUS_TYP_HOLDING;
            }
            else
                goto error;
        }

        if (ret > 4) {
            res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 4, arg, MAX_SUBSTRINGS);
            if (res < 0) {
                SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
                goto error;
            }

            /* We have a correct address option */
            modbus->address = (DetectModbusValue *) SCCalloc(1, sizeof(DetectModbusValue));
            if (unlikely(modbus->address == NULL))
                goto error;

            if (arg[0] == '>') {
                modbus->address->min    = atoi((const char*) (arg+1));
                modbus->address->mode   = DETECT_MODBUS_GT;
            } else if (arg[0] == '<') {
                modbus->address->min    = atoi((const char*) (arg+1));
                modbus->address->mode   = DETECT_MODBUS_LT;
            } else {
                modbus->address->min    = atoi((const char*) arg);
            }
            SCLogDebug("and min/equal address %d", modbus->address->min);

            if (ret > 5) {
                res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 5, arg, MAX_SUBSTRINGS);
                if (res < 0) {
                    SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
                    goto error;
                }

                if (*arg != '\0') {
                    modbus->address->max    = atoi((const char*) (arg+2));
                    modbus->address->mode   = DETECT_MODBUS_RA;
                    SCLogDebug("and max address %d", modbus->address->max);
                }

                if (ret > 7) {
                    res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 7, arg, MAX_SUBSTRINGS);
                    if (res < 0) {
                        SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
                        goto error;
                    }

                    if (modbus->address->mode != DETECT_MODBUS_EQ) {
                        SCLogError(SC_ERR_CONFLICTING_RULE_KEYWORDS, "rule contains conflicting keywords (address range and value).");
                        goto error;
                    }

                    /* We have a correct address option */
                    modbus->data = (DetectModbusValue *) SCCalloc(1, sizeof(DetectModbusValue));
                    if (unlikely(modbus->data == NULL))
                        goto error;

                    if (arg[0] == '>') {
                        modbus->data->min   = atoi((const char*) (arg+1));
                        modbus->data->mode  = DETECT_MODBUS_GT;
                    } else if (arg[0] == '<') {
                        modbus->data->min   = atoi((const char*) (arg+1));
                        modbus->data->mode  = DETECT_MODBUS_LT;
                    } else {
                        modbus->data->min   = atoi((const char*) arg);
                    }
                    SCLogDebug("and min/equal value %d", modbus->data->min);

                    if (ret > 8) {
                        res = pcre_copy_substring(str, ov, MAX_SUBSTRINGS, 8, arg, MAX_SUBSTRINGS);
                        if (res < 0) {
                            SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
                            goto error;
                        }

                        if (*arg != '\0') {
                            modbus->data->max   = atoi((const char*) (arg+2));
                            modbus->data->mode  = DETECT_MODBUS_RA;
                            SCLogDebug("and max value %d", modbus->data->max);
                        }
                    }
                }
            }
        }
    }

    SCReturnPtr(modbus, "DetectModbusAccess");

error:
    if (modbus != NULL)
        DetectModbusFree(modbus);

    SCReturnPtr(NULL, "DetectModbus");
}
static const uint8_t *DetectEngineSMTPGetBufferForTX(uint64_t tx_id,
                                               DetectEngineCtx *de_ctx,
                                               DetectEngineThreadCtx *det_ctx,
                                               Flow *f, File *curr_file,
                                               uint8_t flags,
                                               uint32_t *buffer_len,
                                               uint32_t *stream_start_offset)
{
    SCEnter();
    int index = 0;
    const uint8_t *buffer = NULL;
    *buffer_len = 0;
    *stream_start_offset = 0;
    uint64_t file_size = FileDataSize(curr_file);

    if (det_ctx->smtp_buffers_list_len == 0) {
        if (SMTPCreateSpace(det_ctx, 1) < 0)
            goto end;
        index = 0;

        if (det_ctx->smtp_buffers_list_len == 0) {
            det_ctx->smtp_start_tx_id = tx_id;
        }
        det_ctx->smtp_buffers_list_len++;
    } else {
        if ((tx_id - det_ctx->smtp_start_tx_id) < det_ctx->smtp_buffers_list_len) {
            if (det_ctx->smtp[(tx_id - det_ctx->smtp_start_tx_id)].buffer_len != 0) {
                *buffer_len = det_ctx->smtp[(tx_id - det_ctx->smtp_start_tx_id)].buffer_len;
                *stream_start_offset = det_ctx->smtp[(tx_id - det_ctx->smtp_start_tx_id)].offset;
                buffer = det_ctx->smtp[(tx_id - det_ctx->smtp_start_tx_id)].buffer;

                SCReturnPtr(buffer, "uint8_t");
            }
        } else {
            if (SMTPCreateSpace(det_ctx, (tx_id - det_ctx->smtp_start_tx_id) + 1) < 0)
                goto end;

            if (det_ctx->smtp_buffers_list_len == 0) {
                det_ctx->smtp_start_tx_id = tx_id;
            }
            det_ctx->smtp_buffers_list_len++;
        }
        index = (tx_id - det_ctx->smtp_start_tx_id);
    }

    SCLogDebug("smtp_config.content_limit %u, smtp_config.content_inspect_min_size %u",
                smtp_config.content_limit, smtp_config.content_inspect_min_size);

    SCLogDebug("file %p size %"PRIu64", state %d", curr_file, file_size, curr_file->state);

    /* no new data */
    if (curr_file->content_inspected == file_size) {
        SCLogDebug("no new data");
        goto end;
    }

    if (file_size == 0) {
        SCLogDebug("no data to inspect for this transaction");
        goto end;
    }

    if ((smtp_config.content_limit == 0 || file_size < smtp_config.content_limit) &&
        file_size < smtp_config.content_inspect_min_size &&
        !(flags & STREAM_EOF) && !(curr_file->state > FILE_STATE_OPENED)) {
        SCLogDebug("we still haven't seen the entire content. "
                   "Let's defer content inspection till we see the "
                   "entire content.");
        goto end;
    }

    StreamingBufferGetDataAtOffset(curr_file->sb,
            &det_ctx->smtp[index].buffer, &det_ctx->smtp[index].buffer_len,
            curr_file->content_inspected);

    det_ctx->smtp[index].offset = curr_file->content_inspected;

    /* updat inspected tracker */
    curr_file->content_inspected = FileDataSize(curr_file);

    SCLogDebug("content_inspected %"PRIu64", offset %"PRIu64,
            curr_file->content_inspected, det_ctx->smtp[index].offset);

    buffer = det_ctx->smtp[index].buffer;
    *buffer_len = det_ctx->smtp[index].buffer_len;
    *stream_start_offset = det_ctx->smtp[index].offset;

end:
    SCLogDebug("buffer %p, len %u", buffer, *buffer_len);
    SCReturnPtr(buffer, "uint8_t");
}
/**
 * \internal
 * \brief This function is used to parse reference options passed via reference: keyword
 *
 * \param rawstr Pointer to the user provided reference options.
 *
 * \retval ref  Pointer to signature reference on success.
 * \retval NULL On failure.
 */
static DetectReference *DetectReferenceParse(char *rawstr, DetectEngineCtx *de_ctx)
{
    SCEnter();

    DetectReference *ref = NULL;
#define MAX_SUBSTRINGS 30
    int ret = 0, res = 0;
    int ov[MAX_SUBSTRINGS];
    const char *key = NULL;
    const char *content = NULL;

    ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr),
                    0, 0, ov, MAX_SUBSTRINGS);
    if (ret < 2) {
        SCLogError(SC_ERR_INVALID_SIGNATURE, "Unable to parse \"reference\" "
                   "keyword argument - \"%s\".   Invalid argument.", rawstr);
        goto error;
    }

    ref = SCMalloc(sizeof(DetectReference));
    if (unlikely(ref == NULL)) {
        goto error;
    }
    memset(ref, 0, sizeof(DetectReference));

    res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, &key);
    if (res < 0) {
        SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
        goto error;
    }

    res = pcre_get_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, &content);
    if (res < 0) {
        SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
        goto error;
    }

    if (key == NULL || content == NULL)
        goto error;

    SCRConfReference *lookup_ref_conf = SCRConfGetReference(key, de_ctx);
    if (lookup_ref_conf != NULL) {
        ref->key = lookup_ref_conf->url;
    } else {
        SCLogError(SC_ERR_REFERENCE_UNKNOWN, "unknown reference key \"%s\". "
                   "Supported keys are defined in reference.config file.  Please "
                   "have a look at the conf param \"reference-config-file\"", key);
        goto error;
    }

    /* make a copy so we can free pcre's substring */
    ref->reference = SCStrdup((char *)content);
    if (ref->reference == NULL) {
        SCLogError(SC_ERR_MEM_ALLOC, "strdup failed: %s", strerror(errno));
        goto error;
    }

    /* free the substrings */
    pcre_free_substring(key);
    pcre_free_substring(content);
    SCReturnPtr(ref, "Reference");

error:
    if (key != NULL)
        pcre_free_substring(key);
    if (content != NULL)
        pcre_free_substring(content);
    if (ref != NULL)
        DetectReferenceFree(ref);

    SCReturnPtr(NULL, "Reference");
}
Beispiel #30
0
/**
 * \internal
 * \brief This function is used to parse flags options passed via flags: keyword
 *
 * \param rawstr Pointer to the user provided flags options
 *
 * \retval de pointer to DetectFlagsData on success
 * \retval NULL on failure
 */
static DetectFlagsData *DetectFlagsParse (const char *rawstr)
{
    SCEnter();

#define MAX_SUBSTRINGS 30
    int ret = 0, found = 0, ignore = 0, res = 0;
    int ov[MAX_SUBSTRINGS];
    char *ptr;

    char arg1[16] = "";
    char arg2[16] = "";
    char arg3[16] = "";

    ret = pcre_exec(parse_regex, parse_regex_study, rawstr, strlen(rawstr),
            0, 0, ov, MAX_SUBSTRINGS);
    SCLogDebug("input '%s', pcre said %d", rawstr, ret);
    if (ret < 3) {
        SCLogError(SC_ERR_PCRE_MATCH, "pcre match failed");
        SCReturnPtr(NULL, "DetectFlagsData");
    }

    res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 1, arg1, sizeof(arg1));
    if (res < 0) {
        SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
        SCReturnPtr(NULL, "DetectFlagsData");
    }
    if (ret >= 2) {
        res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 2, arg2, sizeof(arg2));
        if (res < 0) {
            SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
            SCReturnPtr(NULL, "DetectFlagsData");
        }
    }
    if (ret >= 3) {
        res = pcre_copy_substring((char *)rawstr, ov, MAX_SUBSTRINGS, 3, arg3, sizeof(arg3));
        if (res < 0) {
            SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
            SCReturnPtr(NULL, "DetectFlagsData");
        }
    }
    SCLogDebug("args '%s', '%s', '%s'", arg1, arg2, arg3);

    if (strlen(arg2) == 0) {
        SCLogDebug("empty argument");
        SCReturnPtr(NULL, "DetectFlagsData");
    }

    DetectFlagsData *de = SCMalloc(sizeof(DetectFlagsData));
    if (unlikely(de == NULL))
        goto error;
    memset(de, 0, sizeof(DetectFlagsData));
    de->ignored_flags = 0xff;

    /** First parse args1 */
    ptr = arg1;
    while (*ptr != '\0') {
        switch (*ptr) {
            case 'S':
            case 's':
                de->flags |= TH_SYN;
                found++;
                break;
            case 'A':
            case 'a':
                de->flags |= TH_ACK;
                found++;
                break;
            case 'F':
            case 'f':
                de->flags |= TH_FIN;
                found++;
                break;
            case 'R':
            case 'r':
                de->flags |= TH_RST;
                found++;
                break;
            case 'P':
            case 'p':
                de->flags |= TH_PUSH;
                found++;
                break;
            case 'U':
            case 'u':
                de->flags |= TH_URG;
                found++;
                break;
            case '1':
                de->flags |= TH_CWR;
                found++;
                break;
            case '2':
                de->flags |= TH_ECN;
                found++;
                break;
            case 'C':
            case 'c':
                de->flags |= TH_CWR;
                found++;
                break;
            case 'E':
            case 'e':
                de->flags |= TH_ECN;
                found++;
                break;
            case '0':
                de->flags = 0;
                found++;
                break;

            case '!':
                de->modifier = MODIFIER_NOT;
                break;
            case '+':
                de->modifier = MODIFIER_PLUS;
                break;
            case '*':
                de->modifier = MODIFIER_ANY;
                break;
        }
        ptr++;
    }

    /** Second parse first set of flags */
    if (strlen(arg2) > 0) {
        ptr = arg2;
        while (*ptr != '\0') {
            switch (*ptr) {
                case 'S':
                case 's':
                    de->flags |= TH_SYN;
                    found++;
                    break;
                case 'A':
                case 'a':
                    de->flags |= TH_ACK;
                    found++;
                    break;
                case 'F':
                case 'f':
                    de->flags |= TH_FIN;
                    found++;
                    break;
                case 'R':
                case 'r':
                    de->flags |= TH_RST;
                    found++;
                    break;
                case 'P':
                case 'p':
                    de->flags |= TH_PUSH;
                    found++;
                    break;
                case 'U':
                case 'u':
                    de->flags |= TH_URG;
                    found++;
                    break;
                case '1':
                case 'C':
                case 'c':
                    de->flags |= TH_CWR;
                    found++;
                    break;
                case '2':
                case 'E':
                case 'e':
                    de->flags |= TH_ECN;
                    found++;
                    break;
                case '0':
                    de->flags = 0;
                    found++;
                    break;

                case '!':
                    if (de->modifier != 0) {
                        SCLogError(SC_ERR_FLAGS_MODIFIER, "\"flags\" supports only"
                                " one modifier at a time");
                        goto error;
                    }
                    de->modifier = MODIFIER_NOT;
                    SCLogDebug("NOT modifier is set");
                    break;
                case '+':
                    if (de->modifier != 0) {
                        SCLogError(SC_ERR_FLAGS_MODIFIER, "\"flags\" supports only"
                                " one modifier at a time");
                        goto error;
                    }
                    de->modifier = MODIFIER_PLUS;
                    SCLogDebug("PLUS modifier is set");
                    break;
                case '*':
                    if (de->modifier != 0) {
                        SCLogError(SC_ERR_FLAGS_MODIFIER, "\"flags\" supports only"
                                " one modifier at a time");
                        goto error;
                    }
                    de->modifier = MODIFIER_ANY;
                    SCLogDebug("ANY modifier is set");
                    break;
                default:
                    break;
            }
            ptr++;
        }

        if (found == 0)
            goto error;
    }

    /** Finally parse ignored flags */
    if (strlen(arg3) > 0) {
        ptr = arg3;

        while (*ptr != '\0') {
            switch (*ptr) {
                case 'S':
                case 's':
                    de->ignored_flags &= ~TH_SYN;
                    ignore++;
                    break;
                case 'A':
                case 'a':
                    de->ignored_flags &= ~TH_ACK;
                    ignore++;
                    break;
                case 'F':
                case 'f':
                    de->ignored_flags &= ~TH_FIN;
                    ignore++;
                    break;
                case 'R':
                case 'r':
                    de->ignored_flags &= ~TH_RST;
                    ignore++;
                    break;
                case 'P':
                case 'p':
                    de->ignored_flags &= ~TH_PUSH;
                    ignore++;
                    break;
                case 'U':
                case 'u':
                    de->ignored_flags &= ~TH_URG;
                    ignore++;
                    break;
                case '1':
                    de->ignored_flags &= ~TH_CWR;
                    ignore++;
                    break;
                case '2':
                    de->ignored_flags &= ~TH_ECN;
                    ignore++;
                    break;
                case 'C':
                case 'c':
                    de->ignored_flags &= ~TH_CWR;
                    ignore++;
                    break;
                case 'E':
                case 'e':
                    de->ignored_flags &= ~TH_ECN;
                    ignore++;
                    break;
                case '0':
                    break;
                default:
                    break;
            }
            ptr++;
        }

        if (ignore == 0) {
            SCLogDebug("ignore == 0");
            goto error;
        }
    }

    SCLogDebug("found %"PRId32" ignore %"PRId32"", found, ignore);
    SCReturnPtr(de, "DetectFlagsData");

error:
    if (de) {
        SCFree(de);
    }
    SCReturnPtr(NULL, "DetectFlagsData");
}