pax_global_header00006660000000000000000000000064140136046170014514gustar00rootroot0000000000000052 comment=c98938b320f5aba5e40312e1ad6db9fe55733909 tcpflow-tcpflow-1.6.1/000077500000000000000000000000001401360461700146535ustar00rootroot00000000000000tcpflow-tcpflow-1.6.1/.github/000077500000000000000000000000001401360461700162135ustar00rootroot00000000000000tcpflow-tcpflow-1.6.1/.github/workflows/000077500000000000000000000000001401360461700202505ustar00rootroot00000000000000tcpflow-tcpflow-1.6.1/.github/workflows/continuous-integration.yml000066400000000000000000000022031401360461700255170ustar00rootroot00000000000000# This file based on https://gist.github.com/mwouts/9842452d020c08faf9e84a3bba38a66f # See: https://help.github.com/en/actions/reference/software-installed-on-github-hosted-runners # 2020-06-22 - slg - customized # 2020-06-27 - slg - expanded to G++ for MacOS # 2020-07-03 - slg - ported to be13_api; removed python (be13_api doesn't use python) name: BE13_API CI (c++14) on: [push] jobs: build: runs-on: ${{ matrix.os }} strategy: matrix: os: ['ubuntu-20.04'] steps: # https://github.com/actions/checkout - name: Checkout uses: actions/checkout@v2 with: submodules: recursive - name: Install C++ dependencies on MacOS if: startsWith(matrix.os, 'macOS') run: | bash etc/install_autotools.sh - name: Install C++ dependencies on Ubuntu if: startsWith(matrix.os, 'ubuntu') run: | sudo apt install libtool autoconf automake g++ libboost-all-dev libssl-dev libpcap-dev libcairo2-dev automake --help - name: c/c++ test run: | bash bootstrap.sh ./configure && make && make check tcpflow-tcpflow-1.6.1/.gitignore000066400000000000000000000023711401360461700166460ustar00rootroot00000000000000 # Backup Files and autoconf nonsense # Compiled source # # Executables # Logs and databases # # OS generated files # # Packages # # git has its own built in compression methods # http://help.github.com/ignore-files/ # http://stackoverflow.com/questions/3290908/which-files-generated-by-autotools-should-i-keep-in-git-repository # it's better to unpack these files and commit the raw source # plus vim backups ############ ################### ###################### *.7z *.a *.aff *.class *.com *.dll *.dmg *.exe *.gz *.iso *.jar *.log *.o *.obj *.pyc *.rar *.sig *.so *.sql *.sqlite *.swp *.tar *.trs *.zip *~ .DS_Store .DS_Store* .deps .dirstamp .libs Icon? Makefile Makefile.in TAGS Thumbs.db a.out.dSYM aclocal.m4 affconfig.h affconfig.h.in afflib-*.tar.gz afflib.lib afflib.pc afflib.spec autom4te.cache config.guess config.h config.h.in config.log config.status config.sub configure depcomp doc/tcpflow.1 ehthumbs.db install-sh libtool ltmain.sh m4/libtool.m4 m4/ltoptions.m4 m4/ltsugar.m4 m4/ltversion.m4 m4/lt~obsolete.m4 missing out out-* report.xml src/a.out src/config.h src/iphtest-nitroba-100.txt src/iphtest-nitroba-1000.txt src/iphtest-nitroba-10000.txt src/tcpflow stamp-h* tags tcpflow.spec test-driver tests/*.pdf tests/out tests/packet1.pcap *.d ar-lib tcpflow-tcpflow-1.6.1/.gitmodules000066400000000000000000000001501401360461700170240ustar00rootroot00000000000000[submodule "src/http-parser"] path = src/http-parser url = https://github.com/simsong/http-parser.git tcpflow-tcpflow-1.6.1/.travis.yml000066400000000000000000000004631401360461700167670ustar00rootroot00000000000000addons: apt: packages: - automake - autoconf - g++ - libboost-dev - libssl-dev - libpcap-dev - libcairo2-dev language: cpp arch: - amd64 - ppc64le dist: bionic compiler: clang install: - ./bootstrap.sh && ./configure && make script: - make check tcpflow-tcpflow-1.6.1/AUTHORS000066400000000000000000000012651401360461700157270ustar00rootroot00000000000000MAINTAINER ========== Simson L. Garfinkel COPYRIGHT ========= Version 1.5.0 (C) Simson L. Garfinkel, Licensed under GPL 3.0 ACKNOWLEDGEMENTS ================ Thanks to: * Jeffrey Pang, for the radiotap implementation * Doug Madory, for the original Wifi parser * Jeremy Elson, for the original idea and initial tcp/ip implementation Additional and thanks: * Johnny Tevessen , for Linux systems still using libc5. * Ross Golder , for a spec file for generating tcpflow RPMs. * Jose M. Alcaide , patch for the -r option * olibre , for encouragmenet, lots of patches, and CMake implementation tcpflow-tcpflow-1.6.1/CMakeLists.txt000066400000000000000000000014461401360461700174200ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.1) project(tcpflow VERSION 1.4.6 LANGUAGES CXX C) # Within the above line, "C" is required for two reasons: # 1. find_package(Threads) fails using only CXX on cmake-3.3 and previous # 2. CMake files use CMAKE_C_COMPILER_ID instead of CMAKE_CXX_COMPILER_ID # The following line if for find_package(pcap) -> cmake/FindPCAP.cmake set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake) include(cmake/options.cmake) # Set default CMake options include(cmake/coverage.cmake) # Configure the build "Coverage" include(cmake/compilation-flags.cmake) # Compiler & Linker flags include(cmake/warning-flags.cmake) # Compiler & Linker warnings # Source code add_subdirectory(src) # Generate documentation #add_subdirectory( doc EXCLUDE_FROM_ALL ) tcpflow-tcpflow-1.6.1/CONFIGURE_ARCH_17_8.sh000077500000000000000000000001451401360461700200660ustar00rootroot00000000000000sudo pacman --sync --noconfirm emacs sudo pacman --sync --noconfirm zlib openssl boost cairo libpcap tcpflow-tcpflow-1.6.1/CONFIGURE_AWS_LINUX.sh000077500000000000000000000003561401360461700202300ustar00rootroot00000000000000PACKAGES="emacs automake zlib zlib-static openssl-devel boost-devel cairo-devel libpcap-devel libpcap-devel cairo-devel gcc-c++ python-devel" sudo yum install -y install $PACKAGES sh bootstrap.sh ./configure --disable-dependency-tracking tcpflow-tcpflow-1.6.1/CONFIGURE_CENTOS8.bash000066400000000000000000000051771401360461700202100ustar00rootroot00000000000000#!/bin/bash LIBEWF_URL=https://github.com/libyal/libewf/releases/download/20171104/libewf-experimental-20171104.tar.gz cat < /tmp/local.conf sudo mv /tmp/local.conf /etc/ld.so.conf.d/local.conf sudo ldconfig # # # echo ... echo 'Now running ../bootstrap.sh and configure' pushd .. sh bootstrap.sh sh configure popd echo ================================================================ echo ================================================================ echo 'You are now ready to compile bulk_extractor for Linux.' echo 'To compile, type make' echo 'To make a distribution, type make release'tcpflow-tcpflow-1.6.1/CONFIGURE_FEDORA_18.sh000077500000000000000000000071101401360461700200620ustar00rootroot00000000000000#!/bin/sh cat < Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them 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 prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If 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 convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state 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 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 3 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, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . tcpflow-tcpflow-1.6.1/ChangeLog000066400000000000000000000626021401360461700164330ustar00rootroot000000000000002018-11-18 Simson Garfinkel * updated for pcap_findalldevs * added -Wno-address-of-packed-member to avoid error 2017-07-12 Simson Garfinkel * updated to work with Fedora 26 compilers * Found bug in sbuf.cpp * Fixed C++ warnings in hash * Now works with OpenSSL 1.1.0f-fips 25 May 2017 2014-02-24 Man Page * src/tcpflow.cpp (main): alternating color output option changed from -J to -g 2013-12-06 Basic * configure.ac: upped version number to 1.4.3 * tests/test-multifile.sh (OUT): now handles multifile and nitroba packets not being present. 2013-11-28 Basic * src/scan_http.cpp (scan_http): BUGFIX: was not clearing byte_run DFXML between each attachment. Now does. 2013-11-18 Basic * src/wifipcap/wifipcap.cpp (WifipcapCallbacks::decode_data_frame): now calls Handle80211Data() for all data packets * configure.ac: changes to test per Ryan Schmidt 2013-11-17 Basic * configure.ac: updated to 1.4.2 * src/be13_api/be13_configure.m4: fixed so that it still compiles on MacOS 10.8. 2013-11-15 Basic * src/datalink.cpp (dl_null): removed DLT_NULL_BROKEN; it's not needed anymore. 2013-10-21 Man Page * src/flow.cpp (flow::filename): Since some people don't understand what %c and %C do, they don't provide it. It is required, so now a %c is appended if it is not specified. 2013-06-11 Basic * doc/tcpflow.1.in (std): removed explaination of filtering expressions 2013-05-26 Basic * src/tcpip.cpp (tcpip::print_packet): implemented hex dump * src/scan_netviz.cpp (scan_netviz): disabled by default for now. * src/tcpip.cpp (tcpip::print_packet): now prints 'filename' with console output (wasn't working due to bug). 2013-04-17 Simson Garfinkel * src/iptree.h (template): changed inc() to add() 2013-04-16 Simson Garfinkel * src/iptree.h: changed 'trim' to 'prune' for correct terminology. 2013-03-30 Simson Garfinkel * src/scan_tcpdemux.cpp (scan_tcpdemux): added -S tcp_timeout 2013-03-03 Simson Garfinkel * src/scan_netviz.cpp (scan_netviz): scan_netviz enabled by default 2013-02-27 Simson Garfinkel * configure.ac: added /usr/boost/include to search path 2013-01-27 Simson Garfinkel * src/tcpdemux.cpp (close_all_fd): now calls close_file(false), to preven openflows from being modified while it is being iterated. * src/tcpflow.h: removed SET_BIT as it wasn't being used * configure.ac: removed bcopy & bzero 2013-01-26 Simson Garfinkel 2013-01-08 Simson Garfinkel * src/scan_netviz.cpp (th_shutdown): th_one_page is now lazily created and destroyed at end 2013-01-03 Simson Garfinkel * src/tcpflow.cpp (main): opt_gzip_decompress renamed to gzip_decompress and implemented. * src/flow.cpp (flow::new_filename): now automatically makes subdirectories if necessary 2013-01-02 Simson Garfinkel * src/scan_http.cpp: zero-length attachments are no longer created on disk. * src/tcpip.cpp (tcpip::store_packet): zero-length flows are no longer created on disk. 2012-12-27 Simson Garfinkel * renamed stored_flow as saved_flow becuase they are all stored, but only some are saved in the ring bufer. * src/tcpdemux.cpp (tcpdemux::close_all): renamed close_all_fd(). close_tcpip renamed close_tcpip_fd; close_oldest renamed close_oldest_fd() (tcpdemux::remove_all_flows): renamed. 2012-12-24 Simson Garfinkel * src/tcpip.h (class flow): removed connection_count from flow identifier becuase it cannot be derrived from the flow. We really should have the LSN as part of the flow or something. The connection_count will be found when the filename is made. 2012-12-23 Simson Garfinkel * src/tcpdemux.cpp (tcpdemux::process_tcp): option output_enabled changed to store_output 2012-12-22 Simson Garfinkel * src/be13_api/sbuf.cpp (sbuf_t::map_file): * src/scan_http.cpp (scan_http_cbo::on_headers_complete): changed retrying_open to open() to eliminate dependency on tcpdemux * src/tcpip.h: put in its own file * src/util.cpp (mmap): moved fake mmap() cover to util.cpp * src/tcpip.cpp (tcpip): no longer closes the file at the end of every tcpip and then re-opens it if there is post-processing. Now it re-uses the same fd. (tcpip): renamed opt_after_header to opt_post_processing 2012-12-18 Simson Garfinkel * src/tcpflow.cpp (main): fixed opt_all; it was always true, but it shoudln't be. 2012-12-16 Simson Garfinkel * src/tcpdemux.h (class tcpdemux): removed write_to_file (class tcpdemux): removed struct packet_info_t * src/tcpdemux.cpp (tcpdemux::post_process_capture_flow): added delete of sbuf * src/scan_http.cpp (scan_http_cbo::on_headers_complete): changed O_APPEND to O_TRUNC * src/tcpdemux.cpp: removed process_gzip, since it is now done in scan_http 2012-12-07 Simson Garfinkel * src/tcpdemux.h (class flow_addr): fixed operator< type 2012-11-17 Simson Garfinkel * src/tcpflow.cpp (usage): usage now goes to stdout and not stderr. 2012-11-15 Simson Garfinkel * src/tcpdemux.h (class tcpdemux): retrying_open now takes a std:;string 2012-11-14 Simson Garfinkel * src/tcpip.cpp (tcpip::store_packet): added bytes_processed addition so that is properly updated. * src/be13_api/bulk_extractor_i.h: renamed histograms to be feature_histograms * src/plugin.cpp (process_sbuf): renamed process_extract to process_sbuf and put it here. 2012-11-06 Simson Garfinkel * src/tcpdemux.cpp (tcpdemux::process_tcp): first packet sense was inverted. Fixed. * src/main.cpp (main): renamed main.cpp to tcpflow.cpp 2012-11-05 Simson Garfinkel * src/main.cpp (main): print_usage() renamed usage() for consistency with bulk_extractor (usage): usage made static 2012-10-28 Simson Garfinkel * src/pcb_timehistogram.cpp: made histograms static * src/tcpip.cpp (tcpip::store_packet): debug_level changed to debug in all files. 2012-10-26 Simson Garfinkel * src/flow.cpp (flow::print_usage): shortened filename template usage. * src/tcpip.cpp (insert): added this function to insert a space at the beginning of a file. Now tcpflow can handle a flow with missing SYNs and out-of-order packets. 2012-10-25 Simson Garfinkel * src/tcpip.cpp (tcpip::print_packet): implemented strip-on-fputc * src/tcpdemux.cpp (do_strip_nonprint): removed this function, as it could be replaced with strip-on-fputc 2012-10-24 Simson Garfinkel * src/tcpdemux.cpp (tcpdemux::open_tcpfile): now asserts that file is not open (tcpdemux::open_tcpfile): retrying_fopen changed to retrying_open (tcpdemux::process_tcp): completely rewrote the TCP implementation (tcpdemux::process_ip4): The old state machine kept tract of each flow's initial sequence number (ISN) and computed the absolute 32-bit position within the TCP flow for each TCP segment. The problem with this approach is that it would not handle segments larger than 4GiB. The new state machine computes what it expects the Next Sequence Number (NSN) to be based on the previously processed segment in the flow. If there is a difference between the actual NSN and the predicted NSN then there is a relative seek done in the file. If I file needs to be closed (due to file handle exhaustion) and re-opened (because a segment on the flow shows up), the file pointer is put at the end of the file and the NSN is predicted from the ISN (which was cached). This will allow closing and re-opening flows bigger than 4GiB because the bits over 32 bit will be ignored in the NSN calculation. * src/tcpdemux.h (class tcpip): store_packet modified to take a delta rather than a sequence number (class tcpip): changed from FILE* to fd for all i/o * src/tcpdemux.cpp (tcpdemux::process_tcp): renamed console_only to console_output; modified order of stripping and console_output checking to check first for console output before checking to see if data should be stripped 2012-10-23 Simson Garfinkel * src/tcpdemux.cpp (tcpdemux::tcpdemux): packet_time renamed packet_counter * src/tcpdemux.h (class tcpip): renamed last_packet_time to be last_packet_number as it was not being used * src/tcpip.cpp (tcpip::store_packet): removed the 'finished' flag from the tcpip:: class. It was being set when the flow went over demux.max_bytes_per_flow. However, if a packet was then received which was less than max_bytes_per_flow the bytes would not be recorded, because the max had already been passed. 2012-10-21 Simson Garfinkel * src/tcpip.cpp (tcpip::store_packet): removed syn_set parameter and put in tcpdemux::process_tcp * configure.ac: changed version number to 1.3.1devel 2012-10-20 Simson Garfinkel * src/tcpdemux.h (class tcpdemux): process_tcp, process_ip, process_ip4 and process_ip6 now take const struct timeval &ts instead of const struct timeval *ts as their first argument, becuase ts should never be NULL. 2012-09-16 Simson Garfinkel * src/flow.cpp (flow::filename): TM_FORMAT is now "%Y-%m-%dT%H:%M:%SZ" * src/xml.cpp (xml::add_DFXML_execution_environment): TM_FORMAT is now always "%Y-%m-%dT%H:%M:%SZ" 2012-09-11 Simson Garfinkel * src/datalink.cpp (dl_ethernet): now handles ETHERTYPE_LOOPBACK not defined. 2012-08-20 Simson Garfinkel * configure.ac: increased version number to 1.3.0 2012-08-16 Simson Garfinkel * src/tcpdemux.cpp (tcpdemux::process_tcp): fixed bug in which myflow.tlast wasn't being set. 2012-08-16 Simson Garfinkel * configure.ac: Increased version number to 1.2.9 * src/main.cpp (main): fixed compile bugs that resulted from adoption of standard DFXML header. 2012-08-10 Simson Garfinkel * configure.ac (HAVE_PTHREAD): fixed typo in configure.ac 2012-08-08 Simson Garfinkel * src/tcpdemux.h: removed struct ip as it was redundent to struct iphdr * configure.ac: tcpflow now compiles under mingw for Windows * src/tcpdemux.cpp: moved tcpdemux class methods into this new file. 2012-08-03 Simson Garfinkel * src/tcpip.cpp (tcpip::close_file): added support for FUTIMENS, but I don't yet have a system on which to test it. Hope that it's good. 2012-07-23 Simson Garfinkel * src/main.cpp (main): added calling process_infile(expression,device,"",true) when no files are provided to fix bug of no live capture. * configure.ac: version 1.2.8 2012-07-02 Simson Garfinkel * src/sysdep.h: removed; put code in tcpflow.h for simplicity 2012-06-26 mike * src/datalink.cpp (dl_null): moved ETHERTYPE_IPV6 from sysdep.h to datalink.cpp 2012-06-18 Simson Garfinkel * bootstrap.sh: added --add-missing to bootstrap.sh 2012-05-24 Simson Garfinkel * configure.ac: increased version to 1.2.7. * src/main.cpp (main): -r option now allows for multiple files to be specified. * src/main.cpp (main): -R option now allows for incomplete tcp connections to be finished. 2012-05-16 Simson Garfinkel * src/main.cpp (main): removed global "tcpdemux demux" variable. Now it's passed as *user in the datalink methods, as it should be. * src/tcpdemux.h (class tcpip): bytes_printed renamed to bytes_processed, as it will be used in packet processing as well. 2012-04-19 Simson Garfinkel * configure.ac: incremented version to 1.2.6 (1.2.5 had a bad tag) * src/tcpip.cpp (tcpip::print_packet): fixed error in fwrite(). 2012-04-11 Simson Garfinkel * created version 1.2.4 tag 2012-04-03 Simson Garfinkel * src/main.cpp (print_usage): fixed misspelling of name * src/tcpip.cpp (tcpdemux::tcpdemux): default outdir is now "." 2012-03-26 Simson Garfinkel * src/xml.cpp (xml::add_cpuid): better handling of CPUID instruction. Now it really should not show up on non-Intel architectures. 2012-03-19 Simson Garfinkel * src/xml.cpp: added unistd.h 2012-03-18 Simson Garfinkel * src/main.cpp (main): added printing stats for debug level 3. * src/datalink.cpp (find_handler): changed 'looking for handler' to debug level 2. 2012-03-18 Simson Garfinkel * src/tcpip.cpp (tcpdemux::close_all): Jeremey's FD ring has been replaced with an unordere dset. * src/tcpdemux.h (class tcpdemux): tcpdemux is now a class. By 1.3 it will be a linkable class separate from this program. 2012-03-11 Simson L. Garfinkel * configure.ac: added -funit-at-a-time 2012-03-10 Simson Garfinkel * COPYING: updated to GPLv3 2012-03-10 Simson Garfinkel * src/xml.cpp (xml::xmlout): writing with size-length tag just outputs the value now. 2012-03-03 Simson Garfinkel * configure.ac: changed verison number to 1.2.1 * src/xml.cpp (xml::cpuid): added another #if defined(HAVE_ASM_CPUID) to protect another __asm__("cpuid") 2012-03-03 Simson Garfinkel * configure.ac: changed version number to 1.2.0 2012-03-09 Simson Garfinkel * src/tcpip.cpp (tcpip::attempt_fopen): output files now opened in binary mode (tcpip::store_packet): added error message for packet received after flow finished * src/md5.c: added file. * src/md5.h: added file. * src/tcpip.cpp (tcpip::open_file): removed "done" variable, as it was not needed. (tcpip): string constants that are converted to strings are now const statics. 2012-02-26 Simson Garfinkel * src/flow.cpp (flow::filename): completely rewrote to support templates. (flow::print_usage): added to give information on templates. * src/flow.h (class flow): renamed flow_t to flow * src/main.cpp (main): removed last vistaves of DEFAULT_FILTER (main): error is now a local variable. 2012-02-23 Simson Garfinkel * src/sysdep.h: changed to C++ headers for stdio, stdlib, cctype, cstdarg and cerrorno * src/tcpip.cpp (tcpip::tcpip): outdir changed from const char * to std::string. Flow names no longer have ./ prepended if outdir is ".". 2012-01-18 Simson Garfinkel * src/tcpip.cpp (tcpip::process_tcp): converted dir_cs and dir_sc to a single dir enum type. 2012-01-15 Simson Garfinkel * src/tcpip.cpp (tcpip): fixed crashing bug when no XML file was being generated. 2012-01-06 Simson Garfinkel * src/flow.h (class tcpip): replaced std::map with std::tr1::unordered_map. Old performance: 2.879478 3.227067 7675904 1953 26 0 3 4649 14.634266 new performance: 1.323023 2.676657 7430144 1921 0 0 0 4739 8.399374 2012-01-05 Simson Garfinkel * src/tcpip.cpp (do_strip_nonprint): do_strip_nonprint is now threadsafe * src/flow.h (class tcpip): pos changed from long to uint64_t * src/tcpip.cpp (tcpip::process_tcp): whoops; only drop the connection if the seek is bigger than min_offset 2012-01-04 Simson Garfinkel * configure.ac: incremented version counter to beta2 * src/main.cpp (main): fixed option parsing bug. 2012-01-03 Simson Garfinkel * src/tcpip.cpp (do_strip_nonprint): removed; do_strip_nonprint is now embedded in the caller, and is now thread-safe. * src/util.cpp (check_malloc): removed * src/tcpip.cpp (tcpip::store_packet): flow_state renamed tcpip (because it is). * src/flow.h (class flow_state): first is now called tstart and appears in the flow_t. (class flow_addr): renamed flow_t to flow_addr; it's the flow address. (class flow_t): created this class which has additional per-flow information (class flow_addr): moved vlan to flow_t from flow_addr 2012-01-01 Simson Garfinkel * src/tcpflow.h (struct): flow_t renamed to be the flow class. (class ipaddr): created class for IP addresses (class flow_state_struct): created class from struct * src/main.cpp (print_usage): -X added for XML output. 2011-12-29 Simson Garfinkel * src/main.cpp (main): changed bytes_per_flow from int to uint64_t progname is now a global. added support for named semaphores to lock output between invocations. * src/util.cpp: removed cvsid * src/tcpip.cpp: removed cvsid * src/datalink.cpp: removed cvsid * src/flow.cpp: removed cvsid * Makefile.am (EXTRA_DIST): added m4/ax_pthread.m4 to EXTRA_DIST * configure.ac: increased version number to 1.0.7 * src/main.cpp (main): added -B option to force binary output. * doc/tcpflow.1: corrected typo in -c/-C which crept it. 2011-12-23 Simson Garfinkel * src/util.cpp: removed copy_argv(); replaced with a simple std::string manipulation. (flow_filename): modified to work with outdir * src/tcpip.cpp: renamed from tcpip.c to tcpip.cpp * src/main.cpp: renamed from main.c to main.cpp; * src/util.cpp: renamed util.c; changed most "char *" to "const char *" * src/flow.cpp: renamed flow.c to flow.cpp 2011-12-04 Simson Garfinkel * configure.ac: increased version counter to 1.0.6 * src/tcpflow.h (flow_state_struct): added bytes_printed counter * src/tcpip.c (print_packet): modified to respect bytes_per_flow * configure.ac: increased version counter to 1.0.5 * src/sysdep.h: added #ifndef for ETHERTYPE_VLAN for Oracle Enterprise Linux. 2011-11-24 Simson Garfinkel * configure.ac: increased version counter to 1.0.4 2011-10-13 Simson Garfinkel * src/main.c (main): removed prepending of (ip or ip6 or vlan) from user expressions. We now just use what the user provided. 2011-09-30 Simson Garfinkel * configure.ac: incremented version counter to 1.0.2 and re-released. 2011-09-20 Simson Garfinkel * src/flow.c (open_file): replaced FGETPOS(flow_state->fp, &(flow_state->pos)) with ftell() * src/tcpip.c (store_packet): FSETPOS replaced with fseek (it's better now than in 1999) 2011-09-20 Simson Garfinkel * src/util.c: applied ipv6 patches * src/tcpip.c: applied ipv6 patches * src/tcpflow.h: applied ipv6 patches * src/sysdep.h: applied ipv6 patches * src/main.c: applied ipv6 patches * src/datalink.c: applied ipv6 patches * configure.ac: applied ipv6 patches. * src/sysdep.h: removed standards.h and added sys/cdefs.h. 2011-04-14 Simson Garfinkel * Makefile.am (EXTRA_DIST): added TODO.txt 2011-03-12 Simson Garfinkel * doc/tcpflow.1.in: updated doc to reflect new author and distribution point. * src/main.c (print_usage): removed "by Jeremy Elson " from usage. * src/util.c (flow_filename): vlan changed from [42] to --42 to avoid some shell issues. * Applied debian patch 20_fix-usage, which fixed the usage statement. 2011-02-27 Simson Garfinkel * manually applied debian patch 10_extra-opts, which improves color rendering and passes the state structure, rather than forcing it to be re-calculated. 2008-10-06 Simson Garfinkel * src/flow.c (flow_same): created a flow_same() function to return true if two flows are the same (because we will be adding additional information to the flow) (close_file): modified so that flows are timestamped with the time of the closing * src/tcpflow.h: reimplemented portable_signal to return void, rather than RETSIGTYPE, since RETSIGTYPE hasn't been used for at least 15 years. * src/sysdep.h: added #include before #include * configure.ac: rewrote to remove patches for circa 2002 Linux bugs. Fixed prerequisite header for net/if.h 2003-08-07 Jeremy Elson * Released v0.21. Sticking to my strict schedule of releasing at least one minor release per year. :-) 2003-08-07 Jeremy Elson * src/main.c: Fixed format string attack. Found by David Goldsmith of atstake.com. 2002-03-29 Jeremy Elson * configure.in: Fixed --with-pcap (was broken since moving sources into src) 2002-03-29 Jeremy Elson * src/datalink.c: Added support for ISDN (/dev/ippp0), datalink handler for DLT_LINUX_SLL. Contributed by Detlef Conradin 2001-08-23 Jeremy Elson * src/tcpip.c: fflush stdout in console print mode, from suggestion of Andreas Schweitzer , who says "Otherwise, I can't redirect or pipe the console output. At least on FreeBSD. I will check later today if this also cures the same problems I had on OpenBSD." 2001-02-26 Jeremy Elson * Released version 0.20. * util.c, main.c: we now catch SIGTERM, SIGINT and SIGHUP, and call exit(). Should give libpcap a chance to reset the interface state (it calls onexit()). * main.c, tcpflow.1.in: Added patch from "Jose M. Alcaide" (FreeBSD port maintainer) so that tcpflow can read from tcpdump output files. 2000-01-12 Jeremy Elson * tcpflow.spec.in: New file for creating RPMs, submitted by Ross Golder . * configure.in: Added generation of tcpflow.spec * Makefile.am: Added distribution of tcpflow.spec.in 1999-04-20 Jeremy Elson * Released version 0.12. 1999-04-20 Jeremy Elson * tcpflow.1.in: Updated man page. * main.c (main): libpcap, when running under Linux, doesn't seem to be able to handle filtering expressions when using DLT_NULL (usually the loopback interface -- i.e. "localhost"), so we don't allow those expressions and print a warning if the user is trying to use one. Controlled via the DLT_NULL_BROKEN define in conf.h. * datalink.c (dl_null): We no longer check that the datalink type is AF_INET if DLT_NULL_BROKEN is defined. * configure.in: Added AC_CANONICAL_SYSTEM, and define DLT_NO_BROKEN if we are using Linux. * acconfig.h: Added entry for DLT_NULL_BROKEN. * tcpflow.h: We use __attribute__ now only if __GNUC__ is defined, so that the code compiles on non-GCC compilers. * configure.in: Check for standards.h, for IRIX compatibility. (I have a custom autoconf that I changed to automatically #include standards.h, if the check succeeds, in future header file checks.) * sysdep.h: Conditional #include added. * configure.in: Only check for -lnsl if gethostbyaddr() doesn't work without it; same for -lsocket and socket(). * tcpip.c (process_ip, process_tcp, do_strip_nonprint, print_packet, store_packet): Changed to take a u_char. * tcpflow.h: Changed packet handling function argument prototypes and return values to use u_char instead of char. * configure.in: Added checking for u_char. * acconfig.h: Added entry for u_char. * tcpip.c (process_ip, process_tcp): Added debugging messages. * tcpip.c (store_packet): Changed debug level of messages. 1999-04-14 Jeremy Elson * tcpip.c (store_packet): Now correctly checking the return value of fwrite(). Pointed out by Johnny Tevessen . 1999-04-13 Jeremy Elson * Released version 0.11. 1999-04-13 Jeremy Elson * tcpip.c (process_ip): Portability: added typecast of an int to a long, and changed the printf format to use a long (%ld) instead of an int (%d). This is because some systems define these variables as long to begin with. * tcpip.c (store_packet): Same thing. * util.c (init_debug): Same thing. * main.c (print_usage): Added function to give help. * sysdep.h: Linux libc5 systems have different names for certain structures. Patch sent by Johnny Tevessen * configure.in: All system header files are now detected by autoconf and conditionally included in sysdep.h. * sydep.h: Same. * main.c: Same. * tcpip.c: Same. * Makefile.am (EXTRA_DIST): Changed from tcpflow.1 to tcpflow.1.in to reflect the fact that tcpflow.1 is now created by 'configure'. * configure.in: Same. * tcpflow.1.in: Same. * AUTHORS: Created & added initial entries. 1999-04-12 Jeremy Elson * Initial public release. tcpflow-tcpflow-1.6.1/INSTALL000066400000000000000000000001501401360461700157000ustar00rootroot00000000000000Better install instructions will go here. 1 - ./bootstrap.sh 2 - ./configure 3 - make 4 - make install tcpflow-tcpflow-1.6.1/Makefile.am000066400000000000000000000031301401360461700167040ustar00rootroot00000000000000# Makefile.am for tcpflow # SUBDIRS = src doc tests EXTRA_DIST = tcpflow.spec.in TODO.txt m4/ax_pthread.m4 ACLOCAL_AMFLAGS = -I m4 AM_CFLAGS = -Wall renew: touch NEWS README AUTHORS ChangeLog stamp-h aclocal autoheader -f autoconf -f automake --add-missing -c grenew: touch NEWS README AUTHORS ChangeLog stamp-h aclocal autoheader -f autoconf -f automake --add-missing -c # For testing: pdft: (cd src;make tcpflow) /bin/rm -rf out src/tcpflow -a -o out -r /corp/nps/packets/2008-nitroba/nitroba.pcap -w out/extra.pcap open out/report.pdf # # AFFLIB RELEASE SYSTEM V1.0 FOLLOWS # RELEASE_USER = simsong@ RELEASE_HOST = digitalcorpora.org RELEASE_DIR = digitalcorpora.org/ RELEASE_LOC = $(RELEASE_DIR)/downloads/ VERSION_FN = $(PACKAGE)_version.txt RELEASE_PATH = $(RELEASE_LOC)/$(VERSION_FN) RELEASE_SSH = $(RELEASE_USER)$(RELEASE_HOST):$(RELEASE_LOC) release: make dist make distcheck make the_release the_release: $(RELEASEFN) gpg --detach-sign $(RELEASEFN) @echo Release $(RELEASE_VER) uploaded to server tcpflow32.exe: mingw32-configure make clean make mv -f src/tcpflow.exe tcpflow32.exe tcpflow64.exe: mingw64-configure make clean make mv -f src/tcpflow.exe tcpflow64.exe FN=$(PACKAGE_TARNAME)-$(PACKAGE_VERSION).zip $(FN): tcpflow32.exe tcpflow64.exe /bin/rm -f tcpflow*.exe $(FN) make tcpflow32.exe make tcpflow64.exe zip $(FN) tcpflow32.exe tcpflow64.exe winrelease: $(FN) pub: $(FN) scp $(FN) dcorpora@digitalcorpora.org:downloads/tcpflow/ .PHONY: pull pull: git pull (cd src/dfxml;git pull) (cd src/be13_api;git pull) # # END OF AFFLIB RELEASE SYSTEM # tcpflow-tcpflow-1.6.1/NEWS000066400000000000000000000170701401360461700153570ustar00rootroot00000000000000Version 1.3.1 NOV ?? Complete rewrite of the TCP state machine, now handles flows larger than 4GiB. Version 1.3.0 SEP 30 2012 Release for end of FY2012, includes bug fixes, better support for autoconf, DFXML standardizations, and the ability to compile under mingw for Windows (that was a LOT of work). Version 1.2.7 May 24 2012 (GIT) I am pleased to announce the release of tcpflow version 1.2.7 Version 1.2.7 offers two significant features over previous versions relating to the processing of the -r and the new -R options. -r file1.pcap - This option specifies a pcap file to be read. New with version 1.2.7, the -r flag may be repeated any number of times. -R file0.pcap - This option, new with version 1.2.7, allows a file to be specified that was captured in time *before* the file specified with -r. This option allows TCP sessions that started in file0.pcap and which continued into file1.pcap to be properly started. This option is useful when some external process makes packet capture files at regular intervals and then the files are reassembled later. Typically these files result from tcpdump run with the -w or -C options. Verison 1.2.7 can be downloaded from github: $ git clone git://github.com/simsong/tcpflow.git $ cd tcpflow $ sh bootstrap.sh $ ./configure $ make or from: $ https://github.com/downloads/simsong/tcpflow/tcpflow-1.2.7.tar.gz ================================================================ Version 1.2 March 15 2012 (SVN ) I am pleased to announce the release of tcpflow version 1.2. Version 1.2 is the first to include post-processing of TCP connections integrated directly into the tcpflow program itself. post-processing is optional and is performed on a per-connection basis when the connection is closed. The following post-processing method methods are currently defined. -FM - Compute the MD5 hash value of every stream on close. Currently MD5 hashes are only computed for TCP streams that contain packets transmitted contigiously. -FM processing can happen even when output is suppressed. The MD5 is written into the DFXML file. -AH - Detect Email/HTTP responses and separate headers from body. This requires that the output files be captured. If the output file is 208.111.153.175.00080-192.168.001.064.37314, Then the post-processing will create the files: 208.111.153.175.00080-192.168.001.064.37314-HTTP 208.111.153.175.00080-192.168.001.064.37314-HTTPBODY If the HTTPBODY was compressed with GZIP, you may get a third file as well: 208.111.153.175.00080-192.168.001.064.37314-HTTPBODY-GZIP Additional information about these streams, such as their MD5 hash value, is also written to the DFXML file These features are all present in Version 1.2.2, which is available now for download from http://afflib.org/ Version 1.1.0 19 January 2012 (SVN 8118) I am pleased to announce the release of tcpflow version 1.1. Version 1.1 represents a significant rewrite of tcpflow. All users are encouraged to upgrade. Significant changes include: * Entire code base migrated to C++ ; code generally improved. tcpflow's original hash table has been replaced with a tr1::unordered_map which should offer significantly more scalability. * tcpflow now automatically expires out old connections. This finally end the program's memory-hogging problem. (You can disable this behavior with -P, which makes tcpflow run faster because it never cleans up after itself. That's fine if you are working with less than a million connections.) * Multiple connections with the same (source/destination) are now detected and stored in different files. This is significant, as the previous implementation would make a single file 1-2GB in length if you the same host/port pairs with two different flows. Additional files have the same filename and a "c0001", "c0002" appended. * Filenames may now be prefixed with either the ISO8601 time or a Unix timestamp indicating the time that the connection was first seen. * tcpflow will now save a DFXML file containing information for each flow that it reconstructs. * The following new options are now implemented: -o outdir --- now works (previously was not implemented) -X xmfile --- now reports execution results in a DFXML file. (Version 1.1 will include complete notion in the XML file of every TCP connection as a DFXML -Fc --- Every file has the 'cXXXX' postfix, rather than just the files with duplicate source/destination. -Ft --- Every file has the T prefix. -FT --- Every file has an ISO8601 time prefix, e.g. 2012-01-01T09:45:15Z -mNNNN --- Specifies the minimum number of bytes that need to be skipped in a TCP connection before a new -Lname --- use the named semaphore 'name' to prevent multiple tcpflow processes printing to standard output from overprinting each other. -P --- do not prune the tcp connection table. Other improvements include: * Support for IPv6 * Support for VLANs * The default filter which was causing problems under MacOS has been removed. tcpflow can be downloaded from: http://afflib.org/ http://afflib.org/software/tcpflow Finally, because the previous maintainer had lost control of the old tcpflow mailing list, a new one has been created at Google Groups. You can subscribe at: http://groups.google.com/group/tcpflow-users Version 1.0.4 November 24, 2011 * Default fitler changed to ""; previous default filter was causing problems on macs. Version 1.0.2 September 30, 2011 * IPv6 code added Version 1.0.0 January 2011 * Updated to support VLANs. VLAN packets are marked by hex 0x8100 following the destination and source mac addresses, followed by the 16-bit VLAN address, followed by 0x0800 marking the beginning of the traditional IP header. Version 0.30 October 2007 * Simson Garfinkel is now the maintainer of this package * Modified to set the time of each tcpflow with the time of the first packet. * Created a regression test, so "make check" and "make distcheck" now work. * Updated to modern autoconf tools. Version 0.20 (February 26, 2001): * A bug was fixed that caused out-of-order reassembly to generate seemingly very large files on some systems (specifically, those that support fgetpos/fsetpos). * Bug fixed that caused the interface to be left in promiscuous mode after tcpflow terminated * The -r option was added, contributed by Jose M. Alcaide * We now distribute tcpflow RPMs, thanks to a spec file submitted by Ross Golder . Version 0.12 (April 20, 1999): * Now compiles under IRIX, and using non-GCC compilers. * Workaround for the Linux/libpcap bug that prevented tcpflow from listening to packets on the Linux loopback interface. It's not perfect -- it appears impossible to install a libpcap filtering expression when listening to the Linux loopback interface. Thus, *all* flows on that interface are recorded. Someday I may try to fix either libpcap or the Linux kernel so that this workaround is not necessary. Version 0.11 (April 13, 1999): * Support for older (libc5) Linux systems (submitted by Johnny Tevessen ). * Some minor fixes. Version 0.10 (April 12, 1999): * First public release. tcpflow-tcpflow-1.6.1/README.md000066400000000000000000000220361401360461700161350ustar00rootroot00000000000000TCPFLOW 1.5.0 ============= Downloads directory: http://digitalcorpora.org/downloads/tcpflow/ Installation ------------ Most common GNU/Linux distributions ship tcpflow in their repositories. So on Debian/Ubuntu/etc you can say sudo apt-get install tcpflow and on Fedora/RedHat/CentOS/etc you can say sudo dnf install tcpflow And that's it. If this isn't good-enough for whatever reason, you can build from source: Building from source -------------------- To compile for Linux Be sure you have the necessary precursors. There are files in the root directory that will do this for you, depending on your host operating system: CONFIGURE_ARCH_17_8.sh CONFIGURE_FEDORA_18.sh CONFIGURE_FEDORA_26.sh CONFIGURE_UBUNTU_16_04.sh Depending on your OS, just: # sudo bash CONFIGURE_.sh Once you have configured your OS, compile and install with: ./configure make sudo make install If you want do download the development tree with git, be sure to do a *complete* checkout with `--recursive` and then run `bootstrap.sh`, `configure` and `make`: git clone --recursive https://github.com/simsong/tcpflow.git cd tcpflow bash bootstrap.sh ./configure make sudo make install To download and compile for Amazon AMI: ssh ec2-user@ sudo bash yum -y install git make gcc-c++ automake autoconf boost-devel cairo-devel libpcap-devel openssl-devel zlib-devel git clone --recursive https://github.com/simsong/tcpflow.git sh bootstrap.sh To Compile for Windows with mingw on Fedora Core: yum -y install mingw64-gcc mingw64-gcc-c++ mingw64-boost mingw64-cairo mingw64-zlib mingw64-configure make To use CMake, see detailed instructions: [cmake/README.md](./cmake/README.md) Build RPM --------- From a clean repository as normal user (not root): ./bootstrap.sh # Generates the file ./configure ./configure # Generates the file tcpflow.spec rpmbuild -bb tcpflow.spec --build-in-place Check the specfile and resulted RPM: rpmlint tcpflow.spec rpmlint ~/rpmbuild/RPMS/x86_64/tcpflow-....rpm Install: sudo dnf install ~/rpmbuild/RPMS/x86_64/tcpflow-....rpm Introduction To tcpflow ======================= tcpflow is a program that captures data transmitted as part of TCP connections (flows), and stores the data in a way that is convenient for protocol analysis and debugging. Each TCP flow is stored in its own file. Thus, the typical TCP flow will be stored in two files, one for each direction. tcpflow can also process stored 'tcpdump' packet flows. tcpflow stores all captured data in files that have names of the form: [timestampT]sourceip.sourceport-destip.destport[--VLAN][cNNNN] where: timestamp is an optional timestamp of the time that the first packet was seen T is a delimiter that indicates a timestamp was provided sourceip is the source IP address sourceport is the source port destip is the destination ip address destport is the destination port VLAN is the VLAN port c is a delimiter indicating that multiple connections are present NNNN is a connection counter, when there are multiple connections with the same [time]/sourceip/sourceport/destip/destport combination. Note that connection counting rarely happens when timestamp prefixing is performed. HERE are some examples: 128.129.130.131.02345-010.011.012.013.45103 The contents of the above file would be data transmitted from host 128.129.131.131 port 2345, to host 10.11.12.13 port 45103. 128.129.130.131.02345-010.011.012.013.45103c0005 The sixth connection from 128.129.131.131 port 2345, to host 10.11.12.13 port 45103. 1325542703T128.129.130.131.02345-010.011.012.013.45103 A connection from 128.129.131.131 port 2345, to host 10.11.12.13 port 45103, that started on at 5:19pm (-0500) on January 2, 2012 128.129.130.131.02345-010.011.012.013.45103--3 A connection from 128.129.131.131 port 2345, to host 10.11.12.13 port 45103 that was seen on VLAN port 3. You can change the template that is used to create filenames with the -F and -T options. If a directory appears in the template the directory will be automatically created. If you use the -a option, tcpflow will automatically interpret HTTP responses. If the output file is 208.111.153.175.00080-192.168.001.064.37314, Then the post-processing will create the files: 208.111.153.175.00080-192.168.001.064.37314-HTTP 208.111.153.175.00080-192.168.001.064.37314-HTTPBODY If the HTTPBODY was compressed with GZIP, you may get a third file as well: 208.111.153.175.00080-192.168.001.064.37314-HTTPBODY-GZIP Additional information about these streams, such as their MD5 hash value, is also written to the DFXML file tcpflow is similar to 'tcpdump', in that both process packets from the wire or from a stored file. But it's different in that it reconstructs the actual data streams and stores each flow in a separate file for later analysis. tcpflow understands sequence numbers and will correctly reconstruct data streams regardless of retransmissions or out-of-order delivery. However, tcpflow currently does not understand IP fragments; flows containing IP fragments will not be recorded properly. tcpflow can output a summary report file in DFXML format. This file includes information about the system on which the tcpflow program was compiled, where it was run, and every TCP flow, including source and destination IP addresses and ports, number of bytes, number of packets, and (optionally) the MD5 hash of every bytestream. tcpflow uses the LBL Packet Capture Library (available at ftp://ftp.ee.lbl.gov/libpcap.tar.Z) and therefore supports the same rich filtering expressions that programs like 'tcpdump' support. It should compile under most popular versions of UNIX; see the INSTALL file for details. What use is it? --------------- tcpflow is a useful tool for understanding network packet flows and performing network forensics. Unlike programs such as WireShark, which show lots of packets or a single TCP connection, tcpflow can show hundreds, thousands, or hundreds of thousands of TCP connections in context. A common use of tcpflow is to reveal the contents of HTTP sessions. Using tcpflow you can reconstruct web pages downloaded over HTTP. You can even extract malware delivered as 'drive-by downloads.' Jeremy Elson originally wrote this program to capture the data being sent by various programs that use undocumented network protocols in an attempt to reverse engineer those protocols. RealPlayer (and most other streaming media players), ICQ, and AOL IM are good examples of this type of application. It was later used for HTTP protocol analysis. Simson Garfinkel founded Sandstorm Enterprises in 1998. Sandstorm created a program similar to tcpflow called TCPDEMUX and another version of the program called NetIntercept. Those programs are commercial. After Simson left Sandstorm he had need for a tcp flow reassembling program. He found tcpflow and took over its maintenance. Bugs ---- Please enter bugs on the [github issue tracker](https://github.com/simsong/tcpflow/issues?state=open) tcpflow currently does not understand IP fragments. Flows containing IP fragments will not be recorded correctly. IP fragmentation is increasingly a rare event, so this does not seem to be a significant problem. RECOMMENDED CITATION ==================== If you are writing an article about tcpflow, please cite our technical report: * Passive TCP Reconstruction and Forensic Analysis with tcpflow, Simson Garfinkel and Michael Shick, Naval Postgraduate School Technical Report NPS-CS-13-003, September 2013. https://calhoun.nps.edu/handle/10945/36026 MAINTAINER ========== Simson L. Garfinkel TCPFLOW 1.6 STATUS REPORT ========================= I continue to port bulk_extractor, tcpflow, be13_api and dfxml to modern C++. After surveying the standards I’ve decided to go with C++17 and not C++14, as support for 17 is now widespread. (I probably don’t need 20). I am sticking with autotools, although there seems a strong reason to move to CMake. I am keeping be13_api and dfxml as a modules that are included, python-style, rather than making them stand-alone libraries that are linked against. I’m not 100% sure that’s the correct decision, though. The project is taking longer than anticipated because I am also doing a general code refactoring. The main thing that is taking time is figuring out how to detangle all of the C++ objects having to do with parser options and configuration. Given that tcpflow and bulk_extractor both use be13_api, my attention has shifted to using tcpflow to get be13_api operational, as it is a simpler program. I’m about three quarters of the way through now. I anticipate having something finished before the end of 2020. --- Simson Garfinkel, October 18, 2020 ACKNOWLEDGEMENTS ================ Thanks to: * Jeffrey Pang, for the radiotap implementation * Doug Madory, for the Wifi parser * Jeremy Elson, for the original idea and initial tcp/ip implementation tcpflow-tcpflow-1.6.1/TODO.txt000066400000000000000000000156141401360461700161700ustar00rootroot00000000000000Accomplished for 1.4: + update tcpip structure to indicate if a SYN was seen; If packets arrive before the beginning of the connection and a SYN was not seen, insert in the beginning of the file. + remove syn_set from store_packet. Make sure that it's called when we know the packet offset. + discover and create MIME objects. + Regression testing by randomizing packet order and making sure that the results are the same. ================================================================ ================ Here is an idea currently plan for the plugin approach: -Ps "command" --- Run command at the start of each flow; pipe the flow to stdin -Pe "command" --- Run command at the end of each flow; pipe the flow to stdin (from the file) -PE "command" --- Run command at the end of each flow, but do not pipe flow to stdin ================================================================ Other programs to look at: http://net.doit.wisc.edu/~plonka/FlowScan/ http://ant.isi.edu/wiv2012/program.html ================ Current bugs: - Add more tests, specifically a test to read multiple files at once. tests/bug2.pcap has a connection with multiple packets sent after it is closed. src/tcpflow -d 100 -o bug2 -r tests/bug2.pcap --- gets data corruption because the retransmitted packets overwrite the beginning src/tcpflow -P -d 100 -o bug2 -r tests/bug2.pcap --- doesn't. - Need to see if the filename that's tried to open already exists. If it does, we need to incrment connection count and then go on. - But then, we need to realize that it shouldn't be expired out... tests/bug3.pcap (think that it's the same problem as above) - Run the program twice to the same output directory and the second transcript file doesn't match the first. - Run the program with remove_flow() commented out in tcpdemux.cpp:391 and the results are correct; run with it in and the results are different. - Should be the same results each time. bug3 has some retransmitted packets: 18:44 Mucha:~/gits/tcpflow/src$ tcpdump -n -r bugshow.pcap reading from file bugshow.pcap, link-type EN10MB (Ethernet) 19:59:14.168870 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [S.], seq 2626615675, ack 2244319387, win 8190, options [mss 1404], length 0 19:59:14.245209 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], ack 176, win 6432, length 0 19:59:14.262536 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 1:1405, ack 176, win 6432, length 1404 19:59:14.264902 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 1405:2809, ack 176, win 6432, length 1404 19:59:14.339295 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 2809:4213, ack 176, win 6432, length 1404 19:59:14.341381 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 4213:5617, ack 176, win 6432, length 1404 19:59:14.415653 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 5617:7021, ack 176, win 6432, length 1404 19:59:14.616627 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 1405:2809, ack 176, win 6432, length 1404 19:59:15.168975 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 1405:2809, ack 176, win 6432, length 1404 19:59:15.244915 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 4213:5617, ack 176, win 6432, length 1404 19:59:16.352607 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 4213:5617, ack 176, win 6432, length 1404 19:59:18.560576 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 4213:5617, ack 176, win 6432, length 1404 19:59:18.741621 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 5617:7021, ack 176, win 6432, length 1404 19:59:18.941183 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 7021:8425, ack 176, win 6432, length 1404 19:59:23.360857 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 7021:8425, ack 176, win 6432, length 1404 19:59:32.192737 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 7021:8425, ack 176, win 6432, length 1404 19:59:44.267381 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 8425:9829, ack 176, win 6432, length 1404 19:59:44.269510 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 9829:11233, ack 176, win 6432, length 1404 19:59:44.271699 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 11233:12637, ack 176, win 6432, length 1404 19:59:44.273920 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 12637:14041, ack 176, win 6432, length 1404 19:59:44.276258 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 14041:15445, ack 176, win 6432, length 1404 19:59:44.278144 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 15445:16849, ack 176, win 6432, length 1404 19:59:44.280288 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 16849:18253, ack 176, win 6432, length 1404 19:59:44.282501 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 18253:19657, ack 176, win 6432, length 1404 19:59:44.284995 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 19657:21061, ack 176, win 6432, length 1404 19:59:44.287025 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 21061:22465, ack 176, win 6432, length 1404 19:59:44.289222 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 22465:23869, ack 176, win 6432, length 1404 19:59:44.291409 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 23869:25273, ack 176, win 6432, length 1404 19:59:44.293651 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 25273:26677, ack 176, win 6432, length 1404 19:59:44.295618 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 26677:28081, ack 176, win 6432, length 1404 19:59:44.297842 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 28081:29485, ack 176, win 6432, length 1404 19:59:44.300019 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 29485:30889, ack 176, win 6432, length 1404 19:59:44.302461 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 30889:32293, ack 176, win 6432, length 1404 19:59:44.304704 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 32293:33697, ack 176, win 6432, length 1404 19:59:44.304718 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [FP.], seq 35101:35106, ack 176, win 6432, length 5 19:59:44.306948 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 33697:35101, ack 176, win 6432, length 1404 19:59:44.347541 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [F.], seq 35106, ack 176, win 8190, length 0 19:59:49.856312 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 7021:8425, ack 176, win 6432, length 1404 19:59:49.929110 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [F.], seq 35106, ack 176, win 8190, length 0 19:59:49.931878 IP 65.212.118.21.80 > 192.168.1.64.33410: Flags [.], seq 11233:12637, ack 176, win 6432, length 1404 18:44 Mucha:~/gits/tcpflow/src$ So we are not handling the retransmits properly. If the file is already there: - Assume it's our file and open it; set up the buffers accordingly On retransmit: - If the data doesn't match, increment the connection count (easy way to document the retransmit) tcpflow-tcpflow-1.6.1/bootstrap.sh000077500000000000000000000020211401360461700172220ustar00rootroot00000000000000#!/bin/bash # Hopefully you checked out with: # $ git clone --recursive https://github.com/simsong/tcpflow.git # Make sure we have automake installed function usage() { echo tcpflow bootstrap: echo be sure to run the appropriate CONFIGURE script to install the necessary packages. exit 1 } automake --help 1>/dev/null 2>&1 || usage for sub in be13_api http-parser do if [ ! -r src/$sub/.git ] ; then echo bringing in submodules echo next time check out with git clone --recursive git submodule init git submodule update fi done ## The new way: # have automake do an initial population iff necessary if [ ! -e config.guess -o ! -e config.sub -o ! -e install-sh -o ! -e missing -o ! -e test-driver ]; then /bin/rm -rf aclocal.m4 autoheader -f aclocal -I m4 autoconf -f automake --add-missing --copy else autoreconf -f fi echo be sure to run ./configure ## The old way: # /bin/rm -rf aclocal.m4 # autoheader -f # aclocal -I m4 # autoconf -f # automake --add-missing --copy # ./configure tcpflow-tcpflow-1.6.1/cmake/000077500000000000000000000000001401360461700157335ustar00rootroot00000000000000tcpflow-tcpflow-1.6.1/cmake/FindPCAP.cmake000066400000000000000000000017001401360461700202570ustar00rootroot00000000000000# Tries to find libpcap headers and libraries # # Usage of this module as follows: # # find_package(PCAP) # # Variables used by this module, they can change the default behaviour and need # to be set before calling find_package: # # PCAP_ROOT_DIR Set this variable to the root installation of # libpcap if the module has problems finding # the proper installation path. # # Variables defined by this module: # # PCAP_FOUND System has PCAP libs/headers # PCAP_LIBRARIES The PCAP libraries # PCAP_INCLUDE_DIR The location of PCAP headers find_path(PCAP_INCLUDE_DIR NAMES pcap.h HINTS ${PCAP_ROOT_DIR}/include) find_library(PCAP_LIBRARIES NAMES pcap HINTS ${PCAP_ROOT_DIR}/lib) include(FindPackageHandleStandardArgs) find_package_handle_standard_args( PCAP DEFAULT_MSG PCAP_LIBRARIES PCAP_INCLUDE_DIR) mark_as_advanced( PCAP_ROOT_DIR PCAP_LIBRARIES PCAP_INCLUDE_DIR) tcpflow-tcpflow-1.6.1/cmake/README.md000066400000000000000000000160661401360461700172230ustar00rootroot00000000000000CMake for TcpFlow ================= Objective --------- The provided CMake scripts within the **TcpFlow** source code are not a replacement for autotools/automake scripts. The autotools/automake scripts are required to generate the header `config.h` and also to build official release. But CMake provide other advantages: * Generate IDE project settings as for Qt Creator, Eclipse CDT or Visual C++. * Generate `ninja` build scripts as an alternative to `Makefiles`. * Provide build type *Coverage* and targets to visualize reports. * Facilities for static and runtime source code analysis. * ... The following chapters explain how to use the features available by the current CMake scripts. Quick start ----------- Clone Git repository and its submodules recursively. git clone --recursive https://github.com/simsong/tcpflow cd tcpflow Generate the header `config.h` (autotools check the availability of libraries and features within your environment). ./boostrap.sh ./configure And use CMake. mkdir build-dir cd build-dir cmake .. # Generate the build scripts (e.g. Makefiles) cd .. cmake --build build-dir # Run the build tool (e.g. make) CMake v3.1 ---------- The CMake scripts require CMake v3.1 (2015) that may not be available on your platform. To get a recent CMake version, you may build it from source code: git clone https://cmake.org/cmake.git cd cmake git checkout v3.4.3 cmake . cmake --build . To install freshly built CMake: cmake install # To be checked Or you may use `checkinstall` to create a package `*.deb` sudo apt install checkinstall sudo checkinstall Build Directory --------------- Tools like autotools usually write temporary files within the source code tree. CMake can also pollute the source code tree with temporaries, but you can decide where CMake write its temporary files, libraries and executables. The classic way is to create a directory `build`: cd /path/to/tcpflow/root/dir mkdir build ( cd build && cmake .. ) cmake --build build But you can also decide any other directory name: cd /path/to/tcpflow/root/dir mkdir /my/build/directory ( cd /my/build/directory && cmake $OLDPWD ) cmake --build /my/build/directory Build Tool ---------- CMake does not build the project: CMake is not a build tool. CMake generates files for a build tool as [gmake, nmake, ninja, Visual Studio...](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html). ### Makefiles On most Unix-like platforms, CMake generates *Unix Makefiles* when GNU Make is available. Therefore, command `make` can also be used to build the project. mkdir build cd build cmake .. # Generate Makefiles make -j4 # Build using four jobs To enable verbose mode use `VERBOSE=1` to display the full command lines during build. make -j4 VERBOSE=1 ### Ninja If [`ninja`](https://github.com/ninja-build/ninja) is available, you can use it instead of `make`. mkdir build cd build cmake .. -G Ninja ninja Use argument `-v` for verbose mode: mkdir build cd build cmake .. -G Ninja ninja -v ### CMake argument `--build ` Use `cmake --build ` to abstract the build tool. mkdir build cd build cmake .. -G "${MY_CMAKE_GENERATOR}" cmake --build . ### Integrated Development Environment Qt Creator is natively compatible with CMake and the root file `CMakeLists.txt` can be opened directly from Qt Creator. For other IDE, you can use CMake argument `-G`. Below example is for IDE Eclipse using `make`: mkdir build cd build cmake .. -G "Eclipse CDT4 - Unix Makefiles" Please see [IDE Build Tool Generators](https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html#ide-build-tool-generators) in CMake documentation. Compiler -------- You can also select another compiler using `CC` and `CXX` environment variables. mkdir build cd build CC=clang CXX=clang++ cmake .. cmake --build . mkdir build cd build CC=clang CXX=clang++ cmake .. cmake --build . Build Types ----------- The CMake scripts of **TcpFlow** project supports three build types: **Debug**, **Release** and **Coverage**. You can select the build type with the variable **`CMAKE_BUILD_TYPE`**. The default build type is **Debug**. * **Debug** (use options `-O0` and `-g3` for GCC and Clang compilers) mkdir build-debug cd build-debug cmake .. -DCMAKE_BUILD_TYPE=Debug * **Release** (still include debug info `-g3` for GCC and Clang compilers) mkdir build-release cd build-release cmake .. -DCMAKE_BUILD_TYPE=Release * **Coverage** (GCC only) mkdir build-coverage cd build-coverage cmake .. -DCMAKE_BUILD_TYPE=Coverage Target ------ Instead of building `all` just build a library and its dependencies. make netvix Compiler/Linker cache `ccache` ------------------------------ The command `ccache` can speed up compilation and link. If you clean and rebuild often, you may consider installing `ccache`. The CMake scripts of **TcpFlow** project use `ccache` when available. sudo apt install ccache cd build cmake .. time make # First build: ccache caches all compiler output make clean time make # ccache detects same input and bypasses the compiler In the same way, the CMake scripts detect presence on command `distcc`. Options ------- ### Static code analysis CMake script of **TcpFlow** project enables the option `CMAKE_EXPORT_COMPILE_COMMANDS` that produce the file `compile_commands.json` during the build. This file can be then used by static code analysis tools as `clang-check`: awk -F: '/"file"/{print $2 }' build/compile_commands.json | xargs clang-check -fixit -p build ### Run-time code analysis Option `SANITIZE=ON` let you run the run-time code analysis. cmake .. -DSANITIZE=ON ### Optimizations Option `MARCH` let you control the `CFLAG -march`. In order to use recent processor instructions set, the CMake script uses default option `MARCH=corei7` (`-march=corei7`). You can use `MARCH=native` to request `gcc` to provide the real *cpu-type* used in order to keep a reproducible build on another machine. You can use empty option `MARCH=` to unset flag `-march`. cmake .. -DMARCH=native # Detect corresponding cpu-type before build cmake .. -DMARCH= # Disable flag -march Option `OPTIM` let you control the flags `-O0 -Og -O1 -Os -O2 -O3 -Ofast`. cmake .. -DOPTIM=-Ofast The default value `OPTIM` depends on the value `CMAKE_BUILD_TYPE`: * Release: Empty `OPTIM` => Use the default `-O2` set by CMake * Debug: Use `-O0` because `-Og` does not always step-by-step debugging * Coverage: Use `-O0` to ensure code line/branch coverage Test ---- Use `cmake --build .` and `ctest` as an abstraction of the specific build tool (`ninja` or `make`) cmake .. -DCMAKE_BUILD_TYPE=Release -G Ninja cmake --build . ctest cmake .. -DCMAKE_BUILD_TYPE=Release -G Ninja cmake --build . --target netvix tcpflow-tcpflow-1.6.1/cmake/compilation-flags.cmake000066400000000000000000000113561401360461700223530ustar00rootroot00000000000000# This files sets the compiler/linker flags # Supported compilers: GCC and Clang # Use distcc/ccache if available # TODO(olibre): Use "CMAKE_{C,CXX}_COMPILER_LAUNCHER=ccache" with cmake-v3.4 find_program(path_distcc distcc) find_program(path_ccache ccache) if(path_ccache AND path_distcc) message(STATUS " Commands 'distcc' and 'ccache' detected => Use 'distcc' and 'ccache' to speed up build" ) set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "env CCACHE_PREFIX=distcc") set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "env CCACHE_PREFIX=distcc") elseif(path_ccache) message(STATUS " Command 'ccache' detected => Use 'ccache' to speed up compilation and link") set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache) set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache) elseif(path_distcc) message(STATUS " Command 'distcc' detected => Use 'distcc' to speed up compilation and link") set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE distcc) set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK distcc) endif() if(NOT CMAKE_COMPILER_IS_GNUCXX AND NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang") message(STATUS " Rest of compiler/linker flags are not available for your C++ compiler '${CMAKE_CXX_COMPILER_ID}' (only GNU and Clang are supported for the moment, please help extend these flags for your tools)") return() endif() if (BUILD_COLOR) message(STATUS " Detected defined BUILD_COLOR => Use -fdiagnostics-color=${BUILD_COLOR}") add_compile_options (-fdiagnostics-color=${BUILD_COLOR}) link_libraries (-fdiagnostics-color=${BUILD_COLOR}) endif() # -g3 => Max debug info for all targets (for any CMAKE_BUILD_TYPE) # Replace -g3 by -g2 if produced binaries are too big # Binaries may also be stripped (at packaging stage) to remove debug info add_compile_options(-g3) # -g3 -> include also the MACRO definitions # Compilation flag -march if(MARCH STREQUAL "native") if(CMAKE_COMPILER_IS_GNUCXX) EXECUTE_PROCESS( COMMAND ${CMAKE_CXX_COMPILER} -march=native -Q --help=target COMMAND awk "/-march=/{ printf $2}" OUTPUT_VARIABLE march_native ) message(STATUS " MARCH is native and compiler is GNU => Detected processor '${march_native}' => -march=${march_native}") add_compile_options( -march=${march_native} ) else() message(STATUS " MARCH is native and compiler is *not* GNU => -march=native") add_compile_options( -march=native ) endif() elseif( MARCH ) message(STATUS " MARCH is not native => -march=${MARCH}") add_compile_options( -march=${MARCH} ) else() message(STATUS " MARCH is empty => Do not set flag -march") endif() # # Speed up build using pipes (rather than temporary files) for communication between the various GCC stages # add_compile_options(-pipe) # set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pipe") # TODO(olibre): Command link_libraries(-pipe) may be use instead of above line (why not?) # Optimization flag # Set -O0/-Og/-O1/-O2/-O3/-Ofast depending on CMAKE_BUILD_TYPE if(OPTIM STREQUAL "default") if(CMAKE_BUILD_TYPE STREQUAL "Release") message(STATUS " OPTIM=${OPTIM} and CMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} => -02") add_compile_options(-O2) else() message(STATUS " OPTIM=${OPTIM} and CMAKE_BUILD_TYPE!='Release' => -O0 -fno-inline") add_compile_options(-O0 -fno-inline) endif() elseif(OPTIM) message(STATUS " OPTIM!='default' => Add content of OPTIM=${OPTIM} in compiler flags") add_compile_options(${OPTIM}) endif() if(CMAKE_BUILD_TYPE STREQUAL "Debug") message(STATUS " CMAKE_BUILD_TYPE='${CMAKE_BUILD_TYPE}' => Add -D_GLIBCXX_DEBUG_PEDANTIC in compiler flags") add_definitions(-D_GLIBCXX_DEBUG_PEDANTIC) endif() # Instrument the produced libraries/executables for run-time analysis if(SANITIZE STREQUAL "multi") message(STATUS " Detected SANITIZE='${SANITIZE}' => Add '-fsanitize=address -fsanitize=leak -fsanitize=undefined -fsanitize=signed-integer-overflow -fsanitize=shift -fsanitize=integer-divide-by-zero -fsanitize=null' in compiler flags") add_compile_options(-fsanitize=address -fsanitize=leak -fsanitize=undefined -fsanitize=signed-integer-overflow -fsanitize=shift -fsanitize=integer-divide-by-zero -fsanitize=null) elseif(SANITIZE) message(STATUS " Detected SANITIZE is enable but not 'multi' => Add '-fsanitize=${SANITIZE}' in compiler flags") add_compile_options(-fsanitize=${SANITIZE}) endif() tcpflow-tcpflow-1.6.1/cmake/coverage.cmake000066400000000000000000000076051401360461700205400ustar00rootroot00000000000000# Configuraion of the Coverage build # Also adds targets to generate coverage repports # Process this file only if BUILD_TYPE is "Coverage" if( NOT CMAKE_BUILD_TYPE STREQUAL "Coverage" ) return() endif() # This file support coverage only for GCC and Clang compilers if( NOT CMAKE_COMPILER_IS_GNUCXX AND NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang" ) message(WARNING " Coverage not yet implemented for your compiler '${CMAKE_CXX_COMPILER_ID}' (only GNU and Clang)") return() endif() # The function assert() may introduce a bias in covered lines count # To ignore lines about assert() => Disable assert() add_definitions(-DNDEBUG) # Compilers GCC and Clang need flag --coverage # Flag --coverage is a synonym for -fprofile-arcs -ftest-coverage (when compiling) and -lgcov (when linking) # See https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html#index-g_t_0040command_007bgcov_007d-938 add_compile_options( --coverage ) link_libraries( --coverage ) # Depending on presence of tools gcov/gcovr/lcov/genhtml => Add targets # HTML report: # - gcovr --root . --html --html-details --output coverage.html --exclude-unreachable-branches --print-summary # - lcov + genhtml find_program (gcov gcov) if (NOT gcov) message(WARNING " Cannot find gcov => Build may fail...") endif() find_program (gcovr gcovr) if (gcovr) message (STATUS " Found command 'gcovr' => Use target 'gcovr' to generate coverage report '${CMAKE_BINARY_DIR}/gcovr.html'") add_custom_target (gcovr COMMAND ${gcovr} --root ${CMAKE_SOURCE_DIR} --exclude ${CMAKE_SOURCE_DIR}/3rdparty --exclude ${CMAKE_BINARY_DIR} --object-directory ${CMAKE_BINARY_DIR} --output ${CMAKE_BINARY_DIR}/gcovr.html --html --html-details --sort-uncovered --print-summary --exclude-unreachable-branches COMMAND echo " To display coverage report: firefox ${CMAKE_BINARY_DIR}/gcovr.html" ) else() message(WARNING " Cannot find command 'gcovr' => Please install package 'gcovr' to generate code coverage report (HTML)") endif() find_program (lcov lcov ) find_program (genhtml genhtml) if (lcov AND genhtml) message (STATUS " Found commands 'lcov' and 'genhtml' => Use target 'lcov' to generate coverage report '${CMAKE_BINARY_DIR}/lcov/index.html'") add_custom_target (lcov COMMAND ${lcov} --capture --directory ${CMAKE_BINARY_DIR} --no-external --output-file ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}-all.info --no-checksum --base-directory ${CMAKE_SOURCE_DIR} --rc lcov_branch_coverage=1 --quiet COMMAND ${lcov} --remove ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}-all.info ${CMAKE_SOURCE_DIR}/*/test/* ${CMAKE_SOURCE_DIR}/*/*/test/* ${CMAKE_SOURCE_DIR}/*/*/*/test/* --rc lcov_branch_coverage=1 --output-file ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.info COMMAND ${genhtml} --rc genhtml_branch_coverage=1 ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.info --output-directory ${CMAKE_BINARY_DIR}/lcov --highlight --legend --quiet COMMAND echo " To display coverage report: firefox ${CMAKE_BINARY_DIR}/lcov/index.html" ) else() message(WARNING " Cannot find both commands 'lcov' and 'genhtml' => Please install package 'lcov' to generate code coverage report (HTML)") endif() tcpflow-tcpflow-1.6.1/cmake/options.cmake000066400000000000000000000056511401360461700204370ustar00rootroot00000000000000# Default options and popular parameters # --------- CMAKE_BUILD_TYPE ---------- # * Release = -O2 + disable assert (-DNDEBUG) # * Debug = -O0 + enable assert <-- Default value # * Coverage = -O0 + disable assert (-DNDEBUG) set(CMAKE_CONFIGURATION_TYPES Release Debug Coverage CACHE STRING "Reset the supported CMAKE_BUILD_TYPEs." FORCE) # Use "cmake -DCMAKE_BUILD_TYPE=Release" or "cmake -DCMAKE_BUILD_TYPE=Coverage" to override default value 'Debug' if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE) set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "Coverage") message(STATUS " CMAKE_BUILD_TYPE not set => Use default value '${CMAKE_BUILD_TYPE}'.") endif() # Use "cmake -DSANITIZE=address" to enable Address sanitizer # Use "cmake -DSANITIZE=thread" to enable Thread sanitizer # Use "cmake -DSANITIZE=memory" to enable Memory sanitizer # Use "cmake -DSANITIZE=dataflow" for DataFlowSanitizer # Use "cmake -DSANITIZE=cfi" for control flow integrity checks (requires -flto) # Use "cmake -DSANITIZE=safe-stack" for safe stack protection against stack-based memory corruption errors. # Use "cmake -DSANITIZE=multi" to combine some of them if(NOT SANITIZE) set(SANITIZE "OFF" CACHE STRING "Enable Address/Thread/Memory sanitizer.") set_property(CACHE SANITIZE PROPERTY STRINGS "OFF" "address" "thread" "memory" "dataflow" "cfi" "safe-stack" "multi") message(STATUS " SANITIZE not set (cmake -DSANITIZE=xxx) => Set default value SANITIZE='${SANITIZE}'") endif() #option(SANITIZE "Sanity check" OFF) # Use "cmake -DMARCH=native" to detect your current cpu-type 'xxx' and CMake will convert to -march=xxx # Use "cmake -DMARCH=zzzz" to set a specific flag -march=zzzz # Default is "-DMARCH=corei7" (fine on x86 architecture) # Use "cmake -DMARCH= " (empty value) to disable flag -march set(MARCH "corei7" CACHE STRING "Control flag -march") # Control flags -O0 -O1 -O2 -O3 -Ofast -Os -Og set(OPTIM "" CACHE STRING "Control flags -Ox") # For clang-check set(CMAKE_EXPORT_COMPILE_COMMANDS "on") # Colorize output: "always" or "auto" ("auto" colorizes if output is TTY) if (ENV{BUILD_COLOR}) option(BUILD_COLOR " Enable colored output for make and compiler" $ENV{BUILD_COLOR}) else() option(BUILD_COLOR " Enable colored output for make and compiler" always) endif() # Static code analysis # Below line is to generate the file 'compile_commands.json' during the build # Then, the file 'compile_commands.json' can be used with clang-check using the below command line: # awk -F: '/"file"/{print $2 }' build/compile_commands.json | xargs clang-check -fixit -p build set(CMAKE_EXPORT_COMPILE_COMMANDS "on") # For Tools like YouCompleteMe # TODO(???): Provide BuildConfig.json.in # configure_file(${CMAKE_CURRENT_LIST_DIR}/templates/BuildConfig.json.in ${CMAKE_CURRENT_BINARY_DIR}/BuildConfig.json) tcpflow-tcpflow-1.6.1/cmake/warning-flags.cmake000066400000000000000000000104151401360461700214750ustar00rootroot00000000000000# Warning flags and Macro (#define) # For the moment only support GCC and Clang if(NOT CMAKE_COMPILER_IS_GNUCXX AND NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang") message(STATUS " No warning set for your compiler '${CMAKE_CXX_COMPILER_ID}' (only GNU and Clang are supported for the moment)") return() endif() # See http://stackoverflow.com/a/16604146/938111 add_definitions(-D_FORTIFY_SOURCE=2) # Colorize output if (BUILD_COLOR) add_compile_options(-fdiagnostics-color=${BUILD_COLOR}) endif() # Clang specifics if (CMAKE_C_COMPILER_ID STREQUAL Clang) add_compile_options( -Weverything -Wno-c++98-compat -Wno-c++98-compat-pedantic ) endif() add_compile_options( -Wall # Classic warnings -Wextra # Extra amount of warnings -Weffc++ # Books "Effective C++" from Scott Meyers -pedantic # Reject code not following ISO C++ (e.g. GNU extensions) -Winit-self # Variables initialized with themselves (enabled by -Wall) -Wswitch-enum # Missing case for values of switch(enum) -Wswitch # Missing enumerated type in 'case' labels -Wcast-align # Incompatible alignment pointers -Wcast-qual # Cast between pointers leads to target type qualifier removal -Wconversion # Conversion might lead to value alteration, confusing overload resolution -Wsign-conversion -Wformat=2 # Invalid argument types and format strings in formatting functions (printf, scanf...) -Wuninitialized # Variable used without being initialized -Wmissing-field-initializers # Fields is left uninitialized during (non-designated) structure initialization -Wmissing-include-dirs # User-supplied include directory does not exist -Wpointer-arith # [void and function] Operations addition/subtraction/sizeof are GNU extension -Wredundant-decls # Multiple declarations of the same entity is encountered in the same scope -Wshadow # Variable/typedef/struct/class/enum shadows another one having same name -Wunreachable-code # Unreachable code -Wunused # Unused entity (functions, labels, variables, typedefs, parameters, ...) -Wwrite-strings # Deprecated conversion from string literals to 'char *' (enable by default in C++) -fmax-errors=50 # Limit number of errors to 50. Default is 0 => no limit -fstack-protector-strong # Checks for buffer overflows such as stack smashing attacks (extra code is added) -Wstack-protector # Warn if option '-fstack-protector-strong' complained about codes vulnerable to stack smashing -Wpointer-arith -Wshadow -Wwrite-strings -Wcast-align -Wredundant-decls -Wdisabled-optimization -Wfloat-equal -Wmultichar -Wmissing-noreturn -Woverloaded-virtual -Wsign-promo -funit-at-a-time -Weffc++ -Wall -Wpointer-arith -Wshadow -Wwrite-strings -Wcast-align -Wredundant-decls -Wdisabled-optimization -Wfloat-equal -Wmultichar -Wmissing-noreturn -Woverloaded-virtual -Wsign-promo -funit-at-a-time -Wstrict-null-sentinel -Wswitch-enum -Wpadded -Wfloat-conversion -Wunused-macros -Wshadow -Wmissing-prototypes ) # Temporary disable some warnings because too much warnings :-( add_compile_options( -Wno-sign-conversion # 1125 warnings (GCC-6) -Wno-padded # 650 warnings (GCC-6) -Wno-unused-parameter # 577 warnings (GCC-6) -Wno-pedantic # 326 warnings (GCC-6) -Wno-cast-qual # 211 warnings (GCC-6) -Wno-conversion # 123 warnings (GCC-6) -Wno-switch-enum # 111 warnings (GCC-6) -Wno-old-style-cast # 1679 warnings (Clang-3.9) -Wno-extra-semi # 490 warnings (Clang-3.9) -Wno-weak-vtables # 325 warnings (Clang-3.9) -Wno-packed # 304 warnings (Clang-3.9) -Wno-documentation # 187 warnings (Clang-3.9) -Wno-reserved-id-macro # 138 warnings (Clang-3.9) -Wno-deprecated # 123 warnings (Clang-3.9) ) tcpflow-tcpflow-1.6.1/compile000077500000000000000000000162451401360461700162410ustar00rootroot00000000000000#! /bin/sh # Wrapper for compilers which do not understand '-c -o'. scriptversion=2012-10-14.11; # UTC # Copyright (C) 1999-2013 Free Software Foundation, Inc. # Written by Tom Tromey . # # 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, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . nl=' ' # We need space, tab and new line, in precisely that order. Quoting is # there to prevent tools from complaining about whitespace usage. IFS=" "" $nl" file_conv= # func_file_conv build_file lazy # Convert a $build file to $host form and store it in $file # Currently only supports Windows hosts. If the determined conversion # type is listed in (the comma separated) LAZY, no conversion will # take place. func_file_conv () { file=$1 case $file in / | /[!/]*) # absolute file, and not a UNC file if test -z "$file_conv"; then # lazily determine how to convert abs files case `uname -s` in MINGW*) file_conv=mingw ;; CYGWIN*) file_conv=cygwin ;; *) file_conv=wine ;; esac fi case $file_conv/,$2, in *,$file_conv,*) ;; mingw/*) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; cygwin/*) file=`cygpath -m "$file" || echo "$file"` ;; wine/*) file=`winepath -w "$file" || echo "$file"` ;; esac ;; esac } # func_cl_dashL linkdir # Make cl look for libraries in LINKDIR func_cl_dashL () { func_file_conv "$1" if test -z "$lib_path"; then lib_path=$file else lib_path="$lib_path;$file" fi linker_opts="$linker_opts -LIBPATH:$file" } # func_cl_dashl library # Do a library search-path lookup for cl func_cl_dashl () { lib=$1 found=no save_IFS=$IFS IFS=';' for dir in $lib_path $LIB do IFS=$save_IFS if $shared && test -f "$dir/$lib.dll.lib"; then found=yes lib=$dir/$lib.dll.lib break fi if test -f "$dir/$lib.lib"; then found=yes lib=$dir/$lib.lib break fi if test -f "$dir/lib$lib.a"; then found=yes lib=$dir/lib$lib.a break fi done IFS=$save_IFS if test "$found" != yes; then lib=$lib.lib fi } # func_cl_wrapper cl arg... # Adjust compile command to suit cl func_cl_wrapper () { # Assume a capable shell lib_path= shared=: linker_opts= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. eat=1 case $2 in *.o | *.[oO][bB][jJ]) func_file_conv "$2" set x "$@" -Fo"$file" shift ;; *) func_file_conv "$2" set x "$@" -Fe"$file" shift ;; esac ;; -I) eat=1 func_file_conv "$2" mingw set x "$@" -I"$file" shift ;; -I*) func_file_conv "${1#-I}" mingw set x "$@" -I"$file" shift ;; -l) eat=1 func_cl_dashl "$2" set x "$@" "$lib" shift ;; -l*) func_cl_dashl "${1#-l}" set x "$@" "$lib" shift ;; -L) eat=1 func_cl_dashL "$2" ;; -L*) func_cl_dashL "${1#-L}" ;; -static) shared=false ;; -Wl,*) arg=${1#-Wl,} save_ifs="$IFS"; IFS=',' for flag in $arg; do IFS="$save_ifs" linker_opts="$linker_opts $flag" done IFS="$save_ifs" ;; -Xlinker) eat=1 linker_opts="$linker_opts $2" ;; -*) set x "$@" "$1" shift ;; *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) func_file_conv "$1" set x "$@" -Tp"$file" shift ;; *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) func_file_conv "$1" mingw set x "$@" "$file" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -n "$linker_opts"; then linker_opts="-link$linker_opts" fi exec "$@" $linker_opts exit 1 } eat= case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: compile [--help] [--version] PROGRAM [ARGS] Wrapper for compilers which do not understand '-c -o'. Remove '-o dest.o' from ARGS, run PROGRAM with the remaining arguments, and rename the output as expected. If you are trying to build a whole package this is not the right script to run: please start by reading the file 'INSTALL'. Report bugs to . EOF exit $? ;; -v | --v*) echo "compile $scriptversion" exit $? ;; cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) func_cl_wrapper "$@" # Doesn't return... ;; esac ofile= cfile= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. # So we strip '-o arg' only if arg is an object. eat=1 case $2 in *.o | *.obj) ofile=$2 ;; *) set x "$@" -o "$2" shift ;; esac ;; *.c) cfile=$1 set x "$@" "$1" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -z "$ofile" || test -z "$cfile"; then # If no '-o' option was seen then we might have been invoked from a # pattern rule where we don't need one. That is ok -- this is a # normal compilation that the losing compiler can handle. If no # '.c' file was seen then we are probably linking. That is also # ok. exec "$@" fi # Name of file we expect compiler to create. cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` # Create the lock directory. # Note: use '[/\\:.-]' here to ensure that we don't use the same name # that we are using for the .o file. Also, base the name on the expected # object file name, since that is what matters with a parallel build. lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d while true; do if mkdir "$lockdir" >/dev/null 2>&1; then break fi sleep 1 done # FIXME: race condition here if user kills between mkdir and trap. trap "rmdir '$lockdir'; exit 1" 1 2 15 # Run the compile. "$@" ret=$? if test -f "$cofile"; then test "$cofile" = "$ofile" || mv "$cofile" "$ofile" elif test -f "${cofile}bj"; then test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" fi rmdir "$lockdir" exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: tcpflow-tcpflow-1.6.1/configure.ac000066400000000000000000000416721401360461700171530ustar00rootroot00000000000000# -*- Autoconf -*- # tcpflow configure.ac # # Process this file with autoconf to produce a configure script. # Order is largely irrevellant, although it must start with AC_INIT and end with AC_OUTPUT # See http://autotoolset.sourceforge.net/tutorial.html # and http://www.openismus.com/documents/linux/automake/automake.shtml AC_PREREQ(2.57) AC_INIT(TCPFLOW, 1.6.1, simsong@acm.org) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_FILES([Makefile src/Makefile tests/Makefile doc/Makefile]) AC_CONFIG_FILES([doc/tcpflow.1]) AC_CONFIG_FILES([tcpflow.spec]) AC_CONFIG_HEADER([config.h]) # https://stackoverflow.com/questions/15013672/use-autotools-with-readme-md AM_INIT_AUTOMAKE([foreign]) AM_MAINTAINER_MODE AC_PREFIX_PROGRAM(tcpflow) dnl build for same location # Endian check is required for MD5 implementation AC_C_BIGENDIAN # Programs we will be using AC_PROG_CC AC_PROG_CXX AM_PROG_CC_C_O dnl allow per-product flags AC_PROG_INSTALL m4_include([m4/slg_searchdirs.m4]) m4_include([m4/slg_gcc_all_warnings.m4]) # Must use C++17 mode. (mandatory) AC_LANG_PUSH(C++) AX_CXX_COMPILE_STDCXX([17], [noext], [mandatory]) AC_LANG_POP() ################################################################ ## See if we are running on mingw # http://osdir.com/ml/gnu.mingw.devel/2003-09/msg00040.html # Note: Windows 95 WINVER=0x400 # Windows 98 WINVER=0x400 _WIN32_WINDOWS=0x0410 # Windows Me WINVER=0x400 _WIN32_WINDOWS=0x0490 # Windows NT 4.0 WINVER=0x0400 _WIN32_WINNT=0x0400 # Windows NT 4.0 SP3 WINVER=0x0400 _WIN32_WINNT=0x0403 # Windows 2000 WINVER=0x500 _WIN32_WINNT=0x0500 # Windows XP WINVER=0x501 _WIN32_WINNT=0x0501 # Windows Server 2003 WINVER=0x502 _WIN32_WINNT=0x0502 # # mingw32 includes i686-w64-mingw32 and x86_64-w64-mingw32 mingw="no" case $host in *-*-*linux*-*) AC_DEFINE([__LINUX__],1,[Linux operating system functions]) ;; *-*-mingw32*) LIBS="-lpsapi -lws2_32 -lgdi32 $LIBS" CPPFLAGS="-DUNICODE -D_UNICODE -D__MSVCRT_VERSION__=0x0601 -DWINVER=0x0500 -D_WIN32_WINNT=0x0500 -g $CPPFLAGS" CPPFLAGS="$CPPFLAGS --static" CFLAGS="$CFLAGS --static -static-libgcc -static-libstdc++" CXXFLAGS="$CXXFLAGS -Wno-format " # compiler mingw-4.3.0 is broken on I64u formats CXXFLAGS="$CXXFLAGS --static -static-libgcc -static-libstdc++" LDFLAGS="$LDFLAGS --static" mingw="yes" ;; *) CXXFLAGS="$CXXFLAGS -Wno-address-of-packed-member" ;; esac if test x"${mingw}" == "xno" ; then # Bring additional directories where things might be found into our # search path. I don't know why autoconf doesn't do this by default for spfx in /usr/local /opt/local /sw /usr/local/ssl /usr/boost/include ; do AC_MSG_NOTICE([checking ${spfx}/include]) if test -d ${spfx}/include; then CPPFLAGS="-I${spfx}/include $CPPFLAGS" LDFLAGS="-L${spfx}/lib $LDFLAGS" AC_MSG_NOTICE([ *** ADDING ${spfx}/include to CPPFLAGS *** ]) AC_MSG_NOTICE([ *** ADDING ${spfx}/lib to LDFLAGS *** ]) fi done AC_MSG_NOTICE([ CPPFLAGS = ${CPPFLAGS} ]) AC_MSG_NOTICE([ LDFLAGS = ${LDFLAGS} ]) fi if test -r /bin/uname.exe ; then if test "`uname -o`" == "Msys" ; then AC_MSG_NOTICE([Compiling with Msys. Setting flags appropriately.]) LIBS="$LIBS -lws2_32 -lgdi32" LDFLAGS="$LDFLAGS -Wl,--enable-auto-import" fi fi ################################################################ # # Enable all the compiler debugging we can find # # This is originally from PhotoRec, but modified substantially by Simson # Figure out which flags we can use with the compiler. # # These I don't like: # -Wdeclaration-after-statement -Wconversion # doesn't work: -Wunreachable-code # causes configure to crash on gcc-4.2.1: -Wsign-compare-Winline # causes warnings with unistd.h: -Wnested-externs # Just causes too much annoyance: -Wmissing-format-attribute # Check GCC WARNINGS_TO_TEST="-MD -D_FORTIFY_SOURCE=2 -Wpointer-arith -Wmissing-declarations -Wmissing-prototypes \ -Wshadow -Wwrite-strings -Wcast-align -Waggregate-return \ -Wbad-function-cast -Wcast-qual -Wundef -Wredundant-decls -Wdisabled-optimization \ -Wfloat-equal -Wmultichar -Wc++-compat -Wmissing-noreturn " if test $mingw = "no" ; then # add the warnings we do not want to do on mingw WARNINGS_TO_TEST="$WARNINGS_TO_TEST -Wall -Wstrict-prototypes" fi echo "Warnings to test: $WARNINGS_TO_TEST" for option in $WARNINGS_TO_TEST do SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $option" AC_MSG_CHECKING([whether gcc understands $option]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], [has_option=yes], [has_option=no; CFLAGS="$SAVE_CFLAGS"]) AC_MSG_RESULT($has_option) unset has_option unset SAVE_CFLAGS if test $option = "-Wmissing-format-attribute" ; then AC_DEFINE(HAVE_MISSING_FORMAT_ATTRIBUTE_WARNING,1, [Indicates that we have the -Wmissing-format-attribute G++ warning]) fi done unset option # CUT1 ################################################################ ## # # ZLIB is required for decompressing # Note you cannot put comments in the AC_MSG_ERROR for some reason AC_CHECK_LIB([z],[uncompress],, AC_MSG_ERROR([zlib libraries not installed; try installing zlib-dev zlib-devel zlib1g-dev or libz-dev])) AC_CHECK_HEADERS([zlib.h]) ################################################################ ## regex support ## there are several options ## tre is better than regex AC_CHECK_HEADER([lightgrep/api.h]) AC_CHECK_LIB([lightgrep], [lg_create_pattern]) AC_CHECK_HEADERS([regex.h tre/tre.h]) AC_CHECK_LIB([regex],[regcomp]) AC_CHECK_LIB([tre],[tre_regcomp]) AC_CHECK_FUNCS([regcomp tre_regcomp tre_version]) ################################################################ ## OpenSSL Support (required for hash_t ) AC_CHECK_HEADERS([openssl/aes.h openssl/bio.h openssl/evp.h openssl/hmac.h openssl/md5.h openssl/pem.h openssl/rand.h openssl/rsa.h openssl/sha.h openssl/pem.h openssl/x509.h]) AC_CHECK_LIB([dl],[dlopen]) dnl apparently OpenSSL now needs -ldl on some Linux AC_CHECK_LIB([crypto],[EVP_get_digestbyname]) # if crypto is available, get it AC_CHECK_LIB([md],[MD5]) # if libmd is available, get it # Need either SSL_library_init or OPENSSL_init_ssl, depending on openssl version AC_CHECK_LIB([ssl],[SSL_library_init],, AC_CHECK_LIB([ssl],[OPENSSL_init_ssl],, AC_MSG_ERROR([OpenSSL developer library 'libssl-dev' or 'openssl-devel' not installed]))) AC_CHECK_FUNCS([MD5_Init EVP_get_digestbyname]) ################################################################ ## Includes m4_include([src/be13_api/be13_configure.m4]) m4_include([src/be13_api/dfxml/src/dfxml_configure.m4]) ################################################################ # Boost AC_CHECK_HEADERS([boost/version.hpp],, AC_MSG_WARN([tcpflow now requires boost interval_map and interval_set.]) if test x"$mingw" = x"yes" ; then AC_MSG_ERROR([Please install mingw32-boost and mingw64-boost]) else AC_MSG_ERROR([Please install boost-devel or libboost-dev.]) fi ) # Now make sure we have the correct boost version AC_LANG_PUSH(C++) have_interval=yes AC_CHECK_HEADERS([boost/icl/interval.hpp boost/icl/interval_map.hpp boost/icl/interval_set.hpp],,have_interval=no) if test "${have_interval}" != yes ; then AC_MSG_ERROR([ tcpflow requires a version of Boost that has Boost interval_map and interval_set. Your version is too old! Please install a current version of Boost from http://www.boost.org/users/download/. Try these commands: wget http://downloads.sourceforge.net/project/boost/boost/1.53.0/boost_1_53_0.tar.gz?r=http%3A%2F%2Fsourceforge.net%2Fprojects%2Fboost%2Ffiles%2Fboost%2F1.53.0%2F&ts=1362359340&use_mirror=hivelocity tar xfz boost_1_53_0.tar.gz cd boost_1_53_0 sh bootstrap.sh ./b2 sudo ./b2 install ... and then re-run configure! ]) fi AC_LANG_POP() ################################################################ # drawing support via cairo # cairo=test AC_ARG_ENABLE([cairo],[ --enable-cairo=false to disable libcairo even if present]) if test "${enable_cairo}" = false ; then cairo=false fi if test $cairo = test ; then # Cairo requires these to be explicitly included on mingw (and perhaps others): AC_CHECK_LIB([expat],[XML_ParserCreate]) AC_CHECK_LIB([pixman-1],[pixman_region_init]) AC_CHECK_LIB([bz2],[BZ2_bzDecompress]) AC_CHECK_LIB([freetype],[FT_Init_FreeType]) # requires bz2 AC_CHECK_LIB([fontconfig],[FcBlanksCreate]) # requires freetype expat AC_CHECK_HEADERS([cairo/cairo.h cairo/cairo-pdf.h]) AC_CHECK_HEADERS([cairo.h cairo-pdf.h]) AC_CHECK_LIB([cairo],[cairo_create], , [ AC_MSG_WARN([ *** cairo libraries not detected. *** Please install cairo-devel to get 1-page PDF summary generation. ]) Fmissing_library="$Fmissing_library cairo-devel " Umissing_library="$Umissing_library libcairo2-dev " Mmissing_library="$Mmissing_library cairo-devel " ]) fi ################################################################ # pcap support. A bit more involved than normal due to the error message # AC_CHECK_HEADERS(pcap.h pcap/pcap.h ) if test x"$mingw" = x"yes" ; then AC_MSG_WARN([pcap not supported under mingw]) else AC_CHECK_LIB(pcap, pcap_lookupdev, , [ enable_pcap=no AC_MSG_WARN([ Can't find the pcap library (libpcap.a). tcpflow will not live capture or compile rules without pcap! If you need rules or live capture, you must install the pcap and/or pcap-dev library. Please execute this command: UBUNTU: sudo apt-get install libpcap-dev DEBIAN: sudo apt-get install libpcap-dev FEDORA: sudo dnf install libpcap-devel MINGW: Sorry! libpcap is not currently available when cross-compiling. If your libpcap is installed in a non-standard location, you will need to use the --with-pcap=directory to specify where your pcap is located.]) Fmissing_library="$Fmissing_library libpcap-dev " Umissing_library="$Umissing_library libpcap-dev " Mmissing_library="$Mmissing_library libpcap " ]) fi AC_CHECK_FUNCS([pcap_findalldevs]) dnl set with_wifi to 0 if you do not want it AC_ARG_ENABLE([wifi], AS_HELP_STRING([--disable-wifi], [Disable WIFI decoding]), [], [ if test x"no" = x"$mingw"; then AC_DEFINE(USE_WIFI, 1, [Use WIFI decompression]) wifi="yes" fi ]) AM_CONDITIONAL([WIFI_ENABLED], [test "yes" = "$wifi"]) ################################################################ # # LIBCAP_NG # Check for libcap-ng AC_MSG_CHECKING(whether to use libcap-ng) # Specify location for both includes and libraries. want_libcap_ng=ifavailable AC_ARG_WITH(cap_ng, AS_HELP_STRING([--with-cap-ng], [use libcap-ng @<:@default=yes, if available@:>@]), [ if test $withval = no then want_libcap_ng=no AC_MSG_RESULT(no) elif test $withval = yes then want_libcap_ng=yes AC_MSG_RESULT(yes) fi ],[ # # Use libcap-ng if it's present, otherwise don't. # want_libcap_ng=ifavailable AC_MSG_RESULT([yes, if available]) ]) if test "$want_libcap_ng" != "no"; then # # note: it really is cap-ng.h, and not cap_ng.h # AC_CHECK_LIB(cap-ng, capng_change_id) AC_CHECK_HEADERS(cap-ng.h) fi ################################################################ # Specify our other headers AC_HEADER_STDC AC_CHECK_HEADERS([\ arpa/inet.h \ ctype.h \ fcntl.h \ grp.h \ inttypes.h \ linux/if_ether.h \ net/ethernet.h \ netinet/in.h \ netinet/in_systm.h \ netinet/tcp.h \ regex.h \ semaphore.h \ signal.h \ string.h \ strings.h \ stdio.h \ stdlib.h \ string.h \ syslog.h \ sys/cdefs.h \ sys/mman.h \ sys/param.h \ sys/resource.h \ sys/socket.h \ sys/types.h \ sys/bitypes.h \ sys/wait.h \ unistd.h \ ]) AC_CHECK_FUNCS([getdtablesize]) # # These all require additional headers. See: # http://www.gnu.org/software/autoconf/manual/autoconf-2.67/html_node/Present-But-Cannot-Be-Compiled.html # AC_CHECK_HEADERS([net/if_var.h], [], [], [[ #include #include #include ]]) AC_CHECK_HEADERS([net/if.h], [], [], [[ #ifdef HAVE_SYS_TYPES_H #include #endif #if HAVE_NET_IF_VAR_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif ]]) AC_CHECK_HEADERS([netinet/ip_var.h], [], [], [[ #ifdef HAVE_SYS_TYPES_H #include #endif #if HAVE_NETINET_IN_H #include #endif ]]) AC_CHECK_HEADERS([netinet/ip.h], [], [], [[ #ifdef HAVE_SYS_TYPES_H #include #endif #if HAVE_NETINET_IN_H #include #endif ]]) AC_CHECK_HEADERS([netinet/ip_ether.h], [], [], [[ #ifdef HAVE_SYS_TYPES_H #include #endif #if HAVE_NETINET_IN_H #include #endif ]]) AC_CHECK_HEADERS([netinet/tcpip.h], [], [], [[ #ifdef HAVE_SYS_TYPES_H #include #endif #if HAVE_NETINET_IN_H #include #endif #if HAVE_NETINET_IP_VAR_H #include #endif #if HAVE_NETINET_TCP_H #include #endif ]]) AC_CHECK_FUNCS([inet_ntop sigaction sigset strnstr setuid setgid mmap futimes futimens ]) AC_CHECK_TYPES([socklen_t], [], [], [[ #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETINET_TCP_H #include #endif ]] ) AC_CHECK_TYPES([sa_family_t], [], [], [[ #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_SYS_SOCKET_H #include #endif #ifdef HAVE_NETINET_TCP_H #include #endif ]] ) ################################################################ # Plugin scan_python.cpp requires header "Python.h" # If the header is not present => Disable the source code of the plugin # AC_CHECK_HEADERS(python2.7/Python.h) # ==> #define HAVE_PYTHON2_7_PYTHON_H AC_CHECK_LIB(python2.7,Py_Initialize,,[ AC_MSG_WARN([ *** Cannot find python library. *** Please install python-devel to enable scanner python. ]) Fmissing_library="$Fmissing_library python-devel " # Validated on Fedora 25 Umissing_library="$Umissing_library libpython2.7-dev" # Should be OK: https://packages.ubuntu.com/yakkety/libpython2.7-dev Mmissing_library="$Mmissing_library python27" # Not sure: https://github.com/macports/macports-ports/blob/master/lang/python27/Portfile ]) ################################################################ # Plugin scanner_python.cpp requires header "Python.h" # If the header is not present => Disable the source code of the plugin # AC_CHECK_HEADERS(python2.7/Python.h) # ==> #define HAVE_PYTHON2_7_PYTHON_H AC_CHECK_LIB(python2.7,Py_Initialize,,[ AC_MSG_WARN([ *** Cannot find python library. *** Please install python-devel to enable scanner python. ]) Fmissing_library="$Fmissing_library python-devel " # Validated on Fedora 25 Umissing_library="$Umissing_library libpython2.7-dev" # Should be OK: https://packages.ubuntu.com/yakkety/libpython2.7-dev Mmissing_library="$Mmissing_library python27" # Not sure: https://github.com/macports/macports-ports/blob/master/lang/python27/Portfile ]) ############## drop optimization flags if requested ################ # Should we disable optimization? AC_ARG_WITH([opt], AC_HELP_STRING([--without-opt], [Drop all -O C flags])) # Or maybe just tone it down a bit? AC_ARG_WITH([o3], AC_HELP_STRING([--without-o3], [Do not force O3 optimization; use default level])) if test x"${AFF_NOOPT}" != "x" ; then AC_MSG_NOTICE([Dropping optimization flags because AFF_NOOPT is set.]) with_opt="no"; fi if test "${with_opt}" = "no" ; then AC_MSG_NOTICE([Dropping optimization flags]) CFLAGS=`echo "$CFLAGS" | sed s/-O[[0-9]]//` # note the double quoting! CXXFLAGS=`echo "$CXXFLAGS" | sed s/-O[[0-9]]//` AC_MSG_NOTICE([Removing -D_FORTIFY_SOURCE=2]) CPPFLAGS=`echo $CPPFLAGS | sed s/-D_FORTIFY_SOURCE=2//` CXXFLAGS=`echo $CXXFLAGS | sed s/-D_FORTIFY_SOURCE=2//` CFLAGS=`echo $CFLAGS | sed s/-D_FORTIFY_SOURCE=2//` else # and increase optimizer from -O2 to -O3 if not explicitly forbidden if test "${with_o3}" != "no" ; then CFLAGS=`echo -g "$CFLAGS" | sed s/-O2/-O3/` # note the double quoting! CXXFLAGS=`echo -g "$CXXFLAGS" | sed s/-O2/-O3/` fi fi AC_OUTPUT ## Finally, record the values of CFLAGS, CPPFLAGS, and CXXFLAGS for DFXML echo "#define CPPFLAGS \"$CPPFLAGS\"" >> config.h echo "#define CFLAGS \"$CFLAGS\"" >> config.h echo "#define CXXFLAGS \"$CXXFLAGS\"" >> config.h echo "#define LIBS \"$LIBS\"" >> config.h echo "#define LDFLAGS \"$LDFLAGS\"" >> config.h if test x"$GIT_COMMIT" != "x" ; then echo "#define GIT_COMMIT \"$GIT_COMMIT\"" >> config.h fi if test "x${Fmissing_library}" != "x" ; then AC_MSG_NOTICE([*** You have missing libraries. To install them:]) AC_MSG_NOTICE([*** Red Hat: sudo yum install $Fmissing_library]) AC_MSG_NOTICE([*** Fedora: sudo dnf install $Fmissing_library]) AC_MSG_NOTICE([*** Ubuntu: sudo apt-get install $Umissing_library]) AC_MSG_NOTICE([*** MacOS: sudo port install $Mmissing_library]) fi tcpflow-tcpflow-1.6.1/doc/000077500000000000000000000000001401360461700154205ustar00rootroot00000000000000tcpflow-tcpflow-1.6.1/doc/Makefile.am000066400000000000000000000000541401360461700174530ustar00rootroot00000000000000man_MANS = tcpflow.1 CLEANFILES = tcpflow.1 tcpflow-tcpflow-1.6.1/doc/Planning-1page.txt000066400000000000000000000061111401360461700207210ustar00rootroot00000000000000[mockup of 1 page report] tcpflow input: Date range: ISO-8601 to ISO-8601 Packets Analyzed: COUNT (XXX MB) Protocols: IPv4 (%); IPv6 (%); ARP (%); Other (?) +-------------------------------------------------------------+ | | | | | Bandwidth Histogram | | | +-------------------------------------------------------------+ +-------------------------------------------------------------+ | | | | | MAP | | | +-------------------------------------------------------------+ +-----------------------+ +-----------------------+ | | | | | | | | | | | | | Top Server IPs | -> | Top Client IPs | | | | | | | | | +-----------------------+ +-----------------------+ Top #1: IP (%) Top #1: IP (%) Top #2: IP (%) Top #2: IP (%) Top #3: IP (%) Top #3: IP (%) +-----------------------+ +-----------------------+ | | | | | | | | | | | | | Top Server Ports | -> | Top Client Ports | | | | | | | | | +-----------------------+ +-----------------------+ Top #1: Port (%) Top #1: Port (%) Top #2: Port (%) Top #2: Port (%) Top #3: Port (%) Top #3: Port (%) +-----------------------+ +-----------------------+ | | | | | | | | | | | | | | | Observed Downloaded | | | | Types | | | | | +-----------------------+ +-----------------------+ ==== Notes: 1 - DNS Resolution: 1.1 - IP addresses only. 1.2 - Passive DNS 1.3 - Passive DNS augmented by a list of DNS records (in PCAP format) 1.4 - Generate a list of IP addresses requiring resolution tcpflow-tcpflow-1.6.1/doc/announce_1_3.txt000066400000000000000000000006171401360461700204350ustar00rootroot00000000000000I'm pleased to announce the release of tcpflow version 1.3.0. Key elements in 1.3.0 include: - Compiles with mingw32 and mingw64 for 32-bit and 64-bit windows. I am now distributing pre-compiled binaries of some releases. - Better support for DFXML (fixed some bugs) You can download version 1.3.0, both source and precompiled windows binaries, from: https://github.com/simsong/tcpflow/downloads tcpflow-tcpflow-1.6.1/doc/announce_1_4.txt000066400000000000000000000072521401360461700204400ustar00rootroot00000000000000I'm pleased to announce the release of tcpflow version 1.4.0. Key elements in 1.4.0 include: Completely rewritten TCP implementation that: * Handles TCP flows larger than 4GiB * Handles TCP packets sent after a connection is closed. Such packets are compared with the packets from the connection that were already received. If the packets match, they are discarded as retransmissions. If they do not match they are put in new transcript files. Incompatiable Changes: * -e (alternate colors of console output) has been renamed -J so that -e and -E can be used in a manner consistent with bulk_extractor Completely rewritten HTTP parser * Handles multiple HTTP objects per connections * Optional http_cmd will run a program or script for each HTTP attachment received as received. For example, to run the program /bin/echo and provide the filename of the attachment for each attachment, specify: tcpflow -Shttp_cmd=/bin/echo ... * Optional timeout on tcp connections, causes processing of HTTP objects before the HTTP connection closes: -Stcp_timeout=10 * Optional alert file descriptor causes http parser to alert as files are opened and closed by the HTTP parser. e.g.: $ ./tcpflow -o out -a -E http -S http_alert_fd=1 -r ../tests/multifile_25_21.pcap open out/038.122.002.045.00080-192.168.123.101.04634-HTTPBODY-001.png close out/038.122.002.045.00080-192.168.123.101.04634-HTTPBODY-001.png open out/038.122.002.045.00080-192.168.123.101.04637-HTTPBODY-001.png close out/038.122.002.045.00080-192.168.123.101.04637-HTTPBODY-001.png open out/038.122.002.045.00080-192.168.123.101.04637-HTTPBODY-002.png close out/038.122.002.045.00080-192.168.123.101.04637-HTTPBODY-002.png open out/038.122.002.045.00080-192.168.123.101.04648-HTTPBODY-001.png close out/038.122.002.045.00080-192.168.123.101.04648-HTTPBODY-001.png open out/038.122.002.045.00080-192.168.123.101.04649-HTTPBODY-001.png close out/038.122.002.045.00080-192.168.123.101.04649-HTTPBODY-001.png open out/038.122.002.045.00080-192.168.123.101.04654-HTTPBODY-001 close out/038.122.002.045.00080-192.168.123.101.04654-HTTPBODY-001 open out/038.122.002.045.00080-192.168.123.101.04655-HTTPBODY-001 close out/038.122.002.045.00080-192.168.123.101.04655-HTTPBODY-001 open out/038.122.002.045.00080-192.168.123.101.04655-HTTPBODY-002 close out/038.122.002.045.00080-192.168.123.101.04655-HTTPBODY-002 ... New Scalability features: * Automatically creates new directories as necessary for output filenames that include forward slashes ("/"). * -Fk option automatically bins up to a thousand flows in a thousand directories in one directory layer, easily handling up to million flows. * -Fm option automatically bins up to a thousand flows in a million directories (two directory layers), easily handling up to billion flows. * -Fg option automatically bins up to a thousand flows in a billion directories (three directory layers), easily handling up to trillion flows. Additional features: * Produces a one-page visualization (report.pdf) of the packets that were analyzed. * New -w option writes a PCAP file of packets not processed by tcpflow. * Better support for decoding and decompressing HTTP objects, including multiple objects sent over a single HTTP stream. * Full support for the bulk_extractor plug-in system You can download version 1.4.0, both source and precompiled windows binaries, from: https://github.com/simsong/tcpflow/downloads (what we didn't get to) The following is scheduled for release 1.5: * Full handling of radiotap files * Passive DNS implementation * top-100 connection map tcpflow-tcpflow-1.6.1/doc/announce_1_5.txt000066400000000000000000000021261401360461700204340ustar00rootroot00000000000000I'm pleased to announce the release of tcpflow version 1.5.0. This version was going to be called version 1.4.7, but so much has changed that it seemed like a good time to bump the minor version number. It's more than just a bug-fix release! Changes from 1.4.6: * We now pin to simsong/http-parser rather than nodejs/http-parser, so that we have more control over http-parser's .gitignore file. * support for cmake. (May not be current, but it's there for you cmake fans!) * CONFIGURE_FEDORA_26.sh script installs all needed Fedora 26 packages. * CONFIGURE_UBUNTU_16_04.sh script installs all needed Ubuntu 16.04 packages * CONFIGURE_ARCH_17_8.sh installs all needed Arch Linux 17.8 packages! Yes, we now support Arch! * getopt_long() support. Now you can go to town and create long-versions of all your favorite, one-character tcpflow options (provided you know C++, of course. Please submit pull requests!) * tcpflow man page updated * There's a Python post-processor option as well. * chroot() and drop root, allowing better control of privledge. * Support for libcap (capability library). tcpflow-tcpflow-1.6.1/doc/make_web.sh000066400000000000000000000014611401360461700175300ustar00rootroot00000000000000#!/bin/bash # # Create the files for the tcpflow website CORP=/corp/ DEST=/var/www/digitalcorpora/tcpflow/demo TCPFLOW=../src/tcpflow TMP=/tmp/out$$ if [ ! -d $DEST ]; then mkdir -p $DEST ; fi if [ ! -x $TCPFLOW ]; then (cd .. ; make ) ; fi run() { DPDF=$DEST/$2 DPNG=${DPDF%pdf}png echo DPDF=$DPDF echo DPNG=$DPNG echo $TCPFLOW -o $TMP -x tcpdemux -E netviz $1 $TCPFLOW -o $TMP -x tcpdemux -E netviz $1 if [ ! -r $TMP/report.pdf ]; then echo tcpflow failed exit 1 fi mv $TMP/report.pdf $DPDF /bin/rm -rf $TMP convert -scale 300 $DPDF $DPNG ls -l $DPDF $DPNG } run "-r $CORP/nps/packets/2008-nitroba/nitroba.pcap" nitroba.pdf run "-l $CORP/nps/packets/2009-m57-patents/net-2009*.gz" m57-net.pdf run "-l $CORP/mitll/packets/ideval99/week?/*/outside*gz" id99-outside.pdf tcpflow-tcpflow-1.6.1/doc/tcpflow-logo.pdf000066400000000000000000004457651401360461700205540ustar00rootroot00000000000000%PDF-1.3 % 4 0 obj << /Length 5 0 R /Filter /FlateDecode >> stream xAO wl -݄ă`Hi]jiAH`^#x RZ<~&/Slbش}z(3+:cq5?;Sh?_{Lo^SFav(! ()ɺ6T&΍RZmTx@=1wÿ'\&;Gv ljV Șgd]CI?9^8/3c, endstream endobj 5 0 obj 253 endobj 2 0 obj << /Type /Page /Parent 3 0 R /Resources 6 0 R /Contents 4 0 R /MediaBox [0 0 122 110] /CropBox [0 3.090372 122 110] /BleedBox [0 0 122 110] /TrimBox [0 0 122 110] /ArtBox [0 0 122 110] >> endobj 6 0 obj << /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /ColorSpace << /Cs1 7 0 R >> /ExtGState << /Gs1 12 0 R >> /Font << /TT2 11 0 R /TT1 10 0 R >> /XObject << /Im1 8 0 R >> >> endobj 8 0 obj << /Length 9 0 R /Type /XObject /Subtype /Image /Width 794 /Height 567 /Interpolate true /ColorSpace 13 0 R /Intent /Perceptual /SMask 14 0 R /BitsPerComponent 8 /Filter /FlateDecode >> stream xydurlX&iR2EKHV!/RdHvڊ"PȌ?[&1f0 @FPztR{U;wUՃaOq';*Ys <"%'VzD8>8h4;ǣH/x!   -%W*7slBҿH$Z+P'yM$@$@$@$0:͖;P*X|T"1I nP!   *(TۥZV]T33Y,lJJ'?$   &E3j=UZޮzh4BD7ոIHHH`@49)7 AUQ)z(i6*fS! 8D2W)6j%KB+f5PA\[ɍHHHH@ ] aT5WrV-6 P]~DG$@$@$@H R2= Ӥ@:ɲ JWL{F!JDh¿p7r   2aGY+_(MP=H*nW;Z >g&!.%o2epIHHH)!O!Q)Oex BUlN7|B+HHH` H3$ndR7Yb_7lSzaNքzOb|$@$@$@L@l _B)%6FiUPaB*T] :"Cѧ ; hT$VLk)T:hv1 L=#Q$.e sQGeP|WT}%P(bk*wp Tu. 𾘙[ehE k !`ic Q7׫X9o.ӹU_ʢu[wV <rgx8a'C*HOdS HJ-~G"  |Ə,oNIe[b[y*y֦2.lMeDcQMMˍHHɋ3YqLȭ;[;&B*,^*Ӌ^jcv3zoSFȦPx SFO:JXHHHDq4Kd^+>M}Mīj^g|$@$@$pt M;kkm zu.In*6cB v?Gz}5 4Ja`Atf։\ڼ޺voױ>=l Ћh$^tJHUĦS:*g͘2'ݞ@4PB$@$@$@G@̉&fg0T~}ͽ޺ nط#2c{1{epyvwuqm[[2xJt^5f%mDϵCe6upfkJ{Q3:l#}@sDc:{K$@$@$0%4(ӇlNx}|7 W+oWPJM76u'%BTU)=yM3J)C@ {XB5%O& @ę=.03&ȱfǜ{k!w~ԥ&//JmE76^tdS*f(:sl*hQ Pk6mk<$gOf^B$@$@$@O&h"~\ j88_/\/]p\\XcC;IEHPh!EOcT[d#TբIOiDt.:+4foShTX|ҚmfSo 33mxސ D?[DJLş~g{ūŕƅ*/K0el%S:?9Nxg߄M\TS8OayިuܾHK_$@$@$@O6Be©h‰%x:ϣط޺PD/dW62s}2̴2bSX(բ!gM)3WæujPmaNBOuFqoDP|x~ߓ#  &= db.O]+CdCRES)0rj¦ Tl!֦3\)E?MQ^wJ:y!   '@4)'܉~╅ڥ/...-U//װQú^Snmo'$S9ig[*46JoV}!CզSᬙ U; A.bJ*Cꉅ;F$@$@$0E"D<8/AQHoO\ lJfxjMasu6Uibߠ Y3P [)z JQ9k7/.7-V}x6sͨ6)kSڋœ)SXTp Rf"   P)(JPx/|UXlMZ+}ZC6R9 ;SjS JJ>WlЎ1ZWb梛FAṃ8U  G&}Cx IHH`|J*kwo..1S 6uq‚MuJmJxZRQ jSkbg{NQ ]=h5mj]#T~OTl wHHH s%!KgJ)~6BOPaNBpʌ?c<Oɦvڔ w\t6BeACTGQކP*; y.G#  xVc^eSPCT0ɳxJ}RZζO6O<ͦpmP{ BO e%I$@$@G@4rg7o-W:PµfSO̦.xj9놋}!Ȟ9ٷ)OyOA*ml 6)Ji /Tw_|h$@$@$dhQ2C[;iL|v To,T_+9_Յ}FdN] }fTٔS[[M ^t61*a1ҹ+tOQ z/b[jRX<Րߠal{J*T Jޑ !:gHU ;1=1g./7+ N;8t[l c<澆|gOCT7Z8u">   'B#x‰`^Z,aٻ7*o/^[@|(lj¦bM̤:s1#geSRS2BOMa5cy<"  x$Eb%\42f#1WC6uayvbm BJ-ይMSaw6^H!TƦ\TԎb)LB>)ݡtG`}NyHHHdIu"LE_.4;wJ!^/ x*lSv<}CPaTRօPMOPOSOmS¨=nF[?4   K e>3ĝ臯.1Z%ѧsKWL!‡WO)}BOؔ*y:'AmJJG% v!GMT؇( 9q&xxHHH3θl*zBvQ;EtLRݓ6*= 1~oelJ)9bfSjS:=Y*WcSMa.zOΚ7Zcq] 1lIHH+ A3z|浻;>>$*3eԦTҧSPڔ0SmJz'OI<%S-̦:%' Cl)\t<TO   N&$_d j락_{FtO) SXE̴k:usvkkSffs_kY+:xSfs_]NѡJBPkw{S?~J4ѿ* ?IHH%1H _^*~~RmoboS*T{ڔ)3;m)`jE7؇ hDWDi ǎ =n$   GC@Βqo/q|o.71½mJ *;m&yCbg)lNȦR8>Õ QmPw!   @46߹)l;ܑ;+ M8tE>.;jSfTdS֦Tlڔ)<5aS4Z$SfMuM:5aSj0 Tp(tMaZQFi0fp HHH=ً#]_{'}~ڒlJV碿ܑM6>ͦJ~ئ0v2*Ju~0h mD7S=z$@$@$@G@ c"H4۳OΑ T,̌b8 sfe}:BMb5E7k9eN57`S77ZX8hFvwC糭\{12Sl;r89[sv}rS0x bssG$@$@$ ȌNLH(>z+'Ʀ:6UԦRFGTئWi)4;*>0ђcoO$@$@$pd jlLlqⷖqa)$TMlZݞه{A੅dS(SMMum6`)99MagT 㧆mc}HHH;(xzeT2:ϭMB:e+}PJ_Pξطæ)=YxBLهljѹE7f'}0@<FtOM)PAcg@$@$@$p Ho&bs?X^X(_`SFdfئ&` CgU14MIxM-g*4k<S)!!}dSX)Z?/|2ZQȦ؇ϏKHH#bSZsư9xyM=PBEmSbST$xjO*E4ϦM6ٔqH{R!  #J@lJj|ѧ-0j|QٔOeSA/cgBؔE76؇xjS梣uK=SȦ)L ?"VkNA!}?161YwoHT`SlJm BSXƣ T)3G}žLs12gOMͲ'SbߤM;X< Tw(>g%S|z~xS ! {4Ay؝;lwqx}6Bg6em NuJ_hg)dbrFI3-Mb_GmjB^Nx+32ž OSް?0!;m0x V>`({c^ |$@$@$@'f=)ǝ,۪Z4{kv+E#<(UOm:žMlD߯ojO #fO T89OG%ۚMM!ZͷզsLx.mSu :'AzBd6A$@$@SJ@R)hԌINdVZy.nlH tlؔ tH6тYe$^titmSdS<<mؔ 'a!ȡSfĦ~, Cp޶/ 2xHHH` DR3f7:ѪD譥 lVU>;dSAz  Iu=+}c [E'cꝤ{suct.mT{buSl6}֦2u׏.JMA4S>9y{4[mow]Q;_7HHH)XʴO[H5nKoƔ',4,!Z.& nCܸҷsOΞwO}z)SLd'hiOaK5OCwJPq/M SVwU؇)2ʾzxHHHm籈R7aS"Tk #)8*:5aSbߤM}Ʀ؇}aJU\sʌT. :xJZ`Ma.:l p-~xi| @@M@o*q"Ly!ӄMa&)~6eG%h6k۾4 ۔m ۔k#S/Ȧ&lʌJxJ[RvTBE6ewMSfĦPSP!x*ȦMu.T ٔ9k 7P ' T2E>':kBu@0*TaP&QzfS֦!T&Aևdj|rئbS)9ecbT NQRƷYh\ʬ9ɦ0 "z27iS HwbP;OhJf)tg)<.6xJl*هctT.>cS̾=e )UئģF"TߧNHHH` `y$fkLs2T ҂okS:ۦpTJeS޷MkS{GU`SOa:e)=6Bl 6ߦTPx*M.Ybldl**)MafSw6[w੕ZSjS[UT1"T݁fSjSI ds63z!vI$@$@$0{ԝTiȦPò)ͦ&ld!m ž}m !{6U"mG
    )SHt1PSf{tO51*a63 EO$Ot.zOc(z8±}8K{e'%ΚAih $X GɈF1h D1A?֊}SHum6!mJ6B6e6kSȦ T֦RQ BBu_1|H$@$@$@֯9[!Jlj9mȍm*Ӌ.g C]Pel ԞTئ&)ӞKVpC%B66S:۔46l GISYC/zEbN)i6`S*TjS*TȦ=<93!xO  8e}x#љdY#Y/Vys'k0n)=eƏ:kS2x 8S};Tam)RL)3*}:S$pf_}n"6KOAj))>ӋRµ)N!ZC 8ʯ!>6  fJE ɦR#]qS&tLi4 Zt"ہQ Hl@b 5 ~~1h? Jx 6 Ix8{ ξ) TSfjBe ۔*c`0*7HH^)4JAf @f+RoTKE 7伐M51!SCB)3xjlSdZ9 p U DvE}ȾxpkC&b!ȾM@  VЩx|v&KZh>,w1ZXx*Y'dSlJhSV²t@~4/ȨϦn$VȦds꘴͜2SlSf{J}TU)ߦؔ ڔ ) G=m ʤ *66C2xJl*M6b_ئPC5s¦BSXMmC)+TH! xm} TDHsU7ެ TX[%IohV8T !AȃFfSOOS8JZSdJ:x|U%Hs{o2GiʅA<5<뺳F.ڪ6tOS2=ے1rݳ6@m vs_8B$Sߧ!=}yHHYtL9)T )*kS(M澰M>4/ 2Sa vyMջ9aS澮}aFtFd HlH*E:"?|$@$@M@ͦh*Իp҃MP<;OymJ`T<%:%6sȦl/Φf)D )gga(:{P>-ٝ})tOi*eG%`fSz*5ݿy|$@$@Gy[ 4ZM `m6BBEO{6Bem J6Be$hlJ~Ub2l<]MapJ[X)3rW8žڔSȦl<< $JJ~ җ +HHy[:xkt]PJWMIVmS03BIr_ AP٩Sݷ)=US &Z)iD궾Mi<x*lSzf_0xJHJPٿ    #xbToL4U `*ؔЎnm*'6S)+T>pMZmʎ񼰀Jꇱ@d(ͦTO'lFz8?Y+(hbA tT' f?6eJm~e>SRFk0fgg>S_g  M@Bh TJS)4cH~6Q 8Srl>6Be`SV6RO-Kv̾@ުMPj *ɔ-kSy x8rN;C[}ؔLKt.}oyTfs_G;8YA}T Ԧ)ܶ7N$@$@֦'r1.jS6!ߦM)NB152*ؔR<cSV`S]TxTBئ`w6j:'!ECߵMw6JI*@^ @5))rAMi<5aSEl g Rl<ΦtN*Myl ? ?Q͜DU)mP 9!!LIHH '%D":Vۅ ThD7SF6d2=3S rf_ 0BeOə}$R3C5c< M&mm IDJ)ه6vt\=O) U]bTpʌ4lS͎Uۓ^žBR}?/=   PDN$jw;f{ )$0 @fB`SE)= NMP=ImJ);x `SP5žs nюt'jS6߰bOmJSH0 +(IȆPu* S)|)nx R3e>3xR Tv;爟!  x2 &>4G`j;`MudS*4 YzOeS);QQ FLYb_^ͦ`S8 ՞6um۔ 0J)^LTUM!6BӦ Q*{=M< KSLtCɦ P{JO!l TxJbl əw) ׹ui6:,;EGp$ђ>iD_0W5w6L|O"BP~7s4h7M{ Ԇ1C 6;{FY3Yx &i}p4+އ}A#]}-l6Nh051-A[%=# b-e>zX8J҄>M|6e6)Cv۔mmSPM)-tv*TvgMMo*: MdS{To`\Zv۔NMilJ6뉝} Q:B7e;T}! t6|~[̐M!HA6G6xjxM%{ABC1H6ՄMPANwهtlJ)ͦ)҄JÇ).{ >66{ _ )ZIќ23*s̠V]#T8hPMa. ՄMN(ln_$)kVA$@$@$$An?.txm SjSO)ؔL„m *k{<aSA<%slF6B *_mMP)[8iMy'mߔT(TO¯  4x{hwDB,9t{R F%<0vɅS,wJ: 2x PQ |J gGX:zm;쳃9A/tk+XlM&oWYihGl ΆddԸ{ʜ'sS-2%D+}ȦS><8s[hzlJ}Mdbcr'ҩ `SBc.'P̈́P1(lʷ)P)al j~M ³e?V+'%  N6۴Y06 wMej"TZcg_:ezcSOmJ$4·R:'j Q=OOB%JQ)Jم"T2Sc<6 ۔S>Ds|Q E 64ޣq_M2k)9ƦH6z3'wHH`j @H;"%$YcҔ65P^530Rc3]lJJ'ymJG%h<@bF%Mia*}֦&fSfTB<^p6RBWȦ!xnk6 BeAN¦Mip  'fSmE>jz6Sqڋ,ؔ D6@:ئS6P,T6S2c}`lj0aS:*A+})y^̞>;{ĻA$@$p %y\k I)"tR?BA ϕIS ڋ}hB,c)BZxTօ`a:sѥ>1+:xb%\ T&#~\UX>EF,cEom5n'[w1'ۇ^z1x\Xҋ.<唙`si8@PȦd.ElyE^tTT*m\+}F Nz)" apkHHjMv6Qxg=v5wjh.VoSЃm2<61ƦtTɏ9OxJF&%,(Ӧ@ 7&*Wmɞ6g ۔A6Bem JyMkSE)u2ڔ EEmJw\♂D,pOZwyu P[ް׮Zt|xHdSA/Sr2fꔴdc!Sf6#U0xJ:xʷ 92oMI))vVM?hS7)՝ɦd;lS6aSPt01CK<N6eOi<5QzPCO=j"9& <&&S[-ޑn ΦPJPb߃l aMafQ:ϰMaҸ`S*T6bJӦHVMLPl 4,|dS)*kSOI/TM:e}H`SFdfS:x*8eEMuƒ Tٔ]p`%;Gl*oP))g_`S&I>0f.oSh}*TƦ::xΞ1jS*THTMvCIjB~d  x]@t6PC#Xߑm!.֦xJl B~6XTES!B?N"s2i{Vf ‚LTxT Y_1VYzSK.B5aSf)3-O;ߪ" I/T-JvG%),IѧC/\Cz8&xf8^H$@$@$0l9 m]o|Ma'"TG)~<54 B{JV*)3mJJG%Lؔ1ȔcSVpC-am ];ؔ*M15KmUJ1YKm Bx {M<%øJm){ʌ:M:Z:0zOt8Η=5 cShG6NC'ԄMa) 6xJ).ʦ~`xNJQbmJ4J<ձ6ex֦d᝘=vG*7$  $oC[' ۔o_N0S2[N5BBe6S>?Jvr`Sv.:lĴNxiwad7M0*rEO0 F$k^&_Xmr XaS(#"B ?]$@p'QDu~2*:x ^LݵVK{mK r{RH2ґ*k"اhoA;mJ<5 ,*=hF))S~}vgil#:4 ч)4+p=5)no7|$@$@<ʪl3k4l?ٔFƩ7w&쳃0ۜ2#Be$JOԝ}}2uJ2ۋ>Y$JT'8݂gmJ*S!m?xjҦ6Zm bSYWwI6Uix(nڝ}bҹjS@)#噱On` 7^Q$@$@$04Si`Jy'ޗ\Jɛ6BͦtNO}fg/Tؔ<%sэPS8S3<S:@҄M}0|$@$@-@QҎ{0B۔*YZ aS*T6;P9Pt6%J:]&yddئ0u;tgOw)߲poMO7>3'!EOxJv!2' u\Ds:'A}3tThTvPb@Tئm]sX_Q$@$@$0҇]c!eoͦxjMgZ,ɩsT^*T}O)I69*T23P&MQ ^.6Be+}֦&l _o`S:*ٔl wCljC\tMIf}`|vt|25ߒg!TSL=Fx:}S*C0s).^tXͦ)*)/<3lShD75/“nLoٔR֦`nasd3'AT6eZW2 A<0kSD40éoSVOQhx"Mh)3Sf>'Zf2Er<3oơ,O~6S𷸑H$Ұ$@$@$0R*sQ'6atxC7Syr*~w6pT>kSR{M_(k  ٔ)Ӌ.'MAHoSfT#)i eSP2:yVv(ئdT6!$SfԦTĦj6\Vm >ؔ*6S d xOo5 l 4ɈM!*7:Ҋ[]T!!TȦ}Sx7Rm;6V=mJN xM)MNzƆS6z6]m 9\"=)9e&)=eTwM–6ezcg ǐ1[7Sy!kHHH`j h6j NJ{XFی: T`BdI0߈v=E>5 uB:z2;xY)3ݵ3Pt$&y=o*!‚$O3 !fci4WP)G/_mF/|u*)mֺQ;UHE>D՝}`ZCgM/gJZo "Bo4cXAt#䄄kĜM' 8l:pިO{/!Jw DYnm ޕM]mJ֩GjS*T`SOᔙ65iMqnD6 [6zX 6GWk[_Uz[ۘ! ~9ႌ*;Tx7+fb,+#O#vi%& 8L1hȐff66zwP=Miܡo֚M鵵)|OkSoO$0WS=UI@0̾"9*T%3(6>%ؔ*3 ':M`SVpcM;h^tӵ%F,dS?uelJxZPڝ}$nG.L UB_է ~54qCvoWv:JAE)9&} ԇbSj\R4R%J5BڏOx!  #G "BXke+Rr폐P)ؔ7>.lSx~66vBkSO)ȃNTds1RIq-;N)۬M!p#TMPaT*|%n Su;*6s|jS*KO1⑚x }BÎ̄jY[2{zx|,o ^x*I܄ ?IspGBn9   D@)ZC(J3]jm3c!D]lJߚ5bz(B6 ר=~6IB)7<mJ ;`#mJ ȅ&l B6exԣ7\A‡YӒGY%tifLˇW%ITMTqY SdRB$@$@J C0|ssSw‚`TXz9ݾ)۷=oMؔ )*}b`AnIm˜2);'YԦ2lA9 *Ogm [Rٔ*ͦ{ڔ~fSakO$ۈ&lJ*lSN,§)Mʦ_mJ}3$ C0 mwf^,7 VTRLY\;qS1'J>XĉX7&A-/$@$@$pd DԏZd_joqNpBB5aS:~ӦB:Mi/Swu'))SoS:xqv ¦BB%CC6ղž=m h=mJv)kwu׀J*^jFV+KPțK.9B&[Jfrŵ䝅Wď~yŨB98hF"D+'KN7DXF?| y*FJՑ>0 ,t%c q[gB # `Tޝ5G2AFioF֝&nmAFb}x ͦ0 e˩tq}3s/y⵷/<_xw^.w_v— br/}:/|2'2/<;};ޚu049㔎;םȜq.8[ y!2{ҙ~ӉHם?q"I]'wǜ"bYЭSN츓a hzGloqd`¬#+_璯+߼QDtj%YLs4-e?Tq8 lqBaғLB>,>CE(O Ϡ c"=v o Ƃ B65צ61 yM6Jm vo[LKB"]!![dk^"+YozkRzw3TVffFfz Kwi;[K+K++WW/־R}czv\չZ$]ʥ{ w+++\rBRrRr¦RźIq|if |)+r,(G^TLgaJIRfn>u~ŷo^(r6O~n}6O羜K~s*K3:lٓ *~Ti|(9yxL Yg}ٟ3xl#3;GOh61<6;&n,щG1q2,"#'z4J$H)Gbqh_Eq~q;痍tƻ~q>ƈ la#K,t[12Dg[D06oawm |O W-q#RLʬ8-t zfCC" x RF!*Lp z埨ٔE)m9M! ~6B~YC4nJ՛jsULm WJ]d8Kb[(xlo.KJj麾| ?6rrR9ҕչ2ƹ:*ܑ/5įH[1_|}>wv!n)qpyue1wy!fVN.oʙt.S\ʔ˗ "䩰[ܝ\Rxƹ˯d7'R3_,~ >3Ͽz[_:lsXg'5t3XS˝ Y-|:{g?~i G/| +3ُ}K' :>tt#_pF~ßs g3觝O:pD3D}=匎;ch%Q<29Xt;ŻjN̬:9'~Ӊ_q8Ο;7;^tfvot88ȉF_t:^w#·$ yˤ,QDBAi$%a=!.¿ɬ|_2&UAd~՚*( [\_k  \fJxld[ņeZ32c}}Ȧƍ(=̾ x .|+ͦ+N*܍\msM,7Wk^͚VV+RXj.Z;֝\^}7ӺnI5޶j *}R^\m]Xi"A:\;wu~}SWtzv{KWs7VsJ&Y)jچffe5Pvқo|3G>>^sȝ~Q,cgg^̜Aqܩ3 'N9Uz$ȬfNE)?4V酏a_|ZWg:Ot᳧3/<[—|&3tgr_;)ONae?;USo|.cW~GF7w g;l]gN_wVퟋz|3OGz-HF?}$>3ۈڞu3LwnhӉUh!OFb+؜D/:sNe'-'vG\q㠧?:qMS88Ec1v>>Xbc>%2-ugWdYfd<䙏N:u:sT QO쳿w /.V湏e& dDٗNAr>U3>{g pœ/.}T~7N`A8]3o=WX9t;gq3X?[yLg(vR7Nϝ*?p2}go&3?3#߈ƶWcvF3g+?qF ~g:~Y3NO:#pmmmH1g8c®ckzhˉ֝8br+NǹwW#/D(,r'uuį;_sP["/Dm.Ttp㦿K G~I),&LL)%)|~Z#$M< %[c\/u=@$@$A67jZhJ)gIp59˦$)Rҝbؔ*M=M)vB{JRBm S$[VQUJTpqΝ?=ݜOV*BdhNgF&Jnnnn/ΝΛ?W׳Zᓟ} ϥ;zOoh''^<#3r'NNu:?NxFTWNlkg_?N4,(3o|L;g= V{2?~LNgJ;p*stN宝^:!+s:߽fljB%RH ! $$!IHH:f W\)61w{*L/*o}4@ȽY9::6f]o|ghb{+{$=^gdb_x]XPVej*aڨIT PoZi +¯E &VA9 'RcGc(4>QI$SAcy͗Y\p_i ])qV˴=mTBbi2 !/~GI{DwAJ_du9K]@tRNA#"#`_B}Q$%@ҢcM$WbT%7 Ov6C+0C+?`|JOFS.//b%6etμJ̗r^!6Bz:,F~IʻǦTQg":|/ѓjʴud2L&td Ff2c5XsYXxgYշ/̱ƾ[V׉`.kxv(`EVe|1x>lY"ɉUɕ@rr=5bMfU+ת~s^|C7CP73oCEb=$|?d/ #U镑ʈ*d C֦H*9؛C23`{BW_q a`0nɆ@o5@9-~V4`xCܪTH +QKma$ͣsxunW&g9Ө0$Fb 1gs>O>xW<=gO'q]EΝ|[s39(#^ˤ%kL\ I\(V<ʝ˲PΥR*NSOαT8\ZP<%\zqQ++k"ݤ0m+ 4[&!&3#Bu 3IB \g L1.F W,O^-͆Xi\އPKZZU.s|hI:?ɦ\o)PT[JŐ{dJػY['Vns_LKmF[Ƚ'3q _\n?k1H[@|9Osgpq*\ݓ9i@:9Gs1r.=JRy85K&JLk伎1&V{ʧo"i:H{c #tLe7:*2]Aڥ_Hb# 88"".\0+@:Ї kЂG|K OMmq·q9ypt_SvD*R2]Ȥt)݇}\[ʉά@Ao"4yEa \?%'}@rd6D$ۊkEq-lCEƌL(h!CG~(E#hR %ARCHjB%4j{fz)h Xy~ kH͊ۺH & { cnlucMO:??':`U$T=t@EB݊;K$*%4R2%$̀ϑ;f6E(RQ#lMqK*ҭҕD%^U̪NwM?Jޗ#q{{7gbnj/ʿ okbsp_LʿHc)Q gJ`YfD'-ߙO<_ă>)jR>U@Ѻ(jۙ,#DבRr&ƭ/yِ(>K%$Жx6Lv&Μ3?n1D&>qLv)B&[n 8e y0}mhFAO|/q>k8` ן~,0t9iבv ӅŋW;Ms,xP^,T ]vTW:Ľd`yurl ))]ͻ<>bh8$_?h n1\/#PW#נLmJWN9r (v䑥NƯ@Æt@|ou S^ihnh5FQ+ېhC%)9/Jĺr 9OΗuz{^'Do:< ^33M[2yJy%Uf.UpĎTZUNʌLLln _b +̷+E~kq,(TG,mMub?^ ڠy j+*jMDsRm2cVHDL2+b@$HaHl#~DωDR4@TT<(fY@AhGRJ0g$O'8YmvGýᢏDXwDѠ8.qf]>uL(|bO,eMx]s*/K%KS0(?QTNHI )HK2|\ͤ"'bȈxlbcHf\g1$E<@>Fc;ĿMt3D_!麔|KM ?R١^Rv^tzc"d>H]<|,0!K1/u.nޥ<#/>pxUƇ!_' 0t/{^|BzshV`h>B¢[*ҏ)RSO=o7nBSS %T}ɮF`e tZX*PtW<KØٶ)tmcFEC:@2JT}(929#z)Wm+RPjs$+ Wz>V-#IHU12jFfUʪJa+]yj̇4 #"\%JԮKc ?nWPb> Z%Fp,"iJU>JTLcLT-oU~?e0 3dW4*,Y#L>J#9ΰNA\d)#Em$I1"a8 A.j5O;5P1t6+HoX@5JEK"1$/KҦUEn\?9#HgH9/jpч/DJW;ZZkN$@ %kzUVyv*a+z{;,nLn~.6fDtjUbs[#a *s_5q`5WHi(j2mݓSd}*,= '# s$0 *QsD2^T@-p2X<~ֲGv²xm~!O)GS<{rS`I|hMx(ӁLTxx(a24=zRt#/e,0%ኞ9-iO֯}+67eKa0FbӣV j(m:]A5yړ?fK-Bk~RϓȑO>r{b$ C&YZL*9k[!zXs.wq-}<ɵAG˙Lx*hWQ!D *$ӵğH 8'>S8 $B@19 )1.5sʩb?ƺg@ka %Ep0.hrw-4FS5ٱXD"2Gzƿ1@DrI. :_u/ITb`\"dG f[&Ifب "VcĶĈ+ mN5PLl-f !o3 [y`|mE{Uo2ۭ k?Wg9rx&6&̲?Z ZT-=q~BzAT+Y%(-]X= V~is47ÝL%Vozeٽj285tuߕyZ7 ~P Cv¥CcM5햭viKt@P.\ K YV !QZe]b"aH|Yn3MLrw?swܭ$YI# $'.dbh5SQ:deU*!,[y8BcQB+>FHr3<~1Y@.sf25D6roaY&ʡxU!mB/Q1Dn] nɞDmzݳ4 ~\sO>YL$"56QMU:ʛD3}|7G&qqkZk}KZv&QR55"E|;n5DKI{PXFdbHC"G"=A~Ntktsq}ѥ>Ɋ?A1X!fYz" T`PsL sxKй |qcVvݡZ+yȱBu_* yWR?,Q9.W25ޒ]T8*v6eNxv/rѣx:$3]i'U;4:Xm5zے`;2E }n03CILMLM Nū{á8CH< 8I/@hZrY7tJ ܥ2} y _lrQ:Jr&3\/T&G''@N9ϑ 49Z$8\U@Tw#$SLA}2TƓ3E&:ߐ)[ɽ\Fdxgȹ&a߂wA yCYpd.OΩL} 8'>9Q@1-YOClTH-h\%UE71'UCd$g,%zIYǪ FaR蟇~FtK}rv)DODu¤/WHpF7B 㮡 V<|M84O#@PvvECCqjwvhhܵs}5ڑp֣/ُL_kY:0/Փtwdz{{}Z_?lwg_{ƴ;t{k[zZJeE_J4=JZր)hV+iu b 7tcgg,`fК[S$1`b L:/Qz:$1o Sh(l gBL*mcl}%16`'Z>54+RrjfII'R[_f'u h&[bK<5 ool쪯}k{Ç@~t`.i޴3l­@6&Ab Y+?G"hY>Us/9{伿ÌS)uQs[cIPc:\:CŒbї]Z(킾Cƥ? zVhQ+Ҭjmt k} (!*0bYAb1"ESILY`Y).,LD}RRZ8~bKnZܕ>w,Ģro-\\b/2iJ㥨R +Ɩ>߸xZ*Z,'kI+Y@,<%kiC{IaribN&0VQK(䇢eZ5j5**:ׂ%-H[R[!qKm1qTy/. eI nqx& \% DʤK:OYAj\K3a^E0. Rb.zMa"U=%Ep+ڢ2tݩ\7ji?3iw Nd\ .0*VԡZ+ DZKؖvJ;;sر^!ϣGe*"gRxJ8y zWe-{rx׾DDWك9,1Ӑ>D%DӽL_ߐSfvG60)S0b |0e`s/[/\1fq0Sv`nkM-}b";C6=5_n^jYc+d.Kɷ+ }=x=` +0#fPrJ(99N&c 1kTĬc Tq\Ciڰ`("iZ`:>Q1֨6r|NDp&idTbt#4 2Dxx εXx/V=K_jM}y\eDՉ5FdQάZoD6ER 5`M .-Qwؿ`EA!}m@]`;@ >I4ͻ!)M.=S"67N9}χ7Zr;ml/KP9V>,WV&хaǹDAt vO )Q*|w G=ӂ\k`*-A+GZ!˅t%OJ*SL9\AB-yp- tȐdYO$D C$2/.dxU4\G:rWrJQ]ʽCY@yJy8grgNfz8y-d;H4-#h?\=т%_(,eÜLwSNQ$"[oHBںQAN@j-G$:ɞD3/A=\$:CY8N3x-y!pɒ0<"2Z0.8Ka\0W1&{Y ZFk##b D/Mg4. Ѕ"уj}r-D_Gy՜1 c dsEp"cEPXU FYOuZ~D{eD܃` #O{u6<|މ>;_og7VĠ zj$1]uUO?ʕ+dyI>xTIfs֭[~J'aw75͝%6j05A2;A)obSǦ2DZay:ʥStCb]"sP} F,{{0=Mq_vY(0lSFK!k<&)XJ}.Բ) w ( 6ʥ$D'TdAM֜:90A&kbO,4Ϝ%.Vo2y uCO ML$MLX-.FqQ 0:\`3 +EW/htO5Sx&.-&nWS!mɔ-"jE5^=CyRq[HqO3xy:nyceǙn1q^xJ(&|7RT>U'1_GK'z6ҏUl{臡WXOt*_8Hvp?O<Ϸ, d!d({O~mp~ӒM 4;lwK~Mll*ڥnhSŒ`hSrL')L@6;rMR]Y5/ 6U"TO\655c߻9*4]r' / @'d\(NWz{{;rm}9{Fw!euvmLG<Mu&;[L-ޞimO6ZmkniN˴lnO4V[+-`KĮ 5zrsOn׆5!kn$Ÿ\^CU w`@,HW}x-l*SRCmB3B` Y)`IU3Q9ɺU2`2B0>`cU+Gc@u0ZG#zkDo$h%4xmH8@a#I2!TԫQ)Ȫ(06YNldP!0 N=(Ff*&g4sU-t=}hʞE=G)ќfKoж/PӅ&B֙.t/ xפt`?p|C]!hEF ߡC0 !d!BV U*/}\:Ӯ3̵E@Oԃki*5=$ÚE2; Fkl(Yr.e{}GC_*~:J/GbWCD5p@ԒF!r~.P@|G:F ֏C$YFT~-C=^|[e>FxԵ jȬ-t#_"ںtK/?%\$uK%[.-Lt 8EpXL:%׀K {%E()*0d.h\*.LEb0ϣ]q?w[KJʅN359zѨAr&)ѽ .L4s~g3:$ND EF* 녜;^Ǐr 1<;^F+r]]1:DmsZ3nKiN:T7X"ޛ֞F>#?>H5l;eĀt,j XmK랦ƪX|i<(z%i0lez5**3b;YolBvi6 Z淖T@3̲߫`'J8_'oH&fN B='lJYz303$1#buj0As3CxkB0 `V0e{ߨ@u J@[PA7ÌH0>jT_QuvI4 kWne_[þH+MF3=Ny?khWh7QwccNPj9"Ol=7ef~HD 0Pe]žĦMyx1dx@ lb011dx@&0>lw ciwLGS۱BC aY:>C(]|}aFaݺt:=6Jȧx GK?fF}^N/ֳD$yu/;~S/K2(; }7ڷaw$A ] BxwDW "QXhKVh 0G]eLVJPK2,+PX`YV7+tAbв )Vˊ6CѬIb&..G#eBzY$1|&-gHLG \Cw4\itD-gl>q&TSSy4ʫቅ9Aj\E`1.t{"4`rOxfNUD4}T@jV.cf Dc˯,P&ߣ=LHح2/F~#$*t]铜ct.c`t*# إ*kѥ~WFy j6j+[]yTyӟ_` >RKG>D9css ODx+];%*<ԍʎ\glniՇTK ڔdSDWHFj8CT[e7iHlꊯjO,I&2Zcsc3' qVhsU|o$'ݢ'! خۃm$!UC [6=>\ DWcK(bz'dLx| E1)"dR7_ /0;d l~0gLdJO931)b}~8>ٓ5q:)$hhTUV-?6}ygꎺr7ݼYLͥGz 3h jvFwHXdNm'Qq{  sY :F bbP/Px\á.PЯl*|FAA@Jʾ.-se ZZ lT;(*jN'C+CU c>L&1inUԲ6H(+Z*EHu : ZݹҠTg4ËP'x$K?(TQxG8û3RQ=f-iQ.~Cy b$ZЇȥ_ B"LQC 70z~;r_y'b..Eܽ9pSqO p"ǹ8.orgB11V8ɿ(>J|0̃n3,WFY>#]q!4WUEɵG+ʌ2#K{LⓉaQ1H߈QMct/gnNHA`2t]Btʋ8JL]CWZf:coI&yBSWe4AxQTjѢE(]x!:y;%Tq^Wj|M|kһjGs7h'OuJyD,()D%'sMqOJؔG K$ &0 SICTU*dn'בkzS=> ՝3xg.֑tL$;vgdJ4]{=}Z{wm*4uonعSs}΍:\}c:^_׾m}5{kulsE]j2HX0b]( \ɡӥtK?ueS!jP.<$ }S5Aek!OUoeMb1ϑv#u{+xвB pyjrw L 4JN3ٰNgI^Rg 9põRr높ktU;\U:T-Wr-ђY=|^l)CTN V٢"P \$k_0yܟ 9Kx5D{>9#;8ӻdivrn(nVzn$q yKL2/H䯀IITç=Lq Dϸ= ӊ- ʾ%K潿< V [e\@T<%ƕbC &P[0W2~ݘ ոD#xUeDLQ1T6s 0to ] я{\t}V ԡ+gYt$`\**ogÆ (]{Sґw*-!x~Ҏް?}kaá4MO*PĦ=6SyE)M%m U>ޖ/Ac1'=@Ie)O<՛=pO^-:D{ $vdSFg?苵d3L!]O'V?d}}X7}[:v5hjۉmK-͙M zkӡé͇2mM?Y{m]m+jdVJ ׾ffZ] a>( z׆Òm8؁zpMZ6ovl;:vƻzkc}cls2bc7ږm&SF:KEӨ?fv2NF3vS8Zmִ1X4ZwD*KVl:ho;BnBkmG}asOڭKK]7mu9dưu#{7[k"暪ƵIg,ƒsR.k=sxX Wʙ+Վ'%i^D=@Wo {я簟MG'4K6Am4zNZv mv^I># ?I:Ez{gG;\sYRNqG*A7Uˑg^n zNP*+ӱG{K\\pY.FD;VrdeeJyYrN1T1%90nwch009 9,yo Gfn6ɢ*̒fn8n(&x8UXW7 %KңQ CY_S x8Di\ǘxD@,\<( 2qt- S=i }pjIEK[v&P"a=!^Ðhx DK$|$>pJHDЖdY ]g!TĖ9˿y0s*s1dARYq$pAՕc*V1.vgCIΰDERٜ Z yx=[MYL\30z\r>kAUJ_C;cV#0x9'}x8Ͼ 7 ^"J䡴?$8s̻{p!gnРdi( \ NFɸp 7%eijwxl }gj(vE;S:Y繧)җ씝}ܧ*`r(I*Ƴ㽗޾D;m=Y=n][4>&xWx Pғ#ևD&OCXkIgSM>iD{ʒx#ĦZ;wvâ`}5c67~׾\(4AnBuÊ`S2<JCTz:NNҙQv! 6-tLzx"=6wTPʞ&?N3҂;|o竮[\\;t ~œ'ڎ/.CE % _R3;PvNvQYQA!: @`?s_ pH*F ,hygDJb iULYrP,=D^u:IH+;P7ˊ*_V#zp^*(-K6֐؄!A*jʭrrާCzsxaAyu90L#gLw_PcE.U .-D= AC_kzCK ƒܟpfsDŽp-H[οI] 3zd. eDv]˹PFtnb*#^G9_aBGt$8kZb%q['Br/b\&Α=2q 2n!RrVuQ:Y\@nIrޥ`_4\'+xy\yIA s5$: \hVK9C+v3`vTJϊ^}|Ç;*++=Nr <P" #o(]r%g/픞?)Z?*\uӎxЄܱ@rK}TEfZ4}oXy'{ s sN*i:3W~E.]/jzWpE1=QOsp*ݲq6.^wem[ZM^'a5 B޻-ejVXeS& 9~Mk|Bq=$@$4kV+٤ʚuZ };aVR.6MeP ̝2TG$MMgyxUs4r .21E- Gsj]ˋҒ\i fYRSqg݂1!Z$µ49u~-ZRBh<aҲwbm|=^l݈oصPZ/kpP+ŬOKDYLpp]%# Ֆ-EΔ8ޭT=Dr~"H,&z;5B#)'$qyOrU$ \?:ah߭OAHѼwN*aQ &@AE"9 &PQ@AĜs\ӚYATDE9J]s߭zS .-{Ձz9sM<Gq yǏkW%(E|(k?*&:CNS&zg,~z(!*Pj|GS2MC m8'a] EԌOV^tX.,Ql](EA!+0o-snZ} F5?]qcz3Ǵ!bW :պE#qUPώ˔ݺl01Ili˵FK:wlg-TcjD>4"PY[|Ue._ ?$Ls.Sϗgǽ!F}7W_9hT}p>}v}ٞ&~8f5UKuh>ms Uy)r;VŊBTC=.F_bT[pCwx8f/ژw?tFB 5LY&xĦeC4FI$M"0 'Lc*084O/k "1Y^Xb0h8 Fרh8g}!|8mzSF)|-MkQm #܈'Lxp6;mzKrڬx!zF-lKأs>@biֵmXemA݂h=Xh[&w j\oxUmiqIk\yqƛ\,MXB @=È6%hJ ̃!xug@U"RB? x'<Ukj0bYex-rASbQ-0G8 V1JFoH*&,Ra#KmjvHjtp:u8lC#΢g/U_ғ 6Qhdu3O>&ρVi㽻d']pmB 7AS`*k~pjġD/R:RM:ͣCgQ?ӱQq܏Tw4Q^fw=~K/_uOΣ/ϤV45Z?-Ckӆj2LTٜ8|! X lB,';:e,?z|1ьf[u3=8G/TovΣO_pVïGЬipaui;RUU geI%#+uX Y6 ^MFd!G{tmЩ wtO@d@/;HNzKȚb5.4|!jMYE|ackVRJRDrW+ZJeY&x5EhYʚxmcfpQCf3FZ(#vka9 mz/@ =qp)[iX `4uMi= @%юaػ?tXm-[1JȲ9OY}ew8(T5jhȐ!(3/u!7 >{J>z{N8~Hp/6=k26e8uwVN9GŧНgc]ԛQ)fJ!i5`]) ^`u3v"QvR, 'b zw*UUܬڨbB:l:wv>s﬏uM]q6}P깫k:OϠ[ӄV4X櫙†.K+ӦJSQ׈k(3v-!ݫY! UBY:Gn{tm V?jX@ =_ hԛF(YY>ER49@,ŖjY#e!+UؾU|x&wXkyax=jnh βcgW,e&oJPZh).OP@meނ J/;/Xֳ^uC>ld>-;=FiY9A- ZZ k]qarElb2h;LY{Ђ8ԩS{EnJZdx/B0=rײនvϮ޶*} nq0iog[YvҜX6ia=xXeFJi)KSSx)K<)*}8MaJ_4m;4PA3q (hj*Y1¢6s ?S.ZELvM8@SiJ *Nh*.O4PPGS8XJ)U~Z*A_) D⠰$Nms>Yb)f/ 9a@_ $FEq *?0Lm>^ W%MWEMh ϥM|OBY?M2|9ZI@N~=]^ޯW{sxaITxRPWWRJ]LŝUB ZhpL(G?J,w, /W T]q#YE-S,TUMf*ZOѹNoK^սWS7ߥ^?_?Wx ݉>:-XNZODŽ5!-ݗVդ5h ;Qc&  |z|zRF4#,e), Y(I! y*D )d%}mIFk 8, 12AYʬ0k!2+Xj#9kYlКv6 ~"V _YGfj/`Oj۽OPdعI?c9ȓ>vv΄[&0ij$&ESh9* )))EQ  Tb߿~Ti4%7SHS/S,PmGh lKSx⍷[BSB݆~%>'!ІZ>tJ"_ ɟGW!(xP9%\YE z$TQ()"q<Wʁ0 F ą.G*Z5tCt~[ґ^F)רC`(H0_ Vz(:O5/s :+2O:#x_]uƻ7O<:@=s~JHXjdguk|4)M?fJ ?ڈ0%k ʙdaeQŧcGZuQ{'u!Dc]pnC{@X/zI67& IFʅo˅`& /8LʂaYy䠏*cʆ,ye!^(K!<(QdA|]i8V/=[4$X{trmU^v(Q)r8?r_6FƍhxA8a4%aޔ)SN8axx߽_Oy6OYxVȚ8g93g&ԡĖ3q~,)N<M(V7WsSvq%k m})-q jaqPW(< Gm,:^Q|tx% /\^G=R_2qmz~늌dLRlRαœ9Wz+B:W A 1U#*>Xݮ\U Dc7,O)O)Tet\3Z[~NDwz7˙>zB{N}0W_{׻ϣO~8Cg66V+ Tw񰖐ZĪ (k?[%<&pցwӡbqh0Еv,o5ߊ{2T׌zè d}ʲ E@VEK[.mhH @(Y m6)ʏ|ehgG.b! s Z0h!>غe)?Y&xZq,6d'0>,ͫʼ_y^<3Km<BЂղ;;nUbӊZ%k=^kTu%-m(ylwB_ D62bMYׂzCdQk'wi? a?ķM%NWxժU/Gk #S\R5Q ˺Wv) 3{Oּ~T);MThȉhJ<ň^BS:FS1yjB&>;Ç#4kA;5cGb1BSOD%8ZXEu:* TK~i j'4#/)b_XhA^ V|/S6m.[DٔY*UZը޾t /+ӎD*BvK-]yBu9VmvL ?f*/2P T~=jϣ#Sf %)uIJkҰatz'EU[X܌~kB3F.-jCJbK̼rlJ@< dU% $ְ 0 A1~q~ AtsG;zӧ]gX7A"Mz)v޵B - 3\+ hO|ZꀰMYF:O'FP #?#fm }YzJ偺aE j2`F6i0{e6gYc0=lͨ4>L;=AM--NM;ڈ{5E</~xY-f-ÇZZZ!nūW0kM_d-c I{}yH[m715e$XDgBq$ ܎)"iۡjSBSl rQsG\Ӕ0Mg8Mб+8m )H+)*[C(vh*m m "LJ4m*=[4rTiC&7R-EбZ*s]M0$cp33͈x\!UΥ9j :Uw:p:|>6iϩ꺇 m7ѣ٫8hnQ'*a[Xf5U5 Q%TUTҹr2IX22{%U6j&!aPS( T PFCł @?1 Fc4XOދ~kAƻLLgT0!#K!˧[2M"]yjћg uhl) IY#1 8a=q*jmV)?!ń\CLB40ٗ%m mBN8Άfc(͊e Z~dICz8M(Xx ,`ɝw=l7/w}0J'Lh`;~?u||Ue}?}巳aeF)Z24t,ȭ쳫b֏(&^(2mSTSN7~D+LBSx))i ض4^t*;m ^tس%'-fb +ˍ4u.srHhJ) o4%Y) hJV-\ÙZ M~8u'3i@%>op-tq4@eS`WqKvU(cb*GjWxuiQԢ&&tA ۖF>IcI%C?\cZ dlX7zXk! tޖ3 ^)s"+:B g[8>BAAH& ^~B /~ T4p:˩w!-}KSz73_=y8hq;A\r۷4}tեd(ܔK/s dE^\6QQr;HI 熝42n_;;oܜ/OR4fj>%$krֺ0`9Zꆝ @fV悧 ];$bd1P)pc^*)+O+cBGMqj\vOŏ]2Q iJD){\t^ַ o؊b_T'd@,pURw*=]2p܋S 0"a@ZӔ T Ҿs BS𤸂ʫըttrc:HuәW.U_7ц8ʿ5Ն2_˹,ðpNBgv`W:@u)~U6m+oW}qP%De4a(2T*IWj:w_x>.#Я>ҍw[ӽC5|Oz {ȮK!a@[_% rԠ UiK˦2T.=0AKcT +UP(ݽnޜums!Dcub˻xW}UB}(m>E_;޵-o {w[+\(8VzMMFo|Ê!,DP_L @Y6ZZ R6Ff-!fnSx636^BY?+wOq+vg}RZVDYbʒ.lޥ6pg,k nIケwl87( =:6m$grDMl=F!oo׮]J+cv|m qĊ?ÿ^,*QQc|ELi4%F)KSlhk MqS]YzodƭLSY\M٣r 1\Kݐ%$xŁє/8 bc<ThmJ)Ѧde_M<5¨i4j&(cE%x x?!M-jQrB)rJASK7i*ߨ>:^x\ZPJTpt{)MS٣b2Mn^'E%jlX9 |1B"OTr/- `S TX=HvWAj*@d2HX.b^&eCA7J]@T,Js;JDh9ùӈxUV%65ȯLIW aTv$ *VV>7wkP Rc |>vj6.x_u.z_h4u c_z޹rgю$؊~>~?]X ӒǾ&*7/W@.*gËU&j]רFbT7h[蓍w3ƻ$uW}уf( {ߨǍQ/#(7>4S4z)hY]8[j 2z6!U,1~g YVΒ ` P"P4/KQyajta'TT[7,^lۢ hIhe;( Z*#Q%!ZbЊD-Taڦ!޷'iapaU5)%Pl{4큊}Ĉ諪>(о @ ˧cRtOm|:'(<7evEa/8ޱ0 Cºv*|3y|h+ti]WNO] Zl}0o( #E)*EF%!aa0eic(쭓, $.n`-Q lh-І9pѐ$5+&v_6x,֬)TQlh,9DU>n8R: vu×dx{ߥ޳@i%9nC~Mv'=K)YYYБШeڴi8Q\6伍{ צMhOa/1p 8?fiD?RH2nƚ|1uRE34mPBZS6t})Y)Yzh 3fKSswRxLqhjiSQ)<")2FS{* 99RƮ 婒ONevJYbt*+L@SAKM#}Y;eRlшNkNag:'F^e_j5ZCu!ZÁn A.F&;(R)L8ml?J2.HnW+SNW 2+0ɡrf;;ﻜX@Ϧ~#1xutڗt'=2]],W`7>Z7zz\u*}Ն&G[Дf40јD ulǜ- 3S'~Ri%,3&yhdg/GXWX{_xNC7"~⑔ /7g;d"aȂ}I@X] U7- UBB1IYQ04e%wH"_Xy̌ul@%Si95A,#Ԍ>ɋd dJ&h)~s|*3-܋C8rqڔДc49 V}JMbDFYhJJ툦'>v`Eg@C琯28N ,yTy#X+߲D%t)d|y([+)5~vq+J}~p~bz/ruz#}A>Sk'|oa,aa9ᒺj%ݫFHXU^yokf #82> x-aYCJAGu\Ynh&6+ ؀vp4V ź( U6.*dax sCtk_{x1Wh' bͶNcb ˅guc#˷1YHBCYhAˊʅZhe!*N͂MvR; hEECؐAwy_` dh/!0.xM4߿? yׯ1fIx \;)~CpO='xb:~(S䧻 ܌oˣu8iBA[H>ϮL.m njz"}V(%#򢇶GSҶ=R+Oc[h8LSv=hJڛ alv) T<;"04phR +}x4r+TE4-*[ }@])@yebn/:vPԄyVvxT1PٜԎh*JX#ij,Y8 K:V uEGmh*~Ma?coT̈.%`( @P+'͖B(6zBğb" 2ã d"ăՠJy[nHm3.i >S=r~޼y4G6cNVŃTl_}Ta/ʻ\v͠{3ٞjSdK*:Z'=UPU|@}DzA ^U8)uT>'3h>8VW.¯Pto:'j5ڍ>NQWTյ{莛P?<@?y~~"n'9ը3ՠƷ Ӵ4 kLeu.͕*SQ.5(ls*TRU]_7:$GtL @:ŧ35twB! =P7tbQ!>Ë^4`zׄXc 3bV(tDȂ潣q!wɱ] ňJC,pr!bJYsl$)v!e , ;*98%"#oV+wib̗(N5|M]vk&~C)l0c/q6.rhS#>- /ż)^oAVLxNi m97ÈnߖSL1b\4kYr0,4#f޴ 8%ӺДlSne)"BEw@<}RiJ-p8Tm8R0_½Ѫy,!6*AVbD-xIT$ Gr#⾧`F *Y Mou!:lw؃S,I0'&(>ǀ2OlU*իCMsՔ:M3 Ii`Z ] n>8v'8_ez2M.A6mP9I'ўe*s2 Pam $>"WTiU@QM/p 5Gffұ߁T~vuW/Sߧ'hC4cw>v z~R΅Au9]+!ˡٍi! Zr 7W慄e Sy*Tu U%rCb;5kTPHـ" |PbƻFAo-b=h豀 ;n ~dg,THo3hMa3#K( B)6clCddӱ /=JJCƔ˂]RI/k}+pqhтBޔ)SQN m/NfÆ F67~o`\7󶌞6NS4ɺ}I˶n۬BTċ-Z'.)7;($XT16O8M P}-Tr]N)wqm  mE%`զv]P* (Tc4w5؇TEMm̍۾BSS.U MaE;dH:+N='Q}z`p5 eUPlƀ@^ރ8,  ":Z|e3'3ƶo۞Я*X 4729=U7@jX5N+2FutK9=a4wݬD AwKNc۩oзpaCE7Yhށqz2g5l"+􄯼dVV*LU$l" YUgt}v9GuPN:ըh aI1uC47Yʒ 9Ka]F! 2{xq@PD~2YӍ7[YBY 1YlfAYF e-x s #HR.ܪU4LY{/o@f94 F8p yH5?SZHg%g=;o쌍Xԗ3}=7K8Mb_\^2f@U R4=1GKS 4%ДQXڔ|a q¼iSI'O0BU[cmJBw}Tiy ()'O.MIež*є-} "+4}r仌#":]G@S}DP}/Ax,9Yq* $*;p(E@bY="u+V5:ޑ-x ]~A=q!޷i B "GW7?Oi+lwd.i* 6 Mx~*hT!t1p#U29$ɢ*(f{jP/S{ yaU_qT+: :S:cKP^P<<Wzg~zd_ՋtJ9ӼOoOP?Os֜&PZҀj~z_ɦ25%Hc!*ak5BT#9 0:4jijosυ‹aW 蚀h,.tg@@=z.m fY## ,&hR*Z; C@#k őSV(J0ɍ CU^{+A=ZzC޹WС믿hMiekg MyNGyy}ڴB9q  ȕ6rFdBm-GB氄" dquOIf d*[B"_Ba pO/\WɁOP?du9)}۵o0oJ1؃Θdw2#G2*: avF |6ZC;^x*p"9 X\(O卿/XP_@r:5yuuG` -\]@0_%;RѹTX64ghlZRZh3574LYX1}8SWr=NTŰӎ"њh"Fk\q3WeMa B{Yۿ?_#\ʗ(7a 󾞹 4fˌќ<stMAvh %XKӔ?ey]㓆])|OzK:MŬS0-fvDS?) Дx PI ;)[Qҡw[S.1`MbIgHSQ%)K1O"rĮG;QTaz1Ak7n 99G<8)g A̲TլBW6iMԫ mO=1J6@-Wܨ -7S+0@JfMi r/tV2~*%G/ݜl@`jkS3r^U|2*R|Q^!%RVWo~UkBs9tt:W:z  NKg|N~HߡnoPרqB8w4zJH7Н^B9ٙI4XcKh<6 iF_B$V-q0byɌFl\* ai亻P, =$FZbdiδѣsBnݓGj ۀh,=¨9XW^|У Y81P|BhYl{:dG_5=z^;z7q)X"R)5gΜ~]vyFA|e}Eycg|`鼚o@M2SuiSi4it^}zYoզ4îcmjCK)E܊֑8m'`C>i qm /)N MESYD#-c'kٜnI6bS\(Д]x M<?:KS 1TBSr\oDSNY/Ў$(LM؃~KX6vM9p8drI)p|p԰/il)|5#ߚ磞uw6VffRrbPzhs<]ՆNtfً 97꡴&u*IcKe|u+x[@fmW9v9+j+2jbc%Ϋdj`W>Ob|t_mj@ eYߩůp'WhAxg}.ւusBvB #7'饞^#r3W7mXj4Hq[x0MPAB M l{1۲ĆVB.G1 v P,F !V HwY>.F_xby}MZXW6_}z׏gHhV YcgԷk$nYde* |饗$ZΟ EΨ({ݻwwˏ=gi奈]Dܤy뾞y‚,8/̊tFvBSӴզե4M+x*Ndyj]{iSR܈mNR;K՗դoh4GP9ae j)AWFWv<#"_󕱁ö6{巢ԱjNL@ CBq%\4 U7nP&ND> wXMEQwW9N)?yBxG7ߥ5JߠOp%z z{BOΥg7Wc-#1'KXjPf5T[zYL]֋9KX(1Z2apvQmxչF`wخ(QϦ*~pӱ^0:;H`ı_۸ Yii*ort4~TqZQӔ]Wv1v6hjG.9E|.` P^t|v!bTk~xGCB/C"ZUTC7;7Ge'ЀS+Wx{Ӯ RlW#ȿ|iW7:]x*ol(C),_n'vec(وyU_QJ}]p.jl'~6tX@TxrmxBxR\+{@2@\fPkРu]yPyMx )x3B猣'Fm/񽱇9LT0c:8Y뾝>M*E6iGSиd}ӴM&9>Q<.34e͈ Ύ<0!içy4MŁ*NSJh @S%SBSE0.[PMUD>Д-TД=RS hM{)<}%V=bM yE%i5){PL"C&g"~*x+PC@!NG!=/y{L ŋe <^Xߦbf1\ՆrlJgDןG޸TC7?\\|ەT~ ޔLp^ ળ?[6pf;U(lȼB`_+j :۱r햯d ,+F,3@ʥ o_XJ R<{-iәG]}ԕOu u C~\ʡ7NV:>?ƜBO-irsڔFBqPVMjW*PA97RA /2]ƨl!C*lh!#P%l.I[:zЦu_fX}AFB4v{@N:꫋-S"΁**MBߣG{nP wʶ0T.$ν7sV5箟Ru))T(!єM9ij)#h .T+p4hxljH@GSZ?^7 AjUTzJP{gg{E}.DP@zOnefߵ9k{sS 99 L=Z3c۹0{acO)|=O/ye1i9}p;YQgЕo2OLY;|>7WU^$ Hr6X:•ř]+tM+u6XGr*7D_ Dq47-W?8VD;/'ύ%%y Ģ/A?w{p:?nIwGGs4#a4v&OΐITŨ#ܳ(v JXKwp+s[LGYp+׽eԳy?.U(57,lQ՟᫭}!^Ŋ0ګa_Rvy·}; ֹ刊K򺩪H8>`i+pӰD9V{lr{WWC=AdĻ7j^dh;WGH^/3C)Eza1_\C LoARGf)HMhզjiJk0浡)F!MTp\M!OJ4TCSR!J)M "!d|rv4eLv ,wTb# ]a8.3H]7oa\LJI+ğۄb{n8&[U;ehv7vtfn–nmݾ;#w+I ^|L|IgG_}r菷9wew"^QeWTkA;|"8D΍nE0d,XQcJZ,: $rL[dɜsO{ ϰ{X~#y!)eNV ;T/)STq S(PUʙ06#IL'òjl>A\jiU|%ukg4mGb1}vtr>Ed_SWYئLGkcÏ362l$(dz?5T|99;0c'ݱG7@AOŅ_x{vpk+^yWDY{VhV|sV+J= W53_7|]m'EdQq壼a;WoL=}q{np䋯pͣ8W+ FlR8be>W,8Վ ѯ]kv|3ßpG;w YWxwe˾_E}?}%Jr a]=+)tFWD0?{@D }˻ˢwOjXM6.(W%Al+/,Ka׷ʫmW[7Ieq/I>?X`+w;pW}MU?݇.XwxUs߹~‘O7; uҝw݅.JO?>{v}\}2b{O:co + 4GadosxRlkεm:ǹg 68W V~?11H{N6'?ʕ+ CI/ hAm //}SNQ T3ЗO.3?r#A5}% (MiThT4Rk:HYg_j ˲xj)#HhD[.YⵎWT"m$4%+Azqk O !MQ M>L@M1G '4>fM --8k3'8JԖBz':u9111ф'{l[twhm'9}ۤ=}9Ϳ-3n>h J+LEp5QyjDNWԴSvu Ryu_ xޖAI_QΚ8lW,;+WT{*;/4~yg4=oTxx._p¡OG>pḇb_`1+zWk|EwgphUX_}u ]=n{rf3ߜZ#oura~E7Yϋi'(n}曱Q b_UsĉgyW2CIOhO9kcKFޥ^:yd}帅'b;tdk8,/(|Zr6{rvcs"*4\"q)⯅cbtv煊U4UeL#rBHSD^?M!d_2]O 'L$}6:nt΄Jh)M!MyyJjxf<PҔA̬!M@SI7P9RRT8GzN֧n4RmJWeI)TJz0)PifzvUYJc@Mrz»ܷ/~mn+,rgENn'>Z WlK`6Wf68 +XW@Yqw\IzqtB$eo` JWm7;3 (%Ȋ +|UDFK` v7m6ov[-s햹]R=3o;'ݑr>L};gS~S.+ZZ??>"?Nw. t~*F?8loNlȑ=y}wfϙ)3`Ї>裏*#q ^b?,^硇Z󨣎ҁ v^8[6x>k$%F} ̠U42# >3捰N*?;=~u'7V!&(0J'i\O;)D͜9ӟiOe#%{yu+so :Q Be+2aIgqFvǹV.;C'7t{QOvÅ~tEQs1Ww->35Ѓxu'Wv{TBeW2|uu$W Rَ[;|uUTĭH)zl/:ԕhߕYgw_vsZܾ/nZt $HH(q֭nbK]iYW~ϻ=:)wcbU8񔟹~]ߋ D|:z]цwhs7IWsLuzHX?g„ +yIysOE)=w]MMMt]ve;B^:{3woEv6Zwe BS cxeşweAןg-{iJu)_jS`M)P)Mph;JSKR=MQ7:[ כkӦҸHUѦ)PZ!Iwi/<[\k@SZ=OTxڔS>'+T]524k`.qmJiw):Qp)W0ͫIdgv2j- 3צeϤtRe_npWzkG7F[m!V =:`wrj(h'-xEF?Ê݂Ng^ϕ?vUەgxë; &JfҴqqXQ S1l`QMQX28_]i W,SG`(Jӝê`qoTƼŝݘ>][vWz'ݛ[uo{X_o?vG|ſSn\Jq.XKtC2 3gnO"U(bfGᄝc=k?O8 Iq1\~辞?N7PŷK!U܎Hq `F΁yx E]7&2Zzn4oxJ津>)Ki=8tcyJ;#>)o%8FwϵfD}V׽|킅Ϡ^-4k9SM:3nKO-}OQ@Abl@PQ:#kEcXP&HHɇ9(|R.TfvO{sB9Zw3Ui])"75E] g/EKYkA͌Z=T+:*!2?_;|qcf8Y)*`o]d *6:  ,ŁLS척fakg\M }6|墆u[3wf(Ww^|DfJoJ7DiuQnzv\RWؕ+ Wx2raq< r]e]{K񕯿"?( 4D~A\y*0wcnXoX{_59;:o1%X,A?? vaE\sUÌOξ'DKN'}QXk~Ңg$"EfvWִ~5SCQʮkW|qW +mWA鹚_T^5b~5FqneKEFgu=z3WѱNŸG^z] wl77u]ޢ»[n9կ~u֬YIz:TMbG@"*:veõ^2-sզttE5]Ĭ.Wzj^k=>Bz׌8^Zc_I$ Q:Txy+LG;(PL ^{BTB2c(m*JH)o64KTQ>צnvxjq73MC+jiB-@%S TJS<3+@D2E'nH4ET8eFS(6_wZW*/o+ɶШZm9w# 8BFd,hDt'wM=&)?t+ϯs^!-xGN KZQYp32k7kNke֕.wK\Et_g: 5W2ɮ|lGvAl#΢X9񮴹+m&kRN[+~7mofe]Sa&7ymnlKbiwvok8?Po;N&7;c!# Tn2v^>$sڎYQM|gqa V<3{9qP54'4i*@)By&ӇQŚRt_jѥG hj:UKhJʌdJT>6z_uFS"At*l&g+dDKE=L}z*)4EOiJV _PdcUZ#_ʾtJ44U͔_y mJѷ5b:M}Pj@TR)cTƤԝ,nLf4O $? D0<%<;' MQ@/J\:tF4+9~UX`L J-ı[=Žyw7KOp?}l7.wY#7fM5u$&XdoK7ăd9ٮvޭH |uaT–۫\LW>eW9Ir[#R3*,$W^mT|fTGfA*8__ _ƣ{-іĕ<(̏/esc)W\qOSYE),FD;-؂'ocTpml㺩_`M˟f34=;=WV4l!MGmjhJJHFSКF'^IARP%5Z~V-:ۑB@Kؤt7=P/z M&S@T?UOť= 6r9bD4NP]y2}B4'K*uH,p VZsBt%d)MY[-My9QXTz+س4eSfX:egCm04%V]cYR(*.צ6f.ߺ*SׂX.H`eSGxWm4M;vwљE%vtso\PT۫wɽkW\Q~+ݣ&( lx^"ΐUT:3 =ԴkUtH*WQyWTރ5qA$75ij]5#H Y9[{++7ˍkw-n1яbH/֚C8YEOBb &+)kOˎ؄)7~~&+#_Xf.i'3Ι1M J4h6S0UjS4iH!B3vl/IEj)՗*FFUѹN#;aɾ@2fٷ~}]CLQ}s:of.xvA/7eK:1EGi*F3dӦth*3))urB֍J> zXiPRY@ob:hUSyJ}P*)jhJkfzf*hThV^KS^)So6)):d+^2#ҜҔ]\%MQfS6MMOqq@e6_*v!LTMRT߱}b)@_o'MȄriw}X"^TYK&ʪ͛rn- \;wa}ޓ㏼}=7/?io=fڧ"8=w.:8lwVW:ܮ^]+])ʕ,xEջ}e9t+a&*ʫ}&坤sP2_)emAqW:$⍽O"OOs<;dv/:曣c'O(ŵid/;ܫĵ3dጀ2}-Z$oIz|Y(nB5.FS&OAST3a CS*wʀ_LEj MMyO!iS:ˈ:B<g pɚZ vJ0I'z9ʮ>2'bF +Xy F-5:; waD77}\]jiܳٷ%ӣֻ\όOM`*aaW7 YWt(|\Qvu$dD⊧y9qGC] W<{=\N ;o( n'mlk>k/ )u*3@«1O&Dg/bʥ5UFK ǤS4SktĵєDNBSiMj>x:_Lcth5[j M;#$,֋StȻ!%[7!4=L,jm#|!,^PEnpVO6UP24JhʊN> #ɒ@*O|i-:\j A>&O$NX=eIM"R']PNG"k~G`uF@ ZpfBA}ow{(\}tMos}tJ/D߹s7YX]Mw fUwIOމU+omA7HU~uQT| Aīĭx A5qXs u8ؕJQyvJŝ"3FD<5qI:b=L?1QUΎ޽{GZZg7FҘe?,K4 KST:e\"1 w]SNz]KSDjpF},=d)ުO!4US:5})NhC2;KS+ AS]BS#4(q6i(RJuBD½T>b`4L4LdCS>9V4e>%fOYҔTkOb#ĺ9"lO)*lEs$cWQ\m[pOw>7tWݽOc~+6zznb |`7k7  joEd)xuY,ωgE)qH N'!T^a+{qkjo]pҷdw)>q#;?lnn̠ee;z0bGyt?^!͞Zz)YaWH:=MYV 9J*J@~1)) Ӳ\3bI˛UB`T"OymkןtY)H)5C UjSJSt*YؗN MUS V )PピFSO*Vni*4[ro"OI-zHSz*TR-Q))E<ƊAhS:kCiS#)5:E":b3Y-wYzXVQC'#0 즑7*Ū$AqN*xPs5mn7y;p o߻p{=!=xTkݓG0EwFM4 sEDG^of%el7Mt+Q~ nëFW&lEY;ۙ~A*ѯ+ +ۏZ>x1 3(}#O!gO|⥗^SRJo`L<ʨvuW{9:x9{z9rݘ1>53Wm*EL|qNH)Ӧq,HCjSR>s5\"ҔVס) y dU dǠ)5jxʌL}ߠեjSTUb<4ER *lVyJk20Z&S5ċ<%QbdTZ^_Rզ*d/զP7}}EHL24P)MI͒w LMjJZf>N\X{ڵOҔTsG*hje[q;yxFTShjB ƾlh$Kxfn}wם~hw֓)3g/_W^Xo Qq=lQ?9{)KwƥQx[T5.o, X۫kqqeq_XNW돦,t@8QsGCz衇8?۩@ tÓ#@ҹfߵjzcզ.mιME}'~!ASIOjv;y\)Mqm"^WbsM)lI I|bS SOBV8 _2ke6%>!Md|ҩ!C!+ +MU2G=AxJ! 4> )P<%ڔҔ_e,"xy*KS$`6)k#fh*L4Sg4e@Uٗ2ÇU_t?_)MBJ|/2) 1RfcC5ݦ 2-5W^;sqjcOShhSFSM WASz0*MZG"h6N]jYUpL}ʮ+Pr*4.,O PRb)=,5LPxJSOou $tE)u 1CS ET~8hJK؀*䥐t_)c?SRRm*mU*t}ZWyٸRGεbzŋț:u*T| K'p2 o7p@@Us@Y+Ut'єJ CSk%.TJ yEH!3|\֘e;Y ܠJ@ڔ$6Q&avl0P/ FXLP' o}#u*bb<UyJމNZ=%Xkѥm-AjћIkTi@2Yʌ& UPFWFE)pKw҉)b4٧S*Uxc|H멾j/l@#S!Car5mhݶ[p+Ȇk>xR)g-W3IACP|ԛoG 37Yy ^U^ԺMo.\1vhJEMioxZei)f43MItjiJeգ)JSB% ,s0ui\4'ɾJS%jgҔү|i@);[;s])c@4}"M3#!h!F W[]s{;awڡyGEMj>3{ݏ.~uMu雤jncۙqEnV2렃!׿^5iș} g1c؋f7`wzdY1)H:l__^d߲|'oԹmJ0^T-MADSkCSSAsj;-Qri2#MզiN)?S#զ_:%Tu6Eöuu\)x֑6ДΉ68&'A䩦nhSK:3M5#LN9$}cCXZytYNWfe>^"O%Hn$TkDZ|(ݔ,X,X6I)>$IBt:nTRL2Lgb,LՇF MK])ed,Y>+GKS@ TVDRօX6?;'ɾje`M pouk49G  2MրwJ&PeYf}L-dI6Mlt,ǨMizNYlFNk; yZ2)xkFft-o ;}]s07#!bUZd#hʏ- nm~Gǝr{כU'[NHIz t)`9o޼U=[6UJ ڴ#oW 3;u?;ɗ*$'M5wiJH M Ȭmꩨ@iJ8'KSچO ij@Wjєa(M%mT5MOaAVRPGCFP=*!@ItNYVS }i*%_"|w3ٗNZ&4e}QLգ)*Ts&22M/B TFShoU7Ϧ++zdd*5rbF™Fz)2m{bSYOʒ}PPNJSK2wau%q4!|zs nInv-ts,3vv،3zV=* tCRwBc({1;㔝{Vч\IwF2Hc M-i<eϚaca[HS_.@>Ԇ4XK$Է#OI'SKu:4/o!-o~Lӥ8LBbdaڸlY2JSZ=q MUޤG焦4:#Ő*LU YIhehA[/Ȣ2Aa@bb+f4EUN@ɦN7I]y t_\(-o]e$?O1k\++Y&C2`a vykpiKfN8󙋑cx-G/n8UӘupQdž>}~TV[^knvE}_pzv=lO3g׾55n;^#,Y}AiН/ |h,织GtØe͝4}F*PjIE-kx탵kO' Mi65M!x#]x>=b4G/ST!O},V6-=m Ry*5sThJh* }'#Z 7BtIlf*S*3zf*T`)eKST@MEuGS{╎4 e/窬1&K5U}z418T7mJX/™<PnA[SwQhEX#S:dӋjV7O-i?F'O}5IϜyU9,r??7x{/0ٵb@o_6}9̿#0>.rt0EGsGߒⲎ"(5oE'* U5M kd4UӚ)RH*OBS4TO MkSj)4Fd0y֡ǻ왝Z9<Ŕ6T)MI4S}YbPc~{>(Mٵ8%l^Bq/_I@_m=M?@DЍx: lξegpb7;ͩE7R)V@ٜÌHC枦A T@x])쓅Z`ݥDÿ.qKH:CdF{kiJm< ')-D_* 4e( k׆RSQ{oYwi*-~vjWIS$Ы@Uah )I4lFSxi4@P `6eɾDbsO BcԷ!i@e;]l#yǟy#(v%{!(`Pw];a57=^Ln#mF SMm&Hul*5ڔT(OU7U|}XC)",i 5GHS!G~HSb2٧Oڔi4 H7mʛI|mecx*4C11զjp}iiRm*CSSO#}_[OҔf!OM+'TJSSdSKS̚jS*' ̇)__dja׉Eg~. k  ^W'#g'tA)25uʹ6H^2qkWoKg_Ul| Ң^5z)qK i y_)#"ku$OSO343ҩx Hyb( ?$oT?>R=|V9I-vIHj4E`g =E^tJtJ7)ӦGB_$)fG ٌf[}UX)6!CS.s4NPe]E9MPeuKR0^bSOm0*tduRnɾ~= 02љ#4E=Y)3tE*12|rA  Qca'CSJh lHqwΥMhSui*$^]9Xg4.Cɓ$(PtصQnv*PAS!jQ/@En̴k@wֲNcYE0lΗєM5Q;Yv(elŬե)fPk_dҦjwrk\}6_?u<zYhtr-{0yy+Y`C,|V.;z @$#Vvf+ Pz W$ePI"1BU`8HHUժ"j-/4ih 0m4<4Py_tQ2 L+Ԧ{m3_MhJS{/Go0@j#`S'|0y7R -[ BpF;^ϟ8xL9WFj_љ)4ȹT샦d(!iJR9#0j-4SBSTJS=M %Oy -+T[?N1j34ELi04֡>XW3Ghel$T<$T)P[/h2Z24'׶Uzxf[d_8/Uh*UU3U T,@/:yk%4PRy-oV));$e;6e4Prd>pcKw 8_[  X1C7P>,X;<֬-(5qm7)ިF2F r=wۥ躩~TB) mJ)ӦրSaiLRm*)KΈ@TE3j^RCyT4:ϕ,4ES'(mT70!MQ:XXn,w6 Ǽ"c ThSbm$F MA#;5MQ6`)"τaz@eڔҔh) gه<)ѼѺfFg>$Z}c) h7|!\.MORC)P M<jS*O4ֶ{+oS\ ) l#45ff E~7uCUoL4%MjS+r8$ٗ4ٗ%$>M$4E`M}imhʇJxR))șt{{hdQse* Z̑ iS ,ef2}<>)bxdT.\A+CS6FKNi 4@W_*ig_b ]4G2R7]|:p)=)ҔULΣNNN\lui7gehꩥ-=Q~H=#@>l#ESidO:zЦ:{)<4ř0TR`k)lON)J@1rtf]jg"BmJ#F|ջ)*=U-c^)$f1*>Q|A]/I?A MT5C>^Q 4SUk&4 P4#JtkȵTJS SDR{H~@SaT Ttv0vF>FK]*T;D.  Fg ΫKS:/Ml6Ҕv T6;LP4Xe <'R)CKh ^x*axRTE it|gf廧Kޙ|TE? ./Ojjր24EAjSIO(MTHec@\5k܌*~پM﬜|FZ5n tS-UL R@?)M-(5?@%ɾ~ ES}T҉jS24$)0m4{3/#J),č4@+M!ͅ4EVRRR#)W-tHZ)P%}^ʺJ1hBbBӉd_JS R/CS,g]PhJ SM)fD4KiJK6Y|"O9sVO zDꢆvL: JS-IHST"Ҕ猜X VZ 푙m&O4tK]4T,iJ36M#aiS<,CSd`kiʇ(ٞHTDAT<|hjD`s4\jKh) i E1CS:_eVW9Mu ^lm M̔|G`# S:EV ObHS$L7:5Z"t,sgCdħ ɾ_j5cdF*`4'ω"9$npFOͩ2vF/HKy\Dq4 Mܑ,4Id_``hv7;UdP.̎MWevQu)MIa!O׿]N bXdpCK}a> g&H #O&^4ӔJHҮiJ/O>LT5Hz~G |X#JiO"{Y)NlMq]stJ)ji k M'Tq6e4+s*xͶ҇jSFSIHI`CR9bg)_拮JwLK*T@Sx$mbhHSXܡZxW9Ԧ)IT,@J x0M/OIN8}uRB24uD4GjI$i.i TAȻm/lf1:4FW})63 B*O M)MY-Ӕ29)&x4%yI4h" M4Ub<5DP48&)M9m(mJT蝾31PhLӗNIg%ٗ)Iu87MwhIs|Zn>9M?CSZ?%x!;5 1!A)lDZѐZP? Cy4R4%@lٗgk%{1$Mi-ދo4hJ5ЦB*46ig,)Tjdv5 B0CSє^bV ꋭ 8[K#)Gզji d\)rK;:x$Yߕ]igOXy55E))S9:`$MڍOYbNY6¦NoY ͰFB#WЦЕ#|G |>G@kSS$i Gb<1f1HU@WEgbh-MjW?4jp 435 94M)PQό}t2jM"%481zo<%keHS2fxU҃"a1B0=EO}6ҔPS1y{=+Vvz_ւ' dRiJժT@>#G) JSG@RmJJSvJlۇ5a'c<My5T&XCAٵѦTy,ҢДom#PM ѕ㵕Ҕ:E hS&O4iSj h43245'T 2#'H:RyBS JzQUS?(9ҮD䬪sB"Ju M1!M$%g녦 Mi锢/_0|LVj|!2SVI4ŌTSKS*OM-is_=5ɘ1c)%#6Qz Yqpg~ki .~)04@$|Mh$M=.$ j6)v{u=)4ZR)J)3]c4奝I!_ϨДS T݇4da#_{N]R֕RHGBYg'cYMIڔNg )L. m*MPё4գ)TzȬ'OIDS$j34ş){M|էC-M1kv ?kL>?^2}:k郦_(~ui/1sZYf,я F|G zxU jک_"C7զ*'!\)>גN|k-u֠VDJ)`M40^ktǧ4Uai'Ŗ) x*2)BoUf0C|ġq DR!2#6Ae*P7sD5j ,T PIm[ZZ%ut;&RTc4U7XTQ)c3%()hJ婐*BBJdXEr"Yr<',MY)Ҕ?HJJ6EmEEM.ݦ^hz#ɏR:  ka)_:asчʜ״XhsNjДԱT2-Jj.ɂfHO&S҆PmulZ#є4C"IɐV=3z杂R[HaPo6Yh~8MN-MT)MI>Kfw htV(i2X{u> d3yuCFM1KZ!mVAIZu*\dW\LNi-MFjզ24z$4VOiy35`'*uNT UK6$WMS:#\ ;z#Д⤡j4%T2G^ YM%4*l%B@UGZW4姩$( iz -E;g/Ç)&B'%pߦ a*MT 6%Sҹ\imE\IEZJ&b |xUFɲ{v /IDmn)5~J~V F}_ES_6%Qv#hKR_ !CbR(HUMxOm}6 Co{):*"Y]ZLyy;ؓ.e^cnT>٧h+02'[seĹ(I:sޛvuY8I^U-Wɳdy(z'%U: @qOsvDFPb9z2^0eN!;ٻ5mqJް|ۊ6֩ =8o:ugY_E?K FJ ~?x//LS}aJulcJMԚd-j%MTX.DSP{ 4sb_z*;AvY"2LShP){ 4`hTθS`FS_?yJV$ϵ/E#hEij6sN)a8(')7g!/m>T E7F~r XSB@?xC%hv^c׼YHนi{~_ X++P(Uj1:<V6HS,)ZhjďmHsVgBd ^ы4'A_0qɛ%L4>EF%(X?;2īZ!4@S=U4 +dr)UgT@?`L1uc^ PS_ݪV k)(o',:l25I^/işd]T_g;Ys! JE|=Yrh4 fGs1gzMT4 $D!'wg*4!)žM-S^Sj^ ցJ,yfɞʝ}1 PES5$h v SnbFaj4U)+.jHe/zxmiƳ)ⅶ TmT/xu>Mf'rCNLGq8:)Pއ1{quΝ5TξpoX+`ź֩:c Rǔ^R/<)򦦝1IIhx{bgq VҔsش%Ž%e?1KS*S럐=E.R'2GxҢ=dWyl-.1C4cvLͭ724B#5[thQ(~Mqޔ=ՀT hahj?h=MiTBrZՌTi*jaO>?{*iT\[4,GξBVX' _Qkޔ^hJ7԰'#*}g6_+֓ŎGɯw_Z+`( |P7J~|=,NFJ?#k)tպFO( }-Y?<({ )w *oj1)JUNS1{,!)G(8a3rX ٟbv4hM-o*kI1x H=N YL8e}۵(q- ztl_ B4*a<y7Ny+CgEԳy CP ,̓7/_u*hjV#Bh΄FQְndBL9EUcP?Էi@UݎرOiAnS둂Ci*KK(!ȧ0TDzDnpύv (TUuOCEASoET؉ P @PN! U !㞪+C6~ Tzf4x*%j|x ,zuM|{Ӑ7./}rX+`gKtS@>Cq.Ӓr_\OKStzZ09u2^"1H4Z{#"F9uFj(z>2*F%}'֝DS~ z)&CTӞ:J)NH΄[4%_MqI4Peo>Nn4EUt%MBS{Vo)  r;MSДv|4EI4xWZCSԝG~>۸t4.aZ X+`Φ@xA=: ˋiz򯣩F%YS|7SaO^KZՌ4rRyS?Mх΃cT/z};)9qn}߼NSэ3l9ДK,{S"CMOX)ӔTFv7UzoPEdAPjFSTh@UTi!u0-,;ySESSe/q𦚗82dso meO-Px1ix5~Д^)S/h)B}K]ПζrV`A F1Ų_h/BV9IGiIL9GFjsZKξi 07Ĭs2bT+!-*GA4q8d/4"M FJ1Z>$do*qb3;aB.N@^픙v?R4E}h E A׷H5>_TܫjHSh*7q7Rx) JCFVz?M<t7}/?k쑺F:jL=m|)nV X+G k5vg)>Y)cFSESkhMI$u*+9ڨ W夿>TagTO4ꙺ4l&p'G9w8G74o*j2$ @+)fIM0Ir߯)%hBLSÁxmԋNgh {*OY2ÛM3N4@Sh|fYP鷊NTZ:U45`?\i* >xwJL[!Ӌ!PsDSjGҔɶ)Fㆽv`Ow8h6.ҧ!}߰V ,(/}p|z ff5+W_4_SEST00*ajME-,rt R/.o$J{*)z=*G+^3&.~{f1Q-bg3əjXe;aME#PćX{-\TR6Oq:FLrMƤ4$8)o1܏0@\#H=9r9Foj=q-,pQJʩS͞}ÞjӶw(TjoǣmD:HSG`$NB6:o(OChT_}&oD|} b儻5oodvK~ aj}2N쫛R$ݗ ^1:soیP] JjYp/.v r\cY7W7Nٯb~2XDqbWge8BVՉRmžvCEkPaƱM4E&[+xܹ/.\d`+66]5¿V`AlOJqL o ;aOuxݳʰ46x**b? R8e=E6}vh "M͘jGR^)nOM4ʼn*y^t<)TH?bE_ISw#@K4r)1 Ui*a>{0t#N5/{TשhJ@ߞTɼI4S1(Ds0iAMH*?Sbo@qqQT,귰7V X6O#Xi o*eb寵}_V0@Z{/4YZޔ:=ji<7%{hJ夕S"=U4̻i P75Tk)5G4IFth*Gޜ D3${C3Ka,ySZƂř}+AUΰS MQʤ{+2/DtJ{JK^1 g)v M)1h\4зI(MVjj8hxS4R^m%o@x=ET7۩#ҋ4;1-h+lj0 .}u X+`f 8/T '/w_6Յʛbg=>[뷵B?]=ߎ#@S\45lDjɭq0\xS=_9 Tk4%ξaQ>xJʃ3MՖ1uQPqpIu*}:eN-v[Ȍ&%:#M74i RlzSw#@ch =,q*ۊ@%G%@; FZ}7ۃfi*m]0axRuE2ۊ}41}OU2MՍSatOhJnx 3㝓;;jT ɝHT {O)R_LYiG+`h p ˗)mҳta9TZ ޛg+Uk!/LSZPAS/m&qigiTԒ򥈚S ҥǓi*Č';## YtMKՌ.%@S_LU$=SpGAS)HS9Hž) rtVf y쩑TX~U+u\tuO!T#uOq^=@F-NԚH 4EJ)dQԝpoG*hjbW)@z} xM4jf4PI^'T:MTh\` thuqpc7vo?ss/Aչ0-"~e14 蘢xŞztJ}ߺIz<-/')%flegwh6*!;az Mkhg)xh M4Cԋ {ixKlF m,TowS)4̛ZOSMTиљ oJK'XISeOQD4U>*n MtMa'&BS=U4U;1<Oo=fw 4uO;kV`Y|Ҍ2_%lWȕB)mcQSIxJRJټ_+iG?vWUӿ5; ֈ">[ &T"^YeC(>.n(wxC=ہ_KQSE^ wS Ɇ{L>M L/" {|q\l,ͧ=?<\-\`WFX 7zbEXuWTS?M FޏFxSt U>qM5&RST5ivu3<i^#2 4;0{tFb&؏aN™h*6MiMN ;.*F,6d5pwPB׌WFJjNK4@DS߉O{ *ݾ E/^Rkhn(pn)hJ1-HG.  Tbl@L$.<}xؐUIS/oJ)=Gқ" B)5h#P;DVY=Mggξzѣ3ՒP4zTB߉_/fM̛c=ڨ~L)G<4 ʞJoJ4ξ8ދ)igKSJ͸+7ն-TN4\ {harLR=M)HȴtӶPDSi*N}}j Boj"^AP?+M 8쩸rH^4I>Sjw_szj7yl´Ik'J [Gb6R!iiz|."eMtTf4ۙ!fOfZgc'5,j1ci $R/:T/Hŧ)>JWbsHΌLGjvLvf7M)o;d46U(ˋ7ED$+}ESCtZԬLj柫!=;yȵ4=6h*tM YzzyH}ES T4BvBO4ŎN8V[a"RY aO#(.3O ,Qb_PƐbb>MH/*SQ쫐qf4|5<.*o6xJ7Sx_nz<ۻ~1.<TT-k+`:)WɃW,HxSwa'>LfW ş|o ZiJQK Zq`HS~),ئjQ9Tr3NCS|>y%Mejb~|KT GM% negd޶ DSc/:ƺY6SsYczTd!pTmg_YTK{ 84U@U4_>*F| ."q{W~wsjr J1jvtB$́ʞK$X<`v~'^]㉶@SVVt-!Sz[*I?ihG;w(m|!?5RSm[4NV XQ 4=޹*25 ;ǘ+eɠ2c/{~쩑2e7 =.<];.i;"&T4{W4Փud.JO; T}>䝨jA)bAYL@U#eg Hj ~YrTS83egX+{烌mx@gΌPfFSHћFdײ근( .h^whΪ.>S4\qP, =[xsj^oDOMUtOqCJBEo=4{ S)6ȞiYf/?4pՇ;Dї 3Ջ>,~mt oT(hdWGb?]7@MɞMigHHS}yUe{JE^X:ޔP)M?Y֒=5T5)kK{jG7dWr:M>xnX1 ӛjCJ7Sbg>J4t:"ZקN!Q9pa{^%oi/}1ZgkvlDN)Is}w,F+EL7bOB9:V:IJΘh\߷aE'FmPkm8w,PU"YVt)Y_ @f~UӶ:shJMaѳs)& M;|S#LjuE/*WjN56 -،ks݋ݷ϶<M TlWj,v : 1$S|7FsiTBF',/o"FTN9'h|z^1^'1>vSֺto@Ō}=Xl0ޏYvOr4xjͫ5u*AaHҳ*w9t [ +dPs&y|=^0{ez툱#╛1sPؕlca M`'"VcV¥бa1J4N>^(@SH;YESS5Y{FSTf,#M{|*c<{*e4LEb>d/EV_yM=zyOVi I4)54%C*G=;MUv^OS?nT9:`iQT@5!LiJ@Ť}Pp؆iM)MO=9픙loN ,? ښ)vc5&0[(p{"D*Veg=ۣsBv#KZ/Ƃ9 #M}hziĻHS(bߏ)Jp֩sP" M=bDS㍝H8/OG[n~,M!)jTSbIg&֩(VT,D @d/^e܅Q5_MZ+)+@wCxqE3!tVsrX3,,khJ@UT>m%M^?4E)-@=O^|Ώ95UkuNhFSV@E-*p*3R?OMi6-czDo'Wc2FhocHu*DT_#-B*Mu·є3QMC3є֧y쎬gEȥj,LSܧ6z"R#^GôjAfhFSy"q@5)+ahn( k&}!V,d2IǓV=%;1o(B6NrkԕW^iu Jq Y+`>vb7^=j|Wav_!@Eԋ<5srˊ]iA[u̮z!hjjmjgI=wFUNjC_ IԶݑEST$JQzQ5z܁*NU.PihVnyrt4㑻PɞALS*#Ez[sTN==X$iOM^bv~?십p\co0ɕ؆aO٣| M5ʾBhuo H45i)yi${բ)jʉ}gK^b&yP)E-GHGXAy/MK!,luE g(:樓p~EA* IYAS9Xia6qLc,lo;b*9:ZqvԒC,1ETbxdI;hF;u^uP']N M-ppzIGٟ}uSZPKDξks{j`fwhqgnZ!ȁOqL&,m!BS+AC0y{Cyn^(So utaLnf6ɍ |K&{vvAaMy8SChMZ1ϝ9Sh8tkcgz8zʕ1Z>;eOs>ȏdjM$osrWf寅]/e?6399AF7;lgwhNh̝}wlNS}"Ma*S+/ӔJP-TۆioX4E(!$OJ0ESij DEd|L4z+N,p,֕1T(fO-PH4Ue~~-P-o9M=5 BB&ƮbXJM+ܒESP{7;2x W*p1ȵG͛*^t H8_V XGc/hrLJ>؋$#䈦dOݏT=ij>'GOZka׋1Gi/J}3R-IҰD~9x&MmT4wDZ}$A!91sVΜf}M;Ti3Z@xw#rT4W!';ވi*b$o4}ў`ݕUjbTAM);̮ž54U3?{i.CESs7*L{չwM$/QwS-TԎ{*&ES u&"pESTh*E .^cЗ@l֩jG!o=.uГ>Y+`>҂߸~w1kvv˞jɺqL@֩#"_ӆV`1\̋fiJ=_O"⤘ZcMh'>߼ҧ|i*(0@M5:#M5{*aLi/8'{jOGnYY *}FSi>lh*͕ yν MUz5ySIq PowES{j5MBe՟8"e}+3u%c(p?@5ʔ=45ȝ} rRSڈTc|Fw8)so PAAچT;6=S;M%PMiZTCSae9 SIp=p"@- zYhJFGdoOiO y5MMɱ`D'TyuDtT-@9lxa\UєYo#Bp&PM z+Lzo ;зv `ee6 }=tmChZUP"E__$-" J;3T/ڊ;SujwOw}HC=x}QtfƔ]ȓgo9 XF~q΋ýT>8= cdΛk$MɠMU>75[:#MO$M)YGW99^vS]Z֒ _W TTMMՔdޑ"q_y9^}hswQR TTtsEScsdoo{44պqzvnsAMS*lxohw].o¡4E5k#@{*TͲX)*ctx] Mn=F<`JmTeCl# 1SǓĉ/VYPT#/֋qg_vrQP\ESD V?ˣ+)VbD&Tx6?W}49?(׻{[[<:& |^`ԫ`2Y0%=srQ ?XД$t{jŜ[2@l4 z(#Mɞu;Nt|R.;gNS7bo36m]%PBSEiJްXwxS*.1;科[)Ob_Tx}M}t[h7dF[9Gўw=M)d4^c6LUT49{ H 4CԳju[)S:-vP)d'ns^f4E]G@ISq,^0!⇂{ouVl냝l_{q3UlxrY+`>>ןT'g)M$4M3Mmh*Iy%P/n=U%E ~/b2MMbAvQ6LSFR5VĻHS-@g_],Yt3Z9,]p,MCޜ[M2+|gCҞ:J;Yݞ$ohj|H;^b)hml =>~ͷ0ڂ7ss]};~xPqXC}ǓIXOE<1~a  -8AMS _@up'SLB shYU4%R9{oXeqSG<k#5Xk_~T[zk AeO{*[gn@fُF9'2ɹFaEOЇ|ǦQ :E˓I$ܘk4B2u&>ۄ/S49D#ܕbg_6+F{}4uPSzOb9gT1  (Et\JCt#T3@mQnAc9Ƿ1\Z'ا耝\Nm =;pW5~D +t#\q)Rl0}."w؀zcDEIU2:7wen7=m;WlƜv=zK/"؈nANA )L.wt+fz":℣Rqx1`1xE:̷._~*N+`>'Ƽ0 !0xnЍ_~BHSyԙ[M 4>fVDş\I4UsrWb4GihjMzi2MG 44DS4%t:9cDƌ\q!eP@ekig8O{T2a4:nReҳOf4>?MhJ7xCb*?8{Qw^?,GY9T8مx*予?~K|"RcisГ>%?KKj#y\ݳ<דd}PnTOm hƜc0xSɚxqʕ_V4iJ#M^$R99eO;3YgsnK#Jli6Hޔg4U?w"MӋ>ž&@0va2d+aO )25 T%hMQU(qn]Mq\h*p7yBɌ:)XE}*M#*}Ջ>x]5TP+לqHSsPn;;b@RO'R h)Ul}>w~h)h {*kSS/ ?چ0רhJQqEgW/2M {bTNT<8:/JxM}KS"1g)S\jrPȆ(D?$a=x=hj m2dzh\ ITySd(^i+h)6ԇmS45n*ǯctTU4U+d!j|=*Bdz"F8TޜhLS{)%vTɟmE0BS~Mk=p2n(hj*Hioe(C0+s;;6~'|:˯R+`>>Nݓ\7P›mؕ f,5O4:󽉦fX~*3 DS(@M Pj*LkjFS5٠)Sv+q87t͞Z(`6c\\yC=@ {vRSESlZ)m1 kOݤx5/1b=T ӭm'ȞHWV |J MeԿz9ǍL[Z"KZ_CԒ8+ij|$d]4Ŋ^ ײZYkǻa3>3h*Z=45bB&A)\H֕àzF\p.є2ih|M|3R[{Qﵴ5B+@SSoB yKCSz^ @(Y1jS}ʟ&@9;ه-ۘ? b`2LS2G{̆Ͳl&jdPȞ#H%olXTS=pk%G;]ŝ/(ĻTh!Aa[oe{BQqVWU7u M=MU@xh*J>Th`*i)NXIS5UES/Q^CS3"dcM e/T]=Fw~>?onr[eyNPIO@_oewd'@T<]Gb:/~ޯ~M:4E/I4ջg'JChJr6"Qz=)\#zܾ{)v }(2r%ًESuS3oJ$PaFS'.jPm=M3vgy751YNiOܽ-r<0=0X)\22.tT7fSTu'jJo_-mSMA'ySiOEv9T ES;s@S'wo*´0'ySS)3b,J`و37TxÛ8TI(B^ySw쩕4}JkVSK4d6c=xIS9x5G[/oo?dg'kV U P bŜ<~nd=刦zG>NSm>Lk_V; UTeJʳ]g*j%nFGsjTIMC̀<B \iO#KdfvI|iۣAˊTK֍!uʑPˏӻߞ,"@9,J qW5S}DGGTYtД¤pG}TMEE"M#ASI<j~G4sxqCun&)"X=Kӳ oWlƄf4ŚP7Nn"Xw[ċƋon=𾋟sLRq/-V S$\藺3]X/翹W)fe-Yk`33hoKo*ԙOZyž԰Oz;eg||3\9רTaP$;TٙcdtxG=YξEeÑF* AožhnOuZً>Vc$bU;TH\&0bI4&zv^AS Tou*VH0zxN4E8*4zQb{&[}Dn4M>;I HhlDO/t%XTox*9Me hĴ'4EM5hDMQ |4GP5)`kD6Ԑp?NF%ZEese__cB;9oѝ4:f} 4`9ew M_9 cgi.Fb\40\dI48MehR3\fS~HMGNh0רI;I֕SES삥ًe'tj6WwiіC=Źd(hgS}/rt kTijt/t ^rF:<@XEk1*YDg7|$6p;[1:m%1-S4+ 4E>iQxS?-MUaJih*쩨Mixd-Br(zZQ!iŨ0pSnCxSh*+GBSuN+C^z^JMDS?;~R*Fы}7U74ŭ$^)DM2M^h ⒞+ij䮄TliJHSQ@m5?hJzϒ>w@}A]8g#jV X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`V X+`K M endstream endobj 9 0 obj 125435 endobj 14 0 obj << /Length 15 0 R /Type /XObject /Subtype /Image /Width 794 /Height 567 /ColorSpace /DeviceGray /Interpolate true /BitsPerComponent 8 /Filter /FlateDecode >> stream xЁ Pa 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` 0` x endstream endobj 15 0 obj 1985 endobj 12 0 obj << /Type /ExtGState /ca 0 >> endobj 16 0 obj << /Length 17 0 R /N 1 /Alternate /DeviceGray /Filter /FlateDecode >> stream xU]hU>3;yCmK+u!aR&MMخ6Ut'3ٴ } oZWE|-jžT (XA ~gv;pg9;{eF4"_=}GiRpfg)ƮZS-7q޹-25+0Zj9G҉a!Q및 }?ЬVr/ =\KئƂV^vn519= r>W3?iLLJN3ٶ==TGfbFx(ب {t,毘AcmXEHf*0|%]x#Y/5Ia'r0?vȕ>c-orGysxuJ.ߴOFCQeG`n)CC Q`;|':OO/Vk!&rgXC`ERY)$?/:&||[xQۑޠVO>9C?EoDhF̄v|ky?pm͸ή> _:T;ҿY/ۙ5o(UYYTD{2jY}QVlxaui_2;;Kr5a}Xg |ǬV^]#w}M7] kt4iEZ>簮J[ԵOY 94)`6 `)+YK=VUՇ)uP=Rw1FԂ3;*qO6e7ΦHpV '݉83Grxvwۈc A6 oIdz'˖#r1|]8ӏܥʄ2dIS1eD98;TSbv ωd(Oh( >oҊ9<ES&Vm~D[Sۯ-1߶Q*u_{ endstream endobj 17 0 obj 1088 endobj 7 0 obj [ /ICCBased 16 0 R ] endobj 18 0 obj << /Length 19 0 R /N 3 /Alternate /DeviceRGB /Filter /FlateDecode >> stream xYy8U\yy,3|Mq]BHh )Q !)!T$CP yy箽::{3bcP,DP).V"^>" :)(>a*iO58$>VEC\)(B{wRcixb $ mbd8:n.ftc$(a0CHbP b1YĆA$(k: ;h2a'?0& l _lN"%o,`6/QX2S]ƭ(r 3B|5& b6[У߸/<bdP%x)dn(BBo,E@2%Sm~cQ1QvP!6pnH+CP İP)nCD#LߏtqL 77u( .4P>JuЌmG6p7k(m!BbARMivh)Q ysChr1]Rhr7pɖ3C,ՙs v@o$@a (iYKW>fmH*=|C4cjv"x,p8k%NAQ"u!; ,c={ vxwV~{ONaײJX 51rpa"Fzb1iBX'o,[$ǤE`O[ komt#Aн;4fte3Y?JZ$QarX8U!"61AJ "j*t.c5_Y~t෵_Y$_L)J9= 8>-N x0  RAY8΂bP *p4@̍)0w !"/"H""=x#H$ ~$ E"*r iC"s52|EVPh#%B)tP&(;C2PPgP%˨T 5C}C4 -VDNht(ރ>GkͰГyO Î(Ƹc0q=lYL%s3yYXy fb؛NLap8.4N~޸.\6w7{yx3V ~ NNΒ·.... 4*= $}0}2q2f'SV4F j q".V2>3 W0f(h˘xsE"(E4&c*b%; S0^BAO̒&ۙSo0?aggb1c!a)d2򍕝UՉ55! M͂---;]݌=}?{{'CÆ## G'gg!I.4 Wq\\+܂&!܇kyyyBxO6#%(Xt܈򌪋sЎ򱙱qzq(vx$/Ͻ 2 ^'&&FkRLRo\˔K0vmdO{3NWFHL{ss`ƾd2eR2G,>9D>wXp_G}v,:M[٧DISnFmCC]Om<:;29<:</VcǏLLxYJUݤ{߸{v]U3j3-}[̧Ɵ{Pl|^]XXjG~{sezu~̺z/_$ is-%*4`ϞkS.13*`B*@yng1ܘ"ѝ (1`^2~a"2lcMg>)}gO?Vp]1^qD䊴Ll rJjtݚT0:rݗz$jMFL;nWXYZNeK';8;;o wqv8yګػ§n[o_.'7!B"#CE_߱Mщ&%d't7y0e6[h^}ӪӇ: z#ʲ~>.x%';'{~>_HXW2S&vɷRDUIuSZ:kןnh6U~Yԝ/wWZ7}NBk{AÊG՞ޜڏ'j$ ?UzYpiT9_|dR`r7o9O),2blˇkW?Trʗ K:ߊ~Y_3Ż ׊[@hB9rAɣڪ[)a=9z_(aaf`&H갹S9Nq6sM"0#$)$rQ_6xòr% O*+GjM߀`Ţ\D'JWK=k eٰ萱)g Vւk6cvI>FNRDo[_ Jy/saԪ,*pR5-:{xC&awcNS٭ۣ-3w~ )wHg]#mj=J u|'D_`ww3aQz/,'|^F?Ya3<?^덥-?>jm?T8 A)@ޡ4PGPhGt3FSĶpK<:}K$F{$37 φ98.fn~)^M> ~`P1qfꑼ ##Sl܈^{$%DLZy^%WUWZ㚆sZM?Z.[/n)67aXfba`B1U3]47OвXlJַ^cط;d8Z;:m sQwEI}'f ߵtHρAO$zوǑעNE'0)P$4'JKvOśAcKK/~@/!G(هqHTyk~:C(P9]QT{n\PB)/k|R*tMPQGz |q Gn7ݎl9{ݥ{mqgv>}(w!+p1G" Ca6]E½,]~%/ˏuaK8\42#^o#yУ}o ȳaѝqEg dec^a`ef-dak``αƙ%u۟{ 60_"?vA!/apH(XVK򰔓4Ll{JEOJוwҫ]Rߩ᪩ūK-\U_ )cCI#zOMMa޴heuM5jbNT砭.ƮjnRB<\^\|>"d|;o  a;<;5*;#{t@uD I])C{tqd(8(yyQ*Fro0:{!$|ʰfVn6?nJlȢBPֳQ /&侻k?]YH]z]9Uտ7 ɒA'[P$_(I=*UzZ{vGt*=aL fˀ5&cpZd<t&tg G9-LLi,,m!lDFv?әsۇOoUPSpYp(X8ULSrFtLw8n)WխkkV_/onmviQֺqh=ep z<=ms"76oǧ3'?peWE%o)?R~&DR O &aEX<ҍ|:v5fBW0L1wl6v'ux 6])=}P̠0ʘA$03{p yȵ;ǖWO_]`]ЀpHhXxDF.Q9 EY%#ew(j5&tu_0746n7a&g"߲ߚhhkAqSVV?rEs3^_| o?%~ .LNU;EY$tKOۥzb^>=sSY!ǃO?炰oϽ-vpD%Uꏗî#]}}=ͨͬKhGnڵW/q瓴1bϟ%Np6izmOݧf>ϓ?F| l ˥_.[RYw˽?L4s}%|Us`u}-pm]x}/_~-ln?>TBMbƢ\s66VK66Kfc{QCSOTTFC]fhYռ endstream endobj 19 0 obj 6212 endobj 13 0 obj [ /ICCBased 18 0 R ] endobj 3 0 obj << /Type /Pages /MediaBox [0 0 612 792] /Count 1 /Kids [ 2 0 R ] >> endobj 20 0 obj << /Type /Catalog /Pages 3 0 R /Version /1.4 >> endobj 10 0 obj << /Type /Font /Subtype /TrueType /BaseFont /CIPXUP+Arial-BoldMT /FontDescriptor 21 0 R /Encoding /MacRomanEncoding /FirstChar 67 /LastChar 84 /Widths [ 722 0 0 0 0 0 0 0 0 0 0 0 0 667 0 0 0 611 ] >> endobj 21 0 obj << /Type /FontDescriptor /FontName /CIPXUP+Arial-BoldMT /Flags 32 /FontBBox [-628 -376 2000 1018] /ItalicAngle 0 /Ascent 905 /Descent -212 /CapHeight 805 /StemV 0 /Leading 33 /XHeight 604 /MaxWidth 2000 /FontFile2 22 0 R >> endobj 22 0 obj << /Length 23 0 R /Length1 9240 /Filter /FlateDecode >> stream xY xTյ^{sf&!Iy $I$ ə@`gH "|V"r28QG-Xb5_zm}]={&kZk8gtF E om'W-ZaË~c D?FHIXֺ83 gࣗ\qs,o-[47v!}Cӻ7^u ɘe;d\/jmȞRH,=J*lIh.zR_ yג<3}᫓>wd9$tUB8¹O9$hƝ8 uӧW9F⑨}]Dea@+B23 &y0SPv'uPv4;sEΐY'wOq1=Lf6)yH ~h3v(HQ+[ :*ފiVtDz)~+>*QՓ< T2R' t2AQi t[+['NW5 #?r<J^fzCd)iQORP|R&8 M"e2oBBӅwS$`IyL93˚)m "]Y ~ "\bJ~dgYګy2BUҩ NɦiLSX*$YIr:{L7+ P0߆sDAeb4Xu*CO>ceOCqe=lFXte ATMQꕑݵJ.oP.) j@~OMĤo2ZKpl'?*qx 5J7nZ7F# 1HF،SVQz@!i5"0"8zLYd"0%Civ(.IxL.2C Ie4PFfٲJJQ(3GڃРt1$LrIpnyuD։WQ$n~y_ ?xt- G#jm~"?}jc//|,.:_ z {HR˼nFG?h!LA/?+h !~@LqKC$ ;h rMat0?z~VS c N|KRT<`,6)%m6Jcu{lX|J28fAED8u!RiSJB{JJ|qԱo t+6ЏeINJ&@DDD;!Zn]"@ @$B" M@4DD4DMDMaaaaJ )&&DQD %QD %@HD %@H!D@@ D8p)N @8%bA A bP"bSzr( G%( G9:u1avv`$vH%DX@X@X D/@JD/@+@+=@DDD=D=~;9]lk?>omJk%_E|1Ԓw`A2ٛ-`&j2fn!]JG  slilm?dv<6ӶٶvȦ ڸrBh OAx R5/Gg++fIBv*d }/g  Scؙ{"CO@5=Ȟւ*Aeb* 󙣆<^JJObjl[p"ʼnv ?XP{.XPƱT سXT;wP?c~r``D6tU@ WlVP  B4v,Cѱ\A} GIAb{dWBp~S9L??@`1=1*w]iWz=}CY}{baeA};z^wח[zA}~@I~;Mpzꗻ \loM@d񥉢i"Tk-t>2RB){}>_bϵ9RNG#p8lH GM8'q*e'2ę495XD 905\5Jmk1lζ*=i{(0f_EEѺ+JZwON?12WTgVNMPI@<oÍs|֎\U&hѺ}ϓyb}]?OWyrlQav\a6'  aFabv.O0'RˏOv*v}nj> lDǤ17}3غ|$r'eHʊt&H`'+ҙlw=dRqޤBՈդ9g66j<,Tڹ6W}U XV,ɴFN0,%?p[۬NW[UgJܷ/ u^ohKzWk?T]^m*QOU-qj+բ-h+ڪ6e[Kżo9_q<ćcr5bBO\O%yVJ U+TXgB!U)y9!):7$VŬF+o<*|ט-TgR:!!cyǹ'aOw=;tz5Zs ݎu~]zLQdY_\\}8:Nќ<̃d#;ڹ8Ets˖w|eW B24ʍLU8"+C J@wǸR SS-Aw mUMsGh\p<g9:grd/}rY0R!"B)r 8KJa"\xU>))E(4z\`' 'Hm6b)bYav~n:KxLT\TxnXtEc~B[ϱG_ƬKm!?#a4ftj~<@үmѯjE}U%o*Xܳt?gR|!n}OO.aG:ze)",(!4h%uz&v*zk#4>-Yη ѩ?|꧗_POi#_D_92޳G>|*EDft=O/?,,g|]޶NLi_h>di,}-dQS(oL"7bA[i/^#LC%]Ö_AnKաޡ~#3̝MߧU}B@­ d ;(>qz~ZܯRC9QP/Q;USumi팍۲m#mlضf'؛ohg#Y!<70?< kkIԑ{0s*EJ$mR T-|vTWaRe'`YS +T˲kv 񚡞,G-kc=8}bgeGо4"WrچPv!Nbq=PD&jz|zhG_EؕK-F a$uI5l%p$\~O>`"3R 1QCE2qFT `j?J/mu* cb+uD٬zYՔɓ&VV/+-wiqp옂|hרs!,79yu 4}7FQ,:4Â[*ֿIư\5%04;%/mG)nnd_uϾ%eYk)%% NJ\HG ]=n xsOE6M3V\m9YN9aNuv~NB)fsXbk1qW v'F& HMm8?/O I fby 01Whi.=ނFXK&[,Ps\8݁Y|Q.Eܠ>%LH0dp|j}re)?_*l F7* d~dYey)~1>iVJzHB.xɉj)uD+bQd:).q";,by945P]0rشW|Gv&ez_Tj*<$/%/ōrtPΘ}M: %YUvH6rDA%u{]A嬞A7[n~r勖'?;Ig?x#ZJK0ͦ JqRFR&Lv"nd[Yedo]/s݇S WY 7Itcp6$+ut۴LrH{K)Ĥ$q1=ɑ^"$qE?t=$7۞ە: fY:E1ӝ7~A_1bPS'J-7)Sl6+W* ]٫w,k^~~W]QѫK{oҔgV_.]mZ?vt+QK8i܍o;9225¬،qX~#$5{ʳgwqU?kH 3`zVKaGDf/|SQ|vLV. S> endobj 24 0 obj << /Type /FontDescriptor /FontName /MEKPRU+Arial-BoldItalicMT /Flags 96 /FontBBox [-560 -376 1390 1018] /ItalicAngle -6 /Ascent 905 /Descent -212 /CapHeight 625 /StemV 0 /Leading 33 /XHeight 584 /MaxWidth 1333 /FontFile2 25 0 R >> endobj 25 0 obj << /Length 26 0 R /Length1 8424 /Filter /FlateDecode >> stream xYy|Tսf&d!+2w$&ܬ# `I$%EIWZ m(N VԥJmjUZŧB}὾ǻw~緞s~w{Ι[F$2ZKk%6dWrN"嫫W޸scXֵ p 'X]r͒a}O'a~:^_ݵjc?\v͆|ͯ_6lm~=ZBP ],K4rA2x[h:Rj>s9Te|p񂯶9s#>#6mrjjۗs|'z.QZJsÐfG'U1ivwD9pKbgV8:Ro-6]e[-e^'- I)u#Y1@Z;qL)H-.ѾΟKaaܐf74o9$͠]?0 -_YiU4tA.@ʼn0lX;;/̈́j&ى( IـN.#l,fl7ioyKW#tkbvnoy@85bRM_SWF]x 2-N1 =`(yboh#Vڴae6]fӺM6Gi<!!1 :AMRibO]D2,Kkz>a@R-A)H}KR 8p>l۝d P+*UeUJdlkkAͶdLR oD_'~9W#_[cs+<|e<7 a<Є EC*wx9A!qPrPF8(AJsP`а3AǙLq&8t :g3AǙLq&8t :g3AǙLq&8! xA/:W:b$@*eW>̀MN8@16zizQ疦N,M>֣j j j j ]H:!UG;kkP~U ^-p|K\ LdJS,Ve,0F"[lv'EW8L>m/a4}d }/BxY"hI +ZTte4}_˪`v[4/jsJ-WP < 8Bboe0&sE0&}{(C7, 6R|o{߳E_tH~4x}a0Ⱥ)׷E5>z?@*xoYV_g~_G(b\ ~]n~_P7X~F}uEvJ`#7o |8247~;@7=雟NrOqzzkRX-z QZ%Z+u%]˥dp+#4JKY교*[l^aH`fKaWoVcZ|98lZlc;bIK(X7O 3gL S>wƘZ0ʭ i mĜs]y8ih;5:xC27fצMK/N[X5Y\nq~Wb{-66s%"Dy-2D"mrnkH$.Hq-d.Nu|"˲+%m~Զٲ֛t$ u6f;(VH,aYqG`ee0&.mGM}lQjLXck?2cv ' ֍TV o;  6oP/.4innt~eΆ6ZφF6R siZit6F wN&Ijl~7^#nx[#T(Vztnhb~nMG 6B!+`|͍P0 T `EA|0(*F!AużbRP ?<kZw߰t`PrMq'Ezs6+2)Έ|YF0ZiE?>=ԇ~˜|]#{A0Zd( RXK) 9o FDMH?/"DɴJXQ-㫨3J ʽZMgmFPoBZaOYJ#cnU#XBZ _쒯w(Cs4UP5ZAiL|R~VDB N&s*=q8*>ng}*2ōKIS)*Ki.-V)JO!ψYRtd_ =Bt3ӯM[C/.=,,}˷v(ᝇo~@{i??Uzޅ|-oA>_ -jğLi*^Sz9,O/^u =:{㿈$xFס][ɟxow{Ũ#N<ϰ A~KtR5O/о/EToF2;k]bzVKW!mOĺ}/?FOF5S&OXU9||Y鸱%š1E‚huȼܜiޔۥ,@snvra`肠AC|[Ҁfi8yK5T3Do += 紁1͓6=˦BI#ޔQ7So27il[} @2$Lefq4 l'ᔚ6&3'(F*hZjikj#cKLnXXl+MTLͮF^Ȥo}%{vļ8qi`iע6SBMfj1m4nz'kc+yDž<)[{zs.țJDPΞfT]٥prjӨe&Kyn=tCr{L{?k `/ۤfm^ 8/z؟c9kƖySh% IiGgSE'[f`ciKtx@CdY5,FD̥nlJ6o@큓^,RZ3m5.t$|fcK6ĂZQKE&"~իߊuN8/JF)6Ҡ͈f9 ǭ00])M?}x^ m9eE mV'ѽDZ `rJb 9hSJ74`?,5y\٤OJ'r\Lq>]sr5P-h$$ 3tWˇ-_W)qU|JSi݃WI>Fo|D9ɦ6>LG~{Mopߔ#qk\Y,nVITM#DRHԔtHx:`2HRl"T/eI.3jJMQ9$ 7Frƚ*7n{;蕼1qib4W^VѤFN!RדWeI9G: / WM֭wgAھe⚳`jP'9NMykjZM eמ-no_W>)l>:ƧQud|[~a- +&VM( 5UӤC.ٝ52gyOloW.|OVm+5e|V8 KtN*c 6КbijCerU٧@G8Vz?k8aIb4פAijQ2exᘬ?YlڏvsuQCV|ٌ97%?~fLslW9_/弘+ƈ(-siڌr952kzZoPҲ? QaVН>cj\ZMԣPw8.9U-)UQc62<2#kM;<3˚ 'qpjO[`ft/iх<}#22+'VmY}p{jm|զ8c[CCCwpo֢ۖDXc$ơd!4I2<*iRKN)PON/Z WO&Oj= vy=<ޟ]u{7i7$S Wjs\-Vϵ[*JLT'&7VDr:V dzjR F_x0(8AIPɓ9 Pd,ȚutNHLD]nItPD&`'Ąndyh>̃{?z`{[ֿ2?M?4<u*1IVMZfhk^m3䷄И?ivOџxOԧ`jV`x!@ܧVz XK:JغWax&i6RD~RE:dSCo0+> endobj xref 0 29 0000000000 65535 f 0000149703 00000 n 0000000368 00000 n 0000136301 00000 n 0000000022 00000 n 0000000349 00000 n 0000000571 00000 n 0000129892 00000 n 0000000760 00000 n 0000126414 00000 n 0000136448 00000 n 0000143187 00000 n 0000128634 00000 n 0000136264 00000 n 0000126436 00000 n 0000128613 00000 n 0000128679 00000 n 0000129871 00000 n 0000129928 00000 n 0000136243 00000 n 0000136384 00000 n 0000136664 00000 n 0000136904 00000 n 0000143166 00000 n 0000143413 00000 n 0000143660 00000 n 0000149590 00000 n 0000149611 00000 n 0000149661 00000 n trailer << /Size 29 /Root 20 0 R /Info 1 0 R /ID [ <84b9f74159161366b90cc89d41305ef7> <84b9f74159161366b90cc89d41305ef7> ] >> startxref 149778 %%EOF tcpflow-tcpflow-1.6.1/doc/tcpflow.1.in000066400000000000000000000434631401360461700175770ustar00rootroot00000000000000.\"edit the file tcpflow.1.in, not tcpflow.1" .\"" .\"" .TH tcpflow 1 "2013-04-13" "tcpflow @VERSION@" "tcpflow @VERSION@" .SH NAME tcpflow \- TCP flow recorder .SH SYNOPSIS .na .B tcpflow [\c .BI \-aBcCDIpsZ\fR\c ] [\c .BI \-b \ max_bytes\fR\c ] [\c .BI \-d \ debug_level\fR\c ] [\c .BI \-[eE] \ scanner\fR\c ] [\c .BI \-f \ max_fds\fR\c ] [\c .BI \-F[ctTXMkmg]\fR\c ] [\c .BI \-h\fR\c |\c .BI \--help\fR\c ] [\c .BI \-i \ iface\fR\c ] [\c .BI \-l \ file1.pcap\ file2.pcap...\fR\c ] [\c .BI \-L \ semlock\fR\c ] [\c .BI \-m \ min_bytes\fR\c ] [\c .BI \-o \ outdir\fR\c ] [\c .BI \-r \ file1.pcap\fR\c ] [\c .BI \-R \ file0.pcap\fR\c ] [\c .BI \-S \ name=value\fR\c ] [\c .BI \-T[filename\ template]\fR\c ] [\c .BI \-U\fR\c |\c .BI \--relinquish-privileges \ username\fR\c ] [\c .BI \-v\fR\c |\c .BI \--verbose\fR\c ] [\c .BI \-V\fR\c |\c .BI \--version\fR\c ] [\c .BI \-w \ file\fR\c ] [\c .BI \-x \ scanner\fR\c ] [\c .BI \-X \ file.xml\fR\c ] [\c .BI \-z\fR\c |\c .BI \--chroot \ directory\fR\c ] [\c .BI expression\fR\c ] .SH DESCRIPTION .LP .B tcpflow is a program that captures data transmitted as part of TCP connections (flows), and stores the data in a way that is convenient for protocol analysis or debugging. Rather than showing packet-by-packet information, \fBtcpflow\fP reconstructs the actual data streams and stores each flow in a separate file for later analysis. \fBtcpflow\fP understands TCP sequence numbers and will correctly reconstruct data streams regardless of retransmissions or out-of-order delivery. \fBtcpflow\fP provides control over filenames for automatic binning of connections by protocol, IP address or connection number, and has a sophisticated plug-in system for decompressing compressed HTTP connections, undoing MIME encoding, or calling user-provided programs for post-processing. .LP By default \fBtcpflow\fP stores all captured data in files that have names of the form: .in +.5i .nf \fB192.168.101.102.02345-010.011.012.013.45103\fP .fi .in -.5i \,...where the contents of the above file would be data transmitted from host 192.168.101.102 port 2345, to host 10.11.12.13 port 45103. .LP If you want to simply process a few hundred thousand packets and see what you have, try this: .in +.5i .nf \fBtcpflow -a -o outdir -Fk -r packets.pcap\fP .fi .in -.5i This will cause \fBtcpflow\fP to perform (-a) all processing, store the output in a directory called .BI outdir, bin the output in directories of 1000 connections each, and read its input from the file \fBpackets.pcap\fP. More sophisticated processing is possible, of course. .SH OPTIONS .TP .B \-a Enable all processing. Same as .B \-e all. .TP .B \-B Force binary output even when printing to console with .B -C or .B -c. .TP .B \-b \fImax_bytes\fP Specifies the maximum size of a captured flow. Any bytes beyond \fImax_bytes\fP from the first byte captured will be discarded. The default is to store an unlimited number of bytes per flow. \fBNote:\fP before version 1.4, \fBtcpflow\fP could only store a maximum of 4GiB per flow. .TP .B \-c Console print. Print the contents of packets to stdout as they are received, without storing any captured data to files (implies \fB\-s\fP). .TP .B \-C Console print without the packet source and destination details being printed. Print the contents of packets to stdout as they are received, without storing any captured data to files (implies \fB\-s\fP). .TP .B \-D Console output should be in hex. .TP .B \-d Debug level. Set the level of debugging messages printed to stderr to \fIdebug_level\fP. Higher numbers produce more messages. .B \-d 0 causes completely silent operation. .B \-d 1 , the default, produces minimal status messages. .B \-d 10 produces verbose output equivalent to .B \-v . Numbers higher than 10 can produce a large amount of debugging information useful only to developers. .TP .B \-E name Disable all scanners and then enable scanner .B name .TP .B \-e name Enable scanner .B name. .TP .B \-e all Enables all scanners. Same as .B \-a .TP .B \-e http Perform HTTP post-processing ("After" processing). If the output file is .in +.5i .nf \fB208.111.153.175.00080-192.168.001.064.37314,\fP .fi .in -.5i Then the post-processing will create the files: .in +.5i .nf \fB208.111.153.175.00080-192.168.001.064.37314-HTTP\fP \fB208.111.153.175.00080-192.168.001.064.37314-HTTPBODY\fP .fi .in -.5i If the HTTPBODY was compressed with GZIP, you may get a third file as well: .in +.5i .nf \fB208.111.153.175.00080-192.168.001.064.37314-HTTPBODY-GZIP\fP .fi .in -.5i Additional information about these streams, such as their MD5 hash value, is also written to the .B DFXML report file. .TP .B \-e python \-S py_path=path \-S py_module=module \-S py_function=foo Post-process TCP payload by an external python function. .RS .PP The python function must take a single string parameter. The python function can return a string (else the function does must not return). The returned string (if any) is written in the .B DFXML report file inside the XML tag \fB...\fP. A sample python script is available within the tcpflow source code in directory \fBpython/plugins\fP. .PP Example: .PP .nf \fBtcpflow -r my.cap -e python -S py_path=python/plugins -S py_module=samplePlugin -S py_function=sampleFunction\fP .fi .RE .TP .B \-F[format] Specifies format for output filenames. .RS .TP Format specifiers: .TP .B c Appends the connection counter to ALL filenames. .TP .B t Prepends each filename with a Unix timestamp (seconds since epoch). .TP .B T Prepends each filename with an ISO-8601 timestamp. .TP .B X Do not output any files (other than the .B DFXML report file). .RE .TP .B \-FM Include MD5 of each flow in the .B DFXML report file. .TP .B \-FX Suppresses file output entirely, .B DFXML report file is still produced. .TP .B \-Fk bin output in 1K directories .TP .B \-Fm bin output in 1M directories (2 levels) .TP .B \-Fg bin output in 1G directories (3 levels) .TP .B \-f\fImax_fds\fP Max file descriptors used. Limit the number of file descriptors used by \fBtcpflow\fP to \fImax_fds\fP. Higher numbers use more system resources, but usually perform better. If the underlying operating system supports the .B setrlimit() system call, the OS will be asked to enforce the requested limit. The default is for \fBtcpflow\fP to use the maximum number of file descriptors allowed by the OS. The .B \-v option will report how many file descriptors \fBtcpflow\fP is using. .TP .B \-g Output flow information to console in multiple colors. (Blue for client to server flows, red for server to client flows, green for undecided flows.) Note: This option was different from \fBtcpflow\fP 1.3 (-e) and 1.4.4 (-J). .TP .B \-h \--help Help. Print usage information and exit. .TP .B \-hh More help. Print more usage information and exit. .TP .B \-i \fIiface\fP Interface name. Capture packets from the network interface named \fIiface\fP. If no interface is specified with .B \-i , a reasonable default will be used by libpcap automatically. .TP .B \-I Store the reception timestamps (of TCP packets) in a companion file \fB*.findx\fP. Therefore each flow will have two files: (1) the usual file containing payload bytes and (2) the text file containing the corresponding timestamps. This last file \fB*.findx\fP has three columns using the pipe \fB'|'\fP as separator: .nf \fBbyte-index|timestamp|length\fP .fi The \fBbyte-index\fP column is the postion within the file containing the payload bytes. The \fBtimestamp\fP column represents the number of seconds since epoch as a floating point number. The precision is the microsecond but may also be the nanosecond in a future \fBtcpflow\fP version. The \fBlength\fP column is the number of successive bytes concerned by \fBtimestamp\fP and can include several TCP frames (TCP packets). The extension \fBfindx\fP may become from the fact that the timestamps are \fBframe indexed\fP. .TP .B \-L \fIsemlock_name\fP Specifies that \fIsemlock_name\fP should be used as a Unix semaphore to prevent two different copies of \fBtcpflow\fP running in two different processes but outputting to the same standard output from printing on top of each other. This is an application of Unix named semaphores; bet you have never seen one before. .TP .B \-l Treat the following arguments as filenames with an assumed \fB-r\fP command before each one. This allows you to read a lot of files at once with shell globbing. For example, to process all of the pcap files in the current directory, use this: .in +.5i .nf \fBtcpflow -o out -a -l *.pcap\fP .fi .in -.5i .TP .B \-m \fImin_size\fP Forces a new connection output file when there is a skip in the TCP session of \fImin_size\fP bytes or more. .TP .B \-o \fIoutdir\fP Specifies the output directory where the transcript files will be written. .TP .B \-P No purge. Normally \fBtcpflow\fP removes connections from the hash table after the connection is closed with a FIN. This conserves memory but takes additional CPU time. Selecting this option causes the std::tr1:unordered_map to grow without bounds, as \fBtcpflow\fP did prior to version 1.1. That makes \fBtcpflow\fP run faster if there are less than 10 million connections, but can lead to out-of-memory errors. .TP .B \-p No promiscuous mode. Normally, \fBtcpflow\fP attempts to put the network interface into promiscuous mode before capturing packets. The \fB-p\fP option tells \fBtcpflow\fP \fInot\fP to put the interface into promiscuous mode. Note that it might already be in promiscuous mode for some other reason. .TP .B \-q Quiet mode --- don't print warnings. Currently the only warning that \fBtcpflow\fP prints is a warning when more than 10,000 files are created that the user should have provided the \fB-Fk\fP, \fB-Fm\fP, or \fB-Fg\fP options. We might have other warnings in the future. .TP .B \--relinquish-privileges\fB=\fIusername\fP When \fBtcpflow\fP is run as root, this option changes the user ID and group ID to write files owned by \fIusername\fP. The group ID is the first one from the \fIusername\fP groups list. This operation is performed just after opening the capture device or just after opening the first input PCAP file. This option does not support multi root-only readable input files as the root privileges are dropped after opening the first file (e.g. .B \-r \fIroot-only-access.pcap\fP .B \-R \fIroot-only.pcap\fP .B \-l \fIroot-only*.pcap\fP\c ). This option has the same behaviour as the .IR tcpdump (1) option having the same name .B \--relinquish-privileges\fB . .TP .B \-r Read from file. Read packets from \fIfile\fP, which was created using the .B \-w option of .IR tcpdump (1). This option may be repeated any number of times. Standard input is used if \fIfile\fP is "-". Note that for this option to be useful, tcpdump's .B \-s option should be used to set the snaplen to the MTU of the interface (e.g., 1500) while capturing packets. .TP .B \-R Read from a file, but only to complete TCP flows. This option is used when .IR tcpflow is used to process a series of files that are captured over time. For each time period \fIn,\fP file \fIfile(n).pcap\fP should be processed with \fB-R \fIfile(n).pcap\fP, while \fIfile(n-1).pcap\fP should be processed with \fI-r file(n-1).pcap.\fP .TP .B \-S\fIname\fB=\fIvalue\fP Sets a \fIname\fP parameter to be equal to \fIvalue\fP for a plug-in. Use \fB-hh\fP to find out all of the settable parameters. .TP .B \-s Strip non-printables. Convert all non-printable characters to the "." character before printing packets to the console or storing them to a file. .TP .B \-T[format] Specifies an arbitrary template for filenames. .RS .TP .B %A expands to source IP address. .TP .B %a expands to source IP port. .TP .B %B expands to destination IP address. .TP .B %b expands to destination IP port. .TP .B %T expands to timestamp in ISO8601 format. .TP .B %t expands to timestamp in Unix time_t format. .TP .B %V expands to "--" if a VLAN is present. .TP .B %v expands to the VLAN number if a VLAN is present. .TP .B %C expands to "c" if the connection count>0. .TP .B %c expands to the connection count if the connection count>0. .TP .B %# always expands to the connection count. .TP .B %N (connection_number ) % 1000 .TP .B %K (connection_number / 1000) % 1000 .TP .B %M (connection_number / 1000000) % 1000 .TP .B %G (connection_number / 1000000000) % 1000 .TP .B %% prints a "%". .TP .RE When the option \fB\-T\fP is used, \fBtcpflow\fP ignores options \fB\-Fk\fP, \fB\-Fm\fP and \fB\-Fg\fP. However, the option \fB\-T\fP handles \fB'/'\fP within the filename template patern to create sub-directories. For example the following line will create a directory tree \fBout/IP-src/port-src/IP-dst/port-dst\fP. .nf \fBtcpflow -r packets.pcap -o out -T %A/%a/%B/%b/%c%N.flow\fP .fi .TP .B \-V \--version Print the version number and exit. .TP .B \-v \--verbose Verbose operation. Verbosely describe \fBtcpflow\fP's operation. Equivalent to \fB \-d 10\fP. .TP .B \-w \fIfilename.pcap\fP Write packets that were not processed to \fIfilename.pcap\fP. Typically this will be UDP packets. .TP .B \-X \fIfilename.xml\fP Write a .B DFXML report to \fIfilename.xml\fP. The file contains a record of every tcp connection, how the \fBtcpflow\fP program was compiled, and the computer on which \fBtcpflow\fP was run. By default .B tcpflow writes the .B DFXML report in file \fIreport.xml\fP. .TP .B \-Z Don't decompress gzip-compressed streams. .\"START -- tcpdump excerpt" .B \-K Retain per flow isolated pcap structure. .TP \fIexpression\fP selects which packets will be captured. If no \fIexpression\fP is given, all packets on the net will be captured. Otherwise, only packets for which \fIexpression\fP is `true' will be captured. .IP For the \fIexpression\fP syntax, see .BR pcap-filter (7). .IP The \fIexpression\fP argument can be passed to \fItcpflow\fP as either a single Shell argument, or as multiple Shell arguments, whichever is more convenient. Generally, if the expression contains Shell metacharacters, such as backslashes used to escape protocol names, it is easier to pass it as a single, quoted argument rather than to escape the Shell metacharacters. Multiple arguments are concatenated with spaces before being parsed. .SH DFXML report .LP The .B DFXML report is the XML file written by .B tcpflow to provide .B tcpflow build details, command line arguments and information about processed flows. .LP By default the .B DFXML file is named \fIreport.xml\fP. But this filename can be changed using command line option \fB\-X\fP. .LP .B DFXML file respects the .B DFXML schema defined by project \fIhttps://github.com/dfxml-working-group/dfxml_schema\fP. .br Moreover .B tcpflow adds two extra XML tags, as illustrated by the following example: .RS .nf \fB bla bla bla \fP .fi .RE .LP The first XML tag \fB\fP provide information about the captured flow. This tag should be renamed \fB\fP in a future version in order to conform better to \fBDFXML schema\fP. .LP The second XML tag \fB\fP collects processing results. For the moment, only the scanner \fIpython\fP uses this feature. .PP The XML attributes of \fB\fP are: .IP \(bu \fBstartime\fP Reception time of first packet .IP \(bu \fBendtime\fP Reception time of last packet .IP \(bu \fBfamily\fP .IP \(bu \fBmac_daddr\fP Destination MAC address of first packet (printed if any) .IP \(bu \fBmac_saddr\fP Source MAC address of first packet (printed if any) .IP \(bu \fBsrc_ipn\fP IP source .IP \(bu \fBdst_ipn\fP IP destination .IP \(bu \fBsrcport\fP TCP port source .IP \(bu \fBdstport\fP TCP port destination .IP \(bu \fBpackets\fP Nummber of packets .IP \(bu \fBout_of_order_count\fP Number of times .B tcpflow has replaced missing payload by zeros in the flow file, for example when capture does not contain the TCP session begin (printed if any) .IP \(bu \fBviolations\fP Number of protocol violations (printed if any) .IP \(bu \fBlen\fP Sum of un-truncated length of all packet data (including headers, see https://stackoverflow.com/q/1491660) .IP \(bu \fBcaplen\fP Sum of captured bytes of all packet data (including headers, printed if different from \fBlen\fP) .PP The XML attributes of \fB\fP are: .IP \(bu \fBscanner\fP Name of the scanner .IP \(bu \fBpath\fP Directory of the scanner module (printed if relevant) .IP \(bu \fBmodule\fP Module name (printed if relevant, used to indicate the python script) .IP \(bu \fBfunction\fP Function name (printed if relevant, used to indicate the function within the python module) .SH EXAMPLES .LP To record all packets arriving at or departing from \fIsundown\fP and extract all of the HTTP attachments: .RS .nf \fBtcpflow -e http -o outdir host sundown\fP .fi .RE .LP To record traffic between \fIhelios\fR and either \fIhot\fR or \fIace\fR and bin the results into 1000 files per directory and calculate the MD5 of each flow: .RS .nf \fBtcpflow -X report.xml -e md5 -o outdir -Fk host helios and \\( hot or ace \\)\fP .fi .SH BUGS Please send bug reports to simsong@acm.org. .LP \fBtcpflow\fP currently does not understand IP fragments. Flows containing IP fragments will not be recorded correctly. .SH AUTHORS Originally by Jeremy Elson . Substantially modified and maintained by Simson L. Garfinkel . Network visualization code by Michael Shick .LP The current version of this software is available at .RS .I http://digitalcorpora.org/downloads/tcpflow/ .LP .RE An announcement mailing list for this program is at: .RS .I http://groups.google.com/group/tcpflow-users .RE .SH "SEE ALSO" tcpdump(1), nit(4P), bpf(4), pcap(3), pcap-savefile(5), pcap-filter(7) tcpflow-tcpflow-1.6.1/doc/timeline_1.4.txt000066400000000000000000000060201401360461700203470ustar00rootroot00000000000000Timeline for 1.4 ship: + mfs + Document the refactored class hiearchy for one-page-report. + slg will look at before mfs begins refactoring + plot becomes abstract + pure virtual destructor (protected constructor too?) + concrete render(cairo_t, bounds_t) + pure virtual render_data(cairo_t, bounds_t) - This is called by render, which will calculate the bounds within the axes, labels etc. - sublcasses need only override render_data, plot() owns the space given to it - time_histogram split into time_histogram and time_histogram_plot - time_histogram_plot is a concrete subclass of plot - contains pointer to const time_histogram and probably not too much else - time_histogram replaces dyn_time_histogram - time_histogram now contains a vector of maps and a const pointer to the best fit histogram (best fit map) which starts as the most granular histogram and is updated as histograms are dropped for overflow - implement [], size() directly on time_histogram to hide implementation and selection - port_histogram and address_histogram are similarly split - histogram_bar class is added - map (or fixed bucket uints?) values to counts - render(cairo_t, bounds_t, color_map) will fill region with a proportional bar by counts - with a flexible enough histogram_bar class, time_histogram_plot, port_histogram_plot, and address_histogram_plot can be merged into templated histogram_plot concrete subclass of plot if desired - packet intestion logic is moved to one_page_report; histograms are simply data structures - could create ingester class instead too Features needed: ================ - Packet Grid - Documentation (NPS Report) What we are not doing: ====================== - Traffic Map - Language identification - Keyword extraction & clustering - Passive DNS Test Plan: ========== - Performance testing Packaging: ---------- - Put relevant boost headers in boost subdirectory Compile testing: ---------------- Make sure that it compiles on these platforms: - FC17 - Ubuntu - OS10.6, 10.8 - cygwin - mingw - Centos 5.8 - Centos 6.0 - SUSE Reliability testing: -------------------- Test for crashing with all scanners on with specific data sets: - no packets - Lincoln Labs ID98 - One day - All of the packets concatenated together - Lincoln Labs ID99 (All of the packets concatenated together) - One day - All of the packets concatenated together - One day from ID98 & One day from ID99 - M57 Patents - One day - All packets concatenated together - NGDC 2012 - All packets concatenated together - Cada? Correctness testing: -------------------- Create a file of all MD5s of all TCP streams. Sort the file. Use "diff" Data Sets for comparison: - ID98 one day - M57 one day Compare results of: - tcpflow 1.4 with tcpflow 1.0 - Question: Can Suricata provide the MD5 of tcp streams? Packaging: ---------- - .tar.gz file distributed on digitalcorpora. - windows executables on digitalcorpora - downloadable tag from github Announcements: ------------- tcpflow-tcpflow-1.6.1/etc/000077500000000000000000000000001401360461700154265ustar00rootroot00000000000000tcpflow-tcpflow-1.6.1/etc/coverage_report.sh000066400000000000000000000010531401360461700211470ustar00rootroot00000000000000#!/bin/bash # # Create a code-coverage report locally and upload one to codecov # Should be run from the root directory if [ -r coverage_report.sh ]; then echo "coverage_report.sh run in /etc directory. moving to .." cd .. fi #make distclean #CFLAGS="--coverage" CXXFLAGS="--coverage" LDFLAGS="--coverage" ./configure make check lcov --capture --directory . --output-file main_coverage.info genhtml main_coverage.info --output-directory out # Upload the coverage report bash <(curl -s https://codecov.io/bash) /bin/rm -f *.gcov *.gcda *.gcno tcpflow-tcpflow-1.6.1/etc/install_autotools.sh000066400000000000000000000021511401360461700215400ustar00rootroot00000000000000#!/bin/sh # Originally from https://gist.github.com/GraemeConradie/49d2f5962fa72952bc6c64ac093db2d5 # Install gnu autotools for running under github actions ## # Install autoconf, automake and libtool smoothly on Mac OS X. # Newer versions of these libraries are available and may work better on OS X ## export build=~/devtools # or wherever you'd like to build mkdir -p $build ## # Autoconf # https://ftpmirror.gnu.org/autoconf cd $build curl -OL https://ftpmirror.gnu.org/autoconf/autoconf-2.69.tar.gz tar xzf autoconf-2.69.tar.gz cd autoconf-2.69 ./configure --prefix=/usr/local make sudo make install export PATH=$PATH:/usr/local/bin ## # Automake # https://ftpmirror.gnu.org/automake cd $build curl -OL https://ftpmirror.gnu.org/automake/automake-1.16.tar.gz tar xzf automake-1.16.tar.gz cd automake-1.16 ./configure --prefix=/usr/local make sudo make install ## # Libtool # https://ftpmirror.gnu.org/libtool cd $build curl -OL https://ftpmirror.gnu.org/libtool/libtool-2.4.6.tar.gz tar xzf libtool-2.4.6.tar.gz cd libtool-2.4.6 ./configure --prefix=/usr/local make sudo make install echo "Installation complete." tcpflow-tcpflow-1.6.1/gitpull.sh000066400000000000000000000003071401360461700166670ustar00rootroot00000000000000#!/bin/sh # http://stackoverflow.com/questions/5828324/update-git-submodule # pull root and subprojects git pull for dir in src/be13_api do pushd $dir git checkout master git pull popd done tcpflow-tcpflow-1.6.1/m4/000077500000000000000000000000001401360461700151735ustar00rootroot00000000000000tcpflow-tcpflow-1.6.1/m4/ac_check_classpath.m4000066400000000000000000000015361401360461700212240ustar00rootroot00000000000000dnl @synopsis AC_CHECK_CLASSPATH dnl dnl AC_CHECK_CLASSPATH just displays the CLASSPATH, for the edification dnl of the user. dnl dnl Note: This is part of the set of autoconf M4 macros for Java dnl programs. It is VERY IMPORTANT that you download the whole set, dnl some macros depend on other. Unfortunately, the autoconf archive dnl does not support the concept of set of macros, so I had to break it dnl for submission. The general documentation, as well as the sample dnl configure.in, is included in the AC_PROG_JAVA macro. dnl dnl @category Java dnl @author Stephane Bortzmeyer dnl @version 2000-07-19 dnl @license GPLWithACException AC_DEFUN([AC_CHECK_CLASSPATH],[ if test "x$CLASSPATH" = x; then echo "You have no CLASSPATH, I hope it is good" else echo "You have CLASSPATH $CLASSPATH, hope it is correct" fi ]) tcpflow-tcpflow-1.6.1/m4/ac_check_junit.m4000066400000000000000000000032721401360461700203720ustar00rootroot00000000000000dnl @synopsis AC_CHECK_JUNIT dnl dnl AC_CHECK_JUNIT tests the availability of the Junit testing dnl framework, and set some variables for conditional compilation of dnl the test suite by automake. dnl dnl If available, JUNIT is set to a command launching the text based dnl user interface of Junit, @JAVA_JUNIT@ is set to $JAVA_JUNIT and dnl @TESTS_JUNIT@ is set to $TESTS_JUNIT, otherwise they are set to dnl empty values. dnl dnl You can use these variables in your Makefile.am file like this : dnl dnl # Some of the following classes are built only if junit is available dnl JAVA_JUNIT = Class1Test.java Class2Test.java AllJunitTests.java dnl dnl noinst_JAVA = Example1.java Example2.java @JAVA_JUNIT@ dnl dnl EXTRA_JAVA = $(JAVA_JUNIT) dnl dnl TESTS_JUNIT = AllJunitTests dnl dnl TESTS = StandaloneTest1 StandaloneTest2 @TESTS_JUNIT@ dnl dnl EXTRA_TESTS = $(TESTS_JUNIT) dnl dnl AllJunitTests : dnl echo "#! /bin/sh" > $@ dnl echo "exec @JUNIT@ my.package.name.AllJunitTests" >> $@ dnl chmod +x $@ dnl dnl @category Java dnl @author Luc Maisonobe dnl @version 2001-03-02 dnl @license AllPermissive AC_DEFUN([AC_CHECK_JUNIT],[ AC_CACHE_VAL(ac_cv_prog_JUNIT,[ AC_CHECK_CLASS(junit.textui.TestRunner) if test x"`eval 'echo $ac_cv_class_junit_textui_TestRunner'`" != xno ; then ac_cv_prog_JUNIT='$(CLASSPATH_ENV) $(JAVA) $(JAVAFLAGS) junit.textui.TestRunner' fi]) AC_MSG_CHECKING([for junit]) if test x"`eval 'echo $ac_cv_prog_JUNIT'`" != x ; then JUNIT="$ac_cv_prog_JUNIT" JAVA_JUNIT='$(JAVA_JUNIT)' TESTS_JUNIT='$(TESTS_JUNIT)' else JUNIT= JAVA_JUNIT= TESTS_JUNIT= fi AC_MSG_RESULT($JAVA_JUNIT) AC_SUBST(JUNIT) AC_SUBST(JAVA_JUNIT) AC_SUBST(TESTS_JUNIT)]) tcpflow-tcpflow-1.6.1/m4/ac_check_rqrd_class.m4000066400000000000000000000017511401360461700213760ustar00rootroot00000000000000dnl @synopsis AC_CHECK_RQRD_CLASS dnl dnl AC_CHECK_RQRD_CLASS tests the existence of a given Java class, dnl either in a jar or in a '.class' file and fails if it doesn't dnl exist. Its success or failure can depend on a proper setting of the dnl CLASSPATH env. variable. dnl dnl Note: This is part of the set of autoconf M4 macros for Java dnl programs. It is VERY IMPORTANT that you download the whole set, dnl some macros depend on other. Unfortunately, the autoconf archive dnl does not support the concept of set of macros, so I had to break it dnl for submission. The general documentation, as well as the sample dnl configure.in, is included in the AC_PROG_JAVA macro. dnl dnl @category Java dnl @author Stephane Bortzmeyer dnl @version 2000-07-19 dnl @license GPLWithACException AC_DEFUN([AC_CHECK_RQRD_CLASS],[ CLASS=`echo $1|sed 's/\./_/g'` AC_CHECK_CLASS($1) if test "$HAVE_LAST_CLASS" = "no"; then AC_MSG_ERROR([Required class $1 missing, exiting.]) fi ]) tcpflow-tcpflow-1.6.1/m4/ac_java_options.m4000066400000000000000000000023601401360461700205750ustar00rootroot00000000000000dnl @synopsis AC_JAVA_OPTIONS dnl dnl AC_JAVA_OPTIONS adds configure command line options used for Java dnl m4 macros. This Macro is optional. dnl dnl Note: This is part of the set of autoconf M4 macros for Java dnl programs. It is VERY IMPORTANT that you download the whole set, dnl some macros depend on other. Unfortunately, the autoconf archive dnl does not support the concept of set of macros, so I had to break it dnl for submission. The general documentation, as well as the sample dnl configure.in, is included in the AC_PROG_JAVA macro. dnl dnl @category Java dnl @author Devin Weaver dnl @version 2000-07-19 dnl @license AllPermissive AC_DEFUN([AC_JAVA_OPTIONS],[ AC_ARG_WITH(java-prefix, [ --with-java-prefix=PFX prefix where Java runtime is installed (optional)]) AC_ARG_WITH(javac-flags, [ --with-javac-flags=FLAGS flags to pass to the Java compiler (optional)]) AC_ARG_WITH(java-flags, [ --with-java-flags=FLAGS flags to pass to the Java VM (optional)]) JAVAPREFIX=$with_java_prefix JAVACFLAGS=$with_javac_flags JAVAFLAGS=$with_java_flags AC_SUBST(JAVAPREFIX)dnl AC_SUBST(JAVACFLAGS)dnl AC_SUBST(JAVAFLAGS)dnl AC_SUBST(JAVA)dnl AC_SUBST(JAVAC)dnl ]) tcpflow-tcpflow-1.6.1/m4/ac_prog_jar.m4000066400000000000000000000024421401360461700177050ustar00rootroot00000000000000dnl @synopsis AC_PROG_JAR dnl dnl AC_PROG_JAR tests for an existing jar program. It uses the dnl environment variable JAR then tests in sequence various common jar dnl programs. dnl dnl If you want to force a specific compiler: dnl dnl - at the configure.in level, set JAR=yourcompiler before calling dnl AC_PROG_JAR dnl dnl - at the configure level, setenv JAR dnl dnl You can use the JAR variable in your Makefile.in, with @JAR@. dnl dnl Note: This macro depends on the autoconf M4 macros for Java dnl programs. It is VERY IMPORTANT that you download that whole set, dnl some macros depend on other. Unfortunately, the autoconf archive dnl does not support the concept of set of macros, so I had to break it dnl for submission. dnl dnl The general documentation of those macros, as well as the sample dnl configure.in, is included in the AC_PROG_JAVA macro. dnl dnl @category Java dnl @author Egon Willighagen dnl @version 2000-07-19 dnl @license AllPermissive AC_DEFUN([AC_PROG_JAR],[ AC_REQUIRE([AC_EXEEXT])dnl if test "x$JAVAPREFIX" = x; then test "x$JAR" = x && AC_CHECK_PROGS(JAR, jar$EXEEXT) else test "x$JAR" = x && AC_CHECK_PROGS(JAR, jar, $JAVAPREFIX) fi test "x$JAR" = x && AC_MSG_ERROR([no acceptable jar program found in \$PATH]) AC_PROVIDE([$0])dnl ]) tcpflow-tcpflow-1.6.1/m4/ac_prog_java.m4000066400000000000000000000051321401360461700200510ustar00rootroot00000000000000dnl @synopsis AC_PROG_JAVA dnl dnl Here is a summary of the main macros: dnl dnl AC_PROG_JAVAC: finds a Java compiler. dnl dnl AC_PROG_JAVA: finds a Java virtual machine. dnl dnl AC_CHECK_CLASS: finds if we have the given class (beware of dnl CLASSPATH!). dnl dnl AC_CHECK_RQRD_CLASS: finds if we have the given class and stops dnl otherwise. dnl dnl AC_TRY_COMPILE_JAVA: attempt to compile user given source. dnl dnl AC_TRY_RUN_JAVA: attempt to compile and run user given source. dnl dnl AC_JAVA_OPTIONS: adds Java configure options. dnl dnl AC_PROG_JAVA tests an existing Java virtual machine. It uses the dnl environment variable JAVA then tests in sequence various common dnl Java virtual machines. For political reasons, it starts with the dnl free ones. You *must* call [AC_PROG_JAVAC] before. dnl dnl If you want to force a specific VM: dnl dnl - at the configure.in level, set JAVA=yourvm before calling dnl AC_PROG_JAVA dnl dnl (but after AC_INIT) dnl dnl - at the configure level, setenv JAVA dnl dnl You can use the JAVA variable in your Makefile.in, with @JAVA@. dnl dnl *Warning*: its success or failure can depend on a proper setting of dnl the CLASSPATH env. variable. dnl dnl TODO: allow to exclude virtual machines (rationale: most Java dnl programs cannot run with some VM like kaffe). dnl dnl Note: This is part of the set of autoconf M4 macros for Java dnl programs. It is VERY IMPORTANT that you download the whole set, dnl some macros depend on other. Unfortunately, the autoconf archive dnl does not support the concept of set of macros, so I had to break it dnl for submission. dnl dnl A Web page, with a link to the latest CVS snapshot is at dnl . dnl dnl This is a sample configure.in Process this file with autoconf to dnl produce a configure script. dnl dnl AC_INIT(UnTag.java) dnl dnl dnl Checks for programs. dnl AC_CHECK_CLASSPATH dnl AC_PROG_JAVAC dnl AC_PROG_JAVA dnl dnl dnl Checks for classes dnl AC_CHECK_RQRD_CLASS(org.xml.sax.Parser) dnl AC_CHECK_RQRD_CLASS(com.jclark.xml.sax.Driver) dnl dnl AC_OUTPUT(Makefile) dnl dnl @category Java dnl @author Stephane Bortzmeyer dnl @version 2000-07-19 dnl @license GPLWithACException AC_DEFUN([AC_PROG_JAVA],[ AC_REQUIRE([AC_EXEEXT])dnl if test x$JAVAPREFIX = x; then test x$JAVA = x && AC_CHECK_PROGS(JAVA, kaffe$EXEEXT java$EXEEXT) else test x$JAVA = x && AC_CHECK_PROGS(JAVA, kaffe$EXEEXT java$EXEEXT, $JAVAPREFIX) fi test x$JAVA = x && AC_MSG_ERROR([no acceptable Java virtual machine found in \$PATH]) AC_PROG_JAVA_WORKS AC_PROVIDE([$0])dnl ]) tcpflow-tcpflow-1.6.1/m4/ac_prog_java_cc.m4000066400000000000000000000037061401360461700205230ustar00rootroot00000000000000dnl @synopsis AC_PROG_JAVA_CC dnl dnl Finds the appropriate java compiler on your path. By preference the dnl java compiler is gcj, then jikes then javac. dnl dnl The macro can take one argument specifying a space separated list dnl of java compiler names. dnl dnl For example: dnl dnl AC_PROG_JAVA_CC(javac, gcj) dnl dnl The macro also sets the compiler options variable: JAVA_CC_OPTS to dnl something sensible: dnl dnl - for GCJ it sets it to: @GCJ_OPTS@ dnl (if GCJ_OPTS is not yet defined then it is set to "-C") dnl dnl - no other compiler has applicable options yet dnl dnl Here's an example configure.in: dnl dnl AC_INIT(Makefile.in) dnl AC_PROG_JAVA_CC() dnl AC_OUTPUT(Makefile) dnl dnl End. dnl dnl And here's the start of the Makefile.in: dnl dnl PROJECT_ROOT := @srcdir@ dnl # Tool definitions. dnl JAVAC := @JAVA_CC@ dnl JAVAC_OPTS := @JAVA_CC_OPTS@ dnl JAR_TOOL := @jar_tool@ dnl dnl @category Java dnl @author Nic Ferrier dnl @version 2002-03-04 dnl @license GPLWithACException # AC_PROG_JAVA_CC([COMPILER ...]) # -------------------------- # COMPILER ... is a space separated list of java compilers to search for. # This just gives the user an opportunity to specify an alternative # search list for the java compiler. AC_DEFUN([AC_PROG_JAVA_CC], [AC_ARG_VAR([JAVA_CC], [java compiler command])dnl AC_ARG_VAR([JAVA_CC_FLAGS], [java compiler flags])dnl m4_ifval([$1], [AC_CHECK_TOOLS(JAVA_CC, [$1])], [AC_CHECK_TOOL(JAVA_CC, gcj) if test -z "$JAVA_CC"; then AC_CHECK_TOOL(JAVA_CC, javac) fi if test -z "$JAVA_CC"; then AC_CHECK_TOOL(JAVA_CC, jikes) fi ]) if test "$JAVA_CC" = "gcj"; then if test "$GCJ_OPTS" = ""; then AC_SUBST(GCJ_OPTS,-C) fi AC_SUBST(JAVA_CC_OPTS, @GCJ_OPTS@, [Define the compilation options for GCJ]) fi test -z "$JAVA_CC" && AC_MSG_ERROR([no acceptable java compiler found in \$PATH]) ])# AC_PROG_JAVA_CC tcpflow-tcpflow-1.6.1/m4/ac_prog_java_works.m4000066400000000000000000000061731401360461700213040ustar00rootroot00000000000000dnl @synopsis AC_PROG_JAVA_WORKS dnl dnl Internal use ONLY. dnl dnl Note: This is part of the set of autoconf M4 macros for Java dnl programs. It is VERY IMPORTANT that you download the whole set, dnl some macros depend on other. Unfortunately, the autoconf archive dnl does not support the concept of set of macros, so I had to break it dnl for submission. The general documentation, as well as the sample dnl configure.in, is included in the AC_PROG_JAVA macro. dnl dnl @category Java dnl @author Stephane Bortzmeyer dnl @version 2000-07-19 dnl @license GPLWithACException AC_DEFUN([AC_PROG_JAVA_WORKS], [ AC_CHECK_PROG(uudecode, uudecode$EXEEXT, yes) if test x$uudecode = xyes; then AC_CACHE_CHECK([if uudecode can decode base 64 file], ac_cv_prog_uudecode_base64, [ dnl /** dnl * Test.java: used to test if java compiler works. dnl */ dnl public class Test dnl { dnl dnl public static void dnl main( String[] argv ) dnl { dnl System.exit (0); dnl } dnl dnl } cat << \EOF > Test.uue begin-base64 644 Test.class yv66vgADAC0AFQcAAgEABFRlc3QHAAQBABBqYXZhL2xhbmcvT2JqZWN0AQAE bWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBAARDb2RlAQAPTGluZU51 bWJlclRhYmxlDAAKAAsBAARleGl0AQAEKEkpVgoADQAJBwAOAQAQamF2YS9s YW5nL1N5c3RlbQEABjxpbml0PgEAAygpVgwADwAQCgADABEBAApTb3VyY2VG aWxlAQAJVGVzdC5qYXZhACEAAQADAAAAAAACAAkABQAGAAEABwAAACEAAQAB AAAABQO4AAyxAAAAAQAIAAAACgACAAAACgAEAAsAAQAPABAAAQAHAAAAIQAB AAEAAAAFKrcAErEAAAABAAgAAAAKAAIAAAAEAAQABAABABMAAAACABQ= ==== EOF if uudecode$EXEEXT Test.uue; then ac_cv_prog_uudecode_base64=yes else echo "configure: __oline__: uudecode had trouble decoding base 64 file 'Test.uue'" >&AC_FD_CC echo "configure: failed file was:" >&AC_FD_CC cat Test.uue >&AC_FD_CC ac_cv_prog_uudecode_base64=no fi rm -f Test.uue]) fi if test x$ac_cv_prog_uudecode_base64 != xyes; then rm -f Test.class AC_MSG_WARN([I have to compile Test.class from scratch]) if test x$ac_cv_prog_javac_works = xno; then AC_MSG_ERROR([Cannot compile java source. $JAVAC does not work properly]) fi if test x$ac_cv_prog_javac_works = x; then AC_PROG_JAVAC fi fi AC_CACHE_CHECK(if $JAVA works, ac_cv_prog_java_works, [ JAVA_TEST=Test.java CLASS_TEST=Test.class TEST=Test changequote(, )dnl cat << \EOF > $JAVA_TEST /* [#]line __oline__ "configure" */ public class Test { public static void main (String args[]) { System.exit (0); } } EOF changequote([, ])dnl if test x$ac_cv_prog_uudecode_base64 != xyes; then if AC_TRY_COMMAND($JAVAC $JAVACFLAGS $JAVA_TEST) && test -s $CLASS_TEST; then : else echo "configure: failed program was:" >&AC_FD_CC cat $JAVA_TEST >&AC_FD_CC AC_MSG_ERROR(The Java compiler $JAVAC failed (see config.log, check the CLASSPATH?)) fi fi if AC_TRY_COMMAND($JAVA $JAVAFLAGS $TEST) >/dev/null 2>&1; then ac_cv_prog_java_works=yes else echo "configure: failed program was:" >&AC_FD_CC cat $JAVA_TEST >&AC_FD_CC AC_MSG_ERROR(The Java VM $JAVA failed (see config.log, check the CLASSPATH?)) fi rm -fr $JAVA_TEST $CLASS_TEST Test.uue ]) AC_PROVIDE([$0])dnl ] ) tcpflow-tcpflow-1.6.1/m4/ac_prog_javac.m4000066400000000000000000000033021401360461700202110ustar00rootroot00000000000000dnl @synopsis AC_PROG_JAVAC dnl dnl AC_PROG_JAVAC tests an existing Java compiler. It uses the dnl environment variable JAVAC then tests in sequence various common dnl Java compilers. For political reasons, it starts with the free dnl ones. dnl dnl If you want to force a specific compiler: dnl dnl - at the configure.in level, set JAVAC=yourcompiler before calling dnl AC_PROG_JAVAC dnl dnl - at the configure level, setenv JAVAC dnl dnl You can use the JAVAC variable in your Makefile.in, with @JAVAC@. dnl dnl *Warning*: its success or failure can depend on a proper setting of dnl the CLASSPATH env. variable. dnl dnl TODO: allow to exclude compilers (rationale: most Java programs dnl cannot compile with some compilers like guavac). dnl dnl Note: This is part of the set of autoconf M4 macros for Java dnl programs. It is VERY IMPORTANT that you download the whole set, dnl some macros depend on other. Unfortunately, the autoconf archive dnl does not support the concept of set of macros, so I had to break it dnl for submission. The general documentation, as well as the sample dnl configure.in, is included in the AC_PROG_JAVA macro. dnl dnl @category Java dnl @author Stephane Bortzmeyer dnl @version 2000-07-19 dnl @license GPLWithACException AC_DEFUN([AC_PROG_JAVAC],[ AC_REQUIRE([AC_EXEEXT])dnl if test "x$JAVAPREFIX" = x; then test "x$JAVAC" = x && AC_CHECK_PROGS(JAVAC, "gcj$EXEEXT -C" guavac$EXEEXT jikes$EXEEXT javac$EXEEXT) else test "x$JAVAC" = x && AC_CHECK_PROGS(JAVAC, "gcj$EXEEXT -C" guavac$EXEEXT jikes$EXEEXT javac$EXEEXT, $JAVAPREFIX) fi test "x$JAVAC" = x && AC_MSG_ERROR([no acceptable Java compiler found in \$PATH]) AC_PROG_JAVAC_WORKS AC_PROVIDE([$0])dnl ]) tcpflow-tcpflow-1.6.1/m4/ac_prog_javac_works.m4000066400000000000000000000022021401360461700214340ustar00rootroot00000000000000dnl @synopsis AC_PROG_JAVAC_WORKS dnl dnl Internal use ONLY. dnl dnl Note: This is part of the set of autoconf M4 macros for Java dnl programs. It is VERY IMPORTANT that you download the whole set, dnl some macros depend on other. Unfortunately, the autoconf archive dnl does not support the concept of set of macros, so I had to break it dnl for submission. The general documentation, as well as the sample dnl configure.in, is included in the AC_PROG_JAVA macro. dnl dnl @category Java dnl @author Stephane Bortzmeyer dnl @version 2000-07-19 dnl @license GPLWithACException AC_DEFUN([AC_PROG_JAVAC_WORKS],[ AC_CACHE_CHECK([if $JAVAC works], ac_cv_prog_javac_works, [ JAVA_TEST=Test.java CLASS_TEST=Test.class cat << \EOF > $JAVA_TEST /* [#]line __oline__ "configure" */ public class Test { } EOF if AC_TRY_COMMAND($JAVAC $JAVACFLAGS $JAVA_TEST) >/dev/null 2>&1; then ac_cv_prog_javac_works=yes else AC_MSG_ERROR([The Java compiler $JAVAC failed (see config.log, check the CLASSPATH?)]) echo "configure: failed program was:" >&AC_FD_CC cat $JAVA_TEST >&AC_FD_CC fi rm -f $JAVA_TEST $CLASS_TEST ]) AC_PROVIDE([$0])dnl ]) tcpflow-tcpflow-1.6.1/m4/ac_prog_javadoc.m4000066400000000000000000000025701401360461700205420ustar00rootroot00000000000000dnl @synopsis AC_PROG_JAVADOC dnl dnl AC_PROG_JAVADOC tests for an existing javadoc generator. It uses dnl the environment variable JAVADOC then tests in sequence various dnl common javadoc generator. dnl dnl If you want to force a specific compiler: dnl dnl - at the configure.in level, set JAVADOC=yourgenerator before dnl calling AC_PROG_JAVADOC dnl dnl - at the configure level, setenv JAVADOC dnl dnl You can use the JAVADOC variable in your Makefile.in, with dnl @JAVADOC@. dnl dnl Note: This macro depends on the autoconf M4 macros for Java dnl programs. It is VERY IMPORTANT that you download that whole set, dnl some macros depend on other. Unfortunately, the autoconf archive dnl does not support the concept of set of macros, so I had to break it dnl for submission. dnl dnl The general documentation of those macros, as well as the sample dnl configure.in, is included in the AC_PROG_JAVA macro. dnl dnl @category Java dnl @author Egon Willighagen dnl @version 2000-07-19 dnl @license AllPermissive AC_DEFUN([AC_PROG_JAVADOC],[ AC_REQUIRE([AC_EXEEXT])dnl if test "x$JAVAPREFIX" = x; then test "x$JAVADOC" = x && AC_CHECK_PROGS(JAVADOC, javadoc$EXEEXT) else test "x$JAVADOC" = x && AC_CHECK_PROGS(JAVADOC, javadoc, $JAVAPREFIX) fi test "x$JAVADOC" = x && AC_MSG_ERROR([no acceptable javadoc generator found in \$PATH]) AC_PROVIDE([$0])dnl ]) tcpflow-tcpflow-1.6.1/m4/ac_prog_javah.m4000066400000000000000000000020171401360461700202200ustar00rootroot00000000000000dnl @synopsis AC_PROG_JAVAH dnl dnl AC_PROG_JAVAH tests the availability of the javah header generator dnl and looks for the jni.h header file. If available, JAVAH is set to dnl the full path of javah and CPPFLAGS is updated accordingly. dnl dnl @category Java dnl @author Luc Maisonobe dnl @version 2002-03-25 dnl @license AllPermissive AC_DEFUN([AC_PROG_JAVAH],[ AC_REQUIRE([AC_CANONICAL_SYSTEM])dnl AC_REQUIRE([AC_PROG_CPP])dnl AC_PATH_PROG(JAVAH,javah) if test x"`eval 'echo $ac_cv_path_JAVAH'`" != x ; then AC_TRY_CPP([#include ],,[ ac_save_CPPFLAGS="$CPPFLAGS" changequote(, )dnl ac_dir=`echo $ac_cv_path_JAVAH | sed 's,\(.*\)/[^/]*/[^/]*$,\1/include,'` ac_machdep=`echo $build_os | sed 's,[-0-9].*,,' | sed 's,cygwin,win32,'` changequote([, ])dnl CPPFLAGS="$ac_save_CPPFLAGS -I$ac_dir -I$ac_dir/$ac_machdep" AC_TRY_CPP([#include ], ac_save_CPPFLAGS="$CPPFLAGS", AC_MSG_WARN([unable to include ])) CPPFLAGS="$ac_save_CPPFLAGS"]) fi]) tcpflow-tcpflow-1.6.1/m4/ac_try_compile_java.m4000066400000000000000000000023231401360461700214270ustar00rootroot00000000000000dnl @synopsis AC_TRY_COMPILE_JAVA dnl dnl AC_TRY_COMPILE_JAVA attempt to compile user given source. dnl dnl *Warning*: its success or failure can depend on a proper setting of dnl the CLASSPATH env. variable. dnl dnl Note: This is part of the set of autoconf M4 macros for Java dnl programs. It is VERY IMPORTANT that you download the whole set, dnl some macros depend on other. Unfortunately, the autoconf archive dnl does not support the concept of set of macros, so I had to break it dnl for submission. The general documentation, as well as the sample dnl configure.in, is included in the AC_PROG_JAVA macro. dnl dnl @category Java dnl @author Devin Weaver dnl @version 2000-07-19 dnl @license AllPermissive AC_DEFUN([AC_TRY_COMPILE_JAVA],[ AC_REQUIRE([AC_PROG_JAVAC])dnl cat << \EOF > Test.java /* [#]line __oline__ "configure" */ ifelse([$1], , , [import $1;]) public class Test { [$2] } EOF if AC_TRY_COMMAND($JAVAC $JAVACFLAGS Test.java) && test -s Test.class then dnl Don't remove the temporary files here, so they can be examined. ifelse([$3], , :, [$3]) else echo "configure: failed program was:" >&AC_FD_CC cat Test.java >&AC_FD_CC ifelse([$4], , , [ rm -fr Test* $4 ])dnl fi rm -fr Test*]) tcpflow-tcpflow-1.6.1/m4/ac_try_run_javac.m4000066400000000000000000000024331401360461700207500ustar00rootroot00000000000000dnl @synopsis AC_TRY_RUN_JAVA dnl dnl AC_TRY_RUN_JAVA attempt to compile and run user given source. dnl dnl *Warning*: its success or failure can depend on a proper setting of dnl the CLASSPATH env. variable. dnl dnl Note: This is part of the set of autoconf M4 macros for Java dnl programs. It is VERY IMPORTANT that you download the whole set, dnl some macros depend on other. Unfortunately, the autoconf archive dnl does not support the concept of set of macros, so I had to break it dnl for submission. The general documentation, as well as the sample dnl configure.in, is included in the AC_PROG_JAVA macro. dnl dnl @category Java dnl @author Devin Weaver dnl @version 2000-07-19 dnl @license AllPermissive AC_DEFUN([AC_TRY_RUN_JAVA],[ AC_REQUIRE([AC_PROG_JAVAC])dnl AC_REQUIRE([AC_PROG_JAVA])dnl cat << \EOF > Test.java /* [#]line __oline__ "configure" */ ifelse([$1], , , [include $1;]) public class Test { [$2] } EOF if AC_TRY_COMMAND($JAVAC $JAVACFLAGS Test.java) && test -s Test.class && ($JAVA $JAVAFLAGS Test; exit) 2>/dev/null then dnl Don't remove the temporary files here, so they can be examined. ifelse([$3], , :, [$3]) else echo "configure: failed program was:" >&AC_FD_CC cat Test.java >&AC_FD_CC ifelse([$4], , , [ rm -fr Test* $4 ])dnl fi rm -fr Test*]) tcpflow-tcpflow-1.6.1/m4/ax_cxx_compile_stdcxx.m4000066400000000000000000000456471401360461700220540ustar00rootroot00000000000000# =========================================================================== # https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html # =========================================================================== # # SYNOPSIS # # AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional]) # # DESCRIPTION # # Check for baseline language coverage in the compiler for the specified # version of the C++ standard. If necessary, add switches to CXX and # CXXCPP to enable support. VERSION may be '11' (for the C++11 standard) # or '14' (for the C++14 standard). # # The second argument, if specified, indicates whether you insist on an # extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. # -std=c++11). If neither is specified, you get whatever works, with # preference for an extended mode. # # The third argument, if specified 'mandatory' or if left unspecified, # indicates that baseline support for the specified C++ standard is # required and that the macro should error out if no mode with that # support is found. If specified 'optional', then configuration proceeds # regardless, after defining HAVE_CXX${VERSION} if and only if a # supporting mode is found. # # LICENSE # # Copyright (c) 2008 Benjamin Kosnik # Copyright (c) 2012 Zack Weinberg # Copyright (c) 2013 Roy Stogner # Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov # Copyright (c) 2015 Paul Norman # Copyright (c) 2015 Moritz Klammler # Copyright (c) 2016, 2018 Krzesimir Nowak # Copyright (c) 2019 Enji Cooper # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 11 dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro dnl (serial version number 13). AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"], [$1], [14], [ax_cxx_compile_alternatives="14 1y"], [$1], [17], [ax_cxx_compile_alternatives="17 1z"], [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl m4_if([$2], [], [], [$2], [ext], [], [$2], [noext], [], [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true], [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true], [$3], [optional], [ax_cxx_compile_cxx$1_required=false], [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])]) AC_LANG_PUSH([C++])dnl ac_success=no m4_if([$2], [noext], [], [dnl if test x$ac_success = xno; then for alternative in ${ax_cxx_compile_alternatives}; do switch="-std=gnu++${alternative}" cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, $cachevar, [ac_save_CXX="$CXX" CXX="$CXX $switch" AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], [eval $cachevar=yes], [eval $cachevar=no]) CXX="$ac_save_CXX"]) if eval test x\$$cachevar = xyes; then CXX="$CXX $switch" if test -n "$CXXCPP" ; then CXXCPP="$CXXCPP $switch" fi ac_success=yes break fi done fi]) m4_if([$2], [ext], [], [dnl if test x$ac_success = xno; then dnl HP's aCC needs +std=c++11 according to: dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf dnl Cray's crayCC needs "-h std=c++11" for alternative in ${ax_cxx_compile_alternatives}; do for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, $cachevar, [ac_save_CXX="$CXX" CXX="$CXX $switch" AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], [eval $cachevar=yes], [eval $cachevar=no]) CXX="$ac_save_CXX"]) if eval test x\$$cachevar = xyes; then CXX="$CXX $switch" if test -n "$CXXCPP" ; then CXXCPP="$CXXCPP $switch" fi ac_success=yes break fi done if test x$ac_success = xyes; then break fi done fi]) AC_LANG_POP([C++]) if test x$ax_cxx_compile_cxx$1_required = xtrue; then if test x$ac_success = xno; then AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.]) fi fi if test x$ac_success = xno; then HAVE_CXX$1=0 AC_MSG_NOTICE([No compiler with C++$1 support was found]) else HAVE_CXX$1=1 AC_DEFINE(HAVE_CXX$1,1, [define if the compiler supports basic C++$1 syntax]) fi AC_SUBST(HAVE_CXX$1) ]) dnl Test body for checking C++11 support m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11], _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 ) dnl Test body for checking C++14 support m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 ) m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17], _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 ) dnl Tests for new features in C++11 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ // If the compiler admits that it is not ready for C++11, why torture it? // Hopefully, this will speed up the test. #ifndef __cplusplus #error "This is not a C++ compiler" #elif __cplusplus < 201103L #error "This is not a C++11 compiler" #else namespace cxx11 { namespace test_static_assert { template struct check { static_assert(sizeof(int) <= sizeof(T), "not big enough"); }; } namespace test_final_override { struct Base { virtual ~Base() {} virtual void f() {} }; struct Derived : public Base { virtual ~Derived() override {} virtual void f() override {} }; } namespace test_double_right_angle_brackets { template < typename T > struct check {}; typedef check single_type; typedef check> double_type; typedef check>> triple_type; typedef check>>> quadruple_type; } namespace test_decltype { int f() { int a = 1; decltype(a) b = 2; return a + b; } } namespace test_type_deduction { template < typename T1, typename T2 > struct is_same { static const bool value = false; }; template < typename T > struct is_same { static const bool value = true; }; template < typename T1, typename T2 > auto add(T1 a1, T2 a2) -> decltype(a1 + a2) { return a1 + a2; } int test(const int c, volatile int v) { static_assert(is_same::value == true, ""); static_assert(is_same::value == false, ""); static_assert(is_same::value == false, ""); auto ac = c; auto av = v; auto sumi = ac + av + 'x'; auto sumf = ac + av + 1.0; static_assert(is_same::value == true, ""); static_assert(is_same::value == true, ""); static_assert(is_same::value == true, ""); static_assert(is_same::value == false, ""); static_assert(is_same::value == true, ""); return (sumf > 0.0) ? sumi : add(c, v); } } namespace test_noexcept { int f() { return 0; } int g() noexcept { return 0; } static_assert(noexcept(f()) == false, ""); static_assert(noexcept(g()) == true, ""); } namespace test_constexpr { template < typename CharT > unsigned long constexpr strlen_c_r(const CharT *const s, const unsigned long acc) noexcept { return *s ? strlen_c_r(s + 1, acc + 1) : acc; } template < typename CharT > unsigned long constexpr strlen_c(const CharT *const s) noexcept { return strlen_c_r(s, 0UL); } static_assert(strlen_c("") == 0UL, ""); static_assert(strlen_c("1") == 1UL, ""); static_assert(strlen_c("example") == 7UL, ""); static_assert(strlen_c("another\0example") == 7UL, ""); } namespace test_rvalue_references { template < int N > struct answer { static constexpr int value = N; }; answer<1> f(int&) { return answer<1>(); } answer<2> f(const int&) { return answer<2>(); } answer<3> f(int&&) { return answer<3>(); } void test() { int i = 0; const int c = 0; static_assert(decltype(f(i))::value == 1, ""); static_assert(decltype(f(c))::value == 2, ""); static_assert(decltype(f(0))::value == 3, ""); } } namespace test_uniform_initialization { struct test { static const int zero {}; static const int one {1}; }; static_assert(test::zero == 0, ""); static_assert(test::one == 1, ""); } namespace test_lambdas { void test1() { auto lambda1 = [](){}; auto lambda2 = lambda1; lambda1(); lambda2(); } int test2() { auto a = [](int i, int j){ return i + j; }(1, 2); auto b = []() -> int { return '0'; }(); auto c = [=](){ return a + b; }(); auto d = [&](){ return c; }(); auto e = [a, &b](int x) mutable { const auto identity = [](int y){ return y; }; for (auto i = 0; i < a; ++i) a += b--; return x + identity(a + b); }(0); return a + b + c + d + e; } int test3() { const auto nullary = [](){ return 0; }; const auto unary = [](int x){ return x; }; using nullary_t = decltype(nullary); using unary_t = decltype(unary); const auto higher1st = [](nullary_t f){ return f(); }; const auto higher2nd = [unary](nullary_t f1){ return [unary, f1](unary_t f2){ return f2(unary(f1())); }; }; return higher1st(nullary) + higher2nd(nullary)(unary); } } namespace test_variadic_templates { template struct sum; template struct sum { static constexpr auto value = N0 + sum::value; }; template <> struct sum<> { static constexpr auto value = 0; }; static_assert(sum<>::value == 0, ""); static_assert(sum<1>::value == 1, ""); static_assert(sum<23>::value == 23, ""); static_assert(sum<1, 2>::value == 3, ""); static_assert(sum<5, 5, 11>::value == 21, ""); static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, ""); } // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function // because of this. namespace test_template_alias_sfinae { struct foo {}; template using member = typename T::member_type; template void func(...) {} template void func(member*) {} void test(); void test() { func(0); } } } // namespace cxx11 #endif // __cplusplus >= 201103L ]]) dnl Tests for new features in C++14 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[ // If the compiler admits that it is not ready for C++14, why torture it? // Hopefully, this will speed up the test. #ifndef __cplusplus #error "This is not a C++ compiler" #elif __cplusplus < 201402L #error "This is not a C++14 compiler" #else namespace cxx14 { namespace test_polymorphic_lambdas { int test() { const auto lambda = [](auto&&... args){ const auto istiny = [](auto x){ return (sizeof(x) == 1UL) ? 1 : 0; }; const int aretiny[] = { istiny(args)... }; return aretiny[0]; }; return lambda(1, 1L, 1.0f, '1'); } } namespace test_binary_literals { constexpr auto ivii = 0b0000000000101010; static_assert(ivii == 42, "wrong value"); } namespace test_generalized_constexpr { template < typename CharT > constexpr unsigned long strlen_c(const CharT *const s) noexcept { auto length = 0UL; for (auto p = s; *p; ++p) ++length; return length; } static_assert(strlen_c("") == 0UL, ""); static_assert(strlen_c("x") == 1UL, ""); static_assert(strlen_c("test") == 4UL, ""); static_assert(strlen_c("another\0test") == 7UL, ""); } namespace test_lambda_init_capture { int test() { auto x = 0; const auto lambda1 = [a = x](int b){ return a + b; }; const auto lambda2 = [a = lambda1(x)](){ return a; }; return lambda2(); } } namespace test_digit_separators { constexpr auto ten_million = 100'000'000; static_assert(ten_million == 100000000, ""); } namespace test_return_type_deduction { auto f(int& x) { return x; } decltype(auto) g(int& x) { return x; } template < typename T1, typename T2 > struct is_same { static constexpr auto value = false; }; template < typename T > struct is_same { static constexpr auto value = true; }; int test() { auto x = 0; static_assert(is_same::value, ""); static_assert(is_same::value, ""); return x; } } } // namespace cxx14 #endif // __cplusplus >= 201402L ]]) dnl Tests for new features in C++17 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[ // If the compiler admits that it is not ready for C++17, why torture it? // Hopefully, this will speed up the test. #ifndef __cplusplus #error "This is not a C++ compiler" #elif __cplusplus < 201703L #error "This is not a C++17 compiler" #else #include #include #include namespace cxx17 { namespace test_constexpr_lambdas { constexpr int foo = [](){return 42;}(); } namespace test::nested_namespace::definitions { } namespace test_fold_expression { template int multiply(Args... args) { return (args * ... * 1); } template bool all(Args... args) { return (args && ...); } } namespace test_extended_static_assert { static_assert (true); } namespace test_auto_brace_init_list { auto foo = {5}; auto bar {5}; static_assert(std::is_same, decltype(foo)>::value); static_assert(std::is_same::value); } namespace test_typename_in_template_template_parameter { template typename X> struct D; } namespace test_fallthrough_nodiscard_maybe_unused_attributes { int f1() { return 42; } [[nodiscard]] int f2() { [[maybe_unused]] auto unused = f1(); switch (f1()) { case 17: f1(); [[fallthrough]]; case 42: f1(); } return f1(); } } namespace test_extended_aggregate_initialization { struct base1 { int b1, b2 = 42; }; struct base2 { base2() { b3 = 42; } int b3; }; struct derived : base1, base2 { int d; }; derived d1 {{1, 2}, {}, 4}; // full initialization derived d2 {{}, {}, 4}; // value-initialized bases } namespace test_general_range_based_for_loop { struct iter { int i; int& operator* () { return i; } const int& operator* () const { return i; } iter& operator++() { ++i; return *this; } }; struct sentinel { int i; }; bool operator== (const iter& i, const sentinel& s) { return i.i == s.i; } bool operator!= (const iter& i, const sentinel& s) { return !(i == s); } struct range { iter begin() const { return {0}; } sentinel end() const { return {5}; } }; void f() { range r {}; for (auto i : r) { [[maybe_unused]] auto v = i; } } } namespace test_lambda_capture_asterisk_this_by_value { struct t { int i; int foo() { return [*this]() { return i; }(); } }; } namespace test_enum_class_construction { enum class byte : unsigned char {}; byte foo {42}; } namespace test_constexpr_if { template int f () { if constexpr(cond) { return 13; } else { return 42; } } } namespace test_selection_statement_with_initializer { int f() { return 13; } int f2() { if (auto i = f(); i > 0) { return 3; } switch (auto i = f(); i + 4) { case 17: return 2; default: return 1; } } } namespace test_template_argument_deduction_for_class_templates { template struct pair { pair (T1 p1, T2 p2) : m1 {p1}, m2 {p2} {} T1 m1; T2 m2; }; void f() { [[maybe_unused]] auto p = pair{13, 42u}; } } namespace test_non_type_auto_template_parameters { template struct B {}; B<5> b1; B<'a'> b2; } namespace test_structured_bindings { int arr[2] = { 1, 2 }; std::pair pr = { 1, 2 }; auto f1() -> int(&)[2] { return arr; } auto f2() -> std::pair& { return pr; } struct S { int x1 : 2; volatile double y1; }; S f3() { return {}; } auto [ x1, y1 ] = f1(); auto& [ xr1, yr1 ] = f1(); auto [ x2, y2 ] = f2(); auto& [ xr2, yr2 ] = f2(); const auto [ x3, y3 ] = f3(); } namespace test_exception_spec_type_system { struct Good {}; struct Bad {}; void g1() noexcept; void g2(); template Bad f(T*, T*); template Good f(T1*, T2*); static_assert (std::is_same_v); } namespace test_inline_variables { template void f(T) {} template inline T g(T) { return T{}; } template<> inline void f<>(int) {} template<> int g<>(int) { return 5; } } } // namespace cxx17 #endif // __cplusplus < 201703L ]]) tcpflow-tcpflow-1.6.1/m4/ax_cxx_compile_stdcxx_11.m4000066400000000000000000000107631401360461700223440ustar00rootroot00000000000000# ============================================================================ # http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html # ============================================================================ # # SYNOPSIS # # AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional]) # # DESCRIPTION # # Check for baseline language coverage in the compiler for the C++11 # standard; if necessary, add switches to CXXFLAGS to enable support. # # The first argument, if specified, indicates whether you insist on an # extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. # -std=c++11). If neither is specified, you get whatever works, with # preference for an extended mode. # # The second argument, if specified 'mandatory' or if left unspecified, # indicates that baseline C++11 support is required and that the macro # should error out if no mode with that support is found. If specified # 'optional', then configuration proceeds regardless, after defining # HAVE_CXX11 if and only if a supporting mode is found. # # LICENSE # # Copyright (c) 2008 Benjamin Kosnik # Copyright (c) 2012 Zack Weinberg # Copyright (c) 2013 Roy Stogner # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 3 m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [ template struct check { static_assert(sizeof(int) <= sizeof(T), "not big enough"); }; typedef check> right_angle_brackets; int a; decltype(a) b; typedef check check_type; check_type c; check_type&& cr = static_cast(c); auto d = a; ]) AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl m4_if([$1], [], [], [$1], [ext], [], [$1], [noext], [], [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl m4_if([$2], [], [ax_cxx_compile_cxx11_required=true], [$2], [mandatory], [ax_cxx_compile_cxx11_required=true], [$2], [optional], [ax_cxx_compile_cxx11_required=false], [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])])dnl AC_LANG_PUSH([C++])dnl ac_success=no AC_CACHE_CHECK(whether $CXX supports C++11 features by default, ax_cv_cxx_compile_cxx11, [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], [ax_cv_cxx_compile_cxx11=yes], [ax_cv_cxx_compile_cxx11=no])]) if test x$ax_cv_cxx_compile_cxx11 = xyes; then ac_success=yes fi m4_if([$1], [noext], [], [dnl if test x$ac_success = xno; then for switch in -std=gnu++11 -std=gnu++0x; do cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, $cachevar, [ac_save_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS $switch" AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], [eval $cachevar=yes], [eval $cachevar=no]) CXXFLAGS="$ac_save_CXXFLAGS"]) if eval test x\$$cachevar = xyes; then CXXFLAGS="$CXXFLAGS $switch" ac_success=yes break fi done fi]) m4_if([$1], [ext], [], [dnl if test x$ac_success = xno; then for switch in -std=c++11 -std=c++0x; do cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch]) AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch, $cachevar, [ac_save_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS $switch" AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])], [eval $cachevar=yes], [eval $cachevar=no]) CXXFLAGS="$ac_save_CXXFLAGS"]) if eval test x\$$cachevar = xyes; then CXXFLAGS="$CXXFLAGS $switch" ac_success=yes break fi done fi]) AC_LANG_POP([C++]) if test x$ax_cxx_compile_cxx11_required = xtrue; then if test x$ac_success = xno; then AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.]) fi else if test x$ac_success = xno; then HAVE_CXX11=0 AC_MSG_NOTICE([No compiler with C++11 support was found]) else HAVE_CXX11=1 AC_DEFINE(HAVE_CXX11,1, [define if the compiler supports basic C++11 syntax]) fi AC_SUBST(HAVE_CXX11) fi ]) tcpflow-tcpflow-1.6.1/m4/ax_pthread.m4000066400000000000000000000326761401360461700175720ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_pthread.html # =========================================================================== # # SYNOPSIS # # AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) # # DESCRIPTION # # This macro figures out how to build C programs using POSIX threads. It # sets the PTHREAD_LIBS output variable to the threads library and linker # flags, and the PTHREAD_CFLAGS output variable to any special C compiler # flags that are needed. (The user can also force certain compiler # flags/libs to be tested by setting these environment variables.) # # Also sets PTHREAD_CC to any special C compiler that is needed for # multi-threaded programs (defaults to the value of CC otherwise). (This # is necessary on AIX to use the special cc_r compiler alias.) # # NOTE: You are assumed to not only compile your program with these flags, # but also link it with them as well. e.g. you should link with # $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS # # If you are only building threads programs, you may wish to use these # variables in your default LIBS, CFLAGS, and CC: # # LIBS="$PTHREAD_LIBS $LIBS" # CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # CC="$PTHREAD_CC" # # In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant # has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name # (e.g. PTHREAD_CREATE_UNDETACHED on AIX). # # Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the # PTHREAD_PRIO_INHERIT symbol is defined when compiling with # PTHREAD_CFLAGS. # # ACTION-IF-FOUND is a list of shell commands to run if a threads library # is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it # is not found. If ACTION-IF-FOUND is not specified, the default action # will define HAVE_PTHREAD. # # Please let the authors know if this macro fails on any platform, or if # you have any other suggestions or comments. This macro was based on work # by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help # from M. Frigo), as well as ac_pthread and hb_pthread macros posted by # Alejandro Forero Cuervo to the autoconf macro repository. We are also # grateful for the helpful feedback of numerous users. # # Updated for Autoconf 2.68 by Daniel Richard G. # # LICENSE # # Copyright (c) 2008 Steven G. Johnson # Copyright (c) 2011 Daniel Richard G. # # 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 3 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, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 21 AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD]) AC_DEFUN([AX_PTHREAD], [ AC_REQUIRE([AC_CANONICAL_HOST]) AC_LANG_PUSH([C]) ax_pthread_ok=no # We used to check for pthread.h first, but this fails if pthread.h # requires special compiler flags (e.g. on True64 or Sequent). # It gets checked for in the link test anyway. # First of all, check if the user has set any of the PTHREAD_LIBS, # etcetera environment variables, and if threads linking works using # them: if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) AC_TRY_LINK_FUNC([pthread_join], [ax_pthread_ok=yes]) AC_MSG_RESULT([$ax_pthread_ok]) if test x"$ax_pthread_ok" = xno; then PTHREAD_LIBS="" PTHREAD_CFLAGS="" fi LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" fi # We must check for the threads library under a number of different # names; the ordering is very important because some systems # (e.g. DEC) have both -lpthread and -lpthreads, where one of the # libraries is broken (non-POSIX). # Create a list of thread flags to try. Items starting with a "-" are # C compiler flags, and other items are library names, except for "none" # which indicates that we try without any flags at all, and "pthread-config" # which is a program returning the flags for the Pth emulation library. ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config" # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # pthreads: AIX (must check this before -lpthread) # none: in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) # -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) # -pthreads: Solaris/gcc # -mthreads: Mingw32/gcc, Lynx/gcc # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads too; # also defines -D_REENTRANT) # ... -mt is also the pthreads flag for HP/aCC # pthread: Linux, etcetera # --thread-safe: KAI C++ # pthread-config: use pthread-config program (for GNU Pth library) case ${host_os} in solaris*) # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (We need to link with -pthreads/-mt/ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather # a function called by this macro, so we could check for that, but # who knows whether they'll stub that too in a future libc.) So, # we'll just look for -pthreads and -lpthread first: ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags" ;; darwin*) ax_pthread_flags="-pthread $ax_pthread_flags" ;; esac # Clang doesn't consider unrecognized options an error unless we specify # -Werror. We throw in some extra Clang-specific options to ensure that # this doesn't happen for GCC, which also accepts -Werror. AC_MSG_CHECKING([if compiler needs -Werror to reject unknown flags]) save_CFLAGS="$CFLAGS" ax_pthread_extra_flags="-Werror" CFLAGS="$CFLAGS $ax_pthread_extra_flags -Wunknown-warning-option -Wsizeof-array-argument" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int foo(void);],[foo()])], [AC_MSG_RESULT([yes])], [ax_pthread_extra_flags= AC_MSG_RESULT([no])]) CFLAGS="$save_CFLAGS" if test x"$ax_pthread_ok" = xno; then for flag in $ax_pthread_flags; do case $flag in none) AC_MSG_CHECKING([whether pthreads work without any flags]) ;; -*) AC_MSG_CHECKING([whether pthreads work with $flag]) PTHREAD_CFLAGS="$flag" ;; pthread-config) AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no]) if test x"$ax_pthread_config" = xno; then continue; fi PTHREAD_CFLAGS="`pthread-config --cflags`" PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" ;; *) AC_MSG_CHECKING([for the pthreads library -l$flag]) PTHREAD_LIBS="-l$flag" ;; esac save_LIBS="$LIBS" save_CFLAGS="$CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS $ax_pthread_extra_flags" # Check for various functions. We must include pthread.h, # since some functions may be macros. (On the Sequent, we # need a special flag -Kthread to make this header compile.) # We check for pthread_join because it is in -lpthread on IRIX # while pthread_create is in libc. We check for pthread_attr_init # due to DEC craziness with -lpthreads. We check for # pthread_cleanup_push because it is one of the few pthread # functions on Solaris that doesn't have a non-functional libc stub. # We try pthread_create on general principles. AC_LINK_IFELSE([AC_LANG_PROGRAM([#include static void routine(void *a) { a = 0; } static void *start_routine(void *a) { return a; }], [pthread_t th; pthread_attr_t attr; pthread_create(&th, 0, start_routine, 0); pthread_join(th, 0); pthread_attr_init(&attr); pthread_cleanup_push(routine, 0); pthread_cleanup_pop(0) /* ; */])], [ax_pthread_ok=yes], []) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" AC_MSG_RESULT([$ax_pthread_ok]) if test "x$ax_pthread_ok" = xyes; then break; fi PTHREAD_LIBS="" PTHREAD_CFLAGS="" done fi # Various other checks: if test "x$ax_pthread_ok" = xyes; then save_LIBS="$LIBS" LIBS="$PTHREAD_LIBS $LIBS" save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS" # Detect AIX lossage: JOINABLE attribute is called UNDETACHED. AC_MSG_CHECKING([for joinable pthread attribute]) attr_name=unknown for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do AC_LINK_IFELSE([AC_LANG_PROGRAM([#include ], [int attr = $attr; return attr /* ; */])], [attr_name=$attr; break], []) done AC_MSG_RESULT([$attr_name]) if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$attr_name], [Define to necessary symbol if this constant uses a non-standard name on your system.]) fi AC_MSG_CHECKING([if more special flags are required for pthreads]) flag=no case ${host_os} in aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";; osf* | hpux*) flag="-D_REENTRANT";; solaris*) if test "$GCC" = "yes"; then flag="-D_REENTRANT" else # TODO: What about Clang on Solaris? flag="-mt -D_REENTRANT" fi ;; esac AC_MSG_RESULT([$flag]) if test "x$flag" != xno; then PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" fi AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT], [ax_cv_PTHREAD_PRIO_INHERIT], [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]], [[int i = PTHREAD_PRIO_INHERIT;]])], [ax_cv_PTHREAD_PRIO_INHERIT=yes], [ax_cv_PTHREAD_PRIO_INHERIT=no]) ]) AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"], [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])]) LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" # More AIX lossage: compile with *_r variant if test "x$GCC" != xyes; then case $host_os in aix*) AS_CASE(["x/$CC"], [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6], [#handle absolute path differently from PATH based program lookup AS_CASE(["x$CC"], [x/*], [AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])], [AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])]) ;; esac fi fi test -n "$PTHREAD_CC" || PTHREAD_CC="$CC" AC_SUBST([PTHREAD_LIBS]) AC_SUBST([PTHREAD_CFLAGS]) AC_SUBST([PTHREAD_CC]) # Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: if test x"$ax_pthread_ok" = xyes; then ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1]) : else ax_pthread_ok=no $2 fi AC_LANG_POP ])dnl AX_PTHREAD tcpflow-tcpflow-1.6.1/m4/slg_check_gcc_diagnostics.m4000066400000000000000000000017671401360461700225750ustar00rootroot00000000000000AC_TRY_COMPILE([#pragma GCC diagnostic ignored "-Wshadow"],[return 0;], [AC_DEFINE(HAVE_DIAGNOSTIC_SHADOW,1,[define 1 if GCC supports -Wshadow])]) AC_TRY_COMPILE([#pragma GCC diagnostic ignored "-Wundef"],[return 0;], [AC_DEFINE(HAVE_DIAGNOSTIC_UNDEF,1,[define 1 if GCC supports -Wundef])]) AC_TRY_COMPILE([#pragma GCC diagnostic ignored "-Wcast-qual"],[return 0;], [AC_DEFINE(HAVE_DIAGNOSTIC_CAST_QUAL,1,[define 1 if GCC supports -Wcast-qual])]) AC_TRY_COMPILE([#pragma GCC diagnostic ignored "-Weffcpp"],[return 0;], [AC_DEFINE(HAVE_DIAGNOSTIC_EFFCPP,1,[define 1 if GCC supports -Weffc++])]) AC_TRY_COMPILE([#pragma GCC diagnostic ignored "-Wsuggest-attribute=noreturn"],[return 0;], [AC_DEFINE(HAVE_DIAGNOSTIC_SUGGEST_ATTRIBUTE,1, [define 1 if GCC supports -Wsuggest-attribute=noreturn])]) AC_TRY_COMPILE([#pragma GCC diagnostic ignored "-Wdeprecated-register"],[return 0;], [AC_DEFINE(HAVE_DIAGNOSTIC_DEPRECATED_REGISTER,1, [define 1 if GCC supports -Wdeprecated-register])]) tcpflow-tcpflow-1.6.1/m4/slg_gcc_all_warnings.m4000066400000000000000000000062031401360461700215770ustar00rootroot00000000000000################################################################ # # Enable all the compiler debugging we can find # Simson L. Garfinkel # # This is originally from PhotoRec, but modified substantially by Simson # Figure out which flags we can use with the compiler. # # These I don't like: # -Wdeclaration-after-statement -Wconversion # doesn't work: -Wunreachable-code # causes configure to crash on gcc-4.2.1: -Wsign-compare-Winline # causes warnings with unistd.h: -Wnested-externs # Just causes too much annoyance: -Wmissing-format-attribute # First, see if we are using CLANG using_clang=no if (g++ --version 2>&1 | grep clang > /dev/null) ; then AC_MSG_NOTICE([g++ is really clang++]) using_clang=yes fi if test x$CXX == "xclang++" ; then using_clang=yes fi # Check GCC C_WARNINGS_TO_TEST="-MD -Wpointer-arith -Wmissing-declarations -Wmissing-prototypes \ -Wshadow -Wwrite-strings -Wcast-align -Waggregate-return \ -Wbad-function-cast -Wcast-qual -Wundef -Wredundant-decls -Wdisabled-optimization \ -Wfloat-equal -Wmultichar -Wc++-compat -Wmissing-noreturn " if test x"${mingw}" != "xyes" ; then # add the warnings we do not want to do on mingw C_WARNINGS_TO_TEST="$C_WARNINGS_TO_TEST -Wall -Wstrict-prototypes" fi if test $using_clang == "no" ; then # -Wstrict-null-sentinel is not supported under clang CXX_WARNINGS_TO_TEST="$CXX_WARNINGS_TO_TEST -Wstrict-null-sentinel" fi echo "C Warnings to test: $C_WARNINGS_TO_TEST" for option in $C_WARNINGS_TO_TEST do SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $option" AC_MSG_CHECKING([whether gcc understands $option]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], [has_option=yes], [has_option=no; CFLAGS="$SAVE_CFLAGS"]) AC_MSG_RESULT($has_option) unset has_option unset SAVE_CFLAGS if test $option = "-Wmissing-format-attribute" ; then AC_DEFINE(HAVE_MISSING_FORMAT_ATTRIBUTE_WARNING,1, [Indicates that we have the -Wmissing-format-attribute G++ warning]) fi done unset option # Check G++ # We don't use these warnings: # -Waggregate-return -- aggregate returns are GOOD; they simplify code design # We can use these warnings after ZLIB gets upgraded: # -Wundef --- causes problems with zlib # -Wcast-qual # -Wmissing-format-attribute --- Just too annoying AC_LANG_PUSH(C++) AC_CHECK_HEADERS([string]) CXX_WARNINGS_TO_TEST="-Wall -MD -D_FORTIFY_SOURCE=2 -Wpointer-arith \ -Wshadow -Wwrite-strings -Wcast-align \ -Wredundant-decls -Wdisabled-optimization \ -Wfloat-equal -Wmultichar -Wmissing-noreturn \ -Woverloaded-virtual -Wsign-promo \ -funit-at-a-time" if test x"${mingw}" != "xyes" ; then # add the warnings we don't want to do on mingw CXX_WARNINGS_TO_TEST="$CXX_WARNINGS_TO_TEST -Weffc++" fi echo "C++ Warnings to test: $CXX_WARNINGS_TO_TEST" for option in $CXX_WARNINGS_TO_TEST do SAVE_CXXFLAGS="$CXXFLAGS" CXXFLAGS="$CXXFLAGS $option" AC_MSG_CHECKING([whether g++ understands $option]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[]], [[]])], [has_option=yes], [has_option=no; CXXFLAGS="$SAVE_CXXFLAGS"]) AC_MSG_RESULT($has_option) unset has_option unset SAVE_CXXFLAGS done unset option AC_LANG_POP() tcpflow-tcpflow-1.6.1/m4/slg_mingw_support.m4000066400000000000000000000023201401360461700212140ustar00rootroot00000000000000################################################################ ## See if we are running on mingw # http://osdir.com/ml/gnu.mingw.devel/2003-09/msg00040.html # Note: Windows 95 WINVER=0x400 # Windows 98 WINVER=0x400 _WIN32_WINDOWS=0x0410 # Windows Me WINVER=0x400 _WIN32_WINDOWS=0x0490 # Windows NT 4.0 WINVER=0x0400 _WIN32_WINNT=0x0400 # Windows NT 4.0 SP3 WINVER=0x0400 _WIN32_WINNT=0x0403 # Windows 2000 WINVER=0x500 _WIN32_WINNT=0x0500 # Windows XP WINVER=0x501 _WIN32_WINNT=0x0501 # Windows Server 2003 WINVER=0x502 _WIN32_WINNT=0x0502 # # mingw32 includes i686-w64-mingw32 and x86_64-w64-mingw32 mingw="no" case $host in *-*-*linux*-*) AC_DEFINE([__LINUX__],1,[Linux operating system functions]) ;; *mingw*) LIBS="$LIBS -lpsapi -lws2_32 -lgdi32" CPPFLAGS="-DUNICODE -D_UNICODE -D__MSVCRT_VERSION__=0x0601 -DWINVER=0x0500 -D_WIN32_WINNT=0x0500 -g $CPPFLAGS" CPPFLAGS="$CPPFLAGS --static " CFLAGS="$CFLAGS --static -static-libgcc -static-libstdc++" CXXFLAGS="$CXXFLAGS -Wno-format " # compiler mingw-4.3.0 is broken on I64u formats CXXFLAGS="$CXXFLAGS --static -static-libgcc -static-libstdc++" LDFLAGS="$LDFLAGS --static" mingw="yes" ;; esac tcpflow-tcpflow-1.6.1/m4/slg_searchdirs.m4000066400000000000000000000016171401360461700204360ustar00rootroot00000000000000if test x"${mingw}" != "xyes" ; then case $host in *mingw*) AC_MSG_NOTICE([Compiling under mingw; will not search other directories.]) ;; *) AC_MSG_NOTICE(Compiling under $host.) # Bring additional directories where things might be found into our # search path. I don't know why autoconf doesn't do this by default for spfx in /usr/local /opt/local /sw /usr/local/ssl; do AC_MSG_NOTICE([checking ${spfx}/include]) if test -d ${spfx}/include; then CPPFLAGS="$CPPFLAGS -I${spfx}/include" LDFLAGS="$LDFLAGS -L${spfx}/lib" AC_MSG_NOTICE([ *** ADDING ${spfx}/include to CPPFLAGS *** ]) AC_MSG_NOTICE([ *** ADDING ${spfx}/lib to LDFLAGS *** ]) fi done AC_MSG_NOTICE([ CPPFLAGS = ${CPPFLAGS} ]) AC_MSG_NOTICE([ LDFLAGS = ${LDFLAGS} ]) ;; esac fi tcpflow-tcpflow-1.6.1/python/000077500000000000000000000000001401360461700161745ustar00rootroot00000000000000tcpflow-tcpflow-1.6.1/python/plot_wifi_aps.py000066400000000000000000000021361401360461700214070ustar00rootroot00000000000000#!/usr/bin/env python3.3 # # Read a report.xml file and output a graphviz graph of the nodes # import xml.etree.ElementTree as ET if __name__=="__main__": import sys root = ET.parse(sys.argv[1]) macs = set() ssids = set() print("digraph ssids {") for ssidnode in root.findall('.//ssid'): macs.add(ssidnode.attrib['mac']) ssids.add(ssidnode.attrib['ssid']) print(' "{}" -> "{}";'.format(ssidnode.attrib['mac'],ssidnode.attrib['ssid'])) # Send through the attributes # Make all of the boxes for mac in macs: print(' "{}" [shape=box]'.format(mac)) # color all of the SSIDs c = 1 for ssid in ssids: r = (c)//3 g = (c+1)//3 b = (c+2)//3 color = "#{:02X}{:02X}{:02X}".format(255-r*16,255-g*16,255-b*16) c += 1 if c/3>4: c = 0 print(' "{}" [color="{}",style=filled]'.format(ssid,color)) for macnode in root.findall(".//ssid/[@ssid='{}']".format(ssid)): print(' "{}" [color="{}",style=filled]'.format(macnode.attrib['mac'],color)) print("}") tcpflow-tcpflow-1.6.1/python/plugins/000077500000000000000000000000001401360461700176555ustar00rootroot00000000000000tcpflow-tcpflow-1.6.1/python/plugins/README.md000066400000000000000000000014061401360461700211350ustar00rootroot00000000000000To execute customizable python plugins: 1. Check examples in directory `tcpflow/python/plugins`. 2. Create a python script with the following properties: - The script contains one or more functions for tcpflow usage. - Each intended function must take a single string parameter. This parameter will hold the contents of the application data captured by tcpflow. - If an intended function returns, it must return a string, which will then be added to the report.xml file with the "plugindata" tag. 3. Execute the `tcpflow` command line with arguments `-e python -S py_path=path -S py_module=module -S py_function=foo`. Example: tcpflow -r my.cap -o flows -e python -S py_path=python/plugins -S py_module=samplePlugin -S py_function=sampleFunction tcpflow-tcpflow-1.6.1/python/plugins/samplePlugin.py000066400000000000000000000032121401360461700226650ustar00rootroot00000000000000## Example of a python plugin for tcpflow. ## This sample contains three functions. ## The first function takes a string and returns a sample message. ## The input string contains the application data from tcpflow's buffer. def sampleFunction(appData): return "This message appears in the XML tag 'tcpflow:result' of report.xml (DFXML)." ## The second function takes a string (application data) ## and writes the application (HTTP) header data to the file ## myOutput.txt located in the python director. ## This function does not return and simply prints to stdout. def headerWriter(appData): fName = "myOutput.txt" f = open("python/" + fName, 'a') headerFinish = appData.find("\r\n\r\n") + 4 headerData = appData[:headerFinish+1] f.write(headerData) f.close() print "Wrote data to " + fName ## The third function takes a string (application data) ## parses the HTTP message (without headers) ## performs a bitwise xor operation with a key defined in the function ## and returns the text corresponding to this binary result. def xorOp(appData): # Assume variable buffer includes message data. dataStart = appData.find("\r\n\r\n") + 4 httpData = appData[dataStart:] binaryData = ''.join(format(ord(x), 'b') for x in httpData) if len(binaryData) < 1: return 0 key = "01101011101" keyLen = len(key) newKey = "" while len(newKey) + keyLen <= len(binaryData): newKey += key i = 0 while len(newKey) < len(binaryData): if i == keyLen: i = 0 newKey += key[i] i += 1 xorRes = int(binaryData,2) ^ int(newKey,2) return '{0:b}'.format(xorRes) tcpflow-tcpflow-1.6.1/samplePcaps/000077500000000000000000000000001401360461700171235ustar00rootroot00000000000000tcpflow-tcpflow-1.6.1/samplePcaps/jpegs.cap000066400000000000000000011761421401360461700207340ustar00rootroot00000000000000òsA%n>> l"ZE0@1[ e  iP4~p&sAp>>"Z lE0@@$a  eP i7;4pRsAp66 l"ZE(@1b e  iP47;PcsA l"ZE@/ e  iP47;PGET / HTTP/1.1 User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.11 [en] Host: 10.1.1.1 Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,video/x-mng,image/png,image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1 Accept-Language: en Accept-Charset: windows-1252, utf-8, utf-16, iso-8859-1;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Connection: Keep-Alive sA<<"Z lE(8@@c0  eP i7;4[P {gsAF"Z lE9@@a|  eP i7;4[P HTTP/1.1 200 OK Date: Sat, 20 Nov 2004 10:21:06 GMT Server: Apache/2.0.40 (Red Hat Linux) Last-Modified: Mon, 08 Mar 2004 20:27:54 GMT ETag: "46eed-a0-800ce680" Accept-Ranges: bytes Content-Length: 160 Connection: close Content-Type: text/html; charset=ISO-8859-1 Ronnie sahlbergs Websida Familjen Sahlbergs Websida sA<<"Z lE(:@@c.  eP i7;4[P yDEsA66 l"ZE( @1_ e  iP4[7;PLsAI>>]o"ZE0 @^ e kP4\psA66 l"ZE( @1] e  iP4[7;PLsAq<<"Z lE(;@@c-  eP i7;4\P yins1sA>>"Z]oE0ُ@qG eP k}4\p"8sAG66]o"ZE(@^ e kP4\~P sA9ff]o"ZEX@\Z e kP4\~PHPOST /scripts/cms/xcms.asp HTTP/1.1 User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.11 [en] Host: ins1.opera.com Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,video/x-mng,image/png,image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1 Accept-Language: en Accept-Charset: windows-1252, utf-8, utf-16, iso-8859-1;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Connection: Keep-Alive Content-length: 433 Content-Type: application/vnd.xacp sAX <<"Z]oE(@1i eP k~4^P@sAY ]o"ZEٳ@\ e kP4^~P sAF<<"Z]oE(@1i eP k~4`PsA߹"Z]oE]1 ettp://opera1-servedby.advertising.com/site=126885/bnum=opera1/bins=1/opid=@@@@/ver=711/dst=Win_700"/> sA66]o"ZE(@^ e kP4`)P7vsAv66]o"ZE(@^ e kP4`)P7usAy>>]o"ZE0@j] e oP4pIsAsz>>]o"ZE0@j\ e pP4plsA>>]o"ZE0#@jW e qP4mppsAn>>]o"ZE0%@jU e sP4vpnsAp>> l"ZE0&@1: e  tP4p"tsAQ>>"Z lE0@@$a  eP t74psA66 l"ZE('@1A e  tP47P1sAvtt l"ZEf(@/ e  tP47P=GET /Websidan/index.html HTTP/1.1 User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.11 [en] Host: 10.1.1.1 Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,video/x-mng,image/png,image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1 Accept-Language: en Accept-Charset: windows-1252, utf-8, utf-16, iso-8859-1;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Referer: http://10.1.1.1/ Connection: Keep-Alive, TE TE: deflate, gzip, chunked, identity, trailers sA-<<"Z lE(H@@  eP t74 PYsA"Z lEܡI@@}k  eP t74 P4HTTP/1.1 200 OK Date: Sat, 20 Nov 2004 10:21:07 GMT Server: Apache/2.0.40 (Red Hat Linux) Last-Modified: Sun, 29 Aug 2004 19:29:11 GMT ETag: "4abce-10e3-f6736fc0" Accept-Ranges: bytes Content-Length: 4323 Connection: close Content-Type: text/html; charset=ISO-8859-1 Familjen Sahlbergs hemsida

    Familjen Sahlbergs hemsida

    Hej och vlkomna hit.

    Hr kommer vi att bertta lite om vrat liv och vra ventyr i vrt nya hemland Australien. Vi flyttade till Sydney i brjan av augusti 2000 och vi trivs jttebra.
    Vi bor i Kariong som ligger lngst kusten strax norr om Sydney.

    Vilka r vi d?

    Familjen Sahlberg Hannas Egen Sida
    Lite om Kariong Ellinors Egen Sida
    Comming Soon: For Our English Friends
    Dagbok

    Resor och ventyr

    Inom Australien

    The Great North Walk 2004-08
    SeaWorld 2004-07
    HerveyBay 2004-07
    Outback/Broken Hill 2002-02
    Jenolan Caves 2001-12-30
    Rejje i Blue Mountains 2001-12-xx
    Rejje i Sydney 2001-12-xx
    Blue Mountains (igen) 2001-02-xx
    Ku-Ring-Gai 2001-02-11
    Hunter Valley 2001-02-03
    Gosford och dromkring 2001-01-26
    Taronga Zoo 2000-11-04
    Blue Mountains 2000-10-29
    Australian Wildlife Park 2000-10-22
    Surfers Paradise : Indy300 2000-10-12 -16

    Utanfr Australien

    Rhode Island 2001-09-29
    Boston 2001-09-23
    New York 2001-08-31
    Nauset Beach 2001-08-19
    Boston 2001-08-18
    Sverige 2001-07-xx
    Barbados 1998-02

    Annat

    Julafton 2000-12-24
    Julfest 2000-12-16

    2002 Threadbo
    2001 Huset i Narrabeen
    2002 Huset i Kariong
    Julafton 2001-12-24
    Julafton 2002-12-24
    ReptilePark 2002
    The Unit in DeeWhy
    Ellie fyller 3 ar 2001-11-03
    Ellie fyller 2 ar 2000-11-03
    Nyfodd Hannah
    KoalaPark 2000-11
    LongReef 2001
    Midsommar 2001
    e  tP4 7#P%sA4"Z lEL@@?  eP t7#4 P4-07-NelsonsBay/index.html">Nelsons Bay 2002-12-07
    HawthornSuites 2001-08


    sAy66 l"ZE(+@1= e  tP4 7P"$sA8>> l"ZE0,@14 e  uP4MpݢsA<:>>"Z lE0@@$a  eP u7z<4Mp sAg:66 l"ZE(-@1; e  uP4M7z=PLsA@>> l"ZE0.@12 e  vP4 1p"sAA>>"Z lE0@@$a  eP v7K4 2psAA66 l"ZE(/@19 e  vP4 27LP#sA66 l"ZE(0@18 e  tP4 7P"#sA<<"Z lE(M@@  eP t74 P^sA l"ZE}1@. e  uP4M7z=PUGET /Websidan/images/bg2.jpg HTTP/1.1 User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.11 [en] Host: 10.1.1.1 Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,video/x-mng,image/png,image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1 Accept-Language: en Accept-Charset: windows-1252, utf-8, utf-16, iso-8859-1;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Referer: http://10.1.1.1/Websidan/index.html Connection: Keep-Alive, TE TE: deflate, gzip, chunked, identity, trailers sA<<"Z lE(@@b  eP u7z=4PP0sA l"ZE2@. e  vP4 27LP$GET /Websidan/images/sydney.jpg HTTP/1.1 User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.11 [en] Host: 10.1.1.1 Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,video/x-mng,image/png,image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1 Accept-Language: en Accept-Charset: windows-1252, utf-8, utf-16, iso-8859-1;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Referer: http://10.1.1.1/Websidan/index.html Connection: Keep-Alive, TE TE: deflate, gzip, chunked, identity, trailers sA<<"Z lE(@@o  eP v7L4 PxsA"Z lE@@\  eP u7z=4PPHTTP/1.1 200 OK Date: Sat, 20 Nov 2004 10:21:07 GMT Server: Apache/2.0.40 (Red Hat Linux) Last-Modified: Fri, 12 Jan 2001 05:00:00 GMT ETag: "46a4f-2059-5e467400" Accept-Ranges: bytes Content-Length: 8281 Connection: close Content-Type: image/jpeg X-Pad: avoid browser bug JFIFHHCreated with The GIMPC 2!=,.$2I@LKG@FEPZsbPUmVEFdemw{N`}s~|C;!!;|SFS||||||||||||||||||||||||||||||||||||||||||||||||||"  gC+ MBU%R("e.uq1u\ҳ`h(PR,(%H() RYe(Y$L2U@P,"@ XBPJIEX-"")&RB (XH((YK((@RPPX((BK%*R,(*APY@ E$3uZP B @4ԡK4%Y@* , l*Q`X,f R,* (-͖DX*RHAA,$4T, !RjU4%EKR(X,@,K"ҡuU,QPDW+-AYR\! 3M"e\K,*ؕeHTIeT,(ʒ-2E@"KL% lʠZRU$RZ(PY @PQ"ijIe(H"UP,-JT,,"T D3M3AePP , Z%(*RKЫHK2)jR(%%B,Yj Y@@ ,E١U ,I5VQYMKBYI5*YE,  `U$K`U$RƊ$R BLR Z* KP\`9Ұ΢RK$d*bRsRY5,XX)@ƍBXK37eP *Q(Pk6 K V,Ȣ((RjR܁H+I43h, 5P#QUP%B "`"*Q(J%@ Bʈ*ZX IV%Q AsE  P% $ "ȠKLYE "AjE%X 5,sA"Z lE@@\  eP u7z4PP "(Y@k6Z@ ` ,-YB3,JQ`X* ,"‚JB@m4 S3B)e,RP,6)H[,% ŔeYRi e&RT\W6U@[ \P %J%$"’ZB"ZXUQVRYB`K ,AHR - b,bPEE2(T[sR5&5 (d-JAVPYB ` R hDm,,  a(P&P K, ʬV ( @!,)r-lP.R:R 5-΀P% QJ"ʔ@K Ae[(I,4P"R(Q,Bh, b*K[f%H ,DYA` @LثI@J%,Ēe((RC4JmRMdU2$5lQ Bj Te%E "[" UUYKsDS2ˬj Qe,B`pژ[|???# 0A!1@PQqa?!3" m^*_iQb2xROtV|J9!B+Mӆ^)…xw@.S_E?w) (n]㖖/ u^~mbKǠZ/*Z|Ӷ#7.2EaNhJJBR8ſ4P*P9 *Tx#}FhqYƺ=R iT7τum- (n .sT8E <0< c.cWM#IjX>01~[PO4,X/|]gAk~Pb7btXajhZ#HV/Ct)x`~/ ?H7) †68[]c۔VbpS̀qX& ҆9]AۨSžrZZM6ijͧSAZAźO KMדяWo~d1i$x[…ݡG 4Z)/7=fצ2 pb !Ì[iSB)*P(*h~+ J*T P->çGcH*.<>hscBq|={ 3퇫MQp >y~友X_ePExA" j7bҶGq,>00 sA,66 l"ZE(3@15 e  uP4P7zP>sAi"Z lEܴ@@i  eP v7L4 PȒyHTTP/1.1 200 OK Date: Sat, 20 Nov 2004 10:21:07 GMT Server: Apache/2.0.40 (Red Hat Linux) Last-Modified: Tue, 16 Jan 2001 05:00:00 GMT ETag: "46a51-2355-d5a3f400" Accept-Ranges: bytes Content-Length: 9045 Connection: close Content-Type: image/jpeg X-Pad: avoid browser bug JFIFHHCreated with The GIMPC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222Y" ݙG8C.$&iDdlt-2Խ**yX/x#(&`B"əIL!$k#/DETR`/;bH|Uet-#y}܃[O"ͮ }' jY׫v3Y`[]\2$,KhTLWU] !F6=ׅqWlnY6]qfkD}e.T2w=ƎMF"8yuapWOaO,z8 `53`Cރ-98o*W'5X։ܷk#f0l&++R,XT΢Ў%XnU^n9Y@0r۬Vhz Nո%r j L+!V!=תdXbS9"GBy͠1>36p33۪zںס#faψ]rD-sj9GlotEMeϫ^Yؘ| æ왞ĵ߹mvAI>ѿ}b']sAK"Z lE@@\  eP u7z4PPn}Kpciq凛kux]<8Dmn8ëE.T[ Z  P?CU4  '  `)L`QB(@IG"]HG#j 0#9(E"ȅ)@v$;r"Fn0$ -HD4M[Jԑ,7$0 J%Y:$(  2TA=%Lc&Hkg vIRA5iJ :"GDΊUXʊ ԐXY(SVh$ʩ^N1V` آy) B >%HXt[j3*i[RMa0*O=exn'өIjڋMgxy" bh]: ~iaiT@*ʭ*#+$Bz><  4*ym42XAN ]R`  ,3f[*R~2XH)xaނ@4b8R??'!1AQaq 0?viDlBVqBxgDaVbTAR0V*(ay,o J 6tR&,ޙnDȣm Gb 8Ӄ,4q)m[m=#Rx S%E #fkLx9aāvRTYL)&d"cjd{%-CG=٥ਖo) ePZ= g1g"( "`(A 4%kT4=446"±;IĴ#\nv .s轞F폂T$ R8G2#z8#;"x6B MIl^@ѴXްSnh"Z=R&Nrpqp$D,k&NH@"2(>.Щ+Pȁe xEYhj(ϱSWB]lDV$Md,NFÐlj=C}٭"h%WeP*vl zc" eF#d\-"% 8=k HsA66 l"ZE(4@14 e  uP4P7zYP9.sA6"Z lE@@\  eP u7zY4PP<"P"!$  ׳؛^H9GHR@4I84q L+RǸCwblJ7>"+y%u:*-LhQz95 lgpLJ!_$v66'[/G:evC>ˑ ޻ (klp'PE 5Й)A6MᡮD1F 9b<Dw95:c9:N-eI)M$Ȕ;!cT1)991F%=(D%#cvOV7]:EQcDTL%#FEj' #};٥g+6lN6FrI xbFA0OV2ɂW"=ξ ehCCv2C,p(!}B/3abSb4IppNf $ g"d z$,FYX9k Ɂg4-yhC&Ɖ HJj9%u$͋vhb/l4{gR9cnD7[(d`DH($Njdt*؞r}[/"ddP 4nb\FY?ѡɑ1aFXg4?D7Dx,fK"6ɫeXę"i E0$5؈ʴ<̍ǁm Y''D_#HR؄@ؾ)b99q0Bl$E`K,@NPQ.ƇDAQ.M 히o6sHF%p(*D}< y"t4~b"|XJȱi4ĥġpB_?(T͚#8^'%Rŏǡz>N4WxVy)D.PmtYC؆E2n qА>L#Q#n;BaAGxZ9"ĶH؋%?jy[V8%CW 64[?Bi2d$\xX8b$bbIq'j4=l蔋 -[r(rR;s$?#n:e< P$6h'D &vpGCU&4C$no!)6DXR*D?ōԡ+(VoNDq^^FgєďDY̓dpݔODIZbxbb7gdD2Dlp;f_b"4 T hMoCDvO((%p[mn Ŧp(Z68/ZB]aA?V5ȨDEaGH\H=/$t$t4d{%6%}pxcP=%8H5N\}#pDB ʂxr=D&ih;ȝ!{KO~DbP{(wН A$l#F) dԐ@S[5ڄ(tGw{P@IpC=5[cP℘HDWcDcxdYb^4dG| 4`D+ fSxؗc얶"Xv6pqB$cU)gDc)RBӤS><@QIYBEk꠪99D'BA}b}bX~K$ibE0#, R} >K"٢g:& zx¼5&ЄxycxDa؄8P4AqC&ׄD(- kFbi ld'g4ĚM\%y%txQ-LhPDŽ{W>9I{ jE J܏lz LF&D ,k}>>N< d#VWLog4rW# ӂqIL} !(vXb&ГD(x~$$/a=Oc#KkO+sBDӂ! #,p7Е;٪ؘ$r1>$hD\>d8ěƉ^F%F/'Erz887n,YI ([%6qr'$?q&Ȋ4O5l+@Pɍ"#lC&;fG)! Cf pټ  z% |7-^ƃJFaaaOctm Y Ј"D'Xh? Xv5Drer*ĿFQdp$&$xCk3M5sA66 l"ZE(5@13 e  uP4P7zP-sA(("Z lE@@]  eP u7z4PP~<#[&p5;^4$C!-D%6&ɫ <5dHƼnE%'I(p;8G=lxp+,L;C#) 4#GhAK2تd DXN͊ 6D>#RxRaQYc=@>cW&>ɃIcvZ*X" ؤLhxzΐsׂlP1(^O?8$V7C M WpI$ w|;72ɓAzоIhX{'$V ؄Gď2 XD?p;cpd$XX22?;G/3DDMPxMf 8ÿ 8(S@"KGDH-D5?6yE.Iꆠ#dGhW/X~ɃD~LȻ#`X˂%*O9"}#xVxHcT11B[*Ȍ1F=..M-CdKhDCLTɁR95fxXg"dxB|!Pš(rr.ŲxVYhGÞDFps&$C$'/C9#&q#kG%1FqI'\ QycD}{Sr6;4J9z k$EDlF _GXbЧ` )1 ~k[ ױR,IV"a4Aivi:)?<,,D$10hX4isȭ E CШnp oD-!IhЉ.C+$4FW(B] DP#fCTp;Bc$8FJ$xP'%x )D_"K[D~/D4GB,<ŬB7w3hNv1Z ?D4MY3U|')nZ[4'(D64 5g0A>I4&áN#*= 4@4q"xT RB'D_xQ,M .J7n (s$ 7ClOlA=$x Roٲ lLXE8LvD; RD {,&= $OOgџٻsA66 l"ZE(6@12 e  uP4P7zP -sA"Z lEܴ@@i  eP v74 Pȡ:4+D˙}Ƥ[s3>3ϡD\$[`3J-KŹBi-us]\⺏R6r076tj}7bjX Գ>FikQc(װlR=b[jX). Q5dH&Xbgk7:!s+z[Qe<"|YZO|XU+oib]S}V6C WvF Eh0'9pѪm,*rr;dNy6l$m'7B/3ASﲖf4VmܹfB}dI^J{T~U.~]~Ms;%hF7 zS1[b 96+#n76 3140RӅ 3_M8o8qecbi&pbwȖ=;$G|-v!Ѽ1sleIb96o?8# BE`D|,cyOJJ*TH*R *T"Ig2!1A"Q 02aqPB@Rb?Ʊ%JҪ}IHؔ\/v&\82$7[!:ܽ#égdͽO9 UUGf9U_$-1LRf!ೱni?z?dJٗDoDmy<\[Mb&1scOR=3 }[rBFXgQܝYy7!gLi7-}cOJCi8J}^UR5S"SwDM?FhS>0:z_ G9,rԿR,EDFE0p cM.o/:lA>8=/ܺ]~^Xθ?)9Z].ѕݴ70aaQJw 1ňrEZ=_'!1AQaq ?!>A* dRiTL/70K2tZft1)*\@ YQ;*%3ȕZr&_-BͭϘ4kdX=;Js;,0NFA~Rh{D-9w!Y8e˖SLdVuHf)Ch7*= n&j!S"/7\ 3.bIKhm?S~V-/QGhl/")3 B2fycD" OF&Dk B(sY)/B(cz7o^%@7c[r5qq083+탧3ٔ@(eh{9`a6QvcRn0L F}A4{Pyz#3..-s'RORJ /P1s380l\,ܔTqc]Qio)_Q^ħnUzڧѽp~"ڡXIb~>^3(`\>!۞(Ŕ(ESy{n:[+5̲cW+,=:= 58G?Qt=n8F:zq?CGshG~]st?ߟ  FD ~e&,׳ }||EY.@n/jʪ$>i`y f)\茌uQRMV6bq:Z~ &4N ؋C $=Q 1lgB‚QBB 4 h=I!RQ1LKñŽ|E, E85O!1AQ qa?ߖ~Na,[m'2ضB۷vAsa`, K72~zژyՃm"W̋d6m2\%.0D,>ɹ,qsA="Z lEܴ@@i  eP v7 4 PN;Z#"QP;tv|ڳ+`w2յrG'pC^YRU}yhٱ@;Kkk+jJr#6l]O29$#ܞ['bǃ3b͉ڻdyԶ'!1AQaq ? (&&J; eK[`M79ZU*NH]M)q'0L0K[')]„ Q.!dC $,e\@L(!3!qT_[QILZƜ9xtY@b&C@^}1o@ T j6\z2b&FTȼ1,)({Ƅ gH&7YbPVrq(uHASSRe*ϼ0#y`|\haDL+d՗-Ί)/HLo0G+ψ v$(m ." Թ 'doL_U G`S"&)tv|DĶŶY[QjVgLSp7vrw)Y_1=44G(sB|mxdM$p䣇JW=,4bQijK(k2wXrK]q j)*"/AQ+ sl"=Ȑ9Jm(VۛWQu%iK`b@Vb`ܐ c*=r֜*`!W5Lٱ%*}DQb2i*8*)a/0Z91ΚiP[)jF-U .#Xq64^c%UeR&ErK[(ZL2/kKEw Pbՠl}( [ c#n(R ,T`5?1`&Sľ?x@ۚdL0r- mU"ս+`tR\J_è=Y0p1\ ^}a , x^g;'fׂ]T,XhΡ]Z*B! g nP!yqUViDLZ)ūU)vÈMڣhF( u`pLe }_ȿ/塣4tn$8bcHb_4@_+7jb609Priĉ]j)VSM@R~Yc m}+|M75eqJsR *ʭq"iEEM2<˲·EyG|&n6/!ȐځNKՎ%;^>~,wz#$[08?0X? \;WzݩT'W$t䔴k?قeF_eCn`dyVg/TOsA\66 l"ZE(9@1/ e  vP4 7PsA""Z lEܴ@@i  eP v74 Pƹ}壓5)$J1DS. zC^(abQYÒcʰ.K 4eFlSEj}'ĪpIR=/O ʉ+'Sku4"6p8SAjruq+$w L%%)q[o6(MW.-x2qIt^,F%W.0*Z69ZדB\ǴhK&Q+h/6\ A[k, 9늠&eB3qLJ14 +[ ږsU CSW[C[nsX2q3pnމj=82DW`jmZk <'D 2(*.@f҅dS*gq(^3Ϥ]Do"4R*"i0PRڬ>s6{'@qo9h30}y(6%7 4Kp?`SP]Ōc~g#z[[ axGZrƵ,m}Oy~|A-| T_$o0H*Q׮)y’qǦX[Ohs慔u[{ 1k'ءxF ||ȾGLEpz!4f 3&G&=rUq$ }`\ dUQ,v<iTK?QQ IrER&mMQHUEΠ_^УBai@*}^u*MLi~bot3-.BΟ0cSA1!r0*s*JԽli`Si-r`v-ˊ@z0>ѶqVpEl59z`/YЊb#t2gPȭ`jظ -3cע 57)ZOsA_66 l"ZE(:@1. e  vP4 7PsAkpp"Z lEb@@m^  eP v74 PP=!TM鈩*yAAu1+XŔωdsgzAV2e wscĪMD UoW<$} 6.5ccH\uT-ys/PF%Ra'RkQ2E=PKeL\yN?1cNA#C?PS e*|^P<BiO:e@~e8o>!SY, WE%ňq[@r<Ȯ Hq⍞KӳV+Ħ<He`>0 CeЃLU.-R8g*hA<)j",Juj>g͂'Eiumdey,PWH>Hi\=& V^X&LV/^.'8a" Y@\>:Y2܎rW3dЦWu5v猷&b i_pkl^9d܎!{&蜞jz5fMfiZ0fs&M泟l7_OMވ}wu}lٛSs6YٻsA66 l"ZE(;@1- e  vP4 7PsAK <<"Z]oE(@1i eP k)4`P sA| >>"Z]oE0@0m{ eP o:4psA-} 66]o"ZE(<@jF e oP4:PJ;sA >>"Z]oE0@0m{ eP pE4pDsAO 66]o"ZE(=@jE e pP4FP sA >>"Z]oE0@0m{ eP qV4mp^sA@ 66]o"ZE(>@jD e qP4mWP8sA ]o"ZEܳ?@d e oP4:PGET /site=126885/bnum=opera1/bins=1/opid=10030285/ver=711/dst=Win_700 HTTP/1.1 User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.11 [en] Host: opera1-servedby.advertising.com Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,video/x-mng,image/png,image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1 Accept-Language: en Accept-Charset: windows-1252, utf-8, utf-16, iso-8859-1;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Cookie: opera1=_4197c290,,126885^76592&127709^162766_; ACID=ee440010568883680002!; BASE=I9PbXsuDOePjSe2vKrrCSFCkbS4bJ4cuPcmErx85XsxxbLWN57hTMkwaoEGwJcbgAeiU6I3kLpaOB9FsfHZRMbi4E+6ANWpiTWCVj43x54Jamu4nxtXcghhEAMTGzIYIPsXQOttbEwPBD4EfFavQNSwBma85qhmudMAPtwj9bGZkrvYVvJh1IGOe769w/6tbmY0pHbrzlazeGlr+9wgQ2l1KAb+7+g06VQm30/O1HiiJ0oDPxRWVBNEJcGuH3rDtA405LpbFoxdVzqX8DK9Jgd7NZUJn6pGi0mZNEbfUN5jP82cZjapg5yw/Ae2r4Wcbtjas+w41VVm13apJtqT3cm1EkXnfoWkeYr07Kw4Bc6fY6ov/zNBWIHVtwfej6QaB8JD38YnFrBpHtoaD3m24SlXEYlhaNi9uth8DrfxdnQA/hVqqYCyW66F5sFP+ks79IK3o+KOui1fVBDssNcvfCND+a8LJ9wwIjEzmkHQ2bBIE7pcfO7GllXeqJwLRUPQ2Ccs/a7Z0jmdXKNC+Z9GIUaNyWKwvFQRSa1b5yMFRNGbCbIaQn5BHpWq4yN7JY1UifxjsNQvv8hXHPezOK/OolqE+k2oY9vUK6iVhJIcDDmSaPGJNf8KUsZxUskthDOzFfR0AFqLagTv3HWa14Tv++Up9kEmoP2pOObxY4rQWa95IEWDN88r41es86cnk0+Fkh8eY8URccZwFsrw4+FecKmqAtoGlEGhC9RCfN72oW4ATAP+SZsCoayViCJBuRdgXoeIij34w/wJgAIkcWTri+suR6vk27loQSeXJrkHJ5TINJnuV4CJw9Hfw8N3kb8jrT89sA> ]o"ZE@@e e oP4 Q:P[X2FEdTsjFxyPj476AYTSU7luDDTIwlPP+S6I8VUGhotFELuHmZ/bNs4hHDDQesJYHoL7C0jmDkj3Qxua4d6Za6cxjIzTd0o6yVP6jeJWEsuIQ9sxzKrxWG5Ngd6jSLEQNX1xRM+E/EM7xmZEaAJdY98kKdxnVM1qk67DIhy29ZG8xYF1SfUtkqRTECV7tYy6WImFo+CPIHPTmpdwLHb38Kmj+7fKJI2GyjMr/mX0jww/ySaSKFQLw2APgKDYhhQ1kPOsgmsnmVqhhEDCwZ3R2CGMRE6ZSuzN7BLvBZpvcRNMiqRtyQwTfBORHP92eGyI2pUgMISxfZYfS2UCVtjKMAdBkl2lZPg71KKUiYlGhui1owWh4/AT/67cgJQcFuX/1MRbiiDZtjg5fuqlHNJjcWnYqFYYLOzWm+nSl47+2o+FEc38Q+uDDBaXVQQ5afYoLbFQ+axx+Ry99y2xnt+KaV2VrDgoIE4KgUN8wTgg0aD3ksAXFQtrnS+3R2/XWs6MxfuXXm3vRYVP/KqomT3av1lvxHDKmDF1KIbxrZgk/bPOtjNJvJNv1VGGNc7lXOyb9QIO3nNS0JkiogRYFuHUN9mTlxF5O5Q7cVJwIyZmQeenOG+k2a+pEu2lV/sXns0TCHJCfRoNFn5Xi9ugUKA36J8O4al71cLrQMClzYgFuPJ2xqn6Ukaih/RmD6X7o2bkw9Kr18jK0SspdbQlzfYjNsVGsTGWOX5MFmjn5foLuXg7BQNMSxy5WjKyCa/zAHGdFb0ju2Bv/pug9wmlVZOapWdmVBZM+ZjgcFezND9x3Q0C!; ROLL=31xDrGN5IimxKkJ51kc5Cx4G7qMgPtReMWYbRmrJuOY1K7T0qekbO3O4PBZKI/JVLaqdFAyPtYSbjo3WMAAeIqfFtCRWt/xKVPbo/EOHQah6/PQnwjFfXecQD+xHLgat+JBSLn+poF57xWdsYjdmaMqI1YfjU7xOIgQL+sklB1t3kGtcPaEE07NoKZnOW5ac3ml8vMH9ZZuYpMIPB8wxrYWVAfvwoy1oi7AoQsho/ZO6X3SxKTFyIXviy62QHGC+cYrI5y3b+20HxMb4+onw+vjDUiL436A! Cookie2: $Version=1 Connection: Keep-Alive sAv ]o"ZEܳA@d e pP4FP@GET /site=126885/bnum=opera2/bins=1/opid=10030867/ver=711/dst=Win_700 HTTP/1.1 User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.11 [en] Host: opera2-servedby.advertising.com Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,video/x-mng,image/png,image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1 Accept-Language: en Accept-Charset: windows-1252, utf-8, utf-16, iso-8859-1;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Cookie: opera2=_4197c290,,126885^76592&127709^162766_; ACID=ee440010568883680002!; BASE=I9PbXsuDOePjSe2vKrrCSFCkbS4bJ4cuPcmErx85XsxxbLWN57hTMkwaoEGwJcbgAeiU6I3kLpaOB9FsfHZRMbi4E+6ANWpiTWCVj43x54Jamu4nxtXcghhEAMTGzIYIPsXQOttbEwPBD4EfFavQNSwBma85qhmudMAPtwj9bGZkrvYVvJh1IGOe769w/6tbmY0pHbrzlazeGlr+9wgQ2l1KAb+7+g06VQm30/O1HiiJ0oDPxRWVBNEJcGuH3rDtA405LpbFoxdVzqX8DK9Jgd7NZUJn6pGi0mZNEbfUN5jP82cZjapg5yw/Ae2r4Wcbtjas+w41VVm13apJtqT3cm1EkXnfoWkeYr07Kw4Bc6fY6ov/zNBWIHVtwfej6QaB8JD38YnFrBpHtoaD3m24SlXEYlhaNi9uth8DrfxdnQA/hVqqYCyW66F5sFP+ks79IK3o+KOui1fVBDssNcvfCND+a8LJ9wwIjEzmkHQ2bBIE7pcfO7GllXeqJwLRUPQ2Ccs/a7Z0jmdXKNC+Z9GIUaNyWKwvFQRSa1b5yMFRNGbCbIaQn5BHpWq4yN7JY1UifxjsNQvv8hXHPezOK/OolqE+k2oY9vUK6iVhJIcDDmSaPGJNf8KUsZxUskthDOzFfR0AFqLagTv3HWa14Tv++Up9kEmoP2pOObxY4rQWa95IEWDN88r41es86cnk0+Fkh8eY8URccZwFsrw4+FecKmqAtoGlEGhC9RCfN72oW4ATAP+SZsCoayViCJBuRdgXoeIij34w/wJgAIkcWTri+suR6vk27loQSeXJrkHJ5TINJnuV4CJw9Hfw8N3kb8jrT89sA ]o"ZEB@e e pP4渊FPX2FEdTsjFxyPj476AYTSU7luDDTIwlPP+S6I8VUGhotFELuHmZ/bNs4hHDDQesJYHoL7C0jmDkj3Qxua4d6Za6cxjIzTd0o6yVP6jeJWEsuIQ9sxzKrxWG5Ngd6jSLEQNX1xRM+E/EM7xmZEaAJdY98kKdxnVM1qk67DIhy29ZG8xYF1SfUtkqRTECV7tYy6WImFo+CPIHPTmpdwLHb38Kmj+7fKJI2GyjMr/mX0jww/ySaSKFQLw2APgKDYhhQ1kPOsgmsnmVqhhEDCwZ3R2CGMRE6ZSuzN7BLvBZpvcRNMiqRtyQwTfBORHP92eGyI2pUgMISxfZYfS2UCVtjKMAdBkl2lZPg71KKUiYlGhui1owWh4/AT/67cgJQcFuX/1MRbiiDZtjg5fuqlHNJjcWnYqFYYLOzWm+nSl47+2o+FEc38Q+uDDBaXVQQ5afYoLbFQ+axx+Ry99y2xnt+KaV2VrDgoIE4KgUN8wTgg0aD3ksAXFQtrnS+3R2/XWs6MxfuXXm3vRYVP/KqomT3av1lvxHDKmDF1KIbxrZgk/bPOtjNJvJNv1VGGNc7lXOyb9QIO3nNS0JkiogRYFuHUN9mTlxF5O5Q7cVJwIyZmQeenOG+k2a+pEu2lV/sXns0TCHJCfRoNFn5Xi9ugUKA36J8O4al71cLrQMClzYgFuPJ2xqn6Ukaih/RmD6X7o2bkw9Kr18jK0SspdbQlzfYjNsVGsTGWOX5MFmjn5foLuXg7BQNMSxy5WjKyCa/zAHGdFb0ju2Bv/pug9wmlVZOapWdmVBZM+ZjgcFezND9x3Q0C!; ROLL=31xDrGN5IimxKkJ51kc5Cx4G7qMgPtReMWYbRmrJuOY1K7T0qekbO3O4PBZKI/JVLaqdFAyPtYSbjo3WMAAeIqfFtCRWt/xKVPbo/EOHQah6/PQnwjFfXecQD+xHLgat+JBSLn+poF57xWdsYjdmaMqI1YfjU7xOIgQL+sklB1t3kGtcPaEE07NoKZnOW5ac3ml8vMH9ZZuYpMIPB8wxrYWVAfvwoy1oi7AoQsho/ZO6X3SxKTFyIXviy62QHGC+cYrI5y3b+20HxMb4+onw+vjDUiL436A! Cookie2: $Version=1 Connection: Keep-Alive sA ]o"ZEܳC@d e qP4mWP?GET /site=126885/bnum=opera3/bins=1/opid=10032112/ver=711/dst=Win_700 HTTP/1.1 User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.11 [en] Host: opera3-servedby.advertising.com Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,video/x-mng,image/png,image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1 Accept-Language: en Accept-Charset: windows-1252, utf-8, utf-16, iso-8859-1;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Cookie: opera3=_4197c291,,126885^76592&127709^162766_; ACID=ee440010568883680002!; BASE=I9PbXsuDOePjSe2vKrrCSFCkbS4bJ4cuPcmErx85XsxxbLWN57hTMkwaoEGwJcbgAeiU6I3kLpaOB9FsfHZRMbi4E+6ANWpiTWCVj43x54Jamu4nxtXcghhEAMTGzIYIPsXQOttbEwPBD4EfFavQNSwBma85qhmudMAPtwj9bGZkrvYVvJh1IGOe769w/6tbmY0pHbrzlazeGlr+9wgQ2l1KAb+7+g06VQm30/O1HiiJ0oDPxRWVBNEJcGuH3rDtA405LpbFoxdVzqX8DK9Jgd7NZUJn6pGi0mZNEbfUN5jP82cZjapg5yw/Ae2r4Wcbtjas+w41VVm13apJtqT3cm1EkXnfoWkeYr07Kw4Bc6fY6ov/zNBWIHVtwfej6QaB8JD38YnFrBpHtoaD3m24SlXEYlhaNi9uth8DrfxdnQA/hVqqYCyW66F5sFP+ks79IK3o+KOui1fVBDssNcvfCND+a8LJ9wwIjEzmkHQ2bBIE7pcfO7GllXeqJwLRUPQ2Ccs/a7Z0jmdXKNC+Z9GIUaNyWKwvFQRSa1b5yMFRNGbCbIaQn5BHpWq4yN7JY1UifxjsNQvv8hXHPezOK/OolqE+k2oY9vUK6iVhJIcDDmSaPGJNf8KUsZxUskthDOzFfR0AFqLagTv3HWa14Tv++Up9kEmoP2pOObxY4rQWa95IEWDN88r41es86cnk0+Fkh8eY8URccZwFsrw4+FecKmqAtoGlEGhC9RCfN72oW4ATAP+SZsCoayViCJBuRdgXoeIij34w/wJgAIkcWTri+suR6vk27loQSeXJrkHJ5TINJnuV4CJw9Hfw8N3kb8jrT89sA ]o"ZED@e e qP4sWP-YX2FEdTsjFxyPj476AYTSU7luDDTIwlPP+S6I8VUGhotFELuHmZ/bNs4hHDDQesJYHoL7C0jmDkj3Qxua4d6Za6cxjIzTd0o6yVP6jeJWEsuIQ9sxzKrxWG5Ngd6jSLEQNX1xRM+E/EM7xmZEaAJdY98kKdxnVM1qk67DIhy29ZG8xYF1SfUtkqRTECV7tYy6WImFo+CPIHPTmpdwLHb38Kmj+7fKJI2GyjMr/mX0jww/ySaSKFQLw2APgKDYhhQ1kPOsgmsnmVqhhEDCwZ3R2CGMRE6ZSuzN7BLvBZpvcRNMiqRtyQwTfBORHP92eGyI2pUgMISxfZYfS2UCVtjKMAdBkl2lZPg71KKUiYlGhui1owWh4/AT/67cgJQcFuX/1MRbiiDZtjg5fuqlHNJjcWnYqFYYLOzWm+nSl47+2o+FEc38Q+uDDBaXVQQ5afYoLbFQ+axx+Ry99y2xnt+KaV2VrDgoIE4KgUN8wTgg0aD3ksAXFQtrnS+3R2/XWs6MxfuXXm3vRYVP/KqomT3av1lvxHDKmDF1KIbxrZgk/bPOtjNJvJNv1VGGNc7lXOyb9QIO3nNS0JkiogRYFuHUN9mTlxF5O5Q7cVJwIyZmQeenOG+k2a+pEu2lV/sXns0TCHJCfRoNFn5Xi9ugUKA36J8O4al71cLrQMClzYgFuPJ2xqn6Ukaih/RmD6X7o2bkw9Kr18jK0SspdbQlzfYjNsVGsTGWOX5MFmjn5foLuXg7BQNMSxy5WjKyCa/zAHGdFb0ju2Bv/pug9wmlVZOapWdmVBZM+ZjgcFezND9x3Q0C!; ROLL=31xDrGN5IimxKkJ51kc5Cx4G7qMgPtReMWYbRmrJuOY1K7T0qekbO3O4PBZKI/JVLaqdFAyPtYSbjo3WMAAeIqfFtCRWt/xKVPbo/EOHQah6/PQnwjFfXecQD+xHLgat+JBSLn+poF57xWdsYjdmaMqI1YfjU7xOIgQL+sklB1t3kGtcPaEE07NoKZnOW5ac3ml8vMH9ZZuYpMIPB8wxrYWVAfvwoy1oi7AoQsho/ZO6X3SxKTFyIXviy62QHGC+cYrI5y3b+20HxMb4+onw+vjDUiL436A! Cookie2: $Version=1 Connection: Keep-Alive sA 2 >>"Z]oE0@0m{ eP s>4vp sAe2 66]o"ZE(E@j= e sP4v>PPlsA6 ]o"ZEܳF@d e sP4v>PGET /site=126885/bnum=opera4/bins=1/opid=10003005/ver=711/dst=Win_700 HTTP/1.1 User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.11 [en] Host: opera4-servedby.advertising.com Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,video/x-mng,image/png,image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1 Accept-Language: en Accept-Charset: windows-1252, utf-8, utf-16, iso-8859-1;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Cookie: opera4=_4197c291,,126885^76592&127709^162766_; ACID=ee440010568883680002!; BASE=I9PbXsuDOePjSe2vKrrCSFCkbS4bJ4cuPcmErx85XsxxbLWN57hTMkwaoEGwJcbgAeiU6I3kLpaOB9FsfHZRMbi4E+6ANWpiTWCVj43x54Jamu4nxtXcghhEAMTGzIYIPsXQOttbEwPBD4EfFavQNSwBma85qhmudMAPtwj9bGZkrvYVvJh1IGOe769w/6tbmY0pHbrzlazeGlr+9wgQ2l1KAb+7+g06VQm30/O1HiiJ0oDPxRWVBNEJcGuH3rDtA405LpbFoxdVzqX8DK9Jgd7NZUJn6pGi0mZNEbfUN5jP82cZjapg5yw/Ae2r4Wcbtjas+w41VVm13apJtqT3cm1EkXnfoWkeYr07Kw4Bc6fY6ov/zNBWIHVtwfej6QaB8JD38YnFrBpHtoaD3m24SlXEYlhaNi9uth8DrfxdnQA/hVqqYCyW66F5sFP+ks79IK3o+KOui1fVBDssNcvfCND+a8LJ9wwIjEzmkHQ2bBIE7pcfO7GllXeqJwLRUPQ2Ccs/a7Z0jmdXKNC+Z9GIUaNyWKwvFQRSa1b5yMFRNGbCbIaQn5BHpWq4yN7JY1UifxjsNQvv8hXHPezOK/OolqE+k2oY9vUK6iVhJIcDDmSaPGJNf8KUsZxUskthDOzFfR0AFqLagTv3HWa14Tv++Up9kEmoP2pOObxY4rQWa95IEWDN88r41es86cnk0+Fkh8eY8URccZwFsrw4+FecKmqAtoGlEGhC9RCfN72oW4ATAP+SZsCoayViCJBuRdgXoeIij34w/wJgAIkcWTri+suR6vk27loQSeXJrkHJ5TINJnuV4CJw9Hfw8N3kb8jrT89sA76 ]o"ZEG@e e sP4|>PیX2FEdTsjFxyPj476AYTSU7luDDTIwlPP+S6I8VUGhotFELuHmZ/bNs4hHDDQesJYHoL7C0jmDkj3Qxua4d6Za6cxjIzTd0o6yVP6jeJWEsuIQ9sxzKrxWG5Ngd6jSLEQNX1xRM+E/EM7xmZEaAJdY98kKdxnVM1qk67DIhy29ZG8xYF1SfUtkqRTECV7tYy6WImFo+CPIHPTmpdwLHb38Kmj+7fKJI2GyjMr/mX0jww/ySaSKFQLw2APgKDYhhQ1kPOsgmsnmVqhhEDCwZ3R2CGMRE6ZSuzN7BLvBZpvcRNMiqRtyQwTfBORHP92eGyI2pUgMISxfZYfS2UCVtjKMAdBkl2lZPg71KKUiYlGhui1owWh4/AT/67cgJQcFuX/1MRbiiDZtjg5fuqlHNJjcWnYqFYYLOzWm+nSl47+2o+FEc38Q+uDDBaXVQQ5afYoLbFQ+axx+Ry99y2xnt+KaV2VrDgoIE4KgUN8wTgg0aD3ksAXFQtrnS+3R2/XWs6MxfuXXm3vRYVP/KqomT3av1lvxHDKmDF1KIbxrZgk/bPOtjNJvJNv1VGGNc7lXOyb9QIO3nNS0JkiogRYFuHUN9mTlxF5O5Q7cVJwIyZmQeenOG+k2a+pEu2lV/sXns0TCHJCfRoNFn5Xi9ugUKA36J8O4al71cLrQMClzYgFuPJ2xqn6Ukaih/RmD6X7o2bkw9Kr18jK0SspdbQlzfYjNsVGsTGWOX5MFmjn5foLuXg7BQNMSxy5WjKyCa/zAHGdFb0ju2Bv/pug9wmlVZOapWdmVBZM+ZjgcFezND9x3Q0C!; ROLL=31xDrGN5IimxKkJ51kc5Cx4G7qMgPtReMWYbRmrJuOY1K7T0qekbO3O4PBZKI/JVLaqdFAyPtYSbjo3WMAAeIqfFtCRWt/xKVPbo/EOHQah6/PQnwjFfXecQD+xHLgat+JBSLn+poF57xWdsYjdmaMqI1YfjU7xOIgQL+sklB1t3kGtcPaEE07NoKZnOW5ac3ml8vMH9ZZuYpMIPB8wxrYWVAfvwoy1oi7AoQsho/ZO6X3SxKTFyIXviy62QHGC+cYrI5y3b+20HxMb4+onw+vjDUiL436A! Cookie2: $Version=1 Connection: Keep-Alive sA 66 l"ZE(H@1 e  uP4P7zP -sA\ <<"Z lE(@@b  eP u7z4PP+=!TsA}G 66 l"ZE(M@1 e  vP4 7PsA(I <<"Z lE(@@o  eP v74 P=!TsA'<<"Z]oE(@0 eP o:4 QP"8"OsAr{<<"Z]oE(@0 eP o:4$P-bsAЋHH"Z]oE:@0 eP o:4$P-HTTP/1.0 302 MOVEDsA"Z]oE]0" eA7PWDtenR0LJF3ZgyTDqaZn4YzYSs0w0ggqHL9E4m7laya3mvftXhELuOvWhXX0+TivBpJwFb53rfvUo2S9tZYVs8X/udIPPZGed7hYAJL5n/k5U2h5qdU6CBU+rBAMZvhaG4tHURShhTojQdJfow5aPzfcCeKw5sbHrdC1p9WZxAj1TmK4JLswBX3tdeqUS/10seEPPSy1bbraFRE0EPKgxFeWd1/VYVHeOsMpd+Ra6QaWgcbBC7ao09NjIldaZs5JHDF5N71PDE8NbyT+05gvLU0nEh4LGU6UKN/piRPTnujzl8prroC8S6hgwl3VvKk+cjtvg+fBNEDC4ZlCAQm57LERBrdp8po/Tck8Ao2fi2jBYCpyjQW+ufSzOSiANZlS4vVJIvYJGwuLR5upaLYQTAhLOHeHvXuauYhq5AIdQbW3H0eFj+W34jrfsFbvtC7ImIt8kwHYz66F05jXpy8PprfcUyAUG2aprFdM9pDmytB5J7kw29Q3nNNj7btSICrpxReSpAXTBV4DoQo1yevZjpI0I3YIRWLUgXXKf7k2hG9/S6zrZn0aExD0ha0RdejBPm15kl0pn1Kpx8Ru+XZHxEuzn8JNGpqpCVR/X+lRRmwtbI4wA89gLlRB1JXhKrybwgERY6f/7yfaYYp4Ja0Cgwkt68GMeDZzGECOtW0b4dQRoz8d4nr2d4TnLhfkZGJ+uay6+gnb291r1A25dFL0nYyvIXVaxsA66]o"ZE(N@j4 e oP4$֊:P:<sAX"Z]oE@0 eP o:4$P-Mz0GgEWJFIIr7NwU3LPvf1bk922UmzL2PT3Hei1q7X9n2scTDAagfc0nb+8LrrFHN4OeDX1FBzUcLObbSwtL/jOc1Z9mSu7ADKOEt4TqIUTZL42IgNfIIMecN4UzWK/Q2KYYhj3vxxFIrQ9RbhJ9MS7FnuksZHbXHLqsPve785+7i3vCrr9Av2/mMU+l97zFI8nZyS5PsqaHvNLqyia/Lajt3zmuQXm9FN2lzTDL48/e2hJEOcDvu6i+ApBsG4nEM09xj9rAkXKbp1Wi9UkbdNYUBNcTDRoegoTGvly0erhMQcRHM6so+9h8bCP5wLvE2jbQxnJBRfOfszsFVs7qxj7dsD9/pz9YVk17NWzLapcmCWw7l0VrTwl4Ko1eBftOrYJ3OUizghkHR65tpXo7Yh/EFyyRmXRXPzzRVBbpZBLngkLhaNXRudp/QD+XFpVuQgG5lJTDLKyaNP0ZyQjJMwlYOVWhD7ffsjwKFwQv2U1TDSntdZohD/14xM!; domain=.advertising.com; path=/; expires=Wednesday, 18-Nov-2009 22:17:31 GMT Set-Cookie: ROLL=7QTn5TwthIayCNcTMp4Qx1VqIifJqoMapLjSpr4x0Lgh8QUVwN0zRTcNa9ypgStEft+axknn5XsYMIVuwoNjA/yaja6rBmF4CQoEhC28sSl3I9axXXyK2NCA7FOFIQOlRREcRxk6mP9ALn675W5PKpxQ9KR7Tf8C4dlWo9t7qs527NWDccOwN8rZt9DGEBsB6hzyuzJllRB9evLpxCkiQ1dTJPitazRA50EYxOSJZtd4zxH7d1d3OT1Vcx+qC9+/CaB3MQu+K/nuTwpHOFQ3H5Ul9peIlbO!; domain=.advertising.com; path=/; expires=Wednesday, 18-Nov-2009 22:17:31 GMT Location: http://opera1-servedby.advertising.com/site=0000127709/mnum=0000162763/genr=1/logs=0/mdtm=1077726643/bins=1 Content-Length: 134 This document has moved to http://opera1-servedby.advertising.com/site=0000127709/mnum=0000162763/genr=1/logs=0/mdtm=1077726643/bins=1sA)Y66]o"ZE(O@j3 e oP4$֊:P :;sA _66]o"ZE(P@j2 e oP4$֊:P ::sAUc>>]o"ZE0Q@j) e wP4'p<sA<<"Z]oE(y@0 eP pF4P"8sASj<<"Z]oE(y@0 eP pF4=P-sAHH"Z]oE:y@0 eP pF4=P-ԒHTTP/1.0 302 MOVEDsA"Z]oEy]00 ekf3SEOVTgdY9/8u4rI+EgtXApntWoNuyd9u5yZOme/6Z4pXChCsOidcbFNh5NXYnNX2T/M/EXweXfAQwtI56pnfpG0FkYNdXl6iazAOVyDWvVVDavmj4+Hz1uzu/Vwa1AJOuSP6NSCC7nL/ZxT1Cer57QI7GdDQFsr1cjq90nBiuj5xuErfnHOUDBGsOyzQRPOKYNVDD/1KvpbV6du0vmj41LOspU2y5lic8Npu0EPkHMaqhUgFPUp/ZK9Ld/vGET9OG9FER4H9OWCNrVICxbRz3vTbCODW5QBNHueRp5DprIXurB8fzkd8BzTuYAD0Z/wsSw91jgCuK7sWPIvd81AhO3ifMkNB/O7trr+hNMD/5oYZiWTvD+BfFNIjQzgrOI9U0myc73vNKsEr/fez90SyOdmmBBMSc3wvMFEWSMxxuid0b3AM0r6Xjj/CltEdD9UNkPQmxexV2WZvEeLC0Ix6rhiDHUJRmcBc+tHuiJ63VxwZf+D8R+4HlZROv3A1+Egq9BMGDwtocv2tzSj9XAbNk/Vln9bIipJaEroXWp0bJPuSXTNpx3QdF1kq8b0ZCvRupMfbxLu6+e/ngeiJRheKguJxXar6GP5VCsVez0wvavAAsc93qOZkHs9XFxCOilJ2D5+SXs4oGJplC8V8eWZ+rAk7P7w2KF5DD6WNCNCk8Hg0J46RrKWR+koRcoPpFJaVkm2ltuxOUG5wjXONu45RvAjpHczTFsA66]o"ZE(R@j0 e pP4= PsAGS"Z]oEy@0 eP p 4=P-h5ZPAs/eU9GaZQmrwFbfUIau5711n9HzNHNh5WfqMjGHCxC0Q6+Lkh7MLRGCmMIdO2MO5hn/Y5/oWqgIbRQWDDqPUofY3sVsjR6VqHlcZ7XDPqqN9u71tutiCh6oKRajfWHSLfGosSWvDX/omzxRN0XZ3f8qRzpvlfLF/x/TmvwBYVf2Rtb+x2u4KUwRzsgg4RrBpadQnfg43R7eBO3azlHX64+tdcEqFJaMcl3MgrJBErqQpNfUuiq4mS6AfriEFk/YFr/fz3cPOSqvOmFsQPwkKZJ/O0zlh5sUxNp2/zRfOIY1pkBtYUh3rMgnoP4cUtHb1vLdtDXx9tdL2pX+kKX15K5V7cYF1YRgVI9J/YFxfQcry9yBJue7s9hJaxISsfPjOr1Sflt/o0EpIzOx89S0ho68RVj6VPtHWMtm2kZiU8aUPx0nzTBgXJ5WrXMp+2qaPr+lv0AJSFbmjubXe4IhK55AttSQUvW6FGD6k1CNyMcTKxrYP62lvD!; domain=.advertising.com; path=/; expires=Wednesday, 18-Nov-2009 22:17:31 GMT Set-Cookie: ROLL=2Mtm4L9DYEwtNoJM2s62b+p57DnLepvaY0VHJi2+rK0RsSruyat2pS8uzWvKR/bQrwJY0sG+V4DkkQHkQEknH6bgwafsOECCySdLJJ9GNx0a2OI/kl1nBjhsbJLtvK53475BduhhhRSQMsglMGCyd/04Ru3d2+voKdloOJGUYbXkBrujzgY+xXEWeG2ErmRdK00ZSsNbtKlb6no3fMIhXaZZoIy8vsOE22X9n9ktD+f/XCDIPjjsUS8kmrXWHTN8PlPnn4lBQoK+CVFle6uPx3Pr2UK2GSL!; domain=.advertising.com; path=/; expires=Wednesday, 18-Nov-2009 22:17:31 GMT Location: http://opera2-servedby.advertising.com/site=0000127709/mnum=0000162763/genr=1/logs=0/mdtm=1077726643/bins=1 Content-Length: 134 This document has moved to http://opera2-servedby.advertising.com/site=0000127709/mnum=0000162763/genr=1/logs=0/mdtm=1077726643/bins=1sAS66]o"ZE(S@j/ e pP4=$P sAY66]o"ZE(T@j. e pP4=$P sA^>>]o"ZE0U@j% e xP4NpsA6<<"Z]oE(@0\ eP qW4sP"8zLsA U<<"Z]oE(@0\ eP qW4x7P-j_sA <<"Z]oE(;@0G eP s>4|P"8(sA] <<"Z]oE(<@0F eP s>46P-sAq HH"Z]oE:=@03 eP s>46P-&HTTP/1.0 302 MOVEDsA "Z]oE>]0  eyEh650jMYSHKnbZd1df1OD2sbNQ9voud+tboCPl0gvetPVo+wWkRgZ6MI0TvT1Zx0+84y5+Npt58Wz08sE5ppJ0XerkvxjlXubjpvzJMhCpkv0RsaIUTL+iIR4iz26F2BU2dEyrxO10uQPj3Z8ojbE/wu0JYMdDIxbIm8vuHKNv2jo1Q5WiM/nR8rk6EMhpySmNyRXJe7U5R0auBM1P5gHwEE1uU5z31j4ElMhBZeubee4g2hY3MqGoyB3rLewXi6FkpE3l8uOu8ZG9Sg1hM+kYE9qoMpPWGTUqNR32My2selJ1nKqqmqdBZU3Ldu7CZ31WX+Sc9h9jbHkqFrugmnL/0aVR5GzrIUsl7byES8j2ssJVB0uud3Aqov0lSbnmtAXgTUqTb3gkUqKlAbNeMQz5uzrsaPmL+NYIw3bMQpIPPK8bsJrvQkRGWqJPAgqR8vJXEShrQ4WVDTei91XTqDp3yAkrh/I7oyuvI7XazszemxwUsnkeueFkt3ha7RIZNacOPBLiy7rrpRZnP4Ar8iHS0kcZ/+GgG1Y2qcTakd9MYXIjYaYZzvbK0EuCIrVBDnTjtW4YzuJ8qZI0QN5AMQ52++1jvFcOW8ui2nBhNaTKJ5zwDOHtEjw84qLjPL7ZhjGDP4RkModeNpB970Oq/T4Aq/Ic1CX0v4QIRefqJ4P1/k3e1+4wpaPtRfKlsYiXlgJktmNberbBphtYiNw0zERtH6tXixS60sA 66]o"ZE(Z@j( e sP46D`P@msA= "Z]oE?@0d eP sD`46P-s/ib8VHoSzwlFSYpsydx+Y60R9G23UbjcsMHp6yB5yhuZIEepZo51obKdtCpbD+SQ72GVZTlHDOpiZDILM8Ar378bAVmQm2i1IpBUhWerDHJ/rMCua8rwKE2Tlh6srTH5LHUUG5J45uCpAlMbY1o6Qcy4meLvbZiDKHsS9jwBd2O2SnCcj6dliGG/IZZSDhMfNa2rLHJj7Fzhn7TP50NItB9MpYaWL4jgL5qDaLCqyp50k1GfpSC83rE6x+p17CDWYPOAIcVqr4mPKfhon2D9kd8mUYQKQYreM9OVEYtYdSc8/3wxxGk1NPIDVwWQ6lJR6Qi9Kn7vR+Q62pvzXvzxmz44CM6cbNfxs9GU0f+OYkWoRmTOPyvNDcgUiJRiXHXdP+RWmlcMBcaR+NbX0zJfQWYXD00q59lsVjJxbJfG9TxkIqfke4LcxMD8EMml1yX7VPeCcn9S2O43DM1IMCBndn4Zy7yJXcjnFJQuAKc7ueondn/t+uphLsuGI!; domain=.advertising.com; path=/; expires=Wednesday, 18-Nov-2009 22:17:32 GMT Set-Cookie: ROLL=hfmEvrLrNLWZ9roJpS97rB9/cbCMC/dp0Z81LwhPEe+EadQAjCusoMpqiKyodr7OSqWq5MdUCL4axcU2IecIJn9HmXniihH8uDJ+lzTOLIdjnxveBaNAyUpihsWiIsZDToBvog9hXvOfbf2m2TYWNifFAiS5u73hU3/7OsPm58SoYNBl7/D+u+ECQKeC9x51C5FEnyisQuKS3emD0ru7gjRC6IQATCwKiVmoqQT3tdLIkhiiNiIEHKZkqMBA1BlG/bJrPO4Fkuiv3PjU8/zd/b2VIwI304E!; domain=.advertising.com; path=/; expires=Wednesday, 18-Nov-2009 22:17:32 GMT Location: http://opera4-servedby.advertising.com/site=0000127709/mnum=0000162766/genr=1/logs=0/mdtm=1077726645/bins=1 Content-Length: 134 This document has moved to http://opera4-servedby.advertising.com/site=0000127709/mnum=0000162766/genr=1/logs=0/mdtm=1077726645/bins=1sAU= 66]o"ZE([@j' e sP46I@P @lsAO@ <<"Z]oE(@0m eP o:4$P-sAB 66]o"ZE(\@j& e sP46I@P @ksAE >>"Z]oE0@0m{ eP w>4'pЂsAF 66]o"ZE(]@j% e wP4'?PBsA6H >>]o"ZE0^@j e yP4psAI ]o"ZEܳ_@do e wP4'?P%GET /site=0000127709/mnum=0000162763/genr=1/logs=0/mdtm=1077726643/bins=1 HTTP/1.1 User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.11 [en] Host: opera1-servedby.advertising.com Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,video/x-mng,image/png,image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1 Accept-Language: en Accept-Charset: windows-1252, utf-8, utf-16, iso-8859-1;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Cookie: opera1=_419e70fb,,126885^76592&127709^162763_; ACID=ee440010568883680002!; BASE=rf4aU+eDk32GTgLuc8W+tMhzq1tXbKxA6oKsIQ7zqEA+AJK+7j8eB3ZtoKfuCdvsmWlhCSxRwPzdKu3MZXo9bhj9eSUH0qj+g+FE+hayL/03z91hDnqqFujTtNrqVWwu5+qiS0V5uri8jsn8agTqKMzf09Wwyl1fuj1yzgfS0V0s/4DJyqhcBYMpI8th/i1KCMO5oUOBJQ2LqAhfZb0dM4OtpDzXXJlXoctfPl1zWyp6Ri0RG4pdD9eqBt3fVxflQ4oIkqvrFtiwIxYx5I1EqVWo8c0QSQVkkwMjQNs3D39s2WMTc1FaE6VUYTKBglwVpLWMGD0O9vKy66SUPNEbpaZttDJIzQIJ1w8SwNDIPYPCYKAsyWcYIGG5+mqwMPBamvePJcbVb4O6TnL9gG6sc0A7PWDtenR0LJF3ZgyTDqaZn4YzYSs0w0ggqHL9E4m7laya3mvftXhELuOvWhXX0+TivBpJwFb53rfvUo2S9tZYVs8X/udIPPZGed7hYAJL5n/k5U2h5qdU6CBU+rBAMZvhaG4tHURShhTojQdJfow5aPzfcCeKw5sbHrdC1p9WZxAj1TmK4JLswBX3tdeqUS/10seEPPSy1bbraFRE0EPKgxFeWd1/VYVHeOsMpd+Ra6QaWgcbBC7ao09NjIldaZs5JHDF5N71PDE8NbyT+05gvLU0nEh4LGU6UKN/piRPTnujzl8prroC8S6hgwl3VvKk+cjtvg+fBNEDC4ZlCAQm57LERBrdp8po/Tck8Ao2fi2jBYCpyjQW+ufSzOSiANZlS4vVJIvYJGwuLR5upaLYQTAhLOHeHvXuauYhq5AsAI ]o"ZE`@ee e wP4-L?PIdQbW3H0eFj+W34jrfsFbvtC7ImIt8kwHYz66F05jXpy8PprfcUyAUG2aprFdM9pDmytB5J7kw29Q3nNNj7btSICrpxReSpAXTBV4DoQo1yevZjpI0I3YIRWLUgXXKf7k2hG9/S6zrZn0aExD0ha0RdejBPm15kl0pn1Kpx8Ru+XZHxEuzn8JNGpqpCVR/X+lRRmwtbI4wA89gLlRB1JXhKrybwgERY6f/7yfaYYp4Ja0Cgwkt68GMeDZzGECOtW0b4dQRoz8d4nr2d4TnLhfkZGJ+uay6+gnb291r1A25dFL0nYyvIXVaxz0GgEWJFIIr7NwU3LPvf1bk922UmzL2PT3Hei1q7X9n2scTDAagfc0nb+8LrrFHN4OeDX1FBzUcLObbSwtL/jOc1Z9mSu7ADKOEt4TqIUTZL42IgNfIIMecN4UzWK/Q2KYYhj3vxxFIrQ9RbhJ9MS7FnuksZHbXHLqsPve785+7i3vCrr9Av2/mMU+l97zFI8nZyS5PsqaHvNLqyia/Lajt3zmuQXm9FN2lzTDL48/e2hJEOcDvu6i+ApBsG4nEM09xj9rAkXKbp1Wi9UkbdNYUBNcTDRoegoTGvly0erhMQcRHM6so+9h8bCP5wLvE2jbQxnJBRfOfszsFVs7qxj7dsD9/pz9YVk17NWzLapcmCWw7l0VrTwl4Ko1eBftOrYJ3OUizghkHR65tpXo7Yh/EFyyRmXRXPzzRVBbpZBLngkLhaNXRudp/QD+XFpVuQgG5lJTDLKyaNP0ZyQjJMwlYOVWhD7ffsjwKFwQv2U1TDSntdZohD/14xM!; ROLL=7QTn5TwthIayCNcTMp4Qx1VqIifJqoMapLjSpr4x0Lgh8QUVwN0zRTcNa9ypgStEft+axknn5XsYMIVuwoNjA/yaja6rBmF4CQoEhC28sSl3I9axXXyK2NCA7FOFIQOlRREcRxk6mP9ALn675W5PKpxQ9KR7Tf8C4dlWo9t7qs527NWDccOwN8rZt9DGEBsB6hzyuzJllRB9evLpxCkiQ1dTJPitazRA50EYxOSJZtd4zxH7d1d3OT1Vcx+qC9+/CaB3MQu+K/nuTwpHOFQ3H5Ul9peIlbO! Cookie2: $Version=1 Connection: Keep-Alive, TE TE: deflate, gzip, chunked, identity, trailers sAN <<"Z]oE(@0m eP p$4>P-XsAV >>"Z]oE0@0m{ eP x6O4OprsA%V 66]o"ZE(a@j! e xP4O6PP=sAW ]o"ZEܳb@dl e xP4O6PPOGET /site=0000127709/mnum=0000162763/genr=1/logs=0/mdtm=1077726643/bins=1 HTTP/1.1 User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.11 [en] Host: opera2-servedby.advertising.com Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,video/x-mng,image/png,image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1 Accept-Language: en Accept-Charset: windows-1252, utf-8, utf-16, iso-8859-1;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Cookie: opera2=_419e70fb,,126885^76592&127709^162763_; ACID=ee440010568883680002!; BASE=3QYHXfsNvCFBeLNZ206GJi0j25HWC503TNR4QZW9L+6yd7SDOZsCODkwrUPvF7pLinQW+Y4YpDi5YPXp3N5+/p/sZu9hgUI7z0a7h8r6Oes1R+mMCN4bjFM5MOO4k2/yUHOI5yef5lOUKTgk4VgtzkBHQSQB9kDqCJJ3jQQb21A6fXOCivfNF6vM83kqmm08kM50QUUnDKahIBmM3Rx45ku9NsghF9aN+g4WxQ2UoD4ZWFSEoZ88zDPAUFQ34A8th8LM8F4bW12uOTE5tYLN9ysGCh/7G8eYmPpBUWOk/tvufZu2GZJl8pDoPrCeguTNZv4GwOAYfeSRHikoCHwrfPvDTktVlmC++l9KY1h7fsPeqxRkv/TK+SC45kIyTrbpMKK0lzdzDLPuyv4PHchjRakf3SEOVTgdY9/8u4rI+EgtXApntWoNuyd9u5yZOme/6Z4pXChCsOidcbFNh5NXYnNX2T/M/EXweXfAQwtI56pnfpG0FkYNdXl6iazAOVyDWvVVDavmj4+Hz1uzu/Vwa1AJOuSP6NSCC7nL/ZxT1Cer57QI7GdDQFsr1cjq90nBiuj5xuErfnHOUDBGsOyzQRPOKYNVDD/1KvpbV6du0vmj41LOspU2y5lic8Npu0EPkHMaqhUgFPUp/ZK9Ld/vGET9OG9FER4H9OWCNrVICxbRz3vTbCODW5QBNHueRp5DprIXurB8fzkd8BzTuYAD0Z/wsSw91jgCuK7sWPIvd81AhO3ifMkNB/O7trr+hNMD/5oYZiWTvD+BfFNIjQzgrOI9U0myc73vNKsEr/fez90SyOdmmBBMSc3wvMFEWSMsAW ]o"ZEc@eb e xP46PPxxuid0b3AM0r6Xjj/CltEdD9UNkPQmxexV2WZvEeLC0Ix6rhiDHUJRmcBc+tHuiJ63VxwZf+D8R+4HlZROv3A1+Egq9BMGDwtocv2tzSj9XAbNk/Vln9bIipJaEroXWp0bJPuSXTNpx3QdF1kq8b0ZCvRupMfbxLu6+e/ngeiJRheKguJxXar6GP5VCsVez0wvavAAsc93qOZkHs9XFxCOilJ2D5+SXs4oGJplC8V8eWZ+rAk7P7w2KF5DD6WNCNCk8Hg0J46RrKWR+koRcoPpFJaVkm2ltuxOUG5wjXONu45RvAjpHczTF5ZPAs/eU9GaZQmrwFbfUIau5711n9HzNHNh5WfqMjGHCxC0Q6+Lkh7MLRGCmMIdO2MO5hn/Y5/oWqgIbRQWDDqPUofY3sVsjR6VqHlcZ7XDPqqN9u71tutiCh6oKRajfWHSLfGosSWvDX/omzxRN0XZ3f8qRzpvlfLF/x/TmvwBYVf2Rtb+x2u4KUwRzsgg4RrBpadQnfg43R7eBO3azlHX64+tdcEqFJaMcl3MgrJBErqQpNfUuiq4mS6AfriEFk/YFr/fz3cPOSqvOmFsQPwkKZJ/O0zlh5sUxNp2/zRfOIY1pkBtYUh3rMgnoP4cUtHb1vLdtDXx9tdL2pX+kKX15K5V7cYF1YRgVI9J/YFxfQcry9yBJue7s9hJaxISsfPjOr1Sflt/o0EpIzOx89S0ho68RVj6VPtHWMtm2kZiU8aUPx0nzTBgXJ5WrXMp+2qaPr+lv0AJSFbmjubXe4IhK55AttSQUvW6FGD6k1CNyMcTKxrYP62lvD!; ROLL=2Mtm4L9DYEwtNoJM2s62b+p57DnLepvaY0VHJi2+rK0RsSruyat2pS8uzWvKR/bQrwJY0sG+V4DkkQHkQEknH6bgwafsOECCySdLJJ9GNx0a2OI/kl1nBjhsbJLtvK53475BduhhhRSQMsglMGCyd/04Ru3d2+voKdloOJGUYbXkBrujzgY+xXEWeG2ErmRdK00ZSsNbtKlb6no3fMIhXaZZoIy8vsOE22X9n9ktD+f/XCDIPjjsUS8kmrXWHTN8PlPnn4lBQoK+CVFle6uPx3Pr2UK2GSL! Cookie2: $Version=1 Connection: Keep-Alive, TE TE: deflate, gzip, chunked, identity, trailers sA HH"Z]oE:@0\ eP qW4x7P-jHTTP/1.0 302 MOVEDsAP"Z]oE]0 eMa1Zrm4o2iB0PJOTF+XKRwXT/eywSuKtL2y9PPY3iBevLphMDc/X1rbn44ucFZqTzctzUQbqGEyq9q3VK6KC6NEyh2cbf22JL8a00adQ34KFcI3vBBKDakP24ien5ttBldHXaV7Ch089HkzX4rWPV2dfUSqmB6lrmh7x+SYCvg76JMTj9xhneOkTfgnra+Hmz4mLLeuRMCb6lqvUMIslG0XIUvbknixvyo+dPpWYHkPNxbyhhi5wm8FQPC/qt8PR9ZkpsjvRWR7pTiDhcYGf0qjCrWMGgnEn8uFtHgYEx9gahyFx0y1anVqv0KREvp+CH+D3NxbOH5Y4eani7oLzwFAFJHdEERdRdchjQKIUYCtBSf8pgH325P31vAjy/TYriQpF6RYe3Cy++irjjryfEAtqHozeyzKyzvS9tEKOO8ScH7PJqHgJTwjA0t/sgawjDrSTeUN4mrYQTd8Vk4BiSrzDmVEL56jcO2aIwFsdsUnQqyCNrk35+Lp/G/dhVvTor2ZJ8R5bXgcpi9oX4YPWUjNYRtEb1cy41MF6KOMogyBXZB2+hP1RVJbJkKeEqQ1mzjnC6ZzMWHZjrMCB2L1uHWtNqYPkFh6BuBEH3j8fbskjHzSi1JMKH3QZunktSC/2M+gOEL0iSvXo6a3I0AxA+B6UumM/ogVc7B0esHMLbN2Klgpr3uqwvTprXoUqJJVd+Bo84NksN6Sv8KkR58g96yRRb4BLRDsIsAP66]o"ZE(h@j e qP4x7P9sA"Z]oE@0X eP q4x7P-VLlEIDSCxb30Dz/xMabFd08YGSkAo5v5PhCXzdb/DqlwJsQcX6xLedJ/myhRYo9ALIwO6bJzHJ9Ep3B2fT3UR6+1DxVcB+BAXYkfzF/+J8nM74yKY3zzp9xydIDDghah+NWJb2/sHLkr7K2J3xT0wHNJAUbrCrPeRzy2WUR7S+E/MH/50rQUo0pFjNX4qWxCqi5sOUWw1zjZCn940anLczwr8KGwgl4vw7x6TE6xv/hUCag/4HsNwK+QS+u/MKpciTmDEPBhMNuI35zrh73Ehy+9kAWRActBomf5bJ2VNzlZT9DeLIFYjEO3COYO265sZXzuauBeGuRii2kRmee2iMc7fyuLy/swPJb6kVOEEEET4R1bVfdmWQHMZhl22ErsnDd6kBolhQddXXXZoUeCB3/geBeKEeGKXmKibWcwewyjX9B8PiK/5EnHsAw1oYVioAMLdoXDAQO8gQmh7qofMuvBieAyx7a/6u5AF0JB64hkI3OSyQL64G71bD!; domain=.advertising.com; path=/; expires=Wednesday, 18-Nov-2009 22:17:32 GMT Set-Cookie: ROLL=2SflxnACP87TN5KYCWCJd5KAbjFR8F5iksg98EMHA3mxU1pKASxLy1sFfb9YIKFmjn+R07cyySmvhyeXEkU1UQ9ChGKdtqDJ3JSm/vlSsibTWLVdmZnz7ubajzop9ybjN1irbCzIlRgH896qZteR+PTt4l4fH118UXee5KrZ21j7xRQpiLcW7c6xi3rVIDhpAtepPlSi76aEZGjTNc0nfz2+mEF238ov2fCEAyZR3WA7fYPx6yKntE/+xoWhl5Olf4iSbRynLTqeD58bgRvTYQfeIFjMgJH!; domain=.advertising.com; path=/; expires=Wednesday, 18-Nov-2009 22:17:32 GMT Location: http://opera3-servedby.advertising.com/site=0000127709/mnum=0000162763/genr=1/logs=0/mdtm=1077726643/bins=1 Content-Length: 134 This document has moved to http://opera3-servedby.advertising.com/site=0000127709/mnum=0000162763/genr=1/logs=0/mdtm=1077726643/bins=1sA566]o"ZE(i@j e qP4x7P 8sAԲ66]o"ZE(j@j e qP4x7P 7sA7>>]o"ZE0k@j e zP4KpzsAi$<<"Z]oE(@0m eP sI@47P- sAI>>"Z]oE0@0m{ eP yM4psA66]o"ZE(l@j e yP4NPRsAo]o"ZEܳm@da e yP4NP:GET /site=0000127709/mnum=0000162766/genr=1/logs=0/mdtm=1077726645/bins=1 HTTP/1.1 User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.11 [en] Host: opera4-servedby.advertising.com Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,video/x-mng,image/png,image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1 Accept-Language: en Accept-Charset: windows-1252, utf-8, utf-16, iso-8859-1;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Cookie: opera4=_419e70fc,,126885^76592&127709^162766_; ACID=ee440010568883680002!; BASE=EW1XvbJwCMhkztjPmjKG+pQ3/bXppXenUXuVsKuQHxX4n5IH+IBFPwSJZG36Av7k4ixoB9HR9D7AJ4w6b2xaG7AOfFzpK0Y6qsRoUesyxpnRXdCTYjGi0cEXbj+bb9tCYJgVu4KT8Tj+Ob36XjduF5e1fTNmU9rfNr8eCrYzhOx3k0EjpcYj+04nmwEqC4N/0dB6DsFWMZbcIPcFvxYZAoqn4Lg3dJTi6np4nsThwDyDaWWB9zTAHHDRyWemXEjswLmLbXZuq7S1y6wfci2/Wi0hlJsAsot62I+ggzJWZn7CQaw/XwNMBc1Ic/PfR2K6EIQHYdJQhYpR/n+NfDQWqva2Q59/sPKsSnerHy19Fdv7kyk61eQkJuPua770yEHgbdi6q7gbTgxWIu5EusthYlyEh650jMYSHKnbZd1df1OD2sbNQ9voud+tboCPl0gvetPVo+wWkRgZ6MI0TvT1Zx0+84y5+Npt58Wz08sE5ppJ0XerkvxjlXubjpvzJMhCpkv0RsaIUTL+iIR4iz26F2BU2dEyrxO10uQPj3Z8ojbE/wu0JYMdDIxbIm8vuHKNv2jo1Q5WiM/nR8rk6EMhpySmNyRXJe7U5R0auBM1P5gHwEE1uU5z31j4ElMhBZeubee4g2hY3MqGoyB3rLewXi6FkpE3l8uOu8ZG9Sg1hM+kYE9qoMpPWGTUqNR32My2selJ1nKqqmqdBZU3Ldu7CZ31WX+Sc9h9jbHkqFrugmnL/0aVR5GzrIUsl7byES8j2ssJVB0uud3Aqov0lSbnmtAXgTUqTb3gkUqKlAbNeMQz5uzrsaPmL+NYIw3bMQpsA]o"ZEn@eW e yP47NPTIPPK8bsJrvQkRGWqJPAgqR8vJXEShrQ4WVDTei91XTqDp3yAkrh/I7oyuvI7XazszemxwUsnkeueFkt3ha7RIZNacOPBLiy7rrpRZnP4Ar8iHS0kcZ/+GgG1Y2qcTakd9MYXIjYaYZzvbK0EuCIrVBDnTjtW4YzuJ8qZI0QN5AMQ52++1jvFcOW8ui2nBhNaTKJ5zwDOHtEjw84qLjPL7ZhjGDP4RkModeNpB970Oq/T4Aq/Ic1CX0v4QIRefqJ4P1/k3e1+4wpaPtRfKlsYiXlgJktmNberbBphtYiNw0zERtH6tXixS60/ib8VHoSzwlFSYpsydx+Y60R9G23UbjcsMHp6yB5yhuZIEepZo51obKdtCpbD+SQ72GVZTlHDOpiZDILM8Ar378bAVmQm2i1IpBUhWerDHJ/rMCua8rwKE2Tlh6srTH5LHUUG5J45uCpAlMbY1o6Qcy4meLvbZiDKHsS9jwBd2O2SnCcj6dliGG/IZZSDhMfNa2rLHJj7Fzhn7TP50NItB9MpYaWL4jgL5qDaLCqyp50k1GfpSC83rE6x+p17CDWYPOAIcVqr4mPKfhon2D9kd8mUYQKQYreM9OVEYtYdSc8/3wxxGk1NPIDVwWQ6lJR6Qi9Kn7vR+Q62pvzXvzxmz44CM6cbNfxs9GU0f+OYkWoRmTOPyvNDcgUiJRiXHXdP+RWmlcMBcaR+NbX0zJfQWYXD00q59lsVjJxbJfG9TxkIqfke4LcxMD8EMml1yX7VPeCcn9S2O43DM1IMCBndn4Zy7yJXcjnFJQuAKc7ueondn/t+uphLsuGI!; ROLL=hfmEvrLrNLWZ9roJpS97rB9/cbCMC/dp0Z81LwhPEe+EadQAjCusoMpqiKyodr7OSqWq5MdUCL4axcU2IecIJn9HmXniihH8uDJ+lzTOLIdjnxveBaNAyUpihsWiIsZDToBvog9hXvOfbf2m2TYWNifFAiS5u73hU3/7OsPm58SoYNBl7/D+u+ECQKeC9x51C5FEnyisQuKS3emD0ru7gjRC6IQATCwKiVmoqQT3tdLIkhiiNiIEHKZkqMBA1BlG/bJrPO4Fkuiv3PjU8/zd/b2VIwI304E! Cookie2: $Version=1 Connection: Keep-Alive, TE TE: deflate, gzip, chunked, identity, trailers sA0<<"Z]oE(A@0+ eP w?4-LP"8VsA{<<"Z]oE(A@0+ eP w?42 P-1sAREEE"Z]oE7A@0+ eP w?42 P-bHTTP/1.0 200 OKsA,"Z]oEA]0h e! NETSCAPE2.0!,<9H*\ȰÇ#JHŋ3jȱG8Iɓ(S\ɲ˗0cʜI͛8sɳϟ>BH@ѣH*]ʴӧPJJիXjʵW~eT?h}i[iEVjݦq˷߿v6o١I{V\m/fCM4U-<0&08rk9ͽ'}4/%|xr27M593B·p{k%> l"ZE0t@0 e  {P4sp$sAP>>"Z lE0@@$a  eP {7;4spSsAP66 l"ZE(u@0 e  {P4s7 Ellies Dagbok [tillbaka till hemsidan]

    Familjen Sahlbergs Dagbok

    2004

    Arkiv

    2001
    2002
    2003
    sA ~<<"Z lE(z@@P  eP {74uqPƹ}sAR~66 l"ZE(w@0 e  {P4uq7PKsAL"Z]oE]0] e! NETSCAPE2.0!,<9H*\ȰÇ#JHŋ3jȱG8Iɓ(S\ɲ˗0cʜI͛8sɳϟ>BH@ѣH*]ʴӧPJJիXjʵW~eT?h}i[iEVjݦq˷߿v6o١I{V\m/fCM4U-<0&08rk9ͽ'}4/%|xr27M593B·p{k%>"Z]oE0@0m{ eP zCj:4Kp sAʤ66]o"ZE(y@j e zP4KCj;POsAC<<"Z]oE(D@0> eP yN47P"8*sAv]o"ZEܳz@dT e zP4KCj;PJZGET /site=0000127709/mnum=0000162763/genr=1/logs=0/mdtm=1077726643/bins=1 HTTP/1.1 User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.11 [en] Host: opera3-servedby.advertising.com Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,video/x-mng,image/png,image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1 Accept-Language: en Accept-Charset: windows-1252, utf-8, utf-16, iso-8859-1;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Cookie: opera3=_419e70fc,,126885^76592&127709^162763_; ACID=ee440010568883680002!; BASE=XgfauP+OyydIlr/9I6mjniAgObR+9rYYoRlmZpjmRzkAYblQWoOjXtWNOBAvOZ1ruXHePzkOIoZWjYBVpfD6nFqz9KO7PymOdBTouleNTdS+z5Yo4ofCrwQxRbUEI0EcEBLS2pDxpLP4t+NuVpJAraoUZ3nobZ5lyPLJHBKcPJxBPkiEN/ABNnV0NFgrjhdLGdjuJEZMqNqdx7NlVBR3yIefVWxODFNyDXdBbr6yE0e4nAlk8gUi5Psmjne3te0YPqADGlLD7aw3OBHLttEtR6MRzf5ElU1hmDU2eJ/KTGHu48bgSjNEyBDRtiCGJ6KIG8go3gXW3v7Mz+pz84LD80QaG527QMfbOh58Uf+qt0zhTKrmhpuOTGL3GTXIclQshTFOztkLxJQeE0Dfy4tnp7Ma1Zrm4o2iB0PJOTF+XKRwXT/eywSuKtL2y9PPY3iBevLphMDc/X1rbn44ucFZqTzctzUQbqGEyq9q3VK6KC6NEyh2cbf22JL8a00adQ34KFcI3vBBKDakP24ien5ttBldHXaV7Ch089HkzX4rWPV2dfUSqmB6lrmh7x+SYCvg76JMTj9xhneOkTfgnra+Hmz4mLLeuRMCb6lqvUMIslG0XIUvbknixvyo+dPpWYHkPNxbyhhi5wm8FQPC/qt8PR9ZkpsjvRWR7pTiDhcYGf0qjCrWMGgnEn8uFtHgYEx9gahyFx0y1anVqv0KREvp+CH+D3NxbOH5Y4eani7oLzwFAFJHdEERdRdchjQKIUYCtBSf8pgH325P31vAjy/TYriQpF6RYe3Cy++irjjryfEAtqHozeyzKyzvS9tEKOOsA]o"ZE{@eJ e zP4QCj;PO8ScH7PJqHgJTwjA0t/sgawjDrSTeUN4mrYQTd8Vk4BiSrzDmVEL56jcO2aIwFsdsUnQqyCNrk35+Lp/G/dhVvTor2ZJ8R5bXgcpi9oX4YPWUjNYRtEb1cy41MF6KOMogyBXZB2+hP1RVJbJkKeEqQ1mzjnC6ZzMWHZjrMCB2L1uHWtNqYPkFh6BuBEH3j8fbskjHzSi1JMKH3QZunktSC/2M+gOEL0iSvXo6a3I0AxA+B6UumM/ogVc7B0esHMLbN2Klgpr3uqwvTprXoUqJJVd+Bo84NksN6Sv8KkR58g96yRRb4BLRDsILlEIDSCxb30Dz/xMabFd08YGSkAo5v5PhCXzdb/DqlwJsQcX6xLedJ/myhRYo9ALIwO6bJzHJ9Ep3B2fT3UR6+1DxVcB+BAXYkfzF/+J8nM74yKY3zzp9xydIDDghah+NWJb2/sHLkr7K2J3xT0wHNJAUbrCrPeRzy2WUR7S+E/MH/50rQUo0pFjNX4qWxCqi5sOUWw1zjZCn940anLczwr8KGwgl4vw7x6TE6xv/hUCag/4HsNwK+QS+u/MKpciTmDEPBhMNuI35zrh73Ehy+9kAWRActBomf5bJ2VNzlZT9DeLIFYjEO3COYO265sZXzuauBeGuRii2kRmee2iMc7fyuLy/swPJb6kVOEEEET4R1bVfdmWQHMZhl22ErsnDd6kBolhQddXXXZoUeCB3/geBeKEeGKXmKibWcwewyjX9B8PiK/5EnHsAw1oYVioAMLdoXDAQO8gQmh7qofMuvBieAyx7a/6u5AF0JB64hkI3OSyQL64G71bD!; ROLL=2SflxnACP87TN5KYCWCJd5KAbjFR8F5iksg98EMHA3mxU1pKASxLy1sFfb9YIKFmjn+R07cyySmvhyeXEkU1UQ9ChGKdtqDJ3JSm/vlSsibTWLVdmZnz7ubajzop9ybjN1irbCzIlRgH896qZteR+PTt4l4fH118UXee5KrZ21j7xRQpiLcW7c6xi3rVIDhpAtepPlSi76aEZGjTNc0nfz2+mEF238ov2fCEAyZR3WA7fYPx6yKntE/+xoWhl5Olf4iSbRynLTqeD58bgRvTYQfeIFjMgJH! Cookie2: $Version=1 Connection: Keep-Alive, TE TE: deflate, gzip, chunked, identity, trailers sA <<"Z]oE(E@0= eP yN4P-sA§ EE"Z]oE7F@0- eP yN4P-dHTTP/1.0 200 OKsA 66 l"ZE(|@0 e  {P4uq7PKsAW <<"Z lE({@@P  eP {74urPHTTP/1sA "Z]oEG]0  e! NETSCAPE2.0!,<H*\ȰÇ#JHŋ3jȱǏ CIɓ(QX ˗0cʜIMPQIѣH*H *`AB#:ɒ`ÊK6,*KӪ]˶tl U+Ra5zJÅ(^r 6lFLi2g#{ɳ4 ܪ^:i9@,ڵ0 'Nȓ+W΢c$xEиB9 qVxF>ȁgϔ)G8>A ?~G_~ځD`Fx dЛB=p,̱ " :F0OǙf0zYqya19` %Q 萁19J&%DN.T%XB6( @@aFA vPg܈p)tm?5(0A}hf4R EFǽsA 66]o"ZE(}@j e yP4PBrsAL "Z]oEA]0h eL<c Lb }U:w:@ R IH#/bP3nIhvŝg`% n4 O $ j,9-^zEsEщHLb>(}AIM0I1PXB@#),kXf*jUWJNi` ZЁTteMMSgSCѡ̒|tƕMf#WR+k*v>ks }+c.Ԋp1 AZ P1$/%J )VD0搄\У'k[3Lep3WQ"nNUq1+Vmus]fWt: H8D& ŁyU&X`- pʶW.9ZBݵ["ݭr{m.F ܽ*6 '[ Cry0 N;_TN)pºƖ|者 _v>nC%9Ep$5XYTNqVY-r`SMlX;߰ЗzM [kY( t8/ze:^2e@oخc3Lirx&Vt-i_Е&Izg5Tc)'UKϚ.rϴ.Yҽ4w%hJڗ| +j8c#g#zsA "Z]oEA]0h ePE0"d@"0ը\PS8"Hޗd 'gVɧȏegoh~kxabXl")9IPk0#SЌ8h\k H7fdK\@d0FF8seW_a\fQnKvHl5vea̱aYl`(k8Q|Y+!*T ـВ#~lx (0v999؎ JdPxi_y놕R iaXaYؙFoɇ2Y,ك6 8|%񗁹i똘X4ИA7(pHiO8aܩy揺֐9I,y8E%Y@h90%A6y%9l;S@hrNxemLizbhHeFofiOyrV- amYovb&dUyvz  \/h$k8)$ʎY"Y#rSq‚Wzcz<1*J| xCxd0Nd>p(訰Kq*sJ;q\ړFDZ[(Z[ AiEQ1|j@ PzsA 66]o"ZE(~@j e wP42 *jPsAME "Z]oEA@0'e eP w*j42 P-rګjɓN 09z9rZMP2ڭ:[Ecɚʬ$Pj;_;[{+^ PtuӮ"[:{9P~ ";$[&{(+d@J;0Ԩ8:<۳>@;GSш4w6۴NK.R;zJɺ\۵^[Kˊd[f{hjl۶npr;t[v{xzv;[{۸;!, ( Čp!#JHŋ3jȱǏ CIɌagy戁!Ó8sɳϟ@ آK>}ӆ:mf`իXjʵ+GOuC,T7cx۷pʝWAbͺٻ,<FJÈ+f橞t9#F pϠCg 6zt( ۵gsͼ?y*'p[7m#Ëo7$Fb_ T˟O_'F)Ÿ g6P߁&hoGg߄[)@=8\KY8P u0Kg%[z\@)dF-FT8Ē'crx7TRKv$]]oUiZq9 pvg5& "܄|w}Gn`$3tIeyvt)}QńhjF*x*u̡ƫjQǠ |+bS*u+l>ۀ&[F[} f lt,jk:q+P GRM7* TZRAf,R+'QqQ *,Ħ1g<1x\ {wq("rQ2G.lsqH쳩 f?=| Gt4D?m(pPg]-UE-AC=@`x~v ߀.@@;sAE 66]o"ZE(@j e wP42 .PsAF 66]o"ZE(@j e wP42 .PsAp "Z]oE]0\ eL<c Lb }U:w:@ R IH#/bP3nIhvŝg`% n4 O $ j,9-^zEsEщHLb>(}AIM0I1PXB@#),kXf*jUWJNi` ZЁTteMMSgSCѡ̒|tƕMf#WR+k*v>ks }+c.Ԋp1 AZ P1$/%J )VD0搄\У'k[3Lep3WQ"nNUq1+Vmus]fWt: H8D& ŁyU&X`- pʶW.9ZBݵ["ݭr{m.F ܽ*6 '[ Cry0 N;_TN)pºƖ|者 _v>nC%9Ep$5XYTNqVY-r`SMlX;߰ЗzM [kY( t8/ze:^2e@oخc3Lirx&Vt-i_Е&Izg5Tc)'UKϚ.rϴ.Yҽ4w%hJڗ| +j8c#g#zsA "Z]oE]0[ ePE0"d@"0ը\PS8"Hޗd 'gVɧȏegoh~kxabXl")9IPk0#SЌ8h\k H7fdK\@d0FF8seW_a\fQnKvHl5vea̱aYl`(k8Q|Y+!*T ـВ#~lx (0v999؎ JdPxi_y놕R iaXaYؙFoɇ2Y,ك6 8|%񗁹i똘X4ИA7(pHiO8aܩy揺֐9I,y8E%Y@h90%A6y%9l;S@hrNxemLizbhHeFofiOyrV- amYovb&dUyvz  \/h$k8)$ʎY"Y#rSq‚Wzcz<1*J| xCxd0Nd>p(訰Kq*sJ;q\ړFDZ[(Z[ AiEQ1|j@ PzsAy 66]o"ZE(@j e xP46{PsA|r "Z]oE@0 eP x6{4P-mګjɓN 09z9rZMP2ڭ:[Ecɚʬ$Pj;_;[{+^ PtuӮ"[:{9P~ ";$[&{(+d@J;0Ԩ8:<۳>@;GSш4w6۴NK.R;zJɺ\۵^[Kˊd[f{hjl۶npr;t[v{xzv;[{۸;!, ( Čp!#JHŋ3jȱǏ CIɌagy戁!Ó8sɳϟ@ آK>}ӆ:mf`իXjʵ+GOuC,T7cx۷pʝWAbͺٻ,<FJÈ+f橞t9#F pϠCg 6zt( ۵gsͼ?y*'p[7m#Ëo7$Fb_ T˟O_'F)Ÿ g6P߁&hoGg߄[)@=8\KY8P u0Kg%[z\@)dF-FT8Ē'crx7TRKv$]]oUiZq9 pvg5& "܄|w}Gn`$3tIeyvt)}QńhjF*x*u̡ƫjQǠ |+bS*u+l>ۀ&[F[} f lt,jk:q+P GRM7* TZRAf,R+'QqQ *,Ħ1g<1x\ {wq("rQ2G.lsqH쳩 f?=| Gt4D?m(pPg]-UE-AC=@`x~v ߀.@@;sAr 66]o"ZE(@j e xP46PsAs 66]o"ZE(@i e xP46PsA <<"Z]oE(Le@0! eP zCj;4QP"8'sA9<<"Z]oE(Lf@0! eP zCj;4VQP-sAhEE"Z]oE7Lg@0!  eP zCj;4VQP-aHTTP/1.0 200 OKsAjq"Z]oELh]0] e! NETSCAPE2.0!,<9H*\ȰÇ#JHŋ3jȱG8Iɓ(S\ɲ˗0cʜI͛8sɳϟ>BH@ѣH*]ʴӧPJJիXjʵW~eT?h}i[iEVjݦq˷߿v6o١I{V\m/fCM4U-<0&08rk9ͽ'}4/%|xr27M593B·p{k%2X*[(̎E gBN dHHܔ9-NyK e0עQ[ PD}8F:H "Ѐ a+=@%xEݫ)Z΂\!:JQ*}G!K$'"e=\ tj 8KK+V MNYӺGTl^vF jBhX'.p]r =Hx]x§ ڹ&Dizh:\T$WR /AGyx%uЫ8N  ` dt{@h+a ;Y0K{X]P4̤AU׵.pEX8EN :`A2d*Qx[$";.PSJsAiWΠB @ g VPq:BOɸ+LE7-P)Gr֯13KժӢ4TVsAM"Z]oEI]0  eh匠KڈȌ؍ks8؍(HQGhY(|rG9p p>54c3B?JWo]j1<6vȉȸHiHx9yVcH*Yy"!7W ?.'4;3uufH Y]@p/ č)FH Am<4IbْL$ȕш105s,蕤sghXq|=l#!R33g.BoxJɋNXp  Iia6Y &֨&-ٙ9)Xؚyhu98ɗHȓ!3fØ?3K~`/`7ؙa 29(hya ٚ$Ɏ*yH湚ћ~YqGv"-YJb}pУo=pתQw{r,gG[gϾ=Kw'MϿC>g`}Ww˕EF(n1uW_j)C]F$h`6aķd0zhq=q(}AIM0I1PXB@#),kXf*jUWJNi` ZЁTteMMSgSCѡ̒|tƕMf#WR+k*v>ks }+c.Ԋp1 AZ P1$/%J )VD0搄\У'k[3Lep3WQ"nNUq1+Vmus]fWt: H8D& ŁyU&X`- pʶW.9ZBݵ["ݭr{m.F ܽ*6 '[ Cry0 N;_TN)pºƖ|者 _v>nC%9Ep$5XYTNqVY-r`SMlX;߰ЗzM [kY( t8/ze:^2e@oخc3Lirx&Vt-i_Е&Izg5Tc)'UKϚ.rϴ.Yҽ4w%hJڗ| +j8c#g#zsAK"Z]oELj]0] ePE0"d@"0ը\PS8"Hޗd 'gVɧȏegoh~kxabXl")9IPk0#SЌ8h\k H7fdK\@d0FF8seW_a\fQnKvHl5vea̱aYl`(k8Q|Y+!*T ـВ#~lx (0v999؎ JdPxi_y놕R iaXaYؙFoɇ2Y,ك6 8|%񗁹i똘X4ИA7(pHiO8aܩy揺֐9I,y8E%Y@h90%A6y%9l;S@hrNxemLizbhHeFofiOyrV- amYovb&dUyvz  \/h$k8)$ʎY"Y#rSq‚Wzcz<1*J| xCxd0Nd>p(訰Kq*sJ;q\ړFDZ[(Z[ AiEQ1|j@ PzsA66]o"ZE(@i e zP4VQC{fP4sA`"Z]oELk@0 eP zC{f4VQP-hګjɓN 09z9rZMP2ڭ:[Ecɚʬ$Pj;_;[{+^ PtuӮ"[:{9P~ ";$[&{(+d@J;0Ԩ8:<۳>@;GSш4w6۴NK.R;zJɺ\۵^[Kˊd[f{hjl۶npr;t[v{xzv;[{۸;!, ( Čp!#JHŋ3jȱǏ CIɌagy戁!Ó8sɳϟ@ آK>}ӆ:mf`իXjʵ+GOuC,T7cx۷pʝWAbͺٻ,<FJÈ+f橞t9#F pϠCg 6zt( ۵gsͼ?y*'p[7m#Ëo7$Fb_ T˟O_'F)Ÿ g6P߁&hoGg߄[)@=8\KY8P u0Kg%[z\@)dF-FT8Ē'crx7TRKv$]]oUiZq9 pvg5& "܄|w}Gn`$3tIeyvt)}QńhjF*x*u̡ƫjQǠ |+bS*u+l>ۀ&[F[} f lt,jk:q+P GRM7* TZRAf,R+'QqQ *,Ħ1g<1x\ {wq("rQ2G.lsqH쳩 f?=| Gt4D?m(pPg]-UE-AC=@`x~v ߀.@@;sA`66]o"ZE(@i e zP4VQCP4sA/b66]o"ZE(@i e zP4VQCP4sA"Z]oEK]0  eh2b܎.Y^ LINrHۂ.ߓmzKXl(=h=5@Kk0 d&bYtҠTb07|D&JQf^tbcNAyPR lP/9nL7C)%͝LS,`VoB"/r,9i@ Yݪ\QR&@a̓Rg:,uyC[?"X\9{ k*<jH,cGػvt+b5XW+ig[ .` X}mi[ pSjֵ(p1S̍.Qe+];sA66]o"ZE(@i e yP4RP'1sA}!66]o"ZE(@i e yP4RP'0sAPA <<"Z]oE(@0m eP zC4VRP-sA <<"Z]oE(@0m eP yR4P-sA>> l"ZE0@0 e  |P4TpsA>>"Z lE0@@$a  eP |7q54UpsA66 l"ZE(@0 e  |P4U7q6PsAm@ l"ZE@.h e  |P4U7q6PGET /Websidan/dagbok/2004/dagbok.html HTTP/1.1 User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.11 [en] Host: 10.1.1.1 Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,video/x-mng,image/png,image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1 Accept-Language: en Accept-Charset: windows-1252, utf-8, utf-16, iso-8859-1;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Referer: http://10.1.1.1/Websidan/dagbok/dagbok.html Connection: Keep-Alive, TE TE: deflate, gzip, chunked, identity, trailers sAIE<<"Z lE(?@@  eP |7q64PbsA{P"Z lE?@@  eP |7q64PbCHTTP/1.1 200 OK Date: Sat, 20 Nov 2004 10:21:11 GMT Server: Apache/2.0.40 (Red Hat Linux) Last-Modified: Wed, 14 Jul 2004 19:31:39 GMT ETag: "1fab4-4ef-a2927cc0" Accept-Ranges: bytes Content-Length: 1263 Connection: close Content-Type: text/html; charset=ISO-8859-1 Ellies Dagbok [tillbaka till index]

    Familjen Sahlbergs Dagbok

    2004 Vecka 6
    2004 Vecka 10
    2004 Vecka 11
    2004 Vecka 12
    2004 Vecka 13
    2004 Vecka 14
    2004 Vecka 15
    2004 Vecka 16
    2004 Vecka 17
    2004 Vecka 18
    2004 Vecka 19
    2004 Vecka 20
    2004 Vecka 21
    2004 Vecka 22
    2004 Vecka 23
    2004 Vecka 24
    2004 Vecka 25
    Vecka 26: 21 - 27 Juni
    Vecka 27: 28 Juni - 4 Juli
    Vecka 28: 5 Juli - 11 Juli

    sASQ66 l"ZE(@0 e  |P47w:P sAjQ<<"Z lE(?@@  eP |7w:4PbHTTP/1sAQ66 l"ZE(@0 e  |P47w;P sAq66 l"ZE(@0 e  |P47w;P sA&<<"Z lE(?@@  eP |7w;4PbHTTP/1sAiK >> l"ZE0@0 e  }P4jpLsA@M >>"Z lE0@@$a  eP }8j84kpđsAoM 66 l"ZE(@0 e  }P4k8j8P&sAgm  l"ZE@.N e  }P4k8j8PSGET /Websidan/dagbok/2004/28/dagbok.html HTTP/1.1 User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.11 [en] Host: 10.1.1.1 Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,video/x-mng,image/png,image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1 Accept-Language: en Accept-Charset: windows-1252, utf-8, utf-16, iso-8859-1;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Referer: http://10.1.1.1/Websidan/dagbok/2004/dagbok.html Connection: Keep-Alive, TE TE: deflate, gzip, chunked, identity, trailers sAGr <<"Z lE(j@@}  eP }8j84PsA} "Z lEj@@  eP }8j84PHTTP/1.1 200 OK Date: Sat, 20 Nov 2004 10:21:12 GMT Server: Apache/2.0.40 (Red Hat Linux) Last-Modified: Sun, 18 Jul 2004 18:57:10 GMT ETag: "75912-8b8-9e9d8d80" Accept-Ranges: bytes Content-Length: 2232 Connection: close Content-Type: text/html; charset=ISO-8859-1 Familjen Sahlbergs Dagbok: 2004 Vecka 28 [tillbaka till index]

    Dagbok: 2004 Vecka 28

    5 Juli - 11 Juli


    P onsdagen begav vi oss ivg uppt Queensland. Vi ska upp dit och trffa lite kompisar och det blev en lng resa med besk i HerveyBay, Brisbane och SeaWorld(SurfersParadise). Klicka p lnkarna fr att se mer bilder frn resan.

    I Hervey Bay som ligger ca 3,5 timme norr om Brisbane (ca 120 mil frn Kariong, dr vi bor) beskte vi en familj som tidigare bodde i kariong. Ellie var jttebra kompis med deras dotter Lily. Tjejerna hade jttekul och vi kte runt och sg oss omkring, barnen badade och det var varmt och sknt p beachen ven fast vattnet var lite kallt.

    P lrdagen begav vi oss ner till Redcliff som ligger ca 3 mil norr om Brisbane. Ronnies kompis Mats bor dr nu med fru och 2 barn. Det var kul att trffa dem igen, det var ju ca 2 r sedan sist.

    sAI OO"Z lEAj@@b  eP }8j>4P P sndagen trffade vi en annan svensk familj som vi lrde knna i Sydney. De bor nu nra Surfers Paradise, sder om Brisbane. Vi trffades p Seaworld och hade en underbar dag med delfinshow, en massa karuseller fr barnen etc. Ellinor och deras lsta dotter Lina lekte och hade kul nsta direkt.

    P sndag eftermiddag megav vi oss hemt och Ronnie var pigg och bestmde sig fr att kra hela vgen, s runt 01.00 kom vi hem och gissa om det var sknt att f sova i sin egen sng igen.

    Det var kul att trffa sina vnner som tyvrr bor lite lngt borta men vem vet, vi kanske tar vrt pick och pack och flyttar upp dit. Vintarna r ju vldigt trevliga dr...


    sA 66 l"ZE(@0 e  }P48jBPsA <<"Z lE(j@@z  eP }8jB4P/HTTP/1sAӁ 66 l"ZE(@0 e  }P48jBPsA >> l"ZE0@0 e  ~P4tpfsAd >>"Z lE0@@$a  eP ~74up/%sA 66 l"ZE(@0 e  ~P4u7PrsA >> l"ZE0@0 e  P4bWpsAմ >>"Z lE0@@$a  eP 8t4bXpgsA 66 l"ZE(@0 e  P4bX8tPsA l"ZE@.9 e  ~P4u7PNGET /Websidan/2004-07-SeaWorld/320/DSC07858.JPG HTTP/1.1 User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.11 [en] Host: 10.1.1.1 Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,video/x-mng,image/png,image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1 Accept-Language: en Accept-Charset: windows-1252, utf-8, utf-16, iso-8859-1;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Referer: http://10.1.1.1/Websidan/dagbok/2004/28/dagbok.html Connection: Keep-Alive, TE TE: deflate, gzip, chunked, identity, trailers sAW l"ZE@.8 e  P4bX8tPGET /Websidan/2004-07-SeaWorld/320/DSC07859.JPG HTTP/1.1 User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.11 [en] Host: 10.1.1.1 Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,video/x-mng,image/png,image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1 Accept-Language: en Accept-Charset: windows-1252, utf-8, utf-16, iso-8859-1;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Referer: http://10.1.1.1/Websidan/dagbok/2004/28/dagbok.html Connection: Keep-Alive, TE TE: deflate, gzip, chunked, identity, trailers sA66 l"ZE(@0 e  }P48jBPsA<<"Z lE(@@i  eP ~74P(UsA<<"Z lE()@@??  eP 8t4dP([sA:<<"Z lE(j@@y  eP }8jB4P. P ssA:%"Z lEܺ@@c  eP ~74P(1HTTP/1.1 200 OK Date: Sat, 20 Nov 2004 10:21:13 GMT Server: Apache/2.0.40 (Red Hat Linux) Last-Modified: Sun, 18 Jul 2004 14:49:42 GMT ETag: "2b7fd-2303-299b0d80" Accept-Ranges: bytes Content-Length: 8963 Connection: close Content-Type: image/jpeg X-Pad: avoid browser bug JFIFHHCreated with The GIMPC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222"=!1A"Qa2q#BRb$3%4CSr)!1Q"A2BRaq ?aOMҜ5nb1ƥSb [i D/@ 1142zkMX*@S(9@ NI#ʅ֟P(Dj$ڀ9&1Z`6ifZl"ƛQEF|T)P8AZZ n6е*%E&ZhyF 4ڽhtM}*K]LO>u5l hS  O-0RL"~T]4i.D5-92NqLPU1LW~jT2GDirɤMD֣ fb1 MO`dRC4HV\U V]Gg$ r~I8|6d6@͗GYJ-Gr*EkZko JCzyZA k 6ֈsd8 gΜ^t'U[dyQi)2ڳcd {8q)6/Cǽ ($AdpzvRBJ >tF^YLɠ7>2:*X7|ڗ?E&)O⣬fJi4C")) E5\B{IU(vՍܫf #01s\0YGY oW&Wop_6[&[Jc5,2DN6j- Ӣ7&ګ^{̓*Wn!,Es @=𛩧x3* y\&9m, wϯҽkY%,uYOfL#sA)"Z lEܺ@@c  eP ~74P(3EN)xQ-Dt5@M$w궳ToJ ):VƕS%}DgX>I]Lr Ն>`Uq-xş 806vV%x,x\ K0>YsgPmh}㲶;Øo\ͧi\3yuyC傇IG`⻮ E2[y<1W43Km(5*^#~1٩^՜4|ӎ~yʺ.<:UFEn [yxR >y|6CiMY\e_9"iu2V(nLL(Ve KIqpIJ v$2~CP1ZCuWKФxmM(ydѬj|X V- v9J*7Hrs5[~eH:g4I%|.=fdtJ^xa^k^7q$B!wF'm^o[hUcRZGja2_n=▢2Ů%wžH "gpfXǠ8'Ϧj\ZH/eX0 ]6ΩԒ@YsA<*66 l"ZE(@0 e  ~P47KPdsA1"Z lE*@@9  eP 8t4dP(HTTP/1.1 200 OK Date: Sat, 20 Nov 2004 10:21:13 GMT Server: Apache/2.0.40 (Red Hat Linux) Last-Modified: Sun, 18 Jul 2004 14:49:45 GMT ETag: "2b7fe-29ea-29c8d440" Accept-Ranges: bytes Content-Length: 10730 Connection: close Content-Type: image/jpeg JFIFHHCreated with The GIMPC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222"C!1AQ"aq2#B3R$CrbcES.!1Aa"Q2q#B ? P;λ&EvVn'jh4VA,4`Z4e7 [LQ\0 {h<G!KK`6UYԳ[(?Jj82Ai3"n"RH23>>x8׈u]bP(ԭO2,R$̌?Q\GR2dx{n+\⬘v/r:̘܀ pG8'j]>.jW1\cqȑy*{wAvH~?k=ֿ4#*!H8ٴ㏎E;a=T[VD7+yQ"Yuط$wAۜg>Qb4 ȡq=SБ}?<ַESjYbYl% d}Gucn(Cʟ&~w-w4Ⲩ?ʠS@$$㜬yA }Z}s=Um@!W1W*]+Pݺָ}LF1\5|&lWw>)(皫#ڭ#fr;pOy3Iy1EL.˷[?{izgsaFb=B* 7<94Vpwp7քu.4$WR[G 橨_"d!\E8&Ku5Y#GAV{87embϱm?[VМ0sɮ[)z4eFu~ {h:dcܼj[A쿦VY%BsAb6"Z lEܺ@@c  eP ~7K4P(@0pUx⸇|[# k6LKW‹5ý[s&H\~[[xlk IUl`և WXMs%v5זܬ$Irh)GBC1c}5-1q'*Y'\R}2ſ?=՗~)cTf&sm.zk&[nH'*;<׏,#"Q:Eʪ"im§ĬaWf&*wsڭ{?p琏U=KH#g|dں07HKp8Tp = T!{ o1.ep+w(# Sġ8mݣ4z- *.84.JTrcYr +6zܑ{>[vڹ+۵14Z1qն]{TT  1i 4|/iZL1fѨ!$>`~Fa .v[40:n>xY:Q*zɮ[mWbᅵm,c6kY3>,ֽÖC .Ńqljfv8(K{qĠMnJ|lθDG tR;ޔwjӓ(aիݖ+4FeH9:1\./dYH;*ogYc݊콋7Ɖ͜unq,*mSuyg [/Ru9c3]=Y[Jd vxM[2x28 |*4v&Hy5TB#>fo8ryЦ<7Q9+{;;~uR~γ 6$gN+m98E ']_~.ɞ 1āZOAJbEHNsbX\} Kc#J+YQ8R+CU &v{ZLC<:līb:2^aq-h4S9:sKܦ70?=kH"EE1Sڋdx":8ժۊX͵`(Fr2qڋoxre w_:dר61cQCpeSbВi/`y  Qt:#840)upHnæ|!,!9$1;ګ|\wFxYAQqJ8Jf#TPCrk(5[c륒̫11$ۦI%߄K/2'~X!K!9dqv[iQ_H˃*2ӒqN L2$lI%"x2:NB[lp>nRF3DY9PsA666 l"ZE(@0 e  ~P47P_%sAc;"Z lEܺ@@c  eP ~74P(l~Ĝz+V=O/Wpsڀ#g|DO9=M{vQc2i}6}U ÖJ=6rqߢa2_%;s[lvy⻱UDY{EZKҡ d\WT0g腥ȏn*]I2N4ע(`NҎ ;rCV)y.2.1I&v_e(Ń|52#',eW9_Z4a /\u WK22`OJڕ_ mfൎ-jb<$= Ǟ3UqqtX;|z[s=̬K§;nj.[2e6Pc*5ƅ-Wh.Ğ-DdP~> ~Y /o*ذ9-:NWlj*䟦 Q<"Ű$)*0B~\&D`HWql;?sJZ[vHٙcU~+Ԓ@Y r>^_[.I5*;ڇ[Y9#dU Vh-Q5 ݎ_:۸@B q8_YX)L]bm҇uqp-S8N}r4i,)V2N3փ^$b(u&G%o!!"l,RPò!;v\6L.?.,n31î8M͌Lо RNDszoXkp%x˨H1uFbeNy$6շCois+#d˒3ASrgX 6 c:=өWlAw:)S"{~]4.t*hn#m%zI֠FKr=^j2cR-^mLHaUs] Ud׋*dHNUwy#k9aNb*YQ$9Pğ p׹F֫Df\#恾3'j &Fʱw>ڪ{Ȳ%%)y>t& KYPƭ":G/*I$8jr>.h[$=VPG &p #YqN>3HӲiyDjr6:w)bYϡ5CJp#o!6rCwPNZNTqr;oDX7#tڳYZI8܀|5-&B9[;>[ 72 1@656$nw4y~UR0a] u*tF2{~ 65)R \O>lׇ 6A.FJ&dUzFt< /*r*`ô|J26F('θq{3)fOLOy Zlc']Ⱥ5Lɧ^]oPZ86a(apsYDjuN0?^<:5coҞ> qphUORZFmGUo0ypiRN-Xh \Q`}8 tFarP#@nhm:4nj%)r{i[c*u,-.`iIS#[z<6Y#\)OZs`!NqYeoEaca)Ƞ~a8e e$U^ƧQKqGix#8ElYdw'Ő(^72pCsA@66 l"ZE(@0 e  ~P47gPSsAkE"Z lE+@@9  eP 8t4dP(Kp ҇A8ĊJj>{G#q`Gw==e~G:NRxv+Xu{ bU'7pm_x{ʸGz%gS'Ke:idb=Vu?*#h֝Hf~]v=13Uy'GpG:Ⱦ?iYK\>oeI  H'pHdyuӪI}i'<';}1ʚkey/'!clAm52;@9ϡi qݦɯU!r~? os-"˜> V?jp2Koc;V :gKo-xDXf\2hռ:fvg^UI{ʴ5Ƒ*ʛYj&CKj03ޤm 1x? t~FU<D0WvT|%&7*H*=?gT/쏙ʺF)j61?D} @ڶ{ +x:=xNƻ)kz3|gTK~Rsޏjxfc%~?&ϒzY_]VU!5 ;>Onu-rۼy@ݻssPv֬Iے;}FOFqTr_LҪ2^_A. T xA|=*펱Bxa{R*iuo7!@Pdc:uL}9$iWϯsDn_LW7U*dK|:q4SXme*~_*-2TZV[}"dE8i dSHޭned*? -)`q,x8ܵ %eI\JgʹR. ZD\~8c=KVhh[ oƼEep)f;㺰4>(U$.p$v!Yf{tٯRF|V@0p+%ϣY{\;s`dR<I SEGS*U۰Ioi%Ģ8s*o +adK>eظR^ mn-4{80Xl\b,nHBp;hEKFsdp'~43QfRX1Ne9T-#uk+GPh<#ϯ.u+tn ! 7(#m r tu lrW\gS_;A>*f0݆$xds=>u R\BoqJdb {_| sF"a3LH̩j3pk} G qU񌵩aWTc7`%̣jd)l\i"~" G= *t0Jj^ZIl0|-r[Q?ݶ:dƒڢYv#N|CF7Rr$SE'ւ'?,Az5J ,DN:;Q׶UgܚFXxz7n 朦ҐRrOޕP<1*75.[aOM,Ah9PHR P )?M:Y'U,cl-Ad ѕF#j>Gp0ܜ TsAJ66 l"ZE(@0 e  ~P47 PN sArL"Z lE@@g  eP ~7 4P(CM?* u؁H42*>H*K(9~9i|t;ɤ٥KX~m(O*0~yxj@Hi1l@ɝT i; SL`L!o#MӰWrXQ ڣv-Ҏb&IMl (hBAYbq"㿆ܠaTz3PmAz@>>>`". gP߶0Zhz4UOsQ@NUGrA$:.GړcDtTI:*z}LTuxfEw}i*P'DX24dwԢB:\!rX85-Rc!0*h ?F Rʫ_Q 6{9&F|%p2=`Z;~Zuno@ԪsAL66 l"ZE(@0 e  ~P47 PNsAT"Z lE,@@9  eP 8t|4dP(~:wrm巐H݌Ex[Aj3±-3NѤ哒+z|3O;+c~H}6$jW dr9vG:׬aV@xK Pn+>܏*81iO\e`,|U+Y{TcҶM7$(8VUe99ң 6FXl3^_+kۧ8`%99p'mgyb"P0PFFuN.r-2I1΋X͍h/l`$qž}9V 0s9mp<;ToW4-kg NGU4FhTDʸ?box?f`+R֒G AYLʄ-QHdDv >&K!Ef$qKOE 0v+"g&?֕M i<'Ү]{uV x\rr83A$bdpsn⇗{yC'pWoSjo)RR!r;ʴ{yiHi :M'ևHCe 8ױ@ׂfS(y#vT}1RA:%" $U$Jj-ۆv1$E,fQDޮاk 2{˵AA2 QC 꺕v){Ia\"hY ,}+vU!X0  "N,nrdП/?t.D!F{>5 9M21+ K"U\\ql9=H}1?ѲGXL]?*J_tNyu̫>n6o{h@Y\~4JMCqQ!ߓDvT.`ZZJ fc8>tDž Q%_SRj?ZnR.P^})ӣ-ESPFC6S^$EMO#1ҷ Xn H$z]509!' ?~LqI]G.'Vru.O umb"$ܒqʗHcN?94ӱLy MM$rtPDIbIWUb]jvr湇ꗃvS2s:[/@FF߁UwE$WO Vs,># OXm*N_zsT鉐 `ӎa:ҡcGHB3+)N.zH;J /\Ǖ 1(] {/GvBjgCFߒ];6* b B$0$ <(9w&9oڪ\ul2vb7$w4c(C"ѵēMS Ք@]k] }qT폒}?E`n{?.ޚΞ4Ͷo&0OsHWjҞ,l<4nΗ:/~Si1WQ `}Gj uNiQ30l \r'5{PG"5=JE ]̗r W.>⶷6=-@o®Y3On)"ei5=iGuKuSGz }eo @rw$ O๮wi\@E [nӦ4&LazޯڽM,CY-ǐ6]`3JZ0f#(ι|elI7`jM.;!x*b:aƇLY==?'ПQh/<[񲷒anKDq7O[U߁$lR<%v3M5 66sT4VkP-c|DFFG=Juc*c&̓c6%iD.H ?it˿$ahzaέE~#:ř$qkw#zD4{{klͲU/;EiXj3^]p?AHqAlתD!y[$'Ҧ?pn\BG/~TW M&MW|IYozx(,3ێiHxHАC޲3sA^"Z lE.@@9  eP 8t4dP(We󬣶[HIM#|NM{N-ؙ7 kҲ}dɀ~mfuЋ+XA~d[ip:}Mt:J[X2qn?*ebN91)t~Nv{=??O蚷SZ]-r8@PyPhP>"ȋ>?5OTV=`لKx폏-Myg}o$lY r 0Of5LUMRL; vjŸZGorJ2=O *Rm0H N_%Bc0;6;Q^#iT$ k+c#gYGͱiw%v& 6_gsI̐q^oZ1,p,R*,l#Eʧ?yVYPq'&3[cRäi6z:]m 2ݍ?ʒTA&xq_3EqɐF|zԒ+%c 1:"e3U}/wԾJߟqbBH$Y hfS>#mj&(iط'8gDQēY;^QGކ6!ʑr=G4LO{U8Dc^OiLZ,ǏtlT|ժ¶7=@r1GΉ @9~5\g*D{ε1IsA^66 l"ZE(@0 e  P4d8tӘPsAc"Z lE/@@9  eP 8tӘ4dP(ɠ҇gjc@O,~T!镎7h;e@>~jSZB6Y)>^f lC<(\m ONki/m n@ $Q LWqs4p cMEpHUMm}$#5]@;Rʎ c<=2dg=~j#J3(UܳGOrpJb ;wJGҎx{Y0w-۱N=7K ^4>{A;91 hǩ?a{=*P{fAk\RQ3K Kl=[lN~5q,ҴF8 콃=!wl<΋ Asbs9'f*H;syveݎIy0ݱq5#.EUg؅G'kEf?{OZ$,皌;x`6>Cμ,|k39Ӛ$3 +YZn LȬ@tQrV2B8*PKX<_A?/:nڧm+"ɴߓZr\2EʮPJIo*z01+|cQM8 G*O ݞcBi!cQmw#^S!jo"Xx rBdog'+]E$bλc'+8{Wh\:)Oj_5?fUaf>s<Ҝ=k c(x;=83CE;:MԦXCsAc66 l"ZE(@0 e  P4d8tLPKsAh"Z lE0@@9  eP 8tL4dP(а(u,29ҴfaIݓpj'VmiBy Z )ZcsRdpxCr99?ⲣi9zⲦ>²ldVR•^/[l:1OÀO* `gփK{*3Q `v54ql1&TG"q"[8Ʒ<%`R3Wt37O=94Kr!s Pv!ko3*9>ccbȭRtnݤ"F֎pW|4,n"6E""=Ѹ c.m,(UlحcEqe+ Ϧkd=2_ MfԽ =nV5|Umc=S< ҤFRWj3H#2i=}M>c6G|*ZZEԚѼٝ|83ѭGb]KU- /L# =$A."{[ bT8e=tS[J~'=+]}Q";x;bJnǕ(lKd# R$>sp cuǙ#PItE D*'U&ӝVH"x;NƙY0Ն?q,f`:YIA#K.sONcOM(t8`ht@?*jr Ĩ='spXʄ䟖*\_pTz" t-A!sdL ${ow<ѩ!sGllv2)i$w8"Nq\uSS[iU`yEz%| sAuk88"Z lE*1@@<5  eP 8t4dP(Z$ݳ]j$UỲ"MW +<ͽ=km͂5f.|_0OY*+#vuηGD9޿7Fx xj8j'"u]P\E8f>Ϫlux},E! cvT)ŒIb\zxZT9ZY`-| s*;PpSF峴`r+FV96h\wR9dw iD7gӸ$YHs5iԪaʩ"Po.}MTPHZXLcǝY\H?BZ<GdRs nű;s Tdm4ⅽn2sQЖ}q?Th!{TD5b <ױi4aPdGZ(UgV-\3pI}jȜ-˄Ke;T?_ڊOo8sp?T% O?d5@jW'LK`ogjY#T+;O ~$8KF?CLilBzdbk6FK/L gݲsܐF&g@@|j,(2f~iڢ:FѮM;Z$v㊸Pc&2T TE>2w/ |h1VTxPO}qY@sAk66 l"ZE(@0 e  P4d8tPؔsAH66 l"ZE(@0 e  ~P47 PNsA<<"Z lE(@@i  eP ~7 4P(0$ݳsA66 l"ZE(@0 e  P4d8tPؓsA<<"Z lE(2@@?6  eP 8t4dP(k$ݳsA>> l"ZE0@0z e  P4bpasA>>"Z lE0@@$a  eP 7;.4cpsA66 l"ZE(@0 e  P4c7;/PVsAn1 l"ZE@. e  P4c7;/PîGET /Websidan/2004-07-SeaWorld/fullsize/DSC07858.JPG HTTP/1.1 User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) Opera 7.11 [en] Host: 10.1.1.1 Accept: application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,video/x-mng,image/png,image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1 Accept-Language: en Accept-Charset: windows-1252, utf-8, utf-16, iso-8859-1;q=0.6, *;q=0.1 Accept-Encoding: deflate, gzip, x-gzip, identity, *;q=0 Referer: http://10.1.1.1/Websidan/dagbok/2004/28/dagbok.html Connection: Keep-Alive, TE TE: deflate, gzip, chunked, identity, trailers sA`6<<"Z lE(aD@@$  eP 7;/4P_ysAA"Z lEaE@@o  eP 7;/4P_08HTTP/1.1 200 OK Date: Sat, 20 Nov 2004 10:21:17 GMT Server: Apache/2.0.40 (Red Hat Linux) Last-Modified: Sun, 18 Jul 2004 14:13:19 GMT ETag: "7593f-2ec1b-a77d1dc0" Accept-Ranges: bytes Content-Length: 191515 Connection: close Content-Type: image/jpeg JFIFHHCreated with The GIMPC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222"I !1AQ"a2q#BR3b$r4CS%Dc5s'ET.!1AQ"a2q#BR ?lSJROP K=*OK[b=7JTzT@jTU4oJjTPJz])MTԪ=TRM@*]RB YEښ8K4 ޑMOEKMP4R*YiSfHߥ*jzlT٥Y6}@>iTF1Hɥ4―6h*luZY4 gjU&zY,|ϊ/,DS怗j_jYQ,桜Sg*T(f!Pq֚= *zjTR"zzXtR5PGR1uOMwJ6nԩUJv%Yf>igG4@8K">(QR&4 4OM@,4ԨJ*Rbޕ5.ɥY,SU*$g-T⡚Z jimCU,P*9igz٦@>qLNOo>(Y8$zSgŸږ)g5Sjjtڀ*TG"|sH:ɦ?BYiIfUG4A,ҦڀTjlҡ"E7J]B5, 4SPHRҞ5z]:SRjviMҀzjTQRJsA"Z lEaF@@n  eP 7@4P_/iMjJ*|i/jSR!MK4暕!TԩR*TҦN(J=, ZR)P ?GzcJKn*cV57ҞM =7JlBsMLMDjY-Qޖ6$ԳQJ%,Qɧ ,tiK;U4ڛ4fU,K5**MjzfFYSPlRzTfTƛ4ڛ4@=.jYڀzY6i iM6v*K44MzTb(RJb XzYfCJriҗJ'8MR&ƀbi&Kb,ԩSQJDASv(R19iRHg/RTԨiMJzo4Ҡ5?zjSSbi`zTS iڞMJGK*^Ȧ1iDR"U4Z){*xD暥N*ROtoloKTږ(JhNJcOU@SQP>hK6|@*T1"T6E6h"hLN٥ހDJf5P?n5.D-P*jT*XA>~ƞEN)t$ 9n 9jX6|mKJcG= f4٨bw4Af3OJ#[blm)RBjTMHR*cJb!K>)bl>=b*)|cOM@/zlSPJ4Қ7K #Jҗjj*^R)fjTM@mR5#\ 4*uN٨@KVڲich:ԳPҨzY K4@1jyڅWG&BB;C4%SfOTJDXKDLH@HS}d}:$MD1j4٨ޛ4O>|P'*M@Lj9S@ iZn%@iLNƈN)t6i@9ږi暘j*TҦ5-M]if>7ROJfҟYl(R47!1ҢM04 "i֕*YM=*cKڡJ[N)R)!HMlȦP=5*T8TԱKoB TKMRZb; jjp1J6=x!zsM~ԱOڐzFnݨQSSPiyTwJG1$gڠ*D{R $ M,W:4>{fY⣚b!,SzsTkMW|Y,qC4{RzlTJU6Fi= )j9T sA66 l"ZE(@0 e  P47FP qsA"Z lEaG@@m  eP 7F4P_!jezfmDw*zYG4SfiBMlB R(*$XmMT *l)fM,m],Scj=>)SjT*T*TJTiޞ=ڕ#MzYTLM*T RF@.٥B iy4٥B*TAiSfJnNJ^@S*R|fl{RԱKSz]i)RP6*x@CRj|b>cڀ:ҩb"zTOHMlR*]])S mP=iwOB{|RإOQУX*|v5,5FMJR"{ _Zo|vwj[ qOyյ@Ha5C(Mj >iޘtALOTK5 =:4j)b!@DoR.ŪSdTsM Mޛ,@=,MnMK>**r*8)@Fvb)1iH "F 6*DSb/)iAb) YQm?jDGZ'MHzXiԾ |*|PViӵ SwaR66 85 ,t4j|5R|oLR93EU,mN  J:zOX=6lmV0օ"ibH B8`fVRպqLEVKaإ)x(PNJ)X(5if;Ͻ,gUMl>i.٤( S⡝Zbm:9ހ=*:&4LM6{RP*T*R|OjvjTgzo@9sAD66 l"ZE(@0~ e  P47LKPsA"Z lEaH@@l  eP 7LK4P_*j5/JGcJAMր|ҦB iR-֗jjzpwOҕ=P7zzjGYMHB@RrsR>i⣚ozz@th )fP84ԳPյ6sL)@.1 ~i jTҦ3M|@GjXt4H6)ԻRL@DXc> oRKzRP&;R4@KWjTاP6)cڨ"E6*x6TKA*3M G)c4@Gޞ4(mO٤FMҐ%K=RDqVw#5A Rڧ};f*XZlSzlRK5@DQ#6;Nj5KH Lv5aS Uږj"J$M i@8iJ})LP&zlSf%@RPK=iPcK7ST 4ԩvif7Ҁ|RJ8ހqMOJ6@7jjz]v)P *G*[RLjRK*RJ7ږv!MO@=,Rj5,6w@K&4٧@*zaJz|z|K4*&)*N;UyԁWzq YJԻP"BjU@ƥ )R1oH=6*%@Kiҕ=,UqJlR?jTR!֜ T JԽS5*`phQSSSBH8;SS*CP/z]RڀTڕjUK*T(5>}P{ҩSP TԳObHާiOTb*jzzj,mOK—?CMPM]iejRK4ZR?ޗjZvaP'(fNN(qK5BloRȥ+OMlmQ5,f"iS@7J|b@8;4Ԫf6hK=iu6)fR4>iwJqJ6i~ԩPJzRMzښhQROJjT.ԲMOMDRJ٧ҧ*TJ*f!Jp){ҥXJjCzYQ֞MLn*|UzT):TslBt:PxP-KK9v|c&LERJsA%"Z lEaI@@k  eP 7Q4P_JހqRjԳBRK4ިjYޛ(NP>ӃL>*z]Rǽ =!K@/Kޚ8@*TREޖ)PuJJT6*ɡ P-Q*9`41)nEDUՎ6Ujި--mu^alQ-Q"|PsOKAjlHBM,z[TLM"j9AJ5iUJ*~تKS)(MzT Ա|R"ib4(إzXKRKJjzjSS 6iPHޠ*T@RJTvMJhJzT!OJ7ڕ,oO@6)SJnj]R)vRޟ4ݩ Rޕ@SSDǦDV+$9[hXȮpjdK8S$5*qQ/tRlj:fc8GÙh$6zR:P]7¦lsbm}UR6j]!"ifZjsHjzSbPK5԰Iz?JzzUԅ**j.Ӂ柵4K Ji=!Ht=MD?JA`zնj:RrsK"-MЅIbiK bD2T Q'zaր|QST84Q6BK4٦&|6i}(lQڪSSSQj4 KQSRT!R=.Rڑޚ.J5?ZTg4P OiRAoMOK@j^*R"iP JblP K*FqK4ԩ@zTMڀ~K57jTJ)f~ԍ6if>(RTK>w!K5K4aU 1 ԰sEdӑZ2-eH]$l߇7 R38 D~O^E:xeQܜ~F'׭ʖ̓yJ 4\vmK) WS՚H5}]N .0>{?jȞ圬IgLn"rq^uFlڻc%vUlH\Y2n#ŢY"K(O@Af#ÿ sʽ9%s^Bo~6e/ oBosNJ!Ovd15lG9'=jfiޡY-RTv/TPW 8JTPqOҖiRF&[OY95"518KI>(zB7Ɵ8M@ OڢhQfiޞ&z=58T ޗ=5ؠjTjjTҥozTԳE*UA}?H |TRޖ()t,TR4oP7ZTi`ЃSTM#zU14MJ+\n+,HO4M5hg#ނL`EJteH>޹ɀ^="PY~Չb9",p˨d_5o800zdL@sAc@gu'qHМ^` 6b+YrAGap\$AO+L̋ݿ ƕҽM\H1[ojyƑ1RsZ|AFGP<2~b; b8bH]( zg?&g$H@Q0J|{үp';C=*SR5@Tӊj|Uӊ` AW 2ŸBRS.ƀ)=*UUD@D(4ɥT Ҙi#QSLAUt|݇c ʁzN|ca0Q2$iY-z ffqj@d+'hV+D#XAJ44LiBKG8| v'4٠T4٥THSYqRӚR3 )8H%6MRVKziiڬ#RQZ]LqT YXg4ԈȦئ?j_ZKigjX5*)S.qO>)PgjTP4ےiib)ޅZGZ@T{Rh ,TMKqK8,TQ#z.R>)czL{[j0'keF]p(m8S'MnX̍GDKȥTtj8FH>lJ;-5 u9=s8^\ ($<$NI6;}MBq4{!S#s)[P =qT(i9DQy } 01joA 9;yRcZZ% 4ޞA jzU*aN*j*Zՠ*K>qQ,@"k2PZZPM6Tki494PpՁ**[TK5Z՞(ǵ,oN *:w"4TvLiޖQaV63T[ (YfsAg66 l"ZE(@0| e  P47]gPsA!"Z lEaK@@i  eP 7]g4P_sY\%~Vekk[>\Ŀ9VOV2!KEN8<)\`޻tz,Tؠ#֘7=ӱdۭ UOYrqlU0;9;TR|u5k3M1Hkf8HSx\&J#J&J5P?қ*X}[T)v'4T3=fAWjUplӆsKUF@ڍK]J U*(R)iޠ$ޟ)djZp{jQ@676pE8ee!FfZ|Y ijZ&IWnSKnQ"+JMb*5:cT *[b X@?jڞɥS@fj8C )T @"sQ"hB=)bP6)b4Ūí3H1LHc;ЊhP`qvFM|z#3d+(z֝e $dV{NAWR7Dq?oRpYiSϥƌ$QT\E-3%h#&䱝.sY3 ;l\r%u5lfmwg}ֱ/%9, 7ow*:#JȲB16h{I7LtFO 3 4o'za<}ELYHl80l= ,NT΂+ >m4Sy#МX@O+ÓSq97Bc=z {;-[zxTe1ު(kԒqCˍREqZwqG|rvK!f'vc'$QR5`^|xH6v\>nfm|ViHNvDª"P0?ɬ[$$>'}Bӫ?S杌v[3 cִol1bS ޼q5diW%럲>vip ݏ7jǵx1W+R14:P".Ia]%ٖX3FH:sDz}*9 iN+j@ DĔ־EdҨs5 kedh]O[ TELTugfXХSPg&lЄK5 YހiL *$zRG4$)ڢ 85,j"(A;St-)zKjZsHoR I:PYF# :FEׄq'tΥ>Ƶ%ԮvV~oܯߨѵ-@?ҾwPk֭&}VX\"m jc[u.{WhP'+7ǽ.#krmlq3rI-fv:P&fN Fpq%1 )c |Ll}Y-!sA'"Z lEaL@@h  eP 7c4P_eu?9nFYXs֎-u_WӎrTYJ' z.̋JP5*]7zTҨjzX>) K4bYTM|SO)fcOK(֛UG4)`z49 P_"KTwT_8/4fLHR2vMC4rigji f*yC4*:gIgڟUWY gzlsJiMJiwLvnD"Mc˸@N+LOq*|i$u ?k>zv1RBIsٸ;pخo*zbl95@)i~T bFENDF9"uT;YȨDɾ=J{޹JTZm$#Gh,:dEsx *IPu>⬷f)#7Abh:eiG\nz}+.[XIN[O{s4+zh뻗Ei~%>>I7|}kc]Mݽy.+i,<~q;9mg\hAY1x|Ѩ+ZONS=n[j;j)2;l<$I|ћlѲ.:_ <.v(x]hD #2(G %(2uT`jvW5ApG̕c_@෫Nfʸ% +rvQ\o XnPnMu\p``!.JOrtfGIsi][Hz槐8TVn&.mn-x}Ć71ss\b]6 NN "YUÙ/d?~)sA_YpǤA_\H}{W_3/n+`cq/9"E_֭t!SO&ֺ> q. +TsA:'66 l"ZE(@0{ e  P47hP8sA,"Z lEaM@@g  eP 7h4P_m͋}Z>Md[+oW4̃Nr}, ̐yXk}/h-]Dٚ6(kw$zjdh)OZ 4.OCPiY⣚|l OMɨԳKR OBK4B sHY>iP K ,ҥK.LzҠ4PTԨ R.(,M֕4֚piSS 4Sv7Jzd S3c =3Xz3%ԉ[pkpjfg϶sWT?$8:s\B$h+ X h9WUxʭ ֳRaϹ=ݫ˖Q%dƧ/otBPsm45P9ZY 1zPju#9d2wنᢅr®޾z߼y, x$E }`{⦽'R&6oq W Sqju]@rFbmq=P۫QTCNW"1Ky:{(-A9?ӿJ=84G ?!#Im>_#C&OPEʱ U7#޽2M:Ü$^ ={נY""4vq@}rg$vWoh1Rsn.x 1bF¤}cg*]k [E ҳN+. *- l(>?so%+Cʌr{Р]Ć`ϳ9a^\Y5#7 t3yY?\:WI$XS[5٦ӅmHJl e[4hW g#\6ĝ`u7Hϡkr,I7.zQFǚ?]6Z&ѵ,%!QIQ;-zDjԾW܌8n)ȩgNӷM0,,xT 4F#4p@TT)QFj^ KVzY1qҜ֘P:T5 ZRajz6 RQXwޒz {jC]D2TSykU[~Hyq lWxMΗ[$6٫8 $yEA8xG;Ɖ3$hf0 WQ/)X#cXv[L:r?y%(vgOX\ $9άxrw,ke#;E;+m̘La]|So"eFkٵyZ# N$ϧZduc8j7(ݼ֜LM`+dsAY,66 l"ZE(@0z e  P47nPsAI1"Z lEaN@@f  eP 7n4P_¢&N(5 }CX7RdhG'>|erigcu>eNط+96lN$;Z8REW!G>oA;[XwcGֺ9^\EC9#^+JgM'=![)ŏsʇkYU4dW˧n.g#I{kaZ|=@A=éRI8d汋4ԑ]4u.S6X+sÈ̑^9 6k 澾9-Q,S/R2fxe/ u A2#푍F5ʶJV+KqSPM%F#!qڿՎYuɝx 'jq.N} nQDq' sD՛fGmV4k'Eg?J2$~G5M7HTGzD?JY/ҚJ|MJ~MK4,S M@>iSRJ5MJzYހTM@=7zT BZTҦOwHRJRhT3]ګeϰryQ:c.E|b_u^9ĶH\m#c,^ڹ%|el(=Sp"-\d,eF6{ yt+b1+k{ebCv^? "kɢ׃lX+V"x:F#9#?ȍ6YST J;ڨx =DJ4o-g/A1vj˞ \Ǘp_ힵ`M~"x9뫣}㹷kWXT'ұS۹Z6cs%ُqk;6>u$洸? xQXmjlVg1vU=cX;.)c-iZ a"s$Re?jCP|H 2_ n- |8lvZi:cg9փמ !O_Y0Y)$+'H.* }Vý8SJװ-qWPi[m_£FA#b6nZahmX,q>ߠbf(Ӱd&8d$p;[ZXՑ{X<'I(3{y.f]>a^.*كCL$גN1,ɫձ^:3j*ƙljFi:P\eF,}՟a#mxַF?sNMҳ`0W>;{x[N/d"j*lR@8MJuP4sA(6"Z lEaO@@e  eP 7t74P__eG5PK4Yޠ%Y6q@9$S棚UA,DI4(8ޣ)vm@k:{u)"*8W4x&&S_zdqh?Ass#-JdNzqr,I7 !\tp}k#aY.0zpF̣`Bvr1͌W +syt8DSFUTnyXlqtg]#ph7@vgr>p&d7Zv+-O;5gekFN9ܰ4eTwCpk u?Q]09F5;#k%,|ײ-OsH[neD6Xݽ`ڌm+Y:,qt^\ocy?^W=gn%#eHu6Å،&o,qPCko7B6i26s]a ҫxMs_dž v_H\^h]^\ac_ֽ8Jeۊa0Ԋ{\fdK4vҿP[)8p@ccCh뺧@<jW&KhͲ[}jJTE sAQ666 l"ZE(@0y e  P47yPsAP8"Z lEraP@@  eP 7y4P_a>vH 0F[Y>,TFBM"8.! >ՒBVF&)u d*Ex2/h kR]FCxU]Jb*7fߧ~IFUFzcenVc!tkv*A?XMl1ѿLs!Z!`cYÃu 䥶<qysGM}$f$&6q7:D8٘`)s荄StcqkyfQǜqͫ.y mu?ZʛAp$ Wo5 []&FRDʟcY7F1cnaVHSw[ku,rǾ)]&)otqZ\[dU+︯Lqf,yn`3 Yz'gyd̖ISهq^!tT ]FFetaHo>lI~BtSz&1䟩^s/>j4'4ҥTR58L:sAL?"Z lEaQ@@c  eP 7|54P_]o4R4f*jFM.Ԩޖ{v@84C98=؊DzcQ8=jǚYfCjV?<@N;?]nCkXf,s2wnle_(=#,܊)Cʸ:{y珒#8^\ځ:%s2S*SG!#&Qj:X-bX03QbH Eѷ#88 jLp-:o|֯Y~qwY8,`Ƨr| HF? NYrFW~3 8z2>2HF?.m-'qs%NCJ蠣Ve_1gO>j8htqWlow.v?cXg_X!ɾ"s \dHE 5tV a;Tx kKivZAOPzwK~V4@qkIi 3]h9PfS4qPkS)M$] a㍧fҡJFO\U\5PJFl׶>l3fcs1`]0G }3P ^\ w {wq#W ygMrsAbGoG"]Gڞ4&u"e!h+N?p0=u[Is2XXa}Ilq#6kȊT[soBG=¡r!V7m$`ao%aV٨KcCc>k~59NxR\ \x6w͛rQZ)[ ; 30A֍DO$mvcFvL*åvds< 8eUa9YƬEZ[\4ݹ)"5I>JѴqM2ȲFz&clm"h rZ߲R]Cz(hZOlȫ :[P65ىҌtŴͺ4LB|?(ZMQ W2j֑C<'~kdKdPu:VHhpE\#e1⽘&0ݕX#ZrpJwy1I*%I?G03nl=D&gWXFu@ }> '?ܰJsAi?66 l"ZE(@0x e  P47PsA.D"Z lEaR@@b  eP 74P_~{{Vċ'k B䞙;u +Gil<SJg|+&QmԄ.ҤNֻo'"beIX|݇'rq9>g-⼳lKD7)g,e~ B1+NxdE-d2@ʅLbQ(5 j9!70*XzGq4w%W굑=HGq%nHts̯hLImˀFT汲 m7\ hVkn0:8q랊kW#COn?CXMh21,glLug馼4DjpH,5#cON`vώ JXH%`YCy5岎,ScϑM~AH~"KFv.2dT k,`ew#<׻>bL[-*e6ڹeul/`5կ6__O)1^NRc{P:$p"9#rjdr]Q-w"K(-!)`u3M5岉d03DE&gm*-fg -á] ='نEq2 (_RU6+_ Wb><(9љx–s Q_^c>c]Ӱ%eϱ8dX2urmi?Nߵ{cSZ9G>2"#Z_)$ʲ$A^sT%냗(c="X]ql O8r: 1rEʌ5+^b\nէ+h:Di[,6\q6k$n]2.-3K4R &uQ-ԌX UN T?jZгgXIu{##N<s^l:5ds\G 2 ][bm4b=bPHx'aCt!LJg#۾9?kn!{//DsA?I"Z lEaS@@a  eP 7㇝4P_Ie1௚~9< LC8;tߵL_،}^F@ Hgt12jx iYOBt"]U|zx0aI\G0F[t޴J_;`H~oWNJ[g{qjWqzl֭B8QA$*35Y0$*+s¸Ya .Iʟg\,*2ʪ$7;g2&SN' 7 d] q_+>;:i .XFNaTo2ډ$Ws_ֽ_ MhAS&>b`?zX~KOf ܇CaK+%6_ FzH \2[y:*2grőE?^>EʢnbIN>k1ۈq{0DT&J>hi-$ve:3#tۡ^M5FN+2D<Օ9xtE![2*zYTOMP J,oJ-@5=*FjTؠBښTP JjTKO@/RgzTj|P iUJ*jU@Sf88skmj \y;V]J8m䝼)\#I2AFdX|ݾ\xt_jomnʅ%{v1fYQh];r]n>'S&8 gl*\'XJ/= ptJgͻM 5 WQJ2L#"F!l‘go8@'SlOtm [W*#&OrNZ~'2]xC̘yr6+6VpN>KC ˡHŞs-`n6u|5d6 :By~Pˁ.(Zm ~kUd$Hۃz}LрVL"yϟjѷ 4 j3ȄH~qnDe%۰o*um 3ZMݱ|Wm;}뾰xOD}`6p/nJ;&o,3p>ե$US֤Sچ`=ӭYan-h!(=EzҪ0A*X[ R5@=7zTOXnFzR=i暨ZLpd:"s3?YD<6W\/,eM1gMwzs 8%&(Us]ŷ[-q={z\߅A!CHFlϑs}rJj˴ֈ K)V7 #'եbw|lAâ YsǓkL Rg7q-L .$$1ߒ}҅]ܷZFyFV;(h`zHӹjQU55if$mɓ\4W^"+G];GiMqFYdУz+"0*Q'ǾսQHxqzWOj>i𗾉(?Os Ji[% @OZ’ 78c P<&Cm҄y]NǾZ #Ws;(,#[t!K+lNkŘxyk{MLj1P D;6P!DW>p;:;p@M disִm8o,+iTD[Ivvoqo#ePH=Y3Ln),qj~Csm{/RD;4?aXm5r-վ8j̥`q51cFݍw{HZ@9gzW>WC8Vw{ГrN[$NՈGܗfi%īpvF0zIq ?wl Gr#@ʍA' NX5nQ[- 0}zPkǤeoZq%j"HF|֠8gzƷITi#VV(h E$ע20e>} u2aG͸k)_W/,%{C+p9Ʋ$`^8pÛsk+Ig<9&Z4-C52_glݥ23Z4CH.J8234hp\+ZҸ8 zk沒$K,{îVI9?a\(K" BWr{FK9Y$d NykQ<>{I8'xJ$^f*:]MԶv͖i~ZG?Ft%PO}eM$D ZI;HMBlN3xż# (?v_Ʊ2CoI 1 R€"KibWxTZka1(cGJ})9jF':?ZVXƋK;ئCÏgGu3q^)q8QkW"d(ڵ7 j)8EmEfK0;^}^>Z0(P449#f_@~Jfn{Nk1fvn;Q1:Ǿ3XIP 樸Kd^9Ҥvj jvNjInSwam#jZ0>PةOvyvsAaS66 l"ZE(@0v e  P47㘹PsA(X"Z lEaV@@^  eP 7㘹4P_o@ED *HLo\=h+?).ck*UyOҨ2X8YWN͡F;7 ^o'Yd[%aDF\nfn"i,A<ףZZen!G;|U5!T`-芣m:S8LE}ZIQ;HAX#;SbN1SvޥٛynZ"<џ1m~H!Yڶ$]evoAβd1?\f8! ,vjpVczdTPGR}~ C:!d#r\G三"iNq-B)bnE#|<֣qqH-L/Epɤq4R˒y2FӽcU [ لHPu+5q"h1 ҌX.xh(mA8v72FcxDG҆y#i,3Z0]=!FK>k>MtڊU ң;|U$gbD1ѕqcN{zʺdh=^Qj<>N!rcl`w5Kԍ5iIǣ6qie{ЊucX$+m58:trҽ{D28kv (Lm3ߵ`,cT®eG+s*:Ixvsâ=&Wzb67B.)#:֔ Aun%A4@bE[2Zʿ4D>o[WőMZ9ISmѺ+\ SCyޖP& ~HB[&kGyZ8`>M3 c-^9cШ,2Oyt,v܇ )\88׍-~;K[g OILr]g5gVvIPA1g~"~#v3&POL=Yxf -6IS޼ݹ^oy`YKbfd2(1ZQy~P+cIҹ>,(؁n>NsDƙM8p7SҽXKMLZF濹gXD7\(A 3( (F#)5  hMsA<]"Z lEaW@@]  eP 7m4P_֩gsX>y䴶ͬvu7U~&W g[M+>ntoGڔ"(u7^L\:,h?çpZkVyT9= ?L#<2O+$gm \2c咶ʨ+I#A#S#Zwmh4BFjOi/!*HPqW'iv[-k9s`mMeMI̳PP>Yp6M~!|9֭Z6gciKts(v۬`2P5yƥEI "7SRh 1'Ո$c zPk~$۔yzjBO m{1],-5G8랶2Dh8*X ITu'qdieg(e Xa@=ϊ{؀R2=膗xbPDAC>uȉ` N2A^l\ͤÑfc՜>퓆2Z0GT?jXp۸n8beY/}N9d-?);Z5TG=C}˺Ά{U/so9wt8+*DzA(خ#iG-Y.6jTn]^RQV8ތd[0%OVRާ`K/$roq21ʹV?.ju阶u$!<DeRygrc'I0n1PKrMc'KBW0+|TU>hCF۹q}]:lƉ oEe]Pw_oLx;}ejKU/~%a!Xo&qW;z z5eݕƅ#,N6l^ylw5Ԫ,QwAw5|p1M1 E["ƻ#d, ȕ k*ngi01DF@Єɩz* iڠ7cހ켼<ǿ Â0X~՚SoY(T2.q⌵ң<#'a֔f¯o;VŹBqUz?2][pwUl"~n1/>}Q١/+ෆ  *[m°@!!ESy`#J\QsA]]66 l"ZE(@0u e  P47!PasA#b"Z lEaX@@\  eP 7!4P_bz|lFIR0 6{kIn~Пh/H#Z8R<|z7qemf#, `C}h^lMO'S'X3T䓘W1s\?x<̱t>Z~ S;*DNchfhyZlnc:֤Vұ0L/bYAn8d9qmš2#NV%“^Rkpw|>oʗ+-!dakǝ7GXVnmrGDv Pz};⌺rfSwqnóLp9wMEhcfD,C2=&$n[8qy;x"RWLvm۵zdh/>tzN^Ft4-q,5ol1({w5<"ݣ= a][k'pۯxEe*T`g?j8lʻ{`vI>Gqh mkҭldqΉ͡+ L}bq8`[F;$jfQM=\ŴR=ğjٳڼӋq7f8Lk#?z۸\98<ʼ[F23+>˅I|T*zQb[=+~a@$p:=;;Rg'B>nsl^F̓Ok#p۫!lY58mly\W 0̉`׉V6L=rۃJKbt㌃bpO崊Dfcm*n.{EI]ӓn! A`y ϖ(٬."D7lE ^ddrKCڵM/jR'.VCIM|c%z&&bsWE-TsNk)6O rKRsZ=^RY;AӍNHPi1Uu\O ~ᛙur?Z&nOhTOj]JӝP T@7*zntOM N $1">@t}:;r;DmK?~'Tn&2./H8IjWEVsA8g"Z lEaY@@[  eP 74P_jݣVsڻh; w~ kkX&p+Im?;~6mm$wżpJc8l*ާk3QjL*Ɍxrz:"7S>E۠㋛ˈ?z蘉PVM@SPa' jƹћ-dN!H)@cj&2d!:kV42$r52БHnѾK[#ƔvfG/ļsCBARk.u0`mL4acnc0\$"F źQHMJ&Zqb`w=@dn-k֓ F W_ZFfY$m^SBoJ 錳z7gR` -nXطsPc)#\L$P[HfUm^̛VckiKt޳ۈ%T8;Q*q%N.-L1δrRFi$Ғ0dEJ:-ue>7sx匪KB6#\[70d|WOjwbh#C= y'{5u7(I4 73Va\r,Z<흅uYTAd#Z'ҹP$5A~uMZ R"9iI{֜[ToeK$oGULVt1cY/r.`zW|RmYDa)l4_-IYP'#o՛8t(6ݤ}"ZqmI56/f[^)@}GбFKl)zaDe)z\tvLۨȷ.[ 2O\RbEny.FzڬB;TIwF$mC~Wr>z Uh.ˉx4CNt@D0W֏M:i\ĜJȹlkrn#.9!naYYJWG$Z#OkfEb+¤Kxu`>98vVx$T`au9@âe;ıٱsj%$JzE\Y`wYc32 ('@?j10IO}uz՝vRc#ʟ±̮ąr5IN9Y탟M_!RiӐi^0ĎCLbWL&5 p#~C?WYnR(gvAVH\UlM1鍨bvc ?\BL#RdD pJB }Ar5P8*BCB8$H䝩ቤ#lA0ZPZn=+uuad( ȏYw i5s,P! J.#R6UlRݪX½эrPTUGgs$alwD$cb ^@VD߈nPsAXg66 l"ZE(@0t e  P47㯉PsA l"Z lEaZ@@Z  eP 7㯉4P_\rİ>1A[kkAjo}k:ѥd2).<r4 q_XFr$MY$⋞kx4&k .{U`ΜrsÔ݄c1K,Y1Q.xOH,EܞmW_0"' ЃY⌟VΝ$Ռb{.d:l#CޛHb"Bv2#lF!sq;aV,;ā%gE;*}vj>siosm9!gY mlj>'g) !ӫ|2rAhUlբXJ/_c )Ai3TǷFGuIQj)M,2[y ңwnZf#,csO6m,b5tfs\'I#Bom2E)o99jY h"1bUdj%]Fdhve\E~jn[mOc[aeNCuen!?(~wZ,/aId GQXjFQ9=rH%9w5.K ttoҌU6u1'j6>;B.)і3o.GRa;k5)m^w ۦ$(;-́Qxn9g;u+u dq\Jj rUA~ZqӛpDv :ϒ(l XSz?bY˄H\Z`b>\4$Dm= $u2HV7vbTͤ+!?f&FZt$B۬X؏+b73T;E cK+9ila_C0"xL*Nsn4m.c7ȧ/<9RDC߭nPMR H>Dc݇\ Fi_PGZ,~!@ sA7q"Z lEa[@@Y  eP 7=4P_#9c\dĬوՑY#:!#7$&-uȱ\UVӦaKb|I5N֍gf87 dse ߦA,Z4kL Cl!tQsokm f{/O޴.x7pctj=3*nK;ז&?H`VqӰ*cڱȜTtqNDU PMQdw9wSOqr3^d1I}C"+5N'?2 N[5a4fx78c輼96u#+?WU{r Z"qx탖LNOssnT( )ʰ#KUecC5U>@&ْX7DBH6(`1!?f챎ގeS ,[8OsFэz.nmmPTFz/'v e+ =ɯ>M+7TFV?ej>³9; aI!q ]x$6¯WmHqcPHm2&ҳسH0GSgf׹ T_ xK$}Z]=+9IV$v,NؖLp< ІمQ획]$Yſ";Aƙhq82%ČWzc;gWHBad蛇r}Q,QV!vG.nJ&0%2q$HAGe:lF0>5K^+*_slhq,YK{`zɚәGPŋw%w~ՙG[`WZ[{oZ ]]?0(QrO2RIo t1%捥^a#.N<Վ*٠^"ٛYa?]K lL`F{k&&Wɕ7{ ൹&)Lns?8Kg=TMyBy|&Nⳓ*4$z:2:IiU#85:PVUp_LnnC%UtA;0JFA]{x["y|Ǖ9}v@H0$22#e,F+bȺlb>wo\uvSJ-H_ n`pGYmΖ:+) 2 K$/-j2J HL+u96ԸSkVr{uVzsAWq66 l"ZE(@0s e  P47PsA*v"Z lEa\@@X  eP 74P_j}U,lǧf(9t'Ek$izObJR4h'n=Q:- ^6Ffr^yn Y@H{'qx#;Q}ɂh%+c^׳ [: {Hed{[FQ>OjvumQq1C#р;׮ I* g݄*=/A}} {ɚiSmu4 yt9w>xQuIgɧSWѺ&e'Т12j@JH68NJ,;nM1r8*<էgÞFS!`0<IGx@Y>e!z6IR$=Y ,(V?+{wET\ÜTt[yxeo5 tܰpYmgwc]Yp3io!@`Nzje|6~T/3#s(txY=9Nc7վ? (:.b tOA5M`t$C1;5% QI se[rI'MDaJYY~a@.mD*' r ]c2;g~" ;>YH; M8d02$ٙzPoygse7n5~Zx'sO]:>u7kg9of8m?$d\QM>9mH;K/)pRh98׍fIεhq 2E0C:~kJk-a%RJǓYI(%Vt}L =+9]ѫ'54}ݾT2A{֑.1u\'ZE[/?Ļ Ϛ іw\OMD@`@@A\!Ţx7\x])ERVѱaš w+ -̹Eu{nT y~~,~%nBθr{*ҿd\]d6?+e$qHz~9\aJ͹Sl|xn/\ƀD@NYȧ6:/ >yo$Wv9*?5ĸYⷋhi6aYf%*•g<5+kf.2p>ٿA+q+srh#`{∱71eb`1أۇ[ "xg†:U]Z;VSdѶՏəp0]XBGL֠ɢặҬu8$cjĚ-b~ԣ+1HV3y%7ŕWLׇC!r#C ?'#!IƦk=x1ˌi'1Pui:qԐCn$aB*|ojV-C6d7&7̰3;gz7I%X7 ^~|g$24F 5sA7{"Z lEa]@@W  eP 74P_@\uCSq]p:Fz0?CB-pT NbZp]%i@ArFRhб3av^-ƭRIbQ7N+/ 1y IJռs[2G?.29bOrrsSa}y @뚍WF'qooLL>wD2YL nţn!wmJ[#muX'iLunFzz6ζt"eLxjo-fHhDX{[1tC)+ҳ$?Ĭ')f1$g&# _Q*D2~liVk]6"`wj V+NZ jIl:3uBրApcaǕ4~^#,Y>kqWfdꆖx:A3L-Pp iGlN|`I ivnFȿO7i°~:5D4Z@#oE$BN횫k^#­(i\w[n( R@{XnA? F .TYytBFVWI؝eW :Hn)%ĶŜ4 Qj~/o1 [|?#ynK$^8B1ǝgHawᷲ a5&g%ab\jwW)wb]QF'a/#1D}-eotX݋2u?j;4nr7)am>"Zj#BC0'liW\jBm؊ۊkcWdٷ; q5&Z̈ qnQ~dC=͊MH* SYkG'2K3(^({)ͅ!F9y'SVuAkyC?ClW[9CrIʰ'fG]ߧ(\!hש}/(>yťϧQESCRsM]2)`zW kHuGqY۴=FPc8Βh[&;{&)tV")mI~-JÁFfOJ9{4B[f;6'?1s$=|d{0$l'rkKqT ƉOZEͳM<24';V'p>E6K^|4T`FFհ"Y# ~k|wL싨yn 3NX|o%2?+SɽDՅ'"O' )85oDΕU|u&q+OėBDl/~n3V\ ;"a?ުX #f=p{UO&9݆kjL{˽NsAb{66 l"ZE(@0r e  P47YP)sA"Z lEa^@@V  eP 7Y4P_X/6NʛVsIe\l2ܨ#ye9mVs]G:)bӔǚ)#b(`V'.;c; 4"jD>(;MNcBuP( ]&RIc|#r9cI$dxYe|I Ҫ{P[I&CIkԌz>iB$r ˓޳xI$ PϧsTuEl c2\V2hbǫ qˮr4t$Ic[9.!TPH3Yq,Dtl YRjt%K!5(06GR_j,8[YMēAcx`U#n5)l$XChoRg;֏ ؤRʃVKzJk622cNx.Z1,l;ת1zLdg:̙DdCf1ܟ]`K~)s4v|`zV "ɹcքPRāh#3R92FeKz:QGIuRag@ut;gplhHX @ձzJ&nL-g`<|+=́@g)є)UßsZJz:kD.EF,#\(Y2O #m,Vhj;;և;,+&Uc3n&9$Ki1V[HxvE2$<8IǒHSnLi:⹬-IQY}Ì&9s#hC⯒|(ɨK Hڻ|1fpU1j-( 6mgsN!Sߩ=!|.Cd]\gqC;w5$\juTBI{gP}J(̋hTZp-Ոa{K=O|QU+AHZ*!amc#l)}"X 6Ҥ1F@RDP}HoYp 2IP\,0[VA:C\]K TjAұx2څһȚK6OaPtJ6KUfA$ Urdz#uR0޶nÜxMiD?cVҪy9BE0U:&(٢e#OxZ(]~>> u&wC&ޑ定Ir# C ]E?%`e]̌>@$x< "mK}|*;QsyCE`2{S5@I1g-&O8@|sMF'AcăL# nϕg7b}Y t|5׋"DsA5"Z lEa_@@U  eP 7 4P_G'0vמelX,#VIKf9t "isЬz@ KI*,A#,ї-^,2N;0J&(K$W[őtlj(v|[uFc3?DUb5؛kX´ū?Z3]I?HQWNu$WX&jU?m:=4gȀ.}8BPuL3G]Xt$i$v(<}hRCb8w.㻺iae*/ĄJDTӔ^ a6`zT~(W&69(Ej'F.aj1GǷxrˌito-s^C} Uu]Vl+y#IxDҲ&TTb+ sWp ĮYyaaW${5~bǃQyY0J(ħ8v>ҀJm}msv*ݲ~>:ep}M(l-rj/1{҆ dI7i>ucވsA\66 l"ZE(@0q e  P47PsA@"Z lEa`@@T  eP 74P_d( 2*"NG!*PXǺ vRJ7q i4CFzm*aytpN#VͪXGo⥈#`gyG\ڱ,05ɲm=H$n6@s YRM:9Iy'?Ԛ9͵-͞@&6$m繍YQh1lǙ"p5W U! :c8 7;C](^ 2Gu\j'EHEnHGRf Gz&qS\4)޹KļS]=4,Q7tϓ޴O9&wBBL'1Ifl,OJ[I;m^oļPZ8>=j~,ȣHX=~OhVvI=8jS#Qq׵gMY:*YQeip&2ӑT[h `/'794,,杔ߟH1ڻ猎)=iLcKRNV=p*mJmIĀ3GC}!H/3()⑔ Rxm*GF:{ԢhGsoRz] eW<'lBrA5S4t/wE/(!Xښ ѸfIlNvSO\rJ,R\F5pRχah>=^V4H-Ɗ˲-XpOz1g<36[X=DiՅS0v5 ?/ kK(淸F#,ڈ{[^4< @sڳ%vNw >13f6 ߥe,]A/_-T?Q?O&ᷗ7[-'Fp<Om3lɬTCse`  ҉W 0;mތ7Jv$Uc:؂;.\cp 2e ճø *B޵esAF"Z lEaa@@S  eP 7u4P_ <c$ipA9=<t49 帼̄CA'9;zօ쫭QQ+-ԾOq]tB%U r& } "QVM+F٫mlKڊ5|TTΪީ2rǯzkuz {d nhEL0[Q5<,U?¤LS^!~qN1^w}>dFJŤ:!cS{hk%aHȯ]I%3S+fG$҃ 4 {VpwYhvR)JK1 ڽ_UJ1#@챡.F=[BHr *`MΒq&3L r?oFten)dE CgڲӈH[Q⮏3C1L3y)Kf戸`*j#wj%pHdұi3>؟^M$ރ k!-g(oX gGu@,w0C)R~mAzE)Zc\`4K#Wl:vw,KˡQf,7@Gm ns 1%i=Q Q'>5WV_n0q֬oX s]Vαk2v_w$03˰5wFr:b39ʴqBWoojf\1A$y!XlY׷[a0}n%wDŽ)CƃcvҬ]I##3H|1_%jP (4)`A \,OXFG!*hlQ ~ST;X RPAs(%kW@E :Y1M5 A9 d.NtNkfLwp5zTN褜{ГSF,[\FҤH^yט~Z)]B K5\1 `jVP!XdWe$cbL8nL +CsA}66 l"ZE(@0p e  P47)PYsAH"Z lEab@@R  eP 7)4P_əxm ys&JՈ6mmeIDjN$cFG dX0CnhWU]OGHnY[VA3I%t #?]/㑷 O̼P:nBvQ{357RH@*ڎD#rŻ|B˄IG$1)z)KVN3+۴iԋS6.+/9q:j$kn9KIN}O`* km̈́gVň:ׅeۗY+IeE8`x ŮE&[vuHCaUMwg^nI/]l} OzX)ʮOnPYSl;׾QTZV1jaPkΕ*MkJ4{gsc}6Q\_"+cO=`oއ4ֳV[: ?-wg#1/w$BNoD 4@g$5mS[ .+J-Ƭկlt1! & Dk*<Л{ΠuBY#r} & q RN(,晈)sE ]krnS$Q'tgb>EE?)V7sX"fc ;ՇE.$hlMTЌSR{ht~ʱ֕%w"WTfA:ED8^B0s!R qxj\/.sL+ mڨ{olqn{f-?[{$+ $$ӫs`%3 0AYZ߷)e,I>CE)4Ddh罻(m$)ֵ I.O8[DT mi9&K3dW/@sAJ"Z lEac@@Q  eP 74P_HI,vu=̳֨,p֠SsU+(XٲJBF?MCniyecf9'T }Hڝk $y#0 ,8RC5q>#S@m]!s~Jx+"U&2U$ : *ku;f۰]'Ur_1`#,Jf\3q'>QX:I靺5b ޚqC@ABX.$p2|Ul/cs"*!9'8Jhŵ\lH]H8|Wd1P[pijvGRyWw d5-GZ7 Oe06Ӫ/$k8$%ǫڮKl@yAƃ0 Z|z .]tމb[`7Sر}$ yqy~-mFP::>Xtyױހl pO}:{ ˖o[j YK  ;W];+EY5Eveac. c1PE##ikygC8V`.9ǧUJM;GA )p,K6\/|SA)WQ}CS{Aq fG /'>} RG-ra(>$Z޳:LWnS2r esBM.BXVܹw$j;^D1ѝ8]fRZ]H@C!awĢ]X;ޮL7Fb<\ު~C_S]+@5 9$ATHW8*P\9`Y\Ht+wJImpeoQV+$%>>mbxk&t\ GTVV̇ѶHa8?s֗"p?#TV$c]&Ji51 9H(zpvӮ;#۽?A Uu2[I3iRG׵pw]qX Ҫ7k76:k /\A9ђ]Eld{gV eI-ckӀ&Vѵ/KH8*J׳Eiv9laTKzԯLd$M-.I8CT\rgҹBr{ Y)H ~Pzgy6",63 ]`H#7 > t6" (ܞ\\*nzJѢ?5$M; Fcs]J뭰-E9 ڹ~+s@pu@Ȁd?Ҿ JL-` H|SE3L2#d_ljrj ֱ{ߊQ<P0SRq1J Jc*g3"sA66 l"ZE(@0o e  P47PsA+"Z lEad@@P  eP 74P_Ŵcrk {Ul͏wjV-9EC\A$!Y{WG88˚s/b#=gTs2ܢq`Ճg=7:&`q;ȯ٥YN"^ð̊hcTu UJ~a (Oe:48(H[Lzz]^ 9EFG?OZ-E#' ƒNӜ-՞IAy !а aɐ5lVs2 vsj66FڏM#X%&C#'*&]PL2,1r+Jx+iZoQfĪV0jJKmH /5%h &]:$]fMm1qiInSȐKp<\Uv7\>gV*#lW4ΫGw ,UNP- \Z q3րx-n\(ćoY-s4o-->S.Dַ(`-vog>$cfq][Ǥ.IEpnJܻ;&z?< VSq_f<5tc^LQ喟v >gm&$< q#X\*@%NvjֿXm8XFmXMsm``YGvc4~vY%ĖZTȫtV <5D៊,x=Ȗ&w ec4Rqn|.XGy&fV8?\\g7]/+qyؤR2|QWq^%lx\,$z{/qu,122h֤1^ bH c.ۧOޮcH[Awî͆b2Pu~LQ-M̲Y\ҹ'">g Zrڟ _z Z^(eQl<2}OaN\9k(G)9;JmG?҄)s,G0ZaM,Ү (lt5D:*׻TCl?3?Ao3`gZ.+WV"rFT X359ڮl:P69jH@9U3NO$ 9?|!2ѰZ?FSeg;VA1r6aRM/\d}sߨ'z ksSKx!Nǽ?hWʣjxO4$ee~`Fp[J50ÇIc9nJ86vyX#ɌSO:N՘p[8ET\=}^ifVb^3}h#$qgmQdw?zϟ̐sAN"Z lEae@@O  eP 7E4P_'ea\Y3n(yi,@Fz*ڴ9<_s̃rHթOz\>*@襀i~N"R"wv2m̗|n)[f*Ưk+ ,pa7@N1n#L44?u=k|[? ᳯ X6k[Z;1JذFѡ\4eyY Ic#@â`5j\jV"CnN@}C4sEZ@ǫ5jdm(.PCMj҇;hZY[J-j^'nTy$Wt8OAK{RzW'+:R j$"5N{A if*.3viن{o#kjJX䱨CN`4?&kPr1扆06*ݰ3׾(L>6e2qg]qB(d2[qG<ͦ0p{бn_Vt4VV5Ol 8. V(Pk><ɞ2n*68F"f;0$~Ԭ8Dan*ᑺeG sXg%T"iV3o^ki_KP.<ȣ'9K P=$;e= woqZ''HÕs9C<1bvT$ C$rcim0xD j5і'$柊~(|^8PF#^&rl`]JeOvsq{RR5@$\ĮܘR0z\T X@z'8T#0{E>ziEƸm,Řw\E):Id 9f8$~*mP hM q;y,t+ǡӾ>?5O*:5jfIL\B甆MQ#* hN#OrT 퓾7į iݻLu@u]ބxwEA .oq+U+mo+D& KȤM DRF56z+S5g-0=*!&ޭ[#U=|V:Fz%Ui0D_cԚe7i+k$éBWm7XxxE8*1f}^N՛kA"(曈K71FpKBH5%^nrKz&WФ|x}Z?* Z\p#1WɄb7!u8rsКcI ;_@H95~k'U2\sA66 l"ZE(@0n e  P47PzsA("Z lEaf@@N  eP 74P_ Vc'z;+]#Rm@__c"94zշFVFЌ޹˛΀d 3rr-]32| rӉu QsmN i}s.!$rTMl5rb'`Ơ:A*M IrKnm8ai7OҡQv[$ "y`mى V꣢RWE; OMչ qĬn0SqW8F)b ]N1*>!6NHc #_.V X@,ibIYYp` q5|d w0),NBtʗGR2gQ5pl'6%Niq Bkm}/uF^;4;⟧z اMZ ˜Ղx66^"ggz ;eC/·MuMN6c {9s&J"Jp=J*ZO R'hCrw-Vk~f7C^<-?RWbWȘ;dyAbܧ, NUeW!˶j{:@Ǚَ}MVVfWz橆E]ʿVDK{dCޑ+Dunr}1ܻHn'W qF;fyZPw8jZY% ̾_ڹ@@-և[,v4кۘV(ı%zwPx-RHencVD!Kcd^VbqՎD#\4W6;:B:v4;/(?K!hB3"B9#>U7VOkuȓa}]ZJ[rze1Ms%ŋH 0[gqZX/oe]u -dӆ,a !1>=ӷ DISP|y%M~4aK3y;+E|qڳ,mc.ʼNFZ譸dF5.ľ}2VCįx#ehL}& zuaoO-|(\ c. cN h/7X)POv;Wk~5-R/iYIystNH&S؀ҥǛ 2`JҦ3\p\dn4M?l3";h%::3O,Eq*X nTsAW"Z lEag@@M  eP 74P_G tPo$C VV}DƯCH@vƕ]?@0|rɨNR'gj*R[t.ݨVAʩLϓ: !̐1ߵKdIb@# CMxf[c$̈ 3C+Kɨ;ON5czB^PE ڧ-Bh4{ ;b޷eiP:[D*Fhq3HN3AzFUܬ0gcװGL}޻-l +'=MiB3v @x 3&p}QNNA4%Ÿ 2z4%#nvag9OTF1ݘF9qIH c?KLN?5EbT ,wWs^jqI 7MX!F pfO0f `q1Z9|IJ`q@.:9)FXe(f1ڃRLNa)A|iڪTs|椋|,hAB\J&j'sG=Mepv$0fnmD;g@>MGbL3ˎ#6P v;_K}&YOȇc8D(HE=%Pٲ6x/{H3~+O|賙Tu&"XSsڱno$ a }3Z.-/TKe a$m~R/ze٤ȱ!p'~U<:F:b8͚o/1s/[Da!\6 oC%RTQssmiF%q8ơ橻kex$#*fJ.u ߠa"~dQ"şձIm8eQ *FsjǾxx6V<[U)62A+X-hd8M|>:T{P`ezLS$|Sr2.s 7$6  qLXmPxA1._Z {])ܺ}xB6ܷ@8MʽxԤjCIr39KzFlpk;Ӡ** )$x9'V&g1afiрw$>)W7mM,AʅS6o>nZ.l9J?js'RY1puOSHd(q43Xp;fF0*qg{r^N؊՟aw9[xvR^L9} nF3S㻏FYh%3HStut<0NFCq -eI-[ FX(5x:BoBF2j]"A*FĦu?@GM=,m] e L 3śrug|`p+6oIת1` g[9.z?ҁ&Ṙ-dAӅ~iFXS|{-ś&*S\Քh.NN(O:_p^EPM?0qnPǩVk\ڰ]qmr:ףG v]ULH5g|רylO쨿(-‹Hw,hDp w S*zdc5H==Z*K2 S.6NބEYc QoG'.wG> bki,2z|~a-* nb@nMZ8.X?YIq#S3Rt޺N  Ru!WdoTʕFt(l9b6q( '>~׈ PH%R7ڥ<$`pB'5E2Ò 95\/Oz1A@N|"Co%Ѕ%x8 #m5XY-9D&-E>~ 3O1&`27QvUk6[eaX"= s$+U`٨sE!e4*hm&iX#J0UTfGG]Dm~Yʒ zQ`P V@G.zDYTRc`Wj[}ݒIljNFEF$ʮbtȬ%ҼQ򱼱a] {&n\Qȗ[?zÚوc[yIwsA?"Z lEai@@K  eP 74P_;]1ό%WO}4Gwc?iKg=cBPX;^*z# `cj"Rч¯GϦhE?Zϳ6&T;/,VʼnE11_U/| AZe왢D8ʹa .gHLC–qzMi rz.Dn-v[wT ;`g'~+ܪI>u\YA2ܖ9C9#>iVVڪALaT8Xc]$KU"Yp:F{ 脖#ϲ{*w5z3eJl6ZLv̚tmkVwڹd"oљgç'@Rıo{_Pӓ̒j'Gqh)nx^/Ij6(:˰:޼S9)kQ1f]ZI&!{+;:nƘӢ\"g㒊lٻdr8EŤ.mm)u9WP4 tT`cUL[Wdؓn+SZ6-ļM}r;rfܓֻq ]Vi[+iHt^D7g&In#4.oRDfsZJ TY>2= hK,3s/0! Rc`vPFWM= T2L ɶ>k vR.!,GK>5 yW t/2ܴc/I/D Ž]-QKfhx.y$Rcވdj!kX ܏?Zx! zOOjFFfXq@D֤njB6M#`Vl\2[#| nNOmf\nhhfZ%q۵ |Zx`XΧ;Q4!ЍT{0(K @՝dNaƦ/vOލ,vpdǥ{}fQqmA\jl"ª9:sMgp-ụ/8yUs\jY΍ 9ofNQT2nlJL˖=je8}HR(˼H=*2DR}3QEuCƸ23IBc) dTeu6p=jϐeP&`JQW2[,e`WNY43קj/602Z3h0Tw=GY?Y]c`aV6Fq ,HzIq3F9zDt@X_ҼZ٪aIxt́ E+j/hiǁDpGcPJ8$ jS'Ҟչb+ݗ%tͱ  ' e!${$>crw7@O~,8@d$dU+أ:xvGIa7Fh- M I-hqh--ke=r:P7K"Ȳ+k>2r]0Zyu5TY|wͅ-Gxstb1(#y;n2 S%ҁiӨ`}+85^Z &=Swpn\0Fe3"l@v+H&}Qkۊ ՚jϘçWb^[\*?WƢ| `++=kuFZSЊjY䃸 P9Ď3\cj%D:-D+l-4mMVFNHɰs1[}%Hޯ-,ˌ9 \M?Aja _w--.\řZ/񦱙m3FX?\s ^t+^I0 "c%E#e9CҴLH|jG2q7moʲ^吒{d mbvn$Dcp6 ䷳ڕ$G#|k[8] 1:a(0^$(ci |2$7Er_Ypiܖr6cVp!<ۆрʮ2Ǯl+[ݱZ0kaGA6GCrE(G$,>LõgsA@"Z lEak@@I  eP 7}4P_ 7%D䎿V YHt$66c䲸6Kp "Qұ2 D\I W;`Hf3E%̒Oņ_^=24ԫF]ȠVe">bqZW1Y~siv5w1^׮[7p.g偨iRpipJFz#Nv,3*d^Ytj1TK:c|OщwW[5mFU٣` A[\ZcO&(2ד#Md:KoRVt56È'@ϫF<"$@٤\zt1]ƭFxDF\Tn翰+^ǂ7oEWJ#~Wn%I'IV@F45N5ٻ.8憹r S"0p6kְHtl}Yje&t qI^MkQQn[0#o=˘yMZN8pwn6%ݒ%gt${} mŤom.l32|i=qage;w2ʐG^uVr}x1ڶs}#ǽwy!z5K4Z琝9][^U*Ԛ9-XŒ(Pڰٰ7ک|M.5` UB6pw %|p*2.9oT Snc -82sA{66 l"ZE(@0k e  P471PXQsA$"Z lEal@@H  eP 714P_?414]g/=,ߩs*eѓøL 2Oa[<%,' vv֜2ES߹-_eɮnKn s' dQ]OlW#&6jƬu\kӏq1%S6iV̋ސN3N3@1`:| * s@ݶ ( Α1\K-AhC*6Vg*]qpt'Q\C /6#9H$dBνZDI<50PrPօ+Ku{$+4sne4.2fvZȢmw#=.BHzQ83\ie5{y5jxy m1ă+ƷBG-qsZKm:^Ye*ua.V2Tu҅_Flxŷ5LpĬh7Q[[bJjؠHڊ&]׌NѕqM !y;sA:"Z lEam@@G  eP 74P_<Z:}[ɄH[?^cIR#5јvlYS ְI`38 9.# 9";p#n 7zMhz#usq)f&Vyyx\yY%dMz#'B6rSҠc޺Xd\~Xo;ȓDT;tR}yNardNdGi).nV)G4)W;oMkki ԯ0K23jQIĬe4I#lGmt&=1!~&1.rI՘c7\~ƿD#.ݤ 1ՍGDWR3[PJ6Z6֬,-~5?[Ȑ̑]4?5:}kH"mt*.q8rs+vw^mk< ˠ=._q3,> #n|fi{%`t+<&;h%@v7F)ߘpEtiGAqtg[dCs,_p ~m1>Lj/-Ҧ i"}@*Tv3I[na}׷w6$: eJcgM~߉+tT2N+b''а{T92jic)کY {!y tDY/Gjk߽`Ĥ]*jR~ׅt27J@ICU#&k򌍱kRÁ_{B9~r{ #E-Kv5lwvdžXKkm$U }Oi_M_@Ҥa'$J%:2'!ǸHd,̚ܓAHUާ+#G~z0ۿGC¦!`Xݳ^zHmm*qMHԭfP+MII |>pC,6z`ȼGRX`}/`vOjE#OA /\`l8;ׇM嬎{A,  0=Nں5OO,rrNzǚKKSY$Zw+M] ٙڊOԐm2խ'AsA^66 l"ZE(@0j e  P47!PLsAF"Z lEan@@F  eP 7!4P_ pzW ⎷ܹx;ת;Na&@$/oqF_X.o~*3*n軌niYq)|Z\&:O+#,Arg|y'Zq 1PHơ\O$66V3Lg:P.15ŋñ@H׃y gQ'~-^h/d˜dKq$ioifGa5~+¿XIRI`Z R(R1 3@;W_3GuR'R \7h!~Jԇl/o\Nb*f\aiynGp$LoƸnE2k7v-D1NYbvC XOzǂn%QIz4ўs eQ[\Kxdxe.g*vT"oZQ5ycf ol fv.oJ'U2Ds} ZɐU(Xu_zDZIRGӬ{R&h6 &).FbUsКзrL6dJ;et,& 3aPRspJ5=mge} vpwȧ[w^(PgvYIbm 9BRҔ'@~mY#$os_#G|h nGnRݣB,Vlgӓk*?:mV센+)M%PCsA66 l"ZE(@0i e  P47-PAsA%"Z lEap@@D  eP 7-4P_Dp>>$ @#*V}&d ^DDhŭkH">cx&ym`nɆ"Hs\2;!f%Bu;~}2xR!$XN 8WNpx2=/&X/guԏ12r z#W\>B܃ms1jeq^#wx'^/c +XǦG{!ÙCj~Zk\k*hO;c 79=´xvOR+ϝ8n z0˞aA ^n{FB$3N{oXoR+jَE?d&E1g=IU_SE@z:]G ʠӶ2~YKyms^5 tI)b:_qF>3UQSS x/ nE~A~T;t2zA8ڧbu :sBMb8 op nM=Ec BLNخK5,:GWN N '"YssAJ"Z lEaq@@C  eP 724P_uq!-q8o t,XKHgk%24zk+DREkyWj0~k 2755cR3(UB+.YWʞ\Ndvaּs;dX]dl\ow׸wSmKВ^? 0=nfUXduSibBXbK~=av#-Ϊ9_Rse5&GH1+`rI>?};'Lco^w-LH5ٿ@sK 4(d5⭤r_p*d𵀍oLpHڽG0y $2EP4*ư8Uʄ=3Ֆ4 Su7S,Kst rR͂A ,;G-\«iI @,;RK+Hm ,X\;B0-V-e.4[ʐi`8=@ sI6|ֳeN~BsQhf*ڎ.*PÝp]0A=JAur Ch]! =In iXSЊj3cX^+Վڣ-6y`ϼƭaz)'%&c}HUpYߘ ؏5瓝#<3* BŅ $d,.Jx6"Ud"t̎91)o^ jԇx] :ح(c]$I'lE W#IQ`uyjkBYd;rp1K(.9j2[;n(>qݯLrA*5gSd[}rCc;X ϊ80́_k4%OW$(^ ~"SϏhp`?EI PqhYo/4VȺ"YVkwF]/KI]G& 6;s<5oǧ66$C4>fh;LHw'GV"[#IN+:ׇTFsA66 l"ZE(@0h e  P478iP6sA*"Z lEar@@B  eP 78i4P_E`P8$+,)4=īɶ|dzk+Z٣L=,>㈢h{iؚ*ۆC=,T9,۱q}rxR(͏zʝaEA&uѢsQT1u`[F̺ۻ awslKu.q4M{FtN,#w:hS$!v7$onvFmZv $%S 慴{ hȌ=26Vٲ aGc1ayTu'@ ⴖ15Ż+Ē.@~'e/&m#9|$MOa?`ni(9kT.0-ã_ VIU0#r3_Q2Δp*+kAqҷnvO~v\\pc/nŘ@ydQ՜wv!\lz=$ (s#$qֺ.cl;:j ;uic\#+8U>E+ /@@* ZrDܳkΚh(Ȅ&*Chf =^P3^ Pc#eԠq*0=8ka73(\ɥыW&T7*Å>tᜠ2\Hg;GL{b9RLۥzJ ;+YA7;}Ibd'MQ#JF;w(huL A_m; 7Gk{.5p@f,1a€y \ + qCFB5q(!Lr W/',yqފ\qYQhT9kbcP&FG@}VIco tʒW)|&H*JV;=K!h`ocp6ïo]OGXf6|qh{ ~L7Ow 3c>Ձ͚$jlɀx@7bM}XEc1-#Nm1,k 0v8#aw5$.Yi[4lA=qb߹ IE1vAGx4 ~K٭ +h\[4P_ HI4b ߡ[)pbsׇ֠e1'^{^x81cUyn0{Xv7`& a{qH;~-:{$LR2w$x<+ >i1mv[OnUZ{fl1\ D~#5 qm,;ƪkfZFYOSTߖNt'Fҗag s %Hz,$WLPs1+}SJeeF«S xF毒dd"Ub`I$)jXԊp֢\FOH*uF82 #P!n7P4!Hgoz)8V`h[Fٮ ud? Ds{WGy0PzBhϊe%*s3X?8S`t bE*zy%TsKH A-d*:ge2JxZ۫3q^?"93 O [ZpBK9>{WRyNj=ūg#5A(Kh\q>-ˁY|˝lq"Ȓ(R}{NJăY"5zzĝ3/ӍMc2Im>G0otgݛǒhe, I݄G ɂV-@3jZ>ɝyc:VsZF"88 ;ڴĘr9%0g u*AĞ6!@~QAP;{}+I/)floZVG#LON5ѻ 㪛15@<($Wp҈ƖFۙNG2ؐ ^,MkU9S+LXЩ'+yG\?Ah@DYSC &VNCĈ dE4gKH4d+HƳI{XΣ܋Tf-h(7Pj76域g oG\DUԥSCCwuyBtr?zXo$u#!`G>([!(TָKH-aB`\r k%4wk"Ox`ć\Gbmp:mMiWHI#2ϵI6HR':gem rSPq87%''YNu/#!ӂ@ZJqilD"2.:5&o#+3gHQĠRGGE& 0@]_[\3ƙRsA>"Z lEau@@?  eP 7I4P_Lm+a_ rOAUUnd!T;S+jHS  ?@r9Yi>nU-p>ԥWNU[ڧ/dfiz}6[u.#d]#N {Œܛѵ67Ck/&F2WGdudErr@N?޺MqE\`BV{~B"Lℓ\ѶXG,.pNڊ {yȺpT"ۭ<2 /~ENH h@})YK!99 Xv_IϰO2GH_+1nTΚ;Cbѣi1 uQA"YQ7m޸ uV.ď!#V`oqȄiZȀFO2&$FrX n!}32FmAVa# 3EmLi)j'=+1:= n.gA8u@@5,PqCQZ@1bp1x}(эH8:`3]^T8u1r|k1QGGBĭ,H 6X߅x -,ܐ[hq;o K?`k\In8?j/XkΙ~٥sg QhaMc$/(?5hOppqYKmm®%&:OBT|s3Dї wm .lFXH0wK;˖T̈0J2~ml\k9qٺ0m!ƙsjS|gkq ĺVi!zV$Q eJN<F}piᶢB5_ڳN_vh-vegI8F?zfV$} 80?_M@29N-[qJ&Tz)gomT**.GHţNky`5nkoHU[E/㻈aIzY9 N;4O>,MjssW&%E*t rL\1 =sEqR#Uwmg]%(t7ҩm?/g;8}*%;~Mb\*ڼ(2گW0*^H26,Cn~5YfjXrT/UZ܆Ps[XVv?4w9d\}?I#֪#Α\/DVxqpgMV}]K`dW9zqLOҽ4\ dwf YM홏`+sA66 l"ZE(@0f e  P47O9PIsA"Z lEav@@>  eP 7O94P_hĶ=$W>UN13+G_+wb HF sNlt`Y;p&QS 7l"8 >`3U6?R;+4uYp#ߘ@BE^mw0[M L21|Fvt΅8YO.|v1 .6.z &0kp属b23.!O@+#48:F>)l5s j~cҠ O_`a*q& 1|~!i#)9p)aքr07VшY+Q nvIK`LK\8%sa%` |INXڰ :Ve5i}+2c`p ^/#k.5;+ Uv۩y䤄PȮ],`XZ=.!k.u18ǵ"$|RneƀuzU9A ڱ{-J0تGH+b/OWO}((Tl^p[]W.+E]mId]H3F-^_ga ثvlH=;<4w.C֎5frHu`ޝfRPdIT 'ʹAN*fed^L#Nym޻n}1޹!cE](Zs!ԨLP#kB K#yzǷ3ɢc ]Z֏Fʹ!RfIUCZf+!# ư[IYqXBt=.[QeمbKkǓS)9=aCtOa+݇Ne 8iN0vjSE`UNS'Ǔ dU'9Xb33}W -$0Fە:1'}l{G4i`7گSKnU\ ,;UBp'9CWұnYX)U/I#oY#ƎDy’v5\Q,SHްbk^n $4*QlPfefG5MlvCF̀\C:'=1.ZF(mYԴ$a}*c*Q*"IVr 3EoEJpEP|ZJȑM|&PVͬQA.Xߵdp U+AƭfJነ Gͭ~ʍXo%0bۦo\[`ipX99A4.o!Ia\L"2͂rtQ-,)$h1uX`04ybHܷ0}T3ʼhdC&gIsA."Z lEaw@@=  eP 7T4P_Qw_n}tlލ25T\2XR#jJE #,%T%#GZ_;ҽ Z[0`3[C1l ,puէg if+i|0eѩDc[%zdx yuQn®.X6!]n]pje'IQD*-\ڶ96BvH`P c^ULWmΘlO{+ڼyسPqQ/Cێ!k͈ഇP0+<yH㗖dy*iԮoAb|_2d@YNkdKљE7g%18]4TLaF+1Оٮx-1%bb 7#n7YՃCTU' ^9-GsDf󘏨>cbMwtEab|{P7 /kxK1|&$<9fA8:WdE7_EċNq[pZ{kQgEg%`?!\ϵ_ {kcO I^s_HI u* diZF7Eq|ұ ̒U+;wHt, ;qm nd]Q@+⹈̍r39 b3 1Bd1q$EųA>&ٜe4x\g#5=@2& م5̢ӇL?J͖OF gUty~q$gUgqT.J᣺Mc|ȡRPJ:;ճJ..9e BVfWU-0jj5բ_eb5(uO?xUB|kƷ#PΟ̡N-o4Fԥbs*wM"#I7n9[xǡR/mQ&轘Wapg\:Y n6_CI+)DrsPpebAzyl1F*//k1{creZU|H<caxh.nGdmiߣk -eAV{T:>P9į͵ܒ7@k~B0k>cU2"U8ُҬ"MI}#qRDұ0ӒQsAH66 l"ZE(@0e e  P47ZPsA"Z lEax@@<  eP 7Z4P_Ehѯ&OçiFXV_&؉vyw:/] + oy!ܲ݊*k!c{g/ rI+i]Gy?es4m A$cY-P-vs 2JQdjkn< aNI&>%5s:'%yOW-hn ꬧r˄.e,g+Fq*2F>5tC[*>XbGepzkz%%cvجgS_J_lVǎ  h/&Fś**'<sp)C *f ca0z pB'7xbd?mfXReR`N6s^$xxd><apZVqnn[a VPL$Aeaڊc"P $OJے̈́$ݯdDg݈7 "X˨9]{՗L;O9Hù"Uzq}j, Iآa ~I;cb#g3z?[㼝dQH8P\F WKڡ}q0'1$:W xFtM#yX|2=A+~eǓ8.K% L`?JfcW~m ZkWUwls>H7 PH4ciX*}vd!3MB0\޴ӆI/J;8>:R)s ᬊ %\Kf ^FX0'5*e1ˣĀdgޠlϵyi e*C =ǽiYG Zf뚝3#6)-> xhcX³`Ph2 CUy,ѣ6n繮y2(-Iˡ-ڴT3wY;Y65DeI:I''Vޱ ];qu҉ y\\Hu5de8޳&ЂAk㎻3U8Ո՝##J\9212}޸TՊ9'V[4 "lbAB/F.#U؅ܚ5x%v|`3߯16|kʖײ- @rK|u[:V_N _푑y-[ ut2ƜNu?vx)q9'DAlAUQhKKi9 F]40^-m$1$$WXRtY\2?iБ9uЅ؏|Vt_`U)kysA<"Z lEay@@;  eP 7`U4P_$eafˆ>DNA$d Ҿ[@8r7Urw20OP_ں.Ŵhp7vz#4~b 5k"׬3isчUob6n3߷+s׬+=9IJUG!jbA= 5lixVi⛉q{ibA+2hZ؉$KrŽsX=M&3k3".mYq_G Lx<"0߿ڃn+uu,t2k=ĊrHh/ܡ4s0[FnY rFNxUKrcҁ|.Dg&L`}]s9Rwwx]Q9z7^fhoIRgФW!. !RvϑYP^" 5n:ڏIp g;ySڼWHFcmײ1Ɯja#+o<n4t9')}k m#"{i-cie=mp~,֒\iW(4aM`[ ,SwQŦD`!L}X Fc}ViUNCI!.4[]Rm^c̭ &70gn_zhI8ȭIgp_DCsVN4HX{ n5r# w[d*v}bVu:$f8-gH1( Tg>o+^M9Dld`‡Bochd5-x;C:?ŎJKa7wJZ C!mHq4%seIH8sWZ{ᶑ@  9e#3k9iTΠS"&\A ں!oh2=Fpy7 19M=!F*F50-3Rvx \/s)å <`s^lZ7p.5w^>Gv|֊1ixQ99PMz!Y,󎳖v($¿Q*W4<, )|i5i&}%_ w,&T**9.z|WO4zL@ZDʰƦ ?6DA^A%€3~Չgm(56.zf/⏅lbW:cS+~_hlh`:cqG>$V"yds׍Ic;Gm]9eaAe {PudQ$%Z҉dwDtu> H 9 ںC4l*WHgϚ,b{i9"@UNq ^-b7;kM))Ǧ%& |WnJBCtr#|ZN owdd\_jUqK۩+qCsAV66 l"ZE(@0d e  P47f PysA "Z lEaz@@:  eP 7f 4P_[Ox.[~9l[Le]Q³,Eĉ$*r4OOڍx҈8(6zg|i8$>.jbg̒'t`vڴei"~"hc "ɜ+)O[ z5fC",á u~ R듅cVu/) HqW2EiPҧ#Wl߳{*;]ͼnde0z{P>5YB;/MIeZGC}.<^)IۣٙY8[l$N$ԊMʹāZ(ZIHa@W7  vr:ZgU.ى<\݅:|֌ Z}jWu0^]Y ά ɕc*+D௫#}q]KjJȑrF=:{k4sY!}CVwצ?F48U X+}ҥ6 PtV2+*y$ ױ/)~*M['Vr?yg'Iad)37Jt&a^/!]{:k%#$r @sYel"Fh@#7l?{nؖiцP?zݸ0G8 j%rA&2 >"8HXQڷ-22eo^~ӼU_glʐ2XFX55C p{n[ "S }s_$"CfڴRD\ltǽs^>/Ŵ%U']nVjuTi]kì ĩ")ۯA]nڄVZsZ;nvl;O]kw`VhlIF, AR+Pk|c【wA<\XPuico5~8\O8Y 8@;`.9+ϟK>i%\>AUK,+[6;vnؑ+. (`psZ(U9rAwzݎDFF:Q s ;޹|ߕ#]i Va@bjoG\Iis( Is`=Q#;HĀ;VGԚnVnҎ}rN@r@=D[i%nQfkًqnѯO4E {˹ 4{֬'҃Q=1@p诠J )ƣhB#aQX}K#ֲcu(iV ՘ZH#N32ap$ Uۜ@_5>)qXc8m^ƕ]\Qv{Ґ ΚX#UcUӞsA66 l"ZE(@0c e  P47kPIsA"Z lEa{@@9  eP 7k4P_Y:в6 D$|.ءn5Yp=H ƳlK2,$XBK85!uo5%0*Cy I6xr {QVbT[*Z3,$c2_jαل`6ց bC9w UiLmW6#\Г^ZEK#e^k'.é(E$ۈ̋Yd86Yn Јщ$Xյ6۰+D|wZfV8]>D~'"g'@BlT8]赖Du$ɧ{ݺ¿/_;ɔ vSYhZ$&>X%H3j0 )j:MYDe.jV76jU'\g9+rVZ̗*]=N$z@ UY$k'3*/;VLz^> +5Z% Ovʑr g;$;Gd(\0 * uIPr}+\6:j+HbXdj/` TI;f8̘m1=4-O%c,{}*rglX3EFs&pWQ8[fCm #YqYL칡"Y\lgJзR( EUc{pͼcq3r6t, JK}&+1}_y {|]<-nV0$o 2KE[UbAbY#gsR6uD`exeZvss5e 'sw g!ISejsM>KUIyMG)ŮĝK'2$EUh;%NUIpjEBɫrozFǖ"dFN1{q$Άd,?aބ'-eu(ۋ}8S0aPk*23HH\dқ 29=AVq!,Фeի㠬S-Ŋɥ''ױ#2I x?Er|2%Ae x3KaiHұۧA7aRnŴ4wxNdyy moZKn%~B, $b]a {Vf{ˣ;Uؐs14:+f2|NǚYade+IZ=YͽH(޹ˎ/qʎ8Fg֗ wZ5?SܚdY8Q/އ{nYŞQsiWP#jW 6ym^`B~<}l#v;j/!qq#Ihju8GnwZFl)0+>Pw$*,gפV|7ݱ* ޻6Du6B91k8r:lÒ\WJmpB)'SWOl q8 75bi;)9˓ԏ5{-$0/?7k@.fMfi6'ޯ g\JG8=[Q;8hwq[TcGm*^;HrsS,) `ɿִjEyL9Of̨O7v u?ڀP.FU⳧ .A\ 5p:J3:WPhL%'{Mk9;Z5Kv]YOI,un\`E ;& \AYR2iHge&ӤQ՗rY|mxhs"Gq⩻cEPQn]cMўn6B%Truk..=DuiUhԒ(;HLG%[pE}H4"!`.ym>dAk O2o0\& =zI4kI .H;Yk,&v1@{s*PQG$˨'b*04}6 >D1Z"jӲJXʡ s{@xm8vbh>{3һ[ƙ*[%ϑ\Ӌi3T_jܶsñ"5t:_ {!cm+e#QsQW snaUQqom:VǮQw& Rm?Cl831Փǯ~ b%OCڥ`ھa-m%pAte5)#Ol8!V"GgYmkdq(}R3ϞD1Zԟ ")N[=o{UrH {֗GFiUt{)4n~džZJZWIgh7 { xOFe,{}+ٖG"00cTWXmruAr-g`'4G l$tWN ojhgKƨgTY\-ڴ\S;dc|ך2]"pwա!;k7"P_I 0}sA66 l"ZE(@0b e  P47w%PIsA"Z lEa}@@7  eP 7w%4P_A]{8rojݼeLIǏLܹZA)CMY`zsѩ3[\ ʍcWzٔ+ .`a'B()$_qu2Ph`~]Mona c$oWw2Jb2HT;Y[#jF+b1[!y6bA޵SsvhT+C#~Q( Q\<-;5xE | ܁;`W)u#HޭZ˓Z7_\(ae/H`W .L70\D=OV0 xQ(;.Zͺ'q,h'"kbτVJ8w7>k^34Q1!s/WJisd0 :lPi+-<)$:湀9#'?Jd).oU$J|f&"dh4+pkٍvFG.ҧndc3=6ڮ2í}Z2u_ mڙCk29l׳r**ʥ0 aM'j];zv=w$JlE' 评oުL*[%/ 5f Rά@B21#?)Vݝ Z03x޼^W*7r.")ul4Qn 9"P!#Ys]%!R}(#k^(gFE lI*:h2zX{V|:м.=Q%YC9 o гlK4,b/ Khד]%#(ȶк,fF2>+(Ѻ.jVidF摝ڗFOQb,yJuk R \LVXӇhG Gċcs- &z|X(͙RM>MƚeXI 1Wۇb0l2-'|y qh|Z(Tȏr ܊e2XZV;ojݭ$# C]c@eNJ 6e\j#5ŨIQAaZvm[2ƇVIsYK__́sܟjxg Ti%z۳o5Y|U\/E.483{I!-ccmgqfCIZ sll!ǩqUď)q;;%KF@>d7 %͹QZxպ1+~ cg3դyzԳ,2/J VD)5P#prJ!ZIH.t`m99m~us}Llo&0%Ve]j?z.Phw?"[Z#5'k&`t޵L*H|oV~cfYr䠔EYBɀlč=.8T @CU$nNڭsA"Z lEa~@@6  eP 7|4P_b(꼵Q#.=`IfljҶim* ,DKzP*8lUhIc W=YpᵼI+4qqn4@5ܽ_%hEmDrt3 }ӃsM6`la@+eSp}T&vJ+9K)vIW\q=:ujBNN=nu2 *[9 ĨIwH -`hd'SޫHZ5UkvG8btw9 ҡ(QX>W,C'6N.B(P[Vs' m ޵R@Ǩl62F֚{%E;䑎=wo"!$\ݱcG;1z5N8b,ֻgpIW_|;czb<1@\8&FrKY@֮$m2vYv"D%GB|Jv. Aq^6`7OҸOF5c7"q#5l99pN"mi ,s[ІLFO$53If@F!3j5HB DtڝV*;2{UpjXmKY_G_.GZ QB.DMs#͈0UJi{(=e0# ",CIMEʸ2W*q&UԥN)Gݘ`Ga]vc8 o5Dq(m,եŠӗ}8#M$OH\ 8y8ɪ9n5ezx|2e .:vM 78=iMh_^(+aIVpVH@:NE`qTPu;#Ln}ZOڲnQ #h߶";$XɬId*'B}? q5J6<7~QmKQ֊vQZKvYZ eW-HsA 66 l"ZE(@0a e  P47䂍P/IsA"Z lEa@@5  eP 7䂍4P_#bFTzK669 bBɨuj>WR*UC;w& u;EIea7Gwfqڳr'x5 v&Xà3Az!I/_=0|ve\gicX1ޕ۞affm}=(tpܙW؞X扚7ꎧU lbB=vF,yyP۶X9aWBm;yVmҪ**W:b1FBC\UrؙUII :{WnvRX°ڏ/H HrA ƝDݝ "\ PkwiϦ2X t'tvIAh;\4%dg|W[(Pςm8u|NLwRfsE\W#$%;)l.MiI6ip-$:u*zPKF9x+~*;lc>NpDq<2yM4i;G3oY&u@妜9z*H; ]bcI-T0! .*("]:lI\.C]/q1+-!J=$ukWJɁB=Z(bM 2G5T|QtѭbN6ou\"FTsf7Ʀ׬=q]3"Hփl %ˠHþ<{3aljT8=A+1+Kr=/uڶIev\L`JL~eB=BW^ۻA/nZ"!@;t\$ Ik4R)ݺojbn8:⍰^#j#YL+7 `?cYaR]I^N9PăS6wɮFtS&߆[2vkgaW( {V/nwxM'=Q2I!tu{YBXa4EtƫynJa$gڠ)fX#a6\KEQ.{U/!ccmp8@2io>$֊IwLx[ .#M) GK히MVAIȬ ,8>ko72+Xݭՙzi"zluc#حXΜ'ϊ᲼k'S*fXiF#D5|&Fc-r^D1*@9Yn Hi$d^C !Gjx$Tzq y1έQ|XI"-,+:t /'#xkh'"oމe(#o]q-7j̵.ϸSbۋu᭛$*n%шJ z&JKxz+Qm+G4 669İ|zV G FA= l150yd2Nz̥gKr:sA"Z lEa@@4  eP 7A4P_Y-$@`Oe"m`enORk>~PcLG6\$\0c毑\ѥ*3aZo WDN6mmq7eXҺU˲]ygkVh-$$>nMى-)(=:6ۓl􀹢nWPln|V\3LtG.;X ^٤`ic޷8{ƶlG W}GɮZn'5 'qV.`Gz%5$ˠ*=@x,jf#8'7޲eX0[r=be6(HfJ,m8 pU7xmd ;c߇3٣I+ R`޵מ)lħ;GScIL u53r+<ڢ*i5.Ǫ[۴Fq#Fvr=ʚKV3ÄL֊n"8uRKƤz۾3Gb-IuFk'5˷1A*h`ma\vQFkq3² |Xcދ~k۴}Vpzb~ ,MuR #HӋ  ;Y:0}Pῗcچ-卤bOj[͠XB/͖jJMl86HTjq'@#rƤw6r4H[6MuKzHR}tkpшUwJmyf#*w5lldÌ;´\{TnN?zic"(ӓw6X"9K}_sBe*EqLǸ-fk΁$u59lxvgFA+y ey|1X^h5I1.9R&lG&Hn-#tl9'?LV;Y):~ئY$uUUc_//S;y( p{'{Y'!ֹ=VN)s$I Djv sx^̴]d%,cVOWM3 =C5lĖhEipd> ޳&D!KHλD^FkUl0,=JGŭY!7rXǹ '+I#=C+&F@qWMr~FVD'F8k2\ejum] 1Q ޼sA66 l"ZE(@0` e  P47PIsA"Z lEa@@3  eP 74P_ Y&wvFFO^a;v?&|XzTϖW4 WE8}Z$pT,^M N3?q+Rlj$ne*ُm FАrgr:/ـBpI^̶_hK\;FvPĠ݇QJI(JʦtR^DՉ4nzqioT6".?g ZFwuSh"$qa@F'NǠ*2P݁E}emLqc>Incz2~ I 8p[O.Elc'ȮI?Tmđ(zV%mH sӽPi 59-YHld'z&("AV=@CIUV/H#zܺ!A*`@ !Va `=gwQ^|pQ4PNV6ʀ3<^CglI$q+U*58K푸g$eRchK糸%p`{͏s7TuIsA"Z lEa@@2  eP 7䓩4P_Fv¡+ Oܱ& jͶQsr6;N5弒l {pߒ}^~&fp:ŽOuEszKFтCt[q5n1o_;'N:)RKn-)f  bEIJѸuزs&hfm\F%e*ڤH wcxG [Jaަm"@'?ҏIIe*Ev6Zšz X\U 8`ѕ9}2 *ÕӃ\<1rpϋvF']GL,;ܾk4xk@r5Y[nW㭜G/+^@Kis[\_gqʍmׁ@ck%o]^O,҅t!Vlz)in,*˩Mz}1BШ01~5roRH#'z5.,+$J., nJ2 +5x[3ݽ@u+F='`+6: 6>_–GVi\x+4vt  B+VftB + {%ȖWa?SOx癪&(IeSk K6@76-$N?hmel8}ݜV&C&lͷ~(#Gl6?(!bWձ0CˍI ¯g,bS89Eq5h;3JȼōFϿJ宯d;`RZkԌgg'f[-PA,DD# ڳmqne wڈ >m*fMv|4v(@H{wMΛEs efn‡I!֊sA66 l"ZE( @0_ e  P47]P_IsA"Z lEa@@1  eP 7]4P_0_õ: 8}/(!oU_~gXgeRr5oZļ'+`\^@0c9b2[#~3XMo2GHҤ,B_+;n1%x;z7x.ֹ[CuYՉijR Tj{c"(y 1覮1gVʟkDGA-@JH"ƊiФ?$dz q +N0l3eOCHQ?ÝqܤjkDm2Z\m)U?!w]vN\ĠpGJߚ9 W1Nøg2^/dV=z'6b uƥ>-^~=ke0C z%t$/EvSYMky L|7%`U>~spW9OjQbB&'do?ɚiW}Zx,@}b*6lxa>qB`+xk65d4}5BK6NOzʜ7avmy&[PGV")/:.Bc5TsA"Z lEa@@0  eP 74P_)f#`jVEblZE0z.Xncvڱx #d)R>:|<kyhrGִl8mp,ddx׼B[rmԭ8DrŎd~\% ƦAބ Rl@k c\rD 6ml]%qaW\ihuC,7S(NsW Mg! Yޯ[%ډ&K7E]x⪺#5̰VpWNQA9g$yk&iCGZw+&V$cj~.zGlPlY[g򌺵sn!w\wIq7b'ijR^/qŭj=@Wo%})A˜mEojq"#zh(uf1ҵb.ah e><3k|֟ᦑj=b,(pp+p~P9;r5?٥K+6Cˣ]ި$0!7f%Bp2+ȼ*!G} RLh@*=k~XT ǸPI,cfe> g4iE^w|c45 39\> ߯Zcb3ՙi4{(ra5ēqٙ:ׁBM 9!? c߽_#hffLe0Gڪ2oAeK*Ţ#:])a4n_-^MF?Zϱ|3qhE(R15 fG KiB0ۚ׍[노Kam,CEqpM%VL|f9PvP@UdcYU'=RDcr^)BoֵE401]; od«ll'VE@ruX=^GRwBVn2͙;V ,koAN;+"Z]1+|86]#Rq䤎=),His\0!?s[3\9S|\]`ڻכ9qFGQ:կ9DQ.+OX]k(m*wvHHiuVQ-eO}| *DK̊b2ۓ"gYؑwp5^C Jzhr}L?ӫ\871# Xi&]!2)QnYRi$D\2GՑRRccEGd]q2SY&i m%IL=1YwyAk0*6}I$ح{Y30"$pHΟ5;声@T ^DϒvڒwR(!ssA66 l"ZE( @0^ e  P47PIsA"Z lEa@@/  eP 74P_PݬF'*Z)nq4;"6 Jڊ9NP˥q*7EԊ1Sg ][[<@gJQ{[_cAqAbke{Us2jmEN#d;clIfZPڝ|*/ox%\@dxɮn/5-ف…rwa⏵knqxqcfV%-sf8,ǩ *UjTBەlj#FF\PF#lLha󊿇(~ "viqћ-dH 6$7YDfrpl(0f1 I>o.VTfY z/Yq~ZǪ0Hp:yͮgV~r_ϊ[J,OWk%1]7{Wlk-q[ٖ0qF;O2;a[qQHXa#!w kKn;LL^KҚY}C~ՋDl>2 QFvu.T4Ut>oKbPyjгnβ.?1άuz [Ix -"I5cl6)::9a5F\ǯMk5C;%;) xu B-2;MrK0zҶ wb| ({YcJ'`S|*UYnQ+ٖo&hc׻x#ɐ,끡._G1ahwY9`ZRILq2P1VRigi\(U_\,ƁʸqC\euiPHaU142߇3]Ck>gNPd^IrtwX⺭йde|wO\+[Ps/ c3;i*8<ףRi$ch0aZ#qib}^څ#>2t&zɹAσY3օ͆K+h,5&&ٙ+&C#\bU}ѤsA "Z lEa@@.  eP 7y4P_Fig"m>N+SZJː5 091Ww vP|ו~2(Z.Im6-lw?Z7p8m۰  `; 6#R@Ac[űmO4r/;W0&T}{ &p L׾ϳi $ ++8,jE,Z˒c\$kV"vͻ;С2ArXwڊ`dv8\²bc,iJF2Jyq=ʴjGt}Z mg1fGU< #NaSEz՝,q$q#onpFW)vFpE[,ű+KKoi⑭8lH]0aQNsÅFXiq+ےJ̚cC>>6+ lHsYJj0#WH"rgO{mm{(3?ں p֚E@5sV1.[+.\)vPYzfKcM/'bXZ9Y0{ ܭ(8OQoz1#ַ۟"3('cw; U(wbQ=`oHExfp`qڌ_4fkw7ЂI jҺvHwdOozqé,Mcy^yI&Bsc!Chӏޯ0[&: fr1W|{P4 "VrF+NU#Oi_ӝ(K3 4Țf>Gb;rr7Nua gjy bp7Oݰkۘ#*ShXW+nK FLQEl0'r5aZ2-"6\r Mz9ÂWrqR7e+k9z ?LaCq,H'$z*ݢhu$`=u29oc_-_RgwD5Kx_prPv4/#s~օleHN͔?:=F 6%)m@0C1ԟ]Hdeu ֻK3V|wN7H8meq¤HXl@;֍Y#_om@2`0;f8,4P84y1IU+9Όd][{$ieKoxUUVOoWX,w9]_{,qnn"@eHN>+H2pL;oh+! F\,& a3lqU]EiQ÷\s!`_![w.xa΁mZ0Éډ Eybxùu_EBЙV^q"6ݔgNN3] <8Ftoa\^9DB;126Yq6f2xݨRSL]ռVdT(kFեDP͏:OB4Jzm]eqJ7jBcj` aa%%F~pWZXm# n*eTʑfчW+dHJ64Ijh].{VWQ޳2sA"Z lEa@@,  eP 74P_NԤ{Vr6fta/ÇB •P;V\]jP+ޡ2\H8W>\^k[^UM$1P;`Зz`o$_ 4= ⷷG*ʗ8_Niɚ[+|]2KЬnt^$`eoV1o_p@7{fE;y`).!+9xNQ\{'&ΆYM-Sr;ޭV\C9c!sݾE Sbű6ZHXmy?\WeCvgEowFk)I. {>{f !Fhn6IyٗSPߣӬ4J5?⅖kՌGPjj\5e jAVpQ\g@wFz;CMZYtD`PϵQccS؅@Xc9aII'{f\[q2f ۍԑֱřE4L1C4 WעU旑i3bZ3sQ=GzǫlUFnS<zGxilͺ\3ȎAҸ$q.-[Jp+'[| 8/ib9nw$7,Jň#>:N_|_ܚx-r8}o"|I*#&<9k.(b+[qN;dRq؜W*#'5? q;FN d* ULe#IUtdH@J3 pX19 f1:Ho5*[FpN楯%{c*ى[2XDy9՝=JBgӞ XQ9>dD(CqGI=€rh{4-0:u ⻾ |ɠQ !ڱ9S*[2$"ۂ[ɴN*-i@w?(<2I#k{0/@;R?Vˎ.e+v몌{W[vO iQ%q r_݉`vf2.kHDL0|p5jjCGPpPbG],K|bl O{w &0zs^ }; jرu<>ddcCՈn>Ƶ M-RݐN;f hkلUC+'5k9`7\xw p6w ^N^G%{o]!D?6GbJ,2$pP߆idFThYrvxzӾQ܉Vk$1cvɸsA66 l"ZE( @0\ e  P47仕P'IsA"Z lEa@@+  eP 7仕4P_!HFʭoⱯyVXEheó1 s[2龰QDb+k\?.E|BXm[uQOZY}pr#=Iq d `QxY^mRҺB1ts;ۙun=ֿVѨtlV *Y'9+پD̨@p0mpmfGZ,X!rҭ)Ae֔P$"%$3o_9`I;v>kӎ/-"&5v `J$$!ՂD N)xm/ d6\$W޸3#>|Q̗B[jѷ+4HG F5wl*'Aݗ\ ;0wcnRDZn(^M=n(P]:, cmJPm-6Ն(g}v 'lG+* Mhz>wtv8vnG[`ҙu÷ӽ ɰ23Ϗz"L|oO޴,R=kLfA|(dF7'ZH18<҉Q,ɝ(6 >ҔBȠGܟ#YwXDGz | HjՎb^i!:ކKi2 v<+7*pGƼLblz9#kzoЊRh#q1JŴVWP2ƨ8'*G8vj&+:sTn{bV8Tpg*wqQ%++sn(VA߶Msf"[{XtFJx0 :lbIlpoⰥ/#KpGr6|RxYpH5X^p9)^OyVf*?)֝벗L (otF[ְ!8d0'ڃp`{Z>a ӾX_-D]:HbQi=ۑֱxΜTb!zۗQ"cqvͷf ׄh9;USJ`,aS/ռ.8拗$ퟧ sp"1PLl>>FnevKWIo5XcnooIX# Q\w=EG+IJtEIJ1hY n"g5f_^jtGsXfйۭ{{h9LqcItoKk9؍D[Ci(N[i3d["̨#BV1`Ǘ*ssWؖB|V4olg޳mL"'}h[d2+W9G;g+.zUAUC,*u@5TnUO%s&0\vɩJpZ]"]hٍlp"DQ@gj,n]8N+sA 66 l"ZE( @0[ e  P47PIsA%"Z lEa@@)  eP 74P_xJgKct+Fhߴk&VH,KJK>y#G+kKnxe9Pu+J6ۭ!?dq!fx'Z^6=+˸w:6>1k-%:zl*-pĊj|Ҍg"1IFND_ٽzP.Q'jɑ߸S6Kt;SՍPk.|QܳYZY.[ip؏"}~ o}5y-2DHbF;ח-R4)n3 u3A5=fӆO&oh-,qiUX@r~Mk=։#I3AMH::{5؍H4ը+ m$s=?tn%caȚTPzιTis$-3ﲏW;l.8{ߋ`yC-؃ұ%(Nm~I^'-񌟪 >\}kQtpۋI.bn36 Ҟ;seʒ-`1+?qo~9}+ZYVd#޹qQˊ%@$k[YZCl9pg}n-˻mrG~,na9>VOAqv&^fTcv|I ."B2qcښZGvY 'Af-Hg9\8zy-xy^iŒE;u\iQ\؜’ZfgY (nZX;HE uúj:Z O2wU;x5=nh,rX(ï ULqyrORv^9ùWe T6t?K4W 5`9o*i`}++"hp5,pDi- 3Mh_\F~ 83W/qJY\`|ZXaA-o"ޭ3ңs.UP MrƚpuucUI4縸 \&gS\ɖ/@_,rb>cރE[ydSvޮJ6*`&(6|nM$ avOzn!c=+q%^?! z}($wL,]גY74ZEvVs-P`&w=+-$!%Z(ُ`'+ mqsuyNT^q,fq35hllɰ(v2۰;шR ȄHއ[ iH3 ;})8ʣuSb{ 4V=IH`?.+R[tX]SyO5V1 ,{ձp]]JNI-sA*"Z lEa@@(  eP 7̱4P_Xsn4 R! ?O2B}RMAa?[^$Ϋs|=Й<1a=im8# 4 zqq^,b2#M*R:z!xyr܅F}0@E8OOT{ώJ ܡC>;j1oc7&05 C*q8ڀծcX!ǣ}hss[q !>OZ? \7[Ń1\ܱ[ŝâ X.ޫ' G$m50 :Z6hgRX dny^ʖ\`kx(ԾӜwϊ妆;%Or O F2qV2OapáU kޒ/ׅ[v!٪P-.~߅X.qЎ.`]CKב n:5.·ak#1@QDOnXgayiچ ϽĦ:؎N̒؆Iq@š 8?k> D$*aZ1Yd=e"m0!H| */n# a%x&H'V &~u3[] .s g/nߊ]qma5~(H.? lLztk ¶R\jFvhYg6W6#=H}ɝ]ҿh]'P6+&#4}͜ 9(] :PGH&3ֺQ=A-F5 ?=-yCnhkoms6 `H;vhYFX% 3zӢpE_ ӑ n>~# `==d\ZF*6ya’Ӥ ~u9ϽVHfE$;mGŌm *G .䌖=O'Z&TQ:GV5v#{$7*`ʝ$np$8 {ceaX=%Qrp ;XV!xPXIHE5ͧ)$>=Ͻi2z:;R+a!-4-I14W-}[kX$J>hºv\JmaE^b3dyb\ήP:gֿme7Ƈ $S{ca|Dx}bڊlЏyd5}Rf Қٙ8s2QRcIim(CqdfʐQ$UH\8g \2ȅg56!FOmֲԨbN}͗捾'Z}@'ǚ Duϟ4- c+o<.F9=]8ķqМm&ۃE G>Ysk[ x((L|:xlz95sA*66 l"ZE(@0Z e  P47ePWIsA/"Z lEa@@'  eP 7e4P_4U W8L2g`0p@va\jϰƠhzh~PGJ0fv ڬZTt c!QYW^ƒ#di #iaB%] XK [+'@:p:VL2wNt;֯1^,9Ca%rE|G}qMd|ձ@%T~4.pJ\1RI''m@,a1|נKRA|3޼I#g:5аx":B [Hzn|*[`%-gqk `bp}A/ulE'3m׽_,PD4n<~!xPƜ.F/hYKrAՌ=#OqZakfRNG?*]]ڞGȂ!`8?r {53$\ֹ0ArI'ڋviU]ݼVHN{"J[N>3޳lx[q:U*vki8h@XlVR {'\J%#)ҭ 0u(#4dWa }D8aϟz^H&@)(_{rqtSY%`kFIJ폣Gt[1;I9ծɤH'qD,򬭤aҾ_lZӳF nb$~ꑐřzئЂ}=ksF2Sz|L%"0si|gj36}¦.oc@Ǿz<<JmG5tnK"=ϟjAţ0gQ=\/ h?^ՑƢS $2gWnڲNKG<dx{GD`dW1bT@LdW_dJa$runVHYj%0W/R1B *Ese[bջ>X (ؓ- h/}/0Mc\JUzOY iڼ≭K Q>p8dTG~~iZ֋͙Eɬe7JϰD$;%=Sie~vg78q;0 #!P<3q53-" ?a٫oXpm :@8JE$Ꞡ0>ƸrQIٙ~ϕjQ8j/n F?*~T|8qHWL\OAOp,8tq0\` qNՄνh rdp")Vɟϟ&[|f3> >¹D c8mQ%z3fKv36?VϰOH|$y'"sA4"Z lEa@@&  eP 74P_1o5;+8%F0~]X5mVI4$E&~3*Ͳ.>14J$Ab;H"h"3zҲH*)Hvd k3ฎeJ#H 2ޡkڶgn[RI[u`_۠@+R$&@S~w V_PAکRm{ ¶5wMdJ2cc;OVI|oh$1Dz%cĐt}Ge+{l-dS);]c߅WH.hlq?f$7O̳qY;)K`׼kO64J;1binI lO|VJGʊi$*ǫGnt, ݼ UF)Z7VPǚ4{i%dƔP[Kv4+Q#t$3dġmL{4W,dF}({QXc#aWI&lPcqсfQ!:mh3ʀ+{zhXuL^|Ȳ[6l8,\VϘ!=Ȯb>.m3I Ҷw:]Jd׆o1[OsǚIe^PU6†G}Fv'B; b0qѶWE-Z ي9Sє.XK,7![\47ʹˠJ>][đe+%nǁZR@x7 }dZ&0`{)?Fz22pwoÓ`CdǾk45yĥx'1ͱ-0~ Vk;2chp%F[1?Ē^i`zQuvkv9Gslq ֵmNУGCwR,<:^7il2r 3wϚݧI&U i@'4lxKxnPUkM|>#%0ZơDp|sg%#S\ڸ{ۉb)\ҪNe͌"vTc":ܜy"ѤZ& :}h8S,!tX?ФpTANM Rbi@3X:f%kI&GUc.ndhfQPݺ s|դo_¸6+`]1DmN0(RHDR{泣k}kE+ VmU!FS ڱLɣgGfR `{krQJʂvd*U|B0If˩ DVqfRBXv jE{xP+H2>m[*űCBUǀ¹?#&6:sA566 l"ZE(@0Y e  P47PIsA9"Z lEa@@%  eP 74P_8t Zػ6}#B;8ibī Yl -f/< F3xczs`˚IKv0B#DqLN]$2=Ы,VSsi#pAj3$V#P/c[MEif {K%0\ϙW|cq˵ܭpf\Gp?gp~&uu\&AeOOlҶ c^ !B0/ Dlb6ڻongsVL3dxi8y<|>3F7Ցlmh.qUMKm%H`L!m*0x#%%f"H!wX403{\ JA $D6W8dP k-Fll|Qe9A :BHmB][{YF_egyh$NN}kVkhՄ}^D!D7]N8,;d\YYs+ \wZfTl168HNz8pbR qmX6FEs1{]fN)Iqk$݇ڜ#0ocqWţ: @@6+~kjtݫ) Ieftߨżד‚t($McpK7W5YcW);AUgVG9 ">1ւVVfbWHr)@IL`6 ,=xȐkh2jbli]n9>Ք$jl U=!]}k| .%xC$0(b|*y1$zu Ul)M#(x^99 };\2ɴr[J;z>%g`zsl0w]_[Y'kǂY2;Fz?h*0 4W:xX d19budw6,˕u({auq*c.|jErK}{Wʹcdtݪ>#XGH`;>MQȮRc*H[9by:"ooHqڹi]M>1ȍ˙6# 6⑟gXf( v1[9i]88p;N_pj/WVGtnDFgtLW-΋p 6r(ۄ F3Նƫ+R֔M1"Z lEa@@$  eP 74P_Bǵrl.g$yQv(d37Bg eB!AnCgB%p%=۟h(0O#D$ @BR*;Fΐ(vd'QRmԚ\-#b${װ+mҽ8y.^LՆёIʀ$! OZRIxErH AWIJtߨ5ȍ{ zZVقbOϵX_RSQ\iO,F1TѤh9Tz~S&uz:Z(n-$Xli'V"F:ɫo-/LݢjXͨu5E[Z75[N0Edȓ710q[ V֎?F[T*D'%wכK3J@Wke:cb1@p+;;s/T"M1oA^g<'@N/L‡q(S.[N[}όY`KypCoa0ڴa)aŮos<;DKs]U[,\KF$'Vߠ'үN ̭l7w޴C^\jE+*M*w8үPVv#Kۀ ߅@M44mV4m3ָM4kj^]SұyyãmSM~knyL^J@N kA% ҧ1Y_+iHN̥ heL؏ҹy-J]$rqk{K=,4qe4OvBc]J89!:h},æhka '] ?L[vȬ߆$|o]SoSj"F\ tcymm% "zy5LLI~^4_IZdqg}ׇY2_-,s.ʛơ۵rh/99|Ht湸[/)bL݈5<O0y=8Xuϡ_\ZQj^9"(xaRqdts6EӷX\J"(?Ɨd-p&Մ'`In[KP S;{z1Qj3@wRJT65-/ȄX9sIKlsA?66 l"ZE(@0X e  P475PIsAC"Z lEa@@#  eP 754P_@cE{hb BEٜlc8vށ#Ɨ6q95AenƇC;V'.*NIu\WΞo41Q䁓#}qSd!$dWdn7 x 6Lq(4ܬk{*uG b9VA߭bİq&c u87\-ɨ} o$~Z7oçq5ÎSʶEcWI~xmL%фS@%H$ōc]Kfd;pƯَ6~pGC\j; !bV>zkv=)t5 1LSO\XKo1.H:WQja.0X>AX}RHO5cs#2] ue­,1j$͑mq mDdjeY10Xg]˞0>5cЩ,QL᝵3YVjL1sx$8d("HW8G z$T-S*>-iovqy2H>Wj#+Dݣ}J'EG"[|V0ؕvvv̥d$b/jef9:N|-p4EĻf`z⬴+kRHAC٩C6 $j)2z껋;q .T 9YWpO"E r)m>Ӗ#[N4XgK-,vVEx̮At͖)XccT\eywW+ir}sCg2 dX Svw\^ ٚ'uVc N2 r{uĸtB5R񡕴d.7՗!"b9j/s(tX\cNZ\6%nek&*dtS.:J·Z1#Wx2V5q R@XcnNՙp٬d3?#)њ[̱6(efп\H)&Tϱ5$9VY[{GAB\J [Gwp+(^^=E762hdYMMNҳ DF9Y}BlzR"ż#멂vz "+нٌ2WSo⚶3jYeQ sj 9 @ "lcpjsAH66 l"ZE(@0W e  P47PwIsAM"Z lEa@@!  eP 74P_ ՉTW$̄i FBhSp92Ct=(Nq  zmz]`Z]Sal=2kBaZ[Z+#&r5e奜_zM0斀aUP&үvUc)EhjvX1߰yN42ĝ)K.E6] oUJg+I`;-7XGӨ gnzєNme?0`޲EJѕ*#d2zڌ!1AgƬc[F &+[o0Nf~ QkN,*$[.#ކ7*r2ة_FvdPNKesONkz40rUnztџpG3FpeRk֮F21ҮK2M[Tf#1֡נ gFr zˆRr 1ޭ3c߸MȍW_j?JaqL, qʽtԳ_&{( ޢ6LljYX5D$ZCE&I㏫jZwVȖѳ9wJ-yF#oSi)V憀՘Hj;hȲ)TS :s%t 9,µ?!u$)di_ 81iE['nĎ65g9cWygtUAGн$ xb[ HCQs1@R+Jv֏ q ȂAP8uķ UQ^xmRF3tQY.kN+o%aY'; Y EU~$6?.e#Nm(|.Ej @?Z中3I!_oDJpCI*ޢ3|~Ͷs)J%4 N>WӶbA G[cL O~ u8_&oy51\b}$Ym\0V7GI hĀ,ߊ'v*H$䍎>ۊ2h!Gkz)eUr u UHAAyd1YK\GlQVК2bA\z3ǜhQMĐK n|ᦖNd*HmJكZX7OW_o ȱpR1J.j=KgSYN pDJ.gk=8 7lVm\c,7Gq]ZVa(g*ov;f MqtPzHYSa,ep<ܮ„ )P렷-G~L ģ#jbd3(0ygHն&$5Ȩ(RKyߵhێDmcTD5u|EY|V晥2 *e=1Q1e\~SJ:&"ҧԪqGY|+ZsAR"Z lEa@@  eP 7Q4P_Ezgƃ:UoRJ^mm፣ӂ *ء%'Y=ڜBA!YA'nW k䶴99G|f;'ey`ާ"#sĖsA, :,hnӐ5!* i7ۢmuhF(+^#? ▷LbU*N6#(;:cW17ybDd9Ic[97q.gՉg;t  5qq6,P Y.ْC!Ira@5L95?Ic!G($)@W/~%u{ zE>[`i7$UÙ乹26z{ГՖ(W;b#mIKTqvo ]+f($s Hl9xMۥq 'j覂v&8sYH$*{ص&lh 9ҰעV+ j׀?,#ɐU[m6ͷ\'oeKQCɶ/crHӣjΖk g~  o[m{ih}eP>VJ8bzU3pF )ϾkcVrg p~I0񵳷7 '``W )FNFz} DK@5 Eꘕ.͛E+u`N=HSNV.xR^q.-* cewH)Iٜ¿&'n,0%- ?r6/cڈkĮ o1>9TlvH"C׶Q߃n16w$f⢩$#$بcq '#(:/F2 XтcPb<.ZkegmHаVO ܛ{q%T}Ok8{~P?h[X|"99S;z8۾3ChVAАj+}.z'eq^2im2>j-Wo\nH ֳ 䳜dn]"_I( sF͍ JUReXmJ25YfONQY~αoNÓ<ȀgiDRGLvF }kSE} 3޺-^|<oRQf"XxD6tN~sE¶ 9Qpda&t$rxRTq{If3p*|m6P; ֽK=Dc)qevB\ %/M[=MI8ߵZZmS.V˟8zojIRE-f,rZFDJH?ڈ|Id~&Y\^p7ZI"CjsܢYIͼF2jӰ7JFJϩHfib\F3Fr̳ V9;uS}hfv9ŽnRi6u:d{VR6[ u3 )Y.&2GPh \]:A/7۹nZ[lq$jrX}ZwE6W3U,;5ۥ`!8U}jSoiq5g <b:D@:i 1í!m".1dNi4ւxfY eփ$8&U>Z9R #1h*8&U6+ի@?gq*M)ˆNV1*Fk'-TA-'sKImm"bn'(=ֽk8U !Ƒ\Ģیm̶vlhpQzH&n DFzQ@LJ=!NEf|s]tK(ZH)Gg:cVb8oէK*΀GVHOE.c602j^Qd@lǽh;ZpՊnf#eEqҹέ$n7[3`^GLPqnV$v&~":< 2aH$\)Ȃ-+8VIIBi,Ii=st.#w z8ektvEe_]qs}Irf<0eVԫg-xe:yr%ǹnE0t՝Oo$ Vi9hғ38 ïH3 x.滌AS!aLV2-Ғv^ XH7w&#)-' r$Bl힄K<+EKH]l.+MhQ^9%I# P$$O4'ѓq.ʒI;R6(Yy.cNs]\*K2HZҮ j,. N(#Jq #-!c# dyY-ʚe:r]KÖXX)Z/6FC$RYK(?+~{hb\zCQsA-]66 l"ZE(@0U e  P47 mP`OIsAa"Z lEa@@  eP 7 m4P_N%Ddx`YbHa1* JTscĤH&qYw j6$FF+!'?ӣ]w +KDQ)KḁD>?^4mf$('&Y yR!W~l: Nu)ʙxۤG:[9זy%g|H9h13joHɍF#WEZ۹6bQM-qDJ!9Ϭ9jd2Z2PzW_4-+߭_,9(nj;$LFP\3?rqV0cc޻6B75Toa ImY{ 4qKq7"ZE5-u:XΡVnK{K(2u./o3[ϰf>WT0MEC|V_@$98q;V.l#('Z<"nb:)Ŀ#jG3Jʻmy\ܣDMw@T7=떍b5R9'6ϣ >$oL8#+Qh9#rvzn!g.xTN }Q=GTuSLr&"#)WLv$vXu</@ި.B, >*фTX>z[%yn74Gj0ؖ]QC a^]#jm- O\D4jvO?upIwar~UWv>49L ުK ݶN 8|RDq1j;K-0p[v8Yr;H-"V%,@tPtq":m'h&ӫ ʁ2F+Iщekz%]qd3@W>jbȦ0)R0zVv$0gp0\1'aڵ'8`ڽ2>3K!iFʇ8<6Z1S-nV41A2#0h``驓mrN-ƣoW@q GC`` pŌsAf"Z lEa@@  eP 7!4P_7LGZ7pX? [ݭ'V|/jM\4bB6H S2CFQ`v#aN{xK(J?̇Ԥ# ^Y+@5\R{$UPlҩ E)5"0tc_̭zVt]G$.d:|^G,+a ؠ9`qZ$Qa1%Uwl%9D8V21'b OaRTq0#q"Cp36i8=h6~Cbi.'1 ]*:挾1Iܝ-qYe$k{d"A"Lb@Kzwj=B7^2*۱>+Zs& *a]q+ɥI(^;~溻;pYP$jֹti: p|1]rFŸq-SAPYg KO`]ޱF.q,t;uXKdoa'/ER(C#\ױ!_kvv#g8x[yn{1 z֟Ć;ꄂ]I$fIn *IB9qleDJ0I=s A; FYKȣ`[۵5?KㄠR7֖j!+&昌'H@|}9/ nk nY?j..h%ʨ3ʍ݊qލ6/H^M4PH(; !nC3Co{x`v܈zb (ۥ*FdLVRڞ,-1`2Փu`ܨ՜s;iZk8HbPsӒ} h6&@46+#*q(= "ZvbHZD`z%xf`XCA? pJ_k[in;%äPOVi]04p<AE0^R" <m 5ʗ vA\T>q}$I5W)̔{; "PxF`ܓ'`E$AUA$Q_bf/*F9!Hlݽl{FI٭V`lZ;$ pJz-8gUdbSOl5s~)V6W5j4z$bN+dPa(T!p:SG#ƝܷQ8۫ךh sY#xUʮ]݇=`Tn["H N|@:bUM(KYqV{H!UeV^!9PEbpax#_Otˁ]W<N±)Qm< gq%Q|\Iǿ&tܙyxćBSF#|kOLvt\2MLn*> QIr\DjƉc%,q\i"u2`&CBOV58jf2w;Vz좷d ے,]2?!sж@S=)FǦv4WL6W)Si8+B2's +Ǖ}Ec:;'UvpF]Yڴ8XLaH#D#$]c'l‹[$C01\ܐh#*H$[Xd p 8d.$;t^n E N|e sAp"Z lEa@@  eP 74P_lblA<&S )9\@XxZsC̻>3ѼP 9g 2> VM#ҍHXJ=t4EF,luz094!*\@DYqR2i<(kK'zTdirnhTL@NqTWn);\Ɔ 6ol?; RGHm>OQ=H5|&g',}XJǧ8s h8qAb a59gUR]!f:$#$xz# Ci93*t5ԭu1 3;ںgރi!4.5ͤ@*މS/%x W oLB@v>+k攏[J;WܤJޓ#'UR`;Apϑ\N;j\axF2¦d>w=bsW;K`Ȏrs8ڈ:m:C{A oj*$P&6 [1amqGVZkFKj1:aj<ٯG"k{Bڇ Q]'{mONbEs!Yg*NOMbO&Oo%B(S럥zdw7P {1=읎OJ9),@H-%0{T*z5<Ҹspi!I!HA~bqHi9nZ|ՖBWW|P;+9^fl]xHRi?4``A]-eJѼ}#o)^բ@L7\UwQϭ|n+Q5<(ͳ)5B ' Ƕc&T3!uo:Q1[s54w1ڑɦk䕖>HArh!9ߙLJ!bN8޵(&ҢR^A K!hؑAFAաЫ3O`*|tU^s%uFSJ 2(|CE0BgoGAϐ= ~P$4pB3d2 FX#usAz"Z lEa@@  eP 7'4P_%F})GR4j*f犩1MI9=0skFvdg{*jU2 @ц dKTT6Ga M[ Wnp tT7Hv`nIVK˒-:mA\\ʉ]e 36T8}RLݴj eXCր~H+dO>LgrJ ٤.fa'bUg$jDoe뻉)u㙮 k'5o4Q+tZ7,(cIEFw7#$ w `{[3wFKGY8;Ucj!]q9A$>߅Ȣy"6F{S>Hc_q2s ւ:biX'6 ʱ#Ol7z.VWb<#Iʍoq9˨n>v.A+<[*6yj#A z#H ʌVUY0s$Vt"c$)hɖHRT%0Hhi5zFUI2 ԽCCuҙn|9r毲QVt!]Xn@kP DG`ЉiCZR]Dp|Bp6rSG77̎D«oM7)0P@#!WHdd [OMJ<qWh|iV|Zf `BqdU 0]1m),]8/+|jXX6}訬G[ۥ5) 1o4D<#B5.R(YӢkP*AL s}ǵBN% m*_H{d"U]bzSPlvY#cGP&}(9~@  BsEPNr=YXN0$Zz(ڝ,X9 ICM$Rmy˄9ƃ޴mдNDbm)&H_nXgEw|MDa؍а7OqSwAsԤ950R1>qއYIWՌ|YW\KɥL\_,z[Ĥ$HAX7V\26O~}kӉl;5 +&Ò#:;itm `֊[2zF`Gr:Wi_!8CA> 6Ĕ؝⸳(9 *i=U HZTgoU,j;KgWj&P`TU@wapdӾw`QS7KPt! `Q#-*ozK՟9KϷJ> sAz66 l"ZE(@0R e  P47-P>IsA"Z lEa@@  eP 7-4P_*<ϑFS"401 ަ(8 4BUrvjnw21UhqQ:0N; Ze@ 72)3jx݀;vqP4n5OP4b6YʆPڰ3.F` DcJ(=Xz,=qSFIj,Y{vЮ8#"I&@~]:s[Dz2>d0G8bt}Q@$d5b Fr+ a`Wѽ*#r("z3BFWs][Ha,S#MɎG掑sBEVo'5lvM9bņ9s-!@=3sqThU\:SkU4s$3}i QÍXR)%j&I7QCK}*vC~pk-ѹt%@z%F_M}f}`2d4@ &2WO [ /zu0ޜJtߥ[D:QsҨ9+Г+2*.Kb[wb"Ȑ(l֧Y,6=1 5Q"V1,NŕPK$S9U[[Gt ʷaT.3$q3/-'`\NNc;8>9"ёz?CGq 7iZm27ݬ{̩%Hҋ =1żd1\$R./+.lI;CDT>%:# ֬t,nZIi+i7PIo4FLO4F9'V835*ڀV͕Ԯv52KVV.eYt,tz'g7[7ɇ?܏sYuK;Vէ{_}!qtu5>#qHmٝdֈ+r1CŎ٬ʏ'|Tn$4m9ERhHxFN7Xڶ%|U @}FN\4.!',F[#Y:H}\bbD׭pk'xqW\{ԗ9{F9yv:<֔<" $v6@6{𜲅9xцbi:V ue Tw(iM(`g/,E\gonr2<щsV;d1uXm؜RAA4k,ZMf=RH|Oҧ'%qlXi>3Ѥ⑋;հ,\cpjls4Q&=6oEDA P N&cslrS5tL8rЊN1U`ȣnٮђhi^5,2kP چOV-q*$H@ P9#B<QH?ZݪJHԃЊ*De% i`zfBхĊ;b0 H8#K XŒ#N&FVJɦ)hg[%ᝎ2l:)"ITp:CSgp#j\q3{Ӳ[7GB "w`i0jݱ=(i'J. %$HǃNJ`1fke~H=7 T,P\( 4zVL&x^ 6=:T\9XU573! 5bK-֭wԶ5i!WL83ThŹrȜA."E#OmAN_Ac|Uث .zT)BE\d1d{TIrCz6Q)/5Wqumބ\njIǹsh= DOWGkY%U\zXn טmN50՜Vz)I jFNjKj߭YSjo2l(iYuŽ7&Vh؏jt2ImY4[<7ԠF95yC[ŊZiq\K ӧIH$76T:q5(җҬ1&@QDz|S4r5zh,9JߧZu,֊\s;"D8sюL6Й|:PxV bBtv6KFN646v;敲f_4PT63׆bQrFWGq*rd V^p̧ԾH޵ƌf!uYXm8Z'۔'F#@>mKkP "!j0KnLſ2F2=GҶCG1"1QfV^5),a|zz ^XE΀B$gU}aXf&NB g%lΪfdk4(QKcVvb*F7|kd4P_Vj< Ip>=Z}})?AFحcoՃjpQcݱIEȫ/Yj%̂6 YF5C -܁R[GF6r ,|:tK]NNNzk4Vy(r@,,Co,F㞎ṫLUptt GQZX#6KL`+ٖ#!J R@U J6Q`S%LpcW/R) !#fKkvUb4>lŜY-_U/ H9qs[xٕFe-ޡ;( \!'8V[í*GPwl(5٧>mnO(a _-@B3.2sڭ*(Rm7Ę(ɨ/;XgiƙYM ҹrZEep:pP7~x>U&AQkP}+_ǻ9erq m%wuNbTy5wƖBA4*JEkZf^<愛#7B޹HfI6I=J3Cg.Js G/̶6iKu\iTwwFyXP%#`*x|ᎻVjBg Bc#-Vx0Đ"*;nH0ziVn[MFT/"WΦZAYHDpORv1A}w,hr%ړOV+T4)4 Mަ>\*c;>GZ%(Upzح8.I\vWBِ2UͼK`ꨊaK,lT [1SF}9Er`.psFr0Lou%pρA+.N:RANU%`af@QԌ Ƕa3▙9E3J)Jib23@27RC=69$ҪYjW?Ѣ;5D4Fe_V $܎bNzM lz0X΍+=~\f'RHQ!SFRfSl7#֔i3fK$t9AgsQ8˶;f`9 :[emE-㛕>ggr|AbMV('-?phh:KDTʬM=ÃH@+{UA,5ŖLx793EnFBA Ș>vLgYRcEInUTsQ24v?b=Xfҍkʌ|U_VcalT$Ry*qڢ I61j>lltDRcKx8sG `{k.sAΘ"Z lEa@@  eP 7J)4P_]a ƎF{fg|p˘@)w"1N+:z-clŗ VǶ{ ՜įEܚEdH)A4 XcUA2a\mܝDQ*EU̶$a` A@~VWXS1RH[aFd2H4qw4,@_sC1jL䅄9]z7B9{cU4o5\ JhJ6&S`XgJ_De/&s䞕L{Tѣ#S9 BsQݕNnn#yȍ@fuLGdg>Ir(֤`?*Y9cQ83^eRep$_*U[I eFUB,&87A @,Oba͕*MmXdTQ=r|Zr%pۍ_[@ i Ċ@ [+.Fl2[Q?J4EփGzNzY#.cFBm2n`#ݔI &Z-Z@Ɨ T b#53`MobځT88ΎAgQ+ ^QB*P:H99:bʌ|iYψ/Pt cyƦ;\}+ab:Ir7@@ZNL~t|Sk$&dpB٪c8QYefgDJzx5-u;}QmuHʁIP;q-a߭VY%k0j0uF+d m'dfma2(sZcosX9%PTSV ,ұH>բְ'\j gmY=C[BN'کC/3CLRxIs|*9*;;p+)nwc%ę;@UY< *k;A&EGTEA199Ha=O ~nZN>)"8_ttvNtўY4=DiYp4anwk^cє5SӽVYYc4jcZB: ҦIdz,1G6ܫo{PP+jidr>R_ڭRtXm*ặ㖮;}VG.a "0+";m¥#ITTlM &@GeX.]b$x=*r޵#rUħA!4_T Lq:S`\A1W[/N"U&adUp)G ꩴ9h(%PGM>fsA66 l"ZE(@0O e  P47OPIsA"Z lEa@@  eP 7O4P_LT7𭒲ޤ>" "էᡔț7>+@!LÜ$e#hK*ɡ-_M ad@V852QYGA<̓v2JYCj |1|*ۺF,;}YdW2GMQeV #%z44YےĦNqL8tR8:oVr׻bd$zI]A\Vzt!!wmYUk H5r7JV QШS%أ=fFXdaF7,#=P$m[HaPY2A5 ]95n*4^Z2voW)2@Hyy&w*RC$'2D^ Pr@7Uz}>*K nTdIY]aNN$+zQ[Op&X]]98LIaϑAc\]E',F8Cjc"r4D'OQ<5݈*$m5U e6$2^\+P(EE2EHw5?gM1$s{v[3K=0Lji|zDE\E ,YIӚ,7ltE~++AÚc y -Ɵ́|Qao'V1inGi4y溨޴NTZgn`a(s;VPdw2<.D!\:6N4)53+\cTRZ`I: 1lvR,R Aj^b:A;E VQdz`o"^cI9E m<ȧa"Gu8աѩ'}C N+7e5$F#xrʧ$zy%NHm/b 8όTn-ZpNj&BLġES BWޡX76rQQ8SץRrGފO# 3KVð< eS$*1vJl0O8+#e2jU S]Fw03cpga Yv,C)27lhYÌE? *Y$rڏDL^M!R>(sA"Z lEa@@  eP 7U4P_bc'RYzbu H?A9EЫ#~aˌ@1b fk/oH%4`f0ӷYh:6}F8]Te U-stES$"eM8 N+X"ҬXbKŌQ5Զ x9 9v] V:#jT 5t\l] *ζsч*6BNN ԕPjqJԠ HzdBXA$0IH?\lhN4۽: ,Hv I ܝ bNRj=q≡D#ޟ#z ``fwUϥMyHU*:7Ct@0LSK{t#DH:[#Ay9j(sl5Id_Yr|j1UE`H. 6rulUPcɥ&sىXrt Bk \F+FQs1qgkR;(m T#/ݶz̸`DXZKJ΀h*N1j¬Qs;DI,~(Xꄤ?8W J]w$h4+VdTGgSiJ~k2ãbK nb3?1;֭6pCEU%X2(=5dBѠ&mVݗ۷%ͯz\} 2*^pH(sPqiFbW>]ќ- 7)- P5Jee( j)P{zPGRPX[$lF5,i-mRfq˼aZ mNYw?zBK(>:U:ؑK:msA66 l"ZE(@0N e  P47[EPwIsA"Z lEa@@  eP 7[E4P_ g 9l>4,dUQmepl6뎴-]O?-ء NO`T;LUhs%=:TLH; v[yr3L& J8=sw9RgYc-RhkM#F;RFqGPHI vp6#,IMUW%RzO38ҞKR9۶*E$ F(#Ӷ)@S# [fgGfx6zʌYlVfMnG44)rԲF@b̂.NDp#'Z>8'Q3lL;N`P5 Daf|4eã^W&$rGkiRD+{k+F Ia(Өn ǵsH쑱E9:w Oe=*2^#B?VFGj-XJ*&&рvR[ LOIf,řT 9I0cLdjϝPdW z:BHٗPHʑjB%$Jax5٪L7YHђjYܲoU 9+;@Cǖ':d(̬DNA'ҏ"e3s?jB*ǩàHN;Q:*vc,Xa7 TA *sxfGlaՓVH!8rW#lԚiTiTqTQ$=J*R4nI.ʫ-V# \m$s[G*rD}٦D*=(N6ugޣ5̮>b3EŘ=vEgUhD^2&E]oW%œC=BGW]M>U -4k-¨c_'AF82-t&j2 6.F>j`"Uf$k 9쭜UGw+ `Q*%V81j16^` [RAD9=FT$*X ӶT` [IjiF?t ϳ$˧0/.r12⮆#Aq`6d;ԤV#V\>3VGfJ@eZE~ȃ`hev+'Ueڊ$ĪΠMJ 0r[MUCEa&Q̓#NHQk[Š1mK]K ?.f&EYjrˏN6Zp=3D$'9fR%ftpힵ!2[4`sAǬ"Z lEa@@  eP 7`4P_xOZZ=J"h@i9G_qW(~<+D-N}oWC k38$lu'4j[+$ek 6R.|jŞq-@6jk S-&9G.Dl8ajeZ} ݩY^Eg3өn=$Q2,WsU}Hbhݴ|W0VFɡN)$ک[11J%Of6u*tUܴ:Yu;ڭhQ)`9T&tkވYde. A#fg'4OJ2c'pmm@,ZY}Y;J$Oʌ5%!ҍ51`<ɲ$H A9b1 \YF ^Im@=AyWrKeqXH%'*A5nkBW5)KnoQߦ;fYm;]&Y‚4\W0 -҉4=:;gh7,@LBɓ&AbK K qJ+0۲TEBh$dltu5_3nz޶Y'J䍻@ՠdM lsZ `zV 9_S#ϸD'w:J3զV6NJ1'q̸U׀03E^v_Q dru`F3X hCjhՀJ8-,tT84>*PeUVgm(UG. >+F;=2+,lq{U&5p  (dv2ꗘخh18ޥUq\(OlXszH2n=O&@%NM_"<*}8BrtzvگOᆦ$hZHYa2ˡ\?֔m|lYSjH9Ց;'_e$JZ9viWҤHDn Hp>c]5{1Q `VܳZ)cU @=38/vfF*wLy5i!y8dǶX}&څva_~ HmT\3J2HcaEdvmGHπkЄ泯my26*Yr`[@ iP1YrKmzfKm`iRzk<2Kd@*<ʨ$V̴rJc 6/pv}Dvx ۹2 rET `ҲN,z#ըR uPmMOtdSzG̚r>=sBڃ`++#;շ%M8قD`^8Յ2@*X㳑xTbE:P{"Fm 3oV' k bsA66 l"ZE(@0M e  P47fPIsAek66 l"ZE(@0L e  P47fPXsAt"Z lEa@@  eP 7f4P_\NJx"QT.~Q,Nkb_r7l{T%x$!ԩC=k[i*:QЊkpЫLH V.P| j" d*dw m^b!ށ9H=BQŘ2=+Հ("iIH#+KR5 ՅϚRۺ11 9Z~"x `[kfEqJ%!F\1C cȠ15amz\X6JB`U[\ox_PT- |f[WXPDH5ڵ$+H8/yyb{#LT X`FˀH?1Z *-҅MF )@0}PZDsi-CiJ C2 6*@r0B$ `7JT'p8HH5i[QK3:{Q[m#j G& V/Nzj.'qW*};wː5.F?JE5m-N*2D##Nj\8#"H8؊EF$gMXc“abϜ^Ph 'vcTУHiWۮ1V F\xȤ[C|V\鍪BёE }qN% vС;S;iPNT6#ޔQjw=MN4^DbgO9=7<- ;%aV48f)D$uV\i U0:aq!"hԹPqPdC=g{1#6wMٳl0)>*5YcOJ@J+Z@zSV(HldH6Jǟzqmp U'8 frqR#+ӶjfgXsusT186 MhӲʠcޝf@+Q&;zvYcePrӖLg0S֡# vj}ge*DqL  RE3)V\7fP j6!Us U6Vh.C8v*hR8+.v`ĉv5d<$zJYs$Um0;?Z}^ aFLaV{&gIc )85oWaԅӟQU2#/9UT@ '`ۏz*¨-&$#a9C12HztYbٶRI?:qF٢rfCm`POd#G"ƪzjx6ﭛ^ERsڪ4RsAvy"Z lEa@@  eP 7la4P_!\ɐP.k3-m>*kw ec…ZQ-ȍ"e'?AG4.J᱌wm*9/YdWy` Ԧ-S[Ãͻ)TTXB橎ina v1hy$n$bF6j$Ň@rù,S(,ic.H/-$t4dVRlU*J) o C eNoDrƁ>zި^fj&==qȣe9lQĺלd`{c?zl'bXUgүd*IYQz;?,Fމ)qY-ڠ[M 'Хܧ5I\^\C(\o-\m+w&ʎ$l oRį JQc>QYR3I{)J\!sr0Ҍ̱|.qM&%X&HB}]OE!{}iGxܤ]XN Z.b#m;1'3HW'gI-y&T:1:6e@|PGpW\JvmTq /zc sj.l.bcd@"Vv&ח'HbsAktN`8*Ck2>͓+lg㰸KaިTlAioeL.WUٹI@{TL-#ƣOYKo$F $]ɍCy#A.2 +֔ k//4`f "C,@Pw(ı&B[Nuh,sk#0X0.5>LL!U) g"%ȗ9AG]|FXWIGV ~*fJY f$Ǘq ];n6j͸cx+Y]d/E :Yn-@nCc»6%3k1\ۉZKXa|֬ܥ-SHEf*>sֆyb;meF;|U.Dm H(,x(H~4$:'Jz^wsx0*ێs7jzs 4ȸQ2<۠Yvw `a\s#HN*l,BP|PwFխNuCh֪mn6X>.Vl F+x9-֣$\ɡT*~<2捞tL̟Up[huJ!Iơ%]0|g4K0Hcsw7SH}Yέ'#Z)nC}j BͯS7^.xX`#hSRzr6TsAy66 l"ZE(@0K e  P47rPXsA^~"Z lEa@@  eP 7r4P_&-ġ I5w)02p@Wx020ā!r:EBUܾvj&u J ~l\FE1l4h >zr%Vc5liS"  +] WG\Y5rn4s N[PZuoCr$?|V< ӡ[;d9LUili} 0E5oBKrR!$0\}Ǹ)dg ʘM+YQp:nGƌQ`+3C$epHZ@8Pാ=g'Wǭ[UBcK::i4l 6s}l Z;}jt 3d7d7etcpz{T3FHHb2OR)™FA#Br@% ۭT]'$!,1(uB7Ad`Xaڙn7R2=!*)!0\Y50+!:sHޡ -N2* Y#.4HBXmLQi=OzrؾBs J_F@/n'TiD!֠eذ(pGuФg|m+v#ޭ P;PAoО˗R-er@"@djX.K`4~\ Ԣg9?ZBVN3%xx_QF1#4piXʜk=Ql#dϸ$˝8`eHTEr0bcJ-P3qWDNqB'm%EQ(DrŰxP&reOaW(Sg6n$Vb9ػR\bK'fuE拴ٝ8\zHCٗ=F٥ xD`\v4BzWIAiA-LRKtlR1C|ҵ jNF4Fߦiŋ3UsӑZ6%ՠ CL%>Rvʋ"8R!C%FAP#lQ0s4ӤoVg<j,{1DMmP+5x}`VF4UNAj%Lj35>2s2]Y: 5B Q1@ 3Md$KR\mTKJvQc Sm &Gh硫#`\nlR+h%ARuFPT0ib@WȧcB9I"<|=ELMjgk>}>COsAx"Z lEa@@  eP 7w4P_c)B"\O$?Lm"k-N1z-vqK*KDйN3tiB>'9y,S1XP*8!#@PLʾv=kL2>tVH@b\(#9Ek\]iDP;xv JDBe.+=IRjmN=sP($vUis $/CC4vFc^T *qz}e|J'&h8&+D7nxded$Hnqzb2:H[4◚B:7ZrbVz0رҭY^ۢP_8q rɸvb+ iq$БUD+)-;ޡ\s!;AGC<*A#BՕt[Ԥ : G#cӕ,9h  QWQUe($ϓJߖ[HتHj]R[jY1Th¨jFKS"鑭Bv?J1n|!&dRĀj#D\JR lG ILVN Rߊ&L=+)_(rˤ⃎K ]XcҐsgZbHW sJ+%.zޅZBL,.5D1- -*9= $K΂6ƜJ9߈ETD}K QʹƱ[ӡ4:W[Z4!/ -|}(9M:"B9U-`XYsA66 l"ZE(@0J e  P47}}P/XsA"Z lEa@@  eP 7}}4P_9RH5bE 6ܩ4"樳B'ᬧKq2]U+\,Iȑ;{,aDtf v*Sok ̪ASJ-+8.&PÎތR*]@m{ [L "Ehr8oQtZCw /̨ ~#+Ƞe:iPlA,c׋sc'p=Ϛc)gUKeִI{ VI4LIq7f )C.#]5}SI,,r!Q p@OQC:#UHlh^{Wg/@ Fdcyڡ';T\7r]R~ԳƮ`nhӂA?AK'*r=?{& .."P 'uoṛz&ӇXCI8jbTYxTce) *|hutX,~cֺYxhw;)ax\zK@K5\VTF@Bm[;FfQ!DѬ/2@2 F$93A54ga'GKm S.B3ot©EpJ+$LT(1R ~}1Tu 7@{ֆhj#, )J+BYX`0߭\#bK]j K$scRhY0W;T`N@=6{JEORF拉$l1=*)R7~ CՃAb v:g7٥d.ڠQd4䟗2˒H4 eT(y*rܒ|T%"L*:c#_-J79\ 2lET6BY@9d2JtHD2άv 9vMp3!,NH#N==jv&d, 9GMlYmuauqޅxzBGͱVIn@ QX@qEQòSޒb7zSy=)=Ce$oU#%q;ư&4PIɤboD[v* [g;V\F 9]cFtQˌz)dz|]6J˹Gp3OZmlIφBےT lL.*H LKIX 'HnvϽZLp3խ4Jڸ\g!16T*4.4w\׺$&f>sVIcx`koŀڡ \'0L Kj?E#rlsA"Z lEa@@  eP 714P_&zGɥZ c%I %n5j !2}'Z"@șҠ"qC(q~MAkTV%G֬1}yncsnSå-ŊZ 0=n\):3ܝhVuvRWMݩE F1 L6$s 55'r*“TA&cYRECCyጓ?@5TIT$!_j(R3>2)fYXcQ殥M*< ˱ BڹҨv3QtkӅ"9!էNERĹ +YwJKd s6?]1*Hܞ(sLFEW0*LĞTs P9 ?ڝ-+:ϵ(ˑH"@ODKX-XĸbR utZhXT1ΑYI)/ilƔ-UO=]PW`\GT(DI7(pCŔѢ`}"ٹnd2R(YĈU6^.)D' 1*6I\iDdXKTg\\wFKu'"7scP=riDS;9l$g&n}R-p5aqn"{dS01 O #Z1 Z^h!txȇm\l:c3r:í. Ĥ՞8QO/hSY)#;ӥ,O^v>u´,ɰ:!~k2Ʊ;c|&Yy[^/RFڗ)xu]$ʀW$xu8ϖGrrЮ& !cWb?vHvۘB`Z}# )xӳp?G(W<HZ!^jC1ҷ o8KsV~] &p RE$ ,}6`]$cWF b;\h̖ù56FPFpjq-Č\!e0V?n;ĊVy#Rgw O۽Nq4*S/(^*X* /!nʣQ;OĒ:ēU7%5tĜ>KN!?PyH"[tk44\-rBLŎH%u l>'7wplP|ʡV,{֗W xgX'`hmp/ +0GZsR8mcLGٸ*nuu󊡸%LT1Ae,hF;]ְTM1b"S,FTێ80OjPle'Ԭ̘'eIҠJU"IcԸ591JD0W;PS7 t.Km{5:ʒ~jh L8f@V4H4: m0yʱJZCLޭ"♎cPr{i0>;!O$ʪD|SB.cщfIsw#KTX˳V"! od 6ѶAl 9B8S!*Mt7v!@zRdXeC\{ tKo%wտ=(0TUldc֑ѱvTR.IU,51 ёt~\*vPj3,R /Q{B+2N[p3e\xFTFpq5 QK#4o#giVU\WŅ(N6w>NAsA"Z lEa@@  eP 7厙4P_)n#ڌn $0&[kv+9U۠Qxe ݎ^)#2Ḥp6X8$&S]j\ݳkFKek*IF=UII5mDvi|}sSKt'&宏G=4WKn[?O;)-é#7hK,d'lҡ J5Z0QPa.&MR ilYfS*fna\c?ZL Bz$ncE`JH 9ڄh͖5$Z74ͱ%A-$oUl H"K*`9yb':oRtS19J32t+J 6zh8œ]Ǩެй`F:5nVu1ޒJIڠ-fȨvo9}e; l+Ol7q^F)4q RE؆BlVFoBypAuԲXanw0t*M"jDƸ, 1U@=zӅO S@qUV,@#L0/s/b\iR| lA#A[Q$#SLz`۝LI}QuޥHyڙefeaЎk_%j^5\#9 F[#5>٫ FCr{Wi!0j*XH9eFH}v^4 a_'>[>JSڗ4#>,j7oZa$,M\̘ԞHΖ'C=a՞ޭ eѸQFR.tP] P K+iTW bA#sj );j9l;Ԣ]XHFVs9;be ތneM!:bW\U&:dȦ] CP^jnUS(?SAsdzc8yF,x\uՠj6e*EM<z?1B(Ҏ[\72CbNW$cQVF IZI9UOZh]{"T1¶M8!g'`z!IsAϗ66 l"ZE( @0H e  P47MP_XsAp"Z lEa@@  eP 7M4P_*ՄHڡS7$}e'PzWK(bP999CjSs12qZ =-m)tbU N)ELdRbBVA4uC&qUZ\ݰ*f`N©y, - ghɆ.fG~lFJyj_2eTj¸E8s@}>q@[gs9j9Lwߛ!}FAt&R(8c)d2ԌsZHFoD0Q?1 =2 t\Oy5[` s[dTb1:476~R=(@v٘.9QANE) v;UVgfR.4ƣޮd`H}=(D S}xؿc k`Z#Hڠр@IzlZw'N⬺2q Cj9$ۂ{iY_[qQ gAs9qϑ @X>b7EZpdI 0E9i[1ɫMaˮ@FFWևHVUUqGxx=EfEL[.IDO$'B2TnxLino5KZ6P3NCUz9ց}K{D6ΦU//piD ]R+1K4|QMvDJ4D߫3B ·q@j0<;&N+cF5ğVd| dˠvU菅ei!Oa4e4C)6% F[ z] a-23B*$QA7:`(I ?*QFKDFCU[TYTCLK66hmȶ!BSe%IazLƙszت| 2XTbHprJ Fm|scܽIsDFG;Eśƿ' uӏQ#5TY#泌G&iӊђwh@b)u-ޭiH^άϦ,qUN}+Bg֜;}=x\93CsAá66 l"ZE(!@0G e  P47埵PXsAm"Z lEa@@  eP 7埵4P_ H27۵dzMi0 9Sn*.naU,RVTS3)+N;uHoC2ylzL0~.hUH:'P3H"'Wڭ Q@*8bcUqX=Wj%6ChiΣaгR{ޛKvU(d&G'#N:j|ۧ^-7Qu*5Z*aS0Gg7jǧlv#R4pzy6uV@զQ0qSE3L)ivt3Z6骒HZ4mʁP!{R@b6UeFqG4clKI1%SӋ@͒Evb`*S𑪂;TqƋ[BLUXQ'ڂ12V/,/.Ǿ٩<1cQU)8zK,[{iu =E] UCEc0=tqF1ң4<ߵ0CQ<09zNI*1ވ3!W T`I >拁mÁ),4D%-zbc B$Vw j}A}%BBr*E Kx@̻ J*[X^M,}Y+97[.>AácBAWsH^UX#WAަ! <?3u*$NTBHm?J.cDήY+8fhaIR#䶭g޴Gc$ltfacSh8:2AǜQbAobS`ȠԌS!=~*v.{Vl:85Yq-J|هlT,[eS$T^ުEqN7b_cK\( c,D}5O j־phkr }X#+mhcϗ92@?Jד.R EƄj$PɃr7W<=t+(DJ$*(fi\G@j I$.ڇi:gsLc0Oq{hbu>jֈ" E팓W2i_F@d(ylSF1VjV5 1V5.zbȉD`酰Q&_U━*?Gr*\P*X2s\{WC0@;l4W-c*YRh j&[ʎѼ3e>j sHjiƔACY`y^:́oX#zc<Ѯ0YPNo̸ޝLasVb2˿z `fRyRI'j<3ͻ!nn X (w "Xeު5lPd:j5H;أ5S0}.}$RURſsRr+p[s,<VK#%T;9;v4CT}IRA@Y Y d Y&LP0?4{`ժ5{b0EZ$ ?]W$zGUsA66 l"ZE("@0F e  P47PXsAa"Z lEa@@  eP 74P_NH*h&96Ű} `I8~`n#ڢYޚ)tSBKF;ڪ$䀙%f*u(Qc)D2/|IjFa=2HȫL֪6Fqg$dam,G\ԔL<ԅ7UEBPҡE]A·Vyچjb ^5fYB}Ru7`Fl+=qW,:rjQl&TeiNYXQS:`hi-U~uԧ5}c*¬G"f4}R$N|Ȼ @cDh 4j;(G}&SՏEf1^c]ugQS4[jeZ;I/r+^Д8 p ܁3|&cֲڐ԰+:"e&#ȫMT;*.7UnA G5tz{)PjQqEX9L w'LOuq@b183n2:m"'7{0ewީJC~XG;t"+{#JҨ88 !4{XH$>GZ䤬:1  ]Z7@qTxdSR*- k2cEV 9V+I-m1,A:NjFq_O"Ы>T?Ac>K![#&SnsS|,PM]*}D{UnnZ2[#h.G 0=L&(0{ H*O@O9lV\1֫}V` RjI%)J)g]T8U3a1֤]I~7i!aSYjR-ph.ʡtP?r(v!BBw"QnEKcTA:ZKuX=Y'uhc NB#vqj$(a˜f13GJ9r-K *X|})'8g1^"@a_Qit6Ͻ6{b/s @5WG+WD`:Klf3QcT$p)(,K0]- ]œ(6@M:\3ds3dQ\F0V,Y٘W2aݾ[^% TqW4zr=}-XlX c؝QGnSJ:dffAgv`8sv o*ivAd:R c gǥ|9īOZ[pX͊4@ p1Q9_dC0r`圬j-Cmca׆On]wjڭKfvȀtU1jj%FIc06b,X2KOޣ'"g,&+k0;/4\4`ilQL/ (sAv"Z lEa@@  eP 74P_=ʷv $.tj4/O&s;59V &@(ۢbF*V} X`p1qVH&|<&$<Bmzxc}Nhjd}ci;\B2Jz ŠC LchrЃ-jE%AI0MԜ`]G!L>VFZE|UFv p:S:"f1fYvPjFoY{SmaI!NHQݰ S.b qZP qM LG1AFE<v'7%d9b'.*CVpIUQCg#︨'9jsO֨yNlw z'NRH3;`mPK%v&続)`}sӃ$ܲG֩(X31*rh$Ң \j\'u((BTAa@P/qTPCuHQfeҤ20_дQ%ؓJ;sԮdډrF|feR j"W dگ82.U[v%n4-Ĩ֒[\JrVu`F]dˁYϒ T>@ HEܖoNjKU47"w H^"S5`ϡ\; r2 ɒۀJc`z2)bB&)nlhqH=դ-PSd S*Y}Go5!o"gﱢEA!S ){ↄA|mR1 #dRFKw"zձj( iI HiޣH]l~P&}\@1\2xz#Iom$ ׎nYMc cJLlN͚p\AگL0%GqluO2)1Gf& [T`GږXRR.9stgUG+ l DAE:iI&0l|Ul6$8,f][ҐArMV!SW(\=:EIYY2` 5%ʏPcӓNA맾hl`7"(#I®>YNݪ8\~J.jieö6 u+zNris 1'V JLNiVUlbLEԮﱪT`Vo%QՉ*kW}g ]#pˢep_ME00r #QhѰE:Jg94itJ pұSP@ аą!%)tU;'}ҎπiثHl|7@}G}XF85hdUEY t%jH3g JhTc*T8 $\*:ܜRHmY\jf)1^$i6&8WHWHc*- )vV0J#eAmPpc|ql!׾6^J)J}:߈K:ӷXGbN(8Mo;Qmm<%X1KfHm)1ځqPnZ4Xa|Eo*ȃ0ztdo\qI$ |Et B(ڔNJ$~S>\})㿙[`tzFX;5e4.P6i@:A@cP#;ձ7Ij¸y뚢X1a(nߵfWJ[1#Yr b!uO#UpI?ց[4 4xrWPڔE/Dx-J91ۭVJw(dqSm+"Tu,Fp7R!S$dt ԍơ|؝FȧHa ` b]f)j0IMjݬ <CF|B0l)AH+#FUaW>zb@Ta es0bJ=om2앋L܁0d}tHNN=3Jj4h$JRʼno`jqw9`b#:"v$E8mh휜cګĆ=<{DVG~ 2KoӿFČjU &9( 6\朲*.t6*GJ,-5:Ibqղ*@Vۦ 3\X=I(s-D!qvRa[N=ܯjɲP;.UsHJ3"tF)yB02ǁW@b%ce_,wiSJ"X@=,~֙rptl"AIcV;[:3!ɠ1ǐTܧH*6dbulЁZl`eb|j&SȻ*T-΋X|T hSM*S K{T JG֝& Q)|v{e}:ڏORP{`PȜ Vpqڣs*=Rh)@ItjڈR1ɒ98'NM 0.ݪAԯSJJ2񚹈.9T"\JRumj;56|AV@9hprsI g:G֜oWO՝gbwfbH*=tT,p]醭:{Ti;؆aI[ҢA#cߥ- Xh'ak'W͌jFx?CVW| yĖ:A̬*yG8ձ9Bo?"M鋚L~ojmHCu|Tq2së53i99 1DZONJ`0ۜ?$LojG*CKFAeu]oS۴K9tP!KD1\R@6CT8[n 4}DcFsSϠ4,J)fPte0*L4Cժ9Qq& 'J0HUMCȈݺ5A_;%I#ڣI R c>D$],w]v\!ۧz#P[:͐|\kbIȩ bqb0aաMk횃,z@ P_ \֩"j# 杊,`=L w `pDbf:۩1 6ڢ+4R%.㶈 #!2HqHw7H D,RNRGU1ٻoRIv8+֢FH0prJL3|ZWsTPq(BTMԨ{LN&2?(&~*q&r'鹿=j*uUV#Yh 6{5+cT:;ܸ3`*6i!Ά;;\GU\6O@ssAo"Z lEa@@  eP 7ǡ4P_Q0WpC}hSh8j]>8djϐ4kyrJe,X,3 w 늱\{,if<]JA8mKROj7q{a&1и]:Jd?DH[*8m5C`bː`#|C{Q  4Ԥcګ%259Nv7ri=e#Jɀs )>j>GZu Im N8$w yHPiM~NEqEsV0we,``8 \{b[|`Ӑ@8HBi"(bX\<򭳧'4'mK0>LL '4Dp`>A6Δn,`!z.92ӥ"ӨPGQrT^|A;ѕleW>6ړ3*SjTLl4jjdb|Z4xtɂ|z"mU-h"ڜ'"1H=ڭq|ޥң-Gd Cv>IS_l%-{UZFq]_- QQ71hۦ*q+\3l[NXR*"G=Z--8ԎIQoZv$XP}JbSAsA66 l"ZE(%@0C e  P47UPWXsAW"Z lEa@@  eP 7U4P_-VC^6Sf@[5snh'NU7oI5sNz#fڤHCJeM.Q00ebڢ.V;x)un7ւ9I•y;W0lrB=S;f2y@/LM̏ej8Qs;- *:ewCHW" A1HNV}ULDVTb58Ӑ|,ޠY;;U_^)ΰ16?,jhF~I<V#e6۽H(~.jF(*"Mee?RM$dT8݀=@JHSzp@Zb#,ޓ(e$)hE8,G֤mOЙXfݲ* Oצ4NAt932jb(U`qo53lvT, tbG?MU%Le*J4H[c*zT]qpiEVBFޠ?1xT2>Tzxbɴxؒ>4^ݍB@\I#?7ԚQyX/&Ų=M!RYa`4ώ%M=vUGFqPfE;H5,#>xA"nˌ=ĤaPyRE>!Ij)#("E'ȧ,Qrq]&AҹҌ?0ՙuv,?ZHpvW4&$YȨP|xeqH$H\g\VC), d{z8VGpF.٤Xzr~s@@/{THmӪi5}b?N9$KIVT,[Զ(-Qn`ia'&r$VLt,Q'Ez3zT1vJHA>E.;If;+36% V* F'qL%P\s*I"qS HcQ3`"zȡq1e sbwW+6>6+ڛOj>7;cN2*#t7^5KlV c'P;ڬ$iTAϜ\4ON\Je Qjv9iΜV:cW0oG"2b `.w 3֜H)aTgdMZUjy>⤺Jjr1KV6ҦIB+ޭDo;UNrtO&B9aҡKdHN@sJ`@`zsAn"Z lEa@@  eP 7 4P_|~:)@#) `jQhMӑo-dH-$mo5 AS遂c>SWiN#~ i&s+|~B: Mt87:dUpXe!OO'A> P.-PBۚ)V|cѤ{Sgu$#>Ӳr?Zߠ6O҆B䕎JO>P=AXq>zU&je s3{իt@{3IY~jaЩQN|Se6PyF" Wh%7FAr+n$2Tdᾢ }%“T;(L##*Q"qtf-8(&Nʌ4zX?mCC#fLܥ?SֲLI1qL0$_GrNl4NN@Ut8ވIإ. DY )n0I UqF 812dO?Y#>uRy6F#&/H6(^:p'(598l0"J[35&t+(횏3VS@Lڈ 0w'YrAlAsR[ًPpaCiV[U*Q;O.ҳB:Υ>sVE$JBM!;mXqV!G2⌎.*:T[L3d0 8ٱN׌OPj#0ǟmRIll#'\gQrU)^.w9J%/#. \+%RŃiIRVs}G=) lݤmr[5˯~IE'UW\S[%e#C5,L#GJ!bs-=&4:OB#aډ%pXsA66 l"ZE(&@0B e  P47ؽPXsAS"Z lEa@@  eP 7ؽ4P_`w$9&7@ɩ 3ޖJ& L 8$Ҥ| [GrZJ >vv(Z7R$XaUrh¦ǻ>1Trj6/d'j|APTlW4lc8F^ClY@Mˉ>i@sgBc5CDӦ3@7e*-wH 2j`gzMH1OPpqD5d[nǭ>JzBJ`*~Ի`@c␍ bhI mEN=z&  )zbd/P*U?nG!MPXmU3͍Nzb6=c}X #$\i4 w?1^LL3R+dab |T05UU3aKwoWm@W ǽV]a⩒G%Gm@ OHt;8d}T;|K7!:jRiWJ$T򱌰m $(tKB B H0p tXcԀhݢFSan (FX:)-j m`v\}*?ᩃZh$K> T U7;sAn"Z lEa@@  eP 7q4P_qGiN nJ⩞(A^ CZ$U3q $laMlui h޴?m脹m*?JL>EwO_Z{r6QBGuPQ89Jq&yu)#P71kV)q%`BED{F$硣>2wVۦ5\-I>EN*qH2jzrt㡨3* ԁp%\{ji0T#VZf\V:E5w-Pw5ݎD\U!Y1[ћEpŰ.|Z-L鏜7ޑV*}Ϊ\HdR K%P4ǝ鱠Y%3xqoҏaBJ!W%,dVo5js2Q(9Ć` XlU6ګ7!J$8r*Q=wk,gFTrp {ր** ź `j҃&HBWyLMӧ NԤ@g\jR1trP4)7 s3hӨXw4ࢶZEP)hS*J[$lNlՀ$W6U4ϐ}YR&GҜEˑ d)6 otWuG^4uW2 zBcӤ3'iFȠ"$tKsN^A w;TM$`zbc$n4'zLV13U )>άҭRd7lP [U45ic25hzfնР0;4w[0cjƥEAm⭦Ȅs+ q"GFsTtKF!Fjٺmb\L";1tN෦$(8cr>j0V@;dUH9NWsߥNA"! THZ@FRw4N `|7 LfPK(/@j/|Udɫv2E&rW~Rh 'GJB x1;Et˰񚅱ĪF3ݯ(f4GAN )PнN:M2'$IsW0>*y E\U ULpz楐w1?Ҙ ;45 ۸4e*]]ai>{ugpFPb)ĺ rw4IL=eA트Z,8e>sUX lcZ̼ޤjLr5ϵ"H$;QشmڢQFT;i9uVǜTst2vl`S+cI- ՎE.A֙qyedbWAЮpTI߫Mf,-."5S,3G2qAd gTzWkL-e˸sA66 l"ZE('@0A e  P47%PXsAP"Z lEa@@  eP 7%4P_f i̜HYUt$"A˱Ա'HwͲ/4G 67ڊ:ec.u5[(HXjsV9Xn2=CMj1o|U(,>do:\fPl}Ri;ԵRaf˖$1VV!8ɑ$6R}H23` crB)Tp(EI/c.Ub@!hQq0k}A9fN'qKZ=|zj Y -)NJu@5|Kdv7`|NtM1Ü92 -j얋F5}W:AzV+M *%5Irl-@Y2+!E :xܜ \K tL%e;Ƚ{oV+F>n^*6A@@S $۩"QPRG~b8#Ȩ4|YWXԹ>bM1(E(U25y -%Bi;6ޫHۦ*Z;ɏ`hfIQ|FrOUf[lˤ580BqNFeHA0Ed=8=vAفi1ڟ&{"'b8an, `#?j c pbNBď{b.Gs  СTdSNCF~Vlx4Eν$oR\zZEY/@ tǽ@5o"IONSrzӘv#}J?JdBrbM^q[٥E+ku"ZvޏIN1cȧ-Oޠ-ITcڗG{ !!*?RՓg*×NDV$$5=rcb>l6G#؊BIqR`%Bb{Kbj;-@jyI/+*BaAUSݛ\W`%§!r k#mqDżj^}֦"@~g{pƢ]܋Eo$X'HؑGR;S7%/?zMƬ"qKBv^jd!}#\uޢĊ+[%Ƽ>0MSq<{V p\gVJJ Y~Qq6**?@I,PK|*ISKu<< @kd4\u#K2f S0pAV䃻"-KD猕٘4ԑQja$R1.U*-֖(\r&=Rr:$ I 9J yNNTApMƮg>PDl0_gT:2PۙMmG@1S[1t붕5mUۮ3W5ܛ{Ӂpσ*o]%\ˠ[keU4WsAg"Z lEa@@  eP 74P_.w]1`RH$l6#jgAטiYE_6[ FvcZ2@2!TzK+(j"ķiJ%v&H1oa֘^(EiƜS 7~ CTeAEyRAFARzUsL4Ri.|I ?Z"]D5`F x4[vY `}j+,Xj;Ӌ_)%ˑS+@(n:G7#0qHF0 mH&Re[Ss|棨qqYYsr/i3Έ::o-R'*~SUж2H|R#X 8Y~?ޭr;kt- P4p@ꢜ&=A.~‡3UFRgld14;JMaN5p(N7,d+/4їcT[ r[~eo]BQ2lUG#*W|Ҧyd Y⬶T:D 9=FCNaE;үKc|ʶbf5U*#>eD*qERe-44kHCd5-SVNP*Qy5e>UU]%;I\yIn&r9ddG,%ԌtfI#0e Y0>J] u DgPx {iIoVra.~.3Sȉ"08l 2nQ<(i,Ǟ9Wκ'DQF4>oQ5Be)rb6A ezpޜġQ{hb6xyAI \oީg<fX;Hۺ̥}4h鉣a'ωAQ-?ZAC?pwncP<[Bѩ}Q7V̶Pl*raPZ7MJ# (UrMo̗$RLA쬸uɦy"l#'%=9&KC,K*#KڮTyRϖ}#OT뢐7(逳{bS1\!?@^H_:4 W:Al4#` J0"@AHwU|;ѕ­BysA66 l"ZE((@0@ e  P47PwXsAP"Z lEa@@  eP 74P_]y$7oc5 Eꏍ8uwjaDop|sD,@ˉڜR 'JIC 59phpPG(lkFOT['k%s*4IO$d`٦EVFp= :V66ՏlՠY5Fw]v^{nMJ"NzF!Ms=2rQ=%¯aVsaT-P֘B5iUjf!JtDX6gS\ @c)}X>jET{-dnϬZwX57geL@ {U5M%=(U ]]C*,λU8 r?Ҥo~QIn dG4R^>pAiCCԂ䚴G ?B}953 KբYhc{XX: ͖ڣ.[ku@fZVр*37֭ pwҧ-IM fvBwڝ??* F'Shʣ֙v"p鞙U/$v.4ԱH!ST0#udJpf1(?l5RMpPIهcjwI&4K-ėjbGڝRJ9sE q%27 vp] v9~Z^# @ņ%с)qփa:!WBqr1U4=u'ܚyoFUEaZrq<ӚQZςpjbP֠gy4ʤi;L& ̲0+C>G$qM[ ZL,rjPKef#V0䶆|d#rK?jhHV ̨c=im,x`0K(jOf)v]%g{ fHNSsY_"3v=>25bpJGv4ZlT~]Ye۷jxީ"I &0M[k#Q.vN H26ӟ  捣lRGZ8P:~^BwI9} Y{3q(i!0zL T&ZR%d⦰2F4jPu)+6?E8 SJ KsAd"Z lEa@@  eP 7A4P_y4eJlDtf^93 4 E(#(8V,qC %͔Wm4zŁ$}⊹ 6?1U\W9RXa^<8H?. Ro:Ն ,RK$eܖ(GV$NsZQe*+HP2SSs"QiD%⵲rAu#1 C&PNONe}IJ Kr2~.sEnFm6@k2mέRKn؜% CS5 G|TPD><4o4Ƭ)R!#tgKj  e54x?$ dTB6# ?2rcbdV8{%ˣRB*,㉰6NF|;}p|pEF("N'w4V%0l1׽NڧLUH o#J(2sE蒻`o?@r\0),֬ U9z;eczi8=9IFޤnk-6$s.m\|0wzlC9K:F:E5C:5%&\HޜPMrn`jSHs޶ -`XLKU!6Y(i,%QG|tY F{ob! c#0+>WF jr{THM¸ꭚI&98-g;tΨQ Ǭs ɿ91s5t/J.SK?ig}h;ߵ_@* CLO)h@ٮ&aoIHjHLJOMO 4G*Ŋ0uQY_l4Emc,Hʇ:Kҝ%3JS1{r^Ƞe0댊BbBA;Uq@^ZdzBcV(in~ (>IT-VN]&A_8U5\I*) JzLb'؅I\i Rc (}g#<聄:ҦzZ#׹E*//3F6V<ہuiÎlQ1Fvgeu8x}M!dӨPOުdP-bx܏ xfI8cZڢݯz>Jn/c>⋁xf0r;*hS1?qLD0 /Pπ$zURe/z|AkhAn,֜>ڃ1/}2^a޴b_͚"|D;(UG4yu0%{~a o)R?VQQ94-7W%w :2w-2afTu&dBt# ިhQGUN)@*4$:dIVrgC+A&qQk+ӷEF/y(;c|d梨}ȩrO^o'5!ЏhZYorGGҥ'S*}j̉)>6p(vЖi1P{HSH sZZЀ}XvҷqE94A272`q6{8Գ.Ukn DFzdUXĞj^(犈sAl"Z lEa@@  eP 74P_5[4[g;fot Ih8q|Мy#%ɦ]2$oʚ5#Mo3HIKdnBD"NlvߦsNד4[p+-ɕ<(hs]+AnB 1݅XE7{4MGuyѢPzU>O֠ukܟ1Ut7]#fKԟ-}uCHYjeRptpNlRkBD‘ơQމHrDٛW='O6%~kOPKPٺ3[⽒u|} ѡ ⢜N"J8+n8lH3~"ef{`8'{F⋰G֮빅:&['HR) `X1^mF~GYƪqe|cS8$ǿJIUYr7D.vޠfE;B!88 &EXO\Gu`U-VIH=+.bκ|R2 }k,P9!yg@AQLQ'=YÊ`4:29W'GjC:x`wʿ҅.Sm,W5KitEHJXsaJd0"0 ˎFᑔf)2.e1'lZ%˟zrR4?Gu8ڜXl0FWt1r'lk'~ WB}mr;["=ZE4A# G hƹ:RvX =S-Oα ]Ɋ?4 ,\$CQ'UJD'9 fF;{xZ5U2u1RZvFɡV_!?ޭ"6DCESK]0cޚ>+ۗEF10`$;qD! ͊oӝ@~C]Brq] bE;*Y8?J>H4FVVvi;mdvTyRoZ,N=9TJ!TFrޘ/Xbjq-w<J'w }(,[!_f|qi*X NpQ'B(R| us1om#RDKV~MD x4w䘔{.M-Fk(\eG] >dz1@ ZTV0~6 'Ԝ«M*P3H;jN/F;9#S e  P47]P`OXsAJ"Z lEa@@  eP 7]4P_t \g(Xod2K1V鐀}(⑕.>U2 TgӝcU#suիo ˏ^)$XyĻlT_ d(fhy2E\#lb@Ѥ>hY/lAQKeVd;OĜz;|ٌ{}(Hx2+{n("L$]#0&06`"C.N0 w&Qn&[*'1W<<3eˣ5c`Mi1ɔr Sxثfc;2`u՜M{bWg QF((P?W5Y#"eJ;cWuqn"ۢ:# @>غt4JdZI镧#ӔD?lPS2!^w4{e[t+O:}ⶉvrBT\EvMo8YV5%9)XWNpER~$!ejcK*ulDj_FʹKi'ef&2H-sBFѤs+Հ/vsy;c4h`)&nֶK UHD{B72 |ӊ%%O*R,$*EH8^GDI%Cvl(Q H1 SZ9|b 3oQ mJ*? NL&S/"濳DJ⣪6apvlTƭUQD*&QHɏtc˶z5_ UE/ؠMoc֖(cp doH`tlHPa=Õ0 y]#X1|Rp;V+"ٱI]zD;_B0'_. R1M9ritȣ]JU?Zb#dgV2K%܍D; 8edbcjM_)U®|i }I"|7M[>+Uc+}<ZVTيxkAUև6 5~knojrCy1zA ڀ6MQd=t` :&=x|{Okv[$y1_Ƴڨo M_zӴ+(h[Rj襲E7vmXie51lU H88C -Xel{)"&F"zͨwӁRDFEi&He}R ;V[?00;('l8:3ͥ4_4Iu 6Fe?οҵ92cid yg)8&d69~A2(-\x|I:R}]LNj*dk{=xg(#dI$\;sNmG.RԔ-{h] s}?A,4f eˤKIm-NĚ/J+3Hpt[N |{ݑYYXu9Uo ݲ7Pfy!E:q7R2JtB'`Mi& r)$ ܧ1B8m4C1MD<) l0s`?j0BI_(،:RsA66 l"ZE(+@0= e  P47PTXsAG "Z lEa@@  eP 74P_*]EFE].7qfy,&VlTr f\#o(ss9|SH&ur)LJ# c XռH(4@bɷ mzT$d%8)spxE KDFaylo4@uڠV\y@ږ`gˤKR+H"[sW ij0z}i)1 M4@~Pȫ!zLqEF^s9˾OU:BXt-IxgB[Ìڬ!|A'C/拎?26#+JD&\8D ~rNh$e%k\ :c h'1ifGTer=D8VAS ~S=ŷ\dW[) vL.-؏Y?7J>|cv1{+x](͏}SŋEyީ](Ь`URLmQOrY$+5mU }j9rI^УDAÆ`UIb 0mc FUF-zEү(:0=JëΪ^.ʣ?\H8όZ##9J)Mmzh /Dw$? '5FP?}ņ-ͫTC_Lʌ=pSRԫF޹/~!6TfLE >eik{ bްU6()Z$Hfçn7S;޷VlTc>hozQ p*HIm(ު;ÎT.sP7rWW'?j Ϫ2sW|5[Sϼ;|>#6 /ʂyW ӨJO {\%(cJk+GVPQ<5`dp}3W%*w yjxn"?ud-RFjEpvg 9ď%IZ))X#R2. v5dF[b<9*&2%Lxޠ cRȭ +7> T3MMDd W^uΣpUG[DAlѰIڤl}eB_Lm^V,CZ 8V=#,Qf9 yZؓʙ=\7.*cWe0 mꈜԍg3ⴖK=*1T0R>K2El}vV[l֧!XlBT_b%jP7 3sA\"Z lEa@@  eP 7y4P_ETۿZ(%>4tUeb2s&OR(6Єb/ #ACp7^r⪢l!}H@.V&8m/x3ĉfHlm$Erq+ 0&2NjKHj. \ۏ'56^)E2jC= Z>.@ &cȭ$3+8r;eBlfH9Z2Ùu{LC3Hx4'z8,,sM0$B 4y9֫7xI6jvi*.YRKoT<,ʈN 4vCS#c*q,H @aHWjXtf$}U?._L8T9ڭ]SG^#cME1S6jb0*ɎO1ʱlEOIn&P@ceEM.dUZ)WQKXXXƧ!F:07@e7e~٪>̃c]5y!?аO$֝R'$%3Ri:`$ `ЃNJda"27,**AZ9`ady]Xs!厣 s8W=o1lG)iF]=8M'4< %E j˒By!V}v ,>C[4 DR["Ѧ)vBWLJ8b?ZCA҄V*ވSCKBH\U $S"@hI9r!"2{s`#D+tk,.m^v;'ap%+wj3o3Mj Epϓ˷ѣ=129Jc&CV>ZajW%C%!\\jd!sA|66 l"ZE(,@0< e  P47-PIXsAM"Z lEa@@  eP 7-4P_8A1Q܉R"~֑&Uy8FX ~+o*tcmW/BѮ<χ 7A*LK7Lx΍8ۚjQL 0"Td,nqu<ȷO.hs"ݑJӃhDE[QC>բSPV$Ÿ)E\ |\SgXʮ?U\sVjvx?z;oጏr(Xd;M)R1H%8~1J?_҄XԐGnYBHΒ}@\QPT&7Z_ E&5`(oe9gt)ކk^|~Χ9?H!n9ŴY0`[(:`կVHY,UekޢB9Fګn Tv8jkRMLZ!9;m mYe "I#a`URM KǖضGi=)-~}b@!'[d2+*-iqp9VPTkv1$ Sb?U@msF?#訙xnrdv>)t 2J͝\UKu{Arj}wl< TsN ]b 3lM%g=Kf&Pi ǵPvlNyA Uw7"7m, ȩAnlL,h?z?CDl##JrjR] #gmNm?Jۿ|,\gtlS4QI24 +aZwU- 1{<ߐ: L`eѓ$%Hq- J9`\9$4BS@ ҞIYY@@CnMFYIIqa=X]!BWB1P/TBǺzTdS"{*loHMS',ŒEXM泙~ԥ[l$eໍH\|0,x?J(^@őSYl1f"?N/l o,ĈsݵRbˍ.߮h|%ǬFN{)` *G{8KhQfޚ:2횃-n VJUL֖=7pŠc*i{f#F|-7)`O\~[HO59o={JKՑ9zVUرC11j[4ayǎkY#=vDkEFۈ OW?/a^>@Rik1KgV=NiQzSPbNNR:w:bXVx@>)` 4Yb>.(؎[1DS1LHb15k1pVesA:"Z lEa@@1  eP 7"4P_SnƯѡ0Bhg£錊l9d^}D?oHN>L ]ض>%װb;e->E|P{&H.=GpC2[KO`R0X C \21};NM6 .|#j)A wnphe'ǜQskJR26c%AqNAJǟ'PLAkpAMnDUު@chf#HO{]cA-uYئiZɬjJ1e1JqpEf7HɶE .NHދ>P@ 3 .0}rZ"qAзH{?Ѐ1u`O8'|mZ2:'g\lTGm5LЁU |;V\~#*D, E+6{UX]+){a!I+ԄJuV\ B[KzyJ+5& 帷@41?Uy 9>ZQ 5[Q朚t`%͎ሧ ,)ʼn๸TSLdUn|叒y s&)#R>IxUF:ONjZ/CPq3n*RۙKD# 1˼WFz{>C` P}D2y9)޵ʋH: Zd3 ʌ '8,ĝG؉x'QMi(Վ7qO vJ.ӎo}Rڴ)\~AD-Ҁ%Ɋ\wޅY~ Fѽ [BZ6bObvS1z#-K)xz`ѫŭc^sC>3(.H#CFn Ho cSWF#L֖AFځuU?nޛp>[fQӌSj5DGԜ]G*f >Z5}m)Z";hHfsDsA66 l"ZE(-@0; e  P47(QP>\WsA66 l"ZE(.@0: e  P47(QP+sAE66 l"ZE(3@05 e  P47(QP+sAzG<<"Z lE(a@@Ÿ  eP 7(Q4P_T8Atcpflow-tcpflow-1.6.1/src/000077500000000000000000000000001401360461700154425ustar00rootroot00000000000000tcpflow-tcpflow-1.6.1/src/CMakeLists.txt000066400000000000000000000203541401360461700202060ustar00rootroot00000000000000set(CMAKE_CXX_STANDARD 11) # System Dependencies find_package(Boost) #TODO(olibre): COMPONENTS program_options system) find_package(PCAP) find_package(OpenSSL) find_package(Threads) find_package(PythonLibs) # TODO(olibre): Use target_link_libraries() instead of include_directories() include_directories(.) # TODO(olibre): Fix detection of below headers include (CheckIncludeFiles) # Below lines have been produced using this command line # sed 's|/\* ||' config.h | awk '$1 ~ /#undef|#define/{print $2}' | sort -u | while read w ; do grep -wB1 $w config.h | grep '[^ ]*> header' | sed "s/.*//;s/header.*/$w)/"; done check_include_files(arpa/inet.h HAVE_ARPA_INET_H) check_include_files(boost/icl/interval.hpp HAVE_BOOST_ICL_INTERVAL_HPP) check_include_files(boost/icl/interval_map.hpp HAVE_BOOST_ICL_INTERVAL_MAP_HPP) check_include_files(boost/icl/interval_set.hpp HAVE_BOOST_ICL_INTERVAL_SET_HPP) check_include_files(boost/version.hpp HAVE_BOOST_VERSION_HPP) check_include_files(cairo/cairo.h HAVE_CAIRO_CAIRO_H) check_include_files(cairo/cairo-pdf.h HAVE_CAIRO_CAIRO_PDF_H) check_include_files(cairo.h HAVE_CAIRO_H) check_include_files(cairo-pdf.h HAVE_CAIRO_PDF_H) check_include_files(ctype.h HAVE_CTYPE_H) check_include_files(err.h HAVE_ERR_H) check_include_files(exiv2/image.hpp HAVE_EXIV2_IMAGE_HPP) check_include_files(expat.h HAVE_EXPAT_H) check_include_files(fcntl.h HAVE_FCNTL_H) check_include_files(inttypes.h HAVE_INTTYPES_H) check_include_files(linux/if_ether.h HAVE_LINUX_IF_ETHER_H) check_include_files(memory.h HAVE_MEMORY_H) check_include_files(net/ethernet.h HAVE_NET_ETHERNET_H) check_include_files(net/if.h HAVE_NET_IF_H) check_include_files(net/if_var.h HAVE_NET_IF_VAR_H) check_include_files(netinet/in.h HAVE_NETINET_IN_H) check_include_files(netinet/in_systm.h HAVE_NETINET_IN_SYSTM_H) check_include_files(netinet/ip_ether.h HAVE_NETINET_IP_ETHER_H) check_include_files(netinet/ip.h HAVE_NETINET_IP_H) check_include_files(netinet/ip_var.h HAVE_NETINET_IP_VAR_H) check_include_files(netinet/tcp.h HAVE_NETINET_TCP_H) check_include_files(netinet/tcpip.h HAVE_NETINET_TCPIP_H) check_include_files(openssl/aes.h HAVE_OPENSSL_AES_H) check_include_files(openssl/bio.h HAVE_OPENSSL_BIO_H) check_include_files(openssl/evp.h HAVE_OPENSSL_EVP_H) check_include_files(openssl/hmac.h HAVE_OPENSSL_HMAC_H) check_include_files(openssl/md5.h HAVE_OPENSSL_MD5_H) check_include_files(openssl/pem.h HAVE_OPENSSL_PEM_H) check_include_files(openssl/rand.h HAVE_OPENSSL_RAND_H) check_include_files(openssl/rsa.h HAVE_OPENSSL_RSA_H) check_include_files(openssl/sha.h HAVE_OPENSSL_SHA_H) check_include_files(openssl/x509.h HAVE_OPENSSL_X509_H) check_include_files(pcap.h HAVE_PCAP_H) check_include_files(pcap/pcap.h HAVE_PCAP_PCAP_H) check_include_files(pthread.h HAVE_PTHREAD_H) check_include_files(pwd.h HAVE_PWD_H) check_include_files(regex.h HAVE_REGEX_H) check_include_files(semaphore.h HAVE_SEMAPHORE_H) check_include_files(signal.h HAVE_SIGNAL_H) check_include_files(sqlite3.h HAVE_SQLITE3_H) check_include_files(stdint.h HAVE_STDINT_H) check_include_files(stdio.h HAVE_STDIO_H) check_include_files(stdlib.h HAVE_STDLIB_H) check_include_files(string HAVE_STRING) check_include_files(string.h HAVE_STRING_H) check_include_files(strings.h HAVE_STRINGS_H) check_include_files(sys/bitypes.h HAVE_SYS_BITYPES_H) check_include_files(sys/cdefs.h HAVE_SYS_CDEFS_H) check_include_files(syslog.h HAVE_SYSLOG_H) check_include_files(sys/mman.h HAVE_SYS_MMAN_H) check_include_files(sys/resource.h HAVE_SYS_RESOURCE_H) check_include_files(sys/socket.h HAVE_SYS_SOCKET_H) check_include_files(sys/stat.h HAVE_SYS_STAT_H) check_include_files(sys/types.h HAVE_SYS_TYPES_H) check_include_files(sys/utsname.h HAVE_SYS_UTSNAME_H) check_include_files(sys/wait.h HAVE_SYS_WAIT_H) check_include_files(tr1/unordered_map HAVE_TR1_UNORDERED_MAP) check_include_files(tr1/unordered_set HAVE_TR1_UNORDERED_SET) check_include_files(tre/tre.h HAVE_TRE_TRE_H) check_include_files(unistd.h HAVE_UNISTD_H) check_include_files(unordered_map HAVE_UNORDERED_MAP) check_include_files(unordered_set HAVE_UNORDERED_SET) check_include_files(winsock2.h HAVE_WINSOCK2_H) check_include_files(zlib.h HAVE_ZLIB_H) check_include_files(python2.7/Python.h PYTHON2_7_PYTHON_H) # TODO(olibre): Use instead PYTHON_INCLUDE_DIRS # There are many other #define not (yet) implemented by above CMake directives. # To list the #define use the following command lines: # sed 's|/\* ||' config.h | awk '$1 ~ /#undef|#define/{print $2}' | sort -u | while read w ; do grep -wB1 $w config.h | grep '[^ ]*> header' -q && echo $w; done > already-implemented-using-cmake-directives # ( sed 's|/\* ||' config.h | awk '$1 ~ /#undef|#define/{print $2}' | sort -u | while read w ; do find src -name 'config.h' -o -regex '.*.h\|.*.cpp' -exec fgrep -Iowqm1 $w {} '+' && echo "$w" ; done ) > used-in-source-code # comm -13 already-implemented-using-cmake-directives used-in-source-code | grep -wf - config.h -B1 --color=always > rest-to-implement-using-cmake-directives configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) # When all #define from config.h are implemented using CMake directives the following line... include_directories(..) #include the generated by autotools # ...by this one: # include_directories(${CMAKE_CURRENT_BINARY_DIR}) #include the generated by CMake file (GLOB netviz_cpp netviz/*.cpp) file (GLOB netviz_h netviz/*.h) source_group("netviz headers" FILES ${netviz_h}) add_library (netviz ${netviz_cpp} ${netviz_h}) target_link_libraries(netviz cairo) # TODO(olibre): Only if libcairo is present target_include_directories(netviz PUBLIC netviz) target_link_libraries(netviz cairo) # add_subdirectory(dfxml/src) set(dfxml_writer_h dfxml/src/dfxml_writer.h dfxml/src/hash_t.h) source_group("dfxml_writer headers" FILES ${dfxml_writer_h}) add_library (dfxml_writer dfxml/src/dfxml_writer.cpp ${dfxml_writer_h}) target_link_libraries(dfxml_writer OpenSSL::SSL) target_include_directories(dfxml_writer PUBLIC dfxml/src) #file (GLOB wifipcap_glob_cpp wifipcap/*.cpp) #file (GLOB wifipcap_glob_h wifipcap/*.h) #set (wifipcap_cpp datalink_wifi.cpp ${wifipcap_glob_cpp} ) #set (wifipcap_h datalink_wifi.h ${wifipcap_glob_h} ) set (wifipcap_cpp datalink_wifi.cpp scan_wifiviz.cpp wifipcap/TimeVal.cpp wifipcap/cpack.cpp wifipcap/wifipcap.cpp ) set (wifipcap_h datalink_wifi.h wifipcap/TimeVal.h wifipcap/arp.h wifipcap/cpack.h wifipcap/ether.h wifipcap/ethertype.h wifipcap/extract.h wifipcap/icmp.h wifipcap/ieee802_11_radio.h wifipcap/ip.h wifipcap/ip6.h wifipcap/ipproto.h wifipcap/llc.h wifipcap/os.h wifipcap/oui.h wifipcap/prism.h wifipcap/radiotap.h wifipcap/tcp.h wifipcap/types.h wifipcap/udp.h wifipcap/util.h wifipcap/wifipcap.h ) source_group("wifipcap headers" FILES ${wifipcap_h}) add_library (wifipcap ${wifipcap_cpp} ${wifipcap_h}) target_link_libraries(wifipcap dfxml_writer) target_include_directories(wifipcap PUBLIC wifipcap be13_api pcap) # TODO(olibre): Should not depend on be13_api # add_subdirectory(http-parser) source_group("http-parser headers" FILES http-parser/http_parser.h) add_library (http-parser http-parser/http_parser.h http-parser/http_parser.c ) # add_subdirectory(be13_api) file (GLOB_RECURSE be13_api_h be13_api/*.h) file (GLOB be13_api_cpp be13_api/*.cpp) source_group("be13_api headers" FILES ${be13_api_h}) add_library (be13_api ${be13_api_h} ${be13_api_cpp}) target_link_libraries(be13_api wifipcap) target_include_directories(be13_api PUBLIC be13_api) set (tcpflow_cpp datalink.cpp flow.cpp tcpflow.cpp tcpip.cpp tcpdemux.cpp util.cpp scan_md5.cpp scan_http.cpp # Depends on zlib scan_tcpdemux.cpp scan_netviz.cpp pcap_writer.h mime_map.cpp ) # removed because it hasn't been updated to Python 3: # scan_python.cpp # Depends on PYTHON_LIBRARIES set (tcpflow_h iptree.h mime_map.h tcpip.h intrusive_list.h tcpflow.h tcpdemux.h ) source_group("tcpflow headers" FILES ${tcpflow_h}) add_executable(tcpflow ${tcpflow_cpp} ${tcpflow_h}) target_link_libraries(tcpflow netviz wifipcap be13_api dfxml_writer http-parser z pcap ${PYTHON_LIBRARIES}) # add also ${PYTHON_INCLUDE_PATH} tcpflow-tcpflow-1.6.1/src/Makefile.am000066400000000000000000000067461401360461700175130ustar00rootroot00000000000000# Programs that we compile: bin_PROGRAMS = tcpflow if WIFI_ENABLED WIFI_INCS = -I${top_srcdir}/src/wifipcap else WIFI_INCS = endif AM_CPPFLAGS = -I${top_srcdir}/src/be13_api $(WIFI_INCS) CONFIG_CLEAN_FILES = config.h # old location of config.h include be13_api/Makefile.defs # http://stackoverflow.com/questions/11438613/conditional-subdir-objects AUTOMAKE_OPTIONS = subdir-objects NETVIZ = \ netviz/plot_view.cpp \ netviz/plot_view.h \ netviz/time_histogram_view.cpp \ netviz/time_histogram_view.h \ netviz/time_histogram.cpp \ netviz/time_histogram.h \ netviz/address_histogram_view.cpp \ netviz/address_histogram_view.h \ netviz/address_histogram.cpp \ netviz/address_histogram.h \ netviz/port_histogram_view.cpp \ netviz/port_histogram_view.h \ netviz/port_histogram.cpp \ netviz/port_histogram.h \ netviz/packetfall.cpp \ netviz/packetfall.h \ netviz/net_map.cpp \ netviz/net_map.h \ netviz/legend_view.cpp \ netviz/legend_view.h \ netviz/one_page_report.cpp \ netviz/one_page_report.h WIFI = datalink_wifi.cpp \ datalink_wifi.h \ scan_wifiviz.cpp \ wifipcap/TimeVal.cpp \ wifipcap/TimeVal.h \ wifipcap/arp.h \ wifipcap/cpack.cpp \ wifipcap/cpack.h \ wifipcap/ether.h \ wifipcap/ethertype.h \ wifipcap/extract.h \ wifipcap/icmp.h \ wifipcap/ieee802_11_radio.h \ wifipcap/ip.h \ wifipcap/ip6.h \ wifipcap/ipproto.h \ wifipcap/llc.h \ wifipcap/os.h \ wifipcap/oui.h \ wifipcap/prism.h \ wifipcap/radiotap.h \ wifipcap/tcp.h \ wifipcap/types.h \ wifipcap/udp.h \ wifipcap/util.h \ wifipcap/wifipcap.cpp \ wifipcap/wifipcap.h if WIFI_ENABLED WIFI_FILES = $(WIFI) else WIFI_FILES = endif DFXML_WRITER = be13_api/dfxml/src/dfxml_writer.cpp \ be13_api/dfxml/src/dfxml_writer.h \ be13_api/dfxml/src/hash_t.h DFXML_READER = be13_api/dfxml/src/dfxml_reader.cpp \ be13_api/dfxml/src/dfxml_reader.h \ be13_api/dfxml/src/hash_t.h tcpflow_SOURCES = \ $(DFXML_WRITER) $(NETVIZ) $(BE13_API) $(WIFI_FILES) \ datalink.cpp flow.cpp \ tcpflow.cpp \ tcpip.h tcpip.cpp \ tcpdemux.h tcpdemux.cpp \ intrusive_list.h \ tcpflow.h util.cpp \ scan_md5.cpp \ scan_http.cpp \ scan_tcpdemux.cpp \ scan_netviz.cpp \ pcap_writer.h \ iptree.h \ http-parser/http_parser.c \ http-parser/http_parser.h \ mime_map.cpp \ mime_map.h # Removed because it hasn't been updated to Python 3: # scan_python.cpp EXTRA_DIST =\ inet_ntop.c \ inet_ntop.h \ http-parser/AUTHORS \ http-parser/CONTRIBUTIONS \ http-parser/LICENSE-MIT \ http-parser/Makefile \ http-parser/README.md \ http-parser/http_parser.gyp \ wifipcap/README.txt \ wifipcap/TimeVal.cpp \ wifipcap/TimeVal.h \ wifipcap/arp.h \ wifipcap/ether.h \ wifipcap/ethertype.h \ wifipcap/extract.h \ wifipcap/icmp.h \ wifipcap/ieee802_11_radio.h \ wifipcap/ip.h \ wifipcap/ip6.h \ wifipcap/ipproto.h \ wifipcap/os.h \ wifipcap/oui.h \ wifipcap/prism.h \ wifipcap/radiotap.h \ wifipcap/sample.cpp \ wifipcap/tcp.h \ wifipcap/types.h \ wifipcap/udp.h \ wifipcap/util.cpp \ wifipcap/util.h \ wifipcap/wifipcap.cpp \ wifipcap/wifipcap.h testiph: tcpflow echo Testing the IP histogram for i in 100 1000 10000 ; \ do /bin/rm -f test-$$i out-$$i.txt ; \ ./tcpflow -o test1 -S iphtest=1 -S iphtrim=$$i -r /corp/nps/packets/2008-nitroba/nitroba.pcap > iphtest-nitroba-$$i.txt ; \ done diff ../tests/iphtest-nitroba-100.txt iphtest-nitroba-100.txt diff ../tests/iphtest-nitroba-1000.txt iphtest-nitroba-1000.txt diff ../tests/iphtest-nitroba-10000.txt iphtest-nitroba-10000.txt echo iptree appears okay. tcpflow-tcpflow-1.6.1/src/NOTES.txt000066400000000000000000000001111401360461700170640ustar00rootroot00000000000000 to update be13_api: cd gits/tcpflow/src/be13_api git pull origin master tcpflow-tcpflow-1.6.1/src/be13_api/000077500000000000000000000000001401360461700170255ustar00rootroot00000000000000tcpflow-tcpflow-1.6.1/src/be13_api/Makefile.defs000066400000000000000000000021241401360461700214040ustar00rootroot00000000000000BE13_API= \ be13_api/atomic_set_map.h \ be13_api/aftimer.h \ be13_api/beregex.cpp \ be13_api/beregex.h \ be13_api/bulk_extractor_i.h \ be13_api/cppmutex.h \ be13_api/feature_recorder.cpp \ be13_api/feature_recorder.h \ be13_api/feature_recorder_set.cpp \ be13_api/feature_recorder_set.h \ be13_api/feature_recorder_sql.cpp \ be13_api/histogram.h \ be13_api/histogram.cpp \ be13_api/net_ethernet.h \ be13_api/pcap_fake.cpp \ be13_api/pcap_fake.h \ be13_api/plugin.cpp \ be13_api/sbuf.cpp \ be13_api/sbuf.h \ be13_api/sbuf_private.h \ be13_api/sbuf_stream.cpp \ be13_api/sbuf_stream.h \ be13_api/unicode_escape.cpp \ be13_api/unicode_escape.h \ be13_api/utf8.h \ be13_api/utf8/checked.h \ be13_api/utf8/core.h \ be13_api/utf8/unchecked.h \ be13_api/utils.cpp \ be13_api/utils.h \ be13_api/word_and_context_list.cpp \ be13_api/word_and_context_list.h tcpflow-tcpflow-1.6.1/src/be13_api/aftimer.h000066400000000000000000000105451401360461700206320ustar00rootroot00000000000000#ifndef __AFTIMER_H__ #define __AFTIMER_H__ #ifdef __cplusplus #ifndef WIN32 #ifndef __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS #endif #include #include #endif #include #include #include class aftimer { struct timeval t0; bool running; long total_sec; long total_usec; double lap_time_; // time from when we last did a "stop" public: aftimer():t0(),running(false),total_sec(0),total_usec(0),lap_time_(0){} void start(); // start the timer void stop(); // stop the timer time_t tstart() const { return t0.tv_sec;} // time we started double elapsed_seconds() const; // how long timer has been running, total double lap_time() const; // how long the timer is running this time double eta(double fraction_done) const; // calculate ETA in seconds, given fraction std::string hms(long t) const; // turn a number of seconds into h:m:s std::string elapsed_text() const; /* how long we have been running */ std::string eta_text(double fraction_done) const; // h:m:s std::string eta_time(double fraction_done) const; // the actual time }; /* This code in part from * http://social.msdn.microsoft.com/Forums/en/vcgeneral/thread/430449b3-f6dd-4e18-84de-eebd26a8d668 */ #if defined(WIN32) || defined(__MINGW32__) # include # include # ifndef DELTA_EPOCH_IN_MICROSECS # if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) # define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 # else # define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL # endif # endif #endif inline void timestamp(struct timeval *t) { #ifdef WIN32 FILETIME ft; GetSystemTimeAsFileTime(&ft); unsigned __int64 tmpres = 0; tmpres |= ft.dwHighDateTime; tmpres <<= 32; tmpres |= ft.dwLowDateTime; /*converting file time to unix epoch*/ tmpres -= DELTA_EPOCH_IN_MICROSECS; tmpres /= 10; /*convert into microseconds*/ t->tv_sec = (long)(tmpres / 1000000UL); t->tv_usec = (long)(tmpres % 1000000UL); #else gettimeofday(t,NULL); #endif } inline void aftimer::start() { timestamp(&t0); running = 1; } inline void aftimer::stop(){ if(running){ struct timeval t; timestamp(&t); total_sec += t.tv_sec - t0.tv_sec; total_usec += t.tv_usec - t0.tv_usec; lap_time_ = (double)(t.tv_sec - t0.tv_sec) + (double)(t.tv_usec - t0.tv_usec)/1000000.0; running = false; } } inline double aftimer::lap_time() const { return lap_time_; } inline double aftimer::elapsed_seconds() const { double ret = (double)total_sec + (double)total_usec/1000000.0; if(running){ struct timeval t; timestamp(&t); ret += t.tv_sec - t0.tv_sec; ret += (t.tv_usec - t0.tv_usec) / 1000000.0; } return ret; } inline std::string aftimer::hms(long t) const { char buf[64]; int days = t / (60*60*24); t = t % (60*60*24); /* what's left */ int h = t / 3600; int m = (t / 60) % 60; int s = t % 60; buf[0] = 0; switch(days){ case 0: snprintf(buf,sizeof(buf),"%2d:%02d:%02d",h,m,s); break; case 1: snprintf(buf,sizeof(buf),"%d day, %2d:%02d:%02d",days,h,m,s); break; default: snprintf(buf,sizeof(buf),"%d days %2d:%02d:%02d",days,h,m,s); } return std::string(buf); } inline std::string aftimer::elapsed_text() const { return hms((int)elapsed_seconds()); } /** * returns the number of seconds until the job is complete. */ inline double aftimer::eta(double fraction_done) const { double t = elapsed_seconds(); if(t<=0) return -1; // can't figure it out if(fraction_done<=0) return -1; // can't figure it out return (t * 1.0/fraction_done - t); } /** * Retuns the number of hours:minutes:seconds until the job is done. */ inline std::string aftimer::eta_text(double fraction_done) const { double e = eta(fraction_done); if(e<0) return std::string("n/a"); // can't figure it out return hms((long)e); } /** * Returns the time when data is due. */ inline std::string aftimer::eta_time(double fraction_done) const { time_t t = time_t(eta(fraction_done)) + time(0); struct tm tm; #ifdef HAVE_LOCALTIME_R localtime_r(&t,&tm); #else tm = *localtime(&t); #endif char buf[64]; snprintf(buf,sizeof(buf),"%02d:%02d:%02d",tm.tm_hour,tm.tm_min,tm.tm_sec); return std::string(buf); } #endif #endif tcpflow-tcpflow-1.6.1/src/be13_api/atomic_set_map.h000066400000000000000000000101071401360461700221610ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * defines atomic_map and atomic_set * */ #ifndef ATOMIC_SET_MAP_H #define ATOMIC_SET_MAP_H #include "cppmutex.h" #include #include #include #if defined(HAVE_UNORDERED_MAP) # include # undef HAVE_TR1_UNORDERED_MAP // be sure we don't use it #else # if defined(HAVE_TR1_UNORDERED_MAP) # include # endif #endif #if defined(HAVE_UNORDERED_SET) #include #undef HAVE_TR1_UNORDERED_SET // be sure we don't use it #else #if defined(HAVE_TR1_UNORDERED_SET) #include #endif #endif template class atomic_histogram { #ifdef HAVE_UNORDERED_MAP typedef std::unordered_map hmap_t; #else #ifdef HAVE_TR1_UNORDERED_MAP typedef std::tr1::unordered_map hmap_t; #else typedef std::map hmap_t; #endif #endif hmap_t amap; // the locked atomic map mutable cppmutex M; // my lock public: atomic_histogram():amap(),M(){}; // The callback is used to report the histogram. // The callback returns '0' if no error is encountered, '-1' if the dumping should stop typedef int (*dump_callback_t)(void *user,const TYPE &val,const CTYPE &count); // add and return the count // http://www.cplusplus.com/reference/unordered_map/unordered_map/insert/ CTYPE add(const TYPE &val,const CTYPE &count){ cppmutex::lock lock(M); std::pair p = amap.insert(std::make_pair(val,count)); if (!p.second) { p.first->second += count; } return p.first->second; } // Dump the database to a user-provided callback. void dump(void *user,dump_callback_t dump_cb) const{ cppmutex::lock lock(M); for(typename hmap_t::const_iterator it = amap.begin();it!=amap.end();it++){ int ret = (*dump_cb)(user,(*it).first,(*it).second); if(ret<0) return; } } struct ReportElement { ReportElement(TYPE aValue,uint64_t aTally):value(aValue),tally(aTally){ } TYPE value; CTYPE tally; static bool compare(const ReportElement *e1, const ReportElement *e2) { if (e1->tally > e2->tally) return true; if (e1->tally < e2->tally) return false; return e1->value < e2->value; } virtual ~ReportElement(){}; }; typedef std::vector< const ReportElement *> element_vector_t; void dump_sorted(void *user,dump_callback_t dump_cb) const { /* Create a list of new elements, sort it, then report the sorted list */ element_vector_t evect; { cppmutex::lock lock(M); for(typename hmap_t::const_iterator it = amap.begin();it!=amap.end();it++){ evect.push_back( new ReportElement((*it).first, (*it).second)); } } std::sort(evect.begin(),evect.end(),ReportElement::compare); for(typename element_vector_t::const_iterator it = evect.begin();it!=evect.end();it++){ int ret = (*dump_cb)(user,(*it)->value,(*it)->tally); delete *it; if(ret<0) break; } } uint64_t size_estimate() const; // Estimate the size of the database }; template class atomic_set { cppmutex M; #ifdef HAVE_UNORDERED_SET std::unordered_setmyset; #else #ifdef HAVE_TR1_UNORDERED_SET std::tr1::unordered_setmyset; #else std::setmyset; #endif #endif public: atomic_set():M(),myset(){} bool contains(const TYPE &s){ cppmutex::lock lock(M); return myset.find(s)!=myset.end(); } void insert(const TYPE &s){ cppmutex::lock lock(M); myset.insert(s); } bool check_for_presence_and_insert(const TYPE &s){ cppmutex::lock lock(M); if(myset.find(s)!=myset.end()) return true; // in the set myset.insert(s); // otherwise insert it return false; // and return that it wasn't } }; #endif tcpflow-tcpflow-1.6.1/src/be13_api/be13_configure.m4000066400000000000000000000024321401360461700220630ustar00rootroot00000000000000# # mix-ins for be13 # AC_MSG_NOTICE([Including be13_configure.m4 from be13_api]) AC_CHECK_HEADERS([err.h pwd.h sys/cdefs.h sys/mman.h sys/resource.h sys/utsname.h unistd.h sqlite3.h ]) AC_CHECK_FUNCS([gmtime_r ishexnumber isxdigit localtime_r unistd.h mmap err errx warn warnx pread64 pread strptime _lseeki64 utimes ]) AC_CHECK_LIB([sqlite3],[sqlite3_libversion]) AC_CHECK_FUNCS([sqlite3_create_function_v2]) AC_TRY_COMPILE([#pragma GCC diagnostic ignored "-Wredundant-decls"],[int a=3;], [AC_DEFINE(HAVE_DIAGNOSTIC_REDUNDANT_DECLS,1,[define 1 if GCC supports -Wredundant-decls])] ) AC_TRY_COMPILE([#pragma GCC diagnostic ignored "-Wcast-align"],[int a=3;], [AC_DEFINE(HAVE_DIAGNOSTIC_CAST_ALIGN,1,[define 1 if GCC supports -Wcast-align])] ) AC_TRY_LINK([#include ], [uint64_t ul; __sync_add_and_fetch(&ul,0);], AC_DEFINE(HAVE___SYNC_ADD_AND_FETCH,1,[define 1 if __sync_add_and_fetch works on 64-bit numbers])) # # Figure out which version of unordered_map we are going to use # AC_LANG_PUSH(C++) AC_MSG_NOTICE([checking for unordered_map]) AC_MSG_NOTICE([ CXXFLAGS: $CXXFLAGS]) AC_CHECK_HEADERS([unordered_map unordered_set],[],[ AC_CHECK_HEADERS([tr1/unordered_map tr1/unordered_set])]) AC_MSG_NOTICE([done]) AC_LANG_POP() tcpflow-tcpflow-1.6.1/src/be13_api/beregex.cpp000066400000000000000000000123431401360461700211550ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ #include "config.h" #include "beregex.h" #include #include #include #include #if defined(HAVE_LIBTRE) && defined(HAVE_TRE_REGCOMP) && defined(HAVE_TRE_TRE_H) #define REGCOMP tre_regcomp #define REGFREE tre_regfree #define REGEXEC tre_regexec #define nreg (regex_t *)nreg_ #define HAVE_REGULAR_EXPRESSIONS static const char *regex_version = "tre"; #endif /* use regcomp() if tre_regcomp() is not available */ #if defined(HAVE_REGCOMP) && !defined(HAVE_REGULAR_EXPRESSIONS) #define REGCOMP regcomp #define REGFREE regfree #define REGEXEC regexec #define nreg (regex_t *)nreg_ #define HAVE_REGULAR_EXPRESSIONS static const char *regex_version = "system"; #endif #ifndef HAVE_REGULAR_EXPRESSIONS #error bulk_extractor requires tre_regcomp or regcomp to run #error download tre from "http://laurikari.net/tre/download/" #endif const char *beregex::version(){return regex_version;} /* Only certain characters are assumed to be a regular expression. These characters are * coincidently never in email addresses. */ bool beregex::is_regex(const std::string &str) { for(std::string::const_iterator it = str.begin();it!=str.end();it++){ switch(*it){ case '*': case '[': case '(': return true; } } return false; } beregex::beregex(const beregex &that):pat(that.pat),flags(that.flags),nreg_(0) { compile(); } beregex::beregex(std::string pat_,int flags_):pat(pat_),flags(flags_),nreg_(0) { compile(); } void beregex::compile() // compile the regex { if(pat.size()==0) return; nreg_ = calloc(sizeof(regex_t),1); if(REGCOMP(nreg,pat.c_str(),flags | REG_EXTENDED)!=0){ std::cerr << "regular expression compile error '" << pat << "' flags=" << flags << "\n"; exit(1); } } beregex::~beregex(){ if(nreg_){ REGFREE(nreg); free(nreg_); nreg_ = 0; } } /** * perform a search for a single hit. If there is a group and something is found, * set *found to be what was found, *offset to be the starting offset, and *len to be * the length. Note that this only handles a single group. */ int beregex::search(const std::string &line,std::string *found,size_t *offset,size_t *len) const { static const int REGMAX=2; regmatch_t pmatch[REGMAX]; if(!nreg_) return 0; memset(pmatch,0,sizeof(pmatch)); int r = REGEXEC(nreg,line.c_str(),REGMAX,pmatch,0); if(r==REG_NOMATCH) return 0; if(r!=0) return 0; /* some kind of failure */ /* Make copies of the first group */ if(pmatch[1].rm_so != pmatch[1].rm_eo){ if(found) *found = line.substr(pmatch[1].rm_so,pmatch[1].rm_eo-pmatch[1].rm_so); if(offset) *offset = pmatch[1].rm_so; if(len) *len = pmatch[1].rm_eo-pmatch[1].rm_so; } return 1; /* success */ } /** Perform a search with an array of strings. Return 0 if success, return code if fail.*/ int beregex::search(const std::string &line,std::string *matches,int REGMAX) const { if(!nreg) return 0; regmatch_t *pmatch = (regmatch_t *)calloc(sizeof(regmatch_t),REGMAX+1); int r = REGEXEC(nreg,line.c_str(),REGMAX+1,pmatch,0); if(r==0){ for(int i=0;i0 && (*line.end())=='\r'){ line.erase(line.end()); /* remove the last character while it is a \n or \r */ } patterns.push_back(new beregex(line,0)); } f.close(); return 0; } return -1; } void regex_list::add_regex(const std::string &pat) { patterns.push_back(new beregex(pat,0)); } /* Find the FIRST match in buf */ bool regex_list::check(const std::string &buf,std::string *found, size_t *offset,size_t *len) const { /* Now check check pattern */ /* First check literals, because they are faster */ bool first = true; bool fnd = false; for(std::vector::const_iterator it=patterns.begin(); it != patterns.end(); it++){ std::string nfound; size_t noffset=0; size_t nlen=0; if((*it)->search(buf,&nfound,&noffset,&nlen)){ if(first || noffset<*offset){ fnd = true; *found = nfound; *offset = noffset; *len = nlen; first = false; } } } return fnd; } tcpflow-tcpflow-1.6.1/src/be13_api/beregex.h000066400000000000000000000050321401360461700206170ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /* * beregex.h: * * simple cover for regular expression class. * The class allocates and frees the strings */ #ifndef BEREGEX_H #define BEREGEX_H #ifdef HAVE_TRE_TRE_H # include #else # ifdef HAVE_REGEX_H # include # endif #endif #include #include #include #include #include #include #include class beregex { private: void compile(); beregex & operator=(const beregex&that); // don't use this, please public: /** Bargain-basement detector of things that might be regular expressions. */ static const char *version(); static bool is_regex(const std::string &str); std::string pat; /* our pattern */ int flags; // Note: nreg_ is void* because the compiler will not allow us to define it as "struct regex_t *" // We could get around this by including regex.h, but that introduces dependencies for programs that include // beregex.h. void *nreg_; beregex(const beregex &that); beregex(std::string pat_,int flags_); ~beregex(); /** * perform a search for a single hit. If there is a group and something is found, * set *found to be what was found, *offset to be the starting offset, and *len to be * the length. Note that this only handles a single group. */ int search(const std::string &line,std::string *found,size_t *offset,size_t *len) const; int search(const std::string &line,std::string *matches,int REGMAX) const; std::string search(const std::string &line) const; }; typedef std::vector beregex_vector; /** * The regex_list maintains a list of regular expressions. * The list can be read out of a file. * check() returns true if the provided string is inside the list * This should be combined with the word_and_context_list */ class regex_list { public: std::vector patterns; regex_list():patterns(){} size_t size(){ return patterns.size(); } /** * Read a file; returns 0 if successful, -1 if failure. * @param fname - the file to read. */ virtual ~regex_list(){ for(std::vector::iterator it=patterns.begin(); it != patterns.end(); it++){ delete *it; } } void add_regex(const std::string &pat); int readfile(std::string fname); /** check() is threadsafe. */ bool check(const std::string &probe,std::string *found, size_t *offset,size_t *len) const; }; #endif tcpflow-tcpflow-1.6.1/src/be13_api/bulk_extractor_i.h000066400000000000000000001107111401360461700225370ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /* * By design, this file can be read without reading config.h * #include "config.h" must appear as the first line of your .cpp file. */ #ifndef PACKAGE_NAME #error bulk_extractor_i.h included before config.h #endif #ifndef BULK_EXTRACTOR_I_H #define BULK_EXTRACTOR_I_H #define DEBUG_PEDANTIC 0x0001 // check values more rigorously #define DEBUG_PRINT_STEPS 0x0002 // prints as each scanner is started #define DEBUG_SCANNER 0x0004 // dump all feature writes to stderr #define DEBUG_NO_SCANNERS 0x0008 // do not run the scanners #define DEBUG_DUMP_DATA 0x0010 // dump data as it is seen #define DEBUG_DECODING 0x0020 // debug decoders in scanner #define DEBUG_INFO 0x0040 // print extra info #define DEBUG_EXIT_EARLY 1000 // just print the size of the volume and exis #define DEBUG_ALLOCATE_512MiB 1002 // Allocate 512MiB, but don't set any flags /* We need netinet/in.h or windowsx.h */ #ifdef HAVE_NETINET_IN_H # include #endif #include #if defined(MINGW) || defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__) #ifndef WIN32 #define WIN32 #endif #endif #if defined(WIN32) || defined(__MINGW32__) # include # include # include #endif /* If byte_order hasn't been defined, assume its intel */ #if defined(WIN32) || !defined(__BYTE_ORDER) # define __LITTLE_ENDIAN 1234 # define __BIG_ENDIAN 4321 # define __BYTE_ORDER __LITTLE_ENDIAN #endif #if (__BYTE_ORDER == __LITTLE_ENDIAN) && (__BYTE_ORDER == __BIG_ENDIAN) # error Invalid __BYTE_ORDER #endif /** * \addtogroup plugin_module * @{ */ /** * \file * bulk_extractor scanner plug_in architecture. * * Scanners are called with two parameters: * A reference to a scanner_params (SP) object. * A reference to a recursion_control_block (RCB) object. * * On startup, each scanner is called with a special SP and RCB. * The scanners respond by setting fields in the SP and returning. * * When executing, once again each scanner is called with the SP and RCB. * This is the only file that needs to be included for a scanner. * * \li \c phase_startup - scanners are loaded and register the names of the feature files they want. * \li \c phase_scan - each scanner is called to analyze 1 or more sbufs. * \li \c phase_shutdown - scanners are given a chance to shutdown */ #ifndef __cplusplus # error bulk_extractor_i.h requires C++ #endif #include "sbuf.h" #include "utf8.h" #include "utils.h" // for gmtime_r #include #include #include #include "feature_recorder.h" #include "feature_recorder_set.h" /* Network includes */ /**************************************************************** *** pcap.h --- If we don't have it, fake it. --- ***/ #ifdef HAVE_NETINET_IF_ETHER_H # include #endif #ifdef HAVE_NETINET_IN_H # include #endif #ifdef HAVE_NET_ETHERNET_H # include // for freebsd #endif #if defined(HAVE_LIBPCAP) # ifdef HAVE_DIAGNOSTIC_REDUNDANT_DECLS # pragma GCC diagnostic ignored "-Wredundant-decls" # endif # if defined(HAVE_PCAP_PCAP_H) # include # define GOT_PCAP # endif # if defined(HAVE_PCAP_H) && !defined(GOT_PCAP) # include # define GOT_PCAP # endif # if defined(HAVE_WPCAP_PCAP_H) && !defined(GOT_PCAP) # include # define GOT_PCAP # endif # ifdef HAVE_DIAGNOSTIC_REDUNDANT_DECLS # pragma GCC diagnostic warning "-Wredundant-decls" # endif #else # include "pcap_fake.h" #endif /** * \class scanner_params * The scanner params class is the primary way that the bulk_extractor framework * communicates with the scanners. * @param sbuf - the buffer to be scanned * @param feature_names - if fs==0, add to feature_names the feature file types that this * scanner records.. The names can have a /c appended to indicate * that the feature files should have context enabled. Do not scan. * @param fs - where the features should be saved. Must be provided if feature_names==0. **/ /***************************************************************** *** bulk_extractor has a private implementation of IPv4 and IPv6, *** UDP and TCP. *** *** We did this becuase we found slightly different versions on *** MacOS, Ubuntu Linux, Fedora Linux, Centos, Mingw, and Cygwin. *** TCP/IP isn't changing anytime soon, and when it changes (as it *** did with IPv6), these different systems all implemented it slightly *** differently, and that caused a lot of problems for us. *** So the BE13 API has a single implementation and it's good enough *** for our uses. ***/ namespace be13 { #ifndef ETH_ALEN # define ETH_ALEN 6 // ethernet address len #endif #ifndef IPPROTO_TCP # define IPPROTO_TCP 6 /* tcp */ #endif struct ether_addr { uint8_t ether_addr_octet[ETH_ALEN]; } __attribute__ ((__packed__)); /* 10Mb/s ethernet header */ struct ether_header { uint8_t ether_dhost[ETH_ALEN]; /* destination eth addr */ uint8_t ether_shost[ETH_ALEN]; /* source ether addr */ uint16_t ether_type; /* packet type ID field */ } __attribute__ ((__packed__)); /* The mess below is becuase these items are typedefs and * structs on some systems and #defines on other systems * So in the interest of portability we need to define *new* * structures that are only used here */ typedef uint32_t ip4_addr_t; // historical // on windows we use the definition that's in winsock struct ip4_addr { ip4_addr_t addr; }; /* * Structure of an internet header, naked of options. */ struct ip4 { #if __BYTE_ORDER == __LITTLE_ENDIAN uint8_t ip_hl:4; /* header length */ uint8_t ip_v:4; /* version */ #endif #if __BYTE_ORDER == __BIG_ENDIAN uint8_t ip_v:4; /* version */ uint8_t ip_hl:4; /* header length */ #endif uint8_t ip_tos; /* type of service */ uint16_t ip_len; /* total length */ uint16_t ip_id; /* identification */ uint16_t ip_off; /* fragment offset field */ #define IP_RF 0x8000 /* reserved fragment flag */ #define IP_DF 0x4000 /* dont fragment flag */ #define IP_MF 0x2000 /* more fragments flag */ #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ uint8_t ip_ttl; /* time to live */ uint8_t ip_p; /* protocol */ uint16_t ip_sum; /* checksum */ struct ip4_addr ip_src, ip_dst; /* source and dest address */ } __attribute__ ((__packed__)); struct ip4_dgram { const struct ip4 *header; const uint8_t *payload; uint16_t payload_len; }; /* * IPv6 header structure */ struct ip6_addr { // our own private ipv6 definition union { uint8_t addr8[16]; // three ways to get the data uint16_t addr16[8]; uint32_t addr32[4]; } addr; /* 128-bit IP6 address */ }; struct ip6_hdr { union { struct ip6_hdrctl { uint32_t ip6_un1_flow; /* 20 bits of flow-ID */ uint16_t ip6_un1_plen; /* payload length */ uint8_t ip6_un1_nxt; /* next header */ uint8_t ip6_un1_hlim; /* hop limit */ } ip6_un1; uint8_t ip6_un2_vfc; /* 4 bits version, top 4 bits class */ } ip6_ctlun; struct ip6_addr ip6_src; /* source address */ struct ip6_addr ip6_dst; /* destination address */ } __attribute__((__packed__)); struct ip6_dgram { const struct ip6_hdr *header; const uint8_t *payload; uint16_t payload_len; }; /* * TCP header. * Per RFC 793, September, 1981. */ typedef uint32_t tcp_seq; struct tcphdr { uint16_t th_sport; /* source port */ uint16_t th_dport; /* destination port */ tcp_seq th_seq; /* sequence number */ tcp_seq th_ack; /* acknowledgement number */ # if __BYTE_ORDER == __LITTLE_ENDIAN uint8_t th_x2:4; /* (unused) */ uint8_t th_off:4; /* data offset */ # endif # if __BYTE_ORDER == __BIG_ENDIAN uint8_t th_off:4; /* data offset */ uint8_t th_x2:4; /* (unused) */ # endif uint8_t 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 uint16_t th_win; /* window */ uint16_t th_sum; /* checksum */ uint16_t th_urp; /* urgent pointer */ }; /* * The packet_info structure records packets after they are read from the pcap library. * It preserves the original pcap information and information decoded from the MAC and * VLAN (IEEE 802.1Q) layers, as well as information that might be present from 802.11 * interfaces. However it does not preserve the full radiotap information. * * packet_info is created to make it easier to write network forensic software. It encapsulates * much of the common knowledge needed to operate on packet-based IP networks. * * @param ts - the actual packet time to use (adjusted) * @param pcap_data - Original data offset point from pcap * @param data - the actual packet data, minus the MAC layer * @param datalen - How much data is available at the datalen pointer * */ class packet_info { public: // IPv4 header offsets static const size_t ip4_proto_off = 9; static const size_t ip4_src_off = 12; static const size_t ip4_dst_off = 16; // IPv6 header offsets static const size_t ip6_nxt_hdr_off = 6; static const size_t ip6_plen_off = 4; static const size_t ip6_src_off = 8; static const size_t ip6_dst_off = 24; // TCP header offsets static const size_t tcp_sport_off = 0; static const size_t tcp_dport_off = 2; class frame_too_short : public std::logic_error { public: frame_too_short() : std::logic_error("frame too short to contain requisite network structures") {} }; enum vlan_t {NO_VLAN=-1}; /** create a packet, usually an IP packet. * @param d - start of MAC packet * @param d2 - start of IP data */ packet_info(const int dlt,const struct pcap_pkthdr *h,const u_char *d, const struct timeval &ts_,const uint8_t *d2,size_t dl2): pcap_dlt(dlt),pcap_hdr(h),pcap_data(d),ts(ts_),ip_data(d2),ip_datalen(dl2){} packet_info(const int dlt,const struct pcap_pkthdr *h,const u_char *d): pcap_dlt(dlt),pcap_hdr(h),pcap_data(d),ts(h->ts),ip_data(d),ip_datalen(h->caplen){} const int pcap_dlt; // data link type; needed by libpcap, not provided const struct pcap_pkthdr *pcap_hdr; // provided by libpcap const u_char *pcap_data; // provided by libpcap; where the MAC layer begins const struct timeval &ts; // when packet received; possibly modified before packet_info created const uint8_t *const ip_data; // pointer to where ip data begins const size_t ip_datalen; // length of ip data static u_short nshort(const u_char *buf,size_t pos); // return a network byte order short at offset pos int ip_version() const; // returns 4, 6 or 0 u_short ether_type() const; // returns 0 if not IEEE802, otherwise returns ether_type int vlan() const; // returns NO_VLAN if not IEEE802 or not VLAN, othererwise VID const uint8_t *get_ether_dhost() const; // returns a pointer to ether dhost if ether packet const uint8_t *get_ether_shost() const; // returns a pointer to ether shost if ether packet // packet typing bool is_ip4() const; bool is_ip6() const; bool is_ip4_tcp() const; bool is_ip6_tcp() const; // packet extraction // IPv4 - return pointers to fields or throws frame_too_short exception const struct in_addr *get_ip4_src() const; const struct in_addr *get_ip4_dst() const; uint8_t get_ip4_proto() const; // IPv6 uint8_t get_ip6_nxt_hdr() const; uint16_t get_ip6_plen() const; const struct ip6_addr *get_ip6_src() const; const struct ip6_addr *get_ip6_dst() const; // TCP uint16_t get_ip4_tcp_sport() const; uint16_t get_ip4_tcp_dport() const; uint16_t get_ip6_tcp_sport() const; uint16_t get_ip6_tcp_dport() const; }; #ifdef DLT_IEEE802 inline u_short packet_info::ether_type() const { if(pcap_dlt==DLT_IEEE802 || pcap_dlt==DLT_EN10MB){ const struct ether_header *eth_header = (struct ether_header *) pcap_data; return ntohs(eth_header->ether_type); } return 0; } #endif #ifndef ETHERTYPE_PUP #define ETHERTYPE_PUP 0x0200 /* Xerox PUP */ #endif #ifndef ETHERTYPE_SPRITE #define ETHERTYPE_SPRITE 0x0500 /* Sprite */ #endif #ifndef ETHERTYPE_IP #define ETHERTYPE_IP 0x0800 /* IP */ #endif #ifndef ETHERTYPE_ARP #define ETHERTYPE_ARP 0x0806 /* Address resolution */ #endif #ifndef ETHERTYPE_REVARP #define ETHERTYPE_REVARP 0x8035 /* Reverse ARP */ #endif #ifndef ETHERTYPE_AT #define ETHERTYPE_AT 0x809B /* AppleTalk protocol */ #endif #ifndef ETHERTYPE_AARP #define ETHERTYPE_AARP 0x80F3 /* AppleTalk ARP */ #endif #ifndef ETHERTYPE_VLAN #define ETHERTYPE_VLAN 0x8100 /* IEEE 802.1Q VLAN tagging */ #endif #ifndef ETHERTYPE_IPX #define ETHERTYPE_IPX 0x8137 /* IPX */ #endif #ifndef ETHERTYPE_IPV6 #define ETHERTYPE_IPV6 0x86dd /* IP protocol version 6 */ #endif #ifndef ETHERTYPE_LOOPBACK #define ETHERTYPE_LOOPBACK 0x9000 /* used to test interfaces */ #endif inline u_short packet_info::nshort(const u_char *buf,size_t pos) { return (buf[pos]<<8) | (buf[pos+1]); } inline int packet_info::vlan() const { if(ether_type()==ETHERTYPE_VLAN){ return nshort(pcap_data,sizeof(struct ether_header)); } return -1; } inline int packet_info::ip_version() const { /* This takes advantage of the fact that ip4 and ip6 put the version number in the same place */ if (ip_datalen >= sizeof(struct ip4)) { const struct ip4 *ip_header = (struct ip4 *) ip_data; switch(ip_header->ip_v){ case 4: return 4; case 6: return 6; } } return 0; } // packet typing inline bool packet_info::is_ip4() const { return ip_version() == 4; } inline bool packet_info::is_ip6() const { return ip_version() == 6; } inline bool packet_info::is_ip4_tcp() const { if(ip_datalen < sizeof(struct ip4) + sizeof(struct tcphdr)) { return false; } return *((uint8_t*) (ip_data + ip4_proto_off)) == IPPROTO_TCP; return false; } inline bool packet_info::is_ip6_tcp() const { if(ip_datalen < sizeof(struct ip6_hdr) + sizeof(struct tcphdr)) { return false; } return *((uint8_t*) (ip_data + ip6_nxt_hdr_off)) == IPPROTO_TCP; } // packet extraction // precondition: the apropriate packet type function must return true before using these functions. // example: is_ip4_tcp() must return true before calling get_ip4_tcp_sport() // Get ether addresses; should this handle vlan and such? inline const uint8_t *packet_info::get_ether_dhost() const { if(pcap_hdr->caplen < sizeof(struct ether_addr)){ throw new frame_too_short(); } return ((const struct ether_header *)pcap_data)->ether_dhost; } inline const uint8_t *packet_info::get_ether_shost() const { if(pcap_hdr->caplen < sizeof(struct ether_addr)){ throw new frame_too_short(); } return ((const struct ether_header *)pcap_data)->ether_shost; } // IPv4 # ifdef HAVE_DIAGNOSTIC_CAST_ALIGN # pragma GCC diagnostic ignored "-Wcast-align" # endif inline const struct in_addr *packet_info::get_ip4_src() const { if(ip_datalen < sizeof(struct ip4)) { throw new frame_too_short(); } return (const struct in_addr *) ip_data + ip4_src_off; } inline const struct in_addr *packet_info::get_ip4_dst() const { if(ip_datalen < sizeof(struct ip4)) { throw new frame_too_short(); } return (const struct in_addr *) ip_data + ip4_dst_off; } # ifdef HAVE_DIAGNOSTIC_CAST_ALIGN # pragma GCC diagnostic warning "-Wcast-align" # endif inline uint8_t packet_info::get_ip4_proto() const { if(ip_datalen < sizeof(struct ip4)) { throw new frame_too_short(); } return *((uint8_t *) (ip_data + ip4_proto_off)); } // IPv6 inline uint8_t packet_info::get_ip6_nxt_hdr() const { if(ip_datalen < sizeof(struct ip6_hdr)) { throw new frame_too_short(); } return *((uint8_t *) (ip_data + ip6_nxt_hdr_off)); } inline uint16_t packet_info::get_ip6_plen() const { if(ip_datalen < sizeof(struct ip6_hdr)) { throw new frame_too_short(); } //return ntohs(*((uint16_t *) (ip_data + ip6_plen_off))); return nshort(ip_data,ip6_plen_off); } # ifdef HAVE_DIAGNOSTIC_CAST_ALIGN # pragma GCC diagnostic ignored "-Wcast-align" # endif inline const struct ip6_addr *packet_info::get_ip6_src() const { if(ip_datalen < sizeof(struct ip6_hdr)) { throw new frame_too_short(); } return (const struct ip6_addr *) ip_data + ip6_src_off; } inline const struct ip6_addr *packet_info::get_ip6_dst() const { if(ip_datalen < sizeof(struct ip6_hdr)) { throw new frame_too_short(); } return (const struct ip6_addr *) ip_data + ip6_dst_off; } # ifdef HAVE_DIAGNOSTIC_CAST_ALIGN # pragma GCC diagnostic warning "-Wcast-align" # endif // TCP inline uint16_t packet_info::get_ip4_tcp_sport() const { if(ip_datalen < sizeof(struct tcphdr) + sizeof(struct ip4)) { throw new frame_too_short(); } //return ntohs(*((uint16_t *) (ip_data + sizeof(struct ip4) + tcp_sport_off))); return nshort(ip_data,sizeof(struct ip4) + tcp_sport_off); } inline uint16_t packet_info::get_ip4_tcp_dport() const { if(ip_datalen < sizeof(struct tcphdr) + sizeof(struct ip4)) { throw new frame_too_short(); } //return ntohs(*((uint16_t *) (ip_data + sizeof(struct ip4) + tcp_dport_off))); return nshort(ip_data,sizeof(struct ip4) + tcp_dport_off); // } inline uint16_t packet_info::get_ip6_tcp_sport() const { if(ip_datalen < sizeof(struct tcphdr) + sizeof(struct ip6_hdr)) { throw new frame_too_short(); } //return ntohs(*((uint16_t *) (ip_data + sizeof(struct ip6_hdr) + tcp_sport_off))); return nshort(ip_data,sizeof(struct ip6_hdr) + tcp_sport_off); // } inline uint16_t packet_info::get_ip6_tcp_dport() const { if(ip_datalen < sizeof(struct tcphdr) + sizeof(struct ip6_hdr)) { throw new frame_too_short(); } //return ntohs(*((uint16_t *) (ip_data + sizeof(struct ip6_hdr) + tcp_dport_off))); return nshort(ip_data,sizeof(struct ip6_hdr) + tcp_dport_off); // } }; typedef void scanner_t(const class scanner_params &sp,const class recursion_control_block &rcb); typedef void process_t(const class scanner_params &sp); typedef void packet_callback_t(void *user,const be13::packet_info &pi); /** scanner_info gets filled in by the scanner to tell the caller about the scanner. * */ class scanner_info { private: static std::stringstream helpstream; // where scanner info help messages are saved. // default copy construction and assignment are meaningless // and not implemented scanner_info(const scanner_info &i); scanner_info &operator=(const scanner_info &i); public: static std::string helpstr(){return helpstream.str();} typedef std::map config_t; // configuration for scanner passed in /* scanner flags */ static const int SCANNER_DISABLED = 0x001; // v1: enabled by default static const int SCANNER_NO_USAGE = 0x002; // v1: do not show scanner in usage static const int SCANNER_NO_ALL = 0x004; // v2: do not enable with -eall static const int SCANNER_FIND_SCANNER = 0x008; // v2: this scanner uses the find_list static const int SCANNER_RECURSE = 0x010; // v3: this scanner will recurse static const int SCANNER_RECURSE_EXPAND = 0x020; // v3: recurses AND result is >= original size static const int SCANNER_WANTS_NGRAMS = 0x040; // v3: Scanner gets buffers that are constant n-grams static const int SCANNER_FAST_FIND = 0x080; // v3: This scanner is a very fast FIND scanner static const int SCANNER_DEPTH_0 = 0x100; // v3: scanner only runs at depth 0 by default static const int CURRENT_SI_VERSION = 4; static const std::string flag_to_string(const int flag){ std::string ret; if(flag==0) ret += "NONE "; if(flag & SCANNER_DISABLED) ret += "SCANNER_DISABLED "; if(flag & SCANNER_NO_USAGE) ret += "SCANNER_NO_USAGE "; if(flag & SCANNER_NO_ALL) ret += "SCANNER_NO_ALL "; if(flag & SCANNER_FIND_SCANNER) ret += "SCANNER_FIND_SCANNER "; if(flag & SCANNER_RECURSE) ret += "SCANNER_RECURSE "; if(flag & SCANNER_RECURSE_EXPAND) ret += "SCANNER_RECURSE_EXPAND "; if(flag & SCANNER_WANTS_NGRAMS) ret += "SCANNER_WANTS_NGRAMS "; return ret; } /* Global config is passed to each scanner as a pointer when it is loaded. * Scanner histograms are added to 'histograms' by machinery. */ struct scanner_config { scanner_config():namevals(),debug(){}; virtual ~scanner_config(){} config_t namevals; // v3: (input) name=val map int debug; // v3: (input) current debug level }; // never change the order or delete old fields, or else you will // break backwards compatability scanner_info():si_version(CURRENT_SI_VERSION), name(),author(),description(),url(),scanner_version(),flags(0),feature_names(), histogram_defs(),packet_user(),packet_cb(),config(){} /* PASSED FROM SCANNER to API: */ int si_version; // version number for this structure std::string name; // v1: (output) scanner name std::string author; // v1: (output) who wrote me? std::string description; // v1: (output) what do I do? std::string url; // v1: (output) where I come from std::string scanner_version; // v1: (output) version for the scanner uint64_t flags; // v1: (output) flags std::set feature_names; // v1: (output) features I need histogram_defs_t histogram_defs; // v1: (output) histogram definition info void *packet_user; // v2: (output) data for network callback packet_callback_t *packet_cb; // v2: (output) callback for processing network packets, or NULL /* PASSED FROM API TO SCANNER; access with functions below */ const scanner_config *config; // v3: (intput to scanner) config // These methods are implemented in the plugin system for the scanner to get config information. // The get_config methods should be called on the si object during PHASE_STARTUP virtual void get_config(const scanner_info::config_t &c, const std::string &name,std::string *val,const std::string &help); virtual void get_config(const std::string &name,std::string *val,const std::string &help); virtual void get_config(const std::string &name,uint64_t *val,const std::string &help); virtual void get_config(const std::string &name,int32_t *val,const std::string &help); virtual void get_config(const std::string &name,uint32_t *val,const std::string &help); virtual void get_config(const std::string &name,uint16_t *val,const std::string &help); virtual void get_config(const std::string &name,uint8_t *val,const std::string &help); #ifdef __APPLE__ virtual void get_config(const std::string &name,size_t *val,const std::string &help); #define HAVE_GET_CONFIG_SIZE_T #endif virtual void get_config(const std::string &name,bool *val,const std::string &help); virtual ~scanner_info(){}; }; #include /** * The scanner_params class is a way for sending the scanner parameters * for this particular sbuf to be scanned. */ class scanner_params { public: enum print_mode_t {MODE_NONE=0,MODE_HEX,MODE_RAW,MODE_HTTP}; static const int CURRENT_SP_VERSION=3; typedef std::map PrintOptions; static print_mode_t getPrintMode(const PrintOptions &po){ PrintOptions::const_iterator p = po.find("print_mode_t"); if(p != po.end()){ if(p->second=="MODE_NONE") return MODE_NONE; if(p->second=="MODE_HEX") return MODE_HEX; if(p->second=="MODE_RAW") return MODE_RAW; if(p->second=="MODE_HTTP") return MODE_HTTP; } return MODE_NONE; } static void setPrintMode(PrintOptions &po,int mode){ switch(mode){ default: case MODE_NONE:po["print_mode_t"]="MODE_NONE";return; case MODE_HEX:po["print_mode_t"]="MODE_HEX";return; case MODE_RAW:po["print_mode_t"]="MODE_RAW";return; case MODE_HTTP:po["print_mode_t"]="MODE_HTTP";return; } } // phase_t specifies when the scanner is being called typedef enum { PHASE_NONE = -1, PHASE_STARTUP = 0, // called in main thread when scanner loads; called on EVERY scanner (called for help) PHASE_INIT = 3, // called in main thread for every ENABLED scanner after all scanners loaded PHASE_THREAD_BEFORE_SCAN = 4, // called in worker thread for every ENABLED scanner before first scan PHASE_SCAN = 1, // called in worker thread for every ENABLED scanner to scan an sbuf PHASE_SHUTDOWN = 2, // called in main thread for every ENABLED scanner when scanner is shutdown } phase_t ; static PrintOptions no_options; // in common.cpp /******************** *** CONSTRUCTORS *** ********************/ /* A scanner params with all of the instance variables, typically for scanning */ scanner_params(phase_t phase_,const sbuf_t &sbuf_,class feature_recorder_set &fs_, PrintOptions &print_options_): sp_version(CURRENT_SP_VERSION), phase(phase_),sbuf(sbuf_),fs(fs_),depth(0),print_options(print_options_),info(0),sxml(0){ } /* A scanner params with no print options */ scanner_params(phase_t phase_,const sbuf_t &sbuf_, class feature_recorder_set &fs_): sp_version(CURRENT_SP_VERSION), phase(phase_),sbuf(sbuf_),fs(fs_),depth(0),print_options(no_options),info(0),sxml(0){ } /* A scanner params with no print options but an xmlstream */ scanner_params(phase_t phase_,const sbuf_t &sbuf_,class feature_recorder_set &fs_,std::stringstream *xmladd): sp_version(CURRENT_SP_VERSION), phase(phase_),sbuf(sbuf_),fs(fs_),depth(0),print_options(no_options),info(0),sxml(xmladd){ } /** Construct a scanner_params for recursion from an existing sp and a new sbuf. * Defaults to phase1 */ scanner_params(const scanner_params &sp_existing,const sbuf_t &sbuf_new): sp_version(CURRENT_SP_VERSION),phase(sp_existing.phase), sbuf(sbuf_new),fs(sp_existing.fs),depth(sp_existing.depth+1), print_options(sp_existing.print_options),info(sp_existing.info),sxml(0){ assert(sp_existing.sp_version==CURRENT_SP_VERSION); }; /** * A scanner params with an empty info */ /************************** *** INSTANCE VARIABLES *** **************************/ const int sp_version; /* version number of this structure */ const phase_t phase; /* v1: 0=startup, 1=normal, 2=shutdown (changed to phase_t in v1.3) */ const sbuf_t &sbuf; /* v1: what to scan / only valid in SCAN_PHASE */ class feature_recorder_set &fs; /* v1: where to put the results / only valid in SCAN_PHASE */ const uint32_t depth; /* v1: how far down are we? / only valid in SCAN_PHASE */ PrintOptions &print_options; /* v1: how to print / NOT USED IN SCANNERS */ scanner_info *info; /* v2: set/get parameters on startup, hasher */ std::stringstream *sxml; /* v3: on scanning and shutdown: CDATA added to XML stream (advanced feature) */ }; inline std::ostream & operator <<(std::ostream &os,const class scanner_params &sp){ os << "scanner_params(" << sp.sbuf << ")"; return os; }; class recursion_control_block { public: /** * @param callback_ - the function to call back * @param partName_ - the part of the forensic path processed by this scanner. */ recursion_control_block(process_t *callback_,std::string partName_): callback(callback_),partName(partName_){} process_t *callback; std::string partName; /* eg "ZIP", "GZIP" */ }; /* plugin.cpp. This will become a class... */ class scanner_def { public:; static uint32_t max_depth; // maximum depth to scan for the scanners static uint32_t max_ngram; // maximum ngram size to change scanner_def():scanner(0),enabled(false),info(),pathPrefix(){}; scanner_t *scanner; // pointer to the primary entry point bool enabled; // is enabled? scanner_info info; // info block sent to and returned by scanner std::string pathPrefix; /* path prefix for recursive scanners */ }; namespace be13 { /* plugin.cpp */ struct plugin { typedef std::vector scanner_vector; static scanner_vector current_scanners; // current scanners static bool dup_data_alerts; // notify when duplicate data is not processed static uint64_t dup_data_encountered; // amount of dup data encountered static void set_scanner_debug(int debug); static void load_scanner(scanner_t scanner,const scanner_info::scanner_config &sc); // load a specific scanner static void load_scanner_file(std::string fn,const scanner_info::scanner_config &sc); // load a scanner from a file static void load_scanners(scanner_t * const *scanners_builtin,const scanner_info::scanner_config &sc); // load the scan_ plugins static void load_scanner_directory(const std::string &dirname,const scanner_info::scanner_config &sc); // load scanners in the directory static void load_scanner_directories(const std::vector &dirnames,const scanner_info::scanner_config &sc); static void load_scanner_packet_handlers(); // send every enabled scanner the phase message static void message_enabled_scanners(scanner_params::phase_t phase,feature_recorder_set &fs); // returns the named scanner, or 0 if no scanner of that name static scanner_t *find_scanner(const std::string &name); static void get_enabled_scanners(std::vector &svector); // put the enabled scanners into the vector static void add_enabled_scanner_histograms_to_feature_recorder_set(feature_recorder_set &fs); static bool find_scanner_enabled(); // return true if a find scanner is enabled // print info about the scanners: static void scanners_disable_all(); // saves a command to disable all static void scanners_enable_all(); // enable all of them static void set_scanner_enabled(const std::string &name,bool enable); static void set_scanner_enabled_all(bool enable); static void scanners_enable(const std::string &name); // saves a command to enable this scanner static void scanners_disable(const std::string &name); // saves a command to disable this scanner static void scanners_process_enable_disable_commands(); // process the enable/disable and config commands static void scanners_init(feature_recorder_set &fs); // init the scanners static void info_scanners(bool detailed_info, bool detailed_settings, scanner_t * const *scanners_builtin,const char enable_opt,const char disable_opt); /* Run the phases on the scanners */ static void phase_shutdown(feature_recorder_set &fs,std::stringstream *sxml=0); // sxml is where to put XML from scanners that shutdown static uint32_t get_max_depth_seen(); static void process_sbuf(const class scanner_params &sp); /* process for feature extraction */ static void process_packet(const be13::packet_info &pi); /* recorders */ static void get_scanner_feature_file_names(feature_file_names_t &feature_file_names); }; }; inline std::string itos(int i){ std::stringstream ss; ss << i;return ss.str();} inline std::string dtos(double d){ std::stringstream ss; ss << d;return ss.str();} inline std::string utos(unsigned int i){ std::stringstream ss; ss << i;return ss.str();} inline std::string utos(uint64_t i){ std::stringstream ss; ss << i;return ss.str();} inline std::string utos(uint16_t i){ std::stringstream ss; ss << i;return ss.str();} inline std::string safe_utf16to8(std::wstring s){ // needs to be cleaned up std::string utf8_line; try { utf8::utf16to8(s.begin(),s.end(),back_inserter(utf8_line)); } catch(utf8::invalid_utf16 const &){ /* Exception thrown: bad UTF16 encoding */ utf8_line = ""; } return utf8_line; } inline std::wstring safe_utf8to16(std::string s){ // needs to be cleaned up std::wstring utf16_line; try { utf8::utf8to16(s.begin(),s.end(),back_inserter(utf16_line)); } catch(utf8::invalid_utf8 const &){ /* Exception thrown: bad UTF16 encoding */ utf16_line = L""; } return utf16_line; } // truncate string at the matching char inline void truncate_at(std::string &line, char ch) { size_t pos = line.find(ch); if(pos != std::string::npos) line.resize(pos); } #ifndef HAVE_ISXDIGIT inline int isxdigit(int c) { return (c>='0' && c<='9') || (c>='a' && c<='f') || (c>='A' && c<='F'); } #endif /* Useful functions for scanners */ #define ONE_HUNDRED_NANO_SEC_TO_SECONDS 10000000 #define SECONDS_BETWEEN_WIN32_EPOCH_AND_UNIX_EPOCH 11644473600LL /* * 11644473600 is the number of seconds between the Win32 epoch * and the Unix epoch. * * http://arstechnica.com/civis/viewtopic.php?f=20&t=111992 * gmtime_r() is Linux-specific. You'll find a copy in util.cpp for Windows. */ inline std::string microsoftDateToISODate(const uint64_t &time) { time_t tmp = (time / ONE_HUNDRED_NANO_SEC_TO_SECONDS) - SECONDS_BETWEEN_WIN32_EPOCH_AND_UNIX_EPOCH; struct tm time_tm; gmtime_r(&tmp, &time_tm); char buf[256]; strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%SZ", &time_tm); // Zulu time return std::string(buf); } /* Convert Unix timestamp to ISO format */ inline std::string unixTimeToISODate(const uint64_t &t) { struct tm time_tm; time_t tmp=t; gmtime_r(&tmp, &time_tm); char buf[256]; strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%SZ", &time_tm); // Zulu time return std::string(buf); } /* Many internal windows and Linux structures require a valid printable name in ASCII */ inline bool validASCIIName(const std::string &name) { for(size_t i = 0; i< name.size(); i++){ if(((u_char)name[i]) & 0x80) return false; // high bit should not be set if(((u_char)name[i]) < ' ') return false; // should not be control character if(((u_char)name[i]) == 0x7f) return false; // DEL is not printable } return true; } #endif tcpflow-tcpflow-1.6.1/src/be13_api/cppmutex.h000066400000000000000000000024771401360461700210550ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * Cppmutex is an easy-to-use mutex class. * Create a cppmutex instance for a mutex. * Create a cppmutex::lock(M) object to get a lock; delete the object to free it. * * BE SURE THAT HAVE_PTHREAD IS DEFINED BEFORE INCLUDING THIS FILE */ #ifndef CPPMUTEX_H #define CPPMUTEX_H #include #include #include #include #include #include class cppmutex { // default copy construction and assignment are meaningless and not implemented cppmutex(const cppmutex &c); cppmutex &operator=(const cppmutex &cp); public: pthread_mutex_t M; public: cppmutex():M(){ if(pthread_mutex_init(&M,NULL)){ std::cerr << "pthread_mutex_init failed: " << strerror(errno) << "\n"; exit(1); } } virtual ~cppmutex(){ pthread_mutex_destroy(&M); } class lock { // get private: cppmutex &myMutex; lock(const lock &l); // copy of locks is meaningless lock &operator=(const lock &l); public: lock(cppmutex &m):myMutex(m){ pthread_mutex_lock(&myMutex.M); } ~lock(){ pthread_mutex_unlock(&myMutex.M); } }; }; #endif tcpflow-tcpflow-1.6.1/src/be13_api/dfxml/000077500000000000000000000000001401360461700201375ustar00rootroot00000000000000tcpflow-tcpflow-1.6.1/src/be13_api/dfxml/src/000077500000000000000000000000001401360461700207265ustar00rootroot00000000000000tcpflow-tcpflow-1.6.1/src/be13_api/dfxml/src/Makefile.defs000066400000000000000000000003171401360461700233070ustar00rootroot00000000000000DFXML_WRITER = dfxml/src/dfxml_writer.cpp \ dfxml/src/dfxml_writer.h \ dfxml/src/hash_t.h DFXML_READER = dfxml/src/dfxml_reader.cpp \ dfxml/src/dfxml_reader.h \ dfxml/src/hash_t.h tcpflow-tcpflow-1.6.1/src/be13_api/dfxml/src/dfxml_configure.m4000066400000000000000000000051521401360461700243460ustar00rootroot00000000000000# # mix-ins for dfxml # Support for hash_t as well. # # This file is public domain # Revision History: # 2012 - Simson Garfinkel - Created for bulk_extractor # AC_MSG_NOTICE([Including dfxml_configure.m4 from dfxml]) AC_MSG_NOTICE([Note: checks for afflib/afflib.h and libewf.h should be in the caller, so they can be disabled]) AC_CHECK_HEADERS([err.h expat.h pwd.h sys/cdefs.h sys/mman.h sys/resource.h sys/utsname.h unistd.h winsock2.h ]) AC_CHECK_FUNCS([fork gmtime_r getuid gethostname getpwuid getrusage mkstemp vasprintf ]) AC_LANG_PUSH(C++) AC_CHECK_HEADERS([exiv2/image.hpp]) AC_LANG_POP() # Determine UTC date offset CPPFLAGS="$CPPFLAGS -DUTC_OFFSET=`TZ=UTC date +%z`" # Get the GIT commit into the GIT_COMMIT variable AC_CHECK_PROG([git],[git],[yes],[no]) AM_CONDITIONAL([FOUND_GIT],[test "x$git" = xyes]) AM_COND_IF([FOUND_GIT], [GIT_COMMIT=`git describe --dirty --always` AC_MSG_NOTICE([git commit $GIT_COMMIT])], [AC_MSG_WARN([git not found])]) # Do we have the CPUID instruction? AC_TRY_COMPILE([#define cpuid(id) __asm__( "cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(id), "b"(0), "c"(0), "d"(0))], [unsigned long eax, ebx, ecx, edx;cpuid(0);], have_cpuid=yes, have_cpuid=no) if test "$have_cpuid" = yes; then AC_DEFINE(HAVE_ASM_CPUID, 1, [define to 1 if __asm__ CPUID is available]) fi # Does GCC have the diagnostic pragma? AC_TRY_COMPILE([#pragma GCC diagnostic ignored "-Wredundant-decls"], [], AC_DEFINE([DFXML_GNUC_HAS_DIAGNOSTIC_PRAGMA],[1],[GCC supports #pragma GCC diagnostic]), ) ################################################################ ## on Win32, crypto requires zlib case $host in *mingw32*) AC_CHECK_LIB([z], [gzdopen],[LIBS="-lz $LIBS"], [AC_MSG_ERROR([Could not find zlib library])]) esac ################################################################ ## OpenSSL Support is now required (for hash_t) ## Note that this now works with both OpenSSL 1.0 and OpenSSL 1.1 ## On OpenSSL man page we can read: ## EVP_MD_CTX_create() and EVP_MD_CTX_destroy() were renamed to EVP_MD_CTX_new() and EVP_MD_CTX_free() in OpenSSL 1.1. ## So we need to check for all of them. AC_CHECK_HEADERS([openssl/aes.h openssl/bio.h openssl/evp.h openssl/hmac.h openssl/md5.h openssl/pem.h openssl/rand.h openssl/rsa.h openssl/sha.h openssl/pem.h openssl/x509.h]) # OpenSSL has been installed under at least two different names... AC_CHECK_LIB([crypto],[EVP_get_digestbyname]) AC_CHECK_LIB([ssl],[SSL_library_init]) AC_CHECK_FUNCS([EVP_get_digestbyname],, AC_MSG_ERROR([SSL/OpenSSL support required])) AC_CHECK_FUNCS([EVP_MD_CTX_new EVP_MD_CTX_free]) tcpflow-tcpflow-1.6.1/src/be13_api/dfxml/src/dfxml_writer.cpp000066400000000000000000000475201401360461700241500ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * implementation for C++ XML generation class * * The software provided here is released by the Naval Postgraduate * School, an agency of the U.S. Department of Navy. The software * bears no warranty, either expressed or implied. NPS does not assume * legal liability nor responsibility for a User's use of the software * or the results of such use. * * Please note that within the United States, copyright protection, * under Section 105 of the United States Code, Title 17, is not * available for any work of the United States Government and/or for * any works created by United States Government employees. User * acknowledges that this software contains work which was created by * NPS government employees and is therefore in the public domain and * not subject to copyright. */ #include "config.h" #ifdef HAVE_WINSOCK2_H #include #endif #include #include #ifdef HAVE_SQLITE3_H #include #endif #ifdef HAVE_BOOST_VERSION_HPP #include #endif #ifdef HAVE_PTHREAD #define MUTEX_INIT(M) pthread_mutex_init(M,NULL); #define MUTEX_LOCK(M) pthread_mutex_lock(M) #define MUTEX_UNLOCK(M) pthread_mutex_unlock(M) #else #define MUTEX_INIT(M) {} #define MUTEX_LOCK(M) {} #define MUTEX_UNLOCK(M) {} #endif #ifdef HAVE_TRE_TRE_H #include #endif #include #include #include #include #include #include #include #include #include #include #ifdef _MSC_VER # include #else # include #endif using namespace std; #include "dfxml_writer.h" static const char *xml_header = "\n"; // Implementation of mkstemp for windows found on pan-devel mailing // list archive // @http://www.mail-archive.com/pan-devel@nongnu.org/msg00294.html #ifndef _S_IREAD #define _S_IREAD 256 #endif #ifndef _S_IWRITE #define _S_IWRITE 128 #endif #ifndef O_BINARY #define O_BINARY 0 #endif #ifndef _O_SHORT_LIVED #define _O_SHORT_LIVED 0 #endif #ifndef HAVE_MKSTEMP int mkstemp(char *tmpl) { int ret=-1; mktemp(tmpl); ret=open(tmpl,O_RDWR|O_BINARY|O_CREAT|O_EXCL|_O_SHORT_LIVED, _S_IREAD|_S_IWRITE); return ret; } #endif #ifndef O_BINARY #define O_BINARY 0 #endif #ifndef _O_SHORT_LIVED #define _O_SHORT_LIVED 0 #endif //std::string dfxml_writer::xml_PRId32("%" PRId32); // gets around compiler bug //std::string dfxml_writer::xml_PRIu32("%" PRIu32); // gets around compiler bug //std::string dfxml_writer::xml_PRId64("%" PRId64); // gets around compiler bug //std::string dfxml_writer::xml_PRIu64("%" PRIu64); // gets around compiler bug static const char *cstr(const string &str){ return str.c_str(); } // XML escapes static string xml_lt("<"); static string xml_gt(">"); static string xml_am("&"); static string xml_ap("'"); static string xml_qu("""); // % encodings static string encoding_null("%00"); static string encoding_r("%0D"); static string encoding_n("%0A"); static string encoding_t("%09"); std::string dfxml_writer::xmlescape(const string &xml) { string ret; for(string::const_iterator i = xml.begin(); i!=xml.end(); i++){ switch(*i){ // XML escapes case '>': ret += xml_gt; break; case '<': ret += xml_lt; break; case '&': ret += xml_am; break; case '\'': ret += xml_ap; break; case '"': ret += xml_qu; break; // % encodings case '\000': ret += encoding_null; break; // retain encoded nulls case '\r': ret += encoding_r; break; case '\n': ret += encoding_n; break; case '\t': ret += encoding_t; break; default: ret += *i; } } return ret; } /** * Strip an XML string as necessary for a tag name. */ std::string dfxml_writer::xmlstrip(const string &xml) { string ret; for(string::const_iterator i = xml.begin(); i!=xml.end(); i++){ if(isprint(*i) && !strchr("<>\r\n&'\"",*i)){ ret += isspace(*i) ? '_' : tolower(*i); } } return ret; } /** * xmlmap: * Turns a map into a blob of XML. */ std::string dfxml_writer::xmlmap(const dfxml_writer::strstrmap_t &m,const std::string &outer,const std::string &attrs) { std::stringstream ss; ss << "<" << outer; if(attrs.size()>0) ss << " " << attrs; ss << ">"; for(std::map::const_iterator it=m.begin();it!=m.end();it++){ ss << "<" << (*it).first << ">" << xmlescape((*it).second) << ""; } ss << ""; return ss.str(); } /* This goes to stdout */ dfxml_writer::dfxml_writer():M(),outf(),out(&cout),tags(),tag_stack(),tempfilename(),tempfile_template("/tmp/xml_XXXXXXXX"), t0(),t_last_timestamp(),make_dtd(false),outfilename(),oneline() { #ifdef HAVE_PTHREAD pthread_mutex_init(&M,NULL); #endif gettimeofday(&t0,0); gettimeofday(&t_last_timestamp,0); *out << xml_header; } /* This should be rewritten so that the temp file is done on close, not on open */ dfxml_writer::dfxml_writer(const std::string &outfilename_,bool makeDTD): M(),outf(outfilename_.c_str(),ios_base::out), out(),tags(),tag_stack(),tempfilename(),tempfile_template(outfilename_+"_tmp_XXXXXXXX"), t0(),t_last_timestamp(),make_dtd(false),outfilename(outfilename_),oneline() { MUTEX_INIT(&M); gettimeofday(&t0,0); gettimeofday(&t_last_timestamp,0); if(!outf.is_open()){ perror(outfilename_.c_str()); exit(1); } out = &outf; // use this one instead *out << xml_header; } void dfxml_writer::set_tempfile_template(const std::string &temp) { tempfile_template = temp; } void dfxml_writer::close() { MUTEX_LOCK(&M); outf.close(); if(make_dtd){ /* If we are making the DTD, then we should close the file, * scan the output file for the tags, write to a temp file, and then * close the temp file and have it overwrite the outfile. */ std::ifstream in(cstr(tempfilename)); if(!in.is_open()){ cerr << tempfilename << strerror(errno) << ":Cannot re-open for input\n"; exit(1); } outf.open(cstr(outfilename),ios_base::out); if(!outf.is_open()){ cerr << outfilename << " " << strerror(errno) << ": Cannot open for output; will not delete " << tempfilename << "\n"; exit(1); } // copy over first line --- the XML header std::string line; getline(in,line); outf << line; write_dtd(); // write the DTD while(!in.eof()){ getline(in,line); outf << line << endl; } in.close(); unlink(cstr(tempfilename)); outf.close(); } MUTEX_UNLOCK(&M); } void dfxml_writer::write_dtd() { *out << "::const_iterator it = tags.begin(); it != tags.end(); it++){ *out << "\n"; } *out << "\n"; *out << "\n"; *out << "\n"; *out << "]>\n"; } /** * make sure that a tag is valid and, if so, add it to the list of tags we use */ void dfxml_writer::verify_tag(string tag) { if(tag[0]=='/') tag = tag.substr(1); if(tag.find(" ") != string::npos){ cerr << "tag '" << tag << "' contains space. Cannot continue.\n"; exit(1); } tags.insert(tag); } void dfxml_writer::puts(const string &v) { *out << v; } void dfxml_writer::spaces() { for(unsigned int i=0;i0) *out << " " << attribute; *out << ">"; } #if (!defined(HAVE_VASPRINTF)) || defined(_WIN32) #ifndef _WIN32 #define ms_printf __print #define __MINGW_ATTRIB_NONNULL(x) #endif extern "C" { /** * We do not have vasprintf. * We have determined that vsnprintf() does not perform properly on windows. * So we just allocate a huge buffer and then strdup() and hope! */ int vasprintf(char **ret,const char *fmt,va_list ap) __attribute__((__format__(ms_printf, 2, 0))) __MINGW_ATTRIB_NONNULL(2) ; int vasprintf(char **ret,const char *fmt,va_list ap) { /* Figure out how long the result will be */ char buf[65536]; int size = vsnprintf(buf,sizeof(buf),fmt,ap); if(size<0) return size; /* Now allocate the memory */ *ret = strcpy((char *) malloc(strlen(buf)+1), buf); return size; } } #endif void dfxml_writer::printf(const char *fmt,...) { va_list ap; va_start(ap, fmt); /** printf to stream **/ char *ret = 0; if(vasprintf(&ret,fmt,ap) < 0){ *out << "dfxml_writer::xmlprintf: " << strerror(errno); exit(EXIT_FAILURE); } *out << ret; free(ret); /** end printf to stream **/ va_end(ap); } void dfxml_writer::push(const string &tag,const string &attribute) { spaces(); tag_stack.push(tag); tagout(tag,attribute); if(!oneline) *out << '\n'; } void dfxml_writer::pop() { assert(tag_stack.size()>0); string tag = tag_stack.top(); tag_stack.pop(); spaces(); tagout("/"+tag,""); *out << '\n'; } void dfxml_writer::set_oneline(bool v) { if(v==true) spaces(); if(v==false) *out << "\n"; oneline = v; } void dfxml_writer::cpuid(uint32_t op, unsigned long *eax, unsigned long *ebx, unsigned long *ecx, unsigned long *edx) { #if defined(HAVE_ASM_CPUID) && defined(__i386__) #if defined(__PIC__) __asm__ __volatile__("pushl %%ebx \n\t" /* save %ebx */ "cpuid \n\t" "movl %%ebx, %1 \n\t" /* save what cpuid just put in %ebx */ "popl %%ebx \n\t" /* restore the old %ebx */ : "=a"(*eax), "=r"(*ebx), "=c"(*ecx), "=d"(*edx) : "a"(op) : "cc"); #else __asm__ __volatile__("cpuid" : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx) : "a"(op) : "cc"); #endif #endif } void dfxml_writer::add_cpuid() { #if defined(__i386__) #ifndef __WORDSIZE #define __WORDSIZE 32 #endif #define BFIX(val, base, end) ((val << (__WORDSIZE-end-1)) >> (__WORDSIZE-end+base-1)) char buf[256]; unsigned long eax=0, ebx=0, ecx=0, edx=0; // =0 avoids a compiler warning cpuid(0, &eax, &ebx, &ecx, &edx); snprintf(buf,sizeof(buf),"%.4s%.4s%.4s", (char *)&ebx, (char *)&edx, (char *)&ecx); push("cpuid"); xmlout("identification",buf); cpuid(1, &eax, &ebx, &ecx, &edx); xmlout("family", (int64_t) BFIX(eax, 8, 11)); xmlout("model", (int64_t) BFIX(eax, 4, 7)); xmlout("stepping", (int64_t) BFIX(eax, 0, 3)); xmlout("efamily", (int64_t) BFIX(eax, 20, 27)); xmlout("emodel", (int64_t) BFIX(eax, 16, 19)); xmlout("brand", (int64_t) BFIX(ebx, 0, 7)); xmlout("clflush_size", (int64_t) BFIX(ebx, 8, 15) * 8); xmlout("nproc", (int64_t) BFIX(ebx, 16, 23)); xmlout("apicid", (int64_t) BFIX(ebx, 24, 31)); cpuid(0x80000006, &eax, &ebx, &ecx, &edx); xmlout("L1_cache_size", (int64_t) BFIX(ecx, 16, 31) * 1024); pop(); #undef BFIX #endif } void dfxml_writer::add_DFXML_execution_environment(const std::string &command_line) { push("execution_environment"); #if defined(HAVE_ASM_CPUID) && defined(__i386__) add_cpuid(); #endif #ifdef HAVE_SYS_UTSNAME_H struct utsname name; if(uname(&name)==0){ xmlout("os_sysname",name.sysname); xmlout("os_release",name.release); xmlout("os_version",name.version); xmlout("host",name.nodename); xmlout("arch",name.machine); } #else #ifdef UNAMES xmlout("os_sysname",UNAMES,"",false); #endif #ifdef HAVE_GETHOSTNAME { char hostname[1024]; if(gethostname(hostname,sizeof(hostname))==0){ xmlout("host",hostname); } } #endif #endif xmlout("command_line", command_line); // quote it! #ifdef HAVE_GETUID xmlprintf("uid","","%d",getuid()); #ifdef HAVE_GETPWUID xmlout("username",getpwuid(getuid())->pw_name); #endif #endif #define TM_FORMAT "%Y-%m-%dT%H:%M:%SZ" char buf[256]; time_t t = time(0); strftime(buf,sizeof(buf),TM_FORMAT,gmtime(&t)); xmlout("start_time",buf); pop(); // } #ifdef WIN32 #include "psapi.h" #endif void dfxml_writer::add_rusage() { #ifdef WIN32 /* Note: must link -lpsapi for this */ PROCESS_MEMORY_COUNTERS_EX pmc; memset(&pmc,0,sizeof(pmc)); GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS *)&pmc, sizeof(pmc)); push("PROCESS_MEMORY_COUNTERS"); xmlout("cb",(int64_t)pmc.cb); xmlout("PageFaultCount",(int64_t)pmc.PageFaultCount); xmlout("WorkingSetSize",(int64_t)pmc.WorkingSetSize); xmlout("QuotaPeakPagedPoolUsage",(int64_t)pmc.QuotaPeakPagedPoolUsage); xmlout("QuotaPagedPoolUsage",(int64_t)pmc.QuotaPagedPoolUsage); xmlout("QuotaPeakNonPagedPoolUsage",(int64_t)pmc.QuotaPeakNonPagedPoolUsage); xmlout("PagefileUsage",(int64_t)pmc.PagefileUsage); xmlout("PeakPagefileUsage",(int64_t)pmc.PeakPagefileUsage); xmlout("PrivateUsage",(int64_t)pmc.PrivateUsage); pop(); #endif #ifdef HAVE_GETRUSAGE struct rusage ru; memset(&ru,0,sizeof(ru)); if(getrusage(RUSAGE_SELF,&ru)==0){ push("rusage"); xmlout("utime",ru.ru_utime); xmlout("stime",ru.ru_stime); xmloutl("maxrss",(long)ru.ru_maxrss); xmloutl("minflt",(long)ru.ru_minflt); xmloutl("majflt",(long)ru.ru_majflt); xmloutl("nswap",(long)ru.ru_nswap); xmloutl("inblock",(long)ru.ru_inblock); xmloutl("oublock",(long)ru.ru_oublock); struct timeval t1; gettimeofday(&t1,0); struct timeval t; t.tv_sec = t1.tv_sec - t0.tv_sec; if(t1.tv_usec > t0.tv_usec){ t.tv_usec = t1.tv_usec - t0.tv_usec; } else { t.tv_sec--; t.tv_usec = (t1.tv_usec+1000000) - t0.tv_usec; } xmlout("clocktime",t); pop(); } #endif } void dfxml_writer::add_timestamp(const std::string &name) { struct timeval t1; gettimeofday(&t1,0); struct timeval t; // timestamp delta against t_last_timestamp t.tv_sec = t1.tv_sec - t_last_timestamp.tv_sec; if(t1.tv_usec > t_last_timestamp.tv_usec){ t.tv_usec = t1.tv_usec - t_last_timestamp.tv_usec; } else { t.tv_sec--; t.tv_usec = (t1.tv_usec+1000000) - t_last_timestamp.tv_usec; } char delta[16]; snprintf(delta, 16, "%d.%06d", (int)t.tv_sec, (int)t.tv_usec); // reset t_last_timestamp for the next invocation gettimeofday(&t_last_timestamp,0); // timestamp total t.tv_sec = t1.tv_sec - t0.tv_sec; if(t1.tv_usec > t0.tv_usec){ t.tv_usec = t1.tv_usec - t0.tv_usec; } else { t.tv_sec--; t.tv_usec = (t1.tv_usec+1000000) - t0.tv_usec; } char total[16]; snprintf(total, 16, "%d.%06d", (int)t.tv_sec, (int)t.tv_usec); // prepare attributes std::stringstream ss; ss << "name='" << name << "' delta='" << delta << "' total='" << total << "'"; // add named timestamp xmlout("timestamp", "",ss.str(), true); } /**************************************************************** *** THESE ARE THE ONLY THREADSAFE ROUTINES ****************************************************************/ void dfxml_writer::comment(const string &comment_) { MUTEX_LOCK(&M); *out << "\n"; out->flush(); MUTEX_UNLOCK(&M); } void dfxml_writer::xmlprintf(const std::string &tag,const std::string &attribute, const char *fmt,...) { MUTEX_LOCK(&M); spaces(); tagout(tag,attribute); va_list ap; va_start(ap, fmt); /** printf to stream **/ char *ret = 0; if(vasprintf(&ret,fmt,ap) < 0){ cerr << "dfxml_writer::xmlprintf: " << strerror(errno) << "\n"; exit(EXIT_FAILURE); } *out << ret; free(ret); /** end printf to stream **/ va_end(ap); tagout("/"+tag,""); *out << '\n'; out->flush(); MUTEX_UNLOCK(&M); } void dfxml_writer::xmlout(const string &tag,const string &value,const string &attribute,bool escape_value) { MUTEX_LOCK(&M); spaces(); if(value.size()==0){ if(tag.size()) tagout(tag,attribute+"/"); } else { if(tag.size()) tagout(tag,attribute); *out << (escape_value ? xmlescape(value) : value); if(tag.size()) tagout("/"+tag,""); } *out << "\n"; out->flush(); MUTEX_UNLOCK(&M); } #ifdef HAVE_LIBEWF_H #include #endif #if defined(HAVE_EXIV2) && defined(HAVE_EXIV2_IMAGE_HPP) #ifdef DFXML_GNUC_HAS_DIAGNOSTIC_PRAGMA #pragma GCC diagnostic ignored "-Wshadow" #pragma GCC diagnostic ignored "-Weffc++" #endif #include #include #include #endif #ifdef HAVE_HASHDB #include #endif #ifdef HAVE_AFFLIB_AFFLIB_H //#pragma GCC diagnostic ignored "-Wreserved-user-defined-literal" // required for C11 #include #endif /* These support Digital Forensics XML and require certain variables to be defined */ void dfxml_writer::add_DFXML_build_environment() { /* __DATE__ formats as: Apr 30 2011 */ struct tm tm; memset(&tm,0,sizeof(tm)); push("build_environment"); #ifdef __GNUC__ // See http://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html xmlprintf("compiler","","%d.%d.%d (%s)",__GNUC__, __GNUC_MINOR__,__GNUC_PATCHLEVEL__,__VERSION__); #endif #ifdef CPPFLAGS xmlout("CPPFLAGS",CPPFLAGS,"",true); #endif #ifdef CFLAGS xmlout("CFLAGS",CFLAGS,"",true); #endif #ifdef CXXFLAGS xmlout("CXXFLAGS",CXXFLAGS,"",true); #endif #ifdef LDFLAGS xmlout("LDFLAGS",LDFLAGS,"",true); #endif #ifdef LIBS xmlout("LIBS",LIBS,"",true); #endif #if defined(__DATE__) && defined(__TIME__) && defined(HAVE_STRPTIME) if(strptime(__DATE__,"%b %d %Y",&tm)){ char buf[64]; snprintf(buf,sizeof(buf),"%4d-%02d-%02dT%s",tm.tm_year+1900,tm.tm_mon+1,tm.tm_mday,__TIME__); xmlout("compilation_date",buf); } #endif #ifdef BOOST_VERSION { char buf[64]; snprintf(buf,sizeof(buf),"%d",BOOST_VERSION); xmlout("library", "", std::string("name=\"boost\" version=\"") + buf + "\"",false); } #endif #ifdef HAVE_LIBTSK3 xmlout("library", "", std::string("name=\"tsk\" version=\"") + tsk_version_get_str() + "\"",false); #endif #ifdef HAVE_LIBAFFLIB xmlout("library", "", std::string("name=\"afflib\" version=\"") + af_version() +"\"",false); #endif #ifdef HAVE_LIBEWF xmlout("library", "", std::string("name=\"libewf\" version=\"") + libewf_get_version() + "\"",false); #endif #ifdef HAVE_EXIV2 xmlout("library", "", std::string("name=\"exiv2\" version=\"") + Exiv2::version() + "\"",false); #endif #if defined(HAVE_LIBTRE) && defined(HAVE_TRE_VERSION) && defined(HAVE_TRE_TRE_H) xmlout("library", "", std::string("name=\"tre\" version=\"") + tre_version() + "\"",false); #endif #ifdef HAVE_HASHDB xmlout("library", "", std::string("name=\"hashdb\" version=\"") + hashdb_version() + "\"",false); #endif #ifdef SQLITE_VERSION xmlout("library", "", "name=\"sqlite\" version=\"" SQLITE_VERSION "\" source_id=\"" SQLITE_SOURCE_ID "\"",false); #endif #ifdef HAVE_GNUEXIF // gnuexif does not have a programmatically obtainable version. xmlout("library","","name=\"gnuexif\" version=\"?\"",false); #endif #ifdef GIT_COMMIT xmlout("git", "", "commit=\"" GIT_COMMIT "\"",false); #endif pop(); } tcpflow-tcpflow-1.6.1/src/be13_api/dfxml/src/dfxml_writer.h000066400000000000000000000174511401360461700236150ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /* * Simson's XML output class. * Include this AFTER your config file with the HAVE statements. * Optimized for DFXML generation. */ #ifndef _DFXML_WRITER_H_ #define _DFXML_WRITER_H_ #ifndef __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS #endif #include #include #include #include #include #include /* c++ */ #include #include #include #include #include #include #ifdef HAVE_PTHREAD #include #endif #ifdef HAVE_SYS_CDEFS_H #include #endif #ifdef HAVE_SYS_RESOURCE_H #include #endif #ifdef HAVE_PWD_H #include #endif #ifdef HAVE_SYS_UTSNAME_H #include #endif #ifndef __BEGIN_DECLS #if defined(__cplusplus) #define __BEGIN_DECLS extern "C" { #define __END_DECLS } #else #define __BEGIN_DECLS #define __END_DECLS #endif #endif #ifdef HAVE_LIBTSK3 #include #endif #ifdef __cplusplus #include "cppmutex.h" class dfxml_writer { private: /*** neither copying nor assignment is implemented *** *** We do this by making them private constructors that throw exceptions. ***/ dfxml_writer(const dfxml_writer &); dfxml_writer &operator=(const dfxml_writer &); /****************************************************************/ public: typedef std::map strstrmap_t; typedef std::set stringset; typedef std::set tagid_set_t; private: #ifdef HAVE_PTHREAD pthread_mutex_t M; // mutext protecting out #else int M; // placeholder #endif std::fstream outf; std::ostream *out; // where it is being written; defaulst to stdout stringset tags; // XML tags std::stacktag_stack; std::string tempfilename; std::string tempfile_template; struct timeval t0; struct timeval t_last_timestamp; // for creating delta timestamps bool make_dtd; std::string outfilename; void write_doctype(std::fstream &out); void write_dtd(); void verify_tag(std::string tag); void spaces(); // print spaces corresponding to tag stack //static std::string xml_PRId32; // for compiler bug //static std::string xml_PRIu32; // for compiler bug //static std::string xml_PRId64; // for compiler bug //static std::string xml_PRIu64; // for compiler bug bool oneline; public: static std::string make_command_line(int argc,char * const *argv){ std::string command_line; for(int i=0;i0) command_line.push_back(' '); if (strchr(argv[i],' ') != NULL) { // the argument has a space, so quote the argument command_line.append("\""); command_line.append(argv[i]); command_line.append("\""); } else { // the argument has no space, so append as is command_line.append(argv[i]); } } return command_line; } dfxml_writer(); // defaults to stdout dfxml_writer(const std::string &outfilename,bool makeDTD); // write to a file, optionally making a DTD virtual ~dfxml_writer(){}; void set_tempfile_template(const std::string &temp); static std::string xmlescape(const std::string &xml); static std::string xmlstrip(const std::string &xml); /** xmlmap turns a map into an XML block */ static std::string xmlmap(const strstrmap_t &m,const std::string &outer,const std::string &attrs); void close(); // writes the output to the file void flush(){outf.flush();} void tagout( const std::string &tag,const std::string &attribute); void push(const std::string &tag,const std::string &attribute); void push(const std::string &tag) {push(tag,"");} // writes a std::string as parsed data void puts(const std::string &pdata); // writes a std::string as parsed data void printf(const char *fmt,...) __attribute__((format(printf, 2, 3))); // "2" because this is "1" void pop(); // close the tag void add_timestamp(const std::string &name); void add_DFXML_build_environment(); static void cpuid(uint32_t op, unsigned long *eax, unsigned long *ebx,unsigned long *ecx, unsigned long *edx); void add_cpuid(); void add_DFXML_execution_environment(const std::string &command_line); void add_DFXML_creator(const std::string &program,const std::string &version, const std::string &svn_r, const std::string &command_line){ push("creator","version='1.0'"); xmlout("program",program); xmlout("version",version); if(svn_r.size()>0) xmlout("svn_version",svn_r); add_DFXML_build_environment(); add_DFXML_execution_environment(command_line); pop(); // creator } void add_rusage(); void set_oneline(bool v); const std::string &get_outfilename() const {return outfilename; } ; /******************************** *** THESE ARE ALL THREADSAFE *** ********************************/ void comment(const std::string &comment); void xmlprintf(const std::string &tag,const std::string &attribute,const char *fmt,...) __attribute__((format(printf, 4, 5))); // "4" because this is "1"; void xmlout( const std::string &tag,const std::string &value, const std::string &attribute, const bool escape_value); /* These all call xmlout or xmlprintf which already has locking, so these are all threadsafe! */ void xmlout( const std::string &tag,const std::string &value){ xmlout(tag,value,"",true); } // void xmlout( const std::string &tag,const int value){ xmlprintf(tag,"","%d",value); } void xmloutl(const std::string &tag,const long value){ xmlprintf(tag,"","%ld",value); } #ifdef WIN32 void xmlout( const std::string &tag,const int32_t value){ xmlprintf(tag,"","%I32d",value); } void xmlout( const std::string &tag,const uint32_t value){ xmlprintf(tag,"","%I32u",value); } void xmlout( const std::string &tag,const int64_t value){ xmlprintf(tag,"","%I64d",value); } void xmlout( const std::string &tag,const uint64_t value){ xmlprintf(tag,"","%I64u",value); } #else void xmlout( const std::string &tag,const int32_t value){ xmlprintf(tag,"","%" PRId32,value); } void xmlout( const std::string &tag,const uint32_t value){ xmlprintf(tag,"","%" PRIu32,value); } void xmlout( const std::string &tag,const int64_t value){ xmlprintf(tag,"","%" PRId64,value); } void xmlout( const std::string &tag,const uint64_t value){ xmlprintf(tag,"","%" PRIu64,value); } #ifdef __APPLE__ void xmlout( const std::string &tag,const size_t value){ xmlprintf(tag,"","%" PRIu64,(unsigned long long)value); } #endif #endif void xmlout( const std::string &tag,const double value){ xmlprintf(tag,"","%f",value); } void xmlout( const std::string &tag,const struct timeval &ts) { xmlprintf(tag,"","%d.%06d",(int)ts.tv_sec, (int)ts.tv_usec); } static std::string to8601(const struct timeval &ts) { struct tm tm; char buf[64]; #ifdef HAVE_GMTIME_R gmtime_r(&ts.tv_sec,&tm); #else time_t t = ts.tv_sec; struct tm *tmp; tmp = gmtime(&t); if(!tmp) return std::string("INVALID"); tm = *tmp; #endif strftime(buf,sizeof(buf),"%Y-%m-%dT%H:%M:%S",&tm); if(ts.tv_usec>0){ int len = strlen(buf); snprintf(buf+len,sizeof(buf)-len,".%06d",(int)ts.tv_usec); } strcat(buf,"Z"); return std::string(buf); } }; #endif #endif tcpflow-tcpflow-1.6.1/src/be13_api/dfxml/src/hash_t.h000066400000000000000000000200761401360461700223520ustar00rootroot00000000000000/* * C++ covers for md5, sha1, and sha256 (and sha512 if present) * * hash representation classes: md5_t, sha1_t, sha256_t (sha512_t) * has generators: md5_generator(), sha1_generator(), sha256_generator() * * Generating a hash: * sha1_t val = sha1_generator::hash_buf(buf,bufsize) * sha1_t generator hasher; * hasher.update(buf,bufsize) * hasher.update(buf,bufsize) * hasher.update(buf,bufsize) * sha1_t val = hasher.final() * * Using the values: * string val.hexdigest() --- return a hext digest * val.size() --- the size of the hash in bytes * uint8_t val.digest[SIZE] --- the buffer of the raw bytes * uint8_t val.final() --- synonym for md.digest * * This can be updated in the future for Mac so that the hash__ class * is then subclassed by a hash__openssl or a hash__commonCrypto class. * * * Revision History: * 2012 - Simson L. Garfinkel - Created for bulk_extractor. * * This file is public domain */ #ifndef HASH_T_H #define HASH_T_H #include #include /** * For reasons that defy explanation (at the moment), this is required. */ #ifdef __APPLE__ #include #undef DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER #define DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER #endif #include #include #include #include #include #include #include #if defined(HAVE_OPENSSL_HMAC_H) && defined(HAVE_OPENSSL_EVP_H) #include #include #else #error OpenSSL required for hash_t.h #endif #ifdef HAVE_SYS_MMAN_H #include #endif #ifdef HAVE_SYS_MMAP_H #include #endif template class hash__ { public: uint8_t digest[SIZE]; static size_t size() { return(SIZE); } hash__(){ } hash__(const uint8_t *provided){ memcpy(this->digest,provided,size()); } const uint8_t *final() const { return this->digest; } /* python like interface for hexdigest */ static unsigned int hex2int(char ch){ if(ch>='0' && ch<='9') return ch-'0'; if(ch>='a' && ch<='f') return ch-'a'+10; if(ch>='A' && ch<='F') return ch-'A'+10; return 0; } static unsigned int hex2int(char ch0,char ch1){ return (hex2int(ch0)<<4) | hex2int(ch1); } static hash__ fromhex(const std::string &hexbuf) { hash__ res; assert(hexbuf.size()==SIZE*2); for(unsigned int i=0;i+1=3;i++){ snprintf(hexbuf,bufsize,"%02x",this->digest[i]); hexbuf += 2; bufsize -= 2; } return hexbuf_start; } std::string hexdigest() const { std::string ret; char buf[SIZE*2+1]; return std::string(hexdigest(buf,sizeof(buf))); } /** * Convert a hex representation to binary, and return * the number of bits converted. * @param binbuf output buffer * @param binbuf_size size of output buffer in bytes. * @param hex input buffer (in hex) * @return the number of converted bits. */ static int hex2bin(uint8_t *binbuf,size_t binbuf_size,const char *hex) { int bits = 0; while(hex[0] && hex[1] && binbuf_size>0){ *binbuf++ = hex2int(hex[0],hex[1]); hex += 2; bits += 8; binbuf_size -= 1; } return bits; } static const hash__ *new_from_hex(const char *hex) { hash__ *val = new hash__(); if(hex2bin(val->digest,sizeof(val->digest),hex)!=SIZE*8){ std::cerr << "invalid input " << hex << "(" << SIZE*8 << ")\n"; exit(1); } return val; } bool operator<(const hash__ &s2) const { /* Check the first byte manually as a performance hack */ if(this->digest[0] < s2.digest[0]) return true; if(this->digest[0] > s2.digest[0]) return false; return memcmp(this->digest,s2.digest, SIZE) < 0; } bool operator==(const hash__ &s2) const { if(this->digest[0] != s2.digest[0]) return false; return memcmp(this->digest,s2.digest, SIZE) == 0; } friend std::ostream& operator<<(std::ostream& os,const hash__ &s2) { os << s2.hexdigest(); return os; } }; typedef hash__ md5_t; typedef hash__ sha1_t; typedef hash__ sha256_t; #ifdef HAVE_EVP_SHA512 typedef hash__ sha512_t; #endif template inline std::string digest_name(); template<> inline std::string digest_name() { return "MD5"; } template<> inline std::string digest_name() { return "SHA1"; } template<> inline std::string digest_name() { return "SHA256"; } #ifdef HAVE_EVP_SHA512 template<> inline std::string digest_name() { return "SHA512"; } #endif template class hash_generator__ { /* generates the hash */ private: EVP_MD_CTX* mdctx; /* the context for computing the value */ bool initialized; /* has the context been initialized? */ bool finalized; /* Static function to determine if something is zero */ static bool iszero(const uint8_t *buf,size_t bufsize){ for(unsigned int i=0;i final() { if(finalized){ std::cerr << "currently friendly_geneator does not cache the final value\n"; assert(0); exit(1); // in case compiled with assertions disabled } if(!initialized){ init(); /* do it now! */ } hash__ val; unsigned int len = sizeof(val.digest); EVP_DigestFinal(mdctx,val.digest,&len); finalized = true; return val; } /** Compute a sha1 from a buffer and return the hash */ static hash__ hash_buf(const uint8_t *buf,size_t bufsize){ /* First time through find the SHA1 of 512 NULLs */ hash_generator__ g; g.update(buf,bufsize); return g.final(); } #ifdef HAVE_MMAP /** Static method allocateor */ static hash__ hash_file(const char *fname){ int fd = open(fname,O_RDONLY #ifdef O_BINARY |O_BINARY #endif ); if(fd<0) throw fname; struct stat st; if(fstat(fd,&st)<0){ close(fd); throw fname; } const uint8_t *buf = (const uint8_t *)mmap(0,st.st_size,PROT_READ,MAP_FILE|MAP_SHARED,fd,0); if(buf==0){ close(fd); throw fname; } hash__ s = hash_buf(buf,st.st_size); munmap((void *)buf,st.st_size); close(fd); return s; } #endif }; typedef hash_generator__ md5_generator; typedef hash_generator__ sha1_generator; typedef hash_generator__ sha256_generator; #ifdef HAVE_EVP_SHA512 typedef hash_generator__ sha512_generator; #define HAVE_SHA512_T #endif #endif tcpflow-tcpflow-1.6.1/src/be13_api/feature_recorder.cpp000066400000000000000000000772411401360461700230640ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ #include "config.h" #include "bulk_extractor_i.h" #include "unicode_escape.h" #include "histogram.h" #include #include #include #ifdef HAVE_STDARG_H #include #endif #ifndef MAXPATHLEN #define MAXPATHLEN 65536 #endif #ifndef O_BINARY #define O_BINARY 0 #endif #ifndef DEBUG_PEDANTIC #define DEBUG_PEDANTIC 0x0001// check values more rigorously #endif #ifndef WIN32 pthread_t feature_recorder::main_threadid = 0; #endif size_t feature_recorder::context_window_default=16; /* number of bytes of context */ int64_t feature_recorder::offset_add = 0; std::string feature_recorder::banner_file; uint32_t feature_recorder::opt_max_context_size=1024*1024; uint32_t feature_recorder::opt_max_feature_size=1024*1024; uint32_t feature_recorder::debug=0; /** * Create a feature recorder object. Each recorder records a certain * kind of feature. Features are stored in a file. The filename is * permutated based on the total number of threads and the current * thread that's recording. Each thread records to a different file, * and thus a different feature recorder, to avoid locking * problems. * * @param feature_recorder_set &fs - common information for all of the feature recorders * @param name - the name of the feature being recorded. */ feature_recorder::feature_recorder(class feature_recorder_set &fs_, const std::string &name_): flags(0), name(name_),ignore_encoding(),ios(),bs(), histogram_defs(), fs(fs_), count_(0),context_window_before(context_window_default),context_window_after(context_window_default), Mf(),Mr(),mhistograms(),mhistogram_limit(), stop_list_recorder(0), file_number_(0),carve_cache(),carve_mode(CARVE_ENCODED) { //std::cerr << "feature_recorder(" << name << ") created\n"; open(); // open if we are created } /* Don't have to delete the stop_list_recorder because it is in the * feature_recorder_set and will be separately deleted. */ feature_recorder::~feature_recorder() { if(ios.is_open()){ ios.close(); } } void feature_recorder::banner_stamp(std::ostream &os,const std::string &header) const { int banner_lines = 0; if(banner_file.size()>0){ std::ifstream i(banner_file.c_str()); if(i.is_open()){ std::string line; while(getline(i,line)){ if(line.size()>0 && ((*line.end()=='\r') || (*line.end()=='\n'))){ line.erase(line.end()); /* remove the last character while it is a \n or \r */ } os << "# " << line << "\n"; banner_lines++; } i.close(); } } if(banner_lines==0){ os << "# BANNER FILE NOT PROVIDED (-b option)\n"; } os << bulk_extractor_version_header; os << "# Feature-Recorder: " << name << "\n"; if(fs.get_input_fname().size()) os << "# Filename: " << fs.get_input_fname() << "\n"; if(debug!=0){ os << "# DEBUG: " << debug << " ("; if(debug & DEBUG_PEDANTIC) os << " DEBUG_PEDANTIC "; os << ")\n"; } os << header; } /** * Return the filename with a counter */ std::string feature_recorder::fname_counter(std::string suffix) const { return fs.get_outdir() + "/" + this->name + (suffix.size()>0 ? (std::string("_") + suffix) : "") + ".txt"; } const std::string &feature_recorder::get_outdir() const { return fs.get_outdir(); } /** * open a feature recorder file in the specified output directory. * Called by create_name(). Not clear why it isn't called when created. */ void feature_recorder::open() { if (fs.flag_set(feature_recorder_set::SET_DISABLED)) return; // feature recorder set is disabled /* write to a database? Create tables if necessary and create a prepared statement */ if (fs.flag_set(feature_recorder_set::ENABLE_SQLITE3_RECORDERS)) { char buf[1024]; fs.db_create_table(name); snprintf(buf,sizeof(buf),db_insert_stmt,name.c_str()); bs = new besql_stmt(fs.db3,buf); } /* Write to a file? Open the file and seek to the last line if it exist, otherwise just open database */ if (fs.flag_notset(feature_recorder_set::DISABLE_FILE_RECORDERS)){ /* Open the file recorder */ std::string fname = fname_counter(""); ios.open(fname.c_str(),std::ios_base::in|std::ios_base::out|std::ios_base::ate); if(ios.is_open()){ // opened existing stream ios.seekg(0L,std::ios_base::end); while(ios.is_open()){ /* Get current position */ if(int(ios.tellg())==0){ // at beginning of file; stamp and return ios.seekp(0L,std::ios_base::beg); // be sure we are at the beginning of the file return; } ios.seekg(-1,std::ios_base::cur); // backup to once less than the end of the file if (ios.peek()=='\n'){ // we are finally on the \n ios.seekg(1L,std::ios_base::cur); // move the getting one forward ios.seekp(ios.tellg(),std::ios_base::beg); // put the putter at the getter location count_ = 1; // greater than zero return; } } } // Just open the stream for output ios.open(fname.c_str(),std::ios_base::out); if(!ios.is_open()){ std::cerr << "*** feature_recorder::open CANNOT OPEN FEATURE FILE FOR WRITING " << fname << ":" << strerror(errno) << "\n"; exit(1); } } } void feature_recorder::close() { if(ios.is_open()){ ios.close(); } } void feature_recorder::flush() { cppmutex::lock lock(Mf); // get the lock; released when object is deallocated. ios.flush(); } static inline bool isodigit(char c) { return c>='0' && c<='7'; } /* statics */ const std::string feature_recorder::feature_file_header("# Feature-File-Version: 1.1\n"); const std::string feature_recorder::histogram_file_header("# Histogram-File-Version: 1.1\n"); const std::string feature_recorder::bulk_extractor_version_header("# " PACKAGE_NAME "-Version: " PACKAGE_VERSION " ($Rev: 10844 $)\n"); static inline int hexval(char ch) { switch (ch) { case '0': return 0; case '1': return 1; case '2': return 2; case '3': return 3; case '4': return 4; case '5': return 5; case '6': return 6; case '7': return 7; case '8': return 8; case '9': return 9; case 'a': case 'A': return 10; case 'b': case 'B': return 11; case 'c': case 'C': return 12; case 'd': case 'D': return 13; case 'e': case 'E': return 14; case 'f': case 'F': return 15; } return 0; } /** * Unquote Python or octal-style quoting of a string */ std::string feature_recorder::unquote_string(const std::string &s) { size_t len = s.size(); if(len<4) return s; // too small for a quote std::string out; for(size_t i=0;i= limit) return -1; return 0; } static int callback(void *ptr,const std::string &str,const uint64_t &tally) { return ((mhistogram_callback *)(ptr))->do_callback(str,tally); } }; /**************************************************************** *** PHASE HISTOGRAM (formerly phase 3): Create the histograms ****************************************************************/ /** * We now have three kinds of histograms: * 1 - Traditional post-processing histograms specified by the histogram library * 1a - feature-file based traditional ones * 1b - SQL-based traditional ones. * 2 - In-memory histograms (used primarily by beapi) */ /** Dump a specific histogram */ void feature_recorder::dump_histogram_file(const histogram_def &def,void *user,feature_recorder::dump_callback_t cb) const { /* This is a file based histogram. We will be reading from one file and writing to another */ std::string ifname = fname_counter(""); // source of features std::ifstream f(ifname.c_str()); if(!f.is_open()){ std::cerr << "Cannot open histogram input file: " << ifname << "\n"; return; } /* Read each line of the feature file and add it to the histogram. * If we run out of memory, dump that histogram to a file and start * on the next histogram. */ for(int histogram_counter = 0;histogram_counter0) real_suffix << histogram_counter; std::string ofname = fname_counter(real_suffix.str()); // histogram name std::ofstream o; o.open(ofname.c_str()); // open the file if(!o.is_open()){ std::cerr << "Cannot open histogram output file: " << ofname << "\n"; return; } HistogramMaker::FrequencyReportVector *fr = h.makeReport(); if(fr->size()>0){ banner_stamp(o,histogram_file_header); o << *fr; // sends the entire histogram } for(size_t i = 0;isize();i++){ delete fr->at(i); } delete fr; o.close(); if(f.is_open()==false){ return; // input file was closed } } std::cerr << "Looped " << max_histogram_files << " times on histogram; something seems wrong\n"; } void feature_recorder::dump_histogram(const histogram_def &def,void *user,feature_recorder::dump_callback_t cb) const { /* Inform that we are dumping this histogram */ if(cb) cb(user,*this,def,"",0); /* If this is a memory histogram, dump it and return */ mhistograms_t::const_iterator it = mhistograms.find(def); if(it!=mhistograms.end()){ assert(cb!=0); mhistogram_callback mcbo(user,cb,def,*this,mhistogram_limit); it->second->dump_sorted(static_cast(&mcbo),mhistogram_callback::callback); return; } if (fs.flag_set(feature_recorder_set::ENABLE_SQLITE3_RECORDERS)) { dump_histogram_db(def,user,cb); } if (fs.flag_notset(feature_recorder_set::DISABLE_FILE_RECORDERS)) { dump_histogram_file(def,user,cb); } } /* Dump all of this feature recorders histograms */ void feature_recorder::dump_histograms(void *user,feature_recorder::dump_callback_t cb, feature_recorder_set::xml_notifier_t xml_error_notifier) const { /* If we are recording features to SQL and we have a histogram defintion * for this feature recorder, we need to create a base histogram first, * then we can create the extracted histograms if they are presented. */ /* Loop through all the histograms and dump each one. * This now works for both memory histograms and non-memory histograms. */ for(histogram_defs_t::const_iterator it = histogram_defs.begin();it!=histogram_defs.end();it++){ try { dump_histogram((*it),user,cb); } catch (const std::exception &e) { std::cerr << "ERROR: histogram " << name << ": " << e.what() << "\n"; if(xml_error_notifier){ std::string error = std::string("p(maxsize); if(p.buf==0) return; va_list ap; va_start(ap,fmt); vsnprintf(p.buf,maxsize,fmt,ap); va_end(ap); this->write(p.buf); } /** * Combine the pos0, feature and context into a single line and write it to the feature file. * * @param feature - The feature, which is valid UTF8 (but may not be exactly the bytes on the disk) * @param context - The context, which is valid UTF8 (but may not be exactly the bytes on the disk) * * Interlocking is done in write(). */ void feature_recorder::write0(const pos0_t &pos0,const std::string &feature,const std::string &context) { if ( fs.flag_set(feature_recorder_set::ENABLE_SQLITE3_RECORDERS ) && this->flag_notset(feature_recorder::FLAG_NO_FEATURES_SQL) ) { db_write0( pos0, feature, context); } if ( fs.flag_notset(feature_recorder_set::DISABLE_FILE_RECORDERS )) { std::stringstream ss; ss << pos0.shift( feature_recorder::offset_add).str() << '\t' << feature; if (flag_notset( FLAG_NO_CONTEXT ) && ( context.size()>0 )) ss << '\t' << context; this->write( ss.str() ); } } /** * the main entry point of writing a feature and its context to the feature file. * processes the stop list */ void feature_recorder::quote_if_necessary(std::string &feature,std::string &context) { /* By default quote string that is not UTF-8, and quote backslashes. */ bool escape_bad_utf8 = true; bool escape_backslash = true; if(flags & FLAG_NO_QUOTE){ // don't quote either escape_bad_utf8 = false; escape_backslash = false; } if(flags & FLAG_XML){ // only quote bad utf8 escape_bad_utf8 = true; escape_backslash = false; } feature = validateOrEscapeUTF8(feature, escape_bad_utf8,escape_backslash); if(feature.size() > opt_max_feature_size) feature.resize(opt_max_feature_size); if(flag_notset(FLAG_NO_CONTEXT)){ context = validateOrEscapeUTF8(context,escape_bad_utf8,escape_backslash); if(context.size() > opt_max_context_size) context.resize(opt_max_context_size); } } /** * write() is the main entry point for writing a feature at a given position with context. * write() checks the stoplist and escapes non-UTF8 characters, then calls write0(). */ void feature_recorder::write(const pos0_t &pos0,const std::string &feature_,const std::string &context_) { if(flags & FLAG_DISABLED) return; // disabled if(debug & DEBUG_PEDANTIC){ if(feature_.size() > opt_max_feature_size){ std::cerr << "feature_recorder::write : feature_.size()=" << feature_.size() << "\n"; assert(0); } if(context_.size() > opt_max_context_size){ std::cerr << "feature_recorder::write : context_.size()=" << context_.size() << "\n"; assert(0); } } std::string feature = feature_; std::string context = flag_set(FLAG_NO_CONTEXT) ? "" : context_; std::string *feature_utf8 = HistogramMaker::make_utf8(feature); // a utf8 feature quote_if_necessary(feature,context); if(feature.size()==0){ std::cerr << name << ": zero length feature at " << pos0 << "\n"; if(debug & DEBUG_PEDANTIC) assert(0); return; } if(debug & DEBUG_PEDANTIC){ /* Check for tabs or newlines in feature and and context */ for(size_t i=0;icheck_feature_context(*feature_utf8,context)){ stop_list_recorder->write(pos0,feature,context); delete feature_utf8; return; } } /* The alert list is a special features that are called out. * If we have one of those, write it to the redlist. */ if(flag_notset(FLAG_NO_ALERTLIST) && fs.alert_list && fs.alert_list->check_feature_context(*feature_utf8,context)){ std::string alert_fn = fs.get_outdir() + "/ALERTS_found.txt"; cppmutex::lock lock(Mr); // notice we are locking the alert list std::ofstream rf(alert_fn.c_str(),std::ios_base::app); if(rf.is_open()){ rf << pos0.shift(feature_recorder::offset_add).str() << '\t' << feature << '\t' << "\n"; } } /* Support in-memory histograms */ for(mhistograms_t::iterator it = mhistograms.begin(); it!=mhistograms.end();it++){ const histogram_def &def = it->first; mhistogram_t *m = it->second; std::string new_feature = *feature_utf8; if(def.require.size()==0 || new_feature.find_first_of(def.require)!=std::string::npos){ /* If there is a pattern to use, use it */ if(def.pattern.size()){ if(!def.reg.search(new_feature,&new_feature,0,0)){ // no search match; avoid this feature new_feature = ""; } } if(new_feature.size()) m->add(new_feature,1); } } /* Finally write out the feature and the context */ if(flag_notset(FLAG_NO_FEATURES)){ this->write0(pos0,feature,context); } delete feature_utf8; } /** * Given a buffer, an offset into that buffer of the feature, and the length * of the feature, make the context and write it out. This is mostly used * for writing from within the lexical analyzers. */ void feature_recorder::write_buf(const sbuf_t &sbuf,size_t pos,size_t len) { #ifdef DEBUG_SCANNER if(debug & DEBUG_SCANNER){ std::cerr << "*** write_buf " << name << " sbuf=" << sbuf << " pos=" << pos << " len=" << len << "\n"; // for debugging, print Imagine that when pos= the location where the crash is happening. // then set a breakpoint at std::cerr. if(pos==9999999){ std::cerr << "Imagine that\n"; } } #endif /* If we are in the margin, ignore; it will be processed again */ if(pos >= sbuf.pagesize && pos < sbuf.bufsize){ return; } if(pos >= sbuf.bufsize){ /* Sanity checks */ std::cerr << "*** write_buf: WRITE OUTSIDE BUFFER. " << " pos=" << pos << " sbuf=" << sbuf << "\n"; return; } /* Asked to write beyond bufsize; bring it in */ if(pos+len > sbuf.bufsize){ len = sbuf.bufsize - pos; } std::string feature = sbuf.substr(pos,len); std::string context; if((flags & FLAG_NO_CONTEXT)==0){ /* Context write; create a clean context */ size_t p0 = context_window_before < pos ? pos-context_window_before : 0; size_t p1 = pos+len+context_window_after; if(p1>sbuf.bufsize) p1 = sbuf.bufsize; assert(p0<=p1); context = sbuf.substr(p0,p1-p0); } this->write(sbuf.pos0+pos,feature,context); #ifdef DEBUG_SCANNER if(debug & DEBUG_SCANNER){ std::cerr << ".\n"; } #endif } /** * replace a character in a string with another */ std::string replace(const std::string &src,char f,char t) { std::string ret; for(size_t i=0;i=128 || ch=='"' || ch=='*' || ch=='+' || ch==',' || ch=='/' || ch==':' || ch==';' || ch=='<' || ch=='=' || ch=='>' || ch=='?' || ch=='\\' || ch=='[' || ch==']' || ch=='|' || ch=='$' ){ out.push_back('_'); } else { out.push_back(ch); } } return out; } //const feature_recorder::hash_def &feature_recorder::hasher() //{ // return fs.hasher; //} #include /** * @param sbuf - the buffer to carve * @param pos - offset in the buffer to carve * @param len - how many bytes to carve * */ std::string feature_recorder::carve(const sbuf_t &sbuf,size_t pos,size_t len, const std::string &ext) { if(flags & FLAG_DISABLED) return std::string(); // disabled /* If we are in the margin, ignore; it will be processed again */ if(pos >= sbuf.pagesize && pos < sbuf.bufsize){ return std::string(); } assert(pos < sbuf.bufsize); /* Carve to a file depending on the carving mode. The purpose * of CARVE_ENCODED is to allow us to carve JPEGs when they are * embedded in, say, GZIP files, but not carve JPEGs that are * bare. The difficulty arises when you have a tool that can go * into, say, ZIP files. In this case, we don't want to carve * every ZIP file, just the (for example) XORed ZIP files. So the * ZIP carver doesn't carve every ZIP file, just the ZIP files * that are in HIBER files. That is, we want to not carve a path * of ZIP-234234 but we do want to carve a path of * 1000-HIBER-33423-ZIP-2343. This is implemented by having an * ignore_encoding. the ZIP carver sets it to ZIP so it won't * carve things that are just found in a ZIP file. This means that * it won't carve disembodied ZIP files found in unallocated * space. You might want to do that. If so, set ZIP's carve mode * to CARVE_ALL. */ switch(carve_mode){ case CARVE_NONE: return std::string(); // carve nothing case CARVE_ENCODED: if(sbuf.pos0.path.size()==0) return std::string(); // not encoded if(sbuf.pos0.alphaPart()==ignore_encoding) return std::string(); // ignore if it is just encoded with this break; // otherwise carve case CARVE_ALL: break; } /* If the directory doesn't exist, make it. * If two threads try to make the directory, * that's okay, because the second one will fail. */ sbuf_t cbuf(sbuf,pos,len); // the buf we are going to carve std::string carved_hash_hexvalue = (*fs.hasher.func)(cbuf.buf,cbuf.bufsize); /* See if this is in the cache */ bool in_cache = carve_cache.check_for_presence_and_insert(carved_hash_hexvalue); uint64_t this_file_number = file_number_add(in_cache ? 0 : 1); // increment if we are not in the cache std::string dirname1 = fs.get_outdir() + "/" + name; std::stringstream ss; ss << dirname1 << "/" << std::setw(3) << std::setfill('0') << (this_file_number / 1000); std::string dirname2 = ss.str(); std::string fname = dirname2 + std::string("/") + valid_dosname(cbuf.pos0.str() + ext); std::string fname_feature = fname.substr(fs.get_outdir().size()+1); /* Record what was found in the feature file. */ if (in_cache){ fname=""; // no filename fname_feature=""; } // write to the feature file ss.str(std::string()); // clear the stringstream ss << ""; if (!in_cache) ss << "" << fname << ""; ss << "" << len << ""; ss << "" << carved_hash_hexvalue << ""; this->write(cbuf.pos0,fname_feature,ss.str()); if (in_cache) return fname; // do not make directories or write out if we are cached /* Make the directory if it doesn't exist. */ if (access(dirname2.c_str(),R_OK)!=0){ #ifdef WIN32 mkdir(dirname1.c_str()); mkdir(dirname2.c_str()); #else mkdir(dirname1.c_str(),0777); mkdir(dirname2.c_str(),0777); #endif } /* Check to make sure that directory is there. We don't just the return code * because there could have been two attempts to make the directory simultaneously, * so the mkdir could fail but the directory could nevertheless exist. We need to * remember the error number because the access() call may clear it. */ int oerrno = errno; // remember error number if (access(dirname2.c_str(),R_OK)!=0){ std::cerr << "Could not make directory " << dirname2 << ": " << strerror(oerrno) << "\n"; return std::string(); } /* Write the file into the directory */ int fd = ::open(fname.c_str(),O_CREAT|O_BINARY|O_RDWR,0666); if(fd<0){ std::cerr << "*** carve: Cannot create " << fname << ": " << strerror(errno) << "\n"; return std::string(); } ssize_t ret = cbuf.write(fd,0,len); if(ret<0){ std::cerr << "*** carve: Cannot write(pos=" << fd << "," << pos << " len=" << len << "): "<< strerror(errno) << "\n"; } ::close(fd); return fname; } /** * Currently, we need strptime() and utimes() to set the time. */ void feature_recorder::set_carve_mtime(const std::string &fname, const std::string &mtime_iso8601) { if(flags & FLAG_DISABLED) return; // disabled #if defined(HAVE_STRPTIME) && defined(HAVE_UTIMES) if(fname.size()){ struct tm tm; if(strptime(mtime_iso8601.c_str(),"%Y-%m-%dT%H:%M:%S",&tm)){ time_t t = mktime(&tm); if(t>0){ const struct timeval times[2] = {{t,0},{t,0}}; utimes(fname.c_str(),times); } } } #endif } tcpflow-tcpflow-1.6.1/src/be13_api/feature_recorder.h000066400000000000000000000366571401360461700225370ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ #ifndef FEATURE_RECORDER_H #define FEATURE_RECORDER_H /** * \addtogroup bulk_extractor_APIs * @{ */ /** * feature_recorder.h: * * System for recording features from the scanners into the feature files. * * There is one feature_recorder per feature file. It is used both to record * the features and to perform the histogram calculation. * (That should probably be moved to a different class.) It also also previously * had the ability to do a merge sort, but we took that out because it was * not necessary. * * The feature recorders can also check the global alert_list to see * if the feature should be written to the alert file. It's opened on * demand and immediately flushed and closed. A special mutex is used * to protect it. * * Finally, the feature recorder supports the global stop_list, which * is a list of features that are not written to the main file but are * written to a stop list. That is implemented with a second * feature_recorder. * * There is one feature_recorder_set per process. * The file assumes that bulk_extractor.h is being included. */ #include #include #include #include #include #include #include #ifdef HAVE_SQLITE3_H #include #ifndef BEAPI_SQLITE # define BEAPI_SQLITE3 sqlite3 # define BEAPI_SQLITE3_STMT sqlite3_stmt #endif #endif #ifndef BEAPI_SQLITE3 #define BEAPI_SQLITE3 void #define BEAPI_SQLITE3_STMT void #endif #include "cppmutex.h" #include "dfxml/src/dfxml_writer.h" #include "dfxml/src/hash_t.h" #include "atomic_set_map.h" #include "beregex.h" /** * histogram_def defines the histograms that will be made by a feature recorder. * If the mhistogram is set, the histogram is generated when features are recorded * and kept in memory. If mhistogram is not set, the histogram is generated when the feature recorder is closed. */ struct histogram_def { /** * @param feature- the feature file to histogram (no .txt) * @param re - the regular expression to extract * @param require- require this string on the line (usually in context) * @param suffix - the suffix to add to the histogram file after feature name before .txt * @param flags - any flags (see above) */ histogram_def(std::string feature_,std::string re_,std::string suffix_,uint32_t flags_=0): feature(feature_),pattern(re_),require(),suffix(suffix_),flags(flags_),reg(pattern,REG_EXTENDED){} histogram_def(std::string feature_,std::string re_,std::string require_,std::string suffix_,uint32_t flags_=0): feature(feature_),pattern(re_),require(require_),suffix(suffix_),flags(flags_),reg(pattern,REG_EXTENDED){ } const std::string feature; /* feature file name */ const std::string pattern; /* extract pattern; "" means use entire feature */ const std::string require; /* text required somewhere on the feature line; used for IP histograms */ const std::string suffix; /* suffix to append; "" means "histogram" */ const uint32_t flags; // defined in histogram.h const beregex reg; // regular expression for pattern }; /* NOTE: * 1 - This typedef must remain outside the the feature_recorder due * to historical reasons and cannot be made a vector * 2 - Do not make historam_def const! It breaks some compilers. */ typedef std::set histogram_defs_t; // a set of histogram definitions inline bool operator <(const histogram_def &h1,const histogram_def &h2) { if (h1.featureh2.feature) return false; if (h1.patternh2.pattern) return false; if (h1.suffixh2.suffix) return false; return false; /* equal */ }; inline bool operator !=(const histogram_def &h1,const histogram_def &h2) { return h1.feature!=h2.feature || h1.pattern!=h2.pattern || h1.suffix!=h2.suffix; }; /* carve object cache */ typedef atomic_set carve_cache_t; /* in-memory histograms */ typedef atomic_histogram mhistogram_t; // memory histogram typedef std::map mhistograms_t; class feature_recorder { // default copy construction and assignment are meaningless // and not implemented feature_recorder(const feature_recorder &); feature_recorder &operator=(const feature_recorder &); static uint32_t debug; // are we debugging? static pthread_t main_threadid; // main threads ID static void MAINTHREAD(); // called if can only be run in the main thread uint32_t flags; // flags for this feature recorder /****************************************************************/ public: class besql_stmt { besql_stmt(const besql_stmt &); besql_stmt &operator=(const besql_stmt &); public: cppmutex Mstmt; // a mutext to protect it BEAPI_SQLITE3_STMT *stmt; // the prepared statement besql_stmt(BEAPI_SQLITE3 *db3,const char *sql); virtual ~besql_stmt(); void insert_feature(const pos0_t &pos, // insert it into this table! const std::string &feature,const std::string &feature8, const std::string &context); }; typedef int (dump_callback_t)(void *user,const feature_recorder &fr,const histogram_def &def, const std::string &feature,const uint64_t &count); static void set_main_threadid(){ #ifndef WIN32 main_threadid=pthread_self(); #endif }; // set the main static void set_debug(uint32_t ndebug){debug=ndebug;} typedef std::string offset_t; /** * \name Flags that control scanners * @{ * These flags control scanners. Set them with set_flag(). */ /** Disable this recorder. */ static const int FLAG_DISABLED = 0x01; // feature recorder is Disabled static const int FLAG_NO_CONTEXT = 0x02; // Do not write context. static const int FLAG_NO_STOPLIST = 0x04; // Do not honor the stoplist/alertlist. static const int FLAG_NO_ALERTLIST = 0x08; // Do not honor the stoplist/alertlist. /** * Normally feature recorders automatically quote non-UTF8 characters * with \x00 notation and quote "\" as \x5C. Specify FLAG_NO_QUOTE to * disable this behavior. */ static const int FLAG_NO_QUOTE = 0x10; // do not escape UTF8 codes /** * Use this flag the feature recorder is sending UTF-8 XML. * non-UTF8 will be quoted but "\" will not be escaped. */ static const int FLAG_XML = 0x20; // will be sending XML /** * histogram support. */ static const uint32_t FLAG_NO_FEATURES = 0x40; // do not record features (just memory histogram) static const uint32_t FLAG_NO_FEATURES_SQL = 0x80; // do not write features to SQL /** @} */ static const int max_histogram_files = 10; // don't make more than 10 files in low-memory conditions static const std::string histogram_file_header; static const std::string feature_file_header; static const std::string bulk_extractor_version_header; // These must only be changed in the main thread: static uint32_t opt_max_context_size; static uint32_t opt_max_feature_size; static int64_t offset_add; // added to every reported offset, for use with hadoop static std::string banner_file; // banner for top of every file static std::string extract_feature(const std::string &line); feature_recorder(class feature_recorder_set &fs, const std::string &name); virtual ~feature_recorder(); virtual void set_flag(uint32_t flags_); virtual void unset_flag(uint32_t flags_); void enable_memory_histograms(); // only called from feature_recorder_set virtual void set_memhist_limit(int64_t limit_); bool flag_set(uint32_t f) const {return flags & f;} bool flag_notset(uint32_t f) const {return !(flags & f);} uint32_t get_flags() const {return flags;} virtual const std::string &get_outdir() const; static size_t context_window_default; // global option const std::string name; // name of this feature recorder private: std::string ignore_encoding; // encoding to ignore for carving std::fstream ios; // where features are written class besql_stmt *bs; // prepared beapi sql statement protected:; histogram_defs_t histogram_defs; // histograms that are to be created for this feature recorder public: class feature_recorder_set &fs; // the set in which this feature_recorder resides protected: int64_t count_; /* number of records written */ size_t context_window_before; // context window size_t context_window_after; // context window mutable cppmutex Mf; // protects the file & file_number_ mutable cppmutex Mr; // protects the redlist mhistograms_t mhistograms; // the memory histograms, if we are using them uint64_t mhistogram_limit; // how many we want (per feature recorder limit, rather than per histogram) class feature_recorder *stop_list_recorder; // where stopped features get written int64_t file_number_; /* starts at 0; gets incremented by carve(); */ carve_cache_t carve_cache; public: /* these are not threadsafe and should only be called in startup */ void set_stop_list_recorder(class feature_recorder *fr){ MAINTHREAD(); stop_list_recorder = fr; } void set_context_window(size_t win){ MAINTHREAD(); context_window_before = win; context_window_after = win; } void set_context_window_before(size_t win){ MAINTHREAD(); context_window_before = win;} void set_context_window_after(size_t win){ MAINTHREAD(); context_window_after = win; } void set_carve_ignore_encoding(const std::string &encoding){ MAINTHREAD();ignore_encoding = encoding;} /* End non-threadsafe */ uint64_t file_number_add(uint64_t i){ #ifdef HAVE___SYNC_ADD_AND_FETCH return __sync_add_and_fetch(&file_number_,i); #else cppmutex::lock lock(Mf); file_number_ += i; return file_number_; #endif } void banner_stamp(std::ostream &os,const std::string &header) const; // stamp banner, and header /* where stopped items (on stop_list or context_stop_list) get recorded: */ std::string fname_counter(std::string suffix) const; static std::string quote_string(const std::string &feature); // turns unprintable characters to octal escape static std::string unquote_string(const std::string &feature); // turns octal escape back to binary characters //virtual const feature_recorder_set::hash_def &hasher(); // returns hasher in feature_recorder_set /* feature file management */ virtual void open(); virtual void close(); virtual void flush(); static int dump_callback_test(void *user,const feature_recorder &fr, const std::string &str,const uint64_t &count); // test callback for you to use! /* TK: The histogram_def should be provided at the beginning, so it can be used for in-memory histograms. * The callback needs to have the specific atomic set as the callback as well. */ virtual void add_histogram(const histogram_def &def); // adds a histogram to process virtual void dump_histogram_file(const histogram_def &def,void *user,feature_recorder::dump_callback_t cb) const; virtual void dump_histogram_db(const histogram_def &def,void *user,feature_recorder::dump_callback_t cb) const; virtual void dump_histogram(const histogram_def &def,void *user,feature_recorder::dump_callback_t cb) const; typedef void (*xml_notifier_t)(const std::string &xmlstring); virtual void dump_histograms(void *user,feature_recorder::dump_callback_t cb, xml_notifier_t xml_error_notifier) const; /* Methods to get info */ uint64_t count() const {return count_;} /* Methods to write. * write() is the basic write - you say where, and it does it. * write_buf() writes from a position within the buffer, with context. * It won't write a feature that starts in the margin. * pos0 gives the location and prefix for the beginning of the buffer */ /**************************************************************** *** External entry points. ****************************************************************/ /** * write() actually does the writing to the file. * It uses locks and is threadsafe. * Callers therefore do not need locks. */ virtual void write(const std::string &str); /** * support for writing features */ void quote_if_necessary(std::string &feature,std::string &context); // only virtual functions may be called by plug-ins // printf() prints to the feature file. virtual void printf(const char *fmt_,...) __attribute__((format(printf, 2, 3))); // // write a feature and its context; the feature may be in the context, but doesn't need to be. // write() calls write0() after histogram, quoting, and stoplist processing // write0() calls write0_sql() if sqlwriting is enabled virtual void write0(const pos0_t &pos0,const std::string &feature,const std::string &context); private: virtual void db_write0(const pos0_t &pos0,const std::string &feature,const std::string &context); static const char *db_insert_stmt; public: // write a feature and its context; the feature may be in the context, but doesn't need to be. // entries processed by write below will be processed by histogram system virtual void write(const pos0_t &pos0,const std::string &feature,const std::string &context); // write a feature located at a given place within an sbuf. // Context is written automatically virtual void write_buf(const sbuf_t &sbuf,size_t pos,size_t len); /* writes with context */ /** * support for carving. * Carving writes the filename to the feature file; the context is the file's hash using the provided function. * Automatically de-duplicates. */ enum carve_mode_t { CARVE_NONE=0, CARVE_ENCODED=1, CARVE_ALL=2}; #define CARVE_MODE_DESCRIPTION "0=carve none; 1=carve encoded; 2=carve all" carve_mode_t carve_mode; typedef std::string (*hashing_function_t)(const sbuf_t &sbuf); // returns a hex value void set_carve_mode(carve_mode_t aMode){MAINTHREAD();carve_mode=aMode;} // Carve a file; returns filename of carved file or empty string if nothing carved virtual std::string carve(const sbuf_t &sbuf,size_t pos,size_t len, const std::string &ext); // appended to forensic path // Set the time of the carved file to iso8601 file virtual void set_carve_mtime(const std::string &fname, const std::string &mtime_iso8601); }; // function that can only be called from main thread inline void feature_recorder::MAINTHREAD() { #ifndef WIN32 assert(main_threadid==pthread_self()); #endif }; /** @} */ #endif tcpflow-tcpflow-1.6.1/src/be13_api/feature_recorder_set.cpp000066400000000000000000000200151401360461700237220ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ #include "config.h" #include "bulk_extractor_i.h" #include "histogram.h" /**************************************************************** *** feature_recorder_set: *** Manage the set of feature recorders. *** Handles both file-based feature recorders and the SQLite3 feature recorder. ****************************************************************/ const std::string feature_recorder_set::ALERT_RECORDER_NAME = "alerts"; const std::string feature_recorder_set::DISABLED_RECORDER_NAME = "disabled"; const std::string feature_recorder_set::NO_INPUT = ""; const std::string feature_recorder_set::NO_OUTDIR = ""; static std::string null_hasher_name("null"); static std::string null_hasher_func(const uint8_t *buf,size_t bufsize) { return std::string("0000000000000000"); } feature_recorder_set::hash_def feature_recorder_set::null_hasher(null_hasher_name,null_hasher_func); /* Create an empty recorder with no outdir. */ feature_recorder_set::feature_recorder_set(uint32_t flags_,const feature_recorder_set::hash_def &hasher_, const std::string &input_fname_,const std::string &outdir_): flags(flags_),seen_set(),input_fname(input_fname_), outdir(outdir_), frm(),Mscanner_stats(), histogram_defs(), Min_transaction(),in_transaction(),db3(), alert_list(),stop_list(), scanner_stats(),hasher(hasher_) { if(flags & SET_DISABLED){ create_name(DISABLED_RECORDER_NAME,false); frm[DISABLED_RECORDER_NAME]->set_flag(feature_recorder::FLAG_DISABLED); } } /** * Initialize a properly functioning feature recorder set. * If disabled, create a disabled feature_recorder that can respond to functions as requested. */ void feature_recorder_set::init(const feature_file_names_t &feature_files) { /* Make sure we can write to the outdir if one is provided */ if ((outdir != NO_OUTDIR) && (access(outdir.c_str(),W_OK)!=0)) { throw new std::invalid_argument("output directory not writable"); } if (flag_set(ENABLE_SQLITE3_RECORDERS)) { db_create(); } if (flag_notset(NO_ALERT)) { create_name(feature_recorder_set::ALERT_RECORDER_NAME,false); // make the alert recorder } /* Create the requested feature files */ for(std::set::const_iterator it=feature_files.begin();it!=feature_files.end();it++){ create_name(*it,flags & CREATE_STOP_LIST_RECORDERS); } } /** Flush all of the feature recorder files. * Typically done at the end of an sbuf. */ void feature_recorder_set::flush_all() { for(feature_recorder_map::iterator i = frm.begin();i!=frm.end();i++){ i->second->flush(); } } void feature_recorder_set::close_all() { for(feature_recorder_map::iterator i = frm.begin();i!=frm.end();i++){ i->second->close(); } if ( flag_set(feature_recorder_set::ENABLE_SQLITE3_RECORDERS )) { db_transaction_commit(); } } bool feature_recorder_set::has_name(std::string name) const { return frm.find(name) != frm.end(); } /* * Gets a feature_recorder_set. */ feature_recorder *feature_recorder_set::get_name(const std::string &name) const { const std::string *thename = &name; if(flags & SET_DISABLED){ // if feature recorder set is disabled, return the disabled recorder. thename = &feature_recorder_set::DISABLED_RECORDER_NAME; } if(flags & ONLY_ALERT){ thename = &feature_recorder_set::ALERT_RECORDER_NAME; } cppmutex::lock lock(Mscanner_stats); feature_recorder_map::const_iterator it = frm.find(*thename); if(it!=frm.end()) return it->second; return(0); // feature recorder does not exist } feature_recorder *feature_recorder_set::create_name_factory(const std::string &name_) { return new feature_recorder(*this,name_); } /* * Create a named feature recorder, any associated stoplist recorders, and open the files */ void feature_recorder_set::create_name(const std::string &name,bool create_stop_recorder) { if(frm.find(name)!=frm.end()){ std::cerr << "create_name: feature recorder '" << name << "' already exists\n"; return; } feature_recorder *fr = create_name_factory(name); frm[name] = fr; if (create_stop_recorder){ std::string name_stopped = name+"_stopped"; feature_recorder *fr_stopped = create_name_factory(name_stopped); fr->set_stop_list_recorder(fr_stopped); frm[name_stopped] = fr_stopped; } } feature_recorder *feature_recorder_set::get_alert_recorder() const { if (flag_set(NO_ALERT)) return 0; return get_name(feature_recorder_set::ALERT_RECORDER_NAME); } /* * uses md5 to determine if a block was prevously seen. */ bool feature_recorder_set::check_previously_processed(const uint8_t *buf,size_t bufsize) { std::string md5 = md5_generator::hash_buf(buf,bufsize).hexdigest(); return seen_set.check_for_presence_and_insert(md5); } void feature_recorder_set::add_stats(const std::string &bucket,double seconds) { cppmutex::lock lock(Mscanner_stats); struct pstats &p = scanner_stats[bucket]; // get the location of the stats p.seconds += seconds; p.calls ++; } /* * Send the stats to a callback; if the callback returns less than 0, abort. */ void feature_recorder_set::get_stats(void *user,stat_callback_t stat_callback) const { for(scanner_stats_map::const_iterator it = scanner_stats.begin();it!=scanner_stats.end();it++){ if((*stat_callback)(user,(*it).first,(*it).second.calls,(*it).second.seconds)<0){ break; } } } void feature_recorder_set::dump_name_count_stats(dfxml_writer &writer) const { cppmutex::lock lock(Mscanner_stats); writer.push("feature_files"); for(feature_recorder_map::const_iterator ij = frm.begin(); ij != frm.end(); ij++){ writer.set_oneline(true); writer.push("feature_file"); writer.xmlout("name",ij->second->name); writer.xmlout("count",ij->second->count()); writer.pop(); writer.set_oneline(false); } } void feature_recorder_set::set_flag(uint32_t f) { if(f & MEM_HISTOGRAM){ if(flags & MEM_HISTOGRAM){ std::cerr << "MEM_HISTOGRAM flag cannot be set twice\n"; assert(0); } /* Create the in-memory histograms for all of the feature recorders */ for(feature_recorder_map::const_iterator it = frm.begin(); it!=frm.end(); it++){ feature_recorder *fr = it->second; fr->enable_memory_histograms(); } } flags |= f; } void feature_recorder_set::unset_flag(uint32_t f) { if(f & MEM_HISTOGRAM){ std::cerr << "MEM_HISTOGRAM flag cannot be cleared\n"; assert(0); } flags &= ~f; } /**************************************************************** *** PHASE HISTOGRAM (formerly phase 3): Create the histograms ****************************************************************/ /** * We now have three kinds of histograms: * 1 - Traditional post-processing histograms specified by the histogram library 1a - feature-file based traditional ones 1b - SQL-based traditional ones. * 2 - In-memory histograms (used primarily by beapi) */ void feature_recorder_set::add_histogram(const histogram_def &def) { feature_recorder *fr = get_name(def.feature); if(fr) fr->add_histogram(def); } void feature_recorder_set::dump_histograms(void *user,feature_recorder::dump_callback_t cb, feature_recorder_set::xml_notifier_t xml_error_notifier) const { /* Ask each feature recorder to dump its histograms */ for(feature_recorder_map::const_iterator it = frm.begin(); it!=frm.end(); it++){ feature_recorder *fr = it->second; fr->dump_histograms(user,cb,xml_error_notifier); } } void feature_recorder_set::get_feature_file_list(std::vector &ret) { for(feature_recorder_map::const_iterator it = frm.begin(); it!=frm.end(); it++){ ret.push_back(it->first); } } tcpflow-tcpflow-1.6.1/src/be13_api/feature_recorder_set.h000066400000000000000000000161541401360461700234000ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ #ifndef FEATURE_RECORDER_SET_H #define FEATURE_RECORDER_SET_H #include "feature_recorder.h" #include "cppmutex.h" #include "dfxml/src/dfxml_writer.h" #include "dfxml/src/hash_t.h" #include "word_and_context_list.h" #include #include /** \addtogroup internal_interfaces * @{ */ /** \file */ /** * \class feature_recorder_set * The feature_recorder_set is an object that controls output. It knows where the output goes (outdir), * the various feature recorders that write to that output, and provides for synchronization. * It also has the factory method for new feature_recorders. Therefore if you want a different feature_recorder, * this set should be subclassed as well. */ typedef std::map feature_recorder_map; typedef std::setfeature_file_names_t; class feature_recorder_set { // neither copying nor assignment is implemented feature_recorder_set(const feature_recorder_set &fs); feature_recorder_set &operator=(const feature_recorder_set &fs); uint32_t flags; atomic_set seen_set; // hex hash values of pages that have been seen const std::string input_fname; // input file const std::string outdir; // where output goes feature_recorder_map frm; // map of feature recorders, by name; TK-replace with an atomic_set mutable cppmutex Mscanner_stats; // locks frm and scanner_stats_map histogram_defs_t histogram_defs; // histograms that are to be created. mutable cppmutex Min_transaction; bool in_transaction; public: BEAPI_SQLITE3 *db3; // opened in SQLITE_OPEN_FULLMUTEX mode virtual void heartbeat(){}; // called at a regular basis struct hash_def { hash_def(std::string name_,std::string (*func_)(const uint8_t *buf,const size_t bufsize)):name(name_),func(func_){}; std::string name; // name of hash std::string (*func)(const uint8_t *buf,const size_t bufsize); // hash function }; struct pstats { double seconds; uint64_t calls; }; /** create an emptry feature recorder set. If disabled, create a disabled recorder. */ feature_recorder_set(uint32_t flags_,const hash_def &hasher_, const std::string &input_fname_,const std::string &outdir_); typedef std::map scanner_stats_map; const word_and_context_list *alert_list; /* shold be flagged */ const word_and_context_list *stop_list; /* should be ignored */ scanner_stats_map scanner_stats; const hash_def &hasher; // function for hashing; specified at creation static hash_def null_hasher; // a default hasher available for all to use (it doesn't hash) static const std::string ALERT_RECORDER_NAME; // the name of the alert recorder static const std::string DISABLED_RECORDER_NAME; // the fake disabled feature recorder static const std::string NO_INPUT; // 'filename' indicator that the FRS has no input file static const std::string NO_OUTDIR; // 'dirname' indicator that the FRS produces no file output /* flags */ static const uint32_t ONLY_ALERT = 0x01; // always return the alert recorder static const uint32_t SET_DISABLED = 0x02; // the set is effectively disabled; for path-printer static const uint32_t CREATE_STOP_LIST_RECORDERS= 0x04; // static const uint32_t MEM_HISTOGRAM = 0x20; // enable the in-memory histogram static const uint32_t ENABLE_SQLITE3_RECORDERS = 0x40; // save features to an SQLITE3 databse static const uint32_t DISABLE_FILE_RECORDERS = 0x80; // do not save features to file-based recorders static const uint32_t NO_ALERT = 0x100; // no alert recorder virtual ~feature_recorder_set() { for(feature_recorder_map::iterator i = frm.begin();i!=frm.end();i++){ delete i->second; } db_close(); } std::string get_input_fname() const {return input_fname;} virtual const std::string &get_outdir() const { return outdir;} void set_stop_list(const word_and_context_list *alist){stop_list=alist;} void set_alert_list(const word_and_context_list *alist){alert_list=alist;} /** Initialize a feature_recorder_set. Previously this was a constructor, but it turns out that * virtual functions for the create_name_factory aren't honored in constructors. * * init() is called after all of the scanners have been loaded. It * tells each feature file about its histograms (among other * things) */ void init(const feature_file_names_t &feature_files); void flush_all(); void close_all(); bool has_name(std::string name) const; /* does the named feature exist? */ /* flags */ void set_flag(uint32_t f); void unset_flag(uint32_t f); bool flag_set(uint32_t f) const {return flags & f;} bool flag_notset(uint32_t f) const {return !(flags & f);} uint32_t get_flags() const {return flags;} typedef void (*xml_notifier_t)(const std::string &xmlstring); void add_histogram(const histogram_def &def); // adds it to a local set or to the specific feature recorder void dump_histograms(void *user,feature_recorder::dump_callback_t cb, xml_notifier_t xml_error_notifier) const; virtual feature_recorder *create_name_factory(const std::string &name_); virtual void create_name(const std::string &name,bool create_stop_also); void add_stats(const std::string &bucket,double seconds); typedef int (*stat_callback_t)(void *user,const std::string &name,uint64_t calls,double seconds); void get_stats(void *user,stat_callback_t stat_callback) const; void dump_name_count_stats(dfxml_writer &writer) const; /**************************************************************** *** SQLite3 interface ****************************************************************/ virtual void db_send_sql(BEAPI_SQLITE3 *db3,const char **stmts, ...) ; virtual BEAPI_SQLITE3 *db_create_empty(const std::string &name) ; void db_create_table(const std::string &name) ; void db_create() ; void db_transaction_begin() ; void db_transaction_commit() ; // commit current transaction void db_close() ; // /**************************************************************** *** External Functions ****************************************************************/ // Management of previously seen data virtual bool check_previously_processed(const uint8_t *buf,size_t bufsize); // NOTE: // only virtual functions may be called by plugins! virtual feature_recorder *get_name(const std::string &name) const; virtual feature_recorder *get_alert_recorder() const; virtual void get_feature_file_list(std::vector &ret); // clears ret and fills with a list of feature file names }; #endif tcpflow-tcpflow-1.6.1/src/be13_api/feature_recorder_sql.cpp000066400000000000000000000314271401360461700237370ustar00rootroot00000000000000/* * Feature recorder mods for writing features into an SQLite3 database. */ /* http://blog.quibb.org/2010/08/fast-bulk-inserts-into-sqlite/ */ #include "config.h" #include #include #include #include #include #include "bulk_extractor_i.h" #include "histogram.h" /* * Time results with ubnist1 on R4: * no SQL - 79 seconds * no pragmas - 651 seconds * "PRAGMA synchronous = OFF", - 146 second * "PRAGMA synchronous = OFF", "PRAGMA journal_mode=MEMORY", - 79 seconds * * Time with domexusers: * no SQL - */ #if defined(HAVE_LIBSQLITE3) && defined(HAVE_SQLITE3_H) #define USE_SQLITE3 #endif #define SQLITE_EXTENSION ".sqlite" #ifndef SQLITE_DETERMINISTIC #define SQLITE_DETERMINISTIC 0 #endif static int debug = 0; #ifdef USE_SQLITE3 static const char *schema_db[] = { "PRAGMA synchronous = OFF", "PRAGMA journal_mode=MEMORY", //"PRAGMA temp_store=MEMORY", // did not improve performance "PRAGMA cache_size = 200000", "CREATE TABLE IF NOT EXISTS db_info (schema_ver INTEGER, bulk_extractor_ver INTEGER)", "INSERT INTO db_info (schema_ver, bulk_extractor_ver) VALUES (1,1)", "CREATE TABLE IF NOT EXISTS be_features (tablename VARCHAR,comment TEXT)", "CREATE TABLE IF NOT EXISTS be_config (name VARCHAR,value VARCHAR)", 0}; /* Create a feature table and note that it has been created in be_features */ static const char *schema_tbl[] = { "CREATE TABLE IF NOT EXISTS f_%s (offset INTEGER(12), path VARCHAR, feature_eutf8 TEXT, feature_utf8 TEXT, context_eutf8 TEXT)", "CREATE INDEX IF NOT EXISTS f_%s_idx1 ON f_%s(offset)", "CREATE INDEX IF NOT EXISTS f_%s_idx2 ON f_%s(feature_eutf8)", "CREATE INDEX IF NOT EXISTS f_%s_idx3 ON f_%s(feature_utf8)", "INSERT INTO be_features (tablename,comment) VALUES ('f_%s','')", 0}; /* This creates the base histogram. Note that the SQL fails if the histogram exists */ static const char *schema_hist[] = { "CREATE TABLE h_%s (count INTEGER(12), feature_utf8 TEXT)", "CREATE INDEX h_%s_idx1 ON h_%s(count)", "CREATE INDEX h_%s_idx2 ON h_%s(feature_utf8)", 0}; /* This performs the histogram operation */ static const char *schema_hist1[] = { "INSERT INTO h_%s select COUNT(*),feature_utf8 from f_%s GROUP BY feature_utf8", 0}; #ifdef HAVE_SQLITE3_CREATE_FUNCTION_V2 static const char *schema_hist2[] = { "INSERT INTO h_%s select sum(count),BEHIST(feature_utf8) from h_%s where BEHIST(feature_utf8)!='' GROUP BY BEHIST(feature_utf8)", 0}; #endif #endif const char *feature_recorder::db_insert_stmt = "INSERT INTO f_%s (offset,path,feature_eutf8,feature_utf8,context_eutf8) VALUES (?1, ?2, ?3, ?4, ?5)"; static const char *begin_transaction[] = {"BEGIN TRANSACTION",0}; static const char *commit_transaction[] = {"COMMIT TRANSACTION",0}; void feature_recorder::besql_stmt::insert_feature(const pos0_t &pos, const std::string &feature, const std::string &feature8, const std::string &context) { #ifdef USE_SQLITE3 assert(stmt!=0); cppmutex::lock lock(Mstmt); // grab a lock const std::string &path = pos.str(); sqlite3_bind_int64(stmt, 1, pos.imageOffset()); // offset sqlite3_bind_text(stmt, 2, path.data(), path.size(), SQLITE_STATIC); // path sqlite3_bind_text(stmt, 3, feature.data(), feature.size(), SQLITE_STATIC); sqlite3_bind_text(stmt, 4, feature8.data(), feature8.size(), SQLITE_STATIC); sqlite3_bind_text(stmt, 5, context.data(), context.size(), SQLITE_STATIC); if (sqlite3_step(stmt) != SQLITE_DONE) { fprintf(stderr,"sqlite3_step failed\n"); } sqlite3_reset(stmt); #endif }; feature_recorder::besql_stmt::besql_stmt(BEAPI_SQLITE3 *db3,const char *sql):Mstmt(),stmt() { #ifdef USE_SQLITE3 assert(db3!=0); assert(sql!=0); sqlite3_prepare_v2(db3,sql, strlen(sql), &stmt, NULL); assert(stmt!=0); #endif } feature_recorder::besql_stmt::~besql_stmt() { #ifdef USE_SQLITE3 assert(stmt!=0); sqlite3_finalize(stmt); stmt = 0; #endif } void feature_recorder_set::db_send_sql(BEAPI_SQLITE3 *db,const char **stmts, ...) { #ifdef USE_SQLITE3 assert(db!=0); for(int i=0;stmts[i];i++){ char *errmsg = 0; char buf[65536]; va_list ap; va_start(ap,stmts); vsnprintf(buf,sizeof(buf),stmts[i],ap); va_end(ap); if(debug) std::cerr << "SQL: " << buf << "\n"; // Don't error on a PRAGMA if((sqlite3_exec(db,buf,NULL,NULL,&errmsg) != SQLITE_OK) && (strncmp(buf,"PRAGMA",6)!=0)) { fprintf(stderr,"Error executing '%s' : %s\n",buf,errmsg); exit(1); } } #endif } void feature_recorder_set::db_create_table(const std::string &name) { #ifdef USE_SQLITE3 assert(name.size()>0); db_send_sql(db3,schema_tbl,name.c_str(),name.c_str()); #endif } BEAPI_SQLITE3 *feature_recorder_set::db_create_empty(const std::string &name) { #ifdef USE_SQLITE3 assert(name.size()>0); std::string dbfname = outdir + "/" + name + SQLITE_EXTENSION; if(debug) std::cerr << "create_feature_database " << dbfname << "\n"; BEAPI_SQLITE3 *db=0; if (sqlite3_open_v2(dbfname.c_str(), &db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_FULLMUTEX, 0)!=SQLITE_OK) { std::cerr << "Cannot create database '" << dbfname << "': " << sqlite3_errmsg(db) << "\n"; sqlite3_close(db); exit(1); } return db; #else return 0; #endif } #pragma GCC diagnostic ignored "-Wmissing-noreturn" void feature_recorder_set::db_create() { #ifdef USE_SQLITE3 assert(db3==0); db3 = db_create_empty("report"); db_send_sql(db3,schema_db); #else std::cerr << "*** CANNOT CREATE SQLITE3 DATABASE ***\n"; std::cerr << "*** Compiled without libsqlite ***\n"; assert(0 && debug); // prevent debug from being not used #endif } void feature_recorder_set::db_close() { #ifdef USE_SQLITE3 if(db3){ if(debug) std::cerr << "db_close()\n"; sqlite3_close(db3); db3 = 0; } #endif } void feature_recorder_set::db_transaction_begin() { cppmutex::lock lock(Min_transaction); if(!in_transaction){ db_send_sql(db3,begin_transaction); in_transaction = true; } } void feature_recorder_set::db_transaction_commit() { cppmutex::lock lock(Min_transaction); if(in_transaction){ db_send_sql(db3,commit_transaction); in_transaction = false; } else { std::cerr << "No transaction to commit\n"; } } /* Hook for writing feature to SQLite3 database */ void feature_recorder::db_write0(const pos0_t &pos0,const std::string &feature,const std::string &context) { /** * Note: this is not very efficient, passing through a quoted feature and then unquoting it. * We could make this more efficient. */ std::string *feature8 = HistogramMaker::convert_utf16_to_utf8(feature_recorder::unquote_string(feature)); assert(bs!=0); bs->insert_feature(pos0,feature, feature8 ? *feature8 : feature, flag_set(feature_recorder::FLAG_NO_CONTEXT) ? "" : context); if (feature8) delete feature8; } /* Hook for writing histogram */ #ifdef USE_SQLITE3 static int callback_counter(void *param, int argc, char **argv, char **azColName) { int *counter = reinterpret_cast(param); (*counter)++; return 0; } #ifdef HAVE_SQLITE3_CREATE_FUNCTION_V2 static void behist(sqlite3_context *ctx,int argc,sqlite3_value**argv) { const histogram_def *def = reinterpret_cast(sqlite3_user_data(ctx)); if(debug) std::cerr << "behist feature=" << def->feature << " suffix=" << def->suffix << " argc=" << argc << "value = " << sqlite3_value_text(argv[0]) << "\n"; std::string new_feature(reinterpret_cast(sqlite3_value_text(argv[0]))); if (def->reg.search(new_feature,&new_feature,0,0)) { sqlite3_result_text(ctx,new_feature.c_str(),new_feature.size(),SQLITE_TRANSIENT); } } #endif #endif void feature_recorder::dump_histogram_db(const histogram_def &def,void *user,feature_recorder::dump_callback_t cb) const { #ifdef USE_SQLITE3 /* First check to see if there exists a feature histogram summary. If not, make it */ std::string query = "SELECT name FROM sqlite_master WHERE type='table' AND name='h_" + def.feature +"'"; char *errmsg=0; int rowcount=0; if (sqlite3_exec(fs.db3,query.c_str(),callback_counter,&rowcount,&errmsg)){ std::cerr << "sqlite3: " << errmsg << "\n"; return; } if (rowcount==0){ const char *feature = def.feature.c_str(); fs.db_send_sql(fs.db3,schema_hist, feature, feature); // creates the histogram fs.db_send_sql(fs.db3,schema_hist1, feature, feature); // creates the histogram } #ifdef HAVE_SQLITE3_CREATE_FUNCTION_V2 /* Now create the summarized histogram for the regex, if it is not existing, but only if we have * sqlite3_create_function_v2 */ if (def.pattern.size()>0){ /* Create the database where we will add the histogram */ std::string hname = def.feature + "_" + def.suffix; /* Remove any "-" characters if present */ for(size_t i=0;i &ret){} int main(int argc,char **argv) { const char *dbfile = "test.sql3"; char *errmsg = 0; sqlite3 *db=0; feature_recorder_set fs(0,my_hasher); unlink(dbfile); fs.db_create(); if(1){ /* Create an email table */ fs.db_create_table("email"); /* Lets throw a million features into the table as a test */ //sqlite3_exec(db,"BEGIN TRANSACTION",NULL,NULL,&errmsg); beapi_sql_stmt s(db,"email"); for(int i=0;i<1000000;i++){ pos0_t p; pos0_t p1 = p+i; if(i%10000==0) printf("i=%d\n",i); char feature[64]; snprintf(feature,sizeof(feature),"user%d@company.com",i); char context[64]; snprintf(context,sizeof(context),"this is the context user%d@company.com yes it is!",i); //insert_statement(stmt,p1,feature,context); } //sqlite3_exec(db,"COMMIT TRANSACTION",NULL,NULL,&errmsg); } fs.db_close(); } #endif tcpflow-tcpflow-1.6.1/src/be13_api/histogram.cpp000066400000000000000000000174371401360461700215420ustar00rootroot00000000000000/** * histogram.cpp: * Maintain a histogram for Unicode strings provided as UTF-8 and UTF-16 encodings. * Track number of each coding provided. * * TK: Reimplement top-n with a priority queue. * http://www.cplusplus.com/reference/queue/priority_queue/ */ #include "config.h" #include "bulk_extractor_i.h" #include "unicode_escape.h" #include "histogram.h" #include "utf8.h" using namespace std; ostream & operator << (ostream &os, const HistogramMaker::FrequencyReportVector &rep){ for(HistogramMaker::FrequencyReportVector::const_iterator i = rep.begin(); i!=rep.end();i++){ const HistogramMaker::ReportElement &r = *(*i); os << "n=" << r.tally.count << "\t" << validateOrEscapeUTF8(r.value, true, true); if(r.tally.count16>0) os << "\t(utf16=" << r.tally.count16<<")"; os << "\n"; } return os; } HistogramMaker::FrequencyReportVector *HistogramMaker::makeReport() const { FrequencyReportVector *rep = new FrequencyReportVector(); for(HistogramMap::const_iterator it = h.begin(); it != h.end(); it++){ rep->push_back(new ReportElement(it->first,it->second)); } sort(rep->begin(),rep->end(),ReportElement::compare); return rep; } /* This would be better done with a priority queue */ HistogramMaker::FrequencyReportVector *HistogramMaker::makeReport(int topN) const { HistogramMaker::FrequencyReportVector *r2 = makeReport(); // gets a new report HistogramMaker::FrequencyReportVector::iterator i = r2->begin(); while(topN>0 && i!=r2->end()){ // iterate through the first set i++; topN--; } /* Delete the elements we won't use */ for(HistogramMaker::FrequencyReportVector::iterator j=i;j!=r2->end();j++){ delete (*j); } r2->erase(i,r2->end()); return r2; } /* static */ bool HistogramMaker::looks_like_utf16(const std::string &str,bool &little_endian) { if((uint8_t)str[0]==0xff && (uint8_t)str[1]==0xfe){ little_endian = true; return true; // begins with FFFE } if((uint8_t)str[0]==0xfe && (uint8_t)str[1]==0xff){ little_endian = false; return true; // begins with FFFE } /* If none of the even characters are NULL and some of the odd characters are NULL, it's UTF-16 */ uint32_t even_null_count = 0; uint32_t odd_null_count = 0; for(size_t i=0;i+11){ little_endian = true; return true; } if(odd_null_count==0 && even_null_count>1){ little_endian = false; return true; } return false; } /** * Converts a utf16 with a byte order to utf8, returning an ALLOCATED STRING if conversion is * successful, and returning 0 if it is not. */ /* static */ std::string *HistogramMaker::convert_utf16_to_utf8(const std::string &key,bool little_endian) { /* re-image this string as UTF16*/ std::wstring utf16; for(size_t i=0;isize()>0) { size_t nullpos = tempKey->find('\000'); if(nullpos==string::npos) break; tempKey->erase(nullpos,1); } } catch(utf8::invalid_utf16){ /* Exception; bad UTF16 encoding */ delete tempKey; tempKey = 0; // give up on temp key; otherwise its invalidated below return 0; } return tempKey; } std::string *HistogramMaker::convert_utf16_to_utf8(const std::string &key) { bool little_endian=false; if(looks_like_utf16(key,little_endian)){ return convert_utf16_to_utf8(key,little_endian); } return 0; } std::string *HistogramMaker::make_utf8(const std::string &key) { std::string *utf8 = convert_utf16_to_utf8(key); if(utf8==0) utf8 = new std::string(key); return utf8; } /** * Takes a string (the key) and adds it to the histogram. * automatically determines if the key is UTF-16 and converts * it to UTF8 if so. */ uint32_t HistogramMaker::debug_histogram_malloc_fail_frequency = 0; void HistogramMaker::add(const std::string &key) { if(key.size()==0) return; // don't deal with zero-length keys /** * "key" passed in is a const reference. * But we might want to change it. So keyToAdd points to what will be added. * If we need to change key, we allocate more memory, and make keyToAdd * point to the memory that was allocated. This way we only make a copy * if we need to make a copy. */ const std::string *keyToAdd = &key; // should be a reference, but that doesn't work std::string *tempKey = 0; // place to hold UTF8 key bool found_utf16 = false; bool little_endian=false; if(looks_like_utf16(*keyToAdd,little_endian)){ tempKey = convert_utf16_to_utf8(*keyToAdd,little_endian); if(tempKey){ keyToAdd = tempKey; found_utf16 = true; } } /* If any conversion is necessary AND we have not converted key from UTF-16 to UTF-8, * then the original key is still in 'key'. Allocate tempKey and copy key to tempKey. */ if(flags & (FLAG_LOWERCASE |FLAG_NUMERIC)){ if(tempKey==0){ tempKey = new std::string(key); keyToAdd = tempKey; } } /* Apply the flags */ // See: http://stackoverflow.com/questions/1081456/wchar-t-vs-wint-t if(flags & FLAG_LOWERCASE){ /* keyToAdd is UTF-8; convert to UTF-16, downcase, and convert back to UTF-8 */ try{ std::wstring utf16key; utf8::utf8to16(tempKey->begin(),tempKey->end(),std::back_inserter(utf16key)); for(std::wstring::iterator it = utf16key.begin();it!=utf16key.end();it++){ *it = towlower(*it); } /* erase tempKey and copy the utf16 back into tempKey as utf8 */ tempKey->clear(); // erase the characters utf8::utf16to8(utf16key.begin(),utf16key.end(),std::back_inserter(*tempKey)); } catch(utf8::exception){ /* Exception thrown during utf8 or 16 conversions. * So the string we thought was valid utf8 wasn't valid utf8 afterall. * tempKey will remain unchanged. */ } } if(flags & FLAG_NUMERIC){ /* keyToAdd is UTF-8; convert to UTF-16, extract digits, and convert back to UTF-8 */ std::string originalTempKey(*tempKey); try{ std::wstring utf16key; std::wstring utf16digits; utf8::utf8to16(tempKey->begin(),tempKey->end(),std::back_inserter(utf16key)); for(std::wstring::iterator it = utf16key.begin();it!=utf16key.end();it++){ if(iswdigit(*it) || *it==static_cast('+')){ utf16digits.push_back(*it); } } /* convert it back */ tempKey->clear(); // erase the characters utf8::utf16to8(utf16digits.begin(),utf16digits.end(),std::back_inserter(*tempKey)); } catch(utf8::exception){ /* Exception during utf8 or 16 conversions*. * So the string wasn't utf8. Fall back to just extracting the digits */ tempKey->clear(); for(std::string::iterator it = originalTempKey.begin(); it!=originalTempKey.end(); it++){ if(isdigit(*it)){ tempKey->push_back(*it); } } } } /* For debugging low-memory handling logic, * specify DEBUG_MALLOC_FAIL to make malloc occasionally fail */ if(debug_histogram_malloc_fail_frequency){ if((h.size() % debug_histogram_malloc_fail_frequency)==(debug_histogram_malloc_fail_frequency-1)){ throw bad_alloc(); } } h[*keyToAdd].count++; if(found_utf16) h[*keyToAdd].count16++; // track how many UTF16s were converted if(tempKey){ // if we allocated tempKey, free it delete tempKey; } } tcpflow-tcpflow-1.6.1/src/be13_api/histogram.h000066400000000000000000000102321401360461700211710ustar00rootroot00000000000000#ifndef HISTOGRAM_H #define HISTOGRAM_H /** * \addtogroup internal_interfaces * @{ */ /* C++ Histogram classes. * * Eventually this may become a single class */ #include #include /** * \class CharClass * Examine a block of text and count the number of characters * in various ranges. This is useful for determining if a block of * bytes is coded in BASE16, BASE64, etc. */ class CharClass { public: uint32_t range_0_9; // a range_0_9 character uint32_t range_A_Fi; // a-f or A-F uint32_t range_g_z; // g-z uint32_t range_G_Z; // G-Z CharClass():range_0_9(0),range_A_Fi(0),range_g_z(0),range_G_Z(0){ } void add(uint8_t ch){ if(ch>='a' && ch<='f') range_A_Fi++; if(ch>='A' && ch<='F') range_A_Fi++; if(ch>='g' && ch<='z') range_g_z++; if(ch>='G' && ch<='Z') range_G_Z++; if(ch>='0' && ch<='9') range_0_9++; } void add(uint8_t *buf,size_t len){ for(size_t i=0;i e2.tally.count) return true; if (e1.tally.count < e2.tally.count) return false; return e1.value < e2.value; } static bool compare(const ReportElement *e1,const ReportElement *e2) { if (e1->tally.count > e2->tally.count) return true; if (e1->tally.count < e2->tally.count) return false; return e1->value < e2->value; } virtual ~ReportElement(){}; }; private: /** A HistogramMap holds the histogram while it is being computed. */ typedef std::map HistogramMap; HistogramMap h; // holds the histogram uint32_t flags; // see above public: /** * Determine if a string probably has utf16. */ static bool looks_like_utf16(const std::string &str,bool &little_endian); /* These all allocate a string that must be freed */ static std::string *convert_utf16_to_utf8(const std::string &str); static std::string *convert_utf16_to_utf8(const std::string &str,bool little_endian); static std::string *make_utf8(const std::string &key); HistogramMaker(uint32_t flags_):h(),flags(flags_){} void clear(){h.clear();} void add(const std::string &key); // adds a string to the histogram count /** A FrequencyReportVector is a vector of report elements when the report is generated. */ typedef std::vector FrequencyReportVector; /** makeReport() makes a report and returns a * FrequencyReportVector. */ FrequencyReportVector *makeReport() const; // return a report with all of them FrequencyReportVector *makeReport(int topN) const; // returns just the topN virtual ~HistogramMaker(){}; }; std::ostream & operator <<(std::ostream &os,const HistogramMaker::FrequencyReportVector &rep); #endif tcpflow-tcpflow-1.6.1/src/be13_api/net_ethernet.h000066400000000000000000000062271401360461700216710ustar00rootroot00000000000000/* Copyright (C) 1997, 1999, 2001, 2008 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ /* Based on the FreeBSD version of this file. Curiously, that file lacks a copyright in the header. */ #ifndef __NET_ETHERNET_H #define __NET_ETHERNET_H 1 #include #include //#include /* IEEE 802.3 Ethernet constants */ __BEGIN_DECLS /* This is a name for the 48 bit ethernet address available on many systems. */ struct ether_addr { u_int8_t ether_addr_octet[ETH_ALEN]; } __attribute__ ((__packed__)); /* 10Mb/s ethernet header */ struct ether_header { u_int8_t ether_dhost[ETH_ALEN]; /* destination eth addr */ u_int8_t ether_shost[ETH_ALEN]; /* source ether addr */ u_int16_t ether_type; /* packet type ID field */ } __attribute__ ((__packed__)); /* Ethernet protocol ID's */ #define ETHERTYPE_PUP 0x0200 /* Xerox PUP */ #define ETHERTYPE_SPRITE 0x0500 /* Sprite */ #define ETHERTYPE_IP 0x0800 /* IP */ #define ETHERTYPE_ARP 0x0806 /* Address resolution */ #define ETHERTYPE_REVARP 0x8035 /* Reverse ARP */ #define ETHERTYPE_AT 0x809B /* AppleTalk protocol */ #define ETHERTYPE_AARP 0x80F3 /* AppleTalk ARP */ #define ETHERTYPE_VLAN 0x8100 /* IEEE 802.1Q VLAN tagging */ #define ETHERTYPE_IPX 0x8137 /* IPX */ #define ETHERTYPE_IPV6 0x86dd /* IP protocol version 6 */ #define ETHERTYPE_LOOPBACK 0x9000 /* used to test interfaces */ #define ETHER_ADDR_LEN ETH_ALEN /* size of ethernet addr */ #define ETHER_TYPE_LEN 2 /* bytes in type field */ #define ETHER_CRC_LEN 4 /* bytes in CRC field */ #define ETHER_HDR_LEN ETH_HLEN /* total octets in header */ #define ETHER_MIN_LEN (ETH_ZLEN + ETHER_CRC_LEN) /* min packet length */ #define ETHER_MAX_LEN (ETH_FRAME_LEN + ETHER_CRC_LEN) /* max packet length */ /* make sure ethenet length is valid */ #define ETHER_IS_VALID_LEN(foo) \ ((foo) >= ETHER_MIN_LEN && (foo) <= ETHER_MAX_LEN) /* * The ETHERTYPE_NTRAILER packet types starting at ETHERTYPE_TRAIL have * (type-ETHERTYPE_TRAIL)*512 bytes of data followed * by an ETHER type (as given above) and then the (variable-length) header. */ #define ETHERTYPE_TRAIL 0x1000 /* Trailer packet */ #define ETHERTYPE_NTRAILER 16 #define ETHERMTU ETH_DATA_LEN #define ETHERMIN (ETHER_MIN_LEN - ETHER_HDR_LEN - ETHER_CRC_LEN) __END_DECLS #endif /* net/ethernet.h */ tcpflow-tcpflow-1.6.1/src/be13_api/pcap_fake.cpp000066400000000000000000000152221401360461700214440ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ #include "config.h" #ifndef HAVE_LIBPCAP #include "pcap_fake.h" #include #include #include #include #include #ifdef WIN32 #define SET_BINMODE(f) _setmode(_fileno(f), _O_BINARY) #else #define SET_BINMODE(f) /* ignore */ #endif /* pcap_fake's struct pcap just keeps track of the file that was opened and * whether or not it was byteswapped. */ struct pcap { FILE *fp; // input file we are reading from int swapped; // whether magic number was swapped? uint32_t linktype; bool error; // an error occured bool break_loop; // break_loop was called bool must_close; char err_buf[128]; uint8_t *pktbuf; }; char *pcap_geterr(pcap_t *p) { snprintf(p->err_buf,sizeof(p->err_buf),"not implemented in pcap_fake"); return p->err_buf; } /** * pcap_open_offline() * -- "The name "-" is a synonym for stdin" (pcap manual) * -- allocate the pcap_t structure * -- open a pcap capture file. */ pcap_t *pcap_open_offline(const char *fname, char *errbuf) { FILE *fp = strcmp(fname,"-")==0 ? stdin : fopen(fname,"rb"); if(!fp){ snprintf(errbuf,PCAP_ERRBUF_SIZE,"%s:%s",fname,strerror(errno)); return 0; } pcap_t *p = pcap_fopen_offline(fp,errbuf); if(p && p->fp!=stdin) p->must_close = true; return p; } char *pcap_lookupdev(char *) // not implemented { fprintf(stderr,"pcap_fake.cpp:pcap_lookupdev: tcpflow was compiled without LIBPCAP. Will not live capture.\n"); return 0; } pcap_t *pcap_open_live(const char *, int, int, int, char *) { fprintf(stderr,"pcap_fake.cpp:pcap_open_live: tcpflow was compiled without LIBPCAP. Will not live capture.\n"); return 0; } inline uint32_t swap4(uint32_t x) { return ( ((x & 0xff000000) >> 24) | ((x & 0x00ff0000) >> 8) | ((x & 0x0000ff00) << 8) | ((x & 0x000000ff) << 24)); } inline uint32_t swap2(uint16_t x) { return ( ((x & 0xff00) >> 8) | ((x & 0x00ff) << 8)); } pcap_t *pcap_fopen_offline(FILE *fp, char *errbuf) { SET_BINMODE(fp); bool swapped = false; struct pcap_file_header header; if(fread(&header,sizeof(header),1,fp)!=1){ snprintf(errbuf,PCAP_ERRBUF_SIZE,"Cannot read pcap header"); return 0; // cannot read header } if(header.magic==0xd4c3b2a1){ // check for swap header.magic = swap4(header.magic); header.version_major = swap2(header.version_major); header.version_minor = swap2(header.version_minor); header.thiszone = swap4(header.thiszone); header.sigfigs = swap4(header.sigfigs); header.snaplen = swap4(header.snaplen); header.linktype = swap4(header.linktype); swapped = true; } if(header.magic != 0xa1b2c3d4){ snprintf(errbuf, PCAP_ERRBUF_SIZE,"Cannot decode pcap header 0x%x; swapped=%d", header.magic,swapped); return 0; } if(header.version_major!=PCAP_VERSION_MAJOR || header.version_minor!=PCAP_VERSION_MINOR){ snprintf(errbuf, PCAP_ERRBUF_SIZE,"Cannot read pcap version %d.%d", header.version_major,header.version_minor); return 0; } pcap_t *ret = (pcap_t *)calloc(1,sizeof(pcap_t)); if(ret==0){ snprintf(errbuf, PCAP_ERRBUF_SIZE,"Cannot calloc %u bytes",(unsigned int)sizeof(pcap_t)); return 0; } ret->pktbuf = (uint8_t *)malloc(header.snaplen); if(ret->pktbuf==0) { // did we get the snaplen? std::cerr << "Couldn't get header snaplen"; free(ret); return 0; } //DEBUG(100) ("pcap_fake.cpp DEBUG: header.magic = %x", header.magic); //DEBUG(100) ("pcap_fake.cpp DEBUG: header.version_major = %d", header.version_major); //DEBUG(100) ("pcap_fake.cpp DEBUG: header.version_minor = %d", header.version_minor); //DEBUG(100) ("pcap_fake.cpp DEBUG: header.thiszone = %d", header.thiszone); //DEBUG(100) ("pcap_fake.cpp DEBUG: header.sigfigs = %d", header.sigfigs); //DEBUG(100) ("pcap_fake.cpp DEBUG: header.snaplen = %d", header.snaplen); //DEBUG(100) ("pcap_fake.cpp DEBUG: header.linktype = %d",header.linktype); //DEBUG(100) ("pcap_fake.cpp DEBUG: ret->pktbuf = %s". ret->pktbuf); ret->fp = fp; ret->swapped = swapped; ret->linktype = header.linktype; return ret; } /* * These are not implemented in pcap_fake */ int pcap_compile(pcap_t *p, struct bpf_program *program, const char *expression, int optimize, uint32_t mask) { if(strlen(expression)==0){ program->valid = true; return 0; // we can compile the empty expression } return -1; // we cannot compile otherwise } int pcap_datalink(pcap_t *p) { return p->linktype; } int pcap_setfilter(pcap_t *p, struct bpf_program *prog) { if(prog->valid) return 0; return -1; } int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, uint8_t *user) { while(cnt !=0 && !feof(p->fp) && p->break_loop==false){ uint32_t tv_sec; uint32_t tv_usec; struct pcap_pkthdr hdr; /* Note: struct timeval is 16 bytes on MacOS and not 8 bytes, * so we manually read and set up the structure */ if(fread(&tv_sec,sizeof(uint32_t),1,p->fp)!=1) break; if(fread(&tv_usec,sizeof(uint32_t),1,p->fp)!=1) break; hdr.ts.tv_sec = tv_sec; hdr.ts.tv_usec = tv_usec; if(fread(&hdr.caplen,sizeof(uint32_t),1,p->fp)!=1) break; if(fread(&hdr.len,sizeof(uint32_t),1,p->fp)!=1) break; /* Swap the header if necessary */ if(p->swapped){ hdr.ts.tv_sec = swap4(hdr.ts.tv_sec); hdr.ts.tv_usec = swap4(hdr.ts.tv_usec); hdr.caplen = swap4(hdr.caplen); hdr.len = swap4(hdr.len); } /* Read the packet */ if(fread(p->pktbuf,hdr.caplen,1,p->fp)!=1) break; // no more to read //DEBUG(100) ("pcap_fake: read tv_sec.tv_usec=%d.%06d caplen=%d len=%d", // (int)hdr.ts.tv_sec,(int)hdr.ts.tv_usec,hdr.caplen,hdr.len); /* Process the packet */ (*callback)(user,&hdr,p->pktbuf); /* And loop */ if(cnt>0) cnt--; // decrease the packet count } return 0; } void pcap_break_loop(pcap_t *p) { p->break_loop=true; } void pcap_close(pcap_t *p) // close the file { if(p->must_close) fclose(p->fp); free(p->pktbuf); free(p); } #endif tcpflow-tcpflow-1.6.1/src/be13_api/pcap_fake.h000066400000000000000000000062161401360461700211140ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /* * pcap_fake.h * A fake libpcap implementation that can only read files without a filter. */ #include #include #include #include __BEGIN_DECLS /* * Version number of the current version of the pcap file format. * * NOTE: this is *NOT* the version number of the libpcap library. * To fetch the version information for the version of libpcap * you're using, use pcap_lib_version(). */ #define PCAP_VERSION_MAJOR 2 #define PCAP_VERSION_MINOR 4 #define PCAP_ERRBUF_SIZE 256 struct pcap_file_header { uint32_t magic; // d4 c3 b2 a1 uint16_t version_major; // 02 00 uint16_t version_minor; // 04 00 int32_t thiszone; /* gmt to local correction - 00 00 00 00*/ uint32_t sigfigs; /* accuracy of timestamps */ uint32_t snaplen; /* max length saved portion of each pkt */ uint32_t linktype; /* data link type (LINKTYPE_*) */ } __attribute__((packed)); struct pcap_pkthdr { struct timeval ts; /* time stamp; native */ uint32_t caplen; /* length of portion present */ uint32_t len; /* length this packet (off wire) */ }__attribute__((packed)); /* What we need after opening the file to process each next packet */ typedef struct pcap pcap_t; /* * Taken from pcap-int.h */ //typedef int (*setfilter_op_t)(pcap_t *, struct bpf_program *); typedef void (*pcap_handler)(uint8_t *, const struct pcap_pkthdr *, const uint8_t *); struct bpf_program { int valid; // set true if filter is valid }; char *pcap_lookupdev(char *); // not implemented pcap_t *pcap_open_live(const char *, int, int, int, char *); // not implemented pcap_t *pcap_open_offline(const char *, char *); // open the file; set f pcap_t *pcap_fopen_offline(FILE *fp,char *errbuf); void pcap_close(pcap_t *); // close the file int pcap_loop(pcap_t *, int, pcap_handler, uint8_t *); // read the file and call loopback on each packet int pcap_datalink(pcap_t *); // noop int pcap_setfilter(pcap_t *, struct bpf_program *); // noop int pcap_compile(pcap_t *, struct bpf_program *, const char *, int, uint32_t); // generate error if filter provided char *pcap_geterr(pcap_t *); /* * These are the types that are the same on all platforms, and that * have been defined by for ages. */ #define DLT_NULL 0 /* BSD loopback encapsulation */ #define DLT_EN10MB 1 /* Ethernet (10Mb) */ #define DLT_EN3MB 2 /* Experimental Ethernet (3Mb) */ #define DLT_AX25 3 /* Amateur Radio AX.25 */ #define DLT_PRONET 4 /* Proteon ProNET Token Ring */ #define DLT_CHAOS 5 /* Chaos */ #define DLT_IEEE802 6 /* 802.5 Token Ring */ #define DLT_ARCNET 7 /* ARCNET, with BSD-style header */ #define DLT_SLIP 8 /* Serial Line IP */ #define DLT_PPP 9 /* Point-to-point Protocol */ #define DLT_FDDI 10 /* FDDI */ #define DLT_RAW 101 /* just packets */ __END_DECLS tcpflow-tcpflow-1.6.1/src/be13_api/plugin.cpp000066400000000000000000000613221401360461700210330ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /* * common.cpp: * bulk_extractor backend stuff, used for both standalone executable and bulk_extractor. */ #include "config.h" #include #include #include #include #ifdef HAVE_ERR_H #include #endif #ifdef HAVE_DLFCN_H #include #endif #include "bulk_extractor_i.h" #include "aftimer.h" #include "dfxml/src/hash_t.h" uint32_t scanner_def::max_depth = 7; // max recursion depth uint32_t scanner_def::max_ngram = 10; // max recursion depth static int debug; // local debug variable static uint32_t max_depth_seen=0; static cppmutex max_depth_seenM; bool be13::plugin::dup_data_alerts = false; // by default, is disabled uint64_t be13::plugin::dup_data_encountered = 0; // amount that was not processed class scanner_command { public: enum command_t {DISABLE_ALL=0,ENABLE_ALL,DISABLE,ENABLE}; scanner_command(const scanner_command &sc):command(sc.command),name(sc.name){}; scanner_command(scanner_command::command_t c,const std::string &n):command(c),name(n){}; command_t command; std::string name; }; static std::vector scanner_commands; bool scanner_commands_processed = false; /**************************************************************** *** misc support ****************************************************************/ /**************************************************************** *** SCANNER PLUG-IN SYSTEM ****************************************************************/ /* scanner_params */ scanner_params::PrintOptions scanner_params::no_options; /* vector object for keeping track of packet callbacks */ class packet_plugin_info { public: packet_plugin_info(void *user_,packet_callback_t *callback_):user(user_),callback(callback_){}; void *user; packet_callback_t *callback; }; typedef std::vector packet_plugin_info_vector_t; packet_plugin_info_vector_t packet_handlers; // pcap callback handlers /* plugin */ /** * the vector of current scanners */ be13::plugin::scanner_vector be13::plugin::current_scanners; void be13::plugin::set_scanner_debug(int adebug) { debug = adebug; } /** * return true a scanner is enabled */ /* enable or disable a specific scanner. * enable = 0 - disable that scanner. * enable = 1 - enable that scanner * 'all' is a special scanner that enables all scanners. */ void be13::plugin::set_scanner_enabled(const std::string &name,bool enable) { for(scanner_vector::iterator it = current_scanners.begin();it!=current_scanners.end();it++){ if(name=="all" && (((*it)->info.flags & scanner_info::SCANNER_NO_ALL)==0)){ (*it)->enabled = enable; } if((*it)->info.name==name){ (*it)->enabled = enable; return; } } if(name=="all") return; std::cerr << "Invalid scanner name '" << name << "'\n"; exit(1); } void be13::plugin::set_scanner_enabled_all(bool enable) { for(scanner_vector::const_iterator it = current_scanners.begin();it!=current_scanners.end();it++){ (*it)->enabled = enable; } } /** Name of feature files that should be histogramed. * The histogram should be done in the plug-in */ /**************************************************************** *** scanner plugin loading ****************************************************************/ /** * plugin system phase 0: Load a scanner. * * As part of scanner loading: * - pass configuration to the scanner * - feature files that the scanner requires * - Histograms that the scanner makes (see feature_recorder_set) * This is called before scanners are enabled or disabled, so the pcap handlers * need to be set afterwards */ void be13::plugin::load_scanner(scanner_t scanner,const scanner_info::scanner_config &sc) { /* If scanner is already loaded, return */ for(scanner_vector::const_iterator it = current_scanners.begin();it!=current_scanners.end();it++){ if((*it)->scanner==scanner) return; } /* Use an empty sbuf and an empty feature recorder set as the parameters for the sp below. * we use static values so that the sbuf is not constantly being created and destroyed. */ static const sbuf_t sbuf; static feature_recorder_set fs(feature_recorder_set::SET_DISABLED,feature_recorder_set::null_hasher, feature_recorder_set::NO_INPUT, feature_recorder_set::NO_OUTDIR); // dummy // // Each scanner's params are stored in a scanner_def object that // is created here and retained for the duration of the run. // The scanner_def includes its own scanner_info structure. // We pre-load the structure with the configuration for this scanner // and the global debug variable // // currently every scanner gets the same config. In the future, we might // want to give different scanners different variables. // scanner_params sp(scanner_params::PHASE_STARTUP,sbuf,fs); // scanner_def *sd = new scanner_def(); sd->scanner = scanner; sd->info.config = ≻ sp.info = &sd->info; // Make an empty recursion control block and call the scanner's // initialization function. recursion_control_block rcb(0,""); (*scanner)(sp,rcb); // phase 0 sd->enabled = !(sd->info.flags & scanner_info::SCANNER_DISABLED); current_scanners.push_back(sd); } void be13::plugin::load_scanner_file(std::string fn,const scanner_info::scanner_config &sc) { /* Figure out the function name */ size_t extloc = fn.rfind('.'); if(extloc==std::string::npos){ fprintf(stderr,"Cannot find '.' in %s",fn.c_str()); exit(1); } std::string func_name = fn.substr(0,extloc); size_t slashloc = func_name.rfind('/'); if(slashloc!=std::string::npos) func_name = func_name.substr(slashloc+1); slashloc = func_name.rfind('\\'); if(slashloc!=std::string::npos) func_name = func_name.substr(slashloc+1); if(debug) std::cout << "Loading: " << fn << " (" << func_name << ")\n"; scanner_t *scanner = 0; #if defined(HAVE_DLOPEN) void *lib=dlopen(fn.c_str(), RTLD_LAZY); if(lib==0){ fprintf(stderr,"dlopen: %s\n",dlerror()); exit(1); } /* Resolve the symbol */ scanner = (scanner_t *)dlsym(lib, func_name.c_str()); if(scanner==0){ fprintf(stderr,"dlsym: %s\n",dlerror()); exit(1); } #elif defined(HAVE_LOADLIBRARY) /* Use Win32 LoadLibrary function */ /* See http://msdn.microsoft.com/en-us/library/ms686944(v=vs.85).aspx */ HINSTANCE hinstLib = LoadLibrary(TEXT(fn.c_str())); if(hinstLib==0){ fprintf(stderr,"LoadLibrary(%s) failed",fn.c_str()); exit(1); } scanner = (scanner_t *)GetProcAddress(hinstLib,func_name.c_str()); if(scanner==0){ fprintf(stderr,"GetProcAddress(%s) failed",func_name.c_str()); exit(1); } #else std::cout << " ERROR: Support for loadable libraries not enabled\n"; return; #endif load_scanner(*scanner,sc); } void be13::plugin::load_scanners(scanner_t * const *scanners,const scanner_info::scanner_config &sc) { for(int i=0;scanners[i];i++){ load_scanner(scanners[i],sc); } } void be13::plugin::load_scanner_directory(const std::string &dirname,const scanner_info::scanner_config &sc ) { DIR *dirp = opendir(dirname.c_str()); if(dirp==0){ fprintf(stderr,"Cannot open directory %s:",dirname.c_str()); exit(1); } struct dirent *dp; while ((dp = readdir(dirp)) != NULL){ std::string fname = dp->d_name; if(fname.substr(0,5)=="scan_" || fname.substr(0,5)=="SCAN_"){ size_t extloc = fname.rfind('.'); if(extloc==std::string::npos) continue; // no '.' std::string ext = fname.substr(extloc+1); #ifdef WIN32 if(ext!="DLL") continue; // not a DLL #else if(ext!="so") continue; // not a shared library #endif load_scanner_file(dirname+"/"+fname,sc ); } } } void be13::plugin::load_scanner_directories(const std::vector &dirnames, const scanner_info::scanner_config &sc) { for(std::vector::const_iterator it = dirnames.begin();it!=dirnames.end();it++){ load_scanner_directory(*it,sc); } } void be13::plugin::load_scanner_packet_handlers() { for(scanner_vector::const_iterator it = current_scanners.begin(); it!=current_scanners.end(); it++){ if((*it)->enabled){ const scanner_def *sd = (*it); if(sd->info.packet_cb){ packet_handlers.push_back(packet_plugin_info(sd->info.packet_user,sd->info.packet_cb)); } } } } // send every enabled scanner the phase message void be13::plugin::message_enabled_scanners(scanner_params::phase_t phase,feature_recorder_set &fs) { /* make an empty sbuf and feature recorder set */ const sbuf_t sbuf; scanner_params sp(phase,sbuf,fs); for(scanner_vector::iterator it = current_scanners.begin(); it!=current_scanners.end(); it++){ if((*it)->enabled){ recursion_control_block rcb(0,""); // dummy rcb ((*it)->scanner)(sp,rcb); } } } scanner_t *be13::plugin::find_scanner(const std::string &search_name) { for(scanner_vector::const_iterator it = current_scanners.begin();it!=current_scanners.end();it++){ if(search_name == (*it)->info.name){ return (*it)->scanner; } } return 0; } // put the enabled scanners into the vector void be13::plugin::get_enabled_scanners(std::vector &svector) { for(scanner_vector::const_iterator it=current_scanners.begin();it!=current_scanners.end();it++){ if((*it)->enabled){ svector.push_back((*it)->info.name); } } } bool be13::plugin::find_scanner_enabled() { for(scanner_vector::const_iterator it = current_scanners.begin(); it!=current_scanners.end(); it++){ if( ((*it)->info.flags & scanner_info::SCANNER_FIND_SCANNER) && ((*it)->enabled)){ return true; } } return false; } void be13::plugin::add_enabled_scanner_histograms_to_feature_recorder_set(feature_recorder_set &fs) { for(scanner_vector::const_iterator it = current_scanners.begin(); it!=current_scanners.end(); it++){ if((*it)->enabled){ const scanner_def *sd = (*it); for(histogram_defs_t::const_iterator i2 = sd->info.histogram_defs.begin(); i2 != sd->info.histogram_defs.end(); i2++){ fs.add_histogram((*i2)); } } } } void be13::plugin::scanners_init(feature_recorder_set &fs) { assert(scanner_commands_processed==true); message_enabled_scanners(scanner_params::PHASE_INIT,fs); // tell all enabled scanners to init } /**************************************************************** *** Scanner Commands (which one is enabled or disabled) ****************************************************************/ void be13::plugin::scanners_disable_all() { assert(scanner_commands_processed==false); scanner_commands.push_back(scanner_command(scanner_command::DISABLE_ALL,std::string(""))); } void be13::plugin::scanners_enable_all() { assert(scanner_commands_processed==false); scanner_commands.push_back(scanner_command(scanner_command::ENABLE_ALL,std::string(""))); } void be13::plugin::scanners_enable(const std::string &name) { assert(scanner_commands_processed==false); scanner_commands.push_back(scanner_command(scanner_command::ENABLE,name)); } void be13::plugin::scanners_disable(const std::string &name) { assert(scanner_commands_processed==false); scanner_commands.push_back(scanner_command(scanner_command::DISABLE,name)); } void be13::plugin::scanners_process_enable_disable_commands() { for(std::vector::const_iterator it=scanner_commands.begin(); it!=scanner_commands.end();it++){ switch((*it).command){ case scanner_command::ENABLE_ALL: set_scanner_enabled_all(true);break; case scanner_command::DISABLE_ALL: set_scanner_enabled_all(false); break; case scanner_command::ENABLE: set_scanner_enabled((*it).name,true);break; case scanner_command::DISABLE: set_scanner_enabled((*it).name,false);break; } } load_scanner_packet_handlers(); // can't do until enable/disable commands are run scanner_commands_processed = true; } /**************************************************************** *** PHASE_SHUTDOWN (formerly phase 2): shut down the scanners ****************************************************************/ void be13::plugin::phase_shutdown(feature_recorder_set &fs,std::stringstream *sxml) { assert(scanner_commands_processed==true); for(scanner_vector::iterator it = current_scanners.begin();it!=current_scanners.end();it++){ if((*it)->enabled){ const sbuf_t sbuf; // empty sbuf scanner_params sp(scanner_params::PHASE_SHUTDOWN,sbuf,fs,sxml); recursion_control_block rcb(0,""); // empty rcb (*(*it)->scanner)(sp,rcb); } } } /************************************ *** HELP and option processing *** ************************************/ /* Get the config and build the help strings at the same time! */ std::stringstream scanner_info::helpstream; void scanner_info::get_config(const scanner_info::config_t &c, const std::string &n,std::string *val,const std::string &help) { /* Check to see if we are being called as part of a help operation */ helpstream << " -S " << n << "=" << *val << " " << help << " (" << name << ")\n"; scanner_info::config_t::const_iterator it = c.find(n); if(it!=c.end() && val){ *val = it->second; } } void scanner_info::get_config(const std::string &n,std::string *val,const std::string &help) { scanner_info::get_config(config->namevals,n,val,help); } #define GET_CONFIG(T) void scanner_info::get_config(const std::string &n,T *val,const std::string &help) {\ std::stringstream ss;\ ss << *val;\ std::string v(ss.str());\ get_config(n,&v,help);\ ss.str(v);\ ss >> *val;\ } GET_CONFIG(uint64_t) GET_CONFIG(int32_t) // both int32_t and uint32_t GET_CONFIG(uint32_t) GET_CONFIG(uint16_t) #ifdef HAVE_GET_CONFIG_SIZE_T GET_CONFIG(size_t) #endif /* uint8_t needs cast to uint32_t for << * Otherwise it is interpreted as a character. */ void scanner_info::get_config(const std::string &n,uint8_t *val_,const std::string &help) { uint32_t val = *val_; std::stringstream ss; ss << val; std::string v(ss.str()); get_config(n,&v,help); ss.str(v); ss >> val; *val_ = (uint8_t)val; } /* bool needs special processing for YES/NO/TRUE/FALSE */ void scanner_info::get_config(const std::string &n,bool *val,const std::string &help) { std::stringstream ss; ss << ((*val) ? "YES" : "NO"); std::string v(ss.str()); get_config(n,&v,help); switch(v.at(0)){ case 'Y':case 'y':case 'T':case 't':case '1': *val = true; break; default: *val = false; } } /** * Print a list of scanners. * We need to load them to do this, so they are loaded with empty config * Note that scanners can only be loaded once, so this exits. */ void be13::plugin::info_scanners(bool detailed_info, bool detailed_settings, scanner_t * const *scanners_builtin, const char enable_opt,const char disable_opt) { const scanner_info::scanner_config empty_config; load_scanners(scanners_builtin,empty_config); std::cout << "\n"; std::vector enabled_wordlist; std::vector disabled_wordlist; for(scanner_vector::const_iterator it = current_scanners.begin();it!=current_scanners.end();it++){ if(detailed_info){ if ((*it)->info.name.size()) std::cout << "Scanner Name: " << (*it)->info.name << "\n"; std::cout << "flags: " << scanner_info::flag_to_string((*it)->info.flags) << "\n"; std::cout << "Scanner Interface version: " << (*it)->info.si_version << "\n"; if ((*it)->info.author.size()) std::cout << "Author: " << (*it)->info.author << "\n"; if ((*it)->info.description.size()) std::cout << "Description: " << (*it)->info.description << "\n"; if ((*it)->info.url.size()) std::cout << "URL: " << (*it)->info.url << "\n"; if ((*it)->info.scanner_version.size()) std::cout << "Scanner Version: " << (*it)->info.scanner_version << "\n"; std::cout << "Feature Names: "; for(std::set::const_iterator i2 = (*it)->info.feature_names.begin(); i2 != (*it)->info.feature_names.end(); i2++){ std::cout << *i2 << " "; } std::cout << "\n\n"; } if((*it)->info.flags & scanner_info::SCANNER_NO_USAGE) continue; if((*it)->info.flags & scanner_info::SCANNER_DISABLED){ disabled_wordlist.push_back((*it)->info.name); } else { enabled_wordlist.push_back((*it)->info.name); } } if(detailed_settings){ std::cout << "Settable Options (and their defaults): \n"; std::cout << scanner_info::helpstr(); } sort(disabled_wordlist.begin(),disabled_wordlist.end()); sort(enabled_wordlist.begin(),enabled_wordlist.end()); std::cout << "\n"; std::cout << "These scanners disabled by default; enable with -" << enable_opt << ":\n"; for(std::vector::const_iterator it = disabled_wordlist.begin(); it!=disabled_wordlist.end();it++){ std::cout << " -" << enable_opt << " " << *it << " - enable scanner " << *it << "\n"; } std::cout << "\n"; std::cout << "These scanners enabled by default; disable with -" << disable_opt << ":\n"; for(std::vector::const_iterator it = enabled_wordlist.begin();it!=enabled_wordlist.end();it++){ std::cout << " -" << disable_opt << " " << *it << " - disable scanner " << *it << "\n"; } } /** * upperstr - Turns an ASCII string into upper case (should be UTF-8) */ static std::string upperstr(const std::string &str) { std::string ret; for(std::string::const_iterator i=str.begin();i!=str.end();i++){ ret.push_back(toupper(*i)); } return ret; } /* Determine if the sbuf consists of a repeating ngram */ static size_t find_ngram_size(const sbuf_t &sbuf) { for(size_t ngram_size = 1; ngram_size < scanner_def::max_ngram; ngram_size++){ bool ngram_match = true; for(size_t i=ngram_size;i max_depth_seen) max_depth_seen = sp.depth; } /* If we are too deep, error out */ if(sp.depth >= scanner_def::max_depth){ feature_recorder *fr = fs.get_alert_recorder(); if(fr) fr->write(pos0,"process_extract: MAX DEPTH REACHED",""); return; } /* Determine if we have seen this buffer before */ bool seen_before = fs.check_previously_processed(sp.sbuf.buf,sp.sbuf.bufsize); if(seen_before){ md5_t md5 = md5_generator::hash_buf(sp.sbuf.buf,sp.sbuf.bufsize); feature_recorder *alert_recorder = fs.get_alert_recorder(); std::stringstream ss; ss << "" << sp.sbuf.bufsize << ""; if(alert_recorder && dup_data_alerts) alert_recorder->write(sp.sbuf.pos0,"DUP SBUF "+md5.hexdigest(),ss.str()); #ifdef HAVE__SYNC_ADD_AND_FETCH __sync_add_and_fetch(&dup_data_encountered,sp.sbuf.bufsize); #endif } /* Determine if the sbuf consists of a repeating ngram. If so, * it's only passed to the parsers that want ngrams. (By default, * such sbufs are booring.) */ size_t ngram_size = find_ngram_size(sp.sbuf); /**************************************************************** *** CALL EACH OF THE SCANNERS ON THE SBUF ****************************************************************/ if(debug & DEBUG_DUMP_DATA){ sp.sbuf.hex_dump(std::cerr); } for(scanner_vector::iterator it = current_scanners.begin();it!=current_scanners.end();it++){ // Look for reasons not to run a scanner if((*it)->enabled==false) continue; // not enabled if(((*it)->info.flags & scanner_info::SCANNER_WANTS_NGRAMS)==0){ /* If the scanner does not want ngrams, don't run it if we have ngrams or duplicate data */ if(ngram_size > 0) continue; if(seen_before) continue; } if(sp.depth > 0 && ((*it)->info.flags & scanner_info::SCANNER_DEPTH_0)){ // depth >0 and this scanner only run at depth 0 continue; } const std::string &name = (*it)->info.name; try { /* Compute the effective path for stats */ bool inname=false; std::string epath; for(std::string::const_iterator cc=sp.sbuf.pos0.path.begin();cc!=sp.sbuf.pos0.path.end();cc++){ if(isupper(*cc)) inname=true; if(inname) epath.push_back(toupper(*cc)); if(*cc=='-') inname=false; } if(epath.size()>0) epath.push_back('-'); for(std::string::const_iterator cc=name.begin();cc!=name.end();cc++){ epath.push_back(toupper(*cc)); } /* Create a RCB that will recursively call process_sbuf() */ recursion_control_block rcb(process_sbuf,upperstr(name)); /* Call the scanner.*/ { aftimer t; if(debug & DEBUG_PRINT_STEPS){ std::cerr << "sbuf.pos0=" << sp.sbuf.pos0 << " calling scanner " << name << "\n"; } t.start(); ((*it)->scanner)(sp,rcb); t.stop(); if(debug & DEBUG_PRINT_STEPS){ std::cerr << "sbuf.pos0=" << sp.sbuf.pos0 << " scanner " << name << " t=" << t.elapsed_seconds() << "\n"; } sp.fs.add_stats(epath,t.elapsed_seconds()); } } catch (const std::exception &e ) { std::stringstream ss; ss << "std::exception Scanner: " << name << " Exception: " << e.what() << " sbuf.pos0: " << sp.sbuf.pos0 << " bufsize=" << sp.sbuf.bufsize << "\n"; std::cerr << ss.str(); feature_recorder *alert_recorder = fs.get_alert_recorder(); if(alert_recorder) alert_recorder->write(sp.sbuf.pos0,"scanner="+name, std::string("")+e.what()+""); } catch (...) { std::stringstream ss; ss << "std::exception Scanner: " << name << " Unknown Exception " << " sbuf.pos0: " << sp.sbuf.pos0 << " bufsize=" << sp.sbuf.bufsize << "\n"; std::cerr << ss.str(); feature_recorder *alert_recorder = fs.get_alert_recorder(); if(alert_recorder) alert_recorder->write(sp.sbuf.pos0,"scanner="+name,""); } } fs.flush_all(); } /** * Process a pcap packet. * Designed to be very efficient because we have so many packets. */ void be13::plugin::process_packet(const be13::packet_info &pi) { for(packet_plugin_info_vector_t::iterator it = packet_handlers.begin(); it != packet_handlers.end(); it++){ (*(*it).callback)((*it).user,pi); } } void be13::plugin::get_scanner_feature_file_names(feature_file_names_t &feature_file_names) { for(scanner_vector::const_iterator it=current_scanners.begin();it!=current_scanners.end();it++){ if((*it)->enabled){ for(std::set::const_iterator fi=(*it)->info.feature_names.begin(); fi!=(*it)->info.feature_names.end(); fi++){ feature_file_names.insert(*fi); } } } } tcpflow-tcpflow-1.6.1/src/be13_api/sbuf.cpp000066400000000000000000000253221401360461700204740ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ #include "config.h" #include #include #include #include "bulk_extractor_i.h" #include "unicode_escape.h" /**************************************************************** *** SBUF_T ****************************************************************/ #ifndef O_BINARY #define O_BINARY 0 #endif /** * Map a file; falls back to read if mmap is not available */ const std::string sbuf_t::U10001C("\xf4\x80\x80\x9c"); std::string sbuf_t::map_file_delimiter(sbuf_t::U10001C); sbuf_t *sbuf_t::map_file(const std::string &fname) { int fd = open(fname.c_str(),O_RDONLY|O_BINARY,0); if(fd<0) return 0; /* cannot open file */ sbuf_t *sbuf = sbuf_t::map_file(fname,fd); if(sbuf) { sbuf->should_close = true; // be sure to close the file } return sbuf; } /* Map a file when we are given an open fd. * The fd is not closed when the file is unmapped. * If there is no mmap, just allocate space and read the file */ sbuf_t *sbuf_t::map_file(const std::string &fname,int fd) { struct stat st; if(fstat(fd,&st)){ close(fd); return 0; /* cannot stat */ } #ifdef HAVE_MMAP uint8_t *buf = (uint8_t *)mmap(0,st.st_size,PROT_READ,MAP_FILE|MAP_SHARED,fd,0); bool should_free = false; bool should_unmap = true; #else uint8_t *buf = (uint8_t *)malloc(st.st_size); if(buf==0){ /* malloc failed */ return 0; } lseek(fd,0,SEEK_SET); // go to beginning of file size_t r = (size_t)read(fd,(void *)buf,st.st_size); if(r!=(size_t)st.st_size){ free((void *)buf); /* read failed */ return 0; } close(fd); fd = 0; bool should_free = true; bool should_unmap = false; #endif sbuf_t *sbuf = new sbuf_t(pos0_t(fname+sbuf_t::map_file_delimiter), buf, st.st_size, st.st_size, fd, should_unmap, should_free, false); // the caller's job is to close return sbuf; } /* * Returns self or the highest parent of self, whichever is higher */ const sbuf_t *sbuf_t::highest_parent() const { const sbuf_t *hp = this; while(hp->parent != 0){ hp = hp->parent; } return hp; } /** * rawdump the sbuf to an ostream. */ void sbuf_t::raw_dump(std::ostream &os,uint64_t start,uint64_t len) const { for(uint64_t i=start;ibufsize-start) len=bufsize-start; // maximum left uint64_t written = ::write(fd2,buf+start,len); if(written!=len){ std::cerr << "write: cannot write sbuf.\n"; } } static std::string hexch(unsigned char ch) { char buf[4]; snprintf(buf,sizeof(buf),"%02x",ch); return std::string(buf); } /** * hexdump the sbuf. */ void sbuf_t::hex_dump(std::ostream &os,uint64_t start,uint64_t len) const { const size_t bytes_per_line = 32; size_t max_spaces = 0; for(uint64_t i=start;imax_spaces) max_spaces=spaces; for(;spaces=' ' && ch<='~') os << ch; else os << '.'; } os << "\n"; } } /* Write to a file descriptor */ ssize_t sbuf_t::write(int fd_,size_t loc,size_t len) const { if(loc>=bufsize) return 0; // cannot write if(loc+len>bufsize) len=bufsize-loc; // clip at the end return ::write(fd_,buf+loc,len); } /* Write to a FILE */ ssize_t sbuf_t::write(FILE *f,size_t loc,size_t len) const { if(loc>=bufsize) return 0; // cannot write if(loc+len>bufsize) len=bufsize-loc; // clip at the end return ::fwrite(buf+loc,1,len,f); } /* Return a substring */ std::string sbuf_t::substr(size_t loc,size_t len) const { if(loc>=bufsize) return std::string(""); // cannot write if(loc+len>bufsize) len=bufsize-loc; // clip at the end return std::string((const char *)buf+loc,len); } bool sbuf_t::is_constant(size_t off,size_t len,uint8_t ch) const // verify that it's constant { while(len>0){ if(((*this)[off])!=ch) return false; off++; len--; } return true; } void sbuf_t::hex_dump(std::ostream &os) const { hex_dump(os,0,bufsize); } /** * Convert a binary blob to a hex representation */ #ifndef NSRL_HEXBUF_UPPERCASE #define NSRL_HEXBUF_UPPERCASE 0x01 #define NSRL_HEXBUF_SPACE2 0x02 #define NSRL_HEXBUF_SPACE4 0x04 #endif static int hexcharvals[256] = {-1,0}; static const char *hexbuf(char *dst,int dst_len,const unsigned char *bin,int bytes,int flag) { int charcount = 0; const char *start = dst; // remember where the start of the string is const char *fmt = (flag & NSRL_HEXBUF_UPPERCASE) ? "%02X" : "%02x"; if(hexcharvals[0]==-1){ /* Need to initialize this */ for(int i=0;i<256;i++){ hexcharvals[i] = 0; } for(int i=0;i<10;i++){ hexcharvals['0'+i] = i; } for(int i=10;i<16;i++){ hexcharvals['A'+i-10] = i; hexcharvals['a'+i-10] = i; } } *dst = 0; // begin with null termination while(bytes>0 && dst_len > 3){ sprintf(dst,fmt,*bin); // convert the next byte dst += 2; bin += 1; dst_len -= 2; bytes--; charcount++; // how many characters if((flag & NSRL_HEXBUF_SPACE2) || ((flag & NSRL_HEXBUF_SPACE4) && charcount%2==0)){ *dst++ = ' '; *dst = '\000'; dst_len -= 1; } } return start; // return the start } std::ostream & operator <<(std::ostream &os,const sbuf_t &t){ char hex[17]; hexbuf(hex,sizeof(hex),t.buf,8,0); os << "sbuf[page_number=" << t.page_number << " pos0=" << t.pos0 << " " << "buf[0..8]=0x" << hex << " bufsize=" << t.bufsize << " pagesize=" << t.pagesize << "]"; return os; } /** * Read the requested number of UTF-8 format string octets including any \0. */ void sbuf_t::getUTF8(size_t i, size_t num_octets_requested, std::string &utf8_string) const { // clear any residual value utf8_string = ""; if(i>=bufsize) { // past EOF return; } if(i+num_octets_requested>bufsize) { // clip at EOF num_octets_requested = bufsize - i; } utf8_string = std::string((const char *)buf+i,num_octets_requested); } /** * Read UTF-8 format code octets into string up to but not including \0. */ void sbuf_t::getUTF8(size_t i, std::string &utf8_string) const { // clear any residual value utf8_string = ""; // read octets for (size_t off=i; off=bufsize) { // past EOF return; } if(i+num_code_units_requested*2+1>bufsize) { // clip at EOF num_code_units_requested = ((bufsize-1)-i)/2; } // NOTE: we can't use wstring constructor because we require 16 bits, // not whatever sizeof(wchar_t) is. // utf16_string = std::wstring((const char *)buf+i,num_code_units_requested); // get code units individually for (size_t j = 0; j < num_code_units_requested; j++) { utf16_string.push_back(get16u(i + j*2)); } } /** * Read UTF-16 format code units into wstring up to but not including \U0000. */ void sbuf_t::getUTF16(size_t i, std::wstring &utf16_string) const { // clear any residual value utf16_string = std::wstring(); // read the code units size_t off; for (off=i; off=bufsize) { // past EOF return; } if(i+num_code_units_requested*2+1>bufsize) { // clip at EOF num_code_units_requested = ((bufsize-1)-i)/2; } // NOTE: we can't use wstring constructor because we require 16 bits, // not whatever sizeof(wchar_t) is. // utf16_string = std::wstring((const char *)buf+i,num_code_units_requested); // get code units individually for (size_t j = 0; j < num_code_units_requested; j++) { utf16_string.push_back(get16u(i + j, bo)); } } /** * Read UTF-16 format code units using the specified byte order into wstring up to but not including \U0000. */ void sbuf_t::getUTF16(size_t i, byte_order_t bo, std::wstring &utf16_string) const { // clear any residual value utf16_string = std::wstring(); // read the code units size_t off; for (off=i; off #endif //Don't turn this on; it currently makes scan_net crash. //#define SBUF_TRACK /* required per C++ standard */ #ifndef __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS #endif #include #include #include #include #include /**************************************************************** *** pos0_t ****************************************************************/ /** \addtogroup bulk_extractor_APIs * @{ */ /** \file */ /** * \class pos0_t * The pos0_t structure is used to record the forensic path of the * first byte of an sbuf. The forensic path can include strings associated * with decompressors and ordinals associated with offsets. * * e.g., 1000-GZIP-300-BASE64-30 means go 1000 bytes into the stream, * unzip, go 300 bytes into the decompressed stream, un-BASE64, and * go 30 bytes into that. * * pos0_t uses a string to hold the base path and the offset into that path * in a 64-bit number. */ inline int64_t stoi64(std::string str) { int64_t val(0); std::istringstream ss(str); ss >> val; return val; } class pos0_t { public: const std::string path; /* forensic path of decoders*/ const uint64_t offset; /* location of buf[0] */ explicit pos0_t():path(""),offset(0){} pos0_t(std::string s):path(s),offset(0){} pos0_t(std::string s,uint64_t o):path(s),offset(o){} pos0_t(const pos0_t &obj):path(obj.path),offset(obj.offset){ } std::string str() const { // convert to a string, with offset included std::stringstream ss; if(path.size()>0){ ss << path << "-"; } ss << offset; return ss.str(); } bool isRecursive() const { // is there a path? return path.size() > 0; } std::string firstPart() const { // the first part of the path size_t p = path.find('-'); if(p==std::string::npos) return std::string(""); return path.substr(0,p); } std::string lastAddedPart() const { // the last part of the path, before the offset size_t p = path.rfind('-'); if(p==std::string::npos) return std::string(""); return path.substr(p+1); } std::string alphaPart() const { // return the non-numeric parts, with /'s between each std::string desc; bool inalpha = false; /* Now get the std::string part of pos0 */ for(std::string::const_iterator it = path.begin();it!=path.end();it++){ if((*it)=='-'){ if(desc.size()>0 && desc.at(desc.size()-1)!='/') desc += '/'; inalpha=false; } if(isalpha(*it) || (inalpha && isdigit(*it))){ desc += *it; inalpha=true; } } return desc; } uint64_t imageOffset() const { // return the offset from start of disk if(path.size()>0) return stoi64(path); return offset; } /** * Return a new position that's been shifted by an offset */ pos0_t shift(int64_t s) const { if(s==0) return *this; size_t p = path.find('-'); if(p==std::string::npos){ // no path return pos0_t("",offset+s); } /* Figure out the value of the shift */ int64_t baseOffset = stoi64(path.substr(0,p-1)); std::stringstream ss; ss << (baseOffset+s) << path.substr(p); return pos0_t(ss.str(),offset); } }; /** iostream support for the pos0_t */ inline std::ostream & operator <<(std::ostream &os,const class pos0_t &pos0) { os << "(" << pos0.path << "|" << pos0.offset << ")"; return os; } /** Append a string (subdir). * The current offset is a prefix to the subdir. */ inline class pos0_t operator +(pos0_t pos,const std::string &subdir) { std::stringstream ss; ss << pos.path << (pos.path.size()>0 ? "-" : "") << pos.offset << "-" << subdir; return pos0_t(ss.str(),0); }; /** Adding an offset */ inline class pos0_t operator +(pos0_t pos,int64_t delta) { return pos0_t(pos.path,pos.offset+delta); }; /** \name Comparision operations * @{ */ inline bool operator <(const class pos0_t &pos0,const class pos0_t & pos1) { if(pos0.path.size()==0 && pos1.path.size()==0) return pos0.offset < pos1.offset; if(pos0.path == pos1.path) return pos0.offset < pos1.offset; return pos0.path < pos1.path; }; inline bool operator >(const class pos0_t & pos0,const class pos0_t &pos1) { if(pos0.path.size()==0 && pos1.path.size()==0) return pos0.offset > pos1.offset; if(pos0.path == pos1.path) return pos0.offset > pos1.offset; return pos0.path > pos1.path; }; inline bool operator ==(const class pos0_t & pos0,const class pos0_t &pos1) { return pos0.path==pos1.path && pos0.offset==pos1.offset; }; /** @} */ /** * \class managed_malloc Like new[], but it automatically gets freed when the object is dropped. * throws std::bad_alloc if no memory. */ template < class TYPE > class managed_malloc { // default construction, copy construction and assignment are meaningless // and not implemented managed_malloc& operator=(const managed_malloc&); managed_malloc(const managed_malloc&); managed_malloc(); public: TYPE *buf; managed_malloc(size_t bytes):buf(new TYPE[bytes]){ } ~managed_malloc(){ if(buf) delete []buf; } }; /** * \class sbuf_t * This class describes the search buffer. * The accessors are safe so that no buffer overflow can happen. * Integer readers may throw sbuf_bounds_exception. * * This structure actually holds the data. * We use a pos0_t to maintain the address of the first byte. * * There are lots of ways for allocating an sbuf_t: * - map from a file. * - set from a block of memory. * - a subset of an existing sbuf_t (sbuf+10 gives you 10 bytes in, and therefore 10 bytes shorter) * * The subf_t class remembers how the sbuf_t was allocated and * automatically frees whatever resources are needed when it is freed. * * \warning DANGER: You must delete sbuf_t structures First-In, * Last-out, otherwise bad things can happen. (For example, if you * make a subset sbuf_t from a mapped file and unmap the file, the * subset will now point to unallocated memory.) */ class sbuf_t { private: /* The private structures keep track of memory management */ int fd; /* file this came from if mmapped file */ public:; bool should_unmap; /* munmap buffer when done */ bool should_free; /* should buf be freed when this sbuf is deleted? */ bool should_close; /* close(fd) when done. */ static size_t min(size_t a,size_t b){ return aadd_child(*this); } /** * Make an sbuf from a parent but with a different path. */ explicit sbuf_t(const pos0_t &that_pos0, const sbuf_t &that_sbuf ): fd(0),should_unmap(false),should_free(false),should_close(false), page_number(that_sbuf.page_number),pos0(that_pos0), parent(that_sbuf.highest_parent()),children(0), buf(that_sbuf.buf),bufsize(that_sbuf.bufsize),pagesize(that_sbuf.pagesize){ parent->add_child(*this); } /** * make an sbuf from a parent but with an indent. */ sbuf_t(const sbuf_t &that_sbuf,size_t off): fd(0),should_unmap(false),should_free(false),should_close(false), page_number(that_sbuf.page_number),pos0(that_sbuf.pos0+off), parent(that_sbuf.highest_parent()),children(0), buf(that_sbuf.buf+off), bufsize(that_sbuf.bufsize > off ? that_sbuf.bufsize-off : 0), pagesize(that_sbuf.pagesize > off ? that_sbuf.pagesize-off : 0){ } /** Allocate from an existing sbuf. * The allocated buf MUST be freed before the source, since no copy is made... */ explicit sbuf_t(const sbuf_t &sbuf,size_t off,size_t len): fd(0), should_unmap(false), should_free(false), should_close(false), page_number(sbuf.page_number),pos0(sbuf.pos0+off), parent(sbuf.highest_parent()), children(0), buf(sbuf.buf+off), bufsize(off+lenadd_child(*this); }; /**************************************************************** *** Allocators that allocate from memory ****************************************************************/ /* Allocators */ /** Allocate a new buffer of a given size for filling. * This is the one case where buf is written into... * This should probably be a subclass mutable_sbuf_t() for clarity. */ /* Allocate from an existing buffer, optionally freeing that buffer */ explicit sbuf_t(const pos0_t &pos0_,const uint8_t *buf_, size_t bufsize_,size_t pagesize_, int fd_, bool should_unmap_,bool should_free_,bool should_close_): fd(fd_), should_unmap(should_unmap_), should_free(should_free_), should_close(should_close_), page_number(0),pos0(pos0_),parent(0),children(0),buf(buf_),bufsize(bufsize_), pagesize(min(pagesize_,bufsize_)){ }; /* Similar to above, but with no fd */ explicit sbuf_t(const pos0_t &pos0_,const uint8_t *buf_, size_t bufsize_,size_t pagesize_,bool should_free_): fd(0), should_unmap(false), should_free(should_free_), should_close(false), page_number(0),pos0(pos0_),parent(0),children(0),buf(buf_),bufsize(bufsize_), pagesize(min(pagesize_,bufsize_)){ }; /** * the + operator returns a new sbuf that is i bytes in and, therefore, i bytes smaller. * Note: * 1. We assume that pagesize is always smaller than or equal to bufsize. * 2. The child sbuf uses the parent's memory. If the parent gets deleted, the child points * to invalid data. * * 3. If i is bigger than pagesize, then an sbuf is returned with * 0 bytes in the page and all of the margin. * * (Because we won't return what's in the margin as page data.) */ sbuf_t operator +(size_t off ) const { return sbuf_t(*this,off); } virtual ~sbuf_t(){ #if defined(SBUF_TRACK) && defined(HAVE___SYNC_ADD_AND_FETCH) assert(__sync_fetch_and_add(&children,0)==0); #endif if(parent) parent->del_child(*this); release(); } /* Allocate a sbuf from a file mapped into memory */ static sbuf_t *map_file(const std::string &fname); static sbuf_t *map_file(const std::string &fname,int fd); // if file is already opened static const std::string U10001C; // default delimeter character in bulk_extractor static std::string map_file_delimiter; // character placed static void set_map_file_delimiter(const std::string &new_delim){ map_file_delimiter = new_delim; } /* Properties */ size_t size() const {return bufsize;} // return the number of bytes size_t left(size_t n) const {return n=0); #endif } /** Find the offset of a byte */ size_t offset(const uint8_t *loc) const { if(locbuf+bufsize) return bufsize; return loc-buf; } /** * asString - returns the sbuf as a string */ std::string asString() const {return std::string((reinterpret_cast(buf)),bufsize);} /**************************************************************** *** range_exception_t *** An sbuf_range_exception object is thrown if the attempted sbuf access is out of range. ****************************************************************/ /** * sbuf_t raises an sbuf_range_exception when an attempt is made to read past the end of buf. */ class range_exception_t: public std::exception { public: virtual const char *what() const throw() { return "Error: Read past end of sbuf"; } }; /**************************************************************** *** The following get functions read integer and string types *** or else throw an sbuf_range_exception if out of range. ****************************************************************/ /* Search functions --- memcmp at a particular location */ int memcmp(const uint8_t *cbuf,size_t at,size_t len) const; /** * \name unsigned int Intel (littel-endian) readers * @{ * these get functions safely return an unsigned integer value for the offset of i, * in Intel (little-endian) byte order or else throw sbuf_range_exception if out of range. */ uint8_t get8u(size_t i) const; uint16_t get16u(size_t i) const; uint32_t get32u(size_t i) const; uint64_t get64u(size_t i) const; /** @} */ /** * \name unsigned int Motorola (big-endian) readers * @{ * these get functions safely return an unsigned integer value for the offset of i, * in Motorola (big-endian) byte order or else throw sbuf_range_exception if out of range. */ uint8_t get8uBE(size_t i) const; uint16_t get16uBE(size_t i) const; uint32_t get32uBE(size_t i) const; uint64_t get64uBE(size_t i) const; /** @} */ /** * \name signed int Intel (little-endian) readers * @{ * these get functions safely return a signed integer value for the offset of i, * in Intel (little-endian) byte order or else throw sbuf_range_exception if out of range. */ int8_t get8i(size_t i) const; int16_t get16i(size_t i) const; int32_t get32i(size_t i) const; int64_t get64i(size_t i) const; /** @} */ /** * \name signed int Motorola (big-endian) readers * @{ * these get functions safely return a signed integer value for the offset of i, * in Motorola (big-endian) byte order or else throw sbuf_range_exception if out of range. */ int8_t get8iBE(size_t i) const; int16_t get16iBE(size_t i) const; int32_t get32iBE(size_t i) const; int64_t get64iBE(size_t i) const; /** @} */ /** * some get functions take byte_order_t as a specifier to indicate which endian format to use. */ typedef enum {BO_LITTLE_ENDIAN=0,BO_BIG_ENDIAN=1} byte_order_t; /** * \name unsigned int, byte-order specified readers * @{ * these get functions safely return an unsigned integer value for the offset of i, * in the byte order of your choice or else throw sbuf_range_exception if out of range. */ uint8_t get8u(size_t i,byte_order_t bo) const; uint16_t get16u(size_t i,byte_order_t bo) const; uint32_t get32u(size_t i,byte_order_t bo) const; uint64_t get64u(size_t i,byte_order_t bo) const; /** @} */ /** * \name signed int, byte-order specified readers * @{ * these get functions safely return a signed integer value for the offset of i, * in the byte order of your choice or else throw sbuf_range_exception if out of range. */ int8_t get8i(size_t i,byte_order_t bo) const; int16_t get16i(size_t i,byte_order_t bo) const; int32_t get32i(size_t i,byte_order_t bo) const; int64_t get64i(size_t i,byte_order_t bo) const; /** @} */ /** * \name string readers * @{ * These get functions safely read string */ void getUTF8(size_t i, size_t num_octets_requested, std::string &utf8_string) const; void getUTF8(size_t i, std::string &utf8_string) const; /** @} */ /** * \name wstring readers * @{ * These get functions safely read wstring */ void getUTF16(size_t i, size_t num_code_units_requested, std::wstring &utf16_string) const; void getUTF16(size_t i, std::wstring &utf16_string) const; void getUTF16(size_t i, size_t num_code_units_requested, byte_order_t bo, std::wstring &utf16_string) const; void getUTF16(size_t i, byte_order_t bo, std::wstring &utf16_string) const; /** @} */ /** * The [] operator safely returns what's at index [i] or else returns 0 if out of range. * We made a decision that this would not throw the exception * Notice that we don't need to check to see if i<0 because i is unsigned. */ uint8_t operator [](size_t i) const { return (ipagesize,ch); } // Return a pointer to a structure contained within the sbuf if there is // room, otherwise return a null pointer. template const TYPE * get_struct_ptr(uint32_t pos) const { if (pos + sizeof(TYPE) <= bufsize) { return reinterpret_cast (buf+pos); } return NULL; } /** * These are largely for debugging, but they also support the BEViewer. * Dump the sbuf to a stream. */ void raw_dump(std::ostream &os,uint64_t start,uint64_t len) const; void raw_dump(int fd,uint64_t start,uint64_t len) const; // writes to a raw file descriptor void hex_dump(std::ostream &os,uint64_t start,uint64_t len) const; void hex_dump(std::ostream &os) const; /* dump all */ ssize_t write(int fd,size_t loc,size_t len) const; /* write to a file descriptor, returns # bytes written */ ssize_t write(FILE *f,size_t loc,size_t len) const; /* write to a file descriptor, returns # bytes written */ }; std::ostream & operator <<(std::ostream &os,const sbuf_t &sbuf); #include "sbuf_private.h" #endif tcpflow-tcpflow-1.6.1/src/be13_api/sbuf_private.h000066400000000000000000000112201401360461700216630ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ #ifndef SBUF_PRIVATE_H #define SBUF_PRIVATE_H #include #ifdef HAVE_MMAP #include #endif inline int sbuf_t::memcmp(const uint8_t *cbuf,size_t at,size_t len) const { if(left(at) < len) throw sbuf_t::range_exception_t(); return ::memcmp(this->buf+at,cbuf,len); } /** * Unsigned get interfaces */ inline uint8_t sbuf_t::get8u(size_t i) const { if(i+1>bufsize) throw sbuf_t::range_exception_t(); return this->buf[i]; } inline uint16_t sbuf_t::get16u(size_t i) const { if(i+2>bufsize) throw sbuf_t::range_exception_t(); return 0 | (uint16_t)(this->buf[i+0]<<0) | (uint16_t)(this->buf[i+1]<<8); } inline uint32_t sbuf_t::get32u(size_t i) const { if(i+4>bufsize) throw sbuf_t::range_exception_t(); return 0 | (uint32_t)(this->buf[i+0]<<0) | (uint32_t)(this->buf[i+1]<<8) | (uint32_t)(this->buf[i+2]<<16) | (uint32_t)(this->buf[i+3]<<24); } inline uint64_t sbuf_t::get64u(size_t i) const { if(i+8>bufsize) throw sbuf_t::range_exception_t(); return 0 | ((uint64_t)(this->buf[i+0])<<0) | ((uint64_t)(this->buf[i+1])<<8) | ((uint64_t)(this->buf[i+2])<<16) | ((uint64_t)(this->buf[i+3])<<24) | ((uint64_t)(this->buf[i+4])<<32) | ((uint64_t)(this->buf[i+5])<<40) | ((uint64_t)(this->buf[i+6])<<48) | ((uint64_t)(this->buf[i+7])<<56); } inline uint8_t sbuf_t::get8uBE(size_t i) const { if(i+1>bufsize) throw sbuf_t::range_exception_t(); return this->buf[i]; } inline uint16_t sbuf_t::get16uBE(size_t i) const { if(i+2>bufsize) throw sbuf_t::range_exception_t(); return 0 | (uint16_t)(this->buf[i+1]<<0) | (uint16_t)(this->buf[i+0]<<8); } inline uint32_t sbuf_t::get32uBE(size_t i) const { if(i+4>bufsize) throw sbuf_t::range_exception_t(); return 0 | (uint32_t)(this->buf[i+3]<<0) | (uint32_t)(this->buf[i+2]<<8) | (uint32_t)(this->buf[i+1]<<16) | (uint32_t)(this->buf[i+0]<<24); } inline uint64_t sbuf_t::get64uBE(size_t i) const { if(i+8>bufsize) throw sbuf_t::range_exception_t(); return 0 | ((uint64_t)(this->buf[i+7])<<0) | ((uint64_t)(this->buf[i+6])<<8) | ((uint64_t)(this->buf[i+5])<<16) | ((uint64_t)(this->buf[i+4])<<24) | ((uint64_t)(this->buf[i+3])<<32) | ((uint64_t)(this->buf[i+2])<<40) | ((uint64_t)(this->buf[i+1])<<48) | ((uint64_t)(this->buf[i+0])<<56); } inline uint8_t sbuf_t::get8u(size_t i,sbuf_t::byte_order_t bo) const { return bo==BO_LITTLE_ENDIAN ? get8u(i) : get8uBE(i); } inline uint16_t sbuf_t::get16u(size_t i,sbuf_t::byte_order_t bo) const { return bo==BO_LITTLE_ENDIAN ? get16u(i) : get16uBE(i); } inline uint32_t sbuf_t::get32u(size_t i,sbuf_t::byte_order_t bo) const { return bo==BO_LITTLE_ENDIAN ? get32u(i) : get32uBE(i); } inline uint64_t sbuf_t::get64u(size_t i,sbuf_t::byte_order_t bo) const { return bo==BO_LITTLE_ENDIAN ? get64u(i) : get64uBE(i); } /** * Signed get interfaces simply call the unsigned interfaces and * the return gets cast. */ inline int8_t sbuf_t::get8i(size_t i) const { return get8u(i);} inline int16_t sbuf_t::get16i(size_t i) const { return get16u(i);} inline int32_t sbuf_t::get32i(size_t i) const { return get32u(i);} inline int64_t sbuf_t::get64i(size_t i) const { return get64u(i);} inline int8_t sbuf_t::get8iBE(size_t i) const { return get8uBE(i);} inline int16_t sbuf_t::get16iBE(size_t i) const { return get16uBE(i);} inline int32_t sbuf_t::get32iBE(size_t i) const { return get32uBE(i);} inline int64_t sbuf_t::get64iBE(size_t i) const { return get64uBE(i);} inline int8_t sbuf_t::get8i(size_t i,sbuf_t::byte_order_t bo) const { return bo==BO_LITTLE_ENDIAN ? get8u(i) : get8uBE(i); } inline int16_t sbuf_t::get16i(size_t i,sbuf_t::byte_order_t bo) const { return bo==BO_LITTLE_ENDIAN ? get16u(i) : get16uBE(i); } inline int32_t sbuf_t::get32i(size_t i,sbuf_t::byte_order_t bo) const { return bo==BO_LITTLE_ENDIAN ? get32u(i) : get32uBE(i); } inline int64_t sbuf_t::get64i(size_t i,sbuf_t::byte_order_t bo) const { return bo==BO_LITTLE_ENDIAN ? get64u(i) : get64uBE(i); } inline void sbuf_t::release() { #ifdef HAVE_MMAP if(should_unmap && buf){ munmap((void *)buf,bufsize); should_unmap = false; buf = 0; } #endif if(should_close && fd>0){ ::close(fd); should_close = false; fd=0; } if(should_free && buf){ free((void *)buf); should_free = false; buf = 0; } page_number = 0; bufsize = 0; pagesize = 0; } #endif tcpflow-tcpflow-1.6.1/src/be13_api/sbuf_stream.cpp000066400000000000000000000106041401360461700220440ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ #include "config.h" #include "bulk_extractor_i.h" #include "sbuf_stream.h" /* * Stream interfaces */ sbuf_stream::sbuf_stream(const sbuf_t &sbuf_): sbuf(sbuf_),offset(0) { } sbuf_stream::~sbuf_stream() { } void sbuf_stream::seek(size_t offset_) { offset = offset_; } size_t sbuf_stream::tell() { return offset; } /* * unsigned integers, default little endian */ uint8_t sbuf_stream::get8u() { uint8_t value = sbuf.get8u(offset); offset++; return value; } uint16_t sbuf_stream::get16u() { uint16_t value = sbuf.get16u(offset); offset+=2; return value; } uint32_t sbuf_stream::get32u() { uint32_t value = sbuf.get32u(offset); offset+=4; return value; } uint64_t sbuf_stream::get64u() { uint64_t value = sbuf.get64u(offset); offset+=8; return value; } /* * unsigned integers, big endian */ uint8_t sbuf_stream::get8uBE() { uint8_t value = sbuf.get8uBE(offset); offset++; return value; } uint16_t sbuf_stream::get16uBE() { uint16_t value = sbuf.get16uBE(offset); offset+=2; return value; } uint32_t sbuf_stream::get32uBE() { uint32_t value = sbuf.get32uBE(offset); offset+=4; return value; } uint64_t sbuf_stream::get64uBE() { uint64_t value = sbuf.get64uBE(offset); offset+=8; return value; } /* * unsigned integers, byte order specified */ uint8_t sbuf_stream::get8u(sbuf_t::byte_order_t bo) { uint8_t value = sbuf.get8u(offset, bo); offset++; return value; } uint16_t sbuf_stream::get16u(sbuf_t::byte_order_t bo) { uint16_t value = sbuf.get16u(offset, bo); offset+=2; return value; } uint32_t sbuf_stream::get32u(sbuf_t::byte_order_t bo) { uint32_t value = sbuf.get32u(offset, bo); offset+=4; return value; } uint64_t sbuf_stream::get64u(sbuf_t::byte_order_t bo) { uint64_t value = sbuf.get64u(offset, bo); offset+=8; return value; } /* * signed integers, default little endian */ int8_t sbuf_stream::get8i() { int8_t value = sbuf.get8i(offset); offset++; return value; } int16_t sbuf_stream::get16i() { int16_t value = sbuf.get16i(offset); offset+=2; return value; } int32_t sbuf_stream::get32i() { int32_t value = sbuf.get32i(offset); offset+=4; return value; } int64_t sbuf_stream::get64i() { int64_t value = sbuf.get64i(offset); offset+=8; return value; } /* * signed integers, big endian */ int8_t sbuf_stream::get8iBE() { int8_t value = sbuf.get8iBE(offset); offset++; return value; } int16_t sbuf_stream::get16iBE() { int16_t value = sbuf.get16iBE(offset); offset+=2; return value; } int32_t sbuf_stream::get32iBE() { int32_t value = sbuf.get32iBE(offset); offset+=4; return value; } int64_t sbuf_stream::get64iBE() { int64_t value = sbuf.get64iBE(offset); offset+=8; return value; } /* * signed integers, byte order specified */ int8_t sbuf_stream::get8i(sbuf_t::byte_order_t bo) { uint8_t value = sbuf.get8i(offset, bo); offset++; return value; } int16_t sbuf_stream::get16i(sbuf_t::byte_order_t bo) { uint16_t value = sbuf.get16i(offset, bo); offset+=2; return value; } int32_t sbuf_stream::get32i(sbuf_t::byte_order_t bo) { uint32_t value = sbuf.get32i(offset, bo); offset+=4; return value; } int64_t sbuf_stream::get64i(sbuf_t::byte_order_t bo) { uint64_t value = sbuf.get64i(offset, bo); offset+=8; return value; } /* * string readers */ void sbuf_stream::getUTF8(size_t num_octets_requested, string &utf8_string) { sbuf.getUTF8(num_octets_requested, utf8_string); offset += utf8_string.length(); return; } void sbuf_stream::getUTF8(string &utf8_string) { sbuf.getUTF8(offset, utf8_string); size_t num_bytes = utf8_string.length(); if (num_bytes > 0) { // if anything was read then also skip \0 num_bytes ++; } offset += num_bytes; return; } void sbuf_stream::getUTF16(size_t code_units_requested, wstring &utf16_string) { sbuf.getUTF16(offset, code_units_requested, utf16_string); offset += utf16_string.length() * 2; return; } void sbuf_stream::getUTF16(wstring &utf16_string) { sbuf.getUTF16(offset, utf16_string); size_t num_bytes = utf16_string.length() * 2; if (num_bytes > 0) { // if anything was read then also skip \U0000 num_bytes += 2; } offset += num_bytes; return; } tcpflow-tcpflow-1.6.1/src/be13_api/sbuf_stream.h000066400000000000000000000035261401360461700215160ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ #ifndef SBUF_STREAM_H #define SBUF_STREAM_H /* required per C++ standard */ #ifndef __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS #endif using namespace std; #include #include #include #include #include "sbuf.h" /** \addtogroup bulk_extractor_APIs * @{ */ /** \file */ /** * sbuf_stream provides the get services of sbuf_t but wrapped in a Stream interface. * Note that sbuf_stream is not particularly optimized; it is simply a wrapper. */ class sbuf_stream { private: const sbuf_t sbuf; size_t offset; public: sbuf_stream(const sbuf_t &sbuf_); ~sbuf_stream(); void seek(size_t offset); size_t tell(); /** * \name integer-based stream readers * @{ */ uint8_t get8u(); uint16_t get16u(); uint32_t get32u(); uint64_t get64u(); uint8_t get8uBE(); uint16_t get16uBE(); uint32_t get32uBE(); uint64_t get64uBE(); uint8_t get8u(sbuf_t::byte_order_t bo); uint16_t get16u(sbuf_t::byte_order_t bo); uint32_t get32u(sbuf_t::byte_order_t bo); uint64_t get64u(sbuf_t::byte_order_t bo); int8_t get8i(); int16_t get16i(); int32_t get32i(); int64_t get64i(); int8_t get8iBE(); int16_t get16iBE(); int32_t get32iBE(); int64_t get64iBE(); int8_t get8i(sbuf_t::byte_order_t bo); int16_t get16i(sbuf_t::byte_order_t bo); int32_t get32i(sbuf_t::byte_order_t bo); int64_t get64i(sbuf_t::byte_order_t bo); /** @} */ /** * \name string and wstring stream readers * @{ */ void getUTF8(string &utf8_string); void getUTF8(size_t num_octets_requested, string &utf8_string); void getUTF16(wstring &utf16_string); void getUTF16(size_t num_code_units_requested, wstring &utf16_string); /** @} */ }; #endif tcpflow-tcpflow-1.6.1/src/be13_api/unicode_escape.cpp000066400000000000000000000250511401360461700225020ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * unicode_escape.cpp: * Escape unicode that is not valid. * * References: * http://www.ietf.org/rfc/rfc3987.txt * http://en.wikipedia.org/wiki/UTF-8 * * @author Simson Garfinkel * * * The software provided here is released by the Naval Postgraduate * School, an agency of the U.S. Department of Navy. The software * bears no warranty, either expressed or implied. NPS does not assume * legal liability nor responsibility for a User's use of the software * or the results of such use. * * Please note that within the United States, copyright protection, * under Section 105 of the United States Code, Title 17, is not * available for any work of the United States Government and/or for * any works created by United States Government employees. User * acknowledges that this software contains work which was created by * NPS government employees and is therefore in the public domain and * not subject to copyright. */ #ifndef PACKAGE_NAME #include "config.h" #endif #include "unicode_escape.h" #include #include #include #include #ifndef __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS #endif #ifdef HAVE_STDINT_H #include #endif #define IS_IN_RANGE(c, f, l) (((c) >= (f)) && ((c) <= (l))) #include "utf8.h" //extern int debug; std::string hexesc(unsigned char ch) { char buf[10]; snprintf(buf,sizeof(buf),"\\x%02X",ch); return std::string(buf); } /** returns true if this is a UTF8 continuation character */ bool utf8cont(unsigned char ch) { return ((ch&0x80)==0x80) && ((ch & 0x40)==0); } /** * After a UTF-8 sequence is decided, this function is called * to determine if the character is invalid. The UTF-8 spec now * says that if a UTF-8 decoding produces an invalid character, or * a surrogate, it is not valid. (There were some nasty security * vulnerabilities that were exploited before this came out.) * So we do a lot of checks here. */ bool valid_utf8codepoint(uint32_t unichar) { // Check for invalid characters in the bmp switch(unichar){ case 0xfffe: return false; // reversed BOM case 0xffff: return false; default: break; } if(unichar >= 0xd800 && unichar <=0xdfff) return false; // high and low surrogates if(unichar < 0x10000) return true; // looks like it is in the BMP // check some regions outside the bmp // Plane 1: if(unichar > 0x13fff && unichar < 0x16000) return false; if(unichar > 0x16fff && unichar < 0x1b000) return false; if(unichar > 0x1bfff && unichar < 0x1d000) return false; // Plane 2 if(unichar > 0x2bfff && unichar < 0x2f000) return false; // Planes 3--13 are unassigned if(unichar >= 0x30000 && unichar < 0xdffff) return false; // Above Plane 16 is invalid if(unichar > 0x10FFFF) return false; // above plane 16? return true; // must be valid } /** * validateOrEscapeUTF8 * Input: UTF8 string (possibly corrupt) * Input: do_escape, indicating whether invalid encodings shall be escaped. * Note: * - if not escaping but an invalid encoding is present and DEBUG_PEDANTIC is set, then assert() is called. * - DO NOT USE wchar_t because it is 16-bits on Windows and 32-bits on Unix. * Output: * - UTF8 string. If do_escape is set, then corruptions are escaped in \xFF notation where FF is a hex character. */ //int count=0; bool validateOrEscapeUTF8_validate=false; std::string validateOrEscapeUTF8(const std::string &input, bool escape_bad_utf8,bool escape_backslash) { // // skip the validation if not escaping and not DEBUG_PEDANTIC if (escape_bad_utf8==false && escape_backslash==false && !validateOrEscapeUTF8_validate){ return input; } // validate or escape input std::string output; for(std::string::size_type i =0; i< input.length(); ) { uint8_t ch = (uint8_t)input.at(i); // utf8 1 byte prefix (0xxx xxxx) if((ch & 0x80)==0x00){ // 00 .. 0x7f if(ch=='\\' && escape_backslash){ // escape the escape character as \x92 output += hexesc(ch); i++; continue; } if( ch < ' '){ // not printable are escaped output += hexesc(ch); i++; continue; } output += ch; // printable is not escaped i++; continue; } // utf8 2 bytes (110x xxxx) prefix if(((ch & 0xe0)==0xc0) // 2-byte prefix && (i+1 < input.length()) && utf8cont((uint8_t)input.at(i+1))){ uint32_t unichar = (((uint8_t)input.at(i) & 0x1f) << 6) | (((uint8_t)input.at(i+1) & 0x3f)); // check for valid 2-byte encoding if(valid_utf8codepoint(unichar) && ((uint8_t)input.at(i)!=0xc0) && (unichar >= 0x80)){ output += (uint8_t)input.at(i++); // byte1 output += (uint8_t)input.at(i++); // byte2 continue; } } // utf8 3 bytes (1110 xxxx prefix) if(((ch & 0xf0) == 0xe0) && (i+2 < input.length()) && utf8cont((uint8_t)input.at(i+1)) && utf8cont((uint8_t)input.at(i+2))){ uint32_t unichar = (((uint8_t)input.at(i) & 0x0f) << 12) | (((uint8_t)input.at(i+1) & 0x3f) << 6) | (((uint8_t)input.at(i+2) & 0x3f)); // check for a valid 3-byte code point if(valid_utf8codepoint(unichar) && unichar>=0x800){ output += (uint8_t)input.at(i++); // byte1 output += (uint8_t)input.at(i++); // byte2 output += (uint8_t)input.at(i++); // byte3 continue; } } // utf8 4 bytes (1111 0xxx prefix) if((( ch & 0xf8) == 0xf0) && (i+3 < input.length()) && utf8cont((uint8_t)input.at(i+1)) && utf8cont((uint8_t)input.at(i+2)) && utf8cont((uint8_t)input.at(i+3))){ uint32_t unichar =( (((uint8_t)input.at(i) & 0x07) << 18) |(((uint8_t)input.at(i+1) & 0x3f) << 12) |(((uint8_t)input.at(i+2) & 0x3f) << 6) |(((uint8_t)input.at(i+3) & 0x3f))); if(valid_utf8codepoint(unichar) && unichar>=0x1000000){ output += (uint8_t)input.at(i++); // byte1 output += (uint8_t)input.at(i++); // byte2 output += (uint8_t)input.at(i++); // byte3 output += (uint8_t)input.at(i++); // byte4 continue; } } if (escape_bad_utf8) { // Just escape the next byte and carry on output += hexesc((uint8_t)input.at(i++)); } else { // fatal if we are debug pedantic, otherwise just ignore // note: we shouldn't be here anyway, since if we are not escaping and we are not // pedantic we should have returned above if(validateOrEscapeUTF8_validate){ std::ofstream os("bad_unicode.txt"); os << input << "\n"; os.close(); std::cerr << "INTERNAL ERROR: bad unicode stored in bad_unicode.txt\n"; assert(0); } } } return output; } #ifdef STANDALONE void show(const std::string &ugly) { for(size_t j=0;j /** \addtogroup bulk_extractor_APIs * @{ */ /** \file */ extern bool validateOrEscapeUTF8_validate; std::string validateOrEscapeUTF8(const std::string &input, bool escape_bad_UTF8,bool escape_backslash); #endif tcpflow-tcpflow-1.6.1/src/be13_api/utf8.h000066400000000000000000000031261401360461700200660ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ // Copyright 2006 Nemanja Trifunovic /* Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731 #define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731 #include "utf8/checked.h" #include "utf8/unchecked.h" #endif // header guard tcpflow-tcpflow-1.6.1/src/be13_api/utf8/000077500000000000000000000000001401360461700177135ustar00rootroot00000000000000tcpflow-tcpflow-1.6.1/src/be13_api/utf8/checked.h000066400000000000000000000273011401360461700214550ustar00rootroot00000000000000// Copyright 2006 Nemanja Trifunovic /* Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 #define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 #include "core.h" #include namespace utf8 { // Base for the exceptions that may be thrown from the library class exception : public std::exception { }; // Exceptions that may be thrown from the library functions. class invalid_code_point : public exception { uint32_t cp; public: invalid_code_point(uint32_t cp_) : cp(cp_) {} virtual const char* what() const throw() { return "Invalid code point"; } uint32_t code_point() const {return cp;} }; class invalid_utf8 : public exception { uint8_t u8; public: invalid_utf8 (uint8_t u) : u8(u) {} virtual const char* what() const throw() { return "Invalid UTF-8"; } uint8_t utf8_octet() const {return u8;} }; class invalid_utf16 : public exception { uint16_t u16; public: invalid_utf16 (uint16_t u) : u16(u) {} virtual const char* what() const throw() { return "Invalid UTF-16"; } uint16_t utf16_word() const {return u16;} }; class not_enough_room : public exception { public: virtual const char* what() const throw() { return "Not enough space"; } }; /// The library API - functions intended to be called by the users template output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement) { while (start != end) { octet_iterator sequence_start = start; internal::utf_error err_code = internal::validate_next(start, end); switch (err_code) { case internal::UTF8_OK : for (octet_iterator it = sequence_start; it != start; ++it) *out++ = *it; break; case internal::NOT_ENOUGH_ROOM: throw not_enough_room(); case internal::INVALID_LEAD: append (replacement, out); ++start; break; case internal::INCOMPLETE_SEQUENCE: case internal::OVERLONG_SEQUENCE: case internal::INVALID_CODE_POINT: append (replacement, out); ++start; // just one replacement mark for the sequence while (internal::is_trail(*start) && start != end) ++start; break; } } return out; } template inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out) { static const uint32_t replacement_marker = internal::mask16(0xfffd); return replace_invalid(start, end, out, replacement_marker); } template octet_iterator append(uint32_t cp, octet_iterator result) { if (!internal::is_code_point_valid(cp)) throw invalid_code_point(cp); if (cp < 0x80) // one octet *(result++) = static_cast(cp); else if (cp < 0x800) { // two octets *(result++) = static_cast((cp >> 6) | 0xc0); *(result++) = static_cast((cp & 0x3f) | 0x80); } else if (cp < 0x10000) { // three octets *(result++) = static_cast((cp >> 12) | 0xe0); *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); *(result++) = static_cast((cp & 0x3f) | 0x80); } else { // four octets *(result++) = static_cast((cp >> 18) | 0xf0); *(result++) = static_cast(((cp >> 12) & 0x3f) | 0x80); *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); *(result++) = static_cast((cp & 0x3f) | 0x80); } return result; } template uint32_t next(octet_iterator& it, octet_iterator end) { uint32_t cp = 0; internal::utf_error err_code = internal::validate_next(it, end, &cp); switch (err_code) { case internal::UTF8_OK : break; case internal::NOT_ENOUGH_ROOM : throw not_enough_room(); case internal::INVALID_LEAD : case internal::INCOMPLETE_SEQUENCE : case internal::OVERLONG_SEQUENCE : throw invalid_utf8(*it); case internal::INVALID_CODE_POINT : throw invalid_code_point(cp); } return cp; } template uint32_t peek_next(octet_iterator it, octet_iterator end) { return next(it, end); } template uint32_t prior(octet_iterator& it, octet_iterator start) { // can't do much if it == start if (it == start) throw not_enough_room(); octet_iterator end = it; // Go back until we hit either a lead octet or start while (internal::is_trail(*(--it))) if (it == start) throw invalid_utf8(*it); // error - no lead byte in the sequence return peek_next(it, end); } /// Deprecated in versions that include "prior" template uint32_t previous(octet_iterator& it, octet_iterator pass_start) { octet_iterator end = it; while (internal::is_trail(*(--it))) if (it == pass_start) throw invalid_utf8(*it); // error - no lead byte in the sequence octet_iterator temp = it; return next(temp, end); } template void advance (octet_iterator& it, distance_type n, octet_iterator end) { for (distance_type i = 0; i < n; ++i) next(it, end); } template typename std::iterator_traits::difference_type distance (octet_iterator first, octet_iterator last) { typename std::iterator_traits::difference_type dist; for (dist = 0; first < last; ++dist) next(first, last); return dist; } template octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result) { while (start != end) { uint32_t cp = internal::mask16(*start++); // Take care of surrogate pairs first if (internal::is_lead_surrogate(cp)) { if (start != end) { uint32_t trail_surrogate = internal::mask16(*start++); if (internal::is_trail_surrogate(trail_surrogate)) cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; else throw invalid_utf16(static_cast(trail_surrogate)); } else throw invalid_utf16(static_cast(cp)); } // Lone trail surrogate else if (internal::is_trail_surrogate(cp)) throw invalid_utf16(static_cast(cp)); result = append(cp, result); } return result; } template u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result) { while (start != end) { uint32_t cp = next(start, end); if (cp > 0xffff) { //make a surrogate pair *result++ = static_cast((cp >> 10) + internal::LEAD_OFFSET); *result++ = static_cast((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); } else *result++ = static_cast(cp); } return result; } template octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) { while (start != end) result = append(*(start++), result); return result; } template u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result) { while (start != end) (*result++) = next(start, end); return result; } // The iterator class template class iterator : public std::iterator { octet_iterator it; octet_iterator range_start; octet_iterator range_end; public: iterator () {}; explicit iterator (const octet_iterator& octet_it, const octet_iterator& range_start_, const octet_iterator& range_end_) : it(octet_it), range_start(range_start_), range_end(range_end_) { if (it < range_start || it > range_end) throw std::out_of_range("Invalid utf-8 iterator position"); } // the default "big three" are OK octet_iterator base () const { return it; } uint32_t operator * () const { octet_iterator temp = it; return next(temp, range_end); } bool operator == (const iterator& rhs) const { if (range_start != rhs.range_start || range_end != rhs.range_end) throw std::logic_error("Comparing utf-8 iterators defined with different ranges"); return (it == rhs.it); } bool operator != (const iterator& rhs) const { return !(operator == (rhs)); } iterator& operator ++ () { next(it, range_end); return *this; } iterator operator ++ (int) { iterator temp = *this; next(it, range_end); return temp; } iterator& operator -- () { prior(it, range_start); return *this; } iterator operator -- (int) { iterator temp = *this; prior(it, range_start); return temp; } }; // class iterator } // namespace utf8 #endif //header guard tcpflow-tcpflow-1.6.1/src/be13_api/utf8/core.h000066400000000000000000000267711401360461700210310ustar00rootroot00000000000000// Copyright 2006 Nemanja Trifunovic /* Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 #define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 #include namespace utf8 { // The typedefs for 8-bit, 16-bit and 32-bit unsigned integers // You may need to change them to match your system. // These typedefs have the same names as ones from cstdint, or boost/cstdint typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; // Helper code - not intended to be directly called by the library users. May be changed at any time namespace internal { // Unicode constants // Leading (high) surrogates: 0xd800 - 0xdbff // Trailing (low) surrogates: 0xdc00 - 0xdfff const uint16_t LEAD_SURROGATE_MIN = 0xd800u; const uint16_t LEAD_SURROGATE_MAX = 0xdbffu; const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u; const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu; const uint16_t LEAD_OFFSET = LEAD_SURROGATE_MIN - (0x10000 >> 10); const uint32_t SURROGATE_OFFSET = 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN; // Maximum valid value for a Unicode code point const uint32_t CODE_POINT_MAX = 0x0010ffffu; template inline uint8_t mask8(octet_type oc) { return static_cast(0xff & oc); } template inline uint16_t mask16(u16_type oc) { return static_cast(0xffff & oc); } template inline bool is_trail(octet_type oc) { return ((mask8(oc) >> 6) == 0x2); } template inline bool is_lead_surrogate(u16 cp) { return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX); } template inline bool is_trail_surrogate(u16 cp) { return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX); } template inline bool is_surrogate(u16 cp) { return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX); } template inline bool is_code_point_valid(u32 cp) { return (cp <= CODE_POINT_MAX && !is_surrogate(cp)); } template inline typename std::iterator_traits::difference_type sequence_length(octet_iterator lead_it) { uint8_t lead = mask8(*lead_it); if (lead < 0x80) return 1; else if ((lead >> 5) == 0x6) return 2; else if ((lead >> 4) == 0xe) return 3; else if ((lead >> 3) == 0x1e) return 4; else return 0; } template inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length) { if (cp < 0x80) { if (length != 1) return true; } else if (cp < 0x800) { if (length != 2) return true; } else if (cp < 0x10000) { if (length != 3) return true; } return false; } enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT}; /// get_sequence_x functions decode utf-8 sequences of the length x template utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t* code_point) { if (it != end) { if (code_point) *code_point = mask8(*it); return UTF8_OK; } return NOT_ENOUGH_ROOM; } template utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t* code_point) { utf_error ret_code = NOT_ENOUGH_ROOM; if (it != end) { uint32_t cp = mask8(*it); if (++it != end) { if (is_trail(*it)) { cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f); if (code_point) *code_point = cp; ret_code = UTF8_OK; } else ret_code = INCOMPLETE_SEQUENCE; } else ret_code = NOT_ENOUGH_ROOM; } return ret_code; } template utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t* code_point) { utf_error ret_code = NOT_ENOUGH_ROOM; if (it != end) { uint32_t cp = mask8(*it); if (++it != end) { if (is_trail(*it)) { cp = ((cp << 12) & 0xffff) + ((mask8(*it) << 6) & 0xfff); if (++it != end) { if (is_trail(*it)) { cp += (*it) & 0x3f; if (code_point) *code_point = cp; ret_code = UTF8_OK; } else ret_code = INCOMPLETE_SEQUENCE; } else ret_code = NOT_ENOUGH_ROOM; } else ret_code = INCOMPLETE_SEQUENCE; } else ret_code = NOT_ENOUGH_ROOM; } return ret_code; } template utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t* code_point) { utf_error ret_code = NOT_ENOUGH_ROOM; if (it != end) { uint32_t cp = mask8(*it); if (++it != end) { if (is_trail(*it)) { cp = ((cp << 18) & 0x1fffff) + ((mask8(*it) << 12) & 0x3ffff); if (++it != end) { if (is_trail(*it)) { cp += (mask8(*it) << 6) & 0xfff; if (++it != end) { if (is_trail(*it)) { cp += (*it) & 0x3f; if (code_point) *code_point = cp; ret_code = UTF8_OK; } else ret_code = INCOMPLETE_SEQUENCE; } else ret_code = NOT_ENOUGH_ROOM; } else ret_code = INCOMPLETE_SEQUENCE; } else ret_code = NOT_ENOUGH_ROOM; } else ret_code = INCOMPLETE_SEQUENCE; } else ret_code = NOT_ENOUGH_ROOM; } return ret_code; } template utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t* code_point) { // Save the original value of it so we can go back in case of failure // Of course, it does not make much sense with i.e. stream iterators octet_iterator original_it = it; uint32_t cp = 0; // Determine the sequence length based on the lead octet typedef typename std::iterator_traits::difference_type octet_difference_type; octet_difference_type length = sequence_length(it); if (length == 0) return INVALID_LEAD; // Now that we have a valid sequence length, get trail octets and calculate the code point utf_error err = UTF8_OK; switch (length) { case 1: err = get_sequence_1(it, end, &cp); break; case 2: err = get_sequence_2(it, end, &cp); break; case 3: err = get_sequence_3(it, end, &cp); break; case 4: err = get_sequence_4(it, end, &cp); break; } if (err == UTF8_OK) { // Decoding succeeded. Now, security checks... if (is_code_point_valid(cp)) { if (!is_overlong_sequence(cp, length)){ // Passed! Return here. if (code_point) *code_point = cp; ++it; return UTF8_OK; } else err = OVERLONG_SEQUENCE; } else err = INVALID_CODE_POINT; } // Failure branch - restore the original value of the iterator it = original_it; return err; } template inline utf_error validate_next(octet_iterator& it, octet_iterator end) { return validate_next(it, end, 0); } } // namespace internal /// The library API - functions intended to be called by the users // Byte order mark const uint8_t bom[] = {0xef, 0xbb, 0xbf}; template octet_iterator find_invalid(octet_iterator start, octet_iterator end) { octet_iterator result = start; while (result != end) { internal::utf_error err_code = internal::validate_next(result, end); if (err_code != internal::UTF8_OK) return result; } return result; } template inline bool is_valid(octet_iterator start, octet_iterator end) { return (find_invalid(start, end) == end); } template inline bool starts_with_bom (octet_iterator it, octet_iterator end) { return ( ((it != end) && (internal::mask8(*it++)) == bom[0]) && ((it != end) && (internal::mask8(*it++)) == bom[1]) && ((it != end) && (internal::mask8(*it)) == bom[2]) ); } //Deprecated in release 2.3 template inline bool is_bom (octet_iterator it) { return ( (internal::mask8(*it++)) == bom[0] && (internal::mask8(*it++)) == bom[1] && (internal::mask8(*it)) == bom[2] ); } } // namespace utf8 #endif // header guard tcpflow-tcpflow-1.6.1/src/be13_api/utf8/unchecked.h000066400000000000000000000207001401360461700220140ustar00rootroot00000000000000// Copyright 2006 Nemanja Trifunovic /* Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 #define UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 #include "core.h" namespace utf8 { namespace unchecked { template octet_iterator append(uint32_t cp, octet_iterator result) { if (cp < 0x80) // one octet *(result++) = static_cast(cp); else if (cp < 0x800) { // two octets *(result++) = static_cast((cp >> 6) | 0xc0); *(result++) = static_cast((cp & 0x3f) | 0x80); } else if (cp < 0x10000) { // three octets *(result++) = static_cast((cp >> 12) | 0xe0); *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); *(result++) = static_cast((cp & 0x3f) | 0x80); } else { // four octets *(result++) = static_cast((cp >> 18) | 0xf0); *(result++) = static_cast(((cp >> 12) & 0x3f)| 0x80); *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); *(result++) = static_cast((cp & 0x3f) | 0x80); } return result; } template uint32_t next(octet_iterator& it) { uint32_t cp = internal::mask8(*it); typename std::iterator_traits::difference_type length = utf8::internal::sequence_length(it); switch (length) { case 1: break; case 2: it++; cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f); break; case 3: ++it; cp = ((cp << 12) & 0xffff) + ((internal::mask8(*it) << 6) & 0xfff); ++it; cp += (*it) & 0x3f; break; case 4: ++it; cp = ((cp << 18) & 0x1fffff) + ((internal::mask8(*it) << 12) & 0x3ffff); ++it; cp += (internal::mask8(*it) << 6) & 0xfff; ++it; cp += (*it) & 0x3f; break; } ++it; return cp; } template uint32_t peek_next(octet_iterator it) { return next(it); } template uint32_t prior(octet_iterator& it) { while (internal::is_trail(*(--it))) ; octet_iterator temp = it; return next(temp); } // Deprecated in versions that include prior, but only for the sake of consistency (see utf8::previous) template inline uint32_t previous(octet_iterator& it) { return prior(it); } template void advance (octet_iterator& it, distance_type n) { for (distance_type i = 0; i < n; ++i) next(it); } template typename std::iterator_traits::difference_type distance (octet_iterator first, octet_iterator last) { typename std::iterator_traits::difference_type dist; for (dist = 0; first < last; ++dist) next(first); return dist; } template octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result) { while (start != end) { uint32_t cp = internal::mask16(*start++); // Take care of surrogate pairs first if (internal::is_lead_surrogate(cp)) { uint32_t trail_surrogate = internal::mask16(*start++); cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; } result = append(cp, result); } return result; } template u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result) { while (start < end) { uint32_t cp = next(start); if (cp > 0xffff) { //make a surrogate pair *result++ = static_cast((cp >> 10) + internal::LEAD_OFFSET); *result++ = static_cast((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); } else *result++ = static_cast(cp); } return result; } template octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) { while (start != end) result = append(*(start++), result); return result; } template u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result) { while (start < end) (*result++) = next(start); return result; } // The iterator class template class iterator : public std::iterator { octet_iterator it; public: iterator () {}; explicit iterator (const octet_iterator& octet_it): it(octet_it) {} // the default "big three" are OK octet_iterator base () const { return it; } uint32_t operator * () const { octet_iterator temp = it; return next(temp); } bool operator == (const iterator& rhs) const { return (it == rhs.it); } bool operator != (const iterator& rhs) const { return !(operator == (rhs)); } iterator& operator ++ () { std::advance(it, internal::sequence_length(it)); return *this; } iterator operator ++ (int) { iterator temp = *this; std::advance(it, internal::sequence_length(it)); return temp; } iterator& operator -- () { prior(it); return *this; } iterator operator -- (int) { iterator temp = *this; prior(it); return temp; } }; // class iterator } // namespace utf8::unchecked } // namespace utf8 #endif // header guard tcpflow-tcpflow-1.6.1/src/be13_api/utils.cpp000066400000000000000000000056561401360461700207050ustar00rootroot00000000000000/** * A collection of utility functions that are useful. */ // Just for this module #define _FILE_OFFSET_BITS 64 /* required per C++ standard */ #ifndef __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS #endif #include "config.h" #include "cppmutex.h" #include "utils.h" #ifdef HAVE_UNISTD_H #include #endif #include #include #include #include #include #include #include #include #include #ifndef HAVE_ERR #include void err(int eval,const char *fmt,...) { va_list ap; va_start(ap,fmt); vfprintf(stderr,fmt,ap); va_end(ap); fprintf(stderr,": %s\n",strerror(errno)); exit(eval); } #endif #ifndef HAVE_ERRX #include void errx(int eval,const char *fmt,...) { va_list ap; va_start(ap,fmt); vfprintf(stderr,fmt,ap); fprintf(stderr,"%s\n",strerror(errno)); va_end(ap); exit(eval); } #endif #ifndef HAVE_WARN #include void warn(const char *fmt, ...) { va_list args; va_start(args,fmt); vfprintf(stderr,fmt, args); fprintf(stderr,": %s\n",strerror(errno)); } #endif #ifndef HAVE_WARNX #include void warnx(const char *fmt,...) { va_list ap; va_start(ap,fmt); vfprintf(stderr,fmt,ap); va_end(ap); } #endif /** Extract a buffer... * @param buf - the buffer to extract; * @param buflen - the size of the page to extract * @param pos0 - the byte position of buf[0] */ #ifndef HAVE_LOCALTIME_R /* locking localtime_r implementation */ cppmutex localtime_mutex; void localtime_r(time_t *t,struct tm *tm) { cppmutex::lock lock(localtime_mutex); *tm = *localtime(t); } #endif #ifndef HAVE_GMTIME_R /* locking gmtime_r implementation */ cppmutex gmtime_mutex; void gmtime_r(time_t *t,struct tm *tm) { if(t && tm){ cppmutex::lock lock(gmtime_mutex); struct tm *tmret = gmtime(t); if(tmret){ *tm = *tmret; } else { memset(tm,0,sizeof(*tm)); } } } #endif bool ends_with(const std::string &buf,const std::string &with) { size_t buflen = buf.size(); size_t withlen = with.size(); return buflen>withlen && buf.substr(buflen-withlen,withlen)==with; } bool ends_with(const std::wstring &buf,const std::wstring &with) { size_t buflen = buf.size(); size_t withlen = with.size(); return buflen>withlen && buf.substr(buflen-withlen,withlen)==with; } #include /****************************************************************/ /* C++ string splitting code from http://stackoverflow.com/questions/236129/how-to-split-a-string-in-c */ std::vector &split(const std::string &s, char delim, std::vector &elems) { std::stringstream ss(s); std::string item; while(std::getline(ss, item, delim)) { elems.push_back(item); } return elems; } std::vector split(const std::string &s, char delim) { std::vector elems; return split(s, delim, elems); } tcpflow-tcpflow-1.6.1/src/be13_api/utils.h000066400000000000000000000040701401360461700203370ustar00rootroot00000000000000/**************************************************************** *** utils.h *** *** To use utils.c/utils.h, be sure this is in your configure.ac file: m4_include([be13_api/be13_configure.m4]) *** ****************************************************************/ #ifndef UTILS_H #define UTILS_H #include #include #include #if defined(__cplusplus) #include #include bool ends_with(const std::string &buf,const std::string &with); bool ends_with(const std::wstring &buf,const std::wstring &with); std::vector &split(const std::string &s, char delim, std::vector &elems); std::vector split(const std::string &s, char delim); #endif #ifndef __BEGIN_DECLS #if defined(__cplusplus) #define __BEGIN_DECLS extern "C" { #define __END_DECLS } #else #define __BEGIN_DECLS #define __END_DECLS #endif #endif __BEGIN_DECLS #ifdef HAVE_ERR_H #include #else [[noreturn]] void err(int eval,const char *fmt,...) __attribute__((format(printf, 2, 0))); [[noreturn]] void errx(int eval,const char *fmt,...) __attribute__((format(printf, 2, 0))); void warn(const char *fmt, ...) __attribute__((format(printf, 1, 0))); void warnx(const char *fmt,...) __attribute__((format(printf, 1, 0))); #endif #ifndef HAVE_LOCALTIME_R #ifdef __MINGW32__ #undef localtime_r #endif void localtime_r(time_t *t,struct tm *tm); #endif #ifndef HAVE_GMTIME_R #ifdef __MINGW32__ #undef gmtime_r #endif void gmtime_r(time_t *t,struct tm *tm); #endif int64_t get_filesize(int fd); #ifndef HAVE_ISHEXNUMBER int ishexnumber(int c); inline int ishexnumber(int c) { switch(c){ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': return 1; } return 0; } #endif __END_DECLS #endif tcpflow-tcpflow-1.6.1/src/be13_api/word_and_context_list.cpp000066400000000000000000000105321401360461700241260ustar00rootroot00000000000000/** * class word_and_context_list reads from disk and maintains in memory * a data structure that is used for the stop list and alert list. */ #include "config.h" #include #include #include "word_and_context_list.h" #include "beregex.h" void word_and_context_list::add_regex(const std::string &pat) { patterns.push_back(new beregex(pat,0)); } /** * Insert a feature and context, but only if not already present. * Returns true if added. */ bool word_and_context_list::add_fc(const std::string &f,const std::string &c) { context ctx(f,c); // ctx includes feature, before and after if(c.size()>0 && context_set.find(c) != context_set.end()) return false; // already present context_set.insert(c); // now we've seen it. fcmap.insert(std::pair(f,ctx)); //if(fcmap.size()%100==0) std::cerr << "fcmap size=" << fcmap.size() << "\n"; return true; } /** returns 0 if success, -1 if fail. */ int word_and_context_list::readfile(const std::string &filename) { std::ifstream i(filename.c_str()); if(!i.is_open()) return -1; printf("Reading context stop list %s\n",filename.c_str()); std::string line; uint64_t total_context=0; uint64_t line_counter = 0; uint64_t features_read = 0; while(getline(i,line)){ line_counter++; if(line.size()==0) continue; if(line[0]=='#') continue; // it's a comment if((*line.end())=='\r'){ line.erase(line.end()); /* remove the last character if it is a \r */ } if(line.size()==0) continue; // no line content ++features_read; // If there are two tabs, this is a line from a feature file size_t tab1 = line.find('\t'); if(tab1!=std::string::npos){ size_t tab2 = line.find('\t',tab1+1); if(tab2!=std::string::npos){ size_t tab3 = line.find('\t',tab2+1); if(tab3==std::string::npos) tab3=line.size(); std::string f = line.substr(tab1+1,(tab2-1)-tab1); std::string c = line.substr(tab2+1,(tab3-1)-tab2); if(add_fc(f,c)){ ++total_context; } } else { std::string f = line.substr(tab1+1); add_fc(f,""); // Insert a feature with no context } continue; } // If there is no tab, then this must be a simple item to ignore. // If it is a regular expression, add it to the list of REs if(beregex::is_regex(line)){ patterns.push_back(new beregex(line,REG_ICASE)); } else { // Otherwise, add it as a feature with no context fcmap.insert(std::pair(line,context(line))); } } std::cout << "Stop list read.\n"; std::cout << " Total features read: " << features_read << "\n"; std::cout << " List Size: " << fcmap.size() << "\n"; std::cout << " Context Strings: " << total_context << "\n"; std::cout << " Regular Expressions: " << patterns.size() << "\n"; return 0; } /** check() is threadsafe. */ bool word_and_context_list::check(const std::string &probe,const std::string &before,const std::string &after) const { /* First check literals, because they are faster */ for(stopmap_t::const_iterator it =fcmap.find(probe);it!=fcmap.end();it++){ if((rstrcmp((*it).second.before,before)==0) && (rstrcmp((*it).second.after,after)==0) && ((*it).second.feature==probe)){ return true; } } /* Now check the patterns; do this second */ for(beregex_vector::const_iterator it=patterns.begin(); it != patterns.end(); it++){ if((*it)->search(probe,0,0,0)){ return true; // yep } } return false; }; bool word_and_context_list::check_feature_context(const std::string &probe,const std::string &context) const { std::string before; std::string after; context::extract_before_after(probe,context,before,after); return check(probe,before,after); } void word_and_context_list::dump() { std::cout << "dump context list:\n"; for(stopmap_t::const_iterator it =fcmap.begin();it!=fcmap.end();it++){ std::cout << (*it).first << " = " << (*it).second << "\n"; } std::cout << "dump RE list:\n"; for(beregex_vector::const_iterator it=patterns.begin(); it != patterns.end(); it++){ std::cout << (*it)->pat << "\n"; } } #ifdef STAND int main(int argc,char **argv) { cout << "testing contxt_list\n"; word_and_context_list cl; while(--argc){ argv++; if(cl.readfile(*argv)){ err(1,"Cannot read %s",*argv); } } cl.dump(); exit(1); } #endif tcpflow-tcpflow-1.6.1/src/be13_api/word_and_context_list.h000066400000000000000000000115421401360461700235750ustar00rootroot00000000000000#ifndef WORD_AND_CONTEXT_LIST_H #define WORD_AND_CONTEXT_LIST_H #include "beregex.h" /** * \addtogroup internal_interfaces * @{ * \file * word_and_context_list: * * A re-implementation of the basic stop list, regular expression * stop_list, and context-sensitive stop list. * * Method: * Each entry in the stop list can be represented as: * - a feature that is stopped, with optional context. * - a regular expression * * Context is represented as a std::string before the feature and a std::string after. * * The stop list contains is a map of features that are stopped. * For each feature, there may be no context or a list of context. * If there is no context and the feature is in the list, */ /* * context is a class that records the feature, the text before, and the text after. * Typically this is used for stop lists and alert lists. */ #if defined(HAVE_UNORDERED_SET) #include #else #if defined(HAVE_TR1_UNORDERED_SET) #include #endif #endif /* includes both unordered_map and unordered_multimap */ #if defined(HAVE_UNORDERED_MAP) #include #else #if defined(HAVE_TR1_UNORDERED_MAP) #include #endif #endif #include #include #include // brings in map and multimap class context { public: static void extract_before_after(const std::string &feature,const std::string &ctx, std::string &before,std::string &after){ if(feature.size() <= ctx.size()){ /* The most simple algorithm is a sliding window */ for(size_t i = 0;i stopmap_t; #else #if defined(HAVE_TR1_UNORDERED_MAP) typedef std::tr1::unordered_multimap stopmap_t; #else typedef std::multimap stopmap_t; #endif #endif stopmap_t fcmap; // maps features to contexts; for finding them #if defined(HAVE_UNORDERED_SET) typedef std::unordered_set< std::string > stopset_t; #else #if defined(HAVE_TR1_UNORDERED_SET) typedef std::tr1::unordered_set< std::string > stopset_t; #else typedef std::set< std::string > stopset_t; #endif #endif stopset_t context_set; // presence of a pair in fcmap beregex_vector patterns; public: /** * rstrcmp is like strcmp, except it compares std::strings right-aligned * and only compares the minimum sized std::string of the two. */ static int rstrcmp(const std::string &a,const std::string &b); word_and_context_list():fcmap(),context_set(),patterns(){ } ~word_and_context_list(){ for(beregex_vector::iterator it=patterns.begin(); it != patterns.end(); it++){ delete *it; } } size_t size(){ return fcmap.size() + patterns.size();} void add_regex(const std::string &pat); // not threadsafe bool add_fc(const std::string &f,const std::string &c); // not threadsafe int readfile(const std::string &fname); // not threadsafe // return true if the probe with context is in the list or in the stopmap bool check(const std::string &probe,const std::string &before, const std::string &after) const; // threadsafe bool check_feature_context(const std::string &probe,const std::string &context) const; // threadsafe void dump(); }; inline int word_and_context_list::rstrcmp(const std::string &a,const std::string &b) { size_t alen = a.size(); size_t blen = b.size(); size_t len = alen < blen ? alen : blen; for(size_t i=0;i b[bpos]) return 1; } return 0; } #endif tcpflow-tcpflow-1.6.1/src/datalink.cpp000066400000000000000000000220701401360461700177360ustar00rootroot00000000000000/** * * This file is part of tcpflow. Originally by Jeremy Elson * , rewritten by Simson Garfinkel. * * Initial Release: 7 April 1999. * * This source code is under the GNU Public License (GPL). See * COPYING for details. * * This file contains datalink handlers which are called by the pcap callback. * The purpose of each handler is to make a packet_info() object and then call * process_packet. The packet_info() object contains both the original * MAC-layer (with some of the fields broken out) and the packet data layer. * * For wifi datalink handlers, please see datalink_wifi.cpp */ #include #include "tcpflow.h" /* The DLT_NULL packet header is 4 bytes long. It contains a network * order 32 bit integer that specifies the family, e.g. AF_INET. * DLT_NULL is used by the localhost interface. */ #define NULL_HDRLEN 4 /* Some systems hasn't defined ETHERTYPE_IPV6 */ #ifndef ETHERTYPE_IPV6 # define ETHERTYPE_IPV6 0x86DD #endif #ifndef ETH_P_QINQ1 # define ETH_P_QINQ1 0x9100 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */ #endif #ifndef ETH_P_8021AD # define ETH_P_8021AD 0x88A8 /* 802.1ad Service VLAN */ #endif int32_t datalink_tdelta = 0; #pragma GCC diagnostic ignored "-Wcast-align" void dl_null(u_char *user, const struct pcap_pkthdr *h, const u_char *p) { u_int caplen = h->caplen; u_int length = h->len; uint32_t family = (uint32_t)*p; if (length != caplen) { DEBUG(6) ("warning: only captured %d bytes of %d byte null frame", caplen, length); } if (caplen < NULL_HDRLEN) { DEBUG(6) ("warning: received incomplete null frame"); return; } /* make sure this is AF_INET */ if (family != AF_INET && family != AF_INET6) { DEBUG(6)("warning: received null frame with unknown type (type 0x%x) (AF_INET=%x; AF_INET6=%x)", family,AF_INET,AF_INET6); return; } struct timeval tv; be13::packet_info pi(DLT_NULL,h,p,tvshift(tv,h->ts),p+NULL_HDRLEN,caplen - NULL_HDRLEN); be13::plugin::process_packet(pi); } #pragma GCC diagnostic warning "-Wcast-align" static uint64_t counter=0; /* DLT_RAW: just a raw IP packet, no encapsulation or link-layer * headers. Used for PPP connections under some OSs including Linux * and IRIX. */ void dl_raw(u_char *user, const struct pcap_pkthdr *h, const u_char *p) { if (h->caplen != h->len) { DEBUG(6) ("warning: only captured %d bytes of %d byte raw frame", h->caplen, h->len); } struct timeval tv; be13::packet_info pi(DLT_RAW,h,p,tvshift(tv,h->ts),p, h->caplen); counter++; be13::plugin::process_packet(pi); } /* Ethernet datalink handler; used by all 10 and 100 mbit/sec * ethernet. We are given the entire ethernet header so we check to * make sure it's marked as being IP. */ #pragma GCC diagnostic ignored "-Wcast-align" void dl_ethernet(u_char *user, const struct pcap_pkthdr *h, const u_char *p) { u_int caplen = h->caplen; u_int length = h->len; struct be13::ether_header *eth_header = (struct be13::ether_header *) p; u_int ether_type_offset = offsetof(struct be13::ether_header, ether_type); /* Variables to support VLAN */ const u_short *ether_type = NULL; const u_char *ether_data = NULL; if (caplen < ether_type_offset) { DEBUG(0) ("error: the captured packet header bytes are shorter than the ether_type offset"); return; } ether_type = ð_header->ether_type; /* where the ether type is located */ ether_data = p+sizeof(struct be13::ether_header); /* where the data is located */ if (length != caplen) { DEBUG(6) ("warning: only captured %d bytes of %d byte ether frame", caplen, length); } /* Handle basic VLAN packets */ while (ntohs(*ether_type) == ETHERTYPE_VLAN #ifdef ETH_P_QINQ1 || ntohs(*ether_type) == ETH_P_QINQ1 #endif #ifdef ETH_P_8021AD || ntohs(*ether_type) == ETH_P_8021AD #endif ) { //vlan = ntohs(*(u_short *)(p+sizeof(struct ether_header))); ether_type += 2; /* skip past VLAN header (note it skips by 2s) */ ether_data += 4; /* skip past VLAN header */ caplen -= 4; if (caplen < ether_type_offset) { DEBUG(0) ("error: the captured packet header bytes are shorter than the ether_type offset"); return; } } if (caplen < sizeof(struct be13::ether_header)) { DEBUG(6) ("warning: received incomplete ethernet frame"); return; } /* Create a packet_info structure with ip data and data length */ try { struct timeval tv; be13::packet_info pi(DLT_IEEE802,h,p,tvshift(tv,h->ts), ether_data, caplen - sizeof(struct be13::ether_header)); switch (ntohs(*ether_type)){ case ETHERTYPE_IP: case ETHERTYPE_IPV6: be13::plugin::process_packet(pi); break; #ifdef ETHERTYPE_ARP case ETHERTYPE_ARP: /* What should we do for ARP? */ break; #endif #ifdef ETHERTYPE_LOOPBACK case ETHERTYPE_LOOPBACK: /* What do do for loopback? */ break; #endif #ifdef ETHERTYPE_REVARP case ETHERTYPE_REVARP: /* What to do for REVARP? */ break; #endif default: /* Unknown Ethernet Frame Type */ DEBUG(6) ("warning: received ethernet frame with unknown type 0x%x", ntohs(eth_header->ether_type)); break; } } catch( std::logic_error e){ std::string s(std::string("warning: caught std::logic_error ") + e.what() + std::string(" in packet")); DEBUG(6)(s.c_str()); } } #pragma GCC diagnostic warning "-Wcast-align" /* The DLT_PPP packet header is 4 bytes long. We just move past it * without parsing it. It is used for PPP on some OSs (DLT_RAW is * used by others; see below) */ #define PPP_HDRLEN 4 void dl_ppp(u_char *user, const struct pcap_pkthdr *h, const u_char *p) { u_int caplen = h->caplen; u_int length = h->len; if (length != caplen) { DEBUG(6) ("warning: only captured %d bytes of %d byte PPP frame", caplen, length); } if (caplen < PPP_HDRLEN) { DEBUG(6) ("warning: received incomplete PPP frame"); return; } struct timeval tv; be13::packet_info pi(DLT_PPP,h,p,tvshift(tv,h->ts),p + PPP_HDRLEN, caplen - PPP_HDRLEN); be13::plugin::process_packet(pi); } #ifdef DLT_LINUX_SLL #define SLL_HDR_LEN 16 #define SLL_ADDRLEN 8 #ifndef ETHERTYPE_MPLS #define ETHERTYPE_MPLS 0x8847 #endif #ifndef ETHERTYPE_MPLS_MULTI #define ETHERTYPE_MPLS_MULTI 0x8848 #endif #pragma GCC diagnostic ignored "-Wcast-align" void dl_linux_sll(u_char *user, const struct pcap_pkthdr *h, const u_char *p) { u_int caplen = h->caplen; u_int length = h->len; if (length != caplen) { DEBUG(6) ("warning: only captured %d bytes of %d byte Linux cooked frame", caplen, length); } if (caplen < SLL_HDR_LEN) { DEBUG(6) ("warning: received incomplete Linux cooked frame"); return; } struct _sll_header { u_int16_t sll_pkttype; /* packet type */ u_int16_t sll_hatype; /* link-layer address type */ u_int16_t sll_halen; /* link-layer address length */ u_int8_t sll_addr[SLL_ADDRLEN]; /* link-layer address */ u_int16_t sll_protocol; /* protocol */ }; _sll_header *sllp = (_sll_header*)p; u_int mpls_sz = 0; if (ntohs(sllp->sll_protocol) == ETHERTYPE_MPLS) { // unwind MPLS stack do { if(caplen < SLL_HDR_LEN + mpls_sz + 4){ DEBUG(6) ("warning: MPLS stack overrun"); return; } mpls_sz += 4; caplen -= 4; } while ((p[SLL_HDR_LEN + mpls_sz - 2] & 1) == 0 ); } struct timeval tv; be13::packet_info pi(DLT_LINUX_SLL,h,p,tvshift(tv,h->ts),p + SLL_HDR_LEN + mpls_sz, caplen - SLL_HDR_LEN); be13::plugin::process_packet(pi); } #endif #ifndef DLT_IEEE802_11_RADIO #define DLT_IEEE802_11_RADIO 127 /* 802.11 plus radiotap radio header */ #endif /* List of callbacks for each data link type */ dlt_handler_t handlers[] = { { dl_null, DLT_NULL }, /* Some systems define DLT_RAW as 12, some as 14, and some as 101. * So it is hard-coded here. */ { dl_raw, 12 }, { dl_raw, 14 }, { dl_raw, 101 }, { dl_ethernet, DLT_EN10MB }, { dl_ethernet, DLT_IEEE802 }, { dl_ppp, DLT_PPP }, #ifdef DLT_LINUX_SLL { dl_linux_sll, DLT_LINUX_SLL }, #endif #if defined(USE_WIFI) && !defined(WIN32) { dl_ieee802_11_radio, DLT_IEEE802_11 }, { dl_ieee802_11_radio, DLT_IEEE802_11_RADIO }, { dl_prism, DLT_PRISM_HEADER}, #endif { NULL, 0 } }; pcap_handler find_handler(int datalink_type, const char *device) { int i; DEBUG(3) ("looking for handler for datalink type %d for interface %s", datalink_type, device); for (i = 0; handlers[i].handler != NULL; i++){ if (handlers[i].type == datalink_type){ return handlers[i].handler; } } die("sorry - unknown datalink type %d on interface %s", datalink_type, device); return NULL; /* NOTREACHED */ } tcpflow-tcpflow-1.6.1/src/datalink_wifi.cpp000066400000000000000000000027401401360461700207560ustar00rootroot00000000000000/** * wifi datalink function and callbacks to handle 802.11 * In addition to calling process_packet_info() for the packets, * it maintains some 802.11 specific databases. */ #include "tcpflow.h" #include "datalink_wifi.h" /** * TFCB --- TCPFLOW callbacks for wifippcap */ void TFCB::Handle80211(const WifiPacket &p, u_int16_t fc, const MAC& sa, const MAC& da, const MAC& ra, const MAC& ta, const u_char *ptr, size_t len) { } void TFCB::HandleLLC(const WifiPacket &p, const struct llc_hdr_t *hdr, const u_char *rest, size_t len) { sbuf_t sb(pos0_t(),rest,len,len,0,false,false,false); struct timeval tv; be13::packet_info pi(p.header_type,p.header,p.packet,tvshift(tv,p.header->ts),rest,len); be13::plugin::process_packet(pi); } void TFCB::Handle80211MgmtBeacon(const WifiPacket &p, const mgmt_header_t *hdr, const mgmt_body_t *body) { #ifdef DEBUG_WIFI std::cerr << " " << "802.11 mgmt: " << hdr->sa << " beacon " << body->ssid.ssid << "\""; #endif mac_ssid bcn(hdr->sa,std::string(body->ssid.ssid)); mac_to_ssid[bcn] += 1; } /* Entrance point */ TFCB TFCB::theTFCB; // singleton static Wifipcap theWcap; void dl_ieee802_11_radio(u_char *user, const struct pcap_pkthdr *h, const u_char *p) { theWcap.handle_packet(&TFCB::theTFCB,DLT_IEEE802_11_RADIO,h,p); } void dl_prism(u_char *user, const struct pcap_pkthdr *h, const u_char *p) { #ifdef DLT_PRISM_HEADER theWcap.handle_packet(&TFCB::theTFCB,DLT_PRISM_HEADER,h,p); #endif } tcpflow-tcpflow-1.6.1/src/datalink_wifi.h000066400000000000000000000030701401360461700204200ustar00rootroot00000000000000#ifndef DATALINK_WIFI_H #define DATALINK_WIFI_H #include #include #include "wifipcap.h" //#define DEBUG_WIFI class TFCB : public WifipcapCallbacks { private: public: bool opt_check_fcs; typedef struct mac_ssid { mac_ssid(const MAC &mac_,const std::string &ssid_):mac(mac_),ssid(ssid_){} const MAC mac; const std::string ssid; bool operator<(const struct mac_ssid &b) const{ if (mac < b.mac) return true; if (b.mac < mac) return false; return ssid < b.ssid; }; } mac_ssid_t; typedef struct { bool operator() (const struct mac_ssid &a, const struct mac_ssid &b) const { if (a.mac < b.mac) return true; if (b.mac < a.mac) return false; return a.ssid < b.ssid; } } mac_ssid_lt; typedef std::set mac_ssid_set_t; typedef std::map mac_ssid_map_t; mac_ssid_map_t mac_to_ssid; // mapping of macs to SSIDs static TFCB theTFCB; TFCB():opt_check_fcs(true),mac_to_ssid(){} virtual bool Check80211FCS(const WifiPacket &p) { return opt_check_fcs; } virtual void Handle80211(const WifiPacket &p,u_int16_t fc, const MAC& sa, const MAC& da, const MAC& ra, const MAC& ta, const u_char *ptr, size_t len) ; void HandleLLC(const WifiPacket &p,const struct llc_hdr_t *hdr, const u_char *rest, size_t len) ; void Handle80211MgmtBeacon(const WifiPacket &p,const mgmt_header_t *hdr, const mgmt_body_t *body) ; }; #endif tcpflow-tcpflow-1.6.1/src/flow.cpp000066400000000000000000000145741401360461700171300ustar00rootroot00000000000000/** * * flow.cpp: * * The flow class is used to track individual TCP/IP flows (2 per connection). * The class implements the methods that turn a flow into a filename. * * This file is part of tcpflow by Jeremy Elson * Initial Release: 7 April 1999. * * This source code is under the GNU Public License (GPL). See * LICENSE for details. * */ #include "tcpflow.h" #include "tcpip.h" #include "tcpdemux.h" #ifdef HAVE_ARPA_INET_H #include // inet_ntop #endif #include #include #include std::string flow::filename_template("%A.%a-%B.%b%V%v%C%c"); std::string flow::outdir("."); void flow::usage() { std::cout << "\n" "Filename template format for option -T:\n"; std::cout << " %A/%a - source IP address/port; %B/%b - dest IP address/port\n"; std::cout << " %E/%e - source/dest Ethernet Mac address\n"; std::cout << " %V/%v - VLAN number, '--' if no vlan/'' if no vlan\n"; std::cout << " %T/%t - Timestamp in ISO8601 format/unix time_t\n"; std::cout << " %c - connection_count for connections>0 / %# for all connections;"; std::cout << " %C - 'c' if connection_count >0\n"; std::cout << " %N - (connection_number ) % 1000\n"; std::cout << " %K - (connection_number / 1000) % 1000\n"; std::cout << " %M - (connection_number / 1000000) % 1000\n"; std::cout << " %G - (connection_number / 1000000000) % 1000\n"; std::cout << " %S - session ID\n"; std::cout << " %% - Output a '%'\n"; std::cout << "\n"; std::cout << "Default value is: '"<< flow::filename_template <<"'\n"; std::cout << "\n"; std::cout << "Note: Using the option -T will ignore options -Fk, -Fm and -Fg.\n"; std::cout << " Filename template format handles '/' to create sub-directories.\n"; } std::string flow::filename(uint32_t connection_count, bool is_pcap) { std::stringstream ss; /* Add the outdir */ if(flow::outdir!="." && flow::outdir!=""){ ss << flow::outdir; ss << '/'; } for(unsigned int i=0;i0 if(connection_count>0) ss << "c"; break; case 'c': // connection_count if connection_count >0 if(connection_count>0) ss << connection_count; break; case 'S': // session ID ss << std::setfill('0') << std::setw(20) << session_id; break; case '#': // always output connection count ss << connection_count; break; case '%': // Output a '%' ss << "%"; break; default: std::cerr << "Invalid filename_template: " << filename_template << "\n"; std::cerr << "unknown character: " << filename_template.at(i+1) << "\n"; exit(1); } if(buf[0]) ss << buf; } } if(is_pcap){ ss << ".pcap"; // file extension } return ss.str(); } /** * Find an unused filename for the flow and optionally open it. * This is called from tcpip::open_file(). */ std::string flow::new_filename(int *fd,int flags,int mode) { /* Loop connection count until we find a file that doesn't exist */ for(uint32_t connection_count=0;;connection_count++){ std::string nfn = filename(connection_count, false); if(nfn.find('/')!=std::string::npos) mkdirs_for_path(nfn.c_str()); int nfd = tcpdemux::getInstance()->retrying_open(nfn,flags,mode); if(nfd>=0){ *fd = nfd; return nfn; } if(errno!=EEXIST) die("Cannot open: %s",nfn.c_str()); } return std::string("<>"); // error; no file } std::string flow::new_pcap_filename() { /* Loop connection count until we find a file that doesn't exist */ for(uint32_t connection_count=0;;connection_count++){ std::string nfn = filename(connection_count, true); if(nfn.find('/')!=std::string::npos) mkdirs_for_path(nfn.c_str()); return nfn; } return std::string("<>"); // error; no file } tcpflow-tcpflow-1.6.1/src/hold/000077500000000000000000000000001401360461700163705ustar00rootroot00000000000000tcpflow-tcpflow-1.6.1/src/hold/tcp_options.cpp000066400000000000000000000347741401360461700214540ustar00rootroot00000000000000/* * tcp option parser. * Originally by Doug Madory */ /* These tcp optinos do not have the size octet */ #define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP) void parse_tcp_opts(std::list& opts, const u_char *cp, u_int hlen) { if (hlen == 0) return; register u_int i, opt, datalen; register u_int len; //putchar(' '); //ch = '<'; while (hlen > 0) { tcp_opt_t tcpopt; //putchar(ch); //TCHECK(*cp); opt = *cp++; if (ZEROLENOPT(opt)) len = 1; else { //TCHECK(*cp); len = *cp++; /* total including type, len */ if (len < 2 || len > hlen) // stop processing on bad opt break; --hlen; /* account for length byte */ } --hlen; /* account for type byte */ datalen = 0; /* Bail if "l" bytes of data are not left or were not captured */ #define LENCHECK(l) { if ((l) > hlen) break; } tcpopt.type = opt; tcpopt.data_raw = cp; switch (opt) { case TCPOPT_MAXSEG: //(void)printf("mss"); datalen = 2; LENCHECK(datalen); //(void)printf(" %u", EXTRACT_16BITS(cp)); tcpopt.data.mss = EXTRACT_16BITS(cp); break; case TCPOPT_EOL: //(void)printf("eol"); break; case TCPOPT_NOP: //(void)printf("nop"); break; case TCPOPT_WSCALE: //(void)printf("wscale"); datalen = 1; LENCHECK(datalen); //(void)printf(" %u", *cp); tcpopt.data.wscale = *cp; break; case TCPOPT_SACKOK: //(void)printf("sackOK"); break; case TCPOPT_SACK: datalen = len - 2; if (datalen % 8 != 0) { //(void)printf("malformed sack"); } else { u_int32_t s, e; //(void)printf("sack %d ", datalen / 8); for (i = 0; i < datalen; i += 8) { LENCHECK(i + 4); s = EXTRACT_32BITS(cp + i); LENCHECK(i + 8); e = EXTRACT_32BITS(cp + i + 4); /* XXX leave application to do this translation? if (threv) { s -= thseq; e -= thseq; } else { s -= thack; e -= thack; } (void)printf("{%u:%u}", s, e); */ tcpopt.data_sack.push_back(std::pair(s,e)); } } break; case TCPOPT_ECHO: //(void)printf("echo"); datalen = 4; LENCHECK(datalen); //(void)printf(" %u", EXTRACT_32BITS(cp)); tcpopt.data.echo = EXTRACT_32BITS(cp); break; case TCPOPT_ECHOREPLY: //(void)printf("echoreply"); datalen = 4; LENCHECK(datalen); //(void)printf(" %u", EXTRACT_32BITS(cp)); tcpopt.data.echoreply = EXTRACT_32BITS(cp); break; case TCPOPT_TIMESTAMP: //(void)printf("timestamp"); datalen = 8; //LENCHECK(4); //(void)printf(" %u", EXTRACT_32BITS(cp)); LENCHECK(datalen); //(void)printf(" %u", EXTRACT_32BITS(cp + 4)); tcpopt.data.timestamp.tsval = EXTRACT_32BITS(cp); tcpopt.data.timestamp.tsecr = EXTRACT_32BITS(cp + 4); break; case TCPOPT_CC: //(void)printf("cc"); datalen = 4; LENCHECK(datalen); //(void)printf(" %u", EXTRACT_32BITS(cp)); tcpopt.data.cc = EXTRACT_32BITS(cp); break; case TCPOPT_CCNEW: //(void)printf("ccnew"); datalen = 4; LENCHECK(datalen); //(void)printf(" %u", EXTRACT_32BITS(cp)); tcpopt.data.ccnew = EXTRACT_32BITS(cp); break; case TCPOPT_CCECHO: //(void)printf("ccecho"); datalen = 4; LENCHECK(datalen); //(void)printf(" %u", EXTRACT_32BITS(cp)); tcpopt.data.ccecho = EXTRACT_32BITS(cp); break; case TCPOPT_SIGNATURE: //(void)printf("md5:"); datalen = TCP_SIGLEN; LENCHECK(datalen); for (i = 0; i < TCP_SIGLEN; ++i) //(void)printf("%02x", cp[i]); tcpopt.data.signature[i] = cp[i]; break; default: //(void)printf("opt-%u:", opt); datalen = len - 2; /* for (i = 0; i < datalen; ++i) { LENCHECK(i); (void)printf("%02x", cp[i]); } */ break; } /* Account for data printed */ cp += datalen; hlen -= datalen; /* Check specification against observed length */ //++datalen; /* option octet */ //if (!ZEROLENOPT(opt)) // ++datalen; /* size octet */ //if (datalen != len) // (void)printf("[len %d]", len); //ch = ','; tcpopt.len = datalen; opts.push_back(tcpopt); if (opt == TCPOPT_EOL) break; } //putchar('>'); } void handle_tcp(const struct timeval& t, WifipcapCallbacks *cbs, const u_char *bp, u_int length, struct ip4_hdr_t *ip4h, struct ip6_hdr_t *ip6h, int fragmented) { struct tcphdr *tp; tp = (struct tcphdr *)bp; int hlen; // truncated header if (length < sizeof(*tp)) { cbs->HandleTCP(t, ip4h, ip6h, NULL, NULL, 0, bp, length); return; } hlen = TH_OFF(tp) * 4; // bad header length || missing tcp options if (hlen < (int)sizeof(*tp) || length < (int)sizeof(*tp) || hlen > (int)length) { cbs->HandleTCP(t, ip4h, ip6h, NULL, NULL, 0, bp, length); return; } tcp_hdr_t hdr; hdr.sport = EXTRACT_16BITS(&tp->th_sport); hdr.dport = EXTRACT_16BITS(&tp->th_dport); hdr.seq = EXTRACT_32BITS(&tp->th_seq); hdr.ack = EXTRACT_32BITS(&tp->th_ack); hdr.dataoff = TH_OFF(tp) * 4; hdr.flags = tp->th_flags; hdr.win = EXTRACT_16BITS(&tp->th_win); hdr.cksum = EXTRACT_16BITS(&tp->th_sum); hdr.urgptr = EXTRACT_16BITS(&tp->th_urp); //parse_tcp_opts(hdr.opts, bp+sizeof(*tp), hlen-sizeof(*tp)); cbs->HandleTCP(t, ip4h, ip6h, &hdr, hlen==sizeof(*tp)?NULL:bp+sizeof(*tp), hlen-sizeof(*tp), bp+hlen, length-hlen); } void handle_udp(const struct timeval& t, WifipcapCallbacks *cbs, const u_char *bp, u_int length, struct ip4_hdr_t *ip4h, struct ip6_hdr_t *ip6h, int fragmented) { struct udphdr *uh; uh = (struct udphdr *)bp; if (length < sizeof(struct udphdr)) { // truncated udp header cbs->HandleUDP(t, ip4h, ip6h, NULL, bp, length); return; } udp_hdr_t hdr; hdr.sport = EXTRACT_16BITS(&uh->uh_sport); hdr.dport = EXTRACT_16BITS(&uh->uh_dport); hdr.len = EXTRACT_16BITS(&uh->uh_ulen); hdr.cksum = EXTRACT_16BITS(&uh->uh_sum); cbs->HandleUDP(t, ip4h, ip6h, &hdr, bp+sizeof(struct udphdr), length-sizeof(struct udphdr)); } void handle_icmp(const struct timeval& t, WifipcapCallbacks *cbs, const u_char *bp, u_int length, struct ip4_hdr_t *ip4h, struct ip6_hdr_t *ip6h, int fragmented) { struct icmp *dp; dp = (struct icmp *)bp; if (length < 4) { // truncated icmp header cbs->HandleICMP(t, ip4h, ip6h, -1, -1, bp, length); return; } cbs->HandleICMP(t, ip4h, ip6h, dp->icmp_type, dp->icmp_code, bp+4, length-4); } /////////////////////////////////////////////////////////////////////////////// void handle_ip(const struct timeval& t, WifipcapCallbacks *cbs, const u_char *ptr, int len); void handle_ip6(const struct timeval& t, WifipcapCallbacks *cbs, const u_char *ptr, int len); struct ip_print_demux_state { struct ip *ip; const u_char *cp; u_int len, off; u_char nh; int advance; }; void ip_demux(const struct timeval& t, WifipcapCallbacks *cbs, ip4_hdr_t *hdr, struct ip_print_demux_state *ipds, int len) { //struct protoent *proto; //again: switch (ipds->nh) { case IPPROTO_TCP: /* pass on the MF bit plus the offset to detect fragments */ handle_tcp(t, cbs, ipds->cp, ipds->len, hdr, NULL, ipds->off & (IP_MF|IP_OFFMASK)); break; case IPPROTO_UDP: /* pass on the MF bit plus the offset to detect fragments */ handle_udp(t, cbs, ipds->cp, ipds->len, hdr, NULL, ipds->off & (IP_MF|IP_OFFMASK)); break; case IPPROTO_ICMP: /* pass on the MF bit plus the offset to detect fragments */ handle_icmp(t, cbs, ipds->cp, ipds->len, hdr, NULL, ipds->off & (IP_MF|IP_OFFMASK)); break; case IPPROTO_IPV4: /* DVMRP multicast tunnel (ip-in-ip encapsulation) */ //handle_ip(t, cbs, ipds->cp, ipds->len); //break; case IPPROTO_IPV6: /* ip6-in-ip encapsulation */ //handle_ip6(t, cbs, ipds->cp, ipds->len); //break; ///// Jeff: XXX Some day handle these maybe (see tcpdump code) case IPPROTO_AH: /* ipds->nh = *ipds->cp; ipds->advance = ah_print(ipds->cp); if (ipds->advance <= 0) break; ipds->cp += ipds->advance; ipds->len -= ipds->advance; goto again; */ case IPPROTO_ESP: { /* int enh, padlen; ipds->advance = esp_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip, &enh, &padlen); if (ipds->advance <= 0) break; ipds->cp += ipds->advance; ipds->len -= ipds->advance + padlen; ipds->nh = enh & 0xff; goto again; */ } case IPPROTO_IPCOMP: { /* int enh; ipds->advance = ipcomp_print(ipds->cp, &enh); if (ipds->advance <= 0) break; ipds->cp += ipds->advance; ipds->len -= ipds->advance; ipds->nh = enh & 0xff; goto again; */ } case IPPROTO_SCTP: /* sctp_print(ipds->cp, (const u_char *)ipds->ip, ipds->len); break; */ case IPPROTO_DCCP: /* dccp_print(ipds->cp, (const u_char *)ipds->ip, ipds->len); break; */ case IPPROTO_PIGP: /* * XXX - the current IANA protocol number assignments * page lists 9 as "any private interior gateway * (used by Cisco for their IGRP)" and 88 as * "EIGRP" from Cisco. * * Recent BSD headers define * IP_PROTO_PIGP as 9 and IP_PROTO_IGRP as 88. * We define IP_PROTO_PIGP as 9 and * IP_PROTO_EIGRP as 88; those names better * match was the current protocol number * assignments say. */ /* igrp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip); break; */ case IPPROTO_EIGRP: /* eigrp_print(ipds->cp, ipds->len); break; */ case IPPROTO_ND: /* ND_PRINT((ndo, " nd %d", ipds->len)); break; */ case IPPROTO_EGP: /* egp_print(ipds->cp, ipds->len); break; */ case IPPROTO_OSPF: /* ospf_print(ipds->cp, ipds->len, (const u_char *)ipds->ip); break; */ case IPPROTO_IGMP: /* igmp_print(ipds->cp, ipds->len); break; */ case IPPROTO_RSVP: /* rsvp_print(ipds->cp, ipds->len); break; */ case IPPROTO_GRE: /* do it */ /* gre_print(ipds->cp, ipds->len); break; */ case IPPROTO_MOBILE: /* mobile_print(ipds->cp, ipds->len); break; */ case IPPROTO_PIM: /* pim_print(ipds->cp, ipds->len); break; */ case IPPROTO_VRRP: /* vrrp_print(ipds->cp, ipds->len, ipds->ip->ip_ttl); break; */ case IPPROTO_PGM: /* pgm_print(ipds->cp, ipds->len, (const u_char *)ipds->ip); break; */ default: /* if ((proto = getprotobynumber(ipds->nh)) != NULL) ND_PRINT((ndo, " %s", proto->p_name)); else ND_PRINT((ndo, " ip-proto-%d", ipds->nh)); ND_PRINT((ndo, " %d", ipds->len)); */ cbs->HandleL3Unknown(t, hdr, NULL, ipds->cp, ipds->len); break; } } void handle_ip(const struct timeval& t, WifipcapCallbacks *cbs, const u_char *ptr, int len) { struct ip_print_demux_state ipd; struct ip_print_demux_state *ipds=&ipd; u_int hlen; // truncated (in fact, nothing!) if (len == 0) { cbs->HandleIP(t, NULL, NULL, 0, ptr, len); return; } ipds->ip = (struct ip *)ptr; if (IP_V(ipds->ip) != 4) { if (IP_V(ipds->ip) == 6) { // wrong link-layer encap! handle_ip6(t, cbs, ptr, len); return; } } if (len < sizeof (struct ip)) { // truncated! cbs->HandleIP(t, NULL, NULL, 0, ptr, len); return; } hlen = IP_HL(ipds->ip) * 4; ipds->len = EXTRACT_16BITS(&ipds->ip->ip_len); if (len < (int)ipds->len) { // truncated IP // this is ok, we'll just report the truncation later } if (ipds->len < hlen) { // missing some ip options! cbs->HandleIP(t, NULL, NULL, 0, ptr, len); } ipds->len -= hlen; ipds->off = EXTRACT_16BITS(&ipds->ip->ip_off); struct ip4_hdr_t hdr; hdr.ver = IP_V(ipds->ip); hdr.hlen = IP_HL(ipds->ip) * 4; hdr.tos = ipds->ip->ip_tos; hdr.len = EXTRACT_16BITS(&ipds->ip->ip_len); hdr.id = EXTRACT_16BITS(&ipds->ip->ip_id); hdr.df = (bool)((ipds->off & IP_DF) != 0); hdr.mf = (bool)((ipds->off & IP_MF) != 0); hdr.fragoff = (ipds->off & IP_OFFMASK); hdr.ttl = ipds->ip->ip_ttl; hdr.proto = ipds->ip->ip_p; hdr.cksum = EXTRACT_16BITS(&ipds->ip->ip_sum); hdr.src = ipds->ip->ip_src; hdr.dst = ipds->ip->ip_dst; cbs->HandleIP(t, &hdr, hlen==sizeof(struct ip)?NULL:ptr+sizeof(struct ip), hlen-sizeof(struct ip), ptr+hlen, len-hlen); /* * If this is fragment zero, hand it to the next higher * level protocol. */ if ((ipds->off & 0x1fff) == 0) { ipds->cp = (const u_char *)ipds->ip + hlen; ipds->nh = ipds->ip->ip_p; ip_demux(t, cbs, &hdr, ipds, len); } else { // This is a fragment of a previous packet. can't demux it return; } } void handle_ip6(const struct timeval& t, WifipcapCallbacks *cbs, const u_char *ptr, int len) { const struct ip6_hdr *ip6; if (len < sizeof (struct ip6_hdr)) { cbs->HandleIP6(t, NULL, ptr, len); return; } ip6 = (const struct ip6_hdr *)ptr; ip6_hdr_t hdr; memcpy(&hdr, ip6, sizeof(&hdr)); hdr.ip6_plen = EXTRACT_16BITS(&ip6->ip6_plen); hdr.ip6_flow = EXTRACT_32BITS(&ip6->ip6_flow); cbs->HandleIP6(t, &hdr, ptr+sizeof(hdr), len-sizeof(hdr)); int nh = ip6->ip6_nxt; switch(nh) { case IPPROTO_TCP: handle_tcp(t, cbs, ptr+sizeof(ip6_hdr), len-sizeof(ip6_hdr), NULL, &hdr, 0); break; case IPPROTO_UDP: handle_udp(t, cbs, ptr+sizeof(ip6_hdr), len-sizeof(ip6_hdr), NULL, &hdr, 0); break; default: cbs->HandleL3Unknown(t, NULL, &hdr, ptr+sizeof(ip6_hdr), len-sizeof(ip6_hdr)); break; } } void handle_arp(const struct timeval& t, WifipcapCallbacks *cbs, const u_char *ptr, int len) { struct arp_pkthdr *ap; //u_short pro, hrd, op; if (len < sizeof(struct arp_pkthdr)) { cbs->HandleARP(t, NULL, ptr, len); return; } ap = (struct arp_pkthdr *)ptr; cbs->HandleARP(t, ap, ptr+ARP_HDRLEN, len-ARP_HDRLEN); } /////////////////////////////////////////////////////////////////////////////// void handle_ether(const struct timeval& t, WifipcapCallbacks *cbs, const u_char *ptr, int len) { ether_hdr_t hdr; hdr.da = ether2MAC(ptr); hdr.sa = ether2MAC(ptr+6); hdr.type = EXTRACT_16BITS(ptr + 12); ptr += 14; len -= 14; cbs->HandleEthernet(t, &hdr, ptr, len); switch (hdr.type) { case ETHERTYPE_IP: handle_ip(t, cbs, ptr, len); return; case ETHERTYPE_IPV6: handle_ip6(t, cbs, ptr, len); return; case ETHERTYPE_ARP: handle_arp(t, cbs, ptr, len); return; default: cbs->HandleL2Unknown(t, hdr.type, ptr, len); return; } } tcpflow-tcpflow-1.6.1/src/http-parser/000077500000000000000000000000001401360461700177135ustar00rootroot00000000000000tcpflow-tcpflow-1.6.1/src/inet_ntop.c000066400000000000000000000025241401360461700176100ustar00rootroot00000000000000/** * private implementaiton if inet_ntop for systems that don't have it. * Functionally, correct, this version doesn't do condensing of IPv6 addresses, * and is kind of slow. * * This is included if the OS does not have inet_ntop. * * PUBLIC DOMAIN. * Simson L. Garfinkel, Jan 20, 2013 */ static const char *inet_ntop4(const struct in_addr *addr, char *buf, socklen_t buflen) { const uint8_t *a = (uint8_t *)addr; snprintf(buf,buflen,"%03d.%03d.%03d.%03d", a[0], a[1], a[2], a[3]); return buf; } static const char *inet_ntop6(const struct private_in6_addr *addr, char *buf, socklen_t buflen) { const char *obuf=buf; const uint8_t *a = (uint8_t *)addr; for(size_t i=0;i<16;i++){ if(buflen<2) return 0; /* can't convert */ snprintf(buf,buflen,"%02x",a[i]); buf+=2; buflen-=2; if(i>0 && i<15 && i%2==1){ if(buflen<1) return 0; buf[0] = ':'; buf++; buflen--; } } if(buflen<1) return 0; buf[0] = 0; return obuf; } const char * inet_ntop(int af, const void *addr, char *buf, socklen_t len) { switch(af){ case AF_INET: return inet_ntop4((const struct in_addr *)addr, buf, len); case AF_INET6: return inet_ntop6((const struct private_in6_addr *)addr, buf, len); } return NULL; } tcpflow-tcpflow-1.6.1/src/inet_ntop.h000066400000000000000000000007141401360461700176140ustar00rootroot00000000000000#ifndef TCPFLOW_INET_NTOP_H #define TCPFLOW_INET_NTOP_H #ifdef HAVE_ARPA_INET_H # include #endif #ifndef HAVE_INET_NTOP const char *inet_ntop(int af, const void *src,char *dst, socklen_t size); #endif #if defined(__MINGW32__) // has this prototype for ws2_32 dll, but has type-conflicts with winsock2.h WINSOCK_API_LINKAGE LPCWSTR WSAAPI inet_ntop(INT Family, PVOID pAddr, LPWSTR pStringBuf, size_t StringBufSIze); #endif #endif tcpflow-tcpflow-1.6.1/src/intrusive_list.h000066400000000000000000000022331401360461700206760ustar00rootroot00000000000000#ifndef INTRUSIVE_LIST_H #define INTRUSIVE_LIST_H #include #include // implement boost::intrusive::list using std::list template class intrusive_list { public: intrusive_list():li(), len(0) {} typedef typename std::list::iterator iterator; inline void push_back(T* node) { li.push_back(node); len++; node->it = --li.end(); } inline void erase(T* node) { if (!is_linked(node)) return; li.erase(node->it); len--; reset(node); } inline void move_to_end(T* node) { if (!is_linked(node)) return; li.splice(li.end(), li, node->it); } inline void reset(T* node) { node->it = li.end(); } inline bool empty() { return li.empty(); } inline size_t size() { // std::list.size() is O(n) in some platform. Is there any define flag for that? //return li.size(); return len; } inline iterator begin() { return li.begin(); } inline iterator end() { return li.end(); } private: inline bool is_linked(T* node) { return node->it != li.end(); } std::list li; size_t len; }; #endif // INTRUSIVE_LIST_H tcpflow-tcpflow-1.6.1/src/iptree.h000066400000000000000000000525551401360461700171170ustar00rootroot00000000000000/* * iptree.h: * * Maintains a count of all IP addresses seen, with limits on the * maximum amount of memory. * * #include this file after config.h (or whatever you are calling it) */ #ifndef IPTREE_H #define IPTREE_H #include #include #include #include #include #ifdef HAVE_ARPA_INET_H #include #endif #define IP4_ADDR_LEN 4 #define IP6_ADDR_LEN 16 /** * the iptree. * * pruning a node means cutting off its leaves (the node remains in the tree). */ /* addrbytes is the number of bytes in the address */ template class iptreet { private:; /** * the node class. * Each node tracks the sum that it currently has and its two children. * A node has pointers to the 0 and 1 children, as well as a sum for everything below. * A short address or prefix being tallied may result in BOTH a sum and one or more PTR values. * If a node is pruned, ptr0=ptr1=0 and tsum>0. * If tsum>0 and ptr0=0 and ptr1=0, then the node cannot be extended. * Nodes need to know their parent so that nodes found through the cache can be made dirty, * which requires knowing their parents. * * Note: currently we get a slightly different answer when the pruning cache is enabled. * Not sure why. It's probably not worth fixing at the moment. */ class node { /** best describes the best node to prune */ public: class best { public: best &operator=(const best &that){ ptr = that.ptr; depth = that.depth; return *this; } const node *ptr; int depth; best():ptr(0),depth(-1){}; // don't use this one best(const node *ptr_,int depth_): ptr(ptr_),depth(depth_){} best(const best &b):ptr(b.ptr),depth(b.depth){ } virtual ~best(){} friend std::ostream & operator<<(std::ostream &os,best const & foo) { os << "node=" << foo.ptr << " depth=" << foo.depth << " "; return os; } }; private: /* Assignment and copy are not implemented */ node &operator=(const iptreet::node &that); node(const node &n); public: class node *parent; class node *ptr0; // 0 bit next class node *ptr1; // 1 bit next private: public:; TYPE tsum; // this node and pruned children. /* Caching system */ mutable bool dirty; // add() has been called and cached data is no longer valid mutable best cached_best; public: node(node *p):parent(p),ptr0(0),ptr1(0),tsum(),dirty(false),cached_best(){ } int children() const {return (ptr0 ? 1 : 0) + (ptr1 ? 1 : 0);} ~node(){ delete ptr0; ptr0 = 0; delete ptr1; ptr1 = 0; }; // a node is leaf if tsum>0 and both ptrs are 0. bool isLeaf() const { if(tsum>0 && ptr0==0 && ptr1==0) return true; return false; } /** * prune(): * Cut this node's children off the tree. * Returns the number removed, which should be larger than 0 (or we shouldn't have been called). */ int prune(class iptreet &tree){ // prune this node //std::cerr << "prune " << this << " ptr0= " << ptr0 << " ptr1=" << ptr1 << " parent= " << parent << "\n"; /* If prune() on a node is called, then both ptr0 and ptr1 nodes, if present, * must not have children. * Now delete those that we counted out */ int removed = 0; if(ptr0){ assert(ptr0->isLeaf()); // only prune leaf nodes tsum += ptr0->tsum; tree.cache_remove(ptr0); // remove it from the cache tree.pruned++; delete ptr0; ptr0=0; tree.nodes--; removed++; } if(ptr1){ assert(ptr1->isLeaf()); tsum += ptr1->tsum; tree.cache_remove(ptr1); tree.pruned++; delete ptr1; ptr1=0; tree.nodes--; removed++; } assert(removed>0); assert(isLeaf()); // I am now a leaf! set_dirty(); // should be able to just set parent //std::cerr << " parent dirty=" << parent->dirty << " this=" << this << " isLeaf()=" << isLeaf() << "\n"; //if(parent){ //parent->dirty=true; // parent is dirty, but no need to propigate it up //} return removed; } /** * Return the best node to prune (the node with the leaves to remove) * Possible outputs: * case 1 - no node (if this is a leaf node, it can't be pruned; should not have been called) * case 2 - this node (if all of the children are leaf) * case 3 - the best node of the one child (if there is only one child) * case 4 - the of the non-leaf child (if one child is leaf and one is not) * case 5 - the better node of each child's best node. */ class best best_to_prune(int my_depth) const { if(dirty==false && cached_best.ptr){ //return cached_best; // haven't changed, so return } dirty = false; // we will be cleaning // case 1 - this is a leaf; it was an error to call best_to_prune assert(isLeaf()==0); // case 2 - our only children are leaves; this is the best node if ((ptr0==0 || ptr0->isLeaf()) && (ptr1==0 || ptr1->isLeaf())){ return cached_best = best(this,my_depth); // case 2 } // case 3 - one of our children is a node and not a leaf, // - and the other is a child or not present. // - The best to prune is the child's best if ((ptr0==0 || ptr0->isLeaf()) && (ptr1!=0 && !ptr1->isLeaf())){ return cached_best = ptr1->best_to_prune(my_depth+1); // case 3 } if ((ptr1==0 || ptr1->isLeaf()) && (ptr0!=0 && !ptr0->isLeaf())){ return cached_best = ptr0->best_to_prune(my_depth+1); // case 3 } // case 5 - the better node of each child's best node. best ptr0_best = ptr0->best_to_prune(my_depth+1); best ptr1_best = ptr1->best_to_prune(my_depth+1); // The better to prune of two children is the one with a lower sum, // or the one that is deeper if they have the same sum. TYPE ptr0_best_sum = ptr0_best.ptr->sum(); TYPE ptr1_best_sum = ptr1_best.ptr->sum(); if(ptr0_best_sum < ptr1_best_sum || (ptr0_best_sum == ptr1_best_sum && ptr0_best.depth > ptr1_best.depth)){ return cached_best = ptr0_best; } return cached_best = ptr1_best; } /** The nodesum is the sum of just the node. * This exists purely because tsum is a private variable. */ TYPE nodesum() const { return tsum; } /** The sum is the sum of this node and its children (if they exist) */ TYPE sum() const { TYPE s = tsum; if(ptr0) s+=ptr0->sum(); if(ptr1) s+=ptr1->sum(); return s; } /** Increment this node by the given amount */ void add(TYPE val) { tsum+=val; // increment set_dirty(); } void set_dirty() { // make us dirty and our parent dirty if(dirty==false){ dirty = true; if(parent && parent->dirty==false){ parent->set_dirty(); // recurses to the root or the first dirty node. } } } }; /* end of node class */ class node *root; enum {root_depth=0, max_histogram_depth=128, ipv4_bits=32, ipv6_bits=128, }; iptreet &operator=(const iptreet &that); // not implemented protected: size_t nodes; // nodes in tree size_t maxnodes; // how many will we tolerate? uint64_t ctr_added; // how many were added uint64_t pruned; public: /**************************************************************** *** static member service routines ****************************************************************/ /* get the ith bit; 0 is the MSB */ static bool bit(const uint8_t *addr,size_t i){ return (addr[i / 8]) & (1<<((7-i)&7)); } /* set the ith bit to 1 */ static void setbit(uint8_t *addr,size_t addrlen, size_t i){ if ( i/8 < addrlen) { addr[i / 8] |= (1<<((7-i)&7)); } } virtual ~iptreet(){} // required per compiler warnings /* copy is a deep copy */ iptreet(const iptreet &n):root(n.root ? new node(*n.root) : 0), nodes(n.nodes),maxnodes(n.maxnodes),ctr_added(),pruned(),cache(),cachenext(),cache_hits(),cache_misses(){}; /* create an empty tree */ iptreet(int maxnodes_):root(new node(0)),nodes(0),maxnodes(maxnodes_), ctr_added(),pruned(),cache(),cachenext(),cache_hits(),cache_misses(){ for(size_t i=0;isum();}; /* add a node; implementation below */ void add(const uint8_t *addr,size_t addrlen,TYPE val); /**************************************************************** *** cache ****************************************************************/ class cache_element { public: uint8_t addr[ADDRBYTES]; node *ptr; // 0 means cache entry is not in use cache_element(const uint8_t addr_[ADDRBYTES],size_t addrlen,node *p):addr(),ptr(p){ memcpy(addr,addr_,addrlen); } }; enum {cache_size=4}; typedef std::vector cache_t; cache_t cache; size_t cachenext; // which cache element to evict next uint64_t cache_hits; uint64_t cache_misses; void cache_remove(const node *p){ for(size_t i=0;i=cache.size()) cachenext = 0; memcpy(cache[cachenext].addr,addr,addrlen); cache[cachenext].ptr = ptr; } /**************************************************************** *** pruning ****************************************************************/ /* prune the tree, starting at the root. Find the node to prune and then prune it. * node that best_to_prune() returns a const pointer. But we want to modify it, so we * do a const_cast (which is completely fine). */ int prune_best_node(){ if(root->isLeaf()) return 0; // leaf nodes can't be pruned class node::best b = root->best_to_prune(root_depth); node *tnode = const_cast(b.ptr); if(tnode){ return tnode->prune(*this); } return 0; } /* Simple implementation to prune the table if over the limit. */ void prune_if_needed(){ while(nodes > maxnodes){ if(prune_best_node()==0) return; // cannot prune } } /**************************************************************** *** historam support ****************************************************************/ class addr_elem { public: addr_elem(const uint8_t *addr_,uint8_t depth_,int64_t count_): addr(),depth(depth_),count(count_){ memcpy((void *)addr,addr_,sizeof(addr)); } addr_elem() : addr(), depth(0), count(0) { memset((void *) addr, 0x00, sizeof(addr)); } addr_elem &operator=(const addr_elem &n){ memcpy((void *)this->addr,n.addr,sizeof(this->addr)); this->count = n.count; this->depth = n.depth; return *this; } virtual ~addr_elem(){} const uint8_t addr[ADDRBYTES]; // maximum size address; v4 addresses have addr[4..15]=0 uint8_t depth; // in bits; /depth TYPE count; bool is4() const { return isipv4(addr,ADDRBYTES);}; std::string str() const { return ipstr(addr,ADDRBYTES,depth); } }; /** get a histogram of the tree, and starting at a particular node * The histogram is reported for every node that has a sum. * This is leaf nodes and inleafediate nodes. * This means that there must be a way for converting TYPE(count) to a boolean. * * @param depth - tracks current depth (in bits) into address. * @param ptr - the node currently being queried * @param histogram - where the histogram is written */ typedef std::vector histogram_t; void get_histogram(int depth,const uint8_t *addr,const class node *ptr,histogram_t &histogram) const{ if(ptr->nodesum()){ histogram.push_back(addr_elem(addr,depth,ptr->nodesum())); //return; } if(depth>max_histogram_depth) return; // can't go deeper than this now /* create address with 0 and 1 added */ uint8_t addr0[ADDRBYTES]; uint8_t addr1[ADDRBYTES]; memset(addr0,0,sizeof(addr0)); memcpy(addr0,addr,(depth+7)/8); memset(addr1,0,sizeof(addr1)); memcpy(addr1,addr,(depth+7)/8); setbit(addr1,sizeof(addr1),depth); if(ptr->ptr0) get_histogram(depth+1,addr0,ptr->ptr0,histogram); if(ptr->ptr1) get_histogram(depth+1,addr1,ptr->ptr1,histogram); } void get_histogram(histogram_t &histogram) const { // adds the histogram to the passed in vector uint8_t addr[ADDRBYTES]; memset(addr,0,sizeof(addr)); get_histogram(0,addr,root,histogram); } /**************************************************************** *** output routines ****************************************************************/ // returns true if addr[4..15]==0 static std::string itos(int n){ char buf[64]; snprintf(buf,sizeof(buf),"%d",n); return std::string(buf); } static bool isipv4(const uint8_t *addr,size_t addrlen) { if(addrlen==4) return true; for(u_int i=4;i void iptreet::add(const uint8_t *addr,size_t addrlen,TYPE val) { prune_if_needed(); if(addrlen > ADDRBYTES) addrlen=ADDRBYTES; u_int addr_bits = addrlen * 8; // in bits /* check the cache first */ ssize_t i = cache_search(addr,addrlen); if(i>=0){ cache[i].ptr->add(val); return; } /* descend the radix tree until we run out of bits, or we have a node with no pointers and a non-zero sum. */ node *ptr = root; // start at the root for(u_int depth=0;depth<=addr_bits;depth++){ if(depth==addr_bits){ // reached end of address ptr->add(val); // increment this node (and all of its descendants cache_replace(addr,addrlen,ptr); return; } if((ptr->tsum > 0) && (ptr->ptr0==0) && (ptr->ptr1==0)){ ptr->add(val); cache_replace(addr,addrlen,ptr); return; } /* Not a leaf node, so go down a level based on the next bit, * extending if necessary. */ if(bit(addr,depth)==0){ if(ptr->ptr0==0){ ptr->ptr0 = new node(ptr); nodes++; ctr_added++; } ptr = ptr->ptr0; } else { if(ptr->ptr1==0){ ptr->ptr1 = new node(ptr); nodes++; ctr_added++; } ptr = ptr->ptr1; } } assert(0); // should never happen } /* a structure for a pair of IP addresses */ class ip2tree:public iptreet { public: /* de-interleave a pair of addresses */ static void un_pair(uint8_t *addr1,uint8_t *addr2,size_t addr12len,size_t *depth1,size_t *depth2,const uint8_t *addr,size_t addrlen,size_t depth){ for(size_t i=0;i::bit(addr,i*2)) iptreet::setbit(addr1, addr12len, i); if(iptreet::bit(addr,i*2+1)) iptreet::setbit(addr2, addr12len, i); } *depth1 = (depth+1)/2; *depth2 = (depth)/2; } ip2tree(int maxnodes_):iptreet(maxnodes_){} virtual ~ip2tree(){}; /* str requires more work */ static std::string ip2str(const uint8_t *addr,size_t addrlen,size_t depth){ uint8_t addr1[16];memset(addr1,0,sizeof(addr1)); uint8_t addr2[16];memset(addr2,0,sizeof(addr2)); size_t depth1=0,depth2=0; ip2tree::un_pair(addr1,addr2,sizeof(addr1),&depth1,&depth2,addr,addrlen,depth); return ipstr(addr1,sizeof(addr1),depth1) + " " + ipstr(addr2,sizeof(addr2),depth2); } /* 2tree needs its own dump because a different ipstr is called */ std::ostream & dump(std::ostream &os) const { histogram_t histogram; get_histogram(histogram); os << "nodes: " << nodes << " histogram size: " << histogram.size() << "\n"; for(size_t i=0;i::bit(addr1,i)) iptreet::setbit(addr,sizeof(addr),i*2); if(iptreet::bit(addr2,i)) iptreet::setbit(addr,sizeof(addr),i*2+1); } add(addr,addrlen*2,val); /* Add it */ } }; typedef iptreet iptree; // simple tree for counting; reimplement so val is tcount template std::ostream & operator <<(std::ostream &os,const iptreet &ipt) { return ipt.dump(os); } inline std::ostream & operator <<(std::ostream &os,const ip2tree &ipt) { return ipt.dump(os); } #endif tcpflow-tcpflow-1.6.1/src/mime_map.cpp000066400000000000000000001036001401360461700177320ustar00rootroot00000000000000/* * This file is part of tcpflow by Simson Garfinkel . * Originally by Will Glynn . * * This source code is under the GNU Public License (GPL) version 3. * See COPYING for details. * */ #include "mime_map.h" #include #include std::map mime_map; class PopulateMimeMap { public: PopulateMimeMap(); }; static PopulateMimeMap populate_mime_map; PopulateMimeMap::PopulateMimeMap() { /* Generated from an OSX-provided mime.types, massaged somewhat by hand */ mime_map["application/andrew-inset"] = "ez"; mime_map["application/applixware"] = "aw"; mime_map["application/atom+xml"] = "atom"; mime_map["application/atomcat+xml"] = "atomcat"; mime_map["application/atomsvc+xml"] = "atomsvc"; mime_map["application/ccxml+xml"] = "ccxml"; mime_map["application/cdmi-capability"] = "cdmia"; mime_map["application/cdmi-container"] = "cdmic"; mime_map["application/cdmi-domain"] = "cdmid"; mime_map["application/cdmi-object"] = "cdmio"; mime_map["application/cdmi-queue"] = "cdmiq"; mime_map["application/cu-seeme"] = "cu"; mime_map["application/davmount+xml"] = "davmount"; mime_map["application/dssc+der"] = "dssc"; mime_map["application/dssc+xml"] = "xdssc"; mime_map["application/ecmascript"] = "ecma"; mime_map["application/emma+xml"] = "emma"; mime_map["application/epub+zip"] = "epub"; mime_map["application/exi"] = "exi"; mime_map["application/font-tdpfr"] = "pfr"; mime_map["application/hyperstudio"] = "stk"; mime_map["application/ipfix"] = "ipfix"; mime_map["application/java-archive"] = "jar"; mime_map["application/java-serialized-object"] = "ser"; mime_map["application/java-vm"] = "class"; mime_map["application/javascript"] = "js"; mime_map["application/json"] = "json"; mime_map["application/lost+xml"] = "lostxml"; mime_map["application/mac-binhex40"] = "hqx"; mime_map["application/mac-compactpro"] = "cpt"; mime_map["application/mads+xml"] = "mads"; mime_map["application/marc"] = "mrc"; mime_map["application/marcxml+xml"] = "mrcx"; mime_map["application/mathematica"] = "mb"; mime_map["application/mathml+xml"] = "mathml"; mime_map["application/mbox"] = "mbox"; mime_map["application/mediaservercontrol+xml"] = "mscml"; mime_map["application/metalink4+xml"] = "meta4"; mime_map["application/mets+xml"] = "mets"; mime_map["application/mods+xml"] = "mods"; mime_map["application/mp21"] = "mp21"; mime_map["application/mp4"] = "mp4s"; mime_map["application/msword"] = "doc"; mime_map["application/mxf"] = "mxf"; mime_map["application/oda"] = "oda"; mime_map["application/oebps-package+xml"] = "opf"; mime_map["application/ogg"] = "ogx"; mime_map["application/onenote"] = "onetoc"; mime_map["application/patch-ops-error+xml"] = "xer"; mime_map["application/pdf"] = "pdf"; mime_map["application/pgp-encrypted"] = "pgp"; mime_map["application/pgp-signature"] = "asc"; mime_map["application/pics-rules"] = "prf"; mime_map["application/pkcs10"] = "p10"; mime_map["application/pkcs7-mime"] = "p7m"; mime_map["application/pkcs7-signature"] = "p7s"; mime_map["application/pkcs8"] = "p8"; mime_map["application/pkix-attr-cert"] = "ac"; mime_map["application/pkix-cert"] = "cer"; mime_map["application/pkix-crl"] = "crl"; mime_map["application/pkix-pkipath"] = "pkipath"; mime_map["application/pkixcmp"] = "pki"; mime_map["application/pls+xml"] = "pls"; mime_map["application/postscript"] = "ps"; mime_map["application/prs.cww"] = "cww"; mime_map["application/pskc+xml"] = "pskcxml"; mime_map["application/rdf+xml"] = "rdf"; mime_map["application/reginfo+xml"] = "rif"; mime_map["application/relax-ng-compact-syntax"] = "rnc"; mime_map["application/resource-lists+xml"] = "rl"; mime_map["application/resource-lists-diff+xml"] = "rld"; mime_map["application/rls-services+xml"] = "rs"; mime_map["application/rsd+xml"] = "rsd"; mime_map["application/rss+xml"] = "rss"; mime_map["application/rtf"] = "rtf"; mime_map["application/sbml+xml"] = "sbml"; mime_map["application/scvp-cv-request"] = "scq"; mime_map["application/scvp-cv-response"] = "scs"; mime_map["application/scvp-vp-request"] = "spq"; mime_map["application/scvp-vp-response"] = "spp"; mime_map["application/sdp"] = "sdp"; mime_map["application/set-payment-initiation"] = "setpay"; mime_map["application/set-registration-initiation"] = "setreg"; mime_map["application/shf+xml"] = "shf"; mime_map["application/smil+xml"] = "smil"; mime_map["application/sparql-query"] = "rq"; mime_map["application/sparql-results+xml"] = "srx"; mime_map["application/srgs"] = "gram"; mime_map["application/srgs+xml"] = "grxml"; mime_map["application/sru+xml"] = "sru"; mime_map["application/ssml+xml"] = "ssml"; mime_map["application/tei+xml"] = "teicorpus"; mime_map["application/thraud+xml"] = "tfi"; mime_map["application/timestamped-data"] = "tsd"; mime_map["application/vnd.3gpp.pic-bw-large"] = "plb"; mime_map["application/vnd.3gpp.pic-bw-small"] = "psb"; mime_map["application/vnd.3gpp.pic-bw-var"] = "pvb"; mime_map["application/vnd.3gpp2.tcap"] = "tcap"; mime_map["application/vnd.3m.post-it-notes"] = "pwn"; mime_map["application/vnd.accpac.simply.aso"] = "aso"; mime_map["application/vnd.accpac.simply.imp"] = "imp"; mime_map["application/vnd.acucobol"] = "acu"; mime_map["application/vnd.acucorp"] = "atc"; mime_map["application/vnd.adobe.air-application-installer-package+zip"] = "air"; mime_map["application/vnd.adobe.fxp"] = "fxp"; mime_map["application/vnd.adobe.xdp+xml"] = "xdp"; mime_map["application/vnd.adobe.xfdf"] = "xfdf"; mime_map["application/vnd.ahead.space"] = "ahead"; mime_map["application/vnd.airzip.filesecure.azf"] = "azf"; mime_map["application/vnd.airzip.filesecure.azs"] = "azs"; mime_map["application/vnd.amazon.ebook"] = "azw"; mime_map["application/vnd.americandynamics.acc"] = "acc"; mime_map["application/vnd.amiga.ami"] = "ami"; mime_map["application/vnd.android.package-archive"] = "apk"; mime_map["application/vnd.anser-web-certificate-issue-initiation"] = "cii"; mime_map["application/vnd.anser-web-funds-transfer-initiation"] = "fti"; mime_map["application/vnd.antix.game-component"] = "atx"; mime_map["application/vnd.apple.installer+xml"] = "mpkg"; mime_map["application/vnd.apple.mpegurl"] = "m3u8"; mime_map["application/vnd.aristanetworks.swi"] = "swi"; mime_map["application/vnd.audiograph"] = "aep"; mime_map["application/vnd.blueice.multipass"] = "mpm"; mime_map["application/vnd.bmi"] = "bmi"; mime_map["application/vnd.businessobjects"] = "rep"; mime_map["application/vnd.chemdraw+xml"] = "cdxml"; mime_map["application/vnd.chipnuts.karaoke-mmd"] = "mmd"; mime_map["application/vnd.cinderella"] = "cdy"; mime_map["application/vnd.claymore"] = "cla"; mime_map["application/vnd.cloanto.rp9"] = "rp9"; mime_map["application/vnd.clonk.c4group"] = "c4g"; mime_map["application/vnd.cluetrust.cartomobile-config"] = "c11amc"; mime_map["application/vnd.cluetrust.cartomobile-config-pkg"] = "c11amz"; mime_map["application/vnd.commonspace"] = "csp"; mime_map["application/vnd.contact.cmsg"] = "cdbcmsg"; mime_map["application/vnd.cosmocaller"] = "cmc"; mime_map["application/vnd.crick.clicker"] = "clkx"; mime_map["application/vnd.crick.clicker.keyboard"] = "clkk"; mime_map["application/vnd.crick.clicker.palette"] = "clkp"; mime_map["application/vnd.crick.clicker.template"] = "clkt"; mime_map["application/vnd.crick.clicker.wordbank"] = "clkw"; mime_map["application/vnd.criticaltools.wbs+xml"] = "wbs"; mime_map["application/vnd.ctc-posml"] = "pml"; mime_map["application/vnd.cups-ppd"] = "ppd"; mime_map["application/vnd.curl.car"] = "car"; mime_map["application/vnd.curl.pcurl"] = "pcurl"; mime_map["application/vnd.data-vision.rdz"] = "rdz"; mime_map["application/vnd.denovo.fcselayout-link"] = "fe_launch"; mime_map["application/vnd.dna"] = "dna"; mime_map["application/vnd.dolby.mlp"] = "mlp"; mime_map["application/vnd.dpgraph"] = "dpg"; mime_map["application/vnd.dreamfactory"] = "dfac"; mime_map["application/vnd.dvb.ait"] = "ait"; mime_map["application/vnd.dvb.service"] = "svc"; mime_map["application/vnd.dynageo"] = "geo"; mime_map["application/vnd.ecowin.chart"] = "mag"; mime_map["application/vnd.enliven"] = "nml"; mime_map["application/vnd.epson.esf"] = "esf"; mime_map["application/vnd.epson.msf"] = "msf"; mime_map["application/vnd.epson.quickanime"] = "qam"; mime_map["application/vnd.epson.salt"] = "slt"; mime_map["application/vnd.epson.ssf"] = "ssf"; mime_map["application/vnd.eszigno3+xml"] = "es3"; mime_map["application/vnd.ezpix-album"] = "ez2"; mime_map["application/vnd.ezpix-package"] = "ez3"; mime_map["application/vnd.fdf"] = "fdf"; mime_map["application/vnd.fdsn.mseed"] = "mseed"; mime_map["application/vnd.fdsn.seed"] = "seed"; mime_map["application/vnd.flographit"] = "gph"; mime_map["application/vnd.fluxtime.clip"] = "ftc"; mime_map["application/vnd.framemaker"] = "fm"; mime_map["application/vnd.frogans.fnc"] = "fnc"; mime_map["application/vnd.frogans.ltf"] = "ltf"; mime_map["application/vnd.fsc.weblaunch"] = "fsc"; mime_map["application/vnd.fujitsu.oasys"] = "oas"; mime_map["application/vnd.fujitsu.oasys2"] = "oa2"; mime_map["application/vnd.fujitsu.oasys3"] = "oa3"; mime_map["application/vnd.fujitsu.oasysgp"] = "fg5"; mime_map["application/vnd.fujitsu.oasysprs"] = "bh2"; mime_map["application/vnd.fujixerox.ddd"] = "ddd"; mime_map["application/vnd.fujixerox.docuworks"] = "xdw"; mime_map["application/vnd.fujixerox.docuworks.binder"] = "xbd"; mime_map["application/vnd.fuzzysheet"] = "fzs"; mime_map["application/vnd.genomatix.tuxedo"] = "txd"; mime_map["application/vnd.geogebra.file"] = "ggb"; mime_map["application/vnd.geogebra.tool"] = "ggt"; mime_map["application/vnd.geometry-explorer"] = "gex"; mime_map["application/vnd.geonext"] = "gxt"; mime_map["application/vnd.geoplan"] = "g2w"; mime_map["application/vnd.geospace"] = "g3w"; mime_map["application/vnd.gmx"] = "gmx"; mime_map["application/vnd.google-earth.kml+xml"] = "kml"; mime_map["application/vnd.google-earth.kmz"] = "kmz"; mime_map["application/vnd.grafeq"] = "gqf"; mime_map["application/vnd.groove-account"] = "gac"; mime_map["application/vnd.groove-help"] = "ghf"; mime_map["application/vnd.groove-identity-message"] = "gim"; mime_map["application/vnd.groove-injector"] = "grv"; mime_map["application/vnd.groove-tool-message"] = "gtm"; mime_map["application/vnd.groove-tool-template"] = "tpl"; mime_map["application/vnd.groove-vcard"] = "vcg"; mime_map["application/vnd.hal+xml"] = "hal"; mime_map["application/vnd.handheld-entertainment+xml"] = "zmm"; mime_map["application/vnd.hbci"] = "hbci"; mime_map["application/vnd.hhe.lesson-player"] = "les"; mime_map["application/vnd.hp-hpgl"] = "hpgl"; mime_map["application/vnd.hp-hpid"] = "hpid"; mime_map["application/vnd.hp-hps"] = "hps"; mime_map["application/vnd.hp-jlyt"] = "jlt"; mime_map["application/vnd.hp-pcl"] = "pcl"; mime_map["application/vnd.hp-pclxl"] = "pclxl"; mime_map["application/vnd.hydrostatix.sof-data"] = "sfd-hdstx"; mime_map["application/vnd.hzn-3d-crossword"] = "x3d"; mime_map["application/vnd.ibm.minipay"] = "mpy"; mime_map["application/vnd.ibm.modcap"] = "afp"; mime_map["application/vnd.ibm.rights-management"] = "irm"; mime_map["application/vnd.ibm.secure-container"] = "sc"; mime_map["application/vnd.iccprofile"] = "icc"; mime_map["application/vnd.igloader"] = "igl"; mime_map["application/vnd.immervision-ivp"] = "ivp"; mime_map["application/vnd.immervision-ivu"] = "ivu"; mime_map["application/vnd.insors.igm"] = "igm"; mime_map["application/vnd.intercon.formnet"] = "xpw"; mime_map["application/vnd.intergeo"] = "i2g"; mime_map["application/vnd.intu.qbo"] = "qbo"; mime_map["application/vnd.intu.qfx"] = "qfx"; mime_map["application/vnd.ipunplugged.rcprofile"] = "rcprofile"; mime_map["application/vnd.irepository.package+xml"] = "irp"; mime_map["application/vnd.is-xpr"] = "xpr"; mime_map["application/vnd.isac.fcs"] = "fcs"; mime_map["application/vnd.jam"] = "jam"; mime_map["application/vnd.jcp.javame.midlet-rms"] = "rms"; mime_map["application/vnd.jisp"] = "jisp"; mime_map["application/vnd.joost.joda-archive"] = "joda"; mime_map["application/vnd.kahootz"] = "ktz"; mime_map["application/vnd.kde.karbon"] = "karbon"; mime_map["application/vnd.kde.kchart"] = "chrt"; mime_map["application/vnd.kde.kformula"] = "kfo"; mime_map["application/vnd.kde.kivio"] = "flw"; mime_map["application/vnd.kde.kontour"] = "kon"; mime_map["application/vnd.kde.kpresenter"] = "kpr"; mime_map["application/vnd.kde.kspread"] = "ksp"; mime_map["application/vnd.kde.kword"] = "kwd"; mime_map["application/vnd.kenameaapp"] = "htke"; mime_map["application/vnd.kidspiration"] = "kia"; mime_map["application/vnd.kinar"] = "knp"; mime_map["application/vnd.koan"] = "skp"; mime_map["application/vnd.kodak-descriptor"] = "sse"; mime_map["application/vnd.las.las+xml"] = "lasxml"; mime_map["application/vnd.llamagraphics.life-balance.desktop"] = "lbd"; mime_map["application/vnd.llamagraphics.life-balance.exchange+xml"] = "lbe"; mime_map["application/vnd.lotus-1-2-3"] = "123"; mime_map["application/vnd.lotus-approach"] = "apr"; mime_map["application/vnd.lotus-freelance"] = "pre"; mime_map["application/vnd.lotus-notes"] = "nsf"; mime_map["application/vnd.lotus-organizer"] = "org"; mime_map["application/vnd.lotus-screencam"] = "scm"; mime_map["application/vnd.lotus-wordpro"] = "lwp"; mime_map["application/vnd.macports.portpkg"] = "portpkg"; mime_map["application/vnd.mcd"] = "mcd"; mime_map["application/vnd.medcalcdata"] = "mc1"; mime_map["application/vnd.mediastation.cdkey"] = "cdkey"; mime_map["application/vnd.mfer"] = "mwf"; mime_map["application/vnd.mfmp"] = "mfm"; mime_map["application/vnd.micrografx.flo"] = "flo"; mime_map["application/vnd.micrografx.igx"] = "igx"; mime_map["application/vnd.mif"] = "mif"; mime_map["application/vnd.mobius.daf"] = "daf"; mime_map["application/vnd.mobius.dis"] = "dis"; mime_map["application/vnd.mobius.mbk"] = "mbk"; mime_map["application/vnd.mobius.mqy"] = "mqy"; mime_map["application/vnd.mobius.msl"] = "msl"; mime_map["application/vnd.mobius.plc"] = "plc"; mime_map["application/vnd.mobius.txf"] = "txf"; mime_map["application/vnd.mophun.application"] = "mpn"; mime_map["application/vnd.mophun.certificate"] = "mpc"; mime_map["application/vnd.mozilla.xul+xml"] = "xul"; mime_map["application/vnd.ms-artgalry"] = "cil"; mime_map["application/vnd.ms-cab-compressed"] = "cab"; mime_map["application/vnd.ms-excel"] = "xls"; mime_map["application/vnd.ms-excel.addin.macroenabled.12"] = "xlam"; mime_map["application/vnd.ms-excel.sheet.binary.macroenabled.12"] = "xlsb"; mime_map["application/vnd.ms-excel.sheet.macroenabled.12"] = "xlsm"; mime_map["application/vnd.ms-excel.template.macroenabled.12"] = "xltm"; mime_map["application/vnd.ms-fontobject"] = "eot"; mime_map["application/vnd.ms-htmlhelp"] = "chm"; mime_map["application/vnd.ms-ims"] = "ims"; mime_map["application/vnd.ms-lrm"] = "lrm"; mime_map["application/vnd.ms-officetheme"] = "thmx"; mime_map["application/vnd.ms-pki.seccat"] = "cat"; mime_map["application/vnd.ms-pki.stl"] = "stl"; mime_map["application/vnd.ms-powerpoint"] = "ppt"; mime_map["application/vnd.ms-powerpoint.addin.macroenabled.12"] = "ppam"; mime_map["application/vnd.ms-powerpoint.presentation.macroenabled.12"] = "pptm"; mime_map["application/vnd.ms-powerpoint.slide.macroenabled.12"] = "sldm"; mime_map["application/vnd.ms-powerpoint.slideshow.macroenabled.12"] = "ppsm"; mime_map["application/vnd.ms-powerpoint.template.macroenabled.12"] = "potm"; mime_map["application/vnd.ms-project"] = "mpp"; mime_map["application/vnd.ms-word.document.macroenabled.12"] = "docm"; mime_map["application/vnd.ms-word.template.macroenabled.12"] = "dotm"; mime_map["application/vnd.ms-works"] = "wps"; mime_map["application/vnd.ms-wpl"] = "wpl"; mime_map["application/vnd.ms-xpsdocument"] = "xps"; mime_map["application/vnd.mseq"] = "mseq"; mime_map["application/vnd.musician"] = "mus"; mime_map["application/vnd.muvee.style"] = "msty"; mime_map["application/vnd.neurolanguage.nlu"] = "nlu"; mime_map["application/vnd.noblenet-directory"] = "nnd"; mime_map["application/vnd.noblenet-sealer"] = "nns"; mime_map["application/vnd.noblenet-web"] = "nnw"; mime_map["application/vnd.nokia.n-gage.data"] = "ngdat"; mime_map["application/vnd.nokia.n-gage.symbian.install"] = "n-gage"; mime_map["application/vnd.nokia.radio-preset"] = "rpst"; mime_map["application/vnd.nokia.radio-presets"] = "rpss"; mime_map["application/vnd.novadigm.edm"] = "edm"; mime_map["application/vnd.novadigm.edx"] = "edx"; mime_map["application/vnd.novadigm.ext"] = "ext"; mime_map["application/vnd.oasis.opendocument.chart"] = "odc"; mime_map["application/vnd.oasis.opendocument.chart-template"] = "otc"; mime_map["application/vnd.oasis.opendocument.database"] = "odb"; mime_map["application/vnd.oasis.opendocument.formula"] = "odf"; mime_map["application/vnd.oasis.opendocument.formula-template"] = "odft"; mime_map["application/vnd.oasis.opendocument.graphics"] = "odg"; mime_map["application/vnd.oasis.opendocument.graphics-template"] = "otg"; mime_map["application/vnd.oasis.opendocument.image"] = "odi"; mime_map["application/vnd.oasis.opendocument.image-template"] = "oti"; mime_map["application/vnd.oasis.opendocument.presentation"] = "odp"; mime_map["application/vnd.oasis.opendocument.presentation-template"] = "otp"; mime_map["application/vnd.oasis.opendocument.spreadsheet"] = "ods"; mime_map["application/vnd.oasis.opendocument.spreadsheet-template"] = "ots"; mime_map["application/vnd.oasis.opendocument.text"] = "odt"; mime_map["application/vnd.oasis.opendocument.text-master"] = "odm"; mime_map["application/vnd.oasis.opendocument.text-template"] = "ott"; mime_map["application/vnd.oasis.opendocument.text-web"] = "oth"; mime_map["application/vnd.olpc-sugar"] = "xo"; mime_map["application/vnd.oma.dd2+xml"] = "dd2"; mime_map["application/vnd.openofficeorg.extension"] = "oxt"; mime_map["application/vnd.openxmlformats-officedocument.presentationml.presentation"] = "pptx"; mime_map["application/vnd.openxmlformats-officedocument.presentationml.slide"] = "sldx"; mime_map["application/vnd.openxmlformats-officedocument.presentationml.slideshow"] = "ppsx"; mime_map["application/vnd.openxmlformats-officedocument.presentationml.template"] = "potx"; mime_map["application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"] = "xlsx"; mime_map["application/vnd.openxmlformats-officedocument.spreadsheetml.template"] = "xltx"; mime_map["application/vnd.openxmlformats-officedocument.wordprocessingml.document"] = "docx"; mime_map["application/vnd.openxmlformats-officedocument.wordprocessingml.template"] = "dotx"; mime_map["application/vnd.osgeo.mapguide.package"] = "mgp"; mime_map["application/vnd.osgi.dp"] = "dp"; mime_map["application/vnd.palm"] = "pdb"; mime_map["application/vnd.pawaafile"] = "paw"; mime_map["application/vnd.pg.format"] = "str"; mime_map["application/vnd.pg.osasli"] = "ei6"; mime_map["application/vnd.picsel"] = "efif"; mime_map["application/vnd.pmi.widget"] = "wg"; mime_map["application/vnd.pocketlearn"] = "plf"; mime_map["application/vnd.powerbuilder6"] = "pbd"; mime_map["application/vnd.previewsystems.box"] = "box"; mime_map["application/vnd.proteus.magazine"] = "mgz"; mime_map["application/vnd.publishare-delta-tree"] = "qps"; mime_map["application/vnd.pvi.ptid1"] = "ptid"; mime_map["application/vnd.quark.quarkxpress"] = "qxd"; mime_map["application/vnd.realvnc.bed"] = "bed"; mime_map["application/vnd.recordare.musicxml"] = "mxl"; mime_map["application/vnd.recordare.musicxml+xml"] = "musicxml"; mime_map["application/vnd.rig.cryptonote"] = "cryptonote"; mime_map["application/vnd.rim.cod"] = "cod"; mime_map["application/vnd.rn-realmedia"] = "rm"; mime_map["application/vnd.route66.link66+xml"] = "link66"; mime_map["application/vnd.sailingtracker.track"] = "st"; mime_map["application/vnd.seemail"] = "see"; mime_map["application/vnd.sema"] = "sema"; mime_map["application/vnd.semd"] = "semd"; mime_map["application/vnd.semf"] = "semf"; mime_map["application/vnd.shana.informed.formdata"] = "ifm"; mime_map["application/vnd.shana.informed.formtemplate"] = "itp"; mime_map["application/vnd.shana.informed.interchange"] = "iif"; mime_map["application/vnd.shana.informed.package"] = "ipk"; mime_map["application/vnd.simtech-mindmapper"] = "twd"; mime_map["application/vnd.smaf"] = "mmf"; mime_map["application/vnd.smart.teacher"] = "teacher"; mime_map["application/vnd.solent.sdkm+xml"] = "sdkm"; mime_map["application/vnd.spotfire.dxp"] = "dxp"; mime_map["application/vnd.spotfire.sfs"] = "sfs"; mime_map["application/vnd.stardivision.calc"] = "sdc"; mime_map["application/vnd.stardivision.draw"] = "sda"; mime_map["application/vnd.stardivision.impress"] = "sdd"; mime_map["application/vnd.stardivision.math"] = "smf"; mime_map["application/vnd.stardivision.writer"] = "sdw"; mime_map["application/vnd.stardivision.writer-global"] = "sgl"; mime_map["application/vnd.stepmania.stepchart"] = "sm"; mime_map["application/vnd.sun.xml.calc"] = "sxc"; mime_map["application/vnd.sun.xml.calc.template"] = "stc"; mime_map["application/vnd.sun.xml.draw"] = "sxd"; mime_map["application/vnd.sun.xml.draw.template"] = "std"; mime_map["application/vnd.sun.xml.impress"] = "sxi"; mime_map["application/vnd.sun.xml.impress.template"] = "sti"; mime_map["application/vnd.sun.xml.math"] = "sxm"; mime_map["application/vnd.sun.xml.writer"] = "sxw"; mime_map["application/vnd.sun.xml.writer.global"] = "sxg"; mime_map["application/vnd.sun.xml.writer.template"] = "stw"; mime_map["application/vnd.sus-calendar"] = "sus"; mime_map["application/vnd.svd"] = "svd"; mime_map["application/vnd.symbian.install"] = "sis"; mime_map["application/vnd.syncml+xml"] = "xsm"; mime_map["application/vnd.syncml.dm+wbxml"] = "bdm"; mime_map["application/vnd.syncml.dm+xml"] = "xdm"; mime_map["application/vnd.tao.intent-module-archive"] = "tao"; mime_map["application/vnd.tmobile-livetv"] = "tmo"; mime_map["application/vnd.trid.tpt"] = "tpt"; mime_map["application/vnd.triscape.mxs"] = "mxs"; mime_map["application/vnd.trueapp"] = "tra"; mime_map["application/vnd.ufdl"] = "ufdl"; mime_map["application/vnd.uiq.theme"] = "utz"; mime_map["application/vnd.umajin"] = "umj"; mime_map["application/vnd.unity"] = "unityweb"; mime_map["application/vnd.uoml+xml"] = "uoml"; mime_map["application/vnd.vcx"] = "vcx"; mime_map["application/vnd.visio"] = "vsd"; mime_map["application/vnd.visionary"] = "vis"; mime_map["application/vnd.vsf"] = "vsf"; mime_map["application/vnd.wap.wbxml"] = "wbxml"; mime_map["application/vnd.wap.wmlc"] = "wmlc"; mime_map["application/vnd.wap.wmlscriptc"] = "wmlsc"; mime_map["application/vnd.webturbo"] = "wtb"; mime_map["application/vnd.wolfram.player"] = "nbp"; mime_map["application/vnd.wordperfect"] = "wpd"; mime_map["application/vnd.wqd"] = "wqd"; mime_map["application/vnd.wt.stf"] = "stf"; mime_map["application/vnd.xara"] = "xar"; mime_map["application/vnd.xfdl"] = "xfdl"; mime_map["application/vnd.yamaha.hv-dic"] = "hvd"; mime_map["application/vnd.yamaha.hv-script"] = "hvs"; mime_map["application/vnd.yamaha.hv-voice"] = "hvp"; mime_map["application/vnd.yamaha.openscoreformat"] = "osf"; mime_map["application/vnd.yamaha.openscoreformat.osfpvg+xml"] = "osfpvg"; mime_map["application/vnd.yamaha.smaf-audio"] = "saf"; mime_map["application/vnd.yamaha.smaf-phrase"] = "spf"; mime_map["application/vnd.yellowriver-custom-menu"] = "cmp"; mime_map["application/vnd.zul"] = "zir"; mime_map["application/vnd.zzazz.deck+xml"] = "zaz"; mime_map["application/voicexml+xml"] = "vxml"; mime_map["application/widget"] = "wgt"; mime_map["application/winhlp"] = "hlp"; mime_map["application/wsdl+xml"] = "wsdl"; mime_map["application/wspolicy+xml"] = "wspolicy"; mime_map["application/x-7z-compressed"] = "7z"; mime_map["application/x-abiword"] = "abw"; mime_map["application/x-ace-compressed"] = "ace"; mime_map["application/x-authorware-map"] = "aam"; mime_map["application/x-authorware-seg"] = "aas"; mime_map["application/x-bcpio"] = "bcpio"; mime_map["application/x-bittorrent"] = "torrent"; mime_map["application/x-bzip"] = "bz"; mime_map["application/x-bzip2"] = "bz2"; mime_map["application/x-cdlink"] = "vcd"; mime_map["application/x-chat"] = "chat"; mime_map["application/x-chess-pgn"] = "pgn"; mime_map["application/x-cpio"] = "cpio"; mime_map["application/x-csh"] = "csh"; mime_map["application/x-debian-package"] = "deb"; mime_map["application/x-director"] = "dir"; mime_map["application/x-doom"] = "wad"; mime_map["application/x-dtbncx+xml"] = "ncx"; mime_map["application/x-dtbook+xml"] = "dtb"; mime_map["application/x-dtbresource+xml"] = "res"; mime_map["application/x-dvi"] = "dvi"; mime_map["application/x-font-bdf"] = "bdf"; mime_map["application/x-font-ghostscript"] = "gsf"; mime_map["application/x-font-linux-psf"] = "psf"; mime_map["application/x-font-otf"] = "otf"; mime_map["application/x-font-pcf"] = "pcf"; mime_map["application/x-font-snf"] = "snf"; mime_map["application/x-font-ttf"] = "ttf"; mime_map["application/x-font-type1"] = "afm"; mime_map["application/x-font-woff"] = "woff"; mime_map["application/x-futuresplash"] = "spl"; mime_map["application/x-gnumeric"] = "gnumeric"; mime_map["application/x-gtar"] = "gtar"; mime_map["application/x-hdf"] = "hdf"; mime_map["application/x-java-jnlp-file"] = "jnlp"; mime_map["application/x-latex"] = "latex"; mime_map["application/x-mobipocket-ebook"] = "mobi"; mime_map["application/x-mpegurl"] = "m3u8"; mime_map["application/x-ms-application"] = "application"; mime_map["application/x-ms-wmd"] = "wmd"; mime_map["application/x-ms-wmz"] = "wmz"; mime_map["application/x-ms-xbap"] = "xbap"; mime_map["application/x-msaccess"] = "mdb"; mime_map["application/x-msbinder"] = "obd"; mime_map["application/x-mscardfile"] = "crd"; mime_map["application/x-msclip"] = "clp"; mime_map["application/x-msmediaview"] = "mvb"; mime_map["application/x-msmetafile"] = "wmf"; mime_map["application/x-msmoney"] = "mny"; mime_map["application/x-mspublisher"] = "pub"; mime_map["application/x-msschedule"] = "scd"; mime_map["application/x-msterminal"] = "trm"; mime_map["application/x-mswrite"] = "wri"; mime_map["application/x-netcdf"] = "nc"; mime_map["application/x-pkcs12"] = "p12"; mime_map["application/x-pkcs7-certificates"] = "p7b"; mime_map["application/x-pkcs7-certreqresp"] = "p7r"; mime_map["application/x-rar-compressed"] = "rar"; mime_map["application/x-sh"] = "sh"; mime_map["application/x-shar"] = "shar"; mime_map["application/x-shockwave-flash"] = "swf"; mime_map["application/x-silverlight-app"] = "xap"; mime_map["application/x-stuffit"] = "sit"; mime_map["application/x-stuffitx"] = "sitx"; mime_map["application/x-sv4cpio"] = "sv4cpio"; mime_map["application/x-sv4crc"] = "sv4crc"; mime_map["application/x-tar"] = "tar"; mime_map["application/x-tcl"] = "tcl"; mime_map["application/x-tex"] = "tex"; mime_map["application/x-tex-tfm"] = "tfm"; mime_map["application/x-texinfo"] = "texi"; mime_map["application/x-ustar"] = "ustar"; mime_map["application/x-wais-source"] = "src"; mime_map["application/x-x509-ca-cert"] = "crt"; mime_map["application/x-xfig"] = "fig"; mime_map["application/x-xpinstall"] = "xpi"; mime_map["application/xcap-diff+xml"] = "xdf"; mime_map["application/xenc+xml"] = "xenc"; mime_map["application/xhtml+xml"] = "xhtml"; mime_map["application/xml"] = "xml"; mime_map["application/xml-dtd"] = "dtd"; mime_map["application/xop+xml"] = "xop"; mime_map["application/xslt+xml"] = "xslt"; mime_map["application/xspf+xml"] = "xspf"; mime_map["application/xv+xml"] = "xvml"; mime_map["application/yang"] = "yang"; mime_map["application/yin+xml"] = "yin"; mime_map["application/zip"] = "zip"; mime_map["audio/adpcm"] = "adp"; mime_map["audio/basic"] = "au"; mime_map["audio/midi"] = "mid"; mime_map["audio/mp4"] = "mp4a"; mime_map["audio/mp4a-latm"] = "m4a"; mime_map["audio/mpeg"] = "mpga"; mime_map["audio/ogg"] = "ogg"; mime_map["audio/vnd.dece.audio"] = "uvva"; mime_map["audio/vnd.digital-winds"] = "eol"; mime_map["audio/vnd.dra"] = "dra"; mime_map["audio/vnd.dts"] = "dts"; mime_map["audio/vnd.dts.hd"] = "dtshd"; mime_map["audio/vnd.lucent.voice"] = "lvp"; mime_map["audio/vnd.ms-playready.media.pya"] = "pya"; mime_map["audio/vnd.nuera.ecelp4800"] = "ecelp4800"; mime_map["audio/vnd.nuera.ecelp7470"] = "ecelp7470"; mime_map["audio/vnd.nuera.ecelp9600"] = "ecelp9600"; mime_map["audio/vnd.rip"] = "rip"; mime_map["audio/webm"] = "weba"; mime_map["audio/x-aac"] = "aac"; mime_map["audio/x-aiff"] = "aiff"; mime_map["audio/x-mpegurl"] = "m3u"; mime_map["audio/x-ms-wax"] = "wax"; mime_map["audio/x-ms-wma"] = "wma"; mime_map["audio/x-pn-realaudio"] = "ram"; mime_map["audio/x-pn-realaudio-plugin"] = "rmp"; mime_map["audio/x-wav"] = "wav"; mime_map["chemical/x-cdx"] = "cdx"; mime_map["chemical/x-cif"] = "cif"; mime_map["chemical/x-cmdf"] = "cmdf"; mime_map["chemical/x-cml"] = "cml"; mime_map["chemical/x-csml"] = "csml"; mime_map["chemical/x-xyz"] = "xyz"; mime_map["image/bmp"] = "bmp"; mime_map["image/cgm"] = "cgm"; mime_map["image/g3fax"] = "g3"; mime_map["image/gif"] = "gif"; mime_map["image/ief"] = "ief"; mime_map["image/jp2"] = "jp2"; mime_map["image/jpeg"] = "jpg"; mime_map["image/ktx"] = "ktx"; mime_map["image/pict"] = "pict"; mime_map["image/png"] = "png"; mime_map["image/prs.btif"] = "btif"; mime_map["image/svg+xml"] = "svg"; mime_map["image/tiff"] = "tiff"; mime_map["image/vnd.adobe.photoshop"] = "psd"; mime_map["image/vnd.dece.graphic"] = "uvi"; mime_map["image/vnd.djvu"] = "djvu"; mime_map["image/vnd.dvb.subtitle"] = "sub"; mime_map["image/vnd.dwg"] = "dwg"; mime_map["image/vnd.dxf"] = "dxf"; mime_map["image/vnd.fastbidsheet"] = "fbs"; mime_map["image/vnd.fpx"] = "fpx"; mime_map["image/vnd.fst"] = "fst"; mime_map["image/vnd.fujixerox.edmics-mmr"] = "mmr"; mime_map["image/vnd.fujixerox.edmics-rlc"] = "rlc"; mime_map["image/vnd.ms-modi"] = "mdi"; mime_map["image/vnd.net-fpx"] = "npx"; mime_map["image/vnd.wap.wbmp"] = "wbmp"; mime_map["image/vnd.xiff"] = "xif"; mime_map["image/webp"] = "webp"; mime_map["image/x-cmu-raster"] = "ras"; mime_map["image/x-cmx"] = "cmx"; mime_map["image/x-freehand"] = "fh"; mime_map["image/x-icon"] = "ico"; mime_map["image/x-macpaint"] = "pntg"; mime_map["image/x-pcx"] = "pcx"; mime_map["image/x-pict"] = "pict"; mime_map["image/x-portable-anymap"] = "pnm"; mime_map["image/x-portable-bitmap"] = "pbm"; mime_map["image/x-portable-graymap"] = "pgm"; mime_map["image/x-portable-pixmap"] = "ppm"; mime_map["image/x-quicktime"] = "qtif"; mime_map["image/x-rgb"] = "rgb"; mime_map["image/x-xbitmap"] = "xbm"; mime_map["image/x-xpixmap"] = "xpm"; mime_map["image/x-xwindowdump"] = "xwd"; mime_map["message/rfc822"] = "eml"; mime_map["model/iges"] = "iges"; mime_map["model/mesh"] = "mesh"; mime_map["model/vnd.collada+xml"] = "dae"; mime_map["model/vnd.dwf"] = "dwf"; mime_map["model/vnd.gdl"] = "gdl"; mime_map["model/vnd.gtw"] = "gtw"; mime_map["model/vnd.mts"] = "mts"; mime_map["model/vnd.vtu"] = "vtu"; mime_map["model/vrml"] = "vrml"; mime_map["text/cache-manifest"] = "manifest"; mime_map["text/calendar"] = "ics"; mime_map["text/css"] = "css"; mime_map["text/csv"] = "csv"; mime_map["text/html"] = "html"; mime_map["text/n3"] = "n3"; mime_map["text/plain"] = "txt"; mime_map["text/prs.lines.tag"] = "dsc"; mime_map["text/richtext"] = "rtx"; mime_map["text/sgml"] = "sgml"; mime_map["text/tab-separated-values"] = "tsv"; mime_map["text/troff"] = "roff"; mime_map["text/turtle"] = "ttl"; mime_map["text/uri-list"] = "urls"; mime_map["text/vnd.curl"] = "curl"; mime_map["text/vnd.curl.dcurl"] = "dcurl"; mime_map["text/vnd.curl.mcurl"] = "mcurl"; mime_map["text/vnd.curl.scurl"] = "scurl"; mime_map["text/vnd.fly"] = "fly"; mime_map["text/vnd.fmi.flexstor"] = "flx"; mime_map["text/vnd.graphviz"] = "gv"; mime_map["text/vnd.in3d.3dml"] = "3dml"; mime_map["text/vnd.in3d.spot"] = "spot"; mime_map["text/vnd.sun.j2me.app-descriptor"] = "jad"; mime_map["text/vnd.wap.wml"] = "wml"; mime_map["text/vnd.wap.wmlscript"] = "wmls"; mime_map["text/x-asm"] = "asm"; mime_map["text/x-c"] = "c"; mime_map["text/x-fortran"] = "f"; mime_map["text/x-java-source"] = "java"; mime_map["text/x-pascal"] = "pas"; mime_map["text/x-setext"] = "etx"; mime_map["text/x-uuencode"] = "uu"; mime_map["text/x-vcalendar"] = "vcs"; mime_map["text/x-vcard"] = "vcf"; mime_map["video/3gpp"] = "3gp"; mime_map["video/3gpp2"] = "3g2"; mime_map["video/h261"] = "h261"; mime_map["video/h263"] = "h263"; mime_map["video/h264"] = "h264"; mime_map["video/jpeg"] = "jpgv"; mime_map["video/jpm"] = "jpm"; mime_map["video/mj2"] = "mj2"; mime_map["video/mp2t"] = "ts"; mime_map["video/mp4"] = "m4v"; mime_map["video/mpeg"] = "mpg"; mime_map["video/ogg"] = "ogv"; mime_map["video/quicktime"] = "mov"; mime_map["video/vnd.dece.hd"] = "uvvh"; mime_map["video/vnd.dece.mobile"] = "uvvm"; mime_map["video/vnd.dece.pd"] = "uvvp"; mime_map["video/vnd.dece.sd"] = "uvvs"; mime_map["video/vnd.dece.video"] = "uvvv"; mime_map["video/vnd.fvt"] = "fvt"; mime_map["video/vnd.mpegurl"] = "m4u"; mime_map["video/vnd.ms-playready.media.pyv"] = "pyv"; mime_map["video/vnd.uvvu.mp4"] = "uvvu"; mime_map["video/vnd.vivo"] = "viv"; mime_map["video/webm"] = "webm"; mime_map["video/x-dv"] = "dv"; mime_map["video/x-f4v"] = "f4v"; mime_map["video/x-fli"] = "fli"; mime_map["video/x-flv"] = "flv"; mime_map["video/x-m4v"] = "m4v"; mime_map["video/x-ms-asf"] = "asf"; mime_map["video/x-ms-wm"] = "wm"; mime_map["video/x-ms-wmv"] = "wmv"; mime_map["video/x-ms-wmx"] = "wmx"; mime_map["video/x-ms-wvx"] = "wvx"; mime_map["video/x-msvideo"] = "avi"; mime_map["video/x-sgi-movie"] = "movie"; mime_map["x-conference/x-cooltalk"] = "ice"; } std::string get_extension_for_mime_type(const std::string& mime_type) { /* Strip anything after a semicolon (e.g. text/html; charset=utf-8) */ std::string base_type(mime_type); size_t semicolon_pos = base_type.find_first_of(";"); if (semicolon_pos != std::string::npos) { base_type = base_type.substr(0, semicolon_pos); } /* Downcase it for comparsion purposes */ std::transform(base_type.begin(), base_type.end(), base_type.begin(), ::tolower); /* Look it up in the map */ return mime_map[base_type]; } tcpflow-tcpflow-1.6.1/src/mime_map.h000066400000000000000000000006011401360461700173740ustar00rootroot00000000000000/* * This file is part of tcpflow by Simson Garfinkel . * Originally by Will Glynn . * * This source code is under the GNU Public License (GPL) version 3. * See COPYING for details. * */ #ifndef MIME_MAP_H #define MIME_MAP_H #include std::string get_extension_for_mime_type(const std::string& mime_type); #endif /* MIME_MAP_H */tcpflow-tcpflow-1.6.1/src/netviz/000077500000000000000000000000001401360461700167615ustar00rootroot00000000000000tcpflow-tcpflow-1.6.1/src/netviz/address_histogram.cpp000066400000000000000000000044751401360461700232010ustar00rootroot00000000000000/** * address_histogram.cpp: * * This source file is public domain, as it is not based on the original tcpflow. * * Author: Michael Shick * */ #include "config.h" #ifdef HAVE_LIBCAIRO #include "tcpflow.h" #include "tcpip.h" #include #include #include #include "address_histogram.h" using namespace std; address_histogram::address_histogram(const iptree &tree) : buckets(), datagrams_ingested(0) { // convert iptree to suitable vector for count histogram iptree::histogram_t addresses; tree.get_histogram(addresses); if(addresses.size() <= bucket_count) { sort(addresses.begin(), addresses.end(), iptree_node_comparator()); } else { partial_sort(addresses.begin(), addresses.begin() + bucket_count, addresses.end(), iptree_node_comparator()); } buckets.clear(); vector::const_iterator it = addresses.begin(); for(size_t ii = 0; ii < bucket_count && it != addresses.end(); ii++, it++) { buckets.push_back(*it); } datagrams_ingested = tree.sum(); } const size_t address_histogram::bucket_count = 10; const iptree::addr_elem &address_histogram::at(size_t index) const { return buckets.at(index); } size_t address_histogram::size() const { return buckets.size(); } uint64_t address_histogram::ingest_count() const { return datagrams_ingested; } address_histogram::ipt_addrs::const_iterator address_histogram::begin() const { return buckets.begin(); } address_histogram::ipt_addrs::const_iterator address_histogram::end() const { return buckets.end(); } address_histogram::ipt_addrs::const_reverse_iterator address_histogram::rbegin() const { return buckets.rbegin(); } address_histogram::ipt_addrs::const_reverse_iterator address_histogram::rend() const { return buckets.rend(); } bool address_histogram::iptree_node_comparator::operator()(const iptree::addr_elem &a, const iptree::addr_elem &b) { if(a.count > b.count) { return true; } else if(a.count < b.count) { return false; } for(size_t ii = 0; ii < sizeof(a.addr); ii++) { if(a.addr[ii] > b.addr[ii]) { return true; } else if(a.addr[ii] < b.addr[ii]) { return false; } } return false; } #endif tcpflow-tcpflow-1.6.1/src/netviz/address_histogram.h000066400000000000000000000016541401360461700226420ustar00rootroot00000000000000/** * address histogram class. * * This source file is public domain, as it is not based on the original tcpflow. * * Author: Michael Shick * */ #ifndef ADDRESS_HISTOGRAM_H #define ADDRESS_HISTOGRAM_H #include "iptree.h" class address_histogram { public: address_histogram(const iptree &tree); class iptree_node_comparator { public: bool operator()(const iptree::addr_elem &a, const iptree::addr_elem &b); }; static const size_t bucket_count; const iptree::addr_elem &at(size_t index) const; size_t size() const; uint64_t ingest_count() const; typedef std::vector ipt_addrs; ipt_addrs::const_iterator begin() const; ipt_addrs::const_iterator end() const; ipt_addrs::const_reverse_iterator rbegin() const; ipt_addrs::const_reverse_iterator rend() const; private: ipt_addrs buckets; uint64_t datagrams_ingested; }; #endif tcpflow-tcpflow-1.6.1/src/netviz/address_histogram_view.cpp000066400000000000000000000135621401360461700242300ustar00rootroot00000000000000/** * address_histogram_view.cpp: * Show packets received vs addr * * This source file is public domain, as it is not based on the original tcpflow. * * Author: Michael Shick * */ #include "config.h" #ifdef HAVE_LIBCAIRO #include "tcpflow.h" #include #include #include "address_histogram_view.h" using namespace std; address_histogram_view::address_histogram_view(const address_histogram &histogram_) : histogram(histogram_), bar_color(0.0, 0.0, 0.0), cdf_color(0.0, 0.0, 0.0) { subtitle = ""; title_on_bottom = true; pad_left_factor = 0.1; pad_right_factor = 0.1; pad_top_factor = 0.5; x_label = ""; y_label = ""; y_tick_font_size = 6.0; right_tick_font_size = 6.0; } const double address_histogram_view::bar_space_factor = 1.2; const size_t address_histogram_view::compressed_ip6_str_max_len = 16; const double address_histogram_view::cdf_line_width = 0.5; const double address_histogram_view::data_width_factor = 0.85; void address_histogram_view::render(cairo_t *cr, const bounds_t &bounds) { y_tick_labels.push_back(plot_view::pretty_byte_total(0)); if(histogram.size() > 0) { y_tick_labels.push_back(plot_view::pretty_byte_total(histogram.at(0).count, 0)); } right_tick_labels.push_back("0%"); right_tick_labels.push_back("100%"); plot_view::render(cr, bounds); } void address_histogram_view::render_data(cairo_t *cr, const bounds_t &bounds) { if(histogram.size() < 1 || histogram.at(0).count == 0) { return; } double data_width = bounds.width * data_width_factor; double data_offset = 0; bounds_t data_bounds(bounds.x + data_offset, bounds.y, data_width, bounds.height); double offset_unit = data_bounds.width / histogram.size(); double bar_width = offset_unit / bar_space_factor; double space_width = (offset_unit - bar_width) / 2.0; uint64_t greatest = histogram.at(0).count; unsigned int index = 0; double cdf_last_x = bounds.x, cdf_last_y = bounds.y + data_bounds.height; for(address_histogram::ipt_addrs::const_iterator it = histogram.begin(); it != histogram.end(); it++) { double bar_height = (((double) it->count) / ((double) greatest)) * data_bounds.height; // bar double bar_x = data_bounds.x + (index * offset_unit + space_width); double bar_y = data_bounds.y + (data_bounds.height - bar_height); bounds_t bar_bounds(bar_x, bar_y, bar_width, bar_height); bucket_view view(*it, bar_color); view.render(cr, bar_bounds); // CDF double cdf_x = cdf_last_x + offset_unit; // account for left and right padding of bars if(index == 0) { cdf_x += data_offset; } if(index == histogram.size() - 1) { cdf_x = bounds.x + bounds.width; } double cdf_y = cdf_last_y - ((double) it->count / (double) histogram.ingest_count()) * data_bounds.height; cairo_move_to(cr, cdf_last_x, cdf_last_y); // don't draw over the left-hand y axis if(index == 0) { cairo_move_to(cr, cdf_last_x, cdf_y); } else { cairo_line_to(cr, cdf_last_x, cdf_y); } cairo_line_to(cr, cdf_x, cdf_y); cairo_set_source_rgb(cr, cdf_color.r, cdf_color.g, cdf_color.b); cairo_set_line_width(cr, cdf_line_width); cairo_stroke(cr); cdf_last_x = cdf_x; cdf_last_y = cdf_y; index++; } index = 0; // labels must be done after the fact to avoid awkward interaction with the CDF for(address_histogram::ipt_addrs::const_iterator it = histogram.begin(); it != histogram.end(); it++) { double bar_height = (((double) it->count) / ((double) greatest)) * data_bounds.height; double bar_x = data_bounds.x + (index * offset_unit + space_width); double bar_y = data_bounds.y + (data_bounds.height - bar_height); bounds_t bar_bounds(bar_x, bar_y, bar_width, bar_height); bucket_view view(*it, bar_color); view.render_label(cr, bar_bounds); index++; } } const address_histogram &address_histogram_view::get_data() const { return histogram; } string address_histogram_view::compressed_ip6_str(iptree::addr_elem address) { return ssprintf("%x:%x...%x", (address.addr[0] << 8) + address.addr[1], (address.addr[2] << 8) + address.addr[3], (address.addr[14] << 8) + address.addr[15]); } // bucket view const double address_histogram_view::bucket_view::label_font_size = 6.0; void address_histogram_view::bucket_view::render(cairo_t *cr, const bounds_t &bounds) { cairo_set_source_rgb(cr, color.r, color.g, color.b); cairo_rectangle(cr, bounds.x, bounds.y, bounds.width, bounds.height); cairo_fill(cr); } void address_histogram_view::bucket_view::render_label(cairo_t *cr, const bounds_t &bounds) { cairo_matrix_t unrotated_matrix; cairo_get_matrix(cr, &unrotated_matrix); cairo_rotate(cr, -M_PI / 4.0); string label = bucket.str(); if(!bucket.is4() && label.length() > compressed_ip6_str_max_len) { label = compressed_ip6_str(bucket); } cairo_set_font_size(cr, label_font_size); cairo_text_extents_t label_extents; cairo_text_extents(cr, label.c_str(), &label_extents); double label_x = bounds.x + bounds.width / 2.0; double label_y = bounds.y - 2.0; cairo_device_to_user(cr, &label_x, &label_y); cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); cairo_rectangle(cr, label_x, label_y, label_extents.width, -label_extents.height); cairo_fill(cr); cairo_rectangle(cr, label_x, label_y, label_extents.width, -label_extents.height); cairo_set_line_width(cr, 2.0); cairo_stroke(cr); cairo_move_to(cr, label_x, label_y); cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); cairo_show_text(cr, label.c_str()); cairo_set_matrix(cr, &unrotated_matrix); } #endif tcpflow-tcpflow-1.6.1/src/netviz/address_histogram_view.h000066400000000000000000000025131401360461700236670ustar00rootroot00000000000000/* * This source file is public domain, as it is not based on the original tcpflow. * * Author: Michael Shick */ #ifndef ADDRESS_HISTOGRAM_VIEW_H #define ADDRESS_HISTOGRAM_VIEW_H #include "config.h" #ifdef HAVE_LIBCAIRO #include "plot_view.h" #include "address_histogram.h" class address_histogram_view : public plot_view { public: address_histogram_view(const address_histogram &histogram_); class bucket_view { public: bucket_view(const iptree::addr_elem &bucket_, const rgb_t &color_) : bucket(bucket_), color(color_) {} const iptree::addr_elem &bucket; const rgb_t &color; static const double label_font_size; void render(cairo_t *cr, const bounds_t &bounds); void render_label(cairo_t *cr, const bounds_t &bounds); }; const address_histogram &histogram; rgb_t bar_color; rgb_t cdf_color; static const double bar_space_factor; static const size_t compressed_ip6_str_max_len; static const double cdf_line_width; static const double data_width_factor; void render(cairo_t *cr, const bounds_t &bounds); void render_data(cairo_t *cr, const bounds_t &bounds); const address_histogram &get_data() const; static std::string compressed_ip6_str(iptree::addr_elem address); }; #endif #endif tcpflow-tcpflow-1.6.1/src/netviz/legend_view.cpp000066400000000000000000000057761401360461700217740ustar00rootroot00000000000000/** * legend_view.cpp: * Show packets received vs port * * This source file is public domain, as it is not based on the original tcpflow. * * Author: Michael Shick * */ #include "config.h" #ifdef HAVE_LIBCAIRO #include "tcpflow.h" #include "legend_view.h" using namespace std; const string legend_view::empty_legend_label = "No TCP"; const double legend_view::base_font_size = 6.0; const double legend_view::chip_length = 8.0; const double legend_view::chip_label_space = 4.0; const double legend_view::inter_item_space = 12.0; const double legend_view::padding = 8.0; const double legend_view::border_width = 0.5; const plot_view::rgb_t legend_view::border_color(0.67, 0.67, 0.67); void legend_view::render(cairo_t *cr, const plot_view::bounds_t &bounds) const { double font_size = base_font_size; if(entries.size() == 0) { font_size *= 2.0; } cairo_set_font_size(cr, font_size); double tallest = 0.0; double total_width = 0.0; for(entries_t::const_iterator it = entries.begin(); it != entries.end(); ++it) { cairo_text_extents_t extents; cairo_text_extents(cr, it->label.c_str(), &extents); total_width += chip_length + chip_label_space + extents.width; if(it + 1 != entries.end()) { total_width += inter_item_space; } if(extents.height > tallest) { tallest = extents.height; } } if(entries.size() == 0) { cairo_text_extents_t extents; cairo_text_extents(cr, empty_legend_label.c_str(), &extents); total_width += extents.width; tallest = extents.height; } double chip_y = bounds.y + ((bounds.height - chip_length) / 2.0); double label_y = bounds.y + ((bounds.height + tallest) / 2.0); double x = bounds.x + ((bounds.width - total_width) / 2.0); cairo_set_source_rgb(cr, border_color.r, border_color.g, border_color.b); cairo_set_line_width(cr, border_width); cairo_rectangle(cr, x, bounds.y, total_width + (padding * 2.0), bounds.height); cairo_stroke(cr); x += padding; for(entries_t::const_iterator it = entries.begin(); it != entries.end(); ++it) { cairo_text_extents_t extents; cairo_text_extents(cr, it->label.c_str(), &extents); const plot_view::rgb_t &color = it->color; cairo_set_source_rgb(cr, color.r, color.g, color.b); cairo_rectangle(cr, x, chip_y, chip_length, chip_length); cairo_fill(cr); x += chip_length + chip_label_space; cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); cairo_move_to(cr, x, label_y); cairo_show_text(cr, it->label.c_str()); x += extents.width + inter_item_space; } if(entries.size() == 0) { cairo_text_extents_t extents; cairo_text_extents(cr, empty_legend_label.c_str(), &extents); cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); cairo_move_to(cr, x, label_y); cairo_show_text(cr, empty_legend_label.c_str()); x += extents.width + inter_item_space; } } #endif tcpflow-tcpflow-1.6.1/src/netviz/legend_view.h000066400000000000000000000022731401360461700214260ustar00rootroot00000000000000/* * This source file is public domain, as it is not based on the original tcpflow. * * Author: Michael Shick */ #ifndef LEGEND_VIEW_H #define LEGEND_VIEW_H #include "plot_view.h" class legend_view { public: // legend_view::entry to everyone else class entry_t { public: entry_t(plot_view::rgb_t color_, std::string label_, uint16_t port_) : color(color_), label(label_), port(port_) {} plot_view::rgb_t color; std::string label; uint16_t port; }; typedef std::vector entries_t; legend_view(entries_t entries_) : entries(entries_) {} void render(cairo_t *cr, const plot_view::bounds_t &bounds) const; static const std::string empty_legend_label; static const double base_font_size; static const double chip_length; static const double chip_label_space; static const double inter_item_space; static const double padding; static const double border_width; static const plot_view::rgb_t border_color; private: const entries_t entries; }; inline bool operator<(const legend_view::entry_t &a, const legend_view::entry_t &b) { return a.port < b.port; } #endif tcpflow-tcpflow-1.6.1/src/netviz/net_map.cpp000066400000000000000000000020071401360461700211070ustar00rootroot00000000000000/** * net_map.cpp: * Show map of network traffic by host * * This source file is public domain, as it is not based on the original tcpflow. * * Author: Michael Shick * */ #include "config.h" #ifdef HAVE_LIBCAIRO #include "tcpflow.h" #include "net_map.h" void net_map::ingest_packet(const be13::packet_info &pi) { } void net_map::render(cairo_t *cr, const plot_view::bounds_t &bounds) { cairo_set_source_rgb(cr, 0.67, 0.67, 0.67); cairo_rectangle(cr, bounds.x, bounds.y, bounds.width, bounds.height); cairo_fill(cr); double font_size = 16.0; std::string label = "pretty map"; cairo_text_extents_t extents; cairo_set_font_size(cr, font_size); cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); cairo_text_extents(cr, label.c_str(), &extents); double text_x = bounds.x + (bounds.width - extents.width) / 2.0; double text_y = bounds.y + (bounds.height + extents.height) / 2.0; cairo_move_to(cr, text_x, text_y); cairo_show_text(cr, label.c_str()); } #endif tcpflow-tcpflow-1.6.1/src/netviz/net_map.h000066400000000000000000000006531401360461700205610ustar00rootroot00000000000000/** * net_map.h: * Show map of network traffic by host * * This source file is public domain, as it is not based on the original tcpflow. * * Author: Michael Shick * */ #ifndef NET_MAP_H #define NET_MAP_H #include "plot_view.h" class net_map { public: net_map() {} void ingest_packet(const be13::packet_info &pi); void render(cairo_t *cr, const plot_view::bounds_t &bounds); }; #endif tcpflow-tcpflow-1.6.1/src/netviz/one_page_report.cpp000066400000000000000000000547071401360461700226520ustar00rootroot00000000000000/** * one_page_report.cpp: * Generate a one-page visualization from TCP packets * * This source file is public domain, as it is not based on the original tcpflow. * * Author: Michael Shick * */ #include "config.h" #include "be13_api/utils.h" #include "plot_view.h" #ifdef HAVE_LIBCAIRO #include "tcpflow.h" #include "tcpip.h" #include #include #include #include "one_page_report.h" using namespace std; const unsigned int one_page_report::max_bars = 100; const unsigned int one_page_report::port_colors_count = 4; // string constants const string one_page_report::title_version = PACKAGE_NAME " " PACKAGE_VERSION; const string one_page_report::generic_legend_format = "Port %d"; const vector one_page_report::display_transports = one_page_report::build_display_transports(); // ratio constants const double one_page_report::page_margin_factor = 0.05; const double one_page_report::line_space_factor = 0.25; const double one_page_report::histogram_pad_factor_y = 1.1; const double one_page_report::address_histogram_width_divisor = 2.2; // size constants const double one_page_report::packet_histogram_height = 100.0; const double one_page_report::address_histogram_height = 125.0; const double one_page_report::port_histogram_height = 100.0; const double one_page_report::legend_height = 16.0; // color constants const plot_view::rgb_t one_page_report::default_color(0.67, 0.67, 0.67); const plot_view::rgb_t one_page_report::color_orange(1.00, 0.47, 0.00); const plot_view::rgb_t one_page_report::color_red(1.00, 0.00, 0.00); const plot_view::rgb_t one_page_report::color_magenta(0.75, 0.00, 0.60); const plot_view::rgb_t one_page_report::color_purple(0.58, 0.00, 0.75); const plot_view::rgb_t one_page_report::color_deep_purple(0.40, 0.00, 0.75); const plot_view::rgb_t one_page_report::color_blue(0.02, 0.00, 1.00); const plot_view::rgb_t one_page_report::color_teal(0.00, 0.75, 0.65); const plot_view::rgb_t one_page_report::color_green(0.02, 0.75, 0.00); const plot_view::rgb_t one_page_report::color_yellow(0.99, 1.00, 0.00); const plot_view::rgb_t one_page_report::color_light_orange(1.00, 0.73, 0.00); const plot_view::rgb_t one_page_report::cdf_color(0.00, 0.00, 0.00); one_page_report::one_page_report(int max_histogram_size) : source_identifier(), filename("report.pdf"), bounds(0.0, 0.0, 611.0, 792.0), header_font_size(8.0), top_list_font_size(8.0), histogram_show_top_n_text(3), packet_count(0), byte_count(0), earliest(), latest(), transport_counts(), ports_in_time_histogram(), color_labels(), packet_histogram(), src_port_histogram(), dst_port_histogram(), pfall(), netmap(), src_tree(max_histogram_size), dst_tree(max_histogram_size), port_aliases(), port_colormap() { earliest = (struct timeval) { 0 }; latest = (struct timeval) { 0 }; port_colormap[PORT_HTTP] = color_blue; port_colormap[PORT_HTTP_ALT_0] = color_blue; port_colormap[PORT_HTTP_ALT_1] = color_blue; port_colormap[PORT_HTTP_ALT_2] = color_blue; port_colormap[PORT_HTTP_ALT_3] = color_blue; port_colormap[PORT_HTTP_ALT_4] = color_blue; port_colormap[PORT_HTTP_ALT_5] = color_blue; port_colormap[PORT_HTTPS] = color_green; port_colormap[PORT_SSH] = color_purple; port_colormap[PORT_FTP_CONTROL] = color_red; port_colormap[PORT_FTP_DATA] = color_red; // build null alias map to avoid requiring special handling for unmapped ports for(int ii = 0; ii <= 65535; ii++) { port_aliases[ii] = ii; } } void one_page_report::ingest_packet(const be13::packet_info &pi) { if(earliest.tv_sec == 0 || (pi.ts.tv_sec < earliest.tv_sec || (pi.ts.tv_sec == earliest.tv_sec && pi.ts.tv_usec < earliest.tv_usec))) { earliest = pi.ts; } if(pi.ts.tv_sec > latest.tv_sec || (pi.ts.tv_sec == latest.tv_sec && pi.ts.tv_usec > latest.tv_usec)) { latest = pi.ts; } size_t packet_length = pi.pcap_hdr->len; packet_count++; byte_count += packet_length; transport_counts[pi.ether_type()] += packet_length; // should we handle VLANs? // break out TCP/IP info and feed child views // feed IP-only views uint8_t ip_ver = 0; if(pi.is_ip4()) { ip_ver = 4; src_tree.add((uint8_t *) pi.ip_data + pi.ip4_src_off, IP4_ADDR_LEN, packet_length); dst_tree.add((uint8_t *) pi.ip_data + pi.ip4_dst_off, IP4_ADDR_LEN, packet_length); } else if(pi.is_ip6()) { ip_ver = 6; src_tree.add((uint8_t *) pi.ip_data + pi.ip6_src_off, IP6_ADDR_LEN, packet_length); dst_tree.add((uint8_t *) pi.ip_data + pi.ip6_dst_off, IP6_ADDR_LEN, packet_length); } else { packet_histogram.insert(pi.ts, 0, packet_length, time_histogram::F_NON_TCP); return; } // feed TCP views uint16_t tcp_src = 0, tcp_dst = 0; bool has_tcp = false; switch(ip_ver) { case 4: if(!pi.is_ip4_tcp()) { break; } tcp_src = pi.get_ip4_tcp_sport(); tcp_dst = pi.get_ip4_tcp_dport(); has_tcp = true; break; case 6: if(!pi.is_ip6_tcp()) { break; } tcp_src = pi.get_ip6_tcp_sport(); tcp_dst = pi.get_ip6_tcp_dport(); has_tcp = true; break; default: return; } if(!has_tcp) { packet_histogram.insert(pi.ts, 0, packet_length, time_histogram::F_NON_TCP); return; } // if either the TCP source or destination is a pre-colored port, submit that // port to the time histogram port_colormap_t::const_iterator tcp_src_color = port_colormap.find(tcp_src); port_colormap_t::const_iterator tcp_dst_color = port_colormap.find(tcp_dst); in_port_t packet_histogram_port = tcp_src; // if dst is colored and src isn't; use dst instead if(tcp_dst_color != port_colormap.end() && tcp_src_color == port_colormap.end()) { packet_histogram_port = tcp_dst; } // if both are colored, alternate src and dst else if(tcp_src_color != port_colormap.end() && tcp_dst_color != port_colormap.end() && packet_count % 2 == 0) { packet_histogram_port = tcp_dst; } // record that this port appears in the histogram for legend building purposes ports_in_time_histogram[packet_histogram_port] = true; packet_histogram.insert(pi.ts, packet_histogram_port, packet_length); src_port_histogram.increment(tcp_src, packet_length); dst_port_histogram.increment(tcp_dst, packet_length); } void one_page_report::render(const string &outdir) { string fname = outdir + "/" + filename; cairo_surface_t *surface = cairo_pdf_surface_create(fname.c_str(), bounds.width, bounds.height); cairo_t *cr = cairo_create(surface); // // Configure views // double pad_size = bounds.width * page_margin_factor; plot_view::bounds_t pad_bounds(bounds.x + pad_size, bounds.y + pad_size, bounds.width - pad_size * 2, bounds.height - pad_size * 2); // iff a colored common port appears in the time histogram, add its color to the legend if(ports_in_time_histogram[PORT_HTTP] || ports_in_time_histogram[PORT_HTTP_ALT_0] || ports_in_time_histogram[PORT_HTTP_ALT_1] || ports_in_time_histogram[PORT_HTTP_ALT_2] || ports_in_time_histogram[PORT_HTTP_ALT_3] || ports_in_time_histogram[PORT_HTTP_ALT_4] || ports_in_time_histogram[PORT_HTTP_ALT_5]) { color_labels.push_back(legend_view::entry_t(color_blue, "HTTP", PORT_HTTP)); } if(ports_in_time_histogram[PORT_HTTPS]) { color_labels.push_back(legend_view::entry_t(color_green, "HTTPS", PORT_HTTPS)); } if(ports_in_time_histogram[PORT_SSH]) { color_labels.push_back(legend_view::entry_t(color_purple, "SSH", PORT_SSH)); } if(ports_in_time_histogram[PORT_FTP_DATA] || ports_in_time_histogram[PORT_FTP_CONTROL]) { color_labels.push_back(legend_view::entry_t(color_red, "FTP", PORT_FTP_DATA)); } // assign the top 4 source ports colors if they don't already have them vector::const_iterator it = src_port_histogram.begin(); for(size_t count = 0; count < port_colors_count && it != src_port_histogram.end(); it++) { port_colormap_t::const_iterator color = port_colormap.find(it->port); if(color == port_colormap.end()) { string label = ssprintf(generic_legend_format.c_str(), it->port); switch(count) { case 0: if(ports_in_time_histogram[it->port]) { color_labels.push_back(legend_view::entry_t(color_orange, label, it->port)); } port_colormap[it->port] = color_orange; break; case 1: if(ports_in_time_histogram[it->port]) { color_labels.push_back(legend_view::entry_t(color_magenta, label, it->port)); } port_colormap[it->port] = color_magenta; break; case 2: if(ports_in_time_histogram[it->port]) { color_labels.push_back(legend_view::entry_t(color_deep_purple, label, it->port)); } port_colormap[it->port] = color_deep_purple; break; case 3: if(ports_in_time_histogram[it->port]) { color_labels.push_back(legend_view::entry_t(color_teal, label, it->port)); } port_colormap[it->port] = color_teal; break; default: break; } count++; } } sort(color_labels.begin(), color_labels.end()); // time histogram double condension_factor = (double) packet_histogram.non_sparse_size() / (double) max_bars; if(condension_factor > 1.1) { // condense only by whole numbers to avoid messing up bar labels packet_histogram.condense(((int) condension_factor) + 1); } time_histogram_view th_view(packet_histogram, port_colormap, default_color, cdf_color); // color legend legend_view lg_view(color_labels); // address histograms // histograms are built from iptree here address_histogram src_addr_histogram(src_tree); address_histogram dst_addr_histogram(dst_tree); address_histogram_view src_ah_view(src_addr_histogram); if(src_addr_histogram.size() > 0) { src_ah_view.title = "Top Source Addresses"; } else { src_ah_view.title = "No Source Addresses"; } src_ah_view.bar_color = default_color; src_ah_view.cdf_color = cdf_color; address_histogram_view dst_ah_view(dst_addr_histogram); if(dst_addr_histogram.size() > 0) { dst_ah_view.title = "Top Destination Addresses"; } else { dst_ah_view.title = "No Destination Addresses"; } dst_ah_view.bar_color = default_color; dst_ah_view.cdf_color = cdf_color; // port histograms port_histogram_view sp_view(src_port_histogram, port_colormap, default_color, cdf_color); port_histogram_view dp_view(dst_port_histogram, port_colormap, default_color, cdf_color); if(src_port_histogram.size()) { sp_view.title = "Top Source Ports"; } else { sp_view.title = "No Source Ports"; } if(dst_port_histogram.size()) { dp_view.title = "Top Destination Ports"; } else { dp_view.title = "No Destination Ports"; } // // run configured views through render pass // render_pass pass(*this, cr, pad_bounds); pass.render_header(); pass.render(th_view); pass.render(lg_view); if(getenv("DEBUG")) { pass.render_map(); pass.render_packetfall(); } pass.render(src_ah_view, dst_ah_view); pass.render(sp_view, dp_view); // cleanup cairo_destroy (cr); cairo_surface_destroy(surface); } void one_page_report::render_pass::render_header() { string formatted; // title double title_line_space = report.header_font_size * line_space_factor; //// version render_text_line(title_version, report.header_font_size, title_line_space); //// input formatted = ssprintf("Input: %s", report.source_identifier.c_str()); render_text_line(formatted.c_str(), report.header_font_size, title_line_space); //// date generated time_t gen_unix = time(0); struct tm gen_time = *localtime(&gen_unix); formatted = ssprintf("Generated: %04d-%02d-%02d %02d:%02d:%02d", 1900 + gen_time.tm_year, 1 + gen_time.tm_mon, gen_time.tm_mday, gen_time.tm_hour, gen_time.tm_min, gen_time.tm_sec); render_text_line(formatted.c_str(), report.header_font_size, title_line_space); //// trailing pad end_of_content += title_line_space * 4; // quick stats //// date range time_t tstart = report.earliest.tv_sec; struct tm start; memset(&start,0,sizeof(start)); localtime_r(&tstart,&start); time_t tstop = report.latest.tv_sec; struct tm stop; memset(&stop,0,sizeof(stop)); localtime_r(&tstop,&stop); formatted = ssprintf("Date range: %04d-%02d-%02d %02d:%02d:%02d -- %04d-%02d-%02d %02d:%02d:%02d", 1900 + start.tm_year, 1 + start.tm_mon, start.tm_mday, start.tm_hour, start.tm_min, start.tm_sec, 1900 + stop.tm_year, 1 + stop.tm_mon, stop.tm_mday, stop.tm_hour, stop.tm_min, stop.tm_sec); render_text_line(formatted.c_str(), report.header_font_size, title_line_space); //// packet count/size formatted = ssprintf("Packets analyzed: %s (%s)", comma_number_string(report.packet_count).c_str(), plot_view::pretty_byte_total(report.byte_count).c_str()); render_text_line(formatted.c_str(), report.header_font_size, title_line_space); //// protocol breakdown uint64_t transport_total = 0; for(map::const_iterator ii = report.transport_counts.begin(); ii != report.transport_counts.end(); ii++) { transport_total += ii->second; } stringstream ss; unsigned int percentage = 0; uint64_t classified_total = 0; ss << "Transports: "; if(transport_total > 0) { for(vector::const_iterator it = display_transports.begin(); it != display_transports.end(); it++) { uint64_t count = report.transport_counts[it->ethertype]; classified_total += count; percentage = (unsigned int) (((double) count / (double) transport_total) * 100.0); if(percentage > 0) { ss << it->name << " " << percentage << "% "; } } percentage = (unsigned int) (((double) (transport_total - classified_total) / transport_total) * 100.0); if(percentage > 0) { ss << "Other " << percentage << "% "; } } formatted = ss.str(); render_text_line(formatted.c_str(), report.header_font_size, title_line_space); // trailing pad for entire header end_of_content += title_line_space * 4; } void one_page_report::render_pass::render_text(string text, double font_size, double x_offset, cairo_text_extents_t &rendered_extents) { cairo_set_font_size(surface, font_size); cairo_set_source_rgb(surface, 0.0, 0.0, 0.0); cairo_text_extents(surface, text.c_str(), &rendered_extents); cairo_move_to(surface, surface_bounds.x + x_offset, surface_bounds.y + end_of_content + rendered_extents.height); cairo_show_text(surface, text.c_str()); } void one_page_report::render_pass::render_text_line(string text, double font_size, double line_space) { cairo_text_extents_t extents; render_text(text, font_size, 0.0, extents); end_of_content += extents.height + line_space; } void one_page_report::render_pass::render(time_histogram_view &view) { plot_view::bounds_t bnds(surface_bounds.x, surface_bounds.y + end_of_content, surface_bounds.width, packet_histogram_height); view.render(surface, bnds); end_of_content += bnds.height * histogram_pad_factor_y; } void one_page_report::render_pass::render_packetfall() { plot_view::bounds_t bnds(surface_bounds.x, surface_bounds.y + end_of_content, surface_bounds.width, packet_histogram_height); report.pfall.render(surface, bnds); end_of_content += bnds.height * histogram_pad_factor_y; } void one_page_report::render_pass::render_map() { plot_view::bounds_t bnds(surface_bounds.x, surface_bounds.y + end_of_content, surface_bounds.width, packet_histogram_height); report.netmap.render(surface, bnds); end_of_content += bnds.height * histogram_pad_factor_y; } void one_page_report::render_pass::render(address_histogram_view &left, address_histogram_view &right) { double width = surface_bounds.width / address_histogram_width_divisor; const address_histogram &left_data = left.get_data(); const address_histogram &right_data = right.get_data(); uint64_t total_datagrams = left_data.ingest_count(); plot_view::bounds_t left_bounds(surface_bounds.x, surface_bounds.y + end_of_content, width, address_histogram_height); left.render(surface, left_bounds); plot_view::bounds_t right_bounds(surface_bounds.x + (surface_bounds.width - width), surface_bounds.y + end_of_content, width, address_histogram_height); right.render(surface, right_bounds); end_of_content += max(left_bounds.height, right_bounds.height); // text stats string stat_line_format = "%d) %s - %s (%d%%)"; for(size_t ii = 0; ii < report.histogram_show_top_n_text; ii++) { cairo_text_extents_t left_extents, right_extents; if(left_data.size() > ii && left_data.at(ii).count > 0) { const iptree::addr_elem &addr = left_data.at(ii); uint8_t percentage = 0; percentage = (uint8_t) (((double) addr.count / (double) total_datagrams) * 100.0); string str = ssprintf(stat_line_format.c_str(), ii + 1, addr.str().c_str(), plot_view::pretty_byte_total(addr.count).c_str(), percentage); render_text(str.c_str(), report.top_list_font_size, left_bounds.x, left_extents); } if(right_data.size() > ii && right_data.at(ii).count > 0) { const iptree::addr_elem &addr = right_data.at(ii); uint8_t percentage = 0; percentage = (uint8_t) (((double) addr.count / (double) total_datagrams) * 100.0); string str = ssprintf(stat_line_format.c_str(), ii + 1, addr.str().c_str(), plot_view::pretty_byte_total(addr.count).c_str(), percentage); render_text(str.c_str(), report.top_list_font_size, right_bounds.x, right_extents); } if((left_data.size() > ii && left_data.at(ii).count > 0) || (right_data.size() > ii && right_data.at(ii).count > 0)) { end_of_content += max(left_extents.height, right_extents.height) * 1.5; } } end_of_content += max(left_bounds.height, right_bounds.height) * (histogram_pad_factor_y - 1.0); } void one_page_report::render_pass::render(port_histogram_view &left, port_histogram_view &right) { port_histogram &left_data = left.get_data(); port_histogram &right_data = right.get_data(); uint64_t total_bytes = left_data.ingest_count(); double width = surface_bounds.width / address_histogram_width_divisor; plot_view::bounds_t left_bounds(surface_bounds.x, surface_bounds.y + end_of_content, width, port_histogram_height); left.render(surface, left_bounds); plot_view::bounds_t right_bounds(surface_bounds.x + (surface_bounds.width - width), surface_bounds.y + end_of_content, width, port_histogram_height); right.render(surface, right_bounds); end_of_content += max(left_bounds.height, right_bounds.height); // text stats string stat_line_format = "%d) %d - %s (%d%%)"; for(size_t ii = 0; ii < report.histogram_show_top_n_text; ii++) { cairo_text_extents_t left_extents, right_extents; if(left_data.size() > ii && left_data.at(ii).count > 0) { port_histogram::port_count port = left_data.at(ii); uint8_t percentage = 0; percentage = (uint8_t) (((double) port.count / (double) total_bytes) * 100.0); string str = ssprintf(stat_line_format.c_str(), ii + 1, port.port, plot_view::pretty_byte_total(port.count).c_str(), percentage); render_text(str.c_str(), report.top_list_font_size, left_bounds.x, left_extents); } if(right_data.size() > ii && right_data.at(ii).count > 0) { port_histogram::port_count port = right_data.at(ii); uint8_t percentage = 0; percentage = (uint8_t) (((double) port.count / (double) total_bytes) * 100.0); string str = ssprintf(stat_line_format.c_str(), ii + 1, port.port, plot_view::pretty_byte_total(port.count).c_str(), percentage); render_text(str.c_str(), report.top_list_font_size, right_bounds.x, right_extents); } if((left_data.size() > ii && left_data.at(ii).count > 0) || (right_data.size() > ii && right_data.at(ii).count > 0)) { end_of_content += max(left_extents.height, right_extents.height) * 1.5; } } end_of_content += max(left_bounds.height, right_bounds.height) * (histogram_pad_factor_y - 1.0); } void one_page_report::render_pass::render(const legend_view &view) { plot_view::bounds_t view_bounds(surface_bounds.x, surface_bounds.y + end_of_content, surface_bounds.width, legend_height); view.render(surface, view_bounds); end_of_content += legend_height; } vector one_page_report::build_display_transports() { vector v; v.push_back(transport_type(ETHERTYPE_IP, "IPv4")); v.push_back(transport_type(ETHERTYPE_IPV6, "IPv6")); v.push_back(transport_type(ETHERTYPE_ARP, "ARP")); v.push_back(transport_type(ETHERTYPE_VLAN, "VLAN")); return v; } void one_page_report::dump(int dbg) { if(dbg){ std::cout << "src_tree:\n" << src_tree << "\n" << "dst_tree:\n" << dst_tree << "\n"; } } #endif tcpflow-tcpflow-1.6.1/src/netviz/one_page_report.h000066400000000000000000000106061401360461700223050ustar00rootroot00000000000000/** * one_page_report.h: * Show map of network traffic by host * * This source file is public domain, as it is not based on the original tcpflow. * * Author: Michael Shick * */ #ifndef ONE_PAGE_REPORT_H #define ONE_PAGE_REPORT_H #include "plot_view.h" #include "time_histogram.h" #include "time_histogram_view.h" #include "address_histogram.h" #include "address_histogram_view.h" #include "port_histogram.h" #include "port_histogram_view.h" #include "packetfall.h" #include "net_map.h" #include "iptree.h" #include "legend_view.h" class one_page_report { public: class transport_type { public: transport_type(uint16_t ethertype_, std::string name_) : ethertype(ethertype_), name(name_) {} uint16_t ethertype; std::string name; }; typedef std::map port_aliases_t; typedef std::map port_colormap_t; typedef std::vector transport_type_vector; std::string source_identifier; std::string filename; plot_view::bounds_t bounds; double header_font_size; double top_list_font_size; unsigned int histogram_show_top_n_text; // a single render event: content moves down a bounded cairo surface as // indicated by end_of_content between render method invocations class render_pass { public: render_pass(one_page_report &report_, cairo_t *surface_, const plot_view::bounds_t &bounds_) : report(report_), surface(surface_), surface_bounds(bounds_), end_of_content(0.0) {} void render_text_line(std::string text, double font_size, double line_space); void render_text(std::string text, double font_size, double x_offset, cairo_text_extents_t &rendered_extents); void render_header(); void render(time_histogram_view &view); void render(address_histogram_view &left, address_histogram_view &right); void render(port_histogram_view &left, port_histogram_view &right); void render(const legend_view &view); void render_map(); void render_packetfall(); one_page_report &report; cairo_t *surface; plot_view::bounds_t surface_bounds; double end_of_content; }; friend class render_pass; one_page_report(int max_histogram_size); void ingest_packet(const be13::packet_info &pi); void render(const std::string &outdir); plot_view::rgb_t port_color(uint16_t port) const; void dump(int debug); static transport_type_vector build_display_transports(); static const unsigned int max_bars; static const unsigned int port_colors_count; // string constants static const std::string title_version; static const std::string generic_legend_format; static const transport_type_vector display_transports; // ratio constants static const double page_margin_factor; static const double line_space_factor; static const double histogram_pad_factor_y; static const double address_histogram_width_divisor; // size constants static const double packet_histogram_height; static const double address_histogram_height; static const double port_histogram_height; static const double legend_height; // color constants static const plot_view::rgb_t default_color; static const plot_view::rgb_t color_orange; static const plot_view::rgb_t color_red; static const plot_view::rgb_t color_magenta; static const plot_view::rgb_t color_purple; static const plot_view::rgb_t color_deep_purple; static const plot_view::rgb_t color_blue; static const plot_view::rgb_t color_teal; static const plot_view::rgb_t color_green; static const plot_view::rgb_t color_yellow; static const plot_view::rgb_t color_light_orange; static const plot_view::rgb_t cdf_color; private: uint64_t packet_count; uint64_t byte_count; struct timeval earliest; struct timeval latest; std::map transport_counts; std::map ports_in_time_histogram; legend_view::entries_t color_labels; time_histogram packet_histogram; port_histogram src_port_histogram; port_histogram dst_port_histogram; packetfall pfall; net_map netmap; public: iptree src_tree; iptree dst_tree; port_aliases_t port_aliases; port_colormap_t port_colormap; }; #endif tcpflow-tcpflow-1.6.1/src/netviz/packetfall.cpp000066400000000000000000000020241401360461700215710ustar00rootroot00000000000000/** * packetfall.cpp: * Show packets received vs port * * This source file is public domain, as it is not based on the original tcpflow. * * Author: Michael Shick * */ #include "config.h" #ifdef HAVE_LIBCAIRO #include "tcpflow.h" #include "packetfall.h" void packetfall::ingest_packet(const be13::packet_info &pi) { } void packetfall::render(cairo_t *cr, const plot_view::bounds_t &bounds) { cairo_set_source_rgb(cr, 0.67, 0.67, 0.67); cairo_rectangle(cr, bounds.x, bounds.y, bounds.width, bounds.height); cairo_fill(cr); double font_size = 16.0; std::string label = "pretty packetfall"; cairo_text_extents_t extents; cairo_set_font_size(cr, font_size); cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); cairo_text_extents(cr, label.c_str(), &extents); double text_x = bounds.x + (bounds.width - extents.width) / 2.0; double text_y = bounds.y + (bounds.height + extents.height) / 2.0; cairo_move_to(cr, text_x, text_y); cairo_show_text(cr, label.c_str()); } #endif tcpflow-tcpflow-1.6.1/src/netviz/packetfall.h000066400000000000000000000006641401360461700212460ustar00rootroot00000000000000/** * packetfall.h: * Show packets received vs port * * This source file is public domain, as it is not based on the original tcpflow. * * Author: Michael Shick * */ #ifndef PACKETFALL_H #define PACKETFALL_H #include "plot_view.h" class packetfall { public: packetfall() {} void ingest_packet(const be13::packet_info &pi); void render(cairo_t *cr, const plot_view::bounds_t &bounds); }; #endif tcpflow-tcpflow-1.6.1/src/netviz/plot_view.cpp000066400000000000000000000314571401360461700215070ustar00rootroot00000000000000/** * plot_view.cpp: * Render titles, axes, and legends for various plots * * This source file is public domain, as it is not based on the original tcpflow. * * Author: Michael Shick * */ #include "config.h" #include "tcpflow.h" // for ssprintf #include "plot_view.h" #ifdef HAVE_LIBCAIRO #include const double plot_view::rgb_t::epsilon = 1.0 / 256.0; const double plot_view::text_line_base_width = 0.05; const double plot_view::span_arrow_angle = M_PI / 4.0; const double plot_view::span_stop_angle = M_PI / 2.0; const std::vector plot_view::size_suffixes = plot_view::build_size_suffixes(); void plot_view::render(cairo_t *cr, const plot_view::bounds_t &bounds) { cairo_matrix_t original_matrix; cairo_get_matrix(cr, &original_matrix); // purple background for padding checking //cairo_set_source_rgb(cr, 0.50, 0.00, 0.50); //cairo_rectangle(cr, bounds.x, bounds.y, bounds.width, bounds.height); //cairo_fill(cr); double pad_left = width * pad_left_factor; double pad_top = height * pad_top_factor; double pad_bottom = height * pad_bottom_factor; double pad_right = width * pad_right_factor; // compute bounds for subclasses to render content into bounds_t content_bounds; content_bounds.x = bounds.x + pad_left; content_bounds.y = bounds.y + pad_top; content_bounds.width = bounds.width - pad_right - pad_left; content_bounds.height = bounds.height - pad_bottom - pad_top; cairo_text_extents_t title_extents; cairo_text_extents_t subtitle_extents; double font_size_title = title_font_size; cairo_translate(cr, bounds.x, bounds.y); double title_base_y = 0.0; if(title_on_bottom) { title_base_y = bounds.height - pad_bottom; } cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); cairo_set_font_size(cr, font_size_title); cairo_set_source_rgb(cr, 0, 0, 0); cairo_text_extents(cr, title.c_str(), &title_extents); // Is the title too wide? double title_max_width = bounds.width * title_max_width_ratio; if(title_extents.width > title_max_width) { // scale the font size accordingly font_size_title *= title_max_width / title_extents.width; cairo_set_font_size(cr, font_size_title); cairo_text_extents(cr, title.c_str(), &title_extents); } // derive subtitle size and measure double font_size_subtitle = font_size_title * subtitle_font_size_factor; cairo_set_font_size(cr, font_size_subtitle); cairo_text_extents(cr, subtitle.c_str(), &subtitle_extents); double intertitle_padding = subtitle_extents.height * subtitle_y_pad_factor; cairo_set_font_size(cr, font_size_title); double title_padded_height = title_extents.height * title_y_pad_factor; // render title text cairo_move_to(cr, (bounds.width - title_extents.width) / 2.0, title_base_y + title_extents.height + (title_padded_height - title_extents.height) / 2); cairo_show_text(cr, title.c_str()); // render subtitle text cairo_set_font_size(cr, font_size_subtitle); cairo_move_to(cr, (bounds.width - subtitle_extents.width) / 2.0, title_base_y + ((title_padded_height - title_extents.height) / 2) + title_extents.height + intertitle_padding + subtitle_extents.height); cairo_show_text(cr, subtitle.c_str()); // render axis labels cairo_matrix_t unrotated_matrix; cairo_get_matrix(cr, &unrotated_matrix); cairo_text_extents_t axis_label_extents; cairo_set_font_size(cr, y_axis_font_size); cairo_text_extents(cr, y_label.c_str(), &axis_label_extents); double y_label_x = 0.0 + axis_label_extents.height; double y_label_centering_pad = ((content_bounds.height - axis_label_extents.width) / 2.0); double y_label_y = pad_top + y_label_centering_pad + axis_label_extents.width; cairo_move_to(cr, y_label_x, y_label_y); cairo_rotate(cr, -M_PI / 2.0); cairo_show_text(cr, y_label.c_str()); cairo_set_matrix(cr, &unrotated_matrix); // add y axis decoration // TODO not implemented for brevity cairo_set_font_size(cr, x_axis_font_size); cairo_text_extents(cr, x_label.c_str(), &axis_label_extents); double x_label_centering_pad = (content_bounds.width - axis_label_extents.width) / 2.0; double x_label_x = pad_left + x_label_centering_pad; double x_label_y = bounds.height; cairo_move_to(cr, x_label_x, x_label_y); cairo_show_text(cr, x_label.c_str()); // add x axis decoration if(x_axis_decoration == AXIS_SPAN_ARROW || x_axis_decoration == AXIS_SPAN_STOP) { double angle = span_arrow_angle; double line_width = x_axis_font_size * text_line_base_width; double tip_length = line_width * 10.0; if(x_axis_decoration == AXIS_SPAN_STOP) { angle = span_stop_angle; tip_length = line_width * 5.0; } double gap = line_width * 10.0; double x = x_label_x - gap; double y = x_label_y - axis_label_extents.height / 3.0; double pr_x, pr_y; // previous x and y positions // left of label cairo_move_to(cr, x, y); pr_x = x; pr_y = y; x = pr_x - (x_label_centering_pad - gap); y = pr_y; cairo_line_to(cr, x, y); pr_x = x; pr_y = y; x = pr_x + tip_length * sin(angle + M_PI / 2.0); y = pr_y + tip_length * cos(angle + M_PI / 2.0); cairo_line_to(cr, x, y); cairo_move_to(cr, pr_x, pr_y); x = pr_x + tip_length * sin(-angle + M_PI / 2.0); y = pr_y + tip_length * cos(-angle + M_PI / 2.0); cairo_line_to(cr, x, y); // right of label x = x_label_x + axis_label_extents.width + gap; y = x_label_y - axis_label_extents.height / 3.0; cairo_move_to(cr, x, y); pr_x = x; pr_y = y; x = pr_x + (x_label_centering_pad - gap); y = pr_y; cairo_line_to(cr, x, y); pr_x = x; pr_y = y; x = pr_x + tip_length * sin(angle - M_PI / 2.0); y = pr_y - tip_length * cos(angle - M_PI / 2.0); cairo_line_to(cr, x, y); cairo_move_to(cr, pr_x, pr_y); x = pr_x + tip_length * sin(-angle - M_PI / 2.0); y = pr_y - tip_length * cos(-angle - M_PI / 2.0); cairo_line_to(cr, x, y); cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); cairo_set_line_width(cr, line_width); cairo_stroke(cr); } // render ticks double tick_length = bounds.width * tick_length_factor; double tick_width = bounds.height * tick_width_factor; // y ticks (packet counts) cairo_set_font_size(cr, y_tick_font_size); // translate down so the top of the window aligns with the top of // the graph itself cairo_translate(cr, 0, pad_top); double y_height = bounds.height - pad_bottom - pad_top; double y_tick_spacing = 0.0; if(y_tick_labels.size() > 1) { y_tick_spacing = y_height / (double) (y_tick_labels.size() - 1); } for(size_t ii = 0; ii < y_tick_labels.size(); ii++) { cairo_text_extents_t label_extents; double yy = y_height - (((double) ii) * y_tick_spacing); std::string label = y_tick_labels.at(ii); cairo_text_extents(cr, label.c_str(), &label_extents); cairo_move_to(cr, (pad_left - tick_length - label_extents.width), yy + (label_extents.height / 2)); cairo_show_text(cr, label.c_str()); // tick mark cairo_rectangle(cr, pad_left - tick_length, yy - (tick_width / 2), tick_length, tick_width); cairo_fill(cr); } // right ticks (packet counts) cairo_set_font_size(cr, right_tick_font_size); if(right_tick_labels.size() > 1) { y_tick_spacing = y_height / (double) (right_tick_labels.size() - 1); } for(size_t ii = 0; ii < right_tick_labels.size(); ii++) { cairo_text_extents_t label_extents; double yy = y_height - (((double) ii) * y_tick_spacing); std::string label = right_tick_labels.at(ii); cairo_text_extents(cr, label.c_str(), &label_extents); cairo_move_to(cr, (bounds.width - pad_right + tick_length), yy + (label_extents.height / 2)); cairo_show_text(cr, label.c_str()); // tick mark cairo_rectangle(cr, bounds.width - pad_right, yy - (tick_width / 2), tick_length, tick_width); cairo_fill(cr); } cairo_set_matrix(cr, &original_matrix); cairo_translate(cr, bounds.x, bounds.y); // x ticks (time) // TODO prevent overlap cairo_set_font_size(cr, x_tick_font_size); cairo_translate(cr, pad_left, bounds.height - pad_bottom); double x_width = bounds.width - (pad_right + pad_left); double x_tick_spacing = x_width / (x_tick_labels.size() - 1); for(size_t ii = 0; ii < x_tick_labels.size(); ii++) { cairo_text_extents_t label_extents; double xx = ii * x_tick_spacing; const char *label = x_tick_labels.at(ii).c_str(); cairo_text_extents(cr, label, &label_extents); double pad = ((label_extents.height * x_tick_label_pad_factor) - label_extents.height) / 2; // prevent labels from running off the edge of the image double label_x = xx - (label_extents.width / 2.0); label_x = std::max(label_x, - pad_left); label_x = std::min(bounds.width - label_extents.width, label_x); cairo_move_to(cr, label_x, label_extents.height + pad); cairo_show_text(cr, label); } cairo_set_matrix(cr, &original_matrix); cairo_translate(cr, bounds.x, bounds.y); // render legend cairo_text_extents_t legend_label_extents; double chip_length = 0.0; // derive color chip size from largest label height for(size_t ii = 0; ii < legend.size(); ii++) { const legend_entry_t &entry = legend.at(ii); cairo_text_extents(cr, entry.label.c_str(), &legend_label_extents); chip_length = std::max(chip_length, legend_label_extents.height); } chip_length *= legend_chip_factor; cairo_translate(cr, bounds.width - (pad_right * 0.9), pad_top); cairo_set_font_size(cr, legend_font_size); for(size_t ii = 0; ii < legend.size(); ii++) { const legend_entry_t &entry = legend.at(ii); // chip cairo_set_source_rgb(cr, entry.color.r, entry.color.g, entry.color.b); cairo_rectangle(cr, 0, 0, chip_length, chip_length); cairo_fill(cr); // label cairo_set_source_rgb(cr, 0, 0, 0); cairo_text_extents(cr, entry.label.c_str(), &legend_label_extents); cairo_move_to(cr, chip_length * 1.2, (chip_length / 2.0) + (legend_label_extents.height / 2.0)); cairo_show_text(cr, entry.label.c_str()); // translate down for the next legend entry cairo_translate(cr, 0, chip_length); } cairo_set_source_rgb(cr, 0, 0, 0); cairo_set_matrix(cr, &original_matrix); // render axes and update content bounds double axis_width = bounds.height * axis_thickness_factor; cairo_rectangle(cr, content_bounds.x, content_bounds.y, axis_width, content_bounds.height); cairo_rectangle(cr, content_bounds.x, content_bounds.y + (content_bounds.height - axis_width), content_bounds.width, axis_width); // if there are right hand ticks, draw a right-hand axis if(right_tick_labels.size() > 0) { cairo_rectangle(cr, content_bounds.x + content_bounds.width - axis_width, content_bounds.y, axis_width, content_bounds.height); } cairo_fill(cr); content_bounds.x += axis_width; content_bounds.width -= axis_width; if(right_tick_labels.size() > 0) { content_bounds.width -= axis_width; } content_bounds.height -= axis_width; // render data! render_data(cr, content_bounds); } std::string plot_view::pretty_byte_total(uint64_t byte_count, uint8_t precision) { //// packet count/size uint64_t size_log_1000 = (uint64_t) (log(byte_count) / log(1000)); if(size_log_1000 >= size_suffixes.size()) { size_log_1000 = 0; } // only put decimal places if using a unit less granular than the byte (2.00 bytes looks silly) if(size_log_1000 == 0) { precision = 0; } return ssprintf("%.*f %sB", precision, (double) byte_count / pow(1000.0, (double) size_log_1000), size_suffixes.at(size_log_1000).c_str()); } std::string plot_view::pretty_byte_total(uint64_t byte_count) { return pretty_byte_total(byte_count, 2); } std::vector plot_view::build_size_suffixes() { std::vector v; v.push_back(""); v.push_back("K"); v.push_back("M"); v.push_back("G"); v.push_back("T"); v.push_back("P"); v.push_back("E"); return v; } #endif tcpflow-tcpflow-1.6.1/src/netviz/plot_view.h000066400000000000000000000122471401360461700211500ustar00rootroot00000000000000/** * plotview.h: * * This source file is public domain, as it is not based on the original tcpflow. * * Author: Michael Shick * */ #ifndef PLOT_VIEW_H #define PLOT_VIEW_H #ifdef HAVE_LIBCAIRO #ifdef HAVE_CAIRO_H #include #elif defined HAVE_CAIRO_CAIRO_H #include #endif #ifdef HAVE_CAIRO_PDF_H #include #elif defined HAVE_CAIRO_CAIRO_PDF_H #include #endif #include #include #include #ifndef M_PI #define M_PI 3.14159265358979323846 #endif class plot_view { public: plot_view() : title("graph of things"), subtitle("x vs y"), x_label("x axis"), y_label("y axis"), x_tick_labels(), y_tick_labels(), right_tick_labels(), legend(), width(161.803), height(100.000), title_on_bottom(false), title_font_size(8.0), x_axis_font_size(8.0), y_axis_font_size(8.0), title_max_width_ratio(0.8), title_y_pad_factor(2.0), subtitle_y_pad_factor(0.2), subtitle_font_size_factor(0.4), axis_thickness_factor(0.002), tick_length_factor(0.0124), tick_width_factor(0.002), x_tick_label_pad_factor(4.0), y_tick_label_pad_factor(2.0), right_tick_label_pad_factor(2.0), x_tick_font_size(3.0), y_tick_font_size(3.0), right_tick_font_size(3.0), pad_left_factor(0.148), pad_top_factor(0.2), pad_bottom_factor(0.2), pad_right_factor(0.148), legend_chip_factor(1.2), legend_font_size(2.5), x_axis_decoration(AXIS_NO_DECO), y_axis_decoration(AXIS_NO_DECO) {} typedef enum { AXIS_NO_DECO = 0, AXIS_SPAN_ARROW, AXIS_SPAN_STOP } axis_decoration_t; class rgb_t { public: rgb_t() : r(0.0), g(0.0), b(0.0) {} rgb_t(const double r_, const double g_, const double b_) : r(r_), g(g_), b(b_) {} double r; double g; double b; static const double epsilon; // 1/256.0 (not inline due to -Wgnu) }; class legend_entry_t { public: legend_entry_t(const rgb_t color_, const std::string label_) : color(color_), label(label_) {} rgb_t color; std::string label; }; class bounds_t { public: bounds_t() : x(0.0), y(0.0), width(0.0), height(0.0) {} bounds_t(const double x_, const double y_, const double width_, const double height_) : x(x_), y(y_), width(width_), height(height_) {} double x; double y; double width; double height; }; std::string title, subtitle; std::string x_label, y_label; std::vector x_tick_labels, y_tick_labels, right_tick_labels; std::vector legend; // width and height are in pt double width, height; bool title_on_bottom; double title_font_size; double x_axis_font_size, y_axis_font_size; // Title text will be shrunk if needed such that it takes up no more // than this ratio of the image width double title_max_width_ratio; // multiple of title height to be allocated above graph double title_y_pad_factor; // multiple of the subtitle height that will separate the subtitle from // the title double subtitle_y_pad_factor; // multiple of the title font size for the subtitle font size double subtitle_font_size_factor; // axis scale double axis_thickness_factor; // size of scale ticks, in pt double tick_length_factor, tick_width_factor; // multiple of label dummy text length to allocate for spacing double x_tick_label_pad_factor, y_tick_label_pad_factor, right_tick_label_pad_factor; double x_tick_font_size, y_tick_font_size, right_tick_font_size; // non-dynamic padding for the right and bottom of graph double pad_left_factor, pad_top_factor, pad_bottom_factor, pad_right_factor; // legend double legend_chip_factor; double legend_font_size; // axis decoration axis_decoration_t x_axis_decoration, y_axis_decoration; static const double text_line_base_width; static const double span_arrow_angle; static const double span_stop_angle; static const std::vector size_suffixes; virtual ~plot_view() = 0; // render everything common to all plots (everything but the data) void render(cairo_t *cr, const bounds_t &bounds); // called by render(); subclass-specific data rendering virtual void render_data(cairo_t *cr, const bounds_t &bounds) = 0; // format a byte count for humans ( 12 MB etc) static std::string pretty_byte_total(uint64_t byte_count, uint8_t precision); static std::string pretty_byte_total(uint64_t byte_count); static std::vector build_size_suffixes(); }; inline plot_view::~plot_view() {} inline bool operator==(const plot_view::rgb_t &a, const plot_view::rgb_t &b) { return fabs(a.r - b.r) < plot_view::rgb_t::epsilon && fabs(a.g - b.g) < plot_view::rgb_t::epsilon && fabs(a.b - b.b) < plot_view::rgb_t::epsilon; } inline bool operator!=(const plot_view::rgb_t &a, const plot_view::rgb_t &b) { return !(a == b); } inline bool operator<(const plot_view::rgb_t &a, const plot_view::rgb_t &b) { return a.r < b.r || a.g < b.g || a.b < b.b; } #endif #endif tcpflow-tcpflow-1.6.1/src/netviz/port_histogram.cpp000066400000000000000000000044331401360461700225320ustar00rootroot00000000000000/** * port_histogram.cpp: * Show packets received vs port * * This source file is public domain, as it is not based on the original tcpflow. * * Author: Michael Shick * */ #include "config.h" #ifdef HAVE_LIBCAIRO #include "tcpflow.h" #include "port_histogram.h" #include #include using namespace std; const size_t port_histogram::bucket_count = 10; bool port_histogram::descending_counts::operator()(const port_count &a, const port_count &b) { if(a.count > b.count) { return true; } if(a.count < b.count) { return false; } return a.port < b.port; } void port_histogram::increment(uint16_t port, uint64_t delta) { port_counts[port] += delta; data_bytes_ingested += delta; buckets_dirty = true; } const port_histogram::port_count &port_histogram::at(size_t index) { refresh_buckets(); return buckets.at(index); } size_t port_histogram::size() { refresh_buckets(); return buckets.size(); } uint64_t port_histogram::ingest_count() const { return data_bytes_ingested; } port_histogram::port_count_vector::const_iterator port_histogram::begin() { refresh_buckets(); return buckets.begin(); } port_histogram::port_count_vector::const_iterator port_histogram::end() { refresh_buckets(); return buckets.end(); } port_histogram::port_count_vector::const_reverse_iterator port_histogram::rbegin() { refresh_buckets(); return buckets.rbegin(); } port_histogram::port_count_vector::const_reverse_iterator port_histogram::rend() { refresh_buckets(); return buckets.rend(); } void port_histogram::refresh_buckets() { if(!buckets_dirty) { return; } buckets.clear(); for(port_counts_t::const_iterator it = port_counts.begin(); it != port_counts.end(); it++) { buckets.push_back(port_count(it->first, it->second)); } if(buckets.size() <= bucket_count) { sort(buckets.begin(), buckets.end(), descending_counts()); } else { partial_sort(buckets.begin(), buckets.begin() + bucket_count, buckets.end(), descending_counts()); } if(buckets.size() > bucket_count) { buckets.erase(buckets.begin() + bucket_count, buckets.end()); } buckets_dirty = false; } #endif tcpflow-tcpflow-1.6.1/src/netviz/port_histogram.h000066400000000000000000000025611401360461700221770ustar00rootroot00000000000000/** * port_histogram.h: * Show packets received vs port * * This source file is public domain, as it is not based on the original tcpflow. * * Author: Michael Shick * */ #ifndef PORT_HISTOGRAM_H #define PORT_HISTOGRAM_H class port_histogram { public: port_histogram() : port_counts(), data_bytes_ingested(0), buckets(), buckets_dirty(true) {} class port_count { public: port_count(uint16_t port_, uint64_t count_) : port(port_), count(count_) {} uint16_t port; uint64_t count; }; //typedef uint16_t port_t; class descending_counts { public: bool operator()(const port_count &a, const port_count &b); }; void increment(uint16_t port, uint64_t delta); const port_count &at(size_t index); size_t size(); uint64_t ingest_count() const; typedef std::vector port_count_vector; port_count_vector::const_iterator begin(); port_count_vector::const_iterator end(); port_count_vector::const_reverse_iterator rbegin(); port_count_vector::const_reverse_iterator rend(); static const size_t bucket_count; private: typedef std::map port_counts_t; port_counts_t port_counts; uint64_t data_bytes_ingested; std::vector buckets; bool buckets_dirty; void refresh_buckets(); }; #endif tcpflow-tcpflow-1.6.1/src/netviz/port_histogram_view.cpp000066400000000000000000000147271401360461700235730ustar00rootroot00000000000000/** * port_histogram_view.cpp: * Show packets received vs port * * This source file is public domain, as it is not based on the original tcpflow. * * Author: Michael Shick * */ #include "config.h" #ifdef HAVE_LIBCAIRO #include "tcpflow.h" #include "port_histogram_view.h" #include using namespace std; port_histogram_view::port_histogram_view(port_histogram &histogram_, const map &color_map_, const rgb_t &default_color_, const rgb_t &cdf_color_) : histogram(histogram_), color_map(color_map_), default_color(default_color_), cdf_color(cdf_color_) { subtitle = ""; title_on_bottom = true; pad_left_factor = 0.1; pad_right_factor = 0.1; x_label = ""; y_label = ""; y_tick_font_size = 6.0; right_tick_font_size = 6.0; } const double port_histogram_view::bar_space_factor = 1.2; const double port_histogram_view::bar_chip_size_factor = 0.04; const double port_histogram_view::cdf_line_width = 0.5; const double port_histogram_view::data_width_factor = 0.95; void port_histogram_view::render(cairo_t *cr, const plot_view::bounds_t &bounds) { y_tick_labels.push_back(plot_view::pretty_byte_total(0)); if(histogram.size() > 0) { y_tick_labels.push_back(plot_view::pretty_byte_total(histogram.at(0).count, 0)); } right_tick_labels.push_back("0%"); right_tick_labels.push_back("100%"); plot_view::render(cr, bounds); } void port_histogram_view::render_data(cairo_t *cr, const plot_view::bounds_t &bounds) { if(histogram.size() < 1 || histogram.at(0).count == 0) { return; } double data_width = bounds.width * data_width_factor; double data_offset = 0; bounds_t data_bounds(bounds.x + data_offset, bounds.y, data_width, bounds.height); double visibility_chip_height = data_bounds.height * bar_chip_size_factor; double offset_unit = data_bounds.width / histogram.size(); double bar_width = offset_unit / bar_space_factor; double space_width = (offset_unit - bar_width) / 2.0; uint64_t greatest = histogram.at(0).count; unsigned int index = 0; double cdf_last_x = bounds.x, cdf_last_y = bounds.y + data_bounds.height; for(vector::const_iterator it = histogram.begin(); it != histogram.end(); it++) { double bar_height = (((double) it->count) / ((double) greatest)) * data_bounds.height; // bar double bar_x = data_bounds.x + (index * offset_unit + space_width); double bar_y = data_bounds.y + (data_bounds.height - bar_height); bounds_t bar_bounds(bar_x, bar_y, bar_width, bar_height); rgb_t bar_color = default_color; map::const_iterator color = color_map.find(it->port); if(color != color_map.end()) { bar_color = color->second; } bucket_view view(*it, bar_color); if(bar_height < visibility_chip_height && bar_color != default_color) { view.chip_height = visibility_chip_height; view.chip_offset = visibility_chip_height * 0.6; } view.render(cr, bar_bounds); // CDF double cdf_x = cdf_last_x + offset_unit; // account for left and right padding of bars if(index == 0) { cdf_x += data_offset; } if(index == histogram.size() - 1) { cdf_x = bounds.x + bounds.width; } double cdf_y = cdf_last_y - ((double) it->count / (double) histogram.ingest_count()) * data_bounds.height; cairo_move_to(cr, cdf_last_x, cdf_last_y); // don't draw over the left-hand y axis if(index == 0) { cairo_move_to(cr, cdf_last_x, cdf_y); } else { cairo_line_to(cr, cdf_last_x, cdf_y); } cairo_line_to(cr, cdf_x, cdf_y); cairo_set_source_rgb(cr, cdf_color.r, cdf_color.g, cdf_color.b); cairo_set_line_width(cr, cdf_line_width); cairo_stroke(cr); cdf_last_x = cdf_x; cdf_last_y = cdf_y; index++; } index = 0; // labels must be done after the fact to avoid awkward interaction with the CDF for(vector::const_iterator it = histogram.begin(); it != histogram.end(); it++) { double bar_height = (((double) it->count) / ((double) greatest)) * data_bounds.height; double bar_x = data_bounds.x + (index * offset_unit + space_width); double bar_y = data_bounds.y + (data_bounds.height - bar_height); bounds_t bar_bounds(bar_x, bar_y, bar_width, bar_height); // bar label bucket_view view(*it, default_color); view.render_label(cr, bar_bounds); index++; } } port_histogram &port_histogram_view::get_data() { return histogram; } // bucket view const double port_histogram_view::bucket_view::label_font_size = 6.0; const double port_histogram_view::bucket_view::chip_width_factor = 0.4; void port_histogram_view::bucket_view::render(cairo_t *cr, const bounds_t &bounds) { cairo_set_source_rgb(cr, color.r, color.g, color.b); cairo_rectangle(cr, bounds.x, bounds.y, bounds.width, bounds.height); cairo_fill(cr); if(chip_height > 0.0) { double chip_x = bounds.x + (bounds.width * ((1.0 - chip_width_factor) / 2.0)); double chip_y = bounds.y + bounds.height + chip_offset; double chip_width = bounds.width * chip_width_factor; cairo_rectangle(cr, chip_x, chip_y, chip_width, chip_height); cairo_fill(cr); } } void port_histogram_view::bucket_view::render_label(cairo_t *cr, const bounds_t &bounds) { cairo_matrix_t unrotated_matrix; cairo_get_matrix(cr, &unrotated_matrix); cairo_rotate(cr, -M_PI / 4.0); cairo_set_font_size(cr, label_font_size); string label = ssprintf("%d", bucket.port); cairo_text_extents_t label_extents; cairo_text_extents(cr, label.c_str(), &label_extents); double label_x = bounds.x + bounds.width / 2.0; double label_y = bounds.y - 2.0; cairo_device_to_user(cr, &label_x, &label_y); cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); cairo_rectangle(cr, label_x, label_y, label_extents.width, -label_extents.height); cairo_fill(cr); cairo_rectangle(cr, label_x, label_y, label_extents.width, -label_extents.height); cairo_set_line_width(cr, 2.0); cairo_stroke(cr); cairo_move_to(cr, label_x, label_y); cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); cairo_show_text(cr, label.c_str()); cairo_set_matrix(cr, &unrotated_matrix); } #endif tcpflow-tcpflow-1.6.1/src/netviz/port_histogram_view.h000066400000000000000000000031111401360461700232210ustar00rootroot00000000000000/** * port_histogram_view.h: * * This source file is public domain, as it is not based on the original tcpflow. * * Author: Michael Shick * */ #ifndef PORT_HISTOGRAM_VIEW_H #define PORT_HISTOGRAM_VIEW_H #include "config.h" #ifdef HAVE_LIBCAIRO #include "plot_view.h" #include "port_histogram.h" class port_histogram_view : public plot_view { public: port_histogram_view(port_histogram &histogram_, const std::map &color_map_, const rgb_t &default_color, const rgb_t &cdf_color_); class bucket_view { public: bucket_view(const port_histogram::port_count &bucket_, const rgb_t &color_) : bucket(bucket_), color(color_), chip_height(0.0), chip_offset(0.0) {} const port_histogram::port_count &bucket; const rgb_t &color; double chip_height; double chip_offset; static const double label_font_size; static const double chip_width_factor; void render(cairo_t *cr, const bounds_t &bounds); void render_label(cairo_t *cr, const bounds_t &bounds); }; port_histogram &histogram; const std::map &color_map; const rgb_t &default_color; const rgb_t &cdf_color; static const double bar_space_factor; static const double bar_chip_size_factor; static const double cdf_line_width; static const double data_width_factor; void render(cairo_t *cr, const bounds_t &bounds); void render_data(cairo_t *cr, const bounds_t &bounds); port_histogram &get_data(); }; #endif #endif tcpflow-tcpflow-1.6.1/src/netviz/time_histogram.cpp000066400000000000000000000166751401360461700225170ustar00rootroot00000000000000/** * time_histogram.cpp: * organize packet count histograms of various granularities while transparently * exposing the best-fit * * This source file is public domain, as it is not based on the original tcpflow. * * Author: Michael Shick * */ #include #include "time_histogram.h" time_histogram::time_histogram() : histograms(), best_fit_index(0), earliest_ts(), latest_ts(), insert_count(0) { // zero value structs courtesy stackoverflow // http://stackoverflow.com/questions/6462093/reinitialize-timeval-struct earliest_ts = (struct timeval) { 0 }; latest_ts = (struct timeval) { 0 }; for(std::vector::const_iterator it = spans.begin(); it != spans.end(); it++) { histograms.push_back(histogram_map(*it)); } } const float time_histogram::underflow_pad_factor = 0.1; // spans dictates the granularities of each histogram. One histogram // will be created per entry in this vector. Each value must have a greater // value of seconds than the previous const std::vector time_histogram::spans = time_histogram::build_spans(); const time_histogram::bucket time_histogram::empty_bucket; // an empty bucket const unsigned int time_histogram::F_NON_TCP = 0x01; void time_histogram::insert(const struct timeval &ts, const in_port_t port, const uint64_t count, const unsigned int flags) { insert_count += count; if(earliest_ts.tv_sec == 0 || (ts.tv_sec < earliest_ts.tv_sec || (ts.tv_sec == earliest_ts.tv_sec && ts.tv_usec < earliest_ts.tv_usec))) { earliest_ts = ts; } if(ts.tv_sec > latest_ts.tv_sec || (ts.tv_sec == latest_ts.tv_sec && ts.tv_usec > latest_ts.tv_usec)) { latest_ts = ts; } for(std::vector::iterator it = histograms.begin() + best_fit_index; it != histograms.end(); it++) { bool overflowed = it->insert(ts, port, count, flags); // if there was an overflow and the best fit isn't already the least // granular histogram, downgrade granularity by one step if(overflowed && best_fit_index < histograms.size() - 1) { best_fit_index++; } } } // combine each bucket with (factor - 1) subsequent neighbors and increase bucket width by factor // lots of possible optimizations ignored for simplicity's sake void time_histogram::condense(double factor) { const histogram_map &original = histograms.at(best_fit_index); histogram_map condensed(span_params(original.span.usec, (uint64_t) ((double) original.span.bucket_count / factor))); for(histogram_map::buckets_t::const_iterator it = original.buckets.begin(); it != original.buckets.end(); it++) { bucket &bkt = *(it->second); uint64_t recons_usec = it->first * original.bucket_width + original.base_time; struct timeval reconstructed_ts; reconstructed_ts.tv_usec = (time_t) (recons_usec % (1000LL * 1000LL)); reconstructed_ts.tv_sec = (time_t) (recons_usec / (1000LL * 1000LL)); for(bucket::counts_t::const_iterator jt = bkt.counts.begin(); jt != bkt.counts.end(); jt++) { condensed.insert(reconstructed_ts, jt->first, jt->second); } condensed.insert(reconstructed_ts, 0, bkt.portless_count, F_NON_TCP); } histograms.at(best_fit_index) = condensed; } uint64_t time_histogram::usec_per_bucket() const { return histograms.at(best_fit_index).bucket_width; } uint64_t time_histogram::packet_count() const { return histograms.at(best_fit_index).insert_count; } time_t time_histogram::start_date() const { return earliest_ts.tv_sec; } time_t time_histogram::end_date() const { return latest_ts.tv_sec; } uint64_t time_histogram::tallest_bar() const { return histograms.at(best_fit_index).greatest_bucket_sum(); } const time_histogram::bucket &time_histogram::at(uint32_t index) const { const histogram_map::buckets_t hgram = histograms.at(best_fit_index).buckets; histogram_map::buckets_t::const_iterator bkt = hgram.find(index); if(bkt == hgram.end()) { return empty_bucket; } return *(bkt->second); } size_t time_histogram::size() const { return histograms.at(best_fit_index).buckets.size(); } // calculate the number of buckets if this were a non-sparse data structure like a vector size_t time_histogram::non_sparse_size() const { histogram_map::buckets_t buckets = histograms.at(best_fit_index).buckets; histogram_map::buckets_t::const_iterator least = buckets.begin(); if(least == buckets.end()) { return 0; } histogram_map::buckets_t::const_reverse_iterator most = buckets.rbegin(); return most->first - least->first + 1; } time_histogram::histogram_map::buckets_t::const_iterator time_histogram::begin() const { return histograms.at(best_fit_index).buckets.begin(); } time_histogram::histogram_map::buckets_t::const_iterator time_histogram::end() const { return histograms.at(best_fit_index).buckets.end(); } time_histogram::histogram_map::buckets_t::const_reverse_iterator time_histogram::rbegin() const { return histograms.at(best_fit_index).buckets.rbegin(); } time_histogram::histogram_map::buckets_t::const_reverse_iterator time_histogram::rend() const { return histograms.at(best_fit_index).buckets.rend(); } /* This should be rewritten, because currently it is building a bunch of spans and then returning a vector which has to be copied. * It's very inefficient. */ time_histogram::span_params_vector_t time_histogram::build_spans() { span_params_vector_t output; output.push_back(span_params( 1000LL * 1000LL * 60LL, // minute 600)); // 600 0.1 second buckets output.push_back(span_params( 1000LL * 1000LL * 60LL * 60LL, // hour 3600)); // 3,600 1 second buckets output.push_back(span_params( 1000LL * 1000LL * 60LL * 60LL * 24LL, // day 1440)); // 1,440 1 minute buckets output.push_back(span_params( 1000LL * 1000LL * 60LL * 60LL * 24LL * 7LL, // week 1008)); // 1,008 10 minute buckets output.push_back(span_params( 1000LL * 1000LL * 60LL * 60LL * 24LL * 30LL, // month 720)); // 720 1 hour buckets output.push_back(span_params( 1000LL * 1000LL * 60LL * 60LL * 24LL * 30LL * 12LL, // year 360)); // 360 1 day buckets output.push_back(span_params( 1000LL * 1000LL * 60LL * 60LL * 24LL * 3598LL, // approximate decade 514)); // 514 1 week buckets output.push_back(span_params( 1000LL * 1000LL * 60LL * 60LL * 24LL * 30LL * 12LL * 50LL, // semicentury 200)); // 200 3 month intervals return output; } /* * Insert into the time_histogram. * * This is optimized to be as fast as possible, so we compute the sums as necessary when generating the histogram. */ bool time_histogram::histogram_map::insert(const struct timeval &ts, const in_port_t port, const uint64_t count, const unsigned int flags) { uint32_t target_index = scale_timeval(ts); if(target_index >= span.bucket_count) { return true; // overflow; will cause this histogram to be shut down } buckets_t::iterator it = buckets.find(target_index); if(it==buckets.end()){ buckets[target_index] = new bucket(); } buckets[target_index]->increment(port, count, flags); insert_count += count; return false; } tcpflow-tcpflow-1.6.1/src/netviz/time_histogram.h000066400000000000000000000115061401360461700221500ustar00rootroot00000000000000/** * Interface for the timehistogram class * Currently this is a histogram that's specialized to create a stacked bar graph * with up to 2^16 different values on each bar. * * Times are stored as 64-bit microseconds since January 1, 1970 * * This source file is public domain, as it is not based on the original tcpflow. * * Author: Michael Shick * * History: * 2013-01-01 - Initial version by Mike Shick */ #ifndef TIME_HISTOGRAM_H #define TIME_HISTOGRAM_H #include "tcpflow.h" #include class time_histogram { public: time_histogram(); //typedef uint64_t count_t; // counts in a slot //typedef uint16_t port_t; // port number //typedef int32_t timescale_off_t; // ordinal offset within the histogram // parameter for...? class span_params { public: span_params(uint64_t usec_, uint64_t bucket_count_) : usec(usec_), bucket_count(bucket_count_) {} uint64_t usec; uint64_t bucket_count; }; typedef std::vector span_params_vector_t; // a bucket counts packets received in a given timeframe, organized by TCP port class bucket { public: typedef std::map counts_t; bucket() : counts(), portless_count(){}; uint64_t sum() const { /* this could be done with std::accumulate */ uint64_t count = 0; for(counts_t::const_iterator it=counts.begin();it!=counts.end();it++){ count += it->second; } count += portless_count; return count; }; counts_t counts; uint64_t portless_count; void increment(in_port_t port, uint64_t delta, unsigned int flags = 0x00) { if(flags & F_NON_TCP) { portless_count += delta; } else { counts[port] += delta; } } }; class histogram_map { public: typedef std::map buckets_t; buckets_t buckets; histogram_map(span_params span_) : buckets(), span(span_), bucket_width(span.usec / span.bucket_count), base_time(0), insert_count(0){} span_params span; uint64_t bucket_width; // in microseconds uint64_t base_time; // microseconds since Jan 1, 1970; set on first call to scale_timeval uint64_t insert_count; // of entire histogram uint64_t greatest_bucket_sum() const { uint64_t greatest = 0; for(buckets_t::const_iterator it = buckets.begin();it!=buckets.end();it++){ if(it->second->sum() > greatest) greatest = it->second->sum(); } return greatest; } /** convert timeval to a scaled time. */ uint32_t scale_timeval(const struct timeval &ts) { uint64_t raw_time = ts.tv_sec * (1000LL * 1000LL) + ts.tv_usec; if(base_time == 0) { base_time = raw_time - (bucket_width * ((uint64_t)(span.bucket_count * underflow_pad_factor))); // snap base time to nearest bucket_width to simplify bar labelling later uint64_t unit = span.usec / span.bucket_count; base_time = (base_time / unit) * unit; } if (raw_time < base_time) return -1; // underflow return (raw_time - base_time) / bucket_width; } // returns true if the insertion resulted in over/underflow bool insert(const struct timeval &ts, const in_port_t port, const uint64_t count = 1, const unsigned int flags = 0x00); }; void insert(const struct timeval &ts, const in_port_t port, const uint64_t count = 1, const unsigned int flags = 0x00); void condense(double factor); uint64_t usec_per_bucket() const; uint64_t packet_count() const; time_t start_date() const; time_t end_date() const; uint64_t tallest_bar() const; const bucket &at(uint32_t index) const; size_t size() const; size_t non_sparse_size() const; /* iterators for the buckets */ histogram_map::buckets_t::const_iterator begin() const; histogram_map::buckets_t::const_iterator end() const; histogram_map::buckets_t::const_reverse_iterator rbegin() const; histogram_map::buckets_t::const_reverse_iterator rend() const; static span_params_vector_t build_spans(); private: std::vector histograms; uint32_t best_fit_index; struct timeval earliest_ts, latest_ts; uint64_t insert_count; /** configuration: */ static const uint32_t bucket_count; static const float underflow_pad_factor; static const std::vector spans; // in microseconds static const bucket empty_bucket; public: static const unsigned int F_NON_TCP; }; #endif tcpflow-tcpflow-1.6.1/src/netviz/time_histogram_view.cpp000066400000000000000000000456721401360461700235500ustar00rootroot00000000000000/** * time_histogram_view.cpp: * Make fancy time histograms * * This source file is public domain, as it is not based on the original tcpflow. * * Author: Michael Shick * */ #include "config.h" #ifdef HAVE_LIBCAIRO #include "time_histogram_view.h" time_histogram_view::time_histogram_view(const time_histogram &histogram_, const colormap_t &port_colors_, const rgb_t &default_color_, const rgb_t &cdf_color_) : histogram(histogram_), port_colors(port_colors_), default_color(default_color_), cdf_color(cdf_color_), bar_time_unit(), bar_time_value(), bar_time_remainder() { title = ""; subtitle = ""; pad_left_factor = 0.2; pad_top_factor = 0.1; y_tick_font_size = 5.0; right_tick_font_size = 6.0; x_axis_font_size = 8.0; x_axis_decoration = plot_view::AXIS_SPAN_STOP; y_label = ""; } const uint8_t time_histogram_view::y_tick_count = 5; const double time_histogram_view::bar_space_factor = 1.2; const double time_histogram_view::cdf_line_width = 0.5; const std::vector time_histogram_view::time_units = time_histogram_view::build_time_units(); const std::vector time_histogram_view::si_prefixes = time_histogram_view::build_si_prefixes(); const double time_histogram_view::blank_bar_line_width = 0.25; const time_histogram_view::rgb_t time_histogram_view::blank_bar_line_color(0.0, 0.0, 0.0); const double time_histogram_view::bar_label_font_size = 6.0; const double time_histogram_view::bar_label_width_factor = 0.8; const time_histogram_view::rgb_t time_histogram_view::bar_label_normal_color(0.0, 0.0, 0.0); const time_histogram_view::rgb_t time_histogram_view::bar_label_highlight_color(0.86, 0.08, 0.24); void time_histogram_view::render(cairo_t *cr, const bounds_t &bounds) { // // create x label based on duration of capture // uint64_t bar_interval = histogram.usec_per_bucket() / (1000 * 1000); // add a second to duration; considering a partial second a second makes // edge cases look nicer time_t duration = histogram.end_date() - histogram.start_date() + 1; if(histogram.packet_count() == 0) { x_label = "no packets received"; x_axis_decoration = plot_view::AXIS_SPAN_STOP; } else { std::stringstream ss; // how long does is the total capture? if(duration < 1) { ss << "<1 second"; } else { // the total time is represented by the two (or one) coursest appropriate units // example: // 5 hours, 10 minutes // 58 seconds // but never: // 5 hours. 10 minutes, 30 seconds // break the duration down into its constituent parts std::vector duration_values; std::vector duration_names; int remainder = duration; for(std::vector::const_reverse_iterator it = time_units.rbegin(); it != time_units.rend(); it++) { duration_values.push_back(remainder / it->seconds); duration_names.push_back(it->name); remainder %= it->seconds; } int print_count = 0; // find how many time units are worth printing (for comma insertion) for(std::vector::const_iterator it = duration_values.begin(); it != duration_values.end(); it++) { if(*it > 0) { print_count++; } // if we've seen a nonzero unit, and now a zero unit, abort because skipping // a unit is weird (2 months, 1 second) else if(print_count > 0) { break; } } // work back through the values and print the two coursest nonzero print_count = std::min(print_count, 2); int printed = 0; for(size_t ii = 0; ii < time_units.size(); ii++) { std::string name = duration_names.at(ii); uint64_t value = duration_values.at(ii); // skip over insignificant units if(value == 0 && printed == 0) { continue; } printed++; // don't actually print intermediate zero values (no 3 hours, 0 minutes, 30 seconds) if(value > 0) { ss << value << " " << name; } if(value > 1) { ss << "s"; } if(printed < print_count) { ss << ", "; } if(printed == print_count) { break; } } } // how long does each bar represent? if(bar_interval < 1 && duration >= 1) { ss << " (<1 second intervals)"; } else if(bar_interval >= 1) { for(std::vector::const_iterator it = time_units.begin(); it != time_units.end(); it++) { if(it + 1 == time_units.end() || bar_interval < (it+1)->seconds) { bar_time_unit = it->name; bar_time_value = bar_interval / it->seconds; bar_time_remainder = bar_interval % it->seconds; break; } } ss << " ("; if(bar_time_remainder != 0) { ss << "~"; } ss << bar_time_value << " " << bar_time_unit << " intervals)"; } x_label = ss.str(); } // // choose y axis tick labels // // scale raw bucket totals uint8_t unit_log_1000 = (uint8_t) (log(histogram.tallest_bar()) / log(1000)); if(unit_log_1000 >= si_prefixes.size()) { unit_log_1000 = 0; } si_prefix unit = si_prefixes.at(unit_log_1000); double y_scale_range = histogram.tallest_bar() / (double) unit.magnitude; double y_scale_interval = y_scale_range / (y_tick_count - 1); uint64_t next_value = 0; for(int ii = 0; ii < y_tick_count; ii++) { uint64_t value = next_value; double next_raw_value = (ii + 1) * y_scale_interval; next_value = (uint64_t) floor(next_raw_value + 0.5); if(value == next_value && ii < y_tick_count - 1) { continue; } std::string label = ssprintf("%d %sB", value, unit.prefix.c_str()); y_tick_labels.push_back(label); } right_tick_labels.push_back("0%"); right_tick_labels.push_back("100%"); plot_view::render(cr, bounds); } void time_histogram_view::render_data(cairo_t *cr, const bounds_t &bounds) { size_t bars = histogram.non_sparse_size(); double bar_allocation = bounds.width / (double) bars; // bar width with spacing double bar_width = bar_allocation / bar_space_factor; // bar width as rendered double bar_leading_pad = (bar_allocation - bar_width) / 2.0; time_histogram::histogram_map::buckets_t::const_iterator it = histogram.begin(); if(it == histogram.end()) { return; } uint32_t first_offset = it->first; double tallest_bar = (double) histogram.tallest_bar(); for(; it != histogram.end(); it++) { double bar_height = (double) it->second->sum() / tallest_bar * bounds.height; double bar_x = bounds.x + (it->first - first_offset) * bar_allocation + bar_leading_pad; double bar_y = bounds.y + (bounds.height - bar_height); bounds_t bar_bounds(bar_x, bar_y, bar_width, bar_height); bucket_view bar(*it->second, port_colors, default_color); bar.render(cr, bar_bounds); } unsigned bar_label_numeric = 0; int distinct_label_count = 0; // choose initial bar value if(bar_time_unit.length() > 0) { time_t start = histogram.start_date(); struct tm start_time = *localtime(&start); if(bar_time_unit == SECOND_NAME) { bar_label_numeric = start_time.tm_sec; distinct_label_count = 60; } else if(bar_time_unit == MINUTE_NAME) { bar_label_numeric = start_time.tm_min; distinct_label_count = 60; } else if(bar_time_unit == HOUR_NAME) { bar_label_numeric = start_time.tm_hour; distinct_label_count = 24; } else if(bar_time_unit == DAY_NAME) { bar_label_numeric = start_time.tm_wday; distinct_label_count = 7; } else if(bar_time_unit == MONTH_NAME) { bar_label_numeric = start_time.tm_mon; distinct_label_count = 12; } else if(bar_time_unit == YEAR_NAME) { bar_label_numeric = start_time.tm_year; } // snap label to same alignment of histogram bars bar_label_numeric -= (bar_label_numeric % bar_time_value); } // create bar lables so an appropriate font size can be selected std::vector bar_labels; std::vector bar_label_colors; // if bars are thinner than 10pt, thin out the bar labels appropriately int label_every_n_bars = ((int) (10.0 / bar_allocation)) + 1; unsigned label_bars_offset = 0; // find the offset that will cause the '00' label to appear if(distinct_label_count > 0) { label_bars_offset = ((distinct_label_count - bar_label_numeric) % (bar_time_value * label_every_n_bars)) / bar_time_value; } bar_label_numeric += (label_bars_offset * bar_time_value); double widest_bar_label = 0; double tallest_bar_label = 0; cairo_set_font_size(cr, bar_label_font_size); for(size_t ii = 0; ii < bars; ii++) { if(ii % label_every_n_bars != label_bars_offset) { continue; } rgb_t bar_label_color; std::string bar_label = next_bar_label(bar_time_unit, bar_label_numeric, bar_time_value * label_every_n_bars, bar_label_color); cairo_text_extents_t label_extents; cairo_text_extents(cr, bar_label.c_str(), &label_extents); if(label_extents.width > widest_bar_label) { widest_bar_label = label_extents.width; } if(label_extents.height > tallest_bar_label) { tallest_bar_label = label_extents.height; } // add to list for later rendering bar_labels.push_back(bar_label); bar_label_colors.push_back(bar_label_color); } // don't let labels be wider than bars double safe_bar_label_font_size = bar_label_font_size; double bar_label_descent = tallest_bar_label * 1.75; double target_width = bar_width * bar_label_width_factor; if(widest_bar_label > target_width) { double factor = target_width / widest_bar_label; safe_bar_label_font_size *= factor; bar_label_descent *= factor; } // if we're skipping bars for labelling, increase the label size appropriately double label_size_multiplier = pow(1.2, (double) (label_every_n_bars - 1)); safe_bar_label_font_size *= label_size_multiplier; bar_label_descent *= label_size_multiplier; // CDF and bar labels double accumulator = 0.0; double histogram_sum = (double) histogram.packet_count(); cairo_move_to(cr, bounds.x, bounds.y + bounds.height); for(size_t ii = 0; ii < bars; ii++) { const time_histogram::bucket bkt = histogram.at(ii + first_offset); accumulator += (double) bkt.sum() / histogram_sum; double x = bounds.x + ii * bar_allocation; double next_x = x + bar_allocation; double y = bounds.y + (1.0 - accumulator) * bounds.height; // don't draw over the left-hand y axis if(ii == 0) { cairo_move_to(cr, x, y); } else { cairo_line_to(cr, x, y); } cairo_line_to(cr, next_x, y); // draw bar label if(bar_time_unit.length() > 0 && bar_time_remainder == 0 && ii % label_every_n_bars == label_bars_offset) { std::string label = bar_labels.at(ii / label_every_n_bars); rgb_t color = bar_label_colors.at(ii / label_every_n_bars); cairo_set_font_size(cr, safe_bar_label_font_size); cairo_set_source_rgb(cr, color.r, color.g, color.b); cairo_text_extents_t label_extents; cairo_text_extents(cr, label.c_str(), &label_extents); double label_x = x + ((bar_allocation - label_extents.width) / 2.0); double label_y = bounds.y + bounds.height + bar_label_descent; cairo_move_to(cr, label_x, label_y); cairo_show_text(cr, label.c_str()); // move back to appropriate place for next CDF step cairo_move_to(cr, next_x, y); } } cairo_set_source_rgb(cr, cdf_color.r, cdf_color.g, cdf_color.b); cairo_set_line_width(cr, cdf_line_width); cairo_stroke(cr); } // create a new bar label based on numeric_label, then increment numeric_label // by delta example: when invoked with ("day", 0, 2), "S" for sunday is // returned and numeric_label is updated to 2 which will return "T" for tuesday // next time std::string time_histogram_view::next_bar_label(const std::string &unit, unsigned &numeric_label, unsigned delta, rgb_t &label_color) { std::string output; if(numeric_label < delta) { label_color = bar_label_highlight_color; } else { label_color = bar_label_normal_color; } if(unit == SECOND_NAME || unit == MINUTE_NAME) { output = ssprintf("%02d", numeric_label); numeric_label = (numeric_label + delta) % 60; } else if(unit == HOUR_NAME) { output = ssprintf("%02d", numeric_label); numeric_label = (numeric_label + delta) % 24; } else if(unit == DAY_NAME) { label_color = bar_label_normal_color; switch(numeric_label) { case 6: case 0: label_color = bar_label_highlight_color; output = "S"; break; case 1: output = "M"; break; case 2: output = "T"; break; case 3: output = "W"; break; case 4: output = "R"; break; case 5: output = "F"; break; } numeric_label = (numeric_label + delta) % 7; } else if(unit == MONTH_NAME) { switch(numeric_label) { case 0: output = "Jan"; break; case 1: output = "Feb"; break; case 2: output = "Mar"; break; case 3: output = "Apr"; break; case 4: output = "May"; break; case 5: output = "Jun"; break; case 6: output = "Jul"; break; case 7: output = "Aug"; break; case 8: output = "Sep"; break; case 9: output = "Oct"; break; case 10: output = "Nov"; break; case 11: output = "Dec"; break; } numeric_label = (numeric_label + delta) % 12; } else if(unit == YEAR_NAME) { if(delta > 20) { output = ssprintf("%04d", numeric_label); } else { output = ssprintf("%02d", numeric_label % 100); } numeric_label = (numeric_label + delta); } return output; } std::vector time_histogram_view::build_time_units() { std::vector output; output.push_back(time_unit(SECOND_NAME, 1L)); output.push_back(time_unit(MINUTE_NAME, 60L)); output.push_back(time_unit(HOUR_NAME, 60L * 60L)); output.push_back(time_unit(DAY_NAME, 60L * 60L * 24L)); output.push_back(time_unit(WEEK_NAME, 60L * 60L * 24L * 7L)); output.push_back(time_unit(MONTH_NAME, 60L * 60L * 24L * 30L)); output.push_back(time_unit(YEAR_NAME, 60L * 60L * 24L * 360L)); return output; } std::vector time_histogram_view::build_si_prefixes() { std::vector output; output.push_back(si_prefix("", 1LL)); output.push_back(si_prefix("K", 1000LL)); output.push_back(si_prefix("M", 1000LL * 1000LL)); output.push_back(si_prefix("G", 1000LL * 1000LL * 1000LL)); output.push_back(si_prefix("T", 1000LL * 1000LL * 1000LL * 1000LL)); output.push_back(si_prefix("P", 1000LL * 1000LL * 1000LL * 1000LL * 1000LL)); output.push_back(si_prefix("E", 1000LL * 1000LL * 1000LL * 1000LL * 1000LL * 1000LL)); return output; } // bucket view void time_histogram_view::bucket_view::render(cairo_t *cr, const bounds_t &bounds) { // how far up the bar have we rendered so far? double total_height = bounds.y + bounds.height; // if multiple sections of the same color follow, simply accumulate their height double height_accumulator = 0.0; rgb_t next_color = default_color; // The loop below is a bit confusing for(time_histogram::bucket::counts_t::const_iterator it = bucket.counts.begin(); it != bucket.counts.end();) { double height = bounds.height * ((double) it->second / (double) bucket.sum()); // on first section, preload the first color as the 'next' color if(it == bucket.counts.begin()) { colormap_t::const_iterator color_pair = color_map.find(it->first); if(color_pair != color_map.end()) { next_color = color_pair->second; } } // advance to the next color rgb_t color = next_color; next_color = default_color; // if there's a next bucket, get its color for the next color // next consolidate this section with the next if the colors match it++; if(it != bucket.counts.end()) { /* This gets after every bar except the last bar */ colormap_t::const_iterator color_pair = color_map.find(it->first); if(color_pair != color_map.end()) { next_color = color_pair->second; } if(color == next_color) { height_accumulator += height; continue; } } /* this gets run after every bar */ cairo_set_source_rgb(cr, color.r, color.g, color.b); // account for consolidated sections height += height_accumulator; height_accumulator = 0.0; cairo_rectangle(cr, bounds.x, total_height - height, bounds.width, height); cairo_fill(cr); total_height -= height; } // non-TCP packets if(bucket.portless_count > 0) { double height = bounds.height * ((double) bucket.portless_count / (double) bucket.sum()); cairo_set_source_rgb(cr, blank_bar_line_color.r, blank_bar_line_color.g, blank_bar_line_color.b); double offset = blank_bar_line_width / 2; cairo_set_line_width(cr, blank_bar_line_width); cairo_rectangle(cr, bounds.x + offset, total_height - height + offset, bounds.width - blank_bar_line_width, height - blank_bar_line_width); cairo_stroke(cr); } } #endif tcpflow-tcpflow-1.6.1/src/netviz/time_histogram_view.h000066400000000000000000000056031401360461700232030ustar00rootroot00000000000000/** * time_histogram_view.h: * Make fancy time histograms * * This source file is public domain, as it is not based on the original tcpflow. * * Author: Michael Shick * */ #ifndef TIME_HISTOGRAM_VIEW_H #define TIME_HISTOGRAM_VIEW_H #include "config.h" #ifdef HAVE_LIBCAIRO #include "plot_view.h" #include "time_histogram.h" #define SECOND_NAME "second" #define MINUTE_NAME "minute" #define HOUR_NAME "hour" #define DAY_NAME "day" #define WEEK_NAME "week" #define MONTH_NAME "month" #define YEAR_NAME "year" class time_histogram_view : public plot_view { public: typedef std::map colormap_t; time_histogram_view(const time_histogram &histogram_, const colormap_t &port_colors_, const rgb_t &default_color_, const rgb_t &cdf_color_); class time_unit { public: time_unit(std::string name_, uint64_t seconds_) : name(name_), seconds(seconds_) {} std::string name; uint64_t seconds; }; class si_prefix { public: si_prefix(std::string prefix_, uint64_t magnitude_) : prefix(prefix_), magnitude(magnitude_) {} std::string prefix; uint64_t magnitude; }; class bucket_view { public: bucket_view(const time_histogram::bucket &bucket_, const colormap_t &color_map_, const rgb_t &default_color_) : bucket(bucket_), color_map(color_map_), default_color(default_color_) {} const time_histogram::bucket &bucket; const colormap_t &color_map; const rgb_t &default_color; void render(cairo_t *cr, const bounds_t &bounds); }; const time_histogram &histogram; const colormap_t port_colors; const rgb_t default_color; const rgb_t cdf_color; static const uint8_t y_tick_count; static const double bar_space_factor; static const double cdf_line_width; static const std::vector time_units; static const std::vector si_prefixes; static const double blank_bar_line_width; static const rgb_t blank_bar_line_color; static const double bar_label_font_size; static const double bar_label_width_factor; static const rgb_t bar_label_normal_color; static const rgb_t bar_label_highlight_color; void render(cairo_t *cr, const bounds_t &bounds); void render_data(cairo_t *cr, const bounds_t &bounds); static std::string next_bar_label(const std::string &unit, unsigned &numeric_label, unsigned delta, rgb_t &label_color); private: // for labelling purposes, a bar is s wide std::string bar_time_unit; uint32_t bar_time_value; // if the bar time unit isn't exact, we can't label bars because they'll drift uint32_t bar_time_remainder; static std::vector build_time_units(); static std::vector build_si_prefixes(); }; #endif #endif tcpflow-tcpflow-1.6.1/src/pcap_writer.h000066400000000000000000000067461401360461700201470ustar00rootroot00000000000000/* * pcap_writer.h: * * A class for writing pcap files */ #ifndef HAVE_PCAP_WRITER_H #define HAVE_PCAP_WRITER_H class pcap_writer { /* These are not implemented */ pcap_writer &operator=(const pcap_writer &that); pcap_writer(const pcap_writer &t); class write_error: public std::exception { virtual const char *what() const throw() { return "write error in pcap_write"; } }; enum {PCAP_RECORD_HEADER_SIZE = 16, PCAP_MAX_PKT_LEN = 65535, // wire shark may reject larger PCAP_HEADER_SIZE = 4+2+2+4+4+4+4, }; FILE *fcap; // where file is written void write_bytes(const uint8_t * const val, size_t num_bytes) { size_t count = fwrite(val,1,num_bytes,fcap); if (count != num_bytes) throw new write_error(); } void write2(const uint16_t val) { size_t count = fwrite(&val,1,2,fcap); if (count != 2) throw new write_error(); } void write4(const uint32_t val) { size_t count = fwrite(&val,1,4,fcap); if (count != 4) throw new write_error(); } void open(const std::string &fname) { fcap = fopen(fname.c_str(),"wb"); // write the output if(fcap==0) throw new write_error(); } void write_header(const int pcap_dlt){ write4(0xa1b2c3d4); write2(2); // major version number write2(4); // minor version number write4(0); // time zone offset; always 0 write4(0); // accuracy of time stamps in the file; always 0 write4(PCAP_MAX_PKT_LEN); // snapshot length write4(pcap_dlt); // link layer encapsulation } void copy_header(const std::string &ifname){ /* assert byte order is correct */ FILE *f2 = fopen(ifname.c_str(),"rb"); if(f2==0) throw new write_error(); u_char buf[PCAP_HEADER_SIZE]; if(fread(buf,1,sizeof(buf),f2)!=sizeof(buf)) throw new write_error(); if((buf[0]!=0xd4) || (buf[1]!=0xc3) || (buf[2]!=0xb2) || (buf[3]!=0xa1)){ std::cout << "pcap file " << ifname << " is in wrong byte order. Cannot continue.\n"; throw new write_error(); } if(fwrite(buf,1,sizeof(buf),fcap)!=sizeof(buf)) throw new write_error(); if(fclose(f2)!=0) throw new write_error(); } public: pcap_writer():fcap(0){} static pcap_writer *open_new(const std::string &ofname){ pcap_writer *pcw = new pcap_writer(); pcw->open(ofname); pcw->write_header(DLT_EN10MB); // static for temporary regression return pcw; } static pcap_writer *open_copy(const std::string &ofname,const std::string &ifname){ pcap_writer *pcw = new pcap_writer(); pcw->open(ofname); pcw->copy_header(ifname); return pcw; } virtual ~pcap_writer(){ if(fcap) fclose(fcap); } void writepkt(const struct pcap_pkthdr *h,const u_char *p) { /* Write a packet */ write4(h->ts.tv_sec); // time stamp, seconds avalue write4(h->ts.tv_usec); // time stamp, microseconds write4(h->caplen); write4(h->len); size_t count = fwrite(p,1,h->caplen,fcap); // the packet if(count!=h->caplen) throw new write_error(); } void refresh_sink(const std::string &fname, const int pcap_dlt) { open(fname); write_header(pcap_dlt); } void update_sink(FILE *sink) { fcap = sink; } FILE* yield_sink() { return fcap; } }; #endif tcpflow-tcpflow-1.6.1/src/radiotap_old.c000066400000000000000000000367631401360461700202660ustar00rootroot00000000000000/* * Radiotap parser * * Copyright 2007 Andy Green * Copyright 2009 Johannes Berg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See COPYING for more details. */ /** COPYING FOLLOWS */ /* Copyright (c) 2007-2009 Andy Green Copyright (c) 2007-2009 Johannes Berg Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #ifndef __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS #endif #include #include #include #include "radiotap_iter.h" static uint16_t get_unaligned_le16(const uint8_t *b) { return b[0] | (b[1]<<8); } static uint32_t get_unaligned_le32(const uint8_t *b) { return b[0] | (b[1]<<8) | (b[2]<<16) | (b[3]<<24); } /* function prototypes and related defs are in radiotap_iter.h */ static const struct radiotap_align_size rtap_namespace_sizes[] = { [IEEE80211_RADIOTAP_TSFT] = { .align = 8, .size = 8, }, [IEEE80211_RADIOTAP_FLAGS] = { .align = 1, .size = 1, }, [IEEE80211_RADIOTAP_RATE] = { .align = 1, .size = 1, }, [IEEE80211_RADIOTAP_CHANNEL] = { .align = 2, .size = 4, }, [IEEE80211_RADIOTAP_FHSS] = { .align = 2, .size = 2, }, [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = { .align = 1, .size = 1, }, [IEEE80211_RADIOTAP_DBM_ANTNOISE] = { .align = 1, .size = 1, }, [IEEE80211_RADIOTAP_LOCK_QUALITY] = { .align = 2, .size = 2, }, [IEEE80211_RADIOTAP_TX_ATTENUATION] = { .align = 2, .size = 2, }, [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = { .align = 2, .size = 2, }, [IEEE80211_RADIOTAP_DBM_TX_POWER] = { .align = 1, .size = 1, }, [IEEE80211_RADIOTAP_ANTENNA] = { .align = 1, .size = 1, }, [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = { .align = 1, .size = 1, }, [IEEE80211_RADIOTAP_DB_ANTNOISE] = { .align = 1, .size = 1, }, [IEEE80211_RADIOTAP_RX_FLAGS] = { .align = 2, .size = 2, }, [IEEE80211_RADIOTAP_TX_FLAGS] = { .align = 2, .size = 2, }, [IEEE80211_RADIOTAP_RTS_RETRIES] = { .align = 1, .size = 1, }, [IEEE80211_RADIOTAP_DATA_RETRIES] = { .align = 1, .size = 1, }, [IEEE80211_RADIOTAP_MCS] = { .align = 1, .size = 3, }, [IEEE80211_RADIOTAP_AMPDU_STATUS] = { .align = 4, .size = 8, }, /* * add more here as they are defined in radiotap.h */ }; static const struct ieee80211_radiotap_namespace radiotap_ns = { .n_bits = sizeof(rtap_namespace_sizes) / sizeof(rtap_namespace_sizes[0]), .align_size = rtap_namespace_sizes, }; /** * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization * @iterator: radiotap_iterator to initialize * @radiotap_header: radiotap header to parse * @max_length: total length we can parse into (eg, whole packet length) * * Returns: 0 or a negative error code if there is a problem. * * This function initializes an opaque iterator struct which can then * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap * argument which is present in the header. It knows about extended * present headers and handles them. * * How to use: * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator * struct ieee80211_radiotap_iterator (no need to init the struct beforehand) * checking for a good 0 return code. Then loop calling * __ieee80211_radiotap_iterator_next()... it returns either 0, * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem. * The iterator's @this_arg member points to the start of the argument * associated with the current argument index that is present, which can be * found in the iterator's @this_arg_index member. This arg index corresponds * to the IEEE80211_RADIOTAP_... defines. * * Radiotap header length: * You can find the CPU-endian total radiotap header length in * iterator->max_length after executing ieee80211_radiotap_iterator_init() * successfully. * * Alignment Gotcha: * You must take care when dereferencing iterator.this_arg * for multibyte types... the pointer is not aligned. Use * get_unaligned((type *)iterator.this_arg) to dereference * iterator.this_arg for type "type" safely on all arches. * * Example code: parse.c */ int ieee80211_radiotap_iterator_init( struct ieee80211_radiotap_iterator *iterator, struct ieee80211_radiotap_header *radiotap_header, int max_length, const struct ieee80211_radiotap_vendor_namespaces *vns) { /* Linux only supports version 0 radiotap format */ if (radiotap_header->it_version) return -EINVAL; /* sanity check for allowed length and radiotap length field */ if (max_length < get_unaligned_le16((const uint8_t *)&radiotap_header->it_len)) return -EINVAL; iterator->_rtheader = radiotap_header; iterator->_max_length = get_unaligned_le16((const uint8_t *)&radiotap_header->it_len); iterator->_arg_index = 0; iterator->_bitmap_shifter = get_unaligned_le32((const uint8_t *)&radiotap_header->it_present); iterator->_arg = (uint8_t *)radiotap_header + sizeof(*radiotap_header); iterator->_reset_on_ext = 0; iterator->_next_bitmap = &radiotap_header->it_present; iterator->_next_bitmap++; iterator->_vns = vns; iterator->current_namespace = &radiotap_ns; iterator->is_radiotap_ns = 1; #ifdef RADIOTAP_SUPPORT_OVERRIDES iterator->n_overrides = 0; iterator->overrides = NULL; #endif /* find payload start allowing for extended bitmap(s) */ if (iterator->_bitmap_shifter & (1<_arg) & (1 << IEEE80211_RADIOTAP_EXT)) { iterator->_arg += sizeof(uint32_t); /* * check for insanity where the present bitmaps * keep claiming to extend up to or even beyond the * stated radiotap header length */ if ((unsigned long)iterator->_arg - (unsigned long)iterator->_rtheader > (unsigned long)iterator->_max_length) return -EINVAL; } iterator->_arg += sizeof(uint32_t); /* * no need to check again for blowing past stated radiotap * header length, because ieee80211_radiotap_iterator_next * checks it before it is dereferenced */ } iterator->this_arg = iterator->_arg; /* we are all initialized happily */ return 0; } static void find_ns(struct ieee80211_radiotap_iterator *iterator, uint32_t oui, uint8_t subns) { int i; iterator->current_namespace = NULL; if (!iterator->_vns) return; for (i = 0; i < iterator->_vns->n_ns; i++) { if (iterator->_vns->ns[i].oui != oui) continue; if (iterator->_vns->ns[i].subns != subns) continue; iterator->current_namespace = &iterator->_vns->ns[i]; break; } } #ifdef RADIOTAP_SUPPORT_OVERRIDES static int find_override(struct ieee80211_radiotap_iterator *iterator, int *align, int *size) { int i; if (!iterator->overrides) return 0; for (i = 0; i < iterator->n_overrides; i++) { if (iterator->_arg_index == iterator->overrides[i].field) { *align = iterator->overrides[i].align; *size = iterator->overrides[i].size; if (!*align) /* erroneous override */ return 0; return 1; } } return 0; } #endif /** * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg * @iterator: radiotap_iterator to move to next arg (if any) * * Returns: 0 if there is an argument to handle, * -ENOENT if there are no more args or -EINVAL * if there is something else wrong. * * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*) * in @this_arg_index and sets @this_arg to point to the * payload for the field. It takes care of alignment handling and extended * present fields. @this_arg can be changed by the caller (eg, * incremented to move inside a compound argument like * IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in * little-endian format whatever the endianess of your CPU. * * Alignment Gotcha: * You must take care when dereferencing iterator.this_arg * for multibyte types... the pointer is not aligned. Use * get_unaligned((type *)iterator.this_arg) to dereference * iterator.this_arg for type "type" safely on all arches. */ int ieee80211_radiotap_iterator_next( struct ieee80211_radiotap_iterator *iterator) { while (1) { int hit = 0; int pad, align, size, subns; uint32_t oui; /* if no more EXT bits, that's it */ if ((iterator->_arg_index % 32) == IEEE80211_RADIOTAP_EXT && !(iterator->_bitmap_shifter & 1)) return -ENOENT; if (!(iterator->_bitmap_shifter & 1)) goto next_entry; /* arg not present */ /* get alignment/size of data */ switch (iterator->_arg_index % 32) { case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE: case IEEE80211_RADIOTAP_EXT: align = 1; size = 0; break; case IEEE80211_RADIOTAP_VENDOR_NAMESPACE: align = 2; size = 6; break; default: #ifdef RADIOTAP_SUPPORT_OVERRIDES if (find_override(iterator, &align, &size)) { /* all set */ } else #endif if (!iterator->current_namespace || iterator->_arg_index >= iterator->current_namespace->n_bits) { if (iterator->current_namespace == &radiotap_ns) return -ENOENT; align = 0; } else { align = iterator->current_namespace->align_size[iterator->_arg_index].align; size = iterator->current_namespace->align_size[iterator->_arg_index].size; } if (!align) { /* skip all subsequent data */ iterator->_arg = iterator->_next_ns_data; /* give up on this namespace */ iterator->current_namespace = NULL; goto next_entry; } break; } /* * arg is present, account for alignment padding * * Note that these alignments are relative to the start * of the radiotap header. There is no guarantee * that the radiotap header itself is aligned on any * kind of boundary. * * The above is why get_unaligned() is used to dereference * multibyte elements from the radiotap area. */ pad = ((unsigned long)iterator->_arg - (unsigned long)iterator->_rtheader) & (align - 1); if (pad) iterator->_arg += align - pad; if (iterator->_arg_index % 32 == IEEE80211_RADIOTAP_VENDOR_NAMESPACE) { int vnslen; if ((unsigned long)iterator->_arg + size - (unsigned long)iterator->_rtheader > (unsigned long)iterator->_max_length) return -EINVAL; oui = (*iterator->_arg << 16) | (*(iterator->_arg + 1) << 8) | *(iterator->_arg + 2); subns = *(iterator->_arg + 3); find_ns(iterator, oui, subns); vnslen = get_unaligned_le16(iterator->_arg + 4); iterator->_next_ns_data = iterator->_arg + size + vnslen; if (!iterator->current_namespace) size += vnslen; } /* * this is what we will return to user, but we need to * move on first so next call has something fresh to test */ iterator->this_arg_index = iterator->_arg_index; iterator->this_arg = iterator->_arg; iterator->this_arg_size = size; /* internally move on the size of this arg */ iterator->_arg += size; /* * check for insanity where we are given a bitmap that * claims to have more arg content than the length of the * radiotap section. We will normally end up equalling this * max_length on the last arg, never exceeding it. */ if ((unsigned long)iterator->_arg - (unsigned long)iterator->_rtheader > (unsigned long)iterator->_max_length) return -EINVAL; /* these special ones are valid in each bitmap word */ switch (iterator->_arg_index % 32) { case IEEE80211_RADIOTAP_VENDOR_NAMESPACE: iterator->_reset_on_ext = 1; iterator->is_radiotap_ns = 0; /* * If parser didn't register this vendor * namespace with us, allow it to show it * as 'raw. Do do that, set argument index * to vendor namespace. */ iterator->this_arg_index = IEEE80211_RADIOTAP_VENDOR_NAMESPACE; if (!iterator->current_namespace) hit = 1; goto next_entry; case IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE: iterator->_reset_on_ext = 1; iterator->current_namespace = &radiotap_ns; iterator->is_radiotap_ns = 1; goto next_entry; case IEEE80211_RADIOTAP_EXT: /* * bit 31 was set, there is more * -- move to next u32 bitmap */ iterator->_bitmap_shifter = get_unaligned_le32((const uint8_t *)iterator->_next_bitmap); iterator->_next_bitmap++; if (iterator->_reset_on_ext) iterator->_arg_index = 0; else iterator->_arg_index++; iterator->_reset_on_ext = 0; break; default: /* we've got a hit! */ hit = 1; next_entry: iterator->_bitmap_shifter >>= 1; iterator->_arg_index++; } /* if we found a valid arg earlier, return it now */ if (hit) return 0; } } /**************************************************************** ** this code from parse.c ****************************************************************/ static const struct radiotap_align_size align_size_000000_00[] = { [0] = { .align = 1, .size = 4, }, [52] = { .align = 1, .size = 4, }, }; const struct ieee80211_radiotap_namespace vns_array[] = { { .oui = 0x000000, .subns = 0, .n_bits = sizeof(align_size_000000_00), .align_size = align_size_000000_00, }, }; const struct ieee80211_radiotap_vendor_namespaces radiotap_vns = { .ns = vns_array, .n_ns = sizeof(vns_array)/sizeof(vns_array[0]), }; /* Need to create these */ #define le64toh(x) (x) #define le32toh(x) (x) #define le16toh(x) (x) static int fcshdr = 0; void print_radiotap_namespace(struct ieee80211_radiotap_iterator *iter) { switch (iter->this_arg_index) { case IEEE80211_RADIOTAP_TSFT: printf("\tTSFT: %"PRIu64"\n", le64toh(*(unsigned long long *)iter->this_arg)); break; case IEEE80211_RADIOTAP_FLAGS: printf("\tflags: %02x\n", *iter->this_arg); break; case IEEE80211_RADIOTAP_RATE: printf("\trate: %lf\n", (double)*iter->this_arg/2); break; case IEEE80211_RADIOTAP_CHANNEL: case IEEE80211_RADIOTAP_FHSS: case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: case IEEE80211_RADIOTAP_DBM_ANTNOISE: case IEEE80211_RADIOTAP_LOCK_QUALITY: case IEEE80211_RADIOTAP_TX_ATTENUATION: case IEEE80211_RADIOTAP_DB_TX_ATTENUATION: case IEEE80211_RADIOTAP_DBM_TX_POWER: case IEEE80211_RADIOTAP_ANTENNA: case IEEE80211_RADIOTAP_DB_ANTSIGNAL: case IEEE80211_RADIOTAP_DB_ANTNOISE: case IEEE80211_RADIOTAP_TX_FLAGS: break; case IEEE80211_RADIOTAP_RX_FLAGS: if (fcshdr) { printf("\tFCS in header: %.8x\n", le32toh(*(uint32_t *)iter->this_arg)); break; } printf("\tRX flags: %#.4x\n", le16toh(*(uint16_t *)iter->this_arg)); break; case IEEE80211_RADIOTAP_RTS_RETRIES: case IEEE80211_RADIOTAP_DATA_RETRIES: break; break; default: printf("\tBOGUS DATA\n"); break; } } void print_test_namespace(struct ieee80211_radiotap_iterator *iter) { switch (iter->this_arg_index) { case 0: case 52: printf("\t00:00:00-00|%d: %.2x/%.2x/%.2x/%.2x\n", iter->this_arg_index, *iter->this_arg, *(iter->this_arg + 1), *(iter->this_arg + 2), *(iter->this_arg + 3)); break; default: printf("\tBOGUS DATA - vendor ns %d\n", iter->this_arg_index); break; } } static const struct radiotap_override overrides[] = { { .field = 14, .align = 4, .size = 4, } }; tcpflow-tcpflow-1.6.1/src/scan_http.cpp000066400000000000000000000450121401360461700201330ustar00rootroot00000000000000/* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /** * * scan_http: * Decodes HTTP responses */ #include "config.h" #include "tcpflow.h" #include "tcpip.h" #include "tcpdemux.h" #include "http-parser/http_parser.h" #include "mime_map.h" #ifdef HAVE_SYS_WAIT_H #include #endif #ifdef HAVE_LIBZ # define ZLIB_CONST # ifdef GNUC_HAS_DIAGNOSTIC_PRAGMA # pragma GCC diagnostic ignored "-Wundef" # pragma GCC diagnostic ignored "-Wcast-qual" # endif # ifdef HAVE_ZLIB_H # include # endif #else # define z_stream void * // prevents z_stream from generating an error #endif #define MIN_HTTP_BUFSIZE 80 // don't bother parsing smaller than this #include #include #include #include #include #define HTTP_CMD "http_cmd" #define HTTP_ALERT_FD "http_alert_fd" /* options */ std::string http_cmd; // command to run on each http object int http_subproc_max = 10; // how many subprocesses are we allowed? int http_subproc = 0; // how many do we currently have? int http_alert_fd = -1; // where should we send alerts? /* define a callback object for sharing state between scan_http() and its callbacks */ class scan_http_cbo { private: typedef enum {NOTHING,FIELD,VALUE} last_on_header_t; scan_http_cbo(const scan_http_cbo& c); // not implemented scan_http_cbo &operator=(const scan_http_cbo &c); // not implemented public: virtual ~scan_http_cbo(){ on_message_complete(); // make sure message was ended } scan_http_cbo(const std::string& path_,const char *base_,std::stringstream *xmlstream_) : path(path_), base(base_),xmlstream(xmlstream_),xml_fo(),request_no(0), headers(), last_on_header(NOTHING), header_value(), header_field(), output_path(), fd(-1), first_body(true),bytes_written(0),unzip(false),zs(),zinit(false),zfail(false){}; private: const std::string path; // where data gets written const char *base; // where data started in memory std::stringstream *xmlstream; // if present, where to put the fileobject annotations std::stringstream xml_fo; // xml stream for this file object int request_no; // request number /* parsed headers */ std::map headers; /* placeholders for possibly-incomplete header data */ last_on_header_t last_on_header; std::string header_value, header_field; std::string output_path; int fd; // fd for writing bool first_body; // first call to on_body after headers uint64_t bytes_written; /* decompression for gzip-encoded streams. */ bool unzip; // should we be decompressing? z_stream zs; // zstream (avoids casting and memory allocation) bool zinit; // we have initialized the zstream bool zfail; // zstream failed in some manner, so ignore the rest of this stream /* The static functions are callbacks; they wrap the method calls */ #define CBO (reinterpret_cast(parser->data)) public: static int scan_http_cb_on_message_begin(http_parser * parser) { return CBO->on_message_begin();} static int scan_http_cb_on_url(http_parser * parser, const char *at, size_t length) { return 0;} static int scan_http_cb_on_header_field(http_parser * parser, const char *at, size_t length) { return CBO->on_header_field(at,length);} static int scan_http_cb_on_header_value(http_parser * parser, const char *at, size_t length) { return CBO->on_header_value(at,length); } static int scan_http_cb_on_headers_complete(http_parser * parser) { return CBO->on_headers_complete();} static int scan_http_cb_on_body(http_parser * parser, const char *at, size_t length) { return CBO->on_body(at,length);} static int scan_http_cb_on_message_complete(http_parser * parser) {return CBO->on_message_complete();} #undef CBO private: int on_message_begin(); int on_url(const char *at, size_t length); int on_header_field(const char *at, size_t length); int on_header_value(const char *at, size_t length); int on_headers_complete(); int on_body(const char *at, size_t length); int on_message_complete(); }; /** * on_message_begin: * Increment request nubmer. Note that the first request is request_no = 1 */ int scan_http_cbo::on_message_begin() { request_no ++; return 0; } /** * on_url currently not implemented. */ int scan_http_cbo::on_url(const char *at, size_t length) { return 0; } /* Note 1: The state machine is defined in http-parser/README.md * Note 2: All header field names are converted to lowercase. * This is consistent with the RFC. */ int scan_http_cbo::on_header_field(const char *at,size_t length) { std::string field(at,length); std::transform(field.begin(), field.end(), field.begin(), ::tolower); switch(last_on_header){ case NOTHING: // Allocate new buffer and copy callback data into it header_field = field; break; case VALUE: // New header started. // Copy current name,value buffers to headers // list and allocate new buffer for new name headers[header_field] = header_value; header_field = field; break; case FIELD: // Previous name continues. Reallocate name // buffer and append callback data to it header_field.append(field); break; } last_on_header = FIELD; return 0; } int scan_http_cbo::on_header_value(const char *at, size_t length) { const std::string value(at,length); switch(last_on_header){ case FIELD: //Value for current header started. Allocate //new buffer and copy callback data to it header_value = value; break; case VALUE: //Value continues. Reallocate value buffer //and append callback data to it header_value.append(value); break; case NOTHING: // this shouldn't happen DEBUG(10)("Internal error in http-parser"); break; } last_on_header = VALUE; return 0; } /** * called when last header is read. * Determine the filename based on request_no and extension. * Also see if decompressing is happening... */ int scan_http_cbo::on_headers_complete() { tcpdemux *demux = tcpdemux::getInstance(); /* Add the most recently read header to the map, if any */ if (last_on_header==VALUE) { headers[header_field] = header_value; header_field=""; } /* Set output path to -HTTPBODY-nnn.ext for each part. * This is not consistent with tcpflow <= 1.3.0, which supported only one HTTPBODY, * but it's correct... */ std::stringstream os; os << path << "-HTTPBODY-" << std::setw(3) << std::setfill('0') << request_no << std::setw(0); /* See if we can guess a file extension */ std::string extension = get_extension_for_mime_type(headers["content-type"]); if (extension.size()) { os << "." << extension; } output_path = os.str(); /* Choose an output function based on the content encoding */ std::string content_encoding(headers["content-encoding"]); if ((content_encoding == "gzip" || content_encoding == "deflate") && (demux->opt.gzip_decompress)){ #ifdef HAVE_LIBZ DEBUG(10) ( "%s: detected zlib content, decompressing", output_path.c_str()); unzip = true; #else /* We can't decompress, so just give it a .gz */ output_path.append(".gz"); DEBUG(5) ( "%s: refusing to decompress since zlib is unavailable", output_path.c_str() ); #endif } /* Open the output path */ fd = demux->retrying_open(output_path.c_str(), O_WRONLY|O_CREAT|O_BINARY|O_TRUNC, 0644); if (fd < 0) { DEBUG(1) ("unable to open HTTP body file %s", output_path.c_str()); } if(http_alert_fd>=0){ std::stringstream ss; ss << "open\t" << output_path << "\n"; const std::string &sso = ss.str(); if(write(http_alert_fd,sso.c_str(),sso.size())!=(int)sso.size()){ perror("write"); } } first_body = true; // next call to on_body will be the first one /* We can do something smart with the headers here. * * For example, we could: * - Record all headers into the report.xml * - Pick the intended filename if we see Content-Disposition: attachment; name="..." * - Record headers into filesystem extended attributes on the body file */ return 0; } /* Write to fd, optionally decompressing as we go */ int scan_http_cbo::on_body(const char *at,size_t length) { if (fd < 0) return -1; // no open fd? (internal error)x if (length==0) return 0; // nothing to write if(first_body){ // stuff for first time on_body is called xml_fo << " " << output_path << ""; first_body = false; } /* If not decompressing, just write the data and return. */ if(unzip==false){ size_t offset = 0; while (offset < length) { int rv = write(fd, at + offset, length - offset); if (rv < 0) return -1; // write error; that's bad offset += rv; } bytes_written += offset; return 0; } #ifndef HAVE_LIBZ assert(0); // shoudln't have gotten here #endif if(zfail) return 0; // stream was corrupt; ignore rest /* set up this round of decompression, using a small local buffer */ /* Call init if we are not initialized */ char decompressed[65536]; // where decompressed data goes if (!zinit) { memset(&zs,0,sizeof(zs)); zs.next_in = (Bytef*)at; zs.avail_in = length; zs.next_out = (Bytef*)decompressed; zs.avail_out = sizeof(decompressed); int rv = inflateInit2(&zs, 32 + MAX_WBITS); /* 32 auto-detects gzip or deflate */ if (rv != Z_OK) { /* fail! */ DEBUG(3) ("decompression failed at stream initialization; rv=%d bad Content-Encoding?",rv); zfail = true; return 0; } zinit = true; // successfully initted } else { zs.next_in = (Bytef*)at; zs.avail_in = length; zs.next_out = (Bytef*)decompressed; zs.avail_out = sizeof(decompressed); } /* iteratively decompress, writing each time */ while (zs.avail_in > 0) { /* decompress as much as possible */ int rv = inflate(&zs, Z_SYNC_FLUSH); if (rv == Z_STREAM_END) { /* are we done with the stream? */ if (zs.avail_in > 0) { /* ...no. */ DEBUG(3) ("decompression completed, but with trailing garbage"); return 0; } } else if (rv != Z_OK) { /* some other error */ DEBUG(3) ("decompression failed (corrupted stream?)"); zfail = true; // ignore the rest of this stream return 0; } /* successful decompression, at least partly */ /* write the result */ int bytes_decompressed = sizeof(decompressed) - zs.avail_out; ssize_t written = write(fd, decompressed, bytes_decompressed); if (written < bytes_decompressed) { DEBUG(3) ("writing decompressed data failed"); zfail= true; return 0; } bytes_written += written; /* reset the buffer for the next iteration */ zs.next_out = (Bytef*)decompressed; zs.avail_out = sizeof(decompressed); } return 0; } /** * called at the conclusion of each HTTP body. * Clean out all of the state for this HTTP header/body pair. */ int scan_http_cbo::on_message_complete() { /* Close the file */ headers.clear(); header_field = ""; header_value = ""; last_on_header = NOTHING; if(fd >= 0) { if (::close(fd) != 0) { perror("close() of http body"); } fd = -1; } /* Erase zero-length files and update the DFXML */ if(bytes_written>0){ /* Update DFXML */ if(xmlstream){ xml_fo << "" << bytes_written << "\n"; if(xmlstream) *xmlstream << xml_fo.str(); } if(http_alert_fd>=0){ std::stringstream ss; ss << "close\t" << output_path << "\n"; const std::string &sso = ss.str(); if(write(http_alert_fd,sso.c_str(),sso.size()) != (int)sso.size()){ perror("write"); } } if(http_cmd.size()>0 && output_path.size()>0){ /* If we are at maximum number of subprocesses, wait for one to exit */ std::string cmd = http_cmd + " " + output_path; #ifdef HAVE_FORK int status=0; pid_t pid = 0; while(http_subproc >= http_subproc_max){ pid = wait(&status); http_subproc--; } /* Fork off a child */ pid = fork(); if(pid<0) die("Cannot fork child"); if(pid==0){ /* We are the child */ exit(system(cmd.c_str())); } http_subproc++; #else system(cmd.c_str()); #endif } } else { /* Nothing written; erase the file */ if(output_path.size() > 0){ ::unlink(output_path.c_str()); } } /* Erase the state variables for this part */ xml_fo.str(""); output_path = ""; bytes_written=0; unzip = false; if(zinit){ inflateEnd(&zs); zinit = false; } zfail = false; return 0; } /*** * the HTTP scanner plugin itself */ extern "C" void scan_http(const class scanner_params &sp,const recursion_control_block &rcb) { if(sp.sp_version!=scanner_params::CURRENT_SP_VERSION){ std::cerr << "scan_http requires sp version " << scanner_params::CURRENT_SP_VERSION << "; " << "got version " << sp.sp_version << "\n"; exit(1); } if(sp.phase==scanner_params::PHASE_STARTUP){ sp.info->name = "http"; sp.info->flags = scanner_info::SCANNER_DISABLED; // default disabled sp.info->get_config(HTTP_CMD,&http_cmd,"Command to execute on each HTTP attachment"); sp.info->get_config(HTTP_ALERT_FD,&http_alert_fd,"File descriptor to send information about completed HTTP attachments"); return; /* No feature files created */ } if(sp.phase==scanner_params::PHASE_SCAN){ /* See if there is an HTTP response */ if(sp.sbuf.bufsize>=MIN_HTTP_BUFSIZE && sp.sbuf.memcmp(reinterpret_cast("HTTP/1."),0,7)==0){ /* Smells enough like HTTP to try parsing */ /* Set up callbacks */ http_parser_settings scan_http_parser_settings; memset(&scan_http_parser_settings,0,sizeof(scan_http_parser_settings)); // in the event that new callbacks get created scan_http_parser_settings.on_message_begin = scan_http_cbo::scan_http_cb_on_message_begin; scan_http_parser_settings.on_url = scan_http_cbo::scan_http_cb_on_url; scan_http_parser_settings.on_header_field = scan_http_cbo::scan_http_cb_on_header_field; scan_http_parser_settings.on_header_value = scan_http_cbo::scan_http_cb_on_header_value; scan_http_parser_settings.on_headers_complete = scan_http_cbo::scan_http_cb_on_headers_complete; scan_http_parser_settings.on_body = scan_http_cbo::scan_http_cb_on_body; scan_http_parser_settings.on_message_complete = scan_http_cbo::scan_http_cb_on_message_complete; if(sp.sxml) (*sp.sxml) << "\n \n"; for(size_t offset=0;;){ /* Set up a parser instance for the next chunk of HTTP responses and data. * This might be repeated several times due to connection re-use and multiple requests. * Note that the parser is not a C++ library but it can pass a "data" to the * callback. We put the address for the scan_http_cbo object in the data and * recover it with a cast in each of the callbacks. */ /* Make an sbuf for the remaining data. * Note that this may not be necessary, because in our test runs the parser * processed all of the data the first time through... */ sbuf_t sub_buf(sp.sbuf, offset); const char *base = reinterpret_cast(sub_buf.buf); http_parser parser; http_parser_init(&parser, HTTP_RESPONSE); scan_http_cbo cbo(sp.sbuf.pos0.path,base,sp.sxml); parser.data = &cbo; /* Parse */ size_t parsed = http_parser_execute(&parser, &scan_http_parser_settings, base, sub_buf.size()); assert(parsed <= sub_buf.size()); /* Indicate EOF (flushing callbacks) and terminate if we parsed the entire buffer. */ if (parsed == sub_buf.size()) { http_parser_execute(&parser, &scan_http_parser_settings, NULL, 0); break; } /* Stop parsing if we parsed nothing, as that indicates something header! */ if (parsed == 0) { break; } /* Stop parsing if we're a connection upgrade (e.g. WebSockets) */ if (parser.upgrade) { DEBUG(9) ("upgrade connection detected (WebSockets?); cowardly refusing to dump further"); break; } /* Bump the offset for next iteration */ offset += parsed; } if(sp.sxml) (*sp.sxml) << " "; } } } tcpflow-tcpflow-1.6.1/src/scan_md5.cpp000066400000000000000000000021241401360461700176360ustar00rootroot00000000000000/** * * scan_md5: * plug-in demonstration that shows how to write a simple plug-in scanner that calculates * the MD5 of each file.. */ #include "config.h" #include "bulk_extractor_i.h" #include "dfxml/src/hash_t.h" #include #include extern "C" void scan_md5(const class scanner_params &sp,const recursion_control_block &rcb) { if(sp.sp_version!=scanner_params::CURRENT_SP_VERSION){ std::cerr << "scan_md5 requires sp version " << scanner_params::CURRENT_SP_VERSION << "; " << "got version " << sp.sp_version << "\n"; exit(1); } if(sp.phase==scanner_params::PHASE_STARTUP){ sp.info->name = "md5"; sp.info->flags = scanner_info::SCANNER_DISABLED; return; /* No feature files created */ } #ifdef HAVE_EVP_GET_DIGESTBYNAME if(sp.phase==scanner_params::PHASE_SCAN){ static const std::string hash0(""); static const std::string hash1(""); if(sp.sxml){ (*sp.sxml) << hash0 << md5_generator::hash_buf(sp.sbuf.buf,sp.sbuf.bufsize).hexdigest() << hash1; } return; } #endif } tcpflow-tcpflow-1.6.1/src/scan_netviz.cpp000066400000000000000000000043741401360461700205010ustar00rootroot00000000000000/** * scan_netviz: * * Our first try at a pcap visualization engine. * Requires LIBCAIRO */ #include "config.h" #include #include #include "bulk_extractor_i.h" #ifdef HAVE_LIBCAIRO #include "netviz/one_page_report.h" /* These control the size of the iptable histogram * and whether or not it is dumped. The histogram should be kept * either small enough that it is not expensive to maintain, or large * enough so that it never needs to be pruned. */ #define HISTOGRAM_SIZE "netviz_histogram_size" #define HISTOGRAM_DUMP "netviz_histogram_dump" #define DEFAULT_MAX_HISTOGRAM_SIZE 1000 static one_page_report *report=0; static void netviz_process_packet(void *user,const be13::packet_info &pi) { report->ingest_packet(pi); } #endif #ifdef HAVE_LIBCAIRO static int histogram_dump = 0; #endif extern "C" void scan_netviz(const class scanner_params &sp,const recursion_control_block &rcb) { if(sp.sp_version!=scanner_params::CURRENT_SP_VERSION){ std::cout << "scan_timehistogram requires sp version " << scanner_params::CURRENT_SP_VERSION << "; " << "got version " << sp.sp_version << "\n"; exit(1); } if(sp.phase==scanner_params::PHASE_STARTUP){ sp.info->name = "netviz"; sp.info->flags = scanner_info::SCANNER_DISABLED; // disabled by default sp.info->author= "Mike Shick"; sp.info->packet_user = 0; #ifdef HAVE_LIBCAIRO sp.info->description = "Performs 1-page visualization of network packets"; sp.info->packet_cb = netviz_process_packet; sp.info->get_config(HISTOGRAM_DUMP,&histogram_dump,"Dumps the histogram"); int max_histogram_size = DEFAULT_MAX_HISTOGRAM_SIZE; sp.info->get_config(HISTOGRAM_SIZE,&max_histogram_size,"Maximum histogram size"); report = new one_page_report(max_histogram_size); #else sp.info->description = "Disabled (compiled without libcairo"; #endif } #ifdef HAVE_LIBCAIRO if(sp.phase==scanner_params::PHASE_SHUTDOWN){ assert(report!=0); if(histogram_dump){ report->src_tree.dump_stats(std::cout); report->dump(histogram_dump); } report->source_identifier = sp.fs.get_input_fname(); report->render(sp.fs.get_outdir()); delete report; report = 0; } #endif } tcpflow-tcpflow-1.6.1/src/scan_python.cpp000066400000000000000000000177471401360461700205130ustar00rootroot00000000000000/** vi:ft=cpp ts=8 et sw=4 sts=4 tw=80 * emacs: -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8; c-file-style: "linux" -*- * * scan_python: * Use external python scripts to post-process flow files * * 2020-09-27 - slg - removed from build because this is only Python 2.7 */ #include "config.h" #include "dfxml/src/hash_t.h" #include "tcpflow.h" #include #include #if HAVE_PYTHON2_7_PYTHON_H # include // Get header: install package "python-devel" #endif struct ScanPython { ScanPython() : py_path() , py_module() , py_function() , init_script() #if HAVE_PYTHON2_7_PYTHON_H , pythonFunction (NULL) #endif { } ScanPython(const ScanPython& o) : py_path(o.py_path) , py_module(o.py_module) , py_function(o.py_function) , init_script(o.init_script) #if HAVE_PYTHON2_7_PYTHON_H , pythonFunction (NULL) #endif { } ScanPython& operator=(const ScanPython& o) { py_path = o.py_path; py_module = o.py_module; py_function = o.py_function; init_script = o.init_script; #if HAVE_PYTHON2_7_PYTHON_H pythonFunction = NULL; #endif return *this; } void startup(const scanner_params& sp); void init(const scanner_params& sp); void before(); void scan(const scanner_params& sp); void shutdown(); std::string py_path; std::string py_module; std::string py_function; std::string init_script; #if HAVE_PYTHON2_7_PYTHON_H PyObject* pythonFunction; #endif }; void ScanPython::startup(const scanner_params& sp) { if (sp.sp_version != scanner_params::CURRENT_SP_VERSION) { std::cerr << "scan_python requires sp version " << scanner_params::CURRENT_SP_VERSION << "; " << "got version " << sp.sp_version << "\n"; exit(1); } sp.info->name = "python"; sp.info->flags = scanner_info::SCANNER_DISABLED; sp.info->get_config("py_path", &py_path, " Directory to find python module (optional)"); sp.info->get_config("py_module", &py_module, " Name of python module (script name without extension)"); sp.info->get_config("py_function", &py_function, "Function name within the python module"); } static std::string get_working_dir(const std::string& path) { if (path.empty()) { return "os.getcwd()"; } if (path[0] == '/'){ return "'" + path + "'"; } else { return "os.getcwd() + '/" + path + "'"; } } void ScanPython::init(const scanner_params& /*sp*/) { if (py_module.empty() || py_function.empty()) { DEBUG(1)("[scan_python] Cannot call python becase no provided module/function." "\n" "\t\t\t\t" "Please use arguments -S py_module=module -S py_function=foo" ); // "\n" "\t\t\t\t" "The scanner 'python' is disabled to avoid warning messages."); // sp.info->flags = scanner_info::SCANNER_DISABLED; // TODO(simsong): Should we disable the scanner to avoid warnings? return; } // Write the initialization script to set directory to the local system path init_script = "import sys, os" "\n" "workingDir = " + get_working_dir(py_path) + "\n" "sys.path.append(workingDir)" "\n"; #if HAVE_PYTHON2_7_PYTHON_H // Spawn python interpreter Py_Initialize(); DEBUG(10) ("[scan_python] Initialize Python using script:" "\n" "%s", init_script.c_str()); PyRun_SimpleString(init_script.c_str()); // Create PyObject from script filename PyObject* pName = PyString_FromString(py_module.c_str()); if (pName == NULL) { DEBUG(2) ("[scan_python] Cannot create PyObject from path='%s' and module='%s'" "\n" "\t\t\t" "Try using three arguments: -S py_path=path -S py_module=module -S py_function=foo", py_path.c_str(), py_module.c_str()); return; } // Import script file in python interpreter PyObject* pModule = PyImport_Import(pName); if (pModule == NULL) { DEBUG(2) ("[scan_python] Cannot import module='%s' from path='%s' in Python interpreter" "\n" "\t\t\t" "Try using three arguments: -S py_path=path -S py_module=module -S py_function=foo", py_module.c_str(), py_path.c_str()); return; } // Identify function to be used pythonFunction = PyObject_GetAttrString(pModule, py_function.c_str()); if (pythonFunction == NULL) { DEBUG(2) ("[scan_python] Cannot identify function='%s' in module='%s' from path='%s'" "\n" "\t\t\t" "Try using three arguments: -S py_path=path -S py_module=module -S py_function=foo", py_function.c_str(), py_module.c_str(), py_path.c_str()); return; } #endif } // TODO(simsong): Why is PHASE_THREAD_BEFORE_SCAN never processed? void ScanPython::before() { } void ScanPython::scan(const scanner_params& sp) { #if HAVE_PYTHON2_7_PYTHON_H if (pythonFunction == NULL) { init(sp); if (pythonFunction == NULL) { // DEBUG(1)("[scan_python] Cannot initialize => Disabled the scanner to avoid warning messages."); // sp.info->flags = scanner_info::SCANNER_DISABLED; // TODO(simsong): Should we disable the scanner to avoid warnings? return; } } // Cast packet buffer contents into a string and create pyObject std::string data(reinterpret_cast(sp.sbuf.buf)); PyObject* pData = PyString_FromString(data.c_str()); // Compose python argument in the form of a tuple and pass the argument to // the chosen function; if the function does not return anything or // encounters an error, return to exit and/or display the error PyObject* pArgs = PyTuple_New(1); PyTuple_SetItem(pArgs, 0, pData); PyObject* pResult = PyObject_CallObject(pythonFunction, pArgs); if (pResult) { // If XML-reporting enabled => Insert the string returned by the python function if (sp.sxml) { const char* returned_string = PyString_AsString(pResult); (*sp.sxml) << ""<< returned_string <<""; else (*sp.sxml) << "\"/>"; } } #else DEBUG(2) ("[scan_python] tcpflow cannot call python scripts required by the scanner 'python'" "\n" "\t\t" "because the header was not present during the tcpflow build." "\n" "\t\t" "Try to install package 'python-devel' and build again tcpflow (./configure)"); #endif } void ScanPython::shutdown() { #if HAVE_PYTHON2_7_PYTHON_H // Terminate the python interpreter and exit Py_Finalize(); pythonFunction = NULL; #endif } extern "C" void scan_python(const scanner_params& sp, const recursion_control_block& /*rcb*/) { static ScanPython singleton; switch (sp.phase) { case scanner_params::PHASE_NONE: break; // Called in main thread to parse configuration // (also used to build the --help text) case scanner_params::PHASE_STARTUP: singleton.startup(sp); break; // Should be called in main thread after all scanners loaded (but never called) case scanner_params::PHASE_INIT: singleton.init(sp); break; // Called in worker thread before first scan case scanner_params::PHASE_THREAD_BEFORE_SCAN: singleton.before(); break; // Called in worker thread for each sbuf case scanner_params::PHASE_SCAN: singleton.scan(sp); break; // Called in main thread when scanner is shutdown case scanner_params::PHASE_SHUTDOWN: singleton.shutdown(); break; } } tcpflow-tcpflow-1.6.1/src/scan_tcpdemux.cpp000066400000000000000000000037751401360461700210170ustar00rootroot00000000000000/** * tcp demultiplixier scanner. * * We have a single global tcpdemultiplixer because it needs to manage * a global resource --- the maximum number of open files. We get the * singleton instance and put it in the user argument of the global * callback array. We could have designed the callback system to take * an instance which is subclassed from an abstract superclass, but * that would require a virtual function resolution on every function * call, whereas here we simply have a function call with two * arguments (which is faster, but less safe.) */ #include "config.h" #include "tcpflow.h" #include "tcpip.h" #include "tcpdemux.h" #include #include #include "bulk_extractor_i.h" /** callback called by process_packet() */ static void packet_handler(void *user,const be13::packet_info &pi) { reinterpret_cast(user)->process_pkt(pi); } extern "C" void scan_tcpdemux(const class scanner_params &sp,const recursion_control_block &rcb) { if(sp.sp_version!=scanner_params::CURRENT_SP_VERSION){ std::cerr << "scan_tcpdemux requires sp version " << scanner_params::CURRENT_SP_VERSION << "; " << "got version " << sp.sp_version << "\n"; exit(1); } if(sp.phase==scanner_params::PHASE_STARTUP){ sp.info->name = "tcpdemux"; sp.info->author= "Simson Garfinkel"; sp.info->packet_user = tcpdemux::getInstance(); sp.info->packet_cb = packet_handler; sp.info->get_config("tcp_timeout",&tcpdemux::getInstance()->tcp_timeout,"Timeout for TCP connections"); sp.info->get_config("tcp_cmd",&tcpdemux::getInstance()->tcp_cmd,"Command to execute on each TCP flow"); sp.info->get_config("tcp_alert_fd",&tcpdemux::getInstance()->tcp_alert_fd,"File descriptor to send information about completed TCP flows"); return; /* No feature files created */ } if(sp.phase==scanner_params::PHASE_SCAN){ static const std::string hash0(""); static const std::string hash1(""); return; } } tcpflow-tcpflow-1.6.1/src/scan_wifiviz.cpp000066400000000000000000000026161401360461700206460ustar00rootroot00000000000000/** * scan_wifiviz: * * Use the wifipcap and do some basic visualizations */ #include "config.h" #include #include #include "bulk_extractor_i.h" #include "datalink_wifi.h" extern "C" void scan_wifiviz(const class scanner_params &sp,const recursion_control_block &rcb) { if(sp.sp_version!=scanner_params::CURRENT_SP_VERSION){ std::cout << "scan_timehistogram requires sp version " << scanner_params::CURRENT_SP_VERSION << "; " << "got version " << sp.sp_version << "\n"; exit(1); } if(sp.phase==scanner_params::PHASE_STARTUP){ sp.info->name = "wifiviz"; sp.info->flags = scanner_info::SCANNER_DISABLED; sp.info->author= "Simson Garfinkel"; sp.info->packet_user = 0; sp.info->description = "Performs wifi isualization"; sp.info->get_config("check_fcs",&TFCB::theTFCB.opt_check_fcs,"Require valid Frame Check Sum (FCS)"); } if(sp.phase==scanner_params::PHASE_SHUTDOWN){ if(sp.sxml){ (*sp.sxml) << "\n"; for(TFCB::mac_ssid_map_t::const_iterator it=TFCB::theTFCB.mac_to_ssid.begin(); it!=TFCB::theTFCB.mac_to_ssid.end();it++){ (*sp.sxml) << " \n"; } (*sp.sxml) << "\n"; } } } tcpflow-tcpflow-1.6.1/src/stest.cpp000066400000000000000000000054731401360461700173210ustar00rootroot00000000000000#include #include #include #include static int callback(void *NotUsed, int argc, char **argv, char **azColName){ int i; for(i=0; i * * This source code is under the GNU Public License (GPL). See * LICENSE for details. * */ #include "tcpflow.h" #include "tcpip.h" #include "tcpdemux.h" #include #include #include #ifdef HAVE_SYS_WAIT_H #include #endif /* static */ uint32_t tcpdemux::max_saved_flows = 100; /* static */ uint32_t tcpdemux::tcp_timeout = 0; /* static */ int tcpdemux::tcp_subproc_max = 10; /* static */ int tcpdemux::tcp_subproc = 0; /* static */ int tcpdemux::tcp_alert_fd = -1; /* static */ std::string tcpdemux::tcp_cmd = ""; tcpdemux::tcpdemux(): #ifdef HAVE_SQLITE3 db(),insert_flow(), #endif flow_sorter(0),tcp_processor(0), outdir("."),flow_counter(0),packet_counter(0), xreport(0),pwriter(0),max_open_flows(),max_fds(get_max_fds()-NUM_RESERVED_FDS), unique_id(0), flow_map(),open_flows(),saved_flow_map(),flow_fd_cache_map(0), saved_flows(),start_new_connections(false),opt(),fs() { tcp_processor = &tcpdemux::process_tcp; } void tcpdemux::alter_processing_core() { DEBUG(1) ("ensuring pcap core"); tcp_processor = &tcpdemux::dissect_tcp; flow_sorter = new pcap_writer(); } void tcpdemux::openDB() { #ifdef HAVE_SQLITE3 int rc = sqlite3_open("test.db", &db); if( rc ){ fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db)); db = 0; } /* Create SQL statement */ const char *sql = "CREATE TABLE connections (" "starttime TEXT NOT NULL," "endtime TEXT NOT NULL," "src_ipn TEXT," "dst_ipn TEXT," "mac_daddr TEXT," "mac_saddr TEXT," "packets INTEGER," "srcport INTEGER," "dstport INTEGER," "hashdigest_md5 TEXT);"; /* Execute SQL statement */ rc = sqlite3_exec(db, sql, callback, 0, &zErrMsg); if( rc != SQLITE_OK ){ fprintf(stderr, "SQL error: %s\n", zErrMsg); sqlite3_free(zErrMsg); sqlite3_close(db); return 0; } const char* zSql = "INSERT INTO connections (starttime,endtime,src_ipn,dst_ipn,mac_daddr,mac_saddr,packets,srcport,dstport,hashdigest_md5) VALUES (?,?,?,?,?,?,?,?,?,?)"; if(sqlite3_prepare_v2(db, zSql, strlen(zSql), &insert_stmt, NULL)!=SQLITE_OK ){ fprintf(stderr, "SQL prepare error"); db = 0; insert_stmt=0; return(0); } #endif } void tcpdemux::write_flow_record(const std::string &starttime,const std::string &endtime, const std::string &src_ipn,const std::string &dst_ipn, const std::string &mac_daddr,const std::string &mac_saddr, uint64_t packets,uint16_t srcport,uint16_t dstport, const std::string &hashdigest_md5) { } /* static */ tcpdemux *tcpdemux::getInstance() { static tcpdemux * theInstance = 0; if(theInstance==0) theInstance = new tcpdemux(); return theInstance; } /** * find the flow that has been written to in the furthest past and close it. */ void tcpdemux::close_oldest_fd() { tcpip *oldest_tcp = *open_flows.begin(); if(oldest_tcp) oldest_tcp->close_file(); } /* Open a file, closing one of the existing flows f necessary. */ int tcpdemux::retrying_open(const std::string &filename,int oflag,int mask) { while(true){ //Packet index file reduces max_fds by 1/2 as the index files also take a fd if(open_flows.size() >= (opt.output_packet_index ? max_fds/2 : max_fds)) close_oldest_fd(); int fd = ::open(filename.c_str(),oflag,mask); DEBUG(2)("retrying_open ::open(fn=%s,oflag=x%x,mask:x%x)=%d",filename.c_str(),oflag,mask,fd); if(fd>=0){ /* Open was successful */ return fd; } DEBUG(2)("retrying_open ::open failed with errno=%d",errno); if (errno != ENFILE && errno != EMFILE){ DEBUG(2)("retrying_open ::open failed with errno=%d (%s)",errno,strerror(errno)); return -1; // wonder what it was } DEBUG(5) ("too many open files -- contracting FD ring (size=%d)", (int)open_flows.size()); close_oldest_fd(); } } /* Find previously a previously created flow state in the database. */ tcpip *tcpdemux::find_tcpip(const flow_addr &flow) { flow_map_t::const_iterator it = flow_map.find(flow); if (it==flow_map.end()){ return NULL; // flow not found } return it->second; } /* Create a new flow state structure for a given flow. * Puts the flow in the map. * Returns a pointer to the new state. * * This is called by tcpdemux::process_tcp(). (Only place it is called) * * @param - pi - first packet seen on this connection. * * NOTE: We keep pointers to tcp structures in the map, rather than * the structures themselves. This makes the map slightly more efficient, * since it doesn't need to shuffle entire structures. * * * TK: Note that the flow() is created on the stack and then used in new tcpip(). * This is resulting in an unnecessary copy. */ tcpip *tcpdemux::create_tcpip(const flow_addr &flowa, be13::tcp_seq isn,const be13::packet_info &pi) { /* create space for the new state */ flow flow(flowa,flow_counter++,pi); tcpip *new_tcpip = new tcpip(*this,flow,isn); new_tcpip->nsn = isn+1; // expected sequence number of the first byte DEBUG(5) ("new flow %s. path: %s next seq num (nsn):%d", flowa.str().c_str(),new_tcpip->flow_pathname.c_str(),new_tcpip->nsn); flow_map[flow] = new_tcpip; open_flows.reset(new_tcpip); return new_tcpip; } /** * Remove a flow from the database. * Close the flow file. * Write to the report.xml object. * Save in the sqlite database. * This is the ONLY place where a tcpip object is deleted so there is no chance of finding it again. * * Flows are post-processed when a FIN is received and all bytes are received. * If a FIN is received and bytes are outstanding, they are post-processed when the last byte is received. * When the program shut down, all open flows are post-processed. * * Amended to trigger the packet/data location index sort as part of the post-processing. This sorts * the (potentially out of order) index to make it simple for external applications. No processing is * done if the (-I) index generation feature is turned off. --GDD */ void tcpdemux::post_process(tcpip *tcp) { std::stringstream xmladd; // for this if(opt.post_processing && tcp->file_created && tcp->last_byte>0){ /** * After the flow is finished, if more than a byte was * written, then put it in an SBUF and process it. if we are * doing post-processing. This is called from tcpip::~tcpip() * in tcpip.cpp. */ /* Open the fd if it is not already open */ tcp->open_file(); if(tcp->fd>=0){ sbuf_t *sbuf = sbuf_t::map_file(tcp->flow_pathname,tcp->fd); if(sbuf){ be13::plugin::process_sbuf(scanner_params(scanner_params::PHASE_SCAN,*sbuf,*(fs),&xmladd)); delete sbuf; sbuf = 0; } } } tcp->close_file(); if(xreport) tcp->dump_xml(xreport,xmladd.str()); /** * Before we delete the tcp structure, save information about the saved flow */ save_flow(tcp); if(opt.store_output && tcp_alert_fd>=0){ std::stringstream ss; ss << "close\t" << tcp->flow_pathname.c_str() << "\n"; const std::string &sso = ss.str(); if(write(tcp_alert_fd,sso.c_str(),sso.size()) != (int)sso.size()){ perror("write"); } } if(tcp_cmd.size()>0 && tcp->flow_pathname.size()>0){ /* If we are at maximum number of subprocesses, wait for one to exit */ std::string cmd = tcp_cmd + " " + tcp->flow_pathname; #ifdef HAVE_FORK int status=0; pid_t pid = 0; while(tcp_subproc >= tcp_subproc_max){ pid = wait(&status); tcp_subproc--; } /* Fork off a child */ pid = fork(); if(pid<0) die("Cannot fork child"); if(pid==0){ /* We are the child */ exit(system(cmd.c_str())); } tcp_subproc++; #else system(cmd.c_str()); #endif } delete tcp; } void tcpdemux::remove_flow(const flow_addr &flow) { flow_map_t::iterator it = flow_map.find(flow); if(it!=flow_map.end()){ post_process(it->second); flow_map.erase(it); } } void tcpdemux::remove_all_flows() { DEBUG(10) ("Cleaning up flows"); for(flow_map_t::iterator it=flow_map.begin();it!=flow_map.end();it++){ post_process(it->second); } flow_map.clear(); for(sparse_saved_flow_map_t::iterator it=flow_fd_cache_map.begin();it!=flow_fd_cache_map.end();it++){ delete it->second; } flow_fd_cache_map.clear(); } /**************************************************************** *** tcpdemultiplexer ****************************************************************/ /* Try to find the maximum number of FDs this system can have open */ unsigned int tcpdemux::get_max_fds(void) { int max_descs = 0; const char *method=0; /* No longer users OPEN_MAX */ #if defined (HAVE_GETDTABLESIZE) method = "getdtablesize"; max_descs = getdtablesize(); #elif defined(RLIMIT_NOFILE) { struct rlimit limit; memset(&limit,0,sizeof(limit)); method = "rlimit"; if (getrlimit(RLIMIT_NOFILE, &limit) < 0) { perror("getrlimit"); exit(1); } /* set the current to the maximum or specified value */ limit.rlim_cur = limit.rlim_max; #ifdef OPEN_MAX if(limit.rlim_cur > OPEN_MAX) limit.rlim_cur = OPEN_MAX; #endif if (setrlimit(RLIMIT_NOFILE, &limit) < 0) { perror("setrlimit"); exit(1); } max_descs = limit.rlim_max; #ifdef RLIM_INFINITY if (limit.rlim_max == RLIM_INFINITY) max_descs = MAX_FD_GUESS * 4; /* pick a more reasonable max */ #endif } #elif defined (_SC_OPEN_MAX) /* Okay, you don't have getrlimit() and you don't have OPEN_MAX. * Time to try the POSIX sysconf() function. (See Stevens' * _Advanced Programming in the UNIX Environment_). */ method = "POSIX sysconf"; errno = 0; if ((max_descs = sysconf(_SC_OPEN_MAX)) < 0) { if (errno == 0) max_descs = MAX_FD_GUESS * 4; else { perror("calling sysconf"); exit(1); } } /* if everything has failed, we'll just take a guess */ #else method = "MAX_FD_GUESS"; max_descs = MAX_FD_GUESS; #endif /* this must go here, after rlimit code */ DEBUG(10) ("found max FDs to be %d using %s", max_descs, method); return max_descs; } /* * open the packet save flow */ void tcpdemux::save_unk_packets(const std::string &ofname,const std::string &ifname) { pwriter = pcap_writer::open_copy(ofname,ifname); } /** * save information on this flow needed to handle strangling packets */ int c = 0; void tcpdemux::save_flow(tcpip *tcp) { /* First remove the oldest flow if we are in overload */ if(saved_flows.size()>0 && saved_flows.size()>max_saved_flows){ saved_flow *flow0 = saved_flows.at(0); saved_flow_map.erase(flow0->addr); // remove from the map saved_flows.erase(saved_flows.begin()); // remove from the vector delete flow0; // and delete the saved flow } /* Now save the flow */ saved_flow *sf = new saved_flow(tcp); saved_flow_map[sf->addr] = sf; saved_flows.push_back(sf); } /** * dissect_tcp(): * * Called to process tcp pkts in a way that dissected or isolated pcap flows are * emerging afterwards. Similar notions go into the direction of "sorting" pcap pkts * as per flow context. * * Returns 0 if packet is processed, 1 if it is not processed, -1 if error */ int tcpdemux::dissect_tcp(const ipaddr &src, const ipaddr &dst,sa_family_t family, const u_char *ip_data, uint32_t ip_payload_len, const be13::packet_info &pi) { DEBUG(6) ("dissecting pkt *********************"); struct be13::tcphdr *tcp_header = (struct be13::tcphdr *) ip_data; flow_addr this_flow(src,dst,ntohs(tcp_header->th_sport), ntohs(tcp_header->th_dport),family); sparse_saved_flow_map_t::const_iterator it = flow_fd_cache_map.find(this_flow); if(it!=flow_fd_cache_map.end()){ flow_sorter->update_sink(it->second->fcap); } else { flow fn_gen_vehicle(this_flow, 0, pi); // impromptu flow name generator std::string fn = fn_gen_vehicle.new_pcap_filename(); flow_sorter->refresh_sink(fn, pi.pcap_dlt); FILE *sink= flow_sorter->yield_sink(); sparse_saved_flow *ssf = new sparse_saved_flow(this_flow, sink); flow_fd_cache_map[ssf->addr] = ssf; } flow_sorter->writepkt(pi.pcap_hdr,pi.pcap_data); return 0; } /** * process_tcp(): * * Called to processes a tcp packet from either process_ip4() or process_ip6(). * The caller breaks out the ip addresses and finds the start of the tcp header. * * Skips but otherwise ignores TCP options. * * creates a new tcp connection if necessary, then asks the connection to either * print the packet or store it. * * Returns 0 if packet is processed, 1 if it is not processed, -1 if error */ #define FLAG_SET(vector, flag) ((vector) & (flag)) #pragma GCC diagnostic ignored "-Wcast-align" #include "iptree.h" int tcpdemux::process_tcp(const ipaddr &src, const ipaddr &dst,sa_family_t family, const u_char *ip_data, uint32_t ip_payload_len, const be13::packet_info &pi) { if (ip_payload_len < sizeof(struct be13::tcphdr)) { DEBUG(6) ("received truncated TCP segment! (%u<%u)", (u_int)ip_payload_len,(u_int)sizeof(struct be13::tcphdr)); return 1; } struct be13::tcphdr *tcp_header = (struct be13::tcphdr *) ip_data; /* fill in the flow_addr structure with info that identifies this flow */ flow_addr this_flow(src,dst,ntohs(tcp_header->th_sport),ntohs(tcp_header->th_dport),family); be13::tcp_seq seq = ntohl(tcp_header->th_seq); bool syn_set = FLAG_SET(tcp_header->th_flags, TH_SYN); bool ack_set = FLAG_SET(tcp_header->th_flags, TH_ACK); bool fin_set = FLAG_SET(tcp_header->th_flags, TH_FIN); bool rst_set = FLAG_SET(tcp_header->th_flags, TH_RST); /* calculate the total length of the TCP header including options */ u_int tcp_header_len = tcp_header->th_off * 4; /* Find the beginning of the tcp data. */ const u_char *tcp_data = ip_data + tcp_header_len; /* figure out how much tcp data we have, taking into account tcp options */ size_t tcp_datalen = (ip_payload_len > tcp_header_len) ? (ip_payload_len - tcp_header_len) : 0; /* see if we have state about this flow; if not, create it */ int32_t delta = 0; // from current position in tcp connection; must be SIGNED 32 bit! tcpip *tcp = find_tcpip(this_flow); DEBUG(60)("%s%s%s%s tcp_header_len=%d tcp_datalen=%d seq=%u tcp=%p", (syn_set?"SYN ":""),(ack_set?"ACK ":""),(fin_set?"FIN ":""),(rst_set?"RST ":""),(int)tcp_header_len,(int)tcp_datalen,(int)seq,tcp); /* If this_flow is not in the database and the start_new_connections flag is false, just return */ if(tcp==0 && start_new_connections==false) return 0; if(syn_set && tcp && tcp->syn_count>0 && tcp->pos>0){ std::cerr << "SYN TO IGNORE! SYN tcp="<second->isn - 1; bool data_match = false; int fd = open(it->second->saved_filename.c_str(),O_RDONLY | O_BINARY); if(fd>0){ char *buf = (char *)malloc(tcp_datalen); if(buf){ DEBUG(100)("lseek(fd,%" PRId64 ",SEEK_SET)",(int64_t)(offset)); lseek(fd,offset,SEEK_SET); ssize_t r = read(fd,buf,tcp_datalen); data_match = (r==(ssize_t)tcp_datalen) && memcmp(buf,tcp_data,tcp_datalen)==0; free(buf); } close(fd); } DEBUG(60)("Packet matches saved flow. offset=%u len=%d filename=%s data match=%d\n", (u_int)offset,(u_int)tcp_datalen,it->second->saved_filename.c_str(),(u_int)data_match); if(data_match) return 0; } } } /* flow is in the database; make sure the gap isn't too big.*/ if(tcp){ /* Compute delta based on next expected sequence number. * If delta will be too much, start a new flow. * * NOTE: I hope we don't get a packet from the old flow when * we are processing the new one. Perhaps we should be able to have * multiple flows at the same time with the same quad, and they are * at different window areas... * */ delta = seq - tcp->nsn; // notice that signed offset is calculated if(abs(delta) > opt.max_seek){ remove_flow(this_flow); delta = 0; tcp = 0; } } /* At this point, tcp may be NULL because: * case 1 - It's a new connection and SYN IS SET; normal case * case 2 - Extra packets on a now-closed connection * case 3 - Packets for which the initial part of the connection was missed * case 4 - It's a connecton that had a huge gap and was expired out of the databsae * * THIS IS THE ONLY PLACE THAT create_tcpip() is called. */ /* q: what if syn is set AND there is data? */ /* q: what if syn is set AND we already know about this connection? */ if (tcp==NULL){ /* Don't process if this is not a SYN and there is no data. */ if(syn_set==false && tcp_datalen==0) return 0; /* Check if this is the server->client flow related to a client->server flow that is being demultiplexed */ flow_addr reverse_flow(dst,src,ntohs(tcp_header->th_dport),ntohs(tcp_header->th_sport),family); tcpip *reverse_tcp = find_tcpip(reverse_flow); uint64_t uid; if (reverse_tcp) { /* We found a matching client->server flow. Copy its session ID */ uid = reverse_tcp->myflow.session_id; } else { /* Assign a new unique ID */ uid = unique_id++; } /* Create a new connection. * delta will be 0, because it's a new connection! */ be13::tcp_seq isn = syn_set ? seq : seq-1; tcp = create_tcpip(this_flow, isn, pi); tcp->myflow.session_id = uid; } /* Now tcp is valid */ tcp->myflow.tlast = pi.ts; // most recently seen packet tcp->last_packet_number = packet_counter++; tcp->myflow.len += pi.pcap_hdr->len; tcp->myflow.caplen += pi.pcap_hdr->caplen; tcp->myflow.packet_count++; // Does not seem consitent => Print a notice // See also https://stackoverflow.com/q/1491660 if(pi.pcap_hdr->caplen != pi.pcap_hdr->len){ DEBUG(2)("Captured packet has a length caplen=%d different " "from the un-truncated length len=%d provided by PCAP API", pi.pcap_hdr->caplen, pi.pcap_hdr->len); } /* * 2012-10-24 slg - the first byte is sent at SEQ==ISN+1. * The first byte in POSIX files have an LSEEK of 0. * The original code overcame this issue by introducing an intentional off-by-one * error with the statement tcp->isn++. * * With the new TCP state-machine we simply follow the spec. * * The new state machine works by examining the SYN and ACK packets * in accordance with the TCP spec. */ if(syn_set){ /* If the syn is set this is either a SYN or SYN-ACK. We use this information to set the direction * flag, but that's it. The direction flag is only used for coloring. */ if(tcp->syn_count>1){ DEBUG(2)("Multiple SYNs (%d) seen on connection %s",tcp->syn_count,tcp->flow_pathname.c_str()); } tcp->syn_count++; if( !ack_set ){ DEBUG(50) ("packet is handshake SYN"); /* First packet of three-way handshake */ tcp->dir = tcpip::dir_cs; // client->server } else { DEBUG(50) ("packet is handshake SYN/ACK"); /* second packet of three-way handshake */ tcp->dir = tcpip::dir_sc; // server->client } if(tcp_datalen>0){ tcp->violations++; DEBUG(1) ("TCP PROTOCOL VIOLATION: SYN with data! (length=%d)",(int)tcp_datalen); } } if(tcp_datalen==0) DEBUG(50) ("got TCP segment with no data"); // seems pointless to notify /* process any data. * Notice that this typically won't be called for the SYN or SYN/ACK, * since they both have no data by definition. */ if (tcp_datalen>0){ if (opt.console_output) { tcp->print_packet(tcp_data, tcp_datalen); } else { if (opt.store_output){ bool new_file = false; if (tcp->fd < 0) new_file = true; tcp->store_packet(tcp_data, tcp_datalen, delta,pi.ts); if(new_file && tcp_alert_fd>=0){ std::stringstream ss; ss << "open\t" << tcp->flow_pathname.c_str() << "\n"; const std::string &sso = ss.str(); if(write(tcp_alert_fd,sso.c_str(),sso.size())!=(int)sso.size()){ perror("write"); } } } } } if (rst_set){ remove_flow(this_flow); // take it out of the map return 0; } /* Count the FINs. * If this is a fin, determine the size of the stream */ if (fin_set){ tcp->fin_count++; if(tcp->fin_count==1){ tcp->fin_size = (seq+tcp_datalen-tcp->isn)-1; } } else { open_flows.move_to_end(tcp); } /* If a fin was sent and we've seen all of the bytes, close the stream */ DEBUG(50)("%d>0 && %d == %d",tcp->fin_count,tcp->seen_bytes(),tcp->fin_size); if (tcp->fin_count>0 && tcp->seen_bytes() == tcp->fin_size){ DEBUG(50)("all bytes have been received; removing flow"); remove_flow(this_flow); // take it out of the map } DEBUG(50)("fin_set=%d seq=%u fin_count=%d seq_count=%d len=%d isn=%u", fin_set,seq,tcp->fin_count,tcp->syn_count,(int)tcp_datalen,tcp->isn); return 0; // successfully processed } #pragma GCC diagnostic warning "-Wcast-align" /* This is called when we receive an IPv4 datagram. We make sure that * it's valid and contains a TCP segment; if so, we pass it to * process_tcp() for further processing. * * Note: we currently don't know how to handle IP fragments. */ #pragma GCC diagnostic ignored "-Wcast-align" int tcpdemux::process_ip4(const be13::packet_info &pi) { /* make sure that the packet is at least as long as the min IP header */ if (pi.ip_datalen < sizeof(struct be13::ip4)) { DEBUG(6) ("received truncated IP datagram!"); return -1; // couldn't process } const struct be13::ip4 *ip_header = (struct be13::ip4 *) pi.ip_data; DEBUG(100)("process_ip4. caplen=%d vlan=%d ip_p=%d",(int)pi.pcap_hdr->caplen,(int)pi.vlan(),(int)ip_header->ip_p); if(debug>200){ sbuf_t sbuf(pos0_t(),(const uint8_t *)pi.ip_data,pi.ip_datalen,pi.ip_datalen,0,false, false,false); sbuf.hex_dump(std::cerr); } /* for now we're only looking for TCP; throw away everything else */ if (ip_header->ip_p != IPPROTO_TCP) { DEBUG(50) ("got non-TCP frame -- IP proto %d", ip_header->ip_p); return -1; // couldn't process } /* check and see if we got everything. NOTE: we must use * ip_total_len after this, because we may have captured bytes * beyond the end of the packet (e.g. ethernet padding). */ size_t ip_len = ntohs(ip_header->ip_len); if (pi.ip_datalen < ip_len) { DEBUG(6) ("warning: captured only %ld bytes of %ld-byte IP datagram", (long) pi.ip_datalen, (long) ip_len); } /* XXX - throw away everything but fragment 0; this version doesn't * know how to do fragment reassembly. */ if (ntohs(ip_header->ip_off) & 0x1fff) { DEBUG(2) ("warning: throwing away IP fragment from X to X"); return -1; } /* figure out where the IP header ends */ size_t ip_header_len = ip_header->ip_hl * 4; /* make sure there's some data */ if (ip_header_len > ip_len) { DEBUG(6) ("received truncated IP datagram!"); return -1; } /* do TCP processing, faking an ipv6 address */ uint16_t ip_payload_len = pi.ip_datalen - ip_header_len; ipaddr src(ip_header->ip_src.addr); ipaddr dst(ip_header->ip_dst.addr); return (this->*tcp_processor)(src, dst ,AF_INET, pi.ip_data + ip_header_len, ip_payload_len,pi); } #pragma GCC diagnostic warning "-Wcast-align" /* This is called when we receive an IPv6 datagram. * * Note: we don't support IPv6 extended headers */ /* These might be defined from an include file, so undef them to be sure */ int tcpdemux::process_ip6(const be13::packet_info &pi) { /* make sure that the packet is at least as long as the IPv6 header */ if (pi.ip_datalen < sizeof(struct be13::ip6_hdr)) { DEBUG(6) ("received truncated IPv6 datagram!"); return -1; } const struct be13::ip6_hdr *ip_header = (struct be13::ip6_hdr *) pi.ip_data; /* for now we're only looking for TCP; throw away everything else */ if (ip_header->ip6_ctlun.ip6_un1.ip6_un1_nxt != IPPROTO_TCP) { DEBUG(50) ("got non-TCP frame -- IP proto %d", ip_header->ip6_ctlun.ip6_un1.ip6_un1_nxt); return -1; } /* do TCP processing */ uint16_t ip_payload_len = ntohs(ip_header->ip6_ctlun.ip6_un1.ip6_un1_plen); ipaddr src(ip_header->ip6_src.addr.addr8); ipaddr dst(ip_header->ip6_dst.addr.addr8); return (this->*tcp_processor)(src, dst ,AF_INET6, pi.ip_data + sizeof(struct be13::ip6_hdr), ip_payload_len,pi); } /* This is called when we receive an IPv4 or IPv6 datagram. * This function calls process_ip4 or process_ip6 * Returns 0 if packet is processed, 1 if it is not processed, -1 if error. */ #pragma GCC diagnostic ignored "-Wcast-align" int tcpdemux::process_pkt(const be13::packet_info &pi) { DEBUG(10)("process_pkt.............................................................................."); int r = 1; // not processed yet switch(pi.ip_version()){ case 4: r = process_ip4(pi); break; case 6: r = process_ip6(pi); break; } if(r!=0){ // packet not processed? /* Write the packet if we didn't process it */ if(pwriter) pwriter->writepkt(pi.pcap_hdr,pi.pcap_data); } /* Process the timeout, if there is any */ if(tcp_timeout){ /* Get a list of the flows that need to be closed. */ std::vector to_close; for(flow_map_t::iterator it = flow_map.begin(); it!=flow_map.end(); it++){ tcpip &tcp = *(it->second); uint32_t age = pi.ts.tv_sec - tcp.myflow.tlast.tv_sec; if (age > tcp_timeout){ to_close.push_back(&tcp.myflow); } } /* Close them. This removes the flows from the flow_map(), which is why we need * to create the list first. */ for(std::vector::iterator it = to_close.begin(); it!=to_close.end(); it++){ remove_flow(*(*it)); } } return r; } #pragma GCC diagnostic warning "-Wcast-align" tcpflow-tcpflow-1.6.1/src/tcpdemux.h000066400000000000000000000213261401360461700174500ustar00rootroot00000000000000#ifndef TCPDEMUX_H #define TCPDEMUX_H /** * tcpdemux.h * * a tcpip demultiplier. * * Defines the basic classes used by the tcpflow program. This includes: * - IP, TCP and UDP structures * - class ipaddr - IP address (IPv4 and IPv6) * - class flow_addr - The flow address (source addr & port; dest addr & port; family) * - class flow - All of the information for a flow that's being tracked * - class tcp_header_t - convenience class for working with TCP headers * - class tcpip - A one-sided TCP implementation * - class tcpdemux - Processes individual packets, identifies flows, * and creates tcpip objects as required */ #include "pcap_writer.h" #include "dfxml/src/dfxml_writer.h" #include "dfxml/src/hash_t.h" #if defined(HAVE_SQLITE3_H) #include #endif #if defined(HAVE_UNORDERED_MAP) # include # include # undef HAVE_TR1_UNORDERED_MAP // be sure we don't use it #else # if defined(HAVE_TR1_UNORDERED_MAP) # include # include # else # error Requires or # endif #endif #include #include "intrusive_list.h" /** * the tcp demultiplixer * This is a singleton class; we only need a single demultiplexer. */ class tcpdemux { /* see http://mikecvet.wordpress.com/tag/hashing/ */ typedef struct { long operator() (const flow_addr &k) const {return k.hash(); } } flow_addr_hash; typedef struct { bool operator() (const flow_addr &x, const flow_addr &y) const { return x==y;} } flow_addr_key_eq; #ifdef HAVE_TR1_UNORDERED_MAP typedef std::tr1::unordered_map flow_map_t; // active flows typedef std::tr1::unordered_map saved_flow_map_t; // flows that have been saved typedef std::tr1::unordered_map sparse_saved_flow_map_t; // flows ctxt caching for pcap dissection #else typedef std::unordered_map flow_map_t; // active flows typedef std::unordered_map saved_flow_map_t; // flows that have been saved typedef std::unordered_map sparse_saved_flow_map_t; // flows ctxt caching for pcap dissection #endif typedef std::vector saved_flows_t; // needs to be ordered tcpdemux(); #ifdef HAVE_SQLITE3 sqlite3 *db; sqlite3_stmt *insert_flow; #endif pcap_writer *flow_sorter; /* facility logic hinge */ int (tcpdemux::*tcp_processor)(const ipaddr &src, const ipaddr &dst,sa_family_t family, const u_char *tcp_data, uint32_t tcp_length, const be13::packet_info &pi); public: static uint32_t tcp_timeout; static std::string tcp_cmd; // command to run on each tcp flow static int tcp_subproc_max; // how many subprocesses are we allowed? static int tcp_subproc; // how many do we currently have? static int tcp_alert_fd; static unsigned int get_max_fds(void); // returns the max virtual ~tcpdemux(){ delete xreport; delete pwriter; } /* The pure options class means we can add new options without having to modify the tcpdemux constructor. */ class options { public:; enum { MAX_SEEK=1024*1024*16 }; options():console_output(false),console_output_nonewline(false), store_output(true),opt_md5(false), post_processing(false),gzip_decompress(true), max_bytes_per_flow(-1), max_flows(0),suppress_header(0), output_strip_nonprint(true),output_json(false), output_pcap(false),output_hex(false),use_color(0), output_packet_index(false),max_seek(MAX_SEEK) { } bool console_output; bool console_output_nonewline; bool store_output; // do we output? bool opt_md5; // do we calculate MD5 on DFXML output? bool post_processing; // decode headers after tcp connection closes bool gzip_decompress; int64_t max_bytes_per_flow; uint32_t max_flows; bool suppress_header; bool output_strip_nonprint; bool output_json; bool output_pcap; bool output_hex; bool use_color; bool output_packet_index; // Generate a packet index file giving the timestamp and location // bytes written to the flow file. int32_t max_seek; // signed becuase we compare with abs() }; enum { WARN_TOO_MANY_FILES=10000}; // warn if more than this number of files in a directory std::string outdir; /* output directory */ uint64_t flow_counter; // how many flows have we seen? uint64_t packet_counter; // monotomically increasing dfxml_writer *xreport; // DFXML output file pcap_writer *pwriter; // where we should write packets unsigned int max_open_flows; // how large did it ever get? unsigned int max_fds; // maximum number of file descriptors for this tcpdemux uint64_t unique_id; // next unique id to assign flow_map_t flow_map; // db of open tcpip objects, indexed by flow intrusive_list open_flows; // the tcpip flows with open files in access order saved_flow_map_t saved_flow_map; // db of saved flows, indexed by flow sparse_saved_flow_map_t flow_fd_cache_map; // db caching saved flows descriptors, indexed by flow saved_flows_t saved_flows; // the flows that were saved bool start_new_connections; // true if we should start new connections options opt; class feature_recorder_set *fs; // where features extracted from each flow should be stored static uint32_t max_saved_flows; // how many saved flows are kept in the saved_flow_map void alter_processing_core(); static tcpdemux *getInstance(); /* Databse */ void openDB(); // open the database file if we are using it in outdir directory. void write_flow_record(const std::string &starttime,const std::string &endtime, const std::string &src_ipn,const std::string &dst_ipn, const std::string &mac_daddr,const std::string &mac_saddr, uint64_t packets,uint16_t srcport,uint16_t dstport, const std::string &hashdigest_md5); void save_unk_packets(const std::string &wfname,const std::string &ifname); // save unknown packets at this location void post_process(tcpip *tcp); // just before closing; writes XML and closes fd /* management of open fds and in-process tcpip flows*/ void close_tcpip_fd(tcpip *); void close_oldest_fd(); void remove_flow(const flow_addr &flow); // remove a flow from the database, closing open files if necessary void remove_all_flows(); // stop processing all tcpip connections /* open a new file, closing an fd in the openflow database if necessary */ int retrying_open(const std::string &filename,int oflag,int mask); /* the flow database holds in-process tcpip connections */ tcpip *create_tcpip(const flow_addr &flow, be13::tcp_seq isn, const be13::packet_info &pi); tcpip *find_tcpip(const flow_addr &flow); /* saved flows are completed flows that we remember in case straggling packets * show up. Remembering the flows lets us resolve the packets rather than creating * new flows. */ void save_flow(tcpip *); /** packet processing. * Each returns 0 if processed, 1 if not processed, -1 if error. */ int process_tcp(const ipaddr &src, const ipaddr &dst,sa_family_t family, const u_char *tcp_data, uint32_t tcp_length, const be13::packet_info &pi); int dissect_tcp(const ipaddr &src, const ipaddr &dst,sa_family_t family, const u_char *tcp_data, uint32_t tcp_length, const be13::packet_info &pi); int process_ip4(const be13::packet_info &pi); int process_ip6(const be13::packet_info &pi); int process_pkt(const be13::packet_info &pi); private:; /* These are not implemented */ tcpdemux(const tcpdemux &t); tcpdemux &operator=(const tcpdemux &that); }; #endif tcpflow-tcpflow-1.6.1/src/tcpflow.cpp000066400000000000000000001041621401360461700176300ustar00rootroot00000000000000/* * This file is part of tcpflow by Simson Garfinkel . * Originally by Jeremy Elson . * * This source code is under the GNU Public License (GPL) version 3. * See COPYING for details. * */ #define __MAIN_C__ #include "config.h" #include "tcpflow.h" #include "tcpip.h" #include "tcpdemux.h" #include "bulk_extractor_i.h" #include "iptree.h" #include "be13_api/utils.h" #include #include #include #include #include // getopt_long() #ifdef HAVE_GRP_H # include // initgroups() #endif /* bring in inet_ntop if it is not present */ #define ETH_ALEN 6 #ifndef HAVE_INET_NTOP #include "inet_ntop.c" #endif #ifdef HAVE_CAP_NG_H #include #endif /* droproot is from tcpdump. * See https://github.com/the-tcpdump-group/tcpdump/blob/master/tcpdump.c#L611 */ const char *program_name = 0; const char *tcpflow_droproot_username = 0; const char *tcpflow_chroot_dir = 0; int packet_buffer_timeout = 10; scanner_info::scanner_config be_config; // system configuration typedef struct { const char *name; const char *dvalue; const char *help; } default_t; default_t defaults[] = { {"tdelta","0","Time delta in seconds"}, {"packet-buffer-timeout", "10", "Time in milliseconds between each callback from libpcap"}, {0,0,0} }; #ifdef HAVE_NETINET_IP_H #include #endif const char *progname = 0; // name of the program int debug = DEFAULT_DEBUG_LEVEL; // global variable, not clear why /* semaphore prevents multiple copies from outputing on top of each other */ #ifdef HAVE_PTHREAD_H #include sem_t *semlock = 0; #endif #define DEFAULT_REPORT_FILENAME "report.xml" /**************************************************************** *** SCANNER PLUG-IN SYSTEM ****************************************************************/ scanner_t *scanners_builtin[] = { scan_md5, scan_http, scan_netviz, // removed scan_python becasue it does not support Python 3 // scan_python, scan_tcpdemux, #ifdef USE_WIFI scan_wifiviz, #endif 0}; bool opt_no_promisc = false; // true if we should not use promiscious mode /* Long options! * * We need more long options; developers looking at this file should * feel free to submit more! */ static const struct option longopts[] = { { "chroot", required_argument, NULL, 'z' }, { "help", no_argument, NULL, 'h' }, { "relinquish-privileges", required_argument, NULL, 'U' }, { "verbose", no_argument, NULL, 'v' }, { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 } }; /**************************************************************** *** USAGE ****************************************************************/ static void usage(int level) { std::cout << PACKAGE_NAME << " version " << PACKAGE_VERSION << "\n\n"; std::cout << "usage: " << progname << " [-aBcCDhIpsvVZ] [-b max_bytes] [-d debug_level] \n"; std::cout << " [-[eE] scanner] [-f max_fds] [-F[ctTXMkmg]] [-h|--help] [-i iface]\n"; std::cout << " [-l files...] [-L semlock] [-m min_bytes] [-o outdir] [-r file] [-R file]\n"; std::cout << " [-S name=value] [-T template] [-U|--relinquish-privileges user] [-v|--verbose]\n"; std::cout << " [-w file] [-x scanner] [-X xmlfile] [-z|--chroot dir] [expression]\n\n"; std::cout << " -a: do ALL post-processing.\n"; std::cout << " -b max_bytes: max number of bytes per flow to save\n"; std::cout << " -d debug_level: debug level; default is " << DEFAULT_DEBUG_LEVEL << "\n"; std::cout << " -f: maximum number of file descriptors to use\n"; std::cout << " -h: print this help message (-hh for more help)\n"; std::cout << " -H: print detailed information about each scanner\n"; std::cout << " -i: network interface on which to listen\n"; std::cout << " -I: write for each flow another file *.findx to provide byte-indexed timestamps\n"; std::cout << " -g: output each flow in alternating colors (note change!)\n"; std::cout << " -l: treat non-flag arguments as input files rather than a pcap expression\n"; std::cout << " -L semlock - specifies that writes are locked using a named semaphore\n"; std::cout << " -p: don't use promiscuous mode\n"; std::cout << " -q: quiet mode - do not print warnings\n"; std::cout << " -r file : read packets from tcpdump pcap file (may be repeated)\n"; std::cout << " -R file : read packets from tcpdump pcap file TO FINISH CONNECTIONS\n"; std::cout << " -v : verbose operation equivalent to -d 10\n"; std::cout << " -V : print version number and exit\n"; std::cout << " -w file : write packets not processed to file\n"; std::cout << " -o outdir : specify output directory (default '.')\n"; std::cout << " -X filename : DFXML output to filename\n"; std::cout << " -m bytes : specifies skip that starts a new stream (default " << (unsigned)tcpdemux::options::MAX_SEEK << ").\n"; std::cout << " -F{p} : filename prefix/suffix (-hh for options)\n"; std::cout << " -T{t} : filename template (-hh for options; default " << flow::filename_template << ")\n"; std::cout << " -Z do not decompress gzip-compressed HTTP transactions\n"; std::cout << " -K: output|keep pcap flow structure.\n"; std::cout << "\nSecurity:\n"; std::cout << " -U user relinquish privleges and become user (if running as root)\n"; std::cout << " -z dir chroot to dir (requires that -U be used).\n"; std::cout << "\nControl of Scanners:\n"; std::cout << " -E scanner - turn off all scanners except scanner\n"; std::cout << " -S name=value Set a configuration parameter (-hh for info)\n"; if(level > 1) { std::cout << "\n" "Activated options -S name=value:"; for(int i=0;defaults[i].name;i++){ std::cout <<"\n -S "<< defaults[i].name << "=" << defaults[i].dvalue <<'\t'<< defaults[i].help; } std::cout << '\n'; be13::plugin::info_scanners(false,true,scanners_builtin,'e','x'); } std::cout << "\n" "Console output options:\n"; std::cout << " -B: binary output, even with -c or -C (normally -c or -C turn it off)\n"; std::cout << " -c: console print only (don't create files)\n"; std::cout << " -C: console print only, but without the display of source/dest header\n"; std::cout << " -0: don't print newlines after packets when printing to console\n"; std::cout << " -s: strip non-printable characters (change to '.')\n"; std::cout << " -J: output json format.\n"; std::cout << " -D: output in hex (useful to combine with -c or -C)\n"; std::cout << "\n"; #ifndef HAVE_LIBCAIRO std::cout << "Rendering not available because Cairo was not installed.\n\n"; #endif std::cout << "expression: tcpdump-like filtering expression\n"; std::cout << "\nSee the man page for additional information.\n\n"; if(level<2) return; std::cout << "Filename Prefixes:\n"; std::cout << " -Fc : append the connection counter to ALL filenames\n"; std::cout << " -Ft : prepend the time_t UTC timestamp to ALL filenames\n"; std::cout << " -FT : prepend the ISO8601 UTC timestamp to ALL filenames\n"; std::cout << " -FX : Do not output any files (other than report files)\n"; std::cout << " -FM : Calculate the MD5 for every flow (stores in DFXML)\n"; std::cout << " -Fk : Bin output in 1K directories\n"; std::cout << " -Fm : Bin output in 1M directories (2 levels)\n"; std::cout << " -Fg : Bin output in 1G directories (3 levels)\n"; flow::usage(); std::cout << "\n" "Current limitations:" "\n" " get_max_fds() = " << tcpdemux::getInstance()->get_max_fds(); std::cout << "\n" " NUM_RESERVED_FDS = " << NUM_RESERVED_FDS; std::cout << '\n'; } /** * Create the dfxml output */ static void dfxml_create(class dfxml_writer &xreport,int argc,char * const *argv) { xreport.push("dfxml","xmloutputversion='1.0'"); xreport.push("metadata", "\n xmlns='http://afflib.org/tcpflow/' " "\n xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' " "\n xmlns:dc='http://purl.org/dc/elements/1.1/'" ); xreport.xmlout("dc:type","Feature Extraction","",false); xreport.pop(); xreport.add_DFXML_creator(PACKAGE_NAME,PACKAGE_VERSION,"","command line to be provided"); } /* String replace. Perhaps not the most efficient, but it works */ void replace(std::string &str,const std::string &from,const std::string &to) { if(from.size()==0) return; bool changed = false; std::stringstream ss; for(unsigned int i=0;i // transparent decompression for process_infile class inflater { const std::string suffix; const std::string invoc_format; public: inflater(const std::string &suffix_, const std::string &invoc_format_) : suffix(suffix_), invoc_format(invoc_format_) {} // is this inflater appropriate for a given file? bool appropriate(const std::string &file_path) const { return ends_with(file_path,suffix); } // invoke the inflater in a shell, and return the file descriptor to read the inflated file from int invoke(const std::string &file_path, int* ppid) const { std::string invocation = ssprintf(invoc_format.c_str(), file_path.c_str()); int pipe_fds[2]; if(!system(NULL)) { std::cerr << "no shell available to decompress '" << file_path << "'" << std::endl; return -1; } if(pipe(pipe_fds)) { std::cerr << "failed to create pipe to decompress '" << file_path << "'" << std::endl; return -1; } pid_t child_pid; child_pid = fork(); if(child_pid == -1) { std::cerr << "failed to fork child to decompress '" << file_path << "'" << std::endl; return -1; } if(child_pid == 0) { // decompressor close(pipe_fds[0]); dup2(pipe_fds[1], 1); if(system(invocation.c_str())) { std::cerr << "decompressor reported error inflating '" << file_path << "'" << std::endl; exit(1); } exit(0); } *ppid = child_pid; close(pipe_fds[1]); return pipe_fds[0]; } }; typedef std::vector inflaters_t; static inflaters_t *build_inflaters() { inflaters_t *output = new inflaters_t(); // gzip output->push_back(new inflater(".gz", "gunzip -c '%s'")); // zip output->push_back(new inflater(".zip", "unzip -p '%s'")); // bz2 output->push_back(new inflater(".bz2", "bunzip2 -c '%s'")); // xz output->push_back(new inflater(".xz", "unxz -c '%s'")); // lzma output->push_back(new inflater(".lzma", "unlzma -c '%s'")); return output; } #define HAVE_INFLATER #endif // https://github.com/the-tcpdump-group/tcpdump/blob/master/tcpdump.c#L611 #ifndef _WIN32 /* Drop root privileges and chroot if necessary */ static void droproot(tcpdemux &demux,const char *username, const char *chroot_dir) { struct passwd *pw = NULL; if (chroot_dir && !username) { fprintf(stderr, "%s: Chroot without dropping root is insecure\n", program_name); exit(1); } pw = getpwnam(username); if (pw) { /* Begin tcpflow add */ if(demux.xreport){ const char *outfilename = demux.xreport->get_outfilename().c_str(); if(chown(outfilename,pw->pw_uid,pw->pw_gid)){ fprintf(stderr, "%s: Coudln't change owner of '%.64s' to %s (uid %d): %s\n", program_name, outfilename, username, pw->pw_uid, strerror(errno)); exit(1); } } /* end tcpflow add */ if (chroot_dir) { if (chroot(chroot_dir) != 0 || chdir ("/") != 0) { fprintf(stderr, "%s: Couldn't chroot/chdir to '%.64s': %s\n", program_name, chroot_dir, pcap_strerror(errno)); exit(1); } } #ifdef HAVE_LIBCAP_NG { int ret = capng_change_id(pw->pw_uid, pw->pw_gid, CAPNG_NO_FLAG); if (ret < 0) { fprintf(stderr, "error : ret %d\n", ret); } else { fprintf(stderr, "dropped privs to %s\n", username); } } #else if (initgroups(pw->pw_name, pw->pw_gid) != 0 || setgid(pw->pw_gid) != 0 || setuid(pw->pw_uid) != 0) { fprintf(stderr, "%s: Couldn't change to '%.32s' uid=%lu gid=%lu: %s\n", program_name, username, (unsigned long)pw->pw_uid, (unsigned long)pw->pw_gid, pcap_strerror(errno)); exit(1); } else { fprintf(stderr, "dropped privs to %s\n", username); } #endif /* HAVE_LIBCAP_NG */ } else { fprintf(stderr, "%s: Couldn't find user '%.32s'\n", program_name, username); exit(1); } #ifdef HAVE_LIBCAP_NG /* We don't need CAP_SETUID, CAP_SETGID and CAP_SYS_CHROOT any more. */ capng_updatev( CAPNG_DROP, (capng_type_t)(CAPNG_EFFECTIVE | CAPNG_PERMITTED), CAP_SETUID, CAP_SETGID, CAP_SYS_CHROOT, -1); capng_apply(CAPNG_SELECT_BOTH); #endif /* HAVE_LIBCAP_NG */ } #endif /* _WIN32 */ /** * Perform the droproot operation for tcpflow. This needs to be called immediately after pcap_open() */ void tcpflow_droproot(tcpdemux &demux) { if (tcpflow_droproot_username){ droproot(demux,tcpflow_droproot_username,tcpflow_chroot_dir); } } /* * process an input file or device * May be repeated. * If start is false, do not initiate new connections * Return 0 on success or -1 on error */ #ifdef HAVE_INFLATER static inflaters_t *inflaters = 0; #endif static int process_infile(tcpdemux &demux,const std::string &expression,std::string &device,const std::string &infile) { char error[PCAP_ERRBUF_SIZE]; int dlt=0; pcap_handler handler; int waitfor = -1; int pipefd = -1; #ifdef HAVE_INFLATER if(inflaters==0) inflaters = build_inflaters(); #endif if (infile!=""){ std::string file_path = infile; // decompress input if necessary #ifdef HAVE_INFLATER for(inflaters_t::const_iterator it = inflaters->begin(); it != inflaters->end(); it++) { if((*it)->appropriate(infile)) { pipefd = (*it)->invoke(infile, &waitfor); if(pipefd < 0) { std::cerr << "decompression of '" << infile << "' failed: " << strerror (errno) << std::endl; exit(1); } file_path = ssprintf("/dev/fd/%d", pipefd); if(access(file_path.c_str(), R_OK)) { std::cerr << "decompression of '" << infile << "' is not available on this system" << std::endl; exit(1); } break; } } #endif if ((pd = pcap_open_offline(file_path.c_str(), error)) == NULL){ /* open the capture file */ die("%s", error); } tcpflow_droproot(demux); // drop root if requested dlt = pcap_datalink(pd); /* get the handler for this kind of packets */ handler = find_handler(dlt, infile.c_str()); } else { /* if the user didn't specify a device, try to find a reasonable one */ if (device.empty()){ #ifdef HAVE_PCAP_FINDALLDEVS char errbuf[PCAP_ERRBUF_SIZE]; pcap_if_t *alldevs = 0; if (pcap_findalldevs(&alldevs,errbuf)){ die("%s", errbuf); } if (alldevs == 0) { die("found 0 devices, maybe you don't have permissions, switch to root or equivalent user instead."); } device.assign(alldevs[0].name); pcap_freealldevs(alldevs); #else const char* dev = pcap_lookupdev(error); if (dev == NULL) die("%s", error); device.assign(dev); #endif } /* make sure we can open the device */ if ((pd = pcap_open_live(device.c_str(), SNAPLEN, !opt_no_promisc, packet_buffer_timeout, error)) == NULL){ die("%s", error); } tcpflow_droproot(demux); // drop root if requested /* get the handler for this kind of packets */ dlt = pcap_datalink(pd); handler = find_handler(dlt, device.c_str()); } DEBUG(20) ("filter expression: '%s'",expression.c_str()); /* install the filter expression in libpcap */ struct bpf_program fcode; if (pcap_compile(pd, &fcode, expression.c_str(), 1, 0) < 0){ die("%s", pcap_geterr(pd)); } if (pcap_setfilter(pd, &fcode) < 0){ die("%s", pcap_geterr(pd)); } /* initialize our flow state structures */ /* set up signal handlers for graceful exit (pcap uses onexit to put * interface back into non-promiscuous mode */ portable_signal(SIGTERM, terminate); portable_signal(SIGINT, terminate); #ifdef SIGHUP portable_signal(SIGHUP, terminate); #endif /* start listening or reading from the input file */ if (infile == "") DEBUG(1) ("listening on %s", device.c_str()); int pcap_retval = pcap_loop(pd, -1, handler, (u_char *)tcpdemux::getInstance()); if (pcap_retval < 0 && pcap_retval != -2){ DEBUG(1) ("%s: %s", infile.c_str(),pcap_geterr(pd)); return -1; } pcap_close (pd); #ifdef HAVE_FORK if (waitfor != -1) { wait (0); } if (pipefd != -1) { close (pipefd); } #endif return 0; } /* be_hash. Currently this just returns the MD5 of the sbuf, * but eventually it will allow the use of different hashes. */ static std::string be_hash_name("md5"); static std::string be_hash_func(const uint8_t *buf,size_t bufsize) { if(be_hash_name=="md5" || be_hash_name=="MD5"){ return md5_generator::hash_buf(buf,bufsize).hexdigest(); } if(be_hash_name=="sha1" || be_hash_name=="SHA1" || be_hash_name=="sha-1" || be_hash_name=="SHA-1"){ return sha1_generator::hash_buf(buf,bufsize).hexdigest(); } if(be_hash_name=="sha256" || be_hash_name=="SHA256" || be_hash_name=="sha-256" || be_hash_name=="SHA-256"){ return sha256_generator::hash_buf(buf,bufsize).hexdigest(); } std::cerr << "Invalid hash name: " << be_hash_name << "\n"; std::cerr << "This version of bulk_extractor only supports MD5, SHA1, and SHA256\n"; exit(1); } static feature_recorder_set::hash_def be_hash(be_hash_name,be_hash_func); int main(int argc, char *argv[]) { int argc_original = argc; char **argv_original = argv; program_name = argv[0]; int opt_help = 0; int opt_Help = 0; feature_recorder::set_main_threadid(); sbuf_t::set_map_file_delimiter(""); // no delimiter on carving #ifdef BROKEN std::cerr << "WARNING: YOU ARE USING AN EXPERIMENTAL VERSION OF TCPFLOW \n"; std::cerr << "THAT DOES NOT WORK PROPERLY. PLEASE USE A RELEASE DOWNLOADED\n"; std::cerr << "FROM http://digitalcorpora.org/downloads/tcpflow\n"; std::cerr << "\n"; #endif bool opt_enable_report = true; bool force_binary_output = false; std::string device; // default device const char *lockname = 0; std::string reportfilename; std::vector Rfiles; // files for finishing std::vector rfiles; // files to read tcpdemux &demux = *tcpdemux::getInstance(); // the demux object we will be using. std::string command_line = dfxml_writer::make_command_line(argc,argv); std::string opt_unk_packets; bool opt_quiet = false; /* Set up debug system */ progname = argv[0]; init_debug(progname,1); /* Make sure that the system was compiled properly */ if(sizeof(struct be13::ip4)!=20 || sizeof(struct be13::tcphdr)!=20){ fprintf(stderr,"COMPILE ERROR.\n"); fprintf(stderr," sizeof(struct ip)=%d; should be 20.\n", (int)sizeof(struct be13::ip4)); fprintf(stderr," sizeof(struct tcphdr)=%d; should be 20.\n", (int)sizeof(struct be13::tcphdr)); fprintf(stderr,"CANNOT CONTINUE\n"); exit(1); } bool trailing_input_list = false; int arg; while ((arg = getopt_long(argc, argv, "aA:Bb:cCd:DE:e:E:F:f:gHhIi:lL:m:o:pqR:r:S:sT:U:Vvw:x:X:z:ZK0J", longopts, NULL)) != EOF) { switch (arg) { case 'a': demux.opt.post_processing = true; demux.opt.opt_md5 = true; be13::plugin::scanners_enable_all(); break; case 'A': fprintf(stderr,"-AH has been deprecated. Just use -a\n"); break; case 'b': demux.opt.max_bytes_per_flow = atoi(optarg); if(debug > 1) { std::cout << "capturing max of " << demux.opt.max_bytes_per_flow << " bytes per flow." << std::endl; } break; case 'B': force_binary_output = true; demux.opt.output_strip_nonprint = false; DEBUG(10) ("converting non-printable characters to '.'"); break; case 'C': demux.opt.console_output = true; DEBUG(10) ("printing packets to console only"); demux.opt.suppress_header = 1; DEBUG(10) ("packet header dump suppressed"); break; case 'c': demux.opt.console_output = true; DEBUG(10) ("printing packets to console only"); break; case '0': demux.opt.console_output_nonewline = true; break; case 'd': if ((debug = atoi(optarg)) < 0) { debug = DEFAULT_DEBUG_LEVEL; DEBUG(1) ("warning: -d flag with 0 debug level '%s'", optarg); } break; case 'D': demux.opt.output_hex = true;DEBUG(10) ("Console output in hex"); demux.opt.output_strip_nonprint = false; DEBUG(10) ("Will not convert non-printablesto '.'"); break; case 'E': be13::plugin::scanners_disable_all(); be13::plugin::scanners_enable(optarg); break; case 'e': be13::plugin::scanners_enable(optarg); demux.opt.post_processing = true; // enable post processing if anything is turned on break; case 'F': for(const char *cc=optarg;*cc;cc++){ switch(*cc){ case 'c': replace(flow::filename_template,"%c","%C"); break; case 'k': flow::filename_template = "%K/" + flow::filename_template; break; case 'm': flow::filename_template = "%M000-%M999/%M%K/" + flow::filename_template; break; case 'g': flow::filename_template = "%G000000-%G999999/%G%M000-%G%M999/%G%M%K/" + flow::filename_template; break; case 't': flow::filename_template = "%tT" + flow::filename_template; break; case 'T': flow::filename_template = "%T" + flow::filename_template; break; case 'X': demux.opt.store_output = false;break; case 'M': demux.opt.opt_md5 = true;break; default: fprintf(stderr,"-F invalid format specification '%c'\n",*cc); } } break; case 'f': { int mnew = atoi(optarg); DEBUG(1)("changing max_fds from %d to %d",demux.max_fds,mnew); demux.max_fds = mnew; break; } case 'i': device = std::string(optarg); break; case 'I': DEBUG(10) ("creating packet index files"); demux.opt.output_packet_index = true; break; case 'g': demux.opt.use_color = 1; DEBUG(10) ("using colors"); break; case 'l': trailing_input_list = true; break; case 'J': demux.opt.output_json = true; break; case 'K':; demux.opt.output_pcap = true; demux.alter_processing_core(); break; case 'L': lockname = optarg; break; case 'm': demux.opt.max_seek = atoi(optarg); DEBUG(10) ("max_seek set to %d",demux.opt.max_seek); break; case 'o': demux.outdir = optarg; flow::outdir = optarg; break; case 'p': opt_no_promisc = true; DEBUG(10) ("NOT turning on promiscuous mode"); break; case 'q': opt_quiet = true; break; case 'R': Rfiles.push_back(optarg); break; case 'r': rfiles.push_back(optarg); break; case 'S': { std::vector params = split(optarg,'='); if(params.size()!=2){ std::cerr << "Invalid paramter: " << optarg << "\n"; exit(1); } be_config.namevals[params[0]] = params[1]; continue; } case 's': demux.opt.output_strip_nonprint = 1; DEBUG(10) ("converting non-printable characters to '.'"); break; case 'T': flow::filename_template = optarg; if(flow::filename_template.find("%c")==std::string::npos){ flow::filename_template += std::string("%C%c"); // append %C%c if not present } break; case 'U': tcpflow_droproot_username = optarg; break; case 'V': std::cout << PACKAGE_NAME << " " << PACKAGE_VERSION << "\n"; exit (1); case 'v': debug = 10; break; case 'w': opt_unk_packets = optarg;break; case 'x': be13::plugin::scanners_disable(optarg);break; case 'X': reportfilename = optarg;break; case 'z': tcpflow_chroot_dir = optarg; break; case 'Z': demux.opt.gzip_decompress = 0; break; case 'H': opt_Help += 1; break; case 'h': opt_help += 1; break; default: DEBUG(1) ("error: unrecognized switch '%c'", arg); opt_help += 1; break; } } if(tcpflow_chroot_dir && !tcpflow_droproot_username){ err(1,"-z option requires -U option"); } argc -= optind; argv += optind; /* Load all the scanners and enable the ones we care about */ scanner_info si; si.config = &be_config; si.get_config("enable_report",&opt_enable_report,"Enable report.xml"); be13::plugin::load_scanners(scanners_builtin,be_config); if(opt_Help){ be13::plugin::info_scanners(true,true,scanners_builtin,'e','x'); exit(0); } if(opt_help) { usage(opt_help); exit(0); } if(demux.opt.post_processing && !demux.opt.store_output){ std::cerr << "ERROR: post_processing currently requires storing output.\n"; exit(1); } if(demux.opt.opt_md5) be13::plugin::scanners_enable("md5"); be13::plugin::scanners_process_enable_disable_commands(); /* If there is no report filename, call it report.xml in the output directory */ if( reportfilename.size()==0 ){ reportfilename = demux.outdir + "/" + DEFAULT_REPORT_FILENAME; } /* remaining arguments are either an input list (-l flag) or a pcap expression (default) */ std::string expression = ""; if(trailing_input_list) { for(int ii = 0; ii < argc; ii++) { rfiles.push_back(argv[ii]); } } else { /* get the user's expression out of remainder of the arg... */ for(int i=0;i0) expression+=" "; expression += argv[i]; } } /* More option processing */ /* was a semaphore provided for the lock? */ if(lockname){ #if defined(HAVE_SEMAPHORE_H) && defined(HAVE_PTHREAD_H) semlock = sem_open(lockname,O_CREAT,0777,1); // get the semaphore #else fprintf(stderr,"%s: attempt to create lock pthreads not present\n",argv[0]); exit(1); #endif } if(force_binary_output) demux.opt.output_strip_nonprint = false; /* make sure outdir is a directory. If it isn't, try to make it.*/ struct stat stbuf; if(stat(demux.outdir.c_str(),&stbuf)==0){ if(!S_ISDIR(stbuf.st_mode)){ std::cerr << "outdir is not a directory: " << demux.outdir << "\n"; exit(1); } } else { if(MKDIR(demux.outdir.c_str(),0777)){ std::cerr << "cannot create " << demux.outdir << ": " << strerror(errno) << "\n"; exit(1); } } std::string input_fname; if(rfiles.size() > 0) { input_fname = rfiles.at(0); if(rfiles.size() > 1) { input_fname += ssprintf(" + %d more", rfiles.size() - 1); } } /* report file specified? If so, open it. * Note: If we are going to chroot, we need apply the chroot prefix also, * but we need to open the file *now*. */ if(reportfilename.size()>0 && opt_enable_report){ if (tcpflow_chroot_dir){ reportfilename = std::string(tcpflow_chroot_dir) + std::string("/") + reportfilename; } std::cerr << "reportfilename: " << reportfilename << "\n"; xreport = new dfxml_writer(reportfilename,false); dfxml_create(*xreport,argc_original,argv_original); demux.xreport = xreport; } if(opt_unk_packets.size()>0){ if(input_fname.size()==0){ std::cerr << "currently the -w option requires the -r option\n"; exit(1); } if(access(input_fname.c_str(),R_OK)) die("cannot read: %s: %s",input_fname.c_str(),strerror(errno)); demux.save_unk_packets(opt_unk_packets,input_fname); } /* Debug prefix set? */ std::string debug_prefix=progname; si.get_config("debug-prefix",&debug_prefix,"Prefix for debug output"); init_debug(debug_prefix.c_str(),0); DEBUG(10) ("%s version %s ", PACKAGE_NAME, PACKAGE_VERSION); const char *name = device.c_str(); if(input_fname.size()>0) name=input_fname.c_str(); if(name==0) name=""; feature_file_names_t feature_file_names; be13::plugin::get_scanner_feature_file_names(feature_file_names); feature_recorder_set fs(feature_recorder_set::NO_ALERT,be_hash,name,demux.outdir); fs.init(feature_file_names); the_fs = &fs; demux.fs = &fs; si.get_config("tdelta",&datalink_tdelta,"Time offset for packets"); si.get_config("packet-buffer-timeout", &packet_buffer_timeout, "Time in milliseconds between each callback from libpcap"); /* Record the configuration */ if(xreport){ xreport->push("configuration"); xreport->pop(); // configuration xreport->xmlout("tdelta",datalink_tdelta); } /* Process r files and R files */ int exit_val = 0; if(xreport){ xreport->push("configuration"); } if(rfiles.size()==0 && Rfiles.size()==0){ /* live capture */ demux.start_new_connections = true; int err = process_infile(demux,expression,device,""); if (err < 0) { exit_val = 1; } input_fname = device; } else { /* first pick up the new connections with -r */ demux.start_new_connections = true; for(std::vector::const_iterator it=rfiles.begin();it!=rfiles.end();it++){ int err = process_infile(demux,expression,device,*it); if (err < 0) { exit_val = 1; } } /* now pick up the outstanding connection with -R, but don't start new connections */ demux.start_new_connections = false; for(std::vector::const_iterator it=Rfiles.begin();it!=Rfiles.end();it++){ int err = process_infile(demux,expression,device,*it); if (err < 0) { exit_val = 1; } } } /* -1 causes pcap_loop to loop forever, but it finished when the input file is exhausted. */ DEBUG(2)("Open FDs at end of processing: %d",(int)demux.open_flows.size()); DEBUG(2)("demux.max_open_flows: %d",(int)demux.max_open_flows); DEBUG(2)("Flow map size at end of processing: %d",(int)demux.flow_map.size()); DEBUG(2)("Flows seen: %d",(int)demux.flow_counter); int open_fds = (int)demux.open_flows.size(); int flow_map_size = (int)demux.flow_map.size(); demux.remove_all_flows(); // empty the map to capture the state std::stringstream ss; be13::plugin::phase_shutdown(fs,xreport ? &ss : 0); /* * Note: funny formats below are a result of mingw problems with PRId64. */ const std::string total_flow_processed("Total flows processed: %" PRId64); const std::string total_packets_processed("Total packets processed: %" PRId64); DEBUG(2)(total_flow_processed.c_str(),demux.flow_counter); DEBUG(2)(total_packets_processed.c_str(),demux.packet_counter); if(xreport){ xreport->pop(); // fileobjects xreport->xmlout("summary",ss.str(),"",false); xreport->xmlout("open_fds_at_end",open_fds); xreport->xmlout("max_open_flows",demux.max_open_flows); xreport->xmlout("total_flows",demux.flow_counter); xreport->xmlout("flow_map_size",flow_map_size); xreport->xmlout("total_packets",demux.packet_counter); xreport->add_rusage(); xreport->pop(); // bulk_extractor xreport->close(); delete xreport; } if(demux.flow_counter > tcpdemux::WARN_TOO_MANY_FILES){ if(!opt_quiet){ /* Start counting how many files we have in the output directory. * If we find more than 10,000, print the warning, and keep counting... */ uint64_t filecount=0; DIR *dirp = opendir(demux.outdir.c_str()); if(dirp){ struct dirent *dp=0; while((dp=readdir(dirp))!=NULL){ filecount++; if(filecount==10000){ std::cerr << "*** tcpflow WARNING:\n"; std::cerr << "*** Modern operating systems do not perform well \n"; std::cerr << "*** with more than 10,000 entries in a directory.\n"; std::cerr << "***\n"; } } closedir(dirp); } if(filecount>=10000){ std::cerr << "*** tcpflow created " << filecount << " files in output directory " << demux.outdir << "\n"; std::cerr << "***\n"; std::cerr << "*** Next time, specify command-line options: -Fk , -Fm , or -Fg \n"; std::cerr << "*** This will automatically bin output into subdirectories.\n"; std::cerr << "*** type 'tcpflow -hhh' for more information.\n"; } } } exit(exit_val); // return(0) causes crash on Windows } tcpflow-tcpflow-1.6.1/src/tcpflow.h000066400000000000000000000171151401360461700172760ustar00rootroot00000000000000/* * This file is part of tcpflow by Simson Garfinkel, * originally by Jeremy Elson * * This source code is under the GNU Public License (GPL). See * LICENSE for details. * * * */ #ifndef TCPFLOW_H #define TCPFLOW_H #include "config.h" /* Older versions of autoconf define PACKAGE and VERSION. * Newer versions define PACKAGE_VERSION and PACKAGE_NAME. * We now use the new variables; allow the old ones. */ #ifndef PACKAGE_VERSION #define PACKAGE_VERSION VERSION #endif #ifndef PACKAGE_NAME #define PACKAGE_NAME PACAKGE #endif /**************************************************************** *** Windows/mingw compatability seciton. *** *** If we are compiling for Windows, including the Windows-specific *** include files first and disable pthread support. ***/ #if (defined(WIN32) || defined(__MINGW32__)) # undef HAVE_PTHREAD_H # undef HAVE_SEMAPHORE_H # undef HAVE_PTHREAD # undef HAVE_INET_NTOP /* it's not there. Really. */ # undef HAVE_EXTERN_PROGNAME // don't work properly on mingw # define MKDIR(a,b) mkdir(a) // MKDIR only takes 1 argument on windows /* Defines not present in Microsoft Windows stack */ #else /*** Unix-specific elements for windows compatibility section ***/ # define MKDIR(a,b) mkdir(a,b) // MKDIR takes 2 arguments on Posix #endif /*** *** end of windows compatibility section ****************************************************************/ /* If we are including inttypes.h, mmake sure __STDC_FORMAT_MACROS is defined */ #ifndef __STDC_FORMAT_MACROS #define __STDC_FORMAT_MACROS #endif /* We want the BSD flavor of defines if possible */ #ifndef __FAVOR_BSD #define __FAVOR_BSD #endif #ifndef __USE_BSD #define __USE_BSD #endif #include /* required per C++ standard - use the C++ versions*/ #include #include #include #include #include #include #include #include #ifndef O_BINARY #define O_BINARY 0 #endif // These are the required include files; they better be present #include #include #ifdef HAVE_SYS_CDEFS_H # include #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_BITYPES_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #ifdef HAVE_NE_IF_VAR_H #include #endif #ifdef HAVE_NET_IF_H # include #endif /* We have given up on keeping track of this all and are just including our own definitions. */ //#ifdef HAVE_NETINET_IN_SYSTM_H //# include //#endif //#ifdef HAVE_NETINET_IP6_H //#include //#endif //#ifdef HAVE_NETINET_IP_VAR_H //# include // FREEBSD //#endif //#ifdef HAVE_NETINET_IF_ETHER_H //# include //#endif //#ifdef HAVE_NETINET_TCP_H //# include //#endif //#ifdef HAVE_NETINET_TCPIP_H //# include // FREEBSD //#endif //#ifdef HAVE_ARPA_INET_H //# include //#endif ///* // * Oracle Enterprise Linux is missing the definition for // * ETHERTYPE_VLAN // */ //#ifndef ETHERTYPE_VLAN //# define ETHERTYPE_VLAN 0x8100 //#endif #ifdef HAVE_SIGNAL_H # include #endif /****************** Ugly System Dependencies ******************************/ /* We always want to refer to RLIMIT_NOFILE, even if what you actually * have is RLIMIT_OFILE */ #if defined(RLIMIT_OFILE) && !defined(RLIMIT_NOFILE) # define RLIMIT_NOFILE RLIMIT_OFILE #endif /* OPEN_MAX is the maximum number of files to open. * Unfortunately, some systems called this FOPEN_MAX... */ #if defined(FOPEN_MAX) && !defined(OPEN_MAX) # define OPEN_MAX FOPEN_MAX #endif /* some systems don't define SEEK_SET... sigh */ #ifndef SEEK_SET # define SEEK_SET 0 #endif /* SEEK_SET */ /* These may not be defined on some systems */ #ifndef MAX_IPv4_STR_LEN #define MAX_IPv4_STR_LEN (3*4+3) #endif #ifndef MAX_IPv6_STR_LEN #define MAX_IPv6_STR_LEN 256 #endif #ifndef HAVE_SOCKLEN_T typedef size_t socklen_t; #endif #ifndef IN6_IS_ADDR_V4MAPPED #define IN6_IS_ADDR_V4MAPPED(x) 0 #endif #ifndef IN6_IS_ADDR_V4COMPAT #define IN6_IS_ADDR_V4COMPAT(x) 0 #endif #undef s6_addr #define s6_addr __u6_addr.__u6_addr8 #undef s6_addr16 #define s6_addr16 __u6_addr.__u6_addr16 #undef s6_addr32 #define s6_addr32 __u6_addr.__u6_addr32 #ifdef __MINGW32__ typedef uint16_t in_port_t; typedef unsigned char u_int8_t; #endif /**************************** Constants ***********************************/ #define DEFAULT_DEBUG_LEVEL 1 #define MAX_FD_GUESS 64 #define SNAPLEN 65536 /* largest possible MTU we'll see */ /* Reserve FDs for stdin, stdout, stderr, and the packet filter; one for breathing * room (we open new files before closing old ones), and one more to * be safe. */ #define NUM_RESERVED_FDS 6 /* number of FDs to set aside; allows files to be opened as necessary */ #include "be13_api/bulk_extractor_i.h" /***************************** Main Support *************************************/ /* tcpflow.cpp - CLI */ extern const char *progname; void terminate(int sig); #include "inet_ntop.h" #ifdef HAVE_PTHREAD #include extern sem_t *semlock; #endif #ifndef __MAIN_C__ extern int debug; #endif #define DEBUG(message_level) if (debug >= message_level) debug_real /************************* per-file globals ****************************/ /* datalink.cpp - callback for libpcap */ extern int32_t datalink_tdelta; // time delta to add to each packet pcap_handler find_handler(int datalink_type, const char *device); // callback for pcap typedef struct { pcap_handler handler; int type; } dlt_handler_t; void dl_ieee802_11_radio(u_char *user, const struct pcap_pkthdr *h, const u_char *p); void dl_prism(u_char *user, const struct pcap_pkthdr *h, const u_char *p); /** * shift the time value, in line with what the user requested... * previously this returned a structure on the stack, but that * created an optimization problem with gcc 4.7.2 */ inline const timeval &tvshift(struct timeval &tv,const struct timeval &tv_) { tv.tv_sec = tv_.tv_sec + datalink_tdelta; tv.tv_usec = tv_.tv_usec; return tv; } /* util.cpp - utility functions */ extern int debug; std::string ssprintf(const char *fmt,...); std::string comma_number_string(int64_t input); void mkdirs_for_path(std::string path); // creates any directories necessary for the path std::string macaddr(const uint8_t *addr); #define DEBUG_PEDANTIC 0x0001 // check values more rigorously void init_debug(const char *progname,int include_pid); void (*portable_signal(int signo, void (*func)(int)))(int); void debug_real(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); [[noreturn]] void die(const char *fmt, ...) __attribute__ ((__noreturn__)) __attribute__ ((format (printf, 1, 2))); /* scanners */ extern "C" scanner_t scan_md5; extern "C" scanner_t scan_http; extern "C" scanner_t scan_python; extern "C" scanner_t scan_tcpdemux; extern "C" scanner_t scan_netviz; extern "C" scanner_t scan_wifiviz; #ifndef HAVE_TIMEVAL_OUT #define HAVE_TIMEVAL_OUT inline std::ostream& operator<<(std::ostream& os, const struct timeval *t) { return os << t->tv_sec << "." << std::setw(6) << std::setfill('0') << t->tv_usec; } #endif #endif /* __TCPFLOW_H__ */ tcpflow-tcpflow-1.6.1/src/tcpip.cpp000066400000000000000000000540201401360461700172660ustar00rootroot00000000000000/* * This file is part of tcpflow by Simson Garfinkel, * originally by Jeremy Elson * * Modified by Greg Drew to add support for creating a packet time / data index * which allows mapping bytes in the flow back to their relative arrival time. * This is very useful in reassembling inherently bidirectional conversations * such as chat or telnet sessions. --GDD * * This source code is under the GNU Public License (GPL). See * LICENSE for details. * */ #include "tcpflow.h" #include "tcpip.h" #include "tcpdemux.h" #include #include #include #include #pragma GCC diagnostic ignored "-Weffc++" #pragma GCC diagnostic ignored "-Wshadow" /* Create a new tcp object. * * Creating a new object creates a new passive TCP/IP decoder. * It will *NOT* append to a flow that is already on the disk or in memory. * * called from tcpdemux::create_tcpip() */ tcpip::tcpip(tcpdemux &demux_,const flow &flow_,be13::tcp_seq isn_): demux(demux_),myflow(flow_),dir(unknown),isn(isn_),nsn(0), syn_count(0),fin_count(0),fin_size(0),pos(0), flow_pathname(),fd(-1),file_created(false), flow_index_pathname(),idx_file(), seen(new recon_set()), last_byte(), last_packet_number(),out_of_order_count(0),violations(0) { } uint32_t tcpip::seen_bytes() { if(seen) return seen->size(); return 0; } void tcpip::dump_seen() { if(seen){ for(recon_set::const_iterator it = seen->begin(); it!=seen->end(); it++){ std::cerr << *it << ", "; } std::cerr << std::endl; } } void tcpip::dump_xml(class dfxml_writer *xreport,const std::string &xmladd) { static const std::string fileobject_str("fileobject"); static const std::string filesize_str("filesize"); static const std::string filename_str("filename"); static const std::string tcpflow_str("tcpflow"); xreport->push(fileobject_str); if(flow_pathname.size()) xreport->xmlout(filename_str,flow_pathname); xreport->xmlout(filesize_str,last_byte); std::stringstream attrs; attrs << "startime='" << dfxml_writer::to8601(myflow.tstart) << "' "; attrs << "endtime='" << dfxml_writer::to8601(myflow.tlast) << "' "; if(myflow.has_mac_daddr()) attrs << "mac_daddr='" << macaddr(myflow.mac_daddr) << "' "; if(myflow.has_mac_saddr()) attrs << "mac_saddr='" << macaddr(myflow.mac_saddr) << "' "; attrs << "family='" << (int)myflow.family << "' "; attrs << "src_ipn='" << ipaddr_prn(myflow.src, myflow.family) << "' "; attrs << "dst_ipn='" << ipaddr_prn(myflow.dst, myflow.family) << "' "; attrs << "srcport='" << myflow.sport << "' "; attrs << "dstport='" << myflow.dport << "' "; attrs << "packets='" << myflow.packet_count << "' "; if(out_of_order_count) attrs << "out_of_order_count='" << out_of_order_count << "' "; if(violations) attrs << "violations='" << violations << "' "; attrs << "len='" << myflow.len << "' "; if(myflow.len != myflow.caplen) attrs << "caplen='" << myflow.caplen << "' "; xreport->xmlout(tcpflow_str,"",attrs.str(),false); if(xmladd.size()>0) xreport->xmlout("",xmladd,"",false); xreport->pop(); xreport->flush(); } /** * Destructor is called when flow is closed. * It implements "after" processing. * This should only be called from remove_flow() or remove_all_flows() * when a flow is deleted. */ tcpip::~tcpip() { assert(fd<0); // file must be closed delete seen; // no need to check to see if seen is null or not. } #pragma GCC diagnostic warning "-Weffc++" #pragma GCC diagnostic warning "-Wshadow" /**************************************************************** ** SAVE FILE MANAGEMENT **************************************************************** * * Unlike the tcp/ip object, which is created once, the file can be opened, closed, and * re-opened depending on the availability of file handles. * * Closing the file does not delete the tcp/ip object. */ /* Closes the file belonging to a flow. * Does not take tcpip out of flow database. * Does not change pos. */ void tcpip::close_file() { if (fd>=0){ struct timeval times[2]; times[0] = myflow.tstart; times[1] = myflow.tstart; DEBUG(5) ("%s: closing file in tcpip::close_file", flow_pathname.c_str()); /* close the file and remember that it's closed */ #if defined(HAVE_FUTIMES) /* fix microseconds if they are invalid */ for ( int i=0; i<2; i++){ if ( times[i].tv_usec < 0 || times[i].tv_usec >= 1000000 ){ times[i].tv_usec = 0; } } if (futimes(fd,times)){ fprintf(stderr,"%s: futimes(fd=%d,[%ld:%ld,%ld:%ld])\n", strerror(errno),fd, times[0].tv_sec,times[1].tv_usec, times[1].tv_sec,times[1].tv_usec); } #elif defined(HAVE_FUTIMENS) struct timespec tstimes[2]; for(int i=0;i<2;i++){ tstimes[i].tv_sec = times[i].tv_sec; tstimes[i].tv_nsec = times[i].tv_usec * 1000; } if(futimens(fd,tstimes)){ perror("futimens(fd=%d)",fd); } #endif close(fd); fd = -1; demux.open_flows.erase(this); // we are no longer open } // Also close the flow_index file, if flow indexing is in use --GDD if(demux.opt.output_packet_index && idx_file.is_open()){ idx_file.close(); } //std::cerr << "close_file1 " << *this << "\n"; } /* * Opens the file transcript file (creating file if necessary). * Called by store_packet() * Does not change pos. */ int tcpip::open_file() { int create_idx_needed = false; if(fd<0){ //std::cerr << "open_file0 " << ct << " " << *this << "\n"; /* If we don't have a filename, create the flow */ if(flow_pathname.size()==0) { flow_pathname = myflow.new_filename(&fd,O_RDWR|O_BINARY|O_CREAT|O_EXCL,0666); file_created = true; // remember we made it create_idx_needed = true; // We created a new stream, so we need to create a new flow file. --GDD DEBUG(5) ("%s: created new file",flow_pathname.c_str()); } else { /* open an existing flow */ fd = demux.retrying_open(flow_pathname,O_RDWR | O_BINARY | O_CREAT,0666); lseek(fd,pos,SEEK_SET); DEBUG(5) ("%s: opening existing file", flow_pathname.c_str()); } /* If the file isn't open at this point, there's a problem */ if (fd < 0 ) { /* we had some problem opening the file -- set FINISHED so we * don't keep trying over and over again to reopen it */ perror(flow_pathname.c_str()); return -1; } /* Remember that we have this open */ demux.open_flows.push_back(this); if(demux.open_flows.size() > demux.max_open_flows) demux.max_open_flows = demux.open_flows.size(); //std::cerr << "open_file1 " << *this << "\n"; } if(demux.opt.output_packet_index){ //Open the file for the flow index. We don't do this if the flow file could not be // opened. The file must be opened for append, in case this is a reopen. The filename // standard is the flow name followed by ".findx", which google currently says does not // conflict with anything major. flow_index_pathname = flow_pathname + ".findx"; DEBUG(10)("opening index file: %s",flow_index_pathname.c_str()); if(create_idx_needed){ //New flow file, even if there was an old one laying around --GDD idx_file.open(flow_index_pathname.c_str(),std::ios::trunc|std::ios::in|std::ios::out); }else{ //Use existing flow file --GDD idx_file.open(flow_index_pathname.c_str(),std::ios::ate|std::ios::in|std::ios::out); } if(idx_file.bad()){ perror(flow_index_pathname.c_str()); // Be nice and be sure the flow has been closed in the demultiplexer. // demux.close_tcpip_fd(this); Need to fix this. Also, when called, it will // have to differentiate the fact that the open fd cound only needs to be // decremented by one and not by 2.--GDD return -1; } } return 0; } /*************************************************************************/ /* print the contents of this packet to the console. * This is nice for immediate satisfaction, but it can't handle * out of order packets, etc. */ void tcpip::print_packet(const u_char *data, uint32_t length) { /* green, blue, read */ const char *color[3] = { "\033[0;32m", "\033[0;34m", "\033[0;31m" }; if(demux.opt.max_bytes_per_flow>=0){ uint64_t max_bytes_per_flow = (uint64_t)demux.opt.max_bytes_per_flow; if(last_byte > max_bytes_per_flow) return; /* too much has been printed */ if(length > max_bytes_per_flow - last_byte){ length = max_bytes_per_flow - last_byte; /* can only output this much */ if(length==0) return; } } #ifdef HAVE_PTHREAD if(semlock){ if(sem_wait(semlock)){ fprintf(stderr,"%s: attempt to acquire semaphore failed: %s\n",progname,strerror(errno)); exit(1); } } #endif if(flow_pathname.size()==0) flow_pathname = myflow.filename(0, false); if (demux.opt.use_color) fputs(dir==dir_cs ? color[1] : color[2], stdout); if (demux.opt.suppress_header == 0 && demux.opt.output_json == 0){ printf("%s: ", flow_pathname.c_str()); if(demux.opt.output_hex) putchar('\n'); } size_t written = 0; if(demux.opt.output_hex){ const size_t bytes_per_line = 32; size_t max_spaces = 0; for(u_int i=0;imax_spaces) max_spaces=spaces; for(;spaces=' ' && ch<='~') fputc(ch,stdout); else fputc('.',stdout); } fputc('\n',stdout); } written = length; // just fake it. } else if (demux.opt.output_json) { // { // "src_host": "192.168.0.1", // "src_port": 1234, // "dst_host": "1.1.1.1", // "dst_port": 80, // "payload" : [...] // } std::string hoststr = std::string(); putchar('{'); printf("\"src_host\":\""); size_t src_pos = 0; size_t src_end_pos = 0; size_t src_pos_counter = 0; size_t pathname_len = flow_pathname.length(); for(size_t i = 0; i < pathname_len; ++i) { if(flow_pathname[i] == '.') { src_pos_counter++; printf("%d%s", atoi(hoststr.c_str()), (src_pos_counter != 4 ? "." : "")); hoststr.clear(); } else { hoststr = hoststr + flow_pathname[i]; } if(src_pos_counter == 4) { src_pos = i; break; } } src_end_pos = src_pos; for(;src_end_pos < pathname_len; ++src_end_pos) { if(flow_pathname[src_end_pos] == '-') { break; } } printf("\",\"src_port\":%d,\"dst_host\":\"", atoi(flow_pathname.substr(src_pos + 1, src_end_pos - src_pos).c_str())); size_t dst_pos = src_end_pos + 1; size_t dst_end_pos = dst_pos; size_t dst_pos_counter = 0; for(size_t i = dst_pos; i < pathname_len; ++i) { if(flow_pathname[i] == '.') { dst_pos_counter++; printf("%d%s", atoi(hoststr.c_str()), (dst_pos_counter != 4 ? "." : "")); hoststr.clear(); } else { hoststr = hoststr + flow_pathname[i]; } if(dst_pos_counter == 4) { dst_pos = i; break; } } dst_end_pos = dst_pos; for(;dst_end_pos < pathname_len; ++dst_end_pos) { if(flow_pathname[dst_end_pos] == '-') { break; } } printf("\",\"dst_port\":%d,\"payload\": [", atoi(flow_pathname.substr(dst_pos + 1, dst_end_pos - dst_pos).c_str())); for(size_t i = 0; i < length; ++i) { printf("%d%s", data[i], (i != length - 1 ? "," : "]}")); } } else if (demux.opt.output_strip_nonprint) { for(const u_char *cc = data;cc::closed(pos,pos+length-1); } } /* store the contents of this packet to its place in its file * This has to handle out-of-order packets as well as writes * past the 4GiB boundary. * * 2012-10-24 Originally this code simply computed the 32-bit offset * from the beginning of the file using the isn. The new version tracks * nsn (the expected next sequence number for the open file). * * A relative seek before the beginning of the file means that we need * to insert. A relative seek more than max_seek means that we have a * different flow that needs to be separately handled. * * called from tcpdemux::process_tcp_packet() */ void tcpip::store_packet(const u_char *data, uint32_t length, int32_t delta,struct timeval ts) { if(length==0) return; // no need to do anything uint32_t insert_bytes=0; uint64_t offset = pos+delta; // where the data will go in absolute byte positions (first byte is pos=0) if((int64_t)offset < 0){ /* We got bytes before the beginning of the TCP connection. * Either this is a protocol violation, * or else we never saw a SYN and we got the ISN wrong. */ if(syn_count>0){ DEBUG(2)("packet received with offset %" PRId64 "; ignoring",offset); violations++; return; } insert_bytes = -offset; // open up this much space offset = 0; // and write the data here } /* reduce length to write if it goes beyond the number of bytes per flow, * but remember to seek out to the actual position after the truncated write... */ uint32_t wlength = length; // length to write if (demux.opt.max_bytes_per_flow >= 0){ uint64_t max_bytes_per_flow = (uint64_t)demux.opt.max_bytes_per_flow; if(offset >= max_bytes_per_flow){ wlength = 0; } if(offset < max_bytes_per_flow && offset+length > max_bytes_per_flow){ DEBUG(2) ("packet truncated by max_bytes_per_flow on %s", flow_pathname.c_str()); wlength = max_bytes_per_flow - offset; } } /* if we don't have a file open for this flow, try to open it. * return if the open fails. Note that we don't have to explicitly * save the return value because open_tcpfile() puts the file pointer * into the structure for us. */ if (fd < 0) { if (open_file()) { DEBUG(1)("unable to open TCP file %s fd=%d wlength=%d", flow_pathname.c_str(),fd,(int)wlength); return; } } /* Shift the file now if we were going shift it */ if(insert_bytes>0){ if(fd>=0) shift_file(fd,insert_bytes); isn -= insert_bytes; // it's really earlier lseek(fd,(off_t)0,SEEK_SET); // put at the beginning pos = 0; nsn = isn+1; out_of_order_count++; DEBUG(25)("%s: insert(0,%d); lseek(%d,0,SEEK_SET) out_of_order_count=%" PRId64, flow_pathname.c_str(), insert_bytes, fd,out_of_order_count); /* TK: If we have seen packets, everything in the recon set needs to be shifted as well.*/ delete seen; seen = 0; } /* if we're not at the correct point in the file, seek there */ if (offset != pos) { /* Check for a keepalive */ if(delta == -1 && length == 1) { DEBUG(25)("%s: RFC1122 keepalive detected and ignored",flow_pathname.c_str()); return; } if(fd>=0) lseek(fd,(off_t)delta,SEEK_CUR); if(delta<0) out_of_order_count++; // only increment for backwards seeks DEBUG(25)("%s: lseek(%d,%d,SEEK_CUR) offset=%" PRId64 " pos=%" PRId64 " out_of_order_count=%" PRId64, flow_pathname.c_str(), fd,(int)delta,offset,pos,out_of_order_count); pos += delta; // where we are now nsn += delta; // what we expect the nsn to be now } /* write the data into the file */ DEBUG(25) ("%s: %s write %ld bytes @%" PRId64, flow_pathname.c_str(), fd>=0 ? "will" : "won't", (long) wlength, offset); if(fd>=0){ if ((uint32_t)write(fd,data, wlength) != wlength) { DEBUG(1) ("write to %s failed: ", flow_pathname.c_str()); if (debug >= 1) perror(""); } // Write to the index file if needed. Note, index file is sorted before close, so no need to jump around --GDD if (demux.opt.output_packet_index && idx_file.is_open()) { idx_file << offset << "|" << ts.tv_sec << "." << std::setw(6) << std::setfill('0') << ts.tv_usec << "|" << wlength << "\n"; if (idx_file.bad()){ DEBUG(1)("write to index file %s failed: ",flow_index_pathname.c_str()); if(debug >= 1){ perror(""); } } } if(wlength != length){ off_t p = lseek(fd,length-wlength,SEEK_CUR); // seek out the space we didn't write DEBUG(100)(" lseek(%" PRId64 ",SEEK_CUR)=%" PRId64,(int64_t)(length-wlength),(int64_t)p); } } /* Update the database of bytes that we've seen */ if(seen) update_seen(seen,pos,length); /* Update the position in the file and the next expected sequence number */ pos += length; nsn += length; // expected next sequence number if(pos>last_byte) last_byte = pos; if(debug>=100){ uint64_t rpos = lseek(fd,(off_t)0,SEEK_CUR); DEBUG(100)(" pos=%" PRId64 " lseek(fd,0,SEEK_CUR)=%" PRId64,pos,rpos); assert(pos==rpos); } #ifdef DEBUG_REOPEN_LOGIC /* For debugging, force this connection closed */ demux.close_tcpip_fd(this); #endif } /* * Compare two index strings and return the result. Called by * the vector::sort in sort_index. * --GDD */ bool tcpip::compare(std::string a, std::string b){ std::stringstream ss_a(a),ss_b(b); long a_l,b_l; ss_a >> a_l; ss_b >> b_l; return a_l < b_l; } /* * Sort an index file (presumably from this object) if file indexing is * turned on and the file exists. Index files may be out of order due * to the arrival of out of order packets. It is cheaper to reorder them * one time at the end of processing than it is to continually keep them * in order. * --GDD */ void tcpip::sort_index(std::fstream *ix_file) { std::vector idx; std::string line; if (demux.opt.output_packet_index) { if (!(idx_file.good() && idx_file.is_open())) { DEBUG(5)("Skipping index file sort. Unusual behavior.\n"); return; //Nothing to do } //Make sure we are at the beginning. ix_file->clear(); ix_file->seekg(0); do { *ix_file >> line; if (!ix_file->eof()) { idx.push_back(line); } } while (ix_file->good()); std::sort(idx.begin(), idx.end(), &tcpip::compare); ix_file->clear(); ix_file->seekg(0); for (std::vector::iterator s = idx.begin(); s != idx.end(); s++) { *ix_file << *s << "\n"; } } } /* * Convenience function to cause the local index file to be sorted. * --GDD */ void tcpip::sort_index(){ tcpip::sort_index(&(this->idx_file)); } #pragma GCC diagnostic ignored "-Weffc++" #pragma GCC diagnostic ignored "-Wshadow" /* Note --- Turn off warning so that creating the seen() map doesn't throw an error */ //#pragma GCC diagnostic ignored "-Weffc++" tcpflow-tcpflow-1.6.1/src/tcpip.h000066400000000000000000000335271401360461700167440ustar00rootroot00000000000000#ifndef TCPIP_H #define TCPIP_H #include #include "inet_ntop.h" /** On windows, there is no in_addr_t; this is from * /usr/include/netinet/in.h */ #ifndef HAVE_NETINET_IN_H typedef uint32_t in_addr_t; #endif #ifndef HAVE_SA_FAMILY_T typedef unsigned short int sa_family_t; #endif /** * ipaddress class. * represents IPv4 and IPv6 addresses. * IPv4 addresses have address in bytes 0..3 and all NULL for bytes 4..11 */ class ipaddr { public:; ipaddr(){ memset(addr,0,sizeof(addr)); } ipaddr(const in_addr_t &a){ // copy operator addr[0] = ((uint8_t *)&a)[0]; // copy the bottom 4 octets and blank the top 12 addr[1] = ((uint8_t *)&a)[1]; addr[2] = ((uint8_t *)&a)[2]; addr[3] = ((uint8_t *)&a)[3]; memset(addr+4,0,12); } ipaddr(const uint8_t a[16]){ // begin wiped memcpy(addr,a,16); } uint8_t addr[16]; // holds v4 or v16 bool bit(int i) const { // get the ith bit; 0 is MSB return (addr[i / 8]) & (1<<(7-i%8)); } uint32_t quad(int i) const { // gets the ith quad as a 32-bit value return (addr[i*4+0]<<24) | (addr[i*4+2]<<16) | (addr[i*4+1]<<8) | (addr[i*4+3]<<0); } uint64_t dquad(int i) const { // gets the first 64-bit half or the second 64-bit half return (uint64_t)(quad(i*2+1))<<32 | (uint64_t)(quad(i*2)); } inline bool operator ==(const ipaddr &b) const { return memcmp(this->addr,b.addr,sizeof(addr))==0; }; inline bool operator <=(const ipaddr &b) const { return memcmp(this->addr,b.addr,sizeof(addr))<=0; }; inline bool operator > (const ipaddr &b) const { return memcmp(this->addr,b.addr,sizeof(addr))>0; }; inline bool operator >=(const ipaddr &b) const { return memcmp(this->addr,b.addr,sizeof(addr))>=0; }; inline bool operator < (const ipaddr &b) const { return memcmp(this->addr,b.addr,sizeof(this->addr))<0; } }; class ipaddr_prn { public: const ipaddr& ia; const sa_family_t family; ipaddr_prn(const ipaddr& ia_, sa_family_t family_) : ia(ia_), family(family_) { } }; inline std::ostream & operator <<(std::ostream &os, const ipaddr_prn &b) { char buf[INET6_ADDRSTRLEN]; inet_ntop(b.family, b.ia.addr, buf, sizeof(buf)); os << buf; return os; } inline bool operator ==(const struct timeval &a,const struct timeval &b) { return a.tv_sec==b.tv_sec && a.tv_usec==b.tv_usec; } inline bool operator <(const struct timeval &a,const struct timeval &b) { return (a.tv_secsrc==b.src && this->dst==b.dst && this->sport==b.sport && this->dport==b.dport && this->family==b.family; } inline bool operator <(const flow_addr &b) const { if (this->src < b.src) return true; if (this->src > b.src) return false; if (this->dst < b.dst) return true; if (this->dst > b.dst) return false; if (this->sport < b.sport) return true; if (this->sport > b.sport) return false; if (this->dport < b.dport) return true; if (this->dport > b.dport) return false; if (this->family < b.family) return true; if (this->family > b.family) return false; return false; /* they are equal! */ } std::string str() const { std::stringstream s; s << "flow[" << ipaddr_prn(src, family) << ":" << sport << "->" << ipaddr_prn(dst, family) << ":" << dport << "]"; return s.str(); } }; inline std::ostream & operator <<(std::ostream &os,const flow_addr &f) { os << f.str(); return os; } /* * A flow is a flow_addr that has additional information regarding when it was seen * and how many packets were seen. The address is used to locate the flow in the array. * Notice that it contains no pointers, so it can be copied with the default operator. */ class flow : public flow_addr { public:; static void usage(); // print information on flow notation static std::string filename_template; // static std::string outdir; // where the output gets written flow():id(),vlan(),mac_daddr(),mac_saddr(),tstart(),tlast(),len(),caplen(),packet_count(),session_id(){}; flow(const flow_addr &flow_addr_,uint64_t id_,const be13::packet_info &pi): flow_addr(flow_addr_),id(id_),vlan(pi.vlan()), mac_daddr(), mac_saddr(), tstart(pi.ts),tlast(pi.ts), len(0), caplen(0), packet_count(0), session_id(0) { if(pi.pcap_hdr){ memcpy(mac_daddr,pi.get_ether_dhost(),sizeof(mac_daddr)); memcpy(mac_saddr,pi.get_ether_shost(),sizeof(mac_saddr)); } } virtual ~flow(){}; uint64_t id; // flow_counter when this flow was created int32_t vlan; // vlan interface we first observed; -1 means no vlan uint8_t mac_daddr[6]; // dst mac address of first packet uint8_t mac_saddr[6]; // source mac address of first packet struct timeval tstart; // when first seen struct timeval tlast; // when last seen uint64_t len; // off-wire length uint64_t caplen; // captured length uint64_t packet_count; // packet count uint64_t session_id; // session unique id (used to match client->server and server->client flows // return a filename for a flow based on the template and the connection count std::string filename(uint32_t connection_count, bool); // return a new filename for a flow based on the temlate, // optionally opening the file and returning a fd if &fd is provided std::string new_filename(int *fd,int flags,int mode); std::string new_pcap_filename(); bool has_mac_daddr(){ return mac_daddr[0] || mac_daddr[1] || mac_daddr[2] || mac_daddr[3] || mac_daddr[4] || mac_daddr[5]; } bool has_mac_saddr(){ return mac_saddr[0] || mac_saddr[1] || mac_saddr[2] || mac_saddr[3] || mac_saddr[4] || mac_saddr[5]; } }; /* * Convenience class for working with TCP headers */ #define PORT_HTTP 80 #define PORT_HTTP_ALT_0 8080 #define PORT_HTTP_ALT_1 8000 #define PORT_HTTP_ALT_2 8888 #define PORT_HTTP_ALT_3 81 #define PORT_HTTP_ALT_4 82 #define PORT_HTTP_ALT_5 8090 #define PORT_HTTPS 443 #define PORT_SSH 22 #define PORT_FTP_DATA 20 #define PORT_FTP_CONTROL 21 class tcp_header_t { public: #pragma GCC diagnostic ignored "-Wcast-align" tcp_header_t(const u_char *data): tcp_header((struct be13::tcphdr *)data){}; #pragma GCC diagnostic warning "-Wcast-align" tcp_header_t(const tcp_header_t &b): tcp_header(b.tcp_header){} tcp_header_t &operator=(const tcp_header_t &that) { this->tcp_header = that.tcp_header; return *this; } virtual ~tcp_header_t(){} struct be13::tcphdr *tcp_header; size_t tcp_header_len(){ return tcp_header->th_off * 4; } uint16_t sport() {return ntohs(tcp_header->th_sport);} uint16_t dport() {return ntohs(tcp_header->th_dport);} be13::tcp_seq seq() {return ntohl(tcp_header->th_seq);} bool th_fin() {return tcp_header->th_flags & TH_FIN;} bool th_ack() {return tcp_header->th_flags & TH_ACK;} bool th_syn() {return tcp_header->th_flags & TH_SYN;} }; /* * The tcpip class is a passive tcp/ip implementation. * It can reconstruct flows! * * It includes: * - the flow (as an embedded object) * - Information about where the flow is written. * - Information about how much of the flow has been captured. * Currently flows only go in one direction and do not know about their sibling flow */ #pragma GCC diagnostic ignored "-Weffc++" #pragma GCC diagnostic ignored "-Wshadow" #pragma GCC diagnostic ignored "-Wall" #pragma GCC diagnostic ignored "-Wmissing-noreturn" #if defined(HAVE_BOOST_ICL_INTERVAL_HPP) && defined(HAVE_BOOST_ICL_INTERVAL_MAP_HPP) && defined(HAVE_BOOST_ICL_INTERVAL_SET_HPP) #include #include #include typedef boost::icl::interval_set recon_set; // Boost interval set of bytes that were reconstructed. #endif #include "intrusive_list.h" #pragma GCC diagnostic warning "-Weffc++" #pragma GCC diagnostic warning "-Wshadow" #pragma GCC diagnostic warning "-Wall" #pragma GCC diagnostic warning "-Wmissing-noreturn" class tcpip { public: /** track the direction of the flow; this is largely unused */ typedef enum { unknown=0, // unknown direction dir_sc, // server-to-client 1 dir_cs // client-to-server 2 } dir_t; private: /*** Begin Effective C++ error suppression *** *** This class does not implement assignment or copying. *** ***/ tcpip(const tcpip &t); tcpip &operator=(const tcpip &that); /*** End Effective C++ error suppression */ public:; tcpip(class tcpdemux &demux_,const flow &flow_,be13::tcp_seq isn_); /* constructor in tcpip.cpp */ virtual ~tcpip(); // destructor class tcpdemux &demux; // our demultiplexer /* State information for the flow being reconstructed */ flow myflow; /* Description of this flow */ dir_t dir; // direction of flow be13::tcp_seq isn; // Flow's initial sequence number be13::tcp_seq nsn; // fd - expected next sequence number uint32_t syn_count; // number of SYNs seen uint32_t fin_count; // number of FINs received uint32_t fin_size; // length of stream as determined when fin is sent uint64_t pos; // fd - current position+1 (next byte in stream to be written) /* Archiving information */ std::string flow_pathname; // path where flow is saved int fd; // file descriptor for file storing this flow's data bool file_created; // true if file was created /* Flow Index information - only used if flow packet/data indexing is requested --GDD */ std::string flow_index_pathname; // Path for the flow index file std::fstream idx_file; // File descriptor for storing the flow index data /* Stats */ recon_set *seen; // what we've seen; it must be * due to boost lossage uint64_t last_byte; // last byte in flow processed uint64_t last_packet_number; // for finding most recent packet written uint64_t out_of_order_count; // all packets were contigious uint64_t violations; // protocol violation count /* File Acess Order */ intrusive_list::iterator it; /* Methods */ void close_file(); // close fd int open_file(); // opens save file; return -1 if failure, 0 if success void print_packet(const u_char *data, uint32_t length); void store_packet(const u_char *data, uint32_t length, int32_t delta,struct timeval ts); void process_packet(const struct timeval &ts,const int32_t delta,const u_char *data,const uint32_t length); uint32_t seen_bytes(); void dump_seen(); void dump_xml(class dfxml_writer *xmlreport,const std::string &xmladd); static bool compare(std::string a, std::string b); void sort_index(std::fstream *idx_file); void sort_index(); }; /* print a tcpip data structure. Largely for debugging */ inline std::ostream & operator <<(std::ostream &os,const tcpip &f) { os << "tcpip[" << f.myflow << " dir:" << int(f.dir) << " isn:" << f.isn << " nsn: " << f.nsn << " sc:" << f.syn_count << " fc:" << f.fin_count << " fs:" << f.fin_size << " pos:" << f.pos << " fd: " << f.fd << " cr:" << f.file_created << " lb:" << f.last_byte << " lpn:" << f.last_packet_number << " ooc:" << f.out_of_order_count << "]"; if(f.fd>0) os << " ftell(" << f.fd << ")=" << lseek(f.fd,0L,SEEK_CUR); return os; } /* * An saved_flow is a flow for which all of the packets have been received and tcpip state * has been discarded. The saved_flow allows matches against newly received packets * that are not SYN or ACK packets but have data. We can see if the data matches data that's * been written to disk. To do this we need ot know the filename and the ISN... */ class saved_flow { public: saved_flow(tcpip *tcp):addr(tcp->myflow), saved_filename(tcp->flow_pathname), isn(tcp->isn) {} flow_addr addr; // flow address std::string saved_filename; // where the flow was saved be13::tcp_seq isn; // the flow's ISN virtual ~saved_flow(){}; }; class sparse_saved_flow { public: sparse_saved_flow (const flow_addr &idx, FILE *_fcap):addr(idx),fcap(_fcap) {} flow_addr addr; // flow address FILE *fcap; // output pcap file virtual ~sparse_saved_flow() { if(fcap) fclose(fcap); } /* these are not implemented */ private: sparse_saved_flow(const sparse_saved_flow &t); sparse_saved_flow &operator=(const sparse_saved_flow &that); }; #endif tcpflow-tcpflow-1.6.1/src/template_demo.cpp000066400000000000000000000012631401360461700207670ustar00rootroot00000000000000/* * How do we do a template like this? */ #include #include #include template class A { private: T var_; uint64_t count_; public: A(T v):var_(v),count(0){ } uint64_t count() const { return count_;} T var() const { return var_;} void inc_count(); }; template void A::inc_count() { count_++; }; template std::ostream & operator <<(std::ostream &os, const A &e) { os << e.count() << "=" << e.var(); return os; }; int main(int argc,char **argv) { A a(3); a.inc_count(); std::cout << a << "\n"; a.inc_count(); std::cout << a << "\n"; } tcpflow-tcpflow-1.6.1/src/util.cpp000066400000000000000000000134661401360461700171350ustar00rootroot00000000000000/* * This file is part of tcpflow. * Originally by Jeremy Elson * Now maintained by Simson L. Garfinkel * * This source code is under the GNU Public License (GPL). * See LICENSE for details. * */ #include "tcpflow.h" #include static char *debug_prefix = NULL; /* * STD String sprintf wrapper for sane CPP formatting */ std::string ssprintf(const char *fmt,...) { char buf[65536]; va_list ap; va_start(ap,fmt); vsnprintf(buf,sizeof(buf),fmt,ap); va_end(ap); return std::string(buf); } /* * Insert readability commas into an integer without writing a custom locale facet */ std::string comma_number_string(int64_t input) { std::vector tokens; std::stringstream ss; ss << std::setfill('0'); int sign = 1; if(input < 0) { sign = -1; input *= -1; } while(input >= 1000) { tokens.push_back(input % 1000); input /= 1000; } ss << (input * sign); for(std::vector::const_reverse_iterator it = tokens.rbegin(); it != tokens.rend(); it++) { ss << "," << std::setw(3) << *it; } return ss.str(); } std::string macaddr(const uint8_t *addr) { char buf[256]; snprintf(buf,sizeof(buf),"%02x:%02x:%02x:%02x:%02x:%02x", addr[0],addr[1],addr[2],addr[3],addr[4],addr[5]); return std::string(buf); } /* * Remember our program name and process ID so we can use them later * for printing debug messages * */ void init_debug(const char *pfx,int include_pid) { if(debug_prefix) free(debug_prefix); size_t debug_prefix_size = strlen(pfx) + 16; debug_prefix = (char *)calloc(sizeof(char), debug_prefix_size); if(debug_prefix==0) die("malloc failed"); if(include_pid){ snprintf(debug_prefix, debug_prefix_size, "%s[%d]", pfx, (int) getpid()); } else { snprintf(debug_prefix, debug_prefix_size, "%s", pfx); } } /****************************************************************/ /* C++ string splitting code from http://stackoverflow.com/questions/236129/how-to-split-a-string-in-c */ #if 0 static std::vector &split(const std::string &s, char delim, std::vector &elems) { std::stringstream ss(s); std::string item; while(std::getline(ss, item, delim)) { elems.push_back(item); } return elems; } static std::vector split(const std::string &s, char delim) { std::vector elems; return split(s, delim, elems); } #endif /* mkdir all of the containing directories in path. * keep track of those made so we don't need to keep remaking them. */ void mkdirs_for_path(std::string path) { static std::set made_dirs; // track what we made std::string mpath; // the path we are making if(path.at(0)=='/'){ mpath = "/"; path = path.substr(1); } std::vector parts = split(path,'/'); /* Notice that this won't mkdir for the last part. * That's okay, because it's a filename. */ for(std::vector::const_iterator it=parts.begin();it!=parts.end();it++){ if(made_dirs.find(mpath)==made_dirs.end()){ if(mpath.size()){ int r = MKDIR(mpath.c_str(),0777); if(r<0){ /* Can't make path; see if we can execute it*/ if(access(mpath.c_str(),X_OK)<0){ perror(mpath.c_str()); exit(1); } } made_dirs.insert(mpath); } } if(mpath.size()>0) mpath += "/"; mpath += *it; } } /* * Print a debugging message, given a va_list */ void print_debug_message(const char *fmt, va_list ap) { /* print debug prefix */ fprintf(stderr, "%s: ", debug_prefix); /* print the var-arg buffer passed to us */ vfprintf(stderr, fmt, ap); /* add newline */ fprintf(stderr, "\n"); (void) fflush(stderr); } /* Print a debugging or informational message */ void debug_real(const char *fmt, ...) { va_list ap; va_start(ap, fmt); print_debug_message(fmt, ap); va_end(ap); } /* Print a debugging or informatioal message, then exit */ [[noreturn]] void die(const char *fmt, ...) { va_list ap; va_start(ap, fmt); print_debug_message(fmt, ap); exit(1); } /* An attempt at making signal() portable. * * If we detect sigaction, use that; * otherwise if we have setsig, use that; * otherwise, cross our fingers and hope for the best using plain old signal(). * * Our first choice is sigaction (sigaction() is POSIX; signal() is * not.) Taken from Stevens' _Advanced Programming in the UNIX Environment_. * * 10/6/08 - slg - removed RETSIGTYPE, since it hasn't been needed to 15 years */ void (*portable_signal(int signo, void (*func)(int)))(int) { #if defined(HAVE_SIGACTION) struct sigaction act, oact; memset(&act, 0, sizeof(act)); memset(&oact, 0, sizeof(oact)); act.sa_handler = func; sigemptyset(&act.sa_mask); act.sa_flags = 0; if (sigaction(signo, &act, &oact) < 0) return (SIG_ERR); return (oact.sa_handler); #elif defined(HAVE_SIGSET) return sigset(signo, func); #else return signal(signo, func); #endif /* HAVE_SIGACTION, HAVE_SIGSET */ } /************ *** MMAP *** ************/ #ifdef HAVE_SYS_MMAN_H #include #endif /** * fake implementation of mmap and munmap if we don't have them */ #if !defined(HAVE_MMAP) #define PROT_READ 0 #define MAP_FILE 0 #define MAP_SHARED 0 void *mmap(void *addr,size_t length,int prot, int flags, int fd, off_t offset) { void *buf = (void *)malloc(length); if(!buf) return 0; read(fd,buf,length); // should explore return code return buf; } void munmap(void *buf,size_t size) { free(buf); } #endif tcpflow-tcpflow-1.6.1/src/wifipcap/000077500000000000000000000000001401360461700172445ustar00rootroot00000000000000tcpflow-tcpflow-1.6.1/src/wifipcap/README.txt000066400000000000000000000037501401360461700207470ustar00rootroot00000000000000MAINTAINER ========== Simson L. Garfinkel ACKNOWLEDGEMENTS ================ Thanks to: * Jeffrey Pang, for the radiotap implementation * Doug Madory, for the Wifi parser * Jeremy Elson, for the original idea and initial tcp/ip implementation Title: Wifipcap Library Authors: Jeff Pang, Simson L. Garfinkel Description: ============ A simple C++ wrapper around libpcap that allows applications to selectively demultiplex 802.11 frames, and the most common layer 2 and layer 3 protocols contained within them. Basically, the wifipcap library handles all the parsing of 802.11 frames (and/or layer 2/3 packets) from the pcap file (or stream). Some of the code is derived from tcpdump. This program somewhat reworked by Simson Garfinkel Linux: Requires libpcap >= 0.9.4 on Linux. Windows: Requires WinPcap >= 4.0.2 and AirPcap for 802.11 capture See: http://www.cacetech.com/support/downloads.htm Usage: ====== For an overview see wifipcap.h. For an example, see sample.cpp. (0) Compile wifipcap. In Linux: Enter this directory and type: make In Windows: Open wifipcap.sln in Visual Studio and build it. You will need to have the winpcap include and library files in the appropriate search paths. (1) Include the header "wifipcap.h" in your application C++ file(s). (2) Implement a subclass of WifipcapCallbacks. This class has one member function for each type of 802.11 frame and layer 2/3 packets. Each of these functions will be called as a frame/packet is parsed. (3) Create an instance of Wifipcap with either a pcap trace file or a live device to capture packets from. (4) Call Wifipcap::Run with your instance of WifipcapCallbacks. (5) Compile your program linking to libpcap and wifipcap.a. On Linux: g++ -o myprogram myprogram.c /path/to/wifipcap.a -lpcap On Windows: Link the following libraries: wpcap.lib ws2_32.lib WINMM.LIB wifipcap.lib Make sure wifipcap.lib is in the library path. tcpflow-tcpflow-1.6.1/src/wifipcap/TimeVal.cpp000066400000000000000000000032661401360461700213200ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////// // Mercury and Colyseus Software Distribution // // Copyright (C) 2004-2005 Ashwin Bharambe (ashu@cs.cmu.edu) // 2004-2005 Jeffrey Pang (jeffpang@cs.cmu.edu) // 2004 Mukesh Agrawal (mukesh@cs.cmu.edu) // // 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 //////////////////////////////////////////////////////////////////////////////// /* -*- Mode:c++; c-basic-offset:4; tab-width:4; indent-tabs-mode:t -*- */ /************************************************************************** TimeVal.cpp begin : Oct 16, 2003 version : $Id: TimeVal.cpp,v 1.1.1.1 2006/12/14 01:22:11 jpang Exp $ copyright : (C) 2003 Jeff Pang ( jeffpang@cs.cmu.edu ) (C) 2003 Justin Weisz ( jweisz@cs.cmu.edu ) ***************************************************************************/ #include #include #include "TimeVal.h" //using namespace std; TimeVal TIME_NONE = {0,0}; tcpflow-tcpflow-1.6.1/src/wifipcap/TimeVal.h000066400000000000000000000112001401360461700207500ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////// // Mercury and Colyseus Software Distribution // // Copyright (C) 2004-2005 Ashwin Bharambe (ashu@cs.cmu.edu) // 2004-2005 Jeffrey Pang (jeffpang@cs.cmu.edu) // 2004 Mukesh Agrawal (mukesh@cs.cmu.edu) // 2013 Simson L. Garfinkel (simsong@acm.org) // // 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 //////////////////////////////////////////////////////////////////////////////// /* -*- Mode:c++; c-basic-offset:4; tab-width:4; indent-tabs-mode:t -*- */ /************************************************************************** TimeVal.h begin : Oct 16, 2003 version : $Id: TimeVal.h,v 1.1.1.1 2006/12/14 01:22:11 jpang Exp $ copyright : (C) 2003 Jeff Pang ( jeffpang@cs.cmu.edu ) (C) 2003 Justin Weisz ( jweisz@cs.cmu.edu ) (C) 2013 Simson Garfinkel ( simsong@acm.org ) ***************************************************************************/ #ifndef __TIME_VAL_H__ #define __TIME_VAL_H__ #include #include #ifndef _WIN32 #include #include #else #include #endif #include "types.h" typedef struct timeval TimeVal; #define MSEC_IN_SEC 1000 #define USEC_IN_SEC 1000000 #define USEC_IN_MSEC 1000 inline bool operator<(struct timeval a, struct timeval b) { return (a.tv_sec < b.tv_sec) || ((a.tv_sec == b.tv_sec) && (a.tv_usec < b.tv_usec)); } inline bool operator>(struct timeval a, struct timeval b) { return (a.tv_sec > b.tv_sec) || ((a.tv_sec == b.tv_sec) && (a.tv_usec > b.tv_usec)); } inline bool operator==(struct timeval a, struct timeval b) { return (a.tv_sec == b.tv_sec) && (a.tv_usec == b.tv_usec); } inline bool operator<=(struct timeval a, struct timeval b) { return a < b || a == b; } inline bool operator>=(struct timeval a, struct timeval b) { return a > b || a == b; } inline bool operator!=(struct timeval a, struct timeval b) { return !(a == b); } inline struct timeval operator+(struct timeval a, double add_msec) { struct timeval ret; // convert into sec/usec parts sint32 sec_part = (sint32)(add_msec/MSEC_IN_SEC); sint32 usec_part = (sint32)((add_msec - sec_part * MSEC_IN_SEC)*USEC_IN_MSEC); // do the initial addition ret.tv_sec = a.tv_sec + sec_part; ret.tv_usec = a.tv_usec + usec_part; // perform a carry if necessary if (ret.tv_usec > USEC_IN_SEC) { ret.tv_sec++; ret.tv_usec = ret.tv_usec % USEC_IN_SEC; } else if (ret.tv_usec < 0) { ret.tv_sec--; ret.tv_usec = USEC_IN_SEC + ret.tv_usec; } return ret; } inline int64_t operator-(struct timeval a, struct timeval b) { return ((sint64)a.tv_sec - (sint64)b.tv_sec)*USEC_IN_SEC + ((sint64)a.tv_usec - (sint64)b.tv_usec); } inline float timeval_to_float (struct timeval a) { return (float) a.tv_sec + ((float) a.tv_usec / USEC_IN_SEC); } inline std::ostream& operator<<(std::ostream& os, const TimeVal& t) { return os << &t; } #ifndef HAVE_TIMEVAL_OUT #define HAVE_TIMEVAL_OUT inline std::ostream& operator<<(std::ostream& os, const TimeVal* t) { return os << t->tv_sec << "." << std::setw(6) << std::setfill('0') << t->tv_usec; } #endif //bool operator<(struct timeval a, struct timeval b); //bool operator<=(struct timeval a, struct timeval b); //bool operator>(struct timeval a, struct timeval b); //bool operator>=(struct timeval a, struct timeval b); //bool operator==(struct timeval a, struct timeval b); //bool operator!=(struct timeval a, struct timeval b); //struct timeval operator+(struct timeval a, double add_msec); //sint64 operator-(struct timeval a, struct timeval b); /* usec result */ //float timeval_to_float (struct timeval a); extern TimeVal TIME_NONE; //std::ostream& operator<<(std::ostream& os, const TimeVal &t); //std::ostream& operator<<(std::ostream& os, const TimeVal *t); ////////////////////////////////////////////////////////////////////////////// #endif tcpflow-tcpflow-1.6.1/src/wifipcap/arp.h000066400000000000000000000067241401360461700202100ustar00rootroot00000000000000/* * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that: (1) source code distributions * retain the above copyright notice and this paragraph in its entirety, (2) * distributions including binary code include the above copyright notice and * this paragraph in its entirety in the documentation or other materials * provided with the distribution, and (3) all advertising materials mentioning * features or use of this software display the following acknowledgement: * ``This product includes software developed by the University of California, * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of * the University nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior * written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ /* * Address Resolution Protocol. * * See RFC 826 for protocol description. ARP packets are variable * in size; the arphdr structure defines the fixed-length portion. * Protocol type values are the same as those for 10 Mb/s Ethernet. * It is followed by the variable-sized fields ar_sha, arp_spa, * arp_tha and arp_tpa in that order, according to the lengths * specified. Field names used correspond to RFC 826. */ struct arp_pkthdr { u_short ar_hrd; /* format of hardware address */ #define ARPHRD_ETHER 1 /* ethernet hardware format */ #define ARPHRD_IEEE802 6 /* token-ring hardware format */ #define ARPHRD_ARCNET 7 /* arcnet hardware format */ #define ARPHRD_FRELAY 15 /* frame relay hardware format */ #define ARPHRD_STRIP 23 /* Ricochet Starmode Radio hardware format */ #define ARPHRD_IEEE1394 24 /* IEEE 1394 (FireWire) hardware format */ u_short ar_pro; /* format of protocol address */ u_char ar_hln; /* length of hardware address */ u_char ar_pln; /* length of protocol address */ u_short ar_op; /* one of: */ #define ARPOP_REQUEST 1 /* request to resolve address */ #define ARPOP_REPLY 2 /* response to previous request */ #define ARPOP_REVREQUEST 3 /* request protocol address given hardware */ #define ARPOP_REVREPLY 4 /* response giving protocol address */ #define ARPOP_INVREQUEST 8 /* request to identify peer */ #define ARPOP_INVREPLY 9 /* response identifying peer */ /* * The remaining fields are variable in size, * according to the sizes above. */ #ifdef COMMENT_ONLY u_char ar_sha[]; /* sender hardware address */ u_char ar_spa[]; /* sender protocol address */ u_char ar_tha[]; /* target hardware address */ u_char ar_tpa[]; /* target protocol address */ #endif #define ar_sha(ap) (((const u_char *)((ap)+1))+0) #define ar_spa(ap) (((const u_char *)((ap)+1))+ (ap)->ar_hln) #define ar_tha(ap) (((const u_char *)((ap)+1))+ (ap)->ar_hln+(ap)->ar_pln) #define ar_tpa(ap) (((const u_char *)((ap)+1))+2*(ap)->ar_hln+(ap)->ar_pln) }; #define ARP_HDRLEN 8 #define HRD(ap) EXTRACT_16BITS(&(ap)->ar_hrd) #define HLN(ap) ((ap)->ar_hln) #define PLN(ap) ((ap)->ar_pln) #define OP(ap) EXTRACT_16BITS(&(ap)->ar_op) #define PRO(ap) EXTRACT_16BITS(&(ap)->ar_pro) #define SHA(ap) (ar_sha(ap)) #define SPA(ap) (ar_spa(ap)) #define THA(ap) (ar_tha(ap)) #define TPA(ap) (ar_tpa(ap)) tcpflow-tcpflow-1.6.1/src/wifipcap/cpack.cpp000066400000000000000000000071251401360461700210360ustar00rootroot00000000000000/*- * Copyright (c) 2003, 2004 David Young. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of David Young may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. */ #ifndef WIN32 #include #include "cpack.h" #include "extract.h" static u_int8_t * cpack_next_boundary(u_int8_t *buf, u_int8_t *p, size_t alignment) { size_t misalignment = (size_t)(p - buf) % alignment; if (misalignment == 0) return p; return p + (alignment - misalignment); } /* Advance to the next wordsize boundary. Return NULL if fewer than * wordsize bytes remain in the buffer after the boundary. Otherwise, * return a pointer to the boundary. */ static u_int8_t * cpack_align_and_reserve(struct cpack_state *cs, size_t wordsize) { u_int8_t *next; /* Ensure alignment. */ next = cpack_next_boundary(cs->c_buf, cs->c_next, wordsize); /* Too little space for wordsize bytes? */ if (next - cs->c_buf + wordsize > cs->c_len) return 0; return next; } int cpack_init(struct cpack_state *cs, u_int8_t *buf, size_t buflen) { memset(cs, 0, sizeof(*cs)); cs->c_buf = buf; cs->c_len = buflen; cs->c_next = cs->c_buf; return 0; } /* Unpack a 64-bit unsigned integer. */ int cpack_uint64(struct cpack_state *cs, u_int64_t *u) { u_int8_t *next; if ((next = cpack_align_and_reserve(cs, sizeof(*u))) == NULL) return -1; *u = EXTRACT_LE_64BITS(next); /* Move pointer past the u_int64_t. */ cs->c_next = next + sizeof(*u); return 0; } /* Unpack a 32-bit unsigned integer. */ int cpack_uint32(struct cpack_state *cs, u_int32_t *u) { u_int8_t *next; if ((next = cpack_align_and_reserve(cs, sizeof(*u))) == NULL) return -1; *u = EXTRACT_LE_32BITS(next); /* Move pointer past the u_int32_t. */ cs->c_next = next + sizeof(*u); return 0; } /* Unpack a 16-bit unsigned integer. */ int cpack_uint16(struct cpack_state *cs, u_int16_t *u) { u_int8_t *next; if ((next = cpack_align_and_reserve(cs, sizeof(*u))) == NULL) return -1; *u = EXTRACT_LE_16BITS(next); /* Move pointer past the u_int16_t. */ cs->c_next = next + sizeof(*u); return 0; } /* Unpack an 8-bit unsigned integer. */ int cpack_uint8(struct cpack_state *cs, u_int8_t *u) { /* No space left? */ if ((size_t)(cs->c_next - cs->c_buf) >= cs->c_len) return -1; *u = *cs->c_next; /* Move pointer past the u_int8_t. */ cs->c_next++; return 0; } #endif tcpflow-tcpflow-1.6.1/src/wifipcap/cpack.h000066400000000000000000000044411401360461700205010ustar00rootroot00000000000000/*- * Copyright (c) 2003, 2004 David Young. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of David Young may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. */ #ifndef _CPACK_H #define _CPACK_H #include #include struct cpack_state { u_int8_t *c_buf; u_int8_t *c_next; size_t c_len; }; int cpack_init(struct cpack_state *, uint8_t *, size_t); int cpack_uint8(struct cpack_state *, uint8_t *); int cpack_uint16(struct cpack_state *, uint16_t *); int cpack_uint32(struct cpack_state *, uint32_t *); int cpack_uint64(struct cpack_state *, uint64_t *); inline int cpack_int8(struct cpack_state *s, int8_t *p) {return cpack_uint8(s,(uint8_t *)p);} inline int cpack_int16(struct cpack_state *s, int16_t *p) {return cpack_uint16(s,(uint16_t *)p);} inline int cpack_int32(struct cpack_state *s, int32_t *p) {return cpack_uint32(s,(uint32_t *)p);} inline int cpack_int64(struct cpack_state *s, int64_t *p) {return cpack_uint64(s,(uint64_t *)p);} #endif /* _CPACK_H */ tcpflow-tcpflow-1.6.1/src/wifipcap/ether.h000066400000000000000000000000741401360461700205250ustar00rootroot00000000000000 struct ether_hdr_t { MAC sa, da; uint16_t type; }; tcpflow-tcpflow-1.6.1/src/wifipcap/ethertype.h000066400000000000000000000101121401360461700214210ustar00rootroot00000000000000/* * Copyright (c) 1993, 1994, 1996 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that: (1) source code distributions * retain the above copyright notice and this paragraph in its entirety, (2) * distributions including binary code include the above copyright notice and * this paragraph in its entirety in the documentation or other materials * provided with the distribution, and (3) all advertising materials mentioning * features or use of this software display the following acknowledgement: * ``This product includes software developed by the University of California, * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of * the University nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior * written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * @(#) $Header: /home/cvs/wifitools/wifipcap/ethertype.h,v 1.1.1.1 2006/12/14 01:22:11 jpang Exp $ (LBL) */ #ifndef UNI_ETHERTYPE_H #define UNI_ETHERTYPE_H /* * Ethernet types. * * We wrap the declarations with #ifdef, so that if a file includes * , which may declare some of these, we don't * get a bunch of complaints from the C compiler about redefinitions * of these values. * * We declare all of them here so that no file has to include * if all it needs are ETHERTYPE_ values. */ #ifndef ETHERTYPE_LEN #define ETHERTYPE_LEN 2 #endif #ifndef ETHERTYPE_GRE_ISO #define ETHERTYPE_GRE_ISO 0x00FE /* not really an ethertype only used in GRE */ #endif #ifndef ETHERTYPE_PUP #define ETHERTYPE_PUP 0x0200 /* PUP protocol */ #endif #ifndef ETHERTYPE_IP #define ETHERTYPE_IP 0x0800 /* IP protocol */ #endif #ifndef ETHERTYPE_ARP #define ETHERTYPE_ARP 0x0806 /* Addr. resolution protocol */ #endif #ifndef ETHERTYPE_REVARP #define ETHERTYPE_REVARP 0x8035 /* reverse Addr. resolution protocol */ #endif #ifndef ETHERTYPE_NS #define ETHERTYPE_NS 0x0600 #endif #ifndef ETHERTYPE_SPRITE #define ETHERTYPE_SPRITE 0x0500 #endif #ifndef ETHERTYPE_TRAIL #define ETHERTYPE_TRAIL 0x1000 #endif #ifndef ETHERTYPE_MOPDL #define ETHERTYPE_MOPDL 0x6001 #endif #ifndef ETHERTYPE_MOPRC #define ETHERTYPE_MOPRC 0x6002 #endif #ifndef ETHERTYPE_DN #define ETHERTYPE_DN 0x6003 #endif #ifndef ETHERTYPE_LAT #define ETHERTYPE_LAT 0x6004 #endif #ifndef ETHERTYPE_SCA #define ETHERTYPE_SCA 0x6007 #endif #ifndef ETHERTYPE_LANBRIDGE #define ETHERTYPE_LANBRIDGE 0x8038 #endif #ifndef ETHERTYPE_DECDNS #define ETHERTYPE_DECDNS 0x803c #endif #ifndef ETHERTYPE_DECDTS #define ETHERTYPE_DECDTS 0x803e #endif #ifndef ETHERTYPE_VEXP #define ETHERTYPE_VEXP 0x805b #endif #ifndef ETHERTYPE_VPROD #define ETHERTYPE_VPROD 0x805c #endif #ifndef ETHERTYPE_ATALK #define ETHERTYPE_ATALK 0x809b #endif #ifndef ETHERTYPE_AARP #define ETHERTYPE_AARP 0x80f3 #endif #ifndef ETHERTYPE_8021Q #define ETHERTYPE_8021Q 0x8100 #endif #ifndef ETHERTYPE_IPX #define ETHERTYPE_IPX 0x8137 #endif #ifndef ETHERTYPE_IPV6 #define ETHERTYPE_IPV6 0x86dd #endif #ifndef ETHERTYPE_PPP #define ETHERTYPE_PPP 0x880b #endif #ifndef ETHERTYPE_SLOW #define ETHERTYPE_SLOW 0x8809 #endif #ifndef ETHERTYPE_MPLS #define ETHERTYPE_MPLS 0x8847 #endif #ifndef ETHERTYPE_MPLS_MULTI #define ETHERTYPE_MPLS_MULTI 0x8848 #endif #ifndef ETHERTYPE_PPPOED #define ETHERTYPE_PPPOED 0x8863 #endif #ifndef ETHERTYPE_PPPOES #define ETHERTYPE_PPPOES 0x8864 #endif #ifndef ETHERTYPE_JUMBO #define ETHERTYPE_JUMBO 0x8870 #endif #ifndef ETHERTYPE_EAPOL #define ETHERTYPE_EAPOL 0x888e #endif #ifndef ETHERTYPE_LOOPBACK #define ETHERTYPE_LOOPBACK 0x9000 #endif #ifndef ETHERTYPE_VMAN #define ETHERTYPE_VMAN 0x9100 /* Extreme VMAN Protocol */ #endif #ifndef ETHERTYPE_ISO #define ETHERTYPE_ISO 0xfefe /* nonstandard - used in Cisco HDLC encapsulation */ #endif #endif tcpflow-tcpflow-1.6.1/src/wifipcap/extract.h000066400000000000000000000130251401360461700210700ustar00rootroot00000000000000/* * Copyright (c) 1992, 1993, 1994, 1995, 1996 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that: (1) source code distributions * retain the above copyright notice and this paragraph in its entirety, (2) * distributions including binary code include the above copyright notice and * this paragraph in its entirety in the documentation or other materials * provided with the distribution, and (3) all advertising materials mentioning * features or use of this software display the following acknowledgement: * ``This product includes software developed by the University of California, * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of * the University nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior * written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * @(#) $Header: /home/cvs/wifitools/wifipcap/extract.h,v 1.1.1.1 2006/12/14 01:22:11 jpang Exp $ (LBL) */ #ifndef UNI_EXTRACT_H #define UNI_EXTRACT_H /* * Macros to extract possibly-unaligned big-endian integral values. */ #ifdef LBL_ALIGN /* * The processor doesn't natively handle unaligned loads. */ #ifdef HAVE___ATTRIBUTE__ /* * We have __attribute__; we assume that means we have __attribute__((packed)). * Declare packed structures containing a u_int16_t and a u_int32_t, * cast the pointer to point to one of those, and fetch through it; * the GCC manual doesn't appear to explicitly say that * __attribute__((packed)) causes the compiler to generate unaligned-safe * code, but it apppears to do so. * * We do this in case the compiler can generate, for this instruction set, * better code to do an unaligned load and pass stuff to "ntohs()" or * "ntohl()" than the code to fetch the bytes one at a time and * assemble them. (That might not be the case on a little-endian platform, * where "ntohs()" and "ntohl()" might not be done inline.) */ typedef struct { u_int16_t val; } __attribute__((packed)) unaligned_u_int16_t; typedef struct { u_int32_t val; } __attribute__((packed)) unaligned_u_int32_t; #define EXTRACT_16BITS(p) \ ((u_int16_t)ntohs(((const unaligned_u_int16_t *)(p))->val)) #define EXTRACT_32BITS(p) \ ((u_int32_t)ntohl(((const unaligned_u_int32_t *)(p))->val)) #define EXTRACT_64BITS(p) \ ((u_int64_t)(((u_int64_t)ntohl(((const unaligned_u_int32_t *)(p) + 0)->val)) << 32 | \ ((u_int64_t)ntohl(((const unaligned_u_int32_t *)(p) + 1)->val)) << 0)) #else /* HAVE___ATTRIBUTE__ */ /* * We don't have __attribute__, so do unaligned loads of big-endian * quantities the hard way - fetch the bytes one at a time and * assemble them. */ #define EXTRACT_16BITS(p) \ ((u_int16_t)((u_int16_t)*((const u_int8_t *)(p) + 0) << 8 | \ (u_int16_t)*((const u_int8_t *)(p) + 1))) #define EXTRACT_32BITS(p) \ ((u_int32_t)((u_int32_t)*((const u_int8_t *)(p) + 0) << 24 | \ (u_int32_t)*((const u_int8_t *)(p) + 1) << 16 | \ (u_int32_t)*((const u_int8_t *)(p) + 2) << 8 | \ (u_int32_t)*((const u_int8_t *)(p) + 3))) #define EXTRACT_64BITS(p) \ ((u_int64_t)((u_int64_t)*((const u_int8_t *)(p) + 0) << 56 | \ (u_int64_t)*((const u_int8_t *)(p) + 1) << 48 | \ (u_int64_t)*((const u_int8_t *)(p) + 2) << 40 | \ (u_int64_t)*((const u_int8_t *)(p) + 3) << 32 | \ (u_int64_t)*((const u_int8_t *)(p) + 4) << 24 | \ (u_int64_t)*((const u_int8_t *)(p) + 5) << 16 | \ (u_int64_t)*((const u_int8_t *)(p) + 6) << 8 | \ (u_int64_t)*((const u_int8_t *)(p) + 7))) #endif /* HAVE___ATTRIBUTE__ */ #else /* LBL_ALIGN */ /* * The processor natively handles unaligned loads, so we can just * cast the pointer and fetch through it. */ #define EXTRACT_16BITS(p) \ ((u_int16_t)ntohs(*(const u_int16_t *)(p))) #define EXTRACT_32BITS(p) \ ((u_int32_t)ntohl(*(const u_int32_t *)(p))) #define EXTRACT_64BITS(p) \ ((u_int64_t)(((u_int64_t)ntohl(*((const u_int32_t *)(p) + 0))) << 32 | \ ((u_int64_t)ntohl(*((const u_int32_t *)(p) + 1))) << 0)) #endif /* LBL_ALIGN */ #define EXTRACT_24BITS(p) \ ((u_int32_t)((u_int32_t)*((const u_int8_t *)(p) + 0) << 16 | \ (u_int32_t)*((const u_int8_t *)(p) + 1) << 8 | \ (u_int32_t)*((const u_int8_t *)(p) + 2))) /* * Macros to extract possibly-unaligned little-endian integral values. * XXX - do loads on little-endian machines that support unaligned loads? */ #define EXTRACT_LE_8BITS(p) (*(p)) #define EXTRACT_LE_16BITS(p) \ ((u_int16_t)((u_int16_t)*((const u_int8_t *)(p) + 1) << 8 | \ (u_int16_t)*((const u_int8_t *)(p) + 0))) #define EXTRACT_LE_32BITS(p) \ ((u_int32_t)((u_int32_t)*((const u_int8_t *)(p) + 3) << 24 | \ (u_int32_t)*((const u_int8_t *)(p) + 2) << 16 | \ (u_int32_t)*((const u_int8_t *)(p) + 1) << 8 | \ (u_int32_t)*((const u_int8_t *)(p) + 0))) #define EXTRACT_LE_64BITS(p) \ ((u_int64_t)((u_int64_t)*((const u_int8_t *)(p) + 7) << 56 | \ (u_int64_t)*((const u_int8_t *)(p) + 6) << 48 | \ (u_int64_t)*((const u_int8_t *)(p) + 5) << 40 | \ (u_int64_t)*((const u_int8_t *)(p) + 4) << 32 | \ (u_int64_t)*((const u_int8_t *)(p) + 3) << 24 | \ (u_int64_t)*((const u_int8_t *)(p) + 2) << 16 | \ (u_int64_t)*((const u_int8_t *)(p) + 1) << 8 | \ (u_int64_t)*((const u_int8_t *)(p) + 0))) #endif tcpflow-tcpflow-1.6.1/src/wifipcap/icmp.h000066400000000000000000000162661401360461700203600ustar00rootroot00000000000000/* * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994, 1995, 1996 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that: (1) source code distributions * retain the above copyright notice and this paragraph in its entirety, (2) * distributions including binary code include the above copyright notice and * this paragraph in its entirety in the documentation or other materials * provided with the distribution, and (3) all advertising materials mentioning * features or use of this software display the following acknowledgement: * ``This product includes software developed by the University of California, * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of * the University nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior * written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ /* * Interface Control Message Protocol Definitions. * Per RFC 792, September 1981. */ /* * Structure of an icmp header. */ struct icmp { u_int8_t icmp_type; /* type of message, see below */ u_int8_t icmp_code; /* type sub code */ u_int16_t icmp_cksum; /* ones complement cksum of struct */ union { u_int8_t ih_pptr; /* ICMP_PARAMPROB */ struct in_addr ih_gwaddr; /* ICMP_REDIRECT */ struct ih_idseq { u_int16_t icd_id; u_int16_t icd_seq; } ih_idseq; u_int32_t ih_void; /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ struct ih_pmtu { u_int16_t ipm_void; u_int16_t ipm_nextmtu; } ih_pmtu; } icmp_hun; #define icmp_pptr icmp_hun.ih_pptr #define icmp_gwaddr icmp_hun.ih_gwaddr #define icmp_id icmp_hun.ih_idseq.icd_id #define icmp_seq icmp_hun.ih_idseq.icd_seq #define icmp_void icmp_hun.ih_void #define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void #define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu union { struct id_ts { u_int32_t its_otime; u_int32_t its_rtime; u_int32_t its_ttime; } id_ts; struct id_ip { struct ip idi_ip; /* options and then 64 bits of data */ } id_ip; struct mpls_ext { u_int8_t legacy_header[128]; /* extension header starts 128 bytes after ICMP header */ u_int8_t version_res[2]; u_int8_t checksum[2]; u_int8_t data[1]; } mpls_ext; u_int32_t id_mask; u_int8_t id_data[1]; } icmp_dun; #define icmp_otime icmp_dun.id_ts.its_otime #define icmp_rtime icmp_dun.id_ts.its_rtime #define icmp_ttime icmp_dun.id_ts.its_ttime #define icmp_ip icmp_dun.id_ip.idi_ip #define icmp_mask icmp_dun.id_mask #define icmp_data icmp_dun.id_data #define icmp_mpls_ext_version icmp_dun.mpls_ext.version_res #define icmp_mpls_ext_checksum icmp_dun.mpls_ext.checksum #define icmp_mpls_ext_data icmp_dun.mpls_ext.data }; #define ICMP_MPLS_EXT_EXTRACT_VERSION(x) (((x)&0xf0)>>4) #define ICMP_MPLS_EXT_VERSION 2 /* * Lower bounds on packet lengths for various types. * For the error advice packets must first insure that the * packet is large enought to contain the returned ip header. * Only then can we do the check to see if 64 bits of packet * data have been returned, since we need to check the returned * ip header length. */ #define ICMP_MINLEN 8 /* abs minimum */ #define ICMP_EXTD_MINLEN (156 - sizeof (struct ip)) /* draft-bonica-icmp-mpls-02 */ #define ICMP_TSLEN (8 + 3 * sizeof (u_int32_t)) /* timestamp */ #define ICMP_MASKLEN 12 /* address mask */ #define ICMP_ADVLENMIN (8 + sizeof (struct ip) + 8) /* min */ #define ICMP_ADVLEN(p) (8 + (IP_HL(&(p)->icmp_ip) << 2) + 8) /* N.B.: must separately check that ip_hl >= 5 */ /* * Definition of type and code field values. */ #define ICMP_ECHOREPLY 0 /* echo reply */ #define ICMP_UNREACH 3 /* dest unreachable, codes: */ #define ICMP_UNREACH_NET 0 /* bad net */ #define ICMP_UNREACH_HOST 1 /* bad host */ #define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */ #define ICMP_UNREACH_PORT 3 /* bad port */ #define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */ #define ICMP_UNREACH_SRCFAIL 5 /* src route failed */ #define ICMP_UNREACH_NET_UNKNOWN 6 /* unknown net */ #define ICMP_UNREACH_HOST_UNKNOWN 7 /* unknown host */ #define ICMP_UNREACH_ISOLATED 8 /* src host isolated */ #define ICMP_UNREACH_NET_PROHIB 9 /* prohibited access */ #define ICMP_UNREACH_HOST_PROHIB 10 /* ditto */ #define ICMP_UNREACH_TOSNET 11 /* bad tos for net */ #define ICMP_UNREACH_TOSHOST 12 /* bad tos for host */ #define ICMP_SOURCEQUENCH 4 /* packet lost, slow down */ #define ICMP_REDIRECT 5 /* shorter route, codes: */ #define ICMP_REDIRECT_NET 0 /* for network */ #define ICMP_REDIRECT_HOST 1 /* for host */ #define ICMP_REDIRECT_TOSNET 2 /* for tos and net */ #define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */ #define ICMP_ECHO 8 /* echo service */ #define ICMP_ROUTERADVERT 9 /* router advertisement */ #define ICMP_ROUTERSOLICIT 10 /* router solicitation */ #define ICMP_TIMXCEED 11 /* time exceeded, code: */ #define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */ #define ICMP_TIMXCEED_REASS 1 /* ttl==0 in reass */ #define ICMP_PARAMPROB 12 /* ip header bad */ #define ICMP_PARAMPROB_OPTABSENT 1 /* req. opt. absent */ #define ICMP_TSTAMP 13 /* timestamp request */ #define ICMP_TSTAMPREPLY 14 /* timestamp reply */ #define ICMP_IREQ 15 /* information request */ #define ICMP_IREQREPLY 16 /* information reply */ #define ICMP_MASKREQ 17 /* address mask request */ #define ICMP_MASKREPLY 18 /* address mask reply */ #define ICMP_MAXTYPE 18 #define ICMP_INFOTYPE(type) \ ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \ (type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \ (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \ (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \ (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY) #define ICMP_MPLS_EXT_TYPE(type) \ ((type) == ICMP_UNREACH || (type) == ICMP_TIMXCEED) /* rfc1700 */ #ifndef ICMP_UNREACH_NET_UNKNOWN #define ICMP_UNREACH_NET_UNKNOWN 6 /* destination net unknown */ #endif #ifndef ICMP_UNREACH_HOST_UNKNOWN #define ICMP_UNREACH_HOST_UNKNOWN 7 /* destination host unknown */ #endif #ifndef ICMP_UNREACH_ISOLATED #define ICMP_UNREACH_ISOLATED 8 /* source host isolated */ #endif #ifndef ICMP_UNREACH_NET_PROHIB #define ICMP_UNREACH_NET_PROHIB 9 /* admin prohibited net */ #endif #ifndef ICMP_UNREACH_HOST_PROHIB #define ICMP_UNREACH_HOST_PROHIB 10 /* admin prohibited host */ #endif #ifndef ICMP_UNREACH_TOSNET #define ICMP_UNREACH_TOSNET 11 /* tos prohibited net */ #endif #ifndef ICMP_UNREACH_TOSHOST #define ICMP_UNREACH_TOSHOST 12 /* tos prohibited host */ #endif /* rfc1716 */ #ifndef ICMP_UNREACH_FILTER_PROHIB #define ICMP_UNREACH_FILTER_PROHIB 13 /* admin prohibited filter */ #endif #ifndef ICMP_UNREACH_HOST_PRECEDENCE #define ICMP_UNREACH_HOST_PRECEDENCE 14 /* host precedence violation */ #endif #ifndef ICMP_UNREACH_PRECEDENCE_CUTOFF #define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 /* precedence cutoff */ #endif tcpflow-tcpflow-1.6.1/src/wifipcap/ieee802_11_radio.h000066400000000000000000000234041401360461700222400ustar00rootroot00000000000000/*- * Copyright (c) 2003, 2004 David Young. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of David Young may not be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. */ /* Copyright 2013 Simson L. Garfinkel * Cleaned up. */ #ifndef _NET_IF_IEEE80211RADIOTAP_H_ #define _NET_IF_IEEE80211RADIOTAP_H_ #include "os.h" /* A generic radio capture format is desirable. There is one for * Linux, but it is neither rigidly defined (there were not even * units given for some fields) nor easily extensible. * * I suggest the following extensible radio capture format. It is * based on a bitmap indicating which fields are present. * * I am trying to describe precisely what the application programmer * should expect in the following, and for that reason I tell the * units and origin of each measurement (where it applies), or else I * use sufficiently weaselly language ("is a monotonically nondecreasing * function of...") that I cannot set false expectations for lawyerly * readers. */ #ifndef DLT_IEEE802_11_RADIO #define DLT_IEEE802_11_RADIO 127 /* 802.11 plus WLAN header */ #endif #ifdef _WIN32 #pragma pack(push, 1) #endif /* The radio capture header precedes the 802.11 header. */ struct ieee80211_radiotap_header { u_int8_t it_version; /* Version 0. Only increases * for drastic changes, * introduction of compatible * new fields does not count. */ u_int8_t it_pad; u_int16_t it_len; /* length of the whole * header in bytes, including * it_version, it_pad, * it_len, and data fields. */ u_int32_t it_present; /* A bitmap telling which * fields are present. Set bit 31 * (0x80000000) to extend the * bitmap by another 32 bits. * Additional extensions are made * by setting bit 31. */ } _PACKED_; #ifdef _WIN32 #pragma pack(pop) #endif /* Name Data type Units * ---- --------- ----- * * IEEE80211_RADIOTAP_TSFT u_int64_t microseconds * * Value in microseconds of the MAC's 64-bit 802.11 Time * Synchronization Function timer when the first bit of the * MPDU arrived at the MAC. For received frames, only. * * IEEE80211_RADIOTAP_CHANNEL 2 x u_int16_t MHz, bitmap * * Tx/Rx frequency in MHz, followed by flags (see below). * * IEEE80211_RADIOTAP_FHSS u_int16_t see below * * For frequency-hopping radios, the hop set (first byte) * and pattern (second byte). * * IEEE80211_RADIOTAP_RATE u_int8_t 500kb/s * * Tx/Rx data rate * * IEEE80211_RADIOTAP_DBM_ANTSIGNAL int8_t decibels from * one milliwatt (dBm) * * RF signal power at the antenna, decibel difference from * one milliwatt. * * IEEE80211_RADIOTAP_DBM_ANTNOISE int8_t decibels from * one milliwatt (dBm) * * RF noise power at the antenna, decibel difference from one * milliwatt. * * IEEE80211_RADIOTAP_DB_ANTSIGNAL u_int8_t decibel (dB) * * RF signal power at the antenna, decibel difference from an * arbitrary, fixed reference. * * IEEE80211_RADIOTAP_DB_ANTNOISE u_int8_t decibel (dB) * * RF noise power at the antenna, decibel difference from an * arbitrary, fixed reference point. * * IEEE80211_RADIOTAP_LOCK_QUALITY u_int16_t unitless * * Quality of Barker code lock. Unitless. Monotonically * nondecreasing with "better" lock strength. Called "Signal * Quality" in datasheets. (Is there a standard way to measure * this?) * * IEEE80211_RADIOTAP_TX_ATTENUATION u_int16_t unitless * * Transmit power expressed as unitless distance from max * power set at factory calibration. 0 is max power. * Monotonically nondecreasing with lower power levels. * * IEEE80211_RADIOTAP_DB_TX_ATTENUATION u_int16_t decibels (dB) * * Transmit power expressed as decibel distance from max power * set at factory calibration. 0 is max power. Monotonically * nondecreasing with lower power levels. * * IEEE80211_RADIOTAP_DBM_TX_POWER int8_t decibels from * one milliwatt (dBm) * * Transmit power expressed as dBm (decibels from a 1 milliwatt * reference). This is the absolute power level measured at * the antenna port. * * IEEE80211_RADIOTAP_FLAGS u_int8_t bitmap * * Properties of transmitted and received frames. See flags * defined below. * * IEEE80211_RADIOTAP_ANTENNA u_int8_t antenna index * * Unitless indication of the Rx/Tx antenna for this packet. * The first antenna is antenna 0. * * IEEE80211_RADIOTAP_FCS u_int32_t data * * FCS from frame in network byte order. */ enum ieee80211_radiotap_type { IEEE80211_RADIOTAP_TSFT = 0, IEEE80211_RADIOTAP_FLAGS = 1, IEEE80211_RADIOTAP_RATE = 2, IEEE80211_RADIOTAP_CHANNEL = 3, IEEE80211_RADIOTAP_FHSS = 4, IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5, IEEE80211_RADIOTAP_DBM_ANTNOISE = 6, IEEE80211_RADIOTAP_LOCK_QUALITY = 7, IEEE80211_RADIOTAP_TX_ATTENUATION = 8, IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9, IEEE80211_RADIOTAP_DBM_TX_POWER = 10, IEEE80211_RADIOTAP_ANTENNA = 11, IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12, IEEE80211_RADIOTAP_DB_ANTNOISE = 13, IEEE80211_RADIOTAP_RX_FLAGS = 14, IEEE80211_RADIOTAP_TX_FLAGS = 15, IEEE80211_RADIOTAP_RTS_RETRIES = 16, IEEE80211_RADIOTAP_DATA_RETRIES = 17, IEEE80211_RADIOTAP_XCHANNEL = 18, /* Unofficial, used by FreeBSD */ IEEE80211_RADIOTAP_MCS = 19, IEEE80211_RADIOTAP_AMPDU_STATUS = 20, /* valid in every it_present bitmap, even vendor namespaces */ IEEE80211_RADIOTAP_RADIOTAP_NAMESPACE = 29, IEEE80211_RADIOTAP_EXT = 31 }; /* Channel flags. */ #define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */ #define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */ #define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */ #define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */ #define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */ #define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */ #define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */ #define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */ /* For IEEE80211_RADIOTAP_FLAGS */ #define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received * during CFP */ #define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received * with short * preamble */ #define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received * with WEP encryption */ #define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received * with fragmentation */ #define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */ #define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between * 802.11 header and payload * (to 32-bit boundary) */ #define IEEE80211_RADIOTAP_F_BADFCS 0x40 /* does not pass FCS check */ /* For IEEE80211_RADIOTAP_RX_FLAGS */ #define IEEE80211_RADIOTAP_F_RX_BADPLCP 0x0002 /* bad PLCP */ /* For IEEE80211_RADIOTAP_TX_FLAGS */ #define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive * retries */ #define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */ #define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */ /* For IEEE80211_RADIOTAP_AMPDU_STATUS */ #define IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN 0x0001 #define IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN 0x0002 #define IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN 0x0004 #define IEEE80211_RADIOTAP_AMPDU_IS_LAST 0x0008 #define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_ERR 0x0010 #define IEEE80211_RADIOTAP_AMPDU_DELIM_CRC_KNOWN 0x0020 /* For IEEE80211_RADIOTAP_MCS */ #define IEEE80211_RADIOTAP_MCS_HAVE_BW 0x01 #define IEEE80211_RADIOTAP_MCS_HAVE_MCS 0x02 #define IEEE80211_RADIOTAP_MCS_HAVE_GI 0x04 #define IEEE80211_RADIOTAP_MCS_HAVE_FMT 0x08 #define IEEE80211_RADIOTAP_MCS_HAVE_FEC 0x10 #define IEEE80211_RADIOTAP_MCS_BW_MASK 0x03 #define IEEE80211_RADIOTAP_MCS_BW_20 0 #define IEEE80211_RADIOTAP_MCS_BW_40 1 #define IEEE80211_RADIOTAP_MCS_BW_20L 2 #define IEEE80211_RADIOTAP_MCS_BW_20U 3 #define IEEE80211_RADIOTAP_MCS_SGI 0x04 #define IEEE80211_RADIOTAP_MCS_FMT_GF 0x08 #define IEEE80211_RADIOTAP_MCS_FEC_LDPC 0x10 #endif /* _NET_IF_IEEE80211RADIOTAP_H_ */ tcpflow-tcpflow-1.6.1/src/wifipcap/ip.h000066400000000000000000000151651401360461700200350ustar00rootroot00000000000000/* @(#) $Header: /home/cvs/wifitools/wifipcap/ip.h,v 1.1.1.1 2006/12/14 01:22:11 jpang Exp $ (LBL) */ /* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)ip.h 8.2 (Berkeley) 6/1/94 */ /* * Definitions for internet protocol version 4. * Per RFC 791, September 1981. */ #define IPVERSION 4 /* * Structure of an internet header, naked of options. * * We declare ip_len and ip_off to be short, rather than u_short * pragmatically since otherwise unsigned comparisons can result * against negative integers quite easily, and fail in subtle ways. */ struct ip { u_int8_t ip_vhl; /* header length, version */ #define IP_V(ip) (((ip)->ip_vhl & 0xf0) >> 4) #define IP_HL(ip) ((ip)->ip_vhl & 0x0f) u_int8_t ip_tos; /* type of service */ u_int16_t ip_len; /* total length */ u_int16_t ip_id; /* identification */ u_int16_t ip_off; /* fragment offset field */ #define IP_DF 0x4000 /* dont fragment flag */ #define IP_MF 0x2000 /* more fragments flag */ #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ u_int8_t ip_ttl; /* time to live */ u_int8_t ip_p; /* protocol */ u_int16_t ip_sum; /* checksum */ struct in_addr ip_src,ip_dst; /* source and dest address */ }; #define IP_MAXPACKET 65535 /* maximum packet size */ /* * Definitions for IP type of service (ip_tos) */ #define IPTOS_LOWDELAY 0x10 #define IPTOS_THROUGHPUT 0x08 #define IPTOS_RELIABILITY 0x04 /* * Definitions for IP precedence (also in ip_tos) (hopefully unused) */ #define IPTOS_PREC_NETCONTROL 0xe0 #define IPTOS_PREC_INTERNETCONTROL 0xc0 #define IPTOS_PREC_CRITIC_ECP 0xa0 #define IPTOS_PREC_FLASHOVERRIDE 0x80 #define IPTOS_PREC_FLASH 0x60 #define IPTOS_PREC_IMMEDIATE 0x40 #define IPTOS_PREC_PRIORITY 0x20 #define IPTOS_PREC_ROUTINE 0x00 /* * Definitions for options. */ #define IPOPT_COPIED(o) ((o)&0x80) #define IPOPT_CLASS(o) ((o)&0x60) #define IPOPT_NUMBER(o) ((o)&0x1f) #define IPOPT_CONTROL 0x00 #define IPOPT_RESERVED1 0x20 #define IPOPT_DEBMEAS 0x40 #define IPOPT_RESERVED2 0x60 #define IPOPT_EOL 0 /* end of option list */ #define IPOPT_NOP 1 /* no operation */ #define IPOPT_RR 7 /* record packet route */ #define IPOPT_TS 68 /* timestamp */ #define IPOPT_SECURITY 130 /* provide s,c,h,tcc */ #define IPOPT_LSRR 131 /* loose source route */ #define IPOPT_SATID 136 /* satnet id */ #define IPOPT_SSRR 137 /* strict source route */ #define IPOPT_RA 148 /* router-alert, rfc2113 */ /* * Offsets to fields in options other than EOL and NOP. */ #define IPOPT_OPTVAL 0 /* option ID */ #define IPOPT_OLEN 1 /* option length */ #define IPOPT_OFFSET 2 /* offset within option */ #define IPOPT_MINOFF 4 /* min value of above */ /* * Time stamp option structure. */ struct ip_timestamp { u_int8_t ipt_code; /* IPOPT_TS */ u_int8_t ipt_len; /* size of structure (variable) */ u_int8_t ipt_ptr; /* index of current entry */ u_int8_t ipt_oflwflg; /* flags, overflow counter */ #define IPTS_OFLW(ip) (((ipt)->ipt_oflwflg & 0xf0) >> 4) #define IPTS_FLG(ip) ((ipt)->ipt_oflwflg & 0x0f) union ipt_timestamp { u_int32_t ipt_time[1]; struct ipt_ta { struct in_addr ipt_addr; u_int32_t ipt_time; } ipt_ta[1]; } ipt_timestamp; }; /* flag bits for ipt_flg */ #define IPOPT_TS_TSONLY 0 /* timestamps only */ #define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */ #define IPOPT_TS_PRESPEC 3 /* specified modules only */ /* bits for security (not byte swapped) */ #define IPOPT_SECUR_UNCLASS 0x0000 #define IPOPT_SECUR_CONFID 0xf135 #define IPOPT_SECUR_EFTO 0x789a #define IPOPT_SECUR_MMMM 0xbc4d #define IPOPT_SECUR_RESTR 0xaf13 #define IPOPT_SECUR_SECRET 0xd788 #define IPOPT_SECUR_TOPSECRET 0x6bc5 /* * Internet implementation parameters. */ #define MAXTTL 255 /* maximum time to live (seconds) */ #define IPDEFTTL 64 /* default ttl, from RFC 1340 */ #define IPFRAGTTL 60 /* time to live for frags, slowhz */ #define IPTTLDEC 1 /* subtracted when forwarding */ #define IP_MSS 576 /* default maximum segment size */ /* in print-ip.c */ extern u_int32_t ip_finddst(const struct ip *); /////////////////////////////////////////////////////////////////////////////// /* Jeff: will pass this endian-fixed, fully decoded version to applications */ struct ip4_hdr_t { u_int8_t ver; /* ip version */ u_int16_t hlen; /* header length (in bytes) */ u_int8_t tos; /* type of service */ u_int16_t len; /* total length (in bytes) */ u_int16_t id; /* identification */ bool df; /* don't fragment flag */ bool mf; /* more fragments flag */ u_int16_t fragoff; /* fragment offset */ u_int8_t ttl; /* time to live */ u_int8_t proto; /* protocol */ u_int16_t cksum; /* header checksum */ struct in_addr src, dst; /* source and dest address */ }; tcpflow-tcpflow-1.6.1/src/wifipcap/ip6.h000066400000000000000000000175211401360461700201210ustar00rootroot00000000000000/* @(#) $Header: /home/cvs/wifitools/wifipcap/ip6.h,v 1.1.1.1 2006/12/14 01:22:11 jpang Exp $ (LBL) */ /* $NetBSD: ip6.h,v 1.9 2000/07/13 05:34:21 itojun Exp $ */ /* $KAME: ip6.h,v 1.9 2000/07/02 21:01:32 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)ip.h 8.1 (Berkeley) 6/10/93 */ #ifndef _NETINET_IP6_H_ #define _NETINET_IP6_H_ /* * Definition for internet protocol version 6. * RFC 2460 */ struct ip6_hdr { union { struct ip6_hdrctl { u_int32_t ip6_un1_flow; /* 20 bits of flow-ID */ u_int16_t ip6_un1_plen; /* payload length */ u_int8_t ip6_un1_nxt; /* next header */ u_int8_t ip6_un1_hlim; /* hop limit */ } ip6_un1; u_int8_t ip6_un2_vfc; /* 4 bits version, top 4 bits class */ } ip6_ctlun; struct in6_addr ip6_src; /* source address */ struct in6_addr ip6_dst; /* destination address */ }; #define ip6_vfc ip6_ctlun.ip6_un2_vfc #define ip6_flow ip6_ctlun.ip6_un1.ip6_un1_flow #define ip6_plen ip6_ctlun.ip6_un1.ip6_un1_plen #define ip6_nxt ip6_ctlun.ip6_un1.ip6_un1_nxt #define ip6_hlim ip6_ctlun.ip6_un1.ip6_un1_hlim #define ip6_hops ip6_ctlun.ip6_un1.ip6_un1_hlim /* in network endian */ #define IPV6_FLOWINFO_MASK ((u_int32_t)htonl(0x0fffffff)) /* flow info (28 bits) */ #define IPV6_FLOWLABEL_MASK ((u_int32_t)htonl(0x000fffff)) /* flow label (20 bits) */ #if 1 /* ECN bits proposed by Sally Floyd */ #define IP6TOS_CE 0x01 /* congestion experienced */ #define IP6TOS_ECT 0x02 /* ECN-capable transport */ #endif /* * Extension Headers */ struct ip6_ext { u_char ip6e_nxt; u_char ip6e_len; }; /* Hop-by-Hop options header */ /* XXX should we pad it to force alignment on an 8-byte boundary? */ struct ip6_hbh { u_int8_t ip6h_nxt; /* next header */ u_int8_t ip6h_len; /* length in units of 8 octets */ /* followed by options */ }; /* Destination options header */ /* XXX should we pad it to force alignment on an 8-byte boundary? */ struct ip6_dest { u_int8_t ip6d_nxt; /* next header */ u_int8_t ip6d_len; /* length in units of 8 octets */ /* followed by options */ }; /* Option types and related macros */ #define IP6OPT_PAD1 0x00 /* 00 0 00000 */ #define IP6OPT_PADN 0x01 /* 00 0 00001 */ #define IP6OPT_JUMBO 0xC2 /* 11 0 00010 = 194 */ #define IP6OPT_JUMBO_LEN 6 #define IP6OPT_ROUTER_ALERT 0x05 /* 00 0 00101 */ #define IP6OPT_RTALERT_LEN 4 #define IP6OPT_RTALERT_MLD 0 /* Datagram contains an MLD message */ #define IP6OPT_RTALERT_RSVP 1 /* Datagram contains an RSVP message */ #define IP6OPT_RTALERT_ACTNET 2 /* contains an Active Networks msg */ #define IP6OPT_MINLEN 2 #define IP6OPT_BINDING_UPDATE 0xc6 /* 11 0 00110 */ #define IP6OPT_BINDING_ACK 0x07 /* 00 0 00111 */ #define IP6OPT_BINDING_REQ 0x08 /* 00 0 01000 */ #define IP6OPT_HOME_ADDRESS 0xc9 /* 11 0 01001 */ #define IP6OPT_EID 0x8a /* 10 0 01010 */ #define IP6OPT_TYPE(o) ((o) & 0xC0) #define IP6OPT_TYPE_SKIP 0x00 #define IP6OPT_TYPE_DISCARD 0x40 #define IP6OPT_TYPE_FORCEICMP 0x80 #define IP6OPT_TYPE_ICMP 0xC0 #define IP6OPT_MUTABLE 0x20 /* Routing header */ struct ip6_rthdr { u_int8_t ip6r_nxt; /* next header */ u_int8_t ip6r_len; /* length in units of 8 octets */ u_int8_t ip6r_type; /* routing type */ u_int8_t ip6r_segleft; /* segments left */ /* followed by routing type specific data */ }; /* Type 0 Routing header */ struct ip6_rthdr0 { u_int8_t ip6r0_nxt; /* next header */ u_int8_t ip6r0_len; /* length in units of 8 octets */ u_int8_t ip6r0_type; /* always zero */ u_int8_t ip6r0_segleft; /* segments left */ u_int8_t ip6r0_reserved; /* reserved field */ u_int8_t ip6r0_slmap[3]; /* strict/loose bit map */ struct in6_addr ip6r0_addr[1]; /* up to 23 addresses */ }; /* Fragment header */ struct ip6_frag { u_int8_t ip6f_nxt; /* next header */ u_int8_t ip6f_reserved; /* reserved field */ u_int16_t ip6f_offlg; /* offset, reserved, and flag */ u_int32_t ip6f_ident; /* identification */ }; #define IP6F_OFF_MASK 0xfff8 /* mask out offset from ip6f_offlg */ #define IP6F_RESERVED_MASK 0x0006 /* reserved bits in ip6f_offlg */ #define IP6F_MORE_FRAG 0x0001 /* more-fragments flag */ #endif /* not _NETINET_IP6_H_ */ /* Jeff: endian-fixed, decoded version passed to apps (XXX TODO) */ struct ip6_hdr_t { union { struct ip6_hdrctl { u_int32_t ip6_un1_flow; /* 20 bits of flow-ID */ u_int16_t ip6_un1_plen; /* payload length */ u_int8_t ip6_un1_nxt; /* next header */ u_int8_t ip6_un1_hlim; /* hop limit */ } ip6_un1; u_int8_t ip6_un2_vfc; /* 4 bits version, top 4 bits class */ } ip6_ctlun; struct in6_addr ip6_src; /* source address */ struct in6_addr ip6_dst; /* destination address */ }; tcpflow-tcpflow-1.6.1/src/wifipcap/ipproto.h000066400000000000000000000113051401360461700211110ustar00rootroot00000000000000/* * Copyright (c) 1982, 1986, 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#) $Header: /home/cvs/wifitools/wifipcap/ipproto.h,v 1.1.1.1 2006/12/14 01:22:11 jpang Exp $ (LBL) * * From: * @(#)in.h 8.3 (Berkeley) 1/3/94 * $FreeBSD: src/sys/netinet/in.h,v 1.38.2.3 1999/08/29 16:29:34 peter Exp $ */ /*extern struct tok ipproto_values[];*/ #ifndef IPPROTO_IP #define IPPROTO_IP 0 /* dummy for IP */ #endif #ifndef IPPROTO_HOPOPTS #define IPPROTO_HOPOPTS 0 /* IPv6 hop-by-hop options */ #endif #ifndef IPPROTO_ICMP #define IPPROTO_ICMP 1 /* control message protocol */ #endif #ifndef IPPROTO_IGMP #define IPPROTO_IGMP 2 /* group mgmt protocol */ #endif #ifndef IPPROTO_IPV4 #define IPPROTO_IPV4 4 #endif #ifndef IPPROTO_TCP #define IPPROTO_TCP 6 /* tcp */ #endif #ifndef IPPROTO_EGP #define IPPROTO_EGP 8 /* exterior gateway protocol */ #endif #ifndef IPPROTO_PIGP #define IPPROTO_PIGP 9 #endif #ifndef IPPROTO_UDP #define IPPROTO_UDP 17 /* user datagram protocol */ #endif #ifndef IPPROTO_DCCP #define IPPROTO_DCCP 33 /* datagram congestion control protocol */ #endif #ifndef IPPROTO_IPV6 #define IPPROTO_IPV6 41 #endif #ifndef IPPROTO_ROUTING #define IPPROTO_ROUTING 43 /* IPv6 routing header */ #endif #ifndef IPPROTO_FRAGMENT #define IPPROTO_FRAGMENT 44 /* IPv6 fragmentation header */ #endif #ifndef IPPROTO_RSVP #define IPPROTO_RSVP 46 /* resource reservation */ #endif #ifndef IPPROTO_GRE #define IPPROTO_GRE 47 /* General Routing Encap. */ #endif #ifndef IPPROTO_ESP #define IPPROTO_ESP 50 /* SIPP Encap Sec. Payload */ #endif #ifndef IPPROTO_AH #define IPPROTO_AH 51 /* SIPP Auth Header */ #endif #ifndef IPPROTO_MOBILE #define IPPROTO_MOBILE 55 #endif #ifndef IPPROTO_ICMPV6 #define IPPROTO_ICMPV6 58 /* ICMPv6 */ #endif #ifndef IPPROTO_NONE #define IPPROTO_NONE 59 /* IPv6 no next header */ #endif #ifndef IPPROTO_DSTOPTS #define IPPROTO_DSTOPTS 60 /* IPv6 destination options */ #endif #ifndef IPPROTO_MOBILITY_OLD /* * The current Protocol Numbers list says that the IP protocol number for * mobility headers is 135; it cites draft-ietf-mobileip-ipv6-24, but * that draft doesn't actually give a number. * * It appears that 62 used to be used, even though that's assigned to * a protocol called CFTP; however, the only reference for CFTP is a * Network Message from BBN back in 1982, so, for now, we support 62, * aas well as 135, as a protocol number for mobility headers. */ #define IPPROTO_MOBILITY_OLD 62 #endif #ifndef IPPROTO_ND #define IPPROTO_ND 77 /* Sun net disk proto (temp.) */ #endif #ifndef IPPROTO_EIGRP #define IPPROTO_EIGRP 88 /* Cisco/GXS IGRP */ #endif #ifndef IPPROTO_OSPF #define IPPROTO_OSPF 89 #endif #ifndef IPPROTO_PIM #define IPPROTO_PIM 103 #endif #ifndef IPPROTO_IPCOMP #define IPPROTO_IPCOMP 108 #endif #ifndef IPPROTO_VRRP #define IPPROTO_VRRP 112 #endif #ifndef IPPROTO_PGM #define IPPROTO_PGM 113 #endif #ifndef IPPROTO_SCTP #define IPPROTO_SCTP 132 #endif #ifndef IPPROTO_MOBILITY #define IPPROTO_MOBILITY 135 #endif tcpflow-tcpflow-1.6.1/src/wifipcap/llc.h000066400000000000000000000073061401360461700201750ustar00rootroot00000000000000/* * Copyright (c) 1993, 1994, 1997 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that: (1) source code distributions * retain the above copyright notice and this paragraph in its entirety, (2) * distributions including binary code include the above copyright notice and * this paragraph in its entirety in the documentation or other materials * provided with the distribution, and (3) all advertising materials mentioning * features or use of this software display the following acknowledgement: * ``This product includes software developed by the University of California, * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of * the University nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior * written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * * @(#) $Header: /home/cvs/wifitools/wifipcap/llc.h,v 1.1.1.1 2006/12/14 01:22:11 jpang Exp $ (LBL) */ /* * Definitions for information in the LLC header. */ #ifndef UNI_LLC_H #define UNI_LLC_H #define LLC_U_FMT 3 #define LLC_GSAP 1 #define LLC_IG 1 /* Individual / Group */ #define LLC_S_FMT 1 #define LLC_U_POLL 0x10 #define LLC_IS_POLL 0x0100 #define LLC_XID_FI 0x81 #define LLC_U_CMD(u) ((u) & 0xef) #define LLC_UI 0x03 #define LLC_UA 0x63 #define LLC_DISC 0x43 #define LLC_DM 0x0f #define LLC_SABME 0x6f #define LLC_TEST 0xe3 #define LLC_XID 0xaf #define LLC_FRMR 0x87 #define LLC_S_CMD(is) (((is) >> 2) & 0x03) #define LLC_RR 0x0001 #define LLC_RNR 0x0005 #define LLC_REJ 0x0009 #define LLC_IS_NR(is) (((is) >> 9) & 0x7f) #define LLC_I_NS(is) (((is) >> 1) & 0x7f) #ifndef LLCSAP_NULL #define LLCSAP_NULL 0x00 #endif #ifndef LLCSAP_GLOBAL #define LLCSAP_GLOBAL 0xff #endif #ifndef LLCSAP_8021B_I #define LLCSAP_8021B_I 0x02 #endif #ifndef LLCSAP_8021B_G #define LLCSAP_8021B_G 0x03 #endif #ifndef LLCSAP_SNA #define LLCSAP_SNA 0x04 #endif #ifndef LLCSAP_IP #define LLCSAP_IP 0x06 #endif #ifndef LLCSAP_PROWAYNM #define LLCSAP_PROWAYNM 0x0e #endif #ifndef LLCSAP_8021D #define LLCSAP_8021D 0x42 #endif #ifndef LLCSAP_RS511 #define LLCSAP_RS511 0x4e #endif #ifndef LLCSAP_ISO8208 #define LLCSAP_ISO8208 0x7e #endif #ifndef LLCSAP_PROWAY #define LLCSAP_PROWAY 0x8e #endif #ifndef LLCSAP_SNAP #define LLCSAP_SNAP 0xaa #endif #ifndef LLCSAP_IPX #define LLCSAP_IPX 0xe0 #endif #ifndef LLCSAP_NETBEUI #define LLCSAP_NETBEUI 0xf0 #endif #ifndef LLCSAP_ISONS #define LLCSAP_ISONS 0xfe #endif /* * PIDs for use with OUI_CISCO. */ #define PID_CISCO_CDP 0x2000 /* Cisco Discovery Protocol */ /* * PIDs for use with OUI_RFC2684. */ #define PID_RFC2684_ETH_FCS 0x0001 /* Ethernet, with FCS */ #define PID_RFC2684_ETH_NOFCS 0x0007 /* Ethernet, without FCS */ #define PID_RFC2684_802_4_FCS 0x0002 /* 802.4, with FCS */ #define PID_RFC2684_802_4_NOFCS 0x0008 /* 802.4, without FCS */ #define PID_RFC2684_802_5_FCS 0x0003 /* 802.5, with FCS */ #define PID_RFC2684_802_5_NOFCS 0x0009 /* 802.5, without FCS */ #define PID_RFC2684_FDDI_FCS 0x0004 /* FDDI, with FCS */ #define PID_RFC2684_FDDI_NOFCS 0x000a /* FDDI, without FCS */ #define PID_RFC2684_802_6_FCS 0x0005 /* 802.6, with FCS */ #define PID_RFC2684_802_6_NOFCS 0x000b /* 802.6, without FCS */ #define PID_RFC2684_BPDU 0x000e /* BPDUs */ /* Jeff: endian-fixed llc/snap header + ethernet type */ struct llc_hdr_t { uint8_t dsap; uint8_t ssap; uint8_t control; uint16_t oui; uint16_t type; }; #endif tcpflow-tcpflow-1.6.1/src/wifipcap/os.h000066400000000000000000000005631401360461700200420ustar00rootroot00000000000000#pragma once #ifdef _WIN32 #define _PACKED_ #include #define u_int8_t UCHAR #define u_int16_t USHORT #define u_int32_t ULONG #define u_int64_t ULONGLONG #define int8_t CHAR #define int16_t SHORT #define int32_t LONG #define int64_t LONGLONG #define u_char UCHAR #else #define _PACKED_ __attribute__((__packed__)) #endif tcpflow-tcpflow-1.6.1/src/wifipcap/oui.h000066400000000000000000000064501401360461700202160ustar00rootroot00000000000000/* @(#) $Header: /home/cvs/wifitools/wifipcap/oui.h,v 1.1.1.1 2006/12/14 01:22:11 jpang Exp $ (LBL) */ /* * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that: (1) source code * distributions retain the above copyright notice and this paragraph * in its entirety, and (2) distributions including binary code include * the above copyright notice and this paragraph in its entirety in * the documentation or other materials provided with the distribution. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE. * * Original code by Hannes Gredler (hannes@juniper.net) */ #ifndef UNI_OUT_H #define UNI_OUT_H extern struct tok oui_values[]; extern struct tok smi_values[]; #define OUI_ENCAP_ETHER 0x000000 /* encapsulated Ethernet */ #define OUI_CISCO 0x00000c /* Cisco protocols */ #define OUI_NORTEL 0x000081 /* Nortel SONMP */ #define OUI_CISCO_90 0x0000f8 /* Cisco bridging */ #define OUI_RFC2684 0x0080c2 /* RFC 2427/2684 bridged Ethernet */ #define OUI_ATM_FORUM 0x00A03E /* ATM Forum */ #define OUI_CABLE_BPDU 0x00E02F /* DOCSIS spanning tree BPDU */ #define OUI_APPLETALK 0x080007 /* Appletalk */ #define OUI_JUNIPER 0x009069 /* Juniper */ #define OUI_HP 0x080009 /* Hewlett-Packard */ /* * These are SMI Network Management Private Enterprise Codes for * organizations; see * * http://www.iana.org/assignments/enterprise-numbers * * for a list. * * List taken from Ethereal's epan/sminmpec.h. */ #define SMI_IETF 0 /* reserved - used by the IETF in L2TP? */ #define SMI_ACC 5 #define SMI_CISCO 9 #define SMI_HEWLETT_PACKARD 11 #define SMI_SUN_MICROSYSTEMS 42 #define SMI_MERIT 61 #define SMI_SHIVA 166 #define SMI_ERICSSON 193 #define SMI_CISCO_VPN5000 255 #define SMI_LIVINGSTON 307 #define SMI_MICROSOFT 311 #define SMI_3COM 429 #define SMI_ASCEND 529 #define SMI_BAY 1584 #define SMI_FOUNDRY 1991 #define SMI_VERSANET 2180 #define SMI_REDBACK 2352 #define SMI_JUNIPER 2636 #define SMI_APTIS 2637 #define SMI_CISCO_VPN3000 3076 #define SMI_COSINE 3085 #define SMI_SHASTA 3199 #define SMI_NETSCREEN 3224 #define SMI_NOMADIX 3309 #define SMI_SIEMENS 4329 #define SMI_CABLELABS 4491 #define SMI_UNISPHERE 4874 #define SMI_CISCO_BBSM 5263 #define SMI_THE3GPP2 5535 #define SMI_IP_UNPLUGGED 5925 #define SMI_ISSANNI 5948 #define SMI_QUINTUM 6618 #define SMI_INTERLINK 6728 #define SMI_COLUBRIS 8744 #define SMI_COLUMBIA_UNIVERSITY 11862 #define SMI_THE3GPP 10415 #define SMI_GEMTEK_SYSTEMS 10529 #define SMI_WIFI_ALLIANCE 14122 #endif tcpflow-tcpflow-1.6.1/src/wifipcap/prism.h000066400000000000000000000020111401360461700205410ustar00rootroot00000000000000 #include "os.h" /* // prism header: added (from wlan-ng) #define WLAN_DEVNAMELEN_MAX 16 typedef struct { uint32_t did; uint16_t status; uint16_t len; uint32_t data; } __attribute__((__packed__)) p80211item_uint32_t; typedef struct { uint32_t msgcode; uint32_t msglen; uint8_t devname[WLAN_DEVNAMELEN_MAX]; p80211item_uint32_t hosttime; p80211item_uint32_t mactime; p80211item_uint32_t channel; p80211item_uint32_t rssi; p80211item_uint32_t sq; p80211item_uint32_t signal; p80211item_uint32_t noise; p80211item_uint32_t rate; p80211item_uint32_t istx; p80211item_uint32_t frmlen; } __attribute__((__packed__)) prism2_pkthdr; */ #ifdef _WIN32 #pragma pack(push, 1) #endif struct prism2_pkthdr { u_int32_t host_time; u_int32_t mac_time; u_int32_t channel; u_int32_t rssi; u_int32_t sq; int signal; int noise; u_int32_t rate; u_int32_t istx; u_int32_t frmlen; } _PACKED_; #ifdef _WIN32 #pragma pack(pop) #endif tcpflow-tcpflow-1.6.1/src/wifipcap/radiotap.h000066400000000000000000000020351401360461700212200ustar00rootroot00000000000000 #include "os.h" #ifdef _WIN32 #pragma pack(push, 1) #endif struct radiotap_hdr { bool has_channel; int channel; bool has_fhss; int fhss_fhset; int fhss_fhpat; bool has_rate; int rate; bool has_signal_dbm; int signal_dbm; bool has_noise_dbm; int noise_dbm; bool has_signal_db; int signal_db; bool has_noise_db; int noise_db; bool has_quality; int quality; bool has_txattenuation; int txattenuation; bool has_txattenuation_db; int txattenuation_db; bool has_txpower_dbm; int txpower_dbm; bool has_flags; bool flags_cfp; bool flags_short_preamble; bool flags_wep; bool flags_fragmented; bool flags_badfcs; bool has_antenna; int antenna; bool has_tsft; u_int64_t tsft; bool has_rxflags; int rxflags; bool has_txflags; int txflags; bool has_rts_retries; int rts_retries; bool has_data_retries; int data_retries; } _PACKED_; #ifdef _WIN32 #pragma pack(pop) #endif tcpflow-tcpflow-1.6.1/src/wifipcap/sample.cpp000066400000000000000000000074141401360461700212370ustar00rootroot00000000000000#include #include "wifipcap.h" /* Demonstration of how to process pcap packets with a simple callback class */ class TestCB : public WifipcapCallbacks { public: TestCB(){} virtual ~TestCB(){}; virtual const char *name() {return "TestCB";} // override with your own name! virtual void PacketBegin(const WifiPacket &p, const u_char *pkt, size_t len, int origlen) { TimeVal t(p.header->ts); std::cout << &t << " {"; } virtual void PacketEnd(const WifiPacket &p ) { std::cout << "}" << std::endl; } virtual bool Check80211FCS(const WifiPacket &p ) { return true; } // please calculate FCS virtual void Handle80211DataFromAP(const WifiPacket &p, const mac_hdr_t *hdr, const u_char *rest, u_int len) { std::cout << "802.11 data:\t" << hdr->sa << " -> " << hdr->da << "\t" << len ; } virtual void Handle80211DataToAP(const WifiPacket &p, const mac_hdr_t *hdr, const u_char *rest, u_int len) { std::cout << "802.11 data:\t" << hdr->sa << " -> " << hdr->da << "\t" << len ; } virtual void Handle80211MgmtProbeRequest(const WifiPacket &p, const mgmt_header_t *hdr, const mgmt_body_t *body) { std::cout << "802.11 mgmt:\t" << hdr->sa << "\tprobe\t\"" << body->ssid.ssid << "\"" ; } virtual void Handle80211MgmtBeacon(const WifiPacket &p, const struct mgmt_header_t *hdr, const struct mgmt_body_t *body) { std::cout << "802.11 mgmt:\t" << hdr->sa << "\tbeacon\t\"" << body->ssid.ssid << "\"" ; } virtual void HandleTCP(const WifiPacket &p, const ip4_hdr_t *ip4h, const ip6_hdr_t *ip6h, const tcp_hdr_t *hdr, const u_char *options, int optlen, const u_char *rest, u_int len) { if (ip4h && hdr) std::cout << "tcp/ip: \t" << ip4h->src << ":" << hdr->sport << " -> " << ip4h->dst << ":" << hdr->dport << "\t" << ip4h->len ; else std::cout << "tcp/ip: \t" << "[truncated]" ; } virtual void HandleUDP(const WifiPacket &p, const ip4_hdr_t *ip4h, const ip6_hdr_t *ip6h, const udp_hdr_t *hdr, const u_char *rest, u_int len) { if (ip4h && hdr) std::cout << "udp/ip: \t" << ip4h->src << ":" << hdr->sport << " -> " << ip4h->dst << ":" << hdr->dport << "\t" << ip4h->len ; else std::cout << " " << "udp/ip: \t" << "[truncated]" ; } }; /** * usage: test */ int main(int argc, char **argv) { if (argc == 1) { pcap_if_t *alldevs; pcap_if_t *d; int i=0; char errbuf[PCAP_ERRBUF_SIZE]; /* Retrieve the device list from the local machine */ if (pcap_findalldevs(&alldevs, errbuf) == -1) { fprintf(stderr,"Error in pcap_findalldevs_ex: %s\n", errbuf); exit(1); } /* Print the list */ for(d= alldevs; d != NULL; d= d->next) { printf("%d. %s", ++i, d->name); if (d->description) printf(" (%s)\n", d->description); else printf(" (No description available)\n"); } if (i == 0) { printf("\nNo interfaces found! Make sure WinPcap is installed.\n"); return 1; } /* We don't need any more the device list. Free it */ pcap_freealldevs(alldevs); return 1; } bool live = argc == 3 && atoi(argv[2]) == 1; Wifipcap *wcap = new Wifipcap(argv[1], live); wcap->Run(new TestCB()); return 0; } tcpflow-tcpflow-1.6.1/src/wifipcap/tcp.h000066400000000000000000000115711401360461700202100ustar00rootroot00000000000000/* @(#) $Header: /home/cvs/wifitools/wifipcap/tcp.h,v 1.1.1.1 2006/12/14 01:22:11 jpang Exp $ (LBL) */ /* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)tcp.h 8.1 (Berkeley) 6/10/93 */ #ifndef TCP_H #define TCP_H typedef u_int32_t tcp_seq; /* * TCP header. * Per RFC 793, September, 1981. */ struct tcphdr { u_int16_t th_sport; /* source port */ u_int16_t th_dport; /* destination port */ tcp_seq th_seq; /* sequence number */ tcp_seq th_ack; /* acknowledgement number */ u_int8_t th_offx2; /* data offset, rsvd */ #define TH_OFF(th) (((th)->th_offx2 & 0xf0) >> 4) u_int8_t 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 #define TH_ECNECHO 0x40 /* ECN Echo */ #define TH_CWR 0x80 /* ECN Cwnd Reduced */ u_int16_t th_win; /* window */ u_int16_t th_sum; /* checksum */ u_int16_t th_urp; /* urgent pointer */ }; #define TCPOPT_EOL 0 #define TCPOPT_NOP 1 #define TCPOPT_MAXSEG 2 #define TCPOLEN_MAXSEG 4 #define TCPOPT_WSCALE 3 /* window scale factor (rfc1323) */ #define TCPOPT_SACKOK 4 /* selective ack ok (rfc2018) */ #define TCPOPT_SACK 5 /* selective ack (rfc2018) */ #define TCPOPT_ECHO 6 /* echo (rfc1072) */ #define TCPOPT_ECHOREPLY 7 /* echo (rfc1072) */ #define TCPOPT_TIMESTAMP 8 /* timestamp (rfc1323) */ #define TCPOLEN_TIMESTAMP 10 #define TCPOLEN_TSTAMP_APPA (TCPOLEN_TIMESTAMP+2) /* appendix A */ #define TCPOPT_CC 11 /* T/TCP CC options (rfc1644) */ #define TCPOPT_CCNEW 12 /* T/TCP CC options (rfc1644) */ #define TCPOPT_CCECHO 13 /* T/TCP CC options (rfc1644) */ #define TCPOPT_SIGNATURE 19 /* Keyed MD5 (rfc2385) */ #define TCPOLEN_SIGNATURE 18 #define TCP_SIGLEN 16 /* length of an option 19 digest */ #define TCPOPT_AUTH 20 /* Enhanced AUTH option */ #define TCPOPT_TSTAMP_HDR \ (TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_TIMESTAMP<<8|TCPOLEN_TIMESTAMP) #include #include class tcp_opt_t { tcp_opt_t &operator=(const tcp_opt_t &); // not implemented public: tcp_opt_t(const tcp_opt_t &t):type(t.type),len(t.len),data_raw(t.data_raw),data(t.data),data_sack(t.data_sack){}; tcp_opt_t():type(),len(),data_raw(),data(),data_sack(){}; u_int type; u_int len; const u_char *data_raw; union { u_int16_t mss; u_int8_t wscale; u_int32_t echo; u_int32_t echoreply; u_int32_t cc; u_int32_t ccnew; u_int32_t ccecho; struct { u_int32_t tsval; u_int32_t tsecr; } timestamp; u_int8_t signature[TCP_SIGLEN]; } data; std::list< std::pair > data_sack; }; /* Jeff: endian-fixed, fully decoded tcp header */ struct tcp_hdr_t { u_int16_t sport; /* source port */ u_int16_t dport; /* destination port */ tcp_seq seq; /* sequence number */ tcp_seq ack; /* acknowledgement number */ u_int8_t dataoff; /* data offset */ u_int8_t flags; /* flags (see #defines under tcphdr::th_flags above) */ u_int16_t win; /* window */ u_int16_t cksum; /* checksum */ u_int16_t urgptr; /* urgent pointer */ //std::list opts; }; #endif tcpflow-tcpflow-1.6.1/src/wifipcap/types.h000066400000000000000000000040111401360461700205550ustar00rootroot00000000000000//////////////////////////////////////////////////////////////////////////////// // Mercury and Colyseus Software Distribution // // Copyright (C) 2004-2005 Ashwin Bharambe (ashu@cs.cmu.edu) // 2004-2005 Jeffrey Pang (jeffpang@cs.cmu.edu) // 2004 Mukesh Agrawal (mukesh@cs.cmu.edu) // // 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 //////////////////////////////////////////////////////////////////////////////// #ifndef __TYPES__H #define __TYPES__H // basic types and utility macros typedef unsigned char byte; typedef unsigned char ubyte; typedef unsigned char uint8; typedef unsigned short uint16; typedef unsigned int uint32; typedef unsigned long long uint64; typedef char sbyte; typedef char sint8; typedef short sint16; typedef int sint32; typedef long long sint64; typedef float real; typedef float real32; typedef double real64; //typedef long double real64; typedef unsigned int guint; typedef uint32 guint32; typedef uint16 guint16; typedef uint8 guint8; #ifndef MAX #define MAX(x,y) ((x)>(y)?(x):(y)) #endif #ifndef MIN #define MIN(x,y) ((x)<(y)?(x):(y)) #endif #endif // vim: set sw=4 sts=4 ts=8 noet: // Local Variables: // Mode: c++ // c-basic-offset: 4 // tab-width: 8 // indent-tabs-mode: t // End: tcpflow-tcpflow-1.6.1/src/wifipcap/udp.h000066400000000000000000000074741401360461700202210ustar00rootroot00000000000000/* @(#) $Header: /home/cvs/wifitools/wifipcap/udp.h,v 1.1.1.1 2006/12/14 01:22:11 jpang Exp $ (LBL) */ /* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)udp.h 8.1 (Berkeley) 6/10/93 */ /* * Udp protocol header. * Per RFC 768, September, 1981. */ struct udphdr { u_int16_t uh_sport; /* source port */ u_int16_t uh_dport; /* destination port */ u_int16_t uh_ulen; /* udp length */ u_int16_t uh_sum; /* udp checksum */ }; #define TFTP_PORT 69 /*XXX*/ #define KERBEROS_PORT 88 /*XXX*/ #define SUNRPC_PORT 111 /*XXX*/ #define SNMP_PORT 161 /*XXX*/ #define NTP_PORT 123 /*XXX*/ #define SNMPTRAP_PORT 162 /*XXX*/ #define ISAKMP_PORT 500 /*XXX*/ #define SYSLOG_PORT 514 /* rfc3164 */ #define TIMED_PORT 525 /*XXX*/ #define RIP_PORT 520 /*XXX*/ #define LDP_PORT 646 #define AODV_PORT 654 /*XXX*/ #define KERBEROS_SEC_PORT 750 /*XXX*/ #define L2TP_PORT 1701 /*XXX*/ #define SIP_PORT 5060 #define ISAKMP_PORT_NATT 4500 /* rfc3948 */ #define ISAKMP_PORT_USER1 7500 /*XXX - nonstandard*/ #define ISAKMP_PORT_USER2 8500 /*XXX - nonstandard*/ #define RX_PORT_LOW 7000 /*XXX*/ #define RX_PORT_HIGH 7009 /*XXX*/ #define NETBIOS_NS_PORT 137 #define NETBIOS_DGRAM_PORT 138 #define CISCO_AUTORP_PORT 496 /*XXX*/ #define RADIUS_PORT 1645 #define RADIUS_NEW_PORT 1812 #define RADIUS_ACCOUNTING_PORT 1646 #define RADIUS_NEW_ACCOUNTING_PORT 1813 #define HSRP_PORT 1985 /*XXX*/ #define LMP_PORT 701 /* rfc4204 */ #define LWRES_PORT 921 #define ZEPHYR_SRV_PORT 2103 #define ZEPHYR_CLT_PORT 2104 #define MPLS_LSP_PING_PORT 3503 /* draft-ietf-mpls-lsp-ping-02.txt */ #define BFD_CONTROL_PORT 3784 /* draft-katz-ward-bfd-v4v6-1hop-00.txt */ #define BFD_ECHO_PORT 3785 /* draft-katz-ward-bfd-v4v6-1hop-00.txt */ #ifdef INET6 #define RIPNG_PORT 521 /*XXX*/ #define DHCP6_SERV_PORT 546 /*XXX*/ #define DHCP6_CLI_PORT 547 /*XXX*/ #endif /* Jeff: endian-fixed udp header */ struct udp_hdr_t { u_int16_t sport; /* source port */ u_int16_t dport; /* destination port */ u_int16_t len; /* udp length */ u_int16_t cksum; /* udp checksum */ }; tcpflow-tcpflow-1.6.1/src/wifipcap/util.cpp000066400000000000000000000036671401360461700207410ustar00rootroot00000000000000#include "os.h" #include #include #include #include #ifndef _WIN32 #include #include #include #else #define snprintf sprintf_s #endif #include "util.h" #include "ethertype.h" #include "wifipcap.h" //std::ostream& operator<<(std::ostream& out, const WifipcapCallbacks::MAC& mac) { // const char *fmt = WifipcapCallbacks::MAC::print_fmt == WifipcapCallbacks::MAC::PRINT_FMT_COLON ? // "%02x:%02x:%02x:%02x:%02x:%02x" : // "%02x%02x%02x%02x%02x%02x"; // char buf[24]; // sprintf(buf, fmt, // (int)((mac.val>>40)&0xff), // (int)((mac.val>>32)&0xff), // (int)((mac.val>>24)&0xff), // (int)((mac.val>>16)&0xff), // (int)((mac.val>>8)&0xff), // (int)((mac.val)&0xff) // ); // out << buf; // return out; //} // //std::ostream& operator<<(std::ostream& out, const struct in_addr& ip) { // out << inet_ntoa(ip); // return out; //} #if 0 char *va(const char *format, ...) { va_list argptr; static int index = 0; static char buf[8][512]; char *b = *(buf + index); va_start (argptr, format); vsprintf (b, format,argptr); va_end (argptr); index = (index + 1) % 8; return b; } /* * Convert a token value to a string; use "fmt" if not found. */ const char * tok2strbuf(register const struct tok *lp, register const char *fmt, register int v, char *buf, size_t bufsize) { if (lp != NULL) { while (lp->s != NULL) { if (lp->v == v) return (lp->s); ++lp; } } if (fmt == NULL) fmt = "#%d"; (void)snprintf(buf, bufsize, fmt, v); return (const char *)buf; } /* * Convert a token value to a string; use "fmt" if not found. */ const char * tok2str(register const struct tok *lp, register const char *fmt, register int v) { static char buf[4][128]; static int idx = 0; char *ret; ret = buf[idx]; idx = (idx+1) & 3; return tok2strbuf(lp, fmt, v, ret, sizeof(buf[0])); } #endif tcpflow-tcpflow-1.6.1/src/wifipcap/util.h000066400000000000000000000020231401360461700203670ustar00rootroot00000000000000#ifndef __WIFIPCAP_UTIL_H_ #define __WIFIPCAP_UTIL_H_ #include typedef unsigned char uint8_t; typedef unsigned short uint16_t; #ifdef _WIN32 typedef unsigned long long uint64_t; #endif #if 0 struct MAC { uint64_t val; MAC() {} MAC(const uint8_t *stream); MAC(uint64_t val); MAC(const char *str); MAC(const MAC& o); bool operator==(const MAC& o) const { return val == o.val; } bool operator!=(const MAC& o) const { return val != o.val; } bool operator<(const MAC& o) const { return val < o.val; } enum { PRINT_FMT_COLON, PRINT_FMT_PLAIN }; static MAC broadcast; static MAC null; static int print_fmt; }; std::ostream& operator<<(std::ostream& out, const MAC& mac); std::ostream& operator<<(std::ostream& out, const struct in_addr& ip); #endif char *va(const char *format, ...); struct tok { int v; /* value */ const char *s; /* string */ }; extern const char * tok2str(register const struct tok *lp, register const char *fmt, register int v); #endif tcpflow-tcpflow-1.6.1/src/wifipcap/wifipcap.cpp000066400000000000000000001547371401360461700215730ustar00rootroot00000000000000/********************************************************************** * Log: * 2006-03-12: Parts originally authored by Doug Madory as wifi_parser.c * 2013-03-15: Substantially modified by Simson Garfinkel for inclusion into tcpflow * 2013-11-18: reworked static calls to be entirely calls to a class. Changed TimeVal pointer to an instance variable that includes the full packet header. **********************************************************************/ //*do 11-18 #include "config.h" // pull in HAVE_ defines #define __STDC_FORMAT_MACROS #include #include #include #include #include #include #include #include #ifdef HAVE_NET_ETHERNET_H #ifdef HAVE_SYS_PARAM_H #include #endif #include #endif #ifdef HAVE_ARPA_INET_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #pragma GCC diagnostic ignored "-Wcast-align" #include "wifipcap.h" #include "cpack.h" #include "extract.h" #include "oui.h" #include "ethertype.h" #include "icmp.h" #include "ipproto.h" /* wifipcap uses a MAC class which is somewhat lame, but works */ MAC MAC::broadcast(0xffffffffffffULL); MAC MAC::null((uint64_t)0); int WifiPacket::debug=0; int MAC::print_fmt(MAC::PRINT_FMT_COLON); std::ostream& operator<<(std::ostream& out, const MAC& mac) { const char *fmt = MAC::print_fmt == MAC::PRINT_FMT_COLON ? "%02x:%02x:%02x:%02x:%02x:%02x" : "%02x%02x%02x%02x%02x%02x"; char buf[24]; sprintf(buf, fmt, (int)((mac.val>>40)&0xff), (int)((mac.val>>32)&0xff), (int)((mac.val>>24)&0xff), (int)((mac.val>>16)&0xff), (int)((mac.val>>8)&0xff), (int)((mac.val)&0xff) ); out << buf; return out; } std::ostream& operator<<(std::ostream& out, const struct in_addr& ip) { out << inet_ntoa(ip); return out; } struct tok { int v; /* value */ const char *s; /* string */ }; #if 0 static const struct tok ethertype_values[] = { { ETHERTYPE_IP, "IPv4" }, { ETHERTYPE_MPLS, "MPLS unicast" }, { ETHERTYPE_MPLS_MULTI, "MPLS multicast" }, { ETHERTYPE_IPV6, "IPv6" }, { ETHERTYPE_8021Q, "802.1Q" }, { ETHERTYPE_VMAN, "VMAN" }, { ETHERTYPE_PUP, "PUP" }, { ETHERTYPE_ARP, "ARP"}, { ETHERTYPE_REVARP, "Reverse ARP"}, { ETHERTYPE_NS, "NS" }, { ETHERTYPE_SPRITE, "Sprite" }, { ETHERTYPE_TRAIL, "Trail" }, { ETHERTYPE_MOPDL, "MOP DL" }, { ETHERTYPE_MOPRC, "MOP RC" }, { ETHERTYPE_DN, "DN" }, { ETHERTYPE_LAT, "LAT" }, { ETHERTYPE_SCA, "SCA" }, { ETHERTYPE_LANBRIDGE, "Lanbridge" }, { ETHERTYPE_DECDNS, "DEC DNS" }, { ETHERTYPE_DECDTS, "DEC DTS" }, { ETHERTYPE_VEXP, "VEXP" }, { ETHERTYPE_VPROD, "VPROD" }, { ETHERTYPE_ATALK, "Appletalk" }, { ETHERTYPE_AARP, "Appletalk ARP" }, { ETHERTYPE_IPX, "IPX" }, { ETHERTYPE_PPP, "PPP" }, { ETHERTYPE_SLOW, "Slow Protocols" }, { ETHERTYPE_PPPOED, "PPPoE D" }, { ETHERTYPE_PPPOES, "PPPoE S" }, { ETHERTYPE_EAPOL, "EAPOL" }, { ETHERTYPE_JUMBO, "Jumbo" }, { ETHERTYPE_LOOPBACK, "Loopback" }, { ETHERTYPE_ISO, "OSI" }, { ETHERTYPE_GRE_ISO, "GRE-OSI" }, { 0, NULL} }; #endif /*max length of an IEEE 802.11 packet*/ #ifndef MAX_LEN_80211 #define MAX_LEN_80211 3000 #endif /* from ethereal packet-prism.c */ #define pletohs(p) ((u_int16_t) \ ((u_int16_t)*((const u_int8_t *)(p)+1)<<8| \ (u_int16_t)*((const u_int8_t *)(p)+0)<<0)) #define pntohl(p) ((u_int32_t)*((const u_int8_t *)(p)+0)<<24| \ (u_int32_t)*((const u_int8_t *)(p)+1)<<16| \ (u_int32_t)*((const u_int8_t *)(p)+2)<<8| \ (u_int32_t)*((const u_int8_t *)(p)+3)<<0) #define COOK_FRAGMENT_NUMBER(x) ((x) & 0x000F) #define COOK_SEQUENCE_NUMBER(x) (((x) & 0xFFF0) >> 4) /* end ethereal code */ /* Sequence number gap */ #define SEQ_GAP(current, last)(0xfff & (current - last)) /* In the following three arrays, even though the QoS subtypes are listed, in the rest of the program * the QoS subtypes are treated as "OTHER_TYPES". The file "ieee802_11.h" currently doesn't account for * the existence of QoS subtypes. The QoS subtypes might need to be accomodated there in the future. */ #if 0 static const char * mgmt_subtype_text[] = { "AssocReq", "AssocResp", "ReAssocReq", "ReAssocResp", "ProbeReq", "ProbeResp", "", "", "Beacon", "ATIM", "Disassoc", "Auth", "DeAuth", "Action", /*QoS mgmt_subtype*/ "", "" }; static const char * ctrl_subtype_text[] = { "", "", "", "", "", "", "", "", "BlockAckReq", /*QoS ctrl_subtype*/ "BlockAck", /*QoS ctrl_subtype*/ "PS-Poll", "RTS", "CTS", "ACK", "CF-End", "CF-End+CF-Ack" }; static const char * data_subtype_text[] = { "Data", "Data+CF-Ack", "Data+CF-Poll", "Data+CF-Ack+CF-Poll", "Null(no_data)", "CF-Ack(no_data)", "CF-Poll(no_data)", "CF-Ack+CF-Poll(no_data)", "QoS_Data", /*QoS data_subtypes from here on*/ "QoS_Data+CF-Ack", "QoS_Data+CF-Poll", "QoS_Data+CF-Ack+CF-Poll", "QoS_Null(no_data)", "", "QoS_CF-Poll(no_data)", "QoS_CF-Ack+CF-Poll(no_data)" }; #endif /////////////////////////////////////////////////////////////////////////////// // crc32 implementation needed for wifi checksum /* crc32.c * CRC-32 routine * * $Id: crc32.cpp,v 1.1 2007/02/14 00:05:50 jpang Exp $ * * Ethereal - Network traffic analyzer * By Gerald Combs * Copyright 1998 Gerald Combs * * Copied from README.developer * * 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. * * Credits: * * Table from Solomon Peachy * Routine from Chris Waters */ /* * Table for the AUTODIN/HDLC/802.x CRC. * * Polynomial is * * x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^8 + x^7 + * x^5 + x^4 + x^2 + x + 1 */ static const uint32_t crc32_ccitt_table[256] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d }; #define CRC32_CCITT_SEED 0xFFFFFFFF static uint32_t crc32_ccitt_seed(const uint8_t *buf, size_t len, uint32_t seed); static uint32_t crc32_ccitt(const uint8_t *buf, size_t len) { return ( crc32_ccitt_seed(buf, len, CRC32_CCITT_SEED) ); } static uint32_t crc32_ccitt_seed(const uint8_t *buf, size_t len, uint32_t seed) { uint32_t crc32 = seed; for (unsigned int i = 0; i < len; i++){ crc32 = crc32_ccitt_table[(crc32 ^ buf[i]) & 0xff] ^ (crc32 >> 8); } return ( ~crc32 ); } /* * IEEE 802.x version (Ethernet and 802.11, at least) - byte-swap * the result of "crc32()". * * XXX - does this mean we should fetch the Ethernet and 802.11 * Frame Checksum (FCS) with "tvb_get_letohl()" rather than "tvb_get_ntohl()", * or is fetching it big-endian and byte-swapping the CRC done * to cope with 802.x sending stuff out in reverse bit order? */ static uint32_t crc32_802(const unsigned char *buf, size_t len) { uint32_t c_crc; c_crc = crc32_ccitt(buf, len); /* Byte reverse. */ c_crc = ((unsigned char)(c_crc>>0)<<24) | ((unsigned char)(c_crc>>8)<<16) | ((unsigned char)(c_crc>>16)<<8) | ((unsigned char)(c_crc>>24)<<0); return ( c_crc ); } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// /* Translate Ethernet address, as seen in struct ether_header, to type MAC. */ /* Extract header length. */ static size_t extract_header_length(u_int16_t fc) { switch (FC_TYPE(fc)) { case T_MGMT: return MGMT_HDRLEN; case T_CTRL: switch (FC_SUBTYPE(fc)) { case CTRL_PS_POLL: return CTRL_PS_POLL_HDRLEN; case CTRL_RTS: return CTRL_RTS_HDRLEN; case CTRL_CTS: return CTRL_CTS_HDRLEN; case CTRL_ACK: return CTRL_ACK_HDRLEN; case CTRL_CF_END: return CTRL_END_HDRLEN; case CTRL_END_ACK: return CTRL_END_ACK_HDRLEN; default: return 0; } case T_DATA: return (FC_TO_DS(fc) && FC_FROM_DS(fc)) ? 30 : 24; default: return 0; } } /////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// #pragma GCC diagnostic ignored "-Wcast-align" void WifiPacket::handle_llc(const mac_hdr_t &mac,const u_char *ptr, size_t len,u_int16_t fc) { if (len < 7) { // truncated header! cbs->HandleLLC(*this,NULL, ptr, len); return; } // http://www.wildpackets.com/resources/compendium/wireless_lan/wlan_packets llc_hdr_t hdr; hdr.dsap = EXTRACT_LE_8BITS(ptr); // Destination Service Access point hdr.ssap = EXTRACT_LE_8BITS(ptr + 1); // Source Service Access Point hdr.control= EXTRACT_LE_8BITS(ptr + 2); // ignored by most protocols hdr.oui = EXTRACT_24BITS(ptr + 3); hdr.type = EXTRACT_16BITS(ptr + 6); /* "When both the DSAP and SSAP are set to 0xAA, the type is * interpreted as a protocol not defined by IEEE and the LSAP is * referred to as SubNetwork Access Protocol (SNAP). In SNAP, the * 5 bytes that follow the DSAP, SSAP, and control byte are called * the Protocol Discriminator." */ if(hdr.dsap==0xAA && hdr.ssap==0xAA){ cbs->HandleLLC(*this,&hdr,ptr+8,len-8); return; } if (hdr.oui == OUI_ENCAP_ETHER || hdr.oui == OUI_CISCO_90) { cbs->HandleLLC(*this,&hdr, ptr+8, len-8); return; } cbs->HandleLLCUnknown(*this,ptr, len); } void WifiPacket::handle_wep(const u_char *ptr, size_t len) { // Jeff: XXX handle TKIP/CCMP ? how can we demultiplex different // protection protocols? struct wep_hdr_t hdr; u_int32_t iv; if (len < IEEE802_11_IV_LEN + IEEE802_11_KID_LEN) { // truncated! cbs->HandleWEP(*this,NULL, ptr, len); return; } iv = EXTRACT_LE_32BITS(ptr); hdr.iv = IV_IV(iv); hdr.pad = IV_PAD(iv); hdr.keyid = IV_KEYID(iv); cbs->HandleWEP(*this,&hdr, ptr, len); } /////////////////////////////////////////////////////////////////////////////// static const char *auth_alg_text[]={"Open System","Shared Key","EAP"}; #define NUM_AUTH_ALGS (sizeof auth_alg_text / sizeof auth_alg_text[0]) static const char *status_text[] = { "Succesful", /* 0 */ "Unspecified failure", /* 1 */ "Reserved", /* 2 */ "Reserved", /* 3 */ "Reserved", /* 4 */ "Reserved", /* 5 */ "Reserved", /* 6 */ "Reserved", /* 7 */ "Reserved", /* 8 */ "Reserved", /* 9 */ "Cannot Support all requested capabilities in the Capability Information field", /* 10 */ "Reassociation denied due to inability to confirm that association exists", /* 11 */ "Association denied due to reason outside the scope of the standard", /* 12 */ "Responding station does not support the specified authentication algorithm ", /* 13 */ "Received an Authentication frame with authentication transaction " \ "sequence number out of expected sequence", /* 14 */ "Authentication rejected because of challenge failure", /* 15 */ "Authentication rejected due to timeout waiting for next frame in sequence", /* 16 */ "Association denied because AP is unable to handle additional associated stations", /* 17 */ "Association denied due to requesting station not supporting all of the " \ "data rates in BSSBasicRateSet parameter", /* 18 */ }; #define NUM_STATUSES (sizeof status_text / sizeof status_text[0]) static const char *reason_text[] = { "Reserved", /* 0 */ "Unspecified reason", /* 1 */ "Previous authentication no longer valid", /* 2 */ "Deauthenticated because sending station is leaving (or has left) IBSS or ESS", /* 3 */ "Disassociated due to inactivity", /* 4 */ "Disassociated because AP is unable to handle all currently associated stations", /* 5 */ "Class 2 frame received from nonauthenticated station", /* 6 */ "Class 3 frame received from nonassociated station", /* 7 */ "Disassociated because sending station is leaving (or has left) BSS", /* 8 */ "Station requesting (re)association is not authenticated with responding station", /* 9 */ }; #define NUM_REASONS (sizeof reason_text / sizeof reason_text[0]) const char *Wifipcap::WifiUtil::MgmtAuthAlg2Txt(uint v) { return v < NUM_AUTH_ALGS ? auth_alg_text[v] : "Unknown"; } const char *Wifipcap::WifiUtil::MgmtStatusCode2Txt(uint v) { return v < NUM_STATUSES ? status_text[v] : "Reserved"; } const char *Wifipcap::WifiUtil::MgmtReasonCode2Txt(uint v) { return v < NUM_REASONS ? reason_text[v] : "Reserved"; } /////////////////////////////////////////////////////////////////////////////// // Jeff: HACK -- tcpdump uses a global variable to check truncation #define TTEST2(_p, _l) ((const u_char *)&(_p) - p + (_l) <= (ssize_t)len) void WifiPacket::parse_elements(struct mgmt_body_t *pbody, const u_char *p, int offset, size_t len) { /* * We haven't seen any elements yet. */ pbody->challenge_status = NOT_PRESENT; pbody->ssid_status = NOT_PRESENT; pbody->rates_status = NOT_PRESENT; pbody->ds_status = NOT_PRESENT; pbody->cf_status = NOT_PRESENT; pbody->tim_status = NOT_PRESENT; for (;;) { if (!TTEST2(*(p + offset), 1)) return; switch (*(p + offset)) { case E_SSID: /* Present, possibly truncated */ pbody->ssid_status = TRUNCATED; if (!TTEST2(*(p + offset), 2)) return; memcpy(&pbody->ssid, p + offset, 2); offset += 2; if (pbody->ssid.length != 0) { if (pbody->ssid.length > sizeof(pbody->ssid.ssid) - 1) return; if (!TTEST2(*(p + offset), pbody->ssid.length)) return; memcpy(&pbody->ssid.ssid, p + offset, pbody->ssid.length); offset += pbody->ssid.length; } pbody->ssid.ssid[pbody->ssid.length] = '\0'; /* Present and not truncated */ pbody->ssid_status = PRESENT; break; case E_CHALLENGE: /* Present, possibly truncated */ pbody->challenge_status = TRUNCATED; if (!TTEST2(*(p + offset), 2)) return; memcpy(&pbody->challenge, p + offset, 2); offset += 2; if (pbody->challenge.length != 0) { if (pbody->challenge.length > sizeof(pbody->challenge.text) - 1) return; if (!TTEST2(*(p + offset), pbody->challenge.length)) return; memcpy(&pbody->challenge.text, p + offset, pbody->challenge.length); offset += pbody->challenge.length; } pbody->challenge.text[pbody->challenge.length] = '\0'; /* Present and not truncated */ pbody->challenge_status = PRESENT; break; case E_RATES: /* Present, possibly truncated */ pbody->rates_status = TRUNCATED; if (!TTEST2(*(p + offset), 2)) return; memcpy(&(pbody->rates), p + offset, 2); offset += 2; if (pbody->rates.length != 0) { if (pbody->rates.length > sizeof pbody->rates.rate) return; if (!TTEST2(*(p + offset), pbody->rates.length)) return; memcpy(&pbody->rates.rate, p + offset, pbody->rates.length); offset += pbody->rates.length; } /* Present and not truncated */ pbody->rates_status = PRESENT; break; case E_DS: /* Present, possibly truncated */ pbody->ds_status = TRUNCATED; if (!TTEST2(*(p + offset), 3)) return; memcpy(&pbody->ds, p + offset, 3); offset += 3; /* Present and not truncated */ pbody->ds_status = PRESENT; break; case E_CF: /* Present, possibly truncated */ pbody->cf_status = TRUNCATED; if (!TTEST2(*(p + offset), 8)) return; memcpy(&pbody->cf, p + offset, 8); offset += 8; /* Present and not truncated */ pbody->cf_status = PRESENT; break; case E_TIM: /* Present, possibly truncated */ pbody->tim_status = TRUNCATED; if (!TTEST2(*(p + offset), 2)) return; memcpy(&pbody->tim, p + offset, 2); offset += 2; if (!TTEST2(*(p + offset), 3)) return; memcpy(&pbody->tim.count, p + offset, 3); offset += 3; if (pbody->tim.length <= 3) break; if (pbody->rates.length > sizeof pbody->tim.bitmap) return; if (!TTEST2(*(p + offset), pbody->tim.length - 3)) return; memcpy(pbody->tim.bitmap, p + (pbody->tim.length - 3), (pbody->tim.length - 3)); offset += pbody->tim.length - 3; /* Present and not truncated */ pbody->tim_status = PRESENT; break; default: #ifdef DEBUG_WIFI printf("(1) unhandled element_id (%d) ", *(p + offset) ); #endif if (!TTEST2(*(p + offset), 2)) return; if (!TTEST2(*(p + offset + 2), *(p + offset + 1))) return; offset += *(p + offset + 1) + 2; break; } } } /********************************************************************************* * Print Handle functions for the management frame types *********************************************************************************/ int WifiPacket::handle_beacon( const struct mgmt_header_t *pmh, const u_char *p, size_t len) { struct mgmt_body_t pbody; int offset = 0; memset(&pbody, 0, sizeof(pbody)); if (!TTEST2(*p, IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN + IEEE802_11_CAPINFO_LEN)) return 0; memcpy(&pbody.timestamp, p, IEEE802_11_TSTAMP_LEN); offset += IEEE802_11_TSTAMP_LEN; pbody.beacon_interval = EXTRACT_LE_16BITS(p+offset); offset += IEEE802_11_BCNINT_LEN; pbody.capability_info = EXTRACT_LE_16BITS(p+offset); offset += IEEE802_11_CAPINFO_LEN; parse_elements(&pbody, p, offset, len); /* PRINT_SSID(pbody); PRINT_RATES(pbody); printf(" %s", CAPABILITY_ESS(pbody.capability_info) ? "ESS" : "IBSS"); PRINT_DS_CHANNEL(pbody); */ cbs->Handle80211MgmtBeacon(*this, pmh, &pbody); return 1; } int WifiPacket::handle_assoc_request( const struct mgmt_header_t *pmh, const u_char *p, size_t len) { struct mgmt_body_t pbody; int offset = 0; memset(&pbody, 0, sizeof(pbody)); if (!TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN)) return 0; pbody.capability_info = EXTRACT_LE_16BITS(p); offset += IEEE802_11_CAPINFO_LEN; pbody.listen_interval = EXTRACT_LE_16BITS(p+offset); offset += IEEE802_11_LISTENINT_LEN; parse_elements(&pbody, p, offset, len); /* PRINT_SSID(pbody); PRINT_RATES(pbody); */ cbs->Handle80211MgmtAssocRequest(*this, pmh, &pbody); return 1; } int WifiPacket::handle_assoc_response( const struct mgmt_header_t *pmh, const u_char *p, size_t len, bool reassoc) { struct mgmt_body_t pbody; int offset = 0; memset(&pbody, 0, sizeof(pbody)); if (!TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_STATUS_LEN + IEEE802_11_AID_LEN)) return 0; pbody.capability_info = EXTRACT_LE_16BITS(p); offset += IEEE802_11_CAPINFO_LEN; pbody.status_code = EXTRACT_LE_16BITS(p+offset); offset += IEEE802_11_STATUS_LEN; pbody.aid = EXTRACT_LE_16BITS(p+offset); offset += IEEE802_11_AID_LEN; parse_elements(&pbody, p, offset, len); /* printf(" AID(%x) :%s: %s", ((u_int16_t)(pbody.aid << 2 )) >> 2 , CAPABILITY_PRIVACY(pbody.capability_info) ? " PRIVACY " : "", (pbody.status_code < NUM_STATUSES ? status_text[pbody.status_code] : "n/a")); */ if (!reassoc) cbs->Handle80211MgmtAssocResponse(*this, pmh, &pbody); else cbs->Handle80211MgmtReassocResponse(*this, pmh, &pbody); return 1; } int WifiPacket::handle_reassoc_request( const struct mgmt_header_t *pmh, const u_char *p, size_t len) { struct mgmt_body_t pbody; int offset = 0; memset(&pbody, 0, sizeof(pbody)); if (!TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN + IEEE802_11_AP_LEN)) return 0; pbody.capability_info = EXTRACT_LE_16BITS(p); offset += IEEE802_11_CAPINFO_LEN; pbody.listen_interval = EXTRACT_LE_16BITS(p+offset); offset += IEEE802_11_LISTENINT_LEN; memcpy(&pbody.ap, p+offset, IEEE802_11_AP_LEN); offset += IEEE802_11_AP_LEN; parse_elements(&pbody, p, offset, len); /* PRINT_SSID(pbody); printf(" AP : %s", etheraddr_string( pbody.ap )); */ cbs->Handle80211MgmtReassocRequest(*this, pmh, &pbody); return 1; } int WifiPacket::handle_reassoc_response( const struct mgmt_header_t *pmh, const u_char *p, size_t len) { /* Same as a Association Reponse */ return handle_assoc_response(pmh, p, len, true); } int WifiPacket::handle_probe_request( const struct mgmt_header_t *pmh, const u_char *p, size_t len) { struct mgmt_body_t pbody; int offset = 0; memset(&pbody, 0, sizeof(pbody)); parse_elements(&pbody, p, offset, len); /* PRINT_SSID(pbody); PRINT_RATES(pbody); */ cbs->Handle80211MgmtProbeRequest(*this, pmh, &pbody); return 1; } int WifiPacket::handle_probe_response( const struct mgmt_header_t *pmh, const u_char *p, size_t len) { struct mgmt_body_t pbody; int offset = 0; memset(&pbody, 0, sizeof(pbody)); if (!TTEST2(*p, IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN + IEEE802_11_CAPINFO_LEN)) return 0; memcpy(&pbody.timestamp, p, IEEE802_11_TSTAMP_LEN); offset += IEEE802_11_TSTAMP_LEN; pbody.beacon_interval = EXTRACT_LE_16BITS(p+offset); offset += IEEE802_11_BCNINT_LEN; pbody.capability_info = EXTRACT_LE_16BITS(p+offset); offset += IEEE802_11_CAPINFO_LEN; parse_elements(&pbody, p, offset, len); /* PRINT_SSID(pbody); PRINT_RATES(pbody); PRINT_DS_CHANNEL(pbody); */ cbs->Handle80211MgmtProbeResponse(*this, pmh, &pbody); return 1; } int WifiPacket::handle_atim( const struct mgmt_header_t *pmh, const u_char *p, size_t len) { /* the frame body for ATIM is null. */ cbs->Handle80211MgmtATIM(*this, pmh); return 1; } int WifiPacket::handle_disassoc( const struct mgmt_header_t *pmh, const u_char *p, size_t len) { struct mgmt_body_t pbody; memset(&pbody, 0, sizeof(pbody)); if (!TTEST2(*p, IEEE802_11_REASON_LEN)) return 0; pbody.reason_code = EXTRACT_LE_16BITS(p); /* printf(": %s", (pbody.reason_code < NUM_REASONS) ? reason_text[pbody.reason_code] : "Reserved" ); */ cbs->Handle80211MgmtDisassoc(*this, pmh, &pbody); return 1; } int WifiPacket::handle_auth( const struct mgmt_header_t *pmh, const u_char *p, size_t len) { struct mgmt_body_t pbody; int offset = 0; memset(&pbody, 0, sizeof(pbody)); if (!TTEST2(*p, 6)) return 0; pbody.auth_alg = EXTRACT_LE_16BITS(p); offset += 2; pbody.auth_trans_seq_num = EXTRACT_LE_16BITS(p + offset); offset += 2; pbody.status_code = EXTRACT_LE_16BITS(p + offset); offset += 2; parse_elements(&pbody, p, offset, len); /* if ((pbody.auth_alg == 1) && ((pbody.auth_trans_seq_num == 2) || (pbody.auth_trans_seq_num == 3))) { printf(" (%s)-%x [Challenge Text] %s", (pbody.auth_alg < NUM_AUTH_ALGS) ? auth_alg_text[pbody.auth_alg] : "Reserved", pbody.auth_trans_seq_num, ((pbody.auth_trans_seq_num % 2) ? ((pbody.status_code < NUM_STATUSES) ? status_text[pbody.status_code] : "n/a") : "")); return 1; } printf(" (%s)-%x: %s", (pbody.auth_alg < NUM_AUTH_ALGS) ? auth_alg_text[pbody.auth_alg] : "Reserved", pbody.auth_trans_seq_num, (pbody.auth_trans_seq_num % 2) ? ((pbody.status_code < NUM_STATUSES) ? status_text[pbody.status_code] : "n/a") : ""); */ cbs->Handle80211MgmtAuth(*this, pmh, &pbody); return 1; } int WifiPacket::handle_deauth( const struct mgmt_header_t *pmh, const u_char *p, size_t len) { struct mgmt_body_t pbody; int offset = 0; //const char *reason = NULL; memset(&pbody, 0, sizeof(pbody)); if (!TTEST2(*p, IEEE802_11_REASON_LEN)) return 0; pbody.reason_code = EXTRACT_LE_16BITS(p); offset += IEEE802_11_REASON_LEN; /* reason = (pbody.reason_code < NUM_REASONS) ? reason_text[pbody.reason_code] : "Reserved"; if (eflag) { printf(": %s", reason); } else { printf(" (%s): %s", etheraddr_string(pmh->sa), reason); } */ cbs->Handle80211MgmtDeauth(*this, pmh, &pbody); return 1; } /********************************************************************************* * Print Body funcs *********************************************************************************/ /** Decode a management request. * @return 0 - failure, non-zero success * * NOTE — this function and all that it calls should be handled as methods in WifipcapCallbacks */ int WifiPacket::decode_mgmt_body(u_int16_t fc, struct mgmt_header_t *pmh, const u_char *p, size_t len) { if(debug) std::cerr << "decode_mgmt_body FC_SUBTYPE(fc)="<<(int)FC_SUBTYPE(fc)<<" "; switch (FC_SUBTYPE(fc)) { case ST_ASSOC_REQUEST: return handle_assoc_request(pmh, p, len); case ST_ASSOC_RESPONSE: return handle_assoc_response(pmh, p, len); case ST_REASSOC_REQUEST: return handle_reassoc_request(pmh, p, len); case ST_REASSOC_RESPONSE: return handle_reassoc_response(pmh, p, len); case ST_PROBE_REQUEST: return handle_probe_request(pmh, p, len); case ST_PROBE_RESPONSE: return handle_probe_response(pmh, p, len); case ST_BEACON: return handle_beacon(pmh, p, len); case ST_ATIM: return handle_atim(pmh, p, len); case ST_DISASSOC: return handle_disassoc(pmh, p, len); case ST_AUTH: if (len < 3) { return 0; } if ((p[0] == 0 ) && (p[1] == 0) && (p[2] == 0)) { //printf("Authentication (Shared-Key)-3 "); cbs->Handle80211MgmtAuthSharedKey(*this, pmh, p, len); return 0; } return handle_auth(pmh, p, len); case ST_DEAUTH: return handle_deauth(pmh, p, len); break; default: return 0; } } int WifiPacket::decode_mgmt_frame(const u_char * ptr, size_t len, u_int16_t fc, u_int8_t hdrlen) { mgmt_header_t hdr; u_int16_t seq_ctl; hdr.da = MAC::ether2MAC(ptr + 4); hdr.sa = MAC::ether2MAC(ptr + 10); hdr.bssid = MAC::ether2MAC(ptr + 16); hdr.duration = EXTRACT_LE_16BITS(ptr+2); seq_ctl = pletohs(ptr + 22); hdr.seq = COOK_SEQUENCE_NUMBER(seq_ctl); hdr.frag = COOK_FRAGMENT_NUMBER(seq_ctl); cbs->Handle80211(*this, fc, hdr.sa, hdr.da, MAC::null, MAC::null, ptr, len); int ret = decode_mgmt_body(fc, &hdr, ptr+MGMT_HDRLEN, len-MGMT_HDRLEN); if (ret==0) { cbs->Handle80211Unknown(*this, fc, ptr, len); return 0; } return 0; } int WifiPacket::decode_data_frame(const u_char * ptr, size_t len, u_int16_t fc) { mac_hdr_t hdr; hdr.fc = fc; hdr.duration = EXTRACT_LE_16BITS(ptr+2); hdr.seq_ctl = pletohs(ptr + 22); hdr.seq = COOK_SEQUENCE_NUMBER(hdr.seq_ctl); hdr.frag = COOK_FRAGMENT_NUMBER(hdr.seq_ctl); if(FC_TYPE(fc)==2 && FC_SUBTYPE(fc)==8){ // quality of service? hdr.qos = 1; } size_t hdrlen=0; const MAC address1 = MAC::ether2MAC(ptr+4); const MAC address2 = MAC::ether2MAC(ptr+10); const MAC address3 = MAC::ether2MAC(ptr+16); /* call the 80211 callback data callback */ if (FC_TO_DS(fc)==0 && FC_FROM_DS(fc)==0) { /* ad hoc IBSS */ hdr.da = address1; hdr.sa = address2; hdr.bssid = address3; hdrlen = DATA_HDRLEN; if(hdr.qos) hdrlen+=2; cbs->Handle80211( *this, fc, hdr.sa, hdr.da, hdr.ra, hdr.ta, ptr, len); cbs->Handle80211DataIBSS( *this, hdr, ptr+hdrlen, len-hdrlen); } else if (FC_TO_DS(fc)==0 && FC_FROM_DS(fc)) { /* from AP to STA */ hdr.da = address1; hdr.bssid = address2; hdr.sa = address3; hdrlen = DATA_HDRLEN; if(hdr.qos) hdrlen+=2; cbs->Handle80211( *this, fc, hdr.sa, hdr.da, hdr.ra, hdr.ta, ptr, len); cbs->Handle80211DataFromAP( *this, hdr, ptr+hdrlen, len-hdrlen); } else if (FC_TO_DS(fc) && FC_FROM_DS(fc)==0) { /* frame from STA to AP */ hdr.bssid = address1; hdr.sa = address2; hdr.da = address3; hdrlen = DATA_HDRLEN; if(hdr.qos) hdrlen+=2; cbs->Handle80211( *this, fc, hdr.sa, hdr.da, hdr.ra, hdr.ta, ptr, len); cbs->Handle80211DataToAP( *this, hdr, ptr+hdrlen, len-hdrlen); } else if (FC_TO_DS(fc) && FC_FROM_DS(fc)) { /* WDS */ const MAC address4 = MAC::ether2MAC(ptr+18); hdr.ra = address1; hdr.ta = address2; hdr.da = address3; hdr.sa = address4; hdrlen = DATA_WDS_HDRLEN; if(hdr.qos) hdrlen+=2; cbs->Handle80211( *this, fc, hdr.sa, hdr.da, hdr.ra, hdr.ta, ptr, len); cbs->Handle80211DataWDS( *this, hdr, ptr+hdrlen, len-hdrlen); } /* Handle either the WEP or the link layer. This handles the data itself */ if (FC_WEP(fc)) { handle_wep(ptr+hdrlen, len-hdrlen-4 ); } else { handle_llc(hdr, ptr+hdrlen, len-hdrlen-4, fc); } return 0; } int WifiPacket::decode_ctrl_frame(const u_char * ptr, size_t len, u_int16_t fc) { u_int16_t du = EXTRACT_LE_16BITS(ptr+2); //duration switch (FC_SUBTYPE(fc)) { case CTRL_PS_POLL: { ctrl_ps_poll_t hdr; hdr.fc = fc; hdr.aid = du; hdr.bssid = MAC::ether2MAC(ptr+4); hdr.ta = MAC::ether2MAC(ptr+10); cbs->Handle80211( *this, fc, MAC::null, MAC::null, MAC::null, hdr.ta, ptr, len); cbs->Handle80211CtrlPSPoll( *this, &hdr); break; } case CTRL_RTS: { ctrl_rts_t hdr; hdr.fc = fc; hdr.duration = du; hdr.ra = MAC::ether2MAC(ptr+4); hdr.ta = MAC::ether2MAC(ptr+10); cbs->Handle80211( *this, fc, MAC::null, MAC::null, hdr.ra, hdr.ta, ptr, len); cbs->Handle80211CtrlRTS( *this, &hdr); break; } case CTRL_CTS: { ctrl_cts_t hdr; hdr.fc = fc; hdr.duration = du; hdr.ra = MAC::ether2MAC(ptr+4); cbs->Handle80211( *this, fc, MAC::null, MAC::null, hdr.ra, MAC::null, ptr, len); cbs->Handle80211CtrlCTS( *this, &hdr); break; } case CTRL_ACK: { ctrl_ack_t hdr; hdr.fc = fc; hdr.duration = du; hdr.ra = MAC::ether2MAC(ptr+4); cbs->Handle80211( *this, fc, MAC::null, MAC::null, hdr.ra, MAC::null, ptr, len); cbs->Handle80211CtrlAck( *this, &hdr); break; } case CTRL_CF_END: { ctrl_end_t hdr; hdr.fc = fc; hdr.duration = du; hdr.ra = MAC::ether2MAC(ptr+4); hdr.bssid = MAC::ether2MAC(ptr+10); cbs->Handle80211( *this, fc, MAC::null, MAC::null, hdr.ra, MAC::null, ptr, len); cbs->Handle80211CtrlCFEnd( *this, &hdr); break; } case CTRL_END_ACK: { ctrl_end_ack_t hdr; hdr.fc = fc; hdr.duration = du; hdr.ra = MAC::ether2MAC(ptr+4); hdr.bssid = MAC::ether2MAC(ptr+10); cbs->Handle80211( *this, fc, MAC::null, MAC::null, hdr.ra, MAC::null, ptr, len); cbs->Handle80211CtrlEndAck( *this, &hdr); break; } default: { cbs->Handle80211( *this, fc, MAC::null, MAC::null, MAC::null, MAC::null, ptr, len); cbs->Handle80211Unknown( *this, fc, ptr, len); return -1; //add the case statements for QoS control frames once ieee802_11.h is updated } } return 0; } #ifndef roundup2 #define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */ #endif void WifiPacket::handle_80211(const u_char * pkt, size_t len /* , int pad */) { if (debug) std::cerr << "handle_80211(len= " << len << " "; if (len < 2) { cbs->Handle80211( *this, 0, MAC::null, MAC::null, MAC::null, MAC::null, pkt, len); cbs->Handle80211Unknown( *this, -1, pkt, len); return; } u_int16_t fc = EXTRACT_LE_16BITS(pkt); //frame control size_t hdrlen = extract_header_length(fc); /* if (pad) { hdrlen = roundup2(hdrlen, 4); } */ if (debug) std::cerr << "FC_TYPE(fc)= " << FC_TYPE(fc) << " "; if (len < IEEE802_11_FC_LEN || len < hdrlen) { cbs->Handle80211Unknown( *this, fc, pkt, len); return; } /* Always calculate the frame checksum, but only process the packets if the FCS or if we are ignoring it */ if (len >= hdrlen + 4) { // assume fcs is last 4 bytes (?) u_int32_t fcs_sent = EXTRACT_32BITS(pkt+len-4); u_int32_t fcs = crc32_802(pkt, len-4); /* if (fcs != fcs_sent) { cerr << "bad fcs: "; fprintf (stderr, "%08x != %08x\n", fcs_sent, fcs); } */ fcs_ok = (fcs == fcs_sent); } if (cbs->Check80211FCS(*this) && fcs_ok==false){ cbs->Handle80211Unknown(*this,fc,pkt,len); return; } // fill in current_frame: type, sn switch (FC_TYPE(fc)) { case T_MGMT: if(decode_mgmt_frame(pkt, len, fc, hdrlen)<0) return; break; case T_DATA: if(decode_data_frame(pkt, len, fc)<0) return; break; case T_CTRL: if(decode_ctrl_frame(pkt, len, fc)<0) return; break; default: cbs->Handle80211( *this, fc, MAC::null, MAC::null, MAC::null, MAC::null, pkt, len); cbs->Handle80211Unknown( *this, fc, pkt, len); return; } } int WifiPacket::print_radiotap_field(struct cpack_state *s, u_int32_t bit, int *pad, radiotap_hdr *hdr) { union { int8_t i8; u_int8_t u8; int16_t i16; u_int16_t u16; u_int32_t u32; u_int64_t u64; } u, u2, u3; int rc; switch (bit) { case IEEE80211_RADIOTAP_FLAGS: rc = cpack_uint8(s, &u.u8); if (u.u8 & IEEE80211_RADIOTAP_F_DATAPAD) *pad = 1; break; case IEEE80211_RADIOTAP_RATE: case IEEE80211_RADIOTAP_DB_ANTSIGNAL: case IEEE80211_RADIOTAP_DB_ANTNOISE: case IEEE80211_RADIOTAP_ANTENNA: rc = cpack_uint8(s, &u.u8); break; case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: case IEEE80211_RADIOTAP_DBM_ANTNOISE: rc = cpack_int8(s, &u.i8); break; case IEEE80211_RADIOTAP_CHANNEL: rc = cpack_uint16(s, &u.u16); if (rc != 0) break; rc = cpack_uint16(s, &u2.u16); break; case IEEE80211_RADIOTAP_FHSS: case IEEE80211_RADIOTAP_LOCK_QUALITY: case IEEE80211_RADIOTAP_TX_ATTENUATION: rc = cpack_uint16(s, &u.u16); break; case IEEE80211_RADIOTAP_DB_TX_ATTENUATION: rc = cpack_uint8(s, &u.u8); break; case IEEE80211_RADIOTAP_DBM_TX_POWER: rc = cpack_int8(s, &u.i8); break; case IEEE80211_RADIOTAP_TSFT: rc = cpack_uint64(s, &u.u64); break; case IEEE80211_RADIOTAP_RX_FLAGS: rc = cpack_uint16(s, &u.u16); break; case IEEE80211_RADIOTAP_TX_FLAGS: rc = cpack_uint16(s, &u.u16); break; case IEEE80211_RADIOTAP_RTS_RETRIES: rc = cpack_uint8(s, &u.u8); break; case IEEE80211_RADIOTAP_DATA_RETRIES: rc = cpack_uint8(s, &u.u8); break; // simson add follows: case IEEE80211_RADIOTAP_XCHANNEL: rc = cpack_uint8(s, &u.u8); // simson guess break; case IEEE80211_RADIOTAP_MCS: rc = cpack_uint8(s, &u.u8) || cpack_uint8(s, &u2.u8) || cpack_uint8(s, &u3.u8); // simson guess break; // simson end default: /* this bit indicates a field whose * size we do not know, so we cannot * proceed. */ //printf("[0x%08x] ", bit); fprintf(stderr, "wifipcap: unknown radiotap bit: %d (%d)\n", bit,IEEE80211_RADIOTAP_XCHANNEL); return -1 ; } if (rc != 0) { //printf("[|802.11]"); fprintf(stderr, "wifipcap: truncated radiotap header for bit: %d\n", bit); return rc ; } switch (bit) { case IEEE80211_RADIOTAP_CHANNEL: //printf("%u MHz ", u.u16); if (u2.u16 != 0) //printf("(0x%04x) ", u2.u16); hdr->has_channel = true; hdr->channel = u2.u16; break; case IEEE80211_RADIOTAP_FHSS: //printf("fhset %d fhpat %d ", u.u16 & 0xff, (u.u16 >> 8) & 0xff); hdr->has_fhss = true; hdr->fhss_fhset = u.u16 & 0xff; hdr->fhss_fhpat = (u.u16 >> 8) & 0xff; break; case IEEE80211_RADIOTAP_RATE: //PRINT_RATE("", u.u8, " Mb/s "); hdr->has_rate = true; hdr->rate = u.u8; break; case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: //printf("%ddB signal ", u.i8); hdr->has_signal_dbm = true; hdr->signal_dbm = u.i8; break; case IEEE80211_RADIOTAP_DBM_ANTNOISE: //printf("%ddB noise ", u.i8); hdr->has_noise_dbm = true; hdr->noise_dbm = u.i8; break; case IEEE80211_RADIOTAP_DB_ANTSIGNAL: //printf("%ddB signal ", u.u8); hdr->has_signal_db = true; hdr->signal_db = u.u8; break; case IEEE80211_RADIOTAP_DB_ANTNOISE: //printf("%ddB noise ", u.u8); hdr->has_noise_db = true; hdr->noise_db = u.u8; break; case IEEE80211_RADIOTAP_LOCK_QUALITY: //printf("%u sq ", u.u16); hdr->has_quality = true; hdr->quality = u.u16; break; case IEEE80211_RADIOTAP_TX_ATTENUATION: //printf("%d tx power ", -(int)u.u16); hdr->has_txattenuation = true; hdr->txattenuation = -(int)u.u16; break; case IEEE80211_RADIOTAP_DB_TX_ATTENUATION: //printf("%ddB tx power ", -(int)u.u8); hdr->has_txattenuation_db = true; hdr->txattenuation_db = -(int)u.u8; break; case IEEE80211_RADIOTAP_DBM_TX_POWER: //printf("%ddBm tx power ", u.i8); hdr->has_txpower_dbm = true; hdr->txpower_dbm = u.i8; break; case IEEE80211_RADIOTAP_FLAGS: hdr->has_flags = true; if (u.u8 & IEEE80211_RADIOTAP_F_CFP) //printf("cfp "); hdr->flags_cfp = true; if (u.u8 & IEEE80211_RADIOTAP_F_SHORTPRE) //printf("short preamble "); hdr->flags_short_preamble = true; if (u.u8 & IEEE80211_RADIOTAP_F_WEP) //printf("wep "); hdr->flags_wep = true; if (u.u8 & IEEE80211_RADIOTAP_F_FRAG) //printf("fragmented "); hdr->flags_fragmented = true; if (u.u8 & IEEE80211_RADIOTAP_F_BADFCS) //printf("bad-fcs "); hdr->flags_badfcs = true; break; case IEEE80211_RADIOTAP_ANTENNA: //printf("antenna %d ", u.u8); hdr->has_antenna = true; hdr->antenna = u.u8; break; case IEEE80211_RADIOTAP_TSFT: //printf("%" PRIu64 "us tsft ", u.u64); hdr->has_tsft = true; hdr->tsft = u.u64; break; case IEEE80211_RADIOTAP_RX_FLAGS: hdr->has_rxflags = true; hdr->rxflags = u.u16; break; case IEEE80211_RADIOTAP_TX_FLAGS: hdr->has_txflags = true; hdr->txflags = u.u16; break; case IEEE80211_RADIOTAP_RTS_RETRIES: hdr->has_rts_retries = true; hdr->rts_retries = u.u8; break; case IEEE80211_RADIOTAP_DATA_RETRIES: hdr->has_data_retries = true; hdr->data_retries = u.u8; break; } return 0 ; } void WifiPacket::handle_radiotap(const u_char *p,size_t caplen) { #define BITNO_32(x) (((x) >> 16) ? 16 + BITNO_16((x) >> 16) : BITNO_16((x))) #define BITNO_16(x) (((x) >> 8) ? 8 + BITNO_8((x) >> 8) : BITNO_8((x))) #define BITNO_8(x) (((x) >> 4) ? 4 + BITNO_4((x) >> 4) : BITNO_4((x))) #define BITNO_4(x) (((x) >> 2) ? 2 + BITNO_2((x) >> 2) : BITNO_2((x))) #define BITNO_2(x) (((x) & 2) ? 1 : 0) #define BIT(n) (1 << n) #define IS_EXTENDED(__p) (EXTRACT_LE_32BITS(__p) & BIT(IEEE80211_RADIOTAP_EXT)) != 0 // If caplen is too small, just give it a try and carry on. if (caplen < sizeof(struct ieee80211_radiotap_header)) { cbs->HandleRadiotap( *this, NULL, p, caplen); return; } struct ieee80211_radiotap_header *hdr = (struct ieee80211_radiotap_header *)p; size_t len = EXTRACT_LE_16BITS(&hdr->it_len); // length of radiotap header if (caplen < len) { //printf("[|802.11]"); cbs->HandleRadiotap( *this, NULL, p, caplen); return;// caplen; } uint32_t *last_presentp=0; for (last_presentp = &hdr->it_present; IS_EXTENDED(last_presentp) && (u_char*)(last_presentp + 1) <= p + len; last_presentp++){ } /* are there more bitmap extensions than bytes in header? */ if (IS_EXTENDED(last_presentp)) { //printf("[|802.11]"); cbs->HandleRadiotap( *this, NULL, p, caplen); return;// caplen; } const u_char *iter = (u_char*)(last_presentp + 1); struct cpack_state cpacker; /* Handle malformed data */ if ((ssize_t)(len - (iter - p)) <= 0) { cbs->HandleRadiotap( *this, NULL, p, caplen); return;// caplen; } if (cpack_init(&cpacker, (u_int8_t*)iter, len - (iter - p)) != 0) { /* XXX */ //printf("[|802.11]"); cbs->HandleRadiotap( *this, NULL, p, caplen); return;// caplen; } radiotap_hdr ohdr; memset(&ohdr, 0, sizeof(ohdr)); /* Assume no Atheros padding between 802.11 header and body */ int pad = 0; uint32_t *presentp; int bit0=0; for (bit0 = 0, presentp = &hdr->it_present; presentp <= last_presentp; presentp++, bit0 += 32) { u_int32_t present, next_present; for (present = EXTRACT_LE_32BITS(presentp); present; present = next_present) { /* clear the least significant bit that is set */ next_present = present & (present - 1); /* extract the least significant bit that is set */ enum ieee80211_radiotap_type bit = (enum ieee80211_radiotap_type) (bit0 + BITNO_32(present ^ next_present)); /* print the next radiotap field */ int r = print_radiotap_field(&cpacker, bit, &pad, &ohdr); /* If we got an error, break both loops */ if(r!=0) goto done; } } done:; cbs->HandleRadiotap( *this, &ohdr, p, caplen); //return len + ieee802_11_print(p + len, length - len, caplen - len, pad); #undef BITNO_32 #undef BITNO_16 #undef BITNO_8 #undef BITNO_4 #undef BITNO_2 #undef BIT handle_80211(p+len, caplen-len); } void WifiPacket::handle_prism(const u_char *pc, size_t len) { prism2_pkthdr hdr; /* get the fields */ if (len>=144){ hdr.host_time = EXTRACT_LE_32BITS(pc+32); hdr.mac_time = EXTRACT_LE_32BITS(pc+44); hdr.channel = EXTRACT_LE_32BITS(pc+56); hdr.rssi = EXTRACT_LE_32BITS(pc+68); hdr.sq = EXTRACT_LE_32BITS(pc+80); hdr.signal = EXTRACT_LE_32BITS(pc+92); hdr.noise = EXTRACT_LE_32BITS(pc+104); hdr.rate = EXTRACT_LE_32BITS(pc+116)/2; hdr.istx = EXTRACT_LE_32BITS(pc+128); cbs->HandlePrism( *this, &hdr, pc + 144, len - 144); handle_80211(pc+144,len-144); } } /////////////////////////////////////////////////////////////////////////////// /// /// handle_*: /// handle each of the packet types /// /// 2018-08-02: slg - I'm not sure why this is commented out. void WifiPacket::handle_ether(const u_char *ptr, size_t len) { #if 0 ether_hdr_t hdr; hdr.da = MAC::ether2MAC(ptr); hdr.sa = MAC::ether2MAC(ptr+6); hdr.type = EXTRACT_16BITS(ptr + 12); ptr += 14; len -= 14; cbs->HandleEthernet(*this, &hdr, ptr, len); switch (hdr.type) { case ETHERTYPE_IP: handle_ip(ptr, len); return; case ETHERTYPE_IPV6: handle_ip6(ptr, len); return; case ETHERTYPE_ARP: handle_arp( ptr, len); return; default: cbs->HandleL2Unknown(*this, hdr.type, ptr, len); return; } #endif } /////////////////////////////////////////////////////////////////////////////// /* These are all static functions */ #if 0 void Wifipcap::dl_prism(const PcapUserData &data, const struct pcap_pkthdr *header, const u_char * packet) { WifipcapCallbacks *cbs = data.cbs; if(header->caplen < 144) return; // prism header cbs->PacketBegin( packet, header->caplen, header->len); handle_prism(cbs,packet+144,header->caplen-144); cbs->PacketEnd(); } void Wifipcap::dl_prism(u_char *user, const struct pcap_pkthdr *header, const u_char * packet) { PcapUserData *data = reinterpret_cast(user); Wifipcap::dl_prism(*data,header,packet); } #endif #if 0 void Wifipcap::dl_ieee802_11_radio(const PcapUserData &data, const struct pcap_pkthdr *header, const u_char * packet) { data.cbs->PacketBegin( packet, header->caplen, header->len); handle_radiotap(packet, header->caplen); data.cbs->PacketEnd(); } #endif void Wifipcap::dl_ieee802_11_radio(const u_char *user, const struct pcap_pkthdr *header, const u_char * packet) { const PcapUserData *data = reinterpret_cast(user); WifiPacket pkt(data->cbs,data->header_type,header,packet); data->cbs->PacketBegin(pkt,packet,header->caplen,header->len); pkt.handle_radiotap(packet,header->caplen); data->cbs->PacketEnd(pkt); //Wifipcap::dl_ieee802_11_radio(*data,header,packet); } /////////////////////////////////////////////////////////////////////////////// /* None of these are used in tcpflow */ bool Wifipcap::InitNext() { if (morefiles.size() < 1){ return false; } if (descr) { pcap_close(descr); } Init(morefiles.front(), false); morefiles.pop_front(); return true; } void Wifipcap::Init(const char *name, bool live) { if (verbose){ std::cerr << "wifipcap: initializing '" << name << "'" << std::endl; } if (!live) { #ifdef _WIN32 std::cerr << "Trace replay is unsupported in windows." << std::endl; exit(1); #else // mini hack: handle gziped files since all our traces are in // this format int slen = strlen(name); bool gzip = !strcmp(name+slen-3, ".gz"); bool bzip = !strcmp(name+slen-4, ".bz2"); char cmd[256]; char errbuf[256]; if (gzip) sprintf(cmd, "zcat %s", name); else if (bzip) sprintf(cmd, "bzcat %s", name); else // using cat here instead of pcap_open or fopen is intentional // neither of these may be able to handle large files (>2GB files) // but cat uses the linux routines to allow it to sprintf(cmd, "cat %s", name); FILE *pipe = popen(cmd, "r"); if (pipe == NULL) { printf("popen(): %s\n", strerror(errno)); exit(1); } descr = pcap_fopen_offline(pipe, errbuf); if(descr == NULL) { printf("pcap_open_offline(): %s\n", errbuf); exit(1); } #endif } else { char errbuf[256]; descr = pcap_open_live(name,BUFSIZ,1,-1,errbuf); if(descr == NULL) { printf("pcap_open_live(): %s\n", errbuf); exit(1); } } datalink = pcap_datalink(descr); if (datalink != DLT_PRISM_HEADER && datalink != DLT_IEEE802_11_RADIO && datalink != DLT_IEEE802_11) { if (datalink == DLT_EN10MB) { printf("warning: ethernet datalink type: %s\n", pcap_datalink_val_to_name(datalink)); } else { printf("warning: unrecognized datalink type: %s\n", pcap_datalink_val_to_name(datalink)); } } } /* object-oriented version of pcap callback. Called with the callbacks object, * the DLT type, the header and the packet. * This is the main packet processor. * It records some stats and then dispatches to the appropriate callback. */ void Wifipcap::handle_packet(WifipcapCallbacks *cbs,int header_type, const struct pcap_pkthdr *header, const u_char * packet) { /* Record start time if we don't have it */ if (startTime == TIME_NONE) { startTime = header->ts; lastPrintTime = header->ts; } /* Print stats if necessary */ if (header->ts.tv_sec > lastPrintTime.tv_sec + Wifipcap::PRINT_TIME_INTERVAL) { if (verbose) { int hours = (header->ts.tv_sec - startTime.tv_sec)/3600; int days = hours/24; int left = hours%24; fprintf(stderr, "wifipcap: %2d days %2d hours, %10" PRId64 " pkts\n", days, left, packetsProcessed); } lastPrintTime = header->ts; } packetsProcessed++; /* Create the packet object and call the appropriate callbacks */ WifiPacket pkt(cbs,header_type,header,packet); /* Notify callback */ cbs->PacketBegin(pkt, packet, header->caplen, header->len); //int frameLen = header->caplen; switch(header_type) { case DLT_PRISM_HEADER: pkt.handle_prism(packet,header->caplen); break; case DLT_IEEE802_11_RADIO: pkt.handle_radiotap(packet,header->caplen); break; case DLT_IEEE802_11: pkt.handle_80211(packet,header->caplen); break; case DLT_EN10MB: pkt.handle_ether(packet,header->caplen); break; default: #if 0 /// 2018-08-02: slg - I'm also not sure why this is commented out. // try handling it as default IP assuming framing is ethernet // (this is for testing) pkt.handle_ip(packet,header->caplen); #endif break; } cbs->PacketEnd(pkt); } /* The raw callback from pcap; jump back into the object-oriented domain */ /* note: u_char *user may not be const according to spec */ void Wifipcap::handle_packet_callback(u_char *user, const struct pcap_pkthdr *header, const u_char * packet) { Wifipcap::PcapUserData *data = reinterpret_cast(user); data->wcap->handle_packet(data->cbs,data->header_type,header,packet); } const char *Wifipcap::SetFilter(const char *filter) { struct bpf_program fp; #ifdef PCAP_NETMASK_UNKNOWN bpf_u_int32 netp=PCAP_NETMASK_UNKNOWN; #else bpf_u_int32 netp=0; #endif if(pcap_compile(descr,&fp,(char *)filter,0,netp) == -1) { return "Error calling pcap_compile"; } if(pcap_setfilter(descr,&fp) == -1) { return "Error setting filter"; } return NULL; } void Wifipcap::Run(WifipcapCallbacks *cbs, int maxpkts) { /* NOTE: This needs to be fixed so that the correct handle_packet is called */ packetsProcessed = 0; do { PcapUserData data(this,cbs,DLT_IEEE802_11_RADIO); pcap_loop(descr, maxpkts > 0 ? maxpkts - packetsProcessed : 0, Wifipcap::handle_packet_callback, reinterpret_cast(&data)); } while ( InitNext() ); } /////////////////////////////////////////////////////////////////////////////// tcpflow-tcpflow-1.6.1/src/wifipcap/wifipcap.h000066400000000000000000000715621401360461700212320ustar00rootroot00000000000000/** * Include this header in applications using wifipcap. * Released under GPLv3. * Some code (c) Jeffrey Pang , 2003 * (C) Simson Garfinkel 2012- */ #ifndef _WIFIPCAP_H_ #define _WIFIPCAP_H_ #include #include #include #include #include #include "arp.h" #include "ip.h" #include "ip6.h" #include "tcp.h" #include "udp.h" #include "TimeVal.h" /* Lengths of 802.11 header components. */ #define IEEE802_11_FC_LEN 2 #define IEEE802_11_DUR_LEN 2 #define IEEE802_11_DA_LEN 6 #define IEEE802_11_SA_LEN 6 #define IEEE802_11_BSSID_LEN 6 #define IEEE802_11_RA_LEN 6 #define IEEE802_11_TA_LEN 6 #define IEEE802_11_SEQ_LEN 2 #define IEEE802_11_IV_LEN 3 #define IEEE802_11_KID_LEN 1 /* Frame check sequence length. */ #define IEEE802_11_FCS_LEN 4 /* Lengths of beacon components. */ #define IEEE802_11_TSTAMP_LEN 8 #define IEEE802_11_BCNINT_LEN 2 #define IEEE802_11_CAPINFO_LEN 2 #define IEEE802_11_LISTENINT_LEN 2 #define IEEE802_11_AID_LEN 2 #define IEEE802_11_STATUS_LEN 2 #define IEEE802_11_REASON_LEN 2 /* Length of previous AP in reassocation frame */ #define IEEE802_11_AP_LEN 6 #define T_MGMT 0x0 /* management */ #define T_CTRL 0x1 /* control */ #define T_DATA 0x2 /* data */ #define T_RESV 0x3 /* reserved */ #define ST_ASSOC_REQUEST 0x0 #define ST_ASSOC_RESPONSE 0x1 #define ST_REASSOC_REQUEST 0x2 #define ST_REASSOC_RESPONSE 0x3 #define ST_PROBE_REQUEST 0x4 #define ST_PROBE_RESPONSE 0x5 /* RESERVED 0x6 */ /* RESERVED 0x7 */ #define ST_BEACON 0x8 #define ST_ATIM 0x9 #define ST_DISASSOC 0xA #define ST_AUTH 0xB #define ST_DEAUTH 0xC /* RESERVED 0xD */ /* RESERVED 0xE */ /* RESERVED 0xF */ #define CTRL_PS_POLL 0xA #define CTRL_RTS 0xB #define CTRL_CTS 0xC #define CTRL_ACK 0xD #define CTRL_CF_END 0xE #define CTRL_END_ACK 0xF #define DATA_DATA 0x0 #define DATA_DATA_CF_ACK 0x1 #define DATA_DATA_CF_POLL 0x2 #define DATA_DATA_CF_ACK_POLL 0x3 #define DATA_NODATA 0x4 #define DATA_NODATA_CF_ACK 0x5 #define DATA_NODATA_CF_POLL 0x6 #define DATA_NODATA_CF_ACK_POLL 0x7 /* * Bits in the frame control field. */ #define FC_VERSION(fc) ((fc) & 0x3) #define FC_TYPE(fc) (((fc) >> 2) & 0x3) #define FC_SUBTYPE(fc) (((fc) >> 4) & 0xF) #define FC_TO_DS(fc) ((fc) & 0x0100) #define FC_FROM_DS(fc) ((fc) & 0x0200) #define FC_MORE_FLAG(fc) ((fc) & 0x0400) #define FC_RETRY(fc) ((fc) & 0x0800) #define FC_POWER_MGMT(fc) ((fc) & 0x1000) #define FC_MORE_DATA(fc) ((fc) & 0x2000) #define FC_WEP(fc) ((fc) & 0x4000) #define FC_ORDER(fc) ((fc) & 0x8000) #define MGMT_HDRLEN (IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+ \ IEEE802_11_DA_LEN+IEEE802_11_SA_LEN+ \ IEEE802_11_BSSID_LEN+IEEE802_11_SEQ_LEN) #define CAPABILITY_ESS(cap) ((cap) & 0x0001) #define CAPABILITY_IBSS(cap) ((cap) & 0x0002) #define CAPABILITY_CFP(cap) ((cap) & 0x0004) #define CAPABILITY_CFP_REQ(cap) ((cap) & 0x0008) #define CAPABILITY_PRIVACY(cap) ((cap) & 0x0010) struct MAC { enum { PRINT_FMT_COLON, PRINT_FMT_PLAIN }; uint64_t val; MAC():val() {} MAC(uint64_t val_):val(val_){} MAC(const MAC& o):val(o.val){} MAC(const uint8_t *ether):val( ((uint64_t)(ether[0]) << 40) | ((uint64_t)(ether[1]) << 32) | ((uint64_t)(ether[2]) << 24) | ((uint64_t)(ether[3]) << 16) | ((uint64_t)(ether[4]) << 8) | ((uint64_t)(ether[5]) << 0)){} MAC(const char *str):val(){ int ether[6]; int ret = sscanf(str, "%02x:%02x:%02x:%02x:%02x:%02x", ðer[0], ðer[1], ðer[2], ðer[3], ðer[4], ðer[5]); if (ret != 6) { ret = sscanf(str, "%02X:%02X:%02X:%02X:%02X:%02X", ðer[0], ðer[1], ðer[2], ðer[3], ðer[4], ðer[5]); } if (ret != 6) { std::cerr << "bad mac address: " << str << std::endl; val = 0; return; } val = ((uint64_t)(ether[0]) << 40) | ((uint64_t)(ether[1]) << 32) | ((uint64_t)(ether[2]) << 24) | ((uint64_t)(ether[3]) << 16) | ((uint64_t)(ether[4]) << 8) | ((uint64_t)(ether[5]) << 0); } bool operator==(const MAC& o) const { return val == o.val; } bool operator!=(const MAC& o) const { return val != o.val; } bool operator<(const MAC& o) const { return val < o.val; } static MAC ether2MAC(const uint8_t * ether) { return MAC(ether); } static MAC broadcast; static MAC null; static int print_fmt; }; typedef enum { NOT_PRESENT, PRESENT, TRUNCATED } elem_status_t; struct ssid_t { ssid_t():element_id(),length(),ssid(){}; u_int8_t element_id; u_int8_t length; char ssid[33]; /* 32 + 1 for null */ }; struct rates_t { rates_t():element_id(),length(),rate(){}; u_int8_t element_id; u_int8_t length; u_int8_t rate[16]; }; struct challenge_t { challenge_t():element_id(),length(),text(){}; u_int8_t element_id; u_int8_t length; u_int8_t text[254]; /* 1-253 + 1 for null */ }; struct fh_t { fh_t():element_id(),length(),dwell_time(),hop_set(),hop_pattern(),hop_index(){}; u_int8_t element_id; u_int8_t length; u_int16_t dwell_time; u_int8_t hop_set; u_int8_t hop_pattern; u_int8_t hop_index; }; struct ds_t { u_int8_t element_id; u_int8_t length; u_int8_t channel; }; struct cf_t { u_int8_t element_id; u_int8_t length; u_int8_t count; u_int8_t period; u_int16_t max_duration; u_int16_t dur_remaing; }; struct tim_t { u_int8_t element_id; u_int8_t length; u_int8_t count; u_int8_t period; u_int8_t bitmap_control; u_int8_t bitmap[251]; }; #define E_SSID 0 #define E_RATES 1 #define E_FH 2 #define E_DS 3 #define E_CF 4 #define E_TIM 5 #define E_IBSS 6 /* reserved 7 */ /* reserved 8 */ /* reserved 9 */ /* reserved 10 */ /* reserved 11 */ /* reserved 12 */ /* reserved 13 */ /* reserved 14 */ /* reserved 15 */ /* reserved 16 */ #define E_CHALLENGE 16 /* reserved 17 */ /* reserved 18 */ /* reserved 19 */ /* reserved 16 */ /* reserved 16 */ // XXX Jeff: no FCS fields are filled in right now #define CTRL_RTS_HDRLEN (IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+ \ IEEE802_11_RA_LEN+IEEE802_11_TA_LEN) struct ctrl_cts_t { ctrl_cts_t():fc(),duration(),ra(),fcs(){}; u_int16_t fc; u_int16_t duration; MAC ra; u_int8_t fcs[4]; }; #define CTRL_CTS_HDRLEN (IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+IEEE802_11_RA_LEN) struct ctrl_ack_t { ctrl_ack_t():fc(),duration(),ra(),fcs(){}; u_int16_t fc; u_int16_t duration; MAC ra; u_int8_t fcs[4]; }; #define CTRL_ACK_HDRLEN (IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+IEEE802_11_RA_LEN) struct ctrl_ps_poll_t { ctrl_ps_poll_t():fc(),aid(),bssid(),ta(),fcs(){}; u_int16_t fc; u_int16_t aid; MAC bssid; MAC ta; u_int8_t fcs[4]; }; #define CTRL_PS_POLL_HDRLEN (IEEE802_11_FC_LEN+IEEE802_11_AID_LEN+ \ IEEE802_11_BSSID_LEN+IEEE802_11_TA_LEN) struct ctrl_end_t { ctrl_end_t():fc(),duration(),ra(),bssid(),fcs(){} u_int16_t fc; u_int16_t duration; MAC ra; MAC bssid; u_int8_t fcs[4]; }; #define CTRL_END_HDRLEN (IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+ \ IEEE802_11_RA_LEN+IEEE802_11_BSSID_LEN) struct ctrl_end_ack_t { ctrl_end_ack_t():fc(),duration(),ra(),bssid(),fcs(){}; u_int16_t fc; u_int16_t duration; MAC ra; MAC bssid; u_int8_t fcs[4]; }; #define CTRL_END_ACK_HDRLEN (IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+ \ IEEE802_11_RA_LEN+IEEE802_11_BSSID_LEN) #define IV_IV(iv) ((iv) & 0xFFFFFF) #define IV_PAD(iv) (((iv) >> 24) & 0x3F) #define IV_KEYID(iv) (((iv) >> 30) & 0x03) struct mac_hdr_t { // unified 80211 header mac_hdr_t():fc(),duration(),seq_ctl(),seq(),frag(),da(),sa(),ta(),ra(),bssid(),qos(){} uint16_t fc; // frame control uint16_t duration; uint16_t seq_ctl; uint16_t seq; // sequence number uint8_t frag; // fragment number? MAC da; // destination address // address1 MAC sa; // source address // address2 MAC ta; // transmitter // address3 MAC ra; // receiver // address4 MAC bssid; // BSSID bool qos; // has quality of service }; #if 0 struct data_hdr_ibss_t { // 80211 Independent Basic Service Set - e.g. ad hoc mode data_hdr_ibss_t():fc(),duration(),seq(),frag(),fcs(){}; u_int16_t fc; u_int16_t duration; u_int16_t seq; u_int8_t frag; u_int8_t fcs[4]; }; struct data_hdr_t { data_hdr_t():fc(),duration(),seq(),frag(),sa(),da(),bssid(),fcs(){} u_int16_t fc; // u_int16_t duration; // ? u_int16_t seq; // sequence #? u_int8_t frag; // fragment #? MAC sa; // sender address MAC da; // destination address MAC bssid; // base station ID u_int8_t fcs[4]; // frame check sequence }; struct data_hdr_wds_t { // 80211 Wireless Distribution System data_hdr_wds_t():fc(),duration(),seq(),frag(),ra(),ta(),sa(),da(),fcs(){} u_int16_t fc; u_int16_t duration; u_int16_t seq; u_int8_t frag; MAC ra; MAC ta; MAC sa; MAC da; u_int8_t fcs[4]; }; #endif #define DATA_HDRLEN (IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+ \ IEEE802_11_SA_LEN+IEEE802_11_DA_LEN+ \ IEEE802_11_BSSID_LEN+IEEE802_11_SEQ_LEN) #define DATA_WDS_HDRLEN (IEEE802_11_FC_LEN+IEEE802_11_DUR_LEN+ \ IEEE802_11_RA_LEN+IEEE802_11_TA_LEN+ \ IEEE802_11_SA_LEN+IEEE802_11_DA_LEN+IEEE802_11_SEQ_LEN) /* Jeff: added for fully-decoded wep info */ struct wep_hdr_t { wep_hdr_t():iv(),pad(),keyid(){}; u_int32_t iv; u_int32_t pad; u_int32_t keyid; }; /* prism header */ #ifdef _WIN32 #pragma pack(push, 1) #endif struct prism2_pkthdr { uint32_t host_time; uint32_t mac_time; uint32_t channel; uint32_t rssi; uint32_t sq; int32_t signal; int32_t noise; uint32_t rate; uint32_t istx; uint32_t frmlen; } __attribute__((__packed__)); struct radiotap_hdr { bool has_channel; int channel; bool has_fhss; int fhss_fhset; int fhss_fhpat; bool has_rate; int rate; bool has_signal_dbm; int signal_dbm; bool has_noise_dbm; int noise_dbm; bool has_signal_db; int signal_db; bool has_noise_db; int noise_db; bool has_quality; int quality; bool has_txattenuation; int txattenuation; bool has_txattenuation_db; int txattenuation_db; bool has_txpower_dbm; int txpower_dbm; bool has_flags; bool flags_cfp; bool flags_short_preamble; bool flags_wep; bool flags_fragmented; bool flags_badfcs; bool has_antenna; int antenna; bool has_tsft; u_int64_t tsft; bool has_rxflags; int rxflags; bool has_txflags; int txflags; bool has_rts_retries; int rts_retries; bool has_data_retries; int data_retries; } __attribute__((__packed__)); struct ether_hdr_t { ether_hdr_t():sa(),da(),type(){}; MAC sa, da; uint16_t type; }; struct mgmt_header_t { mgmt_header_t():fc(),duration(),da(),sa(),bssid(),seq(),frag(){}; u_int16_t fc; u_int16_t duration; MAC da; MAC sa; MAC bssid; u_int16_t seq; u_int8_t frag; }; struct mgmt_body_t { mgmt_body_t():timestamp(),beacon_interval(),listen_interval(),status_code(),aid(),ap(),reason_code(), auth_alg(),auth_trans_seq_num(),challenge_status(),challenge(),capability_info(), ssid_status(),ssid(),rates_status(),rates(),ds_status(),ds(),cf_status(),cf(), fh_status(),fh(),tim_status(),tim(){}; u_int8_t timestamp[IEEE802_11_TSTAMP_LEN]; u_int16_t beacon_interval; u_int16_t listen_interval; u_int16_t status_code; u_int16_t aid; u_char ap[IEEE802_11_AP_LEN]; u_int16_t reason_code; u_int16_t auth_alg; u_int16_t auth_trans_seq_num; elem_status_t challenge_status; struct challenge_t challenge; u_int16_t capability_info; elem_status_t ssid_status; struct ssid_t ssid; elem_status_t rates_status; struct rates_t rates; elem_status_t ds_status; struct ds_t ds; elem_status_t cf_status; struct cf_t cf; elem_status_t fh_status; struct fh_t fh; elem_status_t tim_status; struct tim_t tim; }; struct ctrl_rts_t { ctrl_rts_t():fc(),duration(),ra(),ta(),fcs(){} u_int16_t fc; u_int16_t duration; MAC ra; MAC ta; u_int8_t fcs[4]; }; #ifdef _WIN32 #pragma pack(pop) #endif /** * Applications should implement a subclass of this interface and pass * it to Wifipcap::Run(). Each time pcap reads a packet, Wifipcap will * call: * * (1) PacketBegin() * * (2) Each Handle*() callback in order from layer 1 to layer 3 (or as * far as it is able to demultiplex the packet). The time values * are the same in all these calls. The 'len' argument passed to * functions refers to the amount of captured data available * (e.g., in the 'rest' variable), not necessarily the original * length of the packet (to get that, look inside appropriate * packet headers, or during PacketBegin()). * * (3) PacketEnd() * * If the header for a layer was truncated, the appropriate function * will be called with the header == NULL and the rest == the start of * the packet. For truncated 802.11 headers, 80211Unknown will be * called with fc == -1; for truncated ICMP headers, type == code == * -1. * * All structures passed to the application will have fields in host * byte-order. For details about each header structure, see the * obvious header (e.g., ieee802_11.h for 802.11 stuff, ip.h for IPv4, * tcp.h for TCP, etc.). Note that there may be structures with * similar names that are only used internally; don't confuse them. * * For help parsing other protocols, the tcpdump source code will be * helpful. See the print-X.c file for help parsing protocol X. * The entry function is usually called X_print(...). */ struct WifiPacket; struct WifipcapCallbacks; class Wifipcap; extern std::ostream& operator<<(std::ostream& out, const MAC& mac); extern std::ostream& operator<<(std::ostream& out, const struct in_addr& ip); /////////////////////////////////////////////////////////////////////////////// /* * This class decodes a specific packet */ struct WifiPacket { /* Some instance variables */ /** 48-bit MACs in 64-bit ints */ static int debug; // prints callback before they are called WifiPacket(WifipcapCallbacks *cbs_,const int header_type_,const struct pcap_pkthdr *header_,const u_char *packet_): cbs(cbs_),header_type(header_type_),header(header_),packet(packet_),fcs_ok(false){} void parse_elements(struct mgmt_body_t *pbody, const u_char *p, int offset, size_t len); int handle_beacon(const struct mgmt_header_t *pmh, const u_char *p, size_t len); int handle_assoc_request(const struct mgmt_header_t *pmh, const u_char *p, size_t len); int handle_assoc_response(const struct mgmt_header_t *pmh, const u_char *p, size_t len, bool reassoc = false); int handle_reassoc_request(const struct mgmt_header_t *pmh, const u_char *p, size_t len); int handle_reassoc_response(const struct mgmt_header_t *pmh, const u_char *p, size_t len); int handle_probe_request(const struct mgmt_header_t *pmh, const u_char *p, size_t len); int handle_probe_response(const struct mgmt_header_t *pmh, const u_char *p, size_t len); int handle_atim(const struct mgmt_header_t *pmh, const u_char *p, size_t len); int handle_disassoc(const struct mgmt_header_t *pmh, const u_char *p, size_t len); int handle_auth(const struct mgmt_header_t *pmh, const u_char *p, size_t len); int handle_deauth(const struct mgmt_header_t *pmh, const u_char *p, size_t len); int decode_mgmt_body(u_int16_t fc, struct mgmt_header_t *pmh, const u_char *p, size_t len); int decode_mgmt_frame(const u_char * ptr, size_t len, u_int16_t fc, u_int8_t hdrlen); int decode_data_frame(const u_char * ptr, size_t len, u_int16_t fc); int decode_ctrl_frame(const u_char * ptr, size_t len, u_int16_t fc); /* Handle the individual packet types based on DTL callback switch */ void handle_llc(const mac_hdr_t &hdr,const u_char *ptr, size_t len,u_int16_t fc); void handle_wep(const u_char *ptr, size_t len); void handle_prism(const u_char *ptr, size_t len); void handle_ether(const u_char *ptr, size_t len); void handle_ip(const u_char *ptr, size_t len); void handle_80211(const u_char *ptr, size_t len); int print_radiotap_field(struct cpack_state *s, u_int32_t bit, int *pad, radiotap_hdr *hdr); void handle_radiotap(const u_char *ptr, size_t caplen); /* And finally the data for each packet */ WifipcapCallbacks *cbs; // the callbacks to use with this packet const int header_type; // DLT const struct pcap_pkthdr *header; // the actual pcap headers const u_char *packet; // the actual packet data bool fcs_ok; // was it okay? }; struct WifipcapCallbacks { /**************************************************************** *** Data Structures for each Packet Follow ****************************************************************/ WifipcapCallbacks(){}; virtual ~WifipcapCallbacks(){}; virtual const char *name() const {return "WifipcapCallbacks";} // override with your own name! /* Instance variables --- for a specific packet. * (Previously all of the functions had these parameters as the arguments, which made no sense) */ /** * @param t the time the packet was captured * @param pkt the entire packet captured * @param len the length of the data captured * @param origlen the original length of the data (before truncated by pcap) */ virtual void PacketBegin(const WifiPacket &p, const u_char *pkt, size_t len, int origlen){} virtual void PacketEnd(const WifiPacket &p ){} // If a Prism or RadioTap packet is found, call these, and then call Handle80211() virtual void HandlePrism(const WifiPacket &p, struct prism2_pkthdr *hdr, const u_char *rest, size_t len){} virtual void HandleRadiotap(const WifiPacket &p, struct radiotap_hdr *hdr, const u_char *rest, size_t len){} // 802.11 MAC (see ieee802_11.h) // // This method is called for every 802.11 frame just before the // specific functions below are called. This allows you to have // one entry point to easily do something with all 802.11 packets. // // The MAC addresses will be MAC::null unless applicable to the // particular type of packet. For unknown 802.11 packets, all // MAC addresses will be MAC::null and if the packet is truncated, // so that fc was not decoded, it will be 0. // // fcs_ok will be true if the frame had a valid fcs (frame // checksum) trailer and Check80211FCS() returns true. virtual void Handle80211(const WifiPacket &p, u_int16_t fc, const MAC& sa, const MAC& da, const MAC& ra, const MAC& ta, const u_char *ptr, size_t len){} // if this returns true, we'll check the fcs on every frame. // Note: if frames are truncated, the fcs check will fail, so you need // a complete packet capture for this to be meaningful virtual bool Check80211FCS(const WifiPacket &p ) { return false; } // Management virtual void Handle80211MgmtBeacon(const WifiPacket &p, const struct mgmt_header_t *hdr, const struct mgmt_body_t *body) {puts("Handle80211MgmtBeacon");} virtual void Handle80211MgmtAssocRequest(const WifiPacket &p, const struct mgmt_header_t *hdr, const struct mgmt_body_t *body){} virtual void Handle80211MgmtAssocResponse(const WifiPacket &p, const struct mgmt_header_t *hdr, const struct mgmt_body_t *body){} virtual void Handle80211MgmtReassocRequest(const WifiPacket &p, const struct mgmt_header_t *hdr, const struct mgmt_body_t *body){} virtual void Handle80211MgmtReassocResponse(const WifiPacket &p, const struct mgmt_header_t *hdr, const struct mgmt_body_t *body){} virtual void Handle80211MgmtProbeRequest(const WifiPacket &p, const struct mgmt_header_t *hdr, const struct mgmt_body_t *body){} virtual void Handle80211MgmtProbeResponse(const WifiPacket &p, const struct mgmt_header_t *hdr, const struct mgmt_body_t *body){} virtual void Handle80211MgmtATIM(const WifiPacket &p, const struct mgmt_header_t *hdr){} virtual void Handle80211MgmtDisassoc(const WifiPacket &p, const struct mgmt_header_t *hdr, const struct mgmt_body_t *body){} virtual void Handle80211MgmtAuth(const WifiPacket &p, const struct mgmt_header_t *hdr, const struct mgmt_body_t *body){} virtual void Handle80211MgmtAuthSharedKey(const WifiPacket &p, const struct mgmt_header_t *hdr, const u_char *rest, size_t len){} virtual void Handle80211MgmtDeauth(const WifiPacket &p, const struct mgmt_header_t *hdr, const struct mgmt_body_t *body){} // Control virtual void Handle80211CtrlPSPoll(const WifiPacket &p, const struct ctrl_ps_poll_t *hdr){} virtual void Handle80211CtrlRTS(const WifiPacket &p, const struct ctrl_rts_t *hdr){} virtual void Handle80211CtrlCTS(const WifiPacket &p, const struct ctrl_cts_t *hdr){} virtual void Handle80211CtrlAck(const WifiPacket &p, const struct ctrl_ack_t *hdr){} virtual void Handle80211CtrlCFEnd(const WifiPacket &p, const struct ctrl_end_t *hdr){} virtual void Handle80211CtrlEndAck(const WifiPacket &p, const struct ctrl_end_ack_t *hdr){} // Data - Each data packet results in a call to Handle80211Data and one of the others virtual void Handle80211Data(const WifiPacket &p, u_int16_t fc, const struct mac_hdr_t &hdr, const u_char *rest, size_t len){} virtual void Handle80211DataIBSS(const WifiPacket &p, const struct mac_hdr_t &hdr, const u_char *rest, size_t len){} virtual void Handle80211DataFromAP(const WifiPacket &p, const struct mac_hdr_t &hdr, const u_char *rest, size_t len){} virtual void Handle80211DataToAP(const WifiPacket &p, const struct mac_hdr_t &hdr, const u_char *rest, size_t len){} virtual void Handle80211DataWDS(const WifiPacket &p, const struct mac_hdr_t &hdr, const u_char *rest, size_t len){} // Erroneous Frames/Truncated Frames // Also called if Check80211FCS() returns true and the checksum is bad virtual void Handle80211Unknown(const WifiPacket &p, int fc, const u_char *rest, size_t len){} // LLC/SNAP (const WifiPacket &p, see llc.h) virtual void HandleLLC(const WifiPacket &p, const struct llc_hdr_t *hdr, const u_char *rest, size_t len){} virtual void HandleLLCUnknown(const WifiPacket &p, const u_char *rest, size_t len){} virtual void HandleWEP(const WifiPacket &p, const struct wep_hdr_t *hdr, const u_char *rest, size_t len){} // for non-802.11 ethernet traces virtual void HandleEthernet(const WifiPacket &p, const struct ether_hdr_t *hdr, const u_char *rest, size_t len){} ///// Layer 2 (see arp.h, ip.h, ip6.h) virtual void HandleARP(const WifiPacket &p, const arp_pkthdr *hdr, const u_char *rest, size_t len){} virtual void HandleIP(const WifiPacket &p, const ip4_hdr_t *hdr, const u_char *options, int optlen, const u_char *rest, size_t len){} virtual void HandleIP6(const WifiPacket &p, const ip6_hdr_t *hdr, const u_char *rest, size_t len){} virtual void HandleL2Unknown(const WifiPacket &p, uint16_t ether_type, const u_char *rest, size_t len){} ///// Layer 3 (see icmp.h, tcp.h, udp.h) // IP headers are included for convenience. one of ip4h, ip6h will // be non-NULL. Only the first fragment in a fragmented packet // will be decoded. The other fragments will not be passed to any // of these functions. // Jeff: XXX icmp callback will probably eventually change to // parse the entire icmp packet virtual void HandleICMP(const WifiPacket &p, const ip4_hdr_t *ip4h, const ip6_hdr_t *ip6h, int type, int code, const u_char *rest, size_t len){} virtual void HandleTCP(const WifiPacket &p, const ip4_hdr_t *ip4h, const ip6_hdr_t *ip6h, const tcp_hdr_t *hdr, const u_char *options, int optlen, const u_char *rest, size_t len){} virtual void HandleUDP(const WifiPacket &p, const ip4_hdr_t *ip4h, const ip6_hdr_t *ip6h, const udp_hdr_t *hdr, const u_char *rest, size_t len){} virtual void HandleL3Unknown(const WifiPacket &p, const ip4_hdr_t *ip4h, const ip6_hdr_t *ip6h, const u_char *rest, size_t len){} }; /** * Applications create an instance of this to start processing a pcap * trace. Example: * * Wifipcap *wp = new Wifipcap("/path/to/mytrace.cap"); * wp->Run(new MyCallbacks()); */ class Wifipcap { // these are not implemented Wifipcap(const Wifipcap &t); Wifipcap &operator=(const Wifipcap &that); public: /** * Utility functions for 802.11 fields. */ class WifiUtil { public: // some functions to convert codes to ascii names static const char *MgmtAuthAlg2Txt(uint v); static const char *MgmtStatusCode2Txt(uint v); static const char *MgmtReasonCode2Txt(uint v); static const char *EtherType2Txt(uint t); }; /** * Initialize the lib. Exits with error message upon failure. * * @param name the device if live = true, else the file name of * the trace. If the file name ends in '.gz', we assume its a * gzipped trace and will pipe it through zcat before parsing it. * @param live true if reading from a device, otherwise a trace */ Wifipcap():descr(),datalink(),morefiles(),verbose(),startTime(),lastPrintTime(),packetsProcessed(){ }; Wifipcap(const char *name, bool live_ = false, bool verbose_ = false): descr(NULL), datalink(),morefiles(),verbose(verbose_), startTime(TIME_NONE), lastPrintTime(TIME_NONE), packetsProcessed(0) { Init(name, live_); } /** * Initialize with nfiles. Will run on all of them in order. */ Wifipcap(const char* const *names, int nfiles_, bool verbose_ = false): descr(NULL), datalink(),morefiles(),verbose(verbose_), startTime(TIME_NONE), lastPrintTime(TIME_NONE), packetsProcessed(0) { for (int i=0; i morefiles; public: bool verbose; struct timeval startTime; struct timeval lastPrintTime; uint64_t packetsProcessed; static const int PRINT_TIME_INTERVAL = 6*60*60; // sec }; /////////////////////////////////////////////////////////////////////////////// #include "ieee802_11_radio.h" #include "llc.h" #endif tcpflow-tcpflow-1.6.1/src/wifipcap/wifipcap_tcpdemux.cpp000066400000000000000000000352141401360461700234700ustar00rootroot00000000000000/////////////////////////////////////////////////////////////////////////////// /* These tcp optinos do not have the size octet */ #define ZEROLENOPT(o) ((o) == TCPOPT_EOL || (o) == TCPOPT_NOP) #if USING_PARSE_TCP_OPTS static void parse_tcp_opts(std::list& opts, const u_char *cp, u_int hlen) { if (hlen == 0) return; register u_int i, opt, datalen; register u_int len; //putchar(' '); //ch = '<'; while (hlen > 0) { tcp_opt_t tcpopt; //putchar(ch); //TCHECK(*cp); opt = *cp++; if (ZEROLENOPT(opt)) len = 1; else { //TCHECK(*cp); len = *cp++; /* total including type, len */ if (len < 2 || len > hlen) // stop processing on bad opt break; --hlen; /* account for length byte */ } --hlen; /* account for type byte */ datalen = 0; /* Bail if "l" bytes of data are not left or were not captured */ #define LENCHECK(l) { if ((l) > hlen) break; } tcpopt.type = opt; tcpopt.data_raw = cp; switch (opt) { case TCPOPT_MAXSEG: //(void)printf("mss"); datalen = 2; LENCHECK(datalen); //(void)printf(" %u", EXTRACT_16BITS(cp)); tcpopt.data.mss = EXTRACT_16BITS(cp); break; case TCPOPT_EOL: //(void)printf("eol"); break; case TCPOPT_NOP: //(void)printf("nop"); break; case TCPOPT_WSCALE: //(void)printf("wscale"); datalen = 1; LENCHECK(datalen); //(void)printf(" %u", *cp); tcpopt.data.wscale = *cp; break; case TCPOPT_SACKOK: //(void)printf("sackOK"); break; case TCPOPT_SACK: datalen = len - 2; if (datalen % 8 != 0) { //(void)printf("malformed sack"); } else { u_int32_t s, e; //(void)printf("sack %d ", datalen / 8); for (i = 0; i < datalen; i += 8) { LENCHECK(i + 4); s = EXTRACT_32BITS(cp + i); LENCHECK(i + 8); e = EXTRACT_32BITS(cp + i + 4); /* XXX leave application to do this translation? if (threv) { s -= thseq; e -= thseq; } else { s -= thack; e -= thack; } (void)printf("{%u:%u}", s, e); */ tcpopt.data_sack.push_back(std::pair(s,e)); } } break; case TCPOPT_ECHO: //(void)printf("echo"); datalen = 4; LENCHECK(datalen); //(void)printf(" %u", EXTRACT_32BITS(cp)); tcpopt.data.echo = EXTRACT_32BITS(cp); break; case TCPOPT_ECHOREPLY: //(void)printf("echoreply"); datalen = 4; LENCHECK(datalen); //(void)printf(" %u", EXTRACT_32BITS(cp)); tcpopt.data.echoreply = EXTRACT_32BITS(cp); break; case TCPOPT_TIMESTAMP: //(void)printf("timestamp"); datalen = 8; //LENCHECK(4); //(void)printf(" %u", EXTRACT_32BITS(cp)); LENCHECK(datalen); //(void)printf(" %u", EXTRACT_32BITS(cp + 4)); tcpopt.data.timestamp.tsval = EXTRACT_32BITS(cp); tcpopt.data.timestamp.tsecr = EXTRACT_32BITS(cp + 4); break; case TCPOPT_CC: //(void)printf("cc"); datalen = 4; LENCHECK(datalen); //(void)printf(" %u", EXTRACT_32BITS(cp)); tcpopt.data.cc = EXTRACT_32BITS(cp); break; case TCPOPT_CCNEW: //(void)printf("ccnew"); datalen = 4; LENCHECK(datalen); //(void)printf(" %u", EXTRACT_32BITS(cp)); tcpopt.data.ccnew = EXTRACT_32BITS(cp); break; case TCPOPT_CCECHO: //(void)printf("ccecho"); datalen = 4; LENCHECK(datalen); //(void)printf(" %u", EXTRACT_32BITS(cp)); tcpopt.data.ccecho = EXTRACT_32BITS(cp); break; case TCPOPT_SIGNATURE: //(void)printf("md5:"); datalen = TCP_SIGLEN; LENCHECK(datalen); for (i = 0; i < TCP_SIGLEN; ++i) //(void)printf("%02x", cp[i]); tcpopt.data.signature[i] = cp[i]; break; default: //(void)printf("opt-%u:", opt); datalen = len - 2; /* for (i = 0; i < datalen; ++i) { LENCHECK(i); (void)printf("%02x", cp[i]); } */ break; } /* Account for data printed */ cp += datalen; hlen -= datalen; /* Check specification against observed length */ //++datalen; /* option octet */ //if (!ZEROLENOPT(opt)) // ++datalen; /* size octet */ //if (datalen != len) // (void)printf("[len %d]", len); //ch = ','; tcpopt.len = datalen; opts.push_back(tcpopt); if (opt == TCPOPT_EOL) break; } //putchar('>'); } #endif void handle_tcp(WifipcapCallbacks *cbs, const u_char *bp, u_int length, struct ip4_hdr_t *ip4h, struct ip6_hdr_t *ip6h, int fragmented) { struct tcphdr *tp; tp = (struct tcphdr *)bp; int hlen; // truncated header if (length < sizeof(*tp)) { cbs->HandleTCP(ip4h, ip6h, NULL, NULL, 0, bp, length); return; } hlen = TH_OFF(tp) * 4; // bad header length || missing tcp options if (hlen < (int)sizeof(*tp) || length < (int)sizeof(*tp) || hlen > (int)length) { cbs->HandleTCP(ip4h, ip6h, NULL, NULL, 0, bp, length); return; } tcp_hdr_t hdr; hdr.sport = EXTRACT_16BITS(&tp->th_sport); hdr.dport = EXTRACT_16BITS(&tp->th_dport); hdr.seq = EXTRACT_32BITS(&tp->th_seq); hdr.ack = EXTRACT_32BITS(&tp->th_ack); hdr.dataoff = TH_OFF(tp) * 4; hdr.flags = tp->th_flags; hdr.win = EXTRACT_16BITS(&tp->th_win); hdr.cksum = EXTRACT_16BITS(&tp->th_sum); hdr.urgptr = EXTRACT_16BITS(&tp->th_urp); #if USING_PARSE_TCP_OPTS parse_tcp_opts(hdr.opts, bp+sizeof(*tp), hlen-sizeof(*tp)); #endif cbs->HandleTCP(ip4h, ip6h, &hdr, hlen==sizeof(*tp)?NULL:bp+sizeof(*tp), hlen-sizeof(*tp), bp+hlen, length-hlen); } void handle_udp( WifipcapCallbacks *cbs, const u_char *bp, u_int length, struct ip4_hdr_t *ip4h, struct ip6_hdr_t *ip6h, int fragmented) { struct udphdr *uh; uh = (struct udphdr *)bp; if (length < sizeof(struct udphdr)) { // truncated udp header cbs->HandleUDP(ip4h, ip6h, NULL, bp, length); return; } udp_hdr_t hdr; hdr.sport = EXTRACT_16BITS(&uh->uh_sport); hdr.dport = EXTRACT_16BITS(&uh->uh_dport); hdr.len = EXTRACT_16BITS(&uh->uh_ulen); hdr.cksum = EXTRACT_16BITS(&uh->uh_sum); cbs->HandleUDP(ip4h, ip6h, &hdr, bp+sizeof(struct udphdr), length-sizeof(struct udphdr)); } void handle_icmp( WifipcapCallbacks *cbs, const u_char *bp, u_int length, struct ip4_hdr_t *ip4h, struct ip6_hdr_t *ip6h, int fragmented) { struct icmp *dp; dp = (struct icmp *)bp; if (length < 4) { // truncated icmp header cbs->HandleICMP(ip4h, ip6h, -1, -1, bp, length); return; } cbs->HandleICMP(ip4h, ip6h, dp->icmp_type, dp->icmp_code, bp+4, length-4); } /////////////////////////////////////////////////////////////////////////////// struct ip_print_demux_state { struct ip *ip; const u_char *cp; u_int len, off; u_char nh; int advance; }; void ip_demux( WifipcapCallbacks *cbs, ip4_hdr_t *hdr, struct ip_print_demux_state *ipds, u_int len) { //struct protoent *proto; //again: switch (ipds->nh) { case IPPROTO_TCP: /* pass on the MF bit plus the offset to detect fragments */ handle_tcp(cbs, ipds->cp, ipds->len, hdr, NULL, ipds->off & (IP_MF|IP_OFFMASK)); break; case IPPROTO_UDP: /* pass on the MF bit plus the offset to detect fragments */ handle_udp(cbs, ipds->cp, ipds->len, hdr, NULL, ipds->off & (IP_MF|IP_OFFMASK)); break; case IPPROTO_ICMP: /* pass on the MF bit plus the offset to detect fragments */ handle_icmp(cbs, ipds->cp, ipds->len, hdr, NULL, ipds->off & (IP_MF|IP_OFFMASK)); break; case IPPROTO_IPV4: /* DVMRP multicast tunnel (ip-in-ip encapsulation) */ //handle_ip(t, cbs, ipds->cp, ipds->len); //break; case IPPROTO_IPV6: /* ip6-in-ip encapsulation */ //handle_ip6(t, cbs, ipds->cp, ipds->len); //break; ///// Jeff: XXX Some day handle these maybe (see tcpdump code) case IPPROTO_AH: /* ipds->nh = *ipds->cp; ipds->advance = ah_print(ipds->cp); if (ipds->advance <= 0) break; ipds->cp += ipds->advance; ipds->len -= ipds->advance; goto again; */ case IPPROTO_ESP: { /* int enh, padlen; ipds->advance = esp_print(ndo, ipds->cp, ipds->len, (const u_char *)ipds->ip, &enh, &padlen); if (ipds->advance <= 0) break; ipds->cp += ipds->advance; ipds->len -= ipds->advance + padlen; ipds->nh = enh & 0xff; goto again; */ } case IPPROTO_IPCOMP: { /* int enh; ipds->advance = ipcomp_print(ipds->cp, &enh); if (ipds->advance <= 0) break; ipds->cp += ipds->advance; ipds->len -= ipds->advance; ipds->nh = enh & 0xff; goto again; */ } case IPPROTO_SCTP: /* sctp_print(ipds->cp, (const u_char *)ipds->ip, ipds->len); break; */ case IPPROTO_DCCP: /* dccp_print(ipds->cp, (const u_char *)ipds->ip, ipds->len); break; */ case IPPROTO_PIGP: /* * XXX - the current IANA protocol number assignments * page lists 9 as "any private interior gateway * (used by Cisco for their IGRP)" and 88 as * "EIGRP" from Cisco. * * Recent BSD headers define * IP_PROTO_PIGP as 9 and IP_PROTO_IGRP as 88. * We define IP_PROTO_PIGP as 9 and * IP_PROTO_EIGRP as 88; those names better * match was the current protocol number * assignments say. */ /* igrp_print(ipds->cp, ipds->len, (const u_char *)ipds->ip); break; */ case IPPROTO_EIGRP: /* eigrp_print(ipds->cp, ipds->len); break; */ case IPPROTO_ND: /* ND_PRINT((ndo, " nd %d", ipds->len)); break; */ case IPPROTO_EGP: /* egp_print(ipds->cp, ipds->len); break; */ case IPPROTO_OSPF: /* ospf_print(ipds->cp, ipds->len, (const u_char *)ipds->ip); break; */ case IPPROTO_IGMP: /* igmp_print(ipds->cp, ipds->len); break; */ case IPPROTO_RSVP: /* rsvp_print(ipds->cp, ipds->len); break; */ case IPPROTO_GRE: /* do it */ /* gre_print(ipds->cp, ipds->len); break; */ case IPPROTO_MOBILE: /* mobile_print(ipds->cp, ipds->len); break; */ case IPPROTO_PIM: /* pim_print(ipds->cp, ipds->len); break; */ case IPPROTO_VRRP: /* vrrp_print(ipds->cp, ipds->len, ipds->ip->ip_ttl); break; */ case IPPROTO_PGM: /* pgm_print(ipds->cp, ipds->len, (const u_char *)ipds->ip); break; */ default: /* if ((proto = getprotobynumber(ipds->nh)) != NULL) ND_PRINT((ndo, " %s", proto->p_name)); else ND_PRINT((ndo, " ip-proto-%d", ipds->nh)); ND_PRINT((ndo, " %d", ipds->len)); */ cbs->HandleL3Unknown(hdr, NULL, ipds->cp, ipds->len); break; } } void handle_ip6( WifipcapCallbacks *cbs, const u_char *ptr, u_int len); void handle_ip( WifipcapCallbacks *cbs, const u_char *ptr, u_int len) { struct ip_print_demux_state ipd; struct ip_print_demux_state *ipds=&ipd; u_int hlen; // truncated (in fact, nothing!) if (len == 0) { cbs->HandleIP(NULL, NULL, 0, ptr, len); return; } ipds->ip = (struct ip *)ptr; if (IP_V(ipds->ip) != 4) { if (IP_V(ipds->ip) == 6) { // wrong link-layer encap! handle_ip6(cbs, ptr, len); return; } } if (len < sizeof (struct ip)) { // truncated! cbs->HandleIP(NULL, NULL, 0, ptr, len); return; } hlen = IP_HL(ipds->ip) * 4; ipds->len = EXTRACT_16BITS(&ipds->ip->ip_len); if (len < ipds->len) { // truncated IP // this is ok, we'll just report the truncation later } if (ipds->len < hlen) { // missing some ip options! cbs->HandleIP(NULL, NULL, 0, ptr, len); } ipds->len -= hlen; ipds->off = EXTRACT_16BITS(&ipds->ip->ip_off); struct ip4_hdr_t hdr; hdr.ver = IP_V(ipds->ip); hdr.hlen = IP_HL(ipds->ip) * 4; hdr.tos = ipds->ip->ip_tos; hdr.len = EXTRACT_16BITS(&ipds->ip->ip_len); hdr.id = EXTRACT_16BITS(&ipds->ip->ip_id); hdr.df = (bool)((ipds->off & IP_DF) != 0); hdr.mf = (bool)((ipds->off & IP_MF) != 0); hdr.fragoff = (ipds->off & IP_OFFMASK); hdr.ttl = ipds->ip->ip_ttl; hdr.proto = ipds->ip->ip_p; hdr.cksum = EXTRACT_16BITS(&ipds->ip->ip_sum); hdr.src = ipds->ip->ip_src; hdr.dst = ipds->ip->ip_dst; cbs->HandleIP(&hdr, hlen==sizeof(struct ip)?NULL:ptr+sizeof(struct ip), hlen-sizeof(struct ip), ptr+hlen, len-hlen); /* * If this is fragment zero, hand it to the next higher * level protocol. */ if ((ipds->off & 0x1fff) == 0) { ipds->cp = (const u_char *)ipds->ip + hlen; ipds->nh = ipds->ip->ip_p; ip_demux(cbs, &hdr, ipds, len); } else { // This is a fragment of a previous packet. can't demux it return; } } void handle_ip6( WifipcapCallbacks *cbs, const u_char *ptr, u_int len) { const struct ip6_hdr *ip6; if (len < sizeof (struct ip6_hdr)) { cbs->HandleIP6(NULL, ptr, len); return; } ip6 = ( const struct ip6_hdr *)ptr; ip6_hdr_t hdr; memcpy(&hdr, ip6, sizeof(hdr)); hdr.ip6_plen = EXTRACT_16BITS(&ip6->ip6_plen); hdr.ip6_flow = EXTRACT_32BITS(&ip6->ip6_flow); cbs->HandleIP6(&hdr, ptr+sizeof(hdr), len-sizeof(hdr)); int nh = ip6->ip6_nxt; switch(nh) { case IPPROTO_TCP: handle_tcp(cbs, ptr+sizeof(ip6_hdr), len-sizeof(ip6_hdr), NULL, &hdr, 0); break; case IPPROTO_UDP: handle_udp(cbs, ptr+sizeof(ip6_hdr), len-sizeof(ip6_hdr), NULL, &hdr, 0); break; default: cbs->HandleL3Unknown(NULL, &hdr, ptr+sizeof(ip6_hdr), len-sizeof(ip6_hdr)); break; } } void handle_arp( WifipcapCallbacks *cbs, const u_char *ptr, u_int len) { struct arp_pkthdr *ap; //u_short pro, hrd, op; if (len < sizeof(struct arp_pkthdr)) { cbs->HandleARP(NULL, ptr, len); return; } ap = (struct arp_pkthdr *)ptr; cbs->HandleARP(ap, ptr+ARP_HDRLEN, len-ARP_HDRLEN); } tcpflow-tcpflow-1.6.1/tcpflow.spec.in000066400000000000000000000030201401360461700176050ustar00rootroot00000000000000%global _hardened_build 1 Name: tcpflow Version: @VERSION@ Release: 0%{?dist} License: GPLv3 Summary: Network traffic recorder URL: https://github.com/simsong/tcpflow Source0: http://digitalcorpora.org/downloads/%{name}/%{name}-%{version}.tar.gz BuildRequires: boost-devel #BuildRequires: bzip2-devel BuildRequires: cairo-devel BuildRequires: libpcap-devel BuildRequires: openssl-devel BuildRequires: zlib-devel %description tcpflow is a program that captures data transmitted as part of TCP connections (flows), and stores the data in a way that is convenient for protocol analysis or debugging. A program like 'tcpdump' shows a summary of packets seen on the wire, but usually doesn't store the data that's actually being transmitted. In contrast, tcpflow reconstructs the actual data streams and stores each flow in a separate file for later analysis. %prep %setup -q %build export CPPFLAGS="%{optflags}" export LDFLAGS="%{__global_ldflags}" %configure make %{?_smp_mflags} %install make DESTDIR=%{buildroot} INSTALL='install -p' install %check #make check %files %doc AUTHORS COPYING ChangeLog NEWS README %{_bindir}/tcpflow %{_mandir}/man1/tcpflow.1* %changelog * Sun Jun 04 2017 O. Libre - 1.4.6-0 - Apply improvements from Fedora Packages repo https://src.fedoraproject.org/cgit/rpms/?q=tcpflow * Sun Feb 26 2012 Simson Garfinkel - 1.2 - Rewrite for version 1.2 * Thu Apr 22 1999 Ross Golder - 0.12 - Wrote for version 0.12 tcpflow-tcpflow-1.6.1/tests/000077500000000000000000000000001401360461700160155ustar00rootroot00000000000000tcpflow-tcpflow-1.6.1/tests/.gitignore000066400000000000000000000000221401360461700177770ustar00rootroot00000000000000nitroba.pcap tmp* tcpflow-tcpflow-1.6.1/tests/Makefile.am000066400000000000000000000017211401360461700200520ustar00rootroot00000000000000# # About the tests: # # test1.sh - # test2.sh - # test3.sh - # # About the test files: # SH_TESTS = test1.sh test-pdfs.sh test-multifile.sh test-iptree.sh test-chroot.sh EXTRA_DIST = $(SH_TESTS) test-subs.sh test1.pcap test2.pcap test3.pcap test4.pcap TESTS = $(SH_TESTS) CLEANFILES = \ out/010.000.000.001.09999-010.000.000.002.36559--42 \ out/010.000.000.002.36559-010.000.000.001.09999--42 \ out/074.125.019.101.00080-192.168.001.102.50956 \ out/074.125.019.104.00080-192.168.001.102.50955 \ out/192.168.001.102.50955-074.125.019.104.00080 \ out/192.168.001.102.50956-074.125.019.101.00080 \ out/2001:6f8:102d::2d0:9ff:fee3:e8de.59201-2001:6f8:900:7c0::2.00080 \ out/2001:6f8:900:7c0::2.00080-2001:6f8:102d::2d0:9ff:fee3:e8de.59201 \ out/report.xml nitroba.pcap: wget http://downloads.digitalcorpora.org/corpora/packets/2008-nitroba/nitroba.pcap clean: @echo Erase any left over trace files /bin/rm -f *.[0-9][0-9][0-9][0-9][0-9]-[0-9][0-9][0-9].* tcpflow-tcpflow-1.6.1/tests/airsnort-linux-browser_page_load.pcap000066400000000000000000000353651401360461700253500ustar00rootroot00000000000000ò әQ&Xk|7aEUd;R"Hp5{uairsnortshmoocom  g obfuscationJ# hostmasterw*0 :XәQ&Xk|7aEUe;R"Hp5{rO 1airsnortshmoocom  g obfuscation0 h͆0 archimedes0 krustyәQlINNXk|7aE@_@4 ͆HpPljD(Vj  eәQuXk|7aE_@4͆HpPljD*6Ў> gHTTP/1.1 200 OK Date: Wed, 15 May 2013 14:29:44 GMT Server: Apache/1.3.34 Ben-SSL/1.57 (Unix) mod_perl/1.29 mod_watch/3.17 Last-Modified: Sun, 05 May 2002 23:46:32 GMT ETag: "8ce054-f04-3cd5c458" Accept-Ranges: bytes Content-Length: 3844 Connection: close Content-Type: text/html AirSnort 0.2.1 Changes

    AirSnort Changes

    New in AirSnort 0.2.1:

    • Packet capture is done using libpcap. THIS MEANS NETLINK SOCKETS ARE NO LONGER SUPPORTED. This primarily affects users of older wlan-ng drivers. For wlan-ng users, you must use a patched 0.1.13 driver, or a 0.1.14 or later driver.

    • It should be possible to use ANY card that passes monitor mode packets up via the PF_PACKET interface. For wlan-ng and patched Orinoco drivers airsnort will do automatic placement into monitor mode and channel scan at a 0.2 second interәQuXk|7aE_@4͆HpPlpTD*6>  gval. For other cards, like Cisco, you will need to manually place the card in monitor mode before airsnort will see any packets. Orinoco users MUST use the the *-packet-* Orinoco driver patch available at http://airsnort.shmoo.com/orinocoinfo.html

    • Minor user interface changes to bring common options to the main page. The preferences dialog is gone. Options are saved and loaded from .airsnortrc in your home directory.

    • Airsnort can save packets in pcap dump format

    • Airsnort can read pcap dump files

    • The gencases tool will generate encrypted packets using weak IVs, and save them to a pcap format dump file. Load the file with Airsnort to observe it crack the password.

    • The decrypt tool opens a pcap dump file and decrypts all packets associated with a specified AP when supplied with the proper password. decrypted packets are saved to a new pcap dump file. As an option, beacon packets can be filtered out of the output file.

    New in AirSnort 0.2.0:

    • Packets are sorted based on the SSID of the associated AP, allowing packets from several APs to be captured simultaneously without hindering the crack operation

    • Cracking is attempted in parallel with capture.  There is no need to guess whether you have eәQ>Xk|7aE`@4͆HpPluD*6D jnough packets to obtain a successful crack. Packet capture for a given AP terminates when that AP is cracked. A couple of cracking parameters are configurable in the Preferences dialog.

    • The GUI may be a bit buggy as I did not take the time to learn about using GTK in a mutli-threading environment.  If anyone wants to look into improving reliability I am all for it.

    • An increased set of IVs that result in a resolved condition is accepted.

    • AirSnort sets the channel to sniff on via direct communication with the nic.  There is no need to place the card in promiscuous mode prior to starting airsnort.  Also, airsnort now has a crude channel scanning capability built in.

    • Orinoco WaveLAN/IEEE cards are now supported, via a patch to the orinoco_cs driver (actually the orinoco.o module) available for the pcmcia-cs-3.1.31 source.

    • Wireless device name is configurable in the Preferences dialog.

    • It is even possible to start a session w/ a prism2 nic, pause it, swap to an orinoco nic, and resume the session, without exiting airsnort.

    • The PF_PACKET interface available with a patch to linux-wlan-ng-0.1.13 and expected to be available in 0.1.14 is supported with a radio button in the preferences dialog.
    әQBBXk|7aE4`@4 ͆HpPl{D*7 mԙQ{Xk|7aEUf;R"Hp5u airsnortshmoocom  g obfuscationJ# hostmasterw*0 :XԙQXk|7aEUg;R"Hp5k!airsnortshmoocom  g obfuscation0 h͆0 krusty0 archimedesԙQR:NNXk|7aE@`@4 ͆HpPjX>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~,l_ H*\ȰÇ#JHŋ3jȱǏ Cy񙢓(QB⮔)}cIr8s漉SE;:ڕg͈ȩi(*~!З38gEvkݿwfƪ-RYAM9c\M`XiɚJޱUUuZ>\B8|GRvg<W939Vg8S"c/ mTUDY.b7gˢkqkƮvTӭԐ9`rO=ٝu73:ԙQkXk|7aE`@4͆HpPjs2PG+8P4` 5 aFnAG 4" $1j1^H!'`8  8B:"CXPlNP/O??tZ5 #!^PȀ!TQ/n0R ?E` $9D0l k {ls>Na <2 Blt-cp{$b2Tq#w;KP ps@Y4 \xP`38! Dt`, TQ C*d>v /(9(`G,P'HBN# E\NvB /5T mDBT!(hG:dwà|@<t"&hءA ۰E)>$[,\ҡaD $5-P ܈6>D$tcP-19VH:GA!A(hz@AɄBɜA"'dGT2'|'> .!H'0 C;PduP3XGE:D:Y e\#1?!?7~ H9d$/7.{IzwCB @A B F{M,!QXʀ!^LY.!vxG-@6R\V&6IVF@ L&X @$, ( ' 8%l;[mBhPl=H `$`BE>f Ȱlz=pC~~ԙQkXk|7aE`@4͆HpPx%πЬ  {HTTP/1.1 200 OK Date: Wed, 15 May 2013 14:29:44 GMT Server: Apache/1.3.34 Ben-SSL/1.57 (Unix) mod_perl/1.29 mod_watch/3.17 Last-Modified: Fri, 03 May 2002 16:51:48 GMT ETag: "8ce03d-1057-3cd2c024" Accept-Ranges: bytes Content-Length: 4183 Connection: close Content-Type: image/jpeg JFIF,,Created with The GIMPC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222]":!1"AQa2q#3bBR$4C+!1A"Q2Ba ?J4[A$ʑCy$@sU[T܉vpbRS/2# cG c o(S68 }O|s8Ƙpz-Tu^4o,DxbQַ֦VqkG9-wu֠O_^:G?F? ~xyͫ+$V:T ;.xg'$88rc2ovDggl38fMWGrגH=;s8]ʷ5Ʉ0AGe*s.bBB?89>:q}7]#\ә mq<ӱf c9=>5q3@2HprՑm=͔70YP|V+J.uXn:'zի;3en-W?K p)!TrMe}O*Q+ Sה1撪GuxԙQAXk|7aE`"@4Y͆HpPj! !)KV0b $c 't<T ._  @c5MW|,@y0ԁA 4x-!  8yd XJjpk N!Z( 0=D8 qC1h8 )-` 8LaA8Ƞ; @8V4Ah  ,9`4`))eA2xɏS0ddm#D \ ɰq`Bn Hz߂c Lp B@6UĜl`ֆ0CH3,䲕eaO`H>ת !hZY߁<v1>4q ͸,H4/4&pUS`Eeюb8@+ Zj_>ۃb"%92 gH=!`d6AK H"uH b '{b pH-l 5%#>a}<\x;cBHoH>I{gRcQ"&4H4$$\s~8 jф` 1Q[4g0 @9qhA9a  )%1^ qqס.b `#r$v $q'8a B >)'' ='h~Aѡ!#0$u##!!-h&fXIBq1s(a"r2@'^($8Ar$QjU8X;ԙQdXk|7aE`#@4͆HpP4%π ~)9 u5B^|xM"{cRlY-V@z;|`)@wdi&[]\2\z`񏊕9=z|7&mE)J@)@)JP R%čׂ0n]NNBSy UuRTr_nUu*{Tk^j{[QQyra`Ke'D@ǩ#$緥BkQb$2e zXwT}_sXЊn=ٯhA/YcADo*19땺״]sip,:XB R?B}j~3F6gݬq5#GW (??~_O"TX[q!XGk<]#bnf7MЌr]kmlˍn7ynNBϧyG;i,nv;3onX/N2Ic'XCK&q{gpqǮp}jYnl.ZuA!2v_R2p*}jNM2䣬R7WԓrOrN7,)YXk,DZxO%ϔ 8Zp( +tǧrGpqZi>-jqK,5_Kd<S|C=kchad./'I>rko"_qQm2Xgp|்D_WOo;QA yq jwEbn@pWr | -I-!r}$k(HY8>.B?qx*i7қ_$Gn,dk2}zn]KRIFÉ]K#6r:zVmVt!H5EDTE 0U[iW_M1OJU')JP R)@CZkz7Lw)%Isn3Ԉ`dd3S%#KMc!lt+U縇GK; /eF(F<ĐY5ƴt7Kd%uk>D2TdB0=0Gg@P]s<Dҷd _6.}7ĥy A\I,FT"POmkۺn-hU>S՜ `r *OvјA%۬q?aV P2ۯ5L$,#{Nbj;sC+$XbL{ԙQXk|7aE`$@4 ͆HpPɒ%πca ~IkKͳzby*ːUҧ/lybm-[.D0xd[='ǚ@P,]˨[6a?TS[@ZZ Uxz%I\H {s_.vO= *'|f܏Q^=fŹگ{#ʯnG|4ȾK5mLjRUV :tw-zvI/}mmIw=޷wv1[w櫢6cc~X)\*()JJRR()JJRR()JJRR()JԙQBBXk|7aE4`%@4 ͆HpPjx{Njp" <^כtG~ZF[ ;}!w>{Ytg {L99Sܙ{L=m'aܽzMEdϚ#tX DA^[I9$?YX_[/yOѯ2zxy _}6xf{vs_{fyH'# ++5|.-m\מG5;?sm튶,mGT你广]ђ <>K֋^$ӷ.^*7s-b\5Z|~'emj.~kEx`jE;Qـ$U{WS՜ kŠjteHe .O`E_@9E0P@XzQ  a+A\}rN~oΙQk)&^TbcQ}r%&v=rzdji?-jH"@nep|^.l6̼r76^kFFKgYYB|׺ %G=B3뼚vq~UDPH1%Bܜύ67TZO{+wP[+[SMcNͮ,IlFmk8# .n j̉!Beolq{5RV73XuJ±{i[7ðFZ>ZZ|홃v|<]Bq2[ v)>Qkv<:A H@H .WO>nX^fGww^3tם78pmZ$H$H$H^ bYsbiho߅̜uv<`܋p$aFi$U 5ыcb[/5.ݓzQTf-f.q,ިDHD"@D0"L"٪gw[=O<\һqSZz*,lG=k<;^p{+cD!2 x ZOBOl: NJ몸W*ڽ>uc&j.=fܳ]Ss6{vbq3wE[?1Klbuk{nu;]nBSVwr'kff嘼@j^% W(3Jμ_uQpdzCsd|0buޢR>]F>wc:ChywҞ?ej(\ub+[=]7s /|)7,/(ikc#\K.=ZkeWgh81QK=#K[gݴfKн/o1kmvfc8Vop3N|E_:kSrVES\xH'%vu{ ԩzݪ]K]&GnSSsN}=myW*ssn)Ly7ӜgY]j\񙴮s3 0;EE[i{3>S*rZE3wY='K@?%zz}_˳1zŚy}_z޵"FuT>=G:9jb'B(*"bu,Rئ(·q<>1uxod1.k7Y#I݆#E_@JۇGXۿO:hĦrLfEZV幽d! F BQB2&ۉ3vzcq;[\ǭ%vj͍eH> .O`Ea@9E0P@cbQ  a+A2ڋIƟ6ӫʍH,k6RS!s?ck~^:܏7Cr$Z:+ZݎY|1iۺ[ǥ5U!VuGc WZtY})'Pn}:ɓ]jM/qqֶ\c3sq?*r-^fQKb<ںe mKz [m#1$kvn98&]K^cGrmx6k{%F-9p\w'z45s2fgq2|삂XfU,ݜ! ܜ5OK#ʦRؔ/#ͱTWkNŎsZ[j9Nj:+_pj5FQ F^G64xnέ(SD HO۱97j3MŠpµbXI;+xv3fKTe,{e׆^FQ F^61$;1A d0bq^݂}GyԠS:lj%eݟ6יa(R].UgxNym`.H :E.67H%RÎ:*a«pM<Σ $-Z<nX#}1۔{2r=&Gp2C\MASʐKN_8Qe{' 'gxHB²k3"et؆NY$5>Eb5 (A+H.] xY-35蒇>NMm>N-g:`X28dKM2 P{, ͪ2 \fF CL|s@O< _z-+յ)ïYI5H(v3j&h\CM34;Pk7«3Lz`4+_RMmЇD:ujB#Bgt[AldM˫S6VMf; `nRa<5׳ΰjƎДtC'HBXpCs eE$ l84٪ kN[sӎ 2[eyfӵL׽g eeaI^6HPA-xj%uQ>ז-`\`-(q'cfD7%V/Cf{KsTg!EDo;! ]^GSĘ1TнH{kQ׿nFsp\l섴5RFcש. |qmäWz_[.G^;E ᑲΧnێfsQ#ۛ7:.ǴSBZ ϬcCeH .O`Eb@9E0P@hQ @ x+A8nG 8s &h8n@^n+GWsbB;VQ$7G a "kwzɖ$Re߁o!]f-F4\k Anmbve%Q;7-%yUdxjnM v\~Ý{\}0˕! 0fR1,ZI6{l|Gxn,e>dZ],h]Y|M9,(/̠ѷ鴒v#vڒ: Iw+\' 8Qs,َ S{IًEv|CGF\%-=LfL˝9Z%\n!K9`4^*s3g=^:5n_ݛȲRٶOY BTN %Dϓρpٮ!QmCWO/׼ᗮH+jY"RlӴa63 +۝vFWf Ks9ff/YɘZ-YM-+6K9Rx X [O*oGDa1_Tw=sNEȢq% Kk)૸kc:wȧ//hmΰ"Ǧ}j[" ,i1ov"DzkM'L]Ŋ~PηF~\V܈UuE9sIN5L{.D}݇.y3H9 '$˸~?KjU92Sͷ}A9M$~5ʻR(hLۥyO.SeSrHLAK+qy/|UDt 5Uf]מi}-C/ia 1$ɒ$8Kwf5t&[8tnߞufmcOaIswt t@*toSK(q- eH .O`Ec@9E0P@nJQ  x+AjiҰ*> ]Cy AYiqsCY^4O*lK%˭qMno&#OnC\s HŔ/ìgY\)7Ҳ(,o&C tq(9Qy~:1֎^)P*TxQEo c9/'5kAuMӑE^:{ng5{C}Oq'r;e bog #-u!>*ӊ ̸"O*tZ=s}oBW0]n49O V$0;ZtvŒ$F"um/!: hPI 8\QlrIoplNwwNC||m(OzOoW#! 0f$=t21ę3+mBI%K/6K1/11#a>i-@Է |yaJ $Y$>ۊiHZ^ADf AkQ#@/ 0MIЈ.BHH{^۪iH4J0M%X2 OaJPSaO)]9. q 42Q!dA?2TښZ\"[Lj}B,m>CKYQt^yԴ7Tyl(x[LJ|93 ^ot8OH7$ϰ/d\EI?3xI7+^AvcպMlDW2zI,eHU .O`Ed@9E0P@sQ i x+A(S,tXQ|B"ObdB2%ߧyy3]w Mc@OziApF - B _\TO`ܘϡSK .إ%hAJg˭o>7GW ͱyI6< %FAݜ- ,cm529|7x&Zd ܫMtݑThURk]c+]k[+;i28x"\ma6WKm3QG4h4 Ai/N Ah4 Ah4 ;f.}~]-;IHR\H@_(G2!H.gӆ:dȌtMCCC"Z*A?[,O.N LB` =4pG?_QeJ, 0ڛ%hPM%% 0Buqï:4ï*>ƢT}[rOgԁ}`dG!A ($M KJ^DM6L:Z;W{FpiJ ^D!׹(f* gwR_\X8}na_327|!d< mn!Da aQ $0\G`6Ǚ_xcNGG3>!4˨g^B3=CqOg~yYDIK+hlax>9_k2͇&_Ajg3 r$f,?j ViC7PHӨ}VÓ*1{9|*yg#g"sEX3[VE6)w yU<W-b[VѸb#0^DA^BS:o))ook!yBefr:lPmBhQa*,9$Oq*[)᭾ BiFp''Au={rma(h'O xy9"=[ Bpd6]ą)%݅"$k64`YEZr 0xY6᫑8p%c =!9<2,r?tUe9s J[L>7u7ݘ}5bɍCfA@8inX'4Y-2s:xMn}['iŹVNw%دAՋ SKryS7mn: b1b[DŽB"}|1%•&Kqqq~joŔAAeH .O`Ee@9E0P@y2Q  z+A'Jf{ '\HjM6B?k|K]RuJA%_ W7|],4yYSГbKz<)s(DI|ØjB)"SK a2 c]BZ3p kk`Ej^[b  $8Q-Ep\܅.A]9BZAa I6arJC[ԯ'd,u8JQ{CRIڊՕoiZV17g17dy?U=9!Sfb_fl]s=W|L'&ck_.ٗyOaVȱTjk(> ^ThYLE[dDhCKm((,[U{J##0d.qb)b'PP_ 30#$B䥗: IkF";pb\q;%cfHa^yZ!i&iQ3g8Ĩ#}!S25)@RBVQ91)Ah48z%eG(sP:~49:3aQJM{pY5=Lr 4j9AjATMsa^JBDnP5Q3dI6o8MrRBZx]V4FqhhDWJecT7A&nG ah核/ɡj90s->k`0Z(q"GA F`EsjIgƺg[2G',&%)F ه8 K,:{dcPFi 8dT‚Ҥ6D9GOPL2\".wA<Ͳ ͧP]68aڎL Շq0]pi힣9h ak*+J)T%RGRP*/Qs Ϣen\C/;υ +޺W[Ss&޳wӺzM$rKK^td;TX7|ҹAB+ -'^YiW%#7UFo N$`K/YWhkLlsWء);OWD((Jύk*jkԾT5/*`m XρmJ(UE~pcm׷3RV=+_ejQj:JUx??G)eH .O`Eg@9E0P@ԄQ c }+A&6-NoL $78tzK]ַk᧵n8 yG$xb#H􂁷g!;PP=J 8j&%u-FϗA곑-4Bɛ_>:FmhF5Gsb΄V7ڄ[8^Vl3: !Rߪa?Ƽb>Psê uOu_q2jωCLMA:D7fJª@fp{ht2GӸk0Xf-(Čb(59"*@⯼ofwryULP!}6zY>z J?&l{äzTx_}?"Yd3M BO-偈z7E}uf[]0 嚝zY6>̮كW65 1 ˙}"cj>chd= rҫղG: RiZ[S^,D`@bi. _'YL:B!e,WŢєdBt}!y$DU8mLXQŠpL-Sx̒#Ϗz_m/gkvk}n'0x[uLMddas®F_sO0WwBW~zw-221DKNjJ1NWT`\>E~INqiFlͲNrvCldf>nѣy$eZLaD`0rc&1fUiΘUy, y>.9"$0ZgKfl7;y<~z*^~"}PPJm6v"Lj8R4C)Pm6{큐{N,N uqb@G?!\;E&[c3wDWVzCn4wm:-QqUXꩍ2{24yBB-~L=SQJ)`7NCqWԝ,(K":->j7, nWxQt{Ƴү%π׋AQSb ǽgA`-Zey*"-+PԾ`"A%] )wH@خ0EΫ{3M[B $xGpIwtb_y%ի-Wj%~ok4G5Ki[1Zj/oxc|x΃eJQcZy*gFc޵&=5]߭]J.XȾlL[nn0؈V -H;cqآeTeCBטw?rc%o8[S>c4v 5WYτ؏Yݕo 7oXٜ<E{N[ QP[p4oDTt?d􅚍gf֣(SU3>k}}^B[QD/vh^ZNO{t/woz<_cwGCGMy;Ͼ7k}3${D.*ZgHj}reN|qE ;t;l,݌]a>^-61-@3K'qƗb =<莧KBu$"MMi'5 *n%q?uBůnXϸGcA=/,X;ߵWeM%lWDmu=!PTQJQۭIFQzr.65<]q48rodڜ@f;vLU1lUzm8\ 2h\Ep<%~O]G','ׯD!t;ըUWOC}E\; U̠$Ks^-> I?ij#QWibnZr7 yí^t[cpP )LihE2sd5ʴM-=%8d?lpĨ2Ԙς .6H6'؞e782IN^Eq[ƸElG%K@)Aƙl!>].r³p⡁ڡEYԠQKn Պ=9ʧWjdkpLf?RMΚ{;=Eb%h띝&,˴ M:ڨ~ \d|.j;m%Y.Vg 8;e; +{B9yL#b9)!FҰ6J́hו G8[sǓߞ>)lwDӪrhTKꚈeHV .O`Ej@9E0P@ԔvQ U +ABMϺH]J&?vuƞmD#%)GBһ* 2Z8r "TL3o][TVp Qك͂}y@1 &;ȏ!ߎ&2885m$TT֟w?3p"KK-#ҳeOFE,C\H?L%8**t%?TEhZ/JAՁzjpBBt!$!$BTHWR&CpeMd( t AJ⹣QeA4z%[D_Wˣ[l\#F( pTY.L?pHiHlTj4_%7F]tZ|J((DJ"`ZP^nSJ9sDT] I4%[nq4W]H:}D6X"ُJ ˝Pت[.(Uhȕj$VK3|;yj]⮆gV"Xdۧ}I [dP8B*KMXD.;d' *exaLONE|)"/TPQzҋZNIo(=pjdB$iEPJ\#Iw|4\Q-{Tqf?'R''ķd7igӈui0R(y1I|UQ^mɐGB" &a-O6G2Cn0m$wHl4-u -ո!ĸ wq$9O\fH۴qU@4xY75o֣sRW w#QRt҄!-59_NeMʜg]a˼@:*(R] Q1Uиrso`!=^ (͆MvOBKN"(bwO(h~[S4[6g{Vb?xbb~62:5So<1?npv)/ZLKnY\ZE45GL-foz:vNӑSOK~LdɥGt0Zf(h>!hZҔ] R幡l|No^HM\pBԈZ4a&-É"-TZZ>zeM+,HiVd"/d!""FhUi_q/Ȋ˵M˕fe lёBo2ŝE7:O*Rb;ԛU&WQ%ς+O55`ZˮK)sXh)֡erdڢ.Y-Qu TzbzWhBZW/zH=~FaQx^#Õ2R,j3tLJvqf Myh:]2/0 U]37^HhGF3쳢hr-hF \bA$hFn讶*3poTꖱZPSL)._+.|돿\W־a$W &x59jo/G[m;.5VR?!cUֺt5e-h>%eAV@d!5״XVpUk0g[MMdy>l *M#Pxq2Ih-r Ɲv &*3ʝd.&[.q "J\뱙 "IKDn'hHlLJ*L\/Wģ]i]iEӅ_6W7uKWl>=i@&h>1aU^Ă^fI(e_L fKplySN2tŰOJbi%в"mϛٗ\l"ˈAd1^M:r>"W"<=' `ZMZoX\(I6 v4ã~4LMNy0 *4/*ꏻ\ jDЉ Y-(|P=8eH .O`El@9E0P@ԟ^Q  +A.b\#5Yiӵmǀ"4Qےz^BsM8mRNeGZVeN"jʚuyi+PRU\Pr$}m, C-l(@NL=u:+W$Z OJ\.-ekк# ňΞֽ "*VSs'nU^QܬDME.8OQpo'>%)VO M6!7ma"#M5Uh%*]ͫo,k'LXW0koj$Q̕IKE5!FP*!T" ^GO %[eC.D|G]y lTm:!r]= k$JU|DG3o6@)UR|?!>ܙq*x.՘WQ$k^.wWW$uaݼˣ0=U:` ^9rMo̕m Wʼn{ZCbtƣ[&a$gљh5_ qm̒ Ze{;2p -̋u<յHθHL~Ӭ_}M6TbĞRxuE8m4kʸ_ x^l{t0($w2mB"mP2uח]-p;$fUvjbd[f(Һh&J[B99@3MyiȮfN>o2\iClӠ zO-[J˭UmS.7Qt* VD ^<$ߖQQQhEEԨQ| DҪ5""`YK5n&OAXUnn 8_a 7 йYm`#q$$Q;uY<UNl_Zi7e1ЋrHP^#ܡDFlbMm,?CFe\u¼5\lq<RWjHƽafhX%ɋ!Vч"f]8\,4QIYa:"_d[s"%5vyO?nuB++kEv!'v}?\jO!3v$+R܌FOFH ӧ 9nf &UݒDV\5S ^Uʍ-z"yJ,/ӥ6A/hJ?H%yN%u+W!0$&+W̩GC"Ft~KLO?8rqQ=M 7weHk .O`Em@9E0P@ԤQ  +ADDJDȉjD^Km <&ڎALs &yȏno$FAS'=iFH@29p (nW eOJ qtĔ/wE<*d#LfƦXƥ,9 NA]9 G֕DK„~1I([λHѝYl+- NU" o-M;|):QSZjŬ"ě -Ə~I^MZj,[n GK?[/W>w ϸƈ05$[gu^v}<̩Zr㐝R\L\,ی[~dBsMl) u #ʕыteM94QK䍓Ϗ4벝mj-Dby5|)u+#/mh](+6T"t[= Ѳlh0RqD}'Q1.2N Z3e:">'@;g$ܦņ ..Jd,?\Ipme$J>NCj4dIA R ܎L(B\ ZhAAԣ QՎ4r hG(hD!Z8ZwOv;}Dhҿ0WͱpߥrnAV!3< c*\-fC)v8F!aȍܕ%gM:E,\o/JiA.dץOuEE)StcP(m7 ŏ 76FT1Z"xtU4򧓙p)v<=@@uX~lB:"$̌9!̖ːxf5jUt\- ׷l]|ǘu¯p?oоMDMi1rݭD\[9y4D(Xaۣž0džFR L5%lS*)jJ&!Qv7/sv{˻ ,.85ܶ?x~߾Hx?ܓ'O|1e 9"OI/\8~czzoBZOa9'ȝVv}DB"&DЈȉ ;|KeH .O`En@9E0P@ԪFQ ? +A[i4㾱K_[Y?ħ8H"],29RxR\ȱOM/Ɇ^m[Ave4}Z$0bD"J('/Yi@DA")ANDDL'p lV"1Si@FO.T\#<l]m ͋ۋrS эp0o)~%8nO/G[,Jj΀~3 ƒ54pFhA=U]~ŝ~wȝs _Z˭Xㆋj <:\:򭒼 ~ 7Hv hqXhϸ>;t&PL^T>B/WC՞ j_+xWf?;,+ה8_JD5]*MMl'Bؕ]KBMD hB|aqgbL_KlpX_Ͳlt^HӖ;q3MȎQ䉸uyuatFGLS( S\^VX|qJRr8E] ̪S̿t%/Fbۅݔ[sv.&>ПS@U u"yi˛왇֥nakZ"ktu':hfWE9prjߏo:.,S)A6׼cY k"}$q!0Ume kv*5'&p3ScψDU}i-iLWZx8@Χ^O b Lm]D/0%pb]FI;(DFH 6gqAo!Otۃ#.Tp"A"We2{i.0iX/[lk/gd:9A|cjm3GGwf깲-oL)qqknv⎎_nFUj3tM(rUeErsoKj?=2 V'Li҅x-Ϊ~B!IyUSIڟ #O`9ȠjUGo x[neUV]P*rܓ&rg`?xE6<{G?m:n]lBD\yQW)DJaB6$*DCf+gͽy84b/+_wpoth;N8E<ɧ ~hea6ZF%G@tI PFX7q)D<Y*?$|I|N.ujp 5]{) vs.Ty P @"m>pOH\~GNxKz '7G *>4Er9W#ԨD7uع]#[ ʞ:yD~t#Is\Dv$,vCf݃~yuJJ=JsĖ ^LzKp_1έ[mmy>`&iaku^|P}Y=ʚc%0/ڄ wsj99}6z;H`Zzyp)vz N(>^uf A4_@=kV7tb^/UQt(-ucm:BJ 3M'T| 8YDݷ_B]2\4%5OB%=3>)믏/uqm\lE򡢢-4_n##Q)R$Da+Zj$Ɍzc_#CWK̘p]N[veMlo5HLTmi9 K뎼hNd[Ͱ/ur0`%kdeܤyd{82FvQ"yIu86r5 DYį14p4\k\ mאJ5~<|rO3K ʕkY*􈶫ε[札LXZjxySɊ]9gXD\"T]qC+Ř;\%tI1ܥ"hE;0)107Z P.6̜+{yމfI:ě>lW r]z40"@QL#0$NiAtjr:wh}ESRs/>z ޚ Fqu'x2?`9pIq& I9!UBM>kÐƼ/[qQ,Ԥش.iiZWb7nvHydUVS'k}fdG\ܸ7X[gU}[Kzɇ#EL.o9*Cj8"ioLiW?i4$/-~3S%u'i|X&^Dw1GrT1jiҕvU|\9K d멆ZcA'$HutKq#%/.@FQg:;EK3eH .O`Ep@9E0P@Ե.Q ķ +A&ܓ g.5%U -G^/Ow Y ;I $xpaȗ%!"_2cmp(5u O&3ޭ Vx8VӪFsdAzյ^˅U=9pτ8~6fAaAԇ2*TDIW囏xkZ1-"ωC#Gu㈭|uG[(([Ae0[.ХHn 3U>iʒ4i&7} ן;x;Sn rƹ6:v$'!d[pؐ˺WEpY .-J#A:p,%HO%~EuiI'uc݁Rϲ0z;CkTM?XZ5W"#n{ }\onQpYj *o&FŵOnCh (EMD/]QMd]QO)- 8É].8g2֑aܛ;} ~YPuvB٨.Sr'~qK췼1*K :I=3^Cf6j z64*#ypHR^Aógʑ6[R7q~*RaC[CME\iJmg; F+zQuWjx 0RRH:5dkM<0klzi0YrŊt[&2㨽0EyǑ}N:ӠMӠ.4d&l@Z.÷>ul.;ò%uw?;ChoǕkƦo'y *܈ڛeρ_..s+t&"m:P/km/aɑvC=,JʒsV:v V9vەE4 ܛf>0X j E&v\WcRPrM8\;-bh ͠@B66:eN51e2YŷhڧKGZ>D\j$q*zJrb)qg\~˜\8δoj]yua񑶘eiDl(ALvOa\}1nv/kCfc)ЇyS 22r*uԔQkk.`c$ rC*{6,W$$@1'̲_LZaD)!ZJ*ao hRXN"|L%3TC AR6 %LiU]W f|4n0Žtޞm{R-iҿm=ge5N˲Ke$(8} KE!i(K)f5L3v\.TmxeH .O`Eq@9E0P@ԺQ v +A1iLBM(Dޮ"F"Cl)n\hl@F!5|:0Rf~[E%\К #NRậDlUT1RD÷@q ۝cz vGӈDCx6֙cUfSlGoVT9BayQ48ׄbm h 7 yWÚ78"d+vrScD6x_g,#O aԠ[\`*~CKe|Xc;2A[qzˁ򰻬 5֛*\ -!•T.'A/ge g~T\ +2@X^5Xs\Lw%(m˝Űw_H4oKtm4&Ņ$̔?B3%ZѥO%y:5'QHQE%N=输>5ºێ !&bٴlw9x'iXaSʈnqI[+̷IQI\^]àLaUxycLNsm8/ӭ4Pp 50˂ͻTũ.Z!ef~&%Y;Yߦt8* MGzс:ʪk&0\pq`hu5_܎DsCf0ԘxLgja$骩"UUh(<9/vkm9 dFx?''*Hi~)&;̈́_F.Y|WCmۯ֕ZKl]CqY/AlDOSv2kz>6"BLIL~eYɰU29, SIٵn`^J݉)f)9]#J7vHԫ̈́^\:UҾDCm).Ԝ3ck3,&vTI vH. FRU8Te\&eHYk.'iҖX>)ӭVqj/Ktv-1㹼<0eH .O`Er@9E0P@Q  +AI-Dz/+O0oiPE4&M/yY:|.iec /4,G.24HNjWXn(J2YO`dnC2Td Ger̵я*U:QySqpކ8At9`cB¡+oK쉡bpyڕtaUIJ$^eO̰\۟"$Đܸ!%U]+NL5`nN וTV)j ĘoRPUi%BOm 0KKYW[l4Z$h4?y%jqf{([_0MR '"Drt~NJ~W".+OMyUHS8fT 1*)i5ޟ.>vSeO+iح ~"ڮ|r$'E(iXVsWSf| yz/2uV$0}Y*%E}] \g= {z:qGtrIЛxD/ +и)1sQяUFamL&Q;+R$Ux5qrhW..UG`tշ=l E!h! UV <,!fQ4 (CaWŕ{kT)/k=Aϲw&7.k6yruvgуydvi~g+u~aro]T6m;,\\j ݝn^ݽM5o^ϟ{,lw-s޻w%6ݳh;eQwmmzNؿl23| ?Hbl{'ٻ7g˸ma9vߟ޻>Mrz}^P^ifg^;t7gug~m{.ݏSst?!S68 װfƵۿ|ϑB.Vļ&R;~: rP6pwxXC~e"(0j?x{Oi=!eH%" .O`Es@9E0P@ŊQ R +AVXWsh՟$tGO ]9>Q8ŗ- }FB{+$G`,8r5~BߘrZ4h”0OOI +>- #Uj*ܙæ/^*%&eCUr7bj [OwA,[K(UеĩBrC0-cm;CiPE 5Bw3:r[ Py0H{!} M3J.Qn[EY[ݠA3"u:})hA?дiiilYEvŧt٠umaC;ڽ]h/hͅĩ A@İ5yWJ3i#tͨ2|x!*BMVik( K2, $*R_K[irQn>43Jh#IGo(n,4o(GA9d ᆅ #al>{&F#"(ug@[JZ48WS? JRZjJ 8MGjuMkjLs,~ajoJ*z[E=T̯bm8em eDT3>E~ٛ; p@8k }c-z|]F l4T]pn@1^EbR@:Vfr>ʻ J?)KI&y0 KᨫCYYJXZrS5Lngop\yA`1x^90rk/,h Tz=f;M`Zi~v^ u䀯 9f4l5-)u2=HSM[ETpBj<#HsoOܹr˗.\tPTyH WYқŽ`,h0?,eH* .O`Et@9E0P@Q v +A LU aDZ829CUgĴ=V~浧3[7^۵L sUv~%˗/µ!UIق-#2YǭJj{UzJWEL,&ex̣x]Vuhl|>1^ W 2X2|ƅ|gM %6)m0.EK=f`r6Wh;*nr&ZaTk_ܹ~7/˗.e4K`PrӌZhC ]L!S"ޅgmB28`%1=eWq=eBrlF7NoࡂTWG( bԝ|KQUh3dU&n0%\~/.\r.\r˗b1̑ m6+-OêK- !>0 C*/VocZr [._˗.\rڱAA..Qk6LK ;x =!Klr>L泻5am&F 4JҢ#mE˗.\r˗.\r˗.\r˗.\r˕% "I9 `-3h[Ek%t&l/ 4Ã*2mK?B2 ϩ3F)N75:A탒.\~r˗.\r˗~㎘>AeH?.O`Eu@9E0P@rQ  +A^D3d|BVW̽ֆjC)E8|M%г܄.GM զ6BJ>MK]bXA%nhjչQa bХ" âShjv._W[*g3FPiThdCkC.\~ /r˗.\r\r˗.\r%޾ս]pl%RZVө;m:YeLkMIo2%9-3Q{K5Knjq@;YT(, hO'd@=e˗r˗r\rχ1@w6^MGx1=F` PLP*/Ϸ<V`Tnٮ޽jpM-{shڕ*Rcǵ\PL)scU|uìzL1"3kDŽ7b9-GrR-.k/vXnu[B:G# ? ]Z*h._"ys t^ @RPj5#g/1U Q\r˗r/˗9HƗ* ,_e\1rH,x tޭL C)am %e˗:hfmq0qGjgTq0hg`*s@܌53BmU U1I]\Z<ЫkhDmab;:vWGߐ5m kw_.\r.\r._xːÖm4m1C& "XMFjyL(z 3'[';V+~$٬YWѠh4 F9ST;*"8aG#KC, EjV˔k+mi /$@tdT>z(!A2T̀u;9Wk^X\8lrYi>'y!b:?)S,Ǯ<;uK-X?:*MivZ'@V,nݐ 5 Re]*"aS*":tbd >]L7 DfQ4nBzT^[~j3A 啎{I'qir--`#lI۫Y,]1Rº^f./ǫ? oQj.4\U*>*䀮1/[zxK)WeH|.O`Ev@9E0P@Q #A +AqH{$48e(M^g|ac@\nN6x.Tjv0,WEֳeCb6d vvGmEͤ>[+j ŲOl]ѯ]dY}܌GK]v7uYf w0-išl.\{VcEdzwy#lYneǮ"Xc "`i [,FjN7dLCewIW,4X vL":(*))Syb& 'p·/GX Z Rj {ì(A em$\l]:pXz=Kwz"#m%0&H/#u~z-m6t#j4%<8Oyrv$zP|h1i-w|"4 V(۠b*l-3[٦5=B.Ci򛀪։uk2{Ch+KN*nL̪kJ)w:8-֠o/jET-4zڍ\L*101}ZZ-|'N4'&mBPQub`8·pnQ3ҤxtT>tMLmKcjUۣ, uHUh-PXSfAm4OCM!Qm!w˵%-kKS-E]t-ĢQ]` vM C#AߡqFBFTKQ8uy34گh.d>*.  {rڰ7{ $sPp"{݁V{.msxwzo lhT!Ku`m*hTEq L*-^&k\;[39ڠƐZZhᕨ*؆;ݨͷqcX pm30Iݎ E֡^5$ssH.MJv.WỞ1YKLOdiTA 1de;pd^ȢԻl7ᯅ63 6W 7AmѡЗ,GnmXҚE]koQxW'|T1y7p'b/ty}&>GX^{c)|sf畧; /loi3Ts?|~xڛ#2/fXEkӟo ^>BsitP8ұ^?!R/߿Y9bŷ_.l#LMsGQ+]?zG||)u\3=O񐎫PL~O)zK^W(5o!W ܟ`V%6ߓ /Je `cs.^*O㿩@_f^[óu=--h;4Փ|Tz{?OGFuz7E=>TPc~Cō~$4:k_ rm5R97S݀+P&b2{޾G7?s7Piq]JnƟR/^@]&K&S%+~RQu+l=f~]_o?ܪËd .>XВ8?)]7֭:DO7T8`>Ȉ$O>]+%8>slzӃz~J*TRBOFh:?f xx tv0+q=is5*^!E؂J*TRJ*\r˗.\pPOI\x K8 aVjQIhK/WH_ S ̈́4x*U hn\r˗.\rJ?=wGpwD1Ae7 S`@:?s5~?O8zL\''<'A7 4 ?giZe:: `4xt(MOܶv/.;,w3$PIeH.O`Ex@9E0P@Q  +A#t5Pk`C04ya3g& ~" e\Kİ8$ =EMg i1W AH4ѷ >C՚(:?k¥ ^5aCQh~ޓNf:F׫= ObWtS4>ĸDhR*)R^+ƥrl[/l~ 8@l-|}OH/0v~NYTh0nsgH&ylrol\[-ez6l^|xZ܎̿|3u V&<1㉏LLx ):S?'ҡdo9sα PZ\lmЃ JR5mob _'yl~ +^AZMW7]~KG98uܻyu|_{J}ÍVÃ[]r˗.\r˗.:p MQZ`{PWc|WDQN\r˖K.\drrWJ_C `h,?;4{"\J_4xE)\S(ax:j<*#32KENJ'Mo{4e{نR}^@)3uc4Zoz%b'%9 |&p~ohz GW/v_waDKNr3,CS#(ʇ' j`*8Bsޙ[Qu>w /_>e}v1\<;))IU.\zxbW ՘6RS] $*520]9L+}cVyt}Ux;ۡwh~ xRΛ_ǬofྦྷT,R6v_brfXrx-[ %J|b۰"-AYX__}n_t_QD*=TïG(WGD<)85"Yv"ex%݂iI4}N~y7]zpTy;@ \7iiX=JWǀ\BvYtKWwBT}Кz~#&ϧ5eH.O`Ey@9E0P@BQ N +AS_N~,:¢i:35)~ 3333333PƽKxhS Oduba)5}9BQ.joe&ffMf Č>R< K~m2;JOcm=~&}u9*ca4oٷi`zuegx5YQD&f |fy?!Rh^.Qy?-}9{Y~;{:5aaXlt_ĻCXt/ c ziؕevSWD611/t{& ѥ74>{l+111111111111111111TfT՚:|>.p䎭t[N77Ѥnonc3n6y:,#u0R=^8jt\4YS+螜|)>w˼m7999^ 0=WƜXh=He/ L9VJYZJoa6(X`+S{5?~#G^DKhN?a ta'@ if1eHu.O`Ez@9E0P@Q x +Ao&y9˯)QDzOQ׫WGI p.x/2pCA`3@~:uF~<>_'Bkt SKj^}ƛOCc-mCG zq`Mg?c`NXo޲\GF,@>nX! Ht8rl5zg#\M6vbZ)v]198 c|u4ZTr|BڞHI?0~U=\ߧb9ل&uҶh뀼5MQaˉ[=##BpFgýv9E'ԡCΧU B^_#E=M X6+[3nD*]E5x FP+,Xk E*ilG6=Huj c.K>]௒mi3_RZZNUVB;W{q4]KjPLeo XkW\m`>ey'am6BzwJ2=s˗KfxIij~GzECbeo' TX4y^u/EX=aY|_xX=DbV}Q(o`R0^ /O?(kW*~I,`F)iˠ:hTCy98"Zݔh5?Ok.$TNŖB.Zjz}:dWXbR齮ZM^M=ȍ*s ?D覫GMQ!;"xXBBe^[amM/0&L3<Oql7U b3Ř<8~b8jF]>wnGm\m&+bxEy1- L?37EZ6uӝ2mW1.<u|t83tBz(i..LQ? zr%?~ߩh4\>u~s:2!Cշ;+|ꤻ3_H8]%U֎Xԅ{!؂[ӷ5zZ`ħ":}o|@7 {Nz2#;by/vpw@{yV7zOvk~Ccnkݍ[٭߱Aw =5QUXfMc&S\S-SXx~EUK x3$eH.O`E{@9E0P@*Q " +A j/hߓ~ΟQ[T&-/ L}MC}%4|":ΛKC1`J&0/ zG_a/(jzsЯHшt{M7yNh5zGB2=i+ r%Alf-DBOz@u-ps#O&cO9? 0jfdױ(5^oλ!~yHnk!nn \mfqB =?oytDB;Ku"S^4J*0:L_>f~y~Xd"}8~thdaRΥapBe_EWuv!By:˰}]R+kH?>+1*Q:%J+!) 9nbWffeLacT Xt~"w` >c{/v1@Xhw/kht;^~rhf>q~Ɇ+> ]1_nG@>[~uH6K7bTT1~eĕ4]$MҥL釣4n,DPb:u93Fu>ϱBwe n;m^z unzk"=(E5ŕBjvV."ڃåG:)so#wi׷>_us*9%x6u'=Y2- (fjkkWH>yJ^Jƾk.ϣrtݻ=/}i06`,ׇO3c+$TŲ]$j: lcL4R +-tv="1-+kXzߏ/;w?b4>byz+_OýVyY|tm6 y_t:m;}?:K~Yo~ 4__9?Ϙ(P-zMS{ړ0+/@Cf׾J["kQ5лǑY{J5\,aZ , 0!m`B#;kiVT9Q5e*Tu3ktnXxYK`uch`1*z7S唡{+u>9: |2w'SSӓ*uւYe tҋPB`Z@Z:"iUcXtLRb ejc( l+(ڥSFldk; 1(( VY ʔI)l{ ]J^%< ^Q̼b!&ӭ(SzΤ=7}'Zu|3q:u'[Nwӣ:q9O?S)x8$gO  6^3nUbV3iSiF Mh@· \V|lT,XT[]#{w{UBKł ؍#eI_a/eU[PV;fqexϯI^':wJ?D`_UJS)4 ÈX0M'?Xԥ"deH .O`E@9E0P@Q ϝ +AIJ~{΁7e4KWܯT;o؋, OzCL@IT 3};p:5Qj%˙ְދYx߽t2e88~%8ujW=o@2ӊϧBWRuƞ%į_WkOܮs޲|ۏG_VΙԧS4i)Mg)|W3]7wYNe)]Fe3\L~$9}'Ƴ{N>No)*5uUQ[RhO{Mju.46OAkIK*2âzDed2˖dO*<Cߣ(-l⊭"Z69FkƍQc ? *:"E]E"Uvֈ/eZF,SBVP` }w"&K(|ἧ>{k)3)?-3cC,ש9soYNe9=ij餧?$'9ƞJzs_;5=>򛧧e<":{ܹr˗._˗.\+PSh݊s>j/= !\C,nZbBXWE UÂv&P;!TgS4v,},/&Z„>6B?2GƬ\17AMrZr/nЊP7sKNY{8qͺZRѝ`:XIDeT*؂jOvMn]4iohA0a Vyiއ![P)(-IBkag Bo9[uw|@סTy8B)+XY4r.TA/@kWN>:Hr{Rdna* *"1:r)Z%cv<@+@:v0xeЈ8/U:IP7n[([5%9333݆3GӔ 'AD:m ok~PU1wnT8aU(ex*p$_BfEmTt`u$%)+J+5o kjVtC(Lձmw4&q>xOƇ^eT]2fnٙOCX";n<m,D6.pS0B& fRӚT:"-?b- 7JϠY$bG,uFd6]IaTx@ uqzj6r2%["1$xؐ X )8tHtn+q].ޱ7EKب6y 'eۄlR)83ǡ5])dM 3:M:kϦs1&کC״IMJ5"NJ 6Jf@8Cq!UL#:=QxhD,eR%:%-pa}Ni n#!g[.[> Ml\ة~H2Kgy NݕCܨKh-^뫦(z&T#8 3^D1H F`\%8>RZ4*im h[UV=Ɇݢ%eH+.O`EЂ@9E0P@VQ & +A^C zHl T'#P̧$|W7D!v4&䢞yfÝY-Pi}9~v<qGo/e%-lۮC'L&Lk2B1113- D%A[:"ZaJ`<".5D V7=4L4늢/IrTX5Q҈#F0+9=ՙ%P G}]{Tм1fOx͂êCq4tF ,:[=H͉d(]ApW @%|ֹf%ZSDg4֎\o\0RDZ+e1>DCpK6Y'Z! "VPV?|k`dUh%ș Y(C-׉ _۔Y*W20"8uX_1@J l4J-j!Urۄ7@|Kd+Ji`BܴRAIh/k:f*a,zZ`Cؐ4miA4z)hflm 9dpI@@KnQt1_N@DB/tt ^*B*1(m"ڥe:&~%eEQdA0{0.sr-<#:xkz>Uo ZF].Ʌ#` *[|MҠ͋ ~ ;ʽs^*צ& SyRGYZD秾{bV0Ĝ0R#h(6U*˦t`@"Xn/A:ȌHꋣ.qc8U*Q°Gu8*4܆@,BPL2&yZDoVm>[v = yRl4Z^ED1^&ΰƙإn^5{ƍ\Eòl/i-9 QfYབྷXsO1bm&q*%omJgb1h #y{fuBM"=R *oT`d,"r] S@Y1L:;Tu_ K6ol\mW?;YǛ~%N&&HzIu\Aft6PPŗ$,EjiVRש9 kA88 :BBڲ&|ҁf zq. YUހ!vЍeH4.O`EЃ@9E0P@Q fQ +AֶCh5t^b+".V+D @Ch$n)ɩêG`)c n20.%BQ@Fl9t܊Al{޸3#^TcUk~Vh`v 0B#fH x7R{=s̢!%LLs<5sQuY٬X^nks8ӯ ޶w[?>3;ݵoC_Ym:ֱ[rώ-U5kzLS]e0̲&|B3-V%ֵz՗P:Ql8קSX\F,FX/QƔ쏦cuq#"!4NDKӬ̪V֝W/.߄XAFu)RjU ѠXGj ]X<IdhooDr&Og'Y&tG lQ_Q>)IjRX:fYRXT4ɤ)a:1bczGZwu۩mUQڊY|w?_y 'Ț#8Iպ meHX=.O`EЄ@9E0P@">Q - +A:gg,[@B>Yxˬ(l)Ͽ#b#S_=#\A 8~1[uw6Kit09 \ 0.Y^ό2en;'uun`;nM[z9&D\>`jOG'%^-TZ6 .3{ku~5+n\d)85:#;GD󈰞e&}5 `5 vH[1Vi}a[]%/7[Bi}PƢK"%iFsP.I8TME]cƳ%%Q}pzg#ӧMωF%Aq/5/WyRԻN[s\jqI-*l4q4q,"apg>-`@c}!#z1D4/wJH*mnSW8apcLl{߀TBBWnۈsQzY@23KUt6d.Ƽ*TS)ktʅo]tueɩs!T$Jcߡ\(W`],s羽@lsaZ~m2?y/O>[Lm e>WkC.=o w/P_wh_z5}%9/`UFZTzqm{.o8twpAh0ұ|]E4ϐiNA:K{DMe1oymv-WĦh'H:C&4U6ʄw@ZTb(G&xUx%mGSp)A{gd):%\ QDP]+ŔE(i"D5%Nh`%%0IoxgRkIilJ4)-"@}!T&YG@DaѶ,{fu%)ĤycS,#Hk;EDwmw LUs-u&:δNxF(ٯ R3HIRzςSC;(@`0MSDj&`>Qt4S:WxԦSɝY`(J&/+0ޕohҺ&58Jk(g3.f̭Y6+WTskr)2,eH.O`EЅ@9E0P@'Q _: +ACYi]rA5`n|V0;%%HKݧq 0%9Q[M)̈́zq,|f.Y%* @RzGLȅֶtBb2nj59 ZE#q=RU7s+WT]S=RWTJzPz0Ma,ސRXK6 c' ML 0y7BhfEUzAIa+p/."^e: &F_/C.qTWv]ׅ^xV4GGtVN+m44kpR\\r -.r 4%T6P6 ca_c EKJfmtfia`1W/zv,o9T(뿃¿xT  +)+))rk~h e 5n:ղ:׸]QSjC|$ayl>M}? g宨ڽؘ#/X+++WIVWŔ+%OtӺwN;t_O |7ieq_m,wN;tӺwN;tӺwN;u{̝e.KLw?p^7VNxΐy> V 大j*8U^qRfEq^ --{L 󬹞as;Bv7b7άVLܡ}M),V .4cyR^A/GLAŮzjǷ]W QZ@%ycH4zE4-ŐnXi`v OS: \S B;XKΐ:m.VnvfHH9`0mDes73o(zJk](̎f?gZ9ihWG6.=[; #W=OXz!B #"T[5Q]V2ղ[ h#-Kê +]?k{Rŭ.rGQ)ݗ xg\PQM-w(Թ(zbTd4-K˗E4B-Je;˘ XhW8ӉNK;N1^.2yb*Y=1覈Eu^yueXj4p!| KyI#e["ì:)xDxE_fv,Keyy>* w&Yk7XCk7a%.1ֈneVE|6׸AyPrygQeiYƿKk`b{:: seHj.O`EІ@9E0P@-&Q _ l+A^0u= ށG[{O:W^gzH1 evzK}f,3p12cjF,a^[u61̴*bۿNC{SJ48D'GgĻ@}\Q65bͺZǠ.4tԪ=^@-bGbg2Ļt{bV}#)Ûݘ{J6]>u72w+2y%V3,uFˮLi~bd Ser 58}M_ƻAtWUVUWūܶJi$7pg{tZCT7`|wZy`@1zX4\vSlOE8(Qxu: w4A|E ŗƿgYiɮـЂ^x | ~Oz \_̪v.^/,U?)wު~19_ig\1|j|-oe{7>5Wb|^o=8웳>1-8N&M8?a~[y>m%q|2pu`1^]ͱ??SuPfPZ-T(U89s6v/'|K:|2 Vmf^騔Y!䍖izzzzzzzzz)-6^] EA7MPR )J3=PXcA Pp{aUpNAUX#z1,XH7b0Fv] umAzsꞩꞩꞩꞩꞩꞩꞩꞩꞯzؾU~( eYп-UDGW4 <mj l)v*9@!@dðѱ( v5Lqvaf8KY뱇q;x`D}С0<:^UiD\h6.ek6FH2n4 `?EƇ5G,[0MPTi.Γ4(,KVOhQĢQģG1"eH0r.O`EЇ@9E0P@2Q # l+A%J%J8%J8q(b=jºt=NjPsX/}@a74 ²HB-} )am6XQ(X@kp,EqeB("%I*aR-QIPPFTpD( =j: L֕3t}N:(q(QģDG%%%J8Al)G0J@Z)WP4Cy`֋@,jXR $&w>RW=+6( BP@{wX+Z@%UzEнo6K)CGQHwu-kouq 5:?ok$FFR uccC$ˆ Xij(8b pB`[1z9OzV]]Yz]IL-a&p krPh]5ł#t'DK!A[VnZ ߝ=2c!ZT)aSQ oG0ȌϤt~WBT!`k0\֤;"ڍ c떪[cű e_M¬< tp7B>Xj&ntC0vشh,F]q rS|-LְI(CF/kD_o%b.5)k&T_s[X b ;Lhյ͍^7W\94j#k.\r˗.&;nzLV]#ܦяMx"~>a_m5 Ԓ2 8c \B͵~d^heF7] :MZ<z[xŎCET7c(qRQ>U_,RDRV\r˗.\r2XPZ%Ju kyQFVG-?`-st_,/z8i= OZZ\0e 71-*(9\oG5q0̦D3 3%1,Sޘnp!%ba5/@Ut1r} @&@݃}D }DMe5 .ɤXto(^ ؞W1Wg?;]B' eLcowDw7ioڶ4QB @[,@ 7 * {73Gf!P}E 83X: {/F$xaeH{.O`EЈ@9E0P@8Q >% l+A5D/=lXkIk RʛWUh=ķeУM7f&CK*d`QZ#@Y؊Z :&#ό*Qvb<eLņM;ܵ2+77ڝAn&ἛԼr@ix@e^L_].#GRFԁA .XoFDň7+s=lڷ;Vzo١+N?j_Trh>$>5 mg1 CnNM:Ph^DJar> pQR{CHl40Z QX<#c5ezãP0/b\^j7H+=V)E,-Vwtǃɻ=DQ(J%D‰K?+hk>SO`v'J!DQ(((J%DQ(Q( 'BW !`7Z{ PA4""9> P \U]!ErP`Z=l$Dn^)xvV. yh __:Ss j%u@DY4Ţꏱkư)AGl_>k/|]4E CdDMo?%GYb~P~4%9wtvUG3!CP|ò*TTal&lФUu:??W5[\ǏOGE" ؖJXhѳ"QA#z{i6{3>_kI5Y6 6!koz̅L"VqQ> xׂEܠJ" Q(Q(aj$ƄWSX-T؁-R;CB, 4&H&F-25f4 VpVq9֯/f7 V5fLqCPu0 "@f'o -TSS4uo((Q %DQw(@ DQ)J?ϑsg=<.!8D41[A8BjVFе)h=e2&rD~s%gDnM}!\d WT7&4JOh%R@6à ]7Ol$bKvp ѶPt ,bW9YgAzkl yi 2mv :mWr,Ur@4GuIc"R -A^^#[#冐ppCNTZ46p-UBUrUEQ4 lE@ gF^?yQ$MeH.O`EЉ@9E0P@=Q  n+AEg7x-^Ɔ#`+W.\r˗.\r<0QuZ㗣f#5r{%˗.\r˗.\r˗ܺL=̧Q2U>hN_Upf;sOW8~__f`By^Zhjjhc1%/>JwTzrjQR!,ApWJ?3fgϟYk/fľk`jJ-@W@pLI->w|]L7>z s r>_|t'6[Yn꣢ޛ>a)v}vHQlpqX!2fgiCN6 ^TmߋֆoջGfň^V{#Q3ŒJ…L%8'X9"IdW#9VH1h*U]ӡrEmr/:Ŝp_Hl-<,STO>h CVn2b62{:9!Ni]u9_vײ4BguD4KC6X6y{`kvң߇>SGQgicd>@HL06FmJJ+[@ h)MUvj܋Mzi.d1'C`>%eK.1ƺJ>, FC*Vd`(٩rX^ڮEY ^K3/6KJ*~OQAASFhF:Ɨix[zz Wb|0@z0mJ^q{_֒,h%-L#q[5N켪@mP]xS)&~Z"ϻLaWBኀ_`u+֠?ag~ V!q]7EUmfZ:e`ÎeH::.O`E(Њ@9NE0P@BQ  n+A:G_GGxPuvu6IP:kpVkkq-|xM:C?N8;~\ X}"2kZTN{?7/8iiY=ghgGg%y/w3{LU +9Rsh R9OQ t jq+7fi#e5EځtY` d8@PrIk#؀cv oDZ][(bW--S9ֽ""X7Z1_ Tߞvvz:g5߰c25`ZUb)q-U,;m"穨>Ag\X(hT9`30/ zD) zPYět3])uejmi͑w4.6;Z|Q@7X,#8M8rOQ#} vbRy&Tb-gSՆ[I莣0ntȷΉ,X*qV./3u/«0*m,ZRg¼33333㙘2+wknD$X)mEUFS%~k2'8RJm; =l5Spu[eEhkLHd@NP NA[*!R'sM;d0GiTmOQͽC]ɜ9ܖݞ=u/v:'QNd믿 GԤ@겔.ׇ@a F7/ j$*EVskw}էvFrn'L.L]Im= Lo]siܞ*yo쓬/MuR.ZʽتIFw|nsg3ؼq7 2g)՚uN0yGG<{ =iqw_؀eHFF.O`E4Ћ@9AE0P@FQ x +A8M#eHza.O`EЌ@9E0P@-&Q ] e+A^0u= ށG[{O:W^gzH1 evzK}f,3p12cjF,a^[u61̴*bۿNC{SJ48D'GgĻ@}\Q65bͺZǠ.4tԪ=^@-bGbg2Ļt{bV}#)Ûݘ{J6]>u72w+2y%V3,uFˮLi~bd Ser 58}M_ƻAtWUVUWūܶJi$7pg{tZCT7`|wZy`@1zX4\vSlOE8(Qxu: w4A|E ŗƿgYiɮـЂ^x | ~Oz \_̪v.^/,U?)wު~19_ig\1|j|-oe{7>5Wb|^o=8웳>1-8N&M8?a~[y>m%q|2pu`1^]ͱ??SuPfPZ-T(U89s6v/'|K:|2 Vmf^騔Y!䍖izzzzzzzzz)-6^] EA7MPR )J3=PXcA Pp{aUpNAUX#z1,XH7b0Fv] umAzsꞩꞩꞩꞩꞩꞩꞩꞩꞯzؾU~( eYп-UDGW4 <mj l)v*9@!@dðѱ( v5Lqvaf8KY뱇q;x`D}С0<:^UiD\h6.ek6FH2n4 `?EƇ5G,[0MPTi.Γ4(,KVOhQĢQģGeHfu.O`EЍ@9E0P@-&Q Y +A^0u= ށG[{O:W^gzH1 evzK}f,3p12cjF,a^[u61̴*bۿNC{SJ48D'GgĻ@}\Q65bͺZǠ.4tԪ=^@-bGbg2Ļt{bV}#)Ûݘ{J6]>u72w+2y%V3,uFˮLi~bd Ser 58}M_ƻAtWUVUWūܶJi$7pg{tZCT7`|wZy`@1zX4\vSlOE8(Qxu: w4A|E ŗƿgYiɮـЂ^x | ~Oz \_̪v.^/,U?)wު~19_ig\1|j|-oe{7>5Wb|^o=8웳>1-8N&M8?a~[y>m%q|2pu`1^]ͱ??SuPfPZ-T(U89s6v/'|K:|2 Vmf^騔Y!䍖izzzzzzzzz)-6^] EA7MPR )J3=PXcA Pp{aUpNAUX#z1,XH7b0Fv] umAzsꞩꞩꞩꞩꞩꞩꞩꞩꞯzؾU~( eYп-UDGW4 <mj l)v*9@!@dðѱ( v5Lqvaf8KY뱇q;x`D}С0<:^UiD\h6.ek6FH2n4 `?EƇ5G,[0MPTi.Γ4(,KVOhQĢQģGteH?.O`EЎ@9E0P@-&Q R i+A^0u= ށG[{O:W^gzH1 evzK}f,3p12cjF,a^[u61̴*bۿNC{SJ48D'GgĻ@}\Q65bͺZǠ.4tԪ=^@-bGbg2Ļt{bV}#)Ûݘ{J6]>u72w+2y%V3,uFˮLi~bd Ser 58}M_ƻAtWUVUWūܶJi$7pg{tZCT7`|wZy`@1zX4\vSlOE8(Qxu: w4A|E ŗƿgYiɮـЂ^x | ~Oz \_̪v.^/,U?)wު~19_ig\1|j|-oe{7>5Wb|^o=8웳>1-8N&M8?a~[y>m%q|2pu`1^]ͱ??SuPfPZ-T(U89s6v/'|K:|2 Vmf^騔Y!䍖izzzzzzzzz)-6^] EA7MPR )J3=PXcA Pp{aUpNAUX#z1,XH7b0Fv] umAzsꞩꞩꞩꞩꞩꞩꞩꞩꞯzؾU~( eYп-UDGW4 <mj l)v*9@!@dðѱ( v5Lqvaf8KY뱇q;x`D}С0<:^UiD\h6.ek6FH2n4 `?EƇ5G,[0MPTi.Γ4(,KVOhQĢQģG>-ڕeHl.O`EЏ@9E0P@-&Q C +A^0u= ށG[{O:W^gzH1 evzK}f,3p12cjF,a^[u61̴*bۿNC{SJ48D'GgĻ@}\Q65bͺZǠ.4tԪ=^@-bGbg2Ļt{bV}#)Ûݘ{J6]>u72w+2y%V3,uFˮLi~bd Ser 58}M_ƻAtWUVUWūܶJi$7pg{tZCT7`|wZy`@1zX4\vSlOE8(Qxu: w4A|E ŗƿgYiɮـЂ^x | ~Oz \_̪v.^/,U?)wު~19_ig\1|j|-oe{7>5Wb|^o=8웳>1-8N&M8?a~[y>m%q|2pu`1^]ͱ??SuPfPZ-T(U89s6v/'|K:|2 Vmf^騔Y!䍖izzzzzzzzz)-6^] EA7MPR )J3=PXcA Pp{aUpNAUX#z1,XH7b0Fv] umAzsꞩꞩꞩꞩꞩꞩꞩꞩꞯzؾU~( eYп-UDGW4 <mj l)v*9@!@dðѱ( v5Lqvaf8KY뱇q;x`D}С0<:^UiD\h6.ek6FH2n4 `?EƇ5G,[0MPTi.Γ4(,KVOhQĢQģG^eH.O`EА@9E0P@-&Q & y+A^0u= ށG[{O:W^gzH1 evzK}f,3p12cjF,a^[u61̴*bۿNC{SJ48D'GgĻ@}\Q65bͺZǠ.4tԪ=^@-bGbg2Ļt{bV}#)Ûݘ{J6]>u72w+2y%V3,uFˮLi~bd Ser 58}M_ƻAtWUVUWūܶJi$7pg{tZCT7`|wZy`@1zX4\vSlOE8(Qxu: w4A|E ŗƿgYiɮـЂ^x | ~Oz \_̪v.^/,U?)wު~19_ig\1|j|-oe{7>5Wb|^o=8웳>1-8N&M8?a~[y>m%q|2pu`1^]ͱ??SuPfPZ-T(U89s6v/'|K:|2 Vmf^騔Y!䍖izzzzzzzzz)-6^] EA7MPR )J3=PXcA Pp{aUpNAUX#z1,XH7b0Fv] umAzsꞩꞩꞩꞩꞩꞩꞩꞩꞯzؾU~( eYп-UDGW4 <mj l)v*9@!@dðѱ( v5Lqvaf8KY뱇q;x`D}С0<:^UiD\h6.ek6FH2n4 `?EƇ5G,[0MPTi.Γ4(,KVOhQĢQģG)tcpflow-tcpflow-1.6.1/tests/bug3.pcap000066400000000000000000001456721401360461700175410ustar00rootroot00000000000000ò>H@@.OakhE,tAv@P{Ř`@|O.>Hٽ@@.OakhE(&@-Av@P|řJP T{>H.OakhE'@-[Av@P|řJP uHTTP/1.1 200 OK Date: Tue, 22 Jul 2008 01:59:37 GMT Server: Apache Cache-Control: no-cache Pragma: no-cache Vary: Accept-Encoding Transfer-Encoding: chunked Content-Type: text/html;charset=ISO-8859-1 2066 Pacific Grove Weather Forecast and Conditions California (93950) var css='style_sheet.css?01272008';if(typeof(pageType)!="undefined"&&pageType=="920"){css="global.css?01272008";} if(typeof(usingGrids)!="undefined"&&usingGrids=="yes"){css="global_grids.css?01272008";} document.write(''); 368a

    Home Travel Driving & Traffic Healthy Living Home & Family Sports & Recreation Climate & Green The Weather Channel TV