Compare commits
110 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
1115251555 | ||
|
72b477da9e | ||
|
87e8da90b0 | ||
|
c348513095 | ||
|
8845bdbff7 | ||
|
132a32a68d | ||
|
12c454119b | ||
|
9db1b0d087 | ||
|
e16844bd3b | ||
|
3cb25a7857 | ||
|
ffbef661cd | ||
|
54244661f7 | ||
|
5054b9b80f | ||
|
b86ecaa11b | ||
|
e467744134 | ||
|
4ebb3c1bb6 | ||
|
d05e801eef | ||
|
e1af5ffa58 | ||
|
6c8d9de3cc | ||
|
9eec142886 | ||
|
f413620c5f | ||
|
903c9eeb1c | ||
|
5a5ae8bfe1 | ||
|
51d4f11448 | ||
|
78ff8e0f07 | ||
|
6505867f7a | ||
|
0654ed6403 | ||
|
9ed48eb03b | ||
|
578f409a03 | ||
|
08c44a36ba | ||
|
e0ad093b0f | ||
|
4ef81ff95d | ||
|
3cdb1bf7aa | ||
|
d11d23c14c | ||
|
fdfa365bae | ||
|
954d427565 | ||
|
bb5d6af78f | ||
|
79f34cd113 | ||
|
4f600654d2 | ||
|
37ffa6986d | ||
|
5608382be9 | ||
|
04cc18d0f8 | ||
|
7b1801d8e7 | ||
|
844403afbe | ||
|
866f1c3e56 | ||
|
425ce3beb6 | ||
|
a8a2342527 | ||
|
ccb987e8e0 | ||
|
0adf359245 | ||
|
54eaac8e76 | ||
|
8963739e4b | ||
|
a747617c05 | ||
|
9d7a95bd56 | ||
|
3933daf793 | ||
|
18db1675a0 | ||
|
4d979df636 | ||
|
fc354343f9 | ||
|
1db982793d | ||
|
95a6f8259c | ||
|
8b76f1a939 | ||
|
121a11d8e5 | ||
|
736e052dc1 | ||
|
aa197d6dc8 | ||
|
d13d575d29 | ||
|
c4b187c8ab | ||
|
5012ce690f | ||
|
4b75b634d9 | ||
|
4b64de4c31 | ||
|
7fa544c3d8 | ||
|
a5a3741291 | ||
|
784d458b82 | ||
|
94edc4f4c5 | ||
|
be63d2ca19 | ||
|
a905437242 | ||
|
3127e726d0 | ||
|
5bb184c54d | ||
|
505ff803e9 | ||
|
d03e3a52e5 | ||
|
fe9444d585 | ||
|
b37135524d | ||
|
7f053670c0 | ||
|
b28e438cdf | ||
|
e495bdf129 | ||
|
287a7ae649 | ||
|
315e129f12 | ||
|
7cb30dd9ee | ||
|
9927d411bf | ||
|
0f28221ec5 | ||
|
57d90c8bf7 | ||
|
8de8634b8b | ||
|
ce149cc7a6 | ||
|
410eaf107c | ||
|
e6cbaf7b6e | ||
|
2d0192b8a8 | ||
|
643d52ac5a | ||
|
b92792fd8d | ||
|
965664798c | ||
|
6d5709de38 | ||
|
107f9117d0 | ||
|
1b3dd058d1 | ||
|
333d722d56 | ||
|
6f0abb7339 | ||
|
a19f758743 | ||
|
f63730c77e | ||
|
ed3ada7c26 | ||
|
b9e6d9742d | ||
|
fbc434e26d | ||
|
cc74869e71 | ||
|
577ac16cf1 | ||
|
810b9ae49a |
@ -17,5 +17,11 @@ EXTRA_DIST = \
|
||||
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
|
||||
|
98
NEWS
98
NEWS
@ -1,6 +1,102 @@
|
||||
Tinyproxy NEWS
|
||||
==============
|
||||
|
||||
Version 1.8.4
|
||||
-------------
|
||||
|
||||
Most notably, this release removes the limitation of
|
||||
a single Listen address of not listening on the
|
||||
wildcard address (BB#63) and a DoS (BB#110, CVE-2012-3505).
|
||||
|
||||
Among several other bug fixes, this release fixes a bunch of issues found
|
||||
by coverity (scan.coverity.com).
|
||||
|
||||
Bugs resolved since version 1.8.3
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* BB#110: fix algorithmic complexity DoS in hashmap
|
||||
* BB#106: fix failing CONNECT requests with IPv6 literal addresses
|
||||
* BB#116: fix invalid free for GET requests to IPv6 literal addresses
|
||||
* BB#63: support multiple Listen statements in configuration
|
||||
* BB#81: support listening on ipv4 and ipv6 wildcard if no Listen specified
|
||||
* BB#109: fix crash when writing to log file fails
|
||||
* BB#112: fix build with autoconf >= 2.69
|
||||
|
||||
Contributors:
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
Mukund Sivaraman, Michael Adam, Gaudenz Steinlin, Peter H. Froehlich
|
||||
|
||||
Version 1.8.3
|
||||
-------------
|
||||
|
||||
This release mostly fixes support for IPv6, and also some security
|
||||
bugs. Fixes to messages, etc. were also made.
|
||||
|
||||
Bugs resolved since version 1.8.2
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* BB#91: Fix upstream proxy support
|
||||
* BB#95: Fix FilterURLs with transparent proxy support
|
||||
* BB#90: Fix bug in ACL netmask generation
|
||||
|
||||
Contributors
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Daniel Egger, John Horne, Michael Adam, Mukund Sivaraman.
|
||||
|
||||
|
||||
Version 1.8.2
|
||||
-------------
|
||||
|
||||
* Minor formatting changes and typo fixes were made.
|
||||
|
||||
Bugs resolved since version 1.8.1
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* BB#69: INET6 not available when configured to Listen and Bind in v4,
|
||||
and vice versa
|
||||
* BB#74: tinyproxy unable to reopen log files after receiving HUP
|
||||
* BB#78: Warn if configuration results in an open proxy
|
||||
* BB#82: https access not working
|
||||
* BB#83: run_tests.sh relies on $USER
|
||||
* BB#84: Unaligned access error on ia64 and alpha
|
||||
* BB#87: Unable to listen on ports less than 1024 (regression in 1.8.1)
|
||||
* BB#88: Crashes when reloading configuration
|
||||
* BB#89: tinyproxy leaks memory over time
|
||||
|
||||
Contributors
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Dmitry Semyonov, John van der Kamp, Jordi Mallach, Michael Adam,
|
||||
Mukund Sivaraman.
|
||||
|
||||
|
||||
Version 1.8.1
|
||||
-------------
|
||||
|
||||
* Tinyproxy now drops `root` user privileges more quickly.
|
||||
* The log and pid files are now stored in a sub-directory in `/var/`.
|
||||
* A format string vulnerability was fixed.
|
||||
* Minor formatting changes and typo fixes were made.
|
||||
|
||||
Bugs fixed since version 1.8.0
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* BB#74: tinyproxy unable to reopen log files after receiving HUP
|
||||
* BB#79: Make the testsuite uninteractive
|
||||
* BB#80: Handle errors in testsuite
|
||||
* BB#81: Listen directive doesn't work as expected
|
||||
* BB#72: upstream support is not reported with tinyproxy -h
|
||||
* BB#73: generated tinyproxy.conf has the wrong location for the html
|
||||
file installation
|
||||
|
||||
Contributors
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Michael Adam, Mukund Sivaraman.
|
||||
|
||||
|
||||
Version 1.8.0
|
||||
-------------
|
||||
|
||||
@ -39,6 +135,7 @@ Contributors
|
||||
|
||||
David Shanks, Mathew Mrosko, Michael Adam, Mukund Sivaraman.
|
||||
|
||||
|
||||
Version 1.7.1
|
||||
-------------
|
||||
|
||||
@ -64,6 +161,7 @@ Contributors
|
||||
Andrew Stribblehill, Jeremy Hinegardner, Matthew Dempsky, Michael Adam,
|
||||
Mukund Sivaraman, Robert James Kaes.
|
||||
|
||||
|
||||
Version 1.7.0
|
||||
-------------
|
||||
|
||||
|
16
README
16
README
@ -15,7 +15,7 @@ administrator.
|
||||
|
||||
For more info, please visit:
|
||||
|
||||
https://www.banu.com/tinyproxy/
|
||||
https://banu.com/tinyproxy/
|
||||
|
||||
|
||||
Installation
|
||||
@ -44,7 +44,7 @@ include:
|
||||
domains and URLs.
|
||||
--enable-upstream Enable support for proxying connections
|
||||
through another proxy server.
|
||||
--enable-transparent-proxy
|
||||
--enable-transparent
|
||||
Allow Tinyproxy to be used as a
|
||||
transparent proxy daemon
|
||||
--enable-static Compile a static version of Tinyproxy
|
||||
@ -58,14 +58,14 @@ Support
|
||||
If you are having problems with Tinyproxy, please submit a bug report
|
||||
using Tinyproxy as the product at:
|
||||
|
||||
https://www.banu.com/bugzilla/
|
||||
https://banu.com/bugzilla/
|
||||
|
||||
You may also wish to subscribe to the Tinyproxy mailing lists. To do so
|
||||
please visit:
|
||||
|
||||
https://www.banu.com/mailman/listinfo/tinyproxy-announce-list
|
||||
https://www.banu.com/mailman/listinfo/tinyproxy-users-list
|
||||
https://www.banu.com/mailman/listinfo/tinyproxy-developers-list
|
||||
https://banu.com/mailman/listinfo/tinyproxy-announce-list
|
||||
https://banu.com/mailman/listinfo/tinyproxy-users-list
|
||||
https://banu.com/mailman/listinfo/tinyproxy-developers-list
|
||||
|
||||
for more information on how to subscribe and post messages to the lists.
|
||||
|
||||
@ -79,11 +79,11 @@ source, please send a patch (preferably as a unified diff. i.e. `diff
|
||||
repository to tinyproxy-developers-list. Please include a description
|
||||
of what your patch does.
|
||||
|
||||
Tinyproxy's git repository is git://www.banu.com/tinyproxy.git. The
|
||||
Tinyproxy's git repository is git://banu.com/tinyproxy.git. The
|
||||
following command creates a local copy:
|
||||
|
||||
----
|
||||
git clone git://www.banu.com/tinyproxy.git
|
||||
git clone git://banu.com/tinyproxy.git
|
||||
----
|
||||
|
||||
The easiest and preferred way to create a patch for submission is to
|
||||
|
8
TODO
8
TODO
@ -38,16 +38,10 @@ against the current tree and I'll integrate it if possible.
|
||||
* 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. [Suggested: Tyrone Tranmer]
|
||||
HTTP/1.1 RFC for more information.
|
||||
|
||||
==> https://www.banu.com/bugzilla/show_bug.cgi?id=13
|
||||
|
||||
* Fix paths inside etc/tinyproxy.conf
|
||||
|
||||
* Finish manpages
|
||||
|
||||
* Move defaults handling to conf.c
|
||||
|
||||
* Remove common.h and fix order of headers
|
||||
|
||||
* Remove memory debugging functions (Valgrind is good enough)
|
||||
|
18
configure.ac
18
configure.ac
@ -5,13 +5,13 @@ AC_PREREQ(2.54)
|
||||
|
||||
m4_define([tinyproxy_major_version], [1])
|
||||
m4_define([tinyproxy_minor_version], [8])
|
||||
m4_define([tinyproxy_micro_version], [0])
|
||||
m4_define([tinyproxy_micro_version], [4])
|
||||
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.8.0])
|
||||
# m4_define([tinyproxy_version], [1.8.2])
|
||||
|
||||
m4_define([tinyproxy_unstable],
|
||||
m4_if(m4_eval(tinyproxy_minor_version % 2), [1], [yes], [no]))
|
||||
@ -19,12 +19,12 @@ m4_define([tinyproxy_stable],
|
||||
m4_if(m4_eval(tinyproxy_minor_version % 2), [0], [yes], [no]))
|
||||
|
||||
AC_INIT([Tinyproxy], [tinyproxy_version],
|
||||
[https://www.banu.com/bugzilla/enter_bug.cgi?product=tinyproxy],
|
||||
[https://banu.com/tinyproxy/],
|
||||
[tinyproxy])
|
||||
|
||||
AC_CANONICAL_TARGET
|
||||
AM_INIT_AUTOMAKE([dist-bzip2])
|
||||
AM_CONFIG_HEADER(config.h)
|
||||
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])])
|
||||
@ -202,8 +202,10 @@ AC_FUNC_REALLOC
|
||||
|
||||
AC_CHECK_FUNCS([gethostname inet_ntoa memchr memset select socket strcasecmp \
|
||||
strchr strdup strerror strncasecmp strpbrk strstr strtol])
|
||||
AC_CHECK_FUNCS([isascii memcpy setrlimit ftruncate regcomp regexec])
|
||||
AC_CHECK_FUNCS([strlcpy strlcat])
|
||||
AC_CHECK_FUNCS([isascii memcpy memmove setrlimit ftruncate regcomp regexec])
|
||||
AC_CHECK_FUNCS([strlcpy strlcat setgroups])
|
||||
|
||||
AC_CHECK_FUNCS([time rand srand])
|
||||
|
||||
|
||||
dnl Enable extra warnings
|
||||
@ -222,7 +224,7 @@ if test x"$debug_enabled" != x"yes" ; then
|
||||
CFLAGS="-DNDEBUG $CFLAGS"
|
||||
fi
|
||||
|
||||
LDFLAGS="-Wl,-z,defs"
|
||||
LDFLAGS="-Wl,-z,defs $LDFLAGS"
|
||||
|
||||
dnl
|
||||
dnl Make sure we can actually handle the "--with-*" and "--enable-*" stuff.
|
||||
|
@ -147,7 +147,7 @@ The possible keywords and their descriptions are as follows:
|
||||
*No Upstream*::
|
||||
|
||||
This option allows you to set up a set of rules for deciding
|
||||
whether an upstream a proxy server is to be used, based on the
|
||||
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
|
||||
@ -210,9 +210,9 @@ The possible keywords and their descriptions are as follows:
|
||||
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 `Access` or `Deny` lines, then all clients are
|
||||
If there are no `Allow` or `Deny` lines, then all clients are
|
||||
allowed. Otherwise, the default action is to deny access.
|
||||
The argument to `Access` or `Deny` can be a single IP address
|
||||
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
|
||||
@ -343,7 +343,7 @@ BUGS
|
||||
----
|
||||
|
||||
To report bugs in Tinyproxy, please visit
|
||||
<https://www.banu.com/tinyproxy/support/[https://www.banu.com/tinyproxy/support/]>.
|
||||
<https://www.banu.com/tinyproxy/[https://www.banu.com/tinyproxy/]>.
|
||||
|
||||
|
||||
SEE ALSO
|
||||
|
@ -130,13 +130,13 @@ configuration variable `StatFile`.
|
||||
FILES
|
||||
-----
|
||||
|
||||
`/etc/tinyproxy/tinyproxy.conf`, `/var/run/tinyproxy.pid`, `/var/log/tinyproxy.log`
|
||||
`/etc/tinyproxy/tinyproxy.conf`, `/var/run/tinyproxy/tinyproxy.pid`, `/var/log/tinyproxy/tinyproxy.log`
|
||||
|
||||
BUGS
|
||||
----
|
||||
|
||||
To report bugs in Tinyproxy, please visit
|
||||
<https://www.banu.com/tinyproxy/support/[https://www.banu.com/tinyproxy/support/]>.
|
||||
<https://www.banu.com/tinyproxy/[https://www.banu.com/tinyproxy/]>.
|
||||
|
||||
|
||||
SEE ALSO
|
||||
|
@ -56,18 +56,18 @@ Timeout 600
|
||||
# /usr/share/tinyproxy
|
||||
# /etc/tinyproxy
|
||||
#
|
||||
#ErrorFile 404 "@datadir@/404.html"
|
||||
#ErrorFile 400 "@datadir@/400.html"
|
||||
#ErrorFile 503 "@datadir@/503.html"
|
||||
#ErrorFile 403 "@datadir@/403.html"
|
||||
#ErrorFile 408 "@datadir@/408.html"
|
||||
#ErrorFile 404 "@pkgdatadir@/404.html"
|
||||
#ErrorFile 400 "@pkgdatadir@/400.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 "@datadir@/default.html"
|
||||
DefaultErrorFile "@pkgdatadir@/default.html"
|
||||
|
||||
#
|
||||
# StatHost: This configures the host name or IP address that is treated
|
||||
@ -84,15 +84,15 @@ DefaultErrorFile "@datadir@/default.html"
|
||||
# for the stathost. If this file doesn't exist a basic page is
|
||||
# hardcoded in tinyproxy.
|
||||
#
|
||||
StatFile "@datadir@/stats.html"
|
||||
StatFile "@pkgdatadir@/stats.html"
|
||||
|
||||
#
|
||||
# Logfile: Allows you to specify the location where information should
|
||||
# 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.
|
||||
#
|
||||
Logfile "@localstatedir@/log/tinyproxy.log"
|
||||
#LogFile "@localstatedir@/log/tinyproxy/tinyproxy.log"
|
||||
|
||||
#
|
||||
# Syslog: Tell tinyproxy to use syslog instead of a logfile. This
|
||||
@ -122,7 +122,7 @@ LogLevel Info
|
||||
# PidFile: Write the PID of the main tinyproxy thread to this file so it
|
||||
# can be used for signalling purposes.
|
||||
#
|
||||
PidFile "@localstatedir@/run/tinyproxy.pid"
|
||||
#PidFile "@localstatedir@/run/tinyproxy/tinyproxy.pid"
|
||||
|
||||
#
|
||||
# XTinyproxy: Tell Tinyproxy to include the X-Tinyproxy header, which
|
||||
|
25
src/acl.c
25
src/acl.c
@ -66,8 +66,8 @@ struct acl_s {
|
||||
*
|
||||
*/
|
||||
static int
|
||||
fill_netmask_array (char *bitmask_string, unsigned char array[],
|
||||
size_t len)
|
||||
fill_netmask_array (char *bitmask_string, int v6,
|
||||
unsigned char array[], size_t len)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned long int mask;
|
||||
@ -81,7 +81,14 @@ fill_netmask_array (char *bitmask_string, unsigned char array[],
|
||||
|| (errno != 0 && mask == 0) || (endptr == bitmask_string))
|
||||
return -1;
|
||||
|
||||
/* valid range for a bit mask */
|
||||
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 * len))
|
||||
return -1;
|
||||
|
||||
@ -160,6 +167,9 @@ int insert_acl (char *location, acl_access_t access_type, vector_t *access_list)
|
||||
*/
|
||||
p = strchr (location, '/');
|
||||
if (p != NULL) {
|
||||
char dst[sizeof(struct in6_addr)];
|
||||
int v6;
|
||||
|
||||
/*
|
||||
* We have a slash, so it's intended to be an
|
||||
* IP address with mask
|
||||
@ -171,8 +181,15 @@ int insert_acl (char *location, acl_access_t access_type, vector_t *access_list)
|
||||
acl.type = ACL_NUMERIC;
|
||||
memcpy (acl.address.ip.octet, ip_dst, IPV6_LEN);
|
||||
|
||||
/* 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
|
||||
(p + 1, &(acl.address.ip.mask[0]), IPV6_LEN)
|
||||
(p + 1, v6, &(acl.address.ip.mask[0]), IPV6_LEN)
|
||||
< 0)
|
||||
return -1;
|
||||
} else {
|
||||
|
@ -236,8 +236,7 @@ ssize_t read_buffer (int fd, struct buffer_s * buffptr)
|
||||
"readbuff: add_to_buffer() error.");
|
||||
bytesin = -1;
|
||||
}
|
||||
} else {
|
||||
if (bytesin == 0) {
|
||||
} else if (bytesin == 0) {
|
||||
/* connection was closed by client */
|
||||
bytesin = -1;
|
||||
} else {
|
||||
@ -254,13 +253,12 @@ ssize_t read_buffer (int fd, struct buffer_s * buffptr)
|
||||
break;
|
||||
default:
|
||||
log_message (LOG_ERR,
|
||||
"readbuff: recv() error \"%s\" on file descriptor %d",
|
||||
strerror (errno), fd);
|
||||
"read_buffer: read() failed on fd %d: %s",
|
||||
fd, strerror(errno));
|
||||
bytesin = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
safefree (buffer);
|
||||
return bytesin;
|
||||
|
141
src/child.c
141
src/child.c
@ -32,8 +32,7 @@
|
||||
#include "utils.h"
|
||||
#include "conf.h"
|
||||
|
||||
static int listenfd;
|
||||
static socklen_t addrlen;
|
||||
static vector_t listen_fds;
|
||||
|
||||
/*
|
||||
* Stores the internal data needed for each child (connection)
|
||||
@ -187,8 +186,13 @@ static void child_main (struct child_s *ptr)
|
||||
int connfd;
|
||||
struct sockaddr *cliaddr;
|
||||
socklen_t clilen;
|
||||
fd_set rfds;
|
||||
int maxfd = 0;
|
||||
ssize_t i;
|
||||
int ret;
|
||||
|
||||
cliaddr = (struct sockaddr *) safemalloc (addrlen);
|
||||
cliaddr = (struct sockaddr *)
|
||||
safemalloc (sizeof(struct sockaddr_storage));
|
||||
if (!cliaddr) {
|
||||
log_message (LOG_CRIT,
|
||||
"Could not allocate memory for child address.");
|
||||
@ -196,11 +200,79 @@ static void child_main (struct child_s *ptr)
|
||||
}
|
||||
|
||||
ptr->connects = 0;
|
||||
srand(time(NULL));
|
||||
|
||||
/*
|
||||
* We have to wait for connections on multiple fds,
|
||||
* so use select.
|
||||
*/
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
|
||||
for (i = 0; i < vector_length(listen_fds); i++) {
|
||||
int *fd = (int *) vector_getentry(listen_fds, i, NULL);
|
||||
|
||||
ret = socket_nonblocking(*fd);
|
||||
if (ret != 0) {
|
||||
log_message(LOG_ERR, "Failed to set the listening "
|
||||
"socket %d to non-blocking: %s",
|
||||
fd, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
FD_SET(*fd, &rfds);
|
||||
maxfd = max(maxfd, *fd);
|
||||
}
|
||||
|
||||
while (!config.quit) {
|
||||
int listenfd = -1;
|
||||
|
||||
ptr->status = T_WAITING;
|
||||
|
||||
clilen = addrlen;
|
||||
clilen = sizeof(struct sockaddr_storage);
|
||||
|
||||
ret = select(maxfd + 1, &rfds, NULL, NULL, NULL);
|
||||
if (ret == -1) {
|
||||
log_message (LOG_ERR, "error calling select: %s",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
} else if (ret == 0) {
|
||||
log_message (LOG_WARNING, "Strange: select returned 0 "
|
||||
"but we did not specify a timeout...");
|
||||
continue;
|
||||
}
|
||||
|
||||
for (i = 0; i < vector_length(listen_fds); i++) {
|
||||
int *fd = (int *) vector_getentry(listen_fds, i, NULL);
|
||||
|
||||
if (FD_ISSET(*fd, &rfds)) {
|
||||
/*
|
||||
* only accept the connection on the first
|
||||
* fd that we find readable. - fair?
|
||||
*/
|
||||
listenfd = *fd;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (listenfd == -1) {
|
||||
log_message(LOG_WARNING, "Strange: None of our listen "
|
||||
"fds was readable after select");
|
||||
continue;
|
||||
}
|
||||
|
||||
ret = socket_blocking(listenfd);
|
||||
if (ret != 0) {
|
||||
log_message(LOG_ERR, "Failed to set listening "
|
||||
"socket %d to blocking for accept: %s",
|
||||
listenfd, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* We have a socket that is readable.
|
||||
* Continue handling this connection.
|
||||
*/
|
||||
|
||||
connfd = accept (listenfd, cliaddr, &clilen);
|
||||
|
||||
@ -464,13 +536,66 @@ void child_kill_children (int sig)
|
||||
}
|
||||
}
|
||||
|
||||
int child_listening_sock (uint16_t port)
|
||||
|
||||
/**
|
||||
* Listen on the various configured interfaces
|
||||
*/
|
||||
int child_listening_sockets(vector_t listen_addrs, uint16_t port)
|
||||
{
|
||||
listenfd = listen_sock (port, &addrlen);
|
||||
return listenfd;
|
||||
int ret;
|
||||
ssize_t i;
|
||||
|
||||
assert (port > 0);
|
||||
|
||||
if (listen_fds == NULL) {
|
||||
listen_fds = vector_create();
|
||||
if (listen_fds == NULL) {
|
||||
log_message (LOG_ERR, "Could not create the list "
|
||||
"of listening fds");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((listen_addrs == NULL) ||
|
||||
(vector_length(listen_addrs) == 0))
|
||||
{
|
||||
/*
|
||||
* no Listen directive:
|
||||
* listen on the wildcard address(es)
|
||||
*/
|
||||
ret = listen_sock(NULL, port, listen_fds);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < vector_length(listen_addrs); i++) {
|
||||
const char *addr;
|
||||
|
||||
addr = (char *)vector_getentry(listen_addrs, i, NULL);
|
||||
if (addr == NULL) {
|
||||
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)
|
||||
{
|
||||
close (listenfd);
|
||||
ssize_t i;
|
||||
|
||||
for (i = 0; i < vector_length(listen_fds); i++) {
|
||||
int *fd = (int *) vector_getentry(listen_fds, i, NULL);
|
||||
close (*fd);
|
||||
}
|
||||
|
||||
vector_delete(listen_fds);
|
||||
|
||||
listen_fds = NULL;
|
||||
}
|
||||
|
@ -21,6 +21,8 @@
|
||||
#ifndef TINYPROXY_CHILD_H
|
||||
#define TINYPROXY_CHILD_H
|
||||
|
||||
#include "vector.h"
|
||||
|
||||
typedef enum {
|
||||
CHILD_MAXCLIENTS,
|
||||
CHILD_MAXSPARESERVERS,
|
||||
@ -30,7 +32,7 @@ typedef enum {
|
||||
} child_config_t;
|
||||
|
||||
extern short int child_pool_create (void);
|
||||
extern int child_listening_sock (uint16_t port);
|
||||
extern int child_listening_sockets (vector_t listen_addrs, uint16_t port);
|
||||
extern void child_close_sock (void);
|
||||
extern void child_main_loop (void);
|
||||
extern void child_kill_children (int sig);
|
||||
|
112
src/conf.c
112
src/conf.c
@ -163,6 +163,8 @@ static HANDLE_FUNC (handle_upstream);
|
||||
static HANDLE_FUNC (handle_upstream_no);
|
||||
#endif
|
||||
|
||||
static void config_free_regex (void);
|
||||
|
||||
/*
|
||||
* This macro can be used to make standard directives in the form:
|
||||
* directive arguments [arguments ...]
|
||||
@ -286,7 +288,7 @@ static void free_config (struct config_s *conf)
|
||||
safefree (conf->stathost);
|
||||
safefree (conf->user);
|
||||
safefree (conf->group);
|
||||
safefree (conf->ipAddr);
|
||||
vector_delete(conf->listen_addrs);
|
||||
#ifdef FILTER_ENABLE
|
||||
safefree (conf->filter);
|
||||
#endif /* FILTER_ENABLE */
|
||||
@ -317,7 +319,8 @@ static void free_config (struct config_s *conf)
|
||||
*
|
||||
* Returns 0 on success; negative upon failure.
|
||||
*/
|
||||
static int config_compile (void)
|
||||
int
|
||||
config_compile_regex (void)
|
||||
{
|
||||
unsigned int i, r;
|
||||
|
||||
@ -335,9 +338,30 @@ static int config_compile (void)
|
||||
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
|
||||
@ -397,7 +421,7 @@ static int load_config_file (const char *config_fname, struct config_s *conf)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (config_compile () || config_parse (conf, config_file)) {
|
||||
if (config_parse (conf, config_file)) {
|
||||
fprintf (stderr, "Unable to parse config file. "
|
||||
"Not starting.\n");
|
||||
goto done;
|
||||
@ -441,8 +465,18 @@ static void initialize_with_defaults (struct config_s *conf,
|
||||
conf->group = safestrdup (defaults->group);
|
||||
}
|
||||
|
||||
if (defaults->ipAddr) {
|
||||
conf->ipAddr = safestrdup (defaults->ipAddr);
|
||||
if (defaults->listen_addrs) {
|
||||
ssize_t i;
|
||||
|
||||
conf->listen_addrs = vector_create();
|
||||
for (i=0; i < vector_length(defaults->listen_addrs); i++) {
|
||||
char *addr;
|
||||
size_t size;
|
||||
addr = (char *)vector_getentry(defaults->listen_addrs,
|
||||
i, &size);
|
||||
vector_append(conf->listen_addrs, addr, size);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#ifdef FILTER_ENABLE
|
||||
@ -617,8 +651,8 @@ set_bool_arg (unsigned int *var, const char *line, regmatch_t * match)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long int
|
||||
get_int_arg (const char *line, regmatch_t * match)
|
||||
static unsigned long
|
||||
get_long_arg (const char *line, regmatch_t * match)
|
||||
{
|
||||
assert (line);
|
||||
assert (match && match->rm_so != -1);
|
||||
@ -627,13 +661,13 @@ get_int_arg (const char *line, regmatch_t * match)
|
||||
}
|
||||
|
||||
static int
|
||||
set_int_arg (unsigned long int *var, const char *line, regmatch_t * match)
|
||||
set_int_arg (unsigned int *var, const char *line, regmatch_t * match)
|
||||
{
|
||||
assert (var);
|
||||
assert (line);
|
||||
assert (match);
|
||||
|
||||
*var = get_int_arg (line, match);
|
||||
*var = (unsigned int) get_long_arg (line, match);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -755,49 +789,58 @@ static HANDLE_FUNC (handle_bindsame)
|
||||
|
||||
static HANDLE_FUNC (handle_port)
|
||||
{
|
||||
return set_int_arg ((unsigned long int *) &conf->port, line, &match[2]);
|
||||
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)
|
||||
{
|
||||
child_configure (CHILD_MAXCLIENTS, get_int_arg (line, &match[2]));
|
||||
child_configure (CHILD_MAXCLIENTS, get_long_arg (line, &match[2]));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static HANDLE_FUNC (handle_maxspareservers)
|
||||
{
|
||||
child_configure (CHILD_MAXSPARESERVERS, get_int_arg (line, &match[2]));
|
||||
child_configure (CHILD_MAXSPARESERVERS,
|
||||
get_long_arg (line, &match[2]));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static HANDLE_FUNC (handle_minspareservers)
|
||||
{
|
||||
child_configure (CHILD_MINSPARESERVERS, get_int_arg (line, &match[2]));
|
||||
child_configure (CHILD_MINSPARESERVERS,
|
||||
get_long_arg (line, &match[2]));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static HANDLE_FUNC (handle_startservers)
|
||||
{
|
||||
child_configure (CHILD_STARTSERVERS, get_int_arg (line, &match[2]));
|
||||
child_configure (CHILD_STARTSERVERS, get_long_arg (line, &match[2]));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static HANDLE_FUNC (handle_maxrequestsperchild)
|
||||
{
|
||||
child_configure (CHILD_MAXREQUESTSPERCHILD,
|
||||
get_int_arg (line, &match[2]));
|
||||
get_long_arg (line, &match[2]));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static HANDLE_FUNC (handle_timeout)
|
||||
{
|
||||
return set_int_arg ((unsigned long int *) &conf->idletimeout, line,
|
||||
&match[2]);
|
||||
return set_int_arg (&conf->idletimeout, line, &match[2]);
|
||||
}
|
||||
|
||||
static HANDLE_FUNC (handle_connectport)
|
||||
{
|
||||
add_connect_port_allowed (get_int_arg (line, &match[2]),
|
||||
add_connect_port_allowed (get_long_arg (line, &match[2]),
|
||||
&conf->connect_ports);
|
||||
return 0;
|
||||
}
|
||||
@ -849,11 +892,27 @@ static HANDLE_FUNC (handle_bind)
|
||||
|
||||
static HANDLE_FUNC (handle_listen)
|
||||
{
|
||||
int r = set_string_arg (&conf->ipAddr, line, &match[2]);
|
||||
char *arg = get_string_arg (line, &match[2]);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
log_message (LOG_INFO, "Listening on IP %s", conf->ipAddr);
|
||||
if (arg == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (conf->listen_addrs == NULL) {
|
||||
conf->listen_addrs = vector_create();
|
||||
if (conf->listen_addrs == NULL) {
|
||||
log_message(LOG_WARNING, "Could not create a list "
|
||||
"of listen addresses.");
|
||||
safefree(arg);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
vector_append (conf->listen_addrs, arg, strlen(arg) + 1);
|
||||
|
||||
log_message(LOG_INFO, "Added address [%s] to listen addresses.", arg);
|
||||
|
||||
safefree (arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -866,7 +925,7 @@ static HANDLE_FUNC (handle_errorfile)
|
||||
* present. This is why the "string" is located at
|
||||
* match[4] (rather than the more intuitive match[3].
|
||||
*/
|
||||
unsigned long int err = get_int_arg (line, &match[2]);
|
||||
unsigned long int err = get_long_arg (line, &match[2]);
|
||||
char *page = get_string_arg (line, &match[4]);
|
||||
|
||||
add_new_errorpage (page, err);
|
||||
@ -900,6 +959,7 @@ static HANDLE_FUNC (handle_addheader)
|
||||
|
||||
/*
|
||||
* Log level's strings.
|
||||
|
||||
*/
|
||||
struct log_levels_s {
|
||||
const char *string;
|
||||
@ -1019,10 +1079,10 @@ static HANDLE_FUNC (handle_upstream)
|
||||
ip = get_string_arg (line, &match[2]);
|
||||
if (!ip)
|
||||
return -1;
|
||||
port = (int) get_int_arg (line, &match[7]);
|
||||
port = (int) get_long_arg (line, &match[7]);
|
||||
|
||||
if (match[9].rm_so != -1) {
|
||||
domain = get_string_arg (line, &match[9]);
|
||||
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);
|
||||
|
@ -40,13 +40,13 @@ struct config_s {
|
||||
char *logf_name;
|
||||
char *config_file;
|
||||
unsigned int syslog; /* boolean */
|
||||
int port;
|
||||
unsigned int port;
|
||||
char *stathost;
|
||||
unsigned int godaemon; /* boolean */
|
||||
unsigned int quit; /* boolean */
|
||||
char *user;
|
||||
char *group;
|
||||
char *ipAddr;
|
||||
vector_t listen_addrs;
|
||||
#ifdef FILTER_ENABLE
|
||||
char *filter;
|
||||
unsigned int filter_url; /* boolean */
|
||||
@ -115,4 +115,6 @@ struct config_s {
|
||||
extern int reload_config_file (const char *config_fname, struct config_s *conf,
|
||||
struct config_s *defaults);
|
||||
|
||||
int config_compile_regex (void);
|
||||
|
||||
#endif
|
||||
|
@ -50,6 +50,7 @@ struct hashbucket_s {
|
||||
};
|
||||
|
||||
struct hashmap_s {
|
||||
uint32_t seed;
|
||||
unsigned int size;
|
||||
hashmap_iter end_iterator;
|
||||
|
||||
@ -63,9 +64,12 @@ struct hashmap_s {
|
||||
* The contents of the key are converted to lowercase, so this function
|
||||
* is not case-sensitive.
|
||||
*
|
||||
* This is Dan Bernstein's hash function as described, for example, here:
|
||||
* http://www.cse.yorku.ca/~oz/hash.html
|
||||
*
|
||||
* If any of the arguments are invalid a negative number is returned.
|
||||
*/
|
||||
static int hashfunc (const char *key, unsigned int size)
|
||||
static int hashfunc (const char *key, unsigned int size, uint32_t seed)
|
||||
{
|
||||
uint32_t hash;
|
||||
|
||||
@ -74,12 +78,8 @@ static int hashfunc (const char *key, unsigned int size)
|
||||
if (size == 0)
|
||||
return -ERANGE;
|
||||
|
||||
for (hash = tolower (*key++); *key != '\0'; key++) {
|
||||
uint32_t bit = (hash & 1) ? (1 << (sizeof (uint32_t) - 1)) : 0;
|
||||
|
||||
hash >>= 1;
|
||||
|
||||
hash += tolower (*key) + bit;
|
||||
for (hash = seed; *key != '\0'; key++) {
|
||||
hash = ((hash << 5) + hash) ^ tolower (*key);
|
||||
}
|
||||
|
||||
/* Keep the hash within the table limits */
|
||||
@ -104,6 +104,7 @@ hashmap_t hashmap_create (unsigned int nbuckets)
|
||||
if (!ptr)
|
||||
return NULL;
|
||||
|
||||
ptr->seed = (uint32_t)rand();
|
||||
ptr->size = nbuckets;
|
||||
ptr->buckets = (struct hashbucket_s *) safecalloc (nbuckets,
|
||||
sizeof (struct
|
||||
@ -201,7 +202,7 @@ hashmap_insert (hashmap_t map, const char *key, const void *data, size_t len)
|
||||
if (!data || len < 1)
|
||||
return -ERANGE;
|
||||
|
||||
hash = hashfunc (key, map->size);
|
||||
hash = hashfunc (key, map->size, map->seed);
|
||||
if (hash < 0)
|
||||
return hash;
|
||||
|
||||
@ -382,7 +383,7 @@ ssize_t hashmap_search (hashmap_t map, const char *key)
|
||||
if (map == NULL || key == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
hash = hashfunc (key, map->size);
|
||||
hash = hashfunc (key, map->size, map->seed);
|
||||
if (hash < 0)
|
||||
return hash;
|
||||
|
||||
@ -416,7 +417,7 @@ ssize_t hashmap_entry_by_key (hashmap_t map, const char *key, void **data)
|
||||
if (!map || !key || !data)
|
||||
return -EINVAL;
|
||||
|
||||
hash = hashfunc (key, map->size);
|
||||
hash = hashfunc (key, map->size, map->seed);
|
||||
if (hash < 0)
|
||||
return hash;
|
||||
|
||||
@ -451,7 +452,7 @@ ssize_t hashmap_remove (hashmap_t map, const char *key)
|
||||
if (map == NULL || key == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
hash = hashfunc (key, map->size);
|
||||
hash = hashfunc (key, map->size, map->seed);
|
||||
if (hash < 0)
|
||||
return hash;
|
||||
|
||||
|
@ -280,7 +280,7 @@ int add_standard_vars (struct conn_s *connptr)
|
||||
add_error_variable (connptr, "date", timebuf);
|
||||
|
||||
add_error_variable (connptr, "website",
|
||||
"https://www.banu.com/tinyproxy/");
|
||||
"https://banu.com/tinyproxy/");
|
||||
add_error_variable (connptr, "version", VERSION);
|
||||
add_error_variable (connptr, "package", PACKAGE);
|
||||
|
||||
|
20
src/log.c
20
src/log.c
@ -188,8 +188,13 @@ void log_message (int level, const char *fmt, ...)
|
||||
|
||||
ret = write (log_file_fd, str, strlen (str));
|
||||
if (ret == -1) {
|
||||
log_message (LOG_WARNING,
|
||||
"Could not write to log file");
|
||||
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");
|
||||
}
|
||||
|
||||
fsync (log_file_fd);
|
||||
@ -206,11 +211,12 @@ 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; (ssize_t) i != vector_length (log_message_storage); ++i) {
|
||||
@ -230,7 +236,7 @@ void send_stored_logs (void)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
log_message (level, ptr);
|
||||
log_message (level, "%s", ptr);
|
||||
}
|
||||
|
||||
vector_delete (log_message_storage);
|
||||
@ -257,10 +263,10 @@ int setup_logging (void)
|
||||
config.syslog = TRUE;
|
||||
|
||||
log_message (LOG_CRIT, "ERROR: Could not create log "
|
||||
"file %s: %s.\n",
|
||||
"file %s: %s.",
|
||||
config.logf_name, strerror (errno));
|
||||
log_message (LOG_CRIT,
|
||||
"Falling back to syslog logging\n");
|
||||
"Falling back to syslog logging.");
|
||||
}
|
||||
}
|
||||
|
||||
|
62
src/main.c
62
src/main.c
@ -162,12 +162,17 @@ display_usage (void)
|
||||
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 bug reporting instructions, please see:\n"
|
||||
"<https://www.banu.com/tinyproxy/support/>.\n");
|
||||
"<https://banu.com/tinyproxy/>.\n");
|
||||
}
|
||||
|
||||
static int
|
||||
@ -272,6 +277,16 @@ change_user (const char *program)
|
||||
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);
|
||||
}
|
||||
@ -321,8 +336,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.log");
|
||||
conf->pidpath = safestrdup (LOCALSTATEDIR "/run/tinyproxy.pid");
|
||||
conf->logf_name = safestrdup (LOCALSTATEDIR "/log/tinyproxy/tinyproxy.log");
|
||||
conf->pidpath = safestrdup (LOCALSTATEDIR "/run/tinyproxy/tinyproxy.pid");
|
||||
}
|
||||
|
||||
/**
|
||||
@ -350,20 +365,23 @@ done:
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* 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_INFO, "Initializing " PACKAGE " ...");
|
||||
|
||||
if (config_compile_regex()) {
|
||||
exit (EX_SOFTWARE);
|
||||
}
|
||||
|
||||
initialize_config_defaults (&config_defaults);
|
||||
process_cmdline (argc, argv, &config_defaults);
|
||||
|
||||
log_message (LOG_INFO, "Initializing " PACKAGE " ...");
|
||||
|
||||
ret = reload_config ();
|
||||
if (ret != 0) {
|
||||
if (reload_config_file (config_defaults.config_file,
|
||||
&config,
|
||||
&config_defaults)) {
|
||||
exit (EX_SOFTWARE);
|
||||
}
|
||||
|
||||
@ -381,14 +399,6 @@ main (int argc, char **argv)
|
||||
if (config.godaemon == TRUE)
|
||||
makedaemon ();
|
||||
|
||||
if (config.pidpath) {
|
||||
if (pidfile_create (config.pidpath) < 0) {
|
||||
fprintf (stderr, "%s: Could not create PID file.\n",
|
||||
argv[0]);
|
||||
exit (EX_OSERR);
|
||||
}
|
||||
}
|
||||
|
||||
if (set_signal_handler (SIGPIPE, SIG_IGN) == SIG_ERR) {
|
||||
fprintf (stderr, "%s: Could not set the \"SIGPIPE\" signal.\n",
|
||||
argv[0]);
|
||||
@ -401,8 +411,8 @@ main (int argc, char **argv)
|
||||
#endif /* FILTER_ENABLE */
|
||||
|
||||
/* Start listening on the selected port. */
|
||||
if (child_listening_sock (config.port) < 0) {
|
||||
fprintf (stderr, "%s: Could not create listening socket.\n",
|
||||
if (child_listening_sockets(config.listen_addrs, config.port) < 0) {
|
||||
fprintf (stderr, "%s: Could not create listening sockets.\n",
|
||||
argv[0]);
|
||||
exit (EX_OSERR);
|
||||
}
|
||||
@ -414,6 +424,20 @@ main (int argc, char **argv)
|
||||
log_message (LOG_WARNING,
|
||||
"Not running as root, so not changing UID/GID.");
|
||||
|
||||
/* Create log file after we drop privileges */
|
||||
if (setup_logging ()) {
|
||||
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",
|
||||
|
@ -191,7 +191,11 @@ ssize_t readline (int fd, char **whole_buffer)
|
||||
goto CLEANUP;
|
||||
}
|
||||
|
||||
recv (fd, line_ptr->data, diff, 0);
|
||||
ret = recv (fd, line_ptr->data, diff, 0);
|
||||
if (ret == -1) {
|
||||
goto CLEANUP;
|
||||
}
|
||||
|
||||
line_ptr->len = diff;
|
||||
|
||||
if (ptr) {
|
||||
|
160
src/reqs.c
160
src/reqs.c
@ -167,12 +167,18 @@ static void strip_username_password (char *host)
|
||||
static int strip_return_port (char *host)
|
||||
{
|
||||
char *ptr1;
|
||||
char *ptr2;
|
||||
int port;
|
||||
|
||||
ptr1 = strchr (host, ':');
|
||||
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;
|
||||
@ -180,10 +186,14 @@ static int strip_return_port (char *host)
|
||||
}
|
||||
|
||||
/*
|
||||
* Pull the information out of the URL line. This will handle both HTTP
|
||||
* and FTP (proxied) URLs.
|
||||
* Pull the information out of the URL line.
|
||||
* This expects urls with the initial '<proto>://'
|
||||
* 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_http_url (const char *url, struct request_s *request)
|
||||
static int extract_url (const char *url, int default_port,
|
||||
struct request_s *request)
|
||||
{
|
||||
char *p;
|
||||
int len;
|
||||
@ -210,7 +220,17 @@ static int extract_http_url (const char *url, struct request_s *request)
|
||||
|
||||
/* Find a proper port in www.site.com:8001 URLs */
|
||||
port = strip_return_port (request->host);
|
||||
request->port = (port != 0) ? port : HTTP_PORT;
|
||||
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;
|
||||
|
||||
@ -223,31 +243,6 @@ ERROR_EXIT:
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract the URL from a SSL connection.
|
||||
*/
|
||||
static int extract_ssl_url (const char *url, struct request_s *request)
|
||||
{
|
||||
request->host = (char *) safemalloc (strlen (url) + 1);
|
||||
if (!request->host)
|
||||
return -1;
|
||||
|
||||
if (sscanf (url, "%[^:]:%hu", request->host, &request->port) == 2) ;
|
||||
else if (sscanf (url, "%s", request->host) == 1)
|
||||
request->port = HTTP_PORT_SSL;
|
||||
else {
|
||||
log_message (LOG_ERR, "extract_ssl_url: Can't parse URL.");
|
||||
|
||||
safefree (request->host);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Remove the username/password if they're present */
|
||||
strip_username_password (request->host);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a connection for HTTP connections.
|
||||
*/
|
||||
@ -255,6 +250,7 @@ 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)
|
||||
@ -262,6 +258,16 @@ establish_http_connection (struct conn_s *connptr, struct request_s *request)
|
||||
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.0\r\n"
|
||||
"Host: [%s]%s\r\n"
|
||||
"Connection: close\r\n",
|
||||
request->method, request->path,
|
||||
request->host, portbuff);
|
||||
} else {
|
||||
return write_message (connptr->server_fd,
|
||||
"%s %s HTTP/1.0\r\n"
|
||||
"Host: %s%s\r\n"
|
||||
@ -269,6 +275,7 @@ establish_http_connection (struct conn_s *connptr, struct request_s *request)
|
||||
request->method, request->path,
|
||||
request->host, portbuff);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* These two defines are for the SSL tunnelling.
|
||||
@ -350,15 +357,6 @@ BAD_REQUEST_ERROR:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!url) {
|
||||
log_message (LOG_ERR,
|
||||
"process_request: Null URL on file descriptor %d",
|
||||
connptr->client_fd);
|
||||
indicate_http_error (connptr, 400, "Bad Request",
|
||||
"detail", "Request has an empty URL",
|
||||
"url", url, NULL);
|
||||
goto fail;
|
||||
}
|
||||
#ifdef REVERSE_SUPPORT
|
||||
if (config.reversepath_list != NULL) {
|
||||
/*
|
||||
@ -385,14 +383,14 @@ BAD_REQUEST_ERROR:
|
||||
{
|
||||
char *skipped_type = strstr (url, "//") + 2;
|
||||
|
||||
if (extract_http_url (skipped_type, request) < 0) {
|
||||
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_ssl_url (url, request) < 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);
|
||||
@ -418,7 +416,7 @@ BAD_REQUEST_ERROR:
|
||||
} else {
|
||||
#ifdef TRANSPARENT_PROXY
|
||||
if (!do_transparent_proxy
|
||||
(connptr, hashofheaders, request, &config, url)) {
|
||||
(connptr, hashofheaders, request, &config, &url)) {
|
||||
goto fail;
|
||||
}
|
||||
#else
|
||||
@ -493,6 +491,7 @@ static int pull_client_data (struct conn_s *connptr, long int length)
|
||||
{
|
||||
char *buffer;
|
||||
ssize_t len;
|
||||
int ret;
|
||||
|
||||
buffer =
|
||||
(char *) safemalloc (min (MAXBUFFSIZE, (unsigned long int) length));
|
||||
@ -518,18 +517,30 @@ static int pull_client_data (struct conn_s *connptr, long int length)
|
||||
* return and line feed) at the end of a POST message. These
|
||||
* need to be eaten for tinyproxy to work correctly.
|
||||
*/
|
||||
socket_nonblocking (connptr->client_fd);
|
||||
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);
|
||||
socket_blocking (connptr->client_fd);
|
||||
|
||||
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 ret;
|
||||
ssize_t bytes_read;
|
||||
|
||||
ret = read (connptr->client_fd, buffer, 2);
|
||||
if (ret == -1) {
|
||||
bytes_read = read (connptr->client_fd, buffer, 2);
|
||||
if (bytes_read == -1) {
|
||||
log_message
|
||||
(LOG_WARNING,
|
||||
"Could not read two bytes from POST message");
|
||||
@ -585,6 +596,13 @@ add_header_to_connection (hashmap_t hashofheaders, char *header, size_t len)
|
||||
return hashmap_insert (hashofheaders, header, sep, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
@ -592,6 +610,7 @@ static int get_all_headers (int fd, hashmap_t hashofheaders)
|
||||
{
|
||||
char *line = NULL;
|
||||
char *header = NULL;
|
||||
int count;
|
||||
char *tmp;
|
||||
ssize_t linelen;
|
||||
ssize_t len = 0;
|
||||
@ -600,7 +619,7 @@ static int get_all_headers (int fd, hashmap_t hashofheaders)
|
||||
assert (fd >= 0);
|
||||
assert (hashofheaders != NULL);
|
||||
|
||||
for (;;) {
|
||||
for (count = 0; count < MAX_HEADERS; count++) {
|
||||
if ((linelen = readline (fd, &line)) <= 0) {
|
||||
safefree (header);
|
||||
safefree (line);
|
||||
@ -666,6 +685,14 @@ static int get_all_headers (int fd, hashmap_t hashofheaders)
|
||||
|
||||
safefree (line);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we get here, this means we reached MAX_HEADERS count.
|
||||
* Bail out with error.
|
||||
*/
|
||||
safefree (header);
|
||||
safefree (line);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -792,7 +819,7 @@ done:
|
||||
/*
|
||||
* Number of buckets to use internally in the hashmap.
|
||||
*/
|
||||
#define HEADER_BUCKETS 32
|
||||
#define HEADER_BUCKETS 256
|
||||
|
||||
/*
|
||||
* Here we loop through all the headers the client is sending. If we
|
||||
@ -1112,8 +1139,19 @@ static void relay_connection (struct conn_s *connptr)
|
||||
int maxfd = max (connptr->client_fd, connptr->server_fd) + 1;
|
||||
ssize_t bytes_received;
|
||||
|
||||
socket_nonblocking (connptr->client_fd);
|
||||
socket_nonblocking (connptr->server_fd);
|
||||
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));
|
||||
return;
|
||||
}
|
||||
|
||||
ret = socket_nonblocking (connptr->server_fd);
|
||||
if (ret != 0) {
|
||||
log_message(LOG_ERR, "Failed to set the server socket "
|
||||
"to non-blocking: %s", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
last_access = time (NULL);
|
||||
|
||||
@ -1188,7 +1226,14 @@ static void relay_connection (struct conn_s *connptr)
|
||||
* Here the server has closed the connection... write the
|
||||
* remainder to the client and then exit.
|
||||
*/
|
||||
socket_blocking (connptr->client_fd);
|
||||
ret = socket_blocking (connptr->client_fd);
|
||||
if (ret != 0) {
|
||||
log_message(LOG_ERR,
|
||||
"Failed to set client socket to blocking: %s",
|
||||
strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
while (buffer_size (connptr->sbuffer) > 0) {
|
||||
if (write_buffer (connptr->client_fd, connptr->sbuffer) < 0)
|
||||
break;
|
||||
@ -1198,7 +1243,14 @@ static void relay_connection (struct conn_s *connptr)
|
||||
/*
|
||||
* Try to send any remaining data to the server if we can.
|
||||
*/
|
||||
socket_blocking (connptr->server_fd);
|
||||
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;
|
||||
@ -1313,7 +1365,7 @@ get_request_entity(struct conn_s *connptr)
|
||||
nread = read_buffer (connptr->client_fd, connptr->cbuffer);
|
||||
if (nread < 0) {
|
||||
log_message (LOG_ERR,
|
||||
"Error reading readble client_fd %d",
|
||||
"Error reading readable client_fd %d",
|
||||
connptr->client_fd);
|
||||
ret = -1;
|
||||
} else {
|
||||
|
147
src/sock.c
147
src/sock.c
@ -162,29 +162,109 @@ int socket_blocking (int sock)
|
||||
return fcntl (sock, F_SETFL, flags & ~O_NONBLOCK);
|
||||
}
|
||||
|
||||
/*
|
||||
* Start listening to a socket. Create a socket with the selected port.
|
||||
* The size of the socket address will be returned to the caller through
|
||||
* the pointer, while the socket is returned as a default return.
|
||||
* - rjkaes
|
||||
|
||||
/**
|
||||
* Try to listen on one socket based on the addrinfo
|
||||
* as returned from getaddrinfo.
|
||||
*
|
||||
* Return the file descriptor upon success, -1 upon error.
|
||||
*/
|
||||
int listen_sock (uint16_t port, socklen_t * addrlen)
|
||||
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, "error calling getnameinfo: %s",
|
||||
gai_strerror(errno));
|
||||
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, vector_t listen_fds)
|
||||
{
|
||||
struct addrinfo hints, *result, *rp;
|
||||
char portstr[6];
|
||||
int listenfd;
|
||||
const int on = 1;
|
||||
int ret = -1;
|
||||
|
||||
assert (port > 0);
|
||||
assert (addrlen != NULL);
|
||||
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);
|
||||
|
||||
if (getaddrinfo (config.ipAddr, portstr, &hints, &result) != 0) {
|
||||
if (getaddrinfo (addr, portstr, &hints, &result) != 0) {
|
||||
log_message (LOG_ERR,
|
||||
"Unable to getaddrinfo() because of %s",
|
||||
strerror (errno));
|
||||
@ -192,45 +272,34 @@ int listen_sock (uint16_t port, socklen_t * addrlen)
|
||||
}
|
||||
|
||||
for (rp = result; rp != NULL; rp = rp->ai_next) {
|
||||
listenfd = socket (rp->ai_family, rp->ai_socktype,
|
||||
rp->ai_protocol);
|
||||
if (listenfd == -1)
|
||||
int listenfd;
|
||||
|
||||
listenfd = listen_on_one_socket(rp);
|
||||
if (listenfd == -1) {
|
||||
continue;
|
||||
|
||||
setsockopt (listenfd, SOL_SOCKET, SO_REUSEADDR, &on,
|
||||
sizeof (on));
|
||||
|
||||
if (bind (listenfd, rp->ai_addr, rp->ai_addrlen) == 0)
|
||||
break; /* success */
|
||||
|
||||
close (listenfd);
|
||||
}
|
||||
|
||||
if (rp == NULL) {
|
||||
/* was not able to bind to any address */
|
||||
log_message (LOG_ERR,
|
||||
"Unable to bind listening socket "
|
||||
"to any address.");
|
||||
vector_append (listen_fds, &listenfd, sizeof(int));
|
||||
|
||||
freeaddrinfo (result);
|
||||
return -1;
|
||||
/* success */
|
||||
ret = 0;
|
||||
|
||||
if (addr != NULL) {
|
||||
/*
|
||||
* Unless wildcard is requested, only listen
|
||||
* on the first result that works.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (listen (listenfd, MAXLISTEN) < 0) {
|
||||
log_message (LOG_ERR,
|
||||
"Unable to start listening socket because of %s",
|
||||
strerror (errno));
|
||||
|
||||
close (listenfd);
|
||||
freeaddrinfo (result);
|
||||
return -1;
|
||||
if (ret != 0) {
|
||||
log_message (LOG_ERR, "Unable to listen on any address.");
|
||||
}
|
||||
|
||||
*addrlen = rp->ai_addrlen;
|
||||
|
||||
freeaddrinfo (result);
|
||||
|
||||
return listenfd;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -28,8 +28,10 @@
|
||||
|
||||
#define MAXLINE (1024 * 4)
|
||||
|
||||
#include "vector.h"
|
||||
|
||||
extern int opensock (const char *host, int port, const char *bind_to);
|
||||
extern int listen_sock (uint16_t port, socklen_t * addrlen);
|
||||
extern int listen_sock (const char *addr, uint16_t port, vector_t listen_fds);
|
||||
|
||||
extern int socket_nonblocking (int sock);
|
||||
extern int socket_blocking (int sock);
|
||||
|
@ -55,11 +55,12 @@ static int build_url (char **url, const char *host, int port, const char *path)
|
||||
int
|
||||
do_transparent_proxy (struct conn_s *connptr, hashmap_t hashofheaders,
|
||||
struct request_s *request, struct config_s *conf,
|
||||
char *url)
|
||||
char **url)
|
||||
{
|
||||
socklen_t length;
|
||||
char *data;
|
||||
size_t ulen = strlen (url);
|
||||
size_t ulen = strlen (*url);
|
||||
ssize_t i;
|
||||
|
||||
length = hashmap_entry_by_key (hashofheaders, "host", (void **) &data);
|
||||
if (length <= 0) {
|
||||
@ -73,7 +74,7 @@ do_transparent_proxy (struct conn_s *connptr, hashmap_t hashofheaders,
|
||||
connptr->client_fd);
|
||||
indicate_http_error (connptr, 400, "Bad Request",
|
||||
"detail", "Unknown destination",
|
||||
"url", url, NULL);
|
||||
"url", *url, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -83,15 +84,12 @@ do_transparent_proxy (struct conn_s *connptr, hashmap_t hashofheaders,
|
||||
request->port = ntohs (dest_addr.sin_port);
|
||||
|
||||
request->path = (char *) safemalloc (ulen + 1);
|
||||
strlcpy (request->path, url, ulen + 1);
|
||||
strlcpy (request->path, *url, ulen + 1);
|
||||
|
||||
/* url overwritten by the call below is the url passed
|
||||
* to this function, and is not the url variable in the
|
||||
* caller. */
|
||||
build_url (&url, request->host, request->port, request->path);
|
||||
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);
|
||||
request->method, *url, connptr->client_fd);
|
||||
} else {
|
||||
request->host = (char *) safemalloc (length + 1);
|
||||
if (sscanf (data, "%[^:]:%hu", request->host, &request->port) !=
|
||||
@ -101,27 +99,36 @@ do_transparent_proxy (struct conn_s *connptr, hashmap_t hashofheaders,
|
||||
}
|
||||
|
||||
request->path = (char *) safemalloc (ulen + 1);
|
||||
strlcpy (request->path, url, ulen + 1);
|
||||
strlcpy (request->path, *url, ulen + 1);
|
||||
|
||||
/* url overwritten by the call below is the url passed
|
||||
* to this function, and is not the url variable in the
|
||||
* caller. */
|
||||
build_url (&url, request->host, request->port, request->path);
|
||||
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);
|
||||
request->method, *url, connptr->client_fd);
|
||||
}
|
||||
if (conf->ipAddr && strcmp (request->host, conf->ipAddr) == 0) {
|
||||
|
||||
if (conf->listen_addrs == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < vector_length(conf->listen_addrs); i++) {
|
||||
const char *addr;
|
||||
|
||||
addr = (char *)vector_getentry(conf->listen_addrs, i, NULL);
|
||||
|
||||
if (addr && strcmp(request->host, addr) == 0) {
|
||||
log_message(LOG_ERR,
|
||||
"process_request: destination IP is localhost %d",
|
||||
connptr->client_fd);
|
||||
"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);
|
||||
"You tried to connect to the "
|
||||
"machine the proxy is running on",
|
||||
"url", *url, NULL);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -32,7 +32,7 @@
|
||||
extern int do_transparent_proxy (struct conn_s *connptr,
|
||||
hashmap_t hashofheaders,
|
||||
struct request_s *request,
|
||||
struct config_s *config, char *url);
|
||||
struct config_s *config, char **url);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -202,10 +202,10 @@ struct upstream *upstream_get (char *host, struct upstream *up)
|
||||
up = NULL;
|
||||
|
||||
if (up)
|
||||
log_message (LOG_INFO, "Found proxy %s:%d for %s",
|
||||
log_message (LOG_INFO, "Found upstream proxy %s:%d for %s",
|
||||
up->host, up->port, host);
|
||||
else
|
||||
log_message (LOG_INFO, "No proxy for %s", host);
|
||||
log_message (LOG_INFO, "No upstream proxy for %s", host);
|
||||
|
||||
return up;
|
||||
}
|
||||
|
@ -26,10 +26,10 @@ LOG_DIR=$TESTENV_DIR/var/log
|
||||
|
||||
TINYPROXY_IP=127.0.0.2
|
||||
TINYPROXY_PORT=12321
|
||||
TINYPROXY_USER=$USER
|
||||
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_LOG_DIR=$LOG_DIR/tinyproxy
|
||||
TINYPROXY_DATA_DIR=$TESTENV_DIR/usr/share/tinyproxy
|
||||
TINYPROXY_CONF_DIR=$TESTENV_DIR/etc/tinyproxy
|
||||
TINYPROXY_CONF_FILE=$TINYPROXY_CONF_DIR/tinyproxy.conf
|
||||
@ -159,12 +159,13 @@ run_basic_webclient_request() {
|
||||
if test "x$WEBCLIENT_EXIT_CODE" = "x0" ; then
|
||||
echo " ok"
|
||||
else
|
||||
echo "ERROR ($EBCLIENT_EXIT_CODE)"
|
||||
echo "ERROR ($WEBCLIENT_EXIT_CODE)"
|
||||
echo "webclient output:"
|
||||
cat $WEBCLIENT_LOG
|
||||
fi
|
||||
}
|
||||
|
||||
return $WEBCLIENT_EXIT_CODE
|
||||
}
|
||||
|
||||
# "main"
|
||||
|
||||
@ -177,22 +178,31 @@ start_tinyproxy
|
||||
|
||||
wait_for_some_seconds 3
|
||||
|
||||
FAILED=0
|
||||
|
||||
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))
|
||||
|
||||
echo "$FAILED errors"
|
||||
|
||||
if test "x$TINYPROXY_TESTS_WAIT" = "xyes"; then
|
||||
echo "You can continue using the webserver and tinyproxy."
|
||||
echo -n "hit <enter> to stop the servers and exit: "
|
||||
read READ
|
||||
fi
|
||||
|
||||
stop_tinyproxy
|
||||
stop_webserver
|
||||
|
||||
echo "done"
|
||||
|
||||
exit 0
|
||||
exit $FAILED
|
||||
|
Loading…
Reference in New Issue
Block a user