From 92a3e63dc3841c4daa05fc2a25635fe9afacf08f Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Wed, 24 Mar 2004 14:56:04 +0000 Subject: [PATCH] Some random changes. --- fd/fd.c | 4 +- tincd.c | 328 ++++++++++++++++++++++++++++++++++++++++++++---------- tnl/tnl.c | 92 ++++++++++----- tnl/tnl.h | 3 +- vnd/vnd.c | 3 +- 5 files changed, 339 insertions(+), 91 deletions(-) diff --git a/fd/fd.c b/fd/fd.c index b969205..ad4a8ca 100644 --- a/fd/fd.c +++ b/fd/fd.c @@ -34,7 +34,7 @@ static avl_tree_t *fds; volatile bool fd_running = false; int fd_compare(struct fd *a, struct fd *b) { - return (a->fd - b->fd) ?: (a->mode - b->mode); + return a->fd - b->fd; }; bool fd_init(void) { @@ -42,7 +42,7 @@ bool fd_init(void) { FD_ZERO(&readset); FD_ZERO(&writeset); - FD_ZERO(&exceptset); + FD_ZERO(&errorset); fds = avl_tree_new((avl_compare_t)fd_compare, NULL); diff --git a/tincd.c b/tincd.c index 5f99cea..7b8d02a 100644 --- a/tincd.c +++ b/tincd.c @@ -22,6 +22,8 @@ #include "system.h" +#include + #include "cfg/cfg.h" #include "fd/event.h" #include "fd/fd.h" @@ -32,90 +34,294 @@ #include "tnl/tnl.h" #include "vnd/vnd.h" -static bool vnd_recv(struct vnd *vnd, char *buf, int len) { - static int p = 0; - char b[4]; - logger(LOG_DEBUG, _("Read packet of %d bytes from vnd %p"), len, vnd); - memcpy(b, buf + 16, 4); - memcpy(buf + 16, buf + 20, 4); - memcpy(buf + 20, b, 4); - vnd->send(vnd, buf, len); - return true; +static bool show_help = false; +static bool show_version = false; +static int kill_tincd = 0; +static bool bypass_security = false; +static bool do_mlock = false; +static bool use_logfile = false; +static bool do_detach = true; +static int debug_level = 1; + +static char *confbase = NULL; +static char *identname = NULL; +static char *pidfilename = NULL; +static char *logfilename = NULL; +static char *cfgfilename = NULL; + +int tinc_argc; +char **tinc_argv; +cfg_tree_t tinc_cfg; + +static struct option const long_options[] = { + {"config", required_argument, NULL, 'c'}, + {"kill", optional_argument, NULL, 'k'}, + {"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}, + {"pidfile", required_argument, NULL, 5}, + {NULL, 0, NULL, 0} +}; + +#ifdef HAVE_MINGW +static struct WSAData wsa_state; +#endif + +static void usage(bool status) { + if(status) + fprintf(stderr, _("Try `%s --help\' for more information.\n"), tinc_argv[0]); + else { + printf(_("Usage: %s [option]...\n\n"), tinc_argv[0]); + 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" + " -k, --kill[=SIGNAL] Attempt to kill a running tincd and exit.\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" + " --pidfile=FILENAME Write PID to FILENAME.\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")); + } } -static bool vnd_stop(event_t *event) { - static int i = 0; +static bool parse_options(int argc, char **argv) { + int result; + int option_index = 0; + + while((result = getopt_long(argc, argv, "c:DLd::k::n:", long_options, &option_index)) != EOF) { + switch (result) { + case 0: + break; + + case 'c': /* --config */ + confbase = xstrdup(optarg); + break; + + case 'D': /* --no-detach */ + do_detach = false; + break; + + case 'L': /* --mlock */ + do_mlock = true; + break; + + case 'd': /* --debug */ + if(optarg) + debug_level = atoi(optarg); + else + debug_level++; + break; + + case 'k': /* --kill */ +#ifndef HAVE_MINGW + if(optarg) { + if(!strcasecmp(optarg, "HUP")) + kill_tincd = SIGHUP; + else if(!strcasecmp(optarg, "TERM")) + kill_tincd = SIGTERM; + else if(!strcasecmp(optarg, "KILL")) + kill_tincd = SIGKILL; + else if(!strcasecmp(optarg, "USR1")) + kill_tincd = SIGUSR1; + else if(!strcasecmp(optarg, "USR2")) + kill_tincd = SIGUSR2; + else if(!strcasecmp(optarg, "WINCH")) + kill_tincd = SIGWINCH; + else if(!strcasecmp(optarg, "INT")) + kill_tincd = SIGINT; + else if(!strcasecmp(optarg, "ALRM")) + kill_tincd = SIGALRM; + else { + kill_tincd = atoi(optarg); - logger(LOG_DEBUG, "i = %d", i++); + if(!kill_tincd) { + fprintf(stderr, _("Invalid argument `%s'; SIGNAL must be a number or one of HUP, TERM, KILL, USR1, USR2, WINCH, INT or ALRM.\n"), + optarg); + usage(true); + return false; + } + } + } else + kill_tincd = SIGTERM; +#else + kill_tincd = 1; +#endif + break; - if(i > 5) { - fd_stop(); - return false; + case 'n': /* --net */ + netname = xstrdup(optarg); + break; + + case 1: /* --help */ + show_help = true; + break; + + case 2: /* --version */ + show_version = true; + break; + + case 3: /* --bypass-security */ + bypass_security = true; + break; + + case 4: /* --logfile */ + use_logfile = true; + if(optarg) + logfilename = xstrdup(optarg); + break; + + case 5: /* --pidfile */ + pidfilename = xstrdup(optarg); + break; + + case '?': + usage(true); + return false; + + default: + break; + } } - event_update(event, event->interval); return true; } -int test(int argc, char **argv) { - vnd_t *vnd; - event_t *stop; - tnl_listen_t *listener; - - //vnd_init(); - if(fd_init() && tnl_init()) { - vnd = vnd_new(); - vnd_set(vnd, "/dev/tun", "test", VND_MODE_TUN, vnd_recv); - - stop = event_new(); - event_set(stop, (struct timeval){5, 0}, vnd_stop, NULL); - event_add(stop); - - clear(new(listener)); - listener->type = SOCK_STREAM; - listener->protocol = IPPROTO_TCP; - sa(&listener->local.address)->sa_family = AF_INET; - - if(tnl_listen(listener) && vnd_open(vnd)) { - fd_run(); - vnd_close(vnd); - listener->close(listener); +static void make_names(void) +{ +#ifdef HAVE_MINGW + HKEY key; + char installdir[1024] = ""; + long len = sizeof(installdir); +#endif + + 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 + + if(!pidfilename) + asprintf(&pidfilename, LOCALSTATEDIR "/run/%s.pid", identname); - vnd_free(vnd); + if(!logfilename) + asprintf(&logfilename, LOCALSTATEDIR "/log/%s.log", identname); - tnl_exit(); - fd_exit(); + if(!confbase) { + if(netname) + asprintf(&confbase, CONFDIR "/tinc/%s", netname); + else + asprintf(&confbase, CONFDIR "/tinc"); } - //vnd_exit(); -} -avl_tree_t *tinc_cfg = NULL; -char *tinc_netname = NULL; + asprintf(&cfgfilename, "%s/tinc.conf", confbase); +} int main(int argc, char **argv) { - tnl_listen_t *listener; + tinc_argc = argc; + tinc_argv = argv; - logger_init("tinc", LOGGER_MODE_STDERR); + 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-2004 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; + } + + if(show_help) { + usage(false); + return 0; + } + + if(kill_tincd) + return !kill_other(kill_tincd); + + openlogger("tinc", use_logfile?LOGMODE_FILE:LOGMODE_STDERR); + + /* Lock all pages into memory if requested */ + + 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; + } + tinc_cfg = cfg_tree_new(); + + asprintf(cfgfilename, "%s/tinc.conf", confbase); - if(!cfg_read_file(tinc_cfg, "tinc.conf")) + if(!cfg_read_file(tinc_cfg, cfgfilename)) return 1; - if(fd_init() && tnl_init()) { - clear(new(listener)); - listener->type = SOCK_STREAM; - listener->protocol = IPPROTO_TCP; - sa(&listener->local.address)->sa_family = AF_INET; - ((struct sockaddr_in *) &listener->local.address)->sin_port = htons(655); - if(tnl_listen(listener)) { - fd_run(); - listener->close(listener); - } - tnl_exit() && fd_exit(); +#ifdef HAVE_MINGW + if(WSAStartup(MAKEWORD(2, 2), &wsa_state)) { + logger(LOG_ERR, _("System call `%s' failed: %s"), "WSAStartup", winerror(GetLastError())); + return 1; } +#endif + if(do_detach && !detach()) + return 1; + + if(!fd_init() || !tnl_init() || !rt_init()) + return 1; + + fd_run(); + + rt_exit(); + tnl_exit(); + fd_exit(); +end: + logger(LOG_NOTICE, _("Terminating")); + +#ifndef HAVE_MINGW + remove_pid(pidfilename); +#endif + + logger_exit(); + return 0; } - diff --git a/tnl/tnl.c b/tnl/tnl.c index 5a767f5..113248f 100644 --- a/tnl/tnl.c +++ b/tnl/tnl.c @@ -139,7 +139,65 @@ static bool tnl_recv_handler(fd_t *fd) { return tnl_recv(tnl); } +static bool tnl_authenticate(tnl_t *tnl) { + gnutls_x509_crt cert; + const gnutls_datum *certs; + int ncerts = 0, result; + char buf[1024], *name, *p; + int len; + + certs = gnutls_certificate_get_peers(tnl->session, &ncerts); + + if (!certs || !ncerts) { + logger(LOG_ERR, _("tnl: no certificates from %s"), tnl->remote.hostname); + return false; + } + + len = sizeof buf; + gnutls_x509_crt_init(&cert); + result = gnutls_x509_crt_import(cert, certs, GNUTLS_X509_FMT_DER) ?: gnutls_x509_crt_get_dn(cert, buf, &len); + + if(result) { + logger(LOG_ERR, _("tnl: error importing certificate from %s: %s"), tnl->remote.hostname, gnutls_strerror(errno)); + gnutls_x509_crt_deinit(cert); + return false; + } + + name = strstr(buf, "CN="); + if(!name) { + logger(LOG_ERR, _("tnl: no name in certificate from %s"), tnl->remote.hostname); + gnutls_x509_crt_deinit(cert); + return false; + } + + name += 3; + for(p = name; *p && *p != ','; p++); + *p = '\0'; + + if(tnl->remote.id && strcmp(tnl->remote.id, name)) { + logger(LOG_ERR, _("tnl: peer %s is %s instead of %s"), tnl->remote.hostname, name, tnl->remote.id); + return false; + } + + replace(tnl->remote.id, name); + + result = gnutls_certificate_verify_peers(tnl->session); + + if(result < 0) { + logger(LOG_ERR, "tnl: error verifying certificate from %s (%s): %s\n", tnl->remote.id, tnl->remote.hostname, gnutls_strerror(result)); + return false; + } + + if(result) { + logger(LOG_ERR, "tnl: certificate from %s (%s) not good, verification result %x", tnl->remote.id, tnl->remote.hostname, result); + return false; + } +} + + + static bool tnl_handshake_handler(fd_t *fd) { + char id[1024]; tnl_t *tnl = fd->data; int result; @@ -157,21 +215,11 @@ static bool tnl_handshake_handler(fd_t *fd) { logger(LOG_DEBUG, _("tnl: handshake finished")); - result = gnutls_certificate_verify_peers(tnl->session); - if(result < 0) { - logger(LOG_ERR, "tnl: certificate error: %s\n", gnutls_strerror(result)); - tnl->close(tnl); - return false; - } - - if(result) { - logger(LOG_ERR, "tnl: certificate not good, verification result %x", result); - tnl->close(tnl); + if(!tnl_authenticate(tnl)) return false; - } tnl->status == TNL_STATUS_UP; - tnl->fd.handler = tnl_recv_handler; + tnl->fd.read = tnl_recv_handler; tnl->accept(tnl); return true; } @@ -231,7 +279,7 @@ static bool tnl_accept_handler(fd_t *fd) { sa_unmap(&ss); - new(tnl); + clear(new(tnl)); tnl->local = listener->local; tnl->remote.address = ss; len = sizeof tnl->local.address; @@ -244,8 +292,7 @@ static bool tnl_accept_handler(fd_t *fd) { tnl->close = tnl_close; tnl->fd.fd = sock; - tnl->fd.mode = FD_MODE_READ; - tnl->fd.handler = tnl_handshake_handler; + tnl->fd.read = tnl_handshake_handler; tnl->fd.data = tnl; fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK); @@ -281,8 +328,6 @@ static bool tnl_connect_handler(fd_t *fd) { return false; } - fd_del(&tnl->fd); - fcntl(tnl->fd.fd, F_SETFL, fcntl(tnl->fd.fd, F_GETFL) | O_NONBLOCK); tnl->status = TNL_STATUS_HANDSHAKE; @@ -294,9 +339,9 @@ static bool tnl_connect_handler(fd_t *fd) { gnutls_transport_set_ptr(tnl->session, (gnutls_transport_ptr)fd->fd); gnutls_handshake(tnl->session); - tnl->fd.mode = FD_MODE_READ; - tnl->fd.handler = tnl_handshake_handler; - fd_add(&tnl->fd); + tnl->fd.write = NULL; + tnl->fd.read = tnl_handshake_handler; + fd_mod(&tnl->fd); logger(LOG_DEBUG, _("tnl: connected")); @@ -330,8 +375,7 @@ bool tnl_connect(tnl_t *tnl) { tnl->status = TNL_STATUS_CONNECTING; tnl->fd.fd = sock; - tnl->fd.mode = FD_MODE_WRITE; - tnl->fd.handler = tnl_connect_handler; + tnl->fd.write = tnl_connect_handler; tnl->fd.data = tnl; tnl->send_packet = tnl_send_packet; @@ -340,7 +384,6 @@ bool tnl_connect(tnl_t *tnl) { tnl_add(tnl); - fd_add(&tnl->fd); return true; @@ -374,8 +417,7 @@ bool tnl_listen(tnl_listen_t *listener) { } listener->fd.fd = sock; - listener->fd.mode = FD_MODE_READ; - listener->fd.handler = tnl_accept_handler; + listener->fd.read = tnl_accept_handler; listener->fd.data = listener; listener->close = tnl_listen_close; diff --git a/tnl/tnl.h b/tnl/tnl.h index 9f1f836..14356be 100644 --- a/tnl/tnl.h +++ b/tnl/tnl.h @@ -47,7 +47,8 @@ typedef enum tnl_status { typedef struct tnl_ep { struct sockaddr_storage address; - struct tnl_ep_identity *id; + char *id; + char *hostname; struct tnl_ep_credentials *cred; struct tnl_ep_cryptoparm *parm; } tnl_ep_t; diff --git a/vnd/vnd.c b/vnd/vnd.c index 538dcb8..802cdd6 100644 --- a/vnd/vnd.c +++ b/vnd/vnd.c @@ -122,8 +122,7 @@ bool vnd_open(vnd_t *vnd) { vnd->mtu = 1514; vnd->send = vnd_send; - vnd->fd.mode = FD_MODE_READ; - vnd->fd.handler = vnd_recv_handler; + vnd->fd.read = vnd_recv_handler; vnd->fd.data = vnd; if(vnd->description) -- 2.25.1