Coverage Report

Created: 2025-02-15 06:25

/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 "packet-tcp.h"
32
#include "packet-tls.h"
33
#include "packet-media-type.h"
34
35
#if defined(HAVE_ZLIB) && !defined(HAVE_ZLIBNG)
36
#define ZLIB_CONST
37
6
#define ZLIB_PREFIX(x) x
38
#include <zlib.h>
39
typedef z_stream zlib_stream;
40
#endif /* HAVE_ZLIB */
41
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 */
47
48
void proto_register_spdy(void);
49
void proto_reg_handoff_spdy(void);
50
51
0
#define MIN_SPDY_VERSION 3
52
53
57
#define SPDY_STREAM_ID_MASK 0x7FFFFFFF
54
55
/*
56
 * Conversation data - used for assembling multi-data-frame
57
 * entities and for decompressing request & reply header blocks.
58
 */
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;
73
74
75
/* The types of SPDY frames */
76
45
#define SPDY_DATA           0
77
30
#define SPDY_SYN_STREAM     1
78
15
#define SPDY_SYN_REPLY      2
79
0
#define SPDY_RST_STREAM     3
80
15
#define SPDY_SETTINGS       4
81
0
#define SPDY_PING           6
82
0
#define SPDY_GOAWAY         7
83
0
#define SPDY_HEADERS        8
84
0
#define SPDY_WINDOW_UPDATE  9
85
0
#define SPDY_CREDENTIAL    10
86
1
#define SPDY_INVALID       11
87
88
29
#define SPDY_FLAG_FIN  0x01
89
14
#define SPDY_FLAG_UNIDIRECTIONAL 0x02
90
14
#define SPDY_FLAG_SETTINGS_CLEAR_SETTINGS 0x01
91
92
/* Flags for each setting in a SETTINGS frame. */
93
14
#define SPDY_FLAG_SETTINGS_PERSIST_VALUE 0x01
94
14
#define SPDY_FLAG_SETTINGS_PERSISTED 0x02
95
96
14
#define TCP_PORT_SPDY 6121
97
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 }
111
};
112
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 }
127
};
128
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 }
138
};
139
140
static const value_string goaway_status_names[] = {
141
  { 0,  "OK" },
142
  { 1,  "PROTOCOL_ERROR" },
143
  { 11, "INTERNAL_ERROR" },
144
  { 0, NULL }
145
};
146
147
/*
148
 * This structure will be tied to each SPDY frame and is used as an argument for
149
 * dissect_spdy_*_payload() functions.
150
 */
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;
158
159
/*
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.
163
 */
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;
170
171
static wmem_list_t *header_info_list;
172
173
/*
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.
177
 */
178
typedef struct _spdy_data_frame_t {
179
  uint8_t *data;
180
  uint32_t length;
181
  uint32_t framenum;
182
} spdy_data_frame_t;
183
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;
193
194
/* Handles for metadata population. */
195
196
static int spdy_tap;
197
static int spdy_eo_tap;
198
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;
230
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;
236
237
static int ett_spdy_encoded_entity;
238
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;
246
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;
251
252
static bool spdy_assemble_entity_bodies = true;
253
254
/*
255
 * Decompression of zlib encoded entities.
256
 */
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
264
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 -   */
445
};
446
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?
450
 */
451
static bool inflate_end_cb (wmem_allocator_t *allocator _U_,
452
0
    wmem_cb_event_t event _U_, void *user_data) {
453
#ifdef HAVE_ZLIBNG
454
  ZLIB_PREFIX(inflateEnd)((zng_streamp)user_data);
455
#else
456
0
  ZLIB_PREFIX(inflateEnd)((z_streamp)user_data);
457
0
#endif
458
0
  return false;
459
0
}
460
#endif
461
462
/*
463
 * Protocol initialization
464
 */
465
static void
466
spdy_init_protocol(void)
467
14
{
468
14
   header_info_list = NULL;
469
14
}
470
471
/*
472
 * Returns conversation data for a given packet. If conversation data can't be
473
 * found, creates and returns new conversation data.
474
 */
475
16
static spdy_conv_t * get_or_create_spdy_conversation_data(packet_info *pinfo) {
476
16
  conversation_t  *conversation;
477
16
  spdy_conv_t *conv_data;
478
16
#if defined (HAVE_ZLIB) || defined (HAVE_ZLIBNG)
479
16
  int retcode;
480
16
#endif
481
482
16
  conversation = find_or_create_conversation(pinfo);
483
484
  /* Retrieve information from conversation */
485
16
  conv_data = (spdy_conv_t *)conversation_get_proto_data(conversation, proto_spdy);
486
16
  if (!conv_data) {
487
    /* Set up the conversation structure itself */
488
3
    conv_data = wmem_new0(wmem_file_scope(), spdy_conv_t);
489
490
3
    conv_data->streams = NULL;
491
3
    if (spdy_decompress_headers) {
492
3
#if defined (HAVE_ZLIB) || defined (HAVE_ZLIBNG)
493
3
      conv_data->rqst_decompressor = wmem_new0(wmem_file_scope(), zlib_stream);
494
3
      conv_data->rply_decompressor = wmem_new0(wmem_file_scope(), zlib_stream);
495
3
      retcode = ZLIB_PREFIX(inflateInit)(conv_data->rqst_decompressor);
496
3
      if (retcode == Z_OK) {
497
3
        wmem_register_callback(wmem_file_scope(), inflate_end_cb,
498
3
            conv_data->rqst_decompressor);
499
3
        retcode = ZLIB_PREFIX(inflateInit)(conv_data->rply_decompressor);
500
3
        if (retcode == Z_OK) {
501
3
          wmem_register_callback(wmem_file_scope(), inflate_end_cb,
502
3
              conv_data->rply_decompressor);
503
3
        }
504
3
      }
505
506
      /* XXX - use wsutil/adler32.h? */
507
3
      conv_data->dictionary_id = ZLIB_PREFIX(adler32)(0L, Z_NULL, 0);
508
3
      conv_data->dictionary_id = ZLIB_PREFIX(adler32)(conv_data->dictionary_id,
509
3
                                         spdy_dictionary,
510
3
                                         (uInt)sizeof(spdy_dictionary));
511
3
#endif
512
3
    }
513
514
3
    conversation_add_proto_data(conversation, proto_spdy, conv_data);
515
3
  }
516
517
16
  return conv_data;
518
16
}
519
520
/*
521
 * Retains state on a given stream.
522
 */
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
0
                                  char *content_encoding) {
529
0
  spdy_stream_info_t *si;
530
531
0
  if (conv_data->streams == NULL) {
532
0
    conv_data->streams = wmem_tree_new(wmem_file_scope());
533
0
  }
534
535
0
  si = wmem_new(wmem_file_scope(), spdy_stream_info_t);
536
0
  si->container_type = container_type;
537
0
  si->content_type = content_type;
538
0
  si->content_type_parameters = content_type_params;
539
0
  si->content_encoding = content_encoding;
540
0
  si->data_frames = wmem_list_new(wmem_file_scope());
541
0
  si->num_data_frames = 0;
542
0
  si->assembled_data = NULL;
543
0
  wmem_tree_insert32(conv_data->streams, stream_id, si);
544
0
}
545
546
/*
547
 * Retrieves previously saved state on a given stream.
548
 */
549
static spdy_stream_info_t* spdy_get_stream_info(spdy_conv_t *conv_data,
550
                                                uint32_t stream_id)
551
11
{
552
11
  if (conv_data->streams == NULL)
553
11
    return NULL;
554
555
0
  return (spdy_stream_info_t*)wmem_tree_lookup32(conv_data->streams, stream_id);
556
11
}
557
558
/*
559
 * Adds a data chunk to a given SPDY conversation/stream.
560
 */
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)
566
0
{
567
0
  spdy_stream_info_t *si = spdy_get_stream_info(conv_data, stream_id);
568
569
0
  if (si != NULL) {
570
0
    spdy_data_frame_t *df = (spdy_data_frame_t *)wmem_new(wmem_file_scope(), spdy_data_frame_t);
571
0
    df->data = data;
572
0
    df->length = length;
573
0
    df->framenum = frame;
574
0
    wmem_list_append(si->data_frames, df);
575
0
    ++si->num_data_frames;
576
0
  }
577
0
}
578
579
/*
580
 * Increment the count of DATA frames found on a given stream.
581
 */
582
static void spdy_increment_data_chunk_count(spdy_conv_t *conv_data,
583
0
                                            uint32_t stream_id) {
584
0
  spdy_stream_info_t *si = spdy_get_stream_info(conv_data, stream_id);
585
0
  if (si != NULL) {
586
0
    ++si->num_data_frames;
587
0
  }
588
0
}
589
590
/*
591
 * Return the number of data frames saved so far for the specified stream.
592
 */
