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/>.
23 static struct iface_struct *probed_ifaces;
24 static int total_probed;
26 static struct interface *local_interfaces;
28 /****************************************************************************
29 Check if an IP is one of mine.
30 **************************************************************************/
32 bool ismyaddr(const struct sockaddr_storage *ip)
35 for (i=local_interfaces;i;i=i->next) {
36 if (addr_equal(&i->ip,ip)) {
43 bool ismyip_v4(struct in_addr ip)
45 struct sockaddr_storage ss;
46 in_addr_to_sockaddr_storage(&ss, ip);
50 /****************************************************************************
51 Try and find an interface that matches an ip. If we cannot, return NULL.
52 **************************************************************************/
54 static struct interface *iface_find(const struct sockaddr_storage *ip,
59 if (is_address_any(ip)) {
60 return local_interfaces;
63 for (i=local_interfaces;i;i=i->next) {
65 if (same_net(ip, &i->ip, &i->netmask)) {
68 } else if (addr_equal(&i->ip, ip)) {
76 /****************************************************************************
77 Check if a packet is from a local (known) net.
78 **************************************************************************/
80 bool is_local_net(const struct sockaddr_storage *from)
83 for (i=local_interfaces;i;i=i->next) {
84 if (same_net(from, &i->ip, &i->netmask)) {
91 /****************************************************************************
92 Check if a packet is from a local (known) net.
93 **************************************************************************/
95 bool is_local_net_v4(struct in_addr from)
97 struct sockaddr_storage ss;
99 in_addr_to_sockaddr_storage(&ss, from);
100 return is_local_net(&ss);
103 /****************************************************************************
104 How many interfaces do we have ?
105 **************************************************************************/
107 int iface_count(void)
112 for (i=local_interfaces;i;i=i->next) {
118 /****************************************************************************
119 How many interfaces do we have (v4 only) ?
120 **************************************************************************/
122 int iface_count_v4(void)
127 for (i=local_interfaces;i;i=i->next) {
128 if (i->ip.ss_family == AF_INET) {
135 /****************************************************************************
136 Return a pointer to the in_addr of the first IPv4 interface.
137 **************************************************************************/
139 const struct in_addr *first_ipv4_iface(void)
143 for (i=local_interfaces;i ;i=i->next) {
144 if (i->ip.ss_family == AF_INET) {
152 return &((const struct sockaddr_in *)&i->ip)->sin_addr;
155 /****************************************************************************
156 Return the Nth interface.
157 **************************************************************************/
159 struct interface *get_interface(int n)
163 for (i=local_interfaces;i && n;i=i->next) {
173 /****************************************************************************
174 Return IP sockaddr_storage of the Nth interface.
175 **************************************************************************/
177 const struct sockaddr_storage *iface_n_sockaddr_storage(int n)
181 for (i=local_interfaces;i && n;i=i->next) {
191 /****************************************************************************
192 Return IPv4 of the Nth interface (if a v4 address). NULL otherwise.
193 **************************************************************************/
195 const struct in_addr *iface_n_ip_v4(int n)
199 for (i=local_interfaces;i && n;i=i->next) {
203 if (i && i->ip.ss_family == AF_INET) {
204 return &((const struct sockaddr_in *)&i->ip)->sin_addr;
209 /****************************************************************************
210 Return IPv4 bcast of the Nth interface (if a v4 address). NULL otherwise.
211 **************************************************************************/
213 const struct in_addr *iface_n_bcast_v4(int n)
217 for (i=local_interfaces;i && n;i=i->next) {
221 if (i && i->ip.ss_family == AF_INET) {
222 return &((const struct sockaddr_in *)&i->bcast)->sin_addr;
227 /****************************************************************************
228 Return bcast of the Nth interface.
229 **************************************************************************/
231 const struct sockaddr_storage *iface_n_bcast(int n)
235 for (i=local_interfaces;i && n;i=i->next) {
245 /* these 3 functions return the ip/bcast/nmask for the interface
246 most appropriate for the given ip address. If they can't find
247 an appropriate interface they return the requested field of the
248 first known interface. */
250 const struct sockaddr_storage *iface_ip(const struct sockaddr_storage *ip)
252 struct interface *i = iface_find(ip, true);
257 /* Search for the first interface with
258 * matching address family. */
260 for (i=local_interfaces;i;i=i->next) {
261 if (i->ip.ss_family == ip->ss_family) {
269 return True if a IP is directly reachable on one of our interfaces
272 bool iface_local(struct sockaddr_storage *ip)
274 return iface_find(ip, True) ? true : false;
277 /****************************************************************************
278 Add an interface to the linked list of interfaces.
279 ****************************************************************************/
281 static void add_interface(const struct iface_struct *ifs)
283 char addr[INET6_ADDRSTRLEN];
284 struct interface *iface;
286 if (iface_find(&ifs->ip, False)) {
287 DEBUG(3,("add_interface: not adding duplicate interface %s\n",
288 print_sockaddr(addr, sizeof(addr),
289 &ifs->ip, sizeof(struct sockaddr_storage)) ));
293 if (!(ifs->flags & (IFF_BROADCAST|IFF_LOOPBACK))) {
294 DEBUG(3,("not adding non-broadcast interface %s\n",
299 iface = SMB_MALLOC_P(struct interface);
304 ZERO_STRUCTPN(iface);
306 iface->name = SMB_STRDUP(ifs->name);
311 iface->flags = ifs->flags;
313 iface->netmask = ifs->netmask;
314 iface->bcast = ifs->bcast;
316 DLIST_ADD(local_interfaces, iface);
318 DEBUG(2,("added interface %s ip=%s ",
320 print_sockaddr(addr, sizeof(addr),
321 &iface->ip, sizeof(struct sockaddr_storage)) ));
322 DEBUG(2,("bcast=%s ",
323 print_sockaddr(addr, sizeof(addr),
325 sizeof(struct sockaddr_storage)) ));
326 DEBUG(2,("netmask=%s\n",
327 print_sockaddr(addr, sizeof(addr),
329 sizeof(struct sockaddr_storage)) ));
332 /****************************************************************************
333 Create a struct sockaddr_storage with the netmask bits set to 1.
334 ****************************************************************************/
336 static bool make_netmask(struct sockaddr_storage *pss_out,
337 const struct sockaddr_storage *pss_in,
338 unsigned long masklen)
341 /* Now apply masklen bits of mask. */
342 #if defined(AF_INET6)
343 if (pss_in->ss_family == AF_INET6) {
344 char *p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
350 for (i = 0; masklen >= 8; masklen -= 8, i++) {
353 /* Deal with the partial byte. */
354 *p++ &= (0xff & ~(0xff>>masklen));
356 for (;i < sizeof(struct in6_addr); i++) {
362 if (pss_in->ss_family == AF_INET) {
366 ((struct sockaddr_in *)pss_out)->sin_addr.s_addr =
367 htonl(((0xFFFFFFFFL >> masklen) ^ 0xFFFFFFFFL));
373 /****************************************************************************
374 Create a struct sockaddr_storage set to the broadcast or network adress from
375 an incoming sockaddr_storage.
376 ****************************************************************************/
378 static void make_bcast_or_net(struct sockaddr_storage *pss_out,
379 const struct sockaddr_storage *pss_in,
380 const struct sockaddr_storage *nmask,
383 unsigned int i = 0, len = 0;
388 /* Set all zero netmask bits to 1. */
389 #if defined(AF_INET6)
390 if (pss_in->ss_family == AF_INET6) {
391 p = (char *)&((struct sockaddr_in6 *)pss_out)->sin6_addr;
392 pmask = (char *)&((struct sockaddr_in6 *)nmask)->sin6_addr;
396 if (pss_in->ss_family == AF_INET) {
397 p = (char *)&((struct sockaddr_in *)pss_out)->sin_addr;
398 pmask = (char *)&((struct sockaddr_in *)nmask)->sin_addr;
402 for (i = 0; i < len; i++, p++, pmask++) {
404 *p = (*p & *pmask) | (*pmask ^ 0xff);
412 static void make_bcast(struct sockaddr_storage *pss_out,
413 const struct sockaddr_storage *pss_in,
414 const struct sockaddr_storage *nmask)
416 make_bcast_or_net(pss_out, pss_in, nmask, true);
419 static void make_net(struct sockaddr_storage *pss_out,
420 const struct sockaddr_storage *pss_in,
421 const struct sockaddr_storage *nmask)
423 make_bcast_or_net(pss_out, pss_in, nmask, false);
426 /****************************************************************************
427 Interpret a single element from a interfaces= config line.
429 This handles the following different forms:
431 1) wildcard interface name
436 ****************************************************************************/
438 static void interpret_interface(char *token)
440 struct sockaddr_storage ss;
441 struct sockaddr_storage ss_mask;
442 struct sockaddr_storage ss_net;
443 struct sockaddr_storage ss_bcast;
444 struct iface_struct ifs;
448 bool goodaddr = false;
450 /* first check if it is an interface name */
451 for (i=0;i<total_probed;i++) {
452 if (gen_fnmatch(token, probed_ifaces[i].name) == 0) {
453 add_interface(&probed_ifaces[i]);
461 /* maybe it is a DNS name */
462 p = strchr_m(token,'/');
464 if (!interpret_string_addr(&ss, token)) {
465 DEBUG(2, ("interpret_interface: Can't find address "
470 for (i=0;i<total_probed;i++) {
471 if (addr_equal(&ss, &probed_ifaces[i].ip)) {
472 add_interface(&probed_ifaces[i]);
476 DEBUG(2,("interpret_interface: "
477 "can't determine interface for %s\n",
482 /* parse it into an IP address/netmasklength pair */
484 goodaddr = interpret_string_addr(&ss, token);
488 DEBUG(2,("interpret_interface: "
489 "can't determine interface for %s\n",
495 goodaddr = interpret_string_addr(&ss_mask, p);
497 DEBUG(2,("interpret_interface: "
498 "can't determine netmask from %s\n",
504 unsigned long val = strtoul(p, &endp, 0);
505 if (p == endp || (endp && *endp != '\0')) {
506 DEBUG(2,("interpret_interface: "
507 "can't determine netmask value from %s\n",
511 if (!make_netmask(&ss_mask, &ss, val)) {
512 DEBUG(2,("interpret_interface: "
513 "can't apply netmask value %lu from %s\n",
520 make_bcast(&ss_bcast, &ss, &ss_mask);
521 make_net(&ss_net, &ss, &ss_mask);
523 /* Maybe the first component was a broadcast address. */
524 if (addr_equal(&ss_bcast, &ss) || addr_equal(&ss_net, &ss)) {
525 for (i=0;i<total_probed;i++) {
526 if (same_net(&ss, &probed_ifaces[i].ip, &ss_mask)) {
527 /* Temporarily replace netmask on
528 * the detected interface - user knows
530 struct sockaddr_storage saved_mask =
531 probed_ifaces[i].netmask;
532 probed_ifaces[i].netmask = ss_mask;
533 DEBUG(2,("interpret_interface: "
534 "using netmask value %s from "
535 "config file on interface %s\n",
537 probed_ifaces[i].name));
538 add_interface(&probed_ifaces[i]);
539 probed_ifaces[i].netmask = saved_mask;
543 DEBUG(2,("interpret_interface: Can't determine ip for "
544 "broadcast address %s\n",
549 /* Just fake up the interface definition. User knows best. */
551 DEBUG(2,("interpret_interface: Adding interface %s\n",
555 safe_strcpy(ifs.name, token, sizeof(ifs.name)-1);
556 ifs.flags = IFF_BROADCAST;
558 ifs.netmask = ss_mask;
559 ifs.bcast = ss_bcast;
563 /****************************************************************************
564 Load the list of network interfaces.
565 ****************************************************************************/
567 void load_interfaces(void)
569 struct iface_struct ifaces[MAX_INTERFACES];
570 const char **ptr = lp_interfaces();
573 SAFE_FREE(probed_ifaces);
575 /* dump the current interfaces if any */
576 while (local_interfaces) {
577 struct interface *iface = local_interfaces;
578 DLIST_REMOVE(local_interfaces, local_interfaces);
579 SAFE_FREE(iface->name);
583 /* Probe the kernel for interfaces */
584 total_probed = get_interfaces(ifaces, MAX_INTERFACES);
586 if (total_probed > 0) {
587 probed_ifaces = (struct iface_struct *)memdup(ifaces,
588 sizeof(ifaces[0])*total_probed);
589 if (!probed_ifaces) {
590 DEBUG(0,("ERROR: memdup failed\n"));
595 /* if we don't have a interfaces line then use all broadcast capable
596 interfaces except loopback */
597 if (!ptr || !*ptr || !**ptr) {
598 if (total_probed <= 0) {
599 DEBUG(0,("ERROR: Could not determine network "
600 "interfaces, you must use a interfaces config line\n"));
603 for (i=0;i<total_probed;i++) {
604 if (probed_ifaces[i].flags & IFF_BROADCAST) {
605 add_interface(&probed_ifaces[i]);
613 char *ptr_cpy = SMB_STRDUP(*ptr);
615 interpret_interface(ptr_cpy);
622 if (!local_interfaces) {
623 DEBUG(0,("WARNING: no network interfaces found\n"));
628 void gfree_interfaces(void)
630 while (local_interfaces) {
631 struct interface *iface = local_interfaces;
632 DLIST_REMOVE(local_interfaces, local_interfaces);
633 SAFE_FREE(iface->name);
637 SAFE_FREE(probed_ifaces);
640 /****************************************************************************
641 Return True if the list of probed interfaces has changed.
642 ****************************************************************************/
644 bool interfaces_changed(void)
647 struct iface_struct ifaces[MAX_INTERFACES];
649 n = get_interfaces(ifaces, MAX_INTERFACES);
651 if ((n > 0 )&& (n != total_probed ||
652 memcmp(ifaces, probed_ifaces, sizeof(ifaces[0])*n))) {