summaryrefslogtreecommitdiff
path: root/usr/src/lib/libinetutil
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libinetutil')
-rw-r--r--usr/src/lib/libinetutil/Makefile.com14
-rw-r--r--usr/src/lib/libinetutil/common/ifaddrlist.c68
-rw-r--r--usr/src/lib/libinetutil/common/ifaddrlistx.c168
-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.h55
-rw-r--r--usr/src/lib/libinetutil/common/mapfile-vers7
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:
*;
};