1/*	$NetBSD: ifaddrlist.c,v 1.9 2011/05/11 00:38:28 christos Exp $	*/
2
3/*
4 * Copyright (c) 1997, 1998, 1999, 2000
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *	This product includes software developed by the Computer Systems
18 *	Engineering Group at Lawrence Berkeley Laboratory.
19 * 4. Neither the name of the University nor of the Laboratory may be used
20 *    to endorse or promote products derived from this software without
21 *    specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include <sys/cdefs.h>
37#ifndef lint
38#if 0
39static const char rcsid[] =
40    "@(#) Header: ifaddrlist.c,v 1.2 97/04/22 13:31:05 leres Exp  (LBL)";
41    "@(#) Id: ifaddrlist.c,v 1.9 2000/11/23 20:01:55 leres Exp  (LBL)";
42#else
43__RCSID("$NetBSD: ifaddrlist.c,v 1.9 2011/05/11 00:38:28 christos Exp $");
44#endif
45#endif
46
47#include <sys/param.h>
48#include <sys/file.h>
49#include <sys/ioctl.h>
50#include <sys/socket.h>
51#ifdef HAVE_SYS_SOCKIO_H
52#include <sys/sockio.h>
53#endif
54#include <sys/time.h>				/* concession to AIX */
55
56struct mbuf;
57struct rtentry;
58
59#include <net/if.h>
60#include <netinet/in.h>
61#include <arpa/inet.h>
62
63#include <ctype.h>
64#include <errno.h>
65#include <memory.h>
66#include <stdio.h>
67#include <stdlib.h>
68#include <string.h>
69#include <unistd.h>
70#include <ifaddrs.h>
71
72#include "gnuc.h"
73#ifdef HAVE_OS_PROTO_H
74#include "os-proto.h"
75#endif
76
77#include "ifaddrlist.h"
78
79/* Not all systems have IFF_LOOPBACK */
80#ifdef IFF_LOOPBACK
81#define ISLOOPBACK(p) ((p)->ifa_flags & IFF_LOOPBACK)
82#else
83#define ISLOOPBACK(p) (strcmp((p)->ifa_name, "lo0") == 0)
84#endif
85
86/*
87 * Return the interface list
88 */
89ssize_t
90ifaddrlist(struct ifaddrlist **ipaddrp, char *errbuf, size_t buflen)
91{
92	struct sockaddr_in *sin;
93	struct ifaddrs *ifap = NULL, *ifa;
94	struct ifaddrlist *al = NULL, *nal;
95	size_t i = 0, maxal = 10;
96
97	if (getifaddrs(&ifap) != 0)
98		goto out;
99
100	if ((al = malloc(maxal * sizeof(*al))) == NULL)
101		goto out;
102
103	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
104		if (ifa->ifa_addr->sa_family != AF_INET)
105			continue;
106
107		/* Must be up */
108		if ((ifa->ifa_flags & IFF_UP) == 0)
109			continue;
110
111		/*
112		 * Must not be a loopback address (127/8)
113		 */
114		sin = (struct sockaddr_in *)ifa->ifa_addr;
115		if (ISLOOPBACK(ifa))
116			if (ntohl(sin->sin_addr.s_addr) == INADDR_LOOPBACK)
117				continue;
118
119		if (i == maxal) {
120			maxal <<= 1;
121			if ((nal = realloc(al, maxal * sizeof(*al))) == NULL)
122				goto out;
123			al = nal;
124		}
125
126		al[i].addr = sin->sin_addr.s_addr;
127		if ((al[i].device = strdup(ifa->ifa_name)) == NULL)
128			goto out;
129		i++;
130	}
131	if ((nal = realloc(al, i * sizeof(*al))) == NULL)
132		goto out;
133	freeifaddrs(ifap);
134	*ipaddrp = nal;
135	return (ssize_t)i;
136out:
137	if (ifap)
138		freeifaddrs(ifap);
139	if (al) {
140		while (i > 0)
141			free(al[--i].device);
142		free(al);
143	}
144	(void)snprintf(errbuf, buflen, "%s: %s", __func__, strerror(errno));
145	return -1;
146}
147