Some random changes.
authorGuus Sliepen <guus@tinc-vpn.org>
Wed, 24 Mar 2004 14:56:04 +0000 (14:56 +0000)
committerGuus Sliepen <guus@tinc-vpn.org>
Wed, 24 Mar 2004 14:56:04 +0000 (14:56 +0000)
fd/fd.c
tincd.c
tnl/tnl.c
tnl/tnl.h
vnd/vnd.c

diff --git a/fd/fd.c b/fd/fd.c
index b969205..ad4a8ca 100644 (file)
--- 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 (file)
--- a/tincd.c
+++ b/tincd.c
@@ -22,6 +22,8 @@
 
 #include "system.h"
 
+#include <getopt.h>
+
 #include "cfg/cfg.h"
 #include "fd/event.h"
 #include "fd/fd.h"
 #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;
 }
-
index 5a767f5..113248f 100644 (file)
--- 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;
 
index 9f1f836..14356be 100644 (file)
--- 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;
index 538dcb8..802cdd6 100644 (file)
--- 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)