Allow to set correct info level log prefix in duplicates of copy_id21_to_sam_passwd.
[Samba.git] / source / lib / interfaces.c
blob3797fc679dc99bca6e971c4afd2f8b6d5208a300
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
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.
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.
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/>.
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
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.
33 #ifndef AUTOCONF_TEST
34 #include "config.h"
35 #endif
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>
49 #ifdef HAVE_IFADDRS_H
50 #include <ifaddrs.h>
51 #endif
53 #ifdef HAVE_SYS_TIME_H
54 #include <sys/time.h>
55 #endif
57 #ifndef SIOCGIFCONF
58 #ifdef HAVE_SYS_SOCKIO_H
59 #include <sys/sockio.h>
60 #endif
61 #endif
63 #ifdef HAVE_STDLIB_H
64 #include <stdlib.h>
65 #endif
67 #ifdef HAVE_STRING_H
68 #include <string.h>
69 #endif
71 #ifdef HAVE_STRINGS_H
72 #include <strings.h>
73 #endif
75 #ifdef __COMPAR_FN_T
76 #define QSORT_CAST (__compar_fn_t)
77 #endif
79 #ifndef QSORT_CAST
80 #define QSORT_CAST (int (*)(const void *, const void *))
81 #endif
83 #ifdef HAVE_NET_IF_H
84 #include <net/if.h>
85 #endif
87 #define SOCKET_WRAPPER_NOT_REPLACE
88 #include "interfaces.h"
89 #include "lib/replace/replace.h"
91 /****************************************************************************
92 Utility functions.
93 ****************************************************************************/
95 /****************************************************************************
96 Create a struct sockaddr_storage with the netmask bits set to 1.
97 ****************************************************************************/
99 bool make_netmask(struct sockaddr_storage *pss_out,
100 const struct sockaddr_storage *pss_in,
101 unsigned long masklen)
103 *pss_out = *pss_in;
104 /* Now apply masklen bits of mask. */
105 #if defined(HAVE_IPV6)
106 if (pss_in->ss_family == AF_INET6) {
107 char *p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
108 unsigned int i;
110 if (masklen > 128) {
111 return false;
113 for (i = 0; masklen >= 8; masklen -= 8, i++) {
114 *p++ = 0xff;
116 /* Deal with the partial byte. */
117 *p++ &= (0xff & ~(0xff>>masklen));
118 i++;
119 for (;i < sizeof(struct in6_addr); i++) {
120 *p++ = '\0';
122 return true;
124 #endif
125 if (pss_in->ss_family == AF_INET) {
126 if (masklen > 32) {
127 return false;
129 ((struct sockaddr_in *)pss_out)->sin_addr.s_addr =
130 htonl(((0xFFFFFFFFL >> masklen) ^ 0xFFFFFFFFL));
131 return true;
133 return false;
136 /****************************************************************************
137 Create a struct sockaddr_storage set to the broadcast or network adress from
138 an incoming sockaddr_storage.
139 ****************************************************************************/
141 static void make_bcast_or_net(struct sockaddr_storage *pss_out,
142 const struct sockaddr_storage *pss_in,
143 const struct sockaddr_storage *nmask,
144 bool make_bcast_p)
146 unsigned int i = 0, len = 0;
147 char *pmask = NULL;
148 char *p = NULL;
149 *pss_out = *pss_in;
151 /* Set all zero netmask bits to 1. */
152 #if defined(HAVE_IPV6)
153 if (pss_in->ss_family == AF_INET6) {
154 p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
155 pmask = (char *)&((struct sockaddr_in6 *)nmask)->sin6_addr;
156 len = 16;
158 #endif
159 if (pss_in->ss_family == AF_INET) {
160 p = (char *)&((struct sockaddr_in *)pss_out)->sin_addr;
161 pmask = (char *)&((struct sockaddr_in *)nmask)->sin_addr;
162 len = 4;
165 for (i = 0; i < len; i++, p++, pmask++) {
166 if (make_bcast_p) {
167 *p = (*p & *pmask) | (*pmask ^ 0xff);
168 } else {
169 /* make_net */
170 *p = (*p & *pmask);
175 void make_bcast(struct sockaddr_storage *pss_out,
176 const struct sockaddr_storage *pss_in,
177 const struct sockaddr_storage *nmask)
179 make_bcast_or_net(pss_out, pss_in, nmask, true);
182 void make_net(struct sockaddr_storage *pss_out,
183 const struct sockaddr_storage *pss_in,
184 const struct sockaddr_storage *nmask)
186 make_bcast_or_net(pss_out, pss_in, nmask, false);
189 /****************************************************************************
190 Try the "standard" getifaddrs/freeifaddrs interfaces.
191 Also gets IPv6 interfaces.
192 ****************************************************************************/
194 #if HAVE_IFACE_GETIFADDRS
195 /****************************************************************************
196 Get the netmask address for a local interface.
197 ****************************************************************************/
199 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
201 struct ifaddrs *iflist = NULL;
202 struct ifaddrs *ifptr = NULL;
203 int total = 0;
204 size_t copy_size;
206 if (getifaddrs(&iflist) < 0) {
207 return -1;
210 /* Loop through interfaces, looking for given IP address */
211 for (ifptr = iflist, total = 0;
212 ifptr != NULL && total < max_interfaces;
213 ifptr = ifptr->ifa_next) {
215 memset(&ifaces[total], '\0', sizeof(ifaces[total]));
217 copy_size = sizeof(struct sockaddr_in);
219 if (!ifptr->ifa_addr || !ifptr->ifa_netmask) {
220 continue;
223 ifaces[total].flags = ifptr->ifa_flags;
225 /* Check the interface is up. */
226 if (!(ifaces[total].flags & IFF_UP)) {
227 continue;
230 #if defined(HAVE_IPV6)
231 if (ifptr->ifa_addr->sa_family == AF_INET6) {
232 copy_size = sizeof(struct sockaddr_in6);
234 #endif
236 memcpy(&ifaces[total].ip, ifptr->ifa_addr, copy_size);
237 memcpy(&ifaces[total].netmask, ifptr->ifa_netmask, copy_size);
239 if (ifaces[total].flags & (IFF_BROADCAST|IFF_LOOPBACK)) {
240 if (ifptr->ifa_broadaddr) {
241 memcpy(&ifaces[total].bcast,
242 ifptr->ifa_broadaddr,
243 copy_size);
244 } else {
245 /* For some reason ifptr->ifa_broadaddr
246 * is null. Make one from ifa_addr and
247 * ifa_netmask.
249 make_bcast(&ifaces[total].bcast,
250 &ifaces[total].ip,
251 &ifaces[total].netmask);
253 } else if ((ifaces[total].flags & IFF_POINTOPOINT) &&
254 ifptr->ifa_dstaddr ) {
255 memcpy(&ifaces[total].bcast,
256 ifptr->ifa_dstaddr,
257 copy_size);
258 } else {
259 continue;
262 strlcpy(ifaces[total].name, ifptr->ifa_name,
263 sizeof(ifaces[total].name));
264 total++;
267 freeifaddrs(iflist);
269 return total;
272 #define _FOUND_IFACE_ANY
273 #endif /* HAVE_IFACE_GETIFADDRS */
274 #if HAVE_IFACE_IFCONF
276 /* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1
277 V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2.
279 It probably also works on any BSD style system. */
281 /****************************************************************************
282 Get the netmask address for a local interface.
283 ****************************************************************************/
285 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
287 struct ifconf ifc;
288 char buff[8192];
289 int fd, i, n;
290 struct ifreq *ifr=NULL;
291 int total = 0;
293 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
294 return -1;
297 ifc.ifc_len = sizeof(buff);
298 ifc.ifc_buf = buff;
300 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
301 close(fd);
302 return -1;
305 ifr = ifc.ifc_req;
307 n = ifc.ifc_len / sizeof(struct ifreq);
309 /* Loop through interfaces, looking for given IP address */
310 for (i=n-1;i>=0 && total < max_interfaces;i--) {
312 memset(&ifaces[total], '\0', sizeof(ifaces[total]));
314 /* Check the interface is up. */
315 if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) != 0) {
316 continue;
319 ifaces[total].flags = ifr[i].ifr_flags;
321 if (!(ifaces[total].flags & IFF_UP)) {
322 continue;
325 if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != 0) {
326 continue;
329 strlcpy(ifaces[total].name, ifr[i].ifr_name,
330 sizeof(ifaces[total].name));
332 memcpy(&ifaces[total].ip, &ifr[i].ifr_addr,
333 sizeof(struct sockaddr_in));
335 if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != 0) {
336 continue;
339 memcpy(&ifaces[total].netmask, &ifr[i].ifr_netmask,
340 sizeof(struct sockaddr_in));
342 if (ifaces[total].flags & IFF_BROADCAST) {
343 if (ioctl(fd, SIOCGIFBRDADDR, &ifr[i]) != 0) {
344 continue;
346 memcpy(&ifaces[total].bcast, &ifr[i].ifr_broadaddr,
347 sizeof(struct sockaddr_in));
348 } else if (ifaces[total].flags & IFF_POINTOPOINT) {
349 if (ioctl(fd, SIOCGIFDSTADDR, &ifr[i]) != 0) {
350 continue;
352 memcpy(&ifaces[total].bcast, &ifr[i].ifr_dstaddr,
353 sizeof(struct sockaddr_in));
354 } else {
355 continue;
358 total++;
361 close(fd);
363 return total;
366 #define _FOUND_IFACE_ANY
367 #endif /* HAVE_IFACE_IFCONF */
368 #ifdef HAVE_IFACE_IFREQ
370 #ifndef I_STR
371 #include <sys/stropts.h>
372 #endif
374 /****************************************************************************
375 This should cover most of the streams based systems.
376 Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code.
377 ****************************************************************************/
379 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
381 struct ifreq ifreq;
382 struct strioctl strioctl;
383 char buff[8192];
384 int fd, i, n;
385 struct ifreq *ifr=NULL;
386 int total = 0;
388 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
389 return -1;
392 strioctl.ic_cmd = SIOCGIFCONF;
393 strioctl.ic_dp = buff;
394 strioctl.ic_len = sizeof(buff);
395 if (ioctl(fd, I_STR, &strioctl) < 0) {
396 close(fd);
397 return -1;
400 /* we can ignore the possible sizeof(int) here as the resulting
401 number of interface structures won't change */
402 n = strioctl.ic_len / sizeof(struct ifreq);
404 /* we will assume that the kernel returns the length as an int
405 at the start of the buffer if the offered size is a
406 multiple of the structure size plus an int */
407 if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) {
408 ifr = (struct ifreq *)(buff + sizeof(int));
409 } else {
410 ifr = (struct ifreq *)buff;
413 /* Loop through interfaces */
415 for (i = 0; i<n && total < max_interfaces; i++) {
417 memset(&ifaces[total], '\0', sizeof(ifaces[total]));
419 ifreq = ifr[i];
421 strioctl.ic_cmd = SIOCGIFFLAGS;
422 strioctl.ic_dp = (char *)&ifreq;
423 strioctl.ic_len = sizeof(struct ifreq);
424 if (ioctl(fd, I_STR, &strioctl) != 0) {
425 continue;
428 ifaces[total].flags = ifreq.ifr_flags;
430 if (!(ifaces[total].flags & IFF_UP)) {
431 continue;
434 strioctl.ic_cmd = SIOCGIFADDR;
435 strioctl.ic_dp = (char *)&ifreq;
436 strioctl.ic_len = sizeof(struct ifreq);
437 if (ioctl(fd, I_STR, &strioctl) != 0) {
438 continue;
441 strlcpy(ifaces[total].name,
442 ifreq.ifr_name,
443 sizeof(ifaces[total].name));
445 memcpy(&ifaces[total].ip, &ifreq.ifr_addr,
446 sizeof(struct sockaddr_in));
448 strioctl.ic_cmd = SIOCGIFNETMASK;
449 strioctl.ic_dp = (char *)&ifreq;
450 strioctl.ic_len = sizeof(struct ifreq);
451 if (ioctl(fd, I_STR, &strioctl) != 0) {
452 continue;
455 memcpy(&ifaces[total].netmask, &ifreq.ifr_addr,
456 sizeof(struct sockaddr_in));
458 if (ifaces[total].flags & IFF_BROADCAST) {
459 strioctl.ic_cmd = SIOCGIFBRDADDR;
460 strioctl.ic_dp = (char *)&ifreq;
461 strioctl.ic_len = sizeof(struct ifreq);
462 if (ioctl(fd, I_STR, &strioctl) != 0) {
463 continue;
465 memcpy(&ifaces[total].bcast, &ifreq.ifr_broadaddr,
466 sizeof(struct sockaddr_in));
467 } else if (ifaces[total].flags & IFF_POINTOPOINT) {
468 strioctl.ic_cmd = SIOCGIFDSTADDR;
469 strioctl.ic_dp = (char *)&ifreq;
470 strioctl.ic_len = sizeof(struct ifreq);
471 if (ioctl(fd, I_STR, &strioctl) != 0) {
472 continue;
474 memcpy(&ifaces[total].bcast, &ifreq.ifr_dstaddr,
475 sizeof(struct sockaddr_in));
476 } else {
477 continue;
480 total++;
483 close(fd);
485 return total;
488 #define _FOUND_IFACE_ANY
489 #endif /* HAVE_IFACE_IFREQ */
490 #ifdef HAVE_IFACE_AIX
492 /****************************************************************************
493 This one is for AIX (tested on 4.2).
494 ****************************************************************************/
496 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
498 char buff[8192];
499 int fd, i;
500 struct ifconf ifc;
501 struct ifreq *ifr=NULL;
502 int total = 0;
504 if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
505 return -1;
509 ifc.ifc_len = sizeof(buff);
510 ifc.ifc_buf = buff;
512 if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
513 close(fd);
514 return -1;
517 ifr = ifc.ifc_req;
519 /* Loop through interfaces */
520 i = ifc.ifc_len;
522 while (i > 0 && total < max_interfaces) {
523 uint_t inc;
525 memset(&ifaces[total], '\0', sizeof(ifaces[total]));
527 inc = ifr->ifr_addr.sa_len;
529 if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) {
530 goto next;
533 ifaces[total].flags = ifr->ifr_flags;
535 if (!(ifaces[total].flags & IFF_UP)) {
536 goto next;
539 if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
540 goto next;
543 memcpy(&ifaces[total].ip, &ifr->ifr_addr,
544 sizeof(struct sockaddr_in));
546 strlcpy(ifaces[total].name, ifr->ifr_name,
547 sizeof(ifaces[total].name));
549 if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
550 goto next;
553 memcpy(&ifaces[total].netmask, &ifr->ifr_addr,
554 sizeof(struct sockaddr_in));
556 if (ifaces[total].flags & IFF_BROADCAST) {
557 if (ioctl(fd, SIOCGIFBRDADDR, ifr) != 0) {
558 goto next;
560 memcpy(&ifaces[total].bcast, &ifr->ifr_broadaddr,
561 sizeof(struct sockaddr_in));
562 } else if (ifaces[total].flags & IFF_POINTOPOINT) {
563 if (ioctl(fd, SIOCGIFDSTADDR, ifr) != 0) {
564 goto next;
566 memcpy(&ifaces[total].bcast, &ifr->ifr_dstaddr,
567 sizeof(struct sockaddr_in));
568 } else {
569 goto next;
573 total++;
575 next:
577 * Patch from Archie Cobbs (archie@whistle.com). The
578 * addresses in the SIOCGIFCONF interface list have a
579 * minimum size. Usually this doesn't matter, but if
580 * your machine has tunnel interfaces, etc. that have
581 * a zero length "link address", this does matter. */
583 if (inc < sizeof(ifr->ifr_addr))
584 inc = sizeof(ifr->ifr_addr);
585 inc += IFNAMSIZ;
587 ifr = (struct ifreq*) (((char*) ifr) + inc);
588 i -= inc;
591 close(fd);
592 return total;
595 #define _FOUND_IFACE_ANY
596 #endif /* HAVE_IFACE_AIX */
597 #ifndef _FOUND_IFACE_ANY
598 static int _get_interfaces(struct iface_struct *ifaces, int max_interfaces)
600 return -1;
602 #endif
605 static int iface_comp(struct iface_struct *i1, struct iface_struct *i2)
607 int r;
609 #if defined(HAVE_IPV6)
611 * If we have IPv6 - sort these interfaces lower
612 * than any IPv4 ones.
614 if (i1->ip.ss_family == AF_INET6 &&
615 i2->ip.ss_family == AF_INET) {
616 return -1;
617 } else if (i1->ip.ss_family == AF_INET &&
618 i2->ip.ss_family == AF_INET6) {
619 return 1;
622 if (i1->ip.ss_family == AF_INET6) {
623 struct sockaddr_in6 *s1 = (struct sockaddr_in6 *)&i1->ip;
624 struct sockaddr_in6 *s2 = (struct sockaddr_in6 *)&i2->ip;
626 r = memcmp(&s1->sin6_addr,
627 &s2->sin6_addr,
628 sizeof(struct in6_addr));
629 if (r) {
630 return r;
633 s1 = (struct sockaddr_in6 *)&i1->netmask;
634 s2 = (struct sockaddr_in6 *)&i2->netmask;
636 r = memcmp(&s1->sin6_addr,
637 &s2->sin6_addr,
638 sizeof(struct in6_addr));
639 if (r) {
640 return r;
643 #endif
645 /* AIX uses __ss_family instead of ss_family inside of
646 sockaddr_storage. Instead of trying to figure out which field to
647 use, we can just cast it to a sockaddr.
650 if (((struct sockaddr *)&i1->ip)->sa_family == AF_INET) {
651 struct sockaddr_in *s1 = (struct sockaddr_in *)&i1->ip;
652 struct sockaddr_in *s2 = (struct sockaddr_in *)&i2->ip;
654 r = ntohl(s1->sin_addr.s_addr) -
655 ntohl(s2->sin_addr.s_addr);
656 if (r) {
657 return r;
660 s1 = (struct sockaddr_in *)&i1->netmask;
661 s2 = (struct sockaddr_in *)&i2->netmask;
663 return ntohl(s1->sin_addr.s_addr) -
664 ntohl(s2->sin_addr.s_addr);
666 return 0;
669 int get_interfaces(struct iface_struct *ifaces, int max_interfaces);
670 /* this wrapper is used to remove duplicates from the interface list generated
671 above */
672 int get_interfaces(struct iface_struct *ifaces, int max_interfaces)
674 int total, i, j;
676 total = _get_interfaces(ifaces, max_interfaces);
677 if (total <= 0) return total;
679 /* now we need to remove duplicates */
680 qsort(ifaces, total, sizeof(ifaces[0]), QSORT_CAST iface_comp);
682 for (i=1;i<total;) {
683 if (iface_comp(&ifaces[i-1], &ifaces[i]) == 0) {
684 for (j=i-1;j<total-1;j++) {
685 ifaces[j] = ifaces[j+1];
687 total--;
688 } else {
689 i++;
693 return total;
697 #ifdef AUTOCONF_TEST
698 /* this is the autoconf driver to test get_interfaces() */
700 static socklen_t calc_sa_size(struct sockaddr *psa)
702 socklen_t sl = sizeof(struct sockaddr_in);
703 #if defined(HAVE_IPV6)
704 if (psa->sa_family == AF_INET6) {
705 sl = sizeof(struct sockaddr_in6);
707 #endif
708 return sl;
711 int main()
713 struct iface_struct ifaces[MAX_INTERFACES];
714 int total = get_interfaces(ifaces, MAX_INTERFACES);
715 int i;
717 printf("got %d interfaces:\n", total);
718 if (total <= 0) {
719 exit(1);
722 for (i=0;i<total;i++) {
723 char addr[INET6_ADDRSTRLEN];
724 int ret;
725 printf("%-10s ", ifaces[i].name);
726 addr[0] = '\0';
727 ret = getnameinfo((struct sockaddr *)&ifaces[i].ip,
728 calc_sa_size(&ifaces[i].ip),
729 addr, sizeof(addr),
730 NULL, 0, NI_NUMERICHOST);
731 printf("IP=%s ", addr);
732 addr[0] = '\0';
733 ret = getnameinfo((struct sockaddr *)&ifaces[i].netmask,
734 calc_sa_size(&ifaces[i].netmask),
735 addr, sizeof(addr),
736 NULL, 0, NI_NUMERICHOST);
737 printf("NETMASK=%s ", addr);
738 addr[0] = '\0';
739 ret = getnameinfo((struct sockaddr *)&ifaces[i].bcast,
740 calc_sa_size(&ifaces[i].bcast),
741 addr, sizeof(addr),
742 NULL, 0, NI_NUMERICHOST);
743 printf("BCAST=%s\n", addr);
745 return 0;
747 #endif