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 58static bool 59isnd6defif(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 74ifconfig_handle_t * 75ifconfig_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 91void 92ifconfig_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 104ifconfig_errtype 105ifconfig_err_errtype(ifconfig_handle_t *h) 106{ 107 108 return (h->error.errtype); 109} 110 111int 112ifconfig_err_errno(ifconfig_handle_t *h) 113{ 114 115 return (h->error.errcode); 116} 117 118unsigned long 119ifconfig_err_ioctlreq(ifconfig_handle_t *h) 120{ 121 122 return (h->error.ioctl_request); 123} 124 125int 126ifconfig_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 150void 151ifconfig_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 165int 166ifconfig_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 217int 218ifconfig_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 254int 255ifconfig_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 270int 271ifconfig_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 295int 296ifconfig_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 333fail: 334 h->error.errtype = OTHER; 335 h->error.errcode = (errno != 0) ? errno : ENOENT; 336 return (-1); 337} 338 339int 340ifconfig_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 355int 356ifconfig_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 371int 372ifconfig_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 387int 388ifconfig_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 405int 406ifconfig_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 421int 422ifconfig_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 437int 438ifconfig_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 474int 475ifconfig_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 491int 492ifconfig_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 524int 525ifconfig_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 532int 533ifconfig_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 546int 547ifconfig_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 586int 587ifconfig_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 613int 614ifconfig_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 632int 633ifconfig_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