diff --git a/AUTHORS b/AUTHORS index 9c82e40..d0e6b30 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,43 +1,39 @@ -Tinyproxy AUTHORS -================= - -//// -This file is generated from authors.xml, do not edit it directly. -//// - -Coding ------- - -The following people have contributed code to Tinyproxy: - - * Andrew Stribblehill - * Chris Lightfoot - * Daniel Egger - * David Shanks - * Dmitry Semyonov - * George Talusan - * James E. Flemer - * Jeremy Hinegardner - * John van der Kamp - * Jordi Mallach - * Kim Holviala - * Mathew Mrosko - * Matthew Dempsky - * Michael Adam - * Moritz Muehlenhoff - * Mukund Sivaraman - * Petr Lampa - * Robert James Kaes - * Steven Young - - -Documentation -------------- - -The following people have helped to document Tinyproxy: - - * Marc Silver - * Michael Adam - * Mukund Sivaraman - * Robert James Kaes - * Steven Young +Andrew 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 diff --git a/Makefile.am b/Makefile.am index 9d62d2c..4a3ead6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,27 +4,13 @@ SUBDIRS = \ etc \ docs \ m4macros \ - tests + tests \ + scripts # tools want this on a single line ACLOCAL_AMFLAGS = -I m4macros -AUTHORS: authors.xml authors.xsl -if HAVE_XSLTPROC - $(AM_V_GEN) $(XSLTPROC) authors.xsl $< > $(@) || rm -f $(@) -else - @echo "*** xsltproc is required to regenerate $(@) ***"; exit 1; -endif - -validate-authors: -if HAVE_XMLLINT - @$(XMLLINT) --noout --path $(srcdir) --valid authors.xml || \ - ( echo "*** authors.xml IS INVALID ***"; exit 1; ) -endif - -all-local: AUTHORS - -check-local: validate-authors +all-local: dist_doc_DATA = \ AUTHORS \ @@ -33,12 +19,10 @@ dist_doc_DATA = \ README.md EXTRA_DIST = \ - authors.dtd \ - authors.xml \ - authors.xsl \ autogen.sh \ tinyproxy-indent.sh \ - TODO + TODO \ + VERSION test: all ./tests/scripts/run_tests.sh diff --git a/NEWS b/NEWS index 550e7fe..c0fddc8 100644 --- a/NEWS +++ b/NEWS @@ -1,12 +1 @@ -Tinyproxy NEWS -============== - -Version 1.9.0 -------------- - -Bugs fixed -~~~~~~~~~~ - -Contributors -~~~~~~~~~~~~ - +See git log for recent changes in Tinyproxy. diff --git a/README.md b/README.md index 2cb8d59..f13e670 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ system. If compiling from a git checkout, you need to first run from the top level directory to generate the `configure` script. The release tarball contains the pre-created `configure` script, -so when building fom a release, you can skip this step. +so when building from a release, you can skip this step. Then basically all you need to do is @@ -56,9 +56,6 @@ Enable support for proxying connections through another proxy server. - `--enable-transparent`: Allow Tinyproxy to be used as a transparent proxy daemon. -- `--enable-static`: -Compile a static version of Tinyproxy. - - `--enable-reverse`: Enable reverse proxying. diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..81c871d --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +1.10.0 diff --git a/authors.dtd b/authors.dtd deleted file mode 100644 index 77d43c5..0000000 --- a/authors.dtd +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/authors.xml b/authors.xml deleted file mode 100644 index 7fc94f2..0000000 --- a/authors.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - Andrew Stribblehill - Chris Lightfoot - Daniel Egger - David Shanks - Dmitry Semyonov - George Talusan - James E. Flemer - Jeremy Hinegardner - John van der Kamp - Jordi Mallach - Kim Holviala - Marc Silver - Mathew Mrosko - Matthew Dempsky - Michael Adam - Moritz Muehlenhoff - Mukund Sivaraman - Petr Lampa - Robert James Kaes - Steven Young - - diff --git a/authors.xsl b/authors.xsl deleted file mode 100644 index 77ba4e0..0000000 --- a/authors.xsl +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - - - - - - - - - Tinyproxy AUTHORS -================= - -//// -This file is generated from authors.xml, do not edit it directly. -//// - -Coding ------- - -The following people have contributed code to Tinyproxy: - - - - - - - -Documentation -------------- - -The following people have helped to document Tinyproxy: - - - - - - - - - - * - - - - diff --git a/configure.ac b/configure.ac index 10036ca..6ddbcc0 100644 --- a/configure.ac +++ b/configure.ac @@ -3,20 +3,7 @@ AC_PREREQ(2.54) -m4_define([tinyproxy_major_version], [1]) -m4_define([tinyproxy_minor_version], [9]) -m4_define([tinyproxy_micro_version], [0]) -m4_define([tinyproxy_real_version], - [tinyproxy_major_version.tinyproxy_minor_version.tinyproxy_micro_version]) -m4_define([tinyproxy_version], [tinyproxy_real_version]) - -# For overriding the version string. Comment out if not needed. -# m4_define([tinyproxy_version], [1.9.0]) - -m4_define([tinyproxy_unstable], - m4_if(m4_eval(tinyproxy_minor_version % 2), [1], [yes], [no])) -m4_define([tinyproxy_stable], - m4_if(m4_eval(tinyproxy_minor_version % 2), [0], [yes], [no])) +m4_define([tinyproxy_version], esyscmd(sh scripts/version.sh | tr -d '\n')) AC_INIT([Tinyproxy], [tinyproxy_version], [https://tinyproxy.github.io/], @@ -29,31 +16,9 @@ AC_CONFIG_MACRO_DIR([m4macros]) m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) -TINYPROXY_MAJOR_VERSION=tinyproxy_major_version -TINYPROXY_MINOR_VERSION=tinyproxy_minor_version -TINYPROXY_MICRO_VERSION=tinyproxy_micro_version -TINYPROXY_REAL_VERSION=tinyproxy_real_version -TINYPROXY_VERSION=tinyproxy_version -TINYPROXY_UNSTABLE=tinyproxy_unstable -AC_SUBST(TINYPROXY_MAJOR_VERSION) -AC_SUBST(TINYPROXY_MINOR_VERSION) -AC_SUBST(TINYPROXY_MICRO_VERSION) -AC_SUBST(TINYPROXY_REAL_VERSION) -AC_SUBST(TINYPROXY_VERSION) -AC_SUBST(TINYPROXY_UNSTABLE) - dnl Temporarily defined here until we get tinyproxy-version.h AC_DEFINE(TINYPROXY_VERSION, "tinyproxy_version", [Tinyproxy version number]) -# The symbol TINYPROXY_UNSTABLE is defined above for substitution in -# Makefiles and conditionally defined here as a preprocessor symbol -# and automake conditional. -if test "x$TINYPROXY_UNSTABLE" = "xyes"; then - AC_DEFINE(TINYPROXY_UNSTABLE, 1, - [Define to 1 if this is an unstable version of Tinyproxy]) -fi -AM_CONDITIONAL(TINYPROXY_UNSTABLE, test "x$TINYPROXY_UNSTABLE" = "xyes") - dnl Check if we're compiling on a weird platform :) AC_USE_SYSTEM_EXTENSIONS @@ -113,8 +78,8 @@ dnl Include support for reverse proxy? AH_TEMPLATE([REVERSE_SUPPORT], [Include support for reverse proxy.]) TP_ARG_ENABLE(reverse, - [Enable reverse proxying (default is NO)], - no) + [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) @@ -124,8 +89,8 @@ 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 NO)], - no) + [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) @@ -173,7 +138,7 @@ AC_CHECK_FUNCS([inet_ntoa strdup]) 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 -pedantic -Wno-overlength-strings -Wc++-compat -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" +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" @@ -245,6 +210,7 @@ docs/man8/tinyproxy.txt m4macros/Makefile tests/Makefile tests/scripts/Makefile +scripts/Makefile ]) AC_OUTPUT diff --git a/docs/man5/tinyproxy.conf.txt.in b/docs/man5/tinyproxy.conf.txt.in index 143b746..564de8b 100644 --- a/docs/man5/tinyproxy.conf.txt.in +++ b/docs/man5/tinyproxy.conf.txt.in @@ -144,21 +144,25 @@ The possible keywords and their descriptions are as follows: `X-Tinyproxy` containing the client's IP address to the request. *Upstream*:: -*No Upstream*:: 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. There are three possible forms for - specifying upstream rules: + LAST matching rule wins. The following forms for specifying upstream + rules exist: - * 'upstream host:port' turns proxy upstream support on generally. + * 'upstream type host:port' turns proxy upstream support on generally. - * 'upstream host:port "site_spec"' turns on the upstream proxy for - the sites matching `site_spec`. + * 'upstream type user:pass@host:port' does the same, but uses the + supplied credentials for authentication. - * 'no upstream "site_spec"' turns off upstream support for sites + * 'upstream type host:port "site_spec"' turns on the upstream proxy + for the sites matching `site_spec`. + + `type` can be one of `http`, `socks4`, `socks5`, `none`. + + * 'upstream none "site_spec"' turns off upstream support for sites matching `site_spec`. The site can be specified in various forms as a hostname, domain @@ -368,10 +372,7 @@ This manpage was written by the Tinyproxy project team. COPYRIGHT --------- -Copyright (c) 1998-2000 Steven Young; -Copyright (c) 2000-2001 Robert James Kaes; -Copyright (c) 2009-2010 Mukund Sivaraman; -Copyright (c) 2009-2010 Michael Adam. +Copyright (c) 1998-2018 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 diff --git a/docs/man8/tinyproxy.txt.in b/docs/man8/tinyproxy.txt.in index e259dcb..54da867 100644 --- a/docs/man8/tinyproxy.txt.in +++ b/docs/man8/tinyproxy.txt.in @@ -12,7 +12,7 @@ tinyproxy - A light-weight HTTP proxy daemon SYNOPSIS -------- -*tinyproxy* [-vldch] +*tinyproxy* [-vdch] DESCRIPTION @@ -40,9 +40,6 @@ OPTIONS *-h*:: Display a short help screen of command line arguments and exit. -*-l*:: - Display the licensing agreement. - *-v*:: Display version information and exit. @@ -153,10 +150,7 @@ This manpage was written by the Tinyproxy project team. COPYRIGHT --------- -Copyright (c) 1998-2000 Steven Young; -Copyright (c) 2000-2001 Robert James Kaes; -Copyright (c) 2009-2010 Mukund Sivaraman; -Copyright (c) 2009-2010 Michael Adam. +Copyright (c) 1998-2018 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 diff --git a/etc/tinyproxy.conf.in b/etc/tinyproxy.conf.in index 5fc63f1..59bdcd4 100644 --- a/etc/tinyproxy.conf.in +++ b/etc/tinyproxy.conf.in @@ -90,7 +90,8 @@ 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. +# exclusive. If neither Syslog nor LogFile are specified, output goes +# to stdout. # #LogFile "@localstatedir@/log/tinyproxy/tinyproxy.log" @@ -102,7 +103,7 @@ StatFile "@pkgdatadir@/stats.html" #Syslog On # -# LogLevel: +# LogLevel: Warning # # Set the logging level. Allowed settings are: # Critical (least verbose) @@ -121,6 +122,7 @@ 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" @@ -138,25 +140,37 @@ LogLevel Info # 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 testproxy:8008 ".test.domain.invalid" -# upstream testproxy:8008 ".our_testbed.example.com" -# upstream testproxy:8008 "192.168.128.0/255.255.254.0" +# 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 -# no upstream ".internal.example.com" -# no upstream "www.example.com" -# no upstream "10.0.0.0/8" -# no upstream "192.168.0.0/255.255.254.0" -# no upstream "." +# 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 cust1_firewall:8008 "testbed_for_cust1" -# upstream cust2_firewall:8008 "testbed_for_cust2" +# upstream http cust1_firewall:8008 "testbed_for_cust1" +# upstream http cust2_firewall:8008 "testbed_for_cust2" # # # default upstream is internet firewall -# upstream firewall.internal.example.com:80 +# 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: @@ -166,7 +180,7 @@ LogLevel Info # IP/bits matches network/mask # IP/mask matches network/mask # -#Upstream some.remote.proxy:port +#Upstream http some.remote.proxy:port # # MaxClients: This is the absolute highest number of threads which will @@ -209,6 +223,11 @@ MaxRequestsPerChild 0 # Allow 127.0.0.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 @@ -292,12 +311,12 @@ ViaProxyName "tinyproxy" # 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 (which is not very secure.) +# allowed. # # The following two ports are used by SSL. # -ConnectPort 443 -ConnectPort 563 +#ConnectPort 443 +#ConnectPort 563 # # Configure one or more ReversePath directives to enable reverse proxy diff --git a/scripts/Makefile.am b/scripts/Makefile.am new file mode 100644 index 0000000..4876c5d --- /dev/null +++ b/scripts/Makefile.am @@ -0,0 +1,2 @@ +EXTRA_DIST = \ + version.sh diff --git a/scripts/gen-authors.sh b/scripts/gen-authors.sh new file mode 100755 index 0000000..671f0c1 --- /dev/null +++ b/scripts/gen-authors.sh @@ -0,0 +1,10 @@ +#!/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}" diff --git a/scripts/version.sh b/scripts/version.sh new file mode 100755 index 0000000..9a965dc --- /dev/null +++ b/scripts/version.sh @@ -0,0 +1,15 @@ +#!/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 + git describe --match '[0-9]*.[0-9]*.[0-9]*' 2>/dev/null \ + | sed -e 's/-/-git-/' + else + sed 's/$/-git/' < VERSION + fi +else + cat VERSION +fi diff --git a/src/Makefile.am b/src/Makefile.am index c42b0dd..af2f621 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -17,7 +17,7 @@ pkgsysconfdir = $(sysconfdir)/$(PACKAGE) -sbin_PROGRAMS = tinyproxy +bin_PROGRAMS = tinyproxy AM_CPPFLAGS = \ -DSYSCONFDIR=\"${pkgsysconfdir}\" \ @@ -26,7 +26,6 @@ AM_CPPFLAGS = \ tinyproxy_SOURCES = \ acl.c acl.h \ anonymous.c anonymous.h \ - authors.c authors.h \ buffer.c buffer.h \ child.c child.h \ common.h \ @@ -47,6 +46,8 @@ tinyproxy_SOURCES = \ utils.c utils.h \ vector.c vector.h \ upstream.c upstream.h \ + basicauth.c basicauth.h \ + base64.c base64.h \ connect-ports.c connect-ports.h EXTRA_tinyproxy_SOURCES = filter.c filter.h \ @@ -54,16 +55,3 @@ EXTRA_tinyproxy_SOURCES = filter.c filter.h \ transparent-proxy.c transparent-proxy.h tinyproxy_DEPENDENCIES = @ADDITIONAL_OBJECTS@ tinyproxy_LDADD = @ADDITIONAL_OBJECTS@ - -EXTRA_DIST = \ - authors.xsl - -authors.c: $(top_srcdir)/authors.xml $(srcdir)/authors.xsl -if HAVE_XSLTPROC - $(AM_V_GEN) $(XSLTPROC) $(srcdir)/authors.xsl $< > $(@) || rm -f $(@) -else - @echo "*** xsltproc is required to regenerate $(@) ***"; exit 1; -endif - -BUILT_SOURCES = \ - authors.c diff --git a/src/authors.c b/src/authors.c deleted file mode 100644 index 496df93..0000000 --- a/src/authors.c +++ /dev/null @@ -1,50 +0,0 @@ - -/* NOTE: This file is auto-generated from authors.xml, do not edit it. */ - -#include "authors.h" - -static const char * const authors[] = -{ - "Andrew Stribblehill", - "Chris Lightfoot", - "Daniel Egger", - "David Shanks", - "Dmitry Semyonov", - "George Talusan", - "James E. Flemer", - "Jeremy Hinegardner", - "John van der Kamp", - "Jordi Mallach", - "Kim Holviala", - "Mathew Mrosko", - "Matthew Dempsky", - "Michael Adam", - "Moritz Muehlenhoff", - "Mukund Sivaraman", - "Petr Lampa", - "Robert James Kaes", - "Steven Young", - NULL -}; - -static const char * const documenters[] = -{ - "Marc Silver", - "Michael Adam", - "Mukund Sivaraman", - "Robert James Kaes", - "Steven Young", - NULL -}; - -const char * const * -authors_get_authors (void) -{ - return authors; -} - -const char * const * -authors_get_documenters (void) -{ - return documenters; -} diff --git a/src/authors.xsl b/src/authors.xsl deleted file mode 100644 index 1388b9a..0000000 --- a/src/authors.xsl +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - - - - - - -/* NOTE: This file is auto-generated from authors.xml, do not edit it. */ - -#include "authors.h" - -static const char * const authors[] = -{ - - - - - NULL -}; - - - -static const char * const documenters[] = -{ - - - - - NULL -}; - -const char * const * -authors_get_authors (void) -{ - return authors; -} - -const char * const * -authors_get_documenters (void) -{ - return documenters; -} - - - - "", - - - diff --git a/src/base64.c b/src/base64.c new file mode 100644 index 0000000..cc9b6ae --- /dev/null +++ b/src/base64.c @@ -0,0 +1,57 @@ +/* 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; +} + diff --git a/src/authors.h b/src/base64.h similarity index 72% rename from src/authors.h rename to src/base64.h index 10e5110..4465b9e 100644 --- a/src/authors.h +++ b/src/base64.h @@ -1,5 +1,5 @@ /* tinyproxy - A fast light-weight HTTP proxy - * Copyright (C) 2010 Mukund Sivaraman + * 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 @@ -16,15 +16,14 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef __AUTHORS_H__ -#define __AUTHORS_H__ +#ifndef TINYPROXY_BASE64_H +#define TINYPROXY_BASE64_H -#include "common.h" +#include -const char * const * -authors_get_authors (void); +/* 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); -const char * const * -authors_get_documenters (void); +#endif -#endif /* __AUTHORS_H__ */ diff --git a/src/basicauth.c b/src/basicauth.c new file mode 100644 index 0000000..d6c2420 --- /dev/null +++ b/src/basicauth.c @@ -0,0 +1,98 @@ +/* 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 (vector_t authlist, + const char *user, const char *pass) +{ + char b[BASE64ENC_BYTES((256+2)-1) + 1]; + 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 (vector_append(authlist, b, ret + 1) == -ENOMEM) { + 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 (vector_t authlist, const char *authstring) +{ + ssize_t vl, i; + size_t el; + const char* entry; + + vl = vector_length (authlist); + if (vl == -EINVAL) return 0; + + for (i = 0; i < vl; i++) { + entry = vector_getentry (authlist, i, &el); + if (strcmp (authstring, entry) == 0) + return 1; + } + return 0; +} diff --git a/src/basicauth.h b/src/basicauth.h new file mode 100644 index 0000000..61dc5c3 --- /dev/null +++ b/src/basicauth.h @@ -0,0 +1,35 @@ +/* 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 "vector.h" + +extern ssize_t basicauth_string(const char *user, const char *pass, + char *buf, size_t bufsize); + +extern void basicauth_add (vector_t authlist, + const char *user, const char *pass); + +extern int basicauth_check (vector_t authlist, const char *authstring); + +#endif diff --git a/src/conf.c b/src/conf.c index 442c473..32167e2 100644 --- a/src/conf.c +++ b/src/conf.c @@ -36,6 +36,7 @@ #include "reverse-proxy.h" #include "upstream.h" #include "connect-ports.h" +#include "basicauth.h" /* * The configuration directives are defined in the structure below. Each @@ -116,6 +117,7 @@ static HANDLE_FUNC (handle_nop) } /* do nothing function */ 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); @@ -232,6 +234,7 @@ struct { handle_deny), STDCONF ("bind", "(" IP "|" IPV6 ")", handle_bind), /* other */ + STDCONF ("basicauth", ALNUM WS ALNUM, handle_basicauth), STDCONF ("errorfile", INT WS STR, handle_errorfile), STDCONF ("addheader", STR WS STR, handle_addheader), @@ -251,13 +254,15 @@ struct { STDCONF ("reversepath", STR "(" WS STR ")?", handle_reversepath), #endif #ifdef UPSTREAM_SUPPORT - /* upstream is rather complicated */ { - BEGIN "(no" WS "upstream)" WS STR END, handle_upstream_no, NULL + BEGIN "(upstream)" WS "(none)" WS STR END, handle_upstream_no, NULL }, { - BEGIN "(upstream)" WS "(" IP "|" ALNUM ")" ":" INT "(" WS STR - ")?" END, handle_upstream, NULL + BEGIN "(upstream)" WS "(http|socks4|socks5)" WS + "(" ALNUM /*username*/ ":" ALNUM /*password*/ "@" ")?" + "(" IP "|" ALNUM ")" + ":" INT "(" WS STR ")?" + END, handle_upstream, NULL }, #endif /* loglevel */ @@ -291,6 +296,7 @@ static void free_config (struct config_s *conf) safefree (conf->user); safefree (conf->group); vector_delete(conf->listen_addrs); + vector_delete(conf->basicauth_list); #ifdef FILTER_ENABLE safefree (conf->filter); #endif /* FILTER_ENABLE */ @@ -786,12 +792,7 @@ static HANDLE_FUNC (handle_xtinyproxy) static HANDLE_FUNC (handle_syslog) { -#ifdef HAVE_SYSLOG_H return set_bool_arg (&conf->syslog, line, &match[2]); -#else - fprintf (stderr, "Syslog support not compiled in executable.\n"); - return 1; -#endif } static HANDLE_FUNC (handle_bindsame) @@ -892,7 +893,6 @@ static HANDLE_FUNC (handle_deny) static HANDLE_FUNC (handle_bind) { -#ifndef TRANSPARENT_PROXY int r = set_string_arg (&conf->bind_address, line, &match[2]); if (r) @@ -900,11 +900,6 @@ static HANDLE_FUNC (handle_bind) log_message (LOG_INFO, "Outgoing connections bound to IP %s", conf->bind_address); return 0; -#else - fprintf (stderr, - "\"Bind\" cannot be used with transparent support enabled.\n"); - return 1; -#endif } static HANDLE_FUNC (handle_listen) @@ -1011,6 +1006,27 @@ static HANDLE_FUNC (handle_loglevel) 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 = vector_create (); + } + + basicauth_add (conf->basicauth_list, user, pass); + safefree (user); + safefree (pass); + return 0; +} + #ifdef FILTER_ENABLE static HANDLE_FUNC (handle_filter) { @@ -1087,27 +1103,58 @@ static HANDLE_FUNC (handle_reversepath) #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; - char *domain; + int port, mi = 2; + char *domain = 0, *user = 0, *pass = 0, *tmp; + enum proxy_type pt; - ip = get_string_arg (line, &match[2]); + 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++; + + ip = get_string_arg (line, &match[mi]); if (!ip) return -1; - port = (int) get_long_arg (line, &match[7]); + mi += 5; - if (match[10].rm_so != -1) { - domain = get_string_arg (line, &match[10]); - if (domain) { - upstream_add (ip, port, domain, &conf->upstream_list); - safefree (domain); - } - } else { - upstream_add (ip, port, NULL, &conf->upstream_list); - } + port = (int) get_long_arg (line, &match[mi]); + mi += 3; + if (match[mi].rm_so != -1) + domain = get_string_arg (line, &match[mi]); + + upstream_add (ip, port, domain, user, pass, pt, &conf->upstream_list); + + safefree (user); + safefree (pass); + safefree (domain); safefree (ip); return 0; @@ -1117,11 +1164,11 @@ static HANDLE_FUNC (handle_upstream_no) { char *domain; - domain = get_string_arg (line, &match[2]); + domain = get_string_arg (line, &match[3]); if (!domain) return -1; - upstream_add (NULL, 0, domain, &conf->upstream_list); + upstream_add (NULL, 0, domain, 0, 0, PT_NONE, &conf->upstream_list); safefree (domain); return 0; diff --git a/src/conf.h b/src/conf.h index 2d38d03..349146b 100644 --- a/src/conf.h +++ b/src/conf.h @@ -37,6 +37,7 @@ typedef struct { * Hold all the configuration time information. */ struct config_s { + vector_t basicauth_list; char *logf_name; char *config_file; unsigned int syslog; /* boolean */ diff --git a/src/html-error.c b/src/html-error.c index 38adf85..625a586 100644 --- a/src/html-error.c +++ b/src/html-error.c @@ -132,6 +132,7 @@ send_html_file (FILE *infile, struct conn_s *connptr) } else in_variable = 0; + /* FALL THROUGH */ default: if (!in_variable) { r = write_message (connptr->client_fd, @@ -156,13 +157,24 @@ send_html_file (FILE *infile, struct conn_s *connptr) int send_http_headers (struct conn_s *connptr, int code, const char *message) { - const char *headers = + const char headers[] = "HTTP/1.0 %d %s\r\n" "Server: %s/%s\r\n" - "Content-Type: text/html\r\n" "Connection: close\r\n" "\r\n"; + "Content-Type: text/html\r\n" + "%s" + "Connection: close\r\n" "\r\n"; + + const char auth_str[] = + "Proxy-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 = code == 407 ? auth_str : ""; return (write_message (connptr->client_fd, headers, - code, message, PACKAGE, VERSION)); + code, message, PACKAGE, VERSION, + add)); } /* diff --git a/src/log.c b/src/log.c index f5a0b44..f85d29d 100644 --- a/src/log.c +++ b/src/log.c @@ -70,7 +70,14 @@ static unsigned int logging_initialized = FALSE; /* boolean */ */ int open_log_file (const char *log_file_name) { - log_file_fd = create_file_safely (log_file_name, FALSE); + if (log_file_name == NULL) { + if(config.godaemon == FALSE) + log_file_fd = fileno(stdout); + else + log_file_fd = -1; + } else { + log_file_fd = create_file_safely (log_file_name, FALSE); + } return log_file_fd; } @@ -79,7 +86,7 @@ int open_log_file (const char *log_file_name) */ void close_log_file (void) { - if (log_file_fd < 0) { + if (log_file_fd < 0 || log_file_fd == fileno(stdout)) { return; } @@ -154,6 +161,9 @@ void log_message (int level, const char *fmt, ...) goto out; } + if(!config.syslog && log_file_fd == -1) + goto out; + if (config.syslog) { #ifdef HAVE_VSYSLOG_H vsyslog (level, fmt, args); @@ -207,7 +217,7 @@ out: /* * This needs to send any stored log messages. */ -void send_stored_logs (void) +static void send_stored_logs (void) { char *string; char *ptr; diff --git a/src/log.h b/src/log.h index 68c89c3..76bfe6b 100644 --- a/src/log.h +++ b/src/log.h @@ -106,7 +106,6 @@ extern void close_log_file (void); extern void log_message (int level, const char *fmt, ...); extern void set_log_level (int level); -extern void send_stored_logs (void); extern int setup_logging (void); extern void shutdown_logging (void); diff --git a/src/main.c b/src/main.c index ae2a3a8..43170c5 100644 --- a/src/main.c +++ b/src/main.c @@ -32,7 +32,6 @@ #include "main.h" #include "anonymous.h" -#include "authors.h" #include "buffer.h" #include "conf.h" #include "daemon.h" @@ -87,55 +86,6 @@ display_version (void) printf ("%s %s\n", PACKAGE, VERSION); } -/* - * Display the copyright and license for this program. - */ -static void -display_license (void) -{ - const char * const *authors; - const char * const *documenters; - - display_version (); - - printf ("\ -\n\ - Copyright 1998 Steven Young (sdyoung@well.com)\n\ - Copyright 1998-2002 Robert James Kaes (rjkaes@users.sourceforge.net)\n\ - Copyright 1999 George Talusan (gstalusan@uwaterloo.ca)\n\ - Copyright 2000 Chris Lightfoot (chris@ex-parrot.com)\n\ - Copyright 2009-2010 Mukund Sivaraman (muks@banu.com)\n\ - Copyright 2009-2010 Michael Adam (obnox@samba.org)\n\ -\n\ - This program is free software; you can redistribute it and/or modify\n\ - it under the terms of the GNU General Public License as published by\n\ - the Free Software Foundation; either version 2, or (at your option)\n\ - any later version.\n\ -\n\ - This program is distributed in the hope that it will be useful,\n\ - but WITHOUT ANY WARRANTY; without even the implied warranty of\n\ - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\ - GNU General Public License for more details.\n\ -\n\ - You should have received a copy of the GNU General Public License\n\ - along with this program; if not, write to the Free Software\n\ - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.\n\ -\n"); - - printf ("\nAUTHORS:\n"); - for (authors = authors_get_authors (); *authors; authors++) { - printf (" %s\n", *authors); - } - - printf ("\nDOCUMENTERS:\n"); - for (documenters = authors_get_documenters (); - *documenters; documenters++) { - printf (" %s\n", *documenters); - } - - printf ("\n"); -} - /* * Display usage to the user. */ @@ -150,7 +100,6 @@ display_usage (void) " -d Do not daemonize (run in foreground).\n" " -c FILE Use an alternate configuration file.\n" " -h Display this usage information.\n" - " -l Display the license.\n" " -v Display version information.\n"); /* Display the modes compiled into tinyproxy */ @@ -224,16 +173,12 @@ process_cmdline (int argc, char **argv, struct config_s *conf) { int opt; - while ((opt = getopt (argc, argv, "c:vldh")) != EOF) { + while ((opt = getopt (argc, argv, "c:vdh")) != EOF) { switch (opt) { case 'v': display_version (); exit (EX_OK); - case 'l': - display_license (); - exit (EX_OK); - case 'd': conf->godaemon = FALSE; break; @@ -355,8 +300,8 @@ static void initialize_config_defaults (struct config_s *conf) conf->errorpages = NULL; conf->stathost = safestrdup (TINYPROXY_STATHOST); conf->idletimeout = MAX_IDLE_TIME; - conf->logf_name = safestrdup (LOCALSTATEDIR "/log/tinyproxy/tinyproxy.log"); - conf->pidpath = safestrdup (LOCALSTATEDIR "/run/tinyproxy/tinyproxy.pid"); + conf->logf_name = NULL; + conf->pidpath = NULL; } /** @@ -415,8 +360,13 @@ main (int argc, char **argv) anonymous_insert ("Content-Type"); } - if (config.godaemon == TRUE) + if (config.godaemon == TRUE) { + if (!config.syslog && config.logf_name == NULL) + fprintf(stderr, "WARNING: logging deactivated " + "(can't log to stdout when daemonized)\n"); + makedaemon (); + } if (set_signal_handler (SIGPIPE, SIG_IGN) == SIG_ERR) { fprintf (stderr, "%s: Could not set the \"SIGPIPE\" signal.\n", @@ -436,6 +386,15 @@ main (int argc, char **argv) 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]); @@ -448,15 +407,6 @@ main (int argc, char **argv) exit (EX_SOFTWARE); } - /* Create pid file after 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); - } - } - if (child_pool_create () < 0) { fprintf (stderr, "%s: Could not create the pool of children.\n", @@ -496,7 +446,7 @@ main (int argc, char **argv) child_close_sock (); /* Remove the PID file */ - if (unlink (config.pidpath) < 0) { + if (config.pidpath != NULL && unlink (config.pidpath) < 0) { log_message (LOG_WARNING, "Could not remove PID file \"%s\": %s.", config.pidpath, strerror (errno)); diff --git a/src/network.c b/src/network.c index 7bae20b..224f924 100644 --- a/src/network.c +++ b/src/network.c @@ -32,10 +32,11 @@ * 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 char *buffer, size_t count) +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); @@ -67,7 +68,7 @@ ssize_t safe_write (int fd, const char *buffer, size_t count) * Matched pair for safe_write(). If an EINTR occurs, pick up and try * again. */ -ssize_t safe_read (int fd, char *buffer, size_t count) +ssize_t safe_read (int fd, void *buffer, size_t count) { ssize_t len; diff --git a/src/network.h b/src/network.h index 15af481..37c0fba 100644 --- a/src/network.h +++ b/src/network.h @@ -21,8 +21,8 @@ #ifndef TINYPROXY_NETWORK_H #define TINYPROXY_NETWORK_H -extern ssize_t safe_write (int fd, const char *buffer, size_t count); -extern ssize_t safe_read (int fd, char *buffer, size_t count); +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); diff --git a/src/reqs.c b/src/reqs.c index e4bcf1d..5370b66 100644 --- a/src/reqs.c +++ b/src/reqs.c @@ -48,6 +48,7 @@ #include "upstream.h" #include "connect-ports.h" #include "conf.h" +#include "basicauth.h" /* * Maximum length of a HTTP line @@ -61,9 +62,11 @@ #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 /* @@ -267,6 +270,17 @@ establish_http_connection (struct conn_s *connptr, struct request_s *request) "Connection: close\r\n", request->method, request->path, 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.0\r\n" + "Host: %s%s\r\n" + "Connection: close\r\n" + "Proxy-Authorization: Basic %s\r\n", + request->method, request->path, + request->host, portbuff, + connptr->upstream_proxy->ua.authstr); } else { return write_message (connptr->server_fd, "%s %s HTTP/1.0\r\n" @@ -882,10 +896,10 @@ process_client_headers (struct conn_s *connptr, hashmap_t hashofheaders) /* * 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 - * proxy is in use.) + * http proxy is in use.) */ if (connptr->server_fd == -1 || connptr->show_stats - || (connptr->connect_method && (connptr->upstream_proxy == NULL))) { + || (connptr->connect_method && ! UPSTREAM_IS_HTTP(connptr))) { log_message (LOG_INFO, "Not sending client headers to remote machine"); return 0; @@ -1317,6 +1331,122 @@ static void relay_connection (struct conn_s *connptr) 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 hostent *host; + 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 */ + host = gethostbyname(request->host); + memcpy(&buff[4], host->h_addr_list[0], 4); /* dest ip */ + buff[8] = 0; /* user */ + if (9 != safe_write(connptr->server_fd, buff, 9)) + 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. */ @@ -1360,6 +1490,9 @@ connect_to_upstream (struct conn_s *connptr, struct request_s *request) 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.", @@ -1527,6 +1660,38 @@ void handle_connection (int fd) goto fail; } + if (config.basicauth_list != NULL) { + ssize_t len; + char *authstring; + int failure = 1; + len = hashmap_entry_by_key (hashofheaders, "proxy-authorization", + (void **) &authstring); + + if (len == 0) { + update_stats (STAT_DENIED); + indicate_http_error (connptr, 407, "Proxy Authentication Required", + "detail", + "This proxy requires authentication.", + NULL); + goto 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) { + update_stats (STAT_DENIED); + indicate_http_error (connptr, 401, "Unauthorized", + "detail", + "The administrator of this proxy has not configured " + "it to service requests from you.", + NULL); + goto fail; + } + hashmap_remove (hashofheaders, "proxy-authorization"); + } + /* * Add any user-specified headers (AddHeader directive) to the * outgoing HTTP request. @@ -1579,7 +1744,7 @@ void handle_connection (int fd) goto fail; } - if (!(connptr->connect_method && (connptr->upstream_proxy == NULL))) { + if (!connptr->connect_method || UPSTREAM_IS_HTTP(connptr)) { if (process_server_headers (connptr) < 0) { update_stats (STAT_BADCONN); goto fail; diff --git a/src/transparent-proxy.c b/src/transparent-proxy.c index 5d0c8f6..df5fbce 100644 --- a/src/transparent-proxy.c +++ b/src/transparent-proxy.c @@ -45,7 +45,7 @@ static int build_url (char **url, const char *host, int port, const char *path) assert (path != NULL); len = strlen (host) + strlen (path) + 14; - *url = (char *) safemalloc (len); + *url = (char *) saferealloc (*url, len); if (*url == NULL) return -1; diff --git a/src/upstream.c b/src/upstream.c index 6b25f9b..327b727 100644 --- a/src/upstream.c +++ b/src/upstream.c @@ -27,12 +27,28 @@ #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"; + } +} + /** * Construct an upstream struct from input data. */ -static struct upstream *upstream_build (const char *host, int port, const char *domain) +static struct upstream *upstream_build (const char *host, int port, const char *domain, + const char *user, const char *pass, + proxy_type type) { char *ptr; struct upstream *up; @@ -44,8 +60,25 @@ static struct upstream *upstream_build (const char *host, int port, const char * return NULL; } - up->host = up->domain = NULL; + up->type = type; + up->host = up->domain = up->ua.user = up->pass = NULL; up->ip = up->mask = 0; + 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) { + log_message (LOG_ERR, + "User / pass in upstream config too long"); + return NULL; + } + up->ua.authstr = safestrdup (b); + } else { + up->ua.user = safestrdup (user); + up->pass = safestrdup (pass); + } + } if (domain == NULL) { if (!host || host[0] == '\0' || port < 1) { @@ -57,9 +90,9 @@ static struct upstream *upstream_build (const char *host, int port, const char * up->host = safestrdup (host); up->port = port; - log_message (LOG_INFO, "Added upstream %s:%d for [default]", - host, port); - } else if (host == NULL) { + log_message (LOG_INFO, "Added upstream %s %s:%d for [default]", + proxy_type_name(type), host, port); + } else if (host == NULL || type == PT_NONE) { if (!domain || domain[0] == '\0') { log_message (LOG_WARNING, "Nonsense no-upstream rule: empty domain"); @@ -91,7 +124,7 @@ static struct upstream *upstream_build (const char *host, int port, const char * log_message (LOG_INFO, "Added no-upstream for %s", domain); } else { if (!host || host[0] == '\0' || port < 1 || !domain - || domain == '\0') { + || domain[0] == '\0') { log_message (LOG_WARNING, "Nonsense upstream rule: invalid parameters"); goto fail; @@ -101,13 +134,15 @@ static struct upstream *upstream_build (const char *host, int port, const char * up->port = port; up->domain = safestrdup (domain); - log_message (LOG_INFO, "Added upstream %s:%d for %s", - host, port, domain); + 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); safefree (up->domain); safefree (up); @@ -119,11 +154,12 @@ fail: * Add an entry to the upstream list */ void upstream_add (const char *host, int port, const char *domain, - struct upstream **upstream_list) + const char *user, const char *pass, + proxy_type type, struct upstream **upstream_list) { struct upstream *up; - up = upstream_build (host, port, domain); + up = upstream_build (host, port, domain, user, pass, type); if (up == NULL) { return; } @@ -202,8 +238,8 @@ struct upstream *upstream_get (char *host, struct upstream *up) up = NULL; if (up) - log_message (LOG_INFO, "Found upstream proxy %s:%d for %s", - up->host, up->port, host); + 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); diff --git a/src/upstream.h b/src/upstream.h index 34dad68..c112784 100644 --- a/src/upstream.h +++ b/src/upstream.h @@ -31,17 +31,32 @@ * 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 *domain; /* optional */ char *host; + union { + char *user; + char *authstr; + } ua; + char *pass; int port; in_addr_t ip, mask; + proxy_type type; }; #ifdef UPSTREAM_SUPPORT +const char *proxy_type_name(proxy_type type); extern void upstream_add (const char *host, int port, const char *domain, - struct upstream **upstream_list); + 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); #endif /* UPSTREAM_SUPPORT */