libsmb: Use clistr_smb2_extract_snapshot_token() in cli_smb2_create_fnum_send()
[Samba.git] / source3 / lib / interface.c
blob440d74cab993dc8aeb12ad7857dd33c04fc20249
1 /*
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/>.
21 #include "includes.h"
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)
37 struct interface *i;
38 for (i=local_interfaces;i;i=i->next) {
39 if (sockaddr_equal((struct sockaddr *)&i->ip,ip)) {
40 return true;
43 return false;
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,
58 bool check_mask)
60 struct interface *i;
62 if (is_address_any(ip)) {
63 return local_interfaces;
66 for (i=local_interfaces;i;i=i->next) {
67 if (check_mask) {
68 if (same_net(ip, (struct sockaddr *)&i->ip, (struct sockaddr *)&i->netmask)) {
69 return i;
71 } else if (sockaddr_equal((struct sockaddr *)&i->ip, ip)) {
72 return i;
76 return NULL;
79 /****************************************************************************
80 Check if a packet is from a local (known) net.
81 **************************************************************************/
83 bool is_local_net(const struct sockaddr *from)
85 struct interface *i;
86 for (i=local_interfaces;i;i=i->next) {
87 if (same_net(from, (struct sockaddr *)&i->ip, (struct sockaddr *)&i->netmask)) {
88 return true;
91 return false;
94 #if defined(HAVE_IPV6)
95 void setup_linklocal_scope_id(struct sockaddr *pss)
97 struct interface *i;
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);
103 return;
107 #endif
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)
127 int ret = 0;
128 struct interface *i;
130 for (i=local_interfaces;i;i=i->next) {
131 ret++;
133 return ret;
136 /****************************************************************************
137 How many non-loopback IPv4 interfaces do we have ?
138 **************************************************************************/
140 int iface_count_v4_nl(void)
142 int ret = 0;
143 struct interface *i;
145 for (i=local_interfaces;i;i=i->next) {
146 if (is_loopback_addr((struct sockaddr *)&i->ip)) {
147 continue;
149 if (i->ip.ss_family == AF_INET) {
150 ret++;
153 return ret;
156 /****************************************************************************
157 Return a pointer to the in_addr of the first IPv4 interface that's
158 not 0.0.0.0.
159 **************************************************************************/
161 const struct in_addr *first_ipv4_iface(void)
163 struct interface *i;
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)))
169 break;
173 if (!i) {
174 return NULL;
176 return &((const struct sockaddr_in *)&i->ip)->sin_addr;
179 /****************************************************************************
180 Return the Nth interface.
181 **************************************************************************/
183 struct interface *get_interface(int n)
185 struct interface *i;
187 for (i=local_interfaces;i && n;i=i->next) {
188 n--;
191 if (i) {
192 return i;
194 return NULL;
197 /****************************************************************************
198 Return IP sockaddr_storage of the Nth interface.
199 **************************************************************************/
201 const struct sockaddr_storage *iface_n_sockaddr_storage(int n)
203 struct interface *i;
205 for (i=local_interfaces;i && n;i=i->next) {
206 n--;
209 if (i) {
210 return &i->ip;
212 return NULL;
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)
221 struct interface *i;
223 for (i=local_interfaces;i && n;i=i->next) {
224 n--;
227 if (i && i->ip.ss_family == AF_INET) {
228 return &((const struct sockaddr_in *)&i->ip)->sin_addr;
230 return NULL;
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)
239 struct interface *i;
241 for (i=local_interfaces;i && n;i=i->next) {
242 n--;
245 if (i && i->ip.ss_family == AF_INET) {
246 return &((const struct sockaddr_in *)&i->bcast)->sin_addr;
248 return NULL;
251 /****************************************************************************
252 Return bcast of the Nth interface.
253 **************************************************************************/
255 const struct sockaddr_storage *iface_n_bcast(int n)
257 struct interface *i;
259 for (i=local_interfaces;i && n;i=i->next) {
260 n--;
263 if (i) {
264 return &i->bcast;
266 return NULL;
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);
277 if (i) {
278 return &i->ip;
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) {
286 return &i->ip;
289 return NULL;
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) ));
313 return;
316 if (!(ifs->flags & (IFF_BROADCAST|IFF_LOOPBACK))) {
317 DEBUG(3,("not adding non-broadcast interface %s\n",
318 ifs->name ));
319 return;
322 iface = SMB_MALLOC_P(struct interface);
323 if (!iface) {
324 return;
327 ZERO_STRUCTPN(iface);
329 iface->name = SMB_STRDUP(ifs->name);
330 if (!iface->name) {
331 SAFE_FREE(iface);
332 return;
334 iface->flags = ifs->flags;
335 iface->ip = ifs->ip;
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 ",
345 iface->name,
346 print_sockaddr(addr, sizeof(addr), &iface->ip) ));
347 DEBUG(2,("bcast=%s ",
348 print_sockaddr(addr, sizeof(addr),
349 &iface->bcast) ));
350 DEBUG(2,("netmask=%s\n",
351 print_sockaddr(addr, sizeof(addr),
352 &iface->netmask) ));
356 static void parse_extra_info(char *key, uint64_t *speed, uint32_t *cap,
357 uint32_t *if_index)
359 while (key != NULL && *key != '\0') {
360 char *next_key;
361 char *val;
362 int error = 0;
364 next_key = strchr_m(key, ',');
365 if (next_key != NULL) {
366 *next_key++ = 0;
369 val = strchr_m(key, '=');
370 if (val != NULL) {
371 *val++ = 0;
373 if (strequal_m(key, "speed")) {
374 *speed = (uint64_t)smb_strtoull(val,
375 NULL,
377 &error,
378 SMB_STR_STANDARD);
379 if (error != 0) {
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;
387 } else {
388 DBG_WARNING("Capability unknown: "
389 "'%s'\n", val);
391 } else if (strequal_m(key, "if_index")) {
392 *if_index = (uint32_t)smb_strtoul(val,
393 NULL,
395 &error,
396 SMB_STR_STANDARD);
397 if (error != 0) {
398 DBG_DEBUG("Invalid key value (%s)\n", val);
400 } else {
401 DBG_DEBUG("Key unknown: '%s'\n", key);
405 key = next_key;
409 /****************************************************************************
410 Interpret a single element from a interfaces= config line.
412 This handles the following different forms:
414 1) wildcard interface name
415 2) DNS name
416 3) IP/masklen
417 4) ip/mask
418 5) bcast/mask
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
427 two interfaces.
429 where
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
435 the kernel sets...
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;
448 char *p;
449 int i;
450 bool added=false;
451 bool goodaddr = false;
452 uint64_t speed = 0;
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, ';');
463 if (p != NULL) {
464 *p++ = 0;
465 parse_extra_info(p, &speed, &cap, &if_index);
466 if (speed != 0) {
467 speed_set = true;
469 if (cap != FSCTL_NET_IFACE_NONE_CAPABLE) {
470 cap_set = true;
472 if (if_index != 0) {
473 if_index_set = true;
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) {
480 if (speed_set) {
481 probed_ifaces[i].linkspeed = speed;
483 if (cap_set) {
484 probed_ifaces[i].capability = cap;
486 if (if_index_set) {
487 probed_ifaces[i].if_index = if_index;
489 add_interface(&probed_ifaces[i]);
490 added = true;
493 if (added) {
494 return;
497 p = strchr_m(token,'/');
498 if (p == NULL) {
499 if (!interpret_string_addr(&ss, token, 0)) {
500 DEBUG(2, ("interpret_interface: Can't find address "
501 "for %s\n", token));
502 return;
505 for (i=0;i<total_probed;i++) {
506 if (sockaddr_equal((struct sockaddr *)&ss,
507 (struct sockaddr *)&probed_ifaces[i].ip))
509 if (speed_set) {
510 probed_ifaces[i].linkspeed = speed;
512 if (cap_set) {
513 probed_ifaces[i].capability = cap;
515 if (if_index_set) {
516 probed_ifaces[i].if_index = if_index;
518 add_interface(&probed_ifaces[i]);
519 return;
522 DEBUG(2,("interpret_interface: "
523 "can't determine interface for %s\n",
524 token));
525 return;
528 /* parse it into an IP address/netmasklength pair */
529 *p = 0;
530 goodaddr = interpret_string_addr(&ss, token, 0);
531 *p++ = '/';
533 if (!goodaddr) {
534 DEBUG(2,("interpret_interface: "
535 "can't determine interface for %s\n",
536 token));
537 return;
540 if (strlen(p) > 2) {
541 goodaddr = interpret_string_addr(&ss_mask, p, 0);
542 if (!goodaddr) {
543 DEBUG(2,("interpret_interface: "
544 "can't determine netmask from %s\n",
545 p));
546 return;
548 } else {
549 int error = 0;
550 unsigned long val;
552 val = smb_strtoul(p, NULL, 0, &error, SMB_STR_FULL_STR_CONV);
553 if (error != 0) {
554 DEBUG(2,("interpret_interface: "
555 "can't determine netmask value from %s\n",
556 p));
557 return;
559 if (!make_netmask(&ss_mask, &ss, val)) {
560 DEBUG(2,("interpret_interface: "
561 "can't apply netmask value %lu from %s\n",
562 val,
563 p));
564 return;
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
580 * best.... */
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));
589 if (speed_set) {
590 probed_ifaces[i].linkspeed = speed;
592 if (cap_set) {
593 probed_ifaces[i].capability = cap;
595 if (if_index_set) {
596 probed_ifaces[i].if_index = if_index;
598 add_interface(&probed_ifaces[i]);
599 probed_ifaces[i].netmask = saved_mask;
600 return;
603 DEBUG(2,("interpret_interface: Can't determine ip for "
604 "broadcast address %s\n",
605 token));
606 return;
609 /* Just fake up the interface definition. User knows best. */
611 DEBUG(2,("interpret_interface: Adding interface %s\n",
612 token));
614 ZERO_STRUCT(ifs);
615 (void)strlcpy(ifs.name, token, sizeof(ifs.name));
616 ifs.flags = IFF_BROADCAST;
617 ifs.ip = ss;
618 ifs.netmask = ss_mask;
619 ifs.bcast = ss_bcast;
620 if (if_index_set) {
621 ifs.if_index = if_index;
623 if (speed_set) {
624 ifs.linkspeed = speed;
625 } else {
626 ifs.linkspeed = 1000 * 1000 * 1000;
628 ifs.capability = cap;
629 add_interface(&ifs);
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();
640 int i;
642 gfree_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"));
652 exit(1);
655 TALLOC_FREE(ifaces);
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"));
663 exit(1);
665 for (i=0;i<total_probed;i++) {
666 if (probed_ifaces[i].flags & IFF_BROADCAST) {
667 add_interface(&probed_ifaces[i]);
670 return;
673 if (ptr) {
674 while (*ptr) {
675 char *ptr_cpy = SMB_STRDUP(*ptr);
676 if (ptr_cpy) {
677 interpret_interface(ptr_cpy);
678 free(ptr_cpy);
680 ptr++;
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);
696 SAFE_FREE(iface);
699 SAFE_FREE(probed_ifaces);
702 /****************************************************************************
703 Return True if the list of probed interfaces has changed.
704 ****************************************************************************/
706 bool interfaces_changed(void)
708 bool ret = false;
709 int n;
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))) {
716 ret = true;
719 TALLOC_FREE(ifaces);
720 return ret;