4 * Copyright (C) 2004, 2005, 2007, 2008 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: ifiter_getifaddrs.c,v 1.11 2008/03/20 23:47:00 tbox Exp */
24 * Obtain the list of network interfaces using the getifaddrs(3) library.
30 #define IFITER_MAGIC ISC_MAGIC('I', 'F', 'I', 'G')
32 #define VALID_IFITER(t) ISC_MAGIC_VALID(t, IFITER_MAGIC)
35 static isc_boolean_t seenv6
= ISC_FALSE
;
38 /*% Iterator structure */
39 struct isc_interfaceiter
{
40 unsigned int magic
; /*%< Magic number. */
42 void *buf
; /*%< (unused) */
43 unsigned int bufsize
; /*%< (always 0) */
44 struct ifaddrs
*ifaddrs
; /*%< List of ifaddrs */
45 struct ifaddrs
*pos
; /*%< Ptr to current ifaddr */
46 isc_interface_t current
; /*%< Current interface data. */
47 isc_result_t result
; /*%< Last result code. */
50 char entry
[ISC_IF_INET6_SZ
];
56 isc_interfaceiter_create(isc_mem_t
*mctx
, isc_interfaceiter_t
**iterp
) {
57 isc_interfaceiter_t
*iter
;
59 char strbuf
[ISC_STRERRORSIZE
];
61 REQUIRE(mctx
!= NULL
);
62 REQUIRE(iterp
!= NULL
);
63 REQUIRE(*iterp
== NULL
);
65 iter
= isc_mem_get(mctx
, sizeof(*iter
));
67 return (ISC_R_NOMEMORY
);
75 * Only open "/proc/net/if_inet6" if we have never seen a IPv6
76 * address returned by getifaddrs().
79 iter
->proc
= fopen("/proc/net/if_inet6", "r");
82 iter
->valid
= ISC_R_FAILURE
;
85 if (getifaddrs(&iter
->ifaddrs
) < 0) {
86 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
87 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
88 isc_msgcat_get(isc_msgcat
,
89 ISC_MSGSET_IFITERGETIFADDRS
,
92 "addresses: getifaddrs: %s"),
94 result
= ISC_R_UNEXPECTED
;
99 * A newly created iterator has an undefined position
100 * until isc_interfaceiter_first() is called.
103 iter
->result
= ISC_R_FAILURE
;
105 iter
->magic
= IFITER_MAGIC
;
107 return (ISC_R_SUCCESS
);
111 if (iter
->proc
!= NULL
)
114 if (iter
->ifaddrs
!= NULL
) /* just in case */
115 freeifaddrs(iter
->ifaddrs
);
116 isc_mem_put(mctx
, iter
, sizeof(*iter
));
121 * Get information about the current interface to iter->current.
122 * If successful, return ISC_R_SUCCESS.
123 * If the interface has an unsupported address family,
124 * return ISC_R_IGNORE.
128 internal_current(isc_interfaceiter_t
*iter
) {
131 unsigned int namelen
;
133 REQUIRE(VALID_IFITER(iter
));
138 if (iter
->pos
== NULL
)
139 return (linux_if_inet6_current(iter
));
143 INSIST(ifa
->ifa_name
!= NULL
);
145 if (ifa
->ifa_addr
== NULL
)
146 return (ISC_R_IGNORE
);
148 family
= ifa
->ifa_addr
->sa_family
;
149 if (family
!= AF_INET
&& family
!= AF_INET6
)
150 return (ISC_R_IGNORE
);
153 if (family
== AF_INET6
)
157 memset(&iter
->current
, 0, sizeof(iter
->current
));
159 namelen
= strlen(ifa
->ifa_name
);
160 if (namelen
> sizeof(iter
->current
.name
) - 1)
161 namelen
= sizeof(iter
->current
.name
) - 1;
163 memset(iter
->current
.name
, 0, sizeof(iter
->current
.name
));
164 memcpy(iter
->current
.name
, ifa
->ifa_name
, namelen
);
166 iter
->current
.flags
= 0;
168 if ((ifa
->ifa_flags
& IFF_UP
) != 0)
169 iter
->current
.flags
|= INTERFACE_F_UP
;
171 if ((ifa
->ifa_flags
& IFF_POINTOPOINT
) != 0)
172 iter
->current
.flags
|= INTERFACE_F_POINTTOPOINT
;
174 if ((ifa
->ifa_flags
& IFF_LOOPBACK
) != 0)
175 iter
->current
.flags
|= INTERFACE_F_LOOPBACK
;
177 if ((ifa
->ifa_flags
& IFF_BROADCAST
) != 0)
178 iter
->current
.flags
|= INTERFACE_F_BROADCAST
;
181 if ((ifa
->ifa_flags
& IFF_MULTICAST
) != 0)
182 iter
->current
.flags
|= INTERFACE_F_MULTICAST
;
185 iter
->current
.af
= family
;
187 get_addr(family
, &iter
->current
.address
, ifa
->ifa_addr
, ifa
->ifa_name
);
189 if (ifa
->ifa_netmask
!= NULL
)
190 get_addr(family
, &iter
->current
.netmask
, ifa
->ifa_netmask
,
193 if (ifa
->ifa_dstaddr
!= NULL
&&
194 (iter
->current
.flags
& INTERFACE_F_POINTTOPOINT
) != 0)
195 get_addr(family
, &iter
->current
.dstaddress
, ifa
->ifa_dstaddr
,
198 if (ifa
->ifa_broadaddr
!= NULL
&&
199 (iter
->current
.flags
& INTERFACE_F_BROADCAST
) != 0)
200 get_addr(family
, &iter
->current
.broadcast
, ifa
->ifa_broadaddr
,
203 return (ISC_R_SUCCESS
);
207 * Step the iterator to the next interface. Unlike
208 * isc_interfaceiter_next(), this may leave the iterator
209 * positioned on an interface that will ultimately
210 * be ignored. Return ISC_R_NOMORE if there are no more
211 * interfaces, otherwise ISC_R_SUCCESS.
214 internal_next(isc_interfaceiter_t
*iter
) {
216 if (iter
->pos
!= NULL
)
217 iter
->pos
= iter
->pos
->ifa_next
;
218 if (iter
->pos
== NULL
) {
221 return (linux_if_inet6_next(iter
));
223 return (ISC_R_NOMORE
);
226 return (ISC_R_SUCCESS
);
230 internal_destroy(isc_interfaceiter_t
*iter
) {
233 if (iter
->proc
!= NULL
)
238 freeifaddrs(iter
->ifaddrs
);
239 iter
->ifaddrs
= NULL
;
243 void internal_first(isc_interfaceiter_t
*iter
) {
246 linux_if_inet6_first(iter
);
248 iter
->pos
= iter
->ifaddrs
;