57740e910f5486211e880c5c6327318834bdb195
[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 RCSID
14     ("$Header$");
15
16 #ifndef KERNEL
17 #ifndef AFS_NT40_ENV
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <sys/time.h>
21 #include <net/if.h>
22 #include <netinet/in.h>
23 #include <sys/ioctl.h>
24 #include <string.h>
25 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
26 #include <sys/sysctl.h>
27 #include <net/route.h>
28 #include <net/if_dl.h>
29 #endif
30
31 /*
32  * By including this, we get any system dependencies. In particular,
33  * the pthreads for solaris requires the socket call to be mapped.
34  */
35 #include "rx.h"
36 #include "rx_globals.h"
37 #endif /* AFS_NT40_ENV */
38 #else /* KERNEL */
39 #ifdef UKERNEL
40 #include "rx/rx_kcommon.h"
41 #else /* UKERNEL */
42 #include "rx/rx.h"
43 #endif /* UKERNEL */
44 #endif /* KERNEL */
45
46 #define NIFS            512
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
138 /* this function returns the total number of interface addresses 
139 ** the buffer has to be passed in by the caller
140 */
141 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
142 int
143 rx_getAllAddr_internal(afs_uint32 buffer[], int maxSize, int loopbacks)
144 {
145     size_t needed;
146     int mib[6];
147     struct if_msghdr *ifm, *nextifm;
148     struct ifa_msghdr *ifam;
149     struct sockaddr_dl *sdl;
150     struct rt_addrinfo info;
151     char *buf, *lim, *next;
152     int count = 0, addrcount = 0;
153
154     mib[0] = CTL_NET;
155     mib[1] = PF_ROUTE;
156     mib[2] = 0;
157     mib[3] = AF_INET;           /* address family */
158     mib[4] = NET_RT_IFLIST;
159     mib[5] = 0;
160     if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
161         return 0;
162     if ((buf = malloc(needed)) == NULL)
163         return 0;
164     if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
165         free(buf);
166         return 0;
167     }
168     lim = buf + needed;
169     next = buf;
170     while (next < lim) {
171         ifm = (struct if_msghdr *)next;
172         if (ifm->ifm_type != RTM_IFINFO) {
173             dpf(("out of sync parsing NET_RT_IFLIST\n"));
174             free(buf);
175             return 0;
176         }
177         sdl = (struct sockaddr_dl *)(ifm + 1);
178         next += ifm->ifm_msglen;
179         ifam = NULL;
180         addrcount = 0;
181         while (next < lim) {
182             nextifm = (struct if_msghdr *)next;
183             if (nextifm->ifm_type != RTM_NEWADDR)
184                 break;
185             if (ifam == NULL)
186                 ifam = (struct ifa_msghdr *)nextifm;
187             addrcount++;
188             next += nextifm->ifm_msglen;
189         }
190         if ((ifm->ifm_flags & IFF_UP) == 0)
191             continue;           /* not up */
192         while (addrcount > 0) {
193             struct sockaddr_in *a;
194
195             info.rti_addrs = ifam->ifam_addrs;
196
197             /* Expand the compacted addresses */
198             rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
199                       &info);
200             if (info.rti_info[RTAX_IFA]->sa_family != AF_INET) {
201                 addrcount--;
202                 continue;
203             }
204             a = (struct sockaddr_in *) info.rti_info[RTAX_IFA];
205
206             if (count >= maxSize)       /* no more space */
207                 dpf(("Too many interfaces..ignoring 0x%x\n",
208                        a->sin_addr.s_addr));
209             else if (!loopbacks && a->sin_addr.s_addr == htonl(0x7f000001)) {
210                 addrcount--;
211                 continue;       /* skip loopback address as well. */
212             } else if (loopbacks && ifm->ifm_flags & IFF_LOOPBACK) {
213                 addrcount--;
214                 continue;       /* skip aliased loopbacks as well. */
215             } else
216                 buffer[count++] = a->sin_addr.s_addr;
217             addrcount--;
218             ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
219         }
220     }
221     free(buf);
222     return count;
223 }
224
225 int
226 rxi_getAllAddrMaskMtu(afs_uint32 addrBuffer[], afs_uint32 maskBuffer[],
227                       afs_uint32 mtuBuffer[], int maxSize)
228 {
229     int s;
230
231     size_t needed;
232     int mib[6];
233     struct if_msghdr *ifm, *nextifm;
234     struct ifa_msghdr *ifam;
235     struct sockaddr_dl *sdl;
236     struct rt_addrinfo info;
237     char *buf, *lim, *next;
238     int count = 0, addrcount = 0;
239
240     mib[0] = CTL_NET;
241     mib[1] = PF_ROUTE;
242     mib[2] = 0;
243     mib[3] = AF_INET;           /* address family */
244     mib[4] = NET_RT_IFLIST;
245     mib[5] = 0;
246     if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
247         return 0;
248     if ((buf = malloc(needed)) == NULL)
249         return 0;
250     if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
251         free(buf);
252         return 0;
253     }
254     s = socket(PF_INET, SOCK_DGRAM, 0);
255     if (s < 0)
256         return 0;
257     lim = buf + needed;
258     next = buf;
259     while (next < lim) {
260         ifm = (struct if_msghdr *)next;
261         if (ifm->ifm_type != RTM_IFINFO) {
262             dpf(("out of sync parsing NET_RT_IFLIST\n"));
263             free(buf);
264             return 0;
265         }
266         sdl = (struct sockaddr_dl *)(ifm + 1);
267         next += ifm->ifm_msglen;
268         ifam = NULL;
269         addrcount = 0;
270         while (next < lim) {
271             nextifm = (struct if_msghdr *)next;
272             if (nextifm->ifm_type != RTM_NEWADDR)
273                 break;
274             if (ifam == NULL)
275                 ifam = (struct ifa_msghdr *)nextifm;
276             addrcount++;
277             next += nextifm->ifm_msglen;
278         }
279         if ((ifm->ifm_flags & IFF_UP) == 0)
280             continue;           /* not up */
281         while (addrcount > 0) {
282             struct sockaddr_in *a;
283
284             info.rti_addrs = ifam->ifam_addrs;
285
286             /* Expand the compacted addresses */
287             rt_xaddrs((char *)(ifam + 1), ifam->ifam_msglen + (char *)ifam,
288                       &info);
289             if (info.rti_info[RTAX_IFA]->sa_family != AF_INET) {
290                 addrcount--;
291                 continue;
292             }
293             a = (struct sockaddr_in *) info.rti_info[RTAX_IFA];
294
295             if (a->sin_addr.s_addr != htonl(0x7f000001) ) {
296                 if (count >= maxSize) { /* no more space */
297                     dpf(("Too many interfaces..ignoring 0x%x\n",
298                            a->sin_addr.s_addr));
299                 } else {
300                     struct ifreq ifr;
301                     
302                     addrBuffer[count] = a->sin_addr.s_addr;
303                     a = (struct sockaddr_in *) info.rti_info[RTAX_NETMASK];
304                     if (a)
305                         maskBuffer[count] = a->sin_addr.s_addr;
306                     else
307                         maskBuffer[count] = htonl(0xffffffff);
308                     memset(&ifr, 0, sizeof(ifr));
309                     ifr.ifr_addr.sa_family = AF_INET;
310                     strncpy(ifr.ifr_name, sdl->sdl_data, sdl->sdl_nlen);
311                     if (ioctl(s, SIOCGIFMTU, (caddr_t) & ifr) < 0)
312                         mtuBuffer[count] = htonl(1500);
313                     else
314                         mtuBuffer[count] = htonl(ifr.ifr_mtu);
315                     count++;
316                 }
317             }
318             addrcount--;
319             ifam = (struct ifa_msghdr *)((char *)ifam + ifam->ifam_msglen);
320         }
321     }
322     free(buf);
323     return count;
324 }
325
326
327 int
328 rx_getAllAddr(afs_uint32 buffer[], int maxSize)
329 {
330     return rx_getAllAddr_internal(buffer, maxSize, 0);
331 }
332 /* this function returns the total number of interface addresses
333 ** the buffer has to be passed in by the caller
334 */
335 #else
336 static int
337 rx_getAllAddr_internal(afs_uint32 buffer[], int maxSize, int loopbacks)
338 {
339     int s;
340     int i, len, count = 0;
341     struct ifconf ifc;
342     struct ifreq ifs[NIFS], *ifr;
343     struct sockaddr_in *a;
344 #if    defined(AFS_AIX41_ENV) || defined (AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
345     char *cp, *cplim, *cpnext;  /* used only for AIX 41 */
346 #endif
347
348     s = socket(AF_INET, SOCK_DGRAM, 0);
349     if (s < 0)
350         return 0;
351     ifc.ifc_len = sizeof(ifs);
352     ifc.ifc_buf = (caddr_t) ifs;
353     i = ioctl(s, SIOCGIFCONF, &ifc);
354     if (i < 0)
355         return 0;
356     len = ifc.ifc_len / sizeof(struct ifreq);
357     if (len > NIFS)
358         len = NIFS;
359 #if    defined(AFS_AIX41_ENV) || defined (AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
360     if (ifc.ifc_len > sizeof(ifs))      /* safety check */
361         ifc.ifc_len = sizeof(ifs);
362     for (cp = (char *)ifc.ifc_buf, cplim = ifc.ifc_buf + ifc.ifc_len;
363          cp < cplim;
364 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
365          cp += _SIZEOF_ADDR_IFREQ(*ifr)
366 #else
367 #ifdef AFS_AIX51_ENV
368          cp = cpnext
369 #else
370          cp += sizeof(ifr->ifr_name) + MAX(a->sin_len, sizeof(*a))
371 #endif
372 #endif
373         ) 
374 #else
375     for (i = 0; i < len; ++i) 
376 #endif
377     {
378 #if    defined(AFS_AIX41_ENV) || defined (AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
379         ifr = (struct ifreq *)cp;
380 #else
381         ifr = &ifs[i];
382 #endif
383         a = (struct sockaddr_in *)&ifr->ifr_addr;
384 #ifdef AFS_AIX51_ENV
385         cpnext = cp + sizeof(ifr->ifr_name) + MAX(a->sin_len, sizeof(*a));
386 #endif
387         if (a->sin_family != AF_INET)
388             continue;
389         if (ioctl(s, SIOCGIFFLAGS, ifr) < 0) {
390             perror("SIOCGIFFLAGS");
391             continue;           /* ignore this address */
392         }
393         if (a->sin_addr.s_addr != 0) {
394             if (!loopbacks) {
395                 if (a->sin_addr.s_addr == htonl(0x7f000001)) 
396                     continue;   /* skip loopback address as well. */
397             } else {
398                 if (ifr->ifr_flags & IFF_LOOPBACK) 
399                     continue;   /* skip aliased loopbacks as well. */
400             }
401             if (count >= maxSize)       /* no more space */
402                 dpf(("Too many interfaces..ignoring 0x%x\n",
403                        a->sin_addr.s_addr));
404             else
405                 buffer[count++] = a->sin_addr.s_addr;
406         }
407     }
408     close(s);
409     return count;
410 }
411
412 int
413 rx_getAllAddr(afs_uint32 buffer[], int maxSize)
414 {
415     return rx_getAllAddr_internal(buffer, maxSize, 0);
416 }
417
418 /* this function returns the total number of interface addresses
419  * the buffer has to be passed in by the caller. It also returns
420  * the interface mask. If AFS_USERSPACE_IP_ADDR is defined, it
421  * gets the mask which is then passed into the kernel and is used
422  * by afsi_SetServerIPRank().
423  */
424 int
425 rxi_getAllAddrMaskMtu(afs_uint32 addrBuffer[], afs_uint32 maskBuffer[],
426                       afs_uint32 mtuBuffer[], int maxSize)
427 {
428     int s;
429     int i, len, count = 0;
430     struct ifconf ifc;
431     struct ifreq ifs[NIFS], *ifr;
432     struct sockaddr_in *a;
433 #if     defined(AFS_AIX41_ENV) || defined(AFS_USR_AIX_ENV)
434     char *cp, *cplim;           /* used only for AIX 41 */
435 #endif
436
437 #if !defined(AFS_USERSPACE_IP_ADDR)
438     count = rx_getAllAddr_internal(addrBuffer, 1024, 0);
439     for (i = 0; i < count; i++) {
440         maskBuffer[i] = htonl(0xffffffff);
441         mtuBuffer[i] = htonl(1500);
442     }
443     return count;
444 #else /* AFS_USERSPACE_IP_ADDR */
445     s = socket(AF_INET, SOCK_DGRAM, 0);
446     if (s < 0)
447         return 0;
448
449     ifc.ifc_len = sizeof(ifs);
450     ifc.ifc_buf = (caddr_t) ifs;
451     i = ioctl(s, SIOCGIFCONF, &ifc);
452     if (i < 0) {
453         close(s);
454         return 0;
455     }
456     len = ifc.ifc_len / sizeof(struct ifreq);
457     if (len > NIFS)
458         len = NIFS;
459
460 #if     defined(AFS_AIX41_ENV) || defined(AFS_USR_AIX_ENV)
461     if (ifc.ifc_len > sizeof(ifs))      /* safety check */
462         ifc.ifc_len = sizeof(ifs);
463     for (cp = (char *)ifc.ifc_buf, cplim = ifc.ifc_buf + ifc.ifc_len;
464          cp < cplim;
465          cp += sizeof(ifr->ifr_name) + MAX(a->sin_len, sizeof(*a))) {
466         ifr = (struct ifreq *)cp;
467 #else
468     for (i = 0; i < len; ++i) {
469         ifr = &ifs[i];
470 #endif
471         a = (struct sockaddr_in *)&ifr->ifr_addr;
472         if (a->sin_addr.s_addr != 0 && a->sin_family == AF_INET) {
473
474             if (ioctl(s, SIOCGIFFLAGS, ifr) < 0) {
475                 perror("SIOCGIFFLAGS");
476                 continue;       /* ignore this address */
477             }
478
479             if (a->sin_addr.s_addr == htonl(0x7f000001) )
480                 continue;   /* skip loopback address as well. */
481
482             if (count >= maxSize) {     /* no more space */
483                 dpf(("Too many interfaces..ignoring 0x%x\n",
484                        a->sin_addr.s_addr));
485                 continue;
486             }
487
488             addrBuffer[count] = a->sin_addr.s_addr;
489
490             if (ioctl(s, SIOCGIFNETMASK, (caddr_t) ifr) < 0) {
491                 perror("SIOCGIFNETMASK");
492                 maskBuffer[count] = htonl(0xffffffff);
493             } else {
494                 maskBuffer[count] = (((struct sockaddr_in *)
495                                       (&ifr->ifr_addr))->sin_addr).s_addr;
496             }
497
498             mtuBuffer[count] = htonl(1500);
499 #ifdef SIOCGIFMTU
500             if (ioctl(s, SIOCGIFMTU, (caddr_t) ifr) < 0) {
501                 perror("SIOCGIFMTU");
502             } else {
503                 mtuBuffer[count] = htonl(ifr->ifr_metric);
504             }
505 #endif /* SIOCGIFMTU */
506 #ifdef SIOCRIPMTU
507             if (ioctl(s, SIOCRIPMTU, (caddr_t) ifr) < 0) {
508                 perror("SIOCRIPMTU");
509             } else {
510                 mtuBuffer[count] = htonl(ifr->ifr_metric);
511             }
512 #endif /* SIOCRIPMTU */
513
514             count++;
515         }
516     }
517     close(s);
518     return count;
519 #endif /* AFS_USERSPACE_IP_ADDR */
520 }
521 #endif
522
523 #endif /* ! AFS_NT40_ENV */
524 #endif /* !KERNEL || UKERNEL */