Compare commits

...

110 Commits
master ... 1.8

Author SHA1 Message Date
Michael Adam
1115251555 Bump version to 1.8.4.
Signed-off-by: Michael Adam <obnox@samba.org>
2014-12-13 01:57:23 +01:00
Michael Adam
72b477da9e Update NEWS for 1.8.4.
Signed-off-by: Michael Adam <obnox@samba.org>
2014-12-13 01:56:27 +01:00
Michael Adam
87e8da90b0 BB#110 Increase number of hash buckets from 32 to 256.
This should make hash processing generally faster.

There is a treadeoff between memory footprint and
speed of processing. 10 KB instead of 1.2 KB of
hash table per process should not be a huge problem
even on very limited current systems.

Who really needs to stick to 32 buckets could
recompile. We could also think about making
this configurable at some point.

Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit 800c3a250c)
2014-12-13 01:49:01 +01:00
Michael Adam
c348513095 BB#110 limit the number of headers per request to prevent DoS
Based on patch provided by gpernot@praksys.org on bugzilla.

Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit 545463c75d)
2014-12-13 01:48:49 +01:00
Michael Adam
8845bdbff7 BB#110 secure the hashmaps by adding a seed
Based on a patch provided by gpernot@praksys.org on bugzilla.

Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit 308305d827)
2014-12-13 01:48:41 +01:00
Peter H. Froehlich
132a32a68d BB#110 Replace hash function with Dan Bernstein's.
This hash function distributes much better than the
original one. The effect is not as visible with
hashes taken modulo 32 than with a bigger modulus,
but it is there. And larger number of buckets migh
become possible in the future...

Reviewed-by: Michael Adam <obnox@samba.org>
(cherry picked from commit ab6255393d)
2014-12-13 01:48:27 +01:00
Michael Adam
12c454119b Update NEWS for coverity fixes.
Signed-off-by: Michael Adam <obnox@samba.org>
2014-07-21 13:26:57 +02:00
Michael Adam
9db1b0d087 buffer: fix log message in read_buffer().
Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit b59ecd0c66)
2014-07-21 13:26:57 +02:00
Michael Adam
e16844bd3b buffer: reduce indentation in read_buffer()
Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit ffa3a56ab8)
2014-07-21 13:26:57 +02:00
Michael Adam
3cb25a7857 reqs: fix typo in a debug message in get_request_entity()
Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit 76bd008cf9)
2014-07-21 13:26:57 +02:00
Michael Adam
ffbef661cd transparent: make transparent support compile after introduction of multi Listen
I seem to have forgotten to compile with transparent support enabled...
This belongs to the fix for bug BB#63.

Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit b3ac7d2c7b)
2014-07-21 13:26:57 +02:00
Michael Adam
54244661f7 child: remove use of config.listen_addrs in child_listening_sockets()
This was accidentially used instead of the function parameter listen_addrs
This still belongs to the fix for bug BB#63.

Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit b92d70be07)
2014-07-21 13:26:57 +02:00
Michael Adam
5054b9b80f reqs: Fix CID 1130969 (part 3) - unchecked return value from library.
Check the return value of socket_blocking (fcntl) at the
end of relay_connection() for client socket.

Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit 3710accf72)
2014-07-21 13:26:57 +02:00
Michael Adam
b86ecaa11b reqs: Fix CID 1130969 (part 2) - unchecked return value from library.
Check the return value of socket_blocking (fcntl) at the
end of relay_connection().

Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit e07c363df2)
2014-07-21 13:26:57 +02:00
Michael Adam
e467744134 reqs: Fix CID 1130972 - remove logically dead code.
url == NULL is caught above.

Found by coverity.

Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit c82840bfcb)
2014-07-21 13:26:57 +02:00
Michael Adam
4ebb3c1bb6 network: Fix CID 113095 - unchecked return value from library
Check return of "recv" in readline().

Found by coverity.

Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit 49c55ed26c)
2014-07-21 13:26:57 +02:00
Michael Adam
d05e801eef reqs: rename a variable.
ret will be used in enclosing scope.
so rename this special varibale.

Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit c27b6d15e2)
2014-07-21 13:26:57 +02:00
Michael Adam
e1af5ffa58 reqs: Fix CID 1130968 - unchecked return value from library
Check the return code of fcntl via socket_nonblocking
in pull_client_data()

Found by coverity.

Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit 9efa5799f0)
2014-07-21 13:26:57 +02:00
Michael Adam
6c8d9de3cc reqs: Fix CID 1130967 - unchecked return value from library.
Check the return code of fcntl via socket_blocking
in pull_client_data().

