Skip to contentSkip to conversation

nfs-utils: Enabling TCP wrappers

PATCH In review Steve Dickson 2 participants 13 messages Dec 15, 2008 – Dec 20, 2008 3 messages not in the archive

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover nfs-utils: Enabling TCP wrappers

Recently I was asked to re-enable the TCP wrapper calls, that check the validity of client that communicate with mountd and statd.

It became very apparent this code had not been used in a while and was as a bit broken. So this patch set fixes the logic and tries to make the code scale better.

The commit blobs in the set are relative to the 'tcpwrap' branch in the git://linux-nfs.org/~steved/nfs-utils-exp.git
git tree.

Comments?

steved.

A message that is not in the archive (sent off-list or not yet received): [email protected]

#2 lore raw

PATCH 1/3 nfs-utils: Enabling TCP wrappers

commit 0e594fd44041c5c0562ed1dfc19d2c6d5d3ede0f

Author: Steve Dickson <[email protected]>
Date:   Mon Dec 15 10:52:01 2008 -0500

When clients are define as IP addresses in /etc/hosts.deny, access is allow due to misinterpreting the return value of hosts_ctl(). This patch reworks that logic which closes that hole.

support/misc/tcpwrapper.c +45 -44
index e4f453b..ceea5ce 100644
@@ -86,6 +86,9 @@ int hosts_ctl(char *daemon, char *name, char *addr, char *user)
 #define log_client(addr, proc, prog) \
   logit(allow_severity, addr, proc, prog, "")
 
+#define ALLOW 1
+#define DENY 0
+
 int
 good_client(daemon, addr)
 char *daemon;
@@ -95,47 +98,44 @@ struct sockaddr_in *addr;
     char **sp;
     char *tmpname;
 
-    /* Check the IP address first. */
-    if (hosts_ctl(daemon, "", inet_ntoa(addr->sin_addr), ""))
-	return 1;
-
-    /* Check the hostname. */
-    hp = gethostbyaddr ((const char *) &(addr->sin_addr),
-			sizeof (addr->sin_addr), AF_INET);
-
-    if (!hp)
-	return 0;
-
-    /* must make sure the hostent is authorative. */
-    tmpname = alloca (strlen (hp->h_name) + 1);
-    strcpy (tmpname, hp->h_name);
-    hp = gethostbyname(tmpname);
-    if (hp) {
-	/* now make sure the "addr->sin_addr" is on the list */
+	/* First check the address. */
+	if (hosts_ctl(daemon, "", inet_ntoa(addr->sin_addr), "") == DENY)
+		return DENY;
+
+	/* Now do the hostname lookup */
+	hp = gethostbyaddr ((const char *) &(addr->sin_addr),
+		sizeof (addr->sin_addr), AF_INET);
+	if (!hp)
+		return DENY; /* never heard of it. misconfigured DNS? */
+
+	/* Make sure the hostent is authorative. */
+	tmpname = strdup(hp->h_name);
+	if (!tmpname)
+		return DENY;
+	hp = gethostbyname(tmpname);
+	free(tmpname);
+	if (!hp)
+		return DENY; /* never heard of it. misconfigured DNS? */
+
+	/* Now make sure the address is on the list */
 	for (sp = hp->h_addr_list ; *sp ; sp++) {
-	    if (memcmp(*sp, &(addr->sin_addr), hp->h_length)==0)
-		break;
+	    if (memcmp(*sp, &(addr->sin_addr), hp->h_length) == 0)
+			break;
 	}
 	if (!*sp)
-	    /* it was a FAKE. */
-	    return 0;
-    }
-    else
-	   /* never heard of it. misconfigured DNS? */
-	   return 0;
-
-   /* Check the official name first. */
-   if (hosts_ctl(daemon, hp->h_name, "", ""))
-	return 1;
-
-   /* Check aliases. */
-   for (sp = hp->h_aliases; *sp ; sp++) {
-	if (hosts_ctl(daemon, *sp, "", ""))
-	    return 1;
-   }
-
-   /* No match */
-   return 0;
+	    return DENY; /* it was a FAKE. */
+
+	/* Check the official name and address. */
+	if (hosts_ctl(daemon, hp->h_name, inet_ntoa(addr->sin_addr), "") == DENY)
+		return DENY;
+
+	/* Now check aliases. */
+	for (sp = hp->h_aliases; *sp ; sp++) {
+		if (hosts_ctl(daemon, *sp, inet_ntoa(addr->sin_addr), "") == DENY)
+	    	return DENY;
+	}
+
+   return ALLOW;
 }
 
 /* check_startup - additional startup code */
