Index: lib/libifconfig/Makefile =================================================================== --- lib/libifconfig/Makefile +++ lib/libifconfig/Makefile @@ -0,0 +1,17 @@ +# $FreeBSD$ + +PACKAGE= lib${LIB} +LIB= ifconfig + +SHLIBDIR?= /lib +SHLIB_MAJOR= 1 +SRCS= libifconfig.c libifconfig_internal.c + +INCSDIR= ${INCLUDEDIR} +INCS= libifconfig.h + +#MAN= libifconfig.3 + +CFLAGS+= -I${.CURDIR} + +.include Index: lib/libifconfig/libifconfig.h =================================================================== --- lib/libifconfig/libifconfig.h +++ lib/libifconfig/libifconfig.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2016, Marie Helene Kvello-Aune + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * thislist of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +typedef enum { + OTHER, IOCTL, SOCKET +} libifc_errtype; + +/* + * Opaque definition so calling application can just pass a + * pointer to it for library use. + */ +struct libifc_handle; +typedef struct libifc_handle libifc_handle_t; + +struct libifc_capabilities { + /** Current capabilities (ifconfig prints this as 'options')*/ + int curcap; + /** Requested capabilities (ifconfig prints this as 'capabilities')*/ + int reqcap; +}; + + +/** Retrieves a new state object for use in other API calls. + * Example usage: + *{@code + * // Create state object + * libifc_handle_t *lifh = libifc_open(); + * + * // Do stuff with it + * + * // Dispose of the state object + * libifc_close(lifh); + * lifh = NULL; + *} + */ +libifc_handle_t *libifc_open(void); + +/** Frees resources held in the provided state object. + * @param h The state object to close. + * @see #libifc_open(void) + */ +void libifc_close(libifc_handle_t *h); + +/** Identifies what kind of error occured. */ +libifc_errtype libifc_err_errtype(libifc_handle_t *h); + +/** Retrieves the errno associated with the error, if any. */ +int libifc_err_errno(libifc_handle_t *h); + +/** If error type was IOCTL, this identifies which request failed. */ +unsigned long libifc_err_ioctlreq(libifc_handle_t *h); + +int libifc_get_description(libifc_handle_t *h, const char *name, + char **description); +int libifc_set_description(libifc_handle_t *h, const char *name, + const char *newdescription); +int libifc_unset_description(libifc_handle_t *h, const char *name); +int libifc_set_name(libifc_handle_t *h, const char *name, const char *newname); +int libifc_set_mtu(libifc_handle_t *h, const char *name, const int mtu); +int libifc_get_mtu(libifc_handle_t *h, const char *name, int *mtu); + +int libifc_set_metric(libifc_handle_t *h, const char *name, const int metric); +int libifc_get_metric(libifc_handle_t *h, const char *name, int *metric); + +int libifc_set_capability(libifc_handle_t *h, const char *name, + const int capability); +int libifc_get_capability(libifc_handle_t *h, const char *name, + struct libifc_capabilities *capability); + +/** Destroy a virtual interface + * @param name Interface to destroy + */ +int libifc_destroy_interface(libifc_handle_t *h, const char *name); + +/** Creates a (virtual) interface + * @param name Name of interface to create. Example: bridge or bridge42 + * @param name ifname Is set to actual name of created interface + */ +int libifc_create_interface(libifc_handle_t *h, const char *name, + char **ifname); Index: lib/libifconfig/libifconfig.c =================================================================== --- lib/libifconfig/libifconfig.c +++ lib/libifconfig/libifconfig.c @@ -0,0 +1,400 @@ +/* + * Copyright (c) 2016, Marie Helene Kvello-Aune + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * thislist of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "libifconfig.h" +#include "libifconfig_internal.h" + + +libifc_handle_t * +libifc_open() +{ + struct libifc_handle *h; + + h = calloc(1, sizeof(struct libifc_handle)); + return (h); +} + + +void +libifc_close(libifc_handle_t *h) +{ + if (h->sockets.sdkeys != NULL) { + free(h->sockets.sdkeys); + h->sockets.sdkeys = NULL; + } + if (h->sockets.sdvals != NULL) { + for (int i = 0; i < h->sockets.sdindex; i++) { + (void)close(h->sockets.sdvals[i]); + } + free(h->sockets.sdvals); + h->sockets.sdvals = NULL; + } + h->sockets.sdindex = 0; + free(h); +} + + +libifc_errtype +libifc_err_errtype(libifc_handle_t *h) +{ + return (h->error.errtype); +} + + +int +libifc_err_errno(libifc_handle_t *h) +{ + return (h->error.errcode); +} + + +unsigned long +libifc_err_ioctlreq(libifc_handle_t *h) +{ + return (h->error.ioctl_request); +} + + +int +libifc_get_description(libifc_handle_t *h, const char *name, char **description) +{ + struct ifreq ifr; + char *descr = NULL; + size_t descrlen = 64; + + (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + for (;;) { + if ((descr = reallocf(descr, descrlen)) != NULL) { + ifr.ifr_buffer.buffer = descr; + ifr.ifr_buffer.length = descrlen; + if (libifc_ioctlwrap(h, AF_LOCAL, SIOCGIFDESCR, + &ifr) == 0) { + if (ifr.ifr_buffer.buffer == descr) { + if (strlen(descr) > 0) { + *description = strdup(descr); + free(descr); + return (0); + } + } else if (ifr.ifr_buffer.length > descrlen) { + descrlen = ifr.ifr_buffer.length; + continue; + } + } else { + return (-1); + } + } else { + free(descr); + h->error.errtype = OTHER; + h->error.errcode = ENOMEM; + return (-1); + } + break; + } + free(descr); + h->error.errtype = OTHER; + h->error.errcode = 0; + return (-1); +} + + +int +libifc_set_description(libifc_handle_t *h, const char *name, + const char *newdescription) +{ + struct ifreq ifr; + int desclen; + + desclen = strlen(newdescription); + + /* + * Unset description if the new description is 0 characters long. + * TODO: Decide whether this should be an error condition instead. + */ + if (desclen == 0) { + return (libifc_unset_description(h, name)); + } + + (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + + ifr.ifr_buffer.length = desclen + 1; + ifr.ifr_buffer.buffer = strdup(newdescription); + if (ifr.ifr_buffer.buffer == NULL) { + h->error.errtype = OTHER; + h->error.errcode = ENOMEM; + return (-1); + } + + /* + * TODO: Check whether this ioctl() call truncates or fails when new + * description is too long. If truncates, this function should probably + * have an error condition for this further up. + */ + if (libifc_ioctlwrap_caddr(h, AF_LOCAL, SIOCSIFDESCR, &ifr) != 0) { + if (ifr.ifr_buffer.buffer != NULL) { + free(ifr.ifr_buffer.buffer); + } + return (-1); + } + if (ifr.ifr_buffer.buffer != NULL) { + free(ifr.ifr_buffer.buffer); + } + return (0); +} + + +int libifc_unset_description(libifc_handle_t *h, const char *name) +{ + struct ifreq ifr; + + (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + ifr.ifr_buffer.length = 0; + ifr.ifr_buffer.buffer = NULL; + + if (libifc_ioctlwrap_caddr(h, AF_LOCAL, SIOCSIFDESCR, &ifr) < 0) { + return (-1); + } + return (0); +} + + +int libifc_set_name(libifc_handle_t *h, const char *name, const char *newname) +{ + struct ifreq ifr; + char *tmpname; + + tmpname = strdup(newname); + if (tmpname == NULL) { + h->error.errtype = OTHER; + h->error.errcode = ENOMEM; + return (-1); + } + + (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + ifr.ifr_data = tmpname; + + /* + * TODO: Check whether this ioctl() call truncates or fails when new + * name is too long. If truncates, this function should have an error + * condition for this further up. + */ + if (libifc_ioctlwrap_caddr(h, AF_LOCAL, SIOCSIFNAME, &ifr) != 0) { + free(tmpname); + return (-1); + } + free(tmpname); + return (0); +} + + +int libifc_set_mtu(libifc_handle_t *h, const char *name, const int mtu) +{ + struct ifreq ifr; + + (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + ifr.ifr_mtu = mtu; + if (libifc_ioctlwrap_caddr(h, AF_LOCAL, SIOCSIFMTU, &ifr) < 0) { + return (-1); + } + return (0); +} + + +int libifc_get_mtu(libifc_handle_t *h, const char *name, int *mtu) +{ + struct ifreq ifr; + + (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + if (libifc_ioctlwrap(h, AF_LOCAL, SIOCGIFMTU, &ifr) == -1) { + return (-1); + } + *mtu = ifr.ifr_mtu; + return (0); +} + + +int libifc_set_metric(libifc_handle_t *h, const char *name, const int mtu) +{ + struct ifreq ifr; + + (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + ifr.ifr_mtu = mtu; + if (libifc_ioctlwrap_caddr(h, AF_LOCAL, SIOCSIFMETRIC, &ifr) < 0) { + return (-1); + } + return (0); +} + + +int libifc_get_metric(libifc_handle_t *h, const char *name, int *metric) +{ + struct ifreq ifr; + + (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + if (libifc_ioctlwrap(h, AF_LOCAL, SIOCGIFMETRIC, &ifr) == -1) { + return (-1); + } + *metric = ifr.ifr_metric; + return (0); +} + + +int libifc_set_capability(libifc_handle_t *h, const char *name, + const int capability) +{ + struct ifreq ifr; + struct libifc_capabilities ifcap; + int flags; + int value; + + if (libifc_get_capability(h, name, &ifcap) != 0) { + return (-1); + } + + value = capability; + flags = ifcap.curcap; + if (value < 0) { + value = -value; + flags &= ~value; + } else { + flags |= value; + } + flags &= ifcap.reqcap; + + (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + + /* + * TODO: Verify that it's safe to not have ifr.ifr_curcap + * set for this request. + */ + ifr.ifr_reqcap = flags; + if (libifc_ioctlwrap_caddr(h, AF_LOCAL, SIOCSIFCAP, &ifr) < 0) { + return (-1); + } + return (0); +} + + +int libifc_get_capability(libifc_handle_t *h, const char *name, + struct libifc_capabilities *capability) +{ + struct ifreq ifr; + + (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + + if (libifc_ioctlwrap_caddr(h, AF_LOCAL, SIOCGIFCAP, &ifr) < 0) { + return (-1); + } + capability->curcap = ifr.ifr_curcap; + capability->reqcap = ifr.ifr_reqcap; + return (0); +} + + +int libifc_destroy_interface(libifc_handle_t *h, const char *name) +{ + struct ifreq ifr; + + (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + + if (libifc_ioctlwrap(h, AF_LOCAL, SIOCIFDESTROY, &ifr) < 0) { + return (-1); + } + return (0); +} + + +int libifc_create_interface(libifc_handle_t *h, const char *name, char **ifname) +{ + struct ifreq ifr; + + (void)strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + + /* + * TODO: + * Insert special snowflake handling here. See GitHub issue #12 for details. + * In the meantime, hard-nosupport interfaces that need special handling. + */ + if ((strncmp(name, "wlan", strlen("wlan")) == 0) || + (strncmp(name, "vlan", strlen("vlan")) == 0) || + (strncmp(name, "vxlan", strlen("vxlan")) == 0)) { + h->error.errtype = OTHER; + h->error.errcode = ENOSYS; + return (-1); + } + + /* No special handling for this interface type. */ + + if (libifc_ioctlwrap(h, AF_LOCAL, SIOCIFCREATE2, &ifr) < 0) { + return (-1); + } + *ifname = strdup(ifr.ifr_name); + return (0); +} Index: lib/libifconfig/libifconfig_internal.h =================================================================== --- lib/libifconfig/libifconfig_internal.h +++ lib/libifconfig/libifconfig_internal.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2016, Marie Helene Kvello-Aune + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * thislist of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "libifconfig.h" + + +struct errstate { + /** + * Type of error. + */ + libifc_errtype errtype; + + /** + * The error occured in this ioctl() request. + * Populated if errtype = IOCTL + */ + unsigned long ioctl_request; + + /** + * The value of the global errno variable when the error occured. + */ + int errcode; +}; + +struct socketcache { + int sdindex; + int sdsize; + int *sdkeys; + int *sdvals; +}; + +struct libifc_handle { + struct errstate error; + struct socketcache sockets; +}; + +/** + * Retrieves socket for address family from + * cache, or creates it if it doesn't already exist. + * @param addressfamily The address family of the socket to retrieve + * @param s The retrieved socket. + * @return 0 on success, -1 on failure. + * {@example + * This example shows how to retrieve a socket from the cache. + * {@code + * static void myfunc() \{ + * int s; + * if (libifc_socket(AF_LOCAL, &s) != 0) \{ + * // Handle error state here + * \} + * // user code here + * \} + * } + * } + */ +int libifc_socket(libifc_handle_t *h, const int addressfamily, int *s); + +/** Function used by other wrapper functions to populate _errstate when appropriate.*/ +int libifc_ioctlwrap_ret(libifc_handle_t *h, unsigned long request, int rcode); + +/** Function to wrap ioctl() and automatically populate libifc_errstate when appropriate.*/ +int libifc_ioctlwrap(libifc_handle_t *h, const int addressfamily, + unsigned long request, struct ifreq *ifr); + +/** function to wrap ioctl(), casting ifr to caddr_t, and automatically populate libifc_errstate when appropriate.*/ +int libifc_ioctlwrap_caddr(libifc_handle_t *h, const int addressfamily, + unsigned long request, struct ifreq *ifr); Index: lib/libifconfig/libifconfig_internal.c =================================================================== --- lib/libifconfig/libifconfig_internal.c +++ lib/libifconfig/libifconfig_internal.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2016, Marie Helene Kvello-Aune + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * thislist of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include + +#include +#include +#include +#include +#include + + +#include "libifconfig.h" // Needed for libifc_errstate +#include "libifconfig_internal.h" + +int +libifc_ioctlwrap_ret(libifc_handle_t *h, unsigned long request, int rcode) +{ + if (rcode != 0) { + h->error.errtype = IOCTL; + h->error.ioctl_request = request; + h->error.errcode = errno; + } + return (rcode); +} + + +int +libifc_ioctlwrap(libifc_handle_t *h, const int addressfamily, + unsigned long request, struct ifreq *ifr) +{ + int s; + + if (libifc_socket(h, addressfamily, &s) != 0) { + return (-1); + } + + int rcode = ioctl(s, request, ifr); + return (libifc_ioctlwrap_ret(h, request, rcode)); +} + + +int +libifc_ioctlwrap_caddr(libifc_handle_t *h, const int addressfamily, + unsigned long request, struct ifreq *ifr) +{ + int s; + + if (libifc_socket(h, addressfamily, &s) != 0) { + return (-1); + } + + int rcode = ioctl(s, request, (caddr_t)ifr); + return (libifc_ioctlwrap_ret(h, request, rcode)); +} + + +static int +sdexpand(libifc_handle_t *h) +{ + /* Initial size of dictionary is 4. If it needs to be larger, double it. */ + int newsize; + + if (h->sockets.sdsize == 0) { + newsize = (4 * sizeof(int)); + } else { + newsize = (2 * h->sockets.sdsize * sizeof(int)); + } + + /* + * Don't use reallocf, as we want to keep the old allocation if + * this one fails. + */ + int *nsdkeys = realloc(h->sockets.sdkeys, newsize); + + /* + * TODO: Decide whether type 'SOCKET' should be strictly for socket(), + * or also for anything involving getting a socket. + */ + if (nsdkeys == NULL) { + h->error.errtype = OTHER; + h->error.errcode = ENOMEM; + return (-1); + } + + int *nsdvals = realloc(h->sockets.sdvals, newsize); + if (nsdvals == NULL) { + free(nsdkeys); + h->error.errtype = OTHER; + h->error.errcode = ENOMEM; + return (-1); + } + + /* Keep old arrays so we can free them later */ + int *osdkeys = h->sockets.sdkeys; + int *osdvals = h->sockets.sdvals; + + /* + * If libifconfig is ever going to be thread-safe and not just + * thread-friendly, it's important sdvals is updated first. + * This would prevent a potential race condition when looking up keys + * whose value isn't set yet. + */ + h->sockets.sdvals = nsdvals; + h->sockets.sdkeys = nsdkeys; + + /* Free old memory maps. */ + free(osdkeys); + free(osdvals); + /* Update size */ + h->sockets.sdsize = newsize; + return (0); +} + + +/* + * Function to get socket for the specified address family. + * If the socket doesn't already exist, attempt to create it. + */ +int libifc_socket(libifc_handle_t *h, const int addressfamily, int *s) +{ + int sock; + + for (int i = 0; i < h->sockets.sdindex; i++) { + if (h->sockets.sdkeys[i] == addressfamily) { + *s = h->sockets.sdvals[i]; + return (0); + } + } + + /* We don't have a socket of that type available. Create one. */ + if ((h->sockets.sdindex == h->sockets.sdsize) && (sdexpand(h) != 0)) { + /* Inherit error from sdexpand() */ + return (-1); + } + + sock = socket(addressfamily, SOCK_DGRAM, 0); + if (sock == -1) { + h->error.errtype = SOCKET; + h->error.errcode = errno; + return (-1); + } + + h->sockets.sdkeys[h->sockets.sdindex] = addressfamily; + h->sockets.sdvals[h->sockets.sdindex] = sock; + h->sockets.sdindex++; + *s = sock; + return (0); +} Index: share/examples/libifconfig/Makefile =================================================================== --- share/examples/libifconfig/Makefile +++ share/examples/libifconfig/Makefile @@ -0,0 +1,5 @@ +default: + $(CC) -Wall -fPIC -lifconfig -g -o example_setdescription setdescription.c + $(CC) -Wall -fPIC -lifconfig -g -o example_setmtu setmtu.c + $(CC) -Wall -fPIC -lifconfig -g -o example_ifdestroy ifdestroy.c + $(CC) -Wall -fPIC -lifconfig -g -o example_ifcreate ifcreate.c Index: share/examples/libifconfig/ifcreate.c =================================================================== --- share/examples/libifconfig/ifcreate.c +++ share/examples/libifconfig/ifcreate.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2016, Marie Helene Kvello-Aune + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * thislist of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +int main(int argc, char *argv[]) +{ + if (argc != 2) { + errx(EINVAL, "Invalid number of arguments." + " Only one argument is accepted, and it should be the name" + " of the interface to be created."); + } + + char *ifname, *ifactualname; + + /* We have a static number of arguments. Therefore we can do it simple. */ + ifname = strdup(argv[1]); + + printf("Requested interface name: %s\n", ifname); + + libifc_handle_t *lifh = libifc_open(); + if (libifc_create_interface(lifh, ifname, &ifactualname) == 0) { + printf("Successfully created interface '%s'\n", ifactualname); + libifc_close(lifh); + lifh = NULL; + free(ifname); + free(ifactualname); + return (0); + } else { + switch (libifc_err_errtype(lifh)) { + case SOCKET: + warnx("couldn't create socket. This shouldn't happen.\n"); + break; + case IOCTL: + if (libifc_err_ioctlreq(lifh) == SIOCIFCREATE2) { + warnx( + "Failed to create interface (SIOCIFCREATE2)\n"); + } + break; + default: + warnx( + "This is a thorough example accommodating for temporary" + " 'not implemented yet' errors. That's likely what happened" + " now. If not, your guess is as good as mine. ;)" + " Error code: %d\n", libifc_err_errno( + lifh)); + break; + } + + libifc_close(lifh); + lifh = NULL; + free(ifname); + free(ifactualname); + return (-1); + } +} Index: share/examples/libifconfig/ifdestroy.c =================================================================== --- share/examples/libifconfig/ifdestroy.c +++ share/examples/libifconfig/ifdestroy.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2016, Marie Helene Kvello-Aune + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * thislist of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +int main(int argc, char *argv[]) +{ + if (argc != 2) { + errx(EINVAL, "Invalid number of arguments." + " Only one argument is accepted, and it should be the name" + " of the interface to be destroyed."); + } + + char *ifname; + + /* We have a static number of arguments. Therefore we can do it simple. */ + ifname = strdup(argv[1]); + + printf("Interface name: %s\n", ifname); + + libifc_handle_t *lifh = libifc_open(); + if (libifc_destroy_interface(lifh, ifname) == 0) { + printf("Successfully destroyed interface '%s'.", ifname); + libifc_close(lifh); + lifh = NULL; + free(ifname); + return (0); + } else { + switch (libifc_err_errtype(lifh)) { + case SOCKET: + warnx("couldn't create socket. This shouldn't happen.\n"); + break; + case IOCTL: + if (libifc_err_ioctlreq(lifh) == SIOCIFDESTROY) { + warnx( + "Failed to destroy interface (SIOCIFDESTROY)\n"); + } + break; + default: + warnx( + "Should basically never end up here in this example.\n"); + break; + } + + libifc_close(lifh); + lifh = NULL; + free(ifname); + return (-1); + } +} Index: share/examples/libifconfig/setdescription.c =================================================================== --- share/examples/libifconfig/setdescription.c +++ share/examples/libifconfig/setdescription.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2016, Marie Helene Kvello-Aune + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * thislist of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + + +int main(int argc, char *argv[]) +{ + if (argc != 3) { + errx(EINVAL, "Invalid number of arguments." + " First argument should be interface name, second argument" + " should be the description to set."); + } + + char *ifname, *ifdescr, *curdescr; + /* We have a static number of arguments. Therefore we can do it simple. */ + ifname = strdup(argv[1]); + ifdescr = strdup(argv[2]); + curdescr = NULL; + + printf("Interface name: %s\n", ifname); + + libifc_handle_t *lifh = libifc_open(); + if (libifc_get_description(lifh, ifname, &curdescr) == 0) { + printf("Old description: %s\n", curdescr); + } + + printf("New description: %s\n\n", ifdescr); + + if (libifc_set_description(lifh, ifname, ifdescr) == 0) { + printf("New description successfully set.\n"); + } else { + switch (libifc_err_errtype(lifh)) { + case SOCKET: + err(libifc_err_errno(lifh), "Socket error"); + break; + case IOCTL: + err(libifc_err_errno( + lifh), "IOCTL(%lu) error", + libifc_err_ioctlreq(lifh)); + break; + case OTHER: + err(libifc_err_errno(lifh), "Other error"); + break; + } + } + + free(ifname); + free(ifdescr); + free(curdescr); + ifname = NULL; + ifdescr = NULL; + curdescr = NULL; + + libifc_close(lifh); + return (0); +} Index: share/examples/libifconfig/setmtu.c =================================================================== --- share/examples/libifconfig/setmtu.c +++ share/examples/libifconfig/setmtu.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2016, Marie Helene Kvello-Aune + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * thislist of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +int main(int argc, char *argv[]) +{ + if (argc != 3) { + errx(EINVAL, "Invalid number of arguments." + " First argument should be interface name, second argument" + " should be the MTU to set."); + } + + char *ifname, *ptr; + int mtu; + + /* We have a static number of arguments. Therefore we can do it simple. */ + ifname = strdup(argv[1]); + mtu = (int)strtol(argv[2], &ptr, 10); + + printf("Interface name: %s\n", ifname); + printf("New MTU: %d", mtu); + + libifc_handle_t *lifh = libifc_open(); + if (libifc_set_mtu(lifh, ifname, mtu) == 0) { + printf("Successfully changed MTU of %s to %d\n", ifname, mtu); + libifc_close(lifh); + lifh = NULL; + free(ifname); + return (0); + } else { + switch (libifc_err_errtype(lifh)) { + case SOCKET: + warnx("couldn't create socket. This shouldn't happen.\n"); + break; + case IOCTL: + if (libifc_err_ioctlreq(lifh) == SIOCSIFMTU) { + warnx("Failed to set MTU (SIOCSIFMTU)\n"); + } else { + warnx( + "Failed to set MTU due to error in unexpected ioctl() call %lu. Error code: %i.\n", + libifc_err_ioctlreq(lifh), + libifc_err_errno(lifh)); + } + break; + default: + warnx( + "Should basically never end up here in this example.\n"); + break; + } + + libifc_close(lifh); + lifh = NULL; + free(ifname); + return (-1); + } +} Index: share/mk/bsd.libnames.mk =================================================================== --- share/mk/bsd.libnames.mk +++ share/mk/bsd.libnames.mk @@ -82,6 +82,7 @@ LIBIBSDP?= ${DESTDIR}${LIBDIR}/libibsdp.a LIBIBUMAD?= ${DESTDIR}${LIBDIR}/libibumad.a LIBIBVERBS?= ${DESTDIR}${LIBDIR}/libibverbs.a +LIBIFCONFIG?= ${DESTDIR}${LIBDIR}/libifconfig.a LIBIPSEC?= ${DESTDIR}${LIBDIR}/libipsec.a LIBJAIL?= ${DESTDIR}${LIBDIR}/libjail.a LIBKADM5CLNT?= ${DESTDIR}${LIBDIR}/libkadm5clnt.a Index: share/mk/src.libnames.mk =================================================================== --- share/mk/src.libnames.mk +++ share/mk/src.libnames.mk @@ -105,6 +105,7 @@ heimntlm \ heimsqlite \ hx509 \ + ifconfig \ ipsec \ jail \ kadm5clnt \