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 #include <sys/ioctl.h> 65 66 #include <net/if.h> 67 68 #include <err.h> 69 #include <errno.h> 70 #include <fcntl.h> 71 #include <stdio.h> 72 #include <stdlib.h> 73 #include <string.h> 74 #include <unistd.h> 75 76 #include "libifconfig.h" 77 #include "libifconfig_internal.h" 78 79 80 ifconfig_handle_t * 81 ifconfig_open(void) 82 { 83 struct ifconfig_handle *h; 84 85 h = calloc(1, sizeof(*h)); 86 for (int i = 0; i <= AF_MAX; i++) { 87 h->sockets[i] = -1; 88 } 89 return (h); 90 } 91 92 void 93 ifconfig_close(ifconfig_handle_t *h) 94 { 95 96 for (int i = 0; i <= AF_MAX; i++) { 97 if (h->sockets[i] != -1) { 98 (void)close(h->sockets[i]); 99 } 100 } 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_get_description(ifconfig_handle_t *h, const char *name, 127 char **description) 128 { 129 struct ifreq ifr; 130 char *descr; 131 size_t descrlen; 132 133 descr = NULL; 134 descrlen = 64; 135 memset(&ifr, 0, sizeof(ifr)); 136 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 137 138 for (;;) { 139 if ((descr = reallocf(descr, descrlen)) == NULL) { 140 h->error.errtype = OTHER; 141 h->error.errcode = ENOMEM; 142 return (-1); 143 } 144 145 ifr.ifr_buffer.buffer = descr; 146 ifr.ifr_buffer.length = descrlen; 147 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFDESCR, &ifr) != 0) { 148 return (-1); 149 } 150 151 if (ifr.ifr_buffer.buffer == descr) { 152 if (strlen(descr) > 0) { 153 *description = strdup(descr); 154 free(descr); 155 return (0); 156 } 157 } else if (ifr.ifr_buffer.length > descrlen) { 158 descrlen = ifr.ifr_buffer.length; 159 continue; 160 } 161 break; 162 } 163 free(descr); 164 h->error.errtype = OTHER; 165 h->error.errcode = 0; 166 return (-1); 167 } 168 169 int 170 ifconfig_set_description(ifconfig_handle_t *h, const char *name, 171 const char *newdescription) 172 { 173 struct ifreq ifr; 174 int desclen; 175 176 memset(&ifr, 0, sizeof(ifr)); 177 desclen = strlen(newdescription); 178 179 /* 180 * Unset description if the new description is 0 characters long. 181 * TODO: Decide whether this should be an error condition instead. 182 */ 183 if (desclen == 0) { 184 return (ifconfig_unset_description(h, name)); 185 } 186 187 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 188 ifr.ifr_buffer.length = desclen + 1; 189 ifr.ifr_buffer.buffer = strdup(newdescription); 190 191 if (ifr.ifr_buffer.buffer == NULL) { 192 h->error.errtype = OTHER; 193 h->error.errcode = ENOMEM; 194 return (-1); 195 } 196 197 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFDESCR, 198 &ifr) != 0) { 199 free(ifr.ifr_buffer.buffer); 200 return (-1); 201 } 202 203 free(ifr.ifr_buffer.buffer); 204 return (0); 205 } 206 207 int 208 ifconfig_unset_description(ifconfig_handle_t *h, const char *name) 209 { 210 struct ifreq ifr; 211 212 memset(&ifr, 0, sizeof(ifr)); 213 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 214 ifr.ifr_buffer.length = 0; 215 ifr.ifr_buffer.buffer = NULL; 216 217 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFDESCR, 218 &ifr) < 0) { 219 return (-1); 220 } 221 return (0); 222 } 223 224 int 225 ifconfig_set_name(ifconfig_handle_t *h, const char *name, const char *newname) 226 { 227 struct ifreq ifr; 228 char *tmpname; 229 230 memset(&ifr, 0, sizeof(ifr)); 231 tmpname = strdup(newname); 232 if (tmpname == NULL) { 233 h->error.errtype = OTHER; 234 h->error.errcode = ENOMEM; 235 return (-1); 236 } 237 238 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 239 ifr.ifr_data = tmpname; 240 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFNAME, 241 &ifr) != 0) { 242 free(tmpname); 243 return (-1); 244 } 245 246 free(tmpname); 247 return (0); 248 } 249 250 int 251 ifconfig_set_mtu(ifconfig_handle_t *h, const char *name, const int mtu) 252 { 253 struct ifreq ifr; 254 255 memset(&ifr, 0, sizeof(ifr)); 256 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 257 ifr.ifr_mtu = mtu; 258 259 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFMTU, 260 &ifr) < 0) { 261 return (-1); 262 } 263 264 return (0); 265 } 266 267 int 268 ifconfig_get_mtu(ifconfig_handle_t *h, const char *name, int *mtu) 269 { 270 struct ifreq ifr; 271 272 memset(&ifr, 0, sizeof(ifr)); 273 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 274 275 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFMTU, 276 &ifr) == -1) { 277 return (-1); 278 } 279 280 *mtu = ifr.ifr_mtu; 281 return (0); 282 } 283 284 int 285 ifconfig_set_metric(ifconfig_handle_t *h, const char *name, const int mtu) 286 { 287 struct ifreq ifr; 288 289 memset(&ifr, 0, sizeof(ifr)); 290 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 291 ifr.ifr_mtu = mtu; 292 293 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFMETRIC, 294 &ifr) < 0) { 295 return (-1); 296 } 297 298 return (0); 299 } 300 301 int 302 ifconfig_get_metric(ifconfig_handle_t *h, const char *name, int *metric) 303 { 304 struct ifreq ifr; 305 306 memset(&ifr, 0, sizeof(ifr)); 307 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 308 309 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFMETRIC, 310 &ifr) == -1) { 311 return (-1); 312 } 313 314 *metric = ifr.ifr_metric; 315 return (0); 316 } 317 318 int 319 ifconfig_set_capability(ifconfig_handle_t *h, const char *name, 320 const int capability) 321 { 322 struct ifreq ifr; 323 struct ifconfig_capabilities ifcap; 324 int flags, value; 325 326 memset(&ifr, 0, sizeof(ifr)); 327 328 if (ifconfig_get_capability(h, name, 329 &ifcap) != 0) { 330 return (-1); 331 } 332 333 value = capability; 334 flags = ifcap.curcap; 335 if (value < 0) { 336 value = -value; 337 flags &= ~value; 338 } else { 339 flags |= value; 340 } 341 flags &= ifcap.reqcap; 342 343 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 344 345 /* 346 * TODO: Verify that it's safe to not have ifr.ifr_curcap 347 * set for this request. 348 */ 349 ifr.ifr_reqcap = flags; 350 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCSIFCAP, 351 &ifr) < 0) { 352 return (-1); 353 } 354 return (0); 355 } 356 357 int 358 ifconfig_get_capability(ifconfig_handle_t *h, const char *name, 359 struct ifconfig_capabilities *capability) 360 { 361 struct ifreq ifr; 362 363 memset(&ifr, 0, sizeof(ifr)); 364 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 365 366 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCGIFCAP, 367 &ifr) < 0) { 368 return (-1); 369 } 370 capability->curcap = ifr.ifr_curcap; 371 capability->reqcap = ifr.ifr_reqcap; 372 return (0); 373 } 374 375 int 376 ifconfig_destroy_interface(ifconfig_handle_t *h, const char *name) 377 { 378 struct ifreq ifr; 379 380 memset(&ifr, 0, sizeof(ifr)); 381 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 382 383 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCIFDESTROY, 384 &ifr) < 0) { 385 return (-1); 386 } 387 return (0); 388 } 389 390 int 391 ifconfig_create_interface(ifconfig_handle_t *h, const char *name, char **ifname) 392 { 393 struct ifreq ifr; 394 395 memset(&ifr, 0, sizeof(ifr)); 396 (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 397 398 /* 399 * TODO: 400 * Insert special snowflake handling here. See GitHub issue #12 for details. 401 * In the meantime, hard-nosupport interfaces that need special handling. 402 */ 403 if ((strncmp(name, "wlan", 404 strlen("wlan")) == 0) || 405 (strncmp(name, "vlan", 406 strlen("vlan")) == 0) || 407 (strncmp(name, "vxlan", 408 strlen("vxlan")) == 0)) { 409 h->error.errtype = OTHER; 410 h->error.errcode = ENOSYS; 411 return (-1); 412 } 413 414 /* No special handling for this interface type. */ 415 if (ifconfig_ioctlwrap(h, AF_LOCAL, SIOCIFCREATE2, &ifr) < 0) { 416 return (-1); 417 } 418 419 *ifname = strdup(ifr.ifr_name); 420 return (0); 421 } 422