tinyproxy/src/conf.c

1142 lines
32 KiB
C
Raw Normal View History

/* tinyproxy - A fast light-weight HTTP proxy
* Copyright (C) 2004 Robert James Kaes <rjkaes@users.sourceforge.net>
* Copyright (C) 2009 Michael Adam <obnox@samba.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* Parses the configuration file and sets up the config_s structure for
* use by the application. This file replaces the old grammar.y and
* scanner.l files. It takes up less space and _I_ think is easier to
* add new directives to. Who knows if I'm right though.
*/
2020-09-12 17:27:41 -07:00
#include "common.h"
#include <regex.h>
2009-09-20 21:11:59 -07:00
#include "conf.h"
#include "acl.h"
#include "anonymous.h"
#include "filter.h"
#include "heap.h"
#include "html-error.h"
#include "log.h"
#include "reqs.h"
#include "reverse-proxy.h"
#include "upstream.h"
#include "connect-ports.h"
#include "basicauth.h"
#include "conf-tokens.h"
#ifdef LINE_MAX
#define TP_LINE_MAX LINE_MAX
#else
#define TP_LINE_MAX 1024
#endif
/*
* The configuration directives are defined in the structure below. Each
* directive requires a regular expression to match against, and a
* function to call when the regex is matched.
*
* Below are defined certain constant regular expression strings that
* can (and likely should) be used when building the regex for the
* given directive.
*/
#define DIGIT "[0-9]"
#define SPACE "[ \t]"
#define WS SPACE "+"
#define STR "\"([^\"]+)\""
#define BOOL "(yes|on|no|off)"
#define INT "(()" DIGIT "+)"
#define ALNUM "([-a-z0-9._]+)"
#define USERNAME "([^:]*)"
#define PASSWORD "([^@]*)"
#define IP "((([0-9]{1,3})\\.){3}[0-9]{1,3})"
#define IPMASK "(" IP "(/" DIGIT "+)?)"
2009-11-08 13:14:14 -08:00
#define IPV6 "(" \
"(([0-9a-f:]{2,39}))|" \
"(([0-9a-f:]{0,29}:" IP "))" \
2009-11-08 13:14:14 -08:00
")"
#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 24
#define CP_WARN(FMT, ...) \
log_message (LOG_WARNING, "line %lu: " FMT, lineno, __VA_ARGS__)
/*
* All configuration handling functions are REQUIRED to be defined
* with the same function template as below.
*/
2018-12-18 15:36:04 -08:00
typedef int (*CONFFILE_HANDLER) (struct config_s *, const char *,
unsigned long, regmatch_t[]);
/*
* Define the pattern used by any directive handling function. The
* following arguments are defined:
*
* struct config_s* conf pointer to the current configuration structure
* const char* line full line matched by the regular expression
* regmatch_t match[] offsets to the substrings matched
*
* The handling function must return 0 if the directive was processed
* properly. Any errors are reported by returning a non-zero value.
*/
2008-12-08 04:26:08 -08:00
#define HANDLE_FUNC(func) \
int func(struct config_s* conf, const char* line, \
2018-12-18 15:36:04 -08:00
unsigned long lineno, regmatch_t match[])
/*
* List all the handling functions. These are defined later, but they need
* to be in-scope before the big structure below.
*/
static HANDLE_FUNC (handle_disabled_feature)
{
fprintf (stderr, "ERROR: accessing feature that was disabled at compiletime on line %lu\n",
lineno);
return -1;
}
static HANDLE_FUNC (handle_allow);
static HANDLE_FUNC (handle_basicauth);
static HANDLE_FUNC (handle_anonymous);
static HANDLE_FUNC (handle_bind);
static HANDLE_FUNC (handle_bindsame);
static HANDLE_FUNC (handle_connectport);
static HANDLE_FUNC (handle_defaulterrorfile);
static HANDLE_FUNC (handle_deny);
static HANDLE_FUNC (handle_errorfile);
static HANDLE_FUNC (handle_addheader);
#ifdef FILTER_ENABLE
static HANDLE_FUNC (handle_filter);
static HANDLE_FUNC (handle_filtercasesensitive);
static HANDLE_FUNC (handle_filterdefaultdeny);
static HANDLE_FUNC (handle_filterextended);
static HANDLE_FUNC (handle_filterurls);
static HANDLE_FUNC (handle_filtertype);
#endif
static HANDLE_FUNC (handle_group);
static HANDLE_FUNC (handle_listen);
static HANDLE_FUNC (handle_logfile);
static HANDLE_FUNC (handle_loglevel);
static HANDLE_FUNC (handle_maxclients);
static HANDLE_FUNC (handle_obsolete);
static HANDLE_FUNC (handle_pidfile);
static HANDLE_FUNC (handle_port);
#ifdef REVERSE_SUPPORT
static HANDLE_FUNC (handle_reversebaseurl);
static HANDLE_FUNC (handle_reversemagic);
static HANDLE_FUNC (handle_reverseonly);
static HANDLE_FUNC (handle_reversepath);
#endif
static HANDLE_FUNC (handle_statfile);
static HANDLE_FUNC (handle_stathost);
static HANDLE_FUNC (handle_syslog);
static HANDLE_FUNC (handle_timeout);
static HANDLE_FUNC (handle_user);
static HANDLE_FUNC (handle_viaproxyname);
static HANDLE_FUNC (handle_disableviaheader);
static HANDLE_FUNC (handle_xtinyproxy);
#ifdef UPSTREAM_SUPPORT
static HANDLE_FUNC (handle_upstream);
#endif
static void config_free_regex (void);
/*
* This macro can be used to make standard directives in the form:
* directive arguments [arguments ...]
*
* The directive itself will be the first matched substring.
*
* Note that this macro is not required. As you can see below, the
* comment and blank line elements are defined explicitly since they
* do not follow the pattern above. This macro is for convenience
* only.
*/
#define STDCONF(d, re, func) [CD_ ## d] = { BEGIN "()" WS re END, func, NULL }
/*
* Holds the regular expression used to match the configuration directive,
* the function pointer to the routine to handle the directive, and
* for internal use, a pointer to the compiled regex so it only needs
* to be compiled one.
*/
struct {
const char *re;
CONFFILE_HANDLER handler;
regex_t *cre;
} directives[] = {
/* string arguments */
STDCONF (logfile, STR, handle_logfile),
STDCONF (pidfile, STR, handle_pidfile),
STDCONF (anonymous, STR, handle_anonymous),
STDCONF (viaproxyname, STR, handle_viaproxyname),
STDCONF (defaulterrorfile, STR, handle_defaulterrorfile),
STDCONF (statfile, STR, handle_statfile),
STDCONF (stathost, STR, handle_stathost),
STDCONF (xtinyproxy, BOOL, handle_xtinyproxy),
/* boolean arguments */
STDCONF (syslog, BOOL, handle_syslog),
STDCONF (bindsame, BOOL, handle_bindsame),
STDCONF (disableviaheader, BOOL, handle_disableviaheader),
/* integer arguments */
STDCONF (port, INT, handle_port),
STDCONF (maxclients, INT, handle_maxclients),
STDCONF (maxspareservers, INT, handle_obsolete),
STDCONF (minspareservers, INT, handle_obsolete),
STDCONF (startservers, INT, handle_obsolete),
STDCONF (maxrequestsperchild, INT, handle_obsolete),
STDCONF (timeout, INT, handle_timeout),
STDCONF (connectport, INT, handle_connectport),
/* alphanumeric arguments */
STDCONF (user, ALNUM, handle_user),
STDCONF (group, ALNUM, handle_group),
/* ip arguments */
STDCONF (listen, "(" IP "|" IPV6 ")", handle_listen),
STDCONF (allow, "(" "(" IPMASK "|" IPV6MASK ")" "|" ALNUM ")",
2009-11-08 13:14:14 -08:00
handle_allow),
STDCONF (deny, "(" "(" IPMASK "|" IPV6MASK ")" "|" ALNUM ")",
2009-11-08 13:14:14 -08:00
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),
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 "|" ALNUM ")"
":" INT "(" WS STR ")?" ")", handle_upstream),
#endif
/* loglevel */
STDCONF (loglevel, "(critical|error|warning|notice|connect|info)",
handle_loglevel)
};
const unsigned int ndirectives = sizeof (directives) / sizeof (directives[0]);
static void
free_added_headers (sblist* add_headers)
{
size_t i;
if (!add_headers) return;
for (i = 0; i < sblist_getsize (add_headers); i++) {
http_header_t *header = sblist_get (add_headers, i);
safefree (header->name);
safefree (header->value);
}
sblist_free (add_headers);
}
2020-09-15 18:07:52 -07:00
static void stringlist_free(sblist *sl) {
size_t i;
char **s;
if(sl) {
for(i = 0; i < sblist_getsize(sl); i++) {
s = sblist_get(sl, i);
if(s) safefree(*s);
}
sblist_free(sl);
}
}
void free_config (struct config_s *conf)
{
2020-09-15 18:07:52 -07:00
char *k;
htab_value *v;
size_t it;
safefree (conf->logf_name);
safefree (conf->stathost);
safefree (conf->user);
safefree (conf->group);
2020-09-15 18:07:52 -07:00
stringlist_free(conf->basicauth_list);
stringlist_free(conf->listen_addrs);
stringlist_free(conf->bind_addrs);
#ifdef FILTER_ENABLE
safefree (conf->filter);
#endif /* FILTER_ENABLE */
#ifdef REVERSE_SUPPORT
free_reversepath_list(conf->reversepath_list);
safefree (conf->reversebaseurl);
#endif
#ifdef UPSTREAM_SUPPORT
free_upstream_list (conf->upstream_list);
#endif /* UPSTREAM_SUPPORT */
safefree (conf->pidpath);
safefree (conf->via_proxy_name);
if (conf->errorpages) {
it = 0;
while((it = htab_next(conf->errorpages, it, &k, &v))) {
safefree(k);
safefree(v->p);
}
htab_destroy (conf->errorpages);
}
free_added_headers (conf->add_headers);
safefree (conf->errorpage_undef);
safefree (conf->statpage);
flush_access_list (conf->access_list);
free_connect_ports_list (conf->connect_ports);
if (conf->anonymous_map) {
it = 0;
while((it = htab_next(conf->anonymous_map, it, &k, &v)))
safefree(k);
htab_destroy (conf->anonymous_map);
}
memset (conf, 0, sizeof(*conf));
}
/*
* Initializes Config parser. Currently this means:
* Compiles the regular expressions used by the configuration file. This
* routine MUST be called before trying to parse the configuration file.
*
* Returns 0 on success; negative upon failure.
*/
int
config_init (void)
{
unsigned int i, r;
for (i = 0; i != ndirectives; ++i) {
assert (!directives[i].cre);
if (!directives[i].handler) {
directives[i].handler = handle_disabled_feature;
continue;
}
directives[i].cre = (regex_t *) safemalloc (sizeof (regex_t));
if (!directives[i].cre)
return -1;
r = regcomp (directives[i].cre,
directives[i].re,
REG_EXTENDED | REG_ICASE | REG_NEWLINE);
if (r)
return r;
}
atexit (config_free_regex);
return 0;
}
/*
* Frees pre-compiled regular expressions used by the configuration
* file. This function is registered to be automatically called at exit.
*/
static void
config_free_regex (void)
{
unsigned int i;
for (i = 0; i < ndirectives; i++) {
if (directives[i].cre) {
regfree (directives[i].cre);
safefree (directives[i].cre);
directives[i].cre = NULL;
}
}
}
/*
* Attempt to match the supplied line with any of the configuration
* regexes defined above. If a match is found, call the handler
* function to process the directive.
*
* Returns 0 if a match was found and successfully processed; otherwise,
* a negative number is returned.
*/
2018-12-18 15:36:04 -08:00
static int check_match (struct config_s *conf, const char *line,
unsigned long lineno, enum config_directive cd)
{
regmatch_t match[RE_MAX_MATCHES];
unsigned int i = cd;
if (!directives[i].cre)
return (*directives[i].handler) (conf, line, lineno, match);
if (!regexec
(directives[i].cre, line, RE_MAX_MATCHES, match, 0))
return (*directives[i].handler) (conf, line, lineno, match);
return -1;
}
/*
* Parse the previously opened configuration stream.
*/
static int config_parse (struct config_s *conf, FILE * f)
{
char buffer[TP_LINE_MAX], *p, *q, c;
const struct config_directive_entry *e;
unsigned long lineno = 1;
for (;fgets (buffer, sizeof (buffer), f);++lineno) {
if(buffer[0] == '#') continue;
p = buffer;
while(isspace(*p))p++;
if(!*p) continue;
q = p;
while(!isspace(*q))q++;
c = *q;
*q = 0;
e = config_directive_find(p, strlen(p));
*q = c;
if (!e || e->value == CD_NIL || check_match (conf, q, lineno, e->value)) {
fprintf (stderr, "ERROR: Syntax error on line %lu\n", lineno);
return 1;
}
2008-12-08 05:39:44 -08:00
}
return 0;
}
/**
* Read the settings from a config file.
*/
static int load_config_file (const char *config_fname, struct config_s *conf)
{
FILE *config_file;
int ret = -1;
config_file = fopen (config_fname, "r");
if (!config_file) {
fprintf (stderr,
"%s: Could not open config file \"%s\".\n",
PACKAGE, config_fname);
goto done;
}
if (config_parse (conf, config_file)) {
fprintf (stderr, "Unable to parse config file. "
"Not starting.\n");
goto done;
}
ret = 0;
done:
if (config_file)
fclose (config_file);
return ret;
}
static void initialize_config_defaults (struct config_s *conf)
{
memset (conf, 0, sizeof(*conf));
/*
* Make sure the HTML error pages array is NULL to begin with.
* (FIXME: Should have a better API for all this)
*/
conf->errorpages = NULL;
conf->stathost = safestrdup (TINYPROXY_STATHOST);
conf->idletimeout = MAX_IDLE_TIME;
conf->logf_name = NULL;
conf->pidpath = NULL;
conf->maxclients = 100;
}
/**
* Load the configuration.
*/
int reload_config_file (const char *config_fname, struct config_s *conf)
{
int ret;
initialize_config_defaults (conf);
ret = load_config_file (config_fname, conf);
if (ret != 0) {
goto done;
}
/* Set the default values if they were not set in the config file. */
if (conf->port == 0) {
2009-12-21 14:56:39 -08:00
/*
* Don't log here in error path:
* logging might not be set up yet!
*/
fprintf (stderr, PACKAGE ": You MUST set a Port in the "
"config file.\n");
ret = -1;
goto done;
}
if (!conf->user && !geteuid()) {
log_message (LOG_WARNING, "You SHOULD set a UserName in the "
"config file. Using current user instead.");
}
if (conf->idletimeout == 0) {
log_message (LOG_WARNING, "Invalid idle time setting. "
"Only values greater than zero are allowed. "
"Therefore setting idle timeout to %u seconds.",
MAX_IDLE_TIME);
conf->idletimeout = MAX_IDLE_TIME;
}
done:
return ret;
}
/***********************************************************************
*
* The following are basic data extraction building blocks that can
* be used to simplify the parsing of a directive.
*
***********************************************************************/
static char *get_string_arg (const char *line, regmatch_t * match)
{
char *p;
const unsigned int len = match->rm_eo - match->rm_so;
assert (line);
assert (len > 0);
p = (char *) safemalloc (len + 1);
if (!p)
return NULL;
memcpy (p, line + match->rm_so, len);
p[len] = '\0';
return p;
}
static int set_string_arg (char **var, const char *line, regmatch_t * match)
{
char *arg = get_string_arg (line, match);
if (!arg)
return -1;
2009-11-16 12:50:27 -08:00
if (*var != NULL) {
safefree (*var);
}
2009-11-16 12:50:27 -08:00
*var = arg;
return 0;
}
static int get_bool_arg (const char *line, regmatch_t * match)
{
const char *p = line + match->rm_so;
assert (line);
assert (match && match->rm_so != -1);
/* "y"es or o"n" map as true, otherwise it's false. */
if (tolower (p[0]) == 'y' || tolower (p[1]) == 'n')
return 1;
else
return 0;
}
static int
set_bool_arg (unsigned int *var, const char *line, regmatch_t * match)
{
assert (var);
assert (line);
assert (match && match->rm_so != -1);
*var = get_bool_arg (line, match);
return 0;
}
static unsigned long
get_long_arg (const char *line, regmatch_t * match)
{
assert (line);
assert (match && match->rm_so != -1);
return strtoul (line + match->rm_so, NULL, 0);
}
static int
set_int_arg (unsigned int *var, const char *line, regmatch_t * match)
{
assert (var);
assert (line);
assert (match);
*var = (unsigned int) get_long_arg (line, match);
return 0;
}
/***********************************************************************
*
* Below are all the directive handling functions. You will notice
* that most of the directives delegate to one of the basic data
* extraction routines. This is deliberate. To add a new directive
* to tinyproxy only requires you to define the regular expression
* above and then figure out what data extract routine to use.
*
* However, you will also notice that more complicated directives are
* possible. You can make your directive as complicated as you require
* to express a solution to the problem you're tackling.
*
* See the definition/comment about the HANDLE_FUNC() macro to learn
* what arguments are supplied to the handler, and to determine what
* values to return.
*
***********************************************************************/
static HANDLE_FUNC (handle_logfile)
{
return set_string_arg (&conf->logf_name, line, &match[2]);
}
static HANDLE_FUNC (handle_pidfile)
{
return set_string_arg (&conf->pidpath, line, &match[2]);
}
static HANDLE_FUNC (handle_anonymous)
{
char *arg = get_string_arg (line, &match[2]);
if (!arg)
return -1;
if(anonymous_insert (conf, arg) < 0) {
CP_WARN ("anonymous_insert() failed: '%s'", arg);
safefree(arg);
return -1;
}
return 0;
}
static HANDLE_FUNC (handle_viaproxyname)
{
int r = set_string_arg (&conf->via_proxy_name, line, &match[2]);
if (r)
return r;
log_message (LOG_INFO,
"Setting \"Via\" header to '%s'",
conf->via_proxy_name);
return 0;
}
static HANDLE_FUNC (handle_disableviaheader)
{
int r = set_bool_arg (&conf->disable_viaheader, line, &match[2]);
if (r) {
return r;
}
log_message (LOG_INFO,
"Disabling transmission of the \"Via\" header.");
return 0;
}
static HANDLE_FUNC (handle_defaulterrorfile)
{
return set_string_arg (&conf->errorpage_undef, line, &match[2]);
}
static HANDLE_FUNC (handle_statfile)
{
return set_string_arg (&conf->statpage, line, &match[2]);
}
static HANDLE_FUNC (handle_stathost)
{
int r = set_string_arg (&conf->stathost, line, &match[2]);
if (r)
return r;
log_message (LOG_INFO, "Stathost set to \"%s\"", conf->stathost);
return 0;
}
static HANDLE_FUNC (handle_xtinyproxy)
{
#ifdef XTINYPROXY_ENABLE
return set_bool_arg (&conf->add_xtinyproxy, line, &match[2]);
#else
if(!get_bool_arg(line, &match[2]))
return 0;
fprintf (stderr,
"XTinyproxy NOT Enabled! Recompile with --enable-xtinyproxy\n");
return 1;
#endif
}
static HANDLE_FUNC (handle_syslog)
{
return set_bool_arg (&conf->syslog, line, &match[2]);
}
static HANDLE_FUNC (handle_bindsame)
{
int r = set_bool_arg (&conf->bindsame, line, &match[2]);
if (r)
return r;
log_message (LOG_INFO, "Binding outgoing connection to incoming IP");
return 0;
}
static HANDLE_FUNC (handle_port)
{
set_int_arg (&conf->port, line, &match[2]);
if (conf->port > 65535) {
fprintf (stderr, "Bad port number (%d) supplied for Port.\n",
conf->port);
return 1;
}
return 0;
}
static HANDLE_FUNC (handle_maxclients)
{
simplify codebase by using one thread/conn, instead of preforked procs the existing codebase used an elaborate and complex approach for its parallelism: 5 different config file options, namely - MaxClients - MinSpareServers - MaxSpareServers - StartServers - MaxRequestsPerChild were used to steer how (and how many) parallel processes tinyproxy would spin up at start, how many processes at each point needed to be idle, etc. it seems all preforked processes would listen on the server port and compete with each other about who would get assigned the new incoming connections. since some data needs to be shared across those processes, a half- baked "shared memory" implementation was provided for this purpose. that implementation used to use files in the filesystem, and since it had a big FIXME comment, the author was well aware of how hackish that approach was. this entire complexity is now removed. the main thread enters a loop which polls on the listening fds, then spins up a new thread per connection, until the maximum number of connections (MaxClients) is hit. this is the only of the 5 config options left after this cleanup. since threads share the same address space, the code necessary for shared memory access has been removed. this means that the other 4 mentioned config option will now produce a parse error, when encountered. currently each thread uses a hardcoded default of 256KB per thread for the thread stack size, which is quite lavish and should be sufficient for even the worst C libraries, but people may want to tweak this value to the bare minimum, thus we may provide a new config option for this purpose in the future. i suspect that on heavily optimized C libraries such a musl, a stack size of 8-16 KB per thread could be sufficient. since the existing list implementation in vector.c did not provide a way to remove a single item from an existing list, i added my own list implementation from my libulz library which offers this functionality, rather than trying to add an ad-hoc, and perhaps buggy implementation to the vector_t list code. the sblist code is contained in an 80 line C file and as simple as it can get, while offering good performance and is proven bugfree due to years of use in other projects.
2018-12-16 16:23:09 -08:00
set_int_arg (&conf->maxclients, line, &match[2]);
return 0;
}
static HANDLE_FUNC (handle_obsolete)
{
fprintf (stderr, "WARNING: obsolete config item on line %lu\n",
lineno);
return 0;
}
static HANDLE_FUNC (handle_timeout)
{
return set_int_arg (&conf->idletimeout, line, &match[2]);
}
static HANDLE_FUNC (handle_connectport)
{
add_connect_port_allowed (get_long_arg (line, &match[2]),
&conf->connect_ports);
return 0;
}
static HANDLE_FUNC (handle_user)
{
return set_string_arg (&conf->user, line, &match[2]);
}
static HANDLE_FUNC (handle_group)
{
return set_string_arg (&conf->group, line, &match[2]);
}
static void warn_invalid_address(char *arg, unsigned long lineno) {
CP_WARN ("Invalid address %s", arg);
}
static HANDLE_FUNC (handle_allow)
{
char *arg = get_string_arg (line, &match[2]);
if(insert_acl (arg, ACL_ALLOW, &conf->access_list) < 0)
warn_invalid_address (arg, lineno);
safefree (arg);
return 0;
}
static HANDLE_FUNC (handle_deny)
{
char *arg = get_string_arg (line, &match[2]);
if(insert_acl (arg, ACL_DENY, &conf->access_list) < 0)
warn_invalid_address (arg, lineno);
safefree (arg);
return 0;
}
static HANDLE_FUNC (handle_bind)
{
char *arg = get_string_arg (line, &match[2]);
if (arg == NULL) {
return -1;
}
if (conf->bind_addrs == NULL) {
conf->bind_addrs = sblist_new(sizeof(char*), 16);
if (conf->bind_addrs == NULL) {
CP_WARN ("Could not create a list "
"of bind addresses.", "");
safefree(arg);
return -1;
}
}
sblist_add (conf->bind_addrs, &arg);
log_message (LOG_INFO,
"Added bind address [%s] for outgoing connections.", arg);
return 0;
}
static HANDLE_FUNC (handle_listen)
{
char *arg = get_string_arg (line, &match[2]);
if (arg == NULL) {
return -1;
}
if (conf->listen_addrs == NULL) {
2020-09-15 18:07:52 -07:00
conf->listen_addrs = sblist_new(sizeof(char*), 16);
if (conf->listen_addrs == NULL) {
CP_WARN ("Could not create a list "
"of listen addresses.", "");
safefree(arg);
return -1;
}
}
2020-09-15 18:07:52 -07:00
sblist_add (conf->listen_addrs, &arg);
log_message(LOG_INFO, "Added address [%s] to listen addresses.", arg);
return 0;
}
static HANDLE_FUNC (handle_errorfile)
{
/*
* Because an integer is defined as ((0x)?[[:digit:]]+) _two_
* match places are used. match[2] matches the full digit
* string, while match[3] matches only the "0x" part if
* present. This is why the "string" is located at
* match[4] (rather than the more intuitive match[3].
*/
unsigned long int err = get_long_arg (line, &match[2]);
char *page = get_string_arg (line, &match[4]);
if(add_new_errorpage (conf, page, err) < 0) {
CP_WARN ("add_new_errorpage() failed: '%s'", page);
safefree (page);
}
return 0;
}
static HANDLE_FUNC (handle_addheader)
{
char *name = get_string_arg (line, &match[2]);
char *value = get_string_arg (line, &match[3]);
http_header_t header;
if (!conf->add_headers) {
conf->add_headers = sblist_new (sizeof(http_header_t), 16);
}
header.name = name;
header.value = value;
sblist_add (conf->add_headers, &header);
/* Don't free name or value here, as they are referenced in the
* struct inserted into the vector. */
return 0;
}
/*
* Log level's strings.
*/
struct log_levels_s {
const char *string;
int level;
};
static struct log_levels_s log_levels[] = {
{"critical", LOG_CRIT},
{"error", LOG_ERR},
{"warning", LOG_WARNING},
{"notice", LOG_NOTICE},
{"connect", LOG_CONN},
{"info", LOG_INFO}
};
static HANDLE_FUNC (handle_loglevel)
{
static const unsigned int nlevels =
sizeof (log_levels) / sizeof (log_levels[0]);
unsigned int i;
char *arg = get_string_arg (line, &match[2]);
for (i = 0; i != nlevels; ++i) {
if (!strcasecmp (arg, log_levels[i].string)) {
set_log_level (log_levels[i].level);
safefree (arg);
return 0;
}
2008-12-08 05:39:44 -08:00
}
safefree (arg);
return -1;
}
static HANDLE_FUNC (handle_basicauth)
{
char *user, *pass;
user = get_string_arg(line, &match[2]);
if (!user)
return -1;
pass = get_string_arg(line, &match[3]);
if (!pass) {
safefree (user);
return -1;
}
if (!conf->basicauth_list) {
2020-09-15 17:54:05 -07:00
conf->basicauth_list = sblist_new (sizeof(char*), 16);
}
basicauth_add (conf->basicauth_list, user, pass);
safefree (user);
safefree (pass);
return 0;
}
#ifdef FILTER_ENABLE
static void warn_deprecated(const char *arg, unsigned long lineno) {
CP_WARN ("deprecated option %s", arg);
}
static HANDLE_FUNC (handle_filter)
{
return set_string_arg (&conf->filter, line, &match[2]);
}
static HANDLE_FUNC (handle_filterurls)
{
conf->filter_opts |=
get_bool_arg (line, &match[2]) * FILTER_OPT_URL;
return 0;
}
static HANDLE_FUNC (handle_filterextended)
{
warn_deprecated("FilterExtended, use FilterType", lineno);
conf->filter_opts |=
get_bool_arg (line, &match[2]) * FILTER_OPT_TYPE_ERE;
return 0;
}
static HANDLE_FUNC (handle_filterdefaultdeny)
{
assert (match[2].rm_so != -1);
conf->filter_opts |=
get_bool_arg (line, &match[2]) * FILTER_OPT_DEFAULT_DENY;
return 0;
}
static HANDLE_FUNC (handle_filtercasesensitive)
{
conf->filter_opts |=
get_bool_arg (line, &match[2]) * FILTER_OPT_CASESENSITIVE;
return 0;
}
static HANDLE_FUNC (handle_filtertype)
{
static const struct { unsigned short flag; char type[8]; }
ftmap[] = {
{FILTER_OPT_TYPE_ERE, "ere"},
{FILTER_OPT_TYPE_BRE, "bre"},
{FILTER_OPT_TYPE_FNMATCH, "fnmatch"},
};
char *type;
unsigned i;
type = get_string_arg(line, &match[2]);
if (!type) return -1;
for(i=0;i<sizeof(ftmap)/sizeof(ftmap[0]);++i)
if(!strcmp(ftmap[i].type, type))
conf->filter_opts |= ftmap[i].flag;
safefree (type);
return 0;
}
#endif
#ifdef REVERSE_SUPPORT
static HANDLE_FUNC (handle_reverseonly)
{
return set_bool_arg (&conf->reverseonly, line, &match[2]);
}
static HANDLE_FUNC (handle_reversemagic)
{
return set_bool_arg (&conf->reversemagic, line, &match[2]);
}
static HANDLE_FUNC (handle_reversebaseurl)
{
return set_string_arg (&conf->reversebaseurl, line, &match[2]);
}
static HANDLE_FUNC (handle_reversepath)
{
/*
* The second string argument is optional.
*/
char *arg1, *arg2;
arg1 = get_string_arg (line, &match[2]);
if (!arg1)
return -1;
if (match[4].rm_so != -1) {
arg2 = get_string_arg (line, &match[4]);
if (!arg2) {
safefree (arg1);
return -1;
}
reversepath_add (arg1, arg2, &conf->reversepath_list);
safefree (arg1);
safefree (arg2);
} else {
reversepath_add (NULL, arg1, &conf->reversepath_list);
safefree (arg1);
2008-12-08 05:39:44 -08:00
}
return 0;
}
#endif
#ifdef UPSTREAM_SUPPORT
static enum proxy_type pt_from_string(const char *s)
{
static const char pt_map[][7] = {
[PT_NONE] = "none",
[PT_HTTP] = "http",
[PT_SOCKS4] = "socks4",
[PT_SOCKS5] = "socks5",
};
unsigned i;
for (i = 0; i < sizeof(pt_map)/sizeof(pt_map[0]); i++)
if (!strcmp(pt_map[i], s))
return i;
return PT_NONE;
}
static HANDLE_FUNC (handle_upstream)
{
char *ip;
int port, mi;
char *domain = 0, *user = 0, *pass = 0, *tmp;
enum proxy_type pt;
enum upstream_build_error ube;
if (match[3].rm_so != -1) {
tmp = get_string_arg (line, &match[3]);
if(!strcmp(tmp, "none")) {
safefree(tmp);
if (match[4].rm_so == -1) return -1;
domain = get_string_arg (line, &match[4]);
if (!domain)
return -1;
ube = upstream_add (NULL, 0, domain, 0, 0, PT_NONE, &conf->upstream_list);
safefree (domain);
goto check_err;
}
}
mi = 6;
tmp = get_string_arg (line, &match[mi]);
pt = pt_from_string(tmp);
safefree(tmp);
mi += 2;
if (match[mi].rm_so != -1)
user = get_string_arg (line, &match[mi]);
mi++;
if (match[mi].rm_so != -1)
pass = get_string_arg (line, &match[mi]);
mi++;
ip = get_string_arg (line, &match[mi]);
if (!ip)
return -1;
mi += 5;
port = (int) get_long_arg (line, &match[mi]);
mi += 3;
if (match[mi].rm_so != -1)
domain = get_string_arg (line, &match[mi]);
ube = upstream_add (ip, port, domain, user, pass, pt, &conf->upstream_list);
safefree (user);
safefree (pass);
safefree (domain);
safefree (ip);
check_err:;
if(ube != UBE_SUCCESS)
CP_WARN("%s", upstream_build_error_string(ube));
return 0;
}
#endif