From d6b3bc69483e6e49961d2cae52d0d0adf219c88b Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Fri, 22 Jul 2016 21:07:12 +0200 Subject: [PATCH] wg: use stream instead of seqpacket To support OS X and Windows, we have to. Ugh. Signed-off-by: Jason A. Donenfeld --- src/ipc.c | 49 +++++++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/src/ipc.c b/src/ipc.c index c4d1128..4203448 100644 --- a/src/ipc.c +++ b/src/ipc.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -99,7 +100,7 @@ static int userspace_interface_fd(const char *interface) if (!S_ISSOCK(sbuf.st_mode)) goto out; - ret = fd = socket(AF_UNIX, SOCK_SEQPACKET, 0); + ret = fd = socket(AF_UNIX, SOCK_STREAM, 0); if (ret < 0) goto out; @@ -172,10 +173,10 @@ static int userspace_set_device(struct wgdevice *dev) ret = -EBADMSG; if (!len) goto out; - ret = send(fd, dev, len, 0); + ret = write(fd, dev, len); if (ret < 0) goto out; - ret = recv(fd, &ret_code, sizeof(ret_code), 0); + ret = read(fd, &ret_code, sizeof(ret_code)); if (ret < 0) goto out; ret = ret_code; @@ -187,50 +188,62 @@ out: static int userspace_get_device(struct wgdevice **dev, const char *interface) { -#ifdef __linux__ - ssize_t len; -#else + struct pollfd pollfd = { .events = POLLIN }; int len; -#endif + char byte = 0; + size_t i; + struct wgpeer *peer; ssize_t ret; int fd = userspace_interface_fd(interface); if (fd < 0) return fd; *dev = NULL; - ret = send(fd, NULL, 0, 0); + ret = write(fd, &byte, sizeof(byte)); if (ret < 0) goto out; -#ifdef __linux__ - ret = len = recv(fd, NULL, 0, MSG_PEEK | MSG_TRUNC); - if (len < 0) + pollfd.fd = fd; + if (poll(&pollfd, 1, -1) < 0) goto out; -#else - ret = recv(fd, &ret, 1, MSG_PEEK); - if (ret < 0) + ret = -ECONNABORTED; + if (!(pollfd.revents & POLLIN)) goto out; + ret = ioctl(fd, FIONREAD, &len); if (ret < 0) { ret = -errno; goto out; } -#endif ret = -EBADMSG; if ((size_t)len < sizeof(struct wgdevice)) goto out; ret = -ENOMEM; - *dev = calloc(len, 1); + *dev = malloc(len); if (!*dev) goto out; - ret = recv(fd, *dev, len, 0); + ret = read(fd, *dev, len); if (ret < 0) goto out; + if (ret != len) { + ret = -EBADMSG; + goto out; + } + + ret = -EBADMSG; + for_each_wgpeer(*dev, peer, i) { + if ((uint8_t *)peer + sizeof(struct wgpeer) > (uint8_t *)*dev + len) + goto out; + if ((uint8_t *)peer + sizeof(struct wgpeer) + sizeof(struct wgipmask) * peer->num_ipmasks > (uint8_t *)*dev + len) + goto out; + } ret = 0; out: - if (*dev && ret) + if (*dev && ret) { free(*dev); + *dev = NULL; + } close(fd); errno = -ret; return ret;