Allow connections via UNIX sockets.
authorGuus Sliepen <guus@tinc-vpn.org>
Thu, 17 Jan 2013 17:12:55 +0000 (18:12 +0100)
committerGuus Sliepen <guus@tinc-vpn.org>
Thu, 17 Jan 2013 17:12:55 +0000 (18:12 +0100)
This is mainly useful for control connections. The client must still present
the control cookie from the PID file.

src/names.c
src/names.h
src/net.h
src/net_setup.c
src/net_socket.c
src/tincctl.c

index 5a5270a..1fb0a8f 100644 (file)
@@ -27,6 +27,7 @@ char *netname = NULL;
 char *confdir = NULL;           /* base configuration directory */
 char *confbase = NULL;          /* base configuration directory for this instance of tinc */
 char *identname = NULL;         /* program name for syslog */
+char *unixsocketname = NULL;    /* UNIX socket location */
 char *logfilename = NULL;       /* log file location */
 char *pidfilename = NULL;
 char *program_name = NULL;
@@ -73,6 +74,9 @@ void make_names(void) {
        if(!pidfilename)
                xasprintf(&pidfilename, LOCALSTATEDIR SLASH "run" SLASH "%s.pid", identname);
 
+       if(!unixsocketname)
+               xasprintf(&unixsocketname, LOCALSTATEDIR SLASH "run" SLASH "%s.socket", identname);
+
        if(netname) {
                if(!confbase)
                        xasprintf(&confbase, CONFDIR SLASH "tinc" SLASH "%s", netname);
@@ -87,6 +91,7 @@ void make_names(void) {
 void free_names(void) {
        free(identname);
        free(netname);
+       free(unixsocketname);
        free(pidfilename);
        free(logfilename);
        free(confbase);
index aef8b45..6f43a2c 100644 (file)
@@ -25,6 +25,7 @@ extern char *confdir;
 extern char *confbase;
 extern char *netname;
 extern char *identname;
+extern char *unixsocketname;
 extern char *logfilename;
 extern char *pidfilename;
 extern char *program_name;
index 4277279..0165d1e 100644 (file)
--- a/src/net.h
+++ b/src/net.h
@@ -128,6 +128,7 @@ extern bool localdiscovery;
 
 extern listen_socket_t listen_socket[MAXSOCKETS];
 extern int listen_sockets;
+extern io_t unix_socket;
 extern int keylifetime;
 extern int udp_rcvbuf;
 extern int udp_sndbuf;
@@ -164,6 +165,7 @@ extern void handle_incoming_vpn_data(void *, int);
 extern void finish_connecting(struct connection_t *);
 extern bool do_outgoing_connection(struct outgoing_t *);
 extern void handle_new_meta_connection(void *, int);
+extern void handle_new_unix_connection(void *, int);
 extern int setup_listen_socket(const sockaddr_t *);
 extern int setup_vpn_in_socket(const sockaddr_t *);
 extern bool send_sptps_data(void *handle, uint8_t type, const char *data, size_t len);
index 0e424ee..15f9f84 100644 (file)
@@ -808,6 +808,37 @@ static bool setup_myself(void) {
 
        /* Open sockets */
 
+#ifndef HAVE_MINGW
+       int unix_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+       if(unix_fd < 0) {
+               logger(DEBUG_ALWAYS, LOG_ERR, "Could not create UNIX socket: %s", sockstrerror(errno));
+               return false;
+       }
+
+       struct sockaddr_un sa;
+       sa.sun_family = AF_UNIX;
+       strncpy(sa.sun_path, unixsocketname, sizeof sa.sun_path);
+
+       if(connect(unix_fd, (struct sockaddr *)&sa, sizeof sa) >= 0) {
+               logger(DEBUG_ALWAYS, LOG_ERR, "UNIX socket %s is still in use!", unixsocketname);
+               return false;
+       }
+
+       unlink(unixsocketname);
+
+       if(bind(unix_fd, (struct sockaddr *)&sa, sizeof sa) < 0) {
+               logger(DEBUG_ALWAYS, LOG_ERR, "Could not bind UNIX socket to %s: %s", unixsocketname, sockstrerror(errno));
+               return false;
+       }
+
+       if(listen(unix_fd, 3) < 0) {
+               logger(DEBUG_ALWAYS, LOG_ERR, "Could not listen on UNIX socket %s: %s", unixsocketname, sockstrerror(errno));
+               return false;
+       }
+
+       io_add(&unix_socket, handle_new_unix_connection, &unix_socket, unix_fd, IO_READ);
+#endif
+
        if(!do_detach && getenv("LISTEN_FDS")) {
                sockaddr_t sa;
                socklen_t salen;
@@ -992,6 +1023,11 @@ void close_network_connections(void) {
                close(listen_socket[i].udp.fd);
        }
 
+#ifndef HAVE_MINGW
+       io_del(&unix_socket);
+       close(unix_socket.fd);
+#endif
+
        char *envp[5];
        xasprintf(&envp[0], "NETNAME=%s", netname ? : "");
        xasprintf(&envp[1], "DEVICE=%s", device ? : "");
index 051955b..49408bd 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "conf.h"
 #include "connection.h"
+#include "control_common.h"
 #include "list.h"
 #include "logger.h"
 #include "meta.h"
@@ -47,6 +48,9 @@ int udp_sndbuf = 0;
 
 listen_socket_t listen_socket[MAXSOCKETS];
 int listen_sockets;
+#ifndef HAVE_MINGW
+io_t unix_socket;
+#endif
 list_t *outgoing_list = NULL;
 
 /* Setup sockets */
@@ -562,6 +566,45 @@ void handle_new_meta_connection(void *data, int flags) {
        send_id(c);
 }
 
+#ifndef HAVE_MINGW
+/*
+  accept a new UNIX socket connection
+*/
+void handle_new_unix_connection(void *data, int flags) {
+       io_t *io = data;
+       connection_t *c;
+       sockaddr_t sa;
+       int fd;
+       socklen_t len = sizeof sa;
+
+       fd = accept(io->fd, &sa.sa, &len);
+
+       if(fd < 0) {
+               logger(DEBUG_ALWAYS, LOG_ERR, "Accepting a new connection failed: %s", sockstrerror(sockerrno));
+               return;
+       }
+
+       sockaddrunmap(&sa);
+
+       c = new_connection();
+       c->name = xstrdup("<control>");
+       c->address = sa;
+       c->hostname = xstrdup("localhost port unix");
+       c->socket = fd;
+       c->last_ping_time = time(NULL);
+
+       logger(DEBUG_CONNECTIONS, LOG_NOTICE, "Connection from %s", c->hostname);
+
+       io_add(&c->io, handle_meta_io, c, c->socket, IO_READ);
+
+       connection_add(c);
+
+       c->allow_request = ID;
+
+       send_id(c);
+}
+#endif
+
 static void free_outgoing(outgoing_t *outgoing) {
        timeout_del(&outgoing->ev);
 
index 1576ba8..afaeda3 100644 (file)
@@ -666,6 +666,26 @@ static bool connect_tincd(bool verbose) {
        }
 #endif
 
+#ifndef HAVE_MINGW
+       struct sockaddr_un sa;
+       sa.sun_family = AF_UNIX;
+       strncpy(sa.sun_path, unixsocketname, sizeof sa.sun_path);
+
+       fd = socket(AF_UNIX, SOCK_STREAM, 0);
+       if(fd < 0) {
+               if(verbose)
+                       fprintf(stderr, "Cannot create UNIX socket: %s\n", sockstrerror(sockerrno));
+               return false;
+       }
+
+       if(connect(fd, (struct sockaddr *)&sa, sizeof sa) < 0) {
+               if(verbose)
+                       fprintf(stderr, "Cannot connect to UNIX socket %s: %s\n", unixsocketname, sockstrerror(sockerrno));
+               close(fd);
+               fd = -1;
+               return false;
+       }
+#else
        struct addrinfo hints = {
                .ai_family = AF_UNSPEC,
                .ai_socktype = SOCK_STREAM,
@@ -706,6 +726,7 @@ static bool connect_tincd(bool verbose) {
        }
 
        freeaddrinfo(res);
+#endif
 
        char data[4096];
        int version;