Fix is_myname_or_ipaddr() to be robust against strange DNS setups.
authorJeremy Allison <jra@samba.org>
Thu, 24 Mar 2011 19:11:02 +0000 (12:11 -0700)
committerJeremy Allison <jra@samba.org>
Thu, 24 Mar 2011 22:11:25 +0000 (15:11 -0700)
If IPv6 DNS names are turned on, but Samba isn't configured to
listen on an IPv6 interface, then is_myname_or_ipaddr() can return
false on a valid DNS name that it should detect is our own. If the
IPv6 addr is returned by preference, then looking at the first addr
only causes is_myname_or_ipaddr() to fail. We need to look at all the
addresses returned by the DNS lookup and check all of them against
our interface list. This is an order N^2 lookup, but there shouldn't
be enough addresses to make this a practical problem.

Jeremy.
(cherry picked from commit 5176a0b2af1bb16e530412faaa2f36108f312a03)

source3/lib/util_sock.c

index 3c9749509926b2336e7844676b77508559e414fe..a2b7a49054f817552f413930c8db2a65aeb13c67 100644 (file)
@@ -1581,6 +1581,40 @@ const char *get_mydnsfullname(void)
        return (const char *)tmp.data;
 }
 
+/************************************************************
+ Is this my ip address ?
+************************************************************/
+
+static bool is_my_ipaddr(const char *ipaddr_str)
+{
+       struct sockaddr_storage ss;
+       struct iface_struct *nics;
+       int i, n;
+
+       if (!interpret_string_addr(&ss, ipaddr_str, AI_NUMERICHOST)) {
+               return false;
+       }
+
+       if (ismyaddr((struct sockaddr *)&ss)) {
+               return true;
+       }
+
+       if (is_zero_addr(&ss) ||
+               is_loopback_addr((struct sockaddr *)&ss)) {
+               return false;
+       }
+
+       n = get_interfaces(talloc_tos(), &nics);
+       for (i=0; i<n; i++) {
+               if (sockaddr_equal((struct sockaddr *)&nics[i].ip, (struct sockaddr *)&ss)) {
+                       TALLOC_FREE(nics);
+                       return true;
+               }
+       }
+       TALLOC_FREE(nics);
+       return false;
+}
+
 /************************************************************
  Is this my name ?
 ************************************************************/
@@ -1588,7 +1622,6 @@ const char *get_mydnsfullname(void)
 bool is_myname_or_ipaddr(const char *s)
 {
        TALLOC_CTX *ctx = talloc_tos();
-       char addr[INET6_ADDRSTRLEN];
        char *name = NULL;
        const char *dnsname;
        char *servername = NULL;
@@ -1636,45 +1669,38 @@ bool is_myname_or_ipaddr(const char *s)
                return true;
        }
 
-       /* Handle possible CNAME records - convert to an IP addr. */
-       if (!is_ipaddress(servername)) {
-               /* Use DNS to resolve the name, but only the first address */
-               struct sockaddr_storage ss;
-               if (interpret_string_addr(&ss, servername, 0)) {
-                       print_sockaddr(addr,
-                                       sizeof(addr),
-                                       &ss);
-                       servername = addr;
-               }
-       }
-
        /* Maybe its an IP address? */
        if (is_ipaddress(servername)) {
-               struct sockaddr_storage ss;
-               struct iface_struct *nics;
-               int i, n;
-
-               if (!interpret_string_addr(&ss, servername, AI_NUMERICHOST)) {
-                       return false;
-               }
+               return is_my_ipaddr(servername);
+       }
 
-               if (ismyaddr((struct sockaddr *)&ss)) {
-                       return true;
-               }
+       /* Handle possible CNAME records - convert to an IP addr. list. */
+       {
+               /* Use DNS to resolve the name, check all addresses. */
+               struct addrinfo *p = NULL;
+               struct addrinfo *res = NULL;
 
-               if (is_zero_addr(&ss) ||
-                       is_loopback_addr((struct sockaddr *)&ss)) {
+               if (!interpret_string_addr_internal(&res,
+                               servername,
+                               AI_ADDRCONFIG)) {
                        return false;
                }
 
-               n = get_interfaces(talloc_tos(), &nics);
-               for (i=0; i<n; i++) {
-                       if (sockaddr_equal((struct sockaddr *)&nics[i].ip, (struct sockaddr *)&ss)) {
-                               TALLOC_FREE(nics);
+               for (p = res; p; p = p->ai_next) {
+                       char addr[INET6_ADDRSTRLEN];
+                       struct sockaddr_storage ss;
+
+                       ZERO_STRUCT(ss);
+                       memcpy(&ss, p->ai_addr, p->ai_addrlen);
+                       print_sockaddr(addr,
+                                       sizeof(addr),
+                                       &ss);
+                       if (is_my_ipaddr(addr)) {
+                               freeaddrinfo(res);
                                return true;
                        }
                }
-               TALLOC_FREE(nics);
+               freeaddrinfo(res);
        }
 
        /* No match */