python/samba: Another object.next() to next(object) py2/py3 converstion
[Samba.git] / source3 / lib / interface.c
bloba3bc5d24e9114774991747492f577b02fbe434e0
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"
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)
36 struct interface *i;
37 for (i=local_interfaces;i;i=i->next) {
38 if (sockaddr_equal((struct sockaddr *)&i->ip,ip)) {
39 return true;
42 return false;
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,
57 bool check_mask)
59 struct interface *i;
61 if (is_address_any(ip)) {
62 return local_interfaces;
65 for (i=local_interfaces;i;i=i->next) {
66 if (check_mask) {
67 if (same_net(ip, (struct sockaddr *)&i->ip, (struct sockaddr *)&i->netmask)) {
68 return i;
70 } else if (sockaddr_equal((struct sockaddr *)&i->ip, ip)) {
71 return i;
75 return NULL;
78 /****************************************************************************
79 Check if a packet is from a local (known) net.
80 **************************************************************************/
82 bool is_local_net(const struct sockaddr *from)
84 struct interface *i;
85 for (i=local_interfaces;i;i=i->next) {
86 if (same_net(from, (struct sockaddr *)&i->ip, (struct sockaddr *)&i->netmask)) {
87 return true;
90 return false;
93 #if defined(HAVE_IPV6)
94 void setup_linklocal_scope_id(struct sockaddr *pss)
96 struct interface *i;
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);
102 return;
106 #endif
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)
126 int ret = 0;
127 struct interface *i;
129 for (i=local_interfaces;i;i=i->next) {
130 ret++;
132 return ret;
135 /****************************************************************************
136 How many non-loopback IPv4 interfaces do we have ?
137 **************************************************************************/
139 int iface_count_v4_nl(void)
141 int ret = 0;
142 struct interface *i;
144 for (i=local_interfaces;i;i=i->next) {
145 if (is_loopback_addr((struct sockaddr *)&i->ip)) {
146 continue;
148 if (i->ip.ss_family == AF_INET) {
149 ret++;
152 return ret;
155 /****************************************************************************
156 Return a pointer to the in_addr of the first IPv4 interface that's
157 not 0.0.0.0.
158 **************************************************************************/
160 const struct in_addr *first_ipv4_iface(void)
162 struct interface *i;
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)))
168 break;
172 if (!i) {
173 return NULL;
175 return &((const struct sockaddr_in *)&i->ip)->sin_addr;
178 /****************************************************************************
179 Return the Nth interface.
180 **************************************************************************/
182 struct interface *get_interface(int n)
184 struct interface *i;
186 for (i=local_interfaces;i && n;i=i->next) {
187 n--;
190 if (i) {
191 return i;
193 return NULL;
196 /****************************************************************************
197 Return IP sockaddr_storage of the Nth interface.
198 **************************************************************************/
200 const struct sockaddr_storage *iface_n_sockaddr_storage(int n)
202 struct interface *i;
204 for (i=local_interfaces;i && n;i=i->next) {
205 n--;
208 if (i) {
209 return &i->ip;
211 return NULL;
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)
220 struct interface *i;
222 for (i=local_interfaces;i && n;i=i->next) {
223 n--;
226 if (i && i->ip.ss_family == AF_INET) {
227 return &((const struct sockaddr_in *)&i->ip)->sin_addr;
229 return NULL;
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)
238 struct interface *i;
240 for (i=local_interfaces;i && n;i=i->next) {
241 n--;
244 if (i && i->ip.ss_family == AF_INET) {
245 return &((const struct sockaddr_in *)&i->bcast)->sin_addr;
247 return NULL;
250 /****************************************************************************
251 Return bcast of the Nth interface.
252 **************************************************************************/
254 const struct sockaddr_storage *iface_n_bcast(int n)
256 struct interface *i;
258 for (i=local_interfaces;i && n;i=i->next) {
259 n--;
262 if (i) {
263 return &i->bcast;
265 return NULL;
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);
276 if (i) {
277 return &i->ip;
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) {
285 return &i->ip;
288 return NULL;
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) ));
312 return;
315 if (!(ifs->flags & (IFF_BROADCAST|IFF_LOOPBACK))) {
316 DEBUG(3,("not adding non-broadcast interface %s\n",
317 ifs->name ));
318 return;
321 iface = SMB_MALLOC_P(struct interface);
322 if (!iface) {
323 return;
326 ZERO_STRUCTPN(iface);
328 iface->name = SMB_STRDUP(ifs->name);
329 if (!iface->name) {
330 SAFE_FREE(iface);
331 return;
333 iface->flags = ifs->flags;
334 iface->ip = ifs->ip;
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 ",
344 iface->name,
345 print_sockaddr(addr, sizeof(addr), &iface->ip) ));
346 DEBUG(2,("bcast=%s ",
347 print_sockaddr(addr, sizeof(addr),
348 &iface->bcast) ));
349 DEBUG(2,("netmask=%s\n",
350 print_sockaddr(addr, sizeof(addr),
351 &iface->netmask) ));
355 static void parse_extra_info(char *key, uint64_t *speed, uint32_t *cap,
356 uint32_t *if_index)
358 while (key != NULL && *key != '\0') {
359 char *next_key;
360 char *val;
362 next_key = strchr_m(key, ',');
363 if (next_key != NULL) {
364 *next_key++ = 0;
367 val = strchr_m(key, '=');
368 if (val != NULL) {
369 *val++ = 0;
371 if (strequal_m(key, "speed")) {
372 *speed = (uint64_t)strtoull(val, NULL, 0);
373 } else if (strequal_m(key, "capability")) {
374 if (strequal_m(val, "RSS")) {
375 *cap |= FSCTL_NET_IFACE_RSS_CAPABLE;
376 } else if (strequal(val, "RDMA")) {
377 *cap |= FSCTL_NET_IFACE_RDMA_CAPABLE;
378 } else {
379 DBG_WARNING("Capability unknown: "
380 "'%s'\n", val);
382 } else if (strequal_m(key, "if_index")) {
383 *if_index = (uint32_t)strtoul(val, NULL, 0);
384 } else {
385 DBG_DEBUG("Key unknown: '%s'\n", key);
389 key = next_key;
393 /****************************************************************************
394 Interpret a single element from a interfaces= config line.
396 This handles the following different forms:
398 1) wildcard interface name
399 2) DNS name
400 3) IP/masklen
401 4) ip/mask
402 5) bcast/mask
404 Additional information for an interface can be specified with
405 this extended syntax:
407 interface[;key1=value1[,key2=value2[...]]]
409 where
410 - keys known: 'speed', 'capability', 'if_index'
411 - speed is in bits per second
412 - capabilites known: 'RSS', 'RDMA'
413 - if_index should be used with care, because
414 these indexes should not conicide with indexes
415 the kernel sets...
417 ****************************************************************************/
419 static void interpret_interface(char *token)
421 struct sockaddr_storage ss;
422 struct sockaddr_storage ss_mask;
423 struct sockaddr_storage ss_net;
424 struct sockaddr_storage ss_bcast;
425 struct iface_struct ifs;
426 char *p;
427 int i;
428 bool added=false;
429 bool goodaddr = false;
430 uint64_t speed = 0;
431 uint32_t cap = FSCTL_NET_IFACE_NONE_CAPABLE;
432 uint32_t if_index = 0;
433 bool speed_set = false;
434 bool cap_set = false;
435 bool if_index_set = false;
437 /* first check if it is an interface name */
438 for (i=0;i<total_probed;i++) {
439 if (gen_fnmatch(token, probed_ifaces[i].name) == 0) {
440 add_interface(&probed_ifaces[i]);
441 added = true;
444 if (added) {
445 return;
449 * extract speed / capability information if present
451 p = strchr_m(token, ';');
452 if (p != NULL) {
453 *p++ = 0;
454 parse_extra_info(p, &speed, &cap, &if_index);
455 if (speed != 0) {
456 speed_set = true;
458 if (cap != FSCTL_NET_IFACE_NONE_CAPABLE) {
459 cap_set = true;
461 if (if_index != 0) {
462 if_index_set = true;
466 p = strchr_m(token,'/');
467 if (p == NULL) {
468 if (!interpret_string_addr(&ss, token, 0)) {
469 DEBUG(2, ("interpret_interface: Can't find address "
470 "for %s\n", token));
471 return;
474 for (i=0;i<total_probed;i++) {
475 if (sockaddr_equal((struct sockaddr *)&ss,
476 (struct sockaddr *)&probed_ifaces[i].ip))
478 if (speed_set) {
479 probed_ifaces[i].linkspeed = speed;
481 if (cap_set) {
482 probed_ifaces[i].capability = cap;
484 if (if_index_set) {
485 probed_ifaces[i].if_index = if_index;
487 add_interface(&probed_ifaces[i]);
488 return;
491 DEBUG(2,("interpret_interface: "
492 "can't determine interface for %s\n",
493 token));
494 return;
497 /* parse it into an IP address/netmasklength pair */
498 *p = 0;
499 goodaddr = interpret_string_addr(&ss, token, 0);
500 *p++ = '/';
502 if (!goodaddr) {
503 DEBUG(2,("interpret_interface: "
504 "can't determine interface for %s\n",
505 token));
506 return;
509 if (strlen(p) > 2) {
510 goodaddr = interpret_string_addr(&ss_mask, p, 0);
511 if (!goodaddr) {
512 DEBUG(2,("interpret_interface: "
513 "can't determine netmask from %s\n",
514 p));
515 return;
517 } else {
518 char *endp = NULL;
519 unsigned long val = strtoul(p, &endp, 0);
520 if (p == endp || (endp && *endp != '\0')) {
521 DEBUG(2,("interpret_interface: "
522 "can't determine netmask value from %s\n",
523 p));
524 return;
526 if (!make_netmask(&ss_mask, &ss, val)) {
527 DEBUG(2,("interpret_interface: "
528 "can't apply netmask value %lu from %s\n",
529 val,
530 p));
531 return;
535 make_bcast(&ss_bcast, &ss, &ss_mask);
536 make_net(&ss_net, &ss, &ss_mask);
538 /* Maybe the first component was a broadcast address. */
539 if (sockaddr_equal((struct sockaddr *)&ss_bcast, (struct sockaddr *)&ss) ||
540 sockaddr_equal((struct sockaddr *)&ss_net, (struct sockaddr *)&ss)) {
541 for (i=0;i<total_probed;i++) {
542 if (same_net((struct sockaddr *)&ss,
543 (struct sockaddr *)&probed_ifaces[i].ip,
544 (struct sockaddr *)&ss_mask)) {
545 /* Temporarily replace netmask on
546 * the detected interface - user knows
547 * best.... */
548 struct sockaddr_storage saved_mask =
549 probed_ifaces[i].netmask;
550 probed_ifaces[i].netmask = ss_mask;
551 DEBUG(2,("interpret_interface: "
552 "using netmask value %s from "
553 "config file on interface %s\n",
555 probed_ifaces[i].name));
556 if (speed_set) {
557 probed_ifaces[i].linkspeed = speed;
559 if (cap_set) {
560 probed_ifaces[i].capability = cap;
562 if (if_index_set) {
563 probed_ifaces[i].if_index = if_index;
565 add_interface(&probed_ifaces[i]);
566 probed_ifaces[i].netmask = saved_mask;
567 return;
570 DEBUG(2,("interpret_interface: Can't determine ip for "
571 "broadcast address %s\n",
572 token));
573 return;
576 /* Just fake up the interface definition. User knows best. */
578 DEBUG(2,("interpret_interface: Adding interface %s\n",
579 token));
581 ZERO_STRUCT(ifs);
582 (void)strlcpy(ifs.name, token, sizeof(ifs.name));
583 ifs.flags = IFF_BROADCAST;
584 ifs.ip = ss;
585 ifs.netmask = ss_mask;
586 ifs.bcast = ss_bcast;
587 if (if_index_set) {
588 probed_ifaces[i].if_index = if_index;
590 if (speed_set) {
591 ifs.linkspeed = speed;
592 } else {
593 ifs.linkspeed = 1000 * 1000 * 1000;
595 ifs.capability = cap;
596 add_interface(&ifs);
599 /****************************************************************************
600 Load the list of network interfaces.
601 ****************************************************************************/
603 void load_interfaces(void)
605 struct iface_struct *ifaces = NULL;
606 const char **ptr = lp_interfaces();
607 int i;
609 gfree_interfaces();
611 /* Probe the kernel for interfaces */
612 total_probed = get_interfaces(talloc_tos(), &ifaces);
614 if (total_probed > 0) {
615 probed_ifaces = (struct iface_struct *)smb_memdup(ifaces,
616 sizeof(ifaces[0])*total_probed);
617 if (!probed_ifaces) {
618 DEBUG(0,("ERROR: smb_memdup failed\n"));
619 exit(1);
622 TALLOC_FREE(ifaces);
624 /* if we don't have a interfaces line then use all broadcast capable
625 interfaces except loopback */
626 if (!ptr || !*ptr || !**ptr) {
627 if (total_probed <= 0) {
628 DEBUG(0,("ERROR: Could not determine network "
629 "interfaces, you must use a interfaces config line\n"));
630 exit(1);
632 for (i=0;i<total_probed;i++) {
633 if (probed_ifaces[i].flags & IFF_BROADCAST) {
634 add_interface(&probed_ifaces[i]);
637 return;
640 if (ptr) {
641 while (*ptr) {
642 char *ptr_cpy = SMB_STRDUP(*ptr);
643 if (ptr_cpy) {
644 interpret_interface(ptr_cpy);
645 free(ptr_cpy);
647 ptr++;
651 if (!local_interfaces) {
652 DEBUG(0,("WARNING: no network interfaces found\n"));
657 void gfree_interfaces(void)
659 while (local_interfaces) {
660 struct interface *iface = local_interfaces;
661 DLIST_REMOVE(local_interfaces, local_interfaces);
662 SAFE_FREE(iface->name);
663 SAFE_FREE(iface);
666 SAFE_FREE(probed_ifaces);
669 /****************************************************************************
670 Return True if the list of probed interfaces has changed.
671 ****************************************************************************/
673 bool interfaces_changed(void)
675 bool ret = false;
676 int n;
677 struct iface_struct *ifaces = NULL;
679 n = get_interfaces(talloc_tos(), &ifaces);
681 if ((n > 0 )&& (n != total_probed ||
682 memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) {
683 ret = true;
686 TALLOC_FREE(ifaces);
687 return ret;