@@ -184,12 +184,13 @@ struct sockaddr_in *addr;
 u_long  proc;
 u_long  prog;
 {
-    if (!(from_local(addr) || good_client(daemon, addr))) {
-	log_bad_host(addr, proc, prog);
-	return (FALSE);
-    }
-    if (verboselog)
-	log_client(addr, proc, prog);
+	if (!(from_local(addr) || good_client(daemon, addr))) {
+		log_bad_host(addr, proc, prog);
+		return (FALSE);
+	}
+	if (verboselog)
+		log_client(addr, proc, prog);
+
     return (TRUE);
 }
 
#3 lore raw

PATCH 2/3 nfs-utils: Enabling TCP wrappers

In reply to a message not in the archive

commit 6f970988b390633efbe3629fc2c19109f7cf96a3

Author: Steve Dickson <[email protected]>
Date:   Mon Dec 15 11:31:45 2008 -0500

Clients IP address and host names are check on every RPC request, to both mountd and statd when TCP wrappers are enabled. To help this process scale better the access rights are stored in a hash table, which are hashed per IP address, RPC program and procudure numbers.

support/misc/tcpwrapper.c +79 -0
index ceea5ce..f7fd3a9 100644
@@ -44,6 +44,7 @@
 #include <pwd.h>
 #include <sys/types.h>
 #include <sys/signal.h>
+#include <sys/queue.h>
 #ifdef SYSV40
 #include <netinet/in.h>
 #include <rpc/rpcent.h>
@@ -89,6 +90,76 @@ int hosts_ctl(char *daemon, char *name, char *addr, char *user)
 #define ALLOW 1
 #define DENY 0
 
+typedef struct _haccess_t {
+	TAILQ_ENTRY(_haccess_t) list;
+	int access;
+    struct in_addr addr;
+} haccess_t;
+
+#define HASH_TABLE_SIZE 1021
+typedef struct _hash_head {
+	TAILQ_HEAD(host_list, _haccess_t) h_head;
+} hash_head;
+hash_head haccess_tbl[HASH_TABLE_SIZE];
+static haccess_t *haccess_lookup(struct sockaddr_in *addr, u_long, u_long);
+static void haccess_add(struct sockaddr_in *addr, u_long, u_long, int);
+
+inline unsigned int strtoint(char *str)
+{
+	unsigned int n = 0;
+	int len = strlen(str);
+	int i;
+
+	for (i=0; i < len; i++)
+		n+=((int)str[i])*i;
+
+	return n;
+}
+inline int hashint(unsigned int num)
+{
+	return num % HASH_TABLE_SIZE;
+}
+#define HASH(_addr, _proc, _prog) \
+	hashint((strtoint((_addr))+(_proc)+(_prog)))
+
+void haccess_add(struct sockaddr_in *addr, u_long proc, 
+	u_long prog, int access)
+{
+	hash_head *head;
+ 	haccess_t *hptr;
+	int hash;
+
+	hptr = (haccess_t *)malloc(sizeof(haccess_t));
+	if (hptr == NULL)
+		return;
+
+	hash = HASH(inet_ntoa(addr->sin_addr), proc, prog);
+	head = &(haccess_tbl[hash]);
+
+	hptr->access = access;
+	hptr->addr.s_addr = addr->sin_addr.s_addr;
+
+	if (TAILQ_EMPTY(&head->h_head))
+		TAILQ_INSERT_HEAD(&head->h_head, hptr, list);
+	else
+		TAILQ_INSERT_TAIL(&head->h_head, hptr, list);
+}
+haccess_t *haccess_lookup(struct sockaddr_in *addr, u_long proc, u_long prog)
+{
+	hash_head *head;
+ 	haccess_t *hptr;
+	int hash;
+
+	hash = HASH(inet_ntoa(addr->sin_addr), proc, prog);
+	head = &(haccess_tbl[hash]);
+
+	TAILQ_FOREACH(hptr, &head->h_head, list) {
+		if (hptr->addr.s_addr == addr->sin_addr.s_addr)
+			return hptr;
+	}
+	return NULL;
+}
+
 int
 good_client(daemon, addr)
 char *daemon;
