Convert get_peer_addr() to IPv6. Only is_myname_or_ipaddr()
authorJeremy Allison <jra@samba.org>
Fri, 12 Oct 2007 20:38:04 +0000 (13:38 -0700)
committerJeremy Allison <jra@samba.org>
Fri, 12 Oct 2007 20:38:04 +0000 (13:38 -0700)
lefto to do then I can fix the lib/access.c functions.
Jeremy.

source/lib/util_sock.c

index 5a96bb79d6e56a79224836903d9fde1a087fb273..8c5d1b6feca2426c0247c2a9926142e0af2c67ef 100644 (file)
@@ -1546,41 +1546,102 @@ int open_udp_socket(const char *host, int port)
        return res;
 }
 
+/*******************************************************************
+ Return the IP addr of the remote end of a socket as a string.
+ Optionally return the struct sockaddr_storage.
+ ******************************************************************/
+
+static const char *get_peer_addr_internal(int fd,
+                               struct sockaddr_storage *pss,
+                               socklen_t *plength)
+{
+       struct sockaddr_storage ss;
+       socklen_t length = sizeof(ss);
+       static char addr_buf[INET6_ADDRSTRLEN];
+
+       safe_strcpy(addr_buf,"0.0.0.0",sizeof(addr_buf)-1);
+
+       if (fd == -1) {
+               return addr_buf;
+       }
+
+       if (pss == NULL) {
+               pss = &ss;
+       }
+       if (plength == NULL) {
+               plength = &length;
+       }
+
+       if (getpeername(fd, (struct sockaddr *)pss, plength) < 0) {
+               DEBUG(0,("getpeername failed. Error was %s\n",
+                                       strerror(errno) ));
+               return addr_buf;
+       }
+
+       print_sockaddr(addr_buf,
+                       sizeof(addr_buf),
+                       pss,
+                       *plength);
+       return addr_buf;
+}
+
+
 /*******************************************************************
  Matchname - determine if host name matches IP address. Used to
  confirm a hostname lookup to prevent spoof attacks.
 ******************************************************************/
 
