diff options
Diffstat (limited to 'usr/src/lib/libinetutil')
-rw-r--r-- | usr/src/lib/libinetutil/Makefile.com | 14 | ||||
-rw-r--r-- | usr/src/lib/libinetutil/common/ifaddrlist.c | 68 | ||||
-rw-r--r-- | usr/src/lib/libinetutil/common/ifaddrlistx.c | 168 | ||||
-rw-r--r-- | usr/src/lib/libinetutil/common/inetutil.c (renamed from usr/src/lib/libinetutil/common/inetutil4.c) | 36 | ||||
-rw-r--r-- | usr/src/lib/libinetutil/common/libinetutil.h | 55 | ||||
-rw-r--r-- | usr/src/lib/libinetutil/common/mapfile-vers | 7 |
6 files changed, 289 insertions, 59 deletions
diff --git a/usr/src/lib/libinetutil/Makefile.com b/usr/src/lib/libinetutil/Makefile.com index 810f24bd71..cd3a0d6e33 100644 --- a/usr/src/lib/libinetutil/Makefile.com +++ b/usr/src/lib/libinetutil/Makefile.com @@ -19,15 +19,13 @@ # CDDL HEADER END # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" -# -LIBRARY = libinetutil.a -VERS = .1 -OBJECTS = octet.o inetutil4.o ifspec.o ifaddrlist.o eh.o tq.o +LIBRARY = libinetutil.a +VERS = .1 +OBJECTS = octet.o inetutil.o ifspec.o ifaddrlist.o ifaddrlistx.o eh.o tq.o include ../../Makefile.lib @@ -38,9 +36,9 @@ LIBS = $(DYNLIB) $(LINTLIB) SRCDIR = ../common COMDIR = $(SRC)/common/net/dhcp -SRCS = $(COMDIR)/octet.c $(SRCDIR)/inetutil4.c \ +SRCS = $(COMDIR)/octet.c $(SRCDIR)/inetutil.c \ $(SRCDIR)/ifspec.c $(SRCDIR)/eh.c $(SRCDIR)/tq.c \ - $(SRCDIR)/ifaddrlist.c + $(SRCDIR)/ifaddrlist.c $(SRCDIR)/ifaddrlistx.c $(LINTLIB):= SRCS = $(SRCDIR)/$(LINTSRC) LDLIBS += -lsocket -lc diff --git a/usr/src/lib/libinetutil/common/ifaddrlist.c b/usr/src/lib/libinetutil/common/ifaddrlist.c index 383dc2afb0..fa67a0fc37 100644 --- a/usr/src/lib/libinetutil/common/ifaddrlist.c +++ b/usr/src/lib/libinetutil/common/ifaddrlist.c @@ -1,5 +1,5 @@ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -38,9 +38,6 @@ * @(#) $Header: ifaddrlist.c,v 1.2 97/04/22 13:31:05 leres Exp $ (LBL) */ -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <alloca.h> #include <errno.h> #include <libinetutil.h> #include <stdio.h> @@ -54,9 +51,9 @@ * See <libinetutil.h> for a description of the programming interface. */ int -ifaddrlist(struct ifaddrlist **ipaddrp, int family, char *errbuf) +ifaddrlist(struct ifaddrlist **ipaddrp, int family, uint_t flags, char *errbuf) { - struct ifaddrlist *ifaddrlist, *al; + struct ifaddrlist *ifaddrlist = NULL, *al = NULL; struct sockaddr_in *sin; struct sockaddr_in6 *sin6; struct lifconf lifc; @@ -64,31 +61,28 @@ ifaddrlist(struct ifaddrlist **ipaddrp, int family, char *errbuf) struct lifreq *lifrp; int i, count, nlifr; int fd; - const char *iocstr; + const char *opstr; + (void) memset(&lifc, 0, sizeof (lifc)); if (family != AF_INET && family != AF_INET6) { (void) strlcpy(errbuf, "invalid address family", ERRBUFSIZE); return (-1); } - fd = socket(family, SOCK_DGRAM, 0); - if (fd == -1) { - (void) snprintf(errbuf, ERRBUFSIZE, "socket: %s", - strerror(errno)); - return (-1); + if ((fd = socket(family, SOCK_DGRAM, 0)) == -1) { + opstr = "socket"; + goto fail; } /* * Get the number of network interfaces of type `family'. */ lifn.lifn_family = family; - lifn.lifn_flags = 0; + lifn.lifn_flags = flags; again: if (ioctl(fd, SIOCGLIFNUM, &lifn) == -1) { - (void) snprintf(errbuf, ERRBUFSIZE, "SIOCGLIFNUM: %s", - strerror(errno)); - (void) close(fd); - return (-1); + opstr = "SIOCGLIFNUM"; + goto fail; } /* @@ -97,16 +91,17 @@ again: */ lifn.lifn_count += 4; + lifc.lifc_flags = flags; lifc.lifc_family = family; lifc.lifc_len = lifn.lifn_count * sizeof (struct lifreq); - lifc.lifc_buf = alloca(lifc.lifc_len); - lifc.lifc_flags = 0; + if ((lifc.lifc_buf = realloc(lifc.lifc_buf, lifc.lifc_len)) == NULL) { + opstr = "realloc"; + goto fail; + } if (ioctl(fd, SIOCGLIFCONF, &lifc) == -1) { - (void) snprintf(errbuf, ERRBUFSIZE, "SIOCGLIFCONF: %s", - strerror(errno)); - (void) close(fd); - return (-1); + opstr = "SIOCGLIFCONF"; + goto fail; } /* @@ -121,12 +116,9 @@ again: /* * Allocate the address list to return. */ - ifaddrlist = calloc(nlifr, sizeof (struct ifaddrlist)); - if (ifaddrlist == NULL) { - (void) snprintf(errbuf, ERRBUFSIZE, "calloc: %s", - strerror(errno)); - (void) close(fd); - return (-1); + if ((ifaddrlist = calloc(nlifr, sizeof (struct ifaddrlist))) == NULL) { + opstr = "calloc"; + goto fail; } /* @@ -142,7 +134,7 @@ again: if (ioctl(fd, SIOCGLIFFLAGS, lifrp) == -1) { if (errno == ENXIO) continue; - iocstr = "SIOCGLIFFLAGS"; + opstr = "SIOCGLIFFLAGS"; goto fail; } al->flags = lifrp->lifr_flags; @@ -150,7 +142,7 @@ again: if (ioctl(fd, SIOCGLIFINDEX, lifrp) == -1) { if (errno == ENXIO) continue; - iocstr = "SIOCGLIFINDEX"; + opstr = "SIOCGLIFINDEX"; goto fail; } al->index = lifrp->lifr_index; @@ -158,7 +150,7 @@ again: if (ioctl(fd, SIOCGLIFADDR, lifrp) == -1) { if (errno == ENXIO) continue; - iocstr = "SIOCGLIFADDR"; + opstr = "SIOCGLIFADDR"; goto fail; } @@ -174,6 +166,7 @@ again: } (void) close(fd); + free(lifc.lifc_buf); if (count == 0) { free(ifaddrlist); *ipaddrp = NULL; @@ -183,9 +176,14 @@ again: *ipaddrp = ifaddrlist; return (count); fail: - (void) snprintf(errbuf, ERRBUFSIZE, "%s: %s: %s", iocstr, al->device, - strerror(errno)); - + if (al == NULL) { + (void) snprintf(errbuf, ERRBUFSIZE, "%s: %s", opstr, + strerror(errno)); + } else { + (void) snprintf(errbuf, ERRBUFSIZE, "%s: %s: %s", opstr, + al->device, strerror(errno)); + } + free(lifc.lifc_buf); free(ifaddrlist); (void) close(fd); return (-1); diff --git a/usr/src/lib/libinetutil/common/ifaddrlistx.c b/usr/src/lib/libinetutil/common/ifaddrlistx.c new file mode 100644 index 0000000000..ce85c5521f --- /dev/null +++ b/usr/src/lib/libinetutil/common/ifaddrlistx.c @@ -0,0 +1,168 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + * + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#include <errno.h> +#include <libinetutil.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/socket.h> +#include <sys/sockio.h> + +/* + * Create a list of the addresses on physical interface `ifname' with at least + * one of the flags in `set' set and all of the flags in `clear' clear. + * Return the number of items in the list, or -1 on failure. + */ +int +ifaddrlistx(const char *ifname, uint64_t set, uint64_t clear, + ifaddrlistx_t **ifaddrsp) +{ + struct lifconf lifc; + struct lifnum lifn; + struct lifreq *lifrp; + ifaddrlistx_t *ifaddrp, *ifaddrs = NULL; + int i, nlifr, naddr = 0; + char *cp; + uint_t flags; + int s4, s6 = -1; + boolean_t isv6; + int save_errno; + struct sockaddr_storage addr; + + (void) memset(&lifc, 0, sizeof (lifc)); + flags = LIFC_NOXMIT | LIFC_ALLZONES | LIFC_TEMPORARY | LIFC_UNDER_IPMP; + + /* + * We need both IPv4 and IPv6 sockets to query both IPv4 and IPv6 + * interfaces below. + */ + if ((s4 = socket(AF_INET, SOCK_DGRAM, 0)) == -1 || + (s6 = socket(AF_INET6, SOCK_DGRAM, 0)) == -1) { + goto fail; + } + + /* + * Get the number of network interfaces of type `family'. + */ + lifn.lifn_family = AF_UNSPEC; + lifn.lifn_flags = flags; +again: + if (ioctl(s4, SIOCGLIFNUM, &lifn) == -1) + goto fail; + + /* + * Pad the interface count to detect when additional interfaces have + * been configured between SIOCGLIFNUM and SIOCGLIFCONF. + */ + lifn.lifn_count += 4; + + lifc.lifc_flags = flags; + lifc.lifc_family = AF_UNSPEC; + lifc.lifc_len = lifn.lifn_count * sizeof (struct lifreq); + if ((lifc.lifc_buf = realloc(lifc.lifc_buf, lifc.lifc_len)) == NULL) + goto fail; + + if (ioctl(s4, SIOCGLIFCONF, &lifc) == -1) + goto fail; + + /* + * If every lifr_req slot is taken, then additional interfaces must + * have been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF. + * Recalculate to make sure we didn't miss any interfaces. + */ + nlifr = lifc.lifc_len / sizeof (struct lifreq); + if (nlifr >= lifn.lifn_count) + goto again; + + /* + * Populate the ifaddrlistx by querying each matching interface. If a + * query ioctl returns ENXIO, then the interface must have been + * removed after the SIOCGLIFCONF completed -- so we just ignore it. + */ + for (lifrp = lifc.lifc_req, i = 0; i < nlifr; i++, lifrp++) { + if ((cp = strchr(lifrp->lifr_name, ':')) != NULL) + *cp = '\0'; + + if (strcmp(lifrp->lifr_name, ifname) != 0) + continue; + + if (cp != NULL) + *cp = ':'; + + addr = lifrp->lifr_addr; + isv6 = addr.ss_family == AF_INET6; + if (ioctl(isv6 ? s6 : s4, SIOCGLIFFLAGS, lifrp) == -1) { + if (errno == ENXIO) + continue; + goto fail; + } + + if (set != 0 && ((lifrp->lifr_flags & set) == 0) || + (lifrp->lifr_flags & clear) != 0) + continue; + + /* + * We've got a match; allocate a new record. + */ + if ((ifaddrp = malloc(sizeof (ifaddrlistx_t))) == NULL) + goto fail; + + (void) strlcpy(ifaddrp->ia_name, lifrp->lifr_name, LIFNAMSIZ); + ifaddrp->ia_flags = lifrp->lifr_flags; + ifaddrp->ia_addr = addr; + ifaddrp->ia_next = ifaddrs; + ifaddrs = ifaddrp; + naddr++; + } + + (void) close(s4); + (void) close(s6); + free(lifc.lifc_buf); + *ifaddrsp = ifaddrs; + return (naddr); +fail: + save_errno = errno; + (void) close(s4); + (void) close(s6); + free(lifc.lifc_buf); + ifaddrlistx_free(ifaddrs); + errno = save_errno; + return (-1); +} + +/* + * Free the provided ifaddrlistx_t. + */ +void +ifaddrlistx_free(ifaddrlistx_t *ifaddrp) +{ + ifaddrlistx_t *next_ifaddrp; + + for (; ifaddrp != NULL; ifaddrp = next_ifaddrp) { + next_ifaddrp = ifaddrp->ia_next; + free(ifaddrp); + } +} diff --git a/usr/src/lib/libinetutil/common/inetutil4.c b/usr/src/lib/libinetutil/common/inetutil.c index ff5607e192..195d080b79 100644 --- a/usr/src/lib/libinetutil/common/inetutil4.c +++ b/usr/src/lib/libinetutil/common/inetutil.c @@ -18,13 +18,12 @@ * * CDDL HEADER END */ + /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <unistd.h> #include <netinet/in.h> #include <libinetutil.h> @@ -32,7 +31,7 @@ extern int getnetmaskbyaddr(const struct in_addr, struct in_addr *); /* - * Generic internet (v4) functions. + * Internet utility functions. */ /* @@ -67,3 +66,32 @@ get_netmask4(const struct in_addr *n_addrp, struct in_addr *s_addrp) else s_addrp->s_addr = IN_CLASSE_NET; } + +/* + * Checks if the IP addresses `ssp1' and `ssp2' are equal. + */ +boolean_t +sockaddrcmp(const struct sockaddr_storage *ssp1, + const struct sockaddr_storage *ssp2) +{ + struct in_addr addr1, addr2; + const struct in6_addr *addr6p1, *addr6p2; + + if (ssp1->ss_family != ssp2->ss_family) + return (B_FALSE); + + if (ssp1 == ssp2) + return (B_TRUE); + + switch (ssp1->ss_family) { + case AF_INET: + addr1 = ((const struct sockaddr_in *)ssp1)->sin_addr; + addr2 = ((const struct sockaddr_in *)ssp2)->sin_addr; + return (addr1.s_addr == addr2.s_addr); + case AF_INET6: + addr6p1 = &((const struct sockaddr_in6 *)ssp1)->sin6_addr; + addr6p2 = &((const struct sockaddr_in6 *)ssp2)->sin6_addr; + return (IN6_ARE_ADDR_EQUAL(addr6p1, addr6p2)); + } + return (B_FALSE); +} diff --git a/usr/src/lib/libinetutil/common/libinetutil.h b/usr/src/lib/libinetutil/common/libinetutil.h index b21d54f56c..0bece07e07 100644 --- a/usr/src/lib/libinetutil/common/libinetutil.h +++ b/usr/src/lib/libinetutil/common/libinetutil.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -21,15 +20,13 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _LIBINETUTIL_H #define _LIBINETUTIL_H -#pragma ident "%Z%%M% %I% %E% SMI" - /* * Contains SMI-private API for general Internet functionality */ @@ -59,11 +56,14 @@ typedef struct { extern boolean_t ifparse_ifspec(const char *, ifspec_t *); extern void get_netmask4(const struct in_addr *, struct in_addr *); +extern boolean_t sockaddrcmp(const struct sockaddr_storage *, + const struct sockaddr_storage *); /* * Extended version of the classic BSD ifaddrlist() interface: * - * int ifaddrlist(struct ifaddrlist **addrlistp, int af, char *errbuf); + * int ifaddrlist(struct ifaddrlist **addrlistp, int af, uint_t flags, + * char *errbuf); * * * addrlistp: Upon success, ifaddrlist() sets *addrlistp to a * dynamically-allocated array of addresses. @@ -71,6 +71,9 @@ extern void get_netmask4(const struct in_addr *, struct in_addr *); * * af: Either AF_INET to obtain IPv4 addresses, or AF_INET6 to * obtain IPv6 addresses. * + * * flags: LIFC_* flags that control the classes of interfaces that + * will be visible. + * * * errbuf: A caller-supplied buffer of ERRBUFSIZE. Upon failure, * provides the reason for the failure. * @@ -89,9 +92,43 @@ struct ifaddrlist { uint64_t flags; /* interface flags */ }; -#define ERRBUFSIZE 128 /* expected size of third argument */ +#define ERRBUFSIZE 128 /* expected size of fourth argument */ + +extern int ifaddrlist(struct ifaddrlist **, int, uint_t, char *); -extern int ifaddrlist(struct ifaddrlist **, int, char *); +/* + * Similar to ifaddrlist(), but returns a linked-list of addresses for a + * *specific* interface name, and allows specific address flags to be matched + * against. A linked list is used rather than an array so that information + * can grow over time without affecting binary compatibility. Also, leaves + * error-handling up to the caller. Returns the number of ifaddrlistx's + * chained through ifaddrp. + * + * int ifaddrlistx(const char *ifname, uint64_t set, uint64_t clear, + * ifaddrlistx_t **ifaddrp); + * + * * ifname: Interface name to match against. + * + * * set: One or more flags that must be set on the address for + * it to be returned. + * + * * clear: Flags that must be clear on the address for it to be + * returned. + * + * * ifaddrp: Upon success, ifaddrlistx() sets *ifaddrp to the head + * of a dynamically-allocated array of ifaddrlistx structures. + * + * Once done, the caller must free `ifaddrp' by calling ifaddrlistx_free(). + */ +typedef struct ifaddrlistx { + struct ifaddrlistx *ia_next; + char ia_name[LIFNAMSIZ]; + uint64_t ia_flags; + struct sockaddr_storage ia_addr; +} ifaddrlistx_t; + +extern int ifaddrlistx(const char *, uint64_t, uint64_t, ifaddrlistx_t **); +extern void ifaddrlistx_free(ifaddrlistx_t *); /* * Timer queues diff --git a/usr/src/lib/libinetutil/common/mapfile-vers b/usr/src/lib/libinetutil/common/mapfile-vers index 51c168fcc4..c9a7829fdb 100644 --- a/usr/src/lib/libinetutil/common/mapfile-vers +++ b/usr/src/lib/libinetutil/common/mapfile-vers @@ -19,17 +19,17 @@ # CDDL HEADER END # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # -# ident "%Z%%M% %I% %E% SMI" -# SUNWprivate_1.1 { global: get_netmask4; hexascii_to_octet; ifaddrlist; + ifaddrlistx; + ifaddrlistx_free; ifparse_ifspec; iu_adjust_timer; iu_cancel_timer; @@ -48,6 +48,7 @@ SUNWprivate_1.1 { iu_tq_destroy; iu_unregister_event; octet_to_hexascii; + sockaddrcmp; local: *; }; |