]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/ifconfig/ifwg.c
Add ELF flag to disable ASLR stack gap.
[FreeBSD/FreeBSD.git] / sbin / ifconfig / ifwg.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2020 Rubicon Communications, LLC (Netgate)
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *   1. Redistributions of source code must retain the above copyright
10  *      notice, this list of conditions and the following disclaimer.
11  *   2. Redistributions in binary form must reproduce the above copyright
12  *      notice, this list of conditions and the following disclaimer in the
13  *      documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #ifndef RESCUE
32 #include <sys/param.h>
33 #include <sys/ioctl.h>
34 #include <sys/socket.h>
35 #include <sys/sysctl.h>
36 #include <sys/time.h>
37 #include <sys/nv.h>
38
39 #include <net/ethernet.h>
40 #include <net/if.h>
41 #include <net/if_dl.h>
42 #include <net/if_types.h>
43 #include <net/if_media.h>
44 #include <net/route.h>
45
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48
49 #include <assert.h>
50 #include <ctype.h>
51 #include <err.h>
52 #include <errno.h>
53 #include <fcntl.h>
54 #include <inttypes.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <netdb.h>
58 #include <string.h>
59 #include <unistd.h>
60 #include <stdarg.h>
61 #include <stddef.h>             /* NB: for offsetof */
62 #include <locale.h>
63 #include <langinfo.h>
64 #include <resolv.h>
65
66 #include "ifconfig.h"
67
68 typedef enum {
69         WGC_GET = 0x5,
70         WGC_SET = 0x6,
71 } wg_cmd_t;
72
73 static nvlist_t *nvl_params;
74 static bool do_peer;
75 static int allowed_ips_count;
76 static int allowed_ips_max;
77 struct allowedip {
78         struct sockaddr_storage a_addr;
79         struct sockaddr_storage a_mask;
80 };
81 struct allowedip *allowed_ips;
82
83 #define ALLOWEDIPS_START 16
84 #define WG_KEY_LEN 32
85 #define WG_KEY_LEN_BASE64 ((((WG_KEY_LEN) + 2) / 3) * 4 + 1)
86 #define WG_KEY_LEN_HEX (WG_KEY_LEN * 2 + 1)
87 #define WG_MAX_STRLEN 64
88
89 static bool
90 key_from_base64(uint8_t key[static WG_KEY_LEN], const char *base64)
91 {
92
93         if (strlen(base64) != WG_KEY_LEN_BASE64 - 1) {
94                 warnx("bad key len - need %d got %zu\n", WG_KEY_LEN_BASE64 - 1, strlen(base64));
95                 return false;
96         }
97         if (base64[WG_KEY_LEN_BASE64 - 2] != '=') {
98                 warnx("bad key terminator, expected '=' got '%c'", base64[WG_KEY_LEN_BASE64 - 2]);
99                 return false;
100         }
101         return (b64_pton(base64, key, WG_KEY_LEN));
102 }
103
104 static void
105 parse_endpoint(const char *endpoint_)
106 {
107         int err;
108         char *base, *endpoint, *port, *colon, *tmp;
109         struct addrinfo hints, *res;
110
111         endpoint = base = strdup(endpoint_);
112         colon = rindex(endpoint, ':');
113         if (colon == NULL)
114                 errx(1, "bad endpoint format %s - no port delimiter found", endpoint);
115         *colon = '\0';
116         port = colon + 1;
117
118         /* [::]:<> */
119         if (endpoint[0] == '[') {
120                 endpoint++;
121                 tmp = index(endpoint, ']');
122                 if (tmp == NULL)
123                         errx(1, "bad endpoint format %s - '[' found with no matching ']'", endpoint);
124                 *tmp = '\0';
125         }
126         bzero(&hints, sizeof(hints));
127         hints.ai_family = AF_UNSPEC;
128         err = getaddrinfo(endpoint, port, &hints, &res);
129         if (err)
130                 errx(1, "%s", gai_strerror(err));
131         nvlist_add_binary(nvl_params, "endpoint", res->ai_addr, res->ai_addrlen);
132         freeaddrinfo(res);
133         free(base);
134 }
135
136 static void
137 in_len2mask(struct in_addr *mask, u_int len)
138 {
139         u_int i;
140         u_char *p;
141
142         p = (u_char *)mask;
143         memset(mask, 0, sizeof(*mask));
144         for (i = 0; i < len / NBBY; i++)
145                 p[i] = 0xff;
146         if (len % NBBY)
147                 p[i] = (0xff00 >> (len % NBBY)) & 0xff;
148 }
149
150 static u_int
151 in_mask2len(struct in_addr *mask)
152 {
153         u_int x, y;
154         u_char *p;
155
156         p = (u_char *)mask;
157         for (x = 0; x < sizeof(*mask); x++) {
158                 if (p[x] != 0xff)
159                         break;
160         }
161         y = 0;
162         if (x < sizeof(*mask)) {
163                 for (y = 0; y < NBBY; y++) {
164                         if ((p[x] & (0x80 >> y)) == 0)
165                                 break;
166                 }
167         }
168         return x * NBBY + y;
169 }
170
171 static void
172 in6_prefixlen2mask(struct in6_addr *maskp, int len)
173 {
174         static const u_char maskarray[NBBY] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff};
175         int bytelen, bitlen, i;
176
177         /* sanity check */
178         if (len < 0 || len > 128) {
179                 errx(1, "in6_prefixlen2mask: invalid prefix length(%d)\n",
180                     len);
181                 return;
182         }
183
184         memset(maskp, 0, sizeof(*maskp));
185         bytelen = len / NBBY;
186         bitlen = len % NBBY;
187         for (i = 0; i < bytelen; i++)
188                 maskp->s6_addr[i] = 0xff;
189         if (bitlen)
190                 maskp->s6_addr[bytelen] = maskarray[bitlen - 1];
191 }
192
193 static int
194 in6_mask2len(struct in6_addr *mask, u_char *lim0)
195 {
196         int x = 0, y;
197         u_char *lim = lim0, *p;
198
199         /* ignore the scope_id part */
200         if (lim0 == NULL || lim0 - (u_char *)mask > sizeof(*mask))
201                 lim = (u_char *)mask + sizeof(*mask);
202         for (p = (u_char *)mask; p < lim; x++, p++) {
203                 if (*p != 0xff)
204                         break;
205         }
206         y = 0;
207         if (p < lim) {
208                 for (y = 0; y < NBBY; y++) {
209                         if ((*p & (0x80 >> y)) == 0)
210                                 break;
211                 }
212         }
213
214         /*
215          * when the limit pointer is given, do a stricter check on the
216          * remaining bits.
217          */
218         if (p < lim) {
219                 if (y != 0 && (*p & (0x00ff >> y)) != 0)
220                         return -1;
221                 for (p = p + 1; p < lim; p++)
222                         if (*p != 0)
223                                 return -1;
224         }
225
226         return x * NBBY + y;
227 }
228
229 static bool
230 parse_ip(struct allowedip *aip, const char *value)
231 {
232         struct addrinfo hints, *res;
233         int err;
234
235         bzero(&aip->a_addr, sizeof(aip->a_addr));
236         bzero(&hints, sizeof(hints));
237         hints.ai_family = AF_UNSPEC;
238         hints.ai_flags = AI_NUMERICHOST;
239         err = getaddrinfo(value, NULL, &hints, &res);
240         if (err)
241                 errx(1, "%s", gai_strerror(err));
242
243         memcpy(&aip->a_addr, res->ai_addr, res->ai_addrlen);
244
245         freeaddrinfo(res);
246         return (true);
247 }
248
249 static void
250 sa_ntop(const struct sockaddr *sa, char *buf, int *port)
251 {
252         const struct sockaddr_in *sin;
253         const struct sockaddr_in6 *sin6;
254         int err;
255
256         err = getnameinfo(sa, sa->sa_len, buf, INET6_ADDRSTRLEN, NULL,
257             0, NI_NUMERICHOST);
258
259         if (sa->sa_family == AF_INET) {
260                 sin = (const struct sockaddr_in *)sa;
261                 if (port)
262                         *port = sin->sin_port;
263         } else if (sa->sa_family == AF_INET6) {
264                 sin6 = (const struct sockaddr_in6 *)sa;
265                 if (port)
266                         *port = sin6->sin6_port;
267         }
268
269         if (err)
270                 errx(1, "%s", gai_strerror(err));
271 }
272
273 static void
274 dump_peer(const nvlist_t *nvl_peer)
275 {
276         const void *key;
277         const struct allowedip *aips;
278         const struct sockaddr *endpoint;
279         char outbuf[WG_MAX_STRLEN];
280         char addr_buf[INET6_ADDRSTRLEN];
281         size_t size;
282         int count, port;
283
284         printf("[Peer]\n");
285         if (nvlist_exists_binary(nvl_peer, "public-key")) {
286                 key = nvlist_get_binary(nvl_peer, "public-key", &size);
287                 b64_ntop((const uint8_t *)key, size, outbuf, WG_MAX_STRLEN);
288                 printf("PublicKey = %s\n", outbuf);
289         }
290         if (nvlist_exists_binary(nvl_peer, "endpoint")) {
291                 endpoint = nvlist_get_binary(nvl_peer, "endpoint", &size);
292                 sa_ntop(endpoint, addr_buf, &port);
293                 printf("Endpoint = %s:%d\n", addr_buf, ntohs(port));
294         }
295
296         if (!nvlist_exists_binary(nvl_peer, "allowed-ips"))
297                 return;
298         aips = nvlist_get_binary(nvl_peer, "allowed-ips", &size);
299         if (size == 0 || size % sizeof(struct allowedip) != 0) {
300                 errx(1, "size %zu not integer multiple of allowedip", size);
301         }
302         printf("AllowedIPs = ");
303         count = size / sizeof(struct allowedip);
304         for (int i = 0; i < count; i++) {
305                 int mask;
306                 sa_family_t family;
307                 void *bitmask;
308                 struct sockaddr *sa;
309
310                 sa = __DECONST(void *, &aips[i].a_addr);
311                 bitmask = __DECONST(void *,
312                     ((const struct sockaddr *)&aips->a_mask)->sa_data);
313                 family = aips[i].a_addr.ss_family;
314                 getnameinfo(sa, sa->sa_len, addr_buf, INET6_ADDRSTRLEN, NULL,
315                     0, NI_NUMERICHOST);
316                 if (family == AF_INET)
317                         mask = in_mask2len(bitmask);
318                 else if (family == AF_INET6)
319                         mask = in6_mask2len(bitmask, NULL);
320                 else
321                         errx(1, "bad family in peer %d\n", family);
322                 printf("%s/%d", addr_buf, mask);
323                 if (i < count -1)
324                         printf(", ");
325         }
326         printf("\n");
327 }
328
329 static int
330 get_nvl_out_size(int sock, u_long op, size_t *size)
331 {
332         struct ifdrv ifd;
333         int err;
334
335         memset(&ifd, 0, sizeof(ifd));
336
337         strlcpy(ifd.ifd_name, name, sizeof(ifd.ifd_name));
338         ifd.ifd_cmd = op;
339         ifd.ifd_len = 0;
340         ifd.ifd_data = NULL;
341
342         err = ioctl(sock, SIOCGDRVSPEC, &ifd);
343         if (err)
344                 return (err);
345         *size = ifd.ifd_len;
346         return (0);
347 }
348
349 static int
350 do_cmd(int sock, u_long op, void *arg, size_t argsize, int set)
351 {
352         struct ifdrv ifd;
353
354         memset(&ifd, 0, sizeof(ifd));
355
356         strlcpy(ifd.ifd_name, name, sizeof(ifd.ifd_name));
357         ifd.ifd_cmd = op;
358         ifd.ifd_len = argsize;
359         ifd.ifd_data = arg;
360
361         return (ioctl(sock, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd));
362 }
363
364 static
365 DECL_CMD_FUNC(peerlist, val, d)
366 {
367         size_t size, peercount;
368         void *packed;
369         const nvlist_t *nvl, *nvl_peer;
370         const nvlist_t *const *nvl_peerlist;
371
372         if (get_nvl_out_size(s, WGC_GET, &size))
373                 errx(1, "can't get peer list size");
374         if ((packed = malloc(size)) == NULL)
375                 errx(1, "malloc failed for peer list");
376         if (do_cmd(s, WGC_GET, packed, size, 0))
377                 errx(1, "failed to obtain peer list");
378
379         nvl = nvlist_unpack(packed, size, 0);
380         if (!nvlist_exists_nvlist_array(nvl, "peer-list"))
381                 return;
382         nvl_peerlist = nvlist_get_nvlist_array(nvl, "peer-list", &peercount);
383
384         for (int i = 0; i < peercount; i++, nvl_peerlist++) {
385                 nvl_peer = *nvl_peerlist;
386                 dump_peer(nvl_peer);
387         }
388 }
389
390 static void
391 peerfinish(int s, void *arg)
392 {
393         nvlist_t *nvl, **nvl_array;
394         void *packed;
395         size_t size;
396
397         if ((nvl = nvlist_create(0)) == NULL)
398                 errx(1, "failed to allocate nvlist");
399         if ((nvl_array = calloc(sizeof(void *), 1)) == NULL)
400                 errx(1, "failed to allocate nvl_array");
401         if (!nvlist_exists_binary(nvl_params, "public-key"))
402                 errx(1, "must specify a public-key for adding peer");
403         if (!nvlist_exists_binary(nvl_params, "endpoint"))
404                 errx(1, "must specify an endpoint for adding peer");
405         if (allowed_ips_count == 0)
406                 errx(1, "must specify at least one range of allowed-ips to add a peer");
407
408         nvl_array[0] = nvl_params;
409         nvlist_add_nvlist_array(nvl, "peer-list", (const nvlist_t * const *)nvl_array, 1);
410         packed = nvlist_pack(nvl, &size);
411
412         if (do_cmd(s, WGC_SET, packed, size, true))
413                 errx(1, "failed to install peer");
414 }
415
416 static
417 DECL_CMD_FUNC(peerstart, val, d)
418 {
419         do_peer = true;
420         callback_register(peerfinish, NULL);
421         allowed_ips = malloc(ALLOWEDIPS_START * sizeof(struct allowedip));
422         allowed_ips_max = ALLOWEDIPS_START;
423         if (allowed_ips == NULL)
424                 errx(1, "failed to allocate array for allowedips");
425 }
426
427 static
428 DECL_CMD_FUNC(setwglistenport, val, d)
429 {
430         struct addrinfo hints, *res;
431         const struct sockaddr_in *sin;
432         const struct sockaddr_in6 *sin6;
433
434         u_long ul;
435         int err;
436
437         bzero(&hints, sizeof(hints));
438         hints.ai_family = AF_UNSPEC;
439         hints.ai_flags = AI_NUMERICHOST;
440         err = getaddrinfo(NULL, val, &hints, &res);
441         if (err)
442                 errx(1, "%s", gai_strerror(err));
443
444         if (res->ai_family == AF_INET) {
445                 sin = (struct sockaddr_in *)res->ai_addr;
446                 ul = sin->sin_port;
447         } else if (res->ai_family == AF_INET6) {
448                 sin6 = (struct sockaddr_in6 *)res->ai_addr;
449                 ul = sin6->sin6_port;
450         } else {
451                 errx(1, "unknown family");
452         }
453         ul = ntohs((u_short)ul);
454         nvlist_add_number(nvl_params, "listen-port", ul);
455 }
456
457 static
458 DECL_CMD_FUNC(setwgprivkey, val, d)
459 {
460         uint8_t key[WG_KEY_LEN];
461
462         if (!key_from_base64(key, val))
463                 errx(1, "invalid key %s", val);
464         nvlist_add_binary(nvl_params, "private-key", key, WG_KEY_LEN);
465 }
466
467 static
468 DECL_CMD_FUNC(setwgpubkey, val, d)
469 {
470         uint8_t key[WG_KEY_LEN];
471
472         if (!do_peer)
473                 errx(1, "setting public key only valid when adding peer");
474
475         if (!key_from_base64(key, val))
476                 errx(1, "invalid key %s", val);
477         nvlist_add_binary(nvl_params, "public-key", key, WG_KEY_LEN);
478 }
479
480 static
481 DECL_CMD_FUNC(setallowedips, val, d)
482 {
483         char *base, *allowedip, *mask;
484         u_long ul;
485         char *endp;
486         struct allowedip *aip;
487
488         if (!do_peer)
489                 errx(1, "setting allowed ip only valid when adding peer");
490         if (allowed_ips_count == allowed_ips_max) {
491                 /* XXX grow array */
492         }
493         aip = &allowed_ips[allowed_ips_count];
494         base = allowedip = strdup(val);
495         mask = index(allowedip, '/');
496         if (mask == NULL)
497                 errx(1, "mask separator not found in allowedip %s", val);
498         *mask = '\0';
499         mask++;
500         parse_ip(aip, allowedip);
501         ul = strtoul(mask, &endp, 0);
502         if (*endp != '\0')
503                 errx(1, "invalid value for allowedip mask");
504         bzero(&aip->a_mask, sizeof(aip->a_mask));
505         if (aip->a_addr.ss_family == AF_INET)
506                 in_len2mask((struct in_addr *)&((struct sockaddr *)&aip->a_mask)->sa_data, ul);
507         else if (aip->a_addr.ss_family == AF_INET6)
508                 in6_prefixlen2mask((struct in6_addr *)&((struct sockaddr *)&aip->a_mask)->sa_data, ul);
509         else
510                 errx(1, "invalid address family %d\n", aip->a_addr.ss_family);
511         allowed_ips_count++;
512         if (allowed_ips_count > 1)
513                 nvlist_free_binary(nvl_params, "allowed-ips");
514         nvlist_add_binary(nvl_params, "allowed-ips", allowed_ips,
515                                           allowed_ips_count*sizeof(*aip));
516
517         dump_peer(nvl_params);
518         free(base);
519 }
520
521 static
522 DECL_CMD_FUNC(setendpoint, val, d)
523 {
524         if (!do_peer)
525                 errx(1, "setting endpoint only valid when adding peer");
526         parse_endpoint(val);
527 }
528
529 static void
530 wireguard_status(int s)
531 {
532         size_t size;
533         void *packed;
534         nvlist_t *nvl;
535         char buf[WG_KEY_LEN_BASE64];
536         const void *key;
537         uint16_t listen_port;
538
539         if (get_nvl_out_size(s, WGC_GET, &size))
540                 return;
541         if ((packed = malloc(size)) == NULL)
542                 return;
543         if (do_cmd(s, WGC_GET, packed, size, 0))
544                 return;
545         nvl = nvlist_unpack(packed, size, 0);
546         if (nvlist_exists_number(nvl, "listen-port")) {
547                 listen_port = nvlist_get_number(nvl, "listen-port");
548                 printf("\tlisten-port: %d\n", listen_port);
549         }
550         if (nvlist_exists_binary(nvl, "private-key")) {
551                 key = nvlist_get_binary(nvl, "private-key", &size);
552                 b64_ntop((const uint8_t *)key, size, buf, WG_MAX_STRLEN);
553                 printf("\tprivate-key: %s\n", buf);
554         }
555         if (nvlist_exists_binary(nvl, "public-key")) {
556                 key = nvlist_get_binary(nvl, "public-key", &size);
557                 b64_ntop((const uint8_t *)key, size, buf, WG_MAX_STRLEN);
558                 printf("\tpublic-key:  %s\n", buf);
559         }
560 }
561
562 static struct cmd wireguard_cmds[] = {
563     DEF_CLONE_CMD_ARG("listen-port",  setwglistenport),
564     DEF_CLONE_CMD_ARG("private-key",  setwgprivkey),
565     DEF_CMD("peer-list",  0, peerlist),
566     DEF_CMD("peer",  0, peerstart),
567     DEF_CMD_ARG("public-key",  setwgpubkey),
568     DEF_CMD_ARG("allowed-ips",  setallowedips),
569     DEF_CMD_ARG("endpoint",  setendpoint),
570 };
571
572 static struct afswtch af_wireguard = {
573         .af_name        = "af_wireguard",
574         .af_af          = AF_UNSPEC,
575         .af_other_status = wireguard_status,
576 };
577
578 static void
579 wg_create(int s, struct ifreq *ifr)
580 {
581         struct iovec iov;
582         void *packed;
583         size_t size;
584
585         setproctitle("ifconfig %s create ...\n", name);
586         if (!nvlist_exists_number(nvl_params, "listen-port"))
587                 goto legacy;
588         if (!nvlist_exists_binary(nvl_params, "private-key"))
589                 goto legacy;
590
591         packed = nvlist_pack(nvl_params, &size);
592         if (packed == NULL)
593                 errx(1, "failed to setup create request");
594         iov.iov_len = size;
595         iov.iov_base = packed;
596         ifr->ifr_data = (caddr_t)&iov;
597         if (ioctl(s, SIOCIFCREATE2, ifr) < 0)
598                 err(1, "SIOCIFCREATE2");
599         return;
600 legacy:
601         ifr->ifr_data == NULL;
602         if (ioctl(s, SIOCIFCREATE, ifr) < 0)
603                 err(1, "SIOCIFCREATE");
604 }
605
606 static __constructor void
607 wireguard_ctor(void)
608 {
609         int i;
610
611         nvl_params = nvlist_create(0);
612         for (i = 0; i < nitems(wireguard_cmds);  i++)
613                 cmd_register(&wireguard_cmds[i]);
614         af_register(&af_wireguard);
615         clone_setdefcallback_prefix("wg", wg_create);
616 }
617
618 #endif