Exemple #1
0
/**
 * \test DetectFlowTestParse01 is a test to make sure that we return "something"
 *  when given valid flow opt
 */
int DetectFlowTestParse01 (void)
{
    DetectFlowData *fd = NULL;
    fd = DetectFlowParse("established");
    FAIL_IF_NULL(fd);
    DetectFlowFree(fd);
    PASS;
}
Exemple #2
0
/**
 * \test DetectFlowTestParseNocase01 is a test to make sure that we return "something"
 *  when given valid flow opt
 */
int DetectFlowTestParseNocase01 (void)
{
    DetectFlowData *fd = NULL;
    fd = DetectFlowParse("ESTABLISHED");
    FAIL_IF_NULL(fd);
    DetectFlowFree(fd);
    PASS;
}
Exemple #3
0
/**
 * \test DetectFlowTestParse03 is a test for setting the stateless flow opt
 */
int DetectFlowTestParse03 (void)
{
    DetectFlowData *fd = NULL;
    fd = DetectFlowParse("stateless");
    FAIL_IF_NULL(fd);
    FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_STATELESS && fd->match_cnt == 1);
    DetectFlowFree(fd);
    PASS;
}
Exemple #4
0
/**
 * \test DetectFlowTestParse06 is a test for setting the from_server flow opt
 */
int DetectFlowTestParse06 (void)
{
    DetectFlowData *fd = NULL;
    fd = DetectFlowParse("from_server");
    FAIL_IF_NULL(fd);
    FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 1);
    DetectFlowFree(fd);
    PASS;
}
Exemple #5
0
/**
 * \test DetectFlowTestParse08 is a test for setting the established,to_client flow opts
 */
int DetectFlowTestParse08 (void)
{
    DetectFlowData *fd = NULL;
    fd = DetectFlowParse("established,to_client");
    FAIL_IF_NULL(fd);
    FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ESTABLISHED && fd->flags & DETECT_FLOW_FLAG_TOCLIENT && fd->match_cnt == 2);
    DetectFlowFree(fd);
    PASS;
}
Exemple #6
0
/**
 * \test DetectFlowTestParseNocase07 is a test for setting the from_client flow opt
 */
int DetectFlowTestParseNocase07 (void)
{
    DetectFlowData *fd = NULL;
    fd = DetectFlowParse("FROM_CLIENT");
    FAIL_IF_NULL(fd);
    FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_TOSERVER && fd->match_cnt == 1);
    DetectFlowFree(fd);
    PASS;
}
Exemple #7
0
/**
 * \test Test parsing of the not_established keyword.
 */
static int DetectFlowTestParseNotEstablished(void)
{
    DetectFlowData *fd = NULL;
    fd = DetectFlowParse("not_established");
    FAIL_IF_NULL(fd);
    FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_NOT_ESTABLISHED);
    DetectFlowFree(fd);
    PASS;
}
Exemple #8
0
/**
 * \test Test parsing of the "only_frag" flow argument.
 */
static int DetectFlowTestParseOnlyFrag(void)
{
    DetectFlowData *fd = NULL;
    fd = DetectFlowParse("only_frag");
    FAIL_IF_NULL(fd);
    FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ONLY_FRAG);
    DetectFlowFree(fd);
    PASS;
}
Exemple #9
0
/**
 * \test DetectFlowTestParseNocase02 is a test for setting the established flow opt
 */
int DetectFlowTestParseNocase02 (void)
{
    DetectFlowData *fd = NULL;
    fd = DetectFlowParse("ESTABLISHED");
    FAIL_IF_NULL(fd);
    FAIL_IF_NOT(fd->flags == DETECT_FLOW_FLAG_ESTABLISHED &&
        fd->match_cnt == 1);
    DetectFlowFree(fd);
    PASS;
}
Exemple #10
0
/**
 * \test DetectFlowTestParseNocase01 is a test to make sure that we return "something"
 *  when given valid flow opt
 */
int DetectFlowTestParseNocase01 (void) {
    int result = 0;
    DetectFlowData *fd = NULL;
    fd = DetectFlowParse("ESTABLISHED");
    if (fd != NULL) {
        DetectFlowFree(fd);
        result = 1;
    }

    return result;
}
Exemple #11
0
/**
 * \brief this function is used to add the parsed flowdata into the current signature
 *
 * \param de_ctx pointer to the Detection Engine Context
 * \param s pointer to the Current Signature
 * \param flowstr pointer to the user provided flow options
 *
 * \retval 0 on Success
 * \retval -1 on Failure
 */
