Skip to contentSkip to conversation

Some IPv6 enhancements for nfs-utils

PATCH In review Neil Brown 4 participants 9 messages Aug 4, 2010 – Sep 27, 2010

Subsystems (2)
lore
Share & tools
lore

Neil Brown

author
#0 lore raw

cover Some IPv6 enhancements for nfs-utils

Hi Chuck et al,
I've been playing with IPv6 server support and offer these patches which get us a little bit closer.
I realise that you may already have similar patches queued in which case feel free to ignore these.

With these plus a couple of #defines of IPV6_SUPPORTED I can export with NFSv4 over IPv6 quite successfully.

NeilBrown

---

Neil Brown (3):
Make buffers large enough for IPv6 addresses Give hostname.c more support for IPv6 Allow check_fqdn to compare IPv6 addresses

 support/export/client.c   |   23 +----------------------
 support/export/hostname.c |   28 +++++++++++++++++++---------
 utils/mountd/cache.c      |    6 +++---
 utils/mountd/rmtab.c      |    2 +-
 4 files changed, 24 insertions(+), 35 deletions(-)
Signature · 1 line
Signature
author
#1 lore raw

PATCH 1/3 Make buffers large enough for IPv6 addresses

Each of these buffers is use to hold the presentation format for an address which could be either IPv4 or IPv6, so make the buffers large enough for either.

---
 support/export/hostname.c |    2 +-
 utils/mountd/cache.c      |    6 +++---
 utils/mountd/rmtab.c      |    2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)
support/export/hostname.c +1 -1
index 232e040..f6a59f1 100644
@@ -299,7 +299,7 @@ struct addrinfo *
 host_numeric_addrinfo(const struct sockaddr *sap)
 {
 	socklen_t salen = sockaddr_size(sap);
-	char buf[INET_ADDRSTRLEN];
+	char buf[INET6_ADDRSTRLEN];
 	struct addrinfo *ai;
 	int error;
 
utils/mountd/cache.c +3 -3
index bf18a9a..736668e 100644
@@ -75,7 +75,7 @@ void auth_unix_ip(FILE *f)
 	 */
 	char *cp;
 	char class[20];
-	char ipaddr[20];
+	char ipaddr[INET6_ADDRSTRLEN];
 	char *client = NULL;
 	struct addrinfo *tmp = NULL;
 	struct addrinfo *ai = NULL;
@@ -90,7 +90,7 @@ void auth_unix_ip(FILE *f)
 	    strcmp(class, "nfsd") != 0)
 		return;
 
-	if (qword_get(&cp, ipaddr, 20) <= 0)
+	if (qword_get(&cp, ipaddr, sizeof(ipaddr)) <= 0)
 		return;
 
 	tmp = host_pton(ipaddr);
