moving http_client_body logic to use it per transactions. Adding unittests

remotes/origin/master-1.0.x
Pablo Rincon 15 years ago committed by Victor Julien
parent ee34c70ad8
commit 06a65cb460

@ -44,12 +44,19 @@
#include "app-layer-htp.h"
#include "util-spm.h"
#include "util-unittest.h"
#include "util-debug.h"
#include "app-layer-htp.h"
#include "util-time.h"
#include <htp/htp.h>
#include "util-unittest.h"
#include "util-unittest-helper.h"
#include "flow-util.h"
#include "detect-engine.h"
#include "detect-engine-state.h"
#include "detect-parse.h"
#include "conf.h"
/** Need a linked list in order to keep track of these */
@ -146,10 +153,6 @@ static void *HTPStateAlloc(void)
memset(s, 0x00, sizeof(HtpState));
s->body.nchunks = 0;
s->body.operation = HTP_BODY_NONE;
s->body.pcre_flags = HTP_PCRE_NONE;
#ifdef DEBUG
SCMutexLock(&htp_state_mem_lock);
htp_state_memcnt++;
@ -176,15 +179,31 @@ void HTPStateFree(void *state)
HtpState *s = (HtpState *)state;
/* Unset the body inspection */
s->flags &=~ HTP_FLAG_NEW_BODY_SET;
/* free the connection parser memory used by HTP library */
if (s != NULL) {
if (s->connp != NULL) {
size_t i;
/* free the list of body chunks */
if (s->connp->conn != NULL) {
for (i = 0; i < list_size(s->connp->conn->transactions); i++) {
htp_tx_t *tx = (htp_tx_t *)list_get(s->connp->conn->transactions, i);
if (tx != NULL) {
SCHtpTxUserData *htud = (SCHtpTxUserData *) htp_tx_get_user_data(tx);
if (htud != NULL) {
HtpBodyFree(&htud->body);
SCFree(htud);
}
htp_tx_set_user_data(tx, NULL);
}
}
}
htp_connp_destroy_all(s->connp);
}
/* free the list of body chunks */
if (s->body.nchunks > 0) {
HtpBodyFree(&s->body);
}
}
SCFree(s);
@ -669,27 +688,27 @@ int HTPCallbackRequestBodyData(htp_tx_data_t *d)
"%"PRIu32"", hstate, d, d->data, (uint32_t)d->len);
//PrintRawDataFp(stdout, d->data, d->len);
SCHtpTxUserData *htud = (SCHtpTxUserData *) htp_tx_get_user_data(d->tx);
if (htud == NULL) {
htud = SCMalloc(sizeof(SCHtpTxUserData));
if (htud == NULL) {
SCLogError(SC_ERR_MEM_ALLOC, "Error allocating memory");
SCReturnInt(HOOK_OK);
}
memset(htud, 0, sizeof(SCHtpTxUserData));
htud->body.operation = HTP_BODY_NONE;
htud->body.pcre_flags = HTP_PCRE_NONE;
/* If it has been inspected by pcre and there's no match,
* remove this chunks */
if ( !(hstate->body.pcre_flags & HTP_PCRE_HAS_MATCH) &&
(hstate->body.pcre_flags & HTP_PCRE_DONE))
{
HtpBodyFree(&hstate->body);
}
/* If its a new operation, remove the old data */
if (hstate->body.operation == HTP_BODY_RESPONSE) {
HtpBodyFree(&hstate->body);
hstate->body.pcre_flags = HTP_PCRE_NONE;
/* Set the user data for handling body chunks on this transaction */
htp_tx_set_user_data(d->tx, htud);
}
hstate->body.operation = HTP_BODY_REQUEST;
htud->body.operation = HTP_BODY_REQUEST;
HtpBodyAppendChunk(&hstate->body, (uint8_t*)d->data, (uint32_t)d->len);
hstate->body.pcre_flags = HTP_PCRE_NONE;
HtpBodyAppendChunk(&htud->body, (uint8_t*)d->data, (uint32_t)d->len);
htud->body.pcre_flags = HTP_PCRE_NONE;
if (SCLogDebugEnabled()) {
HtpBodyPrint(&hstate->body);
HtpBodyPrint(&htud->body);
}
/* set the new chunk flag */
@ -766,12 +785,8 @@ static int HTPCallbackResponse(htp_connp_t *connp) {
SCReturnInt(HOOK_ERROR);
}
/* Free data when we have a response */
if (hstate->body.nchunks > 0)
HtpBodyFree(&hstate->body);
hstate->body.operation = HTP_BODY_RESPONSE;
hstate->body.pcre_flags = HTP_PCRE_NONE;
/* Unset the body inspection (if any) */
hstate->flags &=~ HTP_FLAG_NEW_BODY_SET;
/* remove obsolete transactions */
size_t idx;
@ -780,6 +795,14 @@ static int HTPCallbackResponse(htp_connp_t *connp) {
if (tx == NULL)
continue;
/* This will remove obsolete body chunks */
SCHtpTxUserData *htud = (SCHtpTxUserData *) htp_tx_get_user_data(tx);
if (htud != NULL) {
HtpBodyFree(&htud->body);
htp_tx_set_user_data(tx, NULL);
SCFree(htud);
}
htp_tx_destroy(tx);
}
@ -1807,6 +1830,7 @@ int HTPParserConfigTest03(void)
{
int result = 1;
Flow f;
FLOW_INITIALIZE(&f);
uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost"
" Data is c0oL!";
uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
@ -1908,8 +1932,10 @@ end:
StreamTcpFreeConfig(TRUE);
if (htp_state != NULL)
HTPStateFree(htp_state);
FLOW_DESTROY(&f);
return result;
}
#endif /* UNITTESTS */
/**

@ -82,11 +82,16 @@ typedef struct HtpBody_ {
any pcre (so we can free() without waiting) */
} HtpBody;
/** Now the Body Chunks will be stored per transaction, at
* the tx user data */
typedef struct SCHtpTxUserData_ {
HtpBody body; /**< Body of the request (if any) */
} SCHtpTxUserData;
typedef struct HtpState_ {
htp_connp_t *connp; /**< Connection parser structure for
each connection */
HtpBody body; /**< Body of the request (if any) */
// size_t new_in_tx_index; /**< Index to indicate that after this we have
// new requests to log */
uint8_t flags;

@ -102,50 +102,66 @@ int DetectHttpClientBodyMatch(ThreadVars *t, DetectEngineThreadCtx *det_ctx,
goto end;
}
if (htp_state->body.nchunks == 0) {
SCLogDebug("No http chunks to inspect");
goto end;
} else {
HtpBodyChunk *cur = htp_state->body.first;
/* no chunks?!! get out of here */
if (cur == NULL) {
htp_tx_t *tx = NULL;
size_t idx = 0;
for (idx = 0;//hs->new_in_tx_index;
idx < list_size(htp_state->connp->conn->transactions); idx++)
{
tx = list_get(htp_state->connp->conn->transactions, idx);
if (tx == NULL)
continue;
SCHtpTxUserData *htud = (SCHtpTxUserData *) htp_tx_get_user_data(tx);
if (htud == NULL)
continue;
HtpBodyChunk *cur = htud->body.first;
if (htud->body.nchunks == 0) {
SCLogDebug("No http chunks to inspect");
goto end;
}
} else {
/* no chunks?!! get out of here */
if (cur == NULL) {
SCLogDebug("No http chunks to inspect");
goto end;
}
/* this applies only for the client request body like the keyword name says */
if (htp_state->body.operation != HTP_BODY_REQUEST) {
SCLogDebug("htp chunk not a request chunk");
goto end;
}
/* this applies only for the client request body like the keyword name says */
if (htud->body.operation != HTP_BODY_REQUEST) {
SCLogDebug("htp chunk not a request chunk");
goto end;
}
/* this is not how we do it now. We can rather hold the PM state from
* the previous chunk that was matched, and continue right from where
* we left off. We need to devise a scheme to do that, not just for
* this keyword, but other keywords need it as well */
uint8_t *chunks_buffer = NULL;
uint32_t total_chunks_len = 0;
/* club all the chunks into one whole buffer and call the SPM on the buffer */
while (cur != NULL) {
total_chunks_len += cur->len;
if ( (chunks_buffer = SCRealloc(chunks_buffer, total_chunks_len)) == NULL) {
return 0;
/* this is not how we do it now. We can rather hold the PM state from
* the previous chunk that was matched, and continue right from where
* we left off. We need to devise a scheme to do that, not just for
* this keyword, but other keywords need it as well */
uint8_t *chunks_buffer = NULL;
uint32_t total_chunks_len = 0;
/* club all the chunks into one whole buffer and call the SPM on the buffer */
while (cur != NULL) {
total_chunks_len += cur->len;
if ( (chunks_buffer = SCRealloc(chunks_buffer, total_chunks_len)) == NULL) {
return 0;
}
memcpy(chunks_buffer + total_chunks_len - cur->len, cur->data, cur->len);
cur = cur->next;
}
memcpy(chunks_buffer + total_chunks_len - cur->len, cur->data, cur->len);
cur = cur->next;
}
/* call the case insensitive version if nocase has been specified in the sig */
if (hcbd->flags & DETECT_AL_HTTP_CLIENT_BODY_NOCASE) {
result = (BoyerMooreNocase(hcbd->content, hcbd->content_len, chunks_buffer,
total_chunks_len, hcbd->bm_ctx->bmGs,
hcbd->bm_ctx->bmBc) != NULL);
/* call the case sensitive version if nocase has been specified in the sig */
} else {
result = (BoyerMoore(hcbd->content, hcbd->content_len, chunks_buffer,
total_chunks_len, hcbd->bm_ctx->bmGs,
hcbd->bm_ctx->bmBc) != NULL);
/* call the case insensitive version if nocase has been specified in the sig */
if (hcbd->flags & DETECT_AL_HTTP_CLIENT_BODY_NOCASE) {
result = (BoyerMooreNocase(hcbd->content, hcbd->content_len, chunks_buffer,
total_chunks_len, hcbd->bm_ctx->bmGs,
hcbd->bm_ctx->bmBc) != NULL);
/* call the case sensitive version if nocase has been specified in the sig */
} else {
result = (BoyerMoore(hcbd->content, hcbd->content_len, chunks_buffer,
total_chunks_len, hcbd->bm_ctx->bmGs,
hcbd->bm_ctx->bmBc) != NULL);
}
SCFree(chunks_buffer);
}
SCFree(chunks_buffer);
}
SCMutexUnlock(&f->m);
@ -1320,6 +1336,427 @@ end:
return result;
}
/** \test multiple http transactions and body chunks of request handling */
static int DetectHttpClientBodyTest14(void) {
int result = 0;
Signature *s = NULL;
DetectEngineThreadCtx *det_ctx = NULL;
ThreadVars th_v;
Flow f;
TcpSession ssn;
Packet *p = NULL;
uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n";
uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\nContent-Length: 10\r\n";
uint8_t httpbuf3[] = "Cookie: dummy\r\n\r\n";
uint8_t httpbuf4[] = "Body one!!";
uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
uint8_t httpbuf5[] = "GET /?var=val HTTP/1.1\r\n";
uint8_t httpbuf6[] = "User-Agent: Firefox/1.0\r\n";
uint8_t httpbuf7[] = "Cookie: dummy2\r\nContent-Length: 10\r\n\r\nBody two!!";
uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
uint32_t httplen7 = sizeof(httpbuf7) - 1; /* minus the \0 */
memset(&th_v, 0, sizeof(th_v));
memset(&f, 0, sizeof(f));
memset(&ssn, 0, sizeof(ssn));
p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
FLOW_INITIALIZE(&f);
f.protoctx = (void *)&ssn;
f.proto = IPPROTO_TCP;
f.src.family = AF_INET;
f.dst.family = AF_INET;
p->flow = &f;
p->flowflags |= FLOW_PKT_TOSERVER;
p->flowflags |= FLOW_PKT_ESTABLISHED;
f.alproto = ALPROTO_HTTP;
StreamTcpInitConfig(TRUE);
FlowL7DataPtrInit(&f);
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
if (de_ctx == NULL) {
goto end;
}
de_ctx->flags |= DE_QUIET;
s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; content:\"one\"; http_client_body; sid:1; rev:1;)");
if (s == NULL) {
printf("sig parse failed: ");
goto end;
}
s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; content:\"two\"; http_client_body; sid:2; rev:1;)");
if (s == NULL) {
printf("sig2 parse failed: ");
goto end;
}
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1);
if (r != 0) {
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
if (PacketAlertCheck(p, 1)) {
printf("sig 1 alerted: ");
goto end;
}
p->alerts.cnt = 0;
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2);
if (r != 0) {
printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
if (PacketAlertCheck(p, 1)) {
printf("sig 1 alerted (2): ");
goto end;
}
p->alerts.cnt = 0;
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3);
if (r != 0) {
printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
if (PacketAlertCheck(p, 1)) {
printf("signature matched, but shouldn't have: ");
goto end;
}
p->alerts.cnt = 0;
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4);
if (r != 0) {
printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
result = 0;
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
if (!(PacketAlertCheck(p, 1))) {
printf("sig 1 didn't alert: ");
goto end;
}
p->alerts.cnt = 0;
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5);
if (r != 0) {
printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r);
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
if (PacketAlertCheck(p, 1)) {
printf("sig 1 alerted (5): ");
goto end;
}
p->alerts.cnt = 0;
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6);
if (r != 0) {
printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r);
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
if ((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))) {
printf("sig 1 alerted (request 2, chunk 6): ");
goto end;
}
p->alerts.cnt = 0;
SCLogDebug("sending data chunk 7");
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7);
if (r != 0) {
printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r);
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
if (!(PacketAlertCheck(p, 2))) {
printf("signature 2 didn't match, but should have: ");
goto end;
}
p->alerts.cnt = 0;
HtpState *htp_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
if (htp_state == NULL) {
printf("no http state: ");
result = 0;
goto end;
}
if (list_size(htp_state->connp->conn->transactions) != 2) {
printf("The http app layer doesn't have 2 transactions, but it should: ");
goto end;
}
result = 1;
end:
if (det_ctx != NULL) {
DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
}
if (de_ctx != NULL) {
SigGroupCleanup(de_ctx);
DetectEngineCtxFree(de_ctx);
}
FlowL7DataPtrFree(&f);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
UTHFreePacket(p);
return result;
}
/** \test multiple http transactions and body chunks of request handling */
static int DetectHttpClientBodyTest15(void) {
int result = 0;
Signature *s = NULL;
DetectEngineThreadCtx *det_ctx = NULL;
ThreadVars th_v;
Flow f;
TcpSession ssn;
Packet *p = NULL;
uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n";
uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\nContent-Length: 10\r\n";
uint8_t httpbuf3[] = "Cookie: dummy\r\n\r\n";
uint8_t httpbuf4[] = "Body one!!";
uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
uint8_t httpbuf5[] = "GET /?var=val HTTP/1.1\r\n";
uint8_t httpbuf6[] = "User-Agent: Firefox/1.0\r\n";
uint8_t httpbuf7[] = "Cookie: dummy2\r\nContent-Length: 10\r\n\r\nBody two!!";
uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
uint32_t httplen7 = sizeof(httpbuf7) - 1; /* minus the \0 */
memset(&th_v, 0, sizeof(th_v));
memset(&f, 0, sizeof(f));
memset(&ssn, 0, sizeof(ssn));
p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
FLOW_INITIALIZE(&f);
f.protoctx = (void *)&ssn;
f.proto = IPPROTO_TCP;
f.src.family = AF_INET;
f.dst.family = AF_INET;
p->flow = &f;
p->flowflags |= FLOW_PKT_TOSERVER;
p->flowflags |= FLOW_PKT_ESTABLISHED;
f.alproto = ALPROTO_HTTP;
StreamTcpInitConfig(TRUE);
FlowL7DataPtrInit(&f);
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
if (de_ctx == NULL) {
goto end;
}
de_ctx->flags |= DE_QUIET;
s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; content:\"one\"; http_client_body; sid:1; rev:1;)");
if (s == NULL) {
printf("sig parse failed: ");
goto end;
}
s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; content:\"two\"; http_client_body; sid:2; rev:1;)");
if (s == NULL) {
printf("sig2 parse failed: ");
goto end;
}
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1);
if (r != 0) {
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
if (PacketAlertCheck(p, 1)) {
printf("sig 1 alerted: ");
goto end;
}
p->alerts.cnt = 0;
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2);
if (r != 0) {
printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
if (PacketAlertCheck(p, 1)) {
printf("sig 1 alerted (2): ");
goto end;
}
p->alerts.cnt = 0;
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3);
if (r != 0) {
printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
if (PacketAlertCheck(p, 1)) {
printf("signature matched, but shouldn't have: ");
goto end;
}
p->alerts.cnt = 0;
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4);
if (r != 0) {
printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
result = 0;
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
if (!(PacketAlertCheck(p, 1))) {
printf("sig 1 didn't alert: ");
goto end;
}
p->alerts.cnt = 0;
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5);
if (r != 0) {
printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r);
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
if (PacketAlertCheck(p, 1)) {
printf("sig 1 alerted (5): ");
goto end;
}
p->alerts.cnt = 0;
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6);
if (r != 0) {
printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r);
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
if ((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))) {
printf("sig 1 alerted (request 2, chunk 6): ");
goto end;
}
p->alerts.cnt = 0;
SCLogDebug("sending data chunk 7");
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7);
if (r != 0) {
printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r);
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
if (!(PacketAlertCheck(p, 2))) {
printf("signature 2 didn't match, but should have: ");
goto end;
}
p->alerts.cnt = 0;
HtpState *htp_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
if (htp_state == NULL) {
printf("no http state: ");
result = 0;
goto end;
}
/* hardcoded check of the transactions and it's client body chunks */
if (list_size(htp_state->connp->conn->transactions) != 2) {
printf("The http app layer doesn't have 2 transactions, but it should: ");
goto end;
}
htp_tx_t *t1 = list_get(htp_state->connp->conn->transactions, 0);
htp_tx_t *t2 = list_get(htp_state->connp->conn->transactions, 1);
SCHtpTxUserData *htud = (SCHtpTxUserData *) htp_tx_get_user_data(t1);
HtpBodyChunk *cur = htud->body.first;
if (htud->body.nchunks == 0) {
SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): ");
goto end;
}
if (memcmp(cur->data, "Body one!!", strlen("Body one!!")) != 0) {
SCLogDebug("Body data in t1 is not correctly set: ");
goto end;
}
htud = (SCHtpTxUserData *) htp_tx_get_user_data(t2);
cur = htud->body.first;
if (htud->body.nchunks == 0) {
SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): ");
goto end;
}
if (memcmp(cur->data, "Body two!!", strlen("Body two!!")) != 0) {
SCLogDebug("Body data in t1 is not correctly set: ");
goto end;
}
result = 1;
end:
if (det_ctx != NULL) {
DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
}
if (de_ctx != NULL) {
SigGroupCleanup(de_ctx);
DetectEngineCtxFree(de_ctx);
}
FlowL7DataPtrFree(&f);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
UTHFreePacket(p);
return result;
}
#endif /* UNITTESTS */
void DetectHttpClientBodyRegisterTests(void)
@ -1338,6 +1775,8 @@ void DetectHttpClientBodyRegisterTests(void)
UtRegisterTest("DetectHttpClientBodyTest11", DetectHttpClientBodyTest11, 1);
UtRegisterTest("DetectHttpClientBodyTest12", DetectHttpClientBodyTest12, 1);
UtRegisterTest("DetectHttpClientBodyTest13", DetectHttpClientBodyTest13, 1);
UtRegisterTest("DetectHttpClientBodyTest14", DetectHttpClientBodyTest14, 1);
UtRegisterTest("DetectHttpClientBodyTest15", DetectHttpClientBodyTest15, 1);
#endif /* UNITTESTS */
return;