@@ -184,13 +255,21 @@ struct sockaddr_in *addr;
 u_long  proc;
 u_long  prog;
 {
+	haccess_t *acc = NULL;
+
+	acc = haccess_lookup(addr, proc, prog);
+	if (acc)
+		return (acc->access);
+
 	if (!(from_local(addr) || good_client(daemon, addr))) {
 		log_bad_host(addr, proc, prog);
+		haccess_add(addr, proc, prog, FALSE);
 		return (FALSE);
 	}
 	if (verboselog)
 		log_client(addr, proc, prog);
 
+	haccess_add(addr, proc, prog, TRUE);
     return (TRUE);
 }
 
#4 lore raw

PATCH 3/3 nfs-utils: Enabling TCP wrappers

In reply to a message not in the archive

commit e1956712782b4bb7b4369420bfada972e5bc4398

Author: Steve Dickson <[email protected]>
Date:   Mon Dec 15 11:44:51 2008 -0500

To ensure the hash table of clients has valid access rights, check the modification times on both access files. If one of them have change, update the hash entry instead of creating a new entry.

support/misc/tcpwrapper.c +40 -3
index f7fd3a9..c0c5af7 100644
@@ -45,6 +45,9 @@
 #include <sys/types.h>
 #include <sys/signal.h>
 #include <sys/queue.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
 #ifdef SYSV40
 #include <netinet/in.h>
 #include <rpc/rpcent.h>
@@ -246,6 +249,33 @@ void    check_startup(void)
     (void) signal(SIGINT, toggle_verboselog);
 }
 
+/* check_files - check to see if either access files have changed */
+
+int check_files()
+{
+	static time_t allow_mtime, deny_mtime;
+	struct stat astat, dstat;
+	int changed = 0;
+
+	if (stat("/etc/hosts.allow", &astat) < 0)
+		astat.st_mtime = 0;
+	if (stat("/etc/hosts.deny", &dstat) < 0)
+		dstat.st_mtime = 0;
+
+	if(!astat.st_mtime || !dstat.st_mtime)
+		return changed;
+
+	if (astat.st_mtime != allow_mtime)
+		changed = 1;
+	else if (dstat.st_mtime != deny_mtime)
+		changed = 1;
+
+	allow_mtime = astat.st_mtime;
+	deny_mtime = dstat.st_mtime;
+
+	return changed;
+}
+
 /* check_default - additional checks for NULL, DUMP, GETPORT and unknown */
 
 int
@@ -256,20 +286,27 @@ u_long  proc;
 u_long  prog;
 {
 	haccess_t *acc = NULL;
+	int changed = check_files();
 
 	acc = haccess_lookup(addr, proc, prog);
-	if (acc)
+	if (acc && changed == 0)
 		return (acc->access);
 
 	if (!(from_local(addr) || good_client(daemon, addr))) {
 		log_bad_host(addr, proc, prog);
-		haccess_add(addr, proc, prog, FALSE);
+		if (acc)
+			acc->access = FALSE;
+		else 
+			haccess_add(addr, proc, prog, FALSE);
 		return (FALSE);
 	}
 	if (verboselog)
 		log_client(addr, proc, prog);
 
-	haccess_add(addr, proc, prog, TRUE);
+	if (acc)
+		acc->access = TRUE;
+	else 
+		haccess_add(addr, proc, prog, TRUE);
     return (TRUE);
 }
 
#5 lore raw
In reply to a message not in the archive
Quoted 7 lines · Steve Dickson

Recently I was asked to re-enable the TCP wrapper calls, that check the validity of client that communicate with mountd and statd.

It became very apparent this code had not been used in a while and was as a bit broken. So this patch set fixes the logic and tries to make the code scale better.

Quoted 5 lines

The commit blobs in the set are relative to the 'tcpwrap' branch in the git://linux-nfs.org/~steved/nfs-utils-exp.git
git tree.

Comments?

A general comment: This code will need support for IPv6 addresses.

Until it has it, perhaps we should add some logic to configure.ac that prevents the use of tcpwrappers when --enable-ipv6 is in effect.

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

#6 lore raw
Quoted 12 lines · Chuck Lever
Quoted 11 lines · Steve Dickson

Recently I was asked to re-enable the TCP wrapper calls, that check the validity of client that communicate with mountd and statd.

