2000-10-24 05:44:43 +08:00
|
|
|
/* $Id: tinyproxy.c,v 1.6 2000-10-23 21:44:43 rjkaes Exp $
|
2000-02-17 01:32:49 +08:00
|
|
|
*
|
2000-09-12 08:03:53 +08:00
|
|
|
* The initialise routine. Basically sets up all the initial stuff (logfile,
|
2000-02-17 01:32:49 +08:00
|
|
|
* 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,
|
|
|
|
* stats, etc.) Like any good program, most of the work is actually done
|
|
|
|
* elsewhere.
|
|
|
|
*
|
|
|
|
* Copyright (C) 1998 Steven Young
|
|
|
|
* Copyright (C) 1999 Robert James Kaes (rjkaes@flarenet.com)
|
|
|
|
* Copyright (C) 2000 Chris Lightfoot (chris@ex-parrot.com>
|
|
|
|
*
|
|
|
|
* 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, 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.
|
|
|
|
*/
|
|
|
|
|
2000-09-12 08:03:53 +08:00
|
|
|
#include "tinyproxy.h"
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2000-09-12 08:03:53 +08:00
|
|
|
#include <grp.h>
|
|
|
|
#include <pwd.h>
|
2000-02-17 01:32:49 +08:00
|
|
|
#include <signal.h>
|
|
|
|
#include <sysexits.h>
|
|
|
|
#include <syslog.h>
|
|
|
|
|
2000-09-12 08:03:53 +08:00
|
|
|
#include "anonymous.h"
|
2000-02-17 01:32:49 +08:00
|
|
|
#include "buffer.h"
|
2000-10-24 05:44:43 +08:00
|
|
|
#include "dnscache.h"
|
2000-02-17 01:32:49 +08:00
|
|
|
#include "filter.h"
|
2000-09-12 08:03:53 +08:00
|
|
|
#include "log.h"
|
|
|
|
#include "reqs.h"
|
|
|
|
#include "sock.h"
|
|
|
|
#include "stats.h"
|
|
|
|
#include "thread.h"
|
|
|
|
#include "utils.h"
|
2000-02-17 01:32:49 +08:00
|
|
|
|
|
|
|
void takesig(int sig);
|
|
|
|
|
2000-09-12 08:03:53 +08:00
|
|
|
extern int yyparse(void);
|
|
|
|
extern FILE *yyin;
|
|
|
|
|
2000-02-17 01:32:49 +08:00
|
|
|
/*
|
|
|
|
* Global Structures
|
|
|
|
*/
|
2000-09-12 08:03:53 +08:00
|
|
|
struct config_s config;
|
2000-02-17 01:32:49 +08:00
|
|
|
float load = 0.00;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle a signal
|
|
|
|
*/
|
|
|
|
void takesig(int sig)
|
|
|
|
{
|
|
|
|
switch (sig) {
|
|
|
|
case SIGHUP:
|
|
|
|
if (config.logf)
|
|
|
|
ftruncate(fileno(config.logf), 0);
|
|
|
|
|
2000-09-12 08:03:53 +08:00
|
|
|
log(LOG_NOTICE, "SIGHUP received, cleaning up...");
|
2000-02-17 01:32:49 +08:00
|
|
|
|
|
|
|
#ifdef FILTER_ENABLE
|
|
|
|
if (config.filter) {
|
|
|
|
filter_destroy();
|
|
|
|
filter_init();
|
|
|
|
}
|
2000-09-12 08:03:53 +08:00
|
|
|
log(LOG_NOTICE, "Re-reading filter file.");
|
2000-02-17 01:32:49 +08:00
|
|
|
#endif /* FILTER_ENABLE */
|
2000-09-12 08:03:53 +08:00
|
|
|
log(LOG_NOTICE, "Finished cleaning memory/connections.");
|
2000-02-17 01:32:49 +08:00
|
|
|
break;
|
|
|
|
case SIGTERM:
|
|
|
|
#ifdef FILTER_ENABLE
|
|
|
|
if (config.filter)
|
|
|
|
filter_destroy();
|
|
|
|
#endif /* FILTER_ENABLE */
|
|
|
|
config.quit = TRUE;
|
2000-09-12 08:03:53 +08:00
|
|
|
log(LOG_INFO, "SIGTERM received.");
|
2000-02-17 01:32:49 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (sig != SIGTERM)
|
|
|
|
signal(sig, takesig);
|
|
|
|
signal(SIGPIPE, SIG_IGN);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2000-09-12 08:03:53 +08:00
|
|
|
* 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.
|
2000-02-17 01:32:49 +08:00
|
|
|
*/
|
|
|
|
static void usagedisp(void)
|
|
|
|
{
|
2000-09-12 08:03:53 +08:00
|
|
|
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");
|
|
|
|
|
2000-02-17 01:32:49 +08:00
|
|
|
|
|
|
|
/* Display the modes compiled into tinyproxy */
|
|
|
|
printf("\nFeatures Compiled In:\n");
|
2000-09-12 08:03:53 +08:00
|
|
|
#ifdef XTINYPROXY_ENABLE
|
2000-02-17 01:32:49 +08:00
|
|
|
printf(" XTinyproxy Header\n");
|
|
|
|
#endif /* XTINYPROXY */
|
|
|
|
#ifdef FILTER_ENABLE
|
|
|
|
printf(" Filtering\n");
|
|
|
|
printf(" * with Regular Expression support\n");
|
|
|
|
#endif /* FILTER_ENABLE */
|
|
|
|
#ifndef NDEBUG
|
|
|
|
printf(" Debuggin code\n");
|
|
|
|
#endif /* NDEBUG */
|
2000-09-12 08:03:53 +08:00
|
|
|
#ifdef TUNNEL_SUPPORT
|
|
|
|
printf(" TCP Tunneling\n");
|
|
|
|
#endif /* TUNNEL_SUPPORT */
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
int optch;
|
2000-09-12 08:03:53 +08:00
|
|
|
bool_t godaemon = TRUE;
|
2000-02-17 01:32:49 +08:00
|
|
|
struct passwd *thisuser = NULL;
|
2000-09-12 08:03:53 +08:00
|
|
|
struct group *thisgroup = NULL;
|
|
|
|
char *conf_file = DEFAULT_CONF_FILE;
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2000-09-12 08:03:53 +08:00
|
|
|
while ((optch = getopt(argc, argv, "c:vdh")) !=
|
2000-02-17 01:32:49 +08:00
|
|
|
EOF) {
|
|
|
|
switch (optch) {
|
|
|
|
case 'v':
|
2000-09-12 08:03:53 +08:00
|
|
|
versiondisp();
|
2000-02-17 01:32:49 +08:00
|
|
|
exit(EX_OK);
|
|
|
|
case 'd':
|
|
|
|
godaemon = FALSE;
|
|
|
|
break;
|
2000-09-12 08:03:53 +08:00
|
|
|
case 'c':
|
|
|
|
conf_file = strdup(optarg);
|
|
|
|
if (!conf_file) {
|
|
|
|
log(LOG_EMERG, "tinyproxy: could not allocate memory");
|
2000-03-12 04:37:44 +08:00
|
|
|
exit(EX_SOFTWARE);
|
|
|
|
}
|
|
|
|
break;
|
2000-02-17 01:32:49 +08:00
|
|
|
case 'h':
|
|
|
|
default:
|
2000-09-12 08:03:53 +08:00
|
|
|
usagedisp();
|
|
|
|
exit(EX_OK);
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-04-01 04:08:19 +08:00
|
|
|
/*
|
2000-09-12 08:03:53 +08:00
|
|
|
* Read in the settings from the config file.
|
2000-04-01 04:08:19 +08:00
|
|
|
*/
|
2000-09-12 08:03:53 +08:00
|
|
|
yyin = fopen(conf_file, "r");
|
|
|
|
if (!yyin) {
|
|
|
|
log(LOG_ERR, "Could not open %s file", conf_file);
|
2000-02-17 01:32:49 +08:00
|
|
|
exit(EX_SOFTWARE);
|
|
|
|
}
|
2000-09-12 08:03:53 +08:00
|
|
|
yyparse();
|
2000-02-17 01:32:49 +08:00
|
|
|
|
|
|
|
/* Open the log file if not using syslog */
|
|
|
|
if (config.syslog == FALSE) {
|
2000-09-12 08:03:53 +08:00
|
|
|
if (!config.logf_name) {
|
|
|
|
log(LOG_INFO, "Setting Logfile to \"%s\"", DEFAULT_LOG);
|
|
|
|
config.logf_name = DEFAULT_LOG;
|
|
|
|
}
|
|
|
|
|
2000-02-17 01:32:49 +08:00
|
|
|
if (!(config.logf = fopen(config.logf_name, "a"))) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"Unable to open logfile %s for appending!\n",
|
|
|
|
config.logf_name);
|
|
|
|
exit(EX_CANTCREAT);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (godaemon == TRUE)
|
|
|
|
openlog("tinyproxy", LOG_PID, LOG_DAEMON);
|
|
|
|
else
|
|
|
|
openlog("tinyproxy", LOG_PID, LOG_USER);
|
|
|
|
}
|
|
|
|
|
2000-09-12 08:03:53 +08:00
|
|
|
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;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
2000-09-12 08:03:53 +08:00
|
|
|
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:");
|
|
|
|
}
|
|
|
|
|
2000-02-17 01:32:49 +08:00
|
|
|
if (godaemon == TRUE)
|
|
|
|
makedaemon();
|
2000-09-12 08:03:53 +08:00
|
|
|
|
|
|
|
if (config.pidpath) {
|
|
|
|
pidfile_create(config.pidpath);
|
|
|
|
}
|
2000-02-17 01:32:49 +08:00
|
|
|
|
|
|
|
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
|
2000-09-22 00:57:10 +08:00
|
|
|
log(LOG_CRIT, "Could not set SIGPIPE\n");
|
2000-02-17 01:32:49 +08:00
|
|
|
exit(EX_OSERR);
|
|
|
|
}
|
2000-09-12 08:03:53 +08:00
|
|
|
|
|
|
|
#ifdef FILTER_ENABLE
|
|
|
|
if (config.filter)
|
|
|
|
filter_init();
|
|
|
|
#endif /* FILTER_ENABLE */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Start listening on the selected port.
|
|
|
|
*/
|
|
|
|
if (thread_listening_sock(config.port) < 0) {
|
2000-09-22 00:57:10 +08:00
|
|
|
log(LOG_CRIT, "Problem creating listening socket");
|
2000-02-17 01:32:49 +08:00
|
|
|
exit(EX_OSERR);
|
|
|
|
}
|
2000-09-12 08:03:53 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.");
|
2000-02-17 01:32:49 +08:00
|
|
|
if (signal(SIGTERM, takesig) == SIG_ERR) {
|
2000-09-22 00:57:10 +08:00
|
|
|
log(LOG_CRIT, "Could not set SIGTERM\n");
|
2000-02-17 01:32:49 +08:00
|
|
|
exit(EX_OSERR);
|
|
|
|
}
|
|
|
|
if (signal(SIGHUP, takesig) == SIG_ERR) {
|
2000-09-22 00:57:10 +08:00
|
|
|
log(LOG_CRIT, "Could not set SIGHUP\n");
|
2000-02-17 01:32:49 +08:00
|
|
|
exit(EX_OSERR);
|
|
|
|
}
|
|
|
|
|
2000-10-24 05:44:43 +08:00
|
|
|
/*
|
|
|
|
* Initialize the various subsystems...
|
|
|
|
*/
|
|
|
|
log(LOG_INFO, "Starting the DNS caching subsystem.");
|
|
|
|
if (!new_dnscache())
|
|
|
|
exit(EX_SOFTWARE);
|
|
|
|
log(LOG_INFO, "Starting the Anonymous header subsystem.");
|
|
|
|
if (!new_anonymous())
|
|
|
|
exit(EX_SOFTWARE);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Start the main loop.
|
|
|
|
*/
|
2000-09-12 08:03:53 +08:00
|
|
|
log(LOG_INFO, "Starting main loop. Accepting connections.");
|
|
|
|
thread_main_loop();
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2000-09-12 08:03:53 +08:00
|
|
|
log(LOG_INFO, "Shutting down.");
|
|
|
|
thread_close_sock();
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2000-09-12 08:03:53 +08:00
|
|
|
/*
|
|
|
|
* Remove the PID file.
|
|
|
|
*/
|
|
|
|
if (unlink(config.pidpath) < 0) {
|
|
|
|
log(LOG_WARNING, "Could not remove PID file %s: %s",
|
|
|
|
config.pidpath, strerror(errno));
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef FILTER_ENABLE
|
|
|
|
if (config.filter)
|
|
|
|
filter_destroy();
|
|
|
|
#endif /* FILTER_ENABLE */
|
|
|
|
|
|
|
|
if (config.syslog == FALSE)
|
|
|
|
fclose(config.logf);
|
|
|
|
else
|
|
|
|
closelog();
|
|
|
|
|
|
|
|
exit(EX_OK);
|
|
|
|
}
|