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 Copyright (C) Jelmer Vernooij 2007
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 /* working out the interfaces for a OS is an incredibly non-portable
24 thing. We have several possible implementations below, and autoconf
25 tries each of them to see what works
27 Note that this file does _not_ include includes.h. That is so this code
28 can be called directly from the autoconf tests. That also means
29 this code cannot use any of the normal Samba debug stuff or defines.
30 This is standalone code.
35 #include "system/network.h"
36 #include "interfaces.h"
37 #include "lib/util/tsort.h"
39 /****************************************************************************
40 Create a struct sockaddr_storage with the netmask bits set to 1.
41 ****************************************************************************/
43 bool make_netmask(struct sockaddr_storage *pss_out,
44 const struct sockaddr_storage *pss_in,
45 unsigned long masklen)
48 /* Now apply masklen bits of mask. */
49 #if defined(HAVE_IPV6)
50 if (pss_in->ss_family == AF_INET6) {
51 char *p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
57 for (i = 0; masklen >= 8; masklen -= 8, i++) {
60 /* Deal with the partial byte. */
61 *p++ &= (0xff & ~(0xff>>masklen));
63 for (;i < sizeof(struct in6_addr); i++) {
69 if (pss_in->ss_family == AF_INET) {
73 ((struct sockaddr_in *)pss_out)->sin_addr.s_addr =
74 htonl(((0xFFFFFFFFL >> masklen) ^ 0xFFFFFFFFL));
80 /****************************************************************************
81 Create a struct sockaddr_storage set to the broadcast or network adress from
82 an incoming sockaddr_storage.
83 ****************************************************************************/
85 static void make_bcast_or_net(struct sockaddr_storage *pss_out,
86 const struct sockaddr_storage *pss_in,
87 const struct sockaddr_storage *nmask,
90 unsigned int i = 0, len = 0;
95 /* Set all zero netmask bits to 1. */
96 #if defined(HAVE_IPV6)
97 if (pss_in->ss_family == AF_INET6) {
98 p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
99 pmask = discard_const_p(char, &((struct sockaddr_in6 *)nmask)->sin6_addr);
103 if (pss_in->ss_family == AF_INET) {
104 p = (char *)&((struct sockaddr_in *)pss_out)->sin_addr;
105 pmask = discard_const_p(char, &((struct sockaddr_in *)nmask)->sin_addr);
109 for (i = 0; i < len; i++, p++, pmask++) {
111 *p = (*p & *pmask) | (*pmask ^ 0xff);
119 void make_bcast(struct sockaddr_storage *pss_out,
120 const struct sockaddr_storage *pss_in,
121 const struct sockaddr_storage *nmask)
123 make_bcast_or_net(pss_out, pss_in, nmask, true);
126 void make_net(struct sockaddr_storage *pss_out,
127 const struct sockaddr_storage *pss_in,
128 const struct sockaddr_storage *nmask)
130 make_bcast_or_net(pss_out, pss_in, nmask, false);
134 /****************************************************************************
135 Try the "standard" getifaddrs/freeifaddrs interfaces.
136 Also gets IPv6 interfaces.
137 ****************************************************************************/
139 /****************************************************************************
140 Get the netmask address for a local interface.
141 ****************************************************************************/
143 static int _get_interfaces(TALLOC_CTX *mem_ctx, struct iface_struct **pifaces)
145 struct iface_struct *ifaces;
146 struct ifaddrs *iflist = NULL;
147 struct ifaddrs *ifptr = NULL;
152 if (getifaddrs(&iflist) < 0) {
157 for (ifptr = iflist; ifptr != NULL; ifptr = ifptr->ifa_next) {
158 if (!ifptr->ifa_addr || !ifptr->ifa_netmask) {
161 if (!(ifptr->ifa_flags & IFF_UP)) {
167 ifaces = talloc_array(mem_ctx, struct iface_struct, count);
168 if (ifaces == NULL) {
173 /* Loop through interfaces, looking for given IP address */
174 for (ifptr = iflist; ifptr != NULL; ifptr = ifptr->ifa_next) {
176 if (!ifptr->ifa_addr || !ifptr->ifa_netmask) {
180 /* Check the interface is up. */
181 if (!(ifptr->ifa_flags & IFF_UP)) {
185 memset(&ifaces[total], '\0', sizeof(ifaces[total]));
187 copy_size = sizeof(struct sockaddr_in);
189 ifaces[total].flags = ifptr->ifa_flags;
191 #if defined(HAVE_IPV6)
192 if (ifptr->ifa_addr->sa_family == AF_INET6) {
193 copy_size = sizeof(struct sockaddr_in6);
197 memcpy(&ifaces[total].ip, ifptr->ifa_addr, copy_size);
198 memcpy(&ifaces[total].netmask, ifptr->ifa_netmask, copy_size);
200 if (ifaces[total].flags & (IFF_BROADCAST|IFF_LOOPBACK)) {
201 make_bcast(&ifaces[total].bcast,
203 &ifaces[total].netmask);
204 } else if ((ifaces[total].flags & IFF_POINTOPOINT) &&
205 ifptr->ifa_dstaddr ) {
206 memcpy(&ifaces[total].bcast,
213 strlcpy(ifaces[total].name, ifptr->ifa_name,
214 sizeof(ifaces[total].name));
224 static int iface_comp(struct iface_struct *i1, struct iface_struct *i2)
228 #if defined(HAVE_IPV6)
230 * If we have IPv6 - sort these interfaces lower
231 * than any IPv4 ones.
233 if (i1->ip.ss_family == AF_INET6 &&
234 i2->ip.ss_family == AF_INET) {
236 } else if (i1->ip.ss_family == AF_INET &&
237 i2->ip.ss_family == AF_INET6) {
241 if (i1->ip.ss_family == AF_INET6) {
242 struct sockaddr_in6 *s1 = (struct sockaddr_in6 *)&i1->ip;
243 struct sockaddr_in6 *s2 = (struct sockaddr_in6 *)&i2->ip;
245 r = memcmp(&s1->sin6_addr,
247 sizeof(struct in6_addr));
252 s1 = (struct sockaddr_in6 *)&i1->netmask;
253 s2 = (struct sockaddr_in6 *)&i2->netmask;
255 r = memcmp(&s1->sin6_addr,
257 sizeof(struct in6_addr));
264 /* AIX uses __ss_family instead of ss_family inside of
265 sockaddr_storage. Instead of trying to figure out which field to
266 use, we can just cast it to a sockaddr.
269 if (((struct sockaddr *)&i1->ip)->sa_family == AF_INET) {
270 struct sockaddr_in *s1 = (struct sockaddr_in *)&i1->ip;
271 struct sockaddr_in *s2 = (struct sockaddr_in *)&i2->ip;
273 r = ntohl(s1->sin_addr.s_addr) -
274 ntohl(s2->sin_addr.s_addr);
279 s1 = (struct sockaddr_in *)&i1->netmask;
280 s2 = (struct sockaddr_in *)&i2->netmask;
282 return ntohl(s1->sin_addr.s_addr) -
283 ntohl(s2->sin_addr.s_addr);
288 /* this wrapper is used to remove duplicates from the interface list generated
290 int get_interfaces(TALLOC_CTX *mem_ctx, struct iface_struct **pifaces)
292 struct iface_struct *ifaces;
295 total = _get_interfaces(mem_ctx, &ifaces);
296 if (total <= 0) return total;
298 /* now we need to remove duplicates */
299 TYPESAFE_QSORT(ifaces, total, iface_comp);
302 if (iface_comp(&ifaces[i-1], &ifaces[i]) == 0) {
303 for (j=i-1;j<total-1;j++) {
304 ifaces[j] = ifaces[j+1];