It became very apparent this code had not been used in a while and was as a bit broken. So this patch set fixes the logic and tries to make the code scale better.

The commit blobs in the set are relative to the 'tcpwrap' branch in the git://linux-nfs.org/~steved/nfs-utils-exp.git
git tree.

Quoted 6 lines
Quoted 1 line

Comments?

A general comment: This code will need support for IPv6 addresses.

Until it has it, perhaps we should add some logic to configure.ac that prevents the use of tcpwrappers when --enable-ipv6 is in effect.

Good point...

steved.

#7 lore raw
In reply to Chuck Lever
Quoted 5 lines · Chuck Lever

A general comment: This code will need support for IPv6 addresses.

Until it has it, perhaps we should add some logic to configure.ac that prevents the use of tcpwrappers when --enable-ipv6 is in effect.

The following patch does address this concern....

comments?

steved.

commit 5526bb225c745d169c070d392402fc1a569f1d15

Author: Steve Dickson <[email protected]>
Date:   Thu Dec 18 14:57:52 2008 -0500

Skip the host access check when IPv6 is enabled and its an IPv6 address.

utils/mountd/mount_dispatch.c +19 -0
index f00c0c5..8aa1955 100644
@@ -12,6 +12,8 @@
 #include "tcpwrapper.h"
 #endif
 
+#include <sys/syslog.h>
+
 #include "mountd.h"
 #include "rpcmisc.h"
 
@@ -72,12 +74,29 @@ mount_dispatch(struct svc_req *rqstp, SVCXPRT *transp)
 	union mountd_results	result;
 
 #ifdef HAVE_TCP_WRAPPER
+#ifdef IPV6_SUPPORTED
+	static int once = 0;
+
+	if (svc_getcaller(transp)->sin_family != AF_INET) {
+		if (!once) {
+			syslog(LOG_WARNING, 
+				"No IPv6 support in Access Control Library (TCP Wrappers)"); 
+			once++;
+		}
+		goto skipcheck;
+	}
+#endif
 	/* remote host authorization check */
 	if (!check_default("mountd", svc_getcaller(transp),
 			   rqstp->rq_proc, MOUNTPROG)) {
 		svcerr_auth (transp, AUTH_FAILED);
 		return;
 	}
