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