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