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