Coverage Report

Created: 2025-08-04 07:15

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