Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-spdy.c
blob0ba9025988b0648b9839bacf7c73a1fb7625a695
1 /* packet-spdy.c
2 * Routines for SPDY packet disassembly
3 * For now, the protocol spec can be found at
4 * http://dev.chromium.org/spdy/spdy-protocol
6 * Copyright 2010, Google Inc.
7 * Hasan Khalil <hkhalil@google.com>
8 * Chris Bentzel <cbentzel@google.com>
9 * Eric Shienbrood <ers@google.com>
11 * Copyright 2013-2014
12 * Alexis La Goutte <alexis.lagoutte@gmail.com>
14 * Wireshark - Network traffic analyzer
15 * By Gerald Combs <gerald@wireshark.org>
16 * Copyright 1998 Gerald Combs
18 * Originally based on packet-http.c
20 * SPDX-License-Identifier: GPL-2.0-or-later
23 #include "config.h"
25 #include <epan/packet.h>
26 #include <epan/prefs.h>
27 #include <epan/expert.h>
28 #include <epan/tap.h>
29 #include <epan/tfs.h>
30 #include <wsutil/array.h>
31 #include "packet-tcp.h"
32 #include "packet-tls.h"
33 #include "packet-media-type.h"
35 #if defined(HAVE_ZLIB) && !defined(HAVE_ZLIBNG)
36 #define ZLIB_CONST
37 #define ZLIB_PREFIX(x) x
38 #include <zlib.h>
39 typedef z_stream zlib_stream;
40 #endif /* HAVE_ZLIB */
42 #ifdef HAVE_ZLIBNG
43 #define ZLIB_PREFIX(x) zng_ ## x
44 #include <zlib-ng.h>
45 typedef zng_stream zlib_stream;
46 #endif /* HAVE_ZLIBNG */
48 void proto_register_spdy(void);
49 void proto_reg_handoff_spdy(void);
51 #define MIN_SPDY_VERSION 3
53 #define SPDY_STREAM_ID_MASK 0x7FFFFFFF
56 * Conversation data - used for assembling multi-data-frame
57 * entities and for decompressing request & reply header blocks.
59 typedef struct _spdy_conv_t {
60 #if defined (HAVE_ZLIB) || defined (HAVE_ZLIBNG)
61 #ifdef HAVE_ZLIBNG
62 zng_streamp rqst_decompressor;
63 zng_streamp rply_decompressor;
64 uint32_t dictionary_id;
65 #else
66 z_streamp rqst_decompressor;
67 z_streamp rply_decompressor;
68 uLong dictionary_id;
69 #endif
70 #endif
71 wmem_tree_t *streams;
72 } spdy_conv_t;
75 /* The types of SPDY frames */
76 #define SPDY_DATA 0
77 #define SPDY_SYN_STREAM 1
78 #define SPDY_SYN_REPLY 2
79 #define SPDY_RST_STREAM 3
80 #define SPDY_SETTINGS 4
81 #define SPDY_PING 6
82 #define SPDY_GOAWAY 7
83 #define SPDY_HEADERS 8
84 #define SPDY_WINDOW_UPDATE 9
85 #define SPDY_CREDENTIAL 10
86 #define SPDY_INVALID 11
88 #define SPDY_FLAG_FIN 0x01
89 #define SPDY_FLAG_UNIDIRECTIONAL 0x02
90 #define SPDY_FLAG_SETTINGS_CLEAR_SETTINGS 0x01
92 /* Flags for each setting in a SETTINGS frame. */
93 #define SPDY_FLAG_SETTINGS_PERSIST_VALUE 0x01
94 #define SPDY_FLAG_SETTINGS_PERSISTED 0x02
96 #define TCP_PORT_SPDY 6121
98 static const value_string frame_type_names[] = {
99 { SPDY_DATA, "DATA" },
100 { SPDY_SYN_STREAM, "SYN_STREAM" },
101 { SPDY_SYN_REPLY, "SYN_REPLY" },
102 { SPDY_RST_STREAM, "RST_STREAM" },
103 { SPDY_SETTINGS, "SETTINGS" },
104 { SPDY_PING, "PING" },
105 { SPDY_GOAWAY, "GOAWAY" },
106 { SPDY_HEADERS, "HEADERS" },
107 { SPDY_WINDOW_UPDATE, "WINDOW_UPDATE" },
108 { SPDY_CREDENTIAL, "CREDENTIAL" },
109 { SPDY_INVALID, "INVALID" },
110 { 0, NULL }
113 static const value_string rst_stream_status_names[] = {
114 { 1, "PROTOCOL_ERROR" },
115 { 2, "INVALID_STREAM" },
116 { 3, "REFUSED_STREAM" },
117 { 4, "UNSUPPORTED_VERSION" },
118 { 5, "CANCEL" },
119 { 6, "INTERNAL_ERROR" },
120 { 7, "FLOW_CONTROL_ERROR" },
121 { 8, "STREAM_IN_USE" },
122 { 9, "STREAM_ALREADY_CLOSED" },
123 { 10, "INVALID_CREDENTIALS" },
124 { 11, "FRAME_TOO_LARGE" },
125 { 12, "INVALID" },
126 { 0, NULL }
129 static const value_string setting_id_names[] = {
130 { 1, "UPLOAD_BANDWIDTH" },
131 { 2, "DOWNLOAD_BANDWIDTH" },
132 { 3, "ROUND_TRIP_TIME" },
133 { 4, "MAX_CONCURRENT_STREAMS" },
134 { 5, "CURRENT_CWND" },
135 { 6, "DOWNLOAD_RETRANS_RATE" },
136 { 7, "INITIAL_WINDOW_SIZE" },
137 { 0, NULL }
140 static const value_string goaway_status_names[] = {
141 { 0, "OK" },
142 { 1, "PROTOCOL_ERROR" },
143 { 11, "INTERNAL_ERROR" },
144 { 0, NULL }
148 * This structure will be tied to each SPDY frame and is used as an argument for
149 * dissect_spdy_*_payload() functions.
151 typedef struct _spdy_control_frame_info_t {
152 bool control_bit;
153 uint16_t version;
154 uint16_t type;
155 uint8_t flags;
156 uint32_t length; /* Actually only 24 bits. */
157 } spdy_control_frame_info_t;
160 * This structure will be tied to each SPDY header frame.
161 * Only applies to frames containing headers: SYN_STREAM, SYN_REPLY, HEADERS
162 * Note that there may be multiple SPDY frames in one packet.
164 typedef struct _spdy_header_info_t {
165 uint32_t stream_id;
166 uint8_t *header_block;
167 unsigned header_block_len;
168 uint16_t frame_type;
169 } spdy_header_info_t;
171 static wmem_list_t *header_info_list;
174 * This structures keeps track of all the data frames
175 * associated with a stream, so that they can be
176 * reassembled into a single chunk.
178 typedef struct _spdy_data_frame_t {
179 uint8_t *data;
180 uint32_t length;
181 uint32_t framenum;
182 } spdy_data_frame_t;
184 typedef struct _spdy_stream_info_t {
185 media_container_type_t container_type;
186 char *content_type;
187 char *content_type_parameters;
188 char *content_encoding;
189 wmem_list_t *data_frames;
190 tvbuff_t *assembled_data;
191 unsigned num_data_frames;
192 } spdy_stream_info_t;
194 /* Handles for metadata population. */
196 static int spdy_tap;
197 static int spdy_eo_tap;
199 static int proto_spdy;
200 static int hf_spdy_data;
201 static int hf_spdy_control_bit;
202 static int hf_spdy_version;
203 static int hf_spdy_type;
204 static int hf_spdy_flags;
205 static int hf_spdy_flags_fin;
206 static int hf_spdy_flags_unidirectional;
207 static int hf_spdy_flags_clear_settings;
208 static int hf_spdy_flags_persist_value;
209 static int hf_spdy_flags_persisted;
210 static int hf_spdy_length;
211 static int hf_spdy_header_block;
212 static int hf_spdy_header;
213 static int hf_spdy_header_name;
214 static int hf_spdy_header_value;
215 static int hf_spdy_streamid;
216 static int hf_spdy_associated_streamid;
217 static int hf_spdy_priority;
218 static int hf_spdy_unused;
219 static int hf_spdy_slot;
220 static int hf_spdy_num_headers;
221 static int hf_spdy_rst_stream_status;
222 static int hf_spdy_num_settings;
223 static int hf_spdy_setting;
224 static int hf_spdy_setting_id;
225 static int hf_spdy_setting_value;
226 static int hf_spdy_ping_id;
227 static int hf_spdy_goaway_last_good_stream_id;
228 static int hf_spdy_goaway_status;
229 static int hf_spdy_window_update_delta;
231 static int ett_spdy;
232 static int ett_spdy_flags;
233 static int ett_spdy_header_block;
234 static int ett_spdy_header;
235 static int ett_spdy_setting;
237 static int ett_spdy_encoded_entity;
239 static expert_field ei_spdy_inflation_failed;
240 static expert_field ei_spdy_mal_frame_data;
241 static expert_field ei_spdy_mal_setting_frame;
242 static expert_field ei_spdy_invalid_rst_stream;
243 static expert_field ei_spdy_invalid_go_away;
244 static expert_field ei_spdy_invalid_frame_type;
245 static expert_field ei_spdy_reassembly_info;
247 static dissector_handle_t media_handle;
248 static dissector_handle_t spdy_handle;
249 static dissector_table_t media_type_subdissector_table;
250 static dissector_table_t port_subdissector_table;
252 static bool spdy_assemble_entity_bodies = true;
255 * Decompression of zlib encoded entities.
257 #if defined (HAVE_ZLIB) || defined (HAVE_ZLIBNG)
258 static bool spdy_decompress_body = true;
259 static bool spdy_decompress_headers = true;
260 #else
261 static bool spdy_decompress_body;
262 static bool spdy_decompress_headers;
263 #endif
265 #if defined (HAVE_ZLIB) || defined (HAVE_ZLIBNG)
266 static const char spdy_dictionary[] = {
267 0x00, 0x00, 0x00, 0x07, 0x6f, 0x70, 0x74, 0x69, /* - - - - o p t i */
268 0x6f, 0x6e, 0x73, 0x00, 0x00, 0x00, 0x04, 0x68, /* o n s - - - - h */
269 0x65, 0x61, 0x64, 0x00, 0x00, 0x00, 0x04, 0x70, /* e a d - - - - p */
270 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x03, 0x70, /* o s t - - - - p */
271 0x75, 0x74, 0x00, 0x00, 0x00, 0x06, 0x64, 0x65, /* u t - - - - d e */
272 0x6c, 0x65, 0x74, 0x65, 0x00, 0x00, 0x00, 0x05, /* l e t e - - - - */
273 0x74, 0x72, 0x61, 0x63, 0x65, 0x00, 0x00, 0x00, /* t r a c e - - - */
274 0x06, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x00, /* - a c c e p t - */
275 0x00, 0x00, 0x0e, 0x61, 0x63, 0x63, 0x65, 0x70, /* - - - a c c e p */
276 0x74, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, /* t - c h a r s e */
277 0x74, 0x00, 0x00, 0x00, 0x0f, 0x61, 0x63, 0x63, /* t - - - - a c c */
278 0x65, 0x70, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, /* e p t - e n c o */
279 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x0f, /* d i n g - - - - */
280 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2d, 0x6c, /* a c c e p t - l */
281 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x00, /* a n g u a g e - */
282 0x00, 0x00, 0x0d, 0x61, 0x63, 0x63, 0x65, 0x70, /* - - - a c c e p */
283 0x74, 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, /* t - r a n g e s */
284 0x00, 0x00, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00, /* - - - - a g e - */
285 0x00, 0x00, 0x05, 0x61, 0x6c, 0x6c, 0x6f, 0x77, /* - - - a l l o w */
286 0x00, 0x00, 0x00, 0x0d, 0x61, 0x75, 0x74, 0x68, /* - - - - a u t h */
287 0x6f, 0x72, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, /* o r i z a t i o */
288 0x6e, 0x00, 0x00, 0x00, 0x0d, 0x63, 0x61, 0x63, /* n - - - - c a c */
289 0x68, 0x65, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, /* h e - c o n t r */
290 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x0a, 0x63, 0x6f, /* o l - - - - c o */
291 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, /* n n e c t i o n */
292 0x00, 0x00, 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, /* - - - - c o n t */
293 0x65, 0x6e, 0x74, 0x2d, 0x62, 0x61, 0x73, 0x65, /* e n t - b a s e */
294 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, 0x6e, 0x74, /* - - - - c o n t */
295 0x65, 0x6e, 0x74, 0x2d, 0x65, 0x6e, 0x63, 0x6f, /* e n t - e n c o */
296 0x64, 0x69, 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, /* d i n g - - - - */
297 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, /* c o n t e n t - */
298 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, /* l a n g u a g e */
299 0x00, 0x00, 0x00, 0x0e, 0x63, 0x6f, 0x6e, 0x74, /* - - - - c o n t */
300 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x65, 0x6e, 0x67, /* e n t - l e n g */
301 0x74, 0x68, 0x00, 0x00, 0x00, 0x10, 0x63, 0x6f, /* t h - - - - c o */
302 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x6c, 0x6f, /* n t e n t - l o */
303 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, /* c a t i o n - - */
304 0x00, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, /* - - c o n t e n */
305 0x74, 0x2d, 0x6d, 0x64, 0x35, 0x00, 0x00, 0x00, /* t - m d 5 - - - */
306 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, /* - c o n t e n t */
307 0x2d, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, /* - r a n g e - - */
308 0x00, 0x0c, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, /* - - c o n t e n */
309 0x74, 0x2d, 0x74, 0x79, 0x70, 0x65, 0x00, 0x00, /* t - t y p e - - */
310 0x00, 0x04, 0x64, 0x61, 0x74, 0x65, 0x00, 0x00, /* - - d a t e - - */
311 0x00, 0x04, 0x65, 0x74, 0x61, 0x67, 0x00, 0x00, /* - - e t a g - - */
312 0x00, 0x06, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, /* - - e x p e c t */
313 0x00, 0x00, 0x00, 0x07, 0x65, 0x78, 0x70, 0x69, /* - - - - e x p i */
314 0x72, 0x65, 0x73, 0x00, 0x00, 0x00, 0x04, 0x66, /* r e s - - - - f */
315 0x72, 0x6f, 0x6d, 0x00, 0x00, 0x00, 0x04, 0x68, /* r o m - - - - h */
316 0x6f, 0x73, 0x74, 0x00, 0x00, 0x00, 0x08, 0x69, /* o s t - - - - i */
317 0x66, 0x2d, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, /* f - m a t c h - */
318 0x00, 0x00, 0x11, 0x69, 0x66, 0x2d, 0x6d, 0x6f, /* - - - i f - m o */
319 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x2d, 0x73, /* d i f i e d - s */
320 0x69, 0x6e, 0x63, 0x65, 0x00, 0x00, 0x00, 0x0d, /* i n c e - - - - */
321 0x69, 0x66, 0x2d, 0x6e, 0x6f, 0x6e, 0x65, 0x2d, /* i f - n o n e - */
322 0x6d, 0x61, 0x74, 0x63, 0x68, 0x00, 0x00, 0x00, /* m a t c h - - - */
323 0x08, 0x69, 0x66, 0x2d, 0x72, 0x61, 0x6e, 0x67, /* - i f - r a n g */
324 0x65, 0x00, 0x00, 0x00, 0x13, 0x69, 0x66, 0x2d, /* e - - - - i f - */
325 0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, /* u n m o d i f i */
326 0x65, 0x64, 0x2d, 0x73, 0x69, 0x6e, 0x63, 0x65, /* e d - s i n c e */
327 0x00, 0x00, 0x00, 0x0d, 0x6c, 0x61, 0x73, 0x74, /* - - - - l a s t */
328 0x2d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, /* - m o d i f i e */
329 0x64, 0x00, 0x00, 0x00, 0x08, 0x6c, 0x6f, 0x63, /* d - - - - l o c */
330 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, /* a t i o n - - - */
331 0x0c, 0x6d, 0x61, 0x78, 0x2d, 0x66, 0x6f, 0x72, /* - m a x - f o r */
332 0x77, 0x61, 0x72, 0x64, 0x73, 0x00, 0x00, 0x00, /* w a r d s - - - */
333 0x06, 0x70, 0x72, 0x61, 0x67, 0x6d, 0x61, 0x00, /* - p r a g m a - */
334 0x00, 0x00, 0x12, 0x70, 0x72, 0x6f, 0x78, 0x79, /* - - - p r o x y */
335 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, /* - a u t h e n t */
336 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, 0x00, /* i c a t e - - - */
337 0x13, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2d, 0x61, /* - p r o x y - a */
338 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x7a, 0x61, /* u t h o r i z a */
339 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x05, /* t i o n - - - - */
340 0x72, 0x61, 0x6e, 0x67, 0x65, 0x00, 0x00, 0x00, /* r a n g e - - - */
341 0x07, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x72, /* - r e f e r e r */
342 0x00, 0x00, 0x00, 0x0b, 0x72, 0x65, 0x74, 0x72, /* - - - - r e t r */
343 0x79, 0x2d, 0x61, 0x66, 0x74, 0x65, 0x72, 0x00, /* y - a f t e r - */
344 0x00, 0x00, 0x06, 0x73, 0x65, 0x72, 0x76, 0x65, /* - - - s e r v e */
345 0x72, 0x00, 0x00, 0x00, 0x02, 0x74, 0x65, 0x00, /* r - - - - t e - */
346 0x00, 0x00, 0x07, 0x74, 0x72, 0x61, 0x69, 0x6c, /* - - - t r a i l */
347 0x65, 0x72, 0x00, 0x00, 0x00, 0x11, 0x74, 0x72, /* e r - - - - t r */
348 0x61, 0x6e, 0x73, 0x66, 0x65, 0x72, 0x2d, 0x65, /* a n s f e r - e */
349 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x00, /* n c o d i n g - */
350 0x00, 0x00, 0x07, 0x75, 0x70, 0x67, 0x72, 0x61, /* - - - u p g r a */
351 0x64, 0x65, 0x00, 0x00, 0x00, 0x0a, 0x75, 0x73, /* d e - - - - u s */
352 0x65, 0x72, 0x2d, 0x61, 0x67, 0x65, 0x6e, 0x74, /* e r - a g e n t */
353 0x00, 0x00, 0x00, 0x04, 0x76, 0x61, 0x72, 0x79, /* - - - - v a r y */
354 0x00, 0x00, 0x00, 0x03, 0x76, 0x69, 0x61, 0x00, /* - - - - v i a - */
355 0x00, 0x00, 0x07, 0x77, 0x61, 0x72, 0x6e, 0x69, /* - - - w a r n i */
356 0x6e, 0x67, 0x00, 0x00, 0x00, 0x10, 0x77, 0x77, /* n g - - - - w w */
357 0x77, 0x2d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, /* w - a u t h e n */
358 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x00, 0x00, /* t i c a t e - - */
359 0x00, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, /* - - m e t h o d */
360 0x00, 0x00, 0x00, 0x03, 0x67, 0x65, 0x74, 0x00, /* - - - - g e t - */
361 0x00, 0x00, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, /* - - - s t a t u */
362 0x73, 0x00, 0x00, 0x00, 0x06, 0x32, 0x30, 0x30, /* s - - - - 2 0 0 */
363 0x20, 0x4f, 0x4b, 0x00, 0x00, 0x00, 0x07, 0x76, /* - O K - - - - v */
364 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x00, /* e r s i o n - - */
365 0x00, 0x08, 0x48, 0x54, 0x54, 0x50, 0x2f, 0x31, /* - - H T T P - 1 */
366 0x2e, 0x31, 0x00, 0x00, 0x00, 0x03, 0x75, 0x72, /* - 1 - - - - u r */
367 0x6c, 0x00, 0x00, 0x00, 0x06, 0x70, 0x75, 0x62, /* l - - - - p u b */
368 0x6c, 0x69, 0x63, 0x00, 0x00, 0x00, 0x0a, 0x73, /* l i c - - - - s */
369 0x65, 0x74, 0x2d, 0x63, 0x6f, 0x6f, 0x6b, 0x69, /* e t - c o o k i */
370 0x65, 0x00, 0x00, 0x00, 0x0a, 0x6b, 0x65, 0x65, /* e - - - - k e e */
371 0x70, 0x2d, 0x61, 0x6c, 0x69, 0x76, 0x65, 0x00, /* p - a l i v e - */
372 0x00, 0x00, 0x06, 0x6f, 0x72, 0x69, 0x67, 0x69, /* - - - o r i g i */
373 0x6e, 0x31, 0x30, 0x30, 0x31, 0x30, 0x31, 0x32, /* n 1 0 0 1 0 1 2 */
374 0x30, 0x31, 0x32, 0x30, 0x32, 0x32, 0x30, 0x35, /* 0 1 2 0 2 2 0 5 */
375 0x32, 0x30, 0x36, 0x33, 0x30, 0x30, 0x33, 0x30, /* 2 0 6 3 0 0 3 0 */
376 0x32, 0x33, 0x30, 0x33, 0x33, 0x30, 0x34, 0x33, /* 2 3 0 3 3 0 4 3 */
377 0x30, 0x35, 0x33, 0x30, 0x36, 0x33, 0x30, 0x37, /* 0 5 3 0 6 3 0 7 */
378 0x34, 0x30, 0x32, 0x34, 0x30, 0x35, 0x34, 0x30, /* 4 0 2 4 0 5 4 0 */
379 0x36, 0x34, 0x30, 0x37, 0x34, 0x30, 0x38, 0x34, /* 6 4 0 7 4 0 8 4 */
380 0x30, 0x39, 0x34, 0x31, 0x30, 0x34, 0x31, 0x31, /* 0 9 4 1 0 4 1 1 */
381 0x34, 0x31, 0x32, 0x34, 0x31, 0x33, 0x34, 0x31, /* 4 1 2 4 1 3 4 1 */
382 0x34, 0x34, 0x31, 0x35, 0x34, 0x31, 0x36, 0x34, /* 4 4 1 5 4 1 6 4 */
383 0x31, 0x37, 0x35, 0x30, 0x32, 0x35, 0x30, 0x34, /* 1 7 5 0 2 5 0 4 */
384 0x35, 0x30, 0x35, 0x32, 0x30, 0x33, 0x20, 0x4e, /* 5 0 5 2 0 3 - N */
385 0x6f, 0x6e, 0x2d, 0x41, 0x75, 0x74, 0x68, 0x6f, /* o n - A u t h o */
386 0x72, 0x69, 0x74, 0x61, 0x74, 0x69, 0x76, 0x65, /* r i t a t i v e */
387 0x20, 0x49, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, /* - I n f o r m a */
388 0x74, 0x69, 0x6f, 0x6e, 0x32, 0x30, 0x34, 0x20, /* t i o n 2 0 4 - */
389 0x4e, 0x6f, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x65, /* N o - C o n t e */
390 0x6e, 0x74, 0x33, 0x30, 0x31, 0x20, 0x4d, 0x6f, /* n t 3 0 1 - M o */
391 0x76, 0x65, 0x64, 0x20, 0x50, 0x65, 0x72, 0x6d, /* v e d - P e r m */
392 0x61, 0x6e, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x34, /* a n e n t l y 4 */
393 0x30, 0x30, 0x20, 0x42, 0x61, 0x64, 0x20, 0x52, /* 0 0 - B a d - R */
394 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x34, 0x30, /* e q u e s t 4 0 */
395 0x31, 0x20, 0x55, 0x6e, 0x61, 0x75, 0x74, 0x68, /* 1 - U n a u t h */
396 0x6f, 0x72, 0x69, 0x7a, 0x65, 0x64, 0x34, 0x30, /* o r i z e d 4 0 */
397 0x33, 0x20, 0x46, 0x6f, 0x72, 0x62, 0x69, 0x64, /* 3 - F o r b i d */
398 0x64, 0x65, 0x6e, 0x34, 0x30, 0x34, 0x20, 0x4e, /* d e n 4 0 4 - N */
399 0x6f, 0x74, 0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, /* o t - F o u n d */
400 0x35, 0x30, 0x30, 0x20, 0x49, 0x6e, 0x74, 0x65, /* 5 0 0 - I n t e */
401 0x72, 0x6e, 0x61, 0x6c, 0x20, 0x53, 0x65, 0x72, /* r n a l - S e r */
402 0x76, 0x65, 0x72, 0x20, 0x45, 0x72, 0x72, 0x6f, /* v e r - E r r o */
403 0x72, 0x35, 0x30, 0x31, 0x20, 0x4e, 0x6f, 0x74, /* r 5 0 1 - N o t */
404 0x20, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, /* - I m p l e m e */
405 0x6e, 0x74, 0x65, 0x64, 0x35, 0x30, 0x33, 0x20, /* n t e d 5 0 3 - */
406 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x20, /* S e r v i c e - */
407 0x55, 0x6e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, /* U n a v a i l a */
408 0x62, 0x6c, 0x65, 0x4a, 0x61, 0x6e, 0x20, 0x46, /* b l e J a n - F */
409 0x65, 0x62, 0x20, 0x4d, 0x61, 0x72, 0x20, 0x41, /* e b - M a r - A */
410 0x70, 0x72, 0x20, 0x4d, 0x61, 0x79, 0x20, 0x4a, /* p r - M a y - J */
411 0x75, 0x6e, 0x20, 0x4a, 0x75, 0x6c, 0x20, 0x41, /* u n - J u l - A */
412 0x75, 0x67, 0x20, 0x53, 0x65, 0x70, 0x74, 0x20, /* u g - S e p t - */
413 0x4f, 0x63, 0x74, 0x20, 0x4e, 0x6f, 0x76, 0x20, /* O c t - N o v - */
414 0x44, 0x65, 0x63, 0x20, 0x30, 0x30, 0x3a, 0x30, /* D e c - 0 0 - 0 */
415 0x30, 0x3a, 0x30, 0x30, 0x20, 0x4d, 0x6f, 0x6e, /* 0 - 0 0 - M o n */
416 0x2c, 0x20, 0x54, 0x75, 0x65, 0x2c, 0x20, 0x57, /* - - T u e - - W */
417 0x65, 0x64, 0x2c, 0x20, 0x54, 0x68, 0x75, 0x2c, /* e d - - T h u - */
418 0x20, 0x46, 0x72, 0x69, 0x2c, 0x20, 0x53, 0x61, /* - F r i - - S a */
419 0x74, 0x2c, 0x20, 0x53, 0x75, 0x6e, 0x2c, 0x20, /* t - - S u n - - */
420 0x47, 0x4d, 0x54, 0x63, 0x68, 0x75, 0x6e, 0x6b, /* G M T c h u n k */
421 0x65, 0x64, 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, /* e d - t e x t - */
422 0x68, 0x74, 0x6d, 0x6c, 0x2c, 0x69, 0x6d, 0x61, /* h t m l - i m a */
423 0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x2c, 0x69, /* g e - p n g - i */
424 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x6a, 0x70, 0x67, /* m a g e - j p g */
425 0x2c, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x67, /* - i m a g e - g */
426 0x69, 0x66, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, /* i f - a p p l i */
427 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, /* c a t i o n - x */
428 0x6d, 0x6c, 0x2c, 0x61, 0x70, 0x70, 0x6c, 0x69, /* m l - a p p l i */
429 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x78, /* c a t i o n - x */
430 0x68, 0x74, 0x6d, 0x6c, 0x2b, 0x78, 0x6d, 0x6c, /* h t m l - x m l */
431 0x2c, 0x74, 0x65, 0x78, 0x74, 0x2f, 0x70, 0x6c, /* - t e x t - p l */
432 0x61, 0x69, 0x6e, 0x2c, 0x74, 0x65, 0x78, 0x74, /* a i n - t e x t */
433 0x2f, 0x6a, 0x61, 0x76, 0x61, 0x73, 0x63, 0x72, /* - j a v a s c r */
434 0x69, 0x70, 0x74, 0x2c, 0x70, 0x75, 0x62, 0x6c, /* i p t - p u b l */
435 0x69, 0x63, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, /* i c p r i v a t */
436 0x65, 0x6d, 0x61, 0x78, 0x2d, 0x61, 0x67, 0x65, /* e m a x - a g e */
437 0x3d, 0x67, 0x7a, 0x69, 0x70, 0x2c, 0x64, 0x65, /* - g z i p - d e */
438 0x66, 0x6c, 0x61, 0x74, 0x65, 0x2c, 0x73, 0x64, /* f l a t e - s d */
439 0x63, 0x68, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, /* c h c h a r s e */
440 0x74, 0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x63, /* t - u t f - 8 c */
441 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, 0x3d, 0x69, /* h a r s e t - i */
442 0x73, 0x6f, 0x2d, 0x38, 0x38, 0x35, 0x39, 0x2d, /* s o - 8 8 5 9 - */
443 0x31, 0x2c, 0x75, 0x74, 0x66, 0x2d, 0x2c, 0x2a, /* 1 - u t f - - - */
444 0x2c, 0x65, 0x6e, 0x71, 0x3d, 0x30, 0x2e /* - e n q - 0 - */
447 /* callback function used at the end of file-scope to cleanup zlib's inflate
448 * streams to avoid memory leaks.
449 * XXX: can we be more aggressive and call this sooner for finished streams?
451 static bool inflate_end_cb (wmem_allocator_t *allocator _U_,
452 wmem_cb_event_t event _U_, void *user_data) {
453 #ifdef HAVE_ZLIBNG
454 ZLIB_PREFIX(inflateEnd)((zng_streamp)user_data);
455 #else
456 ZLIB_PREFIX(inflateEnd)((z_streamp)user_data);
457 #endif
458 return false;
460 #endif
463 * Protocol initialization
465 static void
466 spdy_init_protocol(void)
468 header_info_list = NULL;
472 * Returns conversation data for a given packet. If conversation data can't be
473 * found, creates and returns new conversation data.
475 static spdy_conv_t * get_or_create_spdy_conversation_data(packet_info *pinfo) {
476 conversation_t *conversation;
477 spdy_conv_t *conv_data;
478 #if defined (HAVE_ZLIB) || defined (HAVE_ZLIBNG)
479 int retcode;
480 #endif
482 conversation = find_or_create_conversation(pinfo);
484 /* Retrieve information from conversation */
485 conv_data = (spdy_conv_t *)conversation_get_proto_data(conversation, proto_spdy);
486 if (!conv_data) {
487 /* Set up the conversation structure itself */
488 conv_data = wmem_new0(wmem_file_scope(), spdy_conv_t);
490 conv_data->streams = NULL;
491 if (spdy_decompress_headers) {
492 #if defined (HAVE_ZLIB) || defined (HAVE_ZLIBNG)
493 conv_data->rqst_decompressor = wmem_new0(wmem_file_scope(), zlib_stream);
494 conv_data->rply_decompressor = wmem_new0(wmem_file_scope(), zlib_stream);
495 retcode = ZLIB_PREFIX(inflateInit)(conv_data->rqst_decompressor);
496 if (retcode == Z_OK) {
497 wmem_register_callback(wmem_file_scope(), inflate_end_cb,
498 conv_data->rqst_decompressor);
499 retcode = ZLIB_PREFIX(inflateInit)(conv_data->rply_decompressor);
500 if (retcode == Z_OK) {
501 wmem_register_callback(wmem_file_scope(), inflate_end_cb,
502 conv_data->rply_decompressor);
506 /* XXX - use wsutil/adler32.h? */
507 conv_data->dictionary_id = ZLIB_PREFIX(adler32)(0L, Z_NULL, 0);
508 conv_data->dictionary_id = ZLIB_PREFIX(adler32)(conv_data->dictionary_id,
509 spdy_dictionary,
510 (uInt)sizeof(spdy_dictionary));
511 #endif
514 conversation_add_proto_data(conversation, proto_spdy, conv_data);
517 return conv_data;
521 * Retains state on a given stream.
523 static void spdy_save_stream_info(spdy_conv_t *conv_data,
524 uint32_t stream_id,
525 media_container_type_t container_type,
526 char *content_type,
527 char *content_type_params,
528 char *content_encoding) {
529 spdy_stream_info_t *si;
531 if (conv_data->streams == NULL) {
532 conv_data->streams = wmem_tree_new(wmem_file_scope());
535 si = wmem_new(wmem_file_scope(), spdy_stream_info_t);
536 si->container_type = container_type;
537 si->content_type = content_type;
538 si->content_type_parameters = content_type_params;
539 si->content_encoding = content_encoding;
540 si->data_frames = wmem_list_new(wmem_file_scope());
541 si->num_data_frames = 0;
542 si->assembled_data = NULL;
543 wmem_tree_insert32(conv_data->streams, stream_id, si);
547 * Retrieves previously saved state on a given stream.
549 static spdy_stream_info_t* spdy_get_stream_info(spdy_conv_t *conv_data,
550 uint32_t stream_id)
552 if (conv_data->streams == NULL)
553 return NULL;
555 return (spdy_stream_info_t*)wmem_tree_lookup32(conv_data->streams, stream_id);
559 * Adds a data chunk to a given SPDY conversation/stream.
561 static void spdy_add_data_chunk(spdy_conv_t *conv_data,
562 uint32_t stream_id,
563 uint32_t frame,
564 uint8_t *data,
565 uint32_t length)
567 spdy_stream_info_t *si = spdy_get_stream_info(conv_data, stream_id);
569 if (si != NULL) {
570 spdy_data_frame_t *df = (spdy_data_frame_t *)wmem_new(wmem_file_scope(), spdy_data_frame_t);
571 df->data = data;
572 df->length = length;
573 df->framenum = frame;
574 wmem_list_append(si->data_frames, df);
575 ++si->num_data_frames;
580 * Increment the count of DATA frames found on a given stream.
582 static void spdy_increment_data_chunk_count(spdy_conv_t *conv_data,
583 uint32_t stream_id) {
584 spdy_stream_info_t *si = spdy_get_stream_info(conv_data, stream_id);
585 if (si != NULL) {
586 ++si->num_data_frames;
591 * Return the number of data frames saved so far for the specified stream.
593 static unsigned spdy_get_num_data_frames(spdy_conv_t *conv_data,
594 uint32_t stream_id) {
595 spdy_stream_info_t *si = spdy_get_stream_info(conv_data, stream_id);
597 return si == NULL ? 0 : si->num_data_frames;
601 * Reassembles DATA frames for a given stream into one tvb.
603 static spdy_stream_info_t* spdy_assemble_data_frames(spdy_conv_t *conv_data,
604 uint32_t stream_id) {
605 spdy_stream_info_t *si = spdy_get_stream_info(conv_data, stream_id);
606 tvbuff_t *tvb;
608 if (si == NULL) {
609 return NULL;
613 * Compute the total amount of data and concatenate the
614 * data chunks, if it hasn't already been done.
616 if (si->assembled_data == NULL) {
617 spdy_data_frame_t *df;
618 uint8_t *data;
619 uint32_t datalen;
620 uint32_t offset;
621 wmem_list_t *dflist = si->data_frames;
622 wmem_list_frame_t *frame;
623 if (wmem_list_count(dflist) == 0) {
624 return si;
626 datalen = 0;
628 * It'd be nice to use a composite tvbuff here, but since
629 * only a real-data tvbuff can be the child of another
630 * tvb, we can't. It would be nice if this limitation
631 * could be fixed.
633 frame = wmem_list_frame_next(wmem_list_head(dflist));
634 while (frame != NULL) {
635 df = (spdy_data_frame_t *)wmem_list_frame_data(frame);
636 datalen += df->length;
637 frame = wmem_list_frame_next(frame);
639 if (datalen != 0) {
640 data = (uint8_t *)wmem_alloc(wmem_file_scope(), datalen);
641 dflist = si->data_frames;
642 offset = 0;
643 frame = wmem_list_frame_next(wmem_list_head(dflist));
644 while (frame != NULL) {
645 df = (spdy_data_frame_t *)wmem_list_frame_data(frame);
646 memcpy(data+offset, df->data, df->length);
647 offset += df->length;
648 frame = wmem_list_frame_next(frame);
650 tvb = tvb_new_real_data(data, datalen, datalen);
651 si->assembled_data = tvb;
654 return si;
658 * Same as dissect_spdy_stream_id below, except with explicit field index.
660 static void dissect_spdy_stream_id_field(tvbuff_t *tvb,
661 int offset,
662 packet_info *pinfo _U_,
663 proto_tree *frame_tree,
664 const int hfindex)
666 uint32_t stream_id = tvb_get_ntohl(tvb, offset) & SPDY_STREAM_ID_MASK;
668 /* Add stream id to tree. */
669 proto_tree_add_item(frame_tree, hfindex, tvb, offset, 4, ENC_BIG_ENDIAN);
671 if (hfindex == hf_spdy_streamid) {
672 proto_item_append_text(frame_tree, ", Stream: %u", stream_id);
677 * Adds flag details to proto tree.
679 static void dissect_spdy_flags(tvbuff_t *tvb,
680 int offset,
681 proto_tree *frame_tree,
682 const spdy_control_frame_info_t *frame) {
683 proto_item *flags_ti;
684 proto_tree *flags_tree;
686 /* Create flags substree. */
687 flags_ti = proto_tree_add_item(frame_tree, hf_spdy_flags, tvb, offset, 1, ENC_BIG_ENDIAN);
688 flags_tree = proto_item_add_subtree(flags_ti, ett_spdy_flags);
690 /* Add FIN flag for appropriate frames. */
691 if (frame->type == SPDY_DATA ||
692 frame->type == SPDY_SYN_STREAM ||
693 frame->type == SPDY_SYN_REPLY ||
694 frame->type == SPDY_HEADERS) {
695 /* Add FIN flag. */
696 proto_tree_add_item(flags_tree, hf_spdy_flags_fin, tvb, offset, 1, ENC_BIG_ENDIAN);
697 if (frame->flags & SPDY_FLAG_FIN) {
698 proto_item_append_text(frame_tree, " (FIN)");
699 proto_item_append_text(flags_ti, " (FIN)");
703 /* Add UNIDIRECTIONAL flag, only applicable for SYN_STREAM. */
704 if (frame->type == SPDY_SYN_STREAM) {
705 proto_tree_add_item(flags_tree, hf_spdy_flags_unidirectional, tvb,
706 offset, 1, ENC_BIG_ENDIAN);
707 if (frame->flags & SPDY_FLAG_UNIDIRECTIONAL) {
708 proto_item_append_text(flags_ti, " (UNIDIRECTIONAL)");
712 /* Add CLEAR_SETTINGS flag, only applicable for SETTINGS. */
713 if (frame->type == SPDY_SETTINGS) {
714 proto_tree_add_item(flags_tree, hf_spdy_flags_clear_settings, tvb,
715 offset, 1, ENC_BIG_ENDIAN);
716 if (frame->flags & SPDY_FLAG_SETTINGS_CLEAR_SETTINGS) {
717 proto_item_append_text(flags_ti, " (CLEAR)");
723 * Performs DATA frame payload dissection.
725 static int dissect_spdy_data_payload(tvbuff_t *tvb,
726 int offset,
727 packet_info *pinfo,
728 proto_tree *top_level_tree _U_,
729 proto_tree *spdy_tree,
730 proto_item *spdy_proto,
731 spdy_conv_t *conv_data,
732 uint32_t stream_id,
733 const spdy_control_frame_info_t *frame)
735 dissector_handle_t handle;
736 unsigned num_data_frames;
737 bool dissected;
738 media_content_info_t content_info;
740 /* Add frame description. */
741 proto_item_append_text(spdy_proto, ", Stream: %d, Length: %d",
742 stream_id,
743 frame->length);
745 /* Add data. */
746 proto_tree_add_item(spdy_tree, hf_spdy_data, tvb, offset, frame->length, ENC_NA);
748 num_data_frames = spdy_get_num_data_frames(conv_data, stream_id);
749 if (frame->length != 0 || num_data_frames != 0) {
751 * There's stuff left over; process it.
753 tvbuff_t *next_tvb = NULL;
754 tvbuff_t *data_tvb = NULL;
755 spdy_stream_info_t *si = NULL;
756 uint8_t *copied_data;
757 bool is_single_chunk = false;
758 bool have_entire_body;
759 char *media_str = NULL;
762 * Create a tvbuff for the payload.
764 if (frame->length != 0) {
765 next_tvb = tvb_new_subset_length(tvb, offset, frame->length);
766 is_single_chunk = num_data_frames == 0 &&
767 (frame->flags & SPDY_FLAG_FIN) != 0;
768 if (!pinfo->fd->visited) {
769 if (!is_single_chunk) {
770 if (spdy_assemble_entity_bodies) {
771 copied_data = (uint8_t *)tvb_memdup(wmem_file_scope(),next_tvb, 0, frame->length);
772 spdy_add_data_chunk(conv_data, stream_id, pinfo->num, copied_data, frame->length);
773 } else {
774 spdy_increment_data_chunk_count(conv_data, stream_id);
778 } else {
779 is_single_chunk = (num_data_frames == 1);
782 if (!(frame->flags & SPDY_FLAG_FIN)) {
783 col_set_fence(pinfo->cinfo, COL_INFO);
784 proto_item_append_text(spdy_proto, " (partial entity body)");
785 /* would like the proto item to say */
786 /* " (entity body fragment N of M)" */
787 goto body_dissected;
789 have_entire_body = is_single_chunk;
791 * On seeing the last data frame in a stream, we can
792 * reassemble the frames into one data block.
794 si = spdy_assemble_data_frames(conv_data, stream_id);
795 if (si == NULL) {
796 goto body_dissected;
798 data_tvb = si->assembled_data;
799 if (spdy_assemble_entity_bodies) {
800 have_entire_body = true;
803 if (!have_entire_body) {
804 goto body_dissected;
807 if (data_tvb == NULL) {
808 if (next_tvb == NULL)
809 goto body_dissected;
810 data_tvb = next_tvb;
811 } else {
812 add_new_data_source(pinfo, data_tvb, "Assembled entity body");
815 if (have_entire_body && si->content_encoding != NULL &&
816 g_ascii_strcasecmp(si->content_encoding, "identity") != 0) {
818 * We currently can't handle, for example, "compress";
819 * just handle them as data for now.
821 * After July 7, 2004 the LZW patent expires, so support
822 * might be added then. However, I don't think that
823 * anybody ever really implemented "compress", due to
824 * the aforementioned patent.
826 tvbuff_t *uncomp_tvb = NULL;
827 proto_item *e_ti = NULL;
828 proto_tree *e_tree = NULL;
830 if (spdy_decompress_body &&
831 (g_ascii_strcasecmp(si->content_encoding, "gzip") == 0 ||
832 g_ascii_strcasecmp(si->content_encoding, "deflate") == 0)) {
833 uncomp_tvb = tvb_child_uncompress_zlib(tvb, data_tvb, 0,
834 tvb_reported_length(data_tvb));
837 * Add the encoded entity to the protocol tree
839 e_tree = proto_tree_add_subtree_format(spdy_tree, data_tvb,
840 0, tvb_reported_length(data_tvb), ett_spdy_encoded_entity, &e_ti,
841 "Content-encoded entity body (%s): %u bytes",
842 si->content_encoding,
843 tvb_reported_length(data_tvb));
844 if (si->num_data_frames > 1) {
845 wmem_list_t *dflist = si->data_frames;
846 wmem_list_frame_t *frame_item;
847 spdy_data_frame_t *df;
848 uint32_t framenum = 0;
849 wmem_strbuf_t *str_frames = wmem_strbuf_new(pinfo->pool, "");
851 frame_item = wmem_list_frame_next(wmem_list_head(dflist));
852 while (frame_item != NULL) {
853 df = (spdy_data_frame_t *)wmem_list_frame_data(frame_item);
854 if (framenum != df->framenum) {
855 wmem_strbuf_append_printf(str_frames, " #%u", df->framenum);
856 framenum = df->framenum;
858 frame_item = wmem_list_frame_next(frame_item);
861 proto_tree_add_expert_format(e_tree, pinfo, &ei_spdy_reassembly_info, data_tvb, 0,
862 tvb_reported_length(data_tvb),
863 "Assembled from %d frames in packet(s)%s",
864 si->num_data_frames, wmem_strbuf_get_str(str_frames));
867 if (uncomp_tvb != NULL) {
869 * Decompression worked
872 /* XXX - Don't free this, since it's possible
873 * that the data was only partially
874 * decompressed, such as when desegmentation
875 * isn't enabled.
877 tvb_free(next_tvb);
879 proto_item_append_text(e_ti, " -> %u bytes", tvb_reported_length(uncomp_tvb));
880 data_tvb = uncomp_tvb;
881 add_new_data_source(pinfo, data_tvb, "Uncompressed entity body");
882 } else {
883 if (spdy_decompress_body) {
884 proto_item_append_text(e_ti, " [Error: Decompression failed]");
886 call_data_dissector(data_tvb, pinfo, e_tree);
888 goto body_dissected;
893 * Do subdissector checks.
895 * First, check whether some subdissector asked that they
896 * be called if something was on some particular port.
899 if (have_entire_body && port_subdissector_table != NULL) {
900 handle = dissector_get_uint_handle(port_subdissector_table,
901 pinfo->match_uint);
902 } else {
903 handle = NULL;
905 if (handle == NULL && have_entire_body && si->content_type != NULL &&
906 media_type_subdissector_table != NULL) {
908 * We didn't find any subdissector that
909 * registered for the port, and we have a
910 * Content-Type value. Is there any subdissector
911 * for that content type?
913 if (si->content_type_parameters) {
914 media_str = wmem_strdup(pinfo->pool, si->content_type_parameters);
917 * Calling the string handle for the media type
918 * dissector table will set pinfo->match_string
919 * to si->content_type for us.
921 pinfo->match_string = si->content_type;
922 handle = dissector_get_string_handle(media_type_subdissector_table,
923 si->content_type);
925 content_info.type = si->container_type;
926 content_info.media_str = media_str;
927 content_info.data = NULL;
928 if (handle != NULL) {
930 * We have a subdissector - call it.
932 dissected = call_dissector_with_data(handle, data_tvb, pinfo, spdy_tree, &content_info);
933 } else {
934 dissected = false;
937 if (!dissected && have_entire_body && si->content_type != NULL) {
939 * Calling the default media handle if there is a content-type that
940 * wasn't handled above.
942 call_dissector_with_data(media_handle, next_tvb, pinfo, spdy_tree, &content_info);
943 } else {
944 /* Call the default data dissector */
945 call_data_dissector(next_tvb, pinfo, spdy_tree);
948 body_dissected:
950 * We've processed frame->length bytes worth of data
951 * (which may be no data at all); advance the
952 * offset past whatever data we've processed.
956 return frame->length;
959 #if defined (HAVE_ZLIB) || defined (HAVE_ZLIBNG)
961 * Performs header decompression.
963 * The returned buffer is automatically scoped to the lifetime of the capture
964 * (via wmem_memdup() with file scope).
966 #define DECOMPRESS_BUFSIZE 16384
968 static uint8_t* spdy_decompress_header_block(tvbuff_t *tvb,
969 packet_info *pinfo,
970 #ifdef HAVE_ZLIBNG
971 zng_streamp decomp,
972 #else
973 z_streamp decomp,
974 #endif
975 uLong dictionary_id,
976 int offset,
977 uint32_t length,
978 unsigned *uncomp_length) {
979 int retcode;
980 const uint8_t *hptr = tvb_get_ptr(tvb, offset, length);
981 uint8_t *uncomp_block = (uint8_t *)wmem_alloc(pinfo->pool, DECOMPRESS_BUFSIZE);
983 #ifdef z_const
984 decomp->next_in = (z_const Bytef *)hptr;
985 #else
986 DIAG_OFF(cast-qual)
987 decomp->next_in = (Bytef *)hptr;
988 DIAG_ON(cast-qual)
989 #endif
990 decomp->avail_in = length;
991 decomp->next_out = uncomp_block;
992 decomp->avail_out = DECOMPRESS_BUFSIZE;
993 retcode = ZLIB_PREFIX(inflate)(decomp, Z_SYNC_FLUSH);
994 if (retcode == Z_NEED_DICT) {
995 if (decomp->adler == dictionary_id) {
996 retcode = ZLIB_PREFIX(inflateSetDictionary)(decomp,
997 spdy_dictionary,
998 sizeof(spdy_dictionary));
999 if (retcode == Z_OK) {
1000 retcode = ZLIB_PREFIX(inflate)(decomp, Z_SYNC_FLUSH);
1005 /* Handle errors. */
1006 if (retcode != Z_OK) {
1007 return NULL;
1010 /* Handle successful inflation. */
1011 *uncomp_length = DECOMPRESS_BUFSIZE - decomp->avail_out;
1013 return (uint8_t *)wmem_memdup(wmem_file_scope(), uncomp_block, *uncomp_length);
1015 #endif
1019 * Saves state on header data for a given stream.
1021 static spdy_header_info_t* spdy_save_header_block(packet_info *pinfo _U_,
1022 uint32_t stream_id,
1023 uint16_t frame_type,
1024 uint8_t *header,
1025 unsigned length) {
1026 spdy_header_info_t *header_info;
1028 if (header_info_list == NULL)
1029 header_info_list = wmem_list_new(wmem_file_scope());
1031 header_info = wmem_new(wmem_file_scope(), spdy_header_info_t);
1032 header_info->stream_id = stream_id;
1033 header_info->header_block = header;
1034 header_info->header_block_len = length;
1035 header_info->frame_type = frame_type;
1036 wmem_list_append(header_info_list, header_info);
1037 return header_info;
1041 * Retrieves saved state for a given stream.
1043 static spdy_header_info_t* spdy_find_saved_header_block(packet_info *pinfo _U_,
1044 uint32_t stream_id,
1045 uint16_t frame_type) {
1046 wmem_list_frame_t *frame;
1048 if ((header_info_list == NULL) || (wmem_list_head(header_info_list) == NULL))
1049 return NULL;
1051 frame = wmem_list_frame_next(wmem_list_head(header_info_list));
1052 while (frame != NULL) {
1053 spdy_header_info_t *hi = (spdy_header_info_t *)wmem_list_frame_data(frame);
1054 if (hi->stream_id == stream_id && hi->frame_type == frame_type)
1055 return hi;
1056 frame = wmem_list_frame_next(frame);
1058 return NULL;
1062 * Given a content type string that may contain optional parameters,
1063 * return the parameter string, if any, otherwise return NULL. This
1064 * also has the side effect of null terminating the content type
1065 * part of the original string.
1067 static char* spdy_parse_content_type(char *content_type) {
1068 char *cp = content_type;
1070 while (*cp != '\0' && *cp != ';' && !g_ascii_isspace(*cp)) {
1071 *cp = g_ascii_tolower(*cp);
1072 ++cp;
1074 if (*cp == '\0') {
1075 cp = NULL;
1078 if (cp != NULL) {
1079 *cp++ = '\0';
1080 while (*cp == ';' || g_ascii_isspace(*cp)) {
1081 ++cp;
1083 if (*cp != '\0') {
1084 return cp;
1087 return NULL;
1090 static int dissect_spdy_header_payload(
1091 tvbuff_t *tvb,
1092 int offset,
1093 packet_info *pinfo,
1094 proto_tree *frame_tree,
1095 const spdy_control_frame_info_t *frame,
1096 spdy_conv_t *conv_data) {
1097 uint32_t stream_id;
1098 int header_block_length = frame->length;
1099 int hdr_offset = 0;
1100 tvbuff_t *header_tvb = NULL;
1101 const char *hdr_method = NULL;
1102 const char *hdr_path = NULL;
1103 const char *hdr_version = NULL;
1104 const char *hdr_host = NULL;
1105 const char *hdr_scheme = NULL;
1106 const char *hdr_status = NULL;
1107 char *content_type = NULL;
1108 char *content_encoding = NULL;
1109 uint32_t num_headers = 0;
1110 proto_item *header_block_item;
1111 proto_tree *header_block_tree;
1113 /* Get stream id, which is present in all types of header frames. */
1114 stream_id = tvb_get_ntohl(tvb, offset) & SPDY_STREAM_ID_MASK;
1115 dissect_spdy_stream_id_field(tvb, offset, pinfo, frame_tree, hf_spdy_streamid);
1116 offset += 4;
1118 /* Get SYN_STREAM-only fields. */
1119 if (frame->type == SPDY_SYN_STREAM) {
1120 /* Get associated stream ID. */
1121 dissect_spdy_stream_id_field(tvb, offset, pinfo, frame_tree, hf_spdy_associated_streamid);
1122 offset += 4;
1124 /* Get priority */
1125 proto_tree_add_item(frame_tree, hf_spdy_priority, tvb, offset, 2, ENC_BIG_ENDIAN);
1126 proto_tree_add_item(frame_tree, hf_spdy_unused, tvb, offset, 2, ENC_BIG_ENDIAN);
1127 proto_tree_add_item(frame_tree, hf_spdy_slot, tvb, offset, 2, ENC_BIG_ENDIAN);
1128 offset += 2;
1132 /* Get our header block length. */
1133 switch (frame->type) {
1134 case SPDY_SYN_STREAM:
1135 header_block_length -= 10;
1136 break;
1137 case SPDY_SYN_REPLY:
1138 case SPDY_HEADERS:
1139 header_block_length -= 4;
1140 break;
1141 default:
1142 /* Unhandled case. This should never happen. */
1143 DISSECTOR_ASSERT_NOT_REACHED();
1146 /* Add the header block. */
1147 header_block_item = proto_tree_add_item(frame_tree,
1148 hf_spdy_header_block,
1149 tvb,
1150 offset,
1151 header_block_length,
1152 ENC_NA);
1153 header_block_tree = proto_item_add_subtree(header_block_item,
1154 ett_spdy_header_block);
1156 /* Decompress header block as necessary. */
1157 if (!spdy_decompress_headers) {
1158 header_tvb = tvb;
1159 hdr_offset = offset;
1160 } else {
1161 spdy_header_info_t *header_info;
1163 /* First attempt to find previously decompressed data.
1164 * This will not work correctly for lower-level frames that contain more
1165 * than one SPDY frame of the same type. We assume this to never be the
1166 * case, though. */
1167 header_info = spdy_find_saved_header_block(pinfo,
1168 stream_id,
1169 frame->type);
1171 /* Generate decompressed data and store it, since none was found. */
1172 if (header_info == NULL) {
1173 uint8_t *uncomp_ptr = NULL;
1174 unsigned uncomp_length = 0;
1175 #if defined (HAVE_ZLIB) || defined (HAVE_ZLIBNG)
1176 #ifdef HAVE_ZLIBNG
1177 zng_streamp decomp;
1178 #else
1179 z_streamp decomp;
1180 #endif
1182 /* Get our decompressor. */
1183 if (stream_id % 2 == 0) {
1184 /* Even streams are server-initiated and should never get a
1185 * client-initiated header block. Use reply decompressor. */
1186 decomp = conv_data->rply_decompressor;
1187 } else if (frame->type == SPDY_HEADERS) {
1188 /* Odd streams are client-initiated, but may have HEADERS from either
1189 * side. Currently, no known clients send HEADERS so we assume they are
1190 * all from the server. */
1191 decomp = conv_data->rply_decompressor;
1192 } else if (frame->type == SPDY_SYN_STREAM) {
1193 decomp = conv_data->rqst_decompressor;
1194 } else if (frame->type == SPDY_SYN_REPLY) {
1195 decomp = conv_data->rply_decompressor;
1196 } else {
1197 /* Unhandled case. This should never happen. */
1198 DISSECTOR_ASSERT_NOT_REACHED();
1201 /* Decompress. */
1202 uncomp_ptr = spdy_decompress_header_block(tvb,
1203 pinfo,
1204 decomp,
1205 conv_data->dictionary_id,
1206 offset,
1207 header_block_length,
1208 &uncomp_length);
1210 /* Catch decompression failures. */
1211 if (uncomp_ptr == NULL) {
1212 expert_add_info(pinfo, frame_tree, &ei_spdy_inflation_failed);
1214 proto_item_append_text(frame_tree, " [Error: Header decompression failed]");
1215 return -1;
1217 #endif
1219 /* Store decompressed data. */
1220 header_info = spdy_save_header_block(pinfo, stream_id, frame->type, uncomp_ptr, uncomp_length);
1223 /* Create a tvb containing the uncompressed data. */
1224 header_tvb = tvb_new_child_real_data(tvb, header_info->header_block,
1225 header_info->header_block_len,
1226 header_info->header_block_len);
1227 add_new_data_source(pinfo, header_tvb, "Uncompressed headers");
1228 hdr_offset = 0;
1231 /* Get header block details. */
1232 if (header_tvb == NULL || !spdy_decompress_headers) {
1233 num_headers = 0;
1234 } else {
1235 num_headers = tvb_get_ntohl(header_tvb, hdr_offset);
1236 /*ti = */ proto_tree_add_item(header_block_tree,
1237 hf_spdy_num_headers,
1238 header_tvb,
1239 hdr_offset,
1241 ENC_BIG_ENDIAN);
1243 hdr_offset += 4;
1245 /* Process headers. */
1246 while (num_headers--) {
1247 char *header_name;
1248 const char *header_value;
1249 proto_tree *header_tree;
1250 proto_item *header;
1251 int header_name_offset;
1252 int header_value_offset;
1253 int header_name_length;
1254 int header_value_length;
1256 /* Get header name details. */
1257 if (tvb_reported_length_remaining(header_tvb, hdr_offset) < 4) {
1258 expert_add_info_format(pinfo, frame_tree, &ei_spdy_mal_frame_data,
1259 "Not enough frame data for header name size.");
1260 break;
1262 header_name_offset = hdr_offset;
1263 header_name_length = tvb_get_ntohl(header_tvb, hdr_offset);
1264 hdr_offset += 4;
1265 if (tvb_reported_length_remaining(header_tvb, hdr_offset) < header_name_length) {
1266 expert_add_info_format(pinfo, frame_tree, &ei_spdy_mal_frame_data,
1267 "Not enough frame data for header name.");
1268 break;
1270 header_name = (char *)tvb_get_string_enc(pinfo->pool, header_tvb,
1271 hdr_offset,
1272 header_name_length, ENC_ASCII|ENC_NA);
1273 hdr_offset += header_name_length;
1275 /* Get header value details. */
1276 if (tvb_reported_length_remaining(header_tvb, hdr_offset) < 4) {
1277 expert_add_info_format(pinfo, frame_tree, &ei_spdy_mal_frame_data,
1278 "Not enough frame data for header value size.");
1279 break;
1281 header_value_offset = hdr_offset;
1282 header_value_length = tvb_get_ntohl(header_tvb, hdr_offset);
1283 hdr_offset += 4;
1284 if (tvb_reported_length_remaining(header_tvb, hdr_offset) < header_value_length) {
1285 expert_add_info_format(pinfo, frame_tree, &ei_spdy_mal_frame_data,
1286 "Not enough frame data for header value.");
1287 break;
1289 header_value = (char *)tvb_get_string_enc(pinfo->pool,header_tvb,
1290 hdr_offset,
1291 header_value_length, ENC_ASCII|ENC_NA);
1292 hdr_offset += header_value_length;
1294 /* Populate tree with header name/value details. */
1295 if (frame_tree) {
1296 /* Add 'Header' subtree with description. */
1297 header = proto_tree_add_item(frame_tree,
1298 hf_spdy_header,
1299 header_tvb,
1300 header_name_offset,
1301 hdr_offset - header_name_offset,
1302 ENC_NA);
1303 proto_item_append_text(header, ": %s: %s", header_name, header_value);
1304 header_tree = proto_item_add_subtree(header, ett_spdy_header);
1306 /* Add header name. */
1307 proto_tree_add_item(header_tree, hf_spdy_header_name, header_tvb,
1308 header_name_offset, 4, ENC_ASCII|ENC_BIG_ENDIAN);
1310 /* Add header value. */
1311 proto_tree_add_item(header_tree, hf_spdy_header_value, header_tvb,
1312 header_value_offset, 4, ENC_ASCII|ENC_BIG_ENDIAN);
1316 * TODO(ers) check that the header name contains only legal characters.
1318 /* TODO(hkhalil): Make sure that prohibited headers aren't sent. */
1319 if (g_strcmp0(header_name, ":method") == 0) {
1320 hdr_method = header_value;
1321 } else if (g_strcmp0(header_name, ":path") == 0) {
1322 hdr_path = header_value;
1323 } else if (g_strcmp0(header_name, ":version") == 0) {
1324 hdr_version = header_value;
1325 } else if (g_strcmp0(header_name, ":host") == 0) {
1326 hdr_host = header_value;
1327 } else if (g_strcmp0(header_name, ":scheme") == 0) {
1328 hdr_scheme = header_value;
1329 } else if (g_strcmp0(header_name, ":status") == 0) {
1330 hdr_status = header_value;
1331 } else if (g_strcmp0(header_name, "content-type") == 0) {
1332 content_type = wmem_strdup(wmem_file_scope(), header_value);
1333 } else if (g_strcmp0(header_name, "content-encoding") == 0) {
1334 content_encoding = wmem_strdup(wmem_file_scope(), header_value);
1338 /* Set Info column. */
1339 if (hdr_version != NULL) {
1340 if (hdr_status == NULL) {
1341 proto_item_append_text(frame_tree, ", Request: %s %s://%s%s %s",
1342 hdr_method, hdr_scheme, hdr_host, hdr_path, hdr_version);
1343 } else {
1344 proto_item_append_text(frame_tree, ", Response: %s %s",
1345 hdr_status, hdr_version);
1350 * If we expect data on this stream, we need to remember the content
1351 * type and content encoding.
1353 if (content_type != NULL && !pinfo->fd->visited) {
1354 char *content_type_params = spdy_parse_content_type(content_type);
1355 spdy_save_stream_info(conv_data, stream_id,
1356 (hdr_status == NULL) ? MEDIA_CONTAINER_HTTP_REQUEST : MEDIA_CONTAINER_HTTP_RESPONSE,
1357 content_type, content_type_params, content_encoding);
1360 return frame->length;
1363 static int dissect_spdy_rst_stream_payload(
1364 tvbuff_t *tvb,
1365 int offset,
1366 packet_info *pinfo,
1367 proto_tree *frame_tree,
1368 const spdy_control_frame_info_t *frame) {
1369 uint32_t rst_status;
1370 proto_item *ti;
1371 const char* str;
1373 /* Get stream ID and add to info column and tree. */
1374 dissect_spdy_stream_id_field(tvb, offset, pinfo, frame_tree, hf_spdy_streamid);
1375 offset += 4;
1377 /* Get status. */
1379 ti = proto_tree_add_item(frame_tree, hf_spdy_rst_stream_status, tvb, offset, 4, ENC_BIG_ENDIAN);
1380 rst_status = tvb_get_ntohl(tvb, offset);
1381 if (try_val_to_str(rst_status, rst_stream_status_names) == NULL) {
1382 /* Handle boundary conditions. */
1383 expert_add_info_format(pinfo, ti, &ei_spdy_invalid_rst_stream,
1384 "Invalid status code for RST_STREAM: %u", rst_status);
1387 str = val_to_str(rst_status, rst_stream_status_names, "Unknown (%d)");
1389 proto_item_append_text(frame_tree, ", Status: %s", str);
1391 return frame->length;
1394 static int dissect_spdy_settings_payload(
1395 tvbuff_t *tvb,
1396 int offset,
1397 packet_info *pinfo,
1398 proto_tree *frame_tree,
1399 const spdy_control_frame_info_t *frame) {
1400 uint32_t num_entries;
1401 proto_item *ti, *ti_setting;
1402 proto_tree *setting_tree;
1403 proto_tree *flags_tree;
1405 /* Make sure that we have enough room for our number of entries field. */
1406 if (frame->length < 4) {
1407 expert_add_info(pinfo, frame_tree, &ei_spdy_mal_setting_frame);
1408 return -1;
1411 /* Get number of entries, and make sure we have enough room for them. */
1412 num_entries = tvb_get_ntohl(tvb, offset);
1413 if (frame->length < num_entries * 8) {
1414 expert_add_info_format(pinfo, frame_tree, &ei_spdy_mal_setting_frame,
1415 "SETTINGS frame too small [num_entries=%d]", num_entries);
1416 return -1;
1419 proto_tree_add_item(frame_tree, hf_spdy_num_settings, tvb, offset, 4, ENC_BIG_ENDIAN);
1420 offset += 4;
1422 /* Dissect each entry. */
1423 while (num_entries > 0) {
1424 const char *setting_id_str;
1425 uint32_t setting_value;
1427 /* Create key/value pair subtree. */
1428 ti_setting = proto_tree_add_item(frame_tree, hf_spdy_setting, tvb, offset, 8, ENC_NA);
1429 setting_tree = proto_item_add_subtree(ti_setting, ett_spdy_setting);
1431 /* Set flags. */
1432 if (setting_tree) {
1433 ti = proto_tree_add_item(setting_tree, hf_spdy_flags, tvb, offset, 1, ENC_BIG_ENDIAN);
1435 /* TODO(hkhalil): Prettier output for flags sub-tree description. */
1436 flags_tree = proto_item_add_subtree(ti, ett_spdy_flags);
1437 proto_tree_add_item(flags_tree, hf_spdy_flags_persist_value, tvb, offset, 1, ENC_BIG_ENDIAN);
1438 proto_tree_add_item(flags_tree, hf_spdy_flags_persisted, tvb, offset, 1, ENC_BIG_ENDIAN);
1440 offset += 1;
1442 /* Set ID. */
1443 setting_id_str = val_to_str(tvb_get_ntoh24(tvb, offset), setting_id_names, "Unknown(%d)");
1445 proto_tree_add_item(setting_tree, hf_spdy_setting_id, tvb, offset, 3, ENC_BIG_ENDIAN);
1446 offset += 3;
1448 /* Set Value. */
1449 setting_value = tvb_get_ntohl(tvb, offset);
1451 proto_tree_add_item(setting_tree, hf_spdy_setting_value, tvb, offset, 4, ENC_BIG_ENDIAN);
1452 proto_item_append_text(ti_setting, ", %s: %u", setting_id_str, setting_value);
1453 proto_item_append_text(frame_tree, ", %s: %u", setting_id_str, setting_value);
1454 offset += 4;
1456 /* Increment. */
1457 --num_entries;
1460 return frame->length;
1463 static int dissect_spdy_ping_payload(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
1464 proto_tree *frame_tree, const spdy_control_frame_info_t *frame)
1466 /* Get ping ID. */
1467 uint32_t ping_id = tvb_get_ntohl(tvb, offset);
1469 /* Add proto item for ping ID. */
1470 proto_tree_add_item(frame_tree, hf_spdy_ping_id, tvb, offset, 4, ENC_BIG_ENDIAN);
1471 proto_item_append_text(frame_tree, ", ID: %u", ping_id);
1473 return frame->length;
1476 static int dissect_spdy_goaway_payload(tvbuff_t *tvb,
1477 int offset,
1478 packet_info *pinfo,
1479 proto_tree *frame_tree,
1480 const spdy_control_frame_info_t *frame) {
1481 uint32_t goaway_status;
1482 proto_item* ti;
1484 /* Get last good stream ID and add to info column and tree. */
1485 dissect_spdy_stream_id_field(tvb, offset, pinfo, frame_tree, hf_spdy_goaway_last_good_stream_id);
1486 offset += 4;
1488 /* Add proto item for goaway_status. */
1489 ti = proto_tree_add_item(frame_tree, hf_spdy_goaway_status, tvb, offset, 4, ENC_BIG_ENDIAN);
1490 goaway_status = tvb_get_ntohl(tvb, offset);
1492 if (try_val_to_str(goaway_status, goaway_status_names) == NULL) {
1493 /* Handle boundary conditions. */
1494 expert_add_info_format(pinfo, ti, &ei_spdy_invalid_go_away,
1495 "Invalid status code for GOAWAY: %u", goaway_status);
1498 /* Add status to info column. */
1499 proto_item_append_text(frame_tree, " Status=%s)",
1500 val_to_str(goaway_status, rst_stream_status_names, "Unknown (%d)"));
1502 return frame->length;
1505 static int dissect_spdy_window_update_payload(
1506 tvbuff_t *tvb,
1507 int offset,
1508 packet_info *pinfo,
1509 proto_tree *frame_tree,
1510 const spdy_control_frame_info_t *frame)
1512 uint32_t window_update_delta;
1514 /* Get stream ID. */
1515 dissect_spdy_stream_id_field(tvb, offset, pinfo, frame_tree, hf_spdy_streamid);
1516 offset += 4;
1518 /* Get window update delta. */
1519 window_update_delta = tvb_get_ntohl(tvb, offset) & 0x7FFFFFFF;
1521 /* Add proto item for window update delta. */
1522 proto_tree_add_item(frame_tree, hf_spdy_window_update_delta, tvb, offset, 4, ENC_BIG_ENDIAN);
1523 proto_item_append_text(frame_tree, ", Delta: %u", window_update_delta);
1525 return frame->length;
1529 * Performs SPDY frame dissection.
1531 static int dissect_spdy_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
1533 uint8_t control_bit;
1534 spdy_control_frame_info_t frame;
1535 uint32_t stream_id = 0;
1536 const char *frame_type_name;
1537 proto_tree *spdy_tree;
1538 proto_item *spdy_item, *type_item = NULL;
1539 int offset = 0;
1540 spdy_conv_t *conv_data;
1542 conv_data = get_or_create_spdy_conversation_data(pinfo);
1544 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SPDY");
1546 /* Create frame root. */
1547 spdy_item = proto_tree_add_item(tree, proto_spdy, tvb, offset, -1, ENC_NA);
1548 spdy_tree = proto_item_add_subtree(spdy_item, ett_spdy);
1550 /* Add control bit. */
1551 control_bit = tvb_get_uint8(tvb, offset) & 0x80;
1552 proto_tree_add_item(spdy_tree, hf_spdy_control_bit, tvb, offset, 2, ENC_NA);
1554 /* Process first four bytes of frame, formatted depending on control bit. */
1555 if (control_bit) {
1556 /* Add version. */
1557 frame.version = tvb_get_ntohs(tvb, offset) & 0x7FFF;
1558 proto_tree_add_item(spdy_tree, hf_spdy_version, tvb, offset, 2, ENC_BIG_ENDIAN);
1559 offset += 2;
1561 /* Add control frame type. */
1562 type_item = proto_tree_add_item(spdy_tree, hf_spdy_type, tvb, offset, 2, ENC_BIG_ENDIAN);
1563 frame.type = tvb_get_ntohs(tvb, offset);
1564 if (frame.type >= SPDY_INVALID) {
1565 expert_add_info_format(pinfo, type_item, &ei_spdy_invalid_frame_type,
1566 "Invalid SPDY control frame type: %d", frame.type);
1567 return -1;
1569 offset += 2;
1571 } else {
1572 frame.type = SPDY_DATA;
1573 frame.version = 0; /* Version doesn't apply to DATA. */
1575 /* Add stream ID. */
1576 stream_id = tvb_get_ntohl(tvb, offset) & SPDY_STREAM_ID_MASK;
1577 proto_tree_add_item(spdy_tree, hf_spdy_streamid, tvb, offset, 4, ENC_BIG_ENDIAN);
1578 offset += 4;
1581 /* Add frame info. */
1582 frame_type_name = val_to_str(frame.type, frame_type_names, "Unknown(%d)");
1583 col_append_sep_str(pinfo->cinfo, COL_INFO, ", ", frame_type_name);
1585 proto_item_append_text(spdy_tree, ": %s", frame_type_name);
1587 /* Add flags. */
1588 frame.flags = tvb_get_uint8(tvb, offset);
1589 if (spdy_tree) {
1590 dissect_spdy_flags(tvb, offset, spdy_tree, &frame);
1592 offset += 1;
1594 /* Add length. */
1595 frame.length = tvb_get_ntoh24(tvb, offset);
1597 proto_item_set_len(spdy_item, frame.length + 8);
1598 proto_tree_add_item(spdy_tree, hf_spdy_length, tvb, offset, 3, ENC_BIG_ENDIAN);
1599 offset += 3;
1602 * Make sure there's as much data as the frame header says there is.
1604 if ((unsigned)tvb_reported_length_remaining(tvb, offset) < frame.length) {
1605 expert_add_info_format(pinfo, tree, &ei_spdy_mal_frame_data,
1606 "Not enough frame data: %d vs. %d",
1607 frame.length, tvb_reported_length_remaining(tvb, offset));
1608 return -1;
1611 /* Dissect DATA payload as necessary. */
1612 if (!control_bit) {
1613 return offset + dissect_spdy_data_payload(tvb, offset, pinfo, tree, spdy_tree,
1614 spdy_item, conv_data, stream_id, &frame);
1617 /* Abort here if the version is too low. */
1618 if (frame.version < MIN_SPDY_VERSION) {
1619 proto_item_append_text(spdy_item, " [Unsupported Version]");
1620 return frame.length + 8;
1623 switch (frame.type) {
1624 case SPDY_SYN_STREAM:
1625 case SPDY_SYN_REPLY:
1626 case SPDY_HEADERS:
1627 dissect_spdy_header_payload(tvb, offset, pinfo, spdy_tree, &frame, conv_data);
1628 break;
1630 case SPDY_RST_STREAM:
1631 dissect_spdy_rst_stream_payload(tvb, offset, pinfo, spdy_tree, &frame);
1632 break;
1634 case SPDY_SETTINGS:
1635 dissect_spdy_settings_payload(tvb, offset, pinfo, spdy_tree, &frame);
1636 break;
1638 case SPDY_PING:
1639 dissect_spdy_ping_payload(tvb, offset, pinfo, spdy_tree, &frame);
1640 break;
1642 case SPDY_GOAWAY:
1643 dissect_spdy_goaway_payload(tvb, offset, pinfo, spdy_tree, &frame);
1644 break;
1646 case SPDY_WINDOW_UPDATE:
1647 dissect_spdy_window_update_payload(tvb, offset, pinfo, spdy_tree, &frame);
1648 break;
1650 case SPDY_CREDENTIAL:
1651 /* TODO(hkhalil): Show something meaningful. */
1652 break;
1654 default:
1655 expert_add_info_format(pinfo, type_item, &ei_spdy_invalid_frame_type,
1656 "Unhandled SPDY frame type: %d", frame.type);
1657 break;
1661 * OK, we've set the Protocol and Info columns for the
1662 * first SPDY message; set a fence so that subsequent
1663 * SPDY messages don't overwrite the Info column.
1665 col_set_fence(pinfo->cinfo, COL_INFO);
1667 /* Assume that we've consumed the whole frame. */
1668 return 8 + frame.length;
1671 static unsigned get_spdy_message_len(packet_info *pinfo _U_, tvbuff_t *tvb,
1672 int offset, void *data _U_)
1674 return (unsigned)tvb_get_ntoh24(tvb, offset + 5) + 8;
1678 * Wrapper for dissect_spdy_frame, sets fencing and desegments as necessary.
1680 static int dissect_spdy(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
1682 col_clear(pinfo->cinfo, COL_INFO);
1684 tcp_dissect_pdus(tvb, pinfo, tree, true, 8, get_spdy_message_len, dissect_spdy_frame, data);
1685 return tvb_captured_length(tvb);
1689 * Looks for SPDY frame at tvb start.
1690 * If not enough data for either, requests more via desegment struct.
1692 static bool dissect_spdy_heur(tvbuff_t *tvb,
1693 packet_info *pinfo,
1694 proto_tree *tree,
1695 void *data _U_)
1698 * The first byte of a SPDY frame must be either 0 or
1699 * 0x80. If it's not, assume that this is not SPDY.
1700 * (In theory, a data frame could have a stream ID
1701 * >= 2^24, in which case it won't have 0 for a first
1702 * byte, but this is a pretty reliable heuristic for
1703 * now.)
1705 uint8_t first_byte = tvb_get_uint8(tvb, 0);
1706 if (first_byte != 0x80 && first_byte != 0x0) {
1707 return false;
1710 /* Attempt dissection. */
1711 if (dissect_spdy(tvb, pinfo, tree, NULL) != 0) {
1712 return true;
1715 return false;
1719 * Performs plugin registration.
1721 void proto_register_spdy(void)
1723 static hf_register_info hf[] = {
1724 { &hf_spdy_data,
1725 { "Data", "spdy.data",
1726 FT_BYTES, BASE_NONE, NULL, 0x0,
1727 NULL, HFILL
1730 { &hf_spdy_control_bit,
1731 { "Control frame", "spdy.control_bit",
1732 FT_BOOLEAN, 16, TFS(&tfs_yes_no), 0x8000,
1733 "true if SPDY control frame", HFILL
1736 { &hf_spdy_version,
1737 { "Version", "spdy.version",
1738 FT_UINT16, BASE_DEC, NULL, 0x7FFF,
1739 NULL, HFILL
1742 { &hf_spdy_type,
1743 { "Type", "spdy.type",
1744 FT_UINT16, BASE_DEC,
1745 VALS(frame_type_names), 0x0,
1746 NULL, HFILL
1749 { &hf_spdy_flags,
1750 { "Flags", "spdy.flags",
1751 FT_UINT8, BASE_HEX, NULL, 0x0,
1752 NULL, HFILL
1755 { &hf_spdy_flags_fin,
1756 { "FIN", "spdy.flags.fin",
1757 FT_BOOLEAN, 8,
1758 TFS(&tfs_set_notset), SPDY_FLAG_FIN,
1759 NULL, HFILL
1762 { &hf_spdy_flags_unidirectional,
1763 { "Unidirectional", "spdy.flags.unidirectional",
1764 FT_BOOLEAN, 8,
1765 TFS(&tfs_set_notset), SPDY_FLAG_UNIDIRECTIONAL,
1766 NULL, HFILL
1769 { &hf_spdy_flags_clear_settings,
1770 { "Persist Value", "spdy.flags.clear_settings",
1771 FT_BOOLEAN, 8,
1772 TFS(&tfs_set_notset), SPDY_FLAG_SETTINGS_CLEAR_SETTINGS,
1773 NULL, HFILL
1776 { &hf_spdy_flags_persist_value,
1777 { "Persist Value", "spdy.flags.persist_value",
1778 FT_BOOLEAN, 8,
1779 TFS(&tfs_set_notset), SPDY_FLAG_SETTINGS_PERSIST_VALUE,
1780 NULL, HFILL
1783 { &hf_spdy_flags_persisted,
1784 { "Persisted", "spdy.flags.persisted",
1785 FT_BOOLEAN, 8,
1786 TFS(&tfs_set_notset), SPDY_FLAG_SETTINGS_PERSISTED,
1787 NULL, HFILL
1790 { &hf_spdy_length,
1791 { "Length", "spdy.length",
1792 FT_UINT24, BASE_DEC, NULL, 0x0,
1793 NULL, HFILL
1796 { &hf_spdy_header_block,
1797 { "Header block", "spdy.header_block",
1798 FT_BYTES, BASE_NONE, NULL, 0x0,
1799 NULL, HFILL
1802 { &hf_spdy_header,
1803 { "Header", "spdy.header",
1804 FT_NONE, BASE_NONE, NULL, 0x0,
1805 NULL, HFILL
1808 { &hf_spdy_header_name,
1809 { "Name", "spdy.header.name",
1810 FT_UINT_STRING, BASE_NONE, NULL, 0x0,
1811 NULL, HFILL
1814 { &hf_spdy_header_value,
1815 { "Value", "spdy.header.value",
1816 FT_UINT_STRING, BASE_NONE, NULL, 0x0,
1817 NULL, HFILL
1820 { &hf_spdy_streamid,
1821 { "Stream ID", "spdy.streamid",
1822 FT_UINT32, BASE_DEC, NULL, SPDY_STREAM_ID_MASK,
1823 NULL, HFILL
1826 { &hf_spdy_associated_streamid,
1827 { "Associated Stream ID", "spdy.associated.streamid",
1828 FT_UINT32, BASE_DEC, NULL, SPDY_STREAM_ID_MASK,
1829 NULL, HFILL
1832 { &hf_spdy_priority,
1833 { "Priority", "spdy.priority",
1834 FT_UINT16, BASE_DEC, NULL, 0xE000,
1835 NULL, HFILL
1838 { &hf_spdy_unused,
1839 { "Unused", "spdy.unused",
1840 FT_UINT16, BASE_HEX, NULL, 0x1F00,
1841 "Reserved for future use", HFILL
1844 { &hf_spdy_slot,
1845 { "Slot", "spdy.slot",
1846 FT_UINT16, BASE_DEC, NULL, 0x00FF,
1847 "Specifying the index in the server's CREDENTIAL vector of the client certificate to be used for this request", HFILL
1850 { &hf_spdy_num_headers,
1851 { "Number of headers", "spdy.numheaders",
1852 FT_UINT32, BASE_DEC, NULL, 0x0,
1853 NULL, HFILL
1856 { &hf_spdy_rst_stream_status,
1857 { "Reset Status", "spdy.rst_stream_status",
1858 FT_UINT32, BASE_DEC, VALS(rst_stream_status_names), 0x0,
1859 NULL, HFILL
1862 { &hf_spdy_num_settings,
1863 { "Number of Settings", "spdy.num_settings",
1864 FT_UINT32, BASE_DEC, NULL, 0x0,
1865 NULL, HFILL
1868 { &hf_spdy_setting,
1869 { "Setting", "spdy.setting",
1870 FT_NONE, BASE_NONE, NULL, 0x0,
1871 NULL, HFILL
1874 { &hf_spdy_setting_id,
1875 { "ID", "spdy.setting.id",
1876 FT_UINT24, BASE_DEC, VALS(setting_id_names), 0x0,
1877 NULL, HFILL
1880 { &hf_spdy_setting_value,
1881 { "Value", "spdy.setting.value",
1882 FT_UINT32, BASE_DEC, NULL, 0x0,
1883 NULL, HFILL
1886 { &hf_spdy_ping_id,
1887 { "Ping ID", "spdy.ping_id",
1888 FT_UINT32, BASE_DEC, NULL, 0x0,
1889 NULL, HFILL
1892 { &hf_spdy_goaway_last_good_stream_id,
1893 { "Last Good Stream ID", "spdy.goaway_last_good_stream_id",
1894 FT_UINT32, BASE_DEC, NULL, SPDY_STREAM_ID_MASK,
1895 NULL, HFILL
1898 { &hf_spdy_goaway_status,
1899 { "Go Away Status", "spdy.goaway_status",
1900 FT_UINT32, BASE_DEC, VALS(goaway_status_names), 0x0,
1901 NULL, HFILL
1904 { &hf_spdy_window_update_delta,
1905 { "Window Update Delta", "spdy.window_update_delta",
1906 FT_UINT32, BASE_DEC, NULL, 0x7FFFFFFF,
1907 NULL, HFILL
1911 static int *ett[] = {
1912 &ett_spdy,
1913 &ett_spdy_flags,
1914 &ett_spdy_header_block,
1915 &ett_spdy_header,
1916 &ett_spdy_setting,
1917 &ett_spdy_encoded_entity,
1920 static ei_register_info ei[] = {
1921 { &ei_spdy_inflation_failed, { "spdy.inflation_failed", PI_UNDECODED, PI_ERROR, "Inflation failed. Aborting.", EXPFILL }},
1922 { &ei_spdy_mal_frame_data, { "spdy.malformed.frame_data", PI_MALFORMED, PI_ERROR, "Not enough frame data", EXPFILL }},
1923 { &ei_spdy_mal_setting_frame, { "spdy.malformed.setting_frame", PI_MALFORMED, PI_ERROR, "SETTINGS frame too small for number of entries field.", EXPFILL }},
1924 { &ei_spdy_invalid_rst_stream, { "spdy.rst_stream.invalid", PI_PROTOCOL, PI_WARN, "Invalid status code for RST_STREAM", EXPFILL }},
1925 { &ei_spdy_invalid_go_away, { "spdy.goaway.invalid", PI_PROTOCOL, PI_WARN, "Invalid status code for GOAWAY", EXPFILL }},
1926 { &ei_spdy_invalid_frame_type, { "spdy.type.invalid", PI_PROTOCOL, PI_WARN, "Invalid SPDY frame type", EXPFILL }},
1927 { &ei_spdy_reassembly_info, { "spdy.reassembly_info", PI_REASSEMBLE, PI_CHAT, "Assembled from frames in packet(s)", EXPFILL }},
1930 module_t *spdy_module;
1931 expert_module_t* expert_spdy;
1933 proto_spdy = proto_register_protocol("SPDY", "SPDY", "spdy");
1934 proto_register_field_array(proto_spdy, hf, array_length(hf));
1935 proto_register_subtree_array(ett, array_length(ett));
1936 expert_spdy = expert_register_protocol(proto_spdy);
1937 expert_register_field_array(expert_spdy, ei, array_length(ei));
1939 spdy_handle = register_dissector("spdy", dissect_spdy, proto_spdy);
1941 spdy_module = prefs_register_protocol(proto_spdy, NULL);
1942 prefs_register_bool_preference(spdy_module, "assemble_data_frames",
1943 "Assemble SPDY bodies that consist of multiple DATA frames",
1944 "Whether the SPDY dissector should reassemble multiple "
1945 "data frames into an entity body.",
1946 &spdy_assemble_entity_bodies);
1948 prefs_register_bool_preference(spdy_module, "decompress_headers",
1949 "Uncompress SPDY headers",
1950 "Whether to uncompress SPDY headers.",
1951 &spdy_decompress_headers);
1952 prefs_register_bool_preference(spdy_module, "decompress_body",
1953 "Uncompress entity bodies",
1954 "Whether to uncompress entity bodies that are compressed "
1955 "using \"Content-Encoding: \"",
1956 &spdy_decompress_body);
1958 register_init_routine(&spdy_init_protocol);
1961 * Register for tapping
1963 spdy_tap = register_tap("spdy"); /* SPDY statistics tap */
1964 spdy_eo_tap = register_tap("spdy_eo"); /* SPDY Export Object tap */
1967 void proto_reg_handoff_spdy(void) {
1969 dissector_add_uint_with_preference("tcp.port", TCP_PORT_SPDY, spdy_handle);
1970 /* Use "0" to avoid overwriting HTTPS port and still offer support over TLS */
1971 ssl_dissector_add(0, spdy_handle);
1972 dissector_add_string("http.upgrade", "spdy", spdy_handle);
1974 media_handle = find_dissector_add_dependency("media", proto_spdy);
1975 port_subdissector_table = find_dissector_table("http.port");
1976 media_type_subdissector_table = find_dissector_table("media_type");
1978 /* Weak heuristic, so disabled by default */
1979 heur_dissector_add("tcp", dissect_spdy_heur, "SPDY over TCP", "spdy_tcp", proto_spdy, HEURISTIC_DISABLE);
1983 * Editor modelines
1985 * Local Variables:
1986 * c-basic-offset: 2
1987 * tab-width: 8
1988 * indent-tabs-mode: nil
1989 * End:
1991 * ex: set shiftwidth=2 tabstop=8 expandtab:
1992 * :indentSize=4:tabSize=8:noTabs=true: