Two patches
[ira/wip.git] / source3 / lib / interfaces.c
1 /*
2    Unix SMB/CIFS implementation.
3    return a list of network interfaces
4    Copyright (C) Andrew Tridgell 1998
5    Copyright (C) Jeremy Allison 2007
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21
22 /* working out the interfaces for a OS is an incredibly non-portable
23    thing. We have several possible implementations below, and autoconf
24    tries each of them to see what works
25
26    Note that this file does _not_ include includes.h. That is so this code
27    can be called directly from the autoconf tests. That also means
28    this code cannot use any of the normal Samba debug stuff or defines.
29    This is standalone code.
30
31 */
32
33 #ifndef AUTOCONF_TEST
34 #include "config.h"
35 #endif
36
37 #include <unistd.h>
38 #include <stdio.h>
39 #include <sys/types.h>
40 #include <netdb.h>
41 #include <sys/ioctl.h>
42 #include <netdb.h>
43 #include <sys/ioctl.h>
44 #include <sys/time.h>
45 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48
49 #ifdef HAVE_IFADDRS_H
50 #include <ifaddrs.h>
51 #endif
52
53 #ifdef HAVE_SYS_TIME_H
54 #include <sys/time.h>
55 #endif
56
57 #ifndef SIOCGIFCONF
58 #ifdef HAVE_SYS_SOCKIO_H
59 #include <sys/sockio.h>
60 #endif
61 #endif
62
63 #ifdef HAVE_STDLIB_H
64 #include <stdlib.h>
65 #endif
66
67 #ifdef HAVE_STRING_H
68 #include <string.h>
69 #endif
70
71 #ifdef HAVE_STRINGS_H
72 #include <strings.h>
73 #endif
74
75 #ifdef __COMPAR_FN_T
76 #define QSORT_CAST (__compar_fn_t)
77 #endif
78
79 #ifndef QSORT_CAST
80 #define QSORT_CAST (int (*)(const void *, const void *))
81 #endif
82
83 #ifdef HAVE_NET_IF_H
84 #include <net/if.h>
85 #endif
86
87 #include "interfaces.h"
88 #include "lib/replace/replace.h"
89
90 /****************************************************************************
91  Utility functions.
92 ****************************************************************************/
93
94 /****************************************************************************
95  Create a struct sockaddr_storage with the netmask bits set to 1.
96 ****************************************************************************/
97
98 bool make_netmask(struct sockaddr_storage *pss_out,
99                         const struct sockaddr_storage *pss_in,
100                         unsigned long masklen)
101 {
102         *pss_out = *pss_in;
103         /* Now apply masklen bits of mask. */
104 #if defined(HAVE_IPV6)
105         if (pss_in->ss_family == AF_INET6) {
106                 char *p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
107                 unsigned int i;
108
109                 if (masklen > 128) {
110                         return false;
111                 }
112                 for (i = 0; masklen >= 8; masklen -= 8, i++) {
113                         *p++ = 0xff;
114                 }
115                 /* Deal with the partial byte. */
116                 *p++ &= (0xff & ~(0xff>>masklen));
117                 i++;
118                 for (;i < sizeof(struct in6_addr); i++) {
119                         *p++ = '\0';
120                 }
121                 return true;
122         }
123 #endif
124         if (pss_in->ss_family == AF_INET) {
125                 if (masklen > 32) {
126                         return false;
127                 }
128                 ((struct sockaddr_in *)pss_out)->sin_addr.s_addr =
129                         htonl(((0xFFFFFFFFL >> masklen) ^ 0xFFFFFFFFL));
130                 return true;
131         }
132         return false;
133 }
134
135 /****************************************************************************
136  Create a struct sockaddr_storage set to the broadcast or network adress from
137  an incoming sockaddr_storage.
138 ****************************************************************************/
139
140 static void make_bcast_or_net(struct sockaddr_storage *pss_out,
141                         const struct sockaddr_storage *pss_in,
142                         const struct sockaddr_storage *nmask,
143                         bool make_bcast_p)
144 {
145         unsigned int i = 0, len = 0;
146         char *pmask = NULL;
147         char *p = NULL;
148         *pss_out = *pss_in;
149
150         /* Set all zero netmask bits to 1. */
151 #if defined(HAVE_IPV6)
152         if (pss_in->ss_family == AF_INET6) {
153                 p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
154                 pmask = (char *)&((struct sockaddr_in6 *)nmask)->sin6_addr;
155                 len = 16;
156         }
157 #endif
158         if (pss_in->ss_family == AF_INET) {
159                 p = (char *)&((struct sockaddr_in *)pss_out)->sin_addr;
160                 pmask = (char *)&((struct sockaddr_in *)nmask)->sin_addr;
161                 len = 4;
162         }
163
164         for (i = 0; i < len; i++, p++, pmask++) {
165                 if (make_bcast_p) {
166                         *p = (*p & *pmask) | (*pmask ^ 0xff);
167                 } else {
168                         /* make_net */
169                         *p = (*p & *pmask);
170                 }
171         }
172 }
173
174 void make_bcast(struct sockaddr_storage *pss_out,
175                         const struct sockaddr_storage *pss_in,
176                         const struct sockaddr_storage *nmask)
177 {
178         make_bcast_or_net(pss_out, pss_in, nmask, true);
179 }
180
181 void make_net(struct sockaddr_storage *pss_out,
182                         const struct sockaddr_storage *pss_in,
183                         const struct sockaddr_storage *nmask)
184 {
185         make_bcast_or_net(pss_out, pss_in, nmask, false);
186 }
187
188 /****************************************************************************
189  Try the "standard" getifaddrs/freeifaddrs interfaces.
190  Also gets IPv6 interfaces.
191 ****************************************************************************/
192
193 #if HAVE_IFACE_GETIFADDRS
194 /****************************************************************************
195  Get the netmask address for a local interface.
196 ****************************************************************************/
197
198 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
199 {
200         struct ifaddrs *iflist = NULL;
201         struct ifaddrs *ifptr = NULL;
202         int total = 0;
203         size_t copy_size;
204
205         if (getifaddrs(&iflist) < 0) {
206                 return -1;
207         }
208
209         /* Loop through interfaces, looking for given IP address */
210         for (ifptr = iflist, total = 0;
211                         ifptr != NULL && total < max_interfaces;
212                         ifptr = ifptr->ifa_next) {
213
214                 memset(&ifaces[total], '\0', sizeof(ifaces[total]));
215
216                 copy_size = sizeof(struct sockaddr_in);
217
218                 if (!ifptr->ifa_addr || !ifptr->ifa_netmask) {
219                         continue;
220                 }
221
222                 ifaces[total].flags = ifptr->ifa_flags;
223
224                 /* Check the interface is up. */
225                 if (!(ifaces[total].flags & IFF_UP)) {
226                         continue;
227                 }
228
229 #if defined(HAVE_IPV6)
230                 if (ifptr->ifa_addr->sa_family == AF_INET6) {
231                         copy_size = sizeof(struct sockaddr_in6);
232                 }
233 #endif
234
235                 memcpy(&ifaces[total].ip, ifptr->ifa_addr, copy_size);
236                 memcpy(&ifaces[total].netmask, ifptr->ifa_netmask, copy_size);
237
238                 if (ifaces[total].flags & (IFF_BROADCAST|IFF_LOOPBACK)) {
239                         if (ifptr->ifa_broadaddr) {
240                                 memcpy(&ifaces[total].bcast,
241                                         ifptr->ifa_broadaddr,
242                                         copy_size);
243                         } else {
244                                 /* For some reason ifptr->ifa_broadaddr
245                                  * is null. Make one from ifa_addr and
246                                  * ifa_netmask.
247                                  */
248                                 make_bcast(&ifaces[total].bcast,
249                                         &ifaces[total].ip,
250                                         &ifaces[total].netmask);
251                         }
252                 } else if ((ifaces[total].flags & IFF_POINTOPOINT) &&
253                                ifptr->ifa_dstaddr ) {
254                         memcpy(&ifaces[total].bcast,
255                                 ifptr->ifa_dstaddr,
256                                 copy_size);
257                 } else {
258                         continue;
259                 }
260
261                 strlcpy(ifaces[total].name, ifptr->ifa_name,
262                         sizeof(ifaces[total].name));
263                 total++;
264         }
265
266         freeifaddrs(iflist);
267
268         return total;
269 }
270
271 #define _FOUND_IFACE_ANY
272 #endif /* HAVE_IFACE_GETIFADDRS */
273 #if HAVE_IFACE_IFCONF
274
275 /* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1
276    V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2.
277
278    It probably also works on any BSD style system.  */
279
280 /****************************************************************************
281  Get the netmask address for a local interface.
282 ****************************************************************************/
283
284 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
285 {
286         struct ifconf ifc;
287         char buff[8192];
288         int fd, i, n;
289         struct ifreq *ifr=NULL;
290         int total = 0;
291
292         if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
293                 return -1;
294         }
295
296         ifc.ifc_len = sizeof(buff);
297         ifc.ifc_buf = buff;
298
299         if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
300                 close(fd);
301                 return -1;
302         }
303
304         ifr = ifc.ifc_req;
305
306         n = ifc.ifc_len / sizeof(struct ifreq);
307
308         /* Loop through interfaces, looking for given IP address */
309         for (i=n-1;i>=0 && total < max_interfaces;i--) {
310
311                 memset(&ifaces[total], '\0', sizeof(ifaces[total]));
312
313                 /* Check the interface is up. */
314                 if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) != 0) {
315                         continue;
316                 }
317
318                 ifaces[total].flags = ifr[i].ifr_flags;
319
320                 if (!(ifaces[total].flags & IFF_UP)) {
321                         continue;
322                 }
323
324                 if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != 0) {
325                         continue;
326                 }
327
328                 strlcpy(ifaces[total].name, ifr[i].ifr_name,
329                         sizeof(ifaces[total].name));
330
331                 memcpy(&ifaces[total].ip, &ifr[i].ifr_addr,
332                                 sizeof(struct sockaddr_in));
333
334                 if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != 0) {
335                         continue;
336                 }
337
338                 memcpy(&ifaces[total].netmask, &ifr[i].ifr_netmask,
339                                 sizeof(struct sockaddr_in));
340
341                 if (ifaces[total].flags & IFF_BROADCAST) {
342                         if (ioctl(fd, SIOCGIFBRDADDR, &ifr[i]) != 0) {
343                                 continue;
344                         }
345                         memcpy(&ifaces[total].bcast, &ifr[i].ifr_broadaddr,
346                                 sizeof(struct sockaddr_in));
347                 } else if (ifaces[total].flags & IFF_POINTOPOINT) {
348                         if (ioctl(fd, SIOCGIFDSTADDR, &ifr[i]) != 0) {
349                                 continue;
350                         }
351                         memcpy(&ifaces[total].bcast, &ifr[i].ifr_dstaddr,
352                                 sizeof(struct sockaddr_in));
353                 } else {
354                         continue;
355                 }
356
357                 total++;
358         }
359
360         close(fd);
361
362         return total;
363 }
364
365 #define _FOUND_IFACE_ANY
366 #endif /* HAVE_IFACE_IFCONF */
367 #ifdef HAVE_IFACE_IFREQ
368
369 #ifndef I_STR
370 #include <sys/stropts.h>
371 #endif
372
373 /****************************************************************************
374  This should cover most of the streams based systems.
375  Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code.
376 ****************************************************************************/
377
378 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
379 {
380         struct ifreq ifreq;
381         struct strioctl strioctl;
382         char buff[8192];
383         int fd, i, n;
384         struct ifreq *ifr=NULL;
385         int total = 0;
386
387         if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
388                 return -1;
389         }
390
391         strioctl.ic_cmd = SIOCGIFCONF;
392         strioctl.ic_dp  = buff;
393         strioctl.ic_len = sizeof(buff);
394         if (ioctl(fd, I_STR, &strioctl) < 0) {
395                 close(fd);
396                 return -1;
397         }
398
399         /* we can ignore the possible sizeof(int) here as the resulting
400            number of interface structures won't change */
401         n = strioctl.ic_len / sizeof(struct ifreq);
402
403         /* we will assume that the kernel returns the length as an int
404            at the start of the buffer if the offered size is a
405            multiple of the structure size plus an int */
406         if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) {
407                 ifr = (struct ifreq *)(buff + sizeof(int));
408         } else {
409                 ifr = (struct ifreq *)buff;
410         }
411
412         /* Loop through interfaces */
413
414         for (i = 0; i<n && total < max_interfaces; i++) {
415
416                 memset(&ifaces[total], '\0', sizeof(ifaces[total]));
417
418                 ifreq = ifr[i];
419
420                 strioctl.ic_cmd = SIOCGIFFLAGS;
421                 strioctl.ic_dp  = (char *)&ifreq;
422                 strioctl.ic_len = sizeof(struct ifreq);
423                 if (ioctl(fd, I_STR, &strioctl) != 0) {
424                         continue;
425                 }
426
427                 ifaces[total].flags = ifreq.ifr_flags;
428
429                 if (!(ifaces[total].flags & IFF_UP)) {
430                         continue;
431                 }
432
433                 strioctl.ic_cmd = SIOCGIFADDR;
434                 strioctl.ic_dp  = (char *)&ifreq;
435                 strioctl.ic_len = sizeof(struct ifreq);
436                 if (ioctl(fd, I_STR, &strioctl) != 0) {
437                         continue;
438                 }
439
440                 strlcpy(ifaces[total].name,
441                                 ifreq.ifr_name,
442                                 sizeof(ifaces[total].name));
443
444                 memcpy(&ifaces[total].ip, &ifreq.ifr_addr,
445                                 sizeof(struct sockaddr_in));
446
447                 strioctl.ic_cmd = SIOCGIFNETMASK;
448                 strioctl.ic_dp  = (char *)&ifreq;
449                 strioctl.ic_len = sizeof(struct ifreq);
450                 if (ioctl(fd, I_STR, &strioctl) != 0) {
451                         continue;
452                 }
453
454                 memcpy(&ifaces[total].netmask, &ifreq.ifr_addr,
455                                 sizeof(struct sockaddr_in));
456
457                 if (ifaces[total].flags & IFF_BROADCAST) {
458                         strioctl.ic_cmd = SIOCGIFBRDADDR;
459                         strioctl.ic_dp  = (char *)&ifreq;
460                         strioctl.ic_len = sizeof(struct ifreq);
461                         if (ioctl(fd, I_STR, &strioctl) != 0) {
462                                 continue;
463                         }
464                         memcpy(&ifaces[total].bcast, &ifreq.ifr_broadaddr,
465                                 sizeof(struct sockaddr_in));
466                 } else if (ifaces[total].flags & IFF_POINTOPOINT) {
467                         strioctl.ic_cmd = SIOCGIFDSTADDR;
468                         strioctl.ic_dp  = (char *)&ifreq;
469                         strioctl.ic_len = sizeof(struct ifreq);
470                         if (ioctl(fd, I_STR, &strioctl) != 0) {
471                                 continue;
472                         }
473                         memcpy(&ifaces[total].bcast, &ifreq.ifr_dstaddr,
474                                 sizeof(struct sockaddr_in));
475                 } else {
476                         continue;
477                 }
478
479                 total++;
480         }
481
482         close(fd);
483
484         return total;
485 }
486
487 #define _FOUND_IFACE_ANY
488 #endif /* HAVE_IFACE_IFREQ */
489 #ifdef HAVE_IFACE_AIX
490
491 /****************************************************************************
492  This one is for AIX (tested on 4.2).
493 ****************************************************************************/
494
495 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
496 {
497         char buff[8192];
498         int fd, i;
499         struct ifconf ifc;
500         struct ifreq *ifr=NULL;
501         int total = 0;
502
503         if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
504                 return -1;
505         }
506
507
508         ifc.ifc_len = sizeof(buff);
509         ifc.ifc_buf = buff;
510
511         if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
512                 close(fd);
513                 return -1;
514         }
515
516         ifr = ifc.ifc_req;
517
518         /* Loop through interfaces */
519         i = ifc.ifc_len;
520
521         while (i > 0 && total < max_interfaces) {
522                 uint_t inc;
523
524                 memset(&ifaces[total], '\0', sizeof(ifaces[total]));
525
526                 inc = ifr->ifr_addr.sa_len;
527
528                 if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
529                         goto next;
530                 }
531
532                 ifaces[total].flags = ifr->ifr_flags;
533
534                 if (!(ifaces[total].flags & IFF_UP)) {
535                         goto next;
536                 }
537
538                 if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
539                         goto next;
540                 }
541
542                 memcpy(&ifaces[total].ip, &ifr->ifr_addr,
543                                 sizeof(struct sockaddr_in));
544
545                 strlcpy(ifaces[total].name, ifr->ifr_name,
546                         sizeof(ifaces[total].name));
547
548                 if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
549                         goto next;
550                 }
551
552                 memcpy(&ifaces[total].netmask, &ifr->ifr_addr,
553                                 sizeof(struct sockaddr_in));
554
555                 if (ifaces[total].flags & IFF_BROADCAST) {
556                         if (ioctl(fd, SIOCGIFBRDADDR, ifr) != 0) {
557                                 goto next;
558                         }
559                         memcpy(&ifaces[total].bcast, &ifr->ifr_broadaddr,
560                                 sizeof(struct sockaddr_in));
561                 } else if (ifaces[total].flags & IFF_POINTOPOINT) {
562                         if (ioctl(fd, SIOCGIFDSTADDR, ifr) != 0) {
563                                 goto next;
564                         }
565                         memcpy(&ifaces[total].bcast, &ifr->ifr_dstaddr,
566                                 sizeof(struct sockaddr_in));
567                 } else {
568                         goto next;
569                 }
570
571
572                 total++;
573
574         next:
575                 /*
576                  * Patch from Archie Cobbs (archie@whistle.com).  The
577                  * addresses in the SIOCGIFCONF interface list have a
578                  * minimum size. Usually this doesn't matter, but if
579                  * your machine has tunnel interfaces, etc. that have
580                  * a zero length "link address", this does matter.  */
581
582                 if (inc < sizeof(ifr->ifr_addr))
583                         inc = sizeof(ifr->ifr_addr);
584                 inc += IFNAMSIZ;
585
586                 ifr = (struct ifreq*) (((char*) ifr) + inc);
587                 i -= inc;
588         }
589
590         close(fd);
591         return total;
592 }
593
594 #define _FOUND_IFACE_ANY
595 #endif /* HAVE_IFACE_AIX */
596 #ifndef _FOUND_IFACE_ANY
597 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
598 {
599         return -1;
600 }
601 #endif
602
603
604 static int iface_comp(struct iface_struct *i1, struct iface_struct *i2)
605 {
606         int r;
607
608 #if defined(HAVE_IPV6)
609         /*
610          * If we have IPv6 - sort these interfaces lower
611          * than any IPv4 ones.
612          */
613         if (i1->ip.ss_family == AF_INET6 &&
614                         i2->ip.ss_family == AF_INET) {
615                 return -1;
616         } else if (i1->ip.ss_family == AF_INET &&
617                         i2->ip.ss_family == AF_INET6) {
618                 return 1;
619         }
620
621         if (i1->ip.ss_family == AF_INET6) {
622                 struct sockaddr_in6 *s1 = (struct sockaddr_in6 *)&i1->ip;
623                 struct sockaddr_in6 *s2 = (struct sockaddr_in6 *)&i2->ip;
624
625                 r = memcmp(&s1->sin6_addr,
626                                 &s2->sin6_addr,
627                                 sizeof(struct in6_addr));
628                 if (r) {
629                         return r;
630                 }
631
632                 s1 = (struct sockaddr_in6 *)&i1->netmask;
633                 s2 = (struct sockaddr_in6 *)&i2->netmask;
634
635                 r = memcmp(&s1->sin6_addr,
636                                 &s2->sin6_addr,
637                                 sizeof(struct in6_addr));
638                 if (r) {
639                         return r;
640                 }
641         }
642 #endif
643
644         /* AIX uses __ss_family instead of ss_family inside of
645            sockaddr_storage. Instead of trying to figure out which field to
646            use, we can just cast it to a sockaddr.
647          */
648
649         if (((struct sockaddr *)&i1->ip)->sa_family == AF_INET) {
650                 struct sockaddr_in *s1 = (struct sockaddr_in *)&i1->ip;
651                 struct sockaddr_in *s2 = (struct sockaddr_in *)&i2->ip;
652
653                 r = ntohl(s1->sin_addr.s_addr) -
654                         ntohl(s2->sin_addr.s_addr);
655                 if (r) {
656                         return r;
657                 }
658
659                 s1 = (struct sockaddr_in *)&i1->netmask;
660                 s2 = (struct sockaddr_in *)&i2->netmask;
661
662                 return ntohl(s1->sin_addr.s_addr) -
663                         ntohl(s2->sin_addr.s_addr);
664         }
665         return 0;
666 }
667
668 int get_interfaces(struct iface_struct *ifaces, int max_interfaces);
669 /* this wrapper is used to remove duplicates from the interface list generated
670    above */
671 int get_interfaces(struct iface_struct *ifaces, int max_interfaces)
672 {
673         int total, i, j;
674
675         total = _get_interfaces(ifaces, max_interfaces);
676         if (total <= 0) return total;
677
678         /* now we need to remove duplicates */
679         qsort(ifaces, total, sizeof(ifaces[0]), QSORT_CAST iface_comp);
680
681         for (i=1;i<total;) {
682                 if (iface_comp(&ifaces[i-1], &ifaces[i]) == 0) {
683                         for (j=i-1;j<total-1;j++) {
684                                 ifaces[j] = ifaces[j+1];
685                         }
686                         total--;
687                 } else {
688                         i++;
689                 }
690         }
691
692         return total;
693 }
694
695
696 #ifdef AUTOCONF_TEST
697 /* this is the autoconf driver to test get_interfaces() */
698
699  int main()
700 {
701         struct iface_struct ifaces[MAX_INTERFACES];
702         int total = get_interfaces(ifaces, MAX_INTERFACES);
703         int i;
704
705         printf("got %d interfaces:\n", total);
706         if (total <= 0) {
707                 exit(1);
708         }
709
710         for (i=0;i<total;i++) {
711                 char addr[INET6_ADDRSTRLEN];
712                 int ret;
713                 printf("%-10s ", ifaces[i].name);
714                 addr[0] = '\0';
715                 ret = getnameinfo((struct sockaddr *)&ifaces[i].ip,
716                                 sizeof(ifaces[i].ip),
717                                 addr, sizeof(addr),
718                                 NULL, 0, NI_NUMERICHOST);
719                 printf("IP=%s ", addr);
720                 addr[0] = '\0';
721                 ret = getnameinfo((struct sockaddr *)&ifaces[i].netmask,
722                                 sizeof(ifaces[i].netmask),
723                                 addr, sizeof(addr),
724                                 NULL, 0, NI_NUMERICHOST);
725                 printf("NETMASK=%s ", addr);
726                 addr[0] = '\0';
727                 ret = getnameinfo((struct sockaddr *)&ifaces[i].bcast,
728                                 sizeof(ifaces[i].bcast),
729                                 addr, sizeof(addr),
730                                 NULL, 0, NI_NUMERICHOST);
731                 printf("BCAST=%s\n", addr);
732         }
733         return 0;
734 }
735 #endif