593
static unsigned spdy_get_num_data_frames(spdy_conv_t *conv_data,
594
11
                                      uint32_t stream_id) {
595
11
  spdy_stream_info_t *si = spdy_get_stream_info(conv_data, stream_id);
596
597
11
  return si == NULL ? 0 : si->num_data_frames;
598
11
}
599
600
/*
601
 * Reassembles DATA frames for a given stream into one tvb.
602
 */
603
static spdy_stream_info_t* spdy_assemble_data_frames(spdy_conv_t *conv_data,
604
0
                                                     uint32_t stream_id) {
605
0
  spdy_stream_info_t *si = spdy_get_stream_info(conv_data, stream_id);
606
0
  tvbuff_t *tvb;
607
608
0
  if (si == NULL) {
609
0
    return NULL;
610
0
  }
611
612
  /*
613
   * Compute the total amount of data and concatenate the
614
   * data chunks, if it hasn't already been done.
615
   */
616
0
  if (si->assembled_data == NULL) {
617
0
    spdy_data_frame_t *df;
618
0
    uint8_t *data;
619
0
    uint32_t datalen;
620
0
    uint32_t offset;
621
0
    wmem_list_t *dflist = si->data_frames;
622
0
    wmem_list_frame_t *frame;
623
0
    if (wmem_list_count(dflist) == 0) {
624
0
      return si;
625
0
    }
626
0
    datalen = 0;
627
    /*
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.
632
     */
633
0
    frame = wmem_list_frame_next(wmem_list_head(dflist));
634
0
    while (frame != NULL) {
635
0
      df = (spdy_data_frame_t *)wmem_list_frame_data(frame);
636
0
      datalen += df->length;
637
0
      frame = wmem_list_frame_next(frame);
638
0
    }
639
0
    if (datalen != 0) {
640
0
      data = (uint8_t *)wmem_alloc(wmem_file_scope(), datalen);
641
0
      dflist = si->data_frames;
642
0
      offset = 0;
643
0
      frame = wmem_list_frame_next(wmem_list_head(dflist));
644
0
      while (frame != NULL) {
645
0
        df = (spdy_data_frame_t *)wmem_list_frame_data(frame);
646
0
        memcpy(data+offset, df->data, df->length);
647
0
        offset += df->length;
648
0
        frame = wmem_list_frame_next(frame);
649
0
      }
650
0
      tvb = tvb_new_real_data(data, datalen, datalen);
651
0
      si->assembled_data = tvb;
652
0
    }
653
0
  }
654
0
  return si;
655
0
}
656
657
/*
658
 * Same as dissect_spdy_stream_id below, except with explicit field index.
659
 */
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)
665
0
{
666
0
  uint32_t stream_id = tvb_get_ntohl(tvb, offset) & SPDY_STREAM_ID_MASK;
667
668
  /* Add stream id to tree. */
669
0
  proto_tree_add_item(frame_tree, hfindex, tvb, offset, 4, ENC_BIG_ENDIAN);
670
671
0
  if (hfindex == hf_spdy_streamid) {
672
0
    proto_item_append_text(frame_tree, ", Stream: %u", stream_id);
673
0
  }
674
0
}
675
676
/*
677
 * Adds flag details to proto tree.
678
 */
679
static void dissect_spdy_flags(tvbuff_t *tvb,
680
                               int offset,
681
                               proto_tree *frame_tree,
682
15
                               const spdy_control_frame_info_t *frame) {
683
15
  proto_item *flags_ti;
684
15
  proto_tree *flags_tree;
685
686
  /* Create flags substree. */
687
15
  flags_ti = proto_tree_add_item(frame_tree, hf_spdy_flags, tvb, offset, 1, ENC_BIG_ENDIAN);
688
15
  flags_tree = proto_item_add_subtree(flags_ti, ett_spdy_flags);
689
690
  /* Add FIN flag for appropriate frames. */
691
15
  if (frame->type == SPDY_DATA ||
692
15
      frame->type == SPDY_SYN_STREAM ||
693
15
      frame->type == SPDY_SYN_REPLY ||
694
15
      frame->type == SPDY_HEADERS) {
695
    /* Add FIN flag. */
696
15
    proto_tree_add_item(flags_tree, hf_spdy_flags_fin, tvb, offset, 1, ENC_BIG_ENDIAN);
697
15
    if (frame->flags & SPDY_FLAG_FIN) {
698
1
      proto_item_append_text(frame_tree, " (FIN)");
699
1
      proto_item_append_text(flags_ti, " (FIN)");
700
1
    }
701
15
  }
702
703
  /* Add UNIDIRECTIONAL flag, only applicable for SYN_STREAM. */
704
15
  if (frame->type == SPDY_SYN_STREAM) {
705
0
    proto_tree_add_item(flags_tree, hf_spdy_flags_unidirectional, tvb,
706
0
                        offset, 1, ENC_BIG_ENDIAN);
707
0
    if (frame->flags & SPDY_FLAG_UNIDIRECTIONAL) {
708
0
      proto_item_append_text(flags_ti, " (UNIDIRECTIONAL)");
709
0
    }
710
0
  }
711
712
  /* Add CLEAR_SETTINGS flag, only applicable for SETTINGS. */
713
15
  if (frame->type == SPDY_SETTINGS) {
714
0
    proto_tree_add_item(flags_tree, hf_spdy_flags_clear_settings, tvb,
715
0
                        offset, 1, ENC_BIG_ENDIAN);
716
0
    if (frame->flags & SPDY_FLAG_SETTINGS_CLEAR_SETTINGS) {
717
0
      proto_item_append_text(flags_ti, " (CLEAR)");
718
0
    }
719
0
  }
720
15
}
721
722
/*
723
 * Performs DATA frame payload dissection.
724
 */
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)
734
15
{
735
15
  dissector_handle_t handle;
736
15
  unsigned num_data_frames;
737
15
  bool dissected;
738
15
  media_content_info_t content_info;
739
740
  /* Add frame description. */
741
15
  proto_item_append_text(spdy_proto, ", Stream: %d, Length: %d",
742
15
                           stream_id,
743
15
                           frame->length);
744
745
  /* Add data. */
746
15
  proto_tree_add_item(spdy_tree, hf_spdy_data, tvb, offset, frame->length, ENC_NA);
747
748
15
  num_data_frames = spdy_get_num_data_frames(conv_data, stream_id);
749
15
  if (frame->length != 0 || num_data_frames != 0) {
750
    /*
751
     * There's stuff left over; process it.
752
     */
753
0
    tvbuff_t *next_tvb = NULL;
754
0
    tvbuff_t    *data_tvb = NULL;
755
0
    spdy_stream_info_t *si = NULL;
756
0
    uint8_t *copied_data;
757
0
    bool is_single_chunk = false;
758
0
    bool have_entire_body;
759
0
    char *media_str = NULL;
760
761
    /*
762
     * Create a tvbuff for the payload.
763
     */
764
0
    if (frame->length != 0) {
765
0
      next_tvb = tvb_new_subset_length(tvb, offset, frame->length);
766
0
      is_single_chunk = num_data_frames == 0 &&
767
0
          (frame->flags & SPDY_FLAG_FIN) != 0;
768
0
      if (!pinfo->fd->visited) {
769
0
        if (!is_single_chunk) {
770
0
          if (spdy_assemble_entity_bodies) {
771
0
            copied_data = (uint8_t *)tvb_memdup(wmem_file_scope(),next_tvb, 0, frame->length);
772
0
            spdy_add_data_chunk(conv_data, stream_id, pinfo->num, copied_data, frame->length);
773
0
          } else {
774
0
            spdy_increment_data_chunk_count(conv_data, stream_id);
775
0
          }
776
0
        }
777
0
      }
778
0
    } else {
779
0
      is_single_chunk = (num_data_frames == 1);
780
0
    }
781
782
0
    if (!(frame->flags & SPDY_FLAG_FIN)) {
783
0
      col_set_fence(pinfo->cinfo, COL_INFO);
784
0
      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
0
      goto body_dissected;
788
0
    }
789
0
    have_entire_body = is_single_chunk;
790
    /*
791
     * On seeing the last data frame in a stream, we can
792
     * reassemble the frames into one data block.
793
     */
794
0
    si = spdy_assemble_data_frames(conv_data, stream_id);
795
0
    if (si == NULL) {
796
0
      goto body_dissected;
797
0
    }
798
0
    data_tvb = si->assembled_data;
799
0
    if (spdy_assemble_entity_bodies) {
800
0
      have_entire_body = true;
801
0
    }
802
803
0
    if (!have_entire_body) {
804
0
      goto body_dissected;
805
0
    }
806
807
0
    if (data_tvb == NULL) {
808
0
      if (next_tvb == NULL)
809
0
        goto body_dissected;
810
0
      data_tvb = next_tvb;
811
0
    } else {
812
0
      add_new_data_source(pinfo, data_tvb, "Assembled entity body");
813
0
    }
814
815
0
    if (have_entire_body && si->content_encoding != NULL &&
816
0
      g_ascii_strcasecmp(si->content_encoding, "identity") != 0) {
817
      /*
818
       * We currently can't handle, for example, "compress";
819
       * just handle them as data for now.
820
       *
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.
825
       */
826
0
      tvbuff_t *uncomp_tvb = NULL;
827
0
      proto_item *e_ti = NULL;
828
0
      proto_tree *e_tree = NULL;
829
830
0
      if (spdy_decompress_body &&
831
0
          (g_ascii_strcasecmp(si->content_encoding, "gzip") == 0 ||
832
0
           g_ascii_strcasecmp(si->content_encoding, "deflate") == 0)) {
833
0
        uncomp_tvb = tvb_child_uncompress_zlib(tvb, data_tvb, 0,
834
0
                                               tvb_reported_length(data_tvb));
835
0
      }
836
      /*
837
       * Add the encoded entity to the protocol tree
838
       */
839
0
      e_tree = proto_tree_add_subtree_format(spdy_tree, data_tvb,
840
0
                                 0, tvb_reported_length(data_tvb), ett_spdy_encoded_entity, &e_ti,
841
0
                                 "Content-encoded entity body (%s): %u bytes",
842
0
                                 si->content_encoding,
843
0
                                 tvb_reported_length(data_tvb));
844
0
      if (si->num_data_frames > 1) {
845
0
        wmem_list_t *dflist = si->data_frames;
846
0
        wmem_list_frame_t *frame_item;
847
0
        spdy_data_frame_t *df;
848
0
        uint32_t framenum = 0;
849
0
        wmem_strbuf_t *str_frames = wmem_strbuf_new(pinfo->pool, "");
850
851
0
        frame_item = wmem_list_frame_next(wmem_list_head(dflist));
852
0
        while (frame_item != NULL) {
853
0
          df = (spdy_data_frame_t *)wmem_list_frame_data(frame_item);
854
0
          if (framenum != df->framenum) {
855
0
            wmem_strbuf_append_printf(str_frames, " #%u", df->framenum);
856
0
            framenum = df->framenum;
857
0
          }
858
0
          frame_item = wmem_list_frame_next(frame_item);
859
0
        }
860
861
0
        proto_tree_add_expert_format(e_tree, pinfo, &ei_spdy_reassembly_info, data_tvb, 0,
862
0
                                    tvb_reported_length(data_tvb),
863
0
                                    "Assembled from %d frames in packet(s)%s",
864
0
                                    si->num_data_frames, wmem_strbuf_get_str(str_frames));
865
0
      }
866
867
0
      if (uncomp_tvb != NULL) {
868
        /*
869
         * Decompression worked
870
         */
871
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.
876
         *
877
         tvb_free(next_tvb);
878
         */
879
0
        proto_item_append_text(e_ti, " -> %u bytes", tvb_reported_length(uncomp_tvb));
880
0
        data_tvb = uncomp_tvb;
881
0
        add_new_data_source(pinfo, data_tvb, "Uncompressed entity body");
882
0
      } else {
883
0
        if (spdy_decompress_body) {
884
0
          proto_item_append_text(e_ti, " [Error: Decompression failed]");
885
0
        }
886
0
        call_data_dissector(data_tvb, pinfo, e_tree);
887
888
0
        goto body_dissected;
889
0
      }
890
0
    }
891
892
    /*
893
     * Do subdissector checks.
894
     *
895
     * First, check whether some subdissector asked that they
896
     * be called if something was on some particular port.
897
     */
898
899
0
    if (have_entire_body && port_subdissector_table != NULL) {
900
0
      handle = dissector_get_uint_handle(port_subdissector_table,
901
0
                                         pinfo->match_uint);
902
0
    } else {
903
0
      handle = NULL;
904
0
    }
905
0
    if (handle == NULL && have_entire_body && si->content_type != NULL &&
906
0
      media_type_subdissector_table != NULL) {
907
      /*
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?
912
       */
913
0
      if (si->content_type_parameters) {
914
0
        media_str = wmem_strdup(pinfo->pool, si->content_type_parameters);
915
0
      }
916
      /*
917
       * Calling the string handle for the media type
918
       * dissector table will set pinfo->match_string
919
       * to si->content_type for us.
920
       */
921
0
      pinfo->match_string = si->content_type;
922
0
      handle = dissector_get_string_handle(media_type_subdissector_table,
923
0
                                           si->content_type);
924
0
    }
925
0
    content_info.type = si->container_type;
926
0
    content_info.media_str = media_str;
927
0
    content_info.data = NULL;
928
0
    if (handle != NULL) {
929
      /*
930
       * We have a subdissector - call it.
931
       */
932
0
      dissected = call_dissector_with_data(handle, data_tvb, pinfo, spdy_tree, &content_info);
933
0
    } else {
934
0
      dissected = false;
935
0
    }
936
937
0
    if (!dissected && have_entire_body && si->content_type != NULL) {
938
      /*
939
       * Calling the default media handle if there is a content-type that
940
       * wasn't handled above.
941
       */
942
0
      call_dissector_with_data(media_handle, next_tvb, pinfo, spdy_tree, &content_info);
943
0
    } else {
944
      /* Call the default data dissector */
945
0
      call_data_dissector(next_tvb, pinfo, spdy_tree);
946
0
    }
947
948
0
body_dissected:
949
    /*
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.
953
     */
954
0
    ;
955
0
  }
956
15
  return frame->length;
957
15
}
958
959
#if defined (HAVE_ZLIB) || defined (HAVE_ZLIBNG)
960
/*
961
 * Performs header decompression.
962
 *
963
 * The returned buffer is automatically scoped to the lifetime of the capture
964
 * (via wmem_memdup() with file scope).
965
 */
966
0
#define DECOMPRESS_BUFSIZE   16384
967
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
0
                                            unsigned *uncomp_length) {
979
0
  int retcode;
980
0
  const uint8_t *hptr = tvb_get_ptr(tvb, offset, length);
981
0
  uint8_t *uncomp_block = (uint8_t *)wmem_alloc(pinfo->pool, DECOMPRESS_BUFSIZE);
982
983
0
#ifdef z_const
984
0
  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
0
  decomp->avail_in = length;
991
0
  decomp->next_out = uncomp_block;
992
0
  decomp->avail_out = DECOMPRESS_BUFSIZE;
993
0
  retcode = ZLIB_PREFIX(inflate)(decomp, Z_SYNC_FLUSH);
994
0
  if (retcode == Z_NEED_DICT) {
995
0
    if (decomp->adler == dictionary_id) {
996
0
      retcode = ZLIB_PREFIX(inflateSetDictionary)(decomp,
997
0
                                     spdy_dictionary,
998
0
                                     sizeof(spdy_dictionary));
999
0
      if (retcode == Z_OK) {
1000
0
        retcode = ZLIB_PREFIX(inflate)(decomp, Z_SYNC_FLUSH);
1001
0
      }
1002
0
    }
1003
0
  }
1004
1005
  /* Handle errors. */
1006
0
  if (retcode != Z_OK) {
1007
0
    return NULL;
1008
0
  }
1009
1010
  /* Handle successful inflation. */
1011
0
  *uncomp_length = DECOMPRESS_BUFSIZE - decomp->avail_out;
1012
1013
0
  return (uint8_t *)wmem_memdup(wmem_file_scope(), uncomp_block, *uncomp_length);
1014
0
}
1015
#endif
1016
1017
1018
/*
1019
 * Saves state on header data for a given stream.
1020
 */
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
0
                                                  unsigned length) {
1026
0
  spdy_header_info_t *header_info;
1027
1028
0
  if (header_info_list == NULL)
1029
0
    header_info_list = wmem_list_new(wmem_file_scope());
1030
1031
0
  header_info = wmem_new(wmem_file_scope(), spdy_header_info_t);
1032
0
  header_info->stream_id = stream_id;
1033
0
  header_info->header_block = header;
1034
0
  header_info->header_block_len = length;
1035
0
  header_info->frame_type = frame_type;
1036
0
  wmem_list_append(header_info_list, header_info);
1037
0
  return header_info;
1038
0
}
1039
1040
/*
1041
 * Retrieves saved state for a given stream.
1042
 */
