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