aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/suricata/src
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/suricata/src')
-rw-r--r--framework/src/suricata/src/Makefile.am2
-rw-r--r--framework/src/suricata/src/app-layer-dns-common.c2
-rw-r--r--framework/src/suricata/src/app-layer-htp.c432
-rw-r--r--framework/src/suricata/src/app-layer-smtp.c7
-rw-r--r--framework/src/suricata/src/app-layer-ssl.c101
-rw-r--r--framework/src/suricata/src/app-layer-ssl.h6
-rw-r--r--framework/src/suricata/src/detect-engine-content-inspection.c18
-rw-r--r--framework/src/suricata/src/detect-engine-content-inspection.h1
-rw-r--r--framework/src/suricata/src/detect-engine.c441
-rw-r--r--framework/src/suricata/src/detect-engine.h2
-rw-r--r--framework/src/suricata/src/detect-parse.c15
-rw-r--r--framework/src/suricata/src/detect.c19
-rw-r--r--framework/src/suricata/src/detect.h11
-rw-r--r--framework/src/suricata/src/log-tlslog.c3
-rw-r--r--framework/src/suricata/src/output-json-tls.c6
-rw-r--r--framework/src/suricata/src/output-json.c7
-rw-r--r--framework/src/suricata/src/runmode-unittests.c1
-rw-r--r--framework/src/suricata/src/suricata.c19
-rw-r--r--framework/src/suricata/src/suricata.h2
-rw-r--r--framework/src/suricata/src/util-base64.c19
-rw-r--r--framework/src/suricata/src/util-base64.h3
-rw-r--r--framework/src/suricata/src/util-decode-mime.c6
-rw-r--r--framework/src/suricata/src/util-error.c2
-rw-r--r--framework/src/suricata/src/util-error.h3
-rw-r--r--framework/src/suricata/src/util-logopenfile.c4
-rw-r--r--framework/src/suricata/src/util-logopenfile.h1
-rw-r--r--framework/src/suricata/src/util-lua-tls.c41
-rw-r--r--framework/src/suricata/src/util-profiling-locks.c6
-rw-r--r--framework/src/suricata/src/util-rule-vars.c2
29 files changed, 879 insertions, 303 deletions
diff --git a/framework/src/suricata/src/Makefile.am b/framework/src/suricata/src/Makefile.am
index 98e094c1..4af253a8 100644
--- a/framework/src/suricata/src/Makefile.am
+++ b/framework/src/suricata/src/Makefile.am
@@ -71,6 +71,8 @@ detect-ack.c detect-ack.h \
detect-app-layer-event.c detect-app-layer-event.h \
detect-app-layer-protocol.c detect-app-layer-protocol.h \
detect-asn1.c detect-asn1.h \
+detect-base64-data.c detect-base64-data.h \
+detect-base64-decode.c detect-base64-decode.h \
detect-byte-extract.c detect-byte-extract.h \
detect-bytejump.c detect-bytejump.h \
detect-bytetest.c detect-bytetest.h \
diff --git a/framework/src/suricata/src/app-layer-dns-common.c b/framework/src/suricata/src/app-layer-dns-common.c
index 4a3f9ccd..3c67fe44 100644
--- a/framework/src/suricata/src/app-layer-dns-common.c
+++ b/framework/src/suricata/src/app-layer-dns-common.c
@@ -979,7 +979,7 @@ const uint8_t *DNSReponseParse(DNSState *dns_state, const DNSHeader * const dns_
do {
//PrintRawDataFp(stdout, (uint8_t*)tdata, txtlen);
- if (txtlen > datalen)
+ if (txtlen >= datalen)
goto bad_data;
DNSStoreAnswerInState(dns_state, list, fqdn, fqdn_len,
diff --git a/framework/src/suricata/src/app-layer-htp.c b/framework/src/suricata/src/app-layer-htp.c
index 0abcda3b..e8da88eb 100644
--- a/framework/src/suricata/src/app-layer-htp.c
+++ b/framework/src/suricata/src/app-layer-htp.c
@@ -2824,7 +2824,7 @@ void HtpConfigRestoreBackup(void)
* response of the parser from HTP library. */
int HTPParserTest01(void)
{
- int result = 1;
+ int result = 0;
Flow *f = NULL;
uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost"
" Data is c0oL!";
@@ -2860,7 +2860,6 @@ int HTPParserTest01(void)
if (r != 0) {
printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
" 0: ", u, r);
- result = 0;
SCMutexUnlock(&f->m);
goto end;
}
@@ -2870,7 +2869,6 @@ int HTPParserTest01(void)
htp_state = f->alstate;
if (htp_state == NULL) {
printf("no http state: ");
- result = 0;
goto end;
}
@@ -2885,10 +2883,10 @@ int HTPParserTest01(void)
" and got: %s \n", bstr_util_strdup_to_c(h->value),
bstr_util_strdup_to_c(tx->request_method),
bstr_util_strdup_to_c(tx->request_protocol));
- result = 0;
goto end;
}
+ result = 1;
end:
if (alp_tctx != NULL)
AppLayerParserThreadCtxFree(alp_tctx);
@@ -2903,7 +2901,7 @@ end:
* response of the parser from HTP library. */
static int HTPParserTest01a(void)
{
- int result = 1;
+ int result = 0;
Flow *f = NULL;
uint8_t httpbuf1[] = " POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\nPost"
" Data is c0oL!";
@@ -2939,7 +2937,6 @@ static int HTPParserTest01a(void)
if (r != 0) {
printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
" 0: ", u, r);
- result = 0;
SCMutexUnlock(&f->m);
goto end;
}
@@ -2949,7 +2946,6 @@ static int HTPParserTest01a(void)
htp_state = f->alstate;
if (htp_state == NULL) {
printf("no http state: ");
- result = 0;
goto end;
}
@@ -2964,10 +2960,9 @@ static int HTPParserTest01a(void)
" and got: %s \n", bstr_util_strdup_to_c(h->value),
bstr_util_strdup_to_c(tx->request_method),
bstr_util_strdup_to_c(tx->request_protocol));
- result = 0;
goto end;
}
-
+ result = 1;
end:
if (alp_tctx != NULL)
AppLayerParserThreadCtxFree(alp_tctx);
@@ -2981,7 +2976,7 @@ end:
/** \test See how it deals with an incomplete request. */
int HTPParserTest02(void)
{
- int result = 1;
+ int result = 0;
Flow *f = NULL;
uint8_t httpbuf1[] = "POST";
uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
@@ -3004,7 +2999,6 @@ int HTPParserTest02(void)
STREAM_EOF, httpbuf1, httplen1);
if (r != 0) {
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- result = 0;
SCMutexUnlock(&f->m);
goto end;
}
@@ -3013,7 +3007,6 @@ int HTPParserTest02(void)
http_state = f->alstate;
if (http_state == NULL) {
printf("no http state: ");
- result = 0;
goto end;
}
@@ -3022,10 +3015,9 @@ int HTPParserTest02(void)
if ((tx->request_method) != NULL || h != NULL)
{
printf("expected method NULL, got %s \n", bstr_util_strdup_to_c(tx->request_method));
- result = 0;
goto end;
}
-
+ result = 1;
end:
if (alp_tctx != NULL)
AppLayerParserThreadCtxFree(alp_tctx);
@@ -3040,12 +3032,11 @@ end:
* and check the response of the parser from HTP library. */
int HTPParserTest03(void)
{
- int result = 1;
+ int result = 0;
Flow *f = NULL;
uint8_t httpbuf1[] = "HELLO / HTTP/1.0\r\n";
uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
TcpSession ssn;
-
HtpState *htp_state = NULL;
int r = 0;
AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
@@ -3073,7 +3064,6 @@ int HTPParserTest03(void)
if (r != 0) {
printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
" 0: ", u, r);
- result = 0;
SCMutexUnlock(&f->m);
goto end;
}
@@ -3082,7 +3072,6 @@ int HTPParserTest03(void)
htp_state = f->alstate;
if (htp_state == NULL) {
printf("no http state: ");
- result = 0;
goto end;
}
@@ -3095,10 +3084,9 @@ int HTPParserTest03(void)
printf("expected method M_UNKNOWN and got %s: , expected protocol "
"HTTP/1.0 and got %s \n", bstr_util_strdup_to_c(tx->request_method),
bstr_util_strdup_to_c(tx->request_protocol));
- result = 0;
goto end;
}
-
+ result = 1;
end:
if (alp_tctx != NULL)
AppLayerParserThreadCtxFree(alp_tctx);
@@ -3113,7 +3101,7 @@ end:
* parser from HTP library. */
int HTPParserTest04(void)
{
- int result = 1;
+ int result = 0;
Flow *f = NULL;
HtpState *htp_state = NULL;
uint8_t httpbuf1[] = "World!\r\n";
@@ -3144,7 +3132,6 @@ int HTPParserTest04(void)
htp_state = f->alstate;
if (htp_state == NULL) {
printf("no http state: ");
- result = 0;
goto end;
}
@@ -3156,10 +3143,9 @@ int HTPParserTest04(void)
printf("expected method M_UNKNOWN and got %s: , expected protocol "
"NULL and got %s \n", bstr_util_strdup_to_c(tx->request_method),
bstr_util_strdup_to_c(tx->request_protocol));
- result = 0;
goto end;
}
-
+ result = 1;
end:
if (alp_tctx != NULL)
AppLayerParserThreadCtxFree(alp_tctx);
@@ -3174,7 +3160,7 @@ end:
* properly parsed them and also keeps them separated. */
int HTPParserTest05(void)
{
- int result = 1;
+ int result = 0;
Flow *f = NULL;
HtpState *http_state = NULL;
uint8_t httpbuf1[] = "POST / HTTP/1.0\r\nUser-Agent: Victor/1.0\r\n\r\n";
@@ -3208,7 +3194,6 @@ int HTPParserTest05(void)
httpbuf1, httplen1);
if (r != 0) {
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- result = 0;
SCMutexUnlock(&f->m);
goto end;
}
@@ -3217,7 +3202,6 @@ int HTPParserTest05(void)
httplen4);
if (r != 0) {
printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
- result = 0;
SCMutexUnlock(&f->m);
goto end;
}
@@ -3225,7 +3209,6 @@ int HTPParserTest05(void)
r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf5, httplen5);
if (r != 0) {
printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r);
- result = 0;
SCMutexUnlock(&f->m);
goto end;
}
@@ -3233,7 +3216,6 @@ int HTPParserTest05(void)
r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf2, httplen2);
if (r != 0) {
printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
- result = 0;
SCMutexUnlock(&f->m);
goto end;
}
@@ -3242,7 +3224,6 @@ int HTPParserTest05(void)
httplen3);
if (r != 0) {
printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
- result = 0;
SCMutexUnlock(&f->m);
goto end;
}
@@ -3251,7 +3232,6 @@ int HTPParserTest05(void)
httplen6);
if (r != 0) {
printf("toserver chunk 6 returned %" PRId32 ", expected 0: ", r);
- result = 0;
SCMutexUnlock(&f->m);
goto end;
}
@@ -3260,7 +3240,6 @@ int HTPParserTest05(void)
http_state = f->alstate;
if (http_state == NULL) {
printf("no http state: ");
- result = 0;
goto end;
}
@@ -3272,7 +3251,6 @@ int HTPParserTest05(void)
printf("expected method M_POST and got %s: , expected protocol "
"HTTP/1.0 and got %s \n", bstr_util_strdup_to_c(tx->request_method),
bstr_util_strdup_to_c(tx->request_protocol));
- result = 0;
goto end;
}
@@ -3281,9 +3259,9 @@ int HTPParserTest05(void)
"HTTP/1.0 and got %s \n", tx->response_status_number,
bstr_util_strdup_to_c(tx->response_message),
bstr_util_strdup_to_c(tx->response_protocol));
- result = 0;
goto end;
}
+ result = 1;
end:
if (alp_tctx != NULL)
AppLayerParserThreadCtxFree(alp_tctx);
@@ -3298,7 +3276,7 @@ end:
*/
int HTPParserTest06(void)
{
- int result = 1;
+ int result = 0;
Flow *f = NULL;
uint8_t httpbuf1[] = "GET /ld/index.php?id=412784631&cid=0064&version=4&"
"name=try HTTP/1.1\r\nAccept: */*\r\nUser-Agent: "
@@ -3361,7 +3339,6 @@ int HTPParserTest06(void)
httpbuf1, httplen1);
if (r != 0) {
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- result = 0;
SCMutexUnlock(&f->m);
goto end;
}
@@ -3370,7 +3347,6 @@ int HTPParserTest06(void)
httplen2);
if (r != 0) {
printf("toclient chunk 2 returned %" PRId32 ", expected 0: ", r);
- result = 0;
SCMutexUnlock(&f->m);
goto end;
}
@@ -3379,7 +3355,6 @@ int HTPParserTest06(void)
http_state = f->alstate;
if (http_state == NULL) {
printf("no http state: ");
- result = 0;
goto end;
}
@@ -3391,7 +3366,6 @@ int HTPParserTest06(void)
printf("expected method M_GET and got %s: , expected protocol "
"HTTP/1.1 and got %s \n", bstr_util_strdup_to_c(tx->request_method),
bstr_util_strdup_to_c(tx->request_protocol));
- result = 0;
goto end;
}
@@ -3402,9 +3376,9 @@ int HTPParserTest06(void)
"col HTTP/1.1 and got %s \n", tx->response_status_number,
bstr_util_strdup_to_c(tx->response_message),
bstr_util_strdup_to_c(tx->response_protocol));
- result = 0;
goto end;
}
+ result = 1;
end:
if (alp_tctx != NULL)
AppLayerParserThreadCtxFree(alp_tctx);
@@ -3640,7 +3614,6 @@ libhtp:\n\
if (r != 0) {
printf("toserver chunk returned %" PRId32 ", expected"
" 0: ", r);
- result = 0;
SCMutexUnlock(&f->m);
goto end;
}
@@ -3649,7 +3622,6 @@ libhtp:\n\
htp_state = f->alstate;
if (htp_state == NULL) {
printf("no http state: ");
- result = 0;
goto end;
}
@@ -4577,7 +4549,6 @@ libhtp:\n\
if (r != 0) {
printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
" 0: ", u, r);
- result = 0;
SCMutexUnlock(&f->m);
goto end;
}
@@ -4587,7 +4558,6 @@ libhtp:\n\
htp_state = f->alstate;
if (htp_state == NULL) {
printf("no http state: ");
- result = 0;
goto end;
}
@@ -4748,7 +4718,6 @@ libhtp:\n\
if (r != 0) {
printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
" 0: ", u, r);
- result = 0;
SCMutexUnlock(&f->m);
goto end;
}
@@ -4758,7 +4727,6 @@ libhtp:\n\
htp_state = f->alstate;
if (htp_state == NULL) {
printf("no http state: ");
- result = 0;
goto end;
}
@@ -4917,7 +4885,6 @@ libhtp:\n\
if (r != 0) {
printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
" 0: ", u, r);
- result = 0;
SCMutexUnlock(&f->m);
goto end;
}
@@ -4927,7 +4894,6 @@ libhtp:\n\
htp_state = f->alstate;
if (htp_state == NULL) {
printf("no http state: ");
- result = 0;
goto end;
}
@@ -5056,7 +5022,6 @@ libhtp:\n\
if (r != 0) {
printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
" 0: ", u, r);
- result = 0;
SCMutexUnlock(&f->m);
goto end;
}
@@ -5066,7 +5031,6 @@ libhtp:\n\
htp_state = f->alstate;
if (htp_state == NULL) {
printf("no http state: ");
- result = 0;
goto end;
}
@@ -5168,7 +5132,6 @@ libhtp:\n\
if (r != 0) {
printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
" 0: ", u, r);
- result = 0;
SCMutexUnlock(&f->m);
goto end;
}
@@ -5178,7 +5141,6 @@ libhtp:\n\
htp_state = f->alstate;
if (htp_state == NULL) {
printf("no http state: ");
- result = 0;
goto end;
}
@@ -5280,7 +5242,6 @@ libhtp:\n\
if (r != 0) {
printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
" 0: ", u, r);
- result = 0;
SCMutexUnlock(&f->m);
goto end;
}
@@ -5290,7 +5251,6 @@ libhtp:\n\
htp_state = f->alstate;
if (htp_state == NULL) {
printf("no http state: ");
- result = 0;
goto end;
}
@@ -5393,7 +5353,6 @@ libhtp:\n\
if (r != 0) {
printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
" 0: ", u, r);
- result = 0;
SCMutexUnlock(&f->m);
goto end;
}
@@ -5403,7 +5362,6 @@ libhtp:\n\
htp_state = f->alstate;
if (htp_state == NULL) {
printf("no http state: ");
- result = 0;
goto end;
}
@@ -5503,7 +5461,6 @@ libhtp:\n\
if (r != 0) {
printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
" 0: ", u, r);
- result = 0;
SCMutexUnlock(&f->m);
goto end;
}
@@ -5513,7 +5470,6 @@ libhtp:\n\
htp_state = f->alstate;
if (htp_state == NULL) {
printf("no http state: ");
- result = 0;
goto end;
}
@@ -5614,7 +5570,6 @@ libhtp:\n\
if (r != 0) {
printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
" 0: ", u, r);
- result = 0;
SCMutexUnlock(&f->m);
goto end;
}
@@ -5624,7 +5579,6 @@ libhtp:\n\
htp_state = f->alstate;
if (htp_state == NULL) {
printf("no http state: ");
- result = 0;
goto end;
}
@@ -5770,7 +5724,6 @@ libhtp:\n\
int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START, httpbuf1, httplen1);
if (r != 0) {
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- result = 0;
SCMutexUnlock(&f->m);
goto end;
}
@@ -5780,7 +5733,6 @@ libhtp:\n\
r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER, httpbuf1, httplen1);
if (r != 0) {
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- result = 0;
SCMutexUnlock(&f->m);
goto end;
}
@@ -5789,7 +5741,6 @@ libhtp:\n\
http_state = f->alstate;
if (http_state == NULL) {
printf("no http state: ");
- result = 0;
goto end;
}
@@ -5893,7 +5844,6 @@ libhtp:\n\
if (r != 0) {
printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
" 0: ", u, r);
- result = 0;
SCMutexUnlock(&f->m);
goto end;
}
@@ -5901,7 +5851,6 @@ libhtp:\n\
if (r != -1) {
printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
" -1: ", u, r);
- result = 0;
SCMutexUnlock(&f->m);
goto end;
}
@@ -6036,7 +5985,6 @@ libhtp:\n\
if (r != 0) {
printf("toserver chunk %" PRIu32 " returned %" PRId32 ", expected"
" 0: ", u, r);
- result = 0;
SCMutexUnlock(&f->m);
goto end;
}
@@ -6119,7 +6067,6 @@ int HTPParserTest16(void)
r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, flags, (uint8_t *)httpbuf, len);
if (r != 0) {
printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
- result = 0;
SCMutexUnlock(&f->m);
goto end;
}
@@ -6170,6 +6117,354 @@ end:
return result;
}
+/** \test CONNECT with plain text HTTP being tunneled */
+int HTPParserTest17(void)
+{
+ int result = 0;
+ Flow *f = NULL;
+ HtpState *http_state = NULL;
+ /* CONNECT setup */
+ uint8_t httpbuf1[] = "CONNECT abc:443 HTTP/1.1\r\nUser-Agent: Victor/1.0\r\n\r\n";
+ uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
+ uint8_t httpbuf2[] = "HTTP/1.1 200 OK\r\nServer: VictorServer/1.0\r\n\r\n";
+ uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
+ /* plain text HTTP */
+ uint8_t httpbuf3[] = "GET / HTTP/1.1\r\nUser-Agent: Victor/1.0\r\n\r\n";
+ uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
+ uint8_t httpbuf4[] = "HTTP/1.1 200 OK\r\nServer: VictorServer/1.0\r\n\r\n";
+ uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&ssn, 0, sizeof(ssn));
+
+ f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
+ if (f == NULL)
+ goto end;
+ f->protoctx = &ssn;
+ f->proto = IPPROTO_TCP;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f->m);
+ int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START,
+ httpbuf1, httplen1);
+ if (r != 0) {
+ printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f->m);
+ goto end;
+ }
+
+ r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, httpbuf2,
+ httplen2);
+ if (r != 0) {
+ printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f->m);
+ goto end;
+ }
+ r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER,
+ httpbuf3, httplen3);
+ if (r != 0) {
+ printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f->m);
+ goto end;
+ }
+
+ r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf4,
+ httplen4);
+ if (r != 0) {
+ printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f->m);
+ goto end;
+ }
+
+ SCMutexUnlock(&f->m);
+
+ http_state = f->alstate;
+ if (http_state == NULL) {
+ printf("no http state: ");
+ goto end;
+ }
+
+ htp_tx_t *tx = HTPStateGetTx(http_state, 0);
+ if (tx == NULL)
+ goto end;
+ htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
+ if (tx->request_method_number != HTP_M_CONNECT ||
+ h == NULL || tx->request_protocol_number != HTP_PROTOCOL_1_1)
+ {
+ printf("expected method M_POST and got %s: , expected protocol "
+ "HTTP/1.1 and got %s \n", bstr_util_strdup_to_c(tx->request_method),
+ bstr_util_strdup_to_c(tx->request_protocol));
+ goto end;
+ }
+
+ if (tx->response_status_number != 200) {
+ printf("expected response 200 OK and got %"PRId32" %s: , expected protocol "
+ "HTTP/1.1 and got %s \n", tx->response_status_number,
+ bstr_util_strdup_to_c(tx->response_message),
+ bstr_util_strdup_to_c(tx->response_protocol));
+ goto end;
+ }
+
+ tx = HTPStateGetTx(http_state, 1);
+ if (tx == NULL)
+ goto end;
+ h = htp_table_get_index(tx->request_headers, 0, NULL);
+ if (tx->request_method_number != HTP_M_GET ||
+ h == NULL || tx->request_protocol_number != HTP_PROTOCOL_1_1)
+ {
+ printf("expected method M_GET and got %s: , expected protocol "
+ "HTTP/1.1 and got %s \n", bstr_util_strdup_to_c(tx->request_method),
+ bstr_util_strdup_to_c(tx->request_protocol));
+ goto end;
+ }
+
+ if (tx->response_status_number != 200) {
+ printf("expected response 200 OK and got %"PRId32" %s: , expected protocol "
+ "HTTP/1.1 and got %s \n", tx->response_status_number,
+ bstr_util_strdup_to_c(tx->response_message),
+ bstr_util_strdup_to_c(tx->response_protocol));
+ goto end;
+ }
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ if (http_state != NULL)
+ HTPStateFree(http_state);
+ UTHFreeFlow(f);
+ return result;
+}
+
+/** \test CONNECT with plain text HTTP being tunneled */
+int HTPParserTest18(void)
+{
+ int result = 0;
+ Flow *f = NULL;
+ HtpState *http_state = NULL;
+ /* CONNECT setup */
+ uint8_t httpbuf1[] = "CONNECT abc:443 HTTP/1.1\r\nUser-Agent: Victor/1.0\r\n\r\n";
+ uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
+ uint8_t httpbuf2[] = "HTTP/1.1 200 OK\r\nServer: VictorServer/1.0\r\n\r\n";
+ uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
+ /* plain text HTTP */
+ uint8_t httpbuf3[] = "GE";
+ uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
+ uint8_t httpbuf4[] = "T / HTTP/1.1\r\nUser-Agent: Victor/1.0\r\n\r\n";
+ uint32_t httplen4 = sizeof(httpbuf4) - 1; /* minus the \0 */
+ uint8_t httpbuf5[] = "HTTP/1.1 200 OK\r\nServer: VictorServer/1.0\r\n\r\n";
+ uint32_t httplen5 = sizeof(httpbuf5) - 1; /* minus the \0 */
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&ssn, 0, sizeof(ssn));
+
+ f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
+ if (f == NULL)
+ goto end;
+ f->protoctx = &ssn;
+ f->proto = IPPROTO_TCP;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f->m);
+ int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START,
+ httpbuf1, httplen1);
+ if (r != 0) {
+ printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f->m);
+ goto end;
+ }
+
+ r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, httpbuf2,
+ httplen2);
+ if (r != 0) {
+ printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f->m);
+ goto end;
+ }
+ r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER,
+ httpbuf3, httplen3);
+ if (r != 0) {
+ printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f->m);
+ goto end;
+ }
+ r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER,
+ httpbuf4, httplen4);
+ if (r != 0) {
+ printf("toserver chunk 4 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f->m);
+ goto end;
+ }
+
+
+ r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT, httpbuf5,
+ httplen5);
+ if (r != 0) {
+ printf("toserver chunk 5 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f->m);
+ goto end;
+ }
+
+ SCMutexUnlock(&f->m);
+
+ http_state = f->alstate;
+ if (http_state == NULL) {
+ printf("no http state: ");
+ goto end;
+ }
+
+ htp_tx_t *tx = HTPStateGetTx(http_state, 0);
+ if (tx == NULL)
+ goto end;
+ htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
+ if (tx->request_method_number != HTP_M_CONNECT ||
+ h == NULL || tx->request_protocol_number != HTP_PROTOCOL_1_1)
+ {
+ printf("expected method M_POST and got %s: , expected protocol "
+ "HTTP/1.1 and got %s \n", bstr_util_strdup_to_c(tx->request_method),
+ bstr_util_strdup_to_c(tx->request_protocol));
+ goto end;
+ }
+
+ if (tx->response_status_number != 200) {
+ printf("expected response 200 OK and got %"PRId32" %s: , expected protocol "
+ "HTTP/1.1 and got %s \n", tx->response_status_number,
+ bstr_util_strdup_to_c(tx->response_message),
+ bstr_util_strdup_to_c(tx->response_protocol));
+ goto end;
+ }
+
+ tx = HTPStateGetTx(http_state, 1);
+ if (tx == NULL)
+ goto end;
+ h = htp_table_get_index(tx->request_headers, 0, NULL);
+ if (tx->request_method_number != HTP_M_GET ||
+ h == NULL || tx->request_protocol_number != HTP_PROTOCOL_1_1)
+ {
+ printf("expected method M_GET and got %s: , expected protocol "
+ "HTTP/1.1 and got %s \n", bstr_util_strdup_to_c(tx->request_method),
+ bstr_util_strdup_to_c(tx->request_protocol));
+ goto end;
+ }
+
+ if (tx->response_status_number != 200) {
+ printf("expected response 200 OK and got %"PRId32" %s: , expected protocol "
+ "HTTP/1.1 and got %s \n", tx->response_status_number,
+ bstr_util_strdup_to_c(tx->response_message),
+ bstr_util_strdup_to_c(tx->response_protocol));
+ goto end;
+ }
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ if (http_state != NULL)
+ HTPStateFree(http_state);
+ UTHFreeFlow(f);
+ return result;
+}
+
+/** \test CONNECT with TLS content (start of it at least) */
+int HTPParserTest19(void)
+{
+ int result = 0;
+ Flow *f = NULL;
+ HtpState *http_state = NULL;
+ /* CONNECT setup */
+ uint8_t httpbuf1[] = "CONNECT abc:443 HTTP/1.1\r\nUser-Agent: Victor/1.0\r\n\r\n";
+ uint32_t httplen1 = sizeof(httpbuf1) - 1; /* minus the \0 */
+ uint8_t httpbuf2[] = "HTTP/1.1 200 OK\r\nServer: VictorServer/1.0\r\n\r\n";
+ uint32_t httplen2 = sizeof(httpbuf2) - 1; /* minus the \0 */
+ /* start of TLS/SSL */
+ uint8_t httpbuf3[] = "\x16\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
+ uint32_t httplen3 = sizeof(httpbuf3) - 1; /* minus the \0 */
+ TcpSession ssn;
+ AppLayerParserThreadCtx *alp_tctx = AppLayerParserThreadCtxAlloc();
+
+ memset(&ssn, 0, sizeof(ssn));
+
+ f = UTHBuildFlow(AF_INET, "1.2.3.4", "1.2.3.5", 1024, 80);
+ if (f == NULL)
+ goto end;
+ f->protoctx = &ssn;
+ f->proto = IPPROTO_TCP;
+
+ StreamTcpInitConfig(TRUE);
+
+ SCMutexLock(&f->m);
+ int r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER|STREAM_START,
+ httpbuf1, httplen1);
+ if (r != 0) {
+ printf("toserver chunk 1 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f->m);
+ goto end;
+ }
+
+ r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOCLIENT|STREAM_START, httpbuf2,
+ httplen2);
+ if (r != 0) {
+ printf("toserver chunk 2 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f->m);
+ goto end;
+ }
+ r = AppLayerParserParse(alp_tctx, f, ALPROTO_HTTP, STREAM_TOSERVER,
+ httpbuf3, httplen3);
+ if (r != 0) {
+ printf("toserver chunk 3 returned %" PRId32 ", expected 0: ", r);
+ SCMutexUnlock(&f->m);
+ goto end;
+ }
+
+ SCMutexUnlock(&f->m);
+
+ http_state = f->alstate;
+ if (http_state == NULL) {
+ printf("no http state: ");
+ goto end;
+ }
+
+ htp_tx_t *tx = HTPStateGetTx(http_state, 0);
+ if (tx == NULL)
+ goto end;
+ htp_header_t *h = htp_table_get_index(tx->request_headers, 0, NULL);
+ if (tx->request_method_number != HTP_M_CONNECT ||
+ h == NULL || tx->request_protocol_number != HTP_PROTOCOL_1_1)
+ {
+ printf("expected method M_POST and got %s: , expected protocol "
+ "HTTP/1.1 and got %s \n", bstr_util_strdup_to_c(tx->request_method),
+ bstr_util_strdup_to_c(tx->request_protocol));
+ goto end;
+ }
+
+ if (tx->response_status_number != 200) {
+ printf("expected response 200 OK and got %"PRId32" %s: , expected protocol "
+ "HTTP/1.1 and got %s \n", tx->response_status_number,
+ bstr_util_strdup_to_c(tx->response_message),
+ bstr_util_strdup_to_c(tx->response_protocol));
+ goto end;
+ }
+
+ /* no new tx should have been set up for the tunneled data */
+ tx = HTPStateGetTx(http_state, 1);
+ if (tx != NULL)
+ goto end;
+
+ result = 1;
+end:
+ if (alp_tctx != NULL)
+ AppLayerParserThreadCtxFree(alp_tctx);
+ StreamTcpFreeConfig(TRUE);
+ if (http_state != NULL)
+ HTPStateFree(http_state);
+ UTHFreeFlow(f);
+ return result;
+}
+
#endif /* UNITTESTS */
/**
@@ -6216,6 +6511,9 @@ void HTPParserRegisterTests(void)
UtRegisterTest("HTPParserTest14", HTPParserTest14, 1);
UtRegisterTest("HTPParserTest15", HTPParserTest15, 1);
UtRegisterTest("HTPParserTest16", HTPParserTest16, 1);
+ UtRegisterTest("HTPParserTest17", HTPParserTest17, 1);
+ UtRegisterTest("HTPParserTest18", HTPParserTest18, 1);
+ UtRegisterTest("HTPParserTest19", HTPParserTest19, 1);
HTPFileParserRegisterTests();
HTPXFFParserRegisterTests();
diff --git a/framework/src/suricata/src/app-layer-smtp.c b/framework/src/suricata/src/app-layer-smtp.c
index 0c161edb..cd0a732e 100644
--- a/framework/src/suricata/src/app-layer-smtp.c
+++ b/framework/src/suricata/src/app-layer-smtp.c
@@ -879,7 +879,12 @@ static int SMTPProcessReply(SMTPState *state, Flow *f,
if (state->cmds_idx == state->cmds_cnt) {
if (!(state->parser_state & SMTP_PARSER_STATE_FIRST_REPLY_SEEN)) {
- state->parser_state |= SMTP_PARSER_STATE_FIRST_REPLY_SEEN;
+ /* the first server reply can be a multiline message. Let's
+ * flag the fact that we have seen the first reply only at the end
+ * of a multiline reply
+ */
+ if (!(state->parser_state & SMTP_PARSER_STATE_PARSING_MULTILINE_REPLY))
+ state->parser_state |= SMTP_PARSER_STATE_FIRST_REPLY_SEEN;
if (reply_code == SMTP_REPLY_220)
SCReturnInt(0);
else
diff --git a/framework/src/suricata/src/app-layer-ssl.c b/framework/src/suricata/src/app-layer-ssl.c
index 5fb41ba1..3d4605af 100644
--- a/framework/src/suricata/src/app-layer-ssl.c
+++ b/framework/src/suricata/src/app-layer-ssl.c
@@ -119,10 +119,15 @@ SslConfig ssl_config;
#define SSLV3_RECORD_HDR_LEN 5
#define SSLV3_MESSAGE_HDR_LEN 4
+#define SSLV3_CLIENT_HELLO_VERSION_LEN 2
+#define SSLV3_CLIENT_HELLO_RANDOM_LEN 32
+
/* TLS heartbeat protocol types */
#define TLS_HB_REQUEST 1
#define TLS_HB_RESPONSE 2
+#define HAS_SPACE(n) ((uint32_t)((input) + (n) - (initial_input)) > (uint32_t)(input_len)) ? 0 : 1
+
static void SSLParserReset(SSLState *ssl_state)
{
ssl_state->curr_connp->bytes_processed = 0;
@@ -143,11 +148,101 @@ static int SSLv3ParseHandshakeType(SSLState *ssl_state, uint8_t *input,
switch (ssl_state->curr_connp->handshake_type) {
case SSLV3_HS_CLIENT_HELLO:
ssl_state->flags |= SSL_AL_FLAG_STATE_CLIENT_HELLO;
+
+ /* skip version */
+ input += SSLV3_CLIENT_HELLO_VERSION_LEN;
+
+ /* skip random */
+ input += SSLV3_CLIENT_HELLO_RANDOM_LEN;
+
+ if (!(HAS_SPACE(1)))
+ goto end;
+
+ /* skip session id */
+ uint8_t session_id_length = *(input++);
+
+ input += session_id_length;
+
+ if (!(HAS_SPACE(2)))
+ goto end;
+
+ /* skip cipher suites */
+ uint16_t cipher_suites_length = ntohs(*(uint16_t *)input);
+ input += 2;
+
+ input += cipher_suites_length;
+
+ if (!(HAS_SPACE(1)))
+ goto end;
+
+ /* skip compression methods */
+ uint8_t compression_methods_length = *(input++);
+
+ input += compression_methods_length;
+
+ if (!(HAS_SPACE(2)))
+ goto end;
+
+ uint16_t extensions_len = ntohs(*(uint16_t *)input);
+ input += 2;
+
+ uint16_t processed_len = 0;
+ while (processed_len < extensions_len)
+ {
+ if (!(HAS_SPACE(2)))
+ goto end;
+
+ uint16_t ext_type = ntohs(*(uint16_t *)input);
+ input += 2;
+
+ if (!(HAS_SPACE(2)))
+ goto end;
+
+ uint16_t ext_len = ntohs(*(uint16_t *)input);
+ input += 2;
+
+
+ switch (ext_type) {
+ case SSL_EXTENSION_SNI:
+ {
+ /* skip sni_list_length and sni_type */
+ input += 3;
+
+ if (!(HAS_SPACE(2)))
+ goto end;
+
+ uint16_t sni_len = ntohs(*(uint16_t *)input);
+ input += 2;
+
+ size_t sni_strlen = sni_len + 1;
+ ssl_state->curr_connp->sni = SCMalloc(sni_strlen);
+
+ if (unlikely(ssl_state->curr_connp->sni == NULL))
+ goto end;
+
+ if (!(HAS_SPACE(sni_len)))
+ goto end;
+
+ memcpy(ssl_state->curr_connp->sni, input,
+ sni_strlen - 1);
+ ssl_state->curr_connp->sni[sni_strlen-1] = 0;
+
+ input += sni_len;
+ break;
+ }
+ default:
+ {
+ input += ext_len;
+ break;
+ }
+ }
+ processed_len += ext_len + 4;
+ }
+end:
break;
case SSLV3_HS_SERVER_HELLO:
ssl_state->flags |= SSL_AL_FLAG_STATE_SERVER_HELLO;
-
break;
case SSLV3_HS_SERVER_KEY_EXCHANGE:
@@ -1141,6 +1236,8 @@ void SSLStateFree(void *p)
SCFree(ssl_state->client_connp.cert0_issuerdn);
if (ssl_state->client_connp.cert0_fingerprint)
SCFree(ssl_state->client_connp.cert0_fingerprint);
+ if (ssl_state->client_connp.sni)
+ SCFree(ssl_state->client_connp.sni);
if (ssl_state->server_connp.trec)
SCFree(ssl_state->server_connp.trec);
@@ -1150,6 +1247,8 @@ void SSLStateFree(void *p)
SCFree(ssl_state->server_connp.cert0_issuerdn);
if (ssl_state->server_connp.cert0_fingerprint)
SCFree(ssl_state->server_connp.cert0_fingerprint);
+ if (ssl_state->server_connp.sni)
+ SCFree(ssl_state->server_connp.sni);
/* Free certificate chain */
while ((item = TAILQ_FIRST(&ssl_state->server_connp.certs))) {
diff --git a/framework/src/suricata/src/app-layer-ssl.h b/framework/src/suricata/src/app-layer-ssl.h
index 2fc1a969..e6274249 100644
--- a/framework/src/suricata/src/app-layer-ssl.h
+++ b/framework/src/suricata/src/app-layer-ssl.h
@@ -86,7 +86,8 @@ enum {
/* config flags */
#define SSL_TLS_LOG_PEM (1 << 0)
-
+/* extensions */
+#define SSL_EXTENSION_SNI 0x0000
/* SSL versions. We'll use a unified format for all, with the top byte
* holding the major version and the lower byte the minor version */
@@ -134,6 +135,9 @@ typedef struct SSLStateConnp_ {
char *cert0_issuerdn;
char *cert0_fingerprint;
+ /* ssl server name indication extension */
+ char *sni;
+
uint8_t *cert_input;
uint32_t cert_input_len;
diff --git a/framework/src/suricata/src/detect-engine-content-inspection.c b/framework/src/suricata/src/detect-engine-content-inspection.c
index a434ca5a..17df02ce 100644
--- a/framework/src/suricata/src/detect-engine-content-inspection.c
+++ b/framework/src/suricata/src/detect-engine-content-inspection.c
@@ -42,6 +42,8 @@
#include "detect-uricontent.h"
#include "detect-urilen.h"
#include "detect-lua.h"
+#include "detect-base64-decode.h"
+#include "detect-base64-data.h"
#include "app-layer-dcerpc.h"
@@ -551,6 +553,16 @@ int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx
SCLogDebug("lua match");
goto match;
#endif /* HAVE_LUA */
+ } else if (sm->type == DETECT_BASE64_DECODE) {
+ if (DetectBase64DecodeDoMatch(det_ctx, s, sm, buffer, buffer_len)) {
+ if (s->sm_arrays[DETECT_SM_LIST_BASE64_DATA] != NULL) {
+ KEYWORD_PROFILING_END(det_ctx, sm->type, 1);
+ if (DetectBase64DataDoMatch(de_ctx, det_ctx, s, f)) {
+ /* Base64 is a terminal list. */
+ goto final_match;
+ }
+ }
+ }
} else {
SCLogDebug("sm->type %u", sm->type);
#ifdef DEBUG
@@ -569,8 +581,8 @@ match:
KEYWORD_PROFILING_END(det_ctx, sm->type, 1);
int r = DetectEngineContentInspection(de_ctx, det_ctx, s, sm->next, f, buffer, buffer_len, stream_start_offset, inspection_mode, data);
SCReturnInt(r);
- } else {
- KEYWORD_PROFILING_END(det_ctx, sm->type, 1);
- SCReturnInt(1);
}
+final_match:
+ KEYWORD_PROFILING_END(det_ctx, sm->type, 1);
+ SCReturnInt(1);
}
diff --git a/framework/src/suricata/src/detect-engine-content-inspection.h b/framework/src/suricata/src/detect-engine-content-inspection.h
index dc0b5026..5e80b9b8 100644
--- a/framework/src/suricata/src/detect-engine-content-inspection.h
+++ b/framework/src/suricata/src/detect-engine-content-inspection.h
@@ -50,6 +50,7 @@ enum {
DETECT_ENGINE_CONTENT_INSPECTION_MODE_HRHHD,
DETECT_ENGINE_CONTENT_INSPECTION_MODE_DNSQUERY,
DETECT_ENGINE_CONTENT_INSPECTION_MODE_FD_SMTP,
+ DETECT_ENGINE_CONTENT_INSPECTION_MODE_BASE64,
DETECT_ENGINE_CONTENT_INSPECTION_MODE_TEMPLATE_BUFFER,
};
diff --git a/framework/src/suricata/src/detect-engine.c b/framework/src/suricata/src/detect-engine.c
index 431f4b2a..cba76ca3 100644
--- a/framework/src/suricata/src/detect-engine.c
+++ b/framework/src/suricata/src/detect-engine.c
@@ -102,13 +102,17 @@
static uint32_t detect_engine_ctx_id = 1;
static DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload(
- ThreadVars *tv, DetectEngineCtx *new_de_ctx);
+ ThreadVars *tv, DetectEngineCtx *new_de_ctx, int mt);
static uint8_t DetectEngineCtxLoadConf(DetectEngineCtx *);
static DetectEngineMasterCtx g_master_de_ctx = { SCMUTEX_INITIALIZER, 0, NULL, NULL, TENANT_SELECTOR_UNKNOWN, NULL,};
-static DetectEngineThreadCtx *DetectEngineThreadCtxInitForMT(ThreadVars *tv);
+static uint32_t TenantIdHash(HashTable *h, void *data, uint16_t data_len);
+static char TenantIdCompare(void *d1, uint16_t d1_len, void *d2, uint16_t d2_len);
+static void TenantIdFree(void *d);
+static uint32_t DetectEngineTentantGetIdFromVlanId(const void *ctx, const Packet *p);
+static uint32_t DetectEngineTentantGetIdFromPcap(const void *ctx, const Packet *p);
/* 2 - for each direction */
DetectEngineAppInspectionEngine *app_inspection_engine[FLOW_PROTO_DEFAULT][ALPROTO_MAX][2];
@@ -553,7 +557,6 @@ int DetectEngineReloadIsDone(void)
static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx)
{
SCEnter();
-
int i = 0;
int no_of_detect_tvs = 0;
ThreadVars *tv = NULL;
@@ -623,10 +626,8 @@ static int DetectEngineReloadThreads(DetectEngineCtx *new_de_ctx)
old_det_ctx[i] = SC_ATOMIC_GET(slots->slot_data);
detect_tvs[i] = tv;
- if (new_de_ctx != NULL)
- new_det_ctx[i] = DetectEngineThreadCtxInitForReload(tv, new_de_ctx);
- else
- new_det_ctx[i] = DetectEngineThreadCtxInitForMT(tv);
+
+ new_det_ctx[i] = DetectEngineThreadCtxInitForReload(tv, new_de_ctx, 1);
if (new_det_ctx[i] == NULL) {
SCLogError(SC_ERR_LIVE_RULE_SWAP, "Detect engine thread init "
"failure in live rule swap. Let's get out of here");
@@ -1280,6 +1281,114 @@ static void DetectEngineThreadCtxDeinitKeywords(DetectEngineCtx *de_ctx, DetectE
}
}
+/** NOTE: master MUST be locked before calling this */
+static TmEcode DetectEngineThreadCtxInitForMT(ThreadVars *tv, DetectEngineThreadCtx *det_ctx)
+{
+ DetectEngineMasterCtx *master = &g_master_de_ctx;
+ DetectEngineTenantMapping *map_array = NULL;
+ uint32_t map_array_size = 0;
+ uint32_t map_cnt = 0;
+ int max_tenant_id = 0;
+ DetectEngineCtx *list = master->list;
+ HashTable *mt_det_ctxs_hash = NULL;
+
+ if (master->tenant_selector == TENANT_SELECTOR_UNKNOWN) {
+ SCLogError(SC_ERR_MT_NO_SELECTOR, "no tenant selector set: "
+ "set using multi-detect.selector");
+ return TM_ECODE_FAILED;
+ }
+
+ uint32_t tcnt = 0;
+ while (list) {
+ if (list->tenant_id > max_tenant_id)
+ max_tenant_id = list->tenant_id;
+
+ list = list->next;
+ tcnt++;
+ }
+
+ mt_det_ctxs_hash = HashTableInit(tcnt * 2, TenantIdHash, TenantIdCompare, TenantIdFree);
+ if (mt_det_ctxs_hash == NULL) {
+ goto error;
+ }
+
+ if (max_tenant_id == 0) {
+ SCLogInfo("no tenants left, or none registered yet");
+ } else {
+ max_tenant_id++;
+
+ DetectEngineTenantMapping *map = master->tenant_mapping_list;
+ while (map) {
+ map_cnt++;
+ map = map->next;
+ }
+
+ if (map_cnt > 0) {
+ map_array_size = map_cnt + 1;
+
+ map_array = SCCalloc(map_array_size, sizeof(*map_array));
+ if (map_array == NULL)
+ goto error;
+
+ /* fill the array */
+ map_cnt = 0;
+ map = master->tenant_mapping_list;
+ while (map) {
+ BUG_ON(map_cnt > map_array_size);
+ map_array[map_cnt].traffic_id = map->traffic_id;
+ map_array[map_cnt].tenant_id = map->tenant_id;
+ map_cnt++;
+ map = map->next;
+ }
+
+ }
+
+ /* set up hash for tenant lookup */
+ list = master->list;
+ while (list) {
+ SCLogInfo("tenant-id %u", list->tenant_id);
+ if (list->tenant_id != 0) {
+ DetectEngineThreadCtx *mt_det_ctx = DetectEngineThreadCtxInitForReload(tv, list, 0);
+ if (mt_det_ctx == NULL)
+ goto error;
+ BUG_ON(HashTableAdd(mt_det_ctxs_hash, mt_det_ctx, 0) != 0);
+ }
+ list = list->next;
+ }
+ }
+
+ det_ctx->mt_det_ctxs_hash = mt_det_ctxs_hash;
+ mt_det_ctxs_hash = NULL;
+
+ det_ctx->mt_det_ctxs_cnt = max_tenant_id;
+
+ det_ctx->tenant_array = map_array;
+ det_ctx->tenant_array_size = map_array_size;
+
+ switch (master->tenant_selector) {
+ case TENANT_SELECTOR_UNKNOWN:
+ SCLogDebug("TENANT_SELECTOR_UNKNOWN");
+ break;
+ case TENANT_SELECTOR_VLAN:
+ det_ctx->TenantGetId = DetectEngineTentantGetIdFromVlanId;
+ SCLogDebug("TENANT_SELECTOR_VLAN");
+ break;
+ case TENANT_SELECTOR_DIRECT:
+ det_ctx->TenantGetId = DetectEngineTentantGetIdFromPcap;
+ SCLogDebug("TENANT_SELECTOR_DIRECT");
+ break;
+ }
+
+ return TM_ECODE_OK;
+error:
+ if (map_array != NULL)
+ SCFree(map_array);
+ if (mt_det_ctxs_hash != NULL)
+ HashTableFree(mt_det_ctxs_hash);
+
+ return TM_ECODE_FAILED;
+}
+
/** \internal
* \brief Helper for DetectThread setup functions
*/
@@ -1338,6 +1447,16 @@ static TmEcode ThreadCtxDoInit (DetectEngineCtx *de_ctx, DetectEngineThreadCtx *
return TM_ECODE_FAILED;
}
+ /* Allocate space for base64 decoded data. */
+ if (de_ctx->base64_decode_max_len) {
+ det_ctx->base64_decoded = SCMalloc(de_ctx->base64_decode_max_len);
+ if (det_ctx->base64_decoded == NULL) {
+ return TM_ECODE_FAILED;
+ }
+ det_ctx->base64_decoded_len_max = de_ctx->base64_decode_max_len;
+ det_ctx->base64_decoded_len = 0;
+ }
+
DetectEngineThreadCtxInitKeywords(de_ctx, det_ctx);
#ifdef PROFILING
SCProfilingRuleThreadSetup(de_ctx->profile_ctx, det_ctx);
@@ -1367,12 +1486,6 @@ static TmEcode ThreadCtxDoInit (DetectEngineCtx *de_ctx, DetectEngineThreadCtx *
*/
TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
{
- if (DetectEngineMultiTenantEnabled()) {
- DetectEngineThreadCtx *mt_det_ctx = DetectEngineThreadCtxInitForMT(tv);
- *data = (void *)mt_det_ctx;
- return (mt_det_ctx == NULL) ? TM_ECODE_FAILED : TM_ECODE_OK;
- }
-
/* first register the counter. In delayed detect mode we exit right after if the
* rules haven't been loaded yet. */
uint16_t counter_alerts = StatsRegisterCounter("detect.alert", tv);
@@ -1422,6 +1535,11 @@ TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
/* pass thread data back to caller */
*data = (void *)det_ctx;
+ if (DetectEngineMultiTenantEnabled()) {
+ if (DetectEngineThreadCtxInitForMT(tv, det_ctx) != TM_ECODE_OK)
+ return TM_ECODE_FAILED;
+ }
+
return TM_ECODE_OK;
}
@@ -1429,10 +1547,13 @@ TmEcode DetectEngineThreadCtxInit(ThreadVars *tv, void *initdata, void **data)
* \internal
* \brief initialize a det_ctx for reload cases
* \param new_de_ctx the new detection engine
+ * \param mt flag to indicate if MT should be set up for this det_ctx
+ * this should only be done for the 'root' det_ctx
+ *
* \retval det_ctx detection engine thread ctx or NULL in case of error
*/
static DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload(
- ThreadVars *tv, DetectEngineCtx *new_de_ctx)
+ ThreadVars *tv, DetectEngineCtx *new_de_ctx, int mt)
{
DetectEngineThreadCtx *det_ctx = SCMalloc(sizeof(DetectEngineThreadCtx));
if (unlikely(det_ctx == NULL))
@@ -1467,6 +1588,14 @@ static DetectEngineThreadCtx *DetectEngineThreadCtxInitForReload(
det_ctx->counter_match_list = counter_match_list;
#endif
+ if (mt && DetectEngineMultiTenantEnabled()) {
+ if (DetectEngineThreadCtxInitForMT(tv, det_ctx) != TM_ECODE_OK) {
+ DetectEngineDeReference(&det_ctx->de_ctx);
+ SCFree(det_ctx);
+ return NULL;
+ }
+ }
+
return det_ctx;
}
@@ -1542,6 +1671,11 @@ void DetectEngineThreadCtxFree(DetectEngineThreadCtx *det_ctx)
SCFree(det_ctx->hcbd);
}
+ /* Decoded base64 data. */
+ if (det_ctx->base64_decoded != NULL) {
+ SCFree(det_ctx->base64_decoded);
+ }
+
if (det_ctx->de_ctx != NULL) {
DetectEngineThreadCtxDeinitKeywords(det_ctx->de_ctx, det_ctx);
#ifdef UNITTESTS
@@ -1822,7 +1956,7 @@ static int DetectLoaderFuncLoadTenant(void *vctx, int loader_id)
{
TenantLoaderCtx *ctx = (TenantLoaderCtx *)vctx;
- SCLogInfo("loader %d", loader_id);
+ SCLogDebug("loader %d", loader_id);
if (DetectEngineMultiTenantLoadTenant(ctx->tenant_id, ctx->yaml, loader_id) != 0) {
return -1;
}
@@ -1909,10 +2043,14 @@ int DetectEngineReloadTenantBlocking(uint32_t tenant_id, const char *yaml, int r
* Tenants and mappings are optional, and can also dynamically be added
* and removed from the unix socket.
*/
-void DetectEngineMultiTenantSetup(void)
+int DetectEngineMultiTenantSetup(void)
{
+ enum DetectEngineTenantSelectors tenant_selector = TENANT_SELECTOR_UNKNOWN;
DetectEngineMasterCtx *master = &g_master_de_ctx;
+ int unix_socket = 0;
+ (void)ConfGetBool("unix-command.enabled", &unix_socket);
+
int failure_fatal = 0;
(void)ConfGetBool("engine.init-failure-fatal", &failure_fatal);
@@ -1929,12 +2067,21 @@ void DetectEngineMultiTenantSetup(void)
char *handler = NULL;
if (ConfGet("multi-detect.selector", &handler) == 1) {
- SCLogInfo("selector %s", handler);
+ SCLogInfo("multi-tenant selector type %s", handler);
if (strcmp(handler, "vlan") == 0) {
- master->tenant_selector = TENANT_SELECTOR_VLAN;
+ tenant_selector = master->tenant_selector = TENANT_SELECTOR_VLAN;
+
+ int vlanbool = 0;
+ if ((ConfGetBool("vlan.use-for-tracking", &vlanbool)) == 1 && vlanbool == 0) {
+ SCLogError(SC_ERR_INVALID_VALUE, "vlan tracking is disabled, "
+ "can't use multi-detect selector 'vlan'");
+ SCMutexUnlock(&master->lock);
+ goto error;
+ }
+
} else if (strcmp(handler, "direct") == 0) {
- master->tenant_selector = TENANT_SELECTOR_DIRECT;
+ tenant_selector = master->tenant_selector = TENANT_SELECTOR_DIRECT;
} else {
SCLogError(SC_ERR_INVALID_VALUE, "unknown value %s "
"multi-detect.selector", handler);
@@ -1949,43 +2096,44 @@ void DetectEngineMultiTenantSetup(void)
ConfNode *mappings_root_node = ConfGetNode("multi-detect.mappings");
ConfNode *mapping_node = NULL;
+ int mapping_cnt = 0;
if (mappings_root_node != NULL) {
TAILQ_FOREACH(mapping_node, &mappings_root_node->head, next) {
- if (strcmp(mapping_node->val, "vlan") == 0) {
- ConfNode *tenant_id_node = ConfNodeLookupChild(mapping_node, "tenant-id");
- if (tenant_id_node == NULL)
- goto bad_mapping;
- ConfNode *vlan_id_node = ConfNodeLookupChild(mapping_node, "vlan-id");
- if (vlan_id_node == NULL)
- goto bad_mapping;
-
- SCLogInfo("vlan %s %s", tenant_id_node->val, vlan_id_node->val);
-
- uint32_t tenant_id = 0;
- if (ByteExtractStringUint32(&tenant_id, 10, strlen(tenant_id_node->val),
- tenant_id_node->val) == -1)
- {
- SCLogError(SC_ERR_INVALID_ARGUMENT, "tenant-id "
- "of %s is invalid", tenant_id_node->val);
- goto bad_mapping;
- }
+ ConfNode *tenant_id_node = ConfNodeLookupChild(mapping_node, "tenant-id");
+ if (tenant_id_node == NULL)
+ goto bad_mapping;
+ ConfNode *vlan_id_node = ConfNodeLookupChild(mapping_node, "vlan-id");
+ if (vlan_id_node == NULL)
+ goto bad_mapping;
- uint16_t vlan_id = 0;
- if (ByteExtractStringUint16(&vlan_id, 10, strlen(vlan_id_node->val),
- vlan_id_node->val) == -1)
- {
- SCLogError(SC_ERR_INVALID_ARGUMENT, "vlan-id "
- "of %s is invalid", vlan_id_node->val);
- goto bad_mapping;
- }
+ uint32_t tenant_id = 0;
+ if (ByteExtractStringUint32(&tenant_id, 10, strlen(tenant_id_node->val),
+ tenant_id_node->val) == -1)
+ {
+ SCLogError(SC_ERR_INVALID_ARGUMENT, "tenant-id "
+ "of %s is invalid", tenant_id_node->val);
+ goto bad_mapping;
+ }
- if (DetectEngineTentantRegisterVlanId(tenant_id, (uint32_t)vlan_id) != 0) {
- goto error;
- }
- } else {
- SCLogWarning(SC_ERR_INVALID_VALUE, "multi-detect.mappings expects a list of 'vlan's. Not %s", mapping_node->val);
+ uint16_t vlan_id = 0;
+ if (ByteExtractStringUint16(&vlan_id, 10, strlen(vlan_id_node->val),
+ vlan_id_node->val) == -1)
+ {
+ SCLogError(SC_ERR_INVALID_ARGUMENT, "vlan-id "
+ "of %s is invalid", vlan_id_node->val);
goto bad_mapping;
}
+ if (vlan_id == 0 || vlan_id >= 4095) {
+ SCLogError(SC_ERR_INVALID_ARGUMENT, "vlan-id "
+ "of %s is invalid. Valid range 1-4094.", vlan_id_node->val);
+ goto bad_mapping;
+ }
+
+ if (DetectEngineTentantRegisterVlanId(tenant_id, (uint32_t)vlan_id) != 0) {
+ goto error;
+ }
+ SCLogInfo("vlan %u connected to tenant-id %u", vlan_id, tenant_id);
+ mapping_cnt++;
continue;
bad_mapping:
@@ -1994,22 +2142,38 @@ void DetectEngineMultiTenantSetup(void)
}
}
+ if (tenant_selector == TENANT_SELECTOR_VLAN && mapping_cnt == 0) {
+ /* no mappings are valid when we're in unix socket mode,
+ * they can be added on the fly. Otherwise warn/error
+ * depending on failure_fatal */
+
+ if (unix_socket) {
+ SCLogNotice("no tenant traffic mappings defined, "
+ "tenants won't be used until mappings are added");
+ } else {
+ if (failure_fatal) {
+ SCLogError(SC_ERR_MT_NO_MAPPING, "no multi-detect mappings defined");
+ goto error;
+ } else {
+ SCLogWarning(SC_ERR_MT_NO_MAPPING, "no multi-detect mappings defined");
+ }
+ }
+ }
+
/* tenants */
ConfNode *tenants_root_node = ConfGetNode("multi-detect.tenants");
ConfNode *tenant_node = NULL;
if (tenants_root_node != NULL) {
TAILQ_FOREACH(tenant_node, &tenants_root_node->head, next) {
- if (strcmp(tenant_node->val, "tenant") != 0) {
- SCLogWarning(SC_ERR_INVALID_VALUE, "multi-detect.tenants expects a list of 'tenant's. Not %s", tenant_node->val);
- goto bad_tenant;
- }
ConfNode *id_node = ConfNodeLookupChild(tenant_node, "id");
- if (id_node == NULL)
+ if (id_node == NULL) {
goto bad_tenant;
+ }
ConfNode *yaml_node = ConfNodeLookupChild(tenant_node, "yaml");
- if (yaml_node == NULL)
+ if (yaml_node == NULL) {
goto bad_tenant;
+ }
uint32_t tenant_id = 0;
if (ByteExtractStringUint32(&tenant_id, 10, strlen(id_node->val),
@@ -2030,7 +2194,8 @@ void DetectEngineMultiTenantSetup(void)
goto bad_tenant;
}
- if (DetectLoaderSetupLoadTenant(tenant_id, yaml_node->val) != 0) {
+ int r = DetectLoaderSetupLoadTenant(tenant_id, yaml_node->val);
+ if (r < 0) {
/* error logged already */
goto bad_tenant;
}
@@ -2043,22 +2208,18 @@ void DetectEngineMultiTenantSetup(void)
}
/* wait for our loaders to complete their tasks */
- if (DetectLoadersSync() != 0)
- goto error;
-
- if (DetectEngineMTApply() < 0) {
- SCLogError(SC_ERR_DETECT_PREPARE, "initializing the detection engine failed");
+ if (DetectLoadersSync() != 0) {
goto error;
}
-
} else {
SCLogDebug("multi-detect not enabled (multi tenancy)");
}
+ return 0;
error:
- return;
+ return -1;
}
-uint32_t DetectEngineTentantGetIdFromVlanId(const void *ctx, const Packet *p)
+static uint32_t DetectEngineTentantGetIdFromVlanId(const void *ctx, const Packet *p)
{
const DetectEngineThreadCtx *det_ctx = ctx;
uint32_t x = 0;
@@ -2118,7 +2279,7 @@ static int DetectEngineTentantRegisterSelector(enum DetectEngineTenantSelectors
master->tenant_selector = selector;
- SCLogInfo("tenant handler %u %u %u registered", selector, tenant_id, traffic_id);
+ SCLogDebug("tenant handler %u %u %u registered", selector, tenant_id, traffic_id);
SCMutexUnlock(&master->lock);
return 0;
}
@@ -2181,7 +2342,7 @@ int DetectEngineTentantUnregisterPcapFile(uint32_t tenant_id)
return DetectEngineTentantUnregisterSelector(TENANT_SELECTOR_DIRECT, tenant_id, 0);
}
-uint32_t DetectEngineTentantGetIdFromPcap(const void *ctx, const Packet *p)
+static uint32_t DetectEngineTentantGetIdFromPcap(const void *ctx, const Packet *p)
{
return p->pcap_v.tenant_id;
}
@@ -2423,135 +2584,6 @@ static void TenantIdFree(void *d)
DetectEngineThreadCtxFree(d);
}
-/** NOTE: master MUST be locked before calling this */
-static DetectEngineThreadCtx *DetectEngineThreadCtxInitForMT(ThreadVars *tv)
-{
- DetectEngineMasterCtx *master = &g_master_de_ctx;
- DetectEngineTenantMapping *map_array = NULL;
- uint32_t map_array_size = 0;
- uint32_t map_cnt = 0;
- int max_tenant_id = 0;
- DetectEngineCtx *list = master->list;
- HashTable *mt_det_ctxs_hash = NULL;
- DetectEngineThreadCtx *det_ctx = NULL;
-
- if (master->tenant_selector == TENANT_SELECTOR_UNKNOWN) {
- SCLogError(SC_ERR_MT_NO_SELECTOR, "no tenant selector set: "
- "set using multi-detect.selector");
- return NULL;
- }
-
- uint32_t tcnt = 0;
- while (list) {
- if (list->tenant_id > max_tenant_id)
- max_tenant_id = list->tenant_id;
-
- list = list->next;
- tcnt++;
- }
-
- mt_det_ctxs_hash = HashTableInit(tcnt * 2, TenantIdHash, TenantIdCompare, TenantIdFree);
- if (mt_det_ctxs_hash == NULL) {
- goto error;
- }
-
- if (max_tenant_id == 0) {
- SCLogInfo("no tenants left, or none registered yet");
- } else {
- max_tenant_id++;
-
- DetectEngineTenantMapping *map = master->tenant_mapping_list;
- while (map) {
- map_cnt++;
- map = map->next;
- }
-
- if (map_cnt > 0) {
- map_array_size = map_cnt + 1;
-
- map_array = SCCalloc(map_array_size, sizeof(*map_array));
- if (map_array == NULL)
- goto error;
-
- /* fill the array */
- map_cnt = 0;
- map = master->tenant_mapping_list;
- while (map) {
- BUG_ON(map_cnt > map_array_size);
- map_array[map_cnt].traffic_id = map->traffic_id;
- map_array[map_cnt].tenant_id = map->tenant_id;
- map_cnt++;
- map = map->next;
- }
-
- }
-
- /* set up hash for tenant lookup */
- list = master->list;
- while (list) {
- if (list->tenant_id != 0) {
- DetectEngineThreadCtx *mt_det_ctx = DetectEngineThreadCtxInitForReload(tv, list);
- if (mt_det_ctx == NULL)
- goto error;
- BUG_ON(HashTableAdd(mt_det_ctxs_hash, mt_det_ctx, 0) != 0);
- }
- list = list->next;
- }
- }
-
- det_ctx = SCCalloc(1, sizeof(DetectEngineThreadCtx));
- if (det_ctx == NULL) {
- goto error;
- }
- det_ctx->mt_det_ctxs_hash = mt_det_ctxs_hash;
- mt_det_ctxs_hash = NULL;
-
- /* first register the counter. In delayed detect mode we exit right after if the
- * rules haven't been loaded yet. */
- uint16_t counter_alerts = StatsRegisterCounter("detect.alert", tv);
-#ifdef PROFILING
- uint16_t counter_mpm_list = StatsRegisterAvgCounter("detect.mpm_list", tv);
- uint16_t counter_nonmpm_list = StatsRegisterAvgCounter("detect.nonmpm_list", tv);
- uint16_t counter_fnonmpm_list = StatsRegisterAvgCounter("detect.fnonmpm_list", tv);
- uint16_t counter_match_list = StatsRegisterAvgCounter("detect.match_list", tv);
-#endif
- /** alert counter setup */
- det_ctx->counter_alerts = counter_alerts;
-#ifdef PROFILING
- det_ctx->counter_mpm_list = counter_mpm_list;
- det_ctx->counter_nonmpm_list = counter_nonmpm_list;
- det_ctx->counter_fnonmpm_list = counter_fnonmpm_list;
- det_ctx->counter_match_list = counter_match_list;
-#endif
- det_ctx->mt_det_ctxs_cnt = max_tenant_id;
-
- det_ctx->tenant_array = map_array;
- det_ctx->tenant_array_size = map_array_size;
-
- switch (master->tenant_selector) {
- case TENANT_SELECTOR_UNKNOWN:
- SCLogDebug("TENANT_SELECTOR_UNKNOWN");
- break;
- case TENANT_SELECTOR_VLAN:
- det_ctx->TenantGetId = DetectEngineTentantGetIdFromVlanId;
- SCLogDebug("TENANT_SELECTOR_VLAN");
- break;
- case TENANT_SELECTOR_DIRECT:
- det_ctx->TenantGetId = DetectEngineTentantGetIdFromPcap;
- SCLogDebug("TENANT_SELECTOR_DIRECT");
- break;
- }
-
- return det_ctx;
-error:
- if (map_array != NULL)
- SCFree(map_array);
- if (mt_det_ctxs_hash != NULL)
- HashTableFree(mt_det_ctxs_hash);
-
- return NULL;
-}
-
int DetectEngineMTApply(void)
{
DetectEngineMasterCtx *master = &g_master_de_ctx;
@@ -2564,13 +2596,25 @@ int DetectEngineMTApply(void)
}
DetectEngineCtx *minimal_de_ctx = NULL;
- /* if we have no tenants, we need a minimal on */
+ /* if we have no tenants, we need a minimal one */
if (master->list == NULL) {
minimal_de_ctx = master->list = DetectEngineCtxInitMinimal();
SCLogDebug("no tenants, using minimal %p", minimal_de_ctx);
} else if (master->list->next == NULL && master->list->tenant_id == 0) {
minimal_de_ctx = master->list;
SCLogDebug("no tenants, using original %p", minimal_de_ctx);
+
+ /* the default de_ctx should be in the list with tenant_id 0 */
+ } else {
+ DetectEngineCtx *list = master->list;
+ for ( ; list != NULL; list = list->next) {
+ SCLogInfo("list %p tenant %u", list, list->tenant_id);
+
+ if (list->tenant_id == 0) {
+ minimal_de_ctx = list;
+ break;
+ }
+ }
}
/* update the threads */
@@ -2646,6 +2690,9 @@ const char *DetectSigmatchListEnumToString(enum DetectSigmatchListEnum type)
case DETECT_SM_LIST_MODBUS_MATCH:
return "modbus";
+ case DETECT_SM_LIST_BASE64_DATA:
+ return "base64_data";
+
case DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH:
return "template_buffer";
diff --git a/framework/src/suricata/src/detect-engine.h b/framework/src/suricata/src/detect-engine.h
index 7b621710..70b18133 100644
--- a/framework/src/suricata/src/detect-engine.h
+++ b/framework/src/suricata/src/detect-engine.h
@@ -79,7 +79,7 @@ int DetectEngineReload(const char *filename, SCInstance *suri);
int DetectEngineEnabled(void);
int DetectEngineMTApply(void);
int DetectEngineMultiTenantEnabled(void);
-void DetectEngineMultiTenantSetup(void);
+int DetectEngineMultiTenantSetup(void);
int DetectEngineReloadStart(void);
int DetectEngineReloadIsStart(void);
diff --git a/framework/src/suricata/src/detect-parse.c b/framework/src/suricata/src/detect-parse.c
index 9ac53e03..f91e7591 100644
--- a/framework/src/suricata/src/detect-parse.c
+++ b/framework/src/suricata/src/detect-parse.c
@@ -1319,6 +1319,21 @@ int SigValidate(DetectEngineCtx *de_ctx, Signature *s)
}
}
+ if (s->sm_lists[DETECT_SM_LIST_BASE64_DATA] != NULL) {
+ int list;
+ uint16_t idx = s->sm_lists[DETECT_SM_LIST_BASE64_DATA]->idx;
+ for (list = 0; list < DETECT_SM_LIST_MAX; list++) {
+ if (list != DETECT_SM_LIST_BASE64_DATA &&
+ s->sm_lists[list] != NULL) {
+ if (s->sm_lists[list]->idx > idx) {
+ SCLogError(SC_ERR_INVALID_SIGNATURE, "Rule buffer "
+ "cannot be reset after base64_data.");
+ SCReturnInt(0);
+ }
+ }
+ }
+ }
+
#ifdef HAVE_LUA
DetectLuaPostSetup(s);
#endif
diff --git a/framework/src/suricata/src/detect.c b/framework/src/suricata/src/detect.c
index c9a16ead..401d2b00 100644
--- a/framework/src/suricata/src/detect.c
+++ b/framework/src/suricata/src/detect.c
@@ -60,6 +60,8 @@
#include "detect-engine-event.h"
#include "decode.h"
+#include "detect-base64-decode.h"
+#include "detect-base64-data.h"
#include "detect-ipopts.h"
#include "detect-flags.h"
#include "detect-fragbits.h"
@@ -1254,6 +1256,8 @@ int SigMatchSignatures(ThreadVars *th_v, DetectEngineCtx *de_ctx, DetectEngineTh
p->alerts.cnt = 0;
det_ctx->filestore_cnt = 0;
+ det_ctx->base64_decoded_len = 0;
+
/* No need to perform any detection on this packet, if the the given flag is set.*/
if (p->flags & PKT_NOPACKET_INSPECTION) {
SCReturnInt(0);
@@ -1994,12 +1998,10 @@ TmEcode Detect(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQue
det_ctx);
}
- if (det_ctx->TenantGetId != NULL) {
- /* in MT mode, but no tenants registered yet */
- if (det_ctx->mt_det_ctxs_cnt == 0) {
- return TM_ECODE_OK;
- }
-
+ /* if in MT mode _and_ we have tenants registered, use
+ * MT logic. */
+ if (det_ctx->mt_det_ctxs_cnt > 0 && det_ctx->TenantGetId != NULL)
+ {
uint32_t tenant_id = p->tenant_id;
if (tenant_id == 0)
tenant_id = det_ctx->TenantGetId(det_ctx, p);
@@ -2017,7 +2019,8 @@ TmEcode Detect(ThreadVars *tv, Packet *p, void *data, PacketQueue *pq, PacketQue
SCLogDebug("MT de_ctx %p det_ctx %p (tenant %u)", de_ctx, det_ctx, tenant_id);
}
} else {
- return TM_ECODE_OK;
+ /* use default if no tenants are registered for this packet */
+ de_ctx = det_ctx->de_ctx;
}
} else {
de_ctx = det_ctx->de_ctx;
@@ -5130,6 +5133,8 @@ void SigTableSetup(void)
DetectDnsQueryRegister();
DetectModbusRegister();
DetectAppLayerProtocolRegister();
+ DetectBase64DecodeRegister();
+ DetectBase64DataRegister();
DetectTemplateRegister();
DetectTemplateBufferRegister();
}
diff --git a/framework/src/suricata/src/detect.h b/framework/src/suricata/src/detect.h
index 8d131b92..89ce35ab 100644
--- a/framework/src/suricata/src/detect.h
+++ b/framework/src/suricata/src/detect.h
@@ -126,6 +126,8 @@ enum DetectSigmatchListEnum {
DETECT_SM_LIST_MODBUS_MATCH,
+ DETECT_SM_LIST_BASE64_DATA,
+
DETECT_SM_LIST_TEMPLATE_BUFFER_MATCH,
/* list for post match actions: flowbit set, flowint increment, etc */
@@ -687,6 +689,9 @@ typedef struct DetectEngineCtx_ {
* we can't lookup by proto, address, port as we don't have these */
struct SigGroupHead_ *decoder_event_sgh;
+ /* Maximum size of the buffer for decoded base64 data. */
+ uint32_t base64_decode_max_len;
+
/** Store rule file and line so that parsers can use them in errors. */
char *rule_file;
int rule_line;
@@ -883,6 +888,10 @@ typedef struct DetectEngineThreadCtx_ {
void **keyword_ctxs_array;
int keyword_ctxs_size;
+ uint8_t *base64_decoded;
+ int base64_decoded_len;
+ int base64_decoded_len_max;
+
#ifdef PROFILING
struct SCProfileData_ *rule_perf_data;
int rule_perf_data_size;
@@ -1221,6 +1230,8 @@ enum {
DETECT_AL_MODBUS,
DETECT_XBITS,
+ DETECT_BASE64_DECODE,
+ DETECT_BASE64_DATA,
DETECT_TEMPLATE,
DETECT_AL_TEMPLATE_BUFFER,
diff --git a/framework/src/suricata/src/log-tlslog.c b/framework/src/suricata/src/log-tlslog.c
index edb0ded2..53ebad8b 100644
--- a/framework/src/suricata/src/log-tlslog.c
+++ b/framework/src/suricata/src/log-tlslog.c
@@ -83,6 +83,9 @@ static void LogTlsLogExtended(LogTlsLogThread *aft, SSLState * state)
if (state->server_connp.cert0_fingerprint != NULL) {
MemBufferWriteString(aft->buffer, " SHA1='%s'", state->server_connp.cert0_fingerprint);
}
+ if (state->client_connp.sni != NULL) {
+ MemBufferWriteString(aft->buffer, " SNI='%s'", state->client_connp.sni);
+ }
switch (state->server_connp.version) {
case TLS_VERSION_UNKNOWN:
MemBufferWriteString(aft->buffer, " VERSION='UNDETERMINED'");
diff --git a/framework/src/suricata/src/output-json-tls.c b/framework/src/suricata/src/output-json-tls.c
index 4cbd21ae..d8b8078f 100644
--- a/framework/src/suricata/src/output-json-tls.c
+++ b/framework/src/suricata/src/output-json-tls.c
@@ -92,6 +92,12 @@ void JsonTlsLogJSONExtended(json_t *tjs, SSLState * state)
json_object_set_new(tjs, "fingerprint",
json_string(state->server_connp.cert0_fingerprint));
+ /* tls.sni */
+ if (state->client_connp.sni) {
+ json_object_set_new(tjs, "sni",
+ json_string(state->client_connp.sni));
+ }
+
/* tls.version */
switch (state->server_connp.version) {
case TLS_VERSION_UNKNOWN:
diff --git a/framework/src/suricata/src/output-json.c b/framework/src/suricata/src/output-json.c
index 9cc9bd94..b9c2b886 100644
--- a/framework/src/suricata/src/output-json.c
+++ b/framework/src/suricata/src/output-json.c
@@ -345,7 +345,7 @@ static int MemBufferCallback(const char *str, size_t size, void *data)
MemBufferExpand(&memb, OUTPUT_BUFFER_SIZE);
}
#endif
- MemBufferWriteString(memb, "%s", str);
+ MemBufferWriteRaw(memb, str, size);
return 0;
}
@@ -356,6 +356,9 @@ int OutputJSONBuffer(json_t *js, LogFileCtx *file_ctx, MemBuffer *buffer)
json_string(file_ctx->sensor_name));
}
+ if (file_ctx->prefix)
+ MemBufferWriteRaw(buffer, file_ctx->prefix, file_ctx->prefix_len);
+
int r = json_dump_callback(js, MemBufferCallback, buffer,
JSON_PRESERVE_ORDER|JSON_COMPACT|JSON_ENSURE_ASCII|
#ifdef JSON_ESCAPE_SLASH
@@ -496,6 +499,7 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf)
const char *prefix = ConfNodeLookupChildValue(conf, "prefix");
if (prefix != NULL)
{
+ SCLogInfo("Using prefix '%s' for JSON messages", prefix);
json_ctx->file_ctx->prefix = SCStrdup(prefix);
if (json_ctx->file_ctx->prefix == NULL)
{
@@ -503,6 +507,7 @@ OutputCtx *OutputJsonInitCtx(ConfNode *conf)
"Failed to allocate memory for eve-log.prefix setting.");
exit(EXIT_FAILURE);
}
+ json_ctx->file_ctx->prefix_len = strlen(prefix);
}
if (json_ctx->json_out == LOGFILE_TYPE_FILE ||
diff --git a/framework/src/suricata/src/runmode-unittests.c b/framework/src/suricata/src/runmode-unittests.c
index 3701d29a..33220209 100644
--- a/framework/src/suricata/src/runmode-unittests.c
+++ b/framework/src/suricata/src/runmode-unittests.c
@@ -206,7 +206,6 @@ void RunUnittests(int list_unittests, char *regex_arg)
StatsRegisterTests();
DecodePPPRegisterTests();
DecodeVLANRegisterTests();
- HTPParserRegisterTests();
DecodeRawRegisterTests();
DecodePPPOERegisterTests();
DecodeICMPV4RegisterTests();
diff --git a/framework/src/suricata/src/suricata.c b/framework/src/suricata/src/suricata.c
index 173ef75f..b368f21d 100644
--- a/framework/src/suricata/src/suricata.c
+++ b/framework/src/suricata/src/suricata.c
@@ -2285,12 +2285,21 @@ int main(int argc, char **argv)
if (!suri.disabled_detect) {
SCClassConfInit();
SCReferenceConfInit();
- DetectEngineMultiTenantSetup();
SetupDelayedDetect(&suri);
- if (!suri.delayed_detect) {
- de_ctx = DetectEngineCtxInit();
- } else {
+ int mt_enabled = 0;
+ (void)ConfGetBool("multi-detect.enabled", &mt_enabled);
+ int default_tenant = 0;
+ if (mt_enabled)
+ (void)ConfGetBool("multi-detect.default", &default_tenant);
+ if (DetectEngineMultiTenantSetup() == -1) {
+ SCLogError(SC_ERR_INITIALIZATION, "initializing multi-detect "
+ "detection engine contexts failed.");
+ exit(EXIT_FAILURE);
+ }
+ if (suri.delayed_detect || (mt_enabled && !default_tenant)) {
de_ctx = DetectEngineCtxInitMinimal();
+ } else {
+ de_ctx = DetectEngineCtxInit();
}
if (de_ctx == NULL) {
SCLogError(SC_ERR_INITIALIZATION, "initializing detection engine "
@@ -2303,7 +2312,7 @@ int main(int argc, char **argv)
CudaVarsSetDeCtx(de_ctx);
#endif /* __SC_CUDA_SUPPORT__ */
- if (!suri.delayed_detect) {
+ if (!de_ctx->minimal) {
if (LoadSignatures(de_ctx, &suri) != TM_ECODE_OK)
exit(EXIT_FAILURE);
if (suri.run_mode == RUNMODE_ENGINE_ANALYSIS) {
diff --git a/framework/src/suricata/src/suricata.h b/framework/src/suricata/src/suricata.h
index 12e72697..b11239ac 100644
--- a/framework/src/suricata/src/suricata.h
+++ b/framework/src/suricata/src/suricata.h
@@ -71,7 +71,7 @@
/* the name of our binary */
#define PROG_NAME "Suricata"
-#define PROG_VER "2.1dev"
+#define PROG_VER "3.0dev"
/* workaround SPlint error (don't know __gnuc_va_list) */
#ifdef S_SPLINT_S
diff --git a/framework/src/suricata/src/util-base64.c b/framework/src/suricata/src/util-base64.c
index f4b508a0..bea92d52 100644
--- a/framework/src/suricata/src/util-base64.c
+++ b/framework/src/suricata/src/util-base64.c
@@ -50,8 +50,8 @@ static const int b64table[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
*
* \return The decoded value (0 or above), or -1 if the parameter is invalid
*/
-static inline int GetBase64Value(uint8_t c) {
-
+static inline int GetBase64Value(uint8_t c)
+{
int val = -1;
/* Pull from conversion table */
@@ -70,8 +70,8 @@ static inline int GetBase64Value(uint8_t c) {
*
* \return none
*/
-static inline void DecodeBase64Block(uint8_t ascii[ASCII_BLOCK], uint8_t b64[B64_BLOCK]) {
-
+static inline void DecodeBase64Block(uint8_t ascii[ASCII_BLOCK], uint8_t b64[B64_BLOCK])
+{
ascii[0] = (uint8_t) (b64[0] << 2) | (b64[1] >> 4);
ascii[1] = (uint8_t) (b64[1] << 4) | (b64[2] >> 2);
ascii[2] = (uint8_t) (b64[2] << 6) | (b64[3]);
@@ -83,11 +83,14 @@ static inline void DecodeBase64Block(uint8_t ascii[ASCII_BLOCK], uint8_t b64[B64
* \param dest The destination byte buffer
* \param src The source string
* \param len The length of the source string
+ * \param strict If set file on invalid byte, otherwise return what has been
+ * decoded.
*
* \return Number of bytes decoded, or 0 if no data is decoded or it fails
*/
-uint32_t DecodeBase64(uint8_t *dest, const uint8_t *src, uint32_t len) {
-
+uint32_t DecodeBase64(uint8_t *dest, const uint8_t *src, uint32_t len,
+ int strict)
+{
int val;
uint32_t padding = 0, numDecoded = 0, bbidx = 0, valid = 1, i;
uint8_t *dptr = dest;
@@ -103,7 +106,9 @@ uint32_t DecodeBase64(uint8_t *dest, const uint8_t *src, uint32_t len) {
/* Invalid character found, so decoding fails */
if (src[i] != '=') {
valid = 0;
- numDecoded = 0;
+ if (strict) {
+ numDecoded = 0;
+ }
break;
}
padding++;
diff --git a/framework/src/suricata/src/util-base64.h b/framework/src/suricata/src/util-base64.h
index fb1a90a3..7c8bed62 100644
--- a/framework/src/suricata/src/util-base64.h
+++ b/framework/src/suricata/src/util-base64.h
@@ -49,6 +49,7 @@
#define B64_BLOCK 4
/* Function prototypes */
-uint32_t DecodeBase64(uint8_t *dest, const uint8_t *src, uint32_t len);
+uint32_t DecodeBase64(uint8_t *dest, const uint8_t *src, uint32_t len,
+ int strict);
#endif
diff --git a/framework/src/suricata/src/util-decode-mime.c b/framework/src/suricata/src/util-decode-mime.c
index 51d1468e..ded4cd60 100644
--- a/framework/src/suricata/src/util-decode-mime.c
+++ b/framework/src/suricata/src/util-decode-mime.c
@@ -1227,7 +1227,7 @@ static uint8_t ProcessBase64Remainder(const uint8_t *buf, uint32_t len,
/* Only decode if divisible by 4 */
if (state->bvr_len == B64_BLOCK || force) {
remdec = DecodeBase64(state->data_chunk + state->data_chunk_len,
- state->bvremain, state->bvr_len);
+ state->bvremain, state->bvr_len, 1);
if (remdec > 0) {
/* Track decoded length */
@@ -1329,7 +1329,7 @@ static int ProcessBase64BodyLine(const uint8_t *buf, uint32_t len,
SCLogDebug("Decoding: %u", len - rem1 - rem2);
numDecoded = DecodeBase64(state->data_chunk + state->data_chunk_len,
- buf + offset, tobuf);
+ buf + offset, tobuf, 1);
if (numDecoded > 0) {
/* Track decoded length */
@@ -2888,7 +2888,7 @@ static int MimeBase64DecodeTest01(void)
if (dst == NULL)
return 0;
- ret = DecodeBase64(dst, (const uint8_t *)base64msg, strlen(base64msg));
+ ret = DecodeBase64(dst, (const uint8_t *)base64msg, strlen(base64msg), 1);
if (memcmp(dst, msg, strlen(msg)) == 0) {
ret = 0;
diff --git a/framework/src/suricata/src/util-error.c b/framework/src/suricata/src/util-error.c
index 461e1870..7f2caf00 100644
--- a/framework/src/suricata/src/util-error.c
+++ b/framework/src/suricata/src/util-error.c
@@ -309,7 +309,9 @@ const char * SCErrorToString(SCError err)
CASE_CODE (SC_ERR_IPPAIR_INIT);
CASE_CODE (SC_ERR_MT_NO_SELECTOR);
CASE_CODE (SC_ERR_MT_DUPLICATE_TENANT);
+ CASE_CODE (SC_ERR_MT_NO_MAPPING);
CASE_CODE (SC_ERR_NO_JSON_SUPPORT);
+ CASE_CODE (SC_ERR_INVALID_RULE_ARGUMENT);
}
return "UNKNOWN_ERROR";
diff --git a/framework/src/suricata/src/util-error.h b/framework/src/suricata/src/util-error.h
index b7df4766..cd2ce249 100644
--- a/framework/src/suricata/src/util-error.h
+++ b/framework/src/suricata/src/util-error.h
@@ -299,6 +299,9 @@ typedef enum {
SC_ERR_MT_NO_SELECTOR,
SC_ERR_MT_DUPLICATE_TENANT,
SC_ERR_NO_JSON_SUPPORT,
+ SC_ERR_INVALID_RULE_ARGUMENT, /**< Generic error code for invalid
+ * rule argument. */
+ SC_ERR_MT_NO_MAPPING,
} SCError;
const char *SCErrorToString(SCError);
diff --git a/framework/src/suricata/src/util-logopenfile.c b/framework/src/suricata/src/util-logopenfile.c
index 65b80fac..84e5d2fe 100644
--- a/framework/src/suricata/src/util-logopenfile.c
+++ b/framework/src/suricata/src/util-logopenfile.c
@@ -519,8 +519,10 @@ int LogFileFreeCtx(LogFileCtx *lf_ctx)
SCMutexDestroy(&lf_ctx->fp_mutex);
- if (lf_ctx->prefix != NULL)
+ if (lf_ctx->prefix != NULL) {
SCFree(lf_ctx->prefix);
+ lf_ctx->prefix_len = 0;
+ }
if(lf_ctx->filename != NULL)
SCFree(lf_ctx->filename);
diff --git a/framework/src/suricata/src/util-logopenfile.h b/framework/src/suricata/src/util-logopenfile.h
index f0a123ac..cccbba47 100644
--- a/framework/src/suricata/src/util-logopenfile.h
+++ b/framework/src/suricata/src/util-logopenfile.h
@@ -102,6 +102,7 @@ typedef struct LogFileCtx_ {
/**< Used by some alert loggers like the unified ones that append
* the date onto the end of files. */
char *prefix;
+ size_t prefix_len;
/** Generic size_limit and size_current
* They must be common to the threads accesing the same file */
diff --git a/framework/src/suricata/src/util-lua-tls.c b/framework/src/suricata/src/util-lua-tls.c
index 8816d5d5..5963ac24 100644
--- a/framework/src/suricata/src/util-lua-tls.c
+++ b/framework/src/suricata/src/util-lua-tls.c
@@ -133,12 +133,53 @@ static int TlsGetCertInfo(lua_State *luastate)
return r;
}
+static int GetSNI(lua_State *luastate, const Flow *f)
+{
+ void *state = FlowGetAppState(f);
+ if (state == NULL)
+ return LuaCallbackError(luastate, "error: no app layer state");
+
+ SSLState *ssl_state = (SSLState *)state;
+
+ if (ssl_state->client_connp.sni == NULL)
+ return LuaCallbackError(luastate, "error: no server name indication");
+
+ return LuaPushStringBuffer(luastate, (uint8_t *)ssl_state->client_connp.sni,
+ strlen(ssl_state->client_connp.sni));
+}
+
+static int TlsGetSNI(lua_State *luastate)
+{
+ int r;
+
+ if (!(LuaStateNeedProto(luastate, ALPROTO_TLS)))
+ return LuaCallbackError(luastate, "error: protocol not tls");
+
+ int lock_hint = 0;
+ Flow *f = LuaStateGetFlow(luastate, &lock_hint);
+ if (f == NULL)
+ return LuaCallbackError(luastate, "internal error: no flow");
+
+ if (lock_hint == LUA_FLOW_NOT_LOCKED_BY_PARENT) {
+ FLOWLOCK_RDLOCK(f);
+ r = GetSNI(luastate, f);
+ FLOWLOCK_UNLOCK(f);
+ } else {
+ r = GetSNI(luastate, f);
+ }
+ return r;
+}
+
/** \brief register tls lua extensions in a luastate */
int LuaRegisterTlsFunctions(lua_State *luastate)
{
/* registration of the callbacks */
lua_pushcfunction(luastate, TlsGetCertInfo);
lua_setglobal(luastate, "TlsGetCertInfo");
+
+ lua_pushcfunction(luastate, TlsGetSNI);
+ lua_setglobal(luastate, "TlsGetSNI");
+
return 0;
}
diff --git a/framework/src/suricata/src/util-profiling-locks.c b/framework/src/suricata/src/util-profiling-locks.c
index 97cc3e0d..7719e6d5 100644
--- a/framework/src/suricata/src/util-profiling-locks.c
+++ b/framework/src/suricata/src/util-profiling-locks.c
@@ -24,13 +24,13 @@
*
*/
-#ifdef PROFILING
-#ifdef PROFILE_LOCKING
-
#include "suricata-common.h"
#include "util-profiling-locks.h"
#include "util-hashlist.h"
+#ifdef PROFILING
+#ifdef PROFILE_LOCKING
+
__thread ProfilingLock locks[PROFILING_MAX_LOCKS];
__thread int locks_idx = 0;
__thread int record_locks = 0;
diff --git a/framework/src/suricata/src/util-rule-vars.c b/framework/src/suricata/src/util-rule-vars.c
index f3b5604f..57347f4f 100644
--- a/framework/src/suricata/src/util-rule-vars.c
+++ b/framework/src/suricata/src/util-rule-vars.c
@@ -75,7 +75,7 @@ char *SCRuleVarsGetConfVar(const DetectEngineCtx *de_ctx,
if (conf_var_name == NULL)
goto end;
- while (conf_var_name[0] != '\0' && isspace(conf_var_name[0])) {
+ while (conf_var_name[0] != '\0' && isspace((unsigned char)conf_var_name[0])) {
conf_var_name++;
}