diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libc/net/Makefile.inc | 10 | ||||
-rw-r--r-- | lib/libc/net/getifaddrs.3 | 161 | ||||
-rw-r--r-- | lib/libc/net/getifaddrs.c | 373 |
3 files changed, 539 insertions, 5 deletions
diff --git a/lib/libc/net/Makefile.inc b/lib/libc/net/Makefile.inc index 7174d682205..7504a3e1959 100644 --- a/lib/libc/net/Makefile.inc +++ b/lib/libc/net/Makefile.inc @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile.inc,v 1.28 2000/01/27 05:18:46 itojun Exp $ +# $OpenBSD: Makefile.inc,v 1.29 2000/02/23 06:55:58 itojun Exp $ # net sources .PATH: ${LIBCSRCDIR}/arch/${MACHINE_ARCH}/net ${LIBCSRCDIR}/net @@ -6,7 +6,7 @@ CFLAGS+=-DRESOLVSORT SRCS+= base64.c freeaddrinfo.c gai_strerror.c getaddrinfo.c gethostnamadr.c \ - getnameinfo.c getnetbyaddr.c getnetbyname.c getnetent.c \ + getifaddrs.c getnameinfo.c getnetbyaddr.c getnetbyname.c getnetent.c \ getnetnamadr.c getproto.c getprotoent.c getprotoname.c \ getservbyname.c getservbyport.c getservent.c herror.c \ if_indextoname.c if_nameindex.c if_nametoindex.c inet_addr.c \ @@ -28,9 +28,9 @@ SRCS+= ip6opt.c rthdr.c vars6.c .include "${LIBCSRCDIR}/arch/${MACHINE_ARCH}/net/Makefile.inc" -MAN+= byteorder.3 ethers.3 getaddrinfo.3 gethostbyname.3 getnameinfo.3 \ - getnetent.3 getprotoent.3 getservent.3 inet.3 if_indextoname.3 \ - inet_net.3 iso_addr.3 link_addr.3 ns.3 ipx.3 \ +MAN+= byteorder.3 ethers.3 getaddrinfo.3 gethostbyname.3 getifaddrs.3 \ + getnameinfo.3 getnetent.3 getprotoent.3 getservent.3 inet.3 \ + if_indextoname.3 inet_net.3 iso_addr.3 link_addr.3 ns.3 ipx.3 \ rcmd.3 rcmdsh.3 resolver.3 net_addrcmp.3 \ inet6_option_space.3 inet6_rthdr_space.3 diff --git a/lib/libc/net/getifaddrs.3 b/lib/libc/net/getifaddrs.3 new file mode 100644 index 00000000000..68c12b552a8 --- /dev/null +++ b/lib/libc/net/getifaddrs.3 @@ -0,0 +1,161 @@ +.\" $OpenBSD: getifaddrs.3,v 1.1 2000/02/23 06:55:58 itojun Exp $ +.\" BSDI getifaddrs.3,v 2.4 1999/03/15 20:57:20 jch Exp +.\" +.\" Copyright (c) 1995, 1999 +.\" Berkeley Software Design, Inc. 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. +.\" +.\" THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``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 Berkeley Software Design, Inc. 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. +.Dd "October 12, 1995" +.Dt GETIFADDRS 3 +.Sh NAME +.Nm getifaddrs +.Nd get interface addresses +.Sh SYNOPSIS +.Fd #include <sys/types.h> +.Fd #include <sys/socket.h> +.Fd #include <ifaddrs.h> +.Ft int +.Fn getifaddrs "struct ifaddrs **ifap" +.Sh DESCRIPTION +The +.Fn getifaddrs +function stores a reference to a linked list of the network interfaces +on the local machine in the memory referenced by +.Fa ifap . +The list consists of +.Nm ifaddrs +structures, as defined in the include file +.Aq Pa ifaddrs.h . +The +.Nm ifaddrs +structure contains at least the following entries: +.Bd -literal + struct ifaddrs *ifa_next; /* Pointer to next struct */ + char *ifa_name; /* Interface name */ + u_int ifa_flags; /* Interface flags */ + struct sockaddr *ifa_addr; /* Interface address */ + struct sockaddr *ifa_netmask; /* Interface netmask */ + struct sockaddr *ifa_broadaddr; /* Interface broadcast address */ + struct sockaddr *ifa_dstaddr; /* P2P interface destination */ + void *ifa_data; /* Address specific data */ +.Ed +.Pp +The +.Li ifa_next +field contains a pointer to the next structure on the list. +This field is +.Dv NULL +in last structure on the list. +.Pp +The +.Li ifa_name +field contains the interface name. +.Pp +The +.Li ifa_flags +field contains the interface flags, as set by +.Xr ifconfig 8 +utility. +.Pp +The +.Li ifa_addr +field references either the address of the interface or the link level +address of the interface, if one exists, otherwise it is NULL. +(The +.Li sa_family +field of the +.Li ifa_addr +field should be consulted to determine the format of the +.Li ifa_addr +address.) +.Pp +The +.Li ifa_netmask +field references the netmask associated with +.Li ifa_addr , +if one is set, otherwise it is NULL. +.Pp +The +.Li ifa_broadaddr +field, +which should only be referenced for non-P2P interfaces, +references the broadcast address associated with +.Li ifa_addr , +if one exists, otherwise it is NULL. +.Pp +The +.Li ifa_dstaddr +field references the destination address on a P2P interface, +if one exists, otherwise it is NULL. +.Pp +The +.Li ifa_data +field references address family specific data. For +.Dv AF_LINK +addresses it contains a pointer to the +.Fa struct if_data +.Pq as defined in include file Aq Pa net/if.h +which contains various interface attributes and statistics. +For all other address families, it contains a pointer to the +.Fa struct ifa_data +.Pq as defined in include file Aq Pa net/if.h +which contains per-address interface statistics. +.Pp +The data returned by +.Fn getifaddrs +is dynamically allocated and should be freed using +.Fn free +.Pq see Xr free 3 +when no longer needed. +.Sh RETURN VALUES +Upon successful completion, a value of 0 is returned. +Otherwise, a value of -1 is returned and +.Va errno +is set to indicate the error. +.Sh ERRORS +The +.Fn getifaddrs +may fail and set +.Va errno +for any of the errors specified for the library routines +.Xr ioctl 2 , +.Xr socket 2 , +.Xr malloc 3 +or +.Xr sysctl 3 . +.Sh BUGS +If both +.Aq Pa net/if.h +and +.Aq Pa ifaddrs.h +are being included, +.Aq Pa net/if.h +.Em must +be included before +.Aq Pa ifaddrs.h . +.Sh SEE ALSO +.Xr ioctl 2 , +.Xr socket 2 , +.Xr sysctl 3 , +.Xr networking 4 , +.Xr ifconfig 8 +.Sh HISTORY +The +.Nm +implementation first appeared in BSDI BSD/OS. diff --git a/lib/libc/net/getifaddrs.c b/lib/libc/net/getifaddrs.c new file mode 100644 index 00000000000..9537405667c --- /dev/null +++ b/lib/libc/net/getifaddrs.c @@ -0,0 +1,373 @@ +/* $OpenBSD: getifaddrs.c,v 1.1 2000/02/23 06:55:58 itojun Exp $ */ + +/* + * Copyright (c) 1995, 1999 + * Berkeley Software Design, Inc. 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. + * + * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``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 Berkeley Software Design, Inc. 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. + * + * BSDI getifaddrs.c,v 2.11 1999/03/15 20:57:20 jch Exp + */ +/* + * NOTE: SIOCGIFCONF case is not LP64 friendly. it also does not perform + * try-and-error for region size. + */ +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <net/if.h> +#ifdef NET_RT_IFLIST +#include <sys/param.h> +#include <net/route.h> +#include <sys/sysctl.h> +#include <net/if_dl.h> +#endif + +#include <errno.h> +#include <ifaddrs.h> +#include <stdlib.h> +#include <string.h> + +#if !defined(AF_LINK) +#define SA_LEN(sa) sizeof(struct sockaddr) +#endif + +#if !defined(SA_LEN) +#define SA_LEN(sa) (sa)->sa_len +#endif + +#define SALIGN (sizeof(long) - 1) +#define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : (SALIGN + 1)) + +#ifndef ALIGNBYTES +/* + * On systems with a routing socket, ALIGNBYTES should match the value + * that the kernel uses when building the messages. + */ +#define ALIGNBYTES XXX +#endif +#ifndef ALIGN +#define ALIGN(p) (((u_long)(p) + ALIGNBYTES) &~ ALIGNBYTES) +#endif + +#if _BSDI_VERSION >= 199701 +#define HAVE_IFM_DATA +#endif + +#if _BSDI_VERSION >= 199802 +#define HAVE_IFAM_DATA +#endif + +int +getifaddrs(struct ifaddrs **pif) +{ + int icnt = 1; + int dcnt = 0; + int ncnt = 0; +#ifdef NET_RT_IFLIST + int mib[6]; + size_t needed; + char *buf; + char *next; + struct ifaddrs *cif = 0; + char *p, *p0; + struct rt_msghdr *rtm; + struct if_msghdr *ifm; + struct ifa_msghdr *ifam; + struct sockaddr_dl *dl; + struct sockaddr *sa; + struct ifaddrs *ifa, *ift; + u_short index = 0; +#else /* NET_RT_IFLIST */ + char buf[1024]; + int m, sock; + struct ifconf ifc; + struct ifreq *ifr; + struct ifreq *lifr; +#endif /* NET_RT_IFLIST */ + int i; + size_t len, alen; + char *data; + char *names; + +#ifdef NET_RT_IFLIST + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; /* protocol */ + mib[3] = 0; /* wildcard address family */ + mib[4] = NET_RT_IFLIST; + mib[5] = 0; /* no flags */ + if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) + return (-1); + if ((buf = malloc(needed)) == NULL) + return (-1); + if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { + free(buf); + return (-1); + } + + for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { + rtm = (struct rt_msghdr *)next; + if (rtm->rtm_version != RTM_VERSION) + continue; + switch (rtm->rtm_type) { + case RTM_IFINFO: + ifm = (struct if_msghdr *)rtm; + if (ifm->ifm_addrs & RTA_IFP) { + index = ifm->ifm_index; + ++icnt; + dl = (struct sockaddr_dl *)(ifm + 1); + dcnt += SA_RLEN((struct sockaddr *)dl) + + ALIGNBYTES; +#ifdef HAVE_IFM_DATA + dcnt += sizeof(ifm->ifm_data); +#endif /* HAVE_IFM_DATA */ + ncnt += dl->sdl_nlen + 1; + } else + index = 0; + break; + + case RTM_NEWADDR: + ifam = (struct ifa_msghdr *)rtm; + if (index && ifam->ifam_index != index) + abort(); /* this cannot happen */ + +#define RTA_MASKS (RTA_NETMASK | RTA_IFA | RTA_BRD) + if (index == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0) + break; + p = (char *)(ifam + 1); + ++icnt; +#ifdef HAVE_IFAM_DATA + dcnt += sizeof(ifam->ifam_data) + ALIGNBYTES; +#endif /* HAVE_IFAM_DATA */ + /* Scan to look for length of address */ + alen = 0; + for (p0 = p, i = 0; i < RTAX_MAX; i++) { + if ((RTA_MASKS & ifam->ifam_addrs & (1 << i)) + == 0) + continue; + sa = (struct sockaddr *)p; + len = SA_RLEN(sa); + if (i == RTAX_IFA) { + alen = len; + break; + } + p += len; + } + for (p = p0, i = 0; i < RTAX_MAX; i++) { + if ((RTA_MASKS & ifam->ifam_addrs & (1 << i)) + == 0) + continue; + sa = (struct sockaddr *)p; + len = SA_RLEN(sa); + if (i == RTAX_NETMASK && SA_LEN(sa) == 0) + dcnt += alen; + else + dcnt += len; + p += len; + } + break; + } + } +#else /* NET_RT_IFLIST */ + ifc.ifc_buf = buf; + ifc.ifc_len = sizeof(buf); + + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) + return (-1); + i = ioctl(sock, SIOCGIFCONF, (char *)&ifc); + close(sock); + if (i < 0) + return (-1); + + ifr = ifc.ifc_req; + lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len]; + + while (ifr < lifr) { + struct sockaddr *sa; + + sa = &ifr->ifr_addr; + ++icnt; + dcnt += SA_RLEN(sa); + ncnt += sizeof(ifr->ifr_name) + 1; + + ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa)); + } +#endif /* NET_RT_IFLIST */ + + if (icnt + dcnt + ncnt == 1) { + *pif = NULL; + free(buf); + return (0); + } + data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt); + if (data == NULL) { + free(buf); + return(-1); + } + + ifa = (struct ifaddrs *)data; + data += sizeof(struct ifaddrs) * icnt; + names = data + dcnt; + + memset(ifa, 0, sizeof(struct ifaddrs) * icnt); + ift = ifa; + +#ifdef NET_RT_IFLIST + index = 0; + for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { + rtm = (struct rt_msghdr *)next; + if (rtm->rtm_version != RTM_VERSION) + continue; + switch (rtm->rtm_type) { + case RTM_IFINFO: + ifm = (struct if_msghdr *)rtm; + if (ifm->ifm_addrs & RTA_IFP) { + index = ifm->ifm_index; + dl = (struct sockaddr_dl *)(ifm + 1); + + cif = ift; + ift->ifa_name = names; + ift->ifa_flags = (int)ifm->ifm_flags; + memcpy(names, dl->sdl_data, dl->sdl_nlen); + names[dl->sdl_nlen] = 0; + names += dl->sdl_nlen + 1; + + ift->ifa_addr = (struct sockaddr *)data; + memcpy(data, dl, SA_LEN((struct sockaddr *)dl)); + data += SA_RLEN((struct sockaddr *)dl); + +#ifdef HAVE_IFM_DATA + /* ifm_data needs to be aligned */ + ift->ifa_data = data = (void *)ALIGN(data); + memcpy(data, &ifm->ifm_data, sizeof(ifm->ifm_data)); + data += sizeof(ifm->ifm_data); +#else /* HAVE_IFM_DATA */ + ift->ifa_data = NULL; +#endif /* HAVE_IFM_DATA */ + + ift = (ift->ifa_next = ift + 1); + } else + index = 0; + break; + + case RTM_NEWADDR: + ifam = (struct ifa_msghdr *)rtm; + if (index && ifam->ifam_index != index) + abort(); /* this cannot happen */ + + if (index == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0) + break; + ift->ifa_name = cif->ifa_name; + ift->ifa_flags = cif->ifa_flags; + ift->ifa_data = NULL; + p = (char *)(ifam + 1); + /* Scan to look for length of address */ + alen = 0; + for (p0 = p, i = 0; i < RTAX_MAX; i++) { + if ((RTA_MASKS & ifam->ifam_addrs & (1 << i)) + == 0) + continue; + sa = (struct sockaddr *)p; + len = SA_RLEN(sa); + if (i == RTAX_IFA) { + alen = len; + break; + } + p += len; + } + for (p = p0, i = 0; i < RTAX_MAX; i++) { + if ((RTA_MASKS & ifam->ifam_addrs & (1 << i)) + == 0) + continue; + sa = (struct sockaddr *)p; + len = SA_RLEN(sa); + switch (i) { + case RTAX_IFA: + ift->ifa_addr = (struct sockaddr *)data; + memcpy(data, p, len); + data += len; + break; + + case RTAX_NETMASK: + ift->ifa_netmask = + (struct sockaddr *)data; + if (SA_LEN(sa) == 0) { + memset(data, 0, alen); + data += alen; + break; + } + memcpy(data, p, len); + data += len; + break; + + case RTAX_BRD: + ift->ifa_broadaddr = + (struct sockaddr *)data; + memcpy(data, p, len); + data += len; + break; + } + p += len; + } + +#ifdef HAVE_IFAM_DATA + /* ifam_data needs to be aligned */ + ift->ifa_data = data = (void *)ALIGN(data); + memcpy(data, &ifam->ifam_data, sizeof(ifam->ifam_data)); + data += sizeof(ifam->ifam_data); +#endif /* HAVE_IFAM_DATA */ + + ift = (ift->ifa_next = ift + 1); + break; + } + } + + free(buf); +#else /* NET_RT_IFLIST */ + ifr = ifc.ifc_req; + lifr = (struct ifreq *)&ifc.ifc_buf[ifc.ifc_len]; + + while (ifr < lifr) { + struct sockaddr *sa; + + ift->ifa_name = names; + names[sizeof(ifr->ifr_name)] = 0; + strncpy(names, ifr->ifr_name, sizeof(ifr->ifr_name)); + while (*names++) + ; + + ift->ifa_addr = (struct sockaddr *)data; + sa = &ifr->ifr_addr; + memcpy(data, sa, SA_LEN(sa)); + data += SA_RLEN(sa); + + ifr = (struct ifreq *)(((char *)sa) + SA_LEN(sa)); + ift = (ift->ifa_next = ift + 1); + } +#endif /* NET_RT_IFLIST */ + if (--ift >= ifa) { + ift->ifa_next = NULL; + *pif = ifa; + } else { + *pif = NULL; + free(ifa); + } + return (0); +} |