http2: rename http2.header to http.request_header

Or http.response_header based on the direction

http2.header had a different behavior than http.header and this was
confusing.

Ticket: #5780
pull/9001/head
Philippe Antoine 2 years ago committed by Victor Julien
parent 746fb50d58
commit 656554f293

@ -110,22 +110,38 @@ Examples::
``http2.header_name`` can be used as ``fast_pattern``.
http2.header
-----------------
http.request_header
-------------------
Match on the name and value of a HTTP2 header from a HEADER frame (or PUSH_PROMISE or CONTINUATION).
Match on the name and value of a HTTP2 request header from a HEADER frame (or PUSH_PROMISE or CONTINUATION).
Name and value get concatenated by ": ", colon and space.
Each colon in the name or the value should be escaped as a double colon "::" for detection
Examples::
http2.header; content:"agent: nghttp2";
http2.header; content:"custom-header: I love::colons";
http.request_header; content:"agent: nghttp2";
http.request_header; content:"custom-header: I love::colons";
``http.request_header`` is a 'sticky buffer'.
``http.request_header`` can be used as ``fast_pattern``.
http.response_header
--------------------
Match on the name and value of a HTTP2 response header from a HEADER frame (or PUSH_PROMISE or CONTINUATION).
Name and value get concatenated by ": ", colon and space.
Each colon in the name or the value should be escaped as a double colon "::" for detection
Examples::
``http2.header`` is a 'sticky buffer'.
http.response_header; content:"server: nghttp2";
http.response_header; content:"custom-header: I love::colons";
``http2.header`` can be used as ``fast_pattern``.
``http.response_header`` is a 'sticky buffer'.
``http.response_header`` can be used as ``fast_pattern``.
Additional information
----------------------

@ -72,6 +72,7 @@ Deprecations
Other changes
~~~~~~~~~~~~~
- Experimental keyword `http2.header` is removed. `http.header`, `http.request_header`, and `http.response_header` are to be used.
- NSS is no longer required. File hashing and JA3 can now be used without the NSS compile time dependency.
- If installing Suricata without the bundled Suricata-Update, the ``default-rule-path`` has been changed from ``/etc/suricata/rules`` to ``/var/lib/suricata/rules`` to be consistent with Suricata when installed with Suricata-Update.
- FTP has been updated with a maximum command request and response line length of 4096 bytes. To change the default see :ref:`suricata-yaml-configure-ftp`.

