Re: [PATCH] prevent autofs to try the wrong IP protocol

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mo, 2016-01-18 at 10:36 +0800, Ian Kent wrote:
> On Sun, 2016-01-17 at 22:14 +0100, Andreas Steinmetz wrote:
> > [please CC me on replies, I'm not subscribed]
> > 
> > If the user configures an IPv6 protocol for nfs, autofs tries IPv4
> > too,
> > and vice versa. The attached patch against autofs-5.1.1 prevents
> > this.
> > 
> > The additional tries for the wrong IP protocol can be quite costly
> > if
> > e.g. an IPSec tunnel must be brought up.
> 
> Is this close to what your asking for (not even compile tested)?
> 
> I'm not certain this won't have any undesired side effects AFAICS it
> looks ok.
> 
> autofs-5.1.1 - fix ipv6 proto option handling
> 

Well, I had to fix up your patch slightly to work, at least for my IPv6
use cases. Except for the fact that there are now new version bits in
use which do hopefully not cause any unwanted side effects it now seems
ok to me. Modified patch of yours is attached.

-- 
Andreas Steinmetz                       SPAMmers use robotrap@xxxxxxxx

diff -rNup autofs-5.1.1.orig/include/replicated.h autofs-5.1.1/include/replicated.h
--- autofs-5.1.1.orig/include/replicated.h	2015-04-21 11:37:45.000000000 +0200
+++ autofs-5.1.1/include/replicated.h	2016-01-19 01:17:53.775088582 +0100
@@ -37,7 +37,10 @@
 #define UDP_SUPPORTED		0x0002
 #define TCP_REQUESTED		TCP_SUPPORTED
 #define UDP_REQUESTED		UDP_SUPPORTED
+#define TCP6_REQUESTED		0x0100
+#define UDP6_REQUESTED		0x0200
 #define NFS_PROTO_MASK		(TCP_SUPPORTED|UDP_SUPPORTED)
+#define NFS_IPV6_MASK		(TCP6_REQUESTED|UDP6_REQUESTED)
 
 #define NFS2_TCP_SUPPORTED	NFS2_SUPPORTED
 #define NFS3_TCP_SUPPORTED	NFS3_SUPPORTED
diff -rNup autofs-5.1.1.orig/modules/mount_nfs.c autofs-5.1.1/modules/mount_nfs.c
--- autofs-5.1.1.orig/modules/mount_nfs.c	2015-04-21 11:37:45.000000000 +0200
+++ autofs-5.1.1/modules/mount_nfs.c	2016-01-18 23:58:29.882810579 +0100
@@ -167,9 +167,17 @@ int mount_mount(struct autofs_point *ap,
 				} else if (_strncmp("proto=udp", cp, o_len) == 0 ||
 					   _strncmp("udp", cp, o_len) == 0) {
 					vers &= ~TCP_SUPPORTED;
+				} else if (_strncmp("proto=udp6", cp, o_len) == 0 ||
+					   _strncmp("udp6", cp, o_len) == 0) {
+					vers &= ~TCP_SUPPORTED;
+					vers |= UDP6_REQUESTED;
 				} else if (_strncmp("proto=tcp", cp, o_len) == 0 ||
 					   _strncmp("tcp", cp, o_len) == 0) {
 					vers &= ~UDP_SUPPORTED;
+				} else if (_strncmp("proto=tcp6", cp, o_len) == 0 ||
+					   _strncmp("tcp6", cp, o_len) == 0) {
+					vers &= ~UDP_SUPPORTED;
+					vers |= TCP6_REQUESTED;
 				}
 				/* Check for options that also make sense
 				   with bind mounts */
@@ -207,11 +215,16 @@ int mount_mount(struct autofs_point *ap,
 	 * configuration only probe NFSv4 and let mount.nfs(8) do fallback
 	 * to NFSv3 (if it can). If the NFSv4 probe fails then probe as
 	 * normal.
+	 *
+	 * Note: some NFS servers consider it a protocol violation to use
+	 * NFSv4 over UDP so if it has been requested in the mount options
+	 * we can't use this at all.
 	 */
 	if ((hosts && !hosts->next) &&
 	    mount_default_proto == 4 &&
 	    (vers & NFS_VERS_MASK) != 0 &&
-	    (vers & NFS4_VERS_MASK) != 0) {
+	    (vers & NFS4_VERS_MASK) != 0 &&
+	    !(vers & UDP6_REQUESTED)) {
 		unsigned int v4_probe_ok = 0;
 		struct host *tmp = new_host(hosts->name,
 					    hosts->addr, hosts->addr_len,
diff -rNup autofs-5.1.1.orig/modules/replicated.c autofs-5.1.1/modules/replicated.c
--- autofs-5.1.1.orig/modules/replicated.c	2015-04-21 11:37:45.000000000 +0200
+++ autofs-5.1.1/modules/replicated.c	2016-01-19 01:13:07.992472011 +0100
@@ -459,6 +459,32 @@ done_ver:
 	return supported;
 }
 
+static int check_address_proto(unsigned logopt,
+			       struct host *host, unsigned int version)
+{
+	int ipv6_requested = version & NFS_IPV6_MASK;
+	int ret = 1;
+	socklen_t len = INET6_ADDRSTRLEN;
+	char buf[len + 1];
+
+	/* If a protocol has been explicitly requested then don't
+	 * consider addresses that don't match the requested protocol.
+	 */
+	if (ipv6_requested) {
+		if (host->addr_len == INET_ADDRSTRLEN)
+			ret = 0;
+	} else {
+		if (host->addr_len == INET6_ADDRSTRLEN)
+			ret = 0;
+	}
+
+	if (!ret)
+		debug(logopt, "requested protocol does not match host %s(%s)",
+			host->name, get_addr_string(host->addr, buf, len));
+
+	return ret;
+}
+
 static int get_vers_and_cost(unsigned logopt, struct host *host,
 			     unsigned int version, int port)
 {
@@ -467,6 +493,9 @@ static int get_vers_and_cost(unsigned lo
 	unsigned int supported, vers = (NFS_VERS_MASK | NFS4_VERS_MASK);
 	int ret = 0;
 
+	if (!check_address_proto(logopt, host, version))
+		return 0;
+
 	memset(&pm_info, 0, sizeof(struct conn_info));
 	memset(&rpc_info, 0, sizeof(struct conn_info));
 
@@ -529,6 +558,11 @@ static int get_supported_ver_and_cost(un
 	time_t timeout = RPC_TIMEOUT;
 	int status = 0;
 
+	if (!check_address_proto(logopt, host, version))
+		return 0;
+
+	version &= ~NFS_IPV6_MASK;
+
 	if (host->addr)
 		debug(logopt, "called with host %s(%s) version 0x%x",
 			host->name, get_addr_string(host->addr, buf, len),
@@ -819,7 +853,8 @@ int prune_host_list(unsigned logopt, str
 			add_host(&new, this);
 		} else {
 			status = get_supported_ver_and_cost(logopt, this,
-						selected_version, port);
+				selected_version | (vers & NFS_IPV6_MASK),
+				port);
 			if (status) {
 				this->version = selected_version;
 				remove_host(list, this);

[Index of Archives]     [Linux Filesystem Development]     [Linux Ext4]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux