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/>.
23 static struct iface_struct
*probed_ifaces
;
24 static int total_probed
;
26 static struct interface
*local_interfaces
;
28 /****************************************************************************
29 Check if an IP is one of mine.
30 **************************************************************************/
32 bool ismyaddr(const struct sockaddr_storage
*ip
)
35 for (i
=local_interfaces
;i
;i
=i
->next
) {
36 if (addr_equal(&i
->ip
,ip
)) {
43 bool ismyip_v4(struct in_addr ip
)
45 struct sockaddr_storage ss
;
46 in_addr_to_sockaddr_storage(&ss
, ip
);
50 /****************************************************************************
51 Try and find an interface that matches an ip. If we cannot, return NULL.
52 **************************************************************************/
54 static struct interface
*iface_find(const struct sockaddr_storage
*ip
,
59 if (is_address_any(ip
)) {
60 return local_interfaces
;
63 for (i
=local_interfaces
;i
;i
=i
->next
) {
65 if (same_net(ip
, &i
->ip
, &i
->netmask
)) {
68 } else if (addr_equal(&i
->ip
, ip
)) {
76 /****************************************************************************
77 Check if a packet is from a local (known) net.
78 **************************************************************************/
80 bool is_local_net(const struct sockaddr_storage
*from
)
83 for (i
=local_interfaces
;i
;i
=i
->next
) {
84 if (same_net(from
, &i
->ip
, &i
->netmask
)) {
91 #if defined(HAVE_IPV6)
92 void setup_linklocal_scope_id(struct sockaddr_storage
*pss
)
95 for (i
=local_interfaces
;i
;i
=i
->next
) {
96 if (addr_equal(&i
->ip
,pss
)) {
97 struct sockaddr_in6
*psa6
=
98 (struct sockaddr_in6
*)pss
;
99 psa6
->sin6_scope_id
= if_nametoindex(i
->name
);
106 /****************************************************************************
107 Check if a packet is from a local (known) net.
108 **************************************************************************/
110 bool is_local_net_v4(struct in_addr from
)
112 struct sockaddr_storage ss
;
114 in_addr_to_sockaddr_storage(&ss
, from
);
115 return is_local_net(&ss
);
118 /****************************************************************************
119 How many interfaces do we have ?
120 **************************************************************************/
122 int iface_count(void)
127 for (i
=local_interfaces
;i
;i
=i
->next
) {
133 /****************************************************************************
134 How many non-loopback IPv4 interfaces do we have ?
135 **************************************************************************/
137 int iface_count_v4_nl(void)
142 for (i
=local_interfaces
;i
;i
=i
->next
) {
143 if (is_loopback_addr(&i
->ip
)) {
146 if (i
->ip
.ss_family
== AF_INET
) {
153 /****************************************************************************
154 Return a pointer to the in_addr of the first IPv4 interface.
155 **************************************************************************/
157 const struct in_addr
*first_ipv4_iface(void)
161 for (i
=local_interfaces
;i
;i
=i
->next
) {
162 if (i
->ip
.ss_family
== AF_INET
) {
170 return &((const struct sockaddr_in
*)&i
->ip
)->sin_addr
;
173 /****************************************************************************
174 Return the Nth interface.
175 **************************************************************************/
177 struct interface
*get_interface(int n
)
181 for (i
=local_interfaces
;i
&& n
;i
=i
->next
) {
191 /****************************************************************************
192 Return IP sockaddr_storage of the Nth interface.
193 **************************************************************************/
195 const struct sockaddr_storage
*iface_n_sockaddr_storage(int n
)
199 for (i
=local_interfaces
;i
&& n
;i
=i
->next
) {
209 /****************************************************************************
210 Return IPv4 of the Nth interface (if a v4 address). NULL otherwise.
211 **************************************************************************/
213 const struct in_addr
*iface_n_ip_v4(int n
)
217 for (i
=local_interfaces
;i
&& n
;i
=i
->next
) {
221 if (i
&& i
->ip
.ss_family
== AF_INET
) {
222 return &((const struct sockaddr_in
*)&i
->ip
)->sin_addr
;
227 /****************************************************************************
228 Return IPv4 bcast of the Nth interface (if a v4 address). NULL otherwise.
229 **************************************************************************/
231 const struct in_addr
*iface_n_bcast_v4(int n
)
235 for (i
=local_interfaces
;i
&& n
;i
=i
->next
) {
239 if (i
&& i
->ip
.ss_family
== AF_INET
) {
240 return &((const struct sockaddr_in
*)&i
->bcast
)->sin_addr
;
245 /****************************************************************************
246 Return bcast of the Nth interface.
247 **************************************************************************/
249 const struct sockaddr_storage
*iface_n_bcast(int n
)
253 for (i
=local_interfaces
;i
&& n
;i
=i
->next
) {
263 /* these 3 functions return the ip/bcast/nmask for the interface
264 most appropriate for the given ip address. If they can't find
265 an appropriate interface they return the requested field of the
266 first known interface. */
268 const struct sockaddr_storage
*iface_ip(const struct sockaddr_storage
*ip
)
270 struct interface
*i
= iface_find(ip
, true);
275 /* Search for the first interface with
276 * matching address family. */
278 for (i
=local_interfaces
;i
;i
=i
->next
) {
279 if (i
->ip
.ss_family
== ip
->ss_family
) {
287 return True if a IP is directly reachable on one of our interfaces
290 bool iface_local(const struct sockaddr_storage
*ip
)
292 return iface_find(ip
, True
) ? true : false;
295 /****************************************************************************
296 Add an interface to the linked list of interfaces.
297 ****************************************************************************/
299 static void add_interface(const struct iface_struct
*ifs
)
301 char addr
[INET6_ADDRSTRLEN
];
302 struct interface
*iface
;
304 if (iface_find(&ifs
->ip
, False
)) {
305 DEBUG(3,("add_interface: not adding duplicate interface %s\n",
306 print_sockaddr(addr
, sizeof(addr
), &ifs
->ip
) ));
310 if (!(ifs
->flags
& (IFF_BROADCAST
|IFF_LOOPBACK
))) {
311 DEBUG(3,("not adding non-broadcast interface %s\n",
316 iface
= SMB_MALLOC_P(struct interface
);
321 ZERO_STRUCTPN(iface
);
323 iface
->name
= SMB_STRDUP(ifs
->name
);
328 iface
->flags
= ifs
->flags
;
330 iface
->netmask
= ifs
->netmask
;
331 iface
->bcast
= ifs
->bcast
;
333 DLIST_ADD(local_interfaces
, iface
);
335 DEBUG(2,("added interface %s ip=%s ",
337 print_sockaddr(addr
, sizeof(addr
), &iface
->ip
) ));
338 DEBUG(2,("bcast=%s ",
339 print_sockaddr(addr
, sizeof(addr
),
341 DEBUG(2,("netmask=%s\n",
342 print_sockaddr(addr
, sizeof(addr
),
346 /****************************************************************************
347 Interpret a single element from a interfaces= config line.
349 This handles the following different forms:
351 1) wildcard interface name
356 ****************************************************************************/
358 static void interpret_interface(char *token
)
360 struct sockaddr_storage ss
;
361 struct sockaddr_storage ss_mask
;
362 struct sockaddr_storage ss_net
;
363 struct sockaddr_storage ss_bcast
;
364 struct iface_struct ifs
;
368 bool goodaddr
= false;
370 /* first check if it is an interface name */
371 for (i
=0;i
<total_probed
;i
++) {
372 if (gen_fnmatch(token
, probed_ifaces
[i
].name
) == 0) {
373 add_interface(&probed_ifaces
[i
]);
381 /* maybe it is a DNS name */
382 p
= strchr_m(token
,'/');
384 if (!interpret_string_addr(&ss
, token
, 0)) {
385 DEBUG(2, ("interpret_interface: Can't find address "
390 for (i
=0;i
<total_probed
;i
++) {
391 if (addr_equal(&ss
, &probed_ifaces
[i
].ip
)) {
392 add_interface(&probed_ifaces
[i
]);
396 DEBUG(2,("interpret_interface: "
397 "can't determine interface for %s\n",
402 /* parse it into an IP address/netmasklength pair */
404 goodaddr
= interpret_string_addr(&ss
, token
, 0);
408 DEBUG(2,("interpret_interface: "
409 "can't determine interface for %s\n",
415 goodaddr
= interpret_string_addr(&ss_mask
, p
, 0);
417 DEBUG(2,("interpret_interface: "
418 "can't determine netmask from %s\n",
424 unsigned long val
= strtoul(p
, &endp
, 0);
425 if (p
== endp
|| (endp
&& *endp
!= '\0')) {
426 DEBUG(2,("interpret_interface: "
427 "can't determine netmask value from %s\n",
431 if (!make_netmask(&ss_mask
, &ss
, val
)) {
432 DEBUG(2,("interpret_interface: "
433 "can't apply netmask value %lu from %s\n",
440 make_bcast(&ss_bcast
, &ss
, &ss_mask
);
441 make_net(&ss_net
, &ss
, &ss_mask
);
443 /* Maybe the first component was a broadcast address. */
444 if (addr_equal(&ss_bcast
, &ss
) || addr_equal(&ss_net
, &ss
)) {
445 for (i
=0;i
<total_probed
;i
++) {
446 if (same_net(&ss
, &probed_ifaces
[i
].ip
, &ss_mask
)) {
447 /* Temporarily replace netmask on
448 * the detected interface - user knows
450 struct sockaddr_storage saved_mask
=
451 probed_ifaces
[i
].netmask
;
452 probed_ifaces
[i
].netmask
= ss_mask
;
453 DEBUG(2,("interpret_interface: "
454 "using netmask value %s from "
455 "config file on interface %s\n",
457 probed_ifaces
[i
].name
));
458 add_interface(&probed_ifaces
[i
]);
459 probed_ifaces
[i
].netmask
= saved_mask
;
463 DEBUG(2,("interpret_interface: Can't determine ip for "
464 "broadcast address %s\n",
469 /* Just fake up the interface definition. User knows best. */
471 DEBUG(2,("interpret_interface: Adding interface %s\n",
475 (void)strlcpy(ifs
.name
, token
, sizeof(ifs
.name
));
476 ifs
.flags
= IFF_BROADCAST
;
478 ifs
.netmask
= ss_mask
;
479 ifs
.bcast
= ss_bcast
;
483 /****************************************************************************
484 Load the list of network interfaces.
485 ****************************************************************************/
487 void load_interfaces(void)
489 struct iface_struct ifaces
[MAX_INTERFACES
];
490 const char **ptr
= lp_interfaces();
493 SAFE_FREE(probed_ifaces
);
495 /* dump the current interfaces if any */
496 while (local_interfaces
) {
497 struct interface
*iface
= local_interfaces
;
498 DLIST_REMOVE(local_interfaces
, local_interfaces
);
499 SAFE_FREE(iface
->name
);
503 /* Probe the kernel for interfaces */
504 total_probed
= get_interfaces(ifaces
, MAX_INTERFACES
);
506 if (total_probed
> 0) {
507 probed_ifaces
= (struct iface_struct
*)memdup(ifaces
,
508 sizeof(ifaces
[0])*total_probed
);
509 if (!probed_ifaces
) {
510 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)
567 struct iface_struct ifaces
[MAX_INTERFACES
];
569 n
= get_interfaces(ifaces
, MAX_INTERFACES
);
571 if ((n
> 0 )&& (n
!= total_probed
||
572 memcmp(ifaces
, probed_ifaces
, sizeof(ifaces
[0])*n
))) {