bind - Upgraded vendor branch to 9.5.2-P1
[dragonfly.git] / contrib / bind-9.5.2 / lib / isc / unix / ifiter_getifaddrs.c
1 /*
2  * Copyright (C) 2004, 2005, 2007  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and/or 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.9 2007/06/18 23:47:48 tbox Exp $ */
19
20 /*! \file
21  * \brief
22  * Obtain the list of network interfaces using the getifaddrs(3) library.
23  */
24
25 #include <ifaddrs.h>
26
27 /*% Iterator Magic */
28 #define IFITER_MAGIC            ISC_MAGIC('I', 'F', 'I', 'G')
29 /*% Valid Iterator */
30 #define VALID_IFITER(t)         ISC_MAGIC_VALID(t, IFITER_MAGIC)
31
32 /*% Iterator structure */
33 struct isc_interfaceiter {
34         unsigned int            magic;          /*%< Magic number. */
35         isc_mem_t               *mctx;
36         void                    *buf;           /*%< (unused) */
37         unsigned int            bufsize;        /*%< (always 0) */
38         struct ifaddrs          *ifaddrs;       /*%< List of ifaddrs */
39         struct ifaddrs          *pos;           /*%< Ptr to current ifaddr */
40         isc_interface_t         current;        /*%< Current interface data. */
41         isc_result_t            result;         /*%< Last result code. */
42 };
43
44
45 isc_result_t
46 isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
47         isc_interfaceiter_t *iter;
48         isc_result_t result;
49         char strbuf[ISC_STRERRORSIZE];
50
51         REQUIRE(mctx != NULL);
52         REQUIRE(iterp != NULL);
53         REQUIRE(*iterp == NULL);
54
55         iter = isc_mem_get(mctx, sizeof(*iter));
56         if (iter == NULL)
57                 return (ISC_R_NOMEMORY);
58
59         iter->mctx = mctx;
60         iter->buf = NULL;
61         iter->bufsize = 0;
62         iter->ifaddrs = NULL;
63
64         if (getifaddrs(&iter->ifaddrs) < 0) {
65                 isc__strerror(errno, strbuf, sizeof(strbuf));
66                 UNEXPECTED_ERROR(__FILE__, __LINE__,
67                                  isc_msgcat_get(isc_msgcat,
68                                                 ISC_MSGSET_IFITERGETIFADDRS,
69                                                 ISC_MSG_GETIFADDRS,
70                                                 "getting interface "
71                                                 "addresses: getifaddrs: %s"),
72                                  strbuf);
73                 result = ISC_R_UNEXPECTED;
74                 goto failure;
75         }
76
77         /*
78          * A newly created iterator has an undefined position
79          * until isc_interfaceiter_first() is called.
80          */
81         iter->pos = NULL;
82         iter->result = ISC_R_FAILURE;
83
84         iter->magic = IFITER_MAGIC;
85         *iterp = iter;
86         return (ISC_R_SUCCESS);
87
88  failure:
89         if (iter->ifaddrs != NULL) /* just in case */
90                 freeifaddrs(iter->ifaddrs);
91         isc_mem_put(mctx, iter, sizeof(*iter));
92         return (result);
93 }
94
95 /*
96  * Get information about the current interface to iter->current.
97  * If successful, return ISC_R_SUCCESS.
98  * If the interface has an unsupported address family,
99  * return ISC_R_IGNORE.
100  */
101
102 static isc_result_t
103 internal_current(isc_interfaceiter_t *iter) {
104         struct ifaddrs *ifa;
105         int family;
106         unsigned int namelen;
107
108         REQUIRE(VALID_IFITER(iter));
109
110         ifa = iter->pos;
111
112         INSIST(ifa != NULL);
113         INSIST(ifa->ifa_name != NULL);
114
115         if (ifa->ifa_addr == NULL)
116                 return (ISC_R_IGNORE);
117
118         family = ifa->ifa_addr->sa_family;
119         if (family != AF_INET && family != AF_INET6)
120                 return (ISC_R_IGNORE);
121
122         memset(&iter->current, 0, sizeof(iter->current));
123
124         namelen = strlen(ifa->ifa_name);
125         if (namelen > sizeof(iter->current.name) - 1)
126                 namelen = sizeof(iter->current.name) - 1;
127
128         memset(iter->current.name, 0, sizeof(iter->current.name));
129         memcpy(iter->current.name, ifa->ifa_name, namelen);
130
131         iter->current.flags = 0;
132
133         if ((ifa->ifa_flags & IFF_UP) != 0)
134                 iter->current.flags |= INTERFACE_F_UP;
135
136         if ((ifa->ifa_flags & IFF_POINTOPOINT) != 0)
137                 iter->current.flags |= INTERFACE_F_POINTTOPOINT;
138
139         if ((ifa->ifa_flags & IFF_LOOPBACK) != 0)
140                 iter->current.flags |= INTERFACE_F_LOOPBACK;
141
142         iter->current.af = family;
143
144         get_addr(family, &iter->current.address, ifa->ifa_addr, ifa->ifa_name);
145
146         if (ifa->ifa_netmask != NULL)
147                 get_addr(family, &iter->current.netmask, ifa->ifa_netmask,
148                          ifa->ifa_name);
149
150         if (ifa->ifa_dstaddr != NULL &&
151             (iter->current.flags & IFF_POINTOPOINT) != 0)
152                 get_addr(family, &iter->current.dstaddress, ifa->ifa_dstaddr,
153                          ifa->ifa_name);
154
155         return (ISC_R_SUCCESS);
156 }
157
158 /*
159  * Step the iterator to the next interface.  Unlike
160  * isc_interfaceiter_next(), this may leave the iterator
161  * positioned on an interface that will ultimately
162  * be ignored.  Return ISC_R_NOMORE if there are no more
163  * interfaces, otherwise ISC_R_SUCCESS.
164  */
165 static isc_result_t
166 internal_next(isc_interfaceiter_t *iter) {
167         iter->pos = iter->pos->ifa_next;
168
169         if (iter->pos == NULL)
170                 return (ISC_R_NOMORE);
171
172         return (ISC_R_SUCCESS);
173 }
174
175 static void
176 internal_destroy(isc_interfaceiter_t *iter) {
177         if (iter->ifaddrs)
178                 freeifaddrs(iter->ifaddrs);
179         iter->ifaddrs = NULL;
180 }
181
182 static
183 void internal_first(isc_interfaceiter_t *iter) {
184         iter->pos = iter->ifaddrs;
185 }