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