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