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