smbd: Simplify filename_convert_dirfsp_nosymlink()
[samba4-gss.git] / source3 / lib / interface.c
blob032362b4da38f2bfb43caea7981365e8969d3ee5
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;
341 iface->options = ifs->options;
343 DLIST_ADD(local_interfaces, iface);
345 DEBUG(2,("added interface %s ip=%s ",
346 iface->name,
347 print_sockaddr(addr, sizeof(addr), &iface->ip) ));
348 DEBUG(2,("bcast=%s ",
349 print_sockaddr(addr, sizeof(addr),
350 &iface->bcast) ));
351 DEBUG(2,("netmask=%s\n",
352 print_sockaddr(addr, sizeof(addr),
353 &iface->netmask) ));
357 static void parse_extra_info(char *key,
358 uint64_t *speed,
359 uint32_t *cap,
360 uint32_t *if_index,
361 uint32_t *options)
363 while (key != NULL && *key != '\0') {
364 char *next_key;
365 char *val;
366 int error = 0;
368 next_key = strchr_m(key, ',');
369 if (next_key != NULL) {
370 *next_key++ = 0;
373 val = strchr_m(key, '=');
374 if (val != NULL) {
375 *val++ = 0;
377 if (strequal_m(key, "speed")) {
378 *speed = (uint64_t)smb_strtoull(val,
379 NULL,
381 &error,
382 SMB_STR_STANDARD);
383 if (error != 0) {
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;
391 } else {
392 DBG_WARNING("Capability unknown: "
393 "'%s'\n", val);
395 } else if (strequal_m(key, "if_index")) {
396 *if_index = (uint32_t)smb_strtoul(val,
397 NULL,
399 &error,
400 SMB_STR_STANDARD);
401 if (error != 0) {
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;
409 } else {
410 DBG_WARNING("Options unknown: "
411 "'%s'\n", val);
413 } else {
414 DBG_DEBUG("Key unknown: '%s'\n", key);
418 key = next_key;
422 /****************************************************************************
423 Interpret a single element from a interfaces= config line.
425 This handles the following different forms:
427 1) wildcard interface name
428 2) DNS name
429 3) IP/masklen
430 4) ip/mask
431 5) bcast/mask
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
440 two interfaces.
442 where
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
448 the kernel sets...
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;
461 char *p;
462 int i;
463 bool added=false;
464 bool goodaddr = false;
465 uint64_t speed = 0;
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, ';');
478 if (p != NULL) {
479 *p++ = 0;
480 parse_extra_info(p, &speed, &cap, &if_index, &options);
481 if (speed != 0) {
482 speed_set = true;
484 if (cap != FSCTL_NET_IFACE_NONE_CAPABLE) {
485 cap_set = true;
487 if (if_index != 0) {
488 if_index_set = true;
490 if (options != IFACE_NONE_OPTION) {
491 options_set = true;
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) {
498 if (speed_set) {
499 probed_ifaces[i].linkspeed = speed;
501 if (cap_set) {
502 probed_ifaces[i].capability = cap;
504 if (if_index_set) {
505 probed_ifaces[i].if_index = if_index;
507 if (options_set) {
508 probed_ifaces[i].options = options;
510 add_interface(&probed_ifaces[i]);
511 added = true;
514 if (added) {
515 return;
518 p = strchr_m(token,'/');
519 if (p == NULL) {
520 if (!interpret_string_addr(&ss, token, 0)) {
521 DEBUG(2, ("interpret_interface: Can't find address "
522 "for %s\n", token));
523 return;
526 for (i=0;i<total_probed;i++) {
527 if (sockaddr_equal((struct sockaddr *)&ss,
528 (struct sockaddr *)&probed_ifaces[i].ip))
530 if (speed_set) {
531 probed_ifaces[i].linkspeed = speed;
533 if (cap_set) {
534 probed_ifaces[i].capability = cap;
536 if (if_index_set) {
537 probed_ifaces[i].if_index = if_index;
539 if (options_set) {
540 probed_ifaces[i].options = options;
542 add_interface(&probed_ifaces[i]);
543 return;
546 DEBUG(2,("interpret_interface: "
547 "can't determine interface for %s\n",
548 token));
549 return;
552 /* parse it into an IP address/netmasklength pair */
553 *p = 0;
554 goodaddr = interpret_string_addr(&ss, token, 0);
555 *p++ = '/';
557 if (!goodaddr) {
558 DEBUG(2,("interpret_interface: "
559 "can't determine interface for %s\n",
560 token));
561 return;
564 if (strlen(p) > 2) {
565 goodaddr = interpret_string_addr(&ss_mask, p, 0);
566 if (!goodaddr) {
567 DEBUG(2,("interpret_interface: "
568 "can't determine netmask from %s\n",
569 p));
570 return;
572 } else {
573 int error = 0;
574 unsigned long val;
576 val = smb_strtoul(p, NULL, 0, &error, SMB_STR_FULL_STR_CONV);
577 if (error != 0) {
578 DEBUG(2,("interpret_interface: "
579 "can't determine netmask value from %s\n",
580 p));
581 return;
583 if (!make_netmask(&ss_mask, &ss, val)) {
584 DEBUG(2,("interpret_interface: "
585 "can't apply netmask value %lu from %s\n",
586 val,
587 p));
588 return;
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
604 * best.... */
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));
613 if (speed_set) {
614 probed_ifaces[i].linkspeed = speed;
616 if (cap_set) {
617 probed_ifaces[i].capability = cap;
619 if (if_index_set) {
620 probed_ifaces[i].if_index = if_index;
622 if (options_set) {
623 probed_ifaces[i].options = options;
625 add_interface(&probed_ifaces[i]);
626 probed_ifaces[i].netmask = saved_mask;
627 return;
630 DEBUG(2,("interpret_interface: Can't determine ip for "
631 "broadcast address %s\n",
632 token));
633 return;
636 /* Just fake up the interface definition. User knows best. */
638 DEBUG(2,("interpret_interface: Adding interface %s\n",
639 token));
641 ZERO_STRUCT(ifs);
642 (void)strlcpy(ifs.name, token, sizeof(ifs.name));
643 ifs.flags = IFF_BROADCAST;
644 ifs.ip = ss;
645 ifs.netmask = ss_mask;
646 ifs.bcast = ss_bcast;
647 if (if_index_set) {
648 ifs.if_index = if_index;
650 if (speed_set) {
651 ifs.linkspeed = speed;
652 } else {
653 ifs.linkspeed = 1000 * 1000 * 1000;
655 ifs.capability = cap;
656 ifs.options = options;
657 add_interface(&ifs);
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();
668 int i;
670 gfree_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"));
680 exit(1);
683 TALLOC_FREE(ifaces);
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"));
691 exit(1);
693 for (i=0;i<total_probed;i++) {
694 if (probed_ifaces[i].flags & IFF_BROADCAST) {
695 add_interface(&probed_ifaces[i]);
698 return;
701 if (ptr) {
702 while (*ptr) {
703 char *ptr_cpy = SMB_STRDUP(*ptr);
704 if (ptr_cpy) {
705 interpret_interface(ptr_cpy);
706 free(ptr_cpy);
708 ptr++;
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);
724 SAFE_FREE(iface);
727 SAFE_FREE(probed_ifaces);
730 /****************************************************************************
731 Return True if the list of probed interfaces has changed.
732 ****************************************************************************/
734 bool interfaces_changed(void)
736 bool ret = false;
737 int n;
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))) {
744 ret = true;
747 TALLOC_FREE(ifaces);
748 return ret;
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)) {
761 return true;
765 return false;