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 "lib/socket/interfaces.h"
23 #include "librpc/gen_ndr/ioctl.h"
25 static struct iface_struct
*probed_ifaces
;
26 static int total_probed
;
28 static struct interface
*local_interfaces
;
30 /****************************************************************************
31 Check if an IP is one of mine.
32 **************************************************************************/
34 bool ismyaddr(const struct sockaddr
*ip
)
37 for (i
=local_interfaces
;i
;i
=i
->next
) {
38 if (sockaddr_equal((struct sockaddr
*)&i
->ip
,ip
)) {
45 bool ismyip_v4(struct in_addr ip
)
47 struct sockaddr_storage ss
;
48 in_addr_to_sockaddr_storage(&ss
, ip
);
49 return ismyaddr((struct sockaddr
*)&ss
);
52 /****************************************************************************
53 Try and find an interface that matches an ip. If we cannot, return NULL.
54 **************************************************************************/
56 static struct interface
*iface_find(const struct sockaddr
*ip
,
61 if (is_address_any(ip
)) {
62 return local_interfaces
;
65 for (i
=local_interfaces
;i
;i
=i
->next
) {
67 if (same_net(ip
, (struct sockaddr
*)&i
->ip
, (struct sockaddr
*)&i
->netmask
)) {
70 } else if (sockaddr_equal((struct sockaddr
*)&i
->ip
, ip
)) {
78 /****************************************************************************
79 Check if a packet is from a local (known) net.
80 **************************************************************************/
82 bool is_local_net(const struct sockaddr
*from
)
85 for (i
=local_interfaces
;i
;i
=i
->next
) {
86 if (same_net(from
, (struct sockaddr
*)&i
->ip
, (struct sockaddr
*)&i
->netmask
)) {
93 #if defined(HAVE_IPV6)
94 void setup_linklocal_scope_id(struct sockaddr
*pss
)
97 for (i
=local_interfaces
;i
;i
=i
->next
) {
98 if (sockaddr_equal((struct sockaddr
*)&i
->ip
,pss
)) {
99 struct sockaddr_in6
*psa6
=
100 (struct sockaddr_in6
*)pss
;
101 psa6
->sin6_scope_id
= if_nametoindex(i
->name
);
108 /****************************************************************************
109 Check if a packet is from a local (known) net.
110 **************************************************************************/
112 bool is_local_net_v4(struct in_addr from
)
114 struct sockaddr_storage ss
;
116 in_addr_to_sockaddr_storage(&ss
, from
);
117 return is_local_net((struct sockaddr
*)&ss
);
120 /****************************************************************************
121 How many interfaces do we have ?
122 **************************************************************************/
124 int iface_count(void)
129 for (i
=local_interfaces
;i
;i
=i
->next
) {
135 /****************************************************************************
136 How many non-loopback IPv4 interfaces do we have ?
137 **************************************************************************/
139 int iface_count_v4_nl(void)
144 for (i
=local_interfaces
;i
;i
=i
->next
) {
145 if (is_loopback_addr((struct sockaddr
*)&i
->ip
)) {
148 if (i
->ip
.ss_family
== AF_INET
) {
155 /****************************************************************************
156 Return a pointer to the in_addr of the first IPv4 interface that's
158 **************************************************************************/
160 const struct in_addr
*first_ipv4_iface(void)
164 for (i
=local_interfaces
;i
;i
=i
->next
) {
165 if ((i
->ip
.ss_family
== AF_INET
) &&
166 (!is_zero_ip_v4(((struct sockaddr_in
*)&i
->ip
)->sin_addr
)))
175 return &((const struct sockaddr_in
*)&i
->ip
)->sin_addr
;
178 /****************************************************************************
179 Return the Nth interface.
180 **************************************************************************/
182 struct interface
*get_interface(int n
)
186 for (i
=local_interfaces
;i
&& n
;i
=i
->next
) {
196 /****************************************************************************
197 Return IP sockaddr_storage of the Nth interface.
198 **************************************************************************/
200 const struct sockaddr_storage
*iface_n_sockaddr_storage(int n
)
204 for (i
=local_interfaces
;i
&& n
;i
=i
->next
) {
214 /****************************************************************************
215 Return IPv4 of the Nth interface (if a v4 address). NULL otherwise.
216 **************************************************************************/
218 const struct in_addr
*iface_n_ip_v4(int n
)
222 for (i
=local_interfaces
;i
&& n
;i
=i
->next
) {
226 if (i
&& i
->ip
.ss_family
== AF_INET
) {
227 return &((const struct sockaddr_in
*)&i
->ip
)->sin_addr
;
232 /****************************************************************************
233 Return IPv4 bcast of the Nth interface (if a v4 address). NULL otherwise.
234 **************************************************************************/
236 const struct in_addr
*iface_n_bcast_v4(int n
)
240 for (i
=local_interfaces
;i
&& n
;i
=i
->next
) {
244 if (i
&& i
->ip
.ss_family
== AF_INET
) {
245 return &((const struct sockaddr_in
*)&i
->bcast
)->sin_addr
;
250 /****************************************************************************
251 Return bcast of the Nth interface.
252 **************************************************************************/
254 const struct sockaddr_storage
*iface_n_bcast(int n
)
258 for (i
=local_interfaces
;i
&& n
;i
=i
->next
) {
268 /* these 3 functions return the ip/bcast/nmask for the interface
269 most appropriate for the given ip address. If they can't find
270 an appropriate interface they return the requested field of the
271 first known interface. */
273 const struct sockaddr_storage
*iface_ip(const struct sockaddr
*ip
)
275 struct interface
*i
= iface_find(ip
, true);
280 /* Search for the first interface with
281 * matching address family. */
283 for (i
=local_interfaces
;i
;i
=i
->next
) {
284 if (i
->ip
.ss_family
== ip
->sa_family
) {
292 return True if a IP is directly reachable on one of our interfaces
295 bool iface_local(const struct sockaddr
*ip
)
297 return iface_find(ip
, true) ? true : false;
300 /****************************************************************************
301 Add an interface to the linked list of interfaces.
302 ****************************************************************************/
304 static void add_interface(const struct iface_struct
*ifs
)
306 char addr
[INET6_ADDRSTRLEN
];
307 struct interface
*iface
;
309 if (iface_find((const struct sockaddr
*)&ifs
->ip
, False
)) {
310 DEBUG(3,("add_interface: not adding duplicate interface %s\n",
311 print_sockaddr(addr
, sizeof(addr
), &ifs
->ip
) ));
315 if (!(ifs
->flags
& (IFF_BROADCAST
|IFF_LOOPBACK
))) {
316 DEBUG(3,("not adding non-broadcast interface %s\n",
321 iface
= SMB_MALLOC_P(struct interface
);
326 ZERO_STRUCTPN(iface
);
328 iface
->name
= SMB_STRDUP(ifs
->name
);
333 iface
->flags
= ifs
->flags
;
335 iface
->netmask
= ifs
->netmask
;
336 iface
->bcast
= ifs
->bcast
;
337 iface
->linkspeed
= ifs
->linkspeed
;
338 iface
->capability
= ifs
->capability
;
339 iface
->if_index
= ifs
->if_index
;
341 DLIST_ADD(local_interfaces
, iface
);
343 DEBUG(2,("added interface %s ip=%s ",
345 print_sockaddr(addr
, sizeof(addr
), &iface
->ip
) ));
346 DEBUG(2,("bcast=%s ",
347 print_sockaddr(addr
, sizeof(addr
),
349 DEBUG(2,("netmask=%s\n",
350 print_sockaddr(addr
, sizeof(addr
),
355 static void parse_extra_info(char *key
, uint64_t *speed
, uint32_t *cap
,
358 while (key
!= NULL
&& *key
!= '\0') {
362 next_key
= strchr_m(key
, ',');
363 if (next_key
!= NULL
) {
367 val
= strchr_m(key
, '=');
371 if (strequal_m(key
, "speed")) {
372 *speed
= (uint64_t)strtoull(val
, NULL
, 0);
373 } else if (strequal_m(key
, "capability")) {
374 if (strequal_m(val
, "RSS")) {
375 *cap
|= FSCTL_NET_IFACE_RSS_CAPABLE
;
376 } else if (strequal(val
, "RDMA")) {
377 *cap
|= FSCTL_NET_IFACE_RDMA_CAPABLE
;
379 DBG_WARNING("Capability unknown: "
382 } else if (strequal_m(key
, "if_index")) {
383 *if_index
= (uint32_t)strtoul(val
, NULL
, 0);
385 DBG_DEBUG("Key unknown: '%s'\n", key
);
393 /****************************************************************************
394 Interpret a single element from a interfaces= config line.
396 This handles the following different forms:
398 1) wildcard interface name
404 Additional information for an interface can be specified with
405 this extended syntax:
407 interface[;key1=value1[,key2=value2[...]]]
410 - keys known: 'speed', 'capability', 'if_index'
411 - speed is in bits per second
412 - capabilites known: 'RSS', 'RDMA'
413 - if_index should be used with care, because
414 these indexes should not conicide with indexes
417 ****************************************************************************/
419 static void interpret_interface(char *token
)
421 struct sockaddr_storage ss
;
422 struct sockaddr_storage ss_mask
;
423 struct sockaddr_storage ss_net
;
424 struct sockaddr_storage ss_bcast
;
425 struct iface_struct ifs
;
429 bool goodaddr
= false;
431 uint32_t cap
= FSCTL_NET_IFACE_NONE_CAPABLE
;
432 uint32_t if_index
= 0;
433 bool speed_set
= false;
434 bool cap_set
= false;
435 bool if_index_set
= false;
437 /* first check if it is an interface name */
438 for (i
=0;i
<total_probed
;i
++) {
439 if (gen_fnmatch(token
, probed_ifaces
[i
].name
) == 0) {
440 add_interface(&probed_ifaces
[i
]);
449 * extract speed / capability information if present
451 p
= strchr_m(token
, ';');
454 parse_extra_info(p
, &speed
, &cap
, &if_index
);
458 if (cap
!= FSCTL_NET_IFACE_NONE_CAPABLE
) {
466 p
= strchr_m(token
,'/');
468 if (!interpret_string_addr(&ss
, token
, 0)) {
469 DEBUG(2, ("interpret_interface: Can't find address "
474 for (i
=0;i
<total_probed
;i
++) {
475 if (sockaddr_equal((struct sockaddr
*)&ss
,
476 (struct sockaddr
*)&probed_ifaces
[i
].ip
))
479 probed_ifaces
[i
].linkspeed
= speed
;
482 probed_ifaces
[i
].capability
= cap
;
485 probed_ifaces
[i
].if_index
= if_index
;
487 add_interface(&probed_ifaces
[i
]);
491 DEBUG(2,("interpret_interface: "
492 "can't determine interface for %s\n",
497 /* parse it into an IP address/netmasklength pair */
499 goodaddr
= interpret_string_addr(&ss
, token
, 0);
503 DEBUG(2,("interpret_interface: "
504 "can't determine interface for %s\n",
510 goodaddr
= interpret_string_addr(&ss_mask
, p
, 0);
512 DEBUG(2,("interpret_interface: "
513 "can't determine netmask from %s\n",
519 unsigned long val
= strtoul(p
, &endp
, 0);
520 if (p
== endp
|| (endp
&& *endp
!= '\0')) {
521 DEBUG(2,("interpret_interface: "
522 "can't determine netmask value from %s\n",
526 if (!make_netmask(&ss_mask
, &ss
, val
)) {
527 DEBUG(2,("interpret_interface: "
528 "can't apply netmask value %lu from %s\n",
535 make_bcast(&ss_bcast
, &ss
, &ss_mask
);
536 make_net(&ss_net
, &ss
, &ss_mask
);
538 /* Maybe the first component was a broadcast address. */
539 if (sockaddr_equal((struct sockaddr
*)&ss_bcast
, (struct sockaddr
*)&ss
) ||
540 sockaddr_equal((struct sockaddr
*)&ss_net
, (struct sockaddr
*)&ss
)) {
541 for (i
=0;i
<total_probed
;i
++) {
542 if (same_net((struct sockaddr
*)&ss
,
543 (struct sockaddr
*)&probed_ifaces
[i
].ip
,
544 (struct sockaddr
*)&ss_mask
)) {
545 /* Temporarily replace netmask on
546 * the detected interface - user knows
548 struct sockaddr_storage saved_mask
=
549 probed_ifaces
[i
].netmask
;
550 probed_ifaces
[i
].netmask
= ss_mask
;
551 DEBUG(2,("interpret_interface: "
552 "using netmask value %s from "
553 "config file on interface %s\n",
555 probed_ifaces
[i
].name
));
557 probed_ifaces
[i
].linkspeed
= speed
;
560 probed_ifaces
[i
].capability
= cap
;
563 probed_ifaces
[i
].if_index
= if_index
;
565 add_interface(&probed_ifaces
[i
]);
566 probed_ifaces
[i
].netmask
= saved_mask
;
570 DEBUG(2,("interpret_interface: Can't determine ip for "
571 "broadcast address %s\n",
576 /* Just fake up the interface definition. User knows best. */
578 DEBUG(2,("interpret_interface: Adding interface %s\n",
582 (void)strlcpy(ifs
.name
, token
, sizeof(ifs
.name
));
583 ifs
.flags
= IFF_BROADCAST
;
585 ifs
.netmask
= ss_mask
;
586 ifs
.bcast
= ss_bcast
;
588 probed_ifaces
[i
].if_index
= if_index
;
591 ifs
.linkspeed
= speed
;
593 ifs
.linkspeed
= 1000 * 1000 * 1000;
595 ifs
.capability
= cap
;
599 /****************************************************************************
600 Load the list of network interfaces.
601 ****************************************************************************/
603 void load_interfaces(void)
605 struct iface_struct
*ifaces
= NULL
;
606 const char **ptr
= lp_interfaces();
611 /* Probe the kernel for interfaces */
612 total_probed
= get_interfaces(talloc_tos(), &ifaces
);
614 if (total_probed
> 0) {
615 probed_ifaces
= (struct iface_struct
*)smb_memdup(ifaces
,
616 sizeof(ifaces
[0])*total_probed
);
617 if (!probed_ifaces
) {
618 DEBUG(0,("ERROR: smb_memdup failed\n"));
624 /* if we don't have a interfaces line then use all broadcast capable
625 interfaces except loopback */
626 if (!ptr
|| !*ptr
|| !**ptr
) {
627 if (total_probed
<= 0) {
628 DEBUG(0,("ERROR: Could not determine network "
629 "interfaces, you must use a interfaces config line\n"));
632 for (i
=0;i
<total_probed
;i
++) {
633 if (probed_ifaces
[i
].flags
& IFF_BROADCAST
) {
634 add_interface(&probed_ifaces
[i
]);
642 char *ptr_cpy
= SMB_STRDUP(*ptr
);
644 interpret_interface(ptr_cpy
);
651 if (!local_interfaces
) {
652 DEBUG(0,("WARNING: no network interfaces found\n"));
657 void gfree_interfaces(void)
659 while (local_interfaces
) {
660 struct interface
*iface
= local_interfaces
;
661 DLIST_REMOVE(local_interfaces
, local_interfaces
);
662 SAFE_FREE(iface
->name
);
666 SAFE_FREE(probed_ifaces
);
669 /****************************************************************************
670 Return True if the list of probed interfaces has changed.
671 ****************************************************************************/
673 bool interfaces_changed(void)
677 struct iface_struct
*ifaces
= NULL
;
679 n
= get_interfaces(talloc_tos(), &ifaces
);
681 if ((n
> 0 )&& (n
!= total_probed
||
682 memcmp(ifaces
, probed_ifaces
, sizeof(ifaces
[0])*n
))) {