1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright (C) 2015-2021 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved. 4 * 5 */ 6 7 #include <sys/nv.h> 8 #include <sys/sockio.h> 9 #include <dev/wg/if_wg.h> 10 11 #define IPC_SUPPORTS_KERNEL_INTERFACE 12 13 static int get_dgram_socket(void) 14 { 15 static int sock = -1; 16 if (sock < 0) 17 sock = socket(AF_INET, SOCK_DGRAM, 0); 18 return sock; 19 } 20 21 static int kernel_get_wireguard_interfaces(struct string_list *list) 22 { 23 struct ifgroupreq ifgr = { .ifgr_name = "wg" }; 24 struct ifg_req *ifg; 25 int s = get_dgram_socket(), ret = 0; 26 27 if (s < 0) 28 return -errno; 29 30 if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) < 0) 31 return errno == ENOENT ? 0 : -errno; 32 33 ifgr.ifgr_groups = calloc(1, ifgr.ifgr_len); 34 if (!ifgr.ifgr_groups) 35 return -errno; 36 if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) < 0) { 37 ret = -errno; 38 goto out; 39 } 40 41 for (ifg = ifgr.ifgr_groups; ifg && ifgr.ifgr_len > 0; ++ifg) { 42 if ((ret = string_list_add(list, ifg->ifgrq_member)) < 0) 43 goto out; 44 ifgr.ifgr_len -= sizeof(struct ifg_req); 45 } 46 47 out: 48 free(ifgr.ifgr_groups); 49 return ret; 50 } 51 52 static int kernel_get_device(struct wgdevice **device, const char *ifname) 53 { 54 struct wg_data_io wgd = { 0 }; 55 nvlist_t *nvl_device = NULL; 56 const nvlist_t *const *nvl_peers; 57 struct wgdevice *dev = NULL; 58 size_t size, peer_count, i; 59 uint64_t number; 60 const void *binary; 61 int ret = 0, s; 62 63 *device = NULL; 64 s = get_dgram_socket(); 65 if (s < 0) 66 goto err; 67 68 strlcpy(wgd.wgd_name, ifname, sizeof(wgd.wgd_name)); 69 if (ioctl(s, SIOCGWG, &wgd) < 0) 70 goto err; 71 72 wgd.wgd_data = malloc(wgd.wgd_size); 73 if (!wgd.wgd_data) 74 goto err; 75 if (ioctl(s, SIOCGWG, &wgd) < 0) 76 goto err; 77 78 dev = calloc(1, sizeof(*dev)); 79 if (!dev) 80 goto err; 81 strlcpy(dev->name, ifname, sizeof(dev->name)); 82 nvl_device = nvlist_unpack(wgd.wgd_data, wgd.wgd_size, 0); 83 if (!nvl_device) 84 goto err; 85 86 if (nvlist_exists_number(nvl_device, "listen-port")) { 87 number = nvlist_get_number(nvl_device, "listen-port"); 88 if (number <= UINT16_MAX) { 89 dev->listen_port = number; 90 dev->flags |= WGDEVICE_HAS_LISTEN_PORT; 91 } 92 } 93 if (nvlist_exists_number(nvl_device, "user-cookie")) { 94 number = nvlist_get_number(nvl_device, "user-cookie"); 95 if (number <= UINT32_MAX) { 96 dev->fwmark = number; 97 dev->flags |= WGDEVICE_HAS_FWMARK; 98 } 99 } 100 if (nvlist_exists_binary(nvl_device, "public-key")) { 101 binary = nvlist_get_binary(nvl_device, "public-key", &size); 102 if (binary && size == sizeof(dev->public_key)) { 103 memcpy(dev->public_key, binary, sizeof(dev->public_key)); 104 dev->flags |= WGDEVICE_HAS_PUBLIC_KEY; 105 } 106 } 107 if (nvlist_exists_binary(nvl_device, "private-key")) { 108 binary = nvlist_get_binary(nvl_device, "private-key", &size); 109 if (binary && size == sizeof(dev->private_key)) { 110 memcpy(dev->private_key, binary, sizeof(dev->private_key)); 111 dev->flags |= WGDEVICE_HAS_PRIVATE_KEY; 112 } 113 } 114 if (!nvlist_exists_nvlist_array(nvl_device, "peers")) 115 goto skip_peers; 116 nvl_peers = nvlist_get_nvlist_array(nvl_device, "peers", &peer_count); 117 if (!nvl_peers) 118 goto skip_peers; 119 for (i = 0; i < peer_count; ++i) { 120 struct wgpeer *peer; 121 struct wgallowedip *aip; 122 const nvlist_t *const *nvl_aips; 123 size_t aip_count, j; 124 125 peer = calloc(1, sizeof(*peer)); 126 if (!peer) 127 goto err_peer; 128 if (nvlist_exists_binary(nvl_peers[i], "public-key")) { 129 binary = nvlist_get_binary(nvl_peers[i], "public-key", &size); 130 if (binary && size == sizeof(peer->public_key)) { 131 memcpy(peer->public_key, binary, sizeof(peer->public_key)); 132 peer->flags |= WGPEER_HAS_PUBLIC_KEY; 133 } 134 } 135 if (nvlist_exists_binary(nvl_peers[i], "preshared-key")) { 136 binary = nvlist_get_binary(nvl_peers[i], "preshared-key", &size); 137 if (binary && size == sizeof(peer->preshared_key)) { 138 memcpy(peer->preshared_key, binary, sizeof(peer->preshared_key)); 139 if (!key_is_zero(peer->preshared_key)) 140 peer->flags |= WGPEER_HAS_PRESHARED_KEY; 141 } 142 } 143 if (nvlist_exists_number(nvl_peers[i], "persistent-keepalive-interval")) { 144 number = nvlist_get_number(nvl_peers[i], "persistent-keepalive-interval"); 145 if (number <= UINT16_MAX) { 146 peer->persistent_keepalive_interval = number; 147 peer->flags |= WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL; 148 } 149 } 150 if (nvlist_exists_binary(nvl_peers[i], "endpoint")) { 151 const struct sockaddr *endpoint = nvlist_get_binary(nvl_peers[i], "endpoint", &size); 152 if (endpoint && size <= sizeof(peer->endpoint) && size >= sizeof(peer->endpoint.addr) && 153 (endpoint->sa_family == AF_INET || endpoint->sa_family == AF_INET6)) 154 memcpy(&peer->endpoint.addr, endpoint, size); 155 } 156 if (nvlist_exists_number(nvl_peers[i], "rx-bytes")) 157 peer->rx_bytes = nvlist_get_number(nvl_peers[i], "rx-bytes"); 158 if (nvlist_exists_number(nvl_peers[i], "tx-bytes")) 159 peer->tx_bytes = nvlist_get_number(nvl_peers[i], "tx-bytes"); 160 if (nvlist_exists_binary(nvl_peers[i], "last-handshake-time")) { 161 binary = nvlist_get_binary(nvl_peers[i], "last-handshake-time", &size); 162 if (binary && size == sizeof(peer->last_handshake_time)) 163 memcpy(&peer->last_handshake_time, binary, sizeof(peer->last_handshake_time)); 164 } 165 166 if (!nvlist_exists_nvlist_array(nvl_peers[i], "allowed-ips")) 167 goto skip_allowed_ips; 168 nvl_aips = nvlist_get_nvlist_array(nvl_peers[i], "allowed-ips", &aip_count); 169 if (!aip_count || !nvl_aips) 170 goto skip_allowed_ips; 171 for (j = 0; j < aip_count; ++j) { 172 aip = calloc(1, sizeof(*aip)); 173 if (!aip) 174 goto err_allowed_ips; 175 if (!nvlist_exists_number(nvl_aips[j], "cidr")) 176 continue; 177 number = nvlist_get_number(nvl_aips[j], "cidr"); 178 if (nvlist_exists_binary(nvl_aips[j], "ipv4")) { 179 binary = nvlist_get_binary(nvl_aips[j], "ipv4", &size); 180 if (!binary || number > 32) { 181 ret = EINVAL; 182 goto err_allowed_ips; 183 } 184 aip->family = AF_INET; 185 aip->cidr = number; 186 memcpy(&aip->ip4, binary, sizeof(aip->ip4)); 187 } else if (nvlist_exists_binary(nvl_aips[j], "ipv6")) { 188 binary = nvlist_get_binary(nvl_aips[j], "ipv6", &size); 189 if (!binary || number > 128) { 190 ret = EINVAL; 191 goto err_allowed_ips; 192 } 193 aip->family = AF_INET6; 194 aip->cidr = number; 195 memcpy(&aip->ip6, binary, sizeof(aip->ip6)); 196 } else 197 continue; 198 199 if (!peer->first_allowedip) 200 peer->first_allowedip = aip; 201 else 202 peer->last_allowedip->next_allowedip = aip; 203 peer->last_allowedip = aip; 204 continue; 205 206 err_allowed_ips: 207 if (!ret) 208 ret = -errno; 209 free(aip); 210 goto err_peer; 211 } 212 skip_allowed_ips: 213 if (!dev->first_peer) 214 dev->first_peer = peer; 215 else 216 dev->last_peer->next_peer = peer; 217 dev->last_peer = peer; 218 continue; 219 220 err_peer: 221 if (!ret) 222 ret = -errno; 223 free(peer); 224 goto err; 225 } 226 227 skip_peers: 228 free(wgd.wgd_data); 229 nvlist_destroy(nvl_device); 230 *device = dev; 231 return 0; 232 233 err: 234 if (!ret) 235 ret = -errno; 236 free(wgd.wgd_data); 237 nvlist_destroy(nvl_device); 238 free(dev); 239 return ret; 240 } 241 242 243 static int kernel_set_device(struct wgdevice *dev) 244 { 245 struct wg_data_io wgd = { 0 }; 246 nvlist_t *nvl_device = NULL, **nvl_peers = NULL; 247 size_t peer_count = 0, i = 0; 248 struct wgpeer *peer; 249 int ret = 0, s; 250 251 strlcpy(wgd.wgd_name, dev->name, sizeof(wgd.wgd_name)); 252 253 nvl_device = nvlist_create(0); 254 if (!nvl_device) 255 goto err; 256 257 for_each_wgpeer(dev, peer) 258 ++peer_count; 259 if (peer_count) { 260 nvl_peers = calloc(peer_count, sizeof(*nvl_peers)); 261 if (!nvl_peers) 262 goto err; 263 } 264 if (dev->flags & WGDEVICE_HAS_PRIVATE_KEY) 265 nvlist_add_binary(nvl_device, "private-key", dev->private_key, sizeof(dev->private_key)); 266 if (dev->flags & WGDEVICE_HAS_LISTEN_PORT) 267 nvlist_add_number(nvl_device, "listen-port", dev->listen_port); 268 if (dev->flags & WGDEVICE_HAS_FWMARK) 269 nvlist_add_number(nvl_device, "user-cookie", dev->fwmark); 270 if (dev->flags & WGDEVICE_REPLACE_PEERS) 271 nvlist_add_bool(nvl_device, "replace-peers", true); 272 273 for_each_wgpeer(dev, peer) { 274 size_t aip_count = 0, j = 0; 275 nvlist_t **nvl_aips = NULL; 276 struct wgallowedip *aip; 277 278 nvl_peers[i] = nvlist_create(0); 279 if (!nvl_peers[i]) 280 goto err_peer; 281 for_each_wgallowedip(peer, aip) 282 ++aip_count; 283 if (aip_count) { 284 nvl_aips = calloc(aip_count, sizeof(*nvl_aips)); 285 if (!nvl_aips) 286 goto err_peer; 287 } 288 nvlist_add_binary(nvl_peers[i], "public-key", peer->public_key, sizeof(peer->public_key)); 289 if (peer->flags & WGPEER_HAS_PRESHARED_KEY) 290 nvlist_add_binary(nvl_peers[i], "preshared-key", peer->preshared_key, sizeof(peer->preshared_key)); 291 if (peer->flags & WGPEER_HAS_PERSISTENT_KEEPALIVE_INTERVAL) 292 nvlist_add_number(nvl_peers[i], "persistent-keepalive-interval", peer->persistent_keepalive_interval); 293 if (peer->endpoint.addr.sa_family == AF_INET || peer->endpoint.addr.sa_family == AF_INET6) 294 nvlist_add_binary(nvl_peers[i], "endpoint", &peer->endpoint.addr, peer->endpoint.addr.sa_len); 295 if (peer->flags & WGPEER_REPLACE_ALLOWEDIPS) 296 nvlist_add_bool(nvl_peers[i], "replace-allowedips", true); 297 if (peer->flags & WGPEER_REMOVE_ME) 298 nvlist_add_bool(nvl_peers[i], "remove", true); 299 for_each_wgallowedip(peer, aip) { 300 nvl_aips[j] = nvlist_create(0); 301 if (!nvl_aips[j]) 302 goto err_peer; 303 nvlist_add_number(nvl_aips[j], "cidr", aip->cidr); 304 if (aip->family == AF_INET) 305 nvlist_add_binary(nvl_aips[j], "ipv4", &aip->ip4, sizeof(aip->ip4)); 306 else if (aip->family == AF_INET6) 307 nvlist_add_binary(nvl_aips[j], "ipv6", &aip->ip6, sizeof(aip->ip6)); 308 ++j; 309 } 310 if (j) { 311 nvlist_add_nvlist_array(nvl_peers[i], "allowed-ips", (const nvlist_t *const *)nvl_aips, j); 312 for (j = 0; j < aip_count; ++j) 313 nvlist_destroy(nvl_aips[j]); 314 free(nvl_aips); 315 } 316 ++i; 317 continue; 318 319 err_peer: 320 ret = -errno; 321 for (j = 0; j < aip_count && nvl_aips; ++j) 322 nvlist_destroy(nvl_aips[j]); 323 free(nvl_aips); 324 nvlist_destroy(nvl_peers[i]); 325 goto err; 326 } 327 if (i) { 328 nvlist_add_nvlist_array(nvl_device, "peers", (const nvlist_t *const *)nvl_peers, i); 329 for (i = 0; i < peer_count; ++i) 330 nvlist_destroy(nvl_peers[i]); 331 free(nvl_peers); 332 } 333 wgd.wgd_data = nvlist_pack(nvl_device, &wgd.wgd_size); 334 nvlist_destroy(nvl_device); 335 if (!wgd.wgd_data) 336 goto err; 337 s = get_dgram_socket(); 338 if (s < 0) 339 return -errno; 340 return ioctl(s, SIOCSWG, &wgd); 341 342 err: 343 if (!ret) 344 ret = -errno; 345 for (i = 0; i < peer_count && nvl_peers; ++i) 346 nvlist_destroy(nvl_peers[i]); 347 free(nvl_peers); 348 nvlist_destroy(nvl_device); 349 return ret; 350 } 351