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"
24 #include "lib/util/smb_strtox.h"
26 static struct iface_struct
*probed_ifaces
;
27 static int total_probed
;
29 static struct interface
*local_interfaces
;
31 /****************************************************************************
32 Check if an IP is one of mine.
33 **************************************************************************/
35 bool ismyaddr(const struct sockaddr
*ip
)
38 for (i
=local_interfaces
;i
;i
=i
->next
) {
39 if (sockaddr_equal((struct sockaddr
*)&i
->ip
,ip
)) {
46 bool ismyip_v4(struct in_addr ip
)
48 struct sockaddr_storage ss
;
49 in_addr_to_sockaddr_storage(&ss
, ip
);
50 return ismyaddr((struct sockaddr
*)&ss
);
53 /****************************************************************************
54 Try and find an interface that matches an ip. If we cannot, return NULL.
55 **************************************************************************/
57 static struct interface
*iface_find(const struct sockaddr
*ip
,
62 if (is_address_any(ip
)) {
63 return local_interfaces
;
66 for (i
=local_interfaces
;i
;i
=i
->next
) {
68 if (same_net(ip
, (struct sockaddr
*)&i
->ip
, (struct sockaddr
*)&i
->netmask
)) {
71 } else if (sockaddr_equal((struct sockaddr
*)&i
->ip
, ip
)) {
79 /****************************************************************************
80 Check if a packet is from a local (known) net.
81 **************************************************************************/
83 bool is_local_net(const struct sockaddr
*from
)
86 for (i
=local_interfaces
;i
;i
=i
->next
) {
87 if (same_net(from
, (struct sockaddr
*)&i
->ip
, (struct sockaddr
*)&i
->netmask
)) {
94 #if defined(HAVE_IPV6)
95 void setup_linklocal_scope_id(struct sockaddr
*pss
)
98 for (i
=local_interfaces
;i
;i
=i
->next
) {
99 if (sockaddr_equal((struct sockaddr
*)&i
->ip
,pss
)) {
100 struct sockaddr_in6
*psa6
=
101 (struct sockaddr_in6
*)pss
;
102 psa6
->sin6_scope_id
= if_nametoindex(i
->name
);
109 /****************************************************************************
110 Check if a packet is from a local (known) net.
111 **************************************************************************/
113 bool is_local_net_v4(struct in_addr from
)
115 struct sockaddr_storage ss
;
117 in_addr_to_sockaddr_storage(&ss
, from
);
118 return is_local_net((struct sockaddr
*)&ss
);
121 /****************************************************************************
122 How many interfaces do we have ?
123 **************************************************************************/
125 int iface_count(void)
130 for (i
=local_interfaces
;i
;i
=i
->next
) {
136 /****************************************************************************
137 How many non-loopback IPv4 interfaces do we have ?
138 **************************************************************************/
140 int iface_count_v4_nl(void)
145 for (i
=local_interfaces
;i
;i
=i
->next
) {
146 if (is_loopback_addr((struct sockaddr
*)&i
->ip
)) {
149 if (i
->ip
.ss_family
== AF_INET
) {
156 /****************************************************************************
157 Return a pointer to the in_addr of the first IPv4 interface that's
159 **************************************************************************/
161 const struct in_addr
*first_ipv4_iface(void)
165 for (i
=local_interfaces
;i
;i
=i
->next
) {
166 if ((i
->ip
.ss_family
== AF_INET
) &&
167 (!is_zero_ip_v4(((struct sockaddr_in
*)&i
->ip
)->sin_addr
)))
176 return &((const struct sockaddr_in
*)&i
->ip
)->sin_addr
;
179 /****************************************************************************
180 Return the Nth interface.
181 **************************************************************************/
183 struct interface
*get_interface(int n
)
187 for (i
=local_interfaces
;i
&& n
;i
=i
->next
) {
197 /****************************************************************************
198 Return IP sockaddr_storage of the Nth interface.
199 **************************************************************************/
201 const struct sockaddr_storage
*iface_n_sockaddr_storage(int n
)
205 for (i
=local_interfaces
;i
&& n
;i
=i
->next
) {
215 /****************************************************************************
216 Return IPv4 of the Nth interface (if a v4 address). NULL otherwise.
217 **************************************************************************/
219 const struct in_addr
*iface_n_ip_v4(int n
)
223 for (i
=local_interfaces
;i
&& n
;i
=i
->next
) {
227 if (i
&& i
->ip
.ss_family
== AF_INET
) {
228 return &((const struct sockaddr_in
*)&i
->ip
)->sin_addr
;
233 /****************************************************************************
234 Return IPv4 bcast of the Nth interface (if a v4 address). NULL otherwise.
235 **************************************************************************/
237 const struct in_addr
*iface_n_bcast_v4(int n
)
241 for (i
=local_interfaces
;i
&& n
;i
=i
->next
) {
245 if (i
&& i
->ip
.ss_family
== AF_INET
) {
246 return &((const struct sockaddr_in
*)&i
->bcast
)->sin_addr
;
251 /****************************************************************************
252 Return bcast of the Nth interface.
253 **************************************************************************/
255 const struct sockaddr_storage
*iface_n_bcast(int n
)
259 for (i
=local_interfaces
;i
&& n
;i
=i
->next
) {
269 /* these 3 functions return the ip/bcast/nmask for the interface
270 most appropriate for the given ip address. If they can't find
271 an appropriate interface they return the requested field of the
272 first known interface. */
274 const struct sockaddr_storage
*iface_ip(const struct sockaddr
*ip
)
276 struct interface
*i
= iface_find(ip
, true);
281 /* Search for the first interface with
282 * matching address family. */
284 for (i
=local_interfaces
;i
;i
=i
->next
) {
285 if (i
->ip
.ss_family
== ip
->sa_family
) {
293 return True if a IP is directly reachable on one of our interfaces
296 bool iface_local(const struct sockaddr
*ip
)
298 return iface_find(ip
, true) ? true : false;
301 /****************************************************************************
302 Add an interface to the linked list of interfaces.
303 ****************************************************************************/
305 static void add_interface(const struct iface_struct
*ifs
)
307 char addr
[INET6_ADDRSTRLEN
];
308 struct interface
*iface
;
310 if (iface_find((const struct sockaddr
*)&ifs
->ip
, False
)) {
311 DEBUG(3,("add_interface: not adding duplicate interface %s\n",
312 print_sockaddr(addr
, sizeof(addr
), &ifs
->ip
) ));
316 if (!(ifs
->flags
& (IFF_BROADCAST
|IFF_LOOPBACK
))) {
317 DEBUG(3,("not adding non-broadcast interface %s\n",
322 iface
= SMB_MALLOC_P(struct interface
);
327 ZERO_STRUCTPN(iface
);
329 iface
->name
= SMB_STRDUP(ifs
->name
);
334 iface
->flags
= ifs
->flags
;
336 iface
->netmask
= ifs
->netmask
;
337 iface
->bcast
= ifs
->bcast
;
338 iface
->linkspeed
= ifs
->linkspeed
;
339 iface
->capability
= ifs
->capability
;
340 iface
->if_index
= ifs
->if_index
;
341 iface
->options
= ifs
->options
;
343 DLIST_ADD(local_interfaces
, iface
);
345 DEBUG(2,("added interface %s ip=%s ",
347 print_sockaddr(addr
, sizeof(addr
), &iface
->ip
) ));
348 DEBUG(2,("bcast=%s ",
349 print_sockaddr(addr
, sizeof(addr
),
351 DEBUG(2,("netmask=%s\n",
352 print_sockaddr(addr
, sizeof(addr
),
357 static void parse_extra_info(char *key
,
363 while (key
!= NULL
&& *key
!= '\0') {
368 next_key
= strchr_m(key
, ',');
369 if (next_key
!= NULL
) {
373 val
= strchr_m(key
, '=');
377 if (strequal_m(key
, "speed")) {
378 *speed
= (uint64_t)smb_strtoull(val
,
384 DBG_DEBUG("Invalid speed value (%s)\n", val
);
386 } else if (strequal_m(key
, "capability")) {
387 if (strequal_m(val
, "RSS")) {
388 *cap
|= FSCTL_NET_IFACE_RSS_CAPABLE
;
389 } else if (strequal(val
, "RDMA")) {
390 *cap
|= FSCTL_NET_IFACE_RDMA_CAPABLE
;
392 DBG_WARNING("Capability unknown: "
395 } else if (strequal_m(key
, "if_index")) {
396 *if_index
= (uint32_t)smb_strtoul(val
,
402 DBG_DEBUG("Invalid key value (%s)\n", val
);
404 } else if (strequal_m(key
, "options")) {
405 if (strequal_m(val
, "dynamic")) {
406 *options
|= IFACE_DYNAMIC_OPTION
;
407 } else if (strequal_m(val
, "nodynamic")) {
408 *options
&= ~IFACE_DYNAMIC_OPTION
;
410 DBG_WARNING("Options unknown: "
414 DBG_DEBUG("Key unknown: '%s'\n", key
);
422 /****************************************************************************
423 Interpret a single element from a interfaces= config line.
425 This handles the following different forms:
427 1) wildcard interface name
433 Additional information for an interface can be specified with
434 this extended syntax:
436 "interface[;key1=value1[,key2=value2[...]]]"
438 Note: The double quoting is important for the
439 smb.conf parser! Otherwise the ';' and ',' separates
443 - keys known: 'speed', 'capability', 'if_index'
444 - speed is in bits per second
445 - capabilities known: 'RSS', 'RDMA'
446 - if_index should be used with care, because
447 these indexes should not conicide with indexes
450 Note: The specified values overwrite the autodetected values!
452 ****************************************************************************/
454 static void interpret_interface(char *token
)
456 struct sockaddr_storage ss
;
457 struct sockaddr_storage ss_mask
;
458 struct sockaddr_storage ss_net
;
459 struct sockaddr_storage ss_bcast
;
460 struct iface_struct ifs
;
464 bool goodaddr
= false;
466 uint32_t cap
= FSCTL_NET_IFACE_NONE_CAPABLE
;
467 uint32_t if_index
= 0;
468 bool speed_set
= false;
469 bool cap_set
= false;
470 bool if_index_set
= false;
471 uint32_t options
= IFACE_NONE_OPTION
;
472 bool options_set
= false;
475 * extract speed / capability information if present
477 p
= strchr_m(token
, ';');
480 parse_extra_info(p
, &speed
, &cap
, &if_index
, &options
);
484 if (cap
!= FSCTL_NET_IFACE_NONE_CAPABLE
) {
490 if (options
!= IFACE_NONE_OPTION
) {
495 /* first check if it is an interface name */
496 for (i
=0;i
<total_probed
;i
++) {
497 if (gen_fnmatch(token
, probed_ifaces
[i
].name
) == 0) {
499 probed_ifaces
[i
].linkspeed
= speed
;
502 probed_ifaces
[i
].capability
= cap
;
505 probed_ifaces
[i
].if_index
= if_index
;
508 probed_ifaces
[i
].options
= options
;
510 add_interface(&probed_ifaces
[i
]);
518 p
= strchr_m(token
,'/');
520 if (!interpret_string_addr(&ss
, token
, 0)) {
521 DEBUG(2, ("interpret_interface: Can't find address "
526 for (i
=0;i
<total_probed
;i
++) {
527 if (sockaddr_equal((struct sockaddr
*)&ss
,
528 (struct sockaddr
*)&probed_ifaces
[i
].ip
))
531 probed_ifaces
[i
].linkspeed
= speed
;
534 probed_ifaces
[i
].capability
= cap
;
537 probed_ifaces
[i
].if_index
= if_index
;
540 probed_ifaces
[i
].options
= options
;
542 add_interface(&probed_ifaces
[i
]);
546 DEBUG(2,("interpret_interface: "
547 "can't determine interface for %s\n",
552 /* parse it into an IP address/netmasklength pair */
554 goodaddr
= interpret_string_addr(&ss
, token
, 0);
558 DEBUG(2,("interpret_interface: "
559 "can't determine interface for %s\n",
565 goodaddr
= interpret_string_addr(&ss_mask
, p
, 0);
567 DEBUG(2,("interpret_interface: "
568 "can't determine netmask from %s\n",
576 val
= smb_strtoul(p
, NULL
, 0, &error
, SMB_STR_FULL_STR_CONV
);
578 DEBUG(2,("interpret_interface: "
579 "can't determine netmask value from %s\n",
583 if (!make_netmask(&ss_mask
, &ss
, val
)) {
584 DEBUG(2,("interpret_interface: "
585 "can't apply netmask value %lu from %s\n",
592 make_bcast(&ss_bcast
, &ss
, &ss_mask
);
593 make_net(&ss_net
, &ss
, &ss_mask
);
595 /* Maybe the first component was a broadcast address. */
596 if (sockaddr_equal((struct sockaddr
*)&ss_bcast
, (struct sockaddr
*)&ss
) ||
597 sockaddr_equal((struct sockaddr
*)&ss_net
, (struct sockaddr
*)&ss
)) {
598 for (i
=0;i
<total_probed
;i
++) {
599 if (same_net((struct sockaddr
*)&ss
,
600 (struct sockaddr
*)&probed_ifaces
[i
].ip
,
601 (struct sockaddr
*)&ss_mask
)) {
602 /* Temporarily replace netmask on
603 * the detected interface - user knows
605 struct sockaddr_storage saved_mask
=
606 probed_ifaces
[i
].netmask
;
607 probed_ifaces
[i
].netmask
= ss_mask
;
608 DEBUG(2,("interpret_interface: "
609 "using netmask value %s from "
610 "config file on interface %s\n",
612 probed_ifaces
[i
].name
));
614 probed_ifaces
[i
].linkspeed
= speed
;
617 probed_ifaces
[i
].capability
= cap
;
620 probed_ifaces
[i
].if_index
= if_index
;
623 probed_ifaces
[i
].options
= options
;
625 add_interface(&probed_ifaces
[i
]);
626 probed_ifaces
[i
].netmask
= saved_mask
;
630 DEBUG(2,("interpret_interface: Can't determine ip for "
631 "broadcast address %s\n",
636 /* Just fake up the interface definition. User knows best. */
638 DEBUG(2,("interpret_interface: Adding interface %s\n",
642 (void)strlcpy(ifs
.name
, token
, sizeof(ifs
.name
));
643 ifs
.flags
= IFF_BROADCAST
;
645 ifs
.netmask
= ss_mask
;
646 ifs
.bcast
= ss_bcast
;
648 ifs
.if_index
= if_index
;
651 ifs
.linkspeed
= speed
;
653 ifs
.linkspeed
= 1000 * 1000 * 1000;
655 ifs
.capability
= cap
;
656 ifs
.options
= options
;
660 /****************************************************************************
661 Load the list of network interfaces.
662 ****************************************************************************/
664 void load_interfaces(void)
666 struct iface_struct
*ifaces
= NULL
;
667 const char **ptr
= lp_interfaces();
672 /* Probe the kernel for interfaces */
673 total_probed
= get_interfaces(talloc_tos(), &ifaces
);
675 if (total_probed
> 0) {
676 probed_ifaces
= (struct iface_struct
*)smb_memdup(ifaces
,
677 sizeof(ifaces
[0])*total_probed
);
678 if (!probed_ifaces
) {
679 DEBUG(0,("ERROR: smb_memdup failed\n"));
685 /* if we don't have a interfaces line then use all broadcast capable
686 interfaces except loopback */
687 if (!ptr
|| !*ptr
|| !**ptr
) {
688 if (total_probed
<= 0) {
689 DEBUG(0,("ERROR: Could not determine network "
690 "interfaces, you must use a interfaces config line\n"));
693 for (i
=0;i
<total_probed
;i
++) {
694 if (probed_ifaces
[i
].flags
& IFF_BROADCAST
) {
695 add_interface(&probed_ifaces
[i
]);
703 char *ptr_cpy
= SMB_STRDUP(*ptr
);
705 interpret_interface(ptr_cpy
);
712 if (!local_interfaces
) {
713 DEBUG(0,("WARNING: no network interfaces found\n"));
718 void gfree_interfaces(void)
720 while (local_interfaces
) {
721 struct interface
*iface
= local_interfaces
;
722 DLIST_REMOVE(local_interfaces
, local_interfaces
);
723 SAFE_FREE(iface
->name
);
727 SAFE_FREE(probed_ifaces
);
730 /****************************************************************************
731 Return True if the list of probed interfaces has changed.
732 ****************************************************************************/
734 bool interfaces_changed(void)
738 struct iface_struct
*ifaces
= NULL
;
740 n
= get_interfaces(talloc_tos(), &ifaces
);
742 if ((n
> 0 )&& (n
!= total_probed
||
743 memcmp(ifaces
, probed_ifaces
, sizeof(ifaces
[0])*n
))) {
751 /****************************************************************************
752 Return True if interface exists for given interface index and options
753 **************************************************************************/
755 bool interface_ifindex_exists_with_options(int if_index
, uint32_t options
)
757 struct interface
*i
= NULL
;
759 for (i
= local_interfaces
; i
!= NULL
; i
= i
->next
) {
760 if ((i
->if_index
== if_index
) && (i
->options
& options
)) {