From: Victor Julien Date: Mon, 15 Jul 2013 10:20:46 +0000 (+0200) Subject: libhtp: remove libhtp from repo X-Git-Tag: suricata-2.0beta1~22 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=3599e22e4c0981caf216d6fbd6e83102ab6df789;p=thirdparty%2Fsuricata.git libhtp: remove libhtp from repo --- diff --git a/libhtp/AUTHORS b/libhtp/AUTHORS deleted file mode 100644 index 769b9a2506..0000000000 --- a/libhtp/AUTHORS +++ /dev/null @@ -1 +0,0 @@ -Ivan Ristic diff --git a/libhtp/COPYING b/libhtp/COPYING deleted file mode 100644 index 64bc050eb2..0000000000 --- a/libhtp/COPYING +++ /dev/null @@ -1,13 +0,0 @@ -/* - * LibHTP (http://www.libhtp.org) - * Copyright 2009,2010 Ivan Ristic - * - * LibHTP is an open source product, released under terms of the General Public Licence - * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text - * of the license. - * - * In addition, there is a special exception that allows LibHTP to be freely - * used with any OSI-approved open source licence. Please refer to the file - * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. - * - */ \ No newline at end of file diff --git a/libhtp/ChangeLog b/libhtp/ChangeLog deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/libhtp/LIBHTP_LICENSING_EXCEPTION b/libhtp/LIBHTP_LICENSING_EXCEPTION deleted file mode 100644 index 815af7b087..0000000000 --- a/libhtp/LIBHTP_LICENSING_EXCEPTION +++ /dev/null @@ -1,120 +0,0 @@ - -LIBHTP LICENSING EXCEPTION -=============================== - -Version 1.0, 6 January 2010 - -As a special exception ("Exception") to the terms and conditions of version 2 -of the GPL, Ivan Ristic hereby grants you the rights described below, provided -you agree to the terms and conditions in this Exception, including its -obligations and restrictions on use. - - -Exception Intent -================ - -We want specified Free/Libre and Open Source Software ("FLOSS") programs to be -able to use LibHTP (the "Program") despite the fact that not all FLOSS -licenses are compatible with version 2 of the GNU General Public License (the -"GPLv2"). - - -Legal Terms and Conditions -========================== - -You are free to distribute a Derivative Work that is formed entirely from the -Program and one or more works (each, a "FLOSS Work") licensed under one or -more of the licenses listed below in section 1, as long as all of the -following conditions are met: - - 1. You obey the GPLv2 in all respects for the Program and the Derivative - Work, except for identifiable sections of the Derivative Work which are - - 1. not derived from the Program, and - - 2. are not designed to interact with the Program, and - - 3. which can reasonably be considered independent and separate works in - themselves. - - 2. All such identifiable sections of the Derivative Work are - - 1. distributed subject to one of the FLOSS licenses listed below, and - - 2. the object code or executable form of those sections are accompanied - by the complete corresponding machine-readable source code for those - sections on the same medium and under the same FLOSS license as the - corresponding object code or executable forms of those sections. - - 3. Any works which are aggregated with the Program or with a Derivative Work - on a volume of a storage or distribution medium in accordance with the - GPLv2, can reasonably be considered independent and separate works in - themselves which are not derivatives of either the Program, a Derivative - Work or a FLOSS Work, and are not designed to interact with the Program. - -If the above conditions are not met, then the Program may only be copied, -modified, distributed or used under the terms and conditions of the GPLv2 -or another valid licensing option from Ivan Ristic. - - -FLOSS License List -================== - -License name Version(s)/Copyright Date ------------------------------------------------------------------------ -Academic Free License 2.0 -Apache Software License 1.0/1.1/2.0 -Apple Public Source License 2.0 -Artistic license From Perl 5.8.0 -BSD license "July 22 1999" -Common Development and Distribution License (CDDL) 1.0 -Common Public License 1.0 -Eclipse Public License 1.0 -GNU Library or "Lesser" General Public License (LGPL) 2.0/2.1/3.0 -Jabber Open Source License 1.0 -MIT License (As listed in file MIT-License.txt) - -Mozilla Public License (MPL) 1.0/1.1 -Open Software License 2.0 -OpenSSL license (with original SSLeay license) "2003" ("1998") -PHP License 3.0 -Python license (CNRI Python License) - -Python Software Foundation License 2.1.1 -Sleepycat License "1999" -University of Illinois/NCSA Open Source License - -W3C License "2001" -X11 License "2001" -Zlib/libpng License - -Zope Public License 2.0 - -Due to the many variants of some of the above licenses, we require that for -any version of the listed FLOSS licenses to qualify under this exception, it -must follow the 2003 version of the Free Software Foundation's Free Software -Definition (http://www.gnu.org/philosophy/free-sw.html) or version 1.9 of the -Open Source Definition by the Open Source Initiative -(http://www.opensource.org/docs/definition.php). - - -Definitions -=========== - -1. Terms used, but not defined, herein shall have the meaning provided in the - version 2 of the GPL. - -2. Derivative Work means a derivative work under copyright law. - - -Applicability -============= - -This Exception applies to all Programs that contain a notice placed by Ivan -Ristic saying that the Program may be distributed under the terms of -this Exception. If you create or distribute a work which is a Derivative Work -of both the Program and any other work licensed under the GPL, then this FLOSS -Exception is not available for that work; thus, you must remove the FLOSS -Exception notice from that work and comply with the GPL in all respects, -including by retaining all GPL notices. - -You may choose to redistribute a copy of the Program exclusively under the -terms of the GPLv2 by removing the Exception notice from that copy of the -Program, provided that the copy has never been modified by you or any third -party. diff --git a/libhtp/LICENSE b/libhtp/LICENSE deleted file mode 100644 index 0cd26d5b96..0000000000 --- a/libhtp/LICENSE +++ /dev/null @@ -1,281 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Library General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - diff --git a/libhtp/Makefile.am b/libhtp/Makefile.am deleted file mode 100644 index 8ff13fa7ab..0000000000 --- a/libhtp/Makefile.am +++ /dev/null @@ -1,8 +0,0 @@ - -SUBDIRS= $(GENERIC_LIBRARY_NAME) test - -DIST_SUBDIRS = $(GENERIC_LIBRARY_NAME) test - -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = htp.pc - diff --git a/libhtp/NEWS b/libhtp/NEWS deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/libhtp/README b/libhtp/README deleted file mode 100644 index cbde65e994..0000000000 --- a/libhtp/README +++ /dev/null @@ -1,103 +0,0 @@ - -LibHTP (http://www.libhtp.org) -Copyright 2009,2010 Ivan Ristic -====================================================== - -LibHTP is a security-aware parser for the HTTP protocol and the related bits -and pieces. The goals of the project, in the order of importance, are as -follows: - - 1. Completeness of coverage; LibHTP must be able to parse virtually all - traffic that is found in practice. - - 2. Permissive parsing; LibHTP must never fail to parse a stream that would - be parsed by some other web server. - - 3. Awareness of evasion techniques; LibHTP must be able to detect and - effectively deal with various evasion techniques, producing, where - practical, identical or practically identical results as the web - server processing the same traffic stream. - - 4. Performance; The performance must be adequate for the desired tasks. - Completeness and security are often detremental to performance. Our - idea of handling the conflicting requirements is to put the library - user in control, allowing him to choose the most desired library - characteristic. - - | IMPORTANT LIBHTP IS NOT YET CONSIDERED STABLE. USE AT YOUR OWN RISK. DO NOT - | USE IN PRODUCTION. WORK IS CURRENTLY UNDER WAY TO ENSURE THAT - | LIBHTP IS SECURE AND THAT IT PERFORMS WELL. - - | STATUS LIBHTP IS VERY YOUNG AT THIS POINT. IT WILL BE SOME TIME BEFORE - | IT CAN BE CONSIDER COMPLETE. AT THE MOMENT, THE FOCUS OF DEVELOPMENT - | IS ON ACHIEVING THE FIRST TWO GOALS. - -LibHTP is an open source product, released under terms of the General Public Licence -version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text -of the license. - -In addition, there is a special exception that allows LibHTP to be freely -used with any OSI-approved open source licence. Please refer to the file -LIBHTP_LICENSING_EXCEPTION for the full text of the exception. - - -INSTALLATION ------------- - -The installation process should be as simple as: - - $ ./configure - $ make - # make install - - | NOTE If you already have an early 0.2.x version installed, you must - | uninstall it before proceeding. Initially /usr was used for the - | installation, but /usr/local is used now. If you forgot to uninstall, - | clean all traces of LibHTP from /usr/lib/libhtp* and /usr/include/htp/*. - -If you want to use a repository version of LibHTP, do the following: - - 1. Use svn export to retrieve the sources of the version you wish to use - - 2. Run ./update_version, which will update htp.c with the latest Subversion - revision used - - 3. You may wish to also update htp.pc.in and configure.ac with the correct version - - 4. Run autoconf -i --force, which will prepare the library for installation - - 5. Run doxygen to generate the API documentation - - 6. Continue to install as described above - - -DOCUMENTATION -------------- - -The best documentation at this time is the code itself and the Doxygen output (which -should be all right). There's also a quick start guide in the doc/ folder, which -should give you enough information to get going. - - -NO WARRANTY ------------ - - BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. diff --git a/libhtp/configure.ac b/libhtp/configure.ac deleted file mode 100644 index 8519fef6a0..0000000000 --- a/libhtp/configure.ac +++ /dev/null @@ -1,137 +0,0 @@ - -dnl ---------------------- -dnl Initialization macros -dnl ---------------------- - -AC_INIT(htp/htp.h) -AC_CONFIG_HEADERS([config.h]) - - -dnl ----------------------------------------------- -dnl Package name and version number (user defined) -dnl ----------------------------------------------- - -GENERIC_LIBRARY_NAME=htp - -GENERIC_MAJOR_VERSION=0 -GENERIC_MINOR_VERSION=2 -GENERIC_MICRO_VERSION=12 - -# API version (often = GENERIC_MAJOR_VERSION.GENERIC_MINOR_VERSION) -GENERIC_API_VERSION=1.0 -AC_SUBST(GENERIC_API_VERSION) - -# Shared library versioning -GENERIC_LIBRARY_VERSION=1:2:0 -# | | | -# +------+ | +---+ -# | | | -# current:revision:age -# | | | -# | | +- increment if interfaces have been added -# | | set to zero if interfaces have been removed -# or changed -# | +- increment if source code has changed -# | set to zero if current is incremented -# +- increment if interfaces have been added, removed or changed - - -dnl -------------------------------- -dnl Package name and version number -dnl -------------------------------- - -AC_SUBST(GENERIC_LIBRARY_VERSION) - -PACKAGE=$GENERIC_LIBRARY_NAME -AC_SUBST(GENERIC_LIBRARY_NAME) - -GENERIC_VERSION=$GENERIC_MAJOR_VERSION.$GENERIC_MINOR_VERSION.$GENERIC_MICRO_VERSION -GENERIC_RELEASE=$GENERIC_MAJOR_VERSION.$GENERIC_MINOR_VERSION -AC_SUBST(GENERIC_RELEASE) -AC_SUBST(GENERIC_VERSION) - -VERSION=$GENERIC_VERSION - -AM_INIT_AUTOMAKE($PACKAGE, $VERSION, no-define) - -AC_CONFIG_MACRO_DIR([m4]) - -AC_ARG_ENABLE(htp-debug, [ --enable-htp-debug Enable debug output], [ enable_htp_debug=yes ]) -if test "$enable_htp_debug" = "yes"; then - CFLAGS="${CFLAGS} -DHTP_DEBUG" - echo "Debug mode enabled" -fi - -dnl ----------------------------------------------- -dnl Checks for programs. -dnl ----------------------------------------------- - -AC_PROG_CC -AM_PROG_LIBTOOL -AM_SANITY_CHECK - -dnl ----------------------------------------------- -dnl Checks for libs. -dnl ----------------------------------------------- -AC_CHECK_HEADER(zlib.h,,[AC_ERROR(zlib.h not found ...)]) -ZLIB="" -AC_CHECK_LIB(z, inflate,, ZLIB="no") -if test "$ZLIB" = "no"; then - echo - echo " ERROR! zlib library not found" - echo - exit 1 -fi - -dnl ----------------------------------------------- -dnl provides a read-only relocation table area in the final ELF -dnl ----------------------------------------------- -AC_MSG_CHECKING(for -z relro) -TMPLDFLAGS="${LDFLAGS}" -LDFLAGS="${LDFLAGS} -z relro" -AC_TRY_LINK(,,SECLDFLAGS="${SECLDFLAGS} -z relro" -AC_MSG_RESULT(yes), -AC_MSG_RESULT(no)) -LDFLAGS="${TMPLDFLAGS}" - - -#check for os -AC_MSG_CHECKING([host os]) - -# If no host os was detected, try with uname -if test -z "$host" ; then - host="`uname`" -fi -case "$host" in - *-*-openbsd*) - CFLAGS="${CFLAGS} -fgnu89-inline" - ;; -esac -AC_MSG_RESULT(ok) - - -dnl ----------------------------------------------- -dnl forces all relocations to be resolved at run-time -dnl ----------------------------------------------- -AC_MSG_CHECKING(for -z now) -TMPLDFLAGS="${LDFLAGS}" -LDFLAGS="${LDFLAGS} -z now" -AC_TRY_LINK(,,SECLDFLAGS="${SECLDFLAGS} -z now" -AC_MSG_RESULT(yes), -AC_MSG_RESULT(no)) -LDFLAGS="${TMPLDFLAGS}" - -CFLAGS="${CFLAGS} ${SECCFLAGS}" -LDFLAGS="${LDFLAGS} ${SECLDFLAGS}" - -dnl ----------------------------------------------- -dnl Generates Makefile's, configuration files and scripts -dnl ----------------------------------------------- - -AC_PREFIX_DEFAULT(/usr/local) - -AC_OUTPUT(Makefile \ - htp.pc \ - htp/Makefile \ - test/Makefile -) diff --git a/libhtp/docs/QUICK_START b/libhtp/docs/QUICK_START deleted file mode 100644 index 57dcec7c2a..0000000000 --- a/libhtp/docs/QUICK_START +++ /dev/null @@ -1,102 +0,0 @@ - -QUICK START ------------ - -LibHTP is envisioned to be many things, but the only scenario in which it has been tested -so far is that when you need to parse a duplex HTTP stream which you have obtained by -passively intercepting a communication channel. The assumption is that you have raw TCP data -(after SSL, if SSL is used). - -Every parsing operation needs to follow these steps: - - 1. Configure-time: - - 1.1. Create one or more parser configuration structures. - - 1.2. Tweak the configuration of each parser to match the behaviour of - the server you're intercepting the communication of (htp_config_set_* functions). - - 1.3. Register the parser callbacks you'll need. You will need to use parser callbacks - if you want to monitor parsing events as they occur, and gain access to partial - transaction information. If you are processing data in batch (off-line) you may - simply parse entire streams at a time and only analyze complete transaction data - after the fact. - - If you need to gain access to request and response bodies, your only option at - this time is to use the callbacks, because the parser will not preserve that - information. - - For callback registration, look up the htp_config_register_* functions. - - If your program operates in real-time then it may be desirable to dispose of - the used resources after each transaction is parsed. To do that, you are allowed - to call htp_tx_destroy() at the end of the RESPONSE callback. - - 2. Run-time: - - 2.1. Create a parser instance for every TCP stream you want to process. - - 2.2. Feed the parser inbound and outbound data. - - The parser will typically always consume complete data chunks and return - STREAM_STATE_DATA, which means that you can continue to feed it more data - when you have it. If you have a queue of data chunks, always send the - parsed all the request chunks you have. That will ensure that the parser - never encounters a response for which it had not seen a request. - - If you get STREAM_STATE_ERROR, the parser has encountered a fatal error and - is unable to continue to parse the stream. An error should never happen for - a valid HTTP stream. If you encounter such an error please send me the pcap - file for analysis. - - There is one situation when the parser will not be able to consume a complete - request data chunk, in which case it will return STREAM_STATE_DATA_OTHER. You - will then need to do the following: - - 2.2.1. Remember how many bytes of data were consumed (using - htp_connp_req_data_consumed()). - - 2.2.2. Suspend request parsing until you get some response data. - - 2.2.3. Feed some response data to the parser. - - Note that it is now possible to receive STREAM_STATE_DATA_OTHER - from the response parser. If that happens, you will need to - remember how many bytes were consumed using - htp_connp_res_data_consumed(). - - 2.2.4. After each chunk of response data fed to the parser, attempt - to resume request stream parsing. - - 2.2.5. If you again receive STREAM_STATE_DATA_OTHER go back to 2.2.3. - - 2.2.6. At this point you should feed the parser all the request data - you have accumulated before giving it any response data. This is - necessary to prevent the case of the parser seeing more responses - than requests (which would inevitably result with an error). - - 2.2.7. Send unprocessed response data from 2.2.3 (if any). - - 2.2.8. Continue sending request/response data as normal. - - The above situation should occur very rarely. - - 2.3. Analyze transaction data in callbacks (if any). - - 2.4. Analyze transaction data after an entire TCP stream has been processed. - - 2.4. Destroy parser instance to free up the allocated resources. - - -USER DATA ---------- - -If you're using the callbacks and you need to keep state between invocations, you have two -options: - - 1. Associate one opaque structure with a parser instance, using htp_connp_set_user_data(). - - 2. Associate one opaque structure with a transaction instance, using htp_tx_set_user_data(). - The best place to do this is in a TRANSACTION_START callback. Don't forget to free up - any resources you allocate on per-transaction basis, before you delete each transaction. - diff --git a/libhtp/docs/doxygen.conf b/libhtp/docs/doxygen.conf deleted file mode 100644 index 5493caef61..0000000000 --- a/libhtp/docs/doxygen.conf +++ /dev/null @@ -1,1356 +0,0 @@ -# Doxyfile 1.5.5 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project -# -# All text after a hash (#) is considered a comment and will be ignored -# The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all -# text before the first occurrence of this tag. Doxygen uses libiconv (or the -# iconv built into libc) for the transcoding. See -# http://www.gnu.org/software/libiconv for the list of possible encodings. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -# by quotes) that should identify the project. - -PROJECT_NAME = HTP - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. - -PROJECT_NUMBER = 0.1 - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. - -OUTPUT_DIRECTORY = doxygen/ - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would -# otherwise cause performance problems for the file system. - -CREATE_SUBDIRS = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, -# Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, -# Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish, -# and Ukrainian. - -OUTPUT_LANGUAGE = English - -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" -# "represents" "a" "an" "the" - -ABBREVIATE_BRIEF = - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. - -FULL_PATH_NAMES = YES - -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the -# path to strip. - -STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that -# are normally passed to the compiler using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful is your file systems -# doesn't support long names like on DOS, Mac, or CD-ROM. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like regular Qt-style comments -# (thus requiring an explicit @brief command for a brief description.) - -JAVADOC_AUTOBRIEF = NO - -# If the QT_AUTOBRIEF tag is set to YES then Doxygen will -# interpret the first line (until the first dot) of a Qt-style -# comment as the brief description. If set to NO, the comments -# will behave just like regular Qt-style comments (thus requiring -# an explicit \brief command for a brief description.) - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the DETAILS_AT_TOP tag is set to YES then Doxygen -# will output the detailed description near the top, like JavaDoc. -# If set to NO, the detailed description appears after the member -# documentation. - -DETAILS_AT_TOP = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# re-implements. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will -# be part of the file/class/namespace that contains it. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. - -TAB_SIZE = 8 - -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. - -ALIASES = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list -# of all members will be omitted, etc. - -OPTIMIZE_OUTPUT_FOR_C = YES - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for -# Java. For instance, namespaces will be presented as packages, qualified -# scopes will look different, etc. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources only. Doxygen will then generate output that is more tailored for -# Fortran. - -OPTIMIZE_FOR_FORTRAN = NO - -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for -# VHDL. - -OPTIMIZE_OUTPUT_VHDL = NO - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. - -BUILTIN_STL_SUPPORT = NO - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. - -CPP_CLI_SUPPORT = NO - -# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. -# Doxygen will parse them like normal C++ but will assume all classes use public -# instead of private inheritance when no explicit protection keyword is present. - -SIP_SUPPORT = NO - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. - -DISTRIBUTE_GROUP_DOC = NO - -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using -# the \nosubgrouping command. - -SUBGROUPING = YES - -# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum -# is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically -# be useful for C code in case the coding convention dictates that all compound -# types are typedef'ed and only the typedef is referenced, never the tag name. - -TYPEDEF_HIDES_STRUCT = NO - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES - -EXTRACT_ALL = YES - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. - -EXTRACT_PRIVATE = NO - -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. - -EXTRACT_STATIC = NO - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. - -EXTRACT_LOCAL_CLASSES = YES - -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. -# If set to NO (the default) only methods in the interface are included. - -EXTRACT_LOCAL_METHODS = NO - -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base -# name of the file that contains the anonymous namespace. By default -# anonymous namespace are hidden. - -EXTRACT_ANON_NSPACES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the -# documentation. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the -# function's detailed documentation block. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. - -INTERNAL_DOCS = NO - -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. - -CASE_SENSE_NAMES = YES - -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. - -HIDE_SCOPE_NAMES = NO - -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation -# of that file. - -SHOW_INCLUDE_FILES = YES - -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. - -SORT_MEMBER_DOCS = YES - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in -# declaration order. - -SORT_BRIEF_DOCS = NO - -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the -# hierarchy of group names into alphabetical order. If set to NO (the default) -# the group names will appear in their defined order. - -SORT_GROUP_NAMES = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the -# alphabetical list. - -SORT_BY_SCOPE_NAME = NO - -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo -# commands in the documentation. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting -# \deprecated commands in the documentation. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or define consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and defines in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the -# list will mention the files that were used to generate the documentation. - -SHOW_USED_FILES = YES - -# If the sources in your project are distributed over multiple directories -# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy -# in the documentation. The default is NO. - -SHOW_DIRECTORIES = NO - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command , where is the value of -# the FILE_VERSION_FILTER tag, and is the name of an input file -# provided by doxygen. Whatever the program writes to standard output -# is used as the file version. See the manual for examples. - -FILE_VERSION_FILTER = - -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. - -QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. - -WARNINGS = YES - -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. - -WARN_IF_UNDOCUMENTED = YES - -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that -# don't exist or using markup commands wrongly. - -WARN_IF_DOC_ERROR = YES - -# This WARN_NO_PARAMDOC option can be abled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of -# documentation. - -WARN_NO_PARAMDOC = NO - -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could -# be obtained via FILE_VERSION_FILTER) - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -INPUT = ../htp - -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is -# also the default input encoding. Doxygen uses libiconv (or the iconv built -# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for -# the list of possible encodings. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx -# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 - -FILE_PATTERNS = *.c *.h - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. - -RECURSIVE = NO - -# The EXCLUDE tag can be used to specify files and/or directories that should -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -# directories that are symbolic links (a Unix filesystem feature) are excluded -# from the input. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories -# for example use the pattern */test/* - -EXCLUDE_PATTERNS = - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test - -EXCLUDE_SYMBOLS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - -EXAMPLE_PATTERNS = - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. If FILTER_PATTERNS is specified, this tag will be -# ignored. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER -# is applied to all files. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). - -FILTER_SOURCE_FILES = NO - -#--------------------------------------------------------------------------- -# configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also -# VERBATIM_HEADERS is set to NO. - -SOURCE_BROWSER = NO - -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES (the default) -# then for each documented function all documented -# functions referencing it will be listed. - -REFERENCED_BY_RELATION = NO - -# If the REFERENCES_RELATION tag is set to YES (the default) -# then for each documented function all documented entities -# called/used by that function will be listed. - -REFERENCES_RELATION = NO - -# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) -# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from -# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. Otherwise they will link to the documentstion. - -REFERENCES_LINK_SOURCE = YES - -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You -# will need version 4.8.6 or higher. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. - -VERBATIM_HEADERS = YES - -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. - -ALPHABETICAL_INDEX = NO - -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - -HTML_OUTPUT = ./ - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# stylesheet in the HTML output directory as well, or it will be erased! - -HTML_STYLESHEET = - -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to -# NO a bullet list will be used. - -HTML_ALIGN_MEMBERS = YES - -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) -# of the generated HTML documentation. - -GENERATE_HTMLHELP = NO - -# If the GENERATE_DOCSET tag is set to YES, additional index files -# will be generated that can be used as input for Apple's Xcode 3 -# integrated development environment, introduced with OSX 10.5 (Leopard). -# To create a documentation set, doxygen will generate a Makefile in the -# HTML output directory. Running make will produce the docset in that -# directory and running "make install" will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find -# it at startup. - -GENERATE_DOCSET = NO - -# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the -# feed. A documentation feed provides an umbrella under which multiple -# documentation sets from a single provider (such as a company or product suite) -# can be grouped. - -DOCSET_FEEDNAME = "Doxygen generated docs" - -# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that -# should uniquely identify the documentation set bundle. This should be a -# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen -# will append .docset to the name. - -DOCSET_BUNDLE_ID = org.doxygen.Project - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. For this to work a browser that supports -# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox -# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). - -HTML_DYNAMIC_SECTIONS = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be -# written to the html output directory. - -CHM_FILE = - -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run -# the HTML help compiler on the generated index.hhp. - -HHC_LOCATION = - -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). - -GENERATE_CHI = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the HTML help documentation and to the tree view. - -TOC_EXPAND = NO - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. - -DISABLE_INDEX = NO - -# This tag can be used to set the number of enum values (range [1..20]) -# that doxygen will group on one line in the generated HTML documentation. - -ENUM_VALUES_PER_LINE = 4 - -# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be -# generated containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, -# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are -# probably better off using the HTML help feature. - -GENERATE_TREEVIEW = NO - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. - -TREEVIEW_WIDTH = 250 - -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - -GENERATE_LATEX = NO - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - -LATEX_OUTPUT = latex - -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be -# invoked. If left blank `latex' will be used as the default command name. - -LATEX_CMD_NAME = latex - -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the -# default command name. - -MAKEINDEX_CMD_NAME = makeindex - -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_LATEX = NO - -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, a4wide, letter, legal and -# executive. If left blank a4wide will be used. - -PAPER_TYPE = a4wide - -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -# packages that should be included in the LaTeX output. - -EXTRA_PACKAGES = - -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a -# standard header. Notice: only use this tag if you know what you are doing! - -LATEX_HEADER = - -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references -# This makes the output suitable for online browsing using a pdf viewer. - -PDF_HYPERLINKS = YES - -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a -# higher quality PDF documentation. - -USE_PDFLATEX = YES - -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. -# This option is also used when generating formulas in HTML. - -LATEX_BATCHMODE = NO - -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) -# in the output. - -LATEX_HIDE_INDICES = NO - -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- - -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with -# other RTF readers or editors. - -GENERATE_RTF = NO - -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `rtf' will be used as the default path. - -RTF_OUTPUT = rtf - -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_RTF = NO - -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. -# Note: wordpad (write) and others do not support links. - -RTF_HYPERLINKS = NO - -# Load stylesheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide -# replacements, missing definitions are set to their default value. - -RTF_STYLESHEET_FILE = - -# Set optional variables used in the generation of an rtf document. -# Syntax is similar to doxygen's config file. - -RTF_EXTENSIONS_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- - -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -# generate man pages - -GENERATE_MAN = NO - -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `man' will be used as the default path. - -MAN_OUTPUT = man - -# The MAN_EXTENSION tag determines the extension that is added to -# the generated man pages (default is the subroutine's section .3) - -MAN_EXTENSION = .3 - -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command -# would be unable to find the correct page. The default is NO. - -MAN_LINKS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- - -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of -# the code including all documentation. - -GENERATE_XML = NO - -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `xml' will be used as the default path. - -XML_OUTPUT = xml - -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_DTD = - -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that -# enabling this will significantly increase the size of the XML output. - -XML_PROGRAMLISTING = YES - -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- - -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental -# and incomplete at the moment. - -GENERATE_AUTOGEN_DEF = NO - -#--------------------------------------------------------------------------- -# configuration options related to the Perl module output -#--------------------------------------------------------------------------- - -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the -# moment. - -GENERATE_PERLMOD = NO - -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able -# to generate PDF and DVI output from the Perl module output. - -PERLMOD_LATEX = NO - -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. This is useful -# if you want to understand what is going on. On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller -# and Perl will parse it just the same. - -PERLMOD_PRETTY = YES - -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same -# Makefile don't overwrite each other's variables. - -PERLMOD_MAKEVAR_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - -ENABLE_PREPROCESSING = YES - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled -# way by setting EXPAND_ONLY_PREDEF to YES. - -MACRO_EXPANSION = NO - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_DEFINED tags. - -EXPAND_ONLY_PREDEF = NO - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# in the INCLUDE_PATH (see below) will be search if a #include is found. - -SEARCH_INCLUDES = YES - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - -INCLUDE_PATH = - -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will -# be used. - -INCLUDE_FILE_PATTERNS = - -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator -# instead of the = operator. - -PREDEFINED = - -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition. - -EXPAND_AS_DEFINED = - -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all function-like macros that are alone -# on a line, have an all uppercase name, and do not end with a semicolon. Such -# function macros are typically used for boiler-plate code, and will confuse -# the parser if not removed. - -SKIP_FUNCTION_MACROS = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to external references -#--------------------------------------------------------------------------- - -# The TAGFILES option can be used to specify one or more tagfiles. -# Optionally an initial location of the external documentation -# can be added for each tagfile. The format of a tag file without -# this location is as follows: -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths or -# URLs. If a location is present for each tag, the installdox tool -# does not have to be run to correct the links. -# Note that each tag file must have a unique name -# (where the name does NOT include the path) -# If a tag file is not located in the directory in which doxygen -# is run, you must also specify the path to the tagfile here. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - -GENERATE_TAGFILE = - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - -ALLEXTERNALS = NO - -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will -# be listed. - -EXTERNAL_GROUPS = YES - -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of `which perl'). - -PERL_PATH = /usr/bin/perl - -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- - -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option is superseded by the HAVE_DOT option below. This is only a -# fallback. It is recommended to install and use dot, since it yields more -# powerful graphs. - -CLASS_DIAGRAMS = YES - -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see -# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented -# or is not a class. - -HIDE_UNDOC_RELATIONS = YES - -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section -# have no effect if this option is set to NO (the default) - -HAVE_DOT = NO - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# the CLASS_DIAGRAMS tag to NO. - -CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - -COLLABORATION_GRAPH = YES - -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for groups, showing the direct groups dependencies - -GROUP_GRAPHS = YES - -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling -# Language. - -UML_LOOK = NO - -# If set to YES, the inheritance and collaboration graphs will show the -# relations between templates and their instances. - -TEMPLATE_RELATIONS = NO - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with -# other documented files. - -INCLUDE_GRAPH = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or -# indirectly include this file. - -INCLUDED_BY_GRAPH = YES - -# If the CALL_GRAPH and HAVE_DOT options are set to YES then -# doxygen will generate a call dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable call graphs -# for selected functions only using the \callgraph command. - -CALL_GRAPH = NO - -# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then -# doxygen will generate a caller dependency graph for every global function -# or class method. Note that enabling this option will significantly increase -# the time of a run. So in most cases it will be better to enable caller -# graphs for selected functions only using the \callergraph command. - -CALLER_GRAPH = NO - -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will graphical hierarchy of all classes instead of a textual one. - -GRAPHICAL_HIERARCHY = YES - -# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories -# in a graphical way. The dependency relations are determined by the #include -# relations between the files in the directories. - -DIRECTORY_GRAPH = YES - -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are png, jpg, or gif -# If left blank png will be used. - -DOT_IMAGE_FORMAT = png - -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found in the path. - -DOT_PATH = - -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the -# \dotfile command). - -DOTFILE_DIRS = - -# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -# nodes that will be shown in the graph. If the number of nodes in a graph -# becomes larger than this value, doxygen will truncate the graph, which is -# visualized by representing a node as a red box. Note that doxygen if the -# number of direct children of the root node in a graph is already larger than -# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note -# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. - -DOT_GRAPH_MAX_NODES = 50 - -# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the -# graphs generated by dot. A depth value of 3 means that only nodes reachable -# from the root by following a path via at most 3 edges will be shown. Nodes -# that lay further from the root node will be omitted. Note that setting this -# option to 1 or 2 may greatly reduce the computation time needed for large -# code bases. Also note that the size of a graph can be further restricted by -# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. - -MAX_DOT_GRAPH_DEPTH = 0 - -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is enabled by default, which results in a transparent -# background. Warning: Depending on the platform used, enabling this option -# may lead to badly anti-aliased labels on the edges of a graph (i.e. they -# become hard to read). - -DOT_TRANSPARENT = YES - -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) -# support this, this feature is disabled by default. - -DOT_MULTI_TARGETS = NO - -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and -# arrows in the dot generated graphs. - -GENERATE_LEGEND = YES - -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate -# the various graphs. - -DOT_CLEANUP = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to the search engine -#--------------------------------------------------------------------------- - -# The SEARCHENGINE tag specifies whether or not a search engine should be -# used. If set to NO the values of all tags below this one will be ignored. - -SEARCHENGINE = NO diff --git a/libhtp/htp.pc.in b/libhtp/htp.pc.in deleted file mode 100644 index 754851e2fc..0000000000 --- a/libhtp/htp.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=/usr -exec_prefix=${prefix} -libdir=${exec_prefix}/lib -includedir=${prefix}/include - -Name: HTP -Description: HTTP parser -Version: 0.2.12 -Libs: -L${libdir} -lhtp -Cflags: -I${includedir}/htp -I${libdir}/htp/include - diff --git a/libhtp/htp/Makefile.am b/libhtp/htp/Makefile.am deleted file mode 100644 index ce4a9d3c88..0000000000 --- a/libhtp/htp/Makefile.am +++ /dev/null @@ -1,14 +0,0 @@ - -h_sources = bstr.h dslib.h hooks.h htp.h utf8_decoder.h htp_decompressors.h -c_sources = bstr.c hooks.c htp_config.c htp_connection_parser.c htp_request_apache_2_2.c htp_request_generic.c htp_request_parsers.c htp_response_generic.c htp_util.c dslib.c htp.c htp_connection.c htp_parsers.c htp_request.c htp_response.c htp_transaction.c utf8_decoder.c htp_decompressors.c - -library_includedir = $(includedir)/$(GENERIC_LIBRARY_NAME) -library_include_HEADERS = $(h_sources) - -INCLUDES = -I$(top_srcdir) -AM_CFLAGS = -D_GNU_SOURCE -g -O2 -Wall -Wextra -std=gnu99 -pedantic - -lib_LTLIBRARIES= libhtp.la -libhtp_la_SOURCES= $(h_sources) $(c_sources) -libhtp_la_LDFLAGS= -version-info $(GENERIC_LIBRARY_VERSION) -release $(GENERIC_RELEASE) - diff --git a/libhtp/htp/bstr.c b/libhtp/htp/bstr.c deleted file mode 100644 index 9cf330cfb3..0000000000 --- a/libhtp/htp/bstr.c +++ /dev/null @@ -1,657 +0,0 @@ -/* - * LibHTP (http://www.libhtp.org) - * Copyright 2009,2010 Ivan Ristic - * - * LibHTP is an open source product, released under terms of the General Public Licence - * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text - * of the license. - * - * In addition, there is a special exception that allows LibHTP to be freely - * used with any OSI-approved open source licence. Please refer to the file - * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. - * - */ - -#include "bstr.h" -#include - -/** - * Allocate a zero-length bstring, but reserving space for at least len bytes. - * - * @param len - * @return New string - */ -bstr *bstr_alloc(size_t len) { - unsigned char *s = malloc(sizeof (bstr_t) + len); - if (s == NULL) return NULL; - - bstr_t *b = (bstr_t *) s; - b->len = 0; - b->size = len; - b->ptr = NULL; - - return (bstr *) s; -} - -/** - * Deallocate a bstring. Allows a NULL bstring on input. - * - * @param b - */ -void bstr_free(bstr *b) { - if (b == NULL) return; - free(b); -} - -/** - * Append source bstring to destination bstring, growing - * destination if necessary. - * - * @param destination - * @param source - * @return destination, at a potentially different memory location - */ -bstr *bstr_add_str(bstr *destination, bstr *source) { - return bstr_add_mem(destination, bstr_ptr(source), bstr_len(source)); -} - -/** - * Append a NUL-terminated source to destination, growing - * destination if necessary. - * - * @param destination - * @param source - * @return destination, at a potentially different memory location - */ -bstr *bstr_add_cstr(bstr *destination, char *source) { - return bstr_add_mem(destination, source, strlen(source)); -} - -/** - * Append a memory region to destination, growing destination - * if necessary. - * - * @param destination - * @param data - * @param len - * @return destination, at a potentially different memory location - */ -bstr *bstr_add_mem(bstr *destination, char *data, size_t len) { - if (bstr_size(destination) < bstr_len(destination) + len) { - destination = bstr_expand(destination, bstr_len(destination) + len); - if (destination == NULL) return NULL; - } - - bstr_t *b = (bstr_t *) destination; - memcpy(bstr_ptr(destination) + b->len, data, len); - b->len = b->len + len; - - return destination; -} - -/** - * Append source bstring to destination bstring, growing - * destination if necessary. - * - * @param destination - * @param source - * @return destination, at a potentially different memory location - */ -bstr *bstr_add_str_noex(bstr *destination, bstr *source) { - return bstr_add_mem_noex(destination, bstr_ptr(source), bstr_len(source)); -} - -/** - * Append a NUL-terminated source to destination, growing - * destination if necessary. - * - * @param destination - * @param source - * @return destination, at a potentially different memory location - */ -bstr *bstr_add_cstr_noex(bstr *destination, char *source) { - return bstr_add_mem_noex(destination, source, strlen(source)); -} - -/** - * Append a memory region to destination, growing destination - * if necessary. - * - * @param destination - * @param data - * @param len - * @return destination, at a potentially different memory location - */ -bstr *bstr_add_mem_noex(bstr *destination, char *data, size_t len) { - size_t copylen = len; - - if (bstr_size(destination) < bstr_len(destination) + copylen) { - copylen = bstr_size(destination) - bstr_len(destination); - if (copylen <= 0) return destination; - } - - bstr_t *b = (bstr_t *) destination; - memcpy(bstr_ptr(destination) + b->len, data, copylen); - b->len = b->len + copylen; - - return destination; -} - -/** - * Expand a string to support at least newsize bytes. The input bstring - * is not changed if it is big enough to accommodate the desired size. If - * the input bstring is smaller, however, it is expanded. The pointer to - * the bstring may change. If the expansion fails, the original bstring - * is left untouched (it is not freed). - * - * @param s - * @param newsize - * @return new bstring, or NULL if memory allocation failed - */ -bstr *bstr_expand(bstr *s, size_t newsize) { - if (((bstr_t *) s)->ptr != NULL) { - void * newblock = realloc(((bstr_t *) s)->ptr, newsize); - if (newblock == NULL) { - return NULL; - } else { - ((bstr_t *) s)->ptr = newblock; - } - } else { - void *newblock = realloc(s, sizeof (bstr_t) + newsize); - if (newblock == NULL) { - return NULL; - } else { - s = newblock; - } - } - - ((bstr_t *) s)->size = newsize; - - return s; -} - -/** - * Create a new bstring by copying the provided NUL-terminated string. - * - * @param data - * @return new bstring - */ -bstr *bstr_cstrdup(char *data) { - return bstr_memdup(data, strlen(data)); -} - -/** - * Create a new bstring by copying the provided memory region. - * - * @param data - * @param len - * @return new bstring - */ -bstr *bstr_memdup(char *data, size_t len) { - bstr *b = bstr_alloc(len); - if (b == NULL) return NULL; - memcpy(bstr_ptr(b), data, len); - ((bstr_t *) b)->len = len; - return b; -} - -/** - * Create a new bstring by copying the provided bstring. - * - * @param b - * @return new bstring - */ -bstr *bstr_strdup(bstr *b) { - return bstr_strdup_ex(b, 0, bstr_len(b)); -} - -/** - * Create a new bstring by copying a part of the provided - * bstring. - * - * @param b - * @param offset - * @param len - * @return new bstring - */ -bstr *bstr_strdup_ex(bstr *b, size_t offset, size_t len) { - bstr *bnew = bstr_alloc(len); - if (bnew == NULL) return NULL; - memcpy(bstr_ptr(bnew), bstr_ptr(b) + offset, len); - ((bstr_t *) bnew)->len = len; - return bnew; -} - -/** - * Take the provided memory region and construct a NUL-terminated - * string, replacing NUL bytes with "\0". - * - * @param data - * @param len - * @return new NUL-terminated string - */ -char *bstr_memtocstr(char *data, size_t len) { - // Count how many NUL bytes we have in the string. - size_t i, nulls = 0; - for (i = 0; i < len; i++) { - if (data[i] == '\0') { - nulls++; - } - } - - // Now copy the string into a NUL-terminated buffer. - char *r, *t; - r = t = malloc(len + nulls + 1); - if (t == NULL) return NULL; - - while (len--) { - // Escape NUL bytes, but just copy everything else. - if (*data == '\0') { - data++; - *t++ = '\\'; - *t++ = '0'; - } else { - *t++ = *data++; - } - } - - // Terminate string. - *t = '\0'; - - return r; -} - -/** - * Create a new NUL-terminated string out of the provided bstring. - * - * @param b - * @return new NUL-terminated string - */ -char *bstr_tocstr(bstr *b) { - if (b == NULL) return NULL; - return bstr_memtocstr(bstr_ptr(b), bstr_len(b)); -} - -/** - * Return the first position of the provided character (byte). - * - * @param b - * @param c - * @return the first position of the character, or -1 if it could not be found - */ -int bstr_chr(bstr *b, int c) { - char *data = bstr_ptr(b); - size_t len = bstr_len(b); - - size_t i = 0; - while (i < len) { - if (data[i] == c) { - return i; - } - - i++; - } - - return -1; -} - -/** - * Return the last position of a character (byte). - * - * @param b - * @param c - * @return the last position of the character, or -1 if it could not be found - */ -int bstr_rchr(bstr *b, int c) { - char *data = bstr_ptr(b); - size_t len = bstr_len(b); - - int i = len; - while (i >= 0) { - if (data[i] == c) { - return i; - } - - i--; - } - - return -1; -} - -/** - * Compare two memory regions. - * - * @param s1 - * @param l1 - * @param s2 - * @param l2 - * @return 0 if the memory regions are identical, -1 or +1 if they're not - */ -int bstr_cmp_ex(char *s1, size_t l1, char *s2, size_t l2) { - size_t p1 = 0, p2 = 0; - - while ((p1 < l1) && (p2 < l2)) { - if (s1[p1] != s2[p2]) { - // Difference - return (s1[p1] < s2[p2]) ? -1 : 1; - } - - p1++; - p2++; - } - - if ((p1 == l2) && (p2 == l1)) { - // They're identical - return 0; - } else { - // One string is shorter - if (p1 == l1) return -1; - else return 1; - } -} - -/** - * Case-insensitive comparison of two memory regions. - * - * @param s1 - * @param l1 - * @param s2 - * @param l2 - * @return 0 if the memory regions are identical, -1 or +1 if they're not - */ -int bstr_cmp_nocase_ex(char *s1, size_t l1, char *s2, size_t l2) { - size_t p1 = 0, p2 = 0; - - while ((p1 < l1) && (p2 < l2)) { - if (tolower((int)s1[p1]) != tolower((int)s2[p2])) { - // Difference - return (tolower((int)s1[p1]) < tolower((int)s2[p2])) ? -1 : 1; - } - - p1++; - p2++; - } - - if ((p1 == l2) && (p2 == l1)) { - // They're identical - return 0; - } else { - // One string is shorter - if (p1 == l1) return -1; - else return 1; - } -} - -/** - * Compare a bstring with a NUL-terminated string. - * - * @param b - * @param c - * @return 0, -1 or +1 - */ -int bstr_cmpc(bstr *b, char *c) { - return bstr_cmp_ex(bstr_ptr(b), bstr_len(b), c, strlen(c)); -} - -/** - * Compare two bstrings. - * - * @param b1 - * @param b2 - * @return 0, -1 or +1 - */ -int bstr_cmp(bstr *b1, bstr *b2) { - return bstr_cmp_ex(bstr_ptr(b1), bstr_len(b1), bstr_ptr(b2), bstr_len(b2)); -} - -/** - * Case-insensitive comparison two bstrings. - * - * @param b1 - * @param b2 - * @return 0, -1 or +1 - */ -int bstr_cmp_nocase(bstr *b1, bstr *b2) { - return bstr_cmp_nocase_ex(bstr_ptr(b1), bstr_len(b1), bstr_ptr(b2), bstr_len(b2)); -} - -/** - * Convert bstring to lowercase. - * - * @param b - * @return b - */ -bstr *bstr_tolowercase(bstr *b) { - if (b == NULL) return NULL; - - unsigned char *data = (unsigned char *)bstr_ptr(b); - size_t len = bstr_len(b); - - size_t i = 0; - while (i < len) { - data[i] = tolower(data[i]); - i++; - } - - return b; -} - -/** - * Create a copy of the provided bstring, then convert it to lowercase. - * - * @param b - * @return bstring copy - */ -bstr *bstr_dup_lower(bstr *b) { - return bstr_tolowercase(bstr_strdup(b)); -} - -/** - * - */ -int bstr_util_memtoip(char *data, size_t len, int base, size_t *lastlen) { - int rval = 0, tval = 0, tflag = 0; - - size_t i = *lastlen = 0; - for (i = 0; i < len; i++) { - int d = data[i]; - - *lastlen = i; - - // Convert character to digit. - if ((d >= '0') && (d <= '9')) { - d -= '0'; - } else if ((d >= 'a') && (d <= 'z')) { - d -= 'a' - 10; - } else if ((d >= 'A') && (d <= 'Z')) { - d -= 'A' - 10; - } else { - d = -1; - } - - // Check that the digit makes sense with the base - // we are using. - if ((d == -1) || (d >= base)) { - if (tflag) { - // Return what we have so far; lastlen points - // to the first non-digit position. - return rval; - } else { - // We didn't see a single digit. - return -1; - } - } - - if (tflag) { - rval *= base; - - if (tval > rval) { - // Overflow - return -2; - } - - rval += d; - - if (tval > rval) { - // Overflow - return -2; - } - - tval = rval; - } else { - tval = rval = d; - tflag = 1; - } - } - - *lastlen = i + 1; - - return rval; -} - -/** - * Find needle in a haystack. - * - * @param haystack - * @param needle - * @return - */ -int bstr_indexof(bstr *haystack, bstr *needle) { - return bstr_indexofmem(haystack, bstr_ptr(needle), bstr_len(needle)); -} - -/** - * Find index in the haystack, with the needle being a NUL-terminated string. - * - * @param haystack - * @param needle - * @return - */ -int bstr_indexofc(bstr *haystack, char *needle) { - return bstr_indexofmem(haystack, needle, strlen(needle)); -} - -/** - * Find index in the haystack. Ignore case differences. - * - * @param haystack - * @param needle - * @return - */ -int bstr_indexof_nocase(bstr *haystack, bstr *needle) { - return bstr_indexofmem_nocase(haystack, bstr_ptr(needle), bstr_len(needle)); -} - -/** - * Find index in the haystack, with the needle being a NUL-terminated string. - * Ignore case differences. - * - * @param haystack - * @param needle - * @return - */ -int bstr_indexofc_nocase(bstr *haystack, char *needle) { - return bstr_indexofmem_nocase(haystack, needle, strlen(needle)); -} - -/** - * Find index in the haystack, with the needle being a memory region. - * - * @param haystack - * @param data2 - * @param len2 - * @return - */ -int bstr_indexofmem(bstr *haystack, char *data2, size_t len2) { - unsigned char *data = (unsigned char *)bstr_ptr(haystack); - size_t len = bstr_len(haystack); - size_t i, j; - - // TODO Is an optimisation here justified? - // http://en.wikipedia.org/wiki/Knuth-Morris-Pratt_algorithm - - for (i = 0; i < len; i++) { - size_t k = i; - - for (j = 0; ((j < len2) && (k < len)); j++) { - if (data[k++] != data2[j]) break; - } - - if ((k - i) == len2) { - return i; - } - } - - return -1; -} - -/** - * Find index in the haystack, with the needle being a memory region. - * Ignore case differences. - * - * @param haystack - * @param data2 - * @param len2 - * @return - */ -int bstr_indexofmem_nocase(bstr *haystack, char *data2, size_t len2) { - unsigned char *data = (unsigned char *)bstr_ptr(haystack); - size_t len = bstr_len(haystack); - size_t i, j; - - // TODO No need to inspect the last len2 - 1 bytes - for (i = 0; i < len; i++) { - size_t k = i; - - for (j = 0; ((j < len2) && (k < len)); j++) { - if (toupper(data[k++]) != toupper((unsigned char)data2[j])) break; - } - - if ((k - i) == len2) { - return i; - } - } - - return -1; -} - -/** - * Remove one byte from the end of the string. - * - * @param s - */ -void bstr_chop(bstr *s) { - bstr_t *b = (bstr_t *) s; - if (b->len > 0) { - b->len--; - } -} - -/** - * Adjust bstring length. You will need to use this method whenever - * you work directly with the string contents, and you end up changing - * its length. - * - * @param s - * @param newlen - */ -void bstr_len_adjust(bstr *s, size_t newlen) { - bstr_t *b = (bstr_t *) s; - b->len = newlen; -} - -/** - * Return the character (byte) at the given position. - * - * @param s - * @param pos - * @return the character, or -1 if the bstring is too short - */ -char bstr_char_at(bstr *s, size_t pos) { - unsigned char *data = (unsigned char *)bstr_ptr(s); - size_t len = bstr_len(s); - - if (pos > len) return -1; - return data[pos]; -} - diff --git a/libhtp/htp/bstr.h b/libhtp/htp/bstr.h deleted file mode 100644 index 9122249b3f..0000000000 --- a/libhtp/htp/bstr.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * LibHTP (http://www.libhtp.org) - * Copyright 2009,2010 Ivan Ristic - * - * LibHTP is an open source product, released under terms of the General Public Licence - * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text - * of the license. - * - * In addition, there is a special exception that allows LibHTP to be freely - * used with any OSI-approved open source licence. Please refer to the file - * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. - * - */ - -#ifndef _BSTR_H -#define _BSTR_H - -#include -#include -#include - -// IMPORTANT This binary string library is used internally by the parser and you should -// not rely on it in your code. The implementation may change. -// -// TODO -// - Add a function that wraps an existing data -// - Support Unicode bstrings - -typedef void * bstr; - -bstr *bstr_alloc(size_t newsize); -void bstr_free(bstr *s); -bstr *bstr_expand(bstr *s, size_t newsize); -bstr *bstr_cstrdup(char *); -bstr *bstr_memdup(char *data, size_t len); -bstr *bstr_strdup(bstr *b); -bstr *bstr_strdup_ex(bstr *b, size_t offset, size_t len); -char *bstr_tocstr(bstr *); - -int bstr_chr(bstr *, int); -int bstr_rchr(bstr *, int); - -int bstr_cmpc(bstr *, char *); -int bstr_cmp(bstr *, bstr *); -int bstr_cmp_nocase(bstr *, bstr *); - -bstr *bstr_dup_lower(bstr *); -bstr *bstr_tolowercase(bstr *); - -bstr *bstr_add_mem(bstr *, char *, size_t); -bstr *bstr_add_str(bstr *, bstr *); -bstr *bstr_add_cstr(bstr *, char *); - -bstr *bstr_add_mem_noex(bstr *, char *, size_t); -bstr *bstr_add_str_noex(bstr *, bstr *); -bstr *bstr_add_cstr_noex(bstr *, char *); - -int bstr_util_memtoip(char *data, size_t len, int base, size_t *lastlen); -char *bstr_memtocstr(char *data, size_t len); - -int bstr_indexof(bstr *haystack, bstr *needle); -int bstr_indexofc(bstr *haystack, char *needle); -int bstr_indexof_nocase(bstr *haystack, bstr *needle); -int bstr_indexofc_nocase(bstr *haystack, char *needle); -int bstr_indexofmem(bstr *haystack, char *data, size_t len); -int bstr_indexofmem_nocase(bstr *haystack, char *data, size_t len); - -void bstr_chop(bstr *b); -void bstr_len_adjust(bstr *s, size_t newlen); - -char bstr_char_at(bstr *s, size_t pos); - -typedef struct bstr_t bstr_t; - -struct bstr_t { - /** The length of the string stored in the buffer. */ - size_t len; - - /** The current size of the buffer. If the buffer is bigger than the - * string then it will be able to expand without having to reallocate. - */ - size_t size; - - /** Optional buffer pointer. If this pointer is NUL (as it currently is - * in virtually all cases, the string buffer will immediatelly follow - * this structure. If the pointer is not NUL, it points to the actual - * buffer used, and there's no data following this structure. - */ - char *ptr; -}; - -#define bstr_len(X) ((*(bstr_t *)(X)).len) -#define bstr_size(X) ((*(bstr_t *)(X)).size) -#define bstr_ptr(X) ( ((*(bstr_t *)(X)).ptr == NULL) ? (char *)((char *)(X) + sizeof(bstr_t)) : (char *)(*(bstr_t *)(X)).ptr ) - -#endif /* _BSTR_H */ - diff --git a/libhtp/htp/dslib.c b/libhtp/htp/dslib.c deleted file mode 100644 index 507094bc1c..0000000000 --- a/libhtp/htp/dslib.c +++ /dev/null @@ -1,563 +0,0 @@ -/* - * LibHTP (http://www.libhtp.org) - * Copyright 2009,2010 Ivan Ristic - * - * LibHTP is an open source product, released under terms of the General Public Licence - * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text - * of the license. - * - * In addition, there is a special exception that allows LibHTP to be freely - * used with any OSI-approved open source licence. Please refer to the file - * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. - * - */ - -#include -#include - -#include "dslib.h" - - -// -- Queue List -- - -/** - * Add element to list. - * - * @param list - * @param element - * @return 1 on success, -1 on error (memory allocation failure) - */ -static int list_linked_push(list_t *_q, void *element) { - list_linked_t *q = (list_linked_t *) _q; - list_linked_element_t *qe = calloc(1, sizeof (list_linked_element_t)); - if (qe == NULL) return -1; - - // Rememeber the element - qe->data = element; - - // If the queue is empty, make this element first - if (!q->first) { - q->first = qe; - } - - if (q->last) { - q->last->next = qe; - } - - q->last = qe; - - return 1; -} - -/** - * Remove one element from the beginning of the list. - * - * @param list - * @return a pointer to the removed element, or NULL if the list is empty. - */ -static void *list_linked_pop(list_t *_q) { - list_linked_t *q = (list_linked_t *) _q; - void *r = NULL; - - if (!q->first) { - return NULL; - } - - list_linked_element_t *qe = q->first; - q->first = qe->next; - r = qe->data; - - if (!q->first) { - q->last = NULL; - } - - free(qe); - - return r; -} - -/** - * Is the list empty? - * - * @param list - * @return 1 if the list is empty, 0 if it is not - */ -static int list_linked_empty(list_t *_q) { - list_linked_t *q = (list_linked_t *) _q; - - if (!q->first) { - return 1; - } else { - return 0; - } -} - -/** - * Destroy list. This function will not destroy any of the - * data stored in it. You'll have to do that manually beforehand. - * - * @param l - */ -void list_linked_destroy(list_linked_t *l) { - // Free the list structures - list_linked_element_t *temp = l->first; - list_linked_element_t *prev = NULL; - while (temp != NULL) { - free(temp->data); - prev = temp; - temp = temp->next; - free(prev); - } - - // Free the list itself - free(l); -} - -/** - * Create a new linked list. - * - * @return a pointer to the newly creted list (list_t), or NULL on memory allocation failure - */ -list_t *list_linked_create(void) { - list_linked_t *q = calloc(1, sizeof (list_linked_t)); - if (q == NULL) return NULL; - - q->push = list_linked_push; - q->pop = list_linked_pop; - q->empty = list_linked_empty; - q->destroy = (void (*)(list_t *))list_linked_destroy; - - return (list_t *) q; -} - -// -- Queue Array -- - -/** - * Add new element to the end of the list, expanding the list - * as necessary. - * - * @param list - * @param element - * - * @return 1 on success or -1 on failure (memory allocation) - */ -static int list_array_push(list_t *_q, void *element) { - list_array_t *q = (list_array_t *) _q; - - // Check if we're full - if (q->current_size >= q->max_size) { - int new_size = q->max_size * 2; - void *newblock = NULL; - - if (q->first == 0) { - // The simple case of expansion is when the first - // element in the list resides in the first slot. In - // that case we just add some new space to the end, - // adjust the max_size and that's that. - newblock = realloc(q->elements, new_size * sizeof (void *)); - if (newblock == NULL) return -1; - } else { - // When the first element is not in the first - // memory slot, we need to rearrange the order - // of the elements in order to expand the storage area. - newblock = malloc(new_size * sizeof (void *)); - if (newblock == NULL) return -1; - - // Copy the beginning of the list to the beginning of the new memory block - memcpy(newblock, (char *)q->elements + q->first * sizeof (void *), (q->max_size - q->first) * sizeof (void *)); - // Append the second part of the list to the end - memcpy((char *)newblock + (q->max_size - q->first) * sizeof (void *), q->elements, q->first * sizeof (void *)); - - free(q->elements); - } - - q->first = 0; - q->last = q->current_size; - q->max_size = new_size; - q->elements = newblock; - } - - q->elements[q->last] = element; - q->current_size++; - - q->last++; - if (q->last == q->max_size) { - q->last = 0; - } - - return 1; -} - -/** - * Remove one element from the beginning of the list. - * - * @param list - * @return the removed element, or NULL if the list is empty - */ -static void *list_array_pop(list_t *_q) { - list_array_t *q = (list_array_t *) _q; - void *r = NULL; - - if (q->current_size == 0) { - return NULL; - } - - r = q->elements[q->first]; - q->first++; - if (q->first == q->max_size) { - q->first = 0; - } - - q->current_size--; - - return r; -} - -/** - * Returns the size of the list. - * - * @param list - */ -static size_t list_array_size(list_t *_l) { - return ((list_array_t *) _l)->current_size; -} - -/** - * Return the element at the given index. - * - * @param list - * @param index - * @return the desired element, or NULL if the list is too small, or - * if the element at that position carries a NULL - */ -static void *list_array_get(list_t *_l, size_t idx) { - list_array_t *l = (list_array_t *) _l; - void *r = NULL; - - if (idx + 1 > l->current_size) return NULL; - - size_t i = l->first; - r = l->elements[l->first]; - - while (idx--) { - if (++i == l->max_size) { - i = 0; - } - - r = l->elements[i]; - } - - return r; -} - -/** - * Replace the element at the given index with the provided element. - * - * @param list - * @param index - * @param element - * - * @return 1 if the element was replaced, or 0 if the list is too small - */ -static int list_array_replace(list_t *_l, size_t idx, void *element) { - list_array_t *l = (list_array_t *) _l; - - if (idx + 1 > l->current_size) return 0; - - size_t i = l->first; - - while (idx--) { - if (++i == l->max_size) { - i = 0; - } - } - - l->elements[i] = element; - - return 1; -} - -/** - * Reset the list iterator. - * - * @param l - */ -void list_array_iterator_reset(list_array_t *l) { - l->iterator_index = 0; -} - -/** - * Advance to the next list value. - * - * @param l - * @return the next list value, or NULL if there aren't more elements - * left to iterate over or if the element itself is NULL - */ -void *list_array_iterator_next(list_array_t *l) { - void *r = NULL; - - if (l->iterator_index < l->current_size) { - r = list_get(l, l->iterator_index); - l->iterator_index++; - } - - return r; -} - -/** - * Free the memory occupied by this list. This function assumes - * the data elements were freed beforehand. - * - * @param l - */ -void list_array_destroy(list_array_t *l) { - free(l->elements); - free(l); -} - -/** - * Create new array-based list. - * - * @param size - * @return newly allocated list (list_t) - */ -list_t *list_array_create(size_t size) { - // Allocate the list structure - list_array_t *q = calloc(1, sizeof (list_array_t)); - if (q == NULL) return NULL; - - // Allocate the initial batch of elements - q->elements = malloc(size * sizeof (void *)); - if (q->elements == NULL) { - free(q); - return NULL; - } - - // Initialise structure - q->first = 0; - q->last = 0; - q->max_size = size; - q->push = list_array_push; - q->pop = list_array_pop; - q->get = list_array_get; - q->replace = list_array_replace; - q->size = list_array_size; - q->iterator_reset = (void (*)(list_t *))list_array_iterator_reset; - q->iterator_next = (void *(*)(list_t *))list_array_iterator_next; - q->destroy = (void (*)(list_t *))list_array_destroy; - - return (list_t *) q; -} - - -// -- Table -- - -/** - * Create a new table structure. - * - * @param size - * @return newly created table_t - */ -table_t *table_create(size_t size) { - table_t *t = calloc(1, sizeof (table_t)); - if (t == NULL) return NULL; - - // Use a list behind the scenes - t->list = list_array_create(size * 2); - if (t->list == NULL) { - free(t); - return NULL; - } - - return t; -} - -/** - * Destroy a table. - * - * @param table - */ -void table_destroy(table_t * table) { - // Free keys only - int counter = 0; - void *data = NULL; - - list_iterator_reset(table->list); - - while ((data = list_iterator_next(table->list)) != NULL) { - // Free key - if ((counter % 2) == 0) { - free(data); - } - - counter++; - } - - list_destroy(table->list); - - free(table); -} - -/** - * Add a new table element. This function currently makes a copy of - * the key, which is inefficient. - * - * @param table - * @param key - * @param element - */ -int table_add(table_t *table, bstr *key, void *element) { - // Lowercase key - bstr *lkey = bstr_dup_lower(key); - if (lkey == NULL) { - return -1; - } - - // Add key - if (list_add(table->list, lkey) != 1) { - free(lkey); - return -1; - } - - // Add element - if (list_add(table->list, element) != 1) { - list_pop(table->list); - free(lkey); - return -1; - } - - return 1; -} - -/** - * @param table - * @param key - */ -static void *table_get_internal(table_t *table, bstr *key) { - // Iterate through the list, comparing - // keys with the parameter, return data if found. - bstr *ts = NULL; - list_iterator_reset(table->list); - while ((ts = list_iterator_next(table->list)) != NULL) { - void *data = list_iterator_next(table->list); - if (bstr_cmp(ts, key) == 0) { - return data; - } - } - - return NULL; -} - -/** - * Retrieve the first element in the table with the given - * key (as a NUL-terminated string). - * - * @param table - * @param cstr - * @return table element, or NULL if not found - */ -void *table_getc(table_t *table, char *cstr) { - if (table == NULL||cstr == NULL) - return NULL; - // TODO This is very inefficient - bstr *key = bstr_cstrdup(cstr); - if (key == NULL) - return NULL; - bstr_tolowercase(key); - void *data = table_get_internal(table, key); - free(key); - return data; -} - -/** - * Retrieve the first element in the table with the given key. - * - * @param table - * @param key - * @return table element, or NULL if not found - */ -void *table_get(table_t *table, bstr *key) { - if (table == NULL||key == NULL) - return NULL; - // TODO This is very inefficient - bstr *lkey = bstr_dup_lower(key); - if (lkey == NULL) - return NULL; - void *data = table_get_internal(table, lkey); - free(lkey); - return data; -} - -/** - * Reset the table iterator. - * - * @param table - */ -void table_iterator_reset(table_t *table) { - list_iterator_reset(table->list); -} - -/** - * Advance to the next table element. - * - * @param t - * @param data - * @return pointer to the key and the element if there is a next element, NULL otherwise - */ -bstr *table_iterator_next(table_t *t, void **data) { - bstr *s = list_iterator_next(t->list); - if (s != NULL) { - *data = list_iterator_next(t->list); - } - - return s; -} - -/** - * Returns the size of the table. - * - * @param table - * @return table size - */ -size_t table_size(table_t *table) { - return list_size(table->list) / 2; -} - -/** - * Remove all elements from the table. - * - * @param table - */ -void table_clear(table_t *table) { - // TODO Clear table by removing the existing elements - if (table == NULL) - return; - size_t size = list_size(table->list); - - list_destroy(table->list); - - // Use a list behind the scenes - table->list = list_array_create(size == 0 ? 10 : size); - if (table->list == NULL) { - free(table); - } -} - -#if 0 - -int main(int argc, char **argv) { - list_t *q = list_linked_create(); - - list_push(q, "1"); - list_push(q, "2"); - list_push(q, "3"); - list_push(q, "4"); - - char *s = NULL; - while ((s = (char *) list_pop(q)) != NULL) { - printf("Got: %s\n", s); - } - - free(q); -} -#endif diff --git a/libhtp/htp/dslib.h b/libhtp/htp/dslib.h deleted file mode 100644 index 1cc2b6c3ca..0000000000 --- a/libhtp/htp/dslib.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * LibHTP (http://www.libhtp.org) - * Copyright 2009,2010 Ivan Ristic - * - * LibHTP is an open source product, released under terms of the General Public Licence - * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text - * of the license. - * - * In addition, there is a special exception that allows LibHTP to be freely - * used with any OSI-approved open source licence. Please refer to the file - * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. - * - */ - -#ifndef _DSLIB_H -#define _DSLIB_H - -#include "bstr.h" - -// IMPORTANT This library is used internally by the parser and you should -// not rely on it in your code. The implementation may change at -// some point in the future. - -// What we have here is two implementations of a list structure (array- and link-list-based), -// and one implementation of a table (case-insensitive keys; multiple key values are allowed). -// The lists can be used as a stack. -// -// TODO The table element retrieval if very inefficient at the moment. - -#define list_push(L, E) (L)->push(L, E) -#define list_pop(L) (L)->pop(L) -#define list_empty(L) (L)->empty(L) -#define list_get(L, N) (L)->get((list_t *)L, N) -#define list_replace(L, N, E) (L)->replace((list_t *)L, N, E) -#define list_add(L, N) (L)->push(L, N) -#define list_size(L) (L)->size(L) -#define list_iterator_reset(L) (L)->iterator_reset(L) -#define list_iterator_next(L) (L)->iterator_next(L) -#define list_destroy(L) (L)->destroy(L) - -#define LIST_COMMON \ - int (*push)(list_t *, void *); \ - void *(*pop)(list_t *); \ - int (*empty)(list_t *); \ - void *(*get)(list_t *, size_t index); \ - int (*replace)(list_t *, size_t index, void *); \ - size_t (*size)(list_t *); \ - void (*iterator_reset)(list_t *); \ - void *(*iterator_next)(list_t *); \ - void (*destroy)(list_t *) - -typedef struct list_t list_t; -typedef struct list_array_t list_array_t; -typedef struct list_linked_element_t list_linked_element_t; -typedef struct list_linked_t list_linked_t; - -typedef struct table_t table_t; - -struct list_t { - LIST_COMMON; -}; - -struct list_linked_element_t { - void *data; - list_linked_element_t *next; -}; - -struct list_linked_t { - LIST_COMMON; - - list_linked_element_t *first; - list_linked_element_t *last; -}; - -struct list_array_t { - LIST_COMMON; - - size_t first; - size_t last; - size_t max_size; - size_t current_size; - void **elements; - - size_t iterator_index; -}; - -list_t *list_linked_create(void); -list_t *list_array_create(size_t size); - -struct table_t { - list_t *list; -}; - -table_t *table_create(size_t size); - int table_add(table_t *, bstr *, void *); - void table_set(table_t *, bstr *, void *); - void *table_get(table_t *, bstr *); - void *table_getc(table_t *, char *); - void table_iterator_reset(table_t *); - bstr *table_iterator_next(table_t *, void **); - size_t table_size(table_t *t); - void table_destroy(table_t *); - void table_clear(table_t *); - -#endif /* _DSLIB_H */ - diff --git a/libhtp/htp/hooks.c b/libhtp/htp/hooks.c deleted file mode 100644 index 37fd2c9226..0000000000 --- a/libhtp/htp/hooks.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * LibHTP (http://www.libhtp.org) - * Copyright 2009,2010 Ivan Ristic - * - * LibHTP is an open source product, released under terms of the General Public Licence - * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text - * of the license. - * - * In addition, there is a special exception that allows LibHTP to be freely - * used with any OSI-approved open source licence. Please refer to the file - * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. - * - */ - -#include "hooks.h" - -/** - * Creates a new hook. - * - * @return New htp_hook_t structure on success, NULL on failure - */ -htp_hook_t *hook_create() { - htp_hook_t *hook = calloc(1, sizeof (htp_hook_t)); - if (hook == NULL) return NULL; - - hook->callbacks = list_array_create(4); - if (hook->callbacks == NULL) { - free(hook); - return NULL; - } - - return hook; -} - -/** - * Creates a copy of the provided hook. The hook is allowed to be NULL, - * in which case this function simply returns a NULL. - * - * @param hook - * @return A copy of the hook, or NULL (if the provided hook was NULL - * or, if it wasn't, if there was a memory allocation problem while - * constructing a copy). - */ -htp_hook_t * hook_copy(htp_hook_t *hook) { - if (hook == NULL) return NULL; - - htp_hook_t *copy = hook_create(); - if (copy == NULL) return NULL; - - htp_callback_t *callback = NULL; - list_iterator_reset(hook->callbacks); - while ((callback = list_iterator_next(hook->callbacks)) != NULL) { - if (hook_register(©, callback->fn) < 0) { - hook_destroy(copy); - return NULL; - } - } - - return copy; -} - -/** - * Destroys an existing hook. It is all right to send a NULL - * to this method because it will simply return straight away. - * - * @param hook - */ -void hook_destroy(htp_hook_t *hook) { - if (hook == NULL) return; - - htp_callback_t *callback = NULL; - list_iterator_reset(hook->callbacks); - while ((callback = list_iterator_next(hook->callbacks)) != NULL) { - free(callback); - } - - list_destroy(hook->callbacks); - - free(hook); -} - -/** - * Registers a new callback with the hook. - * - * @param hook - * @param callback_fn - * @return 1 on success, -1 on memory allocation error - */ -int hook_register(htp_hook_t **hook, int (*callback_fn)()) { - int hook_created = 0; - htp_callback_t *callback = calloc(1, sizeof (htp_callback_t)); - if (callback == NULL) return -1; - - callback->fn = callback_fn; - - // Create a new hook if one does not exist - if (*hook == NULL) { - *hook = hook_create(); - if (*hook == NULL) { - free(callback); - return -1; - } - - hook_created = 1; - } - - // Add callback - if (list_add((*hook)->callbacks, callback) < 0) { - if (hook_created) { - free(*hook); - } - - free(callback); - return -1; - } - - return 1; -} - -/** - * Runs all the callbacks associated with a given hook. Only stops if - * one of the callbacks returns an error (HOOK_ERROR). - * - * @param hook - * @param data - * @return HOOK_OK or HOOK_ERROR - */ -int hook_run_all(htp_hook_t *hook, void *data) { - if (hook == NULL) { - return HOOK_OK; - } - - /* HACK https://redmine.openinfosecfoundation.org/issues/601 */ - size_t i = 0; - for (i = 0; i < ((list_array_t *)hook->callbacks)->current_size; i++) { - void *r = ((list_array_t *)hook->callbacks)->elements[i]; - if (r == NULL) - continue; - - htp_callback_t *callback = r; - if (callback->fn(data) == HOOK_ERROR) { - return HOOK_ERROR; - } - } -#if 0 - htp_callback_t *callback = NULL; - list_iterator_reset(hook->callbacks); - while ((callback = list_iterator_next(hook->callbacks)) != NULL) { - if (callback->fn(data) == HOOK_ERROR) { - return HOOK_ERROR; - } - } -#endif - return HOOK_OK; -} - -/** - * Run callbacks until one of them accepts to service the hook. - * - * @param hook - * @param data - * @return HOOK_OK on success, HOOK_DECLINED if no callback wanted to run and HOOK_ERROR on error. - */ -int hook_run_one(htp_hook_t *hook, void *data) { - if (hook == NULL) { - return HOOK_DECLINED; - } - - /* HACK https://redmine.openinfosecfoundation.org/issues/601 */ - size_t i = 0; - for (i = 0; i < ((list_array_t *)hook->callbacks)->current_size; i++) { - void *r = ((list_array_t *)hook->callbacks)->elements[i]; - if (r == NULL) - continue; - - htp_callback_t *callback = r; - int status = callback->fn(data); - if (status != HOOK_DECLINED) { - return status; - } - } -#if 0 - htp_callback_t *callback = NULL; - list_iterator_reset(hook->callbacks); - while ((callback = list_iterator_next(hook->callbacks)) != NULL) { - int status = callback->fn(data); - // Both HOOK_OK and HOOK_ERROR will stop hook processing - if (status != HOOK_DECLINED) { - return status; - } - } -#endif - return HOOK_DECLINED; -} diff --git a/libhtp/htp/hooks.h b/libhtp/htp/hooks.h deleted file mode 100644 index 80ced945a3..0000000000 --- a/libhtp/htp/hooks.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * LibHTP (http://www.libhtp.org) - * Copyright 2009,2010 Ivan Ristic - * - * LibHTP is an open source product, released under terms of the General Public Licence - * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text - * of the license. - * - * In addition, there is a special exception that allows LibHTP to be freely - * used with any OSI-approved open source licence. Please refer to the file - * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. - * - */ - -#ifndef _HOOKS_H -#define _HOOKS_H - -#include "dslib.h" - -#ifdef _HTP_H -#define HOOK_ERROR HTP_ERROR -#define HOOK_OK HTP_OK -#define HOOK_DECLINED HTP_DECLINED -#else -#define HOOK_ERROR -1 -#define HOOK_OK 0 -#define HOOK_DECLINED 1 -#endif - -typedef struct htp_hook_t htp_hook_t; -typedef struct htp_callback_t htp_callback_t; - -struct htp_hook_t { - list_t *callbacks; -}; - -struct htp_callback_t { - int (*fn)(); -}; - - int hook_register(htp_hook_t **hook, int (*callback_fn)()); - int hook_run_one(htp_hook_t *hook, void *data); - int hook_run_all(htp_hook_t *hook, void *data); - -htp_hook_t *hook_create(); -htp_hook_t *hook_copy(htp_hook_t *hook); - void hook_destroy(htp_hook_t *hook); - - -#endif /* _HOOKS_H */ - diff --git a/libhtp/htp/htp.c b/libhtp/htp/htp.c deleted file mode 100644 index 4fc92d7906..0000000000 --- a/libhtp/htp/htp.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * LibHTP (http://www.libhtp.org) - * Copyright 2009,2010 Ivan Ristic - * - * LibHTP is an open source product, released under terms of the General Public Licence - * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text - * of the license. - * - * In addition, there is a special exception that allows LibHTP to be freely - * used with any OSI-approved open source licence. Please refer to the file - * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. - * - */ - -#include -#include "htp.h" - -/** - * Returns the library version. - */ -const char *htp_get_version() { - return HTP_BASE_VERSION_TEXT; -} - - - - diff --git a/libhtp/htp/htp.h b/libhtp/htp/htp.h deleted file mode 100644 index 01465fa423..0000000000 --- a/libhtp/htp/htp.h +++ /dev/null @@ -1,1168 +0,0 @@ -/* - * LibHTP (http://www.libhtp.org) - * Copyright 2009,2010 Ivan Ristic - * - * LibHTP is an open source product, released under terms of the General Public Licence - * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text - * of the license. - * - * In addition, there is a special exception that allows LibHTP to be freely - * used with any OSI-approved open source licence. Please refer to the file - * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. - * - */ - -#ifndef _HTP_H -#define _HTP_H - -typedef struct htp_cfg_t htp_cfg_t; -typedef struct htp_conn_t htp_conn_t; -typedef struct htp_connp_t htp_connp_t; -typedef struct htp_header_t htp_header_t; -typedef struct htp_header_line_t htp_header_line_t; -typedef struct htp_log_t htp_log_t; -typedef struct htp_tx_data_t htp_tx_data_t; -typedef struct htp_tx_t htp_tx_t; -typedef struct htp_uri_t htp_uri_t; -typedef struct htp_urldecoder_t htp_urldecoder_t; - -#include -#include -#include -#include -#include -#include -#include - -#include "bstr.h" -#include "dslib.h" -#include "hooks.h" -#include "htp_decompressors.h" - -// -- Defines ------------------------------------------------------------------------------------- - -#define HTP_BASE_VERSION_TEXT "0.2.12" - -#define HTP_ERROR -1 -#define HTP_OK 0 -#define HTP_DATA 1 -#define HTP_DATA_OTHER 2 -#define HTP_DECLINED 3 - -#define PROTOCOL_UNKNOWN -1 -#define HTTP_0_9 9 -#define HTTP_1_0 100 -#define HTTP_1_1 101 - -#define COMPRESSION_NONE 0 -#define COMPRESSION_GZIP 1 -#define COMPRESSION_COMPRESS 2 // Not implemented -#define COMPRESSION_DEFLATE 3 // Not implemented - -#define HTP_LOG_MARK __FILE__,__LINE__ - -#define HTP_LOG_ERROR 1 -#define HTP_LOG_WARNING 2 -#define HTP_LOG_NOTICE 3 -#define HTP_LOG_INFO 4 -#define HTP_LOG_DEBUG 5 -#define HTP_LOG_DEBUG2 6 - -#define HTP_HEADER_MISSING_COLON 1 -#define HTP_HEADER_INVALID_NAME 2 -#define HTP_HEADER_LWS_AFTER_FIELD_NAME 3 -#define HTP_LINE_TOO_LONG_HARD 4 -#define HTP_LINE_TOO_LONG_SOFT 5 - -#define HTP_HEADER_LIMIT_HARD 18000 -#define HTP_HEADER_LIMIT_SOFT 9000 - -#define LOG_NO_CODE 0 - -#define CR '\r' -#define LF '\n' - -#define M_UNKNOWN -1 - -// The following request method are defined in Apache 2.2.13, in httpd.h. -#define M_GET 0 -#define M_PUT 1 -#define M_POST 2 -#define M_DELETE 3 -#define M_CONNECT 4 -#define M_OPTIONS 5 -#define M_TRACE 6 -#define M_PATCH 7 -#define M_PROPFIND 8 -#define M_PROPPATCH 9 -#define M_MKCOL 10 -#define M_COPY 11 -#define M_MOVE 12 -#define M_LOCK 13 -#define M_UNLOCK 14 -#define M_VERSION_CONTROL 15 -#define M_CHECKOUT 16 -#define M_UNCHECKOUT 17 -#define M_CHECKIN 18 -#define M_UPDATE 19 -#define M_LABEL 20 -#define M_REPORT 21 -#define M_MKWORKSPACE 22 -#define M_MKACTIVITY 23 -#define M_BASELINE_CONTROL 24 -#define M_MERGE 25 -#define M_INVALID 26 - -// Interestingly, Apache does not define M_HEAD -#define M_HEAD 1000 - -#define HTP_FIELD_UNPARSEABLE 0x000001 -#define HTP_FIELD_INVALID 0x000002 -#define HTP_FIELD_FOLDED 0x000004 -#define HTP_FIELD_REPEATED 0x000008 -#define HTP_FIELD_LONG 0x000010 -#define HTP_FIELD_NUL_BYTE 0x000020 -#define HTP_REQUEST_SMUGGLING 0x000040 -#define HTP_INVALID_FOLDING 0x000080 -#define HTP_INVALID_CHUNKING 0x000100 -#define HTP_MULTI_PACKET_HEAD 0x000200 -#define HTP_HOST_MISSING 0x000400 -#define HTP_AMBIGUOUS_HOST 0x000800 -#define HTP_PATH_ENCODED_NUL 0x001000 -#define HTP_PATH_INVALID_ENCODING 0x002000 -#define HTP_PATH_INVALID 0x004000 -#define HTP_PATH_OVERLONG_U 0x008000 -#define HTP_PATH_ENCODED_SEPARATOR 0x010000 - -#define HTP_PATH_UTF8_VALID 0x020000 /* At least one valid UTF-8 character and no invalid ones */ -#define HTP_PATH_UTF8_INVALID 0x040000 -#define HTP_PATH_UTF8_OVERLONG 0x080000 -#define HTP_PATH_FULLWIDTH_EVASION 0x100000 /* Range U+FF00 - U+FFFF detected */ - -#define PIPELINED_CONNECTION 1 - -#define HTP_SERVER_MINIMAL 0 -#define HTP_SERVER_GENERIC 1 -#define HTP_SERVER_IDS 2 -#define HTP_SERVER_IIS_4_0 4 /* Windows NT 4.0 */ -#define HTP_SERVER_IIS_5_0 5 /* Windows 2000 */ -#define HTP_SERVER_IIS_5_1 6 /* Windows XP Professional */ -#define HTP_SERVER_IIS_6_0 7 /* Windows 2003 */ -#define HTP_SERVER_IIS_7_0 8 /* Windows 2008 */ -#define HTP_SERVER_IIS_7_5 9 /* Windows 7 */ -#define HTP_SERVER_TOMCAT_6_0 10 /* Unused */ -#define HTP_SERVER_APACHE 11 -#define HTP_SERVER_APACHE_2_2 12 - -#define NONE 0 -#define IDENTITY 1 -#define CHUNKED 2 - -#define TX_PROGRESS_NEW 0 -#define TX_PROGRESS_REQ_LINE 1 -#define TX_PROGRESS_REQ_HEADERS 2 -#define TX_PROGRESS_REQ_BODY 3 -#define TX_PROGRESS_REQ_TRAILER 4 -#define TX_PROGRESS_WAIT 5 -#define TX_PROGRESS_RES_LINE 6 -#define TX_PROGRESS_RES_HEADERS 7 -#define TX_PROGRESS_RES_BODY 8 -#define TX_PROGRESS_RES_TRAILER 9 -#define TX_PROGRESS_DONE 10 - -#define STREAM_STATE_NEW 0 -#define STREAM_STATE_OPEN 1 -#define STREAM_STATE_CLOSED 2 -#define STREAM_STATE_ERROR 3 -#define STREAM_STATE_TUNNEL 4 -#define STREAM_STATE_DATA_OTHER 5 -#define STREAM_STATE_DATA 9 - -#define URL_DECODER_PRESERVE_PERCENT 0 -#define URL_DECODER_REMOVE_PERCENT 1 -#define URL_DECODER_DECODE_INVALID 2 -#define URL_DECODER_STATUS_400 400 - -#define NONE 0 -#define NO 0 -#define BESTFIT 0 -#define YES 1 -#define TERMINATE 1 -#define STATUS_400 400 -#define STATUS_404 401 - -#define IN_TEST_NEXT_BYTE_OR_RETURN(X) \ -if ((X)->in_current_offset >= (X)->in_current_len) { \ - return HTP_DATA; \ -} - -#define IN_NEXT_BYTE(X) \ -if ((X)->in_current_offset < (X)->in_current_len) { \ - (X)->in_next_byte = (X)->in_current_data[(X)->in_current_offset]; \ - (X)->in_current_offset++; \ - (X)->in_stream_offset++; \ -} else { \ - (X)->in_next_byte = -1; \ -} - -#define IN_NEXT_BYTE_OR_RETURN(X) \ -if ((X)->in_current_offset < (X)->in_current_len) { \ - (X)->in_next_byte = (X)->in_current_data[(X)->in_current_offset]; \ - (X)->in_current_offset++; \ - (X)->in_stream_offset++; \ -} else { \ - return HTP_DATA; \ -} - -#define IN_COPY_BYTE_OR_RETURN(X) \ -if ((X)->in_current_offset < (X)->in_current_len) { \ - (X)->in_next_byte = (X)->in_current_data[(X)->in_current_offset]; \ - (X)->in_current_offset++; \ - (X)->in_stream_offset++; \ -} else { \ - return HTP_DATA; \ -} \ -\ -if ((X)->in_line_len < (X)->in_line_size) { \ - (X)->in_line[(X)->in_line_len] = (X)->in_next_byte; \ - (X)->in_line_len++; \ - if (((X)->in_line_len == HTP_HEADER_LIMIT_SOFT)&&(!((X)->in_tx->flags & HTP_FIELD_LONG))) { \ - (X)->in_tx->flags |= HTP_FIELD_LONG; \ - htp_log((X), HTP_LOG_MARK, HTP_LOG_ERROR, HTP_LINE_TOO_LONG_SOFT, "Request field over soft limit"); \ - } \ -} else { \ - htp_log((X), HTP_LOG_MARK, HTP_LOG_ERROR, HTP_LINE_TOO_LONG_HARD, "Request field over hard limit"); \ - return HTP_ERROR; \ -} - -#define OUT_TEST_NEXT_BYTE_OR_RETURN(X) \ -if ((X)->out_current_offset >= (X)->out_current_len) { \ - return HTP_DATA; \ -} - -#define OUT_NEXT_BYTE(X) \ -if ((X)->out_current_offset < (X)->out_current_len) { \ - (X)->out_next_byte = (X)->out_current_data[(X)->out_current_offset]; \ - (X)->out_current_offset++; \ - (X)->out_stream_offset++; \ -} else { \ - (X)->out_next_byte = -1; \ -} - -#define OUT_NEXT_BYTE_OR_RETURN(X) \ -if ((X)->out_current_offset < (X)->out_current_len) { \ - (X)->out_next_byte = (X)->out_current_data[(X)->out_current_offset]; \ - (X)->out_current_offset++; \ - (X)->out_stream_offset++; \ -} else { \ - return HTP_DATA; \ -} - -#define OUT_COPY_BYTE_OR_RETURN(X) \ -if ((X)->out_current_offset < (X)->out_current_len) { \ - (X)->out_next_byte = (X)->out_current_data[(X)->out_current_offset]; \ - (X)->out_current_offset++; \ - (X)->out_stream_offset++; \ -} else { \ - return HTP_DATA; \ -} \ -\ -if ((X)->out_line_len < (X)->out_line_size) { \ - (X)->out_line[(X)->out_line_len] = (X)->out_next_byte; \ - (X)->out_line_len++; \ - if (((X)->out_line_len == HTP_HEADER_LIMIT_SOFT)&&(!((X)->out_tx->flags & HTP_FIELD_LONG))) { \ - (X)->out_tx->flags |= HTP_FIELD_LONG; \ - htp_log((X), HTP_LOG_MARK, HTP_LOG_ERROR, HTP_LINE_TOO_LONG_SOFT, "Response field over soft limit"); \ - } \ -} else { \ - htp_log((X), HTP_LOG_MARK, HTP_LOG_ERROR, HTP_LINE_TOO_LONG_HARD, "Response field over hard limit"); \ - return HTP_ERROR; \ -} - -typedef uint32_t htp_time_t; - -// -- Data structures ----------------------------------------------------------------------------- - -struct htp_cfg_t { - /** Hard field limit length. If the parser encounters a line that's longer - * than this value it will give up parsing. Do note that the line limit - * is not the same thing as header length limit. Because of header folding, - * a header can end up being longer than the line limit. - */ - size_t field_limit_hard; - - /** Soft field limit length. If this limit is reached the parser will issue - * a warning but continue to run. - */ - size_t field_limit_soft; - - /** Log level, which will be used when deciding whether to store or - * ignore the messages issued by the parser. - */ - int log_level; - - /** - * Server personality ID. - */ - int spersonality; - - /** The function used for request line parsing. Depends on the personality. */ - int (*parse_request_line)(htp_connp_t *connp); - - /** The function used for response line parsing. Depends on the personality. */ - int (*parse_response_line)(htp_connp_t *connp); - - /** The function used for request header parsing. Depends on the personality. */ - int (*process_request_header)(htp_connp_t *connp); - - /** The function used for response header parsing. Depends on the personality. */ - int (*process_response_header)(htp_connp_t *connp); - - - // Path handling - - /** Should we treat backslash characters as path segment separators? */ - int path_backslash_separators; - int query_backslash_separators; - - /** Should we treat paths as case insensitive? */ - int path_case_insensitive; - int query_case_insensitive; - - /** Should we compress multiple path segment separators into one? */ - int path_compress_separators; - int query_compress_separators; - - /** This parameter is used to predict how a server will react when control - * characters are present in a request path, but does not affect path - * normalization. - */ - int path_control_char_handling; - int query_control_char_handling; - - /** Should the parser convert UTF-8 into a single-byte stream, using - * best-fit? - */ - int path_convert_utf8; - - /** Should we URL-decode encoded path segment separators? */ - int path_decode_separators; - int query_decode_separators; - - /** Should we decode %u-encoded characters? */ - int path_decode_u_encoding; - int query_decode_u_encoding; - - /** How do handle invalid encodings: URL_DECODER_LEAVE_PERCENT, - * URL_DECODER_REMOVE_PERCENT or URL_DECODER_DECODE_INVALID. - */ - int path_invalid_encoding_handling; - int query_invalid_encoding_handling; - - /** Controls how invalid UTF-8 characters are handled. */ - int path_invalid_utf8_handling; - - /** Controls how encoded NUL bytes are handled. */ - int path_nul_encoded_handling; - int query_nul_encoded_handling; - - /** Controls how raw NUL bytes are handled. */ - int path_nul_raw_handling; - int query_nul_raw_handling; - - /** The replacement character used when there is no best-fit mapping. */ - unsigned char path_replacement_char; - - /** How will the server handle UCS-2 characters? */ - int path_unicode_mapping; - - /** XXX Unused */ - int path_utf8_overlong_handling; - - /** The best-fit map to use to decode %u-encoded characters. */ - unsigned char *path_u_bestfit_map; - - /** Whether to generate the request_uri_normalized field. */ - int generate_request_uri_normalized; - - - // Hooks - - /** Transaction start hook, invoked when the parser receives the first - * byte of a new transaction. - */ - htp_hook_t *hook_transaction_start; - - /** Request line hook, invoked after a request line has been parsed. */ - htp_hook_t *hook_request_line; - - /** Request URI normalization hook, for overriding default normalization of URI. */ - htp_hook_t *hook_request_uri_normalize; - - /** Request headers hook, invoked after all request headers are seen. */ - htp_hook_t *hook_request_headers; - - /** Request body data hook, invoked every time body data is available. Chunked data - * will be dechunked and compressed data will be decompressed (not implemented at present) - * before the data is passed to this hook. - */ - htp_hook_t *hook_request_body_data; - - /** Request trailer hook, invoked after all trailer headers are seen, - * and if they are seen (not invoked otherwise). - */ - htp_hook_t *hook_request_trailer; - - /** Request hook, invoked after a complete request is seen. */ - htp_hook_t *hook_request; - - /** Response line hook, invoked after a response line has been parsed. */ - htp_hook_t *hook_response_line; - - /** Response headers book, invoked after all response headers have been seen. */ - htp_hook_t *hook_response_headers; - - /** Response body data hook, invoked whenever a chunk of response data is available. Chunked - * data will be dechunked and compressed data will be decompressed (not implemented - * at present) before the data is passed to this hook.*/ - htp_hook_t *hook_response_body_data; - - /** Response trailer hook, invoked after all trailer headers have been processed, - * and only if the trailer exists. - */ - htp_hook_t *hook_response_trailer; - - /** Response hook, invoked after a response has been seen. There isn't a separate - * transaction hook, use this hook to do something whenever a transaction is - * complete. - */ - htp_hook_t *hook_response; - - /** - * Log hook, invoked every time the library wants to log. - */ - htp_hook_t *hook_log; - - /** Opaque user data associated with this configuration structure. */ - void *user_data; -}; - -struct htp_conn_t { - /** Connection parser associated with this connection. */ - htp_connp_t *connp; - - /** Remote IP address. */ - char *remote_addr; - - /** Remote port. */ - int remote_port; - - /** Local IP address. */ - char *local_addr; - - /** Local port. */ - int local_port; - - /** Transactions carried out on this connection. The list may contain - * NULL elements when some of the transactions are deleted (and then - * removed from a connection by calling htp_conn_remove_tx(). - */ - list_t *transactions; - - /** Log messages associated with this connection. */ - list_t *messages; - - /** Parsing flags: PIPELINED_CONNECTION. */ - unsigned int flags; - - /** When was this connection opened? */ - htp_time_t open_timestamp; - - /** When was this connection closed? */ - htp_time_t close_timestamp; - - /** Inbound data counter. */ - size_t in_data_counter; - - /** Outbound data counter. */ - size_t out_data_counter; - - /** Inbound packet counter. */ - size_t in_packet_counter; - - /** Outbound packet counter. */ - size_t out_packet_counter; -}; - -struct htp_connp_t { - // General fields - - /** Current parser configuration structure. */ - htp_cfg_t *cfg; - - /** Is the configuration structure only used with this connection - * parser? If it is, then it can be changed as parsing goes on, - * and destroyed along with the parser in the end. - */ - int is_cfg_private; - - /** The connection structure associated with this parser. */ - htp_conn_t *conn; - - /** Opaque user data associated with this parser. */ - void *user_data; - - /** On parser failure, this field will contain the error information. Do note, however, - * that the value in this field will only be valid immediately after an error condition, - * but it is not guaranteed to remain valid if the parser is invoked again. - */ - htp_log_t *last_error; - - // Request parser fields - - /** Parser inbound status. Starts as HTP_OK, but may turn into HTP_ERROR. */ - unsigned int in_status; - - /** Parser output status. Starts as HTP_OK, but may turn into HTP_ERROR. */ - unsigned int out_status; - - /** The time when the last request data chunk was received. */ - htp_time_t in_timestamp; - - /** Pointer to the current request data chunk. */ - unsigned char *in_current_data; - - /** The length of the current request data chunk. */ - int64_t in_current_len; - - /** The offset of the next byte in the request data chunk to consume. */ - int64_t in_current_offset; - - /** How many data chunks does the inbound connection stream consist of? */ - size_t in_chunk_count; - - /** The index of the first chunk used in the current request. */ - size_t in_chunk_request_index; - - /** The offset, in the entire connection stream, of the next request byte. */ - int64_t in_stream_offset; - - /** The value of the request byte currently being processed. */ - int in_next_byte; - - /** Pointer to the request line buffer. */ - unsigned char *in_line; - - /** Size of the request line buffer. */ - size_t in_line_size; - - /** Lenght of the current request line. */ - size_t in_line_len; - - /** Ongoing inbound transaction. */ - htp_tx_t *in_tx; - - /** The request header line currently being processed. */ - htp_header_line_t *in_header_line; - - /** The index, in the structure holding all request header lines, of the - * line with which the current header begins. The header lines are - * kept in the transaction structure. - */ - int in_header_line_index; - - /** How many lines are there in the current request header? */ - int in_header_line_counter; - - /** - * The request body length declared in a valid request headers. The key here - * is "valid". This field will not be populated if a request contains both - * a Transfer-Encoding header and a Content-Lenght header. - */ - int64_t in_content_length; - - /** Holds the remaining request body length that we expect to read. This - * field will be available only when the length of a request body is known - * in advance, i.e. when request headers contain a Content-Length header. - */ - int64_t in_body_data_left; - - /** Holds the amount of data that needs to be read from the - * current data chunk. Only used with chunked request bodies. - */ - int in_chunked_length; - - /** Current request parser state. */ - int (*in_state)(htp_connp_t *); - - // Response parser fields - - /** Response counter, incremented with every new response. This field is - * used to match responses to requests. The expectation is that for every - * response there will already be a transaction (request) waiting. - */ - size_t out_next_tx_index; - - /** The time when the last response data chunk was received. */ - htp_time_t out_timestamp; - - /** Pointer to the current response data chunk. */ - unsigned char *out_current_data; - - /** The length of the current response data chunk. */ - int64_t out_current_len; - - /** The offset of the next byte in the response data chunk to consume. */ - int64_t out_current_offset; - - /** The offset, in the entire connection stream, of the next response byte. */ - int64_t out_stream_offset; - - /** The value of the response byte currently being processed. */ - int out_next_byte; - - /** Pointer to the response line buffer. */ - unsigned char *out_line; - - /** Size of the response line buffer. */ - size_t out_line_size; - - /** Lenght of the current response line. */ - size_t out_line_len; - - /** Ongoing outbound transaction */ - htp_tx_t *out_tx; - - /** The response header line currently being processed. */ - htp_header_line_t *out_header_line; - - /** The index, in the structure holding all response header lines, of the - * line with which the current header begins. The header lines are - * kept in the transaction structure. - */ - int out_header_line_index; - - /** How many lines are there in the current response header? */ - int out_header_line_counter; - - /** - * The length of the current response body as presented in the - * Content-Length response header. - */ - int64_t out_content_length; - - /** The remaining length of the current response body, if known. */ - int64_t out_body_data_left; - - /** Holds the amount of data that needs to be read from the - * current response data chunk. Only used with chunked response bodies. - */ - int out_chunked_length; - - /** Current response parser state. */ - int (*out_state)(htp_connp_t *); - - /** Response decompressor used to decompress response body data. */ - htp_decompressor_t *out_decompressor; -}; - -struct htp_log_t { - /** The connection parser associated with this log message. */ - htp_connp_t *connp; - - /** The transaction associated with this log message, if any. */ - htp_tx_t *tx; - - /** Log message. */ - const char *msg; - - /** Message level. */ - int level; - - /** Message code. */ - int code; - - /** File in which the code that emitted the message resides. */ - const char *file; - - /** Line number on which the code that emitted the message resides. */ - unsigned int line; -}; - -struct htp_header_line_t { - /** Header line data. */ - bstr *line; - - /** Offset at which header name begins, if applicable. */ - size_t name_offset; - - /** Header name length, if applicable. */ - size_t name_len; - - /** Offset at which header value begins, if applicable. */ - size_t value_offset; - - /** Value length, if applicable. */ - size_t value_len; - - /** How many NUL bytes are there on this header line? */ - unsigned int has_nulls; - - /** The offset of the first NUL byte, or -1. */ - int first_nul_offset; - - /** Parsing flags: HTP_FIELD_INVALID_NOT_FATAL, HTP_FIELD_INVALID_FATAL, HTP_FIELD_LONG */ - unsigned int flags; - - /** terminator characters, if NULL assume RFC compliant 0d 0a */ - bstr *terminators; - - /** Header that uses this line. */ - htp_header_t *header; -}; - -struct htp_header_t { - /** Header name. */ - bstr *name; - - /** Header value. */ - bstr *value; - - /** Parsing flags: HTP_FIELD_INVALID_NOT_FATAL, HTP_FIELD_FOLDED, HTP_FIELD_REPEATED */ - unsigned int flags; -}; - -struct htp_tx_t { - /** The connection parsed associated with this transaction. */ - htp_connp_t *connp; - - /** The connection to which this transaction belongs. */ - htp_conn_t *conn; - - /** The configuration structure associated with this transaction. */ - htp_cfg_t *cfg; - - /** Is the configuration structure shared with other transactions or connections? As - * a rule of thumb transactions will initially share their configuration structure, but - * copy-on-write may be used when an attempt to modify configuration is detected. - */ - int is_cfg_shared; - - /** The user data associated with this transaction. */ - void *user_data; - - // Request - unsigned int request_ignored_lines; - - /** The first line of this request. */ - bstr *request_line; - - /** How many NUL bytes are there in the request line? */ - int request_line_nul; - - /** The offset of the first NUL byte. */ - int request_line_nul_offset; - - /** Request method. */ - bstr *request_method; - - /** Request method, as number. Available only if we were able to recognize the request method. */ - int request_method_number; - - /** Request URI, raw, as given to us on the request line. */ - bstr *request_uri; - - /** - * Normalized request URI as a single string. The availability of this - * field depends on configuration. Use htp_config_set_generate_request_uri_normalized() - * to ask for the field to be generated. - */ - bstr *request_uri_normalized; - - /** Request protocol, as text. */ - bstr *request_protocol; - - /** Protocol version as a number: -1 means unknown, 9 (HTTP_0_9) means 0.9, - * 100 (HTTP_1_0) means 1.0 and 101 (HTTP_1_1) means 1.1. - */ - int request_protocol_number; - - /** Is this request using a short-style HTTP/0.9 request? */ - int protocol_is_simple; - - /** This structure holds a parsed request_uri, with the missing information - * added (e.g., adding port number from the TCP information) and the fields - * normalized. This structure should be used to make decisions about a request. - * To inspect raw data, either use request_uri, or parsed_uri_incomplete. - */ - htp_uri_t *parsed_uri; - - /** This structure holds the individual components parsed out of the request URI. No - * attempt is made to normalize the contents or replace the missing pieces with - * defaults. The purpose of this field is to allow you to look at the data as it - * was supplied. Use parsed_uri when you need to act on data. Note that this field - * will never have the port as a number. - */ - htp_uri_t *parsed_uri_incomplete; - - /** The actual message length (the length _after_ transformations - * have been applied). This field will change as a request body is being - * received, with the final value available once the entire body has - * been received. - */ - size_t request_message_len; - - /** The actual entity length (the length _before_ transformations - * have been applied). This field will change as a request body is being - * received, with the final value available once the entire body has - * been received. - */ - size_t request_entity_len; - - /** TODO The length of the data transmitted in a request body, minus the length - * of the files (if any). At worst, this field will be equal to the entity - * length if the entity encoding is not recognized. If we recognise the encoding - * (e.g., if it is application/x-www-form-urlencoded or multipart/form-data), the - * decoder may be able to separate the data from everything else, in which case - * the value in this field will be lower. - */ - size_t request_nonfiledata_len; - - /** TODO The length of the files uploaded using multipart/form-data, or in a - * request that uses PUT (in which case this field will be equal to the - * entity length field). This field will be zero in all other cases. - */ - size_t request_filedata_len; - - /** Original request header lines. This list stores instances of htp_header_line_t. */ - list_t *request_header_lines; - - /** Parsed request headers. */ - table_t *request_headers; - - /** Contains raw request headers. This field is generated on demand, use - * htp_tx_get_request_headers_raw() to get it. - */ - bstr *request_headers_raw; - - /** How many request header lines have been included in the raw - * buffer (above). - */ - size_t request_headers_raw_lines; - - - /** Request transfer coding: IDENTITY or CHUNKED. Only available on requests that have bodies. */ - int request_transfer_coding; - - /** Compression; currently COMPRESSION_NONE or COMPRESSION_GZIP. */ - int request_content_encoding; - - // Response - - /** How many empty lines did we ignore before reaching the status line? */ - unsigned int response_ignored_lines; - - /** Response line. */ - bstr *response_line; - - /** Response protocol, as text. */ - bstr *response_protocol; - - /** Response protocol as number. Only available if we were - * able to parse the protocol version. - */ - int response_protocol_number; - - /** Response status code, as text. */ - bstr *response_status; - - /** Reponse status code, available only if we were able to parse it. */ - int response_status_number; - - /** This field is set by the protocol decoder with it thinks that the - * backend server will reject a request with a particular status code. - */ - int response_status_expected_number; - - /** The message associated with the response status code. */ - bstr *response_message; - - /** Have we seen the server respond with a 100 response? */ - int seen_100continue; - - /** Original response header lines. */ - list_t *response_header_lines; - - /** Parsed response headers. */ - table_t *response_headers; - - /** Contains raw response headers. This field is generated on demand, use - * htp_tx_get_response_headers_raw() to get it. - */ - bstr *response_headers_raw; - - /** How many response header lines have been included in the raw - * buffer (above). - */ - size_t response_headers_raw_lines; - - /** The actual message length (the length _after_ transformations - * have been applied). This field will change as a request body is being - * received, with the final value available once the entire body has - * been received. - */ - size_t response_message_len; - - /** The actual entity length (the length _before_ transformations - * have been applied). This field will change as a request body is being - * received, with the final value available once the entire body has - * been received. - */ - size_t response_entity_len; - - /** Response transfer coding: IDENTITY or CHUNKED. Only available on responses that have bodies. */ - int response_transfer_coding; - - /** Compression; currently COMPRESSION_NONE or COMPRESSION_GZIP. */ - int response_content_encoding; - - // Common - - /** Parsing flags: HTP_INVALID_CHUNKING, HTP_INVALID_FOLDING, - * HTP_REQUEST_SMUGGLING, HTP_MULTI_PACKET_HEAD. - */ - unsigned int flags; - - /** Transaction progress. Look for the TX_PROGRESS_* constants for more information. */ - unsigned int progress[2]; -}; - -/** This structure is used to pass transaction data to callbacks. */ -struct htp_tx_data_t { - /** Transaction pointer. */ - htp_tx_t *tx; - - /** Pointer to the data buffer. */ - unsigned char *data; - - /** Buffer length. */ - size_t len; -}; - -/** URI structure. Each of the fields provides access to a single - * URI element. A typical URI will look like this: - * http://username:password@hostname.com:8080/path?query#fragment. - */ -struct htp_uri_t { - /** Scheme */ - bstr *scheme; - - /** Username */ - bstr *username; - - /** Password */ - bstr *password; - - /** Hostname */ - bstr *hostname; - - /** Port, as string */ - bstr *port; - - /** Port, as number, but only if the port is valid. */ - int port_number; - - /** The path part of this URI */ - bstr *path; - - /** Query string */ - bstr *query; - - /** Fragment identifier */ - bstr *fragment; -}; - -// -- Functions ----------------------------------------------------------------------------------- - -const char *htp_get_version(); - -htp_cfg_t *htp_config_copy(htp_cfg_t *cfg); -htp_cfg_t *htp_config_create(); - void htp_config_destroy(htp_cfg_t *cfg); - -void htp_config_register_transaction_start(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)); -void htp_config_register_request_line(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)); -void htp_config_register_request_uri_normalize(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)); -void htp_config_register_request_headers(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)); -void htp_config_register_request_body_data(htp_cfg_t *cfg, int (*callback_fn)(htp_tx_data_t *)); -void htp_config_register_request_trailer(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)); -void htp_config_register_request(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)); - -void htp_config_register_response_line(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)); -void htp_config_register_response_headers(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)); -void htp_config_register_response_body_data(htp_cfg_t *cfg, int (*callback_fn)(htp_tx_data_t *)); -void htp_config_register_response_trailer(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)); -void htp_config_register_response(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)); - -void htp_config_register_log(htp_cfg_t *cfg, int (*callback_fn)(htp_log_t *)); - - int htp_config_set_server_personality(htp_cfg_t *cfg, int personality); - -void htp_config_set_bestfit_map(htp_cfg_t *cfg, unsigned char *map); -void htp_config_set_path_backslash_separators(htp_cfg_t *cfg, int backslash_separators); -void htp_config_set_query_backslash_separators(htp_cfg_t *cfg, int backslash_separators); -void htp_config_set_path_case_insensitive(htp_cfg_t *cfg, int path_case_insensitive); -void htp_config_set_query_case_insensitive(htp_cfg_t *cfg, int case_insensitive); -void htp_config_set_path_compress_separators(htp_cfg_t *cfg, int compress_separators); -void htp_config_set_query_compress_separators(htp_cfg_t *cfg, int compress_separators); -void htp_config_set_path_control_char_handling(htp_cfg_t *cfg, int control_char_handling); -void htp_config_set_query_control_char_handling(htp_cfg_t *cfg, int control_char_handling); -void htp_config_set_path_convert_utf8(htp_cfg_t *cfg, int convert_utf8); -void htp_config_set_path_decode_separators(htp_cfg_t *cfg, int backslash_separators); -void htp_config_set_query_decode_separators(htp_cfg_t *cfg, int decode_separators); -void htp_config_set_path_decode_u_encoding(htp_cfg_t *cfg, int decode_u_encoding); -void htp_config_set_query_decode_u_encoding(htp_cfg_t *cfg, int decode_u_encoding); -void htp_config_set_path_invalid_encoding_handling(htp_cfg_t *cfg, int invalid_encoding_handling); -void htp_config_set_query_invalid_encoding_handling(htp_cfg_t *cfg, int invalid_encoding_handling); -void htp_config_set_path_invalid_utf8_handling(htp_cfg_t *cfg, int invalid_utf8_handling); -void htp_config_set_path_nul_encoded_handling(htp_cfg_t *cfg, int nul_encoded_handling); -void htp_config_set_query_nul_encoded_handling(htp_cfg_t *cfg, int nul_encoded_handling); -void htp_config_set_path_nul_raw_handling(htp_cfg_t *cfg, int nul_raw_handling); -void htp_config_set_query_nul_raw_handling(htp_cfg_t *cfg, int nul_raw_handling); -void htp_config_set_path_replacement_char(htp_cfg_t *cfg, int replacement_char); -void htp_config_set_path_unicode_mapping(htp_cfg_t *cfg, int unicode_mapping); - -void htp_config_set_generate_request_uri_normalized(htp_cfg_t *cfg, int generate); - - -htp_connp_t *htp_connp_create(htp_cfg_t *cfg); -htp_connp_t *htp_connp_create_copycfg(htp_cfg_t *cfg); -void htp_connp_open(htp_connp_t *connp, const char *remote_addr, int remote_port, const char *local_addr, int local_port, htp_time_t timestamp); -void htp_connp_close(htp_connp_t *connp, htp_time_t timestamp); -void htp_connp_destroy(htp_connp_t *connp); -void htp_connp_destroy_all(htp_connp_t *connp); - - void htp_connp_set_user_data(htp_connp_t *connp, void *user_data); -void *htp_connp_get_user_data(htp_connp_t *connp); - -htp_conn_t *htp_conn_create(htp_connp_t *connp); - void htp_conn_destroy(htp_conn_t *conn); - int htp_conn_remove_tx(htp_conn_t *conn, htp_tx_t *tx); - - int htp_connp_req_data(htp_connp_t *connp, htp_time_t timestamp, unsigned char *data, size_t len); -size_t htp_connp_req_data_consumed(htp_connp_t *connp); - int htp_connp_res_data(htp_connp_t *connp, htp_time_t timestamp, unsigned char *data, size_t len); -size_t htp_connp_res_data_consumed(htp_connp_t *connp); - - void htp_connp_clear_error(htp_connp_t *connp); -htp_log_t *htp_connp_get_last_error(htp_connp_t *connp); - -htp_header_t *htp_connp_header_parse(htp_connp_t *, unsigned char *, size_t); - -#define CFG_NOT_SHARED 0 -#define CFG_SHARED 1 - -htp_tx_t *htp_tx_create(htp_cfg_t *cfg, int is_cfg_shared, htp_conn_t *conn); - void htp_tx_destroy(htp_tx_t *tx); - void htp_tx_set_config(htp_tx_t *tx, htp_cfg_t *cfg, int is_cfg_shared); - - void htp_tx_set_user_data(htp_tx_t *tx, void *user_data); - void *htp_tx_get_user_data(htp_tx_t *tx); - - bstr *htp_tx_get_request_uri_normalized(htp_tx_t *tx); - -// Parsing functions - -int htp_parse_request_line_generic(htp_connp_t *connp); -int htp_parse_request_header_generic(htp_connp_t *connp, htp_header_t *h, unsigned char *data, size_t len); -int htp_process_request_header_generic(htp_connp_t *); - -int htp_parse_request_header_apache_2_2(htp_connp_t *connp, htp_header_t *h, unsigned char *data, size_t len); -int htp_parse_request_line_apache_2_2(htp_connp_t *connp); -int htp_process_request_header_apache_2_2(htp_connp_t *); - -int htp_parse_response_line_generic(htp_connp_t *connp); -int htp_process_response_header_generic(htp_connp_t *connp); - -// Parser states - -int htp_connp_REQ_IDLE(htp_connp_t *connp); -int htp_connp_REQ_LINE(htp_connp_t *connp); -int htp_connp_REQ_PROTOCOL(htp_connp_t *connp); -int htp_connp_REQ_HEADERS(htp_connp_t *connp); -int htp_connp_REQ_BODY_DETERMINE(htp_connp_t *connp); -int htp_connp_REQ_BODY_IDENTITY(htp_connp_t *connp); -int htp_connp_REQ_BODY_CHUNKED_LENGTH(htp_connp_t *connp); -int htp_connp_REQ_BODY_CHUNKED_DATA(htp_connp_t *connp); -int htp_connp_REQ_BODY_CHUNKED_DATA_END(htp_connp_t *connp); - -int htp_connp_REQ_CONNECT_CHECK(htp_connp_t *connp); -int htp_connp_REQ_CONNECT_WAIT_RESPONSE(htp_connp_t *connp); - -int htp_connp_RES_IDLE(htp_connp_t *connp); -int htp_connp_RES_LINE(htp_connp_t *connp); -int htp_connp_RES_HEADERS(htp_connp_t *connp); -int htp_connp_RES_BODY_DETERMINE(htp_connp_t *connp); -int htp_connp_RES_BODY_IDENTITY(htp_connp_t *connp); -int htp_connp_RES_BODY_CHUNKED_LENGTH(htp_connp_t *connp); -int htp_connp_RES_BODY_CHUNKED_DATA(htp_connp_t *connp); -int htp_connp_RES_BODY_CHUNKED_DATA_END(htp_connp_t *connp); - -// Utility functions - -int htp_convert_method_to_number(bstr *); -int htp_is_lws(int c); -int htp_is_separator(int c); -int htp_is_text(int c); -int htp_is_token(int c); -int htp_chomp(unsigned char *data, size_t *len); -int htp_is_space(int c); - -int htp_parse_protocol(bstr *protocol); - -int htp_is_line_empty(unsigned char *data, size_t len); -int htp_is_line_whitespace(unsigned char *data, size_t len); - -int htp_connp_is_line_folded(unsigned char *data, size_t len); -int htp_connp_is_line_terminator(htp_connp_t *connp, unsigned char *data, size_t len); -int htp_connp_is_line_ignorable(htp_connp_t *connp, unsigned char *data, size_t len); - -int htp_parse_uri(bstr *input, htp_uri_t **uri); -int htp_parse_authority(htp_connp_t *connp, bstr *input, htp_uri_t **uri); -int htp_normalize_parsed_uri(htp_connp_t *connp, htp_uri_t *parsed_uri_incomplete, htp_uri_t *parsed_uri); -bstr *htp_normalize_hostname_inplace(bstr *input); -void htp_replace_hostname(htp_connp_t *connp, htp_uri_t *parsed_uri, bstr *hostname); - -int htp_decode_path_inplace(htp_cfg_t *cfg, htp_tx_t *tx, bstr *path); -int htp_decode_query_inplace(htp_cfg_t *cfg, htp_tx_t *tx, bstr *path); - -void htp_uriencoding_normalize_inplace(bstr *s); - - int htp_prenormalize_uri_path_inplace(bstr *s, int *flags, int case_insensitive, int backslash, int decode_separators, int remove_consecutive); -void htp_normalize_uri_path_inplace(bstr *s); - -void htp_utf8_decode_path_inplace(htp_cfg_t *cfg, htp_tx_t *tx, bstr *path); -void htp_utf8_validate_path(htp_tx_t *tx, bstr *path); - -int htp_parse_content_length(bstr *b); -int htp_parse_chunked_length(unsigned char *data, size_t len); -int htp_parse_positive_integer_whitespace(unsigned char *data, size_t len, int base); -int htp_parse_status(bstr *status); - -void htp_log(htp_connp_t *connp, const char *file, int line, int level, int code, const char *fmt, ...); -void htp_print_log(FILE *stream, htp_log_t *log); - -void fprint_raw_data(FILE *stream, const char *name, unsigned char *data, size_t len); - -char *htp_connp_in_state_as_string(htp_connp_t *connp); -char *htp_connp_out_state_as_string(htp_connp_t *connp); -char *htp_tx_progress_as_string(htp_tx_t *tx, int direction); - -bstr *htp_unparse_uri_noencode(htp_uri_t *uri); - -bstr *htp_tx_get_request_headers_raw(htp_tx_t *tx); -bstr *htp_tx_get_response_headers_raw(htp_tx_t *tx); - -#endif /* _HTP_H */ - - diff --git a/libhtp/htp/htp_config.c b/libhtp/htp/htp_config.c deleted file mode 100644 index bceba1f075..0000000000 --- a/libhtp/htp/htp_config.c +++ /dev/null @@ -1,886 +0,0 @@ -/* - * LibHTP (http://www.libhtp.org) - * Copyright 2009,2010 Ivan Ristic - * - * LibHTP is an open source product, released under terms of the General Public Licence - * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text - * of the license. - * - * In addition, there is a special exception that allows LibHTP to be freely - * used with any OSI-approved open source licence. Please refer to the file - * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. - * - */ - -#include "htp.h" - -/** - * This map is used by default for best-fit mapping from the Unicode - * values U+0100-FFFF. - */ -static unsigned char bestfit_1252[] = -{ 0x01, 0x00, 0x41, 0x01, 0x01, 0x61, 0x01, 0x02, 0x41, 0x01, 0x03, 0x61, - 0x01, 0x04, 0x41, 0x01, 0x05, 0x61, 0x01, 0x06, 0x43, 0x01, 0x07, 0x63, - 0x01, 0x08, 0x43, 0x01, 0x09, 0x63, 0x01, 0x0a, 0x43, 0x01, 0x0b, 0x63, - 0x01, 0x0c, 0x43, 0x01, 0x0d, 0x63, 0x01, 0x0e, 0x44, 0x01, 0x0f, 0x64, - 0x01, 0x11, 0x64, 0x01, 0x12, 0x45, 0x01, 0x13, 0x65, 0x01, 0x14, 0x45, - 0x01, 0x15, 0x65, 0x01, 0x16, 0x45, 0x01, 0x17, 0x65, 0x01, 0x18, 0x45, - 0x01, 0x19, 0x65, 0x01, 0x1a, 0x45, 0x01, 0x1b, 0x65, 0x01, 0x1c, 0x47, - 0x01, 0x1d, 0x67, 0x01, 0x1e, 0x47, 0x01, 0x1f, 0x67, 0x01, 0x20, 0x47, - 0x01, 0x21, 0x67, 0x01, 0x22, 0x47, 0x01, 0x23, 0x67, 0x01, 0x24, 0x48, - 0x01, 0x25, 0x68, 0x01, 0x26, 0x48, 0x01, 0x27, 0x68, 0x01, 0x28, 0x49, - 0x01, 0x29, 0x69, 0x01, 0x2a, 0x49, 0x01, 0x2b, 0x69, 0x01, 0x2c, 0x49, - 0x01, 0x2d, 0x69, 0x01, 0x2e, 0x49, 0x01, 0x2f, 0x69, 0x01, 0x30, 0x49, - 0x01, 0x31, 0x69, 0x01, 0x34, 0x4a, 0x01, 0x35, 0x6a, 0x01, 0x36, 0x4b, - 0x01, 0x37, 0x6b, 0x01, 0x39, 0x4c, 0x01, 0x3a, 0x6c, 0x01, 0x3b, 0x4c, - 0x01, 0x3c, 0x6c, 0x01, 0x3d, 0x4c, 0x01, 0x3e, 0x6c, 0x01, 0x41, 0x4c, - 0x01, 0x42, 0x6c, 0x01, 0x43, 0x4e, 0x01, 0x44, 0x6e, 0x01, 0x45, 0x4e, - 0x01, 0x46, 0x6e, 0x01, 0x47, 0x4e, 0x01, 0x48, 0x6e, 0x01, 0x4c, 0x4f, - 0x01, 0x4d, 0x6f, 0x01, 0x4e, 0x4f, 0x01, 0x4f, 0x6f, 0x01, 0x50, 0x4f, - 0x01, 0x51, 0x6f, 0x01, 0x54, 0x52, 0x01, 0x55, 0x72, 0x01, 0x56, 0x52, - 0x01, 0x57, 0x72, 0x01, 0x58, 0x52, 0x01, 0x59, 0x72, 0x01, 0x5a, 0x53, - 0x01, 0x5b, 0x73, 0x01, 0x5c, 0x53, 0x01, 0x5d, 0x73, 0x01, 0x5e, 0x53, - 0x01, 0x5f, 0x73, 0x01, 0x62, 0x54, 0x01, 0x63, 0x74, 0x01, 0x64, 0x54, - 0x01, 0x65, 0x74, 0x01, 0x66, 0x54, 0x01, 0x67, 0x74, 0x01, 0x68, 0x55, - 0x01, 0x69, 0x75, 0x01, 0x6a, 0x55, 0x01, 0x6b, 0x75, 0x01, 0x6c, 0x55, - 0x01, 0x6d, 0x75, 0x01, 0x6e, 0x55, 0x01, 0x6f, 0x75, 0x01, 0x70, 0x55, - 0x01, 0x71, 0x75, 0x01, 0x72, 0x55, 0x01, 0x73, 0x75, 0x01, 0x74, 0x57, - 0x01, 0x75, 0x77, 0x01, 0x76, 0x59, 0x01, 0x77, 0x79, 0x01, 0x79, 0x5a, - 0x01, 0x7b, 0x5a, 0x01, 0x7c, 0x7a, 0x01, 0x80, 0x62, 0x01, 0x97, 0x49, - 0x01, 0x9a, 0x6c, 0x01, 0x9f, 0x4f, 0x01, 0xa0, 0x4f, 0x01, 0xa1, 0x6f, - 0x01, 0xab, 0x74, 0x01, 0xae, 0x54, 0x01, 0xaf, 0x55, 0x01, 0xb0, 0x75, - 0x01, 0xb6, 0x7a, 0x01, 0xc0, 0x7c, 0x01, 0xc3, 0x21, 0x01, 0xcd, 0x41, - 0x01, 0xce, 0x61, 0x01, 0xcf, 0x49, 0x01, 0xd0, 0x69, 0x01, 0xd1, 0x4f, - 0x01, 0xd2, 0x6f, 0x01, 0xd3, 0x55, 0x01, 0xd4, 0x75, 0x01, 0xd5, 0x55, - 0x01, 0xd6, 0x75, 0x01, 0xd7, 0x55, 0x01, 0xd8, 0x75, 0x01, 0xd9, 0x55, - 0x01, 0xda, 0x75, 0x01, 0xdb, 0x55, 0x01, 0xdc, 0x75, 0x01, 0xde, 0x41, - 0x01, 0xdf, 0x61, 0x01, 0xe4, 0x47, 0x01, 0xe5, 0x67, 0x01, 0xe6, 0x47, - 0x01, 0xe7, 0x67, 0x01, 0xe8, 0x4b, 0x01, 0xe9, 0x6b, 0x01, 0xea, 0x4f, - 0x01, 0xeb, 0x6f, 0x01, 0xec, 0x4f, 0x01, 0xed, 0x6f, 0x01, 0xf0, 0x6a, - 0x02, 0x61, 0x67, 0x02, 0xb9, 0x27, 0x02, 0xba, 0x22, 0x02, 0xbc, 0x27, - 0x02, 0xc4, 0x5e, 0x02, 0xc8, 0x27, 0x02, 0xcb, 0x60, 0x02, 0xcd, 0x5f, - 0x03, 0x00, 0x60, 0x03, 0x02, 0x5e, 0x03, 0x03, 0x7e, 0x03, 0x0e, 0x22, - 0x03, 0x31, 0x5f, 0x03, 0x32, 0x5f, 0x03, 0x7e, 0x3b, 0x03, 0x93, 0x47, - 0x03, 0x98, 0x54, 0x03, 0xa3, 0x53, 0x03, 0xa6, 0x46, 0x03, 0xa9, 0x4f, - 0x03, 0xb1, 0x61, 0x03, 0xb4, 0x64, 0x03, 0xb5, 0x65, 0x03, 0xc0, 0x70, - 0x03, 0xc3, 0x73, 0x03, 0xc4, 0x74, 0x03, 0xc6, 0x66, 0x04, 0xbb, 0x68, - 0x05, 0x89, 0x3a, 0x06, 0x6a, 0x25, 0x20, 0x00, 0x20, 0x20, 0x01, 0x20, - 0x20, 0x02, 0x20, 0x20, 0x03, 0x20, 0x20, 0x04, 0x20, 0x20, 0x05, 0x20, - 0x20, 0x06, 0x20, 0x20, 0x10, 0x2d, 0x20, 0x11, 0x2d, 0x20, 0x17, 0x3d, - 0x20, 0x32, 0x27, 0x20, 0x35, 0x60, 0x20, 0x44, 0x2f, 0x20, 0x74, 0x34, - 0x20, 0x75, 0x35, 0x20, 0x76, 0x36, 0x20, 0x77, 0x37, 0x20, 0x78, 0x38, - 0x20, 0x7f, 0x6e, 0x20, 0x80, 0x30, 0x20, 0x81, 0x31, 0x20, 0x82, 0x32, - 0x20, 0x83, 0x33, 0x20, 0x84, 0x34, 0x20, 0x85, 0x35, 0x20, 0x86, 0x36, - 0x20, 0x87, 0x37, 0x20, 0x88, 0x38, 0x20, 0x89, 0x39, 0x20, 0xa7, 0x50, - 0x21, 0x02, 0x43, 0x21, 0x07, 0x45, 0x21, 0x0a, 0x67, 0x21, 0x0b, 0x48, - 0x21, 0x0c, 0x48, 0x21, 0x0d, 0x48, 0x21, 0x0e, 0x68, 0x21, 0x10, 0x49, - 0x21, 0x11, 0x49, 0x21, 0x12, 0x4c, 0x21, 0x13, 0x6c, 0x21, 0x15, 0x4e, - 0x21, 0x18, 0x50, 0x21, 0x19, 0x50, 0x21, 0x1a, 0x51, 0x21, 0x1b, 0x52, - 0x21, 0x1c, 0x52, 0x21, 0x1d, 0x52, 0x21, 0x24, 0x5a, 0x21, 0x28, 0x5a, - 0x21, 0x2a, 0x4b, 0x21, 0x2c, 0x42, 0x21, 0x2d, 0x43, 0x21, 0x2e, 0x65, - 0x21, 0x2f, 0x65, 0x21, 0x30, 0x45, 0x21, 0x31, 0x46, 0x21, 0x33, 0x4d, - 0x21, 0x34, 0x6f, 0x22, 0x12, 0x2d, 0x22, 0x15, 0x2f, 0x22, 0x16, 0x5c, - 0x22, 0x17, 0x2a, 0x22, 0x1a, 0x76, 0x22, 0x1e, 0x38, 0x22, 0x23, 0x7c, - 0x22, 0x29, 0x6e, 0x22, 0x36, 0x3a, 0x22, 0x3c, 0x7e, 0x22, 0x61, 0x3d, - 0x22, 0x64, 0x3d, 0x22, 0x65, 0x3d, 0x23, 0x03, 0x5e, 0x23, 0x20, 0x28, - 0x23, 0x21, 0x29, 0x23, 0x29, 0x3c, 0x23, 0x2a, 0x3e, 0x25, 0x00, 0x2d, - 0x25, 0x0c, 0x2b, 0x25, 0x10, 0x2b, 0x25, 0x14, 0x2b, 0x25, 0x18, 0x2b, - 0x25, 0x1c, 0x2b, 0x25, 0x2c, 0x2d, 0x25, 0x34, 0x2d, 0x25, 0x3c, 0x2b, - 0x25, 0x50, 0x2d, 0x25, 0x52, 0x2b, 0x25, 0x53, 0x2b, 0x25, 0x54, 0x2b, - 0x25, 0x55, 0x2b, 0x25, 0x56, 0x2b, 0x25, 0x57, 0x2b, 0x25, 0x58, 0x2b, - 0x25, 0x59, 0x2b, 0x25, 0x5a, 0x2b, 0x25, 0x5b, 0x2b, 0x25, 0x5c, 0x2b, - 0x25, 0x5d, 0x2b, 0x25, 0x64, 0x2d, 0x25, 0x65, 0x2d, 0x25, 0x66, 0x2d, - 0x25, 0x67, 0x2d, 0x25, 0x68, 0x2d, 0x25, 0x69, 0x2d, 0x25, 0x6a, 0x2b, - 0x25, 0x6b, 0x2b, 0x25, 0x6c, 0x2b, 0x25, 0x84, 0x5f, 0x27, 0x58, 0x7c, - 0x30, 0x00, 0x20, 0x30, 0x08, 0x3c, 0x30, 0x09, 0x3e, 0x30, 0x1a, 0x5b, - 0x30, 0x1b, 0x5d, 0xff, 0x01, 0x21, 0xff, 0x02, 0x22, 0xff, 0x03, 0x23, - 0xff, 0x04, 0x24, 0xff, 0x05, 0x25, 0xff, 0x06, 0x26, 0xff, 0x07, 0x27, - 0xff, 0x08, 0x28, 0xff, 0x09, 0x29, 0xff, 0x0a, 0x2a, 0xff, 0x0b, 0x2b, - 0xff, 0x0c, 0x2c, 0xff, 0x0d, 0x2d, 0xff, 0x0e, 0x2e, 0xff, 0x0f, 0x2f, - 0xff, 0x10, 0x30, 0xff, 0x11, 0x31, 0xff, 0x12, 0x32, 0xff, 0x13, 0x33, - 0xff, 0x14, 0x34, 0xff, 0x15, 0x35, 0xff, 0x16, 0x36, 0xff, 0x17, 0x37, - 0xff, 0x18, 0x38, 0xff, 0x19, 0x39, 0xff, 0x1a, 0x3a, 0xff, 0x1b, 0x3b, - 0xff, 0x1c, 0x3c, 0xff, 0x1d, 0x3d, 0xff, 0x1e, 0x3e, 0xff, 0x20, 0x40, - 0xff, 0x21, 0x41, 0xff, 0x22, 0x42, 0xff, 0x23, 0x43, 0xff, 0x24, 0x44, - 0xff, 0x25, 0x45, 0xff, 0x26, 0x46, 0xff, 0x27, 0x47, 0xff, 0x28, 0x48, - 0xff, 0x29, 0x49, 0xff, 0x2a, 0x4a, 0xff, 0x2b, 0x4b, 0xff, 0x2c, 0x4c, - 0xff, 0x2d, 0x4d, 0xff, 0x2e, 0x4e, 0xff, 0x2f, 0x4f, 0xff, 0x30, 0x50, - 0xff, 0x31, 0x51, 0xff, 0x32, 0x52, 0xff, 0x33, 0x53, 0xff, 0x34, 0x54, - 0xff, 0x35, 0x55, 0xff, 0x36, 0x56, 0xff, 0x37, 0x57, 0xff, 0x38, 0x58, - 0xff, 0x39, 0x59, 0xff, 0x3a, 0x5a, 0xff, 0x3b, 0x5b, 0xff, 0x3c, 0x5c, - 0xff, 0x3d, 0x5d, 0xff, 0x3e, 0x5e, 0xff, 0x3f, 0x5f, 0xff, 0x40, 0x60, - 0xff, 0x41, 0x61, 0xff, 0x42, 0x62, 0xff, 0x43, 0x63, 0xff, 0x44, 0x64, - 0xff, 0x45, 0x65, 0xff, 0x46, 0x66, 0xff, 0x47, 0x67, 0xff, 0x48, 0x68, - 0xff, 0x49, 0x69, 0xff, 0x4a, 0x6a, 0xff, 0x4b, 0x6b, 0xff, 0x4c, 0x6c, - 0xff, 0x4d, 0x6d, 0xff, 0x4e, 0x6e, 0xff, 0x4f, 0x6f, 0xff, 0x50, 0x70, - 0xff, 0x51, 0x71, 0xff, 0x52, 0x72, 0xff, 0x53, 0x73, 0xff, 0x54, 0x74, - 0xff, 0x55, 0x75, 0xff, 0x56, 0x76, 0xff, 0x57, 0x77, 0xff, 0x58, 0x78, - 0xff, 0x59, 0x79, 0xff, 0x5a, 0x7a, 0xff, 0x5b, 0x7b, 0xff, 0x5c, 0x7c, - 0xff, 0x5d, 0x7d, 0xff, 0x5e, 0x7e, 0x00, 0x00, 0x00 -}; - -/** - * Creates a new configuration structure. Configuration structures created at - * configuration time must not be changed afterwards in order to support lock-less - * copying. - * - * @return New configuration structure. - */ -htp_cfg_t *htp_config_create() { - htp_cfg_t *cfg = calloc(1, sizeof(htp_cfg_t)); - if (cfg == NULL) return NULL; - - cfg->field_limit_hard = HTP_HEADER_LIMIT_HARD; - cfg->field_limit_soft = HTP_HEADER_LIMIT_SOFT; - cfg->log_level = HTP_LOG_NOTICE; - - cfg->path_u_bestfit_map = bestfit_1252; - cfg->path_replacement_char = '?'; - - // No need to create hooks here; they will be created on-demand, - // during callback registration - - // Set the default personality before we return - htp_config_set_server_personality(cfg, HTP_SERVER_MINIMAL); - - return cfg; -} - -/** - * Creates a copy of the supplied configuration structure. The idea is to create - * one or more configuration objects at configuration-time, but to use this - * function to create per-connection copies. That way it will be possible to - * adjust per-connection configuration as necessary, without affecting the - * global configuration. Make sure no other thread changes the configuration - * object while this function is operating. - * - * @param cfg - * @return A copy of the configuration structure. - */ -htp_cfg_t *htp_config_copy(htp_cfg_t *cfg) { - htp_cfg_t *copy = malloc(sizeof(htp_cfg_t)); - if (copy == NULL) return NULL; - - *copy = *cfg; - - // Create copies of the hooks' structures - if (cfg->hook_transaction_start != NULL) { - copy->hook_transaction_start = hook_copy(cfg->hook_transaction_start); - if (copy->hook_transaction_start == NULL) { - free(copy); - return NULL; - } - } - - if (cfg->hook_request_line != NULL) { - copy->hook_request_line = hook_copy(cfg->hook_request_line); - if (copy->hook_request_line == NULL) { - free(copy); - return NULL; - } - } - - if (cfg->hook_request_uri_normalize != NULL) { - copy->hook_request_uri_normalize = hook_copy(cfg->hook_request_uri_normalize); - if (copy->hook_request_uri_normalize == NULL) { - free(copy); - return NULL; - } - } - - if (cfg->hook_request_headers != NULL) { - copy->hook_request_headers = hook_copy(cfg->hook_request_headers); - if (copy->hook_request_headers == NULL) { - free(copy); - return NULL; - } - } - - if (cfg->hook_request_body_data != NULL) { - copy->hook_request_body_data = hook_copy(cfg->hook_request_body_data); - if (copy->hook_request_body_data == NULL) { - free(copy); - return NULL; - } - } - - if (cfg->hook_request_trailer != NULL) { - copy->hook_request_trailer = hook_copy(cfg->hook_request_trailer); - if (copy->hook_request_trailer == NULL) { - free(copy); - return NULL; - } - } - - if (cfg->hook_request != NULL) { - copy->hook_request = hook_copy(cfg->hook_request); - if (copy->hook_request == NULL) { - free(copy); - return NULL; - } - } - - if (cfg->hook_response_line != NULL) { - copy->hook_response_line = hook_copy(cfg->hook_response_line); - if (copy->hook_response_line == NULL) { - free(copy); - return NULL; - } - } - - if (cfg->hook_response_headers != NULL) { - copy->hook_response_headers = hook_copy(cfg->hook_response_headers); - if (copy->hook_response_headers == NULL) { - free(copy); - return NULL; - } - } - - if (cfg->hook_response_body_data != NULL) { - copy->hook_response_body_data = hook_copy(cfg->hook_response_body_data); - if (copy->hook_response_body_data == NULL) { - free(copy); - return NULL; - } - } - - if (cfg->hook_response_trailer != NULL) { - copy->hook_response_trailer = hook_copy(cfg->hook_response_trailer); - if (copy->hook_response_trailer == NULL) { - free(copy); - return NULL; - } - } - - if (cfg->hook_response != NULL) { - copy->hook_response = hook_copy(cfg->hook_response); - if (copy->hook_response == NULL) { - free(copy); - return NULL; - } - } - - if (cfg->hook_log != NULL) { - copy->hook_log = hook_copy(cfg->hook_log); - if (copy->hook_log == NULL) { - free(copy); - return NULL; - } - } - - return copy; -} - -/** - * Destroy a configuration structure. - * - * @param cfg - */ -void htp_config_destroy(htp_cfg_t *cfg) { - // Destroy the hooks - hook_destroy(cfg->hook_transaction_start); - hook_destroy(cfg->hook_request_line); - hook_destroy(cfg->hook_request_uri_normalize); - hook_destroy(cfg->hook_request_headers); - hook_destroy(cfg->hook_request_body_data); - hook_destroy(cfg->hook_request_trailer); - hook_destroy(cfg->hook_request); - hook_destroy(cfg->hook_response_line); - hook_destroy(cfg->hook_response_headers); - hook_destroy(cfg->hook_response_body_data); - hook_destroy(cfg->hook_response_trailer); - hook_destroy(cfg->hook_response); - hook_destroy(cfg->hook_log); - - // Free the structure itself - free(cfg); -} - -/** - * Registers a transaction_start callback. - * - * @param cfg - * @param callback_fn - */ -void htp_config_register_transaction_start(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)) { - hook_register(&cfg->hook_transaction_start, callback_fn); -} - -/** - * Registers a request_line callback. - * - * @param cfg - * @param callback_fn - */ -void htp_config_register_request_line(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)) { - hook_register(&cfg->hook_request_line, callback_fn); -} - -/** - * Registers a request_uri_normalize callback. - * - * @param cfg - * @param callback_fn - */ -void htp_config_register_request_uri_normalize(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)) { - hook_register(&cfg->hook_request_uri_normalize, callback_fn); -} - -/** - * Registers a request_headers callback. - * - * @param cfg - * @param callback_fn - */ -void htp_config_register_request_headers(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)) { - hook_register(&cfg->hook_request_headers, callback_fn); -} - -/** - * Registers a request_trailer callback. - * - * @param cfg - * @param callback_fn - */ -void htp_config_register_request_trailer(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)) { - hook_register(&cfg->hook_request_trailer, callback_fn); -} - -/** - * Registers a request_body_data callback. - * - * @param cfg - * @param callback_fn - */ -void htp_config_register_request_body_data(htp_cfg_t *cfg, int (*callback_fn)(htp_tx_data_t *)) { - hook_register(&cfg->hook_request_body_data, callback_fn); -} - -/** - * Registers a request callback. - * - * @param cfg - * @param callback_fn - */ -void htp_config_register_request(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)) { - hook_register(&cfg->hook_request, callback_fn); -} - -/** - * Registers a request_line callback. - * - * @param cfg - * @param callback_fn - */ -void htp_config_register_response_line(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)) { - hook_register(&cfg->hook_response_line, callback_fn); -} - -/** - * Registers a request_headers callback. - * - * @param cfg - * @param callback_fn - */ -void htp_config_register_response_headers(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)) { - hook_register(&cfg->hook_response_headers, callback_fn); -} - -/** - * Registers a request_trailer callback. - * - * @param cfg - * @param callback_fn - */ -void htp_config_register_response_trailer(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)) { - hook_register(&cfg->hook_response_trailer, callback_fn); -} - -/** - * Registers a request_body_data callback. - * - * @param cfg - * @param callback_fn - */ -void htp_config_register_response_body_data(htp_cfg_t *cfg, int (*callback_fn)(htp_tx_data_t *)) { - hook_register(&cfg->hook_response_body_data, callback_fn); -} - -/** - * Registers a request callback. - * - * @param cfg - * @param callback_fn - */ -void htp_config_register_response(htp_cfg_t *cfg, int (*callback_fn)(htp_connp_t *)) { - hook_register(&cfg->hook_response, callback_fn); -} - -/** - * Registers a callback that is invoked every time there is a log message. - * - * @param cfg - * @param callback_fn - */ -void htp_config_register_log(htp_cfg_t *cfg, int (*callback_fn)(htp_log_t *)) { - hook_register(&cfg->hook_log, callback_fn); -} - -/** - * Update the best-fit map, which is used to convert UCS-2 characters into - * single-byte characters. By default a Windows 1252 best-fit map is used. The map - * is an list of triplets, the first 2 bytes being an UCS-2 character to map from, - * and the third byte being the single byte to map to. Make sure that your map contains - * the mappings to cover the fullwidth form characters (U+FF00-FFEF). - * - * @param cfg - * @param map - */ -void htp_config_set_bestfit_map(htp_cfg_t *cfg, unsigned char *map) { - cfg->path_u_bestfit_map = map; -} - -/** - * Whether to generate the request_uri_normalized field. - * - * @param cfg - * @param generate - */ -void htp_config_set_generate_request_uri_normalized(htp_cfg_t *cfg, int generate) { - cfg->generate_request_uri_normalized = generate; -} - -/** - * Configures whether backslash characters are treated as path segment separators. They - * are not on Unix systems, but are on Windows systems. If this setting is enabled, a path - * such as "/one\two/three" will be converted to "/one/two/three". - * - * @param cfg - * @param backslash_separators - */ -void htp_config_set_path_backslash_separators(htp_cfg_t *cfg, int backslash_separators) { - cfg->path_backslash_separators = backslash_separators; -} - -/** - * Configures whether backslash characters are treated as query segment separators. They - * are not on Unix systems, but are on Windows systems. If this setting is enabled, a query - * such as "/one\two/three" will be converted to "/one/two/three". - * - * @param cfg - * @param backslash_separators - */ -void htp_config_set_query_backslash_separators(htp_cfg_t *cfg, int backslash_separators) { - cfg->query_backslash_separators = backslash_separators; -} - -/** - * Configures filesystem sensitivity. This setting affects - * how URL paths are normalized. There are no path modifications by default, but - * on a case-insensitive systems path will be converted to lowercase. - * - * @param cfg - * @param case_insensitive - */ -void htp_config_set_path_case_insensitive(htp_cfg_t *cfg, int case_insensitive) { - cfg->path_case_insensitive = case_insensitive; -} - -/** - * Configures filesystem sensitivity. This setting affects - * how URL querys are normalized. There are no query modifications by default, but - * on a case-insensitive systems query will be converted to lowercase. - * - * @param cfg - * @param case_insensitive - */ -void htp_config_set_query_case_insensitive(htp_cfg_t *cfg, int case_insensitive) { - cfg->query_case_insensitive = case_insensitive; -} - -/** - * Configures whether consecutive path segment separators will be compressed. When - * enabled, a path such as "/one//two" will be normalized to "/one/two". The backslash_separators - * and decode_separators parameters are used before compression takes place. For example, if - * backshasl_deparators and decode_separators are both enabled, the path "/one\\/two\/%5cthree/%2f//four" - * will be converted to "/one/two/three/four". - * - * @param cfg - * @param compress_separators - */ -void htp_config_set_path_compress_separators(htp_cfg_t *cfg, int compress_separators) { - cfg->path_compress_separators = compress_separators; -} - -/** - * Configures whether consecutive query segment separators will be compressed. When - * enabled, a query such as "/one//two" will be normalized to "/one/two". The backslash_separators - * and decode_separators parameters are used before compression takes place. For example, if - * backshasl_deparators and decode_separators are both enabled, the query "/one\\/two\/%5cthree/%2f//four" - * will be converted to "/one/two/three/four". - * - * @param cfg - * @param compress_separators - */ -void htp_config_set_query_compress_separators(htp_cfg_t *cfg, int compress_separators) { - cfg->query_compress_separators = compress_separators; -} - -/** - * This parameter is used to predict how a server will react when control - * characters are present in a request path, but does not affect path - * normalization. - * - * @param cfg - * @param control_char_handling Use NONE with servers that ignore control characters in - * request path, and STATUS_400 with servers that respond - * with 400. - */ -void htp_config_set_path_control_char_handling(htp_cfg_t *cfg, int control_char_handling) { - cfg->path_control_char_handling = control_char_handling; -} - -/** - * This parameter is used to predict how a server will react when control - * characters are present in a request query, but does not affect query - * normalization. - * - * @param cfg - * @param control_char_handling Use NONE with servers that ignore control characters in - * request query, and STATUS_400 with servers that respond - * with 400. - */ -void htp_config_set_query_control_char_handling(htp_cfg_t *cfg, int control_char_handling) { - cfg->query_control_char_handling = control_char_handling; -} - -/** - * Controls the UTF-8 treatment of request paths. One option is to only validate - * path as UTF-8. In this case, the UTF-8 flags will be raised as appropriate, and - * the path will remain in UTF-8 (if it was UTF-8in the first place). The other option - * is to convert a UTF-8 path into a single byte stream using best-fit mapping. - * - * @param cfg - * @param convert_utf8 - */ -void htp_config_set_path_convert_utf8(htp_cfg_t *cfg, int convert_utf8) { - cfg->path_convert_utf8 = convert_utf8; -} - -/** - * Configures whether encoded path segment separators will be decoded. Apache does - * not do this, but IIS does. If enabled, a path such as "/one%2ftwo" will be normalized - * to "/one/two". If the backslash_separators option is also enabled, encoded backslash - * characters will be converted too (and subseqently normalized to forward slashes). - * - * @param cfg - * @param decode_separators - */ -void htp_config_set_path_decode_separators(htp_cfg_t *cfg, int decode_separators) { - cfg->path_decode_separators = decode_separators; -} - -/** - * Configures whether encoded query segment separators will be decoded. Apache does - * not do this, but IIS does. If enabled, a query such as "/one%2ftwo" will be normalized - * to "/one/two". If the backslash_separators option is also enabled, encoded backslash - * characters will be converted too (and subseqently normalized to forward slashes). - * - * @param cfg - * @param decode_separators - */ -void htp_config_set_query_decode_separators(htp_cfg_t *cfg, int decode_separators) { - cfg->query_decode_separators = decode_separators; -} - -/** - * Configures whether %u-encoded sequences in path will be decoded. Such sequences - * will be treated as invalid URL encoding if decoding is not desireable. - * - * @param cfg - * @param decode_u_encoding - */ -void htp_config_set_path_decode_u_encoding(htp_cfg_t *cfg, int decode_u_encoding) { - cfg->path_decode_u_encoding = decode_u_encoding; -} - -/** - * Configures whether %u-encoded sequences in query will be decoded. Such sequences - * will be treated as invalid URL encoding if decoding is not desireable. - * - * @param cfg - * @param decode_u_encoding - */ -void htp_config_set_query_decode_u_encoding(htp_cfg_t *cfg, int decode_u_encoding) { - cfg->query_decode_u_encoding = decode_u_encoding; -} - -/** - * Configures how server reacts to invalid encoding in path. - * - * @param cfg - * @param invalid_encoding_handling The available options are: URL_DECODER_PRESERVE_PERCENT, - * URL_DECODER_REMOVE_PERCENT, URL_DECODER_DECODE_INVALID - * and URL_DECODER_STATUS_400. - */ -void htp_config_set_path_invalid_encoding_handling(htp_cfg_t *cfg, int invalid_encoding_handling) { - cfg->path_invalid_encoding_handling = invalid_encoding_handling; -} - -/** - * Configures how server reacts to invalid encoding in query. - * - * @param cfg - * @param invalid_encoding_handling The available options are: URL_DECODER_PRESERVE_PERCENT, - * URL_DECODER_REMOVE_PERCENT, URL_DECODER_DECODE_INVALID - * and URL_DECODER_STATUS_400. - */ -void htp_config_set_query_invalid_encoding_handling(htp_cfg_t *cfg, int invalid_encoding_handling) { - cfg->query_invalid_encoding_handling = invalid_encoding_handling; -} - - -/** - * Configures how server reacts to invalid UTF-8 characters in path. This setting will - * not affect path normalization; it only controls what response status we expect for - * a request that contains invalid UTF-8 characters. - * - * @param cfg - * @param invalid_utf8_handling Possible values: NONE or STATUS_400. - */ -void htp_config_set_path_invalid_utf8_handling(htp_cfg_t *cfg, int invalid_utf8_handling) { - cfg->path_invalid_utf8_handling = invalid_utf8_handling; -} - -/** - * Configures how server reacts to encoded NUL bytes. Some servers will terminate - * path at NUL, while some will respond with 400 or 404. When the termination option - * is not used, the NUL byte will remain in the path. - * - * @param cfg - * @param nul_encoded_handling Possible values: TERMINATE, STATUS_400, STATUS_404 - */ -void htp_config_set_path_nul_encoded_handling(htp_cfg_t *cfg, int nul_encoded_handling) { - cfg->path_nul_encoded_handling = nul_encoded_handling; -} - -/** - * Configures how server reacts to encoded NUL bytes. Some servers will terminate - * query at NUL, while some will respond with 400 or 404. When the termination option - * is not used, the NUL byte will remain in the query. - * - * @param cfg - * @param nul_encoded_handling Possible values: TERMINATE, STATUS_400, STATUS_404 - */ -void htp_config_set_query_nul_encoded_handling(htp_cfg_t *cfg, int nul_encoded_handling) { - cfg->query_nul_encoded_handling = nul_encoded_handling; -} - -/** - * Configures how server reacts to raw NUL bytes. Some servers will terminate - * path at NUL, while some will respond with 400 or 404. When the termination option - * is not used, the NUL byte will remain in the path. - * - * @param cfg - * @param nul_raw_handling Possible values: TERMINATE, STATUS_400, STATUS_404 - */ -void htp_config_set_path_nul_raw_handling(htp_cfg_t *cfg, int nul_raw_handling) { - cfg->path_nul_raw_handling = nul_raw_handling; -} - -/** - * Configures how server reacts to raw NUL bytes. Some servers will terminate - * query at NUL, while some will respond with 400 or 404. When the termination option - * is not used, the NUL byte will remain in the query. - * - * @param cfg - * @param nul_raw_handling Possible values: TERMINATE, STATUS_400, STATUS_404 - */ -void htp_config_set_query_nul_raw_handling(htp_cfg_t *cfg, int nul_raw_handling) { - cfg->query_nul_raw_handling = nul_raw_handling; -} - -/** - * Sets the replacement characater that will be used to in the lossy best-fit - * mapping from Unicode characters into single-byte streams. The question mark - * is the default replacement character. - * - * @param cfg - * @param replacement_char - */ -void htp_config_set_path_replacement_char(htp_cfg_t *cfg, int replacement_char) { - cfg->path_replacement_char = replacement_char; -} - -/** - * Controls what the library does when it encounters an Unicode character where - * only a single-byte would do (e.g., the %u-encoded characters). Conversion always - * takes place; this parameter is used to correctly predict the status code used - * in response. In the future there will probably be an option to convert such - * characters to UCS-2 or UTF-8. - * - * @param cfg - * @param unicode_mapping Possible values: BESTFIT, STATUS_400, STATUS_404. - */ -void htp_config_set_path_unicode_mapping(htp_cfg_t *cfg, int unicode_mapping) { - cfg->path_unicode_mapping = unicode_mapping; -} - -/** - * Controls how server reacts to overlong UTF-8 characters. - * XXX Not used at the moment. - * - * @param cfg - * @param utf8_overlong_handling - */ -void htp_config_set_path_utf8_overlong_handling(htp_cfg_t *cfg, int utf8_overlong_handling) { - cfg->path_utf8_overlong_handling = utf8_overlong_handling; -} - -/** - * Configure desired server personality. - * - * @param cfg - * @param personality - * @return HTP_OK if the personality is supported, HTP_ERROR if it isn't. - */ -int htp_config_set_server_personality(htp_cfg_t *cfg, int personality) { - switch (personality) { - case HTP_SERVER_MINIMAL: - cfg->parse_request_line = htp_parse_request_line_generic; - cfg->process_request_header = htp_process_request_header_generic; - cfg->parse_response_line = htp_parse_response_line_generic; - cfg->process_response_header = htp_process_response_header_generic; - break; - - case HTP_SERVER_GENERIC: - cfg->parse_request_line = htp_parse_request_line_generic; - cfg->process_request_header = htp_process_request_header_generic; - cfg->parse_response_line = htp_parse_response_line_generic; - cfg->process_response_header = htp_process_response_header_generic; - - cfg->path_backslash_separators = YES; - cfg->path_decode_separators = YES; - cfg->path_compress_separators = YES; - -// cfg->query_backslash_separators = YES; - cfg->query_decode_separators = YES; -// cfg->query_compress_separators = YES; - break; - - case HTP_SERVER_IDS: - cfg->parse_request_line = htp_parse_request_line_generic; - cfg->process_request_header = htp_process_request_header_generic; - cfg->parse_response_line = htp_parse_response_line_generic; - cfg->process_response_header = htp_process_response_header_generic; - - cfg->path_backslash_separators = YES; - cfg->path_case_insensitive = YES; - cfg->path_decode_separators = YES; - cfg->path_compress_separators = YES; - cfg->path_decode_u_encoding = YES; - cfg->path_unicode_mapping = BESTFIT; - cfg->path_convert_utf8 = YES; - -// cfg->query_backslash_separators = YES; - cfg->query_case_insensitive = YES; - cfg->query_decode_separators = YES; -// cfg->query_compress_separators = YES; - cfg->query_decode_u_encoding = YES; - break; - - case HTP_SERVER_APACHE : - case HTP_SERVER_APACHE_2_2: - cfg->parse_request_line = htp_parse_request_line_apache_2_2; - cfg->process_request_header = htp_process_request_header_apache_2_2; - cfg->parse_response_line = htp_parse_response_line_generic; - cfg->process_response_header = htp_process_response_header_generic; - - cfg->path_backslash_separators = NO; - cfg->path_decode_separators = NO; - cfg->path_compress_separators = YES; - cfg->path_invalid_encoding_handling = URL_DECODER_STATUS_400; - cfg->path_control_char_handling = NONE; - -// cfg->query_backslash_separators = NO; - cfg->query_decode_separators = NO; -// cfg->query_compress_separators = YES; - cfg->query_invalid_encoding_handling = URL_DECODER_STATUS_400; - cfg->query_control_char_handling = NONE; - break; - - case HTP_SERVER_IIS_5_1: - cfg->parse_request_line = htp_parse_request_line_generic; - cfg->process_request_header = htp_process_request_header_generic; - cfg->parse_response_line = htp_parse_response_line_generic; - cfg->process_response_header = htp_process_response_header_generic; - - cfg->path_backslash_separators = YES; - cfg->path_decode_separators = NO; - cfg->path_compress_separators = YES; - cfg->path_invalid_encoding_handling = URL_DECODER_PRESERVE_PERCENT; - cfg->path_decode_u_encoding = YES; - cfg->path_unicode_mapping = BESTFIT; - cfg->path_control_char_handling = NONE; - -// cfg->query_backslash_separators = YES; - cfg->query_decode_separators = NO; -// cfg->query_compress_separators = YES; - cfg->query_invalid_encoding_handling = URL_DECODER_PRESERVE_PERCENT; - cfg->query_decode_u_encoding = YES; -// cfg->query_unicode_mapping = BESTFIT; - cfg->query_control_char_handling = NONE; - break; - - case HTP_SERVER_IIS_6_0: - cfg->parse_request_line = htp_parse_request_line_generic; - cfg->process_request_header = htp_process_request_header_generic; - cfg->parse_response_line = htp_parse_response_line_generic; - cfg->process_response_header = htp_process_response_header_generic; - - cfg->path_backslash_separators = YES; - cfg->path_decode_separators = YES; - cfg->path_compress_separators = YES; - cfg->path_invalid_encoding_handling = URL_DECODER_STATUS_400; - cfg->path_decode_u_encoding = YES; - cfg->path_unicode_mapping = STATUS_400; - cfg->path_control_char_handling = STATUS_400; - -// cfg->query_backslash_separators = YES; - cfg->query_decode_separators = YES; -// cfg->query_compress_separators = YES; - cfg->query_invalid_encoding_handling = URL_DECODER_STATUS_400; - cfg->query_decode_u_encoding = YES; -// cfg->query_unicode_mapping = STATUS_400; - cfg->query_control_char_handling = STATUS_400; - break; - - case HTP_SERVER_IIS_7_0: - case HTP_SERVER_IIS_7_5: - cfg->parse_request_line = htp_parse_request_line_generic; - cfg->process_request_header = htp_process_request_header_generic; - cfg->parse_response_line = htp_parse_response_line_generic; - cfg->process_response_header = htp_process_response_header_generic; - - cfg->path_backslash_separators = YES; - cfg->path_decode_separators = YES; - cfg->path_compress_separators = YES; - cfg->path_invalid_encoding_handling = URL_DECODER_STATUS_400; - cfg->path_control_char_handling = STATUS_400; - -// cfg->query_backslash_separators = YES; - cfg->query_decode_separators = YES; -// cfg->query_compress_separators = YES; - cfg->query_invalid_encoding_handling = URL_DECODER_STATUS_400; - cfg->query_control_char_handling = STATUS_400; - break; - - default: - return HTP_ERROR; - } - - // Remember the personality - cfg->spersonality = personality; - - return HTP_OK; -} diff --git a/libhtp/htp/htp_connection.c b/libhtp/htp/htp_connection.c deleted file mode 100644 index cd2a9a616e..0000000000 --- a/libhtp/htp/htp_connection.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * LibHTP (http://www.libhtp.org) - * Copyright 2009,2010 Ivan Ristic - * - * LibHTP is an open source product, released under terms of the General Public Licence - * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text - * of the license. - * - * In addition, there is a special exception that allows LibHTP to be freely - * used with any OSI-approved open source licence. Please refer to the file - * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. - * - */ - -#include "htp.h" - -/** - * Creates a new connection structure. - * - * @param connp - * @return A new htp_connp_t structure on success, NULL on memory allocation failure. - */ -htp_conn_t *htp_conn_create(htp_connp_t *connp) { - htp_conn_t *conn = calloc(1, sizeof (htp_conn_t)); - if (conn == NULL) return NULL; - - conn->connp = connp; - - conn->transactions = list_array_create(16); - if (conn->transactions == NULL) { - free(conn); - return NULL; - } - - conn->messages = list_array_create(8); - if (conn->messages == NULL) { - list_destroy(conn->transactions); - free(conn); - return NULL; - } - - return conn; -} - -/** - * Destroys a connection, as well as all the transactions it contains. It is - * not possible to destroy a connection structure yet leave any of its - * transactions intact. This is because transactions need its connection and - * connection structures hold little data anyway. The opposite is true, though - * it is possible to delete a transaction but leave its connection alive. - * - * @param conn - */ -void htp_conn_destroy(htp_conn_t *conn) { - if (conn == NULL) return; - - // Destroy individual transactions. Do note that iterating - // using the iterator does not work here because some of the - // list element may be NULL (and with the iterator it is impossible - // to distinguish a NULL element from the end of the list). - if (conn->transactions != NULL) { - size_t i; - for (i = 0; i < list_size(conn->transactions); i++) { - htp_tx_t *tx = (htp_tx_t *)list_get(conn->transactions, i); - if (tx != NULL) { - htp_tx_destroy(tx); - } - } - - list_destroy(conn->transactions); - } - - // Destroy individual messages - if (conn->messages != NULL) { - htp_log_t *l = NULL; - list_iterator_reset(conn->messages); - while ((l = list_iterator_next(conn->messages)) != NULL) { - free((void *)l->msg); - free(l); - } - - list_destroy(conn->messages); - } - - if (conn->local_addr != NULL) { - free(conn->local_addr); - } - - if (conn->remote_addr != NULL) { - free(conn->remote_addr); - } - - // Finally, destroy the connection - // structure itself. - free(conn); -} - -/** - * Removes the given transaction structure, which makes it possible to - * safely destroy it. It is safe to destroy transactions in this way - * because the index of the transactions (in a connection) is preserved. - * - * @param conn - * @param tx - * @return 1 if transaction was removed or 0 if it wasn't found - */ -int htp_conn_remove_tx(htp_conn_t *conn, htp_tx_t *tx) { - if ((tx == NULL)||(conn == NULL)||(conn->transactions == NULL)) return 0; - - unsigned int i = 0; - for (i = 0; i < list_size(conn->transactions); i++) { - htp_tx_t *etx = list_get(conn->transactions, i); - if (tx == etx) { - list_replace(conn->transactions, i, NULL); - return 1; - } - } - - return 0; -} diff --git a/libhtp/htp/htp_connection_parser.c b/libhtp/htp/htp_connection_parser.c deleted file mode 100644 index f8b995b86f..0000000000 --- a/libhtp/htp/htp_connection_parser.c +++ /dev/null @@ -1,288 +0,0 @@ -/* - * LibHTP (http://www.libhtp.org) - * Copyright 2009,2010 Ivan Ristic - * - * LibHTP is an open source product, released under terms of the General Public Licence - * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text - * of the license. - * - * In addition, there is a special exception that allows LibHTP to be freely - * used with any OSI-approved open source licence. Please refer to the file - * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. - * - */ - -#include "htp.h" - -// NOTE The parser contains a lot of duplicated code. That is on purpose. -// -// Within the request parser alone there are several states in which -// bytes are copied into the line buffer and lines are processed one at a time. -// This code could be made more elegant by adding a new line-reading state along -// with a what-fn-to-invoke-to-handle-line pointer. -// -// Furthermore, the entire request parser is terribly similar to the response parser. -// It is imaginable that a single parser could handle both. -// -// After some thought, I decided not to make any changes (at least not for the time -// being). State-based parsers are sometimes difficult to understand. I remember trying -// to figure one once and I had a hard time following the logic because each function -// was small and did exactly one thing. There was jumping all around. You could probably -// say that it was elegant, but I saw it as difficult to understand, verify and maintain. -// -// Thus, I am keeping this inelegant but quite straightforward parser with duplicated code, -// mostly for the sake of maintenance. -// -// For the time being, anyway. I will review at a later time. - -/** - * Clears an existing parser error, if any. - * - * @param connp - */ -void htp_connp_clear_error(htp_connp_t *connp) { - connp->last_error = NULL; -} - -/** - * Closes the connection associated with the supplied parser. - * - * @param connp - * @param timestamp - */ -void htp_connp_close(htp_connp_t *connp, htp_time_t timestamp) { - // Update internal information - connp->conn->close_timestamp = timestamp; - connp->in_status = STREAM_STATE_CLOSED; - connp->out_status = STREAM_STATE_CLOSED; - - // Call the parsers one last time, which will allow them - // to process the events that depend on stream closure - htp_connp_req_data(connp, timestamp, NULL, 0); - htp_connp_res_data(connp, timestamp, NULL, 0); -} - -/** - * Creates a new connection parser using the provided configuration. Because - * the configuration structure is used directly, in a multithreaded environment - * you are not allowed to change the structure, ever. If you have a need to - * change configuration on per-connection basis, make a copy of the configuration - * structure to go along with every connection parser. - * - * @param cfg - * @return A pointer to a newly created htp_connp_t instance. - */ -htp_connp_t *htp_connp_create(htp_cfg_t *cfg) { - htp_connp_t *connp = calloc(1, sizeof (htp_connp_t)); - if (connp == NULL) return NULL; - - // Use the supplied configuration structure - connp->cfg = cfg; - - // Create a new connection object - connp->conn = htp_conn_create(connp); - if (connp->conn == NULL) { - free(connp); - return NULL; - } - - connp->in_status = HTP_OK; - - // Request parsing - - connp->in_line_size = cfg->field_limit_hard; - connp->in_line_len = 0; - connp->in_line = malloc(connp->in_line_size); - if (connp->in_line == NULL) { - htp_conn_destroy(connp->conn); - free(connp); - return NULL; - } - - connp->in_header_line_index = -1; - connp->in_state = htp_connp_REQ_IDLE; - - // Response parsing - - connp->out_line_size = cfg->field_limit_hard; - connp->out_line_len = 0; - connp->out_line = malloc(connp->out_line_size); - if (connp->out_line == NULL) { - free(connp->in_line); - htp_conn_destroy(connp->conn); - free(connp); - return NULL; - } - - connp->out_header_line_index = -1; - connp->out_state = htp_connp_RES_IDLE; - - connp->in_status = STREAM_STATE_NEW; - connp->out_status = STREAM_STATE_NEW; - - return connp; -} - -/** - * Creates a new configuration parser, making a copy of the supplied - * configuration structure. - * - * @param cfg - * @return A pointer to a newly created htp_connp_t instance. - */ -htp_connp_t *htp_connp_create_copycfg(htp_cfg_t *cfg) { - htp_connp_t *connp = htp_connp_create(cfg); - if (connp == NULL) return NULL; - - connp->cfg = htp_config_copy(cfg); - if (connp->cfg == NULL) { - htp_connp_destroy(connp); - return NULL; - } - - connp->is_cfg_private = 1; - - return connp; -} - -/** - * Destroys the connection parser and its data structures, leaving - * the connection data intact. - * - * @param connp - */ -void htp_connp_destroy(htp_connp_t *connp) { - if (connp == NULL) - return; - - if (connp->out_decompressor != NULL) { - connp->out_decompressor->destroy(connp->out_decompressor); - connp->out_decompressor = NULL; - } - - if (connp->in_header_line != NULL) { - if (connp->in_header_line->line != NULL) { - free(connp->in_header_line->line); - } - - free(connp->in_header_line); - } - - if (connp->in_line != NULL) - free(connp->in_line); - - if (connp->out_header_line != NULL) { - if (connp->out_header_line->line != NULL) { - free(connp->out_header_line->line); - } - - free(connp->out_header_line); - } - - if (connp->out_line != NULL) - free(connp->out_line); - - // Destroy the configuration structure, but only - // if it is our private copy - if ((connp->is_cfg_private) && (connp->cfg != NULL)) { - htp_config_destroy(connp->cfg); - } - - free(connp); -} - -/** - * Destroys the connection parser, its data structures, as well - * as the connection and its transactions. - * - * @param connp - */ -void htp_connp_destroy_all(htp_connp_t *connp) { - if (connp == NULL) - return; - - if (connp->conn != NULL) { - // Destroy connection - htp_conn_destroy(connp->conn); - connp->conn = NULL; - } - - // Destroy everything else - htp_connp_destroy(connp); -} - -/** - * Retrieve the user data associated with this connection parser. - * - * @param connp - * @return User data, or NULL if there isn't any. - */ -void *htp_connp_get_data(htp_connp_t *connp) { - return connp->user_data; -} - -/** - * Returns the last error that occured with this connection parser. Do note, however, - * that the value in this field will only be valid immediately after an error condition, - * but it is not guaranteed to remain valid if the parser is invoked again. - * - * @param connp - * @return A pointer to an htp_log_t instance if there is an error, or NULL - * if there isn't. - */ -htp_log_t *htp_connp_get_last_error(htp_connp_t *connp) { - return connp->last_error; -} - -/** - * Opens connection. - * - * @param connp - * @param remote_addr Remote address - * @param remote_port Remote port - * @param local_addr Local address - * @param local_port Local port - * @param timestamp - */ -void htp_connp_open(htp_connp_t *connp, const char *remote_addr, int remote_port, const char *local_addr, int local_port, htp_time_t timestamp) { - if ((connp->in_status != STREAM_STATE_NEW) || (connp->out_status != STREAM_STATE_NEW)) { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Connection is already open"); - return; - } - - if (remote_addr != NULL) { - connp->conn->remote_addr = strdup(remote_addr); - if (connp->conn->remote_addr == NULL) return; - } - - connp->conn->remote_port = remote_port; - - if (local_addr != NULL) { - connp->conn->local_addr = strdup(local_addr); - if (connp->conn->local_addr == NULL) { - if (connp->conn->remote_addr != NULL) { - free(connp->conn->remote_addr); - } - return; - } - } - - connp->conn->local_port = local_port; - connp->conn->open_timestamp = timestamp; - connp->in_status = STREAM_STATE_OPEN; - connp->out_status = STREAM_STATE_OPEN; -} - -/** - * Associate user data with the supplied parser. - * - * @param connp - * @param user_data - */ -void htp_connp_set_user_data(htp_connp_t *connp, void *user_data) { - connp->user_data = user_data; -} - -void *htp_connp_get_user_data(htp_connp_t *connp) { - return(connp->user_data); -} diff --git a/libhtp/htp/htp_decompressors.c b/libhtp/htp/htp_decompressors.c deleted file mode 100644 index d9a0c0d5c6..0000000000 --- a/libhtp/htp/htp_decompressors.c +++ /dev/null @@ -1,226 +0,0 @@ -/* - * LibHTP (http://www.libhtp.org) - * Copyright 2009,2010 Ivan Ristic - * - * LibHTP is an open source product, released under terms of the General Public Licence - * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text - * of the license. - * - * In addition, there is a special exception that allows LibHTP to be freely - * used with any OSI-approved open source licence. Please refer to the file - * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. - * - */ - -#include "htp.h" -#include "htp_decompressors.h" - -/** - * Decompress a chunk of gzip-compressed data. - * - * @param drec - * @param d - */ -static int htp_gzip_decompressor_decompress(htp_decompressor_gzip_t *drec, htp_tx_data_t *d) { - size_t consumed = 0; - - // Return if we've previously had an error - if (drec->initialized < 0) { - return drec->initialized; - } - - // Do we need to initialize? - if (drec->initialized == 0) { - // Check the header - if ((drec->header_len == 0) && (d->len >= 10)) { - // We have received enough data initialize; use the input buffer directly - if ((d->data[0] != DEFLATE_MAGIC_1) || (d->data[1] != DEFLATE_MAGIC_2)) { - htp_log(d->tx->connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, - "GZip decompressor: Magic bytes mismatch"); - drec->initialized = -1; - return -1; - } - - if (d->data[3] == 0) { - drec->initialized = 1; - consumed = 10; - } else if ((d->data[3] & (1 << 3)) || (d->data[3] & (1 << 4))) { - /* skip past - * - FNAME extension, which is a name ended in a NUL terminator - * or - * - FCOMMENT extension, which is a commend ended in a NULL terminator - */ - - size_t len; - for (len = 10; len < d->len && d->data[len] != '\0'; len++); - - drec->initialized = 1; - consumed = len + 1; - } else { - htp_log(d->tx->connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, - "GZip decompressor: Unable to handle flags: %d", d->data[3]); - drec->initialized = -1; - return -1; - } - } else { - // We do not (or did not) have enough bytes, so we have - // to copy some data into our internal header buffer. - - // How many bytes do we need? - size_t copylen = 10 - drec->header_len; - - // Is there enough in input? - if (copylen > d->len) copylen = d->len; - - // Copy the bytes - memcpy(drec->header + drec->header_len, d->data, copylen); - drec->header_len += copylen; - consumed = copylen; - - // Do we have enough now? - if (drec->header_len == 10) { - // We do! - if ((drec->header[0] != DEFLATE_MAGIC_1) || (drec->header[1] != DEFLATE_MAGIC_2)) { - htp_log(d->tx->connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, - "GZip decompressor: Magic bytes mismatch"); - drec->initialized = -1; - return -1; - } - - if (drec->header[3] != 0) { - htp_log(d->tx->connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, - "GZip decompressor: Unable to handle flags: %d", d->data[3]); - drec->initialized = -1; - return -1; - } - - drec->initialized = 1; - } else { - // Need more data - return 1; - } - } - } - - // Decompress data - int rc = 0; - drec->stream.next_in = d->data + consumed; - drec->stream.avail_in = d->len - consumed; - - while (drec->stream.avail_in != 0) { - // If there's no more data left in the - // buffer, send that information out - if (drec->stream.avail_out == 0) { - drec->crc = crc32(drec->crc, drec->buffer, GZIP_BUF_SIZE); - - // Prepare data for callback - htp_tx_data_t d2; - d2.tx = d->tx; - d2.data = drec->buffer; - d2.len = GZIP_BUF_SIZE; - - // Send decompressed data to callback - if (drec->super.callback(&d2) < 0) { - inflateEnd(&drec->stream); - drec->zlib_initialized = 0; - return -1; - } - - drec->stream.next_out = drec->buffer; - drec->stream.avail_out = GZIP_BUF_SIZE; - } - - rc = inflate(&drec->stream, Z_NO_FLUSH); - - if (rc == Z_STREAM_END) { - // How many bytes do we have? - size_t len = GZIP_BUF_SIZE - drec->stream.avail_out; - - // Update CRC - drec->crc = crc32(drec->crc, drec->buffer, len); - - // Prepare data for callback - htp_tx_data_t d2; - d2.tx = d->tx; - d2.data = drec->buffer; - d2.len = len; - - // Send decompressed data to callback - if (drec->super.callback(&d2) < 0) { - inflateEnd(&drec->stream); - drec->zlib_initialized = 0; - return -1; - } - - // TODO Handle trailer - - return 1; - } - - if (rc != Z_OK) { - htp_log(d->tx->connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, - "GZip decompressor: inflate failed with %d", rc); - - inflateEnd(&drec->stream); - drec->zlib_initialized = 0; - - return -1; - } - } - - return 1; -} - -/** - * Shut down gzip decompressor. - * - * @param drec - */ -static void htp_gzip_decompressor_destroy(htp_decompressor_gzip_t * drec) { - if (drec == NULL) return; - - if (drec->zlib_initialized) { - inflateEnd(&drec->stream); - drec->zlib_initialized = 0; - } - - free(drec->buffer); - free(drec); -} - -/** - * Initialize gzip decompressor. - * - * @param connp - */ -htp_decompressor_t * htp_gzip_decompressor_create(htp_connp_t *connp) { - htp_decompressor_gzip_t *drec = calloc(1, sizeof (htp_decompressor_gzip_t)); - if (drec == NULL) return NULL; - - drec->super.decompress = (int (*)(htp_decompressor_t *, htp_tx_data_t *)) htp_gzip_decompressor_decompress; - drec->super.destroy = (void (*)(htp_decompressor_t *))htp_gzip_decompressor_destroy; - - drec->buffer = malloc(GZIP_BUF_SIZE); - if (drec->buffer == NULL) { - free(drec); - return NULL; - } - - int rc = inflateInit2(&drec->stream, GZIP_WINDOW_SIZE); - if (rc != Z_OK) { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "GZip decompressor: inflateInit2 failed with code %d", rc); - - inflateEnd(&drec->stream); - free(drec->buffer); - free(drec); - - return NULL; - } - - drec->zlib_initialized = 1; - drec->stream.avail_out = GZIP_BUF_SIZE; - drec->stream.next_out = drec->buffer; - - return (htp_decompressor_t *) drec; -} diff --git a/libhtp/htp/htp_decompressors.h b/libhtp/htp/htp_decompressors.h deleted file mode 100644 index 178279773b..0000000000 --- a/libhtp/htp/htp_decompressors.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * LibHTP (http://www.libhtp.org) - * Copyright 2009,2010 Ivan Ristic - * - * LibHTP is an open source product, released under terms of the General Public Licence - * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text - * of the license. - * - * In addition, there is a special exception that allows LibHTP to be freely - * used with any OSI-approved open source licence. Please refer to the file - * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. - * - */ - -#ifndef _HTP_DECOMPRESSORS_H -#define _HTP_DECOMPRESSORS_H - -typedef struct htp_decompressor_gzip_t htp_decompressor_gzip_t; -typedef struct htp_decompressor_t htp_decompressor_t; - -#include "zlib.h" - -#define GZIP_BUF_SIZE 8192 -#define GZIP_WINDOW_SIZE -15 - -#define DEFLATE_MAGIC_1 0x1f -#define DEFLATE_MAGIC_2 0x8b - -struct htp_decompressor_t { - int (*decompress)(htp_decompressor_t *, htp_tx_data_t *); - int (*callback)(htp_tx_data_t *); - void (*destroy)(htp_decompressor_t *); -}; - -struct htp_decompressor_gzip_t { - htp_decompressor_t super; - int initialized; - int zlib_initialized; - uint8_t header[10]; - uint8_t header_len; - z_stream stream; - unsigned char *buffer; - unsigned long crc; -}; - -htp_decompressor_t * htp_gzip_decompressor_create(htp_connp_t *connp); - -#endif /* _HTP_DECOMPRESSORS_H */ - diff --git a/libhtp/htp/htp_parsers.c b/libhtp/htp/htp_parsers.c deleted file mode 100644 index 5d9bdc88ea..0000000000 --- a/libhtp/htp/htp_parsers.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * LibHTP (http://www.libhtp.org) - * Copyright 2009,2010 Ivan Ristic - * - * LibHTP is an open source product, released under terms of the General Public Licence - * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text - * of the license. - * - * In addition, there is a special exception that allows LibHTP to be freely - * used with any OSI-approved open source licence. Please refer to the file - * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. - * - */ - -#include "htp.h" - -/** - * Determines protocol number from a textual representation (i.e., "HTTP/1.1"). This - * function will only understand a properly formatted protocol information. It does - * not try to be flexible. - * - * @param protocol - * @return Protocol version or PROTOCOL_UKNOWN. - */ -int htp_parse_protocol(bstr *protocol) { - if (protocol != NULL && bstr_len(protocol) == 8) { - char *ptr = bstr_ptr(protocol); - if ((ptr[0] == 'H') && (ptr[1] == 'T') && (ptr[2] == 'T') && (ptr[3] == 'P') - && (ptr[4] == '/') && (ptr[6] == '.')) { - // Check the version numbers - if (ptr[5] == '0') { - if (ptr[7] == '9') { - return HTTP_0_9; - } - } else if (ptr[5] == '1') { - if (ptr[7] == '0') { - return HTTP_1_0; - } else if (ptr[7] == '1') { - return HTTP_1_1; - } - } - } - } - - return PROTOCOL_UNKNOWN; -} - -/** - * Determines the numerical value of a response status given as a string. - * - * @param status - * @return Status code on success, or -1 on error. - */ -int htp_parse_status(bstr *status) { - return htp_parse_positive_integer_whitespace((unsigned char *)bstr_ptr(status), bstr_len(status), 10); -} diff --git a/libhtp/htp/htp_request.c b/libhtp/htp/htp_request.c deleted file mode 100644 index f7d3d89eaf..0000000000 --- a/libhtp/htp/htp_request.c +++ /dev/null @@ -1,915 +0,0 @@ -/* - * LibHTP (http://www.libhtp.org) - * Copyright 2009,2010 Ivan Ristic - * - * LibHTP is an open source product, released under terms of the General Public Licence - * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text - * of the license. - * - * In addition, there is a special exception that allows LibHTP to be freely - * used with any OSI-approved open source licence. Please refer to the file - * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. - * - */ - -#include - -#include "htp.h" - -/** - * Performs check for a CONNECT transaction to decide whether inbound - * parsing needs to be suspended. - * - * @param connp - * @return HTP_OK if the request does not use CONNECT, HTP_DATA_OTHER if - * inbound parsing needs to be suspended until we hear from the - * other side - */ -int htp_connp_REQ_CONNECT_CHECK(htp_connp_t *connp) { - // If the request uses the CONNECT method, then there will - // not be a request body, but first we need to wait to see the - // response in order to determine if the tunneling request - // was a success. - if (connp->in_tx->request_method_number == M_CONNECT) { - connp->in_state = htp_connp_REQ_CONNECT_WAIT_RESPONSE; - connp->in_status = STREAM_STATE_DATA_OTHER; - connp->in_tx->progress[0] = TX_PROGRESS_WAIT; - - return HTP_DATA_OTHER; - } - - // Continue to the next step to determine the presence - // of the request body - connp->in_state = htp_connp_REQ_BODY_DETERMINE; - - return HTP_OK; -} - -/** - * Determines whether inbound parsing, which was suspended after - * encountering a CONNECT transaction, can proceed (after receiving - * the response). - * - * @param connp - * @return HTP_OK if the parser can resume parsing, HTP_DATA_OTHER if - * it needs to continue waiting. - */ -int htp_connp_REQ_CONNECT_WAIT_RESPONSE(htp_connp_t *connp) { - // Check that we saw the response line of the current - // inbound transaction. - if (connp->in_tx->progress[0] <= TX_PROGRESS_RES_LINE) { - return HTP_DATA_OTHER; - } - - // A 2xx response means a tunnel was established. Anything - // else means we continue to follow the HTTP stream. - if ((connp->in_tx->response_status_number >= 200) && (connp->in_tx->response_status_number <= 299)) { - // TODO Check that the server did not accept a connection - // to itself. - - // The requested tunnel was established: we are going - // to ignore the remaining data on this stream - connp->in_status = STREAM_STATE_TUNNEL; - connp->in_state = htp_connp_REQ_IDLE; - } else { - // No tunnel; continue to the next transaction - connp->in_state = htp_connp_REQ_IDLE; - } - - return HTP_OK; -} - -/** - * Consumes bytes until the end of the current line. - * - * @param connp - * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. - */ -int htp_connp_REQ_BODY_CHUNKED_DATA_END(htp_connp_t *connp) { - // TODO We shouldn't really see anything apart from CR and LF, - // so we should warn about anything else. - - for (;;) { - IN_NEXT_BYTE_OR_RETURN(connp); - - connp->in_tx->request_message_len++; - - if (connp->in_next_byte == LF) { - connp->in_state = htp_connp_REQ_BODY_CHUNKED_LENGTH; - return HTP_OK; - } - } - return HTP_ERROR; -} - -/** - * Processes a chunk of data. - * - * @param connp - * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. - */ -int htp_connp_REQ_BODY_CHUNKED_DATA(htp_connp_t *connp) { - htp_tx_data_t d; - - d.tx = connp->in_tx; - d.data = &connp->in_current_data[connp->in_current_offset]; - d.len = 0; - - for (;;) { - IN_NEXT_BYTE(connp); - - if (connp->in_next_byte == -1) { - // Send data to callbacks - int rc = hook_run_all(connp->cfg->hook_request_body_data, &d); - if (rc != HOOK_OK) { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Request body data callback returned error (%d)", rc); - return HTP_ERROR; - } - - // Ask for more data - return HTP_DATA; - } else { - connp->in_tx->request_message_len++; - connp->in_tx->request_entity_len++; - connp->in_chunked_length--; - d.len++; - - if (connp->in_chunked_length == 0) { - // End of data chunk - - // Send data to callbacks - int rc = hook_run_all(connp->cfg->hook_request_body_data, &d); - if (rc != HOOK_OK) { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Request body data callback returned error (%d)", rc); - return HTP_ERROR; - } - - connp->in_state = htp_connp_REQ_BODY_CHUNKED_DATA_END; - - return HTP_OK; - } - } - } - return HTP_ERROR; -} - -/** - * Extracts chunk length. - * - * @param connp - * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. - */ -int htp_connp_REQ_BODY_CHUNKED_LENGTH(htp_connp_t *connp) { - for (;;) { - IN_COPY_BYTE_OR_RETURN(connp); - - connp->in_tx->request_message_len++; - - // Have we reached the end of the line? - if (connp->in_next_byte == LF) { - htp_chomp(connp->in_line, &connp->in_line_len); - - // Extract chunk length - connp->in_chunked_length = htp_parse_chunked_length(connp->in_line, connp->in_line_len); - - // Cleanup for the next line - connp->in_line_len = 0; - - // Handle chunk length - if (connp->in_chunked_length > 0) { - // More data available - // TODO Add a check for chunk length - connp->in_state = htp_connp_REQ_BODY_CHUNKED_DATA; - } else if (connp->in_chunked_length == 0) { - // End of data - connp->in_state = htp_connp_REQ_HEADERS; - connp->in_tx->progress[0] = TX_PROGRESS_REQ_TRAILER; - } else { - // Invalid chunk length - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Request chunk encoding: Invalid chunk length"); - return HTP_ERROR; - } - - return HTP_OK; - } - } - return HTP_ERROR; -} - -/** - * Processes identity request body. - * - * @param connp - * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. - */ -int htp_connp_REQ_BODY_IDENTITY(htp_connp_t *connp) { - htp_tx_data_t d; - - d.tx = connp->in_tx; - d.data = &connp->in_current_data[connp->in_current_offset]; - d.len = 0; - - for (;;) { - IN_NEXT_BYTE(connp); - - if (connp->in_next_byte == -1) { - // End of chunk - - if (d.len != 0) { - int rc = hook_run_all(connp->cfg->hook_request_body_data, &d); - if (rc != HOOK_OK) { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Request body data callback returned error (%d)", rc); - return HTP_ERROR; - } - } - - // Ask for more data - return HTP_DATA; - } else { - connp->in_tx->request_message_len++; - connp->in_tx->request_entity_len++; - connp->in_body_data_left--; - d.len++; - - if (connp->in_body_data_left == 0) { - // End of body - - if (d.len != 0) { - int rc = hook_run_all(connp->cfg->hook_request_body_data, &d); - if (rc != HOOK_OK) { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Request body data callback returned error (%d)", rc); - return HTP_ERROR; - } - } - - // Done - connp->in_state = htp_connp_REQ_IDLE; - connp->in_tx->progress[0] = TX_PROGRESS_WAIT; - - return HTP_OK; - } - } - } - return HTP_ERROR; -} - -/** - * Determines presence (and encoding) of a request body. - * - * @param connp - * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. - */ -int htp_connp_REQ_BODY_DETERMINE(htp_connp_t *connp) { - htp_header_t *cl = table_getc(connp->in_tx->request_headers, "content-length"); - htp_header_t *te = table_getc(connp->in_tx->request_headers, "transfer-encoding"); - - // Check for the Transfer-Encoding header, which - // would indicate a chunked request body - if (te != NULL && te->value != NULL) { - // Make sure it contains "chunked" only - if (bstr_cmpc(te->value, "chunked") != 0) { - // Invalid T-E header value - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Invalid T-E value in request"); - } - - // Chunked encoding is a HTTP/1.1 feature. Check - // that some other protocol is not used. The flag will - // also be set if the protocol could not be parsed. - // - // TODO IIS 7.0, for example, would ignore the T-E header when it - // it is used with a protocol below HTTP 1.1. - if (connp->in_tx->request_protocol_number < HTTP_1_1) { - connp->in_tx->flags |= HTP_INVALID_CHUNKING; - // TODO Log - } - - // If the T-E header is present we are going to use it. - connp->in_tx->request_transfer_coding = CHUNKED; - - // We are still going to check for the presence of C-L - if (cl != NULL) { - // This is a violation of the RFC - connp->in_tx->flags |= HTP_REQUEST_SMUGGLING; - // TODO Log - } - - connp->in_state = htp_connp_REQ_BODY_CHUNKED_LENGTH; - connp->in_tx->progress[0] = TX_PROGRESS_REQ_BODY; - } else - // Next check for the presence of the Content-Length header - if (cl != NULL && cl->value != NULL) { - // It seems that we have a request body. - connp->in_tx->request_transfer_coding = IDENTITY; - - // Check for a folded C-L header - if (cl->flags & HTP_FIELD_FOLDED) { - connp->in_tx->flags |= HTP_REQUEST_SMUGGLING; - // TODO Log - } - - // Check for multiple C-L headers - if (cl->flags & HTP_FIELD_REPEATED) { - connp->in_tx->flags |= HTP_REQUEST_SMUGGLING; - // TODO Log - } - - // Get body length - int i = htp_parse_content_length(cl->value); - if (i < 0) { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Invalid C-L field in request"); - return HTP_ERROR; - } else { - connp->in_content_length = i; - connp->in_body_data_left = connp->in_content_length; - - if (connp->in_content_length != 0) { - connp->in_state = htp_connp_REQ_BODY_IDENTITY; - connp->in_tx->progress[0] = TX_PROGRESS_REQ_BODY; - } else { - connp->in_state = htp_connp_REQ_IDLE; - connp->in_tx->progress[0] = TX_PROGRESS_WAIT; - } - } - } else { - // This request does not have a body, which - // means that we're done with it - connp->in_state = htp_connp_REQ_IDLE; - connp->in_tx->progress[0] = TX_PROGRESS_WAIT; - } - - // Host resolution - htp_header_t *h = table_getc(connp->in_tx->request_headers, "host"); - if (h == NULL) { - // No host information in the headers - - // HTTP/1.1 requires host information in the headers - if (connp->in_tx->request_protocol_number >= HTTP_1_1) { - connp->in_tx->flags |= HTP_HOST_MISSING; - htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, - "Host information in request headers required by HTTP/1.1"); - } - } else { - // Host information available in the headers - - // Is there host information in the URI? - if (connp->in_tx->parsed_uri->hostname == NULL) { - // There is no host information in the URI. Place the - // hostname from the headers into the parsed_uri structure. - htp_replace_hostname(connp, connp->in_tx->parsed_uri, h->value); - } else if (bstr_cmp_nocase(h->value, connp->in_tx->parsed_uri->hostname) != 0) { - // The host information is different in the - // headers and the URI. The HTTP RFC states that - // we should ignore the headers copy. - connp->in_tx->flags |= HTP_AMBIGUOUS_HOST; - htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Host information ambiguous"); - } - } - - // Run hook REQUEST_HEADERS - int rc = hook_run_all(connp->cfg->hook_request_headers, connp); - if (rc != HOOK_OK) { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Request headers callback returned error (%d)", rc); - return HTP_ERROR; - } - - return HTP_OK; -} - -/** - * Parses request headers. - * - * @param connp - * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. - */ -int htp_connp_REQ_HEADERS(htp_connp_t *connp) { - for (;;) { - IN_COPY_BYTE_OR_RETURN(connp); - - if (connp->in_header_line == NULL) { - connp->in_header_line = calloc(1, sizeof (htp_header_line_t)); - if (connp->in_header_line == NULL) return HTP_ERROR; - connp->in_header_line->first_nul_offset = -1; - } - - // Keep track of NUL bytes - if (connp->in_next_byte == 0) { - // Store the offset of the first NUL - if (connp->in_header_line->has_nulls == 0) { - connp->in_header_line->first_nul_offset = connp->in_line_len; - } - - // Remember how many NULs there were - connp->in_header_line->flags |= HTP_FIELD_NUL_BYTE; - connp->in_header_line->has_nulls++; - } - - // Have we reached the end of the line? - if (connp->in_next_byte == LF) { - #ifdef HTP_DEBUG - fprint_raw_data(stderr, __FUNCTION__, connp->in_line, connp->in_line_len); - #endif - - // Should we terminate headers? - if (htp_connp_is_line_terminator(connp, connp->in_line, connp->in_line_len)) { - // Terminator line - - // Parse previous header, if any - if (connp->in_header_line_index != -1) { - if (connp->cfg->process_request_header(connp) != HTP_OK) { - // Note: downstream responsible for error logging - return HTP_ERROR; - } - - // Reset index - connp->in_header_line_index = -1; - } - - // Cleanup - free(connp->in_header_line); - connp->in_line_len = 0; - connp->in_header_line = NULL; - - // We've seen all request headers - if (connp->in_chunk_count != connp->in_chunk_request_index) { - connp->in_tx->flags |= HTP_MULTI_PACKET_HEAD; - } - - // Move onto the next processing phase - if (connp->in_tx->progress[0] == TX_PROGRESS_REQ_HEADERS) { - // Determine if this request has a body - //connp->in_state = htp_connp_REQ_BODY_DETERMINE; - connp->in_state = htp_connp_REQ_CONNECT_CHECK; - } else { - // Run hook REQUEST_TRAILER - int rc = hook_run_all(connp->cfg->hook_request_trailer, connp); - if (rc != HOOK_OK) { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Request trailer callback returned error (%d)", rc); - return HTP_ERROR; - } - - // We've completed parsing this request - connp->in_state = htp_connp_REQ_IDLE; - connp->in_tx->progress[0] = TX_PROGRESS_WAIT; - } - - return HTP_OK; - } - - // Prepare line for consumption - size_t raw_in_line_len = connp->in_line_len; - htp_chomp(connp->in_line, &connp->in_line_len); - - // Check for header folding - if (htp_connp_is_line_folded(connp->in_line, connp->in_line_len) == 0) { - // New header line - - // Parse previous header, if any - if (connp->in_header_line_index != -1) { - if (connp->cfg->process_request_header(connp) != HTP_OK) { - // Note: downstream responsible for error logging - return HTP_ERROR; - } - - // Reset index - connp->in_header_line_index = -1; - } - - // Remember the index of the fist header line - connp->in_header_line_index = connp->in_header_line_counter; - } else { - // Folding; check that there's a previous header line to add to - if (connp->in_header_line_index == -1) { - if (!(connp->in_tx->flags & HTP_INVALID_FOLDING)) { - connp->in_tx->flags |= HTP_INVALID_FOLDING; - htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, - "Invalid request field folding"); - } - } - } - - // Add the raw header line to the list - if (raw_in_line_len > connp->in_line_len) { - if (raw_in_line_len - connp->in_line_len == 2 && - connp->in_line[connp->in_line_len] == 0x0d && - connp->in_line[connp->in_line_len + 1] == 0x0a) { - connp->in_header_line->terminators = NULL; - } else { - connp->in_header_line->terminators = - bstr_memdup((char *) connp->in_line + connp->in_line_len, - raw_in_line_len - connp->in_line_len); - if (connp->in_header_line->terminators == NULL) { - return HTP_ERROR; - } - } - } else { - connp->in_header_line->terminators = NULL; - } - - connp->in_header_line->line = bstr_memdup((char *) connp->in_line, connp->in_line_len); - if (connp->in_header_line->line == NULL) { - return HTP_ERROR; - } - list_add(connp->in_tx->request_header_lines, connp->in_header_line); - connp->in_header_line = NULL; - - // Cleanup for the next line - connp->in_line_len = 0; - if (connp->in_header_line_index == -1) { - connp->in_header_line_index = connp->in_header_line_counter; - } - - connp->in_header_line_counter++; - } - } - return HTP_ERROR; -} - -/** - * Determines request protocol. - * - * @param connp - * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. - */ -int htp_connp_REQ_PROTOCOL(htp_connp_t *connp) { - // Is this a short-style HTTP/0.9 request? If it is, - // we will not want to parse request headers. - if (connp->in_tx->protocol_is_simple == 0) { - // Switch to request header parsing. - connp->in_state = htp_connp_REQ_HEADERS; - connp->in_tx->progress[0] = TX_PROGRESS_REQ_HEADERS; - } else { - // We're done with this request. - connp->in_state = htp_connp_REQ_IDLE; - connp->in_tx->progress[0] = TX_PROGRESS_WAIT; - } - - return HTP_OK; -} - -/** - * Parses request line. - * - * @param connp - * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. - */ -int htp_connp_REQ_LINE(htp_connp_t *connp) { - for (;;) { - // Get one byte - IN_COPY_BYTE_OR_RETURN(connp); - - // Keep track of NUL bytes - if (connp->in_next_byte == 0) { - // Remember how many NULs there were - connp->in_tx->request_line_nul++; - - // Store the offset of the first NUL byte - if (connp->in_tx->request_line_nul_offset == -1) { - connp->in_tx->request_line_nul_offset = connp->in_line_len; - } - } - - // Have we reached the end of the line? - if (connp->in_next_byte == LF) { - #ifdef HTP_DEBUG - fprint_raw_data(stderr, __FUNCTION__, connp->in_line, connp->in_line_len); - #endif - - // Is this a line that should be ignored? - if (htp_connp_is_line_ignorable(connp, connp->in_line, connp->in_line_len)) { - // We have an empty/whitespace line, which we'll note, ignore and move on - connp->in_tx->request_ignored_lines++; - - // TODO How many empty lines are we willing to accept? - - // Start again - connp->in_line_len = 0; - - return HTP_OK; - } - - // Process request line - - htp_chomp(connp->in_line, &connp->in_line_len); - connp->in_tx->request_line = bstr_memdup((char *) connp->in_line, connp->in_line_len); - if (connp->in_tx->request_line == NULL) { - return HTP_ERROR; - } - - // Parse request line - if (connp->cfg->parse_request_line(connp) != HTP_OK) { - // Note: downstream responsible for error logging - return HTP_ERROR; - } - - if (connp->in_tx->request_method_number == M_CONNECT) { - // Parse authority - if (htp_parse_authority(connp, connp->in_tx->request_uri, &(connp->in_tx->parsed_uri_incomplete)) != HTP_OK) { - // Note: downstream responsible for error logging - return HTP_ERROR; - } - } else { - // Parse the request URI - if (htp_parse_uri(connp->in_tx->request_uri, &(connp->in_tx->parsed_uri_incomplete)) != HTP_OK) { - // Note: downstream responsible for error logging - return HTP_ERROR; - } - - // Keep the original URI components, but - // create a copy which we can normalize and use internally - if (htp_normalize_parsed_uri(connp, connp->in_tx->parsed_uri_incomplete, connp->in_tx->parsed_uri)) { - // Note: downstream responsible for error logging - return HTP_ERROR; - } - - // Run hook REQUEST_URI_NORMALIZE - int rc = hook_run_all(connp->cfg->hook_request_uri_normalize, connp); - if (rc != HOOK_OK) { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Request URI normalize callback returned error (%d)", rc); - return HTP_ERROR; - } - - // Now is a good time to generate request_uri_normalized, before we finalize - // parsed_uri (and lose the information which parts were provided in the request and - // which parts we added). - if (connp->cfg->generate_request_uri_normalized) { - connp->in_tx->request_uri_normalized = htp_unparse_uri_noencode(connp->in_tx->parsed_uri); - - if (connp->in_tx->request_uri_normalized == NULL) { - // There's no sense in logging anything on a memory allocation failure - return HTP_ERROR; - } - - #ifdef HTP_DEBUG - fprint_raw_data(stderr, "request_uri_normalized", - (unsigned char *) bstr_ptr(connp->in_tx->request_uri_normalized), - bstr_len(connp->in_tx->request_uri_normalized)); - #endif - } - - // Finalize parsed_uri - - // Scheme - if (connp->in_tx->parsed_uri->scheme != NULL) { - if (bstr_cmpc(connp->in_tx->parsed_uri->scheme, "http") != 0) { - // TODO Invalid scheme - } - } else { - connp->in_tx->parsed_uri->scheme = bstr_cstrdup("http"); - if (connp->in_tx->parsed_uri->scheme == NULL) { - return HTP_ERROR; - } - } - - // Port - if (connp->in_tx->parsed_uri->port != NULL) { - if (connp->in_tx->parsed_uri->port_number != -1) { - // Check that the port in the URI is the same - // as the port on which the client is talking - // to the server - if (connp->in_tx->parsed_uri->port_number != connp->conn->local_port) { - // Incorrect port; use the real port instead - connp->in_tx->parsed_uri->port_number = connp->conn->local_port; - // TODO Log - } - } else { - // Invalid port; use the real port instead - connp->in_tx->parsed_uri->port_number = connp->conn->local_port; - // TODO Log - } - } else { - connp->in_tx->parsed_uri->port_number = connp->conn->local_port; - } - - // Path - if (connp->in_tx->parsed_uri->path == NULL) { - connp->in_tx->parsed_uri->path = bstr_cstrdup("/"); - if (connp->in_tx->parsed_uri->path == NULL) { - return HTP_ERROR; - } - } - } - - // Run hook REQUEST_LINE - int rc = hook_run_all(connp->cfg->hook_request_line, connp); - if (rc != HOOK_OK) { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Request line callback returned error (%d)", rc); - return HTP_ERROR; - } - - // Clean up. - connp->in_line_len = 0; - - // Move on to the next phase. - connp->in_state = htp_connp_REQ_PROTOCOL; - - return HTP_OK; - } - } - return HTP_ERROR; -} - -/** - * The idle state is invoked before and after every transaction. Consequently, - * it will start a new transaction when data is available and finalise a transaction - * which has been processed. - * - * @param connp - * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. - */ -int htp_connp_REQ_IDLE(htp_connp_t * connp) { - // If we're here and a transaction object exists that - // means we've just completed parsing a request. We need - // to run the final hook and start over. - if (connp->in_tx != NULL) { - // Run hook REQUEST - int rc = hook_run_all(connp->cfg->hook_request, connp); - if (rc != HOOK_OK) { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Request callback returned error (%d)", rc); - return HTP_ERROR; - } - - // Start afresh - connp->in_tx = NULL; - } - - // We want to start parsing the next request (and change - // the state from IDLE) only if there's at least one - // byte of data available. Otherwise we could be creating - // new structures even if there's no more data on the - // connection. - IN_TEST_NEXT_BYTE_OR_RETURN(connp); - - // Detect pipelining - if (list_size(connp->conn->transactions) > connp->out_next_tx_index) { - connp->conn->flags |= PIPELINED_CONNECTION; - } - - // Parsing a new request - connp->in_tx = htp_tx_create(connp->cfg, CFG_SHARED, connp->conn); - if (connp->in_tx == NULL) return HTP_ERROR; - - connp->in_tx->connp = connp; - - list_add(connp->conn->transactions, connp->in_tx); - - connp->in_content_length = -1; - connp->in_body_data_left = -1; - connp->in_header_line_index = -1; - connp->in_header_line_counter = 0; - connp->in_chunk_request_index = connp->in_chunk_count; - - // Run hook TRANSACTION_START - int rc = hook_run_all(connp->cfg->hook_transaction_start, connp); - if (rc != HOOK_OK) { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Transaction start callback returned error (%d)", rc); - return HTP_ERROR; - } - - // Change state into request line parsing - connp->in_state = htp_connp_REQ_LINE; - connp->in_tx->progress[0] = TX_PROGRESS_REQ_LINE; - - return HTP_OK; -} - -size_t htp_connp_req_data_consumed(htp_connp_t *connp) { - return connp->in_current_offset; -} - -/** - * Process a chunk of inbound (client or request) data. - * - * @param connp - * @param timestamp - * @param data - * @param len - * @return HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. - */ -int htp_connp_req_data(htp_connp_t *connp, htp_time_t timestamp, unsigned char *data, size_t len) { - #ifdef HTP_DEBUG - fprintf(stderr, "htp_connp_req_data(connp->in_status %x)\n", connp->in_status); - fprint_raw_data(stderr, __FUNCTION__, data, len); - #endif - - // Return if the connection has had a fatal error - if (connp->in_status == STREAM_STATE_ERROR) { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Inbound parser is in STREAM_STATE_ERROR"); - - #ifdef HTP_DEBUG - fprintf(stderr, "htp_connp_req_data: returning STREAM_STATE_DATA (previous error)\n"); - #endif - - return STREAM_STATE_ERROR; - } - - // If the length of the supplied data chunk is zero, proceed - // only if the stream has been closed. We do not allow zero-sized - // chunks in the API, but we use it internally to force the parsers - // to finalize parsing. - if ((len == 0) && (connp->in_status != STREAM_STATE_CLOSED)) { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Zero-length data chunks are not allowed"); - - #ifdef HTP_DEBUG - fprintf(stderr, "htp_connp_req_data: returning STREAM_STATE_DATA (zero-length chunk)\n"); - #endif - - return STREAM_STATE_ERROR; - } - - // Store the current chunk information - connp->in_timestamp = timestamp; - connp->in_current_data = data; - connp->in_current_len = len; - connp->in_current_offset = 0; - connp->in_chunk_count++; - connp->conn->in_data_counter += len; - connp->conn->in_packet_counter++; - - // Return without processing any data if the stream is in tunneling - // mode (which it would be after an initial CONNECT transaction). - if (connp->in_status == STREAM_STATE_TUNNEL) { - #ifdef HTP_DEBUG - fprintf(stderr, "htp_connp_req_data: returning STREAM_STATE_TUNNEL\n"); - #endif - return STREAM_STATE_TUNNEL; - } - - // Invoke a processor, in a loop, until an error - // occurs or until we run out of data. Many processors - // will process a request, each pointing to the next - // processor that needs to run. - for (;;) { - #ifdef HTP_DEBUG - fprintf(stderr, "htp_connp_req_data: in state=%s, progress=%s\n", - htp_connp_in_state_as_string(connp), - htp_tx_progress_as_string(connp->in_tx, 0)); - #endif - - // Return if there's been an error - // or if we've run out of data. We are relying - // on processors to add error messages, so we'll - // keep quiet here. - int rc = connp->in_state(connp); - if (rc == HTP_OK) { - if (connp->in_status == STREAM_STATE_TUNNEL) { - #ifdef HTP_DEBUG - fprintf(stderr, "htp_connp_req_data: returning STREAM_STATE_TUNNEL\n"); - #endif - - return STREAM_STATE_TUNNEL; - } - } else { - // Do we need more data? - if (rc == HTP_DATA) { - #ifdef HTP_DEBUG - fprintf(stderr, "htp_connp_req_data: returning STREAM_STATE_DATA\n"); - #endif - - return STREAM_STATE_DATA; - } - - // Check for suspended parsing - if (rc == HTP_DATA_OTHER) { - // We might have actually consumed the entire data chunk? - if (connp->in_current_offset >= connp->in_current_len) { - // Do not send STREAM_DATE_DATA_OTHER if we've - // consumed the entire chunk - #ifdef HTP_DEBUG - fprintf(stderr, "htp_connp_req_data: returning STREAM_STATE_DATA (suspended parsing)\n"); - #endif - return STREAM_STATE_DATA; - } else { - // Partial chunk consumption - #ifdef HTP_DEBUG - fprintf(stderr, "htp_connp_req_data: returning STREAM_STATE_DATA_OTHER\n"); - #endif - return STREAM_STATE_DATA_OTHER; - } - } - - // Remember that we've had an error. Errors are - // (at least at present) not possible to recover from. - connp->in_status = STREAM_STATE_ERROR; - - #ifdef HTP_DEBUG - fprintf(stderr, "htp_connp_req_data: returning STREAM_STATE_ERROR (state response)\n"); - #endif - - return STREAM_STATE_ERROR; - } - } - return HTP_ERROR; -} - diff --git a/libhtp/htp/htp_request_apache_2_2.c b/libhtp/htp/htp_request_apache_2_2.c deleted file mode 100644 index e8e0f30cc7..0000000000 --- a/libhtp/htp/htp_request_apache_2_2.c +++ /dev/null @@ -1,336 +0,0 @@ -/* - * LibHTP (http://www.libhtp.org) - * Copyright 2009,2010 Ivan Ristic - * - * LibHTP is an open source product, released under terms of the General Public Licence - * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text - * of the license. - * - * In addition, there is a special exception that allows LibHTP to be freely - * used with any OSI-approved open source licence. Please refer to the file - * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. - * - */ - -#include "htp.h" - -/** - * Extract one request header. A header can span multiple lines, in - * which case they will be folded into one before parsing is attempted. - * - * @param connp - * @return HTP_OK or HTP_ERROR - */ -int htp_process_request_header_apache_2_2(htp_connp_t *connp) { - bstr *tempstr = NULL; - unsigned char *data = NULL; - size_t len = 0; - - // Create new header structure - htp_header_t *h = calloc(1, sizeof (htp_header_t)); - if (h == NULL) return HTP_ERROR; - - // Ensure we have the necessary header data in a single buffer - if (connp->in_header_line_index + 1 == connp->in_header_line_counter) { - // Single line - htp_header_line_t *hl = list_get(connp->in_tx->request_header_lines, - connp->in_header_line_index); - if (hl == NULL) { - // Internal error - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Process request header (Apache 2.2): Internal error"); - free(h); - return HTP_ERROR; - } - - data = (unsigned char *) bstr_ptr(hl->line); - len = bstr_len(hl->line); - hl->header = h; - } else { - // Multiple lines (folded) - int i = 0; - - for (i = connp->in_header_line_index; i < connp->in_header_line_counter; i++) { - htp_header_line_t *hl = list_get(connp->in_tx->request_header_lines, i); - if (hl == NULL) { - // Internal error - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Process request header (Apache 2.2): Internal error"); - free(h); - return HTP_ERROR; - } - len += bstr_len(hl->line); - } - - tempstr = bstr_alloc(len); - if (tempstr == NULL) { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Process request header (Apache 2.2): Failed to allocate bstring of %d bytes", len); - free(h); - return HTP_ERROR; - } - - for (i = connp->in_header_line_index; i < connp->in_header_line_counter; i++) { - htp_header_line_t *hl = list_get(connp->in_tx->request_header_lines, i); - if (hl == NULL) { - // Internal error - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Process request header (Apache 2.2): Internal error"); - bstr_free(tempstr); - free(h); - return HTP_ERROR; - } - char *data = bstr_ptr(hl->line); - size_t len = bstr_len(hl->line); - htp_chomp((unsigned char *)data, &len); - bstr_add_mem_noex(tempstr, data, len); - hl->header = h; - } - - data = (unsigned char *) bstr_ptr(tempstr); - } - - // Now try to parse the header - if (htp_parse_request_header_apache_2_2(connp, h, data, len) != HTP_OK) { - // Note: downstream responsible for error logging - if (tempstr != NULL) { - free(tempstr); - } - free(h); - return HTP_ERROR; - } - - // Do we already have a header with the same name? - htp_header_t *h_existing = table_get(connp->in_tx->request_headers, h->name); - if (h_existing != NULL) { - // TODO Do we want to keep a list of the headers that are - // allowed to be combined in this way? - - // Add to existing header - h_existing->value = bstr_expand(h_existing->value, bstr_len(h_existing->value) - + 2 + bstr_len(h->value)); - bstr_add_mem_noex(h_existing->value, ", ", 2); - bstr_add_str_noex(h_existing->value, h->value); - - // The header is no longer needed - if (h->name != NULL) - free(h->name); - if (h->value != NULL) - free(h->value); - free(h); - - // Keep track of same-name headers - h_existing->flags |= HTP_FIELD_REPEATED; - } else { - // Add as a new header - table_add(connp->in_tx->request_headers, h->name, h); - } - - if (tempstr != NULL) { - free(tempstr); - } - - return HTP_OK; -} - -/** - * Parses a message header line as Apache 2.2 does. - * - * @param connp - * @param h - * @param data - * @param len - * @return HTP_OK or HTP_ERROR - */ -int htp_parse_request_header_apache_2_2(htp_connp_t *connp, htp_header_t *h, unsigned char *data, size_t len) { - size_t name_start, name_end; - size_t value_start, value_end; - - htp_chomp(data, &len); - - name_start = 0; - - // Look for the colon - size_t colon_pos = 0; - while ((colon_pos < len) && (data[colon_pos] != '\0') && (data[colon_pos] != ':')) colon_pos++; - - if ((colon_pos == len) || (data[colon_pos] == '\0')) { - // Missing colon - h->flags |= HTP_FIELD_UNPARSEABLE; - - if (!(connp->in_tx->flags & HTP_FIELD_UNPARSEABLE)) { - connp->in_tx->flags |= HTP_FIELD_UNPARSEABLE; - // Only log once per transaction - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Request field invalid: colon missing"); - } - - return HTP_ERROR; - } - - if (colon_pos == 0) { - // Empty header name - h->flags |= HTP_FIELD_INVALID; - - if (!(connp->in_tx->flags & HTP_FIELD_INVALID)) { - connp->in_tx->flags |= HTP_FIELD_INVALID; - // Only log once per transaction - htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Request field invalid: empty name"); - } - } - - name_end = colon_pos; - - // Ignore LWS after field-name - size_t prev = name_end - 1; - while ((prev > name_start) && (htp_is_lws(data[prev]))) { - prev--; - name_end--; - - h->flags |= HTP_FIELD_INVALID; - - if (!(connp->in_tx->flags & HTP_FIELD_INVALID)) { - connp->in_tx->flags |= HTP_FIELD_INVALID; - htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Request field invalid: LWS after name"); - } - } - - // Value - - value_start = colon_pos; - - // Go over the colon - if (value_start < len) { - value_start++; - } - - // Ignore LWS before field-content - while ((value_start < len) && (htp_is_lws(data[value_start]))) { - value_start++; - } - - // Look for the end of field-content - value_end = value_start; - while ((value_end < len) && (data[value_end] != '\0')) value_end++; - - // Ignore LWS after field-content - prev = value_end - 1; - while ((prev > value_start) && (htp_is_lws(data[prev]))) { - prev--; - value_end--; - } - - // Check that the header name is a token - size_t i = name_start; - while (i < name_end) { - if (!htp_is_token(data[i])) { - h->flags |= HTP_FIELD_INVALID; - - if (!(connp->in_tx->flags & HTP_FIELD_INVALID)) { - connp->in_tx->flags |= HTP_FIELD_INVALID; - htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Request header name is not a token"); - } - - break; - } - - i++; - } - - // Now extract the name and the value - h->name = bstr_memdup((char *) data + name_start, name_end - name_start); - if (h->name == NULL) - return HTP_ERROR; - h->value = bstr_memdup((char *) data + value_start, value_end - value_start); - if (h->value == NULL) { - bstr_free(h->name); - return HTP_ERROR; - } - - return HTP_OK; -} - -/** - * Parse request line as Apache 2.2 does. - * - * @param connp - * @return HTP_OK or HTP_ERROR - */ -int htp_parse_request_line_apache_2_2(htp_connp_t *connp) { - htp_tx_t *tx = connp->in_tx; - unsigned char *data = (unsigned char *) bstr_ptr(tx->request_line); - size_t len = bstr_len(tx->request_line); - size_t pos = 0; - - // In this implementation we assume the - // line ends with the first NUL byte. - if (tx->request_line_nul_offset != -1) { - len = tx->request_line_nul_offset - 1; - } - - // The request method starts at the beginning of the - // line and ends with the first whitespace character. - while ((pos < len) && (!htp_is_space(data[pos]))) { - pos++; - } - - // No, we don't care if the method is empty. - - tx->request_method = bstr_memdup((char *) data, pos); - if (tx->request_method == NULL) { - return HTP_ERROR; - } - -#ifdef HTP_DEBUG - fprint_raw_data(stderr, __FUNCTION__, (unsigned char *)bstr_ptr(tx->request_method), bstr_len(tx->request_method)); -#endif - - tx->request_method_number = htp_convert_method_to_number(tx->request_method); - - // Ignore whitespace after request method. The RFC allows - // for only one SP, but then suggests any number of SP and HT - // should be permitted. Apache uses isspace(), which is even - // more permitting, so that's what we use here. - while ((pos < len) && (isspace(data[pos]))) { - pos++; - } - - size_t start = pos; - - // The URI ends with the first whitespace. - while ((pos < len) && (!htp_is_space(data[pos]))) { - pos++; - } - - tx->request_uri = bstr_memdup((char *) data + start, pos - start); - if (tx->request_uri == NULL) { - return HTP_ERROR; - } - -#ifdef HTP_DEBUG - fprint_raw_data(stderr, __FUNCTION__, (unsigned char *)bstr_ptr(tx->request_uri), bstr_len(tx->request_uri)); -#endif - - // Ignore whitespace after URI - while ((pos < len) && (htp_is_space(data[pos]))) { - pos++; - } - - // Is there protocol information available? - if (pos == len) { - // No, this looks like a HTTP/0.9 request. - tx->protocol_is_simple = 1; - return HTP_OK; - } - - // The protocol information spreads until the end of the line. - tx->request_protocol = bstr_memdup((char *) data + pos, len - pos); - if (tx->request_protocol == NULL) - return HTP_ERROR; - tx->request_protocol_number = htp_parse_protocol(tx->request_protocol); - -#ifdef HTP_DEBUG - fprint_raw_data(stderr, __FUNCTION__, (unsigned char *)bstr_ptr(tx->request_protocol), bstr_len(tx->request_protocol)); -#endif - - return HTP_OK; -} diff --git a/libhtp/htp/htp_request_generic.c b/libhtp/htp/htp_request_generic.c deleted file mode 100644 index 56ad6ffd5f..0000000000 --- a/libhtp/htp/htp_request_generic.c +++ /dev/null @@ -1,309 +0,0 @@ -/* - * LibHTP (http://www.libhtp.org) - * Copyright 2009,2010 Ivan Ristic - * - * LibHTP is an open source product, released under terms of the General Public Licence - * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text - * of the license. - * - * In addition, there is a special exception that allows LibHTP to be freely - * used with any OSI-approved open source licence. Please refer to the file - * LIBHTP_LICENSING_EXCEPTION fo the full text of the exception. - * - */ - -#include "htp.h" - -/** - * Extract one request header. A header can span multiple lines, in - * which case they will be folded into one before parsing is attempted. - * - * @param connp - * @return HTP_OK or HTP_ERROR - */ -int htp_process_request_header_generic(htp_connp_t *connp) { - bstr *tempstr = NULL; - unsigned char *data = NULL; - size_t len = 0; - - // Create new header structure - htp_header_t *h = calloc(1, sizeof (htp_header_t)); - if (h == NULL) { - // TODO - return HTP_ERROR; - } - - // Ensure we have the necessary header data in a single buffer - if (connp->in_header_line_index + 1 == connp->in_header_line_counter) { - // Single line - htp_header_line_t *hl = list_get(connp->in_tx->request_header_lines, - connp->in_header_line_index); - if (hl == NULL) { - // Internal error - // TODO - free(h); - return HTP_ERROR; - } - - data = (unsigned char *)bstr_ptr(hl->line); - if (data == NULL) { - free(h); - return HTP_ERROR; - } - len = bstr_len(hl->line); - hl->header = h; - } else { - // Multiple lines (folded) - int i = 0; - - for (i = connp->in_header_line_index; i < connp->in_header_line_counter; i++) { - htp_header_line_t *hl = list_get(connp->in_tx->request_header_lines, i); - len += bstr_len(hl->line); - } - - tempstr = bstr_alloc(len); - if (tempstr == NULL) { - // TODO - free(h); - return HTP_ERROR; - } - - for (i = connp->in_header_line_index; i < connp->in_header_line_counter; i++) { - htp_header_line_t *hl = list_get(connp->in_tx->request_header_lines, i); - char *data = bstr_ptr(hl->line); - size_t len = bstr_len(hl->line); - htp_chomp((unsigned char *)data, &len); - bstr_add_mem_noex(tempstr, data, len); - hl->header = h; - } - - data = (unsigned char *)bstr_ptr(tempstr); - } - - // Now try to oparse the header - if (htp_parse_request_header_generic(connp, h, data, len) != HTP_OK) { - if (tempstr != NULL) { - free(tempstr); - } - - free(h); - - return HTP_ERROR; - } - - // Do we already have a header with the same name? - htp_header_t *h_existing = table_get(connp->in_tx->request_headers, h->name); - if (h_existing != NULL) { - // TODO Do we want to keep a list of the headers that are - // allowed to be combined in this way? - - // Add to existing header - h_existing->value = bstr_expand(h_existing->value, bstr_len(h_existing->value) - + 2 + bstr_len(h->value)); - bstr_add_mem_noex(h_existing->value, ", ", 2); - bstr_add_str_noex(h_existing->value, h->value); - - // The header is no longer needed - free(h->name); - free(h->value); - free(h); - - // Keep track of same-name headers - h_existing->flags |= HTP_FIELD_REPEATED; - } else { - // Add as a new header - table_add(connp->in_tx->request_headers, h->name, h); - } - - if (tempstr != NULL) { - free(tempstr); - } - - return HTP_OK; -} - -/** - * Generic request header parser. - * - * @param connp - * @param h - * @param data - * @param len - * @return HTP_OK or HTP_ERROR - */ -int htp_parse_request_header_generic(htp_connp_t *connp, htp_header_t *h, unsigned char *data, size_t len) { - size_t name_start, name_end; - size_t value_start, value_end; - - htp_chomp(data, &len); - - name_start = 0; - - // Look for the colon - size_t colon_pos = 0; - - while ((colon_pos < len) && (data[colon_pos] != ':')) colon_pos++; - - if (colon_pos == len) { - // Missing colon - h->flags |= HTP_FIELD_UNPARSEABLE; - - if (!(connp->in_tx->flags & HTP_FIELD_UNPARSEABLE)) { - connp->in_tx->flags |= HTP_FIELD_UNPARSEABLE; - // Only log once per transaction - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Request field invalid: colon missing"); - } - - return HTP_ERROR; - } - - if (colon_pos == 0) { - // Empty header name - h->flags |= HTP_FIELD_INVALID; - - if (!(connp->in_tx->flags & HTP_FIELD_INVALID)) { - connp->in_tx->flags |= HTP_FIELD_INVALID; - // Only log once per transaction - htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Request field invalid: empty name"); - } - } - - name_end = colon_pos; - - // Ignore LWS after field-name - size_t prev = name_end - 1; - while ((prev > name_start) && (htp_is_lws(data[prev]))) { - prev--; - name_end--; - - h->flags |= HTP_FIELD_INVALID; - - if (!(connp->in_tx->flags & HTP_FIELD_INVALID)) { - connp->in_tx->flags |= HTP_FIELD_INVALID; - htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Request field invalid: LWS after name"); - } - } - - // Value - - value_start = colon_pos; - - // Go over the colon - if (value_start < len) { - value_start++; - } - - // Ignore LWS before field-content - while ((value_start < len) && (htp_is_lws(data[value_start]))) { - value_start++; - } - - // Look for the end of field-content - value_end = value_start; - - while (value_end < len) value_end++; - - // Ignore LWS after field-content - prev = value_end - 1; - while ((prev > value_start) && (htp_is_lws(data[prev]))) { - prev--; - value_end--; - } - - // Check that the header name is a token - size_t i = name_start; - while (i < name_end) { - if (!htp_is_token(data[i])) { - h->flags |= HTP_FIELD_INVALID; - - if (!(connp->in_tx->flags & HTP_FIELD_INVALID)) { - connp->in_tx->flags |= HTP_FIELD_INVALID; - htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Request header name is not a token"); - } - - break; - } - - i++; - } - - // Now extract the name and the value - h->name = bstr_memdup((char *)data + name_start, name_end - name_start); - if (h->name == NULL) { - return HTP_ERROR; - } - h->value = bstr_memdup((char *)data + value_start, value_end - value_start); - if (h->name == NULL) { - return HTP_ERROR; - } - - return HTP_OK; -} - -/** - * Generic request line parser. - * - * @param connp - * @return HTP_OK or HTP_ERROR - */ -int htp_parse_request_line_generic(htp_connp_t *connp) { - htp_tx_t *tx = connp->in_tx; - unsigned char *data = (unsigned char *)bstr_ptr(tx->request_line); - size_t len = bstr_len(tx->request_line); - size_t pos = 0; - - // The request method starts at the beginning of the - // line and ends with the first whitespace character. - while ((pos < len) && (!htp_is_space(data[pos]))) { - pos++; - } - - // No, we don't care if the method is empty. - - tx->request_method = bstr_memdup((char *)data, pos); - if (tx->request_method == NULL) { - return HTP_ERROR; - } - tx->request_method_number = htp_convert_method_to_number(tx->request_method); - - // Ignore whitespace after request method. The RFC allows - // for only one SP, but then suggests any number of SP and HT - // should be permitted. - while ((pos < len) && (isspace(data[pos]))) { - pos++; - } - - size_t start = pos; - - // The URI ends with the first whitespace. - while ((pos < len) && (!htp_is_space(data[pos]))) { - pos++; - } - - tx->request_uri = bstr_memdup((char *)data + start, pos - start); - if (tx->request_uri == NULL) { - return HTP_ERROR; - } - - // Ignore whitespace after URI - while ((pos < len) && (htp_is_space(data[pos]))) { - pos++; - } - - // Is there protocol information available? - if (pos == len) { - // No, this looks like a HTTP/0.9 request. - tx->protocol_is_simple = 1; - return HTP_OK; - } - - // The protocol information spreads until the end of the line. - tx->request_protocol = bstr_memdup((char *)data + pos, len - pos); - if (tx->request_protocol == NULL) { - return HTP_ERROR; - } - tx->request_protocol_number = htp_parse_protocol(tx->request_protocol); - - return HTP_OK; -} - diff --git a/libhtp/htp/htp_request_parsers.c b/libhtp/htp/htp_request_parsers.c deleted file mode 100644 index 33080bcd2f..0000000000 --- a/libhtp/htp/htp_request_parsers.c +++ /dev/null @@ -1,123 +0,0 @@ -/* - * LibHTP (http://www.libhtp.org) - * Copyright 2009,2010 Ivan Ristic - * - * LibHTP is an open source product, released under terms of the General Public Licence - * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text - * of the license. - * - * In addition, there is a special exception that allows LibHTP to be freely - * used with any OSI-approved open source licence. Please refer to the file - * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. - * - */ - -#include "htp.h" - -#if 0 - -/** - * - */ -int htp_header_parse_internal_strict(unsigned char *data, size_t len, htp_header_t *h) { - size_t name_start, name_end; - size_t value_start, value_end; - - // Deal with the name first - name_start = name_end = 0; - - // Find where the header name ends - while (name_end < len) { - if (htp_is_lws(data[name_end]) || data[name_end] == ':') break; - name_end++; - } - - if (name_end == 0) { - // Empty header name - return -1; - } - - if (name_end == len) { - // TODO - return -1; - } - - // Is there any LWS before colon? - size_t pos = name_end; - while (pos < len) { - if (!htp_is_lws(data[pos])) break; - pos++; - // TODO - // return -1; - } - - if (pos == len) { - // TODO - return -1; - } - - // The next character must be a colon - if (data[pos] != ':') { - // TODO - return -1; - } - - // Move over the colon - pos++; - - // Again, ignore any LWS - while (pos < len) { - if (!htp_is_lws(data[pos])) break; - pos++; - } - - if (pos == len) { - // TODO - return -1; - } - - value_start = value_end = pos; - - while (value_end < len) { - if (htp_is_lws(data[value_end])) break; - value_end++; - } - - h->name_offset = name_start; - h->name_len = name_end - name_start; - h->value_offset = value_start; - h->value_len = value_end - value_start; - - return 1; -} - */ - -/** - * - */ -htp_header_t *htp_connp_header_parse(htp_connp_t *reqp, unsigned char *data, size_t len) { - htp_header_t *h = calloc(1, sizeof (htp_header_t)); - if (h == NULL) return NULL; - - // Parse the header line - if (reqp->impl_header_parse(data, len, h) < 0) { - // Invalid header line - h->is_parsed = 0; - h->name = bstr_memdup(data, len); - - return h; - } - - // Now extract the name and the value - h->name = bstr_memdup(data + h->name_offset, h->name_len); - h->value = bstr_memdup(data + h->value_offset, h->value_len); - h->is_parsed = 1; - - // Because header names are case-insensitive, we will convert - // the name to lowercase to use it as a lookup key. - h->name_lowercase = bstr_tolowercase(h->name); - - return h; -} - -#endif diff --git a/libhtp/htp/htp_response.c b/libhtp/htp/htp_response.c deleted file mode 100644 index 3a0a24432e..0000000000 --- a/libhtp/htp/htp_response.c +++ /dev/null @@ -1,848 +0,0 @@ -/* - * LibHTP (http://www.libhtp.org) - * Copyright 2009,2010 Ivan Ristic - * - * LibHTP is an open source product, released under terms of the General Public Licence - * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text - * of the license. - * - * In addition, there is a special exception that allows LibHTP to be freely - * used with any OSI-approved open source licence. Please refer to the file - * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. - * - */ - -#include -#include "htp.h" - -/** - * Invoked whenever decompressed response body data becomes available. - * - * @param d - * @return HTP_OK on state change, HTP_ERROR on error. - */ -static int htp_connp_RES_BODY_DECOMPRESSOR_CALLBACK(htp_tx_data_t *d) { - // Invoke all callbacks - int rc = hook_run_all(d->tx->connp->cfg->hook_response_body_data, d); - if (rc != HTP_OK) { - htp_log(d->tx->connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Response body data callback returned error (%d)", rc); - return HTP_ERROR; - } - - return HTP_OK; -} - -/** - * Consumes bytes until the end of the current line. - * - * @param connp - * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. - */ -int htp_connp_RES_BODY_CHUNKED_DATA_END(htp_connp_t *connp) { - // TODO We shouldn't really see anything apart from CR and LF, - // so we should warn about anything else. - - for (;;) { - OUT_NEXT_BYTE_OR_RETURN(connp); - - connp->out_tx->request_message_len++; - - if (connp->out_next_byte == LF) { - connp->out_state = htp_connp_RES_BODY_CHUNKED_LENGTH; - - return HTP_OK; - } - } - - return HTP_ERROR; -} - -/** - * Processes a chunk of data. - * - * @param connp - * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. - */ -int htp_connp_RES_BODY_CHUNKED_DATA(htp_connp_t *connp) { - htp_tx_data_t d; - - d.tx = connp->out_tx; - d.data = &connp->out_current_data[connp->out_current_offset]; - d.len = 0; - - for (;;) { - OUT_NEXT_BYTE(connp); - - if (connp->out_next_byte == -1) { - if (connp->out_tx->response_content_encoding != COMPRESSION_NONE) { - connp->out_decompressor->decompress(connp->out_decompressor, &d); - } else { - // Send data to callbacks - int rc = hook_run_all(connp->cfg->hook_response_body_data, &d); - if (rc != HOOK_OK) { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Response body data callback returned error (%d)", rc); - return HTP_ERROR; - } - } - - // Ask for more data - return HTP_DATA; - } else { - connp->out_tx->response_message_len++; - connp->out_tx->response_entity_len++; - connp->out_chunked_length--; - d.len++; - - if (connp->out_chunked_length == 0) { - // End of data chunk - - if (connp->out_tx->response_content_encoding != COMPRESSION_NONE) { - connp->out_decompressor->decompress(connp->out_decompressor, &d); - } else { - // Send data to callbacks - int rc = hook_run_all(connp->cfg->hook_response_body_data, &d); - if (rc != HOOK_OK) { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Response body data callback returned error (%d)", rc); - return HTP_ERROR; - } - } - - connp->out_state = htp_connp_RES_BODY_CHUNKED_DATA_END; - - return HTP_OK; - } - } - } - return HTP_ERROR; -} - -/** - * Extracts chunk length. - * - * @param connp - * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. - */ -int htp_connp_RES_BODY_CHUNKED_LENGTH(htp_connp_t *connp) { - for (;;) { - OUT_COPY_BYTE_OR_RETURN(connp); - - connp->out_tx->response_message_len++; - - // Have we reached the end of the line? - if (connp->out_next_byte == LF) { - htp_chomp(connp->out_line, &connp->out_line_len); - - // Extract chunk length - connp->out_chunked_length = htp_parse_chunked_length(connp->out_line, connp->out_line_len); - - // Cleanup for the next line - connp->out_line_len = 0; - - // Handle chunk length - if (connp->out_chunked_length > 0) { - // More data available - // TODO Add a check for chunk length - connp->out_state = htp_connp_RES_BODY_CHUNKED_DATA; - } else if (connp->out_chunked_length == 0) { - // End of data - connp->out_state = htp_connp_RES_HEADERS; - connp->out_tx->progress[1] = TX_PROGRESS_RES_TRAILER; - } else { - // Invalid chunk length - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Response chunk encoding: Invalid chunk length: %d", connp->out_chunked_length); - return HTP_ERROR; - } - - return HTP_OK; - } - } - return HTP_ERROR; -} - -/** - * Processes identity response body. - * - * @param connp - * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. - */ -int htp_connp_RES_BODY_IDENTITY(htp_connp_t *connp) { - htp_tx_data_t d; - - d.tx = connp->out_tx; - d.data = &connp->out_current_data[connp->out_current_offset]; - d.len = 0; - - for (;;) { - OUT_NEXT_BYTE(connp); - - if (connp->out_next_byte == -1) { - // End of chunk - - // Send data to callbacks - if (d.len != 0) { - if (connp->out_tx->response_content_encoding != COMPRESSION_NONE) { - connp->out_decompressor->decompress(connp->out_decompressor, &d); - } else { - int rc = hook_run_all(connp->cfg->hook_response_body_data, &d); - if (rc != HOOK_OK) { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Response body data callback returned error (%d)", rc); - return HTP_ERROR; - } - } - } - - // If we don't know the length, then we must check - // to see if the stream closed; that would signal the - // end of the response body (and the end of the transaction). - if ((connp->out_content_length == -1) && (connp->out_status == STREAM_STATE_CLOSED)) { - connp->out_state = htp_connp_RES_IDLE; - connp->out_tx->progress[1] = TX_PROGRESS_DONE; - - return HTP_OK; - } else { - // Ask for more data - return HTP_DATA; - } - } else { - connp->out_tx->response_message_len++; - connp->out_tx->response_entity_len++; - - if (connp->out_body_data_left > 0) { - // We know the length of response body - - connp->out_body_data_left--; - d.len++; - - if (connp->out_body_data_left == 0) { - // End of body - - // Send data to callbacks - if (d.len != 0) { - if (connp->out_tx->response_content_encoding != COMPRESSION_NONE) { - connp->out_decompressor->decompress(connp->out_decompressor, &d); - } else { - int rc = hook_run_all(connp->cfg->hook_response_body_data, &d); - if (rc != HOOK_OK) { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Response body data callback returned error (%d)", rc); - return HTP_ERROR; - } - } - } - - // Done - connp->out_state = htp_connp_RES_IDLE; - connp->out_tx->progress[1] = TX_PROGRESS_DONE; - - return HTP_OK; - } - } else { - d.len++; - // We don't know the length of the response body, which means - // that the body will consume all data until the connection - // is closed. - // - // We don't need to do anything here. - } - } - } - return HTP_ERROR; -} - -/** - * Determines presence (and encoding) of a response body. - * - * @param connp - * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. - */ -int htp_connp_RES_BODY_DETERMINE(htp_connp_t *connp) { - // If the request uses the CONNECT method, then not only are we - // to assume there's no body, but we need to ignore all - // subsequent data in the stream. - if ((connp->out_tx->request_method_number == M_CONNECT) - &&(connp->out_tx->response_status_number >= 200) - &&(connp->out_tx->response_status_number <= 299)) - { - connp->out_status = STREAM_STATE_TUNNEL; - connp->out_state = htp_connp_RES_IDLE; - connp->out_tx->progress[1] = TX_PROGRESS_DONE; - - return HTP_OK; - } - - // Check for an interim "100 Continue" - // response. Ignore it if found, and revert back to RES_FIRST_LINE. - if (connp->out_tx->response_status_number == 100) { - if (connp->out_tx->seen_100continue != 0) { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Already seen 100-Continue"); - return HTP_ERROR; - } - - // Ignore any response headers set - table_clear(connp->out_tx->response_headers); - - connp->out_state = htp_connp_RES_LINE; - connp->out_tx->progress[1] = TX_PROGRESS_RES_LINE; - connp->out_tx->seen_100continue++; - - return HTP_OK; - } - - // Check for compression - htp_header_t *ce = table_getc(connp->out_tx->response_headers, "content-encoding"); - if (ce != NULL) { - // TODO Improve detection - // TODO How would a Content-Range header affect us? - if ((bstr_cmpc(ce->value, "gzip") == 0) || (bstr_cmpc(ce->value, "x-gzip") == 0)) { - connp->out_decompressor = (htp_decompressor_t *) htp_gzip_decompressor_create(connp); - if (connp->out_decompressor != NULL) { - connp->out_tx->response_content_encoding = COMPRESSION_GZIP; - connp->out_decompressor->callback = htp_connp_RES_BODY_DECOMPRESSOR_CALLBACK; - } else { - // No need to do anything; the error will have already - // been reported by the failed decompressor. - } - } - } - - // 1. Any response message which MUST NOT include a message-body - // (such as the 1xx, 204, and 304 responses and any response to a HEAD - // request) is always terminated by the first empty line after the - // header fields, regardless of the entity-header fields present in the - // message. - if (((connp->out_tx->response_status_number >= 100) && (connp->out_tx->response_status_number <= 199)) - || (connp->out_tx->response_status_number == 204) || (connp->out_tx->response_status_number == 304) - || (connp->out_tx->request_method_number == M_HEAD)) { - // There's no response body - connp->out_state = htp_connp_RES_IDLE; - } else { - // We have a response body - - htp_header_t *cl = table_getc(connp->out_tx->response_headers, "content-length"); - htp_header_t *te = table_getc(connp->out_tx->response_headers, "transfer-encoding"); - - // 2. If a Transfer-Encoding header field (section 14.40) is present and - // indicates that the "chunked" transfer coding has been applied, then - // the length is defined by the chunked encoding (section 3.6). - if (te != NULL) { - if (bstr_cmpc(te->value, "chunked") != 0) { - // Invalid T-E header value - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Invalid T-E value in response"); - } - - // If the T-E header is present we are going to use it. - connp->out_tx->response_transfer_coding = CHUNKED; - - // We are still going to check for the presence of C-L - if (cl != NULL) { - // This is a violation of the RFC - connp->out_tx->flags |= HTP_REQUEST_SMUGGLING; - // TODO - } - - connp->out_state = htp_connp_RES_BODY_CHUNKED_LENGTH; - connp->out_tx->progress[1] = TX_PROGRESS_RES_BODY; - }// 3. If a Content-Length header field (section 14.14) is present, its - // value in bytes represents the length of the message-body. - else if (cl != NULL) { - // We know the exact length - connp->out_tx->response_transfer_coding = IDENTITY; - - // Check for multiple C-L headers - if (cl->flags & HTP_FIELD_REPEATED) { - connp->out_tx->flags |= HTP_REQUEST_SMUGGLING; - // TODO Log - } - - // Get body length - int i = htp_parse_content_length(cl->value); - if (i < 0) { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Invalid C-L field in response"); - return HTP_ERROR; - } else { - connp->out_content_length = i; - connp->out_body_data_left = connp->out_content_length; - - if (connp->out_content_length != 0) { - connp->out_state = htp_connp_RES_BODY_IDENTITY; - connp->out_tx->progress[1] = TX_PROGRESS_RES_BODY; - } else { - connp->out_state = htp_connp_RES_IDLE; - connp->out_tx->progress[1] = TX_PROGRESS_DONE; - } - } - } else { - // 4. If the message uses the media type "multipart/byteranges", which is - // self-delimiting, then that defines the length. This media type MUST - // NOT be used unless the sender knows that the recipient can parse it; - // the presence in a request of a Range header with multiple byte-range - // specifiers implies that the client can parse multipart/byteranges - // responses. - htp_header_t *ct = table_getc(connp->out_tx->response_headers, "content-type"); - if (ct != NULL) { - // TODO Handle multipart/byteranges - - if (bstr_indexofc_nocase(ct->value, "multipart/byteranges") != -1) { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "C-T multipart/byteranges in responses not supported"); - return HTP_ERROR; - } - } - - // 5. By the server closing the connection. (Closing the connection - // cannot be used to indicate the end of a request body, since that - // would leave no possibility for the server to send back a response.) - connp->out_state = htp_connp_RES_BODY_IDENTITY; - connp->out_tx->progress[1] = TX_PROGRESS_RES_BODY; - } - } - - // NOTE We do not need to check for short-style HTTP/0.9 requests here because - // that is done earlier, before response line parsing begins - - // Run hook RESPONSE_HEADERS_COMPLETE - int rc = hook_run_all(connp->cfg->hook_response_headers, connp); - if (rc != HOOK_OK) { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Response headers callback returned error (%d)", rc); - return HTP_ERROR; - } - - return HTP_OK; -} - -/** - * Parses response headers. - * - * @param connp - * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. - */ -int htp_connp_RES_HEADERS(htp_connp_t *connp) { - for (;;) { - OUT_COPY_BYTE_OR_RETURN(connp); - - if (connp->out_header_line == NULL) { - connp->out_header_line = calloc(1, sizeof (htp_header_line_t)); - if (connp->out_header_line == NULL) return HTP_ERROR; - connp->out_header_line->first_nul_offset = -1; - } - - // Keep track of NUL bytes - if (connp->out_next_byte == 0) { - // Store the offset of the first NUL - if (connp->out_header_line->has_nulls == 0) { - connp->out_header_line->first_nul_offset = connp->out_line_len; - } - - // Remember how many NULs there were - connp->out_header_line->flags |= HTP_FIELD_NUL_BYTE; - connp->out_header_line->has_nulls++; - } - - // Have we reached the end of the line? - if (connp->out_next_byte == LF) { - #ifdef HTP_DEBUG - fprint_raw_data(stderr, __FUNCTION__, connp->out_line, connp->out_line_len); - #endif - - // Should we terminate headers? - if (htp_connp_is_line_terminator(connp, connp->out_line, connp->out_line_len)) { - // Terminator line - - // Parse previous header, if any - if (connp->out_header_line_index != -1) { - if (connp->cfg->process_response_header(connp) != HTP_OK) { - // Note: downstream responsible for error logging - return HTP_ERROR; - } - - // Reset index - connp->out_header_line_index = -1; - } - - // Cleanup - free(connp->out_header_line); - connp->out_line_len = 0; - connp->out_header_line = NULL; - - // We've seen all response headers - if (connp->out_tx->progress[1] == TX_PROGRESS_RES_HEADERS) { - // Determine if this response has a body - connp->out_state = htp_connp_RES_BODY_DETERMINE; - } else { - // Run hook response_TRAILER - int rc = hook_run_all(connp->cfg->hook_response_trailer, connp); - if (rc != HOOK_OK) { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Response trailer callback returned error (%d)", rc); - return HTP_ERROR; - } - - // We've completed parsing this response - connp->out_state = htp_connp_RES_IDLE; - } - - return HTP_OK; - } - - // Prepare line for consumption - size_t raw_out_line_len = connp->out_line_len; - htp_chomp(connp->out_line, &connp->out_line_len); - - // Check for header folding - if (htp_connp_is_line_folded(connp->out_line, connp->out_line_len) == 0) { - // New header line - - // Parse previous header, if any - if (connp->out_header_line_index != -1) { - if (connp->cfg->process_response_header(connp) != HTP_OK) { - // Note: downstream responsible for error logging - return HTP_ERROR; - } - - // Reset index - connp->out_header_line_index = -1; - } - - // Remember the index of the fist header line - connp->out_header_line_index = connp->out_header_line_counter; - } else { - // Folding; check that there's a previous header line to add to - if (connp->out_header_line_index == -1) { - if (!(connp->out_tx->flags & HTP_INVALID_FOLDING)) { - connp->out_tx->flags |= HTP_INVALID_FOLDING; - htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Invalid response field folding"); - } - } - } - - // Add the raw header line to the list - - if (raw_out_line_len > connp->out_line_len) { - if (raw_out_line_len - connp->out_line_len == 2 && - connp->out_line[connp->out_line_len] == 0x0d && - connp->out_line[connp->out_line_len + 1] == 0x0a) { - connp->out_header_line->terminators = NULL; - } else { - connp->out_header_line->terminators = - bstr_memdup((char *) connp->out_line + connp->out_line_len, - raw_out_line_len - connp->out_line_len); - if (connp->out_header_line->terminators == NULL) { - return HTP_ERROR; - } - } - } else { - connp->out_header_line->terminators = NULL; - } - - connp->out_header_line->line = bstr_memdup((char *) connp->out_line, connp->out_line_len); - if (connp->out_header_line->line == NULL) { - return HTP_ERROR; - } - list_add(connp->out_tx->response_header_lines, connp->out_header_line); - connp->out_header_line = NULL; - - // Cleanup for the next line - connp->out_line_len = 0; - if (connp->out_header_line_index == -1) { - connp->out_header_line_index = connp->out_header_line_counter; - } - - connp->out_header_line_counter++; - } - } - return HTP_ERROR; -} - -/** - * Parses response line. - * - * @param connp - * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. - */ -int htp_connp_RES_LINE(htp_connp_t *connp) { - for (;;) { - // Get one byte - OUT_COPY_BYTE_OR_RETURN(connp); - - // Have we reached the end of the line? - if (connp->out_next_byte == LF) { - #ifdef HTP_DEBUG - fprint_raw_data(stderr, __FUNCTION__, connp->out_line, connp->out_line_len); - #endif - - // Is this a line that should be ignored? - if (htp_connp_is_line_ignorable(connp, connp->out_line, connp->out_line_len)) { - // We have an empty/whitespace line, which we'll note, ignore and move on - connp->out_tx->response_ignored_lines++; - - // TODO How many lines are we willing to accept? - - // Start again - connp->out_line_len = 0; - - return HTP_OK; - } - - // Process response line - - htp_chomp(connp->out_line, &connp->out_line_len); - - // Deallocate previous response line allocations, which we woud have on a 100 response - // TODO Consider moving elsewhere; no need to make these checks on every response - if (connp->out_tx->response_line != NULL) { - bstr_free(connp->out_tx->response_line); - } - - if (connp->out_tx->response_protocol != NULL) { - bstr_free(connp->out_tx->response_protocol); - } - - if (connp->out_tx->response_status != NULL) { - bstr_free(connp->out_tx->response_status); - } - - if (connp->out_tx->response_message != NULL) { - bstr_free(connp->out_tx->response_message); - } - - connp->out_tx->response_line = bstr_memdup((char *) connp->out_line, connp->out_line_len); - if (connp->out_tx->response_line == NULL) { - return HTP_ERROR; - } - - // Parse response line - if (connp->cfg->parse_response_line(connp) != HTP_OK) { - // Note: downstream responsible for error logging - return HTP_ERROR; - } - - // Run hook RESPONSE_LINE - int rc = hook_run_all(connp->cfg->hook_response_line, connp); - if (rc != HOOK_OK) { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Response line callback returned error (%d)", rc); - return HTP_ERROR; - } - - // Clean up. - connp->out_line_len = 0; - - // Move on to the next phase. - connp->out_state = htp_connp_RES_HEADERS; - connp->out_tx->progress[1] = TX_PROGRESS_RES_HEADERS; - - return HTP_OK; - } - } - return HTP_ERROR; -} - -size_t htp_connp_res_data_consumed(htp_connp_t *connp) { - return connp->out_current_offset; -} - -/** - * The response idle state will initialize response processing, as well as - * finalize each transactions after we are done with it. - * - * @param connp - * @returns HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed. - */ -int htp_connp_RES_IDLE(htp_connp_t * connp) { - // If we're here and an outgoing transaction object exists that - // means we've just completed parsing a response. We need - // to run the final hook in a transaction and start over. - if (connp->out_tx != NULL) { - // Shut down the decompressor, if we've used one - if (connp->out_decompressor != NULL) { - connp->out_decompressor->destroy(connp->out_decompressor); - connp->out_decompressor = NULL; - } - - connp->out_tx->progress[1] = TX_PROGRESS_DONE; - - // Run hook RESPONSE - int rc = hook_run_all(connp->cfg->hook_response, connp); - if (rc != HTP_OK) { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Response callback returned error (%d)", rc); - return HTP_ERROR; - } - - // Check if the inbound parser is waiting on us. If it is that means that - // there might be request data that the inbound parser hasn't consumed yet. - // If we don't stop parsing we might encounter a response without a - // request. - if ((connp->in_status == STREAM_STATE_DATA_OTHER) && (connp->in_tx == connp->out_tx)) { - connp->out_tx = NULL; - return HTP_DATA_OTHER; - } - - // Start afresh - connp->out_tx = NULL; - } - - // We want to start parsing the next response (and change - // the state from IDLE) only if there's at least one - // byte of data available. Otherwise we could be creating - // new structures even if there's no more data on the - // connection. - OUT_TEST_NEXT_BYTE_OR_RETURN(connp); - - // Parsing a new response - - // Find the next outgoing transaction - connp->out_tx = list_get(connp->conn->transactions, connp->out_next_tx_index); - if (connp->out_tx == NULL) { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Unable to match response to request"); - return HTP_ERROR; - } - - // We've used one transaction - connp->out_next_tx_index++; - - // TODO Detect state mismatch - - connp->out_content_length = -1; - connp->out_body_data_left = -1; - connp->out_header_line_index = -1; - connp->out_header_line_counter = 0; - - // Change state into response line parsing, except if we're following - // a short HTTP/0.9 request, because such requests to not have a - // response line and headers. - if (connp->out_tx->protocol_is_simple) { - connp->out_tx->response_transfer_coding = IDENTITY; - connp->out_state = htp_connp_RES_BODY_IDENTITY; - connp->out_tx->progress[1] = TX_PROGRESS_RES_BODY; - } else { - connp->out_state = htp_connp_RES_LINE; - connp->out_tx->progress[1] = TX_PROGRESS_RES_LINE; - } - - return HTP_OK; -} - -/** - * Process a chunk of outbound (server or response) data. - * - * @param connp - * @param timestamp - * @param data - * @param len - * @return HTP_OK on state change, HTTP_ERROR on error, or HTP_DATA when more data is needed - */ -int htp_connp_res_data(htp_connp_t *connp, htp_time_t timestamp, unsigned char *data, size_t len) { - #ifdef HTP_DEBUG - fprintf(stderr, "htp_connp_res_data(connp->out_status %x)\n", connp->out_status); - fprint_raw_data(stderr, __FUNCTION__, data, len); - #endif - - // Return if the connection has had a fatal error - if (connp->out_status == STREAM_STATE_ERROR) { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Outbound parser is in STREAM_STATE_ERROR"); - - #ifdef HTP_DEBUG - fprintf(stderr, "htp_connp_res_data: returning STREAM_STATE_DATA (previous error)\n"); - #endif - - return STREAM_STATE_ERROR; - } - - // If the length of the supplied data chunk is zero, proceed - // only if the stream has been closed. We do not allow zero-sized - // chunks in the API, but we use it internally to force the parsers - // to finalize parsing. - if ((len == 0) && (connp->out_status != STREAM_STATE_CLOSED)) { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Zero-length data chunks are not allowed"); - - #ifdef HTP_DEBUG - fprintf(stderr, "htp_connp_res_data: returning STREAM_STATE_DATA (zero-length chunk)\n"); - #endif - - return STREAM_STATE_ERROR; - } - - // Store the current chunk information - connp->out_timestamp = timestamp; - connp->out_current_data = data; - connp->out_current_len = len; - connp->out_current_offset = 0; - connp->conn->out_data_counter += len; - connp->conn->out_packet_counter++; - - // Return without processing any data if the stream is in tunneling - // mode (which it would be after an initial CONNECT transaction. - if (connp->out_status == STREAM_STATE_TUNNEL) { - #ifdef HTP_DEBUG - fprintf(stderr, "htp_connp_res_data: returning STREAM_STATE_TUNNEL\n"); - #endif - return STREAM_STATE_TUNNEL; - } - - // Invoke a processor, in a loop, until an error - // occurs or until we run out of data. Many processors - // will process a request, each pointing to the next - // processor that needs to run. - for (;;) { - #ifdef HTP_DEBUG - fprintf(stderr, "htp_connp_res_data: out state=%s, progress=%s\n", - htp_connp_out_state_as_string(connp), - htp_tx_progress_as_string(connp->out_tx, 1)); - #endif - // Return if there's been an error - // or if we've run out of data. We are relying - // on processors to add error messages, so we'll - // keep quiet here. - int rc = connp->out_state(connp); - if (rc == HTP_OK) { - if (connp->out_status == STREAM_STATE_TUNNEL) { - #ifdef HTP_DEBUG - fprintf(stderr, "htp_connp_res_data: returning STREAM_STATE_TUNNEL\n"); - #endif - - return STREAM_STATE_TUNNEL; - } - } else { - // Do we need more data? - if (rc == HTP_DATA) { - return STREAM_STATE_DATA; - } - - // Check for suspended parsing - if (rc == HTP_DATA_OTHER) { - // We might have actually consumed the entire data chunk? - if (connp->out_current_offset >= connp->out_current_len) { - // Do not send STREAM_DATE_DATA_OTHER if we've - // consumed the entire chunk - #ifdef HTP_DEBUG - fprintf(stderr, "htp_connp_res_data: returning STREAM_STATE_DATA (suspended parsing)\n"); - #endif - return STREAM_STATE_DATA; - } else { - // Partial chunk consumption - #ifdef HTP_DEBUG - fprintf(stderr, "htp_connp_req_data: returning STREAM_STATE_DATA_OTHER\n"); - #endif - return STREAM_STATE_DATA_OTHER; - } - } - - // Remember that we've had an error. Errors are - // not possible to recover from. - connp->out_status = STREAM_STATE_ERROR; - - return STREAM_STATE_ERROR; - } - } - return HTP_ERROR; -} - diff --git a/libhtp/htp/htp_response_generic.c b/libhtp/htp/htp_response_generic.c deleted file mode 100644 index 13992956a7..0000000000 --- a/libhtp/htp/htp_response_generic.c +++ /dev/null @@ -1,294 +0,0 @@ -/* - * LibHTP (http://www.libhtp.org) - * Copyright 2009,2010 Ivan Ristic - * - * LibHTP is an open source product, released under terms of the General Public Licence - * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text - * of the license. - * - * In addition, there is a special exception that allows LibHTP to be freely - * used with any OSI-approved open source licence. Please refer to the file - * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. - * - */ - -#include "htp.h" - -/** - * Generic response line parser. - * - * @param connp - * @return HTP status - */ -int htp_parse_response_line_generic(htp_connp_t *connp) { - htp_tx_t *tx = connp->out_tx; - unsigned char *data = (unsigned char *)bstr_ptr(tx->response_line); - size_t len = bstr_len(tx->response_line); - size_t pos = 0; - - // The request method starts at the beginning of the - // line and ends with the first whitespace character. - while ((pos < len) && (!htp_is_space(data[pos]))) { - pos++; - } - - tx->response_protocol = bstr_memdup((char *)data, pos); - if (tx->response_protocol == NULL) { - return HTP_ERROR; - } - tx->response_protocol_number = htp_parse_protocol(tx->response_protocol); - -#ifdef HTP_DEBUG - fprint_raw_data(stderr, __FUNCTION__, (unsigned char *)bstr_ptr(tx->response_protocol), bstr_len(tx->response_protocol)); -#endif - - // Ignore whitespace after response protocol - while ((pos < len) && (isspace(data[pos]))) { - pos++; - } - - size_t start = pos; - - // Find the next whitespace character - while ((pos < len) && (!htp_is_space(data[pos]))) { - pos++; - } - - tx->response_status = bstr_memdup((char *)data + start, pos - start); - if (tx->response_status == NULL) { - return HTP_ERROR; - } - tx->response_status_number = htp_parse_status(tx->response_status); - -#ifdef HTP_DEBUG - fprint_raw_data(stderr, __FUNCTION__, (unsigned char *)bstr_ptr(tx->response_status), bstr_len(tx->response_status)); -#endif - - // Ignore whitespace that follows - while ((pos < len) && (isspace(data[pos]))) { - pos++; - } - - tx->response_message = bstr_memdup((char *)data + pos, len - pos); - if (tx->response_message == NULL) { - return HTP_ERROR; - } - -#ifdef HTP_DEBUG - fprint_raw_data(stderr, __FUNCTION__, (unsigned char *)bstr_ptr(tx->response_message), bstr_len(tx->response_message)); -#endif - - return HTP_OK; -} - -/** - * Generic response header parser. - * - * @param connp - * @param h - * @param data - * @param len - * @return HTP status - */ -int htp_parse_response_header_generic(htp_connp_t *connp, htp_header_t *h, char *data, size_t len) { - size_t name_start, name_end; - size_t value_start, value_end; - - name_start = 0; - - // Look for the colon - size_t colon_pos = 0; - while ((colon_pos < len) && (data[colon_pos] != ':')) colon_pos++; - - if (colon_pos == len) { - // Missing colon - h->flags |= HTP_FIELD_UNPARSEABLE; - - if (!(connp->out_tx->flags & HTP_FIELD_UNPARSEABLE)) { - connp->out_tx->flags |= HTP_FIELD_UNPARSEABLE; - // Only log once per transaction - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Response field invalid: colon missing"); - } - - return HTP_ERROR; - } - - if (colon_pos == 0) { - // Empty header name - h->flags |= HTP_FIELD_INVALID; - - if (!(connp->out_tx->flags & HTP_FIELD_INVALID)) { - connp->out_tx->flags |= HTP_FIELD_INVALID; - // Only log once per transaction - htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Response field invalid: empty name"); - } - } - - name_end = colon_pos; - - // Ignore LWS after field-name - size_t prev = name_end - 1; - while ((prev > name_start) && (htp_is_lws(data[prev]))) { - prev--; - name_end--; - - h->flags |= HTP_FIELD_INVALID; - - if (!(connp->out_tx->flags & HTP_FIELD_INVALID)) { - connp->out_tx->flags |= HTP_FIELD_INVALID; - htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Response field invalid: LWS after name"); - } - } - - // Value - - value_start = colon_pos; - - // Go over the colon - if (value_start < len) { - value_start++; - } - - // Ignore LWS before field-content - while ((value_start < len) && (htp_is_lws(data[value_start]))) { - value_start++; - } - - // Look for the end of field-content - value_end = value_start; - while (value_end < len) value_end++; - - // Ignore LWS after field-content - prev = value_end - 1; - while ((prev > value_start) && (htp_is_lws(data[prev]))) { - prev--; - value_end--; - } - - // Check that the header name is a token - size_t i = name_start; - while (i < name_end) { - if (!htp_is_token(data[i])) { - h->flags |= HTP_FIELD_INVALID; - - if (!(connp->out_tx->flags & HTP_FIELD_INVALID)) { - connp->out_tx->flags |= HTP_FIELD_INVALID; - htp_log(connp, HTP_LOG_MARK, HTP_LOG_WARNING, 0, "Response header name is not a token"); - } - - break; - } - - i++; - } - - // Now extract the name and the value - h->name = bstr_memdup(data + name_start, name_end - name_start); - if (h->name == NULL) { - return HTP_ERROR; - } - h->value = bstr_memdup(data + value_start, value_end - value_start); - if (h->value == NULL) { - return HTP_ERROR; - } - - return HTP_OK; -} - -/** - * Generic response header line(s) processor, which assembles folded lines - * into a single buffer before invoking the parsing function. - * - * @param connp - * @return HTP status - */ -int htp_process_response_header_generic(htp_connp_t *connp) { - bstr *tempstr = NULL; - char *data = NULL; - size_t len = 0; - - // Parse header - htp_header_t *h = calloc(1, sizeof (htp_header_t)); - if (h == NULL) return HTP_ERROR; - - // Ensure we have the necessary header data in a single buffer - if (connp->out_header_line_index + 1 == connp->out_header_line_counter) { - // Single line - htp_header_line_t *hl = list_get(connp->out_tx->response_header_lines, - connp->out_header_line_index); - if (hl == NULL) { - // Internal error - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Process response header (generic): Internal error"); - free(h); - return HTP_ERROR; - } - - data = bstr_ptr(hl->line); - len = bstr_len(hl->line); - hl->header = h; - } else { - // Multiple lines (folded) - int i = 0; - - for (i = connp->out_header_line_index; i < connp->out_header_line_counter; i++) { - htp_header_line_t *hl = list_get(connp->out_tx->response_header_lines, i); - len += bstr_len(hl->line); - } - - tempstr = bstr_alloc(len); - if (tempstr == NULL) { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, - "Process reqsponse header (generic): Failed to allocate bstring of %d bytes", len); - free(h); - return HTP_ERROR; - } - - for (i = connp->out_header_line_index; i < connp->out_header_line_counter; i++) { - htp_header_line_t *hl = list_get(connp->out_tx->response_header_lines, i); - bstr_add_str_noex(tempstr, hl->line); - hl->header = h; - } - - data = bstr_ptr(tempstr); - } - - if (htp_parse_response_header_generic(connp, h, data, len) != HTP_OK) { - // Note: downstream responsible for error logging - if (tempstr != NULL) { - free(tempstr); - } - free(h); - return HTP_ERROR; - } - - // Do we already have a header with the same name? - htp_header_t *h_existing = table_get(connp->out_tx->response_headers, h->name); - if (h_existing != NULL) { - // TODO Do we want to keep a list of the headers that are - // allowed to be combined in this way? - - // Add to existing header - h_existing->value = bstr_expand(h_existing->value, bstr_len(h_existing->value) - + 2 + bstr_len(h->value)); - bstr_add_mem_noex(h_existing->value, ", ", 2); - bstr_add_str_noex(h_existing->value, h->value); - - // The header is no longer needed - free(h->name); - free(h->value); - free(h); - - // Keep track of same-name headers - h_existing->flags |= HTP_FIELD_REPEATED; - } else { - // Add as a new header - table_add(connp->out_tx->response_headers, h->name, h); - } - - if (tempstr != NULL) { - free(tempstr); - } - - return HTP_OK; -} diff --git a/libhtp/htp/htp_transaction.c b/libhtp/htp/htp_transaction.c deleted file mode 100644 index 3b33891cfb..0000000000 --- a/libhtp/htp/htp_transaction.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * LibHTP (http://www.libhtp.org) - * Copyright 2009,2010 Ivan Ristic - * - * LibHTP is an open source product, released under terms of the General Public Licence - * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text - * of the license. - * - * In addition, there is a special exception that allows LibHTP to be freely - * used with any OSI-approved open source licence. Please refer to the file - * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. - * - */ - -#include "htp.h" - -/** - * Creates a new transaction structure. - * - * @param cfg - * @param is_cfg_shared - * @param conn - * @return The newly created transaction, or NULL on memory allocation failure. - */ -htp_tx_t *htp_tx_create(htp_cfg_t *cfg, int is_cfg_shared, htp_conn_t *conn) { - htp_tx_t *tx = calloc(1, sizeof (htp_tx_t)); - if (tx == NULL) return NULL; - - tx->conn = conn; - tx->cfg = cfg; - tx->is_cfg_shared = is_cfg_shared; - - tx->conn = conn; - - tx->request_header_lines = list_array_create(32); - tx->request_headers = table_create(32); - tx->request_line_nul_offset = -1; - tx->parsed_uri = calloc(1, sizeof (htp_uri_t)); - tx->parsed_uri_incomplete = calloc(1, sizeof (htp_uri_t)); - - tx->response_header_lines = list_array_create(32); - tx->response_headers = table_create(32); - - tx->request_protocol_number = -1; - - return tx; -} - -/** - * Destroys the supplied transaction. - * - * @param tx - */ -void htp_tx_destroy(htp_tx_t *tx) { - bstr_free(tx->request_line); - bstr_free(tx->request_method); - bstr_free(tx->request_uri); - bstr_free(tx->request_uri_normalized); - bstr_free(tx->request_protocol); - - if (tx->parsed_uri != NULL) { - bstr_free(tx->parsed_uri->scheme); - bstr_free(tx->parsed_uri->username); - bstr_free(tx->parsed_uri->password); - bstr_free(tx->parsed_uri->hostname); - bstr_free(tx->parsed_uri->port); - bstr_free(tx->parsed_uri->path); - bstr_free(tx->parsed_uri->query); - bstr_free(tx->parsed_uri->fragment); - - free(tx->parsed_uri); - } - - if (tx->parsed_uri_incomplete != NULL) { - bstr_free(tx->parsed_uri_incomplete->scheme); - bstr_free(tx->parsed_uri_incomplete->username); - bstr_free(tx->parsed_uri_incomplete->password); - bstr_free(tx->parsed_uri_incomplete->hostname); - bstr_free(tx->parsed_uri_incomplete->port); - bstr_free(tx->parsed_uri_incomplete->path); - bstr_free(tx->parsed_uri_incomplete->query); - bstr_free(tx->parsed_uri_incomplete->fragment); - - free(tx->parsed_uri_incomplete); - } - - // Destroy request_header_lines - htp_header_line_t *hl = NULL; - if (tx->request_header_lines != NULL) { - list_iterator_reset(tx->request_header_lines); - while ((hl = list_iterator_next(tx->request_header_lines)) != NULL) { - bstr_free(hl->line); - bstr_free(hl->terminators); - // No need to destroy hl->header because - // htp_header_line_t does not own it. - free(hl); - } - - list_destroy(tx->request_header_lines); - } - - // Destroy request_headers - htp_header_t *h = NULL; - if (tx->request_headers != NULL) { - table_iterator_reset(tx->request_headers); - while (table_iterator_next(tx->request_headers, (void **) & h) != NULL) { - bstr_free(h->name); - bstr_free(h->value); - free(h); - } - - table_destroy(tx->request_headers); - } - - if (tx->request_headers_raw != NULL) { - bstr_free(tx->request_headers_raw); - } - - bstr_free(tx->response_line); - bstr_free(tx->response_protocol); - bstr_free(tx->response_status); - bstr_free(tx->response_message); - - // Destroy response_header_lines - hl = NULL; - if (tx->response_header_lines != NULL) { - list_iterator_reset(tx->response_header_lines); - while ((hl = list_iterator_next(tx->response_header_lines)) != NULL) { - bstr_free(hl->line); - bstr_free(hl->terminators); - // No need to destroy hl->header because - // htp_header_line_t does not own it. - free(hl); - } - list_destroy(tx->response_header_lines); - } - - // Destroy response headers - h = NULL; - if (tx->response_headers) { - table_iterator_reset(tx->response_headers); - while (table_iterator_next(tx->response_headers, (void **) & h) != NULL) { - bstr_free(h->name); - bstr_free(h->value); - free(h); - } - table_destroy(tx->response_headers); - } - - // Tell the connection to remove this transaction - // from the list - htp_conn_remove_tx(tx->conn, tx); - - // Invalidate the pointer to this transactions held - // by the connection parser. This is to allow a transaction - // to be destroyed from within the final response callback. - if (tx->connp != NULL) { - if (tx->connp->out_tx == tx) { - tx->connp->out_tx = NULL; - } - } - - free(tx); -} - -/** - * Returns the user data associated with this transaction. - * - * @param tx - * @return A pointer to user data or NULL - */ -void *htp_tx_get_user_data(htp_tx_t *tx) { - return tx->user_data; -} - -/** - * Sets the configuration that is to be used for this transaction. - * - * @param tx - * @param cfg - * @param is_cfg_shared - */ -void htp_tx_set_config(htp_tx_t *tx, htp_cfg_t *cfg, int is_cfg_shared) { - tx->cfg = cfg; - tx->is_cfg_shared = is_cfg_shared; -} - -/** - * Associates user data with this transaction. - * - * @param tx - * @param user_data - */ -void htp_tx_set_user_data(htp_tx_t *tx, void *user_data) { - tx->user_data = user_data; -} diff --git a/libhtp/htp/htp_util.c b/libhtp/htp/htp_util.c deleted file mode 100644 index 6c6acd479e..0000000000 --- a/libhtp/htp/htp_util.c +++ /dev/null @@ -1,2260 +0,0 @@ -/* - * LibHTP (http://www.libhtp.org) - * Copyright 2009,2010 Ivan Ristic - * - * LibHTP is an open source product, released under terms of the General Public Licence - * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text - * of the license. - * - * In addition, there is a special exception that allows LibHTP to be freely - * used with any OSI-approved open source licence. Please refer to the file - * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. - * - */ - -#include "htp.h" -#include "utf8_decoder.h" - -/** - * Is character a linear white space character? - * - * @param c - * @return 0 or 1 - */ -int htp_is_lws(int c) { - if ((c == ' ') || (c == '\t')) return 1; - else return 0; -} - -/** - * Is character a separator character? - * - * @param c - * @return 0 or 1 - */ -int htp_is_separator(int c) { - /* separators = "(" | ")" | "<" | ">" | "@" - | "," | ";" | ":" | "\" | <"> - | "/" | "[" | "]" | "?" | "=" - | "{" | "}" | SP | HT */ - switch (c) { - case '(': - case ')': - case '<': - case '>': - case '@': - case ',': - case ';': - case ':': - case '\\': - case '"': - case '/': - case '[': - case ']': - case '?': - case '=': - case '{': - case '}': - case ' ': - case '\t': - return 1; - break; - default: - return 0; - } -} - -/** - * Is character a text character? - * - * @param c - * @return 0 or 1 - */ -int htp_is_text(int c) { - if (c == '\t') return 1; - if (c < 32) return 0; - return 1; -} - -/** - * Is character a token character? - * - * @param c - * @return 0 or 1 - */ -int htp_is_token(int c) { - /* token = 1* */ - /* CHAR = */ - if ((c < 32) || (c > 126)) return 0; - if (htp_is_separator(c)) return 0; - return 1; -} - -/** - * Remove one or more line terminators (LF or CRLF) from - * the end of the line provided as input. - * - * @return 0 if nothing was removed, 1 if one or more LF characters were removed, or - * 2 if one or more CR and/or LF characters were removed. - */ -int htp_chomp(unsigned char *data, size_t *len) { - int r = 0; - - // Loop until there's no more stuff in the buffer - while (*len > 0) { - // Try one LF first - if (data[*len - 1] == LF) { - (*len)--; - r = 1; - - if (*len == 0) return r; - - // A CR is allowed before LF - if (data[*len - 1] == CR) { - (*len)--; - r = 2; - } - } else return r; - } - - return r; -} - -/** - * Is character a white space character? - * - * @param c - * @return 0 or 1 - */ -int htp_is_space(int c) { - switch (c) { - case ' ': - case '\f': - case '\v': - case '\t': - case '\r': - case '\n': - return 1; - default: - return 0; - } -} - -/** - * Converts request method, given as a string, into a number. - * - * @param method - * @return Method number of M_UNKNOWN - */ -int htp_convert_method_to_number(bstr *method) { - if (method == NULL) return M_UNKNOWN; - // TODO Optimize using parallel matching, or something - if (bstr_cmpc(method, "GET") == 0) return M_GET; - if (bstr_cmpc(method, "PUT") == 0) return M_PUT; - if (bstr_cmpc(method, "POST") == 0) return M_POST; - if (bstr_cmpc(method, "DELETE") == 0) return M_DELETE; - if (bstr_cmpc(method, "CONNECT") == 0) return M_CONNECT; - if (bstr_cmpc(method, "OPTIONS") == 0) return M_OPTIONS; - if (bstr_cmpc(method, "TRACE") == 0) return M_TRACE; - if (bstr_cmpc(method, "PATCH") == 0) return M_PATCH; - if (bstr_cmpc(method, "PROPFIND") == 0) return M_PROPFIND; - if (bstr_cmpc(method, "PROPPATCH") == 0) return M_PROPPATCH; - if (bstr_cmpc(method, "MKCOL") == 0) return M_MKCOL; - if (bstr_cmpc(method, "COPY") == 0) return M_COPY; - if (bstr_cmpc(method, "MOVE") == 0) return M_MOVE; - if (bstr_cmpc(method, "LOCK") == 0) return M_LOCK; - if (bstr_cmpc(method, "UNLOCK") == 0) return M_UNLOCK; - if (bstr_cmpc(method, "VERSION_CONTROL") == 0) return M_VERSION_CONTROL; - if (bstr_cmpc(method, "CHECKOUT") == 0) return M_CHECKOUT; - if (bstr_cmpc(method, "UNCHECKOUT") == 0) return M_UNCHECKOUT; - if (bstr_cmpc(method, "CHECKIN") == 0) return M_CHECKIN; - if (bstr_cmpc(method, "UPDATE") == 0) return M_UPDATE; - if (bstr_cmpc(method, "LABEL") == 0) return M_LABEL; - if (bstr_cmpc(method, "REPORT") == 0) return M_REPORT; - if (bstr_cmpc(method, "MKWORKSPACE") == 0) return M_MKWORKSPACE; - if (bstr_cmpc(method, "MKACTIVITY") == 0) return M_MKACTIVITY; - if (bstr_cmpc(method, "BASELINE_CONTROL") == 0) return M_BASELINE_CONTROL; - if (bstr_cmpc(method, "MERGE") == 0) return M_MERGE; - if (bstr_cmpc(method, "INVALID") == 0) return M_INVALID; - if (bstr_cmpc(method, "HEAD") == 0) return M_HEAD; - - return M_UNKNOWN; -} - -/** - * Is the given line empty? This function expects the line to have - * a terminating LF. - * - * @param data - * @param len - * @return 0 or 1 - */ -int htp_is_line_empty(unsigned char *data, size_t len) { - if ((len == 1) || ((len == 2) && (data[0] == CR))) { - return 1; - } - - return 0; -} - -/** - * Does line consist entirely of whitespace characters? - * - * @param data - * @param len - * @return 0 or 1 - */ -int htp_is_line_whitespace(unsigned char *data, size_t len) { - size_t i; - - for (i = 0; i < len; i++) { - if (!isspace(data[i])) { - return 0; - } - } - - return 1; -} - -/** - * Parses Content-Length string (positive decimal number). - * White space is allowed before and after the number. - * - * @param b - * @return Content-Length as a number, or -1 on error. - */ -int htp_parse_content_length(bstr *b) { - return htp_parse_positive_integer_whitespace((unsigned char *) bstr_ptr(b), bstr_len(b), 10); -} - -/** - * Parses chunk length (positive hexadecimal number). - * White space is allowed before and after the number. - * - * @param data - * @param len - * @return Chunk length, or -1 on error. - */ -int htp_parse_chunked_length(unsigned char *data, size_t len) { - return htp_parse_positive_integer_whitespace(data, len, 16); -} - -/** - * A forgiving parser for a positive integer in a given base. - * White space is allowed before and after the number. - * - * @param data - * @param len - * @param base - * @return The parsed number, or -1 on error. - */ -int htp_parse_positive_integer_whitespace(unsigned char *data, size_t len, int base) { - size_t pos = 0; - - // Ignore LWS before - while ((pos < len) && (htp_is_lws(data[pos]))) pos++; - if (pos == len) return -1001; - - int r = bstr_util_memtoip((char *) data + pos, len - pos, base, &pos); - if (r < 0) return r; - - // Ignore LWS after - while (pos < len) { - if (!htp_is_lws(data[pos])) { - return -1002; - } - - pos++; - } - - return r; -} - -/** - * Prints one log message to stderr. - * - * @param log - */ -void htp_print_log(FILE *stream, htp_log_t *log) { - if (log->code != 0) { - fprintf(stream, "[%d][code %d][file %s][line %d] %s\n", log->level, - log->code, log->file, log->line, log->msg); - } else { - fprintf(stream, "[%d][file %s][line %d] %s\n", log->level, - log->file, log->line, log->msg); - } -} - -/** - * Records one log message. - * - * @param connp - * @param file - * @param line - * @param level - * @param code - * @param fmt - */ -void htp_log(htp_connp_t *connp, const char *file, int line, int level, int code, const char *fmt, ...) { - char buf[1024]; - va_list args; - - // Ignore messages below our log level - if (connp->cfg->log_level < level) { - return; - } - - va_start(args, fmt); - - int r = vsnprintf(buf, 1023, fmt, args); - - va_end(args); - - if (r < 0) { - // TODO Will vsnprintf ever return an error? - snprintf(buf, 1024, "[vnsprintf returned error %d]", r); - } - - // Indicate overflow with a '+' at the end - if (r > 1023) { - buf[1022] = '+'; - buf[1023] = '\0'; - } - - // Create a new log entry... - htp_log_t *log = calloc(1, sizeof (htp_log_t)); - if (log == NULL) return; - - log->connp = connp; - log->file = file; - log->line = line; - log->level = level; - log->code = code; - log->msg = strdup(buf); - - list_add(connp->conn->messages, log); - - if (level == HTP_LOG_ERROR) { - connp->last_error = log; - } - - hook_run_all(connp->cfg->hook_log, log); -} - -/** - * Determines if the given line is a continuation (of some previous line). - * - * @param connp - * @param data - * @param len - * @return 0 or 1 - */ -int htp_connp_is_line_folded(unsigned char *data, size_t len) { - // Is there a line? - if (len == 0) { - return -1; - } - - if (htp_is_lws(data[0])) return 1; - else return 0; -} - -/** - * Determines if the given line is a request terminator. - * - * @param connp - * @param data - * @param len - * @return 0 or 1 - */ -int htp_connp_is_line_terminator(htp_connp_t *connp, unsigned char *data, size_t len) { - // Is this the end of request headers? - switch (connp->cfg->spersonality) { - case HTP_SERVER_IIS_5_1: - // IIS 5 will accept a whitespace line as a terminator - if (htp_is_line_whitespace(data, len)) { - return 1; - } - - // Fall through - default: - // Treat an empty line as terminator - if (htp_is_line_empty(data, len)) { - return 1; - } - break; - } - - return 0; -} - -/** - * Determines if the given line can be ignored when it appears before a request. - * - * @param connp - * @param data - * @param len - * @return 0 or 1 - */ -int htp_connp_is_line_ignorable(htp_connp_t *connp, unsigned char *data, size_t len) { - return htp_connp_is_line_terminator(connp, data, len); -} - -/** - * Parses request URI, making no attempt to validate the contents. - * - * @param connp - * @param authority - * @param uri - * @return HTP_ERROR on memory allocation failure, HTP_OK otherwise - */ -int htp_parse_authority(htp_connp_t *connp, bstr *authority, htp_uri_t **uri) { - int colon = bstr_chr(authority, ':'); - if (colon == -1) { - // Hostname alone - (*uri)->hostname = bstr_strdup(authority); - htp_normalize_hostname_inplace((*uri)->hostname); - } else { - // Hostname and port - - // Hostname - (*uri)->hostname = bstr_strdup_ex(authority, 0, colon); - // TODO Handle whitespace around hostname - htp_normalize_hostname_inplace((*uri)->hostname); - - // Port - int port = htp_parse_positive_integer_whitespace((unsigned char *) bstr_ptr(authority) - + colon + 1, bstr_len(authority) - colon - 1, 10); - if (port < 0) { - // Failed to parse port - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Invalid server port information in request"); - } else if ((port > 0) && (port < 65536)) { - // Valid port - (*uri)->port_number = port; - } else { - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Invalid authority port"); - } - } - - return HTP_OK; -} - -/** - * Parses request URI, making no attempt to validate the contents. - * - * @param input - * @param uri - * @return HTP_ERROR on memory allocation failure, HTP_OK otherwise - */ -int htp_parse_uri(bstr *input, htp_uri_t **uri) { - if (input == NULL) - return HTP_ERROR; - char *data = bstr_ptr(input); - size_t len = bstr_len(input); - size_t start, pos; - - // Allow a htp_uri_t structure to be provided on input, - // but allocate a new one if there isn't one - if (*uri == NULL) { - *uri = calloc(1, sizeof (htp_uri_t)); - if (*uri == NULL) return HTP_ERROR; - } - - if (len == 0) { - // Empty string - return HTP_OK; - } - - pos = 0; - - // Scheme test: if it doesn't start with a forward slash character (which it must - // for the contents to be a path or an authority, then it must be the scheme part - if (data[0] != '/') { - // Parse scheme - - // Find the colon, which marks the end of the scheme part - start = pos; - while ((pos < len) && (data[pos] != ':')) pos++; - - if (pos >= len) { - // We haven't found a colon, which means that the URI - // is invalid. Apache will ignore this problem and assume - // the URI contains an invalid path so, for the time being, - // we are going to do the same. - pos = 0; - } else { - // Make a copy of the scheme - (*uri)->scheme = bstr_memdup(data + start, pos - start); - - // Go over the colon - pos++; - } - } - - // Authority test: two forward slash characters and it's an authority. - // One, three or more slash characters, and it's a path. We, however, - // only attempt to parse authority if we've seen a scheme. - if ((*uri)->scheme != NULL) - if ((pos + 2 < len) && (data[pos] == '/') && (data[pos + 1] == '/') && (data[pos + 2] != '/')) { - // Parse authority - - // Go over the two slash characters - start = pos = pos + 2; - - // Authority ends with a question mark, forward slash or hash - while ((pos < len) && (data[pos] != '?') && (data[pos] != '/') && (data[pos] != '#')) pos++; - - char *hostname_start; - size_t hostname_len; - - // Are the credentials included in the authority? - char *m = memchr(data + start, '@', pos - start); - if (m != NULL) { - // Credentials present - char *credentials_start = data + start; - size_t credentials_len = m - data - start; - - // Figure out just the hostname part - hostname_start = data + start + credentials_len + 1; - hostname_len = pos - start - credentials_len - 1; - - // Extract the username and the password - m = memchr(credentials_start, ':', credentials_len); - if (m != NULL) { - // Username and password - (*uri)->username = bstr_memdup(credentials_start, m - credentials_start); - (*uri)->password = bstr_memdup(m + 1, credentials_len - (m - credentials_start) - 1); - } else { - // Username alone - (*uri)->username = bstr_memdup(credentials_start, credentials_len); - } - } else { - // No credentials - hostname_start = data + start; - hostname_len = pos - start; - } - - // Still parsing authority; is there a port provided? - m = memchr(hostname_start, ':', hostname_len); - if (m != NULL) { - size_t port_len = hostname_len - (m - hostname_start) - 1; - hostname_len = hostname_len - port_len - 1; - - // Port string - (*uri)->port = bstr_memdup(m + 1, port_len); - - // We deliberately don't want to try to convert the port - // string as a number. That will be done later, during - // the normalization and validation process. - } - - // Hostname - (*uri)->hostname = bstr_memdup(hostname_start, hostname_len); - } - - // Path - start = pos; - - // The path part will end with a question mark or a hash character, which - // mark the beginning of the query part or the fragment part, respectively. - while ((pos < len) && (data[pos] != '?') && (data[pos] != '#')) pos++; - - // Path - (*uri)->path = bstr_memdup(data + start, pos - start); - - if (pos == len) return HTP_OK; - - // Query - if (data[pos] == '?') { - // Step over the question mark - start = pos + 1; - - // The query part will end with the end of the input - // or the beginning of the fragment part - while ((pos < len) && (data[pos] != '#')) pos++; - - // Query string - (*uri)->query = bstr_memdup(data + start, pos - start); - - if (pos == len) return HTP_OK; - } - - // Fragment - if (data[pos] == '#') { - // Step over the hash character - start = pos + 1; - - // Fragment; ends with the end of the input - (*uri)->fragment = bstr_memdup(data + start, len - start); - } - - return HTP_OK; -} - -/** - * Convert two input bytes, pointed to by the pointer parameter, - * into a single byte by assuming the input consists of hexadecimal - * characters. This function will happily convert invalid input. - * - * @param what - * @return hex-decoded byte - */ -unsigned char x2c(unsigned char *what) { - register unsigned char digit; - - digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0')); - digit *= 16; - digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0')); - - return digit; -} - -/** - * Convert a Unicode codepoint into a single-byte, using best-fit - * mapping (as specified in the provided configuration structure). - * - * @param cfg - * @param codepoint - * @return converted single byte - */ -uint8_t bestfit_codepoint(htp_cfg_t *cfg, uint32_t codepoint) { - // Is it a single-byte codepoint? - if (codepoint < 0x100) { - return (uint8_t) codepoint; - } - - // Our current implementation only converts the 2-byte codepoints - if (codepoint > 0xffff) { - return cfg->path_replacement_char; - } - - uint8_t *p = cfg->path_u_bestfit_map; - - // TODO Optimize lookup - - for (;;) { - uint32_t x = (p[0] << 8) + p[1]; - - if (x == 0) { - return cfg->path_replacement_char; - } - - if (x == codepoint) { - return p[2]; - break; - } - - // Move to the next triplet - p += 3; - } - return cfg->path_replacement_char; -} - -/** - * Decode a UTF-8 encoded path. Overlong characters will be decoded, invalid - * chararacters will be left as-is. Best-fit mapping will be used to convert - * UTF-8 into a single-byte stream. - * - * @param cfg - * @param tx - * @param path - */ -void htp_utf8_decode_path_inplace(htp_cfg_t *cfg, htp_tx_t *tx, bstr *path) { - if (path == NULL) - return; - - uint8_t *data = (unsigned char *) bstr_ptr(path); - size_t len = bstr_len(path); - size_t rpos = 0; - size_t wpos = 0; - size_t charpos = 0; - uint32_t codepoint = 0; - uint32_t state = UTF8_ACCEPT; - uint32_t counter = 0; - uint8_t seen_valid = 0; - - while (rpos < len) { - counter++; - - switch (utf8_decode_allow_overlong(&state, &codepoint, data[rpos])) { - case UTF8_ACCEPT: - if (counter == 1) { - // ASCII character - data[wpos++] = (uint8_t) codepoint; - } else { - // A valid UTF-8 character - seen_valid = 1; - - // Check for overlong characters and set the - // flag accordingly - switch (counter) { - case 2: - if (codepoint < 0x80) { - tx->flags |= HTP_PATH_UTF8_OVERLONG; - } - break; - case 3: - if (codepoint < 0x800) { - tx->flags |= HTP_PATH_UTF8_OVERLONG; - } - break; - case 4: - if (codepoint < 0x10000) { - tx->flags |= HTP_PATH_UTF8_OVERLONG; - } - break; - } - - // Special flag for fullwidth form evasion - if ((codepoint > 0xfeff) && (codepoint < 0x010000)) { - tx->flags |= HTP_PATH_FULLWIDTH_EVASION; - } - - // Use best-fit mapping to convert to a single byte - data[wpos++] = bestfit_codepoint(cfg, codepoint); - } - - // Advance over the consumed byte - rpos++; - - // Prepare for the next character - counter = 0; - charpos = rpos; - - break; - - case UTF8_REJECT: - // Invalid UTF-8 character - tx->flags |= HTP_PATH_UTF8_INVALID; - - // Is the server expected to respond with 400? - if (cfg->path_invalid_utf8_handling == STATUS_400) { - tx->response_status_expected_number = 400; - } - - // Override the state in the UTF-8 decoder because - // we want to ignore invalid characters - state = UTF8_ACCEPT; - - // Copy the invalid bytes into the output stream - while (charpos <= rpos) { - data[wpos++] = data[charpos++]; - } - - // Advance over the consumed byte - rpos++; - - // Prepare for the next character - counter = 0; - charpos = rpos; - - break; - - default: - // Keep going; the character is not yet formed - rpos++; - break; - } - } - - // Did the input stream seem like a valid UTF-8 string? - if ((seen_valid) && (!(tx->flags & HTP_PATH_UTF8_INVALID))) { - tx->flags |= HTP_PATH_UTF8_VALID; - } - - // Adjust the length of the string, because - // we're doing in-place decoding. - bstr_len_adjust(path, wpos); -} - -/** - * Validate a path that is quite possibly UTF-8 encoded. - * - * @param cfg - * @param tx - * @param path - */ -void htp_utf8_validate_path(htp_tx_t *tx, bstr *path) { - unsigned char *data = (unsigned char *) bstr_ptr(path); - size_t len = bstr_len(path); - size_t rpos = 0; - uint32_t codepoint = 0; - uint32_t state = UTF8_ACCEPT; - uint32_t counter = 0; - uint8_t seen_valid = 0; - - while (rpos < len) { - counter++; - - switch (utf8_decode_allow_overlong(&state, &codepoint, data[rpos])) { - case UTF8_ACCEPT: - // ASCII character - - if (counter > 1) { - // A valid UTF-8 character - seen_valid = 1; - - // Check for overlong characters and set the - // flag accordingly - switch (counter) { - case 2: - if (codepoint < 0x80) { - tx->flags |= HTP_PATH_UTF8_OVERLONG; - } - break; - case 3: - if (codepoint < 0x800) { - tx->flags |= HTP_PATH_UTF8_OVERLONG; - } - break; - case 4: - if (codepoint < 0x10000) { - tx->flags |= HTP_PATH_UTF8_OVERLONG; - } - break; - } - } - - // Special flag for fullwidth form evasion - if ((codepoint > 0xfeff) && (codepoint < 0x010000)) { - tx->flags |= HTP_PATH_FULLWIDTH_EVASION; - } - - // Advance over the consumed byte - rpos++; - - // Prepare for the next character - counter = 0; - - break; - - case UTF8_REJECT: - // Invalid UTF-8 character - tx->flags |= HTP_PATH_UTF8_INVALID; - - // Override the state in the UTF-8 decoder because - // we want to ignore invalid characters - state = UTF8_ACCEPT; - - // Advance over the consumed byte - rpos++; - - // Prepare for the next character - counter = 0; - - break; - - default: - // Keep going; the character is not yet formed - rpos++; - break; - } - } - - // Did the input stream seem like a valid UTF-8 string? - if ((seen_valid) && (!(tx->flags & HTP_PATH_UTF8_INVALID))) { - tx->flags |= HTP_PATH_UTF8_VALID; - } -} - -/** - * Decode a %u-encoded character, using best-fit mapping as necessary. - * - * @param cfg - * @param tx - * @param data - * @return decoded byte - */ -int decode_u_encoding(htp_cfg_t *cfg, htp_tx_t *tx, unsigned char *data) { - unsigned int c1 = x2c(data); - unsigned int c2 = x2c(data + 2); - int r = cfg->path_replacement_char; - - if (c1 == 0x00) { - r = c2; - tx->flags |= HTP_PATH_OVERLONG_U; - } else { - // Check for fullwidth form evasion - if (c1 == 0xff) { - tx->flags |= HTP_PATH_FULLWIDTH_EVASION; - } - - switch (cfg->path_unicode_mapping) { - case STATUS_400: - tx->response_status_expected_number = 400; - break; - case STATUS_404: - tx->response_status_expected_number = 404; - break; - } - - // Use best-fit mapping - unsigned char *p = cfg->path_u_bestfit_map; - - // TODO Optimize lookup - - for (;;) { - // Have we reached the end of the map? - if ((p[0] == 0) && (p[1] == 0)) { - break; - } - - // Have we found the mapping we're looking for? - if ((p[0] == c1) && (p[1] == c2)) { - r = p[2]; - break; - } - - // Move to the next triplet - p += 3; - } - } - - // Check for encoded path separators - if ((r == '/') || ((cfg->path_backslash_separators) && (r == '\\'))) { - tx->flags |= HTP_PATH_ENCODED_SEPARATOR; - } - - return r; -} - -/** - * Decode a request query according to the settings in the - * provided configuration structure. - * - * @param cfg - * @param tx - * @param query - */ -int htp_decode_query_inplace(htp_cfg_t *cfg, htp_tx_t *tx, bstr *query) { - if (query == NULL) - return -1; - - unsigned char *data = (unsigned char *) bstr_ptr(query); - if (data == NULL) { - return -1; - } - size_t len = bstr_len(query); - - // TODO I don't like this function. It's too complex. - - size_t rpos = 0; - size_t wpos = 0; - int previous_was_separator = 0; - - while (rpos < len) { - int c = data[rpos]; - - // Decode encoded characters - if (c == '%') { - if (rpos + 2 < len) { - int handled = 0; - - if (cfg->query_decode_u_encoding) { - // Check for the %u encoding - if ((data[rpos + 1] == 'u') || (data[rpos + 1] == 'U')) { - handled = 1; - - if (cfg->query_decode_u_encoding == STATUS_400) { - tx->response_status_expected_number = 400; - } - - if (rpos + 5 < len) { - if (isxdigit(data[rpos + 2]) && (isxdigit(data[rpos + 3])) - && isxdigit(data[rpos + 4]) && (isxdigit(data[rpos + 5]))) { - // Decode a valid %u encoding - c = decode_u_encoding(cfg, tx, &data[rpos + 2]); - rpos += 6; - - if (c == 0) { - tx->flags |= HTP_PATH_ENCODED_NUL; - - if (cfg->query_nul_encoded_handling == STATUS_400) { - tx->response_status_expected_number = 400; - } else if (cfg->query_nul_encoded_handling == STATUS_404) { - tx->response_status_expected_number = 404; - } - } - } else { - // Invalid %u encoding - tx->flags |= HTP_PATH_INVALID_ENCODING; - - switch (cfg->query_invalid_encoding_handling) { - case URL_DECODER_REMOVE_PERCENT: - // Do not place anything in output; eat - // the percent character - rpos++; - continue; - break; - case URL_DECODER_PRESERVE_PERCENT: - // Leave the percent character in output - rpos++; - break; - case URL_DECODER_DECODE_INVALID: - // Decode invalid %u encoding - c = decode_u_encoding(cfg, tx, &data[rpos + 2]); - rpos += 6; - break; - case URL_DECODER_STATUS_400: - // Set expected status to 400 - tx->response_status_expected_number = 400; - - // Decode invalid %u encoding - c = decode_u_encoding(cfg, tx, &data[rpos + 2]); - rpos += 6; - break; - break; - default: - // Unknown setting - return -1; - break; - } - } - } else { - // Invalid %u encoding (not enough data) - tx->flags |= HTP_PATH_INVALID_ENCODING; - - if (cfg->query_invalid_encoding_handling == URL_DECODER_REMOVE_PERCENT) { - // Remove the percent character from output - rpos++; - continue; - } else { - rpos++; - } - } - } - } - - // Handle standard URL encoding - if (!handled) { - if ((isxdigit(data[rpos + 1])) && (isxdigit(data[rpos + 2]))) { - c = x2c(&data[rpos + 1]); - - if (c == 0) { - tx->flags |= HTP_PATH_ENCODED_NUL; - - switch (cfg->query_nul_encoded_handling) { - case TERMINATE: - bstr_len_adjust(query, wpos); - return 1; - break; - case STATUS_400: - tx->response_status_expected_number = 400; - break; - case STATUS_404: - tx->response_status_expected_number = 404; - break; - } - } - - if ((c == '/') || ((cfg->query_backslash_separators) && (c == '\\'))) { - tx->flags |= HTP_PATH_ENCODED_SEPARATOR; - - switch (cfg->query_decode_separators) { - case STATUS_404: - tx->response_status_expected_number = 404; - // Fall-through - case NO: - // Leave encoded - c = '%'; - rpos++; - break; - case YES: - // Decode - rpos += 3; - break; - } - } else { - // Decode - rpos += 3; - } - } else { - // Invalid encoding - tx->flags |= HTP_PATH_INVALID_ENCODING; - - switch (cfg->query_invalid_encoding_handling) { - case URL_DECODER_REMOVE_PERCENT: - // Do not place anything in output; eat - // the percent character - rpos++; - continue; - break; - case URL_DECODER_PRESERVE_PERCENT: - // Leave the percent character in output - rpos++; - break; - case URL_DECODER_DECODE_INVALID: - // Decode - c = x2c(&data[rpos + 1]); - rpos += 3; - // Note: What if an invalid encoding decodes into a path - // separator? This is theoretical at the moment, because - // the only platform we know doesn't convert separators is - // Apache, who will also respond with 400 if invalid encoding - // is encountered. Thus no check for a separator here. - break; - case URL_DECODER_STATUS_400: - // Backend will reject request with 400, which means - // that it does not matter what we do. - tx->response_status_expected_number = 400; - - // Preserve the percent character - rpos++; - break; - default: - // Unknown setting - return -1; - break; - } - } - } - } else { - // Invalid encoding (not enough data) - tx->flags |= HTP_PATH_INVALID_ENCODING; - - if (cfg->query_invalid_encoding_handling == URL_DECODER_REMOVE_PERCENT) { - // Do not place the percent character in output - rpos++; - continue; - } else { - rpos++; - } - } - } else { - // One non-encoded character - - // Is it a NUL byte? - if (c == 0) { - switch (cfg->query_nul_raw_handling) { - case TERMINATE: - // Terminate path with a raw NUL byte - bstr_len_adjust(query, wpos); - return 1; - break; - case STATUS_400: - // Leave the NUL byte, but set the expected status - tx->response_status_expected_number = 400; - break; - case STATUS_404: - // Leave the NUL byte, but set the expected status - tx->response_status_expected_number = 404; - break; - } - } - - rpos++; - } - - // Place the character into output - - // Check for control characters - if (c < 0x20) { - if (cfg->query_control_char_handling == STATUS_400) { - tx->response_status_expected_number = 400; - } - } - - // Convert backslashes to forward slashes, if necessary - if ((c == '\\') && (cfg->query_backslash_separators)) { - c = '/'; - } - - // Lowercase characters, if necessary - if (cfg->query_case_insensitive) { - c = tolower(c); - } - - // If we're compressing separators then we need - // to track if the previous character was a separator - if (cfg->query_compress_separators) { - if (c == '/') { - if (!previous_was_separator) { - data[wpos++] = c; - previous_was_separator = 1; - } else { - // Do nothing; we don't want - // another separator in output - } - } else { - data[wpos++] = c; - previous_was_separator = 0; - } - } else { - data[wpos++] = c; - } - } - - bstr_len_adjust(query, wpos); - - return 1; -} - -/** - * Decode a request path according to the settings in the - * provided configuration structure. - * - * @param cfg - * @param tx - * @param path - */ -int htp_decode_path_inplace(htp_cfg_t *cfg, htp_tx_t *tx, bstr *path) { - if (path == NULL) - return -1; - - unsigned char *data = (unsigned char *) bstr_ptr(path); - if (data == NULL) { - return -1; - } - size_t len = bstr_len(path); - - // TODO I don't like this function. It's too complex. - - size_t rpos = 0; - size_t wpos = 0; - int previous_was_separator = 0; - - while (rpos < len) { - int c = data[rpos]; - - // Decode encoded characters - if (c == '%') { - if (rpos + 2 < len) { - int handled = 0; - - if (cfg->path_decode_u_encoding) { - // Check for the %u encoding - if ((data[rpos + 1] == 'u') || (data[rpos + 1] == 'U')) { - handled = 1; - - if (cfg->path_decode_u_encoding == STATUS_400) { - tx->response_status_expected_number = 400; - } - - if (rpos + 5 < len) { - if (isxdigit(data[rpos + 2]) && (isxdigit(data[rpos + 3])) - && isxdigit(data[rpos + 4]) && (isxdigit(data[rpos + 5]))) { - // Decode a valid %u encoding - c = decode_u_encoding(cfg, tx, &data[rpos + 2]); - rpos += 6; - - if (c == 0) { - tx->flags |= HTP_PATH_ENCODED_NUL; - - if (cfg->path_nul_encoded_handling == STATUS_400) { - tx->response_status_expected_number = 400; - } else if (cfg->path_nul_encoded_handling == STATUS_404) { - tx->response_status_expected_number = 404; - } - } - } else { - // Invalid %u encoding - tx->flags |= HTP_PATH_INVALID_ENCODING; - - switch (cfg->path_invalid_encoding_handling) { - case URL_DECODER_REMOVE_PERCENT: - // Do not place anything in output; eat - // the percent character - rpos++; - continue; - break; - case URL_DECODER_PRESERVE_PERCENT: - // Leave the percent character in output - rpos++; - break; - case URL_DECODER_DECODE_INVALID: - // Decode invalid %u encoding - c = decode_u_encoding(cfg, tx, &data[rpos + 2]); - rpos += 6; - break; - case URL_DECODER_STATUS_400: - // Set expected status to 400 - tx->response_status_expected_number = 400; - - // Decode invalid %u encoding - c = decode_u_encoding(cfg, tx, &data[rpos + 2]); - rpos += 6; - break; - break; - default: - // Unknown setting - return -1; - break; - } - } - } else { - // Invalid %u encoding (not enough data) - tx->flags |= HTP_PATH_INVALID_ENCODING; - - if (cfg->path_invalid_encoding_handling == URL_DECODER_REMOVE_PERCENT) { - // Remove the percent character from output - rpos++; - continue; - } else { - rpos++; - } - } - } - } - - // Handle standard URL encoding - if (!handled) { - if ((isxdigit(data[rpos + 1])) && (isxdigit(data[rpos + 2]))) { - c = x2c(&data[rpos + 1]); - - if (c == 0) { - tx->flags |= HTP_PATH_ENCODED_NUL; - - switch (cfg->path_nul_encoded_handling) { - case TERMINATE: - bstr_len_adjust(path, wpos); - return 1; - break; - case STATUS_400: - tx->response_status_expected_number = 400; - break; - case STATUS_404: - tx->response_status_expected_number = 404; - break; - } - } - - if ((c == '/') || ((cfg->path_backslash_separators) && (c == '\\'))) { - tx->flags |= HTP_PATH_ENCODED_SEPARATOR; - - switch (cfg->path_decode_separators) { - case STATUS_404: - tx->response_status_expected_number = 404; - // Fall-through - case NO: - // Leave encoded - c = '%'; - rpos++; - break; - case YES: - // Decode - rpos += 3; - break; - } - } else { - // Decode - rpos += 3; - } - } else { - // Invalid encoding - tx->flags |= HTP_PATH_INVALID_ENCODING; - - switch (cfg->path_invalid_encoding_handling) { - case URL_DECODER_REMOVE_PERCENT: - // Do not place anything in output; eat - // the percent character - rpos++; - continue; - break; - case URL_DECODER_PRESERVE_PERCENT: - // Leave the percent character in output - rpos++; - break; - case URL_DECODER_DECODE_INVALID: - // Decode - c = x2c(&data[rpos + 1]); - rpos += 3; - // Note: What if an invalid encoding decodes into a path - // separator? This is theoretical at the moment, because - // the only platform we know doesn't convert separators is - // Apache, who will also respond with 400 if invalid encoding - // is encountered. Thus no check for a separator here. - break; - case URL_DECODER_STATUS_400: - // Backend will reject request with 400, which means - // that it does not matter what we do. - tx->response_status_expected_number = 400; - - // Preserve the percent character - rpos++; - break; - default: - // Unknown setting - return -1; - break; - } - } - } - } else { - // Invalid encoding (not enough data) - tx->flags |= HTP_PATH_INVALID_ENCODING; - - if (cfg->path_invalid_encoding_handling == URL_DECODER_REMOVE_PERCENT) { - // Do not place the percent character in output - rpos++; - continue; - } else { - rpos++; - } - } - } else { - // One non-encoded character - - // Is it a NUL byte? - if (c == 0) { - switch (cfg->path_nul_raw_handling) { - case TERMINATE: - // Terminate path with a raw NUL byte - bstr_len_adjust(path, wpos); - return 1; - break; - case STATUS_400: - // Leave the NUL byte, but set the expected status - tx->response_status_expected_number = 400; - break; - case STATUS_404: - // Leave the NUL byte, but set the expected status - tx->response_status_expected_number = 404; - break; - } - } - - rpos++; - } - - // Place the character into output - - // Check for control characters - if (c < 0x20) { - if (cfg->path_control_char_handling == STATUS_400) { - tx->response_status_expected_number = 400; - } - } - - // Convert backslashes to forward slashes, if necessary - if ((c == '\\') && (cfg->path_backslash_separators)) { - c = '/'; - } - - // Lowercase characters, if necessary - if (cfg->path_case_insensitive) { - c = tolower(c); - } - - // If we're compressing separators then we need - // to track if the previous character was a separator - if (cfg->path_compress_separators) { - if (c == '/') { - if (!previous_was_separator) { - data[wpos++] = c; - previous_was_separator = 1; - } else { - // Do nothing; we don't want - // another separator in output - } - } else { - data[wpos++] = c; - previous_was_separator = 0; - } - } else { - data[wpos++] = c; - } - } - - bstr_len_adjust(path, wpos); - - return 1; -} - -/** - * Normalize a previously-parsed request URI. - * - * @param connp - * @param incomplete - * @param normalized - * @return HTP_OK or HTP_ERROR - */ -int htp_normalize_parsed_uri(htp_connp_t *connp, htp_uri_t *incomplete, htp_uri_t *normalized) { - // Scheme - if (incomplete->scheme != NULL) { - // Duplicate and convert to lowercase - normalized->scheme = bstr_dup_lower(incomplete->scheme); - if (normalized->scheme == NULL) - return HTP_ERROR; - } - - // Username - if (incomplete->username != NULL) { - normalized->username = bstr_strdup(incomplete->username); - if (normalized->username == NULL) - return HTP_ERROR; - htp_uriencoding_normalize_inplace(normalized->username); - } - - // Password - if (incomplete->password != NULL) { - normalized->password = bstr_strdup(incomplete->password); - if (normalized->password == NULL) - return HTP_ERROR; - htp_uriencoding_normalize_inplace(normalized->password); - } - - // Hostname - if (incomplete->hostname != NULL) { - // We know that incomplete->hostname does not contain - // port information, so no need to check for it here - normalized->hostname = bstr_strdup(incomplete->hostname); - if (normalized->hostname == NULL) - return HTP_ERROR; - htp_uriencoding_normalize_inplace(normalized->hostname); - htp_normalize_hostname_inplace(normalized->hostname); - } - - // Port - if (incomplete->port != NULL) { - // Parse provided port - normalized->port_number = htp_parse_positive_integer_whitespace((unsigned char *) bstr_ptr(incomplete->port), - bstr_len(incomplete->port), 10); - // We do not report failed port parsing, but leave - // to upstream to detect and act upon it. - } - - // Path - if (incomplete->path != NULL) { - // Make a copy of the path, on which we can work on - normalized->path = bstr_strdup(incomplete->path); - if (normalized->path != NULL) { - // Decode URL-encoded (and %u-encoded) characters, as well as lowercase, - // compress separators and convert backslashes. - htp_decode_path_inplace(connp->cfg, connp->in_tx, normalized->path); - - // Handle UTF-8 in path - if (connp->cfg->path_convert_utf8) { - // Decode Unicode characters into a single-byte stream, using best-fit mapping - htp_utf8_decode_path_inplace(connp->cfg, connp->in_tx, normalized->path); - } else { - // Only validate path as a UTF-8 stream - htp_utf8_validate_path(connp->in_tx, normalized->path); - } - - // RFC normalization - htp_normalize_uri_path_inplace(normalized->path); - } else { - return HTP_ERROR; - } - } - - // Query - if (incomplete->query != NULL) { - // We cannot URL-decode the query string here; it needs to be - // parsed into individual key-value pairs first. - normalized->query = bstr_strdup(incomplete->query); - if (normalized->query == NULL) - return HTP_ERROR; - } - - // Fragment - if (incomplete->fragment != NULL) { - normalized->fragment = bstr_strdup(incomplete->fragment); - if (normalized->fragment == NULL) - return HTP_ERROR; - htp_uriencoding_normalize_inplace(normalized->fragment); - } - - return HTP_OK; -} - -/** - * Normalize request hostname. Convert all characters to lowercase and - * remove trailing dots from the end, if present. - * - * @param hostname - * @return normalized hostnanme - */ -bstr *htp_normalize_hostname_inplace(bstr *hostname) { - if (hostname == NULL) - return NULL; - bstr_tolowercase(hostname); - - char *data = bstr_ptr(hostname); - size_t len = bstr_len(hostname); - - while (len > 0) { - if (data[len - 1] != '.') return hostname; - - bstr_chop(hostname); - len--; - } - - return hostname; -} - -/** - * Replace the URI in the structure with the one provided as the parameter - * to this function (which will typically be supplied in a Host header). - * - * @param connp - * @param parsed_uri - * @param hostname - */ -void htp_replace_hostname(htp_connp_t *connp, htp_uri_t *parsed_uri, bstr *hostname) { - if (hostname == NULL) - return; - int colon = bstr_chr(hostname, ':'); - if (colon == -1) { - // Hostname alone - parsed_uri->hostname = bstr_strdup(hostname); - htp_normalize_hostname_inplace(parsed_uri->hostname); - } else { - // Hostname - parsed_uri->hostname = bstr_strdup_ex(hostname, 0, colon); - // TODO Handle whitespace around hostname - htp_normalize_hostname_inplace(parsed_uri->hostname); - - // Port - int port = htp_parse_positive_integer_whitespace((unsigned char *) bstr_ptr(hostname) + colon + 1, - bstr_len(hostname) - colon - 1, 10); - if (port < 0) { - // Failed to parse port - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Invalid server port information in request"); - } else if ((port > 0) && (port < 65536)) { - // Valid port - if (port != connp->conn->local_port) { - // Port is different from the TCP port - htp_log(connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Request server port number differs from the actual TCP port"); - } else { - parsed_uri->port_number = port; - } - } - } -} - -/** - * Is URI character reserved? - * - * @param c - * @return 1 if it is, 0 if it isn't - */ -int htp_is_uri_unreserved(unsigned char c) { - if (((c >= 0x41) && (c <= 0x5a)) || - ((c >= 0x61) && (c <= 0x7a)) || - ((c >= 0x30) && (c <= 0x39)) || - (c == 0x2d) || (c == 0x2e) || - (c == 0x5f) || (c == 0x7e)) { - return 1; - } else { - return 0; - } -} - -/** - * Decode a URL-encoded string, leaving the reserved - * characters and invalid encodings alone. - * - * @param s - */ -void htp_uriencoding_normalize_inplace(bstr *s) { - if (s == NULL) return; - unsigned char *data = (unsigned char *) bstr_ptr(s); - size_t len = bstr_len(s); - - size_t rpos = 0; - size_t wpos = 0; - - while (rpos < len) { - if (data[rpos] == '%') { - if (rpos + 2 < len) { - if (isxdigit(data[rpos + 1]) && (isxdigit(data[rpos + 2]))) { - unsigned char c = x2c(&data[rpos + 1]); - - if (!htp_is_uri_unreserved(c)) { - // Leave reserved characters encoded, but convert - // the hexadecimal digits to uppercase - data[wpos++] = data[rpos++]; - data[wpos++] = toupper(data[rpos++]); - data[wpos++] = toupper(data[rpos++]); - } else { - // Decode unreserved character - data[wpos++] = c; - rpos += 3; - } - } else { - // Invalid URL encoding: invalid hex digits - - // Copy over what's there - data[wpos++] = data[rpos++]; - data[wpos++] = toupper(data[rpos++]); - data[wpos++] = toupper(data[rpos++]); - } - } else { - // Invalid URL encoding: string too short - - // Copy over what's there - data[wpos++] = data[rpos++]; - while (rpos < len) { - data[wpos++] = toupper(data[rpos++]); - } - } - } else { - data[wpos++] = data[rpos++]; - } - } - - bstr_len_adjust(s, wpos); -} - -#if 0 - -/** - * - */ -int htp_prenormalize_uri_path_inplace(bstr *s, int *flags, int case_insensitive, int backslash, int decode_separators, int remove_consecutive) { - char *data = bstr_ptr(s); - size_t len = bstr_len(s); - - size_t rpos = 0; - size_t wpos = 0; - - while (rpos < len) { - char c = data[rpos]; - - // Convert backslash characters where necessary - if ((c == '/') || ((c == '\\') && (backslash))) { - if ((!remove_consecutive) || (wpos == 0) || (data[wpos - 1] != '/')) { - data[wpos++] = '/'; - } - - rpos++; - } else - if ((c == '%') && (decode_separators)) { - if (rpos + 2 < len) { - if (isxdigit(data[rpos + 1]) && (isxdigit(data[rpos + 2]))) { - unsigned char x = x2c(&data[rpos + 1]); - - if (x == 0) { - (*flags) |= HTP_PATH_ENCODED_NUL; - } - - if ((x == '/') || ((backslash) && (x == '\\'))) { - data[wpos++] = '/'; - rpos += 3; - continue; - } - } else { - // Invalid URL encoding - (*flags) |= HTP_PATH_INVALID_ENCODING; - - // Copy over all three bytes - data[wpos++] = data[rpos++]; - data[wpos++] = data[rpos++]; - data[wpos++] = data[rpos++]; - } - } else { - // Not enough characters - (*flags) |= HTP_PATH_INVALID_ENCODING; - - // Copy over what's there - while (rpos < len) { - data[wpos++] = data[rpos++]; - } - } - } else { - // Just copy the character - if (case_insensitive) { - data[wpos++] = tolower(c); - } else { - data[wpos++] = c; - } - - rpos++; - } - } - - bstr_len_adjust(s, wpos); -} -#endif - -/** - * Normalize URL path. This function implements the remove dot segments algorithm - * speficied in RFC 3986, section 5.2.4. - * - * @param s - */ -void htp_normalize_uri_path_inplace(bstr *s) { - if (s == NULL) return; - char *data = bstr_ptr(s); - size_t len = bstr_len(s); - - size_t rpos = 0; - size_t wpos = 0; - - int c = -1; - while (rpos < len) { - if (c == -1) { - c = data[rpos++]; - } - - // A. If the input buffer begins with a prefix of "../" or "./", - // then remove that prefix from the input buffer; otherwise, - if (c == '.') { - if ((rpos + 1 < len) && (data[rpos] == '.') && (data[rpos + 1] == '/')) { - c = -1; - rpos += 2; - continue; - } else if ((rpos < len) && (data[rpos + 1] == '/')) { - c = -1; - rpos += 2; - continue; - } - } - - if (c == '/') { - // B. if the input buffer begins with a prefix of "/./" or "/.", - // where "." is a complete path segment, then replace that - // prefix with "/" in the input buffer; otherwise, - if ((rpos + 1 < len) && (data[rpos] == '.') && (data[rpos + 1] == '/')) { - c = '/'; - rpos += 2; - continue; - } else if ((rpos + 1 == len) && (data[rpos] == '.')) { - c = '/'; - rpos += 1; - continue; - } - - // C. if the input buffer begins with a prefix of "/../" or "/..", - // where ".." is a complete path segment, then replace that - // prefix with "/" in the input buffer and remove the last - // segment and its preceding "/" (if any) from the output - // buffer; otherwise, - if ((rpos + 2 < len) && (data[rpos] == '.') && (data[rpos + 1] == '.') && (data[rpos + 2] == '/')) { - c = '/'; - rpos += 3; - - // Remove the last segment - while ((wpos > 0) && (data[wpos - 1] != '/')) wpos--; - if (wpos > 0) wpos--; - continue; - } else if ((rpos + 2 == len) && (data[rpos] == '.') && (data[rpos + 1] == '.')) { - c = '/'; - rpos += 2; - - // Remove the last segment - while ((wpos > 0) && (data[wpos - 1] != '/')) wpos--; - if (wpos > 0) wpos--; - continue; - } - } - - // D. if the input buffer consists only of "." or "..", then remove - // that from the input buffer; otherwise, - if ((c == '.') && (rpos == len)) { - rpos++; - continue; - } - - if ((c == '.') && (rpos + 1 == len) && (data[rpos] == '.')) { - rpos += 2; - continue; - } - - // E. move the first path segment in the input buffer to the end of - // the output buffer, including the initial "/" character (if - // any) and any subsequent characters up to, but not including, - // the next "/" character or the end of the input buffer. - data[wpos++] = c; - - while ((rpos < len) && (data[rpos] != '/')) { - // data[wpos++] = data[rpos++]; - int c2 = data[rpos++]; - data[wpos++] = c2; - } - - c = -1; - } - - bstr_len_adjust(s, wpos); -} - -/** - * - */ -void fprint_raw_data(FILE *stream, const char *name, unsigned char *data, size_t len) { - char buf[160]; - size_t offset = 0; - - fprintf(stream, "\n%s: data len %zd (0x%zx)\n", name, len, len); - - while (offset < len) { - size_t i; - - sprintf(buf, "%08zx", offset); - strcat(buf + strlen(buf), " "); - - i = 0; - while (i < 8) { - if (offset + i < len) { - sprintf(buf + strlen(buf), "%02x ", data[offset + i]); - } else { - strcat(buf + strlen(buf), " "); - } - - i++; - } - - strcat(buf + strlen(buf), " "); - - i = 8; - while (i < 16) { - if (offset + i < len) { - sprintf(buf + strlen(buf), "%02x ", data[offset + i]); - } else { - strcat(buf + strlen(buf), " "); - } - - i++; - } - - strcat(buf + strlen(buf), " |"); - - i = 0; - char *p = buf + strlen(buf); - while ((offset + i < len) && (i < 16)) { - int c = data[offset + i]; - - if (isprint(c)) { - *p++ = c; - } else { - *p++ = '.'; - } - - i++; - } - - *p++ = '|'; - *p++ = '\n'; - *p++ = '\0'; - - fprintf(stream, "%s", buf); - offset += 16; - } - - fprintf(stream, "\n"); -} - - -/* - - */ - -/** - * - */ -char *htp_connp_in_state_as_string(htp_connp_t *connp) { - if (connp == NULL) return "NULL"; - - if (connp->in_state == htp_connp_REQ_IDLE) return "REQ_IDLE"; - if (connp->in_state == htp_connp_REQ_LINE) return "REQ_FIRST_LINE"; - if (connp->in_state == htp_connp_REQ_PROTOCOL) return "REQ_PROTOCOL"; - if (connp->in_state == htp_connp_REQ_HEADERS) return "REQ_HEADERS"; - if (connp->in_state == htp_connp_REQ_BODY_DETERMINE) return "REQ_BODY_DETERMINE"; - if (connp->in_state == htp_connp_REQ_BODY_IDENTITY) return "REQ_BODY_IDENTITY"; - if (connp->in_state == htp_connp_REQ_BODY_CHUNKED_LENGTH) return "REQ_BODY_CHUNKED_LENGTH"; - if (connp->in_state == htp_connp_REQ_BODY_CHUNKED_DATA) return "REQ_BODY_CHUNKED_DATA"; - if (connp->in_state == htp_connp_REQ_BODY_CHUNKED_DATA_END) return "REQ_BODY_CHUNKED_DATA_END"; - - if (connp->in_state == htp_connp_REQ_CONNECT_CHECK) return "htp_connp_REQ_CONNECT_CHECK"; - if (connp->in_state == htp_connp_REQ_CONNECT_WAIT_RESPONSE) return "htp_connp_REQ_CONNECT_WAIT_RESPONSE"; - - return "UNKNOWN"; -} - -/** - * - */ -char *htp_connp_out_state_as_string(htp_connp_t *connp) { - if (connp == NULL) return "NULL"; - - if (connp->out_state == htp_connp_RES_IDLE) return "RES_IDLE"; - if (connp->out_state == htp_connp_RES_LINE) return "RES_LINE"; - if (connp->out_state == htp_connp_RES_HEADERS) return "RES_HEADERS"; - if (connp->out_state == htp_connp_RES_BODY_DETERMINE) return "RES_BODY_DETERMINE"; - if (connp->out_state == htp_connp_RES_BODY_IDENTITY) return "RES_BODY_IDENTITY"; - if (connp->out_state == htp_connp_RES_BODY_CHUNKED_LENGTH) return "RES_BODY_CHUNKED_LENGTH"; - if (connp->out_state == htp_connp_RES_BODY_CHUNKED_DATA) return "RES_BODY_CHUNKED_DATA"; - if (connp->out_state == htp_connp_RES_BODY_CHUNKED_DATA_END) return "RES_BODY_CHUNKED_DATA_END"; - - return "UNKNOWN"; -} - -/** - * - */ -char *htp_tx_progress_as_string(htp_tx_t *tx, int direction) { - if (tx == NULL) return "NULL"; - - switch ((direction == 0) ? tx->progress[0] : tx->progress[1]) { - case TX_PROGRESS_NEW: - return "NEW"; - case TX_PROGRESS_REQ_LINE: - return "REQ_LINE"; - case TX_PROGRESS_REQ_HEADERS: - return "REQ_HEADERS"; - case TX_PROGRESS_REQ_BODY: - return "REQ_BODY"; - case TX_PROGRESS_REQ_TRAILER: - return "REQ_TRAILER"; - case TX_PROGRESS_WAIT: - return "WAIT"; - case TX_PROGRESS_RES_LINE: - return "RES_LINE"; - case TX_PROGRESS_RES_HEADERS: - return "RES_HEADERS"; - case TX_PROGRESS_RES_BODY: - return "RES_BODY"; - case TX_PROGRESS_RES_TRAILER: - return "RES_TRAILER"; - case TX_PROGRESS_DONE: - return "DONE"; - } - - return "UNKNOWN"; -} - -bstr *htp_unparse_uri_noencode(htp_uri_t *uri) { - if (uri == NULL) { - return NULL; - } - - // On the first pass determine the length of the final string - size_t len = 0; - - if (uri->scheme != NULL) { - len += bstr_len(uri->scheme); - len += 3; // "://" - } - - if ((uri->username != NULL) || (uri->password != NULL)) { - if (uri->username != NULL) { - len += bstr_len(uri->username); - } - - len += 1; // ":" - - if (uri->password != NULL) { - len += bstr_len(uri->password); - } - - len += 1; // "@" - } - - if (uri->hostname != NULL) { - len += bstr_len(uri->hostname); - } - - if (uri->port != NULL) { - len += 1; // ":" - len += bstr_len(uri->port); - } - - if (uri->path != NULL) { - len += bstr_len(uri->path); - } - - if (uri->query != NULL) { - len += 1; // "?" - len += bstr_len(uri->query); - } - - if (uri->fragment != NULL) { - len += 1; // "#" - len += bstr_len(uri->fragment); - } - - // On the second pass construct the string - bstr *r = bstr_alloc(len); - if (r == NULL) { - return NULL; - } - - if (uri->scheme != NULL) { - bstr_add_str_noex(r, uri->scheme); - bstr_add_cstr_noex(r, "://"); - } - - if ((uri->username != NULL) || (uri->password != NULL)) { - if (uri->username != NULL) { - bstr_add_str_noex(r, uri->username); - } - - bstr_add_cstr(r, ":"); - - if (uri->password != NULL) { - bstr_add_str_noex(r, uri->password); - } - - bstr_add_cstr_noex(r, "@"); - } - - if (uri->hostname != NULL) { - bstr_add_str_noex(r, uri->hostname); - } - - if (uri->port != NULL) { - bstr_add_cstr(r, ":"); - bstr_add_str_noex(r, uri->port); - } - - if (uri->path != NULL) { - bstr_add_str_noex(r, uri->path); - } - - if (uri->query != NULL) { - bstr *query = bstr_strdup(uri->query); - htp_uriencoding_normalize_inplace(query); - bstr_add_cstr_noex(r, "?"); - bstr_add_str_noex(r, query); - bstr_free(query); - } - - if (uri->fragment != NULL) { - bstr_add_cstr_noex(r, "#"); - bstr_add_str_noex(r, uri->fragment); - } - - return r; -} - -/** - * Construct a bstr that contains the raw request headers. - * - * @param tx - * @return - */ -bstr *htp_tx_generate_request_headers_raw(htp_tx_t *tx) { - bstr *request_headers_raw = NULL; - size_t i, len = 0; - - for (i = 0; i < list_size(tx->request_header_lines); i++) { - htp_header_line_t *hl = list_get(tx->request_header_lines, i); - len += bstr_len(hl->line); - if (hl->terminators) - len += bstr_len(hl->terminators); - else - len += 2; // 0d 0a - } - - request_headers_raw = bstr_alloc(len); - if (request_headers_raw == NULL) { - htp_log(tx->connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Failed to allocate bstring of %d bytes", len); - return NULL; - } - - for (i = 0; i < list_size(tx->request_header_lines); i++) { - htp_header_line_t *hl = list_get(tx->request_header_lines, i); - bstr_add_str_noex(request_headers_raw, hl->line); - if (hl->terminators) - bstr_add_str_noex(request_headers_raw, hl->terminators); - else - bstr_add_cstr_noex(request_headers_raw, "\r\n"); - } - - return request_headers_raw; -} - -/** - * Get a bstr that contains the raw request headers. This method will always - * return an up-to-date buffer, containing the last known headers. Thus, if - * it is called once after REQUEST_HEADERS phase it will return one buffer, but - * it may return a different buffer if called after REQUEST_TRAILERS phase (but - * only if the request actually contains trailer headers). Do not retain the - * bstr pointer, as the buffer may change. If there are no changes to the - * request header structure, only one buffer will be contstructed and used. (Multiple - * invocations of this method will not cause multiple buffers to be created.) - * - * @param tx - * @return - */ -bstr *htp_tx_get_request_headers_raw(htp_tx_t *tx) { - // Check that we are not called too early - if (tx->progress[0] < TX_PROGRESS_REQ_HEADERS) return NULL; - - if (tx->request_headers_raw == NULL) { - tx->request_headers_raw = htp_tx_generate_request_headers_raw(tx); - tx->request_headers_raw_lines = list_size(tx->request_header_lines); - } else { - // Check that the buffer we have is not obsolete - if (tx->request_headers_raw_lines < list_size(tx->request_header_lines)) { - // Rebuild raw buffer - bstr_free(tx->request_headers_raw); - tx->request_headers_raw = htp_tx_generate_request_headers_raw(tx); - tx->request_headers_raw_lines = list_size(tx->request_header_lines); - } - } - - return tx->request_headers_raw; -} - -/** - * Construct a bstr that contains the raw response headers. - * - * @param tx - * @return - */ -bstr *htp_tx_generate_response_headers_raw(htp_tx_t *tx) { - bstr *response_headers_raw = NULL; - size_t i, len = 0; - - for (i = 0; i < list_size(tx->response_header_lines); i++) { - htp_header_line_t *hl = list_get(tx->response_header_lines, i); - len += bstr_len(hl->line); - if (hl->terminators) - len += bstr_len(hl->terminators); - else - len += 2; // 0d 0a - } - - response_headers_raw = bstr_alloc(len); - if (response_headers_raw == NULL) { - htp_log(tx->connp, HTP_LOG_MARK, HTP_LOG_ERROR, 0, "Failed to allocate bstring of %d bytes", len); - return NULL; - } - - for (i = 0; i < list_size(tx->response_header_lines); i++) { - htp_header_line_t *hl = list_get(tx->response_header_lines, i); - bstr_add_str_noex(response_headers_raw, hl->line); - if (hl->terminators) - bstr_add_str_noex(response_headers_raw, hl->terminators); - else - bstr_add_cstr_noex(response_headers_raw, "\r\n"); - } - - return response_headers_raw; -} - -/** - * Get a bstr that contains the raw response headers. This method will always - * return an up-to-date buffer, containing the last known headers. Thus, if - * it is called once after RESPONSE_HEADERS phase it will return one buffer, but - * it may return a different buffer if called after RESPONSE_TRAILERS phase (but - * only if the response actually contains trailer headers). Do not retain the - * bstr pointer, as the buffer may change. If there are no changes to the - * response header structure, only one buffer will be contstructed and used. (Multiple - * invocations of this method will not cause multiple buffers to be created.) - * - * @param tx - * @return - */ -bstr *htp_tx_get_response_headers_raw(htp_tx_t *tx) { - // Check that we are not called too early - if (tx->progress[1] < TX_PROGRESS_RES_HEADERS) return NULL; - - if (tx->response_headers_raw == NULL) { - tx->response_headers_raw = htp_tx_generate_response_headers_raw(tx); - tx->response_headers_raw_lines = list_size(tx->response_header_lines); - } else { - // Check that the buffer we have is not obsolete - if (tx->response_headers_raw_lines < list_size(tx->response_header_lines)) { - // Rebuild raw buffer - bstr_free(tx->response_headers_raw); - tx->response_headers_raw = htp_tx_generate_response_headers_raw(tx); - tx->response_headers_raw_lines = list_size(tx->response_header_lines); - } - } - - return tx->response_headers_raw; -} diff --git a/libhtp/htp/utf8_decoder.c b/libhtp/htp/utf8_decoder.c deleted file mode 100644 index 35c6ae6164..0000000000 --- a/libhtp/htp/utf8_decoder.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * LibHTP (http://www.libhtp.org) - * Copyright 2009,2010 Ivan Ristic - * - * LibHTP is an open source product, released under terms of the General Public Licence - * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text - * of the license. - * - * In addition, there is a special exception that allows LibHTP to be freely - * used with any OSI-approved open source licence. Please refer to the file - * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. - * - */ - -/* -Copyright (c) 2008-2009 Bjoern Hoehrmann - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software -and associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -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 AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -// Copyright (c) 2008-2009 Bjoern Hoehrmann -// See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for details. - -#include "utf8_decoder.h" - -static const uint8_t utf8d[] = { - 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, // 00..1f - 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, // 20..3f - 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, // 40..5f - 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, // 60..7f - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf - 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df - 0xa,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef - 0xb,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff - 0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2 - 1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4 - 1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6 - 1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8 -}; - -static const uint8_t utf8d_allow_overlong[] = { - 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, // 00..1f - 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, // 20..3f - 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, // 40..5f - 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, // 60..7f - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, // 80..9f - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, // a0..bf - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // c0..df; changed c0 and c1 - 0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x3,0x4,0x3,0x3, // e0..ef; changed e0 - 0x6,0x6,0x6,0x6,0x5,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8,0x8, // f0..ff; changed f0 - 0x0,0x1,0x2,0x3,0x5,0x8,0x7,0x1,0x1,0x1,0x4,0x6,0x1,0x1,0x1,0x1, // s0..s0 - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,1,1, // s1..s2 - 1,2,1,1,1,1,1,2,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1, // s3..s4 - 1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,1,1,1,3,1,3,1,1,1,1,1,1, // s5..s6 - 1,3,1,1,1,1,1,3,1,3,1,1,1,1,1,1,1,3,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // s7..s8 -}; - -inline uint32_t utf8_decode(uint32_t* state, uint32_t* codep, uint32_t byte) { - uint32_t type = utf8d[byte]; - - *codep = (*state != UTF8_ACCEPT) ? - (byte & 0x3fu) | (*codep << 6) : - (0xff >> type) & (byte); - - *state = utf8d[256 + *state*16 + type]; - return *state; -} - -inline uint32_t utf8_decode_allow_overlong(uint32_t* state, uint32_t* codep, uint32_t byte) { - uint32_t type = utf8d_allow_overlong[byte]; - - *codep = (*state != UTF8_ACCEPT) ? - (byte & 0x3fu) | (*codep << 6) : - (0xff >> type) & (byte); - - *state = utf8d[256 + *state*16 + type]; - return *state; -} - diff --git a/libhtp/htp/utf8_decoder.h b/libhtp/htp/utf8_decoder.h deleted file mode 100644 index e6825284fa..0000000000 --- a/libhtp/htp/utf8_decoder.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * LibHTP (http://www.libhtp.org) - * Copyright 2009,2010 Ivan Ristic - * - * LibHTP is an open source product, released under terms of the General Public Licence - * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text - * of the license. - * - * In addition, there is a special exception that allows LibHTP to be freely - * used with any OSI-approved open source licence. Please refer to the file - * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. - * - */ - -#ifndef _UTF8_DECODER_H -#define _UTF8_DECODER_H - -/* HTP changes: - * - * - Changed the name of the function from "decode" to "utf8_decode" - * - Created a separate header file - * - Copied the licence from the web page - * - Created a copy of the data and function "utf8_decode_allow_overlong", which - * does not treat overlong characters as invalid. - */ - -/* -Copyright (c) 2008-2009 Bjoern Hoehrmann - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software -and associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -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 AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#include - -#define UTF8_ACCEPT 0 -#define UTF8_REJECT 1 - -uint32_t utf8_decode(uint32_t* state, uint32_t* codep, uint32_t byte); -uint32_t utf8_decode_allow_overlong(uint32_t* state, uint32_t* codep, uint32_t byte); - -#endif /* _UTF8_DECODER_H */ - diff --git a/libhtp/m4/.keep b/libhtp/m4/.keep deleted file mode 100644 index ab93fd8072..0000000000 --- a/libhtp/m4/.keep +++ /dev/null @@ -1,2 +0,0 @@ -libhtp/m4 dir won't be created on CentOS 5.3 by autogen.sh, so work around that by having it in git - diff --git a/libhtp/test/Makefile.am b/libhtp/test/Makefile.am deleted file mode 100644 index ddf2952d94..0000000000 --- a/libhtp/test/Makefile.am +++ /dev/null @@ -1,12 +0,0 @@ - -check_PROGRAMS = main -main_SOURCES = main.c test.c test.h test-tcpick.c - -LDADD = ../htp/.libs/libhtp.a -lz -AM_CFLAGS = -g -O2 - - -#check: all -# ./main - - diff --git a/libhtp/test/files/01-get.t b/libhtp/test/files/01-get.t deleted file mode 100644 index 832f8e9c9a..0000000000 --- a/libhtp/test/files/01-get.t +++ /dev/null @@ -1,14 +0,0 @@ ->>> -GET /?p=%20 HTTP/1.0 -User-Agent: Mozilla - - -<<< -HTTP/1.0 200 OK -Date: Mon, 31 Aug 2009 20:25:50 GMT -Server: Apache -Connection: close -Content-Type: text/html -Content-Length: 12 - -Hello World! diff --git a/libhtp/test/files/02-header-test-apache2.t b/libhtp/test/files/02-header-test-apache2.t deleted file mode 100644 index ee6652d28e..0000000000 Binary files a/libhtp/test/files/02-header-test-apache2.t and /dev/null differ diff --git a/libhtp/test/files/03-post-urlencoded.t b/libhtp/test/files/03-post-urlencoded.t deleted file mode 100644 index e81076fdc2..0000000000 --- a/libhtp/test/files/03-post-urlencoded.t +++ /dev/null @@ -1,34 +0,0 @@ ->>> -POST / HTTP/1.0 -Content-Length: 12 -Content-Type: application/x-www-form-urlencoded -User-Agent: Mozilla - -p=0123456789 -<<< -HTTP/1.0 200 OK -Date: Mon, 31 Aug 2009 20:25:50 GMT -Server: Apache -Connection: close -Content-Type: text/html -Content-Length: 12 - -Hello World! ->>> -GET / HTTP/1.0 - - -<<< -HTTP/1.0 200 OK -Date: Mon, 31 Aug 2009 20:25:50 GMT -Server: Apache -Connection: close -Content-Type: text/html -Transfer-Encoding: chunked - -9 -012345678 -1 -9 -0 - diff --git a/libhtp/test/files/04-post-urlencoded-chunked.t b/libhtp/test/files/04-post-urlencoded-chunked.t deleted file mode 100644 index d99bb03296..0000000000 --- a/libhtp/test/files/04-post-urlencoded-chunked.t +++ /dev/null @@ -1,24 +0,0 @@ ->>> -POST / HTTP/1.1 -Transfer-Encoding: chunked -Content-Type: application/x-www-form-urlencoded -User-Agent: Mozilla -Cookie: 1 - -9 -012345678 -1 -9 -0 -Cookie: 2 - - -<<< -HTTP/1.0 200 OK -Date: Mon, 31 Aug 2009 20:25:50 GMT -Server: Apache -Connection: close -Content-Type: text/html -Content-Length: 12 - -Hello World! \ No newline at end of file diff --git a/libhtp/test/files/05-expect.t b/libhtp/test/files/05-expect.t deleted file mode 100644 index d6d474f4d5..0000000000 --- a/libhtp/test/files/05-expect.t +++ /dev/null @@ -1,37 +0,0 @@ ->>> -POST / HTTP/1.1 -User-Agent: curl/7.18.2 (i486-pc-linux-gnu) libcurl/7.18.2 OpenSSL/0.9.8g zlib/1.2.3.3 libidn/1.8 libssh2/0.18 -Accept: */* -Content-Length: 216 -Expect: 100-continue -Content-Type: multipart/form-data; boundary=----------------------------07869933ca1b - - -<<< -HTTP/1.1 100 Continue - - ->>> -------------------------------07869933ca1b -Content-Disposition: form-data; name="file"; filename="404.php" -Content-Type: application/octet-stream - - ->>> - ->>> - -------------------------------07869933ca1b-- - -<<< -HTTP/1.1 200 OK -Date: Tue, 03 Nov 2009 09:27:47 GMT -Server: Apache -Last-Modified: Thu, 30 Apr 2009 12:20:49 GMT -ETag: "2dcada-2d-468c4b9ec6a40" -Accept-Ranges: bytes -Content-Length: 45 -Vary: Accept-Encoding -Content-Type: text/html - -

It works!

diff --git a/libhtp/test/files/06-uri-normal.t b/libhtp/test/files/06-uri-normal.t deleted file mode 100644 index 0f83fc840c..0000000000 --- a/libhtp/test/files/06-uri-normal.t +++ /dev/null @@ -1,9 +0,0 @@ ->>> -GET http://username:password@www.example.com:8080/sub/folder/file.jsp?p=q#f HTTP/1.0 - - -<<< -HTTP/1.0 200 OK -Content-Length: 12 - -Hello World! \ No newline at end of file diff --git a/libhtp/test/files/07-pipelined-connection.t b/libhtp/test/files/07-pipelined-connection.t deleted file mode 100644 index bcb602ac98..0000000000 --- a/libhtp/test/files/07-pipelined-connection.t +++ /dev/null @@ -1,15 +0,0 @@ ->>> -GET /first HTTP/1.1 - -GET /second HTTP/1.1 - - -<<< -HTTP/1.0 200 OK -Content-Length: 12 - -Hello World! -HTTP/1.0 200 OK -Content-Length: 12 - -Hello World! \ No newline at end of file diff --git a/libhtp/test/files/08-not-pipelined-connection.t b/libhtp/test/files/08-not-pipelined-connection.t deleted file mode 100644 index ae1eb996d3..0000000000 --- a/libhtp/test/files/08-not-pipelined-connection.t +++ /dev/null @@ -1,18 +0,0 @@ ->>> -GET /first HTTP/1.1 - - -<<< -HTTP/1.0 200 OK -Content-Length: 12 - -Hello World! ->>> -GET /second HTTP/1.1 - - -<<< -HTTP/1.0 200 OK -Content-Length: 12 - -Hello World! \ No newline at end of file diff --git a/libhtp/test/files/09-multi-packet-request-head.t b/libhtp/test/files/09-multi-packet-request-head.t deleted file mode 100644 index 28ee8e8a3e..0000000000 --- a/libhtp/test/files/09-multi-packet-request-head.t +++ /dev/null @@ -1,14 +0,0 @@ ->>> -GET / HTTP/1.0 - ->>> -Host: www.example.com - ->>> - - -<<< -HTTP/1.0 200 OK -Content-Length: 12 - -Hello World! \ No newline at end of file diff --git a/libhtp/test/files/10-host-in-headers.t b/libhtp/test/files/10-host-in-headers.t deleted file mode 100644 index ac7766c6bb..0000000000 --- a/libhtp/test/files/10-host-in-headers.t +++ /dev/null @@ -1,34 +0,0 @@ ->>> -GET / HTTP/1.1 -Host: www.example.com - - -<<< -HTTP/1.0 200 OK -Content-Length: 12 - -Hello World! ->>> -GET / HTTP/1.1 -Host: www.example.com... - - -<<< -HTTP/1.0 200 OK -Content-Length: 12 ->>> -GET / HTTP/1.1 -Host: WwW.ExamPle.cOm - - -<<< -HTTP/1.0 200 OK -Content-Length: 12 ->>> -GET / HTTP/1.1 -Host: www.example.com:80 - - -<<< -HTTP/1.0 200 OK -Content-Length: 12 \ No newline at end of file diff --git a/libhtp/test/files/11-response-stream-closure.t b/libhtp/test/files/11-response-stream-closure.t deleted file mode 100644 index 2bc9d369ee..0000000000 --- a/libhtp/test/files/11-response-stream-closure.t +++ /dev/null @@ -1,13 +0,0 @@ ->>> -GET / HTTP/1.0 -User-Agent: Mozilla - - -<<< -HTTP/1.0 200 OK -Date: Mon, 31 Aug 2009 20:25:50 GMT -Server: Apache -Connection: close -Content-Type: text/html - -Hello World! \ No newline at end of file diff --git a/libhtp/test/files/12-connect-request.t b/libhtp/test/files/12-connect-request.t deleted file mode 100644 index e1fbe33471..0000000000 --- a/libhtp/test/files/12-connect-request.t +++ /dev/null @@ -1,21 +0,0 @@ ->>> -CONNECT www.ssllabs.com:443 HTTP/1.0 - - -<<< -HTTP/1.1 405 Method Not Allowed -Date: Sat, 12 Dec 2009 05:08:45 GMT -Server: Apache/2.2.14 (Unix) mod_ssl/2.2.14 OpenSSL/0.9.8g PHP/5.3.0 -Allow: GET,HEAD,POST,OPTIONS,TRACE -Vary: Accept-Encoding -Content-Length: 230 -Connection: close -Content-Type: text/html; charset=iso-8859-1 - - - -405 Method Not Allowed - -

Method Not Allowed

-

The requested method CONNECT is not allowed for the URL /.

- \ No newline at end of file diff --git a/libhtp/test/files/13-compressed-response-gzip-ct.t b/libhtp/test/files/13-compressed-response-gzip-ct.t deleted file mode 100644 index d5a2e31743..0000000000 Binary files a/libhtp/test/files/13-compressed-response-gzip-ct.t and /dev/null differ diff --git a/libhtp/test/files/14-compressed-response-gzip-chunked.t b/libhtp/test/files/14-compressed-response-gzip-chunked.t deleted file mode 100644 index bae8a2d3ce..0000000000 Binary files a/libhtp/test/files/14-compressed-response-gzip-chunked.t and /dev/null differ diff --git a/libhtp/test/files/15-connect-complete.t b/libhtp/test/files/15-connect-complete.t deleted file mode 100644 index 071d0643ba..0000000000 Binary files a/libhtp/test/files/15-connect-complete.t and /dev/null differ diff --git a/libhtp/test/files/16-connect-extra.t b/libhtp/test/files/16-connect-extra.t deleted file mode 100644 index da6b352362..0000000000 --- a/libhtp/test/files/16-connect-extra.t +++ /dev/null @@ -1,32 +0,0 @@ ->>> -CONNECT www.feistyduck.com:80 HTTP/1.1 -Host: www.feistyduck.com - -HEAD / HTTP/1.0 - - -<<< -HTTP/1.1 301 Moved Permanently -Date: Wed, 06 Jan 2010 17:41:34 GMT -Server: Apache -Location: https://www.feistyduck.com/ -Vary: Accept-Encoding -Content-Length: 235 -Content-Type: text/html; charset=iso-8859-1 - - - -301 Moved Permanently - -

Moved Permanently

-

The document has moved here.

- - -HTTP/1.1 301 Moved Permanently -Date: Wed, 06 Jan 2010 17:41:46 GMT -Server: Apache -Location: https://www.feistyduck.com/ -Vary: Accept-Encoding -Connection: close -Content-Type: text/html; charset=iso-8859-1 - diff --git a/libhtp/test/files/anchor.empty b/libhtp/test/files/anchor.empty deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/libhtp/test/files/misc.t b/libhtp/test/files/misc.t deleted file mode 100644 index 8ca3fceb90..0000000000 --- a/libhtp/test/files/misc.t +++ /dev/null @@ -1,10 +0,0 @@ ->>> -GET http://www.example%64.com/one/two/three.php?p=%64&q=%64#fff HTTP/1.0 - - -<<< -HTTP/1.1 200 OK -Content-Type: text/html -Content-Length: 12 - -Hello World! \ No newline at end of file diff --git a/libhtp/test/main.c b/libhtp/test/main.c deleted file mode 100644 index 4a2abde8de..0000000000 --- a/libhtp/test/main.c +++ /dev/null @@ -1,1388 +0,0 @@ -/* - * LibHTP (http://www.libhtp.org) - * Copyright 2009,2010 Ivan Ristic - * - * LibHTP is an open source product, released under terms of the General Public Licence - * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text - * of the license. - * - * In addition, there is a special exception that allows LibHTP to be freely - * used with any OSI-approved open source licence. Please refer to the file - * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. - * - */ - -#include -#include -#include -#include -#include -#include - -#include "../htp/bstr.h" -#include "../htp/htp.h" -#include "test.h" - -char *home = NULL; - -/** - * - */ -int test_get(htp_cfg_t *cfg) { - htp_connp_t *connp = NULL; - - int rc = test_run(home, "01-get.t", cfg, &connp); - if (rc < 0) { - if (connp != NULL) htp_connp_destroy_all(connp); - return -1; - } - - htp_connp_destroy_all(connp); - - return 1; -} - -/** - * - */ -int test_post_urlencoded_chunked(htp_cfg_t *cfg) { - htp_connp_t *connp = NULL; - - int rc = test_run(home, "04-post-urlencoded-chunked.t", cfg, &connp); - if (rc < 0) { - if (connp != NULL) htp_connp_destroy_all(connp); - return -1; - } - - htp_tx_t *tx = list_get(connp->conn->transactions, 0); - - bstr *key = NULL; - htp_header_t *h = NULL; - table_iterator_reset(tx->request_headers); - while ((key = table_iterator_next(tx->request_headers, (void **) & h)) != NULL) { - char *key = bstr_tocstr(h->name); - char *value = bstr_tocstr(h->value); - printf("-- HEADER [%s][%s]\n", key, value); - free(value); - free(key); - } - - bstr *raw = htp_tx_get_request_headers_raw(tx); - fprint_raw_data(stdout, "REQUEST HEADERS RAW 2", bstr_ptr(raw), bstr_len(raw)); - - htp_connp_destroy_all(connp); - - return 1; -} - -/** - * - */ -int test_post_urlencoded(htp_cfg_t *cfg) { - htp_connp_t *connp = NULL; - - int rc = test_run(home, "03-post-urlencoded.t", cfg, &connp); - if (rc < 0) { - if (connp != NULL) htp_connp_destroy_all(connp); - return -1; - } - - htp_connp_destroy_all(connp); - - return 1; -} - -/** - * - */ -int test_apache_header_parsing(htp_cfg_t *cfg) { - htp_connp_t *connp = NULL; - - int rc = test_run(home, "02-header-test-apache2.t", cfg, &connp); - if (rc < 0) { - if (connp != NULL) htp_connp_destroy_all(connp); - return -1; - } - - htp_tx_t *tx = list_get(connp->conn->transactions, 0); - if (tx == NULL) return -1; - - int count = 0; - bstr *key = NULL; - htp_header_t *h = NULL; - table_iterator_reset(tx->request_headers); - while ((key = table_iterator_next(tx->request_headers, (void **) & h)) != NULL) { - char *key = bstr_tocstr(h->name); - char *value = bstr_tocstr(h->value); - printf("-- HEADER [%s][%s]\n", key, value); - free(value); - free(key); - } - - // There must be 9 headers - if (table_size(tx->request_headers) != 9) { - printf("Got %i headers, but expected 9\n", table_size(tx->request_headers)); - htp_connp_destroy(connp); - return -1; - } - - // Check every header - count = 0; - key = NULL; - h = NULL; - table_iterator_reset(tx->request_headers); - while ((key = table_iterator_next(tx->request_headers, (void **) & h)) != NULL) { - - switch (count) { - case 0: - if (bstr_cmpc(h->name, " Invalid-Folding") != 0) { - printf("Header %i incorrect name\n", count + 1); - return -1; - } - if (bstr_cmpc(h->value, "1") != 0) { - printf("Header %i incorrect value\n", count + 1); - return -1; - } - break; - case 1: - if (bstr_cmpc(h->name, "Valid-Folding") != 0) { - printf("Header %i incorrect name\n", count + 1); - return -1; - } - if (bstr_cmpc(h->value, "2 2") != 0) { - printf("Header %i incorrect value\n", count + 1); - return -1; - } - break; - case 2: - if (bstr_cmpc(h->name, "Normal-Header") != 0) { - printf("Header %i incorrect name\n", count + 1); - return -1; - } - if (bstr_cmpc(h->value, "3") != 0) { - printf("Header %i incorrect value\n", count + 1); - return -1; - } - break; - case 3: - if (bstr_cmpc(h->name, "Invalid Header Name") != 0) { - printf("Header %i incorrect name\n", count + 1); - return -1; - } - if (bstr_cmpc(h->value, "4") != 0) { - printf("Header %i incorrect value\n", count + 1); - return -1; - } - break; - case 4: - if (bstr_cmpc(h->name, "Same-Name-Headers") != 0) { - printf("Header %i incorrect name\n", count + 1); - return -1; - } - if (bstr_cmpc(h->value, "5, 6") != 0) { - printf("Header %i incorrect value\n", count + 1); - return -1; - } - break; - case 5: - if (bstr_cmpc(h->name, "Empty-Value-Header") != 0) { - printf("Header %i incorrect name\n", count + 1); - return -1; - } - if (bstr_cmpc(h->value, "") != 0) { - printf("Header %i incorrect value\n", count + 1); - return -1; - } - break; - case 6: - if (bstr_cmpc(h->name, "") != 0) { - printf("Header %i incorrect name\n", count + 1); - return -1; - } - if (bstr_cmpc(h->value, "8, ") != 0) { - printf("Header %i incorrect value\n", count + 1); - return -1; - } - break; - case 7: - if (bstr_cmpc(h->name, "Header-With-LWS-After") != 0) { - printf("Header %i incorrect name\n", count + 1); - return -1; - } - if (bstr_cmpc(h->value, "9") != 0) { - printf("Header %i incorrect value\n", count + 1); - return -1; - } - break; - case 8: - { - bstr *b = bstr_memdup("BEFORE", 6); - if (bstr_cmpc(h->name, "Header-With-NUL") != 0) { - printf("Header %i incorrect name\n", count + 1); - bstr_free(b); - return -1; - } - if (bstr_cmp(h->value, b) != 0) { - printf("Header %i incorrect value\n", count + 1); - bstr_free(b); - return -1; - } - bstr_free(b); - } - break; - } - - count++; - } - - htp_connp_destroy_all(connp); - - return 1; -} - -/** - * - */ -int test_expect(htp_cfg_t *cfg) { - htp_connp_t *connp = NULL; - - int rc = test_run(home, "05-expect.t", cfg, &connp); - if (rc < 0) { - if (connp != NULL) htp_connp_destroy_all(connp); - return -1; - } - - htp_connp_destroy_all(connp); - - return 1; -} - -/** - * - */ -int test_uri_normal(htp_cfg_t *cfg) { - htp_connp_t *connp = NULL; - - int rc = test_run(home, "06-uri-normal.t", cfg, &connp); - if (rc < 0) { - if (connp != NULL) htp_connp_destroy_all(connp); - return -1; - } - - htp_connp_destroy_all(connp); - - return 1; -} - -/** - * - */ -int test_pipelined_connection(htp_cfg_t *cfg) { - htp_connp_t *connp = NULL; - - int rc = test_run(home, "07-pipelined-connection.t", cfg, &connp); - if (rc < 0) { - if (connp != NULL) htp_connp_destroy_all(connp); - return -1; - } - - if (list_size(connp->conn->transactions) != 2) { - printf("Expected 2 transactions but found %i.", list_size(connp->conn->transactions)); - return -1; - } - - if (!(connp->conn->flags & PIPELINED_CONNECTION)) { - printf("The pipelined flag not set on a pipelined connection."); - return -1; - } - - htp_connp_destroy_all(connp); - - return 1; -} - -/** - * - */ -int test_not_pipelined_connection(htp_cfg_t *cfg) { - htp_connp_t *connp = NULL; - - int rc = test_run(home, "08-not-pipelined-connection.t", cfg, &connp); - if (rc < 0) { - if (connp != NULL) htp_connp_destroy_all(connp); - return -1; - } - - if (list_size(connp->conn->transactions) != 2) { - printf("Expected 2 transactions but found %i.", list_size(connp->conn->transactions)); - return -1; - } - - if (connp->conn->flags & PIPELINED_CONNECTION) { - printf("The pipelined flag set on a connection that is not pipelined."); - return -1; - } - - htp_tx_t *tx = list_get(connp->conn->transactions, 0); - - if (tx->flags & HTP_MULTI_PACKET_HEAD) { - printf("The HTP_MULTI_PACKET_HEAD flag set on a single-packet transaction."); - return -1; - } - - htp_connp_destroy_all(connp); - - return 1; -} - -/** - * - */ -int test_multi_packet_request_head(htp_cfg_t *cfg) { - htp_connp_t *connp = NULL; - - int rc = test_run(home, "09-multi-packet-request-head.t", cfg, &connp); - if (rc < 0) { - if (connp != NULL) htp_connp_destroy_all(connp); - return -1; - } - - if (list_size(connp->conn->transactions) != 1) { - printf("Expected 1 transaction but found %i.", list_size(connp->conn->transactions)); - return -1; - } - - htp_tx_t *tx = list_get(connp->conn->transactions, 0); - - if (!(tx->flags & HTP_MULTI_PACKET_HEAD)) { - printf("The HTP_MULTI_PACKET_HEAD flag is not set on a multipacket transaction."); - return -1; - } - - htp_connp_destroy_all(connp); - - return 1; -} - -int test_misc(htp_cfg_t *cfg) { - htp_connp_t *connp = NULL; - - int rc = test_run(home, "misc.t", cfg, &connp); - if (rc < 0) { - if (connp != NULL) htp_connp_destroy_all(connp); - return -1; - } - - if (list_size(connp->conn->transactions) == 0) { - printf("Expected at least one transaction"); - return -1; - } - - htp_tx_t *tx = list_get(connp->conn->transactions, 0); - - printf("Parsed URI: %s\n", bstr_tocstr(tx->parsed_uri_incomplete->path)); - - htp_connp_destroy_all(connp); - - return 1; -} - -/** - * - */ -int test_host_in_headers(htp_cfg_t *cfg) { - htp_connp_t *connp = NULL; - - int rc = test_run(home, "10-host-in-headers.t", cfg, &connp); - if (rc < 0) { - if (connp != NULL) htp_connp_destroy_all(connp); - return -1; - } - - if (list_size(connp->conn->transactions) != 4) { - printf("Expected 4 transactions but found %i.", list_size(connp->conn->transactions)); - return -1; - } - - htp_tx_t *tx1 = list_get(connp->conn->transactions, 0); - htp_tx_t *tx2 = list_get(connp->conn->transactions, 1); - htp_tx_t *tx3 = list_get(connp->conn->transactions, 2); - htp_tx_t *tx4 = list_get(connp->conn->transactions, 3); - - if ((tx1->parsed_uri->hostname == NULL) || (bstr_cmpc(tx1->parsed_uri->hostname, "www.example.com") != 0)) { - printf("1) Expected 'www.example.com' as hostname, but got: %s", tx1->parsed_uri->hostname); - return -1; - } - - if ((tx2->parsed_uri->hostname == NULL) || (bstr_cmpc(tx2->parsed_uri->hostname, "www.example.com") != 0)) { - printf("2) Expected 'www.example.com' as hostname, but got: %s", tx2->parsed_uri->hostname); - return -1; - } - - if ((tx3->parsed_uri->hostname == NULL) || (bstr_cmpc(tx3->parsed_uri->hostname, "www.example.com") != 0)) { - printf("3) Expected 'www.example.com' as hostname, but got: %s", tx3->parsed_uri->hostname); - return -1; - } - - if ((tx4->parsed_uri->hostname == NULL) || (bstr_cmpc(tx4->parsed_uri->hostname, "www.example.com") != 0)) { - printf("4) Expected 'www.example.com' as hostname, but got: %s", tx4->parsed_uri->hostname); - return -1; - } - - htp_connp_destroy_all(connp); - - return 1; -} - -int test_response_stream_closure(htp_cfg_t *cfg) { - htp_connp_t *connp = NULL; - - int rc = test_run(home, "11-response-stream-closure.t", cfg, &connp); - if (rc < 0) { - if (connp != NULL) htp_connp_destroy_all(connp); - return -1; - } - - if (list_size(connp->conn->transactions) == 0) { - printf("Expected at least one transaction"); - return -1; - } - - htp_tx_t *tx = list_get(connp->conn->transactions, 0); - - if (tx->progress != TX_PROGRESS_DONE) { - printf("Expected the only transaction to be complete (but got %i).", tx->progress); - return -1; - } - - htp_connp_destroy_all(connp); - - return 1; -} - -int test_connect(htp_cfg_t *cfg) { - htp_connp_t *connp = NULL; - - int rc = test_run(home, "12-connect-request.t", cfg, &connp); - if (rc < 0) { - if (connp != NULL) htp_connp_destroy_all(connp); - return -1; - } - - if (list_size(connp->conn->transactions) == 0) { - printf("Expected at least one transaction"); - return -1; - } - - htp_tx_t *tx = list_get(connp->conn->transactions, 0); - - if (tx->progress != TX_PROGRESS_DONE) { - printf("Expected the only transaction to be complete (but got %i).", tx->progress); - return -1; - } - - //printf("Parsed URI: %x\n", tx->parsed_uri); - // printf("Server: %s\n", bstr_len(tx->parsed_uri->hostname), bstr_ptr(tx->parsed_uri->hostname)); - //printf("Port: %s\n", bstr_ptr(tx->parsed_uri->port)); - - htp_connp_destroy_all(connp); - - return 1; -} - -int test_connect_complete(htp_cfg_t *cfg) { - htp_connp_t *connp = NULL; - - int rc = test_run(home, "15-connect-complete.t", cfg, &connp); - if (rc < 0) { - if (connp != NULL) htp_connp_destroy_all(connp); - return -1; - } - - if (list_size(connp->conn->transactions) == 0) { - printf("Expected at least one transaction"); - return -1; - } - - htp_tx_t *tx = list_get(connp->conn->transactions, 0); - - if (tx->progress != TX_PROGRESS_DONE) { - printf("Expected the only transaction to be complete (but got %i).", tx->progress); - return -1; - } - - htp_connp_destroy_all(connp); - - return 1; -} - -int test_connect_extra(htp_cfg_t *cfg) { - htp_connp_t *connp = NULL; - - int rc = test_run(home, "16-connect-extra.t", cfg, &connp); - if (rc < 0) { - if (connp != NULL) htp_connp_destroy_all(connp); - return -1; - } - - if (list_size(connp->conn->transactions) == 0) { - printf("Expected at least one transaction"); - return -1; - } - - htp_tx_t *tx = list_get(connp->conn->transactions, 0); - - if (tx->progress != TX_PROGRESS_DONE) { - printf("Expected the only transaction to be complete (but got %i).", tx->progress); - return -1; - } - - htp_connp_destroy_all(connp); - - return 1; -} - -int test_compressed_response_gzip_ct(htp_cfg_t *cfg) { - htp_connp_t *connp = NULL; - - int rc = test_run(home, "13-compressed-response-gzip-ct.t", cfg, &connp); - if (rc < 0) { - if (connp != NULL) htp_connp_destroy_all(connp); - return -1; - } - - if (list_size(connp->conn->transactions) == 0) { - printf("Expected at least one transaction"); - return -1; - } - - htp_tx_t *tx = list_get(connp->conn->transactions, 0); - - if (tx->progress != TX_PROGRESS_DONE) { - printf("Expected the only transaction to be complete (but got %i).", tx->progress); - return -1; - } - - htp_connp_destroy_all(connp); - - return 1; -} - -int test_compressed_response_gzip_chunked(htp_cfg_t *cfg) { - htp_connp_t *connp = NULL; - - int rc = test_run(home, "14-compressed-response-gzip-chunked.t", cfg, &connp); - if (rc < 0) { - if (connp != NULL) htp_connp_destroy_all(connp); - return -1; - } - - if (list_size(connp->conn->transactions) == 0) { - printf("Expected at least one transaction"); - return -1; - } - - htp_tx_t *tx = list_get(connp->conn->transactions, 0); - - if (tx->progress != TX_PROGRESS_DONE) { - printf("Expected the only transaction to be complete (but got %i).", tx->progress); - return -1; - } - - htp_connp_destroy_all(connp); - - return 1; -} - -int callback_transaction_start(htp_connp_t *connp) { - printf("-- Callback: transaction_start\n"); - return HOOK_OK; -} - -int callback_request_line(htp_connp_t *connp) { - printf("-- Callback: request_line\n"); - return HOOK_OK; -} - -int callback_request_headers(htp_connp_t *connp) { - printf("-- Callback: request_headers\n"); - return HOOK_OK; -} - -int callback_request_body_data(htp_tx_data_t *d) { - printf("-- Callback: request_body_data\n"); - fprint_raw_data(stdout, __FUNCTION__, d->data, d->len); - return HOOK_OK; -} - -int callback_request_trailer(htp_connp_t *connp) { - printf("-- Callback: request_trailer\n"); - return HOOK_OK; -} - -int callback_request(htp_connp_t *connp) { - printf("-- Callback: request\n"); - return HOOK_OK; -} - -int callback_response_line(htp_connp_t *connp) { - printf("-- Callback: response_line\n"); - return HOOK_OK; -} - -int callback_response_headers(htp_connp_t *connp) { - printf("-- Callback: response_headers\n"); - return HOOK_OK; -} - -int callback_response_body_data(htp_tx_data_t *d) { - printf("-- Callback: response_body_data\n"); - fprint_raw_data(stdout, __FUNCTION__, d->data, d->len); - return HOOK_OK; -} - -int callback_response_trailer(htp_connp_t *connp) { - printf("-- Callback: response_trailer\n"); - return HOOK_OK; -} - -int callback_response(htp_connp_t *connp) { - printf("-- Callback: response\n"); - return HOOK_OK; -} - -int callback_response_destroy(htp_connp_t *connp) { - htp_tx_destroy(connp->out_tx); - printf("-- Destroyed transaction\n"); - return HOOK_OK; -} - -int callback_log(htp_log_t *log) { - htp_print_log(stdout, log); - return HOOK_OK; -} - -static void print_tx(htp_connp_t *connp, htp_tx_t *tx) { - char *request_line = bstr_tocstr(tx->request_line); - htp_header_t *h_user_agent = table_getc(tx->request_headers, "user-agent"); - htp_header_t *h_referer = table_getc(tx->request_headers, "referer"); - char *referer, *user_agent; - char buf[256]; - - time_t t = time(NULL); - struct tm *tmp = localtime(&t); - - strftime(buf, 255, "%d/%b/%Y:%T %z", tmp); - - if (h_user_agent == NULL) user_agent = strdup("-"); - else { - user_agent = bstr_tocstr(h_user_agent->value); - } - - if (h_referer == NULL) referer = strdup("-"); - else { - referer = bstr_tocstr(h_referer->value); - } - - printf("%s - - [%s] \"%s\" %i %i \"%s\" \"%s\"\n", connp->conn->remote_addr, buf, - request_line, tx->response_status_number, tx->response_message_len, - referer, user_agent); - - free(referer); - free(user_agent); - free(request_line); -} - -static int run_directory(char *dirname, htp_cfg_t *cfg) { - struct dirent *entry; - char buf[1025]; - DIR *d = opendir(dirname); - htp_connp_t *connp; - - if (d == NULL) { - printf("Failed to open directory: %s\n", dirname); - return -1; - } - - while ((entry = readdir(d)) != NULL) { - if (strncmp(entry->d_name, "stream", 6) == 0) { - int rc = test_run(dirname, entry->d_name, cfg, &connp); - - if (rc < 0) { - if (connp != NULL) { - htp_log_t *last_error = htp_connp_get_last_error(connp); - if (last_error != NULL) { - printf(" -- failed: %s\n", last_error->msg); - } else { - printf(" -- failed: ERROR NOT AVAILABLE\n"); - } - - return 0; - } else { - return -1; - } - } else { - printf(" -- %i transaction(s)\n", list_size(connp->conn->transactions)); - - htp_tx_t *tx = NULL; - list_iterator_reset(connp->conn->transactions); - while ((tx = list_iterator_next(connp->conn->transactions)) != NULL) { - printf(" "); - print_tx(connp, tx); - } - - printf("\n"); - - htp_connp_destroy_all(connp); - } - } - } - - closedir(d); - - return 1; -} - -int main_dir(int argc, char** argv) { - htp_cfg_t *cfg = htp_config_create(); - htp_config_register_log(cfg, callback_log); - htp_config_register_response(cfg, callback_response_destroy); - - run_directory("C:\\http_traces\\run5", cfg); - //run_directory("/home/ivanr/work/traces/run3/", cfg); - - htp_config_destroy(cfg); - return (EXIT_SUCCESS); -} - -#define RUN_TEST(X, Y) \ - {\ - tests++; \ - printf("---------------------------------\n"); \ - printf("Test: " #X "\n"); \ - int rc = X(Y); \ - if (rc < 0) { \ - printf(" Failed with %i\n", rc); \ - failures++; \ - } \ - printf("\n"); \ - } - -/** - * Entry point; runs a bunch of tests and exits. - */ -int main(int argc, char** argv) { - char buf[1025]; - int tests = 0, failures = 0; - - home = NULL; - - // Try the current working directory first - int fd = open("./files/anchor.empty", 0, O_RDONLY); - if (fd != -1) { - close(fd); - home = "./files"; - } else { - // Try the directory in which the executable resides - strncpy(buf, argv[0], 1024); - strncat(buf, "/../files/anchor.empty", 1024 - strlen(buf)); - fd = open(buf, 0, O_RDONLY); - if (fd != -1) { - close(fd); - strncpy(buf, argv[0], 1024); - strncat(buf, "/../files", 1024 - strlen(buf)); - home = buf; - } else { - // Try the directory in which the executable resides - strncpy(buf, argv[0], 1024); - strncat(buf, "/../../files/anchor.empty", 1024 - strlen(buf)); - fd = open(buf, 0, O_RDONLY); - if (fd != -1) { - close(fd); - strncpy(buf, argv[0], 1024); - strncat(buf, "/../../files", 1024 - strlen(buf)); - home = buf; - } - } - } - - if (home == NULL) { - printf("Failed to find test files."); - exit(-1); - } - - htp_cfg_t *cfg = htp_config_create(); - //htp_config_set_server_personality(cfg, HTP_SERVER_GENERIC); - htp_config_set_server_personality(cfg, HTP_SERVER_APACHE_2_2); - - // Register hooks - htp_config_register_transaction_start(cfg, callback_transaction_start); - - htp_config_register_request_line(cfg, callback_request_line); - htp_config_register_request_headers(cfg, callback_request_headers); - htp_config_register_request_body_data(cfg, callback_request_body_data); - htp_config_register_request_trailer(cfg, callback_request_trailer); - htp_config_register_request(cfg, callback_request); - - htp_config_register_response_line(cfg, callback_response_line); - htp_config_register_response_headers(cfg, callback_response_headers); - htp_config_register_response_body_data(cfg, callback_response_body_data); - htp_config_register_response_trailer(cfg, callback_response_trailer); - htp_config_register_response(cfg, callback_response); - - htp_config_register_log(cfg, callback_log); - - htp_config_set_generate_request_uri_normalized(cfg, 1); - - RUN_TEST(test_get, cfg); - //RUN_TEST(test_apache_header_parsing, cfg); - //RUN_TEST(test_post_urlencoded, cfg); - //RUN_TEST(test_post_urlencoded_chunked, cfg); - //RUN_TEST(test_expect, cfg); - //RUN_TEST(test_uri_normal, cfg); - //RUN_TEST(test_pipelined_connection, cfg); - //RUN_TEST(test_not_pipelined_connection, cfg); - //RUN_TEST(test_multi_packet_request_head, cfg); - //RUN_TEST(test_response_stream_closure, cfg); - //RUN_TEST(test_host_in_headers, cfg); - //RUN_TEST(test_compressed_response_gzip_ct, cfg); - //RUN_TEST(test_compressed_response_gzip_chunked, cfg); - - //RUN_TEST(test_connect, cfg); - //RUN_TEST(test_connect_complete, cfg); - //RUN_TEST(test_connect_extra, cfg); - - //RUN_TEST(test_misc, cfg); - //RUN_TEST(test_post_urlencoded_chunked, cfg); - - printf("Tests: %i\n", tests); - printf("Failures: %i\n", failures); - - htp_config_destroy(cfg); - - return (EXIT_SUCCESS); -} - -int main_path_decoding_tests(int argc, char** argv) { - htp_cfg_t *cfg = htp_config_create(); - htp_tx_t *tx = htp_tx_create(cfg, 0, NULL); - - bstr *path = NULL; - - // - path = bstr_cstrdup("/One\\two///ThRee%2ffive%5csix/se%xxven"); - cfg->path_case_insensitive = 1; - - printf("Before: %s\n", bstr_tocstr(path)); - htp_decode_path_inplace(cfg, tx, path); - printf("After: %s\n\n", bstr_tocstr(path)); - - // - path = bstr_cstrdup("/One\\two///ThRee%2ffive%5csix/se%xxven"); - cfg->path_case_insensitive = 1; - cfg->path_compress_separators = 1; - - printf("Before: %s\n", bstr_tocstr(path)); - htp_decode_path_inplace(cfg, tx, path); - printf("After: %s\n\n", bstr_tocstr(path)); - - // - path = bstr_cstrdup("/One\\two///ThRee%2ffive%5csix/se%xxven"); - cfg->path_case_insensitive = 1; - cfg->path_compress_separators = 1; - cfg->path_backslash_separators = 1; - - printf("Before: %s\n", bstr_tocstr(path)); - htp_decode_path_inplace(cfg, tx, path); - printf("After: %s\n\n", bstr_tocstr(path)); - - // - path = bstr_cstrdup("/One\\two///ThRee%2ffive%5csix/se%xxven"); - cfg->path_case_insensitive = 1; - cfg->path_compress_separators = 1; - cfg->path_backslash_separators = 1; - cfg->path_decode_separators = 1; - - printf("Before: %s\n", bstr_tocstr(path)); - htp_decode_path_inplace(cfg, tx, path); - printf("After: %s\n\n", bstr_tocstr(path)); - - // - path = bstr_cstrdup("/One\\two///ThRee%2ffive%5csix/se%xxven"); - cfg->path_case_insensitive = 1; - cfg->path_compress_separators = 1; - cfg->path_backslash_separators = 1; - cfg->path_decode_separators = 1; - cfg->path_invalid_encoding_handling = URL_DECODER_REMOVE_PERCENT; - - printf("Before: %s\n", bstr_tocstr(path)); - htp_decode_path_inplace(cfg, tx, path); - printf("After: %s\n\n", bstr_tocstr(path)); - - // - path = bstr_cstrdup("/One\\two///ThRee%2ffive%5csix/se%xxven/%u0074"); - cfg->path_case_insensitive = 1; - cfg->path_compress_separators = 1; - cfg->path_backslash_separators = 1; - cfg->path_decode_separators = 1; - cfg->path_invalid_encoding_handling = URL_DECODER_DECODE_INVALID; - - printf("Before: %s\n", bstr_tocstr(path)); - htp_decode_path_inplace(cfg, tx, path); - printf("After: %s\n\n", bstr_tocstr(path)); - - // - path = bstr_cstrdup("/One\\two///ThRee%2ffive%5csix/se%xxven/%u0074%u0100"); - cfg->path_case_insensitive = 1; - cfg->path_compress_separators = 1; - cfg->path_backslash_separators = 1; - cfg->path_decode_separators = 1; - cfg->path_invalid_encoding_handling = URL_DECODER_PRESERVE_PERCENT; - cfg->path_decode_u_encoding = 1; - - printf("Before: %s\n", bstr_tocstr(path)); - htp_decode_path_inplace(cfg, tx, path); - printf("After: %s\n\n", bstr_tocstr(path)); - - return (EXIT_SUCCESS); -} - -void encode_utf8_2(uint8_t *data, uint32_t i) { - i = i & 0x7ff; - data[0] = 0xc0 + (i >> 6); - data[1] = 0x80 + (i & 0x3f); -} - -void encode_utf8_3(uint8_t *data, uint32_t i) { - i = i & 0xffff; - data[0] = 0xe0 + (i >> 12); - data[1] = 0x80 + ((i >> 6) & 0x3f); - data[2] = 0x80 + (i & 0x3f); -} - -void encode_utf8_4(uint8_t *data, uint32_t i) { - i = i & 0x10ffff; - data[0] = 0xf0 + (i >> 18); - data[1] = 0x80 + ((i >> 12) & 0x3f); - data[2] = 0x80 + ((i >> 6) & 0x3f); - data[3] = 0x80 + (i & 0x3f); -} - -int main_utf8_decoder_tests(int argc, char** argv) { - htp_cfg_t *cfg = htp_config_create(); - htp_tx_t *tx = htp_tx_create(cfg, 0, NULL); - - bstr *path = NULL; - - path = bstr_cstrdup("//////////"); - uint8_t *data = bstr_ptr(path); - - int i = 0; - - for (i = 0; i < 0x80; i++) { - memset(data, 0x2f, 10); - tx->flags = 0; - encode_utf8_2(data, i); - htp_utf8_validate_path(tx, path); - if (tx->flags != HTP_PATH_UTF8_OVERLONG) { - printf("#2 i %i data %x %x flags %x\n", i, (uint8_t) data[0], (uint8_t) data[1], tx->flags); - } - } - - for (i = 0; i < 0x800; i++) { - memset(data, 0x2f, 10); - tx->flags = 0; - encode_utf8_3(data, i); - htp_utf8_validate_path(tx, path); - if (tx->flags != HTP_PATH_UTF8_OVERLONG) { - printf("#3 i %x data %x %x %x flags %x\n", i, (uint8_t) data[0], (uint8_t) data[1], (uint8_t) data[2], tx->flags); - } - } - - for (i = 0; i < 0x10000; i++) { - memset(data, 0x2f, 10); - tx->flags = 0; - encode_utf8_4(data, i); - htp_utf8_validate_path(tx, path); - if ((i >= 0xff00) && (i <= 0xffff)) { - if (tx->flags != (HTP_PATH_UTF8_OVERLONG | HTP_PATH_FULLWIDTH_EVASION)) { - printf("#4 i %x data %x %x %x %x flags %x\n", i, (uint8_t) data[0], (uint8_t) data[1], (uint8_t) data[2], (uint8_t) data[3], tx->flags); - } - } else { - if (tx->flags != HTP_PATH_UTF8_OVERLONG) { - printf("#4 i %x data %x %x %x %x flags %x\n", i, (uint8_t) data[0], (uint8_t) data[1], (uint8_t) data[2], (uint8_t) data[3], tx->flags); - } - } - } - return (EXIT_SUCCESS); -} - -#define PATH_DECODE_TEST_BEFORE(NAME) \ - test_name = NAME; \ - tests++; \ - expected_status = 0; \ - expected_flags = -1; \ - success = 0; \ - cfg = htp_config_create(); \ - tx = htp_tx_create(cfg, 0, NULL); - -#define PATH_DECODE_TEST_AFTER() \ - htp_decode_path_inplace(cfg, tx, input); \ - htp_utf8_decode_path_inplace(cfg, tx, input); \ - if (bstr_cmp(input, expected) == 0) success = 1; \ - printf("[%2i] %s: %s\n", tests, (success == 1 ? "SUCCESS" : "FAILURE"), test_name); \ - if ((success == 0)||((expected_status != 0)&&(expected_status != tx->response_status_expected_number))) { \ - char *s1 = bstr_tocstr(input); \ - char *s2 = bstr_tocstr(expected); \ - printf(" Output: [%s]\n", s1); \ - printf(" Expected: [%s]\n", s2); \ - if (expected_status != 0) { \ - printf(" Expected status %i; got %i\n", expected_status, tx->response_status_expected_number); \ - } \ - if (expected_flags != -1) { \ - printf(" Expected flags 0x%x; got 0x%x\n", expected_flags, tx->flags); \ - } \ - free(s2); \ - free(s1); \ - failures++; \ - } \ - htp_tx_destroy(tx); \ - htp_config_destroy(cfg); \ - bstr_free(expected); \ - bstr_free(input); - - -int main_path_tests(int argc, char** argv) { - htp_cfg_t *cfg = NULL; - htp_tx_t *tx = NULL; - bstr *input = NULL; - bstr *expected = NULL; - int success = 0; - int tests = 0; - int failures = 0; - int expected_status = 0; - int expected_flags = 0; - char *test_name = NULL; - - PATH_DECODE_TEST_BEFORE("URL-decoding"); - input = bstr_cstrdup("/%64est"); - expected = bstr_cstrdup("/dest"); - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("Invalid URL-encoded, preserve %"); - input = bstr_cstrdup("/%xxest"); - expected = bstr_cstrdup("/%xxest"); - expected_flags = HTP_PATH_INVALID_ENCODING; - cfg->path_invalid_encoding_handling = URL_DECODER_PRESERVE_PERCENT; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("Invalid URL-encoded, remove %"); - input = bstr_cstrdup("/%xxest"); - expected = bstr_cstrdup("/xxest"); - expected_flags = HTP_PATH_INVALID_ENCODING; - cfg->path_invalid_encoding_handling = URL_DECODER_REMOVE_PERCENT; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("Invalid URL-encoded (end of string, test 1), preserve %"); - input = bstr_cstrdup("/test/%2"); - expected = bstr_cstrdup("/test/%2"); - expected_flags = HTP_PATH_INVALID_ENCODING; - cfg->path_invalid_encoding_handling = URL_DECODER_PRESERVE_PERCENT; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("Invalid URL-encoded (end of string, test 2), preserve %"); - input = bstr_cstrdup("/test/%"); - expected = bstr_cstrdup("/test/%"); - expected_flags = HTP_PATH_INVALID_ENCODING; - cfg->path_invalid_encoding_handling = URL_DECODER_PRESERVE_PERCENT; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("Invalid URL-encoded, preserve % and 400"); - input = bstr_cstrdup("/%xxest"); - expected = bstr_cstrdup("/%xxest"); - expected_status = 400; - expected_flags = HTP_PATH_INVALID_ENCODING; - cfg->path_invalid_encoding_handling = URL_DECODER_STATUS_400; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("%u decoding (expected not to decode; 400)"); - input = bstr_cstrdup("/%u0064"); - expected = bstr_cstrdup("/%u0064"); - expected_flags = HTP_PATH_INVALID_ENCODING; - expected_status = 400; - cfg->path_invalid_encoding_handling = URL_DECODER_STATUS_400; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("%u decoding (decode; 400)"); - input = bstr_cstrdup("/%u0064"); - expected = bstr_cstrdup("/d"); - expected_status = 400; - expected_flags = HTP_PATH_OVERLONG_U; - cfg->path_decode_u_encoding = STATUS_400; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("%u decoding (also overlong)"); - input = bstr_cstrdup("/%u0064"); - expected = bstr_cstrdup("/d"); - expected_flags = HTP_PATH_OVERLONG_U; - cfg->path_decode_u_encoding = YES; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("Invalid %u decoding, leave; preserve percent"); - input = bstr_cstrdup("/%uXXXX---"); - expected = bstr_cstrdup("/%uXXXX---"); - expected_flags = HTP_PATH_INVALID_ENCODING; - cfg->path_decode_u_encoding = YES; - cfg->path_invalid_encoding_handling = URL_DECODER_PRESERVE_PERCENT; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("Invalid %u decoding, decode invalid; preserve percent"); - input = bstr_cstrdup("/%uXXXX---"); - expected = bstr_cstrdup("/?---"); - expected_flags = HTP_PATH_INVALID_ENCODING; - cfg->path_decode_u_encoding = YES; - cfg->path_invalid_encoding_handling = URL_DECODER_DECODE_INVALID; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("Invalid %u decoding, decode invalid; preserve percent; 400"); - input = bstr_cstrdup("/%uXXXX---"); - expected = bstr_cstrdup("/?---"); - expected_flags = HTP_PATH_INVALID_ENCODING; - expected_status = 400; - cfg->path_decode_u_encoding = YES; - cfg->path_invalid_encoding_handling = URL_DECODER_STATUS_400; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("Invalid %u decoding (not enough data 1), preserve percent"); - input = bstr_cstrdup("/%u123"); - expected = bstr_cstrdup("/%u123"); - expected_flags = HTP_PATH_INVALID_ENCODING; - cfg->path_decode_u_encoding = YES; - cfg->path_invalid_encoding_handling = URL_DECODER_PRESERVE_PERCENT; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("Invalid %u decoding (not enough data 2), preserve percent"); - input = bstr_cstrdup("/%u12"); - expected = bstr_cstrdup("/%u12"); - expected_flags = HTP_PATH_INVALID_ENCODING; - cfg->path_decode_u_encoding = YES; - cfg->path_invalid_encoding_handling = URL_DECODER_PRESERVE_PERCENT; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("Invalid %u decoding (not enough data 3), preserve percent"); - input = bstr_cstrdup("/%u1"); - expected = bstr_cstrdup("/%u1"); - expected_flags = HTP_PATH_INVALID_ENCODING; - cfg->path_decode_u_encoding = YES; - cfg->path_invalid_encoding_handling = URL_DECODER_PRESERVE_PERCENT; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("%u decoding, best-fit mapping"); - input = bstr_cstrdup("/%u0107"); - expected = bstr_cstrdup("/c"); - cfg->path_decode_u_encoding = YES; - cfg->path_unicode_mapping = BESTFIT; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("%u decoding, 404 to UCS-2 characters"); - input = bstr_cstrdup("/%u0107"); - expected = bstr_cstrdup("/c"); - expected_status = 404; - cfg->path_decode_u_encoding = YES; - cfg->path_unicode_mapping = STATUS_404; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("Forward slash (URL-encoded), not expect to decode"); - input = bstr_cstrdup("/one%2ftwo"); - expected = bstr_cstrdup("/one%2ftwo"); - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("Forward slash (URL-encoded), expect to decode"); - input = bstr_cstrdup("/one%2ftwo"); - expected = bstr_cstrdup("/one/two"); - cfg->path_decode_separators = YES; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("Forward slash (URL-encoded), expect not do decode and 404"); - input = bstr_cstrdup("/one%2ftwo"); - expected = bstr_cstrdup("/one%2ftwo"); - expected_status = 404; - cfg->path_decode_separators = STATUS_404; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("Forward slash (%u-encoded), expect to decode"); - input = bstr_cstrdup("/one%u002ftwo"); - expected = bstr_cstrdup("/one/two"); - cfg->path_decode_separators = YES; - cfg->path_decode_u_encoding = YES; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("Forward slash (%u-encoded, fullwidth), expect to decode"); - input = bstr_cstrdup("/one%uff0ftwo"); - expected = bstr_cstrdup("/one/two"); - cfg->path_decode_separators = YES; - cfg->path_decode_u_encoding = YES; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("Backslash (URL-encoded), not a separator; expect to decode"); - input = bstr_cstrdup("/one%5ctwo"); - expected = bstr_cstrdup("/one\\two"); - cfg->path_decode_separators = YES; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("Backslash (URL-encoded), as path segment separator"); - input = bstr_cstrdup("/one%5ctwo"); - expected = bstr_cstrdup("/one/two"); - cfg->path_decode_separators = YES; - cfg->path_backslash_separators = 1; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("Backslash (not encoded), as path segment separator"); - input = bstr_cstrdup("/one\\two"); - expected = bstr_cstrdup("/one/two"); - cfg->path_backslash_separators = YES; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("Backslash (%u-encoded), as path segment separator"); - input = bstr_cstrdup("/one%u005ctwo"); - expected = bstr_cstrdup("/one/two"); - cfg->path_decode_separators = YES; - cfg->path_backslash_separators = YES; - cfg->path_decode_u_encoding = YES; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("Backslash (%u-encoded, fullwidth), as path segment separator"); - input = bstr_cstrdup("/one%uff3ctwo"); - expected = bstr_cstrdup("/one/two"); - cfg->path_decode_separators = YES; - cfg->path_backslash_separators = 1; - cfg->path_decode_u_encoding = YES; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("Invalid UTF-8 encoding, encoded"); - input = bstr_cstrdup("/%f7test"); - expected = bstr_cstrdup("/\xf7test"); - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("Invalid UTF-8 encoding, encoded (400)"); - input = bstr_cstrdup("/%f7test"); - expected = bstr_cstrdup("/\xf7test"); - expected_status = 400; - expected_flags = HTP_PATH_UTF8_INVALID; - cfg->path_invalid_utf8_handling = STATUS_400; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("NUL byte (raw) in path; leave"); - input = bstr_memdup("/test\0text", 10); - expected = bstr_memdup("/test\0text", 10); - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("NUL byte (raw) in path; terminate path"); - input = bstr_memdup("/test\0text", 10); - expected = bstr_cstrdup("/test"); - cfg->path_nul_raw_handling = TERMINATE; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("NUL byte (raw) in path; 400"); - input = bstr_memdup("/test\0text", 10); - expected = bstr_memdup("/test\0text", 10); - cfg->path_nul_raw_handling = STATUS_400; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("NUL byte (URL-encoded) in path; leave"); - input = bstr_cstrdup("/test%00text"); - expected = bstr_memdup("/test\0text", 10); - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("NUL byte (URL-encoded) in path; terminate path"); - input = bstr_cstrdup("/test%00text"); - expected = bstr_cstrdup("/test"); - cfg->path_nul_encoded_handling = TERMINATE; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("NUL byte (URL-encoded) in path; 400"); - input = bstr_cstrdup("/test%00text"); - expected = bstr_memdup("/test\0text", 10); - cfg->path_nul_encoded_handling = STATUS_400; - expected_status = 400; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("NUL byte (URL-encoded) in path; 404"); - input = bstr_cstrdup("/test%00text"); - expected = bstr_memdup("/test\0text", 10); - cfg->path_nul_encoded_handling = STATUS_404; - expected_status = 404; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("NUL byte (%u-encoded) in path; terminate path"); - input = bstr_cstrdup("/test%00text"); - expected = bstr_cstrdup("/test"); - cfg->path_nul_encoded_handling = TERMINATE; - cfg->path_decode_u_encoding = YES; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("NUL byte (%u-encoded) in path; 400"); - input = bstr_cstrdup("/test%00text"); - expected = bstr_memdup("/test\0text", 10); - cfg->path_nul_encoded_handling = STATUS_400; - cfg->path_decode_u_encoding = YES; - expected_status = 400; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("NUL byte (%u-encoded) in path; 404"); - input = bstr_cstrdup("/test%00text"); - expected = bstr_memdup("/test\0text", 10); - cfg->path_nul_encoded_handling = STATUS_404; - cfg->path_decode_u_encoding = YES; - expected_status = 404; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("Control char in path, encoded (no effect)"); - input = bstr_cstrdup("/%01test"); - expected = bstr_cstrdup("/\x01test"); - cfg->path_control_char_handling = NONE; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("Control char in path, raw (no effect)"); - input = bstr_cstrdup("/\x01test"); - expected = bstr_cstrdup("/\x01test"); - cfg->path_control_char_handling = NONE; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("Control char in path, encoded (400)"); - input = bstr_cstrdup("/%01test"); - expected = bstr_cstrdup("/\x01test"); - expected_status = 400; - cfg->path_control_char_handling = STATUS_400; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("Control char in path, raw (400)"); - input = bstr_cstrdup("/\x01test"); - expected = bstr_cstrdup("/\x01test"); - expected_status = 400; - cfg->path_control_char_handling = STATUS_400; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("UTF-8; overlong 2-byte sequence"); - input = bstr_cstrdup("/%c1%b4est"); - expected = bstr_cstrdup("/test"); - expected_flags = HTP_PATH_UTF8_OVERLONG; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("UTF-8; overlong 3-byte sequence"); - input = bstr_cstrdup("/%e0%81%b4est"); - expected = bstr_cstrdup("/test"); - expected_flags = HTP_PATH_UTF8_OVERLONG; - PATH_DECODE_TEST_AFTER(); - - PATH_DECODE_TEST_BEFORE("UTF-8; overlong 4-byte sequence"); - input = bstr_cstrdup("/%f0%80%81%b4est"); - expected = bstr_cstrdup("/test"); - expected_flags = HTP_PATH_UTF8_OVERLONG; - PATH_DECODE_TEST_AFTER(); - - printf("\n"); - printf("Total tests: %i, %i failure(s).\n", tests, failures); - - return (EXIT_SUCCESS); -} diff --git a/libhtp/test/test-tcpick.c b/libhtp/test/test-tcpick.c deleted file mode 100644 index f14312aa2a..0000000000 --- a/libhtp/test/test-tcpick.c +++ /dev/null @@ -1,335 +0,0 @@ -/* - * LibHTP (http://www.libhtp.org) - * Copyright 2009,2010 Ivan Ristic - * - * LibHTP is an open source product, released under terms of the General Public Licence - * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text - * of the license. - * - * In addition, there is a special exception that allows LibHTP to be freely - * used with any OSI-approved open source licence. Please refer to the file - * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. - * - */ - -#include -#include -#include -#include - -#include "../htp/htp.h" - -#define CLIENT 1 -#define SERVER 2 - -static int parse_filename(const char *filename, char **remote_addr, char **local_addr) { - char *copy = strdup(filename); - char *p, *saveptr; - - char *start = copy; - char *q = strrchr(copy, '/'); - if (q != NULL) start = q; - - q = strrchr(start, '\\'); - if (q != NULL) start = q; - - int count = 0; - p = strtok_r(start, "_", &saveptr); - while (p != NULL) { - count++; - // printf("%i %s\n", count, p); - - switch (count) { - case 3: - *remote_addr = strdup(p); - break; - case 4: - *local_addr = strdup(p); - break; - } - - p = strtok_r(NULL, "_", &saveptr); - } - - free(copy); - - return 0; -} - -static int parse_chunk_info(char *buf, size_t *response_offset, size_t *response_len) { - char *p = buf; - size_t lastlen; - - while ((*p != ']') && (p != '\0')) p++; - if (*p == '\0') return -1; - p++; - - while (isspace(*p)) p++; - - *response_offset = bstr_util_memtoip(p, strlen(p), 10, &lastlen); - - p += lastlen; - - while ((*p != '(') && (p != '\0')) p++; - if (*p == '\0') return -1; - p++; - - *response_len = bstr_util_memtoip(p, strlen(p), 10, &lastlen); - - return 1; -} - -static int tcpick_run_file(const char *filename, htp_cfg_t *cfg, htp_connp_t **connp) { - struct timeval tv; - char buf[1025]; - int first = -1, current = -1; - char *remote_addr, *local_addr; - - char *request_last_chunk = NULL; - char *response_last_chunk = NULL; - size_t request_offset, request_len; - size_t request_last_offset = 0, request_last_len = 0; - size_t response_offset, response_len; - size_t response_last_offset = 0, response_last_len = 0; - - if (parse_filename(filename, &remote_addr, &local_addr) < 0) { - printf("Failed to parse filename: %s\n", filename); - return -1; - } - - FILE *f = fopen(filename, "rb"); - if (f == NULL) { - printf("Unable to open file: %s\n", filename); - return -1; - } - - gettimeofday(&tv, NULL); - - // Create parser - *connp = htp_connp_create(cfg); - - // Find all chunks and feed them to the parser - while (fgets(buf, 1024, f) != NULL) { - // Ignore empty lines - if (buf[0] == LF) { - continue; - } - - if (strncmp(buf, "[server", 7) == 0) { - current = SERVER; - } else { - current = CLIENT; - } - - if (first == -1) { - first = current; - - if (first == SERVER) { - htp_connp_open(*connp, local_addr, 80, remote_addr, 80, tv.tv_usec); - } else { - htp_connp_open(*connp, remote_addr, 80, local_addr, 80, tv.tv_usec); - } - } - - int len = 0; - - if (first == current) { - if (parse_chunk_info(buf, &request_offset, &request_len) < 0) { - printf("Invalid line: %s", buf); - fclose(f); - htp_connp_destroy_all(*connp); - *connp = NULL; - return -1; - } - - len = request_len; - - // printf("# Request offset %i len %i\n", request_offset, request_len); - } else { - if (parse_chunk_info(buf, &response_offset, &response_len) < 0) { - printf("Invalid line: %s", buf); - fclose(f); - htp_connp_destroy_all(*connp); - *connp = NULL; - return -1; - } - - len = response_len; - - // printf("# Response offset %i len %i\n", response_offset, response_len); - } - - // printf("Len: %i\n", len); - - if (len <= 0) { - printf("Invalid length: %i\n", len); - fclose(f); - htp_connp_destroy_all(*connp); - *connp = NULL; - return -1; - } - - char *data = malloc(len); - if (data == NULL) { - printf("Failed to allocate %i bytes\n", len); - fclose(f); - htp_connp_destroy_all(*connp); - *connp = NULL; - return -1; - } - - int read = fread(data, 1, len, f); - if (read != len) { - // printf("Failed to read %i bytes (got %i)\n", len, read); - fclose(f); - htp_connp_destroy_all(*connp); - *connp = NULL; - return -1; - } - - if (first == current) { - if ((request_last_chunk == NULL) || (request_len != request_last_len) || (memcmp(data, request_last_chunk, request_len) != 0)) { - // printf("# Parse request data: %i byte(s)\n", len); - if (htp_connp_req_data(*connp, tv.tv_usec, data, len) == HTP_ERROR) { - fclose(f); - return -1; - } - } - - request_last_offset = request_offset; - request_last_len = request_len; - if (request_last_chunk != NULL) { - free(request_last_chunk); - } - request_last_chunk = data; - } else { - if ((response_last_chunk == NULL) || (response_len != response_last_len) || (memcmp(data, response_last_chunk, response_len) != 0)) { - // printf("# Parse response data: %i byte(s)\n", len); - if (htp_connp_res_data(*connp, tv.tv_usec, data, len) == HTP_ERROR) { - fclose(f); - return -1; - } - } - - response_last_offset = response_offset; - response_last_len = response_len; - if (response_last_chunk != NULL) { - free(response_last_chunk); - } - response_last_chunk = data; - } - } - - fclose(f); - - htp_connp_close(*connp, tv.tv_usec); - - return 1; -} - -static void print_tx(htp_connp_t *connp, htp_tx_t *tx) { - char *request_line = bstr_tocstr(tx->request_line); - htp_header_t *h_user_agent = table_getc(tx->request_headers, "user-agent"); - htp_header_t *h_referer = table_getc(tx->request_headers, "referer"); - char *referer, *user_agent; - char buf[256]; - - time_t t = time(NULL); - struct tm *tmp = localtime(&t); - - strftime(buf, 255, "%d/%b/%Y:%T %z", tmp); - - if (h_user_agent == NULL) user_agent = strdup("-"); - else { - user_agent = bstr_tocstr(h_user_agent->value); - } - - if (h_referer == NULL) referer = strdup("-"); - else { - referer = bstr_tocstr(h_referer->value); - } - - printf("%s - - [%s] \"%s\" %i %i \"%s\" \"%s\"\n", connp->conn->remote_addr, buf, - request_line, tx->response_status_number, tx->response_message_len, - referer, user_agent); - - free(referer); - free(user_agent); - free(request_line); -} - -static int run_file(char *filename, htp_cfg_t *cfg) { - htp_connp_t *connp; - - fprintf(stdout, "Running file %s", filename); - - int rc = tcpick_run_file(filename, cfg, &connp); - if (rc < 0) { - if (connp != NULL) { - htp_log_t *last_error = htp_connp_get_last_error(connp); - if (last_error != NULL) { - printf(" -- failed: %s\n", last_error->msg); - } else { - printf(" -- failed: ERROR NOT AVAILABLE\n"); - } - - return 0; - } else { - return -1; - } - } else { - printf(" -- %i transaction(s)\n", list_size(connp->conn->transactions)); - - htp_tx_t *tx = NULL; - list_iterator_reset(connp->conn->transactions); - while ((tx = list_iterator_next(connp->conn->transactions)) != NULL) { - printf(" "); - print_tx(connp, tx); - } - - printf("\n"); - - htp_connp_destroy_all(connp); - - return 1; - } -} - -static int run_directory(char *dirname, htp_cfg_t *cfg) { - struct dirent *entry; - char buf[1025]; - DIR *d = opendir(dirname); - - if (d == NULL) { - printf("Failed to open directory: %s\n", dirname); - return -1; - } - - while ((entry = readdir(d)) != NULL) { - if (strncmp(entry->d_name, "tcpick", 6) == 0) { - strncpy(buf, dirname, 1024); - strncat(buf, "/", 1024 - strlen(buf)); - strncat(buf, entry->d_name, 1024 - strlen(buf)); - - // fprintf(stderr, "Filename: %s\n", buf); - run_file(buf, cfg); - //if (run_file(buf, cfg) <= 0) { - // closedir(d); - // return 0; - //} - } - } - - closedir(d); - - return 1; -} - -int main_xxx(int argc, char** argv) { - htp_cfg_t *cfg = htp_config_create(); - - //run_file("c:/http_traces/run1//tcpick_000015_192.168.1.67_66.249.80.118_www.both.dat", cfg); - run_directory("c:/http_traces/run1/", cfg); - - return 0; -} diff --git a/libhtp/test/test.c b/libhtp/test/test.c deleted file mode 100644 index 16aeef39f9..0000000000 --- a/libhtp/test/test.c +++ /dev/null @@ -1,375 +0,0 @@ -/* - * LibHTP (http://www.libhtp.org) - * Copyright 2009,2010 Ivan Ristic - * - * LibHTP is an open source product, released under terms of the General Public Licence - * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text - * of the license. - * - * In addition, there is a special exception that allows LibHTP to be freely - * used with any OSI-approved open source licence. Please refer to the file - * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "../htp/htp.h" -#include "test.h" - -/** - * Destroys a test. - * - * @param test - */ -static void test_destroy(test_t *test) { - if (test->buf != NULL) { - free(test->buf); - test->buf = NULL; - } -} - -/** - * Checks if there's a chunk boundary at the given position. - * - * @param test - * @param pos - * @return Zero if there is no boundary, SERVER or CLIENT if a boundary - * was found, and a negative value on error (e.g., not enough data - * to determine if a boundary is present). - */ -static int test_is_boundary(test_t *test, int pos) { - // Check that there's enough room - if (pos + 3 >= test->len) return -1; - - if ((test->buf[pos] == '<') && (test->buf[pos + 1] == '<') && (test->buf[pos + 2] == '<')) { - if (test->buf[pos + 3] == '\n') { - return SERVER; - } - - if (test->buf[pos + 3] == '\r') { - if (pos + 4 >= test->len) return -1; - else if (test->buf[pos + 4] == '\n') { - return SERVER; - } - } - } - - if ((test->buf[pos] == '>') && (test->buf[pos + 1] == '>') && (test->buf[pos + 2] == '>')) { - if (test->buf[pos + 3] == '\n') { - return CLIENT; - } - - if (test->buf[pos + 3] == '\r') { - if (pos + 4 >= test->len) return -1; - else if (test->buf[pos + 4] == '\n') { - return CLIENT; - } - } - } - - return 0; -} - -/** - * Initializes test by loading the entire data file into a memory block. - * - * @param test - * @param filename - * @return Non-negative value on success, negative value on error. - */ -static int test_init(test_t *test, const char *filename) { - memset(test, 0, sizeof (test_t)); - - int fd = open(filename, O_RDONLY | O_BINARY); - if (fd < 0) return -1; - - struct stat buf; - if (fstat(fd, &buf) < 0) { - return -1; - } - - test->buf = malloc(buf.st_size); - test->len = 0; - test->pos = 0; - - int bytes_read = 0; - while ((bytes_read = read(fd, test->buf + test->len, buf.st_size - test->len)) > 0) { - test->len += bytes_read; - } - - if (test->len != buf.st_size) { - free(test->buf); - return -2; - } - - close(fd); - - return 1; -} - -void test_start(test_t *test) { - test->pos = 0; -} - -/** - * Finds the next data chunk in the given test. - * - * @param test - * @return One if a chunk is found or zero if there are no more chunks in the test. On - * success, test->chunk will point to the beginning of the chunk, while - * test->chunk_len will contain its length. - */ -static int test_next_chunk(test_t *test) { - if (test->pos >= test->len) { - return 0; - } - - test->chunk = NULL; - - while (test->pos < test->len) { - // Do we need to start another chunk? - if (test->chunk == NULL) { - // Are we at a boundary - test->chunk_direction = test_is_boundary(test, test->pos); - if (test->chunk_direction <= 0) { - // Error - return -1; - } - - // Move over the boundary - test->pos += 4; - if (test->buf[test->pos] == '\n') test->pos++; - - // Start new chunk - test->chunk = test->buf + test->pos; - test->chunk_offset = test->pos; - } - - // Are we at the end of a line? - if (test->buf[test->pos] == '\n') { - int r = test_is_boundary(test, test->pos + 1); - if ((r == CLIENT) || (r == SERVER)) { - // We got ourselves a chunk - test->chunk_len = test->pos - test->chunk_offset; - - // Remove one '\r' (in addition to the '\n' that we've already removed), - // which belongs to the next boundary - if ((test->chunk_len > 0) && (test->chunk[test->chunk_len - 1] == '\r')) { - test->chunk_len--; - } - - // Position at the next boundary line - test->pos++; - - return 1; - } - } - - test->pos++; - } - - - if (test->chunk != NULL) { - test->chunk_len = test->pos - test->chunk_offset; - return 1; - } - - return 0; -} - -static int parse_filename(const char *filename, char **remote_addr, int *remote_port, char **local_addr, int *local_port) { - char *copy = strdup(filename); - char *p, *saveptr; - - char *start = copy; - char *q = strrchr(copy, '/'); - if (q != NULL) start = q; - - q = strrchr(start, '\\'); - if (q != NULL) start = q; - - int count = 0; - p = strtok_r(start, "_", &saveptr); - while (p != NULL) { - count++; - // printf("%i %s\n", count, p); - - switch (count) { - case 2: - *remote_addr = strdup(p); - break; - case 3: - *remote_port = atoi(p); - break; - case 4: - *local_addr = strdup(p); - case 5: - *local_port = atoi(p); - break; - } - - p = strtok_r(NULL, "_", &saveptr); - } - - free(copy); - - return 0; -} - -/** - * Runs a single test. - * - * @param filename - * @param cfg - * @return A pointer to the instance of htp_connp_t created during - * the test, or NULL if the test failed for some reason. - */ -int test_run(const char *testsdir, const char *testname, htp_cfg_t *cfg, htp_connp_t **connp) { - char filename[1025]; - test_t test; - struct timeval tv_start, tv_end; - int rc; - - *connp = NULL; - - strncpy(filename, testsdir, 1024); - strncat(filename, "/", 1024 - strlen(filename)); - strncat(filename, testname, 1024 - strlen(filename)); - - printf("Filename: %s\n", filename); - - // Initinialize test - - rc = test_init(&test, filename); - if (rc < 0) { - return rc; - } - - gettimeofday(&tv_start, NULL); - - test_start(&test); - - // Create parser - *connp = htp_connp_create(cfg); - if (*connp == NULL) { - fprintf(stderr, "Failed to create connection parser\n"); - exit(1); - } - - htp_connp_set_user_data(*connp, (void *) 0x02); - - // Does the filename contain connection metdata? - if (strncmp(testname, "stream", 6) == 0) { - // It does; use it - char *remote_addr, *local_addr; - int remote_port, local_port; - - parse_filename(testname, &remote_addr, &remote_port, &local_addr, &local_port); - htp_connp_open(*connp, (const char *) remote_addr, remote_port, (const char *) local_addr, local_port, tv_start.tv_usec); - free(remote_addr); - free(local_addr); - } else { - // No connection metadata; provide some fake information instead - htp_connp_open(*connp, (const char *) "127.0.0.1", 10000, (const char *) "127.0.0.1", 80, tv_start.tv_usec); - } - - // Find all chunks and feed them to the parser - int in_data_other = 0; - char *in_data; - size_t in_data_len; - size_t in_data_offset; - - int out_data_other = 0; - char *out_data; - size_t out_data_len; - size_t out_data_offset; - - for (;;) { - if (test_next_chunk(&test) <= 0) { - break; - } - - if (test.chunk_direction == CLIENT) { - if (in_data_other) { - test_destroy(&test); - fprintf(stderr, "Unable to buffer more than one inbound chunk.\n"); - return -1; - } - - int rc = htp_connp_req_data(*connp, tv_start.tv_usec, test.chunk, test.chunk_len); - if (rc == STREAM_STATE_ERROR) { - test_destroy(&test); - return -101; - } - if (rc == STREAM_STATE_DATA_OTHER) { - // Parser needs to see the outbound stream in order to continue - // parsing the inbound stream. - in_data_other = 1; - in_data = test.chunk; - in_data_len = test.chunk_len; - in_data_offset = htp_connp_req_data_consumed(*connp); - } - } else { - if (out_data_other) { - int rc = htp_connp_res_data(*connp, tv_start.tv_usec, out_data + out_data_offset, out_data_len - out_data_offset); - if (rc == STREAM_STATE_ERROR) { - test_destroy(&test); - return -104; - } - out_data_other = 0; - } - - int rc = htp_connp_res_data(*connp, tv_start.tv_usec, test.chunk, test.chunk_len); - if (rc == STREAM_STATE_ERROR) { - test_destroy(&test); - return -102; - } - if (rc == STREAM_STATE_DATA_OTHER) { - // Parser needs to see the outbound stream in order to continue - // parsing the inbound stream. - out_data_other = 1; - out_data = test.chunk; - out_data_len = test.chunk_len; - out_data_offset = htp_connp_res_data_consumed(*connp); - // printf("# YYY out offset is %d\n", out_data_offset); - } - - if (in_data_other) { - int rc = htp_connp_req_data(*connp, tv_start.tv_usec, in_data + in_data_offset, in_data_len - in_data_offset); - if (rc == STREAM_STATE_ERROR) { - test_destroy(&test); - return -103; - } - in_data_other = 0; - } - } - } - - if (out_data_other) { - int rc = htp_connp_res_data(*connp, tv_start.tv_usec, out_data + out_data_offset, out_data_len - out_data_offset); - if (rc == STREAM_STATE_ERROR) { - test_destroy(&test); - return -104; - } - out_data_other = 0; - } - - gettimeofday(&tv_end, NULL); - - // Close the connection - htp_connp_close(*connp, tv_end.tv_usec); - - // printf("Parsing time: %i\n", tv_end.tv_usec - tv_start.tv_usec); - - // Clean up - test_destroy(&test); - - return 1; -} diff --git a/libhtp/test/test.h b/libhtp/test/test.h deleted file mode 100644 index f9621f4223..0000000000 --- a/libhtp/test/test.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * LibHTP (http://www.libhtp.org) - * Copyright 2009,2010 Ivan Ristic - * - * LibHTP is an open source product, released under terms of the General Public Licence - * version 2 (GPLv2). Please refer to the file LICENSE, which contains the complete text - * of the license. - * - * In addition, there is a special exception that allows LibHTP to be freely - * used with any OSI-approved open source licence. Please refer to the file - * LIBHTP_LICENSING_EXCEPTION for the full text of the exception. - * - */ - -#ifndef _TEST_H -#define _TEST_H - -#include -#include -#include -#include -#include - -#define UNKNOWN 0 -#define CLIENT 1 -#define SERVER 2 - -#ifndef O_BINARY -#define O_BINARY 0 -#endif - -typedef struct test_t test_t; - -struct test_t { - char *buf; - size_t pos; - size_t len; - - char *chunk; - size_t chunk_offset; - size_t chunk_len; - int chunk_direction; -}; - -int test_run(const char *testsdir, const char *testname, htp_cfg_t *cfg, htp_connp_t **connp); - -#endif /* _TEST_H */ -