aboutsummaryrefslogtreecommitdiffstats
path: root/epan/dissectors/packet-http2.c
diff options
context:
space:
mode:
authorAlexander Gryanko <xpahos@gmail.com>2017-11-18 05:09:50 +0300
committerPeter Wu <peter@lekensteyn.nl>2018-01-14 14:16:44 +0000
commitd06b60db7151a6d79697866da15afa23cd99c703 (patch)
tree7523e099c9d6d0f20f9ca6f2b6fb0b5767b6776c /epan/dissectors/packet-http2.c
parent9922dc263ea7f5584dc20003e998ad69812a8988 (diff)
http2: headers filter with UAT support
Make HTTP2 headers filterable. Change-Id: I1a1a42ccdb41461f048e9ae462421ecad79da61b Reviewed-on: https://code.wireshark.org/review/24475 Petri-Dish: Peter Wu <peter@lekensteyn.nl> Tested-by: Petri Dish Buildbot Reviewed-by: Peter Wu <peter@lekensteyn.nl>
Diffstat (limited to 'epan/dissectors/packet-http2.c')
-rw-r--r--epan/dissectors/packet-http2.c602
1 files changed, 601 insertions, 1 deletions
diff --git a/epan/dissectors/packet-http2.c b/epan/dissectors/packet-http2.c
index edd8b226dd..d6c8e86531 100644
--- a/epan/dissectors/packet-http2.c
+++ b/epan/dissectors/packet-http2.c
@@ -46,7 +46,10 @@
#include <epan/dissectors/packet-http2.h>
#ifdef HAVE_NGHTTP2
+#include <epan/uat.h>
+
#include <nghttp2/nghttp2.h>
+
#endif
#include "packet-tcp.h"
@@ -55,6 +58,7 @@
#include <epan/reassemble.h>
#include "wsutil/pint.h"
+#include "wsutil/strtoi.h"
#ifdef HAVE_NGHTTP2
#define http2_header_repr_type_VALUE_STRING_LIST(XXX) \
@@ -321,6 +325,59 @@ static int hf_http2_continuation_padding = -1;
static int hf_http2_altsvc_origin_len = -1;
static int hf_http2_altsvc_origin = -1;
static int hf_http2_altsvc_field_value = -1;
+#if HAVE_NGHTTP2
+/* HTTP2 header static fields */
+static int hf_http2_headers_status = -1;
+static int hf_http2_headers_path = -1;
+static int hf_http2_headers_method = -1;
+static int hf_http2_headers_scheme = -1;
+static int hf_http2_headers_accept = -1;
+static int hf_http2_headers_accept_charset = -1;
+static int hf_http2_headers_accept_encoding = -1;
+static int hf_http2_headers_accept_language = -1;
+static int hf_http2_headers_accept_ranges = -1;
+static int hf_http2_headers_access_control_allow_origin = -1;
+static int hf_http2_headers_age = -1;
+static int hf_http2_headers_allow = -1;
+static int hf_http2_headers_authorization = -1;
+static int hf_http2_headers_authority = -1;
+static int hf_http2_headers_cache_control = -1;
+static int hf_http2_headers_content_disposition = -1;
+static int hf_http2_headers_content_encoding = -1;
+static int hf_http2_headers_content_language = -1;
+static int hf_http2_headers_content_length = -1;
+static int hf_http2_headers_content_location = -1;
+static int hf_http2_headers_content_range = -1;
+static int hf_http2_headers_content_type = -1;
+static int hf_http2_headers_cookie = -1;
+static int hf_http2_headers_date = -1;
+static int hf_http2_headers_etag = -1;
+static int hf_http2_headers_expect = -1;
+static int hf_http2_headers_expires = -1;
+static int hf_http2_headers_from = -1;
+static int hf_http2_headers_if_match = -1;
+static int hf_http2_headers_if_modified_since = -1;
+static int hf_http2_headers_if_none_match = -1;
+static int hf_http2_headers_if_range = -1;
+static int hf_http2_headers_if_unmodified_since = -1;
+static int hf_http2_headers_last_modified = -1;
+static int hf_http2_headers_link = -1;
+static int hf_http2_headers_location = -1;
+static int hf_http2_headers_max_forwards = -1;
+static int hf_http2_headers_proxy_authenticate = -1;
+static int hf_http2_headers_proxy_authorization = -1;
+static int hf_http2_headers_range = -1;
+static int hf_http2_headers_referer = -1;
+static int hf_http2_headers_refresh = -1;
+static int hf_http2_headers_retry_after = -1;
+static int hf_http2_headers_server = -1;
+static int hf_http2_headers_set_cookie = -1;
+static int hf_http2_headers_strict_transport_security = -1;
+static int hf_http2_headers_user_agent = -1;
+static int hf_http2_headers_vary = -1;
+static int hf_http2_headers_via = -1;
+static int hf_http2_headers_www_authenticate = -1;
+#endif
/* Blocked */
/*
@@ -384,6 +441,472 @@ static wmem_map_t *http2_hdrcache_map = NULL;
static char *http2_header_pstr = NULL;
#endif
+#ifdef HAVE_NGHTTP2
+/* Stuff for generation/handling of fields for HTTP2 headers */
+
+enum header_field_type {
+ val_string,
+ val_uint64
+};
+
+typedef struct _header_field_t {
+ gchar* header_name;
+ enum header_field_type header_type;
+ gchar* header_desc;
+} header_field_t;
+
+static header_field_t* header_fields = NULL;
+static guint num_header_fields = 0;
+static guint num_header_fields_cleanup = 0;
+
+static GHashTable* header_fields_hash = NULL;
+
+static gboolean
+header_fields_update_cb(void *r, char **err)
+{
+ header_field_t *rec = (header_field_t *)r;
+ char c;
+
+ if (rec->header_name == NULL) {
+ *err = g_strdup("Header name can't be empty");
+ return FALSE;
+ }
+
+ g_strstrip(rec->header_name);
+ if (rec->header_name[0] == 0) {
+ *err = g_strdup("Header name can't be empty");
+ return FALSE;
+ }
+
+ /* Check for invalid characters (to avoid asserting out when
+ * registering the field).
+ */
+ c = proto_check_field_name(rec->header_name);
+ if (c) {
+ *err = g_strdup_printf("Header name can't contain '%c'", c);
+ return FALSE;
+ }
+
+ /* If the hash table is empty(e.g. on startup), do not try to check a value */
+ if (header_fields_hash != NULL) {
+ const gint *entry = (const gint *) g_hash_table_lookup(header_fields_hash, rec->header_name);
+ if (entry != NULL) {
+ *err = g_strdup_printf("This header field is already defined in UAT or it is a static header field");
+ return FALSE;
+ }
+ }
+
+ *err = NULL;
+ return TRUE;
+}
+
+static void *
+header_fields_copy_cb(void* n, const void* o, size_t siz _U_)
+{
+ header_field_t* new_rec = (header_field_t*)n;
+ const header_field_t* old_rec = (const header_field_t*)o;
+
+ new_rec->header_name = g_strdup(old_rec->header_name);
+ new_rec->header_type = old_rec->header_type;
+ new_rec->header_desc = g_strdup(old_rec->header_desc);
+
+ return new_rec;
+}
+
+static void
+header_fields_free_cb(void*r)
+{
+ header_field_t* rec = (header_field_t*)r;
+
+ g_hash_table_remove(header_fields_hash, rec->header_name);
+
+ g_free(rec->header_name);
+ g_free(rec->header_desc);
+
+}
+
+static void
+register_static_headers(void) {
+ header_fields_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, NULL);
+
+ /* Here hf[x].hfinfo.name is a header method which is used as key
+ * for matching ids while processing HTTP2 packets */
+ static hf_register_info hf[] = {
+ {
+ &hf_http2_headers_authority,
+ {":authority", "http2.headers.authority",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Authority portion of the target URI", HFILL}
+ },
+ {
+ &hf_http2_headers_status,
+ {":status", "http2.headers.status",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ NULL, HFILL}
+ },
+ {
+ &hf_http2_headers_path,
+ {":path", "http2.headers.path",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ NULL, HFILL}
+ },
+ {
+ &hf_http2_headers_method,
+ {":method", "http2.headers.method",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ NULL, HFILL}
+ },
+ {
+ &hf_http2_headers_scheme,
+ {":scheme", "http2.headers.scheme",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ NULL, HFILL}
+ },
+ {
+ &hf_http2_headers_accept,
+ {"accept", "http2.headers.accept",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Media types that are acceptable to the user agent", HFILL}
+ },
+ {
+ &hf_http2_headers_accept_charset,
+ {"accept_charset", "http2.headers.accept_charset",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Acceptable charsets in textual responses for the user agent", HFILL}
+ },
+ {
+ &hf_http2_headers_accept_encoding,
+ {"accept_encoding", "http2.headers.accept_encoding",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Acceptable content codings (like compression) in responses for the user agent", HFILL}
+ },
+ {
+ &hf_http2_headers_accept_language,
+ {"accept_language", "http2.headers.accept_language",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Preferred natural languages for the user agent", HFILL}
+ },
+ {
+ &hf_http2_headers_accept_ranges,
+ {"accept_ranges", "http2.headers.accept_ranges",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Bytes range which server may use for partial data transfer", HFILL}
+ },
+ {
+ &hf_http2_headers_access_control_allow_origin,
+ {"access_control_allow_origin", "http2.headers.access_control_allow_origin",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Origin control for cross-origin resource sharing", HFILL}
+ },
+ {
+ &hf_http2_headers_age,
+ {"age", "http2.headers.age",
+ FT_UINT64, BASE_DEC, NULL, 0x0,
+ "Time in seconds which was spent for transferring data through proxy", HFILL}
+ },
+ {
+ &hf_http2_headers_allow,
+ {"allow", "http2.headers.allow",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "List of allowed methods for request", HFILL}
+ },
+ {
+ &hf_http2_headers_authorization,
+ {"authorization", "http2.headers.authorization",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Credentials for a server-side authorization", HFILL}
+ },
+ {
+ &hf_http2_headers_cache_control,
+ {"cache_control", "http2.headers.cache_control",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Request or response directives for a cache control", HFILL}
+ },
+ {
+ &hf_http2_headers_content_disposition,
+ {"content_disposition", "http2.headers.content_disposition",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Indicates that response will be displayed as page or downloaded with dialog box", HFILL}
+ },
+ {
+ &hf_http2_headers_content_encoding,
+ {"content_encoding", "http2.headers.content_encoding",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ NULL, HFILL}
+ },
+ {
+ &hf_http2_headers_content_language,
+ {"content_language", "http2.headers.content_language",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ NULL, HFILL}
+ },
+ {
+ &hf_http2_headers_content_length,
+ {"content_length", "http2.headers.content_length",
+ FT_UINT64, BASE_DEC, NULL, 0x0,
+ "Size of body in bytes", HFILL}
+ },
+ {
+ &hf_http2_headers_content_location,
+ {"content_location", "http2.headers.content_location",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Alternative URL for a response data", HFILL}
+ },
+ {
+ &hf_http2_headers_content_range,
+ {"content_range", "http2.headers.content_range",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Range of bytes which was sent by server for partial data transfer", HFILL}
+ },
+ {
+ &hf_http2_headers_content_type,
+ {"content_type", "http2.headers.content_type",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "MIME type of response", HFILL}
+ },
+ {
+ &hf_http2_headers_cookie,
+ {"cookie", "http2.headers.cookie",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Stored cookies", HFILL}
+ },
+ {
+ &hf_http2_headers_date,
+ {"date", "http2.headers.date",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Date and time at which the data was originated", HFILL}
+ },
+ {
+ &hf_http2_headers_etag,
+ {"etag", "http2.headers.etag",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Directive for version indication of resource", HFILL}
+ },
+ {
+ &hf_http2_headers_expect,
+ {"expect", "http2.headers.expect",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Expectations that need to be fulfilled for correct request", HFILL}
+ },
+ {
+ &hf_http2_headers_expires,
+ {"expires", "http2.headers.expires",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Data after which resource will be stale", HFILL}
+ },
+ {
+ &hf_http2_headers_from,
+ {"from", "http2.headers.from",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Email of a person who responsible for a requesting data", HFILL}
+ },
+ {
+ &hf_http2_headers_if_match,
+ {"if_match", "http2.headers.if_match",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Mechanism for requesting data matched by a list of ETags", HFILL}
+ },
+ {
+ &hf_http2_headers_if_modified_since,
+ {"if_modified_since", "http2.headers.if_modified_since",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Resource will be sent with status code 200 if it was modified otherwise with status code 304", HFILL}
+ },
+ {
+ &hf_http2_headers_if_none_match,
+ {"if_none_match", "http2.headers.if_none_match",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Mechanism for requesting data not matched by a list of ETags", HFILL}
+ },
+ {
+ &hf_http2_headers_if_range,
+ {"if_range", "http2.headers.if_range",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Mechanism for a range request which is used to check if a resource was modified", HFILL}
+ },
+ {
+ &hf_http2_headers_if_unmodified_since,
+ {"if_unmodified_since", "http2.headers.if_unmodified_since",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Resource will be processed if it was not modified otherwise 412 error will be returned", HFILL}
+ },
+ {
+ &hf_http2_headers_last_modified,
+ {"last_modified", "http2.headers.last_modified",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Date and time at which the origin server believes the resource was last modified", HFILL}
+ },
+ {
+ &hf_http2_headers_link,
+ {"link", "http2.headers.link",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Mechanism for indicating that resource will be preloaded", HFILL}
+ },
+ {
+ &hf_http2_headers_location,
+ {"location", "http2.headers.location",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Mechanism for indicating that client will be redirected", HFILL}
+ },
+ {
+ &hf_http2_headers_max_forwards,
+ {"max_forwards", "http2.headers.max_forwards",
+ FT_UINT64, BASE_DEC, NULL, 0x0,
+ "Mechanism for limiting the number of proxies", HFILL}
+ },
+ {
+ &hf_http2_headers_proxy_authenticate,
+ {"proxy_authenticate", "http2.headers.proxy_authenticate",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Authentication method that should be used to gain access to a resource behind a proxy server", HFILL}
+ },
+ {
+ &hf_http2_headers_proxy_authorization,
+ {"proxy_authorization", "http2.headers.proxy_authorization",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Credentials for a proxy-side authorization", HFILL}
+ },
+ {
+ &hf_http2_headers_range,
+ {"range", "http2.headers.range",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Range of resource bytes that server should return", HFILL}
+ },
+ {
+ &hf_http2_headers_referer,
+ {"referer", "http2.headers.referer",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Address of the previous web page", HFILL}
+ },
+ {
+ &hf_http2_headers_refresh,
+ {"refresh", "http2.headers.refresh",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Time in seconds after which client will be redirected by given url", HFILL}
+ },
+ {
+ &hf_http2_headers_retry_after,
+ {"retry_after", "http2.headers.retry_after",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Mechanism to indicate when resource expected to be available", HFILL}
+ },
+ {
+ &hf_http2_headers_server,
+ {"server", "http2.headers.server",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Information about server software", HFILL}
+ },
+ {
+ &hf_http2_headers_set_cookie,
+ {"set_cookie", "http2.headers.set_cookie",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Send a cookie to the client", HFILL}
+ },
+ {
+ &hf_http2_headers_strict_transport_security,
+ {"strict_transport_security", "http2.headers.strict_transport_security",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "HSTS indicates that resource should be accessed only using HTTPS", HFILL}
+ },
+ {
+ &hf_http2_headers_user_agent,
+ {"user_agent", "http2.headers.user_agent",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Information about client software", HFILL}
+ },
+ {
+ &hf_http2_headers_vary,
+ {"vary", "http2.headers.vary",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Mechanism for selecting which header will be used for content negotiation algorithm", HFILL}
+ },
+ {
+ &hf_http2_headers_via,
+ {"via", "http2.headers.via",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Additional information for loop detection and protocol capabilities in proxy requests", HFILL}
+ },
+ {
+ &hf_http2_headers_www_authenticate,
+ {"www_authenticate", "http2.headers.www_authenticate",
+ FT_STRING, STR_UNICODE, NULL, 0x0,
+ "Authentication method that should be used to gain access to a resource", HFILL}
+ }
+ };
+ gchar* header_name;
+ for (guint i = 0; i < G_N_ELEMENTS(hf); ++i) {
+ header_name = g_strdup(hf[i].hfinfo.name);
+
+ g_hash_table_insert(header_fields_hash, header_name, &hf[i].hfinfo.id);
+ }
+ proto_register_field_array(proto_http2, hf, G_N_ELEMENTS(hf));
+}
+
+UAT_CSTRING_CB_DEF(header_fields, header_name, header_field_t)
+UAT_VS_DEF(header_fields, header_type, header_field_t, enum header_field_type, val_string, "string")
+UAT_CSTRING_CB_DEF(header_fields, header_desc, header_field_t)
+
+static hf_register_info* hf_uat = NULL;
+#endif
+
+static void
+http2_init_protocol(void)
+{
+#if HAVE_NGHTTP2
+ gint* hf_id;
+ guint i;
+ gchar* header_name;
+ gchar* header_name_key;
+
+ /* Add to hash table headers from UAT */
+ if (num_header_fields) {
+ hf_uat = g_new0(hf_register_info, num_header_fields);
+ num_header_fields_cleanup = num_header_fields;
+
+ for (i = 0; i < num_header_fields; i++) {
+ hf_id = g_new(gint,1);
+ *hf_id = -1;
+ header_name = g_strdup(header_fields[i].header_name);
+ header_name_key = g_ascii_strdown(header_name, -1);
+
+ hf_uat[i].p_id = hf_id;
+ hf_uat[i].hfinfo.name = header_name;
+ hf_uat[i].hfinfo.abbrev = g_strdup_printf("http2.headers.%s", header_name);
+ switch(header_fields[i].header_type) {
+ case val_uint64:
+ hf_uat[i].hfinfo.type = FT_UINT64;
+ hf_uat[i].hfinfo.display = BASE_DEC;
+ break;
+ default: // string
+ hf_uat[i].hfinfo.type = FT_STRING;
+ hf_uat[i].hfinfo.display = BASE_NONE;
+ break;
+ }
+ hf_uat[i].hfinfo.strings = NULL;
+ hf_uat[i].hfinfo.bitmask = 0;
+ hf_uat[i].hfinfo.blurb = g_strdup(header_fields[i].header_desc);
+ HFILL_INIT(hf_uat[i]);
+
+ g_hash_table_insert(header_fields_hash, header_name_key, hf_id);
+ }
+
+ proto_register_field_array(proto_http2, hf_uat, num_header_fields);
+ }
+#endif
+}
+
+static void
+http2_cleanup_protocol(void) {
+#if HAVE_NGHTTP2
+ for (guint i = 0; i < num_header_fields_cleanup; ++i) {
+ proto_deregister_field(proto_http2, *(hf_uat[i].p_id));
+ }
+ proto_add_deregistered_data(hf_uat);
+ proto_free_deregistered_fields();
+#endif
+}
+
static dissector_handle_t http2_handle;
static reassembly_table http2_body_reassembly_table;
@@ -1007,6 +1530,37 @@ try_append_method_path_info(packet_info *pinfo, proto_tree *tree,
}
static void
+try_add_named_header_field(proto_tree *tree, tvbuff_t *tvb, int offset, guint32 length, const char *header_name, const char *header_value)
+{
+ int hf_id = -1;
+ header_field_info *hfi;
+
+ const gint *entry = (const gint*) g_hash_table_lookup(header_fields_hash, header_name);
+ if (entry == NULL) {
+ return;
+ }
+
+ hf_id = *entry;
+
+ hfi = proto_registrar_get_nth(hf_id);
+ DISSECTOR_ASSERT(hfi != NULL);
+
+ if (IS_FT_UINT32(hfi->type)) {
+ guint32 value;
+ if (ws_strtou32(header_value, NULL, &value)) {
+ proto_tree_add_uint(tree, hf_id, tvb, offset, length, value);
+ }
+ } else if (IS_FT_UINT(hfi->type)) {
+ guint64 value;
+ if (ws_strtou64(header_value, NULL, &value)) {
+ proto_tree_add_uint64(tree, hf_id, tvb, offset, length, value);
+ }
+ } else {
+ proto_tree_add_item(tree, hf_id, tvb, offset, length, ENC_BIG_ENDIAN);
+ }
+}
+
+static void
inflate_http2_header_block(tvbuff_t *tvb, packet_info *pinfo, guint offset,
proto_tree *tree, size_t headlen,
http2_session_t *h2session, guint8 flags)
@@ -1243,6 +1797,8 @@ inflate_http2_header_block(tvbuff_t *tvb, packet_info *pinfo, guint offset,
/* Add header value. */
proto_tree_add_item_ret_string(header_tree, hf_http2_header_value, header_tvb, hoffset, header_value_length, ENC_ASCII|ENC_NA, wmem_packet_scope(), &header_value);
+ // check if field is http2 header https://tools.ietf.org/html/rfc7541#appendix-A
+ try_add_named_header_field(header_tree, header_tvb, hoffset, header_value_length, header_name, header_value);
hoffset += header_value_length;
/* Only track HEADER and CONTINUATION frames part there of. Don't look at PUSH_PROMISE and trailing CONTINUATION.
@@ -1348,7 +1904,6 @@ dissect_http2_header_flags(tvbuff_t *tvb, packet_info *pinfo _U_, proto_tree *ht
break;
}
-
return flags;
}
@@ -2704,6 +3259,51 @@ proto_register_http2(void)
prefs_register_obsolete_preference(http2_module, "heuristic_http2");
+#ifdef HAVE_NGHTTP2
+ uat_t* headers_uat;
+
+ static const value_string http2_custom_type_vals[] = {
+ { val_string, "string" },
+ { val_uint64, "unsigned 64-bit integer" },
+ { 0x00, NULL }
+ };
+
+ static uat_field_t custom_header_uat_fields[] = {
+ UAT_FLD_CSTRING(header_fields, header_name, "Header name", "HTTP2 header name"),
+ UAT_FLD_VS(header_fields, header_type, "Header type", http2_custom_type_vals, "Field type"),
+ UAT_FLD_CSTRING(header_fields, header_desc, "Field desc", "Description of the value contained in the header"),
+ UAT_END_FIELDS
+ };
+
+ headers_uat = uat_new("Custom HTTP2 Header Fields",
+ sizeof(header_field_t),
+ "custom_http2_header_fields",
+ TRUE,
+ &header_fields,
+ &num_header_fields,
+ /* specifies named fields, so affects dissection
+ and the set of named fields */
+ UAT_AFFECTS_DISSECTION|UAT_AFFECTS_FIELDS,
+ NULL,
+ header_fields_copy_cb,
+ header_fields_update_cb,
+ header_fields_free_cb,
+ NULL,
+ NULL,
+ custom_header_uat_fields
+ );
+
+ prefs_register_uat_preference(http2_module, "custom_http2_header_fields", "Custom HTTP2 header fields",
+ "A table to define custom HTTP2 header for which fields can be setup and used for filtering/data extraction etc.",
+ headers_uat);
+
+ /* Fill hash table with static headers */
+ register_static_headers();
+#endif
+
+ register_init_routine(&http2_init_protocol);
+ register_cleanup_routine(&http2_cleanup_protocol);
+
http2_handle = register_dissector("http2", dissect_http2, proto_http2);
reassembly_table_register(&http2_body_reassembly_table,