s4-ipv6: fix iface_list_best_ip() for IPv6
[abartlet/samba.git/.git] / source4 / lib / socket / interface.c
index 9ae658da3efd97f23c9a8a143b72cf465aca775d..1bf1e4f62b369725a6383fdc7b52a43b46f2c720 100644 (file)
@@ -75,7 +75,8 @@ static struct interface *iface_list_find(struct interface *interfaces,
 /****************************************************************************
 add an interface to the linked list of interfaces
 ****************************************************************************/
-static void add_interface(TALLOC_CTX *mem_ctx, const struct iface_struct *ifs, struct interface **interfaces)
+static void add_interface(TALLOC_CTX *mem_ctx, const struct iface_struct *ifs, struct interface **interfaces,
+                         bool enable_ipv6)
 {
        char addr[INET6_ADDRSTRLEN];
        struct interface *iface;
@@ -92,6 +93,10 @@ static void add_interface(TALLOC_CTX *mem_ctx, const struct iface_struct *ifs, s
                return;
        }
 
+       if (!enable_ipv6 && ifs->ip.ss_family != AF_INET) {
+               return;
+       }
+
        iface = talloc(*interfaces == NULL ? mem_ctx : *interfaces, struct interface);
        if (iface == NULL) 
                return;
@@ -147,7 +152,8 @@ static void interpret_interface(TALLOC_CTX *mem_ctx,
                                const char *token, 
                                struct iface_struct *probed_ifaces, 
                                int total_probed,
-                               struct interface **local_interfaces)
+                               struct interface **local_interfaces,
+                               bool enable_ipv6)
 {
        struct sockaddr_storage ss;
        struct sockaddr_storage ss_mask;
@@ -163,7 +169,7 @@ static void interpret_interface(TALLOC_CTX *mem_ctx,
        for (i=0;i<total_probed;i++) {
                if (gen_fnmatch(token, probed_ifaces[i].name) == 0) {
                        add_interface(mem_ctx, &probed_ifaces[i],
-                                     local_interfaces);
+                                     local_interfaces, enable_ipv6);
                        added = true;
                }
        }
@@ -183,7 +189,7 @@ static void interpret_interface(TALLOC_CTX *mem_ctx,
                for (i=0;i<total_probed;i++) {
                        if (sockaddr_equal((struct sockaddr *)&ss, (struct sockaddr *)&probed_ifaces[i].ip)) {
                                add_interface(mem_ctx, &probed_ifaces[i],
-                                             local_interfaces);
+                                             local_interfaces, enable_ipv6);
                                return;
                        }
                }
@@ -253,7 +259,7 @@ static void interpret_interface(TALLOC_CTX *mem_ctx,
                                        p,
                                        probed_ifaces[i].name));
                                add_interface(mem_ctx, &probed_ifaces[i],
-                                             local_interfaces);
+                                             local_interfaces, enable_ipv6);
                                probed_ifaces[i].netmask = saved_mask;
                                return;
                        }
@@ -276,19 +282,20 @@ static void interpret_interface(TALLOC_CTX *mem_ctx,
        ifs.netmask = ss_mask;
        ifs.bcast = ss_bcast;
        add_interface(mem_ctx, &ifs,
-                     local_interfaces);
+                     local_interfaces, enable_ipv6);
 }
 
 
 /**
 load the list of network interfaces
 **/
-void load_interface_list(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;
        int total_probed;
+       bool enable_ipv6 = lpcfg_parm_bool(lp_ctx, NULL, "ipv6", "enable", true);
 
        *local_interfaces = NULL;
 
@@ -302,14 +309,14 @@ void load_interface_list(TALLOC_CTX *mem_ctx, const char **interfaces, struct in
                        DEBUG(0,("ERROR: Could not determine network interfaces, you must use a interfaces config line\n"));
                }
                for (i=0;i<total_probed;i++) {
-                       if (!is_loopback_addr(&ifaces[i].ip)) {
-                               add_interface(mem_ctx, &ifaces[i], local_interfaces);
+                       if (!is_loopback_addr((struct sockaddr *)&ifaces[i].ip)) {
+                               add_interface(mem_ctx, &ifaces[i], local_interfaces, enable_ipv6);
                        }
                }
        }
 
        while (ptr && *ptr) {
-               interpret_interface(mem_ctx, *ptr, ifaces, total_probed, local_interfaces);
+               interpret_interface(mem_ctx, *ptr, ifaces, total_probed, local_interfaces, enable_ipv6);
                ptr++;
        }
 
@@ -348,6 +355,55 @@ const char *iface_list_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
   **/
@@ -396,7 +452,12 @@ const char *iface_list_best_ip(struct interface *ifaces, const char *dest)
        if (iface) {
                return iface->ip_s;
        }
-       return iface_list_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);
 }
 
 /**
@@ -446,7 +507,9 @@ const char **iface_list_wildcard(TALLOC_CTX *mem_ctx, struct loadparm_context *l
        if (ret == NULL) return NULL;
 
 #ifdef HAVE_IPV6
-       return str_list_add(ret, "::");
+       if (lpcfg_parm_bool(lp_ctx, NULL, "ipv6", "enable", true)) {
+               return str_list_add(ret, "::");
+       }
 #endif
 
        return ret;