X-Git-Url: https://tinc-vpn.org/git/browse?a=blobdiff_plain;f=src%2Ftincd.c;h=a06f3fe37fbddad06c53269b854e356e3d637d79;hb=6c453769fd16125ec18e8e6d102a3eaa09d370c7;hp=f63540aa9e4ce2fbffca28cfb82dc084eeb2f945;hpb=24874d0806bac5d75663ea9de67a71171bfc97b6;p=tinc diff --git a/src/tincd.c b/src/tincd.c index f63540aa..cb86cd8b 100644 --- a/src/tincd.c +++ b/src/tincd.c @@ -1,7 +1,7 @@ /* tincd.c -- the main file for tincd - Copyright (C) 1998,1999,2000 Ivo Timmermans - 2000 Guus Sliepen + Copyright (C) 1998-2005 Ivo Timmermans + 2000-2007 Guus Sliepen 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 @@ -17,479 +17,333 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id: tincd.c,v 1.10.4.6 2000/06/30 11:45:16 guus Exp $ + $Id$ */ -#include "config.h" +#include "system.h" -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_SYS_IOCTL_H -# include +/* Darwin (MacOS/X) needs the following definition... */ +#ifndef _P1003_1B_VISIBLE +#define _P1003_1B_VISIBLE +#endif + +#ifdef HAVE_SYS_MMAN_H +#include #endif -#include -#include -#include +#include LZO1X_H + +#include #include "conf.h" -#include "encr.h" +#include "control.h" +#include "crypto.h" +#include "device.h" +#include "logger.h" #include "net.h" #include "netutl.h" - -#include "system.h" +#include "process.h" +#include "protocol.h" +#include "utils.h" +#include "xalloc.h" /* The name this program was run with. */ -char *program_name; +char *program_name = NULL; /* If nonzero, display usage information and exit. */ -static int show_help; +bool show_help = false; /* If nonzero, print the version on standard output and exit. */ -static int show_version; - -/* If nonzero, it will attempt to kill a running tincd and exit. */ -static int kill_tincd = 0; - -/* If zero, don't detach from the terminal. */ -static int do_detach = 1; - -char *confbase = NULL; /* directory in which all config files are */ -/* char *configfilename = NULL; /* configuration file name, moved to config.c */ -char *identname; /* program name for syslog */ -char *netname = NULL; /* name of the vpn network */ -char *pidfilename; /* pid file location */ -static pid_t ppid; /* pid of non-detached part */ -char **g_argv; /* a copy of the cmdline arguments */ - -void cleanup_and_exit(int); -int detach(void); -int kill_other(void); -void make_names(void); -RETSIGTYPE parent_exit(int a); -void setup_signals(void); -int write_pidfile(void); - -static struct option const long_options[] = -{ - { "kill", no_argument, NULL, 'k' }, - { "net", required_argument, NULL, 'n' }, - { "timeout", required_argument, NULL, 'p' }, - { "help", no_argument, &show_help, 1 }, - { "version", no_argument, &show_version, 1 }, - { "no-detach", no_argument, &do_detach, 0 }, - { NULL, 0, NULL, 0 } +bool show_version = false; + +/* If nonzero, use null ciphers and skip all key exchanges. */ +bool bypass_security = false; + +/* If nonzero, disable swapping for this process. */ +bool do_mlock = false; + +/* If nonzero, write log entries to a separate file. */ +bool use_logfile = false; + +char *identname = NULL; /* program name for syslog */ +char *controlsocketname = NULL; /* control socket location */ +char *logfilename = NULL; /* log file location */ +char **g_argv; /* a copy of the cmdline arguments */ + +static int status; + +static struct option const long_options[] = { + {"config", required_argument, NULL, 'c'}, + {"net", required_argument, NULL, 'n'}, + {"help", no_argument, NULL, 1}, + {"version", no_argument, NULL, 2}, + {"no-detach", no_argument, NULL, 'D'}, + {"debug", optional_argument, NULL, 'd'}, + {"bypass-security", no_argument, NULL, 3}, + {"mlock", no_argument, NULL, 'L'}, + {"logfile", optional_argument, NULL, 4}, + {"controlsocket", required_argument, NULL, 5}, + {NULL, 0, NULL, 0} }; -static void -usage(int status) -{ - if(status != 0) - fprintf(stderr, _("Try `%s --help\' for more information.\n"), program_name); - else - { - printf(_("Usage: %s [option]...\n\n"), program_name); - printf(_(" -c, --config=FILE Read configuration options from FILE.\n" - " -D, --no-detach Don't fork and detach.\n" - " -d Increase debug level.\n" - " -k, --kill Attempt to kill a running tincd and exit.\n" - " -n, --net=NETNAME Connect to net NETNAME.\n" - " -t, --timeout=TIMEOUT Seconds to wait before giving a timeout.\n")); - printf(_(" --help Display this help and exit.\n" - " --version Output version information and exit.\n\n")); - printf(_("Report bugs to tinc@nl.linux.org.\n")); - } - exit(status); -} - -void -parse_options(int argc, char **argv, char **envp) -{ - int r; - int option_index = 0; - config_t *p; - - while((r = getopt_long(argc, argv, "c:Ddkn:t:", long_options, &option_index)) != EOF) - { - switch(r) - { - case 0: /* long option */ - break; - case 'c': /* config file */ - configfilename = xmalloc(strlen(optarg)+1); - strcpy(configfilename, optarg); - break; - case 'D': /* no detach */ - do_detach = 0; - break; - case 'd': /* inc debug level */ - debug_lvl++; - break; - case 'k': /* kill old tincds */ - kill_tincd = 1; - break; - case 'n': /* net name given */ - netname = xmalloc(strlen(optarg)+1); - strcpy(netname, optarg); - break; - case 't': /* timeout */ - if(!(p = add_config_val(&config, TYPE_INT, optarg))) - { - printf(_("Invalid timeout value `%s'.\n"), optarg); - usage(1); - } - break; - case '?': - usage(1); - default: - break; - } - } -} +#ifdef HAVE_MINGW +static struct WSAData wsa_state; +#endif -void memory_full(int size) +static void usage(bool status) { - syslog(LOG_ERR, _("Memory exhausted (last is %s:%d) (couldn't allocate %d bytes), exiting."), cp_file, cp_line, size); - exit(1); + if(status) + fprintf(stderr, _("Try `%s --help\' for more information.\n"), + program_name); + else { + printf(_("Usage: %s [option]...\n\n"), program_name); + printf(_( " -c, --config=DIR Read configuration options from DIR.\n" + " -D, --no-detach Don't fork and detach.\n" + " -d, --debug[=LEVEL] Increase debug level or set it to LEVEL.\n" + " -n, --net=NETNAME Connect to net NETNAME.\n" + " -L, --mlock Lock tinc into main memory.\n" + " --logfile[=FILENAME] Write log entries to a logfile.\n" + " --controlsocket=FILENAME Open control socket at FILENAME.\n" + " --bypass-security Disables meta protocol security, for debugging.\n" + " --help Display this help and exit.\n" + " --version Output version information and exit.\n\n")); + printf(_("Report bugs to tinc@tinc-vpn.org.\n")); + } } -/* - Detach from current terminal, write pidfile, kill parent -*/ -int detach(void) +static bool parse_options(int argc, char **argv) { - int fd; - pid_t pid; - - if(do_detach) - { - ppid = getpid(); - - if((pid = fork()) < 0) - { - perror("fork"); - return -1; + int r; + int option_index = 0; + + while((r = getopt_long(argc, argv, "c:DLd::n:", long_options, &option_index)) != EOF) { + switch (r) { + case 0: /* long option */ + break; + + case 'c': /* config file */ + confbase = xstrdup(optarg); + break; + + case 'D': /* no detach */ + do_detach = false; + break; + + case 'L': /* no detach */ + do_mlock = true; + break; + + case 'd': /* inc debug level */ + if(optarg) + debug_level = atoi(optarg); + else + debug_level++; + break; + + case 'n': /* net name given */ + netname = xstrdup(optarg); + break; + + case 1: /* show help */ + show_help = true; + break; + + case 2: /* show version */ + show_version = true; + break; + + case 3: /* bypass security */ + bypass_security = true; + break; + + case 4: /* write log entries to a file */ + use_logfile = true; + if(optarg) + logfilename = xstrdup(optarg); + break; + + case 5: /* open control socket here */ + controlsocketname = xstrdup(optarg); + break; + + case '?': + usage(true); + return false; + + default: + break; + } } - if(pid) /* parent process */ - { - signal(SIGTERM, parent_exit); - sleep(600); /* wait 10 minutes */ - exit(1); - } - } - - if(write_pidfile()) - return -1; - - if(do_detach) - { - if((fd = open("/dev/tty", O_RDWR)) >= 0) - { - if(ioctl(fd, TIOCNOTTY, NULL)) - { - perror("ioctl"); - return -1; - } - close(fd); - } - - if(setsid() < 0) - return -1; - - kill(ppid, SIGTERM); - } - - chdir("/"); /* avoid keeping a mointpoint busy */ - - openlog(identname, LOG_CONS | LOG_PID, LOG_DAEMON); - if(debug_lvl > 0) - syslog(LOG_NOTICE, _("tincd %s (%s %s) starting, debug level %d"), - VERSION, __DATE__, __TIME__, debug_lvl); - else - syslog(LOG_NOTICE, _("tincd %s starting"), VERSION, debug_lvl); - - xalloc_fail_func = memory_full; - - return 0; + return true; } /* - Close network connections, and terminate neatly + Set all files and paths according to netname */ -void cleanup_and_exit(int c) +static void make_names(void) { - close_network_connections(); - - if(debug_lvl > 0) - syslog(LOG_INFO, _("Total bytes written: tap %d, socket %d; bytes read: tap %d, socket %d"), - total_tap_out, total_socket_out, total_tap_in, total_socket_in); +#ifdef HAVE_MINGW + HKEY key; + char installdir[1024] = ""; + long len = sizeof(installdir); +#endif - closelog(); - kill(ppid, SIGTERM); - exit(c); -} + if(netname) + asprintf(&identname, "tinc.%s", netname); + else + identname = xstrdup("tinc"); + +#ifdef HAVE_MINGW + if(!RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\tinc", 0, KEY_READ, &key)) { + if(!RegQueryValueEx(key, NULL, 0, 0, installdir, &len)) { + if(!logfilename) + asprintf(&logfilename, "%s/log/%s.log", identname); + if(!confbase) { + if(netname) + asprintf(&confbase, "%s/%s", installdir, netname); + else + asprintf(&confbase, "%s", installdir); + } + } + RegCloseKey(key); + if(*installdir) + return; + } +#endif -/* - check for an existing tinc for this net, and write pid to pidfile -*/ -int write_pidfile(void) -{ - int pid; - - if((pid = check_pid(pidfilename))) - { - if(netname) - fprintf(stderr, _("A tincd is already running for net `%s' with pid %d.\n"), - netname, pid); - else - fprintf(stderr, _("A tincd is already running with pid %d.\n"), pid); - return 1; - } - - /* if it's locked, write-protected, or whatever */ - if(!write_pid(pidfilename)) - return 1; - - return 0; -} + if(!controlsocketname) + asprintf(&controlsocketname, LOCALSTATEDIR "/run/%s.control", identname); -/* - kill older tincd for this net -*/ -int kill_other(void) -{ - int pid; - - if(!(pid = read_pid(pidfilename))) - { - if(netname) - fprintf(stderr, _("No other tincd is running for net `%s'.\n"), netname); - else - fprintf(stderr, _("No other tincd is running.\n")); - return 1; - } - - errno = 0; /* No error, sometimes errno is only changed on error */ - /* ESRCH is returned when no process with that pid is found */ - if(kill(pid, SIGTERM) && errno == ESRCH) - fprintf(stderr, _("Removing stale lock file.\n")); - remove_pid(pidfilename); - - return 0; -} + if(!logfilename) + asprintf(&logfilename, LOCALSTATEDIR "/log/%s.log", identname); -/* - Set all files and paths according to netname -*/ -void make_names(void) -{ - if(!configfilename) - { - if(netname) - { - configfilename = xmalloc(strlen(netname)+18+strlen(CONFDIR)); - sprintf(configfilename, "%s/tinc/%s/tinc.conf", CONFDIR, netname); + if(netname) { + if(!confbase) + asprintf(&confbase, CONFDIR "/tinc/%s", netname); + else + logger(LOG_INFO, _("Both netname and configuration directory given, using the latter...")); + } else { + if(!confbase) + asprintf(&confbase, CONFDIR "/tinc"); } - else - { - configfilename = xmalloc(17+strlen(CONFDIR)); - sprintf(configfilename, "%s/tinc/tinc.conf", CONFDIR); - } - } - - if(netname) - { - pidfilename = xmalloc(strlen(netname)+20); - sprintf(pidfilename, "/var/run/tinc.%s.pid", netname); - confbase = xmalloc(strlen(netname)+8+strlen(CONFDIR)); - sprintf(confbase, "%s/tinc/%s/", CONFDIR, netname); - identname = xmalloc(strlen(netname)+7); - sprintf(identname, "tinc.%s", netname); - } - else - { - pidfilename = "/var/run/tinc.pid"; - confbase = xmalloc(7+strlen(CONFDIR)); - sprintf(confbase, "%s/tinc/", CONFDIR); - identname = "tinc"; - } } -int -main(int argc, char **argv, char **envp) +int main(int argc, char **argv) { - program_name = argv[0]; - - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); - - parse_options(argc, argv, envp); - - if(show_version) - { - printf(_("%s version %s\n"), PACKAGE, VERSION); - printf(_("Copyright (C) 1998,1999,2000 Ivo Timmermans and others,\n" - "see the AUTHORS file for a complete list.\n\n" - "tinc comes with ABSOLUTELY NO WARRANTY. This is free software,\n" - "and you are welcome to redistribute it under certain conditions;\n" - "see the file COPYING for details.\n\n")); - printf(_("This product includes software developed by Eric Young (eay@mincom.oz.au)\n")); + program_name = argv[0]; + + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + if(!parse_options(argc, argv)) + return 1; + + make_names(); + + if(show_version) { + printf(_("%s version %s (built %s %s, protocol %d)\n"), PACKAGE, + VERSION, __DATE__, __TIME__, PROT_CURRENT); + printf(_("Copyright (C) 1998-2007 Ivo Timmermans, Guus Sliepen and others.\n" + "See the AUTHORS file for a complete list.\n\n" + "tinc comes with ABSOLUTELY NO WARRANTY. This is free software,\n" + "and you are welcome to redistribute it under certain conditions;\n" + "see the file COPYING for details.\n")); + + return 0; + } - return 0; - } + if(show_help) { + usage(false); + return 0; + } - if(show_help) - usage(0); + openlogger("tinc", use_logfile?LOGMODE_FILE:LOGMODE_STDERR); - if(geteuid()) - { - fprintf(stderr, _("You must be root to run this program. Sorry.\n")); - return 1; - } + if(!event_init()) { + logger(LOG_ERR, _("Error initializing libevent!")); + return 1; + } - g_argv = argv; + if(!init_control()) + return 1; - make_names(); + /* Lock all pages into memory if requested */ - if(kill_tincd) - exit(kill_other()); + if(do_mlock) +#ifdef HAVE_MLOCKALL + if(mlockall(MCL_CURRENT | MCL_FUTURE)) { + logger(LOG_ERR, _("System call `%s' failed: %s"), "mlockall", + strerror(errno)); +#else + { + logger(LOG_ERR, _("mlockall() not supported on this platform!")); +#endif + return -1; + } - if(read_config_file(configfilename)) - return 1; + g_argv = argv; - setup_signals(); + init_configuration(&config_tree); - if(detach()) - exit(0); + /* Slllluuuuuuurrrrp! */ - if(security_init()) - return 1; + srand(time(NULL)); + crypto_init(); - for(;;) - { - setup_network_connections(); + if(!read_server_config()) + return 1; - main_loop(); + if(lzo_init() != LZO_E_OK) { + logger(LOG_ERR, _("Error initializing LZO compressor!")); + return 1; + } - cleanup_and_exit(1); +#ifdef HAVE_MINGW + if(WSAStartup(MAKEWORD(2, 2), &wsa_state)) { + logger(LOG_ERR, _("System call `%s' failed: %s"), "WSAStartup", winerror(GetLastError())); + return 1; + } - syslog(LOG_ERR, _("Unrecoverable error, restarting in %d seconds!"), MAXTIMEOUT); - sleep(MAXTIMEOUT); - } + if(!do_detach || !init_service()) + return main2(argc, argv); + else + return 1; } -RETSIGTYPE -sigterm_handler(int a) +int main2(int argc, char **argv) { - if(debug_lvl > 0) - syslog(LOG_NOTICE, _("Got TERM signal")); - cleanup_and_exit(0); -} +#endif -RETSIGTYPE -sigquit_handler(int a) -{ - if(debug_lvl > 0) - syslog(LOG_NOTICE, _("Got QUIT signal")); - cleanup_and_exit(0); -} + if(!detach()) + return 1; + -RETSIGTYPE -sigsegv_square(int a) -{ - syslog(LOG_NOTICE, _("Got another SEGV signal: not restarting")); - exit(0); -} + /* Setup sockets and open device. */ -RETSIGTYPE -sigsegv_handler(int a) -{ - if(cp_file) - syslog(LOG_NOTICE, _("Got SEGV signal after %s line %d, trying to re-execute"), - cp_file, cp_line); - else - syslog(LOG_NOTICE, _("Got SEGV signal, trying to re-execute")); - - signal(SIGSEGV, sigsegv_square); - close_network_connections(); - remove_pid(pidfilename); - execvp(g_argv[0], g_argv); -} + if(!setup_network_connections()) + goto end; -RETSIGTYPE -sighup_handler(int a) -{ - if(debug_lvl > 0) - syslog(LOG_NOTICE, _("Got HUP signal, rereading configuration and restarting")); - sighup = 1; -} + /* Start main loop. It only exits when tinc is killed. */ -RETSIGTYPE -sigint_handler(int a) -{ - if(debug_lvl > 0) - syslog(LOG_NOTICE, _("Got INT signal, exiting")); - cleanup_and_exit(0); -} + status = main_loop(); -RETSIGTYPE -sigusr1_handler(int a) -{ - dump_conn_list(); -} + /* Shutdown properly. */ -RETSIGTYPE -sigusr2_handler(int a) -{ - if(debug_lvl > 1) - syslog(LOG_NOTICE, _("Got USR2 signal, forcing new key generation")); - regenerate_keys(); -} + close_network_connections(); -RETSIGTYPE -sighuh(int a) -{ - if(cp_file) - syslog(LOG_NOTICE, _("Got unexpected signal %d after %s line %d"), - a, cp_file, cp_line); - else - syslog(LOG_NOTICE, _("Got unexpected signal %d"), a); -} + ifdebug(CONNECTIONS) + dump_device_stats(); -void -setup_signals(void) -{ - int i; - - for(i=0;i<32;i++) - signal(i,sighuh); - - if(signal(SIGTERM, SIG_IGN) != SIG_ERR) - signal(SIGTERM, sigterm_handler); - if(signal(SIGQUIT, SIG_IGN) != SIG_ERR) - signal(SIGQUIT, sigquit_handler); - if(signal(SIGSEGV, SIG_IGN) != SIG_ERR) - signal(SIGSEGV, sigsegv_handler); - if(signal(SIGHUP, SIG_IGN) != SIG_ERR) - signal(SIGHUP, sighup_handler); - signal(SIGPIPE, SIG_IGN); - if(signal(SIGINT, SIG_IGN) != SIG_ERR) - signal(SIGINT, sigint_handler); - signal(SIGUSR1, sigusr1_handler); - signal(SIGUSR2, sigusr2_handler); -// signal(SIGCHLD, parent_exit); -} +end: + logger(LOG_NOTICE, _("Terminating")); -RETSIGTYPE parent_exit(int a) -{ - exit(0); +#ifndef HAVE_MINGW + exit_control(); +#endif + + crypto_exit(); + + return status; }