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
;
342 DLIST_ADD(local_interfaces
, iface
);
344 DEBUG(2,("added interface %s ip=%s ",
346 print_sockaddr(addr
, sizeof(addr
), &iface
->ip
) ));
347 DEBUG(2,("bcast=%s ",
348 print_sockaddr(addr
, sizeof(addr
),
350 DEBUG(2,("netmask=%s\n",
351 print_sockaddr(addr
, sizeof(addr
),
356 static void parse_extra_info(char *key
, uint64_t *speed
, uint32_t *cap
,
359 while (key
!= NULL
&& *key
!= '\0') {
364 next_key
= strchr_m(key
, ',');
365 if (next_key
!= NULL
) {
369 val
= strchr_m(key
, '=');
373 if (strequal_m(key
, "speed")) {
374 *speed
= (uint64_t)smb_strtoull(val
,
380 DBG_DEBUG("Invalid speed value (%s)\n", val
);
382 } else if (strequal_m(key
, "capability")) {
383 if (strequal_m(val
, "RSS")) {
384 *cap
|= FSCTL_NET_IFACE_RSS_CAPABLE
;
385 } else if (strequal(val
, "RDMA")) {
386 *cap
|= FSCTL_NET_IFACE_RDMA_CAPABLE
;
388 DBG_WARNING("Capability unknown: "
391 } else if (strequal_m(key
, "if_index")) {
392 *if_index
= (uint32_t)smb_strtoul(val
,
398 DBG_DEBUG("Invalid key value (%s)\n", val
);
401 DBG_DEBUG("Key unknown: '%s'\n", key
);
409 /****************************************************************************
410 Interpret a single element from a interfaces= config line.
412 This handles the following different forms:
414 1) wildcard interface name
420 Additional information for an interface can be specified with
421 this extended syntax:
423 "interface[;key1=value1[,key2=value2[...]]]"
425 Note: The double quoting is important for the
426 smb.conf parser! Otherwise the ';' and ',' separates
430 - keys known: 'speed', 'capability', 'if_index'
431 - speed is in bits per second
432 - capabilites known: 'RSS', 'RDMA'
433 - if_index should be used with care, because
434 these indexes should not conicide with indexes
437 Note: The specified values overwrite the autodetected values!
439 ****************************************************************************/
441 static void interpret_interface(char *token
)
443 struct sockaddr_storage ss
;
444 struct sockaddr_storage ss_mask
;
445 struct sockaddr_storage ss_net
;
446 struct sockaddr_storage ss_bcast
;
447 struct iface_struct ifs
;
451 bool goodaddr
= false;
453 uint32_t cap
= FSCTL_NET_IFACE_NONE_CAPABLE
;
454 uint32_t if_index
= 0;
455 bool speed_set
= false;
456 bool cap_set
= false;
457 bool if_index_set
= false;
460 * extract speed / capability information if present
462 p
= strchr_m(token
, ';');
465 parse_extra_info(p
, &speed
, &cap
, &if_index
);
469 if (cap
!= FSCTL_NET_IFACE_NONE_CAPABLE
) {
477 /* first check if it is an interface name */
478 for (i
=0;i
<total_probed
;i
++) {
479 if (gen_fnmatch(token
, probed_ifaces
[i
].name
) == 0) {
481 probed_ifaces
[i
].linkspeed
= speed
;
484 probed_ifaces
[i
].capability
= cap
;
487 probed_ifaces
[i
].if_index
= if_index
;
489 add_interface(&probed_ifaces
[i
]);
497 p
= strchr_m(token
,'/');
499 if (!interpret_string_addr(&ss
, token
, 0)) {
500 DEBUG(2, ("interpret_interface: Can't find address "
505 for (i
=0;i
<total_probed
;i
++) {
506 if (sockaddr_equal((struct sockaddr
*)&ss
,
507 (struct sockaddr
*)&probed_ifaces
[i
].ip
))
510 probed_ifaces
[i
].linkspeed
= speed
;
513 probed_ifaces
[i
].capability
= cap
;
516 probed_ifaces
[i
].if_index
= if_index
;
518 add_interface(&probed_ifaces
[i
]);
522 DEBUG(2,("interpret_interface: "
523 "can't determine interface for %s\n",
528 /* parse it into an IP address/netmasklength pair */
530 goodaddr
= interpret_string_addr(&ss
, token
, 0);
534 DEBUG(2,("interpret_interface: "
535 "can't determine interface for %s\n",
541 goodaddr
= interpret_string_addr(&ss_mask
, p
, 0);
543 DEBUG(2,("interpret_interface: "
544 "can't determine netmask from %s\n",
552 val
= smb_strtoul(p
, NULL
, 0, &error
, SMB_STR_FULL_STR_CONV
);
554 DEBUG(2,("interpret_interface: "
555 "can't determine netmask value from %s\n",
559 if (!make_netmask(&ss_mask
, &ss
, val
)) {
560 DEBUG(2,("interpret_interface: "
561 "can't apply netmask value %lu from %s\n",
568 make_bcast(&ss_bcast
, &ss
, &ss_mask
);
569 make_net(&ss_net
, &ss
, &ss_mask
);
571 /* Maybe the first component was a broadcast address. */
572 if (sockaddr_equal((struct sockaddr
*)&ss_bcast
, (struct sockaddr
*)&ss
) ||
573 sockaddr_equal((struct sockaddr
*)&ss_net
, (struct sockaddr
*)&ss
)) {
574 for (i
=0;i
<total_probed
;i
++) {
575 if (same_net((struct sockaddr
*)&ss
,
576 (struct sockaddr
*)&probed_ifaces
[i
].ip
,
577 (struct sockaddr
*)&ss_mask
)) {
578 /* Temporarily replace netmask on
579 * the detected interface - user knows
581 struct sockaddr_storage saved_mask
=
582 probed_ifaces
[i
].netmask
;
583 probed_ifaces
[i
].netmask
= ss_mask
;
584 DEBUG(2,("interpret_interface: "
585 "using netmask value %s from "
586 "config file on interface %s\n",
588 probed_ifaces
[i
].name
));
590 probed_ifaces
[i
].linkspeed
= speed
;
593 probed_ifaces
[i
].capability
= cap
;
596 probed_ifaces
[i
].if_index
= if_index
;
598 add_interface(&probed_ifaces
[i
]);
599 probed_ifaces
[i
].netmask
= saved_mask
;
603 DEBUG(2,("interpret_interface: Can't determine ip for "
604 "broadcast address %s\n",
609 /* Just fake up the interface definition. User knows best. */
611 DEBUG(2,("interpret_interface: Adding interface %s\n",
615 (void)strlcpy(ifs
.name
, token
, sizeof(ifs
.name
));
616 ifs
.flags
= IFF_BROADCAST
;
618 ifs
.netmask
= ss_mask
;
619 ifs
.bcast
= ss_bcast
;
621 ifs
.if_index
= if_index
;
624 ifs
.linkspeed
= speed
;
626 ifs
.linkspeed
= 1000 * 1000 * 1000;
628 ifs
.capability
= cap
;
632 /****************************************************************************
633 Load the list of network interfaces.
634 ****************************************************************************/
636 void load_interfaces(void)
638 struct iface_struct
*ifaces
= NULL
;
639 const char **ptr
= lp_interfaces();
644 /* Probe the kernel for interfaces */
645 total_probed
= get_interfaces(talloc_tos(), &ifaces
);
647 if (total_probed
> 0) {
648 probed_ifaces
= (struct iface_struct
*)smb_memdup(ifaces
,
649 sizeof(ifaces
[0])*total_probed
);
650 if (!probed_ifaces
) {
651 DEBUG(0,("ERROR: smb_memdup failed\n"));
657 /* if we don't have a interfaces line then use all broadcast capable
658 interfaces except loopback */
659 if (!ptr
|| !*ptr
|| !**ptr
) {
660 if (total_probed
<= 0) {
661 DEBUG(0,("ERROR: Could not determine network "
662 "interfaces, you must use a interfaces config line\n"));
665 for (i
=0;i
<total_probed
;i
++) {
666 if (probed_ifaces
[i
].flags
& IFF_BROADCAST
) {
667 add_interface(&probed_ifaces
[i
]);
675 char *ptr_cpy
= SMB_STRDUP(*ptr
);
677 interpret_interface(ptr_cpy
);
684 if (!local_interfaces
) {
685 DEBUG(0,("WARNING: no network interfaces found\n"));
690 void gfree_interfaces(void)
692 while (local_interfaces
) {
693 struct interface
*iface
= local_interfaces
;
694 DLIST_REMOVE(local_interfaces
, local_interfaces
);
695 SAFE_FREE(iface
->name
);
699 SAFE_FREE(probed_ifaces
);
702 /****************************************************************************
703 Return True if the list of probed interfaces has changed.
704 ****************************************************************************/
706 bool interfaces_changed(void)
710 struct iface_struct
*ifaces
= NULL
;
712 n
= get_interfaces(talloc_tos(), &ifaces
);
714 if ((n
> 0 )&& (n
!= total_probed
||
715 memcmp(ifaces
, probed_ifaces
, sizeof(ifaces
[0])*n
))) {