2 Unix SMB/CIFS implementation.
3 multiple interface handling
4 Copyright (C) Andrew Tridgell 1992-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 #include "interfaces.h"
24 static struct iface_struct
*probed_ifaces
;
25 static int total_probed
;
27 static struct interface
*local_interfaces
;
29 /****************************************************************************
30 Check if an IP is one of mine.
31 **************************************************************************/
33 bool ismyaddr(const struct sockaddr
*ip
)
36 for (i
=local_interfaces
;i
;i
=i
->next
) {
37 if (sockaddr_equal((struct sockaddr
*)&i
->ip
,ip
)) {
44 bool ismyip_v4(struct in_addr ip
)
46 struct sockaddr_storage ss
;
47 in_addr_to_sockaddr_storage(&ss
, ip
);
48 return ismyaddr((struct sockaddr
*)&ss
);
51 /****************************************************************************
52 Try and find an interface that matches an ip. If we cannot, return NULL.
53 **************************************************************************/
55 static struct interface
*iface_find(const struct sockaddr
*ip
,
60 if (is_address_any(ip
)) {
61 return local_interfaces
;
64 for (i
=local_interfaces
;i
;i
=i
->next
) {
66 if (same_net(ip
, (struct sockaddr
*)&i
->ip
, (struct sockaddr
*)&i
->netmask
)) {
69 } else if (sockaddr_equal((struct sockaddr
*)&i
->ip
, ip
)) {
77 /****************************************************************************
78 Check if a packet is from a local (known) net.
79 **************************************************************************/
81 bool is_local_net(const struct sockaddr
*from
)
84 for (i
=local_interfaces
;i
;i
=i
->next
) {
85 if (same_net(from
, (struct sockaddr
*)&i
->ip
, (struct sockaddr
*)&i
->netmask
)) {
92 #if defined(HAVE_IPV6)
93 void setup_linklocal_scope_id(struct sockaddr
*pss
)
96 for (i
=local_interfaces
;i
;i
=i
->next
) {
97 if (sockaddr_equal((struct sockaddr
*)&i
->ip
,pss
)) {
98 struct sockaddr_in6
*psa6
=
99 (struct sockaddr_in6
*)pss
;
100 psa6
->sin6_scope_id
= if_nametoindex(i
->name
);
107 /****************************************************************************
108 Check if a packet is from a local (known) net.
109 **************************************************************************/
111 bool is_local_net_v4(struct in_addr from
)
113 struct sockaddr_storage ss
;
115 in_addr_to_sockaddr_storage(&ss
, from
);
116 return is_local_net((struct sockaddr
*)&ss
);
119 /****************************************************************************
120 How many interfaces do we have ?
121 **************************************************************************/
123 int iface_count(void)
128 for (i
=local_interfaces
;i
;i
=i
->next
) {
134 /****************************************************************************
135 How many non-loopback IPv4 interfaces do we have ?
136 **************************************************************************/
138 int iface_count_v4_nl(void)
143 for (i
=local_interfaces
;i
;i
=i
->next
) {
144 if (is_loopback_addr((struct sockaddr
*)&i
->ip
)) {
147 if (i
->ip
.ss_family
== AF_INET
) {
154 /****************************************************************************
155 Return a pointer to the in_addr of the first IPv4 interface that's
157 **************************************************************************/
159 const struct in_addr
*first_ipv4_iface(void)
163 for (i
=local_interfaces
;i
;i
=i
->next
) {
164 if ((i
->ip
.ss_family
== AF_INET
) &&
165 (!is_zero_ip_v4(((struct sockaddr_in
*)&i
->ip
)->sin_addr
)))
174 return &((const struct sockaddr_in
*)&i
->ip
)->sin_addr
;
177 /****************************************************************************
178 Return the Nth interface.
179 **************************************************************************/
181 struct interface
*get_interface(int n
)
185 for (i
=local_interfaces
;i
&& n
;i
=i
->next
) {
195 /****************************************************************************
196 Return IP sockaddr_storage of the Nth interface.
197 **************************************************************************/
199 const struct sockaddr_storage
*iface_n_sockaddr_storage(int n
)
203 for (i
=local_interfaces
;i
&& n
;i
=i
->next
) {
213 /****************************************************************************
214 Return IPv4 of the Nth interface (if a v4 address). NULL otherwise.
215 **************************************************************************/
217 const struct in_addr
*iface_n_ip_v4(int n
)
221 for (i
=local_interfaces
;i
&& n
;i
=i
->next
) {
225 if (i
&& i
->ip
.ss_family
== AF_INET
) {
226 return &((const struct sockaddr_in
*)&i
->ip
)->sin_addr
;
231 /****************************************************************************
232 Return IPv4 bcast of the Nth interface (if a v4 address). NULL otherwise.
233 **************************************************************************/
235 const struct in_addr
*iface_n_bcast_v4(int n
)
239 for (i
=local_interfaces
;i
&& n
;i
=i
->next
) {
243 if (i
&& i
->ip
.ss_family
== AF_INET
) {
244 return &((const struct sockaddr_in
*)&i
->bcast
)->sin_addr
;
249 /****************************************************************************
250 Return bcast of the Nth interface.
251 **************************************************************************/
253 const struct sockaddr_storage
*iface_n_bcast(int n
)
257 for (i
=local_interfaces
;i
&& n
;i
=i
->next
) {
267 /* these 3 functions return the ip/bcast/nmask for the interface
268 most appropriate for the given ip address. If they can't find
269 an appropriate interface they return the requested field of the
270 first known interface. */
272 const struct sockaddr_storage
*iface_ip(const struct sockaddr
*ip
)
274 struct interface
*i
= iface_find(ip
, true);
279 /* Search for the first interface with
280 * matching address family. */
282 for (i
=local_interfaces
;i
;i
=i
->next
) {
283 if (i
->ip
.ss_family
== ip
->sa_family
) {
291 return True if a IP is directly reachable on one of our interfaces
294 bool iface_local(const struct sockaddr
*ip
)
296 return iface_find(ip
, true) ? true : false;
299 /****************************************************************************
300 Add an interface to the linked list of interfaces.
301 ****************************************************************************/
303 static void add_interface(const struct iface_struct
*ifs
)
305 char addr
[INET6_ADDRSTRLEN
];
306 struct interface
*iface
;
308 if (iface_find((struct sockaddr
*)&ifs
->ip
, False
)) {
309 DEBUG(3,("add_interface: not adding duplicate interface %s\n",
310 print_sockaddr(addr
, sizeof(addr
), &ifs
->ip
) ));
314 if (!(ifs
->flags
& (IFF_BROADCAST
|IFF_LOOPBACK
))) {
315 DEBUG(3,("not adding non-broadcast interface %s\n",
320 iface
= SMB_MALLOC_P(struct interface
);
325 ZERO_STRUCTPN(iface
);
327 iface
->name
= SMB_STRDUP(ifs
->name
);
332 iface
->flags
= ifs
->flags
;
334 iface
->netmask
= ifs
->netmask
;
335 iface
->bcast
= ifs
->bcast
;
337 DLIST_ADD(local_interfaces
, iface
);
339 DEBUG(2,("added interface %s ip=%s ",
341 print_sockaddr(addr
, sizeof(addr
), &iface
->ip
) ));
342 DEBUG(2,("bcast=%s ",
343 print_sockaddr(addr
, sizeof(addr
),
345 DEBUG(2,("netmask=%s\n",
346 print_sockaddr(addr
, sizeof(addr
),
350 /****************************************************************************
351 Interpret a single element from a interfaces= config line.
353 This handles the following different forms:
355 1) wildcard interface name
360 ****************************************************************************/
362 static void interpret_interface(char *token
)
364 struct sockaddr_storage ss
;
365 struct sockaddr_storage ss_mask
;
366 struct sockaddr_storage ss_net
;
367 struct sockaddr_storage ss_bcast
;
368 struct iface_struct ifs
;
372 bool goodaddr
= false;
374 /* first check if it is an interface name */
375 for (i
=0;i
<total_probed
;i
++) {
376 if (gen_fnmatch(token
, probed_ifaces
[i
].name
) == 0) {
377 add_interface(&probed_ifaces
[i
]);
385 /* maybe it is a DNS name */
386 p
= strchr_m(token
,'/');
388 if (!interpret_string_addr(&ss
, token
, 0)) {
389 DEBUG(2, ("interpret_interface: Can't find address "
394 for (i
=0;i
<total_probed
;i
++) {
395 if (sockaddr_equal((struct sockaddr
*)&ss
, (struct sockaddr
*)&probed_ifaces
[i
].ip
)) {
396 add_interface(&probed_ifaces
[i
]);
400 DEBUG(2,("interpret_interface: "
401 "can't determine interface for %s\n",
406 /* parse it into an IP address/netmasklength pair */
408 goodaddr
= interpret_string_addr(&ss
, token
, 0);
412 DEBUG(2,("interpret_interface: "
413 "can't determine interface for %s\n",
419 goodaddr
= interpret_string_addr(&ss_mask
, p
, 0);
421 DEBUG(2,("interpret_interface: "
422 "can't determine netmask from %s\n",
428 unsigned long val
= strtoul(p
, &endp
, 0);
429 if (p
== endp
|| (endp
&& *endp
!= '\0')) {
430 DEBUG(2,("interpret_interface: "
431 "can't determine netmask value from %s\n",
435 if (!make_netmask(&ss_mask
, &ss
, val
)) {
436 DEBUG(2,("interpret_interface: "
437 "can't apply netmask value %lu from %s\n",
444 make_bcast(&ss_bcast
, &ss
, &ss_mask
);
445 make_net(&ss_net
, &ss
, &ss_mask
);
447 /* Maybe the first component was a broadcast address. */
448 if (sockaddr_equal((struct sockaddr
*)&ss_bcast
, (struct sockaddr
*)&ss
) ||
449 sockaddr_equal((struct sockaddr
*)&ss_net
, (struct sockaddr
*)&ss
)) {
450 for (i
=0;i
<total_probed
;i
++) {
451 if (same_net((struct sockaddr
*)&ss
,
452 (struct sockaddr
*)&probed_ifaces
[i
].ip
,
453 (struct sockaddr
*)&ss_mask
)) {
454 /* Temporarily replace netmask on
455 * the detected interface - user knows
457 struct sockaddr_storage saved_mask
=
458 probed_ifaces
[i
].netmask
;
459 probed_ifaces
[i
].netmask
= ss_mask
;
460 DEBUG(2,("interpret_interface: "
461 "using netmask value %s from "
462 "config file on interface %s\n",
464 probed_ifaces
[i
].name
));
465 add_interface(&probed_ifaces
[i
]);
466 probed_ifaces
[i
].netmask
= saved_mask
;
470 DEBUG(2,("interpret_interface: Can't determine ip for "
471 "broadcast address %s\n",
476 /* Just fake up the interface definition. User knows best. */
478 DEBUG(2,("interpret_interface: Adding interface %s\n",
482 (void)strlcpy(ifs
.name
, token
, sizeof(ifs
.name
));
483 ifs
.flags
= IFF_BROADCAST
;
485 ifs
.netmask
= ss_mask
;
486 ifs
.bcast
= ss_bcast
;
490 /****************************************************************************
491 Load the list of network interfaces.
492 ****************************************************************************/
494 void load_interfaces(void)
496 struct iface_struct
*ifaces
= NULL
;
497 const char **ptr
= lp_interfaces();
502 /* Probe the kernel for interfaces */
503 total_probed
= get_interfaces(talloc_tos(), &ifaces
);
505 if (total_probed
> 0) {
506 probed_ifaces
= (struct iface_struct
*)memdup(ifaces
,
507 sizeof(ifaces
[0])*total_probed
);
508 if (!probed_ifaces
) {
509 DEBUG(0,("ERROR: memdup failed\n"));
515 /* if we don't have a interfaces line then use all broadcast capable
516 interfaces except loopback */
517 if (!ptr
|| !*ptr
|| !**ptr
) {
518 if (total_probed
<= 0) {
519 DEBUG(0,("ERROR: Could not determine network "
520 "interfaces, you must use a interfaces config line\n"));
523 for (i
=0;i
<total_probed
;i
++) {
524 if (probed_ifaces
[i
].flags
& IFF_BROADCAST
) {
525 add_interface(&probed_ifaces
[i
]);
533 char *ptr_cpy
= SMB_STRDUP(*ptr
);
535 interpret_interface(ptr_cpy
);
542 if (!local_interfaces
) {
543 DEBUG(0,("WARNING: no network interfaces found\n"));
548 void gfree_interfaces(void)
550 while (local_interfaces
) {
551 struct interface
*iface
= local_interfaces
;
552 DLIST_REMOVE(local_interfaces
, local_interfaces
);
553 SAFE_FREE(iface
->name
);
557 SAFE_FREE(probed_ifaces
);
560 /****************************************************************************
561 Return True if the list of probed interfaces has changed.
562 ****************************************************************************/
564 bool interfaces_changed(void)
568 struct iface_struct
*ifaces
= NULL
;
570 n
= get_interfaces(talloc_tos(), &ifaces
);
572 if ((n
> 0 )&& (n
!= total_probed
||
573 memcmp(ifaces
, probed_ifaces
, sizeof(ifaces
[0])*n
))) {