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') {
363 next_key = strchr_m(key, ',');
364 if (next_key != NULL) {
368 val = strchr_m(key, '=');
372 if (strequal_m(key, "speed")) {
373 *speed = (uint64_t)strtoull_err(val, NULL, 0, &error);
375 DBG_DEBUG("Invalid speed value (%s)\n", val);
377 } else if (strequal_m(key, "capability")) {
378 if (strequal_m(val, "RSS")) {
379 *cap |= FSCTL_NET_IFACE_RSS_CAPABLE;
380 } else if (strequal(val, "RDMA")) {
381 *cap |= FSCTL_NET_IFACE_RDMA_CAPABLE;
383 DBG_WARNING("Capability unknown: "
386 } else if (strequal_m(key, "if_index")) {
387 *if_index = (uint32_t)strtoul_err(val, NULL, 0, &error);
389 DBG_DEBUG("Invalid key value (%s)\n", val);
392 DBG_DEBUG("Key unknown: '%s'\n", key);
400 /****************************************************************************
401 Interpret a single element from a interfaces= config line.
403 This handles the following different forms:
405 1) wildcard interface name
411 Additional information for an interface can be specified with
412 this extended syntax:
414 interface[;key1=value1[,key2=value2[...]]]
417 - keys known: 'speed', 'capability', 'if_index'
418 - speed is in bits per second
419 - capabilites known: 'RSS', 'RDMA'
420 - if_index should be used with care, because
421 these indexes should not conicide with indexes
424 ****************************************************************************/
426 static void interpret_interface(char *token)
428 struct sockaddr_storage ss;
429 struct sockaddr_storage ss_mask;
430 struct sockaddr_storage ss_net;
431 struct sockaddr_storage ss_bcast;
432 struct iface_struct ifs;
436 bool goodaddr = false;
438 uint32_t cap = FSCTL_NET_IFACE_NONE_CAPABLE;
439 uint32_t if_index = 0;
440 bool speed_set = false;
441 bool cap_set = false;
442 bool if_index_set = false;
444 /* first check if it is an interface name */
445 for (i=0;i<total_probed;i++) {
446 if (gen_fnmatch(token, probed_ifaces[i].name) == 0) {
447 add_interface(&probed_ifaces[i]);
456 * extract speed / capability information if present
458 p = strchr_m(token, ';');
461 parse_extra_info(p, &speed, &cap, &if_index);
465 if (cap != FSCTL_NET_IFACE_NONE_CAPABLE) {
473 p = strchr_m(token,'/');
475 if (!interpret_string_addr(&ss, token, 0)) {
476 DEBUG(2, ("interpret_interface: Can't find address "
481 for (i=0;i<total_probed;i++) {
482 if (sockaddr_equal((struct sockaddr *)&ss,
483 (struct sockaddr *)&probed_ifaces[i].ip))
486 probed_ifaces[i].linkspeed = speed;
489 probed_ifaces[i].capability = cap;
492 probed_ifaces[i].if_index = if_index;
494 add_interface(&probed_ifaces[i]);
498 DEBUG(2,("interpret_interface: "
499 "can't determine interface for %s\n",
504 /* parse it into an IP address/netmasklength pair */
506 goodaddr = interpret_string_addr(&ss, token, 0);
510 DEBUG(2,("interpret_interface: "
511 "can't determine interface for %s\n",
517 goodaddr = interpret_string_addr(&ss_mask, p, 0);
519 DEBUG(2,("interpret_interface: "
520 "can't determine netmask from %s\n",
529 val = strtoul_err(p, &endp, 0, &error);
530 if (p == endp || (endp && *endp != '\0') || error != 0) {
531 DEBUG(2,("interpret_interface: "
532 "can't determine netmask value from %s\n",
536 if (!make_netmask(&ss_mask, &ss, val)) {
537 DEBUG(2,("interpret_interface: "
538 "can't apply netmask value %lu from %s\n",
545 make_bcast(&ss_bcast, &ss, &ss_mask);
546 make_net(&ss_net, &ss, &ss_mask);
548 /* Maybe the first component was a broadcast address. */
549 if (sockaddr_equal((struct sockaddr *)&ss_bcast, (struct sockaddr *)&ss) ||
550 sockaddr_equal((struct sockaddr *)&ss_net, (struct sockaddr *)&ss)) {
551 for (i=0;i<total_probed;i++) {
552 if (same_net((struct sockaddr *)&ss,
553 (struct sockaddr *)&probed_ifaces[i].ip,
554 (struct sockaddr *)&ss_mask)) {
555 /* Temporarily replace netmask on
556 * the detected interface - user knows
558 struct sockaddr_storage saved_mask =
559 probed_ifaces[i].netmask;
560 probed_ifaces[i].netmask = ss_mask;
561 DEBUG(2,("interpret_interface: "
562 "using netmask value %s from "
563 "config file on interface %s\n",
565 probed_ifaces[i].name));
567 probed_ifaces[i].linkspeed = speed;
570 probed_ifaces[i].capability = cap;
573 probed_ifaces[i].if_index = if_index;
575 add_interface(&probed_ifaces[i]);
576 probed_ifaces[i].netmask = saved_mask;
580 DEBUG(2,("interpret_interface: Can't determine ip for "
581 "broadcast address %s\n",
586 /* Just fake up the interface definition. User knows best. */
588 DEBUG(2,("interpret_interface: Adding interface %s\n",
592 (void)strlcpy(ifs.name, token, sizeof(ifs.name));
593 ifs.flags = IFF_BROADCAST;
595 ifs.netmask = ss_mask;
596 ifs.bcast = ss_bcast;
598 probed_ifaces[i].if_index = if_index;
601 ifs.linkspeed = speed;
603 ifs.linkspeed = 1000 * 1000 * 1000;
605 ifs.capability = cap;
609 /****************************************************************************
610 Load the list of network interfaces.
611 ****************************************************************************/
613 void load_interfaces(void)
615 struct iface_struct *ifaces = NULL;
616 const char **ptr = lp_interfaces();
621 /* Probe the kernel for interfaces */
622 total_probed = get_interfaces(talloc_tos(), &ifaces);
624 if (total_probed > 0) {
625 probed_ifaces = (struct iface_struct *)smb_memdup(ifaces,
626 sizeof(ifaces[0])*total_probed);
627 if (!probed_ifaces) {
628 DEBUG(0,("ERROR: smb_memdup failed\n"));
634 /* if we don't have a interfaces line then use all broadcast capable
635 interfaces except loopback */
636 if (!ptr || !*ptr || !**ptr) {
637 if (total_probed <= 0) {
638 DEBUG(0,("ERROR: Could not determine network "
639 "interfaces, you must use a interfaces config line\n"));
642 for (i=0;i<total_probed;i++) {
643 if (probed_ifaces[i].flags & IFF_BROADCAST) {
644 add_interface(&probed_ifaces[i]);
652 char *ptr_cpy = SMB_STRDUP(*ptr);
654 interpret_interface(ptr_cpy);
661 if (!local_interfaces) {
662 DEBUG(0,("WARNING: no network interfaces found\n"));
667 void gfree_interfaces(void)
669 while (local_interfaces) {
670 struct interface *iface = local_interfaces;
671 DLIST_REMOVE(local_interfaces, local_interfaces);
672 SAFE_FREE(iface->name);
676 SAFE_FREE(probed_ifaces);
679 /****************************************************************************
680 Return True if the list of probed interfaces has changed.
681 ****************************************************************************/
683 bool interfaces_changed(void)
687 struct iface_struct *ifaces = NULL;
689 n = get_interfaces(talloc_tos(), &ifaces);
691 if ((n > 0 )&& (n != total_probed ||
692 memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) {