From 94587264bda45cce0295aaa37b59905d4b9843a8 Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Thu, 17 Jan 2013 18:12:55 +0100 Subject: [PATCH] Allow connections via UNIX sockets. This is mainly useful for control connections. The client must still present the control cookie from the PID file. --- src/names.c | 5 +++++ src/names.h | 1 + src/net.h | 2 ++ src/net_setup.c | 36 ++++++++++++++++++++++++++++++++++++ src/net_socket.c | 43 +++++++++++++++++++++++++++++++++++++++++++ src/tincctl.c | 21 +++++++++++++++++++++ 6 files changed, 108 insertions(+) diff --git a/src/names.c b/src/names.c index 5a5270a9..1fb0a8f2 100644 --- a/src/names.c +++ b/src/names.c @@ -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); diff --git a/src/names.h b/src/names.h index aef8b45a..6f43a2c8 100644 --- a/src/names.h +++ b/src/names.h @@ -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; diff --git a/src/net.h b/src/net.h index 4277279a..0165d1e0 100644 --- 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); diff --git a/src/net_setup.c b/src/net_setup.c index 0e424eef..15f9f84b 100644 --- a/src/net_setup.c +++ b/src/net_setup.c @@ -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 ? : ""); diff --git a/src/net_socket.c b/src/net_socket.c index 051955bf..49408bd9 100644 --- a/src/net_socket.c +++ b/src/net_socket.c @@ -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(""); + 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); diff --git a/src/tincctl.c b/src/tincctl.c index 1576ba86..afaeda32 100644 --- a/src/tincctl.c +++ b/src/tincctl.c @@ -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;