Merge from vendor branch HEIMDAL:
[dragonfly.git] / contrib / bind-9.2.4rc7 / lib / isc / unix / ifiter_ioctl.c
1 /*
2  * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2001, 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_ioctl.c,v 1.19.2.6 2004/03/09 06:12:10 marka Exp $ */
19
20 /*
21  * Obtain the list of network interfaces using the SIOCGLIFCONF ioctl.
22  * See netintro(4).
23  */
24 #ifdef __hpux
25 #undef SIOCGLIFCONF
26 #undef lifc_len
27 #undef lifc_buf
28 #undef lifc_req
29 #undef lifconf
30 #undef SIOCGLIFADDR
31 #undef SIOCGLIFFLAGS
32 #undef SIOCGLIFDSTADDR
33 #undef SIOCGLIFNETMASK
34 #undef lifr_addr
35 #undef lifr_name
36 #undef lifr_dstaddr
37 #undef lifr_flags
38 #undef ss_family
39 #undef lifreq
40 #endif
41
42 #ifndef SIOCGLIFCONF
43 #define SIOCGLIFCONF SIOCGIFCONF
44 #define lifc_len ifc_len
45 #define lifc_buf ifc_buf
46 #define lifc_req ifc_req
47 #define lifconf ifconf
48 #else
49 #define ISC_HAVE_LIFC_FAMILY 1
50 #define ISC_HAVE_LIFC_FLAGS 1
51 #endif
52 #ifndef SIOCGLIFADDR
53 #define SIOCGLIFADDR SIOCGIFADDR
54 #define SIOCGLIFFLAGS SIOCGIFFLAGS
55 #define SIOCGLIFDSTADDR SIOCGIFDSTADDR
56 #define SIOCGLIFNETMASK SIOCGIFNETMASK
57 #define lifr_addr ifr_addr
58 #define lifr_name ifr_name
59 #define lifr_dstaddr ifr_dstaddr
60 #define lifr_flags ifr_flags
61 #define ss_family sa_family
62 #define lifreq ifreq
63 #endif
64
65
66 #define IFITER_MAGIC            ISC_MAGIC('I', 'F', 'I', 'T')
67 #define VALID_IFITER(t)         ISC_MAGIC_VALID(t, IFITER_MAGIC)
68
69 struct isc_interfaceiter {
70         unsigned int            magic;          /* Magic number. */
71         isc_mem_t               *mctx;
72         int                     socket;
73         struct lifconf          ifc;
74         void                    *buf;           /* Buffer for sysctl data. */
75         unsigned int            bufsize;        /* Bytes allocated. */
76         unsigned int            pos;            /* Current offset in
77                                                    SIOCGLIFCONF data */
78         isc_interface_t         current;        /* Current interface data. */
79         isc_result_t            result;         /* Last result code. */
80 };
81
82
83 /*
84  * Size of buffer for SIOCGLIFCONF, in bytes.  We assume no sane system
85  * will have more than a megabyte of interface configuration data.
86  */
87 #define IFCONF_BUFSIZE_INITIAL  4096
88 #define IFCONF_BUFSIZE_MAX      1048576
89
90 isc_result_t
91 isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
92         isc_interfaceiter_t *iter;
93         isc_result_t result;
94         char strbuf[ISC_STRERRORSIZE];
95
96         REQUIRE(mctx != NULL);
97         REQUIRE(iterp != NULL);
98         REQUIRE(*iterp == NULL);
99
100         iter = isc_mem_get(mctx, sizeof(*iter));
101         if (iter == NULL)
102                 return (ISC_R_NOMEMORY);
103
104         iter->mctx = mctx;
105         iter->buf = NULL;
106
107         /*
108          * Create an unbound datagram socket to do the SIOCGLIFADDR ioctl on.
109          */
110         if ((iter->socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
111                 isc__strerror(errno, strbuf, sizeof(strbuf));
112                 UNEXPECTED_ERROR(__FILE__, __LINE__,
113                                  isc_msgcat_get(isc_msgcat,
114                                                 ISC_MSGSET_IFITERIOCTL,
115                                                 ISC_MSG_MAKESCANSOCKET,
116                                                 "making interface "
117                                                 "scan socket: %s"),
118                                  strbuf);
119                 result = ISC_R_UNEXPECTED;
120                 goto socket_failure;
121         }
122
123         /*
124          * Get the interface configuration, allocating more memory if
125          * necessary.
126          */
127         iter->bufsize = IFCONF_BUFSIZE_INITIAL;
128
129         for (;;) {
130                 iter->buf = isc_mem_get(mctx, iter->bufsize);
131                 if (iter->buf == NULL) {
132                         result = ISC_R_NOMEMORY;
133                         goto alloc_failure;
134                 }
135
136                 memset(&iter->ifc, 0, sizeof(iter->ifc));
137 #ifdef ISC_HAVE_LIFC_FAMILY
138                 iter->ifc.lifc_family = AF_UNSPEC;
139 #endif
140 #ifdef ISC_HAVE_LIFC_FLAGS
141                 iter->ifc.lifc_flags = 0;
142 #endif
143                 iter->ifc.lifc_len = iter->bufsize;
144                 iter->ifc.lifc_buf = iter->buf;
145                 /*
146                  * Ignore the HP/UX warning about "interger overflow during
147                  * conversion".  It comes from its own macro definition,
148                  * and is really hard to shut up.
149                  */
150                 if (ioctl(iter->socket, SIOCGLIFCONF, (char *)&iter->ifc)
151                     == -1) {
152                         if (errno != EINVAL) {
153                                 isc__strerror(errno, strbuf, sizeof(strbuf));
154                                 UNEXPECTED_ERROR(__FILE__, __LINE__,
155                                                  isc_msgcat_get(isc_msgcat,
156                                                         ISC_MSGSET_IFITERIOCTL,
157                                                         ISC_MSG_GETIFCONFIG,
158                                                         "get interface "
159                                                         "configuration: %s"),
160                                                  strbuf);
161                                 result = ISC_R_UNEXPECTED;
162                                 goto ioctl_failure;
163                         }
164                         /*
165                          * EINVAL.  Retry with a bigger buffer.
166                          */
167                 } else {
168                         /*
169                          * The ioctl succeeded.
170                          * Some OS's just return what will fit rather
171                          * than set EINVAL if the buffer is too small
172                          * to fit all the interfaces in.  If
173                          * ifc.lifc_len is too near to the end of the
174                          * buffer we will grow it just in case and
175                          * retry.
176                          */
177                         if (iter->ifc.lifc_len + 2 * sizeof(struct lifreq)
178                             < iter->bufsize)
179                                 break;
180                 }
181                 if (iter->bufsize >= IFCONF_BUFSIZE_MAX) {
182                         UNEXPECTED_ERROR(__FILE__, __LINE__,
183                                          isc_msgcat_get(isc_msgcat,
184                                                         ISC_MSGSET_IFITERIOCTL,
185                                                         ISC_MSG_BUFFERMAX,
186                                                         "get interface "
187                                                         "configuration: "
188                                                         "maximum buffer "
189                                                         "size exceeded"));
190                         result = ISC_R_UNEXPECTED;
191                         goto ioctl_failure;
192                 }
193                 isc_mem_put(mctx, iter->buf, iter->bufsize);
194
195                 iter->bufsize *= 2;
196         }
197
198         /*
199          * A newly created iterator has an undefined position
200          * until isc_interfaceiter_first() is called.
201          */
202         iter->pos = (unsigned int) -1;
203         iter->result = ISC_R_FAILURE;
204
205         iter->magic = IFITER_MAGIC;
206         *iterp = iter;
207         return (ISC_R_SUCCESS);
208
209  ioctl_failure:
210         isc_mem_put(mctx, iter->buf, iter->bufsize);
211
212  alloc_failure:
213         (void) close(iter->socket);
214
215  socket_failure:
216         isc_mem_put(mctx, iter, sizeof *iter);
217         return (result);
218 }
219
220 /*
221  * Get information about the current interface to iter->current.
222  * If successful, return ISC_R_SUCCESS.
223  * If the interface has an unsupported address family, or if
224  * some operation on it fails, return ISC_R_IGNORE to make
225  * the higher-level iterator code ignore it.
226  */
227
228 static isc_result_t
229 internal_current(isc_interfaceiter_t *iter) {
230         struct lifreq *ifrp;
231         struct lifreq lifreq;
232         int family;
233         char strbuf[ISC_STRERRORSIZE];
234
235         REQUIRE(VALID_IFITER(iter));
236         REQUIRE (iter->pos < (unsigned int) iter->ifc.lifc_len);
237
238         ifrp = (struct lifreq *)((char *) iter->ifc.lifc_req + iter->pos);
239
240         memset(&lifreq, 0, sizeof lifreq);
241         memcpy(&lifreq, ifrp, sizeof lifreq);
242
243         family = lifreq.lifr_addr.ss_family;
244         if (family != AF_INET)
245                 return (ISC_R_IGNORE);
246
247         memset(&iter->current, 0, sizeof(iter->current));
248         iter->current.af = family;
249
250         INSIST(sizeof(lifreq.lifr_name) <= sizeof(iter->current.name));
251         memset(iter->current.name, 0, sizeof(iter->current.name));
252         memcpy(iter->current.name, lifreq.lifr_name, sizeof(lifreq.lifr_name));
253
254         get_addr(family, &iter->current.address,
255                  (struct sockaddr *)&lifreq.lifr_addr);
256
257         /*
258          * If the interface does not have a address ignore it.
259          */
260         switch (family) {
261         case AF_INET:
262                 if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
263                         return (ISC_R_IGNORE);
264                 break;
265         case AF_INET6:
266                 if (memcmp(&iter->current.address.type.in6, &in6addr_any,
267                            sizeof(in6addr_any)) == 0)
268                         return (ISC_R_IGNORE);
269                 break;
270         }
271
272         /*
273          * Get interface flags.
274          */
275
276         iter->current.flags = 0;
277
278         /*
279          * Ignore the HP/UX warning about "interger overflow during
280          * conversion.  It comes from its own macro definition,
281          * and is really hard to shut up.
282          */
283         if (ioctl(iter->socket, SIOCGLIFFLAGS, (char *) &lifreq) < 0) {
284                 isc__strerror(errno, strbuf, sizeof(strbuf));
285                 UNEXPECTED_ERROR(__FILE__, __LINE__,
286                                  "%s: getting interface flags: %s",
287                                  lifreq.lifr_name, strbuf);
288                 return (ISC_R_IGNORE);
289         }
290
291         if ((lifreq.lifr_flags & IFF_UP) != 0)
292                 iter->current.flags |= INTERFACE_F_UP;
293
294         if ((lifreq.lifr_flags & IFF_POINTOPOINT) != 0)
295                 iter->current.flags |= INTERFACE_F_POINTTOPOINT;
296
297         if ((lifreq.lifr_flags & IFF_LOOPBACK) != 0)
298                 iter->current.flags |= INTERFACE_F_LOOPBACK;
299
300         /*
301          * If the interface is point-to-point, get the destination address.
302          */
303         if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
304                 /*
305                  * Ignore the HP/UX warning about "interger overflow during
306                  * conversion.  It comes from its own macro definition,
307                  * and is really hard to shut up.
308                  */
309                 if (ioctl(iter->socket, SIOCGLIFDSTADDR, (char *)&lifreq)
310                     < 0) {
311                         isc__strerror(errno, strbuf, sizeof(strbuf));
312                         UNEXPECTED_ERROR(__FILE__, __LINE__,
313                                 isc_msgcat_get(isc_msgcat,
314                                                ISC_MSGSET_IFITERIOCTL,
315                                                ISC_MSG_GETDESTADDR,
316                                                "%s: getting "
317                                                "destination address: %s"),
318                                          lifreq.lifr_name, strbuf);
319                         return (ISC_R_IGNORE);
320                 }
321                 get_addr(family, &iter->current.dstaddress,
322                          (struct sockaddr *)&lifreq.lifr_dstaddr);
323         }
324
325         /*
326          * Get the network mask.
327          */
328         memset(&lifreq, 0, sizeof lifreq);
329         memcpy(&lifreq, ifrp, sizeof lifreq);
330         switch (family) {
331         case AF_INET:
332                 /*
333                  * Ignore the HP/UX warning about "interger overflow during
334                  * conversion.  It comes from its own macro definition,
335                  * and is really hard to shut up.
336                  */
337                 if (ioctl(iter->socket, SIOCGLIFNETMASK, (char *)&lifreq)
338                     < 0) {
339                         isc__strerror(errno, strbuf, sizeof(strbuf));
340                         UNEXPECTED_ERROR(__FILE__, __LINE__,
341                                 isc_msgcat_get(isc_msgcat,
342                                                ISC_MSGSET_IFITERIOCTL,
343                                                ISC_MSG_GETNETMASK,
344                                                "%s: getting netmask: %s"),
345                                          lifreq.lifr_name, strbuf);
346                         return (ISC_R_IGNORE);
347                 }
348                 get_addr(family, &iter->current.netmask,
349                          (struct sockaddr *)&lifreq.lifr_addr);
350                 break;
351         case AF_INET6: {
352 #ifdef lifr_addrlen
353                 int i, bits;
354
355                 /*
356                  * Netmask already zeroed.
357                  */
358                 iter->current.netmask.family = family;
359                 for (i = 0 ; i < lifreq.lifr_addrlen; i += 8) {
360                         bits = lifreq.lifr_addrlen - i;
361                         bits = (bits < 8 ) ? (8-bits) : 0;
362                         iter->current.netmask.type.in6.s6_addr[i/8] =
363                                  (~0 << bits) &0xff;
364                 }
365 #endif
366                 break;
367         }
368         }
369
370         return (ISC_R_SUCCESS);
371 }
372
373 /*
374  * Step the iterator to the next interface.  Unlike
375  * isc_interfaceiter_next(), this may leave the iterator
376  * positioned on an interface that will ultimately
377  * be ignored.  Return ISC_R_NOMORE if there are no more
378  * interfaces, otherwise ISC_R_SUCCESS.
379  */
380 static isc_result_t
381 internal_next(isc_interfaceiter_t *iter) {
382         struct lifreq *ifrp;
383
384         REQUIRE (iter->pos < (unsigned int) iter->ifc.lifc_len);
385
386         ifrp = (struct lifreq *)((char *) iter->ifc.lifc_req + iter->pos);
387
388 #ifdef ISC_PLATFORM_HAVESALEN
389         if (ifrp->lifr_addr.sa_len > sizeof(struct sockaddr))
390                 iter->pos += sizeof(ifrp->lifr_name) + ifrp->lifr_addr.sa_len;
391         else
392 #endif
393                 iter->pos += sizeof *ifrp;
394
395         if (iter->pos >= (unsigned int) iter->ifc.lifc_len)
396                 return (ISC_R_NOMORE);
397
398         return (ISC_R_SUCCESS);
399 }
400
401 static void
402 internal_destroy(isc_interfaceiter_t *iter) {
403         (void) close(iter->socket);
404 }