Found by coverity.

Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit 0a99803425)
2014-07-21 13:26:57 +02:00
Michael Adam
9eec142886 child: Fix CID 1130966 - unchecked return value from library
check the return code of fcntl via socket_nonblocking
on the listen sockets in child_main()

Found by coverity.

Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit 38ef36d998)
2014-07-21 13:26:56 +02:00
Michael Adam
f413620c5f child: check return code of socket_blocking for accept in child_main
Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit 198600ce42)
2014-07-21 13:26:56 +02:00
Michael Adam
903c9eeb1c reqs: fix CID 1130969 - unchecked return code from library
Effectively, the return code of fcntl was not checked
by not checking the return code of socket_nonblocking()
for the server fd.

Found by coverity.

Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit 68bd0b61b5)
2014-07-21 13:26:56 +02:00
Michael Adam
5a5ae8bfe1 reqs: fix CID 1130970 - unchecked return code from library
Effectively, the return code of fcntl was not checked
by not checking the return code of socket_nonblocking()
for the client fd.

Found by coverity.

Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit 2004abc1e3)
2014-07-21 13:26:56 +02:00
Michael Adam
51d4f11448 conf: Fix CID 1130973 - resource leak.
Found by coverity.

Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit a244c1d4aa)
2014-07-21 13:26:56 +02:00
Mukund Sivaraman
78ff8e0f07 Remove suggester (see Banu RT #138) 2014-05-01 14:00:44 +05:30
Michael Adam
6505867f7a NEWS: fix typo
Signed-off-by: Michael Adam <obnox@samba.org>
2013-11-20 14:25:31 +01:00
Michael Adam
0654ed6403 Start updating NEWS for 1.8.4
Signed-off-by: Michael Adam <obnox@samba.org>
2013-11-16 15:34:43 +01:00
Michael Adam
9ed48eb03b BB#106: remove now unused extract_ssl_url.
Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit 0f18e4fc3a)
2013-11-16 15:27:06 +01:00
Michael Adam
578f409a03 BB#106: fix CONNECT requsts with IPv6 literal addresses as host.
Use extract_url instead of the old extract_ssl_url:
extract_url is generic and handles ipv6 literal addresses correctly.

Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit 9f43cfd488)
2013-11-16 15:27:00 +01:00
Michael Adam
08c44a36ba BB#106: add default_port argument to extract_http_url and rename it to extract_url
There is in fact nothing http-specific any more about this function, hence
the rename. The input has been stripped of the <proto>:// header anyways.

This in preparation of fixing bug BB#106: ssl fails with literal ipv6 addrs.

Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit 98f77ef8c7)
2013-11-16 15:26:53 +01:00
Michael Adam
e0ad093b0f BB#116: fix invalid free when connecting to ipv6 literal address
When removing the '[' and ']' characers from the ipv6 literal address, make sure
the pointer that is later free'd stays a malloced pointer by memmoving the
string one place left.

Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit bb2e894e0d)
2013-11-16 13:13:18 +01:00
Michael Adam
4ef81ff95d build: check for memmove
Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit 7e1d8154de)
2013-11-16 13:13:17 +01:00
Michael Adam
3cdb1bf7aa [BB#63] conf: Allow multiple Listen statements in the config.
This introduces a list (vector) of addresses instead of
having just one address string.

Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit e82080a5f6)
2013-11-16 11:35:58 +01:00
Michael Adam
d11d23c14c [BB#81] allow listening on multiple families when no Listen is provided in config
This is achieved by not stopping at the first result of getaddrinfo
that we managed to listen on: Without "Listen" in the config, we
call getraddrinfo with NULL address. With AI_PASSIVE, this gives results
for both IPv4 and IPv6 wildcard addresses (if both are supported).

This lets tinyproxy listen on both IPv4 and IPv6 wildcard if the system
supports them.

Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit d0732f9ade)
2013-11-16 11:35:58 +01:00
Michael Adam
fdfa365bae sock: add a starting debug message to listen_sock()
Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit e40b91974a)
2013-11-16 11:35:58 +01:00
Michael Adam
954d427565 sock: update introductory comment for listen_sock()
Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit 22587d3d41)
2013-11-16 11:35:58 +01:00
Michael Adam
bb5d6af78f sock: set IPV6_V6ONLY on the socket before binding an IPv6 address
so that we can bind wildcard for both IPv4 and IPv6.

Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit 0698e4d180)
2013-11-16 11:35:58 +01:00
Michael Adam
79f34cd113 sock: factor listening on one socket out of the gai-result-loop in listen_sock()
for clarity of the code

Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit d7f67768eb)
2013-11-16 11:35:58 +01:00
Michael Adam
4f600654d2 sock: in listen_sock(), move variable for setsockopt() into scope
Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit 157879d4f6)
2013-11-16 11:35:58 +01:00
Michael Adam
37ffa6986d sock: log each result of getaddrinfo() in listen_sock()
Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit a7898a2c98)
2013-11-16 11:35:58 +01:00
Michael Adam
5608382be9 sock: in listen_sock(), add a log message for when bind() has failed
Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit 947e255d19)
2013-11-16 11:35:58 +01:00
Michael Adam
04cc18d0f8 sock: in listen_sock(), detect and log failure to call setsockopt()
Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit b41d140984)
2013-11-16 11:35:58 +01:00
Michael Adam
7b1801d8e7 sock: in listen_sock(), add debug message when socket() call failed.
Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit 5392e9829c)
2013-11-16 11:35:58 +01:00
Michael Adam
844403afbe sock: move listen() into the getaddrinfo result loop in listen_sock()
This also reverses the exit logic of the loop.
It prepares listening on multiple addresses.

Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit fa26ad4d56)
2013-11-16 11:35:58 +01:00
Michael Adam
866f1c3e56 child: use a list of listen_fds instead of one single listenfd.
This prepares listenting on multiple sockets, which will be ussed to
fix listening on the wildcard (listen on both ipv6 and ipv4) and
help add the support for multiple Listen statements in the config

Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit 2ebfd456ef)
2013-11-16 11:35:58 +01:00
Michael Adam
425ce3beb6 child: add addr argument to child_listening_sock().
Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit 070d621534)
2013-11-16 11:35:58 +01:00
Michael Adam
a8a2342527 sock: add addr argument to listen_sock()
instead of using config.ipAddr internally.
This is in preparation to make it possible
to call it for multiple addresses.

Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit 2bd919f01e)
2013-11-16 11:35:58 +01:00
Michael Adam
ccb987e8e0 sock/child: remove global variable addrlen.
This changes listen_sock() to not return the
addrlen of the used address from getaddrinfo call
to the caller, stored in global addrlen in child.c.

