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 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 * 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 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 105 ifconfig_err_errtype(ifconfig_handle_t *h) 106 { 107 108 return (h->error.errtype); 109 } 110 111 int 112 ifconfig_err_errno(ifconfig_handle_t *h) 113 { 114 115 return (h->error.errcode); 116 } 117 118 unsigned long 119 ifconfig_err_ioctlreq(ifconfig_handle_t *h) 120 { 121 122 return (h->error.ioctl_request); 123 } 124 125 int 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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