Re: [PATCH v2 1/1] Add check of clientaddr argument

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

 




> On Jun 5, 2018, at 1:28 PM, Olga Kornievskaia <aglo@xxxxxxxxx> wrote:
> 
> On Tue, Jun 5, 2018 at 12:49 PM, Chuck Lever <chuck.lever@xxxxxxxxxx> wrote:
>> 
>> 
>>> On Jun 5, 2018, at 11:51 AM, Olga Kornievskaia <kolga@xxxxxxxxxx> wrote:
>>> 
>>> If the user supplies a clientaddr value,
>> 
>> Suggest instead:
>> 
>> "If an NFS client administrator supplies the clientaddr mount option,"
> 
> Ok.
> 
>>> it should be either
>>> a special value of either IPv4/IPv6 any address or one of the
>>> machine's network addresses. Otherwise, the use of an arbitrary
>>> value of the clientaddr value is not allowed.
>> 
>>> Signed-off-by: Olga Kornievskaia <kolga@xxxxxxxxxx>
>>> ---
>>> utils/mount/network.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
>>> utils/mount/network.h |  2 ++
>>> utils/mount/stropts.c | 28 +++++++++++++++++++++++++---
>>> 3 files changed, 72 insertions(+), 3 deletions(-)
>>> 
>>> diff --git a/utils/mount/network.c b/utils/mount/network.c
>>> index e490399..2a54f82 100644
>>> --- a/utils/mount/network.c
>>> +++ b/utils/mount/network.c
>>> @@ -50,6 +50,8 @@
>>> #include <rpc/rpc.h>
>>> #include <rpc/pmap_prot.h>
>>> #include <rpc/pmap_clnt.h>
>>> +#include <net/if.h>
>>> +#include <ifaddrs.h>
>>> 
>>> #include "sockaddr.h"
>>> #include "xcommon.h"
>>> @@ -1759,3 +1761,46 @@ int nfs_umount_do_umnt(struct mount_options *options,
>>> 
>>>      return EX_SUCCESS;
>>> }
>>> +
>>> +int nfs_is_inaddr_any(struct sockaddr *nfs_saddr)
>>> +{
>>> +     switch (nfs_saddr->sa_family) {
>>> +     case AF_INET: {
>>> +             if (((struct sockaddr_in *)nfs_saddr)->sin_addr.s_addr ==
>>> +                             INADDR_ANY)
>>> +                     return 1;
>>> +     }
>>> +     case AF_INET6:
>>> +             if (!memcmp(&((struct sockaddr_in6 *)nfs_saddr)->sin6_addr,
>>> +                             &in6addr_any, sizeof(in6addr_any)))
>>> +                     return 1;
>>> +     }
>>> +     return 0;
>>> +}
>>> +
>>> +int nfs_addr_matches_localips(struct sockaddr *nfs_saddr)
>>> +{
>>> +     struct ifaddrs *myaddrs, *ifa;
>>> +     int found = 0;
>>> +
>>> +     /* acquire exiting network interfaces */
>>> +     if (getifaddrs(&myaddrs) != 0)
>>> +             return 0;
>>> +
>>> +     /* interate over the available interfaces and check if we
>>> +      * we find a match to the supplied clientaddr value
>>> +      */
>>> +     for (ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next) {
>>> +             if (ifa->ifa_addr == NULL)
>>> +                     continue;
>>> +             if (!(ifa->ifa_flags & IFF_UP))
>>> +                     continue;
>>> +             if (!memcmp(ifa->ifa_addr, nfs_saddr,
>>> +                             sizeof(struct sockaddr))) {
>>> +                     found = 1;
>>> +                     break;
>>> +             }
>>> +     }
>>> +     freeifaddrs(myaddrs);
>>> +     return found;
>>> +}
>> 
>> This looks like what we discussed, and it is implemented IMO
>> correctly.

While I was watching TV and eating lunch, it occurred to me
that mount.nfs could pass the clientaddr value to bind(2).
bind(2) should work for an ANY address or a local address, but
would fail with a non-local address, unless I'm confused. Just
a random thought.


>> Can you also provide an update to nfs(5)?