@ -567,60 +567,77 @@ int DetectPcreALDoMatch(DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch *
if (htp_state == NULL) {
SCLogDebug("No htp state, no match at http body data");
goto unlock;
} else if (htp_state->body.nchunks == 0) {
SCLogDebug("No body data to inspect");
goto unlock;
} else {
pcreret = 0;
int wspace[255];
int flags = PCRE_PARTIAL;
}
htp_tx_t *tx = NULL;
size_t idx = 0;
for (idx = 0;//hs->new_in_tx_index;
idx < list_size(htp_state->connp->conn->transactions); idx++)
{
tx = list_get(htp_state->connp->conn->transactions, idx);
if (tx == NULL)
continue;
HtpBodyChunk *cur = htp_state->body.first;
if (cur == NULL) {
SCLogDebug("No body chunks to inspect");
SCHtpTxUserData *htud = (SCHtpTxUserData *) htp_tx_get_user_data(tx);
if (htud == NULL)
continue;
HtpBodyChunk *cur = htud->body.first;
if (htud->body.nchunks == 0) {
SCLogDebug("No body data to inspect");
goto unlock;
}
htp_state->body.pcre_flags |= HTP_PCRE_DONE;
} else {
pcreret = 0;
int wspace[255];
int flags = PCRE_PARTIAL;
while (cur != NULL) {
if (SCLogDebugEnabled()) {
printf("\n");
PrintRawUriFp(stdout, (uint8_t*)cur->data, cur->len);
printf("\n");
if (cur == NULL) {
SCLogDebug("No body chunks to inspect");
goto unlock;
}
pcreret = pcre_dfa_exec(pe->re, NULL, (char*)cur->data, cur->len, 0,
flags|PCRE_DFA_SHORTEST, ov, MAX_SUBSTRINGS,
wspace, MAX_SUBSTRINGS);
cur = cur->next;
SCLogDebug("Pcre Ret %d", pcreret);
switch (pcreret) {
case PCRE_ERROR_PARTIAL:
/* make pcre to use the working space of the last partial
* match, (match over multiple chunks)
*/
SCLogDebug("partial match");
flags |= PCRE_DFA_RESTART;
htp_state->body.pcre_flags |= HTP_PCRE_HAS_MATCH;
break;
case PCRE_ERROR_NOMATCH:
SCLogDebug("no match");
flags = PCRE_PARTIAL;
break;
case 0:
SCLogDebug("Perfect Match!");
ret = 1;
goto unlock;
break;
default:
if (pcreret > 0) {
SCLogDebug("Match with captured data");
htud->body.pcre_flags |= HTP_PCRE_DONE;
while (cur != NULL) {
if (SCLogDebugEnabled()) {
printf("\n");
PrintRawUriFp(stdout, (uint8_t*)cur->data, cur->len);
printf("\n");
}
pcreret = pcre_dfa_exec(pe->re, NULL, (char*)cur->data, cur->len, 0,
flags|PCRE_DFA_SHORTEST, ov, MAX_SUBSTRINGS,
wspace, MAX_SUBSTRINGS);
cur = cur->next;
SCLogDebug("Pcre Ret %d", pcreret);
switch (pcreret) {
case PCRE_ERROR_PARTIAL:
/* make pcre to use the working space of the last partial
* match, (match over multiple chunks)
*/
SCLogDebug("partial match");
flags |= PCRE_DFA_RESTART;
htud->body.pcre_flags |= HTP_PCRE_HAS_MATCH;
break;
case PCRE_ERROR_NOMATCH:
SCLogDebug("no match");
flags = PCRE_PARTIAL;
break;
case 0:
SCLogDebug("Perfect Match!");
ret = 1;
} else {
SCLogDebug("No match, pcre failed");
ret = 0;
}
goto unlock;
goto unlock;
break;
default:
if (pcreret > 0) {
SCLogDebug("Match with captured data");
ret = 1;
} else {
SCLogDebug("No match, pcre failed");
ret = 0;
}
goto unlock;
}
}
}
}
@ -2189,13 +2206,6 @@ static int DetectPcreModifPTest05(void) {
/* do detect for p1 */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p1);
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2);
if (r != 0) {
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
result = 0;
goto end;
}
HtpState *http_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
if (http_state == NULL) {
printf("no http state: ");
@ -2203,9 +2213,6 @@ static int DetectPcreModifPTest05(void) {
goto end;
}
/* do detect for p2 */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
if (!(PacketAlertCheck(p1, 1))) {
printf("sid 1 didn't match on p1 but should have: ");
goto end;
@ -2217,6 +2224,16 @@ static int DetectPcreModifPTest05(void) {
goto end;
}
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2);
if (r != 0) {
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
result = 0;
goto end;
}
/* do detect for p2 */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p2);
if ((PacketAlertCheck(p2, 1))) {
printf("sid 1 did match on p2 but should have: ");
goto end;
@ -2842,6 +2859,572 @@ end:
return result;
}
/** \test Test tracking of body chunks per transactions (on requests)
*/
static int DetectPcreTxBodyChunksTest01(void) {
int result = 0;
Flow f;
TcpSession ssn;
Packet *p = NULL;
uint8_t httpbuf1[] = "GET / HTTP/1.1\r\n";
uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\nContent-Length: 10\r\n";
uint8_t httpbuf3[] = "Cookie: dummy\r\n\r\n";
uint8_t httpbuf4[] = "Body one!!";
uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
uint8_t httpbuf5[] = "GET /?var=val HTTP/1.1\r\n";
uint8_t httpbuf6[] = "User-Agent: Firefox/1.0\r\n";
uint8_t httpbuf7[] = "Cookie: dummy2\r\nContent-Length: 10\r\n\r\nBody two!!";
uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
uint32_t httplen7 = sizeof(httpbuf7) - 1; /* minus the \0 */
memset(&f, 0, sizeof(f));
memset(&ssn, 0, sizeof(ssn));
p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
FLOW_INITIALIZE(&f);
f.protoctx = (void *)&ssn;
f.proto = IPPROTO_TCP;
f.src.family = AF_INET;
f.dst.family = AF_INET;
p->flow = &f;
p->flowflags |= FLOW_PKT_TOSERVER;
p->flowflags |= FLOW_PKT_ESTABLISHED;
f.alproto = ALPROTO_HTTP;
StreamTcpInitConfig(TRUE);
FlowL7DataPtrInit(&f);
AppLayerHtpEnableRequestBodyCallback();
int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1);
if (r != 0) {
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
goto end;
}
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2);
if (r != 0) {
printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
goto end;
}
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3);
if (r != 0) {
printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
goto end;
}
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4);
if (r != 0) {
printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
result = 0;
goto end;
}
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5);
if (r != 0) {
printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r);
goto end;
}
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6);
if (r != 0) {
printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r);
goto end;
}
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7);
if (r != 0) {
printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r);
goto end;
}
/* Now we should have 2 transactions, each with it's own list
* of request body chunks (let's test it) */
HtpState *htp_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
if (htp_state == NULL) {
printf("no http state: ");
result = 0;
goto end;
}
/* hardcoded check of the transactions and it's client body chunks */
if (list_size(htp_state->connp->conn->transactions) != 2) {
printf("The http app layer doesn't have 2 transactions, but it should: ");
goto end;
}
htp_tx_t *t1 = list_get(htp_state->connp->conn->transactions, 0);
htp_tx_t *t2 = list_get(htp_state->connp->conn->transactions, 1);
SCHtpTxUserData *htud = (SCHtpTxUserData *) htp_tx_get_user_data(t1);
if (htud == NULL) {
printf("No body data in t1 (it should be removed only when the tx is destroyed): ");
goto end;
}
HtpBodyChunk *cur = htud->body.first;
if (htud->body.nchunks == 0) {
SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): ");
goto end;
}
if (memcmp(cur->data, "Body one!!", strlen("Body one!!")) != 0) {
SCLogDebug("Body data in t1 is not correctly set: ");
goto end;
}
htud = (SCHtpTxUserData *) htp_tx_get_user_data(t2);
cur = htud->body.first;
if (htud->body.nchunks == 0) {
SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): ");
goto end;
}
if (memcmp(cur->data, "Body two!!", strlen("Body two!!")) != 0) {
SCLogDebug("Body data in t1 is not correctly set: ");
goto end;
}
FlowL7DataPtrFree(&f);
result = 1;
end:
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
UTHFreePacket(p);
return result;
}
/** \test test pcre P modifier with multiple pipelined http transactions */
static int DetectPcreTxBodyChunksTest02(void) {
int result = 0;
Signature *s = NULL;
DetectEngineThreadCtx *det_ctx = NULL;
ThreadVars th_v;
Flow f;
TcpSession ssn;
Packet *p = NULL;
uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n";
uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\nContent-Length: 10\r\n";
uint8_t httpbuf3[] = "Cookie: dummy\r\n\r\n";
uint8_t httpbuf4[] = "Body one!!";
uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
uint8_t httpbuf5[] = "GET /?var=val HTTP/1.1\r\n";
uint8_t httpbuf6[] = "User-Agent: Firefox/1.0\r\n";
uint8_t httpbuf7[] = "Cookie: dummy2\r\nContent-Length: 10\r\n\r\nBody two!!";
uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
uint32_t httplen7 = sizeof(httpbuf7) - 1; /* minus the \0 */
memset(&th_v, 0, sizeof(th_v));
memset(&f, 0, sizeof(f));
memset(&ssn, 0, sizeof(ssn));
p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
FLOW_INITIALIZE(&f);
f.protoctx = (void *)&ssn;
f.proto = IPPROTO_TCP;
f.src.family = AF_INET;
f.dst.family = AF_INET;
p->flow = &f;
p->flowflags |= FLOW_PKT_TOSERVER;
p->flowflags |= FLOW_PKT_ESTABLISHED;
f.alproto = ALPROTO_HTTP;
StreamTcpInitConfig(TRUE);
FlowL7DataPtrInit(&f);
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
if (de_ctx == NULL) {
goto end;
}
de_ctx->flags |= DE_QUIET;
s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; pcre:\"/one/P\"; sid:1; rev:1;)");
if (s == NULL) {
printf("sig parse failed: ");
goto end;
}
s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; pcre:\"/two/P\"; sid:2; rev:1;)");
if (s == NULL) {
printf("sig2 parse failed: ");
goto end;
}
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1);
if (r != 0) {
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
if (PacketAlertCheck(p, 1)) {
printf("sig 1 alerted: ");
goto end;
}
p->alerts.cnt = 0;
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2);
if (r != 0) {
printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
if (PacketAlertCheck(p, 1)) {
printf("sig 1 alerted (2): ");
goto end;
}
p->alerts.cnt = 0;
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3);
if (r != 0) {
printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
if (PacketAlertCheck(p, 1)) {
printf("signature matched, but shouldn't have: ");
goto end;
}
p->alerts.cnt = 0;
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4);
if (r != 0) {
printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
result = 0;
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
if (!(PacketAlertCheck(p, 1))) {
printf("sig 1 didn't alert: ");
goto end;
}
p->alerts.cnt = 0;
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5);
if (r != 0) {
printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r);
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
if (PacketAlertCheck(p, 1)) {
printf("sig 1 alerted (5): ");
goto end;
}
p->alerts.cnt = 0;
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6);
if (r != 0) {
printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r);
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
if ((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))) {
printf("sig 1 alerted (request 2, chunk 6): ");
goto end;
}
p->alerts.cnt = 0;
SCLogDebug("sending data chunk 7");
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7);
if (r != 0) {
printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r);
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
if (!(PacketAlertCheck(p, 2))) {
printf("signature 2 didn't match, but should have: ");
goto end;
}
p->alerts.cnt = 0;
HtpState *htp_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
if (htp_state == NULL) {
printf("no http state: ");
result = 0;
goto end;
}
/* hardcoded check of the transactions and it's client body chunks */
if (list_size(htp_state->connp->conn->transactions) != 2) {
printf("The http app layer doesn't have 2 transactions, but it should: ");
goto end;
}
htp_tx_t *t1 = list_get(htp_state->connp->conn->transactions, 0);
htp_tx_t *t2 = list_get(htp_state->connp->conn->transactions, 1);
SCHtpTxUserData *htud = (SCHtpTxUserData *) htp_tx_get_user_data(t1);
HtpBodyChunk *cur = htud->body.first;
if (htud->body.nchunks == 0) {
SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): ");
goto end;
}
if (memcmp(cur->data, "Body one!!", strlen("Body one!!")) != 0) {
SCLogDebug("Body data in t1 is not correctly set: ");
goto end;
}
htud = (SCHtpTxUserData *) htp_tx_get_user_data(t2);
cur = htud->body.first;
if (htud->body.nchunks == 0) {
SCLogDebug("No body data in t1 (it should be removed only when the tx is destroyed): ");
goto end;
}
if (memcmp(cur->data, "Body two!!", strlen("Body two!!")) != 0) {
SCLogDebug("Body data in t1 is not correctly set: ");
goto end;
}
result = 1;
end:
if (det_ctx != NULL) {
DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
}
if (de_ctx != NULL) {
SigGroupCleanup(de_ctx);
DetectEngineCtxFree(de_ctx);
}
FlowL7DataPtrFree(&f);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
UTHFreePacket(p);
return result;
}
/** \test multiple http transactions and body chunks of request handling */
static int DetectPcreTxBodyChunksTest03(void) {
int result = 0;
Signature *s = NULL;
DetectEngineThreadCtx *det_ctx = NULL;
ThreadVars th_v;
Flow f;
TcpSession ssn;
Packet *p = NULL;
uint8_t httpbuf1[] = "POST / HTTP/1.1\r\n";
uint8_t httpbuf2[] = "User-Agent: Mozilla/1.0\r\nContent-Length: 10\r\n";
uint8_t httpbuf3[] = "Cookie: dummy\r\n\r\n";
uint8_t httpbuf4[] = "Body one!!";
uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
uint8_t httpbuf5[] = "GET /?var=val HTTP/1.1\r\n";
uint8_t httpbuf6[] = "User-Agent: Firefox/1.0\r\n";
uint8_t httpbuf7[] = "Cookie: dummy2\r\nContent-Length: 10\r\n\r\nBody two!!";
uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
uint32_t httplen6 = sizeof(httpbuf6) - 1; /* minus the \0 */
uint32_t httplen7 = sizeof(httpbuf7) - 1; /* minus the \0 */
memset(&th_v, 0, sizeof(th_v));
memset(&f, 0, sizeof(f));
memset(&ssn, 0, sizeof(ssn));
p = UTHBuildPacket(NULL, 0, IPPROTO_TCP);
FLOW_INITIALIZE(&f);
f.protoctx = (void *)&ssn;
f.proto = IPPROTO_TCP;
f.src.family = AF_INET;
f.dst.family = AF_INET;
p->flow = &f;
p->flowflags |= FLOW_PKT_TOSERVER;
p->flowflags |= FLOW_PKT_ESTABLISHED;
f.alproto = ALPROTO_HTTP;
StreamTcpInitConfig(TRUE);
FlowL7DataPtrInit(&f);
DetectEngineCtx *de_ctx = DetectEngineCtxInit();
if (de_ctx == NULL) {
goto end;
}
de_ctx->flags |= DE_QUIET;
s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"POST\"; http_method; content:\"Mozilla\"; http_header; content:\"dummy\"; http_cookie; pcre:\"/one/P\"; sid:1; rev:1;)");
if (s == NULL) {
printf("sig parse failed: ");
goto end;
}
s = DetectEngineAppendSig(de_ctx, "alert tcp any any -> any any (content:\"GET\"; http_method; content:\"Firefox\"; http_header; content:\"dummy2\"; http_cookie; pcre:\"/two/P\"; sid:2; rev:1;)");
if (s == NULL) {
printf("sig2 parse failed: ");
goto end;
}
SigGroupBuild(de_ctx);
DetectEngineThreadCtxInit(&th_v, (void *)de_ctx, (void *)&det_ctx);
int r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1);
if (r != 0) {
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
if (PacketAlertCheck(p, 1)) {
printf("sig 1 alerted: ");
goto end;
}
p->alerts.cnt = 0;
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2);
if (r != 0) {
printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
if (PacketAlertCheck(p, 1)) {
printf("sig 1 alerted (2): ");
goto end;
}
p->alerts.cnt = 0;
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf3, httplen3);
if (r != 0) {
printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
if (PacketAlertCheck(p, 1)) {
printf("signature matched, but shouldn't have: ");
goto end;
}
p->alerts.cnt = 0;
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf4, httplen4);
if (r != 0) {
printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
result = 0;
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
if (!(PacketAlertCheck(p, 1))) {
printf("sig 1 didn't alert: ");
goto end;
}
p->alerts.cnt = 0;
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf5, httplen5);
if (r != 0) {
printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r);
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
if (PacketAlertCheck(p, 1)) {
printf("sig 1 alerted (5): ");
goto end;
}
p->alerts.cnt = 0;
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf6, httplen6);
if (r != 0) {
printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r);
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
if ((PacketAlertCheck(p, 1)) || (PacketAlertCheck(p, 2))) {
printf("sig 1 alerted (request 2, chunk 6): ");
goto end;
}
p->alerts.cnt = 0;
SCLogDebug("sending data chunk 7");
r = AppLayerParse(&f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf7, httplen7);
if (r != 0) {
printf("toserver chunk 7 returned %" PRId32 ", expected 0: ", r);
goto end;
}
/* do detect */
SigMatchSignatures(&th_v, de_ctx, det_ctx, p);
if (!(PacketAlertCheck(p, 2))) {
printf("signature 2 didn't match, but should have: ");
goto end;
}
p->alerts.cnt = 0;
HtpState *htp_state = f.aldata[AlpGetStateIdx(ALPROTO_HTTP)];
if (htp_state == NULL) {
printf("no http state: ");
result = 0;
goto end;
}
if (list_size(htp_state->connp->conn->transactions) != 2) {
printf("The http app layer doesn't have 2 transactions, but it should: ");
goto end;
}
result = 1;
end:
if (det_ctx != NULL) {
DetectEngineThreadCtxDeinit(&th_v, (void *)det_ctx);
}
if (de_ctx != NULL) {
SigGroupCleanup(de_ctx);
DetectEngineCtxFree(de_ctx);
}
FlowL7DataPtrFree(&f);
StreamTcpFreeConfig(TRUE);
FLOW_DESTROY(&f);
UTHFreePacket(p);
return result;
}
#endif /* UNITTESTS */
/**
@ -2880,6 +3463,9 @@ void DetectPcreRegisterTests(void) {
UtRegisterTest("DetectPcreTestSig12 -- negated Method modifier", DetectPcreTestSig12, 1);
UtRegisterTest("DetectPcreTestSig13 -- Header modifier", DetectPcreTestSig13, 1);
UtRegisterTest("DetectPcreTestSig14 -- negated Header modifier", DetectPcreTestSig14, 1);
UtRegisterTest("DetectPcreTxBodyChunksTest01", DetectPcreTxBodyChunksTest01, 1);
UtRegisterTest("DetectPcreTxBodyChunksTest02 -- modifier P, body chunks per tx", DetectPcreTxBodyChunksTest02, 1);
UtRegisterTest("DetectPcreTxBodyChunksTest03 -- modifier P, body chunks per tx", DetectPcreTxBodyChunksTest03, 1);
#endif /* UNITTESTS */
}

@ -52,7 +52,7 @@ SC_ATOMIC_EXTERN(unsigned int, engine_stage);
ptrmem = malloc(a); \
if (ptrmem == NULL && a > 0) { \
SCLogError(SC_ERR_MEM_ALLOC, "SCMalloc failed: %s, while trying " \
"to allocate %"PRIdMAX" bytes", strerror(errno), (intmax_t)a); \
"to allocate %Zu bytes", strerror(errno), (size_t)a); \
if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) {\
SCLogError(SC_ERR_FATAL, "Out of memory. The engine cannot be initialized. Exiting..."); \
exit(EXIT_FAILURE); \
@ -62,7 +62,7 @@ SC_ATOMIC_EXTERN(unsigned int, engine_stage);
global_mem += a; \
if (print_mem_flag == 1) \
SCLogInfo("SCMalloc return at %p of size %"PRIdMAX, \
ptrmem, (intmax_t)a); \
ptrmem, (size_t)a); \
\
(void*)ptrmem; \
})
@ -75,7 +75,7 @@ SC_ATOMIC_EXTERN(unsigned int, engine_stage);
ptrmem = realloc(x, a); \
if (ptrmem == NULL && a > 0) { \
SCLogError(SC_ERR_MEM_ALLOC, "SCRealloc failed: %s, while trying " \
"to allocate %"PRIdMAX" bytes", strerror(errno), (intmax_t)a); \
"to allocate %Zu bytes", strerror(errno), (size_t)a); \
if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) {\
SCLogError(SC_ERR_FATAL, "Out of memory. The engine cannot be initialized. Exiting..."); \
exit(EXIT_FAILURE); \
@ -85,7 +85,7 @@ SC_ATOMIC_EXTERN(unsigned int, engine_stage);
global_mem += a; \
if (print_mem_flag == 1) \
SCLogInfo("SCRealloc return at %p (old:%p) of size %"PRIdMAX, \
ptrmem, x, (intmax_t)a); \
ptrmem, x, (size_t)a); \
\
(void*)ptrmem; \
})
@ -98,7 +98,7 @@ SC_ATOMIC_EXTERN(unsigned int, engine_stage);
ptrmem = calloc(nm, a); \
if (ptrmem == NULL && a > 0) { \
SCLogError(SC_ERR_MEM_ALLOC, "SCCalloc failed: %s, while trying " \
"to allocate %"PRIdMAX" bytes", strerror(errno), (intmax_t)a); \
"to allocate %Zu bytes", strerror(errno), (size_t)a); \
if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) {\
SCLogError(SC_ERR_FATAL, "Out of memory. The engine cannot be initialized. Exiting..."); \
exit(EXIT_FAILURE); \
@ -107,8 +107,8 @@ SC_ATOMIC_EXTERN(unsigned int, engine_stage);
\
global_mem += a*nm; \
if (print_mem_flag == 1) \
SCLogInfo("SCCalloc return at %p of size %"PRIdMAX" nm %"PRIdMAX, \
ptrmem, (intmax_t)a, (intmax_t)nm); \
SCLogInfo("SCCalloc return at %p of size %Zu nm %"PRIdMAX, \
ptrmem, (size_t)a, (size_t)nm); \
\
(void*)ptrmem; \
})
@ -117,12 +117,12 @@ SC_ATOMIC_EXTERN(unsigned int, engine_stage);
char *ptrmem = NULL; \
extern size_t global_mem; \
extern uint8_t print_mem_flag; \
size_t len = strlen(a); \
\
ptrmem = strdup(a); \
if (ptrmem == NULL && len > 0) { \
if (ptrmem == NULL) { \
size_t len = strlen(a); \
SCLogError(SC_ERR_MEM_ALLOC, "SCStrdup failed: %s, while trying " \
"to allocate %"PRIu64" bytes", strerror(errno), (intmax_t)len); \
"to allocate %"PRIuMAX" bytes", strerror(errno), (size_t)len); \
if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) {\
SCLogError(SC_ERR_FATAL, "Out of memory. The engine cannot be initialized. Exiting..."); \
exit(EXIT_FAILURE); \
@ -132,7 +132,7 @@ SC_ATOMIC_EXTERN(unsigned int, engine_stage);
global_mem += len; \
if (print_mem_flag == 1) \
SCLogInfo("SCStrdup return at %p of size %"PRIdMAX, \
ptrmem, (intmax_t)len); \
ptrmem, (size_t)len); \
\
(void*)ptrmem; \
})
@ -160,7 +160,7 @@ SC_ATOMIC_EXTERN(unsigned int, engine_stage);
ptrmem = malloc(a); \
if (ptrmem == NULL && a > 0) { \
SCLogError(SC_ERR_MEM_ALLOC, "SCMalloc failed: %s, while trying " \
"to allocate %"PRIdMAX" bytes", strerror(errno), (intmax_t)a); \
"to allocate %Zu bytes", strerror(errno), (size_t)a); \
if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) {\
SCLogError(SC_ERR_FATAL, "Out of memory. The engine cannot be initialized. Exiting..."); \
exit(EXIT_FAILURE); \
@ -175,7 +175,7 @@ SC_ATOMIC_EXTERN(unsigned int, engine_stage);
ptrmem = realloc(x, a); \
if (ptrmem == NULL && a > 0) { \
SCLogError(SC_ERR_MEM_ALLOC, "SCRealloc failed: %s, while trying " \
"to allocate %"PRIdMAX" bytes", strerror(errno), (intmax_t)a); \
"to allocate %Zu bytes", strerror(errno), (size_t)a); \
if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) {\
SCLogError(SC_ERR_FATAL, "Out of memory. The engine cannot be initialized. Exiting..."); \
exit(EXIT_FAILURE); \
@ -190,7 +190,7 @@ SC_ATOMIC_EXTERN(unsigned int, engine_stage);
ptrmem = calloc(nm, a); \
if (ptrmem == NULL && a > 0) { \
SCLogError(SC_ERR_MEM_ALLOC, "SCCalloc failed: %s, while trying " \
"to allocate %"PRIdMAX" bytes", strerror(errno), (intmax_t)a); \
"to allocate %Zu bytes", strerror(errno), (size_t)a); \
if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) {\
SCLogError(SC_ERR_FATAL, "Out of memory. The engine cannot be initialized. Exiting..."); \
exit(EXIT_FAILURE); \
@ -201,12 +201,12 @@ SC_ATOMIC_EXTERN(unsigned int, engine_stage);
#define SCStrdup(a) ({ \
char *ptrmem = NULL; \
size_t len = strlen(a); \
\
ptrmem = strdup(a); \
if (ptrmem == NULL && len > 0) { \
if (ptrmem == NULL) { \
size_t len = strlen(a); \
SCLogError(SC_ERR_MEM_ALLOC, "SCStrdup failed: %s, while trying " \
"to allocate %"PRIu64" bytes", strerror(errno), (intmax_t)len); \
"to allocate %"PRIuMAX" bytes", strerror(errno), (size_t)len); \
if (SC_ATOMIC_GET(engine_stage) == SURICATA_INIT) {\
SCLogError(SC_ERR_FATAL, "Out of memory. The engine cannot be initialized. Exiting..."); \
exit(EXIT_FAILURE); \

Loading…
Cancel
Save