int DetectFlowSetup (DetectEngineCtx *de_ctx, Signature *s, char *flowstr)
{
    DetectFlowData *fd = NULL;
    SigMatch *sm = NULL;

    fd = DetectFlowParse(flowstr);
    if (fd == NULL)
        goto error;

    /*ensure only one flow option*/
    if (s->init_flags & SIG_FLAG_INIT_FLOW) {
        SCLogError (SC_ERR_INVALID_SIGNATURE, "A signature may have only one flow option.");
        goto error;
    }

    /* 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_FLOW;
    sm->ctx = (SigMatchCtx *)fd;

    SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_MATCH);

    /* set the signature direction flags */
    if (fd->flags & DETECT_FLOW_FLAG_TOSERVER) {
        s->flags |= SIG_FLAG_TOSERVER;
    } else if (fd->flags & DETECT_FLOW_FLAG_TOCLIENT) {
        s->flags |= SIG_FLAG_TOCLIENT;
    } else {
        s->flags |= SIG_FLAG_TOSERVER;
        s->flags |= SIG_FLAG_TOCLIENT;
    }
    if (fd->flags & DETECT_FLOW_FLAG_ONLYSTREAM) {
        s->flags |= SIG_FLAG_REQUIRE_STREAM;
    }
    if (fd->flags & DETECT_FLOW_FLAG_NOSTREAM) {
        s->flags |= SIG_FLAG_REQUIRE_PACKET;
    } else {
        s->init_flags |= SIG_FLAG_INIT_FLOW;
    }

    return 0;

error:
    if (fd != NULL)
        DetectFlowFree(fd);
    if (sm != NULL)
        SCFree(sm);
    return -1;

}
Exemple #12
0
/**
 * \test DetectFlowTestParseNocase08 is a test for setting the established,to_client flow opts
 */
int DetectFlowTestParseNocase08 (void)
{
    DetectFlowData *fd = NULL;
    fd = DetectFlowParse("ESTABLISHED,TO_CLIENT");
    FAIL_IF_NULL(fd);
    FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ESTABLISHED &&
        fd->flags & DETECT_FLOW_FLAG_TOCLIENT &&
        fd->match_cnt == 2);
    DetectFlowFree(fd);
    PASS;
}
Exemple #13
0
/**
 * \test DetectFlowTestParseNocase11 is a test for setting the from_server,stateless flow opts with spaces all around
 */
int DetectFlowTestParseNocase11 (void)
{
    DetectFlowData *fd = NULL;
    fd = DetectFlowParse(" FROM_SERVER , STATELESS ");
    FAIL_IF_NULL(fd);
    FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS &&
        fd->flags & DETECT_FLOW_FLAG_TOCLIENT &&
        fd->match_cnt == 2);
    DetectFlowFree(fd);
    PASS;
}
Exemple #14
0
/**
 * \test DetectFlowTestParse01 is a test to make sure that we return "something"
 *  when given valid flow opt
 */
int DetectFlowTestParse01 (void) {
    int result = 0;
    DetectFlowData *fd = NULL;
    fd = DetectFlowParse("established");
    if (fd != NULL) {
        DetectFlowFree(fd);
        result = 1;
    }

    return result;
}
Exemple #15
0
/**
 * \test DetectFlowTestParse11 is a test for setting the from_server,stateless flow opts with spaces all around
 */
int DetectFlowTestParse11 (void)
{
    DetectFlowData *fd = NULL;
    fd = DetectFlowParse(" from_server , stateless ");
    FAIL_IF_NULL(fd);
    FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_STATELESS &&
        fd->flags & DETECT_FLOW_FLAG_TOCLIENT &&
        fd->match_cnt == 2);
    DetectFlowFree(fd);
    PASS;
}
Exemple #16
0
/**
 * \test DetectFlowTestParse20 is a test for setting from_server, established, no_stream
 */