>> After all the dialog and thinking more about it, I'm less convinced
>> that prohibiting non-local addresses is wise. The client can mount
>> through a NAT and specify a clientaddr that points to the NAT. That
>> seems like a correct configuration that would now be prohibited.
>> 
>> However I don't know of any actual deployments like this, so it's
>> hard to argue convincingly that mount.nfs needs to continue to allow
>> it.
>> 
>> May I suggest a slight alteration?
>> 
>> - If the value of clientaddr= is not a presentation address,
>>   report the problem and fail the mount (no change)
>> 
>> - Allow the value of clientaddr= to be an ANY address without
>>   complaint (no change)
>> 
>> - If the value of clientaddr= is not a local address, warn but
>>   allow it (rather than failing)
>> 
>> That permits flexibility but also gives a good indication to
>> administrators who have made an honest mistake.
> 
> Given that we are changing the kernel to not use the cl_ipaddr to
> construct the client ID, then I'm ok with allowing a none local
> address with a warning. But can you tell me how you think specifying a
> non local address would actually work? It doesn't make sense to me as
> to how the callback would ever reach the appropriate client.  When the
> server establishes connected back to the NAT router IP, there is
> nothing that's listening there. And also NAT router doesn't know where
> to send it to.

How it might work:

- Each client would have it's own callback service running on
  a distinct port

- The NAT would need to be programmed to route the callback
  connection to the correct client, by port


> If we are allowing but warning about the use of the arbitrary IP, do
> we need any change to the nfs(5)?

Hm...

You mentioned nfs(5) doesn't document the clientaddr=ANY trick.
If we want to leave that undocumented (say, to try to implement
a more pleasant administrative interface to disable NFSv4.0
callback) then I suppose we could leave nfs(5) alone.


>>> diff --git a/utils/mount/network.h b/utils/mount/network.h
>>> index ecaac33..0fc98ac 100644
>>> --- a/utils/mount/network.h
>>> +++ b/utils/mount/network.h
>>> @@ -54,6 +54,8 @@ int nfs_callback_address(const struct sockaddr *, const socklen_t,
>>> int clnt_ping(struct sockaddr_in *, const unsigned long,
>>>              const unsigned long, const unsigned int,
>>>              struct sockaddr_in *);
>>> +int nfs_is_inaddr_any(struct sockaddr *);
>>> +int nfs_addr_matches_localips(struct sockaddr *);
>>> 
>>> struct mount_options;
>>> 
>>> diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
>>> index d1b0708..e22216f 100644
>>> --- a/utils/mount/stropts.c
>>> +++ b/utils/mount/stropts.c
>>> @@ -229,7 +229,8 @@ static int nfs_append_addr_option(const struct sockaddr *sap,
>>> 
>>> /*
>>> * Called to discover our address and append an appropriate 'clientaddr='
>>> - * option to the options string.
>>> + * option to the options string. If the supplied 'clientaddr=' value does
>>> + * not match either IPV4/IPv6 any or a local address, then fail the mount.
>>> *
>>> * Returns 1 if 'clientaddr=' option created successfully or if
>>> * 'clientaddr=' option is already present; otherwise zero.
>>> @@ -242,8 +243,29 @@ static int nfs_append_clientaddr_option(const struct sockaddr *sap,
>>>      struct sockaddr *my_addr = &address.sa;
>>>      socklen_t my_len = sizeof(address);
>>> 
>>> -     if (po_contains(options, "clientaddr") == PO_FOUND)
>>> -             return 1;
>>> +     if (po_contains(options, "clientaddr") == PO_FOUND) {
>>> +             char *addr = po_get(options, "clientaddr");
>>> +             union nfs_sockaddr nfs_address;
>>> +             struct sockaddr *nfs_saddr = &nfs_address.sa;
>>> +             socklen_t nfs_salen = sizeof(nfs_address);
>>> +
>>> +             /* translate the input for clientaddr to nfs_sockaddr */
>>> +             if (!nfs_string_to_sockaddr(addr, nfs_saddr, &nfs_salen))
>>> +                     return 0;
>>> +
>>> +             /* check for IPV4_ANY and IPV6_ANY */
>>> +             if (nfs_is_inaddr_any(nfs_saddr))
>>> +                     return 1;
>>> +
>>> +             /* check if ip matches local network addresses */
>>> +             if (!nfs_addr_matches_localips(nfs_saddr)) {
>>> +                     nfs_error(_("%s: supplied clientaddr=%s does not "
>>> +                             "match any existing network addresses"),
>>> +                             progname, addr);
>>> +                     return 0;
>>> +             } else
>>> +                     return 1;
>>> +     }
>>> 
>>>      nfs_callback_address(sap, salen, my_addr, &my_len);
>>> 
>>> --
>>> 1.8.3.1
>>> 
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
>>> the body of a message to majordomo@xxxxxxxxxxxxxxx
>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>> 
>> --
>> Chuck Lever
>> 
>> 
>> 
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
>> the body of a message to majordomo@xxxxxxxxxxxxxxx
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
Chuck Lever



--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux