getifaddrs.c revision 78527
172445Sassar/*
272445Sassar * Copyright (c) 2000 - 2001 Kungliga Tekniska H�gskolan
372445Sassar * (Royal Institute of Technology, Stockholm, Sweden).
472445Sassar * All rights reserved.
572445Sassar *
672445Sassar * Redistribution and use in source and binary forms, with or without
772445Sassar * modification, are permitted provided that the following conditions
872445Sassar * are met:
972445Sassar *
1072445Sassar * 1. Redistributions of source code must retain the above copyright
1172445Sassar *    notice, this list of conditions and the following disclaimer.
1272445Sassar *
1372445Sassar * 2. Redistributions in binary form must reproduce the above copyright
1472445Sassar *    notice, this list of conditions and the following disclaimer in the
1572445Sassar *    documentation and/or other materials provided with the distribution.
1672445Sassar *
1772445Sassar * 3. Neither the name of the Institute nor the names of its contributors
1872445Sassar *    may be used to endorse or promote products derived from this software
1972445Sassar *    without specific prior written permission.
2072445Sassar *
2172445Sassar * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
2272445Sassar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2372445Sassar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2472445Sassar * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
2572445Sassar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2672445Sassar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2772445Sassar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2872445Sassar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2972445Sassar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3072445Sassar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3172445Sassar * SUCH DAMAGE.
3272445Sassar */
3372445Sassar
3472445Sassar#ifdef HAVE_CONFIG_H
3572445Sassar#include <config.h>
3678527SassarRCSID("$Id: getifaddrs.c,v 1.5 2001/04/17 08:27:47 joda Exp $");
3772445Sassar#endif
3872445Sassar#include "roken.h"
3972445Sassar
4072445Sassar#ifdef __osf__
4172445Sassar/* hate */
4272445Sassarstruct rtentry;
4372445Sassarstruct mbuf;
4472445Sassar#endif
4572445Sassar#ifdef HAVE_NET_IF_H
4672445Sassar#include <net/if.h>
4772445Sassar#endif
4872445Sassar
4972445Sassar#ifdef HAVE_SYS_SOCKIO_H
5072445Sassar#include <sys/sockio.h>
5172445Sassar#endif /* HAVE_SYS_SOCKIO_H */
5272445Sassar
5372445Sassar#ifdef HAVE_NETINET_IN6_VAR_H
5472445Sassar#include <netinet/in6_var.h>
5572445Sassar#endif /* HAVE_NETINET_IN6_VAR_H */
5672445Sassar
5772445Sassar#include <ifaddrs.h>
5872445Sassar
5972445Sassarstatic int
6072445Sassargetifaddrs2(struct ifaddrs **ifap,
6172445Sassar	    int af, int siocgifconf, int siocgifflags,
6272445Sassar	    size_t ifreq_sz)
6372445Sassar{
6472445Sassar    int ret;
6572445Sassar    int fd;
6672445Sassar    size_t buf_size;
6772445Sassar    char *buf;
6872445Sassar    struct ifconf ifconf;
6972445Sassar    int num, j = 0;
7072445Sassar    char *p;
7172445Sassar    size_t sz;
7272445Sassar    struct sockaddr sa_zero;
7372445Sassar    struct ifreq *ifr;
7472445Sassar
7572445Sassar    struct ifaddrs *start,  **end = &start;
7672445Sassar
7772445Sassar    buf = NULL;
7872445Sassar
7972445Sassar    memset (&sa_zero, 0, sizeof(sa_zero));
8072445Sassar    fd = socket(af, SOCK_DGRAM, 0);
8172445Sassar    if (fd < 0)
8272445Sassar	return -1;
8372445Sassar
8472445Sassar    buf_size = 8192;
8572445Sassar    for (;;) {
8672445Sassar	buf = calloc(1, buf_size);
8772445Sassar	if (buf == NULL) {
8872445Sassar	    ret = ENOMEM;
8972445Sassar	    goto error_out;
9072445Sassar	}
9172445Sassar	ifconf.ifc_len = buf_size;
9272445Sassar	ifconf.ifc_buf = buf;
9372445Sassar
9472445Sassar	/*
9572445Sassar	 * Solaris returns EINVAL when the buffer is too small.
9672445Sassar	 */
9772445Sassar	if (ioctl (fd, siocgifconf, &ifconf) < 0 && errno != EINVAL) {
9872445Sassar	    ret = errno;
9972445Sassar	    goto error_out;
10072445Sassar	}
10172445Sassar	/*
10272445Sassar	 * Can the difference between a full and a overfull buf
10372445Sassar	 * be determined?
10472445Sassar	 */
10572445Sassar
10672445Sassar	if (ifconf.ifc_len < buf_size)
10772445Sassar	    break;
10872445Sassar	free (buf);
10972445Sassar	buf_size *= 2;
11072445Sassar    }
11172445Sassar
11272445Sassar    num = ifconf.ifc_len / ifreq_sz;
11372445Sassar    j = 0;
11472445Sassar    for (p = ifconf.ifc_buf;
11572445Sassar	 p < ifconf.ifc_buf + ifconf.ifc_len;
11672445Sassar	 p += sz) {
11772445Sassar	struct ifreq ifreq;
11872445Sassar	struct sockaddr *sa;
11972445Sassar	size_t salen;
12072445Sassar
12172445Sassar	ifr = (struct ifreq *)p;
12272445Sassar	sa  = &ifr->ifr_addr;
12372445Sassar
12472445Sassar	sz = ifreq_sz;
12572445Sassar	salen = sizeof(struct sockaddr);
12672445Sassar#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
12772445Sassar	salen = sa->sa_len;
12872445Sassar	sz = max(sz, sizeof(ifr->ifr_name) + sa->sa_len);
12972445Sassar#endif
13072445Sassar#ifdef SA_LEN
13172445Sassar	salen = SA_LEN(sa);
13272445Sassar	sz = max(sz, sizeof(ifr->ifr_name) + SA_LEN(sa));
13372445Sassar#endif
13472445Sassar	memset (&ifreq, 0, sizeof(ifreq));
13572445Sassar	memcpy (ifreq.ifr_name, ifr->ifr_name, sizeof(ifr->ifr_name));
13672445Sassar
13772445Sassar	if (ioctl(fd, siocgifflags, &ifreq) < 0) {
13872445Sassar	    ret = errno;
13972445Sassar	    goto error_out;
14072445Sassar	}
14172445Sassar
14272445Sassar	*end = malloc(sizeof(**end));
14372445Sassar
14472445Sassar	(*end)->ifa_next = NULL;
14572445Sassar	(*end)->ifa_name = strdup(ifr->ifr_name);
14672445Sassar	(*end)->ifa_flags = ifreq.ifr_flags;
14772445Sassar	(*end)->ifa_addr = malloc(salen);
14872445Sassar	memcpy((*end)->ifa_addr, sa, salen);
14972445Sassar	(*end)->ifa_netmask = NULL;
15072445Sassar
15172445Sassar#if 0
15272445Sassar	/* fix these when we actually need them */
15372445Sassar	if(ifreq.ifr_flags & IFF_BROADCAST) {
15472445Sassar	    (*end)->ifa_broadaddr = malloc(sizeof(ifr->ifr_broadaddr));
15572445Sassar	    memcpy((*end)->ifa_broadaddr, &ifr->ifr_broadaddr,
15672445Sassar		   sizeof(ifr->ifr_broadaddr));
15772445Sassar	} else if(ifreq.ifr_flags & IFF_POINTOPOINT) {
15872445Sassar	    (*end)->ifa_dstaddr = malloc(sizeof(ifr->ifr_dstaddr));
15972445Sassar	    memcpy((*end)->ifa_dstaddr, &ifr->ifr_dstaddr,
16072445Sassar		   sizeof(ifr->ifr_dstaddr));
16172445Sassar	} else
16272445Sassar	    (*end)->ifa_dstaddr = NULL;
16372445Sassar#else
16472445Sassar	    (*end)->ifa_dstaddr = NULL;
16572445Sassar#endif
16672445Sassar
16772445Sassar	(*end)->ifa_data = NULL;
16872445Sassar
16972445Sassar	end = &(*end)->ifa_next;
17072445Sassar
17172445Sassar    }
17272445Sassar    *ifap = start;
17378527Sassar    close(fd);
17472445Sassar    free(buf);
17572445Sassar    return 0;
17672445Sassar  error_out:
17778527Sassar    close(fd);
17872445Sassar    free(buf);
17972445Sassar    errno = ret;
18072445Sassar    return -1;
18172445Sassar}
18272445Sassar
18372445Sassarint
18472445Sassargetifaddrs(struct ifaddrs **ifap)
18572445Sassar{
18672445Sassar    int ret = -1;
18772445Sassar    errno = ENXIO;
18872445Sassar#if defined(AF_INET6) && defined(SIOCGIF6CONF) && defined(SIOCGIF6FLAGS)
18972445Sassar    if (ret)
19072445Sassar	ret = getifaddrs2 (ifap, AF_INET6, SIOCGIF6CONF, SIOCGIF6FLAGS,
19172445Sassar			   sizeof(struct in6_ifreq));
19272445Sassar#endif
19372445Sassar#if defined(HAVE_IPV6) && defined(SIOCGIFCONF)
19472445Sassar    if (ret)
19572445Sassar	ret = getifaddrs2 (ifap, AF_INET6, SIOCGIFCONF, SIOCGIFFLAGS,
19672445Sassar			   sizeof(struct ifreq));
19772445Sassar#endif
19872445Sassar#if defined(AF_INET) && defined(SIOCGIFCONF) && defined(SIOCGIFFLAGS)
19972445Sassar    if (ret)
20072445Sassar	ret = getifaddrs2 (ifap, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS,
20172445Sassar			   sizeof(struct ifreq));
20272445Sassar#endif
20372445Sassar    return ret;
20472445Sassar}
20572445Sassar
20672445Sassarvoid
20772445Sassarfreeifaddrs(struct ifaddrs *ifp)
20872445Sassar{
20972445Sassar    struct ifaddrs *p, *q;
21072445Sassar
21172445Sassar    for(p = ifp; p; ) {
21272445Sassar	free(p->ifa_name);
21372445Sassar	if(p->ifa_addr)
21472445Sassar	    free(p->ifa_addr);
21572445Sassar	if(p->ifa_dstaddr)
21672445Sassar	    free(p->ifa_dstaddr);
21772445Sassar	if(p->ifa_netmask)
21872445Sassar	    free(p->ifa_netmask);
21972445Sassar	if(p->ifa_data)
22072445Sassar	    free(p->ifa_data);
22172445Sassar	q = p;
22272445Sassar	p = p->ifa_next;
22372445Sassar	free(q);
22472445Sassar    }
22572445Sassar}
22672445Sassar
22772445Sassar#ifdef TEST
22872445Sassar
22972445Sassarvoid
23072445Sassarprint_addr(const char *s, struct sockaddr *sa)
23172445Sassar{
23272445Sassar    int i;
23372445Sassar    printf("  %s=%d/", s, sa->sa_family);
23472445Sassar#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
23572445Sassar    for(i = 0; i < sa->sa_len - ((long)sa->sa_data - (long)&sa->sa_family); i++)
23672445Sassar	printf("%02x", ((unsigned char*)sa->sa_data)[i]);
23772445Sassar#else
23872445Sassar    for(i = 0; i < sizeof(sa->sa_data); i++)
23972445Sassar	printf("%02x", ((unsigned char*)sa->sa_data)[i]);
24072445Sassar#endif
24172445Sassar    printf("\n");
24272445Sassar}
24372445Sassar
24472445Sassarvoid
24572445Sassarprint_ifaddrs(struct ifaddrs *x)
24672445Sassar{
24772445Sassar    struct ifaddrs *p;
24872445Sassar
24972445Sassar    for(p = x; p; p = p->ifa_next) {
25072445Sassar	printf("%s\n", p->ifa_name);
25172445Sassar	printf("  flags=%x\n", p->ifa_flags);
25272445Sassar	if(p->ifa_addr)
25372445Sassar	    print_addr("addr", p->ifa_addr);
25472445Sassar	if(p->ifa_dstaddr)
25572445Sassar	    print_addr("dstaddr", p->ifa_dstaddr);
25672445Sassar	if(p->ifa_netmask)
25772445Sassar	    print_addr("netmask", p->ifa_netmask);
25872445Sassar	printf("  %p\n", p->ifa_data);
25972445Sassar    }
26072445Sassar}
26172445Sassar
26272445Sassarint
26372445Sassarmain()
26472445Sassar{
26572445Sassar    struct ifaddrs *a = NULL, *b;
26672445Sassar    getifaddrs2(&a, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS, sizeof(struct ifreq));
26772445Sassar    print_ifaddrs(a);
26872445Sassar    printf("---\n");
26972445Sassar    getifaddrs(&b);
27072445Sassar    print_ifaddrs(b);
27172445Sassar    return 0;
27272445Sassar}
27372445Sassar#endif
274