1043
static spdy_header_info_t* spdy_find_saved_header_block(packet_info *pinfo _U_,
1044
                                                        uint32_t stream_id,
1045
0
                                                        uint16_t frame_type) {
1046
0
  wmem_list_frame_t *frame;
1047
1048
0
  if ((header_info_list == NULL) || (wmem_list_head(header_info_list) == NULL))
1049
0
      return NULL;
1050
1051
0
  frame = wmem_list_frame_next(wmem_list_head(header_info_list));
1052
0
  while (frame != NULL) {
1053
0
      spdy_header_info_t *hi = (spdy_header_info_t *)wmem_list_frame_data(frame);
1054
0
      if (hi->stream_id == stream_id && hi->frame_type == frame_type)
1055
0
          return hi;
1056
0
      frame = wmem_list_frame_next(frame);
1057
0
  }
1058
0
  return NULL;
1059
0
}
1060
1061
/*
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.
1066
 */
1067
0
static char* spdy_parse_content_type(char *content_type) {
1068
0
  char *cp = content_type;
1069
1070
0
  while (*cp != '\0' && *cp != ';' && !g_ascii_isspace(*cp)) {
1071
0
    *cp = g_ascii_tolower(*cp);
1072
0
    ++cp;
1073
0
  }
1074
0
  if (*cp == '\0') {
1075
0
    cp = NULL;
1076
0
  }
1077
1078
0
  if (cp != NULL) {
1079
0
    *cp++ = '\0';
1080
0
    while (*cp == ';' || g_ascii_isspace(*cp)) {
1081
0
      ++cp;
1082
0
    }
1083
0
    if (*cp != '\0') {
1084
0
      return cp;
1085
0
    }
1086
0
  }
1087
0
  return NULL;
1088
0
}
1089
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
0
  spdy_conv_t *conv_data) {
1097
0
  uint32_t stream_id;
1098
0
  int header_block_length = frame->length;
1099
0
  int hdr_offset = 0;
1100
0
  tvbuff_t *header_tvb = NULL;
1101
0
  const char *hdr_method = NULL;
1102
0
  const char *hdr_path = NULL;
1103
0
  const char *hdr_version = NULL;
1104
0
  const char *hdr_host = NULL;
1105
0
  const char *hdr_scheme = NULL;
1106
0
  const char *hdr_status = NULL;
1107
0
  char *content_type = NULL;
1108
0
  char *content_encoding = NULL;
1109
0
  uint32_t num_headers = 0;
1110
0
  proto_item *header_block_item;
1111
0
  proto_tree *header_block_tree;
1112
1113
  /* Get stream id, which is present in all types of header frames. */
1114
0
  stream_id = tvb_get_ntohl(tvb, offset) & SPDY_STREAM_ID_MASK;
1115
0
  dissect_spdy_stream_id_field(tvb, offset, pinfo, frame_tree, hf_spdy_streamid);
1116
0
  offset += 4;
1117
1118
  /* Get SYN_STREAM-only fields. */
1119
0
  if (frame->type == SPDY_SYN_STREAM) {
1120
    /* Get associated stream ID. */
1121
0
    dissect_spdy_stream_id_field(tvb, offset, pinfo, frame_tree, hf_spdy_associated_streamid);
1122
0
    offset += 4;
1123
1124
    /* Get priority */
1125
0
    proto_tree_add_item(frame_tree, hf_spdy_priority, tvb, offset, 2, ENC_BIG_ENDIAN);
1126
0
    proto_tree_add_item(frame_tree, hf_spdy_unused, tvb, offset, 2, ENC_BIG_ENDIAN);
1127
0
    proto_tree_add_item(frame_tree, hf_spdy_slot, tvb, offset, 2, ENC_BIG_ENDIAN);
1128
0
    offset += 2;
1129
0
  }
1130
1131
1132
  /* Get our header block length. */
1133
0
  switch (frame->type) {
1134
0
    case SPDY_SYN_STREAM:
1135
0
      header_block_length -= 10;
1136
0
      break;
1137
0
    case SPDY_SYN_REPLY:
1138
0
    case SPDY_HEADERS:
1139
0
      header_block_length -= 4;
1140
0
      break;
1141
0
    default:
1142
      /* Unhandled case. This should never happen. */
1143
0
      DISSECTOR_ASSERT_NOT_REACHED();
1144
0
  }
1145
1146
  /* Add the header block. */
1147
0
  header_block_item = proto_tree_add_item(frame_tree,
1148
0
                                            hf_spdy_header_block,
1149
0
                                            tvb,
1150
0
                                            offset,
1151
0
                                            header_block_length,
1152
0
                                            ENC_NA);
1153
0
  header_block_tree = proto_item_add_subtree(header_block_item,
1154
0
                                               ett_spdy_header_block);
1155
1156
  /* Decompress header block as necessary. */
1157
0
  if (!spdy_decompress_headers) {
1158
0
    header_tvb = tvb;
1159
0
    hdr_offset = offset;
1160
0
  } else {
1161
0
    spdy_header_info_t *header_info;
1162
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
0
    header_info = spdy_find_saved_header_block(pinfo,
1168
0
                                               stream_id,
1169
0
                                               frame->type);
1170
1171
    /* Generate decompressed data and store it, since none was found. */
1172
0
    if (header_info == NULL) {
1173
0
      uint8_t *uncomp_ptr = NULL;
1174
0
      unsigned uncomp_length = 0;
1175
0
#if defined (HAVE_ZLIB) || defined (HAVE_ZLIBNG)
1176
#ifdef HAVE_ZLIBNG
1177
      zng_streamp decomp;
1178
#else
1179
0
      z_streamp decomp;
1180
0
#endif
1181
1182
      /* Get our decompressor. */
1183
0
      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
0
        decomp = conv_data->rply_decompressor;
1187
0
      } 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
0
        decomp = conv_data->rply_decompressor;
1192
0
      } else if (frame->type == SPDY_SYN_STREAM) {
1193
0
        decomp = conv_data->rqst_decompressor;
1194
0
      } else if (frame->type == SPDY_SYN_REPLY) {
1195
0
        decomp = conv_data->rply_decompressor;
1196
0
      } else {
1197
        /* Unhandled case. This should never happen. */
1198
0
        DISSECTOR_ASSERT_NOT_REACHED();
1199
0
      }
1200
1201
      /* Decompress. */
1202
0
      uncomp_ptr = spdy_decompress_header_block(tvb,
1203
0
                                                pinfo,
1204
0
                                                decomp,
1205
0
                                                conv_data->dictionary_id,
1206
0
                                                offset,
1207
0
                                                header_block_length,
1208
0
                                                &uncomp_length);
1209
1210
      /* Catch decompression failures. */
1211
0
      if (uncomp_ptr == NULL) {
1212
0
        expert_add_info(pinfo, frame_tree, &ei_spdy_inflation_failed);
1213
1214
0
        proto_item_append_text(frame_tree, " [Error: Header decompression failed]");
1215
0
        return -1;
1216
0
      }
1217
0
#endif
1218
1219
      /* Store decompressed data. */
1220
0
      header_info = spdy_save_header_block(pinfo, stream_id, frame->type, uncomp_ptr, uncomp_length);
1221
0
    }
1222
1223
    /* Create a tvb containing the uncompressed data. */
1224
0
    header_tvb = tvb_new_child_real_data(tvb, header_info->header_block,
1225
0
                                         header_info->header_block_len,
1226
0
                                         header_info->header_block_len);
1227
0
    add_new_data_source(pinfo, header_tvb, "Uncompressed headers");
1228
0
    hdr_offset = 0;
1229
0
  }
1230
1231
  /* Get header block details. */
1232
0
  if (header_tvb == NULL || !spdy_decompress_headers) {
1233
0
    num_headers = 0;
1234
0
  } else {
1235
0
    num_headers = tvb_get_ntohl(header_tvb, hdr_offset);
1236
0
    /*ti = */ proto_tree_add_item(header_block_tree,
1237
0
                             hf_spdy_num_headers,
1238
0
                             header_tvb,
1239
0
                             hdr_offset,
1240
0
                             4,
1241
0
                             ENC_BIG_ENDIAN);
1242
0
  }
1243
0
  hdr_offset += 4;
1244
1245
  /* Process headers. */
