1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
3*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
4*7c478bd9Sstevel@tonic-gate  */
5*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
6*7c478bd9Sstevel@tonic-gate /*
7*7c478bd9Sstevel@tonic-gate  * include/foreachaddr.c
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * Copyright 1990,1991,2000,2001,2002 by the Massachusetts Institute of Technology.
10*7c478bd9Sstevel@tonic-gate  * All Rights Reserved.
11*7c478bd9Sstevel@tonic-gate  *
12*7c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may
13*7c478bd9Sstevel@tonic-gate  *   require a specific license from the United States Government.
14*7c478bd9Sstevel@tonic-gate  *   It is the responsibility of any person or organization contemplating
15*7c478bd9Sstevel@tonic-gate  *   export to obtain such a license before exporting.
16*7c478bd9Sstevel@tonic-gate  *
17*7c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
18*7c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
19*7c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
20*7c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
21*7c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
22*7c478bd9Sstevel@tonic-gate  * the name of M.I.T. not be used in advertising or publicity pertaining
23*7c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
24*7c478bd9Sstevel@tonic-gate  * permission.  Furthermore if you modify this software you must label
25*7c478bd9Sstevel@tonic-gate  * your software as modified software and not distribute it in such a
26*7c478bd9Sstevel@tonic-gate  * fashion that it might be confused with the original M.I.T. software.
27*7c478bd9Sstevel@tonic-gate  * M.I.T. makes no representations about the suitability of
28*7c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
29*7c478bd9Sstevel@tonic-gate  * or implied warranty.
30*7c478bd9Sstevel@tonic-gate  *
31*7c478bd9Sstevel@tonic-gate  *
32*7c478bd9Sstevel@tonic-gate  * Iterate over the protocol addresses supported by this host, invoking
33*7c478bd9Sstevel@tonic-gate  * a callback function or three supplied by the caller.
34*7c478bd9Sstevel@tonic-gate  *
35*7c478bd9Sstevel@tonic-gate  * XNS support is untested, but "should just work".  (Hah!)
36*7c478bd9Sstevel@tonic-gate  */
37*7c478bd9Sstevel@tonic-gate 
38*7c478bd9Sstevel@tonic-gate /* This is the primary "export" of this file.  It's a static function,
39*7c478bd9Sstevel@tonic-gate    so this file must be #included in the .c file containing the
40*7c478bd9Sstevel@tonic-gate    caller.
41*7c478bd9Sstevel@tonic-gate 
42*7c478bd9Sstevel@tonic-gate    This function iterates over all the addresses it can find for the
43*7c478bd9Sstevel@tonic-gate    local system, in one or two passes.  In each pass, and between the
44*7c478bd9Sstevel@tonic-gate    two, it can invoke callback functions supplied by the caller.  The
45*7c478bd9Sstevel@tonic-gate    two passes should operate on the same information, though not
46*7c478bd9Sstevel@tonic-gate    necessarily in the same order each time.  Duplicate and local
47*7c478bd9Sstevel@tonic-gate    addresses should be eliminated.  Storage passed to callback
48*7c478bd9Sstevel@tonic-gate    functions should not be assumed to be valid after foreach_localaddr
49*7c478bd9Sstevel@tonic-gate    returns.
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate    The int return value is an errno value (XXX or krb5_error_code
52*7c478bd9Sstevel@tonic-gate    returned for a socket error) if something internal to
53*7c478bd9Sstevel@tonic-gate    foreach_localaddr fails.  If one of the callback functions wants to
54*7c478bd9Sstevel@tonic-gate    indicate an error, it should store something via the 'data' handle.
55*7c478bd9Sstevel@tonic-gate    If any callback function returns a non-zero value,
56*7c478bd9Sstevel@tonic-gate    foreach_localaddr will clean up and return immediately.
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate    Multiple definitions are provided below, dependent on various
59*7c478bd9Sstevel@tonic-gate    system facilities for extracting the necessary information.  */
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate /* Solaris Kerberos: changing foreach_localaddr to non-static as it's called in
62*7c478bd9Sstevel@tonic-gate  * a couple places.
63*7c478bd9Sstevel@tonic-gate  */
64*7c478bd9Sstevel@tonic-gate 
65*7c478bd9Sstevel@tonic-gate #ifdef TEST
66*7c478bd9Sstevel@tonic-gate # define Tprintf(X) printf X
67*7c478bd9Sstevel@tonic-gate # define Tperror(X) perror(X)
68*7c478bd9Sstevel@tonic-gate #else
69*7c478bd9Sstevel@tonic-gate # define Tprintf(X) (void) X
70*7c478bd9Sstevel@tonic-gate # define Tperror(X) (void)(X)
71*7c478bd9Sstevel@tonic-gate #endif
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate /*
74*7c478bd9Sstevel@tonic-gate  * The SIOCGIF* ioctls require a socket.
75*7c478bd9Sstevel@tonic-gate  * It doesn't matter *what* kind of socket they use, but it has to be
76*7c478bd9Sstevel@tonic-gate  * a socket.
77*7c478bd9Sstevel@tonic-gate  *
78*7c478bd9Sstevel@tonic-gate  * Of course, you can't just ask the kernel for a socket of arbitrary
79*7c478bd9Sstevel@tonic-gate  * type; you have to ask for one with a valid type.
80*7c478bd9Sstevel@tonic-gate  *
81*7c478bd9Sstevel@tonic-gate  */
82*7c478bd9Sstevel@tonic-gate #ifdef HAVE_NETINET_IN_H
83*7c478bd9Sstevel@tonic-gate #include <netinet/in.h>
84*7c478bd9Sstevel@tonic-gate #ifndef USE_AF
85*7c478bd9Sstevel@tonic-gate #define USE_AF AF_INET
86*7c478bd9Sstevel@tonic-gate #define USE_TYPE SOCK_DGRAM
87*7c478bd9Sstevel@tonic-gate #define USE_PROTO 0
88*7c478bd9Sstevel@tonic-gate #endif
89*7c478bd9Sstevel@tonic-gate #endif
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate #ifdef KRB5_USE_NS
92*7c478bd9Sstevel@tonic-gate #include <netns/ns.h>
93*7c478bd9Sstevel@tonic-gate #ifndef USE_AF
94*7c478bd9Sstevel@tonic-gate #define USE_AF AF_NS
95*7c478bd9Sstevel@tonic-gate #define USE_TYPE SOCK_DGRAM
96*7c478bd9Sstevel@tonic-gate #define USE_PROTO 0		/* guess */
97*7c478bd9Sstevel@tonic-gate #endif
98*7c478bd9Sstevel@tonic-gate #endif
99*7c478bd9Sstevel@tonic-gate /*
100*7c478bd9Sstevel@tonic-gate  * Add more address families here.
101*7c478bd9Sstevel@tonic-gate  */
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate #include <errno.h>
104*7c478bd9Sstevel@tonic-gate #include <fake-addrinfo.h>
105*7c478bd9Sstevel@tonic-gate #include <sys/sockio.h>
106*7c478bd9Sstevel@tonic-gate #include <k5-int.h>
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate /*
109*7c478bd9Sstevel@tonic-gate  * Return all the protocol addresses of this host.
110*7c478bd9Sstevel@tonic-gate  *
111*7c478bd9Sstevel@tonic-gate  * We could kludge up something to return all addresses, assuming that
112*7c478bd9Sstevel@tonic-gate  * they're valid kerberos protocol addresses, but we wouldn't know the
113*7c478bd9Sstevel@tonic-gate  * real size of the sockaddr or know which part of it was actually the
114*7c478bd9Sstevel@tonic-gate  * host part.
115*7c478bd9Sstevel@tonic-gate  *
116*7c478bd9Sstevel@tonic-gate  * This uses the SIOCGIFCONF, SIOCGIFFLAGS, and SIOCGIFADDR ioctl's.
117*7c478bd9Sstevel@tonic-gate  */
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate /*
120*7c478bd9Sstevel@tonic-gate  * BSD 4.4 defines the size of an ifreq to be
121*7c478bd9Sstevel@tonic-gate  * max(sizeof(ifreq), sizeof(ifreq.ifr_name)+ifreq.ifr_addr.sa_len
122*7c478bd9Sstevel@tonic-gate  * However, under earlier systems, sa_len isn't present, so the size is
123*7c478bd9Sstevel@tonic-gate  * just sizeof(struct ifreq).
124*7c478bd9Sstevel@tonic-gate  */
125*7c478bd9Sstevel@tonic-gate #ifdef HAVE_SA_LEN
126*7c478bd9Sstevel@tonic-gate #ifndef max
127*7c478bd9Sstevel@tonic-gate #define max(a,b) ((a) > (b) ? (a) : (b))
128*7c478bd9Sstevel@tonic-gate #endif
129*7c478bd9Sstevel@tonic-gate #define ifreq_size(i) max(sizeof(struct ifreq),\
130*7c478bd9Sstevel@tonic-gate      sizeof((i).ifr_name)+(i).ifr_addr.sa_len)
131*7c478bd9Sstevel@tonic-gate #else
132*7c478bd9Sstevel@tonic-gate #define ifreq_size(i) sizeof(struct ifreq)
133*7c478bd9Sstevel@tonic-gate #endif /* HAVE_SA_LEN*/
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate #ifdef SIOCGLIFCONF /* Solaris */
137*7c478bd9Sstevel@tonic-gate static int
138*7c478bd9Sstevel@tonic-gate get_lifconf (int af, int s, size_t *lenp, char *buf)
139*7c478bd9Sstevel@tonic-gate     /*@modifies *buf,*lenp@*/
140*7c478bd9Sstevel@tonic-gate {
141*7c478bd9Sstevel@tonic-gate     int ret;
142*7c478bd9Sstevel@tonic-gate     struct lifconf lifc;
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate     lifc.lifc_family = af;
145*7c478bd9Sstevel@tonic-gate     lifc.lifc_flags = 0;
146*7c478bd9Sstevel@tonic-gate     lifc.lifc_len = *lenp;
147*7c478bd9Sstevel@tonic-gate     lifc.lifc_buf = buf;
148*7c478bd9Sstevel@tonic-gate     memset(buf, 0, *lenp);
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate     ret = ioctl (s, SIOCGLIFCONF, (char *)&lifc);
151*7c478bd9Sstevel@tonic-gate     if (ret)
152*7c478bd9Sstevel@tonic-gate 	Tperror ("SIOCGLIFCONF");
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate     *lenp = lifc.lifc_len;
155*7c478bd9Sstevel@tonic-gate     return ret;
156*7c478bd9Sstevel@tonic-gate }
157*7c478bd9Sstevel@tonic-gate #endif
158*7c478bd9Sstevel@tonic-gate 
159*7c478bd9Sstevel@tonic-gate /* Return value is errno if internal stuff failed, otherwise zero,
160*7c478bd9Sstevel@tonic-gate    even in the case where a called function terminated the iteration.
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate    If one of the callback functions wants to pass back an error
163*7c478bd9Sstevel@tonic-gate    indication, it should do it via some field pointed to by the DATA
164*7c478bd9Sstevel@tonic-gate    argument.  */
165*7c478bd9Sstevel@tonic-gate 
166*7c478bd9Sstevel@tonic-gate int
167*7c478bd9Sstevel@tonic-gate foreach_localaddr (void *data,
168*7c478bd9Sstevel@tonic-gate 		   int (*pass1fn) (void *, struct sockaddr *),
169*7c478bd9Sstevel@tonic-gate 		   int (*betweenfn) (void *),
170*7c478bd9Sstevel@tonic-gate 		   int (*pass2fn) (void *, struct sockaddr *))
171*7c478bd9Sstevel@tonic-gate {
172*7c478bd9Sstevel@tonic-gate     /* Okay, this is kind of odd.  We have to use each of the address
173*7c478bd9Sstevel@tonic-gate        families we care about, because with an AF_INET socket, extra
174*7c478bd9Sstevel@tonic-gate        interfaces like hme0:1 that have only AF_INET6 addresses will
175*7c478bd9Sstevel@tonic-gate        cause errors.  Similarly, if hme0 has more AF_INET addresses
176*7c478bd9Sstevel@tonic-gate        than AF_INET6 addresses, we won't be able to retrieve all of
177*7c478bd9Sstevel@tonic-gate        the AF_INET addresses if we use an AF_INET6 socket.  Since
178*7c478bd9Sstevel@tonic-gate        neither family is guaranteed to have the greater number of
179*7c478bd9Sstevel@tonic-gate        addresses, we should use both.
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate        If it weren't for this little quirk, we could use one socket of
182*7c478bd9Sstevel@tonic-gate        any type, and ask for addresses of all types.  At least, it
183*7c478bd9Sstevel@tonic-gate        seems to work that way.  */
184*7c478bd9Sstevel@tonic-gate 
185*7c478bd9Sstevel@tonic-gate     /* Solaris kerberos: avoid using AF_NS if no define */
186*7c478bd9Sstevel@tonic-gate #if defined (KRB5_USE_INET6) && defined (KRB5_USE_NS)
187*7c478bd9Sstevel@tonic-gate     static const int afs[] = { AF_INET, AF_NS, AF_INET6 };
188*7c478bd9Sstevel@tonic-gate #elif defined (KRB5_USE_INET6)
189*7c478bd9Sstevel@tonic-gate     static const int afs[] = { AF_INET, AF_INET6 };
190*7c478bd9Sstevel@tonic-gate #else
191*7c478bd9Sstevel@tonic-gate     static const int afs[] = { AF_INET };
192*7c478bd9Sstevel@tonic-gate #endif
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate #define N_AFS (sizeof (afs) / sizeof (afs[0]))
195*7c478bd9Sstevel@tonic-gate     struct {
196*7c478bd9Sstevel@tonic-gate 	int af;
197*7c478bd9Sstevel@tonic-gate 	int sock;
198*7c478bd9Sstevel@tonic-gate 	void *buf;
199*7c478bd9Sstevel@tonic-gate 	size_t buf_size;
200*7c478bd9Sstevel@tonic-gate 	struct lifnum lifnum;
201*7c478bd9Sstevel@tonic-gate     } afp[N_AFS];
202*7c478bd9Sstevel@tonic-gate     int code, i, j;
203*7c478bd9Sstevel@tonic-gate     int retval = 0, afidx;
204*7c478bd9Sstevel@tonic-gate     krb5_error_code sock_err = 0;
205*7c478bd9Sstevel@tonic-gate     struct lifreq *lifr, lifreq, *lifr2;
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate #define FOREACH_AF() for (afidx = 0; afidx < N_AFS; afidx++)
208*7c478bd9Sstevel@tonic-gate #define P (afp[afidx])
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate     KRB5_LOG0(KRB5_INFO, "foreach_localaddr() start");
211*7c478bd9Sstevel@tonic-gate     /* init */
212*7c478bd9Sstevel@tonic-gate     FOREACH_AF () {
213*7c478bd9Sstevel@tonic-gate 	P.af = afs[afidx];
214*7c478bd9Sstevel@tonic-gate 	P.sock = -1;
215*7c478bd9Sstevel@tonic-gate 	P.buf = 0;
216*7c478bd9Sstevel@tonic-gate     }
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate     /* first pass: get raw data, discard uninteresting addresses, callback */
219*7c478bd9Sstevel@tonic-gate     FOREACH_AF () {
220*7c478bd9Sstevel@tonic-gate 	KRB5_LOG (KRB5_INFO, "foreach_localaddr() trying af %d", P.af);
221*7c478bd9Sstevel@tonic-gate 	P.sock = socket (P.af, USE_TYPE, USE_PROTO);
222*7c478bd9Sstevel@tonic-gate 	if (P.sock < 0) {
223*7c478bd9Sstevel@tonic-gate 	    sock_err = SOCKET_ERROR;
224*7c478bd9Sstevel@tonic-gate 	    Tperror ("socket");
225*7c478bd9Sstevel@tonic-gate 	    continue;
226*7c478bd9Sstevel@tonic-gate 	}
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate 	P.lifnum.lifn_family = P.af;
229*7c478bd9Sstevel@tonic-gate 	P.lifnum.lifn_flags = 0;
230*7c478bd9Sstevel@tonic-gate 	P.lifnum.lifn_count = 0;
231*7c478bd9Sstevel@tonic-gate 	code = ioctl (P.sock, SIOCGLIFNUM, &P.lifnum);
232*7c478bd9Sstevel@tonic-gate 	if (code) {
233*7c478bd9Sstevel@tonic-gate 	    Tperror ("ioctl(SIOCGLIFNUM)");
234*7c478bd9Sstevel@tonic-gate 	    retval = errno;
235*7c478bd9Sstevel@tonic-gate 	    goto punt;
236*7c478bd9Sstevel@tonic-gate 	}
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate 	KRB5_LOG (KRB5_INFO, "foreach_localaddr() lifn_count %d",
239*7c478bd9Sstevel@tonic-gate 		P.lifnum.lifn_count);
240*7c478bd9Sstevel@tonic-gate 	P.buf_size = P.lifnum.lifn_count * sizeof (struct lifreq) * 2;
241*7c478bd9Sstevel@tonic-gate 	P.buf = malloc (P.buf_size);
242*7c478bd9Sstevel@tonic-gate 	if (P.buf == NULL) {
243*7c478bd9Sstevel@tonic-gate 	    retval = errno;
244*7c478bd9Sstevel@tonic-gate 	    goto punt;
245*7c478bd9Sstevel@tonic-gate 	}
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate 	code = get_lifconf (P.af, P.sock, &P.buf_size, P.buf);
248*7c478bd9Sstevel@tonic-gate 	if (code < 0) {
249*7c478bd9Sstevel@tonic-gate 	    retval = errno;
250*7c478bd9Sstevel@tonic-gate 	    goto punt;
251*7c478bd9Sstevel@tonic-gate 	}
252*7c478bd9Sstevel@tonic-gate 
253*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < P.buf_size; i+= sizeof (*lifr)) {
254*7c478bd9Sstevel@tonic-gate 	    /*LINTED*/
255*7c478bd9Sstevel@tonic-gate 	    lifr = (struct lifreq *)((caddr_t) P.buf+i);
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate 	    strncpy(lifreq.lifr_name, lifr->lifr_name,
258*7c478bd9Sstevel@tonic-gate 		    sizeof (lifreq.lifr_name));
259*7c478bd9Sstevel@tonic-gate 	    KRB5_LOG (KRB5_INFO, "foreach_localaddr() interface %s",
260*7c478bd9Sstevel@tonic-gate 		    lifreq.lifr_name);
261*7c478bd9Sstevel@tonic-gate 	    /* ioctl unknown to lclint */
262*7c478bd9Sstevel@tonic-gate 	    if (ioctl (P.sock, SIOCGLIFFLAGS, (char *)&lifreq) < 0) {
263*7c478bd9Sstevel@tonic-gate 		Tperror ("ioctl(SIOCGLIFFLAGS)");
264*7c478bd9Sstevel@tonic-gate 	    skip:
265*7c478bd9Sstevel@tonic-gate 		KRB5_LOG (KRB5_INFO,
266*7c478bd9Sstevel@tonic-gate 			"foreach_localaddr() skipping interface %s",
267*7c478bd9Sstevel@tonic-gate 			lifr->lifr_name);
268*7c478bd9Sstevel@tonic-gate 		/* mark for next pass */
269*7c478bd9Sstevel@tonic-gate 		lifr->lifr_name[0] = '\0';
270*7c478bd9Sstevel@tonic-gate 		continue;
271*7c478bd9Sstevel@tonic-gate 	    }
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate #ifdef IFF_LOOPBACK
274*7c478bd9Sstevel@tonic-gate 	    /* None of the current callers want loopback addresses.  */
275*7c478bd9Sstevel@tonic-gate 	    if (lifreq.lifr_flags & IFF_LOOPBACK) {
276*7c478bd9Sstevel@tonic-gate 		Tprintf (("  loopback\n"));
277*7c478bd9Sstevel@tonic-gate 		goto skip;
278*7c478bd9Sstevel@tonic-gate 	    }
279*7c478bd9Sstevel@tonic-gate #endif
280*7c478bd9Sstevel@tonic-gate 	    /* Ignore interfaces that are down.  */
281*7c478bd9Sstevel@tonic-gate 	    if ((lifreq.lifr_flags & IFF_UP) == 0) {
282*7c478bd9Sstevel@tonic-gate 		Tprintf (("  down\n"));
283*7c478bd9Sstevel@tonic-gate 		goto skip;
284*7c478bd9Sstevel@tonic-gate 	    }
285*7c478bd9Sstevel@tonic-gate 
286*7c478bd9Sstevel@tonic-gate 	    /* Make sure we didn't process this address already.  */
287*7c478bd9Sstevel@tonic-gate 	    for (j = 0; j < i; j += sizeof (*lifr2)) {
288*7c478bd9Sstevel@tonic-gate 		/*LINTED*/
289*7c478bd9Sstevel@tonic-gate 		lifr2 = (struct lifreq *)((caddr_t) P.buf+j);
290*7c478bd9Sstevel@tonic-gate 		if (lifr2->lifr_name[0] == '\0')
291*7c478bd9Sstevel@tonic-gate 		    continue;
292*7c478bd9Sstevel@tonic-gate 		if (lifr2->lifr_addr.ss_family == lifr->lifr_addr.ss_family
293*7c478bd9Sstevel@tonic-gate 		    /* Compare address info.  If this isn't good enough --
294*7c478bd9Sstevel@tonic-gate 		       i.e., if random padding bytes turn out to differ
295*7c478bd9Sstevel@tonic-gate 		       when the addresses are the same -- then we'll have
296*7c478bd9Sstevel@tonic-gate 		       to do it on a per address family basis.  */
297*7c478bd9Sstevel@tonic-gate 		    && !memcmp (&lifr2->lifr_addr, &lifr->lifr_addr,
298*7c478bd9Sstevel@tonic-gate 				sizeof (*lifr))) {
299*7c478bd9Sstevel@tonic-gate 		    Tprintf (("  duplicate addr\n"));
300*7c478bd9Sstevel@tonic-gate 		    KRB5_LOG0 (KRB5_INFO, "foreach_localaddr() dup addr");
301*7c478bd9Sstevel@tonic-gate 		    goto skip;
302*7c478bd9Sstevel@tonic-gate 		}
303*7c478bd9Sstevel@tonic-gate 	    }
304*7c478bd9Sstevel@tonic-gate 
305*7c478bd9Sstevel@tonic-gate 	    if ((*pass1fn) (data, ss2sa (&lifr->lifr_addr)))
306*7c478bd9Sstevel@tonic-gate 		goto punt;
307*7c478bd9Sstevel@tonic-gate 	}
308*7c478bd9Sstevel@tonic-gate     }
309*7c478bd9Sstevel@tonic-gate 
310*7c478bd9Sstevel@tonic-gate     /* Did we actually get any working sockets?  */
311*7c478bd9Sstevel@tonic-gate     FOREACH_AF ()
312*7c478bd9Sstevel@tonic-gate 	if (P.sock != -1)
313*7c478bd9Sstevel@tonic-gate 	    goto have_working_socket;
314*7c478bd9Sstevel@tonic-gate     retval = sock_err;
315*7c478bd9Sstevel@tonic-gate     goto punt;
316*7c478bd9Sstevel@tonic-gate have_working_socket:
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate     if (betweenfn != NULL && (*betweenfn)(data))
319*7c478bd9Sstevel@tonic-gate 	goto punt;
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate     if (pass2fn)
322*7c478bd9Sstevel@tonic-gate 	FOREACH_AF ()
323*7c478bd9Sstevel@tonic-gate 	    if (P.sock >= 0) {
324*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < P.buf_size; i+= sizeof (*lifr)) {
325*7c478bd9Sstevel@tonic-gate 		    /*LINTED*/
326*7c478bd9Sstevel@tonic-gate 		    lifr = (struct lifreq *)((caddr_t) P.buf+i);
327*7c478bd9Sstevel@tonic-gate 
328*7c478bd9Sstevel@tonic-gate 		    if (lifr->lifr_name[0] == '\0')
329*7c478bd9Sstevel@tonic-gate 			/* Marked in first pass to be ignored.  */
330*7c478bd9Sstevel@tonic-gate 			continue;
331*7c478bd9Sstevel@tonic-gate 
332*7c478bd9Sstevel@tonic-gate 		    KRB5_LOG (KRB5_INFO,
333*7c478bd9Sstevel@tonic-gate 			    "foreach_localaddr() doing pass2fn i = %d",
334*7c478bd9Sstevel@tonic-gate 			    i);
335*7c478bd9Sstevel@tonic-gate 		    if ((*pass2fn) (data, ss2sa (&lifr->lifr_addr)))
336*7c478bd9Sstevel@tonic-gate 			goto punt;
337*7c478bd9Sstevel@tonic-gate 		}
338*7c478bd9Sstevel@tonic-gate 	    }
339*7c478bd9Sstevel@tonic-gate punt:
340*7c478bd9Sstevel@tonic-gate     FOREACH_AF () {
341*7c478bd9Sstevel@tonic-gate 	closesocket(P.sock);
342*7c478bd9Sstevel@tonic-gate 	free (P.buf);
343*7c478bd9Sstevel@tonic-gate     }
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate     return retval;
346*7c478bd9Sstevel@tonic-gate }
347