Linux NFS development
 help / color / mirror / Atom feed
From: Steve Dickson <steved@redhat.com>
To: Trond Myklebust <trondmy@hammerspace.com>,
	"linux-nfs@vger.kernel.org" <linux-nfs@vger.kernel.org>,
	"alex@caoua.org" <alex@caoua.org>
Subject: Re: [PATCH] mount: If a reserved ports is used, do so for the pings as well
Date: Sun, 21 Apr 2024 17:38:31 -0400	[thread overview]
Message-ID: <32779e7d-1f5d-449d-890f-6d26f0d6cf4a@redhat.com> (raw)
In-Reply-To: <838909fda3f022bdf1ae3775ae0c0395e6102f85.camel@hammerspace.com>



On 4/21/24 12:06 PM, Trond Myklebust wrote:
> On Sun, 2024-04-21 at 07:09 -0400, Steve Dickson wrote:
>>
>>
>> On 4/12/24 6:26 AM, Alexandre Ratchov wrote:
>>> Hi,
>>>
>>> mount.nfs always uses a high port to probe the server's ports
>>> (regardless of
>>> the "-o resvport" option).  Certain NFS servers (ex.  OpenBSD -
>>> current) will
>>> drop the connection, the probe will fail, and mount.nfs will exit
>>> before any
>>> attempt to mount the file-system.  If mount.nfs doesn't ping the
>>> server from
>>> a high port, mounting the file system will just work.
>>>
>>> Note that the same will happen if the server is behind a firewall
>>> that
>>> blocks connections to the NFS service that originates from a high
>>> port.
>> Committed... (tag: nfs-utils-2-7-1-rc7)
>>
>> I just hope we don't run out of privilege ports during
>> a mount storm (aka when a server reboots).
> 
> Agreed, and that is why this change was entirely the wrong thing to do.
Well the patch was sitting around for a while without any objection
so I figured I would go with it since it would make mounts
work on other OSs

> 
> The point of the ping is to allow for fast failover in the case where
> the portmap/rpcbind server returns incorrect or stale information.
> 
> If there are servers out there that deliberately break the convention
> for NULL ping, as described in RFC5531, then we might allow optional
> use of the privileged port for those servers, but please don't force
> this on everyone else.
The patch is on the top of stack... easy revert-able... Is that what
you are suggesting?

steved.

