1 /*
2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
4 * Copyright (c) 2016-2017, Marie Helene Kvello-Aune. All rights reserved.
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 * 3. Neither the name of the University nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 *
30 * $FreeBSD$
31 */
32
33 #include <sys/types.h>
34 #include <sys/ioctl.h>
35 #include <sys/sysctl.h>
36
37 #include <net/if.h>
38 #include <net/if_mib.h>
39 #include <netinet/in.h>
40 #include <netinet6/in6_var.h>
41 #include <netinet6/nd6.h>
42
43 #include <err.h>
44 #include <errno.h>
45 #include <fcntl.h>
46 #include <ifaddrs.h>
47 #include <stdbool.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <unistd.h>
52
53 #include <net/if_vlan_var.h>
54
55 #include "libifconfig.h"
56 #include "libifconfig_internal.h"
57
58 #define NOTAG ((u_short) -1)
59
60 static bool
isnd6defif(ifconfig_handle_t * h,const char * name)61 isnd6defif(ifconfig_handle_t *h, const char *name)
62 {
63 struct in6_ndifreq ndifreq;
64 unsigned int ifindex;
65
66 memset(&ndifreq, 0, sizeof(ndifreq));
67 strlcpy(ndifreq.ifname, name, sizeof(ndifreq.ifname));
68 ifindex = if_nametoindex(ndifreq.ifname);
69 if (ifconfig_ioctlwrap(h, AF_INET6, SIOCGDEFIFACE_IN6, &ndifreq) < 0) {
70 return (false);
71 }
72 h->error.errtype = OK;
73 return (ndifreq.ifindex == ifindex);
74 }
75
76 ifconfig_handle_t *
ifconfig_open(void)77 ifconfig_open(void)
78 {
79 ifconfig_handle_t *h;
80
81 h = calloc(1, sizeof(*h));
82
83 if (h == NULL) {
84 return (NULL);
85 }
86 for (int i = 0; i <= AF_MAX; i++) {
87 h->sockets[i] = -1;
88 }
89
90 return (h);
91 }
92
93 void
ifconfig_close(ifconfig_handle_t * h)94 ifconfig_close(ifconfig_handle_t *h)
95 {
96
97 for (int i = 0; i <= AF_MAX; i++) {
98 if (h->sockets[i] != -1) {
99 (void)close(h->sockets[i]);
100 }
101 }
102 freeifaddrs(h->ifap);
103 free(h);
104 }
105
106 ifconfig_errtype
ifconfig_err_errtype(ifconfig_handle_t * h)107 ifconfig_err_errtype(ifconfig_handle_t *h)
108 {
109
110 return (h->error.errtype);
111 }
112
113 int
ifconfig_err_errno(ifconfig_handle_t * h)114 ifconfig_err_errno(ifconfig_handle_t *h)
115 {
116
117 return (h->error.errcode);
118 }
119
120 unsigned long
ifconfig_err_ioctlreq(ifconfig_handle_t * h)121 ifconfig_err_ioctlreq(ifconfig_handle_t *h)
122 {
123
124 return (h->error.ioctl_request);
125 }
126
127 int
ifconfig_foreach_iface(ifconfig_handle_t * h,ifconfig_foreach_func_t cb,void * udata)128 ifconfig_foreach_iface(ifconfig_handle_t *h,
129 ifconfig_foreach_func_t cb, void *udata)
130 {
131 int ret;
132
133 ret = ifconfig_getifaddrs(h);
134 if (ret == 0) {
135 struct ifaddrs *ifa;
136 char *ifname = NULL;
137
138 for (ifa = h->ifap; ifa; ifa = ifa->ifa_next) {
139 if (ifname != ifa->ifa_name) {
140 ifname = ifa->ifa_name;
141 cb(h, ifa, udata);
142 }
143 }
144 }
145 /* Free ifaddrs so we don't accidentally cache stale data */
146 freeifaddrs(h->ifap);
147 h->ifap = NULL;
148
149 return (ret);
150 }
151
152 void
ifconfig_foreach_ifaddr(ifconfig_handle_t * h,struct ifaddrs * ifa,ifconfig_foreach_func_t cb,void * udata)153 ifconfig_foreach_ifaddr(ifconfig_handle_t *h, struct ifaddrs *ifa,
154 ifconfig_foreach_func_t cb, void *udata)
155 {
156 struct ifaddrs *ift;
157
158 for (ift = ifa;
159 ift != NULL &&
160 ift->ifa_addr != NULL &&
161 strcmp(ift->ifa_name, ifa->ifa_name) == 0;
162 ift = ift->ifa_next) {
163 cb(h, ift, udata);
164 }
165 }
166
167 int
ifconfig_get_description(ifconfig_handle_t * h,const char * name,char ** description)168 ifconfig_get_description(ifconfig_handle_t *h, const char *name,
169 char **description)
170 {
171 struct ifreq ifr;
172 char *descr;
173 size_t descrlen;
174
175 descr = NULL;
176 descrlen = 64;
177 memset(&ifr, 0, sizeof(ifr));
178 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
179
180 for (;;) {
181 if ((descr = reallocf(descr, descrlen)) == NULL) {
182 h->error.errtype = OTHER;
183 h->error.errcode = ENOMEM;
184 return (-1);
185 }
186
187 ifr.ifr_buffer.buffer = descr;
188 ifr.ifr_buffer.length = descrlen;
189 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFDESCR, &ifr) != 0) {
190 free(descr);
191 return (-1);
192 }
193
194 if (ifr.ifr_buffer.buffer == descr) {
195 if (strlen(descr) > 0) {
196 *description = strdup(descr);
197 free(descr);
198
199 if (description == NULL) {
200 h->error.errtype = OTHER;
201 h->error.errcode = ENOMEM;
202 return (-1);
203 }
204
205 return (0);
206 }
207 } else if (ifr.ifr_buffer.length > descrlen) {
208 descrlen = ifr.ifr_buffer.length;
209 continue;
210 }
211 break;
212 }
213 free(descr);
214 h->error.errtype = OTHER;
215 h->error.errcode = 0;
216 return (-1);
217 }
218
219 int
ifconfig_set_description(ifconfig_handle_t * h,const char * name,const char * newdescription)220 ifconfig_set_description(ifconfig_handle_t *h, const char *name,
221 const char *newdescription)
222 {
223 struct ifreq ifr;
224 int desclen;
225
226 memset(&ifr, 0, sizeof(ifr));
227 desclen = strlen(newdescription);
228
229 /*
230 * Unset description if the new description is 0 characters long.
231 * TODO: Decide whether this should be an error condition instead.
232 */
233 if (desclen == 0) {
234 return (ifconfig_unset_description(h, name));
235 }
236
237 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
238 ifr.ifr_buffer.length = desclen + 1;
239 ifr.ifr_buffer.buffer = strdup(newdescription);
240
241 if (ifr.ifr_buffer.buffer == NULL) {
242 h->error.errtype = OTHER;
243 h->error.errcode = ENOMEM;
244 return (-1);
245 }
246
247 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFDESCR, &ifr) != 0) {
248 free(ifr.ifr_buffer.buffer);
249 return (-1);
250 }
251
252 free(ifr.ifr_buffer.buffer);
253 return (0);
254 }
255
256 int
ifconfig_unset_description(ifconfig_handle_t * h,const char * name)257 ifconfig_unset_description(ifconfig_handle_t *h, const char *name)
258 {
259 struct ifreq ifr;
260
261 memset(&ifr, 0, sizeof(ifr));
262 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
263 ifr.ifr_buffer.length = 0;
264 ifr.ifr_buffer.buffer = NULL;
265
266 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFDESCR, &ifr) < 0) {
267 return (-1);
268 }
269 return (0);
270 }
271
272 int
ifconfig_set_name(ifconfig_handle_t * h,const char * name,const char * newname)273 ifconfig_set_name(ifconfig_handle_t *h, const char *name, const char *newname)
274 {
275 struct ifreq ifr;
276 char *tmpname;
277
278 memset(&ifr, 0, sizeof(ifr));
279 tmpname = strdup(newname);
280 if (tmpname == NULL) {
281 h->error.errtype = OTHER;
282 h->error.errcode = ENOMEM;
283 return (-1);
284 }
285
286 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
287 ifr.ifr_data = tmpname;
288 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFNAME, &ifr) != 0) {
289 free(tmpname);
290 return (-1);
291 }
292
293 free(tmpname);
294 return (0);
295 }
296
297 int
ifconfig_get_orig_name(ifconfig_handle_t * h,const char * ifname,char ** orig_name)298 ifconfig_get_orig_name(ifconfig_handle_t *h, const char *ifname,
299 char **orig_name)
300 {
301 size_t len;
302 unsigned int ifindex;
303 int name[6];
304
305 ifindex = if_nametoindex(ifname);
306 if (ifindex == 0) {
307 goto fail;
308 }
309
310 name[0] = CTL_NET;
311 name[1] = PF_LINK;
312 name[2] = NETLINK_GENERIC;
313 name[3] = IFMIB_IFDATA;
314 name[4] = ifindex;
315 name[5] = IFDATA_DRIVERNAME;
316
317 len = 0;
318 if (sysctl(name, 6, NULL, &len, 0, 0) < 0) {
319 goto fail;
320 }
321
322 *orig_name = malloc(len);
323 if (*orig_name == NULL) {
324 goto fail;
325 }
326
327 if (sysctl(name, 6, *orig_name, &len, 0, 0) < 0) {
328 free(*orig_name);
329 *orig_name = NULL;
330 goto fail;
331 }
332
333 return (0);
334
335 fail:
336 h->error.errtype = OTHER;
337 h->error.errcode = (errno != 0) ? errno : ENOENT;
338 return (-1);
339 }
340
341 int
ifconfig_get_fib(ifconfig_handle_t * h,const char * name,int * fib)342 ifconfig_get_fib(ifconfig_handle_t *h, const char *name, int *fib)
343 {
344 struct ifreq ifr;
345
346 memset(&ifr, 0, sizeof(ifr));
347 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
348
349 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFFIB, &ifr) == -1) {
350 return (-1);
351 }
352
353 *fib = ifr.ifr_fib;
354 return (0);
355 }
356
357 int
ifconfig_set_mtu(ifconfig_handle_t * h,const char * name,const int mtu)358 ifconfig_set_mtu(ifconfig_handle_t *h, const char *name, const int mtu)
359 {
360 struct ifreq ifr;
361
362 memset(&ifr, 0, sizeof(ifr));
363 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
364 ifr.ifr_mtu = mtu;
365
366 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFMTU, &ifr) < 0) {
367 return (-1);
368 }
369
370 return (0);
371 }
372
373 int
ifconfig_get_mtu(ifconfig_handle_t * h,const char * name,int * mtu)374 ifconfig_get_mtu(ifconfig_handle_t *h, const char *name, int *mtu)
375 {
376 struct ifreq ifr;
377
378 memset(&ifr, 0, sizeof(ifr));
379 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
380
381 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFMTU, &ifr) == -1) {
382 return (-1);
383 }
384
385 *mtu = ifr.ifr_mtu;
386 return (0);
387 }
388
389 int
ifconfig_get_nd6(ifconfig_handle_t * h,const char * name,struct in6_ndireq * nd)390 ifconfig_get_nd6(ifconfig_handle_t *h, const char *name,
391 struct in6_ndireq *nd)
392 {
393 memset(nd, 0, sizeof(*nd));
394 strlcpy(nd->ifname, name, sizeof(nd->ifname));
395 if (ifconfig_ioctlwrap(h, AF_INET6, SIOCGIFINFO_IN6, nd) == -1) {
396 return (-1);
397 }
398 if (isnd6defif(h, name)) {
399 nd->ndi.flags |= ND6_IFF_DEFAULTIF;
400 } else if (h->error.errtype != OK) {
401 return (-1);
402 }
403
404 return (0);
405 }
406
407 int
ifconfig_set_metric(ifconfig_handle_t * h,const char * name,const int metric)408 ifconfig_set_metric(ifconfig_handle_t *h, const char *name, const int metric)
409 {
410 struct ifreq ifr;
411
412 memset(&ifr, 0, sizeof(ifr));
413 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
414 ifr.ifr_metric = metric;
415
416 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFMETRIC, &ifr) < 0) {
417 return (-1);
418 }
419
420 return (0);
421 }
422
423 int
ifconfig_get_metric(ifconfig_handle_t * h,const char * name,int * metric)424 ifconfig_get_metric(ifconfig_handle_t *h, const char *name, int *metric)
425 {
426 struct ifreq ifr;
427
428 memset(&ifr, 0, sizeof(ifr));
429 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
430
431 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFMETRIC, &ifr) == -1) {
432 return (-1);
433 }
434
435 *metric = ifr.ifr_metric;
436 return (0);
437 }
438
439 int
ifconfig_set_capability(ifconfig_handle_t * h,const char * name,const int capability)440 ifconfig_set_capability(ifconfig_handle_t *h, const char *name,
441 const int capability)
442 {
443 struct ifreq ifr;
444 struct ifconfig_capabilities ifcap;
445 int flags, value;
446
447 memset(&ifr, 0, sizeof(ifr));
448
449 if (ifconfig_get_capability(h, name, &ifcap) != 0) {
450 return (-1);
451 }
452
453 value = capability;
454 flags = ifcap.curcap;
455 if (value < 0) {
456 value = -value;
457 flags &= ~value;
458 } else {
459 flags |= value;
460 }
461 flags &= ifcap.reqcap;
462
463 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
464
465 /*
466 * TODO: Verify that it's safe to not have ifr.ifr_curcap
467 * set for this request.
468 */
469 ifr.ifr_reqcap = flags;
470 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFCAP, &ifr) < 0) {
471 return (-1);
472 }
473 return (0);
474 }
475
476 int
ifconfig_get_capability(ifconfig_handle_t * h,const char * name,struct ifconfig_capabilities * capability)477 ifconfig_get_capability(ifconfig_handle_t *h, const char *name,
478 struct ifconfig_capabilities *capability)
479 {
480 struct ifreq ifr;
481
482 memset(&ifr, 0, sizeof(ifr));
483 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
484
485 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFCAP, &ifr) < 0) {
486 return (-1);
487 }
488 capability->curcap = ifr.ifr_curcap;
489 capability->reqcap = ifr.ifr_reqcap;
490 return (0);
491 }
492
493 int
ifconfig_get_groups(ifconfig_handle_t * h,const char * name,struct ifgroupreq * ifgr)494 ifconfig_get_groups(ifconfig_handle_t *h, const char *name,
495 struct ifgroupreq *ifgr)
496 {
497 int len;
498
499 memset(ifgr, 0, sizeof(*ifgr));
500 strlcpy(ifgr->ifgr_name, name, IFNAMSIZ);
501
502 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFGROUP, ifgr) == -1) {
503 if ((h->error.errcode == EINVAL) ||
504 (h->error.errcode == ENOTTY)) {
505 return (0);
506 } else {
507 return (-1);
508 }
509 }
510
511 len = ifgr->ifgr_len;
512 ifgr->ifgr_groups = (struct ifg_req *)malloc(len);
513 if (ifgr->ifgr_groups == NULL) {
514 h->error.errtype = OTHER;
515 h->error.errcode = ENOMEM;
516 return (-1);
517 }
518 bzero(ifgr->ifgr_groups, len);
519 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFGROUP, ifgr) == -1) {
520 return (-1);
521 }
522
523 return (0);
524 }
525
526 int
ifconfig_get_ifstatus(ifconfig_handle_t * h,const char * name,struct ifstat * ifs)527 ifconfig_get_ifstatus(ifconfig_handle_t *h, const char *name,
528 struct ifstat *ifs)
529 {
530 strlcpy(ifs->ifs_name, name, sizeof(ifs->ifs_name));
531 return (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFSTATUS, ifs));
532 }
533
534 int
ifconfig_destroy_interface(ifconfig_handle_t * h,const char * name)535 ifconfig_destroy_interface(ifconfig_handle_t *h, const char *name)
536 {
537 struct ifreq ifr;
538
539 memset(&ifr, 0, sizeof(ifr));
540 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
541
542 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCIFDESTROY, &ifr) < 0) {
543 return (-1);
544 }
545 return (0);
546 }
547
548 int
ifconfig_create_interface(ifconfig_handle_t * h,const char * name,char ** ifname)549 ifconfig_create_interface(ifconfig_handle_t *h, const char *name, char **ifname)
550 {
551 struct ifreq ifr;
552
553 memset(&ifr, 0, sizeof(ifr));
554
555 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
556
557 /*
558 * TODO:
559 * Insert special snowflake handling here. See GitHub issue #12 for details.
560 * In the meantime, hard-nosupport interfaces that need special handling.
561 */
562 if ((strncmp(name, "wlan",
563 strlen("wlan")) == 0) ||
564 (strncmp(name, "vlan",
565 strlen("vlan")) == 0) ||
566 (strncmp(name, "vxlan",
567 strlen("vxlan")) == 0)) {
568 h->error.errtype = OTHER;
569 h->error.errcode = ENOSYS;
570 return (-1);
571 }
572
573 /* No special handling for this interface type. */
574 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCIFCREATE2, &ifr) < 0) {
575 return (-1);
576 }
577
578 *ifname = strdup(ifr.ifr_name);
579 if (ifname == NULL) {
580 h->error.errtype = OTHER;
581 h->error.errcode = ENOMEM;
582 return (-1);
583 }
584
585 return (0);
586 }
587
588 int
ifconfig_create_interface_vlan(ifconfig_handle_t * h,const char * name,char ** ifname,const char * vlandev,const unsigned short vlantag)589 ifconfig_create_interface_vlan(ifconfig_handle_t *h, const char *name,
590 char **ifname, const char *vlandev, const unsigned short vlantag)
591 {
592 struct ifreq ifr;
593 struct vlanreq params;
594
595 if ((vlantag == NOTAG) || (vlandev[0] == '\0')) {
596 // TODO: Add proper error tracking here
597 return (-1);
598 }
599
600 bzero(¶ms, sizeof(params));
601 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
602 params.vlr_tag = vlantag;
603 (void)strlcpy(params.vlr_parent, vlandev, sizeof(params.vlr_parent));
604 ifr.ifr_data = (caddr_t)¶ms;
605
606 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCIFCREATE2, &ifr) < 0) {
607 // TODO: Add proper error tracking here
608 return (-1);
609 }
610
611 *ifname = strdup(ifr.ifr_name);
612 return (0);
613 }
614
615 int
ifconfig_set_vlantag(ifconfig_handle_t * h,const char * name,const char * vlandev,const unsigned short vlantag)616 ifconfig_set_vlantag(ifconfig_handle_t *h, const char *name,
617 const char *vlandev, const unsigned short vlantag)
618 {
619 struct ifreq ifr;
620 struct vlanreq params;
621
622 bzero(¶ms, sizeof(params));
623 params.vlr_tag = vlantag;
624 strlcpy(params.vlr_parent, vlandev, sizeof(params.vlr_parent));
625
626 ifr.ifr_data = (caddr_t)¶ms;
627 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
628 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSETVLAN, &ifr) == -1) {
629 return (-1);
630 }
631 return (0);
632 }
633
634 int
ifconfig_list_cloners(ifconfig_handle_t * h,char ** bufp,size_t * lenp)635 ifconfig_list_cloners(ifconfig_handle_t *h, char **bufp, size_t *lenp)
636 {
637 struct if_clonereq ifcr;
638 char *buf;
639
640 memset(&ifcr, 0, sizeof(ifcr));
641 *bufp = NULL;
642 *lenp = 0;
643
644 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCIFGCLONERS, &ifcr) < 0)
645 return (-1);
646
647 buf = malloc(ifcr.ifcr_total * IFNAMSIZ);
648 if (buf == NULL) {
649 h->error.errtype = OTHER;
650 h->error.errcode = ENOMEM;
651 return (-1);
652 }
653
654 ifcr.ifcr_count = ifcr.ifcr_total;
655 ifcr.ifcr_buffer = buf;
656 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCIFGCLONERS, &ifcr) < 0) {
657 free(buf);
658 return (-1);
659 }
660
661 *bufp = buf;
662 *lenp = ifcr.ifcr_total;
663 return (0);
664 }
665