Page MenuHomeFreeBSD

D42880.diff
No OneTemporary

D42880.diff

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

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)

Event Timeline