From: gerald Date: Wed, 16 Sep 1998 02:39:15 +0000 (+0000) Subject: Initial revision X-Git-Url: http://git.samba.org/samba.git/?p=obnox%2Fwireshark%2Fwip.git;a=commitdiff_plain;h=ba22fd6da0503da55c5a3e5187b45190609a7af3 Initial revision git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@2 f5534014-38df-0310-8fa8-9805f1628bb7 --- diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000000..d2f4f82996 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,36 @@ +Original Author +-------- ------ +Gerald Combs + + +Contributors +------------ +Gilbert Ramirez Jr. { + /* add your info here */ +} + +Hannes R. Boehm { + http://hannes.boehm.org/ + + OSPFv2 + RIPv1, RIPv2 + started IPv6 support +} + +Mike Hall { + /* add your info here */ +} + +Bobo Rajec { + /* add your info here */ +} + +Laurent Deniel { + /* add your info here */ +} + +Alain Magloire was kind enough to +give his permission to use his version of snprintf.c. + +Dan Lasley gave permission for his dumpit() hex-dump +routine to be used. diff --git a/COPYING b/COPYING new file mode 100644 index 0000000000..bf50f20de6 --- /dev/null +++ b/COPYING @@ -0,0 +1,482 @@ + GNU LIBRARY GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 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. + +[This is the first released version of the library GPL. It is + numbered 2 because it goes with version 2 of the ordinary GPL.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Library General Public License, applies to some +specially designated Free Software Foundation software, and to any +other libraries whose authors decide to use it. You can use it for +your libraries, 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 library, or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link a program with the library, you must provide +complete object files to the recipients so that they can relink them +with the library, after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + Our method of protecting your rights has two steps: (1) copyright +the library, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the library. + + Also, for each distributor's protection, we want to make certain +that everyone understands that there is no warranty for this free +library. If the library is modified by someone else and passed on, we +want its recipients to know that what they have is not the original +version, 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 companies distributing free +software will individually obtain patent licenses, thus in effect +transforming the program into proprietary software. To prevent this, +we have made it clear that any patent must be licensed for everyone's +free use or not licensed at all. + + Most GNU software, including some libraries, is covered by the ordinary +GNU General Public License, which was designed for utility programs. This +license, the GNU Library General Public License, applies to certain +designated libraries. This license is quite different from the ordinary +one; be sure to read it in full, and don't assume that anything in it is +the same as in the ordinary license. + + The reason we have a separate public license for some libraries is that +they blur the distinction we usually make between modifying or adding to a +program and simply using it. Linking a program with a library, without +changing the library, is in some sense simply using the library, and is +analogous to running a utility program or application program. However, in +a textual and legal sense, the linked executable is a combined work, a +derivative of the original library, and the ordinary General Public License +treats it as such. + + Because of this blurred distinction, using the ordinary General +Public License for libraries did not effectively promote software +sharing, because most developers did not use the libraries. We +concluded that weaker conditions might promote sharing better. + + However, unrestricted linking of non-free programs would deprive the +users of those programs of all benefit from the free status of the +libraries themselves. This Library General Public License is intended to +permit developers of non-free programs to use free libraries, while +preserving your freedom as a user of such programs to change the free +libraries that are incorporated in them. (We have not seen how to achieve +this as regards changes in header files, but we have achieved it as regards +changes in the actual functions of the Library.) The hope is that this +will lead to faster development of free libraries. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, while the latter only +works together with the library. + + Note that it is possible for a library to be covered by the ordinary +General Public License rather than by this special one. + + GNU LIBRARY GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library which +contains a notice placed by the copyright holder or other authorized +party saying it may be distributed under the terms of this Library +General Public License (also called "this License"). Each licensee is +addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, 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 library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete 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 distribute a copy of this License along with the +Library. + + 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 Library or any portion +of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +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 Library, 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 Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you 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. + + If distribution of 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 satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also compile or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + c) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + d) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library 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. + + 9. 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 Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +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. + + 11. 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 Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library 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 Library. + +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. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library 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. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Library 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 Library +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 Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +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 + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. 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 LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. 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. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; 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. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000000..e69de29bb2 diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000000..b42a17ac46 --- /dev/null +++ b/INSTALL @@ -0,0 +1,182 @@ +Basic Installation +================== + + These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, a file +`config.cache' that saves the results of its tests to speed up +reconfiguring, and a file `config.log' containing compiler output +(useful mainly for debugging `configure'). + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If at some point `config.cache' +contains results you don't want to keep, you may remove or edit it. + + The file `configure.in' is used to create `configure' by a program +called `autoconf'. You only need `configure.in' if you want to change +it or regenerate `configure' using a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. You can give `configure' +initial values for variables by setting them in the environment. Using +a Bourne-compatible shell, you can do that on the command line like +this: + CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure + +Or on systems that have the `env' program, you can do it like this: + env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not supports the `VPATH' +variable, you have to compile the package for one architecture at a time +in the source code directory. After you have installed the package for +one architecture, use `make distclean' before reconfiguring for another +architecture. + +Installation Names +================== + + By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PATH'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PATH', the package will use +PATH as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=PATH' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + + There may be some features `configure' can not figure out +automatically, but needs to determine by the type of host the package +will run on. Usually `configure' can figure that out, but if it prints +a message saying it can not guess the host type, give it the +`--host=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name with three fields: + CPU-COMPANY-SYSTEM + +See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the host type. + + If you are building compiler tools for cross-compiling, you can also +use the `--target=TYPE' option to select the type of system they will +produce code for and the `--build=TYPE' option to select the type of +system on which you are compiling the package. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Operation Controls +================== + + `configure' recognizes the following options to control how it +operates. + +`--cache-file=FILE' + Use and save the results of the tests in FILE instead of + `./config.cache'. Set FILE to `/dev/null' to disable caching, for + debugging `configure'. + +`--help' + Print a summary of the options to `configure', and exit. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--version' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`configure' also accepts some other, not widely useful, options. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000000..2c148261ab --- /dev/null +++ b/Makefile.am @@ -0,0 +1,69 @@ +bin_PROGRAMS = ethereal + +man_MANS = ethereal.1 + +ethereal_SOURCES = \ + capture.c \ + ethereal.c \ + ethertype.c \ + file.c \ + filter.c \ + menu.c \ + packet.c \ + packet-arp.c \ + packet-bootp.c \ + packet-data.c \ + packet-dns.c \ + packet-eth.c \ + packet-llc.c \ + packet-lpd.c \ + packet-ip.c \ + packet-ipv6.c \ + packet-ipx.c \ + packet-ospf.c \ + packet-ppp.c \ + packet-raw.c \ + packet-rip.c \ + packet-tcp.c \ + packet-tr.c \ + packet-trmac.c \ + packet-udp.c \ + print.c \ + ps.c \ + resolv.c \ + util.c \ + capture.h \ + config.h \ + ethereal.h \ + etypes.h \ + file.h \ + filter.h \ + menu.h \ + packet.h \ + packet-ipv6.h \ + packet-ospf.h \ + packet-rip.h \ + print.h \ + ps.h \ + resolv.h \ + snprintf.h \ + util.h + +ps.c: print.ps rdps + ./rdps print.ps ps.c + +rdps: rdps.c + $(CC) -o rdps rdps.c + +EXTRA_ethereal_SOURCES = @SNPRINTF_C@ +ethereal_DEPENDENCIES = @SNPRINTF_O@ +LDADD = @SNPRINTF_O@ + +EXTRA_DIST = \ + ethereal.1 \ + snprintf.c \ + rdps.c \ + print.ps \ + image/icon-excl.xpm \ + doc/Makefile \ + doc/ethereal.pod diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000000..9881ae67d1 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,475 @@ +# Makefile.in generated automatically by automake 1.3 from Makefile.am + +# Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = /bin/sh + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DISTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = . + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +CC = @CC@ +GTK_CFLAGS = @GTK_CFLAGS@ +GTK_CONFIG = @GTK_CONFIG@ +GTK_LIBS = @GTK_LIBS@ +MAKEINFO = @MAKEINFO@ +PACKAGE = @PACKAGE@ +SNPRINTF_C = @SNPRINTF_C@ +SNPRINTF_O = @SNPRINTF_O@ +VERSION = @VERSION@ + +bin_PROGRAMS = ethereal + +man_MANS = ethereal.1 + +ethereal_SOURCES = \ + capture.c \ + ethereal.c \ + ethertype.c \ + file.c \ + filter.c \ + menu.c \ + packet.c \ + packet-arp.c \ + packet-bootp.c \ + packet-data.c \ + packet-dns.c \ + packet-eth.c \ + packet-llc.c \ + packet-lpd.c \ + packet-ip.c \ + packet-ipv6.c \ + packet-ipx.c \ + packet-ospf.c \ + packet-ppp.c \ + packet-raw.c \ + packet-rip.c \ + packet-tcp.c \ + packet-tr.c \ + packet-trmac.c \ + packet-udp.c \ + print.c \ + ps.c \ + resolv.c \ + util.c \ + capture.h \ + config.h \ + ethereal.h \ + etypes.h \ + file.h \ + filter.h \ + menu.h \ + packet.h \ + packet-ipv6.h \ + packet-ospf.h \ + packet-rip.h \ + print.h \ + ps.h \ + resolv.h \ + snprintf.h \ + util.h + +EXTRA_ethereal_SOURCES = @SNPRINTF_C@ +ethereal_DEPENDENCIES = @SNPRINTF_O@ +LDADD = @SNPRINTF_O@ + +EXTRA_DIST = \ + ethereal.1 \ + snprintf.c \ + rdps.c \ + print.ps \ + image/icon-excl.xpm \ + doc/Makefile \ + doc/ethereal.pod +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(bin_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +ethereal_OBJECTS = capture.o ethereal.o ethertype.o file.o filter.o \ +menu.o packet.o packet-arp.o packet-bootp.o packet-data.o packet-dns.o \ +packet-eth.o packet-llc.o packet-lpd.o packet-ip.o packet-ipv6.o \ +packet-ipx.o packet-ospf.o packet-ppp.o packet-raw.o packet-rip.o \ +packet-tcp.o packet-tr.o packet-trmac.o packet-udp.o print.o ps.o \ +resolv.o util.o +ethereal_LDADD = $(LDADD) +ethereal_LDFLAGS = +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) +LINK = $(CC) $(CFLAGS) $(LDFLAGS) -o $@ +man1dir = $(mandir)/man1 +MANS = $(man_MANS) + +NROFF = nroff +DIST_COMMON = README AUTHORS COPYING ChangeLog INSTALL Makefile.am \ +Makefile.in NEWS acconfig.h aclocal.m4 config.h.in configure \ +configure.in install-sh missing mkinstalldirs stamp-h.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP = --best +SOURCES = $(ethereal_SOURCES) $(EXTRA_ethereal_SOURCES) +OBJECTS = $(ethereal_OBJECTS) + +all: Makefile $(PROGRAMS) $(MANS) config.h + +.SUFFIXES: +.SUFFIXES: .S .c .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$@ CONFIG_HEADERS= $(SHELL) ./config.status + +$(ACLOCAL_M4): configure.in + cd $(srcdir) && $(ACLOCAL) + +config.status: $(srcdir)/configure + $(SHELL) ./config.status --recheck +$(srcdir)/configure: $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES) + cd $(srcdir) && $(AUTOCONF) + +config.h: stamp-h + @: +stamp-h: $(srcdir)/config.h.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES= CONFIG_HEADERS=config.h \ + $(SHELL) ./config.status + @echo timestamp > stamp-h +$(srcdir)/config.h.in: $(srcdir)/stamp-h.in +$(srcdir)/stamp-h.in: $(top_srcdir)/configure.in $(ACLOCAL_M4) acconfig.h + cd $(top_srcdir) && $(AUTOHEADER) + @echo timestamp > $(srcdir)/stamp-h.in + +mostlyclean-hdr: + +clean-hdr: + +distclean-hdr: + -rm -f config.h + +maintainer-clean-hdr: + +mostlyclean-binPROGRAMS: + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) + +distclean-binPROGRAMS: + +maintainer-clean-binPROGRAMS: + +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`"; \ + $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + list='$(bin_PROGRAMS)'; for p in $$list; do \ + rm -f $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`; \ + done + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +ethereal: $(ethereal_OBJECTS) $(ethereal_DEPENDENCIES) + @rm -f ethereal + $(LINK) $(ethereal_LDFLAGS) $(ethereal_OBJECTS) $(ethereal_LDADD) $(LIBS) + +install-man1: + $(mkinstalldirs) $(DESTDIR)$(man1dir) + @list='$(man1_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst; \ + done + +uninstall-man1: + @list='$(man1_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man1dir)/$$inst"; \ + rm -f $(DESTDIR)$(man1dir)/$$inst; \ + done +install-man: $(MANS) + @$(NORMAL_INSTALL) + $(MAKE) install-man1 +uninstall-man: + @$(NORMAL_UNINSTALL) + $(MAKE) uninstall-man1 + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $(SOURCES) $(HEADERS) $(LISP) + +TAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)config.h.in$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags config.h.in $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + -rm -rf $(distdir) + GZIP=$(GZIP) $(TAR) zxf $(distdir).tar.gz + mkdir $(distdir)/=build + mkdir $(distdir)/=inst + dc_install_base=`cd $(distdir)/=inst && pwd`; \ + cd $(distdir)/=build \ + && ../configure --srcdir=.. --prefix=$$dc_install_base \ + && $(MAKE) \ + && $(MAKE) dvi \ + && $(MAKE) check \ + && $(MAKE) install \ + && $(MAKE) installcheck \ + && $(MAKE) dist + -rm -rf $(distdir) + @echo "========================"; \ + echo "$(distdir).tar.gz is ready for distribution"; \ + echo "========================" +dist: distdir + -chmod -R a+r $(distdir) + GZIP=$(GZIP) $(TAR) chozf $(distdir).tar.gz $(distdir) + -rm -rf $(distdir) +dist-all: distdir + -chmod -R a+r $(distdir) + GZIP=$(GZIP) $(TAR) chozf $(distdir).tar.gz $(distdir) + -rm -rf $(distdir) +distdir: $(DISTFILES) + -rm -rf $(distdir) + mkdir $(distdir) + -chmod 777 $(distdir) + $(mkinstalldirs) $(distdir)/doc $(distdir)/image + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file; \ + done +capture.o: capture.c config.h packet.h file.h capture.h etypes.h util.h \ + image/icon-excl.xpm +ethereal.o: ethereal.c config.h packet.h file.h ethereal.h menu.h \ + etypes.h print.h resolv.h +ethertype.o: ethertype.c config.h packet.h ethereal.h etypes.h +file.o: file.c config.h packet.h file.h ethereal.h util.h \ + image/icon-excl.xpm +filter.o: filter.c config.h filter.h packet.h file.h menu.h +menu.o: menu.c config.h menu.h ethereal.h capture.h filter.h packet.h \ + print.h +packet-arp.o: packet-arp.c config.h ethereal.h packet.h etypes.h +packet-bootp.o: packet-bootp.c config.h packet.h ethereal.h etypes.h +packet-data.o: packet-data.c config.h ethereal.h packet.h +packet-dns.o: packet-dns.c config.h packet.h +packet-eth.o: packet-eth.c config.h packet.h ethereal.h etypes.h +packet-ip.o: packet-ip.c config.h ethereal.h packet.h etypes.h resolv.h +packet-ipv6.o: packet-ipv6.c config.h ethereal.h packet.h packet-ipv6.h \ + etypes.h +packet-ipx.o: packet-ipx.c config.h ethereal.h packet.h +packet-llc.o: packet-llc.c config.h packet.h ethereal.h etypes.h +packet-lpd.o: packet-lpd.c config.h packet.h ethereal.h etypes.h +packet-ospf.o: packet-ospf.c config.h ethereal.h packet.h packet-ospf.h +packet-ppp.o: packet-ppp.c config.h packet.h ethereal.h +packet-raw.o: packet-raw.c config.h packet.h ethereal.h +packet-rip.o: packet-rip.c config.h ethereal.h packet.h packet-rip.h +packet-tcp.o: packet-tcp.c config.h ethereal.h packet.h +packet-tr.o: packet-tr.c config.h packet.h ethereal.h etypes.h +packet-trmac.o: packet-trmac.c config.h packet.h ethereal.h etypes.h +packet-udp.o: packet-udp.c config.h ethereal.h packet.h resolv.h +packet.o: packet.c config.h packet.h ethereal.h etypes.h file.h +print.o: print.c config.h packet.h print.h +ps.o: ps.c ps.h +resolv.o: resolv.c config.h packet.h resolv.h +util.o: util.c config.h util.h image/icon-excl.xpm + +info: +dvi: +check: all + $(MAKE) +installcheck: +install-exec: install-binPROGRAMS + @$(NORMAL_INSTALL) + +install-data: install-man + @$(NORMAL_INSTALL) + +install: install-exec install-data all + @: + +uninstall: uninstall-binPROGRAMS uninstall-man + +install-strip: + $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install +installdirs: + $(mkinstalldirs) $(DATADIR)$(bindir) $(DESTDIR)$(mandir)/man1 + + +mostlyclean-generic: + -test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES) + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -rm -f Makefile $(DISTCLEANFILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +mostlyclean: mostlyclean-hdr mostlyclean-binPROGRAMS \ + mostlyclean-compile mostlyclean-tags \ + mostlyclean-generic + +clean: clean-hdr clean-binPROGRAMS clean-compile clean-tags \ + clean-generic mostlyclean + +distclean: distclean-hdr distclean-binPROGRAMS distclean-compile \ + distclean-tags distclean-generic clean + -rm -f config.status + +maintainer-clean: maintainer-clean-hdr maintainer-clean-binPROGRAMS \ + maintainer-clean-compile maintainer-clean-tags \ + maintainer-clean-generic distclean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + -rm -f config.status + +.PHONY: mostlyclean-hdr distclean-hdr clean-hdr maintainer-clean-hdr \ +mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \ +maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile install-man1 uninstall-man1 install-man \ +uninstall-man tags mostlyclean-tags distclean-tags clean-tags \ +maintainer-clean-tags distdir info dvi installcheck install-exec \ +install-data install uninstall all installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +ps.c: print.ps rdps + ./rdps print.ps ps.c + +rdps: rdps.c + $(CC) -o rdps rdps.c + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/NEWS b/NEWS new file mode 100644 index 0000000000..dbbbb64b83 --- /dev/null +++ b/NEWS @@ -0,0 +1,118 @@ +Overview of changes in Ethereal 0.3.15: + +* OSPF fixes (Hannes) +* Preliminary IPv6 support (Hannes) +* Name resolution (Laurent) +* Font and help option (Laurent) +* Token ring fixes (Gilbert) +* DLT_RAW #define fixes (Laurent, Hannes and a few others) + +Overview of changes in Ethereal 0.3.14: + +* Added Laurent's fixes to pntoh[sl]. +* RIP fixes (Laurent) +* Added Gilbert's BOOTP code. + +Overview of changes in Ethereal 0.3.13: + +* Made the tree items "sticky" +* Expanded the pntoh[sl] macros, fixed alignment problems with IPX code. +* Changes to packet-ppp and packet-raw + +Overview of changes in Ethereal 0.3.12: + +* RIP support (Hannes) +* LPR/LPD support (Gilbert) +* Changes to #includes to improve compatibility. + +Overview of changes in Ethereal 0.3.11: + +* Fixed a file capture bug. + +Overview of changes in Ethereal 0.3.10: + +* Fixed a Makefile bug with the new snprintf package. + +Overview of changes in Ethereal 0.3.9: + +* Switched to a different version of snprintf.c. +* Minor bug fixes. +* Fixes to Makefile.am. + +Overview of changes in Ethereal 0.3.8: + +* PostScript(R) output (Gilbert) +* More OSPF code (Hannes) +* Enhanced DNS (Bobo) + +Overview of changes in Ethereal 0.3.7: + +* Enhanced OSPF (Hannes) +* Fixed small bug in filter dialog. + +Overview of changes in Ethereal 0.3.6: + +* Added OSPF support, thanks to Hannes Boehm. +* Added -B, -P, and -T flags. + +Overview of changes in Ethereal 0.3.5: + +* Command line argument fixes/upgrades. +* Compatibility fixes. +* Initial pod/man page documentation. +* Miscellaneous changes to the way things are done in capture.c. +* Initial support for DNS and IGMP. + +Overview of changes in Ethereal 0.3.4: + +* Printer preferences dialog added (Gilbert) +* Misc fixes/upgrades. + +Overview of changes in Ethereal 0.3.3: + +* Added PPP support, thanks to Mike Hall. +* Added dialogs for errors/warnings. +* Support for the -r flag was added. +* Other minor fixes/upgrades. + +Overview of changes in Ethereal 0.3.2: + +* Misc bug fixes & minor enhancements. +* Added preliminary ICMP support +* Added preliminary printing support (Gilbert) + +Overview of changes in Ethereal 0.3.1: + +* Fixed bug that prevented capturing with a filter. +* Fixed misc. header problems. + +Overview of changes in Ethereal 0.3.0: + +* Initial support for filters. +* Fixes/enhancements for IPX and token ring (Gilbert). + +Overview of changes in Ethereal 0.2.3: + +* Added support for IPX, thanks to Gilbert. + +Overview of changes in Ethereal 0.2.2: + +* Added support for token ring, thanks to Gilbert Ramirez, Jr. + +Overview of changes in Ethereal 0.2.1: + +* Internal structs for ARP/RARP, IP, TCP, and UDP were created. Trying to + sort out which #includes were needed for each system was just too much of + a hassle. +* Added support for systems that don't have snprintf() and vsnprintf(), thanks + to Theo de Raadt. +* Minor changes to the README file. + +Overview of changes in Ethereal 0.2.0: + +* Initial public release. +* GNU autoconf-ified distribution +* Runs under Linux 2.0.x and Solaris 2.6. +* Requires GTK+ (1.0.1 tested) and libpcap (0.4a6 tested) +* For optimal results under Linux, the Karpski libpcap should be used. +* General documentation and a minimal web site have been prepared. diff --git a/README b/README new file mode 100644 index 0000000000..859859a6e7 --- /dev/null +++ b/README @@ -0,0 +1,112 @@ +General Information +------- ----------- + +Ethereal is a network traffic analyzer for Unix-ish operating systems. +It is based on GTK+, a graphical user interface library, and libpcap, +a packet capture and filtering library. + +The official home of Ethereal is + + http://ethereal.zing.org + +The latest distribution can be found in the subdirectory + + http://ethereal.zing.org/distribution + + +Installation +------------ + +Ethereal is known to compile and run under Linux (2.0.35) and Solaris +(2.6). It should run on other systems without too much trouble. + + +Installation Checklist (Short): + + [ ] 1. Unpack the archive. + + [ ] 2. Run './configure; make; make install; make install-man'. + If there are any problems, read on: + + +Installation Checklist (Long): + + [ ] 0. This is alpha software. Beware. + + [ ] 1. Make sure you have GTK+ installed. Try running 'gtk-config + --version'. If you need to install/reinstall GTK, you can find + it at + + http://www.gtk.org . + + Ethereal should work with the latest stable (1.0.x) version, but + I've had reports that it doesn't compile with the development + (1.1.x) tree. + + [ ] 2. Make sure you have libpcap installed. The latest version can be + found at + + ftp://ftp.ee.lbl.gov . + + Make sure you install the headers ('make install-incl') when you + install the library. + + [ ] 3. Run './configure' in the Ethereal distribution directory. + Running './configure --help' displays a list of options. + The file 'INSTALL' contains general instructions for running + 'configure'. + + [ ] 4. Run 'make'. Hopefully, you won't run into any problems. + + [ ] 5. Run './ethereal', and make sure things are working. You must + have root privileges in order to capture live data. + + [ ] 6. Run 'make install'. If you wish to install the man page, run + 'make install-man'. You're done. + + +Usage +----- + +In order to capture packets from the network, you need to be running +as root. Although it might be tempting to make the Ethereal executable +setuid root, please don't - alpha code is by nature not very robust, and +liable to contain security holes. + +The filtering mechanism is far from complete. Until the interface +solidifies, here's a description of what each component of the filter +dialog: + + - 'Filter name' entry: Gives a name to the filter you are about to create + or modify, e.g. 'Web and DNS traffic' + + - 'Filter string' entry: The text describing the filtering action to + take. It must have the same format as tcpdump filter strings (both + programs use the same underlying library), e.g. + + 'tcp port 80 or tcp port 443 or port 53' + + - 'New' button: If there is text in the two entry boxes, adds it to the + list. + + - 'Change' button: Modifies the currently selected list item to match + what's in the two entry boxes. + + - 'Copy' button: Makes a copy of the currently-selected list item. + + - 'Delete' button: Deletes the currently-selected list item. + + - 'OK' button: Sets the selected list item as the active filter. If + nothing is selected, turns filtering off. + + - 'Save' button: Saves the current filter list in + $HOME/.ethereal/filters. + + - 'Cancel' button: Closes the window without making changes. + + +Disclaimer +---------- + +There is no warranty, expressed or implied, associated with this product. +Use at your own risk. diff --git a/acconfig.h b/acconfig.h new file mode 100644 index 0000000000..789385ab98 --- /dev/null +++ b/acconfig.h @@ -0,0 +1,5 @@ +#undef PACKAGE + +#undef VERSION + +#undef HAVE_SOCKADDR_SA_LEN diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000000..de2d1a35e6 --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,335 @@ +dnl aclocal.m4 generated automatically by aclocal 1.3 + +dnl Copyright (C) 1994, 1995, 1996, 1997, 1998 Free Software Foundation, Inc. +dnl This Makefile.in is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. + +# Do all the work for Automake. This macro actually does too much -- +# some checks are only needed if your package does certain things. +# But this isn't really a big deal. + +# serial 1 + +dnl Usage: +dnl AM_INIT_AUTOMAKE(package,version, [no-define]) + +AC_DEFUN(AM_INIT_AUTOMAKE, +[AC_REQUIRE([AM_PROG_INSTALL]) +PACKAGE=[$1] +AC_SUBST(PACKAGE) +VERSION=[$2] +AC_SUBST(VERSION) +dnl test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi +ifelse([$3],, +AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE") +AC_DEFINE_UNQUOTED(VERSION, "$VERSION")) +AC_REQUIRE([AM_SANITY_CHECK]) +AC_REQUIRE([AC_ARG_PROGRAM]) +dnl FIXME This is truly gross. +missing_dir=`cd $ac_aux_dir && pwd` +AM_MISSING_PROG(ACLOCAL, aclocal, $missing_dir) +AM_MISSING_PROG(AUTOCONF, autoconf, $missing_dir) +AM_MISSING_PROG(AUTOMAKE, automake, $missing_dir) +AM_MISSING_PROG(AUTOHEADER, autoheader, $missing_dir) +AM_MISSING_PROG(MAKEINFO, makeinfo, $missing_dir) +AC_REQUIRE([AC_PROG_MAKE_SET])]) + + +# serial 1 + +AC_DEFUN(AM_PROG_INSTALL, +[AC_REQUIRE([AC_PROG_INSTALL]) +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' +AC_SUBST(INSTALL_SCRIPT)dnl +]) + +# +# Check to make sure that the build environment is sane. +# + +AC_DEFUN(AM_SANITY_CHECK, +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "[$]*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + if test "[$]*" != "X $srcdir/configure conftestfile" \ + && test "[$]*" != "X conftestfile $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "[$]2" = conftestfile + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +rm -f conftest* +AC_MSG_RESULT(yes)]) + +dnl AM_MISSING_PROG(NAME, PROGRAM, DIRECTORY) +dnl The program must properly implement --version. +AC_DEFUN(AM_MISSING_PROG, +[AC_MSG_CHECKING(for working $2) +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if ($2 --version) < /dev/null > /dev/null 2>&1; then + $1=$2 + AC_MSG_RESULT(found) +else + $1="$3/missing $2" + AC_MSG_RESULT(missing) +fi +AC_SUBST($1)]) + +# Configure paths for GTK+ +# Owen Taylor 97-11-3 + +dnl AM_PATH_GTK([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) +dnl Test for GTK, and define GTK_CFLAGS and GTK_LIBS +dnl +AC_DEFUN(AM_PATH_GTK, +[dnl +dnl Get the cflags and libraries from the gtk-config script +dnl +AC_ARG_WITH(gtk-prefix,[ --with-gtk-prefix=PFX Prefix where GTK is installed (optional)], + gtk_config_prefix="$withval", gtk_config_prefix="") +AC_ARG_WITH(gtk-exec-prefix,[ --with-gtk-exec-prefix=PFX Exec prefix where GTK is installed (optional)], + gtk_config_exec_prefix="$withval", gtk_config_exec_prefix="") +AC_ARG_ENABLE(gtktest, [ --disable-gtktest Do not try to compile and run a test GTK program], + , enable_gtktest=yes) + + if test x$gtk_config_exec_prefix != x ; then + gtk_config_args="$gtk_config_args --exec-prefix=$gtk_config_exec_prefix" + if test x${GTK_CONFIG+set} != xset ; then + GTK_CONFIG=$gtk_config_exec_prefix/bin/gtk-config + fi + fi + if test x$gtk_config_prefix != x ; then + gtk_config_args="$gtk_config_args --prefix=$gtk_config_prefix" + if test x${GTK_CONFIG+set} != xset ; then + GTK_CONFIG=$gtk_config_prefix/bin/gtk-config + fi + fi + + AC_PATH_PROG(GTK_CONFIG, gtk-config, no) + min_gtk_version=ifelse([$1], ,0.99.7,$1) + AC_MSG_CHECKING(for GTK - version >= $min_gtk_version) + no_gtk="" + if test "$GTK_CONFIG" = "no" ; then + no_gtk=yes + else + GTK_CFLAGS=`$GTK_CONFIG $gtk_config_args --cflags` + GTK_LIBS=`$GTK_CONFIG $gtk_config_args --libs` + gtk_config_major_version=`$GTK_CONFIG $gtk_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + gtk_config_minor_version=`$GTK_CONFIG $gtk_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + gtk_config_micro_version=`$GTK_CONFIG $gtk_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + if test "x$enable_gtktest" = "xyes" ; then + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $GTK_CFLAGS" + LIBS="$LIBS $GTK_LIBS" +dnl +dnl Now check if the installed GTK is sufficiently new. (Also sanity +dnl checks the results of gtk-config to some extent +dnl + rm -f conf.gtktest + AC_TRY_RUN([ +#include +#include + +int +main () +{ + int major, minor, micro; + + system ("touch conf.gtktest"); + + if (sscanf("$min_gtk_version", "%d.%d.%d", &major, &minor, µ) != 3) { + printf("%s, bad version string\n", "$min_gtk_version"); + exit(1); + } + + if ((gtk_major_version != $gtk_config_major_version) || + (gtk_minor_version != $gtk_config_minor_version) || + (gtk_micro_version != $gtk_config_micro_version)) + { + printf("\n*** 'gtk-config --version' returned %d.%d.%d, but GTK+ (%d.%d.%d)\n", + $gtk_config_major_version, $gtk_config_minor_version, $gtk_config_micro_version, + gtk_major_version, gtk_minor_version, gtk_micro_version); + printf ("*** was found! If gtk-config was correct, then it is best\n"); + printf ("*** to remove the old version of GTK+. You may also be able to fix the error\n"); + printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n"); + printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n"); + printf("*** required on your system.\n"); + printf("*** If gtk-config was wrong, set the environment variable GTK_CONFIG\n"); + printf("*** to point to the correct copy of gtk-config, and remove the file config.cache\n"); + printf("*** before re-running configure\n"); + } + else + { + if ((gtk_major_version > major) || + ((gtk_major_version == major) && (gtk_minor_version > minor)) || + ((gtk_major_version == major) && (gtk_minor_version == minor) && (gtk_micro_version >= micro))) + { + return 0; + } + else + { + printf("\n*** An old version of GTK+ (%d.%d.%d) was found.\n", + gtk_major_version, gtk_minor_version, gtk_micro_version); + printf("*** You need a version of GTK+ newer than %d.%d.%d. The latest version of\n", + major, minor, micro); + printf("*** GTK+ is always available from ftp://ftp.gtk.org.\n"); + printf("***\n"); + printf("*** If you have already installed a sufficiently new version, this error\n"); + printf("*** probably means that the wrong copy of the gtk-config shell script is\n"); + printf("*** being found. The easiest way to fix this is to remove the old version\n"); + printf("*** of GTK+, but you can also set the GTK_CONFIG environment to point to the\n"); + printf("*** correct copy of gtk-config. (In this case, you will have to\n"); + printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); + printf("*** so that the correct libraries are found at run-time))\n"); + } + } + return 1; +} +],, no_gtk=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + if test "x$no_gtk" = x ; then + AC_MSG_RESULT(yes) + ifelse([$2], , :, [$2]) + else + AC_MSG_RESULT(no) + if test "$GTK_CONFIG" = "no" ; then + echo "*** The gtk-config script installed by GTK could not be found" + echo "*** If GTK was installed in PREFIX, make sure PREFIX/bin is in" + echo "*** your path, or set the GTK_CONFIG environment variable to the" + echo "*** full path to gtk-config." + else + if test -f conf.gtktest ; then + : + else + echo "*** Could not run GTK test program, checking why..." + CFLAGS="$CFLAGS $GTK_CFLAGS" + LIBS="$LIBS $GTK_LIBS" + AC_TRY_LINK([ +#include +#include +], [ return ((gtk_major_version) || (gtk_minor_version) || (gtk_micro_version)); ], + [ echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding GTK or finding the wrong" + echo "*** version of GTK. If it is not finding GTK, you'll need to set your" + echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" + echo "*** to the installed location Also, make sure you have run ldconfig if that" + echo "*** is required on your system" + echo "***" + echo "*** If you have an old version installed, it is best to remove it, although" + echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" + echo "***" + echo "*** If you have a RedHat 5.0 system, you should remove the GTK package that" + echo "*** came with the system with the command" + echo "***" + echo "*** rpm --erase --nodeps gtk gtk-devel" ], + [ echo "*** The test program failed to compile or link. See the file config.log for the" + echo "*** exact error that occured. This usually means GTK was incorrectly installed" + echo "*** or that you have moved GTK since it was installed. In the latter case, you" + echo "*** may want to edit the gtk-config script: $GTK_CONFIG" ]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + GTK_CFLAGS="" + GTK_LIBS="" + ifelse([$3], , :, [$3]) + fi + AC_SUBST(GTK_CFLAGS) + AC_SUBST(GTK_LIBS) + rm -f conf.gtktest +]) + +dnl This was copied from the libpcap 0.4a6 source. +dnl ftp://ftp.ee.lbl.gov + +dnl +dnl Checks to see if the sockaddr struct has the 4.4 BSD sa_len member +dnl +dnl usage: +dnl +dnl AC_LBL_SOCKADDR_SA_LEN +dnl +dnl results: +dnl +dnl HAVE_SOCKADDR_SA_LEN (defined) +dnl +AC_DEFUN(AC_LBL_SOCKADDR_SA_LEN, + [AC_MSG_CHECKING(if sockaddr struct has sa_len member) + AC_CACHE_VAL(ac_cv_lbl_sockaddr_has_sa_len, + AC_TRY_COMPILE([ +# include +# include ], + [u_int i = sizeof(((struct sockaddr *)0)->sa_len)], + ac_cv_lbl_sockaddr_has_sa_len=yes, + ac_cv_lbl_sockaddr_has_sa_len=no)) + AC_MSG_RESULT($ac_cv_lbl_sockaddr_has_sa_len) + if test $ac_cv_lbl_sockaddr_has_sa_len = yes ; then + AC_DEFINE(HAVE_SOCKADDR_SA_LEN) + fi]) + +# Like AC_CONFIG_HEADER, but automatically create stamp file. + +AC_DEFUN(AM_CONFIG_HEADER, +[AC_PREREQ([2.12]) +AC_CONFIG_HEADER([$1]) +dnl When config.status generates a header, we must update the stamp-h file. +dnl This file resides in the same directory as the config header +dnl that is generated. We must strip everything past the first ":", +dnl and everything past the last "/". +AC_OUTPUT_COMMANDS(changequote(<<,>>)dnl +ifelse(patsubst(<<$1>>, <<[^ ]>>, <<>>), <<>>, +<>CONFIG_HEADERS" || echo timestamp > patsubst(<<$1>>, <<^\([^:]*/\)?.*>>, <<\1>>)stamp-h<<>>dnl>>, +<>; do + case " <<$>>CONFIG_HEADERS " in + *" <<$>>am_file "*<<)>> + echo timestamp > `echo <<$>>am_file | sed -e 's%:.*%%' -e 's%[^/]*$%%'`stamp-h$am_indx + ;; + esac + am_indx=`expr "<<$>>am_indx" + 1` +done<<>>dnl>>) +changequote([,]))]) + diff --git a/capture.c b/capture.c new file mode 100644 index 0000000000..73d575fbb2 --- /dev/null +++ b/capture.c @@ -0,0 +1,501 @@ +/* capture.c + * Routines for packet capture windows + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include +#include +#include +#include + +#ifdef HAVE_SYS_SOCKIO_H +# include +#endif + +#include "packet.h" +#include "file.h" +#include "capture.h" +#include "etypes.h" +#include "util.h" + +extern capture_file cf; +extern GtkWidget *info_bar; +extern guint file_ctx; + +/* File selection data keys */ +const gchar *prep_fs_key = "prep_fs", + *prep_te_key = "prep_te"; + +/* Capture callback data keys */ +const gchar *cap_iface_key = "cap_iface", + *cap_file_key = "cap_file", + *cap_count_key = "cap_count", + *cap_open_key = "cap_open", + *cap_snap_key = "cap_snap"; + +GList * +get_interface_list() { + GList *il = NULL; + struct ifreq *ifr, *last; + struct ifconf ifc; + int sock = socket(AF_INET, SOCK_DGRAM, 0); + + if (sock < 0) + { + simple_dialog(ESD_TYPE_WARN, NULL, + "Can't list interfaces: error opening socket."); + return NULL; + } + + /* Since we have to grab the interface list all at once, we'll make + plenty of room */ + ifc.ifc_len = 1024 * sizeof(struct ifreq); + ifc.ifc_buf = malloc(ifc.ifc_len); + + if (ioctl(sock, SIOCGIFCONF, &ifc) < 0 || + ifc.ifc_len < sizeof(struct ifreq)) + { + simple_dialog(ESD_TYPE_WARN, NULL, + "Can't list interfaces: ioctl error."); + return NULL; + } + + ifr = (struct ifreq *) ifc.ifc_req; + last = (struct ifreq *) ((char *) ifr + ifc.ifc_len); + while (ifr < last) + { + /* + * What we want: + * - Interfaces that are up, and not loopback + * - IP interfaces (do we really need this?) + * - Anything that doesn't begin with "lo" (loopback again) or "dummy" + * - Anything that doesn't include a ":" (Solaris virtuals) + */ + if (! (ifr->ifr_flags & (IFF_UP | IFF_LOOPBACK)) && + (ifr->ifr_addr.sa_family == AF_INET) && + strncmp(ifr->ifr_name, "lo", 2) && + strncmp(ifr->ifr_name, "dummy", 5) && + ! strchr(ifr->ifr_name, ':')) { + il = g_list_append(il, g_strdup(ifr->ifr_name)); + } +#ifdef HAVE_SOCKADDR_SA_LEN + ifr = (struct ifreq *) ((char *) ifr + ifr->ifr_addr.sa_len + IFNAMSIZ); +#else + ifr = (struct ifreq *) ((char *) ifr + sizeof(struct ifreq)); +#endif + } + + free(ifc.ifc_buf); + return il; +} + +void +capture_prep_cb(GtkWidget *w, gpointer d) { + GtkWidget *cap_open_w, *if_cb, *if_lb, *file_te, *file_bt, + *count_lb, *count_cb, *main_vb, *top_hb, *middle_hb, + *bottom_hb, *bbox, *ok_bt, *cancel_bt, *capfile_ck, + *snap_lb, *snap_sb; + GtkAdjustment *adj; + GList *if_list, *count_list = NULL; + gchar *count_item1 = "0 (Infinite)", count_item2[16]; + + cap_open_w = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(cap_open_w), "Ethereal: Capture Preferences"); + + /* Container for each row of widgets */ + main_vb = gtk_vbox_new(FALSE, 3); + gtk_container_border_width(GTK_CONTAINER(main_vb), 5); + gtk_container_add(GTK_CONTAINER(cap_open_w), main_vb); + gtk_widget_show(main_vb); + + /* Top row: Interface and count selections */ + top_hb = gtk_hbox_new(FALSE, 1); + gtk_container_add(GTK_CONTAINER(main_vb), top_hb); + gtk_widget_show(top_hb); + + if_lb = gtk_label_new("Interface:"); + gtk_box_pack_start(GTK_BOX(top_hb), if_lb, FALSE, FALSE, 3); + gtk_widget_show(if_lb); + + if_list = get_interface_list(); + if_cb = gtk_combo_new(); + gtk_combo_set_popdown_strings(GTK_COMBO(if_cb), if_list); + if (cf.iface) + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(if_cb)->entry), cf.iface); + else if (if_list) + gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(if_cb)->entry), if_list->data); + gtk_box_pack_start(GTK_BOX(top_hb), if_cb, FALSE, FALSE, 3); + gtk_widget_show(if_cb); + while (if_list) { + g_free(if_list->data); + if_list = g_list_remove_link(if_list, if_list); + } + + if (cf.count) { + snprintf(count_item2, 15, "%d", cf.count); + count_list = g_list_append(count_list, count_item2); + } + count_list = g_list_append(count_list, count_item1); + count_cb = gtk_combo_new(); + gtk_combo_set_popdown_strings(GTK_COMBO(count_cb), count_list); + gtk_box_pack_end(GTK_BOX(top_hb), count_cb, FALSE, FALSE, 3); + gtk_widget_show(count_cb); + while (count_list) + count_list = g_list_remove_link(count_list, count_list); + + count_lb = gtk_label_new("Count:"); + gtk_box_pack_end(GTK_BOX(top_hb), count_lb, FALSE, FALSE, 3); + gtk_widget_show(count_lb); + + /* Middle row: File: button and text entry */ + middle_hb = gtk_hbox_new(FALSE, 1); + gtk_container_add(GTK_CONTAINER(main_vb), middle_hb); + gtk_widget_show(middle_hb); + + file_bt = gtk_button_new_with_label("File:"); + gtk_box_pack_start(GTK_BOX(middle_hb), file_bt, FALSE, FALSE, 3); + gtk_widget_show(file_bt); + + file_te = gtk_entry_new(); + if (cf.save_file) + gtk_entry_set_text(GTK_ENTRY(file_te), cf.save_file); + gtk_box_pack_start(GTK_BOX(middle_hb), file_te, TRUE, TRUE, 3); + gtk_widget_show(file_te); + + gtk_signal_connect_object(GTK_OBJECT(file_bt), "clicked", + GTK_SIGNAL_FUNC(capture_prep_file_cb), GTK_OBJECT(file_te)); + + /* Bottom row: Capture file checkbox and snap spinbutton */ + bottom_hb = gtk_hbox_new(FALSE, 1); + gtk_container_add(GTK_CONTAINER(main_vb), bottom_hb); + gtk_widget_show(bottom_hb); + + capfile_ck = gtk_check_button_new_with_label("Open file after capture"); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(capfile_ck), TRUE); + gtk_box_pack_start(GTK_BOX(bottom_hb), capfile_ck, FALSE, FALSE, 3); + gtk_widget_show(capfile_ck); + + snap_lb = gtk_label_new("Capture length"); + gtk_misc_set_alignment(GTK_MISC(snap_lb), 0, 0.5); + gtk_box_pack_start(GTK_BOX(bottom_hb), snap_lb, FALSE, FALSE, 6); + gtk_widget_show(snap_lb); + + adj = (GtkAdjustment *) gtk_adjustment_new((float) cf.snap, 1.0, 4096.0, + 1.0, 10.0, 0.0); + snap_sb = gtk_spin_button_new (adj, 0, 0); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (snap_sb), TRUE); + gtk_widget_set_usize (snap_sb, 80, 0); + gtk_box_pack_start (GTK_BOX(bottom_hb), snap_sb, FALSE, FALSE, 3); + gtk_widget_show(snap_sb); + + /* Button row: OK and cancel buttons */ + bbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END); + gtk_container_add(GTK_CONTAINER(main_vb), bbox); + gtk_widget_show(bbox); + + ok_bt = gtk_button_new_with_label ("OK"); + gtk_signal_connect_object(GTK_OBJECT(ok_bt), "clicked", + GTK_SIGNAL_FUNC(capture_prep_ok_cb), GTK_OBJECT(cap_open_w)); + gtk_container_add(GTK_CONTAINER(bbox), ok_bt); +/* GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT); + gtk_widget_grab_default(ok_bt); */ + gtk_widget_show(ok_bt); + + cancel_bt = gtk_button_new_with_label ("Cancel"); + gtk_signal_connect_object(GTK_OBJECT(cancel_bt), "clicked", + GTK_SIGNAL_FUNC(capture_prep_close_cb), GTK_OBJECT(cap_open_w)); + gtk_container_add(GTK_CONTAINER(bbox), cancel_bt); + gtk_widget_show(cancel_bt); + + /* Attach pointers to needed widges to the capture prefs window/object */ + gtk_object_set_data(GTK_OBJECT(cap_open_w), cap_iface_key, if_cb); + gtk_object_set_data(GTK_OBJECT(cap_open_w), cap_file_key, file_te); + gtk_object_set_data(GTK_OBJECT(cap_open_w), cap_count_key, count_cb); + gtk_object_set_data(GTK_OBJECT(cap_open_w), cap_open_key, capfile_ck); + gtk_object_set_data(GTK_OBJECT(cap_open_w), cap_snap_key, snap_sb); + + gtk_widget_show(cap_open_w); +} + +void +capture_prep_file_cb(GtkWidget *w, gpointer te) { + GtkWidget *fs; + + fs = gtk_file_selection_new ("Ethereal: Open Save File"); + + gtk_object_set_data(GTK_OBJECT(w), prep_fs_key, fs); + gtk_object_set_data(GTK_OBJECT(w), prep_te_key, (GtkWidget *) te); + + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION(fs)->ok_button), + "clicked", (GtkSignalFunc) cap_prep_fs_ok_cb, w); + + /* Connect the cancel_button to destroy the widget */ + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION(fs)->cancel_button), + "clicked", (GtkSignalFunc) cap_prep_fs_cancel_cb, w); + + gtk_widget_show(fs); +} + +void +cap_prep_fs_ok_cb(GtkWidget *w, gpointer data) { + GtkWidget *fs, *te; + + fs = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(data), prep_fs_key); + te = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(data), prep_te_key); + + gtk_entry_set_text(GTK_ENTRY(te), + gtk_file_selection_get_filename (GTK_FILE_SELECTION(fs))); + cap_prep_fs_cancel_cb(w, data); +} + +void +cap_prep_fs_cancel_cb(GtkWidget *w, gpointer data) { + GtkWidget *fs; + + fs = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(data), prep_fs_key); + + gtk_widget_destroy(fs); +} + +void +capture_prep_ok_cb(GtkWidget *w, gpointer data) { + GtkWidget *if_cb, *file_te, *count_cb, *open_ck, *snap_sb; + gchar *file; + gint open; + + if_cb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(data), cap_iface_key); + file_te = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(data), cap_file_key); + count_cb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(data), cap_count_key); + open_ck = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(data), cap_open_key); + snap_sb = (GtkWidget *) gtk_object_get_data(GTK_OBJECT(data), cap_snap_key); + + if (cf.iface) g_free(cf.iface); + cf.iface = + g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(if_cb)->entry))); + if (cf.save_file) g_free(cf.save_file); + cf.save_file = g_strdup(gtk_entry_get_text(GTK_ENTRY(file_te))); + cf.count = + atoi(g_strdup(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(count_cb)->entry)))); + open = GTK_TOGGLE_BUTTON(open_ck)->active; + cf.snap = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(snap_sb)); + if (cf.snap < 1) + cf.snap = 4096; + else if (cf.snap < 68) + cf.snap = 68; + + gtk_widget_destroy(GTK_WIDGET(data)); + + capture(open); +} + +void +capture_prep_close_cb(GtkWidget *w, gpointer win) { + + gtk_grab_remove(GTK_WIDGET(win)); + gtk_widget_destroy(GTK_WIDGET(win)); +} + +void +capture(gint open) { + GtkWidget *cap_w, *main_vb, *count_lb, *tcp_lb, *udp_lb, *other_lb, + *stop_bt; + pcap_t *pch; + gchar err_str[PCAP_ERRBUF_SIZE], label_str[32]; + loop_data ld; + bpf_u_int32 netnum, netmask; + time_t upd_time, cur_time; + + ld.go = TRUE; + ld.count = 0; + ld.max = cf.count; + ld.tcp = 0; + ld.udp = 0; + ld.other = 0; + ld.pdh = NULL; + + close_cap_file(&cf, info_bar, file_ctx); + + pch = pcap_open_live(cf.iface, cf.snap, 1, 250, err_str); + + if (pch) { + if (cf.save_file[0]) { + ld.pdh = pcap_dump_open(pch, cf.save_file); + if (ld.pdh == NULL) { /* We have an error */ + snprintf(err_str, PCAP_ERRBUF_SIZE, "Error trying to open dump " + "file:\n%s", pcap_geterr(pch)); + simple_dialog(ESD_TYPE_WARN, NULL, err_str); + g_free(cf.save_file); + cf.save_file = NULL; + pcap_close(pch); + return; + } + } + + if (cf.filter) { + if (pcap_lookupnet (cf.iface, &netnum, &netmask, err_str) < 0) { + simple_dialog(ESD_TYPE_WARN, NULL, + "Can't use filter: Couldn't obtain netmask info."); + return; + } else if (pcap_compile(pch, &cf.fcode, cf.filter, 1, netmask) < 0) { + simple_dialog(ESD_TYPE_WARN, NULL, "Unable to parse filter string."); + return; + } else if (pcap_setfilter(pch, &cf.fcode) < 0) { + simple_dialog(ESD_TYPE_WARN, NULL, "Can't install filter."); + return; + } + } + + cap_w = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(cap_w), "Ethereal: Capture / Playback"); + + /* Container for capture display widgets */ + main_vb = gtk_vbox_new(FALSE, 1); + gtk_container_border_width(GTK_CONTAINER(main_vb), 5); + gtk_container_add(GTK_CONTAINER(cap_w), main_vb); + gtk_widget_show(main_vb); + + count_lb = gtk_label_new("Count: 0"); + gtk_box_pack_start(GTK_BOX(main_vb), count_lb, FALSE, FALSE, 3); + gtk_widget_show(count_lb); + + tcp_lb = gtk_label_new("TCP: 0 (0.0%)"); + gtk_box_pack_start(GTK_BOX(main_vb), tcp_lb, FALSE, FALSE, 3); + gtk_widget_show(tcp_lb); + + udp_lb = gtk_label_new("UDP: 0 (0.0%)"); + gtk_box_pack_start(GTK_BOX(main_vb), udp_lb, FALSE, FALSE, 3); + gtk_widget_show(udp_lb); + + other_lb = gtk_label_new("Other: 0 (0.0%)"); + gtk_box_pack_start(GTK_BOX(main_vb), other_lb, FALSE, FALSE, 3); + gtk_widget_show(other_lb); + + stop_bt = gtk_button_new_with_label ("Stop"); + gtk_signal_connect(GTK_OBJECT(stop_bt), "clicked", + GTK_SIGNAL_FUNC(capture_stop_cb), (gpointer) &ld); + gtk_box_pack_end(GTK_BOX(main_vb), stop_bt, FALSE, FALSE, 3); + GTK_WIDGET_SET_FLAGS(stop_bt, GTK_CAN_DEFAULT); + gtk_widget_grab_default(stop_bt); + GTK_WIDGET_SET_FLAGS(stop_bt, GTK_CAN_DEFAULT); + gtk_widget_grab_default(stop_bt); + gtk_widget_show(stop_bt); + + gtk_widget_show(cap_w); + gtk_grab_add(cap_w); + + upd_time = time(NULL); + while (ld.go) { + while (gtk_events_pending()) gtk_main_iteration(); + pcap_dispatch(pch, 1, capture_pcap_cb, (u_char *) &ld); + /* Only update once a second so as not to overload slow displays */ + cur_time = time(NULL); + if (cur_time > upd_time) { + upd_time = cur_time; + sprintf(label_str, "Count: %d", ld.count); + gtk_label_set(GTK_LABEL(count_lb), label_str); + sprintf(label_str, "TCP: %d (%.1f%%)", ld.tcp, pct(ld.tcp, ld.count)); + gtk_label_set(GTK_LABEL(tcp_lb), label_str); + sprintf(label_str, "UDP: %d (%.1f%%)", ld.udp, pct(ld.udp, ld.count)); + gtk_label_set(GTK_LABEL(udp_lb), label_str); + sprintf(label_str, "Other: %d (%.1f%%)", ld.other, + pct(ld.other, ld.count)); + gtk_label_set(GTK_LABEL(other_lb), label_str); + } + } + + if (ld.pdh) pcap_dump_close(ld.pdh); + pcap_close(pch); + + gtk_grab_remove(GTK_WIDGET(cap_w)); + gtk_widget_destroy(GTK_WIDGET(cap_w)); + } else { + while (gtk_events_pending()) gtk_main_iteration(); + simple_dialog(ESD_TYPE_WARN, NULL, + "The capture session could not be initiated. Please\n" + "check to make sure you have sufficient permissions, and\n" + "that you have the proper interface specified."); + g_free(cf.save_file); + cf.save_file = NULL; + } + + if (cf.save_file && open) load_cap_file(cf.save_file, &cf); +} + +float +pct(gint num, gint denom) { + if (denom) { + return (float) num * 100.0 / (float) denom; + } else { + return 0.0; + } +} + +void +capture_stop_cb(GtkWidget *w, gpointer data) { + loop_data *ld = (loop_data *) data; + + ld->go = FALSE; +} + +void +capture_pcap_cb(u_char *user, const struct pcap_pkthdr *phdr, + const u_char *pd) { + + guint16 etype; + guint8 iptype = 0; + gint offset = 14; + + loop_data *ld = (loop_data *) user; + + if ((++ld->count >= ld->max) && (ld->max > 0)) ld->go = FALSE; + /* Currently, pcap_dumper_t is a FILE *. Let's hope that doesn't change. */ + if (ld->pdh) pcap_dump((u_char *) ld->pdh, phdr, pd); + + etype = etype = (pd[12] << 8) | pd[13]; + if (etype <= IEEE_802_3_MAX_LEN) { + etype = (pd[20] << 8) | pd[21]; + offset = 22; + } + + if (etype == ETHERTYPE_IP) { + iptype = pd[offset + 9]; + switch (iptype) { + case 6: + ld->tcp++; + break; + case 17: + ld->udp++; + break; + default: + ld->other++; + } + } else { + ld->other++; + } +} diff --git a/capture.h b/capture.h new file mode 100644 index 0000000000..ae6bdebd54 --- /dev/null +++ b/capture.h @@ -0,0 +1,49 @@ +/* capture.h + * Definitions for packet capture windows + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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 __CAPTURE_H__ +#define __CAPTURE_H__ + +typedef struct _loop_data { + gint go; + gint count; + gint max; + gint tcp; + gint udp; + gint other; + pcap_dumper_t *pdh; +} loop_data; + +GList *get_interface_list(); +void capture_prep_cb(GtkWidget *, gpointer); +void capture_prep_file_cb(GtkWidget *, gpointer); +void cap_prep_fs_ok_cb(GtkWidget *, gpointer); +void cap_prep_fs_cancel_cb(GtkWidget *, gpointer); +void capture_prep_ok_cb(GtkWidget *, gpointer); +void capture_prep_close_cb(GtkWidget *, gpointer); +void capture(gint); +float pct(gint, gint); +void capture_stop_cb(GtkWidget *, gpointer); +void capture_pcap_cb(u_char *, const struct pcap_pkthdr *, const u_char *); + +#endif /* capture.h */ diff --git a/config.h b/config.h new file mode 100644 index 0000000000..d1a798900c --- /dev/null +++ b/config.h @@ -0,0 +1,24 @@ +/* config.h. Generated automatically by configure. */ +/* config.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define if your processor stores words with the most significant + byte first (like Motorola and SPARC, unlike Intel and VAX). */ +/* #undef WORDS_BIGENDIAN */ + +#define PACKAGE "ethereal" + +#define VERSION "0.3.15" + +/* #undef HAVE_SOCKADDR_SA_LEN */ + +/* Define if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_SOCKIO_H */ + +/* Define if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define if you have the pcap library (-lpcap). */ +#define HAVE_LIBPCAP 1 diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000000..67cd0c40ae --- /dev/null +++ b/config.h.in @@ -0,0 +1,23 @@ +/* config.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define if your processor stores words with the most significant + byte first (like Motorola and SPARC, unlike Intel and VAX). */ +#undef WORDS_BIGENDIAN + +#undef PACKAGE + +#undef VERSION + +#undef HAVE_SOCKADDR_SA_LEN + +/* Define if you have the header file. */ +#undef HAVE_NETINET_IN_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_SOCKIO_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define if you have the pcap library (-lpcap). */ +#undef HAVE_LIBPCAP diff --git a/configure b/configure new file mode 100755 index 0000000000..65548f4945 --- /dev/null +++ b/configure @@ -0,0 +1,2075 @@ +#! /bin/sh + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.12 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: +ac_help="$ac_help + --with-gtk-prefix=PFX Prefix where GTK is installed (optional)" +ac_help="$ac_help + --with-gtk-exec-prefix=PFX Exec prefix where GTK is installed (optional)" +ac_help="$ac_help + --disable-gtktest Do not try to compile and run a test GTK program" + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +x_includes=NONE +x_libraries=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +libdir='${exec_prefix}/lib' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var] + --libdir=DIR object code libraries in DIR [EPREFIX/lib] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --x-includes=DIR X include files are in DIR + --x-libraries=DIR X library files are in DIR +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.12" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes="$ac_optarg" ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=etypes.h + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + + +ac_aux_dir= +for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:559: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + for ac_prog in ginstall installbsd scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + # OSF/1 installbsd also uses dspmsg, but is usable. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' + +echo $ac_n "checking whether build environment is sane""... $ac_c" 1>&6 +echo "configure:612: checking whether build environment is sane" >&5 +# Just in case +sleep 1 +echo timestamp > conftestfile +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftestfile 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftestfile` + fi + if test "$*" != "X $srcdir/configure conftestfile" \ + && test "$*" != "X conftestfile $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { echo "configure: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" 1>&2; exit 1; } + fi + + test "$2" = conftestfile + ) +then + # Ok. + : +else + { echo "configure: error: newly created file is older than distributed files! +Check your system clock" 1>&2; exit 1; } +fi +rm -f conftest* +echo "$ac_t""yes" 1>&6 +if test "$program_transform_name" = s,x,x,; then + program_transform_name= +else + # Double any \ or $. echo might interpret backslashes. + cat <<\EOF_SED > conftestsed +s,\\,\\\\,g; s,\$,$$,g +EOF_SED + program_transform_name="`echo $program_transform_name|sed -f conftestsed`" + rm -f conftestsed +fi +test "$program_prefix" != NONE && + program_transform_name="s,^,${program_prefix},; $program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s,\$\$,${program_suffix},; $program_transform_name" + +# sed with no file args requires a program. +test "$program_transform_name" = "" && program_transform_name="s,x,x," + +echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6 +echo "configure:669: checking whether ${MAKE-make} sets \${MAKE}" >&5 +set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftestmake <<\EOF +all: + @echo 'ac_maketemp="${MAKE}"' +EOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=` +if test -n "$ac_maketemp"; then + eval ac_cv_prog_make_${ac_make}_set=yes +else + eval ac_cv_prog_make_${ac_make}_set=no +fi +rm -f conftestmake +fi +if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then + echo "$ac_t""yes" 1>&6 + SET_MAKE= +else + echo "$ac_t""no" 1>&6 + SET_MAKE="MAKE=${MAKE-make}" +fi + + +PACKAGE=ethereal + +VERSION=0.3.15 + +if test "`cd $srcdir && pwd`" != "`pwd`" && test -f $srcdir/config.status; then + { echo "configure: error: source directory already configured; run "make distclean" there first" 1>&2; exit 1; } +fi +cat >> confdefs.h <> confdefs.h <&6 +echo "configure:715: checking for working aclocal" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (aclocal --version) < /dev/null > /dev/null 2>&1; then + ACLOCAL=aclocal + echo "$ac_t""found" 1>&6 +else + ACLOCAL="$missing_dir/missing aclocal" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working autoconf""... $ac_c" 1>&6 +echo "configure:728: checking for working autoconf" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (autoconf --version) < /dev/null > /dev/null 2>&1; then + AUTOCONF=autoconf + echo "$ac_t""found" 1>&6 +else + AUTOCONF="$missing_dir/missing autoconf" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working automake""... $ac_c" 1>&6 +echo "configure:741: checking for working automake" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (automake --version) < /dev/null > /dev/null 2>&1; then + AUTOMAKE=automake + echo "$ac_t""found" 1>&6 +else + AUTOMAKE="$missing_dir/missing automake" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working autoheader""... $ac_c" 1>&6 +echo "configure:754: checking for working autoheader" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (autoheader --version) < /dev/null > /dev/null 2>&1; then + AUTOHEADER=autoheader + echo "$ac_t""found" 1>&6 +else + AUTOHEADER="$missing_dir/missing autoheader" + echo "$ac_t""missing" 1>&6 +fi + +echo $ac_n "checking for working makeinfo""... $ac_c" 1>&6 +echo "configure:767: checking for working makeinfo" >&5 +# Run test in a subshell; some versions of sh will print an error if +# an executable is not found, even if stderr is redirected. +# Redirect stdin to placate older versions of autoconf. Sigh. +if (makeinfo --version) < /dev/null > /dev/null 2>&1; then + MAKEINFO=makeinfo + echo "$ac_t""found" 1>&6 +else + MAKEINFO="$missing_dir/missing makeinfo" + echo "$ac_t""missing" 1>&6 +fi + + + +# Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:784: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:813: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + ac_prog_rejected=no + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi + +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:861: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:895: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:900: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 + +if test $ac_cv_prog_gcc = yes; then + GCC=yes + ac_test_CFLAGS="${CFLAGS+set}" + ac_save_CFLAGS="$CFLAGS" + CFLAGS= + echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:924: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 + if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" + elif test $ac_cv_prog_cc_g = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-O2" + fi +else + GCC= + test "${CFLAGS+set}" = set || CFLAGS="-g" +fi + + +# If LD_LIBRARY_PATH is defined, add it as a link directory. +# This should help Solaris users. +if test x$LD_LIBRARY_PATH != x ; then + LIBS="$LIBS -R$LD_LIBRARY_PATH" +fi + +# GTK checks +# Check whether --with-gtk-prefix or --without-gtk-prefix was given. +if test "${with_gtk_prefix+set}" = set; then + withval="$with_gtk_prefix" + gtk_config_prefix="$withval" +else + gtk_config_prefix="" +fi + +# Check whether --with-gtk-exec-prefix or --without-gtk-exec-prefix was given. +if test "${with_gtk_exec_prefix+set}" = set; then + withval="$with_gtk_exec_prefix" + gtk_config_exec_prefix="$withval" +else + gtk_config_exec_prefix="" +fi + +# Check whether --enable-gtktest or --disable-gtktest was given. +if test "${enable_gtktest+set}" = set; then + enableval="$enable_gtktest" + : +else + enable_gtktest=yes +fi + + + if test x$gtk_config_exec_prefix != x ; then + gtk_config_args="$gtk_config_args --exec-prefix=$gtk_config_exec_prefix" + if test x${GTK_CONFIG+set} != xset ; then + GTK_CONFIG=$gtk_config_exec_prefix/bin/gtk-config + fi + fi + if test x$gtk_config_prefix != x ; then + gtk_config_args="$gtk_config_args --prefix=$gtk_config_prefix" + if test x${GTK_CONFIG+set} != xset ; then + GTK_CONFIG=$gtk_config_prefix/bin/gtk-config + fi + fi + + # Extract the first word of "gtk-config", so it can be a program name with args. +set dummy gtk-config; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1000: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_GTK_CONFIG'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$GTK_CONFIG" in + /*) + ac_cv_path_GTK_CONFIG="$GTK_CONFIG" # Let the user override the test with a path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_GTK_CONFIG="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + test -z "$ac_cv_path_GTK_CONFIG" && ac_cv_path_GTK_CONFIG="no" + ;; +esac +fi +GTK_CONFIG="$ac_cv_path_GTK_CONFIG" +if test -n "$GTK_CONFIG"; then + echo "$ac_t""$GTK_CONFIG" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + min_gtk_version=1.0.0 + echo $ac_n "checking for GTK - version >= $min_gtk_version""... $ac_c" 1>&6 +echo "configure:1031: checking for GTK - version >= $min_gtk_version" >&5 + no_gtk="" + if test "$GTK_CONFIG" = "no" ; then + no_gtk=yes + else + GTK_CFLAGS=`$GTK_CONFIG $gtk_config_args --cflags` + GTK_LIBS=`$GTK_CONFIG $gtk_config_args --libs` + gtk_config_major_version=`$GTK_CONFIG $gtk_config_args --version | \ + sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\1/'` + gtk_config_minor_version=`$GTK_CONFIG $gtk_config_args --version | \ + sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\2/'` + gtk_config_micro_version=`$GTK_CONFIG $gtk_config_args --version | \ + sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\3/'` + if test "x$enable_gtktest" = "xyes" ; then + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $GTK_CFLAGS" + LIBS="$LIBS $GTK_LIBS" + rm -f conf.gtktest + if test "$cross_compiling" = yes; then + echo $ac_n "cross compiling; assumed OK... $ac_c" +else + cat > conftest.$ac_ext < +#include + +int +main () +{ + int major, minor, micro; + + system ("touch conf.gtktest"); + + if (sscanf("$min_gtk_version", "%d.%d.%d", &major, &minor, µ) != 3) { + printf("%s, bad version string\n", "$min_gtk_version"); + exit(1); + } + + if ((gtk_major_version != $gtk_config_major_version) || + (gtk_minor_version != $gtk_config_minor_version) || + (gtk_micro_version != $gtk_config_micro_version)) + { + printf("\n*** 'gtk-config --version' returned %d.%d.%d, but GTK+ (%d.%d.%d)\n", + $gtk_config_major_version, $gtk_config_minor_version, $gtk_config_micro_version, + gtk_major_version, gtk_minor_version, gtk_micro_version); + printf ("*** was found! If gtk-config was correct, then it is best\n"); + printf ("*** to remove the old version of GTK+. You may also be able to fix the error\n"); + printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n"); + printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n"); + printf("*** required on your system.\n"); + printf("*** If gtk-config was wrong, set the environment variable GTK_CONFIG\n"); + printf("*** to point to the correct copy of gtk-config, and remove the file config.cache\n"); + printf("*** before re-running configure\n"); + } + else + { + if ((gtk_major_version > major) || + ((gtk_major_version == major) && (gtk_minor_version > minor)) || + ((gtk_major_version == major) && (gtk_minor_version == minor) && (gtk_micro_version >= micro))) + { + return 0; + } + else + { + printf("\n*** An old version of GTK+ (%d.%d.%d) was found.\n", + gtk_major_version, gtk_minor_version, gtk_micro_version); + printf("*** You need a version of GTK+ newer than %d.%d.%d. The latest version of\n", + major, minor, micro); + printf("*** GTK+ is always available from ftp://ftp.gtk.org.\n"); + printf("***\n"); + printf("*** If you have already installed a sufficiently new version, this error\n"); + printf("*** probably means that the wrong copy of the gtk-config shell script is\n"); + printf("*** being found. The easiest way to fix this is to remove the old version\n"); + printf("*** of GTK+, but you can also set the GTK_CONFIG environment to point to the\n"); + printf("*** correct copy of gtk-config. (In this case, you will have to\n"); + printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); + printf("*** so that the correct libraries are found at run-time))\n"); + } + } + return 1; +} + +EOF +if { (eval echo configure:1117: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + no_gtk=yes +fi +rm -fr conftest* +fi + + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + if test "x$no_gtk" = x ; then + echo "$ac_t""yes" 1>&6 + CFLAGS="$CFLAGS $GTK_CFLAGS" LIBS="$LIBS $GTK_LIBS" + else + echo "$ac_t""no" 1>&6 + if test "$GTK_CONFIG" = "no" ; then + echo "*** The gtk-config script installed by GTK could not be found" + echo "*** If GTK was installed in PREFIX, make sure PREFIX/bin is in" + echo "*** your path, or set the GTK_CONFIG environment variable to the" + echo "*** full path to gtk-config." + else + if test -f conf.gtktest ; then + : + else + echo "*** Could not run GTK test program, checking why..." + CFLAGS="$CFLAGS $GTK_CFLAGS" + LIBS="$LIBS $GTK_LIBS" + cat > conftest.$ac_ext < +#include + +int main() { + return ((gtk_major_version) || (gtk_minor_version) || (gtk_micro_version)); +; return 0; } +EOF +if { (eval echo configure:1161: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding GTK or finding the wrong" + echo "*** version of GTK. If it is not finding GTK, you'll need to set your" + echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" + echo "*** to the installed location Also, make sure you have run ldconfig if that" + echo "*** is required on your system" + echo "***" + echo "*** If you have an old version installed, it is best to remove it, although" + echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" + echo "***" + echo "*** If you have a RedHat 5.0 system, you should remove the GTK package that" + echo "*** came with the system with the command" + echo "***" + echo "*** rpm --erase --nodeps gtk gtk-devel" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + echo "*** The test program failed to compile or link. See the file config.log for the" + echo "*** exact error that occured. This usually means GTK was incorrectly installed" + echo "*** or that you have moved GTK since it was installed. In the latter case, you" + echo "*** may want to edit the gtk-config script: $GTK_CONFIG" +fi +rm -f conftest* + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + GTK_CFLAGS="" + GTK_LIBS="" + { echo "configure: error: GTK+ distribution not found." 1>&2; exit 1; } + fi + + + rm -f conf.gtktest + + +# Pcap checks +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:1202: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1223: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext < +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1240: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +ac_safe=`echo "pcap.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for pcap.h""... $ac_c" 1>&6 +echo "configure:1264: checking for pcap.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1274: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +{ echo "configure: error: Header file pcap.h not found." 1>&2; exit 1; } +fi + +ac_safe=`echo "net/bpf.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for net/bpf.h""... $ac_c" 1>&6 +echo "configure:1298: checking for net/bpf.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1308: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +{ echo "configure: error: Header file net/bpf.h not found." 1>&2; exit 1; } +fi + +echo $ac_n "checking for pcap_open_offline in -lpcap""... $ac_c" 1>&6 +echo "configure:1331: checking for pcap_open_offline in -lpcap" >&5 +ac_lib_var=`echo pcap'_'pcap_open_offline | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lpcap $LIBS" +cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo pcap | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <&6 +{ echo "configure: error: Library libpcap not found." 1>&2; exit 1; } +fi + + +# AC_HEADER_STDC +# AC_CHECK_HEADERS(fcntl.h strings.h sys/ioctl.h sys/time.h unistd.h) + +for ac_hdr in sys/sockio.h sys/types.h netinet/in.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:1386: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1396: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <&6 +fi +done + + +# AC_C_CONST + +# We need libpcap's AC_LBL_SOCKADDR_SA_LEN test for get_interface_list(). + +echo $ac_n "checking if sockaddr struct has sa_len member""... $ac_c" 1>&6 +echo "configure:1428: checking if sockaddr struct has sa_len member" >&5 + if eval "test \"`echo '$''{'ac_cv_lbl_sockaddr_has_sa_len'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +# include +int main() { +u_int i = sizeof(((struct sockaddr *)0)->sa_len) +; return 0; } +EOF +if { (eval echo configure:1442: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_lbl_sockaddr_has_sa_len=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_lbl_sockaddr_has_sa_len=no +fi +rm -f conftest* +fi + + echo "$ac_t""$ac_cv_lbl_sockaddr_has_sa_len" 1>&6 + if test $ac_cv_lbl_sockaddr_has_sa_len = yes ; then + cat >> confdefs.h <<\EOF +#define HAVE_SOCKADDR_SA_LEN 1 +EOF + + fi + +# We must know our byte order +echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6 +echo "configure:1464: checking whether byte ordering is bigendian" >&5 +if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_cv_c_bigendian=unknown +# See if sys/param.h defines the BYTE_ORDER macro. +cat > conftest.$ac_ext < +#include +int main() { + +#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN + bogus endian macros +#endif +; return 0; } +EOF +if { (eval echo configure:1482: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + # It does; now see whether it defined to BIG_ENDIAN or not. +cat > conftest.$ac_ext < +#include +int main() { + +#if BYTE_ORDER != BIG_ENDIAN + not big endian +#endif +; return 0; } +EOF +if { (eval echo configure:1497: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_bigendian=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_c_bigendian=no +fi +rm -f conftest* +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* +if test $ac_cv_c_bigendian = unknown; then +if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null +then + ac_cv_c_bigendian=no +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_c_bigendian=yes +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_c_bigendian" 1>&6 +if test $ac_cv_c_bigendian = yes; then + cat >> confdefs.h <<\EOF +#define WORDS_BIGENDIAN 1 +EOF + +fi + + +if test $ac_cv_prog_gcc = yes; then + echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6 +echo "configure:1556: checking whether ${CC-cc} needs -traditional" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_pattern="Autoconf.*'x'" + cat > conftest.$ac_ext < +Autoconf TIOCGETP +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "$ac_pattern" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_prog_gcc_traditional=yes +else + rm -rf conftest* + ac_cv_prog_gcc_traditional=no +fi +rm -f conftest* + + + if test $ac_cv_prog_gcc_traditional = no; then + cat > conftest.$ac_ext < +Autoconf TCGETA +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "$ac_pattern" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_prog_gcc_traditional=yes +fi +rm -f conftest* + + fi +fi + +echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6 + if test $ac_cv_prog_gcc_traditional = yes; then + CC="$CC -traditional" + fi +fi + +echo $ac_n "checking for socket""... $ac_c" 1>&6 +echo "configure:1602: checking for socket" >&5 +if eval "test \"`echo '$''{'ac_cv_func_socket'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char socket(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_socket) || defined (__stub___socket) +choke me +#else +socket(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1630: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_func_socket=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_socket=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'socket`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +{ echo "configure: error: Function 'socket' not found." 1>&2; exit 1; } +fi + +# If there's a system out there that has snprintf and _doesn't_ have vsnprintf, +# then this won't work. +echo $ac_n "checking for snprintf""... $ac_c" 1>&6 +echo "configure:1653: checking for snprintf" >&5 +if eval "test \"`echo '$''{'ac_cv_func_snprintf'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext < +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char snprintf(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_snprintf) || defined (__stub___snprintf) +choke me +#else +snprintf(); +#endif + +; return 0; } +EOF +if { (eval echo configure:1681: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then + rm -rf conftest* + eval "ac_cv_func_snprintf=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_snprintf=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'snprintf`\" = yes"; then + echo "$ac_t""yes" 1>&6 + SNPRINTF_C="" SNPRINTF_O="" +else + echo "$ac_t""no" 1>&6 +SNPRINTF_C="snprintf.c" SNPRINTF_O="snprintf.o" +fi + + + + + + + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +DEFS=-DHAVE_CONFIG_H + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS </dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.12" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir +ac_given_INSTALL="$INSTALL" + +trap 'rm -fr `echo "Makefile config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS < conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g +s%@PACKAGE@%$PACKAGE%g +s%@VERSION@%$VERSION%g +s%@ACLOCAL@%$ACLOCAL%g +s%@AUTOCONF@%$AUTOCONF%g +s%@AUTOMAKE@%$AUTOMAKE%g +s%@AUTOHEADER@%$AUTOHEADER%g +s%@MAKEINFO@%$MAKEINFO%g +s%@SET_MAKE@%$SET_MAKE%g +s%@CC@%$CC%g +s%@GTK_CONFIG@%$GTK_CONFIG%g +s%@GTK_CFLAGS@%$GTK_CFLAGS%g +s%@GTK_LIBS@%$GTK_LIBS%g +s%@CPP@%$CPP%g +s%@SNPRINTF_C@%$SNPRINTF_C%g +s%@SNPRINTF_O@%$SNPRINTF_O%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +s%@INSTALL@%$INSTALL%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='$%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' + +if test "${CONFIG_HEADERS+set}" != set; then +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +fi +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + cat $ac_file_inputs > conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. And first: +# Protect against being on the right side of a sed subst in config.status. +# Protect against being in an unquoted here document in config.status. +rm -f conftest.vals +cat > conftest.hdr <<\EOF +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >> conftest.vals <<\EOF +s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% +EOF + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + fi + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + +EOF +cat >> $CONFIG_STATUS <> $CONFIG_STATUS <<\EOF +test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h + +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + diff --git a/configure.in b/configure.in new file mode 100644 index 0000000000..266ba4cd89 --- /dev/null +++ b/configure.in @@ -0,0 +1,51 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(etypes.h) + +AM_INIT_AUTOMAKE(ethereal, 0.3.15) + +dnl Checks for programs. +AC_PROG_CC + +# If LD_LIBRARY_PATH is defined, add it as a link directory. +# This should help Solaris users. +if test x$LD_LIBRARY_PATH != x ; then + LIBS="$LIBS -R$LD_LIBRARY_PATH" +fi + +# GTK checks +AM_PATH_GTK(1.0.0, CFLAGS="$CFLAGS $GTK_CFLAGS" LIBS="$LIBS $GTK_LIBS", + AC_MSG_ERROR(GTK+ distribution not found.)) + +# Pcap checks +AC_CHECK_HEADER(pcap.h,, AC_MSG_ERROR(Header file pcap.h not found.)) +AC_CHECK_HEADER(net/bpf.h,, AC_MSG_ERROR(Header file net/bpf.h not found.)) +AC_CHECK_LIB(pcap, pcap_open_offline,, AC_MSG_ERROR(Library libpcap not found.)) + +dnl Checks for header files. +# AC_HEADER_STDC +# AC_CHECK_HEADERS(fcntl.h strings.h sys/ioctl.h sys/time.h unistd.h) + +AC_CHECK_HEADERS(sys/sockio.h sys/types.h netinet/in.h) + +dnl Checks for typedefs, structures, and compiler characteristics. +# AC_C_CONST + +# We need libpcap's AC_LBL_SOCKADDR_SA_LEN test for get_interface_list(). + +AC_LBL_SOCKADDR_SA_LEN + +# We must know our byte order +AC_C_BIGENDIAN + +dnl Checks for library functions. +AC_PROG_GCC_TRADITIONAL +AC_CHECK_FUNC(socket,, AC_MSG_ERROR(Function 'socket' not found.)) +# If there's a system out there that has snprintf and _doesn't_ have vsnprintf, +# then this won't work. +AC_CHECK_FUNC(snprintf, SNPRINTF_C="" SNPRINTF_O="", + SNPRINTF_C="snprintf.c" SNPRINTF_O="snprintf.o") +AC_SUBST(SNPRINTF_C) +AC_SUBST(SNPRINTF_O) + +AM_CONFIG_HEADER(config.h) +AC_OUTPUT(Makefile) diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000000..6105c9ca05 --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,5 @@ +../ethereal.1: ethereal.pod + pod2man ethereal.pod \ + --center="The Ethereal Network Analyzer" \ + --release=`cat ../VERSION` \ + > ../ethereal.1 diff --git a/doc/ethereal.pod b/doc/ethereal.pod new file mode 100644 index 0000000000..f987e7103a --- /dev/null +++ b/doc/ethereal.pod @@ -0,0 +1,233 @@ + +=head1 NAME + +Ethereal - Interactively browse network traffic + +=head1 SYNOPSYS + +B +S<[ B<-v> ]> +S<[ B<-B> byte view height ]> +S<[ B<-c> count ]> +S<[ B<-i> interface ]> +S<[ B<-P> packet list height ]> +S<[ B<-r> infile ]> +S<[ B<-s> snaplen ]> +S<[ B<-T> tree view height ]> +S<[ B<-w> savefile]> + +=head1 DESCRIPTION + +B is a network protocol analyzer based on the B GUI toolkit. It lets +you interactively browse packet data from a live network or from a B +/ B formatted capture file. + +=head1 OPTIONS + +=over 4 + +=item -B + +Sets the initial height of the byte view (bottom) pane + +=item -c + +The default number of packets to read when capturing live data. + +=item -i + +The name of the interface to use for live packet capture. It should match +one of the names listed in "B" or "B". + +=item -P + +Sets the initial height of the packet list (top) pane + +=item -r + +Read packet data from I. Currently, B only understands +B / B formatted files. + +=item -s + +The default snapshot length to use when capturing live data. No more than +I bytes of each network packet will be read into memory, or saved +to disk. + +=item -T + +Sets the initial height of the tree view (top) pane + +=item -v + +Prints the version and exits. + +=item -w + +Sets the default capture file name. + +=back + +=head1 INTERFACE + +=head2 MENU ITEMS + +=over 4 + +=item File:Open, File:Close + +Open or close a capture file. + +=item File:Print Packet + +Print a description of each protocol header found in the packet, followed +by the packet data itself. Printing options can be set with the +I menu item. + +=item File:Quit + +Exits the application. + +=item Edit:Printer Options + +Sets the packet printing options (see L<"Printer Options"> below). + +=item Tools:Capture + +Initiates a live packet capture (see L<"Capture Preferences"> below). + +=item Tools:Filter + +Sets the filter preferences (see L<"Filters"> below). + +=back + +=head2 WINDOWS + +=over 4 + +=item Main Window + +The main window is split into three sections. You can resize each section +using a "thumb" at the right end of each divider line. An informational +message is also displayed at the bottom of the main window. + +The top section contains the list of network packets that you can scroll +through and select. The packet number, source and destination addresses, +protocol, and description are printed for each packet. An effort is made +to display information as high up the protocol stack as possible, e.g. IP +addresses are displayed for IP packets, but the MAC layer address is +displayed for unknown packet types. + +The middle section contains a I for the currently-selected +packet. The tree displays each field and its value in each protocol header +in the stack. + +The bottom section contains a hex dump of the actual packet data. +Selecting a field in the I highlights the appropriate bytes +in this section. + +=item Printer Options + +The I dialog lets you select the output format of packets +printed using the I menu item. + +The radio buttons at the top of the dialog allow you choose between +printing the packets as text or PostScript, and sending the output +directly to a command or saving it to a file. The I text entry +box is the command to send files to (usually B), and the I +entry box lets you enter the name of the file you wish to save to. +Additinally, you can select the I button to browse the file system +for a particular save file. + +=item Capture Preferences + +The I dialog lets you specify various parameters for +capturing live packet data. + +The I entry box lets you specify the interface from which to +capture packet data. The I entry specifies the number of packets +to capture. Entering 0 will capture packets indefinitely. The I +entry specifies the file to save to, as in the I dialog +above. You can choose to open the file after capture, and you can also +specify the maximum number of bytes to capture per packet with the +I entry. + +=item Filters + +The I dialog lets you create and modify filters, and set the +default filter to use when capturing data or opening a capture file. + +The I entry specifies a descriptive name for a filter, e.g. +B. The I entry is the text that +actually describes the filtering action to take. It must have the same +format as B filter strings, since both programs use the same +underlying library. A filter for HTTP, HTTPS, and DNS traffic might look +like this: + + tcp port 80 or tcp port 443 or port 53 + +The dialog buttons perform the following actions: + +=over 8 + +=item New + +If there is text in the two entry boxes, it creates a new associated list +item. + +=item Change + +Modifies the currently selected list item to match what's in the entry +boxes. + +=item Copy + +Makes a copy of the currently selected list item. + +=item Delete + +Deletes the currently selected list item. + +=item OK + +Sets the currently selected list item as the active filter. If nothing +is selected, turns filtering off. + +=item Save + +Saves the current filter list in F<$HOME/.ethereal/filters>. + +=item Cancel + +Closes the dialog without making any changes. + +=head1 SEE ALSO + +L, L + +=head1 NOTES + +The latest version of B can be found at +B. + +=head1 AUTHORS + + Original Author + -------- ------ + Gerald Combs + + + Contributors + ------------ + Gilbert Ramirez Jr. + Hannes R. Boehm + Mike Hall + cpg + + +Theo de Raadt was kind enough to give his +permission to use his version of snprintf.c. + +Dan Lasley gave permission for his dumpit() hex-dump +routine to be used. diff --git a/ethereal.1 b/ethereal.1 new file mode 100644 index 0000000000..9381c89c5b --- /dev/null +++ b/ethereal.1 @@ -0,0 +1,427 @@ +.rn '' }` +''' $RCSfile: ethereal.1,v $$Revision: 1.1 $$Date: 1998/09/16 02:39:18 $ +''' +''' $Log: ethereal.1,v $ +''' Revision 1.1 1998/09/16 02:39:18 gerald +''' Initial revision +''' +''' Revision 1.1.1.1 1998/08/30 17:53:24 gerald +''' Imported sources +''' +''' +.de Sh +.br +.if t .Sp +.ne 5 +.PP +\fB\\$1\fR +.PP +.. +.de Sp +.if t .sp .5v +.if n .sp +.. +.de Ip +.br +.ie \\n(.$>=3 .ne \\$3 +.el .ne 3 +.IP "\\$1" \\$2 +.. +.de Vb +.ft CW +.nf +.ne \\$1 +.. +.de Ve +.ft R + +.fi +.. +''' +''' +''' Set up \*(-- to give an unbreakable dash; +''' string Tr holds user defined translation string. +''' Bell System Logo is used as a dummy character. +''' +.tr \(*W-|\(bv\*(Tr +.ie n \{\ +.ds -- \(*W- +.ds PI pi +.if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +.if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +.ds L" "" +.ds R" "" +''' \*(M", \*(S", \*(N" and \*(T" are the equivalent of +''' \*(L" and \*(R", except that they are used on ".xx" lines, +''' such as .IP and .SH, which do another additional levels of +''' double-quote interpretation +.ds M" """ +.ds S" """ +.ds N" """"" +.ds T" """"" +.ds L' ' +.ds R' ' +.ds M' ' +.ds S' ' +.ds N' ' +.ds T' ' +'br\} +.el\{\ +.ds -- \(em\| +.tr \*(Tr +.ds L" `` +.ds R" '' +.ds M" `` +.ds S" '' +.ds N" `` +.ds T" '' +.ds L' ` +.ds R' ' +.ds M' ` +.ds S' ' +.ds N' ` +.ds T' ' +.ds PI \(*p +'br\} +.\" If the F register is turned on, we'll generate +.\" index entries out stderr for the following things: +.\" TH Title +.\" SH Header +.\" Sh Subsection +.\" Ip Item +.\" X<> Xref (embedded +.\" Of course, you have to process the output yourself +.\" in some meaninful fashion. +.if \nF \{ +.de IX +.tm Index:\\$1\t\\n%\t"\\$2" +.. +.nr % 0 +.rr F +.\} +.TH ETHEREAL 1 "0.3.8" "24/Aug/98" "The Ethereal Network Analyzer" +.UC +.if n .hy 0 +.if n .na +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.de CQ \" put $1 in typewriter font +.ft CW +'if n "\c +'if t \\&\\$1\c +'if n \\&\\$1\c +'if n \&" +\\&\\$2 \\$3 \\$4 \\$5 \\$6 \\$7 +'.ft R +.. +.\" @(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2 +. \" AM - accent mark definitions +.bd B 3 +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds ? ? +. ds ! ! +. ds / +. ds q +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds ? \s-2c\h'-\w'c'u*7/10'\u\h'\*(#H'\zi\d\s+2\h'\w'c'u*8/10' +. ds ! \s-2\(or\s+2\h'-\w'\(or'u'\v'-.8m'.\v'.8m' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +. ds q o\h'-\w'o'u*8/10'\s-4\v'.4m'\z\(*i\v'-.4m'\s+4\h'\w'o'u*8/10' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds v \\k:\h'-(\\n(.wu*9/10-\*(#H)'\v'-\*(#V'\*(#[\s-4v\s0\v'\*(#V'\h'|\\n:u'\*(#] +.ds _ \\k:\h'-(\\n(.wu*9/10-\*(#H+(\*(#F*2/3))'\v'-.4m'\z\(hy\v'.4m'\h'|\\n:u' +.ds . \\k:\h'-(\\n(.wu*8/10)'\v'\*(#V*4/10'\z.\v'-\*(#V*4/10'\h'|\\n:u' +.ds 3 \*(#[\v'.2m'\s-2\&3\s0\v'-.2m'\*(#] +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +.ds oe o\h'-(\w'o'u*4/10)'e +.ds Oe O\h'-(\w'O'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds v \h'-1'\o'\(aa\(ga' +. ds _ \h'-1'^ +. ds . \h'-1'. +. ds 3 3 +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +. ds oe oe +. ds Oe OE +.\} +.rm #[ #] #H #V #F C +.SH "NAME" +Ethereal \- Interactively browse network traffic +.SH "SYNOPSYS" +\fBethereal\fR +[\ \fB\-v\fR\ ] +[\ \fB\-B\fR\ byte\ view\ height\ ] +[\ \fB\-c\fR\ count\ ] +[\ \fB\-i\fR\ interface\ ] +[\ \fB\-P\fR\ packet\ list\ height\ ] +[\ \fB\-r\fR\ infile\ ] +[\ \fB\-s\fR\ snaplen\ ] +[\ \fB\-T\fR\ tree\ view\ height\ ] +[\ \fB\-w\fR\ savefile] +.SH "DESCRIPTION" +\fBEthereal\fR is a network protocol analyzer based on the \fBGTK+\fR GUI toolkit. It lets +you interactively browse packet data from a live network or from a \fBpcap\fR +/ \fBtcpdump()\fR formatted capture file. +.SH "OPTIONS" +.Ip "-B" 4 +Sets the initial height of the byte view (bottom) pane +.Ip "-c" 4 +The default number of packets to read when capturing live data. +.Ip "-i" 4 +The name of the interface to use for live packet capture. It should match +one of the names listed in \*(L"\fBnetstat \-i\fR\*(R" or \*(L"\fBifconfig \-a\fR\*(R". +.Ip "-P" 4 +Sets the initial height of the packet list (top) pane +.Ip "-r" 4 +Read packet data from \fIfile\fR. Currently, \fBEthereal\fR only understands +\fBpcap\fR / \fBtcpdump\fR formatted files. +.Ip "-s" 4 +The default snapshot length to use when capturing live data. No more than +\fIsnaplen\fR bytes of each network packet will be read into memory, or saved +to disk. +.Ip "-T" 4 +Sets the initial height of the tree view (top) pane +.Ip "-v" 4 +Prints the version and exits. +.Ip "-w" 4 +Sets the default capture file name. +.SH "INTERFACE" +.Sh "\s-1MENU\s0 \s-1ITEMS\s0" +.Ip "File:Open, File:Close" 4 +Open or close a capture file. +.Ip "File:Print Packet" 4 +Print a description of each protocol header found in the packet, followed +by the packet data itself. Printing options can be set with the +\fIEdit:Menu Options\fR menu item. +.Ip "File:Quit" 4 +Exits the application. +.Ip "Edit:Printer Options" 4 +Sets the packet printing options (see the section on \fIPrinter Options\fR below). +.Ip "Tools:Capture" 4 +Initiates a live packet capture (see the section on \fICapture Preferences\fR below). +.Ip "Tools:Filter" 4 +Sets the filter preferences (see the section on \fIFilters\fR below). +.Sh "\s-1WINDOWS\s0" +.Ip "Main Window" 4 +The main window is split into three sections. You can resize each section +using a \*(L"thumb\*(R" at the right end of each divider line. An informational +message is also displayed at the bottom of the main window. +.Sp +The top section contains the list of network packets that you can scroll +through and select. The packet number, source and destination addresses, +protocol, and description are printed for each packet. An effort is made +to display information as high up the protocol stack as possible, e.g. \s-1IP\s0 +addresses are displayed for \s-1IP\s0 packets, but the \s-1MAC\s0 layer address is +displayed for unknown packet types. +.Sp +The middle section contains a \fIprotocol tree\fR for the currently-selected +packet. The tree displays each field and its value in each protocol header +in the stack. +.Sp +The bottom section contains a hex dump of the actual packet data. +Selecting a field in the \fIprotocol tree\fR highlights the appropriate bytes +in this section. +.Ip "Printer Options" 4 +The \fIPrinter Options\fR dialog lets you select the output format of packets +printed using the \fIFile:Print Packet\fR menu item. +.Sp +The radio buttons at the top of the dialog allow you choose between +printing the packets as text or PostScript, and sending the output +directly to a command or saving it to a file. The \fICommand:\fR text entry +box is the command to send files to (usually \fBlpr\fR), and the \fIFile:\fR +entry box lets you enter the name of the file you wish to save to. +Additinally, you can select the \fIFile:\fR button to browse the file system +for a particular save file. +.Ip "Capture Preferences" 4 +The \fICapture Preferences\fR dialog lets you specify various parameters for +capturing live packet data. +.Sp +The \fIInterface:\fR entry box lets you specify the interface from which to +capture packet data. The \fICount:\fR entry specifies the number of packets +to capture. Entering 0 will capture packets indefinitely. The \fIFile:\fR +entry specifies the file to save to, as in the \fIPrinter Options\fR dialog +above. You can choose to open the file after capture, and you can also +specify the maximum number of bytes to capture per packet with the +\fICapture length\fR entry. +.Ip "Filters" 4 +The \fIFilters\fR dialog lets you create and modify filters, and set the +default filter to use when capturing data or opening a capture file. +.Sp +The \fIFilter name\fR entry specifies a descriptive name for a filter, e.g. +\fBWeb and \s-1DNS\s0 traffic\fR. The \fIFilter string\fR entry is the text that +actually describes the filtering action to take. It must have the same +format as \fBtcpdump\fR filter strings, since both programs use the same +underlying library. A filter for \s-1HTTP\s0, \s-1HTTPS\s0, and \s-1DNS\s0 traffic might look +like this: +.Sp +.Vb 1 +\& tcp port 80 or tcp port 443 or port 53 +.Ve +The dialog buttons perform the following actions: +.Ip "New" 12 +If there is text in the two entry boxes, it creates a new associated list +item. +.Ip "Change" 12 +Modifies the currently selected list item to match what's in the entry +boxes. +.Ip "Copy" 12 +Makes a copy of the currently selected list item. +.Ip "Delete" 12 +Deletes the currently selected list item. +.Ip "\s-1OK\s0" 12 +Sets the currently selected list item as the active filter. If nothing +is selected, turns filtering off. +.Ip "Save" 12 +Saves the current filter list in \fI$\s-1HOME\s0/.ethereal/filters\fR. +.Ip "Cancel" 12 +Closes the dialog without making any changes. +.SH "SEE ALSO" +the \fItcpdump(1)\fR manpage, the \fIpcap(3)\fR manpage +.SH "NOTES" +The latest version of \fBethereal\fR can be found at +\fBhttp://ethereal.zing.org\fR. +.SH "AUTHORS" +.Sp +.Vb 3 +\& Original Author +\& -------- ------ +\& Gerald Combs +.Ve +.Vb 6 +\& Contributors +\& ------------ +\& Gilbert Ramirez Jr. +\& Hannes R. Boehm +\& Mike Hall +\& cpg +.Ve +Theo de Raadt was kind enough to give his +permission to use his version of snprintf.c. +.Sp +Dan Lasley gave permission for his \fIdumpit()\fR hex-dump +routine to be used. + +.rn }` '' +.IX Title "ETHEREAL 1" +.IX Name "Ethereal - Interactively browse network traffic" + +.IX Header "NAME" + +.IX Header "SYNOPSYS" + +.IX Header "DESCRIPTION" + +.IX Header "OPTIONS" + +.IX Item "-B" + +.IX Item "-c" + +.IX Item "-i" + +.IX Item "-P" + +.IX Item "-r" + +.IX Item "-s" + +.IX Item "-T" + +.IX Item "-v" + +.IX Item "-w" + +.IX Header "INTERFACE" + +.IX Subsection "\s-1MENU\s0 \s-1ITEMS\s0" + +.IX Item "File:Open, File:Close" + +.IX Item "File:Print Packet" + +.IX Item "File:Quit" + +.IX Item "Edit:Printer Options" + +.IX Item "Tools:Capture" + +.IX Item "Tools:Filter" + +.IX Subsection "\s-1WINDOWS\s0" + +.IX Item "Main Window" + +.IX Item "Printer Options" + +.IX Item "Capture Preferences" + +.IX Item "Filters" + +.IX Item "New" + +.IX Item "Change" + +.IX Item "Copy" + +.IX Item "Delete" + +.IX Item "\s-1OK\s0" + +.IX Item "Save" + +.IX Item "Cancel" + +.IX Header "SEE ALSO" + +.IX Header "NOTES" + +.IX Header "AUTHORS" + diff --git a/ethereal.c b/ethereal.c new file mode 100644 index 0000000000..5705b8fda5 --- /dev/null +++ b/ethereal.c @@ -0,0 +1,440 @@ +/* ethereal.c + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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. + * + * + * To do: + * - Add time stamps to packet list? + * - Live browser/capture display + * - Graphs + * - Prefs dialog + * - Get AIX to work + * - Fix PPP support. + * - Check for end of packet in dissect_* routines. + * - Playback window + * - Multiple window support + * - Add cut/copy/paste + * - Handle snoop files + * - Fix progress/status bar glitches? (GTK+ bug?) + * - Create header parsing routines + * - Check fopens, freads, fwrites + * - Make byte view scrollbars automatic? + * - Make byte view selections more fancy? + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "packet.h" +#include "file.h" +#include "ethereal.h" +#include "menu.h" +#include "etypes.h" +#include "print.h" +#include "resolv.h" + +capture_file cf; +GtkWidget *file_sel, *packet_list, *tree_view, *byte_view, *prog_bar, + *info_bar; +GdkFont *m_r_font, *m_b_font; +guint main_ctx, file_ctx; +frame_data *fd; +gint start_capture = 0; + +const gchar *list_item_data_key = "list_item_data"; + +extern pr_opts printer_opts; + +/* Things to do when the OK button is pressed */ +void +file_sel_ok_cb(GtkWidget *w, GtkFileSelection *fs) { + gchar *cf_name; + int err; + + cf_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (fs))); + gtk_widget_hide(GTK_WIDGET (fs)); + gtk_widget_destroy(GTK_WIDGET (fs)); + + if ((err = load_cap_file(cf_name, &cf)) == 0) + chdir(cf_name); + g_free(cf_name); +} + +/* Update the progress bar */ +gint +file_progress_cb(gpointer p) { + gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), + (gfloat) ftell(cf.fh) / (gfloat) cf.f_len); + return TRUE; +} + +/* Open a file */ +void +file_open_cmd_cb(GtkWidget *widget, gpointer data) { + file_sel = gtk_file_selection_new ("Ethereal: Open Capture File"); + + /* Connect the ok_button to file_ok_sel_cb function */ + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button), + "clicked", (GtkSignalFunc) file_sel_ok_cb, file_sel ); + + /* Connect the cancel_button to destroy the widget */ + gtk_signal_connect_object(GTK_OBJECT (GTK_FILE_SELECTION + (file_sel)->cancel_button), "clicked", (GtkSignalFunc) + gtk_widget_destroy, GTK_OBJECT (file_sel)); + + gtk_file_selection_set_filename(GTK_FILE_SELECTION(file_sel), ""); + + gtk_widget_show(file_sel); +} + +/* Close a file */ +void +file_close_cmd_cb(GtkWidget *widget, gpointer data) { + close_cap_file(&cf, info_bar, file_ctx); + set_menu_sensitivity("
/File/Close", FALSE); +} + +/* Print a packet */ +void +file_print_cmd_cb(GtkWidget *widget, gpointer data) { + print_tree(cf.pd, fd, GTK_TREE(tree_view)); +} + +/* What to do when a list item is selected/unselected */ +void +packet_list_select_cb(GtkWidget *w, gint row, gint col, gpointer evt) { + GList *l; + + gtk_text_freeze(GTK_TEXT(byte_view)); + gtk_text_set_point(GTK_TEXT(byte_view), 0); + gtk_text_forward_delete(GTK_TEXT(byte_view), + gtk_text_get_length(GTK_TEXT(byte_view))); + l = g_list_nth(cf.plist, row); + if (l) { + fd = (frame_data *) l->data; + fseek(cf.fh, fd->file_off, SEEK_SET); + fread(cf.pd, sizeof(guint8), fd->cap_len, cf.fh); + dissect_packet(cf.pd, fd, GTK_TREE(tree_view)); + packet_hex_print(GTK_TEXT(byte_view), cf.pd, fd->cap_len, -1, -1); + } + gtk_text_thaw(GTK_TEXT(byte_view)); +} + +void +packet_list_unselect_cb(GtkWidget *w, gint row, gint col, gpointer evt) { + gtk_text_freeze(GTK_TEXT(byte_view)); + gtk_text_set_point(GTK_TEXT(byte_view), 0); + gtk_text_forward_delete(GTK_TEXT(byte_view), + gtk_text_get_length(GTK_TEXT(byte_view))); + gtk_text_thaw(GTK_TEXT(byte_view)); + gtk_tree_clear_items(GTK_TREE(tree_view), 0, + g_list_length(GTK_TREE(tree_view)->children)); +} + +void +tree_view_cb(GtkWidget *w) { + gint start = -1, len = -1; + guint32 tinfo = 0; + + if (GTK_TREE(w)->selection) { + tinfo = (guint32) gtk_object_get_user_data(GTK_TREE(w)->selection->data); + start = (tinfo >> 16) & 0xffff; + len = tinfo & 0xffff; + } + + gtk_text_freeze(GTK_TEXT(byte_view)); + gtk_text_set_point(GTK_TEXT(byte_view), 0); + gtk_text_forward_delete(GTK_TEXT(byte_view), + gtk_text_get_length(GTK_TEXT(byte_view))); + packet_hex_print(GTK_TEXT(byte_view), cf.pd, fd->cap_len, start, len); + gtk_text_thaw(GTK_TEXT(byte_view)); +} + +void +file_quit_cmd_cb (GtkWidget *widget, gpointer data) { + gtk_exit(0); +} + +/* Things to do when the OK button is pressed */ +void +main_realize_cb(GtkWidget *w, gpointer data) { + gchar *cf_name = (gchar *) data; + int err; + + if (cf_name) { + err = load_cap_file(cf_name, &cf); + cf_name[0] = '\0'; + } + if (start_capture) { + if (cf.save_file) + capture(1); + else + capture(0); + start_capture = 0; + } +} + +void +print_usage(void) { + + fprintf(stderr, "This is GNU %s %s\n", PACKAGE, VERSION); + fprintf(stderr, "%s [-v] [-b bold font] [-B byte view height] [-c count] [-h]\n", + PACKAGE); + fprintf(stderr, " [-i interface] [-m medium font] [-n] [-P packet list height]\n"); + fprintf(stderr, " [-r infile] [-s snaplen] [-T tree view height]\n"); + fprintf(stderr, " [-w savefile] \n"); +} + +int +main(int argc, char *argv[]) +{ + int opt; + extern char *optarg; + GtkWidget *window, *main_vbox, *menubar, *u_pane, *l_pane, + *bv_table, *bv_hscroll, *bv_vscroll, *stat_hbox, + *tv_scrollw; + GtkStyle *pl_style; + GtkAcceleratorTable *accel; + gint col_width, pl_size = 280, tv_size = 95, bv_size = 75; + gchar *rc_file, *cf_name = NULL; + gchar *cl_title[] = {"No.", "Source", "Destination", + "Protocol", "Info"}; + gchar *medium_font = MONO_MEDIUM_FONT; + gchar *bold_font = MONO_BOLD_FONT; + + /* Initialize the capture file struct */ + cf.plist = NULL; + cf.pfh = NULL; + cf.fh = NULL; + cf.filter = NULL; + cf.iface = NULL; + cf.save_file = NULL; + cf.snap = 68; + cf.count = 0; + + /* Let GTK get its args */ + gtk_init (&argc, &argv); + + /* Now get our args */ + while ((opt = getopt(argc, argv, "b:B:c:hi:m:nP:r:s:T:w:v")) != EOF) { + switch (opt) { + case 'b': /* Bold font */ + bold_font = g_strdup(optarg); + break; + case 'B': /* Byte view pane height */ + bv_size = atoi(optarg); + break; + case 'c': /* Capture xxx packets */ + cf.count = atoi(optarg); + break; + case 'h': /* Print help and exit */ + print_usage(); + exit(0); + break; + case 'i': /* Use interface xxx */ + cf.iface = g_strdup(optarg); + break; + case 'm': /* Medium font */ + medium_font = g_strdup(optarg); + break; + case 'n': /* No name resolution */ + g_resolving_actif = 0; + break; + case 'k': /* Start capture immediately */ + start_capture = 1; + break; + case 'P': /* Packet list pane height */ + pl_size = atoi(optarg); + break; + case 'r': /* Read capture file xxx */ + cf_name = g_strdup(optarg); + break; + case 's': /* Set the snapshot (capture) length */ + cf.snap = atoi(optarg); + break; + case 'T': /* Tree view pane height */ + tv_size = atoi(optarg); + break; + case 'v': /* Show version and exit */ + printf("%s %s\n", PACKAGE, VERSION); + exit(0); + break; + case 'w': /* Write capture file xxx */ + cf.save_file = g_strdup(optarg); + break; + } + } + + if (cf.snap < 1) + cf.snap = 4096; + else if (cf.snap < 68) + cf.snap = 68; + + rc_file = (gchar *) g_malloc(strlen(getenv("HOME")) + strlen(RC_FILE) + 4); + sprintf(rc_file, "%s/%s", getenv("HOME"), RC_FILE); + gtk_rc_parse(rc_file); + + /* initialize printer options. temporary! we should only initialize + * if the options are not set in some ethereal initialization file */ + printer_opts.output_format = 0; + printer_opts.output_dest = 0; + printer_opts.file = g_strdup("ethereal.out"); + printer_opts.cmd = g_strdup("lpr"); + + if ((m_r_font = gdk_font_load(medium_font)) == NULL) { + fprintf(stderr, "Error font %s not found (use -m option)\n", medium_font); + exit(1); + } + + if ((m_b_font = gdk_font_load(bold_font)) == NULL) { + fprintf(stderr, "Error font %s not found (use -b option)\n", bold_font); + exit(1); + } + + /* Main window */ + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_widget_set_name(window, "main window"); + gtk_signal_connect(GTK_OBJECT(window), "delete_event", + GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy"); + gtk_signal_connect(GTK_OBJECT(window), "destroy", + GTK_SIGNAL_FUNC(file_quit_cmd_cb), "WM destroy"); + gtk_signal_connect(GTK_OBJECT (window), "realize", + GTK_SIGNAL_FUNC(main_realize_cb), cf_name); + gtk_window_set_title(GTK_WINDOW(window), "The Ethereal Network Analyzer"); + gtk_widget_set_usize(GTK_WIDGET(window), DEF_WIDTH, -1); + + /* Container for menu bar, paned windows and progress/info box */ + main_vbox = gtk_vbox_new(FALSE, 1); + gtk_container_border_width(GTK_CONTAINER(main_vbox), 1); + gtk_container_add(GTK_CONTAINER(window), main_vbox); + gtk_widget_show(main_vbox); + + /* Menu bar */ + get_main_menu(&menubar, &accel); + gtk_window_add_accelerator_table(GTK_WINDOW(window), accel); + gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0); + gtk_widget_show(menubar); + + /* Panes for the packet list, tree, and byte view */ + u_pane = gtk_vpaned_new(); + l_pane = gtk_vpaned_new(); + gtk_container_add(GTK_CONTAINER(main_vbox), u_pane); + gtk_widget_show(u_pane); + gtk_paned_add2 (GTK_PANED(u_pane), l_pane); + gtk_widget_show(l_pane); + + /* Packet list */ + packet_list = gtk_clist_new_with_titles(5, cl_title); + pl_style = gtk_style_new(); + gdk_font_unref(pl_style->font); + pl_style->font = m_r_font; + gtk_widget_set_style(packet_list, pl_style); + gtk_widget_set_name(packet_list, "packet list"); + gtk_signal_connect(GTK_OBJECT(packet_list), "select_row", + GTK_SIGNAL_FUNC(packet_list_select_cb), NULL); + gtk_signal_connect(GTK_OBJECT(packet_list), "unselect_row", + GTK_SIGNAL_FUNC(packet_list_unselect_cb), NULL); + gtk_clist_set_column_justification(GTK_CLIST(packet_list), 0, + GTK_JUSTIFY_RIGHT); + col_width = (gdk_string_width(pl_style->font, "0") * 7) + 2; + gtk_clist_set_column_width(GTK_CLIST(packet_list), 0, col_width); + col_width = gdk_string_width(pl_style->font, "00:00:00:00:00:00") + 2; + gtk_clist_set_column_width(GTK_CLIST(packet_list), 1, col_width); + gtk_clist_set_column_width(GTK_CLIST(packet_list), 2, col_width); + col_width = gdk_string_width(pl_style->font, "AppleTalk") + 2; + gtk_clist_set_column_width(GTK_CLIST(packet_list), 3, col_width); + gtk_widget_set_usize(packet_list, -1, pl_size); + gtk_paned_add1(GTK_PANED(u_pane), packet_list); + gtk_widget_show(packet_list); + + /* Tree view */ + tv_scrollw = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(tv_scrollw), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_paned_add1(GTK_PANED(l_pane), tv_scrollw); + gtk_widget_set_usize(tv_scrollw, -1, tv_size); + gtk_widget_show(tv_scrollw); + + tree_view = gtk_tree_new(); + gtk_container_add(GTK_CONTAINER(tv_scrollw), tree_view); + gtk_tree_set_selection_mode(GTK_TREE(tree_view), GTK_SELECTION_SINGLE); + gtk_tree_set_view_lines(GTK_TREE(tree_view), FALSE); + gtk_tree_set_view_mode(GTK_TREE(tree_view), TRUE); + gtk_signal_connect(GTK_OBJECT(tree_view), "selection_changed", + GTK_SIGNAL_FUNC(tree_view_cb), NULL); + gtk_widget_show(tree_view); + + /* Byte view */ + bv_table = gtk_table_new (2, 2, FALSE); + gtk_paned_add2(GTK_PANED(l_pane), bv_table); + gtk_widget_set_usize(bv_table, -1, bv_size); + gtk_widget_show(bv_table); + + byte_view = gtk_text_new(NULL, NULL); + gtk_text_set_editable(GTK_TEXT(byte_view), FALSE); + gtk_text_set_word_wrap(GTK_TEXT(byte_view), FALSE); + gtk_table_attach (GTK_TABLE (bv_table), byte_view, 0, 1, 0, 1, + GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0); + gtk_widget_show(byte_view); + + bv_hscroll = gtk_hscrollbar_new(GTK_TEXT(byte_view)->hadj); + gtk_table_attach(GTK_TABLE(bv_table), bv_hscroll, 0, 1, 1, 2, + GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); + gtk_widget_show (bv_hscroll); + + bv_vscroll = gtk_vscrollbar_new(GTK_TEXT(byte_view)->vadj); + gtk_table_attach(GTK_TABLE(bv_table), bv_vscroll, 1, 2, 0, 1, + GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0); + gtk_widget_show(bv_vscroll); + + /* Progress/info box */ + stat_hbox = gtk_hbox_new(FALSE, 1); + gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0); + gtk_box_pack_start(GTK_BOX(main_vbox), stat_hbox, FALSE, TRUE, 0); + gtk_widget_show(stat_hbox); + + prog_bar = gtk_progress_bar_new(); + gtk_box_pack_start(GTK_BOX(stat_hbox), prog_bar, FALSE, TRUE, 0); + gtk_widget_show(prog_bar); + + info_bar = gtk_statusbar_new(); + main_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "main"); + file_ctx = gtk_statusbar_get_context_id(GTK_STATUSBAR(info_bar), "file"); + gtk_statusbar_push(GTK_STATUSBAR(info_bar), main_ctx, DEF_READY_MESSAGE); + gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0); + gtk_widget_show(info_bar); + + gtk_widget_show(window); + gtk_main(); + + exit(0); +} diff --git a/ethereal.h b/ethereal.h new file mode 100644 index 0000000000..067f079a55 --- /dev/null +++ b/ethereal.h @@ -0,0 +1,79 @@ +/* ethereal.h + * Global defines, etc. + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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 __ETHEREAL_H__ +#define __ETHEREAL_H__ + +#include "config.h" + +#define RC_FILE ".etherealrc" +#define MONO_MEDIUM_FONT "-*-lucidatypewriter-medium-r-normal-*-*-120-*-*-*-*-iso8859-1" +#define MONO_BOLD_FONT "-*-lucidatypewriter-bold-r-normal-*-*-120-*-*-*-*-iso8859-1" +#define DEF_WIDTH 750 +#define DEF_HEIGHT 550 +#define DEF_READY_MESSAGE " Ready to load or capture" + +/* Byte swapping routines */ +#define SWAP16(x) \ + ( (((x) & 0x00ff) << 8) | \ + (((x) & 0xff00) >> 8) ) +#define SWAP32(x) \ + ( (((x) & 0x000000ff) << 24) | \ + (((x) & 0x0000ff00) << 8) | \ + (((x) & 0x00ff0000) >> 8) | \ + (((x) & 0xff000000) >> 24) ) + +/* Byte ordering */ +#ifndef BYTE_ORDER + #define LITTLE_ENDIAN 1234 + #define BIG_ENDIAN 1234 + #ifdef WORDS_BIGENDIAN + #define BYTE_ORDER BIG_ENDIAN + #else + #define BYTE_ORDER LITTLE_ENDIAN + #endif +#endif + +/* From the K&R book, p. 89 */ +#ifndef MAX + #define MAX(x, y) ((x) > (y) ? (x) : (y)) +#endif + +#ifndef MIN + #define MIN(x, y) ((x) < (y) ? (x) : (y)) +#endif + +typedef struct _selection_info { + GtkWidget *tree; + GtkWidget *text; +} selection_info; + +void file_sel_ok_cb(GtkWidget *, GtkFileSelection *); +gint file_progress_cb(gpointer); +void file_open_cmd_cb(GtkWidget *, gpointer); +void file_close_cmd_cb(GtkWidget *, gpointer); +void file_quit_cmd_cb(GtkWidget *, gpointer); +void file_print_cmd_cb(GtkWidget *, gpointer); +void main_realize_cb(GtkWidget *, gpointer); + +#endif /* ethereal.h */ diff --git a/ethertype.c b/ethertype.c new file mode 100644 index 0000000000..55fe9bebbb --- /dev/null +++ b/ethertype.c @@ -0,0 +1,107 @@ +/* ethertype.c + * Routines for calling the right protocol for the ethertype. + * This is called by both packet-eth.c (Ethernet II) and packet-llc.c (SNAP) + * + * Gilbert Ramirez + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include + +#include + +#include "packet.h" +#include "ethereal.h" +#include "etypes.h" + +void +ethertype(guint16 etype, int offset, + const u_char *pd, frame_data *fd, GtkTree *tree, GtkWidget + *fh_tree) +{ + gchar etype_str[][10] = {"IP", "ARP", "RARP", "AppleTalk", "AARP"}; + + switch (etype) { + case ETHERTYPE_IP: + if (tree) { + add_item_to_tree(fh_tree, offset - 2, 2, "Type: IP (0x%04x)", + etype); + } + dissect_ip(pd, offset, fd, tree); + break; + case ETHERTYPE_IPv6: + if (tree) { + add_item_to_tree(fh_tree, offset - 2, 2, "Type: IPv6 (0x%04x)", + etype); + } + dissect_ipv6(pd, offset, fd, tree); + break; + case ETHERTYPE_ARP: + if (tree) { + add_item_to_tree(fh_tree, offset - 2, 2, + "Type: ARP (0x%04x)", etype); + } + dissect_arp(pd, offset, fd, tree); + break; + case ETHERTYPE_REVARP: + if (tree) { + add_item_to_tree(fh_tree, offset - 2, 2, + "Type: RARP (0x%04x)", etype); + } + dissect_arp(pd, offset, fd, tree); + break; + case ETHERTYPE_ATALK: + if (tree) { + add_item_to_tree(fh_tree, offset - 2, 2, + "Type: AppleTalk (0x%04x)", etype); + } + if (fd->win_info[0]) { strcpy(fd->win_info[3], etype_str[3]); } + break; + case ETHERTYPE_AARP: + if (tree) { + add_item_to_tree(fh_tree, offset - 2, 2, + "Type: AARP (0x%04x)", etype); + } + if (fd->win_info[0]) { strcpy(fd->win_info[3], etype_str[4]); } + break; + case ETHERTYPE_IPX: + if (tree) { + add_item_to_tree(fh_tree, offset - 2, 2, + "Type: Netware IPX/SPX (0x%04x)", etype); + } + dissect_ipx(pd, offset, fd, tree); + break; + default: + if (tree) { + add_item_to_tree(fh_tree, offset - 2, 2, + "Type: Unknown (0x%04x)", etype); + dissect_data(pd, offset, fd, tree); + } + if (fd->win_info[0]) { sprintf(fd->win_info[3], "0x%04x", etype); } + break; + } + } diff --git a/etypes.h b/etypes.h new file mode 100644 index 0000000000..8b8ea1c2ab --- /dev/null +++ b/etypes.h @@ -0,0 +1,67 @@ +/* etypes.h + * Defines ethernet packet types, similar to tcpdump's ethertype.h + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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 __ETYPES_H__ +#define __ETYPES_H__ + +#ifndef ETHERTYPE_UNK +#define ETHERTYP_UNK 0x0000 +#endif + +/* Sources: + * http://www.isi.edu/in-notes/iana/assignments/ethernet-numbers + * TCP/IP Illustrated, Volume 1 + * RFCs 894, 1042, 826 + * tcpdump's ethertype.h + * http://www.cavebear.com/CaveBear/Ethernet/ + */ + +#ifndef ETHERTYPE_IP +#define ETHERTYPE_IP 0x0800 +#endif + +#ifndef ETHERTYPE_IPv6 +#define ETHERTYPE_IPv6 0x086dd +#endif + +#ifndef ETHERTYPE_ARP +#define ETHERTYPE_ARP 0x0806 +#endif + +#ifndef ETHERTYPE_REVARP +#define ETHERTYPE_REVARP 0x8035 +#endif + +#ifndef ETHERTYPE_ATALK +#define ETHERTYPE_ATALK 0x809b +#endif + +#ifndef ETHERTYPE_AARP +#define ETHERTYPE_AARP 0x80f3 +#endif + +#ifndef ETHERTYPE_IPX +#define ETHERTYPE_IPX 0x8137 +#endif + +#endif /* etypes.h */ diff --git a/file.c b/file.c new file mode 100644 index 0000000000..5ee508b0b9 --- /dev/null +++ b/file.c @@ -0,0 +1,356 @@ +/* file.c + * File I/O routines + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include +#include +#include +#include + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#ifdef HAVE_NETINET_IN_H +# include +#endif + + +#include "packet.h" +#include "file.h" +#include "ethereal.h" +#include "util.h" + +extern GtkWidget *packet_list, *prog_bar, *info_bar, *byte_view, *tree_view; +extern guint file_ctx; + +guint32 ssec, susec; + +int +open_cap_file(char *fname, capture_file *cf) { + guint32 magic[2]; + char err_str[PCAP_ERRBUF_SIZE]; + struct stat cf_stat; + + /* First, make sure the file is valid */ + if (stat(fname, &cf_stat)) { + simple_dialog(ESD_TYPE_WARN, NULL, "File does not exist."); + return 1; + } + if (! S_ISREG(cf_stat.st_mode) && ! S_ISFIFO(cf_stat.st_mode)) { + simple_dialog(ESD_TYPE_WARN, NULL, "The file you have chosen is invalid."); + return 1; + } + + /* Next, try to open the file */ + cf->fh = fopen(fname, "r"); + if (cf->fh == NULL) + return (errno); + + fseek(cf->fh, 0L, SEEK_END); + cf->f_len = ftell(cf->fh); + fseek(cf->fh, 0L, SEEK_SET); + fread(magic, sizeof(guint32), 2, cf->fh); + fseek(cf->fh, 0L, SEEK_SET); + fclose(cf->fh); + cf->fh = NULL; + + /* Next, find out what type of file we're dealing with */ + + cf->cd_t = CD_UNKNOWN; + cf->lnk_t = DLT_NULL; + cf->swap = 0; + cf->count = 0; + cf->drops = 0; + cf->esec = 0; + cf->eusec = 0; + cf->snap = 0; + if (cf->plist == NULL) { + cf->plist = g_list_alloc(); + cf->plist->data = (frame_data *) g_malloc(sizeof(frame_data)); + } else { + cf->plist = g_list_first(cf->plist); + } + ssec = 0, susec = 0; + + if (magic[0] == PCAP_MAGIC || magic[0] == SWAP32(PCAP_MAGIC)) { + + /* Pcap/Tcpdump file */ + cf->pfh = pcap_open_offline(fname, err_str); + if (cf->pfh == NULL) { + simple_dialog(ESD_TYPE_WARN, NULL, "Could not open file."); + return 1; + } + + if (cf->filter) { + if (pcap_compile(cf->pfh, &cf->fcode, cf->filter, 1, 0) < 0) { + simple_dialog(ESD_TYPE_WARN, NULL, "Unable to parse filter string."); + } else if (pcap_setfilter(cf->pfh, &cf->fcode) < 0) { + simple_dialog(ESD_TYPE_WARN, NULL, "Can't install filter."); + } + } + + cf->fh = pcap_file(cf->pfh); + cf->swap = pcap_is_swapped(cf->pfh); + if ((cf->swap && BYTE_ORDER == BIG_ENDIAN) || + (!cf->swap && BYTE_ORDER == LITTLE_ENDIAN)) { + /* Data is big-endian */ + cf->cd_t = CD_PCAP_BE; + } else { + cf->cd_t = CD_PCAP_LE; + } + cf->vers = ( ((pcap_major_version(cf->pfh) & 0x0000ffff) << 16) | + pcap_minor_version(cf->pfh) ); + cf->snap = pcap_snapshot(cf->pfh); + cf->lnk_t = pcap_datalink(cf->pfh); + } else if (ntohl(magic[0]) == SNOOP_MAGIC_1 && ntohl(magic[1]) == SNOOP_MAGIC_2) { + /* Snoop file */ + simple_dialog(ESD_TYPE_WARN, NULL, "The snoop format is not yet supported."); + return 1; + /* + fread(&sfh, sizeof(snoop_file_hdr), 1, cf->fh); + cf->cd_t = CD_SNOOP; + cf->vers = ntohl(sfh.vers); + if (cf->vers < SNOOP_MIN_VERSION || cf->vers > SNOOP_MAX_VERSION) { + g_warning("ethereal:open_cap_file:%s:bad snoop file version(%d)", + fname, cf->vers); + return 1; + } + switch (ntohl(sfh.s_lnk_t)) { + case 4: + cf->lnk_t = DLT_EN10MB; + break; + } + */ + } + + if (cf->cd_t == CD_UNKNOWN) { + simple_dialog(ESD_TYPE_WARN, NULL, "Can't determine file type."); + return 1; + } + return 0; +} + +/* Reset everything to a pristine state */ +void +close_cap_file(capture_file *cf, GtkWidget *w, guint context) { + if (cf->fh) { + fclose(cf->fh); + cf->fh = NULL; + } + if (cf->pfh) { + pcap_close(cf->pfh); + cf->pfh = NULL; + } + gtk_text_freeze(GTK_TEXT(byte_view)); + gtk_text_set_point(GTK_TEXT(byte_view), 0); + gtk_text_forward_delete(GTK_TEXT(byte_view), + gtk_text_get_length(GTK_TEXT(byte_view))); + gtk_text_thaw(GTK_TEXT(byte_view)); + gtk_tree_clear_items(GTK_TREE(tree_view), 0, + g_list_length(GTK_TREE(tree_view)->children)); + + gtk_clist_freeze(GTK_CLIST(packet_list)); + gtk_clist_clear(GTK_CLIST(packet_list)); + gtk_clist_thaw(GTK_CLIST(packet_list)); + gtk_statusbar_pop(GTK_STATUSBAR(w), context); +} + +int +load_cap_file(char *fname, capture_file *cf) { + gchar *name_ptr, *load_msg, *load_fmt = " Loading: %s..."; + gchar *done_fmt = " File: %s Packets: %d Drops: %d Elapsed: %d.%06ds"; + gchar *err_fmt = " Error: Could not load '%s'"; + gint timeout; + size_t msg_len; + int err; + + close_cap_file(cf, info_bar, file_ctx); + + if ((name_ptr = (gchar *) strrchr(fname, '/')) == NULL) + name_ptr = fname; + else + name_ptr++; + load_msg = g_malloc(strlen(name_ptr) + strlen(load_fmt) + 2); + sprintf(load_msg, load_fmt, name_ptr); + gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg); + + timeout = gtk_timeout_add(250, file_progress_cb, (gpointer) &cf); + + err = open_cap_file(fname, cf); + if ((err == 0) && (cf->cd_t != CD_UNKNOWN)) { + gtk_clist_freeze(GTK_CLIST(packet_list)); + pcap_loop(cf->pfh, 0, pcap_dispatch_cb, (u_char *) cf); + pcap_close(cf->pfh); + cf->pfh = NULL; + cf->plist = g_list_first(cf->plist); + cf->fh = fopen(fname, "r"); + gtk_clist_thaw(GTK_CLIST(packet_list)); + } + + gtk_timeout_remove(timeout); + gtk_progress_bar_update(GTK_PROGRESS_BAR(prog_bar), 0); + + gtk_statusbar_pop(GTK_STATUSBAR(info_bar), file_ctx); + + if (err == 0) { + msg_len = strlen(name_ptr) + strlen(load_fmt) + 64; + load_msg = g_realloc(load_msg, msg_len); + snprintf(load_msg, msg_len, done_fmt, name_ptr, cf->count, cf->drops, + cf->esec, cf->eusec); + gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg); + g_free(load_msg); + + name_ptr[-1] = '\0'; + set_menu_sensitivity("
/File/Close", TRUE); + } else { + msg_len = strlen(name_ptr) + strlen(err_fmt) + 2; + load_msg = g_realloc(load_msg, msg_len); + snprintf(load_msg, msg_len, err_fmt, name_ptr); + gtk_statusbar_push(GTK_STATUSBAR(info_bar), file_ctx, load_msg); + g_free(load_msg); + set_menu_sensitivity("
/File/Close", FALSE); + } + + return err; +} + +void +pcap_dispatch_cb(u_char *user, const struct pcap_pkthdr *phdr, + const u_char *buf) { + frame_data *fdata; + /* To do: make sure this is big enough. */ + gchar p_info[5][256]; + gint i, row; + capture_file *cf = (capture_file *) user; + + while (gtk_events_pending()) + gtk_main_iteration(); + + fdata = cf->plist->data; + cf->cur = fdata; + cf->count++; + + fdata->pkt_len = phdr->len; + fdata->cap_len = phdr->caplen; + fdata->file_off = ftell(cf->fh) - phdr->caplen; + fdata->secs = phdr->ts.tv_sec; + fdata->usecs = phdr->ts.tv_usec; + + for (i = 0; i < 5; i++) { fdata->win_info[i] = &p_info[i][0]; } + sprintf(fdata->win_info[0], "%d", cf->count); + dissect_packet(buf, fdata, NULL); + row = gtk_clist_append(GTK_CLIST(packet_list), fdata->win_info); + for (i = 0; i < 5; i++) { fdata->win_info[i] = NULL; } + + if (!ssec && !susec) { + ssec = fdata->secs; + susec = fdata->usecs; + } + cf->esec = fdata->secs - ssec; + if (susec < fdata->usecs) { + cf->eusec = fdata->usecs - susec; + } else { + cf->eusec = susec - fdata->usecs; + cf->esec--; + } + + /* Make sure we always have an available list entry */ + if (cf->plist->next == NULL) { + fdata = (frame_data *) g_malloc(sizeof(frame_data)); + g_list_append(cf->plist, (gpointer) fdata); + } + cf->plist = cf->plist->next; +} + +/* Uncomment when we handle snoop files again. + +size_t +read_frame_header(capture_file *cf) { + snoop_frame_hdr shdr; + pcap_frame_hdr phdr; + gint16 pkt_len, cap_len; + guint32 secs, usecs; + frame_data *fdata; + size_t err; + + if ((cf->cd_t == CD_PCAP_BE) || (cf->cd_t == CD_PCAP_LE)) { + err = fread((char *)&phdr, sizeof(pcap_frame_hdr), 1, cf->fh); + if (!err) { return err; } + fdata = (frame_data *) g_malloc(sizeof(frame_data)); + if (cf->swap) { + pkt_len = SWAP32(phdr.pkt_len); + cap_len = SWAP32(phdr.cap_len); + secs = SWAP32(phdr.tm.tv_sec); + usecs = SWAP32(phdr.tm.tv_usec); + } else { + pkt_len = phdr.pkt_len; + cap_len = phdr.cap_len; + secs = phdr.tm.tv_sec; + usecs = phdr.tm.tv_usec; + } + } else if (cf->cd_t == CD_SNOOP) { + err = fread(&shdr, sizeof(snoop_frame_hdr), 1, cf->fh); + fdata = (frame_data *) g_malloc(sizeof(frame_data)); + if (!err) { return err; } + pkt_len = ntohl(shdr.inc_len); + cap_len = ntohl(shdr.pr_len) - 24; + secs = ntohl(shdr.secs); + usecs = ntohl(shdr.usecs); + shdr.drops = ntohl(shdr.drops); + if (!ssec && !susec) { ssec = secs; susec = usecs; } + cf->drops = shdr.drops; + cf->esec = secs - ssec; + if (susec < shdr.usecs) { + cf->eusec = usecs - susec; + } else { + cf->eusec = susec - usecs; + cf->esec--; + } + } + cf->cur = fdata; + fdata->pkt_len = pkt_len; + fdata->cap_len = cap_len; + fdata->secs = secs; + fdata->usecs = usecs; + g_list_append(cf->plist, (gpointer) fdata); + if (!ssec && !susec) { + ssec = secs; + susec = usecs; + } + cf->esec = secs - ssec; + if (susec < usecs) { + cf->eusec = usecs - susec; + } else { + cf->eusec = susec - usecs; + cf->esec--; + } + return err; +} +*/ diff --git a/file.h b/file.h new file mode 100644 index 0000000000..8f1ef9b0dc --- /dev/null +++ b/file.h @@ -0,0 +1,99 @@ +/* file.h + * Definitions for file structures and routines + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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 __FILE_H__ +#define __FILE_H__ + +#include +#include + +#include + +/* Data file formats */ +#define CD_UNKNOWN 0 +#define CD_WIRE 1 +#define CD_SNOOP 2 +#define CD_PCAP_BE 3 +#define CD_PCAP_LE 4 +#define CD_NA_UNCOMPR 5 + +/* Data file magic info */ +#define SNOOP_MAGIC_1 0x736e6f6f /* 'snoop' in ASCII */ +#define SNOOP_MAGIC_2 0x70000000 +#define PCAP_MAGIC 0xa1b2c3d4 + +/* Data file format versions we can handle */ +#define SNOOP_MIN_VERSION 2 +#define SNOOP_MAX_VERSION 2 + +/* Link types (removed in favor of the DLT_* defines from bpf.h */ + +typedef struct bpf_program bpf_prog; + +typedef struct _capture_file { + FILE *fh; /* Capture file */ + long f_len; /* File length */ + int swap; /* Swap data bytes? */ + guint16 cd_t; /* Capture data type */ + guint32 vers; /* Version. For tcpdump minor is appended to major */ + guint32 lnk_t; /* Network link type */ + guint32 count; /* Packet count */ + guint32 drops; /* Dropped packets */ + guint32 esec; /* Elapsed seconds */ + guint32 eusec; /* Elapsed microseconds */ + guint32 snap; /* Captured packet length */ + gchar *iface; /* Interface */ + gchar *save_file; /* File to write capture data */ + pcap_t *pfh; /* Pcap session */ + gchar *filter; /* Pcap filter string */ + bpf_prog fcode; /* Compiled filter program */ + guint8 pd[4096]; /* Packet data */ + GList *plist; /* Packet list */ + frame_data *cur; /* Current list item */ +} capture_file; + +/* Taken from RFC 1761 */ + +typedef struct _snoop_file_hdr { + guint32 magic1; + guint32 magic2; + guint32 vers; + guint32 s_lnk_t; +} snoop_file_hdr; + +typedef struct _snoop_frame_hdr { + guint32 orig_len; + guint32 inc_len; + guint32 pr_len; + guint32 drops; + guint32 secs; + guint32 usecs; +} snoop_frame_hdr; + +int open_cap_file(char *, capture_file *); +void close_cap_file(capture_file *, GtkWidget *, guint); +int load_cap_file(char *, capture_file *); +void pcap_dispatch_cb(u_char *, const struct pcap_pkthdr *, const u_char *); +/* size_t read_frame_header(capture_file *); */ + +#endif /* file.h */ diff --git a/filter.c b/filter.c new file mode 100644 index 0000000000..d3ea96f896 --- /dev/null +++ b/filter.c @@ -0,0 +1,472 @@ +/* filter.c + * Routines for managing filter sets + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include +#include +#include + +#include "filter.h" +#include "packet.h" +#include "file.h" +#include "menu.h" + +extern capture_file cf; + +const gchar *fn_key = "filter_name"; +const gchar *fl_key = "filter_label"; +GtkWidget *filter_l, *chg_bt, *copy_bt, *del_bt, *name_te, *filter_te; +gint in_cancel = FALSE; +GList *fl = NULL; + +GList * +read_filter_list() { + filter_def *filt; + FILE *ff; + gchar *ff_path, *ff_name = ".ethereal/filters", f_buf[256]; + gchar *name_begin, *name_end, *filt_begin; + int len, line = 0; + + in_cancel = FALSE; + + /* To do: generalize this */ + ff_path = (gchar *) g_malloc(strlen(getenv("HOME")) + strlen(ff_name) + 4); + sprintf(ff_path, "%s/%s", getenv("HOME"), ff_name); + + if ((ff = fopen(ff_path, "r")) == NULL) { + g_free(ff_path); + return NULL; + } + + while (fgets(f_buf, 256, ff)) { + line++; + len = strlen(f_buf); + if (f_buf[len - 1] = '\n') { + len--; + f_buf[len] = '\0'; + } + name_begin = strchr(f_buf, '"'); + /* Empty line */ + if (name_begin == NULL) + continue; + name_end = strchr(name_begin + 1, '"'); + /* No terminating quote */ + if (name_end == NULL) { + g_warning("Malformed filter in '%s' line %d.", ff_path, line); + continue; + } + name_begin++; + name_end[0] = '\0'; + filt_begin = name_end + 1; + while(isspace(filt_begin[0])) filt_begin++; + /* No filter string */ + if (filt_begin[0] == '\0') { + g_warning("Malformed filter in '%s' line %d.", ff_path, line); + continue; + } + filt = (filter_def *) g_malloc(sizeof(filter_def)); + filt->name = g_strdup(name_begin); + filt->strval = g_strdup(filt_begin); + fl = g_list_append(fl, filt); + } + fclose(ff); + g_free(ff_path); + return fl; +} + +/* filter_sel_cb - Create and display the filter selection dialog. */ +/* Called when the 'Filter' menu item is selected. */ +void +filter_sel_cb(GtkWidget *w, gpointer d) { + GtkWidget *filter_w, *main_vb, *top_hb, *list_bb, *bbox, + *new_bt, *ok_bt, *save_bt, *cancel_bt, *filter_sc, *nl_item, + *nl_lb, *middle_hb, *name_lb, *bottom_hb, *filter_lb; + GtkWidget *l_select = NULL; + GList *flp = NULL, *nl = NULL; + filter_def *filt; + + fl = read_filter_list(); + + filter_w = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(filter_w), "Ethereal: Filters"); + + /* Container for each row of widgets */ + main_vb = gtk_vbox_new(FALSE, 5); + gtk_container_border_width(GTK_CONTAINER(main_vb), 5); + gtk_container_add(GTK_CONTAINER(filter_w), main_vb); + gtk_widget_show(main_vb); + + /* Top row: Filter list and buttons */ + top_hb = gtk_hbox_new(FALSE, 5); + gtk_container_add(GTK_CONTAINER(main_vb), top_hb); + gtk_widget_show(top_hb); + + list_bb = gtk_vbutton_box_new(); + gtk_button_box_set_layout (GTK_BUTTON_BOX (list_bb), GTK_BUTTONBOX_START); + gtk_container_add(GTK_CONTAINER(top_hb), list_bb); + gtk_widget_show(list_bb); + + new_bt = gtk_button_new_with_label ("New"); + gtk_signal_connect(GTK_OBJECT(new_bt), "clicked", + GTK_SIGNAL_FUNC(filter_sel_new_cb), NULL); + gtk_container_add(GTK_CONTAINER(list_bb), new_bt); + gtk_widget_show(new_bt); + + chg_bt = gtk_button_new_with_label ("Change"); + gtk_widget_set_sensitive(chg_bt, FALSE); + gtk_signal_connect(GTK_OBJECT(chg_bt), "clicked", + GTK_SIGNAL_FUNC(filter_sel_chg_cb), NULL); + gtk_container_add(GTK_CONTAINER(list_bb), chg_bt); + gtk_widget_show(chg_bt); + + copy_bt = gtk_button_new_with_label ("Copy"); + gtk_widget_set_sensitive(copy_bt, FALSE); + gtk_signal_connect(GTK_OBJECT(copy_bt), "clicked", + GTK_SIGNAL_FUNC(filter_sel_copy_cb), NULL); + gtk_container_add(GTK_CONTAINER(list_bb), copy_bt); + gtk_widget_show(copy_bt); + + del_bt = gtk_button_new_with_label ("Delete"); + gtk_widget_set_sensitive(del_bt, FALSE); + gtk_signal_connect(GTK_OBJECT(del_bt), "clicked", + GTK_SIGNAL_FUNC(filter_sel_del_cb), NULL); + gtk_container_add(GTK_CONTAINER(list_bb), del_bt); + gtk_widget_show(del_bt); + + filter_sc = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(filter_sc), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_widget_set_usize(filter_sc, 250, 150); + gtk_container_add(GTK_CONTAINER(top_hb), filter_sc); + gtk_widget_show(filter_sc); + + filter_l = gtk_list_new(); + gtk_signal_connect(GTK_OBJECT(filter_l), "selection_changed", + GTK_SIGNAL_FUNC(filter_sel_list_cb), NULL); + gtk_container_add(GTK_CONTAINER(filter_sc), filter_l); + gtk_widget_show(filter_l); + + flp = g_list_first(fl); + while (flp) { + filt = (filter_def *) flp->data; + nl_lb = gtk_label_new(filt->name); + nl_item = gtk_list_item_new(); + gtk_misc_set_alignment (GTK_MISC (nl_lb), 0.0, 0.5); + gtk_container_add(GTK_CONTAINER(nl_item), nl_lb); + gtk_widget_show(nl_lb); + gtk_container_add(GTK_CONTAINER(filter_l), nl_item); + gtk_widget_show(nl_item); + gtk_object_set_data(GTK_OBJECT(nl_item), fl_key, nl_lb); + gtk_object_set_data(GTK_OBJECT(nl_item), fn_key, flp); + if (cf.filter && filt->strval) + if (strcmp(cf.filter, filt->strval) == 0) + l_select = nl_item; + flp = flp->next; + } + + /* Middle row: Filter name entry */ + middle_hb = gtk_hbox_new(FALSE, 5); + gtk_container_add(GTK_CONTAINER(main_vb), middle_hb); + gtk_widget_show(middle_hb); + + name_lb = gtk_label_new("Filter name:"); + gtk_box_pack_start(GTK_BOX(middle_hb), name_lb, FALSE, FALSE, 3); + gtk_widget_show(name_lb); + + name_te = gtk_entry_new(); + gtk_box_pack_start(GTK_BOX(middle_hb), name_te, TRUE, TRUE, 3); + gtk_widget_show(name_te); + + /* Bottom row: Filter text entry */ + bottom_hb = gtk_hbox_new(FALSE, 5); + gtk_container_add(GTK_CONTAINER(main_vb), bottom_hb); + gtk_widget_show(bottom_hb); + + filter_lb = gtk_label_new("Filter string:"); + gtk_box_pack_start(GTK_BOX(bottom_hb), filter_lb, FALSE, FALSE, 3); + gtk_widget_show(filter_lb); + + filter_te = gtk_entry_new(); + gtk_box_pack_start(GTK_BOX(bottom_hb), filter_te, TRUE, TRUE, 3); + gtk_widget_show(filter_te); + + /* Button row: OK and cancel buttons */ + bbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END); + gtk_container_add(GTK_CONTAINER(main_vb), bbox); + gtk_widget_show(bbox); + + ok_bt = gtk_button_new_with_label ("OK"); + gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked", + GTK_SIGNAL_FUNC(filter_sel_ok_cb), (gpointer) filter_w); + gtk_container_add(GTK_CONTAINER(bbox), ok_bt); + GTK_WIDGET_SET_FLAGS(ok_bt, GTK_CAN_DEFAULT); + gtk_widget_grab_default(ok_bt); + gtk_widget_show(ok_bt); + + save_bt = gtk_button_new_with_label ("Save"); + gtk_signal_connect(GTK_OBJECT(save_bt), "clicked", + GTK_SIGNAL_FUNC(filter_sel_save_cb), (gpointer) fl); + gtk_container_add(GTK_CONTAINER(bbox), save_bt); + gtk_widget_show(save_bt); + + cancel_bt = gtk_button_new_with_label ("Cancel"); + gtk_signal_connect(GTK_OBJECT(cancel_bt), "clicked", + GTK_SIGNAL_FUNC(filter_sel_cancel_cb), (gpointer) filter_w); + gtk_container_add(GTK_CONTAINER(bbox), cancel_bt); + gtk_widget_show(cancel_bt); + + gtk_widget_show(filter_w); + + if (l_select) + gtk_list_select_child(GTK_LIST(filter_l), l_select); +} + +void +filter_sel_list_cb(GtkWidget *l, gpointer data) { + filter_def *filt; + gchar *name = "", *strval = ""; + GList *sl, *flp; + GtkObject *l_item; + gint sensitivity = FALSE; + + sl = GTK_LIST(l)->selection; + + if (sl) { /* Something was selected */ + l_item = GTK_OBJECT(sl->data); + flp = (GList *) gtk_object_get_data(l_item, fn_key); + if (flp) { + filt = (filter_def *) flp->data; + name = filt->name; + strval = filt->strval; + sensitivity = TRUE; + } + } + + /* Did you know that this function is called when the window is destroyed? */ + /* Funny, that. */ + if (!in_cancel) { + gtk_entry_set_text(GTK_ENTRY(name_te), name); + gtk_entry_set_text(GTK_ENTRY(filter_te), strval); + gtk_widget_set_sensitive(chg_bt, sensitivity); + gtk_widget_set_sensitive(copy_bt, sensitivity); + gtk_widget_set_sensitive(del_bt, sensitivity); + } +} + +/* To do: add input checking to each of these callbacks */ + +void +filter_sel_new_cb(GtkWidget *w, gpointer data) { + GList *nl = NULL; + filter_def *filt; + gchar *name, *strval; + GtkWidget *nl_item, *nl_lb; + + name = gtk_entry_get_text(GTK_ENTRY(name_te)); + strval = gtk_entry_get_text(GTK_ENTRY(filter_te)); + + if (strlen(name) > 0 && strlen(strval) > 0) { + filt = (filter_def *) g_malloc(sizeof(filter_def)); + filt->name = g_strdup(name); + filt->strval = g_strdup(strval); + fl = g_list_append(fl, filt); + nl_lb = gtk_label_new(filt->name); + nl_item = gtk_list_item_new(); + gtk_misc_set_alignment (GTK_MISC (nl_lb), 0.0, 0.5); + gtk_container_add(GTK_CONTAINER(nl_item), nl_lb); + gtk_widget_show(nl_lb); + gtk_container_add(GTK_CONTAINER(filter_l), nl_item); + gtk_widget_show(nl_item); + gtk_object_set_data(GTK_OBJECT(nl_item), fl_key, nl_lb); + gtk_object_set_data(GTK_OBJECT(nl_item), fn_key, g_list_last(fl)); + } +} + +void +filter_sel_chg_cb(GtkWidget *w, gpointer data) { + filter_def *filt; + gchar *name = "", *strval = ""; + GList *sl, *flp; + GtkObject *l_item; + GtkLabel *nl_lb; + gint sensitivity = FALSE; + + sl = GTK_LIST(filter_l)->selection; + name = gtk_entry_get_text(GTK_ENTRY(name_te)); + strval = gtk_entry_get_text(GTK_ENTRY(filter_te)); + + if (sl) { /* Something was selected */ + l_item = GTK_OBJECT(sl->data); + flp = (GList *) gtk_object_get_data(l_item, fn_key); + nl_lb = (GtkLabel *) gtk_object_get_data(l_item, fl_key); + if (flp && nl_lb) { + filt = (filter_def *) flp->data; + + if (strlen(name) > 0 && strlen(strval) > 0 && filt) { + g_free(filt->name); + g_free(filt->strval); + filt->name = g_strdup(name); + filt->strval = g_strdup(strval); + gtk_label_set(nl_lb, filt->name); + } + } + } +} + +void +filter_sel_copy_cb(GtkWidget *w, gpointer data) { + GList *nl = NULL, *sl, *flp; + filter_def *filt, *nfilt; + gchar *name, *strval, *prefix = "Copy of "; + GtkObject *l_item; + GtkWidget *nl_item, *nl_lb; + + sl = GTK_LIST(filter_l)->selection; + if (sl) { /* Something was selected */ + l_item = GTK_OBJECT(sl->data); + flp = (GList *) gtk_object_get_data(l_item, fn_key); + if (flp) { + filt = (filter_def *) flp->data; + nfilt = (filter_def *) g_malloc(sizeof(filter_def)); + nfilt->name = g_malloc(strlen(prefix) + strlen(filt->name) + 1); + sprintf(nfilt->name, "%s%s", prefix, filt->name); + nfilt->strval = g_strdup(filt->strval); + fl = g_list_append(fl, nfilt); + nl_lb = gtk_label_new(nfilt->name); + nl_item = gtk_list_item_new(); + gtk_misc_set_alignment (GTK_MISC (nl_lb), 0.0, 0.5); + gtk_container_add(GTK_CONTAINER(nl_item), nl_lb); + gtk_widget_show(nl_lb); + gtk_container_add(GTK_CONTAINER(filter_l), nl_item); + gtk_widget_show(nl_item); + gtk_object_set_data(GTK_OBJECT(nl_item), fl_key, nl_lb); + gtk_object_set_data(GTK_OBJECT(nl_item), fn_key, g_list_last(fl)); + } + } +} + +void +filter_sel_del_cb(GtkWidget *w, gpointer data) { + GList *sl, *flp; + filter_def *filt; + GtkObject *l_item; + GtkWidget *nl_item; + gint pos; + + sl = GTK_LIST(filter_l)->selection; + if (sl) { /* Something was selected */ + l_item = GTK_OBJECT(sl->data); + pos = gtk_list_child_position(GTK_LIST(filter_l), + GTK_WIDGET(l_item)); + flp = (GList *) gtk_object_get_data(l_item, fn_key); + if (flp) { + filt = (filter_def *) flp->data; + g_free(filt->name); + g_free(filt->strval); + g_free(filt); + fl = g_list_remove_link(fl, flp); + gtk_list_clear_items(GTK_LIST(filter_l), pos, pos + 1); + } + } +} + +void +filter_sel_ok_cb(GtkWidget *w, gpointer data) { + GList *flp, *sl; + GtkObject *l_item; + filter_def *filt; + + if (cf.filter) { + g_free(cf.filter); + cf.filter = NULL; + } + + sl = GTK_LIST(filter_l)->selection; + if (sl) { /* Something was selected */ + l_item = GTK_OBJECT(sl->data); + flp = (GList *) gtk_object_get_data(l_item, fn_key); + if (flp) { + filt = (filter_def *) flp->data; + cf.filter = g_strdup(filt->strval); + } + } + + filter_sel_cancel_cb(w, data); +} + +void +filter_sel_save_cb(GtkWidget *w, gpointer data) { + GList *flp; + filter_def *filt; + gchar *ff_path, *ff_dir = ".ethereal", *ff_name = "filters"; + FILE *ff; + struct stat s_buf; + + ff_path = (gchar *) g_malloc(strlen(getenv("HOME")) + strlen(ff_dir) + + strlen(ff_name) + 4); + sprintf(ff_path, "%s/%s", getenv("HOME"), ff_dir); + + if (stat(ff_path, &s_buf) != 0) + mkdir(ff_path, 0755); + + sprintf(ff_path, "%s/%s/%s", getenv("HOME"), ff_dir, ff_name); + + if ((ff = fopen(ff_path, "w")) != NULL) { + flp = g_list_first(fl); + while (flp) { + filt = (filter_def *) flp->data; + fprintf(ff, "\"%s\" %s\n", filt->name, filt->strval); + flp = flp->next; + } + fclose(ff); + } + + g_free(ff_path); +} + +void +filter_sel_cancel_cb(GtkWidget *w, gpointer win) { + filter_def *filt; + GList *sl; + + while (fl) { + if (fl->data) { + filt = (filter_def *) fl->data; + g_free(filt->name); + g_free(filt->strval); + g_free(filt); + } + fl = g_list_remove_link(fl, fl); + } + + /* Let the list cb know we're about to destroy the widget tree, so it */ + /* doesn't operate on widgets that don't exist. */ + in_cancel = TRUE; + gtk_widget_destroy(GTK_WIDGET(win)); +} diff --git a/filter.h b/filter.h new file mode 100644 index 0000000000..4508ed3000 --- /dev/null +++ b/filter.h @@ -0,0 +1,55 @@ +/* filter.h + * Definitions for packet filter window + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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 __FILTER_H__ +#define __FILTER_H__ + +typedef struct _filter_def { + char *name; + char *strval; +} filter_def; + +typedef struct _filter_cb_data { + GList *fl; + GtkWidget *win; +} filter_cb_data; + +GList *read_filter_list(); +void filter_sel_cb(GtkWidget *, gpointer); +void filter_sel_list_cb(GtkWidget *, gpointer); +void filter_sel_new_cb(GtkWidget *, gpointer); +void filter_sel_chg_cb(GtkWidget *, gpointer); +void filter_sel_copy_cb(GtkWidget *, gpointer); +void filter_sel_del_cb(GtkWidget *, gpointer); +void filter_sel_ok_cb(GtkWidget *, gpointer); +void filter_sel_save_cb(GtkWidget *, gpointer); +void filter_sel_cancel_cb(GtkWidget *, gpointer); + +/* GList *get_interface_list(); +void capture_prep_file_cb(GtkWidget *, gpointer); +void cap_prep_fs_ok_cb(GtkWidget *, gpointer); +void cap_prep_fs_cancel_cb(GtkWidget *, gpointer); +void capture_prep_ok_cb(GtkWidget *, gpointer); +void capture_prep_close_cb(GtkWidget *, gpointer); + */ +#endif /* capture.h */ diff --git a/image/icon-excl.xpm b/image/icon-excl.xpm new file mode 100644 index 0000000000..dfd3ecb57b --- /dev/null +++ b/image/icon-excl.xpm @@ -0,0 +1,88 @@ +/* XPM */ +static char * icon_excl_xpm[] = { +"64 64 21 1", +" c None", +". c #FFFFFF", +"+ c #A95454", +"@ c #7F0000", +"# c #9B3838", +"$ c #A95555", +"% c #D4A9A9", +"& c #B77171", +"* c #8D1C1C", +"= c #D3A9A9", +"- c #F0E2E2", +"; c #A85353", +"> c #C68D8D", +", c #B77070", +"' c #E2C6C6", +") c #8D1D1D", +"! c #C58D8D", +"~ c #D3A8A8", +"{ c #E2C5C5", +"] c #A85252", +"^ c #C58C8C", +" ", +" ", +" ", +" ", +" ", +" ............ ", +" .................... ", +" ......................... ", +" ............................. ", +" .............+@#$%............. ", +" .............&@@@@@*=............ ", +" ..............-@@@@@@@;............. ", +" ................>@@@@@@@,............. ", +" .................*@@@@@@@'.............. ", +" .................>@@@@@@@#............... ", +" ..................*@@@@@@@'............... ", +" ..................>@@@@@@@+................ ", +" ...................*@@@@@@@-................ ", +" ...................%@@@@@@@&................. ", +" ....................#@@@@@@@-................. ", +" ...................'@@@@@@@&.................. ", +" ....................#@@@@@@).................... ", +" ....................-@@@@@@@>................... ", +" ....................&@@@@@@*.................... ", +" ....................-@@@@@@@>.................... ", +" ....................>@@@@@@*..................... ", +" .....................*@@@@@@>..................... ", +" ....................'@@@@@@*..................... ", +" ....................+@@@@@@>..................... ", +" ...................-@@@@@@*...................... ", +" ....................&@@@@@@>..................... ", +" ....................*@@@@@*...................... ", +" ...................%@@@@@@!...................... ", +" ....................#@@@@@*...................... ", +" ...................-@@@@@@!...................... ", +" ...................&@@@@@*...................... ", +" ...................@@@@@@>...................... ", +" ..................>@@@@@)...................... ", +" ..................#@@@@@&...................... ", +" ..................@@@@@@'..................... ", +" ..................*@@@@@%..................... ", +" ..................%@@@@@'.................... ", +" ...................=@@@#..................... ", +" ....................-!!..................... ", +" .................'~{........................ ", +" ................!@@@]...................... ", +" ..............'@@@@@^.................... ", +" ..............+@@@@@@................... ", +" ..............@@@@@@@................... ", +" .............%@@@@@@@.................. ", +" .............&@@@@@@@................. ", +" ............+@@@@@@#................ ", +" ............+@@@@@@>............... ", +" ...........+@@@@@*............... ", +" ..........{@@@@@%.............. ", +" ...........'#@*%.............. ", +" ........................... ", +" ......................... ", +" ...................... ", +" ................. ", +" .......... ", +" ", +" ", +" "}; diff --git a/install-sh b/install-sh new file mode 100755 index 0000000000..e8436696c1 --- /dev/null +++ b/install-sh @@ -0,0 +1,250 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/menu.c b/menu.c new file mode 100644 index 0000000000..be9a3c4fed --- /dev/null +++ b/menu.c @@ -0,0 +1,215 @@ +/* menu.c + * Menu routines + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include +#include + +#include + +#include "menu.h" +#include "ethereal.h" +#include "capture.h" +#include "filter.h" +#include "packet.h" +#include "print.h" + +/* Much of this was take from the GTK+ tuturial at http://www.gtk.org */ + +static void menus_remove_accel (GtkWidget *, gchar *, gchar *); +static gint menus_install_accel (GtkWidget *, gchar *, gchar, gchar, gchar *); + +/* this is the GtkMenuEntry structure used to create new menus. The + * first member is the menu definition string. The second, the + * default accelerator key used to access this menu function with + * the keyboard. The third is the callback function to call when + * this menu item is selected (by the accelerator key, or with the + * mouse.) The last member is the data to pass to your callback function. + */ + +static GtkMenuEntry menu_items[] = +{ + {"
/File/Open", "O", file_open_cmd_cb, NULL}, + {"
/File/Close", "W", file_close_cmd_cb, NULL}, + {"
/File/Save", "S", NULL, NULL}, + {"
/File/Save as", NULL, NULL, NULL}, + {"
/File/", NULL, NULL, NULL}, + {"
/File/Print Packet", "P", file_print_cmd_cb, NULL}, + {"
/File/", NULL, NULL, NULL}, + {"
/File/Quit", "Q", file_quit_cmd_cb, NULL}, + {"
/Edit/Cut", "X", NULL, NULL}, + {"
/Edit/Copy", "C", NULL, NULL}, + {"
/Edit/Paste", "V", NULL, NULL}, + {"
/Edit/", NULL, NULL, NULL}, + {"
/Edit/Find", "F", NULL, NULL}, + {"
/Edit/", NULL, NULL, NULL}, + {"
/Edit/Printer Options", NULL, printer_opts_cb, NULL}, + {"
/Tools/Capture", "K", capture_prep_cb, NULL}, + {"
/Tools/Filter", NULL, filter_sel_cb, NULL}, + {"
/Tools/Graph", NULL, NULL, NULL}, + {"
/Help/About Ethereal", NULL, NULL, NULL} +}; + +/* calculate the number of menu_items */ +static int nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]); + +static int initialize = TRUE; +static GtkMenuFactory *factory = NULL; +static GtkMenuFactory *subfactory[1]; +static GHashTable *entry_ht = NULL; + +void +get_main_menu(GtkWidget ** menubar, GtkAcceleratorTable ** table) { + if (initialize) + menus_init(); + + if (menubar) + *menubar = subfactory[0]->widget; + if (table) + *table = subfactory[0]->table; +} + +void +menus_init(void) { + GtkMenuPath *mp; + + if (initialize) { + initialize = FALSE; + + factory = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR); + subfactory[0] = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR); + + gtk_menu_factory_add_subfactory(factory, subfactory[0], "
"); + menus_create(menu_items, nmenu_items); + + set_menu_sensitivity("
/File/Close", FALSE); + set_menu_sensitivity("
/File/Save", FALSE); + set_menu_sensitivity("
/File/Save as", FALSE); + set_menu_sensitivity("
/Edit/Cut", FALSE); + set_menu_sensitivity("
/Edit/Copy", FALSE); + set_menu_sensitivity("
/Edit/Paste", FALSE); + set_menu_sensitivity("
/Edit/Find", FALSE); + set_menu_sensitivity("
/Tools/Graph", FALSE); + set_menu_sensitivity("
/Help/About Ethereal", FALSE); + if ((mp = gtk_menu_factory_find(factory, "
/Help")) != NULL) { + gtk_menu_item_right_justify((GtkMenuItem *) mp->widget); + } + } +} + +void +set_menu_sensitivity (gchar *path, gint val) { + GtkMenuPath *mp; + + if ((mp = gtk_menu_factory_find(factory, path)) != NULL) { + gtk_widget_set_sensitive(mp->widget, val); + } +} + +void +menus_create(GtkMenuEntry * entries, int nmenu_entries) { + char *accelerator; + int i; + + if (initialize) + menus_init(); + + if (entry_ht) + for (i = 0; i < nmenu_entries; i++) { + accelerator = g_hash_table_lookup(entry_ht, entries[i].path); + if (accelerator) { + if (accelerator[0] == '\0') + entries[i].accelerator = NULL; + else + entries[i].accelerator = accelerator; + } + } + gtk_menu_factory_add_entries(factory, entries, nmenu_entries); + + for (i = 0; i < nmenu_entries; i++) + if (entries[i].widget) { + gtk_signal_connect(GTK_OBJECT(entries[i].widget), "install_accelerator", + (GtkSignalFunc) menus_install_accel, entries[i].path); + gtk_signal_connect(GTK_OBJECT(entries[i].widget), "remove_accelerator", + (GtkSignalFunc) menus_remove_accel, entries[i].path); + } +} + +static gint +menus_install_accel(GtkWidget * widget, gchar * signal_name, gchar key, gchar modifiers, gchar * path) { + char accel[64]; + char *t1, t2[2]; + + accel[0] = '\0'; + if (modifiers & GDK_CONTROL_MASK) + strcat(accel, ""); + if (modifiers & GDK_SHIFT_MASK) + strcat(accel, ""); + if (modifiers & GDK_MOD1_MASK) + strcat(accel, ""); + + t2[0] = key; + t2[1] = '\0'; + strcat(accel, t2); + + if (entry_ht) { + t1 = g_hash_table_lookup(entry_ht, path); + g_free(t1); + } else + entry_ht = g_hash_table_new(g_str_hash, g_str_equal); + + g_hash_table_insert(entry_ht, path, g_strdup(accel)); + + return TRUE; +} + +static void +menus_remove_accel(GtkWidget * widget, gchar * signal_name, gchar * path) { + char *t; + + if (entry_ht) { + t = g_hash_table_lookup(entry_ht, path); + g_free(t); + + g_hash_table_insert(entry_ht, path, g_strdup("")); + } +} + +void +menus_set_sensitive(char *path, int sensitive) { + GtkMenuPath *menu_path; + + if (initialize) + menus_init(); + + menu_path = gtk_menu_factory_find(factory, path); + if (menu_path) + gtk_widget_set_sensitive(menu_path->widget, sensitive); + else + g_warning("Unable to set sensitivity for menu which doesn't exist: %s", path); +} diff --git a/menu.h b/menu.h new file mode 100644 index 0000000000..268c98527c --- /dev/null +++ b/menu.h @@ -0,0 +1,41 @@ +/* menu.h + * Menu definitions + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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 __MENU_H__ +#define __MENU_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +void menus_init (void); +void get_main_menu (GtkWidget **, GtkAcceleratorTable **); +void set_menu_sensitivity (gchar *, gint); +void menus_create (GtkMenuEntry *, int); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __MENU_H__ */ diff --git a/missing b/missing new file mode 100755 index 0000000000..cbe2b0ef0e --- /dev/null +++ b/missing @@ -0,0 +1,188 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. +# Copyright (C) 1996, 1997 Free Software Foundation, Inc. +# Franc,ois Pinard , 1996. + +# 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, 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. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +case "$1" in + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + yacc create \`y.tab.[ch]', if possible, from existing .[ch]" + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing - GNU libit 0.0" + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + + aclocal) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acinclude.m4' or \`configure.in'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`configure.in'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acconfig.h' or \`configure.in'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER([^):]*:\([^)]*\)).*/\1/p' configure.in` + if test -z "$files"; then + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^):]*\)).*/\1/p' configure.in` + test -z "$files" || files="$files.in" + else + files=`echo "$files" | sed -e 's/:/ /g'` + fi + test -z "$files" && files="config.h.in" + touch $files + ;; + + automake) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print \ + | sed 's/^\(.*\).am$/touch \1.in/' \ + | sh + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if [ ! -f y.tab.h ]; then + echo >y.tab.h + fi + if [ ! -f y.tab.c ]; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex|flex) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if [ ! -f lex.yy.c ]; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + makeinfo) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file` + fi + touch $file + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and you do not seem to have it handy on your + system. You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequirements for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 diff --git a/mkinstalldirs b/mkinstalldirs new file mode 100755 index 0000000000..14845e07de --- /dev/null +++ b/mkinstalldirs @@ -0,0 +1,40 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman +# Created: 1993-05-16 +# Public domain + +# $Id: mkinstalldirs,v 1.1 1998/09/16 02:39:16 gerald Exp $ + +errstatus=0 + +for file +do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d + do + pathcomp="$pathcomp$d" + case "$pathcomp" in + -* ) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" 1>&2 + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + fi + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# mkinstalldirs ends here diff --git a/packet-arp.c b/packet-arp.c new file mode 100644 index 0000000000..c989b6a89b --- /dev/null +++ b/packet-arp.c @@ -0,0 +1,122 @@ +/* packet-arp.c + * Routines for ARP packet disassembly + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#ifdef HAVE_NETINET_IN_H +# include +#endif + +#include "ethereal.h" +#include "packet.h" +#include "etypes.h" + +void +dissect_arp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) { + e_ether_arp *ea; + guint16 ar_hrd, ar_pro, ar_op; + gchar *req_type[] = { "ARP request", "ARP reply", + "RARP request", "RARP reply" }; + GtkWidget *arp_tree, *ti; + + /* To do: Check for {cap len,pkt len} < struct len */ + ea = (e_ether_arp *) &pd[offset]; + ar_hrd = ntohs(ea->ar_hrd); + ar_pro = ntohs(ea->ar_pro); + /* To do: Check for bounds on ar_op */ + ar_op = ntohs(ea->ar_op); + + if (fd->win_info[0]) { strcpy(fd->win_info[3], "ARP"); } + + if (tree) { + ti = add_item_to_tree(GTK_WIDGET(tree), offset, 28, req_type[ar_op - 1]); + arp_tree = gtk_tree_new(); + add_subtree(ti, arp_tree, ETT_ARP); + add_item_to_tree(arp_tree, offset, 2, + "Hardware type: 0x%04x", ar_hrd); + add_item_to_tree(arp_tree, offset + 2, 2, + "Protocol type: 0x%04x", ar_pro); + add_item_to_tree(arp_tree, offset + 4, 1, + "Hardware size: 0x%02x", ea->ar_hln); + add_item_to_tree(arp_tree, offset + 5, 1, + "Protocol size: 0x%02x", ea->ar_pln); + add_item_to_tree(arp_tree, offset + 6, 2, + "Opcode: 0x%04x", ar_op); + add_item_to_tree(arp_tree, offset + 8, 6, + "Sender ether: %s", ether_to_str((guint8 *) ea->arp_sha)); + add_item_to_tree(arp_tree, offset + 14, 4, + "Sender IP: %s", ip_to_str((guint8 *) ea->arp_spa)); + add_item_to_tree(arp_tree, offset + 18, 6, + "Target ether: %s", ether_to_str((guint8 *) ea->arp_tha)); + add_item_to_tree(arp_tree, offset + 24, 4, + "Target IP: %s", ip_to_str((guint8 *) ea->arp_tpa)); + } + + if (ar_pro != ETHERTYPE_IP && fd->win_info[0]) { + sprintf(fd->win_info[4], "h/w %d (%d) prot %d (%d) op 0x%04x", + ar_hrd, ea->ar_hln, ar_pro, ea->ar_pln, ar_op); + return; + } + switch (ar_op) { + case ARPOP_REQUEST: + if (fd->win_info[0]) { + sprintf(fd->win_info[4], "Who has %s? Tell %s", + ip_to_str((guint8 *) ea->arp_tpa), ip_to_str((guint8 *) ea->arp_spa)); + } + break; + case ARPOP_REPLY: + if (fd->win_info[0]) { + sprintf(fd->win_info[4], "%s is at %s", + ip_to_str((guint8 *) ea->arp_spa), + ether_to_str((guint8 *) ea->arp_sha)); + } + break; + case ARPOP_RREQUEST: + if (fd->win_info[0]) { + strcpy(fd->win_info[3], "RARP"); + sprintf(fd->win_info[4], "Who is %s? Tell %s", + ether_to_str((guint8 *) ea->arp_tha), + ether_to_str((guint8 *) ea->arp_sha)); + } + break; + case ARPOP_RREPLY: + if (fd->win_info[0]) { + strcpy(fd->win_info[3], "RARP"); + sprintf(fd->win_info[4], "%s is at %s", + ether_to_str((guint8 *) ea->arp_sha), + ip_to_str((guint8 *) ea->arp_spa)); + } + break; + } +} diff --git a/packet-bootp.c b/packet-bootp.c new file mode 100644 index 0000000000..f3dc4092f9 --- /dev/null +++ b/packet-bootp.c @@ -0,0 +1,487 @@ +/* packet-bootp.c + * Routines for BOOTP/DHCP packet disassembly + * Gilbert Ramirez + * + * The information used comes from: + * RFC 2132: DHCP Options and BOOTP Vendor Extensions + * RFC 1542: Clarifications and Extensions for the Bootstrap Protocol + * RFC 2131: Dynamic Host Configuration Protocol + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#ifdef HAVE_NETINET_IN_H +# include +#endif + +#include + +#include "packet.h" +#include "ethereal.h" +#include "etypes.h" + +enum field_type { none, ipv4, string, toggle, yes_no, special, opaque, + val_u_byte, val_u_short, val_u_long, + val_s_long }; + +struct opt_info { + char *text; + enum field_type ftype; +}; + +#define NUM_OPT_INFOS 77 + +/* returns the number of bytes consumed by this option */ +int +bootp_option(const u_char *pd, GtkWidget *bp_tree, int voff, int eoff) +{ + char *text; + enum field_type ftype; + u_char code = pd[voff]; + int vlen = pd[voff+1]; + int i, consumed; + GtkWidget *vti, *v_tree; + + char *opt53_text[] = { + "Unknown Message Type", + "Discover", + "Offer", + "Request", + "Decline", + "ACK", + "NAK", + "Release", + "Inform" + }; + + static struct opt_info opt[] = { + /* 0 */ { "Padding", none }, + /* 1 */ { "Subnet Mask", ipv4 }, + /* 2 */ { "Time Offset", val_s_long }, + /* 3 */ { "Router", ipv4 }, + /* 4 */ { "Time Server", ipv4 }, + /* 5 */ { "Name Server", ipv4 }, + /* 6 */ { "Domain Name Server", ipv4 }, + /* 7 */ { "Log Server", ipv4 }, + /* 8 */ { "Cookie Server", ipv4 }, + /* 9 */ { "LPR Server", ipv4 }, + /* 10 */ { "Impress Server", ipv4 }, + /* 11 */ { "Resource Location Server", ipv4 }, + /* 12 */ { "Host Name", string }, + /* 13 */ { "Boot File Size", val_u_short }, + /* 14 */ { "Merit Dump File", string }, + /* 15 */ { "Domain Name", string }, + /* 16 */ { "Swap Server", ipv4 }, + /* 17 */ { "Root Path", string }, + /* 18 */ { "Extensions Path", string }, + /* 19 */ { "IP Forwarding", toggle }, + /* 20 */ { "Non-Local Source Routing", toggle }, + /* 21 */ { "Policy Filter", special }, + /* 22 */ { "Maximum Datagram Reassembly Size", val_u_short }, + /* 23 */ { "Default IP Time-to-Live", val_u_byte }, + /* 24 */ { "Path MTU Aging Timeout", val_u_long }, + /* 25 */ { "Path MTU Plateau Table", val_u_short }, + /* 26 */ { "Interface MTU", val_u_short }, + /* 27 */ { "All Subnets are Local", yes_no }, + /* 28 */ { "Broadcast Address", ipv4 }, + /* 29 */ { "Perform Mask Discovery", toggle }, + /* 30 */ { "Mask Supplier", yes_no }, + /* 31 */ { "Perform Router Discover", toggle }, + /* 32 */ { "Router Solicitation Address", ipv4 }, + /* 33 */ { "Static Route", special }, + /* 34 */ { "Trailer Encapsulation", toggle }, + /* 35 */ { "ARP Cache Timeout", val_u_long }, + /* 36 */ { "Ethernet Encapsulation", toggle }, + /* 37 */ { "TCP Default TTL", val_u_byte }, + /* 38 */ { "TCP Keepalive Interval", val_u_long }, + /* 39 */ { "TCP Keepalive Garbage", toggle }, + /* 40 */ { "Network Information Service Domain", string }, + /* 41 */ { "Network Information Service Servers", ipv4 }, + /* 42 */ { "Network Time Protocol Servers", ipv4 }, + /* 43 */ { "Vendor-Specific Information", special }, + /* 44 */ { "NetBIOS over TCP/IP Name Server", ipv4 }, + /* 45 */ { "NetBIOS over TCP/IP Datagram Distribution Name Server", ipv4 }, + /* 46 */ { "NetBIOS over TCP/IP Node Type", special }, + /* 47 */ { "NetBIOS over TCP/IP Scope", string }, + /* 48 */ { "X Window System Font Server", ipv4 }, + /* 49 */ { "X Window System Display Manager", ipv4 }, + /* 50 */ { "Requested IP Address", ipv4 }, + /* 51 */ { "IP Address Lease Time", val_u_long }, + /* 52 */ { "Option Overload", special }, + /* 53 */ { "DHCP Message Type", special }, + /* 54 */ { "Server Identifier", ipv4 }, + /* 55 */ { "Parameter Request List", opaque }, + /* 56 */ { "Message", string }, + /* 57 */ { "Maximum DHCP Message Size", val_u_short }, + /* 58 */ { "Renewal Time Value", val_u_long }, + /* 59 */ { "Rebinding Time Value", val_u_long }, + /* 60 */ { "Vendor class identifier", opaque }, + /* 61 */ { "Client identifier", special }, + /* 64 */ { "Network Information Service+ Domain", string }, + /* 65 */ { "Network Information Service+ Servers", ipv4 }, + /* 66 */ { "TFTP Server Name", string }, + /* 67 */ { "Bootfile name", string }, + /* 68 */ { "Mobile IP Home Agent", ipv4 }, + /* 69 */ { "SMTP Server", ipv4 }, + /* 70 */ { "POP3 Server", ipv4 }, + /* 71 */ { "NNTP Server", ipv4 }, + /* 72 */ { "Default WWW Server", ipv4 }, + /* 73 */ { "Default Finger Server", ipv4 }, + /* 74 */ { "Default IRC Server", ipv4 }, + /* 75 */ { "StreetTalk Server", ipv4 }, + /* 76 */ { "StreetTalk Directory Assistance Server", ipv4 } + }; + + text = opt[code].text; + /* Special cases */ + switch (code) { + /* Padding */ + case 0: + /* check how much padding we have */ + for (i = voff + 1; i < eoff; i++ ) { + if (pd[i] != 0) { + break; + } + } + i = i - voff; + add_item_to_tree(bp_tree, voff, i, "Padding"); + consumed = i; + return consumed; + + /* Policy Filter */ + case 21: + /* one IP address pair */ + if (vlen == 8) { + add_item_to_tree(bp_tree, voff, consumed, + "Option %d: %s = %s/%s", code, text, + ip_to_str((guint8*)&pd[voff+2]), + ip_to_str((guint8*)&pd[voff+6])); + } + /* > 1 IP address pair. Let's make a sub-tree */ + else { + + vti = add_item_to_tree(GTK_WIDGET(bp_tree), voff, + consumed, "Option %d: %s", code, text); + v_tree = gtk_tree_new(); + add_subtree(vti, v_tree, ETT_BOOTP_OPTION); + for (i = voff + 2; i < voff + consumed; i += 8) { + add_item_to_tree(v_tree, i, 4, "IP Address/Mask: %s/%s", + ip_to_str((guint8*)&pd[i]), + ip_to_str((guint8*)&pd[i+4])); + } + } + + /* Static Route */ + case 33: + /* one IP address pair */ + if (vlen == 8) { + add_item_to_tree(bp_tree, voff, consumed, + "Option %d: %s = %s/%s", code, text, + ip_to_str((guint8*)&pd[voff+2]), + ip_to_str((guint8*)&pd[voff+6])); + } + /* > 1 IP address pair. Let's make a sub-tree */ + else { + + vti = add_item_to_tree(GTK_WIDGET(bp_tree), voff, + consumed, "Option %d: %s", code, text); + v_tree = gtk_tree_new(); + add_subtree(vti, v_tree, ETT_BOOTP_OPTION); + for (i = voff + 2; i < voff + consumed; i += 8) { + add_item_to_tree(v_tree, i, 4, + "Destination IP Address/Router: %s/%s", + ip_to_str((guint8*)&pd[i]), + ip_to_str((guint8*)&pd[i+4])); + } + } + + /* DHCP Message Type */ + case 53: + if (pd[voff+2] > 0 && pd[voff+2] < 9) { + i = pd[voff + 2]; + } + else { + i = 0; + } + add_item_to_tree(bp_tree, voff, 3, "Option %d: %s = DHCP %s", + code, text, opt53_text[i]); + return vlen + 2; + + /* Client Identifier */ + case 61: + consumed = vlen + 2; + /* We *MAY* use hwtype/hwaddr. If we have 7 bytes, I'll + guess that the first is the hwtype, and the last 6 are + the hw addr */ + if (pd[voff+1] == 7) { + vti = add_item_to_tree(GTK_WIDGET(bp_tree), voff, + consumed, "Option %d: %s", code, text); + v_tree = gtk_tree_new(); + add_subtree(vti, v_tree, ETT_BOOTP_OPTION); + add_item_to_tree(v_tree, voff+2, 1, + "Hardware type: 0x%02x", pd[voff+2]); + add_item_to_tree(v_tree, voff+3, 6, + "Client hardware address: %s", + ether_to_str((guint8*)&pd[voff+3])); + } + /* otherwise, it's opaque data */ + else { + add_item_to_tree(bp_tree, voff, consumed, + "Option %d: %s (%d bytes)", code, text, vlen); + } + return consumed; + + /* End Option */ + case 255: + add_item_to_tree(bp_tree, voff, 1, "End Option", code); + consumed = 1; + return consumed; + + default: + /* nothing */ + } + + /* Normal cases */ + if (code < NUM_OPT_INFOS) { + consumed = vlen + 2; + text = opt[code].text; + ftype = opt[code].ftype; + + switch (ftype) { + case ipv4: + /* one IP address */ + if (vlen == 4) { + add_item_to_tree(bp_tree, voff, consumed, + "Option %d: %s = %s", code, text, + ip_to_str((guint8*)&pd[voff+2])); + } + /* > 1 IP addresses. Let's make a sub-tree */ + else { + + vti = add_item_to_tree(GTK_WIDGET(bp_tree), voff, + consumed, "Option %d: %s", code, text); + v_tree = gtk_tree_new(); + add_subtree(vti, v_tree, ETT_BOOTP_OPTION); + for (i = voff + 2; i < voff + consumed; i += 4) { + add_item_to_tree(v_tree, i, 4, "IP Address: %s", + ip_to_str((guint8*)&pd[i])); + } + } + break; + + case string: + add_item_to_tree(bp_tree, voff, consumed, + "Option %d: %s = %s", code, text, &pd[voff+2]); + break; + + case opaque: + add_item_to_tree(bp_tree, voff, consumed, + "Option %d: %s = %s (%d bytes)", + code, text, &pd[voff+2], vlen); + break; + + case val_u_short: + /* one IP address */ + if (vlen == 2) { + add_item_to_tree(bp_tree, voff, consumed, + "Option %d: %s = %d", code, text, + pntohs(&pd[voff+2])); + } + /* > 1 u_short */ + else { + vti = add_item_to_tree(GTK_WIDGET(bp_tree), voff, + consumed, "Option %d: %s", code, text); + v_tree = gtk_tree_new(); + add_subtree(vti, v_tree, ETT_BOOTP_OPTION); + for (i = voff + 2; i < voff + consumed; i += 2) { + add_item_to_tree(v_tree, i, 4, "Value: %d", + pntohs(&pd[i])); + } + } + break; + + case val_u_long: + add_item_to_tree(bp_tree, voff, consumed, + "Option %d: %s = %d", code, text, + pntohl(&pd[voff+2])); + break; + + case val_u_byte: + add_item_to_tree(bp_tree, voff, consumed, + "Option %d: %s = %d", code, text, pd[voff+2]); + break; + + case toggle: + i = pd[voff+2]; + if (i != 0 && i != 1) { + add_item_to_tree(bp_tree, voff, consumed, + "Option %d: %s = Invalid Value %d", code, text, + pd[voff+2]); + } + else { + add_item_to_tree(bp_tree, voff, consumed, + "Option %d: %s = %s", code, text, + pd[voff+2] == 0 ? "Disabled" : "Enabled"); + } + break; + + case yes_no: + i = pd[voff+2]; + if (i != 0 && i != 1) { + add_item_to_tree(bp_tree, voff, consumed, + "Option %d: %s = Invalid Value %d", code, text, + pd[voff+2]); + } + else { + add_item_to_tree(bp_tree, voff, consumed, + "Option %d: %s = %s", code, text, + pd[voff+2] == 0 ? "No" : "Yes"); + } + break; + + default: + add_item_to_tree(bp_tree, voff, consumed, "Option %d: %s", + code, text); + } + } + else { + add_item_to_tree(bp_tree, voff, 1, "Unknown Option Code: %d", code); + } + + return consumed; +} + +void +dissect_bootp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) +{ + GtkWidget *bp_tree, *ti; + int voff, eoff; /* vender offset, end offset */ + int vlen; + + if (fd->win_info[0]) { + strcpy(fd->win_info[3], "BOOTP"); + + /* if hwaddr is 6 bytes, assume MAC */ + if (pd[offset] == 1 && pd[offset+2] == 6) { + sprintf(fd->win_info[4], "Boot Request from %s", + ether_to_str((guint8*)&pd[offset+28])); + } + else { + strcpy(fd->win_info[4], pd[offset] == 1 ? "Boot Request" : + "Boot Reply"); + } + } + + if (tree) { + ti = add_item_to_tree(GTK_WIDGET(tree), offset, fd->cap_len - offset, + "Bootstrap Protocol"); + bp_tree = gtk_tree_new(); + add_subtree(ti, bp_tree, ETT_BOOTP); + + add_item_to_tree(bp_tree, offset, 1, pd[offset] == 1 ? + "Boot Request" : "Boot Reply"); + add_item_to_tree(bp_tree, offset + 1, 1, + "Hardware type: 0x%02x", pd[offset+1]); + add_item_to_tree(bp_tree, offset + 2, 1, + "Hardware address length: %d", pd[offset+2]); + add_item_to_tree(bp_tree, offset + 3, 1, + "Hops: %d", pd[offset+3]); + add_item_to_tree(bp_tree, offset + 4, 4, + "Transaction ID: 0x%08x", pntohl(&pd[offset+4])); + add_item_to_tree(bp_tree, offset + 8, 2, + "Seconds elapsed: %d", pntohs(&pd[offset+8])); + add_item_to_tree(bp_tree, offset + 10, 2, + "Broadcast flag: %d", pd[offset+10] & 1); + add_item_to_tree(bp_tree, offset + 12, 4, + "Client IP address: %s", ip_to_str((guint8*)&pd[offset+12])); + add_item_to_tree(bp_tree, offset + 16, 4, + "Your (client) IP address: %s", ip_to_str((guint8*)&pd[offset+16])); + add_item_to_tree(bp_tree, offset + 20, 4, + "Next server IP address: %s", ip_to_str((guint8*)&pd[offset+20])); + add_item_to_tree(bp_tree, offset + 24, 4, + "Relay agent IP address: %s", ip_to_str((guint8*)&pd[offset+24])); + + /* If HW address is 6 bytes, assume MAC. */ + if (pd[offset+2] == 6) { + add_item_to_tree(bp_tree, offset + 28, 6, + "Client hardware address: %s", + ether_to_str((guint8*)&pd[offset+28])); + } + else { + add_item_to_tree(bp_tree, offset + 28, 16, + "Client hardware address: %02x:%02x%02x:%02x:%02x:%02x:%02x:%02x%02x:%02x%02x:%02x:%02x:%02x:%02x:%02x", + pd[offset+28], pd[offset+29], pd[offset+30], pd[offset+31], + pd[offset+32], pd[offset+33], pd[offset+34], pd[offset+35], + pd[offset+36], pd[offset+37], pd[offset+38], pd[offset+39], + pd[offset+40], pd[offset+41], pd[offset+42], pd[offset+43]); + } + + /* The server host name is optional */ + if (pd[offset+44]) { + add_item_to_tree(bp_tree, offset + 44, 64, + "Server host name: %s", &pd[offset+44]); + } + else { + add_item_to_tree(bp_tree, offset + 44, 64, + "Server host name not given"); + } + + /* Boot file */ + if (pd[offset+108]) { + add_item_to_tree(bp_tree, offset + 108, 128, + "Boot file nme: %s", &pd[offset+108]); + } + else { + add_item_to_tree(bp_tree, offset + 108, 128, + "Boot file name not given"); + } + + if (pntohl(&pd[offset+236]) == 0x63538263) { + add_item_to_tree(bp_tree, offset + 236, 4, + "Magic cookie: %s (generic)", + ip_to_str((guint8*)&pd[offset+236])); + } + else { + add_item_to_tree(bp_tree, offset + 236, 4, + "Magic cookie: %s", + ip_to_str((guint8*)&pd[offset+236])); + } + + voff = offset+240; + eoff = fd->cap_len; + + while (voff < eoff) { + voff += bootp_option(pd, bp_tree, voff, eoff); + } + } +} + diff --git a/packet-data.c b/packet-data.c new file mode 100644 index 0000000000..5437bd3e47 --- /dev/null +++ b/packet-data.c @@ -0,0 +1,51 @@ + +/* packet-data.c + * Routines for raw data (default case) + * Gilbert Ramirez + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#include "ethereal.h" +#include "packet.h" + + +void +dissect_data(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) { + + if (fd->cap_len > offset && tree) { + (void) add_item_to_tree(GTK_WIDGET(tree), offset, fd->cap_len - offset, + "Data"); + } +} + diff --git a/packet-dns.c b/packet-dns.c new file mode 100644 index 0000000000..c4ef11f7ce --- /dev/null +++ b/packet-dns.c @@ -0,0 +1,442 @@ +/* packet-dns.c + * Routines for DNS packet disassembly + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#ifdef HAVE_NETINET_IN_H +# include +#endif + +#include "packet.h" + + +/* DNS structs and definitions */ + +typedef struct _e_dns { + guint16 dns_id; + guint16 dns_flags; + guint16 dns_quest; + guint16 dns_ans; + guint16 dns_auth; + guint16 dns_add; +} e_dns; + +#define MAXDNAME 1025 /* maximum domain name */ + +/* type values */ +#define T_A 1 /* host address */ +#define T_NS 2 /* authoritative server */ +#define T_CNAME 5 /* canonical name */ +#define T_SOA 6 /* start of authority zone */ +#define T_WKS 11 /* well known service */ +#define T_PTR 12 /* domain name pointer */ +#define T_HINFO 13 /* host information */ +#define T_MX 15 /* mail routing information */ +#define T_TXT 16 /* text strings */ +#define T_AAAA 28 /* IP6 Address */ + + +static const u_char *dns_data_ptr; + +static char * +dns_type_name (int type) +{ + char *type_names[36] = { + "unused", "A", "NS", "MD", "MF", "CNAME", "SOA", "MB", "MG", "MR", + "NULL", "WKS", "PTR", "HINFO", "MINFO", "MX", "TXT", "RP", "AFSDB", + "X25", "ISDN", "RT", "NSAP", "NSAP_PTR", "SIG", "KEY", "PX", "GPOS", + "AAAA", "LOC", "NXT", "EID", "NIMLOC", "SRV", "ATMA", "NAPTR" + }; + + if (type <= 35) + return type_names[type]; + + /* special cases */ + switch (type) + { + /* non standard */ + case 100: + return "UINFO"; + case 101: + return "UID"; + case 102: + return "GID"; + case 103: + return "UNSPEC"; + + /* queries */ + case 251: + return "IXFR"; + case 252: + return "AXFR"; + case 253: + return "MAILB"; + case 254: + return "MAILA"; + case 255: + return "ANY"; + } + + return "unknown"; +} + + +static char * +dns_class_name(int class) +{ + char *class_name; + + switch (class) { + case 1: + class_name = "inet"; + break; + case 3: + class_name = "chaos"; + break; + case 4: + class_name = "hesiod"; + break; + default: + class_name = "unknown"; + } + + return class_name; +} + + +static int +is_compressed_name(const u_char *foo) +{ + return (0xc0 == (*foo & 0xc0)); +} + + +static int +get_compressed_name_offset(const u_char *ptr) +{ + return ((*ptr & ~0xc0) << 8) | *(ptr+1); +} + + +static int +copy_one_name_component(const u_char *dataptr, char *nameptr) +{ + int len; + int n; + + len = n = *dataptr++; + if (0 == len) + return 0; + + while (n-- > 0) + *nameptr++ = *dataptr++; + + return len; +} + + +static int +copy_name_component_rec(const u_char *dataptr, char *nameptr, int *real_string_len) +{ + int len = 0; + int str_len; + int offset; + int compress = 0; + + if (is_compressed_name(dataptr)) { + compress = 1; + offset = get_compressed_name_offset(dataptr); + dataptr = dns_data_ptr + offset; + copy_name_component_rec(dataptr, nameptr, &str_len); + *real_string_len += str_len; + nameptr += str_len; + len = 2; + } + else { + str_len = copy_one_name_component(dataptr, nameptr); + *real_string_len = str_len; + dataptr += str_len + 1; + len += str_len + 1; + nameptr += str_len; + } + + if (compress) + return len; + + (*real_string_len)++; + + if (*dataptr > 0) { + *nameptr++ = '.'; + len += copy_name_component_rec(dataptr, nameptr, &str_len); + *real_string_len += str_len; + return len; + } + + return len + 1; +} + + +static int +get_dns_name(const u_char *pd, int offset, char *nameptr, int maxname) +{ + int len; + const u_char *dataptr = pd + offset; + int str_len = 0; + + memset (nameptr, 0, maxname); + len = copy_name_component_rec(dataptr, nameptr, &str_len); + + return len; +} + + +static int +get_dns_name_type_class (const u_char *pd, + int offset, + char *name_ret, + int *type_ret, + int *class_ret) +{ + int len; + int name_len; + int type; + int class; + char name[MAXDNAME]; + const u_char *pd_save; + + name_len = get_dns_name(pd, offset, name, sizeof(name)); + pd += offset; + pd_save = pd; + pd += name_len; + + type = (*pd << 8) | *(pd + 1); + pd += 2; + class = (*pd << 8) | *(pd + 1); + pd += 2; + + strcpy (name_ret, name); + *type_ret = type; + *class_ret = class; + + len = pd - pd_save; + return len; +} + + +static int +dissect_dns_query(const u_char *pd, int offset, GtkWidget *dns_tree) +{ + int len; + char name[MAXDNAME]; + int type; + int class; + char *class_name; + char *type_name; + + len = get_dns_name_type_class (pd, offset, name, &type, &class); + + type_name = dns_type_name(type); + class_name = dns_class_name(class); + + add_item_to_tree(dns_tree, offset, len, "%s: type %s, class %s", + name, type_name, class_name ); + + return len; +} + + +static int +dissect_dns_answer(const u_char *pd, int offset, GtkWidget *dns_tree) +{ + int len; + char name[MAXDNAME]; + int type; + int class; + char *class_name; + char *type_name; + const u_char *dptr; + const u_char *data_start; + const u_char *res_ptr; + u_int ttl; + u_short data_len; + + data_start = dptr = pd + offset; + + len = get_dns_name_type_class (pd, offset, name, &type, &class); + dptr += len; + + /* this works regardless of the alignment */ + ttl = (*dptr << 24) | *(dptr + 1) << 16 | *(dptr + 2) << 8 | *(dptr + 3); + dptr += 4; + data_len = (*dptr << 8) | *(dptr + 1); + dptr += 2; + + type_name = dns_type_name(type); + class_name = dns_class_name(class); + res_ptr = dptr; + + /* skip the resource data */ + dptr += data_len; + + len = dptr - data_start; + + switch (type) { + case T_A: /* "A" record */ + add_item_to_tree(dns_tree, offset, len, + "%s: type %s, class %s, addr %d.%d.%d.%d", + name, type_name, class_name, + *res_ptr, *(res_ptr+1), *(res_ptr+2), *(res_ptr+3)); + break; + + case T_NS: /* "NS" record */ + { + char ns_name[MAXDNAME]; + + get_dns_name(res_ptr, 0, ns_name, sizeof(ns_name)); + add_item_to_tree(dns_tree, offset, len, + "%s: %s, type %s, class %s", + name, ns_name, type_name, class_name); + + } + break; + + /* TODO: parse more record types */ + + default: + add_item_to_tree(dns_tree, offset, len, "%s: type %s, class %s", + name, type_name, class_name); + } + + return len; +} + + +static int +dissect_answer_records(int count, const u_char *pd, int cur_off, + GtkWidget *dns_tree, char *name) +{ + int start_off; + GtkWidget *qatree, *ti; + + qatree = gtk_tree_new(); + start_off = cur_off; + + while (count-- > 0) + cur_off += dissect_dns_answer(pd, cur_off, qatree); + ti = add_item_to_tree(GTK_WIDGET(dns_tree), start_off, cur_off - start_off, name); + add_subtree(ti, qatree, ETT_DNS_ANS); + + return cur_off - start_off; +} + + +static int +dissect_query_records(int count, const u_char *pd, + int cur_off, GtkWidget *dns_tree) +{ + int start_off; + GtkWidget *qatree, *ti; + + qatree = gtk_tree_new(); + start_off = cur_off; + + while (count-- > 0) + cur_off += dissect_dns_query(pd, cur_off, qatree); + ti = add_item_to_tree(GTK_WIDGET(dns_tree), + start_off, cur_off - start_off, "Queries"); + add_subtree(ti, qatree, ETT_DNS_QRY); + + return cur_off - start_off; +} + + + +void +dissect_dns(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) { + e_dns *dh; + GtkWidget *dns_tree, *ti; + guint16 id, flags, quest, ans, auth, add; + int query = 0; + int cur_off; + + dns_data_ptr = &pd[offset]; + dh = (e_dns *) dns_data_ptr; + + /* To do: check for runts, errs, etc. */ + id = ntohs(dh->dns_id); + flags = ntohs(dh->dns_flags); + quest = ntohs(dh->dns_quest); + ans = ntohs(dh->dns_ans); + auth = ntohs(dh->dns_auth); + add = ntohs(dh->dns_add); + + query = ! (flags & (1 << 15)); + + if (fd->win_info[0]) { + strcpy(fd->win_info[3], "DNS (UDP)"); + strcpy(fd->win_info[4], query ? "Query" : "Response"); + } + + if (tree) { + ti = add_item_to_tree(GTK_WIDGET(tree), offset, 4, + query ? "DNS query" : "DNS response"); + + dns_tree = gtk_tree_new(); + add_subtree(ti, dns_tree, ETT_DNS); + + add_item_to_tree(dns_tree, offset, 2, "ID: 0x%04x", id); + + add_item_to_tree(dns_tree, offset + 2, 2, "Flags: 0x%04x", flags); + add_item_to_tree(dns_tree, offset + 4, 2, "Questions: %d", quest); + add_item_to_tree(dns_tree, offset + 6, 2, "Answer RRs: %d", ans); + add_item_to_tree(dns_tree, offset + 8, 2, "Authority RRs: %d", auth); + add_item_to_tree(dns_tree, offset + 10, 2, "Additional RRs: %d", add); + + cur_off = offset + 12; + + if (quest > 0) + cur_off += dissect_query_records(quest, pd, cur_off, dns_tree); + + if (ans > 0) + cur_off += dissect_answer_records(ans, pd, cur_off, dns_tree, "Answers"); + + if (auth > 0) + cur_off += dissect_answer_records(auth, pd, cur_off, dns_tree, + "Authoritative nameservers"); + + if (add > 0) + cur_off += dissect_answer_records(add, pd, cur_off, dns_tree, + "Additional records"); + } +} diff --git a/packet-eth.c b/packet-eth.c new file mode 100644 index 0000000000..cc5c1154b1 --- /dev/null +++ b/packet-eth.c @@ -0,0 +1,125 @@ +/* packet-eth.c + * Routines for ethernet packet disassembly + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include + +#include + +#include "packet.h" +#include "ethereal.h" +#include "etypes.h" + +/* These are the Netware-ish names for the different Ethernet frame types. + EthernetII: The ethernet with a Type field instead of a length field + Ethernet802.2: An 802.3 header followed by an 802.3 header + Ethernet802.3: A raw 802.3 packet. IPX/SPX can be the only payload. + There's not 802.2 hdr in this. + EthernetSNAP: Basically 802.2, just with 802.2SNAP. For our purposes, + there's no difference between 802.2 and 802.2SNAP, since we just + pass it down to dissect_llc(). -- Gilbert +*/ +#define ETHERNET_II 0 +#define ETHERNET_802_2 1 +#define ETHERNET_802_3 2 +#define ETHERNET_SNAP 3 + +void +dissect_eth(const u_char *pd, frame_data *fd, GtkTree *tree) { + guint16 etype, length; + int offset = 14; + GtkWidget *fh_tree, *ti; + int ethhdr_type; /* the type of ethernet frame */ + + if (fd->win_info[0]) { + strcpy(fd->win_info[2], ether_to_str((guint8 *)&pd[0])); + strcpy(fd->win_info[1], ether_to_str((guint8 *)&pd[6])); + strcpy(fd->win_info[4], "Ethernet II"); + } + + etype = (pd[12] << 8) | pd[13]; + + /* either ethernet802.3 or ethernet802.2 */ + if (etype <= IEEE_802_3_MAX_LEN) { + length = etype; + + /* Is there an 802.2 layer? I can tell by looking at the first 2 + bytes after the 802.3 header. If they are 0xffff, then what + follows the 802.3 header is an IPX payload, meaning no 802.2. + (IPX/SPX is they only thing that can be contained inside a + straight 802.3 packet). A non-0xffff value means that there's an + 802.2 layer inside the 802.3 layer */ + if (pd[14] == 0xff && pd[15] == 0xff) { + ethhdr_type = ETHERNET_802_3; + } + else { + ethhdr_type = ETHERNET_802_2; + } + + if (fd->win_info[0]) { sprintf(fd->win_info[4], "802.3"); } + if (tree) { + ti = add_item_to_tree(GTK_WIDGET(tree), 0, offset, + "IEEE 802.3 %s(%d on wire, %d captured)", + (ethhdr_type == ETHERNET_802_3 ? "Raw " : ""), + fd->pkt_len, fd->cap_len); + + fh_tree = gtk_tree_new(); + add_subtree(ti, fh_tree, ETT_IEEE8023); + add_item_to_tree(fh_tree, 0, 6, "Destination: %s", + ether_to_str((guint8 *) &pd[0])); + add_item_to_tree(fh_tree, 6, 6, "Source: %s", + ether_to_str((guint8 *) &pd[6])); + add_item_to_tree(fh_tree, 12, 2, "Length: %d", length); + } + + } else if (tree) { + ethhdr_type = ETHERNET_II; + ti = add_item_to_tree(GTK_WIDGET(tree), 0, 14, + "Ethernet II (%d on wire, %d captured)", fd->pkt_len, fd->cap_len); + fh_tree = gtk_tree_new(); + add_subtree(ti, fh_tree, ETT_ETHER2); + add_item_to_tree(fh_tree, 0, 6, "Destination: %s", + ether_to_str((guint8 *) &pd[0])); + add_item_to_tree(fh_tree, 6, 6, "Source: %s", + ether_to_str((guint8 *) &pd[6])); + } + + /* either ethernet802.3 or ethernet802.2 */ + switch (ethhdr_type) { + case ETHERNET_802_3: + dissect_ipx(pd, offset, fd, tree); + return; + case ETHERNET_802_2: + dissect_llc(pd, offset, fd, tree); + return; + } + + /* Ethernet_II */ + ethertype(etype, offset, pd, fd, tree, fh_tree); +} + diff --git a/packet-ip.c b/packet-ip.c new file mode 100644 index 0000000000..3675e28a8f --- /dev/null +++ b/packet-ip.c @@ -0,0 +1,319 @@ +/* packet-ip.c + * Routines for IP and miscellaneous IP protocol packet disassembly + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#ifdef HAVE_NETINET_IN_H +# include +#endif + +#include "ethereal.h" +#include "packet.h" +#include "etypes.h" +#include "resolv.h" + +void +dissect_ip(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) { + e_ip iph; + GtkWidget *ip_tree, *ti; + gchar tos_str[32]; + + /* To do: check for runts, errs, etc. */ + /* Avoids alignment problems on many architectures. */ + memcpy(&iph, &pd[offset], sizeof(e_ip)); + iph.ip_len = ntohs(iph.ip_len); + iph.ip_id = ntohs(iph.ip_id); + iph.ip_off = ntohs(iph.ip_off); + iph.ip_sum = ntohs(iph.ip_sum); + + if (fd->win_info[0]) { + switch (iph.ip_p) { + case IP_PROTO_ICMP: + case IP_PROTO_IGMP: + case IP_PROTO_TCP: + case IP_PROTO_UDP: + case IP_PROTO_OSPF: + /* Names are set in the associated dissect_* routines */ + break; + default: + strcpy(fd->win_info[3], "IP"); + sprintf(fd->win_info[4], "Unknown IP protocol (%02x)", iph.ip_p); + } + + strcpy(fd->win_info[1], get_hostname(iph.ip_src)); + strcpy(fd->win_info[2], get_hostname(iph.ip_dst)); + } + + iph.ip_tos = IPTOS_TOS(iph.ip_tos); + switch (iph.ip_tos) { + case IPTOS_NONE: + strcpy(tos_str, "None"); + break; + case IPTOS_LOWDELAY: + strcpy(tos_str, "Minimize delay"); + break; + case IPTOS_THROUGHPUT: + strcpy(tos_str, "Maximize throughput"); + break; + case IPTOS_RELIABILITY: + strcpy(tos_str, "Maximize reliability"); + break; + case IPTOS_LOWCOST: + strcpy(tos_str, "Minimize cost"); + break; + default: + strcpy(tos_str, "Unknon. Malformed?"); + break; + } + + if (tree) { + ti = add_item_to_tree(GTK_WIDGET(tree), offset, (iph.ip_hl * 4), + "Internet Protocol"); + ip_tree = gtk_tree_new(); + add_subtree(ti, ip_tree, ETT_IP); + add_item_to_tree(ip_tree, offset, 1, "Version: %d", iph.ip_v); + add_item_to_tree(ip_tree, offset, 1, "Header length: %d", iph.ip_hl); + add_item_to_tree(ip_tree, offset + 1, 1, "Type of service: 0x%02x (%s)", + iph.ip_tos, tos_str); + add_item_to_tree(ip_tree, offset + 2, 2, "Total length: %d", iph.ip_len); + add_item_to_tree(ip_tree, offset + 4, 2, "Identification: 0x%04x", + iph.ip_id); + /* To do: add flags */ + add_item_to_tree(ip_tree, offset + 6, 2, "Fragment offset: %d", + iph.ip_off & 0x1fff); + add_item_to_tree(ip_tree, offset + 8, 1, "Time to live: %d", + iph.ip_ttl); + add_item_to_tree(ip_tree, offset + 9, 1, "Protocol: 0x%02x", + iph.ip_p); + add_item_to_tree(ip_tree, offset + 10, 2, "Header checksum: 0x%04x", + iph.ip_sum); + add_item_to_tree(ip_tree, offset + 12, 4, "Source address: %s", + get_hostname(iph.ip_src)); + add_item_to_tree(ip_tree, offset + 16, 4, "Destination address: %s", + get_hostname(iph.ip_dst)); + } + + offset += iph.ip_hl * 4; + switch (iph.ip_p) { + case IP_PROTO_ICMP: + dissect_icmp(pd, offset, fd, tree); + break; + case IP_PROTO_IGMP: + dissect_igmp(pd, offset, fd, tree); + break; + case IP_PROTO_TCP: + dissect_tcp(pd, offset, fd, tree); + break; + case IP_PROTO_UDP: + dissect_udp(pd, offset, fd, tree); + break; + case IP_PROTO_OSPF: + dissect_ospf(pd, offset, fd, tree); + break; + } +} + + +const gchar *unreach_str[] = {"Network unreachable", + "Host unreachable", + "Protocol unreachable", + "Port unreachable", + "Fragmentation needed", + "Source route failed", + "Administratively prohibited", + "Network unreachable for TOS", + "Host unreachable for TOS", + "Communication administratively filtered", + "Host precedence violation", + "Precedence cutoff in effect"}; + +const gchar *redir_str[] = {"Redirect for network", + "Redirect for host", + "Redirect for TOS and network", + "Redirect for TOS and host"}; + +const gchar *ttl_str[] = {"TTL equals 0 during transit", + "TTL equals 0 during reassembly"}; + +const gchar *par_str[] = {"IP header bad", "Required option missing"}; + +void +dissect_icmp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) { + e_icmp *ih; + GtkWidget *icmp_tree, *ti; + guint16 cksum; + gchar type_str[64], code_str[64] = ""; + + ih = (e_icmp *) &pd[offset]; + /* To do: check for runts, errs, etc. */ + cksum = ntohs(ih->icmp_cksum); + + switch (ih->icmp_type) { + case ICMP_ECHOREPLY: + strcpy(type_str, "Echo (ping) reply"); + break; + case ICMP_UNREACH: + strcpy(type_str, "Destination unreachable"); + if (ih->icmp_code < 12) { + sprintf(code_str, "(%s)", unreach_str[ih->icmp_code]); + } else { + strcpy(code_str, "(Unknown - error?)"); + } + break; + case ICMP_SOURCEQUENCH: + strcpy(type_str, "Source quench (flow control)"); + break; + case ICMP_REDIRECT: + strcpy(type_str, "Redirect"); + if (ih->icmp_code < 4) { + sprintf(code_str, "(%s)", redir_str[ih->icmp_code]); + } else { + strcpy(code_str, "(Unknown - error?)"); + } + break; + case ICMP_ECHO: + strcpy(type_str, "Echo (ping) request"); + break; + case ICMP_TIMXCEED: + strcpy(type_str, "Time-to-live exceeded"); + if (ih->icmp_code < 2) { + sprintf(code_str, "(%s)", ttl_str[ih->icmp_code]); + } else { + strcpy(code_str, "(Unknown - error?)"); + } + break; + case ICMP_PARAMPROB: + strcpy(type_str, "Parameter problem"); + if (ih->icmp_code < 2) { + sprintf(code_str, "(%s)", par_str[ih->icmp_code]); + } else { + strcpy(code_str, "(Unknown - error?)"); + } + break; + case ICMP_TSTAMP: + strcpy(type_str, "Timestamp request"); + break; + case ICMP_TSTAMPREPLY: + strcpy(type_str, "Timestamp reply"); + break; + case ICMP_MASKREQ: + strcpy(type_str, "Address mask request"); + break; + case ICMP_MASKREPLY: + strcpy(type_str, "Address mask reply"); + break; + default: + strcpy(type_str, "Unknown ICMP (obsolete or malformed?)"); + } + + if (fd->win_info[0]) { + strcpy(fd->win_info[3], "ICMP"); + strcpy(fd->win_info[4], type_str); + } + + if (tree) { + ti = add_item_to_tree(GTK_WIDGET(tree), offset, 4, + "Internet Control Message Protocol"); + icmp_tree = gtk_tree_new(); + add_subtree(ti, icmp_tree, ETT_ICMP); + add_item_to_tree(icmp_tree, offset, 1, "Type: %d (%s)", + ih->icmp_type, type_str); + add_item_to_tree(icmp_tree, offset + 1, 1, "Code: %d %s", + ih->icmp_code, code_str); + add_item_to_tree(icmp_tree, offset + 2, 2, "Checksum: 0x%04x", + ih->icmp_cksum); + } +} + +void +dissect_igmp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) { + e_igmp *ih; + GtkWidget *igmp_tree, *ti; + guint16 cksum; + gchar type_str[64] = ""; + + ih = (e_igmp *) &pd[offset]; + /* To do: check for runts, errs, etc. */ + cksum = ntohs(ih->igmp_cksum); + + switch (ih->igmp_t) { + case IGMP_M_QRY: + strcpy(type_str, "Router query"); + break; + case IGMP_V1_M_RPT: + strcpy(type_str, "Host response (v1)"); + break; + case IGMP_V2_LV_GRP: + strcpy(type_str, "Leave group (v2)"); + break; + case IGMP_DVMRP: + strcpy(type_str, "DVMRP"); + break; + case IGMP_PIM: + strcpy(type_str, "PIM"); + break; + case IGMP_V2_M_RPT: + strcpy(type_str, "Host reponse (v2)"); + break; + case IGMP_MTRC_RESP: + strcpy(type_str, "Traceroute response"); + break; + case IGMP_MTRC: + strcpy(type_str, "Traceroute message"); + break; + default: + strcpy(type_str, "Unknown IGMP"); + } + + if (fd->win_info[0]) { + strcpy(fd->win_info[3], "IGMP"); + } + + if (tree) { + ti = add_item_to_tree(GTK_WIDGET(tree), offset, 4, + "Internet Group Management Protocol"); + igmp_tree = gtk_tree_new(); + add_subtree(ti, igmp_tree, ETT_IGMP); + add_item_to_tree(igmp_tree, offset, 1, "Version: %d", + ih->igmp_v); + add_item_to_tree(igmp_tree, offset , 1, "Type: %d (%s)", + ih->igmp_t, type_str); + add_item_to_tree(igmp_tree, offset + 1, 1, "Unused: 0x%02x", + ih->igmp_unused); + add_item_to_tree(igmp_tree, offset + 2, 2, "Checksum: 0x%04x", + ih->igmp_cksum); + add_item_to_tree(igmp_tree, offset + 4, 4, "Group address: %s", + ip_to_str((guint8 *) &ih->igmp_gaddr)); + } +} diff --git a/packet-ipv6.c b/packet-ipv6.c new file mode 100644 index 0000000000..c2a84b6678 --- /dev/null +++ b/packet-ipv6.c @@ -0,0 +1,105 @@ +/* packet-ipv6.c + * Routines for IPv6 packet disassembly + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#ifdef HAVE_NETINET_IN_H +# include +#endif + +#include "ethereal.h" +#include "packet.h" +#include "packet-ipv6.h" +#include "etypes.h" + +void +dissect_ipv6(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) { + GtkWidget *ipv6_tree, *ti; + + e_ipv6_header ipv6; + + memcpy(&ipv6, (void *) &pd[offset], 8); + + if (fd->win_info[0]) { + switch(ipv6.next_header){ + /* + case IP_PROTO_ICMP: + case IP_PROTO_IGMP: + case IP_PROTO_TCP: + case IP_PROTO_UDP: + case IP_PROTO_OSPF: + */ + /* Names are set in the associated dissect_* routines */ + /* break; */ + default: + strcpy(fd->win_info[3], "IPv6"); + sprintf(fd->win_info[4], "IPv6 support is still under development (%d)", ipv6.next_header); + } + } + if (tree) { + /* !!! specify length */ + ti = add_item_to_tree(GTK_WIDGET(tree), offset, 40, + "Internet Protocol Version 6"); + ipv6_tree = gtk_tree_new(); + add_subtree(ti, ipv6_tree, ETT_IPv6); + + /* !!! warning: version also contains 4 Bit priority */ + add_item_to_tree(ipv6_tree, offset, 1, "Version: %d Priority: %d", ipv6.version >> 4 , ipv6.version & 15); + add_item_to_tree(ipv6_tree, offset + 6, 1, "Next Header: %d", ipv6.next_header); + add_item_to_tree(ipv6_tree, offset + 4, 2, "Payload Length: %d", ntohs(ipv6.payload_length)); + } + + /* start of the new header (could be a extension header) */ + offset += 40; + switch (ipv6.next_header) { + case IP_PROTO_ICMP: + dissect_icmp(pd, offset, fd, tree); + break; + case IP_PROTO_IGMP: + dissect_igmp(pd, offset, fd, tree); + break; + case IP_PROTO_TCP: + dissect_tcp(pd, offset, fd, tree); + break; + case IP_PROTO_UDP: + dissect_udp(pd, offset, fd, tree); + break; + case IP_PROTO_OSPF: + dissect_ospf(pd, offset, fd, tree); + break; + default: + dissect_data(pd, offset, fd, tree); + } +} + diff --git a/packet-ipv6.h b/packet-ipv6.h new file mode 100644 index 0000000000..75ac3d9dd0 --- /dev/null +++ b/packet-ipv6.h @@ -0,0 +1,8 @@ +typedef struct _e_ipv6_header{ + /* the version contains 4-bit version and 4-bit priority */ + guint8 version; + guint8 flow_label[3]; + guint16 payload_length; + guint8 next_header; + guint8 hop_limit; +} e_ipv6_header; diff --git a/packet-ipx.c b/packet-ipx.c new file mode 100644 index 0000000000..53c3f3f770 --- /dev/null +++ b/packet-ipx.c @@ -0,0 +1,492 @@ +/* packet-ipx.c + * Routines for NetWare's IPX + * Gilbert Ramirez + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include + +#include + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#ifdef HAVE_NETINET_IN_H +# include +#endif + +#include "ethereal.h" +#include "packet.h" + +/* The information in this module (IPX, SPX, NCP) comes from: + NetWare LAN Analysis, Second Edition + Laura A. Chappell and Dan E. Hakes + (c) 1994 Novell, Inc. + Novell Press, San Jose. + ISBN: 0-7821-1362-1 +*/ + +static void +dissect_spx(const u_char *pd, int offset, frame_data *fd, GtkTree *tree); +static void +dissect_ncp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree); + + +struct port_info { + u_short port; + char *text; +}; + +struct conn_info { + u_char ctrl; + char *text; +}; + +struct req_info { + u_short req; + char *text; +}; + +/* ================================================================= */ +/* IPX */ +/* ================================================================= */ +static char* +port_text(u_short port) { + int i=0; + + static struct port_info ports[] = { + { 0x0451, "NCP" }, + { 0x0452, "SAP" }, + { 0x0453, "RIP" }, + { 0x0455, "NetBIOS" }, + { 0x0456, "Diagnostic" }, + { 0x0457, "Serialization" }, + { 0x0000, NULL } + }; + + while (ports[i].text != NULL) { + if (ports[i].port == port) { + return ports[i].text; + } + i++; + } + return "Unknown"; +} + +char * +ipx_packet_type(u_char val) +{ + if (val == 0) { + return "IPX"; + } + else if (val == 5) { + return "SPX"; + } + else if (val == 17) { + return "NCP"; + } + else if (val == 20) { + return "NetBIOS"; + } + else if (val >= 16 && val <= 31) { + return "Experimental Protocol"; + } + else { + return "Unknown"; + } +} + +gchar* +network_to_string(const guint8 *ad) +{ + static gchar str[3][12]; + static gchar *cur; + + if (cur == &str[0][0]) { + cur = &str[1][0]; + } else if (cur == &str[1][0]) { + cur = &str[2][0]; + } else { + cur = &str[0][0]; + } + + sprintf(cur, "%02X %02X %02X %02X", ad[0], ad[1], ad[2], ad[3]); + return cur; +} + +void +dissect_ipx(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) { + + GtkWidget *ipx_tree, *ti; + u_char ipx_type; + + char *dnet, *snet; + guint16 dsocket, ssocket; + + /* Calculate here for use in win_info[] and in tree */ + dnet = network_to_string((guint8*)&pd[offset+6]); + snet = network_to_string((guint8*)&pd[offset+18]); + dsocket = pntohs(&pd[offset+16]); + + if (fd->win_info[0]) { + strcpy(fd->win_info[3], "IPX"); + /*sprintf(fd->win_info[4], "Network %s --> %s", snet, dnet);*/ + sprintf(fd->win_info[4], "%s (0x%04X)", port_text(dsocket), dsocket); + } + + ipx_type = pd[offset+5]; + + if (tree) { + ti = add_item_to_tree(GTK_WIDGET(tree), offset, 30, + "Internetwork Packet Exchange"); + ipx_tree = gtk_tree_new(); + add_subtree(ti, ipx_tree, ETT_IPX); + add_item_to_tree(ipx_tree, offset, 2, "Checksum: 0x%04X", + (pd[offset] << 8) | pd[offset+1]); + add_item_to_tree(ipx_tree, offset+2, 2, "Length: %d bytes", + (pd[offset+2] << 8) | pd[offset+3]); + add_item_to_tree(ipx_tree, offset+4, 1, "Transport Control: %d hops", + pd[offset+4]); + add_item_to_tree(ipx_tree, offset+5, 1, "Packet Type: %s", + ipx_packet_type(ipx_type)); + add_item_to_tree(ipx_tree, offset+6, 4, "Destination Network: %s", + dnet); + add_item_to_tree(ipx_tree, offset+10, 6, "Destination Node: %s", + ether_to_str((guint8*)&pd[offset+10])); + /*dsocket = ntohs(*((guint16*)&pd[offset+16]));*/ + add_item_to_tree(ipx_tree, offset+16, 2, + "Destination Socket: %s (0x%04X)", port_text(dsocket), dsocket); + add_item_to_tree(ipx_tree, offset+18, 4, "Source Network: %s", + snet); + add_item_to_tree(ipx_tree, offset+22, 6, "Source Node: %s", + ether_to_str((guint8*)&pd[offset+22])); + ssocket = pntohs(&pd[offset+28]); + add_item_to_tree(ipx_tree, offset+28, 2, + "Source Socket: %s (0x%04X)", port_text(ssocket), ssocket); + } + offset += 30; + + switch (ipx_type) { + case 0: /* IPX */ + dissect_data(pd, offset, fd, tree); /* the IPX payload */ + break; + case 5: /* SPX */ + dissect_spx(pd, offset, fd, tree); + break; + case 17: /* NCP */ + dissect_ncp(pd, offset, fd, tree); + break; + case 20: /* NetBIOS */ + dissect_data(pd, offset, fd, tree); /* until implemented */ + break; + default: + dissect_data(pd, offset, fd, tree); + break; + } +} + + +/* ================================================================= */ +/* SPX */ +/* ================================================================= */ +static char* +spx_conn_ctrl(u_char ctrl) +{ + int i=0; + + static struct conn_info conns[] = { + { 0x10, "End-of-Message" }, + { 0x20, "Attention" }, + { 0x40, "Acknowledgment Required"}, + { 0x80, "System Packet"} + }; + + while (conns[i].text != NULL) { + if (conns[i].ctrl == ctrl) { + return conns[i].text; + } + i++; + } + return "Unknown"; +} + +static char* +datastream(u_char type) +{ + switch (type) { + case 0xfe: + return "End-of-Connection"; + case 0xff: + return "End-of-Connection Acknowledgment"; + default: + return "Client-Defined"; + } +} + +static void +dissect_spx(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) { + + GtkWidget *spx_tree, *ti; + + if (fd->win_info[0]) { + strcpy(fd->win_info[3], "SPX"); + strcpy(fd->win_info[4], "SPX"); + } + + if (tree) { + ti = add_item_to_tree(GTK_WIDGET(tree), offset, 12, + "Sequenced Packet Exchange"); + spx_tree = gtk_tree_new(); + add_subtree(ti, spx_tree, ETT_SPX); + + add_item_to_tree(spx_tree, offset, 1, + "Connection Control: %s (0x%02X)", + spx_conn_ctrl(pd[offset]), pd[offset]); + + add_item_to_tree(spx_tree, offset+1, 1, + "Datastream Type: %s (0x%02X)", + datastream(pd[offset+1]), pd[offset+1]); + + add_item_to_tree(spx_tree, offset+2, 2, + "Source Connection ID: %d", pntohs( &pd[offset+2] ) ); + + add_item_to_tree(spx_tree, offset+4, 2, + "Destination Connection ID: %d", pntohs( &pd[offset+4] ) ); + + add_item_to_tree(spx_tree, offset+6, 2, + "Sequence Number: %d", pntohs( &pd[offset+6] ) ); + + add_item_to_tree(spx_tree, offset+8, 2, + "Acknowledgment Number: %d", pntohs( &pd[offset+8] ) ); + + add_item_to_tree(spx_tree, offset+10, 2, + "Allocation Number: %d", pntohs( &pd[offset+10] ) ); + + offset += 12; + dissect_data(pd, offset, fd, tree); + } +} + +/* ================================================================= */ +/* NCP */ +/* ================================================================= */ +static char* +req_text(u_short req) { + int i=0; + + static struct req_info reqs[] = { + { 0x1111, "Create a service connection" }, + { 0x2222, "Service request" }, + { 0x3333, "Service reply" }, + { 0x5555, "Destroy service connection" }, + { 0x7777, "Burst mode transfer" }, + { 0x9999, "Request being processed" }, + { 0x0000, NULL } + }; + + while (reqs[i].text != NULL) { + if (reqs[i].req == req) { + return reqs[i].text; + } + i++; + } + return "Unknown"; +} + +static char* +ncp2222_func(u_short func) { + int i=0; + + static struct req_info ncp[] = { + { 17, "Print and Queue Services" }, + { 21, "Message Services" }, + { 22, "File and Directory Services" }, + { 23, "Binding and Rights Services" }, + { 34, "Transaction Tacking Services" }, + { 35, "Apple File Services" }, + { 86, "Extended Attributes Services" }, + { 87, "File and Directory Services" }, + { 88, "Auditing Services" }, + { 104, "Netware Directory Services" }, + { 123, "Netware 4.x Statistical Information Services" }, + { 0, NULL } + }; + + while (ncp[i].text != NULL) { + if (ncp[i].req == func) { + return ncp[i].text; + } + i++; + } + return "Unknown"; +} + +static char* +ncp2222_subfunc(u_short func, u_short subfunc) { + int i=0; + struct req_info *info_ptr = NULL; + + /* Accounting Services */ + static struct req_info ncp_23[] = { + { 150, "Get Current Account Status" }, + { 151, "Submit Account Charge" }, + { 152, "Submit Account Hold" }, + { 153, "Submit Account Note" }, + { 0, NULL } + }; + + /* Apple File Services */ + static struct req_info ncp_35[] = { + { 1, "AFP Create Directory" }, + { 2, "AFP Create File" }, + { 3, "AFP Delete" }, + { 4, "AFP Get Entry ID from Name" }, + { 5, "AFP Get File Information" }, + { 6, "AFP Get Entry ID From NetWare Handle" }, + { 7, "AFP Rename" }, + { 8, "AFP Open File Fork" }, + { 9, "AFP Set File Information" }, + { 10, "AFP Scan File Information" }, + { 11, "AFP 2.0 Alloc Temporary Directory Handle" }, + { 12, "AFP Get Entry ID from Name Path" }, + { 13, "AFP 2.0 Create Directory" }, + { 14, "AFP 2.0 Create File" }, +/* ??? { 15, "AFP 2.0 Delete File" }, just guessing */ + { 16, "AFP 2.0 Set File Information" }, + { 17, "AFP 2.0 Scan File Information" }, + { 18, "AFP Get DOS Name from Entry ID" }, + { 19, "AFP Get Macintosh Info on Deleted File" }, + { 0, NULL } + }; + + /* Auditing Services */ + static struct req_info ncp_88[] = { + { 1, "Query Volume Audit Status" }, + { 2, "Add Audit Property" }, + { 3, "Add Auditor Access" }, + + { 0, NULL } + }; + + switch (func) { + case 23: + info_ptr = ncp_23; + break; + case 35: + info_ptr = ncp_35; + break; + case 88: + info_ptr = ncp_88; + break; + default: + return "Unkown function"; + } + + + while (info_ptr[i].text != NULL) { + if (info_ptr[i].req == subfunc) { + printf("subfunc=%s\n", info_ptr[i].text); + return info_ptr[i].text; + } + i++; + } + return "Unknown"; +} + + +static void +dissect_ncp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) { + + GtkWidget *ncp_tree, *ti; + guint16 ncp_type; + int ncp_hdr; + + if (fd->win_info[0]) { + strcpy(fd->win_info[3], "NCP"); + strcpy(fd->win_info[4], "NCP"); + } + + ncp_type = pntohs(&pd[offset]); + + if (ncp_type == 0x1111 || ncp_type == 0x2222 || ncp_type == 0x5555 || + ncp_type == 0x7777) { + ncp_hdr = 6; + } + else if (ncp_type == 0x3333 || ncp_type == 0x9999) { + ncp_hdr = 8; + } + else { + ncp_hdr = 1; /* ? */ + } + + if (tree) { + ti = add_item_to_tree(GTK_WIDGET(tree), offset, ncp_hdr, + "NetWare Core Protocol"); + ncp_tree = gtk_tree_new(); + add_subtree(ti, ncp_tree, ETT_NCP); + + add_item_to_tree(ncp_tree, offset, 2, + "Type: %s", req_text( pntohs( &pd[offset] ) ) ); + + add_item_to_tree(ncp_tree, offset+2, 1, + "Sequence Number: %d", pd[offset+2]); + + add_item_to_tree(ncp_tree, offset+3, 1, + "Connection Number Low: %d", pd[offset+3]); + + add_item_to_tree(ncp_tree, offset+4, 1, + "Task Number: %d", pd[offset+4]); + + add_item_to_tree(ncp_tree, offset+5, 1, + "Connection Number High: %d", pd[offset+5]); + + if (ncp_hdr == 8) { + add_item_to_tree(ncp_tree, offset+6, 1, + "Completion Code: %d", pd[offset+6]); + + add_item_to_tree(ncp_tree, offset+7, 1, + "Connection Status: %d", pd[offset+7]); + } + + offset += ncp_hdr; + + if (ncp_type == 0x2222) { + /* my offset is different now */ + add_item_to_tree(ncp_tree, offset, 1, + "Function Code: %s (%d)", + ncp2222_func(pd[offset]), pd[offset]); + + add_item_to_tree(ncp_tree, offset+2, 1, + "Subfunction Code: %s (%d)", + ncp2222_subfunc(pd[offset], pd[offset+2]), pd[offset+2]); + + offset += 3; + } + + dissect_data(pd, offset, fd, tree); + } +} diff --git a/packet-llc.c b/packet-llc.c new file mode 100644 index 0000000000..2385cda7b6 --- /dev/null +++ b/packet-llc.c @@ -0,0 +1,163 @@ +/* packet-llc.c + * Routines for IEEE 802.2 LLC layer + * Gilbert Ramirez + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include + +#include + +#include "packet.h" +#include "ethereal.h" +#include "etypes.h" + +struct sap_info { + u_char sap; + char *text; +}; + +static char* +sap_text(u_char sap) { + int i=0; + + static struct sap_info saps[] = { + { 0x00, "NULL LSAP" }, + { 0x02, "LLC Sub-Layer Management Individual" }, + { 0x03, "LLC Sub-Layer Management Group" }, + { 0x04, "SNA Path Control Individual" }, + { 0x05, "SNA Path Control Group" }, + { 0x06, "TCP/IP" }, + { 0x08, "SNA" }, + { 0x0C, "SNA" }, + { 0x42, "Spanning Tree BPDU" }, + { 0x7F, "ISO 802.2" }, + { 0x80, "XNS" }, + { 0xAA, "SNAP" }, + { 0xBA, "Banyan Vines" }, + { 0xBC, "Banyan Vines" }, + { 0xE0, "NetWare" }, + { 0xF0, "NetBIOS" }, + { 0xF4, "IBM Net Management Individual" }, + { 0xF5, "IBM Net Management Group" }, + { 0xF8, "Remote Program Load" }, + { 0xFC, "Remote Program Load" }, + { 0xFE, "ISO Network Layer" }, + { 0xFF, "Global LSAP" }, + { 0x00, NULL } + }; + + while (saps[i].text != NULL) { + if (saps[i].sap == sap) { + return saps[i].text; + } + i++; + } + return "Unknown"; +} + +static char* +llc_org(const u_char *ptr) { + + unsigned long org = (ptr[0] << 16) | (ptr[1] << 8) | ptr[2]; + char *llc_org[1] = { + "Encapsulated Ethernet"}; + + if (org > 0) { + return "Unknown"; + } + else { + return llc_org[org]; + } +} + +void +dissect_llc(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) { + + GtkWidget *llc_tree, *ti; + guint16 etype; + int is_snap; + + /* LLC Strings */ + char *llc_ctrl[4] = { + "Information Transfer", "Supervisory", + "", "Unnumbered Information" }; + + is_snap = (pd[offset] == 0xAA) && (pd[offset+1] == 0xAA); + + if (fd->win_info[0]) { + strcpy(fd->win_info[3], "LLC"); + } + + if (tree) { + ti = add_item_to_tree(GTK_WIDGET(tree), offset, (is_snap ? 8 : 3), + "Logical-Link Control"); + llc_tree = gtk_tree_new(); + add_subtree(ti, llc_tree, ETT_LLC); + add_item_to_tree(llc_tree, offset, 1, "DSAP: %s (0x%02X)", + sap_text(pd[offset]), pd[offset]); + add_item_to_tree(llc_tree, offset+1, 1, "SSAP: %s (0x%02X)", + sap_text(pd[offset+1]), pd[offset+1]); + add_item_to_tree(llc_tree, offset+2, 1, "Control: %s", + llc_ctrl[pd[offset+2] & 3]); + } + + if (is_snap) { + if (fd->win_info[0]) { + strcpy(fd->win_info[4], "802.2 LLC (SNAP)"); + } + if (tree) { + add_item_to_tree(llc_tree, offset+3, 3, + "Organization Code: %s (%02X-%02X-%02X)", + llc_org(&pd[offset+3]), + pd[offset+3], pd[offset+4], pd[offset+5]); + } + etype = (pd[offset+6] << 8) | pd[offset+7]; + offset += 8; + ethertype(etype, offset, pd, fd, tree, llc_tree); + } + else { + if (fd->win_info[0]) { + sprintf(fd->win_info[4], "802.2 LLC (%s)", sap_text(pd[offset])); + } + + /* non-SNAP */ + offset += 3; + + switch (pd[offset-3]) { + case 0x06: /* TCP/IP */ + dissect_ip(pd, offset, fd, tree); + break; + case 0xe0: /* NetWare (IPX) */ + dissect_ipx(pd, offset, fd, tree); + break; + default: + dissect_data(pd, offset, fd, tree); + break; + } + } +} diff --git a/packet-lpd.c b/packet-lpd.c new file mode 100644 index 0000000000..0cc52128e6 --- /dev/null +++ b/packet-lpd.c @@ -0,0 +1,154 @@ +/* packet-lpr.c + * Routines for LPR and LPRng packet disassembly + * Gilbert Ramirez + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include +#include + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#ifdef HAVE_NETINET_IN_H +# include +#endif + +#include + +#include "packet.h" +#include "ethereal.h" +#include "etypes.h" + +enum lpr_type { request, response }; + +void +dissect_lpd(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) +{ + GtkWidget *lpd_tree, *ti; + enum lpr_type lpr_packet_type; + char *newline, *printer, *line_pos; + int substr_len, curr_offset; + + /* This information comes from the LPRng HOWTO, which also describes + RFC 1179. http://www.astart.com/lprng/LPRng-HOWTO.html */ + char *lpd_client_code[] = { + "Unknown command", + "LPC: start print", + "LPR: transfer a printer job", + "LPQ: print short form of queue status", + "LPQ: print long form of queue status", + "LPRM: remove jobs", + "LPRng lpc: do control operation", + "LPRng lpr: transfer a block format print job", + "LPRng lpc: secure command transfer", + "LPRng lpq: verbose status information" + }; + char *lpd_server_code[] = { + "Success: accepted, proceed", + "Queue not accepting jobs", + "Queue temporarily full, retry later", + "Bad job format, do not retry" + }; + + + if (pd[offset+1] == '\n') { + lpr_packet_type = response; + } + else if (pd[offset] <= 9) { + lpr_packet_type = request; + } + else { + lpr_packet_type = response; + } + + + if (fd->win_info[0]) { + strcpy(fd->win_info[3], "LPD"); + if (lpr_packet_type == request) { + strcpy(fd->win_info[4], lpd_client_code[pd[offset]]); + } + else { + strcpy(fd->win_info[4], "LPD response"); + } + } + + if (tree) { + ti = add_item_to_tree(GTK_WIDGET(tree), offset, fd->cap_len - offset, + "Line Printer Daemon Protocol"); + lpd_tree = gtk_tree_new(); + add_subtree(ti, lpd_tree, ETT_LPD); + + if (lpr_packet_type == request) { + if (pd[offset] <= 9) { + add_item_to_tree(lpd_tree, offset, 1, + lpd_client_code[pd[offset]]); + } + else { + add_item_to_tree(lpd_tree, offset, 1, + lpd_client_code[0]); + } + printer = strdup(&pd[offset+1]); + + /* get rid of the new-line so that the tree prints out nicely */ + if (printer[fd->cap_len - offset - 2] == 0x0a) { + printer[fd->cap_len - offset - 2] = 0; + } + add_item_to_tree(lpd_tree, offset+1, fd->cap_len - (offset+1), + /*"Printer/options: %s", &pd[offset+1]);*/ + "Printer/options: %s", printer); + free(printer); + } + else { + if (pd[offset] <= 3) { + add_item_to_tree(lpd_tree, offset, 2, "Response: %s", + lpd_server_code[pd[offset]]); + } + else { + printer = strdup(&pd[offset]); + line_pos = printer; + curr_offset = offset; + while (fd->cap_len > curr_offset) { + newline = strchr(line_pos, '\n'); + if (!newline) { + add_item_to_tree(lpd_tree, curr_offset, + fd->cap_len - offset, "Text: %s", line_pos); + break; + } + *newline = 0; + substr_len = strlen(line_pos); + add_item_to_tree(lpd_tree, curr_offset, substr_len + 1, + "Text: %s", line_pos); + curr_offset += substr_len + 1; + line_pos = newline + 1; + } + } + } + } +} + diff --git a/packet-ospf.c b/packet-ospf.c new file mode 100644 index 0000000000..46529dc95e --- /dev/null +++ b/packet-ospf.c @@ -0,0 +1,550 @@ +/* packet-ospf.c + * Routines for OSPF packet disassembly + * (c) Copyright Hannes R. Boehm + * + * At this time, this module is able to analyze OSPF + * packets as specified in RFC2328. MOSPF (RFC1584) and other + * OSPF Extensions which introduce new Packet types + * (e.g the External Atributes LSA) are not supported. + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#ifdef HAVE_NETINET_IN_H +# include +#endif + +#include "ethereal.h" +#include "packet.h" +#include "packet-ospf.h" + + +void +dissect_ospf(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) { + e_ospfhdr *ospfh; + + GtkWidget *ospf_tree = NULL, *ti; + GtkWidget *ospf_header_tree; + char auth_data[9]=""; + char *packet_type; + + ospfh = (e_ospfhdr *) &pd[offset]; + + switch(ospfh->packet_type) { + case OSPF_HELLO: + packet_type="Hello Packet"; + break; + case OSPF_DB_DESC: + packet_type="DB Descr."; + break; + case OSPF_LS_REQ: + packet_type="LS Request"; + break; + case OSPF_LS_UPD: + packet_type="LS Update"; + break; + case OSPF_LS_ACK: + packet_type="LS Acknowledge"; + break; + default: + } + if (fd->win_info[0]) { + strcpy(fd->win_info[3], "OSPF"); + sprintf(fd->win_info[4], "%s", packet_type); + } + + if (tree) { + ti = add_item_to_tree(GTK_WIDGET(tree), offset, ntohs(ospfh->length), "Open Shortest Path First"); + ospf_tree = gtk_tree_new(); + add_subtree(ti, ospf_tree, ETT_OSPF); + + ti = add_item_to_tree(GTK_WIDGET(ospf_tree), offset, OSPF_HEADER_LENGTH, "OSPF Header"); + ospf_header_tree = gtk_tree_new(); + add_subtree(ti, ospf_header_tree, ETT_OSPF_HDR); + + add_item_to_tree(ospf_header_tree, offset, 1, "OSPF Version: %d", ospfh->version); + add_item_to_tree(ospf_header_tree, offset + 1 , 1, "OSPF Packet Type: %d (%s)", + ospfh->packet_type, packet_type); + add_item_to_tree(ospf_header_tree, offset + 2 , 2, "Packet Legth: %d", + ntohs(ospfh->length)); + add_item_to_tree(ospf_header_tree, offset + 4 , 4, "Source OSPF Router ID: %s", + + ip_to_str((guint8 *) &(ospfh->routerid))); + if (!(ospfh->area)) { + add_item_to_tree(ospf_header_tree, offset + 8 , 4, "Area ID: Backbone"); + } else { + add_item_to_tree(ospf_header_tree, offset + 8 , 4, "Area ID: %s", ip_to_str((guint8 *) &(ospfh->area))); + } + add_item_to_tree(ospf_header_tree, offset + 12 , 2, "Packet Checksum"); + switch( ntohs(ospfh->auth_type) ) { + case OSPF_AUTH_NONE: + add_item_to_tree(ospf_header_tree, offset + 14 , 2, "Auth Type: none"); + add_item_to_tree(ospf_header_tree, offset + 16 , 8, "Auth Data (none)"); + break; + case OSPF_AUTH_SIMPLE: + add_item_to_tree(ospf_header_tree, offset + 14 , 2, "Auth Type: simple"); + strncpy(auth_data, &(ospfh->auth_data), 8); + add_item_to_tree(ospf_header_tree, offset + 16 , 8, "Auth Data: %s", auth_data); + break; + case OSPF_AUTH_CRYPT: + add_item_to_tree(ospf_header_tree, offset + 14 , 2, "Auth Type: crypt"); + add_item_to_tree(ospf_header_tree, offset + 16 , 8, "Auth Data (crypt)"); + break; + default: + add_item_to_tree(ospf_header_tree, offset + 14 , 2, "Auth Type (unknown)"); + add_item_to_tree(ospf_header_tree, offset + 16 , 8, "Auth Data (unknown)"); + } + + } + + /* Skip over header */ + offset += OSPF_HEADER_LENGTH; + switch(ospfh->packet_type){ + case OSPF_HELLO: + dissect_ospf_hello(pd, offset, fd, (GtkTree *) ospf_tree); + break; + case OSPF_DB_DESC: + dissect_ospf_db_desc(pd, offset, fd, (GtkTree *) ospf_tree); + break; + case OSPF_LS_REQ: + dissect_ospf_ls_req(pd, offset, fd, (GtkTree *) ospf_tree); + break; + case OSPF_LS_UPD: + dissect_ospf_ls_upd(pd, offset, fd, (GtkTree *) ospf_tree); + break; + case OSPF_LS_ACK: + dissect_ospf_ls_ack(pd, offset, fd, (GtkTree *) ospf_tree); + break; + default: + dissect_data(pd, offset, fd, tree); + } +} + +void +dissect_ospf_hello(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) { + e_ospf_hello *ospfhello; + guint32 *ospfneighbor; + char options[20]=""; + int options_offset; + + GtkWidget *ospf_hello_tree, *ti; + + ospfhello = (e_ospf_hello *) &pd[offset]; + + if (tree) { + ti = add_item_to_tree(GTK_WIDGET(tree), offset, (fd->cap_len - offset) , "OSPF Hello Packet"); + ospf_hello_tree = gtk_tree_new(); + add_subtree(ti, ospf_hello_tree, ETT_OSPF_HELLO); + + + add_item_to_tree(ospf_hello_tree, offset , 4, "Network Mask: %s", ip_to_str((guint8 *) &ospfhello->network_mask)); + add_item_to_tree(ospf_hello_tree, offset + 4, 2, "Hello Intervall: %d seconds", ntohs(ospfhello->hellointervall)); + + /* ATTENTION !!! no check for length of options string */ + options_offset=0; + if(( ospfhello->options & OSPF_OPTIONS_E ) == OSPF_OPTIONS_E){ + strcpy( (char *)(options + options_offset), "E"); + options_offset+=1; + } + if(( ospfhello->options & OSPF_OPTIONS_MC ) == OSPF_OPTIONS_MC){ + strcpy((char *) (options + options_offset), "/MC"); + options_offset+=3; + } + if(( ospfhello->options & OSPF_OPTIONS_NP ) == OSPF_OPTIONS_NP){ + strcpy((char *) (options + options_offset), "/NP"); + options_offset+=3; + } + if(( ospfhello->options & OSPF_OPTIONS_EA ) == OSPF_OPTIONS_EA){ + strcpy((char *) (options + options_offset) , "/EA"); + options_offset+=3; + } + if(( ospfhello->options & OSPF_OPTIONS_DC ) == OSPF_OPTIONS_DC){ + strcpy((char *) (options + options_offset) , "/DC"); + options_offset+=3; + } + + add_item_to_tree(ospf_hello_tree, offset + 6, 1, "Options: %d (%s)", ospfhello->options, options); + add_item_to_tree(ospf_hello_tree, offset + 7, 1, "Router Priority: %d", ospfhello->priority); + add_item_to_tree(ospf_hello_tree, offset + 8, 4, "RouterDeadIntervall: %d seconds", ntohl(ospfhello->dead_interval)); + add_item_to_tree(ospf_hello_tree, offset + 12, 4, "Designated Router: %s", ip_to_str((guint8 *) &ospfhello->drouter)); + add_item_to_tree(ospf_hello_tree, offset + 16, 4, "Backup Designated Router: %s", ip_to_str((guint8 *) &ospfhello->bdrouter)); + + + offset+=20; + while(((int)(fd->cap_len - offset)) >= 4){ + printf("%d", fd->cap_len - offset); + ospfneighbor=(guint32 *) &pd[offset]; + add_item_to_tree(ospf_hello_tree, offset, 4, "Active Neighbor: %s", ip_to_str((guint8 *) ospfneighbor)); + offset+=4; + } + } +} + +void +dissect_ospf_db_desc(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) { + e_ospf_dbd *ospf_dbd; + char options[20]=""; + int options_offset; + char flags[20]=""; + int flags_offset; + + GtkWidget *ospf_db_desc_tree=NULL, *ti; + + ospf_dbd = (e_ospf_dbd *) &pd[offset]; + + if (tree) { + ti = add_item_to_tree(GTK_WIDGET(tree), offset, (fd->cap_len - offset) , "OSPF DB Description"); + ospf_db_desc_tree = gtk_tree_new(); + add_subtree(ti, ospf_db_desc_tree, ETT_OSPF_DESC); + + add_item_to_tree(ospf_db_desc_tree, offset, 2, "Interface MTU: %d", ntohs(ospf_dbd->interface_mtu) ); + + + options_offset=0; + if(( ospf_dbd->options & OSPF_OPTIONS_E ) == OSPF_OPTIONS_E){ + strcpy( (char *)(options + options_offset), "_E_"); + options_offset+=1; + } + if(( ospf_dbd->options & OSPF_OPTIONS_MC ) == OSPF_OPTIONS_MC){ + strcpy((char *) (options + options_offset), "_MC_"); + options_offset+=3; + } + if(( ospf_dbd->options & OSPF_OPTIONS_NP ) == OSPF_OPTIONS_NP){ + strcpy((char *) (options + options_offset), "_NP_"); + options_offset+=3; + } + if(( ospf_dbd->options & OSPF_OPTIONS_EA ) == OSPF_OPTIONS_EA){ + strcpy((char *) (options + options_offset) , "_EA_"); + options_offset+=3; + } + if(( ospf_dbd->options & OSPF_OPTIONS_DC ) == OSPF_OPTIONS_DC){ + strcpy((char *) (options + options_offset) , "_DC_"); + options_offset+=3; + } + + add_item_to_tree(ospf_db_desc_tree, offset + 2 , 1, "Options: %d (%s)", ospf_dbd->options, options ); + + + flags_offset=0; + if(( ospf_dbd->flags & OSPF_DBD_FLAG_MS ) == OSPF_DBD_FLAG_MS){ + strcpy( (char *)(flags + flags_offset), "_I_"); + flags_offset+=1; + } + if(( ospf_dbd->flags & OSPF_DBD_FLAG_M ) == OSPF_DBD_FLAG_M){ + strcpy((char *) (flags + flags_offset), "_M_"); + flags_offset+=3; + } + if(( ospf_dbd->flags & OSPF_DBD_FLAG_I ) == OSPF_DBD_FLAG_I){ + strcpy((char *) (flags + flags_offset), "_I_"); + flags_offset+=3; + } + + add_item_to_tree(ospf_db_desc_tree, offset + 3 , 1, "Flags: %d (%s)", ospf_dbd->flags, flags ); + add_item_to_tree(ospf_db_desc_tree, offset + 4 , 4, "DD Sequence: %d", ntohl(ospf_dbd->dd_sequence) ); + } + /* LS Headers will be processed here */ + /* skip to the end of DB-Desc header */ + offset+=8; + while( ((int) (fd->cap_len - offset)) >= OSPF_LSA_HEADER_LENGTH ) { + dissect_ospf_lsa(pd, offset, fd, (GtkTree *) tree, FALSE); + offset+=OSPF_LSA_HEADER_LENGTH; + } +} + +void +dissect_ospf_ls_req(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) { + e_ospf_ls_req *ospf_lsr; + + GtkWidget *ospf_lsr_tree, *ti; + + + /* zero or more LS requests may be within a LS Request */ + /* we place every request for a LSA in a single subtree */ + if (tree) { + while( ((int) ( fd->cap_len - offset)) >= OSPF_LS_REQ_LENGTH ){ + ospf_lsr = (e_ospf_ls_req *) &pd[offset]; + ti = add_item_to_tree(GTK_WIDGET(tree), offset, OSPF_LS_REQ_LENGTH, "Link State Request"); + ospf_lsr_tree = gtk_tree_new(); + add_subtree(ti, ospf_lsr_tree, ETT_OSPF_LSR); + + switch( ntohl( ospf_lsr->ls_type ) ){ + case OSPF_LSTYPE_ROUTER: + add_item_to_tree(ospf_lsr_tree, offset, 4, "LS Type: Router-LSA (%d)", + ntohl( ospf_lsr->ls_type ) ); + break; + case OSPF_LSTYPE_NETWORK: + add_item_to_tree(ospf_lsr_tree, offset, 4, "LS Type: Network-LSA (%d)", + ntohl( ospf_lsr->ls_type ) ); + break; + case OSPF_LSTYPE_SUMMERY: + add_item_to_tree(ospf_lsr_tree, offset, 4, "LS Type: Summary-LSA (IP network) (%d)", + ntohl( ospf_lsr->ls_type ) ); + break; + case OSPF_LSTYPE_ASBR: + add_item_to_tree(ospf_lsr_tree, offset, 4, "LS Type: Summary-LSA (ASBR) (%d)", + ntohl( ospf_lsr->ls_type ) ); + break; + case OSPF_LSTYPE_ASEXT: + add_item_to_tree(ospf_lsr_tree, offset, 4, "LS Type: AS-External-LSA (ASBR) (%d)", + ntohl( ospf_lsr->ls_type ) ); + break; + default: + add_item_to_tree(ospf_lsr_tree, offset, 4, "LS Type: %d (unknown)", + ntohl( ospf_lsr->ls_type ) ); + } + + add_item_to_tree(ospf_lsr_tree, offset + 4, 4, "Link State ID : %s", + ip_to_str((guint8 *) &(ospf_lsr->ls_id))); + add_item_to_tree(ospf_lsr_tree, offset + 8, 4, "Advertising Router : %s", + ip_to_str((guint8 *) &(ospf_lsr->adv_router))); + + offset+=12; + } + } +} +void +dissect_ospf_ls_upd(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) { + e_ospf_lsa_upd_hdr *upd_hdr; + guint32 lsa_counter; + + GtkWidget *ospf_lsa_upd_tree=NULL, *ti; + + upd_hdr = (e_ospf_lsa_upd_hdr *) &pd[offset]; + + if (tree) { + ti = add_item_to_tree(GTK_WIDGET(tree), offset, (fd->cap_len - offset) , "LS Update Packet"); + ospf_lsa_upd_tree = gtk_tree_new(); + add_subtree(ti, ospf_lsa_upd_tree, ETT_OSPF_LSA_UPD); + + add_item_to_tree(ospf_lsa_upd_tree, offset, 4, "Nr oF LSAs: %d", ntohl(upd_hdr->lsa_nr) ); + } + /* skip to the beginning of the first LSA */ + offset+=4; /* the LS Upd PAcket contains only a 32 bit #LSAs field */ + + lsa_counter = 0; + while(lsa_counter < ntohl(upd_hdr->lsa_nr)){ + offset+=dissect_ospf_lsa(pd, offset, fd, (GtkTree *) ospf_lsa_upd_tree, TRUE); + lsa_counter += 1; + } +} + +void +dissect_ospf_ls_ack(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) { + + /* the body of a LS Ack packet simply contains zero or more LSA Headers */ + while( ((int)(fd->cap_len - offset)) >= OSPF_LSA_HEADER_LENGTH ) { + dissect_ospf_lsa(pd, offset, fd, (GtkTree *) tree, FALSE); + offset+=OSPF_LSA_HEADER_LENGTH; + } + +} + +int +dissect_ospf_lsa(const u_char *pd, int offset, frame_data *fd, GtkTree *tree, int disassemble_body) { + e_ospf_lsa_hdr *lsa_hdr; + char *lsa_type; + + /* data strutures for the router LSA */ + e_ospf_router_lsa *router_lsa; + e_ospf_router_data *router_data; + e_ospf_router_metric *tos_data; + guint16 link_counter; + guint8 tos_counter; + char *link_type; + char *link_id; + + /* data structures for the network lsa */ + e_ospf_network_lsa *network_lsa; + guint32 *attached_router; + + /* data structures for the summary and ASBR LSAs */ + e_ospf_summary_lsa *summary_lsa; + guint8 *tos; + guint16 *tos_metric; + + + + GtkWidget *ospf_lsa_tree, *ti; + + lsa_hdr = (e_ospf_lsa_hdr *) &pd[offset]; + + + switch(lsa_hdr->ls_type) { + case OSPF_LSTYPE_ROUTER: + lsa_type="Router LSA"; + break; + case OSPF_LSTYPE_NETWORK: + lsa_type="Network LSA"; + break; + case OSPF_LSTYPE_SUMMERY: + lsa_type="Summery LSA"; + break; + case OSPF_LSTYPE_ASBR: + lsa_type="ASBR LSA"; + break; + case OSPF_LSTYPE_ASEXT: + lsa_type="AS-external-LSA"; + break; + default: + lsa_type="unknown"; + } + + if (tree) { + if(disassemble_body){ + ti = add_item_to_tree(GTK_WIDGET(tree), offset, ntohs(lsa_hdr->length), + "%s (Type: %d)", lsa_type, lsa_hdr->ls_type); + } else { + ti = add_item_to_tree(GTK_WIDGET(tree), offset, OSPF_LSA_HEADER_LENGTH, "LSA Header"); + } + ospf_lsa_tree = gtk_tree_new(); + add_subtree(ti, ospf_lsa_tree, ETT_OSPF_LSA); + + + add_item_to_tree(ospf_lsa_tree, offset, 2, "LS Age: %d seconds", ntohs(lsa_hdr->ls_age)); + add_item_to_tree(ospf_lsa_tree, offset + 2, 1, "Options: %d ", lsa_hdr->options); + add_item_to_tree(ospf_lsa_tree, offset + 3, 1, "LSA Type: %d (%s)", lsa_hdr->ls_type, lsa_type); + + add_item_to_tree(ospf_lsa_tree, offset + 4, 4, "Linke State ID: %s ", + ip_to_str((guint8 *) &(lsa_hdr->ls_id))); + + add_item_to_tree(ospf_lsa_tree, offset + 8, 4, "Advertising Router: %s ", + ip_to_str((guint8 *) &(lsa_hdr->adv_router))); + add_item_to_tree(ospf_lsa_tree, offset + 12, 4, "LS Sequence Number: 0x%04x ", + ntohl(lsa_hdr->ls_seq)); + add_item_to_tree(ospf_lsa_tree, offset + 16, 2, "LS Checksum: %d ", ntohs(lsa_hdr->ls_checksum)); + + add_item_to_tree(ospf_lsa_tree, offset + 18, 2, "Length: %d ", ntohs(lsa_hdr->length)); + + if(!disassemble_body){ + return OSPF_LSA_HEADER_LENGTH; + } + + /* the LSA body starts afte 20 bytes of LSA Header */ + offset+=20; + + switch(lsa_hdr->ls_type){ + case(OSPF_LSTYPE_ROUTER): + router_lsa = (e_ospf_router_lsa *) &pd[offset]; + + /* again: flags should be secified in detail */ + add_item_to_tree(ospf_lsa_tree, offset, 1, "Flags: 0x%02x ", router_lsa->flags); + add_item_to_tree(ospf_lsa_tree, offset + 2, 2, "Nr. of Links: %d ", + ntohs(router_lsa->nr_links)); + offset += 4; + /* router_lsa->nr_links links follow + * maybe we should put each of the links into its own subtree ??? + */ + for(link_counter = 1 ; link_counter <= ntohs(router_lsa->nr_links); link_counter++){ + + router_data = (e_ospf_router_data *) &pd[offset]; + /* check the Link Type and ID */ + switch(router_data->link_type) { + case OSPF_LINK_PTP: + link_type="Point-to-point connection to another router"; + link_id="Neighboring router's Router ID"; + break; + case OSPF_LINK_TRANSIT: + link_type="Connection to a transit network"; + link_id="IP address of Designated Router"; + break; + case OSPF_LINK_STUB: + link_type="Connection to a stub network"; + link_id="IP network/subnet number"; + break; + case OSPF_LINK_VIRTUAL: + link_type="Virtual link"; + link_id="Neighboring router's Router ID"; + break; + default: + link_type="unknown link type"; + link_id="unknown link id"; + } + + add_item_to_tree(ospf_lsa_tree, offset, 4, "%s: %s", link_id, + ip_to_str((guint8 *) &(router_data->link_id))); + + /* link_data should be specified in detail (e.g. network mask) (depends on link type)*/ + add_item_to_tree(ospf_lsa_tree, offset + 4, 4, "Link Data: %s", + ip_to_str((guint8 *) &(router_data->link_data))); + + add_item_to_tree(ospf_lsa_tree, offset + 8, 1, "Link Type: %d - %s", + router_data->link_type, link_type); + add_item_to_tree(ospf_lsa_tree, offset + 9, 1, "Nr. of TOS metrics: %d", router_data->nr_tos); + add_item_to_tree(ospf_lsa_tree, offset + 10, 2, "TOS 0 metric: %d", ntohs( router_data->tos0_metric )); + + offset += 12; + + /* router_data->nr_tos metrics may follow each link + * ATTENTION: TOS metrics are not tested (I don't have TOS based routing) + * please send me a mail if it is/isn't working + */ + + for(tos_counter = 1 ; link_counter <= ntohs(router_data->nr_tos); tos_counter++){ + tos_data = (e_ospf_router_metric *) &pd[offset]; + add_item_to_tree(ospf_lsa_tree, offset, 1, "TOS: %d, Metric: %d", + tos_data->tos, ntohs(tos_data->metric)); + offset += 4; + } + } + break; + case(OSPF_LSTYPE_NETWORK): + network_lsa = (e_ospf_network_lsa *) &pd[offset]; + add_item_to_tree(ospf_lsa_tree, offset, 4, "Netmask: %s", + ip_to_str((guint8 *) &(network_lsa->network_mask))); + offset += 4; + + while( ((int) (fd->cap_len - offset)) >= 4){ + attached_router = (guint32 *) &pd[offset]; + add_item_to_tree(ospf_lsa_tree, offset, 4, "Attached Router: %s", + ip_to_str((guint8 *) attached_router)); + offset += 4; + } + break; + case(OSPF_LSTYPE_SUMMERY): + /* Type 3 and 4 LSAs have the same format */ + case(OSPF_LSTYPE_ASBR): + summary_lsa = (e_ospf_summary_lsa *) &pd[offset]; + add_item_to_tree(ospf_lsa_tree, offset, 4, "Netmask: %s", + ip_to_str((guint8 *) &(summary_lsa->network_mask))); + break; + case(OSPF_LSTYPE_ASEXT): + /* not yet implemented */ + add_item_to_tree(ospf_lsa_tree, offset, (fd->cap_len - offset), "AS-external-LSA not yet implemented"); + break; + default: + /* unknown LSA type */ + add_item_to_tree(ospf_lsa_tree, offset, (fd->cap_len - offset), "Unknown LSA Type"); + } + } + /* return the length of this LSA */ + return ntohs(lsa_hdr->length); +} diff --git a/packet-ospf.h b/packet-ospf.h new file mode 100644 index 0000000000..8e3b6af377 --- /dev/null +++ b/packet-ospf.h @@ -0,0 +1,127 @@ +/* packet-ospf.h (c) 1998 Hannes Boehm */ + +#define OSPF_HEADER_LENGTH 24 + +#define OSPF_HELLO 1 +#define OSPF_DB_DESC 2 +#define OSPF_LS_REQ 3 +#define OSPF_LS_UPD 4 +#define OSPF_LS_ACK 5 + +#define OSPF_AUTH_NONE 0 +#define OSPF_AUTH_SIMPLE 1 +#define OSPF_AUTH_CRYPT 2 + +#define OSPF_OPTIONS_E 2 +#define OSPF_OPTIONS_MC 4 +#define OSPF_OPTIONS_NP 8 +#define OSPF_OPTIONS_EA 16 +#define OSPF_OPTIONS_DC 32 + +#define OSPF_DBD_FLAG_MS 1 +#define OSPF_DBD_FLAG_M 2 +#define OSPF_DBD_FLAG_I 4 + +#define OSPF_LS_REQ_LENGTH 12 + +#define OSPF_LSTYPE_ROUTER 1 +#define OSPF_LSTYPE_NETWORK 2 +#define OSPF_LSTYPE_SUMMERY 3 +#define OSPF_LSTYPE_ASBR 4 +#define OSPF_LSTYPE_ASEXT 5 + +#define OSPF_LINK_PTP 1 +#define OSPF_LINK_TRANSIT 2 +#define OSPF_LINK_STUB 3 +#define OSPF_LINK_VIRTUAL 4 + +#define OSPF_LSA_HEADER_LENGTH 20 + +typedef struct _e_ospfhdr { + guint8 version; + guint8 packet_type; + guint16 length; + guint32 routerid; + guint32 area; + guint16 checksum; + guint16 auth_type; + char auth_data[8]; +} e_ospfhdr; + +typedef struct _e_ospf_hello { + guint32 network_mask; + guint16 hellointervall; + guint8 options; + guint8 priority; + guint32 dead_interval; + guint32 drouter; + guint32 bdrouter; +} e_ospf_hello ; + +typedef struct _e_ospf_dbd { + guint16 interface_mtu; + guint8 options; + guint8 flags; + guint32 dd_sequence; +} e_ospf_dbd; + +typedef struct _e_ospf_ls_req { + guint32 ls_type; + guint32 ls_id; + guint32 adv_router; +} e_ospf_ls_req; + +typedef struct _e_ospf_lsa_hdr { + guint16 ls_age; + guint8 options; + guint8 ls_type; + guint32 ls_id; + guint32 adv_router; + guint32 ls_seq; + guint16 ls_checksum; + guint16 length; +} e_ospf_lsa_hdr; + +typedef struct _e_ospf_router_lsa { + guint8 flags; + guint8 empfty; + guint16 nr_links; +} e_ospf_router_lsa; + +typedef struct _e_ospf_router_data { + guint32 link_id; + guint32 link_data; + guint8 link_type; + guint8 nr_tos; + guint16 tos0_metric; +} e_ospf_router_data; + +typedef struct _e_ospf_router_metric { + guint8 tos; + guint8 empty; + guint16 metric; +} e_ospf_router_metric; + +typedef struct _e_ospf_network_lsa { + guint32 network_mask; +} e_ospf_network_lsa; + +typedef struct _e_ospf_lsa_upd_hdr { + guint32 lsa_nr; +} e_ospf_lsa_upd_hdr; + +typedef struct _e_ospf_summary_lsa { + guint32 network_mask; +} e_ospf_summary_lsa; + +void dissect_ospf_hello(const u_char*, int, frame_data*, GtkTree*); +void dissect_ospf_db_desc(const u_char*, int, frame_data*, GtkTree*); +void dissect_ospf_ls_req(const u_char*, int, frame_data*, GtkTree*); +void dissect_ospf_ls_upd(const u_char*, int, frame_data*, GtkTree*); +void dissect_ospf_ls_ack(const u_char*, int, frame_data*, GtkTree*); + +/* dissect_ospf_lsa returns the length of the LSA + * if disassemble_body is set to FALSE (e.g. in LSA ACK + * packets), the header length is returned + */ +int dissect_ospf_lsa(const u_char*, int, frame_data*, GtkTree*, int disassemble_body); diff --git a/packet-ppp.c b/packet-ppp.c new file mode 100644 index 0000000000..cce8fd677e --- /dev/null +++ b/packet-ppp.c @@ -0,0 +1,79 @@ +/* packet-ppp.c + * Routines for ppp packet disassembly + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * + * This file created and by Mike Hall + * Copyright 1998 + * + * 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 +#include +#include + +#include "packet.h" +#include "ethereal.h" + +void +dissect_ppp( const u_char *pd, frame_data *fd, GtkTree *tree ) { + e_ppphdr ph; + GtkWidget *ti, *fh_tree; + + guchar flag, addr, control; + guint protocol; + + ph.ppp_flag = pd[0]; + ph.ppp_addr = pd[1]; + ph.ppp_ctl = pd[2]; + ph.ppp_prot = pntohs(&pd[3]); + + /* load the top pane info. This should be overwritten by + the next protocol in the stack */ + if(fd->win_info[0]) { + strcpy(fd->win_info[1], "N/A" ); + strcpy(fd->win_info[2], "N/A" ); + strcpy(fd->win_info[4], "PPP" ); + } + + /* populate a tree in the second pane with the status of the link + layer (ie none) */ + if(tree) { + ti = add_item_to_tree( GTK_WIDGET(tree), 0, 5, + "Point-to-Point Protocol (%d on link, %d captured)", fd->pkt_len, + fd->cap_len ); + fh_tree = gtk_tree_new(); + add_subtree(ti, fh_tree, ETT_PPP); + add_item_to_tree(fh_tree, 0, 1, "Flag: %02x", ph.ppp_flag); + add_item_to_tree(fh_tree, 1, 1, "Address: %02x", ph.ppp_addr); + add_item_to_tree(fh_tree, 2, 1, "Control: %02x", ph.ppp_ctl); + add_item_to_tree(fh_tree, 3, 2, "Protocol: %04x", ph.ppp_prot); + } + + switch (ph.ppp_prot) { + case 0x0021: + dissect_ip(pd, 5, fd, tree); + break; + default: + dissect_data(pd, 5, fd, tree); + break; + } +} diff --git a/packet-raw.c b/packet-raw.c new file mode 100644 index 0000000000..d666bd8b62 --- /dev/null +++ b/packet-raw.c @@ -0,0 +1,72 @@ +/* packet-raw.c + * Routines for raw packet disassembly + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * + * This file created and by Mike Hall + * Copyright 1998 + * + * 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 +#include +#include + +#include "packet.h" +#include "ethereal.h" + +void +dissect_raw( const u_char *pd, frame_data *fd, GtkTree *tree ) { + GtkWidget *ti, *fh_tree; + + /* load the top pane info. This should be overwritten by + the next protocol in the stack */ + if(fd->win_info[0]) { + strcpy(fd->win_info[1], "N/A" ); + strcpy(fd->win_info[2], "N/A" ); + strcpy(fd->win_info[4], "Raw packet data" ); + } + + /* populate a tree in the second pane with the status of the link + layer (ie none) */ + if(tree) { + ti = add_item_to_tree( GTK_WIDGET(tree), 0, 0, + "Raw packet data (%d on link, %d captured)", + fd->pkt_len, fd->cap_len ); + fh_tree = gtk_tree_new(); + add_subtree(ti, fh_tree, ETT_RAW); + add_item_to_tree(fh_tree, 0, 0, "No link information available"); + } + + /* So far, the only time we get raw connection types are with Linux and + * Irix PPP connections. We can't tell what type of data is coming down + * the line, so our safest bet is IP. - GCC + */ + + /* Currently, the Linux 2.1.xxx PPP driver passes back some of the header + * sometimes. This check should be removed when 2.2 is out. + */ + if (pd[0] == 0xff && pd[1] == 0x03) + dissect_ip(pd, 4, fd, tree); + else + dissect_ip(pd, 0, fd, tree); +} + diff --git a/packet-rip.c b/packet-rip.c new file mode 100644 index 0000000000..d0e0bbe337 --- /dev/null +++ b/packet-rip.c @@ -0,0 +1,144 @@ +/* packet-ospf.c + * Routines for RIPv1 and RIPv2 packet disassembly + * (c) Copyright Hannes R. Boehm + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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. + */ + +#include "config.h" + +#include + +#include + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#include "ethereal.h" +#include "packet.h" +#include "packet-rip.h" + + +void +dissect_rip(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) { + e_riphdr *rip_header; + e_rip_vektor rip_vektor; + int auth = FALSE; + + GtkWidget *rip_tree = NULL, *ti; + GtkWidget *rip_vektor_tree; + + + /* we do the range checking of the index when checking wether or not this is a RIP packet */ + char *packet_type[8] = { "never used", "Request", "Response", + "Traceon", "Traceoff", "Vendor specific (Sun)" }; + char *version[3] = { "RIP", "RIPv1", "RIPv2" }; + + + rip_header = (e_riphdr *) &pd[offset]; + /* Check if we 've realy got a RIP packet */ + + switch(rip_header->version) { + case RIPv1: + /* the domain field has to be set to zero for RIPv1 */ + if(!(rip_header->domain == 0)){ + dissect_data(pd, offset, fd, tree); + return; + } + /* the RIPv2 checks are also made for v1 packets */ + case RIPv2: + /* check wether or not command nr. is between 1-7 + * (range checking for index of char* packet_type is done at the same time) + */ + if( !( (rip_header->command > 0) && (rip_header->command <= 7) )){ + dissect_data(pd, offset, fd, tree); + return; + } + break; + default: + /* we only know RIPv1 and RIPv2 */ + dissect_data(pd, offset, fd, tree); + return; + } + + + if (fd->win_info[0]) { + strcpy(fd->win_info[3], version[rip_header->version] ); + sprintf(fd->win_info[4], "%s", packet_type[rip_header->command]); + } + + if (tree) { + ti = add_item_to_tree(GTK_WIDGET(tree), offset, (fd->cap_len - offset), "Routing Information Protocol"); + rip_tree = gtk_tree_new(); + add_subtree(ti, rip_tree, ETT_RIP); + + add_item_to_tree(rip_tree, offset + 1, 1, "Version: %d", rip_header->version); + add_item_to_tree(rip_tree, offset, 1, "Command: %d (%s)", rip_header->command, packet_type[rip_header->command]); + switch(ntohs(rip_header->family)){ + case 2: /* IP */ + add_item_to_tree(rip_tree, offset + 4 , 2, "Address Family ID: IP"); + break; + case 0xFFFF: + add_item_to_tree(rip_tree, offset + 4 , 2, "Authenticated Packet"); + auth = TRUE; + break; + default: + /* return; */ + } + + if(rip_header->version == RIPv2) { + add_item_to_tree(rip_tree, offset + 2 , 2, "Routing Domain: %d", ntohs(rip_header->domain)); + add_item_to_tree(rip_tree, offset + 6 , 2, "Route Tag: %d", ntohs(rip_header->tag)); + } + /* skip header */ + offset += RIP_HEADER_LENGTH; + + /* if present, skip the authentication */ + if(auth){ + offset += RIP_VEKTOR_LENGTH; + } + /* zero or more distance vektors */ + + while((fd->cap_len - offset) >= RIP_VEKTOR_LENGTH){ + ti = add_item_to_tree(GTK_WIDGET(rip_tree), offset, RIP_VEKTOR_LENGTH, "RIP Vektor"); + rip_vektor_tree = gtk_tree_new(); + add_subtree(ti, rip_vektor_tree, ETT_RIP_VEC); + + memcpy(&rip_vektor, &pd[offset], sizeof(rip_vektor)); /* avoid alignment problem */ + add_item_to_tree(rip_vektor_tree, offset, 4, "IP Address: %s", ip_to_str((guint8 *) &(rip_vektor.ip))); + + if(rip_header->version == RIPv2) { + add_item_to_tree(rip_vektor_tree, offset + 4 , 4, "Netmask: %s", + ip_to_str((guint8 *) &(rip_vektor.mask))); + add_item_to_tree(rip_vektor_tree, offset + 8 , 4, "Next Hop: %s", + ip_to_str((guint8 *) &(rip_vektor.next_hop))); + } + + add_item_to_tree(rip_vektor_tree, offset + 12 , 4, "Metric: %d", ntohl(rip_vektor.metric)); + + offset += RIP_VEKTOR_LENGTH; + }; + } +} diff --git a/packet-rip.h b/packet-rip.h new file mode 100644 index 0000000000..59606fc254 --- /dev/null +++ b/packet-rip.h @@ -0,0 +1,23 @@ +/* packet-rip.h (c) 1998 Hannes Boehm */ + +#define RIPv1 1 +#define RIPv2 2 + +#define RIP_HEADER_LENGTH 8 +#define RIP_VEKTOR_LENGTH 16 + +typedef struct _e_riphdr { + guint8 command; + guint8 version; + guint16 domain; + guint16 family; + guint16 tag; +} e_riphdr; + + +typedef struct _e_rip_vektor { + guint32 ip; + guint32 mask; + guint32 next_hop; + guint32 metric; +} e_rip_vektor; diff --git a/packet-tcp.c b/packet-tcp.c new file mode 100644 index 0000000000..66dbacd733 --- /dev/null +++ b/packet-tcp.c @@ -0,0 +1,116 @@ +/* packet-tcp.c + * Routines for TCP packet disassembly + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#ifdef HAVE_NETINET_IN_H +# include +#endif + +#include "ethereal.h" +#include "packet.h" + +void +dissect_tcp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) { + e_tcphdr th; + GtkWidget *tcp_tree, *ti; + gchar flags[64] = ""; + gchar *fstr[] = {"FIN", "SYN", "RST", "PSH", "ACK", "URG"}; + gint fpos = 0, i; + guint bpos; + + /* To do: Check for {cap len,pkt len} < struct len */ + /* Avoids alignment problems on many architectures. */ + memcpy(&th, &pd[offset], sizeof(e_tcphdr)); + th.th_sport = ntohs(th.th_sport); + th.th_dport = ntohs(th.th_dport); + th.th_win = ntohs(th.th_win); + th.th_sum = ntohs(th.th_sum); + th.th_urp = ntohs(th.th_urp); + th.th_seq = ntohl(th.th_seq); + th.th_ack = ntohl(th.th_ack); + + for (i = 0; i < 6; i++) { + bpos = 1 << i; + if (th.th_flags & bpos) { + if (fpos) { + strcpy(&flags[fpos], ", "); + fpos += 2; + } + strcpy(&flags[fpos], fstr[i]); + fpos += 3; + } + } + flags[fpos] = '\0'; + + if (fd->win_info[0]) { + strcpy(fd->win_info[3], "TCP"); + sprintf(fd->win_info[4], "Source port: %d Destination port: %d", + th.th_sport, th.th_dport); + } + + if (tree) { + ti = add_item_to_tree(GTK_WIDGET(tree), offset, 20, + "Transmission Control Protocol"); + tcp_tree = gtk_tree_new(); + add_subtree(ti, tcp_tree, ETT_TCP); + add_item_to_tree(tcp_tree, offset, 2, "Source port: %d", th.th_sport); + add_item_to_tree(tcp_tree, offset + 2, 2, "Destination port: %d", th.th_dport); + add_item_to_tree(tcp_tree, offset + 4, 4, "Sequence number: 0x%08x", + th.th_seq); + add_item_to_tree(tcp_tree, offset + 8, 4, "Acknowledgement number: 0x%08x", + th.th_ack); + add_item_to_tree(tcp_tree, offset + 12, 1, "Header length: %d", th.th_off); + add_item_to_tree(tcp_tree, offset + 13, 1, "Flags: %s", flags); + add_item_to_tree(tcp_tree, offset + 14, 2, "Window size: %d", th.th_win); + add_item_to_tree(tcp_tree, offset + 16, 2, "Checksum: 0x%04x", th.th_sum); + add_item_to_tree(tcp_tree, offset + 18, 2, "Urgent pointer: 0x%04x", + th.th_urp); + /* To do: TCP options */ + + } + /* Skip over header + options */ + offset += 4 * th.th_off; + + /* until we decode those options, I'll check the packet length + to see if there's more data. -- gilbert */ + if (fd->cap_len > offset) { + switch(MIN(th.th_sport, th.th_dport)) { + case TCP_PORT_PRINTER: + dissect_lpd(pd, offset, fd, tree); + break; + default: + dissect_data(pd, offset, fd, tree); + } + } +} diff --git a/packet-tr.c b/packet-tr.c new file mode 100644 index 0000000000..7615d87003 --- /dev/null +++ b/packet-tr.c @@ -0,0 +1,253 @@ +/* packet-tr.c + * Routines for Token-Ring packet disassembly + * Gilbert Ramirez + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#ifdef HAVE_NETINET_IN_H +# include +#endif + +#include + +#include "packet.h" +#include "ethereal.h" +#include "etypes.h" + +static void +add_ring_bridge_pairs(int rcf_len, const u_char *pd, GtkWidget *tree); + +static char* +sr_broadcast(u_char val) { + + if (val < 4) { + return "Non-broadcast"; + } + else if (val < 6) { + return "All-routes broadcast"; + } + else { + return "Single-route broadcast"; + } +} + +static int +sr_frame(u_char val) { + + int rc_frame[7] = { 516, 1500, 2052, 4472, 8144, 11407, 17800 }; + + if (val > 6) { + return -1; + } + else return rc_frame[val]; +} + +void +dissect_tr(const u_char *pd, frame_data *fd, GtkTree *tree) { + + GtkWidget *fh_tree, *ti; + int offset = 14; + int source_routed = 0; + int rif_bytes = 0; + guint8 nonsr_hwaddr[8]; + int frame_type = (pd[1] & 192) >> 6; /* I use this value a lot */ + #ifdef linux + int silly_linux = 0; + #endif + + /* Token-Ring Strings */ + char *fc[] = { "MAC", "LLC", "Reserved" }; + char *fc_pcf[] = { + "Normal buffer", "Express buffer", "Purge", + "Claim Token", "Beacon", "Active Monitor Present", + "Standby Monitor Present" }; + char *rc_arrow[] = { "-->", "<--" }; + char *rc_direction[] = { "From originating station", + "To originating station" }; + + /* if the high bit on the first byte of src hwaddr is 1, then + this packet is source-routed */ + source_routed = pd[8] & 128; + + /* sometimes we have a RCF but no RIF... half source-routed? */ + /* I'll check for 2 bytes of RIF and the 0x70 byte */ + if (!source_routed) { + if ((pd[14] & 31) == 2 && pd[15] == 0x70) { + source_routed = 1; + } + } + + if (source_routed) { + rif_bytes = pd[14] & 31; + } + /* this is a silly hack for Linux 2.0.x. Read the comment below, + in front of the other #ifdef linux */ + #ifdef linux + if ((source_routed && rif_bytes == 2 && frame_type == 1) || + (!source_routed && frame_type == 1)) { + /* look for SNAP or IPX only */ + if ( (pd[0x20] == 0xaa && pd[0x21] == 0xaa && pd[0x22] == 03) || + (pd[0x20] == 0xe0 && pd[0x21] == 0xe0) ) { + silly_linux = 1; + rif_bytes = 18; + } + } + #endif + offset += rif_bytes; + + /* Make a copy of the src hwaddr, w/o source routing. I'll do this + for all packets, even non-sr packets */ + memcpy(nonsr_hwaddr, &pd[8], 6); + nonsr_hwaddr[0] &= 127; + + if (fd->win_info[0]) { + strcpy(fd->win_info[2], ether_to_str((guint8 *)&pd[2])); + strcpy(fd->win_info[1], ether_to_str(nonsr_hwaddr)); + strcpy(fd->win_info[3], "TR"); + sprintf(fd->win_info[4], "Token-Ring %s", fc[frame_type]); + } + + if (tree) { + ti = add_item_to_tree(GTK_WIDGET(tree), 0, 14 + rif_bytes, + "Token-Ring (%d on wire, %d captured)", fd->pkt_len, fd->cap_len); + fh_tree = gtk_tree_new(); + add_subtree(ti, fh_tree, ETT_TOKEN_RING); + add_item_to_tree(fh_tree, 0, 1, + "Access Control: %s, Priority=%d, Monitor Count=%d, " + "Priority Reservation=%d", + ((pd[0] & 16) >> 4) ? "Frame" : "Token", /* frame/token */ + ((pd[0] & 224) >> 5), /* priority */ + ((pd[0] & 8) >> 3), /* monitor count */ + ((pd[0] & 7))); /* priority reserv. */ + + add_item_to_tree(fh_tree, 1, 1, + "Frame Control: %s, Physical Control=%d (%s)", + fc[frame_type], (pd[1] & 15), + fc_pcf[(pd[1] & 15)]); + + add_item_to_tree(fh_tree, 2, 6, "Destination: %s", + ether_to_str((guint8 *) &pd[2])); + add_item_to_tree(fh_tree, 8, 6, "Source: %s", + ether_to_str((guint8 *) &pd[8])); + + if (source_routed) { + add_item_to_tree(fh_tree, 14, 1, "RIF length: %d bytes", + pd[14] & 31); /* not rif_bytes because of silly_linux */ + + add_item_to_tree(fh_tree, 15, 1, + "%s, up to %d bytes in frame (LF=%d)", + sr_broadcast((pd[14] & 224) >> 5), + sr_frame((pd[15] & 112) >> 4), + (pd[15] & 112) >> 4); + + add_item_to_tree(fh_tree, 15, 1, + "Direction: %s (%s)", + rc_direction[(pd[15] & 128) >> 7], + rc_arrow[(pd[15] & 128) >> 7]); + + /* if we have more than 2 bytes of RIF, then we have + ring/bridge pairs */ + if ((pd[14] & 31) > 2) { /* not rif_bytes because of silly_linux */ + add_ring_bridge_pairs(rif_bytes, pd, fh_tree); + } + } + + /* Linux 2.0.x has a problem in that the 802.5 code creates + an emtpy full (18-byte) RIF area. It's up to the tr driver to + either fill it in or remove it before sending the bytes out + to the wire. If you run tcpdump on a Linux 2.0.x machine running + token-ring, tcpdump will capture these 18 filler bytes. They + are filled with garbage. The best way to detect this problem is + to know the src hwaddr of the machine from which you were running + tcpdump. W/o that, however, I'm guessing that DSAP == SSAP if the + frame type is LLC. It's very much a hack. -- Gilbert Ramirez */ + #ifdef linux + if ( (source_routed && ((pd[14] & 31) == 2) && silly_linux) || + (!source_routed) && silly_linux ) { + add_item_to_tree(fh_tree, 14, 18, + "Empty RIF from Linux 2.0.x driver. The sniffing NIC " + "is also running a protocol stack."); + } + #endif + } + + /* The package is either MAC or LLC */ + switch (frame_type) { + /* MAC */ + case 0: + /* dissect_trmac(pd, offset, fd, tree) */ + dissect_trmac(pd, offset, fd, tree); + break; + case 1: + dissect_llc(pd, offset, fd, tree); + break; + default: + /* non-MAC, non-LLC, i.e., "Reserved" */ + dissect_data(pd, offset, fd, tree); + break; + } +} + +/* this routine is taken from the Linux net/802/tr.c code, which shows +ring-bridge paires in the /proc/net/tr_rif virtual file. */ +static void +add_ring_bridge_pairs(int rcf_len, const u_char *pd, GtkWidget *tree) +{ + int j, size; + int segment, brdgnmb; + char buffer[50]; + int buff_offset=0; + + rcf_len -= 2; + + if (rcf_len) + rcf_len >>= 1; + + for(j = 1; j < rcf_len; j++) { + if (j==1) { + segment=ntohs(*((unsigned short*)&pd[16])) >> 4; + size = sprintf(buffer,"%03X",segment); + buff_offset += size; + } + segment=ntohs(*((unsigned short*)&pd[17+j])) >> 4; + brdgnmb=pd[16+j] & 0x0f; + size = sprintf(buffer+buff_offset,"-%01X-%03X",brdgnmb,segment); + buff_offset += size; + } + + add_item_to_tree(tree, 16, rcf_len << 1, + "Ring-Bridge Pairs: %s", + buffer); + +} + diff --git a/packet-trmac.c b/packet-trmac.c new file mode 100644 index 0000000000..b0c6ce6c97 --- /dev/null +++ b/packet-trmac.c @@ -0,0 +1,322 @@ +/* packet-trmac.c + * Routines for Token-Ring Media Access Control + * Gilbert Ramirez + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include + +#include + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#ifdef HAVE_NETINET_IN_H +# include +#endif + +#include "packet.h" +#include "ethereal.h" +#include "etypes.h" + +struct vec_info { + u_char cmd; + char *text; +}; + +/* Major Vector */ +static void +mv_text(u_char cmd, int offset, frame_data *fd, GtkWidget *tree) { + int i=0; + + static struct vec_info mv[] = { + { 0x00, "Response" }, + { 0x02, "Beacon" }, + { 0x03, "Claim Token" }, + { 0x04, "Ring Purge" }, + { 0x05, "Active Monitor Present" }, + { 0x06, "Standby Monitor Present" }, + { 0x07, "Duplicate Address Test" }, + { 0x09, "Transmit Forward" }, + { 0x0B, "Remove Ring Station" }, + { 0x0C, "Change Parameters" }, + { 0x0D, "Initialize Ring Station" }, + { 0x0E, "Request Ring Station Address" }, + { 0x0F, "Request Ring Station Address" }, + { 0x10, "Request Ring Station Attachments" }, + { 0x20, "Request Initialization" }, + { 0x22, "Report Ring Station Address" }, + { 0x23, "Report Ring Station State" }, + { 0x24, "Report Ring Station Attachments" }, + { 0x25, "Report New Active Monitor" }, + { 0x26, "Report NAUN Change" }, + { 0x27, "Report Poll Error" }, + { 0x28, "Report Monitor Errors" }, + { 0x29, "Report Error" }, + { 0x2A, "Report Transmit Forward" }, + { 0x00, NULL } + }; + + while (mv[i].text != NULL) { + if (mv[i].cmd == cmd) { + if (fd->win_info[0]) { + /* I can do this because no higher-level dissect() + will strcpy onto me. */ + fd->win_info[4] = mv[i].text; + } + if (tree) { + add_item_to_tree(tree, offset, 1, "Major Vector Command: %s", + mv[i].text); + } + return; + } + i++; + } + /* failure */ + add_item_to_tree(tree, offset, 1, "Major Vector Command: %02X (Unknown)", + cmd); +} + +/* Sub-vectors */ +static int +sv_text(const u_char *pd, int pkt_offset, GtkWidget *tree) +{ + int sv_length = pd[0]; + + char *beacon[] = {"Recovery mode set", "Signal loss error", + "Streaming signal not Claim Token MAC frame", + "Streaming signal, Claim Token MAC frame"}; + + GtkWidget *sv_tree, *ti; + + u_char errors[6]; /* isolating or non-isolating */ + + /* this just adds to the clutter on the screen... + add_item_to_tree(tree, pkt_offset, 1, + "Subvector Length: %d bytes", sv_length);*/ + + switch(pd[1]) { + case 0x01: /* Beacon Type */ + add_item_to_tree(tree, pkt_offset+1, sv_length-1, + "Beacon Type: %s", beacon[ pntohs( &pd[2] ) ] ); + break; + + case 0x02: /* NAUN */ + add_item_to_tree(tree, pkt_offset+1, sv_length-1, + "NAUN: %s", ether_to_str((guint8*)&pd[2])); + break; + + case 0x03: /* Local Ring Number */ + add_item_to_tree(tree, pkt_offset+1, sv_length-1, + "Local Ring Number: 0x%04X (%d)", + pntohs( &pd[2] ), pntohs( &pd[2] )); + break; + + case 0x04: /* Assign Physical Location */ + add_item_to_tree(tree, pkt_offset+1, sv_length-1, + "Assign Physical Location: 0x%08X", pntohl( &pd[2] ) ); + break; + + case 0x05: /* Soft Error Report Value */ + add_item_to_tree(tree, pkt_offset+1, sv_length-1, + "Soft Error Report Value: %d ms", 10 * pntohs( &pd[2] ) ); + break; + + case 0x06: /* Enabled Function Classes */ + add_item_to_tree(tree, pkt_offset+1, sv_length-1, + "Enabled Function Classes: %04X", pntohs( &pd[2] ) ); + break; + + case 0x07: /* Allowed Access Priority */ + add_item_to_tree(tree, pkt_offset+1, sv_length-1, + "Allowed Access Priority: %04X", pntohs( &pd[2] ) ); + break; + + case 0x09: /* Correlator */ + add_item_to_tree(tree, pkt_offset+1, sv_length-1, + "Correlator: %04X", pntohs( &pd[2] ) ); + break; + + case 0x0A: /* Address of last neighbor notification */ + add_item_to_tree(tree, pkt_offset+1, sv_length-1, + "Address of Last Neighbor Notification: %s", + ether_to_str((guint8*)&pd[2])); + break; + + case 0x0B: /* Physical Location */ + add_item_to_tree(tree, pkt_offset+1, sv_length-1, + "Physical Location: 0x%08X", pntohl( &pd[2] ) ); + break; + + case 0x20: /* Response Code */ + add_item_to_tree(tree, pkt_offset+1, sv_length-1, + "Response Code: 0x%04X 0x%04X", pntohl( &pd[2] ), + pntohl( &pd[4] ) ); + break; + + case 0x21: /* Reserved */ + add_item_to_tree(tree, pkt_offset+1, sv_length-1, + "Reserved: 0x%04X", pntohs( &pd[2] ) ); + break; + + case 0x22: /* Product Instance ID */ + add_item_to_tree(tree, pkt_offset+1, sv_length-1, + "Product Instance ID: ..."); + break; + + case 0x23: /* Ring Station Microcode Level */ + add_item_to_tree(tree, pkt_offset+1, sv_length-1, + "Ring Station Microcode Level: ..."); + break; + + case 0x26: /* Wrap data */ + add_item_to_tree(tree, pkt_offset+1, sv_length-1, + "Wrap Data: ... (%d bytes)", sv_length - 2); + break; + + case 0x27: /* Frame Forward */ + add_item_to_tree(tree, pkt_offset+1, sv_length-1, + "Frame Forward: ... (%d bytes)", sv_length - 2); + break; + + case 0x29: /* Ring Station Status Subvector */ + add_item_to_tree(tree, pkt_offset+1, sv_length-1, + "Ring Station Status Subvector: ..."); + break; + + case 0x2A: /* Transmit Status Code */ + add_item_to_tree(tree, pkt_offset+1, sv_length-1, + "Transmit Status Code: %04X", pntohs( &pd[2] ) ); + break; + + case 0x2B: /* Group Address */ + add_item_to_tree(tree, pkt_offset+1, sv_length-1, + "Group Address: %08X", pntohl( &pd[2] ) ); + break; + + case 0x2C: /* Functional Address */ + add_item_to_tree(tree, pkt_offset+1, sv_length-1, + "Functional Address: %08X", pntohl( &pd[2] ) ); + break; + + case 0x2D: /* Isolating Error Counts */ + memcpy(errors, &pd[2], 6); + ti = add_item_to_tree(GTK_WIDGET(tree), pkt_offset+1, sv_length-1, + "Isolating Error Counts (%d total)", + errors[0] + errors[1] + errors[2] + errors[3] + errors[4]); + sv_tree = gtk_tree_new(); + add_subtree(ti, sv_tree, ETT_TR_IERR_CNT); + + add_item_to_tree(sv_tree, pkt_offset+2, 1, + "Line Errors: %d", errors[0]); + add_item_to_tree(sv_tree, pkt_offset+3, 1, + "Internal Errors: %d", errors[1]); + add_item_to_tree(sv_tree, pkt_offset+4, 1, + "Burst Errors: %d", errors[2]); + add_item_to_tree(sv_tree, pkt_offset+5, 1, + "A/C Errors: %d", errors[3]); + add_item_to_tree(sv_tree, pkt_offset+6, 1, + "Abort delimiter transmitted: %d", errors[4]); + + break; + + case 0x2E: /* Non-Isolating Error Counts */ + memcpy(errors, &pd[2], 6); + ti = add_item_to_tree(GTK_WIDGET(tree), pkt_offset+1, sv_length-1, + "Non-Isolating Error Counts (%d total)", + errors[0] + errors[1] + errors[2] + errors[3] + errors[4]); + sv_tree = gtk_tree_new(); + add_subtree(ti, sv_tree, ETT_TR_NERR_CNT); + + add_item_to_tree(sv_tree, pkt_offset+2, 1, + "Lost Frame Errors: %d", errors[0]); + add_item_to_tree(sv_tree, pkt_offset+3, 1, + "Receiver Congestion: %d", errors[1]); + add_item_to_tree(sv_tree, pkt_offset+4, 1, + "Frame-Copied Congestion: %d", errors[2]); + add_item_to_tree(sv_tree, pkt_offset+5, 1, + "Frequency Errors: %d", errors[3]); + add_item_to_tree(sv_tree, pkt_offset+6, 1, + "Token Errors: %d", errors[4]); + break; + + case 0x30: /* Error Code */ + add_item_to_tree(tree, pkt_offset+1, sv_length-1, + "Error Code: %04X", pntohs( &pd[2] ) ); + break; + + default: /* Unknown */ + add_item_to_tree(tree, pkt_offset+1, 1, + "Unknown Sub-Vector: 0x%02X", pd[1]); + } + return sv_length; +} + +void +dissect_trmac(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) { + + GtkWidget *mac_tree = NULL, *ti; + int mv_length, sv_length, sv_offset; + char *class[] = { "Ring Station", "LLC Manager", "", "", + "Configuration Report Server", "Ring Parameter Server", + "Ring Error Monitor" }; + + if (fd->win_info[0]) { + strcpy(fd->win_info[3], "TR MAC"); + } + + mv_length = ntohs(*((guint16*)&pd[offset])); + + if (tree) { + ti = add_item_to_tree(GTK_WIDGET(tree), offset, mv_length, + "Media Access Control"); + mac_tree = gtk_tree_new(); + add_subtree(ti, mac_tree, ETT_TR_MAC); + } + + /* Interpret the major vector */ + mv_text(pd[offset+3], offset+3, fd, mac_tree); + + if (tree) { + add_item_to_tree(mac_tree, offset, 2, "Total Length: %d bytes", + mv_length); + add_item_to_tree(mac_tree, offset+2, 1, "Source Class: %s", + class[ pd[offset+2] & 0x0f ]); + add_item_to_tree(mac_tree, offset+2, 1, "Destination Class: %s", + class[ pd[offset+2] >> 4 ]); + + /* interpret the subvectors */ + sv_offset = 0; + offset += 4; + sv_length = mv_length - 4; + while (sv_offset < sv_length) { + sv_offset += sv_text(&pd[offset + sv_offset], offset + sv_offset, + mac_tree); + } + } +} diff --git a/packet-udp.c b/packet-udp.c new file mode 100644 index 0000000000..f9d37c71fb --- /dev/null +++ b/packet-udp.c @@ -0,0 +1,92 @@ +/* packet-udp.c + * Routines for UDP packet disassembly + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#ifdef HAVE_NETINET_IN_H +# include +#endif + +#include "ethereal.h" +#include "packet.h" +#include "resolv.h" + +void +dissect_udp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) { + e_udphdr *uh; + guint16 uh_sport, uh_dport, uh_ulen, uh_sum; + GtkWidget *udp_tree, *ti; + + /* To do: Check for {cap len,pkt len} < struct len */ + uh = (e_udphdr *) &pd[offset]; + uh_sport = ntohs(uh->uh_sport); + uh_dport = ntohs(uh->uh_dport); + uh_ulen = ntohs(uh->uh_ulen); + uh_sum = ntohs(uh->uh_sum); + + if (fd->win_info[0]) { + strcpy(fd->win_info[3], "UDP"); + sprintf(fd->win_info[4], "Source port: %s Destination port: %s", + get_udp_port(uh_sport), get_udp_port(uh_dport)); + } + + if (tree) { + ti = add_item_to_tree(GTK_WIDGET(tree), offset, 8, + "User Datagram Protocol"); + udp_tree = gtk_tree_new(); + add_subtree(ti, udp_tree, ETT_UDP); + add_item_to_tree(udp_tree, offset, 2, "Source port: %s", get_udp_port(uh_sport)); + add_item_to_tree(udp_tree, offset + 2, 2, "Destination port: %s", get_udp_port(uh_dport)); + add_item_to_tree(udp_tree, offset + 4, 2, "Length: %d", uh_ulen); + add_item_to_tree(udp_tree, offset + 6, 2, "Checksum: 0x%04x", uh_sum); + } + + /* Skip over header */ + offset += 8; + + /* To do: make sure we aren't screwing ourselves with the MIN call. */ + switch (MIN(uh_sport, uh_dport)) { + case UDP_PORT_BOOTPS: + dissect_bootp(pd, offset, fd, tree); + break; + case UDP_PORT_DNS: + dissect_dns(pd, offset, fd, tree); + break; + case UDP_PORT_RIP: + /* we should check the source port too (RIP: UDP src and dst port 520) */ + dissect_rip(pd, offset, fd, tree); + break; + default: + dissect_data(pd, offset, fd, tree); + } +} diff --git a/packet.c b/packet.c new file mode 100644 index 0000000000..ef30704d1f --- /dev/null +++ b/packet.c @@ -0,0 +1,216 @@ +/* packet.c + * Routines for packet disassembly + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include +#include +#include + +#ifdef HAVE_NETINET_IN_H +# include +#endif + +#include "packet.h" +#include "ethereal.h" +#include "etypes.h" +#include "file.h" + +extern GtkWidget *byte_view; +extern GdkFont *m_r_font, *m_b_font; +extern capture_file cf; + +gchar * +ether_to_str(guint8 *ad) { + static gchar str[3][18]; + static gchar *cur; + + if (cur == &str[0][0]) { + cur = &str[1][0]; + } else if (cur == &str[1][0]) { + cur = &str[2][0]; + } else { + cur = &str[0][0]; + } + sprintf(cur, "%02x:%02x:%02x:%02x:%02x:%02x", ad[0], ad[1], ad[2], + ad[3], ad[4], ad[5]); + return cur; +} + +gchar * +ip_to_str(guint8 *ad) { + static gchar str[3][16]; + static gchar *cur; + + if (cur == &str[0][0]) { + cur = &str[1][0]; + } else if (cur == &str[1][0]) { + cur = &str[2][0]; + } else { + cur = &str[0][0]; + } + sprintf(cur, "%d.%d.%d.%d", ad[0], ad[1], ad[2], ad[3]); + return cur; +} + +void +packet_hex_print(GtkText *bv, guchar *pd, gint len, gint bstart, gint blen) { + gint i = 0, j, k, cur; + gchar line[128], hexchars[] = "0123456789abcdef"; + GdkFont *cur_font, *new_font; + + while (i < len) { + /* Print the line number */ + sprintf(line, "%04x ", i); + gtk_text_insert(bv, m_r_font, NULL, NULL, line, -1); + /* Do we start in bold? */ + cur_font = (i >= bstart && i < (bstart + blen)) ? m_b_font : m_r_font; + j = i; + k = i + BYTE_VIEW_WIDTH; + cur = 0; + /* Print the hex bit */ + while (i < k) { + if (i < len) { + line[cur++] = hexchars[(pd[i] & 0xf0) >> 4]; + line[cur++] = hexchars[pd[i] & 0x0f]; + } else { + line[cur++] = ' '; line[cur++] = ' '; + } + line[cur++] = ' '; + i++; + /* Did we cross a bold/plain boundary? */ + new_font = (i >= bstart && i < (bstart + blen)) ? m_b_font : m_r_font; + if (cur_font != new_font) { + gtk_text_insert(bv, cur_font, NULL, NULL, line, cur); + cur_font = new_font; + cur = 0; + } + } + line[cur++] = ' '; + gtk_text_insert(bv, cur_font, NULL, NULL, line, cur); + cur = 0; + i = j; + /* Print the ASCII bit */ + cur_font = (i >= bstart && i < (bstart + blen)) ? m_b_font : m_r_font; + while (i < k) { + if (i < len) { + line[cur++] = (isgraph(pd[i])) ? pd[i] : '.'; + } else { + line[cur++] = ' '; + } + i++; + /* Did we cross a bold/plain boundary? */ + new_font = (i >= bstart && i < (bstart + blen)) ? m_b_font : m_r_font; + if (cur_font != new_font) { + gtk_text_insert(bv, cur_font, NULL, NULL, line, cur); + cur_font = new_font; + cur = 0; + } + } + line[cur++] = '\n'; + line[cur] = '\0'; + gtk_text_insert(bv, cur_font, NULL, NULL, line, -1); + } +} + +GtkWidget * +add_item_to_tree(GtkWidget *tree, gint start, gint len, + gchar *format, ...) { + GtkWidget *ti; + va_list ap; + gchar label_str[256]; + guint32 t_info; + + /* This limits us to a max packet size of 65535 bytes. */ + /* Are there any systems out there with < 32-bit pointers? */ + /* To do: use gtk_object_set_data instead, now that I know it exists. */ + t_info = ((start & 0xffff) << 16) | (len & 0xffff); + va_start(ap, format); + vsnprintf(label_str, 256, format, ap); + ti = gtk_tree_item_new_with_label(label_str); + gtk_object_set_user_data(GTK_OBJECT(ti), (gpointer) t_info); + gtk_tree_append(GTK_TREE(tree), ti); + gtk_widget_show(ti); + + return ti; +} + +void +add_subtree(GtkWidget *ti, GtkWidget *subtree, gint idx) { + static gint tree_type[NUM_TREE_TYPES]; + + gtk_tree_item_set_subtree(GTK_TREE_ITEM(ti), subtree); + if (tree_type[idx]) + gtk_tree_item_expand(GTK_TREE_ITEM(ti)); + gtk_signal_connect(GTK_OBJECT(ti), "expand", (GtkSignalFunc) expand_tree, + (gpointer) &tree_type[idx]); + gtk_signal_connect(GTK_OBJECT(ti), "collapse", (GtkSignalFunc) collapse_tree, + (gpointer) &tree_type[idx]); +} + +void +expand_tree(GtkWidget *w, gpointer data) { + gint *val = (gint *) data; + *val = 1; +} + +void +collapse_tree(GtkWidget *w, gpointer data) { + gint *val = (gint *) data; + *val = 0; +} + +/* decodes the protocol start and length thare are encoded into + the t_info field in add_item_to_tree. */ +void +decode_start_len(GtkTreeItem *ti, gint *pstart, gint *plen) +{ + guint32 t_info; + int start, len; + + t_info = (guint32) gtk_object_get_user_data(GTK_OBJECT(ti)); + *pstart = t_info >> 16; + *plen = t_info & 0xffff; +} + + +/* this routine checks the frame type from the cf structure */ +void +dissect_packet(const u_char *pd, frame_data *fd, GtkTree *tree) { + + switch (cf.lnk_t) { + case DLT_EN10MB : + dissect_eth(pd, fd, tree); + break; + case DLT_IEEE802 : + dissect_tr(pd, fd, tree); + break; + case DLT_RAW : + dissect_raw(pd, fd, tree); + break; + } +} diff --git a/packet.h b/packet.h new file mode 100644 index 0000000000..9cc9b57139 --- /dev/null +++ b/packet.h @@ -0,0 +1,354 @@ +/* packet.h + * Definitions for packet disassembly structures and routines + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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_H__ +#define __PACKET_H__ + +/* Pointer versions of ntohs and ntohl. Given a pointer to a member of a + * byte array, returns the value of the two or four bytes at the pointer. + * Handy for + */ + +#if BYTE_ORDER == LITTLE_ENDIAN +#define pntohs(p) ((guint16) \ + ((guint16)*((guint8 *)p+0)<<8| \ + (guint16)*((guint8 *)p+1)<<0)) + +#define pntohl(p) ((guint32)*((guint8 *)p+0)<<24| \ + (guint32)*((guint8 *)p+1)<<16| \ + (guint32)*((guint8 *)p+2)<<8| \ + (guint32)*((guint8 *)p+3)<<0) +#else /* BIG_ENDIAN */ +#define pntohs(p) ((guint16) \ + ((guint16)*((guint8 *)p+1)<<8| \ + (guint16)*((guint8 *)p+0)<<0)) + +#define pntohl(p) ((guint32)*((guint8 *)p+3)<<24| \ + (guint32)*((guint8 *)p+2)<<16| \ + (guint32)*((guint8 *)p+1)<<8| \ + (guint32)*((guint8 *)p+0)<<0) +#endif /* LITTLE_ENDIAN */ + +#define IEEE_802_3_MAX_LEN 1500 +#define BYTE_VIEW_WIDTH 16 + +typedef struct _frame_data { + guint32 pkt_len; /* Packet length */ + guint32 cap_len; /* Amount actually captured */ + guint32 secs; /* Seconds */ + guint32 usecs; /* Microseconds */ + long file_off; /* File offset */ + gchar *win_info[5]; /* Packet list text */ +} frame_data; + +/* Many of the structs and definitions below were taken from include files + * in the Linux distribution. */ + +/* ARP / RARP structs and definitions */ + +typedef struct _e_ether_arp { + guint16 ar_hrd; + guint16 ar_pro; + guint8 ar_hln; + guint8 ar_pln; + guint16 ar_op; + guint8 arp_sha[6]; + guint8 arp_spa[4]; + guint8 arp_tha[6]; + guint8 arp_tpa[4]; +} e_ether_arp; + +#ifndef ARPOP_REQUEST +#define ARPOP_REQUEST 1 /* ARP request. */ +#endif +#ifndef ARPOP_REPLY +#define ARPOP_REPLY 2 /* ARP reply. */ +#endif +/* Some OSes have different names, or don't define these at all */ +#ifndef ARPOP_RREQUEST +#define ARPOP_RREQUEST 3 /* RARP request. */ +#endif +#ifndef ARPOP_RREPLY +#define ARPOP_RREPLY 4 /* RARP reply. */ +#endif + +/* ICMP structs and definitions */ + +typedef struct _e_icmp { + guint8 icmp_type; + guint8 icmp_code; + guint16 icmp_cksum; + union { + struct { /* Address mask request/reply */ + guint16 id; + guint16 seq; + guint32 sn_mask; + } am; + struct { /* Timestap request/reply */ + guint16 id; + guint16 seq; + guint32 orig; + guint32 recv; + guint32 xmit; + } ts; + guint32 zero; /* Unreachable */ + } opt; +} e_icmp; + +#define ICMP_ECHOREPLY 0 +#define ICMP_UNREACH 3 +#define ICMP_SOURCEQUENCH 4 +#define ICMP_REDIRECT 5 +#define ICMP_ECHO 8 +#define ICMP_TIMXCEED 11 +#define ICMP_PARAMPROB 12 +#define ICMP_TSTAMP 13 +#define ICMP_TSTAMPREPLY 14 +#define ICMP_IREQ 15 +#define ICMP_IREQREPLY 16 +#define ICMP_MASKREQ 17 +#define ICMP_MASKREPLY 18 + +/* IGMP structs and definitions */ + +typedef struct _e_igmp { +#if BYTE_ORDER == BIG_ENDIAN + guint8 igmp_v:4; + guint8 igmp_t:4; +#else /* Little endian */ + guint8 igmp_t:4; + guint8 igmp_v:4; +#endif + guint8 igmp_unused; + guint16 igmp_cksum; + guint32 igmp_gaddr; +} e_igmp; + +#define IGMP_M_QRY 0x01 +#define IGMP_V1_M_RPT 0x02 +#define IGMP_V2_LV_GRP 0x07 +#define IGMP_DVMRP 0x03 +#define IGMP_PIM 0x04 +#define IGMP_V2_M_RPT 0x06 +#define IGMP_MTRC_RESP 0x1e +#define IGMP_MTRC 0x1f + +/* IP structs and definitions */ + +typedef struct _e_ip { +#if BYTE_ORDER == BIG_ENDIAN + guint8 ip_v:4; + guint8 ip_hl:4; +#else /* Little endian */ + guint8 ip_hl:4; + guint8 ip_v:4; +#endif + guint8 ip_tos; + guint16 ip_len; + guint16 ip_id; + guint16 ip_off; + guint8 ip_ttl; + guint8 ip_p; + guint16 ip_sum; + guint32 ip_src; + guint32 ip_dst; +} e_ip; + +#define IPTOS_TOS_MASK 0x1E +#define IPTOS_TOS(tos) ((tos) & IPTOS_TOS_MASK) +#define IPTOS_NONE 0x00 +#define IPTOS_LOWDELAY 0x10 +#define IPTOS_THROUGHPUT 0x08 +#define IPTOS_RELIABILITY 0x04 +#define IPTOS_LOWCOST 0x02 + +#define IP_PROTO_ICMP 1 +#define IP_PROTO_IGMP 2 +#define IP_PROTO_TCP 6 +#define IP_PROTO_UDP 17 +#define IP_PROTO_OSPF 89 + +/* PPP structs and definitions */ + +typedef struct _e_ppphdr { + guint8 ppp_flag; + guint8 ppp_addr; + guint8 ppp_ctl; + guint16 ppp_prot; +} e_ppphdr; + +/* TCP structs and definitions */ + +typedef struct _e_tcphdr { + guint16 th_sport; + guint16 th_dport; + guint32 th_seq; + guint32 th_ack; +#if BYTE_ORDER == LITTLE_ENDIAN + guint8 th_x2:4; + guint8 th_off:4; +#else + guint8 th_off:4; + guint8 th_x2:4; +#endif + guint8 th_flags; +#define TH_FIN 0x01 +#define TH_SYN 0x02 +#define TH_RST 0x04 +#define TH_PUSH 0x08 +#define TH_ACK 0x10 +#define TH_URG 0x20 + guint16 th_win; + guint16 th_sum; + guint16 th_urp; +} e_tcphdr; + +/* UDP structs and definitions */ + +typedef struct _e_udphdr { + guint16 uh_sport; + guint16 uh_dport; + guint16 uh_ulen; + guint16 uh_sum; +} e_udphdr; + +/* UDP Ports -> should go in packet-udp.h */ + +#define UDP_PORT_DNS 53 +#define UDP_PORT_BOOTPS 67 +#define UDP_PORT_RIP 520 + +/* TCP Ports */ + +#define TCP_PORT_PRINTER 515 + +/* Tree types. Each dissect_* routine should have one for each + add_subtree() call. */ + +#define ETT_IEEE8023 0 +#define ETT_ETHER2 1 +#define ETT_LLC 2 +#define ETT_TOKEN_RING 3 +#define ETT_TR_IERR_CNT 4 +#define ETT_TR_NERR_CNT 5 +#define ETT_TR_MAC 6 +#define ETT_PPP 7 +#define ETT_ARP 8 +#define ETT_IP 9 +#define ETT_UDP 10 +#define ETT_TCP 11 +#define ETT_ICMP 12 +#define ETT_IGMP 13 +#define ETT_IPX 14 +#define ETT_SPX 15 +#define ETT_NCP 16 +#define ETT_DNS 17 +#define ETT_DNS_ANS 18 +#define ETT_DNS_QRY 19 +#define ETT_RIP 20 +#define ETT_RIP_VEC 21 +#define ETT_OSPF 22 +#define ETT_OSPF_HDR 23 +#define ETT_OSPF_HELLO 24 +#define ETT_OSPF_DESC 25 +#define ETT_OSPF_LSR 26 +#define ETT_OSPF_LSA_UPD 27 +#define ETT_OSPF_LSA 28 +#define ETT_LPD 29 +#define ETT_RAW 30 +#define ETT_BOOTP 31 +#define ETT_BOOTP_OPTION 32 +#define ETT_IPv6 33 + +/* Should be the last item number plus one */ +#define NUM_TREE_TYPES 34 + +/* The version of pcap.h that comes with some systems is missing these + * #defines. + */ + +#ifndef DLT_RAW +#define DLT_RAW 12 +#endif + +#ifndef DLT_SLIP_BSDOS +#define DLT_SLIP_BSDOS 13 +#endif + +#ifndef DLT_PPP_BSDOS +#define DLT_PPP_BSDOS 14 +#endif + +/* Utility routines used by packet*.c */ +gchar* ether_to_str(guint8 *); +gchar* ip_to_str(guint8 *); +void packet_hex_print(GtkText *, guint8 *, gint, gint, gint); +GtkWidget* add_item_to_tree(GtkWidget *, gint, gint, gchar *, ...); +void decode_start_len(GtkTreeItem *, gint*, gint*); + +/* Routines in packet.c */ +void dissect_packet(const u_char *, frame_data *, GtkTree *); +void add_subtree(GtkWidget *, GtkWidget*, gint); +void expand_tree(GtkWidget *, gpointer); +void collapse_tree(GtkWidget *, gpointer); + +/* + * Routines in packet-*.c + * Routines should take three args: packet data *, frame_data *, tree * + * They should never modify the packet data. + */ +void dissect_eth(const u_char *, frame_data *, GtkTree *); +void dissect_ppp(const u_char *, frame_data *, GtkTree *); +void dissect_raw(const u_char *, frame_data *, GtkTree *); +void dissect_tr(const u_char *, frame_data *, GtkTree *); + +/* + * Routines in packet-*.c + * Routines should take four args: packet data *, offset, frame_data *, + * tree * + * They should never modify the packet data. + */ +void dissect_arp(const u_char *, int, frame_data *, GtkTree *); +void dissect_bootp(const u_char *, int, frame_data *, GtkTree *); +void dissect_data(const u_char *, int, frame_data *, GtkTree *); +void dissect_dns(const u_char *, int, frame_data *, GtkTree *); +void dissect_icmp(const u_char *, int, frame_data *, GtkTree *); +void dissect_igmp(const u_char *, int, frame_data *, GtkTree *); +void dissect_ip(const u_char *, int, frame_data *, GtkTree *); +void dissect_ipv6(const u_char *, int, frame_data *, GtkTree *); +void dissect_ipx(const u_char *, int, frame_data *, GtkTree *); +void dissect_llc(const u_char *, int, frame_data *, GtkTree *); +void dissect_lpd(const u_char *, int, frame_data *, GtkTree *); +void dissect_ospf(const u_char *, int, frame_data *, GtkTree *); +void dissect_ospf_hello(const u_char *, int, frame_data *, GtkTree *); +void dissect_tcp(const u_char *, int, frame_data *, GtkTree *); +void dissect_trmac(const u_char *, int, frame_data *, GtkTree *); +void dissect_udp(const u_char *, int, frame_data *, GtkTree *); + +/* This function is in ethertype.c */ +void ethertype(guint16 etype, int offset, + const u_char *pd, frame_data *fd, GtkTree *tree, + GtkWidget *fh_tree); + +#endif /* packet.h */ diff --git a/print.c b/print.c new file mode 100644 index 0000000000..4ec296f8ea --- /dev/null +++ b/print.c @@ -0,0 +1,509 @@ +/* print.c + * Routines for printing packet analysis trees. + * + * Gilbert Ramirez + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#include "packet.h" +#include "print.h" + +static void printer_opts_file_cb(GtkWidget *w, gpointer te); +static void printer_opts_fs_cancel_cb(GtkWidget *w, gpointer data); +static void printer_opts_fs_ok_cb(GtkWidget *w, gpointer data); +static void printer_opts_ok_cb(GtkWidget *w, gpointer data); +static void printer_opts_close_cb(GtkWidget *w, gpointer win); +static void printer_opts_toggle_format(GtkWidget *widget, gpointer data); +static void printer_opts_toggle_dest(GtkWidget *widget, gpointer data); +static void dumpit (FILE *fh, register const u_char *cp, register u_int length); +static void dumpit_ps (FILE *fh, register const u_char *cp, register u_int length); +static void ps_clean_string(unsigned char *out, const unsigned char *in, + int outbuf_size); + +/* #include "ps.c" */ + +pr_opts printer_opts; + +void printer_opts_cb(GtkWidget *w, gpointer d) +{ + GtkWidget *propt_w, *main_vb, *button; + GtkWidget *format_hb, *format_lb; + GtkWidget *dest_hb, *dest_lb; + GtkWidget *cmd_hb, *cmd_lb, *cmd_te; + GtkWidget *file_hb, *file_bt, *file_te; + GtkWidget *bbox, *ok_bt, *cancel_bt; + GSList *format_grp, *dest_grp; + pr_opts *temp_pr_opts = g_malloc(sizeof(pr_opts)); + + /* Make a working copy of the printer data */ + memcpy(temp_pr_opts, &printer_opts, sizeof(pr_opts)); +/* temp_pr_opts->cmd = g_strdup(printer_opts->cmd); + temp_pr_opts->file = g_strdup(printer_opts->file);*/ + + propt_w = gtk_window_new(GTK_WINDOW_TOPLEVEL); + temp_pr_opts->window = propt_w; + + /* Container for each row of widgets */ + main_vb = gtk_vbox_new(FALSE, 3); + gtk_container_border_width(GTK_CONTAINER(main_vb), 5); + gtk_container_add(GTK_CONTAINER(propt_w), main_vb); + gtk_widget_show(main_vb); + + /* Output format */ + format_hb = gtk_hbox_new(FALSE, 1); + gtk_container_add(GTK_CONTAINER(main_vb), format_hb); + gtk_widget_show(format_hb); + + format_lb = gtk_label_new("Format:"); + gtk_box_pack_start(GTK_BOX(format_hb), format_lb, FALSE, FALSE, 3); + gtk_widget_show(format_lb); + + button = gtk_radio_button_new_with_label(NULL, "Plain Text"); + if (printer_opts.output_format == 0) { + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), TRUE); + } + format_grp = gtk_radio_button_group(GTK_RADIO_BUTTON(button)); + gtk_box_pack_start(GTK_BOX(format_hb), button, TRUE, TRUE, 0); + gtk_widget_show(button); + + button = gtk_radio_button_new_with_label(format_grp, "PostScript"); + if (printer_opts.output_format == 1) { + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), TRUE); + } + gtk_signal_connect(GTK_OBJECT(button), "toggled", + GTK_SIGNAL_FUNC(printer_opts_toggle_format), + (gpointer)temp_pr_opts); + gtk_box_pack_start(GTK_BOX(format_hb), button, TRUE, TRUE, 0); + gtk_widget_show(button); + + /* Output destination */ + dest_hb = gtk_hbox_new(FALSE, 1); + gtk_container_add(GTK_CONTAINER(main_vb), dest_hb); + gtk_widget_show(dest_hb); + + dest_lb = gtk_label_new("Print to:"); + gtk_box_pack_start(GTK_BOX(dest_hb), dest_lb, FALSE, FALSE, 3); + gtk_widget_show(dest_lb); + + button = gtk_radio_button_new_with_label(NULL, "Command"); + if (printer_opts.output_dest == 0) { + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), TRUE); + } + dest_grp = gtk_radio_button_group(GTK_RADIO_BUTTON(button)); + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), TRUE); + gtk_box_pack_start(GTK_BOX(dest_hb), button, TRUE, TRUE, 0); + gtk_widget_show(button); + + button = gtk_radio_button_new_with_label(dest_grp, "File"); + if (printer_opts.output_dest == 1) { + gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(button), TRUE); + } + gtk_signal_connect(GTK_OBJECT(button), "toggled", + GTK_SIGNAL_FUNC(printer_opts_toggle_dest), + (gpointer)temp_pr_opts); + gtk_box_pack_start(GTK_BOX(dest_hb), button, TRUE, TRUE, 0); + gtk_widget_show(button); + + /* Command text entry */ + cmd_hb = gtk_hbox_new(FALSE, 1); + gtk_container_add(GTK_CONTAINER(main_vb), cmd_hb); + gtk_widget_show(cmd_hb); + + cmd_lb = gtk_label_new("Command:"); + gtk_box_pack_start(GTK_BOX(cmd_hb), cmd_lb, FALSE, FALSE, 3); + gtk_widget_show(cmd_lb); + + cmd_te = gtk_entry_new(); + temp_pr_opts->cmd_te = cmd_te; + gtk_entry_set_text(GTK_ENTRY(cmd_te), printer_opts.cmd); + gtk_box_pack_start(GTK_BOX(cmd_hb), cmd_te, TRUE, TRUE, 3); + gtk_widget_show(cmd_te); + + /* File button and text entry */ + file_hb = gtk_hbox_new(FALSE, 1); + gtk_container_add(GTK_CONTAINER(main_vb), file_hb); + gtk_widget_show(file_hb); + + file_bt = gtk_button_new_with_label("File:"); + gtk_box_pack_start(GTK_BOX(file_hb), file_bt, FALSE, FALSE, 3); + gtk_widget_show(file_bt); + + file_te = gtk_entry_new(); + temp_pr_opts->file_te = file_te; + gtk_entry_set_text(GTK_ENTRY(file_te), printer_opts.file); + gtk_box_pack_start(GTK_BOX(file_hb), file_te, TRUE, TRUE, 3); + gtk_widget_show(file_te); + + gtk_signal_connect_object(GTK_OBJECT(file_bt), "clicked", + GTK_SIGNAL_FUNC(printer_opts_file_cb), GTK_OBJECT(file_te)); + + + /* Button row: OK and cancel buttons */ + bbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END); + gtk_container_add(GTK_CONTAINER(main_vb), bbox); + gtk_widget_show(bbox); + + ok_bt = gtk_button_new_with_label ("OK"); + gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked", + GTK_SIGNAL_FUNC(printer_opts_ok_cb), (gpointer)temp_pr_opts); + gtk_container_add(GTK_CONTAINER(bbox), ok_bt); + gtk_widget_show(ok_bt); + + cancel_bt = gtk_button_new_with_label ("Cancel"); + gtk_signal_connect_object(GTK_OBJECT(cancel_bt), "clicked", + GTK_SIGNAL_FUNC(printer_opts_close_cb), (gpointer)temp_pr_opts); + gtk_container_add(GTK_CONTAINER(bbox), cancel_bt); + gtk_widget_show(cancel_bt); + + /* Show the completed window */ + gtk_widget_show(propt_w); +} + + +static void +printer_opts_file_cb(GtkWidget *w, gpointer te) { + GtkWidget *fs, **w_list; + + w_list = g_malloc(2 * sizeof(GtkWidget *)); + + fs = gtk_file_selection_new ("Ethereal: Print to a File"); + w_list[0] = fs; + w_list[1] = (GtkWidget *) te; + + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION(fs)->ok_button), + "clicked", (GtkSignalFunc) printer_opts_fs_ok_cb, w_list); + + /* Connect the cancel_button to destroy the widget */ + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION(fs)->cancel_button), + "clicked", (GtkSignalFunc) printer_opts_fs_cancel_cb, w_list); + + gtk_widget_show(fs); +} + +static void +printer_opts_fs_ok_cb(GtkWidget *w, gpointer data) { + GtkWidget **w_list = (GtkWidget **) data; + + gtk_entry_set_text(GTK_ENTRY(w_list[1]), + gtk_file_selection_get_filename (GTK_FILE_SELECTION(w_list[0]))); + printer_opts_fs_cancel_cb(w, data); +} + +static void +printer_opts_fs_cancel_cb(GtkWidget *w, gpointer data) { + GtkWidget **w_list = (GtkWidget **) data; + + gtk_widget_destroy(w_list[0]); + g_free(data); +} + +static void +printer_opts_ok_cb(GtkWidget *w, gpointer data) +{ + printer_opts.output_format = ((pr_opts*)data)->output_format; + printer_opts.output_dest = ((pr_opts*)data)->output_dest; + + free(printer_opts.cmd); + printer_opts.cmd = + g_strdup(gtk_entry_get_text(GTK_ENTRY(((pr_opts*)data)->cmd_te))); + + free(printer_opts.file); + printer_opts.file = + g_strdup(gtk_entry_get_text(GTK_ENTRY(((pr_opts*)data)->file_te))); + + gtk_widget_destroy(GTK_WIDGET(((pr_opts*)data)->window)); + g_free(data); +} + +static void +printer_opts_close_cb(GtkWidget *w, gpointer data) +{ + gtk_widget_destroy(GTK_WIDGET(((pr_opts*)data)->window)); + g_free(data); +} + +static void +printer_opts_toggle_format(GtkWidget *widget, gpointer data) +{ + if (GTK_TOGGLE_BUTTON (widget)->active) { + ((pr_opts*)data)->output_format = 1; + /* toggle file/cmd */ + } + else { + ((pr_opts*)data)->output_format = 0; + /* toggle file/cmd */ + } +} + +static void +printer_opts_toggle_dest(GtkWidget *widget, gpointer data) +{ + if (GTK_TOGGLE_BUTTON (widget)->active) { + ((pr_opts*)data)->output_dest = 1; + } + else { + ((pr_opts*)data)->output_dest = 0; + } +} + +/* ========================================================== */ +void print_tree(const u_char *pd, frame_data *fd, GtkTree *tree) +{ + FILE *fh; + char *out; + + /* Open the file or command for output */ + if (printer_opts.output_dest == 0) { + out = printer_opts.cmd; + fh = popen(printer_opts.cmd, "w"); + } + else { + out = printer_opts.file; + fh = fopen(printer_opts.file, "w"); + } + + if (!fh) { + g_error("Cannot open %s for output.\n", out); + return; + } + + /* Create the output */ + if (printer_opts.output_format == 0) { + print_tree_text(fh, pd, fd, tree); + } + else { + print_ps_preamble(fh); + print_tree_ps(fh, pd, fd, tree); + print_ps_finale(fh); + } + + /* Close the file or command */ + if (printer_opts.output_dest == 0) { + pclose(fh); + } + else { + fclose(fh); + } +} + +/* Print a tree's data in plain text */ +void print_tree_text(FILE *fh, const u_char *pd, frame_data *fd, GtkTree *tree) +{ + GList *children, *child, *widgets, *label; + GtkWidget *subtree; + int num_children, i, j; + char *text; + int num_spaces; + char space[41]; + gint data_start, data_len; + + /* Prepare the tabs for printing, depending on tree level */ + num_spaces = tree->level * 4; + if (num_spaces > 40) { + num_spaces = 40; + } + for (i = 0; i < num_spaces; i++) { + space[i] = ' '; + } + /* The string is NUL-terminated */ + space[num_spaces] = 0; + + /* Get the children of this tree */ + children = tree->children; + num_children = g_list_length(children); + + for (i = 0; i < num_children; i++) { + /* Each child of the tree is a widget container */ + child = g_list_nth(children, i); + widgets = gtk_container_children(GTK_CONTAINER(child->data)); + + /* And the container holds a label object, which holds text */ + label = g_list_nth(widgets, 0); + gtk_label_get(GTK_LABEL(label->data), &text); + + /* Print the text */ + fprintf(fh, "%s%s\n", space, text); + + /* Recurse into the subtree, if it exists */ + subtree = (GTK_TREE_ITEM(child->data))->subtree; + if (subtree) { + print_tree_text(fh, pd, fd, GTK_TREE(subtree)); + } + else if (strcmp("Data", text) == 0) { + decode_start_len(GTK_TREE_ITEM(child->data), &data_start, &data_len); + dumpit(fh, &pd[data_start], data_len); + } + } +} + +/* This routine was created by Dan Lasley , and +only slightly modified for ethereal by Gilbert Ramirez. */ +static +void dumpit (FILE *fh, register const u_char *cp, register u_int length) +{ + register int ad, i, j, k; + u_char c; + u_char line[60]; + static u_char binhex[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + + memset (line, ' ', sizeof line); + line[sizeof (line)-1] = 0; + for (ad=i=j=k=0; i>4]; + line[j++] = binhex[c&0xf]; + if (i&1) j++; + line[42+k++] = c >= ' ' && c < 0x7f ? c : '.'; + if ((i & 15) == 15) { + fprintf (fh, "\n%4x %s", ad, line); + /*if (i==15) printf (" %d", length);*/ + memset (line, ' ', sizeof line); + line[sizeof (line)-1] = j = k = 0; + ad += 16; + } + } + + if (line[0] != ' ') fprintf (fh, "\n%4x %s", ad, line); + fprintf(fh, "\n"); + return; + +} + +#define MAX_LINE_LENGTH 256 + +static +void dumpit_ps (FILE *fh, register const u_char *cp, register u_int length) +{ + register int ad, i, j, k; + u_char c; + u_char line[60]; + static u_char binhex[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + u_char psline[MAX_LINE_LENGTH]; + + memset (line, ' ', sizeof line); + line[sizeof (line)-1] = 0; + for (ad=i=j=k=0; i>4]; + line[j++] = binhex[c&0xf]; + if (i&1) j++; + line[42+k++] = c >= ' ' && c < 0x7f ? c : '.'; + if ((i & 15) == 15) { + ps_clean_string(psline, line, MAX_LINE_LENGTH); + fprintf (fh, "(%4x %s) hexdump\n", ad, psline); + memset (line, ' ', sizeof line); + line[sizeof (line)-1] = j = k = 0; + ad += 16; + } + } + + if (line[0] != ' ') { + ps_clean_string(psline, line, MAX_LINE_LENGTH); + fprintf (fh, "(%4x %s) hexdump\n", ad, psline); + } + return; + +} + +/* Print a tree's data in PostScript */ +void print_tree_ps(FILE *fh, const u_char *pd, frame_data *fd, GtkTree *tree) +{ + GList *children, *child, *widgets, *label; + GtkWidget *subtree; + int num_children, i, j; + char *text; + gint data_start, data_len; + char psbuffer[MAX_LINE_LENGTH]; /* static sized buffer! */ + + /* Get the children of this tree */ + children = tree->children; + num_children = g_list_length(children); + + for (i = 0; i < num_children; i++) { + /* Each child of the tree is a widget container */ + child = g_list_nth(children, i); + widgets = gtk_container_children(GTK_CONTAINER(child->data)); + + /* And the container holds a label object, which holds text */ + label = g_list_nth(widgets, 0); + gtk_label_get(GTK_LABEL(label->data), &text); + + /* Print the text */ + ps_clean_string(psbuffer, text, MAX_LINE_LENGTH); + fprintf(fh, "%d (%s) putline\n", tree->level, psbuffer); + + /* Recurse into the subtree, if it exists */ + subtree = (GTK_TREE_ITEM(child->data))->subtree; + if (subtree) { + print_tree_ps(fh, pd, fd, GTK_TREE(subtree)); + } + else if (strcmp("Data", text) == 0) { + decode_start_len(GTK_TREE_ITEM(child->data), &data_start, &data_len); + print_ps_hex(fh); + dumpit_ps(fh, &pd[data_start], data_len); + } + } +} + +static +void ps_clean_string(unsigned char *out, const unsigned char *in, + int outbuf_size) +{ + int rd, wr; + char c; + + for (rd = 0, wr = 0 ; wr < outbuf_size; rd++, wr++ ) { + c = in[rd]; + switch (c) { + case '(': + case ')': + case '\\': + out[wr] = '\\'; + out[++wr] = c; + break; + + default: + out[wr] = c; + break; + } + + if (c == 0) { + break; + } + } +} diff --git a/print.h b/print.h new file mode 100644 index 0000000000..07b5a4d086 --- /dev/null +++ b/print.h @@ -0,0 +1,47 @@ +/* print.h + * Definitions for printing packet analysis trees. + * + * Gilbert Ramirez + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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 __PRINT_H__ +#define __PRINT_H__ + +typedef struct pr_opts { + int output_format; /* 0=text, 1=postscript */ + int output_dest; /* 0=cmd, 1=file */ + char *file; + char *cmd; + + /* for the dialogue box */ + GtkWidget *window; + GtkWidget *cmd_te; + GtkWidget *file_te; +} pr_opts; + +/* Functions in print.h */ + +void printer_opts_cb(GtkWidget *, gpointer); +void print_tree_text(FILE *fh, const u_char *pd, frame_data *fd, GtkTree *tree); +void print_tree_ps(FILE *fh, const u_char *pd, frame_data *fd, GtkTree *tree); + +#endif /* print.h */ diff --git a/print.ps b/print.ps new file mode 100644 index 0000000000..b1277df79f --- /dev/null +++ b/print.ps @@ -0,0 +1,100 @@ +%! +% +% Code between start/end remarks is put into ps.c +% Anything else is thrown away, and is for testing only. +% +% ---- ethereal preamble start ---- % +%! +%!PS-Adobe-2.0 +% +% Ethereal - Network traffic analyzer +% By Gerald Combs +% Copyright 1998 Gerald Combs +% +%%Creator: Ethereal +%%Title: ethereal.ps +%%DocumentFonts: Helvetica Courier +%%EndComments +%! + +% Get the Imagable Area of the page +clippath pathbbox + +% Set vmax to the vertical size of the page, +% hmax to the horizontal size of the page. +/vmax exch def +/hmax exch def +pop pop % junk + +% 1-inch margins +/lmargin 72 def +/tmargin vmax 72 sub def +/bmargin 72 def + +% Counters +/vpos vmax 70 sub def + +/putline { + exch 10 mul lmargin add % X + vpos % Y + moveto + show + + /vpos vpos 10 sub def + + vpos bmargin le % is vpos <= bottom margin? + {showpage + /vpos tmargin def} + if % then formfeed and start at top +} def + +/hexdump { + lmargin % X + vpos % Y + moveto + show + + /vpos vpos 10 sub def + + vpos bmargin le % is vpos <= bottom margin? + {showpage + /vpos tmargin def} + if % then formfeed and start at top +} def + +% Set the font to 10 point +/Helvetica findfont 10 scalefont setfont + +% Display our output lines. +% ---- ethereal preamble end ---- % +0 (Ethernet II \(98 on wire, 68 captured\)) putline +1 (Destination: 00:00:0c:36:00:2a) putline +1 (Source: 00:c0:4f:c7:eb:c0) putline +1 (Type: IP \(0x0800\)) putline +0 (Ethernet II \(98 on wire, 68 captured\)) putline +1 (Source: 00:c0:4f:c7:eb:c0) putline +1 (Type: IP \(0x0800\)) putline +0 (Source: 00:c0:4f:c7:eb:c0) putline + +% ---- ethereal hex start ---- % +% Set the font to 10 point +/Courier findfont 10 scalefont setfont +() hexdump +% ---- ethereal hex end ---- % + +( 0 cc00 0000 0000 0702 0000 0000 0000 0000 ................ ) hexdump +( 10 0000 bd0e fe16 0100 3e00 0308 584c 2038 ........>...XL 8 ) hexdump +( 20 3020 494d 3300 1601 0034 0016 0101 3500 0 IM3....4....5. ) hexdump +( 30 1601 0236 0016 0103 6e00 1601 ff6f 0016 ...6....n....o.. ) hexdump +( 40 01ff 7000 1601 ff71 0016 01ff 4800 0104 ..p....q....H... ) hexdump +( 50 ff03 0700 2400 0101 0525 0001 0105 2600 ....$....%....&. ) hexdump +( 60 0101 0527 0001 0105 6a00 0101 006b 0001 ...'....j....k.. ) hexdump +( 70 0100 6c00 0101 006d 0001 0100 3d00 0102 ..l....m....=... ) hexdump +( 80 0200 c000 0308 8000 0000 0000 0000 b400 ................ ) hexdump +( 90 0104 c0a8 42ef 3900 1608 0505 0505 0000 ....B.9......... ) hexdump +( a0 0000 0003 2036 4120 5269 6e67 0000 0000 .... 6A Ring.... ) hexdump +( b0 0000 0000 0000 ...... ) hexdump + +% ---- ethereal finale start ---- % +showpage +% ---- ethereal finale end ---- % diff --git a/ps.c b/ps.c new file mode 100644 index 0000000000..2de8f706e4 --- /dev/null +++ b/ps.c @@ -0,0 +1,87 @@ +/* Created by rdps.c. Do not edit! */ + +#include + +#include + +/* Created by rdps.c. Do not edit! */ +void print_ps_preamble(FILE *fd) { + fprintf(fd, "%%!\n"); + fprintf(fd, "%%!PS-Adobe-2.0\n"); + fprintf(fd, "%%\n"); + fprintf(fd, "%% Ethereal - Network traffic analyzer\n"); + fprintf(fd, "%% By Gerald Combs \n"); + fprintf(fd, "%% Copyright 1998 Gerald Combs\n"); + fprintf(fd, "%%\n"); + fprintf(fd, "%%%%Creator: Ethereal\n"); + fprintf(fd, "%%%%Title: ethereal.ps\n"); + fprintf(fd, "%%%%DocumentFonts: Helvetica Courier\n"); + fprintf(fd, "%%%%EndComments\n"); + fprintf(fd, "%%!\n"); + fprintf(fd, "\n"); + fprintf(fd, "%% Get the Imagable Area of the page\n"); + fprintf(fd, "clippath pathbbox\n"); + fprintf(fd, "\n"); + fprintf(fd, "%% Set vmax to the vertical size of the page,\n"); + fprintf(fd, "%% hmax to the horizontal size of the page.\n"); + fprintf(fd, "/vmax exch def\n"); + fprintf(fd, "/hmax exch def\n"); + fprintf(fd, "pop pop %% junk\n"); + fprintf(fd, "\n"); + fprintf(fd, "%% 1-inch margins\n"); + fprintf(fd, "/lmargin 72 def\n"); + fprintf(fd, "/tmargin vmax 72 sub def\n"); + fprintf(fd, "/bmargin 72 def\n"); + fprintf(fd, "\n"); + fprintf(fd, "%% Counters\n"); + fprintf(fd, "/vpos vmax 70 sub def\n"); + fprintf(fd, "\n"); + fprintf(fd, "/putline {\n"); + fprintf(fd, " exch 10 mul lmargin add %% X\n"); + fprintf(fd, " vpos %% Y\n"); + fprintf(fd, " moveto\n"); + fprintf(fd, " show\n"); + fprintf(fd, "\n"); + fprintf(fd, " /vpos vpos 10 sub def\n"); + fprintf(fd, "\n"); + fprintf(fd, " vpos bmargin le %% is vpos <= bottom margin?\n"); + fprintf(fd, " {showpage\n"); + fprintf(fd, " /vpos tmargin def}\n"); + fprintf(fd, " if %% then formfeed and start at top\n"); + fprintf(fd, "} def\n"); + fprintf(fd, "\n"); + fprintf(fd, "/hexdump {\n"); + fprintf(fd, " lmargin %% X\n"); + fprintf(fd, " vpos %% Y\n"); + fprintf(fd, " moveto\n"); + fprintf(fd, " show\n"); + fprintf(fd, "\n"); + fprintf(fd, " /vpos vpos 10 sub def\n"); + fprintf(fd, "\n"); + fprintf(fd, " vpos bmargin le %% is vpos <= bottom margin?\n"); + fprintf(fd, " {showpage\n"); + fprintf(fd, " /vpos tmargin def}\n"); + fprintf(fd, " if %% then formfeed and start at top\n"); + fprintf(fd, "} def\n"); + fprintf(fd, "\n"); + fprintf(fd, "%% Set the font to 10 point\n"); + fprintf(fd, "/Helvetica findfont 10 scalefont setfont\n"); + fprintf(fd, "\n"); + fprintf(fd, "%% Display our output lines.\n"); +} + + +/* Created by rdps.c. Do not edit! */ +void print_ps_hex(FILE *fd) { + fprintf(fd, "%% Set the font to 10 point\n"); + fprintf(fd, "/Courier findfont 10 scalefont setfont\n"); + fprintf(fd, "() hexdump\n"); +} + + +/* Created by rdps.c. Do not edit! */ +void print_ps_finale(FILE *fd) { + fprintf(fd, "showpage\n"); +} + + diff --git a/ps.h b/ps.h new file mode 100644 index 0000000000..8a1a06adb6 --- /dev/null +++ b/ps.h @@ -0,0 +1,35 @@ +/* ps.h + * Definitions for generating PostScript(R) packet output. + * + * Gilbert Ramirez + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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 __PS_H__ +#define __PS_H__ + +/* Functions in ps.c; automatically generated by rdps */ + +void print_ps_preamble(FILE *); +void print_ps_hex(FILE *); +void print_ps_finale(FILE *); + +#endif /* ps.h */ diff --git a/rdps.c b/rdps.c new file mode 100644 index 0000000000..a15cb72edc --- /dev/null +++ b/rdps.c @@ -0,0 +1,185 @@ +/* rdps.c + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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. + */ + +/* takes the file listed as the first argument and creates the file listed +as the second argument. It takes a PostScript file and creates a C program +with 3 functions: + print_ps_preamble() + print_ps_hex() + print_ps_finale() + +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include +#include + +#define BUFFER_SIZE 1024 + +void start_code(FILE *fd, char *func); +void write_code(FILE *fd, char *string); +void end_code(FILE *fd); +void ps_clean_string(unsigned char *out, const unsigned char *in, + int outbuf_size); + +enum ps_state { null, preamble, hex, finale }; + +int main(int argc, char **argv) +{ + FILE *input; + FILE *output; + char buf[BUFFER_SIZE]; /* static sized buffer! */ + enum ps_state state = null; + + if (argc != 3) { + fprintf(stderr, "%s: input_file output_file\n", argv[0]); + exit(-1); + } + + if (!(input = fopen(argv[1], "r"))) { + fprintf(stderr, "%s: cannot open %s for input.\n", argv[0], argv[1]); + exit(-1); + } + + if (!(output = fopen(argv[2], "w"))) { + fprintf(stderr, "%s: cannot open %s for output.\n", argv[0], argv[2]); + exit(-1); + } + + fprintf(output, "/* Created by rdps.c. Do not edit! */\n\n" + "#include \n\n" + "#include \n\n"); + + while (fgets(buf, BUFFER_SIZE - 1, input)) { + + if (state == null) { + if (strcmp(buf, "% ---- ethereal preamble start ---- %\n") == 0) { + state = preamble; + start_code(output, "preamble"); + continue; + } + else if (strcmp(buf, "% ---- ethereal hex start ---- %\n") == 0) { + state = hex; + start_code(output, "hex"); + continue; + } + else if (strcmp(buf, "% ---- ethereal finale start ---- %\n") == 0) { + state = finale; + start_code(output, "finale"); + continue; + } + } + else if (state == preamble) { + if (strcmp(buf, "% ---- ethereal preamble end ---- %\n") == 0) { + state = null; + end_code(output); + continue; + } + else { + write_code(output, buf); + } + } + else if (state == hex) { + if (strcmp(buf, "% ---- ethereal hex end ---- %\n") == 0) { + state = null; + end_code(output); + continue; + } + else { + write_code(output, buf); + } + } + else if (state == finale) { + if (strcmp(buf, "% ---- ethereal finale end ---- %\n") == 0) { + state = null; + end_code(output); + continue; + } + else { + write_code(output, buf); + } + } + else { + fprintf(stderr, "NO MATCH:%s", buf); + exit(-1); + } + } + exit(0); +} + +void start_code(FILE *fd, char *func) +{ + fprintf(fd, "/* Created by rdps.c. Do not edit! */\n"); + fprintf(fd, "void print_ps_%s(FILE *fd) {\n", func); +} + +void write_code(FILE *fd, char *string) +{ + char psbuf[BUFFER_SIZE]; + ps_clean_string(psbuf, string, BUFFER_SIZE); + fprintf(fd, "\tfprintf(fd, \"%s\");\n", psbuf); +} + +void end_code(FILE *fd) +{ + fprintf(fd, "}\n\n\n"); +} + +void ps_clean_string(unsigned char *out, const unsigned char *in, + int outbuf_size) +{ + int rd, wr; + char c; + + for (rd = 0, wr = 0 ; wr < outbuf_size; rd++, wr++ ) { + c = in[rd]; + switch (c) { + case '\\': + out[wr] = '\\'; + out[++wr] = '\\'; + out[++wr] = c; + break; + + case '%': + out[wr] = '%'; + out[++wr] = '%'; + break; + + case '\n': + out[wr] = '\\'; + out[++wr] = 'n'; + break; + + default: + out[wr] = c; + break; + } + + if (c == 0) { + break; + } + } +} diff --git a/resolv.c b/resolv.c new file mode 100644 index 0000000000..bcc9211a68 --- /dev/null +++ b/resolv.c @@ -0,0 +1,269 @@ +/* resolv.c + * Routines for network object lookup + * + * Laurent Deniel + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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. + * + * + * To do: + * + * - Add ethernet address resolution + * - In a future live capture and decode mode, + * add hostname entries in hash table from DNS packet decoding. + * + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifndef AVOID_DNS_TIMEOUT +#define AVOID_DNS_TIMEOUT +#endif + +#include +#include +#include +#include + +#ifdef HAVE_SYS_TYPES_H +# include +#endif + +#ifdef HAVE_NETINET_IN_H +# include +#endif + +#include +#include +#include + +#ifdef AVOID_DNS_TIMEOUT +# include +#endif + +#include "packet.h" +#include "resolv.h" + +#define MAXNAMELEN 64 /* max name length (hostname and port name) */ +#define HASHHOSTSIZE 1024 +#define HASHPORTSIZE 256 + +/* hash table used for host and port lookup */ + +typedef struct hashname { + u_int addr; + u_char name[MAXNAMELEN]; + struct hashname *next; +} hashname_t; + +static hashname_t *host_table[HASHHOSTSIZE]; +static hashname_t *udp_port_table[HASHPORTSIZE]; +static hashname_t *tcp_port_table[HASHPORTSIZE]; + +/* global variable that indicates if name resolving is actif */ + +int g_resolving_actif = 1; /* routines are active by default */ + +/* local function definitions */ + +static u_char *serv_name_lookup(u_int port, u_int proto) +{ + + hashname_t *tp; + hashname_t **table; + char *serv_proto = NULL; + struct servent *servp; + int i; + + switch(proto) { + case IPPROTO_UDP: + table = udp_port_table; + serv_proto = "udp"; + break; + case IPPROTO_TCP: + table = tcp_port_table; + serv_proto = "tcp"; + break; + default: + /* not yet implemented */ + return NULL; + /*NOTREACHED*/ + break; + } /* proto */ + + i = port & (HASHPORTSIZE - 1); + tp = table[ i & (HASHPORTSIZE - 1)]; + + if( tp == NULL ) { + tp = table[ i & (HASHPORTSIZE - 1)] = + (hashname_t *)g_malloc(sizeof(hashname_t)); + } else { + while(1) { + if( tp->addr == port ) { + return tp->name; + } + if (tp->next == NULL) { + tp->next = (hashname_t *)g_malloc(sizeof(hashname_t)); + tp = tp->next; + break; + } + tp = tp->next; + } + } + + /* fill in a new entry */ + tp->addr = port; + tp->next = NULL; + + if ((servp = getservbyport(htons(port), serv_proto)) == NULL) { + /* unknown port */ + sprintf(tp->name, "%d", port); + } else { + strncpy(tp->name, servp->s_name, MAXNAMELEN); + } + + return (tp->name); + +} /* serv_name_lookup */ + +#ifdef AVOID_DNS_TIMEOUT + +#define DNS_TIMEOUT 5 /* max sec per call */ + +jmp_buf hostname_env; + +static void abort_network_query(int sig) +{ + longjmp(hostname_env, 1); +} +#endif /* AVOID_DNS_TIMEOUT */ + +static u_char *host_name_lookup(u_int addr) +{ + + hashname_t *tp; + hashname_t **table = host_table; + struct hostent *hostp; + + tp = table[ addr & (HASHHOSTSIZE - 1)]; + + if( tp == NULL ) { + tp = table[ addr & (HASHHOSTSIZE - 1)] = + (hashname_t *)g_malloc(sizeof(hashname_t)); + } else { + while(1) { + if( tp->addr == addr ) { + return tp->name; + } + if (tp->next == NULL) { + tp->next = (hashname_t *)g_malloc(sizeof(hashname_t)); + tp = tp->next; + break; + } + tp = tp->next; + } + } + + /* fill in a new entry */ + tp->addr = addr; + tp->next = NULL; + +#ifdef AVOID_DNS_TIMEOUT + + /* Quick hack to avoid DNS/YP timeout */ + + if (!setjmp(hostname_env)) { + signal(SIGALRM, abort_network_query); + alarm(DNS_TIMEOUT); +#endif + hostp = gethostbyaddr((char *)&addr, 4, AF_INET); +#ifdef AVOID_DNS_TIMEOUT + alarm(0); +#endif + if (hostp != NULL) { + strncpy(tp->name, hostp->h_name, MAXNAMELEN); + return tp->name; + } +#ifdef AVOID_DNS_TIMEOUT + } +#endif + + /* unknown host or DNS timeout */ + + sprintf(tp->name, "%s", ip_to_str((guint8 *)&addr)); + return (tp->name); + +} /* host_name_lookup */ + +/* external functions */ + +extern u_char *get_hostname(u_int addr) +{ + if (!g_resolving_actif) + return ip_to_str((guint8 *)&addr); + + return host_name_lookup(addr); +} + +extern u_char *get_udp_port(u_int port) +{ + static gchar str[3][MAXNAMELEN]; + static gchar *cur; + + if (!g_resolving_actif) { + if (cur == &str[0][0]) { + cur = &str[1][0]; + } else if (cur == &str[1][0]) { + cur = &str[2][0]; + } else { + cur = &str[0][0]; + } + sprintf(cur, "%d", port); + return cur; + } + + return serv_name_lookup(port, IPPROTO_UDP); + +} /* get_udp_port */ + + +extern u_char *get_tcp_port(u_int port) +{ + static gchar str[3][MAXNAMELEN]; + static gchar *cur; + + if (!g_resolving_actif) { + if (cur == &str[0][0]) { + cur = &str[1][0]; + } else if (cur == &str[1][0]) { + cur = &str[2][0]; + } else { + cur = &str[0][0]; + } + sprintf(cur, "%d", port); + return cur; + } + + return serv_name_lookup(port, IPPROTO_TCP); + +} /* get_tcp_port */ + diff --git a/resolv.h b/resolv.h new file mode 100644 index 0000000000..d34f977e68 --- /dev/null +++ b/resolv.h @@ -0,0 +1,39 @@ +/* resolv.h + * Definitions for network object lookup + * + * Laurent Deniel + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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 __RESOLV_H__ +#define __RESOLV_H__ + +/* global variable */ + +extern int g_resolving_actif; + +/* Functions in resolv.c */ + +extern u_char *get_udp_port(u_int port); +extern u_char *get_tcp_port(u_int port); +extern u_char *get_hostname(u_int addr); + +#endif /* __RESOLV_H__ */ diff --git a/snprintf.c b/snprintf.c new file mode 100644 index 0000000000..f131ca4dfb --- /dev/null +++ b/snprintf.c @@ -0,0 +1,822 @@ + +/* + Unix snprintf implementation. + Version 1.2 + + 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. + It can be redistribute also under the terms of GNU Library General + Public Lincense. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + Revision History: + + 1.2: + * put the program under LGPL. + 1.1: + * added changes from Miles Bader + * corrected a bug with %f + * added support for %#g + * added more comments :-) + 1.0: + * supporting must ANSI syntaxic_sugars + 0.0: + * suppot %s %c %d + + THANKS(for the patches and ideas): + Miles Bader + Cyrille Rustom + Jacek Slabocewiz + Mike Parker(mouse) + +*/ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "snprintf.h" + +/* + * Find the nth power of 10 + */ +PRIVATE double +#ifdef __STDC__ +pow_10(int n) +#else +pow_10(n) +int n; +#endif +{ + int i; + double P; + + if (n < 0) + for (i = 1, P = 1., n = -n ; i <= n ; i++) {P *= .1;} + else + for (i = 1, P = 1. ; i <= n ; i++) {P *= 10.0;} + return P; +} + +/* + * Find the integral part of the log in base 10 + * Note: this not a real log10() + I just need and approximation(integerpart) of x in: + 10^x ~= r + * log_10(200) = 2; + * log_10(250) = 2; + */ +PRIVATE int +#ifdef __STDC__ +log_10(double r) +#else +log_10(r) +double r; +#endif +{ + int i = 0; + double result = 1.; + + if (r < 0.) + r = -r; + + if (r < 1.) { + while (result >= r) {result *= .1; i++;} + return (-i); + } else { + while (result <= r) {result *= 10.; i++;} + return (i - 1); + } +} + +/* + * This function return the fraction part of a double + * and set in ip the integral part. + * In many ways it resemble the modf() found on most Un*x + */ +PRIVATE double +#ifdef __STDC__ +integral(double real, double * ip) +#else +integral(real, ip) +double real; +double * ip; +#endif +{ + int j; + double i, s, p; + double real_integral = 0.; + +/* take care of the obvious */ +/* equal to zero ? */ + if (real == 0.) { + *ip = 0.; + return (0.); + } + +/* negative number ? */ + if (real < 0.) + real = -real; + +/* a fraction ? */ + if ( real < 1.) { + *ip = 0.; + return real; + } +/* the real work :-) */ + for (j = log_10(real); j >= 0; j--) { + p = pow_10(j); + s = (real - real_integral)/p; + i = 0.; + while (i + 1. <= s) {i++;} + real_integral += i*p; + } + *ip = real_integral; + return (real - real_integral); +} + +#define PRECISION 1.e-6 +/* + * return an ascii representation of the integral part of the number + * and set fract to be an ascii representation of the fraction part + * the container for the fraction and the integral part or staticly + * declare with fix size + */ +PRIVATE char * +#ifdef __STDC__ +numtoa(double number, int base, int precision, char ** fract) +#else +numtoa(number, base, precision, fract) +double number; +int base; +int precision; +char ** fract; +#endif +{ + register int i, j; + double ip, fp; /* integer and fraction part */ + double fraction; + int digits = MAX_INT - 1; + static char integral_part[MAX_INT]; + static char fraction_part[MAX_FRACT]; + double sign; + int ch; + +/* taking care of the obvious case: 0.0 */ + if (number == 0.) { + integral_part[0] = '0'; + integral_part[1] = '\0'; + fraction_part[0] = '0'; + fraction_part[1] = '\0'; + return integral_part; + } + +/* for negative numbers */ + if ((sign = number) < 0.) { + number = -number; + digits--; /* sign consume one digit */ + } + + fraction = integral(number, &ip); + number = ip; +/* do the integral part */ + if ( ip == 0.) { + integral_part[0] = '0'; + i = 1; + } else { + for ( i = 0; i < digits && number != 0.; ++i) { + number /= base; + fp = integral(number, &ip); + ch = (int)((fp + PRECISION)*base); /* force to round */ + integral_part[i] = (ch <= 9) ? ch + '0' : ch + 'a' - 10; + if (! isxdigit(integral_part[i])) /* bail out overflow !! */ + break; + number = ip; + } + } + +/* Oh No !! out of bound, ho well fill it up ! */ + if (number != 0.) + for (i = 0; i < digits; ++i) + integral_part[i] = '9'; + +/* put the sign ? */ + if (sign < 0.) + integral_part[i++] = '-'; + + integral_part[i] = '\0'; + +/* reverse every thing */ + for ( i--, j = 0; j < i; j++, i--) + SWAP_INT(integral_part[i], integral_part[j]); + +/* the fractionnal part */ + for (i=0, fp=fraction; precision > 0 && i < MAX_FRACT ; i++, precision-- ) { + fraction_part[i] = (int)((fp + PRECISION)*10. + '0'); + if (! isdigit(fraction_part[i])) /* underflow ? */ + break; + fp = (fp*10.0) - (double)(long)((fp + PRECISION)*10.); + } + fraction_part[i] = '\0'; + + if (fract != (char **)0) + *fract = fraction_part; + + return integral_part; + +} + +/* for %d and friends, it puts in holder + * the representation with the right padding + */ +PRIVATE void +#ifdef __STDC__ +decimal(struct DATA *p, double d) +#else +decimal(p, d) +struct DATA *p; +double d; +#endif +{ + char *tmp; + + tmp = itoa(d); + p->width -= strlen(tmp); + PAD_RIGHT(p); + PUT_PLUS(d, p); + PUT_SPACE(d, p); + while (*tmp) { /* the integral */ + PUT_CHAR(*tmp, p); + tmp++; + } + PAD_LEFT(p); +} + +/* for %o octal representation */ +PRIVATE void +#ifdef __STDC__ +octal(struct DATA *p, double d) +#else +octal(p, d) +struct DATA *p; +double d; +#endif +{ + char *tmp; + + tmp = otoa(d); + p->width -= strlen(tmp); + PAD_RIGHT(p); + if (p->square == FOUND) /* had prefix '0' for octal */ + PUT_CHAR('0', p); + while (*tmp) { /* octal */ + PUT_CHAR(*tmp, p); + tmp++; + } + PAD_LEFT(p); +} + +/* for %x %X hexadecimal representation */ +PRIVATE void +#ifdef __STDC__ +hexa(struct DATA *p, double d) +#else +hexa(p, d) +struct DATA *p; +double d; +#endif +{ + char *tmp; + + tmp = htoa(d); + p->width -= strlen(tmp); + PAD_RIGHT(p); + if (p->square == FOUND) { /* prefix '0x' for hexa */ + PUT_CHAR('0', p); PUT_CHAR(*p->pf, p); + } + while (*tmp) { /* hexa */ + PUT_CHAR((*p->pf == 'X' ? toupper(*tmp) : *tmp), p); + tmp++; + } + PAD_LEFT(p); +} + +/* %s strings */ +PRIVATE void +#ifdef __STDC__ +strings(struct DATA *p, char *tmp) +#else +strings(p, tmp) +struct DATA *p; +char *tmp; +#endif +{ + int i; + + i = strlen(tmp); + if (p->precision != NOT_FOUND) /* the smallest number */ + i = (i < p->precision ? i : p->precision); + p->width -= i; + PAD_RIGHT(p); + while (i-- > 0) { /* put the sting */ + PUT_CHAR(*tmp, p); + tmp++; + } + PAD_LEFT(p); +} + +/* %f or %g floating point representation */ +PRIVATE void +#ifdef __STDC__ +floating(struct DATA *p, double d) +#else +floating(p, d) +struct DATA *p; +double d; +#endif +{ + char *tmp, *tmp2; + int i; + + DEF_PREC(p); + d = ROUND(d, p); + tmp = dtoa(d, p->precision, &tmp2); + /* calculate the padding. 1 for the dot */ + p->width = p->width - + ((d > 0. && p->justify == RIGHT) ? 1:0) - + ((p->space == FOUND) ? 1:0) - + strlen(tmp) - p->precision - 1; + PAD_RIGHT(p); + PUT_PLUS(d, p); + PUT_SPACE(d, p); + while (*tmp) { /* the integral */ + PUT_CHAR(*tmp, p); + tmp++; + } + if (p->precision != 0 || p->square == FOUND) + PUT_CHAR('.', p); /* put the '.' */ + if (*p->pf == 'g' || *p->pf == 'G') /* smash the trailing zeros */ + for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--) + tmp2[i] = '\0'; + for (; *tmp2; tmp2++) + PUT_CHAR(*tmp2, p); /* the fraction */ + + PAD_LEFT(p); +} + +/* %e %E %g exponent representation */ +PRIVATE void +#ifdef __STDC__ +exponent(struct DATA *p, double d) +#else +exponent(p, d) +struct DATA *p; +double d; +#endif +{ + char *tmp, *tmp2; + int j, i; + + DEF_PREC(p); + j = log_10(d); + d = d / pow_10(j); /* get the Mantissa */ + d = ROUND(d, p); + tmp = dtoa(d, p->precision, &tmp2); + /* 1 for unit, 1 for the '.', 1 for 'e|E', + * 1 for '+|-', 3 for 'exp' */ + /* calculate how much padding need */ + p->width = p->width - + ((d > 0. && p->justify == RIGHT) ? 1:0) - + ((p->space == FOUND) ? 1:0) - p->precision - 7; + PAD_RIGHT(p); + PUT_PLUS(d, p); + PUT_SPACE(d, p); + while (*tmp) {/* the integral */ + PUT_CHAR(*tmp, p); + tmp++; + } + if (p->precision != 0 || p->square == FOUND) + PUT_CHAR('.', p); /* the '.' */ + if (*p->pf == 'g' || *p->pf == 'G') /* smash the trailing zeros */ + for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--) + tmp2[i] = '\0'; + for (; *tmp2; tmp2++) + PUT_CHAR(*tmp2, p); /* the fraction */ + + if (*p->pf == 'g' || *p->pf == 'e') { /* the exponent put the 'e|E' */ + PUT_CHAR('e', p); + } else + PUT_CHAR('E', p); + if (j > 0) { /* the sign of the exp */ + PUT_CHAR('+', p); + } else { + PUT_CHAR('-', p); + j = -j; + } + tmp = itoa((double)j); + if (j < 9) { /* need to pad the exponent with 0 '000' */ + PUT_CHAR('0', p); PUT_CHAR('0', p); + } else if (j < 99) + PUT_CHAR('0', p); + while (*tmp) { /* the exponent */ + PUT_CHAR(*tmp, p); + tmp++; + } + PAD_LEFT(p); +} + +/* initialize the conversion specifiers */ +PRIVATE void +#ifdef __STDC__ +conv_flag(char * s, struct DATA * p) +#else +conv_flag(s, p) +char * s; +struct DATA * p; +#endif +{ + char number[MAX_FIELD/2]; + int i; + + p->precision = p->width = NOT_FOUND; + p->star_w = p->star_p = NOT_FOUND; + p->square = p->space = NOT_FOUND; + p->a_long = p->justify = NOT_FOUND; + p->pad = ' '; + + for(;s && *s ;s++) { + switch(*s) { + case ' ': p->space = FOUND; break; + case '#': p->square = FOUND; break; + case '*': if (p->width == NOT_FOUND) + p->width = p->star_w = FOUND; + else + p->precision = p->star_p = FOUND; + break; + case '+': p->justify = RIGHT; break; + case '-': p->justify = LEFT; break; + case '.': if (p->width == NOT_FOUND) + p->width = 0; + break; + case '0': p->pad = '0'; break; + case '1': case '2': case '3': + case '4': case '5': case '6': + case '7': case '8': case '9': /* gob all the digits */ + for (i = 0; isdigit(*s); i++, s++) + if (i < MAX_FIELD/2 - 1) + number[i] = *s; + number[i] = '\0'; + if (p->width == NOT_FOUND) + p->width = atoi(number); + else + p->precision = atoi(number); + s--; /* went to far go back */ + break; + } + } +} + +PUBLIC int +#ifdef __STDC__ +vsnprintf(char *string, size_t length, const char * format, va_list args) +#else +vsnprintf(string, length, format, args) +char *string; +size_t length; +char * format; +va_list args; +#endif +{ + struct DATA data; + char conv_field[MAX_FIELD]; + double d; /* temporary holder */ + int state; + int i; + + data.length = length - 1; /* leave room for '\0' */ + data.holder = string; + data.pf = format; + data.counter = 0; + + +/* sanity check, the string must be > 1 */ + if (length < 1) + return -1; + + + for (; *data.pf && (data.counter < data.length); data.pf++) { + if ( *data.pf == '%' ) { /* we got a magic % cookie */ + conv_flag((char *)0, &data); /* initialise format flags */ + for (state = 1; *data.pf && state;) { + switch (*(++data.pf)) { + case '\0': /* a NULL here ? ? bail out */ + *data.holder = '\0'; + return data.counter; + break; + case 'f': /* float, double */ + STAR_ARGS(&data); + d = va_arg(args, double); + floating(&data, d); + state = 0; + break; + case 'g': + case 'G': + STAR_ARGS(&data); + DEF_PREC(&data); + d = va_arg(args, double); + i = log_10(d); + /* + * for '%g|%G' ANSI: use f if exponent + * is in the range or [-4,p] exclusively + * else use %e|%E + */ + if (-4 < i && i < data.precision) + floating(&data, d); + else + exponent(&data, d); + state = 0; + break; + case 'e': + case 'E': /* Exponent double */ + STAR_ARGS(&data); + d = va_arg(args, double); + exponent(&data, d); + state = 0; + break; + case 'u': + case 'd': /* decimal */ + STAR_ARGS(&data); + if (data.a_long == FOUND) + d = va_arg(args, long); + else + d = va_arg(args, int); + decimal(&data, d); + state = 0; + break; + case 'o': /* octal */ + STAR_ARGS(&data); + if (data.a_long == FOUND) + d = va_arg(args, long); + else + d = va_arg(args, int); + octal(&data, d); + state = 0; + break; + case 'x': + case 'X': /* hexadecimal */ + STAR_ARGS(&data); + if (data.a_long == FOUND) + d = va_arg(args, long); + else + d = va_arg(args, int); + hexa(&data, d); + state = 0; + break; + case 'c': /* character */ + d = va_arg(args, int); + PUT_CHAR(d, &data); + state = 0; + break; + case 's': /* string */ + STAR_ARGS(&data); + strings(&data, va_arg(args, char *)); + state = 0; + break; + case 'n': + *(va_arg(args, int *)) = data.counter; /* what's the count ? */ + state = 0; + break; + case 'l': + data.a_long = FOUND; + break; + case 'h': + break; + case '%': /* nothing just % */ + PUT_CHAR('%', &data); + state = 0; + break; + case '#': case ' ': case '+': case '*': + case '-': case '.': case '0': case '1': + case '2': case '3': case '4': case '5': + case '6': case '7': case '8': case '9': + /* initialize width and precision */ + for (i = 0; isflag(*data.pf); i++, data.pf++) + if (i < MAX_FIELD - 1) + conv_field[i] = *data.pf; + conv_field[i] = '\0'; + conv_flag(conv_field, &data); + data.pf--; /* went to far go back */ + break; + default: + /* is this an error ? maybe bail out */ + state = 0; + break; + } /* end switch */ + } /* end of for state */ + } else { /* not % */ + PUT_CHAR(*data.pf, &data); /* add the char the string */ + } + } + + *data.holder = '\0'; /* the end ye ! */ + + return data.counter; +} + +#ifndef HAVE_SNPRINTF + +PUBLIC int +#if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__ +snprintf(char *string, size_t length, const char * format, ...) +#else +snprintf(string, length, format, va_alist) +char *string; +size_t length; +char * format; +va_dcl +#endif +{ + int rval; + va_list args; + +#if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__ + va_start(args, format); +#else + va_start(args); +#endif + + rval = vsnprintf (string, length, format, args); + + va_end(args); + + return rval; +} + +#endif /* HAVE_SNPRINTF */ + + +#ifdef DRIVER + +#include + +/* set of small tests for snprintf() */ +void main() +{ + char holder[100]; + int i; + +/* + printf("Suite of test for snprintf:\n"); + printf("a_format\n"); + printf("printf() format\n"); + printf("snprintf() format\n\n"); +*/ +/* Checking the field widths */ + + printf("/%%d/, 336\n"); + snprintf(holder, sizeof holder, "/%d/\n", 336); + printf("/%d/\n", 336); + printf("%s\n", holder); + + printf("/%%2d/, 336\n"); + snprintf(holder, sizeof holder, "/%2d/\n", 336); + printf("/%2d/\n", 336); + printf("%s\n", holder); + + printf("/%%10d/, 336\n"); + snprintf(holder, sizeof holder, "/%10d/\n", 336); + printf("/%10d/\n", 336); + printf("%s\n", holder); + + printf("/%%-10d/, 336\n"); + snprintf(holder, sizeof holder, "/%-10d/\n", 336); + printf("/%-10d/\n", 336); + printf("%s\n", holder); + + +/* floating points */ + + printf("/%%f/, 1234.56\n"); + snprintf(holder, sizeof holder, "/%f/\n", 1234.56); + printf("/%f/\n", 1234.56); + printf("%s\n", holder); + + printf("/%%e/, 1234.56\n"); + snprintf(holder, sizeof holder, "/%e/\n", 1234.56); + printf("/%e/\n", 1234.56); + printf("%s\n", holder); + + printf("/%%4.2f/, 1234.56\n"); + snprintf(holder, sizeof holder, "/%4.2f/\n", 1234.56); + printf("/%4.2f/\n", 1234.56); + printf("%s\n", holder); + + printf("/%%3.1f/, 1234.56\n"); + snprintf(holder, sizeof holder, "/%3.1f/\n", 1234.56); + printf("/%3.1f/\n", 1234.56); + printf("%s\n", holder); + + printf("/%%10.3f/, 1234.56\n"); + snprintf(holder, sizeof holder, "/%10.3f/\n", 1234.56); + printf("/%10.3f/\n", 1234.56); + printf("%s\n", holder); + + printf("/%%10.3e/, 1234.56\n"); + snprintf(holder, sizeof holder, "/%10.3e/\n", 1234.56); + printf("/%10.3e/\n", 1234.56); + printf("%s\n", holder); + + printf("/%%+4.2f/, 1234.56\n"); + snprintf(holder, sizeof holder, "/%+4.2f/\n", 1234.56); + printf("/%+4.2f/\n", 1234.56); + printf("%s\n", holder); + + printf("/%%010.2f/, 1234.56\n"); + snprintf(holder, sizeof holder, "/%010.2f/\n", 1234.56); + printf("/%010.2f/\n", 1234.56); + printf("%s\n", holder); + +#define BLURB "Outstanding acting !" +/* strings precisions */ + + printf("/%%2s/, \"%s\"\n", BLURB); + snprintf(holder, sizeof holder, "/%2s/\n", BLURB); + printf("/%2s/\n", BLURB); + printf("%s\n", holder); + + printf("/%%22s/ %s\n", BLURB); + snprintf(holder, sizeof holder, "/%22s/\n", BLURB); + printf("/%22s/\n", BLURB); + printf("%s\n", holder); + + printf("/%%22.5s/ %s\n", BLURB); + snprintf(holder, sizeof holder, "/%22.5s/\n", BLURB); + printf("/%22.5s/\n", BLURB); + printf("%s\n", holder); + + printf("/%%-22.5s/ %s\n", BLURB); + snprintf(holder, sizeof holder, "/%-22.5s/\n", BLURB); + printf("/%-22.5s/\n", BLURB); + printf("%s\n", holder); + +/* see some flags */ + + printf("%%x %%X %%#x, 31, 31, 31\n"); + snprintf(holder, sizeof holder, "%x %X %#x\n", 31, 31, 31); + printf("%x %X %#x\n", 31, 31, 31); + printf("%s\n", holder); + + printf("**%%d**%% d**%% d**, 42, 42, -42\n"); + snprintf(holder, sizeof holder, "**%d**% d**% d**\n", 42, 42, -42); + printf("**%d**% d**% d**\n", 42, 42, -42); + printf("%s\n", holder); + +/* other flags */ + + printf("/%%g/, 31.4\n"); + snprintf(holder, sizeof holder, "/%g/\n", 31.4); + printf("/%g/\n", 31.4); + printf("%s\n", holder); + + printf("/%%.6g/, 31.4\n"); + snprintf(holder, sizeof holder, "/%.6g/\n", 31.4); + printf("/%.6g/\n", 31.4); + printf("%s\n", holder); + + printf("/%%.1G/, 31.4\n"); + snprintf(holder, sizeof holder, "/%.1G/\n", 31.4); + printf("/%.1G/\n", 31.4); + printf("%s\n", holder); + + printf("abc%%n\n"); + printf("abc%n", &i); printf("%d\n", i); + snprintf(holder, sizeof holder, "abc%n", &i); + printf("%s", holder); printf("%d\n\n", i); + + printf("%%*.*s --> 10.10\n"); + snprintf(holder, sizeof holder, "%*.*s\n", 10, 10, BLURB); + printf("%*.*s\n", 10, 10, BLURB); + printf("%s\n", holder); + + printf("%%%%%%%%\n"); + snprintf(holder, sizeof holder, "%%%%\n"); + printf("%%%%\n"); + printf("%s\n", holder); + +#define BIG "Hello this is a too big string for the buffer" +/* printf("A buffer to small of 10, trying to put this:\n");*/ + printf("<%%>, %s\n", BIG); + i = snprintf(holder, 10, "%s\n", BIG); + printf("<%s>\n", BIG); + printf("<%s>\n", holder); +} +#endif diff --git a/snprintf.h b/snprintf.h new file mode 100644 index 0000000000..245739541e --- /dev/null +++ b/snprintf.h @@ -0,0 +1,232 @@ +/* + Unix snprintf implementation. + Version 1.2 + + 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. + It can be redistribute also under the terms of GNU Library General + Public Lincense. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + Revision History: + + 1.2: + * put under LGPL. + 1.1: + * added changes from Miles Bader + * corrected a bug with %f + * added support for %#g + * added more comments :-) + 1.0: + * supporting must ANSI syntaxic_sugars(see below) + 0.0: + * suppot %s %c %d + + it understands: + Integer: + %lu %lu %u + %hd %ld %d decimal + %ho %lo %o octal + %hx %lx %x %X hexa + Floating points: + %g %G %e %E %f double + Strings: + %s %c string + %% % + + Formating conversion flags: + - justify left + + Justify right or put a plus if number + # prefix 0x, 0X for hexa and 0 for octal + * precision/witdth is specify as an (int) in the arguments + ' ' leave a blank for number with no sign + l the later should be a long + h the later should be a short + +format: + snprintf(holder, sizeof_holder, format, ...) + +Return values: + (sizeof_holder - 1) + + + THANKS(for the patches and ideas): + Miles Bader + Cyrille Rustom + Jacek Slabocewiz + Mike Parker(mouse) + +Alain Magloire: alainm@rcsm.ee.mcgill.ca +*/ + +#if defined(HAVE_STDARG_H) && defined(__STDC__) && __STDC__ +#include +#else +#include +#endif + +#include /* for atoi() */ +#include + + +/* + * For the FLOATING POINT FORMAT : + * the challenge was finding a way to + * manipulate the Real numbers without having + * to resort to mathematical function(it + * would require to link with -lm) and not + * going down to the bit pattern(not portable) + * + * so a number, a real is: + + real = integral + fraction + + integral = ... + a(2)*10^2 + a(1)*10^1 + a(0)*10^0 + fraction = b(1)*10^-1 + b(2)*10^-2 + ... + + where: + 0 <= a(i) => 9 + 0 <= b(i) => 9 + + from then it was simple math + */ + +/* + * size of the buffer for the integral part + * and the fraction part + */ +#define MAX_INT 99 + 1 /* 1 for the null */ +#define MAX_FRACT 29 + 1 + +/* + * numtoa() uses PRIVATE buffers to store the results, + * So this function is not reentrant + */ +#define itoa(n) numtoa(n, 10, 0, (char **)0) +#define otoa(n) numtoa(n, 8, 0, (char **)0) +#define htoa(n) numtoa(n, 16, 0, (char **)0) +#define dtoa(n, p, f) numtoa(n, 10, p, f) + +#define SWAP_INT(a,b) {int t; t = (a); (a) = (b); (b) = t;} + +/* this struct holds everything we need */ +struct DATA { + int length; + char *holder; + int counter; +#ifdef __STDC__ + const char *pf; +#else + char *pf; +#endif +/* FLAGS */ + int width, precision; + int justify; char pad; + int square, space, star_w, star_p, a_long ; +}; + +#define PRIVATE static +#define PUBLIC +/* signature of the functions */ +#ifdef __STDC__ +/* the floating point stuff */ + PRIVATE double pow_10(int); + PRIVATE int log_10(double); + PRIVATE double integral(double, double *); + PRIVATE char * numtoa(double, int, int, char **); + +/* for the format */ + PRIVATE void conv_flag(char *, struct DATA *); + PRIVATE void floating(struct DATA *, double); + PRIVATE void exponent(struct DATA *, double); + PRIVATE void decimal(struct DATA *, double); + PRIVATE void octal(struct DATA *, double); + PRIVATE void hexa(struct DATA *, double); + PRIVATE void strings(struct DATA *, char *); + +#else +/* the floating point stuff */ + PRIVATE double pow_10(); + PRIVATE int log_10(); + PRIVATE double integral(); + PRIVATE char * numtoa(); + +/* for the format */ + PRIVATE void conv_flag(); + PRIVATE void floating(); + PRIVATE void exponent(); + PRIVATE void decimal(); + PRIVATE void octal(); + PRIVATE void hexa(); + PRIVATE void strings(); +#endif + +/* those are defines specific to snprintf to hopefully + * make the code clearer :-) + */ +#define RIGHT 1 +#define LEFT 0 +#define NOT_FOUND -1 +#define FOUND 1 +#define MAX_FIELD 15 + +/* the conversion flags */ +#define isflag(c) ((c) == '#' || (c) == ' ' || \ + (c) == '*' || (c) == '+' || \ + (c) == '-' || (c) == '.' || \ + isdigit(c)) + +/* round off to the precision */ +#define ROUND(d, p) \ + (d < 0.) ? \ + d - pow_10(-(p)->precision) * 0.5 : \ + d + pow_10(-(p)->precision) * 0.5 + +/* set default precision */ +#define DEF_PREC(p) \ + if ((p)->precision == NOT_FOUND) \ + (p)->precision = 6 + +/* put a char */ +#define PUT_CHAR(c, p) \ + if ((p)->counter < (p)->length) { \ + *(p)->holder++ = (c); \ + (p)->counter++; \ + } + +#define PUT_PLUS(d, p) \ + if ((d) > 0. && (p)->justify == RIGHT) \ + PUT_CHAR('+', p) + +#define PUT_SPACE(d, p) \ + if ((p)->space == FOUND && (d) > 0.) \ + PUT_CHAR(' ', p) + +/* pad right */ +#define PAD_RIGHT(p) \ + if ((p)->width > 0 && (p)->justify != LEFT) \ + for (; (p)->width > 0; (p)->width--) \ + PUT_CHAR((p)->pad, p) + +/* pad left */ +#define PAD_LEFT(p) \ + if ((p)->width > 0 && (p)->justify == LEFT) \ + for (; (p)->width > 0; (p)->width--) \ + PUT_CHAR((p)->pad, p) + +/* if width and prec. in the args */ +#define STAR_ARGS(p) \ + if ((p)->star_w == FOUND) \ + (p)->width = va_arg(args, int); \ + if ((p)->star_p == FOUND) \ + (p)->precision = va_arg(args, int) diff --git a/stamp-h.in b/stamp-h.in new file mode 100644 index 0000000000..9788f70238 --- /dev/null +++ b/stamp-h.in @@ -0,0 +1 @@ +timestamp diff --git a/util.c b/util.c new file mode 100644 index 0000000000..50d38a9726 --- /dev/null +++ b/util.c @@ -0,0 +1,125 @@ +/* util.c + * Utility routines + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include + +#include + +#include "util.h" + +const gchar *bm_key = "button mask"; + +/* Simple dialog function - Displays a dialog box with the supplied message + * text. + * + * Args: + * type : One of ESD_TYPE_*. Currently ignored. + * btn_mask : The address of a gint. The value passed in determines if + * the 'Cancel' button is displayed. The button pressed by the + * user is passed back. + * message : The text displayed in the dialog. + * + * To do: + * - Switch to variable args + */ +void +simple_dialog(gint type, gint *btn_mask, gchar *message) { + GtkWidget *win, *main_vb, *top_hb, *type_pm, *msg_label, + *bbox, *ok_btn, *cancel_btn; + GdkPixmap *pixmap; + GdkBitmap *mask; + GtkStyle *style; + GdkColormap *cmap; + + /* Main window */ + win = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_container_border_width(GTK_CONTAINER(win), 7); + gtk_window_set_title(GTK_WINDOW(win), "Ethereal: Warning"); + gtk_object_set_data(GTK_OBJECT(win), bm_key, btn_mask); + + /* Container for our rows */ + main_vb = gtk_vbox_new(FALSE, 5); + gtk_container_border_width(GTK_CONTAINER(main_vb), 5); + gtk_container_add(GTK_CONTAINER(win), main_vb); + gtk_widget_show(main_vb); + + /* Top row: Icon and message text */ + top_hb = gtk_hbox_new(FALSE, 5); + gtk_container_add(GTK_CONTAINER(main_vb), top_hb); + gtk_widget_show(top_hb); + + style = gtk_widget_get_style(win); + cmap = gdk_colormap_get_system(); + pixmap = gdk_pixmap_colormap_create_from_xpm_d(NULL, cmap, &mask, + &style->bg[GTK_STATE_NORMAL], icon_excl_xpm); + type_pm = gtk_pixmap_new(pixmap, mask); + gtk_container_add(GTK_CONTAINER(top_hb), type_pm); + gtk_widget_show(type_pm); + + msg_label = gtk_label_new(message); + gtk_label_set_justify(GTK_LABEL(msg_label), GTK_JUSTIFY_FILL); + gtk_container_add(GTK_CONTAINER(top_hb), msg_label); + gtk_widget_show(msg_label); + + /* Button row */ + bbox = gtk_hbutton_box_new(); + gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END); + gtk_container_add(GTK_CONTAINER(main_vb), bbox); + gtk_widget_show(bbox); + + ok_btn = gtk_button_new_with_label ("OK"); + gtk_signal_connect_object(GTK_OBJECT(ok_btn), "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT (win)); + gtk_container_add(GTK_CONTAINER(bbox), ok_btn); + GTK_WIDGET_SET_FLAGS(ok_btn, GTK_CAN_DEFAULT); + gtk_widget_grab_default(ok_btn); + gtk_widget_show(ok_btn); + + if (btn_mask && *btn_mask == ESD_BTN_CANCEL) { + cancel_btn = gtk_button_new_with_label("Cancel"); + gtk_signal_connect(GTK_OBJECT(cancel_btn), "clicked", + GTK_SIGNAL_FUNC(simple_dialog_cancel_cb), (gpointer) win); + gtk_container_add(GTK_CONTAINER(bbox), cancel_btn); + gtk_widget_show(cancel_btn); + } + + if (btn_mask) + *btn_mask = ESD_BTN_OK; + + gtk_widget_show(win); +} + +void +simple_dialog_cancel_cb(GtkWidget *w, gpointer win) { + gint *btn_mask = (gint *) gtk_object_get_data(win, bm_key); + + if (btn_mask) + *btn_mask = ESD_BTN_CANCEL; + gtk_widget_destroy(GTK_WIDGET(win)); +} diff --git a/util.h b/util.h new file mode 100644 index 0000000000..40425c7af3 --- /dev/null +++ b/util.h @@ -0,0 +1,49 @@ +/* util.h + * Utility definitions + * + * Ethereal - Network traffic analyzer + * By Gerald Combs + * 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 __UTIL_H__ +#define __UTIL_H__ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "image/icon-excl.xpm" + +/* Dialog type. Currently, only ESD_TYPE_WARN is supported. */ +#define ESD_TYPE_INFO 0 +#define ESD_TYPE_WARN 1 +#define ESD_TYPE_CRIT 2 + +/* Which buttons to display. */ +#define ESD_BTN_OK 0 +#define ESD_BTN_CANCEL 1 + +void simple_dialog(gint, gint *, gchar *); +void simple_dialog_cancel_cb(GtkWidget *, gpointer); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __UTIL_H__ */