Fix is_myname_or_ipaddr() to be robust against strange DNS setups.
[samba.git] / source3 / lib / util_sock.c
index 08cbced1e514783e6a70b99fea297e677f6fc867..1441560470c0721c843e29be23c7667a7b6c1803 100644 (file)
@@ -495,6 +495,11 @@ NTSTATUS read_fd_with_timeout(int fd, char *buf,
        timeout.tv_usec = (long)(1000 * (time_out % 1000));
 
        for (nread=0; nread < mincnt; ) {
+               if (fd < 0 || fd >= FD_SETSIZE) {
+                       errno = EBADF;
+                       return map_nt_error_from_unix(EBADF);
+               }
+
                FD_ZERO(&fds);
                FD_SET(fd,&fds);
 
@@ -1235,7 +1240,7 @@ bool open_any_socket_out(struct sockaddr_storage *addrs, int num_addrs,
 
        for (i=0; i<num_addrs; i++) {
                sockets[i] = socket(addrs[i].ss_family, SOCK_STREAM, 0);
-               if (sockets[i] < 0)
+               if (sockets[i] < 0 || sockets[i] >= FD_SETSIZE)
                        goto done;
                set_blocking(sockets[i], false);
        }
@@ -1284,8 +1289,10 @@ bool open_any_socket_out(struct sockaddr_storage *addrs, int num_addrs,
        FD_ZERO(&r_fds);
 
        for (i=0; i<num_addrs; i++) {
-               if (sockets[i] == -1)
+               if (sockets[i] < 0 || sockets[i] >= FD_SETSIZE) {
+                       /* This cannot happen - ignore if so. */
                        continue;
+               }
                FD_SET(sockets[i], &wr_fds);
                FD_SET(sockets[i], &r_fds);
                if (sockets[i]>maxfd)
@@ -1305,8 +1312,10 @@ bool open_any_socket_out(struct sockaddr_storage *addrs, int num_addrs,
 
        for (i=0; i<num_addrs; i++) {
 
-               if (sockets[i] == -1)
+               if (sockets[i] < 0 || sockets[i] >= FD_SETSIZE) {
+                       /* This cannot happen - ignore if so. */
                        continue;
+               }
 
                /* Stevens, Network Programming says that if there's a
                 * successful connect, the socket is only writable. Upon an
@@ -1829,6 +1838,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((struct sockaddr *)&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 ?
 ************************************************************/
@@ -1836,7 +1879,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;
@@ -1884,45 +1926,38 @@ bool is_myname_or_ipaddr(const char *s)
                return true;
        }
 
-       /* Handle possible CNAME records - convert to an IP addr. */
+       /* Handle possible CNAME records - convert to an IP addr. list. */
        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;
+               /* Use DNS to resolve the name, check all addresses. */
+               struct addrinfo *p = NULL;
+               struct addrinfo *res = NULL;
 
-               if (!interpret_string_addr(&ss, servername, AI_NUMERICHOST)) {
+               if (!interpret_string_addr_internal(&res,
+                               servername,
+                               AI_ADDRCONFIG)) {
                        return false;
                }
 
-               if (ismyaddr((struct sockaddr *)&ss)) {
-                       return true;
-               }
-
-               if (is_zero_addr((struct sockaddr *)&ss) || 
-                       is_loopback_addr((struct sockaddr *)&ss)) {
-                       return false;
-               }
+               for (p = res; p; p = p->ai_next) {
+                       char addr[INET6_ADDRSTRLEN];
+                       struct sockaddr_storage ss;
 
-               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);
+                       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);
+       }
+
+       /* Maybe its an IP address? */
+       if (is_ipaddress(servername)) {
+               return is_my_ipaddr(servername);
        }
 
        /* No match */