Skip to content

Commit 5c66f6e

Browse files
Matt Dunwoodiezx2c4
authored andcommitted
ipc: add support for openbsd kernel implementation
Signed-off-by: Matt Dunwoodie <ncon@noconroy.net>
1 parent b60e30e commit 5c66f6e

1 file changed

Lines changed: 262 additions & 3 deletions

File tree

src/ipc.c

Lines changed: 262 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
#include <linux/wireguard.h>
1010
#include "netlink.h"
1111
#endif
12+
#ifdef __OpenBSD__
13+
#include <net/if_wg.h>
14+
#endif
1215
#include <netinet/in.h>
1316
#include <sys/socket.h>
1417
#include <net/if.h>
@@ -922,13 +925,269 @@ static int kernel_get_device(struct wgdevice **device, const char *iface)
922925
}
923926
#endif
924927

928+
#ifdef __OpenBSD__
929+
int s = -1;
930+
931+
void
932+
getsock()
933+
{
934+
if (s < 0)
935+
s = socket(AF_INET, SOCK_DGRAM, 0);
936+
}
937+
938+
static int kernel_get_wireguard_interfaces(struct string_list *list)
939+
{
940+
struct ifgroupreq ifgr;
941+
struct ifg_req *ifg;
942+
size_t len = 0;
943+
int ret = 0;
944+
945+
getsock();
946+
947+
bzero(&ifgr, sizeof(ifgr));
948+
strlcpy(ifgr.ifgr_name, "wg", sizeof(ifgr.ifgr_name));
949+
950+
if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1)
951+
return errno;
952+
953+
len = ifgr.ifgr_len;
954+
if ((ifgr.ifgr_groups = calloc(1, len)) == NULL)
955+
return errno;
956+
if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) {
957+
ret = errno;
958+
goto out;
959+
}
960+
961+
for (ifg = ifgr.ifgr_groups; ifg && len > 0; ifg++) {
962+
if ((ret = string_list_add(list, ifg->ifgrq_member)) < 0)
963+
goto out;
964+
len -= sizeof(struct ifg_req);
965+
}
966+
967+
out:
968+
free(ifgr.ifgr_groups);
969+
return ret;
970+
}
971+
972+
static int kernel_get_device(struct wgdevice **device, const char *iface)
973+
{
974+
struct wg_data_io wgdata;
975+
struct wg_interface_io *wg_iface;
976+
struct wg_peer_io *wg_peer;
977+
struct wg_aip_io *wg_aip;
978+
979+
struct wgdevice *dev;
980+
struct wgpeer *peer;
981+
struct wgallowedip *aip;
982+
983+
size_t size;
984+
985+
getsock();
986+
987+
*device = NULL;
988+
989+
strlcpy(wgdata.wgd_name, iface, sizeof(wgdata.wgd_name));
990+
wgdata.wgd_size = size = 0;
991+
wgdata.wgd_mem = NULL;
992+
993+
if (ioctl(s, SIOCGWG, (caddr_t)&wgdata) == -1 &&
994+
(errno == ENOTTY || errno == EPERM))
995+
return -errno;
996+
997+
while (size < wgdata.wgd_size) {
998+
size = wgdata.wgd_size;
999+
wgdata.wgd_mem = realloc(wgdata.wgd_mem, size);
1000+
if (ioctl(s, SIOCGWG, (caddr_t)&wgdata) == -1)
1001+
return -errno;
1002+
}
1003+
1004+
wg_iface = wgdata.wgd_mem;
1005+
1006+
if ((dev = calloc(1, sizeof(*dev))) == NULL)
1007+
return -errno;
1008+
strlcpy(dev->name, iface, sizeof(dev->name));
1009+
1010+
if (wg_iface->i_flags & WG_INTERFACE_HAS_RTABLE) {
1011+
dev->fwmark = wg_iface->i_rtable;
1012+
dev->flags |= WGDEVICE_HAS_FWMARK;
1013+
}
1014+
1015+
if (wg_iface->i_flags & WG_INTERFACE_HAS_PORT) {
1016+
dev->listen_port = ntohs(wg_iface->i_port);
1017+
dev->flags |= WGDEVICE_HAS_LISTEN_PORT;
1018+
}
1019+
1020+
if (wg_iface->i_flags & WG_INTERFACE_HAS_PUBLIC) {
1021+
memcpy(dev->public_key, wg_iface->i_public, WG_KEY_SIZE);
1022+
dev->flags |= WGDEVICE_HAS_PUBLIC_KEY;
1023+
}
1024+
1025+
if (wg_iface->i_flags & WG_INTERFACE_HAS_PRIVATE) {
1026+
memcpy(dev->private_key, wg_iface->i_private, WG_KEY_SIZE);
1027+
dev->flags |= WGDEVICE_HAS_PRIVATE_KEY;
1028+
}
1029+
1030+
for (wg_peer = wg_iface->i_peers; wg_peer != NULL; wg_peer = wg_peer->p_next) {
1031+
if ((peer = calloc(1, sizeof(*peer))) == NULL)
1032+
return -errno;
1033+
1034+
if (dev->first_peer == NULL)
1035+
dev->first_peer = peer;
1036+
else
1037+
dev->last_peer->next_peer = peer;
1038+
dev->last_peer = peer;
1039+
1040+
if (wg_peer->p_flags & WG_PEER_HAS_PUBLIC) {
1041+
memcpy(peer->public_key, wg_peer->p_public, WG_KEY_SIZE);
1042+
peer->flags |= WGPEER_HAS_PUBLIC_KEY;
1043+
}
1044+
1045+
if (wg_peer->p_flags & WG_PEER_HAS_PSK) {
1046+
memcpy(peer->preshared_key, wg_peer->p_psk, WG_KEY_SIZE);
1047+
peer->flags |= WGPEER_HAS_PRESHARED_KEY;
1048+
}
1049+
1050+
if (wg_peer->p_flags & WG_PEER_HAS_PKA) {
1051+
peer->persistent_keepalive_interval = wg_peer->p_pka;
1052+
peer->flags |= WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL;
1053+
}
1054+
1055+
if (wg_peer->p_flags & WG_PEER_HAS_SOCKADDR)
1056+
memcpy(&peer->endpoint.addr, &wg_peer->p_sa,
1057+
wg_peer->p_sa.sa_len);
1058+
1059+
peer->rx_bytes = wg_peer->p_rxbytes;
1060+
peer->tx_bytes = wg_peer->p_txbytes;
1061+
1062+
peer->last_handshake_time.tv_sec = wg_peer->p_last_handshake.tv_sec;
1063+
peer->last_handshake_time.tv_nsec = wg_peer->p_last_handshake.tv_nsec;
1064+
1065+
for (wg_aip = wg_peer->p_aips; wg_aip != NULL; wg_aip = wg_aip->a_next) {
1066+
if ((aip = calloc(1, sizeof(*aip))) == NULL)
1067+
return -errno;
1068+
1069+
if (peer->first_allowedip == NULL)
1070+
peer->first_allowedip = aip;
1071+
else
1072+
peer->last_allowedip->next_allowedip = aip;
1073+
peer->last_allowedip = aip;
1074+
1075+
aip->family = wg_aip->a_af;
1076+
if (wg_aip->a_af == AF_INET) {
1077+
memcpy(&aip->ip4, &wg_aip->a_ipv4, sizeof(aip->ip4));
1078+
aip->cidr = wg_aip->a_mask;
1079+
} else if (wg_aip->a_af == AF_INET6) {
1080+
memcpy(&aip->ip6, &wg_aip->a_ipv6, sizeof(aip->ip6));
1081+
aip->cidr = wg_aip->a_mask;
1082+
}
1083+
}
1084+
}
1085+
1086+
*device = dev;
1087+
free(wgdata.wgd_mem);
1088+
return 0;
1089+
}
1090+
1091+
static int kernel_set_device(struct wgdevice *dev)
1092+
{
1093+
struct wg_data_io wgdata;
1094+
struct wg_interface_io wg_iface;
1095+
struct wg_peer_io *wg_peer;
1096+
struct wg_aip_io *wg_aip;
1097+
1098+
struct wgpeer *peer;
1099+
struct wgallowedip *aip;
1100+
1101+
getsock();
1102+
1103+
strlcpy(wgdata.wgd_name, dev->name, sizeof(wgdata.wgd_name));
1104+
wgdata.wgd_mem = &wg_iface;
1105+
1106+
bzero(&wg_iface, sizeof(wg_iface));
1107+
1108+
if (dev->flags & WGDEVICE_HAS_PRIVATE_KEY) {
1109+
memcpy(wg_iface.i_private, dev->private_key, WG_KEY_SIZE);
1110+
wg_iface.i_flags |= WG_INTERFACE_HAS_PRIVATE;
1111+
}
1112+
1113+
if (dev->flags & WGDEVICE_HAS_LISTEN_PORT) {
1114+
wg_iface.i_port = htons(dev->listen_port);
1115+
wg_iface.i_flags |= WG_INTERFACE_HAS_PORT;
1116+
}
1117+
1118+
if (dev->flags & WGDEVICE_HAS_FWMARK) {
1119+
wg_iface.i_rtable = dev->fwmark;
1120+
wg_iface.i_flags |= WG_INTERFACE_HAS_RTABLE;
1121+
}
1122+
1123+
if (dev->flags & WGDEVICE_REPLACE_PEERS)
1124+
wg_iface.i_flags |= WG_INTERFACE_REPLACE_PEERS;
1125+
1126+
for_each_wgpeer(dev, peer) {
1127+
if ((wg_peer = calloc(1, sizeof(*wg_peer))) == NULL)
1128+
return -errno;
1129+
1130+
wg_peer->p_flags = WG_PEER_HAS_PUBLIC;
1131+
memcpy(wg_peer->p_public, peer->public_key, WG_KEY_SIZE);
1132+
1133+
if (peer->flags & WGPEER_HAS_PRESHARED_KEY) {
1134+
memcpy(wg_peer->p_psk, peer->preshared_key, WG_KEY_SIZE);
1135+
wg_peer->p_flags |= WG_PEER_HAS_PSK;
1136+
}
1137+
1138+
if (peer->flags & WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL) {
1139+
wg_peer->p_pka = peer->persistent_keepalive_interval;
1140+
wg_peer->p_flags |= WG_PEER_HAS_PKA;
1141+
}
1142+
1143+
if (peer->endpoint.addr.sa_family == AF_INET ||
1144+
peer->endpoint.addr.sa_family == AF_INET6) {
1145+
memcpy(&wg_peer->p_sa, &peer->endpoint.addr, peer->endpoint.addr.sa_len);
1146+
wg_peer->p_flags |= WG_PEER_HAS_SOCKADDR;
1147+
}
1148+
1149+
if (peer->flags & WGPEER_REPLACE_ALLOWEDIPS)
1150+
wg_peer->p_flags |= WG_PEER_REPLACE_AIPS;
1151+
1152+
if (peer->flags & WGPEER_REMOVE_ME)
1153+
wg_peer->p_flags |= WG_PEER_REMOVE;
1154+
1155+
wg_peer->p_next = wg_iface.i_peers;
1156+
wg_iface.i_peers = wg_peer;
1157+
1158+
for_each_wgallowedip(peer, aip) {
1159+
if ((wg_aip = calloc(1, sizeof(*wg_aip))) == NULL)
1160+
return -errno;
1161+
1162+
wg_aip->a_af = aip->family;
1163+
wg_aip->a_mask = aip->cidr;
1164+
1165+
if (aip->family == AF_INET)
1166+
memcpy(&wg_aip->a_ipv4, &aip->ip4, sizeof(aip->ip4));
1167+
else if (aip->family == AF_INET6)
1168+
memcpy(&wg_aip->a_ipv6, &aip->ip6, sizeof(aip->ip6));
1169+
else
1170+
return -1;
1171+
1172+
wg_aip->a_next = wg_peer->p_aips;
1173+
wg_peer->p_aips = wg_aip;
1174+
}
1175+
}
1176+
1177+
if (ioctl(s, SIOCSWG, (caddr_t)&wgdata) == -1)
1178+
return -errno;
1179+
1180+
return 0;
1181+
}
1182+
#endif /* OpenBSD */
1183+
9251184
/* first\0second\0third\0forth\0last\0\0 */
9261185
char *ipc_list_devices(void)
9271186
{
9281187
struct string_list list = { 0 };
9291188
int ret;
9301189

931-
#ifdef __linux__
1190+
#if defined(__linux__) || defined(__OpenBSD__)
9321191
ret = kernel_get_wireguard_interfaces(&list);
9331192
if (ret < 0)
9341193
goto cleanup;
@@ -948,7 +1207,7 @@ char *ipc_list_devices(void)
9481207

9491208
int ipc_get_device(struct wgdevice **dev, const char *iface)
9501209
{
951-
#ifdef __linux__
1210+
#if defined(__linux__) || defined(__OpenBSD__)
9521211
if (userspace_has_wireguard_interface(iface))
9531212
return userspace_get_device(dev, iface);
9541213
return kernel_get_device(dev, iface);
@@ -959,7 +1218,7 @@ int ipc_get_device(struct wgdevice **dev, const char *iface)
9591218

9601219
int ipc_set_device(struct wgdevice *dev)
9611220
{
962-
#ifdef __linux__
1221+
#if defined(__linux__) || defined(__OpenBSD__)
9631222
if (userspace_has_wireguard_interface(dev->name))
9641223
return userspace_set_device(dev);
9651224
return kernel_set_device(dev);

0 commit comments

Comments
 (0)