wg: support horrible freebsd/osx/unix semantics

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
Jason A. Donenfeld 2016-07-20 20:52:11 +02:00
parent b16641e30c
commit 9889b42788

View file

@ -80,14 +80,40 @@ static int add_next_to_inflatable_buffer(struct inflatable_buffer *buffer)
return 0; return 0;
} }
#ifndef __linux__
static void close_and_unlink(int fd)
{
struct sockaddr_un addr;
socklen_t len = sizeof(addr);
if (!getsockname(fd, (struct sockaddr *)&addr, &len))
unlink(addr.sun_path);
close(fd);
}
#endif
static int userspace_interface_fd(const char *interface) static int userspace_interface_fd(const char *interface)
{ {
struct stat sbuf; struct stat sbuf;
struct sockaddr_un addr = { .sun_family = AF_UNIX }; struct sockaddr_un addr = { .sun_family = AF_UNIX };
#ifndef __linux__
struct sockaddr_un bind_addr = { .sun_family = AF_UNIX };
mode_t old_umask;
#endif
int fd = -1, ret; int fd = -1, ret;
ret = -EINVAL;
if (strchr(interface, '/'))
goto out;
ret = snprintf(addr.sun_path, sizeof(addr.sun_path) - 1, SOCK_PATH "%s" SOCK_SUFFIX, interface); ret = snprintf(addr.sun_path, sizeof(addr.sun_path) - 1, SOCK_PATH "%s" SOCK_SUFFIX, interface);
if (ret < 0) if (ret < 0)
goto out; goto out;
#ifndef __linux__
ret = snprintf(bind_addr.sun_path, sizeof(bind_addr.sun_path) - 1, SOCK_PATH ".wg-tool-%s-%d.client", interface, getpid());
if (ret < 0)
goto out;
unlink(bind_addr.sun_path);
#endif
ret = stat(addr.sun_path, &sbuf); ret = stat(addr.sun_path, &sbuf);
if (ret < 0) if (ret < 0)
goto out; goto out;
@ -98,9 +124,16 @@ static int userspace_interface_fd(const char *interface)
ret = fd = socket(AF_UNIX, SOCK_DGRAM, 0); ret = fd = socket(AF_UNIX, SOCK_DGRAM, 0);
if (ret < 0) if (ret < 0)
goto out; goto out;
#ifdef __linux__
ret = bind(fd, (struct sockaddr *)&addr, sizeof(sa_family_t)); ret = bind(fd, (struct sockaddr *)&addr, sizeof(sa_family_t));
#else
old_umask = umask(0077);
ret = bind(fd, (struct sockaddr *)&bind_addr, sizeof(bind_addr));
umask(old_umask);
#endif
if (ret < 0) if (ret < 0)
goto out; goto out;
ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr)); ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
if (ret < 0) { if (ret < 0) {
if (errno == ECONNREFUSED) /* If the process is gone, we try to clean up the socket. */ if (errno == ECONNREFUSED) /* If the process is gone, we try to clean up the socket. */
@ -109,7 +142,11 @@ static int userspace_interface_fd(const char *interface)
} }
out: out:
if (ret && fd >= 0) if (ret && fd >= 0)
#ifdef __linux__
close(fd); close(fd);
#else
close_and_unlink(fd);
#endif
if (!ret) if (!ret)
ret = fd; ret = fd;
return ret; return ret;
@ -120,7 +157,11 @@ static bool userspace_has_wireguard_interface(const char *interface)
int fd = userspace_interface_fd(interface); int fd = userspace_interface_fd(interface);
if (fd < 0) if (fd < 0)
return false; return false;
#ifdef __linux__
close(fd); close(fd);
#else
close_and_unlink(fd);
#endif
return true; return true;
} }
@ -178,14 +219,23 @@ static int userspace_set_device(struct wgdevice *dev)
goto out; goto out;
ret = ret_code; ret = ret_code;
out: out:
#ifdef __linux__
close(fd); close(fd);
#else
close_and_unlink(fd);
#endif
return (int)ret; return (int)ret;
} }
static int userspace_get_device(struct wgdevice **dev, const char *interface) static int userspace_get_device(struct wgdevice **dev, const char *interface)
{ {
#ifdef __linux__
ssize_t len; ssize_t len;
int ret, fd = userspace_interface_fd(interface); #else
int len;
#endif
ssize_t ret;
int fd = userspace_interface_fd(interface);
if (fd < 0) if (fd < 0)
return fd; return fd;
*dev = NULL; *dev = NULL;
@ -193,9 +243,20 @@ static int userspace_get_device(struct wgdevice **dev, const char *interface)
if (ret < 0) if (ret < 0)
goto out; goto out;
#ifdef __linux__
ret = len = recv(fd, NULL, 0, MSG_PEEK | MSG_TRUNC); ret = len = recv(fd, NULL, 0, MSG_PEEK | MSG_TRUNC);
if (len < 0) if (len < 0)
goto out; goto out;
#else
ret = recv(fd, &ret, 1, MSG_PEEK);
if (ret < 0)
goto out;
ret = ioctl(fd, FIONREAD, &len);
if (ret < 0) {
ret = -errno;
goto out;
}
#endif
ret = -EBADMSG; ret = -EBADMSG;
if ((size_t)len < sizeof(struct wgdevice)) if ((size_t)len < sizeof(struct wgdevice))
goto out; goto out;
@ -212,7 +273,11 @@ static int userspace_get_device(struct wgdevice **dev, const char *interface)
out: out:
if (*dev && ret) if (*dev && ret)
free(*dev); free(*dev);
#ifdef __linux__
close(fd); close(fd);
#else
close_and_unlink(fd);
#endif
errno = -ret; errno = -ret;
return ret; return ret;
} }