wg: support horrible freebsd/osx/unix semantics
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
parent
b16641e30c
commit
9889b42788
1 changed files with 66 additions and 1 deletions
67
src/kernel.c
67
src/kernel.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue