Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F112053570
D42880.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
D42880.diff
View Options
diff --git a/lib/libifconfig/Makefile b/lib/libifconfig/Makefile
--- a/lib/libifconfig/Makefile
+++ b/lib/libifconfig/Makefile
@@ -19,7 +19,8 @@
libifconfig_internal.c \
libifconfig_lagg.c \
libifconfig_media.c \
- libifconfig_sfp.c
+ libifconfig_sfp.c \
+ libifconfig_wg.c
GEN= libifconfig_sfp_tables.h \
libifconfig_sfp_tables.c \
diff --git a/lib/libifconfig/libifconfig.h b/lib/libifconfig/libifconfig.h
--- a/lib/libifconfig/libifconfig.h
+++ b/lib/libifconfig/libifconfig.h
@@ -27,6 +27,7 @@
#pragma once
#include <sys/types.h>
+#include <sys/queue.h>
#include <net/if.h>
@@ -289,6 +290,40 @@
struct in6_addr carpr_addr6;
};
+#define WG_KEY_LEN 32
+
+struct ifconfig_wg_allowed_ip {
+ uint16_t family;
+ union {
+ struct in_addr ip4;
+ struct in_addr ip6;
+ };
+ uint8_t cidr;
+ STAILQ_ENTRY(ifconfig_wg_allowed_ip) next;
+};
+
+struct ifconfig_wg_peer {
+ uint8_t public_key[WG_KEY_LEN];
+ uint8_t preshared_key[WG_KEY_LEN];
+
+ union {
+ struct sockaddr addr;
+ struct sockaddr_in addr4;
+ struct sockaddr_in6 addr6;
+ } endpoint;
+
+ struct timespec last_handshake_time;
+ uint16_t persistent_keepalive_interval;
+ STAILQ_HEAD(, ifconfig_wg_allowed_ip) allowed_ips;
+ STAILQ_ENTRY(ifconfig_wg_peer) next;
+};
+
+struct ifconfig_wg {
+ uint8_t public_key[WG_KEY_LEN];
+ uint16_t listen_port;
+ STAILQ_HEAD(, ifconfig_wg_peer) peers;
+};
+
int ifconfig_carp_get_vhid(ifconfig_handle_t *h, const char *name,
struct ifconfig_carp *carpr, uint32_t vhid);
int ifconfig_carp_get_info(ifconfig_handle_t *h, const char *name,
@@ -375,3 +410,7 @@
* length of *lenp * IFNAMSIZ bytes.
*/
int ifconfig_list_cloners(ifconfig_handle_t *h, char **bufp, size_t *lenp);
+
+int ifconfig_wg_get_info(ifconfig_handle_t *h, const char *name,
+ struct ifconfig_wg *wgr);
+void ifconfig_wg_free(struct ifconfig_wg *dev);
diff --git a/lib/libifconfig/libifconfig_wg.c b/lib/libifconfig/libifconfig_wg.c
new file mode 100644
--- /dev/null
+++ b/lib/libifconfig/libifconfig_wg.c
@@ -0,0 +1,204 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright (C) 2015-2021 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
+ * Copyright (C) 2023 Baptiste Daroussin <bapt@FreeBSD.org>.
+ *
+ */
+
+#include <sys/nv.h>
+#include <sys/ioctl.h>
+#include <sys/queue.h>
+
+#include <libifconfig.h>
+#include <libifconfig_internal.h>
+#include <strings.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+struct wg_data_io {
+ char wgd_name[IFNAMSIZ];
+ void *wgd_data;
+ size_t wgd_size;
+};
+
+#define SIOCSWG _IOWR('i', 210, struct wg_data_io)
+#define SIOCGWG _IOWR('i', 211, struct wg_data_io)
+
+void
+ifconfig_wg_free(struct ifconfig_wg *dev)
+{
+ struct ifconfig_wg_peer *peer, *tpeer;
+ struct ifconfig_wg_allowed_ip *aip, *taip;
+ if (dev == NULL)
+ return;
+ STAILQ_FOREACH_SAFE(peer, &dev->peers, next, tpeer) {
+ STAILQ_FOREACH_SAFE(aip, &peer->allowed_ips, next, taip) {
+ STAILQ_REMOVE(&peer->allowed_ips, aip, ifconfig_wg_allowed_ip, next);
+ free(aip);
+ }
+ STAILQ_REMOVE(&dev->peers, peer, ifconfig_wg_peer, next);
+ free(peer);
+ }
+}
+
+static int
+ifconfig_wg_get_allowed_ips(ifconfig_handle_t *h, const nvlist_t *nvl_peer,
+ struct ifconfig_wg_peer *peer)
+{
+ struct ifconfig_wg_allowed_ip *aip = NULL;
+ const nvlist_t *const *nvl_aips;
+ size_t aip_count, size;
+ const void *binary;
+ uint64_t number;
+
+ if (!nvlist_exists_nvlist_array(nvl_peer, "allowed-ips"))
+ return (0);
+ nvl_aips = nvlist_get_nvlist_array(nvl_peer, "allowed-ips", &aip_count);
+ if (aip_count == 0 || nvl_aips == NULL)
+ return (-1);
+ for (size_t i = 0; i < aip_count; i++) {
+ if (!nvlist_exists_number(nvl_aips[i], "cidr"))
+ continue;
+ if (!nvlist_exists_binary(nvl_aips[i], "ipv4") &&
+ !nvlist_exists_binary(nvl_aips[i], "ipv6"))
+ continue;
+ if ((aip = calloc(1, sizeof(*aip))) == NULL) {
+ h->error.errtype = OTHER;
+ h->error.errcode = ENOMEM;
+ return (-1);
+ }
+ number = nvlist_get_number(nvl_aips[i], "cidr");
+ if (nvlist_exists_binary(nvl_aips[i], "ipv4")) {
+ binary = nvlist_get_binary(nvl_aips[i], "ipv4", &size);
+ if (!binary || number > 32) {
+ h->error.errtype = OTHER;
+ h->error.errcode = EINVAL;
+ free(aip);
+ return (-1);
+ }
+ aip->family = AF_INET;
+ aip->cidr = number;
+ memcpy(&aip->ip4, binary, sizeof(aip->ip4));
+ } else {
+ binary = nvlist_get_binary(nvl_aips[i], "ipv6", &size);
+ if (!binary || number > 128) {
+ h->error.errtype = OTHER;
+ h->error.errcode = EINVAL;
+ free(aip);
+ return (-1);
+ }
+ aip->family = AF_INET6;
+ aip->cidr = number;
+ memcpy(&aip->ip6, binary, sizeof(aip->ip6));
+ }
+ STAILQ_INSERT_TAIL(&peer->allowed_ips, aip, next);
+ }
+ return (0);
+}
+
+static int
+ifconfig_wg_get_peers(ifconfig_handle_t *h, nvlist_t *nvl_device,
+ struct ifconfig_wg *dev)
+{
+ const nvlist_t *const *nvl_peers;
+ size_t size, peer_count;
+ const void *binary;
+ uint64_t number;
+
+ if (!nvlist_exists_nvlist_array(nvl_device, "peers"))
+ return (0);
+ nvl_peers = nvlist_get_nvlist_array(nvl_device, "peers", &peer_count);
+ if (nvl_peers == NULL)
+ return (0);
+ for (size_t i = 0; i < peer_count; ++i) {
+ struct ifconfig_wg_peer *peer = NULL;
+
+ if ((peer = calloc(1, sizeof(*peer))) == NULL) {
+ h->error.errtype = OTHER;
+ h->error.errcode = ENOMEM;
+ return (-1);
+ }
+ STAILQ_INIT(&peer->allowed_ips);
+ if (nvlist_exists_binary(nvl_peers[i], "public-key")) {
+ binary = nvlist_get_binary(nvl_peers[i], "public-key", &size);
+ if (binary && size == sizeof(peer->public_key))
+ memcpy(peer->public_key, binary, sizeof(peer->public_key));
+ }
+ if (nvlist_exists_number(nvl_peers[i], "persistent-keepalive-interval")) {
+ number = nvlist_get_number(nvl_peers[i], "persistent-keepalive-interval");
+ if (number <= UINT16_MAX)
+ peer->persistent_keepalive_interval = number;
+ }
+ if (nvlist_exists_binary(nvl_peers[i], "endpoint")) {
+ const struct sockaddr *endpoint = nvlist_get_binary(nvl_peers[i], "endpoint", &size);
+ if (endpoint && size <= sizeof(peer->endpoint) && size >= sizeof(peer->endpoint.addr) &&
+ (endpoint->sa_family == AF_INET || endpoint->sa_family == AF_INET6))
+ memcpy(&peer->endpoint.addr, endpoint, size);
+ }
+ if (nvlist_exists_binary(nvl_peers[i], "last-handshake-time")) {
+ binary = nvlist_get_binary(nvl_peers[i], "last-handshake-time", &size);
+ if (binary && size == sizeof(peer->last_handshake_time))
+ memcpy(&peer->last_handshake_time, binary, sizeof(peer->last_handshake_time));
+ }
+ if (ifconfig_wg_get_allowed_ips(h, nvl_peers[i], peer) == -1) {
+ free(peer);
+ return (-1);
+ }
+ STAILQ_INSERT_TAIL(&dev->peers, peer, next);
+ }
+ return (0);
+}
+
+int
+ifconfig_wg_get_info(ifconfig_handle_t *h, const char *ifname,
+ struct ifconfig_wg *dev)
+{
+ struct wg_data_io wgd = { 0 };
+ nvlist_t *nvl_device = NULL;
+ size_t size;
+ uint64_t number;
+ const void *binary;
+ int ret = -1;
+
+ strlcpy(wgd.wgd_name, ifname, sizeof(wgd.wgd_name));
+ if (ifconfig_ioctlwrap(h, AF_INET, SIOCGWG, &wgd) <0)
+ goto err;
+
+ wgd.wgd_data = malloc(wgd.wgd_size);
+ if (!wgd.wgd_data)
+ goto err;
+ if (ifconfig_ioctlwrap(h, AF_INET, SIOCGWG, &wgd) <0)
+ goto err;
+
+ STAILQ_INIT(&dev->peers);
+ nvl_device = nvlist_unpack(wgd.wgd_data, wgd.wgd_size, 0);
+ if (!nvl_device)
+ goto err;
+
+ if (nvlist_exists_number(nvl_device, "listen-port")) {
+ number = nvlist_get_number(nvl_device, "listen-port");
+ if (number <= UINT16_MAX)
+ dev->listen_port = number;
+ }
+ if (nvlist_exists_binary(nvl_device, "public-key")) {
+ binary = nvlist_get_binary(nvl_device, "public-key", &size);
+ if (binary && size == sizeof(dev->public_key))
+ memcpy(dev->public_key, binary, sizeof(dev->public_key));
+ }
+ if (ifconfig_wg_get_peers(h, nvl_device, dev) == -1)
+ goto err;
+
+ ret = 0;
+err:
+ if (ret != 0)
+ ifconfig_wg_free(dev);
+ free(wgd.wgd_data);
+ nvlist_destroy(nvl_device);
+ return ret;
+}
diff --git a/sbin/ifconfig/Makefile b/sbin/ifconfig/Makefile
--- a/sbin/ifconfig/Makefile
+++ b/sbin/ifconfig/Makefile
@@ -35,6 +35,7 @@
SRCS+= ifgre.c # GRE keys etc
SRCS+= ifgif.c # GIF reversed header workaround
SRCS+= ifipsec.c # IPsec VTI
+SRCS+= wg.c # Wireguard
SRCS+= sfp.c # SFP/SFP+ information
LIBADD+= ifconfig m util
diff --git a/sbin/ifconfig/wg.c b/sbin/ifconfig/wg.c
new file mode 100644
--- /dev/null
+++ b/sbin/ifconfig/wg.c
@@ -0,0 +1,114 @@
+#include <libifconfig.h>
+#include "ifconfig.h"
+#include <stdio.h>
+#include <string.h>
+#include <resolv.h>
+#include <inttypes.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+static void
+print_endpoint(const struct sockaddr *addr)
+{
+ char host[4096 + 1];
+ char service[512 + 1];
+ int ret;
+ socklen_t addr_len = 0;
+
+ if (addr->sa_family == AF_INET)
+ addr_len = sizeof(struct sockaddr_in);
+ else if (addr->sa_family == AF_INET6)
+ addr_len = sizeof(struct sockaddr_in6);
+
+ ret = getnameinfo(addr, addr_len, host, sizeof(host), service, sizeof(service), NI_DGRAM | NI_NUMERICSERV | NI_NUMERICHOST);
+ if (ret) {
+ printf("%s", gai_strerror(ret));
+ } else
+ printf((addr->sa_family == AF_INET6 && strchr(host, ':')) ? "[%s]:%s" : "%s:%s", host, service);
+}
+
+static void
+print_ip(const struct ifconfig_wg_allowed_ip *wgaip)
+{
+ char buf[INET6_ADDRSTRLEN + 1];
+
+ memset(buf, 0, sizeof(buf));
+ if (wgaip->family == AF_INET)
+ inet_ntop(AF_INET, &wgaip->ip4, buf, sizeof(buf));
+ else
+ inet_ntop(AF_INET, &wgaip->ip6, buf, sizeof(buf));
+ printf("%s", buf);
+}
+
+static void
+print_key(void *key, size_t len)
+{
+ char b64key[BUFSIZ];
+
+ memset(b64key, 0, sizeof(b64key));
+ b64_ntop(key, len, b64key, sizeof(b64key));
+ printf("%s", b64key);
+}
+
+static void
+wg_status(if_ctx *ctx __unused)
+{
+ struct ifconfig_wg wg;
+ struct ifconfig_wg_peer *wgpeer;
+ struct ifconfig_wg_allowed_ip *wgaip;
+
+ memset(&wg, 0, sizeof(wg));
+ if (ifconfig_wg_get_info(lifh, ctx->ifname, &wg) != 0)
+ return;
+ if (wg.public_key[0] != '\0') {
+ printf("\twg public key ");
+ print_key(wg.public_key, sizeof(wg.public_key));
+ printf("\n");
+ }
+ if (wg.listen_port > 0)
+ printf("\twg listen-port %hu\n", wg.listen_port);
+
+ STAILQ_FOREACH(wgpeer, &wg.peers, next) {
+ printf("\twg peer ");
+ print_key(wgpeer->public_key, sizeof(wgpeer->public_key));
+ printf("\n");
+ if (wgpeer->endpoint.addr.sa_family == AF_INET || wgpeer->endpoint.addr.sa_family == AF_INET6) {
+ printf("\t endpoint: ");
+ print_endpoint(&wgpeer->endpoint.addr);
+ printf("\n");
+ }
+ if (!STAILQ_EMPTY(&wgpeer->allowed_ips))
+ printf("\t allowed ips: ");
+ STAILQ_FOREACH(wgaip, &wgpeer->allowed_ips, next) {
+ print_ip(wgaip);
+ printf("/%u", wgaip->cidr);
+ if (STAILQ_NEXT(wgaip, next) != NULL)
+ printf(", ");
+ else
+ printf("\n");
+ }
+ if (wgpeer->last_handshake_time.tv_sec > 0) {
+ time_t now = time(NULL);
+ printf("\t last handshake: %"PRIdMAX" seconds\n", (intmax_t)now - wgpeer->last_handshake_time.tv_sec);
+ }
+ if (wgpeer->persistent_keepalive_interval > 0)
+ printf("\t keepalive: %"PRIdMAX" seconds\n", (intmax_t)wgpeer->persistent_keepalive_interval);
+ }
+ ifconfig_wg_free(&wg);
+}
+
+static struct afswtch af_wg = {
+ .af_name = "af_wg",
+ .af_af = AF_UNSPEC,
+ .af_other_status = wg_status,
+};
+
+static __constructor void
+wg_ctor(void)
+{
+ af_register(&af_wg);
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Mar 13, 4:02 AM (16 h, 40 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
17129700
Default Alt Text
D42880.diff (11 KB)
Attached To
Mode
D42880: wireguard: extend ifconfig
Attached
Detach File
Event Timeline
Log In to Comment