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/>.
23 /****************************************************************************
24 Create a struct sockaddr_storage with the netmask bits set to 1.
25 ****************************************************************************/
27 bool make_netmask(struct sockaddr_storage
*pss_out
,
28 const struct sockaddr_storage
*pss_in
,
29 unsigned long masklen
)
32 /* Now apply masklen bits of mask. */
33 #if defined(HAVE_IPV6)
34 if (pss_in
->ss_family
== AF_INET6
) {
35 char *p
= (char *)&((struct sockaddr_in6
*)pss_out
)->sin6_addr
;
41 for (i
= 0; masklen
>= 8; masklen
-= 8, i
++) {
44 /* Deal with the partial byte. */
45 *p
++ &= (0xff & ~(0xff>>masklen
));
47 for (;i
< sizeof(struct in6_addr
); i
++) {
53 if (pss_in
->ss_family
== AF_INET
) {
57 ((struct sockaddr_in
*)pss_out
)->sin_addr
.s_addr
=
58 htonl(((0xFFFFFFFFL
>> masklen
) ^ 0xFFFFFFFFL
));
64 /****************************************************************************
65 Create a struct sockaddr_storage set to the broadcast or network adress from
66 an incoming sockaddr_storage.
67 ****************************************************************************/
69 static void make_bcast_or_net(struct sockaddr_storage
*pss_out
,
70 const struct sockaddr_storage
*pss_in
,
71 const struct sockaddr_storage
*nmask
,
74 unsigned int i
= 0, len
= 0;
79 /* Set all zero netmask bits to 1. */
80 #if defined(HAVE_IPV6)
81 if (pss_in
->ss_family
== AF_INET6
) {
82 p
= (char *)&((struct sockaddr_in6
*)pss_out
)->sin6_addr
;
83 pmask
= (char *)&((struct sockaddr_in6
*)nmask
)->sin6_addr
;
87 if (pss_in
->ss_family
== AF_INET
) {
88 p
= (char *)&((struct sockaddr_in
*)pss_out
)->sin_addr
;
89 pmask
= (char *)&((struct sockaddr_in
*)nmask
)->sin_addr
;
93 for (i
= 0; i
< len
; i
++, p
++, pmask
++) {
95 *p
= (*p
& *pmask
) | (*pmask
^ 0xff);
103 void make_bcast(struct sockaddr_storage
*pss_out
,
104 const struct sockaddr_storage
*pss_in
,
105 const struct sockaddr_storage
*nmask
)
107 make_bcast_or_net(pss_out
, pss_in
, nmask
, true);
110 void make_net(struct sockaddr_storage
*pss_out
,
111 const struct sockaddr_storage
*pss_in
,
112 const struct sockaddr_storage
*nmask
)
114 make_bcast_or_net(pss_out
, pss_in
, nmask
, false);
117 /****************************************************************************
118 Try the "standard" getifaddrs/freeifaddrs interfaces.
119 Also gets IPv6 interfaces.
120 ****************************************************************************/
122 /****************************************************************************
123 Get the netmask address for a local interface.
124 ****************************************************************************/
126 static int _get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
)
128 struct ifaddrs
*iflist
= NULL
;
129 struct ifaddrs
*ifptr
= NULL
;
133 if (getifaddrs(&iflist
) < 0) {
137 /* Loop through interfaces, looking for given IP address */
138 for (ifptr
= iflist
, total
= 0;
139 ifptr
!= NULL
&& total
< max_interfaces
;
140 ifptr
= ifptr
->ifa_next
) {
142 memset(&ifaces
[total
], '\0', sizeof(ifaces
[total
]));
144 copy_size
= sizeof(struct sockaddr_in
);
146 if (!ifptr
->ifa_addr
|| !ifptr
->ifa_netmask
) {
150 ifaces
[total
].flags
= ifptr
->ifa_flags
;
152 /* Check the interface is up. */
153 if (!(ifaces
[total
].flags
& IFF_UP
)) {
157 #if defined(HAVE_IPV6)
158 if (ifptr
->ifa_addr
->sa_family
== AF_INET6
) {
159 copy_size
= sizeof(struct sockaddr_in6
);
163 memcpy(&ifaces
[total
].ip
, ifptr
->ifa_addr
, copy_size
);
164 memcpy(&ifaces
[total
].netmask
, ifptr
->ifa_netmask
, copy_size
);
166 if (ifaces
[total
].flags
& (IFF_BROADCAST
|IFF_LOOPBACK
)) {
167 make_bcast(&ifaces
[total
].bcast
,
169 &ifaces
[total
].netmask
);
170 } else if ((ifaces
[total
].flags
& IFF_POINTOPOINT
) &&
171 ifptr
->ifa_dstaddr
) {
172 memcpy(&ifaces
[total
].bcast
,
179 strlcpy(ifaces
[total
].name
, ifptr
->ifa_name
,
180 sizeof(ifaces
[total
].name
));
189 static int iface_comp(struct iface_struct
*i1
, struct iface_struct
*i2
)
193 #if defined(HAVE_IPV6)
195 * If we have IPv6 - sort these interfaces lower
196 * than any IPv4 ones.
198 if (i1
->ip
.ss_family
== AF_INET6
&&
199 i2
->ip
.ss_family
== AF_INET
) {
201 } else if (i1
->ip
.ss_family
== AF_INET
&&
202 i2
->ip
.ss_family
== AF_INET6
) {
206 if (i1
->ip
.ss_family
== AF_INET6
) {
207 struct sockaddr_in6
*s1
= (struct sockaddr_in6
*)&i1
->ip
;
208 struct sockaddr_in6
*s2
= (struct sockaddr_in6
*)&i2
->ip
;
210 r
= memcmp(&s1
->sin6_addr
,
212 sizeof(struct in6_addr
));
217 s1
= (struct sockaddr_in6
*)&i1
->netmask
;
218 s2
= (struct sockaddr_in6
*)&i2
->netmask
;
220 r
= memcmp(&s1
->sin6_addr
,
222 sizeof(struct in6_addr
));
229 /* AIX uses __ss_family instead of ss_family inside of
230 sockaddr_storage. Instead of trying to figure out which field to
231 use, we can just cast it to a sockaddr.
234 if (((struct sockaddr
*)&i1
->ip
)->sa_family
== AF_INET
) {
235 struct sockaddr_in
*s1
= (struct sockaddr_in
*)&i1
->ip
;
236 struct sockaddr_in
*s2
= (struct sockaddr_in
*)&i2
->ip
;
238 r
= ntohl(s1
->sin_addr
.s_addr
) -
239 ntohl(s2
->sin_addr
.s_addr
);
244 s1
= (struct sockaddr_in
*)&i1
->netmask
;
245 s2
= (struct sockaddr_in
*)&i2
->netmask
;
247 return ntohl(s1
->sin_addr
.s_addr
) -
248 ntohl(s2
->sin_addr
.s_addr
);
253 int get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
);
254 /* this wrapper is used to remove duplicates from the interface list generated
256 int get_interfaces(struct iface_struct
*ifaces
, int max_interfaces
)
260 total
= _get_interfaces(ifaces
, max_interfaces
);
261 if (total
<= 0) return total
;
263 /* now we need to remove duplicates */
264 qsort(ifaces
, total
, sizeof(ifaces
[0]), QSORT_CAST iface_comp
);
267 if (iface_comp(&ifaces
[i
-1], &ifaces
[i
]) == 0) {
268 for (j
=i
-1;j
<total
-1;j
++) {
269 ifaces
[j
] = ifaces
[j
+1];