pax_global_header00006660000000000000000000000064146167413770014532gustar00rootroot0000000000000052 comment=dd49e975a04a66c2a32e6d2fc7cd7ddf0cb9fe33 tinyproxy-1.11.2/000077500000000000000000000000001461674137700137015ustar00rootroot00000000000000tinyproxy-1.11.2/.github/000077500000000000000000000000001461674137700152415ustar00rootroot00000000000000tinyproxy-1.11.2/.github/ISSUE_TEMPLATE/000077500000000000000000000000001461674137700174245ustar00rootroot00000000000000tinyproxy-1.11.2/.github/ISSUE_TEMPLATE/new-issue--bug-report--question.md000066400000000000000000000012141461674137700257460ustar00rootroot00000000000000--- name: New Issue, Bug report, Question about: New Issue, Bug report, Question title: '' labels: '' assignees: '' --- # IMPORTANT NOTICE Before filing an issue here PLEASE keep in mind that **tinyproxy 1.10.0 and older are no longer supported**. Do not report issues with 1.10.0 or older, first try latest release 1.11.0, or even better, git master, and see whether the issue is already fixed. ## Tinyproxy version State the tinyproxy version you're using; whether git master or 1.11.0 stable. ## Issue Fill in your Issue text here. A good issue report is detailed and includes full error messages from tinyproxy's output, not "X doesn't work". tinyproxy-1.11.2/.github/workflows/000077500000000000000000000000001461674137700172765ustar00rootroot00000000000000tinyproxy-1.11.2/.github/workflows/main.yml000066400000000000000000000013771461674137700207550ustar00rootroot00000000000000name: CI on: push: branches: [ master ] pull_request: branches: [ master ] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - run: ./autogen.sh - run: ./configure - run: make - run: make test test-macos: runs-on: macos-latest steps: - uses: actions/checkout@v2 - run: brew install automake - run: ./autogen.sh - run: ./configure - run: make valgrind-test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - run: sudo apt update - run: sudo apt install --assume-yes valgrind - run: ./autogen.sh - run: ./configure --enable-debug --enable-transparent --enable-reverse - run: make - run: make test - run: make valgrind-test tinyproxy-1.11.2/.github/workflows/release_tarball.yml000066400000000000000000000034251461674137700231460ustar00rootroot00000000000000name: Generate Source Tarball # Trigger whenever a release is created on: release: types: - created jobs: build: name: build runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 with: submodules: recursive - name: archive id: archive run: | sudo apt install -y gperf rm -rf .git autoreconf -i VERSION=$(cat VERSION) PKGNAME="tinyproxy-$VERSION" ./configure make dist echo "::set-output name=tarball_xz::${PKGNAME}.tar.xz" echo "::set-output name=tarball_gz::${PKGNAME}.tar.gz" echo "::set-output name=tarball_bz2::${PKGNAME}.tar.bz2" - name: upload tarball_xz uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ github.event.release.upload_url }} asset_path: ./${{ steps.archive.outputs.tarball_xz }} asset_name: ${{ steps.archive.outputs.tarball_xz }} asset_content_type: application/x-xz - name: upload tarball_gz uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ github.event.release.upload_url }} asset_path: ./${{ steps.archive.outputs.tarball_gz }} asset_name: ${{ steps.archive.outputs.tarball_gz }} asset_content_type: application/x-gzip - name: upload tarball_bz2 uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ github.event.release.upload_url }} asset_path: ./${{ steps.archive.outputs.tarball_bz2 }} asset_name: ${{ steps.archive.outputs.tarball_bz2 }} asset_content_type: application/x-bzip2 tinyproxy-1.11.2/.gitignore000066400000000000000000000003501461674137700156670ustar00rootroot00000000000000INSTALL Makefile Makefile.in aclocal.m4 config.cache config.guess config.h config.h.in config.log config.status config.sub configure depcomp install-sh libtool missing stamp-h1 autom4te.cache cscope.files cscope.out compile *~ tags tinyproxy-1.11.2/.travis.yml000066400000000000000000000004551461674137700160160ustar00rootroot00000000000000language: C dist: trusty sudo: true before_install: - sudo apt-get update -qq - sudo apt-get install --assume-yes valgrind script: - ./autogen.sh - ./configure - make - make test - make clean - ./configure --enable-debug --enable-transparent --enable-reverse - make - make test - make valgrind-test tinyproxy-1.11.2/AUTHORS000066400000000000000000000010211461674137700147430ustar00rootroot00000000000000Andrew Stribblehill bertliao Bob Showalter Brian Cain cvs2svn Daniel Egger Daniel M. Drucker David Shanks Dmitry Semyonov dmz-uk Drew G. Wallace Frank Morgner gary-wzl77 Gaudenz Steinlin goba62000374 Gonzalo Tornaria Greg Jeremy Hinegardner John Spencer John van der Kamp John Weldon Jordi Jordi Mallach Julien Hartmann kikuchan Mathew Mrosko Matthew Dempsky Michael Adam Mike Mead Mukund Sivaraman Pablo Panero Peter H. Froehlich Robert James Kaes rofl0r Stephan Leemburg Steven Conaway Steven Young Valen Blanco Vladimir Belov tinyproxy-1.11.2/COPYING000066400000000000000000000431031461674137700147350ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. tinyproxy-1.11.2/ChangeLog000066400000000000000000000000601461674137700154470ustar00rootroot00000000000000The ChangeLog is maintained in the git history. tinyproxy-1.11.2/Makefile.am000066400000000000000000000007631461674137700157430ustar00rootroot00000000000000SUBDIRS = \ src \ data \ etc \ docs \ m4macros \ tests \ scripts # tools want this on a single line ACLOCAL_AMFLAGS = -I m4macros all-local: dist_doc_DATA = \ AUTHORS \ NEWS \ README \ README.md EXTRA_DIST = \ autogen.sh \ tinyproxy-indent.sh \ TODO \ VERSION test: all ./tests/scripts/run_tests.sh test-wait: TINYPROXY_TESTS_WAIT=yes $(MAKE) test valgrind-test: all ./tests/scripts/run_tests_valgrind.sh valgrind-test-wait: TINYPROXY_TESTS_WAIT=yes $(MAKE) valgrind-test tinyproxy-1.11.2/NEWS000066400000000000000000000000551461674137700144000ustar00rootroot00000000000000See git log for recent changes in Tinyproxy. tinyproxy-1.11.2/README000066400000000000000000000000161461674137700145560ustar00rootroot00000000000000see README.md tinyproxy-1.11.2/README.md000066400000000000000000000055021461674137700151620ustar00rootroot00000000000000# Tinyproxy Tinyproxy is a small, efficient HTTP/SSL proxy daemon released under the GNU General Public License. Tinyproxy is very useful in a small network setting, where a larger proxy would either be too resource intensive, or a security risk. One of the key features of Tinyproxy is the buffering connection concept. In effect, Tinyproxy will buffer a high speed response from a server, and then relay it to a client at the highest speed the client will accept. This feature greatly reduces the problems with sluggishness on the Internet. If you are sharing an Internet connection with a small network, and you only want to allow HTTP requests to be allowed, then Tinyproxy is a great tool for the network administrator. For more info, please visit [the Tinyproxy web site](https://tinyproxy.github.io/). ## Installation Tinyproxy uses a standard GNU `configure` script based on the automake system. If compiling from a git checkout, you need to first run ``` ./autogen.sh ``` from the top level directory to generate the `configure` script. The release tarball contains the pre-created `configure` script, so when building from a release, you can skip this step. Then basically all you need to do is ``` ./configure make make install ``` in the top level directory to compile and install Tinyproxy. There are additional command line arguments you can supply to `configure`. They include: - `--enable-debug`: If you would like to turn on full debugging support. - `--enable-xtinyproxy`: Compile in support for the XTinyproxy header, which is sent to any web server in your domain. - `--enable-filter`: Allows Tinyproxy to filter out certain domains and URLs. - `--enable-upstream`: Enable support for proxying connections through another proxy server. - `--enable-transparent`: Allow Tinyproxy to be used as a transparent proxy daemon. Unlike other work modes, transparent proxying doesn't require explicit configuration and works automatically when traffic is redirected to the proxy using the appropriate firewall rules. - `--enable-reverse`: Enable reverse proxying. - `--with-stathost=HOST`: Set the default name of the stats host. For more information about the build system, read the INSTALL file that is generated by `autogen.sh` and comes with the release tar ball. ## Support If you are having problems with Tinyproxy, please raise an [issue on github](https://github.com/tinyproxy/tinyproxy/issues). ## Contributing If you would like to contribute a feature, or a bug fix to the Tinyproxy source, please clone the [git repository from github](https://github.com/tinyproxy/tinyproxy.git) and create a [pull request](https://github.com/tinyproxy/tinyproxy/pulls). ## Community You can meet developers and users to discuss development, patches and deployment issues in the `#tinyproxy` IRC channel on libera (`irc.libera.chat`). tinyproxy-1.11.2/SECURITY.md000066400000000000000000000021141461674137700154700ustar00rootroot00000000000000# Security Policy ## Supported Versions | Version | Supported | | --------- | ------------------ | | 1.11.x | :white_check_mark: | | <= 1.10.x | :x: | ## Reporting a Vulnerability Open a public issue on github. The issue will most likely be fixed within a day, unless all maintainers happen to just be taking a vacation at the same time, which is unlikely. Even then, having the bug publicly known will allow competent people to come up with custom patches for distros, most likely quicker than black hats can craft a remote execution exploit. If you really really do not want to make the issue public, come to the tinyproxy IRC channel and ask for a maintainer, which you can then contact via private messages. Do not, however, like ["TALOS Intelligence"](https://talosintelligence.com/vulnerability_reports/TALOS-2023-1889) pull a random email address out of git log, then send an email nobody reads or responds to, and wait for 6 months for publication. this only gives black hats plenty time to sell, use and circulate zero days and get the best possible ROI. tinyproxy-1.11.2/TODO000066400000000000000000000040361461674137700143740ustar00rootroot00000000000000TODO List --------- The following are features that I would like to add to tinyproxy in the future. Where possible, I've listed the person who suggested it. This list is in no particular order. And hey, if you want to implement one of these, or another idea you have, go right ahead. Just mail me the diff against the current tree and I'll integrate it if possible. [ Actually, the ordering has become kind of important as of late. Basically, I'm adding new ideas to the bottom of the list as I go. ] * Include hooks so other types of proxies can be modularly added to the source tree. Then people can simply choose which types of proxies (ftp, www, etc) they'd like enabled in tinyproxy.h Suggested: Tarun Tuli. * Include a function to rewrite the incoming requests. Should not be much of a problem. Just need to modify the process_method() code to look up the URL and rewrite it. If we want to go really fancy with RegEx mapping this could get ugly. :) * Have the ability to send the data from the connections through an external filtering program. I kind of like this idea, but I don't really have a good way of doing it yet. Suggested: Ed Avis * Include the ability to rewrite both incoming and outgoing headers. * Enable an option for chroot() jailing tinyproxy. * Come up with a more consistent (and elegant) way of logging errors for the administrators. Right now it's more a hodge-podge collections of error messages without a _real_ standard. I would prefer a more uniform look. * Include user authentication for accessing tinyproxy itself. Administrators should be allowed to selectively allow certain users access to tinyproxy via a user name/password pair. Check the HTTP/1.1 RFC for more information. ==> https://www.banu.com/bugzilla/show_bug.cgi?id=13 * Remove common.h and fix order of headers * Remove memory debugging functions (Valgrind is good enough) * Make all functions return from one place (the end of the function) * Move TODO items to Banu Bugzilla tinyproxy-1.11.2/VERSION000066400000000000000000000000071461674137700147460ustar00rootroot000000000000001.11.2 tinyproxy-1.11.2/autogen.sh000077500000000000000000000006251461674137700157050ustar00rootroot00000000000000#!/bin/sh srcdir=`dirname $0` test -z "$srcdir" && srcdir=. ORIGDIR=`pwd` set -x cd $srcdir aclocal -I m4macros \ && autoheader \ && automake --gnu --add-missing \ && autoconf cd $ORIGDIR set - echo $srcdir/configure "$@" $srcdir/configure "$@" RC=$? if test $RC -ne 0; then echo echo "Configure failed or did not finish!" exit $RC fi echo echo "Now type 'make' to compile Tinyproxy." tinyproxy-1.11.2/configure.ac000066400000000000000000000172211461674137700161720ustar00rootroot00000000000000# Process this file with autoconf to produce a configure script. # Portions of this file were adapted from GIMP. AC_PREREQ(2.54) m4_define([tinyproxy_version], esyscmd(sh scripts/version.sh | tr -d '\n')) AC_INIT([Tinyproxy], [tinyproxy_version], [https://tinyproxy.github.io/], [tinyproxy]) tpv=tinyproxy_version if test "x$tpv" = "x" ; then AC_MSG_ERROR([got empty result from version script!]) fi AC_CANONICAL_TARGET AM_INIT_AUTOMAKE([dist-bzip2 dist-xz]) AC_CONFIG_HEADERS(config.h) AC_CONFIG_MACRO_DIR([m4macros]) m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) dnl Temporarily defined here until we get tinyproxy-version.h AC_DEFINE(TINYPROXY_VERSION, "tinyproxy_version", [Tinyproxy version number]) dnl Check if we're compiling on a weird platform :) AC_USE_SYSTEM_EXTENSIONS dnl Set the domain name for find the statistics of tinyproxy AH_TEMPLATE([TINYPROXY_STATHOST], [This controls remote proxy stats display.]) AC_ARG_WITH(stathost, [AC_HELP_STRING([--with-stathost=HOST], [Default status host])], [AC_DEFINE_UNQUOTED(TINYPROXY_STATHOST, "$withval") TINYPROXY_STATHOST="$withval"], [AC_DEFINE_UNQUOTED(TINYPROXY_STATHOST, "tinyproxy.stats") TINYPROXY_STATHOST="tinyproxy.stats"]) AC_SUBST(TINYPROXY_STATHOST) dnl Add compiler-specific optimization flags TP_ARG_ENABLE(debug, [Enable debugging support code and methods (default is NO)], no) dnl Check to see if the XTinyproxy header is to be included AH_TEMPLATE([XTINYPROXY_ENABLE], [Define if you want to have the peer's IP address included in a XTinyproxy header sent to the server.]) TP_ARG_ENABLE(xtinyproxy, [Include the X-Tinyproxy header (default is YES)], yes) if test x"$xtinyproxy_enabled" = x"yes"; then AC_DEFINE(XTINYPROXY_ENABLE) fi dnl Include filtering for domain/URLs AH_TEMPLATE([FILTER_ENABLE], [Defined if you would like filtering code included.]) TP_ARG_ENABLE(filter, [Enable filtering of domains/URLS (default is YES)], yes) if test x"$filter_enabled" = x"yes"; then ADDITIONAL_OBJECTS="$ADDITIONAL_OBJECTS filter.o" AC_DEFINE(FILTER_ENABLE) fi dnl Include support for upstream proxies? AH_TEMPLATE([UPSTREAM_SUPPORT], [Include support for connecting to an upstream proxy.]) TP_ARG_ENABLE(upstream, [Enable upstream proxying (default is YES)], yes) if test x"$upstream_enabled" = x"yes"; then AC_DEFINE(UPSTREAM_SUPPORT) fi dnl Include support for reverse proxy? AH_TEMPLATE([REVERSE_SUPPORT], [Include support for reverse proxy.]) TP_ARG_ENABLE(reverse, [Enable reverse proxying (default is YES)], yes) if test x"$reverse_enabled" = x"yes"; then ADDITIONAL_OBJECTS="$ADDITIONAL_OBJECTS reverse-proxy.o" AC_DEFINE(REVERSE_SUPPORT) fi dnl Include the transparent proxy support AH_TEMPLATE([TRANSPARENT_PROXY], [Include support for using tinyproxy as a transparent proxy.]) TP_ARG_ENABLE(transparent, [Enable transparent proxying code (default is YES)], yes) if test x"$transparent_enabled" = x"yes"; then ADDITIONAL_OBJECTS="$ADDITIONAL_OBJECTS transparent-proxy.o" AC_DEFINE(TRANSPARENT_PROXY) fi dnl Let user decide whether he wants support for manpages dnl Which require either pod2man or a tarball release AH_TEMPLATE([MANPAGE_SUPPORT], [Build manpages with pod2man if they are missing from the distribution.]) TP_ARG_ENABLE(manpage_support, [Enable support for building manpages (default is YES)], yes) AM_CONDITIONAL(HAVE_MANPAGE_INTEREST, test x"$manpage_support_enabled" = x"yes") # This is required to build test programs below AC_PROG_CC dnl dnl Checks for libraries dnl AC_CHECK_LIB(socket, socket, , [AC_CHECK_LIB(socket, htonl)]) dnl Some systems (OpenServer 5) dislike -lsocket -lnsl, so we try to dnl avoid -lnsl checks, if we already have the functions which are dnl usually in libnsl unset ac_cv_func_yp_get_default_domain AC_CHECK_FUNC(yp_get_default_domain, tinyproxy_no_nsl_checks=yes, tinyproxy_no_nsl_checks=no) unset ac_cv_func_yp_get_default_domain if test x"$tinyproxy_no_nsl_checks" != x"yes"; then AC_CHECK_LIB(nsl, gethostname, , [AC_CHECK_LIB(nsl, gethostbyaddr)]) fi AC_CHECK_LIB(resolv, inet_aton) dnl dnl Checks for headers dnl AC_HEADER_STDC AC_HEADER_TIME AC_HEADER_SYS_WAIT AC_CHECK_HEADERS([sys/ioctl.h alloca.h memory.h malloc.h sysexits.h \ values.h poll.h]) dnl Checks for libary functions AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK AC_CHECK_FUNCS([strlcpy strlcat setgroups]) dnl Enable extra warnings DESIRED_FLAGS="-fdiagnostics-show-option -Wall -Wextra -Wno-unused-parameter -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations -Wfloat-equal -Wundef -Wformat=2 -Wlogical-op -Wmissing-include-dirs -Wformat-nonliteral -Wold-style-definition -Wpointer-arith -Waggregate-return -Winit-self -Wpacked --std=c89 -ansi -Wno-overlength-strings -Wno-long-long -Wno-overlength-strings -Wdeclaration-after-statement -Wredundant-decls -Wmissing-noreturn -Wshadow -Wendif-labels -Wcast-qual -Wcast-align -Wwrite-strings -Wp,-D_FORTIFY_SOURCE=2 -fno-common" if test -n "${MAINTAINER_MODE_FALSE}"; then DESIRED_FLAGS="-Werror $DESIRED_FLAGS" fi all_desired_work=false AS_COMPILER_FLAG([$DESIRED_FLAGS], [all_desired_work=true]) if $all_desired_work ; then CFLAGS="$CFLAGS $DESIRED_FLAGS" else for flag in $DESIRED_FLAGS; do AS_COMPILER_FLAG([$flag], [CFLAGS="$CFLAGS $flag"]) done fi dnl Disable debugging if it's not specified if test x"$debug_enabled" != x"yes" ; then CFLAGS="-DNDEBUG $CFLAGS" fi dnl dnl Substitute the variables into the various Makefiles dnl AC_SUBST(CFLAGS) AC_SUBST(LDFLAGS) AC_SUBST(CPPFLAGS) AC_SUBST(LIBS) AC_SUBST(ADDITIONAL_OBJECTS) if test x"$manpage_support_enabled" = x"yes"; then AC_PATH_PROG(POD2MAN, pod2man, no) if test "x$POD2MAN" = "xno" && \ ! test -e docs/man5/tinyproxy.conf.5 -a -e docs/man8/tinyproxy.8 ; then AC_MSG_ERROR([ manpage generation requested, but neither pod2man nor pre-generated manpages found. Use --disable-manpage-support if you want to compile anyway.]) fi fi #manpage_support_enabled AM_CONDITIONAL(HAVE_POD2MAN, test "x$POD2MAN" != "x" -a "x$POD2MAN" != "xno") AC_PATH_PROG(GPERF, gperf, no) AH_TEMPLATE([HAVE_GPERF], [Whether you have gperf installed for faster config parsing.]) tmp_gperf=false if test "x$GPERF" != "x" -a "x$GPERF" != "xno" ; then AS_ECHO_N(["checking whether gperf is recent enough... "]) if "$GPERF" < src/conf-tokens.gperf >/dev/null 2>&1 ; then AS_ECHO("yes") AC_DEFINE(HAVE_GPERF) tmp_gperf=true else AS_ECHO("no") fi fi AM_CONDITIONAL(HAVE_GPERF, $tmp_gperf) AC_CONFIG_FILES([ Makefile src/Makefile data/Makefile data/templates/Makefile etc/Makefile docs/Makefile docs/man5/Makefile docs/man5/tinyproxy.conf.txt docs/man8/Makefile docs/man8/tinyproxy.txt m4macros/Makefile tests/Makefile tests/scripts/Makefile scripts/Makefile ]) AC_OUTPUT # the manpages are shipped in the release tarball and we don't want them to # get regenerated if pod2man is not available. the intermediate files from # AC_CONFIG_FILES are created with config.status, which is created at configure # runtime, so we need to touch them after config.status terminated to prevent # make from rebuild them. if test "x$POD2MAN" = "xno" ; then touch docs/man5/tinyproxy.conf.txt touch docs/man8/tinyproxy.txt if test -e docs/man5/tinyproxy.conf.5 ; then touch docs/man5/tinyproxy.conf.5 fi if test -e docs/man8/tinyproxy.8 ; then touch docs/man8/tinyproxy.8 fi fi if test "x$HAVE_GPERF" = "xno" && test -e src/conf-tokens-gperf.inc ; then touch src/conf-tokens-gperf.inc fi tinyproxy-1.11.2/data/000077500000000000000000000000001461674137700146125ustar00rootroot00000000000000tinyproxy-1.11.2/data/Makefile.am000066400000000000000000000000271461674137700166450ustar00rootroot00000000000000SUBDIRS = \ templates tinyproxy-1.11.2/data/templates/000077500000000000000000000000001461674137700166105ustar00rootroot00000000000000tinyproxy-1.11.2/data/templates/Makefile.am000066400000000000000000000002261461674137700206440ustar00rootroot00000000000000templatesdir = $(pkgdatadir) TEMPLATES = \ debug.html \ default.html \ stats.html templates_DATA = \ $(TEMPLATES) EXTRA_DIST = \ $(TEMPLATES) tinyproxy-1.11.2/data/templates/debug.html000066400000000000000000000015521461674137700205670ustar00rootroot00000000000000 {errno} {cause}

{cause}

{detail}

Here are the error variables:

request
{request}
cause
{cause}
clientip
{clientip}
clienthost
{clienthost}
version
{version}
package
{package}
date
{date}
detail
{detail}
url
{url}

Generated by {package} version {version}.

tinyproxy-1.11.2/data/templates/default.html000066400000000000000000000007221461674137700211230ustar00rootroot00000000000000 {errno} {cause}

{cause}

{detail}


Generated by {package} version {version}.

tinyproxy-1.11.2/data/templates/stats.html000066400000000000000000000041201461674137700206310ustar00rootroot00000000000000 Stats [{package} v{version}]
{package} v{version} statistics
Open connections {opens}
Bad connections {badconns}
Denied connections {deniedconns}
Refused (high load) {refusedconns}
Total requests {reqs}
tinyproxy-1.11.2/docs/000077500000000000000000000000001461674137700146315ustar00rootroot00000000000000tinyproxy-1.11.2/docs/.gitignore000066400000000000000000000000371461674137700166210ustar00rootroot00000000000000Makefile Makefile.in report.sh tinyproxy-1.11.2/docs/Makefile.am000066400000000000000000000001221461674137700166600ustar00rootroot00000000000000SUBDIRS = \ man5 \ man8 EXTRA_DIST = \ http-error-codes.txt \ http-rfcs.txt tinyproxy-1.11.2/docs/http-error-codes.txt000066400000000000000000000025241461674137700205760ustar00rootroot00000000000000The following is a list of the response codes for the various states of the server. Currently I would recommend we stick to the HTTP/1.0 return codes for our errors. Once we start to support the distinction between HTTP/1.0 and HTTP/1.1 requests from the client, then we can use the HTTP/1.1 responses. -- rjkaes [ Taken from Apache: The Definitive Guide by Ben Laurie & Peter Laurie. Published by O'Reilly & Associates, Inc. pg. 146-147 ] HTTP/1.0 200 OK 302 Found 304 Not Modified 400 Bad Request 401 Unauthorized 403 Forbidden 404 Not Found 500 Server error 501 Not Implemented 502 Bad Gateway 503 Out of resources HTTP/1.1 100 Continue 101 Switching Protocols 200 Ok 201 Created 202 Accepted 203 Non-Authoritative Information 204 No Content 205 Reset Content 206 Partial Content 300 Multiple Choices 301 Moved Permanently 302 Moved Temporarily 303 See Other 304 Not Modified 305 Use Proxy 400 Bad Request 401 Unauthorized 402 Payment Required 403 Forbidden 404 Not Found 405 Method Not Allowed 406 Not Acceptable 407 Proxy Authentication Required 408 Request Time-out 409 Conflict 410 Gone 411 Length Required 412 Precondition Failed 413 Request Entity Too Large 414 Request-URI Too Large 415 Unsupported Media Type 500 Internal Server Error 501 Not Implemented 502 Bad Gateway 503 Service Unavailable 504 Gateway Time-out 505 HTTP Version not supported tinyproxy-1.11.2/docs/http-rfcs.txt000066400000000000000000000013521461674137700173050ustar00rootroot00000000000000INFO ---- The following files were/are useful for the proper coding of tinyproxy. Please note: someday tinyproxy will actually be RFC compliant, but today is not that day. Right now tinyproxy is pretty close to being HTTP/1.0 compliant, but there are probably a few incompatibilities kicking around. RFCs ---- 1945 Hypertext Transfer Protocol -- HTTP/1.0 2396 Uniform Resource Identifiers (URI): Generic Syntax 2616 Hypertext Transfer Protocol -- HTTP/1.1 2617 HTTP Authentication: Basic and Digest Access Authentication POSSIBLE LOCATION ----------------- There are many places to obtain a copy of the RFCs, but I use http://www.rfc-editor.org/ since it provides a great search feature for finding all the RFCs for a particular topic. tinyproxy-1.11.2/docs/man5/000077500000000000000000000000001461674137700154715ustar00rootroot00000000000000tinyproxy-1.11.2/docs/man5/.gitignore000066400000000000000000000000201461674137700174510ustar00rootroot00000000000000*.5 *.xml *.txt tinyproxy-1.11.2/docs/man5/Makefile.am000066400000000000000000000007201461674137700175240ustar00rootroot00000000000000if HAVE_MANPAGE_INTEREST MAN5_FILES = \ tinyproxy.conf.txt endif M_SECTION=5 M_NAME=TINYPROXY.CONF man_MANS = \ $(MAN5_FILES:.txt=.5) .txt.5: if HAVE_POD2MAN $(AM_V_GEN) $(POD2MAN) --center="Tinyproxy manual" \ --section=$(M_SECTION) --name=$(M_NAME) --release="Version @VERSION@" \ $< > $@ else @echo "*** pod2man is required to regenerate $(@) ***"; exit 1; endif MAINTAINERCLEANFILES = \ $(MAN5_FILES:.txt=.5) EXTRA_DIST = \ $(MAN5_FILES:.txt=.5) tinyproxy-1.11.2/docs/man5/tinyproxy.conf.txt.in000066400000000000000000000324771461674137700216650ustar00rootroot00000000000000=pod =encoding utf8 =head1 NAME tinyproxy.conf - Tinyproxy HTTP proxy daemon configuration file =head1 SYNOPSIS B =head1 DESCRIPTION L reads its configuration file, typically stored in `/etc/tinyproxy/tinyproxy.conf` (or passed to Tinyproxy with -c on the command line). This manpage describes the syntax and contents of the configuration file. The Tinyproxy configuration file contains key-value pairs, one per line. Lines starting with `#` and empty lines are comments and are ignored. Keywords are case-insensitive, whereas values are case-sensitive. Some string values must be enclosed in double quotes (") as noted below. The possible keywords and their descriptions are as follows: =over 4 =item B The user which the Tinyproxy process should run as, after the initial port-binding has been done as the `root` user. Either the user name or the UID may be specified. =item B The group which the Tinyproxy process should run as, after the initial port-binding has been done as the `root` user. Either the group name or the GID may be specified. =item B The port which the Tinyproxy service will listen on. If the port is less than 1024, you will need to start the Tinyproxy process as the `root` user. =item B By default, Tinyproxy listens for connections on all available interfaces (i.e. it listens on the wildcard address `0.0.0.0`). With this configuration parameter, Tinyproxy can be told to listen only on one specific address. =item B This allows you to specify which address Tinyproxy will bind to for outgoing connections. This parameter may be specified multiple times, then Tinyproxy will try all the specified addresses in order. =item B If this boolean parameter is set to `yes`, then Tinyproxy will bind the outgoing connection to the IP address of the incoming connection that triggered the outgoing request. =item B The maximum number of seconds of inactivity a connection is allowed to have before it is closed by Tinyproxy. =item B This parameter controls which HTML file Tinyproxy returns when a given HTTP error occurs. It takes two arguments, the error number and the location of the HTML error file. Enclose the file location in double quotes. =item B The HTML template file returned when an error occurs for which no specific error file has been set. Enclose in double quotes. =item B The host name or IP address that is treated as the `stat host`. Enclose in double quotes. Whenever Tinyproxy receives a request for the `stat host` it returns an internal statistics page instead of forwarding the request to that host. The template for this page can be configured with the `StatFile` configuration option. The default value of `StatHost` is `@TINYPROXY_STATHOST@`. =item B The HTML file that Tinyproxy sends in response to a request for the `stat host`. Enclose in double quotes. If this parameter is not set, Tinyproxy returns a hard-coded basic statistics page. See the STATHOST section in the L manual page for details. Note that the StatFile and the error files configured with ErrorFile and DefaultErrorFile are template files that can contain a few template variables that Tinyproxy expands prior to delivery. Examples are "{cause}" for an abbreviated error description and "{detail}" for a detailed error message. The L manual page contains a description of all template variables. =item B The location of the file to which Tinyproxy writes its debug output. Enclose in double quotes. Alternatively, Tinyproxy can log to syslog -- see the Syslog option. =item B When set to `On`, this option tells Tinyproxy to write its debug messages to syslog instead of to a log file configured with `LogFile`. These two options are mutually exclusive. =item B Sets the log level. Messages from the set level and above are logged. For example, if the LogLevel was set to Warning, then all log messages from Warning to Critical would be output, but Notice and below would be suppressed. Allowed values are: =over 4 =item * Critical (least verbose) =item * Error =item * Warning =item * Notice =item * Connect (log connections without Info's noise) =item * Info (most verbose) =back =item B The location of the file where the main Tinyproxy process stores its process ID for signaling purposes. Enclose in double quotes. =item B Setting this option to `Yes` tells Tinyproxy to add a header `X-Tinyproxy` containing the client's IP address to the request. =item B This option allows you to set up a set of rules for deciding whether an upstream proxy server is to be used, based on the host or domain of the site being accessed. The rules are stored in the order encountered in the configuration file and the LAST matching rule wins. The following forms for specifying upstream rules exist: =over 4 =item * I turns proxy upstream support on generally. =item * I does the same, but uses the supplied credentials for authentication. =item * I turns on the upstream proxy for the sites matching `site_spec`. `type` can be one of `http`, `socks4`, `socks5`, `none`. =item * I turns off upstream support for sites matching `site_spec`, that means the connection is done directly. =back It's recommended to use raw IP addresses to specify the upstream host, so no costly DNS lookup has to be done everytime it is used. IPv6 addresses need to be enclosed in square brackets. The site can be specified in various forms as a hostname, domain name or as an IP range: =over 4 =item * I matches host exactly =item * I<.name> matches any host in domain "name" =item * I<.> matches any host with no domain (in 'empty' domain) =item * I matches network/mask =item * I matches network/mask =back Note that the upstream directive can also be used to null-route a specific target domain/host, e.g.: `upstream http 0.0.0.0:0 ".adserver.com"` =item B Tinyproxy creates one thread for each connected client. This options specifies the absolute highest number processes that will be created. With other words, only MaxClients clients can be connected to Tinyproxy simultaneously. =item B =item B The `Allow` and `Deny` options provide a means to customize which clients are allowed to access Tinyproxy. `Allow` and `Deny` lines can be specified multiple times to build the access control list for Tinyproxy. The order in the config file is important. If there are no `Allow` or `Deny` lines, then all clients are allowed. Otherwise, the default action is to deny access. The argument to `Allow` or `Deny` can be a single IP address of a client host, like `127.0.0.1`, an IP address range, like `192.168.0.1/24` or a string that will be matched against the end of the client host name, i.e, this can be a full host name like `host.example.com` or a domain name like `.example.com` or even a top level domain name like `.com`. Note that by adding a rule using a host or domain name, a costly name lookup has to be done for every new connection, which could slow down the service considerably. =item B Configure HTTP "Basic Authentication" username and password for accessing the proxy. If there are any entries specified, access is only granted for authenticated users. BasicAuth user password =item B Configure one or more HTTP request headers to be added to outgoing HTTP requests that Tinyproxy makes. Note that this option will not work for HTTPS traffic, as Tinyproxy has no control over what headers are exchanged. AddHeader "X-My-Header" "Powered by Tinyproxy" =item B RFC 2616 requires proxies to add a `Via` header to the HTTP requests, but using the real host name can be a security concern. If the `ViaProxyname` option is present, then its string value will be used as the host name in the Via header. Otherwise, the server's host name will be used. Enclose in double quotes. =item B When this is set to yes, Tinyproxy does NOT add the `Via` header to the requests. This virtually puts Tinyproxy into stealth mode. Note that RFC 2616 requires proxies to set the `Via` header, so by enabling this option, you break compliance. Don't disable the `Via` header unless you know what you are doing... =item B Tinyproxy supports filtering of web sites based on URLs or domains. This option specifies the location of the file containing the filter rules, one rule per line. Rules are specified as POSIX basic regular expressions (BRE), unless another FilterType is specified. Comment lines start with a `#` character. Example filter file contents: # filter exactly cnn.com ^cnn\.com$ # filter all subdomains of cnn.com, but not cnn.com itself .*\.cnn.com$ # filter any domain that has cnn.com in it, like xcnn.comfy.org cnn\.com # filter any domain that ends in cnn.com cnn\.com$ # filter any domain that starts with adserver ^adserver =item B This option can be set to one of `bre`, `ere`, or `fnmatch`. If `bre` is set, the rules specified in the filter file are matched using POSIX basic regular expressions, when set to `ere`, using POSIX extended regular expressions, and when set to `fnmatch` using the `fnmatch` function as specified in the manpage `man 3p fnmatch`. `fnmatch` matching is identical to what's used in the shell to match filenames, so for example `*.google.com` matches everything that ends with `.google.com`. If you don't know what regular expressions are or you're using filter lists from 3rd party sources, `fnmatch` is probably what you want. It's also the fastest matching method of the three. =item B If this boolean option is set to `Yes` or `On`, filtering is performed for URLs rather than for domains. The default is to filter based on domains. Note that filtering for URLs works only in plain HTTP scenarios. Since HTTPS has become ubiquitous during the last years, this will only work on a tiny fraction of websites, so it is recommended not to use this option. =item B Deprecated. Use `FilterType ere` instead. If this boolean option is set to `Yes`, then extended POSIX regular expressions are used for matching the filter rules. The default is to use basic POSIX regular expressions. =item B If this boolean option is set to `Yes`, then the filter rules are matched in a case sensitive manner. The default is to match case-insensitively, unfortunately. If you set this to `Yes`, then your matching will be almost twice as fast. This setting affects only `bre` and `ere` FilterTypes, fnmatch is always case sensitive. =item B The default filtering policy is to allow everything that is not matched by a filtering rule. Setting `FilterDefaultDeny` to `Yes` changes the policy do deny everything but the domains or URLs matched by the filtering rules. In other words, if set to `No` the Filter list acts as a blacklist, if set to `Yes` as a whitelist. =item B If an `Anonymous` keyword is present, then anonymous proxying is enabled. The headers listed with `Anonymous` are allowed through, while all others are denied. If no Anonymous keyword is present, then all headers are allowed through. You must include double quotes around the headers. Most sites require cookies to be enabled for them to work correctly, so you will need to allow cookies through if you access those sites. Example: Anonymous "Host" Anonymous "Authorization" Anonymous "Cookie" =item B This option can be used to specify the ports allowed for the CONNECT method. If no `ConnectPort` line is found, then all ports are allowed. To disable CONNECT altogether, include a single ConnectPort line with a value of `0`. =item B Configure one or more ReversePath directives to enable reverse proxy support. With reverse proxying it's possible to make a number of sites appear as if they were part of a single site. If you uncomment the following two directives and run Tinyproxy on your own computer at port 8888, you can access example.com, using http://localhost:8888/example/. ReversePath "/example/" "http://www.example.com/" =item B When using Tinyproxy as a reverse proxy, it is STRONGLY recommended that the normal proxy is turned off by setting this boolean option to `Yes`. =item B Setting this option to `Yes`, makes Tinyproxy use a cookie to track reverse proxy mappings. If you need to reverse proxy sites which have absolute links you must use this option. =item B The URL that is used to access this reverse proxy. The URL is used to rewrite HTTP redirects so that they won't escape the proxy. If you have a chain of reverse proxies, you'll need to put the outermost URL here (the address which the end user types into his/her browser). If this option is not set then no rewriting of redirects occurs. =back =head1 BUGS To report bugs in Tinyproxy, please visit L. =head1 SEE ALSO L =head1 AUTHOR This manpage was written by the Tinyproxy project team. =head1 COPYRIGHT Copyright (c) 1998-2020 the Tinyproxy authors. This program is distributed under the terms of the GNU General Public License version 2 or above. See the COPYING file for additional information. tinyproxy-1.11.2/docs/man8/000077500000000000000000000000001461674137700154745ustar00rootroot00000000000000tinyproxy-1.11.2/docs/man8/.gitignore000066400000000000000000000000201461674137700174540ustar00rootroot00000000000000*.8 *.xml *.txt tinyproxy-1.11.2/docs/man8/Makefile.am000066400000000000000000000007061461674137700175330ustar00rootroot00000000000000if HAVE_MANPAGE_INTEREST MAN8_FILES = \ tinyproxy.txt endif M_SECTION=8 M_NAME=TINYPROXY man_MANS = \ $(MAN8_FILES:.txt=.8) .txt.8: if HAVE_POD2MAN $(AM_V_GEN) $(POD2MAN) --center="Tinyproxy manual" \ --section=$(M_SECTION) --name=$(M_NAME) --release="Version @VERSION@" \ $< > $@ else @echo "*** pod2man is required to regenerate $(@) ***"; exit 1; endif MAINTAINERCLEANFILES = \ $(MAN8_FILES:.txt=.8) EXTRA_DIST = \ $(MAN8_FILES:.txt=.8) tinyproxy-1.11.2/docs/man8/tinyproxy.txt.in000066400000000000000000000074021461674137700207320ustar00rootroot00000000000000=pod =encoding utf8 =head1 NAME tinyproxy - A light-weight HTTP proxy daemon =head1 SYNOPSIS B [-vdch] =head1 DESCRIPTION B is a light-weight HTTP proxy daemon designed to consume a minimum amount of system resources. It listens on a given TCP port and handles HTTP proxy requests. Designed from the ground up to be fast and yet small, it is an ideal solution for use cases such as embedded deployments where a full featured HTTP proxy is required, but the system resources for a larger proxy are unavailable. =head1 OPTIONS B accepts the following options: =over 4 =item B<-c > Use an alternate configuration file. =item B<-d> Don't daemonize and stay in the foreground. Useful for debugging purposes. =item B<-h> Display a short help screen of command line arguments and exit. =item B<-v> Display version information and exit. =back =head1 SIGNALS In addition to command-line options, there are also several signals that can be sent to B while it is running to generate debugging information and to force certain events. =over 4 =item B Force Tinyproxy to do a garbage collection on the current connections linked list. This is usually done automatically after a certain number of connections have been handled. (Daemon mode only) =item B Force reload of config file and filter list. This is handy to update the configuration if Tinyproxy is running in foreground without dropping active connections. =back =head1 TEMPLATE FILES There are two occasions when Tinyproxy delivers HTML pages to the client on it's own right: =over 4 =item * When an error occurred, a corresponding error page is returned. =item * When a request for the stathost is made, a page summarizing the connection statistics is returned. (See STATHOST below.) =back The layout of both error pages and the statistics page can be controlled via configurable HTML template files that are plain HTML files that additionally understand a few template variables. =head1 TEMPLATE VARIABLES There are several standard HTML variables that are available in every template file: =over 4 =item B The full HTTP request line. =item B The abbreviated cause of the error condition. =item B The IP address of the client making the request. =item B The hostname of the client making the request. =item B The version of Tinyproxy. =item B The package name. Presently, resolves to 'tinyproxy'. =item B The current date/time in HTTP format. =back In addition, almost all templates support: =over 4 =item B A detailed, plain English explanation of the error and possible causes. =back When Tinyproxy finds a variable name enclosed in braces, e.g. "{request}", then this is replaced by the value of the corresponding variable before delivery of the page. =head1 STATHOST Tinyproxy returns a HTML page with connection statistics when it receives a HTTP request for a certain host -- the stathost. The stathost name defaults to `@TINYPROXY_STATHOST@` and can be changed at runtime to any name or IP address with the configuration variable `StatHost`. The stat file template can be changed at runtime through the configuration variable `StatFile`. =head1 FILES `/etc/tinyproxy/tinyproxy.conf`, `/var/run/tinyproxy/tinyproxy.pid`, `/var/log/tinyproxy/tinyproxy.log` =head1 BUGS To report bugs in Tinyproxy, please visit L. =head1 SEE ALSO L =head1 AUTHOR This manpage was written by the Tinyproxy project team. =head1 COPYRIGHT Copyright (c) 1998-2020 the Tinyproxy authors. This program is distributed under the terms of the GNU General Public License version 2 or above. See the COPYING file for additional information. tinyproxy-1.11.2/docs/web/000077500000000000000000000000001461674137700154065ustar00rootroot00000000000000tinyproxy-1.11.2/docs/web/Makefile000066400000000000000000000004451461674137700170510ustar00rootroot00000000000000# test webpage with `python -m SimpleHTTPServer` all: index.html tp.html.conf: ../man5/tinyproxy.conf.txt pod2html --noindex < $^ | awk -f podhtml-filter.awk > $@ index.html: tp.html.head tp.html.conf tp.html.foot cat $^ > $@ clean: rm tp.html.conf index.html *.tmp .PHONY: all clean tinyproxy-1.11.2/docs/web/podhtml-filter.awk000066400000000000000000000001571461674137700210470ustar00rootroot00000000000000BEGIN {i=0} /<\/{0,1}h1/ {if(!i)i=1; gsub("h1", "h4", $0);} #/<\/body>/ {i=0;} /BUGS/ {i=-1} {if(i==1) print;} tinyproxy-1.11.2/docs/web/stylesheets/000077500000000000000000000000001461674137700177625ustar00rootroot00000000000000tinyproxy-1.11.2/docs/web/stylesheets/stylesheet.css000066400000000000000000000167301461674137700226740ustar00rootroot00000000000000/******************************************************************************* Slate Theme for GitHub Pages by Jason Costello, @jsncostello *******************************************************************************/ @import url(github-light.css); /******************************************************************************* MeyerWeb Reset *******************************************************************************/ html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { margin: 0; padding: 0; border: 0; font: inherit; vertical-align: baseline; } /* HTML5 display-role reset for older browsers */ article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { display: block; } ol, ul { list-style: none; } table { border-collapse: collapse; border-spacing: 0; } /******************************************************************************* Theme Styles *******************************************************************************/ body { box-sizing: border-box; color:#373737; background: #212121; font-size: 16px; font-family: 'Myriad Pro', Calibri, Helvetica, Arial, sans-serif; line-height: 1.5; -webkit-font-smoothing: antialiased; } h1, h2, h3, h4, h5, h6 { margin: 10px 0; font-weight: 700; color:#222222; font-family: 'Lucida Grande', 'Calibri', Helvetica, Arial, sans-serif; letter-spacing: -1px; } h1 { font-size: 36px; font-weight: 700; } h2 { padding-bottom: 10px; font-size: 32px; background: url('../images/bg_hr.png') repeat-x bottom; } h3 { font-size: 24px; } h4 { font-size: 21px; } h5 { font-size: 18px; } h6 { font-size: 16px; } p { margin: 10px 0 15px 0; } footer p { color: #f2f2f2; } a { text-decoration: none; color: #007edf; text-shadow: none; transition: color 0.5s ease; transition: text-shadow 0.5s ease; -webkit-transition: color 0.5s ease; -webkit-transition: text-shadow 0.5s ease; -moz-transition: color 0.5s ease; -moz-transition: text-shadow 0.5s ease; -o-transition: color 0.5s ease; -o-transition: text-shadow 0.5s ease; -ms-transition: color 0.5s ease; -ms-transition: text-shadow 0.5s ease; } a:hover, a:focus {text-decoration: underline;} footer a { color: #F2F2F2; text-decoration: underline; } em { font-style: italic; } strong { font-weight: bold; } img { position: relative; margin: 0 auto; max-width: 739px; padding: 5px; margin: 10px 0 10px 0; border: 1px solid #ebebeb; box-shadow: 0 0 5px #ebebeb; -webkit-box-shadow: 0 0 5px #ebebeb; -moz-box-shadow: 0 0 5px #ebebeb; -o-box-shadow: 0 0 5px #ebebeb; -ms-box-shadow: 0 0 5px #ebebeb; } p img { display: inline; margin: 0; padding: 0; vertical-align: middle; text-align: center; border: none; } pre, code { width: 100%; color: #222; background-color: #fff; font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; font-size: 14px; border-radius: 2px; -moz-border-radius: 2px; -webkit-border-radius: 2px; } pre { width: 100%; padding: 10px; margin-bottom: 20px; box-shadow: 0 0 10px rgba(0,0,0,.1); overflow: auto; } code { padding: 3px; margin: 0 3px; box-shadow: 0 0 10px rgba(0,0,0,.1); } pre code { display: block; box-shadow: none; } blockquote { color: #666; margin-bottom: 20px; padding: 0 0 0 20px; border-left: 3px solid #bbb; } ul, ol, dl { margin-bottom: 15px } ul { list-style-position: inside; list-style: disc; padding-left: 20px; } ol { list-style-position: inside; list-style: decimal; padding-left: 20px; } dl dt { font-weight: bold; } dl dd { padding-left: 20px; /* font-style: italic; */ } dl p { padding-left: 20px; /* font-style: italic; */ } hr { height: 1px; margin-bottom: 5px; border: none; background: url('../images/bg_hr.png') repeat-x center; } table { border: 1px solid #373737; margin-bottom: 20px; text-align: left; } th { font-family: 'Lucida Grande', 'Helvetica Neue', Helvetica, Arial, sans-serif; padding: 10px; background: #373737; color: #fff; } td { padding: 10px; border: 1px solid #373737; } form { background: #f2f2f2; padding: 20px; } /******************************************************************************* Full-Width Styles *******************************************************************************/ .outer { width: 100%; } .inner { position: relative; max-width: 640px; padding: 20px 10px; margin: 0 auto; } #forkme_banner { display: block; position: absolute; top:0; right: 10px; z-index: 10; padding: 10px 50px 10px 10px; color: #fff; background: url('../images/blacktocat.png') #0090ff no-repeat 95% 50%; font-weight: 700; box-shadow: 0 0 10px rgba(0,0,0,.5); border-bottom-left-radius: 2px; border-bottom-right-radius: 2px; } #header_wrap { background: #212121; background: -moz-linear-gradient(top, #373737, #212121); background: -webkit-linear-gradient(top, #373737, #212121); background: -ms-linear-gradient(top, #373737, #212121); background: -o-linear-gradient(top, #373737, #212121); background: linear-gradient(top, #373737, #212121); } #header_wrap .inner { padding: 50px 10px 30px 10px; } #project_title { margin: 0; color: #fff; font-size: 42px; font-weight: 700; text-shadow: #111 0px 0px 10px; } #project_tagline { color: #fff; font-size: 24px; font-weight: 300; background: none; text-shadow: #111 0px 0px 10px; } #downloads { position: absolute; width: 210px; z-index: 10; bottom: -40px; right: 0; height: 70px; background: url('../images/icon_download.png') no-repeat 0% 90%; } .zip_download_link { display: block; float: right; width: 90px; height:70px; text-indent: -5000px; overflow: hidden; background: url(../images/sprite_download.png) no-repeat bottom left; } .tar_download_link { display: block; float: right; width: 90px; height:70px; text-indent: -5000px; overflow: hidden; background: url(../images/sprite_download.png) no-repeat bottom right; margin-left: 10px; } .zip_download_link:hover { background: url(../images/sprite_download.png) no-repeat top left; } .tar_download_link:hover { background: url(../images/sprite_download.png) no-repeat top right; } #main_content_wrap { background: #f2f2f2; border-top: 1px solid #111; border-bottom: 1px solid #111; } #main_content { padding-top: 40px; } #footer_wrap { background: #212121; } /******************************************************************************* Small Device Styles *******************************************************************************/ @media screen and (max-width: 480px) { body { font-size:14px; } #downloads { display: none; } .inner { min-width: 320px; max-width: 480px; } #project_title { font-size: 32px; } h1 { font-size: 28px; } h2 { font-size: 24px; } h3 { font-size: 21px; } h4 { font-size: 18px; } h5 { font-size: 14px; } h6 { font-size: 12px; } code, pre { min-width: 320px; max-width: 480px; font-size: 11px; } } tinyproxy-1.11.2/docs/web/tp.html.foot000066400000000000000000000010431461674137700176630ustar00rootroot00000000000000

Support

  • Feel free to report a new bug or suggest features via github issues.
  • Tinyproxy developers hang out in #tinyproxy on irc.libera.chat.
tinyproxy-1.11.2/docs/web/tp.html.head000066400000000000000000000157761461674137700176370ustar00rootroot00000000000000 Tinyproxy
View on GitHub

Tinyproxy

lightweight http(s) proxy daemon

Tinyproxy

Tinyproxy is a light-weight HTTP/HTTPS proxy daemon for POSIX operating systems. Designed from the ground up to be fast and yet small, it is an ideal solution for use cases such as embedded deployments where a full featured HTTP proxy is required, but the system resources for a larger proxy are unavailable.

Tinyproxy is distributed using the GNU GPL license (version 2 or above).

Features

Tinyproxy has a small footprint and requires very little in the way of system resources. The memory footprint tends to be around 2 MB with glibc, and the CPU load increases linearly with the number of simultaneous connections (depending on the speed of the connection). Thus, Tinyproxy can be run on an older machine, or on a network appliance such as a Linux-based broadband router, without any noticeable impact on performance.

Tinyproxy requires only a minimal POSIX environment to build and operate. It can use additional libraries to add functionality though.

Tinyproxy allows forwarding of HTTPS connections without modifying traffic in any way through the CONNECT method (see the ConnectPort directive, which you should disable, unless you want to restrict the users).

Tinyproxy supports being configured as a transparent proxy, so that a proxy can be used without requiring any client-side configuration. You can also use it as a reverse proxy front-end to your websites.

Using the AddHeader directive, you can add/insert HTTP headers to outgoing traffic (HTTP only).

If you're looking to build a custom web proxy, Tinyproxy is easy to modify to your custom needs. The source is straightforward, adhering to the KISS principle. As such, it can be used as a foundation for anything you may need a web proxy to do.

Tinyproxy has privacy features which can let you configure which HTTP headers should be allowed through, and which should be blocked. This allows you to restrict both what data comes to your web browser from the HTTP server (e.g., cookies), and to restrict what data is allowed through from your web browser to the HTTP server (e.g., version information). Note that these features do not affect HTTPS connections.

Using the remote monitoring facility, you can access proxy statistics from afar, letting you know exactly how busy the proxy is.

You can configure Tinyproxy to control access by only allowing requests from a certain subnet, or from a certain interface, thus ensuring that random, unauthorized people will not be using your proxy.

With a bit of configuration (specifically, making Tinyproxy created files owned by a non-root user and running it on a port greater than 1024), Tinyproxy can be made to run without any special privileges, thus minimizing the chance of system compromise. In fact, it is recommended to run it as a regular/restricted user. Furthermore, it was designed with an eye towards preventing buffer overflows. The simplicity of the code ensures it remains easy to spot such bugs.

Downloads

Note that many distributions ship horribly outdated versions of tinyproxy, therefore it is recommended to compile it from source.

  • On Red Hat Enterprise Linux, or its derivatives such as CentOS, install Tinyproxy from the EPEL repository by running yum install tinyproxy.
  • On Fedora, install Tinyproxy by running yum install tinyproxy.
  • On Debian and derived distributions, run apt-get install tinyproxy to install Tinyproxy.
  • For openSUSE run: zypper in tinyproxy
  • Arch users can install the Tinyproxy package from the community repository. Run pacman -S tinyproxy to install it.
  • FreeBSD, OpenBSD or NetBSD users can use the pkg_add utility to install the tinyproxy package.
  • Mac OS X users can check MacPorts to see if the Tinyproxy port there is recent enough.

If you feel that the Tinyproxy binary package in your operating system is not recent (likely), please contact the package maintainer for that particular operating system. If this fails, you can always compile the latest stable, or even better, the latest git master version, from source code.

We distribute Tinyproxy in source code form, and it has to be compiled in order to be used on your system. Please see the INSTALL file in the source code tree for build instructions. The current stable version of Tinyproxy is available on the releases page. The Tinyproxy NEWS file contains the release notes. You can verify the tarball using its PGP signature. You can also browse the older releases of Tinyproxy.

We use Git as the version control system for the Tinyproxy source code repository. To get a copy of the Tinyproxy repository, use the command:

git clone https://github.com/tinyproxy/tinyproxy.git

Quickstart

The quickest way to get started is using a minimal config file like the below:


Port 8888
Listen 127.0.0.1
Timeout 600
Allow 127.0.0.1

And then simply run tinyproxy -d -c tinyproxy.conf as your current user. This starts tinyproxy in foreground mode with tinyproxy.conf as its config, while logging to stdout. Now, all programs supporting a HTTP proxy can use 127.0.0.1:8888 as a proxy. You can try it out using http_proxy=127.0.0.1:8888 curl example.com.

Documentation

tinyproxy-1.11.2/etc/000077500000000000000000000000001461674137700144545ustar00rootroot00000000000000tinyproxy-1.11.2/etc/.gitignore000066400000000000000000000000171461674137700164420ustar00rootroot00000000000000tinyproxy.conf tinyproxy-1.11.2/etc/Makefile.am000066400000000000000000000012021461674137700165030ustar00rootroot00000000000000pkgsysconfdir = $(sysconfdir)/$(PACKAGE) pkgsysconf_DATA = \ tinyproxy.conf EXTRA_DIST = \ tinyproxy.conf.in edit = sed \ -e 's|@bindir[@]|$(bindir)|g' \ -e 's|@datadir[@]|$(datadir)|g' \ -e 's|@datarootdir[@]|$(datarootdir)|g' \ -e 's|@pkgsysconfdir[@]|$(pkgsysconfdir)|g' \ -e 's|@localstatedir[@]|$(localstatedir)|g' \ -e 's|@pkgdatadir[@]|$(pkgdatadir)|g' \ -e 's|@prefix[@]|$(prefix)|g' \ -e 's|@TINYPROXY_STATHOST[@]|$(TINYPROXY_STATHOST)|g' tinyproxy.conf: $(top_srcdir)/etc/tinyproxy.conf.in Makefile @rm -f $@ $@.tmp $(AM_V_GEN) $(edit) $(top_srcdir)/etc/$@.in > $@.tmp @mv $@.tmp $@ CLEANFILES = \ tinyproxy.conf tinyproxy-1.11.2/etc/tinyproxy.conf.in000066400000000000000000000236051461674137700200230ustar00rootroot00000000000000## ## tinyproxy.conf -- tinyproxy daemon configuration file ## ## This example tinyproxy.conf file contains example settings ## with explanations in comments. For decriptions of all ## parameters, see the tinyproxy.conf(5) manual page. ## # # User/Group: This allows you to set the user and group that will be # used for tinyproxy after the initial binding to the port has been done # as the root user. Either the user or group name or the UID or GID # number may be used. # User nobody Group nobody # # Port: Specify the port which tinyproxy will listen on. Please note # that should you choose to run on a port lower than 1024 you will need # to start tinyproxy using root. # Port 8888 # # Listen: If you have multiple interfaces this allows you to bind to # only one. If this is commented out, tinyproxy will bind to all # interfaces present. # #Listen 192.168.0.1 # # Bind: This allows you to specify which interface will be used for # outgoing connections. This is useful for multi-home'd machines where # you want all traffic to appear outgoing from one particular interface. # #Bind 192.168.0.1 # # BindSame: If enabled, tinyproxy will bind the outgoing connection to the # ip address of the incoming connection. # #BindSame yes # # Timeout: The maximum number of seconds of inactivity a connection is # allowed to have before it is closed by tinyproxy. # Timeout 600 # # ErrorFile: Defines the HTML file to send when a given HTTP error # occurs. You will probably need to customize the location to your # particular install. The usual locations to check are: # /usr/local/share/tinyproxy # /usr/share/tinyproxy # /etc/tinyproxy # #ErrorFile 400 "@pkgdatadir@/400.html" #ErrorFile 502 "@pkgdatadir@/502.html" #ErrorFile 503 "@pkgdatadir@/503.html" #ErrorFile 403 "@pkgdatadir@/403.html" #ErrorFile 408 "@pkgdatadir@/408.html" # # DefaultErrorFile: The HTML file that gets sent if there is no # HTML file defined with an ErrorFile keyword for the HTTP error # that has occured. # DefaultErrorFile "@pkgdatadir@/default.html" # # StatHost: This configures the host name or IP address that is treated # as the stat host: Whenever a request for this host is received, # Tinyproxy will return an internal statistics page instead of # forwarding the request to that host. The default value of StatHost is # @TINYPROXY_STATHOST@. # #StatHost "@TINYPROXY_STATHOST@" # # # StatFile: The HTML file that gets sent when a request is made # for the stathost. If this file doesn't exist a basic page is # hardcoded in tinyproxy. # StatFile "@pkgdatadir@/stats.html" # # LogFile: Allows you to specify the location where information should # be logged to. If you would prefer to log to syslog, then disable this # and enable the Syslog directive. These directives are mutually # exclusive. If neither Syslog nor LogFile are specified, output goes # to stdout. # #LogFile "@localstatedir@/log/tinyproxy/tinyproxy.log" # # Syslog: Tell tinyproxy to use syslog instead of a logfile. This # option must not be enabled if the Logfile directive is being used. # These two directives are mutually exclusive. # #Syslog On # # LogLevel: Warning # # Set the logging level. Allowed settings are: # Critical (least verbose) # Error # Warning # Notice # Connect (to log connections without Info's noise) # Info (most verbose) # # The LogLevel logs from the set level and above. For example, if the # LogLevel was set to Warning, then all log messages from Warning to # Critical would be output, but Notice and below would be suppressed. # LogLevel Info # # PidFile: Write the PID of the main tinyproxy thread to this file so it # can be used for signalling purposes. # If not specified, no pidfile will be written. # #PidFile "@localstatedir@/run/tinyproxy/tinyproxy.pid" # # XTinyproxy: Tell Tinyproxy to include the X-Tinyproxy header, which # contains the client's IP address. # #XTinyproxy Yes # # Upstream: # # Turns on upstream proxy support. # # The upstream rules allow you to selectively route upstream connections # based on the host/domain of the site being accessed. # # Syntax: upstream type (user:pass@)ip:port ("domain") # Or: upstream none "domain" # The parts in parens are optional. # Possible types are http, socks4, socks5, none # # For example: # # connection to test domain goes through testproxy # upstream http testproxy:8008 ".test.domain.invalid" # upstream http testproxy:8008 ".our_testbed.example.com" # upstream http testproxy:8008 "192.168.128.0/255.255.254.0" # # # upstream proxy using basic authentication # upstream http user:pass@testproxy:8008 ".test.domain.invalid" # # # no upstream proxy for internal websites and unqualified hosts # upstream none ".internal.example.com" # upstream none "www.example.com" # upstream none "10.0.0.0/8" # upstream none "192.168.0.0/255.255.254.0" # upstream none "." # # # connection to these boxes go through their DMZ firewalls # upstream http cust1_firewall:8008 "testbed_for_cust1" # upstream http cust2_firewall:8008 "testbed_for_cust2" # # # default upstream is internet firewall # upstream http firewall.internal.example.com:80 # # You may also use SOCKS4/SOCKS5 upstream proxies: # upstream socks4 127.0.0.1:9050 # upstream socks5 socksproxy:1080 # # The LAST matching rule wins the route decision. As you can see, you # can use a host, or a domain: # name matches host exactly # .name matches any host in domain "name" # . matches any host with no domain (in 'empty' domain) # IP/bits matches network/mask # IP/mask matches network/mask # #Upstream http some.remote.proxy:port # # MaxClients: This is the absolute highest number of threads which will # be created. In other words, only MaxClients number of clients can be # connected at the same time. # MaxClients 100 # # Allow: Customization of authorization controls. If there are any # access control keywords then the default action is to DENY. Otherwise, # the default action is ALLOW. # # The order of the controls are important. All incoming connections are # tested against the controls based on order. # Allow 127.0.0.1 Allow ::1 # BasicAuth: HTTP "Basic Authentication" for accessing the proxy. # If there are any entries specified, access is only granted for authenticated # users. #BasicAuth user password # # AddHeader: Adds the specified headers to outgoing HTTP requests that # Tinyproxy makes. Note that this option will not work for HTTPS # traffic, as Tinyproxy has no control over what headers are exchanged. # #AddHeader "X-My-Header" "Powered by Tinyproxy" # # ViaProxyName: The "Via" header is required by the HTTP RFC, but using # the real host name is a security concern. If the following directive # is enabled, the string supplied will be used as the host name in the # Via header; otherwise, the server's host name will be used. # ViaProxyName "tinyproxy" # # DisableViaHeader: When this is set to yes, Tinyproxy does NOT add # the Via header to the requests. This virtually puts Tinyproxy into # stealth mode. Note that RFC 2616 requires proxies to set the Via # header, so by enabling this option, you break compliance. # Don't disable the Via header unless you know what you are doing... # #DisableViaHeader Yes # # Filter: This allows you to specify the location of the filter file. # #Filter "@pkgsysconfdir@/filter" # # FilterURLs: Filter based on URLs rather than domains. # #FilterURLs On # # FilterType: Use bre (default), ere, or fnmatch for filtering. # #FilterType fnmatch # # FilterCaseSensitive: Use case sensitive regular expressions. # #FilterCaseSensitive On # # FilterDefaultDeny: Change the default policy of the filtering system. # If this directive is commented out, or is set to "No" then the default # policy is to allow everything which is not specifically denied by the # filter file. # # However, by setting this directive to "Yes" the default policy becomes # to deny everything which is _not_ specifically allowed by the filter # file. # #FilterDefaultDeny Yes # # Anonymous: If an Anonymous keyword is present, then anonymous proxying # is enabled. The headers listed are allowed through, while all others # are denied. If no Anonymous keyword is present, then all headers are # allowed through. You must include quotes around the headers. # # Most sites require cookies to be enabled for them to work correctly, so # you will need to allow Cookies through if you access those sites. # #Anonymous "Host" #Anonymous "Authorization" #Anonymous "Cookie" # # ConnectPort: This is a list of ports allowed by tinyproxy when the # CONNECT method is used. To disable the CONNECT method altogether, set # the value to 0. If no ConnectPort line is found, all ports are # allowed. # # The following two ports are used by SSL. # #ConnectPort 443 #ConnectPort 563 # # Configure one or more ReversePath directives to enable reverse proxy # support. With reverse proxying it's possible to make a number of # sites appear as if they were part of a single site. # # If you uncomment the following two directives and run tinyproxy # on your own computer at port 8888, you can access Google using # http://localhost:8888/google/ and Wired News using # http://localhost:8888/wired/news/. Neither will actually work # until you uncomment ReverseMagic as they use absolute linking. # #ReversePath "/google/" "http://www.google.com/" #ReversePath "/wired/" "http://www.wired.com/" # # When using tinyproxy as a reverse proxy, it is STRONGLY recommended # that the normal proxy is turned off by uncommenting the next directive. # #ReverseOnly Yes # # Use a cookie to track reverse proxy mappings. If you need to reverse # proxy sites which have absolute links you must uncomment this. # #ReverseMagic Yes # # The URL that's used to access this reverse proxy. The URL is used to # rewrite HTTP redirects so that they won't escape the proxy. If you # have a chain of reverse proxies, you'll need to put the outermost # URL here (the address which the end user types into his/her browser). # # If not set then no rewriting occurs. # #ReverseBaseURL "http://localhost:8888/" tinyproxy-1.11.2/m4macros/000077500000000000000000000000001461674137700154265ustar00rootroot00000000000000tinyproxy-1.11.2/m4macros/Makefile.am000066400000000000000000000000641461674137700174620ustar00rootroot00000000000000EXTRA_DIST = \ as-compiler-flag.m4 \ argenable.m4 tinyproxy-1.11.2/m4macros/argenable.m4000066400000000000000000000012471461674137700176140ustar00rootroot00000000000000dnl $Id: argenable.m4,v 1.1 2004-08-24 18:40:21 rjkaes Exp $ dnl dnl Define a new AC_ARG_ENABLE like macro which handles invalid inputs dnl correctly. The macro takes three arguments: dnl 1) the option name (used like --enable-option) dnl 2) the help string dnl 3) the default value (either yes or no) dnl dnl This macro also defines on variable in the form "option_enabled" dnl set to either "yes" or "no". dnl AC_DEFUN([TP_ARG_ENABLE], [AC_ARG_ENABLE([$1], AS_HELP_STRING([--enable-$1], [$2]), [case "${enableval}" in yes) $1_enabled=yes ;; no) $1_enabled=no ;; *) AC_MSG_ERROR([bad value ${enableval} for --enable-$1]) ;; esac],[$1_enabled=$3])]) tinyproxy-1.11.2/m4macros/as-compiler-flag.m4000066400000000000000000000025541461674137700210200ustar00rootroot00000000000000dnl as-compiler-flag.m4 0.1.0 dnl autostars m4 macro for detection of compiler flags dnl David Schleef dnl Tim-Philipp Müller dnl AS_COMPILER_FLAG(CFLAGS, ACTION-IF-ACCEPTED, [ACTION-IF-NOT-ACCEPTED]) dnl Tries to compile with the given CFLAGS. dnl Runs ACTION-IF-ACCEPTED if the compiler can compile with the flags, dnl and ACTION-IF-NOT-ACCEPTED otherwise. AC_DEFUN([AS_COMPILER_FLAG], [ AC_MSG_CHECKING([to see if compiler understands $1]) save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS $1" AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no]) CFLAGS="$save_CFLAGS" if test "X$flag_ok" = Xyes ; then $2 true else $3 true fi AC_MSG_RESULT([$flag_ok]) ]) dnl AS_CXX_COMPILER_FLAG(CPPFLAGS, ACTION-IF-ACCEPTED, [ACTION-IF-NOT-ACCEPTED]) dnl Tries to compile with the given CPPFLAGS. dnl Runs ACTION-IF-ACCEPTED if the compiler can compile with the flags, dnl and ACTION-IF-NOT-ACCEPTED otherwise. AC_DEFUN([AS_CXX_COMPILER_FLAG], [ AC_REQUIRE([AC_PROG_CXX]) AC_MSG_CHECKING([to see if c++ compiler understands $1]) save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $1" AC_LANG_PUSH(C++) AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no]) CPPFLAGS="$save_CPPFLAGS" if test "X$flag_ok" = Xyes ; then $2 true else $3 true fi AC_LANG_POP(C++) AC_MSG_RESULT([$flag_ok]) ]) tinyproxy-1.11.2/scripts/000077500000000000000000000000001461674137700153705ustar00rootroot00000000000000tinyproxy-1.11.2/scripts/Makefile.am000066400000000000000000000000401461674137700174160ustar00rootroot00000000000000EXTRA_DIST = \ version.sh tinyproxy-1.11.2/scripts/gen-authors.sh000077500000000000000000000004041461674137700201610ustar00rootroot00000000000000#!/bin/sh SCRIPT_DIR="$(cd "$(dirname "${0}")" && pwd)" BASE_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" AUTHORS_FILE="${BASE_DIR}/AUTHORS" type git > /dev/null || exit test -d "${BASE_DIR}/.git" || exit git log --all --format='%aN' | sort -u > "${AUTHORS_FILE}" tinyproxy-1.11.2/scripts/version.sh000077500000000000000000000006171461674137700174200ustar00rootroot00000000000000#!/bin/sh SCRIPT_DIR="$(cd "$(dirname "${0}")" && pwd)" GIT_DIR="${SCRIPT_DIR}/../.git" if test -d "${GIT_DIR}" ; then if type git >/dev/null 2>&1 ; then gitstr=$(git describe --match '[0-9]*.[0-9]*.*' 2>/dev/null) if test "x$?" != x0 ; then sed 's/$/-git/' < VERSION else printf "%s\n" "$gitstr" | sed -e 's/-g/-git-/' fi else sed 's/$/-git/' < VERSION fi else cat VERSION fi tinyproxy-1.11.2/src/000077500000000000000000000000001461674137700144705ustar00rootroot00000000000000tinyproxy-1.11.2/src/.gitignore000066400000000000000000000000661461674137700164620ustar00rootroot00000000000000.deps .libs Makefile Makefile.in tinyproxy *.o *.pcno tinyproxy-1.11.2/src/Makefile.am000066400000000000000000000037711461674137700165340ustar00rootroot00000000000000# tinyproxy - A fast light-weight HTTP proxy # Copyright (C) 2000 Robert James Kaes # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. pkgsysconfdir = $(sysconfdir)/$(PACKAGE) bin_PROGRAMS = tinyproxy AM_CPPFLAGS = \ -DSYSCONFDIR=\"${pkgsysconfdir}\" \ -DLOCALSTATEDIR=\"${localstatedir}\" tinyproxy_SOURCES = \ hostspec.c hostspec.h \ acl.c acl.h \ anonymous.c anonymous.h \ buffer.c buffer.h \ child.c child.h \ common.h \ conf-tokens.c conf-tokens.h \ conf.c conf.h \ conns.c conns.h \ daemon.c daemon.h \ heap.c heap.h \ html-error.c html-error.h \ http-message.c http-message.h \ log.c log.h \ network.c network.h \ reqs.c reqs.h \ sock.c sock.h \ stats.c stats.h \ text.c text.h \ main.c main.h \ utils.c utils.h \ upstream.c upstream.h \ basicauth.c basicauth.h \ base64.c base64.h \ sblist.c sblist.h \ hsearch.c hsearch.h \ orderedmap.c orderedmap.h \ loop.c loop.h \ mypoll.c mypoll.h \ connect-ports.c connect-ports.h EXTRA_tinyproxy_SOURCES = filter.c filter.h \ reverse-proxy.c reverse-proxy.h \ transparent-proxy.c transparent-proxy.h tinyproxy_DEPENDENCIES = @ADDITIONAL_OBJECTS@ tinyproxy_LDADD = @ADDITIONAL_OBJECTS@ -lpthread if HAVE_GPERF conf-tokens.c: conf-tokens-gperf.inc conf-tokens-gperf.inc: conf-tokens.gperf $(GPERF) $< > $@ endif EXTRA_DIST = conf-tokens.gperf conf-tokens-gperf.inc tinyproxy-1.11.2/src/acl.c000066400000000000000000000213721461674137700154000ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 2000, 2002 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* This system handles Access Control for use of this daemon. A list of * domains, or IP addresses (including IP blocks) are stored in a list * which is then used to compare incoming connections. */ #include "main.h" #include "acl.h" #include "heap.h" #include "log.h" #include "network.h" #include "sock.h" #include "sblist.h" #include "hostspec.h" /* * Hold the information about a particular access control. We store * whether it's an ALLOW or DENY entry, and also whether it's a string * entry (like a domain name) or an IP entry. */ struct acl_s { acl_access_t access; struct hostspec h; }; /** * If the access list has not been set up, create it. */ static int init_access_list(acl_list_t *access_list) { if (!*access_list) { *access_list = sblist_new(sizeof(struct acl_s), 16); if (!*access_list) { log_message (LOG_ERR, "Unable to allocate memory for access list"); return -1; } } return 0; } /* * Inserts a new access control into the list. The function will figure out * whether the location is an IP address (with optional netmask) or a * domain name. * * Returns: * -1 on failure * 0 otherwise. */ int insert_acl (char *location, acl_access_t access_type, acl_list_t *access_list) { struct acl_s acl; assert (location != NULL); if (init_access_list(access_list) != 0) return -1; /* * Start populating the access control structure. */ memset (&acl, 0, sizeof (struct acl_s)); acl.access = access_type; if(hostspec_parse(location, &acl.h) || acl.h.type == HST_NONE) return -1; if(!sblist_add(*access_list, &acl)) return -1; return 0; } /* * This function is called whenever a "string" access control is found in * the ACL. From here we do both a text based string comparison, along with * a reverse name lookup comparison of the IP addresses. * * Return: 0 if host is denied * 1 if host is allowed * -1 if no tests match, so skip */ static int acl_string_processing (struct acl_s *acl, const char *ip_address, union sockaddr_union *addr, char *string_addr) { int match; struct addrinfo hints, *res, *ressave; size_t test_length, match_length; char ipbuf[512]; assert (acl && acl->h.type == HST_STRING); assert (ip_address && strlen (ip_address) > 0); /* * If the first character of the ACL string is a period, we need to * do a string based test only; otherwise, we can do a reverse * lookup test as well. */ if (acl->h.address.string[0] != '.') { memset (&hints, 0, sizeof (struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if (getaddrinfo (acl->h.address.string, NULL, &hints, &res) != 0) goto STRING_TEST; ressave = res; match = FALSE; do { get_ip_string (res->ai_addr, ipbuf, sizeof (ipbuf)); if (strcmp (ip_address, ipbuf) == 0) { match = TRUE; break; } } while ((res = res->ai_next) != NULL); freeaddrinfo (ressave); if (match) { if (acl->access == ACL_DENY) return 0; else return 1; } } STRING_TEST: if(string_addr[0] == 0) { /* only do costly hostname resolution when it is absolutely needed, and only once */ if(getnameinfo ((void *) addr, sizeof (*addr), string_addr, HOSTNAME_LENGTH, NULL, 0, 0) != 0) return -1; } test_length = strlen (string_addr); match_length = strlen (acl->h.address.string); /* * If the string length is shorter than AC string, return a -1 so * that the "driver" will skip onto the next control in the list. */ if (test_length < match_length) return -1; if (strcasecmp (string_addr + (test_length - match_length), acl->h.address.string) == 0) { if (acl->access == ACL_DENY) return 0; else return 1; } /* Indicate that no tests succeeded, so skip to next control. */ return -1; } /* * Compare the supplied numeric IP address with the supplied ACL structure. * * Return: * 1 IP address is allowed * 0 IP address is denied * -1 neither allowed nor denied. */ static int check_numeric_acl (const struct acl_s *acl, uint8_t addr[IPV6_LEN]) { uint8_t x, y; int i; assert (acl && acl->h.type == HST_NUMERIC); for (i = 0; i != IPV6_LEN; ++i) { x = addr[i] & acl->h.address.ip.mask[i]; y = acl->h.address.ip.network[i]; /* If x and y don't match, the IP addresses don't match */ if (x != y) return -1; } /* The addresses match, return the permission */ return (acl->access == ACL_ALLOW); } /* * Checks whether a connection is allowed. * * Returns: * 1 if allowed * 0 if denied */ int check_acl (const char *ip, union sockaddr_union *addr, acl_list_t access_list) { struct acl_s *acl; int perm = 0, is_numeric_addr; size_t i; char string_addr[HOSTNAME_LENGTH]; uint8_t numeric_addr[IPV6_LEN]; assert (ip != NULL); assert (addr != NULL); string_addr[0] = 0; /* * If there is no access list allow everything. */ if (!access_list) return 1; is_numeric_addr = (full_inet_pton (ip, &numeric_addr) > 0); for (i = 0; i < sblist_getsize (access_list); ++i) { acl = sblist_get (access_list, i); switch (acl->h.type) { case HST_STRING: perm = acl_string_processing (acl, ip, addr, string_addr); break; case HST_NUMERIC: if (ip[0] == '\0') continue; perm = is_numeric_addr ? check_numeric_acl (acl, numeric_addr) : -1; break; case HST_NONE: perm = -1; break; } /* * Check the return value too see if the IP address is * allowed or denied. */ if (perm == 0) break; else if (perm == 1) return perm; } /* * Deny all connections by default. */ log_message (LOG_NOTICE, "Unauthorized connection from \"%s\".", ip); return 0; } void flush_access_list (acl_list_t access_list) { struct acl_s *acl; size_t i; if (!access_list) { return; } /* * We need to free allocated data hanging off the acl entries * before we can free the acl entries themselves. * A hierarchical memory system would be great... */ for (i = 0; i < sblist_getsize (access_list); ++i) { acl = sblist_get (access_list, i); if (acl->h.type == HST_STRING) { safefree (acl->h.address.string); } } sblist_free (access_list); } tinyproxy-1.11.2/src/acl.h000066400000000000000000000025121461674137700154000ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 2000 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* See 'acl.c' for detailed information. */ #ifndef TINYPROXY_ACL_H #define TINYPROXY_ACL_H #include "sblist.h" #include "sock.h" typedef enum { ACL_ALLOW, ACL_DENY } acl_access_t; typedef sblist* acl_list_t; extern int insert_acl (char *location, acl_access_t access_type, acl_list_t *access_list); extern int check_acl (const char *ip_address, union sockaddr_union *addr, acl_list_t access_list); extern void flush_access_list (acl_list_t access_list); #endif tinyproxy-1.11.2/src/anonymous.c000066400000000000000000000042131461674137700166640ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 2000 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* Handles insertion and searches for headers which should be let through * when the anonymous feature is turned on. */ #include "main.h" #include "anonymous.h" #include "hsearch.h" #include "heap.h" #include "log.h" #include "conf.h" short int is_anonymous_enabled (struct config_s *conf) { return (conf->anonymous_map != NULL) ? 1 : 0; } /* * Search for the header. This function returns a positive value greater than * zero if the string was found, zero if it wasn't and negative upon error. */ int anonymous_search (struct config_s *conf, const char *s) { assert (s != NULL); assert (conf->anonymous_map != NULL); return !!htab_find (conf->anonymous_map, s); } /* * Insert a new header. * * Return -1 if there is an error, otherwise a 0 is returned if the insert was * successful. */ int anonymous_insert (struct config_s *conf, char *s) { assert (s != NULL); if (!conf->anonymous_map) { conf->anonymous_map = htab_create (32); if (!conf->anonymous_map) return -1; } if (htab_find (conf->anonymous_map, s)) { /* The key was already found. */ return 0; } /* Insert the new key */ return htab_insert (conf->anonymous_map, s, HTV_N(1)) ? 0 : -1; } tinyproxy-1.11.2/src/anonymous.h000066400000000000000000000022071461674137700166720ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 2000 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* See 'anonymous.c' for detailed information. */ #ifndef _TINYPROXY_ANONYMOUS_H_ #define _TINYPROXY_ANONYMOUS_H_ extern short int is_anonymous_enabled (struct config_s *conf); extern int anonymous_search (struct config_s *conf, const char *s); extern int anonymous_insert (struct config_s *conf, char *s); #endif tinyproxy-1.11.2/src/base64.c000066400000000000000000000031711461674137700157220ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * this file Copyright (C) 2016-2018 rofl0r * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "base64.h" static const char base64_tbl[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /* rofl0r's base64 impl (taken from libulz) takes count bytes from src, writing base64 encoded string into dst. dst needs to be at least BASE64ENC_BYTES(count) + 1 bytes in size. the string in dst will be zero-terminated. */ void base64enc(char *dst, const void* src, size_t count) { unsigned const char *s = src; char* d = dst; while(count) { int i = 0, n = *s << 16; s++; count--; if(count) { n |= *s << 8; s++; count--; i++; } if(count) { n |= *s; s++; count--; i++; } *d++ = base64_tbl[(n >> 18) & 0x3f]; *d++ = base64_tbl[(n >> 12) & 0x3f]; *d++ = i ? base64_tbl[(n >> 6) & 0x3f] : '='; *d++ = i == 2 ? base64_tbl[n & 0x3f] : '='; } *d = 0; } tinyproxy-1.11.2/src/base64.h000066400000000000000000000020641461674137700157270ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * this file Copyright (C) 2016-2018 rofl0r * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef TINYPROXY_BASE64_H #define TINYPROXY_BASE64_H #include /* calculates number of bytes base64-encoded stream of N bytes will take. */ #define BASE64ENC_BYTES(N) (((N+2)/3)*4) void base64enc(char *dst, const void* src, size_t count); #endif tinyproxy-1.11.2/src/basicauth.c000066400000000000000000000055271461674137700166100ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * This file: Copyright (C) 2016-2017 rofl0r * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "main.h" #include "basicauth.h" #include "conns.h" #include "heap.h" #include "html-error.h" #include "log.h" #include "conf.h" #include "base64.h" /* * Create basic-auth token in buf. * Returns strlen of token on success, * -1 if user/pass missing * 0 if user/pass too long */ ssize_t basicauth_string(const char *user, const char *pass, char *buf, size_t bufsize) { char tmp[256+2]; int l; if (!user || !pass) return -1; l = snprintf(tmp, sizeof tmp, "%s:%s", user, pass); if (l < 0 || l >= (ssize_t) sizeof tmp) return 0; if (bufsize < (BASE64ENC_BYTES((unsigned)l) + 1)) return 0; base64enc(buf, tmp, l); return BASE64ENC_BYTES(l); } /* * Add entry to the basicauth list */ void basicauth_add (sblist *authlist, const char *user, const char *pass) { char b[BASE64ENC_BYTES((256+2)-1) + 1], *s; ssize_t ret; ret = basicauth_string(user, pass, b, sizeof b); if (ret == -1) { log_message (LOG_WARNING, "Illegal basicauth rule: missing user or pass"); return; } else if (ret == 0) { log_message (LOG_WARNING, "User / pass in basicauth rule too long"); return; } if (!(s = safestrdup(b)) || !sblist_add(authlist, &s)) { safefree(s); log_message (LOG_ERR, "Unable to allocate memory in basicauth_add()"); return; } log_message (LOG_INFO, "Added basic auth user : %s", user); } /* * Check if a user/password combination (encoded as base64) * is in the basicauth list. * return 1 on success, 0 on failure. */ int basicauth_check (sblist *authlist, const char *authstring) { size_t i; char** entry; if (!authlist) return 0; for (i = 0; i < sblist_getsize(authlist); i++) { entry = sblist_get (authlist, i); if (entry && strcmp (authstring, *entry) == 0) return 1; } return 0; } tinyproxy-1.11.2/src/basicauth.h000066400000000000000000000023501461674137700166040ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 2005 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* See 'basicauth.c' for detailed information. */ #ifndef TINYPROXY_BASICAUTH_H #define TINYPROXY_BASICAUTH_H #include #include "sblist.h" extern ssize_t basicauth_string(const char *user, const char *pass, char *buf, size_t bufsize); extern void basicauth_add (sblist *authlist, const char *user, const char *pass); extern int basicauth_check (sblist *authlist, const char *authstring); #endif tinyproxy-1.11.2/src/buffer.c000066400000000000000000000221071461674137700161070ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 1999, 2001 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* The buffer used in each connection is a linked list of lines. As the lines * are read in and written out the buffer expands and contracts. Basically, * by using this method we can increase the buffer size dynamically. However, * we have a hard limit of 64 KB for the size of the buffer. The buffer can be * thought of as a queue were we act on both the head and tail. The various * functions act on each end (the names are taken from what Perl uses to act on * the ends of an array. :) */ #include "main.h" #include "buffer.h" #include "heap.h" #include "log.h" #define BUFFER_HEAD(x) (x)->head #define BUFFER_TAIL(x) (x)->tail struct bufline_s { unsigned char *string; /* the actual string of data */ struct bufline_s *next; /* pointer to next in linked list */ size_t length; /* length of the string of data */ size_t pos; /* start sending from this offset */ }; /* * The buffer structure points to the beginning and end of the buffer list * (and includes the total size) */ struct buffer_s { struct bufline_s *head; /* top of the buffer */ struct bufline_s *tail; /* bottom of the buffer */ size_t size; /* total size of the buffer */ }; /* * Take a string of data and a length and make a new line which can be added * to the buffer. The data IS copied, so make sure if you allocated your * data buffer on the heap, delete it because you now have TWO copies. */ static struct bufline_s *makenewline (unsigned char *data, size_t length) { struct bufline_s *newline; assert (data != NULL); assert (length > 0); newline = (struct bufline_s *) safemalloc (sizeof (struct bufline_s)); if (!newline) return NULL; newline->string = (unsigned char *) safemalloc (length); if (!newline->string) { safefree (newline); return NULL; } memcpy (newline->string, data, length); newline->next = NULL; newline->length = length; /* Position our "read" pointer at the beginning of the data */ newline->pos = 0; return newline; } /* * Free the allocated buffer line */ static void free_line (struct bufline_s *line) { assert (line != NULL); if (!line) return; if (line->string) safefree (line->string); safefree (line); } /* * Create a new buffer */ struct buffer_s *new_buffer (void) { struct buffer_s *buffptr; buffptr = (struct buffer_s *) safemalloc (sizeof (struct buffer_s)); if (!buffptr) return NULL; /* * Since the buffer is initially empty, set the HEAD and TAIL * pointers to NULL since they can't possibly point anywhere at the * moment. */ BUFFER_HEAD (buffptr) = BUFFER_TAIL (buffptr) = NULL; buffptr->size = 0; return buffptr; } /* * Delete all the lines in the buffer and the buffer itself */ void delete_buffer (struct buffer_s *buffptr) { struct bufline_s *next; assert (buffptr != NULL); while (BUFFER_HEAD (buffptr)) { next = BUFFER_HEAD (buffptr)->next; free_line (BUFFER_HEAD (buffptr)); BUFFER_HEAD (buffptr) = next; } safefree (buffptr); } /* * Return the current size of the buffer. */ size_t buffer_size (struct buffer_s *buffptr) { return buffptr->size; } /* * Push a new line on to the end of the buffer. */ int add_to_buffer (struct buffer_s *buffptr, unsigned char *data, size_t length) { struct bufline_s *newline; assert (buffptr != NULL); assert (data != NULL); assert (length > 0); /* * Sanity check here. A buffer with a non-NULL head pointer must * have a size greater than zero, and vice-versa. */ if (BUFFER_HEAD (buffptr) == NULL) assert (buffptr->size == 0); else assert (buffptr->size > 0); /* * Make a new line so we can add it to the buffer. */ if (!(newline = makenewline (data, length))) return -1; if (buffptr->size == 0) BUFFER_HEAD (buffptr) = BUFFER_TAIL (buffptr) = newline; else { BUFFER_TAIL (buffptr)->next = newline; BUFFER_TAIL (buffptr) = newline; } buffptr->size += length; return 0; } /* * Remove the first line from the top of the buffer */ static struct bufline_s *remove_from_buffer (struct buffer_s *buffptr) { struct bufline_s *line; assert (buffptr != NULL); assert (BUFFER_HEAD (buffptr) != NULL); line = BUFFER_HEAD (buffptr); BUFFER_HEAD (buffptr) = line->next; buffptr->size -= line->length; return line; } /* * Reads the bytes from the socket, and adds them to the buffer. * Takes a connection and returns the number of bytes read. */ #define READ_BUFFER_SIZE (1024 * 2) ssize_t read_buffer (int fd, struct buffer_s * buffptr) { ssize_t bytesin; unsigned char *buffer; assert (fd >= 0); assert (buffptr != NULL); /* * Don't allow the buffer to grow larger than MAXBUFFSIZE */ if (buffptr->size >= MAXBUFFSIZE) return 0; buffer = (unsigned char *) safemalloc (READ_BUFFER_SIZE); if (!buffer) { return -ENOMEM; } bytesin = read (fd, buffer, READ_BUFFER_SIZE); if (bytesin > 0) { if (add_to_buffer (buffptr, buffer, bytesin) < 0) { log_message (LOG_ERR, "readbuff: add_to_buffer() error."); bytesin = -1; } } else if (bytesin == 0) { /* connection was closed by client */ bytesin = -1; } else { switch (errno) { #ifdef EWOULDBLOCK case EWOULDBLOCK: #else # ifdef EAGAIN case EAGAIN: # endif #endif case EINTR: bytesin = 0; break; default: log_message (LOG_ERR, "read_buffer: read() failed on fd %d: %s", fd, strerror(errno)); bytesin = -1; break; } } safefree (buffer); return bytesin; } /* * Write the bytes in the buffer to the socket. * Takes a connection and returns the number of bytes written. */ ssize_t write_buffer (int fd, struct buffer_s * buffptr) { ssize_t bytessent; struct bufline_s *line; assert (fd >= 0); assert (buffptr != NULL); if (buffptr->size == 0) return 0; /* Sanity check. It would be bad to be using a NULL pointer! */ assert (BUFFER_HEAD (buffptr) != NULL); line = BUFFER_HEAD (buffptr); bytessent = send (fd, line->string + line->pos, line->length - line->pos, MSG_NOSIGNAL); if (bytessent >= 0) { /* bytes sent, adjust buffer */ line->pos += bytessent; if (line->pos == line->length) free_line (remove_from_buffer (buffptr)); return bytessent; } else { switch (errno) { #ifdef EWOULDBLOCK case EWOULDBLOCK: #else # ifdef EAGAIN case EAGAIN: # endif #endif case EINTR: return 0; case ENOBUFS: case ENOMEM: log_message (LOG_ERR, "writebuff: write() error [NOBUFS/NOMEM] \"%s\" on " "file descriptor %d", strerror (errno), fd); return 0; default: log_message (LOG_ERR, "writebuff: write() error \"%s\" on file descriptor %d", strerror (errno), fd); return -1; } } } tinyproxy-1.11.2/src/buffer.h000066400000000000000000000027331461674137700161170ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 1999 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* See 'buffer.c' for detailed information. */ #ifndef _TINYPROXY_BUFFER_H_ #define _TINYPROXY_BUFFER_H_ /* Forward declaration */ struct buffer_s; extern struct buffer_s *new_buffer (void); extern void delete_buffer (struct buffer_s *buffptr); extern size_t buffer_size (struct buffer_s *buffptr); /* * Add a new line to the given buffer. The data IS copied into the structure. */ extern int add_to_buffer (struct buffer_s *buffptr, unsigned char *data, size_t length); extern ssize_t read_buffer (int fd, struct buffer_s *buffptr); extern ssize_t write_buffer (int fd, struct buffer_s *buffptr); #endif /* __BUFFER_H_ */ tinyproxy-1.11.2/src/child.c000066400000000000000000000217561461674137700157320ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 2000 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* Handles the creation/destruction of the various children required for * processing incoming connections. */ #include "main.h" #include "child.h" #include "daemon.h" #include "filter.h" #include "heap.h" #include "log.h" #include "reqs.h" #include "sock.h" #include "utils.h" #include "conf.h" #include "sblist.h" #include "loop.h" #include "conns.h" #include "mypoll.h" #include static sblist* listen_fds; struct client { union sockaddr_union addr; }; struct child { pthread_t thread; struct client client; struct conn_s conn; volatile int done; }; static void* child_thread(void* data) { struct child *c = data; handle_connection (&c->conn, &c->client.addr); c->done = 1; return NULL; } static sblist *childs; static void collect_threads(void) { size_t i; for (i = 0; i < sblist_getsize(childs); ) { struct child *c = *((struct child**)sblist_get(childs, i)); if (c->done) { pthread_join(c->thread, 0); sblist_delete(childs, i); safefree(c); } else i++; } } /* * This is the main loop accepting new connections. */ void child_main_loop (void) { int connfd; union sockaddr_union cliaddr_storage; struct sockaddr *cliaddr = (void*) &cliaddr_storage; socklen_t clilen; int nfds = sblist_getsize(listen_fds); pollfd_struct *fds = safecalloc(nfds, sizeof *fds); ssize_t i; int ret, listenfd, was_full = 0; pthread_attr_t *attrp, attr; struct child *child; childs = sblist_new(sizeof (struct child*), config->maxclients); for (i = 0; i < nfds; i++) { int *fd = sblist_get(listen_fds, i); fds[i].fd = *fd; fds[i].events |= MYPOLL_READ; } /* * We have to wait for connections on multiple fds, * so use select/poll/whatever. */ while (!config->quit) { collect_threads(); if (sblist_getsize(childs) >= config->maxclients) { if (!was_full) log_message (LOG_WARNING, "Maximum number of connections reached. " "Refusing new connections."); was_full = 1; usleep(16); continue; } was_full = 0; listenfd = -1; /* Handle log rotation if it was requested */ if (received_sighup) { reload_config (1); #ifdef FILTER_ENABLE filter_reload (); #endif /* FILTER_ENABLE */ received_sighup = FALSE; } ret = mypoll(fds, nfds, -1); if (ret == -1) { if (errno == EINTR) { continue; } log_message (LOG_ERR, "error calling " SELECT_OR_POLL ": %s", strerror(errno)); continue; } else if (ret == 0) { log_message (LOG_WARNING, "Strange: " SELECT_OR_POLL " returned 0 " "but we did not specify a timeout..."); continue; } for (i = 0; i < nfds; i++) { if (fds[i].revents & MYPOLL_READ) { /* * only accept the connection on the first * fd that we find readable. - fair? */ listenfd = fds[i].fd; break; } } if (listenfd == -1) { log_message(LOG_WARNING, "Strange: None of our listen " "fds was readable after " SELECT_OR_POLL); continue; } /* * We have a socket that is readable. * Continue handling this connection. */ clilen = sizeof(cliaddr_storage); connfd = accept (listenfd, cliaddr, &clilen); /* * Make sure no error occurred... */ if (connfd < 0) { log_message (LOG_ERR, "Accept returned an error (%s) ... retrying.", strerror (errno)); continue; } child = safecalloc(1, sizeof(struct child)); if (!child) { oom: close(connfd); log_message (LOG_CRIT, "Could not allocate memory for child."); usleep(16); /* prevent 100% CPU usage in OOM situation */ continue; } child->done = 0; if (!sblist_add(childs, &child)) { free(child); goto oom; } conn_struct_init(&child->conn); child->conn.client_fd = connfd; memcpy(&child->client.addr, &cliaddr_storage, sizeof(cliaddr_storage)); attrp = 0; if (pthread_attr_init(&attr) == 0) { attrp = &attr; pthread_attr_setstacksize(attrp, 256*1024); } if (pthread_create(&child->thread, attrp, child_thread, child) != 0) { sblist_delete(childs, sblist_getsize(childs) -1); free(child); goto oom; } } safefree(fds); } /* * Go through all the non-empty children and cancel them. */ void child_kill_children (int sig) { size_t i, tries = 0; if (sig != SIGTERM) return; log_message (LOG_INFO, "trying to bring down %zu threads...", sblist_getsize(childs) ); again: for (i = 0; i < sblist_getsize(childs); i++) { struct child *c = *((struct child**)sblist_get(childs, i)); if (!c->done) pthread_kill(c->thread, SIGCHLD); } usleep(8192); collect_threads(); if (sblist_getsize(childs) != 0) if(tries++ < 8) goto again; if (sblist_getsize(childs) != 0) log_message (LOG_CRIT, "child_kill_children: %zu threads still alive!", sblist_getsize(childs) ); } void child_free_children(void) { sblist_free(childs); childs = 0; } /** * Listen on the various configured interfaces */ int child_listening_sockets(sblist *listen_addrs, uint16_t port) { int ret; size_t i; assert (port > 0); if (listen_fds == NULL) { listen_fds = sblist_new(sizeof(int), 16); if (listen_fds == NULL) { log_message (LOG_ERR, "Could not create the list " "of listening fds"); return -1; } } if (!listen_addrs || !sblist_getsize(listen_addrs)) { /* * no Listen directive: * listen on the wildcard address(es) */ ret = listen_sock(NULL, port, listen_fds); return ret; } for (i = 0; i < sblist_getsize(listen_addrs); i++) { char **addr; addr = sblist_get(listen_addrs, i); if (!addr || !*addr) { log_message(LOG_WARNING, "got NULL from listen_addrs - skipping"); continue; } ret = listen_sock(*addr, port, listen_fds); if (ret != 0) { return ret; } } return 0; } void child_close_sock (void) { size_t i; for (i = 0; i < sblist_getsize(listen_fds); i++) { int *fd = sblist_get(listen_fds, i); close (*fd); } sblist_free(listen_fds); listen_fds = NULL; } tinyproxy-1.11.2/src/child.h000066400000000000000000000027361461674137700157340ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 2002 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* See 'child.c' for detailed information. */ #ifndef TINYPROXY_CHILD_H #define TINYPROXY_CHILD_H #include "sblist.h" typedef enum { CHILD_MAXCLIENTS, CHILD_MAXSPARESERVERS, CHILD_MINSPARESERVERS, CHILD_STARTSERVERS, CHILD_MAXREQUESTSPERCHILD } child_config_t; extern short int child_pool_create (void); extern int child_listening_sockets (sblist *listen_addrs, uint16_t port); extern void child_close_sock (void); extern void child_main_loop (void); extern void child_kill_children (int sig); extern void child_free_children(void); extern short int child_configure (child_config_t type, unsigned int val); #endif tinyproxy-1.11.2/src/common.h000066400000000000000000000064661461674137700161450ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 2002 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* This file groups all the headers required throughout the tinyproxy * system. All this information use to be in the "main.h" header, * but various other "libraries" in the program need the same information, * without the tinyproxy specific defines. */ #ifndef COMMON_HEADER_H #define COMMON_HEADER_H #ifdef HAVE_CONFIG_H # include #endif /* * Include standard headers which are used through-out tinyproxy */ /* standard C headers - we can safely assume they exist. */ #include #include #include #include #include #include #include /* standard POSIX headers - they need to be there as well. */ # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include # include /* rest - some oddball headers */ #ifdef HAVE_VALUES_H # include #endif #ifdef HAVE_SYS_IOCTL_H # include #endif #ifdef HAVE_ALLOCA_H # include #endif #ifdef HAVE_MEMORY_H # include #endif #ifdef HAVE_MALLOC_H # include #endif #ifdef HAVE_SYSEXITS_H # include #endif /* * If MSG_NOSIGNAL is not defined, define it to be zero so that it doesn't * cause any problems. */ #ifndef MSG_NOSIGNAL # define MSG_NOSIGNAL (0) #endif #ifndef SHUT_RD /* these three Posix.1g names are quite new */ # define SHUT_RD 0 /* shutdown for reading */ # define SHUT_WR 1 /* shutdown for writing */ # define SHUT_RDWR 2 /* shutdown for reading and writing */ #endif #define MAXLISTEN 1024 /* Max number of connections */ /* * SunOS doesn't have INADDR_NONE defined. */ #ifndef INADDR_NONE # define INADDR_NONE -1 #endif /* Define boolean values */ #ifndef FALSE # define FALSE 0 # define TRUE (!FALSE) #endif /* Useful function macros */ #if !defined(min) || !defined(max) # define min(a,b) ((a) < (b) ? (a) : (b)) # define max(a,b) ((a) > (b) ? (a) : (b)) #endif #endif tinyproxy-1.11.2/src/conf-tokens.c000066400000000000000000000037621461674137700170720ustar00rootroot00000000000000#ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "conf-tokens.h" #ifdef HAVE_GPERF #include "conf-tokens-gperf.inc" #else #include const struct config_directive_entry * config_directive_find (register const char *str, register size_t len) { size_t i; static const struct config_directive_entry wordlist[] = { {"",CD_NIL}, {"",CD_NIL}, {"allow", CD_allow}, {"stathost", CD_stathost}, {"listen", CD_listen}, {"timeout", CD_timeout}, {"statfile", CD_statfile}, {"pidfile", CD_pidfile}, {"bindsame", CD_bindsame}, {"reversebaseurl", CD_reversebaseurl}, {"viaproxyname", CD_viaproxyname}, {"upstream", CD_upstream}, {"anonymous", CD_anonymous}, {"group", CD_group}, {"defaulterrorfile", CD_defaulterrorfile}, {"startservers", CD_startservers}, {"filtercasesensitive", CD_filtercasesensitive}, {"filtertype", CD_filtertype}, {"filterurls", CD_filterurls}, {"filter", CD_filter}, {"reversemagic", CD_reversemagic}, {"errorfile", CD_errorfile}, {"minspareservers", CD_minspareservers}, {"user", CD_user}, {"disableviaheader", CD_disableviaheader}, {"deny", CD_deny}, {"xtinyproxy", CD_xtinyproxy}, {"reversepath", CD_reversepath}, {"bind", CD_bind}, {"maxclients", CD_maxclients}, {"reverseonly", CD_reverseonly}, {"port", CD_port}, {"maxspareservers", CD_maxspareservers}, {"syslog", CD_syslog}, {"filterdefaultdeny", CD_filterdefaultdeny}, {"loglevel", CD_loglevel}, {"filterextended", CD_filterextended}, {"connectport", CD_connectport}, {"logfile", CD_logfile}, {"basicauth", CD_basicauth}, {"addheader", CD_addheader}, {"maxrequestsperchild", CD_maxrequestsperchild} }; for(i=0;i #include #include "conf-tokens.h" %} struct config_directive_entry { const char* name; enum config_directive value; }; %struct-type %define slot-name name %define initializer-suffix ,CD_NIL %define lookup-function-name config_directive_find %ignore-case %7bit %compare-lengths %readonly-tables %define constants-prefix CDS_ %omit-struct-type %% logfile, CD_logfile pidfile, CD_pidfile anonymous, CD_anonymous viaproxyname, CD_viaproxyname defaulterrorfile, CD_defaulterrorfile statfile, CD_statfile stathost, CD_stathost xtinyproxy, CD_xtinyproxy syslog, CD_syslog bindsame, CD_bindsame disableviaheader, CD_disableviaheader port, CD_port maxclients, CD_maxclients maxspareservers, CD_maxspareservers minspareservers, CD_minspareservers startservers, CD_startservers maxrequestsperchild, CD_maxrequestsperchild timeout, CD_timeout connectport, CD_connectport user, CD_user group, CD_group listen, CD_listen allow, CD_allow deny, CD_deny bind, CD_bind basicauth, CD_basicauth errorfile, CD_errorfile addheader, CD_addheader filter, CD_filter filterurls, CD_filterurls filterextended, CD_filterextended filterdefaultdeny, CD_filterdefaultdeny filtercasesensitive, CD_filtercasesensitive filtertype, CD_filtertype reversebaseurl, CD_reversebaseurl reverseonly, CD_reverseonly reversemagic, CD_reversemagic reversepath, CD_reversepath upstream, CD_upstream loglevel, CD_loglevel %% tinyproxy-1.11.2/src/conf-tokens.h000066400000000000000000000015611461674137700170720ustar00rootroot00000000000000#ifndef CONF_TOKENS_H #define CONF_TOKENS_H enum config_directive { CD_NIL = 0, CD_logfile, CD_pidfile, CD_anonymous, CD_viaproxyname, CD_defaulterrorfile, CD_statfile, CD_stathost, CD_xtinyproxy, CD_syslog, CD_bindsame, CD_disableviaheader, CD_port, CD_maxclients, CD_maxspareservers, CD_minspareservers, CD_startservers, CD_maxrequestsperchild, CD_timeout, CD_connectport, CD_user, CD_group, CD_listen, CD_allow, CD_deny, CD_bind, CD_basicauth, CD_errorfile, CD_addheader, CD_filter, CD_filterurls, CD_filtertype, CD_filterextended, CD_filterdefaultdeny, CD_filtercasesensitive, CD_reversebaseurl, CD_reverseonly, CD_reversemagic, CD_reversepath, CD_upstream, CD_loglevel, }; struct config_directive_entry { const char* name; enum config_directive value; }; const struct config_directive_entry * config_directive_find (register const char *str, register size_t len); #endif tinyproxy-1.11.2/src/conf.c000066400000000000000000001013071461674137700155630ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 2004 Robert James Kaes * Copyright (C) 2009 Michael Adam * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* Parses the configuration file and sets up the config_s structure for * use by the application. This file replaces the old grammar.y and * scanner.l files. It takes up less space and _I_ think is easier to * add new directives to. Who knows if I'm right though. */ #include "common.h" #include #include "conf.h" #include "acl.h" #include "anonymous.h" #include "filter.h" #include "heap.h" #include "html-error.h" #include "log.h" #include "reqs.h" #include "reverse-proxy.h" #include "upstream.h" #include "connect-ports.h" #include "basicauth.h" #include "conf-tokens.h" #ifdef LINE_MAX #define TP_LINE_MAX LINE_MAX #else #define TP_LINE_MAX 1024 #endif /* * The configuration directives are defined in the structure below. Each * directive requires a regular expression to match against, and a * function to call when the regex is matched. * * Below are defined certain constant regular expression strings that * can (and likely should) be used when building the regex for the * given directive. */ #define DIGIT "[0-9]" #define SPACE "[ \t]" #define WS SPACE "+" #define STR "\"([^\"]+)\"" #define BOOL "(yes|on|no|off)" #define INT "(()" DIGIT "+)" #define ALNUM "([-a-z0-9._]+)" #define USERNAME "([^:]*)" #define PASSWORD "([^@]*)" #define IP "((([0-9]{1,3})\\.){3}[0-9]{1,3})" #define IPMASK "(" IP "(/" DIGIT "+)?)" #define IPV6SCOPE "((%[^ \t\\/]{1,16})?)" #define IPV6 "(" \ "([0-9a-f:]{2,39})" IPV6SCOPE "|" \ "([0-9a-f:]{0,29}:" IP ")" IPV6SCOPE \ ")" #define IPV6MASK "(" IPV6 "(/" DIGIT "+)?)" #define BEGIN "^" SPACE "*" #define END SPACE "*$" /* * Limit the maximum number of substring matches to a reasonably high * number. Given the usual structure of the configuration file, sixteen * substring matches should be plenty. */ #define RE_MAX_MATCHES 33 #define CP_WARN(FMT, ...) \ log_message (LOG_WARNING, "line %lu: " FMT, lineno, __VA_ARGS__) /* * All configuration handling functions are REQUIRED to be defined * with the same function template as below. */ typedef int (*CONFFILE_HANDLER) (struct config_s *, const char *, unsigned long, regmatch_t[]); /* * Define the pattern used by any directive handling function. The * following arguments are defined: * * struct config_s* conf pointer to the current configuration structure * const char* line full line matched by the regular expression * regmatch_t match[] offsets to the substrings matched * * The handling function must return 0 if the directive was processed * properly. Any errors are reported by returning a non-zero value. */ #define HANDLE_FUNC(func) \ int func(struct config_s* conf, const char* line, \ unsigned long lineno, regmatch_t match[]) /* * List all the handling functions. These are defined later, but they need * to be in-scope before the big structure below. */ static HANDLE_FUNC (handle_disabled_feature) { fprintf (stderr, "ERROR: accessing feature that was disabled at compiletime on line %lu\n", lineno); return -1; } static HANDLE_FUNC (handle_allow); static HANDLE_FUNC (handle_basicauth); static HANDLE_FUNC (handle_anonymous); static HANDLE_FUNC (handle_bind); static HANDLE_FUNC (handle_bindsame); static HANDLE_FUNC (handle_connectport); static HANDLE_FUNC (handle_defaulterrorfile); static HANDLE_FUNC (handle_deny); static HANDLE_FUNC (handle_errorfile); static HANDLE_FUNC (handle_addheader); #ifdef FILTER_ENABLE static HANDLE_FUNC (handle_filter); static HANDLE_FUNC (handle_filtercasesensitive); static HANDLE_FUNC (handle_filterdefaultdeny); static HANDLE_FUNC (handle_filterextended); static HANDLE_FUNC (handle_filterurls); static HANDLE_FUNC (handle_filtertype); #endif static HANDLE_FUNC (handle_group); static HANDLE_FUNC (handle_listen); static HANDLE_FUNC (handle_logfile); static HANDLE_FUNC (handle_loglevel); static HANDLE_FUNC (handle_maxclients); static HANDLE_FUNC (handle_obsolete); static HANDLE_FUNC (handle_pidfile); static HANDLE_FUNC (handle_port); #ifdef REVERSE_SUPPORT static HANDLE_FUNC (handle_reversebaseurl); static HANDLE_FUNC (handle_reversemagic); static HANDLE_FUNC (handle_reverseonly); static HANDLE_FUNC (handle_reversepath); #endif static HANDLE_FUNC (handle_statfile); static HANDLE_FUNC (handle_stathost); static HANDLE_FUNC (handle_syslog); static HANDLE_FUNC (handle_timeout); static HANDLE_FUNC (handle_user); static HANDLE_FUNC (handle_viaproxyname); static HANDLE_FUNC (handle_disableviaheader); static HANDLE_FUNC (handle_xtinyproxy); #ifdef UPSTREAM_SUPPORT static HANDLE_FUNC (handle_upstream); #endif static void config_free_regex (void); /* * This macro can be used to make standard directives in the form: * directive arguments [arguments ...] * * The directive itself will be the first matched substring. * * Note that this macro is not required. As you can see below, the * comment and blank line elements are defined explicitly since they * do not follow the pattern above. This macro is for convenience * only. */ #define STDCONF(d, re, func) [CD_ ## d] = { BEGIN "()" WS re END, func, NULL } /* * Holds the regular expression used to match the configuration directive, * the function pointer to the routine to handle the directive, and * for internal use, a pointer to the compiled regex so it only needs * to be compiled one. */ struct { const char *re; CONFFILE_HANDLER handler; regex_t *cre; } directives[] = { /* string arguments */ STDCONF (logfile, STR, handle_logfile), STDCONF (pidfile, STR, handle_pidfile), STDCONF (anonymous, STR, handle_anonymous), STDCONF (viaproxyname, STR, handle_viaproxyname), STDCONF (defaulterrorfile, STR, handle_defaulterrorfile), STDCONF (statfile, STR, handle_statfile), STDCONF (stathost, STR, handle_stathost), STDCONF (xtinyproxy, BOOL, handle_xtinyproxy), /* boolean arguments */ STDCONF (syslog, BOOL, handle_syslog), STDCONF (bindsame, BOOL, handle_bindsame), STDCONF (disableviaheader, BOOL, handle_disableviaheader), /* integer arguments */ STDCONF (port, INT, handle_port), STDCONF (maxclients, INT, handle_maxclients), STDCONF (maxspareservers, INT, handle_obsolete), STDCONF (minspareservers, INT, handle_obsolete), STDCONF (startservers, INT, handle_obsolete), STDCONF (maxrequestsperchild, INT, handle_obsolete), STDCONF (timeout, INT, handle_timeout), STDCONF (connectport, INT, handle_connectport), /* alphanumeric arguments */ STDCONF (user, ALNUM, handle_user), STDCONF (group, ALNUM, handle_group), /* ip arguments */ STDCONF (listen, "(" IP "|" IPV6 ")", handle_listen), STDCONF (allow, "(" "(" IPMASK "|" IPV6MASK ")" "|" ALNUM ")", handle_allow), STDCONF (deny, "(" "(" IPMASK "|" IPV6MASK ")" "|" ALNUM ")", handle_deny), STDCONF (bind, "(" IP "|" IPV6 ")", handle_bind), /* other */ STDCONF (basicauth, USERNAME WS PASSWORD, handle_basicauth), STDCONF (errorfile, INT WS STR, handle_errorfile), STDCONF (addheader, STR WS STR, handle_addheader), #ifdef FILTER_ENABLE /* filtering */ STDCONF (filter, STR, handle_filter), STDCONF (filterurls, BOOL, handle_filterurls), STDCONF (filterextended, BOOL, handle_filterextended), STDCONF (filterdefaultdeny, BOOL, handle_filterdefaultdeny), STDCONF (filtercasesensitive, BOOL, handle_filtercasesensitive), STDCONF (filtertype, "(bre|ere|fnmatch)", handle_filtertype), #endif #ifdef REVERSE_SUPPORT /* Reverse proxy arguments */ STDCONF (reversebaseurl, STR, handle_reversebaseurl), STDCONF (reverseonly, BOOL, handle_reverseonly), STDCONF (reversemagic, BOOL, handle_reversemagic), STDCONF (reversepath, STR "(" WS STR ")?", handle_reversepath), #endif #ifdef UPSTREAM_SUPPORT STDCONF (upstream, "(" "(none)" WS STR ")|" \ "(" "(http|socks4|socks5)" WS \ "(" USERNAME /*username*/ ":" PASSWORD /*password*/ "@" ")?" "(" IP "|" "\\[(" IPV6 ")\\]" "|" ALNUM ")" ":" INT "(" WS STR ")?" ")", handle_upstream), #endif /* loglevel */ STDCONF (loglevel, "(critical|error|warning|notice|connect|info)", handle_loglevel) }; const unsigned int ndirectives = sizeof (directives) / sizeof (directives[0]); static void free_added_headers (sblist* add_headers) { size_t i; if (!add_headers) return; for (i = 0; i < sblist_getsize (add_headers); i++) { http_header_t *header = sblist_get (add_headers, i); safefree (header->name); safefree (header->value); } sblist_free (add_headers); } static void stringlist_free(sblist *sl) { size_t i; char **s; if(sl) { for(i = 0; i < sblist_getsize(sl); i++) { s = sblist_get(sl, i); if(s) safefree(*s); } sblist_free(sl); } } void free_config (struct config_s *conf) { char *k; htab_value *v; size_t it; safefree (conf->logf_name); safefree (conf->stathost); safefree (conf->user); safefree (conf->group); stringlist_free(conf->basicauth_list); stringlist_free(conf->listen_addrs); stringlist_free(conf->bind_addrs); #ifdef FILTER_ENABLE safefree (conf->filter); #endif /* FILTER_ENABLE */ #ifdef REVERSE_SUPPORT free_reversepath_list(conf->reversepath_list); safefree (conf->reversebaseurl); #endif #ifdef UPSTREAM_SUPPORT free_upstream_list (conf->upstream_list); #endif /* UPSTREAM_SUPPORT */ safefree (conf->pidpath); safefree (conf->via_proxy_name); if (conf->errorpages) { it = 0; while((it = htab_next(conf->errorpages, it, &k, &v))) { safefree(k); safefree(v->p); } htab_destroy (conf->errorpages); } free_added_headers (conf->add_headers); safefree (conf->errorpage_undef); safefree (conf->statpage); flush_access_list (conf->access_list); free_connect_ports_list (conf->connect_ports); if (conf->anonymous_map) { it = 0; while((it = htab_next(conf->anonymous_map, it, &k, &v))) safefree(k); htab_destroy (conf->anonymous_map); } memset (conf, 0, sizeof(*conf)); } /* * Initializes Config parser. Currently this means: * Compiles the regular expressions used by the configuration file. This * routine MUST be called before trying to parse the configuration file. * * Returns 0 on success; negative upon failure. */ int config_init (void) { unsigned int i, r; for (i = 0; i != ndirectives; ++i) { assert (!directives[i].cre); if (!directives[i].handler) { directives[i].handler = handle_disabled_feature; continue; } directives[i].cre = (regex_t *) safemalloc (sizeof (regex_t)); if (!directives[i].cre) return -1; r = regcomp (directives[i].cre, directives[i].re, REG_EXTENDED | REG_ICASE | REG_NEWLINE); if (r) return r; } atexit (config_free_regex); return 0; } /* * Frees pre-compiled regular expressions used by the configuration * file. This function is registered to be automatically called at exit. */ static void config_free_regex (void) { unsigned int i; for (i = 0; i < ndirectives; i++) { if (directives[i].cre) { regfree (directives[i].cre); safefree (directives[i].cre); directives[i].cre = NULL; } } } /* * Attempt to match the supplied line with any of the configuration * regexes defined above. If a match is found, call the handler * function to process the directive. * * Returns 0 if a match was found and successfully processed; otherwise, * a negative number is returned. */ static int check_match (struct config_s *conf, const char *line, unsigned long lineno, enum config_directive cd) { regmatch_t match[RE_MAX_MATCHES]; unsigned int i = cd; if (!directives[i].cre) return (*directives[i].handler) (conf, line, lineno, match); if (!regexec (directives[i].cre, line, RE_MAX_MATCHES, match, 0)) return (*directives[i].handler) (conf, line, lineno, match); return -1; } /* * Parse the previously opened configuration stream. */ static int config_parse (struct config_s *conf, FILE * f) { char buffer[TP_LINE_MAX], *p, *q, c; const struct config_directive_entry *e; unsigned long lineno = 1; for (;fgets (buffer, sizeof (buffer), f);++lineno) { if(buffer[0] == '#') continue; p = buffer; while(isspace(*p))p++; if(!*p) continue; q = p; while(*q && !isspace(*q))q++; c = *q; *q = 0; e = config_directive_find(p, strlen(p)); *q = c; if (!e || e->value == CD_NIL || check_match (conf, q, lineno, e->value)) { fprintf (stderr, "ERROR: Syntax error on line %lu\n", lineno); return 1; } } return 0; } /** * Read the settings from a config file. */ static int load_config_file (const char *config_fname, struct config_s *conf) { FILE *config_file; int ret = -1; config_file = fopen (config_fname, "r"); if (!config_file) { fprintf (stderr, "%s: Could not open config file \"%s\".\n", PACKAGE, config_fname); goto done; } if (config_parse (conf, config_file)) { fprintf (stderr, "Unable to parse config file. " "Not starting.\n"); goto done; } ret = 0; done: if (config_file) fclose (config_file); return ret; } static void initialize_config_defaults (struct config_s *conf) { memset (conf, 0, sizeof(*conf)); /* * Make sure the HTML error pages array is NULL to begin with. * (FIXME: Should have a better API for all this) */ conf->errorpages = NULL; conf->stathost = safestrdup (TINYPROXY_STATHOST); conf->idletimeout = MAX_IDLE_TIME; conf->logf_name = NULL; conf->pidpath = NULL; conf->maxclients = 100; } /** * Load the configuration. */ int reload_config_file (const char *config_fname, struct config_s *conf) { int ret; initialize_config_defaults (conf); ret = load_config_file (config_fname, conf); if (ret != 0) { goto done; } /* Set the default values if they were not set in the config file. */ if (conf->port == 0) { /* * Don't log here in error path: * logging might not be set up yet! */ fprintf (stderr, PACKAGE ": You MUST set a Port in the " "config file.\n"); ret = -1; goto done; } if (!conf->user && !geteuid()) { log_message (LOG_WARNING, "You SHOULD set a UserName in the " "config file. Using current user instead."); } if (conf->idletimeout == 0) { log_message (LOG_WARNING, "Invalid idle time setting. " "Only values greater than zero are allowed. " "Therefore setting idle timeout to %u seconds.", MAX_IDLE_TIME); conf->idletimeout = MAX_IDLE_TIME; } done: return ret; } /*********************************************************************** * * The following are basic data extraction building blocks that can * be used to simplify the parsing of a directive. * ***********************************************************************/ static char *get_string_arg (const char *line, regmatch_t * match) { char *p; const unsigned int len = match->rm_eo - match->rm_so; assert (line); assert (len > 0); p = (char *) safemalloc (len + 1); if (!p) return NULL; memcpy (p, line + match->rm_so, len); p[len] = '\0'; return p; } static int set_string_arg (char **var, const char *line, regmatch_t * match) { char *arg = get_string_arg (line, match); if (!arg) return -1; if (*var != NULL) { safefree (*var); } *var = arg; return 0; } static int get_bool_arg (const char *line, regmatch_t * match) { const char *p = line + match->rm_so; assert (line); assert (match && match->rm_so != -1); /* "y"es or o"n" map as true, otherwise it's false. */ if (tolower (p[0]) == 'y' || tolower (p[1]) == 'n') return 1; else return 0; } static int set_bool_arg (unsigned int *var, const char *line, regmatch_t * match) { assert (var); assert (line); assert (match && match->rm_so != -1); *var = get_bool_arg (line, match); return 0; } static unsigned long get_long_arg (const char *line, regmatch_t * match) { assert (line); assert (match && match->rm_so != -1); return strtoul (line + match->rm_so, NULL, 0); } static int set_int_arg (unsigned int *var, const char *line, regmatch_t * match) { assert (var); assert (line); assert (match); *var = (unsigned int) get_long_arg (line, match); return 0; } /*********************************************************************** * * Below are all the directive handling functions. You will notice * that most of the directives delegate to one of the basic data * extraction routines. This is deliberate. To add a new directive * to tinyproxy only requires you to define the regular expression * above and then figure out what data extract routine to use. * * However, you will also notice that more complicated directives are * possible. You can make your directive as complicated as you require * to express a solution to the problem you're tackling. * * See the definition/comment about the HANDLE_FUNC() macro to learn * what arguments are supplied to the handler, and to determine what * values to return. * ***********************************************************************/ static HANDLE_FUNC (handle_logfile) { return set_string_arg (&conf->logf_name, line, &match[2]); } static HANDLE_FUNC (handle_pidfile) { return set_string_arg (&conf->pidpath, line, &match[2]); } static HANDLE_FUNC (handle_anonymous) { char *arg = get_string_arg (line, &match[2]); if (!arg) return -1; if(anonymous_insert (conf, arg) < 0) { CP_WARN ("anonymous_insert() failed: '%s'", arg); safefree(arg); return -1; } return 0; } static HANDLE_FUNC (handle_viaproxyname) { int r = set_string_arg (&conf->via_proxy_name, line, &match[2]); if (r) return r; log_message (LOG_INFO, "Setting \"Via\" header to '%s'", conf->via_proxy_name); return 0; } static HANDLE_FUNC (handle_disableviaheader) { int r = set_bool_arg (&conf->disable_viaheader, line, &match[2]); if (r) { return r; } log_message (LOG_INFO, "Disabling transmission of the \"Via\" header."); return 0; } static HANDLE_FUNC (handle_defaulterrorfile) { return set_string_arg (&conf->errorpage_undef, line, &match[2]); } static HANDLE_FUNC (handle_statfile) { return set_string_arg (&conf->statpage, line, &match[2]); } static HANDLE_FUNC (handle_stathost) { int r = set_string_arg (&conf->stathost, line, &match[2]); if (r) return r; log_message (LOG_INFO, "Stathost set to \"%s\"", conf->stathost); return 0; } static HANDLE_FUNC (handle_xtinyproxy) { #ifdef XTINYPROXY_ENABLE return set_bool_arg (&conf->add_xtinyproxy, line, &match[2]); #else if(!get_bool_arg(line, &match[2])) return 0; fprintf (stderr, "XTinyproxy NOT Enabled! Recompile with --enable-xtinyproxy\n"); return 1; #endif } static HANDLE_FUNC (handle_syslog) { return set_bool_arg (&conf->syslog, line, &match[2]); } static HANDLE_FUNC (handle_bindsame) { int r = set_bool_arg (&conf->bindsame, line, &match[2]); if (r) return r; log_message (LOG_INFO, "Binding outgoing connection to incoming IP"); return 0; } static HANDLE_FUNC (handle_port) { set_int_arg (&conf->port, line, &match[2]); if (conf->port > 65535) { fprintf (stderr, "Bad port number (%d) supplied for Port.\n", conf->port); return 1; } return 0; } static HANDLE_FUNC (handle_maxclients) { set_int_arg (&conf->maxclients, line, &match[2]); return 0; } static HANDLE_FUNC (handle_obsolete) { fprintf (stderr, "WARNING: obsolete config item on line %lu\n", lineno); return 0; } static HANDLE_FUNC (handle_timeout) { return set_int_arg (&conf->idletimeout, line, &match[2]); } static HANDLE_FUNC (handle_connectport) { add_connect_port_allowed (get_long_arg (line, &match[2]), &conf->connect_ports); return 0; } static HANDLE_FUNC (handle_user) { return set_string_arg (&conf->user, line, &match[2]); } static HANDLE_FUNC (handle_group) { return set_string_arg (&conf->group, line, &match[2]); } static void warn_invalid_address(char *arg, unsigned long lineno) { CP_WARN ("Invalid address %s", arg); } static HANDLE_FUNC (handle_allow) { char *arg = get_string_arg (line, &match[2]); if(insert_acl (arg, ACL_ALLOW, &conf->access_list) < 0) warn_invalid_address (arg, lineno); safefree (arg); return 0; } static HANDLE_FUNC (handle_deny) { char *arg = get_string_arg (line, &match[2]); if(insert_acl (arg, ACL_DENY, &conf->access_list) < 0) warn_invalid_address (arg, lineno); safefree (arg); return 0; } static HANDLE_FUNC (handle_bind) { char *arg = get_string_arg (line, &match[2]); if (arg == NULL) { return -1; } if (conf->bind_addrs == NULL) { conf->bind_addrs = sblist_new(sizeof(char*), 16); if (conf->bind_addrs == NULL) { CP_WARN ("Could not create a list " "of bind addresses.", ""); safefree(arg); return -1; } } sblist_add (conf->bind_addrs, &arg); log_message (LOG_INFO, "Added bind address [%s] for outgoing connections.", arg); return 0; } static HANDLE_FUNC (handle_listen) { char *arg = get_string_arg (line, &match[2]); if (arg == NULL) { return -1; } if (conf->listen_addrs == NULL) { conf->listen_addrs = sblist_new(sizeof(char*), 16); if (conf->listen_addrs == NULL) { CP_WARN ("Could not create a list " "of listen addresses.", ""); safefree(arg); return -1; } } sblist_add (conf->listen_addrs, &arg); log_message(LOG_INFO, "Added address [%s] to listen addresses.", arg); return 0; } static HANDLE_FUNC (handle_errorfile) { /* * Because an integer is defined as ((0x)?[[:digit:]]+) _two_ * match places are used. match[2] matches the full digit * string, while match[3] matches only the "0x" part if * present. This is why the "string" is located at * match[4] (rather than the more intuitive match[3]. */ unsigned long int err = get_long_arg (line, &match[2]); char *page = get_string_arg (line, &match[4]); if(add_new_errorpage (conf, page, err) < 0) { CP_WARN ("add_new_errorpage() failed: '%s'", page); safefree (page); } return 0; } static HANDLE_FUNC (handle_addheader) { char *name = get_string_arg (line, &match[2]); char *value = get_string_arg (line, &match[3]); http_header_t header; if (!conf->add_headers) { conf->add_headers = sblist_new (sizeof(http_header_t), 16); } header.name = name; header.value = value; sblist_add (conf->add_headers, &header); /* Don't free name or value here, as they are referenced in the * struct inserted into the vector. */ return 0; } /* * Log level's strings. */ struct log_levels_s { const char *string; int level; }; static struct log_levels_s log_levels[] = { {"critical", LOG_CRIT}, {"error", LOG_ERR}, {"warning", LOG_WARNING}, {"notice", LOG_NOTICE}, {"connect", LOG_CONN}, {"info", LOG_INFO} }; static HANDLE_FUNC (handle_loglevel) { static const unsigned int nlevels = sizeof (log_levels) / sizeof (log_levels[0]); unsigned int i; char *arg = get_string_arg (line, &match[2]); for (i = 0; i != nlevels; ++i) { if (!strcasecmp (arg, log_levels[i].string)) { set_log_level (log_levels[i].level); safefree (arg); return 0; } } safefree (arg); return -1; } static HANDLE_FUNC (handle_basicauth) { char *user, *pass; user = get_string_arg(line, &match[2]); if (!user) return -1; pass = get_string_arg(line, &match[3]); if (!pass) { safefree (user); return -1; } if (!conf->basicauth_list) { conf->basicauth_list = sblist_new (sizeof(char*), 16); } basicauth_add (conf->basicauth_list, user, pass); safefree (user); safefree (pass); return 0; } #ifdef FILTER_ENABLE static void warn_deprecated(const char *arg, unsigned long lineno) { CP_WARN ("deprecated option %s", arg); } static HANDLE_FUNC (handle_filter) { return set_string_arg (&conf->filter, line, &match[2]); } static HANDLE_FUNC (handle_filterurls) { conf->filter_opts |= get_bool_arg (line, &match[2]) * FILTER_OPT_URL; return 0; } static HANDLE_FUNC (handle_filterextended) { warn_deprecated("FilterExtended, use FilterType", lineno); conf->filter_opts |= get_bool_arg (line, &match[2]) * FILTER_OPT_TYPE_ERE; return 0; } static HANDLE_FUNC (handle_filterdefaultdeny) { assert (match[2].rm_so != -1); conf->filter_opts |= get_bool_arg (line, &match[2]) * FILTER_OPT_DEFAULT_DENY; return 0; } static HANDLE_FUNC (handle_filtercasesensitive) { conf->filter_opts |= get_bool_arg (line, &match[2]) * FILTER_OPT_CASESENSITIVE; return 0; } static HANDLE_FUNC (handle_filtertype) { static const struct { unsigned short flag; char type[8]; } ftmap[] = { {FILTER_OPT_TYPE_ERE, "ere"}, {FILTER_OPT_TYPE_BRE, "bre"}, {FILTER_OPT_TYPE_FNMATCH, "fnmatch"}, }; char *type; unsigned i; type = get_string_arg(line, &match[2]); if (!type) return -1; for(i=0;ifilter_opts |= ftmap[i].flag; safefree (type); return 0; } #endif #ifdef REVERSE_SUPPORT static HANDLE_FUNC (handle_reverseonly) { return set_bool_arg (&conf->reverseonly, line, &match[2]); } static HANDLE_FUNC (handle_reversemagic) { return set_bool_arg (&conf->reversemagic, line, &match[2]); } static HANDLE_FUNC (handle_reversebaseurl) { return set_string_arg (&conf->reversebaseurl, line, &match[2]); } static HANDLE_FUNC (handle_reversepath) { /* * The second string argument is optional. */ char *arg1, *arg2; arg1 = get_string_arg (line, &match[2]); if (!arg1) return -1; if (match[4].rm_so != -1) { arg2 = get_string_arg (line, &match[4]); if (!arg2) { safefree (arg1); return -1; } reversepath_add (arg1, arg2, &conf->reversepath_list); safefree (arg1); safefree (arg2); } else { reversepath_add (NULL, arg1, &conf->reversepath_list); safefree (arg1); } return 0; } #endif #ifdef UPSTREAM_SUPPORT static enum proxy_type pt_from_string(const char *s) { static const char pt_map[][7] = { [PT_NONE] = "none", [PT_HTTP] = "http", [PT_SOCKS4] = "socks4", [PT_SOCKS5] = "socks5", }; unsigned i; for (i = 0; i < sizeof(pt_map)/sizeof(pt_map[0]); i++) if (!strcmp(pt_map[i], s)) return i; return PT_NONE; } static HANDLE_FUNC (handle_upstream) { char *ip; int port, mi; char *domain = 0, *user = 0, *pass = 0, *tmp; enum proxy_type pt; enum upstream_build_error ube; if (match[3].rm_so != -1) { tmp = get_string_arg (line, &match[3]); if(!strcmp(tmp, "none")) { safefree(tmp); if (match[4].rm_so == -1) return -1; domain = get_string_arg (line, &match[4]); if (!domain) return -1; ube = upstream_add (NULL, 0, domain, 0, 0, PT_NONE, &conf->upstream_list); safefree (domain); goto check_err; } } mi = 6; tmp = get_string_arg (line, &match[mi]); pt = pt_from_string(tmp); safefree(tmp); mi += 2; if (match[mi].rm_so != -1) user = get_string_arg (line, &match[mi]); mi++; if (match[mi].rm_so != -1) pass = get_string_arg (line, &match[mi]); mi++; if (match[mi+4].rm_so != -1) /* IPv6 address in square brackets */ ip = get_string_arg (line, &match[mi+4]); else ip = get_string_arg (line, &match[mi]); if (!ip) return -1; mi += 16; port = (int) get_long_arg (line, &match[mi]); mi += 3; if (match[mi].rm_so != -1) domain = get_string_arg (line, &match[mi]); ube = upstream_add (ip, port, domain, user, pass, pt, &conf->upstream_list); safefree (user); safefree (pass); safefree (domain); safefree (ip); check_err:; if(ube != UBE_SUCCESS) CP_WARN("%s", upstream_build_error_string(ube)); return 0; } #endif tinyproxy-1.11.2/src/conf.h000066400000000000000000000065131461674137700155730ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 2004 Robert James Kaes * Copyright (C) 2009 Michael Adam * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* See 'conf.c' for detailed information. */ #ifndef TINYPROXY_CONF_H #define TINYPROXY_CONF_H #include "hsearch.h" #include "sblist.h" #include "acl.h" /* * Stores a HTTP header created using the AddHeader directive. */ typedef struct { char *name; char *value; } http_header_t; /* * Hold all the configuration time information. */ struct config_s { sblist *basicauth_list; char *logf_name; unsigned int syslog; /* boolean */ unsigned int port; char *stathost; unsigned int quit; /* boolean */ unsigned int maxclients; char *user; char *group; sblist *listen_addrs; #ifdef FILTER_ENABLE char *filter; unsigned int filter_opts; /* enum filter_options */ #endif /* FILTER_ENABLE */ #ifdef XTINYPROXY_ENABLE unsigned int add_xtinyproxy; /* boolean */ #endif #ifdef REVERSE_SUPPORT struct reversepath *reversepath_list; unsigned int reverseonly; /* boolean */ unsigned int reversemagic; /* boolean */ char *reversebaseurl; #endif #ifdef UPSTREAM_SUPPORT struct upstream *upstream_list; #endif /* UPSTREAM_SUPPORT */ char *pidpath; unsigned int idletimeout; sblist *bind_addrs; unsigned int bindsame; /* * The configured name to use in the HTTP "Via" header field. */ char *via_proxy_name; unsigned int disable_viaheader; /* boolean */ /* * Error page support. Map error numbers to file paths. */ struct htab *errorpages; /* * Error page to be displayed if appropriate page cannot be located * in the errorpages structure. */ char *errorpage_undef; /* * The HTML statistics page. */ char *statpage; acl_list_t access_list; /* * Store the list of port allowed by CONNECT. */ sblist *connect_ports; /* * Map of headers which should be let through when the * anonymous feature is turned on. */ struct htab *anonymous_map; /* * Extra headers to be added to outgoing HTTP requests. */ sblist* add_headers; }; extern int reload_config_file (const char *config_fname, struct config_s *conf); int config_init (void); void free_config (struct config_s *conf); #endif tinyproxy-1.11.2/src/connect-ports.c000066400000000000000000000046321461674137700174370ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 1998 Steven Young * Copyright (C) 1999-2005 Robert James Kaes * Copyright (C) 2009 Michael Adam * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "connect-ports.h" #include "log.h" /* * Now, this routine adds a "port" to the list. It also creates the list if * it hasn't already by done. */ void add_connect_port_allowed (int port, sblist **connect_ports) { if (!*connect_ports) { *connect_ports = sblist_new (sizeof(int), 16); if (!*connect_ports) { log_message (LOG_WARNING, "Could not create a list of allowed CONNECT ports"); return; } } log_message (LOG_INFO, "Adding Port [%d] to the list allowed by CONNECT", port); sblist_add (*connect_ports, &port); } /* * This routine checks to see if a port is allowed in the CONNECT method. * * Returns: 1 if allowed * 0 if denied */ int check_allowed_connect_ports (int port, sblist *connect_ports) { size_t i; int *data; /* * The absence of ConnectPort options in the config file * meanas that all ports are allowed for CONNECT. */ if (!connect_ports) return 1; for (i = 0; i < sblist_getsize (connect_ports); ++i) { data = sblist_get (connect_ports, i); if (data && *data == port) return 1; } return 0; } /** * Free a connect_ports list. */ void free_connect_ports_list (sblist *connect_ports) { sblist_free (connect_ports); } tinyproxy-1.11.2/src/connect-ports.h000066400000000000000000000024241461674137700174410ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 1998 Steven Young * Copyright (C) 1999 Robert James Kaes * Copyright (C) 2009 Michael Adam * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _TINYPROXY_CONNECT_PORTS_H_ #define _TINYPROXY_CONNECT_PORTS_H_ #include "common.h" #include "sblist.h" extern void add_connect_port_allowed (int port, sblist **connect_ports); int check_allowed_connect_ports (int port, sblist *connect_ports); void free_connect_ports_list (sblist *connect_ports); #endif /* _TINYPROXY_CONNECT_PORTS_ */ tinyproxy-1.11.2/src/conns.c000066400000000000000000000100651461674137700157560ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 2001 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* Create and free the connection structure. One day there could be * other connection related tasks put here, but for now the header * file and this file are only used for create/free functions and the * connection structure definition. */ #include "main.h" #include "buffer.h" #include "conns.h" #include "heap.h" #include "log.h" #include "stats.h" void conn_struct_init(struct conn_s *connptr) { connptr->error_number = -1; connptr->client_fd = -1; connptr->server_fd = -1; /* There is _no_ content length initially */ connptr->content_length.server = connptr->content_length.client = -1; } int conn_init_contents (struct conn_s *connptr, const char *ipaddr, const char *sock_ipaddr) { struct buffer_s *cbuffer, *sbuffer; assert (connptr->client_fd >= 0); /* * Allocate the memory for all the internal components */ cbuffer = new_buffer (); sbuffer = new_buffer (); if (!cbuffer || !sbuffer) goto error_exit; connptr->cbuffer = cbuffer; connptr->sbuffer = sbuffer; connptr->server_ip_addr = (sock_ipaddr ? safestrdup (sock_ipaddr) : NULL); connptr->client_ip_addr = safestrdup (ipaddr); update_stats (STAT_OPEN); return 1; error_exit: /* * If we got here, there was a problem allocating memory */ if (cbuffer) delete_buffer (cbuffer); if (sbuffer) delete_buffer (sbuffer); return 0; } void conn_destroy_contents (struct conn_s *connptr) { assert (connptr != NULL); if (connptr->client_fd != -1) if (close (connptr->client_fd) < 0) log_message (LOG_INFO, "Client (%d) close message: %s", connptr->client_fd, strerror (errno)); connptr->client_fd = -1; if (connptr->server_fd != -1) if (close (connptr->server_fd) < 0) log_message (LOG_INFO, "Server (%d) close message: %s", connptr->server_fd, strerror (errno)); connptr->server_fd = -1; if (connptr->cbuffer) delete_buffer (connptr->cbuffer); if (connptr->sbuffer) delete_buffer (connptr->sbuffer); if (connptr->request_line) safefree (connptr->request_line); if (connptr->error_variables) { char *k; htab_value *v; size_t it = 0; while((it = htab_next(connptr->error_variables, it, &k, &v))) { safefree(v->p); safefree(k); } htab_destroy (connptr->error_variables); } if (connptr->error_string) safefree (connptr->error_string); if (connptr->server_ip_addr) safefree (connptr->server_ip_addr); if (connptr->client_ip_addr) safefree (connptr->client_ip_addr); #ifdef REVERSE_SUPPORT if (connptr->reversepath) safefree (connptr->reversepath); #endif update_stats (STAT_CLOSE); } tinyproxy-1.11.2/src/conns.h000066400000000000000000000053751461674137700157730ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 2001 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* See 'conns.c' for detailed information. */ #ifndef TINYPROXY_CONNS_H #define TINYPROXY_CONNS_H #include "main.h" #include "hsearch.h" /* * Connection Definition */ struct conn_s { int client_fd; int server_fd; struct buffer_s *cbuffer; struct buffer_s *sbuffer; /* The request line (first line) from the client */ char *request_line; /* Booleans */ unsigned int connect_method; unsigned int show_stats; /* * This structure stores key -> value mappings for substitution * in the error HTML files. */ struct htab *error_variables; int error_number; char *error_string; /* A Content-Length value from the remote server */ struct { long int server; long int client; } content_length; /* * Store the server's IP (for BindSame) */ char *server_ip_addr; /* * Store the client's IP information */ char *client_ip_addr; /* * Store the incoming request's HTTP protocol. */ struct { unsigned int major; unsigned int minor; } protocol; #ifdef REVERSE_SUPPORT /* * Place to store the current per-connection reverse proxy path */ char *reversepath; #endif /* * Pointer to upstream proxy. */ struct upstream *upstream_proxy; }; /* expects pointer to zero-initialized struct, set up struct with default values for initial use */ extern void conn_struct_init(struct conn_s *connptr); /* second stage initializiation, sets up buffers and connection details */ extern int conn_init_contents (struct conn_s *connptr, const char *ipaddr, const char *sock_ipaddr); extern void conn_destroy_contents (struct conn_s *connptr); #endif tinyproxy-1.11.2/src/daemon.c000066400000000000000000000045571461674137700161120ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 2002 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* This file contains functions which are useful when writing a * daemon process. The functions include a "makedaemon" function and * a function to portably set a signal handler. */ #include "main.h" #include "daemon.h" #include "log.h" /* * Fork a child process and then kill the parent so make the calling * program a daemon process. */ void makedaemon (void) { if (fork () != 0) exit (0); setsid (); set_signal_handler (SIGHUP, SIG_IGN); if (fork () != 0) exit (0); if (chdir ("/") != 0) { log_message (LOG_WARNING, "Could not change directory to /"); } umask (0177); #ifdef NDEBUG /* * When not in debugging mode, close the standard file * descriptors. */ close (0); close (1); close (2); #endif } /* * Pass a signal number and a signal handling function into this function * to handle signals sent to the process. */ signal_func *set_signal_handler (int signo, signal_func * func) { struct sigaction act, oact; act.sa_handler = func; sigemptyset (&act.sa_mask); act.sa_flags = 0; if (signo == SIGALRM) { #ifdef SA_INTERRUPT act.sa_flags |= SA_INTERRUPT; /* SunOS 4.x */ #endif } else { #ifdef SA_RESTART act.sa_flags |= SA_RESTART; /* SVR4, 4.4BSD */ #endif } if (sigaction (signo, &act, &oact) < 0) return SIG_ERR; return oact.sa_handler; } tinyproxy-1.11.2/src/daemon.h000066400000000000000000000022611461674137700161050ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 2002 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* See 'daemon.c' for detailed information. */ #ifndef TINYPROXY_DAEMON_H #define TINYPROXY_DAEMON_H typedef void signal_func (int); /* * Pass a singal integer and a function to handle the signal. */ extern signal_func *set_signal_handler (int signo, signal_func * func); /* * Make a program a daemon process */ extern void makedaemon (void); #endif tinyproxy-1.11.2/src/filter.c000066400000000000000000000145451461674137700161320ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 1999 George Talusan * Copyright (C) 2002 James E. Flemer * Copyright (C) 2002 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* A substring of the domain to be filtered goes into the file * pointed at by DEFAULT_FILTER. */ #include "main.h" #include #include #include "filter.h" #include "heap.h" #include "log.h" #include "reqs.h" #include "conf.h" #include "sblist.h" #define FILTER_BUFFER_LEN (512) static int err; struct filter_list { union { regex_t cpatb; char *pattern; } u; }; static sblist *fl = NULL; static int already_init = 0; /* * Initializes a list of strings containing hosts/urls to be filtered */ void filter_init (void) { FILE *fd; struct filter_list fe; char buf[FILTER_BUFFER_LEN]; char *s, *start; int cflags, lineno = 0; if (fl || already_init) { return; } fd = fopen (config->filter, "r"); if (!fd) { perror ("filter file"); exit (EX_DATAERR); } cflags = REG_NEWLINE | REG_NOSUB; cflags |= (REG_EXTENDED * !!(config->filter_opts & FILTER_OPT_TYPE_ERE)); cflags |= (REG_ICASE * !(config->filter_opts & FILTER_OPT_CASESENSITIVE)); while (fgets (buf, FILTER_BUFFER_LEN, fd)) { ++lineno; /* skip leading whitespace */ s = buf; while (*s && isspace ((unsigned char) *s)) s++; start = s; /* * Remove any trailing white space and * comments. */ while (*s) { if (isspace ((unsigned char) *s)) break; if (*s == '#') { /* * If the '#' char is preceeded by * an escape, it's not a comment * string. */ if (s == buf || *(s - 1) != '\\') break; } ++s; } *s = '\0'; s = start; /* skip blank lines and comments */ if (*s == '\0') continue; if (!fl) fl = sblist_new(sizeof(struct filter_list), 4096/sizeof(struct filter_list)); if (config->filter_opts & FILTER_OPT_TYPE_FNMATCH) { fe.u.pattern = safestrdup(s); if (!fe.u.pattern) goto oom; } else { err = regcomp (&fe.u.cpatb, s, cflags); if (err != 0) { if (err == REG_ESPACE) goto oom; fprintf (stderr, "Bad regex in %s: line %d - %s\n", config->filter, lineno, s); exit (EX_DATAERR); } } if (!sblist_add(fl, &fe)) { oom:; fprintf (stderr, "out of memory parsing filter file %s: line %d\n", config->filter, lineno); exit (EX_DATAERR); } } if (ferror (fd)) { perror ("fgets"); exit (EX_DATAERR); } fclose (fd); already_init = 1; } /* unlink the list */ void filter_destroy (void) { struct filter_list *p; size_t i; if (already_init) { if (fl) { for (i = 0; i < sblist_getsize(fl); ++i) { p = sblist_get(fl, i); if (config->filter_opts & FILTER_OPT_TYPE_FNMATCH) safefree(p->u.pattern); else regfree (&p->u.cpatb); } sblist_free(fl); } fl = NULL; already_init = 0; } } /** * reload the filter file if filtering is enabled */ void filter_reload (void) { if (config->filter) { log_message (LOG_NOTICE, "Re-reading filter file."); filter_destroy (); filter_init (); } } /* Return 0 to allow, non-zero to block */ int filter_run (const char *str) { struct filter_list *p; size_t i; int result; if (!fl || !already_init) goto COMMON_EXIT; for (i = 0; i < sblist_getsize(fl); ++i) { p = sblist_get(fl, i); if (config->filter_opts & FILTER_OPT_TYPE_FNMATCH) result = fnmatch (p->u.pattern, str, 0); else result = regexec (&p->u.cpatb, str, (size_t) 0, (regmatch_t *) 0, 0); if (result == 0) { if (!(config->filter_opts & FILTER_OPT_DEFAULT_DENY)) return 1; else return 0; } } COMMON_EXIT: if (!(config->filter_opts & FILTER_OPT_DEFAULT_DENY)) return 0; else return 1; } tinyproxy-1.11.2/src/filter.h000066400000000000000000000026661461674137700161400ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 1999 George Talusan * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* See 'filter.c' for detailed information. */ #ifndef _TINYPROXY_FILTER_H_ #define _TINYPROXY_FILTER_H_ enum filter_options { FILTER_OPT_CASESENSITIVE = 1 << 0, FILTER_OPT_URL = 1 << 1, FILTER_OPT_DEFAULT_DENY = 1 << 2, FILTER_OPT_TYPE_BRE = 1 << 8, FILTER_OPT_TYPE_ERE = 1 << 9, FILTER_OPT_TYPE_FNMATCH = 1 << 10, }; #define FILTER_TYPE_MASK \ (FILTER_OPT_TYPE_BRE | FILTER_OPT_TYPE_ERE | FILTER_OPT_TYPE_FNMATCH) extern void filter_init (void); extern void filter_destroy (void); extern void filter_reload (void); extern int filter_run (const char *str); #endif tinyproxy-1.11.2/src/heap.c000066400000000000000000000055501461674137700155560ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 2002 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* Debugging versions of various heap related functions are combined * here. The debugging versions include assertions and also print * (to standard error) the function called along with the amount * of memory allocated, and where the memory is pointing. The * format of the log message is standardized. */ #include "main.h" #include "heap.h" #include "text.h" #ifndef NDEBUG void *debugging_calloc (size_t nmemb, size_t size, const char *file, unsigned long line) { void *ptr; assert (nmemb > 0); assert (size > 0); ptr = calloc (nmemb, size); fprintf (stderr, "{calloc: %p:%lu x %lu} %s:%lu\n", ptr, (unsigned long) nmemb, (unsigned long) size, file, line); return ptr; } void *debugging_malloc (size_t size, const char *file, unsigned long line) { void *ptr; assert (size > 0); ptr = malloc (size); fprintf (stderr, "{malloc: %p:%lu} %s:%lu\n", ptr, (unsigned long) size, file, line); return ptr; } void *debugging_realloc (void *ptr, size_t size, const char *file, unsigned long line) { void *newptr; assert (size > 0); newptr = realloc (ptr, size); fprintf (stderr, "{realloc: %p -> %p:%lu} %s:%lu\n", ptr, newptr, (unsigned long) size, file, line); return newptr; } void debugging_free (void *ptr, const char *file, unsigned long line) { fprintf (stderr, "{free: %p} %s:%lu\n", ptr, file, line); if (ptr != NULL) free (ptr); return; } char *debugging_strdup (const char *s, const char *file, unsigned long line) { char *ptr; size_t len; assert (s != NULL); len = strlen (s) + 1; ptr = (char *) malloc (len); if (!ptr) return NULL; memcpy (ptr, s, len); fprintf (stderr, "{strdup: %p:%lu} %s:%lu\n", ptr, (unsigned long) len, file, line); return ptr; } #endif /* !NDEBUG */ tinyproxy-1.11.2/src/heap.h000066400000000000000000000041521461674137700155600ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 2002 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* See 'heap.c' for detailed information. */ #ifndef TINYPROXY_HEAP_H #define TINYPROXY_HEAP_H /* * The following is to allow for better memory checking. */ #ifndef NDEBUG extern void *debugging_calloc (size_t nmemb, size_t size, const char *file, unsigned long line); extern void *debugging_malloc (size_t size, const char *file, unsigned long line); extern void debugging_free (void *ptr, const char *file, unsigned long line); extern void *debugging_realloc (void *ptr, size_t size, const char *file, unsigned long line); extern char *debugging_strdup (const char *s, const char *file, unsigned long line); # define safecalloc(x, y) debugging_calloc(x, y, __FILE__, __LINE__) # define safemalloc(x) debugging_malloc(x, __FILE__, __LINE__) # define saferealloc(x, y) debugging_realloc(x, y, __FILE__, __LINE__) # define safestrdup(x) debugging_strdup(x, __FILE__, __LINE__) # define safefree(x) (debugging_free(x, __FILE__, __LINE__), *(&(x)) = NULL) #else # define safecalloc(x, y) calloc(x, y) # define safemalloc(x) malloc(x) # define saferealloc(x, y) realloc(x, y) # define safefree(x) (free (x), *(&(x)) = NULL) # define safestrdup(x) strdup(x) #endif #endif tinyproxy-1.11.2/src/hostspec.c000066400000000000000000000102321461674137700164620ustar00rootroot00000000000000#include "common.h" #include "hostspec.h" #include "heap.h" #include "network.h" static int dotted_mask(char *bitmask_string, unsigned char array[]) { unsigned char v4bits[4]; if (1 != inet_pton (AF_INET, bitmask_string, v4bits)) return -1; memset (array, 0xff, IPV6_LEN-4); memcpy (array + IPV6_LEN-4, v4bits, 4); return 0; } /* * Fills in the netmask array given a numeric value. * * Returns: * 0 on success * -1 on failure (invalid mask value) * */ static int fill_netmask_array (char *bitmask_string, int v6, unsigned char array[]) { unsigned int i; unsigned long int mask; char *endptr; errno = 0; /* to distinguish success/failure after call */ if (strchr (bitmask_string, '.')) { if (v6) return -1; /* ipv6 doesn't supported dotted netmasks */ return dotted_mask(bitmask_string, array); } mask = strtoul (bitmask_string, &endptr, 10); /* check for various conversion errors */ if ((errno == ERANGE && mask == ULONG_MAX) || (errno != 0 && mask == 0) || (endptr == bitmask_string)) return -1; if (v6 == 0) { /* The mask comparison is done as an IPv6 address, so * convert to a longer mask in the case of IPv4 * addresses. */ mask += 12 * 8; } /* check valid range for a bit mask */ if (mask > (8 * IPV6_LEN)) return -1; /* we have a valid range to fill in the array */ for (i = 0; i != IPV6_LEN; ++i) { if (mask >= 8) { array[i] = 0xff; mask -= 8; } else if (mask > 0) { array[i] = (unsigned char) (0xff << (8 - mask)); mask = 0; } else { array[i] = 0; } } return 0; } /* parse a location string containing either an ipv4/ipv4 + hostmask tuple or a dnsname into a struct hostspec. returns 0 on success, non-0 on error (might be memory allocation, bogus ip address or mask). */ int hostspec_parse(char *location, struct hostspec *h) { char *mask, ip_dst[IPV6_LEN]; h->type = HST_NONE; if(!location) return 0; memset(h, 0, sizeof(*h)); if ((mask = strrchr(location, '/'))) *(mask++) = 0; /* * Check for a valid IP address (the simplest case) first. */ if (full_inet_pton (location, ip_dst) > 0) { h->type = HST_NUMERIC; memcpy (h->address.ip.network, ip_dst, IPV6_LEN); if(!mask) memset (h->address.ip.mask, 0xff, IPV6_LEN); else { char dst[sizeof(struct in6_addr)]; int v6, i; /* Check if the IP address before the netmask is * an IPv6 address */ if (inet_pton(AF_INET6, location, dst) > 0) v6 = 1; else v6 = 0; if (fill_netmask_array (mask, v6, &(h->address.ip.mask[0])) < 0) goto err; for (i = 0; i < IPV6_LEN; i++) h->address.ip.network[i] = ip_dst[i] & h->address.ip.mask[i]; } } else { /* either bogus IP or hostname */ /* bogus ipv6 ? */ if (mask || strchr (location, ':')) goto err; /* In all likelihood a string */ h->type = HST_STRING; h->address.string = safestrdup (location); if (!h->address.string) goto err; } /* restore mask */ if(mask) *(--mask) = '/'; return 0; err:; if(mask) *(--mask) = '/'; return -1; } static int string_match(const char *ip, const char *addrspec) { size_t test_length, match_length; if(!strcasecmp(ip, addrspec)) return 1; if(addrspec[0] != '.') return 0; test_length = strlen (ip); match_length = strlen (addrspec); if (test_length < match_length) return 0; return (strcasecmp (ip + (test_length - match_length), addrspec) == 0); } static int numeric_match(const uint8_t addr[], const struct hostspec *h) { uint8_t x, y; int i; for (i = 0; i != IPV6_LEN; ++i) { x = addr[i] & h->address.ip.mask[i]; y = h->address.ip.network[i]; /* If x and y don't match, the IP addresses don't match */ if (x != y) return 0; } return 1; } /* check whether ip matches hostspec. return 1 on match, 0 on non-match */ int hostspec_match(const char *ip, const struct hostspec *h) { int is_numeric_addr; uint8_t numeric_addr[IPV6_LEN]; if (ip[0] == '\0') return 0; is_numeric_addr = (full_inet_pton (ip, &numeric_addr) > 0); switch (h->type) { case HST_STRING: if(is_numeric_addr) return 0; return string_match (ip, h->address.string); case HST_NUMERIC: return numeric_match (numeric_addr, h); case HST_NONE: return 0; } return 0; } tinyproxy-1.11.2/src/hostspec.h000066400000000000000000000007701461674137700164750ustar00rootroot00000000000000#ifndef HOSTSPEC_H #define HOSTSPEC_H #define IPV6_LEN 16 enum hostspec_type { HST_NONE, HST_STRING, HST_NUMERIC, }; struct hostspec { enum hostspec_type type; union { char *string; struct { unsigned char network[IPV6_LEN]; unsigned char mask[IPV6_LEN]; } ip; } address; }; int hostspec_parse(char *domain, struct hostspec *h); int hostspec_match(const char *ip, const struct hostspec *h); #endif tinyproxy-1.11.2/src/hsearch.c000066400000000000000000000116521461674137700162560ustar00rootroot00000000000000/* musl license, hsearch.c originally written by Szabolcs Nagy Copyright © 2005-2020 Rich Felker, et al. 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 #include #include "hsearch.h" /* open addressing hash table with 2^n table size quadratic probing is used in case of hash collision tab indices and hash are size_t after resize fails with ENOMEM the state of tab is still usable */ typedef struct htab_entry { char *key; htab_value data; } htab_entry; struct elem { htab_entry item; size_t hash; }; struct htab { struct elem *elems; size_t mask; size_t used; size_t seed; size_t dead; }; #define MINSIZE 8 #define MAXSIZE ((size_t)-1/2 + 1) #define CASE_INSENSITIVE #ifdef CASE_INSENSITIVE #include #include #define LOWER_OR_NOT(X) tolower(X) #define STRCMP(X, Y) strcasecmp(X, Y) #else #define LOWER_OR_NOT(X) X #define STRCMP(X, Y) strcmp(X, Y) #endif static size_t keyhash(const char *k, size_t seed) { const unsigned char *p = (const void *)k; size_t h = seed; while (*p) h = 31*h + LOWER_OR_NOT(*p++); return h; } static int resize(struct htab *htab, size_t nel) { size_t newsize; size_t i, j; size_t oldmask = htab->mask; struct elem *e, *newe; struct elem *oldtab = htab->elems; struct elem *oldend; if (nel > MAXSIZE) nel = MAXSIZE; for (newsize = MINSIZE; newsize < nel; newsize *= 2); htab->elems = calloc(newsize, sizeof *htab->elems); if (!htab->elems) { htab->elems = oldtab; return 0; } htab->mask = newsize - 1; if (!oldtab) return 1; oldend = oldtab + oldmask + 1; for (e = oldtab; e < oldend; e++) if (e->item.key) { for (i=e->hash,j=1; ; i+=j++) { newe = htab->elems + (i & htab->mask); if (!newe->item.key) break; } *newe = *e; } free(oldtab); return 1; } static struct elem *lookup(struct htab *htab, const char *key, size_t hash, size_t dead) { size_t i, j; struct elem *e; for (i=hash,j=1; ; i+=j++) { e = htab->elems + (i & htab->mask); if ((!e->item.key && (!e->hash || e->hash == dead)) || (e->hash==hash && STRCMP(e->item.key, key)==0)) break; } return e; } struct htab *htab_create(size_t nel) { struct htab *r = calloc(1, sizeof *r); if(r && !resize(r, nel)) { free(r); r = 0; } r->seed = rand(); return r; } void htab_destroy(struct htab *htab) { free(htab->elems); free(htab); } static struct elem *htab_find_elem(struct htab *htab, const char* key) { size_t hash = keyhash(key, htab->seed); struct elem *e = lookup(htab, key, hash, 0); if (e->item.key) { return e; } return 0; } htab_value* htab_find(struct htab *htab, const char* key) { struct elem *e = htab_find_elem(htab, key); if(!e) return 0; return &e->item.data; } htab_value* htab_find2(struct htab *htab, const char* key, char **saved_key) { struct elem *e = htab_find_elem(htab, key); if(!e) return 0; *saved_key = e->item.key; return &e->item.data; } int htab_delete(struct htab *htab, const char* key) { struct elem *e = htab_find_elem(htab, key); if(!e) return 0; e->item.key = 0; e->hash = 0xdeadc0de; --htab->used; ++htab->dead; return 1; } int htab_insert(struct htab *htab, char* key, htab_value value) { size_t hash = keyhash(key, htab->seed), oh; struct elem *e = lookup(htab, key, hash, 0xdeadc0de); if(e->item.key) { /* it's not allowed to overwrite existing data */ return 0; } oh = e->hash; /* save old hash in case it's tombstone marker */ e->item.key = key; e->item.data = value; e->hash = hash; if (++htab->used + htab->dead > htab->mask - htab->mask/4) { if (!resize(htab, 2*htab->used)) { htab->used--; e->item.key = 0; e->hash = oh; return 0; } htab->dead = 0; } else if (oh == 0xdeadc0de) { /* re-used tomb */ --htab->dead; } return 1; } size_t htab_next(struct htab *htab, size_t iterator, char** key, htab_value **v) { size_t i; for(i=iterator;imask+1;++i) { struct elem *e = htab->elems + i; if(e->item.key) { *key = e->item.key; *v = &e->item.data; return i+1; } } return 0; } tinyproxy-1.11.2/src/hsearch.h000066400000000000000000000012261461674137700162570ustar00rootroot00000000000000#ifndef HSEARCH_H #define HSEARCH_H #include typedef union htab_value { void *p; size_t n; } htab_value; #define HTV_N(N) (htab_value) {.n = N} #define HTV_P(P) (htab_value) {.p = P} struct htab * htab_create(size_t); void htab_destroy(struct htab *); htab_value* htab_find(struct htab *, const char* key); /* same as htab_find, but can retrieve the saved key (for freeing) */ htab_value* htab_find2(struct htab *htab, const char* key, char **saved_key); int htab_insert(struct htab *, char*, htab_value); int htab_delete(struct htab *htab, const char* key); size_t htab_next(struct htab *, size_t iterator, char** key, htab_value **v); #endif tinyproxy-1.11.2/src/html-error.c000066400000000000000000000217611461674137700167360ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 2003 Steven Young * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* This file contains source code for the handling and display of * HTML error pages with variable substitution. */ #include "common.h" #include "main.h" #include "buffer.h" #include "conns.h" #include "heap.h" #include "html-error.h" #include "network.h" #include "utils.h" #include "conf.h" #include "log.h" #include /* * Add an error number -> filename mapping to the errorpages list. */ #define ERRORNUM_BUFSIZE 8 /* this is more than required */ #define ERRPAGES_BUCKETCOUNT 16 int add_new_errorpage (struct config_s *conf, char *filepath, unsigned int errornum) { char errornbuf[ERRORNUM_BUFSIZE], *k; if (!conf->errorpages) conf->errorpages = htab_create (ERRPAGES_BUCKETCOUNT); if (!conf->errorpages) return (-1); snprintf (errornbuf, ERRORNUM_BUFSIZE, "%u", errornum); k = safestrdup(errornbuf); if (!k) return -1; if (!htab_insert (conf->errorpages, k, HTV_P(filepath))) { safefree(k); return (-1); } return (0); } /* * Get the file appropriate for a given error. */ static char *get_html_file (unsigned int errornum) { char errornbuf[ERRORNUM_BUFSIZE]; htab_value *hv; assert (errornum >= 100 && errornum < 1000); if (!config->errorpages) return (config->errorpage_undef); snprintf (errornbuf, ERRORNUM_BUFSIZE, "%u", errornum); hv = htab_find (config->errorpages, errornbuf); if (!hv) return (config->errorpage_undef); return hv->p; } static char *lookup_variable (struct htab *map, const char *varname) { htab_value *v; v = htab_find(map, varname); return v ? v->p : 0; } static void varsubst_sendline(struct conn_s *connptr, regex_t *re, char *p) { int fd = connptr->client_fd; while(*p) { regmatch_t match; char varname[32+1], *varval; size_t l; int st = regexec(re, p, 1, &match, 0); if(st == 0) { if(match.rm_so > 0) safe_write(fd, p, match.rm_so); l = match.rm_eo - match.rm_so; assert(l>2 && l-2 < sizeof(varname)); p += match.rm_so; memcpy(varname, p+1, l-2); varname[l-2] = 0; varval = lookup_variable(connptr->error_variables, varname); if(varval) write_message(fd, "%s", varval); else if(varval && !*varval) write_message(fd, "(unknown)"); else safe_write(fd, p, l); p += l; } else { write_message(fd, "%s", p); break; } } } /* * Send an already-opened file to the client with variable substitution. */ int send_html_file (FILE *infile, struct conn_s *connptr) { regex_t re; char *inbuf = safemalloc (4096); (void) regcomp(&re, "{[a-z]\\{1,32\\}}", 0); while (fgets (inbuf, 4096, infile)) { varsubst_sendline(connptr, &re, inbuf); } regfree (&re); safefree (inbuf); return 1; } int send_http_headers ( struct conn_s *connptr, int code, const char *message, const char *extra) { const char headers[] = "HTTP/1.%u %d %s\r\n" "Server: %s/%s\r\n" "Content-Type: text/html\r\n" "%s" "Connection: close\r\n" "\r\n"; return (write_message (connptr->client_fd, headers, connptr->protocol.major != 1 ? 0 : connptr->protocol.minor, code, message, PACKAGE, VERSION, extra)); } /* * Display an error to the client. */ int send_http_error_message (struct conn_s *connptr) { char *error_file; FILE *infile; int ret; const char *fallback_error = "\n" "\n" "\n" "%d %s\n" "\n" "

%s

\n" "

%s

\n" "
\n" "

Generated by %s version %s.

\n" "\n" "\n"; const char p_auth_str[] = "Proxy-Authenticate: Basic realm=\"" PACKAGE_NAME "\"\r\n"; const char w_auth_str[] = "WWW-Authenticate: Basic realm=\"" PACKAGE_NAME "\"\r\n"; /* according to rfc7235, the 407 error must be accompanied by a Proxy-Authenticate header field. */ const char *add = connptr->error_number == 407 ? p_auth_str : (connptr->error_number == 401 ? w_auth_str : ""); send_http_headers (connptr, connptr->error_number, connptr->error_string, add); error_file = get_html_file (connptr->error_number); if (!error_file || !(infile = fopen (error_file, "r"))) { char *detail; if (error_file) log_message (LOG_ERR, "Error opening error file '%s' (%s)", error_file, strerror (errno)); detail = lookup_variable (connptr->error_variables, "detail"); return (write_message (connptr->client_fd, fallback_error, connptr->error_number, connptr->error_string, connptr->error_string, detail, PACKAGE, VERSION)); } ret = send_html_file (infile, connptr); fclose (infile); return (ret); } /* * Add a key -> value mapping for HTML file substitution. */ #define ERRVAR_BUCKETCOUNT 16 int add_error_variable (struct conn_s *connptr, const char *key, const char *val) { char *k, *v; if (!connptr->error_variables) if (! (connptr->error_variables = htab_create (ERRVAR_BUCKETCOUNT))) return (-1); k = safestrdup(key); v = safestrdup(val); if (!v || !k) goto oom; if(htab_insert (connptr->error_variables, k, HTV_P(v))) return 1; oom:; safefree(k); safefree(v); return -1; } #define ADD_VAR_RET(x, y) \ do { \ if (y == NULL) \ break; \ if (add_error_variable(connptr, x, y) < 0) \ return -1; \ } while (0) /* * Set some standard variables used by all HTML pages */ int add_standard_vars (struct conn_s *connptr) { char errnobuf[16]; char timebuf[30]; time_t global_time; struct tm tm_buf; snprintf (errnobuf, sizeof errnobuf, "%d", connptr->error_number); ADD_VAR_RET ("errno", errnobuf); ADD_VAR_RET ("cause", connptr->error_string); ADD_VAR_RET ("request", connptr->request_line); ADD_VAR_RET ("clientip", connptr->client_ip_addr); /* The following value parts are all non-NULL and will * trigger warnings in ADD_VAR_RET(), so we use * add_error_variable() directly. */ global_time = time (NULL); strftime (timebuf, sizeof (timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime_r (&global_time, &tm_buf)); add_error_variable (connptr, "date", timebuf); add_error_variable (connptr, "website", "https://tinyproxy.github.io/"); add_error_variable (connptr, "version", VERSION); add_error_variable (connptr, "package", PACKAGE); return (0); } /* * Add the error information to the conn structure. */ int indicate_http_error (struct conn_s *connptr, int number, const char *message, ...) { va_list ap; char *key, *val; va_start (ap, message); while ((key = va_arg (ap, char *))) { val = va_arg (ap, char *); if (add_error_variable (connptr, key, val) == -1) { va_end (ap); return (-1); } } connptr->error_number = number; connptr->error_string = safestrdup (message); va_end (ap); return (add_standard_vars (connptr)); } tinyproxy-1.11.2/src/html-error.h000066400000000000000000000032371461674137700167410ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 2003 Steven Young * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* See 'html-error.c' for detailed information. */ #ifndef TINYPROXY_HTML_ERROR_H #define TINYPROXY_HTML_ERROR_H /* Forward declaration */ struct conn_s; struct config_s; extern int add_new_errorpage (struct config_s *, char *filepath, unsigned int errornum); extern int send_http_error_message (struct conn_s *connptr); extern int indicate_http_error (struct conn_s *connptr, int number, const char *message, ...); extern int add_error_variable (struct conn_s *connptr, const char *key, const char *val); extern int send_html_file (FILE * infile, struct conn_s *connptr); extern int send_http_headers (struct conn_s *connptr, int code, const char *message, const char *extra); extern int add_standard_vars (struct conn_s *connptr); #endif /* !TINYPROXY_HTML_ERROR_H */ tinyproxy-1.11.2/src/http-message.c000066400000000000000000000204061461674137700172370ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 2003 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* See 'http-message.h' for detailed information. */ #include "common.h" #include "heap.h" #include "http-message.h" #include "network.h" /* * Package up an HTTP message into a nice little structure. As you can * see this structure doesn't actually store any allocated strings; * therefore, the caller must free any memory referenced by this struct. * Also, the caller MUST NOT free the memory while the structure is * still in use---bad things would happen. */ struct http_message_s { /* Response string and code supplied on the HTTP status line */ struct { const char *string; int code; } response; /* * A group of headers to be sent with this message. Right now * the strings are referenced through pointers in an array. * I might change this to a vector in the future. */ struct { const char **strings; unsigned int total; unsigned int used; } headers; /* Body of the message (most likely an HTML message) */ struct { const char *text; size_t length; } body; }; /* * Check if the HTTP message is validly formed. This is the one odd-ball * function. It returns 0 if the message is invalid; otherwise, a positive * number is returned. Useful for if() tests and assert() tests. */ static int is_http_message_valid (http_message_t msg) { if (msg == NULL) return 0; if (msg->headers.strings == NULL) return 0; if (msg->response.string == NULL) return 0; if (msg->response.code < 1 || msg->response.code > 999) return 0; return 1; } /* Initially allocate space for 128 headers */ #define NUMBER_OF_HEADERS 128 /* * Allocate a new http_message structure on the heap. * If memory could not be allocated, return a NULL. */ http_message_t http_message_create (int response_code, const char *response_string) { http_message_t msg; int ret; msg = (struct http_message_s *) safecalloc (1, sizeof (struct http_message_s)); if (msg == NULL) return NULL; msg->headers.strings = (const char **) safecalloc (NUMBER_OF_HEADERS, sizeof (char *)); if (msg->headers.strings == NULL) { safefree (msg); return NULL; } msg->headers.total = NUMBER_OF_HEADERS; /* Store the HTTP response information in the structure */ ret = http_message_set_response (msg, response_code, response_string); if (IS_HTTP_MSG_ERROR (ret)) { safefree (msg->headers.strings); safefree (msg); return NULL; } return msg; } /* * Free up the space associated with this HTTP message structure. * This DOES NOT free the pointers stored in this structure. That memory * is the responsibility of the caller. */ int http_message_destroy (http_message_t msg) { assert (msg != NULL); assert (msg->headers.strings != NULL); /* Check for valid arguments */ if (msg == NULL) return -EFAULT; if (msg->headers.strings != NULL) safefree (msg->headers.strings); safefree (msg); return 0; } /* * Set the HTTP response information for this structure. The response_string * must be a NUL ('\0') terminated C string. */ int http_message_set_response (http_message_t msg, int response_code, const char *response_string) { /* Check for valid arguments */ if (msg == NULL) return -EFAULT; if (response_code < 1 || response_code > 999) return -EINVAL; if (response_string == NULL) return -EINVAL; if (strlen (response_string) == 0) return -EINVAL; msg->response.code = response_code; msg->response.string = response_string; return 0; } /* * Set the HTTP message body. */ int http_message_set_body (http_message_t msg, const char *body, size_t len) { /* Check for valid arguments */ if (msg == NULL) return -EFAULT; if (body == NULL) return -EINVAL; if (len == 0) return -EINVAL; msg->body.text = body; msg->body.length = len; return 0; } /* * Add headers to the structure. */ int http_message_add_headers (http_message_t msg, const char **headers, unsigned int num_headers) { const char **new_headers; unsigned int i; /* Check for valid arguments */ if (msg == NULL) return -EFAULT; if (headers == NULL) return -EINVAL; /* * If the number of headers to add is greater than the space * available, reallocate the memory. */ if (msg->headers.used + num_headers > msg->headers.total) { new_headers = (const char **) safecalloc (msg->headers.total * 2, sizeof (char *)); if (new_headers == NULL) return -ENOMEM; /* Copy the array */ for (i = 0; i != msg->headers.used; ++i) new_headers[i] = msg->headers.strings[i]; /* Remove the old array and replace it with the new array */ safefree (msg->headers.strings); msg->headers.strings = new_headers; msg->headers.total *= 2; } /* * Add the new headers to the structure */ for (i = 0; i != num_headers; ++i) msg->headers.strings[i + msg->headers.used] = headers[i]; msg->headers.used += num_headers; return 0; } /* * Send the completed HTTP message via the supplied file descriptor. */ int http_message_send (http_message_t msg, int fd) { char timebuf[30]; time_t global_time; unsigned int i; struct tm tm_buf; assert (is_http_message_valid (msg)); /* Check for valid arguments */ if (msg == NULL) return -EFAULT; if (fd < 1) return -EBADF; if (!is_http_message_valid (msg)) return -EINVAL; /* Write the response line */ write_message (fd, "HTTP/1.0 %d %s\r\n", msg->response.code, msg->response.string); /* Go through all the headers */ for (i = 0; i != msg->headers.used; ++i) write_message (fd, "%s\r\n", msg->headers.strings[i]); /* Output the date */ global_time = time (NULL); strftime (timebuf, sizeof (timebuf), "%a, %d %b %Y %H:%M:%S GMT", gmtime_r (&global_time, &tm_buf)); write_message (fd, "Date: %s\r\n", timebuf); /* Output the content-length */ write_message (fd, "Content-length: %lu\r\n", (unsigned long) msg->body.length); /* Write the separator between the headers and body */ safe_write (fd, "\r\n", 2); /* If there's a body, send it! */ if (msg->body.length > 0) safe_write (fd, msg->body.text, msg->body.length); return 0; } tinyproxy-1.11.2/src/http-message.h000066400000000000000000000073371461674137700172540ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 2003 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* HTTP Message API * ---------------- * The idea behind this application programming interface (API) is to * represent an HTTP response message as a concrete entity. The API * functions allow the message to be built up systematically before * transmission to a connected socket. * * The order of the functions in your program would look something like * this: * http_message_create() * http_message_set_response() * http_message_set_body() [optional if no body is required] * http_message_add_headers() [optional if no additional headers are used] * http_message_send() * http_message_destroy() * * NOTE: No user data is stored in the http_message_t type; therefore, * do not delete strings referenced by the http_message_t object * before you call http_message_destroy(). By not copying data, the * API functions are faster, but you must take greater care. * * (Side note: be _very_ careful when using stack allocated memory with * this API. Bad things will happen if you try to pass the * http_message_t out of the calling function since the stack * allocated memory referenced by the http_message_t will no long * exist.) */ #ifndef _TINYPROXY_HTTP_MESSAGE_H_ #define _TINYPROXY_HTTP_MESSAGE_H_ /* Use the "http_message_t" as a cookie or handle to the structure. */ typedef struct http_message_s *http_message_t; /* * Macro to test if an error occurred with the API. All the HTTP message * functions will return 0 if no error occurred, or a negative number if * there was a problem. */ #define IS_HTTP_MSG_ERROR(x) (x < 0) /* Initialize the internal structure of the HTTP message */ extern http_message_t http_message_create (int response_code, const char *response_string); /* Free up an _internal_ resources */ extern int http_message_destroy (http_message_t msg); /* * Send an HTTP message via the supplied file descriptor. This function * will add the "Date" header before it's sent. */ extern int http_message_send (http_message_t msg, int fd); /* * Change the internal state of the HTTP message. Either set the * body of the message, update the response information, or * add a new set of headers. */ extern int http_message_set_body (http_message_t msg, const char *body, size_t len); extern int http_message_set_response (http_message_t msg, int response_code, const char *response_string); /* * Set the headers for this HTTP message. Each string must be NUL ('\0') * terminated, but DO NOT include any carriage returns (CR) or * line-feeds (LF) since they will be included when the http_message is * sent. */ extern int http_message_add_headers (http_message_t msg, const char **headers, unsigned int num_headers); #endif /* _TINYPROXY_HTTP_MESSAGE_H_ */ tinyproxy-1.11.2/src/log.c000066400000000000000000000215231461674137700154200ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 1998 Steven Young * Copyright (C) 1999 Robert James Kaes * Copyright (C) 2009 Michael Adam * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* Logs the various messages which tinyproxy produces to either a log file * or the syslog daemon. Not much to it... */ #include "main.h" #include "heap.h" #include "log.h" #include "utils.h" #include "sblist.h" #include "conf.h" #include static const char *syslog_level[] = { NULL, NULL, "CRITICAL", "ERROR", "WARNING", "NOTICE", "INFO", "DEBUG", "CONNECT" }; #define TIME_LENGTH 16 #define STRING_LENGTH 800 static pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER; /* * Global file descriptor for the log file */ int log_file_fd = -1; /* * Store the log level setting. */ static int log_level = LOG_INFO; /* * Hold a listing of log messages which need to be sent once the log * file has been established. * The key is the actual messages (already filled in full), and the value * is the log level. */ static sblist *log_message_storage; static unsigned int logging_initialized = FALSE; /* boolean */ /* * Open the log file and store the file descriptor in a global location. */ int open_log_file (const char *log_file_name) { if (log_file_name == NULL) { log_file_fd = fileno(stdout); } else { log_file_fd = create_file_safely (log_file_name, FALSE); } return log_file_fd; } /* * Close the log file */ void close_log_file (void) { if (log_file_fd < 0 || log_file_fd == fileno(stdout)) { return; } close (log_file_fd); log_file_fd = -1; } /* * Set the log level for writing to the log file. */ void set_log_level (int level) { log_level = level; } /* * This routine logs messages to either the log file or the syslog function. */ void log_message (int level, const char *fmt, ...) { va_list args; struct timespec nowtime; struct tm tm_buf; char time_string[TIME_LENGTH]; char str[STRING_LENGTH]; ssize_t ret; #ifdef NDEBUG /* * Figure out if we should write the message or not. */ if (log_level == LOG_CONN) { if (level == LOG_INFO) return; } else if (log_level == LOG_INFO) { if (level > LOG_INFO && level != LOG_CONN) return; } else if (level > log_level) return; #endif if (config && config->syslog && level == LOG_CONN) level = LOG_INFO; va_start (args, fmt); /* * If the config file hasn't been processed, then we need to store * the messages for later processing. */ if (!logging_initialized) { char *entry_buffer; if (!log_message_storage) { log_message_storage = sblist_new (sizeof(char*), 64); if (!log_message_storage) goto out; } vsnprintf (str, STRING_LENGTH, fmt, args); entry_buffer = (char *) safemalloc (strlen (str) + 6); if (!entry_buffer) goto out; sprintf (entry_buffer, "%d %s", level, str); if(!sblist_add (log_message_storage, &entry_buffer)) safefree (entry_buffer); goto out; } if(!config->syslog && log_file_fd == -1) goto out; if (config->syslog) { pthread_mutex_lock(&log_mutex); #ifdef HAVE_VSYSLOG_H vsyslog (level, fmt, args); #else vsnprintf (str, STRING_LENGTH, fmt, args); syslog (level, "%s", str); #endif pthread_mutex_unlock(&log_mutex); } else { char *p; clock_gettime(CLOCK_REALTIME, &nowtime); /* Format is month day hour:minute:second (24 time) */ strftime (time_string, TIME_LENGTH, "%b %d %H:%M:%S", localtime_r (&nowtime.tv_sec, &tm_buf)); snprintf (str, STRING_LENGTH, "%-9s %s.%03lu [%ld]: ", syslog_level[level], time_string, (unsigned long) nowtime.tv_nsec/1000000ul, (long int) getpid ()); /* * Overwrite the '\0' and leave room for a trailing '\n' * be added next. */ p = str + strlen(str); vsnprintf (p, STRING_LENGTH - strlen(str) - 1, fmt, args); p = str + strlen(str); *p = '\n'; *(p+1) = '\0'; assert (log_file_fd >= 0); pthread_mutex_lock(&log_mutex); ret = write (log_file_fd, str, strlen (str)); pthread_mutex_unlock(&log_mutex); if (ret == -1) { config->syslog = TRUE; log_message(LOG_CRIT, "ERROR: Could not write to log " "file %s: %s.", config->logf_name, strerror(errno)); log_message(LOG_CRIT, "Falling back to syslog logging"); } pthread_mutex_lock(&log_mutex); fsync (log_file_fd); pthread_mutex_unlock(&log_mutex); } out: va_end (args); } /* * This needs to send any stored log messages. */ static void send_stored_logs (void) { char **string; char *ptr; int level; size_t i; if (log_message_storage == NULL) return; log_message(LOG_DEBUG, "sending stored logs"); for (i = 0; i < sblist_getsize (log_message_storage); ++i) { string = sblist_get (log_message_storage, i); if (!string || !*string) continue; ptr = strchr (*string, ' ') + 1; level = atoi (*string); #ifdef NDEBUG if (log_level == LOG_CONN && level == LOG_INFO) continue; else if (log_level == LOG_INFO) { if (level > LOG_INFO && level != LOG_CONN) continue; } else if (level > log_level) continue; #endif log_message (level, "%s", ptr); safefree(*string); } sblist_free (log_message_storage); log_message_storage = NULL; log_message(LOG_DEBUG, "done sending stored logs"); } /** * Initialize the logging subsystem, based on the configuration. * Returns 0 upon success, -1 upon failure. * * This function uses fprintf() instead of log_message(), since * the logging is not yet set up... */ int setup_logging (void) { if (!config->syslog) { if (open_log_file (config->logf_name) < 0) { /* * If opening the log file fails, we try * to fall back to syslog logging... */ config->syslog = TRUE; log_message (LOG_CRIT, "ERROR: Could not create log " "file %s: %s.", config->logf_name, strerror (errno)); log_message (LOG_CRIT, "Falling back to syslog logging."); } } if (config->syslog) { openlog ("tinyproxy", LOG_PID, LOG_USER); } logging_initialized = TRUE; send_stored_logs (); return 0; } /** * Stop the logging subsystem. */ void shutdown_logging (void) { if (!logging_initialized) { return; } if (config->syslog) { closelog (); } else { close_log_file (); } logging_initialized = FALSE; } tinyproxy-1.11.2/src/log.h000066400000000000000000000103771461674137700154320ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 1998 Steven Young * Copyright (C) 1999 Robert James Kaes * Copyright (C) 2009 Michael Adam * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* See 'log.c' for detailed information. */ #ifndef TINYPROXY_LOG_H #define TINYPROXY_LOG_H #ifdef HAVE_CONFIG_H # include #endif /* * Okay, I have modelled the levels for logging off the syslog() interface. * However, I would really prefer if only five of the levels are used. You * can see them below and I'll describe what each level should be for. * Hopefully tinyproxy will remain consistent with these levels. * -- rjkaes * Sorry but I had to destroy the hope ;-) There was a need to log * connections without the INFO stuff and not to have them as NOTICE. * -- hgb * * Level Description * ----- ----------- * LOG_CRIT This is catastrophic. Basically, tinyproxy can not recover * from this and will either close the child (if we're lucky), * or the entire daemon. I would relegate this to conditions * like unable to create the listening socket, or unable to * create a child. If you're going to log at this level provide * as much information as possible. * * LOG_ERR Okay, something bad happened. We can recover from this, but * the connection will be terminated. This should be for things * like when we cannot create a socket, or out of memory. * Basically, the connection will not work, but it's not enough * to bring the whole daemon down. * * LOG_WARNING There is condition which will change the behaviour of * tinyproxy from what is expected. For example, somebody did * not specify a port. tinyproxy will handle this (by using * it's default port), but it's a _higher_ level situation * which the admin should be aware of. * * LOG_NOTICE This is for a special condition. Nothing has gone wrong, but * it is more important than the common LOG_INFO level. Right * now it is used for actions like creating/destroying children, * unauthorized access, signal handling, etc. * * LOG_CONN This additional level is for logging connections only, so * it is easy to control only the requests in the logfile. * If we log through syslog, this is set to LOG_INFO. * -- hgb * * LOG_INFO Everything else ends up here. Logging for incoming * connections, denying due to filtering rules, unable to * connect to remote server, etc. * * LOG_DEBUG Don't use this level. :) Use the two DEBUG?() macros * instead since they can remain in the source if needed. (I * don't advocate this, but it could be useful at times.) */ #include #define LOG_CONN 8 /* extra to log connections without the INFO stuff */ /* Suppress warnings when GCC is in -pedantic mode and not -std=c99 */ #if (__GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)) #pragma GCC system_header #endif /* * Use this for debugging. The format is specific: * DEBUG1("There was a major problem"); * DEBUG2("There was a big problem: %s in connptr %p", "hello", connptr); */ #ifndef NDEBUG # define DEBUG1(x) \ log_message(LOG_DEBUG, "[%s:%d] " x, __FILE__, __LINE__) # define DEBUG2(x, y...) \ log_message(LOG_DEBUG, "[%s:%d] " x, __FILE__, __LINE__, ## y) #else # define DEBUG1(x) do { } while(0) # define DEBUG2(x, y...) do { } while(0) #endif extern int open_log_file (const char *file); extern void close_log_file (void); extern void log_message (int level, const char *fmt, ...); extern void set_log_level (int level); extern int setup_logging (void); extern void shutdown_logging (void); #endif tinyproxy-1.11.2/src/loop.c000066400000000000000000000042401461674137700156050ustar00rootroot00000000000000#include #include #include "loop.h" #include "conf.h" #include "main.h" #include "sblist.h" #include "sock.h" struct loop_record { union sockaddr_union addr; time_t tstamp; }; static sblist *loop_records; static pthread_mutex_t loop_records_lock = PTHREAD_MUTEX_INITIALIZER; void loop_records_init(void) { loop_records = sblist_new(sizeof (struct loop_record), 32); } void loop_records_destroy(void) { sblist_free(loop_records); loop_records = 0; } #if 0 static void su_to_str(union sockaddr_union *addr, char *buf) { int af = addr->v4.sin_family; unsigned port = ntohs(af == AF_INET ? addr->v4.sin_port : addr->v6.sin6_port); char portb[32]; sprintf(portb, ":%u", port); getpeer_information (addr, buf, 256); strcat(buf, portb); } #endif void loop_records_add(union sockaddr_union *addr) { time_t now =time(0); struct loop_record rec; pthread_mutex_lock(&loop_records_lock); rec.tstamp = now; rec.addr = *addr; sblist_add(loop_records, &rec); pthread_mutex_unlock(&loop_records_lock); } #define TIMEOUT_SECS 15 int connection_loops (union sockaddr_union *addr) { int ret = 0, af, our_af = addr->v4.sin_family; void *ipdata, *our_ipdata = our_af == AF_INET ? (void*)&addr->v4.sin_addr.s_addr : (void*)&addr->v6.sin6_addr.s6_addr; size_t i, cmp_len = our_af == AF_INET ? sizeof(addr->v4.sin_addr.s_addr) : sizeof(addr->v6.sin6_addr.s6_addr); unsigned port, our_port = ntohs(our_af == AF_INET ? addr->v4.sin_port : addr->v6.sin6_port); time_t now = time(0); pthread_mutex_lock(&loop_records_lock); for (i = 0; i < sblist_getsize(loop_records); ) { struct loop_record *rec = sblist_get(loop_records, i); if (rec->tstamp + TIMEOUT_SECS < now) { sblist_delete(loop_records, i); continue; } if (!ret) { af = rec->addr.v4.sin_family; if (af != our_af) goto next; port = ntohs(af == AF_INET ? rec->addr.v4.sin_port : rec->addr.v6.sin6_port); if (port != our_port) goto next; ipdata = af == AF_INET ? (void*)&rec->addr.v4.sin_addr.s_addr : (void*)&rec->addr.v6.sin6_addr.s6_addr; if (!memcmp(ipdata, our_ipdata, cmp_len)) { ret = 1; } } next: i++; } pthread_mutex_unlock(&loop_records_lock); return ret; } tinyproxy-1.11.2/src/loop.h000066400000000000000000000003401461674137700156070ustar00rootroot00000000000000#ifndef LOOP_H #define LOOP_H #include "sock.h" void loop_records_init(void); void loop_records_destroy(void); void loop_records_add(union sockaddr_union *addr); int connection_loops (union sockaddr_union *addr); #endif tinyproxy-1.11.2/src/main.c000066400000000000000000000310441461674137700155620ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * * Copyright (C) 1998 Steven Young * Copyright (C) 1998-2002 Robert James Kaes * Copyright (C) 2000 Chris Lightfoot * Copyright (C) 2009-2010 Mukund Sivaraman * Copyright (C) 2009-2010 Michael Adam * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* The initialize routine. Basically sets up all the initial stuff (logfile, * listening socket, config options, etc.) and then sits there and loops * over the new connections until the daemon is closed. Also has additional * functions to handle the "user friendly" aspects of a program (usage, * stats, etc.) Like any good program, most of the work is actually done * elsewhere. */ #include "main.h" #include "anonymous.h" #include "buffer.h" #include "conf.h" #include "daemon.h" #include "heap.h" #include "filter.h" #include "child.h" #include "loop.h" #include "log.h" #include "reqs.h" #include "sock.h" #include "stats.h" #include "utils.h" /* * Global Structures */ struct config_s *config; static struct config_s configs[2]; static const char* config_file; unsigned int received_sighup = FALSE; /* boolean */ static struct config_s* get_next_config(void) { if (config == &configs[0]) return &configs[1]; return &configs[0]; } /* * Handle a signal */ static void takesig (int sig) { pid_t pid; int status; switch (sig) { case SIGUSR1: case SIGHUP: received_sighup = TRUE; break; case SIGINT: case SIGTERM: config->quit = TRUE; break; case SIGCHLD: while ((pid = waitpid (-1, &status, WNOHANG)) > 0) ; break; } return; } /* * Display the version information for the user. */ static void display_version (void) { printf ("%s %s\n", PACKAGE, VERSION); } /* * Display usage to the user. */ static void display_usage (void) { int features = 0; printf ("Usage: %s [options]\n", PACKAGE); printf ("\n" "Options are:\n" " -d Do not daemonize (run in foreground).\n" " -c FILE Use an alternate configuration file.\n" " -h Display this usage information.\n" " -v Display version information.\n"); /* Display the modes compiled into tinyproxy */ printf ("\nFeatures compiled in:\n"); #ifdef XTINYPROXY_ENABLE printf (" XTinyproxy header\n"); features++; #endif /* XTINYPROXY */ #ifdef FILTER_ENABLE printf (" Filtering\n"); features++; #endif /* FILTER_ENABLE */ #ifndef NDEBUG printf (" Debugging code\n"); features++; #endif /* NDEBUG */ #ifdef TRANSPARENT_PROXY printf (" Transparent proxy support\n"); features++; #endif /* TRANSPARENT_PROXY */ #ifdef REVERSE_SUPPORT printf (" Reverse proxy support\n"); features++; #endif /* REVERSE_SUPPORT */ #ifdef UPSTREAM_SUPPORT printf (" Upstream proxy support\n"); features++; #endif /* UPSTREAM_SUPPORT */ if (0 == features) printf (" None\n"); printf ("\n" "For support and bug reporting instructions, please visit\n" ".\n"); } static int get_id (char *str) { char *tstr; if (str == NULL) return -1; tstr = str; while (*tstr != 0) { if (!isdigit (*tstr)) return -1; tstr++; } return atoi (str); } /** * change_user: * @program: The name of the program. Pass argv[0] here. * * This function tries to change UID and GID to the ones specified in * the config file. This function is typically called during * initialization when the effective user is root. **/ static void change_user (const char *program) { if (config->group && strlen (config->group) > 0) { int gid = get_id (config->group); if (gid < 0) { struct group *thisgroup = getgrnam (config->group); if (!thisgroup) { fprintf (stderr, "%s: Unable to find group \"%s\".\n", program, config->group); exit (EX_NOUSER); } gid = thisgroup->gr_gid; } if (setgid (gid) < 0) { fprintf (stderr, "%s: Unable to change to group \"%s\".\n", program, config->group); exit (EX_NOPERM); } #ifdef HAVE_SETGROUPS /* Drop all supplementary groups, otherwise these are inherited from the calling process */ if (setgroups (0, NULL) < 0) { fprintf (stderr, "%s: Unable to drop supplementary groups.\n", program); exit (EX_NOPERM); } #endif log_message (LOG_INFO, "Now running as group \"%s\".", config->group); } if (config->user && strlen (config->user) > 0) { int uid = get_id (config->user); if (uid < 0) { struct passwd *thisuser = getpwnam (config->user); if (!thisuser) { fprintf (stderr, "%s: Unable to find user \"%s\".\n", program, config->user); exit (EX_NOUSER); } uid = thisuser->pw_uid; } if (setuid (uid) < 0) { fprintf (stderr, "%s: Unable to change to user \"%s\".\n", program, config->user); exit (EX_NOPERM); } log_message (LOG_INFO, "Now running as user \"%s\".", config->user); } } /** * convenience wrapper around reload_config_file * that also re-initializes logging. */ int reload_config (int reload_logging) { int ret, ret2; struct config_s *c_next = get_next_config(); log_message (LOG_NOTICE, "Reloading config file (%s)", config_file); if (reload_logging) shutdown_logging (); ret = reload_config_file (config_file, c_next); if (ret == 0) { if(config) free_config (config); config = c_next; } ret2 = reload_logging ? setup_logging () : 0; if (ret != 0) log_message (LOG_WARNING, "Reloading config file failed!"); else log_message (LOG_NOTICE, "Reloading config file finished"); return ret ? ret : ret2; } static void setup_sig(int sig, signal_func *sigh, const char* signame, const char* argv0) { if (set_signal_handler (sig, sigh) == SIG_ERR) { fprintf (stderr, "%s: Could not set the \"%s\" signal.\n", argv0, signame); exit (EX_OSERR); } } int main (int argc, char **argv) { int opt, daemonized = TRUE; srand(time(NULL)); /* for hashmap seeds */ /* Only allow u+rw bits. This may be required for some versions * of glibc so that mkstemp() doesn't make us vulnerable. */ umask (0177); log_message (LOG_NOTICE, "Initializing " PACKAGE " ..."); if (config_init()) { fprintf(stderr, "ERROR: config_init() failed\n"); exit (EX_SOFTWARE); } config_file = SYSCONFDIR "/tinyproxy.conf"; while ((opt = getopt (argc, argv, "c:vdh")) != EOF) { switch (opt) { case 'v': display_version (); exit (EX_OK); case 'd': daemonized = FALSE; break; case 'c': config_file = optarg; break; case 'h': display_usage (); exit (EX_OK); default: display_usage (); exit (EX_USAGE); } } if (reload_config(0)) { exit (EX_SOFTWARE); } init_stats (); /* If ANONYMOUS is turned on, make sure that Content-Length is * in the list of allowed headers, since it is required in a * HTTP/1.0 request. Also add the Content-Type header since it * goes hand in hand with Content-Length. */ if (is_anonymous_enabled (config)) { anonymous_insert (config, safestrdup("Content-Length")); anonymous_insert (config, safestrdup("Content-Type")); } if (daemonized == TRUE) { if (!config->syslog && config->logf_name == NULL) fprintf(stderr, "WARNING: logging deactivated " "(can't log to stdout when daemonized)\n"); makedaemon (); } setup_sig(SIGPIPE, SIG_IGN, "SIGPIPE", argv[0]); #ifdef FILTER_ENABLE if (config->filter) filter_init (); #endif /* FILTER_ENABLE */ /* Start listening on the selected port. */ if (child_listening_sockets(config->listen_addrs, config->port) < 0) { fprintf (stderr, "%s: Could not create listening sockets.\n", argv[0]); exit (EX_OSERR); } /* Create pid file before we drop privileges */ if (config->pidpath) { if (pidfile_create (config->pidpath) < 0) { fprintf (stderr, "%s: Could not create PID file.\n", argv[0]); exit (EX_OSERR); } } /* Switch to a different user if we're running as root */ if (geteuid () == 0) change_user (argv[0]); else log_message (LOG_INFO, "Not running as root, so not changing UID/GID."); /* Create log file after we drop privileges */ if (setup_logging ()) { exit (EX_SOFTWARE); } /* These signals are only for the parent process. */ log_message (LOG_INFO, "Setting the various signals."); setup_sig (SIGCHLD, takesig, "SIGCHLD", argv[0]); setup_sig (SIGTERM, takesig, "SIGTERM", argv[0]); setup_sig (SIGINT, takesig, "SIGINT", argv[0]); if (daemonized) setup_sig (SIGHUP, takesig, "SIGHUP", argv[0]); setup_sig (SIGUSR1, takesig, "SIGUSR1", argv[0]); loop_records_init(); /* Start the main loop */ log_message (LOG_INFO, "Starting main loop. Accepting connections."); child_main_loop (); log_message (LOG_NOTICE, "Shutting down."); child_kill_children (SIGTERM); child_close_sock (); child_free_children(); loop_records_destroy(); /* Remove the PID file */ if (config->pidpath != NULL && unlink (config->pidpath) < 0) { log_message (LOG_WARNING, "Could not remove PID file \"%s\": %s.", config->pidpath, strerror (errno)); } #ifdef FILTER_ENABLE if (config->filter) filter_destroy (); #endif /* FILTER_ENABLE */ free_config (config); shutdown_logging (); return EXIT_SUCCESS; } tinyproxy-1.11.2/src/main.h000066400000000000000000000026061461674137700155710ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 1998 Steven Young * Copyright (C) 1999 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* See 'main.c' for detailed information. */ #ifndef __MAIN_H__ #define __MAIN_H__ #include "common.h" /* Global variables for the main controls of the program */ #define MAXBUFFSIZE ((size_t)(1024 * 96)) /* Max size of buffer */ #define MAX_IDLE_TIME (60 * 10) /* 10 minutes of no activity */ /* Global Structures used in the program */ extern struct config_s *config; extern unsigned int received_sighup; /* boolean */ extern int reload_config (int reload_logging); #endif /* __MAIN_H__ */ tinyproxy-1.11.2/src/mypoll.c000066400000000000000000000022461461674137700161540ustar00rootroot00000000000000#include "mypoll.h" #ifdef HAVE_POLL_H int mypoll(pollfd_struct* fds, int nfds, int timeout) { int i, ret; for(i=0; i maxfd) maxfd = fds[i].fd; if(fds[i].events & MYPOLL_READ) FD_SET(fds[i].fd, r); if(fds[i].events & MYPOLL_WRITE) FD_SET(fds[i].fd, w); } if(timeout >= 0) t = &tv; if(timeout > 0) tv.tv_sec = timeout; ret = select(maxfd+1, r, w, 0, t); switch(ret) { case -1: case 0: return ret; } for(i=0; i typedef struct pollfd pollfd_struct; #define MYPOLL_READ POLLIN #define MYPOLL_WRITE POLLOUT #else #define SELECT_OR_POLL "select" #include typedef struct mypollfd { int fd; short events; short revents; } pollfd_struct; #define MYPOLL_READ (1<<1) #define MYPOLL_WRITE (1<<2) #endif int mypoll(pollfd_struct* fds, int nfds, int timeout); #endif tinyproxy-1.11.2/src/network.c000066400000000000000000000240441461674137700163310ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 2002, 2004 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* The functions found here are used for communicating across a * network. They include both safe reading and writing (which are * the basic building blocks) along with two functions for * easily reading a line of text from the network, and a function * to write an arbitrary amount of data to the network. */ #include "main.h" #include "heap.h" #include "network.h" /* * Write the buffer to the socket. If an EINTR occurs, pick up and try * again. Keep sending until the buffer has been sent. */ ssize_t safe_write (int fd, const void *buf, size_t count) { ssize_t len; size_t bytestosend; const char *buffer = buf; assert (fd >= 0); assert (buffer != NULL); assert (count > 0); bytestosend = count; while (1) { len = send (fd, buffer, bytestosend, MSG_NOSIGNAL); if (len < 0) { if (errno == EINTR) continue; else return -errno; } if ((size_t) len == bytestosend) break; buffer += len; bytestosend -= len; } return count; } /* * Matched pair for safe_write(). If an EINTR occurs, pick up and try * again. */ ssize_t safe_read (int fd, void *buffer, size_t count) { ssize_t len; do { len = read (fd, buffer, count); } while (len < 0 && errno == EINTR); return len; } /* * Send a "message" to the file descriptor provided. This handles the * differences between the various implementations of vsnprintf. This code * was basically stolen from the snprintf() man page of Debian Linux * (although I did fix a memory leak. :) */ int write_message (int fd, const char *fmt, ...) { ssize_t n; size_t size = (1024 * 8); /* start with 8 KB and go from there */ char *buf, *tmpbuf; va_list ap; if ((buf = (char *) safemalloc (size)) == NULL) return -1; while (1) { va_start (ap, fmt); n = vsnprintf (buf, size, fmt, ap); va_end (ap); /* If that worked, break out so we can send the buffer */ if (n > -1 && (size_t) n < size) break; /* Else, try again with more space */ if (n > -1) /* precisely what is needed (glibc2.1) */ size = n + 1; else /* twice the old size (glibc2.0) */ size *= 2; if ((tmpbuf = (char *) saferealloc (buf, size)) == NULL) { safefree (buf); return -1; } else buf = tmpbuf; } if (safe_write (fd, buf, n) < 0) { safefree (buf); return -1; } safefree (buf); return 0; } /* * Read in a "line" from the socket. It might take a few loops through * the read sequence. The full string is allocate off the heap and stored * at the whole_buffer pointer. The caller needs to free the memory when * it is no longer in use. The returned line is NULL terminated. * * Returns the length of the buffer on success (not including the NULL * termination), 0 if the socket was closed, and -1 on all other errors. */ #define SEGMENT_LEN (512) #define MAXIMUM_BUFFER_LENGTH (128 * 1024) ssize_t readline (int fd, char **whole_buffer) { ssize_t whole_buffer_len; char buffer[SEGMENT_LEN]; char *ptr; ssize_t ret; ssize_t diff; struct read_lines_s { char *data; size_t len; struct read_lines_s *next; }; struct read_lines_s *first_line, *line_ptr; first_line = (struct read_lines_s *) safecalloc (sizeof (struct read_lines_s), 1); if (!first_line) return -ENOMEM; line_ptr = first_line; whole_buffer_len = 0; for (;;) { ret = recv (fd, buffer, SEGMENT_LEN, MSG_PEEK); if (ret <= 0) goto CLEANUP; ptr = (char *) memchr (buffer, '\n', ret); if (ptr) diff = ptr - buffer + 1; else diff = ret; whole_buffer_len += diff; /* * Don't allow the buffer to grow without bound. If we * get to more than MAXIMUM_BUFFER_LENGTH close. */ if (whole_buffer_len > MAXIMUM_BUFFER_LENGTH) { ret = -ERANGE; goto CLEANUP; } line_ptr->data = (char *) safemalloc (diff); if (!line_ptr->data) { ret = -ENOMEM; goto CLEANUP; } ret = recv (fd, line_ptr->data, diff, 0); if (ret == -1) { goto CLEANUP; } line_ptr->len = diff; if (ptr) { line_ptr->next = NULL; break; } line_ptr->next = (struct read_lines_s *) safecalloc (sizeof (struct read_lines_s), 1); if (!line_ptr->next) { ret = -ENOMEM; goto CLEANUP; } line_ptr = line_ptr->next; } *whole_buffer = (char *) safemalloc (whole_buffer_len + 1); if (!*whole_buffer) { ret = -ENOMEM; goto CLEANUP; } *(*whole_buffer + whole_buffer_len) = '\0'; whole_buffer_len = 0; line_ptr = first_line; while (line_ptr) { memcpy (*whole_buffer + whole_buffer_len, line_ptr->data, line_ptr->len); whole_buffer_len += line_ptr->len; line_ptr = line_ptr->next; } ret = whole_buffer_len; CLEANUP: do { line_ptr = first_line->next; if (first_line->data) safefree (first_line->data); safefree (first_line); first_line = line_ptr; } while (first_line); return ret; } /* * Convert the network address into either a dotted-decimal or an IPv6 * hex string. */ const char *get_ip_string (struct sockaddr *sa, char *buf, size_t buflen) { const char *result; assert (sa != NULL); assert (buf != NULL); assert (buflen != 0); buf[0] = '\0'; /* start with an empty string */ switch (sa->sa_family) { case AF_INET: { struct sockaddr_in *sa_in = (struct sockaddr_in *) sa; result = inet_ntop (AF_INET, &sa_in->sin_addr, buf, buflen); break; } case AF_INET6: { struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *) sa; result = inet_ntop (AF_INET6, &sa_in6->sin6_addr, buf, buflen); break; } default: /* no valid family */ return NULL; } return result; } /* * Convert a numeric character string into an IPv6 network address * (in binary form.) The function works just like inet_pton(), but it * will accept both IPv4 and IPv6 numeric addresses. * * Returns the same as inet_pton(). */ int full_inet_pton (const char *ip, void *dst) { char buf[24], tmp[24]; /* IPv4->IPv6 = ::FFFF:xxx.xxx.xxx.xxx\0 */ int n; assert (ip != NULL && strlen (ip) != 0); assert (dst != NULL); /* * Check if the string is an IPv4 numeric address. We use the * older inet_aton() call since it handles more IPv4 numeric * address formats. */ n = inet_aton (ip, (struct in_addr *) dst); if (n == 0) { /* * Simple case: "ip" wasn't an IPv4 numeric address, so * try doing the conversion as an IPv6 address. This * will either succeed or fail, but we can't do any * more processing anyway. */ return inet_pton (AF_INET6, ip, dst); } /* * "ip" was an IPv4 address, so we need to convert it to * an IPv4-mapped IPv6 address and do the conversion * again to get the IPv6 network structure. * * We convert the IPv4 binary address back into the * standard dotted-decimal format using inet_ntop() * so we can be sure that inet_pton will accept the * full string. */ snprintf (buf, sizeof (buf), "::ffff:%s", inet_ntop (AF_INET, dst, tmp, sizeof (tmp))); return inet_pton (AF_INET6, buf, dst); } tinyproxy-1.11.2/src/network.h000066400000000000000000000024711461674137700163360ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 2002, 2004 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* See 'network.c' for detailed information. */ #ifndef TINYPROXY_NETWORK_H #define TINYPROXY_NETWORK_H extern ssize_t safe_write (int fd, const void *buf, size_t count); extern ssize_t safe_read (int fd, void *buf, size_t count); extern int write_message (int fd, const char *fmt, ...); extern ssize_t readline (int fd, char **whole_buffer); extern const char *get_ip_string (struct sockaddr *sa, char *buf, size_t len); extern int full_inet_pton (const char *ip, void *dst); #endif tinyproxy-1.11.2/src/orderedmap.c000066400000000000000000000045341461674137700167640ustar00rootroot00000000000000#ifdef HAVE_CONFIG_H # include #else # define _ALL_SOURCE # define _GNU_SOURCE #endif #include #include "sblist.h" #include "orderedmap.h" static void orderedmap_destroy_contents(struct orderedmap *o) { char **p, *q; size_t i; htab_value *v; if(!o) return; if(o->values) { while(sblist_getsize(o->values)) { p = sblist_get(o->values, 0); if(p) free(*p); sblist_delete(o->values, 0); } sblist_free(o->values); } if(o->map) { i = 0; while((i = htab_next(o->map, i, &q, &v))) free(q); htab_destroy(o->map); } } struct orderedmap *orderedmap_create(size_t nbuckets) { struct orderedmap o = {0}, *new; o.values = sblist_new(sizeof(void*), 32); if(!o.values) goto oom; o.map = htab_create(nbuckets); if(!o.map) goto oom; new = malloc(sizeof o); if(!new) goto oom; memcpy(new, &o, sizeof o); return new; oom:; orderedmap_destroy_contents(&o); return 0; } void* orderedmap_destroy(struct orderedmap *o) { orderedmap_destroy_contents(o); free(o); return 0; } int orderedmap_append(struct orderedmap *o, const char *key, char *value) { size_t index; char *nk, *nv; nk = nv = 0; nk = strdup(key); nv = strdup(value); if(!nk || !nv) goto oom; index = sblist_getsize(o->values); if(!sblist_add(o->values, &nv)) goto oom; if(!htab_insert(o->map, nk, HTV_N(index))) { sblist_delete(o->values, index); goto oom; } return 1; oom:; free(nk); free(nv); return 0; } char* orderedmap_find(struct orderedmap *o, const char *key) { char **p; htab_value *v = htab_find(o->map, key); if(!v) return 0; p = sblist_get(o->values, v->n); return p?*p:0; } int orderedmap_remove(struct orderedmap *o, const char *key) { size_t i; char *lk; char *sk; char **sv; htab_value *lv, *v = htab_find2(o->map, key, &sk); if(!v) return 0; sv = sblist_get(o->values, v->n); free(*sv); sblist_delete(o->values, v->n); i = 0; while((i = htab_next(o->map, i, &lk, &lv))) { if(lv->n > v->n) lv->n--; } htab_delete(o->map, key); free(sk); return 1; } size_t orderedmap_next(struct orderedmap *o, size_t iter, char** key, char** value) { size_t h_iter; htab_value* hval; char **p; if(iter < sblist_getsize(o->values)) { h_iter = 0; while((h_iter = htab_next(o->map, h_iter, key, &hval))) { if(hval->n == iter) { p = sblist_get(o->values, iter); *value = p?*p:0; return iter+1; } } } return 0; } tinyproxy-1.11.2/src/orderedmap.h000066400000000000000000000011051461674137700167600ustar00rootroot00000000000000#ifndef ORDEREDMAP_H #define ORDEREDMAP_H #include #include "sblist.h" #include "hsearch.h" typedef struct orderedmap { sblist* values; struct htab *map; } *orderedmap; struct orderedmap *orderedmap_create(size_t nbuckets); void* orderedmap_destroy(struct orderedmap *o); int orderedmap_append(struct orderedmap *o, const char *key, char *value ); char* orderedmap_find(struct orderedmap *o, const char *key); int orderedmap_remove(struct orderedmap *o, const char *key); size_t orderedmap_next(struct orderedmap *o, size_t iter, char** key, char** value); #endif tinyproxy-1.11.2/src/reqs.c000066400000000000000000001750501461674137700156160ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 1998 Steven Young * Copyright (C) 1999-2005 Robert James Kaes * Copyright (C) 2000 Chris Lightfoot * Copyright (C) 2002 Petr Lampa * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* This is where all the work in tinyproxy is actually done. Incoming * connections have a new child created for them. The child then * processes the headers from the client, the response from the server, * and then relays the bytes between the two. */ #include "main.h" #include "acl.h" #include "anonymous.h" #include "buffer.h" #include "conns.h" #include "filter.h" #include "hsearch.h" #include "orderedmap.h" #include "heap.h" #include "html-error.h" #include "log.h" #include "network.h" #include "reqs.h" #include "sock.h" #include "stats.h" #include "text.h" #include "utils.h" #include "sblist.h" #include "reverse-proxy.h" #include "transparent-proxy.h" #include "upstream.h" #include "connect-ports.h" #include "conf.h" #include "basicauth.h" #include "loop.h" #include "mypoll.h" /* * Maximum length of a HTTP line */ #define HTTP_LINE_LENGTH (MAXBUFFSIZE / 6) /* * Macro to help test if the Upstream proxy supported is compiled in and * enabled. */ #ifdef UPSTREAM_SUPPORT # define UPSTREAM_CONFIGURED() (config->upstream_list != NULL) # define UPSTREAM_HOST(host) upstream_get(host, config->upstream_list) # define UPSTREAM_IS_HTTP(conn) (conn->upstream_proxy != NULL && conn->upstream_proxy->type == PT_HTTP) #else # define UPSTREAM_CONFIGURED() (0) # define UPSTREAM_HOST(host) (NULL) # define UPSTREAM_IS_HTTP(up) (0) #endif /* * Codify the test for the carriage return and new line characters. */ #define CHECK_CRLF(header, len) \ (((len) == 1 && header[0] == '\n') || \ ((len) == 2 && header[0] == '\r' && header[1] == '\n')) /* * Codify the test for header fields folded over multiple lines. */ #define CHECK_LWS(header, len) \ ((len) > 0 && (header[0] == ' ' || header[0] == '\t')) /* * Read in the first line from the client (the request line for HTTP * connections. The request line is allocated from the heap, but it must * be freed in another function. */ static int read_request_line (struct conn_s *connptr) { ssize_t len; retry: len = readline (connptr->client_fd, &connptr->request_line); if (len <= 0) { log_message (LOG_ERR, "read_request_line: Client (file descriptor: %d) " "closed socket before read.", connptr->client_fd); return -1; } /* * Strip the new line and carriage return from the string. */ if (chomp (connptr->request_line, len) == len) { /* * If the number of characters removed is the same as the * length then it was a blank line. Free the buffer and * try again (since we're looking for a request line.) */ safefree (connptr->request_line); goto retry; } log_message (LOG_CONN, "Request (file descriptor %d): %s", connptr->client_fd, connptr->request_line); return 0; } /* * Free all the memory allocated in a request. */ static void free_request_struct (struct request_s *request) { if (!request) return; safefree (request->method); safefree (request->protocol); if (request->host) safefree (request->host); if (request->path) safefree (request->path); safefree (request); } /* * Take a host string and if there is a username/password part, strip * it off. */ static void strip_username_password (char *host) { char *p; assert (host); assert (strlen (host) > 0); if ((p = strchr (host, '@')) == NULL) return; /* * Move the pointer past the "@" and then copy from that point * until the NUL to the beginning of the host buffer. */ p++; while (*p) *host++ = *p++; *host = '\0'; } /* * Take a host string and if there is a port part, strip * it off and set proper port variable i.e. for www.host.com:8001 */ static int strip_return_port (char *host) { char *ptr1; char *ptr2; int port; ptr1 = strrchr (host, ':'); if (ptr1 == NULL) return 0; /* Check for IPv6 style literals */ ptr2 = strchr (ptr1, ']'); if (ptr2 != NULL) return 0; *ptr1++ = '\0'; if (sscanf (ptr1, "%d", &port) != 1) /* one conversion required */ return 0; return port; } /* * Pull the information out of the URL line. * This expects urls with the initial '://' * part stripped and hence can handle http urls, * (proxied) ftp:// urls and https-requests that * come in without the proto:// part via CONNECT. */ static int extract_url (const char *url, int default_port, struct request_s *request) { char *p; int port; /* Split the URL on the slash to separate host from path */ p = strchr (url, '/'); if (p != NULL) { int len; len = p - url; request->host = (char *) safemalloc (len + 1); memcpy (request->host, url, len); request->host[len] = '\0'; request->path = safestrdup (p); } else { request->host = safestrdup (url); request->path = safestrdup ("/"); } if (!request->host || !request->path) goto ERROR_EXIT; /* Remove the username/password if they're present */ strip_username_password (request->host); /* Find a proper port in www.site.com:8001 URLs */ port = strip_return_port (request->host); request->port = (port != 0) ? port : default_port; /* Remove any surrounding '[' and ']' from IPv6 literals */ p = strrchr (request->host, ']'); if (p && (*(request->host) == '[')) { memmove(request->host, request->host + 1, strlen(request->host) - 2); *p = '\0'; p--; *p = '\0'; } return 0; ERROR_EXIT: if (request->host) safefree (request->host); if (request->path) safefree (request->path); return -1; } /* * Create a connection for HTTP connections. */ static int establish_http_connection (struct conn_s *connptr, struct request_s *request) { char portbuff[7]; char dst[sizeof(struct in6_addr)]; /* Build a port string if it's not a standard port */ if (request->port != HTTP_PORT && request->port != HTTP_PORT_SSL) snprintf (portbuff, 7, ":%u", request->port); else portbuff[0] = '\0'; if (inet_pton(AF_INET6, request->host, dst) > 0) { /* host is an IPv6 address literal, so surround it with * [] */ return write_message (connptr->server_fd, "%s %s HTTP/1.%u\r\n" "Host: [%s]%s\r\n" "Connection: close\r\n", request->method, request->path, connptr->protocol.major != 1 ? 0 : connptr->protocol.minor, request->host, portbuff); } else if (connptr->upstream_proxy && connptr->upstream_proxy->type == PT_HTTP && connptr->upstream_proxy->ua.authstr) { return write_message (connptr->server_fd, "%s %s HTTP/1.%u\r\n" "Host: %s%s\r\n" "Connection: close\r\n" "Proxy-Authorization: Basic %s\r\n", request->method, request->path, connptr->protocol.major != 1 ? 0 : connptr->protocol.minor, request->host, portbuff, connptr->upstream_proxy->ua.authstr); } else { return write_message (connptr->server_fd, "%s %s HTTP/1.%u\r\n" "Host: %s%s\r\n" "Connection: close\r\n", request->method, request->path, connptr->protocol.major != 1 ? 0 : connptr->protocol.minor, request->host, portbuff); } } /* * Send the appropriate response to the client to establish a * connection via CONNECT method. */ static int send_connect_method_response (struct conn_s *connptr) { return write_message (connptr->client_fd, "HTTP/1.%u 200 Connection established\r\n" "Proxy-agent: " PACKAGE "/" VERSION "\r\n" "\r\n", connptr->protocol.major != 1 ? 0 : connptr->protocol.minor); } /* * Break the request line apart and figure out where to connect and * build a new request line. Finally connect to the remote server. */ static struct request_s *process_request (struct conn_s *connptr, orderedmap hashofheaders) { char *url; struct request_s *request; int ret, skip_trans; size_t request_len; skip_trans = 0; /* NULL out all the fields so frees don't cause segfaults. */ request = (struct request_s *) safecalloc (1, sizeof (struct request_s)); if (!request) return NULL; request_len = strlen (connptr->request_line) + 1; request->method = (char *) safemalloc (request_len); url = (char *) safemalloc (request_len); request->protocol = (char *) safemalloc (request_len); if (!request->method || !url || !request->protocol) { goto fail; } /* zero-terminate the strings so they don't contain junk in error page */ request->method[0] = url[0] = request->protocol[0] = 0; ret = sscanf (connptr->request_line, "%[^ ] %[^ ] %[^ ]", request->method, url, request->protocol); if (ret == 2 && !strcasecmp (request->method, "GET")) { request->protocol[0] = 0; /* Indicate that this is a HTTP/0.9 GET request */ connptr->protocol.major = 0; connptr->protocol.minor = 9; } else if (ret == 3 && !strncasecmp (request->protocol, "HTTP/", 5)) { /* * Break apart the protocol and update the connection * structure. */ ret = sscanf (request->protocol + 5, "%u.%u", &connptr->protocol.major, &connptr->protocol.minor); /* * If the conversion doesn't succeed, drop down below and * send the error to the user. */ if (ret != 2) goto BAD_REQUEST_ERROR; } else { BAD_REQUEST_ERROR: log_message (LOG_ERR, "process_request: Bad Request on file descriptor %d", connptr->client_fd); indicate_http_error (connptr, 400, "Bad Request", "detail", "Request has an invalid format", "url", url, NULL); goto fail; } #ifdef REVERSE_SUPPORT if (config->reversepath_list != NULL) { /* * Rewrite the URL based on the reverse path. After calling * reverse_rewrite_url "url" can be freed since we either * have the newly rewritten URL, or something failed and * we'll be closing anyway. */ char *reverse_url; int reverse_status; reverse_url = reverse_rewrite_url (connptr, hashofheaders, url, &reverse_status); if (reverse_url != NULL) { if (reverse_status == 301) { char buf[PATH_MAX]; snprintf (buf, sizeof buf, "Location: %s\r\n", reverse_url); send_http_headers (connptr, 301, "Moved Permanently", buf); goto fail; } safefree (url); url = reverse_url; skip_trans = 1; } else if (config->reverseonly) { log_message (LOG_ERR, "Bad request, no mapping for '%s' found", url); indicate_http_error (connptr, 400, "Bad Request", "detail", "No mapping found for " "requested url", "url", url, NULL); goto fail; } } #endif if (strncasecmp (url, "http://", 7) == 0 || (UPSTREAM_CONFIGURED () && strncasecmp (url, "ftp://", 6) == 0)) { char *skipped_type = strstr (url, "//") + 2; if (extract_url (skipped_type, HTTP_PORT, request) < 0) { indicate_http_error (connptr, 400, "Bad Request", "detail", "Could not parse URL", "url", url, NULL); goto fail; } } else if (strcmp (request->method, "CONNECT") == 0) { if (extract_url (url, HTTP_PORT_SSL, request) < 0) { indicate_http_error (connptr, 400, "Bad Request", "detail", "Could not parse URL", "url", url, NULL); goto fail; } /* Verify that the port in the CONNECT method is allowed */ if (!check_allowed_connect_ports (request->port, config->connect_ports)) { indicate_http_error (connptr, 403, "Access violation", "detail", "The CONNECT method not allowed " "with the port you tried to use.", "url", url, NULL); log_message (LOG_INFO, "Refused CONNECT method on port %d", request->port); goto fail; } connptr->connect_method = TRUE; } else { #ifdef TRANSPARENT_PROXY if (!skip_trans) { if (!do_transparent_proxy (connptr, hashofheaders, request, config, &url)) goto fail; } else #endif { indicate_http_error (connptr, 501, "Not Implemented", "detail", "Unknown method or unsupported protocol.", "url", url, NULL); log_message (LOG_INFO, "Unknown method (%s) or protocol (%s)", request->method, url); goto fail; } } #ifdef FILTER_ENABLE /* * Filter restricted domains/urls */ if (config->filter) { int fu = config->filter_opts & FILTER_OPT_URL; ret = filter_run (fu ? url : request->host); if (ret) { update_stats (STAT_DENIED); log_message (LOG_NOTICE, "Proxying refused on filtered %s \"%s\"", fu ? "url" : "domain", fu ? url : request->host); indicate_http_error (connptr, 403, "Filtered", "detail", "The request you made has been filtered", "url", url, NULL); goto fail; } } #endif /* * Check to see if they're requesting the stat host */ if (config->stathost && strcmp (config->stathost, request->host) == 0) { log_message (LOG_NOTICE, "Request for the stathost."); connptr->show_stats = TRUE; goto fail; } safefree (url); return request; fail: safefree (url); free_request_struct (request); return NULL; } /* * pull_client_data is used to pull across any client data (like in a * POST) which needs to be handled before an error can be reported, or * server headers can be processed. * - rjkaes */ static int pull_client_data (struct conn_s *connptr, long int length, int iehack) { char *buffer; ssize_t len; int ret; buffer = (char *) safemalloc (min (MAXBUFFSIZE, (unsigned long int) length)); if (!buffer) return -1; do { len = safe_read (connptr->client_fd, buffer, min (MAXBUFFSIZE, (unsigned long int) length)); if (len <= 0) goto ERROR_EXIT; if (!connptr->error_variables) { if (safe_write (connptr->server_fd, buffer, len) < 0) goto ERROR_EXIT; } length -= len; } while (length > 0); if (iehack) { /* * BUG FIX: Internet Explorer will leave two bytes (carriage * return and line feed) at the end of a POST message. These * need to be eaten for tinyproxy to work correctly. */ ret = socket_nonblocking (connptr->client_fd); if (ret != 0) { log_message(LOG_ERR, "Failed to set the client socket " "to non-blocking: %s", strerror(errno)); goto ERROR_EXIT; } len = recv (connptr->client_fd, buffer, 2, MSG_PEEK); ret = socket_blocking (connptr->client_fd); if (ret != 0) { log_message(LOG_ERR, "Failed to set the client socket " "to blocking: %s", strerror(errno)); goto ERROR_EXIT; } if (len < 0 && errno != EAGAIN) goto ERROR_EXIT; if ((len == 2) && CHECK_CRLF (buffer, len)) { ssize_t bytes_read; bytes_read = read (connptr->client_fd, buffer, 2); if (bytes_read == -1) { log_message (LOG_WARNING, "Could not read two bytes from POST message"); } } } safefree (buffer); return 0; ERROR_EXIT: safefree (buffer); return -1; } /* pull chunked client data */ static int pull_client_data_chunked (struct conn_s *connptr) { char *buffer = 0; ssize_t len; long chunklen; while(1) { if (buffer) safefree(buffer); len = readline (connptr->client_fd, &buffer); if (len <= 0) goto ERROR_EXIT; if (!connptr->error_variables) { if (safe_write (connptr->server_fd, buffer, len) < 0) goto ERROR_EXIT; } chunklen = strtol (buffer, (char**)0, 16); if (pull_client_data (connptr, chunklen+2, 0) < 0) goto ERROR_EXIT; if(!chunklen) break; } safefree (buffer); return 0; ERROR_EXIT: safefree (buffer); return -1; } #ifdef XTINYPROXY_ENABLE /* * Add the X-Tinyproxy header to the collection of headers being sent to * the server. * -rjkaes */ static int add_xtinyproxy_header (struct conn_s *connptr) { assert (connptr && connptr->server_fd >= 0); return write_message (connptr->server_fd, "X-Tinyproxy: %s\r\n", connptr->client_ip_addr); } #endif /* XTINYPROXY */ /* * Take a complete header line and break it apart (into a key and the data.) * Now insert this information into the hashmap for the connection so it * can be retrieved and manipulated later. */ static int add_header_to_connection (orderedmap hashofheaders, char *header, size_t len) { char *sep; /* Get rid of the new line and return at the end */ len -= chomp (header, len); sep = strchr (header, ':'); if (!sep) return 0; /* just skip invalid header, do not give error */ /* Blank out colons, spaces, and tabs. */ while (*sep == ':' || *sep == ' ' || *sep == '\t') *sep++ = '\0'; /* Calculate the new length of just the data */ len -= sep - header - 1; return orderedmap_append (hashofheaders, header, sep); } /* * Define maximum number of headers that we accept. * This should be big enough to handle legitimate cases, * but limited to avoid DoS. */ #define MAX_HEADERS 10000 /* * Read all the headers from the stream */ static int get_all_headers (int fd, orderedmap hashofheaders) { char *line = NULL; char *header = NULL; int count; char *tmp; ssize_t linelen; ssize_t len = 0; unsigned int double_cgi = FALSE; /* boolean */ assert (fd >= 0); assert (hashofheaders != NULL); for (count = 0; count < MAX_HEADERS; count++) { if ((linelen = readline (fd, &line)) <= 0) { safefree (header); safefree (line); return -1; } /* * If we received a CR LF or a non-continuation line, then add * the accumulated header field, if any, to the hashmap, and * reset it. */ if (CHECK_CRLF (line, linelen) || !CHECK_LWS (line, linelen)) { if (!double_cgi && len > 0 && add_header_to_connection (hashofheaders, header, len) < 0) { safefree (header); safefree (line); return -1; } len = 0; } /* * If we received just a CR LF on a line, the headers are * finished. */ if (CHECK_CRLF (line, linelen)) { safefree (header); safefree (line); return 0; } /* * BUG FIX: The following code detects a "Double CGI" * situation so that we can handle the nonconforming system. * This problem was found when accessing cgi.ebay.com, and it * turns out to be a wider spread problem as well. * * If "Double CGI" is in effect, duplicate headers are * ignored. * * FIXME: Might need to change this to a more robust check. */ if (linelen >= 5 && strncasecmp (line, "HTTP/", 5) == 0) { double_cgi = TRUE; } /* * Append the new line to the current header field. */ tmp = (char *) saferealloc (header, len + linelen); if (tmp == NULL) { safefree (header); safefree (line); return -1; } header = tmp; memcpy (header + len, line, linelen); len += linelen; safefree (line); } /* * If we get here, this means we reached MAX_HEADERS count. * Bail out with error. */ safefree (header); safefree (line); return -1; } /* * Extract the headers to remove. These headers were listed in the Connection * and Proxy-Connection headers. */ static int remove_connection_headers (orderedmap hashofheaders) { static const char *headers[] = { "connection", "proxy-connection" }; char *data; char *ptr; ssize_t len; int i,j,df; for (i = 0; i != (sizeof (headers) / sizeof (char *)); ++i) { /* Look for the connection header. If it's not found, return. */ data = orderedmap_find(hashofheaders, headers[i]); if (!data) return 0; len = strlen(data); /* * Go through the data line and replace any special characters * with a NULL. */ ptr = data; while ((ptr = strpbrk (ptr, "()<>@,;:\\\"/[]?={} \t"))) *ptr++ = '\0'; /* * All the tokens are separated by NULLs. Now go through the * token and remove them from the hashofheaders. */ ptr = data; while (ptr < data + len) { df = 0; /* check that ptr isn't one of headers to prevent double-free (CVE-2023-49606) */ for (j = 0; j != (sizeof (headers) / sizeof (char *)); ++j) if(!strcasecmp(ptr, headers[j])) df = 1; if (!df) orderedmap_remove (hashofheaders, ptr); /* Advance ptr to the next token */ ptr += strlen (ptr) + 1; while (ptr < data + len && *ptr == '\0') ptr++; } /* Now remove the connection header it self. */ orderedmap_remove (hashofheaders, headers[i]); } return 0; } /* * If there is a Content-Length header, then return the value; otherwise, return * -1. */ static long get_content_length (orderedmap hashofheaders) { char *data; long content_length = -1; data = orderedmap_find (hashofheaders, "content-length"); if (data) content_length = atol (data); return content_length; } static int is_chunked_transfer (orderedmap hashofheaders) { char *data; data = orderedmap_find (hashofheaders, "transfer-encoding"); return data ? !strcmp (data, "chunked") : 0; } /* * Search for Via header in a hash of headers and either write a new Via * header, or append our information to the end of an existing Via header. * * FIXME: Need to add code to "hide" our internal information for security * purposes. */ static int write_via_header (int fd, orderedmap hashofheaders, unsigned int major, unsigned int minor) { char hostname[512]; char *data; int ret; if (config->disable_viaheader) { ret = 0; goto done; } if (config->via_proxy_name) { strlcpy (hostname, config->via_proxy_name, sizeof (hostname)); } else if (gethostname (hostname, sizeof (hostname)) < 0) { strlcpy (hostname, "unknown", 512); } /* * See if there is a "Via" header. If so, again we need to do a bit * of processing. */ data = orderedmap_find (hashofheaders, "via"); if (data) { ret = write_message (fd, "Via: %s, %hu.%hu %s (%s/%s)\r\n", data, major, minor, hostname, PACKAGE, VERSION); orderedmap_remove (hashofheaders, "via"); } else { ret = write_message (fd, "Via: %hu.%hu %s (%s/%s)\r\n", major, minor, hostname, PACKAGE, VERSION); } done: return ret; } /* * Number of buckets to use internally in the hashmap. */ #define HEADER_BUCKETS 32 /* * Here we loop through all the headers the client is sending. If we * are running in anonymous mode, we will _only_ send the headers listed * (plus a few which are required for various methods). * - rjkaes */ static int process_client_headers (struct conn_s *connptr, orderedmap hashofheaders) { static const char *skipheaders[] = { "host", "keep-alive", "proxy-connection", "te", "trailers", "upgrade" }; int i; size_t iter; int ret = 0; char *data, *header; /* * Don't send headers if there's already an error, if the request was * a stats request, or if this was a CONNECT method (unless upstream * http proxy is in use.) */ if (connptr->server_fd == -1 || connptr->show_stats || (connptr->connect_method && ! UPSTREAM_IS_HTTP(connptr))) { log_message (LOG_INFO, "Not sending client headers to remote machine"); return 0; } /* * See if there is a "Content-Length" header. If so, again we need * to do a bit of processing. */ connptr->content_length.client = get_content_length (hashofheaders); /* Check whether client sends chunked data. */ if (connptr->content_length.client == -1 && is_chunked_transfer (hashofheaders)) connptr->content_length.client = -2; /* * See if there is a "Connection" header. If so, we need to do a bit * of processing. :) */ remove_connection_headers (hashofheaders); /* * Delete the headers listed in the skipheaders list */ for (i = 0; i != (sizeof (skipheaders) / sizeof (char *)); i++) { orderedmap_remove (hashofheaders, skipheaders[i]); } /* Send, or add the Via header */ ret = write_via_header (connptr->server_fd, hashofheaders, connptr->protocol.major, connptr->protocol.minor); if (ret < 0) { indicate_http_error (connptr, 503, "Could not send data to remote server", "detail", "A network error occurred while " "trying to write data to the remote web server.", NULL); goto PULL_CLIENT_DATA; } /* * Output all the remaining headers to the remote machine. */ iter = 0; while((iter = orderedmap_next(hashofheaders, iter, &data, &header))) { if (!is_anonymous_enabled (config) || anonymous_search (config, data) > 0) { ret = write_message (connptr->server_fd, "%s: %s\r\n", data, header); if (ret < 0) { indicate_http_error (connptr, 503, "Could not send data to remote server", "detail", "A network error occurred while " "trying to write data to the " "remote web server.", NULL); goto PULL_CLIENT_DATA; } } } #if defined(XTINYPROXY_ENABLE) if (config->add_xtinyproxy) add_xtinyproxy_header (connptr); #endif /* Write the final "blank" line to signify the end of the headers */ if (safe_write (connptr->server_fd, "\r\n", 2) < 0) return -1; /* * Spin here pulling the data from the client. */ PULL_CLIENT_DATA: if (connptr->content_length.client > 0) { ret = pull_client_data (connptr, connptr->content_length.client, 1); } else if (connptr->content_length.client == -2) ret = pull_client_data_chunked (connptr); return ret; } /* * Loop through all the headers (including the response code) from the * server. */ static int process_server_headers (struct conn_s *connptr) { static const char *skipheaders[] = { "keep-alive", "proxy-authenticate", "proxy-authorization", "proxy-connection", }; char *response_line; orderedmap hashofheaders; size_t iter; char *data, *header; ssize_t len; int i; int ret; #ifdef REVERSE_SUPPORT struct reversepath *reverse = config->reversepath_list; #endif /* Get the response line from the remote server. */ retry: len = readline (connptr->server_fd, &response_line); if (len <= 0) return -1; /* * Strip the new line and character return from the string. */ if (chomp (response_line, len) == len) { /* * If the number of characters removed is the same as the * length then it was a blank line. Free the buffer and * try again (since we're looking for a request line.) */ safefree (response_line); goto retry; } hashofheaders = orderedmap_create (HEADER_BUCKETS); if (!hashofheaders) { safefree (response_line); return -1; } /* * Get all the headers from the remote server in a big hash */ if (get_all_headers (connptr->server_fd, hashofheaders) < 0) { log_message (LOG_WARNING, "Could not retrieve all the headers from the remote server."); orderedmap_destroy (hashofheaders); safefree (response_line); indicate_http_error (connptr, 503, "Could not retrieve all the headers", "detail", PACKAGE_NAME " " "was unable to retrieve and process headers from " "the remote web server.", NULL); return -1; } /* * At this point we've received the response line and all the * headers. However, if this is a simple HTTP/0.9 request we * CAN NOT send any of that information back to the client. * Instead we'll free all the memory and return. */ if (connptr->protocol.major < 1) { orderedmap_destroy (hashofheaders); safefree (response_line); return 0; } /* Send the saved response line first */ ret = write_message (connptr->client_fd, "%s\r\n", response_line); safefree (response_line); if (ret < 0) goto ERROR_EXIT; /* * If there is a "Content-Length" header, retrieve the information * from it for later use. */ connptr->content_length.server = get_content_length (hashofheaders); /* * See if there is a connection header. If so, we need to to a bit of * processing. */ remove_connection_headers (hashofheaders); /* * Delete the headers listed in the skipheaders list */ for (i = 0; i != (sizeof (skipheaders) / sizeof (char *)); i++) { orderedmap_remove (hashofheaders, skipheaders[i]); } /* Send, or add the Via header */ ret = write_via_header (connptr->client_fd, hashofheaders, connptr->protocol.major, connptr->protocol.minor); if (ret < 0) goto ERROR_EXIT; #ifdef REVERSE_SUPPORT /* Write tracking cookie for the magical reverse proxy path hack */ if (config->reversemagic && connptr->reversepath) { ret = write_message (connptr->client_fd, "Set-Cookie: " REVERSE_COOKIE "=%s; path=/\r\n", connptr->reversepath); if (ret < 0) goto ERROR_EXIT; } /* Rewrite the HTTP redirect if needed */ if (config->reversebaseurl && (header = orderedmap_find (hashofheaders, "location"))) { /* Look for a matching entry in the reversepath list */ while (reverse) { if (strncasecmp (header, reverse->url, (len = strlen (reverse-> url))) == 0) break; reverse = reverse->next; } if (reverse) { ret = write_message (connptr->client_fd, "Location: %s%s%s\r\n", config->reversebaseurl, (reverse->path + 1), (header + len)); if (ret < 0) goto ERROR_EXIT; log_message (LOG_INFO, "Rewriting HTTP redirect: %s -> %s%s%s", header, config->reversebaseurl, (reverse->path + 1), (header + len)); orderedmap_remove (hashofheaders, "location"); } } #endif /* * All right, output all the remaining headers to the client. */ iter = 0; while ((iter = orderedmap_next(hashofheaders, iter, &data, &header))) { ret = write_message (connptr->client_fd, "%s: %s\r\n", data, header); if (ret < 0) goto ERROR_EXIT; } orderedmap_destroy (hashofheaders); /* Write the final blank line to signify the end of the headers */ if (safe_write (connptr->client_fd, "\r\n", 2) < 0) return -1; return 0; ERROR_EXIT: orderedmap_destroy (hashofheaders); return -1; } /* * Switch the sockets into nonblocking mode and begin relaying the bytes * between the two connections. We continue to use the buffering code * since we want to be able to buffer a certain amount for slower * connections (as this was the reason why I originally modified * tinyproxy oh so long ago...) * - rjkaes */ static void relay_connection (struct conn_s *connptr) { int ret; ssize_t bytes_received; for (;;) { pollfd_struct fds[2] = {0}; fds[0].fd = connptr->client_fd; fds[1].fd = connptr->server_fd; if (buffer_size (connptr->sbuffer) > 0) fds[0].events |= MYPOLL_WRITE; if (buffer_size (connptr->cbuffer) > 0) fds[1].events |= MYPOLL_WRITE; if (buffer_size (connptr->sbuffer) < MAXBUFFSIZE) fds[1].events |= MYPOLL_READ; if (buffer_size (connptr->cbuffer) < MAXBUFFSIZE) fds[0].events |= MYPOLL_READ; ret = mypoll(fds, 2, config->idletimeout); if (ret == 0) { log_message (LOG_INFO, "Idle Timeout (after " SELECT_OR_POLL ")"); return; } else if (ret < 0) { log_message (LOG_ERR, "relay_connection: " SELECT_OR_POLL "() error \"%s\". " "Closing connection (client_fd:%d, server_fd:%d)", strerror (errno), connptr->client_fd, connptr->server_fd); return; } if (fds[1].revents & MYPOLL_READ) { bytes_received = read_buffer (connptr->server_fd, connptr->sbuffer); if (bytes_received < 0) break; connptr->content_length.server -= bytes_received; if (connptr->content_length.server == 0) break; } if ((fds[0].revents & MYPOLL_READ) && read_buffer (connptr->client_fd, connptr->cbuffer) < 0) { break; } if ((fds[1].revents & MYPOLL_WRITE) && write_buffer (connptr->server_fd, connptr->cbuffer) < 0) { break; } if ((fds[0].revents & MYPOLL_WRITE) && write_buffer (connptr->client_fd, connptr->sbuffer) < 0) { break; } } while (buffer_size (connptr->sbuffer) > 0) { if (write_buffer (connptr->client_fd, connptr->sbuffer) < 0) break; } shutdown (connptr->client_fd, SHUT_WR); /* * Try to send any remaining data to the server if we can. */ ret = socket_blocking (connptr->server_fd); if (ret != 0) { log_message(LOG_ERR, "Failed to set server socket to blocking: %s", strerror(errno)); return; } while (buffer_size (connptr->cbuffer) > 0) { if (write_buffer (connptr->server_fd, connptr->cbuffer) < 0) break; } return; } static int connect_to_upstream_proxy(struct conn_s *connptr, struct request_s *request) { unsigned len; unsigned char buff[512]; /* won't use more than 7 + 255 */ unsigned short port; size_t ulen, passlen; struct upstream *cur_upstream = connptr->upstream_proxy; ulen = cur_upstream->ua.user ? strlen(cur_upstream->ua.user) : 0; passlen = cur_upstream->pass ? strlen(cur_upstream->pass) : 0; log_message(LOG_CONN, "Established connection to %s proxy \"%s\" using file descriptor %d.", proxy_type_name(cur_upstream->type), cur_upstream->host, connptr->server_fd); if (cur_upstream->type == PT_SOCKS4) { buff[0] = 4; /* socks version */ buff[1] = 1; /* connect command */ port = htons(request->port); memcpy(&buff[2], &port, 2); /* dest port */ memcpy(&buff[4], "\0\0\0\1" /* socks4a fake ip */ "\0" /* user */, 5); len = strlen(request->host); if(len>255) return -1; memcpy(&buff[9], request->host, len+1); if (9+len+1 != safe_write(connptr->server_fd, buff, 9+len+1)) return -1; if (8 != safe_read(connptr->server_fd, buff, 8)) return -1; if (buff[0]!=0 || buff[1]!=90) return -1; } else if (cur_upstream->type == PT_SOCKS5) { /* init */ int n_methods = ulen ? 2 : 1; buff[0] = 5; /* socks version */ buff[1] = n_methods; /* number of methods */ buff[2] = 0; /* no auth method */ if (ulen) buff[3] = 2; /* auth method -> username / password */ if (2+n_methods != safe_write(connptr->server_fd, buff, 2+n_methods)) return -1; if (2 != safe_read(connptr->server_fd, buff, 2)) return -1; if (buff[0] != 5 || (buff[1] != 0 && buff[1] != 2)) return -1; if (buff[1] == 2) { /* authentication */ char in[2]; char out[515]; char *cur = out; size_t c; *cur++ = 1; /* version */ c = ulen & 0xFF; *cur++ = c; memcpy(cur, cur_upstream->ua.user, c); cur += c; c = passlen & 0xFF; *cur++ = c; memcpy(cur, cur_upstream->pass, c); cur += c; if((cur - out) != safe_write(connptr->server_fd, out, cur - out)) return -1; if(2 != safe_read(connptr->server_fd, in, 2)) return -1; if(in[1] != 0 || !(in[0] == 5 || in[0] == 1)) { return -1; } } /* connect */ buff[0] = 5; /* socks version */ buff[1] = 1; /* connect */ buff[2] = 0; /* reserved */ buff[3] = 3; /* domainname */ len=strlen(request->host); if(len>255) return -1; buff[4] = len; /* length of domainname */ memcpy(&buff[5], request->host, len); /* dest ip */ port = htons(request->port); memcpy(&buff[5+len], &port, 2); /* dest port */ if (7+len != safe_write(connptr->server_fd, buff, 7+len)) return -1; if (4 != safe_read(connptr->server_fd, buff, 4)) return -1; if (buff[0]!=5 || buff[1]!=0) return -1; switch(buff[3]) { case 1: len=4; break; /* ip v4 */ case 4: len=16; break; /* ip v6 */ case 3: /* domainname */ if (1 != safe_read(connptr->server_fd, buff, 1)) return -1; len = buff[0]; /* max = 255 */ break; default: return -1; } if (2+len != safe_read(connptr->server_fd, buff, 2+len)) return -1; } else { return -1; } if (connptr->connect_method) return 0; return establish_http_connection(connptr, request); } /* * Establish a connection to the upstream proxy server. */ static int connect_to_upstream (struct conn_s *connptr, struct request_s *request) { #ifndef UPSTREAM_SUPPORT /* * This function does nothing if upstream support was not compiled * into tinyproxy. */ return -1; #else char *combined_string; int len; struct upstream *cur_upstream = connptr->upstream_proxy; if (!cur_upstream) { log_message (LOG_WARNING, "No upstream proxy defined for %s.", request->host); indicate_http_error (connptr, 502, "Unable to connect to upstream proxy."); return -1; } connptr->server_fd = opensock (cur_upstream->host, cur_upstream->port, connptr->server_ip_addr); if (connptr->server_fd < 0) { log_message (LOG_WARNING, "Could not connect to upstream proxy."); indicate_http_error (connptr, 502, "Unable to connect to upstream proxy", "detail", "A network error occurred while trying to " "connect to the upstream web proxy.", NULL); return -1; } if (cur_upstream->type != PT_HTTP) return connect_to_upstream_proxy(connptr, request); log_message (LOG_CONN, "Established connection to upstream proxy \"%s\" " "using file descriptor %d.", cur_upstream->host, connptr->server_fd); /* * We need to re-write the "path" part of the request so that we * can reuse the establish_http_connection() function. It expects a * method and path. */ if (connptr->connect_method) { len = strlen (request->host) + 7; combined_string = (char *) safemalloc (len); if (!combined_string) { return -1; } snprintf (combined_string, len, "%s:%d", request->host, request->port); } else { len = strlen (request->host) + strlen (request->path) + 14; combined_string = (char *) safemalloc (len); if (!combined_string) { return -1; } snprintf (combined_string, len, "http://%s:%d%s", request->host, request->port, request->path); } if (request->path) safefree (request->path); request->path = combined_string; return establish_http_connection (connptr, request); #endif } /* this function "drains" remaining bytes in the read pipe from the client. it's usually only called on error before displaying an error code/page. */ static int get_request_entity(struct conn_s *connptr) { int ret; pollfd_struct fds[1] = {0}; fds[0].fd = connptr->client_fd; fds[0].events |= MYPOLL_READ; ret = mypoll(fds, 1, config->idletimeout); if (ret == -1) { log_message (LOG_ERR, "Error calling " SELECT_OR_POLL " on client fd %d: %s", connptr->client_fd, strerror(errno)); } else if (ret == 0) { log_message (LOG_INFO, "no entity"); } else if (ret == 1 && (fds[0].revents & MYPOLL_READ)) { ssize_t nread; nread = read_buffer (connptr->client_fd, connptr->cbuffer); if (nread < 0) { log_message (LOG_ERR, "Error reading readable client_fd %d (%s)", connptr->client_fd, strerror(errno)); ret = -1; } else { log_message (LOG_INFO, "Read request entity of %ld bytes", (long) nread); ret = 0; } } else { log_message (LOG_ERR, "strange situation after " SELECT_OR_POLL ": " "ret = %d, but client_fd (%d) is not readable...", ret, connptr->client_fd); ret = -1; } return ret; } static void handle_connection_failure(struct conn_s *connptr, int got_headers) { /* * First, get the body if there is one. * If we don't read all there is from the socket first, * it is still marked for reading and we won't be able * to send our data properly. */ if (!got_headers && get_request_entity (connptr) < 0) { log_message (LOG_WARNING, "Could not retrieve request entity"); indicate_http_error (connptr, 400, "Bad Request", "detail", "Could not retrieve the request entity " "the client.", NULL); update_stats (STAT_BADCONN); } if (connptr->error_variables) { send_http_error_message (connptr); } else if (connptr->show_stats) { showstats (connptr); } } /* * This is the main drive for each connection. As you can tell, for the * first few steps we are using a blocking socket. If you remember the * older tinyproxy code, this use to be a very confusing state machine. * Well, no more! :) The sockets are only switched into nonblocking mode * when we start the relay portion. This makes most of the original * tinyproxy code, which was confusing, redundant. Hail progress. * - rjkaes * this function is called directly from child_thread() with the newly * received fd from accept(). */ void handle_connection (struct conn_s *connptr, union sockaddr_union* addr) { #define HC_FAIL() \ do {handle_connection_failure(connptr, got_headers); goto done;} \ while(0) int got_headers = 0, fd = connptr->client_fd; size_t i; struct request_s *request = NULL; orderedmap hashofheaders = NULL; char sock_ipaddr[IP_LENGTH]; char peer_ipaddr[IP_LENGTH]; getpeer_information (addr, peer_ipaddr, sizeof(peer_ipaddr)); if (config->bindsame) getsock_ip (fd, sock_ipaddr); log_message (LOG_CONN, config->bindsame ? "Connect (file descriptor %d): %s at [%s]" : "Connect (file descriptor %d): %s", fd, peer_ipaddr, sock_ipaddr); if(!conn_init_contents (connptr, peer_ipaddr, config->bindsame ? sock_ipaddr : NULL)) { close (fd); return; } set_socket_timeout(fd); if (connection_loops (addr)) { log_message (LOG_CONN, "Prevented endless loop (file descriptor %d): %s", fd, peer_ipaddr); indicate_http_error(connptr, 400, "Bad Request", "detail", "You tried to connect to the " "machine the proxy is running on", NULL); HC_FAIL(); } if (check_acl (peer_ipaddr, addr, config->access_list) <= 0) { update_stats (STAT_DENIED); indicate_http_error (connptr, 403, "Access denied", "detail", "The administrator of this proxy has not configured " "it to service requests from your host.", NULL); HC_FAIL(); } if (read_request_line (connptr) < 0) { update_stats (STAT_BADCONN); goto done; } /* * The "hashofheaders" store the client's headers. */ hashofheaders = orderedmap_create (HEADER_BUCKETS); if (hashofheaders == NULL) { update_stats (STAT_BADCONN); indicate_http_error (connptr, 503, "Internal error", "detail", "An internal server error occurred while processing " "your request. Please contact the administrator.", NULL); HC_FAIL(); } /* * Get all the headers from the client in a big hash. */ if (get_all_headers (connptr->client_fd, hashofheaders) < 0) { log_message (LOG_WARNING, "Could not retrieve all the headers from the client"); indicate_http_error (connptr, 400, "Bad Request", "detail", "Could not retrieve all the headers from " "the client.", NULL); update_stats (STAT_BADCONN); HC_FAIL(); } got_headers = 1; if (config->basicauth_list != NULL) { char *authstring; int failure = 1, stathost_connect = 0; authstring = orderedmap_find (hashofheaders, "proxy-authorization"); if (!authstring && config->stathost) { authstring = orderedmap_find (hashofheaders, "host"); if (authstring && !strncmp(authstring, config->stathost, strlen(config->stathost))) { authstring = orderedmap_find (hashofheaders, "authorization"); stathost_connect = 1; } else authstring = 0; } if (!authstring) { if (stathost_connect) goto e401; update_stats (STAT_DENIED); indicate_http_error (connptr, 407, "Proxy Authentication Required", "detail", "This proxy requires authentication.", NULL); HC_FAIL(); } if ( /* currently only "basic" auth supported */ (strncmp(authstring, "Basic ", 6) == 0 || strncmp(authstring, "basic ", 6) == 0) && basicauth_check (config->basicauth_list, authstring + 6) == 1) failure = 0; if(failure) { e401: update_stats (STAT_DENIED); log_message (LOG_INFO, "Failed auth attempt (file descriptor: %d), ip %s", connptr->client_fd, connptr->client_ip_addr); indicate_http_error (connptr, 401, "Unauthorized", "detail", "The administrator of this proxy has not configured " "it to service requests from you.", NULL); HC_FAIL(); } orderedmap_remove (hashofheaders, "proxy-authorization"); } /* * Add any user-specified headers (AddHeader directive) to the * outgoing HTTP request. */ if (config->add_headers) for (i = 0; i < sblist_getsize (config->add_headers); i++) { http_header_t *header = sblist_get (config->add_headers, i); orderedmap_append (hashofheaders, header->name, header->value); } request = process_request (connptr, hashofheaders); if (!request) { if (!connptr->show_stats) { update_stats (STAT_BADCONN); } HC_FAIL(); } connptr->upstream_proxy = UPSTREAM_HOST (request->host); if (connptr->upstream_proxy != NULL) { if (connect_to_upstream (connptr, request) < 0) { HC_FAIL(); } } else { connptr->server_fd = opensock (request->host, request->port, connptr->server_ip_addr); if (connptr->server_fd < 0) { indicate_http_error (connptr, 500, "Unable to connect", "detail", PACKAGE_NAME " " "was unable to connect to the remote web server.", "error", strerror (errno), NULL); HC_FAIL(); } log_message (LOG_CONN, "Established connection to host \"%s\" using " "file descriptor %d.", request->host, connptr->server_fd); if (!connptr->connect_method) establish_http_connection (connptr, request); } if (process_client_headers (connptr, hashofheaders) < 0) { update_stats (STAT_BADCONN); log_message (LOG_INFO, "process_client_headers failed: %s. host \"%s\" using " "file descriptor %d.", strerror(errno), request->host, connptr->server_fd); HC_FAIL(); } if (!connptr->connect_method || UPSTREAM_IS_HTTP(connptr)) { if (process_server_headers (connptr) < 0) { update_stats (STAT_BADCONN); log_message (LOG_INFO, "process_server_headers failed: %s. host \"%s\" using " "file descriptor %d.", strerror(errno), request->host, connptr->server_fd); HC_FAIL(); } } else { if (send_connect_method_response (connptr) < 0) { log_message (LOG_ERR, "handle_connection: Could not send CONNECT" " method greeting to client."); update_stats (STAT_BADCONN); HC_FAIL(); } } relay_connection (connptr); log_message (LOG_INFO, "Closed connection between local client (fd:%d) " "and remote client (fd:%d)", connptr->client_fd, connptr->server_fd); done: free_request_struct (request); orderedmap_destroy (hashofheaders); conn_destroy_contents (connptr); return; #undef HC_FAIL } tinyproxy-1.11.2/src/reqs.h000066400000000000000000000026541461674137700156220ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 1998 Steven Young * Copyright (C) 1999 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* See 'reqs.c' for detailed information. */ #ifndef _TINYPROXY_REQS_H_ #define _TINYPROXY_REQS_H_ #include "common.h" #include "sock.h" #include "conns.h" /* * Port constants for HTTP (80) and SSL (443) */ #define HTTP_PORT 80 #define HTTP_PORT_SSL 443 /* * This structure holds the information pulled from a URL request. */ struct request_s { char *method; char *protocol; char *host; uint16_t port; char *path; }; extern void handle_connection (struct conn_s *, union sockaddr_union* addr); #endif tinyproxy-1.11.2/src/reverse-proxy.c000066400000000000000000000150031461674137700174650ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 1999-2005 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* Allow tinyproxy to be used as a reverse proxy. */ #include "main.h" #include "reverse-proxy.h" #include "conns.h" #include "heap.h" #include "html-error.h" #include "log.h" #include "conf.h" /* * Add entry to the reversepath list */ void reversepath_add (const char *path, const char *url, struct reversepath **reversepath_list) { struct reversepath *reverse; size_t l; if (url == NULL) { log_message (LOG_WARNING, "Illegal reverse proxy rule: missing url"); return; } if (!strstr (url, "://")) { log_message (LOG_WARNING, "Skipping reverse proxy rule: '%s' is not a valid url", url); return; } if (path && *path != '/') { log_message (LOG_WARNING, "Skipping reverse proxy rule: path '%s' " "doesn't start with a /", path); return; } reverse = (struct reversepath *) safemalloc (sizeof (struct reversepath)); if (!reverse) { log_message (LOG_ERR, "Unable to allocate memory in reversepath_add()"); return; } if (!path) reverse->path = safestrdup ("/"); else { l = strlen (path); if (l && path[l-1] == '/') reverse->path = safestrdup (path); else { reverse->path = safemalloc (l + 2); memcpy (reverse->path, path, l); reverse->path[l] = '/'; reverse->path[l+1] = 0; } } reverse->url = safestrdup (url); reverse->next = *reversepath_list; *reversepath_list = reverse; log_message (LOG_INFO, "Added reverse proxy rule: %s -> %s", reverse->path, reverse->url); } /* * Check if a request url is in the reversepath list */ struct reversepath *reversepath_get (char *url, struct reversepath *reverse) { size_t l, lu, lp; while (reverse) { lu = strlen (url); lp = strlen (reverse->path); if (( (l = lu) == lp-1 || (l = lp) <= lu ) && !memcmp(url, reverse->path, l)) return reverse; reverse = reverse->next; } return NULL; } /** * Free a reversepath list */ void free_reversepath_list (struct reversepath *reverse) { while (reverse) { struct reversepath *tmp = reverse; reverse = reverse->next; safefree (tmp->url); safefree (tmp->path); safefree (tmp); } } /* * Rewrite the URL for reverse proxying. */ char *reverse_rewrite_url (struct conn_s *connptr, orderedmap hashofheaders, char *url, int *status) { char *rewrite_url = NULL; char *cookie = NULL; char *cookieval; struct reversepath *reverse = NULL; *status = 0; /* Reverse requests always start with a slash */ if (*url == '/') { /* First try locating the reverse mapping by request url */ reverse = reversepath_get (url, config->reversepath_list); if (reverse) { size_t lu = strlen (url); size_t lrp = strlen (reverse->path); if (lrp > lu) { rewrite_url = safestrdup (reverse->path); *status = 301; } else { rewrite_url = safemalloc ( strlen (reverse->url) + lu + 1); sprintf (rewrite_url, "%s%s", reverse->url, url + lrp); } } else if (config->reversemagic && (cookie = orderedmap_find (hashofheaders, "cookie"))) { /* No match - try the magical tracking cookie next */ if ((cookieval = strstr (cookie, REVERSE_COOKIE "=")) && (reverse = reversepath_get (cookieval + strlen (REVERSE_COOKIE) + 1, config->reversepath_list))) { rewrite_url = (char *) safemalloc (strlen (url) + strlen (reverse->url) + 1); strcpy (rewrite_url, reverse->url); strcat (rewrite_url, url + 1); log_message (LOG_INFO, "Magical tracking cookie says: %s", reverse->path); } } } if (rewrite_url == NULL) { return NULL; } log_message (LOG_CONN, "Rewriting URL: %s -> %s", url, rewrite_url); /* Store reverse path so that the magical tracking cookie can be set */ if (config->reversemagic && reverse) connptr->reversepath = safestrdup (reverse->path); return rewrite_url; } tinyproxy-1.11.2/src/reverse-proxy.h000066400000000000000000000031741461674137700175000ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 2005 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* See 'reverse-proxy.c' for detailed information. */ #ifndef TINYPROXY_REVERSE_PROXY_H #define TINYPROXY_REVERSE_PROXY_H #include "conns.h" #include "orderedmap.h" struct reversepath { struct reversepath *next; char *path; char *url; }; #define REVERSE_COOKIE "yummy_magical_cookie" extern void reversepath_add (const char *path, const char *url, struct reversepath **reversepath_list); extern struct reversepath *reversepath_get (char *url, struct reversepath *reverse); void free_reversepath_list (struct reversepath *reverse); extern char *reverse_rewrite_url (struct conn_s *connptr, orderedmap hashofheaders, char *url, int *status); #endif tinyproxy-1.11.2/src/sblist.c000066400000000000000000000033571461674137700161440ustar00rootroot00000000000000#undef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 200809L #include "sblist.h" #include #include #include #define MY_PAGE_SIZE 4096 sblist* sblist_new(size_t itemsize, size_t blockitems) { sblist* ret = (sblist*) malloc(sizeof(sblist)); sblist_init(ret, itemsize, blockitems); return ret; } static void sblist_clear(sblist* l) { l->items = NULL; l->capa = 0; l->count = 0; } void sblist_init(sblist* l, size_t itemsize, size_t blockitems) { if(l) { l->blockitems = blockitems ? blockitems : MY_PAGE_SIZE / itemsize; l->itemsize = itemsize; sblist_clear(l); } } void sblist_free_items(sblist* l) { if(l) { if(l->items) free(l->items); sblist_clear(l); } } void sblist_free(sblist* l) { if(l) { sblist_free_items(l); free(l); } } char* sblist_item_from_index(sblist* l, size_t idx) { return l->items + (idx * l->itemsize); } void* sblist_get(sblist* l, size_t item) { if(item < l->count) return (void*) sblist_item_from_index(l, item); return NULL; } int sblist_set(sblist* l, void* item, size_t pos) { if(pos >= l->count) return 0; memcpy(sblist_item_from_index(l, pos), item, l->itemsize); return 1; } int sblist_grow_if_needed(sblist* l) { char* temp; if(l->count == l->capa) { temp = realloc(l->items, (l->capa + l->blockitems) * l->itemsize); if(!temp) return 0; l->capa += l->blockitems; l->items = temp; } return 1; } int sblist_add(sblist* l, void* item) { if(!sblist_grow_if_needed(l)) return 0; l->count++; return sblist_set(l, item, l->count - 1); } void sblist_delete(sblist* l, size_t item) { if (l->count && item < l->count) { memmove(sblist_item_from_index(l, item), sblist_item_from_index(l, item + 1), (sblist_getsize(l) - (item + 1)) * l->itemsize); l->count--; } } tinyproxy-1.11.2/src/sblist.h000066400000000000000000000056641461674137700161540ustar00rootroot00000000000000#ifndef SBLIST_H #define SBLIST_H /* this file is part of libulz, as of commit 8ab361a27743aaf025323ee43b8b8876dc054fdd modified for direct inclusion in tinyproxy, and for this purpose released under the license of tinyproxy. */ #ifdef __cplusplus extern "C" { #endif #include /* * simple buffer list. * * this thing here is basically a generic dynamic array * will realloc after every blockitems inserts * can store items of any size. * * so think of it as a by-value list, as opposed to a typical by-ref list. * you typically use it by having some struct on the stack, and pass a pointer * to sblist_add, which will copy the contents into its internal memory. * */ typedef struct { size_t itemsize; size_t blockitems; size_t count; size_t capa; char* items; } sblist; #define sblist_getsize(X) ((X)->count) #define sblist_get_count(X) ((X)->count) #define sblist_empty(X) ((X)->count == 0) /* for dynamic style */ sblist* sblist_new(size_t itemsize, size_t blockitems); void sblist_free(sblist* l); /*for static style*/ void sblist_init(sblist* l, size_t itemsize, size_t blockitems); void sblist_free_items(sblist* l); /* accessors */ void* sblist_get(sblist* l, size_t item); /* returns 1 on success, 0 on OOM */ int sblist_add(sblist* l, void* item); int sblist_set(sblist* l, void* item, size_t pos); void sblist_delete(sblist* l, size_t item); char* sblist_item_from_index(sblist* l, size_t idx); int sblist_grow_if_needed(sblist* l); int sblist_insert(sblist* l, void* item, size_t pos); /* same as sblist_add, but returns list index of new item, or -1 */ size_t sblist_addi(sblist* l, void* item); void sblist_sort(sblist *l, int (*compar)(const void *, const void *)); /* insert element into presorted list, returns listindex of new entry or -1*/ size_t sblist_insert_sorted(sblist* l, void* o, int (*compar)(const void *, const void *)); #ifndef __COUNTER__ #define __COUNTER__ __LINE__ #endif #define __sblist_concat_impl( x, y ) x##y #define __sblist_macro_concat( x, y ) __sblist_concat_impl( x, y ) #define __sblist_iterator_name __sblist_macro_concat(sblist_iterator, __COUNTER__) /* use with custom iterator variable */ #define sblist_iter_counter(LIST, ITER, PTR) \ for(size_t ITER = 0; (PTR = sblist_get(LIST, ITER)), ITER < sblist_getsize(LIST); ITER++) /* use with custom iterator variable, which is predeclared */ #define sblist_iter_counter2(LIST, ITER, PTR) \ for(ITER = 0; (PTR = sblist_get(LIST, ITER)), ITER < sblist_getsize(LIST); ITER++) /* use with custom iterator variable, which is predeclared and signed */ /* useful for a loop which can delete items from the list, and then decrease the iterator var. */ #define sblist_iter_counter2s(LIST, ITER, PTR) \ for(ITER = 0; (PTR = sblist_get(LIST, ITER)), ITER < (ssize_t) sblist_getsize(LIST); ITER++) /* uses "magic" iterator variable */ #define sblist_iter(LIST, PTR) sblist_iter_counter(LIST, __sblist_iterator_name, PTR) #ifdef __cplusplus } #endif #endif tinyproxy-1.11.2/src/sock.c000066400000000000000000000316241461674137700156010ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 1998 Steven Young * Copyright (C) 1999, 2004 Robert James Kaes * Copyright (C) 2000 Chris Lightfoot * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* Sockets are created and destroyed here. When a new connection comes in from * a client, we need to copy the socket and the create a second socket to the * remote server the client is trying to connect to. Also, the listening * socket is created and destroyed here. Sounds more impressive than it * actually is. */ #include "main.h" #include "log.h" #include "heap.h" #include "network.h" #include "sock.h" #include "text.h" #include "conf.h" #include "loop.h" #include "sblist.h" /* * Return a human readable error for getaddrinfo() and getnameinfo(). */ static const char * get_gai_error (int n) { if (n == EAI_SYSTEM) return strerror (errno); else return gai_strerror (n); } static const char * family_string (int af) { switch(af) { case AF_UNSPEC: return "AF_UNSPEC"; case AF_INET: return "AF_INET"; case AF_INET6: return "AF_INET6"; } return "unknown"; } /* * Bind the given socket to the supplied address. The socket is * returned if the bind succeeded. Otherwise, -1 is returned * to indicate an error. */ static int bind_socket (int sockfd, const char *addr, int family) { struct addrinfo hints, *res, *ressave; int n; assert (sockfd >= 0); assert (addr != NULL && strlen (addr) != 0); memset (&hints, 0, sizeof (struct addrinfo)); hints.ai_family = family; hints.ai_socktype = SOCK_STREAM; /* The local port is not important */ n = getaddrinfo (addr, NULL, &hints, &res); if (n != 0) { log_message (LOG_INFO, "bind_socket: getaddrinfo failed for %s: %s (af: %s)", addr, get_gai_error (n), family_string(family)); return -1; } ressave = res; /* Loop through the addresses and try to bind to each */ do { if (bind (sockfd, res->ai_addr, res->ai_addrlen) == 0) break; /* success */ } while ((res = res->ai_next) != NULL); freeaddrinfo (ressave); if (res == NULL) /* was not able to bind to any address */ return -1; return sockfd; } /** * Try binding the given socket to supplied addresses, stopping when one succeeds. */ static int bind_socket_list (int sockfd, sblist *addresses, int family) { size_t nb_addresses = sblist_getsize(addresses); size_t i; for (i = 0; i < nb_addresses; i++) { const char *address = *(const char **)sblist_get(addresses, i); if (bind_socket(sockfd, address, family) >= 0) { log_message(LOG_INFO, "Bound to %s", address); return 0; } } return -1; } void set_socket_timeout(int fd) { struct timeval tv; tv.tv_usec = 0; tv.tv_sec = config->idletimeout; setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (void*) &tv, sizeof(tv)); tv.tv_usec = 0; tv.tv_sec = config->idletimeout; setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (void*) &tv, sizeof(tv)); } /* * Open a connection to a remote host. It's been re-written to use * the getaddrinfo() library function, which allows for a protocol * independent implementation (mostly for IPv4 and IPv6 addresses.) */ int opensock (const char *host, int port, const char *bind_to) { int sockfd, n; struct addrinfo hints, *res, *ressave; char portstr[6]; assert (host != NULL); assert (port > 0); log_message(LOG_INFO, "opensock: opening connection to %s:%d", host, port); memset (&hints, 0, sizeof (struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; snprintf (portstr, sizeof (portstr), "%d", port); n = getaddrinfo (host, portstr, &hints, &res); if (n != 0) { log_message (LOG_ERR, "opensock: Could not retrieve address info for %s:%d: %s", host, port, get_gai_error (n)); return -1; } log_message(LOG_INFO, "opensock: getaddrinfo returned for %s:%d", host, port); ressave = res; do { sockfd = socket (res->ai_family, res->ai_socktype, res->ai_protocol); if (sockfd < 0) continue; /* ignore this one */ /* Bind to the specified address */ if (bind_to) { if (bind_socket (sockfd, bind_to, res->ai_family) < 0) { close (sockfd); continue; /* can't bind, so try again */ } } else if (config->bind_addrs) { if (bind_socket_list (sockfd, config->bind_addrs, res->ai_family) < 0) { close (sockfd); continue; /* can't bind, so try again */ } } set_socket_timeout(sockfd); if (connect (sockfd, res->ai_addr, res->ai_addrlen) == 0) { union sockaddr_union *p = (void*) res->ai_addr, u; int af = res->ai_addr->sa_family; unsigned dport = ntohs(af == AF_INET ? p->v4.sin_port : p->v6.sin6_port); socklen_t slen = sizeof u; if (dport == config->port) { getsockname(sockfd, (void*)&u, &slen); loop_records_add(&u); } break; /* success */ } close (sockfd); } while ((res = res->ai_next) != NULL); freeaddrinfo (ressave); if (res == NULL) { log_message (LOG_ERR, "opensock: Could not establish a connection to %s:%d", host, port); return -1; } return sockfd; } /* * Set the socket to non blocking -rjkaes */ int socket_nonblocking (int sock) { int flags; assert (sock >= 0); flags = fcntl (sock, F_GETFL, 0); return fcntl (sock, F_SETFL, flags | O_NONBLOCK); } /* * Set the socket to blocking -rjkaes */ int socket_blocking (int sock) { int flags; assert (sock >= 0); flags = fcntl (sock, F_GETFL, 0); return fcntl (sock, F_SETFL, flags & ~O_NONBLOCK); } /** * Try to listen on one socket based on the addrinfo * as returned from getaddrinfo. * * Return the file descriptor upon success, -1 upon error. */ static int listen_on_one_socket(struct addrinfo *ad) { int listenfd; int ret; const int on = 1; char numerichost[NI_MAXHOST]; int flags = NI_NUMERICHOST; ret = getnameinfo(ad->ai_addr, ad->ai_addrlen, numerichost, NI_MAXHOST, NULL, 0, flags); if (ret != 0) { log_message(LOG_ERR, "getnameinfo failed: %s", get_gai_error (ret)); return -1; } log_message(LOG_INFO, "trying to listen on host[%s], family[%d], " "socktype[%d], proto[%d]", numerichost, ad->ai_family, ad->ai_socktype, ad->ai_protocol); listenfd = socket(ad->ai_family, ad->ai_socktype, ad->ai_protocol); if (listenfd == -1) { log_message(LOG_ERR, "socket() failed: %s", strerror(errno)); return -1; } ret = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); if (ret != 0) { log_message(LOG_ERR, "setsockopt failed to set SO_REUSEADDR: %s", strerror(errno)); close(listenfd); return -1; } if (ad->ai_family == AF_INET6) { ret = setsockopt(listenfd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)); if (ret != 0) { log_message(LOG_ERR, "setsockopt failed to set IPV6_V6ONLY: %s", strerror(errno)); close(listenfd); return -1; } } ret = bind(listenfd, ad->ai_addr, ad->ai_addrlen); if (ret != 0) { log_message(LOG_ERR, "bind failed: %s", strerror (errno)); close(listenfd); return -1; } ret = listen(listenfd, MAXLISTEN); if (ret != 0) { log_message(LOG_ERR, "listen failed: %s", strerror(errno)); close(listenfd); return -1; } log_message(LOG_INFO, "listening on fd [%d]", listenfd); return listenfd; } /* * Start listening on a socket. Create a socket with the selected port. * If the provided address is NULL, we may listen on multiple sockets, * e.g. the wildcard addresse for IPv4 and IPv6, depending on what is * supported. If the address is not NULL, we only listen on the first * address reported by getaddrinfo that works. * * Upon success, the listen-fds are added to the listen_fds list * and 0 is returned. Upon error, -1 is returned. */ int listen_sock (const char *addr, uint16_t port, sblist* listen_fds) { struct addrinfo hints, *result, *rp; char portstr[6]; int ret = -1; int n; assert (port > 0); assert (listen_fds != NULL); log_message(LOG_INFO, "listen_sock called with addr = '%s'", addr == NULL ? "(NULL)" : addr); memset (&hints, 0, sizeof (struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; snprintf (portstr, sizeof (portstr), "%d", port); n = getaddrinfo (addr, portstr, &hints, &result); if (n != 0) { log_message (LOG_ERR, "Unable to getaddrinfo() for %s:%d because of %s", addr, port, get_gai_error (n)); return -1; } for (rp = result; rp != NULL; rp = rp->ai_next) { int listenfd; listenfd = listen_on_one_socket(rp); if (listenfd == -1) { continue; } sblist_add (listen_fds, &listenfd); /* success */ ret = 0; if (addr != NULL) { /* * Unless wildcard is requested, only listen * on the first result that works. */ break; } } if (ret != 0) { log_message (LOG_ERR, "Unable to listen on any address."); } freeaddrinfo (result); return ret; } /* * Takes a socket descriptor and returns the socket's IP address. */ int getsock_ip (int fd, char *ipaddr) { struct sockaddr_storage name; socklen_t namelen = sizeof (name); assert (fd >= 0); if (getsockname (fd, (struct sockaddr *) &name, &namelen) != 0) { log_message (LOG_ERR, "getsock_ip: getsockname() error: %s", strerror (errno)); return -1; } if (get_ip_string ((struct sockaddr *) &name, ipaddr, IP_LENGTH) == NULL) return -1; return 0; } /* * Return the peer's socket information. */ void getpeer_information (union sockaddr_union* addr, char *ipaddr, size_t ipaddr_len) { int af = addr->v4.sin_family; void *ipdata = af == AF_INET ? (void*)&addr->v4.sin_addr : (void*)&addr->v6.sin6_addr; inet_ntop(af, ipdata, ipaddr, ipaddr_len); } tinyproxy-1.11.2/src/sock.h000066400000000000000000000044031461674137700156010ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 1998 Steven Young * Copyright (C) 1999, 2004 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* See 'sock.c' for detailed information. */ #ifndef TINYPROXY_SOCK_H #define TINYPROXY_SOCK_H /* The IP length is set to 48, since IPv6 can be that long */ #define IP_LENGTH 48 #define HOSTNAME_LENGTH 1024 #define MAXLINE (1024 * 4) #include "common.h" #include "sblist.h" #define SOCKADDR_UNION_AF(PTR) (PTR)->v4.sin_family #define SOCKADDR_UNION_LENGTH(PTR) ( \ ( SOCKADDR_UNION_AF(PTR) == AF_INET ) ? sizeof((PTR)->v4) : ( \ ( SOCKADDR_UNION_AF(PTR) == AF_INET6 ) ? sizeof((PTR)->v6) : 0 ) ) #define SOCKADDR_UNION_ADDRESS(PTR) ( \ ( SOCKADDR_UNION_AF(PTR) == AF_INET ) ? (void*) &(PTR)->v4.sin_addr : ( \ ( SOCKADDR_UNION_AF(PTR) == AF_INET6 ) ? (void*) &(PTR)->v6.sin6_addr : (void*) 0 ) ) #define SOCKADDR_UNION_PORT(PTR) ( \ ( SOCKADDR_UNION_AF(PTR) == AF_INET ) ? (PTR)->v4.sin_port : ( \ ( SOCKADDR_UNION_AF(PTR) == AF_INET6 ) ? (PTR)->v6.sin6_port : 0 ) ) union sockaddr_union { struct sockaddr_in v4; struct sockaddr_in6 v6; }; extern int opensock (const char *host, int port, const char *bind_to); extern int listen_sock (const char *addr, uint16_t port, sblist* listen_fds); extern int socket_nonblocking (int sock); extern int socket_blocking (int sock); extern void set_socket_timeout(int fd); extern int getsock_ip (int fd, char *ipaddr); extern void getpeer_information (union sockaddr_union *addr, char *ipaddr, size_t ipaddr_len); #endif tinyproxy-1.11.2/src/stats.c000066400000000000000000000134171461674137700160000ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 2000 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* This module handles the statistics for tinyproxy. There are only two * public API functions. The reason for the functions, rather than just a * external structure is that tinyproxy is now multi-threaded and we can * not allow more than one child to access the statistics at the same * time. This is prevented by a mutex. If there is a need for more * statistics in the future, just add to the structure, enum (in the header), * and the switch statement in update_stats(). */ #include "main.h" #include "log.h" #include "heap.h" #include "html-error.h" #include "stats.h" #include "utils.h" #include "conf.h" #include struct stat_s { unsigned long int num_reqs; unsigned long int num_badcons; unsigned long int num_open; unsigned long int num_refused; unsigned long int num_denied; }; static struct stat_s stats_buf, *stats; static pthread_mutex_t stats_update_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t stats_file_lock = PTHREAD_MUTEX_INITIALIZER; /* * Initialize the statistics information to zero. */ void init_stats (void) { stats = &stats_buf; } /* * Display the statics of the tinyproxy server. */ int showstats (struct conn_s *connptr) { char *message_buffer; char opens[16], reqs[16], badconns[16], denied[16], refused[16]; FILE *statfile; snprintf (opens, sizeof (opens), "%lu", stats->num_open); snprintf (reqs, sizeof (reqs), "%lu", stats->num_reqs); snprintf (badconns, sizeof (badconns), "%lu", stats->num_badcons); snprintf (denied, sizeof (denied), "%lu", stats->num_denied); snprintf (refused, sizeof (refused), "%lu", stats->num_refused); pthread_mutex_lock(&stats_file_lock); if (!config->statpage || (!(statfile = fopen (config->statpage, "r")))) { message_buffer = (char *) safemalloc (MAXBUFFSIZE); if (!message_buffer) { err_minus_one: pthread_mutex_unlock(&stats_file_lock); return -1; } snprintf (message_buffer, MAXBUFFSIZE, "\n" "\n" "\n" "%s version %s run-time statistics\n" "\n" "

%s version %s run-time statistics

\n" "

\n" "Number of open connections: %lu
\n" "Number of requests: %lu
\n" "Number of bad connections: %lu
\n" "Number of denied connections: %lu
\n" "Number of refused connections due to high load: %lu\n" "

\n" "
\n" "

Generated by %s version %s.

\n" "\n" "\n", PACKAGE, VERSION, PACKAGE, VERSION, stats->num_open, stats->num_reqs, stats->num_badcons, stats->num_denied, stats->num_refused, PACKAGE, VERSION); if (send_http_message (connptr, 200, "OK", message_buffer) < 0) { safefree (message_buffer); goto err_minus_one; } safefree (message_buffer); pthread_mutex_unlock(&stats_file_lock); return 0; } add_error_variable (connptr, "opens", opens); add_error_variable (connptr, "reqs", reqs); add_error_variable (connptr, "badconns", badconns); add_error_variable (connptr, "deniedconns", denied); add_error_variable (connptr, "refusedconns", refused); add_standard_vars (connptr); send_http_headers (connptr, 200, "Statistic requested", ""); send_html_file (statfile, connptr); fclose (statfile); pthread_mutex_unlock(&stats_file_lock); return 0; } /* * Update the value of the statistics. The update_level is defined in * stats.h */ int update_stats (status_t update_level) { int ret = 0; pthread_mutex_lock(&stats_update_lock); switch (update_level) { case STAT_BADCONN: ++stats->num_badcons; break; case STAT_OPEN: ++stats->num_open; ++stats->num_reqs; break; case STAT_CLOSE: --stats->num_open; break; case STAT_REFUSE: ++stats->num_refused; break; case STAT_DENIED: ++stats->num_denied; break; default: ret = -1; } pthread_mutex_unlock(&stats_update_lock); return ret; } tinyproxy-1.11.2/src/stats.h000066400000000000000000000030241461674137700157760ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 2000 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* See 'stats.c' for detailed information. */ #ifndef _TINYPROXY_STATS_H_ #define _TINYPROXY_STATS_H_ #include "conns.h" /* * Various logable statistics */ typedef enum { STAT_BADCONN, /* bad connection, for unknown reason */ STAT_OPEN, /* connection opened */ STAT_CLOSE, /* connection closed */ STAT_REFUSE, /* connection refused (to outside world) */ STAT_DENIED /* connection denied to tinyproxy itself */ } status_t; /* * Public API to the statistics for tinyproxy */ extern void init_stats (void); extern int showstats (struct conn_s *connptr); extern int update_stats (status_t update_level); #endif tinyproxy-1.11.2/src/text.c000066400000000000000000000063021461674137700156210ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 2002 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* The functions included here are useful for text manipulation. They * replace or augment the standard C string library. These functions * are either safer replacements, or they provide services not included * with the standard C string library. */ #include "main.h" #include "text.h" #ifndef HAVE_STRLCPY /* * Function API taken from OpenBSD. Like strncpy(), but does not 0 fill the * buffer, and always NULL terminates the buffer. size is the size of the * destination buffer. */ size_t strlcpy (char *dst, const char *src, size_t size) { size_t len = strlen (src); size_t ret = len; if (len >= size) len = size - 1; memcpy (dst, src, len); dst[len] = '\0'; return ret; } #endif #ifndef HAVE_STRLCAT /* * Function API taken from OpenBSD. Like strncat(), but does not 0 fill the * buffer, and always NULL terminates the buffer. size is the length of the * buffer, which should be one more than the maximum resulting string * length. */ size_t strlcat (char *dst, const char *src, size_t size) { size_t len1 = strlen (dst); size_t len2 = strlen (src); size_t ret = len1 + len2; if (len1 + len2 >= size) len2 = size - len1 - 1; if (len2 > 0) { memcpy (dst + len1, src, len2); dst[len1 + len2] = '\0'; } return ret; } #endif /* * Removes any new-line or carriage-return characters from the end of the * string. This function is named after the same function in Perl. * "length" should be the number of characters in the buffer, not including * the trailing NULL. * * Returns the number of characters removed from the end of the string. A * negative return value indicates an error. */ ssize_t chomp (char *buffer, size_t length) { size_t chars; assert (buffer != NULL); assert (length > 0); /* Make sure the arguments are valid */ if (buffer == NULL) return -EFAULT; if (length < 1) return -ERANGE; chars = 0; --length; while (buffer[length] == '\r' || buffer[length] == '\n') { buffer[length] = '\0'; chars++; /* Stop once we get to zero to prevent wrap-around */ if (length-- == 0) break; } return chars; } tinyproxy-1.11.2/src/text.h000066400000000000000000000023111461674137700156220ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 2002 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* See 'text.c' for detailed information. */ #ifndef TINYPROXY_TEXT_H #define TINYPROXY_TEXT_H #ifndef HAVE_STRLCAT extern size_t strlcat (char *dst, const char *src, size_t size); #endif /* HAVE_STRLCAT */ #ifndef HAVE_STRLCPY extern size_t strlcpy (char *dst, const char *src, size_t size); #endif /* HAVE_STRLCPY */ extern ssize_t chomp (char *buffer, size_t length); #endif tinyproxy-1.11.2/src/transparent-proxy.c000066400000000000000000000125531461674137700203620ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 2002 Petr Lampa * Copyright (C) 2008 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* * This section of code is used for the transparent proxy option. You will * need to configure your firewall to redirect all connections for HTTP * traffic to tinyproxy for this to work properly. */ #include "transparent-proxy.h" #include "conns.h" #include "heap.h" #include "html-error.h" #include "log.h" #include "reqs.h" #include "text.h" #include "conf.h" /* * Build a URL from parts. */ static int build_url (char **url, const char *host, int port, const char *path) { int len; assert (url != NULL); assert (host != NULL); assert (port > 0 && port < 32768); assert (path != NULL); len = strlen (host) + strlen (path) + 14; *url = (char *) saferealloc (*url, len); if (*url == NULL) return -1; return snprintf (*url, len, "http://%s:%d%s", host, port, path); } int do_transparent_proxy (struct conn_s *connptr, orderedmap hashofheaders, struct request_s *request, struct config_s *conf, char **url) { socklen_t length; char *data; size_t ulen = strlen (*url); size_t i; data = orderedmap_find (hashofheaders, "host"); if (!data) { union sockaddr_union dest_addr; const void *dest_inaddr; char namebuf[INET6_ADDRSTRLEN+1]; int af; length = sizeof(dest_addr); if (getsockname (connptr->client_fd, (void *) &dest_addr, &length) < 0 || length > sizeof(dest_addr)) { addr_err:; log_message (LOG_ERR, "process_request: cannot get destination IP for %d", connptr->client_fd); indicate_http_error (connptr, 400, "Bad Request", "detail", "Unknown destination", "url", *url, NULL); return 0; } af = SOCKADDR_UNION_AF(&dest_addr); dest_inaddr = SOCKADDR_UNION_ADDRESS(&dest_addr); if (!inet_ntop(af, dest_inaddr, namebuf, sizeof namebuf)) goto addr_err; request->host = safestrdup (namebuf); request->port = ntohs (SOCKADDR_UNION_PORT(&dest_addr)); request->path = (char *) safemalloc (ulen + 1); strlcpy (request->path, *url, ulen + 1); build_url (url, request->host, request->port, request->path); log_message (LOG_INFO, "process_request: trans IP %s %s for %d", request->method, *url, connptr->client_fd); } else { length = strlen (data); request->host = (char *) safemalloc (length + 1); if (sscanf (data, "%[^:]:%hu", request->host, &request->port) != 2) { strlcpy (request->host, data, length + 1); request->port = HTTP_PORT; } request->path = (char *) safemalloc (ulen + 1); strlcpy (request->path, *url, ulen + 1); build_url (url, request->host, request->port, request->path); log_message (LOG_INFO, "process_request: trans Host %s %s for %d", request->method, *url, connptr->client_fd); } if (conf->listen_addrs == NULL) { return 1; } for (i = 0; i < sblist_getsize(conf->listen_addrs); i++) { char **addr; addr = sblist_get(conf->listen_addrs, i); if (addr && *addr && strcmp(request->host, *addr) == 0) { log_message(LOG_ERR, "transparent: destination IP %s is local " "on socket fd %d", request->host, connptr->client_fd); indicate_http_error(connptr, 400, "Bad Request", "detail", "You tried to connect to the " "machine the proxy is running on", "url", *url, NULL); return 0; } } return 1; } tinyproxy-1.11.2/src/transparent-proxy.h000066400000000000000000000024721461674137700203660ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 2008 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* See 'transparent-proxy.c' for detailed information. */ #ifndef TINYPROXY_TRANSPARENT_PROXY_H #define TINYPROXY_TRANSPARENT_PROXY_H #include "common.h" #ifdef TRANSPARENT_PROXY #include "conns.h" #include "orderedmap.h" #include "reqs.h" extern int do_transparent_proxy (struct conn_s *connptr, orderedmap hashofheaders, struct request_s *request, struct config_s *config, char **url); #endif #endif tinyproxy-1.11.2/src/upstream.c000066400000000000000000000167361461674137700165110ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 1998 Steven Young * Copyright (C) 1999-2005 Robert James Kaes * Copyright (C) 2000 Chris Lightfoot * Copyright (C) 2002 Petr Lampa * Copyright (C) 2009 Michael Adam * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* * Routines for handling the list of upstream proxies. */ #include "upstream.h" #include "heap.h" #include "log.h" #include "base64.h" #include "basicauth.h" #ifdef UPSTREAM_SUPPORT const char * proxy_type_name(proxy_type type) { switch(type) { case PT_NONE: return "none"; case PT_HTTP: return "http"; case PT_SOCKS4: return "socks4"; case PT_SOCKS5: return "socks5"; default: return "unknown"; } } const char* upstream_build_error_string(enum upstream_build_error ube) { static const char *emap[] = { [UBE_SUCCESS] = "", [UBE_OOM] = "Unable to allocate memory in upstream_build()", [UBE_USERLEN] = "User / pass in upstream config too long", [UBE_EDOMAIN] = "Nonsense upstream none rule: empty domain", [UBE_INVHOST] = "Nonsense upstream rule: invalid host or port", [UBE_INVPARAMS] = "Nonsense upstream rule: invalid parameters", [UBE_NETMASK] = "Nonsense upstream rule: failed to parse netmask", }; return emap[ube]; } /** * Construct an upstream struct from input data. */ static struct upstream *upstream_build (const char *host, int port, char *domain, const char *user, const char *pass, proxy_type type, enum upstream_build_error *ube) { struct upstream *up; *ube = UBE_SUCCESS; up = (struct upstream *) safemalloc (sizeof (struct upstream)); if (!up) { *ube = UBE_OOM; return NULL; } up->type = type; up->target.type = HST_NONE; up->host = up->ua.user = up->pass = NULL; if (user) { if (type == PT_HTTP) { char b[BASE64ENC_BYTES((256+2)-1) + 1]; ssize_t ret; ret = basicauth_string(user, pass, b, sizeof b); if (ret == 0) { *ube = UBE_USERLEN; return NULL; } up->ua.authstr = safestrdup (b); } else { up->ua.user = safestrdup (user); up->pass = safestrdup (pass); } } if (domain == NULL) { if (type == PT_NONE) { e_nonedomain:; *ube = UBE_EDOMAIN; goto fail; } if (!host || !host[0] || port < 1) { *ube = UBE_INVHOST; goto fail; } up->host = safestrdup (host); up->port = port; log_message (LOG_INFO, "Added upstream %s %s:%d for [default]", proxy_type_name(type), host, port); } else { if (type == PT_NONE) { if (!domain[0]) goto e_nonedomain; } else { if (!host || !host[0] || !domain[0]) { *ube = UBE_INVPARAMS; goto fail; } up->host = safestrdup (host); up->port = port; } if (hostspec_parse(domain, &up->target) || up->target.type == HST_NONE) { *ube = UBE_NETMASK; goto fail; } if (type == PT_NONE) log_message (LOG_INFO, "Added upstream none for %s", domain); else log_message (LOG_INFO, "Added upstream %s %s:%d for %s", proxy_type_name(type), host, port, domain); } return up; fail: safefree (up->ua.user); safefree (up->pass); safefree (up->host); if(up->target.type == HST_STRING) safefree (up->target.address.string); safefree (up); return NULL; } /* * Add an entry to the upstream list */ enum upstream_build_error upstream_add ( const char *host, int port, char *domain, const char *user, const char *pass, proxy_type type, struct upstream **upstream_list) { struct upstream *up; enum upstream_build_error ube; up = upstream_build (host, port, domain, user, pass, type, &ube); if (up == NULL) { return ube; } if (up->target.type == HST_NONE) { /* always add default to end */ struct upstream *tmp = *upstream_list; while (tmp) { if (tmp->target.type == HST_NONE) { log_message (LOG_WARNING, "Duplicate default upstream"); goto upstream_cleanup; } if (!tmp->next) { up->next = NULL; tmp->next = up; return ube; } tmp = tmp->next; } } up->next = *upstream_list; *upstream_list = up; return ube; upstream_cleanup: safefree (up->host); if(up->target.type == HST_STRING) safefree (up->target.address.string); safefree (up); return ube; } /* * Check if a host is in the upstream list */ struct upstream *upstream_get (char *host, struct upstream *up) { while (up) { if (up->target.type == HST_NONE) break; if (hostspec_match(host, &up->target)) break; up = up->next; } if (up && (!up->host)) up = NULL; if (up) log_message (LOG_INFO, "Found upstream proxy %s %s:%d for %s", proxy_type_name(up->type), up->host, up->port, host); else log_message (LOG_INFO, "No upstream proxy for %s", host); return up; } void free_upstream_list (struct upstream *up) { while (up) { struct upstream *tmp = up; up = up->next; if(tmp->target.type == HST_STRING) safefree (tmp->target.address.string); safefree (tmp->host); safefree (tmp); } } #endif tinyproxy-1.11.2/src/upstream.h000066400000000000000000000043771461674137700165140ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 1998 Steven Young * Copyright (C) 1999 Robert James Kaes * Copyright (C) 2009 Michael Adam * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* * Routines for handling the list of upstream proxies. */ #ifndef _TINYPROXY_UPSTREAM_H_ #define _TINYPROXY_UPSTREAM_H_ #include "common.h" #include "hostspec.h" enum upstream_build_error { UBE_SUCCESS = 0, UBE_OOM, UBE_USERLEN, UBE_EDOMAIN, UBE_INVHOST, UBE_INVPARAMS, UBE_NETMASK, }; /* * Even if upstream support is not compiled into tinyproxy, this * structure still needs to be defined. */ typedef enum proxy_type { PT_NONE = 0, PT_HTTP, PT_SOCKS4, PT_SOCKS5 } proxy_type; struct upstream { struct upstream *next; char *host; union { char *user; char *authstr; } ua; char *pass; int port; struct hostspec target; proxy_type type; }; #ifdef UPSTREAM_SUPPORT const char *proxy_type_name(proxy_type type); extern enum upstream_build_error upstream_add ( const char *host, int port, char *domain, const char *user, const char *pass, proxy_type type, struct upstream **upstream_list); extern struct upstream *upstream_get (char *host, struct upstream *up); extern void free_upstream_list (struct upstream *up); extern const char* upstream_build_error_string(enum upstream_build_error); #endif /* UPSTREAM_SUPPORT */ #endif /* _TINYPROXY_UPSTREAM_H_ */ tinyproxy-1.11.2/src/utils.c000066400000000000000000000171411461674137700160000ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 1998 Steven Young * Copyright (C) 1999-2003 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* Misc. routines which are used by the various functions to handle strings * and memory allocation and pretty much anything else we can think of. Also, * the load cutoff routine is in here. Could not think of a better place for * it, so it's in here. */ #include "main.h" #include "conns.h" #include "heap.h" #include "http-message.h" #include "log.h" #include "utils.h" /* * Build the data for a complete HTTP & HTML message for the client. */ int send_http_message (struct conn_s *connptr, int http_code, const char *error_title, const char *message) { static const char *headers[] = { "Server: " PACKAGE "/" VERSION, "Content-type: text/html", "Connection: close" }; http_message_t msg; msg = http_message_create (http_code, error_title); if (msg == NULL) return -1; http_message_add_headers (msg, headers, 3); http_message_set_body (msg, message, strlen (message)); http_message_send (msg, connptr->client_fd); http_message_destroy (msg); return 0; } /* * Safely creates filename and returns the low-level file descriptor. */ int create_file_safely (const char *filename, unsigned int truncate_file) { struct stat lstatinfo; int fildes; /* * lstat() the file. If it doesn't exist, create it with O_EXCL. * If it does exist, open it for writing and perform the fstat() * check. */ if (lstat (filename, &lstatinfo) < 0) { /* * If lstat() failed for any reason other than "file not * existing", exit. */ if (errno != ENOENT) { fprintf (stderr, "%s: Error checking file %s: %s\n", PACKAGE, filename, strerror (errno)); return -EACCES; } /* * The file doesn't exist, so create it with O_EXCL to make * sure an attacker can't slip in a file between the lstat() * and open() */ if ((fildes = open (filename, O_RDWR | O_CREAT | O_EXCL, 0600)) < 0) { fprintf (stderr, "%s: Could not create file %s: %s\n", PACKAGE, filename, strerror (errno)); return fildes; } } else { struct stat fstatinfo; int flags; flags = O_RDWR; if (!truncate_file) flags |= O_APPEND; /* * Open an existing file. */ if ((fildes = open (filename, flags)) < 0) { fprintf (stderr, "%s: Could not open file %s: %s\n", PACKAGE, filename, strerror (errno)); return fildes; } /* * fstat() the opened file and check that the file mode bits, * inode, and device match. */ if (fstat (fildes, &fstatinfo) < 0 || lstatinfo.st_mode != fstatinfo.st_mode || lstatinfo.st_ino != fstatinfo.st_ino || lstatinfo.st_dev != fstatinfo.st_dev) { fprintf (stderr, "%s: The file %s has been changed before it could be opened\n", PACKAGE, filename); close (fildes); return -EIO; } /* * If the above check was passed, we know that the lstat() * and fstat() were done on the same file. Now we check that * there's only one link, and that it's a normal file (this * isn't strictly necessary because the fstat() vs lstat() * st_mode check would also find this) */ if (fstatinfo.st_nlink > 1 || !S_ISREG (lstatinfo.st_mode)) { fprintf (stderr, "%s: The file %s has too many links, " "or is not a regular file: %s\n", PACKAGE, filename, strerror (errno)); close (fildes); return -EMLINK; } /* * Just return the file descriptor if we _don't_ want the file * truncated. */ if (!truncate_file) return fildes; /* * On systems which don't support ftruncate() the best we can * do is to close the file and reopen it in create mode, which * unfortunately leads to a race condition, however "systems * which don't support ftruncate()" is pretty much SCO only, * and if you're using that you deserve what you get. * ("Little sympathy has been extended") */ #ifdef HAVE_FTRUNCATE if (ftruncate (fildes, 0) != 0) { log_message (LOG_WARNING, "Unable to truncate file '%s'", filename); } #else close (fildes); if ((fildes = open (filename, O_RDWR | O_CREAT | O_TRUNC, 0600)) < 0) { fprintf (stderr, "%s: Could not open file %s: %s.", PACKAGE, filename, strerror (errno)); return fildes; } #endif /* HAVE_FTRUNCATE */ } return fildes; } /** * pidfile_create: * @filename: The name of the file which should be created. * * Creates a file with the PID of the Tinyproxy process. * * Returns: %0 on success, non-zero values on errors. **/ int pidfile_create (const char *filename) { int fildes; FILE *fd; /* * Create a new file */ if ((fildes = create_file_safely (filename, TRUE)) < 0) return fildes; /* * Open a stdio file over the low-level one. */ if ((fd = fdopen (fildes, "w")) == NULL) { fprintf (stderr, "%s: Could not write PID file %s: %s.", PACKAGE, filename, strerror (errno)); close (fildes); unlink (filename); return -EIO; } fprintf (fd, "%d\n", getpid ()); fclose (fd); return 0; } tinyproxy-1.11.2/src/utils.h000066400000000000000000000025201461674137700160000ustar00rootroot00000000000000/* tinyproxy - A fast light-weight HTTP proxy * Copyright (C) 1998 Steven Young * Copyright (C) 1999 Robert James Kaes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* See 'utils.c' for detailed information. */ #ifndef TINYPROXY_UTILS_H #define TINYPROXY_UTILS_H /* * Forward declaration. */ struct conn_s; extern int send_http_message (struct conn_s *connptr, int http_code, const char *error_title, const char *message); extern int pidfile_create (const char *path); extern int create_file_safely (const char *filename, unsigned int truncate_file); #endif tinyproxy-1.11.2/tests/000077500000000000000000000000001461674137700150435ustar00rootroot00000000000000tinyproxy-1.11.2/tests/Makefile.am000066400000000000000000000000221461674137700170710ustar00rootroot00000000000000SUBDIRS = scripts tinyproxy-1.11.2/tests/scripts/000077500000000000000000000000001461674137700165325ustar00rootroot00000000000000tinyproxy-1.11.2/tests/scripts/Makefile.am000066400000000000000000000001261461674137700205650ustar00rootroot00000000000000EXTRA_DIST = \ run_tests.sh \ run_tests_valgrind.sh \ webclient.pl \ webserver.pl tinyproxy-1.11.2/tests/scripts/run_tests.sh000077500000000000000000000161451461674137700211260ustar00rootroot00000000000000#!/bin/sh # testsuite runner for tinyproxy # # Copyright (C) 2009 Michael Adam # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the Free # Software Foundation; either version 2 of the License, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # more details. # # You should have received a copy of the GNU General Public License along with # this program; if not, see . SCRIPTS_DIR=$(cd $(dirname $0) && pwd) BASEDIR=$SCRIPTS_DIR/../.. TESTS_DIR=$SCRIPTS_DIR/.. TESTENV_DIR=$TESTS_DIR/env LOG_DIR=$TESTENV_DIR/var/log TINYPROXY_IP=127.0.0.2 TINYPROXY_PORT=12321 TINYPROXY_USER=$(id -un) TINYPROXY_PID_DIR=$TESTENV_DIR/var/run/tinyproxy TINYPROXY_PID_FILE=$TINYPROXY_PID_DIR/tinyproxy.pid TINYPROXY_LOG_DIR=$LOG_DIR/tinyproxy TINYPROXY_LOG_FILE=$TINYPROXY_LOG_DIR/tinyproxy.log TINYPROXY_DATA_DIR=$TESTENV_DIR/usr/share/tinyproxy TINYPROXY_CONF_DIR=$TESTENV_DIR/etc/tinyproxy TINYPROXY_CONF_FILE=$TINYPROXY_CONF_DIR/tinyproxy.conf TINYPROXY_FILTER_FILE=$TINYPROXY_CONF_DIR/filter TINYPROXY_STDERR_LOG=$TINYPROXY_LOG_DIR/tinyproxy.stderr.log TINYPROXY_BIN=$BASEDIR/src/tinyproxy TINYPROXY_STATHOST_IP="127.0.0.127" WEBSERVER_IP=127.0.0.3 WEBSERVER_PORT=32123 WEBSERVER_PID_DIR=$TESTENV_DIR/var/run/webserver WEBSERVER_PID_FILE=$WEBSERVER_PID_DIR/webserver.pid WEBSERVER_LOG_DIR=$TESTENV_DIR/var/log/webserver WEBSERVER_BIN_FILE=webserver.pl WEBSERVER_BIN=$SCRIPTS_DIR/$WEBSERVER_BIN_FILE WEBCLIENT_LOG=$LOG_DIR/webclient.log WEBCLIENT_BIN=$SCRIPTS_DIR/webclient.pl provision_initial() { if test -e $TESTENV_DIR ; then TESTENV_DIR_OLD=$TESTENV_DIR.old if test -e $TESTENV_DIR_OLD ; then rm -rf $TESTENV_DIR_OLD fi mv $TESTENV_DIR $TESTENV_DIR.old fi mkdir -p $LOG_DIR } provision_tinyproxy() { mkdir -p $TINYPROXY_DATA_DIR cp $BASEDIR/data/templates/default.html $TINYPROXY_DATA_DIR cp $BASEDIR/data/templates/debug.html $TINYPROXY_DATA_DIR cp $BASEDIR/data/templates/stats.html $TINYPROXY_DATA_DIR mkdir -p $TINYPROXY_PID_DIR mkdir -p $TINYPROXY_LOG_DIR mkdir -p $TINYPROXY_CONF_DIR cat >>$TINYPROXY_CONF_FILE< $TINYPROXY_FILTER_FILE .*\.google-analytics\.com$ EOF } start_tinyproxy() { echo -n "starting tinyproxy..." $VALGRIND $TINYPROXY_BIN -c $TINYPROXY_CONF_FILE 2> $TINYPROXY_STDERR_LOG echo " done (listening on $TINYPROXY_IP:$TINYPROXY_PORT)" } reload_config() { echo -n "signaling tinyproxy to reload config..." pid=$(cat $TINYPROXY_PID_FILE) #1: SIGHUP kill -1 $pid && echo "ok" || echo "fail" } stop_tinyproxy() { echo -n "killing tinyproxy..." pid=$(cat $TINYPROXY_PID_FILE) kill $pid if test "x$?" = "x0" ; then echo " ok" else echo " error killing pid $pid" ps aux | grep tinyproxy echo "### printing logfile" cat $TINYPROXY_LOG_FILE echo "### printing stderr logfile" cat $TINYPROXY_STDERR_LOG fi } provision_webserver() { mkdir -p $WEBSERVER_PID_DIR mkdir -p $WEBSERVER_LOG_DIR } start_webserver() { echo -n "starting web server..." $WEBSERVER_BIN --port $WEBSERVER_PORT --log-dir $WEBSERVER_LOG_DIR --pid-file $WEBSERVER_PID_FILE echo " done (listening on $WEBSERVER_IP:$WEBSERVER_PORT)" } stop_webserver() { echo -n "killing webserver..." kill $(cat $WEBSERVER_PID_FILE) if test "x$?" = "x0" ; then echo " ok" else echo " error" fi } wait_for_some_seconds() { SECONDS=$1 if test "x$SECONDS" = "x" ; then SECONDS=1 fi echo -n "waiting for $SECONDS seconds." for COUNT in $(seq 1 $SECONDS) ; do sleep 1 echo -n "." done echo " done" } run_basic_webclient_request() { $WEBCLIENT_BIN $1 $2 > $WEBCLIENT_LOG 2>&1 WEBCLIENT_EXIT_CODE=$? if test "x$WEBCLIENT_EXIT_CODE" = "x0" ; then echo " ok" else echo "ERROR ($WEBCLIENT_EXIT_CODE)" echo "webclient output:" cat $WEBCLIENT_LOG echo "######################################" fi return $WEBCLIENT_EXIT_CODE } run_failure_webclient_request() { ec=$1 expected_error=$(($1 - 399)) shift $WEBCLIENT_BIN "$1" "$2" "$3" "$4" > $WEBCLIENT_LOG 2>&1 WEBCLIENT_EXIT_CODE=$? if test "x$WEBCLIENT_EXIT_CODE" = "x$expected_error" ; then echo " ok, got expected error code $ec" return 0 else echo "ERROR ($WEBCLIENT_EXIT_CODE)" echo "webclient output:" cat $WEBCLIENT_LOG echo "######################################" fi return 1 } # "main" provision_initial provision_tinyproxy provision_webserver start_webserver start_tinyproxy wait_for_some_seconds 1 FAILED=0 basic_test() { echo -n "checking direct connection to web server..." run_basic_webclient_request "$WEBSERVER_IP:$WEBSERVER_PORT" / test "x$?" = "x0" || FAILED=$((FAILED + 1)) echo -n "testing connection through tinyproxy..." run_basic_webclient_request "$TINYPROXY_IP:$TINYPROXY_PORT" "http://$WEBSERVER_IP:$WEBSERVER_PORT/" test "x$?" = "x0" || FAILED=$((FAILED + 1)) echo -n "requesting statspage via stathost url..." run_basic_webclient_request "$TINYPROXY_IP:$TINYPROXY_PORT" "http://$TINYPROXY_STATHOST_IP" test "x$?" = "x0" || FAILED=$((FAILED + 1)) } ext_test() { echo -n "checking bogus request..." run_failure_webclient_request 400 --method="BIG FART" "$TINYPROXY_IP:$TINYPROXY_PORT" "http://$WEBSERVER_IP:$WEBSERVER_PORT" test "x$?" = "x0" || FAILED=$((FAILED + 1)) echo -n "testing connection to filtered domain..." run_failure_webclient_request 403 "$TINYPROXY_IP:$TINYPROXY_PORT" "http://badgoy.google-analytics.com/" test "x$?" = "x0" || FAILED=$((FAILED + 1)) echo -n "requesting connect method to denied port..." run_failure_webclient_request 403 --method=CONNECT "$TINYPROXY_IP:$TINYPROXY_PORT" "localhost:12345" test "x$?" = "x0" || FAILED=$((FAILED + 1)) echo -n "testing unavailable backend..." run_failure_webclient_request 502 "$TINYPROXY_IP:$TINYPROXY_PORT" "http://bogus.invalid" test "x$?" = "x0" || FAILED=$((FAILED + 1)) } basic_test reload_config basic_test ext_test echo "$FAILED errors" if test "x$TINYPROXY_TESTS_WAIT" = "xyes"; then echo "You can continue using the webserver and tinyproxy." echo -n "hit to stop the servers and exit: " read READ fi stop_tinyproxy stop_webserver echo "done" exit $FAILED tinyproxy-1.11.2/tests/scripts/run_tests_valgrind.sh000077500000000000000000000020261461674137700230050ustar00rootroot00000000000000#!/bin/sh # testsuite runner for tinyproxy : valgrind wrapper # # Copyright (C) 2009 Michael Adam # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the Free # Software Foundation; either version 2 of the License, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # more details. # # You should have received a copy of the GNU General Public License along with # this program; if not, see . SCRIPTS_DIR=$(dirname $0) BASEDIR=$SCRIPTS_DIR/../.. TESTS_DIR=$SCRIPTS_DIR/.. TESTENV_DIR=$TESTS_DIR/env LOG_DIR=$TESTENV_DIR/var/log VALGRIND="valgrind --track-origins=yes --show-leak-kinds=all --tool=memcheck --leak-check=full --log-file=$LOG_DIR/valgrind.log" $SCRIPTS_DIR/run_tests.sh tinyproxy-1.11.2/tests/scripts/webclient.pl000077500000000000000000000100571461674137700210510ustar00rootroot00000000000000#!/usr/bin/perl -w # Simple command line web client. # Initially loosely based on examples from the perlipc manpage. # # Copyright (C) 2009 Michael Adam # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the Free # Software Foundation; either version 2 of the License, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # more details. # # You should have received a copy of the GNU General Public License along with # this program; if not, see . use strict; use IO::Socket; use Getopt::Long; use Pod::Usage; my $EOL = "\015\012"; my $VERSION = "0.1"; my $NAME = "Tinyproxy-Web-Client"; my $user_agent = "$NAME/$VERSION"; my $user_agent_header = "User-Agent: $user_agent$EOL"; my $http_version = "1.0"; my $method = "GET"; my $dry_run = 0; my $help = 0; my $entity = undef; my $default_port = "80"; my $port = $default_port; sub process_options() { my $result = GetOptions("help|?" => \$help, "http-version=s" => \$http_version, "method=s" => \$method, "dry-run" => \$dry_run, "entity=s" => \$entity); die "Error reading cmdline options! $!" unless $result; pod2usage(1) if $help; # some post-processing: } sub build_request($$$$$$) { my ( $host, $port, $version, $method, $document, $entity ) = @_; my $request = ""; $method = uc($method); if ($version eq '0.9') { if ($method ne 'GET') { die "invalid method '$method'"; } $request = "$method $document$EOL"; } elsif ($version eq '1.0') { $request = "$method $document HTTP/$version$EOL" . $user_agent_header; } elsif ($version eq '1.1') { $request = "$method $document HTTP/$version$EOL" . "Host: $host" . (($port and ($port ne $default_port))?":$port":"") . "$EOL" . $user_agent_header . "Connection: close$EOL"; } else { die "invalid version '$version'"; } $request .= $EOL; if ($entity) { $request .= $entity; } return $request; } # main process_options(); unless (@ARGV > 1) { pod2usage(1); } my $hostarg = shift(@ARGV); my $host = $hostarg; if ($host =~ /^([^:]+):(.*)/) { $port = $2; $host = $1; } foreach my $document (@ARGV) { my $request = build_request($host, $port, $http_version, $method, $document, $entity); if ($dry_run) { print $request; exit(0); } my $remote = IO::Socket::INET->new( Proto => "tcp", PeerAddr => $host, PeerPort => $port, ); unless ($remote) { die "cannot connect to http daemon on $host (port $port)"; } $remote->autoflush(1); print $remote $request; $_ = <$remote>; print; # /* HTTP/1.0 400 Bad Request */ my($errn) = ($_ =~ /HTTP\/\d\.\d (\d{3})/); while (<$remote>) { print; } close $remote; exit($errn - 399) if($errn > 399); } exit(0); __END__ =head1 webclient.pl A simple WEB client written in perl. =head1 SYNOPSIS webclient.pl [options] host[:port] document [document ...] =head1 OPTIONS =over 8 =item B<--help> Print a brief help message and exit. =item B<--http-version> Specify the HTTP protocol version to use (0.9, 1.0, 1.1). Default is 1.0. =item B<--method> Specify the HTTP request method ('GET', 'CONNECT', ...). Default is 'GET'. =item B<--entity> Add the provided string as entity (i.e. body) to the request. =item B<--dry-run> Don't actually connect to the server but print the request that would be sent. =back =head1 DESCRIPTION This is a basic web client. It permits to send http request messages to web servers or web proxy servers. The result is printed as is to standard output, including headers. This is meant as a tool for diagnosing and testing web servers and proxy servers. =head1 COPYRIGHT Copyright (C) 2009 Michael Adam This program is distributed under the terms of the GNU General Public License version 2 or above. See the COPYING file for additional information. =cut tinyproxy-1.11.2/tests/scripts/webserver.pl000077500000000000000000000234101461674137700210760ustar00rootroot00000000000000#!/usr/bin/perl -w # Simple WEB server. # # Inspired by some examples from the perlipc and other perl manual pages. # # Copyright (C) 2009 Michael Adam # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the Free # Software Foundation; either version 2 of the License, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # more details. # # You should have received a copy of the GNU General Public License along with # this program; if not, see . use strict; use IO::Socket; use IO::Select; use Carp; use POSIX qw(setsid :sys_wait_h); use Errno; use Getopt::Long; use Pod::Usage; use Fcntl ':flock'; # import LOCK_* constants my $VERSION = "0.1"; my $NAME = "Tinyproxy-Test-Web-Server"; my $server_header = "Server: $NAME/$VERSION"; my $EOL = "\015\012"; my $port = 2345; my $proto = getprotobyname('tcp'); my $pid_file = "/tmp/webserver.pid"; my $log_dir = "/tmp"; my $access_log_file; my $error_log_file; my $document_root = "/tmp"; my $help = 0; sub create_child($$$); sub logmsg { print STDERR "[", scalar localtime, ", $$] $0: @_\n"; } sub start_server($$) { my $proto = shift; my $port = shift; my $server; $server = IO::Socket::INET->new(Proto => $proto, LocalPort => $port, Listen => SOMAXCONN, Reuse => 1); logmsg "server started listening on port $port"; return $server; } sub REAPER { local $!; # don't let waitpid() overwrite current error while ((my $pid = waitpid(-1,WNOHANG)) > 0 && WIFEXITED($?)) { logmsg "reaped $pid" . ($? ? " with exit code $?" : ''); } $SIG{CHLD} = \&REAPER; } sub parse_request($) { my $client = shift; my $request = {}; # parse the request line my $request_line = <$client>; if (!$request_line) { $request->{error} = "emtpy request"; return $request; } chomp ($request_line); my ($method, $object, $version) = split(" ", $request_line); unless (defined($version) and $version) { $request->{version} = "0.9"; } else { if ($version !~ /HTTP\/(\d\.\d)/gi) { $request->{error} = "illegal version ($version)"; return $request; } $request->{version} = $1; } $request->{method} = uc($method); $request->{object} = $object; # parse the request headers my $current_header_line; $request->{headers} = []; while ($request_line = <$client>) { if ($request_line =~ /^[ \t]/) { # continued header line chomp $request_line; $current_header_line .= $request_line; next; } if ($current_header_line) { # finish current header line my ($name, $value) = split(": ", $current_header_line); push(@{$request->{headers}}, { name => lc($name), value => $value }); } last if ($request_line eq $EOL); chomp $request_line; $current_header_line = $request_line; } # parse entity (body) $request->{entity} = ""; # skip for now, don't block... # if ($request_line) { # while ($request_line = <$client>) { # logmsg "got line '$request_line'"; # $request->{entity} .= $request_line; # } # } my @print_headers = (); foreach my $header (@{$request->{headers}}) { push @print_headers, $header->{name} . ": " . $header->{value}; } logmsg "request:\n" . "------------------------------\n" . "Method: " . $request->{method} . "\n" . "Object: " . $request->{object} . "\n" . "Version: " . $request->{version} . "\n" . "\n" . "Headers:\n" . join("\n", @print_headers) . "\n" . #"\n" . #"Body:\n" . #"'" . $request->{entity} . "'\n" . "------------------------------"; return $request; } sub child_action($) { my $client = shift; my $client_ip = shift; logmsg "client_action: client $client_ip"; $client->autoflush(); my $fortune_bin = "/usr/games/fortune"; my $fortune = ""; if ( -x $fortune_bin) { $fortune = qx(/usr/games/fortune); $fortune =~ s/\n/$EOL/g; } my $request = parse_request($client); if ($request->{error}) { print $client "HTTP/1.0 400 Bad Request$EOL"; print $client "$server_header$EOL"; print $client "Content-Type: text/html$EOL"; print $client "$EOL"; print $client "$EOL"; print $client "

400 Bad Request

$EOL"; print $client "

Error: " . $request->{error} . "

$EOL"; print $client "$EOL"; close $client; return; } if ($request->{version} ne "0.9") { print $client "HTTP/1.0 200 OK$EOL"; print $client "$server_header$EOL"; print $client "Content-Type: text/html$EOL"; print $client "$EOL"; } print $client "$EOL"; print $client "

Tinyproxy test WEB server

$EOL"; print $client "

Fortune

$EOL"; if ($fortune) { print $client "
$fortune
$EOL"; } else { print $client "Sorry, no $fortune_bin not found.$EOL"; } my @print_headers = (); foreach my $header (@{$request->{headers}}) { push @print_headers, $header->{name} . ": " . $header->{value}; } print $client "

Your request:

$EOL"; print $client "
$EOL";
	print $client "Method:  " . $request->{method} . "\n" .
		"Object:  " . $request->{object} . "\n" .
		"Version: " . $request->{version} . "\n" .
		"\n" .
		join("\n", @print_headers) .
		"\n" .
		"entity (body):\n" .
		$request->{entity} . "\n";
	print $client "
$EOL"; print $client "$EOL"; close $client; return 0; } sub create_child($$$) { my $client = shift; my $action = shift; my $client_ip = shift; unless (@_ == 0 && $action && ref($action) eq 'CODE') { confess "internal error. create_child needs code reference as argument"; } my $pid = fork(); if (not defined($pid)) { # error logmsg "cannot fork: $!"; return; } elsif ($pid) { # parent logmsg "child process created with pid $pid"; return; } else { # child exit &$action($client, $client_ip); } } sub process_options() { my $result = GetOptions("help|?" => \$help, "port=s" => \$port, "pid-file=s" => \$pid_file, "log-dir=s" => \$log_dir, "root|document-root=s" => \$document_root); die "Error reading cmdline options! $!" unless $result; pod2usage(1) if $help; # some post-processing: ($port) = $port =~ /^(\d+)$/ or die "invalid port"; $access_log_file = "$log_dir/webserver.access_log"; $error_log_file = "$log_dir/webserver.error_log"; } sub daemonize() { umask 0; chdir "/" or die "daemonize: can't chdir to /: $!"; open STDIN, "/dev/null" or die "daemonize: Can't read from /dev/null: $!"; my $pid = fork(); die "daemonize: can't fork: $!" if not defined($pid); exit(0) if $pid != 0; # parent # child (daemon) setsid or die "damonize: Can't create a new session: $!"; } sub reopen_logs() { open STDOUT, ">> $access_log_file" or die "daemonize: Can't write to '$access_log_file': $!"; open STDERR, ">> $error_log_file" or die "daemonize: Can't write to '$error_log_file': $!"; } sub get_pid_lock() { # first make sure the file exists open(LOCKFILE_W, ">> $pid_file") or die "Error opening pid file '$pid_file' for writing: $!"; # open for reading and try to lock: open(LOCKFILE, "< $pid_file") or die "Error opening pid file '$pid_file' for reading: $!"; unless (flock(LOCKFILE, LOCK_EX|LOCK_NB)) { print "pid file '$pid_file' is already locked.\n"; my $other_pid = ; if (!defined($other_pid)) { print "Error reading from pid file.\n"; } else { chomp($other_pid); if (!$other_pid) { print "pid file is empty.\n"; } else { print "Webserver is already running with pid '$other_pid'.\n"; } } close LOCKFILE; exit(0); } # now re-open for recreating the file and write our pid close(LOCKFILE_W); open(LOCKFILE_W, "> $pid_file") or die "Error opening pid file '$pid_file' for writing: $!"; LOCKFILE_W->autoflush(1); print LOCKFILE_W "$$"; close(LOCKFILE_W); } sub release_pid_lock() { flock(LOCKFILE, LOCK_UN); close LOCKFILE; } # "main" ... $|=1; # autoflush process_options(); daemonize(); get_pid_lock(); reopen_logs(); $SIG{CHLD} = \&REAPER; my $server = start_server($proto, $port); my $slct = IO::Select->new($server); while (1) { my @ready_for_reading = $slct->can_read(); foreach my $fh (@ready_for_reading) { if ($fh != $server) { logmsg "select: fh ready for reading but not server", "don't know what to do..."; } # new connection: my $client = $server->accept() or do { # try again if accept() returned because # a signal was received if ($!{EINTR}) { logmsg "accept: got signal EINTR ..."; next; } die "accept: $!"; }; my $client_ip = inet_ntoa($client->peeraddr); logmsg "connection from $client_ip at port " . $client->peerport; create_child($client, \&child_action, $client_ip); close $client; } } # never reached... logmsg "Server done - ooops!\n"; release_pid_lock(); exit(0); __END__ =head1 webserver.pl A simple WEB server written in perl. =head1 SYNOPSIS webserver.pl [options] =head1 OPTIONS =over 8 =item B<--help> Print a brief help message and exit. =item B<--port> Specify the port number for the server to listen on. =item B<--root|--document-root> Specify the document root directory from which to serve web content. =item B<--log-dir> Specify the directory where the log files should be stored. =item B<--pid-file> Specify the location of the pid lock file. =back =head1 DESCRIPTION This is a very simple web server. It currently does not deliver the specific web page requested, but constructs the same kind of answer for each request, citing a fortune if fortune is available, and printing the originating request. =head1 COPYRIGHT Copyright (C) 2009 Michael Adam This program is distributed under the terms of the GNU General Public License version 2 or above. See the COPYING file for additional information. =cut tinyproxy-1.11.2/tinyproxy-indent.sh000077500000000000000000000005631461674137700176100ustar00rootroot00000000000000#!/bin/sh # This is a script to mostly indent C code to the Tinyproxy coding # style. It needs GNU indent 2.2.10 or above. In a nutshell, Tinyproxy # uses the K&R style, tab size 8, spaces instead of tabs, wrap at column # 80, space before brackets. indent -npro -kr -i8 -ts8 -sob -l80 -ss -cs -cp1 -bs -nlps -nprs -pcs \ -saf -sai -saw -sc -cdw -ce -nut -il0 "$@"