+
+#ifdef IPV6_SUPPORTED
+skipcheck:
+#endif
+
 #endif
 
 	rpc_dispatch(rqstp, transp, dtable, number_of(dtable),

A message that is not in the archive (sent off-list or not yet received): [email protected]

#9 lore raw
Quoted 36 lines · Steve Dickson
Quoted 5 lines · Chuck Lever

A general comment: This code will need support for IPv6 addresses.

Until it has it, perhaps we should add some logic to configure.ac that prevents the use of tcpwrappers when --enable-ipv6 is in effect.

The following patch does address this concern....

comments?

steved.

commit 5526bb225c745d169c070d392402fc1a569f1d15

Author: Steve Dickson <[email protected]>
Date:   Thu Dec 18 14:57:52 2008 -0500

Skip the host access check when IPv6 is enabled and its an IPv6
address.

utils/mountd/mount_dispatch.c +2 -0
index f00c0c5..8aa1955 100644
@@ -12,6 +12,8 @@
 #include "tcpwrapper.h"
 #endif
 
+#include <sys/syslog.h>
+
 #include "mountd.h"
 #include "rpcmisc.h"
 

utils/mountd/mount_dispatch.c mount_dispatch(struct svc_req *rqstp, SVCXPRT · line 81

Quoted 8 lines
utils/mountd/mount_dispatch.c +4 -0
@@ -72,12 +74,29 @@ mount_dispatch(struct svc_req *rqstp, SVCXPRT  
 *transp)
 	union mountd_results	result;
 
 #ifdef HAVE_TCP_WRAPPER
+#ifdef IPV6_SUPPORTED
+	static int once = 0;
+
+	if (svc_getcaller(transp)->sin_family != AF_INET) {

It's not clear to me that svc_getcaller() will ever return a non-AF_INET address.

Should we use svc_getcaller_netbuf() here instead?

Quoted 23 lines
utils/mountd/mount_dispatch.c +13 -0
+		if (!once) {
+			syslog(LOG_WARNING,
+				"No IPv6 support in Access Control Library (TCP Wrappers)");
+			once++;
+		}
+		goto skipcheck;
+	}
+#endif
 	/* remote host authorization check */
 	if (!check_default("mountd", svc_getcaller(transp),
 			   rqstp->rq_proc, MOUNTPROG)) {
 		svcerr_auth (transp, AUTH_FAILED);
 		return;
 	}
+
+#ifdef IPV6_SUPPORTED
+skipcheck:
+#endif
+
 #endif
 

rpc_dispatch(rqstp, transp, dtable, number_of(dtable),

Signature · 2 lines
Chuck Lever
chuck[dot]lever[at]oracle[dot]com
#10 lore raw
Quoted 13 lines · Chuck Lever

utils/mountd/mount_dispatch.c mount_dispatch(struct svc_req *rqstp, SVCXPRT · line 81

Quoted 9 lines
utils/mountd/mount_dispatch.c +4 -0
@@ -72,12 +74,29 @@ mount_dispatch(struct svc_req *rqstp, SVCXPRT
 *transp)
    union mountd_results    result;
 
 #ifdef HAVE_TCP_WRAPPER
+#ifdef IPV6_SUPPORTED
+    static int once = 0;
+
+    if (svc_getcaller(transp)->sin_family != AF_INET) {

It's not clear to me that svc_getcaller() will ever return a non-AF_INET address.

Quoted 1 line

Should we use svc_getcaller_netbuf() here instead?

I would if I could but there is no svc_getcaller_netbuf() in the glibc version of RPC...

steved.

A message that is not in the archive (sent off-list or not yet received): [email protected]

#12 lore raw

Hi Steve-

Quoted 14 lines · Steve Dickson
Quoted 13 lines · Chuck Lever

utils/mountd/mount_dispatch.c mount_dispatch(struct svc_req *rqstp, SVCXPRT · line 81

Quoted 9 lines
utils/mountd/mount_dispatch.c +4 -0
@@ -72,12 +74,29 @@ mount_dispatch(struct svc_req *rqstp, SVCXPRT
 *transp)
   union mountd_results    result;
 
 #ifdef HAVE_TCP_WRAPPER
+#ifdef IPV6_SUPPORTED
+    static int once = 0;
+
+    if (svc_getcaller(transp)->sin_family != AF_INET) {

It's not clear to me that svc_getcaller() will ever return a non-AF_INET address.

Quoted 3 lines
Quoted 1 line

Should we use svc_getcaller_netbuf() here instead?

I would if I could but there is no svc_getcaller_netbuf() in the glibc version of RPC...

If IPV6_SUPPORTED is set than libtirpc is required to be available. nfs-utils won't build with --enable-ipv6 if there's no libtirpc.

Signature · 2 lines
Chuck Lever
chuck[dot]lever[at]oracle[dot]com
#13 lore raw
Quoted 17 lines · Chuck Lever

Hi Steve-

Quoted 14 lines · Steve Dickson
Quoted 13 lines · Chuck Lever

utils/mountd/mount_dispatch.c mount_dispatch(struct svc_req *rqstp, SVCXPRT · line 81

Quoted 9 lines
utils/mountd/mount_dispatch.c +4 -0
@@ -72,12 +74,29 @@ mount_dispatch(struct svc_req *rqstp, SVCXPRT
 *transp)
   union mountd_results    result;
 
 #ifdef HAVE_TCP_WRAPPER
+#ifdef IPV6_SUPPORTED
+    static int once = 0;
+
+    if (svc_getcaller(transp)->sin_family != AF_INET) {

It's not clear to me that svc_getcaller() will ever return a non-AF_INET address.

Quoted 6 lines
Quoted 3 lines
Quoted 1 line

Should we use svc_getcaller_netbuf() here instead?

I would if I could but there is no svc_getcaller_netbuf() in the glibc version of RPC...

If IPV6_SUPPORTED is set than libtirpc is required to be available. nfs-utils won't build with --enable-ipv6 if there's no libtirpc.

Ah... good point! So something like this should work:

    sa = (struct sockaddr *)svc_getcaller_netbuf(transp)->buf;

    if (sa->sa_family != AF_INET) {

        if (!once) {

            syslog(LOG_WARNING,

                "No IPv6 support in Access Control Library (TCP

Wrappers)");

            once++;

        }

        goto skipcheck;

    }

steved.

#14 lore raw
In reply to Chuck Lever
Quoted 13 lines · Chuck Lever

Review mount_dispatch(struct svc_req *rqstp, SVCXPRT · line 81

Quoted 9 lines
(quoted diff) +4 -0
@@ -72,12 +74,29 @@ mount_dispatch(struct svc_req *rqstp, SVCXPRT
 *transp)
    union mountd_results    result;
 
 #ifdef HAVE_TCP_WRAPPER
+#ifdef IPV6_SUPPORTED
+    static int once = 0;
+
+    if (svc_getcaller(transp)->sin_family != AF_INET) {

It's not clear to me that svc_getcaller() will ever return a non-AF_INET address.

Quoted 2 lines

Should we use svc_getcaller_netbuf() here instead?

Here is the same patch using svc_getcaller_netbuf() instead of svc_getcaller():

comments?

steved.

commit 87aef16ecab0ee3b0744d24b0e257e9d108ff4c0

Author: Steve Dickson <[email protected]>
Date:   Fri Dec 19 11:58:02 2008 -0500

Skip the host access check when IPv6 is enabled and its an IPv6 address.

utils/mountd/mount_dispatch.c +22 -0
index f00c0c5..9223509 100644
@@ -12,6 +12,8 @@
 #include "tcpwrapper.h"
 #endif
 
+#include <sys/syslog.h>
+
 #include "mountd.h"
 #include "rpcmisc.h"
 
@@ -72,12 +74,32 @@ mount_dispatch(struct svc_req *rqstp, SVCXPRT *transp)
 	union mountd_results	result;
 
 #ifdef HAVE_TCP_WRAPPER
+#ifdef IPV6_SUPPORTED
+	struct sockaddr *sa;
+	static int once = 0;
+
+	sa = (struct sockaddr *)svc_getcaller_netbuf(transp)->buf;
+	if (sa->sa_family != AF_INET) {
+		if (!once) {
+			syslog(LOG_WARNING, 
+				"No IPv6 support in Access Control Library (TCP Wrappers)"); 
+			once++;
+		}
+		goto skipcheck;
+	}
+#endif
+
 	/* remote host authorization check */
 	if (!check_default("mountd", svc_getcaller(transp),
 			   rqstp->rq_proc, MOUNTPROG)) {
 		svcerr_auth (transp, AUTH_FAILED);
 		return;
 	}
+
+#ifdef IPV6_SUPPORTED
+skipcheck:
+#endif
+
 #endif
 
 	rpc_dispatch(rqstp, transp, dtable, number_of(dtable),
utils/statd/statd.c +19 -0
index 321f7a9..78bf6f8 100644
@@ -88,6 +88,21 @@ extern void simulator (int, char **);
 static void 
 sm_prog_1_wrapper (struct svc_req *rqstp, register SVCXPRT *transp)
 {
+#ifdef IPV6_SUPPORTED
+	struct sockaddr *sa;
+	static int once = 0;
+
+	sa = (struct sockaddr *)svc_getcaller_netbuf(transp)->buf;
+	if (sa->sa_family != AF_INET) {
+		if (!once) {
+			syslog(LOG_WARNING, 
+				"No IPv6 support in Access Control Library (TCP Wrappers)"); 
+			once++;
+		}
+		goto skipcheck;
+	}
+#endif
+
 	/* remote host authorization check */
 	if (!check_default("statd", svc_getcaller(transp),
 				 rqstp->rq_proc, SM_PROG)) {
@@ -95,6 +110,10 @@ sm_prog_1_wrapper (struct svc_req *rqstp, register SVCXPRT *transp)
 		return;
 	}
 
+#ifdef IPV6_SUPPORTED
+skipcheck:
+#endif
+
 	sm_prog_1 (rqstp, transp);
 }
 
#15 lore raw
In reply to a message not in the archive
Quoted 11 lines · Steve Dickson

Recently I was asked to re-enable the TCP wrapper calls, that check the validity of client that communicate with mountd and statd.

It became very apparent this code had not been used in a while and was as a bit broken. So this patch set fixes the logic and tries to make the code scale better.

The commit blobs in the set are relative to the 'tcpwrap' branch in the git://linux-nfs.org/~steved/nfs-utils-exp.git
git tree.

The three patches have been tested and committed.

Note, it was decided the IPv6 patch (the 4th patch) was not needed.

steved.