This was only used to be able to allocate enough space for the
arguments to the later accept call depending on whether
IPv4 or IPv6 is used.

This removes the need to pass this info by always allocating
sizeof(struct sockaddr_storage) instead, which is enough
to carry both sockaddr_in and sockaddr_in6.

Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit 7eea1638bc)
2013-11-16 11:35:58 +01:00
Michael Adam
0adf359245 [BB#109] Fix crash (infinite loop) when writing to log file fails.
Fall back to syslog logging in that case.

Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit 4bbd6e8626)
2013-11-09 13:47:18 +01:00
Michael Adam
54eaac8e76 log: remove extra newline characters in log messages.
Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit d652681e8a)
2013-11-09 13:47:16 +01:00
Gaudenz Steinlin
8963739e4b [BB#115] Drop supplementary groups
Supplementary groups are inherited from the calling process. Drop all
supplementary groups if the "Group" configuration directive is set to
change to a different user. Otherwise the process may have more rights
than expected.

Reviewed-by: Michael Adam <obnox@samba.org>
(cherry picked from commit c8b8247f70)
2013-11-01 06:40:22 +01:00
Michael Adam
a747617c05 [BB#112] build: fix build with autoconf >= 2.69
Use AC_CONFIG_HEADERS instead of obsolete AM_CONFIG_HEADER.

Signed-off-by: Michael Adam <obnox@samba.org>
(cherry picked from commit 3cc59ec3be)

Conflicts:

	configure.ac
2013-04-10 00:01:44 +02:00
Mukund Sivaraman
9d7a95bd56 build: Prepend to LDFLAGS instead of replacing its contents 2012-01-23 16:26:07 +05:30
Mukund Sivaraman
3933daf793 Make .xz compressed dist targets too 2011-09-11 11:53:46 +05:30
Mukund Sivaraman
18db1675a0 Update NEWS 2011-08-16 17:56:04 +05:30
Mukund Sivaraman
4d979df636 Bump version to 1.8.3 2011-08-16 17:45:06 +05:30
Mukund Sivaraman
fc354343f9 Minor whitespace fix 2011-08-16 17:43:59 +05:30
Mukund Sivaraman
1db982793d [BB#90]: Fix bug in ACL netmask generation
Thanks to John Horne who diagnosed this issue and found the problem.
2011-03-04 14:47:54 +05:30
Mukund Sivaraman
95a6f8259c Validate port number specified in Port directive
This was asked in bug #90 comment #8.
2011-03-04 14:10:11 +05:30
Mukund Sivaraman
8b76f1a939 Update URLs of Tinyproxy 2011-02-28 12:46:46 +05:30
Mukund Sivaraman
121a11d8e5 Surround IPv6 literals with [] in Host: headers 2011-02-07 18:01:03 +05:30
Mukund Sivaraman
736e052dc1 Handle IPv6 literals in URLs correctly 2011-02-04 21:03:12 +05:30
Michael Adam
aa197d6dc8 [BB#95] remove two comments that have become wrong by the fix. 2010-12-01 22:21:11 +01:00
Daniel Egger
d13d575d29 [BB#95] Fix FilterURLs with transparent proxy support.
Pass a pointer to a char pointer to do_transparent_proxy so the reassembled URL
will actually end up back in the caller where it is needed for filtering
decisions. This fixes the problem that a tinyproxy configured with the
transparent proxy functionality and "FilterURLs Yes" would filter on everything
but the domain.

Signed-off-by: daniel.egger@sphairon.com
Signed-off-by: Michael Adam <obnox@samba.org>
2010-12-01 22:18:08 +01:00
Michael Adam
c4b187c8ab README: correctly list --enable-transparent
--enable-transparent-proxy was renamed to --enable-transparent
in August 2004... :-)
2010-12-01 21:44:32 +01:00
Michael Adam
5012ce690f [BB#91] Fix upstream proxy support.
Patch by Jordi Mallach.
2010-08-24 22:50:53 +02:00
Michael Adam
4b75b634d9 upstream: clarify debug messages
There are frequent questions "what does 'No proxy for ...' mean?"
on the mailing list and IRC. Be more specific. (No upstream proxy ...)
Correspondingly, log "Found upstream proxy ... for ..."
2010-08-24 22:50:48 +02:00
Mukund Sivaraman
4b64de4c31 Change wording in NEWS 2010-06-05 09:29:58 +05:30
Mukund Sivaraman
7fa544c3d8 Bump version in configure.ac 2010-06-02 10:40:23 +05:30
Mukund Sivaraman
a5a3741291 Add BB#74 to NEWS 2010-06-02 10:39:56 +05:30
Mukund Sivaraman
784d458b82 [BB#74] Create log and pid files after we drop privs 2010-06-02 10:19:49 +05:30
Mukund Sivaraman
94edc4f4c5 Remove excessive code 2010-06-02 10:11:10 +05:30
Mukund Sivaraman
be63d2ca19 Add BB#89 to NEWS 2010-06-02 05:05:30 +05:30
Mukund Sivaraman
a905437242 Add NEWS for 1.8.2 2010-06-01 08:12:29 +05:30
John van der Kamp
3127e726d0 [BB#89] Don't recompile regular expressions
This is a modification of a patch originally written by
John van der Kamp <john@kirika.demon.nl> at
<http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=579427#12>

The modification was done by the committer.
2010-06-01 07:58:02 +05:30
Mukund Sivaraman
5bb184c54d Fix typo in manpage 2010-05-30 10:02:45 +05:30
Jordi Mallach
505ff803e9 [BB#83] Use output of id instead of $USER 2010-04-21 21:01:59 +05:30
Dmitry Semyonov
d03e3a52e5 Fix crash in send_stored_logs() 2010-04-21 20:32:41 +05:30
Mukund Sivaraman
fe9444d585 Fix compiler warning about dereferencing type-punned pointers
This is a backport of commit 19b9bff888
from the master branch.
2010-04-21 20:21:22 +05:30
Mukund Sivaraman
b37135524d Revert "main: drop privileges right after reading the config"
This reverts commit 965664798c. It should
fix the issue in bug #87.
2010-04-21 20:09:20 +05:30
Mukund Sivaraman
7f053670c0 Just fix the support URLs
These should always point to the top-level Tinyproxy homepage.
2010-03-28 10:29:56 +05:30
Mukund Sivaraman
b28e438cdf Revert "Update Tinyproxy website URLs"
This reverts commit e495bdf129.
2010-03-28 10:27:45 +05:30
Mukund Sivaraman
e495bdf129 Update Tinyproxy website URLs 2010-03-27 08:19:53 +05:30
Mukund Sivaraman
287a7ae649 Revert "Revert "Pass address family when binding to outgoing socket""
This reverts commit 577ac16cf1. It looks
like bug #69 needs this fix after all.
2010-03-09 17:07:14 +05:30
Mukund Sivaraman
315e129f12 Pull BB#69 out of NEWS for 1.8.1 2010-03-09 06:58:24 +05:30
Mukund Sivaraman
7cb30dd9ee Separate different versions in NEWS with newlines 2010-03-09 06:55:25 +05:30
Mukund Sivaraman
9927d411bf Add the contributors section to 1.8.1 NEWS 2010-03-03 15:37:10 +05:30
Mukund Sivaraman
0f28221ec5 Minor grammatical change 2010-03-03 15:33:40 +05:30
Mukund Sivaraman
57d90c8bf7 Update NEWS for 1.8.1 2010-03-03 15:31:46 +05:30
Mukund Sivaraman
8de8634b8b Bump version to 1.8.1 2010-03-03 15:21:25 +05:30
Mukund Sivaraman
ce149cc7a6 Use AI_PASSIVE flag to make tinyproxy listen on wildcard interface
Signed-off-by: Michael Adam <obnox@samba.org>
2010-03-03 09:27:22 +01:00
Michael Adam
410eaf107c Comment out the LogFile and PidFile options in the example tinyproxy.conf.
These are compiled in defaults now.

Michael
2010-03-03 01:06:25 +01:00
Michael Adam
e6cbaf7b6e change the default pid file location to "@LOCALSTATEDIR@/run/tinyproxy/tinyproxy.pid"
I.e., add a tinyproxy subdirectory.
This is meant to ease running tinyproxy as non-root user.
The subdirectory can be used to give the tinyproxy user
write permission.

Michael
2010-03-03 01:06:25 +01:00
Michael Adam
2d0192b8a8 change the default log file location to "@LOCALSTATEDIR@/log/tinyproxy/tinyproxy.log"
i.e. add a tinyproxy subdirectory.
This is meant to ease running tinyproxy as non-root user
the subdirectory can be used to give the tinyproxy user
write permission.

Michael
2010-03-03 01:06:25 +01:00
Michael Adam
643d52ac5a main: some tabs->spaces 2010-03-03 01:06:25 +01:00
Michael Adam
b92792fd8d main: move a log message. 2010-03-03 01:06:25 +01:00
Michael Adam
965664798c main: drop privileges right after reading the config
This is the second part of fixing bug #74.
I lets tinyproxy create its log and pid files as the
user as which it is running, so that later on at SIGHUP,
the log file can successfully be reopened.

Michael
2010-03-03 01:06:25 +01:00
Michael Adam
6d5709de38 main: separate loading of config and setup_logging at startup
This is the first part of a fix for bug #74
(making reloading of config work if running as non-privileged user)

Michael
2010-03-03 01:06:25 +01:00
Michael Adam
107f9117d0 tinyproxy.conf: fix LogFile to proper CamelCase for consistency 2010-03-03 01:06:24 +01:00
Michael Adam
1b3dd058d1 tests: fix bug #80: keep track of errors in return codes
Michael
(cherry picked from commit 3f1632603c)
2010-02-23 00:19:26 +01:00
Michael Adam
333d722d56 tests: fix a typo in run_tests.sh
(cherry picked from commit 7c15563430)
2010-02-23 00:19:23 +01:00
Michael Adam
6f0abb7339 test: add make target "make valgrind-test-wait"
(cherry picked from commit ee1f1e38f2)
2010-02-22 23:32:08 +01:00
Michael Adam
a19f758743 tests: add a new make target "make test-wait"
(cherry picked from commit 752e4419a6)
2010-02-22 23:21:18 +01:00
Michael Adam
f63730c77e tests: Fix bug #79. Finish "make test" without waiting for user input.
Old behaviour is preserved by passing in the environment variable
TINYPROXY_TESTS_WAIT=yes.

Michael
(cherry picked from commit d133eee36b)
2010-02-22 23:21:13 +01:00
Mukund Sivaraman
ed3ada7c26 Use format string when logging messages 2010-02-19 21:08:00 +05:30
Mukund Sivaraman
b9e6d9742d Fix pkgdatadir path in tinyproxy.conf 2010-02-19 21:07:58 +05:30
Mukund Sivaraman
fbc434e26d Display upstream proxy support in usage message 2010-02-17 23:18:50 +05:30
Mukund Sivaraman
cc74869e71 Fix typo in manpage 2010-01-25 19:35:41 +05:30
Mukund Sivaraman
577ac16cf1 Revert "Pass address family when binding to outgoing socket"
This reverts commit 65ef313cc4.
This patch could've been the reason for BB#69.
2010-01-24 11:18:27 +05:30
Mukund Sivaraman
810b9ae49a Remove completed items from TODO list 2010-01-18 16:01:16 +05:30
27 changed files with 752 additions and 273 deletions

View File

@ -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
View File

@ -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
View File

@ -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
View File

@ -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)

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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.");
}
}

View File

@ -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",

View File

@ -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) {

View File

@ -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 {

View File

@ -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;
}
/*

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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