1246
0
  while (num_headers--) {
1247
0
    char *header_name;
1248
0
    const char *header_value;
1249
0
    proto_tree *header_tree;
1250
0
    proto_item *header;
1251
0
    int header_name_offset;
1252
0
    int header_value_offset;
1253
0
    int header_name_length;
1254
0
    int header_value_length;
1255
1256
    /* Get header name details. */
1257
0
    if (tvb_reported_length_remaining(header_tvb, hdr_offset) < 4) {
1258
0
      expert_add_info_format(pinfo, frame_tree, &ei_spdy_mal_frame_data,
1259
0
                             "Not enough frame data for header name size.");
1260
0
      break;
1261
0
    }
1262
0
    header_name_offset = hdr_offset;
1263
0
    header_name_length = tvb_get_ntohl(header_tvb, hdr_offset);
1264
0
    hdr_offset += 4;
1265
0
    if (tvb_reported_length_remaining(header_tvb, hdr_offset) < header_name_length) {
1266
0
      expert_add_info_format(pinfo, frame_tree, &ei_spdy_mal_frame_data,
1267
0
                             "Not enough frame data for header name.");
1268
0
      break;
1269
0
    }
1270
0
    header_name = (char *)tvb_get_string_enc(pinfo->pool, header_tvb,
1271
0
                                                    hdr_offset,
1272
0
                                                    header_name_length, ENC_ASCII|ENC_NA);
1273
0
    hdr_offset += header_name_length;
1274
1275
    /* Get header value details. */
1276
0
    if (tvb_reported_length_remaining(header_tvb, hdr_offset) < 4) {
1277
0
      expert_add_info_format(pinfo, frame_tree, &ei_spdy_mal_frame_data,
1278
0
                             "Not enough frame data for header value size.");
1279
0
      break;
1280
0
    }
1281
0
    header_value_offset = hdr_offset;
1282
0
    header_value_length = tvb_get_ntohl(header_tvb, hdr_offset);
1283
0
    hdr_offset += 4;
1284
0
    if (tvb_reported_length_remaining(header_tvb, hdr_offset) < header_value_length) {
1285
0
      expert_add_info_format(pinfo, frame_tree, &ei_spdy_mal_frame_data,
1286
0
                             "Not enough frame data for header value.");
1287
0
      break;
1288
0
    }
1289
0
    header_value = (char *)tvb_get_string_enc(pinfo->pool,header_tvb,
1290
0
                                                     hdr_offset,
1291
0
                                                     header_value_length, ENC_ASCII|ENC_NA);
1292
0
    hdr_offset += header_value_length;
1293
1294
    /* Populate tree with header name/value details. */
1295
0
    if (frame_tree) {
1296
      /* Add 'Header' subtree with description. */
1297
0
      header = proto_tree_add_item(frame_tree,
1298
0
                                   hf_spdy_header,
1299
0
                                   header_tvb,
1300
0
                                   header_name_offset,
1301
0
                                   hdr_offset - header_name_offset,
1302
0
                                   ENC_NA);
1303
0
      proto_item_append_text(header, ": %s: %s", header_name, header_value);
1304
0
      header_tree = proto_item_add_subtree(header, ett_spdy_header);
1305
1306
      /* Add header name. */
1307
0
      proto_tree_add_item(header_tree, hf_spdy_header_name, header_tvb,
1308
0
                          header_name_offset, 4, ENC_ASCII|ENC_BIG_ENDIAN);
1309
1310
      /* Add header value. */
1311
0
      proto_tree_add_item(header_tree, hf_spdy_header_value, header_tvb,
1312
0
                          header_value_offset, 4, ENC_ASCII|ENC_BIG_ENDIAN);
1313
0
    }
1314
1315
    /*
1316
     * TODO(ers) check that the header name contains only legal characters.
1317
     */
1318
    /* TODO(hkhalil): Make sure that prohibited headers aren't sent. */
1319
0
    if (g_strcmp0(header_name, ":method") == 0) {
1320
0
      hdr_method = header_value;
1321
0
    } else if (g_strcmp0(header_name, ":path") == 0) {
1322
0
      hdr_path = header_value;
1323
0
    } else if (g_strcmp0(header_name, ":version") == 0) {
1324
0
      hdr_version = header_value;
1325
0
    } else if (g_strcmp0(header_name, ":host") == 0) {
1326
0
      hdr_host = header_value;
1327
0
    } else if (g_strcmp0(header_name, ":scheme") == 0) {
1328
0
      hdr_scheme = header_value;
1329
0
    } else if (g_strcmp0(header_name, ":status") == 0) {
1330
0
      hdr_status = header_value;
1331
0
    } else if (g_strcmp0(header_name, "content-type") == 0) {
1332
0
      content_type = wmem_strdup(wmem_file_scope(), header_value);
1333
0
    } else if (g_strcmp0(header_name, "content-encoding") == 0) {
1334
0
      content_encoding = wmem_strdup(wmem_file_scope(), header_value);
1335
0
    }
1336
0
  }
1337
1338
  /* Set Info column. */
1339
0
  if (hdr_version != NULL) {
1340
0
    if (hdr_status == NULL) {
1341
0
      proto_item_append_text(frame_tree, ", Request: %s %s://%s%s %s",
1342
0
                      hdr_method, hdr_scheme, hdr_host, hdr_path, hdr_version);
1343
0
    } else {
1344
0
      proto_item_append_text(frame_tree, ", Response: %s %s",
1345
0
                      hdr_status, hdr_version);
1346
0
    }
1347
0
  }
1348
1349
  /*
1350
   * If we expect data on this stream, we need to remember the content
1351
   * type and content encoding.
1352
   */
1353
0
  if (content_type != NULL && !pinfo->fd->visited) {
1354
0
    char *content_type_params = spdy_parse_content_type(content_type);
1355
0
    spdy_save_stream_info(conv_data, stream_id,
1356
0
                          (hdr_status == NULL) ? MEDIA_CONTAINER_HTTP_REQUEST : MEDIA_CONTAINER_HTTP_RESPONSE,
1357
0
                          content_type, content_type_params, content_encoding);
1358
0
  }
1359
1360
0
  return frame->length;
1361
0
}
1362
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
0
  const spdy_control_frame_info_t *frame) {
1369
0
  uint32_t rst_status;
1370
0
  proto_item *ti;
1371
0
  const char* str;
1372
1373
  /* Get stream ID and add to info column and tree. */
1374
0
  dissect_spdy_stream_id_field(tvb, offset, pinfo, frame_tree, hf_spdy_streamid);
1375
0
  offset += 4;
1376
1377
  /* Get status. */
1378
1379
0
  ti = proto_tree_add_item(frame_tree, hf_spdy_rst_stream_status, tvb, offset, 4, ENC_BIG_ENDIAN);
1380
0
  rst_status = tvb_get_ntohl(tvb, offset);
1381
0
  if (try_val_to_str(rst_status, rst_stream_status_names) == NULL) {
1382
    /* Handle boundary conditions. */
1383
0
    expert_add_info_format(pinfo, ti, &ei_spdy_invalid_rst_stream,
1384
0
                           "Invalid status code for RST_STREAM: %u", rst_status);
1385
0
  }
1386
1387
0
  str = val_to_str(rst_status, rst_stream_status_names, "Unknown (%d)");
1388
1389
0
  proto_item_append_text(frame_tree, ", Status: %s", str);
1390
1391
0
  return frame->length;
1392
0
}
1393
1394
static int dissect_spdy_settings_payload(
1395
  tvbuff_t *tvb,
1396
  int offset,
1397
  packet_info *pinfo,
1398
  proto_tree *frame_tree,
1399
0
  const spdy_control_frame_info_t *frame) {
1400
0
  uint32_t num_entries;
1401
0
  proto_item *ti, *ti_setting;
1402
0
  proto_tree *setting_tree;
1403
0
  proto_tree *flags_tree;
1404
1405
  /* Make sure that we have enough room for our number of entries field. */
1406
0
  if (frame->length < 4) {
1407
0
    expert_add_info(pinfo, frame_tree, &ei_spdy_mal_setting_frame);
1408
0
    return -1;
1409
0
  }
1410
1411
  /* Get number of entries, and make sure we have enough room for them. */
1412
0
  num_entries = tvb_get_ntohl(tvb, offset);
1413
0
  if (frame->length < num_entries * 8) {
1414
0
    expert_add_info_format(pinfo, frame_tree, &ei_spdy_mal_setting_frame,
1415
0
        "SETTINGS frame too small [num_entries=%d]", num_entries);
1416
0
    return -1;
1417
0
  }
1418
1419
0
  proto_tree_add_item(frame_tree, hf_spdy_num_settings, tvb, offset, 4, ENC_BIG_ENDIAN);
1420
0
  offset += 4;
1421
1422
  /* Dissect each entry. */
1423
0
  while (num_entries > 0) {
1424
0
    const char *setting_id_str;
1425
0
    uint32_t setting_value;
1426
1427
    /* Create key/value pair subtree. */
1428
0
    ti_setting = proto_tree_add_item(frame_tree, hf_spdy_setting, tvb, offset, 8, ENC_NA);
1429
0
    setting_tree = proto_item_add_subtree(ti_setting, ett_spdy_setting);
1430
1431
    /* Set flags. */
1432
0
    if (setting_tree) {
1433
0
      ti = proto_tree_add_item(setting_tree, hf_spdy_flags, tvb, offset, 1, ENC_BIG_ENDIAN);
1434
1435
      /* TODO(hkhalil): Prettier output for flags sub-tree description. */
1436
0
      flags_tree = proto_item_add_subtree(ti, ett_spdy_flags);
1437
0
      proto_tree_add_item(flags_tree, hf_spdy_flags_persist_value, tvb, offset, 1, ENC_BIG_ENDIAN);
1438
0
      proto_tree_add_item(flags_tree, hf_spdy_flags_persisted, tvb, offset, 1, ENC_BIG_ENDIAN);
1439
0
    }
1440
0
    offset += 1;
1441
1442
    /* Set ID. */
1443
0
    setting_id_str = val_to_str(tvb_get_ntoh24(tvb, offset), setting_id_names, "Unknown(%d)");
1444
1445
0
    proto_tree_add_item(setting_tree, hf_spdy_setting_id, tvb, offset, 3, ENC_BIG_ENDIAN);
1446
0
    offset += 3;
1447
1448
    /* Set Value. */
1449
0
    setting_value = tvb_get_ntohl(tvb, offset);
1450
1451
0
    proto_tree_add_item(setting_tree, hf_spdy_setting_value, tvb, offset, 4, ENC_BIG_ENDIAN);
1452
0
    proto_item_append_text(ti_setting, ", %s: %u", setting_id_str, setting_value);
1453
0
    proto_item_append_text(frame_tree, ", %s: %u", setting_id_str, setting_value);
1454
0
    offset += 4;
1455
1456
    /* Increment. */
1457
0
    --num_entries;
1458
0
  }
1459
1460
0
  return frame->length;
1461
0
}
1462
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)
1465
0
{
1466
  /* Get ping ID. */
1467
0
  uint32_t ping_id = tvb_get_ntohl(tvb, offset);
1468
1469
  /* Add proto item for ping ID. */
1470
0
  proto_tree_add_item(frame_tree, hf_spdy_ping_id, tvb, offset, 4, ENC_BIG_ENDIAN);
1471
0
  proto_item_append_text(frame_tree, ", ID: %u", ping_id);
1472
1473
0
  return frame->length;
1474
0
}
1475
1476
static int dissect_spdy_goaway_payload(tvbuff_t *tvb,
1477
                                       int offset,
1478
                                       packet_info *pinfo,
1479
                                       proto_tree *frame_tree,
1480
0
                                       const spdy_control_frame_info_t *frame) {
1481
0
  uint32_t goaway_status;
1482
0
  proto_item* ti;
1483
1484
  /* Get last good stream ID and add to info column and tree. */
1485
0
  dissect_spdy_stream_id_field(tvb, offset, pinfo, frame_tree, hf_spdy_goaway_last_good_stream_id);
1486
0
  offset += 4;
1487
1488
  /* Add proto item for goaway_status. */
1489
0
  ti = proto_tree_add_item(frame_tree, hf_spdy_goaway_status, tvb, offset, 4, ENC_BIG_ENDIAN);
1490
0
  goaway_status = tvb_get_ntohl(tvb, offset);
1491
1492
0
  if (try_val_to_str(goaway_status, goaway_status_names) == NULL) {
1493
    /* Handle boundary conditions. */
1494
0
    expert_add_info_format(pinfo, ti, &ei_spdy_invalid_go_away,
1495
0
                           "Invalid status code for GOAWAY: %u", goaway_status);
1496
0
  }
1497
1498
  /* Add status to info column. */
1499
0
  proto_item_append_text(frame_tree, " Status=%s)",
1500
0
                  val_to_str(goaway_status, rst_stream_status_names, "Unknown (%d)"));
1501
1502
0
  return frame->length;
1503
0
}
1504
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)
1511
0
{
1512
0
  uint32_t            window_update_delta;
1513
1514
  /* Get stream ID. */
1515
0
  dissect_spdy_stream_id_field(tvb, offset, pinfo, frame_tree, hf_spdy_streamid);
1516
0
  offset += 4;
1517
1518
  /* Get window update delta. */
1519
0
  window_update_delta = tvb_get_ntohl(tvb, offset) & 0x7FFFFFFF;
1520
1521
  /* Add proto item for window update delta. */
1522
0
  proto_tree_add_item(frame_tree, hf_spdy_window_update_delta, tvb, offset, 4, ENC_BIG_ENDIAN);
1523
0
  proto_item_append_text(frame_tree, ", Delta: %u", window_update_delta);
1524
1525
0
  return frame->length;
1526
0
}
1527
1528
/*
1529
 * Performs SPDY frame dissection.
1530
 */
1531
static int dissect_spdy_frame(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
1532
16
{
1533
16
  uint8_t             control_bit;
1534
16
  spdy_control_frame_info_t frame;
1535
16
  uint32_t            stream_id = 0;
1536
16
  const char          *frame_type_name;
1537
16
  proto_tree          *spdy_tree;
1538
16
  proto_item          *spdy_item, *type_item = NULL;
1539
16
  int                 offset = 0;
1540
16
  spdy_conv_t         *conv_data;
1541
1542
16
  conv_data = get_or_create_spdy_conversation_data(pinfo);
1543
1544
16
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "SPDY");
1545
1546
  /* Create frame root. */
1547
16
  spdy_item = proto_tree_add_item(tree, proto_spdy, tvb, offset, -1, ENC_NA);
1548
16
  spdy_tree = proto_item_add_subtree(spdy_item, ett_spdy);
1549
1550
  /* Add control bit. */
1551
16
  control_bit = tvb_get_uint8(tvb, offset) & 0x80;
1552
16
  proto_tree_add_item(spdy_tree, hf_spdy_control_bit, tvb, offset, 2, ENC_NA);
1553
1554
  /* Process first four bytes of frame, formatted depending on control bit. */
1555
16
  if (control_bit) {
1556
    /* Add version. */
1557
1
    frame.version = tvb_get_ntohs(tvb, offset) & 0x7FFF;
1558
1
    proto_tree_add_item(spdy_tree, hf_spdy_version, tvb, offset, 2, ENC_BIG_ENDIAN);
1559
1
    offset += 2;
1560
1561
    /* Add control frame type. */
1562
1
    type_item = proto_tree_add_item(spdy_tree, hf_spdy_type, tvb, offset, 2, ENC_BIG_ENDIAN);
1563
1
    frame.type = tvb_get_ntohs(tvb, offset);
1564
1
    if (frame.type >= SPDY_INVALID) {
1565
1
      expert_add_info_format(pinfo, type_item, &ei_spdy_invalid_frame_type,
1566
1
                             "Invalid SPDY control frame type: %d", frame.type);
1567
1
      return -1;
1568
1
    }
1569
0
    offset += 2;
1570
1571
15
  } else {
1572
15
    frame.type = SPDY_DATA;
1573
15
    frame.version = 0; /* Version doesn't apply to DATA. */
1574
1575
    /* Add stream ID. */
1576
15
    stream_id = tvb_get_ntohl(tvb, offset) & SPDY_STREAM_ID_MASK;
1577
15
    proto_tree_add_item(spdy_tree, hf_spdy_streamid, tvb, offset, 4, ENC_BIG_ENDIAN);
1578
15
    offset += 4;
1579
15
  }
1580
1581
  /* Add frame info. */
1582
15
  frame_type_name = val_to_str(frame.type, frame_type_names, "Unknown(%d)");
1583
15
  col_append_sep_str(pinfo->cinfo, COL_INFO, ", ", frame_type_name);
1584
1585
15
  proto_item_append_text(spdy_tree, ": %s", frame_type_name);
1586
1587
  /* Add flags. */
1588
15
  frame.flags = tvb_get_uint8(tvb, offset);
1589
15
  if (spdy_tree) {
1590
15
    dissect_spdy_flags(tvb, offset, spdy_tree, &frame);
1591
15
  }
1592
15
  offset += 1;
1593
1594
  /* Add length. */
1595
15
  frame.length = tvb_get_ntoh24(tvb, offset);
1596
1597
15
  proto_item_set_len(spdy_item, frame.length + 8);
1598
15
  proto_tree_add_item(spdy_tree, hf_spdy_length, tvb, offset, 3, ENC_BIG_ENDIAN);
1599
15
  offset += 3;
1600
1601
  /*
1602
   * Make sure there's as much data as the frame header says there is.
1603
   */
1604
15
  if ((unsigned)tvb_reported_length_remaining(tvb, offset) < frame.length) {
1605
0
    expert_add_info_format(pinfo, tree, &ei_spdy_mal_frame_data,
1606
0
                           "Not enough frame data: %d vs. %d",
1607
0
                           frame.length, tvb_reported_length_remaining(tvb, offset));
1608
0
    return -1;
1609
0
  }
1610
1611
  /* Dissect DATA payload as necessary. */
1612
15
  if (!control_bit) {
1613
15
    return offset + dissect_spdy_data_payload(tvb, offset, pinfo, tree, spdy_tree,
1614
15
                                              spdy_item, conv_data, stream_id, &frame);
1615
15
  }
1616
1617
  /* Abort here if the version is too low. */
1618
0
  if (frame.version < MIN_SPDY_VERSION) {
1619
0
    proto_item_append_text(spdy_item, " [Unsupported Version]");
1620
0
    return frame.length + 8;
1621
0
  }
1622
1623
0
  switch (frame.type) {
1624
0
    case SPDY_SYN_STREAM:
1625
0
    case SPDY_SYN_REPLY:
1626
0
    case SPDY_HEADERS:
1627
0
      dissect_spdy_header_payload(tvb, offset, pinfo, spdy_tree, &frame, conv_data);
1628
0
      break;
1629
1630
0
    case SPDY_RST_STREAM:
1631
0
      dissect_spdy_rst_stream_payload(tvb, offset, pinfo, spdy_tree, &frame);
1632
0
      break;
1633
1634
0
    case SPDY_SETTINGS:
1635
0
      dissect_spdy_settings_payload(tvb, offset, pinfo, spdy_tree, &frame);
1636
0
      break;
1637
1638
0
    case SPDY_PING:
1639
0
      dissect_spdy_ping_payload(tvb, offset, pinfo, spdy_tree, &frame);
1640
0
      break;
1641
1642
0
    case SPDY_GOAWAY:
1643
0
      dissect_spdy_goaway_payload(tvb, offset, pinfo, spdy_tree, &frame);
1644
0
      break;
1645
1646
0
    case SPDY_WINDOW_UPDATE:
1647
0
      dissect_spdy_window_update_payload(tvb, offset, pinfo, spdy_tree, &frame);
1648
0
      break;
1649
1650
0
    case SPDY_CREDENTIAL:
1651
      /* TODO(hkhalil): Show something meaningful. */
1652
0
      break;
1653
1654
0
    default:
1655
0
      expert_add_info_format(pinfo, type_item, &ei_spdy_invalid_frame_type,
1656
0
                             "Unhandled SPDY frame type: %d", frame.type);
1657
0
      break;
1658
0
  }
1659
1660
  /*
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.
1664
   */
1665
0
  col_set_fence(pinfo->cinfo, COL_INFO);
1666
1667
  /* Assume that we've consumed the whole frame. */
1668
0
  return 8 + frame.length;
1669
0
}
1670
1671
static unsigned get_spdy_message_len(packet_info *pinfo _U_, tvbuff_t *tvb,
1672
                                  int offset, void *data _U_)
