Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
417c258d14 | ||
|
3a920b7163 | ||
|
42bb446c96 | ||
|
dabfd1ad6c | ||
|
ae4cbcabd1 | ||
|
22f059dc5e | ||
|
86379b4b66 | ||
|
57f932a33b | ||
|
173c5b66a7 | ||
|
393e51ba45 | ||
|
b07f7a8422 | ||
|
3eb238634a | ||
|
f1f3994d09 |
@ -1,20 +0,0 @@
|
||||
---
|
||||
name: New Issue, Bug report, Question
|
||||
about: New Issue, Bug report, Question
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
# IMPORTANT NOTICE
|
||||
|
||||
Before filing an issue here PLEASE keep in mind that **tinyproxy 1.10.0 and older are no longer supported**.
|
||||
Do not report issues with 1.10.0 or older, first try latest release 1.11.0, or even better, git master, and see whether the issue is already fixed.
|
||||
|
||||
## Tinyproxy version
|
||||
State the tinyproxy version you're using; whether git master or 1.11.0 stable.
|
||||
|
||||
## Issue
|
||||
Fill in your Issue text here.
|
||||
A good issue report is detailed and includes full error messages from tinyproxy's output, not "X doesn't work".
|
36
.github/workflows/main.yml
vendored
36
.github/workflows/main.yml
vendored
@ -1,36 +0,0 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: ./autogen.sh
|
||||
- run: ./configure
|
||||
- run: make
|
||||
- run: make test
|
||||
test-macos:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: brew install automake
|
||||
- run: ./autogen.sh
|
||||
- run: ./configure
|
||||
- run: make
|
||||
valgrind-test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: sudo apt update
|
||||
- run: sudo apt install --assume-yes valgrind
|
||||
- run: ./autogen.sh
|
||||
- run: ./configure --enable-debug --enable-transparent --enable-reverse
|
||||
- run: make
|
||||
- run: make test
|
||||
- run: make valgrind-test
|
40
.github/workflows/release_tarball.yml
vendored
40
.github/workflows/release_tarball.yml
vendored
@ -1,40 +0,0 @@
|
||||
name: Generate Source Tarball
|
||||
|
||||
# Trigger whenever a release is created
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- created
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: archive
|
||||
id: archive
|
||||
run: |
|
||||
sudo apt install -y gperf
|
||||
rm -rf .git
|
||||
autoreconf -i
|
||||
VERSION=$(cat VERSION)
|
||||
PKGNAME="tinyproxy-$VERSION"
|
||||
./configure
|
||||
make dist
|
||||
echo "tarball_xz=${PKGNAME}.tar.xz" >> "$GITHUB_OUTPUT"
|
||||
echo "tarball_gz=${PKGNAME}.tar.gz" >> "$GITHUB_OUTPUT"
|
||||
echo "tarball_bz2=${PKGNAME}.tar.bz2" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: upload tarballs
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: |
|
||||
${{ steps.archive.outputs.tarball_xz }}
|
||||
${{ steps.archive.outputs.tarball_gz }}
|
||||
${{ steps.archive.outputs.tarball_bz2 }}
|
||||
|
@ -89,4 +89,4 @@ and create a [pull request](https://github.com/tinyproxy/tinyproxy/pulls).
|
||||
|
||||
You can meet developers and users to discuss development,
|
||||
patches and deployment issues in the `#tinyproxy` IRC channel on
|
||||
libera (`irc.libera.chat`).
|
||||
Freenode (`irc.freenode.net`).
|
||||
|
28
SECURITY.md
28
SECURITY.md
@ -1,28 +0,0 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
| Version | Supported |
|
||||
| --------- | ------------------ |
|
||||
| 1.11.x | :white_check_mark: |
|
||||
| <= 1.10.x | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Open a public issue on github. The issue will most likely be fixed
|
||||
within a day, unless all maintainers happen to just be taking a
|
||||
vacation at the same time, which is unlikely.
|
||||
|
||||
Even then, having the bug publicly known will allow competent people
|
||||
to come up with custom patches for distros, most likely quicker
|
||||
than black hats can craft a remote execution exploit.
|
||||
|
||||
If you really really do not want to make the issue public, come
|
||||
to the tinyproxy IRC channel and ask for a maintainer, which you
|
||||
can then contact via private messages.
|
||||
|
||||
Do not, however, like ["TALOS Intelligence"](https://talosintelligence.com/vulnerability_reports/TALOS-2023-1889)
|
||||
pull a random email address out of git log, then send an email
|
||||
nobody reads or responds to, and wait for 6 months for publication.
|
||||
this only gives black hats plenty time to sell, use and circulate
|
||||
zero days and get the best possible ROI.
|
39
configure.ac
39
configure.ac
@ -170,12 +170,20 @@ if test x"$debug_enabled" != x"yes" ; then
|
||||
CFLAGS="-DNDEBUG $CFLAGS"
|
||||
fi
|
||||
|
||||
AS_ECHO_N(["checking to see if linker understands -z,defs... "])
|
||||
LDFLAGS_OLD="-Wl $LDFLAGS"
|
||||
LDFLAGS="-Wl,-z,defs $LDFLAGS"
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM()],
|
||||
AS_ECHO("yes"),
|
||||
AS_ECHO("no"); LDFLAGS="$LDFLAGS_OLD")
|
||||
|
||||
dnl
|
||||
dnl Make sure we can actually handle the "--with-*" and "--enable-*" stuff.
|
||||
dnl
|
||||
|
||||
dnl
|
||||
dnl Substitute the variables into the various Makefiles
|
||||
dnl
|
||||
# runstatedir isn't available for Autoconf < 2.70
|
||||
AS_IF([test -z "${runstatedir}"], [runstatedir='${localstatedir}/run'])
|
||||
AC_SUBST([runstatedir])
|
||||
AC_SUBST(CFLAGS)
|
||||
AC_SUBST(LDFLAGS)
|
||||
AC_SUBST(CPPFLAGS)
|
||||
@ -197,21 +205,23 @@ fi #manpage_support_enabled
|
||||
AM_CONDITIONAL(HAVE_POD2MAN, test "x$POD2MAN" != "x" -a "x$POD2MAN" != "xno")
|
||||
|
||||
AC_PATH_PROG(GPERF, gperf, no)
|
||||
AM_CONDITIONAL(HAVE_GPERF, test "x$GPERF" != "x" -a "x$GPERF" != "xno")
|
||||
AH_TEMPLATE([HAVE_GPERF],
|
||||
[Whether you have gperf installed for faster config parsing.])
|
||||
|
||||
tmp_gperf=false
|
||||
if test "x$GPERF" != "x" -a "x$GPERF" != "xno" ; then
|
||||
AS_ECHO_N(["checking whether gperf is recent enough... "])
|
||||
if "$GPERF" < src/conf-tokens.gperf >/dev/null 2>&1 ; then
|
||||
AS_ECHO("yes")
|
||||
AC_DEFINE(HAVE_GPERF)
|
||||
tmp_gperf=true
|
||||
else
|
||||
AS_ECHO("no")
|
||||
fi
|
||||
fi
|
||||
AM_CONDITIONAL(HAVE_GPERF, $tmp_gperf)
|
||||
|
||||
AC_PATH_PROG(RAGEL, ragel, no)
|
||||
AM_CONDITIONAL(HAVE_RAGEL, test "x$RAGEL" != "x" -a "x$RAGEL" != "xno")
|
||||
AH_TEMPLATE([HAVE_RAGEL],
|
||||
[Whether you have ragel installed for faster config parsing.])
|
||||
|
||||
if test "x$RAGEL" != "x" -a "x$RAGEL" != "xno" ; then
|
||||
AC_DEFINE(HAVE_RAGEL)
|
||||
fi
|
||||
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
@ -223,6 +233,7 @@ docs/Makefile
|
||||
docs/man5/Makefile
|
||||
docs/man5/tinyproxy.conf.txt
|
||||
docs/man8/Makefile
|
||||
docs/man8/tinyproxy.txt
|
||||
m4macros/Makefile
|
||||
tests/Makefile
|
||||
tests/scripts/Makefile
|
||||
@ -247,7 +258,3 @@ if test "x$POD2MAN" = "xno" ; then
|
||||
touch docs/man8/tinyproxy.8
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "x$HAVE_GPERF" = "xno" && test -e src/conf-tokens-gperf.inc ; then
|
||||
touch src/conf-tokens-gperf.inc
|
||||
fi
|
||||
|
@ -30,6 +30,9 @@
|
||||
<dt>clienthost</dt>
|
||||
<dd>{clienthost}</dd>
|
||||
|
||||
<dt>version</dt>
|
||||
<dd>{version}</dd>
|
||||
|
||||
<dt>package</dt>
|
||||
<dd>{package}</dd>
|
||||
|
||||
@ -46,7 +49,7 @@
|
||||
|
||||
<hr />
|
||||
|
||||
<p><em>Generated by <a href="{website}">{package}</a>.</em></p>
|
||||
<p><em>Generated by <a href="{website}">{package}</a> version {version}.</em></p>
|
||||
|
||||
</body>
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
<hr />
|
||||
|
||||
<p><em>Generated by <a href="{website}">{package}</a>.</em></p>
|
||||
<p><em>Generated by <a href="{website}">{package}</a> version {version}.</em></p>
|
||||
|
||||
</body>
|
||||
|
||||
|
@ -1,95 +1,69 @@
|
||||
<!DOCTYPE html>
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Stats [{package}]</title>
|
||||
<meta charset="UTF-8" />
|
||||
<style type="text/css">
|
||||
body {
|
||||
color: #eee;
|
||||
background: #110d0d;
|
||||
text-align: center;
|
||||
font: 12pt/1.6 Open Sans, Segoe UI, sans-serif;
|
||||
}
|
||||
#container {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: table;
|
||||
}
|
||||
#inner {
|
||||
width: 100%;
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
}
|
||||
table {
|
||||
width: auto;
|
||||
margin: auto;
|
||||
height: auto;
|
||||
background: #222020;
|
||||
border: 1px solid #777373;
|
||||
border-spacing: 3px;
|
||||
}
|
||||
th,
|
||||
td {
|
||||
padding: 6px 18px;
|
||||
}
|
||||
th {
|
||||
font-weight: 700;
|
||||
background: linear-gradient(to bottom, #777373, #555151);
|
||||
}
|
||||
.odd {
|
||||
background: #444040;
|
||||
}
|
||||
.even {
|
||||
background: #555151;
|
||||
}
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
.right {
|
||||
text-align: right;
|
||||
font-weight: 600;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
||||
|
||||
<body>
|
||||
<div id="container">
|
||||
<div id="inner">
|
||||
<table>
|
||||
<tr>
|
||||
<th colspan="2">{package} statistics</th>
|
||||
</tr>
|
||||
<tr class="odd">
|
||||
<td class="right">Open connections</td>
|
||||
<td class="center">{opens}</td>
|
||||
</tr>
|
||||
<head>
|
||||
<title>{package} version {version} run-time statistics</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||
|
||||
<tr class="even">
|
||||
<td class="right">Bad connections</td>
|
||||
<td class="center">{badconns}</td>
|
||||
</tr>
|
||||
<style type="text/css" media="screen">
|
||||
<!--/*--><![CDATA[<!--*/
|
||||
|
||||
<tr class="odd">
|
||||
<td class="right">Denied connections</td>
|
||||
<td class="center">{deniedconns}</td>
|
||||
</tr>
|
||||
th, td
|
||||
{
|
||||
text-align: left;
|
||||
padding: 0.5em;
|
||||
border: 1px solid gray;
|
||||
}
|
||||
|
||||
<tr class="even">
|
||||
<td class="right">Refused (high load)</td>
|
||||
<td class="center">{refusedconns}</td>
|
||||
</tr>
|
||||
/*]]>*/-->
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<h1>{package} version {version} run-time statistics</h1>
|
||||
|
||||
<table>
|
||||
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Number of open connections</td>
|
||||
<td>{opens}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Number of requests</td>
|
||||
<td>{reqs}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Number of bad connections</td>
|
||||
<td>{badconns}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Number of denied connections</td>
|
||||
<td>{deniedconns}</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Number of refused connections due to high load</td>
|
||||
<td>{refusedconns}</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
<hr />
|
||||
|
||||
<p><em>Generated by <a href="{website}">{package}</a> version {version}.</em></p>
|
||||
|
||||
</body>
|
||||
|
||||
<tr class="odd">
|
||||
<td class="right">Total requests</td>
|
||||
<td class="center">{reqs}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -22,8 +22,8 @@ configuration file.
|
||||
The Tinyproxy configuration file contains key-value pairs, one per
|
||||
line. Lines starting with `#` and empty lines are comments and are
|
||||
ignored. Keywords are case-insensitive, whereas values are
|
||||
case-sensitive. Some string values must be enclosed in double
|
||||
quotes (") as noted below.
|
||||
case-sensitive. Values may be enclosed in double-quotes (") if they
|
||||
contain spaces.
|
||||
|
||||
The possible keywords and their descriptions are as follows:
|
||||
|
||||
@ -57,9 +57,7 @@ only on one specific address.
|
||||
=item B<Bind>
|
||||
|
||||
This allows you to specify which address Tinyproxy will bind
|
||||
to for outgoing connections.
|
||||
This parameter may be specified multiple times, then Tinyproxy
|
||||
will try all the specified addresses in order.
|
||||
to for outgoing connections to web servers or upstream proxies.
|
||||
|
||||
=item B<BindSame>
|
||||
|
||||
@ -76,29 +74,29 @@ allowed to have before it is closed by Tinyproxy.
|
||||
|
||||
This parameter controls which HTML file Tinyproxy returns when a
|
||||
given HTTP error occurs. It takes two arguments, the error number
|
||||
and the location of the HTML error file. Enclose the file location
|
||||
in double quotes.
|
||||
and the location of the HTML error file.
|
||||
|
||||
=item B<DefaultErrorFile>
|
||||
|
||||
The HTML template file returned when an error occurs for which no
|
||||
specific error file has been set. Enclose in double quotes.
|
||||
This parameter controls the HTML template file returned when an
|
||||
error occurs for which no specific error file has been set.
|
||||
|
||||
=item B<StatHost>
|
||||
|
||||
The host name or IP address that is treated as the `stat host`.
|
||||
Enclose in double quotes. Whenever Tinyproxy receives a request for
|
||||
the `stat host` it returns an internal statistics page instead of
|
||||
forwarding the request to that host. The template for this page can be
|
||||
configured with the `StatFile` configuration option. The default value
|
||||
of `StatHost` is `@TINYPROXY_STATHOST@`.
|
||||
This configures the host name or IP address that is treated
|
||||
as the `stat host`: Whenever a request for this host is received,
|
||||
Tinyproxy will return an internal statistics page instead of
|
||||
forwarding the request to that host. The template for this
|
||||
page can be configured with the `StatFile` configuration option.
|
||||
The default value of `StatHost` is `@TINYPROXY_STATHOST@`.
|
||||
|
||||
=item B<StatFile>
|
||||
|
||||
The HTML file that Tinyproxy sends in response to a request for the
|
||||
`stat host`. Enclose in double quotes. If this parameter is not set,
|
||||
Tinyproxy returns a hard-coded basic statistics page. See the STATHOST
|
||||
section in the L<tinyproxy(8)> manual page for details.
|
||||
This configures the HTML file that Tinyproxy sends when
|
||||
a request for the stathost is received. If this parameter is
|
||||
not set, Tinyproxy returns a hard-coded basic statistics page.
|
||||
See the STATHOST section in the L<tinyproxy(8)> manual page
|
||||
for details.
|
||||
|
||||
Note that the StatFile and the error files configured with ErrorFile
|
||||
and DefaultErrorFile are template files that can contain a few
|
||||
@ -109,9 +107,9 @@ manual page contains a description of all template variables.
|
||||
|
||||
=item B<LogFile>
|
||||
|
||||
The location of the file to which Tinyproxy writes its debug output.
|
||||
Enclose in double quotes. Alternatively, Tinyproxy can log to syslog
|
||||
-- see the Syslog option.
|
||||
This controls the location of the file to which Tinyproxy
|
||||
writes its debug output. Alternatively, Tinyproxy can log
|
||||
to syslog -- see the Syslog option.
|
||||
|
||||
=item B<Syslog>
|
||||
|
||||
@ -144,8 +142,8 @@ and below would be suppressed. Allowed values are:
|
||||
|
||||
=item B<PidFile>
|
||||
|
||||
The location of the file where the main Tinyproxy process stores its
|
||||
process ID for signaling purposes. Enclose in double quotes.
|
||||
This option controls the location of the file where the main
|
||||
Tinyproxy process stores its process ID for signaling purposes.
|
||||
|
||||
=item B<XTinyproxy>
|
||||
|
||||
@ -173,20 +171,12 @@ turns on the upstream proxy for the sites matching `site_spec`.
|
||||
|
||||
`type` can be one of `http`, `socks4`, `socks5`, `none`.
|
||||
|
||||
a `site_spec` is either a full domain name, a domain name starting with a
|
||||
`.`, in which case it is treated as a suffix, or an ip/mask tuple.
|
||||
the `site_spec` needs to be double-quoted.
|
||||
|
||||
=item * I<upstream none "site_spec">
|
||||
turns off upstream support for sites matching `site_spec`, that means the
|
||||
connection is done directly.
|
||||
|
||||
=back
|
||||
|
||||
It's recommended to use raw IP addresses to specify the upstream host, so
|
||||
no costly DNS lookup has to be done everytime it is used.
|
||||
IPv6 addresses need to be enclosed in square brackets.
|
||||
|
||||
The site can be specified in various forms as a hostname, domain
|
||||
name or as an IP range:
|
||||
|
||||
@ -243,14 +233,6 @@ access is only granted for authenticated users.
|
||||
|
||||
BasicAuth user password
|
||||
|
||||
=item B<BasicAuthRealm>
|
||||
|
||||
In case "BasicAuth" is configured, the "realm" information.
|
||||
"Proxy Authentication Required" status http 407 "error-response" can be
|
||||
customized.
|
||||
|
||||
- defaults in code to "Tinyproxy" (PACKAGE_NAME), if not configured.
|
||||
|
||||
=item B<AddHeader>
|
||||
|
||||
Configure one or more HTTP request headers to be added to outgoing
|
||||
@ -266,8 +248,7 @@ RFC 2616 requires proxies to add a `Via` header to the HTTP
|
||||
requests, but using the real host name can be a security
|
||||
concern. If the `ViaProxyname` option is present, then its
|
||||
string value will be used as the host name in the Via header.
|
||||
Otherwise, the server's host name will be used. Enclose in double
|
||||
quotes.
|
||||
Otherwise, the server's host name will be used.
|
||||
|
||||
=item B<DisableViaHeader>
|
||||
|
||||
@ -284,7 +265,7 @@ domains. This option specifies the location of the file
|
||||
containing the filter rules, one rule per line.
|
||||
|
||||
Rules are specified as POSIX basic regular expressions (BRE), unless
|
||||
another FilterType is specified.
|
||||
FilterExtended is activated.
|
||||
Comment lines start with a `#` character.
|
||||
|
||||
Example filter file contents:
|
||||
@ -304,34 +285,14 @@ Example filter file contents:
|
||||
# filter any domain that starts with adserver
|
||||
^adserver
|
||||
|
||||
=item B<FilterType>
|
||||
|
||||
This option can be set to one of `bre`, `ere`, or `fnmatch`.
|
||||
If `bre` is set, the rules specified in the filter file are matched
|
||||
using POSIX basic regular expressions, when set to `ere`, using
|
||||
POSIX extended regular expressions, and when set to `fnmatch` using
|
||||
the `fnmatch` function as specified in the manpage `man 3p fnmatch`.
|
||||
`fnmatch` matching is identical to what's used in the shell to match
|
||||
filenames, so for example `*.google.com` matches everything that
|
||||
ends with `.google.com`.
|
||||
If you don't know what regular expressions are or you're using filter
|
||||
lists from 3rd party sources, `fnmatch` is probably what you want.
|
||||
It's also the fastest matching method of the three.
|
||||
|
||||
=item B<FilterURLs>
|
||||
|
||||
If this boolean option is set to `Yes` or `On`, filtering is
|
||||
performed for URLs rather than for domains. The default is to
|
||||
filter based on domains.
|
||||
|
||||
Note that filtering for URLs works only in plain HTTP scenarios.
|
||||
Since HTTPS has become ubiquitous during the last years, this
|
||||
will only work on a tiny fraction of websites, so it is
|
||||
recommended not to use this option.
|
||||
|
||||
=item B<FilterExtended>
|
||||
|
||||
Deprecated. Use `FilterType ere` instead.
|
||||
If this boolean option is set to `Yes`, then extended POSIX
|
||||
regular expressions are used for matching the filter rules.
|
||||
The default is to use basic POSIX regular expressions.
|
||||
@ -340,11 +301,7 @@ The default is to use basic POSIX regular expressions.
|
||||
|
||||
If this boolean option is set to `Yes`, then the filter rules
|
||||
are matched in a case sensitive manner. The default is to
|
||||
match case-insensitively, unfortunately.
|
||||
If you set this to `Yes`, then your matching will be almost
|
||||
twice as fast.
|
||||
This setting affects only `bre` and `ere` FilterTypes, fnmatch
|
||||
is always case sensitive.
|
||||
match case-insensitively.
|
||||
|
||||
=item B<FilterDefaultDeny>
|
||||
|
||||
@ -352,8 +309,6 @@ The default filtering policy is to allow everything that is
|
||||
not matched by a filtering rule. Setting `FilterDefaultDeny`
|
||||
to `Yes` changes the policy do deny everything but the domains
|
||||
or URLs matched by the filtering rules.
|
||||
In other words, if set to `No` the Filter list acts as a
|
||||
blacklist, if set to `Yes` as a whitelist.
|
||||
|
||||
=item B<Anonymous>
|
||||
|
||||
@ -361,7 +316,7 @@ If an `Anonymous` keyword is present, then anonymous proxying
|
||||
is enabled. The headers listed with `Anonymous` are allowed
|
||||
through, while all others are denied. If no Anonymous keyword
|
||||
is present, then all headers are allowed through. You must
|
||||
include double quotes around the headers.
|
||||
include quotes around the headers.
|
||||
|
||||
Most sites require cookies to be enabled for them to work correctly, so
|
||||
you will need to allow cookies through if you access those sites.
|
||||
@ -432,7 +387,7 @@ This manpage was written by the Tinyproxy project team.
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright (c) 1998-2024 the Tinyproxy authors.
|
||||
Copyright (c) 1998-2020 the Tinyproxy authors.
|
||||
|
||||
This program is distributed under the terms of the GNU General Public
|
||||
License version 2 or above. See the COPYING file for additional
|
||||
|
@ -9,17 +9,6 @@ M_NAME=TINYPROXY
|
||||
man_MANS = \
|
||||
$(MAN8_FILES:.txt=.8)
|
||||
|
||||
edit = sed \
|
||||
-e 's|@localstatedir[@]|$(localstatedir)|g' \
|
||||
-e 's|@runstatedir[@]|$(runstatedir)|g' \
|
||||
-e 's|@sysconfdir[@]|$(sysconfdir)|g' \
|
||||
-e 's|@TINYPROXY_STATHOST[@]|$(TINYPROXY_STATHOST)|g'
|
||||
|
||||
tinyproxy.txt: $(top_srcdir)/docs/man8/tinyproxy.txt.in Makefile
|
||||
@rm -f $@ $@.tmp
|
||||
$(AM_V_GEN) $(edit) $(top_srcdir)/docs/man8/$@.in > $@.tmp
|
||||
@mv $@.tmp $@
|
||||
|
||||
.txt.8:
|
||||
if HAVE_POD2MAN
|
||||
$(AM_V_GEN) $(POD2MAN) --center="Tinyproxy manual" \
|
||||
|
@ -156,11 +156,7 @@ configuration variable `StatFile`.
|
||||
|
||||
=head1 FILES
|
||||
|
||||
F<@sysconfdir@/tinyproxy/tinyproxy.conf>
|
||||
|
||||
F<@runstatedir@/tinyproxy/tinyproxy.pid>
|
||||
|
||||
F<@localstatedir@/log/tinyproxy/tinyproxy.log>
|
||||
`/etc/tinyproxy/tinyproxy.conf`, `/var/run/tinyproxy/tinyproxy.pid`, `/var/log/tinyproxy/tinyproxy.log`
|
||||
|
||||
=head1 BUGS
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
<ul>
|
||||
<li>Feel free to report a new bug or suggest features via github issues.</li>
|
||||
<li>Tinyproxy developers hang out in #tinyproxy on irc.libera.chat.</li>
|
||||
<li>Tinyproxy developers hang out in #tinyproxy on irc.freenode.net.</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
|
@ -41,27 +41,25 @@
|
||||
|
||||
<p>Tinyproxy requires only a <strong>minimal POSIX environment</strong> to build and operate. It can use additional libraries to add functionality though.</p>
|
||||
|
||||
<p>Tinyproxy allows forwarding of <strong>HTTPS connections</strong> without modifying traffic in any way through the <code>CONNECT</code> method (see the <code>ConnectPort</code> directive, which you should disable, unless you want to restrict the users).</p>
|
||||
<p>Tinyproxy allows forwarding of <strong>HTTPS connections</strong> without modifying traffic in any way through the <code>CONNECT</code> method (see the <code>ConnectPort</code> directive).</p>
|
||||
|
||||
<p>Tinyproxy supports being configured as a <strong>transparent proxy</strong>, so that a proxy can be used without requiring any client-side configuration. You can also use it as a <strong>reverse proxy</strong> front-end to your websites.</p>
|
||||
|
||||
<p>Using the <code>AddHeader</code> directive, you can <strong>add/insert HTTP headers</strong> to outgoing traffic (HTTP only).</p>
|
||||
<p>Using the <code>AddHeader</code> directive, you can <strong>add/insert HTTP headers</strong> to outgoing traffic.</p>
|
||||
|
||||
<p>If you're looking to build a custom web proxy, Tinyproxy is <strong>easy to modify</strong> to your custom needs. The source is straightforward, adhering to the KISS principle. As such, it can be used as a foundation for anything you may need a web proxy to do.</p>
|
||||
|
||||
<p>Tinyproxy has <strong>privacy features</strong> which can let you configure which HTTP headers should be allowed through, and which should be blocked. This allows you to restrict both what data comes to your web browser from the HTTP server (e.g., cookies), and to restrict what data is allowed through from your web browser to the HTTP server (e.g., version information). Note that these features do not affect HTTPS connections.</p>
|
||||
<p>Tinyproxy has <strong>privacy features</strong> which can let you configure which HTTP headers should be allowed through, and which should be blocked. This allows you to restrict both what data comes to your web browser from the HTTP server (e.g., cookies), and to restrict what data is allowed through from your web browser to the HTTP server (e.g., version information).</p>
|
||||
|
||||
<p>Using the <strong>remote monitoring</strong> facility, you can access proxy statistics from afar, letting you know exactly how busy the proxy is.</p>
|
||||
|
||||
<p>You can configure Tinyproxy to <strong>control access</strong> by only allowing requests from a certain subnet, or from a certain interface, thus ensuring that random, unauthorized people will not be using your proxy.</p>
|
||||
|
||||
<p>With a bit of configuration (specifically, making Tinyproxy created files owned by a non-root user and running it on a port greater than 1024), Tinyproxy can be made to run without any special privileges, thus minimizing the chance of system compromise. In fact, it is <b>recommended</b> to run it as a regular/restricted user. Furthermore, it was designed with an eye towards preventing buffer overflows. The simplicity of the code ensures it remains easy to spot such bugs.</p>
|
||||
<p>With a bit of configuration (specifically, making Tinyproxy created files owned by a non-root user and running it on a port greater than 1024), Tinyproxy can be made to run without any special privileges, thus minimizing the chance of system compromise. Furthermore, it was designed with an eye towards preventing buffer overflows. The simplicity of the code ensures it remains easy to spot such bugs.</p>
|
||||
|
||||
<h2>
|
||||
<a id="downloads" class="anchor" href="#downloads" aria-hidden="true"><span class="octicon octicon-link"></span></a>Downloads</h2>
|
||||
|
||||
<p>Note that many distributions ship horribly outdated versions of tinyproxy, therefore it is recommended to compile it from source.</p>
|
||||
|
||||
<ul>
|
||||
<li>On Red Hat Enterprise Linux, or its derivatives such as CentOS, install Tinyproxy from the EPEL repository by running yum install tinyproxy.</li>
|
||||
<li>On Fedora, install Tinyproxy by running yum install tinyproxy.</li>
|
||||
@ -72,7 +70,7 @@
|
||||
<li>Mac OS X users can check MacPorts to see if the Tinyproxy port there is recent enough.</li>
|
||||
</ul>
|
||||
|
||||
<p>If you feel that the Tinyproxy binary package in your operating system is not recent (likely), please contact the package maintainer for that particular operating system. If this fails, you can always compile the latest stable, or even better, the latest git master version, from source code.</p>
|
||||
<p>If you feel that the Tinyproxy binary package in your operating system is not recent, please contact the package maintainer for that particular operating system. If this fails, you can always compile the latest stable version from source code.</p>
|
||||
|
||||
<p>We distribute Tinyproxy in source code form, and it has to be compiled in order to be used on your system. Please see the INSTALL file in the source code tree for build instructions. The current stable version of Tinyproxy is available on the <a href="https://github.com/tinyproxy/tinyproxy/releases">releases page</a>. The Tinyproxy NEWS file contains the release notes. You can verify the tarball using its PGP signature. You can also browse the older releases of Tinyproxy.</p>
|
||||
|
||||
@ -80,19 +78,5 @@
|
||||
|
||||
<p>git clone <a href="https://github.com/tinyproxy/tinyproxy.git">https://github.com/tinyproxy/tinyproxy.git</a></p>
|
||||
|
||||
<h2>
|
||||
<a id="quickstart" class="anchor" href="#quickstart" aria-hidden="true"><span class="octicon octicon-link"></span></a>Quickstart</h2>
|
||||
|
||||
<p>The quickest way to get started is using a minimal config file like the below:</p>
|
||||
|
||||
<pre><code>
|
||||
Port 8888
|
||||
Listen 127.0.0.1
|
||||
Timeout 600
|
||||
Allow 127.0.0.1
|
||||
</code></pre>
|
||||
|
||||
<p>And then simply run <code>tinyproxy -d -c tinyproxy.conf</code> as your current user. This starts tinyproxy in foreground mode with <code>tinyproxy.conf</code> as its config, while logging to stdout. Now, all programs supporting a HTTP proxy can use 127.0.0.1:8888 as a proxy. You can try it out using <code>http_proxy=127.0.0.1:8888 curl example.com</code>.</p>
|
||||
|
||||
<h2>
|
||||
<a id="documentation" class="anchor" href="#documentation" aria-hidden="true"><span class="octicon octicon-link"></span></a>Documentation</h2>
|
||||
|
@ -12,7 +12,6 @@ edit = sed \
|
||||
-e 's|@datarootdir[@]|$(datarootdir)|g' \
|
||||
-e 's|@pkgsysconfdir[@]|$(pkgsysconfdir)|g' \
|
||||
-e 's|@localstatedir[@]|$(localstatedir)|g' \
|
||||
-e 's|@runstatedir[@]|$(runstatedir)|g' \
|
||||
-e 's|@pkgdatadir[@]|$(pkgdatadir)|g' \
|
||||
-e 's|@prefix[@]|$(prefix)|g' \
|
||||
-e 's|@TINYPROXY_STATHOST[@]|$(TINYPROXY_STATHOST)|g'
|
||||
|
@ -3,7 +3,7 @@
|
||||
##
|
||||
## This example tinyproxy.conf file contains example settings
|
||||
## with explanations in comments. For decriptions of all
|
||||
## parameters, see the tinyproxy.conf(5) manual page.
|
||||
## parameters, see the tinproxy.conf(5) manual page.
|
||||
##
|
||||
|
||||
#
|
||||
@ -56,8 +56,8 @@ Timeout 600
|
||||
# /usr/share/tinyproxy
|
||||
# /etc/tinyproxy
|
||||
#
|
||||
#ErrorFile 404 "@pkgdatadir@/404.html"
|
||||
#ErrorFile 400 "@pkgdatadir@/400.html"
|
||||
#ErrorFile 502 "@pkgdatadir@/502.html"
|
||||
#ErrorFile 503 "@pkgdatadir@/503.html"
|
||||
#ErrorFile 403 "@pkgdatadir@/403.html"
|
||||
#ErrorFile 408 "@pkgdatadir@/408.html"
|
||||
@ -124,7 +124,7 @@ LogLevel Info
|
||||
# can be used for signalling purposes.
|
||||
# If not specified, no pidfile will be written.
|
||||
#
|
||||
#PidFile "@runstatedir@/tinyproxy/tinyproxy.pid"
|
||||
#PidFile "@localstatedir@/run/tinyproxy/tinyproxy.pid"
|
||||
|
||||
#
|
||||
# XTinyproxy: Tell Tinyproxy to include the X-Tinyproxy header, which
|
||||
@ -205,13 +205,6 @@ Allow ::1
|
||||
# users.
|
||||
#BasicAuth user password
|
||||
|
||||
# BasicAuthRealm : In case BasicAuth is configured, the "realm" information.
|
||||
# "Proxy Authentication Required" status http 407 "error-response" can be
|
||||
# customized.
|
||||
#
|
||||
# - defaults in code to "Tinyproxy" (PACKAGE_NAME), if not configured.
|
||||
#BasicAuthRealm "Tinyproxy"
|
||||
|
||||
#
|
||||
# AddHeader: Adds the specified headers to outgoing HTTP requests that
|
||||
# Tinyproxy makes. Note that this option will not work for HTTPS
|
||||
@ -247,9 +240,10 @@ ViaProxyName "tinyproxy"
|
||||
#FilterURLs On
|
||||
|
||||
#
|
||||
# FilterType: Use bre (default), ere, or fnmatch for filtering.
|
||||
# FilterExtended: Use POSIX Extended regular expressions rather than
|
||||
# basic.
|
||||
#
|
||||
#FilterType fnmatch
|
||||
#FilterExtended On
|
||||
|
||||
#
|
||||
# FilterCaseSensitive: Use case sensitive regular expressions.
|
||||
@ -327,3 +321,6 @@ ViaProxyName "tinyproxy"
|
||||
# If not set then no rewriting occurs.
|
||||
#
|
||||
#ReverseBaseURL "http://localhost:8888/"
|
||||
|
||||
|
||||
|
||||
|
@ -24,7 +24,6 @@ AM_CPPFLAGS = \
|
||||
-DLOCALSTATEDIR=\"${localstatedir}\"
|
||||
|
||||
tinyproxy_SOURCES = \
|
||||
hostspec.c hostspec.h \
|
||||
acl.c acl.h \
|
||||
anonymous.c anonymous.h \
|
||||
buffer.c buffer.h \
|
||||
@ -61,11 +60,22 @@ EXTRA_tinyproxy_SOURCES = filter.c filter.h \
|
||||
tinyproxy_DEPENDENCIES = @ADDITIONAL_OBJECTS@
|
||||
tinyproxy_LDADD = @ADDITIONAL_OBJECTS@ -lpthread
|
||||
|
||||
CLEANFILES =
|
||||
|
||||
if HAVE_GPERF
|
||||
conf-tokens.c: conf-tokens-gperf.inc
|
||||
conf-tokens-gperf.inc: conf-tokens.gperf
|
||||
$(GPERF) $< > $@
|
||||
endif
|
||||
|
||||
EXTRA_DIST = conf-tokens.gperf conf-tokens-gperf.inc
|
||||
if HAVE_RAGEL
|
||||
conf.c: conf_regex.inc
|
||||
conf_regex.inc: conf_regex.rl
|
||||
$(RAGEL) $(RAGEL_FLAGS) -o $@ $<
|
||||
|
||||
CLEANFILES += conf_regex.inc
|
||||
endif
|
||||
|
||||
|
||||
EXTRA_DIST = conf-tokens.gperf conf_regex.rl
|
||||
|
||||
|
149
src/acl.c
149
src/acl.c
@ -29,7 +29,16 @@
|
||||
#include "network.h"
|
||||
#include "sock.h"
|
||||
#include "sblist.h"
|
||||
#include "hostspec.h"
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
/* Define how long an IPv6 address is in bytes (128 bits, 16 bytes) */
|
||||
#define IPV6_LEN 16
|
||||
|
||||
enum acl_type {
|
||||
ACL_STRING,
|
||||
ACL_NUMERIC
|
||||
};
|
||||
|
||||
/*
|
||||
* Hold the information about a particular access control. We store
|
||||
@ -38,9 +47,66 @@
|
||||
*/
|
||||
struct acl_s {
|
||||
acl_access_t access;
|
||||
struct hostspec h;
|
||||
enum acl_type type;
|
||||
union {
|
||||
char *string;
|
||||
struct {
|
||||
unsigned char network[IPV6_LEN];
|
||||
unsigned char mask[IPV6_LEN];
|
||||
} ip;
|
||||
} address;
|
||||
};
|
||||
|
||||
/*
|
||||
* Fills in the netmask array given a numeric value.
|
||||
*
|
||||
* Returns:
|
||||
* 0 on success
|
||||
* -1 on failure (invalid mask value)
|
||||
*
|
||||
*/
|
||||
static int
|
||||
fill_netmask_array (char *bitmask_string, int v6,
|
||||
unsigned char array[], size_t len)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned long int mask;
|
||||
char *endptr;
|
||||
|
||||
errno = 0; /* to distinguish success/failure after call */
|
||||
mask = strtoul (bitmask_string, &endptr, 10);
|
||||
|
||||
/* check for various conversion errors */
|
||||
if ((errno == ERANGE && mask == ULONG_MAX)
|
||||
|| (errno != 0 && mask == 0) || (endptr == bitmask_string))
|
||||
return -1;
|
||||
|
||||
if (v6 == 0) {
|
||||
/* The mask comparison is done as an IPv6 address, so
|
||||
* convert to a longer mask in the case of IPv4
|
||||
* addresses. */
|
||||
mask += 12 * 8;
|
||||
}
|
||||
|
||||
/* check valid range for a bit mask */
|
||||
if (mask > (8 * len))
|
||||
return -1;
|
||||
|
||||
/* we have a valid range to fill in the array */
|
||||
for (i = 0; i != len; ++i) {
|
||||
if (mask >= 8) {
|
||||
array[i] = 0xff;
|
||||
mask -= 8;
|
||||
} else if (mask > 0) {
|
||||
array[i] = (unsigned char) (0xff << (8 - mask));
|
||||
mask = 0;
|
||||
} else {
|
||||
array[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the access list has not been set up, create it.
|
||||
@ -72,6 +138,7 @@ int
|
||||
insert_acl (char *location, acl_access_t access_type, acl_list_t *access_list)
|
||||
{
|
||||
struct acl_s acl;
|
||||
char *mask, ip_dst[IPV6_LEN];
|
||||
|
||||
assert (location != NULL);
|
||||
|
||||
@ -83,11 +150,55 @@ insert_acl (char *location, acl_access_t access_type, acl_list_t *access_list)
|
||||
*/
|
||||
memset (&acl, 0, sizeof (struct acl_s));
|
||||
acl.access = access_type;
|
||||
if(hostspec_parse(location, &acl.h) || acl.h.type == HST_NONE)
|
||||
return -1;
|
||||
|
||||
if ((mask = strrchr(location, '/')))
|
||||
*(mask++) = 0;
|
||||
|
||||
/*
|
||||
* Check for a valid IP address (the simplest case) first.
|
||||
*/
|
||||
if (full_inet_pton (location, ip_dst) > 0) {
|
||||
acl.type = ACL_NUMERIC;
|
||||
memcpy (acl.address.ip.network, ip_dst, IPV6_LEN);
|
||||
if(!mask) memset (acl.address.ip.mask, 0xff, IPV6_LEN);
|
||||
else {
|
||||
char dst[sizeof(struct in6_addr)];
|
||||
int v6, i;
|
||||
/* Check if the IP address before the netmask is
|
||||
* an IPv6 address */
|
||||
if (inet_pton(AF_INET6, location, dst) > 0)
|
||||
v6 = 1;
|
||||
else
|
||||
v6 = 0;
|
||||
|
||||
if (fill_netmask_array
|
||||
(mask, v6, &(acl.address.ip.mask[0]), IPV6_LEN)
|
||||
< 0)
|
||||
goto err;
|
||||
|
||||
for (i = 0; i < IPV6_LEN; i++)
|
||||
acl.address.ip.network[i] = ip_dst[i] &
|
||||
acl.address.ip.mask[i];
|
||||
}
|
||||
} else {
|
||||
/* either bogus IP or hostname */
|
||||
/* bogus ipv6 ? */
|
||||
if (mask || strchr (location, ':'))
|
||||
goto err;
|
||||
|
||||
/* In all likelihood a string */
|
||||
acl.type = ACL_STRING;
|
||||
acl.address.string = safestrdup (location);
|
||||
if (!acl.address.string)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if(!sblist_add(*access_list, &acl)) return -1;
|
||||
return 0;
|
||||
err:;
|
||||
/* restore mask for proper error message */
|
||||
if(mask) *(--mask) = '/';
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -108,7 +219,7 @@ acl_string_processing (struct acl_s *acl, const char *ip_address,
|
||||
size_t test_length, match_length;
|
||||
char ipbuf[512];
|
||||
|
||||
assert (acl && acl->h.type == HST_STRING);
|
||||
assert (acl && acl->type == ACL_STRING);
|
||||
assert (ip_address && strlen (ip_address) > 0);
|
||||
|
||||
/*
|
||||
@ -116,11 +227,11 @@ acl_string_processing (struct acl_s *acl, const char *ip_address,
|
||||
* do a string based test only; otherwise, we can do a reverse
|
||||
* lookup test as well.
|
||||
*/
|
||||
if (acl->h.address.string[0] != '.') {
|
||||
if (acl->address.string[0] != '.') {
|
||||
memset (&hints, 0, sizeof (struct addrinfo));
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
if (getaddrinfo (acl->h.address.string, NULL, &hints, &res) != 0)
|
||||
if (getaddrinfo (acl->address.string, NULL, &hints, &res) != 0)
|
||||
goto STRING_TEST;
|
||||
|
||||
ressave = res;
|
||||
@ -154,7 +265,7 @@ STRING_TEST:
|
||||
}
|
||||
|
||||
test_length = strlen (string_addr);
|
||||
match_length = strlen (acl->h.address.string);
|
||||
match_length = strlen (acl->address.string);
|
||||
|
||||
/*
|
||||
* If the string length is shorter than AC string, return a -1 so
|
||||
@ -165,7 +276,7 @@ STRING_TEST:
|
||||
|
||||
if (strcasecmp
|
||||
(string_addr + (test_length - match_length),
|
||||
acl->h.address.string) == 0) {
|
||||
acl->address.string) == 0) {
|
||||
if (acl->access == ACL_DENY)
|
||||
return 0;
|
||||
else
|
||||
@ -189,11 +300,11 @@ static int check_numeric_acl (const struct acl_s *acl, uint8_t addr[IPV6_LEN])
|
||||
uint8_t x, y;
|
||||
int i;
|
||||
|
||||
assert (acl && acl->h.type == HST_NUMERIC);
|
||||
assert (acl && acl->type == ACL_NUMERIC);
|
||||
|
||||
for (i = 0; i != IPV6_LEN; ++i) {
|
||||
x = addr[i] & acl->h.address.ip.mask[i];
|
||||
y = acl->h.address.ip.network[i];
|
||||
x = addr[i] & acl->address.ip.mask[i];
|
||||
y = acl->address.ip.network[i];
|
||||
|
||||
/* If x and y don't match, the IP addresses don't match */
|
||||
if (x != y)
|
||||
@ -234,12 +345,12 @@ int check_acl (const char *ip, union sockaddr_union *addr, acl_list_t access_lis
|
||||
|
||||
for (i = 0; i < sblist_getsize (access_list); ++i) {
|
||||
acl = sblist_get (access_list, i);
|
||||
switch (acl->h.type) {
|
||||
case HST_STRING:
|
||||
switch (acl->type) {
|
||||
case ACL_STRING:
|
||||
perm = acl_string_processing (acl, ip, addr, string_addr);
|
||||
break;
|
||||
|
||||
case HST_NUMERIC:
|
||||
case ACL_NUMERIC:
|
||||
if (ip[0] == '\0')
|
||||
continue;
|
||||
|
||||
@ -247,10 +358,6 @@ int check_acl (const char *ip, union sockaddr_union *addr, acl_list_t access_lis
|
||||
? check_numeric_acl (acl, numeric_addr)
|
||||
: -1;
|
||||
break;
|
||||
|
||||
case HST_NONE:
|
||||
perm = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -287,8 +394,8 @@ void flush_access_list (acl_list_t access_list)
|
||||
*/
|
||||
for (i = 0; i < sblist_getsize (access_list); ++i) {
|
||||
acl = sblist_get (access_list, i);
|
||||
if (acl->h.type == HST_STRING) {
|
||||
safefree (acl->h.address.string);
|
||||
if (acl->type == ACL_STRING) {
|
||||
safefree (acl->address.string);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ void child_main_loop (void)
|
||||
int connfd;
|
||||
union sockaddr_union cliaddr_storage;
|
||||
struct sockaddr *cliaddr = (void*) &cliaddr_storage;
|
||||
socklen_t clilen;
|
||||
socklen_t clilen = sizeof(cliaddr_storage);
|
||||
int nfds = sblist_getsize(listen_fds);
|
||||
pollfd_struct *fds = safecalloc(nfds, sizeof *fds);
|
||||
ssize_t i;
|
||||
@ -167,7 +167,6 @@ void child_main_loop (void)
|
||||
* Continue handling this connection.
|
||||
*/
|
||||
|
||||
clilen = sizeof(cliaddr_storage);
|
||||
connfd = accept (listenfd, cliaddr, &clilen);
|
||||
|
||||
|
||||
|
@ -68,7 +68,6 @@
|
||||
# include <arpa/inet.h>
|
||||
# include <grp.h>
|
||||
# include <pwd.h>
|
||||
# include <limits.h>
|
||||
|
||||
/* rest - some oddball headers */
|
||||
#ifdef HAVE_VALUES_H
|
||||
|
@ -34,7 +34,6 @@ config_directive_find (register const char *str, register size_t len)
|
||||
{"defaulterrorfile", CD_defaulterrorfile},
|
||||
{"startservers", CD_startservers},
|
||||
{"filtercasesensitive", CD_filtercasesensitive},
|
||||
{"filtertype", CD_filtertype},
|
||||
{"filterurls", CD_filterurls},
|
||||
{"filter", CD_filter},
|
||||
{"reversemagic", CD_reversemagic},
|
||||
@ -57,7 +56,6 @@ config_directive_find (register const char *str, register size_t len)
|
||||
{"connectport", CD_connectport},
|
||||
{"logfile", CD_logfile},
|
||||
{"basicauth", CD_basicauth},
|
||||
{"basicauthrealm", CD_basicauthrealm},
|
||||
{"addheader", CD_addheader},
|
||||
{"maxrequestsperchild", CD_maxrequestsperchild}
|
||||
};
|
||||
|
@ -44,7 +44,6 @@ allow, CD_allow
|
||||
deny, CD_deny
|
||||
bind, CD_bind
|
||||
basicauth, CD_basicauth
|
||||
basicauthrealm, CD_basicauthrealm
|
||||
errorfile, CD_errorfile
|
||||
addheader, CD_addheader
|
||||
filter, CD_filter
|
||||
@ -52,7 +51,6 @@ filterurls, CD_filterurls
|
||||
filterextended, CD_filterextended
|
||||
filterdefaultdeny, CD_filterdefaultdeny
|
||||
filtercasesensitive, CD_filtercasesensitive
|
||||
filtertype, CD_filtertype
|
||||
reversebaseurl, CD_reversebaseurl
|
||||
reverseonly, CD_reverseonly
|
||||
reversemagic, CD_reversemagic
|
||||
|
@ -29,12 +29,10 @@ CD_allow,
|
||||
CD_deny,
|
||||
CD_bind,
|
||||
CD_basicauth,
|
||||
CD_basicauthrealm,
|
||||
CD_errorfile,
|
||||
CD_addheader,
|
||||
CD_filter,
|
||||
CD_filterurls,
|
||||
CD_filtertype,
|
||||
CD_filterextended,
|
||||
CD_filterdefaultdeny,
|
||||
CD_filtercasesensitive,
|
||||
|
328
src/conf.c
328
src/conf.c
@ -40,48 +40,12 @@
|
||||
#include "basicauth.h"
|
||||
#include "conf-tokens.h"
|
||||
|
||||
#ifdef LINE_MAX
|
||||
#define TP_LINE_MAX LINE_MAX
|
||||
#else
|
||||
#define TP_LINE_MAX 1024
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The configuration directives are defined in the structure below. Each
|
||||
* directive requires a regular expression to match against, and a
|
||||
* function to call when the regex is matched.
|
||||
*
|
||||
* Below are defined certain constant regular expression strings that
|
||||
* can (and likely should) be used when building the regex for the
|
||||
* given directive.
|
||||
*/
|
||||
#define DIGIT "[0-9]"
|
||||
#define SPACE "[ \t]"
|
||||
#define WS SPACE "+"
|
||||
#define STR "\"([^\"]+)\""
|
||||
#define BOOL "(yes|on|no|off)"
|
||||
#define INT "(()" DIGIT "+)"
|
||||
#define ALNUM "([-a-z0-9._]+)"
|
||||
#define USERNAME "([^:]*)"
|
||||
#define PASSWORD "([^@]*)"
|
||||
#define IP "((([0-9]{1,3})\\.){3}[0-9]{1,3})"
|
||||
#define IPMASK "(" IP "(/" DIGIT "+)?)"
|
||||
#define IPV6SCOPE "((%[^ \t\\/]{1,16})?)"
|
||||
#define IPV6 "(" \
|
||||
"([0-9a-f:]{2,39})" IPV6SCOPE "|" \
|
||||
"([0-9a-f:]{0,29}:" IP ")" IPV6SCOPE \
|
||||
")"
|
||||
|
||||
#define IPV6MASK "(" IPV6 "(/" DIGIT "+)?)"
|
||||
#define BEGIN "^" SPACE "*"
|
||||
#define END SPACE "*$"
|
||||
|
||||
/*
|
||||
* Limit the maximum number of substring matches to a reasonably high
|
||||
* number. Given the usual structure of the configuration file, sixteen
|
||||
* substring matches should be plenty.
|
||||
*/
|
||||
#define RE_MAX_MATCHES 33
|
||||
#define RE_MAX_MATCHES 16
|
||||
|
||||
#define CP_WARN(FMT, ...) \
|
||||
log_message (LOG_WARNING, "line %lu: " FMT, lineno, __VA_ARGS__)
|
||||
@ -122,7 +86,6 @@ static HANDLE_FUNC (handle_disabled_feature)
|
||||
|
||||
static HANDLE_FUNC (handle_allow);
|
||||
static HANDLE_FUNC (handle_basicauth);
|
||||
static HANDLE_FUNC (handle_basicauthrealm);
|
||||
static HANDLE_FUNC (handle_anonymous);
|
||||
static HANDLE_FUNC (handle_bind);
|
||||
static HANDLE_FUNC (handle_bindsame);
|
||||
@ -137,7 +100,6 @@ static HANDLE_FUNC (handle_filtercasesensitive);
|
||||
static HANDLE_FUNC (handle_filterdefaultdeny);
|
||||
static HANDLE_FUNC (handle_filterextended);
|
||||
static HANDLE_FUNC (handle_filterurls);
|
||||
static HANDLE_FUNC (handle_filtertype);
|
||||
#endif
|
||||
static HANDLE_FUNC (handle_group);
|
||||
static HANDLE_FUNC (handle_listen);
|
||||
@ -180,7 +142,14 @@ static void config_free_regex (void);
|
||||
* do not follow the pattern above. This macro is for convenience
|
||||
* only.
|
||||
*/
|
||||
#define STDCONF(d, re, func) [CD_ ## d] = { BEGIN "()" WS re END, func, NULL }
|
||||
#ifdef HAVE_RAGEL
|
||||
#define RE2R_EXPORT static
|
||||
#include "conf_regex.inc"
|
||||
typedef int (*matchfunc)(const char*, const char*, size_t, regmatch_t[]);
|
||||
#define STDCONF(d, re, func) [CD_ ## d] = { func, re2r_match_ ## d }
|
||||
#else
|
||||
#define STDCONF(d, re, func) [CD_ ## d] = { func, BEGIN re END, NULL }
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Holds the regular expression used to match the configuration directive,
|
||||
@ -189,75 +158,15 @@ static void config_free_regex (void);
|
||||
* to be compiled one.
|
||||
*/
|
||||
struct {
|
||||
const char *re;
|
||||
CONFFILE_HANDLER handler;
|
||||
#ifndef HAVE_RAGEL
|
||||
const char *re;
|
||||
regex_t *cre;
|
||||
#else
|
||||
matchfunc mf;
|
||||
#endif
|
||||
} directives[] = {
|
||||
/* string arguments */
|
||||
STDCONF (basicauthrealm, STR, handle_basicauthrealm),
|
||||
STDCONF (logfile, STR, handle_logfile),
|
||||
STDCONF (pidfile, STR, handle_pidfile),
|
||||
STDCONF (anonymous, STR, handle_anonymous),
|
||||
STDCONF (viaproxyname, STR, handle_viaproxyname),
|
||||
STDCONF (defaulterrorfile, STR, handle_defaulterrorfile),
|
||||
STDCONF (statfile, STR, handle_statfile),
|
||||
STDCONF (stathost, STR, handle_stathost),
|
||||
STDCONF (xtinyproxy, BOOL, handle_xtinyproxy),
|
||||
/* boolean arguments */
|
||||
STDCONF (syslog, BOOL, handle_syslog),
|
||||
STDCONF (bindsame, BOOL, handle_bindsame),
|
||||
STDCONF (disableviaheader, BOOL, handle_disableviaheader),
|
||||
/* integer arguments */
|
||||
STDCONF (port, INT, handle_port),
|
||||
STDCONF (maxclients, INT, handle_maxclients),
|
||||
STDCONF (maxspareservers, INT, handle_obsolete),
|
||||
STDCONF (minspareservers, INT, handle_obsolete),
|
||||
STDCONF (startservers, INT, handle_obsolete),
|
||||
STDCONF (maxrequestsperchild, INT, handle_obsolete),
|
||||
STDCONF (timeout, INT, handle_timeout),
|
||||
STDCONF (connectport, INT, handle_connectport),
|
||||
/* alphanumeric arguments */
|
||||
STDCONF (user, ALNUM, handle_user),
|
||||
STDCONF (group, ALNUM, handle_group),
|
||||
/* ip arguments */
|
||||
STDCONF (listen, "(" IP "|" IPV6 ")", handle_listen),
|
||||
STDCONF (allow, "(" "(" IPMASK "|" IPV6MASK ")" "|" ALNUM ")",
|
||||
handle_allow),
|
||||
STDCONF (deny, "(" "(" IPMASK "|" IPV6MASK ")" "|" ALNUM ")",
|
||||
handle_deny),
|
||||
STDCONF (bind, "(" IP "|" IPV6 ")", handle_bind),
|
||||
/* other */
|
||||
STDCONF (basicauth, USERNAME WS PASSWORD, handle_basicauth),
|
||||
STDCONF (errorfile, INT WS STR, handle_errorfile),
|
||||
STDCONF (addheader, STR WS STR, handle_addheader),
|
||||
|
||||
#ifdef FILTER_ENABLE
|
||||
/* filtering */
|
||||
STDCONF (filter, STR, handle_filter),
|
||||
STDCONF (filterurls, BOOL, handle_filterurls),
|
||||
STDCONF (filterextended, BOOL, handle_filterextended),
|
||||
STDCONF (filterdefaultdeny, BOOL, handle_filterdefaultdeny),
|
||||
STDCONF (filtercasesensitive, BOOL, handle_filtercasesensitive),
|
||||
STDCONF (filtertype, "(bre|ere|fnmatch)", handle_filtertype),
|
||||
#endif
|
||||
#ifdef REVERSE_SUPPORT
|
||||
/* Reverse proxy arguments */
|
||||
STDCONF (reversebaseurl, STR, handle_reversebaseurl),
|
||||
STDCONF (reverseonly, BOOL, handle_reverseonly),
|
||||
STDCONF (reversemagic, BOOL, handle_reversemagic),
|
||||
STDCONF (reversepath, STR "(" WS STR ")?", handle_reversepath),
|
||||
#endif
|
||||
#ifdef UPSTREAM_SUPPORT
|
||||
STDCONF (upstream,
|
||||
"(" "(none)" WS STR ")|" \
|
||||
"(" "(http|socks4|socks5)" WS \
|
||||
"(" USERNAME /*username*/ ":" PASSWORD /*password*/ "@" ")?"
|
||||
"(" IP "|" "\\[(" IPV6 ")\\]" "|" ALNUM ")"
|
||||
":" INT "(" WS STR ")?" ")", handle_upstream),
|
||||
#endif
|
||||
/* loglevel */
|
||||
STDCONF (loglevel, "(critical|error|warning|notice|connect|info)",
|
||||
handle_loglevel)
|
||||
#include "conf_regex.h"
|
||||
};
|
||||
|
||||
const unsigned int ndirectives = sizeof (directives) / sizeof (directives[0]);
|
||||
@ -296,14 +205,12 @@ void free_config (struct config_s *conf)
|
||||
char *k;
|
||||
htab_value *v;
|
||||
size_t it;
|
||||
safefree (conf->basicauth_realm);
|
||||
safefree (conf->logf_name);
|
||||
safefree (conf->stathost);
|
||||
safefree (conf->user);
|
||||
safefree (conf->group);
|
||||
stringlist_free(conf->basicauth_list);
|
||||
stringlist_free(conf->listen_addrs);
|
||||
stringlist_free(conf->bind_addrs);
|
||||
#ifdef FILTER_ENABLE
|
||||
safefree (conf->filter);
|
||||
#endif /* FILTER_ENABLE */
|
||||
@ -315,6 +222,7 @@ void free_config (struct config_s *conf)
|
||||
free_upstream_list (conf->upstream_list);
|
||||
#endif /* UPSTREAM_SUPPORT */
|
||||
safefree (conf->pidpath);
|
||||
safefree (conf->bind_address);
|
||||
safefree (conf->via_proxy_name);
|
||||
if (conf->errorpages) {
|
||||
it = 0;
|
||||
@ -351,23 +259,26 @@ config_init (void)
|
||||
{
|
||||
unsigned int i, r;
|
||||
|
||||
(void) r;
|
||||
|
||||
for (i = 0; i != ndirectives; ++i) {
|
||||
assert (!directives[i].cre);
|
||||
|
||||
if (!directives[i].handler) {
|
||||
directives[i].handler = handle_disabled_feature;
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifndef HAVE_RAGEL
|
||||
directives[i].cre = (regex_t *) safemalloc (sizeof (regex_t));
|
||||
if (!directives[i].cre)
|
||||
return -1;
|
||||
|
||||
r = regcomp (directives[i].cre,
|
||||
directives[i].re,
|
||||
REG_EXTENDED | REG_ICASE | REG_NEWLINE);
|
||||
REG_EXTENDED | REG_NEWLINE);
|
||||
if (r)
|
||||
return r;
|
||||
#endif
|
||||
}
|
||||
|
||||
atexit (config_free_regex);
|
||||
@ -382,6 +293,7 @@ config_init (void)
|
||||
static void
|
||||
config_free_regex (void)
|
||||
{
|
||||
#ifndef HAVE_RAGEL
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ndirectives; i++) {
|
||||
@ -391,6 +303,7 @@ config_free_regex (void)
|
||||
directives[i].cre = NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@ -401,18 +314,25 @@ config_free_regex (void)
|
||||
* Returns 0 if a match was found and successfully processed; otherwise,
|
||||
* a negative number is returned.
|
||||
*/
|
||||
static int check_match (struct config_s *conf, const char *line,
|
||||
static int check_match (struct config_s *conf,
|
||||
const char *line, const char* lineend,
|
||||
unsigned long lineno, enum config_directive cd)
|
||||
{
|
||||
regmatch_t match[RE_MAX_MATCHES];
|
||||
unsigned int i = cd;
|
||||
|
||||
#ifndef HAVE_RAGEL
|
||||
(void) lineend;
|
||||
if (!directives[i].cre)
|
||||
return (*directives[i].handler) (conf, line, lineno, match);
|
||||
|
||||
if (!regexec
|
||||
(directives[i].cre, line, RE_MAX_MATCHES, match, 0))
|
||||
return (*directives[i].handler) (conf, line, lineno, match);
|
||||
#else
|
||||
if (!directives[i].mf(line, lineend, RE_MAX_MATCHES, match))
|
||||
return (*directives[i].handler) (conf, line, lineno, match);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -421,7 +341,7 @@ static int check_match (struct config_s *conf, const char *line,
|
||||
*/
|
||||
static int config_parse (struct config_s *conf, FILE * f)
|
||||
{
|
||||
char buffer[TP_LINE_MAX], *p, *q, c;
|
||||
char buffer[LINE_MAX], *p, *q;
|
||||
const struct config_directive_entry *e;
|
||||
unsigned long lineno = 1;
|
||||
|
||||
@ -431,12 +351,15 @@ static int config_parse (struct config_s *conf, FILE * f)
|
||||
while(isspace(*p))p++;
|
||||
if(!*p) continue;
|
||||
q = p;
|
||||
while(*q && !isspace(*q))q++;
|
||||
c = *q;
|
||||
while(!isspace(*q))q++;
|
||||
*q = 0;
|
||||
e = config_directive_find(p, strlen(p));
|
||||
*q = c;
|
||||
if (!e || e->value == CD_NIL || check_match (conf, q, lineno, e->value)) {
|
||||
++q;
|
||||
while(isspace(*q))++q;
|
||||
p = q;
|
||||
while(*p && *p != '\n') ++p;
|
||||
while(isspace(*p)) *(p--) = 0;
|
||||
if (!e || e->value == CD_NIL || check_match (conf, q, ++p, lineno, e->value)) {
|
||||
fprintf (stderr, "ERROR: Syntax error on line %lu\n", lineno);
|
||||
return 1;
|
||||
}
|
||||
@ -484,7 +407,6 @@ static void initialize_config_defaults (struct config_s *conf)
|
||||
* (FIXME: Should have a better API for all this)
|
||||
*/
|
||||
conf->errorpages = NULL;
|
||||
conf->basicauth_realm = safestrdup (PACKAGE_NAME);
|
||||
conf->stathost = safestrdup (TINYPROXY_STATHOST);
|
||||
conf->idletimeout = MAX_IDLE_TIME;
|
||||
conf->logf_name = NULL;
|
||||
@ -518,7 +440,7 @@ int reload_config_file (const char *config_fname, struct config_s *conf)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!conf->user && !geteuid()) {
|
||||
if (!conf->user) {
|
||||
log_message (LOG_WARNING, "You SHOULD set a UserName in the "
|
||||
"config file. Using current user instead.");
|
||||
}
|
||||
@ -638,24 +560,21 @@ set_int_arg (unsigned int *var, const char *line, regmatch_t * match)
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
static HANDLE_FUNC (handle_basicauthrealm)
|
||||
{
|
||||
return set_string_arg (&conf->basicauth_realm, line, &match[2]);
|
||||
}
|
||||
#define MGROUP1 -1
|
||||
|
||||
static HANDLE_FUNC (handle_logfile)
|
||||
{
|
||||
return set_string_arg (&conf->logf_name, line, &match[2]);
|
||||
return set_string_arg (&conf->logf_name, line, &match[MGROUP1+2]);
|
||||
}
|
||||
|
||||
static HANDLE_FUNC (handle_pidfile)
|
||||
{
|
||||
return set_string_arg (&conf->pidpath, line, &match[2]);
|
||||
return set_string_arg (&conf->pidpath, line, &match[MGROUP1+2]);
|
||||
}
|
||||
|
||||
static HANDLE_FUNC (handle_anonymous)
|
||||
{
|
||||
char *arg = get_string_arg (line, &match[2]);
|
||||
char *arg = get_string_arg (line, &match[MGROUP1+2]);
|
||||
|
||||
if (!arg)
|
||||
return -1;
|
||||
@ -671,7 +590,7 @@ static HANDLE_FUNC (handle_anonymous)
|
||||
|
||||
static HANDLE_FUNC (handle_viaproxyname)
|
||||
{
|
||||
int r = set_string_arg (&conf->via_proxy_name, line, &match[2]);
|
||||
int r = set_string_arg (&conf->via_proxy_name, line, &match[MGROUP1+2]);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
@ -683,7 +602,7 @@ static HANDLE_FUNC (handle_viaproxyname)
|
||||
|
||||
static HANDLE_FUNC (handle_disableviaheader)
|
||||
{
|
||||
int r = set_bool_arg (&conf->disable_viaheader, line, &match[2]);
|
||||
int r = set_bool_arg (&conf->disable_viaheader, line, &match[MGROUP1+2]);
|
||||
|
||||
if (r) {
|
||||
return r;
|
||||
@ -696,17 +615,17 @@ static HANDLE_FUNC (handle_disableviaheader)
|
||||
|
||||
static HANDLE_FUNC (handle_defaulterrorfile)
|
||||
{
|
||||
return set_string_arg (&conf->errorpage_undef, line, &match[2]);
|
||||
return set_string_arg (&conf->errorpage_undef, line, &match[MGROUP1+2]);
|
||||
}
|
||||
|
||||
static HANDLE_FUNC (handle_statfile)
|
||||
{
|
||||
return set_string_arg (&conf->statpage, line, &match[2]);
|
||||
return set_string_arg (&conf->statpage, line, &match[MGROUP1+2]);
|
||||
}
|
||||
|
||||
static HANDLE_FUNC (handle_stathost)
|
||||
{
|
||||
int r = set_string_arg (&conf->stathost, line, &match[2]);
|
||||
int r = set_string_arg (&conf->stathost, line, &match[MGROUP1+2]);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
@ -717,10 +636,8 @@ static HANDLE_FUNC (handle_stathost)
|
||||
static HANDLE_FUNC (handle_xtinyproxy)
|
||||
{
|
||||
#ifdef XTINYPROXY_ENABLE
|
||||
return set_bool_arg (&conf->add_xtinyproxy, line, &match[2]);
|
||||
return set_bool_arg (&conf->add_xtinyproxy, line, &match[MGROUP1+2]);
|
||||
#else
|
||||
if(!get_bool_arg(line, &match[2]))
|
||||
return 0;
|
||||
fprintf (stderr,
|
||||
"XTinyproxy NOT Enabled! Recompile with --enable-xtinyproxy\n");
|
||||
return 1;
|
||||
@ -729,12 +646,12 @@ static HANDLE_FUNC (handle_xtinyproxy)
|
||||
|
||||
static HANDLE_FUNC (handle_syslog)
|
||||
{
|
||||
return set_bool_arg (&conf->syslog, line, &match[2]);
|
||||
return set_bool_arg (&conf->syslog, line, &match[MGROUP1+2]);
|
||||
}
|
||||
|
||||
static HANDLE_FUNC (handle_bindsame)
|
||||
{
|
||||
int r = set_bool_arg (&conf->bindsame, line, &match[2]);
|
||||
int r = set_bool_arg (&conf->bindsame, line, &match[MGROUP1+2]);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
@ -744,7 +661,7 @@ static HANDLE_FUNC (handle_bindsame)
|
||||
|
||||
static HANDLE_FUNC (handle_port)
|
||||
{
|
||||
set_int_arg (&conf->port, line, &match[2]);
|
||||
set_int_arg (&conf->port, line, &match[MGROUP1+2]);
|
||||
|
||||
if (conf->port > 65535) {
|
||||
fprintf (stderr, "Bad port number (%d) supplied for Port.\n",
|
||||
@ -757,7 +674,7 @@ static HANDLE_FUNC (handle_port)
|
||||
|
||||
static HANDLE_FUNC (handle_maxclients)
|
||||
{
|
||||
set_int_arg (&conf->maxclients, line, &match[2]);
|
||||
set_int_arg (&conf->maxclients, line, &match[MGROUP1+2]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -770,24 +687,24 @@ static HANDLE_FUNC (handle_obsolete)
|
||||
|
||||
static HANDLE_FUNC (handle_timeout)
|
||||
{
|
||||
return set_int_arg (&conf->idletimeout, line, &match[2]);
|
||||
return set_int_arg (&conf->idletimeout, line, &match[MGROUP1+2]);
|
||||
}
|
||||
|
||||
static HANDLE_FUNC (handle_connectport)
|
||||
{
|
||||
add_connect_port_allowed (get_long_arg (line, &match[2]),
|
||||
add_connect_port_allowed (get_long_arg (line, &match[MGROUP1+2]),
|
||||
&conf->connect_ports);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static HANDLE_FUNC (handle_user)
|
||||
{
|
||||
return set_string_arg (&conf->user, line, &match[2]);
|
||||
return set_string_arg (&conf->user, line, &match[MGROUP1+2]);
|
||||
}
|
||||
|
||||
static HANDLE_FUNC (handle_group)
|
||||
{
|
||||
return set_string_arg (&conf->group, line, &match[2]);
|
||||
return set_string_arg (&conf->group, line, &match[MGROUP1+2]);
|
||||
}
|
||||
|
||||
static void warn_invalid_address(char *arg, unsigned long lineno) {
|
||||
@ -796,7 +713,7 @@ static void warn_invalid_address(char *arg, unsigned long lineno) {
|
||||
|
||||
static HANDLE_FUNC (handle_allow)
|
||||
{
|
||||
char *arg = get_string_arg (line, &match[2]);
|
||||
char *arg = get_string_arg (line, &match[MGROUP1+2]);
|
||||
|
||||
if(insert_acl (arg, ACL_ALLOW, &conf->access_list) < 0)
|
||||
warn_invalid_address (arg, lineno);
|
||||
@ -806,7 +723,7 @@ static HANDLE_FUNC (handle_allow)
|
||||
|
||||
static HANDLE_FUNC (handle_deny)
|
||||
{
|
||||
char *arg = get_string_arg (line, &match[2]);
|
||||
char *arg = get_string_arg (line, &match[MGROUP1+2]);
|
||||
|
||||
if(insert_acl (arg, ACL_DENY, &conf->access_list) < 0)
|
||||
warn_invalid_address (arg, lineno);
|
||||
@ -816,33 +733,18 @@ static HANDLE_FUNC (handle_deny)
|
||||
|
||||
static HANDLE_FUNC (handle_bind)
|
||||
{
|
||||
char *arg = get_string_arg (line, &match[2]);
|
||||
|
||||
if (arg == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (conf->bind_addrs == NULL) {
|
||||
conf->bind_addrs = sblist_new(sizeof(char*), 16);
|
||||
if (conf->bind_addrs == NULL) {
|
||||
CP_WARN ("Could not create a list "
|
||||
"of bind addresses.", "");
|
||||
safefree(arg);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
sblist_add (conf->bind_addrs, &arg);
|
||||
int r = set_string_arg (&conf->bind_address, line, &match[MGROUP1+2]);
|
||||
|
||||
if (r)
|
||||
return r;
|
||||
log_message (LOG_INFO,
|
||||
"Added bind address [%s] for outgoing connections.", arg);
|
||||
|
||||
"Outgoing connections bound to IP %s", conf->bind_address);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static HANDLE_FUNC (handle_listen)
|
||||
{
|
||||
char *arg = get_string_arg (line, &match[2]);
|
||||
char *arg = get_string_arg (line, &match[MGROUP1+2]);
|
||||
|
||||
if (arg == NULL) {
|
||||
return -1;
|
||||
@ -867,15 +769,8 @@ static HANDLE_FUNC (handle_listen)
|
||||
|
||||
static HANDLE_FUNC (handle_errorfile)
|
||||
{
|
||||
/*
|
||||
* Because an integer is defined as ((0x)?[[:digit:]]+) _two_
|
||||
* match places are used. match[2] matches the full digit
|
||||
* string, while match[3] matches only the "0x" part if
|
||||
* present. This is why the "string" is located at
|
||||
* match[4] (rather than the more intuitive match[3].
|
||||
*/
|
||||
unsigned long int err = get_long_arg (line, &match[2]);
|
||||
char *page = get_string_arg (line, &match[4]);
|
||||
unsigned long int err = get_long_arg (line, &match[MGROUP1+2]);
|
||||
char *page = get_string_arg (line, &match[MGROUP1+3]);
|
||||
|
||||
if(add_new_errorpage (conf, page, err) < 0) {
|
||||
CP_WARN ("add_new_errorpage() failed: '%s'", page);
|
||||
@ -886,8 +781,8 @@ static HANDLE_FUNC (handle_errorfile)
|
||||
|
||||
static HANDLE_FUNC (handle_addheader)
|
||||
{
|
||||
char *name = get_string_arg (line, &match[2]);
|
||||
char *value = get_string_arg (line, &match[3]);
|
||||
char *name = get_string_arg (line, &match[MGROUP1+2]);
|
||||
char *value = get_string_arg (line, &match[MGROUP1+3]);
|
||||
http_header_t header;
|
||||
|
||||
if (!conf->add_headers) {
|
||||
@ -928,7 +823,7 @@ static HANDLE_FUNC (handle_loglevel)
|
||||
sizeof (log_levels) / sizeof (log_levels[0]);
|
||||
unsigned int i;
|
||||
|
||||
char *arg = get_string_arg (line, &match[2]);
|
||||
char *arg = get_string_arg (line, &match[MGROUP1+2]);
|
||||
|
||||
for (i = 0; i != nlevels; ++i) {
|
||||
if (!strcasecmp (arg, log_levels[i].string)) {
|
||||
@ -945,10 +840,10 @@ static HANDLE_FUNC (handle_loglevel)
|
||||
static HANDLE_FUNC (handle_basicauth)
|
||||
{
|
||||
char *user, *pass;
|
||||
user = get_string_arg(line, &match[2]);
|
||||
user = get_string_arg(line, &match[MGROUP1+2]);
|
||||
if (!user)
|
||||
return -1;
|
||||
pass = get_string_arg(line, &match[3]);
|
||||
pass = get_string_arg(line, &match[MGROUP1+3]);
|
||||
if (!pass) {
|
||||
safefree (user);
|
||||
return -1;
|
||||
@ -964,82 +859,50 @@ static HANDLE_FUNC (handle_basicauth)
|
||||
}
|
||||
|
||||
#ifdef FILTER_ENABLE
|
||||
|
||||
static void warn_deprecated(const char *arg, unsigned long lineno) {
|
||||
CP_WARN ("deprecated option %s", arg);
|
||||
}
|
||||
|
||||
static HANDLE_FUNC (handle_filter)
|
||||
{
|
||||
return set_string_arg (&conf->filter, line, &match[2]);
|
||||
return set_string_arg (&conf->filter, line, &match[MGROUP1+2]);
|
||||
}
|
||||
|
||||
static HANDLE_FUNC (handle_filterurls)
|
||||
{
|
||||
conf->filter_opts |=
|
||||
get_bool_arg (line, &match[2]) * FILTER_OPT_URL;
|
||||
return 0;
|
||||
return set_bool_arg (&conf->filter_url, line, &match[MGROUP1+2]);
|
||||
}
|
||||
|
||||
static HANDLE_FUNC (handle_filterextended)
|
||||
{
|
||||
warn_deprecated("FilterExtended, use FilterType", lineno);
|
||||
conf->filter_opts |=
|
||||
get_bool_arg (line, &match[2]) * FILTER_OPT_TYPE_ERE;
|
||||
return 0;
|
||||
return set_bool_arg (&conf->filter_extended, line, &match[MGROUP1+2]);
|
||||
}
|
||||
|
||||
static HANDLE_FUNC (handle_filterdefaultdeny)
|
||||
{
|
||||
assert (match[2].rm_so != -1);
|
||||
conf->filter_opts |=
|
||||
get_bool_arg (line, &match[2]) * FILTER_OPT_DEFAULT_DENY;
|
||||
assert (match[MGROUP1+2].rm_so != -1);
|
||||
|
||||
if (get_bool_arg (line, &match[MGROUP1+2]))
|
||||
filter_set_default_policy (FILTER_DEFAULT_DENY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static HANDLE_FUNC (handle_filtercasesensitive)
|
||||
{
|
||||
conf->filter_opts |=
|
||||
get_bool_arg (line, &match[2]) * FILTER_OPT_CASESENSITIVE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static HANDLE_FUNC (handle_filtertype)
|
||||
{
|
||||
static const struct { unsigned short flag; char type[8]; }
|
||||
ftmap[] = {
|
||||
{FILTER_OPT_TYPE_ERE, "ere"},
|
||||
{FILTER_OPT_TYPE_BRE, "bre"},
|
||||
{FILTER_OPT_TYPE_FNMATCH, "fnmatch"},
|
||||
};
|
||||
char *type;
|
||||
unsigned i;
|
||||
type = get_string_arg(line, &match[2]);
|
||||
if (!type) return -1;
|
||||
|
||||
for(i=0;i<sizeof(ftmap)/sizeof(ftmap[0]);++i)
|
||||
if(!strcasecmp(ftmap[i].type, type))
|
||||
conf->filter_opts |= ftmap[i].flag;
|
||||
|
||||
safefree (type);
|
||||
return 0;
|
||||
return set_bool_arg (&conf->filter_casesensitive, line, &match[MGROUP1+2]);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef REVERSE_SUPPORT
|
||||
static HANDLE_FUNC (handle_reverseonly)
|
||||
{
|
||||
return set_bool_arg (&conf->reverseonly, line, &match[2]);
|
||||
return set_bool_arg (&conf->reverseonly, line, &match[MGROUP1+2]);
|
||||
}
|
||||
|
||||
static HANDLE_FUNC (handle_reversemagic)
|
||||
{
|
||||
return set_bool_arg (&conf->reversemagic, line, &match[2]);
|
||||
return set_bool_arg (&conf->reversemagic, line, &match[MGROUP1+2]);
|
||||
}
|
||||
|
||||
static HANDLE_FUNC (handle_reversebaseurl)
|
||||
{
|
||||
return set_string_arg (&conf->reversebaseurl, line, &match[2]);
|
||||
return set_string_arg (&conf->reversebaseurl, line, &match[MGROUP1+2]);
|
||||
}
|
||||
|
||||
static HANDLE_FUNC (handle_reversepath)
|
||||
@ -1049,12 +912,12 @@ static HANDLE_FUNC (handle_reversepath)
|
||||
*/
|
||||
char *arg1, *arg2;
|
||||
|
||||
arg1 = get_string_arg (line, &match[2]);
|
||||
arg1 = get_string_arg (line, &match[MGROUP1+2]);
|
||||
if (!arg1)
|
||||
return -1;
|
||||
|
||||
if (match[4].rm_so != -1) {
|
||||
arg2 = get_string_arg (line, &match[4]);
|
||||
if (match[MGROUP1+4].rm_so != -1) {
|
||||
arg2 = get_string_arg (line, &match[MGROUP1+4]);
|
||||
if (!arg2) {
|
||||
safefree (arg1);
|
||||
return -1;
|
||||
@ -1095,12 +958,12 @@ static HANDLE_FUNC (handle_upstream)
|
||||
enum proxy_type pt;
|
||||
enum upstream_build_error ube;
|
||||
|
||||
if (match[3].rm_so != -1) {
|
||||
tmp = get_string_arg (line, &match[3]);
|
||||
if (match[MGROUP1+3].rm_so != -1) {
|
||||
tmp = get_string_arg (line, &match[MGROUP1+3]);
|
||||
if(!strcmp(tmp, "none")) {
|
||||
safefree(tmp);
|
||||
if (match[4].rm_so == -1) return -1;
|
||||
domain = get_string_arg (line, &match[4]);
|
||||
if (match[MGROUP1+4].rm_so == -1) return -1;
|
||||
domain = get_string_arg (line, &match[MGROUP1+4]);
|
||||
if (!domain)
|
||||
return -1;
|
||||
ube = upstream_add (NULL, 0, domain, 0, 0, PT_NONE, &conf->upstream_list);
|
||||
@ -1109,7 +972,7 @@ static HANDLE_FUNC (handle_upstream)
|
||||
}
|
||||
}
|
||||
|
||||
mi = 6;
|
||||
mi = MGROUP1+6;
|
||||
|
||||
tmp = get_string_arg (line, &match[mi]);
|
||||
pt = pt_from_string(tmp);
|
||||
@ -1124,16 +987,13 @@ static HANDLE_FUNC (handle_upstream)
|
||||
pass = get_string_arg (line, &match[mi]);
|
||||
mi++;
|
||||
|
||||
if (match[mi+4].rm_so != -1) /* IPv6 address in square brackets */
|
||||
ip = get_string_arg (line, &match[mi+4]);
|
||||
else
|
||||
ip = get_string_arg (line, &match[mi]);
|
||||
ip = get_string_arg (line, &match[mi]);
|
||||
if (!ip)
|
||||
return -1;
|
||||
mi += 16;
|
||||
mi += 3;
|
||||
|
||||
port = (int) get_long_arg (line, &match[mi]);
|
||||
mi += 3;
|
||||
mi += 2;
|
||||
|
||||
if (match[mi].rm_so != -1)
|
||||
domain = get_string_arg (line, &match[mi]);
|
||||
|
@ -39,7 +39,6 @@ typedef struct {
|
||||
*/
|
||||
struct config_s {
|
||||
sblist *basicauth_list;
|
||||
char *basicauth_realm;
|
||||
char *logf_name;
|
||||
unsigned int syslog; /* boolean */
|
||||
unsigned int port;
|
||||
@ -51,7 +50,9 @@ struct config_s {
|
||||
sblist *listen_addrs;
|
||||
#ifdef FILTER_ENABLE
|
||||
char *filter;
|
||||
unsigned int filter_opts; /* enum filter_options */
|
||||
unsigned int filter_url; /* boolean */
|
||||
unsigned int filter_extended; /* boolean */
|
||||
unsigned int filter_casesensitive; /* boolean */
|
||||
#endif /* FILTER_ENABLE */
|
||||
#ifdef XTINYPROXY_ENABLE
|
||||
unsigned int add_xtinyproxy; /* boolean */
|
||||
@ -67,7 +68,7 @@ struct config_s {
|
||||
#endif /* UPSTREAM_SUPPORT */
|
||||
char *pidpath;
|
||||
unsigned int idletimeout;
|
||||
sblist *bind_addrs;
|
||||
char *bind_address;
|
||||
unsigned int bindsame;
|
||||
|
||||
/*
|
||||
|
93
src/conf_regex.h
Normal file
93
src/conf_regex.h
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* The configuration directives are defined in the structure below. Each
|
||||
* directive requires a regular expression to match against, and a
|
||||
* function to call when the regex is matched.
|
||||
*
|
||||
* Below are defined certain constant regular expression strings that
|
||||
* can (and likely should) be used when building the regex for the
|
||||
* given directive.
|
||||
*/
|
||||
#define DIGIT "[0-9]"
|
||||
#define SPACE "[ \\t]"
|
||||
#define WS SPACE "+"
|
||||
#define STR "\"([^\"]+)\""
|
||||
#define BOOL "([Yy][Ee][Ss]|[Oo][Nn]|[Nn][Oo]|[Oo][Ff][Ff])"
|
||||
#define INT "(" DIGIT "+)"
|
||||
#define ALNUM "([-A-Za-z0-9._]+)"
|
||||
#define USERNAME "([^:]*)"
|
||||
#define PASSWORD "([^@]*)"
|
||||
#define IP "([0-9]+[.][0-9]+[.][0-9]+[.][0-9]+)"
|
||||
#define IPMASK "(" IP "(/" DIGIT "+)?)"
|
||||
#define IPV6 "(" \
|
||||
"(([0-9a-fA-F:]{2,39}))|" \
|
||||
"(([0-9a-fA-F:]{0,29}:" IP "))" \
|
||||
")"
|
||||
|
||||
#define IPV6MASK "(" IPV6 "(/" DIGIT "+)?)"
|
||||
#define BEGIN "^"
|
||||
#define END "$"
|
||||
|
||||
|
||||
STDCONF (logfile, STR, handle_logfile),
|
||||
STDCONF (pidfile, STR, handle_pidfile),
|
||||
STDCONF (anonymous, STR, handle_anonymous),
|
||||
STDCONF (viaproxyname, STR, handle_viaproxyname),
|
||||
STDCONF (defaulterrorfile, STR, handle_defaulterrorfile),
|
||||
STDCONF (statfile, STR, handle_statfile),
|
||||
STDCONF (stathost, STR, handle_stathost),
|
||||
STDCONF (xtinyproxy, BOOL, handle_xtinyproxy),
|
||||
/* boolean arguments */
|
||||
STDCONF (syslog, BOOL, handle_syslog),
|
||||
STDCONF (bindsame, BOOL, handle_bindsame),
|
||||
STDCONF (disableviaheader, BOOL, handle_disableviaheader),
|
||||
/* integer arguments */
|
||||
STDCONF (port, INT, handle_port),
|
||||
STDCONF (maxclients, INT, handle_maxclients),
|
||||
STDCONF (maxspareservers, INT, handle_obsolete),
|
||||
STDCONF (minspareservers, INT, handle_obsolete),
|
||||
STDCONF (startservers, INT, handle_obsolete),
|
||||
STDCONF (maxrequestsperchild, INT, handle_obsolete),
|
||||
STDCONF (timeout, INT, handle_timeout),
|
||||
STDCONF (connectport, INT, handle_connectport),
|
||||
/* alphanumeric arguments */
|
||||
STDCONF (user, ALNUM, handle_user),
|
||||
STDCONF (group, ALNUM, handle_group),
|
||||
/* ip arguments */
|
||||
STDCONF (listen, "(" IP "|" IPV6 ")", handle_listen),
|
||||
STDCONF (allow, "(" "(" IPMASK "|" IPV6MASK ")" "|" ALNUM ")",
|
||||
handle_allow),
|
||||
STDCONF (deny, "(" "(" IPMASK "|" IPV6MASK ")" "|" ALNUM ")",
|
||||
handle_deny),
|
||||
STDCONF (bind, "(" IP "|" IPV6 ")", handle_bind),
|
||||
/* other */
|
||||
STDCONF (basicauth, ALNUM WS ALNUM, handle_basicauth),
|
||||
STDCONF (errorfile, INT WS STR, handle_errorfile),
|
||||
STDCONF (addheader, STR WS STR, handle_addheader),
|
||||
|
||||
#ifdef FILTER_ENABLE
|
||||
/* filtering */
|
||||
STDCONF (filter, STR, handle_filter),
|
||||
STDCONF (filterurls, BOOL, handle_filterurls),
|
||||
STDCONF (filterextended, BOOL, handle_filterextended),
|
||||
STDCONF (filterdefaultdeny, BOOL, handle_filterdefaultdeny),
|
||||
STDCONF (filtercasesensitive, BOOL, handle_filtercasesensitive),
|
||||
#endif
|
||||
#ifdef REVERSE_SUPPORT
|
||||
/* Reverse proxy arguments */
|
||||
STDCONF (reversebaseurl, STR, handle_reversebaseurl),
|
||||
STDCONF (reverseonly, BOOL, handle_reverseonly),
|
||||
STDCONF (reversemagic, BOOL, handle_reversemagic),
|
||||
STDCONF (reversepath, STR "(" WS STR ")?", handle_reversepath),
|
||||
#endif
|
||||
#ifdef UPSTREAM_SUPPORT
|
||||
STDCONF (upstream,
|
||||
"(" "(none)" WS STR ")|" \
|
||||
"(" "(http|socks4|socks5)" WS \
|
||||
"(" USERNAME /*username*/ ":" PASSWORD /*password*/ "@" ")?"
|
||||
"(" IP "|" ALNUM ")"
|
||||
":" INT "(" WS STR ")?" ")", handle_upstream),
|
||||
#endif
|
||||
/* loglevel */
|
||||
STDCONF (loglevel, "([Cc]ritical|[Ee]rror|[Ww]arning|[Nn]otice|[Cc]onnect|[Ii]nfo)",
|
||||
handle_loglevel)
|
||||
|
512
src/conf_regex.rl
Normal file
512
src/conf_regex.rl
Normal file
@ -0,0 +1,512 @@
|
||||
/* automatically generated with re2r by rofl0r */
|
||||
%%{
|
||||
machine logfile;
|
||||
action A1 { matches[1].rm_so = p-start; }
|
||||
action E1 { matches[1].rm_eo = p-start; }
|
||||
main := '"'([^"]+) >A1 %E1 '"' ;
|
||||
}%%
|
||||
|
||||
RE2R_EXPORT int re2r_match_logfile(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
size_t i, cs;
|
||||
int par;
|
||||
static const unsigned char parents[] = {[0]=0,[1]=0,};
|
||||
const char *start = p, *eof = pe;
|
||||
%% write data nofinal noerror noentry;
|
||||
for(i=0;i<nmatch;++i) matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1};
|
||||
%% write init;
|
||||
%% write exec;
|
||||
if(cs < %%{ write first_final; }%% ) return -1;
|
||||
matches[0] = (regmatch_t){.rm_so = 0, .rm_eo = eof-start};
|
||||
for(i=1;i<nmatch;++i) if(matches[i].rm_eo == -1) matches[i].rm_so = -1;
|
||||
else if(matches[i].rm_so == matches[i].rm_eo) matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1};
|
||||
else { par = i; while((par = parents[par])) if(matches[par].rm_eo == -1) { matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1}; break; }}
|
||||
return 0;
|
||||
}
|
||||
|
||||
RE2R_EXPORT int re2r_match_pidfile(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
return re2r_match_logfile(p, pe, nmatch, matches);
|
||||
}
|
||||
|
||||
RE2R_EXPORT int re2r_match_anonymous(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
return re2r_match_logfile(p, pe, nmatch, matches);
|
||||
}
|
||||
|
||||
RE2R_EXPORT int re2r_match_viaproxyname(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
return re2r_match_logfile(p, pe, nmatch, matches);
|
||||
}
|
||||
|
||||
RE2R_EXPORT int re2r_match_defaulterrorfile(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
return re2r_match_logfile(p, pe, nmatch, matches);
|
||||
}
|
||||
|
||||
RE2R_EXPORT int re2r_match_statfile(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
return re2r_match_logfile(p, pe, nmatch, matches);
|
||||
}
|
||||
|
||||
RE2R_EXPORT int re2r_match_stathost(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
return re2r_match_logfile(p, pe, nmatch, matches);
|
||||
}
|
||||
|
||||
%%{
|
||||
machine xtinyproxy;
|
||||
action A1 { matches[1].rm_so = p-start; }
|
||||
action E1 { matches[1].rm_eo = p-start; }
|
||||
main := ([Yy][Ee][Ss]|[Oo][Nn]|[Nn][Oo]|[Oo][Ff][Ff]) >A1 %E1 ;
|
||||
}%%
|
||||
|
||||
RE2R_EXPORT int re2r_match_xtinyproxy(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
size_t i, cs;
|
||||
int par;
|
||||
static const unsigned char parents[] = {[0]=0,[1]=0,};
|
||||
const char *start = p, *eof = pe;
|
||||
%% write data nofinal noerror noentry;
|
||||
for(i=0;i<nmatch;++i) matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1};
|
||||
%% write init;
|
||||
%% write exec;
|
||||
if(cs < %%{ write first_final; }%% ) return -1;
|
||||
matches[0] = (regmatch_t){.rm_so = 0, .rm_eo = eof-start};
|
||||
for(i=1;i<nmatch;++i) if(matches[i].rm_eo == -1) matches[i].rm_so = -1;
|
||||
else if(matches[i].rm_so == matches[i].rm_eo) matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1};
|
||||
else { par = i; while((par = parents[par])) if(matches[par].rm_eo == -1) { matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1}; break; }}
|
||||
return 0;
|
||||
}
|
||||
|
||||
RE2R_EXPORT int re2r_match_syslog(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
return re2r_match_xtinyproxy(p, pe, nmatch, matches);
|
||||
}
|
||||
|
||||
RE2R_EXPORT int re2r_match_bindsame(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
return re2r_match_xtinyproxy(p, pe, nmatch, matches);
|
||||
}
|
||||
|
||||
RE2R_EXPORT int re2r_match_disableviaheader(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
return re2r_match_xtinyproxy(p, pe, nmatch, matches);
|
||||
}
|
||||
|
||||
%%{
|
||||
machine port;
|
||||
action A1 { matches[1].rm_so = p-start; }
|
||||
action E1 { matches[1].rm_eo = p-start; }
|
||||
main := ([0-9]+) >A1 %E1 ;
|
||||
}%%
|
||||
|
||||
RE2R_EXPORT int re2r_match_port(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
size_t i, cs;
|
||||
int par;
|
||||
static const unsigned char parents[] = {[0]=0,[1]=0,};
|
||||
const char *start = p, *eof = pe;
|
||||
%% write data nofinal noerror noentry;
|
||||
for(i=0;i<nmatch;++i) matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1};
|
||||
%% write init;
|
||||
%% write exec;
|
||||
if(cs < %%{ write first_final; }%% ) return -1;
|
||||
matches[0] = (regmatch_t){.rm_so = 0, .rm_eo = eof-start};
|
||||
for(i=1;i<nmatch;++i) if(matches[i].rm_eo == -1) matches[i].rm_so = -1;
|
||||
else if(matches[i].rm_so == matches[i].rm_eo) matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1};
|
||||
else { par = i; while((par = parents[par])) if(matches[par].rm_eo == -1) { matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1}; break; }}
|
||||
return 0;
|
||||
}
|
||||
|
||||
RE2R_EXPORT int re2r_match_maxclients(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
return re2r_match_port(p, pe, nmatch, matches);
|
||||
}
|
||||
|
||||
RE2R_EXPORT int re2r_match_maxspareservers(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
return re2r_match_port(p, pe, nmatch, matches);
|
||||
}
|
||||
|
||||
RE2R_EXPORT int re2r_match_minspareservers(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
return re2r_match_port(p, pe, nmatch, matches);
|
||||
}
|
||||
|
||||
RE2R_EXPORT int re2r_match_startservers(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
return re2r_match_port(p, pe, nmatch, matches);
|
||||
}
|
||||
|
||||
RE2R_EXPORT int re2r_match_maxrequestsperchild(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
return re2r_match_port(p, pe, nmatch, matches);
|
||||
}
|
||||
|
||||
RE2R_EXPORT int re2r_match_timeout(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
return re2r_match_port(p, pe, nmatch, matches);
|
||||
}
|
||||
|
||||
RE2R_EXPORT int re2r_match_connectport(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
return re2r_match_port(p, pe, nmatch, matches);
|
||||
}
|
||||
|
||||
%%{
|
||||
machine user;
|
||||
action A1 { matches[1].rm_so = p-start; }
|
||||
action E1 { matches[1].rm_eo = p-start; }
|
||||
main := (('-'|[A-Za-z0-9._])+) >A1 %E1 ;
|
||||
}%%
|
||||
|
||||
RE2R_EXPORT int re2r_match_user(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
size_t i, cs;
|
||||
int par;
|
||||
static const unsigned char parents[] = {[0]=0,[1]=0,};
|
||||
const char *start = p, *eof = pe;
|
||||
%% write data nofinal noerror noentry;
|
||||
for(i=0;i<nmatch;++i) matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1};
|
||||
%% write init;
|
||||
%% write exec;
|
||||
if(cs < %%{ write first_final; }%% ) return -1;
|
||||
matches[0] = (regmatch_t){.rm_so = 0, .rm_eo = eof-start};
|
||||
for(i=1;i<nmatch;++i) if(matches[i].rm_eo == -1) matches[i].rm_so = -1;
|
||||
else if(matches[i].rm_so == matches[i].rm_eo) matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1};
|
||||
else { par = i; while((par = parents[par])) if(matches[par].rm_eo == -1) { matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1}; break; }}
|
||||
return 0;
|
||||
}
|
||||
|
||||
RE2R_EXPORT int re2r_match_group(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
return re2r_match_user(p, pe, nmatch, matches);
|
||||
}
|
||||
|
||||
%%{
|
||||
machine listen;
|
||||
action A1 { matches[1].rm_so = p-start; }
|
||||
action A2 { matches[2].rm_so = p-start; }
|
||||
action A3 { matches[3].rm_so = p-start; }
|
||||
action A4 { matches[4].rm_so = p-start; }
|
||||
action A5 { matches[5].rm_so = p-start; }
|
||||
action A6 { matches[6].rm_so = p-start; }
|
||||
action A7 { matches[7].rm_so = p-start; }
|
||||
action A8 { matches[8].rm_so = p-start; }
|
||||
action E1 { matches[1].rm_eo = p-start; }
|
||||
action E2 { matches[2].rm_eo = p-start; }
|
||||
action E3 { matches[3].rm_eo = p-start; }
|
||||
action E4 { matches[4].rm_eo = p-start; }
|
||||
action E5 { matches[5].rm_eo = p-start; }
|
||||
action E6 { matches[6].rm_eo = p-start; }
|
||||
action E7 { matches[7].rm_eo = p-start; }
|
||||
action E8 { matches[8].rm_eo = p-start; }
|
||||
main := (([0-9]+[.][0-9]+[.][0-9]+[.][0-9]+) >A2 %E2 |((([0-9a-fA-F:]{2,39}) >A5 %E5 ) >A4 %E4 |(([0-9a-fA-F:]{0,29} ":" ([0-9]+[.][0-9]+[.][0-9]+[.][0-9]+) >A8 %E8 ) >A7 %E7 ) >A6 %E6 ) >A3 %E3 ) >A1 %E1 ;
|
||||
}%%
|
||||
|
||||
RE2R_EXPORT int re2r_match_listen(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
size_t i, cs;
|
||||
int par;
|
||||
static const unsigned char parents[] = {[0]=0,[1]=0,[2]=1,[3]=1,[4]=3,[5]=4,[6]=3,[7]=6,[8]=7,};
|
||||
const char *start = p, *eof = pe;
|
||||
%% write data nofinal noerror noentry;
|
||||
for(i=0;i<nmatch;++i) matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1};
|
||||
%% write init;
|
||||
%% write exec;
|
||||
if(cs < %%{ write first_final; }%% ) return -1;
|
||||
matches[0] = (regmatch_t){.rm_so = 0, .rm_eo = eof-start};
|
||||
for(i=1;i<nmatch;++i) if(matches[i].rm_eo == -1) matches[i].rm_so = -1;
|
||||
else if(matches[i].rm_so == matches[i].rm_eo) matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1};
|
||||
else { par = i; while((par = parents[par])) if(matches[par].rm_eo == -1) { matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1}; break; }}
|
||||
return 0;
|
||||
}
|
||||
|
||||
%%{
|
||||
machine allow;
|
||||
action A1 { matches[1].rm_so = p-start; }
|
||||
action A2 { matches[2].rm_so = p-start; }
|
||||
action A3 { matches[3].rm_so = p-start; }
|
||||
action A4 { matches[4].rm_so = p-start; }
|
||||
action A5 { matches[5].rm_so = p-start; }
|
||||
action A6 { matches[6].rm_so = p-start; }
|
||||
action A7 { matches[7].rm_so = p-start; }
|
||||
action A8 { matches[8].rm_so = p-start; }
|
||||
action A9 { matches[9].rm_so = p-start; }
|
||||
action A10 { matches[10].rm_so = p-start; }
|
||||
action A11 { matches[11].rm_so = p-start; }
|
||||
action A12 { matches[12].rm_so = p-start; }
|
||||
action A13 { matches[13].rm_so = p-start; }
|
||||
action A14 { matches[14].rm_so = p-start; }
|
||||
action E1 { matches[1].rm_eo = p-start; }
|
||||
action E2 { matches[2].rm_eo = p-start; }
|
||||
action E3 { matches[3].rm_eo = p-start; }
|
||||
action E4 { matches[4].rm_eo = p-start; }
|
||||
action E5 { matches[5].rm_eo = p-start; }
|
||||
action E6 { matches[6].rm_eo = p-start; }
|
||||
action E7 { matches[7].rm_eo = p-start; }
|
||||
action E8 { matches[8].rm_eo = p-start; }
|
||||
action E9 { matches[9].rm_eo = p-start; }
|
||||
action E10 { matches[10].rm_eo = p-start; }
|
||||
action E11 { matches[11].rm_eo = p-start; }
|
||||
action E12 { matches[12].rm_eo = p-start; }
|
||||
action E13 { matches[13].rm_eo = p-start; }
|
||||
action E14 { matches[14].rm_eo = p-start; }
|
||||
main := (((([0-9]+[.][0-9]+[.][0-9]+[.][0-9]+) >A4 %E4 ( "/" [0-9]+)? >A5 %E5 ) >A3 %E3 |(((([0-9a-fA-F:]{2,39}) >A9 %E9 ) >A8 %E8 |(([0-9a-fA-F:]{0,29} ":" ([0-9]+[.][0-9]+[.][0-9]+[.][0-9]+) >A12 %E12 ) >A11 %E11 ) >A10 %E10 ) >A7 %E7 ( "/" [0-9]+)? >A13 %E13 ) >A6 %E6 ) >A2 %E2 |(('-'|[A-Za-z0-9._])+) >A14 %E14 ) >A1 %E1 ;
|
||||
}%%
|
||||
|
||||
RE2R_EXPORT int re2r_match_allow(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
size_t i, cs;
|
||||
int par;
|
||||
static const unsigned char parents[] = {[0]=0,[1]=0,[2]=1,[3]=2,[4]=3,[5]=3,[6]=2,[7]=6,[8]=7,[9]=8,[10]=7,[11]=10,[12]=11,[13]=6,[14]=1,};
|
||||
const char *start = p, *eof = pe;
|
||||
%% write data nofinal noerror noentry;
|
||||
for(i=0;i<nmatch;++i) matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1};
|
||||
%% write init;
|
||||
%% write exec;
|
||||
if(cs < %%{ write first_final; }%% ) return -1;
|
||||
matches[0] = (regmatch_t){.rm_so = 0, .rm_eo = eof-start};
|
||||
for(i=1;i<nmatch;++i) if(matches[i].rm_eo == -1) matches[i].rm_so = -1;
|
||||
else if(matches[i].rm_so == matches[i].rm_eo) matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1};
|
||||
else { par = i; while((par = parents[par])) if(matches[par].rm_eo == -1) { matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1}; break; }}
|
||||
return 0;
|
||||
}
|
||||
|
||||
RE2R_EXPORT int re2r_match_deny(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
return re2r_match_allow(p, pe, nmatch, matches);
|
||||
}
|
||||
|
||||
RE2R_EXPORT int re2r_match_bind(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
return re2r_match_listen(p, pe, nmatch, matches);
|
||||
}
|
||||
|
||||
%%{
|
||||
machine basicauth;
|
||||
action A1 { matches[1].rm_so = p-start; }
|
||||
action A2 { matches[2].rm_so = p-start; }
|
||||
action E1 { matches[1].rm_eo = p-start; }
|
||||
action E2 { matches[2].rm_eo = p-start; }
|
||||
main := (('-'|[A-Za-z0-9._])+) >A1 %E1 [ \t]+(('-'|[A-Za-z0-9._])+) >A2 %E2 ;
|
||||
}%%
|
||||
|
||||
RE2R_EXPORT int re2r_match_basicauth(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
size_t i, cs;
|
||||
int par;
|
||||
static const unsigned char parents[] = {[0]=0,[1]=0,[2]=0,};
|
||||
const char *start = p, *eof = pe;
|
||||
%% write data nofinal noerror noentry;
|
||||
for(i=0;i<nmatch;++i) matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1};
|
||||
%% write init;
|
||||
%% write exec;
|
||||
if(cs < %%{ write first_final; }%% ) return -1;
|
||||
matches[0] = (regmatch_t){.rm_so = 0, .rm_eo = eof-start};
|
||||
for(i=1;i<nmatch;++i) if(matches[i].rm_eo == -1) matches[i].rm_so = -1;
|
||||
else if(matches[i].rm_so == matches[i].rm_eo) matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1};
|
||||
else { par = i; while((par = parents[par])) if(matches[par].rm_eo == -1) { matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1}; break; }}
|
||||
return 0;
|
||||
}
|
||||
|
||||
%%{
|
||||
machine errorfile;
|
||||
action A1 { matches[1].rm_so = p-start; }
|
||||
action A2 { matches[2].rm_so = p-start; }
|
||||
action E1 { matches[1].rm_eo = p-start; }
|
||||
action E2 { matches[2].rm_eo = p-start; }
|
||||
main := ([0-9]+) >A1 %E1 [ \t]+'"'([^"]+) >A2 %E2 '"' ;
|
||||
}%%
|
||||
|
||||
RE2R_EXPORT int re2r_match_errorfile(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
size_t i, cs;
|
||||
int par;
|
||||
static const unsigned char parents[] = {[0]=0,[1]=0,[2]=0,};
|
||||
const char *start = p, *eof = pe;
|
||||
%% write data nofinal noerror noentry;
|
||||
for(i=0;i<nmatch;++i) matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1};
|
||||
%% write init;
|
||||
%% write exec;
|
||||
if(cs < %%{ write first_final; }%% ) return -1;
|
||||
matches[0] = (regmatch_t){.rm_so = 0, .rm_eo = eof-start};
|
||||
for(i=1;i<nmatch;++i) if(matches[i].rm_eo == -1) matches[i].rm_so = -1;
|
||||
else if(matches[i].rm_so == matches[i].rm_eo) matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1};
|
||||
else { par = i; while((par = parents[par])) if(matches[par].rm_eo == -1) { matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1}; break; }}
|
||||
return 0;
|
||||
}
|
||||
|
||||
%%{
|
||||
machine addheader;
|
||||
action A1 { matches[1].rm_so = p-start; }
|
||||
action A2 { matches[2].rm_so = p-start; }
|
||||
action E1 { matches[1].rm_eo = p-start; }
|
||||
action E2 { matches[2].rm_eo = p-start; }
|
||||
main := '"'([^"]+) >A1 %E1 '"'[ \t]+'"'([^"]+) >A2 %E2 '"' ;
|
||||
}%%
|
||||
|
||||
RE2R_EXPORT int re2r_match_addheader(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
size_t i, cs;
|
||||
int par;
|
||||
static const unsigned char parents[] = {[0]=0,[1]=0,[2]=0,};
|
||||
const char *start = p, *eof = pe;
|
||||
%% write data nofinal noerror noentry;
|
||||
for(i=0;i<nmatch;++i) matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1};
|
||||
%% write init;
|
||||
%% write exec;
|
||||
if(cs < %%{ write first_final; }%% ) return -1;
|
||||
matches[0] = (regmatch_t){.rm_so = 0, .rm_eo = eof-start};
|
||||
for(i=1;i<nmatch;++i) if(matches[i].rm_eo == -1) matches[i].rm_so = -1;
|
||||
else if(matches[i].rm_so == matches[i].rm_eo) matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1};
|
||||
else { par = i; while((par = parents[par])) if(matches[par].rm_eo == -1) { matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1}; break; }}
|
||||
return 0;
|
||||
}
|
||||
|
||||
RE2R_EXPORT int re2r_match_filter(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
return re2r_match_logfile(p, pe, nmatch, matches);
|
||||
}
|
||||
|
||||
RE2R_EXPORT int re2r_match_filterurls(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
return re2r_match_xtinyproxy(p, pe, nmatch, matches);
|
||||
}
|
||||
|
||||
RE2R_EXPORT int re2r_match_filterextended(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
return re2r_match_xtinyproxy(p, pe, nmatch, matches);
|
||||
}
|
||||
|
||||
RE2R_EXPORT int re2r_match_filterdefaultdeny(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
return re2r_match_xtinyproxy(p, pe, nmatch, matches);
|
||||
}
|
||||
|
||||
RE2R_EXPORT int re2r_match_filtercasesensitive(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
return re2r_match_xtinyproxy(p, pe, nmatch, matches);
|
||||
}
|
||||
|
||||
RE2R_EXPORT int re2r_match_reversebaseurl(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
return re2r_match_logfile(p, pe, nmatch, matches);
|
||||
}
|
||||
|
||||
RE2R_EXPORT int re2r_match_reverseonly(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
return re2r_match_xtinyproxy(p, pe, nmatch, matches);
|
||||
}
|
||||
|
||||
RE2R_EXPORT int re2r_match_reversemagic(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
return re2r_match_xtinyproxy(p, pe, nmatch, matches);
|
||||
}
|
||||
|
||||
%%{
|
||||
machine reversepath;
|
||||
action A1 { matches[1].rm_so = p-start; }
|
||||
action A2 { matches[2].rm_so = p-start; }
|
||||
action A3 { matches[3].rm_so = p-start; }
|
||||
action E1 { matches[1].rm_eo = p-start; }
|
||||
action E2 { matches[2].rm_eo = p-start; }
|
||||
action E3 { matches[3].rm_eo = p-start; }
|
||||
main := '"'([^"]+) >A1 %E1 '"'([ \t]+'"'([^"]+) >A3 %E3 '"')? >A2 %E2 ;
|
||||
}%%
|
||||
|
||||
RE2R_EXPORT int re2r_match_reversepath(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
size_t i, cs;
|
||||
int par;
|
||||
static const unsigned char parents[] = {[0]=0,[1]=0,[2]=0,[3]=2,};
|
||||
const char *start = p, *eof = pe;
|
||||
%% write data nofinal noerror noentry;
|
||||
for(i=0;i<nmatch;++i) matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1};
|
||||
%% write init;
|
||||
%% write exec;
|
||||
if(cs < %%{ write first_final; }%% ) return -1;
|
||||
matches[0] = (regmatch_t){.rm_so = 0, .rm_eo = eof-start};
|
||||
for(i=1;i<nmatch;++i) if(matches[i].rm_eo == -1) matches[i].rm_so = -1;
|
||||
else if(matches[i].rm_so == matches[i].rm_eo) matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1};
|
||||
else { par = i; while((par = parents[par])) if(matches[par].rm_eo == -1) { matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1}; break; }}
|
||||
return 0;
|
||||
}
|
||||
|
||||
%%{
|
||||
machine upstream;
|
||||
action A1 { matches[1].rm_so = p-start; }
|
||||
action A2 { matches[2].rm_so = p-start; }
|
||||
action A3 { matches[3].rm_so = p-start; }
|
||||
action A4 { matches[4].rm_so = p-start; }
|
||||
action A5 { matches[5].rm_so = p-start; }
|
||||
action A6 { matches[6].rm_so = p-start; }
|
||||
action A7 { matches[7].rm_so = p-start; }
|
||||
action A8 { matches[8].rm_so = p-start; }
|
||||
action A9 { matches[9].rm_so = p-start; }
|
||||
action A10 { matches[10].rm_so = p-start; }
|
||||
action A11 { matches[11].rm_so = p-start; }
|
||||
action A12 { matches[12].rm_so = p-start; }
|
||||
action A13 { matches[13].rm_so = p-start; }
|
||||
action A14 { matches[14].rm_so = p-start; }
|
||||
action E1 { matches[1].rm_eo = p-start; }
|
||||
action E2 { matches[2].rm_eo = p-start; }
|
||||
action E3 { matches[3].rm_eo = p-start; }
|
||||
action E4 { matches[4].rm_eo = p-start; }
|
||||
action E5 { matches[5].rm_eo = p-start; }
|
||||
action E6 { matches[6].rm_eo = p-start; }
|
||||
action E7 { matches[7].rm_eo = p-start; }
|
||||
action E8 { matches[8].rm_eo = p-start; }
|
||||
action E9 { matches[9].rm_eo = p-start; }
|
||||
action E10 { matches[10].rm_eo = p-start; }
|
||||
action E11 { matches[11].rm_eo = p-start; }
|
||||
action E12 { matches[12].rm_eo = p-start; }
|
||||
action E13 { matches[13].rm_eo = p-start; }
|
||||
action E14 { matches[14].rm_eo = p-start; }
|
||||
main := (( "none" ) >A2 %E2 [ \t]+'"'([^"]+) >A3 %E3 '"') >A1 %E1 |(( "http" | "socks4" | "socks5" ) >A5 %E5 [ \t]+(([^:]*) >A7 %E7 ":" ([^@]*) >A8 %E8 "@" )? >A6 %E6 (([0-9]+[.][0-9]+[.][0-9]+[.][0-9]+) >A10 %E10 |(('-'|[A-Za-z0-9._])+) >A11 %E11 ) >A9 %E9 ":" ([0-9]+) >A12 %E12 ([ \t]+'"'([^"]+) >A14 %E14 '"')? >A13 %E13 ) >A4 %E4 ;
|
||||
}%%
|
||||
|
||||
RE2R_EXPORT int re2r_match_upstream(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
size_t i, cs;
|
||||
int par;
|
||||
static const unsigned char parents[] = {[0]=0,[1]=0,[2]=1,[3]=1,[4]=0,[5]=4,[6]=4,[7]=6,[8]=6,[9]=4,[10]=9,[11]=9,[12]=4,[13]=4,[14]=13,};
|
||||
const char *start = p, *eof = pe;
|
||||
%% write data nofinal noerror noentry;
|
||||
for(i=0;i<nmatch;++i) matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1};
|
||||
%% write init;
|
||||
%% write exec;
|
||||
if(cs < %%{ write first_final; }%% ) return -1;
|
||||
matches[0] = (regmatch_t){.rm_so = 0, .rm_eo = eof-start};
|
||||
for(i=1;i<nmatch;++i) if(matches[i].rm_eo == -1) matches[i].rm_so = -1;
|
||||
else if(matches[i].rm_so == matches[i].rm_eo) matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1};
|
||||
else { par = i; while((par = parents[par])) if(matches[par].rm_eo == -1) { matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1}; break; }}
|
||||
return 0;
|
||||
}
|
||||
|
||||
%%{
|
||||
machine loglevel;
|
||||
action A1 { matches[1].rm_so = p-start; }
|
||||
action E1 { matches[1].rm_eo = p-start; }
|
||||
main := ([Cc] "ritical" |[Ee] "rror" |[Ww] "arning" |[Nn] "otice" |[Cc] "onnect" |[Ii] "nfo" ) >A1 %E1 ;
|
||||
}%%
|
||||
|
||||
RE2R_EXPORT int re2r_match_loglevel(const char *p, const char* pe, size_t nmatch, regmatch_t matches[])
|
||||
{
|
||||
size_t i, cs;
|
||||
int par;
|
||||
static const unsigned char parents[] = {[0]=0,[1]=0,};
|
||||
const char *start = p, *eof = pe;
|
||||
%% write data nofinal noerror noentry;
|
||||
for(i=0;i<nmatch;++i) matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1};
|
||||
%% write init;
|
||||
%% write exec;
|
||||
if(cs < %%{ write first_final; }%% ) return -1;
|
||||
matches[0] = (regmatch_t){.rm_so = 0, .rm_eo = eof-start};
|
||||
for(i=1;i<nmatch;++i) if(matches[i].rm_eo == -1) matches[i].rm_so = -1;
|
||||
else if(matches[i].rm_so == matches[i].rm_eo) matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1};
|
||||
else { par = i; while((par = parents[par])) if(matches[par].rm_eo == -1) { matches[i] = (regmatch_t){.rm_so = -1, .rm_eo = -1}; break; }}
|
||||
return 0;
|
||||
}
|
||||
|
14
src/conf_regex_print.c
Normal file
14
src/conf_regex_print.c
Normal file
@ -0,0 +1,14 @@
|
||||
/* this is a tool to print regexname regex pairs as input for re2r.
|
||||
compile with gcc -I. src/conf_regex_print.c
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define STDCONF(A, B, C) printf("%s %s\n", #A, B)
|
||||
|
||||
int main() {
|
||||
#include "conf_regex.h"
|
||||
;
|
||||
}
|
62
src/filter.c
62
src/filter.c
@ -25,7 +25,6 @@
|
||||
#include "main.h"
|
||||
|
||||
#include <regex.h>
|
||||
#include <fnmatch.h>
|
||||
#include "filter.h"
|
||||
#include "heap.h"
|
||||
#include "log.h"
|
||||
@ -38,17 +37,15 @@
|
||||
static int err;
|
||||
|
||||
struct filter_list {
|
||||
union {
|
||||
regex_t cpatb;
|
||||
char *pattern;
|
||||
} u;
|
||||
regex_t cpatb;
|
||||
};
|
||||
|
||||
static sblist *fl = NULL;
|
||||
static int already_init = 0;
|
||||
static filter_policy_t default_policy = FILTER_DEFAULT_ALLOW;
|
||||
|
||||
/*
|
||||
* Initializes a list of strings containing hosts/urls to be filtered
|
||||
* Initializes a linked list of strings containing hosts/urls to be filtered
|
||||
*/
|
||||
void filter_init (void)
|
||||
{
|
||||
@ -64,13 +61,14 @@ void filter_init (void)
|
||||
|
||||
fd = fopen (config->filter, "r");
|
||||
if (!fd) {
|
||||
perror ("filter file");
|
||||
exit (EX_DATAERR);
|
||||
return;
|
||||
}
|
||||
|
||||
cflags = REG_NEWLINE | REG_NOSUB;
|
||||
cflags |= (REG_EXTENDED * !!(config->filter_opts & FILTER_OPT_TYPE_ERE));
|
||||
cflags |= (REG_ICASE * !(config->filter_opts & FILTER_OPT_CASESENSITIVE));
|
||||
if (config->filter_extended)
|
||||
cflags |= REG_EXTENDED;
|
||||
if (!config->filter_casesensitive)
|
||||
cflags |= REG_ICASE;
|
||||
|
||||
while (fgets (buf, FILTER_BUFFER_LEN, fd)) {
|
||||
++lineno;
|
||||
@ -108,19 +106,13 @@ void filter_init (void)
|
||||
if (!fl) fl = sblist_new(sizeof(struct filter_list),
|
||||
4096/sizeof(struct filter_list));
|
||||
|
||||
if (config->filter_opts & FILTER_OPT_TYPE_FNMATCH) {
|
||||
fe.u.pattern = safestrdup(s);
|
||||
if (!fe.u.pattern) goto oom;
|
||||
} else {
|
||||
|
||||
err = regcomp (&fe.u.cpatb, s, cflags);
|
||||
if (err != 0) {
|
||||
if (err == REG_ESPACE) goto oom;
|
||||
fprintf (stderr,
|
||||
"Bad regex in %s: line %d - %s\n",
|
||||
config->filter, lineno, s);
|
||||
exit (EX_DATAERR);
|
||||
}
|
||||
err = regcomp (&fe.cpatb, s, cflags);
|
||||
if (err != 0) {
|
||||
if (err == REG_ESPACE) goto oom;
|
||||
fprintf (stderr,
|
||||
"Bad regex in %s: line %d - %s\n",
|
||||
config->filter, lineno, s);
|
||||
exit (EX_DATAERR);
|
||||
}
|
||||
if (!sblist_add(fl, &fe)) {
|
||||
oom:;
|
||||
@ -149,10 +141,7 @@ void filter_destroy (void)
|
||||
if (fl) {
|
||||
for (i = 0; i < sblist_getsize(fl); ++i) {
|
||||
p = sblist_get(fl, i);
|
||||
if (config->filter_opts & FILTER_OPT_TYPE_FNMATCH)
|
||||
safefree(p->u.pattern);
|
||||
else
|
||||
regfree (&p->u.cpatb);
|
||||
regfree (&p->cpatb);
|
||||
}
|
||||
sblist_free(fl);
|
||||
}
|
||||
@ -185,14 +174,11 @@ int filter_run (const char *str)
|
||||
|
||||
for (i = 0; i < sblist_getsize(fl); ++i) {
|
||||
p = sblist_get(fl, i);
|
||||
if (config->filter_opts & FILTER_OPT_TYPE_FNMATCH)
|
||||
result = fnmatch (p->u.pattern, str, 0);
|
||||
else
|
||||
result =
|
||||
regexec (&p->u.cpatb, str, (size_t) 0, (regmatch_t *) 0, 0);
|
||||
result =
|
||||
regexec (&p->cpatb, str, (size_t) 0, (regmatch_t *) 0, 0);
|
||||
|
||||
if (result == 0) {
|
||||
if (!(config->filter_opts & FILTER_OPT_DEFAULT_DENY))
|
||||
if (default_policy == FILTER_DEFAULT_ALLOW)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
@ -200,8 +186,16 @@ int filter_run (const char *str)
|
||||
}
|
||||
|
||||
COMMON_EXIT:
|
||||
if (!(config->filter_opts & FILTER_OPT_DEFAULT_DENY))
|
||||
if (default_policy == FILTER_DEFAULT_ALLOW)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the default filtering policy
|
||||
*/
|
||||
void filter_set_default_policy (filter_policy_t policy)
|
||||
{
|
||||
default_policy = policy;
|
||||
}
|
||||
|
18
src/filter.h
18
src/filter.h
@ -21,22 +21,16 @@
|
||||
#ifndef _TINYPROXY_FILTER_H_
|
||||
#define _TINYPROXY_FILTER_H_
|
||||
|
||||
enum filter_options {
|
||||
FILTER_OPT_CASESENSITIVE = 1 << 0,
|
||||
FILTER_OPT_URL = 1 << 1,
|
||||
FILTER_OPT_DEFAULT_DENY = 1 << 2,
|
||||
|
||||
FILTER_OPT_TYPE_BRE = 1 << 8,
|
||||
FILTER_OPT_TYPE_ERE = 1 << 9,
|
||||
FILTER_OPT_TYPE_FNMATCH = 1 << 10,
|
||||
};
|
||||
|
||||
#define FILTER_TYPE_MASK \
|
||||
(FILTER_OPT_TYPE_BRE | FILTER_OPT_TYPE_ERE | FILTER_OPT_TYPE_FNMATCH)
|
||||
typedef enum {
|
||||
FILTER_DEFAULT_ALLOW,
|
||||
FILTER_DEFAULT_DENY
|
||||
} filter_policy_t;
|
||||
|
||||
extern void filter_init (void);
|
||||
extern void filter_destroy (void);
|
||||
extern void filter_reload (void);
|
||||
extern int filter_run (const char *str);
|
||||
|
||||
extern void filter_set_default_policy (filter_policy_t policy);
|
||||
|
||||
#endif
|
||||
|
179
src/hostspec.c
179
src/hostspec.c
@ -1,179 +0,0 @@
|
||||
#include "common.h"
|
||||
#include "hostspec.h"
|
||||
#include "heap.h"
|
||||
#include "network.h"
|
||||
|
||||
static int dotted_mask(char *bitmask_string, unsigned char array[])
|
||||
{
|
||||
unsigned char v4bits[4];
|
||||
if (1 != inet_pton (AF_INET, bitmask_string, v4bits)) return -1;
|
||||
memset (array, 0xff, IPV6_LEN-4);
|
||||
memcpy (array + IPV6_LEN-4, v4bits, 4);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fills in the netmask array given a numeric value.
|
||||
*
|
||||
* Returns:
|
||||
* 0 on success
|
||||
* -1 on failure (invalid mask value)
|
||||
*
|
||||
*/
|
||||
static int
|
||||
fill_netmask_array (char *bitmask_string, int v6,
|
||||
unsigned char array[])
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned long int mask;
|
||||
char *endptr;
|
||||
|
||||
errno = 0; /* to distinguish success/failure after call */
|
||||
if (strchr (bitmask_string, '.')) {
|
||||
if (v6) return -1; /* ipv6 doesn't supported dotted netmasks */
|
||||
return dotted_mask(bitmask_string, array);
|
||||
}
|
||||
mask = strtoul (bitmask_string, &endptr, 10);
|
||||
|
||||
/* check for various conversion errors */
|
||||
if ((errno == ERANGE && mask == ULONG_MAX)
|
||||
|| (errno != 0 && mask == 0) || (endptr == bitmask_string))
|
||||
return -1;
|
||||
|
||||
if (v6 == 0) {
|
||||
/* The mask comparison is done as an IPv6 address, so
|
||||
* convert to a longer mask in the case of IPv4
|
||||
* addresses. */
|
||||
mask += 12 * 8;
|
||||
}
|
||||
|
||||
/* check valid range for a bit mask */
|
||||
if (mask > (8 * IPV6_LEN))
|
||||
return -1;
|
||||
|
||||
/* we have a valid range to fill in the array */
|
||||
for (i = 0; i != IPV6_LEN; ++i) {
|
||||
if (mask >= 8) {
|
||||
array[i] = 0xff;
|
||||
mask -= 8;
|
||||
} else if (mask > 0) {
|
||||
array[i] = (unsigned char) (0xff << (8 - mask));
|
||||
mask = 0;
|
||||
} else {
|
||||
array[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* parse a location string containing either an ipv4/ipv4 + hostmask tuple
|
||||
or a dnsname into a struct hostspec.
|
||||
returns 0 on success, non-0 on error (might be memory allocation, bogus
|
||||
ip address or mask).
|
||||
*/
|
||||
int hostspec_parse(char *location, struct hostspec *h) {
|
||||
char *mask, ip_dst[IPV6_LEN];
|
||||
|
||||
h->type = HST_NONE;
|
||||
if(!location) return 0;
|
||||
|
||||
memset(h, 0, sizeof(*h));
|
||||
if ((mask = strrchr(location, '/')))
|
||||
*(mask++) = 0;
|
||||
|
||||
/*
|
||||
* Check for a valid IP address (the simplest case) first.
|
||||
*/
|
||||
if (full_inet_pton (location, ip_dst) > 0) {
|
||||
h->type = HST_NUMERIC;
|
||||
memcpy (h->address.ip.network, ip_dst, IPV6_LEN);
|
||||
if(!mask) memset (h->address.ip.mask, 0xff, IPV6_LEN);
|
||||
else {
|
||||
char dst[sizeof(struct in6_addr)];
|
||||
int v6, i;
|
||||
/* Check if the IP address before the netmask is
|
||||
* an IPv6 address */
|
||||
if (inet_pton(AF_INET6, location, dst) > 0)
|
||||
v6 = 1;
|
||||
else
|
||||
v6 = 0;
|
||||
|
||||
if (fill_netmask_array
|
||||
(mask, v6, &(h->address.ip.mask[0]))
|
||||
< 0)
|
||||
goto err;
|
||||
|
||||
for (i = 0; i < IPV6_LEN; i++)
|
||||
h->address.ip.network[i] = ip_dst[i] &
|
||||
h->address.ip.mask[i];
|
||||
}
|
||||
} else {
|
||||
/* either bogus IP or hostname */
|
||||
/* bogus ipv6 ? */
|
||||
if (mask || strchr (location, ':'))
|
||||
goto err;
|
||||
|
||||
/* In all likelihood a string */
|
||||
h->type = HST_STRING;
|
||||
h->address.string = safestrdup (location);
|
||||
if (!h->address.string)
|
||||
goto err;
|
||||
}
|
||||
/* restore mask */
|
||||
if(mask) *(--mask) = '/';
|
||||
return 0;
|
||||
err:;
|
||||
if(mask) *(--mask) = '/';
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int string_match(const char *ip, const char *addrspec)
|
||||
{
|
||||
size_t test_length, match_length;
|
||||
if(!strcasecmp(ip, addrspec)) return 1;
|
||||
if(addrspec[0] != '.') return 0;
|
||||
test_length = strlen (ip);
|
||||
match_length = strlen (addrspec);
|
||||
if (test_length < match_length) return 0;
|
||||
return (strcasecmp
|
||||
(ip + (test_length - match_length),
|
||||
addrspec) == 0);
|
||||
}
|
||||
|
||||
static int numeric_match(const uint8_t addr[], const struct hostspec *h)
|
||||
{
|
||||
uint8_t x, y;
|
||||
int i;
|
||||
|
||||
for (i = 0; i != IPV6_LEN; ++i) {
|
||||
x = addr[i] & h->address.ip.mask[i];
|
||||
y = h->address.ip.network[i];
|
||||
|
||||
/* If x and y don't match, the IP addresses don't match */
|
||||
if (x != y)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* check whether ip matches hostspec.
|
||||
return 1 on match, 0 on non-match */
|
||||
int hostspec_match(const char *ip, const struct hostspec *h) {
|
||||
int is_numeric_addr;
|
||||
uint8_t numeric_addr[IPV6_LEN];
|
||||
if (ip[0] == '\0') return 0;
|
||||
is_numeric_addr = (full_inet_pton (ip, &numeric_addr) > 0);
|
||||
switch (h->type) {
|
||||
case HST_STRING:
|
||||
if(is_numeric_addr) return 0;
|
||||
return string_match (ip, h->address.string);
|
||||
case HST_NUMERIC:
|
||||
return numeric_match (numeric_addr, h);
|
||||
case HST_NONE:
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
#ifndef HOSTSPEC_H
|
||||
#define HOSTSPEC_H
|
||||
|
||||
#define IPV6_LEN 16
|
||||
|
||||
enum hostspec_type {
|
||||
HST_NONE,
|
||||
HST_STRING,
|
||||
HST_NUMERIC,
|
||||
};
|
||||
|
||||
struct hostspec {
|
||||
enum hostspec_type type;
|
||||
union {
|
||||
char *string;
|
||||
struct {
|
||||
unsigned char network[IPV6_LEN];
|
||||
unsigned char mask[IPV6_LEN];
|
||||
} ip;
|
||||
} address;
|
||||
};
|
||||
|
||||
int hostspec_parse(char *domain, struct hostspec *h);
|
||||
int hostspec_match(const char *ip, const struct hostspec *h);
|
||||
|
||||
#endif
|
@ -49,7 +49,6 @@ struct htab {
|
||||
size_t mask;
|
||||
size_t used;
|
||||
size_t seed;
|
||||
size_t dead;
|
||||
};
|
||||
|
||||
#define MINSIZE 8
|
||||
@ -80,10 +79,9 @@ static int resize(struct htab *htab, size_t nel)
|
||||
{
|
||||
size_t newsize;
|
||||
size_t i, j;
|
||||
size_t oldmask = htab->mask;
|
||||
struct elem *e, *newe;
|
||||
struct elem *oldtab = htab->elems;
|
||||
struct elem *oldend;
|
||||
struct elem *oldend = htab->elems + htab->mask + 1;
|
||||
|
||||
if (nel > MAXSIZE)
|
||||
nel = MAXSIZE;
|
||||
@ -96,8 +94,6 @@ static int resize(struct htab *htab, size_t nel)
|
||||
htab->mask = newsize - 1;
|
||||
if (!oldtab)
|
||||
return 1;
|
||||
|
||||
oldend = oldtab + oldmask + 1;
|
||||
for (e = oldtab; e < oldend; e++)
|
||||
if (e->item.key) {
|
||||
for (i=e->hash,j=1; ; i+=j++) {
|
||||
@ -111,14 +107,14 @@ static int resize(struct htab *htab, size_t nel)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct elem *lookup(struct htab *htab, const char *key, size_t hash, size_t dead)
|
||||
static struct elem *lookup(struct htab *htab, const char *key, size_t hash)
|
||||
{
|
||||
size_t i, j;
|
||||
struct elem *e;
|
||||
|
||||
for (i=hash,j=1; ; i+=j++) {
|
||||
e = htab->elems + (i & htab->mask);
|
||||
if ((!e->item.key && (!e->hash || e->hash == dead)) ||
|
||||
if (!e->item.key ||
|
||||
(e->hash==hash && STRCMP(e->item.key, key)==0))
|
||||
break;
|
||||
}
|
||||
@ -142,67 +138,50 @@ void htab_destroy(struct htab *htab)
|
||||
free(htab);
|
||||
}
|
||||
|
||||
static struct elem *htab_find_elem(struct htab *htab, const char* key)
|
||||
static htab_entry *htab_find_item(struct htab *htab, const char* key)
|
||||
{
|
||||
size_t hash = keyhash(key, htab->seed);
|
||||
struct elem *e = lookup(htab, key, hash, 0);
|
||||
struct elem *e = lookup(htab, key, hash);
|
||||
|
||||
if (e->item.key) {
|
||||
return e;
|
||||
return &e->item;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
htab_value* htab_find(struct htab *htab, const char* key)
|
||||
{
|
||||
struct elem *e = htab_find_elem(htab, key);
|
||||
if(!e) return 0;
|
||||
return &e->item.data;
|
||||
}
|
||||
|
||||
htab_value* htab_find2(struct htab *htab, const char* key, char **saved_key)
|
||||
{
|
||||
struct elem *e = htab_find_elem(htab, key);
|
||||
if(!e) return 0;
|
||||
*saved_key = e->item.key;
|
||||
return &e->item.data;
|
||||
htab_entry *i = htab_find_item(htab, key);
|
||||
if(i) return &i->data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int htab_delete(struct htab *htab, const char* key)
|
||||
{
|
||||
struct elem *e = htab_find_elem(htab, key);
|
||||
if(!e) return 0;
|
||||
e->item.key = 0;
|
||||
e->hash = 0xdeadc0de;
|
||||
--htab->used;
|
||||
++htab->dead;
|
||||
htab_entry *i = htab_find_item(htab, key);
|
||||
if(!i) return 0;
|
||||
i->key = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int htab_insert(struct htab *htab, char* key, htab_value value)
|
||||
{
|
||||
size_t hash = keyhash(key, htab->seed), oh;
|
||||
struct elem *e = lookup(htab, key, hash, 0xdeadc0de);
|
||||
size_t hash = keyhash(key, htab->seed);
|
||||
struct elem *e = lookup(htab, key, hash);
|
||||
if(e->item.key) {
|
||||
/* it's not allowed to overwrite existing data */
|
||||
return 0;
|
||||
}
|
||||
|
||||
oh = e->hash; /* save old hash in case it's tombstone marker */
|
||||
e->item.key = key;
|
||||
e->item.data = value;
|
||||
e->hash = hash;
|
||||
if (++htab->used + htab->dead > htab->mask - htab->mask/4) {
|
||||
if (++htab->used > htab->mask - htab->mask/4) {
|
||||
if (!resize(htab, 2*htab->used)) {
|
||||
htab->used--;
|
||||
e->item.key = 0;
|
||||
e->hash = oh;
|
||||
return 0;
|
||||
}
|
||||
htab->dead = 0;
|
||||
} else if (oh == 0xdeadc0de) {
|
||||
/* re-used tomb */
|
||||
--htab->dead;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@ -14,8 +14,6 @@ typedef union htab_value {
|
||||
struct htab * htab_create(size_t);
|
||||
void htab_destroy(struct htab *);
|
||||
htab_value* htab_find(struct htab *, const char* key);
|
||||
/* same as htab_find, but can retrieve the saved key (for freeing) */
|
||||
htab_value* htab_find2(struct htab *htab, const char* key, char **saved_key);
|
||||
int htab_insert(struct htab *, char*, htab_value);
|
||||
int htab_delete(struct htab *htab, const char* key);
|
||||
size_t htab_next(struct htab *, size_t iterator, char** key, htab_value **v);
|
||||
|
@ -20,9 +20,10 @@
|
||||
* HTML error pages with variable substitution.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include <regex.h>
|
||||
#include "main.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "buffer.h"
|
||||
#include "conns.h"
|
||||
#include "heap.h"
|
||||
@ -30,9 +31,6 @@
|
||||
#include "network.h"
|
||||
#include "utils.h"
|
||||
#include "conf.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <regex.h>
|
||||
|
||||
/*
|
||||
* Add an error number -> filename mapping to the errorpages list.
|
||||
@ -134,21 +132,30 @@ send_html_file (FILE *infile, struct conn_s *connptr)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int send_http_headers (
|
||||
struct conn_s *connptr, int code,
|
||||
const char *message, const char *extra)
|
||||
int send_http_headers (struct conn_s *connptr, int code, const char *message)
|
||||
{
|
||||
const char headers[] =
|
||||
"HTTP/1.%u %d %s\r\n"
|
||||
"Server: %s\r\n"
|
||||
"HTTP/1.0 %d %s\r\n"
|
||||
"Server: %s/%s\r\n"
|
||||
"Content-Type: text/html\r\n"
|
||||
"%s"
|
||||
"Connection: close\r\n" "\r\n";
|
||||
|
||||
const char p_auth_str[] =
|
||||
"Proxy-Authenticate: Basic realm=\""
|
||||
PACKAGE_NAME "\"\r\n";
|
||||
|
||||
const char w_auth_str[] =
|
||||
"WWW-Authenticate: Basic realm=\""
|
||||
PACKAGE_NAME "\"\r\n";
|
||||
|
||||
/* according to rfc7235, the 407 error must be accompanied by
|
||||
a Proxy-Authenticate header field. */
|
||||
const char *add = code == 407 ? p_auth_str : (code == 401 ? w_auth_str : "");
|
||||
|
||||
return (write_message (connptr->client_fd, headers,
|
||||
connptr->protocol.major != 1 ? 0 : connptr->protocol.minor,
|
||||
code, message, PACKAGE,
|
||||
extra));
|
||||
code, message, PACKAGE, VERSION,
|
||||
add));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -169,47 +176,20 @@ int send_http_error_message (struct conn_s *connptr)
|
||||
"<h1>%s</h1>\n"
|
||||
"<p>%s</p>\n"
|
||||
"<hr />\n"
|
||||
"<p><em>Generated by %s.</em></p>\n" "</body>\n"
|
||||
"<p><em>Generated by %s version %s.</em></p>\n" "</body>\n"
|
||||
"</html>\n";
|
||||
|
||||
/* according to rfc7235, the 407 error must be accompanied by
|
||||
a Proxy-Authenticate header field. */
|
||||
const char *auth_str_type =
|
||||
connptr->error_number == 407 ? "Proxy-Authenticate" :
|
||||
(connptr->error_number == 401 ? "WWW-Authenticate" : "");
|
||||
|
||||
const char auth_str_tpl[] = "%s: Basic realm=\"%s\"\r\n";
|
||||
char* auth_str_add = NULL;
|
||||
|
||||
if (auth_str_type[0] != 0) {
|
||||
int auth_str_size = snprintf (NULL, 0, auth_str_tpl,
|
||||
auth_str_type, config->basicauth_realm) + 1;
|
||||
if (auth_str_size > 0) {
|
||||
auth_str_add = safemalloc (auth_str_size);
|
||||
if (auth_str_add != NULL) {
|
||||
snprintf (auth_str_add, auth_str_size, auth_str_tpl,
|
||||
auth_str_type, config->basicauth_realm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
send_http_headers (connptr, connptr->error_number,
|
||||
connptr->error_string, auth_str_add ? auth_str_add : "");
|
||||
|
||||
if (auth_str_add) safefree (auth_str_add);
|
||||
connptr->error_string);
|
||||
|
||||
error_file = get_html_file (connptr->error_number);
|
||||
if (!error_file || !(infile = fopen (error_file, "r"))) {
|
||||
char *detail;
|
||||
if (error_file) log_message (LOG_ERR,
|
||||
"Error opening error file '%s' (%s)",
|
||||
error_file, strerror (errno));
|
||||
detail = lookup_variable (connptr->error_variables, "detail");
|
||||
if (!(infile = fopen (error_file, "r"))) {
|
||||
char *detail = lookup_variable (connptr->error_variables, "detail");
|
||||
return (write_message (connptr->client_fd, fallback_error,
|
||||
connptr->error_number,
|
||||
connptr->error_string,
|
||||
connptr->error_string,
|
||||
detail, PACKAGE));
|
||||
detail, PACKAGE, VERSION));
|
||||
}
|
||||
|
||||
ret = send_html_file (infile, connptr);
|
||||
@ -263,7 +243,6 @@ int add_standard_vars (struct conn_s *connptr)
|
||||
char errnobuf[16];
|
||||
char timebuf[30];
|
||||
time_t global_time;
|
||||
struct tm tm_buf;
|
||||
|
||||
snprintf (errnobuf, sizeof errnobuf, "%d", connptr->error_number);
|
||||
ADD_VAR_RET ("errno", errnobuf);
|
||||
@ -279,7 +258,7 @@ int add_standard_vars (struct conn_s *connptr)
|
||||
|
||||
global_time = time (NULL);
|
||||
strftime (timebuf, sizeof (timebuf), "%a, %d %b %Y %H:%M:%S GMT",
|
||||
gmtime_r (&global_time, &tm_buf));
|
||||
gmtime (&global_time));
|
||||
add_error_variable (connptr, "date", timebuf);
|
||||
|
||||
add_error_variable (connptr, "website",
|
||||
|
@ -33,7 +33,7 @@ extern int add_error_variable (struct conn_s *connptr, const char *key,
|
||||
const char *val);
|
||||
extern int send_html_file (FILE * infile, struct conn_s *connptr);
|
||||
extern int send_http_headers (struct conn_s *connptr, int code,
|
||||
const char *message, const char *extra);
|
||||
const char *message);
|
||||
extern int add_standard_vars (struct conn_s *connptr);
|
||||
|
||||
#endif /* !TINYPROXY_HTML_ERROR_H */
|
||||
|
@ -232,7 +232,6 @@ int http_message_send (http_message_t msg, int fd)
|
||||
char timebuf[30];
|
||||
time_t global_time;
|
||||
unsigned int i;
|
||||
struct tm tm_buf;
|
||||
|
||||
assert (is_http_message_valid (msg));
|
||||
|
||||
@ -255,11 +254,11 @@ int http_message_send (http_message_t msg, int fd)
|
||||
/* Output the date */
|
||||
global_time = time (NULL);
|
||||
strftime (timebuf, sizeof (timebuf), "%a, %d %b %Y %H:%M:%S GMT",
|
||||
gmtime_r (&global_time, &tm_buf));
|
||||
gmtime (&global_time));
|
||||
write_message (fd, "Date: %s\r\n", timebuf);
|
||||
|
||||
/* Output the content-length */
|
||||
write_message (fd, "Content-length: %lu\r\n", (unsigned long) msg->body.length);
|
||||
write_message (fd, "Content-length: %u\r\n", msg->body.length);
|
||||
|
||||
/* Write the separator between the headers and body */
|
||||
safe_write (fd, "\r\n", 2);
|
||||
|
@ -109,7 +109,6 @@ void log_message (int level, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
struct timespec nowtime;
|
||||
struct tm tm_buf;
|
||||
|
||||
char time_string[TIME_LENGTH];
|
||||
char str[STRING_LENGTH];
|
||||
@ -178,11 +177,11 @@ void log_message (int level, const char *fmt, ...)
|
||||
clock_gettime(CLOCK_REALTIME, &nowtime);
|
||||
/* Format is month day hour:minute:second (24 time) */
|
||||
strftime (time_string, TIME_LENGTH, "%b %d %H:%M:%S",
|
||||
localtime_r (&nowtime.tv_sec, &tm_buf));
|
||||
localtime (&nowtime.tv_sec));
|
||||
|
||||
snprintf (str, STRING_LENGTH, "%-9s %s.%03lu [%ld]: ",
|
||||
snprintf (str, STRING_LENGTH, "%-9s %s.%03u [%ld]: ",
|
||||
syslog_level[level], time_string,
|
||||
(unsigned long) nowtime.tv_nsec/1000000ul,
|
||||
nowtime.tv_nsec/1000000u,
|
||||
(long int) getpid ());
|
||||
|
||||
/*
|
||||
|
21
src/main.c
21
src/main.c
@ -254,28 +254,27 @@ change_user (const char *program)
|
||||
*/
|
||||
int reload_config (int reload_logging)
|
||||
{
|
||||
int ret, ret2;
|
||||
int ret;
|
||||
struct config_s *c_next = get_next_config();
|
||||
|
||||
log_message (LOG_NOTICE, "Reloading config file (%s)", config_file);
|
||||
log_message (LOG_NOTICE, "Reloading config file");
|
||||
|
||||
if (reload_logging) shutdown_logging ();
|
||||
|
||||
ret = reload_config_file (config_file, c_next);
|
||||
|
||||
if (ret == 0) {
|
||||
if(config) free_config (config);
|
||||
config = c_next;
|
||||
if (ret != 0) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret2 = reload_logging ? setup_logging () : 0;
|
||||
if(config) free_config (config);
|
||||
config = c_next;
|
||||
|
||||
if (ret != 0)
|
||||
log_message (LOG_WARNING, "Reloading config file failed!");
|
||||
else
|
||||
log_message (LOG_NOTICE, "Reloading config file finished");
|
||||
if (reload_logging) ret = setup_logging ();
|
||||
log_message (LOG_NOTICE, "Reloading config file finished");
|
||||
|
||||
return ret ? ret : ret2;
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void setup_sig(int sig, signal_func *sigh,
|
||||
|
@ -81,19 +81,14 @@ char* orderedmap_find(struct orderedmap *o, const char *key) {
|
||||
int orderedmap_remove(struct orderedmap *o, const char *key) {
|
||||
size_t i;
|
||||
char *lk;
|
||||
char *sk;
|
||||
char **sv;
|
||||
htab_value *lv, *v = htab_find2(o->map, key, &sk);
|
||||
htab_value *lv, *v = htab_find(o->map, key);
|
||||
if(!v) return 0;
|
||||
sv = sblist_get(o->values, v->n);
|
||||
free(*sv);
|
||||
htab_delete(o->map, key);
|
||||
sblist_delete(o->values, v->n);
|
||||
i = 0;
|
||||
while((i = htab_next(o->map, i, &lk, &lv))) {
|
||||
if(lv->n > v->n) lv->n--;
|
||||
}
|
||||
htab_delete(o->map, key);
|
||||
free(sk);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
285
src/reqs.c
285
src/reqs.c
@ -268,49 +268,48 @@ establish_http_connection (struct conn_s *connptr, struct request_s *request)
|
||||
/* host is an IPv6 address literal, so surround it with
|
||||
* [] */
|
||||
return write_message (connptr->server_fd,
|
||||
"%s %s HTTP/1.%u\r\n"
|
||||
"%s %s HTTP/1.0\r\n"
|
||||
"Host: [%s]%s\r\n"
|
||||
"Connection: close\r\n",
|
||||
request->method, request->path,
|
||||
connptr->protocol.major != 1 ? 0 :
|
||||
connptr->protocol.minor,
|
||||
request->host, portbuff);
|
||||
} else if (connptr->upstream_proxy &&
|
||||
connptr->upstream_proxy->type == PT_HTTP &&
|
||||
connptr->upstream_proxy->ua.authstr) {
|
||||
return write_message (connptr->server_fd,
|
||||
"%s %s HTTP/1.%u\r\n"
|
||||
"%s %s HTTP/1.0\r\n"
|
||||
"Host: %s%s\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Proxy-Authorization: Basic %s\r\n",
|
||||
request->method, request->path,
|
||||
connptr->protocol.major != 1 ? 0 :
|
||||
connptr->protocol.minor,
|
||||
request->host, portbuff,
|
||||
connptr->upstream_proxy->ua.authstr);
|
||||
} else {
|
||||
return write_message (connptr->server_fd,
|
||||
"%s %s HTTP/1.%u\r\n"
|
||||
"%s %s HTTP/1.0\r\n"
|
||||
"Host: %s%s\r\n"
|
||||
"Connection: close\r\n",
|
||||
request->method, request->path,
|
||||
connptr->protocol.major != 1 ? 0 :
|
||||
connptr->protocol.minor,
|
||||
request->host, portbuff);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Send the appropriate response to the client to establish a
|
||||
* connection via CONNECT method.
|
||||
* These two defines are for the SSL tunnelling.
|
||||
*/
|
||||
static int send_connect_method_response (struct conn_s *connptr)
|
||||
#define SSL_CONNECTION_RESPONSE "HTTP/1.0 200 Connection established"
|
||||
#define PROXY_AGENT "Proxy-agent: " PACKAGE "/" VERSION
|
||||
|
||||
/*
|
||||
* Send the appropriate response to the client to establish a SSL
|
||||
* connection.
|
||||
*/
|
||||
static int send_ssl_response (struct conn_s *connptr)
|
||||
{
|
||||
return write_message (connptr->client_fd,
|
||||
"HTTP/1.%u 200 Connection established\r\n"
|
||||
"Proxy-agent: " PACKAGE "\r\n"
|
||||
"\r\n", connptr->protocol.major != 1 ? 0 :
|
||||
connptr->protocol.minor);
|
||||
"%s\r\n"
|
||||
"%s\r\n"
|
||||
"\r\n", SSL_CONNECTION_RESPONSE, PROXY_AGENT);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -322,11 +321,9 @@ static struct request_s *process_request (struct conn_s *connptr,
|
||||
{
|
||||
char *url;
|
||||
struct request_s *request;
|
||||
int ret, skip_trans;
|
||||
int ret;
|
||||
size_t request_len;
|
||||
|
||||
skip_trans = 0;
|
||||
|
||||
/* NULL out all the fields so frees don't cause segfaults. */
|
||||
request =
|
||||
(struct request_s *) safecalloc (1, sizeof (struct request_s));
|
||||
@ -343,12 +340,8 @@ static struct request_s *process_request (struct conn_s *connptr,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* zero-terminate the strings so they don't contain junk in error page */
|
||||
request->method[0] = url[0] = request->protocol[0] = 0;
|
||||
|
||||
ret = sscanf (connptr->request_line, "%[^ ] %[^ ] %[^ ]",
|
||||
request->method, url, request->protocol);
|
||||
|
||||
if (ret == 2 && !strcasecmp (request->method, "GET")) {
|
||||
request->protocol[0] = 0;
|
||||
|
||||
@ -390,20 +383,12 @@ BAD_REQUEST_ERROR:
|
||||
* we'll be closing anyway.
|
||||
*/
|
||||
char *reverse_url;
|
||||
int reverse_status;
|
||||
|
||||
reverse_url = reverse_rewrite_url (connptr, hashofheaders, url, &reverse_status);
|
||||
reverse_url = reverse_rewrite_url (connptr, hashofheaders, url);
|
||||
|
||||
if (reverse_url != NULL) {
|
||||
if (reverse_status == 301) {
|
||||
char buf[PATH_MAX];
|
||||
snprintf (buf, sizeof buf, "Location: %s\r\n", reverse_url);
|
||||
send_http_headers (connptr, 301, "Moved Permanently", buf);
|
||||
goto fail;
|
||||
}
|
||||
safefree (url);
|
||||
url = reverse_url;
|
||||
skip_trans = 1;
|
||||
} else if (config->reverseonly) {
|
||||
log_message (LOG_ERR,
|
||||
"Bad request, no mapping for '%s' found",
|
||||
@ -453,13 +438,11 @@ BAD_REQUEST_ERROR:
|
||||
connptr->connect_method = TRUE;
|
||||
} else {
|
||||
#ifdef TRANSPARENT_PROXY
|
||||
if (!skip_trans) {
|
||||
if (!do_transparent_proxy
|
||||
(connptr, hashofheaders, request, config, &url))
|
||||
goto fail;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (!do_transparent_proxy
|
||||
(connptr, hashofheaders, request, config, &url)) {
|
||||
goto fail;
|
||||
}
|
||||
#else
|
||||
indicate_http_error (connptr, 501, "Not Implemented",
|
||||
"detail",
|
||||
"Unknown method or unsupported protocol.",
|
||||
@ -467,7 +450,7 @@ BAD_REQUEST_ERROR:
|
||||
log_message (LOG_INFO, "Unknown method (%s) or protocol (%s)",
|
||||
request->method, url);
|
||||
goto fail;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef FILTER_ENABLE
|
||||
@ -475,16 +458,22 @@ BAD_REQUEST_ERROR:
|
||||
* Filter restricted domains/urls
|
||||
*/
|
||||
if (config->filter) {
|
||||
int fu = config->filter_opts & FILTER_OPT_URL;
|
||||
ret = filter_run (fu ? url : request->host);
|
||||
if (config->filter_url)
|
||||
ret = filter_run (url);
|
||||
else
|
||||
ret = filter_run (request->host);
|
||||
|
||||
if (ret) {
|
||||
update_stats (STAT_DENIED);
|
||||
|
||||
log_message (LOG_NOTICE,
|
||||
"Proxying refused on filtered %s \"%s\"",
|
||||
fu ? "url" : "domain",
|
||||
fu ? url : request->host);
|
||||
if (config->filter_url)
|
||||
log_message (LOG_NOTICE,
|
||||
"Proxying refused on filtered url \"%s\"",
|
||||
url);
|
||||
else
|
||||
log_message (LOG_NOTICE,
|
||||
"Proxying refused on filtered domain \"%s\"",
|
||||
request->host);
|
||||
|
||||
indicate_http_error (connptr, 403, "Filtered",
|
||||
"detail",
|
||||
@ -521,7 +510,7 @@ fail:
|
||||
* server headers can be processed.
|
||||
* - rjkaes
|
||||
*/
|
||||
static int pull_client_data (struct conn_s *connptr, long int length, int iehack)
|
||||
static int pull_client_data (struct conn_s *connptr, long int length)
|
||||
{
|
||||
char *buffer;
|
||||
ssize_t len;
|
||||
@ -546,75 +535,39 @@ static int pull_client_data (struct conn_s *connptr, long int length, int iehack
|
||||
length -= len;
|
||||
} while (length > 0);
|
||||
|
||||
if (iehack) {
|
||||
/*
|
||||
* BUG FIX: Internet Explorer will leave two bytes (carriage
|
||||
* return and line feed) at the end of a POST message. These
|
||||
* need to be eaten for tinyproxy to work correctly.
|
||||
*/
|
||||
ret = socket_nonblocking (connptr->client_fd);
|
||||
if (ret != 0) {
|
||||
log_message(LOG_ERR, "Failed to set the client socket "
|
||||
"to non-blocking: %s", strerror(errno));
|
||||
goto ERROR_EXIT;
|
||||
}
|
||||
|
||||
len = recv (connptr->client_fd, buffer, 2, MSG_PEEK);
|
||||
|
||||
ret = socket_blocking (connptr->client_fd);
|
||||
if (ret != 0) {
|
||||
log_message(LOG_ERR, "Failed to set the client socket "
|
||||
"to blocking: %s", strerror(errno));
|
||||
goto ERROR_EXIT;
|
||||
}
|
||||
|
||||
if (len < 0 && errno != EAGAIN)
|
||||
goto ERROR_EXIT;
|
||||
|
||||
if ((len == 2) && CHECK_CRLF (buffer, len)) {
|
||||
ssize_t bytes_read;
|
||||
|
||||
bytes_read = read (connptr->client_fd, buffer, 2);
|
||||
if (bytes_read == -1) {
|
||||
log_message
|
||||
(LOG_WARNING,
|
||||
"Could not read two bytes from POST message");
|
||||
}
|
||||
}
|
||||
/*
|
||||
* BUG FIX: Internet Explorer will leave two bytes (carriage
|
||||
* return and line feed) at the end of a POST message. These
|
||||
* need to be eaten for tinyproxy to work correctly.
|
||||
*/
|
||||
ret = socket_nonblocking (connptr->client_fd);
|
||||
if (ret != 0) {
|
||||
log_message(LOG_ERR, "Failed to set the client socket "
|
||||
"to non-blocking: %s", strerror(errno));
|
||||
goto ERROR_EXIT;
|
||||
}
|
||||
|
||||
safefree (buffer);
|
||||
return 0;
|
||||
len = recv (connptr->client_fd, buffer, 2, MSG_PEEK);
|
||||
|
||||
ERROR_EXIT:
|
||||
safefree (buffer);
|
||||
return -1;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/* pull chunked client data */
|
||||
static int pull_client_data_chunked (struct conn_s *connptr) {
|
||||
char *buffer = 0;
|
||||
ssize_t len;
|
||||
long chunklen;
|
||||
if (len < 0 && errno != EAGAIN)
|
||||
goto ERROR_EXIT;
|
||||
|
||||
while(1) {
|
||||
if (buffer) safefree(buffer);
|
||||
len = readline (connptr->client_fd, &buffer);
|
||||
if ((len == 2) && CHECK_CRLF (buffer, len)) {
|
||||
ssize_t bytes_read;
|
||||
|
||||
if (len <= 0)
|
||||
goto ERROR_EXIT;
|
||||
|
||||
if (!connptr->error_variables) {
|
||||
if (safe_write (connptr->server_fd, buffer, len) < 0)
|
||||
goto ERROR_EXIT;
|
||||
bytes_read = read (connptr->client_fd, buffer, 2);
|
||||
if (bytes_read == -1) {
|
||||
log_message
|
||||
(LOG_WARNING,
|
||||
"Could not read two bytes from POST message");
|
||||
}
|
||||
|
||||
chunklen = strtol (buffer, (char**)0, 16);
|
||||
|
||||
if (pull_client_data (connptr, chunklen+2, 0) < 0)
|
||||
goto ERROR_EXIT;
|
||||
|
||||
if(!chunklen) break;
|
||||
}
|
||||
|
||||
safefree (buffer);
|
||||
@ -779,7 +732,7 @@ static int remove_connection_headers (orderedmap hashofheaders)
|
||||
char *data;
|
||||
char *ptr;
|
||||
ssize_t len;
|
||||
int i,j,df;
|
||||
int i;
|
||||
|
||||
for (i = 0; i != (sizeof (headers) / sizeof (char *)); ++i) {
|
||||
/* Look for the connection header. If it's not found, return. */
|
||||
@ -804,12 +757,7 @@ static int remove_connection_headers (orderedmap hashofheaders)
|
||||
*/
|
||||
ptr = data;
|
||||
while (ptr < data + len) {
|
||||
df = 0;
|
||||
/* check that ptr isn't one of headers to prevent
|
||||
double-free (CVE-2023-49606) */
|
||||
for (j = 0; j != (sizeof (headers) / sizeof (char *)); ++j)
|
||||
if(!strcasecmp(ptr, headers[j])) df = 1;
|
||||
if (!df) orderedmap_remove (hashofheaders, ptr);
|
||||
orderedmap_remove (hashofheaders, ptr);
|
||||
|
||||
/* Advance ptr to the next token */
|
||||
ptr += strlen (ptr) + 1;
|
||||
@ -826,7 +774,7 @@ static int remove_connection_headers (orderedmap hashofheaders)
|
||||
|
||||
/*
|
||||
* If there is a Content-Length header, then return the value; otherwise, return
|
||||
* -1.
|
||||
* a negative number.
|
||||
*/
|
||||
static long get_content_length (orderedmap hashofheaders)
|
||||
{
|
||||
@ -841,13 +789,6 @@ static long get_content_length (orderedmap hashofheaders)
|
||||
return content_length;
|
||||
}
|
||||
|
||||
static int is_chunked_transfer (orderedmap hashofheaders)
|
||||
{
|
||||
char *data;
|
||||
data = orderedmap_find (hashofheaders, "transfer-encoding");
|
||||
return data ? !strcmp (data, "chunked") : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Search for Via header in a hash of headers and either write a new Via
|
||||
* header, or append our information to the end of an existing Via header.
|
||||
@ -881,14 +822,15 @@ write_via_header (int fd, orderedmap hashofheaders,
|
||||
data = orderedmap_find (hashofheaders, "via");
|
||||
if (data) {
|
||||
ret = write_message (fd,
|
||||
"Via: %s, %hu.%hu %s (%s)\r\n",
|
||||
data, major, minor, hostname, PACKAGE);
|
||||
"Via: %s, %hu.%hu %s (%s/%s)\r\n",
|
||||
data, major, minor, hostname, PACKAGE,
|
||||
VERSION);
|
||||
|
||||
orderedmap_remove (hashofheaders, "via");
|
||||
} else {
|
||||
ret = write_message (fd,
|
||||
"Via: %hu.%hu %s (%s)\r\n",
|
||||
major, minor, hostname, PACKAGE);
|
||||
"Via: %hu.%hu %s (%s/%s)\r\n",
|
||||
major, minor, hostname, PACKAGE, VERSION);
|
||||
}
|
||||
|
||||
done:
|
||||
@ -941,10 +883,6 @@ process_client_headers (struct conn_s *connptr, orderedmap hashofheaders)
|
||||
*/
|
||||
connptr->content_length.client = get_content_length (hashofheaders);
|
||||
|
||||
/* Check whether client sends chunked data. */
|
||||
if (connptr->content_length.client == -1 && is_chunked_transfer (hashofheaders))
|
||||
connptr->content_length.client = -2;
|
||||
|
||||
/*
|
||||
* See if there is a "Connection" header. If so, we need to do a bit
|
||||
* of processing. :)
|
||||
@ -1009,9 +947,8 @@ process_client_headers (struct conn_s *connptr, orderedmap hashofheaders)
|
||||
PULL_CLIENT_DATA:
|
||||
if (connptr->content_length.client > 0) {
|
||||
ret = pull_client_data (connptr,
|
||||
connptr->content_length.client, 1);
|
||||
} else if (connptr->content_length.client == -2)
|
||||
ret = pull_client_data_chunked (connptr);
|
||||
connptr->content_length.client);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -1286,7 +1223,6 @@ static void relay_connection (struct conn_s *connptr)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef UPSTREAM_SUPPORT
|
||||
static int
|
||||
connect_to_upstream_proxy(struct conn_s *connptr, struct request_s *request)
|
||||
{
|
||||
@ -1295,6 +1231,7 @@ connect_to_upstream_proxy(struct conn_s *connptr, struct request_s *request)
|
||||
unsigned short port;
|
||||
size_t ulen, passlen;
|
||||
|
||||
struct hostent *host;
|
||||
struct upstream *cur_upstream = connptr->upstream_proxy;
|
||||
|
||||
ulen = cur_upstream->ua.user ? strlen(cur_upstream->ua.user) : 0;
|
||||
@ -1311,13 +1248,10 @@ connect_to_upstream_proxy(struct conn_s *connptr, struct request_s *request)
|
||||
buff[1] = 1; /* connect command */
|
||||
port = htons(request->port);
|
||||
memcpy(&buff[2], &port, 2); /* dest port */
|
||||
memcpy(&buff[4], "\0\0\0\1" /* socks4a fake ip */
|
||||
"\0" /* user */, 5);
|
||||
len = strlen(request->host);
|
||||
if(len>255)
|
||||
return -1;
|
||||
memcpy(&buff[9], request->host, len+1);
|
||||
if (9+len+1 != safe_write(connptr->server_fd, buff, 9+len+1))
|
||||
host = gethostbyname(request->host);
|
||||
memcpy(&buff[4], host->h_addr_list[0], 4); /* dest ip */
|
||||
buff[8] = 0; /* user */
|
||||
if (9 != safe_write(connptr->server_fd, buff, 9))
|
||||
return -1;
|
||||
if (8 != safe_read(connptr->server_fd, buff, 8))
|
||||
return -1;
|
||||
@ -1403,7 +1337,7 @@ connect_to_upstream_proxy(struct conn_s *connptr, struct request_s *request)
|
||||
|
||||
return establish_http_connection(connptr, request);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Establish a connection to the upstream proxy server.
|
||||
@ -1427,7 +1361,7 @@ connect_to_upstream (struct conn_s *connptr, struct request_s *request)
|
||||
log_message (LOG_WARNING,
|
||||
"No upstream proxy defined for %s.",
|
||||
request->host);
|
||||
indicate_http_error (connptr, 502,
|
||||
indicate_http_error (connptr, 404,
|
||||
"Unable to connect to upstream proxy.");
|
||||
return -1;
|
||||
}
|
||||
@ -1439,7 +1373,7 @@ connect_to_upstream (struct conn_s *connptr, struct request_s *request)
|
||||
if (connptr->server_fd < 0) {
|
||||
log_message (LOG_WARNING,
|
||||
"Could not connect to upstream proxy.");
|
||||
indicate_http_error (connptr, 502,
|
||||
indicate_http_error (connptr, 404,
|
||||
"Unable to connect to upstream proxy",
|
||||
"detail",
|
||||
"A network error occurred while trying to "
|
||||
@ -1515,13 +1449,13 @@ get_request_entity(struct conn_s *connptr)
|
||||
nread = read_buffer (connptr->client_fd, connptr->cbuffer);
|
||||
if (nread < 0) {
|
||||
log_message (LOG_ERR,
|
||||
"Error reading readable client_fd %d (%s)",
|
||||
connptr->client_fd, strerror(errno));
|
||||
"Error reading readable client_fd %d",
|
||||
connptr->client_fd);
|
||||
ret = -1;
|
||||
} else {
|
||||
log_message (LOG_INFO,
|
||||
"Read request entity of %ld bytes",
|
||||
(long) nread);
|
||||
"Read request entity of %d bytes",
|
||||
nread);
|
||||
ret = 0;
|
||||
}
|
||||
} else {
|
||||
@ -1559,19 +1493,6 @@ static void handle_connection_failure(struct conn_s *connptr, int got_headers)
|
||||
}
|
||||
}
|
||||
|
||||
static void auth_error(struct conn_s *connptr, int code) {
|
||||
const char *tit = code == 401 ? "Unauthorized" : "Proxy Authentication Required";
|
||||
const char *msg = code == 401 ?
|
||||
"The administrator of this proxy has not configured it to service requests from you." :
|
||||
"This proxy requires authentication.";
|
||||
|
||||
update_stats (STAT_DENIED);
|
||||
log_message (LOG_INFO,
|
||||
"Failed auth attempt (file descriptor: %d), ip %s",
|
||||
connptr->client_fd,
|
||||
connptr->client_ip_addr);
|
||||
indicate_http_error (connptr, code, tit, "detail", msg, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the main drive for each connection. As you can tell, for the
|
||||
@ -1581,9 +1502,6 @@ static void auth_error(struct conn_s *connptr, int code) {
|
||||
* when we start the relay portion. This makes most of the original
|
||||
* tinyproxy code, which was confusing, redundant. Hail progress.
|
||||
* - rjkaes
|
||||
|
||||
* this function is called directly from child_thread() with the newly
|
||||
* received fd from accept().
|
||||
*/
|
||||
void handle_connection (struct conn_s *connptr, union sockaddr_union* addr)
|
||||
{
|
||||
@ -1595,6 +1513,7 @@ void handle_connection (struct conn_s *connptr, union sockaddr_union* addr)
|
||||
int got_headers = 0, fd = connptr->client_fd;
|
||||
size_t i;
|
||||
struct request_s *request = NULL;
|
||||
struct timeval tv;
|
||||
orderedmap hashofheaders = NULL;
|
||||
|
||||
char sock_ipaddr[IP_LENGTH];
|
||||
@ -1616,7 +1535,12 @@ void handle_connection (struct conn_s *connptr, union sockaddr_union* addr)
|
||||
return;
|
||||
}
|
||||
|
||||
set_socket_timeout(fd);
|
||||
tv.tv_usec = 0;
|
||||
tv.tv_sec = config->idletimeout;
|
||||
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (void*) &tv, sizeof(tv));
|
||||
tv.tv_usec = 0;
|
||||
tv.tv_sec = config->idletimeout;
|
||||
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (void*) &tv, sizeof(tv));
|
||||
|
||||
if (connection_loops (addr)) {
|
||||
log_message (LOG_CONN,
|
||||
@ -1644,7 +1568,11 @@ void handle_connection (struct conn_s *connptr, union sockaddr_union* addr)
|
||||
|
||||
if (read_request_line (connptr) < 0) {
|
||||
update_stats (STAT_BADCONN);
|
||||
goto done;
|
||||
indicate_http_error (connptr, 408, "Timeout",
|
||||
"detail",
|
||||
"Server timeout waiting for the HTTP request "
|
||||
"from the client.", NULL);
|
||||
HC_FAIL();
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1690,7 +1618,12 @@ void handle_connection (struct conn_s *connptr, union sockaddr_union* addr)
|
||||
}
|
||||
|
||||
if (!authstring) {
|
||||
auth_error(connptr, stathost_connect ? 401 : 407);
|
||||
if (stathost_connect) goto e401;
|
||||
update_stats (STAT_DENIED);
|
||||
indicate_http_error (connptr, 407, "Proxy Authentication Required",
|
||||
"detail",
|
||||
"This proxy requires authentication.",
|
||||
NULL);
|
||||
HC_FAIL();
|
||||
}
|
||||
if ( /* currently only "basic" auth supported */
|
||||
@ -1699,7 +1632,13 @@ void handle_connection (struct conn_s *connptr, union sockaddr_union* addr)
|
||||
basicauth_check (config->basicauth_list, authstring + 6) == 1)
|
||||
failure = 0;
|
||||
if(failure) {
|
||||
auth_error(connptr, stathost_connect ? 401 : 407);
|
||||
e401:
|
||||
update_stats (STAT_DENIED);
|
||||
indicate_http_error (connptr, 401, "Unauthorized",
|
||||
"detail",
|
||||
"The administrator of this proxy has not configured "
|
||||
"it to service requests from you.",
|
||||
NULL);
|
||||
HC_FAIL();
|
||||
}
|
||||
orderedmap_remove (hashofheaders, "proxy-authorization");
|
||||
@ -1773,10 +1712,10 @@ void handle_connection (struct conn_s *connptr, union sockaddr_union* addr)
|
||||
HC_FAIL();
|
||||
}
|
||||
} else {
|
||||
if (send_connect_method_response (connptr) < 0) {
|
||||
if (send_ssl_response (connptr) < 0) {
|
||||
log_message (LOG_ERR,
|
||||
"handle_connection: Could not send CONNECT"
|
||||
" method greeting to client.");
|
||||
"handle_connection: Could not send SSL greeting "
|
||||
"to client.");
|
||||
update_stats (STAT_BADCONN);
|
||||
HC_FAIL();
|
||||
}
|
||||
|
@ -34,7 +34,6 @@ void reversepath_add (const char *path, const char *url,
|
||||
struct reversepath **reversepath_list)
|
||||
{
|
||||
struct reversepath *reverse;
|
||||
size_t l;
|
||||
|
||||
if (url == NULL) {
|
||||
log_message (LOG_WARNING,
|
||||
@ -66,17 +65,8 @@ void reversepath_add (const char *path, const char *url,
|
||||
|
||||
if (!path)
|
||||
reverse->path = safestrdup ("/");
|
||||
else {
|
||||
l = strlen (path);
|
||||
if (l && path[l-1] == '/')
|
||||
reverse->path = safestrdup (path);
|
||||
else {
|
||||
reverse->path = safemalloc (l + 2);
|
||||
memcpy (reverse->path, path, l);
|
||||
reverse->path[l] = '/';
|
||||
reverse->path[l+1] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
reverse->path = safestrdup (path);
|
||||
|
||||
reverse->url = safestrdup (url);
|
||||
|
||||
@ -93,16 +83,10 @@ void reversepath_add (const char *path, const char *url,
|
||||
*/
|
||||
struct reversepath *reversepath_get (char *url, struct reversepath *reverse)
|
||||
{
|
||||
size_t l, lu, lp;
|
||||
while (reverse) {
|
||||
lu = strlen (url);
|
||||
lp = strlen (reverse->path);
|
||||
if ((
|
||||
(l = lu) == lp-1 ||
|
||||
(l = lp) <= lu
|
||||
) &&
|
||||
!memcmp(url, reverse->path, l))
|
||||
if (strstr (url, reverse->path) == url)
|
||||
return reverse;
|
||||
|
||||
reverse = reverse->next;
|
||||
}
|
||||
|
||||
@ -128,30 +112,23 @@ void free_reversepath_list (struct reversepath *reverse)
|
||||
* Rewrite the URL for reverse proxying.
|
||||
*/
|
||||
char *reverse_rewrite_url (struct conn_s *connptr, orderedmap hashofheaders,
|
||||
char *url, int *status)
|
||||
char *url)
|
||||
{
|
||||
char *rewrite_url = NULL;
|
||||
char *cookie = NULL;
|
||||
char *cookieval;
|
||||
struct reversepath *reverse = NULL;
|
||||
|
||||
*status = 0;
|
||||
|
||||
/* Reverse requests always start with a slash */
|
||||
if (*url == '/') {
|
||||
/* First try locating the reverse mapping by request url */
|
||||
reverse = reversepath_get (url, config->reversepath_list);
|
||||
if (reverse) {
|
||||
size_t lu = strlen (url);
|
||||
size_t lrp = strlen (reverse->path);
|
||||
if (lrp > lu) {
|
||||
rewrite_url = safestrdup (reverse->path);
|
||||
*status = 301;
|
||||
} else {
|
||||
rewrite_url = safemalloc (
|
||||
strlen (reverse->url) + lu + 1);
|
||||
sprintf (rewrite_url, "%s%s", reverse->url, url + lrp);
|
||||
}
|
||||
rewrite_url = (char *)
|
||||
safemalloc (strlen (url) + strlen (reverse->url) +
|
||||
1);
|
||||
strcpy (rewrite_url, reverse->url);
|
||||
strcat (rewrite_url, url + strlen (reverse->path));
|
||||
} else if (config->reversemagic
|
||||
&& (cookie = orderedmap_find (hashofheaders,
|
||||
"cookie"))) {
|
||||
|
@ -38,7 +38,6 @@ extern struct reversepath *reversepath_get (char *url,
|
||||
struct reversepath *reverse);
|
||||
void free_reversepath_list (struct reversepath *reverse);
|
||||
extern char *reverse_rewrite_url (struct conn_s *connptr,
|
||||
orderedmap hashofheaders, char *url,
|
||||
int *status);
|
||||
orderedmap hashofheaders, char *url);
|
||||
|
||||
#endif
|
||||
|
51
src/sock.c
51
src/sock.c
@ -34,7 +34,6 @@
|
||||
#include "text.h"
|
||||
#include "conf.h"
|
||||
#include "loop.h"
|
||||
#include "sblist.h"
|
||||
|
||||
/*
|
||||
* Return a human readable error for getaddrinfo() and getnameinfo().
|
||||
@ -47,16 +46,6 @@ static const char * get_gai_error (int n)
|
||||
return gai_strerror (n);
|
||||
}
|
||||
|
||||
static const char * family_string (int af)
|
||||
{
|
||||
switch(af) {
|
||||
case AF_UNSPEC: return "AF_UNSPEC";
|
||||
case AF_INET: return "AF_INET";
|
||||
case AF_INET6: return "AF_INET6";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
/*
|
||||
* Bind the given socket to the supplied address. The socket is
|
||||
* returned if the bind succeeded. Otherwise, -1 is returned
|
||||
@ -79,7 +68,7 @@ bind_socket (int sockfd, const char *addr, int family)
|
||||
n = getaddrinfo (addr, NULL, &hints, &res);
|
||||
if (n != 0) {
|
||||
log_message (LOG_INFO,
|
||||
"bind_socket: getaddrinfo failed for %s: %s (af: %s)", addr, get_gai_error (n), family_string(family));
|
||||
"bind_socket: getaddrinfo failed for %s: ", addr, get_gai_error (n));
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -98,36 +87,6 @@ bind_socket (int sockfd, const char *addr, int family)
|
||||
return sockfd;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try binding the given socket to supplied addresses, stopping when one succeeds.
|
||||
*/
|
||||
static int
|
||||
bind_socket_list (int sockfd, sblist *addresses, int family)
|
||||
{
|
||||
size_t nb_addresses = sblist_getsize(addresses);
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < nb_addresses; i++) {
|
||||
const char *address = *(const char **)sblist_get(addresses, i);
|
||||
if (bind_socket(sockfd, address, family) >= 0) {
|
||||
log_message(LOG_INFO, "Bound to %s", address);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void set_socket_timeout(int fd) {
|
||||
struct timeval tv;
|
||||
tv.tv_usec = 0;
|
||||
tv.tv_sec = config->idletimeout;
|
||||
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (void*) &tv, sizeof(tv));
|
||||
tv.tv_usec = 0;
|
||||
tv.tv_sec = config->idletimeout;
|
||||
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (void*) &tv, sizeof(tv));
|
||||
}
|
||||
|
||||
/*
|
||||
* Open a connection to a remote host. It's been re-written to use
|
||||
* the getaddrinfo() library function, which allows for a protocol
|
||||
@ -175,16 +134,14 @@ int opensock (const char *host, int port, const char *bind_to)
|
||||
close (sockfd);
|
||||
continue; /* can't bind, so try again */
|
||||
}
|
||||
} else if (config->bind_addrs) {
|
||||
if (bind_socket_list (sockfd, config->bind_addrs,
|
||||
res->ai_family) < 0) {
|
||||
} else if (config->bind_address) {
|
||||
if (bind_socket (sockfd, config->bind_address,
|
||||
res->ai_family) < 0) {
|
||||
close (sockfd);
|
||||
continue; /* can't bind, so try again */
|
||||
}
|
||||
}
|
||||
|
||||
set_socket_timeout(sockfd);
|
||||
|
||||
if (connect (sockfd, res->ai_addr, res->ai_addrlen) == 0) {
|
||||
union sockaddr_union *p = (void*) res->ai_addr, u;
|
||||
int af = res->ai_addr->sa_family;
|
||||
|
@ -56,8 +56,6 @@ extern int listen_sock (const char *addr, uint16_t port, sblist* listen_fds);
|
||||
extern int socket_nonblocking (int sock);
|
||||
extern int socket_blocking (int sock);
|
||||
|
||||
extern void set_socket_timeout(int fd);
|
||||
|
||||
extern int getsock_ip (int fd, char *ipaddr);
|
||||
extern void getpeer_information (union sockaddr_union *addr, char *ipaddr, size_t ipaddr_len);
|
||||
|
||||
|
12
src/stats.c
12
src/stats.c
@ -87,9 +87,9 @@ err_minus_one:
|
||||
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\" "
|
||||
"\"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
|
||||
"<html>\n"
|
||||
"<head><title>%s run-time statistics</title></head>\n"
|
||||
"<head><title>%s version %s run-time statistics</title></head>\n"
|
||||
"<body>\n"
|
||||
"<h1>%s run-time statistics</h1>\n"
|
||||
"<h1>%s version %s run-time statistics</h1>\n"
|
||||
"<p>\n"
|
||||
"Number of open connections: %lu<br />\n"
|
||||
"Number of requests: %lu<br />\n"
|
||||
@ -98,13 +98,13 @@ err_minus_one:
|
||||
"Number of refused connections due to high load: %lu\n"
|
||||
"</p>\n"
|
||||
"<hr />\n"
|
||||
"<p><em>Generated by %s.</em></p>\n" "</body>\n"
|
||||
"<p><em>Generated by %s version %s.</em></p>\n" "</body>\n"
|
||||
"</html>\n",
|
||||
PACKAGE, PACKAGE,
|
||||
PACKAGE, VERSION, PACKAGE, VERSION,
|
||||
stats->num_open,
|
||||
stats->num_reqs,
|
||||
stats->num_badcons, stats->num_denied,
|
||||
stats->num_refused, PACKAGE);
|
||||
stats->num_refused, PACKAGE, VERSION);
|
||||
|
||||
if (send_http_message (connptr, 200, "OK",
|
||||
message_buffer) < 0) {
|
||||
@ -122,7 +122,7 @@ err_minus_one:
|
||||
add_error_variable (connptr, "deniedconns", denied);
|
||||
add_error_variable (connptr, "refusedconns", refused);
|
||||
add_standard_vars (connptr);
|
||||
send_http_headers (connptr, 200, "Statistic requested", "");
|
||||
send_http_headers (connptr, 200, "Statistic requested");
|
||||
send_html_file (statfile, connptr);
|
||||
fclose (statfile);
|
||||
pthread_mutex_unlock(&stats_file_lock);
|
||||
|
@ -60,10 +60,11 @@ const char* upstream_build_error_string(enum upstream_build_error ube) {
|
||||
/**
|
||||
* Construct an upstream struct from input data.
|
||||
*/
|
||||
static struct upstream *upstream_build (const char *host, int port, char *domain,
|
||||
static struct upstream *upstream_build (const char *host, int port, const char *domain,
|
||||
const char *user, const char *pass,
|
||||
proxy_type type, enum upstream_build_error *ube)
|
||||
{
|
||||
char *ptr;
|
||||
struct upstream *up;
|
||||
|
||||
*ube = UBE_SUCCESS;
|
||||
@ -74,8 +75,8 @@ static struct upstream *upstream_build (const char *host, int port, char *domain
|
||||
}
|
||||
|
||||
up->type = type;
|
||||
up->target.type = HST_NONE;
|
||||
up->host = up->ua.user = up->pass = NULL;
|
||||
up->host = up->domain = up->ua.user = up->pass = NULL;
|
||||
up->ip = up->mask = 0;
|
||||
if (user) {
|
||||
if (type == PT_HTTP) {
|
||||
char b[BASE64ENC_BYTES((256+2)-1) + 1];
|
||||
@ -120,10 +121,30 @@ static struct upstream *upstream_build (const char *host, int port, char *domain
|
||||
up->port = port;
|
||||
}
|
||||
|
||||
if (hostspec_parse(domain, &up->target)
|
||||
|| up->target.type == HST_NONE) {
|
||||
*ube = UBE_NETMASK;
|
||||
goto fail;
|
||||
ptr = strchr (domain, '/');
|
||||
if (ptr) {
|
||||
struct in_addr addrstruct;
|
||||
|
||||
*ptr = '\0';
|
||||
if (inet_aton (domain, &addrstruct) != 0) {
|
||||
up->ip = ntohl (addrstruct.s_addr);
|
||||
*ptr++ = '/';
|
||||
|
||||
if (strchr (ptr, '.')) {
|
||||
if (inet_aton (ptr, &addrstruct) != 0)
|
||||
up->mask =
|
||||
ntohl (addrstruct.s_addr);
|
||||
} else {
|
||||
up->mask =
|
||||
~((1 << (32 - atoi (ptr))) - 1);
|
||||
}
|
||||
up->ip = up->ip & up->mask;
|
||||
} else {
|
||||
*ube = UBE_NETMASK;
|
||||
goto fail;
|
||||
}
|
||||
} else {
|
||||
up->domain = safestrdup (domain);
|
||||
}
|
||||
|
||||
if (type == PT_NONE)
|
||||
@ -139,8 +160,7 @@ fail:
|
||||
safefree (up->ua.user);
|
||||
safefree (up->pass);
|
||||
safefree (up->host);
|
||||
if(up->target.type == HST_STRING)
|
||||
safefree (up->target.address.string);
|
||||
safefree (up->domain);
|
||||
safefree (up);
|
||||
|
||||
return NULL;
|
||||
@ -150,7 +170,7 @@ fail:
|
||||
* Add an entry to the upstream list
|
||||
*/
|
||||
enum upstream_build_error upstream_add (
|
||||
const char *host, int port, char *domain,
|
||||
const char *host, int port, const char *domain,
|
||||
const char *user, const char *pass,
|
||||
proxy_type type, struct upstream **upstream_list)
|
||||
{
|
||||
@ -162,11 +182,11 @@ enum upstream_build_error upstream_add (
|
||||
return ube;
|
||||
}
|
||||
|
||||
if (up->target.type == HST_NONE) { /* always add default to end */
|
||||
if (!up->domain && !up->ip) { /* always add default to end */
|
||||
struct upstream *tmp = *upstream_list;
|
||||
|
||||
while (tmp) {
|
||||
if (tmp->target.type == HST_NONE) {
|
||||
if (!tmp->domain && !tmp->ip) {
|
||||
log_message (LOG_WARNING,
|
||||
"Duplicate default upstream");
|
||||
goto upstream_cleanup;
|
||||
@ -189,8 +209,7 @@ enum upstream_build_error upstream_add (
|
||||
|
||||
upstream_cleanup:
|
||||
safefree (up->host);
|
||||
if(up->target.type == HST_STRING)
|
||||
safefree (up->target.address.string);
|
||||
safefree (up->domain);
|
||||
safefree (up);
|
||||
|
||||
return ube;
|
||||
@ -201,12 +220,34 @@ upstream_cleanup:
|
||||
*/
|
||||
struct upstream *upstream_get (char *host, struct upstream *up)
|
||||
{
|
||||
while (up) {
|
||||
if (up->target.type == HST_NONE)
|
||||
break;
|
||||
in_addr_t my_ip = INADDR_NONE;
|
||||
|
||||
if (hostspec_match(host, &up->target))
|
||||
break;
|
||||
while (up) {
|
||||
if (up->domain) {
|
||||
if (strcasecmp (host, up->domain) == 0)
|
||||
break; /* exact match */
|
||||
|
||||
if (up->domain[0] == '.') {
|
||||
char *dot = strchr (host, '.');
|
||||
|
||||
if (!dot && !up->domain[1])
|
||||
break; /* local host matches "." */
|
||||
|
||||
while (dot && strcasecmp (dot, up->domain))
|
||||
dot = strchr (dot + 1, '.');
|
||||
|
||||
if (dot)
|
||||
break; /* subdomain match */
|
||||
}
|
||||
} else if (up->ip) {
|
||||
if (my_ip == INADDR_NONE)
|
||||
my_ip = ntohl (inet_addr (host));
|
||||
|
||||
if ((my_ip & up->mask) == up->ip)
|
||||
break;
|
||||
} else {
|
||||
break; /* No domain or IP, default upstream */
|
||||
}
|
||||
|
||||
up = up->next;
|
||||
}
|
||||
@ -228,8 +269,7 @@ void free_upstream_list (struct upstream *up)
|
||||
while (up) {
|
||||
struct upstream *tmp = up;
|
||||
up = up->next;
|
||||
if(tmp->target.type == HST_STRING)
|
||||
safefree (tmp->target.address.string);
|
||||
safefree (tmp->domain);
|
||||
safefree (tmp->host);
|
||||
safefree (tmp);
|
||||
}
|
||||
|
@ -26,7 +26,6 @@
|
||||
#define _TINYPROXY_UPSTREAM_H_
|
||||
|
||||
#include "common.h"
|
||||
#include "hostspec.h"
|
||||
|
||||
enum upstream_build_error {
|
||||
UBE_SUCCESS = 0,
|
||||
@ -51,6 +50,7 @@ typedef enum proxy_type {
|
||||
|
||||
struct upstream {
|
||||
struct upstream *next;
|
||||
char *domain; /* optional */
|
||||
char *host;
|
||||
union {
|
||||
char *user;
|
||||
@ -58,14 +58,14 @@ struct upstream {
|
||||
} ua;
|
||||
char *pass;
|
||||
int port;
|
||||
struct hostspec target;
|
||||
in_addr_t ip, mask;
|
||||
proxy_type type;
|
||||
};
|
||||
|
||||
#ifdef UPSTREAM_SUPPORT
|
||||
const char *proxy_type_name(proxy_type type);
|
||||
extern enum upstream_build_error upstream_add (
|
||||
const char *host, int port, char *domain,
|
||||
const char *host, int port, const char *domain,
|
||||
const char *user, const char *pass,
|
||||
proxy_type type, struct upstream **upstream_list);
|
||||
extern struct upstream *upstream_get (char *host, struct upstream *up);
|
||||
|
@ -39,7 +39,7 @@ send_http_message (struct conn_s *connptr, int http_code,
|
||||
const char *error_title, const char *message)
|
||||
{
|
||||
static const char *headers[] = {
|
||||
"Server: " PACKAGE,
|
||||
"Server: " PACKAGE "/" VERSION,
|
||||
"Content-type: text/html",
|
||||
"Connection: close"
|
||||
};
|
||||
|
@ -18,7 +18,7 @@
|
||||
# this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
SCRIPTS_DIR=$(cd $(dirname $0) && pwd)
|
||||
SCRIPTS_DIR=$(pwd)/$(dirname $0)
|
||||
BASEDIR=$SCRIPTS_DIR/../..
|
||||
TESTS_DIR=$SCRIPTS_DIR/..
|
||||
TESTENV_DIR=$TESTS_DIR/env
|
||||
@ -83,7 +83,6 @@ DefaultErrorFile "$TINYPROXY_DATA_DIR/debug.html"
|
||||
ErrorFile 400 "$TINYPROXY_DATA_DIR/debug.html"
|
||||
ErrorFile 403 "$TINYPROXY_DATA_DIR/debug.html"
|
||||
ErrorFile 501 "$TINYPROXY_DATA_DIR/debug.html"
|
||||
ErrorFile 502 "$TINYPROXY_DATA_DIR/debug.html"
|
||||
StatFile "$TINYPROXY_DATA_DIR/stats.html"
|
||||
Logfile "$TINYPROXY_LOG_FILE"
|
||||
PidFile "$TINYPROXY_PID_FILE"
|
||||
@ -100,7 +99,6 @@ XTinyproxy Yes
|
||||
AddHeader "X-My-Header1" "Powered by Tinyproxy"
|
||||
AddHeader "X-My-Header2" "Powered by Tinyproxy"
|
||||
AddHeader "X-My-Header3" "Powered by Tinyproxy"
|
||||
Upstream http 255.255.255.255:65535 ".invalid"
|
||||
EOF
|
||||
|
||||
cat << 'EOF' > $TINYPROXY_FILTER_FILE
|
||||
@ -246,10 +244,6 @@ test "x$?" = "x0" || FAILED=$((FAILED + 1))
|
||||
echo -n "requesting connect method to denied port..."
|
||||
run_failure_webclient_request 403 --method=CONNECT "$TINYPROXY_IP:$TINYPROXY_PORT" "localhost:12345"
|
||||
test "x$?" = "x0" || FAILED=$((FAILED + 1))
|
||||
|
||||
echo -n "testing unavailable backend..."
|
||||
run_failure_webclient_request 502 "$TINYPROXY_IP:$TINYPROXY_PORT" "http://bogus.invalid"
|
||||
test "x$?" = "x0" || FAILED=$((FAILED + 1))
|
||||
}
|
||||
|
||||
basic_test
|
||||
|
@ -26,8 +26,9 @@ use Pod::Usage;
|
||||
|
||||
my $EOL = "\015\012";
|
||||
|
||||
my $VERSION = "0.1";
|
||||
my $NAME = "Tinyproxy-Web-Client";
|
||||
my $user_agent = "$NAME";
|
||||
my $user_agent = "$NAME/$VERSION";
|
||||
my $user_agent_header = "User-Agent: $user_agent$EOL";
|
||||
my $http_version = "1.0";
|
||||
my $method = "GET";
|
||||
|
@ -31,8 +31,9 @@ use Getopt::Long;
|
||||
use Pod::Usage;
|
||||
use Fcntl ':flock'; # import LOCK_* constants
|
||||
|
||||
my $VERSION = "0.1";
|
||||
my $NAME = "Tinyproxy-Test-Web-Server";
|
||||
my $server_header = "Server: $NAME";
|
||||
my $server_header = "Server: $NAME/$VERSION";
|
||||
|
||||
my $EOL = "\015\012";
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user