summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/tools/spdyshark/AUTHORS2
-rw-r--r--net/tools/spdyshark/COPYING340
-rw-r--r--net/tools/spdyshark/ChangeLog0
-rw-r--r--net/tools/spdyshark/INSTALL0
-rw-r--r--net/tools/spdyshark/Makefile.am126
-rw-r--r--net/tools/spdyshark/Makefile.common40
-rw-r--r--net/tools/spdyshark/Makefile.nmake104
-rw-r--r--net/tools/spdyshark/NEWS0
-rw-r--r--net/tools/spdyshark/moduleinfo.h16
-rw-r--r--net/tools/spdyshark/moduleinfo.nmake28
-rw-r--r--net/tools/spdyshark/packet-spdy.c1464
-rw-r--r--net/tools/spdyshark/packet-spdy.h46
-rw-r--r--net/tools/spdyshark/plugin.rc.in34
13 files changed, 2200 insertions, 0 deletions
diff --git a/net/tools/spdyshark/AUTHORS b/net/tools/spdyshark/AUTHORS
new file mode 100644
index 0000000..5643b20
--- /dev/null
+++ b/net/tools/spdyshark/AUTHORS
@@ -0,0 +1,2 @@
+Author:
+Eric Shienbrood <ers@google.com>
diff --git a/net/tools/spdyshark/COPYING b/net/tools/spdyshark/COPYING
new file mode 100644
index 0000000..d60c31a
--- /dev/null
+++ b/net/tools/spdyshark/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/net/tools/spdyshark/ChangeLog b/net/tools/spdyshark/ChangeLog
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/net/tools/spdyshark/ChangeLog
diff --git a/net/tools/spdyshark/INSTALL b/net/tools/spdyshark/INSTALL
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/net/tools/spdyshark/INSTALL
diff --git a/net/tools/spdyshark/Makefile.am b/net/tools/spdyshark/Makefile.am
new file mode 100644
index 0000000..b707bae
--- /dev/null
+++ b/net/tools/spdyshark/Makefile.am
@@ -0,0 +1,126 @@
+# Makefile.am
+# Automake file for SPDY plugin
+#
+# $Id$
+#
+# Wireshark - Network traffic analyzer
+# By Gerald Combs <gerald@wireshark.org>
+# Copyright 1998 Gerald Combs
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+INCLUDES = -I$(top_srcdir) -I$(includedir)
+
+include Makefile.common
+
+if HAVE_WARNINGS_AS_ERRORS
+AM_CFLAGS = -Werror
+endif
+
+plugin_LTLIBRARIES = spdy.la
+spdy_la_SOURCES = \
+ plugin.c \
+ moduleinfo.h \
+ $(DISSECTOR_SRC) \
+ $(DISSECTOR_SUPPORT_SRC) \
+ $(DISSECTOR_INCLUDES)
+spdy_la_LDFLAGS = -module -avoid-version
+spdy_la_LIBADD = @PLUGIN_LIBS@
+
+# Libs must be cleared, or else libtool won't create a shared module.
+# If your module needs to be linked against any particular libraries,
+# add them here.
+LIBS =
+
+#
+# Build plugin.c, which contains the plugin version[] string, a
+# function plugin_register() that calls the register routines for all
+# protocols, and a function plugin_reg_handoff() that calls the handoff
+# registration routines for all protocols.
+#
+# We do this by scanning sources. If that turns out to be too slow,
+# maybe we could just require every .o file to have an register routine
+# of a given name (packet-aarp.o -> proto_register_aarp, etc.).
+#
+# Formatting conventions: The name of the proto_register_* routines an
+# proto_reg_handoff_* routines must start in column zero, or must be
+# preceded only by "void " starting in column zero, and must not be
+# inside #if.
+#
+# DISSECTOR_SRC is assumed to have all the files that need to be scanned.
+#
+# For some unknown reason, having a big "for" loop in the Makefile
+# to scan all the files doesn't work with some "make"s; they seem to
+# pass only the first few names in the list to the shell, for some
+# reason.
+#
+# Therefore, we have a script to generate the plugin.c file.
+# The shell script runs slowly, as multiple greps and seds are run
+# for each input file; this is especially slow on Windows. Therefore,
+# if Python is present (as indicated by PYTHON being defined), we run
+# a faster Python script to do that work instead.
+#
+# The first argument is the directory in which the source files live.
+# The second argument is "plugin", to indicate that we should build
+# a plugin.c file for a plugin.
+# All subsequent arguments are the files to scan.
+#
+plugin.c: $(DISSECTOR_SRC) $(top_srcdir)/tools/make-dissector-reg \
+ $(top_srcdir)/tools/make-dissector-reg.py
+ @if test -n "$(PYTHON)"; then \
+ echo Making plugin.c with python ; \
+ $(PYTHON) $(top_srcdir)/tools/make-dissector-reg.py $(srcdir) \
+ plugin $(DISSECTOR_SRC) ; \
+ else \
+ echo Making plugin.c with shell script ; \
+ $(top_srcdir)/tools/make-dissector-reg $(srcdir) \
+ $(plugin_src) plugin $(DISSECTOR_SRC) ; \
+ fi
+
+#
+# Currently plugin.c can be included in the distribution because
+# we always build all protocol dissectors. We used to have to check
+# whether or not to build the snmp dissector. If we again need to
+# variably build something, making plugin.c non-portable, uncomment
+# the dist-hook line below.
+#
+# Oh, yuk. We don't want to include "plugin.c" in the distribution, as
+# its contents depend on the configuration, and therefore we want it
+# to be built when the first "make" is done; however, Automake insists
+# on putting *all* source into the distribution.
+#
+# We work around this by having a "dist-hook" rule that deletes
+# "plugin.c", so that "dist" won't pick it up.
+#
+#dist-hook:
+# @rm -f $(distdir)/plugin.c
+
+CLEANFILES = \
+ spdy \
+ *~
+
+MAINTAINERCLEANFILES = \
+ Makefile.in \
+ plugin.c
+
+EXTRA_DIST = \
+ Makefile.common \
+ Makefile.nmake \
+ moduleinfo.nmake \
+ plugin.rc.in
+
+checkapi:
+ $(PERL) $(top_srcdir)/tools/checkAPIs.pl -g abort -g termoutput $(DISSECTOR_SRC)
diff --git a/net/tools/spdyshark/Makefile.common b/net/tools/spdyshark/Makefile.common
new file mode 100644
index 0000000..9386f46
--- /dev/null
+++ b/net/tools/spdyshark/Makefile.common
@@ -0,0 +1,40 @@
+# Makefile.common for SPDY plugin
+# Contains the stuff from Makefile.am and Makefile.nmake that is
+# a) common to both files and
+# b) portable between both files
+#
+# $Id$
+#
+# Wireshark - Network traffic analyzer
+# By Gerald Combs <gerald@wireshark.org>
+# Copyright 1998 Gerald Combs
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# the name of the plugin
+PLUGIN_NAME = spdy
+
+# the dissector sources (without any helpers)
+DISSECTOR_SRC = \
+ packet-spdy.c
+
+# corresponding headers
+DISSECTOR_INCLUDES = \
+ packet-spdy.h
+
+# Dissector helpers. They're included in the source files in this
+# directory, but they're not dissectors themselves, i.e. they're not
+# used to generate "register.c").
+#DISSECTOR_SUPPORT_SRC =
diff --git a/net/tools/spdyshark/Makefile.nmake b/net/tools/spdyshark/Makefile.nmake
new file mode 100644
index 0000000..d554918
--- /dev/null
+++ b/net/tools/spdyshark/Makefile.nmake
@@ -0,0 +1,104 @@
+# Makefile.nmake
+# nmake file for Wireshark plugin
+#
+# $Id: Makefile.nmake 27579 2009-03-02 18:57:35Z gerald $
+#
+
+include ..\..\config.nmake
+include moduleinfo.nmake
+
+include Makefile.common
+
+CFLAGS=/WX /Zi /DHAVE_CONFIG_H /I../.. $(GLIB_CFLAGS) $(ZLIB_CFLAGS) \
+ /I$(PCAP_DIR)\include -D_U_="" $(LOCAL_CFLAGS)
+
+.c.obj::
+ $(CC) $(CFLAGS) -Fd.\ -c $<
+
+LDFLAGS = $(PLUGIN_LDFLAGS)
+
+!IFDEF ENABLE_LIBWIRESHARK
+LINK_PLUGIN_WITH=..\..\epan\libwireshark.lib $(ZLIB_LIBS)
+CFLAGS=/DHAVE_WIN32_LIBWIRESHARK_LIB /D_NEED_VAR_IMPORT_ $(CFLAGS)
+
+DISSECTOR_OBJECTS = $(DISSECTOR_SRC:.c=.obj)
+
+DISSECTOR_SUPPORT_OBJECTS = $(DISSECTOR_SUPPORT_SRC:.c=.obj)
+
+OBJECTS = $(DISSECTOR_OBJECTS) $(DISSECTOR_SUPPORT_OBJECTS) plugin.obj
+
+RESOURCE=$(PLUGIN_NAME).res
+
+all: $(PLUGIN_NAME).dll
+
+$(PLUGIN_NAME).rc : moduleinfo.nmake
+ sed -e s/@PLUGIN_NAME@/$(PLUGIN_NAME)/ \
+ -e s/@RC_MODULE_VERSION@/$(RC_MODULE_VERSION)/ \
+ -e s/@RC_VERSION@/$(RC_VERSION)/ \
+ -e s/@MODULE_VERSION@/$(MODULE_VERSION)/ \
+ -e s/@PACKAGE@/$(PACKAGE)/ \
+ -e s/@VERSION@/$(VERSION)/ \
+ -e s/@MSVC_VARIANT@/$(MSVC_VARIANT)/ \
+ < plugin.rc.in > $@
+
+$(PLUGIN_NAME).dll $(PLUGIN_NAME).exp $(PLUGIN_NAME).lib : $(OBJECTS) $(LINK_PLUGIN_WITH) $(RESOURCE)
+ link -dll /out:$(PLUGIN_NAME).dll $(LDFLAGS) $(OBJECTS) $(LINK_PLUGIN_WITH) \
+ $(GLIB_LIBS) $(RESOURCE)
+
+#
+# Build plugin.c, which contains the plugin version[] string, a
+# function plugin_register() that calls the register routines for all
+# protocols, and a function plugin_reg_handoff() that calls the handoff
+# registration routines for all protocols.
+#
+# We do this by scanning sources. If that turns out to be too slow,
+# maybe we could just require every .o file to have an register routine
+# of a given name (packet-aarp.o -> proto_register_aarp, etc.).
+#
+# Formatting conventions: The name of the proto_register_* routines an
+# proto_reg_handoff_* routines must start in column zero, or must be
+# preceded only by "void " starting in column zero, and must not be
+# inside #if.
+#
+# DISSECTOR_SRC is assumed to have all the files that need to be scanned.
+#
+# For some unknown reason, having a big "for" loop in the Makefile
+# to scan all the files doesn't work with some "make"s; they seem to
+# pass only the first few names in the list to the shell, for some
+# reason.
+#
+# Therefore, we have a script to generate the plugin.c file.
+# The shell script runs slowly, as multiple greps and seds are run
+# for each input file; this is especially slow on Windows. Therefore,
+# if Python is present (as indicated by PYTHON being defined), we run
+# a faster Python script to do that work instead.
+#
+# The first argument is the directory in which the source files live.
+# The second argument is "plugin", to indicate that we should build
+# a plugin.c file for a plugin.
+# All subsequent arguments are the files to scan.
+#
+!IFDEF PYTHON
+plugin.c: $(DISSECTOR_SRC) moduleinfo.h ../../tools/make-dissector-reg.py
+ @echo Making plugin.c (using python)
+ @$(PYTHON) "../../tools/make-dissector-reg.py" . plugin $(DISSECTOR_SRC)
+!ELSE
+plugin.c: $(DISSECTOR_SRC) moduleinfo.h ../../tools/make-dissector-reg
+ @echo Making plugin.c (using sh)
+ @$(SH) ../../tools/make-dissector-reg . plugin $(DISSECTOR_SRC)
+!ENDIF
+
+!ENDIF
+
+clean:
+ rm -f $(OBJECTS) $(RESOURCE) plugin.c *.pdb \
+ $(PLUGIN_NAME).dll $(PLUGIN_NAME).dll.manifest $(PLUGIN_NAME).lib \
+ $(PLUGIN_NAME).exp $(PLUGIN_NAME).rc
+
+distclean: clean
+
+maintainer-clean: distclean
+
+checkapi:
+# TODO: Fix api's :)
+# $(PERL) ../../tools/checkAPIs.pl -g abort -g termoutput $(DISSECTOR_SRC)
diff --git a/net/tools/spdyshark/NEWS b/net/tools/spdyshark/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/net/tools/spdyshark/NEWS
diff --git a/net/tools/spdyshark/moduleinfo.h b/net/tools/spdyshark/moduleinfo.h
new file mode 100644
index 0000000..9e5f7c8
--- /dev/null
+++ b/net/tools/spdyshark/moduleinfo.h
@@ -0,0 +1,16 @@
+/* Included *after* config.h, in order to re-define these macros */
+
+#ifdef PACKAGE
+#undef PACKAGE
+#endif
+
+/* Name of package */
+#define PACKAGE "spdy"
+
+
+#ifdef VERSION
+#undef VERSION
+#endif
+
+/* Version number of package */
+#define VERSION "0.1.0"
diff --git a/net/tools/spdyshark/moduleinfo.nmake b/net/tools/spdyshark/moduleinfo.nmake
new file mode 100644
index 0000000..bbdf766
--- /dev/null
+++ b/net/tools/spdyshark/moduleinfo.nmake
@@ -0,0 +1,28 @@
+#
+# $Id$
+#
+
+# The name
+PACKAGE=spdy
+
+# The version
+MODULE_VERSION_MAJOR=0
+MODULE_VERSION_MINOR=1
+MODULE_VERSION_MICRO=0
+MODULE_VERSION_EXTRA=0
+
+#
+# The RC_VERSION should be comma-separated, not dot-separated,
+# as per Graham Bloice's message in
+#
+# http://www.ethereal.com/lists/ethereal-dev/200303/msg00283.html
+#
+# "The RC_VERSION variable in config.nmake should be comma separated.
+# This allows the resources to be built correctly and the version
+# number to be correctly displayed in the explorer properties dialog
+# for the executables, and XP's tooltip, rather than 0.0.0.0."
+#
+
+MODULE_VERSION=$(MODULE_VERSION_MAJOR).$(MODULE_VERSION_MINOR).$(MODULE_VERSION_MICRO).$(MODULE_VERSION_EXTRA)
+RC_MODULE_VERSION=$(MODULE_VERSION_MAJOR),$(MODULE_VERSION_MINOR),$(MODULE_VERSION_MICRO),$(MODULE_VERSION_EXTRA)
+
diff --git a/net/tools/spdyshark/packet-spdy.c b/net/tools/spdyshark/packet-spdy.c
new file mode 100644
index 0000000..4b48596
--- /dev/null
+++ b/net/tools/spdyshark/packet-spdy.c
@@ -0,0 +1,1464 @@
+/* packet-spdy.c
+ * Routines for SPDY packet disassembly
+ * For now, the protocol spec can be found at
+ * http://dev.chromium.org/spdy/spdy-protocol
+ *
+ * Copyright 2010, Google Inc.
+ * Eric Shienbrood <ers@google.com>
+ *
+ * $Id$
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * Originally based on packet-http.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <ctype.h>
+
+#include <glib.h>
+#include <epan/conversation.h>
+#include <epan/packet.h>
+#include <epan/strutil.h>
+#include <epan/base64.h>
+#include <epan/emem.h>
+#include <epan/stats_tree.h>
+
+#include <epan/req_resp_hdrs.h>
+#include <plugins/spdy/packet-spdy.h>
+#include <epan/dissectors/packet-tcp.h>
+#include <epan/dissectors/packet-ssl.h>
+#include <epan/prefs.h>
+#include <epan/expert.h>
+#include <epan/uat.h>
+
+#define SPDY_FIN 0x01
+
+/* The types of SPDY control frames */
+typedef enum _spdy_type {
+ SPDY_DATA,
+ SPDY_SYN_STREAM,
+ SPDY_SYN_REPLY,
+ SPDY_FIN_STREAM,
+ SPDY_HELLO,
+ SPDY_NOOP,
+ SPDY_PING,
+ SPDY_INVALID
+} spdy_frame_type_t;
+
+static const char *frame_type_names[] = {
+ "DATA", "SYN_STREAM", "SYN_REPLY", "FIN_STREAM", "HELLO", "NOOP",
+ "PING", "INVALID"
+};
+
+/*
+ * This structure will be tied to each SPDY frame.
+ * Note that there may be multiple SPDY frames
+ * in one packet.
+ */
+typedef struct _spdy_frame_info_t {
+ guint32 stream_id;
+ guint8 *header_block;
+ guint header_block_len;
+ guint16 frame_type;
+} spdy_frame_info_t;
+
+/*
+ * This structures keeps track of all the data frames
+ * associated with a stream, so that they can be
+ * reassembled into a single chunk.
+ */
+typedef struct _spdy_data_frame_t {
+ guint8 *data;
+ guint32 length;
+ guint32 framenum;
+} spdy_data_frame_t;
+
+typedef struct _spdy_stream_info_t {
+ gchar *content_type;
+ gchar *content_type_parameters;
+ gchar *content_encoding;
+ GSList *data_frames;
+ tvbuff_t *assembled_data;
+ guint num_data_frames;
+} spdy_stream_info_t;
+
+#include <epan/tap.h>
+
+
+static int spdy_tap = -1;
+static int spdy_eo_tap = -1;
+
+static int proto_spdy = -1;
+static int hf_spdy_syn_stream = -1;
+static int hf_spdy_syn_reply = -1;
+static int hf_spdy_control_bit = -1;
+static int hf_spdy_version = -1;
+static int hf_spdy_type = -1;
+static int hf_spdy_flags = -1;
+static int hf_spdy_flags_fin = -1;
+static int hf_spdy_length = -1;
+static int hf_spdy_header = -1;
+static int hf_spdy_header_name = -1;
+static int hf_spdy_header_name_text = -1;
+static int hf_spdy_header_value = -1;
+static int hf_spdy_header_value_text = -1;
+static int hf_spdy_streamid = -1;
+static int hf_spdy_priority = -1;
+static int hf_spdy_num_headers = -1;
+static int hf_spdy_num_headers_string = -1;
+
+static gint ett_spdy = -1;
+static gint ett_spdy_syn_stream = -1;
+static gint ett_spdy_syn_reply = -1;
+static gint ett_spdy_fin_stream = -1;
+static gint ett_spdy_flags = -1;
+static gint ett_spdy_header = -1;
+static gint ett_spdy_header_name = -1;
+static gint ett_spdy_header_value = -1;
+
+static gint ett_spdy_encoded_entity = -1;
+
+static dissector_handle_t data_handle;
+static dissector_handle_t media_handle;
+static dissector_handle_t spdy_handle;
+
+/* Stuff for generation/handling of fields for custom HTTP headers */
+typedef struct _header_field_t {
+ gchar* header_name;
+ gchar* header_desc;
+} header_field_t;
+
+/*
+ * desegmentation of SPDY control frames
+ * (when we are over TCP or another protocol providing the desegmentation API)
+ */
+static gboolean spdy_desegment_control_frames = TRUE;
+
+/*
+ * desegmentation of SPDY data frames bodies
+ * (when we are over TCP or another protocol providing the desegmentation API)
+ * TODO let the user filter on content-type the bodies he wants desegmented
+ */
+static gboolean spdy_desegment_data_frames = TRUE;
+
+static gboolean spdy_assemble_entity_bodies = TRUE;
+
+/*
+ * Decompression of zlib encoded entities.
+ */
+#ifdef HAVE_LIBZ
+static gboolean spdy_decompress_body = TRUE;
+static gboolean spdy_decompress_headers = TRUE;
+#else
+static gboolean spdy_decompress_body = FALSE;
+static gboolean spdy_decompress_headers = FALSE;
+#endif
+static gboolean spdy_debug = FALSE;
+
+#define TCP_PORT_DAAP 3689
+
+/*
+ * SSDP is implemented atop HTTP (yes, it really *does* run over UDP).
+ */
+#define TCP_PORT_SSDP 1900
+#define UDP_PORT_SSDP 1900
+
+/*
+ * tcp and ssl ports
+ */
+
+#define TCP_DEFAULT_RANGE "80,8080"
+#define SSL_DEFAULT_RANGE "443"
+
+static range_t *global_spdy_tcp_range = NULL;
+static range_t *global_spdy_ssl_range = NULL;
+
+static range_t *spdy_tcp_range = NULL;
+static range_t *spdy_ssl_range = NULL;
+
+static const value_string vals_status_code[] = {
+ { 100, "Continue" },
+ { 101, "Switching Protocols" },
+ { 102, "Processing" },
+ { 199, "Informational - Others" },
+
+ { 200, "OK"},
+ { 201, "Created"},
+ { 202, "Accepted"},
+ { 203, "Non-authoritative Information"},
+ { 204, "No Content"},
+ { 205, "Reset Content"},
+ { 206, "Partial Content"},
+ { 207, "Multi-Status"},
+ { 299, "Success - Others"},
+
+ { 300, "Multiple Choices"},
+ { 301, "Moved Permanently"},
+ { 302, "Found"},
+ { 303, "See Other"},
+ { 304, "Not Modified"},
+ { 305, "Use Proxy"},
+ { 307, "Temporary Redirect"},
+ { 399, "Redirection - Others"},
+
+ { 400, "Bad Request"},
+ { 401, "Unauthorized"},
+ { 402, "Payment Required"},
+ { 403, "Forbidden"},
+ { 404, "Not Found"},
+ { 405, "Method Not Allowed"},
+ { 406, "Not Acceptable"},
+ { 407, "Proxy Authentication Required"},
+ { 408, "Request Time-out"},
+ { 409, "Conflict"},
+ { 410, "Gone"},
+ { 411, "Length Required"},
+ { 412, "Precondition Failed"},
+ { 413, "Request Entity Too Large"},
+ { 414, "Request-URI Too Long"},
+ { 415, "Unsupported Media Type"},
+ { 416, "Requested Range Not Satisfiable"},
+ { 417, "Expectation Failed"},
+ { 418, "I'm a teapot"}, /* RFC 2324 */
+ { 422, "Unprocessable Entity"},
+ { 423, "Locked"},
+ { 424, "Failed Dependency"},
+ { 499, "Client Error - Others"},
+
+ { 500, "Internal Server Error"},
+ { 501, "Not Implemented"},
+ { 502, "Bad Gateway"},
+ { 503, "Service Unavailable"},
+ { 504, "Gateway Time-out"},
+ { 505, "HTTP Version not supported"},
+ { 507, "Insufficient Storage"},
+ { 599, "Server Error - Others"},
+
+ { 0, NULL}
+};
+
+static const char spdy_dictionary[] =
+ "optionsgetheadpostputdeletetraceacceptaccept-charsetaccept-encodingaccept-"
+ "languageauthorizationexpectfromhostif-modified-sinceif-matchif-none-matchi"
+ "f-rangeif-unmodifiedsincemax-forwardsproxy-authorizationrangerefererteuser"
+ "-agent10010120020120220320420520630030130230330430530630740040140240340440"
+ "5406407408409410411412413414415416417500501502503504505accept-rangesageeta"
+ "glocationproxy-authenticatepublicretry-afterservervarywarningwww-authentic"
+ "ateallowcontent-basecontent-encodingcache-controlconnectiondatetrailertran"
+ "sfer-encodingupgradeviawarningcontent-languagecontent-lengthcontent-locati"
+ "oncontent-md5content-rangecontent-typeetagexpireslast-modifiedset-cookieMo"
+ "ndayTuesdayWednesdayThursdayFridaySaturdaySundayJanFebMarAprMayJunJulAugSe"
+ "pOctNovDecchunkedtext/htmlimage/pngimage/jpgimage/gifapplication/xmlapplic"
+ "ation/xhtmltext/plainpublicmax-agecharset=iso-8859-1utf-8gzipdeflateHTTP/1"
+ ".1statusversionurl";
+
+static void reset_decompressors(void)
+{
+ if (spdy_debug) printf("Should reset SPDY decompressors\n");
+}
+
+static spdy_conv_t *
+get_spdy_conversation_data(packet_info *pinfo)
+{
+ conversation_t *conversation;
+ spdy_conv_t *conv_data;
+ int retcode;
+
+ conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
+ if (spdy_debug) {
+ printf("\n===========================================\n\n");
+ printf("Conversation for frame #%d is %p\n", pinfo->fd->num, conversation);
+ if (conversation)
+ printf(" conv_data=%p\n", conversation_get_proto_data(conversation, proto_spdy));
+ }
+
+ if(!conversation) /* Conversation does not exist yet - create it */
+ conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
+
+ /* Retrieve information from conversation
+ */
+ conv_data = conversation_get_proto_data(conversation, proto_spdy);
+ if(!conv_data) {
+ /* Setup the conversation structure itself */
+ conv_data = se_alloc0(sizeof(spdy_conv_t));
+
+ conv_data->streams = NULL;
+ if (spdy_decompress_headers) {
+ conv_data->rqst_decompressor = se_alloc0(sizeof(z_stream));
+ conv_data->rply_decompressor = se_alloc0(sizeof(z_stream));
+ retcode = inflateInit(conv_data->rqst_decompressor);
+ if (retcode == Z_OK)
+ retcode = inflateInit(conv_data->rply_decompressor);
+ if (retcode != Z_OK)
+ printf("frame #%d: inflateInit() failed: %d\n", pinfo->fd->num, retcode);
+ else if (spdy_debug)
+ printf("created decompressor\n");
+ conv_data->dictionary_id = adler32(0L, Z_NULL, 0);
+ conv_data->dictionary_id = adler32(conv_data->dictionary_id,
+ spdy_dictionary,
+ sizeof(spdy_dictionary));
+ }
+
+ conversation_add_proto_data(conversation, proto_spdy, conv_data);
+ register_postseq_cleanup_routine(reset_decompressors);
+ }
+ return conv_data;
+}
+
+static void
+spdy_save_stream_info(spdy_conv_t *conv_data,
+ guint32 stream_id,
+ gchar *content_type,
+ gchar *content_type_params,
+ gchar *content_encoding)
+{
+ spdy_stream_info_t *si;
+
+ if (conv_data->streams == NULL)
+ conv_data->streams = g_array_new(FALSE, TRUE, sizeof(spdy_stream_info_t *));
+ if (stream_id < conv_data->streams->len)
+ DISSECTOR_ASSERT(g_array_index(conv_data->streams, spdy_stream_info_t*, stream_id) == NULL);
+ else
+ g_array_set_size(conv_data->streams, stream_id+1);
+ si = se_alloc(sizeof(spdy_stream_info_t));
+ si->content_type = content_type;
+ si->content_type_parameters = content_type_params;
+ si->content_encoding = content_encoding;
+ si->data_frames = NULL;
+ si->num_data_frames = 0;
+ si->assembled_data = NULL;
+ g_array_index(conv_data->streams, spdy_stream_info_t*, stream_id) = si;
+ if (spdy_debug)
+ printf("Saved stream info for ID %u, content type %s\n", stream_id, content_type);
+}
+
+static spdy_stream_info_t *
+spdy_get_stream_info(spdy_conv_t *conv_data, guint32 stream_id)
+{
+ if (conv_data->streams == NULL || stream_id >= conv_data->streams->len)
+ return NULL;
+ else
+ return g_array_index(conv_data->streams, spdy_stream_info_t*, stream_id);
+}
+
+static void
+spdy_add_data_chunk(spdy_conv_t *conv_data, guint32 stream_id, guint32 frame,
+ guint8 *data, guint32 length)
+{
+ spdy_stream_info_t *si = spdy_get_stream_info(conv_data, stream_id);
+
+ if (si == NULL) {
+ if (spdy_debug) printf("No stream_info found for stream %d\n", stream_id);
+ } else {
+ spdy_data_frame_t *df = g_malloc(sizeof(spdy_data_frame_t));
+ df->data = data;
+ df->length = length;
+ df->framenum = frame;
+ si->data_frames = g_slist_append(si->data_frames, df);
+ ++si->num_data_frames;
+ if (spdy_debug)
+ printf("Saved %u bytes of data for stream %u frame %u\n",
+ length, stream_id, df->framenum);
+ }
+}
+
+static void
+spdy_increment_data_chunk_count(spdy_conv_t *conv_data, guint32 stream_id)
+{
+ spdy_stream_info_t *si = spdy_get_stream_info(conv_data, stream_id);
+ if (si != NULL)
+ ++si->num_data_frames;
+}
+
+/*
+ * Return the number of data frames saved so far for the specified stream.
+ */
+static guint
+spdy_get_num_data_frames(spdy_conv_t *conv_data, guint32 stream_id)
+{
+ spdy_stream_info_t *si = spdy_get_stream_info(conv_data, stream_id);
+
+ return si == NULL ? 0 : si->num_data_frames;
+}
+
+static spdy_stream_info_t *
+spdy_assemble_data_frames(spdy_conv_t *conv_data, guint32 stream_id)
+{
+ spdy_stream_info_t *si = spdy_get_stream_info(conv_data, stream_id);
+ tvbuff_t *tvb;
+
+ if (si == NULL)
+ return NULL;
+
+ /*
+ * Compute the total amount of data and concatenate the
+ * data chunks, if it hasn't already been done.
+ */
+ if (si->assembled_data == NULL) {
+ spdy_data_frame_t *df;
+ guint8 *data;
+ guint32 datalen;
+ guint32 offset;
+ guint32 framenum;
+ GSList *dflist = si->data_frames;
+ if (dflist == NULL)
+ return si;
+ dflist = si->data_frames;
+ datalen = 0;
+ /*
+ * I'd like to use a composite tvbuff here, but since
+ * only a real-data tvbuff can be the child of another
+ * tvb, I can't. It would be nice if this limitation
+ * could be fixed.
+ */
+ while (dflist != NULL) {
+ df = dflist->data;
+ datalen += df->length;
+ dflist = g_slist_next(dflist);
+ }
+ if (datalen != 0) {
+ data = se_alloc(datalen);
+ dflist = si->data_frames;
+ offset = 0;
+ framenum = 0;
+ while (dflist != NULL) {
+ df = dflist->data;
+ memcpy(data+offset, df->data, df->length);
+ offset += df->length;
+ dflist = g_slist_next(dflist);
+ }
+ tvb = tvb_new_real_data(data, datalen, datalen);
+ si->assembled_data = tvb;
+ }
+ }
+ return si;
+}
+
+static void
+spdy_discard_data_frames(spdy_stream_info_t *si)
+{
+ GSList *dflist = si->data_frames;
+ spdy_data_frame_t *df;
+
+ if (dflist == NULL)
+ return;
+ while (dflist != NULL) {
+ df = dflist->data;
+ if (df->data != NULL) {
+ g_free(df->data);
+ df->data = NULL;
+ }
+ dflist = g_slist_next(dflist);
+ }
+ /*g_slist_free(si->data_frames);
+ si->data_frames = NULL; */
+}
+
+static int
+dissect_spdy_data_frame(tvbuff_t *tvb, int offset,
+ packet_info *pinfo,
+ proto_tree *top_level_tree,
+ proto_tree *spdy_tree,
+ proto_item *spdy_proto,
+ spdy_conv_t *conv_data)
+{
+ guint32 stream_id;
+ guint8 flags;
+ guint32 frame_length;
+ proto_item *ti;
+ proto_tree *flags_tree;
+ guint32 reported_datalen;
+ guint32 datalen;
+ dissector_table_t media_type_subdissector_table;
+ dissector_table_t port_subdissector_table;
+ dissector_handle_t handle;
+ guint num_data_frames;
+ gboolean dissected;
+
+ stream_id = tvb_get_bits32(tvb, (offset << 3) + 1, 31, FALSE);
+ flags = tvb_get_guint8(tvb, offset+4);
+ frame_length = tvb_get_ntoh24(tvb, offset+5);
+
+ if (spdy_debug)
+ printf("Data frame [stream_id=%u flags=0x%x length=%d]\n",
+ stream_id, flags, frame_length);
+ if (spdy_tree) proto_item_append_text(spdy_tree, ", data frame");
+ col_add_fstr(pinfo->cinfo, COL_INFO, "DATA[%u] length=%d",
+ stream_id, frame_length);
+
+ proto_item_append_text(spdy_proto, ":%s stream=%d length=%d",
+ flags & SPDY_FIN ? " [FIN]" : "",
+ stream_id, frame_length);
+
+ proto_tree_add_boolean(spdy_tree, hf_spdy_control_bit, tvb, offset, 1, 0);
+ proto_tree_add_uint(spdy_tree, hf_spdy_streamid, tvb, offset, 4, stream_id);
+ ti = proto_tree_add_uint_format(spdy_tree, hf_spdy_flags, tvb, offset+4, 1, flags,
+ "Flags: 0x%02x%s", flags, flags&SPDY_FIN ? " (FIN)" : "");
+
+ flags_tree = proto_item_add_subtree(ti, ett_spdy_flags);
+ proto_tree_add_boolean(flags_tree, hf_spdy_flags_fin, tvb, offset+4, 1, flags);
+ proto_tree_add_uint(spdy_tree, hf_spdy_length, tvb, offset+5, 3, frame_length);
+
+ datalen = tvb_length_remaining(tvb, offset);
+ if (datalen > frame_length)
+ datalen = frame_length;
+
+ reported_datalen = tvb_reported_length_remaining(tvb, offset);
+ if (reported_datalen > frame_length)
+ reported_datalen = frame_length;
+
+ num_data_frames = spdy_get_num_data_frames(conv_data, stream_id);
+ if (datalen != 0 || num_data_frames != 0) {
+ /*
+ * There's stuff left over; process it.
+ */
+ tvbuff_t *next_tvb = NULL;
+ tvbuff_t *data_tvb = NULL;
+ spdy_stream_info_t *si = NULL;
+ void *save_private_data = NULL;
+ guint8 *copied_data;
+ gboolean private_data_changed = FALSE;
+ gboolean is_single_chunk = FALSE;
+ gboolean have_entire_body;
+
+ /*
+ * Create a tvbuff for the payload.
+ */
+ if (datalen != 0) {
+ next_tvb = tvb_new_subset(tvb, offset+8, datalen,
+ reported_datalen);
+ is_single_chunk = num_data_frames == 0 && (flags & SPDY_FIN) != 0;
+ if (!pinfo->fd->flags.visited) {
+ if (!is_single_chunk) {
+ if (spdy_assemble_entity_bodies) {
+ copied_data = tvb_memdup(next_tvb, 0, datalen);
+ spdy_add_data_chunk(conv_data, stream_id, pinfo->fd->num,
+ copied_data, datalen);
+ } else
+ spdy_increment_data_chunk_count(conv_data, stream_id);
+ }
+ }
+ } else
+ is_single_chunk = (num_data_frames == 1);
+
+ if (!(flags & SPDY_FIN)) {
+ col_set_fence(pinfo->cinfo, COL_INFO);
+ col_add_fstr(pinfo->cinfo, COL_INFO, " (partial entity)");
+ proto_item_append_text(spdy_proto, " (partial entity body)");
+ /* would like the proto item to say */
+ /* " (entity body fragment N of M)" */
+ goto body_dissected;
+ }
+ have_entire_body = is_single_chunk;
+ /*
+ * On seeing the last data frame in a stream, we can
+ * reassemble the frames into one data block.
+ */
+ si = spdy_assemble_data_frames(conv_data, stream_id);
+ if (si == NULL)
+ goto body_dissected;
+ data_tvb = si->assembled_data;
+ if (spdy_assemble_entity_bodies)
+ have_entire_body = TRUE;
+
+ if (!have_entire_body)
+ goto body_dissected;
+
+ if (data_tvb == NULL)
+ data_tvb = next_tvb;
+ else
+ add_new_data_source(pinfo, data_tvb, "Assembled entity body");
+
+ if (have_entire_body && si->content_encoding != NULL &&
+ g_ascii_strcasecmp(si->content_encoding, "identity") != 0) {
+ /*
+ * We currently can't handle, for example, "compress";
+ * just handle them as data for now.
+ *
+ * After July 7, 2004 the LZW patent expires, so support
+ * might be added then. However, I don't think that
+ * anybody ever really implemented "compress", due to
+ * the aforementioned patent.
+ */
+ tvbuff_t *uncomp_tvb = NULL;
+ proto_item *e_ti = NULL;
+ proto_item *ce_ti = NULL;
+ proto_tree *e_tree = NULL;
+
+ if (spdy_decompress_body &&
+ (g_ascii_strcasecmp(si->content_encoding, "gzip") == 0 ||
+ g_ascii_strcasecmp(si->content_encoding, "deflate")
+ == 0)) {
+
+ uncomp_tvb = tvb_child_uncompress(tvb, data_tvb, 0,
+ tvb_length(data_tvb));
+ }
+ /*
+ * Add the encoded entity to the protocol tree
+ */
+ e_ti = proto_tree_add_text(top_level_tree, data_tvb,
+ 0, tvb_length(data_tvb),
+ "Content-encoded entity body (%s): %u bytes",
+ si->content_encoding,
+ tvb_length(data_tvb));
+ e_tree = proto_item_add_subtree(e_ti, ett_spdy_encoded_entity);
+ if (si->num_data_frames > 1) {
+ GSList *dflist;
+ spdy_data_frame_t *df;
+ guint32 framenum;
+ ce_ti = proto_tree_add_text(e_tree, data_tvb, 0,
+ tvb_length(data_tvb),
+ "Assembled from %d frames in packet(s)", si->num_data_frames);
+ dflist = si->data_frames;
+ framenum = 0;
+ while (dflist != NULL) {
+ df = dflist->data;
+ if (framenum != df->framenum) {
+ proto_item_append_text(ce_ti, " #%u", df->framenum);
+ framenum = df->framenum;
+ }
+ dflist = g_slist_next(dflist);
+ }
+ }
+
+ if (uncomp_tvb != NULL) {
+ /*
+ * Decompression worked
+ */
+
+ /* XXX - Don't free this, since it's possible
+ * that the data was only partially
+ * decompressed, such as when desegmentation
+ * isn't enabled.
+ *
+ tvb_free(next_tvb);
+ */
+ proto_item_append_text(e_ti, " -> %u bytes", tvb_length(uncomp_tvb));
+ data_tvb = uncomp_tvb;
+ add_new_data_source(pinfo, data_tvb, "Uncompressed entity body");
+ } else {
+ if (spdy_decompress_body)
+ proto_item_append_text(e_ti, " [Error: Decompression failed]");
+ call_dissector(data_handle, data_tvb, pinfo, e_tree);
+
+ goto body_dissected;
+ }
+ }
+ if (si != NULL)
+ spdy_discard_data_frames(si);
+ /*
+ * Do subdissector checks.
+ *
+ * First, check whether some subdissector asked that they
+ * be called if something was on some particular port.
+ */
+
+ port_subdissector_table = find_dissector_table("http.port");
+ media_type_subdissector_table = find_dissector_table("media_type");
+ if (have_entire_body && port_subdissector_table != NULL)
+ handle = dissector_get_port_handle(port_subdissector_table,
+ pinfo->match_port);
+ else
+ handle = NULL;
+ if (handle == NULL && have_entire_body && si->content_type != NULL &&
+ media_type_subdissector_table != NULL) {
+ /*
+ * We didn't find any subdissector that
+ * registered for the port, and we have a
+ * Content-Type value. Is there any subdissector
+ * for that content type?
+ */
+ save_private_data = pinfo->private_data;
+ private_data_changed = TRUE;
+
+ if (si->content_type_parameters)
+ pinfo->private_data = ep_strdup(si->content_type_parameters);
+ else
+ pinfo->private_data = NULL;
+ /*
+ * Calling the string handle for the media type
+ * dissector table will set pinfo->match_string
+ * to si->content_type for us.
+ */
+ pinfo->match_string = si->content_type;
+ handle = dissector_get_string_handle(
+ media_type_subdissector_table,
+ si->content_type);
+ }
+ if (handle != NULL) {
+ /*
+ * We have a subdissector - call it.
+ */
+ dissected = call_dissector(handle, data_tvb, pinfo, top_level_tree);
+ } else
+ dissected = FALSE;
+
+ if (dissected) {
+ /*
+ * The subdissector dissected the body.
+ * Fix up the top-level item so that it doesn't
+ * include the stuff for that protocol.
+ */
+ if (ti != NULL)
+ proto_item_set_len(ti, offset);
+ } else if (have_entire_body && si->content_type != NULL) {
+ /*
+ * Calling the default media handle if there is a content-type that
+ * wasn't handled above.
+ */
+ call_dissector(media_handle, next_tvb, pinfo, top_level_tree);
+ } else {
+ /* Call the default data dissector */
+ call_dissector(data_handle, next_tvb, pinfo, top_level_tree);
+ }
+
+body_dissected:
+ /*
+ * Do *not* attempt at freeing the private data;
+ * it may be in use by subdissectors.
+ */
+ if (private_data_changed) /*restore even NULL value*/
+ pinfo->private_data = save_private_data;
+ /*
+ * We've processed "datalen" bytes worth of data
+ * (which may be no data at all); advance the
+ * offset past whatever data we've processed.
+ */
+ }
+ return frame_length + 8;
+}
+
+static guint8 *
+spdy_decompress_header_block(tvbuff_t *tvb, z_streamp decomp,
+ guint32 dictionary_id, int offset,
+ guint32 length, guint *uncomp_length)
+{
+ int retcode;
+ size_t bufsize = 16384;
+ const guint8 *hptr = tvb_get_ptr(tvb, offset, length);
+ guint8 *uncomp_block = ep_alloc(bufsize);
+ decomp->next_in = (Bytef *)hptr;
+ decomp->avail_in = length;
+ decomp->next_out = uncomp_block;
+ decomp->avail_out = bufsize;
+ retcode = inflate(decomp, Z_SYNC_FLUSH);
+ if (retcode == Z_NEED_DICT) {
+ if (decomp->adler != dictionary_id) {
+ printf("decompressor wants dictionary %#x, but we have %#x\n",
+ (guint)decomp->adler, dictionary_id);
+ } else {
+ retcode = inflateSetDictionary(decomp,
+ spdy_dictionary,
+ sizeof(spdy_dictionary));
+ if (retcode == Z_OK)
+ retcode = inflate(decomp, Z_SYNC_FLUSH);
+ }
+ }
+
+ if (retcode != Z_OK) {
+ return NULL;
+ } else {
+ *uncomp_length = bufsize - decomp->avail_out;
+ if (spdy_debug)
+ printf("Inflation SUCCEEDED. uncompressed size=%d\n", *uncomp_length);
+ if (decomp->avail_in != 0)
+ if (spdy_debug)
+ printf(" but there were %d input bytes left over\n", decomp->avail_in);
+ }
+ return se_memdup(uncomp_block, *uncomp_length);
+}
+
+/*
+ * Try to determine heuristically whether the header block is
+ * compressed. For an uncompressed block, the first two bytes
+ * gives the number of headers. Each header name and value is
+ * a two-byte length followed by ASCII characters.
+ */
+static gboolean
+spdy_check_header_compression(tvbuff_t *tvb,
+ int offset,
+ guint32 frame_length)
+{
+ guint16 length;
+ if (!tvb_bytes_exist(tvb, offset, 6))
+ return 1;
+ length = tvb_get_ntohs(tvb, offset);
+ if (length > frame_length)
+ return 1;
+ length = tvb_get_ntohs(tvb, offset+2);
+ if (length > frame_length)
+ return 1;
+ if (spdy_debug) printf("Looks like the header block is not compressed\n");
+ return 0;
+}
+
+static spdy_frame_info_t *
+spdy_save_header_block(frame_data *fd,
+ guint32 stream_id,
+ guint frame_type,
+ guint8 *header,
+ guint length)
+{
+ GSList *filist = p_get_proto_data(fd, proto_spdy);
+ spdy_frame_info_t *frame_info = se_alloc(sizeof(spdy_frame_info_t));
+ if (filist != NULL)
+ p_remove_proto_data(fd, proto_spdy);
+ frame_info->stream_id = stream_id;
+ frame_info->header_block = header;
+ frame_info->header_block_len = length;
+ frame_info->frame_type = frame_type;
+ filist = g_slist_append(filist, frame_info);
+ p_add_proto_data(fd, proto_spdy, filist);
+ return frame_info;
+ /* TODO(ers) these need to get deleted when no longer needed */
+}
+
+static spdy_frame_info_t *
+spdy_find_saved_header_block(frame_data *fd,
+ guint32 stream_id,
+ guint16 frame_type)
+{
+ GSList *filist = p_get_proto_data(fd, proto_spdy);
+ while (filist != NULL) {
+ spdy_frame_info_t *fi = filist->data;
+ if (fi->stream_id == stream_id && fi->frame_type == frame_type)
+ return fi;
+ filist = g_slist_next(filist);
+ }
+ return NULL;
+}
+
+/*
+ * Given a content type string that may contain optional parameters,
+ * return the parameter string, if any, otherwise return NULL. This
+ * also has the side effect of null terminating the content type
+ * part of the original string.
+ */
+static gchar *
+spdy_parse_content_type(gchar *content_type)
+{
+ gchar *cp = content_type;
+
+ while (*cp != '\0' && *cp != ';' && !isspace(*cp)) {
+ *cp = tolower(*cp);
+ ++cp;
+ }
+ if (*cp == '\0')
+ cp = NULL;
+
+ if (cp != NULL) {
+ *cp++ = '\0';
+ while (*cp == ';' || isspace(*cp))
+ ++cp;
+ if (*cp != '\0')
+ return cp;
+ }
+ return NULL;
+}
+
+static int
+dissect_spdy_message(tvbuff_t *tvb, int offset, packet_info *pinfo,
+ proto_tree *tree, spdy_conv_t *conv_data)
+{
+ guint8 control_bit;
+ guint16 version;
+ guint16 frame_type;
+ guint8 flags;
+ guint32 frame_length;
+ guint32 stream_id;
+ gint priority;
+ guint16 num_headers;
+ guint32 fin_status;
+ guint8 *frame_header;
+ const char *proto_tag;
+ const char *frame_type_name;
+ proto_tree *spdy_tree = NULL;
+ proto_item *ti = NULL;
+ proto_item *spdy_proto = NULL;
+ int orig_offset;
+ int hoffset;
+ int hdr_offset = 0;
+ spdy_frame_type_t spdy_type;
+ proto_tree *sub_tree;
+ proto_tree *flags_tree;
+ tvbuff_t *header_tvb = NULL;
+ gboolean headers_compressed;
+ gchar *hdr_verb = NULL;
+ gchar *hdr_url = NULL;
+ gchar *hdr_version = NULL;
+ gchar *content_type = NULL;
+ gchar *content_encoding = NULL;
+
+ /*
+ * Minimum size for a SPDY frame is 8 bytes.
+ */
+ if (tvb_reported_length_remaining(tvb, offset) < 8)
+ return -1;
+
+ proto_tag = "SPDY";
+
+ if (check_col(pinfo->cinfo, COL_PROTOCOL))
+ col_set_str(pinfo->cinfo, COL_PROTOCOL, proto_tag);
+
+ /*
+ * Is this a control frame or a data frame?
+ */
+ orig_offset = offset;
+ control_bit = tvb_get_bits8(tvb, offset << 3, 1);
+ if (control_bit) {
+ version = tvb_get_bits16(tvb, (offset << 3) + 1, 15, FALSE);
+ frame_type = tvb_get_ntohs(tvb, offset+2);
+ if (frame_type >= SPDY_INVALID) {
+ return -1;
+ }
+ frame_header = ep_tvb_memdup(tvb, offset, 16);
+ } else {
+ version = 1; /* avoid gcc warning */
+ frame_type = SPDY_DATA;
+ frame_header = NULL; /* avoid gcc warning */
+ }
+ frame_type_name = frame_type_names[frame_type];
+ offset += 4;
+ flags = tvb_get_guint8(tvb, offset);
+ frame_length = tvb_get_ntoh24(tvb, offset+1);
+ offset += 4;
+ /*
+ * Make sure there's as much data as the frame header says there is.
+ */
+ if ((guint)tvb_reported_length_remaining(tvb, offset) < frame_length) {
+ if (spdy_debug)
+ printf("Not enough header data: %d vs. %d\n",
+ frame_length, tvb_reported_length_remaining(tvb, offset));
+ return -1;
+ }
+ if (tree) {
+ spdy_proto = proto_tree_add_item(tree, proto_spdy, tvb, orig_offset, frame_length+8, FALSE);
+ spdy_tree = proto_item_add_subtree(spdy_proto, ett_spdy);
+ }
+
+ if (control_bit) {
+ if (spdy_debug)
+ printf("Control frame [version=%d type=%d flags=0x%x length=%d]\n",
+ version, frame_type, flags, frame_length);
+ if (tree) proto_item_append_text(spdy_tree, ", control frame");
+ } else {
+ return dissect_spdy_data_frame(tvb, orig_offset, pinfo, tree,
+ spdy_tree, spdy_proto, conv_data);
+ }
+ num_headers = 0;
+ sub_tree = NULL; /* avoid gcc warning */
+ switch (frame_type) {
+ case SPDY_SYN_STREAM:
+ case SPDY_SYN_REPLY:
+ if (tree) {
+ int hf;
+ hf = frame_type == SPDY_SYN_STREAM ? hf_spdy_syn_stream : hf_spdy_syn_reply;
+ ti = proto_tree_add_bytes(spdy_tree, hf, tvb,
+ orig_offset, 16, frame_header);
+ sub_tree = proto_item_add_subtree(ti, ett_spdy_syn_stream);
+ }
+ stream_id = tvb_get_bits32(tvb, (offset << 3) + 1, 31, FALSE);
+ offset += 4;
+ priority = tvb_get_bits8(tvb, offset << 3, 2);
+ offset += 2;
+ if (tree) {
+ proto_tree_add_boolean(sub_tree, hf_spdy_control_bit, tvb, orig_offset, 1, control_bit);
+ proto_tree_add_uint(sub_tree, hf_spdy_version, tvb, orig_offset, 2, version);
+ proto_tree_add_uint(sub_tree, hf_spdy_type, tvb, orig_offset+2, 2, frame_type);
+ ti = proto_tree_add_uint_format(sub_tree, hf_spdy_flags, tvb, orig_offset+4, 1, flags,
+ "Flags: 0x%02x%s", flags, flags&SPDY_FIN ? " (FIN)" : "");
+ flags_tree = proto_item_add_subtree(ti, ett_spdy_flags);
+ proto_tree_add_boolean(flags_tree, hf_spdy_flags_fin, tvb, orig_offset+4, 1, flags);
+ proto_tree_add_uint(sub_tree, hf_spdy_length, tvb, orig_offset+5, 3, frame_length);
+ proto_tree_add_uint(sub_tree, hf_spdy_streamid, tvb, orig_offset+8, 4, stream_id);
+ proto_tree_add_uint(sub_tree, hf_spdy_priority, tvb, orig_offset+12, 1, priority);
+ proto_item_append_text(spdy_proto, ": %s%s stream=%d length=%d",
+ frame_type_name,
+ flags & SPDY_FIN ? " [FIN]" : "",
+ stream_id, frame_length);
+ if (spdy_debug)
+ printf(" stream ID=%u priority=%d\n", stream_id, priority);
+ }
+ break;
+
+ case SPDY_FIN_STREAM:
+ stream_id = tvb_get_bits32(tvb, (offset << 3) + 1, 31, FALSE);
+ fin_status = tvb_get_ntohl(tvb, offset);
+ // TODO(ers) fill in tree and summary
+ offset += 8;
+ break;
+
+ case SPDY_HELLO:
+ // TODO(ers) fill in tree and summary
+ stream_id = 0; /* avoid gcc warning */
+ break;
+
+ default:
+ stream_id = 0; /* avoid gcc warning */
+ return -1;
+ break;
+ }
+
+ /*
+ * Process the name-value pairs one at a time, after possibly
+ * decompressing the header block.
+ */
+ if (frame_type == SPDY_SYN_STREAM || frame_type == SPDY_SYN_REPLY) {
+ headers_compressed = spdy_check_header_compression(tvb, offset, frame_length);
+ if (!spdy_decompress_headers || !headers_compressed) {
+ header_tvb = tvb;
+ hdr_offset = offset;
+ } else {
+ spdy_frame_info_t *per_frame_info =
+ spdy_find_saved_header_block(pinfo->fd,
+ stream_id,
+ frame_type == SPDY_SYN_REPLY);
+ if (per_frame_info == NULL) {
+ guint uncomp_length;
+ z_streamp decomp = frame_type == SPDY_SYN_STREAM ?
+ conv_data->rqst_decompressor : conv_data->rply_decompressor;
+ guint8 *uncomp_ptr =
+ spdy_decompress_header_block(tvb, decomp,
+ conv_data->dictionary_id,
+ offset, frame_length-6, &uncomp_length);
+ if (uncomp_ptr == NULL) { /* decompression failed */
+ if (spdy_debug)
+ printf("Frame #%d: Inflation failed\n", pinfo->fd->num);
+ proto_item_append_text(spdy_proto, " [Error: Header decompression failed]");
+ } else {
+ if (spdy_debug)
+ printf("Saving %u bytes of uncomp hdr\n", uncomp_length);
+ per_frame_info =
+ spdy_save_header_block(pinfo->fd, stream_id, frame_type == SPDY_SYN_REPLY,
+ uncomp_ptr, uncomp_length);
+ }
+ } else if (spdy_debug) {
+ printf("Found uncompressed header block len %u for stream %u frame_type=%d\n",
+ per_frame_info->header_block_len,
+ per_frame_info->stream_id,
+ per_frame_info->frame_type);
+ }
+ if (per_frame_info != NULL) {
+ header_tvb = tvb_new_child_real_data(tvb,
+ per_frame_info->header_block,
+ per_frame_info->header_block_len,
+ per_frame_info->header_block_len);
+ add_new_data_source(pinfo, header_tvb, "Uncompressed headers");
+ hdr_offset = 0;
+ }
+ }
+ offset += frame_length-6;
+ num_headers = tvb_get_ntohs(header_tvb, hdr_offset);
+ hdr_offset += 2;
+ if (header_tvb == NULL ||
+ (headers_compressed && !spdy_decompress_headers)) {
+ num_headers = 0;
+ ti = proto_tree_add_string(sub_tree, hf_spdy_num_headers_string,
+ tvb, orig_offset+14, 2,
+ "Unknown (header block is compressed)");
+ } else
+ ti = proto_tree_add_uint(sub_tree, hf_spdy_num_headers,
+ tvb, orig_offset+14, 2, num_headers);
+ }
+ spdy_type = SPDY_INVALID; /* type not known yet */
+ if (spdy_debug)
+ printf(" %d Headers:\n", num_headers);
+ if (num_headers > frame_length) {
+ printf("Number of headers is greater than frame length!\n");
+ proto_item_append_text(ti, " [Error: Number of headers is larger than frame length]");
+ col_add_fstr(pinfo->cinfo, COL_INFO, "%s[%d]", frame_type_name, stream_id);
+ return frame_length+8;
+ }
+ hdr_verb = hdr_url = hdr_version = content_type = content_encoding = NULL;
+ while (num_headers-- && tvb_reported_length_remaining(header_tvb, hdr_offset) != 0) {
+ gchar *header_name;
+ gchar *header_value;
+ proto_tree *header_tree;
+ proto_tree *name_tree;
+ proto_tree *value_tree;
+ proto_item *header;
+ gint16 length;
+ gint header_length = 0;
+
+ hoffset = hdr_offset;
+
+ header = proto_tree_add_item(spdy_tree, hf_spdy_header, header_tvb,
+ hdr_offset, frame_length, FALSE);
+ header_tree = proto_item_add_subtree(header, ett_spdy_header);
+
+ length = tvb_get_ntohs(header_tvb, hdr_offset);
+ hdr_offset += 2;
+ header_name = (gchar *)tvb_get_ephemeral_string(header_tvb, hdr_offset, length);
+ hdr_offset += length;
+ header_length += hdr_offset - hoffset;
+ if (tree) {
+ ti = proto_tree_add_text(header_tree, header_tvb, hoffset, length+2, "Name: %s",
+ header_name);
+ name_tree = proto_item_add_subtree(ti, ett_spdy_header_name);
+ proto_tree_add_uint(name_tree, hf_spdy_length, header_tvb, hoffset, 2, length);
+ proto_tree_add_string_format(name_tree, hf_spdy_header_name_text, header_tvb, hoffset+2, length,
+ header_name, "Text: %s", format_text(header_name, length));
+ }
+
+ hoffset = hdr_offset;
+ length = tvb_get_ntohs(header_tvb, hdr_offset);
+ hdr_offset += 2;
+ header_value = (gchar *)tvb_get_ephemeral_string(header_tvb, hdr_offset, length);
+ hdr_offset += length;
+ header_length += hdr_offset - hoffset;
+ if (tree) {
+ ti = proto_tree_add_text(header_tree, header_tvb, hoffset, length+2, "Value: %s",
+ header_value);
+ value_tree = proto_item_add_subtree(ti, ett_spdy_header_value);
+ proto_tree_add_uint(value_tree, hf_spdy_length, header_tvb, hoffset, 2, length);
+ proto_tree_add_string_format(value_tree, hf_spdy_header_value_text, header_tvb, hoffset+2, length,
+ header_value, "Text: %s", format_text(header_value, length));
+ proto_item_append_text(header, ": %s: %s", header_name, header_value);
+ proto_item_set_len(header, header_length);
+ }
+ if (spdy_debug) printf(" %s: %s\n", header_name, header_value);
+ /*
+ * TODO(ers) check that the header name contains only legal characters.
+ */
+ if (g_ascii_strcasecmp(header_name, "method") == 0 ||
+ g_ascii_strcasecmp(header_name, "status") == 0) {
+ hdr_verb = header_value;
+ } else if (g_ascii_strcasecmp(header_name, "url") == 0) {
+ hdr_url = header_value;
+ } else if (g_ascii_strcasecmp(header_name, "version") == 0) {
+ hdr_version = header_value;
+ } else if (g_ascii_strcasecmp(header_name, "content-type") == 0) {
+ content_type = se_strdup(header_value);
+ } else if (g_ascii_strcasecmp(header_name, "content-encoding") == 0) {
+ content_encoding = se_strdup(header_value);
+ }
+ }
+ if (hdr_version != NULL) {
+ if (hdr_url != NULL) {
+ col_add_fstr(pinfo->cinfo, COL_INFO, "%s[%d]: %s %s %s",
+ frame_type_name, stream_id, hdr_verb, hdr_url, hdr_version);
+ } else {
+ col_add_fstr(pinfo->cinfo, COL_INFO, "%s[%d]: %s %s",
+ frame_type_name, stream_id, hdr_verb, hdr_version);
+ }
+ } else {
+ col_add_fstr(pinfo->cinfo, COL_INFO, "%s[%d]", frame_type_name, stream_id);
+ }
+ /*
+ * If we expect data on this stream, we need to remember the content
+ * type and content encoding.
+ */
+ if (content_type != NULL && !pinfo->fd->flags.visited) {
+ gchar *content_type_params = spdy_parse_content_type(content_type);
+ spdy_save_stream_info(conv_data, stream_id, content_type,
+ content_type_params, content_encoding);
+ }
+
+ return offset - orig_offset;
+}
+
+static int
+dissect_spdy(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ spdy_conv_t *conv_data;
+ int offset = 0;
+ int len;
+ int firstpkt = 1;
+
+ /*
+ * The first byte of a SPDY packet must be either 0 or
+ * 0x80. If it's not, assume that this is not SPDY.
+ * (In theory, a data frame could have a stream ID
+ * >= 2^24, in which case it won't have 0 for a first
+ * byte, but this is a pretty reliable heuristic for
+ * now.)
+ */
+ guint8 first_byte = tvb_get_guint8(tvb, 0);
+ if (first_byte != 0x80 && first_byte != 0x0)
+ return 0;
+
+ conv_data = get_spdy_conversation_data(pinfo);
+
+ while (tvb_reported_length_remaining(tvb, offset) != 0) {
+ if (!firstpkt) {
+ col_add_fstr(pinfo->cinfo, COL_INFO, " >> ");
+ col_set_fence(pinfo->cinfo, COL_INFO);
+ }
+ len = dissect_spdy_message(tvb, offset, pinfo, tree, conv_data);
+ if (len <= 0)
+ return 0;
+ offset += len;
+ /*
+ * OK, we've set the Protocol and Info columns for the
+ * first SPDY message; set a fence so that subsequent
+ * SPDY messages don't overwrite the Info column.
+ */
+ col_set_fence(pinfo->cinfo, COL_INFO);
+ firstpkt = 0;
+ }
+ return 1;
+}
+
+static gboolean
+dissect_spdy_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ if (!value_is_in_range(global_spdy_tcp_range, pinfo->destport) &&
+ !value_is_in_range(global_spdy_tcp_range, pinfo->srcport))
+ return FALSE;
+ return dissect_spdy(tvb, pinfo, tree) != 0;
+}
+
+static void reinit_spdy(void)
+{
+}
+
+// NMAKE complains about flags_set_truth not being constant. Duplicate
+// the values inside of it.
+static const true_false_string tfs_spdy_set_notset = { "Set", "Not set" };
+
+void
+proto_register_spdy(void)
+{
+ static hf_register_info hf[] = {
+ { &hf_spdy_syn_stream,
+ { "Syn Stream", "spdy.syn_stream",
+ FT_BYTES, BASE_HEX, NULL, 0x0,
+ "", HFILL }},
+ { &hf_spdy_syn_reply,
+ { "Syn Reply", "spdy.syn_reply",
+ FT_BYTES, BASE_HEX, NULL, 0x0,
+ "", HFILL }},
+ { &hf_spdy_control_bit,
+ { "Control bit", "spdy.control_bit",
+ FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "TRUE if SPDY control frame", HFILL }},
+ { &hf_spdy_version,
+ { "Version", "spdy.version",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "", HFILL }},
+ { &hf_spdy_type,
+ { "Type", "spdy.type",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "", HFILL }},
+ { &hf_spdy_flags,
+ { "Flags", "spdy.flags",
+ FT_UINT8, BASE_HEX, NULL, 0x0,
+ "", HFILL }},
+ { &hf_spdy_flags_fin,
+ { "Fin", "spdy.flags.fin",
+ FT_BOOLEAN, 8, TFS(&tfs_spdy_set_notset),
+ SPDY_FIN, "", HFILL }},
+ { &hf_spdy_length,
+ { "Length", "spdy.length",
+ FT_UINT24, BASE_DEC, NULL, 0x0,
+ "", HFILL }},
+ { &hf_spdy_header,
+ { "Header", "spdy.header",
+ FT_NONE, BASE_NONE, NULL, 0x0,
+ "", HFILL }},
+ { &hf_spdy_header_name,
+ { "Name", "spdy.header.name",
+ FT_NONE, BASE_NONE, NULL, 0x0,
+ "", HFILL }},
+ { &hf_spdy_header_name_text,
+ { "Text", "spdy.header.name.text",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "", HFILL }},
+ { &hf_spdy_header_value,
+ { "Value", "spdy.header.value",
+ FT_NONE, BASE_NONE, NULL, 0x0,
+ "", HFILL }},
+ { &hf_spdy_header_value_text,
+ { "Text", "spdy.header.value.text",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "", HFILL }},
+ { &hf_spdy_streamid,
+ { "Stream ID", "spdy.streamid",
+ FT_UINT32, BASE_DEC, NULL, 0x0,
+ "", HFILL }},
+ { &hf_spdy_priority,
+ { "Priority", "spdy.priority",
+ FT_UINT8, BASE_DEC, NULL, 0x0,
+ "", HFILL }},
+ { &hf_spdy_num_headers,
+ { "Number of headers", "spdy.numheaders",
+ FT_UINT16, BASE_DEC, NULL, 0x0,
+ "", HFILL }},
+ { &hf_spdy_num_headers_string,
+ { "Number of headers", "spdy.numheaders",
+ FT_STRING, BASE_NONE, NULL, 0x0,
+ "", HFILL }},
+ };
+ static gint *ett[] = {
+ &ett_spdy,
+ &ett_spdy_syn_stream,
+ &ett_spdy_syn_reply,
+ &ett_spdy_fin_stream,
+ &ett_spdy_flags,
+ &ett_spdy_header,
+ &ett_spdy_header_name,
+ &ett_spdy_header_value,
+ &ett_spdy_encoded_entity,
+ };
+
+ module_t *spdy_module;
+
+ proto_spdy = proto_register_protocol("SPDY", "SPDY", "spdy");
+ proto_register_field_array(proto_spdy, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+ new_register_dissector("spdy", dissect_spdy, proto_spdy);
+ spdy_module = prefs_register_protocol(proto_spdy, reinit_spdy);
+ prefs_register_bool_preference(spdy_module, "desegment_headers",
+ "Reassemble SPDY control frames spanning multiple TCP segments",
+ "Whether the SPDY dissector should reassemble control frames "
+ "spanning multiple TCP segments. "
+ "To use this option, you must also enable "
+ "\"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
+ &spdy_desegment_control_frames);
+ prefs_register_bool_preference(spdy_module, "desegment_body",
+ "Reassemble SPDY bodies spanning multiple TCP segments",
+ "Whether the SPDY dissector should reassemble "
+ "data frames spanning multiple TCP segments. "
+ "To use this option, you must also enable "
+ "\"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
+ &spdy_desegment_data_frames);
+ prefs_register_bool_preference(spdy_module, "assemble_data_frames",
+ "Assemble SPDY bodies that consist of multiple DATA frames",
+ "Whether the SPDY dissector should reassemble multiple "
+ "data frames into an entity body.",
+ &spdy_assemble_entity_bodies);
+#ifdef HAVE_LIBZ
+ prefs_register_bool_preference(spdy_module, "decompress_headers",
+ "Uncompress SPDY headers",
+ "Whether to uncompress SPDY headers.",
+ &spdy_decompress_headers);
+ prefs_register_bool_preference(spdy_module, "decompress_body",
+ "Uncompress entity bodies",
+ "Whether to uncompress entity bodies that are compressed "
+ "using \"Content-Encoding: \"",
+ &spdy_decompress_body);
+#endif
+ prefs_register_bool_preference(spdy_module, "debug_output",
+ "Print debug info on stdout",
+ "Print debug info on stdout",
+ &spdy_debug);
+#if 0
+ prefs_register_string_preference(ssl_module, "debug_file", "SPDY debug file",
+ "Redirect SPDY debug to file name; "
+ "leave empty to disable debugging, "
+ "or use \"" SPDY_DEBUG_USE_STDOUT "\""
+ " to redirect output to stdout\n",
+ (const gchar **)&sdpy_debug_file_name);
+#endif
+ prefs_register_obsolete_preference(spdy_module, "tcp_alternate_port");
+
+ range_convert_str(&global_spdy_tcp_range, TCP_DEFAULT_RANGE, 65535);
+ spdy_tcp_range = range_empty();
+ prefs_register_range_preference(spdy_module, "tcp.port", "TCP Ports",
+ "TCP Ports range",
+ &global_spdy_tcp_range, 65535);
+
+ range_convert_str(&global_spdy_ssl_range, SSL_DEFAULT_RANGE, 65535);
+ spdy_ssl_range = range_empty();
+ prefs_register_range_preference(spdy_module, "ssl.port", "SSL/TLS Ports",
+ "SSL/TLS Ports range",
+ &global_spdy_ssl_range, 65535);
+
+ spdy_handle = new_create_dissector_handle(dissect_spdy, proto_spdy);
+ /*
+ * Register for tapping
+ */
+ spdy_tap = register_tap("spdy"); /* SPDY statistics tap */
+ spdy_eo_tap = register_tap("spdy_eo"); /* SPDY Export Object tap */
+}
+
+void
+proto_reg_handoff_spdy(void)
+{
+ data_handle = find_dissector("data");
+ media_handle = find_dissector("media");
+ heur_dissector_add("tcp", dissect_spdy_heur, proto_spdy);
+}
+
+/*
+ * Content-Type: message/http
+ */
+
+static gint proto_message_spdy = -1;
+static gint ett_message_spdy = -1;
+
+static void
+dissect_message_spdy(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
+{
+ proto_tree *subtree;
+ proto_item *ti;
+ gint offset = 0, next_offset;
+ gint len;
+
+ if (check_col(pinfo->cinfo, COL_INFO))
+ col_append_str(pinfo->cinfo, COL_INFO, " (message/spdy)");
+ if (tree) {
+ ti = proto_tree_add_item(tree, proto_message_spdy,
+ tvb, 0, -1, FALSE);
+ subtree = proto_item_add_subtree(ti, ett_message_spdy);
+ while (tvb_reported_length_remaining(tvb, offset) != 0) {
+ len = tvb_find_line_end(tvb, offset,
+ tvb_ensure_length_remaining(tvb, offset),
+ &next_offset, FALSE);
+ if (len == -1)
+ break;
+ proto_tree_add_text(subtree, tvb, offset, next_offset - offset,
+ "%s", tvb_format_text(tvb, offset, len));
+ offset = next_offset;
+ }
+ }
+}
+
+void
+proto_register_message_spdy(void)
+{
+ static gint *ett[] = {
+ &ett_message_spdy,
+ };
+
+ proto_message_spdy = proto_register_protocol(
+ "Media Type: message/spdy",
+ "message/spdy",
+ "message-spdy"
+ );
+ proto_register_subtree_array(ett, array_length(ett));
+}
+
+void
+proto_reg_handoff_message_spdy(void)
+{
+ dissector_handle_t message_spdy_handle;
+
+ message_spdy_handle = create_dissector_handle(dissect_message_spdy,
+ proto_message_spdy);
+
+ dissector_add_string("media_type", "message/spdy", message_spdy_handle);
+
+ reinit_spdy();
+}
diff --git a/net/tools/spdyshark/packet-spdy.h b/net/tools/spdyshark/packet-spdy.h
new file mode 100644
index 0000000..02b586b
--- /dev/null
+++ b/net/tools/spdyshark/packet-spdy.h
@@ -0,0 +1,46 @@
+/* packet-spdy.h
+ *
+ * Copyright 2010, Google Inc.
+ * Eric Shienbrood <ers@google.com>
+ *
+ * $Id$
+ *
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __PACKET_SPDY_H__
+#define __PACKET_SPDY_H__
+
+#include <epan/packet.h>
+#ifdef HAVE_LIBZ
+#include <zlib.h>
+#endif
+
+/*
+ * Conversation data - used for assembling multi-data-frame
+ * entities and for decompressing request & reply header blocks.
+ */
+typedef struct _spdy_conv_t {
+ z_streamp rqst_decompressor;
+ z_streamp rply_decompressor;
+ guint32 dictionary_id;
+ GArray *streams;
+} spdy_conv_t;
+
+#endif /* __PACKET_SPDY_H__ */
diff --git a/net/tools/spdyshark/plugin.rc.in b/net/tools/spdyshark/plugin.rc.in
new file mode 100644
index 0000000..568dc07
--- /dev/null
+++ b/net/tools/spdyshark/plugin.rc.in
@@ -0,0 +1,34 @@
+#include "winver.h"
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION @RC_MODULE_VERSION@
+ PRODUCTVERSION @RC_VERSION@
+ FILEFLAGSMASK 0x0L
+#ifdef _DEBUG
+ FILEFLAGS VS_FF_DEBUG
+#else
+ FILEFLAGS 0
+#endif
+ FILEOS VOS_NT_WINDOWS32
+ FILETYPE VFT_DLL
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "The Wireshark developer community, http://www.wireshark.org/\0"
+ VALUE "FileDescription", "@PACKAGE@ dissector\0"
+ VALUE "FileVersion", "@MODULE_VERSION@\0"
+ VALUE "InternalName", "@PACKAGE@ @MODULE_VERSION@\0"
+ VALUE "LegalCopyright", "Copyright © 1998 Gerald Combs <gerald@wireshark.org>, Gilbert Ramirez <gram@alumni.rice.edu> and others\0"
+ VALUE "OriginalFilename", "@PLUGIN_NAME@.dll\0"
+ VALUE "ProductName", "Wireshark\0"
+ VALUE "ProductVersion", "@VERSION@\0"
+ VALUE "Comments", "Build with @MSVC_VARIANT@\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END