]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ntp/libisc/ifiter_getifaddrs.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ntp / libisc / ifiter_getifaddrs.c
1 /*
2  * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /* $Id: ifiter_getifaddrs.c,v 1.2.68.3 2004/03/06 08:14:59 marka Exp $ */
19
20 /*
21  * Obtain the list of network interfaces using the getifaddrs(3) library.
22  */
23
24 #include <ifaddrs.h>
25
26 #define IFITER_MAGIC            ISC_MAGIC('I', 'F', 'I', 'G')
27 #define VALID_IFITER(t)         ISC_MAGIC_VALID(t, IFITER_MAGIC)
28
29 struct isc_interfaceiter {
30         unsigned int            magic;          /* Magic number. */
31         isc_mem_t               *mctx;
32         void                    *buf;           /* (unused) */
33         unsigned int            bufsize;        /* (always 0) */
34         struct ifaddrs          *ifaddrs;       /* List of ifaddrs */
35         struct ifaddrs          *pos;           /* Ptr to current ifaddr */
36         isc_interface_t         current;        /* Current interface data. */
37         isc_result_t            result;         /* Last result code. */
38 };
39
40 isc_result_t
41 isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
42         isc_interfaceiter_t *iter;
43         isc_result_t result;
44         char strbuf[ISC_STRERRORSIZE];
45
46         REQUIRE(iterp != NULL);
47         REQUIRE(*iterp == NULL);
48
49         iter = isc_mem_get(mctx, sizeof(*iter));
50         if (iter == NULL)
51                 return (ISC_R_NOMEMORY);
52
53         iter->mctx = mctx;
54         iter->buf = NULL;
55         iter->bufsize = 0;
56         iter->ifaddrs = NULL;
57
58         if (getifaddrs(&iter->ifaddrs) < 0) {
59                 isc__strerror(errno, strbuf, sizeof(strbuf));
60                 UNEXPECTED_ERROR(__FILE__, __LINE__,
61                                  isc_msgcat_get(isc_msgcat,
62                                                 ISC_MSGSET_IFITERGETIFADDRS,
63                                                 ISC_MSG_GETIFADDRS,
64                                                 "getting interface "
65                                                 "addresses: getifaddrs: %s"),
66                                  strbuf);
67                 result = ISC_R_UNEXPECTED;
68                 goto failure;
69         }
70
71         /*
72          * A newly created iterator has an undefined position
73          * until isc_interfaceiter_first() is called.
74          */
75         iter->pos = NULL;
76         iter->result = ISC_R_FAILURE;
77
78         iter->magic = IFITER_MAGIC;
79         *iterp = iter;
80         return (ISC_R_SUCCESS);
81
82  failure:
83         if (iter->ifaddrs != NULL) /* just in case */
84                 freeifaddrs(iter->ifaddrs);
85         isc_mem_put(mctx, iter, sizeof(*iter));
86         return (result);
87 }
88
89 /*
90  * Get information about the current interface to iter->current.
91  * If successful, return ISC_R_SUCCESS.
92  * If the interface has an unsupported address family,
93  * return ISC_R_IGNORE.
94  */
95
96 static isc_result_t
97 internal_current(isc_interfaceiter_t *iter) {
98         struct ifaddrs *ifa;
99         int family;
100         unsigned int namelen;
101
102         REQUIRE(VALID_IFITER(iter));
103
104         ifa = iter->pos;
105
106         INSIST(ifa != NULL);
107         INSIST(ifa->ifa_name != NULL);
108         INSIST(ifa->ifa_addr != NULL);
109
110         family = ifa->ifa_addr->sa_family;
111         if (family != AF_INET && family != AF_INET6)
112                 return (ISC_R_IGNORE);
113
114         memset(&iter->current, 0, sizeof(iter->current));
115
116         namelen = strlen(ifa->ifa_name);
117         if (namelen > sizeof(iter->current.name) - 1)
118                 namelen = sizeof(iter->current.name) - 1;
119
120         memset(iter->current.name, 0, sizeof(iter->current.name));
121         memcpy(iter->current.name, ifa->ifa_name, namelen);
122
123         iter->current.flags = 0;
124
125         if ((ifa->ifa_flags & IFF_UP) != 0)
126                 iter->current.flags |= INTERFACE_F_UP;
127
128         if ((ifa->ifa_flags & IFF_POINTOPOINT) != 0)
129                 iter->current.flags |= INTERFACE_F_POINTTOPOINT;
130
131         if ((ifa->ifa_flags & IFF_LOOPBACK) != 0)
132                 iter->current.flags |= INTERFACE_F_LOOPBACK;
133
134         if ((ifa->ifa_flags & IFF_BROADCAST) != 0) {
135                 iter->current.flags |= INTERFACE_F_BROADCAST;
136         }
137
138 #ifdef IFF_MULTICAST
139         if ((ifa->ifa_flags & IFF_MULTICAST) != 0) {
140                 iter->current.flags |= INTERFACE_F_MULTICAST;
141         }
142 #endif
143         iter->current.af = family;
144
145         get_addr(family, &iter->current.address, ifa->ifa_addr, ifa->ifa_name);
146
147         if (ifa->ifa_netmask != NULL)
148                 get_addr(family, &iter->current.netmask, ifa->ifa_netmask,
149                          ifa->ifa_name);
150
151         if (ifa->ifa_dstaddr != NULL &&
152             (iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0)
153                 get_addr(family, &iter->current.dstaddress, ifa->ifa_dstaddr,
154                          ifa->ifa_name);
155
156         if (ifa->ifa_broadaddr != NULL &&
157             (iter->current.flags & INTERFACE_F_BROADCAST) != 0)
158                 get_addr(family, &iter->current.broadcast, ifa->ifa_broadaddr,
159                          ifa->ifa_name);
160
161         return (ISC_R_SUCCESS);
162 }
163
164 /*
165  * Step the iterator to the next interface.  Unlike
166  * isc_interfaceiter_next(), this may leave the iterator
167  * positioned on an interface that will ultimately
168  * be ignored.  Return ISC_R_NOMORE if there are no more
169  * interfaces, otherwise ISC_R_SUCCESS.
170  */
171 static isc_result_t
172 internal_next(isc_interfaceiter_t *iter) {
173         iter->pos = iter->pos->ifa_next;
174
175         if (iter->pos == NULL)
176                 return (ISC_R_NOMORE);
177
178         return (ISC_R_SUCCESS);
179 }
180
181 static void
182 internal_destroy(isc_interfaceiter_t *iter) {
183         if (iter->ifaddrs)
184                 freeifaddrs(iter->ifaddrs);
185         iter->ifaddrs = NULL;
186 }
187
188 static
189 void internal_first(isc_interfaceiter_t *iter) {
190         iter->pos = iter->ifaddrs;
191 }