]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ntp/libisc/ifiter_ioctl.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ntp / libisc / ifiter_ioctl.c
1 /*
2  * Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-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.5.2.14 2004/06/22 04:40:23 marka Exp $ */
19
20 /*
21  * Obtain the list of network interfaces using the SIOCGLIFCONF ioctl.
22  * See netintro(4).
23  */
24
25 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
26 #ifdef ISC_PLATFORM_HAVEIF_LADDRCONF
27 #define lifc_len iflc_len
28 #define lifc_buf iflc_buf
29 #define lifc_req iflc_req
30 #define LIFCONF if_laddrconf
31 #else
32 #define ISC_HAVE_LIFC_FAMILY 1
33 #define ISC_HAVE_LIFC_FLAGS 1
34 #define LIFCONF lifconf
35 #endif
36
37 #ifdef ISC_PLATFORM_HAVEIF_LADDRREQ
38 #define lifr_addr iflr_addr
39 #define lifr_name iflr_name
40 #define lifr_dstaddr iflr_dstaddr
41 #define lifr_broadaddr iflr_broadaddr
42 #define lifr_flags iflr_flags
43 #define lifr_index iflr_index
44 #define ss_family sa_family
45 #define LIFREQ if_laddrreq
46 #else
47 #define LIFREQ lifreq
48 #endif
49 #endif
50
51 #define IFITER_MAGIC            ISC_MAGIC('I', 'F', 'I', 'T')
52 #define VALID_IFITER(t)         ISC_MAGIC_VALID(t, IFITER_MAGIC)
53
54 #define ISC_IF_INET6_SZ \
55     sizeof("00000000000000000000000000000001 01 80 10 80 XXXXXXloXXXXXXXX\n")
56
57 struct isc_interfaceiter {
58         unsigned int            magic;          /* Magic number. */
59         isc_mem_t               *mctx;
60         int                     mode;
61         int                     socket;
62         struct ifconf           ifc;
63         void                    *buf;           /* Buffer for sysctl data. */
64         unsigned int            bufsize;        /* Bytes allocated. */
65         unsigned int            pos;            /* Current offset in
66                                                    SIOCGIFCONF data */
67 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
68         int                     socket6;
69         struct LIFCONF          lifc;
70         void                    *buf6;          /* Buffer for sysctl data. */
71         unsigned int            bufsize6;       /* Bytes allocated. */
72         unsigned int            pos6;           /* Current offset in
73                                                    SIOCGLIFCONF data */
74         isc_result_t            result6;        /* Last result code. */
75         isc_boolean_t           first6;
76 #endif
77 #ifdef HAVE_TRUCLUSTER
78         int                     clua_context;   /* Cluster alias context */
79         isc_boolean_t           clua_done;
80         struct sockaddr         clua_sa;
81 #endif
82 #ifdef  __linux
83         FILE *                  proc;
84         char                    entry[ISC_IF_INET6_SZ];
85         isc_result_t            valid;
86         isc_boolean_t           first;
87 #endif
88         isc_interface_t         current;        /* Current interface data. */
89         isc_result_t            result;         /* Last result code. */
90 };
91
92 #ifdef HAVE_TRUCLUSTER
93 #include <clua/clua.h>
94 #include <sys/socket.h>
95 #endif
96
97
98 /*
99  * Size of buffer for SIOCGLIFCONF, in bytes.  We assume no sane system
100  * will have more than a megabyte of interface configuration data.
101  */
102 #define IFCONF_BUFSIZE_INITIAL  4096
103 #define IFCONF_BUFSIZE_MAX      1048576
104
105 #ifdef __linux
106 #ifndef IF_NAMESIZE
107 # ifdef IFNAMSIZ
108 #  define IF_NAMESIZE  IFNAMSIZ  
109 # else
110 #  define IF_NAMESIZE 16
111 # endif
112 #endif
113 #endif
114
115 static isc_result_t
116 getbuf4(isc_interfaceiter_t *iter) {
117         char strbuf[ISC_STRERRORSIZE];
118
119         iter->bufsize = IFCONF_BUFSIZE_INITIAL;
120
121         for (;;) {
122                 iter->buf = isc_mem_get(iter->mctx, iter->bufsize);
123                 if (iter->buf == NULL)
124                         return (ISC_R_NOMEMORY);
125
126                 memset(&iter->ifc.ifc_len, 0, sizeof(iter->ifc.ifc_len));
127                 iter->ifc.ifc_len = iter->bufsize;
128                 iter->ifc.ifc_buf = iter->buf;
129                 /*
130                  * Ignore the HP/UX warning about "integer overflow during
131                  * conversion".  It comes from its own macro definition,
132                  * and is really hard to shut up.
133                  */
134                 if (ioctl(iter->socket, SIOCGIFCONF, (char *)&iter->ifc)
135                     == -1) {
136                         if (errno != EINVAL) {
137                                 isc__strerror(errno, strbuf, sizeof(strbuf));
138                                 UNEXPECTED_ERROR(__FILE__, __LINE__,
139                                                  isc_msgcat_get(isc_msgcat,
140                                                         ISC_MSGSET_IFITERIOCTL,
141                                                         ISC_MSG_GETIFCONFIG,
142                                                         "get interface "
143                                                         "configuration: %s"),
144                                                  strbuf);
145                                 goto unexpected;
146                         }
147                         /*
148                          * EINVAL.  Retry with a bigger buffer.
149                          */
150                 } else {
151                         /*
152                          * The ioctl succeeded.
153                          * Some OS's just return what will fit rather
154                          * than set EINVAL if the buffer is too small
155                          * to fit all the interfaces in.  If
156                          * ifc.lifc_len is too near to the end of the
157                          * buffer we will grow it just in case and
158                          * retry.
159                          */
160                         if (iter->ifc.ifc_len + 2 * sizeof(struct ifreq)
161                             < iter->bufsize)
162                                 break;
163                 }
164                 if (iter->bufsize >= IFCONF_BUFSIZE_MAX) {
165                         UNEXPECTED_ERROR(__FILE__, __LINE__,
166                                          isc_msgcat_get(isc_msgcat,
167                                                         ISC_MSGSET_IFITERIOCTL,
168                                                         ISC_MSG_BUFFERMAX,
169                                                         "get interface "
170                                                         "configuration: "
171                                                         "maximum buffer "
172                                                         "size exceeded"));
173                         goto unexpected;
174                 }
175                 isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
176
177                 iter->bufsize *= 2;
178         }
179         return (ISC_R_SUCCESS);
180
181  unexpected:
182         isc_mem_put(iter->mctx, iter->buf, iter->bufsize);
183         iter->buf = NULL;
184         return (ISC_R_UNEXPECTED);
185 }
186
187 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
188 static isc_result_t
189 getbuf6(isc_interfaceiter_t *iter) {
190         char strbuf[ISC_STRERRORSIZE];
191         isc_result_t result;
192
193         iter->bufsize6 = IFCONF_BUFSIZE_INITIAL;
194
195         for (;;) {
196                 iter->buf6 = isc_mem_get(iter->mctx, iter->bufsize6);
197                 if (iter->buf6 == NULL)
198                         return (ISC_R_NOMEMORY);
199
200                 memset(&iter->lifc, 0, sizeof(iter->lifc));
201 #ifdef ISC_HAVE_LIFC_FAMILY
202                 iter->lifc.lifc_family = AF_INET6;
203 #endif
204 #ifdef ISC_HAVE_LIFC_FLAGS
205                 iter->lifc.lifc_flags = 0;
206 #endif
207                 iter->lifc.lifc_len = iter->bufsize6;
208                 iter->lifc.lifc_buf = iter->buf6;
209                 /*
210                  * Ignore the HP/UX warning about "integer overflow during
211                  * conversion".  It comes from its own macro definition,
212                  * and is really hard to shut up.
213                  */
214                 if (ioctl(iter->socket6, SIOCGLIFCONF, (char *)&iter->lifc)
215                     == -1) {
216 #ifdef __hpux
217                         /*
218                          * IPv6 interface scanning is not available on all
219                          * kernels w/ IPv6 sockets.
220                          */
221                         if (errno == ENOENT) {
222                                 isc__strerror(errno, strbuf, sizeof(strbuf));
223                                 UNEXPECTED_ERROR(__FILE__, __LINE__,
224                                                  isc_msgcat_get(isc_msgcat,
225                                                         ISC_MSGSET_IFITERIOCTL,
226                                                         ISC_MSG_GETIFCONFIG,
227                                                         "get interface "
228                                                         "configuration: %s"),
229                                                  strbuf);
230                                 result = ISC_R_FAILURE;
231                                 goto cleanup;
232                         }
233 #endif
234                         if (errno != EINVAL) {
235                                 isc__strerror(errno, strbuf, sizeof(strbuf));
236                                 UNEXPECTED_ERROR(__FILE__, __LINE__,
237                                                  isc_msgcat_get(isc_msgcat,
238                                                         ISC_MSGSET_IFITERIOCTL,
239                                                         ISC_MSG_GETIFCONFIG,
240                                                         "get interface "
241                                                         "configuration: %s"),
242                                                  strbuf);
243                                 result = ISC_R_UNEXPECTED;
244                                 goto cleanup;
245                         }
246                         /*
247                          * EINVAL.  Retry with a bigger buffer.
248                          */
249                 } else {
250                         /*
251                          * The ioctl succeeded.
252                          * Some OS's just return what will fit rather
253                          * than set EINVAL if the buffer is too small
254                          * to fit all the interfaces in.  If
255                          * ifc.ifc_len is too near to the end of the
256                          * buffer we will grow it just in case and
257                          * retry.
258                          */
259                         if (iter->lifc.lifc_len + 2 * sizeof(struct LIFREQ)
260                             < iter->bufsize6)
261                                 break;
262                 }
263                 if (iter->bufsize6 >= IFCONF_BUFSIZE_MAX) {
264                         UNEXPECTED_ERROR(__FILE__, __LINE__,
265                                          isc_msgcat_get(isc_msgcat,
266                                                         ISC_MSGSET_IFITERIOCTL,
267                                                         ISC_MSG_BUFFERMAX,
268                                                         "get interface "
269                                                         "configuration: "
270                                                         "maximum buffer "
271                                                         "size exceeded"));
272                         result = ISC_R_UNEXPECTED;
273                         goto cleanup;
274                 }
275                 isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
276
277                 iter->bufsize6 *= 2;
278         }
279
280         if (iter->lifc.lifc_len != 0)
281                 iter->mode = 6;
282         return (ISC_R_SUCCESS);
283
284  cleanup:
285         isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
286         iter->buf6 = NULL;
287         return (result);
288 }
289 #endif
290
291 isc_result_t
292 isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
293         isc_interfaceiter_t *iter;
294         isc_result_t result;
295         char strbuf[ISC_STRERRORSIZE];
296
297         REQUIRE(iterp != NULL);
298         REQUIRE(*iterp == NULL);
299
300         iter = isc_mem_get(mctx, sizeof(*iter));
301         if (iter == NULL)
302                 return (ISC_R_NOMEMORY);
303
304         iter->mctx = mctx;
305         iter->mode = 4;
306         iter->buf = NULL;
307         iter->pos = (unsigned int) -1;
308 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
309         iter->buf6 = NULL;
310         iter->pos6 = (unsigned int) -1;
311         iter->result6 = ISC_R_NOMORE;
312         iter->socket6 = -1;
313         iter->first6 = ISC_FALSE;
314 #endif
315
316         /*
317          * Get the interface configuration, allocating more memory if
318          * necessary.
319          */
320
321 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
322         result = isc_net_probeipv6();
323         if (result == ISC_R_SUCCESS) {
324                 /*
325                  * Create an unbound datagram socket to do the SIOCGLIFCONF
326                  * ioctl on.  HP/UX requires an AF_INET6 socket for
327                  * SIOCGLIFCONF to get IPv6 addresses.
328                  */
329                 if ((iter->socket6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
330                         isc__strerror(errno, strbuf, sizeof(strbuf));
331                         UNEXPECTED_ERROR(__FILE__, __LINE__,
332                                          isc_msgcat_get(isc_msgcat,
333                                                         ISC_MSGSET_IFITERIOCTL,
334                                                         ISC_MSG_MAKESCANSOCKET,
335                                                         "making interface "
336                                                         "scan socket: %s"),
337                                          strbuf);
338                         result = ISC_R_UNEXPECTED;
339                         goto socket6_failure;
340                 }
341                 iter->result6 = getbuf6(iter);
342                 if (iter->result6 != ISC_R_NOTIMPLEMENTED &&
343                     iter->result6 != ISC_R_SUCCESS)
344                         goto ioctl6_failure;
345         }
346 #endif
347         if ((iter->socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
348                 isc__strerror(errno, strbuf, sizeof(strbuf));
349                 UNEXPECTED_ERROR(__FILE__, __LINE__,
350                                  isc_msgcat_get(isc_msgcat,
351                                                 ISC_MSGSET_IFITERIOCTL,
352                                                 ISC_MSG_MAKESCANSOCKET,
353                                                 "making interface "
354                                                 "scan socket: %s"),
355                                  strbuf);
356                 result = ISC_R_UNEXPECTED;
357                 goto socket_failure;
358         }
359         result = getbuf4(iter);
360         if (result != ISC_R_SUCCESS)
361                 goto ioctl_failure;
362
363         /*
364          * A newly created iterator has an undefined position
365          * until isc_interfaceiter_first() is called.
366          */
367 #ifdef HAVE_TRUCLUSTER
368         iter->clua_context = -1;
369         iter->clua_done = ISC_TRUE;
370 #endif
371 #ifdef __linux
372         iter->proc = fopen("/proc/net/if_inet6", "r");
373         iter->valid = ISC_R_FAILURE;
374         iter->first = ISC_FALSE;
375 #endif
376         iter->result = ISC_R_FAILURE;
377
378         iter->magic = IFITER_MAGIC;
379         *iterp = iter;
380         return (ISC_R_SUCCESS);
381
382  ioctl_failure:
383         if (iter->buf != NULL)
384                 isc_mem_put(mctx, iter->buf, iter->bufsize);
385         (void) close(iter->socket);
386
387  socket_failure:
388 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
389         if (iter->buf6 != NULL)
390                 isc_mem_put(mctx, iter->buf6, iter->bufsize6);
391   ioctl6_failure:
392         if (iter->socket6 != -1)
393                 (void) close(iter->socket6);
394   socket6_failure:
395 #endif
396  
397         isc_mem_put(mctx, iter, sizeof(*iter));
398         return (result);
399 }
400
401 #ifdef HAVE_TRUCLUSTER
402 static void
403 get_inaddr(isc_netaddr_t *dst, struct in_addr *src) {
404         dst->family = AF_INET;
405         memcpy(&dst->type.in, src, sizeof(struct in_addr));
406 }
407
408 static isc_result_t
409 internal_current_clusteralias(isc_interfaceiter_t *iter) {
410         struct clua_info ci;
411         if (clua_getaliasinfo(&iter->clua_sa, &ci) != CLUA_SUCCESS)
412                 return (ISC_R_IGNORE);
413         memset(&iter->current, 0, sizeof(iter->current));
414         iter->current.af = iter->clua_sa.sa_family;
415         memset(iter->current.name, 0, sizeof(iter->current.name));
416         sprintf(iter->current.name, "clua%d", ci.aliasid);
417         iter->current.flags = INTERFACE_F_UP;
418         get_inaddr(&iter->current.address, &ci.addr);
419         get_inaddr(&iter->current.netmask, &ci.netmask);
420         return (ISC_R_SUCCESS);
421 }
422 #endif
423
424 #ifdef __linux
425 static isc_result_t
426 linux_if_inet6_next(isc_interfaceiter_t *iter) {
427         if (iter->proc != NULL &&
428             fgets(iter->entry, sizeof(iter->entry), iter->proc) != NULL)
429                 iter->valid = ISC_R_SUCCESS;
430         else
431                 iter->valid = ISC_R_NOMORE;
432         return (iter->valid);
433 }
434
435 static void
436 linux_if_inet6_first(isc_interfaceiter_t *iter) {
437         if (iter->proc != NULL) {
438                 rewind(iter->proc);
439                 (void)linux_if_inet6_next(iter);
440         } else
441                 iter->valid = ISC_R_NOMORE;
442         iter->first = ISC_FALSE;
443 }
444
445 static isc_result_t
446 linux_if_inet6_current(isc_interfaceiter_t *iter) {
447         char address[33];
448         char name[IF_NAMESIZE+1];
449         char strbuf[ISC_STRERRORSIZE];
450         struct in6_addr addr6;
451         struct ifreq ifreq;
452         int ifindex, prefix, scope, flags;
453         int res;
454         unsigned int i;
455
456         if (iter->valid != ISC_R_SUCCESS)
457                 return (iter->valid);
458         if (iter->proc == NULL) {
459                 UNEXPECTED_ERROR(__FILE__, __LINE__,
460                               "/proc/net/if_inet6:iter->proc == NULL");
461                 return (ISC_R_FAILURE);
462         }
463
464         /*
465          * Format for /proc/net/if_inet6:
466          * (see iface_proc_info() in net/ipv6/addrconf.c)
467          * <addr6:32> <ifindex:2> <prefix:2> <scope:2> <flags:2> <name:8>
468          */
469         res = sscanf(iter->entry, "%32[a-f0-9] %x %x %x %x %16s\n",
470                      address, &ifindex, &prefix, &scope, &flags, name);
471         if (res != 6) {
472                 UNEXPECTED_ERROR(__FILE__, __LINE__,
473                               "/proc/net/if_inet6:sscanf() -> %d (expected 6)",
474                               res);
475                 return (ISC_R_FAILURE);
476         }
477         if (strlen(address) != 32) {
478                 UNEXPECTED_ERROR(__FILE__, __LINE__,
479                               "/proc/net/if_inet6:strlen(%s) != 32", address);
480                 return (ISC_R_FAILURE);
481         }
482         for (i = 0; i < 16; i++) {
483                 unsigned char byte;
484                 static const char hex[] = "0123456789abcdef";
485                 byte = ((index(hex, address[i * 2]) - hex) << 4) |
486                        (index(hex, address[i * 2 + 1]) - hex);
487                 addr6.s6_addr[i] = byte;
488         }
489         iter->current.af = AF_INET6;
490         /* iter->current.ifindex = ifindex; */
491         iter->current.flags = 0;
492
493         memset(&ifreq, 0, sizeof(ifreq));
494         INSIST(sizeof(ifreq.ifr_name) <= sizeof(iter->current.name));
495         strncpy(ifreq.ifr_name, name, sizeof(ifreq.ifr_name));
496
497         if (ioctl(iter->socket, SIOCGIFFLAGS, (char *) &ifreq) < 0) {
498                 isc__strerror(errno, strbuf, sizeof(strbuf));
499                 UNEXPECTED_ERROR(__FILE__, __LINE__,
500                                  "%s: getting interface flags: %s",
501                                  ifreq.ifr_name, strbuf);
502                 return (ISC_R_IGNORE);
503         }
504
505         if ((ifreq.ifr_flags & IFF_UP) != 0)
506                 iter->current.flags |= INTERFACE_F_UP;
507 #ifdef IFF_POINTOPOINT
508         if ((ifreq.ifr_flags & IFF_POINTOPOINT) != 0) 
509                 iter->current.flags |= INTERFACE_F_POINTTOPOINT;
510 #endif
511         if ((ifreq.ifr_flags & IFF_LOOPBACK) != 0)
512                 iter->current.flags |= INTERFACE_F_LOOPBACK;
513         if ((ifreq.ifr_flags & IFF_BROADCAST) != 0)
514                 iter->current.flags |= INTERFACE_F_BROADCAST;
515 #ifdef IFF_MULTICAST
516         if ((ifreq.ifr_flags & IFF_MULTICAST) != 0)
517                 iter->current.flags |= INTERFACE_F_MULTICAST;
518 #endif
519
520         /*
521          * enable_multicast_if() requires scopeid for setsockopt,
522          * so associate address with their corresponding ifindex.
523          */
524         isc_netaddr_fromin6(&iter->current.address, &addr6);
525         isc_netaddr_setzone(&iter->current.address, (isc_uint32_t)ifindex);
526
527         for (i = 0; i < 16; i++) {
528                 if (prefix > 8) {
529                         addr6.s6_addr[i] = 0xff;
530                         prefix -= 8;
531                 } else {
532                         addr6.s6_addr[i] = (0xff << (8 - prefix)) & 0xff;
533                         prefix = 0;
534                 }
535         }
536         isc_netaddr_fromin6(&iter->current.netmask, &addr6);
537         strncpy(iter->current.name, name, sizeof(iter->current.name));
538         return (ISC_R_SUCCESS);
539 }
540 #endif
541
542 /*
543  * Get information about the current interface to iter->current.
544  * If successful, return ISC_R_SUCCESS.
545  * If the interface has an unsupported address family, or if
546  * some operation on it fails, return ISC_R_IGNORE to make
547  * the higher-level iterator code ignore it.
548  */
549
550 static isc_result_t
551 internal_current4(isc_interfaceiter_t *iter) {
552         struct ifreq *ifrp;
553         struct ifreq ifreq;
554         int family;
555         char strbuf[ISC_STRERRORSIZE];
556 #if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
557         struct lifreq lifreq;
558 #else
559         char sabuf[256];
560 #endif
561         int i, bits, prefixlen;
562 #ifdef __linux
563         isc_result_t result;
564 #endif
565
566         REQUIRE(VALID_IFITER(iter));
567         REQUIRE (iter->pos < (unsigned int) iter->ifc.ifc_len);
568
569 #ifdef __linux
570         result = linux_if_inet6_current(iter);
571         if (result != ISC_R_NOMORE)
572                 return (result);
573         iter->first = ISC_TRUE;
574 #endif
575
576         ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos);
577
578         memset(&ifreq, 0, sizeof(ifreq));
579         memcpy(&ifreq, ifrp, sizeof(ifreq));
580
581         family = ifreq.ifr_addr.sa_family;
582 #if defined(ISC_PLATFORM_HAVEIPV6)
583         if (family != AF_INET && family != AF_INET6)
584 #else
585         if (family != AF_INET)
586 #endif
587                 return (ISC_R_IGNORE);
588
589         memset(&iter->current, 0, sizeof(iter->current));
590         iter->current.af = family;
591
592         INSIST(sizeof(ifreq.ifr_name) <= sizeof(iter->current.name));
593         memset(iter->current.name, 0, sizeof(iter->current.name));
594         memcpy(iter->current.name, ifreq.ifr_name, sizeof(ifreq.ifr_name));
595
596         get_addr(family, &iter->current.address,
597                  (struct sockaddr *)&ifrp->ifr_addr, ifreq.ifr_name);
598
599         /*
600          * If the interface does not have a address ignore it.
601          */
602         switch (family) {
603         case AF_INET:
604                 if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
605                         return (ISC_R_IGNORE);
606                 break;
607 #ifdef ISC_PLATFORM_HAVEIPV6
608         case AF_INET6:
609                 if (memcmp(&iter->current.address.type.in6, &in6addr_any,
610                            sizeof(in6addr_any)) == 0)
611                         return (ISC_R_IGNORE);
612                 break;
613 #endif
614         }
615
616         /*
617          * Get interface flags.
618          */
619
620         iter->current.flags = 0;
621
622         /*
623          * Ignore the HP/UX warning about "integer overflow during
624          * conversion.  It comes from its own macro definition,
625          * and is really hard to shut up.
626          */
627         if (ioctl(iter->socket, SIOCGIFFLAGS, (char *) &ifreq) < 0) {
628                 isc__strerror(errno, strbuf, sizeof(strbuf));
629                 UNEXPECTED_ERROR(__FILE__, __LINE__,
630                                  "%s: getting interface flags: %s",
631                                  ifreq.ifr_name, strbuf);
632                 return (ISC_R_IGNORE);
633         }
634
635         if ((ifreq.ifr_flags & IFF_UP) != 0)
636                 iter->current.flags |= INTERFACE_F_UP;
637
638 #ifdef IFF_POINTOPOINT
639         if ((ifreq.ifr_flags & IFF_POINTOPOINT) != 0)
640                 iter->current.flags |= INTERFACE_F_POINTTOPOINT;
641 #endif
642
643         if ((ifreq.ifr_flags & IFF_LOOPBACK) != 0)
644                 iter->current.flags |= INTERFACE_F_LOOPBACK;
645
646         if ((ifreq.ifr_flags & IFF_BROADCAST) != 0) {
647                 iter->current.flags |= INTERFACE_F_BROADCAST;
648         }
649
650 #ifdef IFF_MULTICAST
651         if ((ifreq.ifr_flags & IFF_MULTICAST) != 0) {
652                 iter->current.flags |= INTERFACE_F_MULTICAST;
653         }
654 #endif
655
656         if (family == AF_INET)
657                 goto inet;
658
659 #if !defined(ISC_PLATFORM_HAVEIF_LADDRREQ) && defined(SIOCGLIFADDR)
660         memset(&lifreq, 0, sizeof(lifreq));
661         memcpy(lifreq.lifr_name, iter->current.name, sizeof(lifreq.lifr_name));
662         memcpy(&lifreq.lifr_addr, &iter->current.address.type.in6,
663                sizeof(iter->current.address.type.in6));
664
665         if (ioctl(iter->socket, SIOCGLIFADDR, &lifreq) < 0) {
666                 isc__strerror(errno, strbuf, sizeof(strbuf));
667                 UNEXPECTED_ERROR(__FILE__, __LINE__,
668                                  "%s: getting interface address: %s",
669                                  ifreq.ifr_name, strbuf);
670                 return (ISC_R_IGNORE);
671         }
672         prefixlen = lifreq.lifr_addrlen;
673 #else
674         isc_netaddr_format(&iter->current.address, sabuf, sizeof(sabuf));
675         UNEXPECTED_ERROR(__FILE__, __LINE__,
676                       isc_msgcat_get(isc_msgcat,
677                                      ISC_MSGSET_IFITERIOCTL,
678                                      ISC_MSG_GETIFCONFIG,
679                                      "prefix length for %s is unknown "
680                                      "(assume 128)"), sabuf);
681         prefixlen = 128;
682 #endif
683
684         /*
685          * Netmask already zeroed.
686          */
687         iter->current.netmask.family = family;
688         for (i = 0; i < 16; i++) {
689                 if (prefixlen > 8) {
690                         bits = 0;
691                         prefixlen -= 8;
692                 } else {
693                         bits = 8 - prefixlen;
694                         prefixlen = 0;
695                 }
696                 iter->current.netmask.type.in6.s6_addr[i] = (~0 << bits) & 0xff;
697         }
698         return (ISC_R_SUCCESS);
699
700  inet:
701         if (family != AF_INET)
702                 return (ISC_R_IGNORE);
703 #ifdef IFF_POINTOPOINT
704         /*
705          * If the interface is point-to-point, get the destination address.
706          */
707         if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
708                 /*
709                  * Ignore the HP/UX warning about "integer overflow during
710                  * conversion.  It comes from its own macro definition,
711                  * and is really hard to shut up.
712                  */
713                 if (ioctl(iter->socket, SIOCGIFDSTADDR, (char *)&ifreq)
714                     < 0) {
715                         isc__strerror(errno, strbuf, sizeof(strbuf));
716                         UNEXPECTED_ERROR(__FILE__, __LINE__,
717                                 isc_msgcat_get(isc_msgcat,
718                                                ISC_MSGSET_IFITERIOCTL,
719                                                ISC_MSG_GETDESTADDR,
720                                                "%s: getting "
721                                                "destination address: %s"),
722                                          ifreq.ifr_name, strbuf);
723                         return (ISC_R_IGNORE);
724                 }
725                 get_addr(family, &iter->current.dstaddress,
726                          (struct sockaddr *)&ifreq.ifr_dstaddr, ifreq.ifr_name);
727         }
728 #endif
729         if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0) {
730                 /*
731                  * Ignore the HP/UX warning about "integer overflow during
732                  * conversion.  It comes from its own macro definition,
733                  * and is really hard to shut up.
734                  */
735                 if (ioctl(iter->socket, SIOCGIFBRDADDR, (char *)&ifreq)
736                     < 0) {
737                         isc__strerror(errno, strbuf, sizeof(strbuf));
738                         UNEXPECTED_ERROR(__FILE__, __LINE__,
739                                 isc_msgcat_get(isc_msgcat,
740                                                ISC_MSGSET_IFITERIOCTL,
741                                                ISC_MSG_GETDESTADDR,
742                                                "%s: getting "
743                                                "broadcast address: %s"),
744                                          ifreq.ifr_name, strbuf);
745                         return (ISC_R_IGNORE);
746                 }
747                 get_addr(family, &iter->current.broadcast,
748                          (struct sockaddr *)&ifreq.ifr_broadaddr, ifreq.ifr_name);
749         }
750
751         /*
752          * Get the network mask.
753          */
754         memset(&ifreq, 0, sizeof(ifreq));
755         memcpy(&ifreq, ifrp, sizeof(ifreq));
756         /*
757          * Ignore the HP/UX warning about "integer overflow during
758          * conversion.  It comes from its own macro definition,
759          * and is really hard to shut up.
760          */
761         if (ioctl(iter->socket, SIOCGIFNETMASK, (char *)&ifreq) < 0) {
762                 isc__strerror(errno, strbuf, sizeof(strbuf));
763                 UNEXPECTED_ERROR(__FILE__, __LINE__,
764                         isc_msgcat_get(isc_msgcat,
765                                        ISC_MSGSET_IFITERIOCTL,
766                                        ISC_MSG_GETNETMASK,
767                                        "%s: getting netmask: %s"),
768                                        ifreq.ifr_name, strbuf);
769                 return (ISC_R_IGNORE);
770         }
771         get_addr(family, &iter->current.netmask,
772                  (struct sockaddr *)&ifreq.ifr_addr, ifreq.ifr_name);
773         return (ISC_R_SUCCESS);
774 }
775
776 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
777 static isc_result_t
778 internal_current6(isc_interfaceiter_t *iter) {
779         struct LIFREQ *ifrp;
780         struct LIFREQ lifreq;
781         int family;
782         char strbuf[ISC_STRERRORSIZE];
783         int fd;
784
785         REQUIRE(VALID_IFITER(iter));
786         if (iter->result6 != ISC_R_SUCCESS)
787                 return (iter->result6);
788         REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len);
789
790         ifrp = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos6);
791
792         memset(&lifreq, 0, sizeof(lifreq));
793         memcpy(&lifreq, ifrp, sizeof(lifreq));
794
795         family = lifreq.lifr_addr.ss_family;
796 #ifdef ISC_PLATFORM_HAVEIPV6
797         if (family != AF_INET && family != AF_INET6)
798 #else
799         if (family != AF_INET)
800 #endif
801                 return (ISC_R_IGNORE);
802
803         memset(&iter->current, 0, sizeof(iter->current));
804         iter->current.af = family;
805
806         INSIST(sizeof(lifreq.lifr_name) <= sizeof(iter->current.name));
807         memset(iter->current.name, 0, sizeof(iter->current.name));
808         memcpy(iter->current.name, lifreq.lifr_name, sizeof(lifreq.lifr_name));
809
810         get_addr(family, &iter->current.address,
811                  (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name);
812
813         /*
814          * If the interface does not have a address ignore it.
815          */
816         switch (family) {
817         case AF_INET:
818                 if (iter->current.address.type.in.s_addr == htonl(INADDR_ANY))
819                         return (ISC_R_IGNORE);
820                 break;
821 #ifdef ISC_PLATFORM_HAVEIPV6
822         case AF_INET6:
823                 if (memcmp(&iter->current.address.type.in6, &in6addr_any,
824                            sizeof(in6addr_any)) == 0)
825                         return (ISC_R_IGNORE);
826                 break;
827 #endif
828         }
829
830         /*
831          * Get interface flags.
832          */
833
834         iter->current.flags = 0;
835
836         if (family == AF_INET6)
837                 fd = iter->socket6;
838         else
839                 fd = iter->socket;
840
841         /*
842          * Ignore the HP/UX warning about "integer overflow during
843          * conversion.  It comes from its own macro definition,
844          * and is really hard to shut up.
845          */
846         if (ioctl(fd, SIOCGLIFFLAGS, (char *) &lifreq) < 0) {
847                 isc__strerror(errno, strbuf, sizeof(strbuf));
848                 UNEXPECTED_ERROR(__FILE__, __LINE__,
849                                  "%s: getting interface flags: %s",
850                                  lifreq.lifr_name, strbuf);
851                 return (ISC_R_IGNORE);
852         }
853
854         if ((lifreq.lifr_flags & IFF_UP) != 0)
855                 iter->current.flags |= INTERFACE_F_UP;
856
857 #ifdef IFF_POINTOPOINT
858         if ((lifreq.lifr_flags & IFF_POINTOPOINT) != 0)
859                 iter->current.flags |= INTERFACE_F_POINTTOPOINT;
860 #endif
861
862         if ((lifreq.lifr_flags & IFF_LOOPBACK) != 0)
863                 iter->current.flags |= INTERFACE_F_LOOPBACK;
864
865         if ((lifreq.lifr_flags & IFF_BROADCAST) != 0) {
866                 iter->current.flags |= INTERFACE_F_BROADCAST;
867         }
868
869 #ifdef IFF_MULTICAST
870         if ((lifreq.lifr_flags & IFF_MULTICAST) != 0) {
871                 iter->current.flags |= INTERFACE_F_MULTICAST;
872         }
873 #endif
874
875 #ifdef IFF_POINTOPOINT
876         /*
877          * If the interface is point-to-point, get the destination address.
878          */
879         if ((iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0) {
880                 /*
881                  * Ignore the HP/UX warning about "interger overflow during
882                  * conversion.  It comes from its own macro definition,
883                  * and is really hard to shut up.
884                  */
885                 if (ioctl(fd, SIOCGLIFDSTADDR, (char *)&lifreq)
886                     < 0) {
887                         isc__strerror(errno, strbuf, sizeof(strbuf));
888                         UNEXPECTED_ERROR(__FILE__, __LINE__,
889                                 isc_msgcat_get(isc_msgcat,
890                                                ISC_MSGSET_IFITERIOCTL,
891                                                ISC_MSG_GETDESTADDR,
892                                                "%s: getting "
893                                                "destination address: %s"),
894                                          lifreq.lifr_name, strbuf);
895                         return (ISC_R_IGNORE);
896                 }
897                 get_addr(family, &iter->current.dstaddress,
898                          (struct sockaddr *)&lifreq.lifr_dstaddr,
899                          lifreq.lifr_name);
900         }
901 #endif
902
903 #ifdef SIOCGLIFBRDADDR
904         if ((iter->current.flags & INTERFACE_F_BROADCAST) != 0) {
905                 /*
906                  * Ignore the HP/UX warning about "integer overflow during
907                  * conversion.  It comes from its own macro definition,
908                  * and is really hard to shut up.
909                  */
910                 if (ioctl(iter->socket, SIOCGLIFBRDADDR, (char *)&lifreq)
911                     < 0) {
912                         isc__strerror(errno, strbuf, sizeof(strbuf));
913                         UNEXPECTED_ERROR(__FILE__, __LINE__,
914                                 isc_msgcat_get(isc_msgcat,
915                                                ISC_MSGSET_IFITERIOCTL,
916                                                ISC_MSG_GETDESTADDR,
917                                                "%s: getting "
918                                                "broadcast address: %s"),
919                                          lifreq.lifr_name, strbuf);
920                         return (ISC_R_IGNORE);
921                 }
922                 get_addr(family, &iter->current.broadcast,
923                          (struct sockaddr *)&lifreq.lifr_broadaddr,
924                          lifreq.lifr_name);
925         }
926 #endif  /* SIOCGLIFBRDADDR */
927
928         /*
929          * Get the network mask.  Netmask already zeroed.
930          */
931         memset(&lifreq, 0, sizeof(lifreq));
932         memcpy(&lifreq, ifrp, sizeof(lifreq));
933
934 #ifdef lifr_addrlen
935         /*
936          * Special case: if the system provides lifr_addrlen member, the
937          * netmask of an IPv6 address can be derived from the length, since
938          * an IPv6 address always has a contiguous mask.
939          */
940         if (family == AF_INET6) {
941                 int i, bits;
942
943                 iter->current.netmask.family = family;
944                 for (i = 0; i < lifreq.lifr_addrlen; i += 8) {
945                         bits = lifreq.lifr_addrlen - i;
946                         bits = (bits < 8) ? (8 - bits) : 0;
947                         iter->current.netmask.type.in6.s6_addr[i / 8] =
948                                 (~0 << bits) & 0xff;
949                 }
950
951                 return (ISC_R_SUCCESS);
952         }
953 #endif
954
955         /*
956          * Ignore the HP/UX warning about "integer overflow during
957          * conversion.  It comes from its own macro definition,
958          * and is really hard to shut up.
959          */
960         if (ioctl(fd, SIOCGLIFNETMASK, (char *)&lifreq) < 0) {
961                 isc__strerror(errno, strbuf, sizeof(strbuf));
962                 UNEXPECTED_ERROR(__FILE__, __LINE__,
963                                  isc_msgcat_get(isc_msgcat,
964                                                 ISC_MSGSET_IFITERIOCTL,
965                                                 ISC_MSG_GETNETMASK,
966                                                 "%s: getting netmask: %s"),
967                                  lifreq.lifr_name, strbuf);
968                 return (ISC_R_IGNORE);
969         }
970         get_addr(family, &iter->current.netmask,
971                  (struct sockaddr *)&lifreq.lifr_addr, lifreq.lifr_name);
972
973         return (ISC_R_SUCCESS);
974 }
975 #endif
976
977 static isc_result_t
978 internal_current(isc_interfaceiter_t *iter) {
979 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
980         if (iter->mode == 6) {
981                 iter->result6 = internal_current6(iter);
982                 if (iter->result6 != ISC_R_NOMORE)
983                         return (iter->result6);
984         }
985 #endif
986 #ifdef HAVE_TRUCLUSTER
987         if (!iter->clua_done)
988                 return(internal_current_clusteralias(iter));
989 #endif
990         return (internal_current4(iter));
991 }
992
993 /*
994  * Step the iterator to the next interface.  Unlike
995  * isc_interfaceiter_next(), this may leave the iterator
996  * positioned on an interface that will ultimately
997  * be ignored.  Return ISC_R_NOMORE if there are no more
998  * interfaces, otherwise ISC_R_SUCCESS.
999  */
1000 static isc_result_t
1001 internal_next4(isc_interfaceiter_t *iter) {
1002         struct ifreq *ifrp;
1003
1004         REQUIRE (iter->pos < (unsigned int) iter->ifc.ifc_len);
1005
1006 #ifdef __linux
1007         if (linux_if_inet6_next(iter) == ISC_R_SUCCESS)
1008                 return (ISC_R_SUCCESS);
1009         if (!iter->first)
1010                 return (ISC_R_SUCCESS);
1011 #endif
1012         ifrp = (struct ifreq *)((char *) iter->ifc.ifc_req + iter->pos);
1013
1014 #ifdef ISC_PLATFORM_HAVESALEN
1015         if (ifrp->ifr_addr.sa_len > sizeof(struct sockaddr))
1016                 iter->pos += sizeof(ifrp->ifr_name) + ifrp->ifr_addr.sa_len;
1017         else
1018 #endif
1019                 iter->pos += sizeof(*ifrp);
1020
1021         if (iter->pos >= (unsigned int) iter->ifc.ifc_len)
1022                 return (ISC_R_NOMORE);
1023
1024         return (ISC_R_SUCCESS);
1025 }
1026
1027 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
1028 static isc_result_t
1029 internal_next6(isc_interfaceiter_t *iter) {
1030         struct LIFREQ *ifrp;
1031         
1032         if (iter->result6 != ISC_R_SUCCESS && iter->result6 != ISC_R_IGNORE)
1033                 return (iter->result6);
1034
1035         REQUIRE(iter->pos6 < (unsigned int) iter->lifc.lifc_len);
1036
1037         ifrp = (struct LIFREQ *)((char *) iter->lifc.lifc_req + iter->pos6);
1038
1039 #ifdef ISC_PLATFORM_HAVESALEN
1040         if (ifrp->lifr_addr.sa_len > sizeof(struct sockaddr))
1041                 iter->pos6 += sizeof(ifrp->lifr_name) + ifrp->lifr_addr.sa_len;
1042         else
1043 #endif
1044                 iter->pos6 += sizeof(*ifrp);
1045
1046         if (iter->pos6 >= (unsigned int) iter->lifc.lifc_len)
1047                 return (ISC_R_NOMORE);
1048
1049         return (ISC_R_SUCCESS);
1050 }
1051 #endif
1052
1053 static isc_result_t
1054 internal_next(isc_interfaceiter_t *iter) {
1055 #ifdef HAVE_TRUCLUSTER
1056         int clua_result;
1057 #endif
1058 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
1059         if (iter->mode == 6) {
1060                 iter->result6 = internal_next6(iter);
1061                 if (iter->result6 != ISC_R_NOMORE)
1062                         return (iter->result6);
1063                 if (iter->first6) {
1064                         iter->first6 = ISC_FALSE;
1065                         return (ISC_R_SUCCESS);
1066                 }
1067         }
1068 #endif
1069 #ifdef HAVE_TRUCLUSTER
1070         if (!iter->clua_done) {
1071                 clua_result = clua_getaliasaddress(&iter->clua_sa,
1072                                                    &iter->clua_context);
1073                 if (clua_result != CLUA_SUCCESS)
1074                         iter->clua_done = ISC_TRUE;
1075                 return (ISC_R_SUCCESS);
1076         }
1077 #endif
1078         return (internal_next4(iter));
1079 }
1080
1081 static void
1082 internal_destroy(isc_interfaceiter_t *iter) {
1083         (void) close(iter->socket);
1084 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
1085         if (iter->socket6 != -1)
1086                 (void) close(iter->socket6);
1087         if (iter->buf6 != NULL) {
1088                 isc_mem_put(iter->mctx, iter->buf6, iter->bufsize6);
1089         }
1090 #endif
1091 #ifdef __linux
1092         if (iter->proc != NULL)
1093                 fclose(iter->proc);
1094 #endif
1095 }
1096
1097 static
1098 void internal_first(isc_interfaceiter_t *iter) {
1099 #ifdef HAVE_TRUCLUSTER
1100         int clua_result;
1101 #endif
1102         iter->pos = 0;
1103 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFADDR)
1104         iter->pos6 = 0;
1105         if (iter->result6 == ISC_R_NOMORE)
1106                 iter->result6 = ISC_R_SUCCESS;
1107         iter->first6 = ISC_TRUE;
1108 #endif
1109 #ifdef HAVE_TRUCLUSTER
1110         iter->clua_context = 0;
1111         clua_result = clua_getaliasaddress(&iter->clua_sa,
1112                                            &iter->clua_context);
1113         iter->clua_done = ISC_TF(clua_result != CLUA_SUCCESS);
1114 #endif
1115 #ifdef __linux
1116         linux_if_inet6_first(iter);
1117 #endif
1118 }