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