docs: fix a typo in history file
[bbaumbach/samba-autobuild/.git] / source4 / lib / socket / interface.c
index c4411b623c04387d1199a507528864de81f344c6..65543c6a294c82f4e7e6e97933b40bd1acd4eb06 100644 (file)
 
 #include "includes.h"
 #include "system/network.h"
+#include "param/param.h"
 #include "lib/socket/netif.h"
 #include "../lib/util/util_net.h"
 #include "../lib/util/dlinklist.h"
+#include "lib/util/smb_strtox.h"
 
-/** used for network interfaces */
+/* used for network interfaces */
 struct interface {
        struct interface *next, *prev;
-       struct in_addr ip;
-       struct in_addr nmask;
+       char *name;
+       int flags;
+       struct sockaddr_storage ip;
+       struct sockaddr_storage netmask;
+       struct sockaddr_storage bcast;
        const char *ip_s;
        const char *bcast_s;
        const char *nmask_s;
@@ -45,60 +50,93 @@ struct interface {
 /****************************************************************************
 Try and find an interface that matches an ip. If we cannot, return NULL
   **************************************************************************/
-static struct interface *iface_find(struct interface *interfaces, 
-                                   struct in_addr ip, bool CheckMask)
+static struct interface *iface_list_find(struct interface *interfaces,
+                                        const struct sockaddr *ip,
+                                        bool check_mask)
 {
        struct interface *i;
-       if (is_zero_ip_v4(ip)) return interfaces;
 
-       for (i=interfaces;i;i=i->next)
-               if (CheckMask) {
-                       if (same_net_v4(i->ip,ip,i->nmask)) return i;
-               } else if (i->ip.s_addr == ip.s_addr) return i;
+       if (is_address_any(ip)) {
+               return interfaces;
+       }
+
+       for (i=interfaces;i;i=i->next) {
+               if (check_mask) {
+                       if (same_net(ip, (struct sockaddr *)&i->ip, (struct sockaddr *)&i->netmask)) {
+                               return i;
+                       }
+               } else if (sockaddr_equal((struct sockaddr *)&i->ip, ip)) {
+                       return i;
+               }
+       }
 
        return NULL;
 }
 
-
 /****************************************************************************
 add an interface to the linked list of interfaces
 ****************************************************************************/
-static void add_interface(TALLOC_CTX *mem_ctx, struct in_addr ip, struct in_addr nmask, struct interface **interfaces)
+static void add_interface(TALLOC_CTX *mem_ctx, const struct iface_struct *ifs, struct interface **interfaces)
 {
+       char addr[INET6_ADDRSTRLEN];
        struct interface *iface;
-       struct in_addr bcast;
 
-       if (iface_find(*interfaces, ip, false)) {
-               DEBUG(3,("not adding duplicate interface %s\n",inet_ntoa(ip)));
+       if (iface_list_find(*interfaces, (const struct sockaddr *)&ifs->ip, false)) {
+               DEBUG(3,("add_interface: not adding duplicate interface %s\n",
+                       print_sockaddr(addr, sizeof(addr), &ifs->ip) ));
                return;
        }
 
-       iface = talloc(*interfaces == NULL ? mem_ctx : *interfaces, struct interface);
-       if (iface == NULL) 
+       if (ifs->ip.ss_family == AF_INET &&
+               !(ifs->flags & (IFF_BROADCAST|IFF_LOOPBACK))) {
+               DEBUG(3,("not adding non-broadcast interface %s\n",
+                                       ifs->name ));
                return;
-       
-       ZERO_STRUCTPN(iface);
+       }
 
-       iface->ip = ip;
-       iface->nmask = nmask;
-       bcast.s_addr = MKBCADDR(iface->ip.s_addr, iface->nmask.s_addr);
+       if (*interfaces != NULL) {
+               mem_ctx = *interfaces;
+       }
 
-       /* keep string versions too, to avoid people tripping over the implied
-          static in inet_ntoa() */
-       iface->ip_s = talloc_strdup(iface, inet_ntoa(iface->ip));
-       iface->nmask_s = talloc_strdup(iface, inet_ntoa(iface->nmask));
-       
-       if (nmask.s_addr != ~0) {
-               iface->bcast_s = talloc_strdup(iface, inet_ntoa(bcast));
+       iface = talloc_zero(mem_ctx, struct interface);
+       if (iface == NULL) {
+               return;
        }
 
-       DLIST_ADD_END(*interfaces, iface, struct interface *);
+       iface->name = talloc_strdup(iface, ifs->name);
+       if (!iface->name) {
+               SAFE_FREE(iface);
+               return;
+       }
+       iface->flags = ifs->flags;
+       iface->ip = ifs->ip;
+       iface->netmask = ifs->netmask;
+       iface->bcast = ifs->bcast;
 
-       DEBUG(3,("added interface ip=%s nmask=%s\n", iface->ip_s, iface->nmask_s));
+       /* keep string versions too, to avoid people tripping over the implied
+          static in inet_ntoa() */
+       print_sockaddr(addr, sizeof(addr), &iface->ip);
+       DEBUG(4,("added interface %s ip=%s ",
+                iface->name, addr));
+       iface->ip_s = talloc_strdup(iface, addr);
+
+       print_sockaddr(addr, sizeof(addr),
+                      &iface->bcast);
+       DEBUG(4,("bcast=%s ", addr));
+       iface->bcast_s = talloc_strdup(iface, addr);
+
+       print_sockaddr(addr, sizeof(addr),
+                      &iface->netmask);
+       DEBUG(4,("netmask=%s\n", addr));
+       iface->nmask_s = talloc_strdup(iface, addr);
+
+       /*
+          this needs to be a ADD_END, as some tests (such as the
+          spoolss notify test) depend on the interfaces ordering
+       */
+       DLIST_ADD_END(*interfaces, iface);
 }
 
-
-
 /**
 interpret a single element from a interfaces= config line 
 
@@ -116,97 +154,164 @@ static void interpret_interface(TALLOC_CTX *mem_ctx,
                                int total_probed,
                                struct interface **local_interfaces)
 {
-       struct in_addr ip, nmask;
+       struct sockaddr_storage ss;
+       struct sockaddr_storage ss_mask;
+       struct sockaddr_storage ss_net;
+       struct sockaddr_storage ss_bcast;
+       struct iface_struct ifs;
        char *p;
-       char *address;
-       int i, added=0;
+       int i;
+       bool added=false;
+       bool goodaddr = false;
 
-       ip.s_addr = 0;
-       nmask.s_addr = 0;
-       
        /* first check if it is an interface name */
        for (i=0;i<total_probed;i++) {
                if (gen_fnmatch(token, probed_ifaces[i].name) == 0) {
-                       add_interface(mem_ctx, probed_ifaces[i].ip,
-                                     probed_ifaces[i].netmask,
+                       add_interface(mem_ctx, &probed_ifaces[i],
                                      local_interfaces);
-                       added = 1;
+                       added = true;
                }
        }
-       if (added) return;
+       if (added) {
+               return;
+       }
+
+       p = strchr_m(token, ';');
+       if (p != NULL) {
+               /*
+                * skip smbd-specific extra data:
+                * link speed, capabilities, and interface index
+                */
+               *p = 0;
+       }
 
        /* maybe it is a DNS name */
        p = strchr_m(token,'/');
-       if (!p) {
-               /* don't try to do dns lookups on wildcard names */
-               if (strpbrk(token, "*?") != NULL) {
+       if (p == NULL) {
+               if (!interpret_string_addr(&ss, token, 0)) {
+                       DEBUG(2, ("interpret_interface: Can't find address "
+                                 "for %s\n", token));
                        return;
                }
-               ip.s_addr = interpret_addr2(token).s_addr;
+
                for (i=0;i<total_probed;i++) {
-                       if (ip.s_addr == probed_ifaces[i].ip.s_addr) {
-                               add_interface(mem_ctx, probed_ifaces[i].ip,
-                                             probed_ifaces[i].netmask,
+                       if (sockaddr_equal((struct sockaddr *)&ss, (struct sockaddr *)&probed_ifaces[i].ip)) {
+                               add_interface(mem_ctx, &probed_ifaces[i],
                                              local_interfaces);
                                return;
                        }
                }
-               DEBUG(2,("can't determine netmask for %s\n", token));
+               DEBUG(2,("interpret_interface: "
+                       "can't determine interface for %s\n",
+                       token));
                return;
        }
 
-       address = talloc_strdup(mem_ctx, token);
-       p = strchr_m(address,'/');
-
        /* parse it into an IP address/netmasklength pair */
-       *p++ = 0;
-
-       ip.s_addr = interpret_addr2(address).s_addr;
+       *p = 0;
+       goodaddr = interpret_string_addr(&ss, token, 0);
+       *p++ = '/';
+
+       if (!goodaddr) {
+               DEBUG(2,("interpret_interface: "
+                       "can't determine interface for %s\n",
+                       token));
+               return;
+       }
 
        if (strlen(p) > 2) {
-               nmask.s_addr = interpret_addr2(p).s_addr;
+               goodaddr = interpret_string_addr(&ss_mask, p, 0);
+               if (!goodaddr) {
+                       DEBUG(2,("interpret_interface: "
+                               "can't determine netmask from %s\n",
+                               p));
+                       return;
+               }
        } else {
-               nmask.s_addr = htonl(((ALLONES >> atoi(p)) ^ ALLONES));
+               int error = 0;
+
+               unsigned long val = smb_strtoul(p,
+                                               NULL,
+                                               0,
+                                               &error,
+                                               SMB_STR_FULL_STR_CONV);
+               if (error != 0) {
+                       DEBUG(2,("interpret_interface: "
+                               "can't determine netmask value from %s\n",
+                               p));
+                       return;
+               }
+               if (!make_netmask(&ss_mask, &ss, val)) {
+                       DEBUG(2,("interpret_interface: "
+                               "can't apply netmask value %lu from %s\n",
+                               val,
+                               p));
+                       return;
+               }
        }
 
-       /* maybe the first component was a broadcast address */
-       if (ip.s_addr == MKBCADDR(ip.s_addr, nmask.s_addr) ||
-           ip.s_addr == MKNETADDR(ip.s_addr, nmask.s_addr)) {
+       make_bcast(&ss_bcast, &ss, &ss_mask);
+       make_net(&ss_net, &ss, &ss_mask);
+
+       /* Maybe the first component was a broadcast address. */
+       if (sockaddr_equal((struct sockaddr *)&ss_bcast, (struct sockaddr *)&ss) ||
+               sockaddr_equal((struct sockaddr *)&ss_net, (struct sockaddr *)&ss)) {
                for (i=0;i<total_probed;i++) {
-                       if (same_net_v4(ip, probed_ifaces[i].ip, nmask)) {
-                               add_interface(mem_ctx, probed_ifaces[i].ip, nmask,
+                       if (same_net((struct sockaddr *)&ss,
+                                                (struct sockaddr *)&probed_ifaces[i].ip,
+                                                (struct sockaddr *)&ss_mask)) {
+                               /* Temporarily replace netmask on
+                                * the detected interface - user knows
+                                * best.... */
+                               struct sockaddr_storage saved_mask =
+                                       probed_ifaces[i].netmask;
+                               probed_ifaces[i].netmask = ss_mask;
+                               DEBUG(2,("interpret_interface: "
+                                       "using netmask value %s from "
+                                       "config file on interface %s\n",
+                                       p,
+                                       probed_ifaces[i].name));
+                               add_interface(mem_ctx, &probed_ifaces[i],
                                              local_interfaces);
-                               talloc_free(address);
+                               probed_ifaces[i].netmask = saved_mask;
                                return;
                        }
                }
-               DEBUG(2,("Can't determine ip for broadcast address %s\n", address));
-               talloc_free(address);
+               DEBUG(2,("interpret_interface: Can't determine ip for "
+                       "broadcast address %s\n",
+                       token));
                return;
        }
 
-       add_interface(mem_ctx, ip, nmask, local_interfaces);
-       talloc_free(address);
+       /* Just fake up the interface definition. User knows best. */
+
+       DEBUG(2,("interpret_interface: Adding interface %s\n",
+               token));
+
+       ZERO_STRUCT(ifs);
+       (void)strlcpy(ifs.name, token, sizeof(ifs.name));
+       ifs.flags = IFF_BROADCAST;
+       ifs.ip = ss;
+       ifs.netmask = ss_mask;
+       ifs.bcast = ss_bcast;
+       add_interface(mem_ctx, &ifs, local_interfaces);
 }
 
 
 /**
 load the list of network interfaces
 **/
-void load_interfaces(TALLOC_CTX *mem_ctx, const char **interfaces, struct interface **local_interfaces)
+void load_interface_list(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct interface **local_interfaces)
 {
-       const char **ptr = interfaces;
+       const char **ptr = lpcfg_interfaces(lp_ctx);
        int i;
-       struct iface_struct ifaces[MAX_INTERFACES];
-       struct in_addr loopback_ip;
+       struct iface_struct *ifaces = NULL;
        int total_probed;
 
        *local_interfaces = NULL;
 
-       loopback_ip = interpret_addr2("127.0.0.1");
-
        /* probe the kernel for interfaces */
-       total_probed = get_interfaces(ifaces, MAX_INTERFACES);
+       total_probed = get_interfaces(mem_ctx, &ifaces);
 
        /* if we don't have a interfaces line then use all interfaces
           except loopback */
@@ -215,9 +320,8 @@ void load_interfaces(TALLOC_CTX *mem_ctx, const char **interfaces, struct interf
                        DEBUG(0,("ERROR: Could not determine network interfaces, you must use a interfaces config line\n"));
                }
                for (i=0;i<total_probed;i++) {
-                       if (ifaces[i].ip.s_addr != loopback_ip.s_addr) {
-                               add_interface(mem_ctx, ifaces[i].ip, 
-                                             ifaces[i].netmask, local_interfaces);
+                       if (!is_loopback_addr((struct sockaddr *)&ifaces[i].ip)) {
+                               add_interface(mem_ctx, &ifaces[i], local_interfaces);
                        }
                }
        }
@@ -230,12 +334,13 @@ void load_interfaces(TALLOC_CTX *mem_ctx, const char **interfaces, struct interf
        if (!*local_interfaces) {
                DEBUG(0,("WARNING: no network interfaces found\n"));
        }
+       talloc_free(ifaces);
 }
 
 /**
   how many interfaces do we have
   **/
-int iface_count(struct interface *ifaces)
+int iface_list_count(struct interface *ifaces)
 {
        int ret = 0;
        struct interface *i;
@@ -248,7 +353,7 @@ int iface_count(struct interface *ifaces)
 /**
   return IP of the Nth interface
   **/
-const char *iface_n_ip(struct interface *ifaces, int n)
+const char *iface_list_n_ip(struct interface *ifaces, int n)
 {
        struct interface *i;
   
@@ -261,10 +366,59 @@ const char *iface_n_ip(struct interface *ifaces, int n)
        return NULL;
 }
 
+
+/**
+  return the first IPv4 interface address we have registered
+  **/
+const char *iface_list_first_v4(struct interface *ifaces)
+{
+       struct interface *i;
+
+       for (i=ifaces; i; i=i->next) {
+               if (i->ip.ss_family == AF_INET) {
+                       return i->ip_s;
+               }
+       }
+       return NULL;
+}
+
+/**
+  return the first IPv6 interface address we have registered
+  **/
+static const char *iface_list_first_v6(struct interface *ifaces)
+{
+       struct interface *i;
+
+#ifdef HAVE_IPV6
+       for (i=ifaces; i; i=i->next) {
+               if (i->ip.ss_family == AF_INET6) {
+                       return i->ip_s;
+               }
+       }
+#endif
+       return NULL;
+}
+
+/**
+   check if an interface is IPv4
+  **/
+bool iface_list_n_is_v4(struct interface *ifaces, int n)
+{
+       struct interface *i;
+
+       for (i=ifaces;i && n;i=i->next)
+               n--;
+
+       if (i) {
+               return i->ip.ss_family == AF_INET;
+       }
+       return false;
+}
+
 /**
   return bcast of the Nth interface
   **/
-const char *iface_n_bcast(struct interface *ifaces, int n)
+const char *iface_list_n_bcast(struct interface *ifaces, int n)
 {
        struct interface *i;
   
@@ -280,7 +434,7 @@ const char *iface_n_bcast(struct interface *ifaces, int n)
 /**
   return netmask of the Nth interface
   **/
-const char *iface_n_netmask(struct interface *ifaces, int n)
+const char *iface_list_n_netmask(struct interface *ifaces, int n)
 {
        struct interface *i;
   
@@ -297,28 +451,37 @@ const char *iface_n_netmask(struct interface *ifaces, int n)
   return the local IP address that best matches a destination IP, or
   our first interface if none match
 */
-const char *iface_best_ip(struct interface *ifaces, const char *dest)
+const char *iface_list_best_ip(struct interface *ifaces, const char *dest)
 {
        struct interface *iface;
-       struct in_addr ip;
+       struct sockaddr_storage ss;
 
-       ip.s_addr = interpret_addr(dest);
-       iface = iface_find(ifaces, ip, true);
+       if (!interpret_string_addr(&ss, dest, AI_NUMERICHOST)) {
+               return iface_list_n_ip(ifaces, 0);
+       }
+       iface = iface_list_find(ifaces, (const struct sockaddr *)&ss, true);
        if (iface) {
                return iface->ip_s;
        }
-       return iface_n_ip(ifaces, 0);
+#ifdef HAVE_IPV6
+       if (ss.ss_family == AF_INET6) {
+               return iface_list_first_v6(ifaces);
+       }
+#endif
+       return iface_list_first_v4(ifaces);
 }
 
 /**
   return true if an IP is one one of our local networks
 */
-bool iface_is_local(struct interface *ifaces, const char *dest)
+bool iface_list_is_local(struct interface *ifaces, const char *dest)
 {
-       struct in_addr ip;
+       struct sockaddr_storage ss;
 
-       ip.s_addr = interpret_addr(dest);
-       if (iface_find(ifaces, ip, true)) {
+       if (!interpret_string_addr(&ss, dest, AI_NUMERICHOST)) {
+               return false;
+       }
+       if (iface_list_find(ifaces, (const struct sockaddr *)&ss, true)) {
                return true;
        }
        return false;
@@ -327,9 +490,36 @@ bool iface_is_local(struct interface *ifaces, const char *dest)
 /**
   return true if a IP matches a IP/netmask pair
 */
-bool iface_same_net(const char *ip1, const char *ip2, const char *netmask)
+bool iface_list_same_net(const char *ip1, const char *ip2, const char *netmask)
 {
-       return same_net_v4(interpret_addr2(ip1),
-                       interpret_addr2(ip2),
-                       interpret_addr2(netmask));
+       struct sockaddr_storage ip1_ss, ip2_ss, nm_ss;
+
+       if (!interpret_string_addr(&ip1_ss, ip1, AI_NUMERICHOST)) {
+               return false;
+       }
+       if (!interpret_string_addr(&ip2_ss, ip2, AI_NUMERICHOST)) {
+               return false;
+       }
+       if (!interpret_string_addr(&nm_ss, netmask, AI_NUMERICHOST)) {
+               return false;
+       }
+
+       return same_net((struct sockaddr *)&ip1_ss,
+                       (struct sockaddr *)&ip2_ss,
+                       (struct sockaddr *)&nm_ss);
+}
+
+/**
+   return the list of wildcard interfaces
+   this will include the IPv4 0.0.0.0, and may include IPv6 ::
+*/
+char **iface_list_wildcard(TALLOC_CTX *mem_ctx)
+{
+       char **ret;
+#ifdef HAVE_IPV6
+       ret = str_list_make(mem_ctx, "::,0.0.0.0", NULL);
+#else
+       ret = str_list_make(mem_ctx, "0.0.0.0", NULL);
+#endif
+       return ret;
 }