From: Steve Dickson Date: Wed, 7 Jan 2009 17:03:07 +0000 (-0500) Subject: Merge branch 'master' of git://linux-nfs.org/nfs-utils X-Git-Tag: nfs-utils-1-1-5~34 X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=commitdiff_plain;h=533e5a05a172306462ac6c11d222a18fe562ec6d;hp=09c7ad1cd9c5ca2fc46631a0057d47309abc8706 Merge branch 'master' of git://linux-nfs.org/nfs-utils --- diff --git a/configure.ac b/configure.ac index 48d76d7..7140f48 100644 --- a/configure.ac +++ b/configure.ac @@ -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 ] ) + 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 ] ) fi dnl ************************************************************* diff --git a/support/nfs/getport.c b/support/nfs/getport.c index 25dca6c..47824a2 100644 --- a/support/nfs/getport.c +++ b/support/nfs/getport.c @@ -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; } diff --git a/utils/mount/network.c b/utils/mount/network.c index 6a9a41a..d262e94 100644 --- a/utils/mount/network.c +++ b/utils/mount/network.c @@ -50,24 +50,6 @@ #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. */