]> git.decadent.org.uk Git - nfs-utils.git/blobdiff - support/export/hostname.c
nfs: fix host_reliable_addrinfo
[nfs-utils.git] / support / export / hostname.c
index 232e04038daaa8f5b0c8592369ee5deff3a99c9e..3e949a18fe52255b51a4d77713f28b1679f16b75 100644 (file)
 #include "sockaddr.h"
 #include "exportfs.h"
 
-#ifndef HAVE_DECL_AI_ADDRCONFIG
-#define AI_ADDRCONFIG  0
-#endif
-
-#ifdef HAVE_GETNAMEINFO
-static socklen_t
-sockaddr_size(const struct sockaddr *sap)
-{
-       if (sap->sa_family != AF_INET)
-               return 0;
-       return (socklen_t)sizeof(struct sockaddr_in);
-}
-#endif /* HAVE_GETNAMEINFO */
-
 /**
  * host_ntop - generate presentation address given a sockaddr
  * @sap: pointer to socket address
@@ -56,7 +42,7 @@ sockaddr_size(const struct sockaddr *sap)
 char *
 host_ntop(const struct sockaddr *sap, char *buf, const size_t buflen)
 {
-       socklen_t salen = sockaddr_size(sap);
+       socklen_t salen = nfs_sockaddr_length(sap);
        int error;
 
        memset(buf, 0, buflen);
@@ -117,7 +103,7 @@ host_pton(const char *paddr)
                .ai_family      = AF_UNSPEC,
        };
        struct sockaddr_in sin;
-       int error;
+       int error, inet4;
 
        /*
         * Although getaddrinfo(3) is easier to use and supports
@@ -129,12 +115,17 @@ host_pton(const char *paddr)
         * have a real AF_INET presentation address, before invoking
         * getaddrinfo(3) to generate the full addrinfo list.
         */
+       inet4 = 1;
        if (inet_pton(AF_INET, paddr, &sin.sin_addr) == 0)
-               return NULL;
+               inet4 = 0;
 
        error = getaddrinfo(paddr, NULL, &hint, &ai);
        switch (error) {
        case 0:
+               if (!inet4 && ai->ai_addr->sa_family == AF_INET) {
+                       freeaddrinfo(ai);
+                       break;
+               }
                return ai;
        case EAI_NONAME:
                if (paddr == NULL)
@@ -168,10 +159,14 @@ host_addrinfo(const char *hostname)
 {
        struct addrinfo *ai = NULL;
        struct addrinfo hint = {
+#ifdef IPV6_SUPPORTED
+               .ai_family      = AF_UNSPEC,
+#else
                .ai_family      = AF_INET,
+#endif
                /* don't return duplicates */
                .ai_protocol    = (int)IPPROTO_UDP,
-               .ai_flags       = AI_ADDRCONFIG | AI_CANONNAME,
+               .ai_flags       = AI_CANONNAME,
        };
        int error;
 
@@ -208,7 +203,7 @@ __attribute_malloc__
 char *
 host_canonname(const struct sockaddr *sap)
 {
-       socklen_t salen = sockaddr_size(sap);
+       socklen_t salen = nfs_sockaddr_length(sap);
        char buf[NI_MAXHOST];
        int error;
 
@@ -263,17 +258,19 @@ host_canonname(const struct sockaddr *sap)
  * @sap: pointer to socket address to look up
  *
  * Reverse and forward lookups are performed to ensure the address has
- * proper forward and reverse mappings.
+ * matching forward and reverse mappings.
  *
- * Returns address info structure with ai_canonname filled in, or NULL
- * if no information is available for @sap.  Caller must free the returned
- * structure with freeaddrinfo(3).
+ * Returns addrinfo structure with just the provided address with
+ * ai_canonname filled in. If there is a problem with resolution or
+ * the resolved records don't match up properly then it returns NULL
+ *
+ * Caller must free the returned structure with freeaddrinfo(3).
  */
 __attribute_malloc__
 struct addrinfo *
 host_reliable_addrinfo(const struct sockaddr *sap)
 {
-       struct addrinfo *ai;
+       struct addrinfo *ai, *a;
        char *hostname;
 
        hostname = host_canonname(sap);
@@ -281,9 +278,31 @@ host_reliable_addrinfo(const struct sockaddr *sap)
                return NULL;
 
        ai = host_addrinfo(hostname);
+       if (!ai)
+               goto out_free_hostname;
+
+       /* make sure there's a matching address in the list */
+       for (a = ai; a; a = a->ai_next)
+               if (nfs_compare_sockaddr(a->ai_addr, sap))
+                       break;
+
+       freeaddrinfo(ai);
+       if (!a)
+               goto out_free_hostname;
+
+       /* get addrinfo with just the original address */
+       ai = host_numeric_addrinfo(sap);
+       if (!ai)
+               goto out_free_hostname;
+
+       /* and populate its ai_canonname field */
+       free(ai->ai_canonname);
+       ai->ai_canonname = hostname;
+       return ai;
 
+out_free_hostname:
        free(hostname);
-       return ai;
+       return NULL;
 }
 
 /**
@@ -298,8 +317,8 @@ __attribute_malloc__
 struct addrinfo *
 host_numeric_addrinfo(const struct sockaddr *sap)
 {
-       socklen_t salen = sockaddr_size(sap);
-       char buf[INET_ADDRSTRLEN];
+       socklen_t salen = nfs_sockaddr_length(sap);
+       char buf[INET6_ADDRSTRLEN];
        struct addrinfo *ai;
        int error;