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);