int DetectFlowTestParse20 (void)
{
    DetectFlowData *fd = NULL;
    fd = DetectFlowParse("from_server,established,no_stream");
    FAIL_IF_NULL(fd);
    FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ESTABLISHED &&
        fd->flags & DETECT_FLOW_FLAG_TOCLIENT &&
        fd->flags & DETECT_FLOW_FLAG_NOSTREAM &&
        fd->match_cnt == 3);
    DetectFlowFree(fd);
    PASS;
}
Exemple #17
0
/**
 * \test DetectFlowTestParse13 is a test for an invalid option
 */
int DetectFlowTestParse13 (void) {
    int result = 1;
    DetectFlowData *fd = NULL;
    fd = DetectFlowParse("invalidoptiontest");
    if (fd != NULL) {
        printf("expected: NULL got 0x%02X %" PRId32 ": ",fd->flags, fd->match_cnt);
        result = 0;
        DetectFlowFree(fd);
    }

    return result;
}
Exemple #18
0
/**
 * \test DetectFlowTestParse15 is a test for an invalid combo of options established,stateless
 */
int DetectFlowTestParse15 (void) {
    int result = 1;
    DetectFlowData *fd = NULL;
    fd = DetectFlowParse("established,stateless");
    if (fd != NULL) {
        printf("expected: NULL got 0x%02X %" PRId32 ": ",fd->flags, fd->match_cnt);
        result = 0;
        DetectFlowFree(fd);
    }

    return result;
}
Exemple #19
0
/**
 * \test DetectFlowTestParse21 is a test for an invalid opt between to valid opts
 */
int DetectFlowTestParse21 (void) {
    int result = 1;
    DetectFlowData *fd = NULL;
    fd = DetectFlowParse("from_server,a,no_stream");
    if (fd != NULL) {
        printf("expected: NULL got 0x%02X %" PRId32 ": ",fd->flags, fd->match_cnt);
        result = 0;
        DetectFlowFree(fd);
    }

    return result;
}
Exemple #20
0
/**
 * \test DetectFlowTestParse20 is a test for setting from_server, established, no_stream
 */
int DetectFlowTestParseNocase20 (void)
{
    DetectFlowData *fd = NULL;
    fd = DetectFlowParse("FROM_SERVER,ESTABLISHED,NO_STREAM");
    FAIL_IF_NULL(fd);
    FAIL_IF_NOT(fd->flags & DETECT_FLOW_FLAG_ESTABLISHED &&
        fd->flags & DETECT_FLOW_FLAG_TOCLIENT &&
        fd->flags & DETECT_FLOW_FLAG_NOSTREAM &&
        fd->match_cnt == 3);
    DetectFlowFree(fd);
    PASS;
}
Exemple #21
0
/**
 * \test DetectFlowTestParse06 is a test for setting the from_server flow opt
 */
int DetectFlowTestParse06 (void) {
    int result = 0;
    DetectFlowData *fd = NULL;
    fd = DetectFlowParse("from_server");
    if (fd != NULL) {
        if (fd->flags == FLOW_PKT_TOCLIENT && fd->match_cnt == 1) {
            result = 1;
        } else {
            printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_TOCLIENT, 1, fd->flags, fd->match_cnt);
        }
        DetectFlowFree(fd);
    }

    return result;
}
Exemple #22
0
/**
 * \test DetectFlowTestParseNocase03 is a test for setting the stateless flow opt
 */
int DetectFlowTestParseNocase03 (void) {
    int result = 0;
    DetectFlowData *fd = NULL;
    fd = DetectFlowParse("STATELESS");
    if (fd != NULL) {
        if (fd->flags == FLOW_PKT_STATELESS && fd->match_cnt == 1) {
            result = 1;
        } else {
            printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_STATELESS, 1, fd->flags, fd->match_cnt);
        }
        DetectFlowFree(fd);
    }

    return result;
}
Exemple #23
0
/**
 * \test DetectFlowTestParseNocase07 is a test for setting the from_client flow opt
 */
int DetectFlowTestParseNocase07 (void) {
    int result = 0;
    DetectFlowData *fd = NULL;
    fd = DetectFlowParse("FROM_CLIENT");
    if (fd != NULL) {
        if (fd->flags == FLOW_PKT_TOSERVER && fd->match_cnt == 1) {
            result = 1;
        } else {
            printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_TOSERVER, 1, fd->flags, fd->match_cnt);
        }
        DetectFlowFree(fd);
    }

    return result;
}
Exemple #24
0
/**
 * \test DetectFlowTestParseNocase08 is a test for setting the established,to_client flow opts
 */
