2013-08-30 11:14:09 +00:00
/* packet-http2.c
* Routines for HTTP2 dissection
* Copyright 2013 , Alexis La Goutte < alexis . lagoutte @ gmail . com >
* Copyright 2013 , Stephen Ludin < sludin @ ludin . org >
2014-04-25 14:29:10 +00:00
* Copyright 2014 , Daniel Stenberg < daniel @ haxx . se >
2014-06-23 14:21:15 +00:00
* Copyright 2014 , Tatsuhiro Tsujikawa < tatsuhiro . t @ gmail . com >
2013-08-30 11:14:09 +00:00
*
* Wireshark - Network traffic analyzer
* By Gerald Combs < gerald @ wireshark . org >
* Copyright 1998 Gerald Combs
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*/
/*
* The information used comes from :
2015-05-15 17:07:38 +00:00
* RFC7540 : Hypertext Transfer Protocol version 2 ( HTTP / 2 )
* RFC7541 : HTTP Header Compression for HTTP / 2
2014-10-30 08:33:36 +00:00
* HTTP Alternative Services draft - ietf - httpbis - alt - svc - 04
2013-08-30 11:14:09 +00:00
*
* TODO
* Enhance display of Data
* Reassembling of continuation frame ( and other frame )
* Add same tap and ping / pong time response
*/
# include "config.h"
# include <epan/packet.h>
2016-02-05 14:41:57 +00:00
# include <epan/expert.h>
2013-08-30 11:14:09 +00:00
# include <epan/prefs.h>
2016-01-25 01:10:20 +00:00
# include <epan/proto_data.h>
2014-05-06 15:54:47 +00:00
2014-07-02 13:10:02 +00:00
# include <epan/nghttp2/nghttp2.h>
2013-08-30 11:14:09 +00:00
# include "packet-tcp.h"
2015-01-08 16:35:58 +00:00
# include <epan/tap.h>
# include <epan/stats_tree.h>
2013-08-30 11:14:09 +00:00
2015-01-20 21:20:54 +00:00
# include "wsutil/pint.h"
2014-08-04 12:06:14 +00:00
# define http2_header_repr_type_VALUE_STRING_LIST(XXX) \
XXX ( HTTP2_HD_NONE , 0x00 , " " ) \
XXX ( HTTP2_HD_INDEXED , 0x01 , " Indexed Header Field " ) \
XXX ( HTTP2_HD_LITERAL_INDEXING_INDEXED_NAME , 0x02 , " Literal Header Field with Incremental Indexing - Indexed Name " ) \
XXX ( HTTP2_HD_LITERAL_INDEXING_NEW_NAME , 0x03 , " Literal Header Field with Incremental Indexing - New Name " ) \
XXX ( HTTP2_HD_LITERAL_INDEXED_NAME , 0x04 , " Literal Header Field without Indexing - Indexed Name " ) \
XXX ( HTTP2_HD_LITERAL_NEW_NAME , 0x05 , " Literal Header Field without Indexing - New Name " ) \
XXX ( HTTP2_HD_LITERAL_NEVER_INDEXING_INDEXED_NAME , 0x06 , " Literal Header Field never Indexed - Indexed Name " ) \
XXX ( HTTP2_HD_LITERAL_NEVER_INDEXING_NEW_NAME , 0x07 , " Literal Header Field never Indexed - New Name " ) \
XXX ( HTTP2_HD_HEADER_TABLE_SIZE_UPDATE , 0x08 , " Maximum Header Table Size Change " )
VALUE_STRING_ENUM ( http2_header_repr_type ) ;
VALUE_STRING_ARRAY ( http2_header_repr_type ) ;
2014-06-23 10:25:33 +00:00
/* Decompressed header field */
typedef struct {
2014-08-04 12:06:14 +00:00
/* one of http2_header_repr_type */
gint type ;
/* encoded (compressed) length */
gint length ;
union {
struct {
/* header data */
char * data ;
/* length of data */
guint datalen ;
/* name index or name/value index if type is one of
HTTP2_HD_INDEXED and HTTP2_HD_ * _INDEXED_NAMEs */
2015-09-03 02:53:05 +00:00
guint idx ;
2014-08-13 00:39:07 +00:00
} data ;
2014-08-04 12:06:14 +00:00
/* header table size if type == HTTP2_HD_HEADER_TABLE_SIZE_UPDATE */
guint header_table_size ;
2014-08-13 00:39:07 +00:00
} table ;
2014-06-23 10:25:33 +00:00
} http2_header_t ;
2014-08-04 12:06:14 +00:00
/* Context to decode header representation */
typedef struct {
/* one of http2_header_repr_type */
gint type ;
/* final or temporal result of decoding integer */
guint integer ;
/* next bit shift to made when decoding integer */
guint next_shift ;
/* TRUE if integer decoding was completed */
gboolean complete ;
} http2_header_repr_info_t ;
2014-06-23 10:25:33 +00:00
/* Cached decompressed header data in one packet_info */
typedef struct {
/* list of pointer to wmem_array_t, which is array of
http2_header_t */
wmem_list_t * header_list ;
/* This points to the list frame containing current decompressed
2016-02-05 14:41:57 +00:00
header for dissecting later . */
2014-06-23 10:25:33 +00:00
wmem_list_frame_t * current ;
2016-02-05 14:41:57 +00:00
/* Bytes decompressed if we exceeded MAX_HTTP2_HEADER_SIZE */
guint header_size_reached ;
/* Bytes decompressed if we had not exceeded MAX_HTTP2_HEADER_SIZE */
guint header_size_attempted ;
/* TRUE if we found >= MAX_HTTP2_HEADER_LINES */
gboolean header_lines_exceeded ;
2014-06-23 10:25:33 +00:00
} http2_header_data_t ;
/* In-flight SETTINGS data. */
typedef struct {
2014-08-02 07:22:28 +00:00
/* header table size last seen in SETTINGS */
guint32 header_table_size ;
/* minimum header table size in SETTINGS */
guint32 min_header_table_size ;
2014-06-23 10:25:33 +00:00
/* nonzero if header_table_size has effective value. */
int has_header_table_size ;
} http2_settings_t ;
2014-05-06 15:54:47 +00:00
/* struct to hold data per HTTP/2 session */
typedef struct {
2014-06-23 10:25:33 +00:00
/* We need to distinguish the direction of the flow to keep track
of in - flight SETTINGS and HPACK inflater objects . To achieve
this , we use fwd member of tcp_analysis . In the first packet ,
we record fwd of tcp_analysis . Later , if processing
packet_info has fwd of tcp_analysis equal to the recorded fwd ,
we use index 0 of settings_queue and hd_inflater . We keep
track of SETTINGS frame sent in this direction in
settings_queue [ 0 ] and inflate header block using
hd_inflater [ 0 ] . Otherwise , we use settings_queue [ 1 ] and
hd_inflater [ 1 ] . */
wmem_queue_t * settings_queue [ 2 ] ;
2014-05-06 15:54:47 +00:00
nghttp2_hd_inflater * hd_inflater [ 2 ] ;
2014-08-04 12:06:14 +00:00
http2_header_repr_info_t header_repr_info [ 2 ] ;
2014-06-23 10:25:33 +00:00
tcp_flow_t * fwd_flow ;
2014-05-06 15:54:47 +00:00
} http2_session_t ;
2013-12-15 23:44:12 +00:00
void proto_register_http2 ( void ) ;
void proto_reg_handoff_http2 ( void ) ;
2015-01-08 16:35:58 +00:00
struct HTTP2Tap {
guint8 type ;
} ;
static int http2_tap = - 1 ;
static const guint8 * st_str_http2 = " HTTP2 " ;
static const guint8 * st_str_http2_type = " Type " ;
static int st_node_http2 = - 1 ;
static int st_node_http2_type = - 1 ;
2014-08-02 10:00:59 +00:00
2013-08-30 11:14:09 +00:00
/* Packet Header */
static int proto_http2 = - 1 ;
2016-02-03 06:06:07 +00:00
static int hf_http2_stream = - 1 ;
2013-08-30 11:14:09 +00:00
static int hf_http2_length = - 1 ;
static int hf_http2_type = - 1 ;
static int hf_http2_r = - 1 ;
static int hf_http2_streamid = - 1 ;
static int hf_http2_magic = - 1 ;
static int hf_http2_unknown = - 1 ;
/* Flags */
static int hf_http2_flags = - 1 ;
static int hf_http2_flags_end_stream = - 1 ;
static int hf_http2_flags_end_headers = - 1 ;
2014-06-23 14:21:15 +00:00
static int hf_http2_flags_padded = - 1 ;
2013-08-30 11:14:09 +00:00
static int hf_http2_flags_priority = - 1 ;
2013-12-15 19:07:40 +00:00
static int hf_http2_flags_settings_ack = - 1 ;
static int hf_http2_flags_ping_ack = - 1 ;
2014-05-12 07:00:52 +00:00
static int hf_http2_flags_unused = - 1 ;
2014-06-23 14:21:15 +00:00
static int hf_http2_flags_unused_settings = - 1 ;
static int hf_http2_flags_unused_ping = - 1 ;
static int hf_http2_flags_unused_continuation = - 1 ;
static int hf_http2_flags_unused_push_promise = - 1 ;
2014-05-12 07:00:52 +00:00
static int hf_http2_flags_unused_data = - 1 ;
2014-06-23 14:21:15 +00:00
static int hf_http2_flags_unused_headers = - 1 ;
2014-04-25 14:29:10 +00:00
/* generic */
2014-06-23 14:21:15 +00:00
static int hf_http2_padding = - 1 ;
2014-05-12 07:00:52 +00:00
static int hf_http2_pad_length = - 1 ;
2014-04-25 14:29:10 +00:00
static int hf_http2_weight = - 1 ;
2014-05-13 15:49:24 +00:00
static int hf_http2_weight_real = - 1 ;
2014-04-25 14:29:10 +00:00
static int hf_http2_stream_dependency = - 1 ;
static int hf_http2_excl_dependency = - 1 ;
/* Data */
static int hf_http2_data_data = - 1 ;
static int hf_http2_data_padding = - 1 ;
2013-08-30 11:14:09 +00:00
/* Headers */
2014-05-06 15:54:47 +00:00
static int hf_http2_headers = - 1 ;
2014-04-25 14:29:10 +00:00
static int hf_http2_headers_padding = - 1 ;
2014-05-06 15:54:47 +00:00
static int hf_http2_header = - 1 ;
static int hf_http2_header_length = - 1 ;
2016-02-05 14:41:57 +00:00
static int hf_http2_header_count = - 1 ;
2014-05-06 15:54:47 +00:00
static int hf_http2_header_name_length = - 1 ;
static int hf_http2_header_name = - 1 ;
static int hf_http2_header_value_length = - 1 ;
static int hf_http2_header_value = - 1 ;
2014-08-04 12:06:14 +00:00
static int hf_http2_header_repr = - 1 ;
static int hf_http2_header_index = - 1 ;
static int hf_http2_header_table_size_update = - 1 ;
static int hf_http2_header_table_size = - 1 ;
2013-08-30 11:14:09 +00:00
/* RST Stream */
static int hf_http2_rst_stream_error = - 1 ;
/* Settings */
static int hf_http2_settings = - 1 ;
static int hf_http2_settings_identifier = - 1 ;
2013-12-15 19:07:40 +00:00
static int hf_http2_settings_header_table_size = - 1 ;
static int hf_http2_settings_enable_push = - 1 ;
2013-08-30 11:14:09 +00:00
static int hf_http2_settings_max_concurrent_streams = - 1 ;
static int hf_http2_settings_initial_window_size = - 1 ;
2014-08-02 07:22:28 +00:00
static int hf_http2_settings_max_frame_size = - 1 ;
static int hf_http2_settings_max_header_list_size = - 1 ;
2013-08-30 11:14:09 +00:00
static int hf_http2_settings_unknown = - 1 ;
/* Push Promise */
static int hf_http2_push_promise_r = - 1 ;
static int hf_http2_push_promise_promised_stream_id = - 1 ;
static int hf_http2_push_promise_header = - 1 ;
2014-04-25 14:29:10 +00:00
static int hf_http2_push_promise_padding = - 1 ;
2013-08-30 11:14:09 +00:00
/* Ping */
static int hf_http2_ping = - 1 ;
static int hf_http2_pong = - 1 ;
2014-04-25 14:29:10 +00:00
/* Goaway */
2013-08-30 11:14:09 +00:00
static int hf_http2_goaway_r = - 1 ;
static int hf_http2_goaway_last_stream_id = - 1 ;
static int hf_http2_goaway_error = - 1 ;
static int hf_http2_goaway_addata = - 1 ;
/* Window Update */
static int hf_http2_window_update_r = - 1 ;
static int hf_http2_window_update_window_size_increment = - 1 ;
/* Continuation */
static int hf_http2_continuation_header = - 1 ;
2014-05-12 07:00:52 +00:00
static int hf_http2_continuation_padding = - 1 ;
2014-04-25 14:29:10 +00:00
/* Altsvc */
static int hf_http2_altsvc_maxage = - 1 ;
static int hf_http2_altsvc_port = - 1 ;
static int hf_http2_altsvc_proto_len = - 1 ;
static int hf_http2_altsvc_protocol = - 1 ;
static int hf_http2_altsvc_host_len = - 1 ;
static int hf_http2_altsvc_host = - 1 ;
static int hf_http2_altsvc_origin = - 1 ;
/* Blocked */
2016-02-05 14:41:57 +00:00
/*
* These values * should * be large enough to handle most use cases while
* keeping hostile traffic from consuming too many resources . If that ' s
* not the case we can convert them to preferences . Current ( Feb 2016 )
* client and server limits :
*
* Apache : 8 K ( LimitRequestFieldSize ) , 100 lines ( LimitRequestFields )
* Chrome : 256 K ?
* Firefox : Unknown
* IIS : 16 K ( MaxRequestBytes )
* Nginx : 8 K ( large_client_header_buffers )
* Safari : Unknown
* Tomcat : 8 K ( maxHttpHeaderSize )
*/
# define MAX_HTTP2_HEADER_SIZE (256 * 1024)
# define MAX_HTTP2_HEADER_LINES 200
static expert_field ei_http2_header_size = EI_INIT ;
static expert_field ei_http2_header_lines = EI_INIT ;
2013-08-30 11:14:09 +00:00
static gint ett_http2 = - 1 ;
static gint ett_http2_header = - 1 ;
2014-05-06 15:54:47 +00:00
static gint ett_http2_headers = - 1 ;
2013-08-30 11:14:09 +00:00
static gint ett_http2_flags = - 1 ;
static gint ett_http2_settings = - 1 ;
2016-02-05 14:41:57 +00:00
/* Due to HPACK compression, we may get lots of relatively large
header fields ( e . g . , 4 KiB ) . Allocating each of them requires lots
of memory . The maximum compression is achieved in HPACK by
referencing header field stored in dynamic table by one or two
bytes . We reduce memory usage by caching header field in this
wmem_map_t to reuse its memory region when we see the same header
field next time . */
static wmem_map_t * http2_hdrcache_map = NULL ;
/* Header name_length + name + value_length + value */
static char * http2_header_pstr = NULL ;
2013-08-30 11:14:09 +00:00
static dissector_handle_t data_handle ;
2013-12-15 19:07:40 +00:00
static dissector_handle_t http2_handle ;
2013-08-30 11:14:09 +00:00
2014-08-02 07:22:28 +00:00
# define FRAME_HEADER_LENGTH 9
2013-08-30 11:14:09 +00:00
# define MAGIC_FRAME_LENGTH 24
# define MASK_HTTP2_RESERVED 0x80000000
# define MASK_HTTP2_STREAMID 0X7FFFFFFF
# define MASK_HTTP2_PRIORITY 0X7FFFFFFF
/* Header Type Code */
# define HTTP2_DATA 0
# define HTTP2_HEADERS 1
# define HTTP2_PRIORITY 2
# define HTTP2_RST_STREAM 3
# define HTTP2_SETTINGS 4
# define HTTP2_PUSH_PROMISE 5
# define HTTP2_PING 6
# define HTTP2_GOAWAY 7
2014-04-25 14:29:10 +00:00
# define HTTP2_WINDOW_UPDATE 8
# define HTTP2_CONTINUATION 9
# define HTTP2_ALTSVC 0xA
# define HTTP2_BLOCKED 0xB
2013-08-30 11:14:09 +00:00
static const value_string http2_type_vals [ ] = {
{ HTTP2_DATA , " DATA " } ,
{ HTTP2_HEADERS , " HEADERS " } ,
{ HTTP2_PRIORITY , " PRIORITY " } ,
{ HTTP2_RST_STREAM , " RST_STREAM " } ,
{ HTTP2_SETTINGS , " SETTINGS " } ,
{ HTTP2_PUSH_PROMISE , " PUSH_PROMISE " } ,
{ HTTP2_PING , " PING " } ,
{ HTTP2_GOAWAY , " GOAWAY " } ,
{ HTTP2_WINDOW_UPDATE , " WINDOW_UPDATE " } ,
{ HTTP2_CONTINUATION , " CONTINUATION " } ,
2014-04-25 14:29:10 +00:00
{ HTTP2_ALTSVC , " ALTSVC " } ,
{ HTTP2_BLOCKED , " BLOCKED " } ,
2013-08-30 11:14:09 +00:00
{ 0 , NULL }
} ;
/* Flags */
2014-04-25 14:29:10 +00:00
# define HTTP2_FLAGS_ACK 0x01 /* for PING and SETTINGS */
# define HTTP2_FLAGS_END_STREAM 0x01
# define HTTP2_FLAGS_END_HEADERS 0x04
2014-06-23 14:21:15 +00:00
# define HTTP2_FLAGS_PADDED 0x08
2014-04-25 14:29:10 +00:00
# define HTTP2_FLAGS_PRIORITY 0x20
2014-08-02 07:22:28 +00:00
# define HTTP2_FLAGS_UNUSED 0xFF
# define HTTP2_FLAGS_UNUSED_SETTINGS (~HTTP2_FLAGS_ACK & 0xFF)
# define HTTP2_FLAGS_UNUSED_PING (~HTTP2_FLAGS_ACK & 0xFF)
# define HTTP2_FLAGS_UNUSED_CONTINUATION (~HTTP2_FLAGS_END_HEADERS & 0xFF)
# define HTTP2_FLAGS_UNUSED_PUSH_PROMISE \
( ~ ( HTTP2_FLAGS_END_HEADERS | HTTP2_FLAGS_PADDED ) & 0xFF )
# define HTTP2_FLAGS_UNUSED_DATA \
( ~ ( HTTP2_FLAGS_END_STREAM | HTTP2_FLAGS_PADDED ) & 0xFF )
# define HTTP2_FLAGS_UNUSED_HEADERS \
( ~ ( HTTP2_FLAGS_END_STREAM | HTTP2_FLAGS_END_HEADERS | \
HTTP2_FLAGS_PADDED | HTTP2_FLAGS_PRIORITY ) & 0xFF )
2013-08-30 11:14:09 +00:00
# define HTTP2_FLAGS_R 0xFF
# define HTTP2_FLAGS_R1 0xFE
# define HTTP2_FLAGS_R2 0xFA
# define HTTP2_FLAGS_R4 0xFB
/* Magic Header : PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n */
static guint8 kMagicHello [ ] = {
0x50 , 0x52 , 0x49 , 0x20 , 0x2a , 0x20 , 0x48 , 0x54 ,
0x54 , 0x50 , 0x2f , 0x32 , 0x2e , 0x30 , 0x0d , 0x0a ,
0x0d , 0x0a , 0x53 , 0x4d , 0x0d , 0x0a , 0x0d , 0x0a
} ;
/* Error Codes */
2014-10-30 08:33:36 +00:00
# define EC_NO_ERROR 0x0
# define EC_PROTOCOL_ERROR 0x1
# define EC_INTERNAL_ERROR 0x2
# define EC_FLOW_CONTROL_ERROR 0x3
# define EC_SETTINGS_TIMEOUT 0x4
# define EC_STREAM_CLOSED 0x5
# define EC_FRAME_SIZE_ERROR 0x6
# define EC_REFUSED_STREAM 0x7
# define EC_CANCEL 0x8
# define EC_COMPRESSION_ERROR 0x9
# define EC_CONNECT_ERROR 0xa
# define EC_ENHANCE_YOUR_CALM 0xb
# define EC_INADEQUATE_SECURITY 0xc
# define EC_HTTP_1_1_REQUIRED 0xd
2013-08-30 11:14:09 +00:00
static const value_string http2_error_codes_vals [ ] = {
2014-04-25 14:29:10 +00:00
{ EC_NO_ERROR , " NO_ERROR " } ,
2013-08-30 11:14:09 +00:00
{ EC_PROTOCOL_ERROR , " PROTOCOL_ERROR " } ,
{ EC_INTERNAL_ERROR , " INTERNAL_ERROR " } ,
{ EC_FLOW_CONTROL_ERROR , " FLOW_CONTROL_ERROR " } ,
2013-12-15 19:07:40 +00:00
{ EC_SETTINGS_TIMEOUT , " SETTINGS_TIMEOUT " } ,
2013-08-30 11:14:09 +00:00
{ EC_STREAM_CLOSED , " STREAM_CLOSED " } ,
2013-12-15 19:07:40 +00:00
{ EC_FRAME_SIZE_ERROR , " FRAME_SIZE_ERROR " } ,
2013-08-30 11:14:09 +00:00
{ EC_REFUSED_STREAM , " REFUSED_STREAM " } ,
{ EC_CANCEL , " CANCEL " } ,
{ EC_COMPRESSION_ERROR , " COMPRESSION_ERROR " } ,
2013-12-15 19:07:40 +00:00
{ EC_CONNECT_ERROR , " CONNECT_ERROR " } ,
{ EC_ENHANCE_YOUR_CALM , " ENHANCE_YOUR_CALM " } ,
2014-06-23 14:21:15 +00:00
{ EC_INADEQUATE_SECURITY , " INADEQUATE_SECURITY " } ,
2014-10-30 08:33:36 +00:00
{ EC_HTTP_1_1_REQUIRED , " HTTP_1_1_REQUIRED " } ,
2013-08-30 11:14:09 +00:00
{ 0 , NULL }
} ;
/* Settings */
2013-12-15 19:07:40 +00:00
# define HTTP2_SETTINGS_HEADER_TABLE_SIZE 1
# define HTTP2_SETTINGS_ENABLE_PUSH 2
2014-04-25 14:29:10 +00:00
# define HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS 3
# define HTTP2_SETTINGS_INITIAL_WINDOW_SIZE 4
2014-08-02 07:22:28 +00:00
# define HTTP2_SETTINGS_MAX_FRAME_SIZE 5
# define HTTP2_SETTINGS_MAX_HEADER_LIST_SIZE 6
2013-08-30 11:14:09 +00:00
static const value_string http2_settings_vals [ ] = {
2013-12-15 19:07:40 +00:00
{ HTTP2_SETTINGS_HEADER_TABLE_SIZE , " Header table size " } ,
{ HTTP2_SETTINGS_ENABLE_PUSH , " Enable PUSH " } ,
2013-08-30 11:14:09 +00:00
{ HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS , " Max concurrent streams " } ,
{ HTTP2_SETTINGS_INITIAL_WINDOW_SIZE , " Initial Windows size " } ,
2014-08-02 07:22:28 +00:00
{ HTTP2_SETTINGS_MAX_FRAME_SIZE , " Max frame size " } ,
{ HTTP2_SETTINGS_MAX_HEADER_LIST_SIZE , " Max header list size " } ,
2013-08-30 11:14:09 +00:00
{ 0 , NULL }
} ;
2014-06-23 10:25:33 +00:00
static gboolean
hd_inflate_del_cb ( wmem_allocator_t * allocator _U_ , wmem_cb_event_t event _U_ , void * user_data )
{
nghttp2_hd_inflate_del ( ( nghttp2_hd_inflater * ) user_data ) ;
2016-02-05 14:41:57 +00:00
http2_hdrcache_map = NULL ;
http2_header_pstr = NULL ;
2014-06-23 10:25:33 +00:00
return FALSE ;
}
2014-05-06 15:54:47 +00:00
static http2_session_t *
2014-06-23 10:25:33 +00:00
get_http2_session ( packet_info * pinfo )
2014-05-06 15:54:47 +00:00
{
conversation_t * conversation ;
http2_session_t * h2session ;
conversation = find_or_create_conversation ( pinfo ) ;
2014-06-23 10:25:33 +00:00
h2session = ( http2_session_t * ) conversation_get_proto_data ( conversation ,
proto_http2 ) ;
if ( ! h2session ) {
struct tcp_analysis * tcpd ;
2014-05-06 15:54:47 +00:00
2014-06-23 10:25:33 +00:00
tcpd = get_tcp_conversation_data ( NULL , pinfo ) ;
2014-05-06 15:54:47 +00:00
2014-06-23 10:25:33 +00:00
h2session = wmem_new0 ( wmem_file_scope ( ) , http2_session_t ) ;
2014-05-06 15:54:47 +00:00
2014-06-23 10:25:33 +00:00
nghttp2_hd_inflate_new ( & h2session - > hd_inflater [ 0 ] ) ;
nghttp2_hd_inflate_new ( & h2session - > hd_inflater [ 1 ] ) ;
2014-05-06 15:54:47 +00:00
2014-06-23 10:25:33 +00:00
wmem_register_callback ( wmem_file_scope ( ) , hd_inflate_del_cb ,
h2session - > hd_inflater [ 0 ] ) ;
wmem_register_callback ( wmem_file_scope ( ) , hd_inflate_del_cb ,
h2session - > hd_inflater [ 1 ] ) ;
2014-05-06 15:54:47 +00:00
2014-06-23 10:25:33 +00:00
h2session - > fwd_flow = tcpd - > fwd ;
h2session - > settings_queue [ 0 ] = wmem_queue_new ( wmem_file_scope ( ) ) ;
h2session - > settings_queue [ 1 ] = wmem_queue_new ( wmem_file_scope ( ) ) ;
2014-05-06 15:54:47 +00:00
2014-06-23 10:25:33 +00:00
conversation_add_proto_data ( conversation , proto_http2 , h2session ) ;
}
2014-05-06 15:54:47 +00:00
return h2session ;
}
2014-06-23 10:25:33 +00:00
static int
select_http2_flow_index ( packet_info * pinfo , http2_session_t * h2session )
2014-05-06 15:54:47 +00:00
{
struct tcp_analysis * tcpd ;
2014-06-23 10:25:33 +00:00
tcpd = get_tcp_conversation_data ( NULL , pinfo ) ;
2014-05-06 15:54:47 +00:00
2014-06-23 10:25:33 +00:00
if ( tcpd - > fwd = = h2session - > fwd_flow ) {
return 0 ;
} else {
return 1 ;
2014-05-06 15:54:47 +00:00
}
2014-06-23 10:25:33 +00:00
}
2014-05-06 15:54:47 +00:00
2014-06-23 10:25:33 +00:00
static void
push_settings ( packet_info * pinfo , http2_session_t * h2session ,
http2_settings_t * settings )
{
wmem_queue_t * queue ;
int flow_index ;
2014-05-06 15:54:47 +00:00
2014-06-23 10:25:33 +00:00
flow_index = select_http2_flow_index ( pinfo , h2session ) ;
2014-05-06 15:54:47 +00:00
2014-06-23 10:25:33 +00:00
queue = h2session - > settings_queue [ flow_index ] ;
wmem_queue_push ( queue , settings ) ;
2014-05-06 15:54:47 +00:00
}
2014-06-23 10:25:33 +00:00
static void
apply_and_pop_settings ( packet_info * pinfo , http2_session_t * h2session )
2014-05-06 15:54:47 +00:00
{
2014-06-23 10:25:33 +00:00
wmem_queue_t * queue ;
http2_settings_t * settings ;
nghttp2_hd_inflater * inflater ;
int flow_index ;
2014-05-06 15:54:47 +00:00
2014-06-23 10:25:33 +00:00
/* When header table size is applied, it affects the inflater of
opposite side . */
2014-05-06 15:54:47 +00:00
2014-06-23 10:25:33 +00:00
flow_index = select_http2_flow_index ( pinfo , h2session ) ;
inflater = h2session - > hd_inflater [ flow_index ] ;
queue = h2session - > settings_queue [ flow_index ^ 1 ] ;
if ( wmem_queue_count ( queue ) = = 0 ) {
return ;
}
settings = ( http2_settings_t * ) wmem_queue_pop ( queue ) ;
if ( settings - > has_header_table_size ) {
2014-08-02 07:22:28 +00:00
if ( settings - > min_header_table_size < settings - > header_table_size ) {
nghttp2_hd_inflate_change_table_size
( inflater , settings - > min_header_table_size ) ;
}
2014-06-23 10:25:33 +00:00
nghttp2_hd_inflate_change_table_size ( inflater ,
settings - > header_table_size ) ;
2014-05-06 15:54:47 +00:00
}
}
2014-08-04 12:06:14 +00:00
/* Decode integer from buf at position p, using prefix bits. This
function can be called several times if buf does not contain whole
integer . header_repr_info remembers the result of previous call .
Returns the number bytes processed . */
static guint read_integer ( http2_header_repr_info_t * header_repr_info ,
const guint8 * buf , guint len , guint p , guint prefix )
{
guint k = ( 1 < < prefix ) - 1 ;
guint n = header_repr_info - > integer ;
guint shift = header_repr_info - > next_shift ;
if ( n = = 0 ) {
DISSECTOR_ASSERT ( p < len ) ;
if ( ( buf [ p ] & k ) ! = k ) {
header_repr_info - > integer = buf [ p ] & k ;
header_repr_info - > complete = TRUE ;
return p + 1 ;
}
n = k ;
+ + p ;
}
for ( ; p < len ; + + p , shift + = 7 ) {
DISSECTOR_ASSERT ( p < len ) ;
n + = ( buf [ p ] & 0x7F ) < < shift ;
if ( ( buf [ p ] & 0x80 ) = = 0 ) {
header_repr_info - > complete = TRUE ;
+ + p ;
break ;
}
}
header_repr_info - > integer = n ;
header_repr_info - > next_shift = shift ;
return p ;
}
static void
reset_http2_header_repr_info ( http2_header_repr_info_t * header_repr_info )
{
header_repr_info - > type = HTTP2_HD_NONE ;
header_repr_info - > integer = 0 ;
header_repr_info - > next_shift = 0 ;
header_repr_info - > complete = FALSE ;
}
/* Reads zero or more header table size update and optionally header
representation information . This function returns when first
header representation is decoded or buf is processed completely .
This function returns the number bytes processed for header table
size update . */
static guint
process_http2_header_repr_info ( wmem_array_t * headers ,
http2_header_repr_info_t * header_repr_info ,
const guint8 * buf , guint len )
{
guint i ;
guint start ;
if ( header_repr_info - > type ! = HTTP2_HD_NONE & &
header_repr_info - > type ! = HTTP2_HD_HEADER_TABLE_SIZE_UPDATE & &
header_repr_info - > complete ) {
return 0 ;
}
start = 0 ;
for ( i = 0 ; i < len ; ) {
if ( header_repr_info - > type = = HTTP2_HD_NONE ) {
guchar c = buf [ i ] ;
if ( ( c & 0xE0 ) = = 0x20 ) {
header_repr_info - > type = HTTP2_HD_HEADER_TABLE_SIZE_UPDATE ;
i = read_integer ( header_repr_info , buf , len , i , 5 ) ;
} else if ( c & 0x80 ) {
header_repr_info - > type = HTTP2_HD_INDEXED ;
i = read_integer ( header_repr_info , buf , len , i , 7 ) ;
} else if ( c = = 0x40 | | c = = 0 | | c = = 0x10 ) {
/* New name */
header_repr_info - > complete = TRUE ;
if ( c & 0x40 ) {
header_repr_info - > type = HTTP2_HD_LITERAL_INDEXING_NEW_NAME ;
} else if ( ( c & 0xF0 ) = = 0x10 ) {
header_repr_info - > type = HTTP2_HD_LITERAL_NEVER_INDEXING_NEW_NAME ;
} else {
header_repr_info - > type = HTTP2_HD_LITERAL_NEW_NAME ;
}
} else {
/* indexed name */
if ( c & 0x40 ) {
header_repr_info - > type = HTTP2_HD_LITERAL_INDEXING_INDEXED_NAME ;
i = read_integer ( header_repr_info , buf , len , i , 6 ) ;
} else if ( ( c & 0xF0 ) = = 0x10 ) {
header_repr_info - > type = HTTP2_HD_LITERAL_NEVER_INDEXING_INDEXED_NAME ;
i = read_integer ( header_repr_info , buf , len , i , 4 ) ;
} else {
header_repr_info - > type = HTTP2_HD_LITERAL_INDEXED_NAME ;
i = read_integer ( header_repr_info , buf , len , i , 4 ) ;
}
}
} else {
i = read_integer ( header_repr_info , buf , len , i , 8 ) ;
}
if ( header_repr_info - > complete ) {
if ( header_repr_info - > type = = HTTP2_HD_HEADER_TABLE_SIZE_UPDATE ) {
http2_header_t * out ;
out = wmem_new ( wmem_file_scope ( ) , http2_header_t ) ;
out - > type = header_repr_info - > type ;
out - > length = i - start ;
2014-08-13 00:39:07 +00:00
out - > table . header_table_size = header_repr_info - > integer ;
2014-08-04 12:06:14 +00:00
wmem_array_append ( headers , out , 1 ) ;
reset_http2_header_repr_info ( header_repr_info ) ;
/* continue to decode header table size update or
first header encoding is encountered . */
start = i ;
} else {
/* Break on first header encoding */
break ;
}
}
}
return start ;
}
2016-02-05 14:41:57 +00:00
static size_t http2_hdrcache_length ( gconstpointer vv )
{
const guint8 * v = ( const guint8 * ) vv ;
guint32 namelen , valuelen ;
namelen = pntoh32 ( v ) ;
valuelen = pntoh32 ( v + sizeof ( namelen ) + namelen ) ;
return namelen + valuelen + sizeof ( namelen ) + sizeof ( valuelen ) ;
}
static guint http2_hdrcache_hash ( gconstpointer key )
{
return wmem_strong_hash ( ( const guint8 * ) key , http2_hdrcache_length ( key ) ) ;
}
static gboolean http2_hdrcache_equal ( gconstpointer lhs , gconstpointer rhs )
{
const guint8 * a = ( const guint8 * ) lhs ;
const guint8 * b = ( const guint8 * ) rhs ;
size_t alen = http2_hdrcache_length ( a ) ;
size_t blen = http2_hdrcache_length ( b ) ;
return alen = = blen & & memcmp ( a , b , alen ) = = 0 ;
}
2014-05-06 15:54:47 +00:00
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 )
{
guint8 * headbuf ;
proto_tree * header_tree ;
proto_item * header , * ti ;
int header_name_length ;
int header_value_length ;
const gchar * header_name ;
const gchar * header_value ;
int hoffset = 0 ;
nghttp2_hd_inflater * hd_inflater ;
tvbuff_t * header_tvb = tvb_new_composite ( ) ;
int rv ;
2014-06-23 10:25:33 +00:00
int header_len = 0 ;
2014-05-06 15:54:47 +00:00
int final ;
2014-06-23 10:25:33 +00:00
int flow_index ;
http2_header_data_t * header_data ;
2014-08-04 12:06:14 +00:00
http2_header_repr_info_t * header_repr_info ;
2014-06-23 10:25:33 +00:00
wmem_list_t * header_list ;
wmem_array_t * headers ;
guint i ;
2016-02-05 14:41:57 +00:00
if ( ! http2_hdrcache_map ) {
http2_hdrcache_map = wmem_map_new ( wmem_file_scope ( ) , http2_hdrcache_hash , http2_hdrcache_equal ) ;
}
2014-06-23 10:25:33 +00:00
header_data = ( http2_header_data_t * ) p_get_proto_data ( wmem_file_scope ( ) , pinfo , proto_http2 , 0 ) ;
header_list = header_data - > header_list ;
if ( ! PINFO_FD_VISITED ( pinfo ) ) {
/* This packet has not been processed yet, which means this is
the first linear scan . We do header decompression only
once in linear scan and cache the result . If we don ' t
cache , already processed data will be fed into decompressor
again and again since dissector will be called randomly .
This makes context out - of - sync . */
2016-02-05 14:41:57 +00:00
int decompressed_bytes = 0 ;
2014-06-23 10:25:33 +00:00
headbuf = ( guint8 * ) wmem_alloc ( wmem_packet_scope ( ) , headlen ) ;
tvb_memcpy ( tvb , headbuf , offset , headlen ) ;
flow_index = select_http2_flow_index ( pinfo , h2session ) ;
hd_inflater = h2session - > hd_inflater [ flow_index ] ;
2014-08-04 12:06:14 +00:00
header_repr_info = & h2session - > header_repr_info [ flow_index ] ;
2014-06-23 10:25:33 +00:00
final = flags & HTTP2_FLAGS_END_HEADERS ;
headers = wmem_array_sized_new ( wmem_file_scope ( ) , sizeof ( http2_header_t ) , 16 ) ;
for ( ; ; ) {
nghttp2_nv nv ;
int inflate_flags = 0 ;
2016-02-05 14:41:57 +00:00
if ( wmem_array_get_count ( headers ) > = MAX_HTTP2_HEADER_LINES ) {
header_data - > header_lines_exceeded = TRUE ;
break ;
}
2014-06-23 10:25:33 +00:00
rv = ( int ) nghttp2_hd_inflate_hd ( hd_inflater , & nv ,
& inflate_flags , headbuf , headlen , final ) ;
if ( rv < 0 ) {
break ;
}
headbuf + = rv ;
headlen - = rv ;
2014-08-04 12:06:14 +00:00
rv - = process_http2_header_repr_info ( headers , header_repr_info , headbuf - rv , rv ) ;
2014-06-23 10:25:33 +00:00
if ( inflate_flags & NGHTTP2_HD_INFLATE_EMIT ) {
2016-02-05 14:41:57 +00:00
char * cached_pstr ;
2014-08-02 07:22:28 +00:00
guint32 len ;
2016-02-05 14:41:57 +00:00
guint datalen = ( guint ) ( 4 + nv . namelen + 4 + nv . valuelen ) ;
2014-06-23 10:25:33 +00:00
http2_header_t * out ;
2016-02-05 14:41:57 +00:00
if ( decompressed_bytes + datalen > = MAX_HTTP2_HEADER_SIZE ) {
header_data - > header_size_reached = decompressed_bytes ;
header_data - > header_size_attempted = decompressed_bytes + datalen ;
break ;
}
2014-06-23 10:25:33 +00:00
out = wmem_new ( wmem_file_scope ( ) , http2_header_t ) ;
2014-08-04 12:06:14 +00:00
out - > type = header_repr_info - > type ;
out - > length = rv ;
2015-09-03 02:53:05 +00:00
out - > table . data . idx = header_repr_info - > integer ;
2014-08-04 12:06:14 +00:00
2016-02-05 14:41:57 +00:00
out - > table . data . datalen = datalen ;
decompressed_bytes + = datalen ;
2014-06-23 10:25:33 +00:00
/* Prepare buffer... with the following format
name length ( uint32 )
name ( string )
value length ( uint32 )
value ( string )
*/
2016-02-05 14:41:57 +00:00
http2_header_pstr = ( char * ) wmem_realloc ( wmem_file_scope ( ) , http2_header_pstr , out - > table . data . datalen ) ;
2014-06-23 10:25:33 +00:00
/* nv.namelen and nv.valuelen are of size_t. In order
to get length in 4 bytes , we have to copy it to
2014-08-02 07:22:28 +00:00
guint32 . */
len = ( guint32 ) nv . namelen ;
2016-02-05 14:41:57 +00:00
phton32 ( & http2_header_pstr [ 0 ] , len ) ;
memcpy ( & http2_header_pstr [ 4 ] , nv . name , nv . namelen ) ;
2014-06-23 10:25:33 +00:00
2014-08-02 07:22:28 +00:00
len = ( guint32 ) nv . valuelen ;
2016-02-05 14:41:57 +00:00
phton32 ( & http2_header_pstr [ 4 + nv . namelen ] , len ) ;
memcpy ( & http2_header_pstr [ 4 + nv . namelen + 4 ] , nv . value , nv . valuelen ) ;
2014-06-23 10:25:33 +00:00
2016-02-05 14:41:57 +00:00
cached_pstr = ( char * ) wmem_map_lookup ( http2_hdrcache_map , http2_header_pstr ) ;
if ( cached_pstr ) {
out - > table . data . data = cached_pstr ;
} else {
wmem_map_insert ( http2_hdrcache_map , http2_header_pstr , http2_header_pstr ) ;
out - > table . data . data = http2_header_pstr ;
http2_header_pstr = NULL ;
}
2014-06-23 10:25:33 +00:00
wmem_array_append ( headers , out , 1 ) ;
2014-08-04 12:06:14 +00:00
reset_http2_header_repr_info ( header_repr_info ) ;
2014-06-23 10:25:33 +00:00
}
if ( inflate_flags & NGHTTP2_HD_INFLATE_FINAL ) {
nghttp2_hd_inflate_end_headers ( hd_inflater ) ;
break ;
}
if ( ( inflate_flags & NGHTTP2_HD_INFLATE_EMIT ) = = 0 & &
headlen = = 0 ) {
break ;
}
}
2014-05-06 15:54:47 +00:00
2014-06-23 10:25:33 +00:00
wmem_list_append ( header_list , headers ) ;
2014-05-06 15:54:47 +00:00
2014-06-23 10:25:33 +00:00
if ( ! header_data - > current ) {
header_data - > current = wmem_list_head ( header_list ) ;
}
2014-05-06 15:54:47 +00:00
2014-06-23 10:25:33 +00:00
} else {
headers = ( wmem_array_t * ) wmem_list_frame_data ( header_data - > current ) ;
2014-05-06 15:54:47 +00:00
2014-06-23 10:25:33 +00:00
header_data - > current = wmem_list_frame_next ( header_data - > current ) ;
2014-05-06 15:54:47 +00:00
2014-06-23 10:25:33 +00:00
if ( ! header_data - > current ) {
header_data - > current = wmem_list_head ( header_list ) ;
2014-05-06 15:54:47 +00:00
}
2014-06-23 10:25:33 +00:00
}
2014-05-06 15:54:47 +00:00
2014-07-16 13:41:27 +00:00
if ( wmem_array_get_count ( headers ) = = 0 ) {
return ;
}
2014-06-23 10:25:33 +00:00
for ( i = 0 ; i < wmem_array_get_count ( headers ) ; + + i ) {
http2_header_t * in ;
tvbuff_t * next_tvb ;
in = ( http2_header_t * ) wmem_array_index ( headers , i ) ;
2014-08-04 12:06:14 +00:00
if ( in - > type = = HTTP2_HD_HEADER_TABLE_SIZE_UPDATE ) {
continue ;
}
2014-08-13 00:39:07 +00:00
header_len + = in - > table . data . datalen ;
2014-06-23 10:25:33 +00:00
/* Now setup the tvb buffer to have the new data */
2016-02-05 14:41:57 +00:00
next_tvb = tvb_new_child_real_data ( tvb , in - > table . data . data , in - > table . data . datalen , in - > table . data . datalen ) ;
2014-06-23 10:25:33 +00:00
tvb_composite_append ( header_tvb , next_tvb ) ;
2014-05-06 15:54:47 +00:00
}
2014-06-23 10:25:33 +00:00
2014-05-06 15:54:47 +00:00
tvb_composite_finalize ( header_tvb ) ;
add_new_data_source ( pinfo , header_tvb , " Decompressed Header " ) ;
ti = proto_tree_add_uint ( tree , hf_http2_header_length , header_tvb , hoffset , 1 , header_len ) ;
PROTO_ITEM_SET_GENERATED ( ti ) ;
2016-02-05 14:41:57 +00:00
if ( header_data - > header_size_attempted > 0 ) {
expert_add_info_format ( pinfo , ti , & ei_http2_header_size ,
" Decompression stopped after %u bytes (%u attempted). " ,
header_data - > header_size_reached ,
header_data - > header_size_attempted ) ;
}
ti = proto_tree_add_uint ( tree , hf_http2_header_count , header_tvb , hoffset , 1 , wmem_array_get_count ( headers ) ) ;
PROTO_ITEM_SET_GENERATED ( ti ) ;
if ( header_data - > header_lines_exceeded ) {
expert_add_info ( pinfo , ti , & ei_http2_header_lines ) ;
}
2014-08-04 12:06:14 +00:00
for ( i = 0 ; i < wmem_array_get_count ( headers ) ; + + i ) {
http2_header_t * in = ( http2_header_t * ) wmem_array_index ( headers , i ) ;
if ( in - > type = = HTTP2_HD_HEADER_TABLE_SIZE_UPDATE ) {
header = proto_tree_add_item ( tree , hf_http2_header_table_size_update , tvb , offset , in - > length , ENC_NA ) ;
header_tree = proto_item_add_subtree ( header , ett_http2_headers ) ;
2014-08-13 00:39:07 +00:00
proto_tree_add_uint ( header_tree , hf_http2_header_table_size , tvb , offset , in - > length , in - > table . header_table_size ) ;
2014-08-04 12:06:14 +00:00
offset + = in - > length ;
continue ;
}
2014-05-06 15:54:47 +00:00
/* Populate tree with header name/value details. */
/* Add 'Header' subtree with description. */
2014-08-04 12:06:14 +00:00
header = proto_tree_add_item ( tree , hf_http2_header , tvb , offset , in - > length , ENC_NA ) ;
2014-05-06 15:54:47 +00:00
header_tree = proto_item_add_subtree ( header , ett_http2_headers ) ;
/* header value length */
2015-01-20 21:20:54 +00:00
header_name_length = tvb_get_ntohl ( header_tvb , hoffset ) ;
2014-08-04 12:06:14 +00:00
proto_tree_add_uint ( header_tree , hf_http2_header_name_length , tvb , offset , in - > length , header_name_length ) ;
2014-05-06 15:54:47 +00:00
hoffset + = 4 ;
/* Add header name. */
header_name = ( gchar * ) tvb_get_string_enc ( wmem_packet_scope ( ) , header_tvb , hoffset , header_name_length , ENC_ASCII | ENC_NA ) ;
2014-08-04 12:06:14 +00:00
proto_tree_add_string ( header_tree , hf_http2_header_name , tvb , offset , in - > length , header_name ) ;
2014-05-06 15:54:47 +00:00
hoffset + = header_name_length ;
/* header value length */
2015-01-20 21:20:54 +00:00
header_value_length = tvb_get_ntohl ( header_tvb , hoffset ) ;
2014-08-04 12:06:14 +00:00
proto_tree_add_uint ( header_tree , hf_http2_header_value_length , tvb , offset , in - > length , header_value_length ) ;
2014-05-06 15:54:47 +00:00
hoffset + = 4 ;
/* Add header value. */
header_value = ( gchar * ) tvb_get_string_enc ( wmem_packet_scope ( ) , header_tvb , hoffset , header_value_length , ENC_ASCII | ENC_NA ) ;
2014-08-04 12:06:14 +00:00
proto_tree_add_string ( header_tree , hf_http2_header_value , tvb , offset , in - > length , header_value ) ;
2014-05-06 15:54:47 +00:00
hoffset + = header_value_length ;
2014-08-04 12:06:14 +00:00
/* Add encoding representation */
proto_tree_add_string ( header_tree , hf_http2_header_repr , tvb , offset , in - > length , http2_header_repr_type [ in - > type ] . strptr ) ;
if ( in - > type = = HTTP2_HD_INDEXED | |
in - > type = = HTTP2_HD_LITERAL_INDEXING_INDEXED_NAME | |
in - > type = = HTTP2_HD_LITERAL_INDEXED_NAME | |
in - > type = = HTTP2_HD_LITERAL_NEVER_INDEXING_INDEXED_NAME ) {
2015-09-03 02:53:05 +00:00
proto_tree_add_uint ( header_tree , hf_http2_header_index , tvb , offset , in - > length , in - > table . data . idx ) ;
2014-08-04 12:06:14 +00:00
}
2014-05-06 15:54:47 +00:00
proto_item_append_text ( header , " : %s: %s " , header_name , header_value ) ;
2014-08-04 12:06:14 +00:00
offset + = in - > length ;
2014-05-06 15:54:47 +00:00
}
}
2013-08-30 11:14:09 +00:00
static guint8
2014-04-25 14:29:10 +00:00
dissect_http2_header_flags ( tvbuff_t * tvb , packet_info * pinfo _U_ , proto_tree * http2_tree , guint offset , guint8 type )
2013-08-30 11:14:09 +00:00
{
proto_item * ti_flags ;
proto_tree * flags_tree ;
guint8 flags ;
2014-12-13 17:52:20 +00:00
ti_flags = proto_tree_add_item ( http2_tree , hf_http2_flags , tvb , offset , 1 , ENC_BIG_ENDIAN ) ;
2013-08-30 11:14:09 +00:00
flags_tree = proto_item_add_subtree ( ti_flags , ett_http2_flags ) ;
flags = tvb_get_guint8 ( tvb , offset ) ;
switch ( type ) {
case HTTP2_DATA :
proto_tree_add_item ( flags_tree , hf_http2_flags_end_stream , tvb , offset , 1 , ENC_NA ) ;
2014-06-23 14:21:15 +00:00
proto_tree_add_item ( flags_tree , hf_http2_flags_padded , tvb , offset , 1 , ENC_NA ) ;
2014-12-13 17:52:20 +00:00
proto_tree_add_item ( flags_tree , hf_http2_flags_unused_data , tvb , offset , 1 , ENC_BIG_ENDIAN ) ;
2014-04-25 14:29:10 +00:00
break ;
2013-08-30 11:14:09 +00:00
case HTTP2_HEADERS :
proto_tree_add_item ( flags_tree , hf_http2_flags_end_stream , tvb , offset , 1 , ENC_NA ) ;
proto_tree_add_item ( flags_tree , hf_http2_flags_end_headers , tvb , offset , 1 , ENC_NA ) ;
2014-06-23 14:21:15 +00:00
proto_tree_add_item ( flags_tree , hf_http2_flags_padded , tvb , offset , 1 , ENC_NA ) ;
2013-08-30 11:14:09 +00:00
proto_tree_add_item ( flags_tree , hf_http2_flags_priority , tvb , offset , 1 , ENC_NA ) ;
2014-12-13 17:52:20 +00:00
proto_tree_add_item ( flags_tree , hf_http2_flags_unused_headers , tvb , offset , 1 , ENC_BIG_ENDIAN ) ;
2014-04-25 14:29:10 +00:00
break ;
2013-08-30 11:14:09 +00:00
case HTTP2_SETTINGS :
2013-12-15 19:07:40 +00:00
proto_tree_add_item ( flags_tree , hf_http2_flags_settings_ack , tvb , offset , 1 , ENC_NA ) ;
2014-12-13 17:52:20 +00:00
proto_tree_add_item ( flags_tree , hf_http2_flags_unused_settings , tvb , offset , 1 , ENC_BIG_ENDIAN ) ;
2014-04-25 14:29:10 +00:00
break ;
case HTTP2_PUSH_PROMISE :
2014-06-23 14:21:15 +00:00
proto_tree_add_item ( flags_tree , hf_http2_flags_end_headers , tvb , offset , 1 , ENC_NA ) ;
proto_tree_add_item ( flags_tree , hf_http2_flags_padded , tvb , offset , 1 , ENC_NA ) ;
2014-12-13 17:52:20 +00:00
proto_tree_add_item ( flags_tree , hf_http2_flags_unused_push_promise , tvb , offset , 1 , ENC_BIG_ENDIAN ) ;
2014-06-23 14:21:15 +00:00
break ;
2014-04-25 14:29:10 +00:00
case HTTP2_CONTINUATION :
proto_tree_add_item ( flags_tree , hf_http2_flags_end_headers , tvb , offset , 1 , ENC_NA ) ;
2014-12-13 17:52:20 +00:00
proto_tree_add_item ( flags_tree , hf_http2_flags_unused_continuation , tvb , offset , 1 , ENC_BIG_ENDIAN ) ;
2014-04-25 14:29:10 +00:00
break ;
case HTTP2_PING :
proto_tree_add_item ( flags_tree , hf_http2_flags_ping_ack , tvb , offset , 1 , ENC_NA ) ;
2014-12-13 17:52:20 +00:00
proto_tree_add_item ( flags_tree , hf_http2_flags_unused_ping , tvb , offset , 1 , ENC_BIG_ENDIAN ) ;
2014-04-25 14:29:10 +00:00
break ;
2014-05-12 07:00:52 +00:00
case HTTP2_PRIORITY :
case HTTP2_RST_STREAM :
2013-08-30 11:14:09 +00:00
case HTTP2_GOAWAY :
case HTTP2_WINDOW_UPDATE :
2014-04-25 14:29:10 +00:00
case HTTP2_ALTSVC :
case HTTP2_BLOCKED :
2013-08-30 11:14:09 +00:00
default :
2014-05-12 07:00:52 +00:00
/* Does not define any flags */
2014-12-13 17:52:20 +00:00
proto_tree_add_item ( flags_tree , hf_http2_flags_unused , tvb , offset , 1 , ENC_BIG_ENDIAN ) ;
2014-04-25 14:29:10 +00:00
break ;
2013-08-30 11:14:09 +00:00
}
return flags ;
}
2014-04-25 14:29:10 +00:00
/* helper function to get the padding data for the frames that feature them */
static guint
dissect_frame_padding ( tvbuff_t * tvb , guint16 * padding , proto_tree * http2_tree ,
guint offset , guint8 flags )
2013-08-30 11:14:09 +00:00
{
2014-05-12 07:00:52 +00:00
proto_item * ti ;
guint pad_len = 0 ;
2014-04-25 14:29:10 +00:00
* padding = 0 ;
2013-08-30 11:14:09 +00:00
2014-06-23 14:21:15 +00:00
if ( flags & HTTP2_FLAGS_PADDED )
2013-08-30 11:14:09 +00:00
{
2014-06-23 14:21:15 +00:00
* padding = tvb_get_guint8 ( tvb , offset ) ; /* read a single octet */
2014-12-13 17:52:20 +00:00
proto_tree_add_item ( http2_tree , hf_http2_padding , tvb , offset , 1 , ENC_BIG_ENDIAN ) ;
2014-04-25 14:29:10 +00:00
offset + + ;
2014-05-12 07:00:52 +00:00
pad_len + + ;
2013-08-30 11:14:09 +00:00
}
2014-05-12 07:00:52 +00:00
ti = proto_tree_add_uint ( http2_tree , hf_http2_pad_length , tvb , offset - pad_len , pad_len , * padding ) ;
PROTO_ITEM_SET_GENERATED ( ti ) ;
2013-08-30 11:14:09 +00:00
return offset ;
}
2014-04-25 14:29:10 +00:00
/* helper function to get the priority dependence for the frames that feature them:
HEADERS and PRIORITY */
static guint
dissect_frame_prio ( tvbuff_t * tvb , proto_tree * http2_tree , guint offset , guint8 flags )
{
2014-05-13 15:49:24 +00:00
proto_tree * ti ;
guint8 weight ;
2014-04-25 14:29:10 +00:00
if ( flags & HTTP2_FLAGS_PRIORITY )
{
2014-05-13 15:49:24 +00:00
proto_tree_add_item ( http2_tree , hf_http2_excl_dependency , tvb , offset , 4 , ENC_NA ) ;
2014-09-19 02:29:29 +00:00
proto_tree_add_item ( http2_tree , hf_http2_stream_dependency , tvb , offset , 4 , ENC_BIG_ENDIAN ) ;
2014-04-25 14:29:10 +00:00
offset + = 4 ;
2014-12-13 17:52:20 +00:00
proto_tree_add_item ( http2_tree , hf_http2_weight , tvb , offset , 1 , ENC_BIG_ENDIAN ) ;
2014-05-13 15:49:24 +00:00
weight = tvb_get_guint8 ( tvb , offset ) ;
/* 6.2: Weight: An 8-bit weight for the stream; Add one to the value to obtain a weight between 1 and 256 */
ti = proto_tree_add_uint ( http2_tree , hf_http2_weight_real , tvb , offset , 1 , weight + 1 ) ;
PROTO_ITEM_SET_GENERATED ( ti ) ;
2014-04-25 14:29:10 +00:00
offset + + ;
}
return offset ;
}
/* Data (0) */
2013-08-30 11:14:09 +00:00
static int
2014-04-25 14:29:10 +00:00
dissect_http2_data ( tvbuff_t * tvb , packet_info * pinfo _U_ , proto_tree * http2_tree ,
guint offset , guint8 flags )
2013-08-30 11:14:09 +00:00
{
2014-04-25 14:29:10 +00:00
guint16 padding ;
2014-04-28 03:16:19 +00:00
gint datalen ;
2013-08-30 11:14:09 +00:00
2014-04-25 14:29:10 +00:00
offset = dissect_frame_padding ( tvb , & padding , http2_tree , offset , flags ) ;
datalen = tvb_reported_length_remaining ( tvb , offset ) - padding ;
2014-09-19 02:29:29 +00:00
proto_tree_add_item ( http2_tree , hf_http2_data_data , tvb , offset , datalen , ENC_NA ) ;
2014-04-25 14:29:10 +00:00
offset + = datalen ;
2013-08-30 11:14:09 +00:00
2014-04-25 14:29:10 +00:00
proto_tree_add_item ( http2_tree , hf_http2_data_padding , tvb , offset , padding , ENC_NA ) ;
offset + = padding ;
return offset ;
}
/* Headers */
static int
2016-02-05 14:41:57 +00:00
dissect_http2_headers ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * http2_tree ,
2014-04-25 14:29:10 +00:00
guint offset , guint8 flags )
{
guint16 padding ;
2014-04-28 03:16:19 +00:00
gint headlen ;
2014-05-06 15:54:47 +00:00
http2_session_t * h2session ;
h2session = get_http2_session ( pinfo ) ;
2014-04-25 14:29:10 +00:00
offset = dissect_frame_padding ( tvb , & padding , http2_tree , offset , flags ) ;
offset = dissect_frame_prio ( tvb , http2_tree , offset , flags ) ;
headlen = tvb_reported_length_remaining ( tvb , offset ) - padding ;
2014-09-19 02:29:29 +00:00
proto_tree_add_item ( http2_tree , hf_http2_headers , tvb , offset , headlen , ENC_NA ) ;
2014-05-12 07:00:52 +00:00
2014-05-06 15:54:47 +00:00
/* decompress the header block */
inflate_http2_header_block ( tvb , pinfo , offset , http2_tree , headlen , h2session , flags ) ;
2014-04-25 14:29:10 +00:00
offset + = headlen ;
proto_tree_add_item ( http2_tree , hf_http2_headers_padding , tvb , offset , padding , ENC_NA ) ;
offset + = padding ;
return offset ;
}
/* Priority */
static int
dissect_http2_priority ( tvbuff_t * tvb , packet_info * pinfo _U_ , proto_tree * http2_tree ,
guint offset , guint8 flags )
{
/* we pretend the HTTP2_FLAGS_PRIORITY flag is set to share the dissect
function */
offset = dissect_frame_prio ( tvb , http2_tree , offset ,
flags | HTTP2_FLAGS_PRIORITY ) ;
2013-08-30 11:14:09 +00:00
return offset ;
}
/* RST Stream */
static int
dissect_http2_rst_stream ( tvbuff_t * tvb , packet_info * pinfo _U_ , proto_tree * http2_tree , guint offset , guint8 flags _U_ )
{
2014-09-19 02:29:29 +00:00
proto_tree_add_item ( http2_tree , hf_http2_rst_stream_error , tvb , offset , 4 , ENC_BIG_ENDIAN ) ;
2013-08-30 11:14:09 +00:00
offset + = 4 ;
return offset ;
}
/* Settings */
static int
2014-06-23 10:25:33 +00:00
dissect_http2_settings ( tvbuff_t * tvb , packet_info * pinfo _U_ , proto_tree * http2_tree , guint offset , guint8 flags )
2013-08-30 11:14:09 +00:00
{
guint32 settingsid ;
proto_item * ti_settings ;
proto_tree * settings_tree ;
2014-08-02 07:22:28 +00:00
guint32 header_table_size ;
guint32 min_header_table_size ;
2014-06-23 10:25:33 +00:00
int header_table_size_found ;
http2_session_t * h2session ;
2013-08-30 11:14:09 +00:00
2014-06-23 10:25:33 +00:00
header_table_size_found = 0 ;
header_table_size = 0 ;
2014-08-02 07:22:28 +00:00
min_header_table_size = 0xFFFFFFFFu ;
2014-05-06 15:54:47 +00:00
2013-08-30 11:14:09 +00:00
while ( tvb_reported_length_remaining ( tvb , offset ) > 0 ) {
2014-04-25 14:29:10 +00:00
ti_settings = proto_tree_add_item ( http2_tree , hf_http2_settings , tvb , offset , 5 , ENC_NA ) ;
2013-08-30 11:14:09 +00:00
settings_tree = proto_item_add_subtree ( ti_settings , ett_http2_settings ) ;
2014-12-13 17:52:20 +00:00
proto_tree_add_item ( settings_tree , hf_http2_settings_identifier , tvb , offset , 2 , ENC_BIG_ENDIAN ) ;
2014-06-23 14:21:15 +00:00
settingsid = tvb_get_ntohs ( tvb , offset ) ;
2014-04-25 14:29:10 +00:00
proto_item_append_text ( ti_settings , " - %s " ,
val_to_str ( settingsid , http2_settings_vals , " Unknown (%u) " ) ) ;
2014-06-23 14:21:15 +00:00
offset + = 2 ;
2013-08-30 11:14:09 +00:00
switch ( settingsid ) {
2013-12-15 19:07:40 +00:00
case HTTP2_SETTINGS_HEADER_TABLE_SIZE :
2014-09-19 02:29:29 +00:00
proto_tree_add_item ( settings_tree , hf_http2_settings_header_table_size , tvb , offset , 4 , ENC_BIG_ENDIAN ) ;
2014-06-23 10:25:33 +00:00
/* We only care the last header table size in SETTINGS */
header_table_size_found = 1 ;
header_table_size = tvb_get_ntohl ( tvb , offset ) ;
2014-08-02 07:22:28 +00:00
if ( min_header_table_size > header_table_size ) {
min_header_table_size = header_table_size ;
}
2013-12-15 19:07:40 +00:00
break ;
case HTTP2_SETTINGS_ENABLE_PUSH :
2014-09-19 02:29:29 +00:00
proto_tree_add_item ( settings_tree , hf_http2_settings_enable_push , tvb , offset , 4 , ENC_BIG_ENDIAN ) ;
2013-12-15 19:07:40 +00:00
break ;
2013-08-30 11:14:09 +00:00
case HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS :
2014-09-19 02:29:29 +00:00
proto_tree_add_item ( settings_tree , hf_http2_settings_max_concurrent_streams , tvb , offset , 4 , ENC_BIG_ENDIAN ) ;
2013-08-30 11:14:09 +00:00
break ;
case HTTP2_SETTINGS_INITIAL_WINDOW_SIZE :
2014-09-19 02:29:29 +00:00
proto_tree_add_item ( settings_tree , hf_http2_settings_initial_window_size , tvb , offset , 4 , ENC_BIG_ENDIAN ) ;
2013-08-30 11:14:09 +00:00
break ;
2014-08-02 07:22:28 +00:00
case HTTP2_SETTINGS_MAX_FRAME_SIZE :
2014-09-19 02:29:29 +00:00
proto_tree_add_item ( settings_tree , hf_http2_settings_max_frame_size , tvb , offset , 4 , ENC_BIG_ENDIAN ) ;
2014-08-02 07:22:28 +00:00
break ;
case HTTP2_SETTINGS_MAX_HEADER_LIST_SIZE :
2014-09-19 02:29:29 +00:00
proto_tree_add_item ( settings_tree , hf_http2_settings_max_header_list_size , tvb , offset , 4 , ENC_BIG_ENDIAN ) ;
2014-08-02 07:22:28 +00:00
break ;
2013-08-30 11:14:09 +00:00
default :
2014-09-19 02:29:29 +00:00
proto_tree_add_item ( settings_tree , hf_http2_settings_unknown , tvb , offset , 4 , ENC_BIG_ENDIAN ) ;
2013-08-30 11:14:09 +00:00
break ;
}
proto_item_append_text ( ti_settings , " : %u " , tvb_get_ntohl ( tvb , offset ) ) ;
offset + = 4 ;
}
2014-06-23 10:25:33 +00:00
if ( ! PINFO_FD_VISITED ( pinfo ) ) {
h2session = get_http2_session ( pinfo ) ;
if ( flags & HTTP2_FLAGS_ACK ) {
apply_and_pop_settings ( pinfo , h2session ) ;
} else {
http2_settings_t * settings ;
settings = wmem_new ( wmem_file_scope ( ) , http2_settings_t ) ;
2014-08-02 07:22:28 +00:00
settings - > min_header_table_size = min_header_table_size ;
2014-06-23 10:25:33 +00:00
settings - > header_table_size = header_table_size ;
settings - > has_header_table_size = header_table_size_found ;
push_settings ( pinfo , h2session , settings ) ;
}
}
2013-08-30 11:14:09 +00:00
return offset ;
}
/* Push Promise */
static int
2014-04-25 14:29:10 +00:00
dissect_http2_push_promise ( tvbuff_t * tvb , packet_info * pinfo _U_ , proto_tree * http2_tree ,
guint offset , guint8 flags _U_ )
2013-08-30 11:14:09 +00:00
{
2014-04-25 14:29:10 +00:00
guint16 padding ;
2014-05-12 07:00:52 +00:00
gint headlen ;
2014-05-06 15:54:47 +00:00
http2_session_t * h2session ;
h2session = get_http2_session ( pinfo ) ;
2013-08-30 11:14:09 +00:00
2014-04-25 14:29:10 +00:00
offset = dissect_frame_padding ( tvb , & padding , http2_tree , offset , flags ) ;
2014-09-19 02:29:29 +00:00
proto_tree_add_item ( http2_tree , hf_http2_push_promise_r , tvb , offset , 4 , ENC_BIG_ENDIAN ) ;
2014-04-25 14:29:10 +00:00
proto_tree_add_item ( http2_tree , hf_http2_push_promise_promised_stream_id , tvb ,
2014-09-19 02:29:29 +00:00
offset , 4 , ENC_BIG_ENDIAN ) ;
2013-08-30 11:14:09 +00:00
offset + = 4 ;
2014-05-12 07:00:52 +00:00
headlen = tvb_reported_length_remaining ( tvb , offset ) - padding ;
proto_tree_add_item ( http2_tree , hf_http2_push_promise_header , tvb , offset , headlen ,
2014-04-25 14:29:10 +00:00
ENC_ASCII | ENC_NA ) ;
2014-05-06 15:54:47 +00:00
inflate_http2_header_block ( tvb , pinfo , offset , http2_tree , headlen , h2session , flags ) ;
2014-05-12 07:00:52 +00:00
offset + = headlen ;
2014-04-25 14:29:10 +00:00
proto_tree_add_item ( http2_tree , hf_http2_push_promise_padding , tvb ,
offset , padding , ENC_NA ) ;
2013-08-30 11:14:09 +00:00
offset + = tvb_reported_length_remaining ( tvb , offset ) ;
return offset ;
}
/* Ping */
static int
2014-04-25 14:29:10 +00:00
dissect_http2_ping ( tvbuff_t * tvb , packet_info * pinfo _U_ , proto_tree * http2_tree ,
guint offset , guint8 flags )
2013-08-30 11:14:09 +00:00
{
/* TODO : Add Response time */
2013-12-15 19:07:40 +00:00
if ( flags & HTTP2_FLAGS_ACK )
2013-08-30 11:14:09 +00:00
{
proto_tree_add_item ( http2_tree , hf_http2_pong , tvb , offset , 8 , ENC_NA ) ;
} else {
proto_tree_add_item ( http2_tree , hf_http2_ping , tvb , offset , 8 , ENC_NA ) ;
}
offset + = 8 ;
return offset ;
}
/* Goaway */
static int
dissect_http2_goaway ( tvbuff_t * tvb , packet_info * pinfo _U_ , proto_tree * http2_tree , guint offset , guint8 flags _U_ )
{
2014-09-19 02:29:29 +00:00
proto_tree_add_item ( http2_tree , hf_http2_goaway_r , tvb , offset , 4 , ENC_BIG_ENDIAN ) ;
proto_tree_add_item ( http2_tree , hf_http2_goaway_last_stream_id , tvb , offset , 4 , ENC_BIG_ENDIAN ) ;
2013-08-30 11:14:09 +00:00
offset + = 4 ;
2014-09-19 02:29:29 +00:00
proto_tree_add_item ( http2_tree , hf_http2_goaway_error , tvb , offset , 4 , ENC_BIG_ENDIAN ) ;
2013-08-30 11:14:09 +00:00
offset + = 4 ;
if ( tvb_reported_length_remaining ( tvb , offset ) > 0 )
{
proto_tree_add_item ( http2_tree , hf_http2_goaway_addata , tvb , offset , - 1 , ENC_NA ) ;
offset + = tvb_reported_length_remaining ( tvb , offset ) ;
}
return offset ;
}
/* Window Update */
static int
dissect_http2_window_update ( tvbuff_t * tvb , packet_info * pinfo _U_ , proto_tree * http2_tree , guint offset , guint8 flags _U_ )
{
2014-09-19 02:29:29 +00:00
proto_tree_add_item ( http2_tree , hf_http2_window_update_r , tvb , offset , 4 , ENC_BIG_ENDIAN ) ;
proto_tree_add_item ( http2_tree , hf_http2_window_update_window_size_increment , tvb , offset , 4 , ENC_BIG_ENDIAN ) ;
2013-08-30 11:14:09 +00:00
offset + = 4 ;
return offset ;
}
static int
2014-05-12 07:00:52 +00:00
dissect_http2_continuation ( tvbuff_t * tvb , packet_info * pinfo _U_ , proto_tree * http2_tree , guint offset , guint8 flags )
2013-08-30 11:14:09 +00:00
{
2014-05-12 07:00:52 +00:00
guint16 padding ;
gint headlen ;
2014-05-06 15:54:47 +00:00
http2_session_t * h2session ;
h2session = get_http2_session ( pinfo ) ;
2014-05-12 07:00:52 +00:00
offset = dissect_frame_padding ( tvb , & padding , http2_tree , offset , flags ) ;
2013-08-30 11:14:09 +00:00
2014-05-12 07:00:52 +00:00
headlen = tvb_reported_length_remaining ( tvb , offset ) - padding ;
proto_tree_add_item ( http2_tree , hf_http2_continuation_header , tvb , offset , headlen , ENC_ASCII | ENC_NA ) ;
2014-05-06 15:54:47 +00:00
inflate_http2_header_block ( tvb , pinfo , offset , http2_tree , headlen , h2session , flags ) ;
2014-05-12 07:00:52 +00:00
offset + = headlen ;
proto_tree_add_item ( http2_tree , hf_http2_continuation_padding , tvb , offset , padding , ENC_NA ) ;
offset + = padding ;
2013-08-30 11:14:09 +00:00
return offset ;
}
2014-04-25 14:29:10 +00:00
/* Altsvc */
static int
dissect_http2_altsvc ( tvbuff_t * tvb , packet_info * pinfo _U_ , proto_tree * http2_tree ,
guint offset , guint8 flags _U_ , guint16 length )
{
guint8 pidlen ;
guint8 hostlen ;
int remain ;
2014-09-19 02:29:29 +00:00
proto_tree_add_item ( http2_tree , hf_http2_altsvc_maxage , tvb , offset , 4 , ENC_BIG_ENDIAN ) ;
2014-04-25 14:29:10 +00:00
offset + = 4 ;
2014-09-19 02:29:29 +00:00
proto_tree_add_item ( http2_tree , hf_http2_altsvc_port , tvb , offset , 2 , ENC_BIG_ENDIAN ) ;
2014-04-25 14:29:10 +00:00
offset + = 2 ;
2014-12-13 17:52:20 +00:00
proto_tree_add_item ( http2_tree , hf_http2_altsvc_proto_len , tvb , offset , 1 , ENC_BIG_ENDIAN ) ;
2014-04-25 14:29:10 +00:00
pidlen = tvb_get_guint8 ( tvb , offset ) ;
offset + + ;
proto_tree_add_item ( http2_tree , hf_http2_altsvc_protocol , tvb , offset , pidlen , ENC_ASCII | ENC_NA ) ;
offset + = pidlen ;
2014-12-13 17:52:20 +00:00
proto_tree_add_item ( http2_tree , hf_http2_altsvc_host_len , tvb , offset , 1 , ENC_BIG_ENDIAN ) ;
2014-04-25 14:29:10 +00:00
hostlen = tvb_get_guint8 ( tvb , offset ) ;
offset + + ;
proto_tree_add_item ( http2_tree , hf_http2_altsvc_host , tvb , offset , hostlen , ENC_ASCII | ENC_NA ) ;
offset + = hostlen ;
remain = length - offset ;
if ( remain > - 8 ) {
/* 8 is the fixed size of the http2 frame header */
proto_tree_add_item ( http2_tree , hf_http2_altsvc_origin , tvb ,
offset , remain + 8 , ENC_ASCII | ENC_NA ) ;
offset + = remain ;
}
return offset ;
}
2013-11-09 17:46:28 +00:00
static int
dissect_http2_pdu ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree , void * data _U_ )
2013-08-30 11:14:09 +00:00
{
proto_item * ti ;
proto_tree * http2_tree ;
guint offset = 0 ;
guint8 type , flags ;
guint16 length ;
guint32 streamid ;
2015-01-08 16:35:58 +00:00
struct HTTP2Tap * http2_stats ;
2013-08-30 11:14:09 +00:00
2014-06-23 10:25:33 +00:00
if ( ! p_get_proto_data ( wmem_file_scope ( ) , pinfo , proto_http2 , 0 ) ) {
http2_header_data_t * header_data ;
2016-02-05 14:41:57 +00:00
header_data = wmem_new0 ( wmem_file_scope ( ) , http2_header_data_t ) ;
2014-06-23 10:25:33 +00:00
header_data - > header_list = wmem_list_new ( wmem_file_scope ( ) ) ;
p_add_proto_data ( wmem_file_scope ( ) , pinfo , proto_http2 , 0 , header_data ) ;
}
2013-08-30 11:14:09 +00:00
/* 4.1 Frame Format
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - +
2014-08-02 07:22:28 +00:00
| Length ( 24 ) |
+ - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - +
| Type ( 8 ) | Flags ( 8 ) |
+ - + - + - - - - - - - - - - - + - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2013-08-30 11:14:09 +00:00
| R | Stream Identifier ( 31 ) |
2014-08-02 07:22:28 +00:00
+ = + = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +
2013-08-30 11:14:09 +00:00
| Frame Payload ( 0. . . ) . . .
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*/
2016-02-03 06:06:07 +00:00
ti = proto_tree_add_item ( tree , hf_http2_stream , tvb , 0 , - 1 , ENC_NA ) ;
2013-08-30 11:14:09 +00:00
http2_tree = proto_item_add_subtree ( ti , ett_http2_header ) ;
/* 3.5 Connection Header
Upon establishment of a TCP connection and determination that
2014-08-02 07:22:28 +00:00
HTTP / 2 will be used by both peers , each endpoint MUST send a
connection preface as a final confirmation and to establish the
initial SETTINGS parameters for the HTTP / 2 connection .
2013-08-30 11:14:09 +00:00
*/
/* tvb_memeql makes certain there are enough bytes in the buffer.
* returns - 1 if there are not enough bytes or if there is not a
* match . Returns 0 on a match
*/
if ( tvb_memeql ( tvb , offset , kMagicHello , MAGIC_FRAME_LENGTH ) = = 0 )
{
col_append_sep_str ( pinfo - > cinfo , COL_INFO , " , " , " Magic " ) ;
proto_item_set_len ( ti , MAGIC_FRAME_LENGTH ) ;
proto_item_append_text ( ti , " : Magic " ) ;
proto_tree_add_item ( http2_tree , hf_http2_magic , tvb , offset , MAGIC_FRAME_LENGTH , ENC_ASCII | ENC_NA ) ;
2014-05-12 07:00:52 +00:00
2013-11-09 17:46:28 +00:00
return MAGIC_FRAME_LENGTH ;
2013-08-30 11:14:09 +00:00
}
2014-09-19 02:29:29 +00:00
proto_tree_add_item ( http2_tree , hf_http2_length , tvb , offset , 3 , ENC_BIG_ENDIAN ) ;
2014-08-02 07:22:28 +00:00
length = tvb_get_ntoh24 ( tvb , offset ) ;
offset + = 3 ;
2013-08-30 11:14:09 +00:00
2014-12-13 17:52:20 +00:00
proto_tree_add_item ( http2_tree , hf_http2_type , tvb , offset , 1 , ENC_BIG_ENDIAN ) ;
2013-08-30 11:14:09 +00:00
type = tvb_get_guint8 ( tvb , offset ) ;
col_append_sep_fstr ( pinfo - > cinfo , COL_INFO , " , " , " %s " , val_to_str ( type , http2_type_vals , " Unknown type (%d) " ) ) ;
offset + = 1 ;
flags = dissect_http2_header_flags ( tvb , pinfo , http2_tree , offset , type ) ;
offset + = 1 ;
2014-09-19 02:29:29 +00:00
proto_tree_add_item ( http2_tree , hf_http2_r , tvb , offset , 4 , ENC_BIG_ENDIAN ) ;
proto_tree_add_item ( http2_tree , hf_http2_streamid , tvb , offset , 4 , ENC_BIG_ENDIAN ) ;
2013-08-30 11:14:09 +00:00
streamid = tvb_get_ntohl ( tvb , offset ) & MASK_HTTP2_STREAMID ;
proto_item_append_text ( ti , " : %s, Stream ID: %u, Length %u " , val_to_str ( type , http2_type_vals , " Unknown type (%d) " ) , streamid , length ) ;
offset + = 4 ;
2015-01-08 16:35:58 +00:00
/* Collect stats */
http2_stats = wmem_new0 ( wmem_packet_scope ( ) , struct HTTP2Tap ) ;
http2_stats - > type = type ;
2013-08-30 11:14:09 +00:00
switch ( type ) {
case HTTP2_DATA : /* Data (0) */
2014-04-25 14:29:10 +00:00
dissect_http2_data ( tvb , pinfo , http2_tree , offset , flags ) ;
2013-08-30 11:14:09 +00:00
break ;
case HTTP2_HEADERS : /* Headers (1) */
dissect_http2_headers ( tvb , pinfo , http2_tree , offset , flags ) ;
break ;
case HTTP2_PRIORITY : /* Priority (2) */
dissect_http2_priority ( tvb , pinfo , http2_tree , offset , flags ) ;
break ;
case HTTP2_RST_STREAM : /* RST Stream (3) */
dissect_http2_rst_stream ( tvb , pinfo , http2_tree , offset , flags ) ;
break ;
case HTTP2_SETTINGS : /* Settings (4) */
dissect_http2_settings ( tvb , pinfo , http2_tree , offset , flags ) ;
break ;
case HTTP2_PUSH_PROMISE : /* PUSH Promise (5) */
dissect_http2_push_promise ( tvb , pinfo , http2_tree , offset , flags ) ;
break ;
case HTTP2_PING : /* Ping (6) */
dissect_http2_ping ( tvb , pinfo , http2_tree , offset , flags ) ;
break ;
case HTTP2_GOAWAY : /* Goaway (7) */
dissect_http2_goaway ( tvb , pinfo , http2_tree , offset , flags ) ;
break ;
2014-04-25 14:29:10 +00:00
case HTTP2_WINDOW_UPDATE : /* Window Update (8) */
2013-08-30 11:14:09 +00:00
dissect_http2_window_update ( tvb , pinfo , http2_tree , offset , flags ) ;
break ;
2014-04-25 14:29:10 +00:00
case HTTP2_CONTINUATION : /* Continuation (9) */
2013-08-30 11:14:09 +00:00
dissect_http2_continuation ( tvb , pinfo , http2_tree , offset , flags ) ;
break ;
2014-04-25 14:29:10 +00:00
case HTTP2_ALTSVC : /* ALTSVC (10) */
dissect_http2_altsvc ( tvb , pinfo , http2_tree , offset , flags , length ) ;
break ;
case HTTP2_BLOCKED : /* BLOCKED (11) */
/* no payload! */
break ;
2013-08-30 11:14:09 +00:00
default :
proto_tree_add_item ( http2_tree , hf_http2_unknown , tvb , offset , - 1 , ENC_NA ) ;
break ;
}
2015-01-08 16:35:58 +00:00
tap_queue_packet ( http2_tap , pinfo , http2_stats ) ;
2014-05-06 15:54:47 +00:00
return tvb_captured_length ( tvb ) ;
2013-08-30 11:14:09 +00:00
}
2015-01-25 19:30:13 +00:00
static guint get_http2_message_len ( packet_info * pinfo _U_ , tvbuff_t * tvb ,
int offset , void * data _U_ )
2013-08-30 11:14:09 +00:00
{
if ( tvb_memeql ( tvb , offset , kMagicHello , MAGIC_FRAME_LENGTH ) = = 0 ) {
return MAGIC_FRAME_LENGTH ;
}
2014-08-02 07:22:28 +00:00
return ( guint ) tvb_get_ntoh24 ( tvb , offset ) + FRAME_HEADER_LENGTH ;
2013-08-30 11:14:09 +00:00
}
static int
dissect_http2 ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree ,
2013-11-09 17:46:28 +00:00
void * data )
2013-08-30 11:14:09 +00:00
{
proto_item * ti ;
proto_tree * http2_tree ;
/* Check that there's enough data */
2014-05-06 15:54:47 +00:00
if ( tvb_captured_length ( tvb ) < FRAME_HEADER_LENGTH )
2013-08-30 11:14:09 +00:00
return 0 ;
col_set_str ( pinfo - > cinfo , COL_PROTOCOL , " HTTP2 " ) ;
col_clear ( pinfo - > cinfo , COL_INFO ) ;
ti = proto_tree_add_item ( tree , proto_http2 , tvb , 0 , - 1 , ENC_NA ) ;
http2_tree = proto_item_add_subtree ( ti , ett_http2 ) ;
tcp_dissect_pdus ( tvb , pinfo , http2_tree , TRUE , FRAME_HEADER_LENGTH ,
2013-11-09 17:46:28 +00:00
get_http2_message_len , dissect_http2_pdu , data ) ;
2013-08-30 11:14:09 +00:00
2014-05-06 15:54:47 +00:00
return tvb_captured_length ( tvb ) ;
2013-08-30 11:14:09 +00:00
}
2013-11-29 08:02:09 +00:00
static gboolean
dissect_http2_heur ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree , void * data )
{
2015-03-10 11:05:25 +00:00
conversation_t * conversation ;
2015-03-21 16:33:50 +00:00
http2_session_t * session ;
conversation = find_or_create_conversation ( pinfo ) ;
session = ( http2_session_t * ) conversation_get_proto_data ( conversation ,
proto_http2 ) ;
/* A http2 conversation was previously started, assume it is still active */
if ( session ) {
dissect_http2 ( tvb , pinfo , tree , data ) ;
return TRUE ;
}
2013-12-23 09:42:10 +00:00
if ( tvb_memeql ( tvb , 0 , kMagicHello , MAGIC_FRAME_LENGTH ) ! = 0 ) {
2015-08-01 09:38:03 +00:00
/* we couldn't find the Magic Hello (PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n). */
return FALSE ;
2013-12-23 09:42:10 +00:00
}
2013-11-29 08:02:09 +00:00
2015-03-21 16:33:50 +00:00
/* Remember http2 conversation. */
get_http2_session ( pinfo ) ;
2013-11-29 08:02:09 +00:00
dissect_http2 ( tvb , pinfo , tree , data ) ;
return ( TRUE ) ;
}
2016-01-11 20:47:03 +00:00
static gboolean
dissect_http2_heur_ssl ( tvbuff_t * tvb , packet_info * pinfo , proto_tree * tree , void * data )
{
dissector_handle_t * app_handle = ( dissector_handle_t * ) data ;
if ( dissect_http2_heur ( tvb , pinfo , tree , NULL ) ) {
* app_handle = http2_handle ;
return TRUE ;
}
return FALSE ;
}
2013-08-30 11:14:09 +00:00
void
proto_register_http2 ( void )
{
static hf_register_info hf [ ] = {
/* Packet Header */
2016-02-03 06:06:07 +00:00
{ & hf_http2_stream ,
{ " Stream " , " http2.stream " ,
2013-08-30 11:14:09 +00:00
FT_NONE , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
{ & hf_http2_length ,
{ " Length " , " http2.length " ,
2014-08-02 07:22:28 +00:00
FT_UINT24 , BASE_DEC , NULL , 0x0 ,
" The length (24 bits) of the frame payload (The 9 octets of the frame header are not included) " , HFILL }
2013-08-30 11:14:09 +00:00
} ,
{ & hf_http2_type ,
{ " Type " , " http2.type " ,
FT_UINT8 , BASE_DEC , VALS ( http2_type_vals ) , 0x0 ,
" The frame type determines how the remainder of the frame header and payload are interpreted " , HFILL }
} ,
{ & hf_http2_r ,
{ " Reserved " , " http2.r " ,
FT_UINT32 , BASE_HEX , NULL , MASK_HTTP2_RESERVED ,
" The semantics of this bit are undefined and the bit MUST remain unset (0) when sending and MUST be ignored when receiving " , HFILL }
} ,
2014-04-25 14:29:10 +00:00
{ & hf_http2_weight ,
{ " Weight " , " http2.headers.weight " ,
FT_UINT8 , BASE_DEC , NULL , 0x0 ,
" An 8-bit weight for the identified priority " , HFILL }
} ,
2014-05-13 15:49:24 +00:00
{ & hf_http2_weight_real ,
{ " Weight real " , " http2.headers.weight_real " ,
FT_UINT8 , BASE_DEC , NULL , 0x0 ,
" Real Weight value (Add one to value) " , HFILL }
} ,
2013-08-30 11:14:09 +00:00
{ & hf_http2_streamid ,
{ " Stream Identifier " , " http2.streamid " ,
FT_UINT32 , BASE_DEC , NULL , MASK_HTTP2_STREAMID ,
" A 31-bit stream identifier " , HFILL }
} ,
{ & hf_http2_magic ,
{ " Magic " , " http2.magic " ,
FT_STRING , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
{ & hf_http2_unknown ,
{ " Unknown " , " http2.unknown " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
/* Flags */
{ & hf_http2_flags ,
{ " Flags " , " http2.flags " ,
FT_UINT8 , BASE_HEX , NULL , 0x0 ,
" Flags are assigned semantics specific to the indicated frame type " , HFILL }
} ,
{ & hf_http2_flags_end_stream ,
2014-04-25 14:29:10 +00:00
{ " End Stream " , " http2.flags.end_stream " ,
FT_BOOLEAN , 8 , NULL , HTTP2_FLAGS_END_STREAM ,
2013-12-15 19:07:40 +00:00
" Indicates that this frame is the last that the endpoint will send for the identified stream " , HFILL }
2013-08-30 11:14:09 +00:00
} ,
{ & hf_http2_flags_end_headers ,
{ " End Headers " , " http2.flags.eh " ,
2014-04-25 14:29:10 +00:00
FT_BOOLEAN , 8 , NULL , HTTP2_FLAGS_END_HEADERS ,
2013-12-15 19:07:40 +00:00
" Indicates that this frame contains an entire header block and is not followed by any CONTINUATION frames. " , HFILL }
2013-08-30 11:14:09 +00:00
} ,
2014-06-23 14:21:15 +00:00
{ & hf_http2_flags_padded ,
{ " Padded " , " http2.flags.padded " ,
FT_BOOLEAN , 8 , NULL , HTTP2_FLAGS_PADDED ,
" Indicates that the Pad Length field is present " , HFILL }
2014-04-25 14:29:10 +00:00
} ,
2013-08-30 11:14:09 +00:00
{ & hf_http2_flags_priority ,
2014-04-25 14:29:10 +00:00
{ " Priority " , " http2.flags.priority " ,
FT_BOOLEAN , 8 , NULL , HTTP2_FLAGS_PRIORITY ,
" Indicates that the Exclusive Flag (E), Stream Dependency, and Weight fields are present " , HFILL }
2013-08-30 11:14:09 +00:00
} ,
2014-04-25 14:29:10 +00:00
2013-12-15 19:07:40 +00:00
{ & hf_http2_flags_ping_ack ,
{ " ACK " , " http2.flags.ack.ping " ,
FT_BOOLEAN , 8 , NULL , HTTP2_FLAGS_ACK ,
2013-08-30 11:14:09 +00:00
" Set indicates that this PING frame is a PING response " , HFILL }
} ,
2014-05-12 07:00:52 +00:00
{ & hf_http2_flags_unused ,
{ " Unused " , " http2.flags.unused " ,
2014-08-02 07:22:28 +00:00
FT_UINT8 , BASE_HEX , NULL , HTTP2_FLAGS_UNUSED ,
2014-05-12 07:00:52 +00:00
" Must be zero " , HFILL }
} ,
2014-06-23 14:21:15 +00:00
{ & hf_http2_flags_unused_settings ,
{ " Unused " , " http2.flags.unused_settings " ,
2014-08-02 07:22:28 +00:00
FT_UINT8 , BASE_HEX , NULL , HTTP2_FLAGS_UNUSED_SETTINGS ,
2014-05-12 07:00:52 +00:00
" Must be zero " , HFILL }
} ,
2014-06-23 14:21:15 +00:00
{ & hf_http2_flags_unused_ping ,
{ " Unused " , " http2.flags.unused_ping " ,
2014-08-02 07:22:28 +00:00
FT_UINT8 , BASE_HEX , NULL , HTTP2_FLAGS_UNUSED_PING ,
2014-06-23 14:21:15 +00:00
" Must be zero " , HFILL }
} ,
{ & hf_http2_flags_unused_continuation ,
{ " Unused " , " http2.flags.unused_continuation " ,
2014-08-02 07:22:28 +00:00
FT_UINT8 , BASE_HEX , NULL , HTTP2_FLAGS_UNUSED_CONTINUATION ,
2014-06-23 14:21:15 +00:00
" Must be zero " , HFILL }
} ,
{ & hf_http2_flags_unused_push_promise ,
{ " Unused " , " http2.flags.unused_push_promise " ,
2014-08-02 07:22:28 +00:00
FT_UINT8 , BASE_HEX , NULL , HTTP2_FLAGS_UNUSED_PUSH_PROMISE ,
2014-05-12 07:00:52 +00:00
" Must be zero " , HFILL }
} ,
{ & hf_http2_flags_unused_data ,
{ " Unused " , " http2.flags.unused_data " ,
2014-08-02 07:22:28 +00:00
FT_UINT8 , BASE_HEX , NULL , HTTP2_FLAGS_UNUSED_DATA ,
2014-05-12 07:00:52 +00:00
" Must be zero " , HFILL }
} ,
2014-06-23 14:21:15 +00:00
{ & hf_http2_flags_unused_headers ,
{ " Unused " , " http2.flags.unused_headers " ,
2014-08-02 07:22:28 +00:00
FT_UINT8 , BASE_HEX , NULL , HTTP2_FLAGS_UNUSED_HEADERS ,
2014-05-12 07:00:52 +00:00
" Must be zero " , HFILL }
} ,
2013-12-15 19:07:40 +00:00
{ & hf_http2_flags_settings_ack ,
{ " ACK " , " http2.flags.ack.settings " ,
FT_BOOLEAN , 8 , NULL , HTTP2_FLAGS_ACK ,
" Indicates that this frame acknowledges receipt and application of the peer's SETTINGS frame " , HFILL }
} ,
2014-06-23 14:21:15 +00:00
{ & hf_http2_padding ,
{ " Pad Length " , " http2.padding " ,
2014-04-25 14:29:10 +00:00
FT_UINT8 , BASE_HEX , NULL , 0x0 ,
2014-06-23 14:21:15 +00:00
" Padding size " , HFILL }
2013-08-30 11:14:09 +00:00
} ,
2014-05-12 07:00:52 +00:00
{ & hf_http2_pad_length ,
{ " Pad Length " , " http2.pad_length " ,
FT_UINT16 , BASE_DEC , NULL , 0x0 ,
NULL , HFILL }
} ,
2014-04-25 14:29:10 +00:00
{ & hf_http2_excl_dependency ,
{ " Exclusive " , " http2.exclusive " ,
2014-05-13 15:49:24 +00:00
FT_BOOLEAN , 32 , NULL , 0x80000000 ,
2014-04-25 14:29:10 +00:00
" A single bit flag indicates that the stream dependency is exclusive " , HFILL }
2013-08-30 11:14:09 +00:00
} ,
2014-04-25 14:29:10 +00:00
{ & hf_http2_stream_dependency ,
{ " Stream Dependency " , " http2.stream_dependency " ,
2014-05-13 15:49:24 +00:00
FT_UINT32 , BASE_DEC , NULL , 0x7FFFFFFF ,
2014-04-25 14:29:10 +00:00
" An identifier for the stream that this stream depends on " , HFILL }
2013-08-30 11:14:09 +00:00
} ,
2014-04-25 14:29:10 +00:00
/* Data */
{ & hf_http2_data_data ,
{ " Data " , " http2.data.data " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
" Application data " , HFILL }
2013-08-30 11:14:09 +00:00
} ,
2014-04-25 14:29:10 +00:00
{ & hf_http2_data_padding ,
{ " Padding " , " http2.data.padding " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
" Padding octets " , HFILL }
} ,
/* Headers */
{ & hf_http2_headers ,
{ " Header Block Fragment " , " http2.headers " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
" A header block fragment " , HFILL }
} ,
{ & hf_http2_headers_padding ,
{ " Padding " , " http2.headers.padding " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
" Padding octets " , HFILL }
2013-08-30 11:14:09 +00:00
} ,
2014-05-06 15:54:47 +00:00
{ & hf_http2_header ,
{ " Header " , " http2.header " ,
FT_NONE , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
{ & hf_http2_header_length ,
{ " Header Length " , " http2.header.length " ,
FT_UINT32 , BASE_DEC , NULL , 0x0 ,
NULL , HFILL }
} ,
2016-02-05 14:41:57 +00:00
{ & hf_http2_header_count ,
{ " Header Count " , " http2.header.count " ,
FT_UINT32 , BASE_DEC , NULL , 0x0 ,
NULL , HFILL }
} ,
2014-05-06 15:54:47 +00:00
{ & hf_http2_header_name_length ,
{ " Name Length " , " http2.header.name.length " ,
FT_UINT32 , BASE_DEC , NULL , 0x0 ,
NULL , HFILL }
} ,
{ & hf_http2_header_name ,
{ " Name " , " http2.header.name " ,
FT_STRING , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
{ & hf_http2_header_value_length ,
{ " Value Length " , " http2.header.value.length " ,
FT_UINT32 , BASE_DEC , NULL , 0x0 ,
NULL , HFILL }
} ,
{ & hf_http2_header_value ,
{ " Value " , " http2.header.value " ,
FT_STRING , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
2014-08-04 12:06:14 +00:00
{ & hf_http2_header_repr ,
{ " Representation " , " http2.header.repr " ,
FT_STRING , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
{ & hf_http2_header_index ,
{ " Index " , " http2.header.index " ,
FT_UINT32 , BASE_DEC , NULL , 0x0 ,
NULL , HFILL }
} ,
{ & hf_http2_header_table_size_update ,
{ " Header table size update " , " http2.header_table_size_update " ,
FT_NONE , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
{ & hf_http2_header_table_size ,
{ " Header table size " , " http2.header_table_size_update.header_table_size " ,
FT_UINT32 , BASE_DEC , NULL , 0x0 ,
NULL , HFILL }
} ,
2013-08-30 11:14:09 +00:00
/* RST Stream */
{ & hf_http2_rst_stream_error ,
{ " Error " , " http2.rst_stream.error " ,
FT_UINT32 , BASE_DEC , VALS ( http2_error_codes_vals ) , 0x0 ,
" The error code indicates why the stream is being terminated " , HFILL }
} ,
/* Settings */
{ & hf_http2_settings ,
{ " Settings " , " http2.settings " ,
FT_NONE , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
{ & hf_http2_settings_identifier ,
{ " Settings Identifier " , " http2.settings.id " ,
2014-12-13 17:52:20 +00:00
FT_UINT16 , BASE_DEC , VALS ( http2_settings_vals ) , 0x0 ,
2013-08-30 11:14:09 +00:00
NULL , HFILL }
} ,
2013-12-15 19:07:40 +00:00
{ & hf_http2_settings_header_table_size ,
{ " Header table size " , " http2.settings.header_table_size " ,
FT_UINT32 , BASE_DEC , NULL , 0x0 ,
2014-04-25 14:29:10 +00:00
" Allows the sender to inform the remote endpoint of the size of the header compression table used to decode header blocks. The initial value is 4096 bytes " , HFILL }
2013-12-15 19:07:40 +00:00
} ,
{ & hf_http2_settings_enable_push ,
{ " Enable PUSH " , " http2.settings.enable_push " ,
FT_UINT32 , BASE_DEC , NULL , 0x0 ,
" The initial value is 1, which indicates that push is permitted " , HFILL }
} ,
2013-08-30 11:14:09 +00:00
{ & hf_http2_settings_max_concurrent_streams ,
{ " Max concurrent streams " , " http2.settings.max_concurrent_streams " ,
FT_UINT32 , BASE_DEC , NULL , 0x0 ,
" Indicates the maximum number of concurrent streams that the sender will allow " , HFILL }
} ,
{ & hf_http2_settings_initial_window_size ,
{ " Initial Windows Size " , " http2.settings.initial_window_size " ,
FT_UINT32 , BASE_DEC , NULL , 0x0 ,
" Indicates the sender's initial window size (in bytes) for stream level flow control " , HFILL }
} ,
2014-08-02 07:22:28 +00:00
{ & hf_http2_settings_max_frame_size ,
{ " Max frame size " , " http2.settings.max_frame_size " ,
FT_UINT32 , BASE_DEC , NULL , 0x0 ,
" Indicates the size of the largest frame payload that the sender will allow " , HFILL }
} ,
{ & hf_http2_settings_max_header_list_size ,
{ " Max header list size " , " http2.settings.max_header_list_size " ,
FT_UINT32 , BASE_DEC , NULL , 0x0 ,
" This advisory setting informs a peer of the maximum size of header list that the sender is prepared to accept. " , HFILL }
} ,
2013-08-30 11:14:09 +00:00
{ & hf_http2_settings_unknown ,
{ " Unknown Settings " , " http2.settings.unknown " ,
FT_UINT32 , BASE_DEC , NULL , 0x0 ,
NULL , HFILL }
} ,
/* Push Promise */
{ & hf_http2_push_promise_r ,
{ " Reserved " , " http2.push_promise.r " ,
FT_UINT32 , BASE_HEX , NULL , MASK_HTTP2_RESERVED ,
" Must be zero " , HFILL }
} ,
2014-04-25 14:29:10 +00:00
2013-08-30 11:14:09 +00:00
{ & hf_http2_push_promise_promised_stream_id ,
{ " Promised-Stream-ID " , " http2.push_promise.promised_stream_id " ,
FT_UINT32 , BASE_DEC , NULL , MASK_HTTP2_PRIORITY ,
" Identifies the stream the endpoint intends to start sending frames for " , HFILL }
} ,
{ & hf_http2_push_promise_header ,
{ " Header " , " http2.push_promise.header " ,
FT_STRING , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
2014-04-25 14:29:10 +00:00
{ & hf_http2_push_promise_padding ,
{ " Padding " , " http2.push_promise.padding " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
" Padding octets " , HFILL }
} ,
2013-08-30 11:14:09 +00:00
/* Ping / Pong */
{ & hf_http2_ping ,
{ " Ping " , " http2.ping " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
{ & hf_http2_pong ,
{ " Pong " , " http2.pong " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
/* Goaway */
{ & hf_http2_goaway_r ,
{ " Reserved " , " http2.goway.r " ,
FT_UINT32 , BASE_HEX , NULL , MASK_HTTP2_RESERVED ,
" Must be zero " , HFILL }
} ,
{ & hf_http2_goaway_last_stream_id ,
{ " Promised-Stream-ID " , " http2.goaway.last_stream_id " ,
FT_UINT32 , BASE_DEC , NULL , MASK_HTTP2_PRIORITY ,
" Contains the highest numbered stream identifier for which the sender of the GOAWAY frame has received frames on and might have taken some action on " , HFILL }
} ,
{ & hf_http2_goaway_error ,
{ " Error " , " http2.goaway.error " ,
FT_UINT32 , BASE_DEC , VALS ( http2_error_codes_vals ) , 0x0 ,
" The error code indicates the reason for closing the connection " , HFILL }
} ,
{ & hf_http2_goaway_addata ,
{ " Additional Debug Data " , " http2.goaway.addata " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
NULL , HFILL }
} ,
/* Window Update */
{ & hf_http2_window_update_r ,
{ " Reserved " , " http2.window_update.r " ,
FT_UINT32 , BASE_HEX , NULL , MASK_HTTP2_RESERVED ,
" Must be zero " , HFILL }
} ,
{ & hf_http2_window_update_window_size_increment ,
{ " Window Size Increment " , " http2.window_update.window_size_increment " ,
FT_UINT32 , BASE_DEC , NULL , MASK_HTTP2_PRIORITY ,
" Indicating the number of bytes that the sender can transmit in addition to the existing flow control window " , HFILL }
} ,
/* Continuation */
{ & hf_http2_continuation_header ,
{ " Continuation Header " , " http2.continuation.header " ,
FT_STRING , BASE_NONE , NULL , 0x0 ,
" Contains a header block fragment " , HFILL }
} ,
2014-05-12 07:00:52 +00:00
{ & hf_http2_continuation_padding ,
{ " Padding " , " http2.continuation.padding " ,
FT_BYTES , BASE_NONE , NULL , 0x0 ,
" Padding octets " , HFILL }
} ,
2013-08-30 11:14:09 +00:00
2014-04-25 14:29:10 +00:00
/* Altsvc */
{ & hf_http2_altsvc_maxage ,
{ " Max-Age " , " http2.altsvc.max-age " ,
FT_UINT32 , BASE_DEC , NULL , 0x0 ,
" An unsigned, 32-bit integer indicating the freshness lifetime of the alternative service association " , HFILL }
} ,
{ & hf_http2_altsvc_port ,
{ " Port " , " http2.altsvc.port " ,
FT_UINT16 , BASE_DEC , NULL , 0x0 ,
" An unsigned, 16-bit integer indicating the port that the alternative service is available upon " , HFILL }
} ,
{ & hf_http2_altsvc_proto_len ,
{ " Proto-Len " , " http2.altsvc.proto_len " ,
FT_UINT8 , BASE_DEC , NULL , 0x0 ,
" An unsigned, 8-bit integer indicating the length, in octets, of the PROTOCOL-ID field " , HFILL }
} ,
{ & hf_http2_altsvc_protocol ,
{ " Protocol-ID " , " http2.altsvc.protocol " ,
FT_STRING , BASE_NONE , NULL , 0x0 ,
" A sequence of bytes containing the ALPN protocol identifier " , HFILL }
} ,
{ & hf_http2_altsvc_host_len ,
{ " Host-Len " , " http2.altsvc.host_len " ,
FT_UINT8 , BASE_DEC , NULL , 0x0 ,
" An unsigned, 8-bit integer indicating the length, in octets, of the Host field " , HFILL }
} ,
{ & hf_http2_altsvc_host ,
{ " Host " , " http2.altsvc.host " ,
FT_STRING , BASE_NONE , NULL , 0x0 ,
" ASCII string indicating the host that the alternative service is available upon " , HFILL }
} ,
{ & hf_http2_altsvc_origin ,
{ " Origin " , " http2.altsvc.origin " ,
FT_STRING , BASE_NONE , NULL , 0x0 ,
" A sequence of characters containing ASCII serialisation of an "
" origin that the alternate service is applicable to. " , HFILL }
} ,
2013-08-30 11:14:09 +00:00
2014-04-25 14:29:10 +00:00
} ;
2013-08-30 11:14:09 +00:00
static gint * ett [ ] = {
& ett_http2 ,
& ett_http2_header ,
2014-05-06 15:54:47 +00:00
& ett_http2_headers ,
2013-08-30 11:14:09 +00:00
& ett_http2_flags ,
& ett_http2_settings
} ;
2016-02-05 14:41:57 +00:00
/* Setup protocol expert items */
/*
* Excessive header size or lines could mean a decompression bomb . Should
* these be PI_SECURITY instead ?
*/
static ei_register_info ei [ ] = {
{ & ei_http2_header_size ,
{ " http2.header_size_exceeded " , PI_UNDECODED , PI_ERROR ,
" Decompression stopped. " , EXPFILL }
} ,
{ & ei_http2_header_lines ,
{ " http2.header_lines_exceeded " , PI_UNDECODED , PI_ERROR ,
" Decompression stopped after " G_STRINGIFY ( MAX_HTTP2_HEADER_LINES ) " header lines. " , EXPFILL }
}
} ;
2014-08-02 10:00:59 +00:00
module_t * http2_module ;
2016-02-05 14:41:57 +00:00
expert_module_t * expert_http2 ;
2014-08-02 10:00:59 +00:00
2013-08-30 11:14:09 +00:00
proto_http2 = proto_register_protocol ( " HyperText Transfer Protocol 2 " , " HTTP2 " , " http2 " ) ;
proto_register_field_array ( proto_http2 , hf , array_length ( hf ) ) ;
proto_register_subtree_array ( ett , array_length ( ett ) ) ;
2014-08-02 10:00:59 +00:00
http2_module = prefs_register_protocol ( proto_http2 , NULL ) ;
2016-02-05 14:41:57 +00:00
expert_http2 = expert_register_protocol ( proto_http2 ) ;
expert_register_field_array ( expert_http2 , ei , array_length ( ei ) ) ;
2015-07-13 00:40:31 +00:00
prefs_register_obsolete_preference ( http2_module , " heuristic_http2 " ) ;
2014-08-02 10:00:59 +00:00
2016-01-11 20:47:03 +00:00
http2_handle = register_dissector ( " http2 " , dissect_http2 , proto_http2 ) ;
2015-01-08 16:35:58 +00:00
http2_tap = register_tap ( " http2 " ) ;
}
static void http2_stats_tree_init ( stats_tree * st )
{
st_node_http2 = stats_tree_create_node ( st , st_str_http2 , 0 , TRUE ) ;
st_node_http2_type = stats_tree_create_pivot ( st , st_str_http2_type , st_node_http2 ) ;
}
static int http2_stats_tree_packet ( stats_tree * st , packet_info * pinfo _U_ , epan_dissect_t * edt _U_ , const void * p )
{
2015-12-26 14:04:03 +00:00
const struct HTTP2Tap * pi = ( const struct HTTP2Tap * ) p ;
2015-01-08 16:35:58 +00:00
tick_stat_node ( st , st_str_http2 , 0 , FALSE ) ;
stats_tree_tick_pivot ( st , st_node_http2_type ,
val_to_str ( pi - > type , http2_type_vals , " Unknown type (%d) " ) ) ;
return 1 ;
2013-08-30 11:14:09 +00:00
}
void
proto_reg_handoff_http2 ( void )
{
data_handle = find_dissector ( " data " ) ;
2013-11-29 08:02:09 +00:00
2014-06-20 16:43:28 +00:00
dissector_add_for_decode_as ( " tcp.port " , http2_handle ) ;
2013-12-15 19:07:40 +00:00
2016-01-11 20:47:03 +00:00
heur_dissector_add ( " ssl " , dissect_http2_heur_ssl , " HTTP2 over SSL " , " http2_ssl " , proto_http2 , HEURISTIC_ENABLE ) ;
2015-07-13 00:40:31 +00:00
heur_dissector_add ( " http " , dissect_http2_heur , " HTTP2 over TCP " , " http2_tcp " , proto_http2 , HEURISTIC_ENABLE ) ;
2015-01-08 16:35:58 +00:00
stats_tree_register ( " http2 " , " http2 " , " HTTP2 " , 0 , http2_stats_tree_packet , http2_stats_tree_init , NULL ) ;
2013-08-30 11:14:09 +00:00
}
/*
* Editor modelines - http : //www.wireshark.org/tools/modelines.html
*
* Local variables :
* c - basic - offset : 4
* tab - width : 8
* indent - tabs - mode : nil
* End :
*
* vi : set shiftwidth = 4 tabstop = 8 expandtab :
* : indentSize = 4 : tabSize = 8 : noTabs = true :
*/