-static bool matchname(char *remotehost,struct in_addr  addr)
+static bool matchname(const char *remotehost,
+               const struct sockaddr_storage *pss,
+               socklen_t len)
 {
-       struct hostent *hp;
-       int     i;
+       struct addrinfo hints;
+       struct addrinfo *res = NULL;
+       struct addrinfo *ailist = NULL;
+       char addr_buf[INET6_ADDRSTRLEN];
+       int ret = -1;
+
+       memset(&hints,'\0',sizeof(struct addrinfo));
+       /* By default make sure it supports TCP. */
+       hints.ai_socktype = SOCK_STREAM;
+       hints.ai_flags = AI_ADDRCONFIG|AI_CANONNAME;
 
-       if ((hp = sys_gethostbyname(remotehost)) == 0) {
-               DEBUG(0,("sys_gethostbyname(%s): lookup failure.\n",
-                                       remotehost));
+       ret = getaddrinfo(remotehost, NULL,
+                       &hints,
+                       &res);
+
+       if (ret || res == NULL) {
+               DEBUG(3,("matchname: getaddrinfo failed for "
+                       "name %s [%s]\n",
+                       remotehost,
+                       gai_strerror(ret) ));
                return false;
        }
 
        /*
-        * Make sure that gethostbyname() returns the "correct" host name.
-        * Unfortunately, gethostbyname("localhost") sometimes yields
-        * "localhost.domain". Since the latter host name comes from the
-        * local DNS, we just have to trust it (all bets are off if the local
-        * DNS is perverted). We always check the address list, though.
+        * Make sure that getaddrinfo() returns the "correct" host name.
         */
 
-       if (!strequal(remotehost, hp->h_name)
-           && !strequal(remotehost, "localhost")) {
-               DEBUG(0,("host name/name mismatch: %s != %s\n",
-                        remotehost, hp->h_name));
+       if (res->ai_canonname == NULL ||
+               (!strequal(remotehost, res->ai_canonname) &&
+                !strequal(remotehost, "localhost"))) {
+               DEBUG(0,("matchname: host name/name mismatch: %s != %s\n",
+                        remotehost,
+                        res->ai_canonname ? res->ai_canonname : "(NULL)"));
+               freeaddrinfo(res);
                return false;
        }
 
        /* Look up the host address in the address list we just got. */
-       for (i = 0; hp->h_addr_list[i]; i++) {
-               if (memcmp(hp->h_addr_list[i], (char *)&addr,sizeof(addr)) == 0)
+       for (ailist = res; ailist; ailist = ailist->ai_next) {
+               if (!ailist->ai_addr) {
+                       continue;
+               }
+               if (addr_equal((const struct sockaddr_storage *)ailist->ai_addr,
+                                       pss)) {
+                       freeaddrinfo(res);
                        return true;
+               }
        }
 
        /*
@@ -1589,8 +1650,14 @@ static bool matchname(char *remotehost,struct in_addr  addr)
         * it, but that could be dangerous, too.
         */
 
-       DEBUG(0,("host name/address mismatch: %s != %s\n",
-                inet_ntoa(addr), hp->h_name));
+       DEBUG(0,("matchname: host name/address mismatch: %s != %s\n",
+               print_sockaddr(addr_buf,
+                       sizeof(addr_buf),
+                       pss,
+                       len),
+                res->ai_canonname ? res->ai_canonname : "(NULL)"));
+
+       freeaddrinfo(res);
        return false;
 }
 
@@ -1600,12 +1667,13 @@ static bool matchname(char *remotehost,struct in_addr  addr)
 
 const char *get_peer_name(int fd, bool force_lookup)
 {
-       static pstring name_buf;
-       pstring tmp_name;
        static fstring addr_buf;
-       struct hostent *hp;
-       struct in_addr addr;
+       static pstring name_buf;
+       struct sockaddr_storage ss;
+       socklen_t length = sizeof(ss);
        const char *p;
+       int ret;
+       pstring tmp_name;
 
        /* reverse lookups can be *very* expensive, and in many
           situations won't work because many networks don't link dhcp
@@ -1615,28 +1683,37 @@ const char *get_peer_name(int fd, bool force_lookup)
                return get_peer_addr(fd);
        }
 
-       p = get_peer_addr(fd);
+       p = get_peer_addr_internal(fd, &ss, &length);
 
        /* it might be the same as the last one - save some DNS work */
-       if (strcmp(p, addr_buf) == 0)
+       if (strcmp(p, addr_buf) == 0) {
                return name_buf;
+       }
 
        pstrcpy(name_buf,"UNKNOWN");
-       if (fd == -1)
+       if (fd == -1) {
                return name_buf;
+       }
 
        fstrcpy(addr_buf, p);
 
-       addr = *interpret_addr2(p);
-
        /* Look up the remote host name. */
-       if ((hp = gethostbyaddr((char *)&addr.s_addr,
-                                       sizeof(addr.s_addr), AF_INET)) == 0) {
-               DEBUG(1,("Gethostbyaddr failed for %s\n",p));
+       ret = getnameinfo((struct sockaddr *)&ss,
+                       length,
+                       name_buf,
+                       sizeof(name_buf),
+                       NULL,
+                       0,
+                       NI_NUMERICHOST);
+
+       if (ret) {
+               DEBUG(1,("get_peer_name: getnameinfo failed "
+                       "for %s with error %s\n",
+                       p,
+                       gai_strerror(ret)));
                pstrcpy(name_buf, p);
        } else {
-               pstrcpy(name_buf,(char *)hp->h_name);
-               if (!matchname(name_buf, addr)) {
+               if (!matchname(name_buf, &ss, length)) {
                        DEBUG(0,("Matchname failed on %s %s\n",name_buf,p));
                        pstrcpy(name_buf,"UNKNOWN");
                }
@@ -1646,7 +1723,7 @@ const char *get_peer_name(int fd, bool force_lookup)
           use --enable-developer or the clobber_region() call will
           get you */
 
-       pstrcpy( tmp_name, name_buf );
+       pstrcpy(tmp_name, name_buf );
        alpha_strcpy(name_buf, tmp_name, "_-.", sizeof(name_buf));
        if (strstr(name_buf,"..")) {
                pstrcpy(name_buf, "UNKNOWN");
@@ -1661,27 +1738,7 @@ const char *get_peer_name(int fd, bool force_lookup)
 
 const char *get_peer_addr(int fd)
 {
-       struct sockaddr_storage ss;
-       socklen_t length = sizeof(ss);
-       static char addr_buf[INET6_ADDRSTRLEN];
-
-       safe_strcpy(addr_buf,"0.0.0.0",sizeof(addr_buf)-1);
-
-       if (fd == -1) {
-               return addr_buf;
-       }
-
-       if (getpeername(fd, (struct sockaddr *)&ss, &length) < 0) {
-               DEBUG(0,("getpeername failed. Error was %s\n",
-                                       strerror(errno) ));
-               return addr_buf;
-       }
-
-       print_sockaddr(addr_buf,
-                       sizeof(addr_buf),
-                       &ss,
-                       length);
-       return addr_buf;
+       return get_peer_addr_internal(fd, NULL, NULL);
 }
 
 /*******************************************************************