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