@ -187,7 +187,8 @@ enum DetectKeywordId {
DETECT_HTTP2_SIZEUPDATE,
DETECT_HTTP2_SETTINGS,
DETECT_HTTP2_HEADERNAME,
DETECT_HTTP2_HEADER,
DETECT_HTTP_REQUEST_HEADER,
DETECT_HTTP_RESPONSE_HEADER,
DETECT_DCE_IFACE,
DETECT_DCE_OPNUM,

@ -92,13 +92,15 @@ static uint8_t DetectEngineInspectHttp2HeaderName(DetectEngineCtx *de_ctx,
DetectEngineThreadCtx *det_ctx, const DetectEngineAppInspectionEngine *engine,
const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id);
static int DetectHTTP2headerSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg);
static int DetectHTTPRequestHeaderSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg);
static int DetectHTTPResponseHeaderSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg);
static int PrefilterMpmHttp2HeaderRegister(DetectEngineCtx *de_ctx, SigGroupHead *sgh,
MpmCtx *mpm_ctx, const DetectBufferMpmRegistry *mpm_reg, int list_id);
static uint8_t DetectEngineInspectHttp2Header(DetectEngineCtx *de_ctx,
DetectEngineThreadCtx *det_ctx, const DetectEngineAppInspectionEngine *engine,
const Signature *s, Flow *f, uint8_t flags, void *alstate, void *txv, uint64_t tx_id);
static bool DetectHttp2HeaderValidateCallback(const Signature *s, const char **sigerror);
static bool DetectHttp2RequestHeaderValidateCallback(const Signature *s, const char **sigerror);
static bool DetectHttp2ResponseHeaderValidateCallback(const Signature *s, const char **sigerror);
#ifdef UNITTESTS
void DetectHTTP2RegisterTests (void);
@ -106,8 +108,8 @@ void DetectHTTP2RegisterTests (void);
static int g_http2_match_buffer_id = 0;
static int g_http2_header_name_buffer_id = 0;
static int g_http2_header_buffer_id = 0;
static int g_http_request_header_buffer_id = 0;
static int g_http_response_header_buffer_id = 0;
/**
* \brief Registration function for HTTP2 keywords
@ -204,30 +206,39 @@ void DetectHttp2Register(void)
"HTTP2 header name");
g_http2_header_name_buffer_id = DetectBufferTypeGetByName("http2_header_name");
sigmatch_table[DETECT_HTTP2_HEADER].name = "http2.header";
sigmatch_table[DETECT_HTTP2_HEADER].desc = "sticky buffer to match on one HTTP2 header name and value";
sigmatch_table[DETECT_HTTP2_HEADER].url = "/rules/http2-keywords.html#header";
sigmatch_table[DETECT_HTTP2_HEADER].Setup = DetectHTTP2headerSetup;
sigmatch_table[DETECT_HTTP2_HEADER].flags |= SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER;
DetectBufferTypeSupportsMultiInstance("http2_header");
DetectAppLayerMpmRegister2("http2_header", SIG_FLAG_TOCLIENT, 2,
PrefilterMpmHttp2HeaderRegister, NULL,
ALPROTO_HTTP2, HTTP2StateOpen);
DetectAppLayerInspectEngineRegister2("http2_header",
ALPROTO_HTTP2, SIG_FLAG_TOCLIENT, HTTP2StateOpen,
DetectEngineInspectHttp2Header, NULL);
DetectAppLayerMpmRegister2("http2_header", SIG_FLAG_TOSERVER, 2,
PrefilterMpmHttp2HeaderRegister, NULL,
ALPROTO_HTTP2, HTTP2StateOpen);
DetectAppLayerInspectEngineRegister2("http2_header",
ALPROTO_HTTP2, SIG_FLAG_TOSERVER, HTTP2StateOpen,
DetectEngineInspectHttp2Header, NULL);
DetectBufferTypeSetDescriptionByName("http2_header",
"HTTP2 header name and value");
DetectBufferTypeRegisterValidateCallback("http2_header", DetectHttp2HeaderValidateCallback);
g_http2_header_buffer_id = DetectBufferTypeGetByName("http2_header");
sigmatch_table[DETECT_HTTP_REQUEST_HEADER].name = "http.request_header";
sigmatch_table[DETECT_HTTP_REQUEST_HEADER].desc =
"sticky buffer to match on only one HTTP header name and value";
sigmatch_table[DETECT_HTTP_REQUEST_HEADER].url = "/rules/http2-keywords.html#request_header";
sigmatch_table[DETECT_HTTP_REQUEST_HEADER].Setup = DetectHTTPRequestHeaderSetup;
sigmatch_table[DETECT_HTTP_REQUEST_HEADER].flags |=
SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER;
DetectAppLayerMpmRegister2("http_request_header", SIG_FLAG_TOSERVER, 2,
PrefilterMpmHttp2HeaderRegister, NULL, ALPROTO_HTTP2, HTTP2StateOpen);
DetectAppLayerInspectEngineRegister2("http_request_header", ALPROTO_HTTP2, SIG_FLAG_TOSERVER,
HTTP2StateOpen, DetectEngineInspectHttp2Header, NULL);
DetectBufferTypeRegisterValidateCallback(
"http_request_header", DetectHttp2RequestHeaderValidateCallback);
DetectBufferTypeSetDescriptionByName("http_request_header", "HTTP header name and value");
g_http_request_header_buffer_id = DetectBufferTypeGetByName("http_request_header");
sigmatch_table[DETECT_HTTP_RESPONSE_HEADER].name = "http.response_header";
sigmatch_table[DETECT_HTTP_RESPONSE_HEADER].desc =
"sticky buffer to match on only one HTTP header name and value";
sigmatch_table[DETECT_HTTP_RESPONSE_HEADER].url = "/rules/http2-keywords.html#response_header";
sigmatch_table[DETECT_HTTP_RESPONSE_HEADER].Setup = DetectHTTPResponseHeaderSetup;
sigmatch_table[DETECT_HTTP_RESPONSE_HEADER].flags |=
SIGMATCH_NOOPT | SIGMATCH_INFO_STICKY_BUFFER;
DetectAppLayerMpmRegister2("http_response_header", SIG_FLAG_TOCLIENT, 2,
PrefilterMpmHttp2HeaderRegister, NULL, ALPROTO_HTTP2, HTTP2StateOpen);
DetectAppLayerInspectEngineRegister2("http_response_header", ALPROTO_HTTP2, SIG_FLAG_TOCLIENT,
HTTP2StateOpen, DetectEngineInspectHttp2Header, NULL);
DetectBufferTypeRegisterValidateCallback(
"http_response_header", DetectHttp2ResponseHeaderValidateCallback);
DetectBufferTypeSetDescriptionByName("http_response_header", "HTTP header name and value");
g_http_response_header_buffer_id = DetectBufferTypeGetByName("http_response_header");
DetectAppLayerInspectEngineRegister2(
"http2", ALPROTO_HTTP2, SIG_FLAG_TOSERVER, 0, DetectEngineInspectGenericList, NULL);
@ -787,9 +798,20 @@ static uint8_t DetectEngineInspectHttp2HeaderName(DetectEngineCtx *de_ctx,
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
}
static int DetectHTTP2headerSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
static int DetectHTTPRequestHeaderSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
{
if (DetectBufferSetActiveList(de_ctx, s, g_http_request_header_buffer_id) < 0)
return -1;
if (DetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0)
return -1;
return 0;
}
static int DetectHTTPResponseHeaderSetup(DetectEngineCtx *de_ctx, Signature *s, const char *arg)
{
if (DetectBufferSetActiveList(de_ctx, s, g_http2_header_buffer_id) < 0)
if (DetectBufferSetActiveList(de_ctx, s, g_http_response_header_buffer_id) < 0)
return -1;
if (DetectSignatureSetAppProto(s, ALPROTO_HTTP2) != 0)
@ -917,54 +939,72 @@ static uint8_t DetectEngineInspectHttp2Header(DetectEngineCtx *de_ctx,
return DETECT_ENGINE_INSPECT_SIG_NO_MATCH;
}
static bool DetectHttp2HeaderValidateCallback(const Signature *s, const char **sigerror)
static bool DetectHttp2HeaderValidateCallback(
const Signature *s, const char **sigerror, int buffer_id)
{
for (uint32_t x = 0; x < s->init_data->buffer_index; x++) {
if (s->init_data->buffers[x].id != (uint32_t)g_http2_header_buffer_id)
if (s->init_data->buffers[x].id != (uint32_t)g_http_request_header_buffer_id &&
s->init_data->buffers[x].id != (uint32_t)g_http_response_header_buffer_id)
continue;
const SigMatch *sm = s->init_data->buffers[x].head;
for (; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_CONTENT)
continue;
const DetectContentData *cd = (DetectContentData *)sm->ctx;
bool escaped = false;
bool namevaluesep = false;
for (size_t i = 0; i < cd->content_len; ++i) {
if (escaped) {
if (cd->content[i] == ' ') {
if (namevaluesep) {
*sigerror = "Invalid http2.header string : "
const SigMatch *sm = s->init_data->buffers[x].head;
for (; sm != NULL; sm = sm->next) {
if (sm->type != DETECT_CONTENT)
continue;
const DetectContentData *cd = (DetectContentData *)sm->ctx;
bool escaped = false;
bool namevaluesep = false;
for (size_t i = 0; i < cd->content_len; ++i) {
if (escaped) {
if (cd->content[i] == ' ') {
if (namevaluesep) {
*sigerror =
"Invalid http2.header string : "
"': ' is a special sequence for separation between name "
"and value "
" and thus can only be present once";
SCLogWarning("rule %u: %s", s->id, *sigerror);
return false;
}
namevaluesep = true;
} else if (cd->content[i] != ':') {
*sigerror = "Invalid http2.header string : "
"':' is an escaping character for itself, "
"or space for the separation between name and value";
SCLogWarning("rule %u: %s", s->id, *sigerror);
return false;
}
namevaluesep = true;
} else if (cd->content[i] != ':') {
*sigerror = "Invalid http2.header string : "
"':' is an escaping character for itself, "
"or space for the separation between name and value";
SCLogWarning("rule %u: %s", s->id, *sigerror);
return false;
escaped = false;
} else if (cd->content[i] == ':') {
escaped = true;
}
escaped = false;
} else if (cd->content[i] == ':') {
escaped = true;
}
}
if (escaped) {
*sigerror = "Invalid http2.header string : "
"':' is an escaping character for itself, "
"or space for the separation between name and value";
SCLogWarning("rule %u: %s", s->id, *sigerror);
return false;
if (escaped) {
*sigerror = "Invalid http2.header string : "
"':' is an escaping character for itself, "
"or space for the separation between name and value";
SCLogWarning("rule %u: %s", s->id, *sigerror);
return false;
}
}
}
}
return true;
}
static bool DetectHttp2RequestHeaderValidateCallback(const Signature *s, const char **sigerror)
{
return DetectHttp2HeaderValidateCallback(s, sigerror, g_http_request_header_buffer_id);
}
static bool DetectHttp2ResponseHeaderValidateCallback(const Signature *s, const char **sigerror)
{
return DetectHttp2HeaderValidateCallback(s, sigerror, g_http_response_header_buffer_id);
}
#ifdef UNITTESTS
#include "tests/detect-http2.c"
#endif

Loading…
Cancel
Save