1*00b67f09SDavid van Moolenbroek /* $NetBSD: ifiter_sysctl.c,v 1.5 2014/12/10 04:38:01 christos Exp $ */
2*00b67f09SDavid van Moolenbroek
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek * Copyright (C) 2004, 2005, 2007, 2014 Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek * Copyright (C) 1999-2003 Internet Software Consortium.
6*00b67f09SDavid van Moolenbroek *
7*00b67f09SDavid van Moolenbroek * Permission to use, copy, modify, and/or distribute this software for any
8*00b67f09SDavid van Moolenbroek * purpose with or without fee is hereby granted, provided that the above
9*00b67f09SDavid van Moolenbroek * copyright notice and this permission notice appear in all copies.
10*00b67f09SDavid van Moolenbroek *
11*00b67f09SDavid van Moolenbroek * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12*00b67f09SDavid van Moolenbroek * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13*00b67f09SDavid van Moolenbroek * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14*00b67f09SDavid van Moolenbroek * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15*00b67f09SDavid van Moolenbroek * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16*00b67f09SDavid van Moolenbroek * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*00b67f09SDavid van Moolenbroek * PERFORMANCE OF THIS SOFTWARE.
18*00b67f09SDavid van Moolenbroek */
19*00b67f09SDavid van Moolenbroek
20*00b67f09SDavid van Moolenbroek /* Id: ifiter_sysctl.c,v 1.25 2007/06/19 23:47:18 tbox Exp */
21*00b67f09SDavid van Moolenbroek
22*00b67f09SDavid van Moolenbroek /*! \file
23*00b67f09SDavid van Moolenbroek * \brief
24*00b67f09SDavid van Moolenbroek * Obtain the list of network interfaces using sysctl.
25*00b67f09SDavid van Moolenbroek * See TCP/IP Illustrated Volume 2, sections 19.8, 19.14,
26*00b67f09SDavid van Moolenbroek * and 19.16.
27*00b67f09SDavid van Moolenbroek */
28*00b67f09SDavid van Moolenbroek
29*00b67f09SDavid van Moolenbroek #include <sys/param.h>
30*00b67f09SDavid van Moolenbroek #include <sys/sysctl.h>
31*00b67f09SDavid van Moolenbroek
32*00b67f09SDavid van Moolenbroek #include <net/route.h>
33*00b67f09SDavid van Moolenbroek #include <net/if_dl.h>
34*00b67f09SDavid van Moolenbroek
35*00b67f09SDavid van Moolenbroek /* XXX what about Alpha? */
36*00b67f09SDavid van Moolenbroek #ifdef sgi
37*00b67f09SDavid van Moolenbroek #define ROUNDUP(a) ((a) > 0 ? \
38*00b67f09SDavid van Moolenbroek (1 + (((a) - 1) | (sizeof(__uint64_t) - 1))) : \
39*00b67f09SDavid van Moolenbroek sizeof(__uint64_t))
40*00b67f09SDavid van Moolenbroek #else
41*00b67f09SDavid van Moolenbroek #define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) \
42*00b67f09SDavid van Moolenbroek : sizeof(long))
43*00b67f09SDavid van Moolenbroek #endif
44*00b67f09SDavid van Moolenbroek
45*00b67f09SDavid van Moolenbroek #define IFITER_MAGIC ISC_MAGIC('I', 'F', 'I', 'S')
46*00b67f09SDavid van Moolenbroek #define VALID_IFITER(t) ISC_MAGIC_VALID(t, IFITER_MAGIC)
47*00b67f09SDavid van Moolenbroek
48*00b67f09SDavid van Moolenbroek struct isc_interfaceiter {
49*00b67f09SDavid van Moolenbroek unsigned int magic; /* Magic number. */
50*00b67f09SDavid van Moolenbroek isc_mem_t *mctx;
51*00b67f09SDavid van Moolenbroek void *buf; /* Buffer for sysctl data. */
52*00b67f09SDavid van Moolenbroek unsigned int bufsize; /* Bytes allocated. */
53*00b67f09SDavid van Moolenbroek unsigned int bufused; /* Bytes used. */
54*00b67f09SDavid van Moolenbroek unsigned int pos; /* Current offset in
55*00b67f09SDavid van Moolenbroek sysctl data. */
56*00b67f09SDavid van Moolenbroek isc_interface_t current; /* Current interface data. */
57*00b67f09SDavid van Moolenbroek isc_result_t result; /* Last result code. */
58*00b67f09SDavid van Moolenbroek };
59*00b67f09SDavid van Moolenbroek
60*00b67f09SDavid van Moolenbroek static int mib[6] = {
61*00b67f09SDavid van Moolenbroek CTL_NET,
62*00b67f09SDavid van Moolenbroek PF_ROUTE,
63*00b67f09SDavid van Moolenbroek 0,
64*00b67f09SDavid van Moolenbroek 0, /* Any address family. */
65*00b67f09SDavid van Moolenbroek NET_RT_IFLIST,
66*00b67f09SDavid van Moolenbroek 0 /* Flags. */
67*00b67f09SDavid van Moolenbroek };
68*00b67f09SDavid van Moolenbroek
69*00b67f09SDavid van Moolenbroek isc_result_t
isc_interfaceiter_create(isc_mem_t * mctx,isc_interfaceiter_t ** iterp)70*00b67f09SDavid van Moolenbroek isc_interfaceiter_create(isc_mem_t *mctx, isc_interfaceiter_t **iterp) {
71*00b67f09SDavid van Moolenbroek isc_interfaceiter_t *iter;
72*00b67f09SDavid van Moolenbroek isc_result_t result;
73*00b67f09SDavid van Moolenbroek size_t bufsize;
74*00b67f09SDavid van Moolenbroek size_t bufused;
75*00b67f09SDavid van Moolenbroek char strbuf[ISC_STRERRORSIZE];
76*00b67f09SDavid van Moolenbroek
77*00b67f09SDavid van Moolenbroek REQUIRE(mctx != NULL);
78*00b67f09SDavid van Moolenbroek REQUIRE(iterp != NULL);
79*00b67f09SDavid van Moolenbroek REQUIRE(*iterp == NULL);
80*00b67f09SDavid van Moolenbroek
81*00b67f09SDavid van Moolenbroek iter = isc_mem_get(mctx, sizeof(*iter));
82*00b67f09SDavid van Moolenbroek if (iter == NULL)
83*00b67f09SDavid van Moolenbroek return (ISC_R_NOMEMORY);
84*00b67f09SDavid van Moolenbroek
85*00b67f09SDavid van Moolenbroek iter->mctx = mctx;
86*00b67f09SDavid van Moolenbroek iter->buf = 0;
87*00b67f09SDavid van Moolenbroek
88*00b67f09SDavid van Moolenbroek /*
89*00b67f09SDavid van Moolenbroek * Determine the amount of memory needed.
90*00b67f09SDavid van Moolenbroek */
91*00b67f09SDavid van Moolenbroek bufsize = 0;
92*00b67f09SDavid van Moolenbroek if (sysctl(mib, 6, NULL, &bufsize, NULL, (size_t) 0) < 0) {
93*00b67f09SDavid van Moolenbroek isc__strerror(errno, strbuf, sizeof(strbuf));
94*00b67f09SDavid van Moolenbroek UNEXPECTED_ERROR(__FILE__, __LINE__,
95*00b67f09SDavid van Moolenbroek isc_msgcat_get(isc_msgcat,
96*00b67f09SDavid van Moolenbroek ISC_MSGSET_IFITERSYSCTL,
97*00b67f09SDavid van Moolenbroek ISC_MSG_GETIFLISTSIZE,
98*00b67f09SDavid van Moolenbroek "getting interface "
99*00b67f09SDavid van Moolenbroek "list size: sysctl: %s"),
100*00b67f09SDavid van Moolenbroek strbuf);
101*00b67f09SDavid van Moolenbroek result = ISC_R_UNEXPECTED;
102*00b67f09SDavid van Moolenbroek goto failure;
103*00b67f09SDavid van Moolenbroek }
104*00b67f09SDavid van Moolenbroek iter->bufsize = bufsize;
105*00b67f09SDavid van Moolenbroek
106*00b67f09SDavid van Moolenbroek iter->buf = isc_mem_get(iter->mctx, iter->bufsize);
107*00b67f09SDavid van Moolenbroek if (iter->buf == NULL) {
108*00b67f09SDavid van Moolenbroek result = ISC_R_NOMEMORY;
109*00b67f09SDavid van Moolenbroek goto failure;
110*00b67f09SDavid van Moolenbroek }
111*00b67f09SDavid van Moolenbroek
112*00b67f09SDavid van Moolenbroek bufused = bufsize;
113*00b67f09SDavid van Moolenbroek if (sysctl(mib, 6, iter->buf, &bufused, NULL, (size_t) 0) < 0) {
114*00b67f09SDavid van Moolenbroek isc__strerror(errno, strbuf, sizeof(strbuf));
115*00b67f09SDavid van Moolenbroek UNEXPECTED_ERROR(__FILE__, __LINE__,
116*00b67f09SDavid van Moolenbroek isc_msgcat_get(isc_msgcat,
117*00b67f09SDavid van Moolenbroek ISC_MSGSET_IFITERSYSCTL,
118*00b67f09SDavid van Moolenbroek ISC_MSG_GETIFLIST,
119*00b67f09SDavid van Moolenbroek "getting interface list: "
120*00b67f09SDavid van Moolenbroek "sysctl: %s"),
121*00b67f09SDavid van Moolenbroek strbuf);
122*00b67f09SDavid van Moolenbroek result = ISC_R_UNEXPECTED;
123*00b67f09SDavid van Moolenbroek goto failure;
124*00b67f09SDavid van Moolenbroek }
125*00b67f09SDavid van Moolenbroek iter->bufused = bufused;
126*00b67f09SDavid van Moolenbroek INSIST(iter->bufused <= iter->bufsize);
127*00b67f09SDavid van Moolenbroek
128*00b67f09SDavid van Moolenbroek /*
129*00b67f09SDavid van Moolenbroek * A newly created iterator has an undefined position
130*00b67f09SDavid van Moolenbroek * until isc_interfaceiter_first() is called.
131*00b67f09SDavid van Moolenbroek */
132*00b67f09SDavid van Moolenbroek iter->pos = (unsigned int) -1;
133*00b67f09SDavid van Moolenbroek iter->result = ISC_R_FAILURE;
134*00b67f09SDavid van Moolenbroek
135*00b67f09SDavid van Moolenbroek iter->magic = IFITER_MAGIC;
136*00b67f09SDavid van Moolenbroek *iterp = iter;
137*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
138*00b67f09SDavid van Moolenbroek
139*00b67f09SDavid van Moolenbroek failure:
140*00b67f09SDavid van Moolenbroek if (iter->buf != NULL)
141*00b67f09SDavid van Moolenbroek isc_mem_put(mctx, iter->buf, iter->bufsize);
142*00b67f09SDavid van Moolenbroek isc_mem_put(mctx, iter, sizeof(*iter));
143*00b67f09SDavid van Moolenbroek return (result);
144*00b67f09SDavid van Moolenbroek }
145*00b67f09SDavid van Moolenbroek
146*00b67f09SDavid van Moolenbroek /*
147*00b67f09SDavid van Moolenbroek * Get information about the current interface to iter->current.
148*00b67f09SDavid van Moolenbroek * If successful, return ISC_R_SUCCESS.
149*00b67f09SDavid van Moolenbroek * If the interface has an unsupported address family,
150*00b67f09SDavid van Moolenbroek * return ISC_R_IGNORE. In case of other failure,
151*00b67f09SDavid van Moolenbroek * return ISC_R_UNEXPECTED.
152*00b67f09SDavid van Moolenbroek */
153*00b67f09SDavid van Moolenbroek
154*00b67f09SDavid van Moolenbroek static isc_result_t
internal_current(isc_interfaceiter_t * iter)155*00b67f09SDavid van Moolenbroek internal_current(isc_interfaceiter_t *iter) {
156*00b67f09SDavid van Moolenbroek struct ifa_msghdr *ifam, *ifam_end;
157*00b67f09SDavid van Moolenbroek
158*00b67f09SDavid van Moolenbroek REQUIRE(VALID_IFITER(iter));
159*00b67f09SDavid van Moolenbroek REQUIRE (iter->pos < (unsigned int) iter->bufused);
160*00b67f09SDavid van Moolenbroek
161*00b67f09SDavid van Moolenbroek ifam = (struct ifa_msghdr *) ((char *) iter->buf + iter->pos);
162*00b67f09SDavid van Moolenbroek ifam_end = (struct ifa_msghdr *) ((char *) iter->buf + iter->bufused);
163*00b67f09SDavid van Moolenbroek
164*00b67f09SDavid van Moolenbroek if (ifam->ifam_type == RTM_IFINFO) {
165*00b67f09SDavid van Moolenbroek struct if_msghdr *ifm = (struct if_msghdr *) ifam;
166*00b67f09SDavid van Moolenbroek struct sockaddr_dl *sdl = (struct sockaddr_dl *) (ifm + 1);
167*00b67f09SDavid van Moolenbroek unsigned int namelen;
168*00b67f09SDavid van Moolenbroek
169*00b67f09SDavid van Moolenbroek memset(&iter->current, 0, sizeof(iter->current));
170*00b67f09SDavid van Moolenbroek
171*00b67f09SDavid van Moolenbroek namelen = sdl->sdl_nlen;
172*00b67f09SDavid van Moolenbroek if (namelen > sizeof(iter->current.name) - 1)
173*00b67f09SDavid van Moolenbroek namelen = sizeof(iter->current.name) - 1;
174*00b67f09SDavid van Moolenbroek
175*00b67f09SDavid van Moolenbroek memset(iter->current.name, 0, sizeof(iter->current.name));
176*00b67f09SDavid van Moolenbroek memmove(iter->current.name, sdl->sdl_data, namelen);
177*00b67f09SDavid van Moolenbroek
178*00b67f09SDavid van Moolenbroek iter->current.flags = 0;
179*00b67f09SDavid van Moolenbroek
180*00b67f09SDavid van Moolenbroek if ((ifam->ifam_flags & IFF_UP) != 0)
181*00b67f09SDavid van Moolenbroek iter->current.flags |= INTERFACE_F_UP;
182*00b67f09SDavid van Moolenbroek
183*00b67f09SDavid van Moolenbroek if ((ifam->ifam_flags & IFF_POINTOPOINT) != 0)
184*00b67f09SDavid van Moolenbroek iter->current.flags |= INTERFACE_F_POINTTOPOINT;
185*00b67f09SDavid van Moolenbroek
186*00b67f09SDavid van Moolenbroek if ((ifam->ifam_flags & IFF_LOOPBACK) != 0)
187*00b67f09SDavid van Moolenbroek iter->current.flags |= INTERFACE_F_LOOPBACK;
188*00b67f09SDavid van Moolenbroek
189*00b67f09SDavid van Moolenbroek /*
190*00b67f09SDavid van Moolenbroek * This is not an interface address.
191*00b67f09SDavid van Moolenbroek * Force another iteration.
192*00b67f09SDavid van Moolenbroek */
193*00b67f09SDavid van Moolenbroek return (ISC_R_IGNORE);
194*00b67f09SDavid van Moolenbroek } else if (ifam->ifam_type == RTM_NEWADDR) {
195*00b67f09SDavid van Moolenbroek int i;
196*00b67f09SDavid van Moolenbroek int family;
197*00b67f09SDavid van Moolenbroek struct sockaddr *mask_sa = NULL;
198*00b67f09SDavid van Moolenbroek struct sockaddr *addr_sa = NULL;
199*00b67f09SDavid van Moolenbroek struct sockaddr *dst_sa = NULL;
200*00b67f09SDavid van Moolenbroek
201*00b67f09SDavid van Moolenbroek struct sockaddr *sa = (struct sockaddr *)(ifam + 1);
202*00b67f09SDavid van Moolenbroek family = sa->sa_family;
203*00b67f09SDavid van Moolenbroek
204*00b67f09SDavid van Moolenbroek for (i = 0; i < RTAX_MAX; i++)
205*00b67f09SDavid van Moolenbroek {
206*00b67f09SDavid van Moolenbroek if ((ifam->ifam_addrs & (1 << i)) == 0)
207*00b67f09SDavid van Moolenbroek continue;
208*00b67f09SDavid van Moolenbroek
209*00b67f09SDavid van Moolenbroek INSIST(sa < (struct sockaddr *) ifam_end);
210*00b67f09SDavid van Moolenbroek
211*00b67f09SDavid van Moolenbroek switch (i) {
212*00b67f09SDavid van Moolenbroek case RTAX_NETMASK: /* Netmask */
213*00b67f09SDavid van Moolenbroek mask_sa = sa;
214*00b67f09SDavid van Moolenbroek break;
215*00b67f09SDavid van Moolenbroek case RTAX_IFA: /* Interface address */
216*00b67f09SDavid van Moolenbroek addr_sa = sa;
217*00b67f09SDavid van Moolenbroek break;
218*00b67f09SDavid van Moolenbroek case RTAX_BRD: /* Broadcast or destination address */
219*00b67f09SDavid van Moolenbroek dst_sa = sa;
220*00b67f09SDavid van Moolenbroek break;
221*00b67f09SDavid van Moolenbroek }
222*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_HAVESALEN
223*00b67f09SDavid van Moolenbroek sa = (struct sockaddr *)((char*)(sa)
224*00b67f09SDavid van Moolenbroek + ROUNDUP(sa->sa_len));
225*00b67f09SDavid van Moolenbroek #else
226*00b67f09SDavid van Moolenbroek #ifdef sgi
227*00b67f09SDavid van Moolenbroek /*
228*00b67f09SDavid van Moolenbroek * Do as the contributed SGI code does.
229*00b67f09SDavid van Moolenbroek */
230*00b67f09SDavid van Moolenbroek sa = (struct sockaddr *)((char*)(sa)
231*00b67f09SDavid van Moolenbroek + ROUNDUP(_FAKE_SA_LEN_DST(sa)));
232*00b67f09SDavid van Moolenbroek #else
233*00b67f09SDavid van Moolenbroek /* XXX untested. */
234*00b67f09SDavid van Moolenbroek sa = (struct sockaddr *)((char*)(sa)
235*00b67f09SDavid van Moolenbroek + ROUNDUP(sizeof(struct sockaddr)));
236*00b67f09SDavid van Moolenbroek #endif
237*00b67f09SDavid van Moolenbroek #endif
238*00b67f09SDavid van Moolenbroek }
239*00b67f09SDavid van Moolenbroek
240*00b67f09SDavid van Moolenbroek if (addr_sa == NULL)
241*00b67f09SDavid van Moolenbroek return (ISC_R_IGNORE);
242*00b67f09SDavid van Moolenbroek
243*00b67f09SDavid van Moolenbroek family = addr_sa->sa_family;
244*00b67f09SDavid van Moolenbroek if (family != AF_INET && family != AF_INET6)
245*00b67f09SDavid van Moolenbroek return (ISC_R_IGNORE);
246*00b67f09SDavid van Moolenbroek
247*00b67f09SDavid van Moolenbroek iter->current.af = family;
248*00b67f09SDavid van Moolenbroek
249*00b67f09SDavid van Moolenbroek get_addr(family, &iter->current.address, addr_sa,
250*00b67f09SDavid van Moolenbroek iter->current.name);
251*00b67f09SDavid van Moolenbroek
252*00b67f09SDavid van Moolenbroek if (mask_sa != NULL)
253*00b67f09SDavid van Moolenbroek get_addr(family, &iter->current.netmask, mask_sa,
254*00b67f09SDavid van Moolenbroek iter->current.name);
255*00b67f09SDavid van Moolenbroek
256*00b67f09SDavid van Moolenbroek if (dst_sa != NULL &&
257*00b67f09SDavid van Moolenbroek (iter->current.flags & INTERFACE_F_POINTTOPOINT) != 0)
258*00b67f09SDavid van Moolenbroek get_addr(family, &iter->current.dstaddress, dst_sa,
259*00b67f09SDavid van Moolenbroek iter->current.name);
260*00b67f09SDavid van Moolenbroek
261*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
262*00b67f09SDavid van Moolenbroek } else {
263*00b67f09SDavid van Moolenbroek printf(isc_msgcat_get(isc_msgcat, ISC_MSGSET_IFITERSYSCTL,
264*00b67f09SDavid van Moolenbroek ISC_MSG_UNEXPECTEDTYPE,
265*00b67f09SDavid van Moolenbroek "warning: unexpected interface list "
266*00b67f09SDavid van Moolenbroek "message type\n"));
267*00b67f09SDavid van Moolenbroek return (ISC_R_IGNORE);
268*00b67f09SDavid van Moolenbroek }
269*00b67f09SDavid van Moolenbroek }
270*00b67f09SDavid van Moolenbroek
271*00b67f09SDavid van Moolenbroek /*
272*00b67f09SDavid van Moolenbroek * Step the iterator to the next interface. Unlike
273*00b67f09SDavid van Moolenbroek * isc_interfaceiter_next(), this may leave the iterator
274*00b67f09SDavid van Moolenbroek * positioned on an interface that will ultimately
275*00b67f09SDavid van Moolenbroek * be ignored. Return ISC_R_NOMORE if there are no more
276*00b67f09SDavid van Moolenbroek * interfaces, otherwise ISC_R_SUCCESS.
277*00b67f09SDavid van Moolenbroek */
278*00b67f09SDavid van Moolenbroek static isc_result_t
internal_next(isc_interfaceiter_t * iter)279*00b67f09SDavid van Moolenbroek internal_next(isc_interfaceiter_t *iter) {
280*00b67f09SDavid van Moolenbroek struct ifa_msghdr *ifam;
281*00b67f09SDavid van Moolenbroek REQUIRE (iter->pos < (unsigned int) iter->bufused);
282*00b67f09SDavid van Moolenbroek
283*00b67f09SDavid van Moolenbroek ifam = (struct ifa_msghdr *) ((char *) iter->buf + iter->pos);
284*00b67f09SDavid van Moolenbroek
285*00b67f09SDavid van Moolenbroek iter->pos += ifam->ifam_msglen;
286*00b67f09SDavid van Moolenbroek
287*00b67f09SDavid van Moolenbroek if (iter->pos >= iter->bufused)
288*00b67f09SDavid van Moolenbroek return (ISC_R_NOMORE);
289*00b67f09SDavid van Moolenbroek
290*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
291*00b67f09SDavid van Moolenbroek }
292*00b67f09SDavid van Moolenbroek
293*00b67f09SDavid van Moolenbroek static void
internal_destroy(isc_interfaceiter_t * iter)294*00b67f09SDavid van Moolenbroek internal_destroy(isc_interfaceiter_t *iter) {
295*00b67f09SDavid van Moolenbroek UNUSED(iter); /* Unused. */
296*00b67f09SDavid van Moolenbroek /*
297*00b67f09SDavid van Moolenbroek * Do nothing.
298*00b67f09SDavid van Moolenbroek */
299*00b67f09SDavid van Moolenbroek }
300*00b67f09SDavid van Moolenbroek
301*00b67f09SDavid van Moolenbroek static
internal_first(isc_interfaceiter_t * iter)302*00b67f09SDavid van Moolenbroek void internal_first(isc_interfaceiter_t *iter) {
303*00b67f09SDavid van Moolenbroek iter->pos = 0;
304*00b67f09SDavid van Moolenbroek }
305