summaryrefslogtreecommitdiffhomepage
path: root/src/tinyproxy.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tinyproxy.c')
-rw-r--r--src/tinyproxy.c518
1 files changed, 181 insertions, 337 deletions
diff --git a/src/tinyproxy.c b/src/tinyproxy.c
index e41d95e..496739f 100644
--- a/src/tinyproxy.c
+++ b/src/tinyproxy.c
@@ -1,6 +1,6 @@
-/* $Id: tinyproxy.c,v 1.3 2000-03-31 20:08:19 rjkaes Exp $
+/* $Id: tinyproxy.c,v 1.4 2000-09-12 00:03:53 rjkaes Exp $
*
- * The initialize routine. Basically sets up all the initial stuff (logfile,
+ * The initialise routine. Basically sets up all the initial stuff (logfile,
* listening socket, config options, etc.) and then sits there and loops
* over the new connections until the daemon is closed. Also has additional
* functions to handle the "user friendly" aspects of a program (usage,
@@ -22,148 +22,55 @@
* General Public License for more details.
*/
-#ifdef HAVE_CONFIG_H
-#include <defines.h>
-#endif
+#include "tinyproxy.h"
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/socket.h>
+#include <grp.h>
+#include <pwd.h>
#include <signal.h>
-#include <stdlib.h>
#include <sysexits.h>
-#include <pwd.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <time.h>
-#include <sys/time.h>
#include <syslog.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-/* chris - need this for asynchronous DNS resolution */
-#include <adns.h>
-
-adns_state adns;
-#include "config.h"
-#include "tinyproxy.h"
-#include "utils.h"
-#include "log.h"
-#include "sock.h"
-#include "conns.h"
-#include "reqs.h"
+#include "anonymous.h"
#include "buffer.h"
#include "filter.h"
-#include "anonymous.h"
+#include "log.h"
+#include "reqs.h"
+#include "sock.h"
+#include "stats.h"
+#include "thread.h"
+#include "utils.h"
void takesig(int sig);
+extern int yyparse(void);
+extern FILE *yyin;
+
/*
* Global Structures
*/
-struct config_s config = {
- NULL, /* Log file handle */
- DEFAULT_LOG, /* Logfile name */
- FALSE, /* Use syslog instead? */
- DEFAULT_CUTOFFLOAD, /* Cut off load */
- DEFAULT_PORT, /* Listen on this port */
- DEFAULT_STATHOST, /* URL of stats host */
- FALSE, /* Quit? */
- DEFAULT_USER, /* Name of user to change to */
- FALSE, /* Run anonymous by default? */
- NULL, /* String containing the subnet allowed */
- NULL, /* IP address to listen on */
-#ifdef FILTER_ENABLE
- NULL, /* Location of filter file */
-#endif /* FILTER_ENABLE */
- FALSE, /* Restrict the log to only errors */
-#ifdef XTINYPROXY
- NULL, /* The name of this domain */
-#endif
-#ifdef UPSTREAM_PROXY
- NULL, /* name of the upstream proxy */
- 0, /* port of the upstream proxy */
-#endif
-};
-
-struct stat_s stats;
+struct config_s config;
float load = 0.00;
/*
- * Dump info to the logfile
- */
-static void dumpdebug(void)
-{
- struct conn_s *connptr = connections;
- long clients = 0, waiting = 0, relaying = 0, closing = 0, finished = 0;
-
- log("SIGUSR1 received, debug dump follows.");
-
- while (connptr) {
- switch (connptr->type) {
- case NEWCONN:
- clients++;
- break;
- case WAITCONN:
- waiting++;
- break;
- case RELAYCONN:
- relaying++;
- break;
- case CLOSINGCONN:
- closing++;
- break;
- case FINISHCONN:
- finished++;
- break;
- default:
- break;
- }
- connptr = connptr->next;
- }
- log("clients: %d, waiting: %d, relaying: %d," \
- "closing: %d, finished: %d",
- clients, waiting, relaying, closing, finished);
- log("total requests handled: %lu", stats.num_reqs);
- log("total connections handled: %lu", stats.num_cons);
- log("total sockets listened: %lu", stats.num_listens);
- log("total sockets opened: %lu", stats.num_opens);
- log("total bad opens: %lu", stats.num_badcons);
- log("total bytes tx: %lu", stats.num_tx);
- log("total bytes rx: %lu", stats.num_rx);
- log("connections refused due to load: %lu", stats.num_refused);
- log("garbage collections: %lu", stats.num_garbage);
- log("idle connections killed: %lu", stats.num_idles);
- log("end debug dump.");
-}
-
-/*
* Handle a signal
*/
void takesig(int sig)
{
switch (sig) {
- case SIGUSR1:
- dumpdebug();
- break;
case SIGHUP:
if (config.logf)
ftruncate(fileno(config.logf), 0);
- log("SIGHUP received, cleaning up...");
- conncoll();
- garbcoll();
+ log(LOG_NOTICE, "SIGHUP received, cleaning up...");
#ifdef FILTER_ENABLE
if (config.filter) {
filter_destroy();
filter_init();
}
- log("Re-reading filter file.");
+ log(LOG_NOTICE, "Re-reading filter file.");
#endif /* FILTER_ENABLE */
- log("Finished cleaning memory/connections.");
+ log(LOG_NOTICE, "Finished cleaning memory/connections.");
break;
case SIGTERM:
#ifdef FILTER_ENABLE
@@ -171,10 +78,7 @@ void takesig(int sig)
filter_destroy();
#endif /* FILTER_ENABLE */
config.quit = TRUE;
- break;
- case SIGALRM:
- calcload();
- alarm(LOAD_RECALCTIMER);
+ log(LOG_INFO, "SIGTERM received.");
break;
}
if (sig != SIGTERM)
@@ -183,57 +87,44 @@ void takesig(int sig)
}
/*
- * Display usage to the user on stderr.
+ * Display the version information for the user.
+ */
+static void versiondisp(void)
+{
+ printf("tinyproxy " VERSION "\n");
+ printf("\
+Copyright 1998 Steven Young (sdyoung@well.com)\n\
+Copyright 1998-2000 Robert James Kaes (rjkaes@flarenet.com)\n\
+Copyright 2000 Chris Lightfoot (chris@ex-parrot.com)\n\
+\n\
+This program is free software; you can redistribute it and/or modify it\n\
+under the terms of the GNU General Public License as published by the Free\n\
+Software Foundation; either version 2, or (at your option) any later\n\
+version.\n\
+\n\
+This program is distributed in the hope that it will be useful, but WITHOUT\n\
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or\n\
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for\n\
+more details.\n");
+}
+
+/*
+ * Display usage to the user.
*/
static void usagedisp(void)
{
- printf("tinyproxy version " VERSION "\n");
- printf("Copyright 1998 Steven Young (sdyoung@well.com)\n");
- printf
- ("Copyright 1998-1999 Robert James Kaes (rjkaes@flarenet.com)\n\n");
- printf("Copyright 2000 Chris Lightfoot (chris@ex-parrot.com)\n");
-
- printf
- ("This software is licensed under the GNU General Public License (GPL).\n");
- printf("See the file 'COPYING' included with tinyproxy source.\n\n");
-
- printf("Compiled with Ian Jackson's adns:\n");
- printf(" http://www.chiark.greenend.org.uk/~ian/adns/\n\n");
-
- printf("Usage: tinyproxy [args]\n");
- printf("Options:\n");
- printf("\t-a header\tallow 'header' through the anon block\n");
- printf("\t-d\t\tdo not daemonize\n");
-#ifdef FILTER_ENABLE
- printf("\t-f filterfile\tblock sites specified in filterfile\n");
-#endif /* FILTER_ENABLE */
- printf("\t-h\t\tdisplay usage\n");
- printf("\t-i ip_address\tonly listen on this address\n");
- printf("\t-l logfile\tlog to 'logfile'\n");
- printf
- ("\t-n ip_address\tallow access from only this subnet. (i.e. 192.168.0.)\n");
- printf("\t-p port\t\tlisten on 'port'\n");
- printf("\t-r\t\trestrict the log to only errors\n");
- printf("\t-s stathost\tset stathost to 'stathost'\n");
-#ifdef HAVE_SYSLOG_H
- printf("\t-S\t\tlog using the syslog instead\n");
-#endif
-#ifdef UPSTREAM_PROXY
- printf("\t-t domain:port\tredirect connections to an upstream proxy\n");
-#endif
- printf("\t-u user\t\tchange to user after startup. \"\" disables\n");
- printf("\t-v\t\tdisplay version number\n");
- printf
- ("\t-w load\t\tstop accepting new connections at 'load'. 0 disables\n");
-#ifdef XTINYPROXY
- printf
- ("\t-x domain\tAdd a XTinyproxy header with the peer's IP address\n");
-#endif
- /* UPSTREAM_PROXY */
+ printf("\
+Usage: tinyproxy [options]\n\
+Options:\n\
+ -d Operate in DEBUG mode.\n\
+ -c FILE Use an alternate configuration file.\n\
+ -h Display this usage information.\n\
+ -v Display the version number.\n");
+
/* Display the modes compiled into tinyproxy */
printf("\nFeatures Compiled In:\n");
-#ifdef XTINYPROXY
+#ifdef XTINYPROXY_ENABLE
printf(" XTinyproxy Header\n");
#endif /* XTINYPROXY */
#ifdef FILTER_ENABLE
@@ -243,157 +134,59 @@ static void usagedisp(void)
#ifndef NDEBUG
printf(" Debuggin code\n");
#endif /* NDEBUG */
-#ifdef UPSTREAM_PROXY
- printf(" Upstream proxy\n");
-#endif /* UPSTREAM_PROXY */
+#ifdef TUNNEL_SUPPORT
+ printf(" TCP Tunneling\n");
+#endif /* TUNNEL_SUPPORT */
}
int main(int argc, char **argv)
{
int optch;
- flag usage = FALSE, godaemon = TRUE, changeid = FALSE;
+ bool_t godaemon = TRUE;
struct passwd *thisuser = NULL;
+ struct group *thisgroup = NULL;
+ char *conf_file = DEFAULT_CONF_FILE;
-#ifdef UPSTREAM_PROXY
- char *upstream_ptr;
-#endif /* UPSTREAM_PROXY */
-
- while ((optch = getopt(argc, argv, "vh?dp:l:Sa:w:s:u:n:i:rx:f:t:")) !=
+ while ((optch = getopt(argc, argv, "c:vdh")) !=
EOF) {
switch (optch) {
case 'v':
- fprintf(stderr, "tinyproxy version " VERSION "\n");
+ versiondisp();
exit(EX_OK);
- break;
- case 'p':
- if (!(config.port = atoi(optarg))) {
- log
- ("bad port on commandline, defaulting to %d",
- DEFAULT_PORT);
- config.port = DEFAULT_PORT;
- }
- break;
- case 'l':
- if (!(config.logf_name = xstrdup(optarg))) {
- log("bad log file, defaulting to %s",
- DEFAULT_LOG);
- config.logf_name = DEFAULT_LOG;
- }
- break;
-#ifdef HAVE_SYSLOG_H
- case 'S': /* Use the syslog function to handle logging */
- config.syslog = TRUE;
- break;
-#endif
case 'd':
godaemon = FALSE;
break;
- case 'w':
- sscanf(optarg, "%f", &config.cutoffload);
- break;
- case 's':
- if (!(config.stathost = xstrdup(optarg))) {
- log("bad stathost, defaulting to %s",
- DEFAULT_STATHOST);
- config.stathost = DEFAULT_STATHOST;
- }
- break;
- case 'u':
- if (!(config.changeuser = xstrdup(optarg))) {
- log("bad user name, defaulting to %s",
- DEFAULT_USER);
- config.changeuser = DEFAULT_USER;
- }
- break;
- case 'a':
- config.anonymous = TRUE;
- anon_insert(optarg);
- break;
- case 'n':
- if (!(config.subnet = xstrdup(optarg))) {
- log("tinyproxy: could not allocate memory");
- exit(EX_SOFTWARE);
- }
- break;
- case 'i':
- if (!(config.ipAddr = xstrdup(optarg))) {
- log("tinyproxy: could not allocate memory");
- exit(EX_SOFTWARE);
- }
- break;
-#ifdef FILTER_ENABLE
- case 'f':
- if (!(config.filter = xstrdup(optarg))) {
- log("tinyproxy: could not allocate memory");
- }
- break;
-#endif /* FILTER_ENABLE */
- case 'r':
- config.restricted = TRUE;
- break;
-#ifdef XTINYPROXY
- case 'x':
- if (!(config.my_domain = xstrdup(optarg))) {
- log("tinyproxy: could not allocate memory");
- exit(EX_SOFTWARE);
- }
- break;
-#endif
-
-#ifdef UPSTREAM_PROXY
- case 't':
- if (!(upstream_ptr = strchr(optarg, ':'))) {
- log("tinyproxy: invalid UPSTREAM declaration");
- break;
- }
-
- *upstream_ptr++ = '\0';
- if (!(config.upstream_name = xstrdup(optarg))) {
- log("tinyproxy: could not allocate memory");
+ case 'c':
+ conf_file = strdup(optarg);
+ if (!conf_file) {
+ log(LOG_EMERG, "tinyproxy: could not allocate memory");
exit(EX_SOFTWARE);
}
- config.upstream_port = atoi(upstream_ptr);
-#ifndef NDEBUG
- log("upstream name: %s", config.upstream_name);
- log("upstream port: %d", config.upstream_port);
-#endif /* NDEBUG */
-
break;
-#endif /* UPSTREAM_PROXY */
-
- case '?':
case 'h':
default:
- usage = TRUE;
- break;
+ usagedisp();
+ exit(EX_OK);
}
}
- if (usage == TRUE) {
- usagedisp();
- exit(EX_OK);
- }
-
/*
- * If ANONYMOUS is turned on, make sure that Content-Length is
- * in the list of allowed headers, since it is required in a
- * HTTP/1.0 request. Also add the Content-Type header since it goes
- * hand in hand with Content-Length.
- * - rjkaes
+ * Read in the settings from the config file.
*/
- if (config.anonymous) {
- anon_insert("Content-Length:");
- anon_insert("Content-Type:");
- }
-
- /* chris - Initialise asynchronous DNS */
- if (adns_init(&adns, 0, 0)) {
- log("tinyproxy: could not initialise ADNS");
+ yyin = fopen(conf_file, "r");
+ if (!yyin) {
+ log(LOG_ERR, "Could not open %s file", conf_file);
exit(EX_SOFTWARE);
}
+ yyparse();
/* Open the log file if not using syslog */
if (config.syslog == FALSE) {
+ if (!config.logf_name) {
+ log(LOG_INFO, "Setting Logfile to \"%s\"", DEFAULT_LOG);
+ config.logf_name = DEFAULT_LOG;
+ }
+
if (!(config.logf = fopen(config.logf_name, "a"))) {
fprintf(stderr,
"Unable to open logfile %s for appending!\n",
@@ -407,72 +200,129 @@ int main(int argc, char **argv)
openlog("tinyproxy", LOG_PID, LOG_USER);
}
- log(PACKAGE " " VERSION " starting...");
-
- if (strlen(config.changeuser)) {
- if ((getuid() != 0) && (geteuid() != 0)) {
- log
- ("not running as root, therefore not changing uid/gid.");
- } else {
- changeid = TRUE;
- if (!(thisuser = getpwnam(config.changeuser))) {
- log("unable to find user \"%s\"!",
- config.changeuser);
- exit(EX_NOUSER);
- }
- log("changing to user \"%s\" (%d/%d).",
- config.changeuser, thisuser->pw_uid,
- thisuser->pw_gid);
- }
+ log(LOG_INFO, PACKAGE " " VERSION " starting...");
+
+ /*
+ * Set the default values if they were not set in the config file.
+ */
+ if (config.port == 0) {
+ log(LOG_INFO, "Setting Port to %u", DEFAULT_PORT);
+ config.port = DEFAULT_PORT;
}
-#ifdef NDEBUG
+ if (!config.stathost) {
+ log(LOG_INFO, "Setting stathost to \"%s\"", DEFAULT_STATHOST);
+ config.stathost = DEFAULT_STATHOST;
+ }
+ if (!config.username) {
+ log(LOG_INFO, "Setting user to \"%s\"", DEFAULT_USER);
+ config.username = DEFAULT_USER;
+ }
+ if (config.idletimeout == 0) {
+ log(LOG_INFO, "Setting idle timeout to %u seconds", MAX_IDLE_TIME);
+ config.idletimeout = MAX_IDLE_TIME;
+ }
+
+ init_stats();
+
+ /*
+ * If ANONYMOUS is turned on, make sure that Content-Length is
+ * in the list of allowed headers, since it is required in a
+ * HTTP/1.0 request. Also add the Content-Type header since it goes
+ * hand in hand with Content-Length.
+ * - rjkaes
+ */
+ if (config.anonymous) {
+ anon_insert("Content-Length:");
+ anon_insert("Content-Type:");
+ }
+
if (godaemon == TRUE)
makedaemon();
-#else
- printf("Debugging is enabled, so you can not go daemon.\n");
-#endif
+
+ if (config.pidpath) {
+ pidfile_create(config.pidpath);
+ }
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
- fprintf(stderr, "Could not set SIGPIPE\n");
+ log(LOG_EMERG, "Could not set SIGPIPE\n");
exit(EX_OSERR);
}
- if (signal(SIGUSR1, takesig) == SIG_ERR) {
- fprintf(stderr, "Could not set SIGUSR1\n");
+
+#ifdef FILTER_ENABLE
+ if (config.filter)
+ filter_init();
+#endif /* FILTER_ENABLE */
+
+ /*
+ * Start listening on the selected port.
+ */
+ if (thread_listening_sock(config.port) < 0) {
+ log(LOG_EMERG, "Problem creating listening socket");
exit(EX_OSERR);
}
+
+ /*
+ * Switch to a different user.
+ */
+ if (geteuid() == 0) {
+ if (config.group && strlen(config.group) > 0) {
+ thisgroup = getgrnam(config.group);
+ if (!thisgroup) {
+ log(LOG_ERR, "Unable to find group '%s'!", config.group);
+ exit(EX_NOUSER);
+ }
+ if (setgid(thisgroup->gr_gid) < 0) {
+ log(LOG_ERR, "Unable to change to group '%s'", config.group);
+ exit(EX_CANTCREAT);
+ }
+ log(LOG_INFO, "Now running as group %s", config.group);
+ }
+ if (config.username && strlen(config.username) > 0) {
+ thisuser = getpwnam(config.username);
+ if (!thisuser) {
+ log(LOG_ERR, "Unable to find user '%s'!", config.username);
+ exit(EX_NOUSER);
+ }
+ if (setuid(thisuser->pw_uid) < 0) {
+ log(LOG_ERR, "Unable to change to user '%s'", config.username);
+ exit(EX_CANTCREAT);
+ }
+ log(LOG_INFO, "Now running as user %s", config.username);
+ }
+ } else {
+ log(LOG_WARNING, "Not running as root, so not changing UID/GID.");
+ }
+
+ if (thread_pool_create() < 0) {
+ log(LOG_ERR, "Could not create the pool of threads");
+ exit(EX_SOFTWARE);
+ }
+
+ /*
+ * These signals are only for the main thread.
+ */
+ log(LOG_INFO, "Setting the various signals.");
if (signal(SIGTERM, takesig) == SIG_ERR) {
- fprintf(stderr, "Could not set SIGTERM\n");
+ log(LOG_EMERG, "Could not set SIGTERM\n");
exit(EX_OSERR);
}
if (signal(SIGHUP, takesig) == SIG_ERR) {
- fprintf(stderr, "Could not set SIGHUP\n");
- exit(EX_OSERR);
- }
- if (signal(SIGALRM, takesig) == SIG_ERR) {
- fprintf(stderr, "Could not set SIGALRM\n");
+ log(LOG_EMERG, "Could not set SIGHUP\n");
exit(EX_OSERR);
}
- alarm(LOAD_RECALCTIMER);
- calcload();
- if (init_listen_sock(config.port) < 0) {
- log("unable to bind port %d!", config.port);
- exit(EX_UNAVAILABLE);
- }
- if (changeid == TRUE) {
- setuid(thisuser->pw_uid);
- setgid(thisuser->pw_gid);
- }
- log("now accepting connections.");
+ log(LOG_INFO, "Starting main loop. Accepting connections.");
+ thread_main_loop();
-#ifdef FILTER_ENABLE
- if (config.filter)
- filter_init();
-#endif /* FILTER_ENABLE */
+ log(LOG_INFO, "Shutting down.");
+ thread_close_sock();
- while (config.quit == FALSE) {
- if (getreqs() < 0)
- break;
+ /*
+ * Remove the PID file.
+ */
+ if (unlink(config.pidpath) < 0) {
+ log(LOG_WARNING, "Could not remove PID file %s: %s",
+ config.pidpath, strerror(errno));
}
#ifdef FILTER_ENABLE
@@ -480,16 +330,10 @@ int main(int argc, char **argv)
filter_destroy();
#endif /* FILTER_ENABLE */
- log("shutting down.");
- de_init_listen_sock();
-
if (config.syslog == FALSE)
fclose(config.logf);
else
closelog();
- /* finsih up ADNS */
- adns_finish(adns);
-
exit(EX_OK);
}