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.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
33 #include <sys/types.h>
34 #include <sys/ioctl.h>
35 #include <sys/sysctl.h>
38 #include <net/if_mib.h>
39 #include <netinet/in.h>
40 #include <netinet6/in6_var.h>
41 #include <netinet6/nd6.h>
53 #include <net/if_vlan_var.h>
55 #include "libifconfig.h"
56 #include "libifconfig_internal.h"
58 #define NOTAG ((u_short) -1)
61 isnd6defif(ifconfig_handle_t *h, const char *name)
63 struct in6_ndifreq ndifreq;
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) {
72 h->error.errtype = OK;
73 return (ndifreq.ifindex == ifindex);
81 h = calloc(1, sizeof(*h));
86 for (int i = 0; i <= AF_MAX; i++) {
94 ifconfig_close(ifconfig_handle_t *h)
97 for (int i = 0; i <= AF_MAX; i++) {
98 if (h->sockets[i] != -1) {
99 (void)close(h->sockets[i]);
102 freeifaddrs(h->ifap);
107 ifconfig_err_errtype(ifconfig_handle_t *h)
110 return (h->error.errtype);
114 ifconfig_err_errno(ifconfig_handle_t *h)
117 return (h->error.errcode);
121 ifconfig_err_ioctlreq(ifconfig_handle_t *h)
124 return (h->error.ioctl_request);
128 ifconfig_foreach_iface(ifconfig_handle_t *h,
129 ifconfig_foreach_func_t cb, void *udata)
133 ret = ifconfig_getifaddrs(h);
138 for (ifa = h->ifap; ifa; ifa = ifa->ifa_next) {
139 if (ifname != ifa->ifa_name) {
140 ifname = ifa->ifa_name;
145 /* Free ifaddrs so we don't accidentally cache stale data */
146 freeifaddrs(h->ifap);
153 ifconfig_foreach_ifaddr(ifconfig_handle_t *h, struct ifaddrs *ifa,
154 ifconfig_foreach_func_t cb, void *udata)
160 ift->ifa_addr != NULL &&
161 strcmp(ift->ifa_name, ifa->ifa_name) == 0;
162 ift = ift->ifa_next) {
168 ifconfig_get_description(ifconfig_handle_t *h, const char *name,
177 memset(&ifr, 0, sizeof(ifr));
178 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
181 if ((descr = reallocf(descr, descrlen)) == NULL) {
182 h->error.errtype = OTHER;
183 h->error.errcode = ENOMEM;
187 ifr.ifr_buffer.buffer = descr;
188 ifr.ifr_buffer.length = descrlen;
189 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFDESCR, &ifr) != 0) {
194 if (ifr.ifr_buffer.buffer == descr) {
195 if (strlen(descr) > 0) {
196 *description = strdup(descr);
199 if (description == NULL) {
200 h->error.errtype = OTHER;
201 h->error.errcode = ENOMEM;
207 } else if (ifr.ifr_buffer.length > descrlen) {
208 descrlen = ifr.ifr_buffer.length;
214 h->error.errtype = OTHER;
215 h->error.errcode = 0;
220 ifconfig_set_description(ifconfig_handle_t *h, const char *name,
221 const char *newdescription)
226 memset(&ifr, 0, sizeof(ifr));
227 desclen = strlen(newdescription);
230 * Unset description if the new description is 0 characters long.
231 * TODO: Decide whether this should be an error condition instead.
234 return (ifconfig_unset_description(h, name));
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);
241 if (ifr.ifr_buffer.buffer == NULL) {
242 h->error.errtype = OTHER;
243 h->error.errcode = ENOMEM;
247 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFDESCR, &ifr) != 0) {
248 free(ifr.ifr_buffer.buffer);
252 free(ifr.ifr_buffer.buffer);
257 ifconfig_unset_description(ifconfig_handle_t *h, const char *name)
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;
266 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFDESCR, &ifr) < 0) {
273 ifconfig_set_name(ifconfig_handle_t *h, const char *name, const char *newname)
278 memset(&ifr, 0, sizeof(ifr));
279 tmpname = strdup(newname);
280 if (tmpname == NULL) {
281 h->error.errtype = OTHER;
282 h->error.errcode = ENOMEM;
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) {
298 ifconfig_get_orig_name(ifconfig_handle_t *h, const char *ifname,
302 unsigned int ifindex;
305 ifindex = if_nametoindex(ifname);
312 name[2] = NETLINK_GENERIC;
313 name[3] = IFMIB_IFDATA;
315 name[5] = IFDATA_DRIVERNAME;
318 if (sysctl(name, 6, NULL, &len, 0, 0) < 0) {
322 *orig_name = malloc(len);
323 if (*orig_name == NULL) {
327 if (sysctl(name, 6, *orig_name, &len, 0, 0) < 0) {
336 h->error.errtype = OTHER;
337 h->error.errcode = (errno != 0) ? errno : ENOENT;
342 ifconfig_get_fib(ifconfig_handle_t *h, const char *name, int *fib)
346 memset(&ifr, 0, sizeof(ifr));
347 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
349 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFFIB, &ifr) == -1) {
358 ifconfig_set_mtu(ifconfig_handle_t *h, const char *name, const int mtu)
362 memset(&ifr, 0, sizeof(ifr));
363 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
366 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFMTU, &ifr) < 0) {
374 ifconfig_get_mtu(ifconfig_handle_t *h, const char *name, int *mtu)
378 memset(&ifr, 0, sizeof(ifr));
379 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
381 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFMTU, &ifr) == -1) {
390 ifconfig_get_nd6(ifconfig_handle_t *h, const char *name,
391 struct in6_ndireq *nd)
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) {
398 if (isnd6defif(h, name)) {
399 nd->ndi.flags |= ND6_IFF_DEFAULTIF;
400 } else if (h->error.errtype != OK) {
408 ifconfig_set_metric(ifconfig_handle_t *h, const char *name, const int metric)
412 memset(&ifr, 0, sizeof(ifr));
413 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
414 ifr.ifr_metric = metric;
416 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFMETRIC, &ifr) < 0) {
424 ifconfig_get_metric(ifconfig_handle_t *h, const char *name, int *metric)
428 memset(&ifr, 0, sizeof(ifr));
429 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
431 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFMETRIC, &ifr) == -1) {
435 *metric = ifr.ifr_metric;
440 ifconfig_set_capability(ifconfig_handle_t *h, const char *name,
441 const int capability)
444 struct ifconfig_capabilities ifcap;
447 memset(&ifr, 0, sizeof(ifr));
449 if (ifconfig_get_capability(h, name, &ifcap) != 0) {
454 flags = ifcap.curcap;
461 flags &= ifcap.reqcap;
463 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
466 * TODO: Verify that it's safe to not have ifr.ifr_curcap
467 * set for this request.
469 ifr.ifr_reqcap = flags;
470 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFCAP, &ifr) < 0) {
477 ifconfig_get_capability(ifconfig_handle_t *h, const char *name,
478 struct ifconfig_capabilities *capability)
482 memset(&ifr, 0, sizeof(ifr));
483 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
485 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFCAP, &ifr) < 0) {
488 capability->curcap = ifr.ifr_curcap;
489 capability->reqcap = ifr.ifr_reqcap;
494 ifconfig_get_groups(ifconfig_handle_t *h, const char *name,
495 struct ifgroupreq *ifgr)
499 memset(ifgr, 0, sizeof(*ifgr));
500 strlcpy(ifgr->ifgr_name, name, IFNAMSIZ);
502 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFGROUP, ifgr) == -1) {
503 if ((h->error.errcode == EINVAL) ||
504 (h->error.errcode == ENOTTY)) {
511 len = ifgr->ifgr_len;
512 ifgr->ifgr_groups = (struct ifg_req *)malloc(len);
513 if (ifgr->ifgr_groups == NULL) {
516 bzero(ifgr->ifgr_groups, len);
517 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFGROUP, ifgr) == -1) {
525 ifconfig_get_ifstatus(ifconfig_handle_t *h, const char *name,
528 strlcpy(ifs->ifs_name, name, sizeof(ifs->ifs_name));
529 return (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFSTATUS, ifs));
533 ifconfig_destroy_interface(ifconfig_handle_t *h, const char *name)
537 memset(&ifr, 0, sizeof(ifr));
538 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
540 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCIFDESTROY, &ifr) < 0) {
547 ifconfig_create_interface(ifconfig_handle_t *h, const char *name, char **ifname)
551 memset(&ifr, 0, sizeof(ifr));
553 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
557 * Insert special snowflake handling here. See GitHub issue #12 for details.
558 * In the meantime, hard-nosupport interfaces that need special handling.
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;
571 /* No special handling for this interface type. */
572 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCIFCREATE2, &ifr) < 0) {
576 *ifname = strdup(ifr.ifr_name);
577 if (ifname == NULL) {
578 h->error.errtype = OTHER;
579 h->error.errcode = ENOMEM;
587 ifconfig_create_interface_vlan(ifconfig_handle_t *h, const char *name,
588 char **ifname, const char *vlandev, const unsigned short vlantag)
591 struct vlanreq params;
593 if ((vlantag == NOTAG) || (vlandev[0] == '\0')) {
594 // TODO: Add proper error tracking here
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;
604 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCIFCREATE2, &ifr) < 0) {
605 // TODO: Add proper error tracking here
609 *ifname = strdup(ifr.ifr_name);
614 ifconfig_set_vlantag(ifconfig_handle_t *h, const char *name,
615 const char *vlandev, const unsigned short vlantag)
618 struct vlanreq params;
620 bzero(¶ms, sizeof(params));
621 params.vlr_tag = vlantag;
622 strlcpy(params.vlr_parent, vlandev, sizeof(params.vlr_parent));
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) {