aboutsummaryrefslogtreecommitdiff
path: root/contrib/wireguard-tools/ipc-uapi-unix.h
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/wireguard-tools/ipc-uapi-unix.h')
-rw-r--r--contrib/wireguard-tools/ipc-uapi-unix.h119
1 files changed, 119 insertions, 0 deletions
diff --git a/contrib/wireguard-tools/ipc-uapi-unix.h b/contrib/wireguard-tools/ipc-uapi-unix.h
new file mode 100644
index 000000000000..aaf60ca69af9
--- /dev/null
+++ b/contrib/wireguard-tools/ipc-uapi-unix.h
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (C) 2015-2020 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
+ */
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+
+#define SOCK_PATH RUNSTATEDIR "/wireguard/"
+#define SOCK_SUFFIX ".sock"
+
+static FILE *userspace_interface_file(const char *iface)
+{
+ struct stat sbuf;
+ struct sockaddr_un addr = { .sun_family = AF_UNIX };
+ int fd = -1, ret;
+ FILE *f = NULL;
+
+ errno = EINVAL;
+ if (strchr(iface, '/'))
+ goto out;
+ ret = snprintf(addr.sun_path, sizeof(addr.sun_path), SOCK_PATH "%s" SOCK_SUFFIX, iface);
+ if (ret < 0)
+ goto out;
+ ret = stat(addr.sun_path, &sbuf);
+ if (ret < 0)
+ goto out;
+ errno = EBADF;
+ if (!S_ISSOCK(sbuf.st_mode))
+ goto out;
+
+ ret = fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (ret < 0)
+ goto out;
+
+ ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
+ if (ret < 0) {
+ if (errno == ECONNREFUSED) /* If the process is gone, we try to clean up the socket. */
+ unlink(addr.sun_path);
+ goto out;
+ }
+ f = fdopen(fd, "r+");
+ if (f)
+ errno = 0;
+out:
+ ret = -errno;
+ if (ret) {
+ if (fd >= 0)
+ close(fd);
+ errno = -ret;
+ return NULL;
+ }
+ return f;
+}
+
+static bool userspace_has_wireguard_interface(const char *iface)
+{
+ struct stat sbuf;
+ struct sockaddr_un addr = { .sun_family = AF_UNIX };
+ int fd, ret;
+
+ if (strchr(iface, '/'))
+ return false;
+ if (snprintf(addr.sun_path, sizeof(addr.sun_path), SOCK_PATH "%s" SOCK_SUFFIX, iface) < 0)
+ return false;
+ if (stat(addr.sun_path, &sbuf) < 0)
+ return false;
+ if (!S_ISSOCK(sbuf.st_mode))
+ return false;
+ ret = fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (ret < 0)
+ return false;
+ ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr));
+ if (ret < 0 && errno == ECONNREFUSED) { /* If the process is gone, we try to clean up the socket. */
+ close(fd);
+ unlink(addr.sun_path);
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+static int userspace_get_wireguard_interfaces(struct string_list *list)
+{
+ DIR *dir;
+ struct dirent *ent;
+ size_t len;
+ char *end;
+ int ret = 0;
+
+ dir = opendir(SOCK_PATH);
+ if (!dir)
+ return errno == ENOENT ? 0 : -errno;
+ while ((ent = readdir(dir))) {
+ len = strlen(ent->d_name);
+ if (len <= strlen(SOCK_SUFFIX))
+ continue;
+ end = &ent->d_name[len - strlen(SOCK_SUFFIX)];
+ if (strncmp(end, SOCK_SUFFIX, strlen(SOCK_SUFFIX)))
+ continue;
+ *end = '\0';
+ if (!userspace_has_wireguard_interface(ent->d_name))
+ continue;
+ ret = string_list_add(list, ent->d_name);
+ if (ret < 0)
+ goto out;
+ }
+out:
+ closedir(dir);
+ return ret;
+}