Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(231)

Side by Side Diff: net/tools/spdyshark/packet-spdy.c

Issue 650167: Wireshark dissector for SPDY protocol. (Closed)
Patch Set: Created 10 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 * Eric Shienbrood <ers@google.com>
8 *
9 * $Id$
10 *
11 * Wireshark - Network traffic analyzer
12 * By Gerald Combs <gerald@wireshark.org>
13 * Copyright 1998 Gerald Combs
14 *
15 * Originally based on packet-http.c
16 *
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License
19 * as published by the Free Software Foundation; either version 2
20 * of the License, or (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 */
31
32 #ifdef HAVE_CONFIG_H
33 #include "config.h"
34 #endif
35
36 #include <string.h>
37 #include <ctype.h>
38
39 #include <glib.h>
40 #include <epan/conversation.h>
41 #include <epan/packet.h>
42 #include <epan/strutil.h>
43 #include <epan/base64.h>
44 #include <epan/emem.h>
45 #include <epan/stats_tree.h>
46
47 #include <epan/req_resp_hdrs.h>
48 #include <plugins/spdy/packet-spdy.h>
49 #include <epan/dissectors/packet-tcp.h>
50 #include <epan/dissectors/packet-ssl.h>
51 #include <epan/prefs.h>
52 #include <epan/expert.h>
53 #include <epan/uat.h>
54
55 #define SPDY_FIN 0x01
56
57 /* The types of SPDY control frames */
58 typedef enum _spdy_type {
59 SPDY_DATA,
60 SPDY_SYN_STREAM,
61 SPDY_SYN_REPLY,
62 SPDY_FIN_STREAM,
63 SPDY_HELLO,
64 SPDY_NOOP,
65 SPDY_PING,
66 SPDY_INVALID
67 } spdy_frame_type_t;
68
69 static const char *frame_type_names[] = {
70 "DATA", "SYN_STREAM", "SYN_REPLY", "FIN_STREAM", "HELLO", "NOOP",
71 "PING", "INVALID"
72 };
73
74 /*
75 * This structure will be tied to each SPDY frame.
76 * Note that there may be multiple SPDY frames
77 * in one packet.
78 */
79 typedef struct _spdy_frame_info_t {
80 guint32 stream_id;
81 guint8 *header_block;
82 guint header_block_len;
83 guint16 frame_type;
84 } spdy_frame_info_t;
85
86 /*
87 * This structures keeps track of all the data frames
88 * associated with a stream, so that they can be
89 * reassembled into a single chunk.
90 */
91 typedef struct _spdy_data_frame_t {
92 guint8 *data;
93 guint32 length;
94 guint32 framenum;
95 } spdy_data_frame_t;
96
97 typedef struct _spdy_stream_info_t {
98 gchar *content_type;
99 gchar *content_type_parameters;
100 gchar *content_encoding;
101 GSList *data_frames;
102 tvbuff_t *assembled_data;
103 guint num_data_frames;
104 } spdy_stream_info_t;
105
106 #include <epan/tap.h>
107
108
109 static int spdy_tap = -1;
110 static int spdy_eo_tap = -1;
111
112 static int proto_spdy = -1;
113 static int hf_spdy_syn_stream = -1;
114 static int hf_spdy_syn_reply = -1;
115 static int hf_spdy_control_bit = -1;
116 static int hf_spdy_version = -1;
117 static int hf_spdy_type = -1;
118 static int hf_spdy_flags = -1;
119 static int hf_spdy_flags_fin = -1;
120 static int hf_spdy_length = -1;
121 static int hf_spdy_header = -1;
122 static int hf_spdy_header_name = -1;
123 static int hf_spdy_header_name_text = -1;
124 static int hf_spdy_header_value = -1;
125 static int hf_spdy_header_value_text = -1;
126 static int hf_spdy_streamid = -1;
127 static int hf_spdy_priority = -1;
128 static int hf_spdy_num_headers = -1;
129 static int hf_spdy_num_headers_string = -1;
130
131 static gint ett_spdy = -1;
132 static gint ett_spdy_syn_stream = -1;
133 static gint ett_spdy_syn_reply = -1;
134 static gint ett_spdy_fin_stream = -1;
135 static gint ett_spdy_flags = -1;
136 static gint ett_spdy_header = -1;
137 static gint ett_spdy_header_name = -1;
138 static gint ett_spdy_header_value = -1;
139
140 static gint ett_spdy_encoded_entity = -1;
141
142 static dissector_handle_t data_handle;
143 static dissector_handle_t media_handle;
144 static dissector_handle_t spdy_handle;
145
146 /* Stuff for generation/handling of fields for custom HTTP headers */
147 typedef struct _header_field_t {
148 gchar* header_name;
149 gchar* header_desc;
150 } header_field_t;
151
152 /*
153 * desegmentation of SPDY control frames
154 * (when we are over TCP or another protocol providing the desegmentation API)
155 */
156 static gboolean spdy_desegment_control_frames = TRUE;
157
158 /*
159 * desegmentation of SPDY data frames bodies
160 * (when we are over TCP or another protocol providing the desegmentation API)
161 * TODO let the user filter on content-type the bodies he wants desegmented
162 */
163 static gboolean spdy_desegment_data_frames = TRUE;
164
165 static gboolean spdy_assemble_entity_bodies = TRUE;
166
167 /*
168 * Decompression of zlib encoded entities.
169 */
170 #ifdef HAVE_LIBZ
171 static gboolean spdy_decompress_body = TRUE;
172 static gboolean spdy_decompress_headers = TRUE;
173 #else
174 static gboolean spdy_decompress_body = FALSE;
175 static gboolean spdy_decompress_headers = FALSE;
176 #endif
177 static gboolean spdy_debug = FALSE;
178
179 #define TCP_PORT_DAAP 3689
Mike Belshe 2010/02/22 21:55:08 Remove?
180
181 /*
182 * SSDP is implemented atop HTTP (yes, it really *does* run over UDP).
183 */
184 #define TCP_PORT_SSDP 1900
Mike Belshe 2010/02/22 21:55:08 Remove?
185 #define UDP_PORT_SSDP 1900
186
187 /*
188 * tcp and ssl ports
189 */
190
191 #define TCP_DEFAULT_RANGE "80,8080"
192 #define SSL_DEFAULT_RANGE "443"
193
194 static range_t *global_spdy_tcp_range = NULL;
195 static range_t *global_spdy_ssl_range = NULL;
196
197 static range_t *spdy_tcp_range = NULL;
198 static range_t *spdy_ssl_range = NULL;
199
200 static const value_string vals_status_code[] = {
201 { 100, "Continue" },
202 { 101, "Switching Protocols" },
203 { 102, "Processing" },
204 { 199, "Informational - Others" },
205
206 { 200, "OK"},
207 { 201, "Created"},
208 { 202, "Accepted"},
209 { 203, "Non-authoritative Information"},
210 { 204, "No Content"},
211 { 205, "Reset Content"},
212 { 206, "Partial Content"},
213 { 207, "Multi-Status"},
214 { 299, "Success - Others"},
215
216 { 300, "Multiple Choices"},
217 { 301, "Moved Permanently"},
218 { 302, "Found"},
219 { 303, "See Other"},
220 { 304, "Not Modified"},
221 { 305, "Use Proxy"},
222 { 307, "Temporary Redirect"},
223 { 399, "Redirection - Others"},
224
225 { 400, "Bad Request"},
226 { 401, "Unauthorized"},
227 { 402, "Payment Required"},
228 { 403, "Forbidden"},
229 { 404, "Not Found"},
230 { 405, "Method Not Allowed"},
231 { 406, "Not Acceptable"},
232 { 407, "Proxy Authentication Required"},
233 { 408, "Request Time-out"},
234 { 409, "Conflict"},
235 { 410, "Gone"},
236 { 411, "Length Required"},
237 { 412, "Precondition Failed"},
238 { 413, "Request Entity Too Large"},
239 { 414, "Request-URI Too Long"},
240 { 415, "Unsupported Media Type"},
241 { 416, "Requested Range Not Satisfiable"},
242 { 417, "Expectation Failed"},
243 { 418, "I'm a teapot"}, /* RFC 2324 */
244 { 422, "Unprocessable Entity"},
245 { 423, "Locked"},
246 { 424, "Failed Dependency"},
247 { 499, "Client Error - Others"},
248
249 { 500, "Internal Server Error"},
250 { 501, "Not Implemented"},
251 { 502, "Bad Gateway"},
252 { 503, "Service Unavailable"},
253 { 504, "Gateway Time-out"},
254 { 505, "HTTP Version not supported"},
255 { 507, "Insufficient Storage"},
256 { 599, "Server Error - Others"},
257
258 { 0, NULL}
259 };
260
261 static const char spdy_dictionary[] =
262 "optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-"
263 "languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi"
264 "f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser"
265 "-agent10010120020120220320420520630030130230330430530630740040140240340440"
266 "5406407408409410411412413414415416417500501502503504505accept-rangesageeta"
267 "glocationproxy-authenticatepublicretry-afterservervarywarningwww-authentic"
268 "ateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertran"
269 "sfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locati"
270 "oncontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMo"
271 "ndayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSe"
272 "pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic"
273 "ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1"
274 ".1statusversionurl";
275
276 static void reset_decompressors(void)
277 {
278 if (spdy_debug) printf("Should reset SPDY decompressors\n");
Mike Belshe 2010/02/22 21:55:08 nit: 2 lines
Eric Shienbrood 2010/02/22 23:30:32 C++ style guide says: "Short conditional statement
279 }
280
281 static spdy_conv_t *
282 get_spdy_conversation_data(packet_info *pinfo)
283 {
284 conversation_t *conversation;
Mike Belshe 2010/02/22 21:55:08 nit: conversation_t* conversation. there are mor
Eric Shienbrood 2010/02/22 23:30:32 I'm not sure we should be following the Google sty
cbentzel 2010/02/23 02:21:58 Agree. I think the ultimate goal is to get this in
285 spdy_conv_t *conv_data;
286 int retcode;
287
288 conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, p info->ptype, pinfo->srcport, pinfo->destport, 0);
Mike Belshe 2010/02/22 21:55:08 nit: 80 cols.
289 if (spdy_debug) {
290 printf("\n===========================================\n\n");
291 printf("Conversation for frame #%d is %p\n", pinfo->fd->num, conversatio n);
292 if (conversation)
293 printf(" conv_data=%p\n", conversation_get_proto_data(conversation, proto_spdy));
294 }
295
296 if(!conversation) /* Conversation does not exist yet - create it */
297 conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst , pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
Mike Belshe 2010/02/22 21:55:08 nit: 80cols
298
299 /* Retrieve information from conversation
300 */
301 conv_data = conversation_get_proto_data(conversation, proto_spdy);
302 if(!conv_data) {
303 /* Setup the conversation structure itself */
304 conv_data = se_alloc0(sizeof(spdy_conv_t));
305
306 conv_data->streams = NULL;
307 if (spdy_decompress_headers) {
308 conv_data->rqst_decompressor = se_alloc0(sizeof(z_stream));
309 conv_data->rply_decompressor = se_alloc0(sizeof(z_stream));
310 retcode = inflateInit(conv_data->rqst_decompressor);
311 if (retcode == Z_OK)
312 retcode = inflateInit(conv_data->rply_decompressor);
313 if (retcode != Z_OK)
314 printf("frame #%d: inflateInit() failed: %d\n", pinfo->fd->num, retcode);
315 else if (spdy_debug)
316 printf("created decompressor\n");
317 conv_data->dictionary_id = adler32(0L, Z_NULL, 0);
318 conv_data->dictionary_id = adler32(conv_data->dictionary_id,
319 spdy_dictionary,
320 sizeof(spdy_dictionary));
321 }
322
323 conversation_add_proto_data(conversation, proto_spdy, conv_data);
324 register_postseq_cleanup_routine(reset_decompressors);
325 }
326 return conv_data;
327 }
328
329 static void
330 spdy_save_stream_info(spdy_conv_t *conv_data,
331 guint32 stream_id,
332 gchar *content_type,
333 gchar *content_type_params,
334 gchar *content_encoding)
335 {
336 spdy_stream_info_t *si;
337
338 if (conv_data->streams == NULL)
339 conv_data->streams = g_array_new(FALSE, TRUE, sizeof(spdy_stream_info_t *));
340 if (stream_id < conv_data->streams->len)
341 DISSECTOR_ASSERT(g_array_index(conv_data->streams, spdy_stream_info_t*, stream_id) == NULL);
342 else
343 g_array_set_size(conv_data->streams, stream_id+1);
344 si = se_alloc(sizeof(spdy_stream_info_t));
345 si->content_type = content_type;
346 si->content_type_parameters = content_type_params;
347 si->content_encoding = content_encoding;
348 si->data_frames = NULL;
349 si->num_data_frames = 0;
350 si->assembled_data = NULL;
351 g_array_index(conv_data->streams, spdy_stream_info_t*, stream_id) = si;
352 if (spdy_debug)
353 printf("Saved stream info for ID %u, content type %s\n", stream_id, cont ent_type);
354 }
355
356 static spdy_stream_info_t *
357 spdy_get_stream_info(spdy_conv_t *conv_data, guint32 stream_id)
358 {
359 if (conv_data->streams == NULL || stream_id >= conv_data->streams->len)
360 return NULL;
361 else
362 return g_array_index(conv_data->streams, spdy_stream_info_t*, stream_id) ;
363 }
364
365 static void
366 spdy_add_data_chunk(spdy_conv_t *conv_data, guint32 stream_id, guint32 frame,
367 guint8 *data, guint32 length)
368 {
369 spdy_stream_info_t *si = spdy_get_stream_info(conv_data, stream_id);
370
371 if (si == NULL) {
372 if (spdy_debug) printf("No stream_info found for stream %d\n", stream_id );
373 } else {
374 spdy_data_frame_t *df = g_malloc(sizeof(spdy_data_frame_t));
375 df->data = data;
376 df->length = length;
377 df->framenum = frame;
378 si->data_frames = g_slist_append(si->data_frames, df);
379 ++si->num_data_frames;
380 if (spdy_debug)
381 printf("Saved %u bytes of data for stream %u frame %u\n",
382 length, stream_id, df->framenum);
383 }
384 }
385
386 static void
387 spdy_increment_data_chunk_count(spdy_conv_t *conv_data, guint32 stream_id)
388 {
389 spdy_stream_info_t *si = spdy_get_stream_info(conv_data, stream_id);
390 if (si != NULL)
391 ++si->num_data_frames;
392 }
393
394 /*
395 * Return the number of data frames saved so far for the specified stream.
396 */
397 static guint
398 spdy_get_num_data_frames(spdy_conv_t *conv_data, guint32 stream_id)
399 {
400 spdy_stream_info_t *si = spdy_get_stream_info(conv_data, stream_id);
401
402 return si == NULL ? 0 : si->num_data_frames;
403 }
404
405 static spdy_stream_info_t *
406 spdy_assemble_data_frames(spdy_conv_t *conv_data, guint32 stream_id)
407 {
408 spdy_stream_info_t *si = spdy_get_stream_info(conv_data, stream_id);
409 tvbuff_t *tvb;
410
411 if (si == NULL)
412 return NULL;
413
414 /*
415 * Compute the total amount of data and concatenate the
416 * data chunks, if it hasn't already been done.
417 */
418 if (si->assembled_data == NULL) {
419 spdy_data_frame_t *df;
420 guint8 *data;
421 guint32 datalen;
422 guint32 offset;
423 guint32 framenum;
424 GSList *dflist = si->data_frames;
425 if (dflist == NULL)
426 return si;
427 dflist = si->data_frames;
428 datalen = 0;
429 /*
430 * I'd like to use a composite tvbuff here, but since
431 * only a real-data tvbuff can be the child of another
432 * tvb, I can't. It would be nice if this limitation
433 * could be fixed.
434 */
435 while (dflist != NULL) {
436 df = dflist->data;
437 datalen += df->length;
438 dflist = g_slist_next(dflist);
439 }
440 if (datalen != 0) {
441 data = se_alloc(datalen);
442 dflist = si->data_frames;
443 offset = 0;
444 framenum = 0;
445 while (dflist != NULL) {
446 df = dflist->data;
447 memcpy(data+offset, df->data, df->length);
448 offset += df->length;
449 dflist = g_slist_next(dflist);
450 }
451 tvb = tvb_new_real_data(data, datalen, datalen);
452 si->assembled_data = tvb;
453 }
454 }
455 return si;
456 }
457
458 static void
459 spdy_discard_data_frames(spdy_stream_info_t *si)
460 {
461 GSList *dflist = si->data_frames;
462 spdy_data_frame_t *df;
463
464 if (dflist == NULL)
465 return;
466 while (dflist != NULL) {
467 df = dflist->data;
468 if (df->data != NULL) {
469 g_free(df->data);
470 df->data = NULL;
471 }
472 dflist = g_slist_next(dflist);
473 }
474 /*g_slist_free(si->data_frames);
475 si->data_frames = NULL; */
476 }
477
478 static int
479 dissect_spdy_data_frame(tvbuff_t *tvb, int offset,
480 packet_info *pinfo,
481 proto_tree *top_level_tree,
482 proto_tree *spdy_tree,
483 proto_item *spdy_proto,
484 spdy_conv_t *conv_data)
485 {
486 guint32 stream_id;
487 guint8 flags;
488 guint32 frame_length;
489 proto_item *ti;
490 proto_tree *flags_tree;
491 guint32 reported_datalen;
492 guint32 datalen;
493 dissector_table_t media_type_subdissector_table;
494 dissector_table_t port_subdissector_table;
495 dissector_handle_t handle;
496 guint num_data_frames;
497 gboolean dissected;
498
499 stream_id = tvb_get_bits32(tvb, (offset << 3) + 1, 31, FALSE);
500 flags = tvb_get_guint8(tvb, offset+4);
501 frame_length = tvb_get_ntoh24(tvb, offset+5);
502
503 if (spdy_debug)
504 printf("Data frame [stream_id=%u flags=0x%x length=%d]\n",
505 stream_id, flags, frame_length);
506 if (spdy_tree) proto_item_append_text(spdy_tree, ", data frame");
507 col_add_fstr(pinfo->cinfo, COL_INFO, "DATA[%u] length=%d",
508 stream_id, frame_length);
509
510 proto_item_append_text(spdy_proto, ":%s stream=%d length=%d",
511 flags & SPDY_FIN ? " [FIN]" : "",
512 stream_id, frame_length);
513
514 proto_tree_add_boolean(spdy_tree, hf_spdy_control_bit, tvb, offset, 1, 0);
515 proto_tree_add_uint(spdy_tree, hf_spdy_streamid, tvb, offset, 4, stream_id);
516 ti = proto_tree_add_uint_format(spdy_tree, hf_spdy_flags, tvb, offset+4, 1, flags,
517 "Flags: 0x%02x%s", flags, flags&SPDY_FIN ? " (FIN)" : "");
518
519 flags_tree = proto_item_add_subtree(ti, ett_spdy_flags);
520 proto_tree_add_boolean(flags_tree, hf_spdy_flags_fin, tvb, offset+4, 1, flag s);
521 proto_tree_add_uint(spdy_tree, hf_spdy_length, tvb, offset+5, 3, frame_lengt h);
522
523 datalen = tvb_length_remaining(tvb, offset);
524 if (datalen > frame_length)
525 datalen = frame_length;
526
527 reported_datalen = tvb_reported_length_remaining(tvb, offset);
528 if (reported_datalen > frame_length)
529 reported_datalen = frame_length;
530
531 num_data_frames = spdy_get_num_data_frames(conv_data, stream_id);
532 if (datalen != 0 || num_data_frames != 0) {
533 /*
534 * There's stuff left over; process it.
535 */
536 tvbuff_t *next_tvb = NULL;
537 tvbuff_t *data_tvb = NULL;
538 spdy_stream_info_t *si = NULL;
539 void *save_private_data = NULL;
540 guint8 *copied_data;
541 gboolean private_data_changed = FALSE;
542 gboolean is_single_chunk = FALSE;
543 gboolean have_entire_body;
544
545 /*
546 * Create a tvbuff for the payload.
547 */
548 if (datalen != 0) {
549 next_tvb = tvb_new_subset(tvb, offset+8, datalen,
550 reported_datalen);
551 is_single_chunk = num_data_frames == 0 && (flags & SPDY_FIN) != 0;
552 if (!pinfo->fd->flags.visited) {
553 if (!is_single_chunk) {
554 if (spdy_assemble_entity_bodies) {
555 copied_data = tvb_memdup(next_tvb, 0, datalen);
556 spdy_add_data_chunk(conv_data, stream_id, pinfo->fd->num ,
557 copied_data, datalen);
558 } else
559 spdy_increment_data_chunk_count(conv_data, stream_id);
560 }
561 }
562 } else
563 is_single_chunk = (num_data_frames == 1);
564
565 if (!(flags & SPDY_FIN)) {
566 col_set_fence(pinfo->cinfo, COL_INFO);
567 col_add_fstr(pinfo->cinfo, COL_INFO, " (partial entity)");
568 proto_item_append_text(spdy_proto, " (partial entity body)");
569 /* would like the proto item to say */
570 /* " (entity body fragment N of M)" */
571 goto body_dissected;
572 }
573 have_entire_body = is_single_chunk;
574 /*
575 * On seeing the last data frame in a stream, we can
576 * reassemble the frames into one data block.
577 */
578 si = spdy_assemble_data_frames(conv_data, stream_id);
579 if (si == NULL)
580 goto body_dissected;
581 data_tvb = si->assembled_data;
582 if (spdy_assemble_entity_bodies)
583 have_entire_body = TRUE;
584
585 if (!have_entire_body)
586 goto body_dissected;
587
588 if (data_tvb == NULL)
589 data_tvb = next_tvb;
590 else
591 add_new_data_source(pinfo, data_tvb, "Assembled entity body");
592
593 if (have_entire_body && si->content_encoding != NULL &&
594 g_ascii_strcasecmp(si->content_encoding, "identity") != 0) {
595 /*
596 * We currently can't handle, for example, "compress";
597 * just handle them as data for now.
598 *
599 * After July 7, 2004 the LZW patent expires, so support
600 * might be added then. However, I don't think that
601 * anybody ever really implemented "compress", due to
602 * the aforementioned patent.
603 */
604 tvbuff_t *uncomp_tvb = NULL;
605 proto_item *e_ti = NULL;
606 proto_item *ce_ti = NULL;
607 proto_tree *e_tree = NULL;
608
609 if (spdy_decompress_body &&
610 (g_ascii_strcasecmp(si->content_encoding, "gzip") == 0 ||
611 g_ascii_strcasecmp(si->content_encoding, "deflate")
612 == 0)) {
613
614 uncomp_tvb = tvb_child_uncompress(tvb, data_tvb, 0,
615 tvb_length(data_tvb));
616 }
617 /*
618 * Add the encoded entity to the protocol tree
619 */
620 e_ti = proto_tree_add_text(top_level_tree, data_tvb,
621 0, tvb_length(data_tvb),
622 "Content-encoded entity body (%s): %u bytes",
623 si->content_encoding,
624 tvb_length(data_tvb));
625 e_tree = proto_item_add_subtree(e_ti, ett_spdy_encoded_entity);
626 if (si->num_data_frames > 1) {
627 GSList *dflist;
628 spdy_data_frame_t *df;
629 guint32 framenum;
630 ce_ti = proto_tree_add_text(e_tree, data_tvb, 0,
631 tvb_length(data_tvb),
632 "Assembled from %d frames in packet(s)", si->num_data_fr ames);
633 dflist = si->data_frames;
634 framenum = 0;
635 while (dflist != NULL) {
636 df = dflist->data;
637 if (framenum != df->framenum) {
638 proto_item_append_text(ce_ti, " #%u", df->framenum);
639 framenum = df->framenum;
640 }
641 dflist = g_slist_next(dflist);
642 }
643 }
644
645 if (uncomp_tvb != NULL) {
646 /*
647 * Decompression worked
648 */
649
650 /* XXX - Don't free this, since it's possible
651 * that the data was only partially
652 * decompressed, such as when desegmentation
653 * isn't enabled.
654 *
655 tvb_free(next_tvb);
656 */
657 proto_item_append_text(e_ti, " -> %u bytes", tvb_length(uncomp_t vb));
658 data_tvb = uncomp_tvb;
659 add_new_data_source(pinfo, data_tvb, "Uncompressed entity body") ;
660 } else {
661 if (spdy_decompress_body)
662 proto_item_append_text(e_ti, " [Error: Decompression failed] ");
663 call_dissector(data_handle, data_tvb, pinfo, e_tree);
664
665 goto body_dissected;
666 }
667 }
668 if (si != NULL)
669 spdy_discard_data_frames(si);
670 /*
671 * Do subdissector checks.
672 *
673 * First, check whether some subdissector asked that they
674 * be called if something was on some particular port.
675 */
676
677 port_subdissector_table = find_dissector_table("http.port");
678 media_type_subdissector_table = find_dissector_table("media_type");
679 if (have_entire_body && port_subdissector_table != NULL)
680 handle = dissector_get_port_handle(port_subdissector_table,
681 pinfo->match_port);
682 else
683 handle = NULL;
684 if (handle == NULL && have_entire_body && si->content_type != NULL &&
685 media_type_subdissector_table != NULL) {
686 /*
687 * We didn't find any subdissector that
688 * registered for the port, and we have a
689 * Content-Type value. Is there any subdissector
690 * for that content type?
691 */
692 save_private_data = pinfo->private_data;
693 private_data_changed = TRUE;
694
695 if (si->content_type_parameters)
696 pinfo->private_data = ep_strdup(si->content_type_parameters);
697 else
698 pinfo->private_data = NULL;
699 /*
700 * Calling the string handle for the media type
701 * dissector table will set pinfo->match_string
702 * to si->content_type for us.
703 */
704 pinfo->match_string = si->content_type;
705 handle = dissector_get_string_handle(
706 media_type_subdissector_table,
707 si->content_type);
708 }
709 if (handle != NULL) {
710 /*
711 * We have a subdissector - call it.
712 */
713 dissected = call_dissector(handle, data_tvb, pinfo, top_level_tree);
714 } else
715 dissected = FALSE;
716
717 if (dissected) {
718 /*
719 * The subdissector dissected the body.
720 * Fix up the top-level item so that it doesn't
721 * include the stuff for that protocol.
722 */
723 if (ti != NULL)
724 proto_item_set_len(ti, offset);
725 } else if (have_entire_body && si->content_type != NULL) {
726 /*
727 * Calling the default media handle if there is a content-type that
728 * wasn't handled above.
729 */
730 call_dissector(media_handle, next_tvb, pinfo, top_level_tree);
731 } else {
732 /* Call the default data dissector */
733 call_dissector(data_handle, next_tvb, pinfo, top_level_tree);
734 }
735
736 body_dissected:
737 /*
738 * Do *not* attempt at freeing the private data;
739 * it may be in use by subdissectors.
740 */
741 if (private_data_changed) /*restore even NULL value*/
742 pinfo->private_data = save_private_data;
743 /*
744 * We've processed "datalen" bytes worth of data
745 * (which may be no data at all); advance the
746 * offset past whatever data we've processed.
747 */
748 }
749 return frame_length + 8;
750 }
751
752 static guint8 *
753 spdy_decompress_header_block(tvbuff_t *tvb, z_streamp decomp,
754 guint32 dictionary_id, int offset,
755 guint32 length, guint *uncomp_length)
756 {
757 int retcode;
758 size_t bufsize = 16384;
759 const guint8 *hptr = tvb_get_ptr(tvb, offset, length);
760 guint8 *uncomp_block = ep_alloc(bufsize);
761 decomp->next_in = (Bytef *)hptr;
762 decomp->avail_in = length;
763 decomp->next_out = uncomp_block;
764 decomp->avail_out = bufsize;
765 retcode = inflate(decomp, Z_SYNC_FLUSH);
766 if (retcode == Z_NEED_DICT) {
767 if (decomp->adler != dictionary_id) {
768 printf("decompressor wants dictionary %#x, but we have %#x\n",
769 (guint)decomp->adler, dictionary_id);
770 } else {
771 retcode = inflateSetDictionary(decomp,
772 spdy_dictionary,
773 sizeof(spdy_dictionary));
Mike Belshe 2010/02/22 21:55:08 This should be sizeof(spdy_dictionary)-1. Probabl
Eric Shienbrood 2010/02/22 23:30:32 Has this changed? It should have been sizeof(...)-
774 if (retcode == Z_OK)
775 retcode = inflate(decomp, Z_SYNC_FLUSH);
776 }
777 }
778
779 if (retcode != Z_OK) {
780 return NULL;
781 } else {
782 *uncomp_length = bufsize - decomp->avail_out;
783 if (spdy_debug)
784 printf("Inflation SUCCEEDED. uncompressed size=%d\n", *uncomp_length );
785 if (decomp->avail_in != 0)
786 if (spdy_debug)
787 printf(" but there were %d input bytes left over\n", decomp->av ail_in);
788 }
789 return se_memdup(uncomp_block, *uncomp_length);
790 }
791
792 /*
793 * Try to determine heuristically whether the header block is
794 * compressed. For an uncompressed block, the first two bytes
795 * gives the number of headers. Each header name and value is
796 * a two-byte length followed by ASCII characters.
797 */
798 static gboolean
799 spdy_check_header_compression(tvbuff_t *tvb,
800 int offset,
801 guint32 frame_length)
802 {
803 guint16 length;
804 if (!tvb_bytes_exist(tvb, offset, 6))
805 return 1;
806 length = tvb_get_ntohs(tvb, offset);
807 if (length > frame_length)
808 return 1;
809 length = tvb_get_ntohs(tvb, offset+2);
810 if (length > frame_length)
811 return 1;
812 if (spdy_debug) printf("Looks like the header block is not compressed\n");
813 return 0;
814 }
815
816 static spdy_frame_info_t *
817 spdy_save_header_block(frame_data *fd,
818 guint32 stream_id,
819 guint frame_type,
820 guint8 *header,
821 guint length)
822 {
823 GSList *filist = p_get_proto_data(fd, proto_spdy);
824 spdy_frame_info_t *frame_info = se_alloc(sizeof(spdy_frame_info_t));
825 if (filist != NULL)
826 p_remove_proto_data(fd, proto_spdy);
827 frame_info->stream_id = stream_id;
828 frame_info->header_block = header;
829 frame_info->header_block_len = length;
830 frame_info->frame_type = frame_type;
831 filist = g_slist_append(filist, frame_info);
832 p_add_proto_data(fd, proto_spdy, filist);
833 return frame_info;
834 /* TODO(ers) these need to get deleted when no longer needed */
835 }
836
837 static spdy_frame_info_t *
838 spdy_find_saved_header_block(frame_data *fd,
839 guint32 stream_id,
840 guint16 frame_type)
841 {
842 GSList *filist = p_get_proto_data(fd, proto_spdy);
843 while (filist != NULL) {
844 spdy_frame_info_t *fi = filist->data;
845 if (fi->stream_id == stream_id && fi->frame_type == frame_type)
846 return fi;
847 filist = g_slist_next(filist);
848 }
849 return NULL;
850 }
851
852 /*
853 * Given a content type string that may contain optional parameters,
854 * return the parameter string, if any, otherwise return NULL. This
855 * also has the side effect of null terminating the content type
856 * part of the original string.
857 */
858 static gchar *
859 spdy_parse_content_type(gchar *content_type)
860 {
861 gchar *cp = content_type;
862
863 while (*cp != '\0' && *cp != ';' && !isspace(*cp)) {
864 *cp = tolower(*cp);
865 ++cp;
866 }
867 if (*cp == '\0')
868 cp = NULL;
869
870 if (cp != NULL) {
871 *cp++ = '\0';
872 while (*cp == ';' || isspace(*cp))
873 ++cp;
874 if (*cp != '\0')
875 return cp;
876 }
877 return NULL;
878 }
879
880 static int
881 dissect_spdy_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
882 proto_tree *tree, spdy_conv_t *conv_data)
883 {
884 guint8 control_bit;
885 guint16 version;
886 guint16 frame_type;
887 guint8 flags;
888 guint32 frame_length;
889 guint32 stream_id;
890 gint priority;
891 guint16 num_headers;
892 guint32 fin_status;
893 guint8 *frame_header;
894 const char *proto_tag;
895 const char *frame_type_name;
896 proto_tree *spdy_tree = NULL;
897 proto_item *ti = NULL;
898 proto_item *spdy_proto = NULL;
899 int orig_offset;
900 int hoffset;
901 int hdr_offset = 0;
902 spdy_frame_type_t spdy_type;
903 proto_tree *sub_tree;
904 proto_tree *flags_tree;
905 tvbuff_t *header_tvb = NULL;
906 gboolean headers_compressed;
907 gchar *hdr_verb = NULL;
908 gchar *hdr_url = NULL;
909 gchar *hdr_version = NULL;
910 gchar *content_type = NULL;
911 gchar *content_encoding = NULL;
912
913 /*
914 * Minimum size for a SPDY frame is 8 bytes.
915 */
916 if (tvb_reported_length_remaining(tvb, offset) < 8)
917 return -1;
918
919 proto_tag = "SPDY";
920
921 if (check_col(pinfo->cinfo, COL_PROTOCOL))
922 col_set_str(pinfo->cinfo, COL_PROTOCOL, proto_tag);
923
924 /*
925 * Is this a control frame or a data frame?
926 */
927 orig_offset = offset;
928 control_bit = tvb_get_bits8(tvb, offset << 3, 1);
929 if (control_bit) {
930 version = tvb_get_bits16(tvb, (offset << 3) + 1, 15, FALSE);
931 frame_type = tvb_get_ntohs(tvb, offset+2);
932 if (frame_type >= SPDY_INVALID) {
933 return -1;
934 }
935 frame_header = ep_tvb_memdup(tvb, offset, 16);
936 } else {
937 version = 1; /* avoid gcc warning */
938 frame_type = SPDY_DATA;
939 frame_header = NULL; /* avoid gcc warning */
940 }
941 frame_type_name = frame_type_names[frame_type];
942 offset += 4;
943 flags = tvb_get_guint8(tvb, offset);
944 frame_length = tvb_get_ntoh24(tvb, offset+1);
945 offset += 4;
946 /*
947 * Make sure there's as much data as the frame header says there is.
948 */
949 if ((guint)tvb_reported_length_remaining(tvb, offset) < frame_length) {
950 if (spdy_debug)
951 printf("Not enough header data: %d vs. %d\n",
952 frame_length, tvb_reported_length_remaining(tvb, offset));
953 return -1;
954 }
955 if (tree) {
956 spdy_proto = proto_tree_add_item(tree, proto_spdy, tvb, orig_offset, fra me_length+8, FALSE);
957 spdy_tree = proto_item_add_subtree(spdy_proto, ett_spdy);
958 }
959
960 if (control_bit) {
961 if (spdy_debug)
962 printf("Control frame [version=%d type=%d flags=0x%x length=%d]\n",
963 version, frame_type, flags, frame_length);
964 if (tree) proto_item_append_text(spdy_tree, ", control frame");
965 } else {
966 return dissect_spdy_data_frame(tvb, orig_offset, pinfo, tree,
967 spdy_tree, spdy_proto, conv_data);
968 }
969 num_headers = 0;
970 sub_tree = NULL; /* avoid gcc warning */
971 switch (frame_type) {
972 case SPDY_SYN_STREAM:
973 case SPDY_SYN_REPLY:
974 if (tree) {
975 int hf;
976 hf = frame_type == SPDY_SYN_STREAM ? hf_spdy_syn_stream : hf_spd y_syn_reply;
977 ti = proto_tree_add_bytes(spdy_tree, hf, tvb,
978 orig_offset, 16, frame_header);
979 sub_tree = proto_item_add_subtree(ti, ett_spdy_syn_stream);
980 }
981 stream_id = tvb_get_bits32(tvb, (offset << 3) + 1, 31, FALSE);
982 offset += 4;
983 priority = tvb_get_bits8(tvb, offset << 3, 2);
984 offset += 2;
985 if (tree) {
986 proto_tree_add_boolean(sub_tree, hf_spdy_control_bit, tvb, orig_ offset, 1, control_bit);
987 proto_tree_add_uint(sub_tree, hf_spdy_version, tvb, orig_offset, 2, version);
988 proto_tree_add_uint(sub_tree, hf_spdy_type, tvb, orig_offset+2, 2, frame_type);
989 ti = proto_tree_add_uint_format(sub_tree, hf_spdy_flags, tvb, or ig_offset+4, 1, flags,
990 "Flags: 0x%02x%s", flags, flags& SPDY_FIN ? " (FIN)" : "");
991 flags_tree = proto_item_add_subtree(ti, ett_spdy_flags);
992 proto_tree_add_boolean(flags_tree, hf_spdy_flags_fin, tvb, orig_ offset+4, 1, flags);
993 proto_tree_add_uint(sub_tree, hf_spdy_length, tvb, orig_offset+5 , 3, frame_length);
994 proto_tree_add_uint(sub_tree, hf_spdy_streamid, tvb, orig_offset +8, 4, stream_id);
995 proto_tree_add_uint(sub_tree, hf_spdy_priority, tvb, orig_offset +12, 1, priority);
996 proto_item_append_text(spdy_proto, ": %s%s stream=%d length=%d",
997 frame_type_name,
998 flags & SPDY_FIN ? " [FIN]" : "",
999 stream_id, frame_length);
1000 if (spdy_debug)
1001 printf(" stream ID=%u priority=%d\n", stream_id, priority);
1002 }
1003 break;
1004
1005 case SPDY_FIN_STREAM:
1006 stream_id = tvb_get_bits32(tvb, (offset << 3) + 1, 31, FALSE);
1007 fin_status = tvb_get_ntohl(tvb, offset);
1008 // TODO(ers) fill in tree and summary
1009 offset += 8;
1010 break;
1011
1012 case SPDY_HELLO:
1013 // TODO(ers) fill in tree and summary
1014 stream_id = 0; /* avoid gcc warning */
1015 break;
1016
1017 default:
1018 stream_id = 0; /* avoid gcc warning */
1019 return -1;
1020 break;
1021 }
1022
1023 /*
1024 * Process the name-value pairs one at a time, after possibly
1025 * decompressing the header block.
1026 */
1027 if (frame_type == SPDY_SYN_STREAM || frame_type == SPDY_SYN_REPLY) {
1028 headers_compressed = spdy_check_header_compression(tvb, offset, frame_le ngth);
1029 if (!spdy_decompress_headers || !headers_compressed) {
1030 header_tvb = tvb;
1031 hdr_offset = offset;
1032 } else {
1033 spdy_frame_info_t *per_frame_info =
1034 spdy_find_saved_header_block(pinfo->fd,
1035 stream_id,
1036 frame_type == SPDY_SYN_REPLY);
1037 if (per_frame_info == NULL) {
1038 guint uncomp_length;
1039 z_streamp decomp = frame_type == SPDY_SYN_STREAM ?
1040 conv_data->rqst_decompressor : conv_data->rply_decompres sor;
1041 guint8 *uncomp_ptr =
1042 spdy_decompress_header_block(tvb, decomp,
1043 conv_data->dictionary_id,
1044 offset, frame_length-6, &un comp_length);
1045 if (uncomp_ptr == NULL) { /* decompression failed */
1046 if (spdy_debug)
1047 printf("Frame #%d: Inflation failed\n", pinfo->fd->num);
1048 proto_item_append_text(spdy_proto, " [Error: Header decompre ssion failed]");
1049 } else {
1050 if (spdy_debug)
1051 printf("Saving %u bytes of uncomp hdr\n", uncomp_length) ;
1052 per_frame_info =
1053 spdy_save_header_block(pinfo->fd, stream_id, frame_type == SPDY_SYN_REPLY,
1054 uncomp_ptr, uncomp_length);
1055 }
1056 } else if (spdy_debug) {
1057 printf("Found uncompressed header block len %u for stream %u fra me_type=%d\n",
1058 per_frame_info->header_block_len,
1059 per_frame_info->stream_id,
1060 per_frame_info->frame_type);
1061 }
1062 if (per_frame_info != NULL) {
1063 header_tvb = tvb_new_child_real_data(tvb,
1064 per_frame_info->header_block,
1065 per_frame_info->header_block_le n,
1066 per_frame_info->header_block_le n);
1067 add_new_data_source(pinfo, header_tvb, "Uncompressed headers");
1068 hdr_offset = 0;
1069 }
1070 }
1071 offset += frame_length-6;
1072 num_headers = tvb_get_ntohs(header_tvb, hdr_offset);
1073 hdr_offset += 2;
1074 if (header_tvb == NULL ||
1075 (headers_compressed && !spdy_decompress_headers)) {
1076 num_headers = 0;
1077 ti = proto_tree_add_string(sub_tree, hf_spdy_num_headers_string,
1078 tvb, orig_offset+14, 2,
1079 "Unknown (header block is compressed)");
1080 } else
1081 ti = proto_tree_add_uint(sub_tree, hf_spdy_num_headers,
1082 tvb, orig_offset+14, 2, num_headers);
1083 }
1084 spdy_type = SPDY_INVALID; /* type not known yet */
1085 if (spdy_debug)
1086 printf(" %d Headers:\n", num_headers);
1087 if (num_headers > frame_length) {
1088 printf("Number of headers is greater than frame length!\n");
1089 proto_item_append_text(ti, " [Error: Number of headers is larger than fr ame length]");
1090 col_add_fstr(pinfo->cinfo, COL_INFO, "%s[%d]", frame_type_name, stream_i d);
1091 return frame_length+8;
1092 }
1093 hdr_verb = hdr_url = hdr_version = content_type = content_encoding = NULL;
1094 while (num_headers-- && tvb_reported_length_remaining(header_tvb, hdr_offset ) != 0) {
1095 gchar *header_name;
1096 gchar *header_value;
1097 proto_tree *header_tree;
1098 proto_tree *name_tree;
1099 proto_tree *value_tree;
1100 proto_item *header;
1101 gint16 length;
1102 gint header_length = 0;
1103
1104 hoffset = hdr_offset;
1105
1106 header = proto_tree_add_item(spdy_tree, hf_spdy_header, header_tvb,
1107 hdr_offset, frame_length, FALSE);
1108 header_tree = proto_item_add_subtree(header, ett_spdy_header);
1109
1110 length = tvb_get_ntohs(header_tvb, hdr_offset);
1111 hdr_offset += 2;
1112 header_name = (gchar *)tvb_get_ephemeral_string(header_tvb, hdr_offset, length);
1113 hdr_offset += length;
1114 header_length += hdr_offset - hoffset;
1115 if (tree) {
1116 ti = proto_tree_add_text(header_tree, header_tvb, hoffset, length+2, "Name: %s",
1117 header_name);
1118 name_tree = proto_item_add_subtree(ti, ett_spdy_header_name);
1119 proto_tree_add_uint(name_tree, hf_spdy_length, header_tvb, hoffset, 2, length);
1120 proto_tree_add_string_format(name_tree, hf_spdy_header_name_text, he ader_tvb, hoffset+2, length,
1121 header_name, "Text: %s", format_text(he ader_name, length));
1122 }
1123
1124 hoffset = hdr_offset;
1125 length = tvb_get_ntohs(header_tvb, hdr_offset);
1126 hdr_offset += 2;
1127 header_value = (gchar *)tvb_get_ephemeral_string(header_tvb, hdr_offset, length);
1128 hdr_offset += length;
1129 header_length += hdr_offset - hoffset;
1130 if (tree) {
1131 ti = proto_tree_add_text(header_tree, header_tvb, hoffset, length+2, "Value: %s",
1132 header_value);
1133 value_tree = proto_item_add_subtree(ti, ett_spdy_header_value);
1134 proto_tree_add_uint(value_tree, hf_spdy_length, header_tvb, hoffset, 2, length);
1135 proto_tree_add_string_format(value_tree, hf_spdy_header_value_text, header_tvb, hoffset+2, length,
1136 header_value, "Text: %s", format_text(h eader_value, length));
1137 proto_item_append_text(header, ": %s: %s", header_name, header_value );
1138 proto_item_set_len(header, header_length);
1139 }
1140 if (spdy_debug) printf(" %s: %s\n", header_name, header_value);
1141 /*
1142 * TODO(ers) check that the header name contains only legal characters.
1143 */
1144 if (g_ascii_strcasecmp(header_name, "method") == 0 ||
1145 g_ascii_strcasecmp(header_name, "status") == 0) {
1146 hdr_verb = header_value;
1147 } else if (g_ascii_strcasecmp(header_name, "url") == 0) {
1148 hdr_url = header_value;
1149 } else if (g_ascii_strcasecmp(header_name, "version") == 0) {
1150 hdr_version = header_value;
1151 } else if (g_ascii_strcasecmp(header_name, "content-type") == 0) {
1152 content_type = se_strdup(header_value);
1153 } else if (g_ascii_strcasecmp(header_name, "content-encoding") == 0) {
1154 content_encoding = se_strdup(header_value);
1155 }
1156 }
1157 if (hdr_version != NULL) {
1158 if (hdr_url != NULL) {
1159 col_add_fstr(pinfo->cinfo, COL_INFO, "%s[%d]: %s %s %s",
1160 frame_type_name, stream_id, hdr_verb, hdr_url, hdr_vers ion);
1161 } else {
1162 col_add_fstr(pinfo->cinfo, COL_INFO, "%s[%d]: %s %s",
1163 frame_type_name, stream_id, hdr_verb, hdr_version);
1164 }
1165 } else {
1166 col_add_fstr(pinfo->cinfo, COL_INFO, "%s[%d]", frame_type_name, stream_i d);
1167 }
1168 /*
1169 * If we expect data on this stream, we need to remember the content
1170 * type and content encoding.
1171 */
1172 if (content_type != NULL && !pinfo->fd->flags.visited) {
1173 gchar *content_type_params = spdy_parse_content_type(content_type);
1174 spdy_save_stream_info(conv_data, stream_id, content_type,
1175 content_type_params, content_encoding);
1176 }
1177
1178 return offset - orig_offset;
1179 }
1180
1181 static int
1182 dissect_spdy(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1183 {
1184 spdy_conv_t *conv_data;
1185 int offset = 0;
1186 int len;
1187 int firstpkt = 1;
1188
1189 /*
1190 * The first byte of a SPDY packet must be either 0 or
1191 * 0x80. If it's not, assume that this is not SPDY.
1192 * (In theory, a data frame could have a stream ID
1193 * >= 2^24, in which case it won't have 0 for a first
1194 * byte, but this is a pretty reliable heuristic for
1195 * now.)
1196 */
1197 guint8 first_byte = tvb_get_guint8(tvb, 0);
1198 if (first_byte != 0x80 && first_byte != 0x0)
1199 return 0;
1200
1201 conv_data = get_spdy_conversation_data(pinfo);
1202
1203 while (tvb_reported_length_remaining(tvb, offset) != 0) {
1204 if (!firstpkt) {
1205 col_add_fstr(pinfo->cinfo, COL_INFO, " >> ");
1206 col_set_fence(pinfo->cinfo, COL_INFO);
1207 }
1208 len = dissect_spdy_message(tvb, offset, pinfo, tree, conv_data);
1209 if (len <= 0)
1210 return 0;
1211 offset += len;
1212 /*
1213 * OK, we've set the Protocol and Info columns for the
1214 * first SPDY message; set a fence so that subsequent
1215 * SPDY messages don't overwrite the Info column.
1216 */
1217 col_set_fence(pinfo->cinfo, COL_INFO);
1218 firstpkt = 0;
1219 }
1220 return 1;
1221 }
1222
1223 static gboolean
1224 dissect_spdy_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1225 {
1226 if (!value_is_in_range(global_spdy_tcp_range, pinfo->destport) &&
1227 !value_is_in_range(global_spdy_tcp_range, pinfo->srcport))
1228 return FALSE;
1229 return dissect_spdy(tvb, pinfo, tree) != 0;
1230 }
1231
1232 static void reinit_spdy(void)
1233 {
1234 }
1235
1236 // NMAKE complains about flags_set_truth not being constant. Duplicate
1237 // the values inside of it.
1238 static const true_false_string tfs_spdy_set_notset = { "Set", "Not set" };
1239
1240 void
1241 proto_register_spdy(void)
1242 {
1243 static hf_register_info hf[] = {
1244 { &hf_spdy_syn_stream,
1245 { "Syn Stream", "spdy.syn_stream",
1246 FT_BYTES, BASE_HEX, NULL, 0x0,
1247 "", HFILL }},
1248 { &hf_spdy_syn_reply,
1249 { "Syn Reply", "spdy.syn_reply",
1250 FT_BYTES, BASE_HEX, NULL, 0x0,
1251 "", HFILL }},
1252 { &hf_spdy_control_bit,
1253 { "Control bit", "spdy.control_bit",
1254 FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1255 "TRUE if SPDY control frame", HFILL }},
1256 { &hf_spdy_version,
1257 { "Version", "spdy.version",
1258 FT_UINT16, BASE_DEC, NULL, 0x0,
1259 "", HFILL }},
1260 { &hf_spdy_type,
1261 { "Type", "spdy.type",
1262 FT_UINT16, BASE_DEC, NULL, 0x0,
1263 "", HFILL }},
1264 { &hf_spdy_flags,
1265 { "Flags", "spdy.flags",
1266 FT_UINT8, BASE_HEX, NULL, 0x0,
1267 "", HFILL }},
1268 { &hf_spdy_flags_fin,
1269 { "Fin", "spdy.flags.fin",
1270 FT_BOOLEAN, 8, TFS(&tfs_spdy_set_notset),
1271 SPDY_FIN, "", HFILL }},
1272 { &hf_spdy_length,
1273 { "Length", "spdy.length",
1274 FT_UINT24, BASE_DEC, NULL, 0x0,
1275 "", HFILL }},
1276 { &hf_spdy_header,
1277 { "Header", "spdy.header",
1278 FT_NONE, BASE_NONE, NULL, 0x0,
1279 "", HFILL }},
1280 { &hf_spdy_header_name,
1281 { "Name", "spdy.header.name",
1282 FT_NONE, BASE_NONE, NULL, 0x0,
1283 "", HFILL }},
1284 { &hf_spdy_header_name_text,
1285 { "Text", "spdy.header.name.text",
1286 FT_STRING, BASE_NONE, NULL, 0x0,
1287 "", HFILL }},
1288 { &hf_spdy_header_value,
1289 { "Value", "spdy.header.value",
1290 FT_NONE, BASE_NONE, NULL, 0x0,
1291 "", HFILL }},
1292 { &hf_spdy_header_value_text,
1293 { "Text", "spdy.header.value.text",
1294 FT_STRING, BASE_NONE, NULL, 0x0,
1295 "", HFILL }},
1296 { &hf_spdy_streamid,
1297 { "Stream ID", "spdy.streamid",
1298 FT_UINT32, BASE_DEC, NULL, 0x0,
1299 "", HFILL }},
1300 { &hf_spdy_priority,
1301 { "Priority", "spdy.priority",
1302 FT_UINT8, BASE_DEC, NULL, 0x0,
1303 "", HFILL }},
1304 { &hf_spdy_num_headers,
1305 { "Number of headers", "spdy.numheaders",
1306 FT_UINT16, BASE_DEC, NULL, 0x0,
1307 "", HFILL }},
1308 { &hf_spdy_num_headers_string,
1309 { "Number of headers", "spdy.numheaders",
1310 FT_STRING, BASE_NONE, NULL, 0x0,
1311 "", HFILL }},
1312 };
1313 static gint *ett[] = {
1314 &ett_spdy,
1315 &ett_spdy_syn_stream,
1316 &ett_spdy_syn_reply,
1317 &ett_spdy_fin_stream,
1318 &ett_spdy_flags,
1319 &ett_spdy_header,
1320 &ett_spdy_header_name,
1321 &ett_spdy_header_value,
1322 &ett_spdy_encoded_entity,
1323 };
1324
1325 module_t *spdy_module;
1326
1327 proto_spdy = proto_register_protocol("SPDY", "SPDY", "spdy");
1328 proto_register_field_array(proto_spdy, hf, array_length(hf));
1329 proto_register_subtree_array(ett, array_length(ett));
1330 new_register_dissector("spdy", dissect_spdy, proto_spdy);
1331 spdy_module = prefs_register_protocol(proto_spdy, reinit_spdy);
1332 prefs_register_bool_preference(spdy_module, "desegment_headers",
1333 "Reassemble SPDY control frames spanning mult iple TCP segments",
1334 "Whether the SPDY dissector should reassemble control frames "
1335 "spanning multiple TCP segments. "
1336 "To use this option, you must also enable "
1337 "\"Allow subdissectors to reassemble TCP stre ams\" in the TCP protocol settings.",
1338 &spdy_desegment_control_frames);
1339 prefs_register_bool_preference(spdy_module, "desegment_body",
1340 "Reassemble SPDY bodies spanning multiple TCP segments",
1341 "Whether the SPDY dissector should reassemble "
1342 "data frames spanning multiple TCP segments. "
1343 "To use this option, you must also enable "
1344 "\"Allow subdissectors to reassemble TCP stre ams\" in the TCP protocol settings.",
1345 &spdy_desegment_data_frames);
1346 prefs_register_bool_preference(spdy_module, "assemble_data_frames",
1347 "Assemble SPDY bodies that consist of multipl e DATA frames",
1348 "Whether the SPDY dissector should reassemble multiple "
1349 "data frames into an entity body.",
1350 &spdy_assemble_entity_bodies);
1351 #ifdef HAVE_LIBZ
1352 prefs_register_bool_preference(spdy_module, "decompress_headers",
1353 "Uncompress SPDY headers",
1354 "Whether to uncompress SPDY headers.",
1355 &spdy_decompress_headers);
1356 prefs_register_bool_preference(spdy_module, "decompress_body",
1357 "Uncompress entity bodies",
1358 "Whether to uncompress entity bodies that are compressed "
1359 "using \"Content-Encoding: \"",
1360 &spdy_decompress_body);
1361 #endif
1362 prefs_register_bool_preference(spdy_module, "debug_output",
1363 "Print debug info on stdout",
1364 "Print debug info on stdout",
1365 &spdy_debug);
1366 #if 0
1367 prefs_register_string_preference(ssl_module, "debug_file", "SPDY debug file" ,
1368 "Redirect SPDY debug to file name; "
1369 "leave empty to disable debugging, "
1370 "or use \"" SPDY_DEBUG_USE_STDOUT "\""
1371 " to redirect output to stdout\n",
1372 (const gchar **)&sdpy_debug_file_name);
1373 #endif
1374 prefs_register_obsolete_preference(spdy_module, "tcp_alternate_port");
1375
1376 range_convert_str(&global_spdy_tcp_range, TCP_DEFAULT_RANGE, 65535);
1377 spdy_tcp_range = range_empty();
1378 prefs_register_range_preference(spdy_module, "tcp.port", "TCP Ports",
1379 "TCP Ports range",
1380 &global_spdy_tcp_range, 65535);
1381
1382 range_convert_str(&global_spdy_ssl_range, SSL_DEFAULT_RANGE, 65535);
1383 spdy_ssl_range = range_empty();
1384 prefs_register_range_preference(spdy_module, "ssl.port", "SSL/TLS Ports",
1385 "SSL/TLS Ports range",
1386 &global_spdy_ssl_range, 65535);
1387
1388 spdy_handle = new_create_dissector_handle(dissect_spdy, proto_spdy);
1389 /*
1390 * Register for tapping
1391 */
1392 spdy_tap = register_tap("spdy"); /* SPDY statistics tap */
1393 spdy_eo_tap = register_tap("spdy_eo"); /* SPDY Export Object tap */
1394 }
1395
1396 void
1397 proto_reg_handoff_spdy(void)
1398 {
1399 data_handle = find_dissector("data");
1400 media_handle = find_dissector("media");
1401 heur_dissector_add("tcp", dissect_spdy_heur, proto_spdy);
1402 }
1403
1404 /*
1405 * Content-Type: message/http
1406 */
1407
1408 static gint proto_message_spdy = -1;
1409 static gint ett_message_spdy = -1;
1410
1411 static void
1412 dissect_message_spdy(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1413 {
1414 proto_tree *subtree;
1415 proto_item *ti;
1416 gint offset = 0, next_offset;
1417 gint len;
1418
1419 if (check_col(pinfo->cinfo, COL_INFO))
1420 col_append_str(pinfo->cinfo, COL_INFO, " (message/spdy)");
1421 if (tree) {
1422 ti = proto_tree_add_item(tree, proto_message_spdy,
1423 tvb, 0, -1, FALSE);
1424 subtree = proto_item_add_subtree(ti, ett_message_spdy);
1425 while (tvb_reported_length_remaining(tvb, offset) != 0) {
1426 len = tvb_find_line_end(tvb, offset,
1427 tvb_ensure_length_remaining(tvb, offset) ,
1428 &next_offset, FALSE);
1429 if (len == -1)
1430 break;
1431 proto_tree_add_text(subtree, tvb, offset, next_offset - offset,
1432 "%s", tvb_format_text(tvb, offset, len)) ;
1433 offset = next_offset;
1434 }
1435 }
1436 }
1437
1438 void
1439 proto_register_message_spdy(void)
1440 {
1441 static gint *ett[] = {
1442 &ett_message_spdy,
1443 };
1444
1445 proto_message_spdy = proto_register_protocol(
1446 "Media Type: message/spdy",
1447 "message/spdy",
1448 "message-spdy"
1449 );
1450 proto_register_subtree_array(ett, array_length(ett));
1451 }
1452
1453 void
1454 proto_reg_handoff_message_spdy(void)
1455 {
1456 dissector_handle_t message_spdy_handle;
1457
1458 message_spdy_handle = create_dissector_handle(dissect_message_spdy,
1459 proto_message_spdy);
1460
1461 dissector_add_string("media_type", "message/spdy", message_spdy_handle);
1462
1463 reinit_spdy();
1464 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698