Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / rx / rx_getaddr.c
1 /*
2 * Copyright 2000, International Business Machines Corporation and others.
3 * All Rights Reserved.
4 *
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
8 */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 #ifndef KERNEL
14
15 # include <roken.h>
16 # ifndef AFS_NT40_ENV
17 # include <net/if.h>
18 # if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
19 # include <sys/sysctl.h>
20 # ifndef AFS_ARM_DARWIN_ENV
21 # include <net/route.h>
22 # endif
23 # include <net/if_dl.h>
24 # endif
25
26 /*
27 * By including this, we get any system dependencies. In particular,
28 * the pthreads for solaris requires the socket call to be mapped.
29 */
30 # include "rx.h"
31 # include "rx_globals.h"
32 # endif /* AFS_NT40_ENV */
33 #else /* KERNEL */
34 # ifdef UKERNEL
35 # include "rx/rx_kcommon.h"
36 # else /* UKERNEL */
37 # include "rx/rx.h"
38 # endif /* UKERNEL */
39 #endif /* KERNEL */
40
41 #define NIFS 512
42
43 #if defined(AFS_USR_DFBSD_ENV)
44 # include <net/if.h>
45 # include <sys/sockio.h>
46 #endif
47
48 #ifdef KERNEL
49 /* only used for generating random noise */
50
51 afs_uint32 rxi_tempAddr = 0; /* default attempt */
52
53 /* set the advisory noise */
54 void
55 rxi_setaddr(afs_uint32 x)
56 {
57 rxi_tempAddr = x;
58 }
59
60 /* get approx to net addr */
61 afs_uint32
62 rxi_getaddr(void)
63 {
64 return rxi_tempAddr;
65 }
66
67 #endif /* KERNEL */
68
69 #ifndef KERNEL
70
71 /* to satisfy those who call setaddr */
72 void
73 rxi_setaddr(afs_uint32 x)
74 {
75 }
76
77 #endif /* !KERNEL */
78
79
80 #if !defined(AFS_NT40_ENV)
81 /* For NT, rxi_getaddr has moved to rx_user.c. rxi_GetIfInfo is called by
82 * rx_Init which sets up the list of addresses for us.
83 */
84
85 #ifndef KERNEL
86
87 /* Return our internet address as a long in network byte order. Returns zero
88 * if it can't find one.
89 */
90 afs_uint32
91 rxi_getaddr(void)
92 {
93 afs_uint32 buffer[1024];
94 int count;
95
96 count = rx_getAllAddr(buffer, 1024);
97 if (count > 0)
98 return buffer[0]; /* returns the first address */
99 else
100 return count;
101 }
102
103 #endif /* !KERNEL */
104
105 #if !defined(KERNEL) || defined(UKERNEL)
106
107 #ifndef MAX
108 #define MAX(A,B) (((A)<(B)) ? (B) : (A))
109 #endif
110
111 #ifdef UKERNEL
112 #undef ioctl
113 #undef socket
114 #endif /* UKERNEL */
115
116 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
117 #define ROUNDUP(a) \
118 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
119 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
120
121 static void
122 rt_xaddrs(caddr_t cp, caddr_t cplim, struct rt_addrinfo *rtinfo)
123 {
124 struct sockaddr *sa;
125 int i;
126
127 memset(rtinfo->rti_info, 0, sizeof(rtinfo->rti_info));
128 for (i = 0; (i < RTAX_MAX) && (cp < cplim); i++) {
129 if ((rtinfo->rti_addrs & (1 << i)) == 0)
130 continue;
131 rtinfo->rti_info[i] = sa = (struct sockaddr *)cp;
132 ADVANCE(cp, sa);
133 }
134 }
135 #endif
136
137 static_inline int
138 rxi_IsLoopbackIface(struct sockaddr_in *a, unsigned long flags)
139 {
140 afs_uint32 addr = ntohl(a->sin_addr.s_addr);
141 if (rx_IsLoopbackAddr(addr)) {
142 return 1;
143 }
144 if ((flags & IFF_LOOPBACK) && ((addr & 0xff000000) == 0x7f000000)) {
145 return 1;
146 }
147 return 0;
148 }
149
150 /* this function returns the total number of interface addresses
151 ** the buffer has to be passed in by the caller
152 */
153 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
154 #if defined(AFS_OBSD42_ENV)
155 void
156 ifm_fixversion(char *buffer, size_t *size) {
157 struct if_msghdr *ifm;
158 char *b = buffer;
159 char *s, *t;
160
161 if ((t = malloc(*size)) != NULL) {
162 memcpy(t, buffer, *size);
163
164 for (s = t; s < t + *size; s += ifm->ifm_msglen) {
165 ifm = (struct if_msghdr *)s;
166
167 if (ifm->ifm_version == RTM_VERSION) {
168 memcpy(b, ifm, ifm->ifm_msglen);
169 b += ifm->ifm_msglen;
170 }
171 }
172
173 free(t);
174
175 *size = b - buffer;
176 }
177 }
178 #endif
179
180 int
181 rx_getAllAddr_internal(afs_uint32 buffer[], int maxSize, int loopbacks)
182 {
183 size_t needed;
184 int mib[6];
185 struct if_msghdr *ifm, *nextifm;
186 struct ifa_msghdr *ifam;
187 struct rt_addrinfo info;
188 char *buf, *lim, *next;
189 int count = 0, addrcount = 0;
190
191 mib[0] = CTL_NET;
192 mib[1] = PF_ROUTE;
193 mib[2] = 0;
194 mib[3] = AF_INET; /* address family */
195 mib[4] = NET_RT_IFLIST;
196 mib[5] = 0;
197 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
198 return 0;
199 if ((buf = malloc(needed)) == NULL)
200 return 0;
201 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
202 free(buf);
203 return 0;
204 }
205 #if defined(AFS_OBSD42_ENV)
206 ifm_fixversion(buf, &needed);
207 #endif
208 lim = buf + needed;
209 next = buf;
210 while (next < lim) {
211 ifm = (struct if_msghdr *)next;
212 if (ifm->ifm_type != RTM_IFINFO) {
213 dpf(("out of sync parsing NET_RT_IFLIST\n"));
214 free(buf);
215 return 0;
216 }
217 next += ifm->ifm_msglen;
218 ifam = NULL;
219 addrcount = 0;
220 while (next < lim) {
221 nextifm = (struct if_msghdr *)next;
222 if (nextifm->ifm_type != RTM_NEWADDR)
223 break;
224 if (ifam == NULL)
225 ifam = (struct ifa_msghdr *)nextifm;
226 addrcount++;
227 next += nextifm->ifm_msglen;
228 }
229 if ((ifm->ifm_flags & IFF_UP) == 0)
230 continue; /* not up */
231 while (addrcount > 0) {
232 struct sockaddr_in *a;
233
234 info.rti_addrs = ifam->ifam_addrs;
235
236 /* Expand the compacted addresses */
237 rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
238 &info);
239 if (info.rti_info[RTAX_IFA]->sa_family != AF_INET) {
240 addrcount--;
241 continue;
242 }
243 a = (struct sockaddr_in *) info.rti_info[RTAX_IFA];
244
245 if (count >= maxSize) /* no more space */
246 dpf(("Too many interfaces..ignoring 0x%x\n",
247 a->sin_addr.s_addr));
248 else if (!loopbacks && rxi_IsLoopbackIface(a, ifm->ifm_flags)) {
249 addrcount--;
250 continue; /* skip loopback address as well. */
251 } else if (loopbacks && ifm->ifm_flags & IFF_LOOPBACK) {
252 addrcount--;
253 continue; /* skip aliased loopbacks as well. */
254 } else
255 buffer[count++] = a->sin_addr.s_addr;
256 addrcount--;
257 ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
258 }
259 }
260 free(buf);
261 return count;
262 }
263
264 int
265 rx_getAllAddrMaskMtu(afs_uint32 addrBuffer[], afs_uint32 maskBuffer[],
266 afs_uint32 mtuBuffer[], int maxSize)
267 {
268 int s;
269
270 size_t needed;
271 int mib[6];
272 struct if_msghdr *ifm, *nextifm;
273 struct ifa_msghdr *ifam;
274 struct sockaddr_dl *sdl;
275 struct rt_addrinfo info;
276 char *buf, *lim, *next;
277 int count = 0, addrcount = 0;
278
279 mib[0] = CTL_NET;
280 mib[1] = PF_ROUTE;
281 mib[2] = 0;
282 mib[3] = AF_INET; /* address family */
283 mib[4] = NET_RT_IFLIST;
284 mib[5] = 0;
285 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
286 return 0;
287 if ((buf = malloc(needed)) == NULL)
288 return 0;
289 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
290 free(buf);
291 return 0;
292 }
293 #if defined(AFS_OBSD42_ENV)
294 ifm_fixversion(buf, &needed);
295 #endif
296 s = socket(PF_INET, SOCK_DGRAM, 0);
297 if (s < 0)
298 return 0;
299 lim = buf + needed;
300 next = buf;
301 while (next < lim) {
302 ifm = (struct if_msghdr *)next;
303 if (ifm->ifm_type != RTM_IFINFO) {
304 dpf(("out of sync parsing NET_RT_IFLIST\n"));
305 free(buf);
306 return 0;
307 }
308 sdl = (struct sockaddr_dl *)(ifm + 1);
309 next += ifm->ifm_msglen;
310 ifam = NULL;
311 addrcount = 0;
312 while (next < lim) {
313 nextifm = (struct if_msghdr *)next;
314 if (nextifm->ifm_type != RTM_NEWADDR)
315 break;
316 if (ifam == NULL)
317 ifam = (struct ifa_msghdr *)nextifm;
318 addrcount++;
319 next += nextifm->ifm_msglen;
320 }
321 if ((ifm->ifm_flags & IFF_UP) == 0)
322 continue; /* not up */
323 while (addrcount > 0) {
324 struct sockaddr_in *a;
325
326 info.rti_addrs = ifam->ifam_addrs;
327
328 /* Expand the compacted addresses */
329 rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
330 &info);
331 if (info.rti_info[RTAX_IFA]->sa_family != AF_INET) {
332 addrcount--;
333 continue;
334 }
335 a = (struct sockaddr_in *) info.rti_info[RTAX_IFA];
336
337 if (!rx_IsLoopbackAddr(ntohl(a->sin_addr.s_addr))) {
338 if (count >= maxSize) { /* no more space */
339 dpf(("Too many interfaces..ignoring 0x%x\n",
340 a->sin_addr.s_addr));
341 } else {
342 struct ifreq ifr;
343
344 addrBuffer[count] = a->sin_addr.s_addr;
345 a = (struct sockaddr_in *) info.rti_info[RTAX_NETMASK];
346 if (a)
347 maskBuffer[count] = a->sin_addr.s_addr;
348 else
349 maskBuffer[count] = htonl(0xffffffff);
350 memset(&ifr, 0, sizeof(ifr));
351 ifr.ifr_addr.sa_family = AF_INET;
352 strncpy(ifr.ifr_name, sdl->sdl_data, sdl->sdl_nlen);
353 if (ioctl(s, SIOCGIFMTU, (caddr_t) & ifr) < 0)
354 mtuBuffer[count] = htonl(1500);
355 else
356 mtuBuffer[count] = htonl(ifr.ifr_mtu);
357 count++;
358 }
359 }
360 addrcount--;
361 ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
362 }
363 }
364 free(buf);
365 return count;
366 }
367
368
369 int
370 rx_getAllAddr(afs_uint32 buffer[], int maxSize)
371 {
372 return rx_getAllAddr_internal(buffer, maxSize, 0);
373 }
374 /* this function returns the total number of interface addresses
375 ** the buffer has to be passed in by the caller
376 */
377 #else /* UKERNEL indirectly, on DARWIN or XBSD */
378 static int
379 rx_getAllAddr_internal(afs_uint32 buffer[], int maxSize, int loopbacks)
380 {
381 int s;
382 int i, len, count = 0;
383 struct ifconf ifc;
384 struct ifreq ifs[NIFS], *ifr;
385 struct sockaddr_in *a;
386 /* can't ever be AFS_DARWIN_ENV or AFS_XBSD_ENV, no? */
387 #if defined(AFS_AIX41_ENV) || defined (AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
388 char *cp, *cplim, *cpnext; /* used only for AIX 41 */
389 #endif
390
391 s = socket(AF_INET, SOCK_DGRAM, 0);
392 if (s < 0)
393 return 0;
394 ifc.ifc_len = sizeof(ifs);
395 ifc.ifc_buf = (caddr_t) ifs;
396 i = ioctl(s, SIOCGIFCONF, &ifc);
397 if (i < 0)
398 return 0;
399 len = ifc.ifc_len / sizeof(struct ifreq);
400 if (len > NIFS)
401 len = NIFS;
402 #if defined(AFS_AIX41_ENV) || defined (AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
403 if (ifc.ifc_len > sizeof(ifs)) /* safety check */
404 ifc.ifc_len = sizeof(ifs);
405 for (cp = (char *)ifc.ifc_buf, cplim = ifc.ifc_buf + ifc.ifc_len;
406 cp < cplim;
407 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
408 cp += _SIZEOF_ADDR_IFREQ(*ifr)
409 #else
410 #ifdef AFS_AIX51_ENV
411 cp = cpnext
412 #else
413 cp += sizeof(ifr->ifr_name) + MAX(a->sin_len, sizeof(*a))
414 #endif
415 #endif
416 )
417 #else
418 for (i = 0; i < len; ++i)
419 #endif
420 {
421 #if defined(AFS_AIX41_ENV) || defined (AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
422 ifr = (struct ifreq *)cp;
423 #else
424 ifr = &ifs[i];
425 #endif
426 a = (struct sockaddr_in *)&ifr->ifr_addr;
427 #ifdef AFS_AIX51_ENV
428 cpnext = cp + sizeof(ifr->ifr_name) + MAX(a->sin_len, sizeof(*a));
429 #endif
430 if (a->sin_family != AF_INET)
431 continue;
432 if (ioctl(s, SIOCGIFFLAGS, ifr) < 0) {
433 perror("SIOCGIFFLAGS");
434 continue; /* ignore this address */
435 }
436 if (a->sin_addr.s_addr != 0) {
437 if (!loopbacks) {
438 if (rxi_IsLoopbackIface(a, ifr->ifr_flags))
439 continue; /* skip loopback address as well. */
440 } else {
441 if (ifr->ifr_flags & IFF_LOOPBACK)
442 continue; /* skip aliased loopbacks as well. */
443 }
444 if (count >= maxSize) /* no more space */
445 dpf(("Too many interfaces..ignoring 0x%x\n",
446 a->sin_addr.s_addr));
447 else
448 buffer[count++] = a->sin_addr.s_addr;
449 }
450 }
451 close(s);
452 return count;
453 }
454
455 int
456 rx_getAllAddr(afs_uint32 buffer[], int maxSize)
457 {
458 return rx_getAllAddr_internal(buffer, maxSize, 0);
459 }
460
461 /* this function returns the total number of interface addresses
462 * the buffer has to be passed in by the caller. It also returns
463 * the interface mask. If AFS_USERSPACE_IP_ADDR is defined, it
464 * gets the mask which is then passed into the kernel and is used
465 * by afsi_SetServerIPRank().
466 */
467 int
468 rx_getAllAddrMaskMtu(afs_uint32 addrBuffer[], afs_uint32 maskBuffer[],
469 afs_uint32 mtuBuffer[], int maxSize)
470 {
471 int i, count = 0;
472 #if defined(AFS_USERSPACE_IP_ADDR)
473 int s, len;
474 struct ifconf ifc;
475 struct ifreq ifs[NIFS], *ifr;
476 struct sockaddr_in *a;
477 #endif
478
479 #if defined(AFS_AIX41_ENV) || defined(AFS_USR_AIX_ENV)
480 char *cp, *cplim; /* used only for AIX 41 */
481 #endif
482
483 #if !defined(AFS_USERSPACE_IP_ADDR)
484 count = rx_getAllAddr_internal(addrBuffer, 1024, 0);
485 for (i = 0; i < count; i++) {
486 maskBuffer[i] = htonl(0xffffffff);
487 mtuBuffer[i] = htonl(1500);
488 }
489 return count;
490 #else /* AFS_USERSPACE_IP_ADDR */
491 s = socket(AF_INET, SOCK_DGRAM, 0);
492 if (s < 0)
493 return 0;
494
495 ifc.ifc_len = sizeof(ifs);
496 ifc.ifc_buf = (caddr_t) ifs;
497 i = ioctl(s, SIOCGIFCONF, &ifc);
498 if (i < 0) {
499 close(s);
500 return 0;
501 }
502 len = ifc.ifc_len / sizeof(struct ifreq);
503 if (len > NIFS)
504 len = NIFS;
505
506 #if defined(AFS_AIX41_ENV) || defined(AFS_USR_AIX_ENV)
507 if (ifc.ifc_len > sizeof(ifs)) /* safety check */
508 ifc.ifc_len = sizeof(ifs);
509 for (cp = (char *)ifc.ifc_buf, cplim = ifc.ifc_buf + ifc.ifc_len;
510 cp < cplim;
511 cp += sizeof(ifr->ifr_name) + MAX(a->sin_len, sizeof(*a))) {
512 ifr = (struct ifreq *)cp;
513 #else
514 for (i = 0; i < len; ++i) {
515 ifr = &ifs[i];
516 #endif
517 a = (struct sockaddr_in *)&ifr->ifr_addr;
518 if (a->sin_addr.s_addr != 0 && a->sin_family == AF_INET) {
519
520 if (ioctl(s, SIOCGIFFLAGS, ifr) < 0) {
521 perror("SIOCGIFFLAGS");
522 continue; /* ignore this address */
523 }
524
525 if (rx_IsLoopbackAddr(ntohl(a->sin_addr.s_addr)))
526 continue; /* skip loopback address as well. */
527
528 if (count >= maxSize) { /* no more space */
529 dpf(("Too many interfaces..ignoring 0x%x\n",
530 a->sin_addr.s_addr));
531 continue;
532 }
533
534 addrBuffer[count] = a->sin_addr.s_addr;
535
536 if (ioctl(s, SIOCGIFNETMASK, (caddr_t) ifr) < 0) {
537 perror("SIOCGIFNETMASK");
538 maskBuffer[count] = htonl(0xffffffff);
539 } else {
540 maskBuffer[count] = (((struct sockaddr_in *)
541 (&ifr->ifr_addr))->sin_addr).s_addr;
542 }
543
544 mtuBuffer[count] = htonl(1500);
545 #ifdef SIOCGIFMTU
546 if (ioctl(s, SIOCGIFMTU, (caddr_t) ifr) < 0) {
547 perror("SIOCGIFMTU");
548 } else {
549 mtuBuffer[count] = htonl(ifr->ifr_metric);
550 }
551 #endif /* SIOCGIFMTU */
552 #ifdef SIOCRIPMTU
553 if (ioctl(s, SIOCRIPMTU, (caddr_t) ifr) < 0) {
554 perror("SIOCRIPMTU");
555 } else {
556 mtuBuffer[count] = htonl(ifr->ifr_metric);
557 }
558 #endif /* SIOCRIPMTU */
559
560 count++;
561 }
562 }
563 close(s);
564 return count;
565 #endif /* AFS_USERSPACE_IP_ADDR */
566 }
567 #endif
568
569 #endif /* ! AFS_NT40_ENV */
570 #endif /* !KERNEL || UKERNEL */