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