> 
> 
>>
>> steved.
>>
>>>
>>> ---
>>>    support/include/nfsrpc.h |  3 ++-
>>>    support/nfs/getport.c    | 10 +++++++---
>>>    utils/mount/network.c    | 36 ++++++++++++++++++++---------------
>>> -
>>>    utils/mount/network.h    |  4 ++--
>>>    utils/mount/nfsmount.c   | 16 +++++++++++-----
>>>    utils/mount/stropts.c    | 24 +++++++++++++++++++++---
>>>    6 files changed, 63 insertions(+), 30 deletions(-)
>>>
>>> diff --git a/support/include/nfsrpc.h b/support/include/nfsrpc.h
>>> index fbbdb6a9..9106c195 100644
>>> --- a/support/include/nfsrpc.h
>>> +++ b/support/include/nfsrpc.h
>>> @@ -170,7 +170,8 @@ extern int		nfs_rpc_ping(const struct
>>> sockaddr *sap,
>>>    				const rpcprog_t program,
>>>    				const rpcvers_t version,
>>>    				const unsigned short protocol,
>>> -				const struct timeval *timeout);
>>> +				const struct timeval *timeout,
>>> +				const int resvport);
>>>    
>>>    /* create AUTH_SYS handle with no supplemental groups */
>>>    extern AUTH *			 nfs_authsys_create(void);
>>> diff --git a/support/nfs/getport.c b/support/nfs/getport.c
>>> index 813f7bf9..ff7e9991 100644
>>> --- a/support/nfs/getport.c
>>> +++ b/support/nfs/getport.c
>>> @@ -730,7 +730,8 @@ static unsigned short nfs_gp_getport(CLIENT
>>> *client,
>>>     */
>>>    int nfs_rpc_ping(const struct sockaddr *sap, const socklen_t
>>> salen,
>>>    		 const rpcprog_t program, const rpcvers_t version,
>>> -		 const unsigned short protocol, const struct
>>> timeval *timeout)
>>> +		 const unsigned short protocol, const struct
>>> timeval *timeout,
>>> +		 const int resvport)
>>>    {
>>>    	union nfs_sockaddr address;
>>>    	struct sockaddr *saddr = &address.sa;
>>> @@ -744,8 +745,11 @@ int nfs_rpc_ping(const struct sockaddr *sap,
>>> const socklen_t salen,
>>>    	nfs_clear_rpc_createerr();
>>>    
>>>    	memcpy(saddr, sap, (size_t)salen);
>>> -	client = nfs_get_rpcclient(saddr, salen, protocol,
>>> -						program, version,
>>> &tout);
>>> +	client = resvport ?
>>> +		 nfs_get_priv_rpcclient(saddr, salen, protocol,
>>> +					program, version, &tout) :
>>> +		 nfs_get_rpcclient(saddr, salen, protocol,
>>> +				   program, version, &tout);
>>>    	if (client != NULL) {
>>>    		result = nfs_gp_ping(client, tout);
>>>    		nfs_gp_map_tcp_errorcodes(protocol);
>>> diff --git a/utils/mount/network.c b/utils/mount/network.c
>>> index 01ead49f..d9221567 100644
>>> --- a/utils/mount/network.c
>>> +++ b/utils/mount/network.c
>>> @@ -525,7 +525,7 @@ static void nfs_pp_debug2(const char *str)
>>>     */
>>>    static int nfs_probe_port(const struct sockaddr *sap, const
>>> socklen_t salen,
>>>    			  struct pmap *pmap, const unsigned long
>>> *versions,
>>> -			  const unsigned int *protos)
>>> +			  const unsigned int *protos, const int
>>> resvp)
>>>    {
>>>    	union nfs_sockaddr address;
>>>    	struct sockaddr *saddr = &address.sa;
>>> @@ -550,7 +550,7 @@ static int nfs_probe_port(const struct sockaddr
>>> *sap, const socklen_t salen,
>>>    				nfs_pp_debug(saddr, salen, prog,
>>> *p_vers,
>>>    						*p_prot, p_port);
>>>    				if (nfs_rpc_ping(saddr, salen,
>>> prog,
>>> -							*p_vers,
>>> *p_prot, NULL))
>>> +						 *p_vers, *p_prot,
>>> NULL, resvp))
>>>    					goto out_ok;
>>>    			} else
>>>    				rpc_createerr.cf_stat =
>>> RPC_PROGNOTREGISTERED;
>>> @@ -603,7 +603,7 @@ out_ok:
>>>     * returned; rpccreateerr.cf_stat is set to reflect the nature of
>>> the error.
>>>     */
>>>    static int nfs_probe_nfsport(const struct sockaddr *sap, const
>>> socklen_t salen,
>>> -			     struct pmap *pmap, int checkv4)
>>> +			     struct pmap *pmap, int checkv4, int
>>> resvp)
>>>    {
>>>    	if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port)
>>>    		return 1;
>>> @@ -617,13 +617,13 @@ static int nfs_probe_nfsport(const struct
>>> sockaddr *sap, const socklen_t salen,
>>>    		memcpy(&save_sa, sap, salen);
>>>    
>>>    		ret = nfs_probe_port(sap, salen, pmap,
>>> -				     probe_nfs3_only,
>>> probe_proto);
>>> +				     probe_nfs3_only, probe_proto,
>>> resvp);
>>>    		if (!ret || !checkv4 || probe_proto !=
>>> probe_tcp_first)
>>>    			return ret;
>>>    
>>>    		nfs_set_port((struct sockaddr *)&save_sa,
>>> NFS_PORT);
>>>    		ret =  nfs_rpc_ping((struct sockaddr *)&save_sa,
>>> salen,
>>> -			NFS_PROGRAM, 4, IPPROTO_TCP, NULL);
>>> +				    NFS_PROGRAM, 4, IPPROTO_TCP,
>>> NULL, resvp);
>>>    		if (ret) {
>>>    			rpc_createerr.cf_stat = RPC_FAILED;
>>>    			rpc_createerr.cf_error.re_errno = EAGAIN;
>>> @@ -632,7 +632,7 @@ static int nfs_probe_nfsport(const struct
>>> sockaddr *sap, const socklen_t salen,
>>>    		return 1;
>>>    	} else
>>>    		return nfs_probe_port(sap, salen, pmap,
>>> -					probe_nfs2_only,
>>> probe_udp_only);
>>> +				      probe_nfs2_only,
>>> probe_udp_only, resvp);
>>>    }
>>>    
>>>    /*
>>> @@ -649,17 +649,17 @@ static int nfs_probe_nfsport(const struct
>>> sockaddr *sap, const socklen_t salen,
>>>     * returned; rpccreateerr.cf_stat is set to reflect the nature of
>>> the error.
>>>     */
>>>    static int nfs_probe_mntport(const struct sockaddr *sap, const
>>> socklen_t salen,
>>> -				struct pmap *pmap)
>>> +			     struct pmap *pmap)
>>>    {
>>>    	if (pmap->pm_vers && pmap->pm_prot && pmap->pm_port)
>>>    		return 1;
>>>    
>>>    	if (nfs_mount_data_version >= 4)
>>>    		return nfs_probe_port(sap, salen, pmap,
>>> -					probe_mnt3_only,
>>> probe_udp_first);
>>> +				      probe_mnt3_only,
>>> probe_udp_first, 0);
>>>    	else
>>>    		return nfs_probe_port(sap, salen, pmap,
>>> -					probe_mnt1_first,
>>> probe_udp_only);
>>> +				      probe_mnt1_first,
>>> probe_udp_only, 0);
>>>    }
>>>    
>>>    /*
>>> @@ -676,9 +676,10 @@ static int nfs_probe_version_fixed(const
>>> struct sockaddr *mnt_saddr,
>>>    			struct pmap *mnt_pmap,
>>>    			const struct sockaddr *nfs_saddr,
>>>    			const socklen_t nfs_salen,
>>> -			struct pmap *nfs_pmap)
>>> +			struct pmap *nfs_pmap,
>>> +			const int resvp)
>>>    {
>>> -	if (!nfs_probe_nfsport(nfs_saddr, nfs_salen, nfs_pmap, 0))
>>> +	if (!nfs_probe_nfsport(nfs_saddr, nfs_salen, nfs_pmap, 0,
>>> resvp))
>>>    		return 0;
>>>    	return nfs_probe_mntport(mnt_saddr, mnt_salen, mnt_pmap);
>>>    }
>>> @@ -706,7 +707,8 @@ int nfs_probe_bothports(const struct sockaddr
>>> *mnt_saddr,
>>>    			const struct sockaddr *nfs_saddr,
>>>    			const socklen_t nfs_salen,
>>>    			struct pmap *nfs_pmap,
>>> -			int checkv4)
>>> +			int checkv4,
>>> +			int resvp)
>>>    {
>>>    	struct pmap save_nfs, save_mnt;
>>>    	const unsigned long *probe_vers;
>>> @@ -718,7 +720,8 @@ int nfs_probe_bothports(const struct sockaddr
>>> *mnt_saddr,
>>>    
>>>    	if (nfs_pmap->pm_vers)
>>>    		return nfs_probe_version_fixed(mnt_saddr,
>>> mnt_salen, mnt_pmap,
>>> -					       nfs_saddr,
>>> nfs_salen, nfs_pmap);
>>> +					       nfs_saddr,
>>> nfs_salen, nfs_pmap,
>>> +					       resvp);
>>>    
>>>    	memcpy(&save_nfs, nfs_pmap, sizeof(save_nfs));
>>>    	memcpy(&save_mnt, mnt_pmap, sizeof(save_mnt));
>>> @@ -727,7 +730,8 @@ int nfs_probe_bothports(const struct sockaddr
>>> *mnt_saddr,
>>>    
>>>    	for (; *probe_vers; probe_vers++) {
>>>    		nfs_pmap->pm_vers = mntvers_to_nfs(*probe_vers);
>>> -		if (nfs_probe_nfsport(nfs_saddr, nfs_salen,
>>> nfs_pmap, checkv4) != 0) {
>>> +		if (nfs_probe_nfsport(nfs_saddr, nfs_salen,
>>> nfs_pmap, checkv4,
>>> +				      resvp) != 0) {
>>>    			mnt_pmap->pm_vers = *probe_vers;
>>>    			if (nfs_probe_mntport(mnt_saddr,
>>> mnt_salen, mnt_pmap) != 0)
>>>    				return 1;
>>> @@ -759,7 +763,7 @@ int nfs_probe_bothports(const struct sockaddr
>>> *mnt_saddr,
>>>     * Otherwise zero is returned; rpccreateerr.cf_stat is set to
>>> reflect
>>>     * the nature of the error.
>>>     */
>>> -int probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t
>>> *nfs_server)
>>> +int probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t
>>> *nfs_server, int resvp)
>>>    {
>>>    	struct sockaddr *mnt_addr = SAFE_SOCKADDR(&mnt_server-
>>>> saddr);
>>>    	struct sockaddr *nfs_addr = SAFE_SOCKADDR(&nfs_server-
>>>> saddr);
>>> @@ -767,7 +771,7 @@ int probe_bothports(clnt_addr_t *mnt_server,
>>> clnt_addr_t *nfs_server)
>>>    	return nfs_probe_bothports(mnt_addr, sizeof(mnt_server-
>>>> saddr),
>>>    					&mnt_server->pmap,
>>>    					nfs_addr,
>>> sizeof(nfs_server->saddr),
>>> -					&nfs_server->pmap, 0);
>>> +					&nfs_server->pmap, 0,
>>> resvp);
>>>    }
>>>    
>>>    /**
>>> diff --git a/utils/mount/network.h b/utils/mount/network.h
>>> index 0fc98acd..8bcc7ace 100644
>>> --- a/utils/mount/network.h
>>> +++ b/utils/mount/network.h
>>> @@ -39,10 +39,10 @@ typedef struct {
>>>    static const struct timeval TIMEOUT = { 20, 0 };
>>>    static const struct timeval RETRY_TIMEOUT = { 3, 0 };
>>>    
>>> -int probe_bothports(clnt_addr_t *, clnt_addr_t *);
>>> +int probe_bothports(clnt_addr_t *, clnt_addr_t *, int);
>>>    int nfs_probe_bothports(const struct sockaddr *, const socklen_t,
>>>    			struct pmap *, const struct sockaddr *,
>>> -			const socklen_t, struct pmap *, int);
>>> +			const socklen_t, struct pmap *, int, int);
>>>    int nfs_gethostbyname(const char *, struct sockaddr_in *);
>>>    int nfs_lookup(const char *hostname, const sa_family_t family,
>>>    		struct sockaddr *sap, socklen_t *salen);
>>> diff --git a/utils/mount/nfsmount.c b/utils/mount/nfsmount.c
>>> index 3d95da94..a792c6e7 100644
>>> --- a/utils/mount/nfsmount.c
>>> +++ b/utils/mount/nfsmount.c
>>> @@ -123,13 +123,13 @@ nfs2_mount(CLIENT *clnt, mnt2arg_t *mnt2arg,
>>> mnt2res_t *mnt2res)
>>>    
>>>    static int
>>>    nfs_call_mount(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server,
>>> -	       mntarg_t *mntarg, mntres_t *mntres)
>>> +	       mntarg_t *mntarg, mntres_t *mntres, int resvp)
>>>    {
>>>    	CLIENT *clnt;
>>>    	enum clnt_stat stat;
>>>    	int msock;
>>>    
>>> -	if (!probe_bothports(mnt_server, nfs_server))
>>> +	if (!probe_bothports(mnt_server, nfs_server, resvp))
>>>    		goto out_bad;
>>>    
>>>    	clnt = mnt_openclnt(mnt_server, &msock);
>>> @@ -164,7 +164,8 @@ nfs_call_mount(clnt_addr_t *mnt_server,
>>> clnt_addr_t *nfs_server,
>>>    static int
>>>    parse_options(char *old_opts, struct nfs_mount_data *data,
>>>    	      int *bg, int *retry, clnt_addr_t *mnt_server,
>>> -	      clnt_addr_t *nfs_server, char *new_opts, const int
>>> opt_size)
>>> +	      clnt_addr_t *nfs_server, char *new_opts, const int
>>> opt_size,
>>> +	      int *resvp)
>>>    {
>>>    	struct sockaddr_in *mnt_saddr = &mnt_server->saddr;
>>>    	struct pmap *mnt_pmap = &mnt_server->pmap;
>>> @@ -177,6 +178,7 @@ parse_options(char *old_opts, struct
>>> nfs_mount_data *data,
>>>    
>>>    	data->flags = 0;
>>>    	*bg = 0;
>>> +	*resvp = 1;
>>>    
>>>    	len = strlen(new_opts);
>>>    	tmp_opts = xstrdup(old_opts);
>>> @@ -365,6 +367,8 @@ parse_options(char *old_opts, struct
>>> nfs_mount_data *data,
>>>    				data->flags &= ~NFS_MOUNT_NOAC;
>>>    				if (!val)
>>>    					data->flags |=
>>> NFS_MOUNT_NOAC;
>>> +			} else if (!strcmp(opt, "resvport")) {
>>> +				*resvp = val;
>>>    #if NFS_MOUNT_VERSION >= 2
>>>    			} else if (!strcmp(opt, "tcp")) {
>>>    				data->flags &= ~NFS_MOUNT_TCP;
>>> @@ -498,6 +502,7 @@ nfsmount(const char *spec, const char *node,
>>> int flags,
>>>    	static struct nfs_mount_data data;
>>>    	int val;
>>>    	static int doonce = 0;
>>> +	int resvp;
>>>    
>>>    	clnt_addr_t mnt_server = {
>>>    		.hostname = &mounthost
>>> @@ -582,7 +587,7 @@ nfsmount(const char *spec, const char *node,
>>> int flags,
>>>    	/* parse options */
>>>    	new_opts[0] = 0;
>>>    	if (!parse_options(old_opts, &data, &bg, &retry,
>>> &mnt_server, &nfs_server,
>>> -			   new_opts, sizeof(new_opts)))
>>> +			   new_opts, sizeof(new_opts), &resvp))
>>>    		goto fail;
>>>    	if (!nfsmnt_check_compat(nfs_pmap, mnt_pmap))
>>>    		goto fail;
>>> @@ -620,6 +625,7 @@ nfsmount(const char *spec, const char *node,
>>> int flags,
>>>    #if NFS_MOUNT_VERSION >= 5
>>>    	printf(_(", sec = %u"), data.pseudoflavor);
>>>    	printf(_(", readdirplus = %d"), (data.flags &
>>> NFS_MOUNT_NORDIRPLUS) != 0);
>>> +	printf(_(", resvp = %u"), resvp);
>>>    #endif
>>>    	printf("\n");
>>>    #endif
>>> @@ -670,7 +676,7 @@ nfsmount(const char *spec, const char *node,
>>> int flags,
>>>    				sleep(30);
>>>    
>>>    			stat = nfs_call_mount(&mnt_server,
>>> &nfs_server,
>>> -					      &dirname, &mntres);
>>> +					      &dirname, &mntres,
>>> resvp);
>>>    			if (stat)
>>>    				break;
>>>    			memcpy(nfs_pmap, &save_nfs,
>>> sizeof(*nfs_pmap));
>>> diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
>>> index a92c4200..85b8ca5a 100644
>>> --- a/utils/mount/stropts.c
>>> +++ b/utils/mount/stropts.c
>>> @@ -337,6 +337,20 @@ static int nfs_verify_lock_option(struct
>>> mount_options *options)
>>>    	return 1;
>>>    }
>>>    
>>> +static const char *nfs_resvport_opttbl[] = {
>>> +	"noresvport",
>>> +	"resvport",
>>> +	NULL,
>>> +};
>>> +
>>> +/*
>>> + * Returns true unless "noresvport" is set
>>> + */
>>> +static int nfs_resvport_option(struct mount_options *options)
>>> +{
>>> +	return po_rightmost(options, nfs_resvport_opttbl) != 0;
>>> +}
>>> +
>>>    static int nfs_insert_sloppy_option(struct mount_options
>>> *options)
>>>    {
>>>    	if (linux_version_code() < MAKE_VERSION(2, 6, 27))
>>> @@ -550,7 +564,7 @@ static int nfs_construct_new_options(struct
>>> mount_options *options,
>>>     * FALSE is returned if some failure occurred.
>>>     */
>>>    static int
>>> -nfs_rewrite_pmap_mount_options(struct mount_options *options, int
>>> checkv4)
>>> +nfs_rewrite_pmap_mount_options(struct mount_options *options, int
>>> checkv4, int resvp)
>>>    {
>>>    	union nfs_sockaddr nfs_address;
>>>    	struct sockaddr *nfs_saddr = &nfs_address.sa;
>>> @@ -604,7 +618,8 @@ nfs_rewrite_pmap_mount_options(struct
>>> mount_options *options, int checkv4)
>>>    	 * negotiate.  Bail now if we can't contact it.
>>>    	 */
>>>    	if (!nfs_probe_bothports(mnt_saddr, mnt_salen, &mnt_pmap,
>>> -				 nfs_saddr, nfs_salen, &nfs_pmap,
>>> checkv4)) {
>>> +				 nfs_saddr, nfs_salen, &nfs_pmap,
>>> +				 checkv4, resvp)) {
>>>    		errno = ESPIPE;
>>>    		if (rpc_createerr.cf_stat ==
>>> RPC_PROGNOTREGISTERED)
>>>    			errno = EOPNOTSUPP;
>>> @@ -670,6 +685,7 @@ static int nfs_do_mount_v3v2(struct
>>> nfsmount_info *mi,
>>>    {
>>>    	struct mount_options *options = po_dup(mi->options);
>>>    	int result = 0;
>>> +	int resvp;
>>>    
>>>    	if (!options) {
>>>    		errno = ENOMEM;
>>> @@ -704,11 +720,13 @@ static int nfs_do_mount_v3v2(struct
>>> nfsmount_info *mi,
>>>    		goto out_fail;
>>>    	}
>>>    
>>> +	resvp = nfs_resvport_option(options);
>>> +
>>>    	if (verbose)
>>>    		printf(_("%s: trying text-based options '%s'\n"),
>>>    			progname, *mi->extra_opts);
>>>    
>>> -	if (!nfs_rewrite_pmap_mount_options(options, checkv4))
>>> +	if (!nfs_rewrite_pmap_mount_options(options, checkv4,
>>> resvp))
>>>    		goto out_fail;
>>>    
>>>    	result = nfs_sys_mount(mi, options);
>>
>>
> 


  reply	other threads:[~2024-04-21 21:38 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-04-12 10:26 [PATCH] mount: If a reserved ports is used, do so for the pings as well Alexandre Ratchov
2024-04-21 11:09 ` Steve Dickson
2024-04-21 16:06   ` Trond Myklebust
2024-04-21 21:38     ` Steve Dickson [this message]
2024-04-21 22:14       ` Trond Myklebust
2024-05-09 14:56         ` Steve Dickson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=32779e7d-1f5d-449d-890f-6d26f0d6cf4a@redhat.com \
    --to=steved@redhat.com \
    --cc=alex@caoua.org \
    --cc=linux-nfs@vger.kernel.org \
    --cc=trondmy@hammerspace.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox