1 /* 2 * Copyright (c) 2016, Marie Helene Kvello-Aune 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without modification, 6 * are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * thislist of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation and/or 13 * other materials provided with the distribution. 14 * 15 * 3. Neither the name of the copyright holder nor the names of its contributors 16 * may be used to endorse or promote products derived from this software without 17 * specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * 30 * $FreeBSD$ 31 */ 32 33 /* 34 * Copyright (c) 1983, 1993 35 * The Regents of the University of California. All rights reserved. 36 * 37 * Redistribution and use in source and binary forms, with or without 38 * modification, are permitted provided that the following conditions 39 * are met: 40 * 1. Redistributions of source code must retain the above copyright 41 * notice, this list of conditions and the following disclaimer. 42 * 2. Redistributions in binary form must reproduce the above copyright 43 * notice, this list of conditions and the following disclaimer in the 44 * documentation and/or other materials provided with the distribution. 45 * 3. Neither the name of the University nor the names of its contributors 46 * may be used to endorse or promote products derived from this software 47 * without specific prior written permission. 48 * 49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 59 * SUCH DAMAGE. 60 * 61 * $FreeBSD$ 62 */ 63 64 /* 65 * Copyright 1996 Massachusetts Institute of Technology 66 * 67 * Permission to use, copy, modify, and distribute this software and 68 * its documentation for any purpose and without fee is hereby 69 * granted, provided that both the above copyright notice and this 70 * permission notice appear in all copies, that both the above 71 * copyright notice and this permission notice appear in all 72 * supporting documentation, and that the name of M.I.T. not be used 73 * in advertising or publicity pertaining to distribution of the 74 * software without specific, written prior permission. M.I.T. makes 75 * no representations about the suitability of this software for any 76 * purpose. It is provided "as is" without express or implied 77 * warranty. 78 * 79 * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 80 * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 81 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 82 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 83 * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 84 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 85 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 86 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 87 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 88 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 89 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 90 * SUCH DAMAGE. 91 * 92 * $FreeBSD$ 93 */ 94 95 #include <sys/types.h> 96 #include <sys/ioctl.h> 97 #include <sys/sysctl.h> 98 99 #include <net/if.h> 100 #include <net/if_mib.h> 101 102 #include <err.h> 103 #include <errno.h> 104 #include <fcntl.h> 105 #include <stdio.h> 106 #include <stdlib.h> 107 #include <string.h> 108 #include <unistd.h> 109 110 #include "libifconfig.h" 111 #include "libifconfig_internal.h" 112 113 114 ifconfig_handle_t * 115 ifconfig_open(void) 116 { 117 struct ifconfig_handle *h; 118 119 h = calloc(1, sizeof(*h)); 120 for (int i = 0; i <= AF_MAX; i++) { 121 h->sockets[i] = -1; 122 } 123 return (h); 124 } 125 126 void 127 ifconfig_close(ifconfig_handle_t *h) 128 { 129 130 for (int i = 0; i <= AF_MAX; i++) { 131 if (h->sockets[i] != -1) { 132 (void)close(h->sockets[i]); 133 } 134 } 135 free(h); 136 } 137 138 ifconfig_errtype 139 ifconfig_err_errtype(ifconfig_handle_t *h) 140 { 141 142 return (h->error.errtype); 143 } 144 145 int 146 ifconfig_err_errno(ifconfig_handle_t *h) 147 { 148 149 return (h->error.errcode); 150 } 151 152 unsigned long 153 ifconfig_err_ioctlreq(ifconfig_handle_t *h) 154 { 155 156 return (h->error.ioctl_request); 157 } 158 159 int 160 ifconfig_get_description(ifconfig_handle_t *h, const char *name, 161 char **description) 162 { 163 struct ifreq ifr; 164 char *descr; 165 size_t descrlen; 166 167 descr = NULL; 168 descrlen = 64; 169 memset(&ifr, 0, sizeof(ifr)); 170 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 171 172 for (;;) { 173 if ((descr = reallocf(descr, descrlen)) == NULL) { 174 h->error.errtype = OTHER; 175 h->error.errcode = ENOMEM; 176 return (-1); 177 } 178 179 ifr.ifr_buffer.buffer = descr; 180 ifr.ifr_buffer.length = descrlen; 181 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFDESCR, &ifr) != 0) { 182 return (-1); 183 } 184 185 if (ifr.ifr_buffer.buffer == descr) { 186 if (strlen(descr) > 0) { 187 *description = strdup(descr); 188 free(descr); 189 return (0); 190 } 191 } else if (ifr.ifr_buffer.length > descrlen) { 192 descrlen = ifr.ifr_buffer.length; 193 continue; 194 } 195 break; 196 } 197 free(descr); 198 h->error.errtype = OTHER; 199 h->error.errcode = 0; 200 return (-1); 201 } 202 203 int 204 ifconfig_set_description(ifconfig_handle_t *h, const char *name, 205 const char *newdescription) 206 { 207 struct ifreq ifr; 208 int desclen; 209 210 memset(&ifr, 0, sizeof(ifr)); 211 desclen = strlen(newdescription); 212 213 /* 214 * Unset description if the new description is 0 characters long. 215 * TODO: Decide whether this should be an error condition instead. 216 */ 217 if (desclen == 0) { 218 return (ifconfig_unset_description(h, name)); 219 } 220 221 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 222 ifr.ifr_buffer.length = desclen + 1; 223 ifr.ifr_buffer.buffer = strdup(newdescription); 224 225 if (ifr.ifr_buffer.buffer == NULL) { 226 h->error.errtype = OTHER; 227 h->error.errcode = ENOMEM; 228 return (-1); 229 } 230 231 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFDESCR, 232 &ifr) != 0) { 233 free(ifr.ifr_buffer.buffer); 234 return (-1); 235 } 236 237 free(ifr.ifr_buffer.buffer); 238 return (0); 239 } 240 241 int 242 ifconfig_unset_description(ifconfig_handle_t *h, const char *name) 243 { 244 struct ifreq ifr; 245 246 memset(&ifr, 0, sizeof(ifr)); 247 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 248 ifr.ifr_buffer.length = 0; 249 ifr.ifr_buffer.buffer = NULL; 250 251 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFDESCR, 252 &ifr) < 0) { 253 return (-1); 254 } 255 return (0); 256 } 257 258 int 259 ifconfig_set_name(ifconfig_handle_t *h, const char *name, const char *newname) 260 { 261 struct ifreq ifr; 262 char *tmpname; 263 264 memset(&ifr, 0, sizeof(ifr)); 265 tmpname = strdup(newname); 266 if (tmpname == NULL) { 267 h->error.errtype = OTHER; 268 h->error.errcode = ENOMEM; 269 return (-1); 270 } 271 272 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 273 ifr.ifr_data = tmpname; 274 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFNAME, 275 &ifr) != 0) { 276 free(tmpname); 277 return (-1); 278 } 279 280 free(tmpname); 281 return (0); 282 } 283 284 int 285 ifconfig_get_orig_name(ifconfig_handle_t *h, const char *ifname, 286 char **orig_name) 287 { 288 struct ifmibdata ifmd; 289 size_t len; 290 int name[6]; 291 int i, maxifno; 292 293 name[0] = CTL_NET; 294 name[1] = PF_LINK; 295 name[2] = NETLINK_GENERIC; 296 name[3] = IFMIB_SYSTEM; 297 name[4] = IFMIB_IFCOUNT; 298 299 len = sizeof maxifno; 300 if (sysctl(name, 5, &maxifno, &len, 0, 0) < 0) { 301 h->error.errtype = OTHER; 302 h->error.errcode = errno; 303 return (-1); 304 } 305 306 name[3] = IFMIB_IFDATA; 307 name[5] = IFDATA_GENERAL; 308 for (i = 1; i <= maxifno; i++) { 309 len = sizeof ifmd; 310 name[4] = i; 311 if (sysctl(name, 6, &ifmd, &len, 0, 0) < 0) { 312 if (errno == ENOENT) 313 continue; 314 315 goto fail; 316 } 317 318 if (strncmp(ifmd.ifmd_name, ifname, IFNAMSIZ) != 0) 319 continue; 320 321 len = 0; 322 name[5] = IFDATA_DRIVERNAME; 323 if (sysctl(name, 6, NULL, &len, 0, 0) < 0) 324 goto fail; 325 326 *orig_name = malloc(len); 327 if (*orig_name == NULL) 328 goto fail; 329 330 if (sysctl(name, 6, *orig_name, &len, 0, 0) < 0) { 331 free(*orig_name); 332 *orig_name = NULL; 333 goto fail; 334 } 335 336 return (0); 337 } 338 339 fail: 340 h->error.errtype = OTHER; 341 h->error.errcode = (i <= maxifno) ? errno : ENOENT; 342 return (-1); 343 } 344 345 int 346 ifconfig_set_mtu(ifconfig_handle_t *h, const char *name, const int mtu) 347 { 348 struct ifreq ifr; 349 350 memset(&ifr, 0, sizeof(ifr)); 351 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 352 ifr.ifr_mtu = mtu; 353 354 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFMTU, 355 &ifr) < 0) { 356 return (-1); 357 } 358 359 return (0); 360 } 361 362 int 363 ifconfig_get_mtu(ifconfig_handle_t *h, const char *name, int *mtu) 364 { 365 struct ifreq ifr; 366 367 memset(&ifr, 0, sizeof(ifr)); 368 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 369 370 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFMTU, 371 &ifr) == -1) { 372 return (-1); 373 } 374 375 *mtu = ifr.ifr_mtu; 376 return (0); 377 } 378 379 int 380 ifconfig_set_metric(ifconfig_handle_t *h, const char *name, const int mtu) 381 { 382 struct ifreq ifr; 383 384 memset(&ifr, 0, sizeof(ifr)); 385 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 386 ifr.ifr_mtu = mtu; 387 388 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFMETRIC, 389 &ifr) < 0) { 390 return (-1); 391 } 392 393 return (0); 394 } 395 396 int 397 ifconfig_get_metric(ifconfig_handle_t *h, const char *name, int *metric) 398 { 399 struct ifreq ifr; 400 401 memset(&ifr, 0, sizeof(ifr)); 402 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 403 404 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFMETRIC, 405 &ifr) == -1) { 406 return (-1); 407 } 408 409 *metric = ifr.ifr_metric; 410 return (0); 411 } 412 413 int 414 ifconfig_set_capability(ifconfig_handle_t *h, const char *name, 415 const int capability) 416 { 417 struct ifreq ifr; 418 struct ifconfig_capabilities ifcap; 419 int flags, value; 420 421 memset(&ifr, 0, sizeof(ifr)); 422 423 if (ifconfig_get_capability(h, name, 424 &ifcap) != 0) { 425 return (-1); 426 } 427 428 value = capability; 429 flags = ifcap.curcap; 430 if (value < 0) { 431 value = -value; 432 flags &= ~value; 433 } else { 434 flags |= value; 435 } 436 flags &= ifcap.reqcap; 437 438 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 439 440 /* 441 * TODO: Verify that it's safe to not have ifr.ifr_curcap 442 * set for this request. 443 */ 444 ifr.ifr_reqcap = flags; 445 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFCAP, 446 &ifr) < 0) { 447 return (-1); 448 } 449 return (0); 450 } 451 452 int 453 ifconfig_get_capability(ifconfig_handle_t *h, const char *name, 454 struct ifconfig_capabilities *capability) 455 { 456 struct ifreq ifr; 457 458 memset(&ifr, 0, sizeof(ifr)); 459 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 460 461 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFCAP, 462 &ifr) < 0) { 463 return (-1); 464 } 465 capability->curcap = ifr.ifr_curcap; 466 capability->reqcap = ifr.ifr_reqcap; 467 return (0); 468 } 469 470 int 471 ifconfig_destroy_interface(ifconfig_handle_t *h, const char *name) 472 { 473 struct ifreq ifr; 474 475 memset(&ifr, 0, sizeof(ifr)); 476 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 477 478 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCIFDESTROY, 479 &ifr) < 0) { 480 return (-1); 481 } 482 return (0); 483 } 484 485 int 486 ifconfig_create_interface(ifconfig_handle_t *h, const char *name, char **ifname) 487 { 488 struct ifreq ifr; 489 490 memset(&ifr, 0, sizeof(ifr)); 491 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 492 493 /* 494 * TODO: 495 * Insert special snowflake handling here. See GitHub issue #12 for details. 496 * In the meantime, hard-nosupport interfaces that need special handling. 497 */ 498 if ((strncmp(name, "wlan", 499 strlen("wlan")) == 0) || 500 (strncmp(name, "vlan", 501 strlen("vlan")) == 0) || 502 (strncmp(name, "vxlan", 503 strlen("vxlan")) == 0)) { 504 h->error.errtype = OTHER; 505 h->error.errcode = ENOSYS; 506 return (-1); 507 } 508 509 /* No special handling for this interface type. */ 510 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCIFCREATE2, &ifr) < 0) { 511 return (-1); 512 } 513 514 *ifname = strdup(ifr.ifr_name); 515 return (0); 516 } 517