From e63291850fd0795c5700e25e67e5dee89ba54c5f Mon Sep 17 00:00:00 2001 From: Ashlee Young Date: Tue, 1 Dec 2015 05:49:27 -0800 Subject: onos commit hash c2999f30c69e50df905a9d175ef80b3f23a98514 Change-Id: I2bb8562c4942b6d6a6d60b663db2e17540477b81 Signed-off-by: Ashlee Young --- framework/src/suricata/ChangeLog | 53 +++ framework/src/suricata/configure.ac | 2 +- framework/src/suricata/src/Makefile.am | 2 + framework/src/suricata/src/app-layer-dns-common.c | 2 +- framework/src/suricata/src/app-layer-htp.c | 432 ++++++++++++++++---- framework/src/suricata/src/app-layer-smtp.c | 7 +- framework/src/suricata/src/app-layer-ssl.c | 101 ++++- framework/src/suricata/src/app-layer-ssl.h | 6 +- .../src/detect-engine-content-inspection.c | 18 +- .../src/detect-engine-content-inspection.h | 1 + framework/src/suricata/src/detect-engine.c | 441 ++++++++++++--------- framework/src/suricata/src/detect-engine.h | 2 +- framework/src/suricata/src/detect-parse.c | 15 + framework/src/suricata/src/detect.c | 19 +- framework/src/suricata/src/detect.h | 11 + framework/src/suricata/src/log-tlslog.c | 3 + framework/src/suricata/src/output-json-tls.c | 6 + framework/src/suricata/src/output-json.c | 7 +- framework/src/suricata/src/runmode-unittests.c | 1 - framework/src/suricata/src/suricata.c | 19 +- framework/src/suricata/src/suricata.h | 2 +- framework/src/suricata/src/util-base64.c | 19 +- framework/src/suricata/src/util-base64.h | 3 +- framework/src/suricata/src/util-decode-mime.c | 6 +- framework/src/suricata/src/util-error.c | 2 + framework/src/suricata/src/util-error.h | 3 + framework/src/suricata/src/util-logopenfile.c | 4 +- framework/src/suricata/src/util-logopenfile.h | 1 + framework/src/suricata/src/util-lua-tls.c | 41 ++ framework/src/suricata/src/util-profiling-locks.c | 6 +- framework/src/suricata/src/util-rule-vars.c | 2 +- 31 files changed, 933 insertions(+), 304 deletions(-) (limited to 'framework/src/suricata') diff --git a/framework/src/suricata/ChangeLog b/framework/src/suricata/ChangeLog index a265dd76..a7e64598 100644 --- a/framework/src/suricata/ChangeLog +++ b/framework/src/suricata/ChangeLog @@ -1,3 +1,56 @@ +3.0RC1 -- 2015-11-25 + +Bug #1150: TLS store disabled by TLS EVE logging +Bug #1210: global counters in stats.log +Bug #1423: Unix domain log file writer should automatically reconnect if receiving program is restarted. +Bug #1466: Rule reload - Rules won't reload if rule files are listed in an included file. +Bug #1467: Specifying an IPv6 entry before an IPv4 entry in host-os-policy causes ASAN heap-buffer-overflow. +Bug #1472: Should 'goodsigs' be 'goodtotal' when checking if signatures were loaded in detect.c? +Bug #1475: app-layer-modbus: AddressSanitizer error (heap-buffer-overflow) +Bug #1481: Leading whitespace in flowbits variable names +Bug #1482: suricata 2.1 beta4: StoreStateTxFileOnly crashes +Bug #1485: hostbits - leading and trailing spaces are treated as part of the name and direction. +Bug #1488: stream_size <= and >= modifiers function as < and > (equality is not functional) +Bug #1491: pf_ring is not able to capture packets when running under non-root account +Bug #1493: config test (-T) doesn't fail on missing files +Bug #1494: off by one on rulefile count +Bug #1500: suricata.log +Bug #1508: address var parsing issue +Bug #1517: Order dependent, ambiguous YAML in multi-detect. +Bug #1518: multitenancy - selector vlan - vlan id range +Bug #1521: multitenancy - global vlan tracking relation to selector +Bug #1523: Decoded base64 payload short by 16 characters +Bug #1530: multitenant mapping relation +Bug #1531: multitenancy - confusing tenant id and vlan id output +Bug #1556: MTU setting on NIC interface not considered by af-packet +Bug #1557: stream: retransmission not detected +Bug #1565: defrag: evasion issue +Bug #1597: dns parser issue (master) +Bug #1601: tls: server name logging +Feature #1116: ips packet stats in stats.log +Feature #1137: Support IP lists in threshold.config +Feature #1228: Suricata stats.log in JSON format +Feature #1265: Replace response on Suricata dns decoder when dns error please +Feature #1281: long snort ruleset support for "SC_ERR_NOT_SUPPORTED(225): content length greater than 255 unsupported" +Feature #1282: support for base64_decode from snort's ruleset +Feature #1342: Support Cisco erspan traffic +Feature #1374: Write pre-aggregated counters for all threads +Feature #1408: multi tenancy for detection +Feature #1440: Load rules file from a folder or with a star pattern rather then adding them manually to suricata.yaml +Feature #1454: Proposal to add Lumberjack/CEE formatting option to EVE JSON syslog output for compatibility with rsyslog parsing +Feature #1492: Add HUP coverage to output json-log +Feature #1498: color output +Feature #1499: json output for engine messages +Feature #1502: Expose tls fields to lua +Feature #1514: SSH softwareversion regex should allow colon +Feature #1527: Add ability to compile as a Position-Independent Executable (PIE) +Feature #1568: TLS lua output support +Feature #1569: SSH lua support +Feature #1582: Redis output support +Feature #1586: Add flow memcap counter +Feature #1599: rule profiling: json output +Optimization #1269: Convert SM List from linked list to array + 2.1beta4 -- 2015-05-08 Bug #1314: http-events performance issues diff --git a/framework/src/suricata/configure.ac b/framework/src/suricata/configure.ac index 9e139383..f3d20a1f 100644 --- a/framework/src/suricata/configure.ac +++ b/framework/src/suricata/configure.ac @@ -1,4 +1,4 @@ - AC_INIT(suricata, 2.1dev) + AC_INIT(suricata, 3.0dev) m4_ifndef([AM_SILENT_RULES], [m4_define([AM_SILENT_RULES],[])])AM_SILENT_RULES([yes]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_SRCDIR([src/suricata.c]) 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++; } -- cgit 1.2.3-korg