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