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/>.
24 #include "system/network.h"
25 #include "interfaces.h"
26 #include "lib/util/tsort.h"
28 /****************************************************************************
29 Create a struct sockaddr_storage with the netmask bits set to 1.
30 ****************************************************************************/
32 bool make_netmask(struct sockaddr_storage
*pss_out
,
33 const struct sockaddr_storage
*pss_in
,
34 unsigned long masklen
)
37 /* Now apply masklen bits of mask. */
38 #if defined(HAVE_IPV6)
39 if (pss_in
->ss_family
== AF_INET6
) {
40 char *p
= (char *)&((struct sockaddr_in6
*)pss_out
)->sin6_addr
;
46 for (i
= 0; masklen
>= 8; masklen
-= 8, i
++) {
49 /* Deal with the partial byte. */
50 *p
++ &= (0xff & ~(0xff>>masklen
));
52 for (;i
< sizeof(struct in6_addr
); i
++) {
58 if (pss_in
->ss_family
== AF_INET
) {
62 ((struct sockaddr_in
*)pss_out
)->sin_addr
.s_addr
=
63 htonl(((0xFFFFFFFFL
>> masklen
) ^ 0xFFFFFFFFL
));
69 /****************************************************************************
70 Create a struct sockaddr_storage set to the broadcast or network adress from
71 an incoming sockaddr_storage.
72 ****************************************************************************/
74 static void make_bcast_or_net(struct sockaddr_storage
*pss_out
,
75 const struct sockaddr_storage
*pss_in
,
76 const struct sockaddr_storage
*nmask
,
79 unsigned int i
= 0, len
= 0;
84 /* Set all zero netmask bits to 1. */
85 #if defined(HAVE_IPV6)
86 if (pss_in
->ss_family
== AF_INET6
) {
87 p
= (char *)&((struct sockaddr_in6
*)pss_out
)->sin6_addr
;
88 pmask
= discard_const_p(char, &((struct sockaddr_in6
*)nmask
)->sin6_addr
);
92 if (pss_in
->ss_family
== AF_INET
) {
93 p
= (char *)&((struct sockaddr_in
*)pss_out
)->sin_addr
;
94 pmask
= discard_const_p(char, &((struct sockaddr_in
*)nmask
)->sin_addr
);
98 for (i
= 0; i
< len
; i
++, p
++, pmask
++) {
100 *p
= (*p
& *pmask
) | (*pmask
^ 0xff);
108 void make_bcast(struct sockaddr_storage
*pss_out
,
109 const struct sockaddr_storage
*pss_in
,
110 const struct sockaddr_storage
*nmask
)
112 make_bcast_or_net(pss_out
, pss_in
, nmask
, true);
115 void make_net(struct sockaddr_storage
*pss_out
,
116 const struct sockaddr_storage
*pss_in
,
117 const struct sockaddr_storage
*nmask
)
119 make_bcast_or_net(pss_out
, pss_in
, nmask
, false);
123 /****************************************************************************
124 Try the "standard" getifaddrs/freeifaddrs interfaces.
125 Also gets IPv6 interfaces.
126 ****************************************************************************/
128 /****************************************************************************
129 Get the netmask address for a local interface.
130 ****************************************************************************/
132 static int _get_interfaces(TALLOC_CTX
*mem_ctx
, struct iface_struct
**pifaces
)
134 struct iface_struct
*ifaces
;
135 struct ifaddrs
*iflist
= NULL
;
136 struct ifaddrs
*ifptr
= NULL
;
141 if (getifaddrs(&iflist
) < 0) {
146 for (ifptr
= iflist
; ifptr
!= NULL
; ifptr
= ifptr
->ifa_next
) {
147 if (!ifptr
->ifa_addr
|| !ifptr
->ifa_netmask
) {
150 if (!(ifptr
->ifa_flags
& IFF_UP
)) {
156 ifaces
= talloc_array(mem_ctx
, struct iface_struct
, count
);
157 if (ifaces
== NULL
) {
162 /* Loop through interfaces, looking for given IP address */
163 for (ifptr
= iflist
; ifptr
!= NULL
; ifptr
= ifptr
->ifa_next
) {
165 if (!ifptr
->ifa_addr
|| !ifptr
->ifa_netmask
) {
169 /* Check the interface is up. */
170 if (!(ifptr
->ifa_flags
& IFF_UP
)) {
174 memset(&ifaces
[total
], '\0', sizeof(ifaces
[total
]));
176 copy_size
= sizeof(struct sockaddr_in
);
178 ifaces
[total
].flags
= ifptr
->ifa_flags
;
180 #if defined(HAVE_IPV6)
181 if (ifptr
->ifa_addr
->sa_family
== AF_INET6
) {
182 copy_size
= sizeof(struct sockaddr_in6
);
186 memcpy(&ifaces
[total
].ip
, ifptr
->ifa_addr
, copy_size
);
187 memcpy(&ifaces
[total
].netmask
, ifptr
->ifa_netmask
, copy_size
);
189 if (ifaces
[total
].flags
& (IFF_BROADCAST
|IFF_LOOPBACK
)) {
190 make_bcast(&ifaces
[total
].bcast
,
192 &ifaces
[total
].netmask
);
193 } else if ((ifaces
[total
].flags
& IFF_POINTOPOINT
) &&
194 ifptr
->ifa_dstaddr
) {
195 memcpy(&ifaces
[total
].bcast
,
202 strlcpy(ifaces
[total
].name
, ifptr
->ifa_name
,
203 sizeof(ifaces
[total
].name
));
213 static int iface_comp(struct iface_struct
*i1
, struct iface_struct
*i2
)
217 #if defined(HAVE_IPV6)
219 * If we have IPv6 - sort these interfaces lower
220 * than any IPv4 ones.
222 if (i1
->ip
.ss_family
== AF_INET6
&&
223 i2
->ip
.ss_family
== AF_INET
) {
225 } else if (i1
->ip
.ss_family
== AF_INET
&&
226 i2
->ip
.ss_family
== AF_INET6
) {
230 if (i1
->ip
.ss_family
== AF_INET6
) {
231 struct sockaddr_in6
*s1
= (struct sockaddr_in6
*)&i1
->ip
;
232 struct sockaddr_in6
*s2
= (struct sockaddr_in6
*)&i2
->ip
;
234 r
= memcmp(&s1
->sin6_addr
,
236 sizeof(struct in6_addr
));
241 s1
= (struct sockaddr_in6
*)&i1
->netmask
;
242 s2
= (struct sockaddr_in6
*)&i2
->netmask
;
244 r
= memcmp(&s1
->sin6_addr
,
246 sizeof(struct in6_addr
));
253 /* AIX uses __ss_family instead of ss_family inside of
254 sockaddr_storage. Instead of trying to figure out which field to
255 use, we can just cast it to a sockaddr.
258 if (((struct sockaddr
*)&i1
->ip
)->sa_family
== AF_INET
) {
259 struct sockaddr_in
*s1
= (struct sockaddr_in
*)&i1
->ip
;
260 struct sockaddr_in
*s2
= (struct sockaddr_in
*)&i2
->ip
;
262 r
= ntohl(s1
->sin_addr
.s_addr
) -
263 ntohl(s2
->sin_addr
.s_addr
);
268 s1
= (struct sockaddr_in
*)&i1
->netmask
;
269 s2
= (struct sockaddr_in
*)&i2
->netmask
;
271 return ntohl(s1
->sin_addr
.s_addr
) -
272 ntohl(s2
->sin_addr
.s_addr
);
277 /* this wrapper is used to remove duplicates from the interface list generated
279 int get_interfaces(TALLOC_CTX
*mem_ctx
, struct iface_struct
**pifaces
)
281 struct iface_struct
*ifaces
;
284 total
= _get_interfaces(mem_ctx
, &ifaces
);
285 if (total
<= 0) return total
;
287 /* now we need to remove duplicates */
288 TYPESAFE_QSORT(ifaces
, total
, iface_comp
);
291 if (iface_comp(&ifaces
[i
-1], &ifaces
[i
]) == 0) {
292 for (j
=i
-1;j
<total
-1;j
++) {
293 ifaces
[j
] = ifaces
[j
+1];