int DetectFlowTestParseNocase08 (void) {
    int result = 0;
    DetectFlowData *fd = NULL;
    fd = DetectFlowParse("ESTABLISHED,TO_CLIENT");
    if (fd != NULL) {
        if (fd->flags & FLOW_PKT_ESTABLISHED && fd->flags & FLOW_PKT_TOCLIENT && fd->match_cnt == 2) {
            result = 1;
        } else {
            printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_ESTABLISHED + FLOW_PKT_TOCLIENT, 2, fd->flags, fd->match_cnt);
        }
        DetectFlowFree(fd);
    }

    return result;
}
Exemple #25
0
/**
 * \test DetectFlowTestParseNocase11 is a test for setting the from_server,stateless flow opts with spaces all around
 */
int DetectFlowTestParseNocase11 (void) {
    int result = 0;
    DetectFlowData *fd = NULL;
    fd = DetectFlowParse(" FROM_SERVER , STATELESS ");
    if (fd != NULL) {
        if (fd->flags & FLOW_PKT_STATELESS  && fd->flags & FLOW_PKT_TOCLIENT && fd->match_cnt == 2){
            result = 1;
        } else {
            printf("expected: 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_STATELESS + FLOW_PKT_TOCLIENT, 2, fd->flags, fd->match_cnt);
        }
        DetectFlowFree(fd);
    }

    return result;
}
Exemple #26
0
/**
 * \test DetectFlowTestParse02 is a test for setting the established flow opt
 */
int DetectFlowTestParse02 (void) {
    int result = 0;
    DetectFlowData *fd = NULL;
    fd = DetectFlowParse("established");
    if (fd != NULL) {
        if (fd->flags == FLOW_PKT_ESTABLISHED && fd->match_cnt == 1) {
            result = 1;
        } else {
            printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_ESTABLISHED, 1, fd->flags, fd->match_cnt);
        }
        DetectFlowFree(fd);
    }

    return result;
}
Exemple #27
0
/**
 * \test DetectFlowTestParseNocase18 is a test for setting the from_server,stateless,only_stream flow opts (order of state,dir reversed)
 */
int DetectFlowTestParseNocase18 (void) {
    int result = 0;
    DetectFlowData *fd = NULL;
    fd = DetectFlowParse("FROM_SERVER,ESTABLISHED,ONLY_STREAM");
    if (fd != NULL) {
        if (fd->flags & FLOW_PKT_ESTABLISHED && fd->flags & FLOW_PKT_TOCLIENT && fd->flags & FLOW_PKT_ONLYSTREAM && fd->match_cnt == 3) {
            result = 1;
        } else {
            printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_ESTABLISHED + FLOW_PKT_TOCLIENT + FLOW_PKT_ONLYSTREAM, 3,
                    fd->flags, fd->match_cnt);
        }
        DetectFlowFree(fd);
    }

    return result;
}
Exemple #28
0
/**
 * \test DetectFlowTestParse18 is a test for setting the from_server,stateless,only_stream flow opts (order of state,dir reversed)
 */
int DetectFlowTestParse18 (void) {
    int result = 0;
    DetectFlowData *fd = NULL;
    fd = DetectFlowParse("from_server,established,only_stream");
    if (fd != NULL) {
        if (fd->flags & FLOW_PKT_ESTABLISHED && fd->flags & FLOW_PKT_TOCLIENT && fd->flags & FLOW_PKT_ONLYSTREAM && fd->match_cnt == 3) {
            result = 1;
        } else {
            printf("expected 0x%02X cnt %" PRId32 " got 0x%02X cnt %" PRId32 ": ", FLOW_PKT_ESTABLISHED + FLOW_PKT_TOCLIENT + FLOW_PKT_ONLYSTREAM, 3,
                    fd->flags, fd->match_cnt);
        }
        DetectFlowFree(fd);
    }

    return result;
}
Exemple #29
0
/**
 * \brief This function is used to parse flow options passed via flow: keyword
 *
 * \param flowstr Pointer to the user provided flow options
 *
 * \retval fd pointer to DetectFlowData on success
 * \retval NULL on failure
 */
