diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/tools/spdyshark/AUTHORS | 2 | ||||
-rw-r--r-- | net/tools/spdyshark/COPYING | 340 | ||||
-rw-r--r-- | net/tools/spdyshark/ChangeLog | 0 | ||||
-rw-r--r-- | net/tools/spdyshark/INSTALL | 0 | ||||
-rw-r--r-- | net/tools/spdyshark/Makefile.am | 126 | ||||
-rw-r--r-- | net/tools/spdyshark/Makefile.common | 40 | ||||
-rw-r--r-- | net/tools/spdyshark/Makefile.nmake | 104 | ||||
-rw-r--r-- | net/tools/spdyshark/NEWS | 0 | ||||
-rw-r--r-- | net/tools/spdyshark/moduleinfo.h | 16 | ||||
-rw-r--r-- | net/tools/spdyshark/moduleinfo.nmake | 28 | ||||
-rw-r--r-- | net/tools/spdyshark/packet-spdy.c | 1464 | ||||
-rw-r--r-- | net/tools/spdyshark/packet-spdy.h | 46 | ||||
-rw-r--r-- | net/tools/spdyshark/plugin.rc.in | 34 |
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 |