Allow connections via UNIX sockets.

This is mainly useful for control connections. The client must still present
the control cookie from the PID file.
This commit is contained in:
Guus Sliepen 2013-01-17 18:12:55 +01:00
parent 2c14123062
commit 94587264bd
6 changed files with 108 additions and 0 deletions

View 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);

View 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;

View file

@ -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);

View 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 ? : "");

View 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);

View 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;