@@ -920,7 +920,7 @@ int cache_export_ent(char *domain, struct exportent *exp, char *path)
 
 int cache_export(nfs_export *exp, char *path)
 {
-	char buf[INET_ADDRSTRLEN];
+	char buf[INET6_ADDRSTRLEN];
 	int err;
 	FILE *f;
 
utils/mountd/rmtab.c +1 -1
index ba0fcf6..d86b0db 100644
@@ -143,7 +143,7 @@ mountlist_del_all(struct sockaddr_in *sin)
 		return;
 	hostname = host_canonname((struct sockaddr *)sin);
 	if (hostname == NULL) {
-		char buf[INET_ADDRSTRLEN];
+		char buf[INET6_ADDRSTRLEN];
 		xlog(L_ERROR, "can't get hostname of %s",
 			host_ntop((struct sockaddr *)sin, buf, sizeof(buf)));
 		goto out_unlock;
#2 lore raw

Re: [PATCH 1/3] Make buffers large enough for IPv6 addresses

Quoted 62 lines · Neil Brown

Each of these buffers is use to hold the presentation format for an address which could be either IPv4 or IPv6, so make the buffers large enough for either.

---
 support/export/hostname.c |    2 +-
 utils/mountd/cache.c      |    6 +++---
 utils/mountd/rmtab.c      |    2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)
support/export/hostname.c +1 -1
index 232e040..f6a59f1 100644
@@ -299,7 +299,7 @@ struct addrinfo *
 host_numeric_addrinfo(const struct sockaddr *sap)
 {
 	socklen_t salen = sockaddr_size(sap);
-	char buf[INET_ADDRSTRLEN];
+	char buf[INET6_ADDRSTRLEN];
 	struct addrinfo *ai;
 	int error;
 
utils/mountd/cache.c +3 -3
index bf18a9a..736668e 100644
@@ -75,7 +75,7 @@ void auth_unix_ip(FILE *f)
 	 */
 	char *cp;
 	char class[20];
-	char ipaddr[20];
+	char ipaddr[INET6_ADDRSTRLEN];
 	char *client = NULL;
 	struct addrinfo *tmp = NULL;
 	struct addrinfo *ai = NULL;
@@ -90,7 +90,7 @@ void auth_unix_ip(FILE *f)
 	    strcmp(class, "nfsd") != 0)
 		return;
 
-	if (qword_get(&cp, ipaddr, 20) <= 0)
+	if (qword_get(&cp, ipaddr, sizeof(ipaddr)) <= 0)
 		return;
 
 	tmp = host_pton(ipaddr);
@@ -920,7 +920,7 @@ int cache_export_ent(char *domain, struct exportent *exp, char *path)
 
 int cache_export(nfs_export *exp, char *path)
 {
-	char buf[INET_ADDRSTRLEN];
+	char buf[INET6_ADDRSTRLEN];
 	int err;
 	FILE *f;
 
utils/mountd/rmtab.c +0 -0
index ba0fcf6..d86b0db 100644

utils/mountd/rmtab.c mountlist_del_all(struct sockaddr_in *sin) · line 149

Quoted 8 lines
utils/mountd/rmtab.c +1 -1
@@ -143,7 +143,7 @@ mountlist_del_all(struct sockaddr_in *sin)
 		return;
 	hostname = host_canonname((struct sockaddr *)sin);
 	if (hostname == NULL) {
-		char buf[INET_ADDRSTRLEN];
+		char buf[INET6_ADDRSTRLEN];
 		xlog(L_ERROR, "can't get hostname of %s",
 			host_ntop((struct sockaddr *)sin, buf, sizeof(buf)));
 		goto out_unlock;

These size changes already exist due to commit d901e32

steved.

author
#3 lore raw

PATCH 2/3 Give hostname.c more support for IPv6

In reply to Neil Brown

Allow host_pton, host_addrinfo, and all functions that use sockaddr_size to work correctly with IPv6 addresses.

This means host_addrinfo can now return IPv6 addresses, but I think all code is ready for that.

---
 support/export/hostname.c |   26 ++++++++++++++++++--------
 1 files changed, 18 insertions(+), 8 deletions(-)
support/export/hostname.c +18 -8
index f6a59f1..46ddfe2 100644
@@ -38,9 +38,11 @@
 static socklen_t
 sockaddr_size(const struct sockaddr *sap)
 {
-	if (sap->sa_family != AF_INET)
-		return 0;
-	return (socklen_t)sizeof(struct sockaddr_in);
+	if (sap->sa_family == AF_INET)
+		return (socklen_t)sizeof(struct sockaddr_in);
+	if (sap->sa_family == AF_INET6)
+		return (socklen_t)sizeof(struct sockaddr_in6);
+	return 0;
 }
 #endif	/* HAVE_GETNAMEINFO */
 
@@ -126,10 +128,12 @@ host_pton(const char *paddr)
 	 * addresses that end with a blank.
 	 *
 	 * inet_pton(3) is much stricter.  Use it to be certain we
-	 * have a real AF_INET presentation address, before invoking
-	 * getaddrinfo(3) to generate the full addrinfo list.
+	 * have a real AF_INET or AF_INET6 presentation address,
+	 * before invoking getaddrinfo(3) to generate the full
+	 * addrinfo list.
 	 */
-	if (inet_pton(AF_INET, paddr, &sin.sin_addr) == 0)
+	if (inet_pton(AF_INET, paddr, &sin.sin_addr) == 0 &&
+	    inet_pton(AF_INET6, paddr, &sin.sin_addr) == 0)
 		return NULL;
 
 	error = getaddrinfo(paddr, NULL, &hint, &ai);
@@ -168,7 +172,7 @@ host_addrinfo(const char *hostname)
 {
 	struct addrinfo *ai = NULL;
 	struct addrinfo hint = {
-		.ai_family	= AF_INET,
+		.ai_family	= AF_UNSPEC,
 		/* don't return duplicates */
 		.ai_protocol	= (int)IPPROTO_UDP,
 		.ai_flags	= AI_ADDRCONFIG | AI_CANONNAME,
@@ -178,7 +182,13 @@ host_addrinfo(const char *hostname)
 	error = getaddrinfo(hostname, NULL, &hint, &ai);
 	switch (error) {
 	case 0:
-		return ai;
+		if (ai->ai_family == AF_INET ||
+		    ai->ai_family == AF_INET6)
+			return ai;
+		freeaddrinfo(ai);
+		xlog(D_GENERAL, "%s: resolved to neither IPv4 nor IPv6 address.",
+				hostname);
+		break;
 	case EAI_SYSTEM:
 		xlog(D_GENERAL, "%s: failed to resolve %s: (%d) %m",
 				__func__, hostname, errno);
#4 lore raw

Re: [PATCH 2/3] Give hostname.c more support for IPv6

Neil Brown wrote:

+ if (inet_pton(AF_INET, paddr, &sin.sin_addr) == 0 &&
+ inet_pton(AF_INET6, paddr, &sin.sin_addr) == 0)
return NULL;

Having converted a few apps myself, I wish there were an equivalent to inet_pton that instead of taking an AF argument, would return the AF that it found. Then you could do the above in a single call.

#5 lore raw

Re: [PATCH 2/3] Give hostname.c more support for IPv6

In reply to Neil Brown
Quoted 19 lines · Neil Brown

Allow host_pton, host_addrinfo, and all functions that use sockaddr_size to work correctly with IPv6 addresses.

This means host_addrinfo can now return IPv6 addresses, but I think all code is ready for that.

---
 support/export/hostname.c |   26 ++++++++++++++++++--------
 1 files changed, 18 insertions(+), 8 deletions(-)
support/export/hostname.c +0 -0
index f6a59f1..46ddfe2 100644
@@ -38,9 +38,11 @@
 static socklen_t
 sockaddr_size(const struct sockaddr *sap)
 {

support/export/hostname.c line 47

Quoted 10 lines
support/export/hostname.c +5 -3
-	if (sap->sa_family != AF_INET)
-		return 0;
-	return (socklen_t)sizeof(struct sockaddr_in);
+	if (sap->sa_family == AF_INET)
+		return (socklen_t)sizeof(struct sockaddr_in);
+	if (sap->sa_family == AF_INET6)
+		return (socklen_t)sizeof(struct sockaddr_in6);
+	return 0;
 }
 #endif	/* HAVE_GETNAMEINFO */

This routine was eliminated with commit 63afb9

Quoted 5 lines
support/export/hostname.c +0 -0
@@ -126,10 +128,12 @@ host_pton(const char *paddr)
 	 * addresses that end with a blank.
 	 *
 	 * inet_pton(3) is much stricter.  Use it to be certain we

support/export/hostname.c host_pton(const char *paddr) · line 137

Quoted 10 lines
support/export/hostname.c +5 -3
-	 * have a real AF_INET presentation address, before invoking
-	 * getaddrinfo(3) to generate the full addrinfo list.
+	 * have a real AF_INET or AF_INET6 presentation address,
+	 * before invoking getaddrinfo(3) to generate the full
+	 * addrinfo list.
 	 */
-	if (inet_pton(AF_INET, paddr, &sin.sin_addr) == 0)
+	if (inet_pton(AF_INET, paddr, &sin.sin_addr) == 0 &&
+	    inet_pton(AF_INET6, paddr, &sin.sin_addr) == 0)
 		return NULL;

This error case is already handled in the current version of of host_pton, but I must say, the above approved is much clear than the existing code... but I'm going to leave things as-is..

Quoted 13 lines
support/export/hostname.c +1 -1
 	error = getaddrinfo(paddr, NULL, &hint, &ai);
@@ -168,7 +172,7 @@ host_addrinfo(const char *hostname)
 {
 	struct addrinfo *ai = NULL;
 	struct addrinfo hint = {
-		.ai_family	= AF_INET,
+		.ai_family	= AF_UNSPEC,
 		/* don't return duplicates */
 		.ai_protocol	= (int)IPPROTO_UDP,
 		.ai_flags	= AI_ADDRCONFIG | AI_CANONNAME,
@@ -178,7 +182,13 @@ host_addrinfo(const char *hostname)
 	error = getaddrinfo(hostname, NULL, &hint, &ai);

support/export/hostname.c host_addrinfo(const char *hostname) · line 191

Quoted 10 lines
support/export/hostname.c +7 -1
 	switch (error) {
 	case 0:
-		return ai;
+		if (ai->ai_family == AF_INET ||
+		    ai->ai_family == AF_INET6)
+			return ai;
+		freeaddrinfo(ai);
+		xlog(D_GENERAL, "%s: resolved to neither IPv4 nor IPv6 address.",
+				hostname);
+		break;

I think I'm going to try and blend this in with Chuck's recent patches since I do like the idea of logging unsupported address families...

steved.

Quoted 5 lines
support/export/hostname.c +0 -0
 	case EAI_SYSTEM:
 		xlog(D_GENERAL, "%s: failed to resolve %s: (%d) %m",
 				__func__, hostname, errno);
author
#6 lore raw

PATCH 3/3 Allow check_fqdn to compare IPv6 addresses

In reply to Neil Brown

Simply use nfs_compare_sockaddr in place of addrs_match

---
 support/export/client.c |   23 +----------------------
 1 files changed, 1 insertions(+), 22 deletions(-)
support/export/client.c +1 -22
index dc01067..286dcd6 100644
@@ -372,27 +372,6 @@ add_name(char *old, const char *add)
 	return new;
 }
 
-static _Bool
-addrs_match4(const struct sockaddr *sa1, const struct sockaddr *sa2)
-{
-	const struct sockaddr_in *si1 = (const struct sockaddr_in *)sa1;
-	const struct sockaddr_in *si2 = (const struct sockaddr_in *)sa2;
-
-	return si1->sin_addr.s_addr == si2->sin_addr.s_addr;
-}
-
-static _Bool
-addrs_match(const struct sockaddr *sa1, const struct sockaddr *sa2)
-{
-	if (sa1->sa_family == sa2->sa_family)
-		switch (sa1->sa_family) {
-		case AF_INET:
-			return addrs_match4(sa1, sa2);
-		}
-
-	return false;
-}
-
 /*
  * Check each address listed in @ai against each address
  * stored in @clp.  Return 1 if a match is found, otherwise
@@ -405,7 +384,7 @@ check_fqdn(const nfs_client *clp, const struct addrinfo *ai)
 
 	for (; ai; ai = ai->ai_next)
 		for (i = 0; i < clp->m_naddr; i++)
-			if (addrs_match(ai->ai_addr, get_addrlist(clp, i)))
+			if (nfs_compare_sockaddr(ai->ai_addr, get_addrlist(clp, i)))
 				return 1;
 
 	return 0;
#7 lore raw

Re: [PATCH 3/3] Allow check_fqdn to compare IPv6 addresses

Quoted 42 lines · Neil Brown

Simply use nfs_compare_sockaddr in place of addrs_match

---
 support/export/client.c |   23 +----------------------
 1 files changed, 1 insertions(+), 22 deletions(-)
support/export/client.c +0 -21
index dc01067..286dcd6 100644
@@ -372,27 +372,6 @@ add_name(char *old, const char *add)
 	return new;
 }
 
-static _Bool
-addrs_match4(const struct sockaddr *sa1, const struct sockaddr *sa2)
-{
-	const struct sockaddr_in *si1 = (const struct sockaddr_in *)sa1;
-	const struct sockaddr_in *si2 = (const struct sockaddr_in *)sa2;
-
-	return si1->sin_addr.s_addr == si2->sin_addr.s_addr;
-}
-
-static _Bool
-addrs_match(const struct sockaddr *sa1, const struct sockaddr *sa2)
-{
-	if (sa1->sa_family == sa2->sa_family)
-		switch (sa1->sa_family) {
-		case AF_INET:
-			return addrs_match4(sa1, sa2);
-		}
-
-	return false;
-}
-
 /*
  * Check each address listed in @ai against each address
  * stored in @clp.  Return 1 if a match is found, otherwise

support/export/client.c check_fqdn(const nfs_client *clp, const struct addrinfo *ai) · line 390

Quoted 8 lines
support/export/client.c +1 -1
@@ -405,7 +384,7 @@ check_fqdn(const nfs_client *clp, const struct addrinfo *ai)
 
 	for (; ai; ai = ai->ai_next)
 		for (i = 0; i < clp->m_naddr; i++)
-			if (addrs_match(ai->ai_addr, get_addrlist(clp, i)))
+			if (nfs_compare_sockaddr(ai->ai_addr, get_addrlist(clp, i)))
 				return 1;
 
 	return 0;

This change already exists due to commit 60abb9

steved.

#8 lore raw
In reply to Neil Brown

Hi Neil-

Quoted 5 lines · Neil Brown

Hi Chuck et al,
I've been playing with IPv6 server support and offer these patches which get us a little bit closer.
I realise that you may already have similar patches queued in which case feel free to ignore these.

The full series of patches giving mountd IPv6 support is in my git repo on linux-nfs.org. See:

http://git.linux-nfs.org/?p=cel/nfs-utils.git;a=summary

This is what we have queued up. We're taking a resting stop for the next nfs-utils release since the pre-requisite patches touched so many parts of mountd, and we'd like to give them some soak time.

If SuSE requires NFS server-side IPv6 support, would it be possible for you to try out my series? It looks like you touched all the important bases in your patch set.

Quoted 13 lines

With these plus a couple of #defines of IPV6_SUPPORTED I can export with NFSv4 over IPv6 quite successfully.

NeilBrown

---

Neil Brown (3):
Make buffers large enough for IPv6 addresses
Give hostname.c more support for IPv6
Allow check_fqdn to compare IPv6 addresses

Quoted 9 lines
support/export/client.c   |   23 +----------------------
support/export/hostname.c |   28 +++++++++++++++++++---------
utils/mountd/cache.c      |    6 +++---
utils/mountd/rmtab.c      |    2 +-
4 files changed, 24 insertions(+), 35 deletions(-)
Signature · 1 line
Signature

--
Chuck Lever
chuck[dot]lever[at]oracle[dot]com