DetectFlowData *DetectFlowParse (char *flowstr)
{
    DetectFlowData *fd = 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, flowstr, strlen(flowstr), 0, 0, ov, MAX_SUBSTRINGS);
    if (ret < 1 || ret > 4) {
        SCLogError(SC_ERR_PCRE_MATCH, "parse error, ret %" PRId32 ", string %s", ret, flowstr);
        goto error;
    }

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

        if (ret > 2) {
            res = pcre_get_substring((char *)flowstr, ov, MAX_SUBSTRINGS, 2, &str_ptr);
            if (res < 0) {
                SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
                goto error;
            }
            args[1] = (char *)str_ptr;
        }
        if (ret > 3) {
            res = pcre_get_substring((char *)flowstr, ov, MAX_SUBSTRINGS, 3, &str_ptr);
            if (res < 0) {
                SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_get_substring failed");
                goto error;
            }
            args[2] = (char *)str_ptr;
        }
    }

    fd = SCMalloc(sizeof(DetectFlowData));
    if (fd == NULL)
        goto error;
    fd->flags = 0;
    fd->match_cnt = 0;

    int i;
    for (i = 0; i < (ret - 1); i++) {
        if (args[i]) {
            /* inspect our options and set the flags */
            if (strcasecmp(args[i], "established") == 0) {
                if (fd->flags & FLOW_PKT_ESTABLISHED) {
                    SCLogError(SC_ERR_FLAGS_MODIFIER, "FLOW_PKT_ESTABLISHED flag is already set");
                    goto error;
                } else if (fd->flags & FLOW_PKT_STATELESS) {
                    SCLogError(SC_ERR_FLAGS_MODIFIER, "FLOW_PKT_STATELESS already set");
                    goto error;
                }
                fd->flags |= FLOW_PKT_ESTABLISHED;
            } else if (strcasecmp(args[i], "stateless") == 0) {
                if (fd->flags & FLOW_PKT_STATELESS) {
                    SCLogError(SC_ERR_FLAGS_MODIFIER, "FLOW_PKT_STATELESS flag is already set");
                    goto error;
                } else if (fd->flags & FLOW_PKT_ESTABLISHED) {
                    SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set FLOW_PKT_STATELESS, FLOW_PKT_ESTABLISHED already set");
                    goto error;
                }
                fd->flags |= FLOW_PKT_STATELESS;
            } else if (strcasecmp(args[i], "to_client") == 0 || strcasecmp(args[i], "from_server") == 0) {
                if (fd->flags & FLOW_PKT_TOCLIENT) {
                    SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set FLOW_PKT_TOCLIENT flag is already set");
                    goto error;
                } else if (fd->flags & FLOW_PKT_TOSERVER) {
                    SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set to_client, FLOW_PKT_TOSERVER already set");
                    goto error;
                }
                fd->flags |= FLOW_PKT_TOCLIENT;
            } else if (strcasecmp(args[i], "to_server") == 0 || strcasecmp(args[i], "from_client") == 0){
                if (fd->flags & FLOW_PKT_TOSERVER) {
                    SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set FLOW_PKT_TOSERVER flag is already set");
                    goto error;
                } else if (fd->flags & FLOW_PKT_TOCLIENT) {
                    SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set to_server, FLOW_PKT_TO_CLIENT flag already set");
                    goto error;
                }
                fd->flags |= FLOW_PKT_TOSERVER;
            } else if (strcasecmp(args[i], "only_stream") == 0) {
                if (fd->flags & FLOW_PKT_ONLYSTREAM) {
                    SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set only_stream flag is already set");
                    goto error;
                } else if (fd->flags & FLOW_PKT_NOSTREAM) {
                    SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set only_stream flag, FLOW_PKT_NOSTREAM already set");
                    goto error;
                }
                fd->flags |= FLOW_PKT_ONLYSTREAM;
            } else if (strcasecmp(args[i], "no_stream") == 0) {
                if (fd->flags & FLOW_PKT_NOSTREAM) {
                    SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set no_stream flag is already set");
                    goto error;
                } else if (fd->flags & FLOW_PKT_ONLYSTREAM) {
                    SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set no_stream flag, FLOW_PKT_ONLYSTREAM already set");
                    goto error;
                }
                fd->flags |= FLOW_PKT_NOSTREAM;
            } else {
                SCLogError(SC_ERR_INVALID_VALUE, "invalid flow option \"%s\"", args[i]);
                goto error;
            }

            fd->match_cnt++;
            //printf("args[%" PRId32 "]: %s match_cnt: %" PRId32 " flags: 0x%02X\n", i, args[i], fd->match_cnt, fd->flags);
        }
    }
    for (i = 0; i < (ret -1); i++){
        if (args[i] != NULL)
            SCFree(args[i]);
    }
    return fd;

