]> git.decadent.org.uk Git - nfs-utils.git/commitdiff
Merge branch 'master' of git://linux-nfs.org/nfs-utils
authorSteve Dickson <steved@redhat.com>
Wed, 7 Jan 2009 17:03:07 +0000 (12:03 -0500)
committerSteve Dickson <steved@redhat.com>
Wed, 7 Jan 2009 17:03:07 +0000 (12:03 -0500)
configure.ac
support/nfs/getport.c
utils/mount/network.c

index 48d76d7c2a64dfac5abdcf98e1858dc1e77ee4cf..7140f48cbf5c10a0cd31ed1d38c1397635f7ba35 100644 (file)
@@ -109,7 +109,7 @@ AC_ARG_WITH(rpcgen,
        AC_SUBST(RPCGEN_PATH)
        AM_CONDITIONAL(CONFIG_RPCGEN, [test "$RPCGEN_PATH" == ""])
 AC_ARG_ENABLE(uuid,
-       [AC_HELP_STRING([--without-uuid], [Exclude uuid support and so avoid possibly buggy libblkid])],
+       [AC_HELP_STRING([--disable-uuid], [Exclude uuid support to avoid buggy libblkid])],
        if test "$enableval" = "yes" ; then choose_blkid=yes; else choose_blkid=no; fi,
        choose_blkid=default)
 AC_ARG_ENABLE(mount,
@@ -246,6 +246,11 @@ if test "$enable_gss" = yes; then
 
 fi
 
+AC_CHECK_DECL([AI_ADDRCONFIG],
+              AC_DEFINE([HAVE_DECL_AI_ADDRCONFIG], 1,
+                         [Define this to 1 if AI_ADDRCONFIG macro is defined]), ,
+              [ #include <netdb.h> ] )
+
 if test "$enable_ipv6" = yes; then
   AC_CHECK_FUNC(inet_ntop, , ,
                AC_MSG_ERROR(Function 'inet_ntop' not found.))
@@ -254,7 +259,10 @@ if test "$enable_ipv6" = yes; then
   AC_CHECK_LIB(tirpc, clnt_tli_create, ,
                AC_MSG_ERROR([libtirpc needed for IPv6 support]))
   AC_CHECK_HEADERS(tirpc/netconfig.h, ,
-               AC_MSG_ERROR([libtirpc-devel needed for IPv6 support]))
+               AC_MSG_ERROR([libtirpc headers needed for IPv6 support]))
+  AC_CHECK_DECL([AI_ADDRCONFIG], ,
+               AC_MSG_ERROR([full getaddrinfo(3) implementation needed for IPv6 support]),
+               [ #include <netdb.h> ] )
 fi
 
 dnl *************************************************************
index 25dca6c0a9da38372332df67a0c057d49f280f2e..47824a24e5a969410cad9424206d927eafbf1bd9 100644 (file)
@@ -73,6 +73,60 @@ static const char *nfs_gp_rpcb_pgmtbl[] = {
        NULL,
 };
 
+#ifdef HAVE_DECL_AI_ADDRCONFIG
+/*
+ * getaddrinfo(3) generates a usable loopback address based on how the
+ * local network interfaces are configured.  RFC 3484 requires that the
+ * results are sorted so that the first result has the best likelihood
+ * of working, so we try just that first result.
+ *
+ * Returns TRUE on success.
+ */
+static int nfs_gp_loopback_address(struct sockaddr *sap, socklen_t *salen)
+{
+       struct addrinfo *gai_results;
+       struct addrinfo gai_hint = {
+               .ai_flags       = AI_ADDRCONFIG,
+       };
+       socklen_t len = *salen;
+       int ret = 0;
+
+       if (getaddrinfo(NULL, "sunrpc", &gai_hint, &gai_results))
+               return 0;
+
+       switch (gai_results->ai_addr->sa_family) {
+       case AF_INET:
+       case AF_INET6:
+               if (len >= gai_results->ai_addrlen) {
+                       memcpy(sap, gai_results->ai_addr,
+                                       gai_results->ai_addrlen);
+                       *salen = gai_results->ai_addrlen;
+                       ret = 1;
+               }
+       }
+
+       freeaddrinfo(gai_results);
+       return ret;
+}
+#else
+/*
+ * Old versions of getaddrinfo(3) don't support AI_ADDRCONFIG, so we
+ * have a fallback for building on legacy systems.
+ */
+static int nfs_gp_loopback_address(struct sockaddr *sap, socklen_t *salen)
+{
+       struct sockaddr_in *sin = (struct sockaddr_in *)sap;
+
+       memset(sin, 0, sizeof(*sin));
+
+       sin->sin_family = AF_INET;
+       sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+       *salen = sizeof(*sin);
+
+       return 1;
+}
+#endif
+
 /*
  * Discover the port number that should be used to contact an
  * rpcbind service.  This will detect if the port has a local
@@ -780,12 +834,10 @@ unsigned short nfs_getlocalport(const rpcprot_t program,
                                const rpcvers_t version,
                                const unsigned short protocol)
 {
-       struct addrinfo *gai_results;
-       struct addrinfo gai_hint = {
-               .ai_flags       = AI_ADDRCONFIG,
-       };
+       struct sockaddr_storage address;
+       struct sockaddr *lb_addr = (struct sockaddr *)&address;
+       socklen_t lb_len = sizeof(lb_addr);
        unsigned short port = 0;
-       int error;
 
 #ifdef NFS_GP_LOCAL
        const struct sockaddr_un sun = {
@@ -811,12 +863,9 @@ unsigned short nfs_getlocalport(const rpcprot_t program,
 #endif /* NFS_GP_LOCAL */
 
        if (port == 0) {
-               error = getaddrinfo(NULL, "sunrpc", &gai_hint, &gai_results);
-               if (error == 0) {
-                       port = nfs_getport(gai_results->ai_addr,
-                                               gai_results->ai_addrlen,
+               if (nfs_gp_loopback_address(lb_addr, &lb_len)) {
+                       port = nfs_getport(lb_addr, lb_len,
                                                program, version, protocol);
-                       freeaddrinfo(gai_results);
                } else
                        rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
        }
index 6a9a41a9f358b839cfbc89fdcb65dab351ac88f7..d262e940091e195449d9d0aea05473a556c2b9fe 100644 (file)
 #include "nfsrpc.h"
 #include "network.h"
 
-/*
- * Earlier versions of glibc's /usr/include/netdb.h exclude these
- * definitions because it was thought they were not part of a stable
- * POSIX standard.  However, they are defined by RFC 2553 and 3493
- * and in POSIX 1003.1-2001, so these definitions were added in later
- * versions of netdb.h.
- */
-#ifndef AI_V4MAPPED
-#define AI_V4MAPPED     0x0008  /* IPv4-mapped addresses are acceptable.  */
-#endif /* AI_V4MAPPED */
-#ifndef AI_ALL
-#define AI_ALL          0x0010  /* Return both IPv4 and IPv6 addresses.  */
-#endif /* AI_ALL */
-#ifndef AI_ADDRCONFIG
-#define AI_ADDRCONFIG   0x0020  /* Use configuration of this host to choose \
-                                  returned address type.  */
-#endif /* AI_ADDRCONFIG */
-
 #define PMAP_TIMEOUT   (10)
 #define CONNECT_TIMEOUT        (20)
 #define MOUNT_TIMEOUT  (30)
@@ -175,9 +157,11 @@ static void nfs_set_port(struct sockaddr *sap, const unsigned short port)
        }
 }
 
+#ifdef HAVE_DECL_AI_ADDRCONFIG
 /**
  * nfs_name_to_address - resolve hostname to an IPv4 or IPv6 socket address
  * @hostname: pointer to C string containing DNS hostname to resolve
+ * @af_hint: hint to restrict resolution to one address family
  * @sap: pointer to buffer to fill with socket address
  * @len: IN: size of buffer to fill; OUT: size of socket address
  *
@@ -228,11 +212,66 @@ int nfs_name_to_address(const char *hostname,
        freeaddrinfo(gai_results);
        return ret;
 }
+#else  /* HAVE_DECL_AI_ADDRCONFIG */
+/**
+ * nfs_name_to_address - resolve hostname to an IPv4 socket address
+ * @hostname: pointer to C string containing DNS hostname to resolve
+ * @af_hint: hint to restrict resolution to one address family
+ * @sap: pointer to buffer to fill with socket address
+ * @len: IN: size of buffer to fill; OUT: size of socket address
+ *
+ * Returns 1 and places a socket address at @sap if successful;
+ * otherwise zero.
+ *
+ * Some older getaddrinfo(3) implementations don't support
+ * AI_ADDRCONFIG or AI_V4MAPPED properly.  For those cases, a DNS
+ * resolver based on the traditional gethostbyname(3) is provided.
+ */
+int nfs_name_to_address(const char *hostname,
+                       const sa_family_t af_hint,
+                       struct sockaddr *sap, socklen_t *salen)
+{
+       struct sockaddr_in *sin = (struct sockaddr_in *)sap;
+       socklen_t len = *salen;
+       struct hostent *hp;
+
+       *salen = 0;
+
+       if (af_hint != AF_INET) {
+               nfs_error(_("%s: address family not supported by DNS resolver\n"),
+                               progname, hostname);
+               return 0;
+       }
+
+       sin->sin_family = AF_INET;
+       if (inet_aton(hostname, &sin->sin_addr)) {
+               *salen = sizeof(*sin);
+               return 1;
+       }
+
+       hp = gethostbyname(hostname);
+       if (hp == NULL) {
+               nfs_error(_("%s: DNS resolution failed for %s: %s"),
+                               progname, hostname, hstrerror(h_errno));
+               return 0;
+       }
+
+       if (hp->h_length > len) {
+               nfs_error(_("%s: DNS resolution results too long for buffer\n"),
+                               progname);
+               return 0;
+       }
+
+       memcpy(&sin->sin_addr, hp->h_addr, hp->h_length);
+       *salen = hp->h_length;
+       return 1;
+}
+#endif /* HAVE_DECL_AI_ADDRCONFIG */
 
 /**
  * nfs_gethostbyname - resolve a hostname to an IPv4 address
  * @hostname: pointer to a C string containing a DNS hostname
- * @saddr: returns an IPv4 address 
+ * @sin: returns an IPv4 address 
  *
  * Returns 1 if successful, otherwise zero.
  */