1673
16
{
1674
16
  return (unsigned)tvb_get_ntoh24(tvb, offset + 5) + 8;
1675
16
}
1676
1677
/*
1678
 * Wrapper for dissect_spdy_frame, sets fencing and desegments as necessary.
1679
 */
1680
static int dissect_spdy(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
1681
5
{
1682
5
  col_clear(pinfo->cinfo, COL_INFO);
1683
1684
5
  tcp_dissect_pdus(tvb, pinfo, tree, true, 8, get_spdy_message_len, dissect_spdy_frame, data);
1685
5
  return tvb_captured_length(tvb);
1686
5
}
1687
1688
/*
1689
 * Looks for SPDY frame at tvb start.
1690
 * If not enough data for either, requests more via desegment struct.
1691
 */
1692
static bool dissect_spdy_heur(tvbuff_t *tvb,
1693
                                  packet_info *pinfo,
1694
                                  proto_tree *tree,
1695
                                   void *data _U_)
1696
0
{
1697
  /*
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.)
1704
   */
1705
0
  uint8_t first_byte = tvb_get_uint8(tvb, 0);
1706
0
  if (first_byte != 0x80 && first_byte != 0x0) {
1707
0
    return false;
1708
0
  }
1709
1710
  /* Attempt dissection. */
1711
0
  if (dissect_spdy(tvb, pinfo, tree, NULL) != 0) {
1712
0
    return true;
1713
0
  }
1714
1715
0
  return false;
1716
0
}
1717
1718
/*
1719
 * Performs plugin registration.
1720
 */
1721
void proto_register_spdy(void)
1722
14
{
1723
14
  static hf_register_info hf[] = {
1724
14
    { &hf_spdy_data,
1725
14
      { "Data",           "spdy.data",
1726
14
        FT_BYTES, BASE_NONE, NULL, 0x0,
1727
14
        NULL, HFILL
1728
14
      }
1729
14
    },
1730
14
    { &hf_spdy_control_bit,
1731
14
      { "Control frame",    "spdy.control_bit",
1732
14
        FT_BOOLEAN, 16, TFS(&tfs_yes_no), 0x8000,
1733
14
        "true if SPDY control frame", HFILL
1734
14
      }
1735
14
    },
1736
14
    { &hf_spdy_version,
1737
14
      { "Version",        "spdy.version",
1738
14
        FT_UINT16, BASE_DEC, NULL, 0x7FFF,
1739
14
        NULL, HFILL
1740
14
      }
1741
14
    },
1742
14
    { &hf_spdy_type,
1743
14
      { "Type",           "spdy.type",
1744
14
        FT_UINT16, BASE_DEC,
1745
14
        VALS(frame_type_names), 0x0,
1746
14
        NULL, HFILL
1747
14
      }
1748
14
    },
1749
14
    { &hf_spdy_flags,
1750
14
      { "Flags",          "spdy.flags",
1751
14
        FT_UINT8, BASE_HEX, NULL, 0x0,
1752
14
        NULL, HFILL
1753
14
      }
1754
14
    },
1755
14
    { &hf_spdy_flags_fin,
1756
14
      { "FIN",            "spdy.flags.fin",
1757
14
        FT_BOOLEAN, 8,
1758
14
        TFS(&tfs_set_notset), SPDY_FLAG_FIN,
1759
14
        NULL, HFILL
1760
14
      }
1761
14
    },
1762
14
    { &hf_spdy_flags_unidirectional,
1763
14
      { "Unidirectional", "spdy.flags.unidirectional",
1764
14
        FT_BOOLEAN, 8,
1765
14
        TFS(&tfs_set_notset), SPDY_FLAG_UNIDIRECTIONAL,
1766
14
        NULL, HFILL
1767
14
      }
1768
14
    },
1769
14
    { &hf_spdy_flags_clear_settings,
1770
14
      { "Persist Value",  "spdy.flags.clear_settings",
1771
14
        FT_BOOLEAN, 8,
1772
14
        TFS(&tfs_set_notset), SPDY_FLAG_SETTINGS_CLEAR_SETTINGS,
1773
14
        NULL, HFILL
1774
14
      }
1775
14
    },
1776
14
    { &hf_spdy_flags_persist_value,
1777
14
      { "Persist Value",  "spdy.flags.persist_value",
1778
14
        FT_BOOLEAN, 8,
1779
14
        TFS(&tfs_set_notset), SPDY_FLAG_SETTINGS_PERSIST_VALUE,
1780
14
        NULL, HFILL
1781
14
      }
1782
14
    },
1783
14
    { &hf_spdy_flags_persisted,
1784
14
      { "Persisted",      "spdy.flags.persisted",
1785
14
        FT_BOOLEAN, 8,
1786
14
        TFS(&tfs_set_notset), SPDY_FLAG_SETTINGS_PERSISTED,
1787
14
        NULL, HFILL
1788
14
      }
1789
14
    },
1790
14
    { &hf_spdy_length,
1791
14
      { "Length",         "spdy.length",
1792
14
        FT_UINT24, BASE_DEC, NULL, 0x0,
1793
14
        NULL, HFILL
1794
14
      }
1795
14
    },
1796
14
    { &hf_spdy_header_block,
1797
14
      { "Header block", "spdy.header_block",
1798
14
          FT_BYTES, BASE_NONE, NULL, 0x0,
1799
14
          NULL, HFILL
1800
14
      }
1801
14
    },
1802
14
    { &hf_spdy_header,
1803
14
      { "Header",         "spdy.header",
1804
14
        FT_NONE, BASE_NONE, NULL, 0x0,
1805
14
        NULL, HFILL
1806
14
      }
1807
14
    },
1808
14
    { &hf_spdy_header_name,
1809
14
      { "Name",           "spdy.header.name",
1810
14
          FT_UINT_STRING, BASE_NONE, NULL, 0x0,
1811
14
          NULL, HFILL
1812
14
      }
1813
14
    },
1814
14
    { &hf_spdy_header_value,
1815
14
      { "Value",          "spdy.header.value",
1816
14
          FT_UINT_STRING, BASE_NONE, NULL, 0x0,
1817
14
          NULL, HFILL
1818
14
      }
1819
14
    },
1820
14
    { &hf_spdy_streamid,
1821
14
      { "Stream ID",      "spdy.streamid",
1822
14
          FT_UINT32, BASE_DEC, NULL, SPDY_STREAM_ID_MASK,
1823
14
          NULL, HFILL
1824
14
      }
1825
14
    },
1826
14
    { &hf_spdy_associated_streamid,
1827
14
      { "Associated Stream ID",   "spdy.associated.streamid",
1828
14
          FT_UINT32, BASE_DEC, NULL, SPDY_STREAM_ID_MASK,
1829
14
          NULL, HFILL
1830
14
      }
1831
14
    },
1832
14
    { &hf_spdy_priority,
1833
14
      { "Priority",       "spdy.priority",
1834
14
          FT_UINT16, BASE_DEC, NULL, 0xE000,
1835
14
          NULL, HFILL
1836
14
      }
1837
14
    },
1838
14
    { &hf_spdy_unused,
1839
14
      { "Unused",       "spdy.unused",
1840
14
          FT_UINT16, BASE_HEX, NULL, 0x1F00,
1841
14
          "Reserved for future use", HFILL
1842
14
      }
1843
14
    },
1844
14
    { &hf_spdy_slot,
1845
14
      { "Slot",       "spdy.slot",
1846
14
          FT_UINT16, BASE_DEC, NULL, 0x00FF,
1847
14
          "Specifying the index in the server's CREDENTIAL vector of the client certificate to be used for this request", HFILL
1848
14
      }
1849
14
    },
1850
14
    { &hf_spdy_num_headers,
1851
14
      { "Number of headers", "spdy.numheaders",
1852
14
          FT_UINT32, BASE_DEC, NULL, 0x0,
1853
14
          NULL, HFILL
1854
14
      }
1855
14
    },
1856
14
    { &hf_spdy_rst_stream_status,
1857
14
      { "Reset Status",   "spdy.rst_stream_status",
1858
14
          FT_UINT32, BASE_DEC, VALS(rst_stream_status_names), 0x0,
1859
14
          NULL, HFILL
1860
14
      }
1861
14
    },
1862
14
    { &hf_spdy_num_settings,
1863
14
      { "Number of Settings", "spdy.num_settings",
1864
14
          FT_UINT32, BASE_DEC, NULL, 0x0,
1865
14
          NULL, HFILL
1866
14
      }
1867
14
    },
1868
14
    { &hf_spdy_setting,
1869
14
      { "Setting",        "spdy.setting",
1870
14
          FT_NONE, BASE_NONE, NULL, 0x0,
1871
14
          NULL, HFILL
1872
14
      }
1873
14
    },
1874
14
    { &hf_spdy_setting_id,
1875
14
      { "ID",             "spdy.setting.id",
1876
14
          FT_UINT24, BASE_DEC, VALS(setting_id_names), 0x0,
1877
14
          NULL, HFILL
1878
14
      }
1879
14
    },
1880
14
    { &hf_spdy_setting_value,
1881
14
      { "Value",          "spdy.setting.value",
1882
14
          FT_UINT32, BASE_DEC, NULL, 0x0,
1883
14
          NULL, HFILL
1884
14
      }
1885
14
    },
1886
14
    { &hf_spdy_ping_id,
1887
14
      { "Ping ID",        "spdy.ping_id",
1888
14
          FT_UINT32, BASE_DEC, NULL, 0x0,
1889
14
          NULL, HFILL
1890
14
      }
1891
14
    },
1892
14
    { &hf_spdy_goaway_last_good_stream_id,
1893
14
      { "Last Good Stream ID", "spdy.goaway_last_good_stream_id",
1894
14
          FT_UINT32, BASE_DEC, NULL, SPDY_STREAM_ID_MASK,
1895
14
          NULL, HFILL
1896
14
      }
1897
14
    },
1898
14
    { &hf_spdy_goaway_status,
1899
14
      { "Go Away Status", "spdy.goaway_status",
1900
14
          FT_UINT32, BASE_DEC, VALS(goaway_status_names), 0x0,
1901
14
          NULL, HFILL
1902
14
      }
1903
14
    },
1904
14
    { &hf_spdy_window_update_delta,
1905
14
      { "Window Update Delta", "spdy.window_update_delta",
1906
14
          FT_UINT32, BASE_DEC, NULL, 0x7FFFFFFF,
1907
14
          NULL, HFILL
1908
14
      }
1909
14
    },
1910
14
  };
1911
14
  static int *ett[] = {
1912
14
    &ett_spdy,
1913
14
    &ett_spdy_flags,
1914
14
    &ett_spdy_header_block,
1915
14
    &ett_spdy_header,
1916
14
    &ett_spdy_setting,
1917
14
    &ett_spdy_encoded_entity,
1918
14
  };
1919
1920
14
  static ei_register_info ei[] = {
1921
14
    { &ei_spdy_inflation_failed, { "spdy.inflation_failed", PI_UNDECODED, PI_ERROR, "Inflation failed. Aborting.", EXPFILL }},
1922
14
    { &ei_spdy_mal_frame_data, { "spdy.malformed.frame_data", PI_MALFORMED, PI_ERROR, "Not enough frame data", EXPFILL }},
1923
14
    { &ei_spdy_mal_setting_frame, { "spdy.malformed.setting_frame", PI_MALFORMED, PI_ERROR, "SETTINGS frame too small for number of entries field.", EXPFILL }},
1924
14
    { &ei_spdy_invalid_rst_stream, { "spdy.rst_stream.invalid", PI_PROTOCOL, PI_WARN, "Invalid status code for RST_STREAM", EXPFILL }},
1925
14
    { &ei_spdy_invalid_go_away, { "spdy.goaway.invalid", PI_PROTOCOL, PI_WARN, "Invalid status code for GOAWAY", EXPFILL }},
1926
14
    { &ei_spdy_invalid_frame_type, { "spdy.type.invalid", PI_PROTOCOL, PI_WARN, "Invalid SPDY frame type", EXPFILL }},
1927
14
    { &ei_spdy_reassembly_info, { "spdy.reassembly_info", PI_REASSEMBLE, PI_CHAT, "Assembled from frames in packet(s)", EXPFILL }},
1928
14
  };
1929
1930
14
  module_t *spdy_module;
1931
14
  expert_module_t* expert_spdy;
1932
1933
14
  proto_spdy = proto_register_protocol("SPDY", "SPDY", "spdy");
1934
14
  proto_register_field_array(proto_spdy, hf, array_length(hf));
1935
14
  proto_register_subtree_array(ett, array_length(ett));
1936
14
  expert_spdy = expert_register_protocol(proto_spdy);
1937
14
  expert_register_field_array(expert_spdy, ei, array_length(ei));
1938
1939
14
  spdy_handle = register_dissector("spdy", dissect_spdy, proto_spdy);
1940
1941
14
  spdy_module = prefs_register_protocol(proto_spdy, NULL);
1942
14
  prefs_register_bool_preference(spdy_module, "assemble_data_frames",
1943
14
                                 "Assemble SPDY bodies that consist of multiple DATA frames",
1944
14
                                 "Whether the SPDY dissector should reassemble multiple "
1945
14
                                 "data frames into an entity body.",
1946
14
                                 &spdy_assemble_entity_bodies);
1947
1948
14
  prefs_register_bool_preference(spdy_module, "decompress_headers",
1949
14
                                 "Uncompress SPDY headers",
1950
14
                                 "Whether to uncompress SPDY headers.",
1951
14
                                 &spdy_decompress_headers);
1952
14
  prefs_register_bool_preference(spdy_module, "decompress_body",
1953
14
                                 "Uncompress entity bodies",
1954
14
                                 "Whether to uncompress entity bodies that are compressed "
1955
14
                                 "using \"Content-Encoding: \"",
1956
14
                                 &spdy_decompress_body);
1957
1958
14
  register_init_routine(&spdy_init_protocol);
1959
1960
  /*
1961
   * Register for tapping
1962
   */
1963
14
  spdy_tap = register_tap("spdy"); /* SPDY statistics tap */
1964
14
  spdy_eo_tap = register_tap("spdy_eo"); /* SPDY Export Object tap */
1965
14
}
1966
1967
14
void proto_reg_handoff_spdy(void) {
1968
1969
14
  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
14
  ssl_dissector_add(0, spdy_handle);
1972
14
  dissector_add_string("http.upgrade", "spdy", spdy_handle);
1973
1974
14
  media_handle = find_dissector_add_dependency("media", proto_spdy);
1975
14
  port_subdissector_table = find_dissector_table("http.port");
1976
14
  media_type_subdissector_table = find_dissector_table("media_type");
1977
1978
  /* Weak heuristic, so disabled by default */
1979
14
  heur_dissector_add("tcp", dissect_spdy_heur, "SPDY over TCP", "spdy_tcp", proto_spdy, HEURISTIC_DISABLE);
1980
14
}
1981
1982
/*
1983
 * Editor modelines
1984
 *
1985
 * Local Variables:
1986
 * c-basic-offset: 2
1987
 * tab-width: 8
1988
 * indent-tabs-mode: nil
1989
 * End:
1990
 *
1991
 * ex: set shiftwidth=2 tabstop=8 expandtab:
1992
 * :indentSize=4:tabSize=8:noTabs=true:
1993
 */