error:
    /* ret can be higher than 3 */
    for (i = 0; i < (ret - 1) && i < 3; i++){
        if (args[i] != NULL)
            SCFree(args[i]);
    }

    if (fd != NULL)
        DetectFlowFree(fd);
    return NULL;

}
Exemple #30
0
/**
 * \brief This function is used to parse flow options passed via flow: keyword
 *
 * \param flowstr Pointer to the user provided flow options
 *
 * \retval fd pointer to DetectFlowData on success
 * \retval NULL on failure
 */
DetectFlowData *DetectFlowParse (char *flowstr)
{
    DetectFlowData *fd = NULL;
    char *args[3] = {NULL,NULL,NULL};
#define MAX_SUBSTRINGS 30
    int ret = 0, res = 0;
    int ov[MAX_SUBSTRINGS];
    char str1[16] = "", str2[16] = "", str3[16] = "";

    ret = pcre_exec(parse_regex, parse_regex_study, flowstr, strlen(flowstr), 0, 0, ov, MAX_SUBSTRINGS);
    if (ret < 1 || ret > 4) {
        SCLogError(SC_ERR_PCRE_MATCH, "parse error, ret %" PRId32 ", string %s", ret, flowstr);
        goto error;
    }

    if (ret > 1) {
        res = pcre_copy_substring((char *)flowstr, ov, MAX_SUBSTRINGS, 1, str1, sizeof(str1));
        if (res < 0) {
            SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed");
            goto error;
        }
        args[0] = (char *)str1;

        if (ret > 2) {
            res = pcre_copy_substring((char *)flowstr, ov, MAX_SUBSTRINGS, 2, str2, sizeof(str2));
            if (res < 0) {
                SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed");
                goto error;
            }
            args[1] = (char *)str2;
        }
        if (ret > 3) {
            res = pcre_copy_substring((char *)flowstr, ov, MAX_SUBSTRINGS, 3, str3, sizeof(str3));
            if (res < 0) {
                SCLogError(SC_ERR_PCRE_GET_SUBSTRING, "pcre_copy_substring failed");
                goto error;
            }
            args[2] = (char *)str3;
        }
    }

    fd = SCMalloc(sizeof(DetectFlowData));
    if (unlikely(fd == NULL))
        goto error;
    fd->flags = 0;
    fd->match_cnt = 0;

    int i;
    for (i = 0; i < (ret - 1); i++) {
        if (args[i]) {
            /* inspect our options and set the flags */
            if (strcasecmp(args[i], "established") == 0) {
                if (fd->flags & DETECT_FLOW_FLAG_ESTABLISHED) {
                    SCLogError(SC_ERR_FLAGS_MODIFIER, "DETECT_FLOW_FLAG_ESTABLISHED flag is already set");
                    goto error;
                } else if (fd->flags & DETECT_FLOW_FLAG_STATELESS) {
                    SCLogError(SC_ERR_FLAGS_MODIFIER, "DETECT_FLOW_FLAG_STATELESS already set");
                    goto error;
                }
                fd->flags |= DETECT_FLOW_FLAG_ESTABLISHED;
            } else if (strcasecmp(args[i], "not_established") == 0) {
                if (fd->flags & DETECT_FLOW_FLAG_NOT_ESTABLISHED) {
                    SCLogError(SC_ERR_FLAGS_MODIFIER, "DETECT_FLOW_FLAG_NOT_ESTABLISHED flag is already set");
                    goto error;
                } else if (fd->flags & DETECT_FLOW_FLAG_NOT_ESTABLISHED) {
                    SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set DETECT_FLOW_FLAG_NOT_ESTABLISHED, DETECT_FLOW_FLAG_ESTABLISHED already set");
                    goto error;
                }
                fd->flags |= DETECT_FLOW_FLAG_NOT_ESTABLISHED;
            } else if (strcasecmp(args[i], "stateless") == 0) {
                if (fd->flags & DETECT_FLOW_FLAG_STATELESS) {
                    SCLogError(SC_ERR_FLAGS_MODIFIER, "DETECT_FLOW_FLAG_STATELESS flag is already set");
                    goto error;
                } else if (fd->flags & DETECT_FLOW_FLAG_ESTABLISHED) {
                    SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set DETECT_FLOW_FLAG_STATELESS, DETECT_FLOW_FLAG_ESTABLISHED already set");
                    goto error;
                }
                fd->flags |= DETECT_FLOW_FLAG_STATELESS;
            } else if (strcasecmp(args[i], "to_client") == 0 || strcasecmp(args[i], "from_server") == 0) {
                if (fd->flags & DETECT_FLOW_FLAG_TOCLIENT) {
                    SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set DETECT_FLOW_FLAG_TOCLIENT flag is already set");
                    goto error;
                } else if (fd->flags & DETECT_FLOW_FLAG_TOSERVER) {
                    SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set to_client, DETECT_FLOW_FLAG_TOSERVER already set");
                    goto error;
                }
                fd->flags |= DETECT_FLOW_FLAG_TOCLIENT;
            } else if (strcasecmp(args[i], "to_server") == 0 || strcasecmp(args[i], "from_client") == 0){
                if (fd->flags & DETECT_FLOW_FLAG_TOSERVER) {
                    SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set DETECT_FLOW_FLAG_TOSERVER flag is already set");
                    goto error;
                } else if (fd->flags & DETECT_FLOW_FLAG_TOCLIENT) {
                    SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set to_server, DETECT_FLOW_FLAG_TO_CLIENT flag already set");
                    goto error;
                }
                fd->flags |= DETECT_FLOW_FLAG_TOSERVER;
            } else if (strcasecmp(args[i], "only_stream") == 0) {
                if (fd->flags & DETECT_FLOW_FLAG_ONLYSTREAM) {
                    SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set only_stream flag is already set");
                    goto error;
                } else if (fd->flags & DETECT_FLOW_FLAG_NOSTREAM) {
                    SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set only_stream flag, DETECT_FLOW_FLAG_NOSTREAM already set");
                    goto error;
                }
                fd->flags |= DETECT_FLOW_FLAG_ONLYSTREAM;
            } else if (strcasecmp(args[i], "no_stream") == 0) {
                if (fd->flags & DETECT_FLOW_FLAG_NOSTREAM) {
                    SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set no_stream flag is already set");
                    goto error;
                } else if (fd->flags & DETECT_FLOW_FLAG_ONLYSTREAM) {
                    SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set no_stream flag, DETECT_FLOW_FLAG_ONLYSTREAM already set");
                    goto error;
                }
                fd->flags |= DETECT_FLOW_FLAG_NOSTREAM;
            } else if (strcasecmp(args[i], "no_frag") == 0) {
                if (fd->flags & DETECT_FLOW_FLAG_NO_FRAG) {
                    SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set no_frag flag is already set");
                    goto error;
                } else if (fd->flags & DETECT_FLOW_FLAG_ONLY_FRAG) {
                    SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set no_frag flag, only_frag already set");
                    goto error;
                }
                fd->flags |= DETECT_FLOW_FLAG_NO_FRAG;
            } else if (strcasecmp(args[i], "only_frag") == 0) {
                if (fd->flags & DETECT_FLOW_FLAG_ONLY_FRAG) {
                    SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set only_frag flag is already set");
                    goto error;
                } else if (fd->flags & DETECT_FLOW_FLAG_NO_FRAG) {
                    SCLogError(SC_ERR_FLAGS_MODIFIER, "cannot set only_frag flag, no_frag already set");
                    goto error;
                }
                fd->flags |= DETECT_FLOW_FLAG_ONLY_FRAG;
            } else {
                SCLogError(SC_ERR_INVALID_VALUE, "invalid flow option \"%s\"", args[i]);
                goto error;
            }

            fd->match_cnt++;
            //printf("args[%" PRId32 "]: %s match_cnt: %" PRId32 " flags: 0x%02X\n", i, args[i], fd->match_cnt, fd->flags);
        }
    }
    return fd;

error:
    if (fd != NULL)
        DetectFlowFree(fd);
    return NULL;

}