Merge branch 'vendor/GCC44'
[dragonfly.git] / contrib / bind-9.3 / lib / isc / unix / 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(mctx != NULL);
47         REQUIRE(iterp != NULL);
48         REQUIRE(*iterp == NULL);
49
50         iter = isc_mem_get(mctx, sizeof(*iter));
51         if (iter == NULL)
52                 return (ISC_R_NOMEMORY);
53
54         iter->mctx = mctx;
55         iter->buf = NULL;
56         iter->bufsize = 0;
57         iter->ifaddrs = NULL;
58
59         if (getifaddrs(&iter->ifaddrs) < 0) {
60                 isc__strerror(errno, strbuf, sizeof(strbuf));
61                 UNEXPECTED_ERROR(__FILE__, __LINE__,
62                                  isc_msgcat_get(isc_msgcat,
63                                                 ISC_MSGSET_IFITERGETIFADDRS,
64                                                 ISC_MSG_GETIFADDRS,
65                                                 "getting interface "
66                                                 "addresses: getifaddrs: %s"),
67                                  strbuf);
68                 result = ISC_R_UNEXPECTED;
69                 goto failure;
70         }
71
72         /*
73          * A newly created iterator has an undefined position
74          * until isc_interfaceiter_first() is called.
75          */
76         iter->pos = NULL;
77         iter->result = ISC_R_FAILURE;
78
79         iter->magic = IFITER_MAGIC;
80         *iterp = iter;
81         return (ISC_R_SUCCESS);
82
83  failure:
84         if (iter->ifaddrs != NULL) /* just in case */
85                 freeifaddrs(iter->ifaddrs);
86         isc_mem_put(mctx, iter, sizeof(*iter));
87         return (result);
88 }
89
90 /*
91  * Get information about the current interface to iter->current.
92  * If successful, return ISC_R_SUCCESS.
93  * If the interface has an unsupported address family,
94  * return ISC_R_IGNORE.
95  */
96
97 static isc_result_t
98 internal_current(isc_interfaceiter_t *iter) {
99         struct ifaddrs *ifa;
100         int family;
101         unsigned int namelen;
102
103         REQUIRE(VALID_IFITER(iter));
104
105         ifa = iter->pos;
106
107         INSIST(ifa != NULL);
108         INSIST(ifa->ifa_name != NULL);
109         INSIST(ifa->ifa_addr != NULL);
110
111         family = ifa->ifa_addr->sa_family;
112         if (family != AF_INET && family != AF_INET6)
113                 return (ISC_R_IGNORE);
114
115         memset(&iter->current, 0, sizeof(iter->current));
116
117         namelen = strlen(ifa->ifa_name);
118         if (namelen > sizeof(iter->current.name) - 1)
119                 namelen = sizeof(iter->current.name) - 1;
120
121         memset(iter->current.name, 0, sizeof(iter->current.name));
122         memcpy(iter->current.name, ifa->ifa_name, namelen);
123
124         iter->current.flags = 0;
125
126         if ((ifa->ifa_flags & IFF_UP) != 0)
127                 iter->current.flags |= INTERFACE_F_UP;
128
129         if ((ifa->ifa_flags & IFF_POINTOPOINT) != 0)
130                 iter->current.flags |= INTERFACE_F_POINTTOPOINT;
131
132         if ((ifa->ifa_flags & IFF_LOOPBACK) != 0)
133                 iter->current.flags |= INTERFACE_F_LOOPBACK;
134
135         iter->current.af = family;
136
137         get_addr(family, &iter->current.address, ifa->ifa_addr, ifa->ifa_name);
138
139         if (ifa->ifa_netmask != NULL)
140                 get_addr(family, &iter->current.netmask, ifa->ifa_netmask,
141                          ifa->ifa_name);
142
143         if (ifa->ifa_dstaddr != NULL &&
144             (iter->current.flags & IFF_POINTOPOINT) != 0)
145                 get_addr(family, &iter->current.dstaddress, ifa->ifa_dstaddr,
146                          ifa->ifa_name);
147
148         return (ISC_R_SUCCESS);
149 }
150
151 /*
152  * Step the iterator to the next interface.  Unlike
153  * isc_interfaceiter_next(), this may leave the iterator
154  * positioned on an interface that will ultimately
155  * be ignored.  Return ISC_R_NOMORE if there are no more
156  * interfaces, otherwise ISC_R_SUCCESS.
157  */
158 static isc_result_t
159 internal_next(isc_interfaceiter_t *iter) {
160         iter->pos = iter->pos->ifa_next;
161
162         if (iter->pos == NULL)
163                 return (ISC_R_NOMORE);
164
165         return (ISC_R_SUCCESS);
166 }
167
168 static void
169 internal_destroy(isc_interfaceiter_t *iter) {
170         if (iter->ifaddrs)
171                 freeifaddrs(iter->ifaddrs);
172         iter->ifaddrs = NULL;
173 }
174
175 static
176 void internal_first(isc_interfaceiter_t *iter) {
177         iter->pos = iter->ifaddrs;
178 }