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.
39 #include <sys/types.h>
41 #include <sys/ioctl.h>
43 #include <sys/ioctl.h>
45 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
53 #ifdef HAVE_SYS_TIME_H
58 #ifdef HAVE_SYS_SOCKIO_H
59 #include <sys/sockio.h>
76 #define QSORT_CAST (__compar_fn_t)
80 #define QSORT_CAST (int (*)(const void *, const void *))
87 #define SOCKET_WRAPPER_NOT_REPLACE
88 #include "interfaces.h"
89 #include "lib/replace/replace.h"
91 /****************************************************************************
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
)
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
;
113 for (i
= 0; masklen
>= 8; masklen
-= 8, i
++) {
116 /* Deal with the partial byte. */
117 *p
++ &= (0xff & ~(0xff>>masklen
));
119 for (;i
< sizeof(struct in6_addr
); i
++) {
125 if (pss_in
->ss_family
== AF_INET
) {
129 ((struct sockaddr_in
*)pss_out
)->sin_addr
.s_addr
=
130 htonl(((0xFFFFFFFFL
>> masklen
) ^ 0xFFFFFFFFL
));
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
,
146 unsigned int i
= 0, len
= 0;
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
;
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
;
165 for (i
= 0; i
< len
; i
++, p
++, pmask
++) {
167 *p
= (*p
& *pmask
) | (*pmask
^ 0xff);
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 /****************************************************************************
195 Get the netmask address for a local interface.
196 ****************************************************************************/
198 static int _get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
)
200 struct ifaddrs
*iflist
= NULL
;
201 struct ifaddrs
*ifptr
= NULL
;
205 if (getifaddrs(&iflist
) < 0) {
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
) {
214 memset(&ifaces
[total
], '\0', sizeof(ifaces
[total
]));
216 copy_size
= sizeof(struct sockaddr_in
);
218 if (!ifptr
->ifa_addr
|| !ifptr
->ifa_netmask
) {
222 ifaces
[total
].flags
= ifptr
->ifa_flags
;
224 /* Check the interface is up. */
225 if (!(ifaces
[total
].flags
& IFF_UP
)) {
229 #if defined(HAVE_IPV6)
230 if (ifptr
->ifa_addr
->sa_family
== AF_INET6
) {
231 copy_size
= sizeof(struct sockaddr_in6
);
235 memcpy(&ifaces
[total
].ip
, ifptr
->ifa_addr
, copy_size
);
236 memcpy(&ifaces
[total
].netmask
, ifptr
->ifa_netmask
, copy_size
);
238 if (ifaces
[total
].flags
& (IFF_BROADCAST
|IFF_LOOPBACK
)) {
239 make_bcast(&ifaces
[total
].bcast
,
241 &ifaces
[total
].netmask
);
242 } else if ((ifaces
[total
].flags
& IFF_POINTOPOINT
) &&
243 ifptr
->ifa_dstaddr
) {
244 memcpy(&ifaces
[total
].bcast
,
251 strlcpy(ifaces
[total
].name
, ifptr
->ifa_name
,
252 sizeof(ifaces
[total
].name
));
261 static int iface_comp(struct iface_struct
*i1
, struct iface_struct
*i2
)
265 #if defined(HAVE_IPV6)
267 * If we have IPv6 - sort these interfaces lower
268 * than any IPv4 ones.
270 if (i1
->ip
.ss_family
== AF_INET6
&&
271 i2
->ip
.ss_family
== AF_INET
) {
273 } else if (i1
->ip
.ss_family
== AF_INET
&&
274 i2
->ip
.ss_family
== AF_INET6
) {
278 if (i1
->ip
.ss_family
== AF_INET6
) {
279 struct sockaddr_in6
*s1
= (struct sockaddr_in6
*)&i1
->ip
;
280 struct sockaddr_in6
*s2
= (struct sockaddr_in6
*)&i2
->ip
;
282 r
= memcmp(&s1
->sin6_addr
,
284 sizeof(struct in6_addr
));
289 s1
= (struct sockaddr_in6
*)&i1
->netmask
;
290 s2
= (struct sockaddr_in6
*)&i2
->netmask
;
292 r
= memcmp(&s1
->sin6_addr
,
294 sizeof(struct in6_addr
));
301 /* AIX uses __ss_family instead of ss_family inside of
302 sockaddr_storage. Instead of trying to figure out which field to
303 use, we can just cast it to a sockaddr.
306 if (((struct sockaddr
*)&i1
->ip
)->sa_family
== AF_INET
) {
307 struct sockaddr_in
*s1
= (struct sockaddr_in
*)&i1
->ip
;
308 struct sockaddr_in
*s2
= (struct sockaddr_in
*)&i2
->ip
;
310 r
= ntohl(s1
->sin_addr
.s_addr
) -
311 ntohl(s2
->sin_addr
.s_addr
);
316 s1
= (struct sockaddr_in
*)&i1
->netmask
;
317 s2
= (struct sockaddr_in
*)&i2
->netmask
;
319 return ntohl(s1
->sin_addr
.s_addr
) -
320 ntohl(s2
->sin_addr
.s_addr
);
325 int get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
);
326 /* this wrapper is used to remove duplicates from the interface list generated
328 int get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
)
332 total
= _get_interfaces(ifaces
, max_interfaces
);
333 if (total
<= 0) return total
;
335 /* now we need to remove duplicates */
336 qsort(ifaces
, total
, sizeof(ifaces
[0]), QSORT_CAST iface_comp
);
339 if (iface_comp(&ifaces
[i
-1], &ifaces
[i
]) == 0) {
340 for (j
=i
-1;j
<total
-1;j
++) {
341 ifaces
[j
] = ifaces
[j
+1];