NFSv4.1/pnfs: fix NFS with TLS in pnfs
authorOlga Kornievskaia <kolga@netapp.com>
Tue, 20 Feb 2024 23:25:34 +0000 (18:25 -0500)
committerTrond Myklebust <trond.myklebust@hammerspace.com>
Sat, 9 Mar 2024 14:14:51 +0000 (09:14 -0500)
Currently, even though xprtsec=tls is specified and used for operations
to MDS, any operations that go to DS travel over unencrypted connection.
Or additionally, if more than 1 DS can serve the data, then trunked
connections are also done unencrypted.

IN GETDEVINCEINFO, we get an entry for the DS which carries a protocol
type (which is TCP), then nfs4_set_ds_client() gets called with TCP
instead of TCP with TLS.

Currently, each trunked connection is created and uses clp->cl_hostname
value which if TLS is used would get passed up in the handshake upcall,
but instead we need to pass in the appropriate trunked address value.

Fixes: c8407f2e560c ("NFS: Add an "xprtsec=" NFS mount option")
Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
fs/nfs/pnfs_nfs.c

index afd23910f3bffc52b7d4505e4bb7b6eaa0b632fa..88e061bd711b746afcd46878e518f870fae19b0c 100644 (file)
@@ -919,6 +919,8 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv,
        dprintk("--> %s DS %s\n", __func__, ds->ds_remotestr);
 
        list_for_each_entry(da, &ds->ds_addrs, da_node) {
+               char servername[48];
+
                dprintk("%s: DS %s: trying address %s\n",
                        __func__, ds->ds_remotestr, da->da_remotestr);
 
@@ -929,6 +931,7 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv,
                                .dstaddr = (struct sockaddr *)&da->da_addr,
                                .addrlen = da->da_addrlen,
                                .servername = clp->cl_hostname,
+                               .xprtsec = clp->cl_xprtsec,
                        };
                        struct nfs4_add_xprt_data xprtdata = {
                                .clp = clp,
@@ -938,10 +941,45 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv,
                                .data = &xprtdata,
                        };
 
-                       if (da->da_transport != clp->cl_proto)
+                       if (da->da_transport != clp->cl_proto &&
+                                       clp->cl_proto != XPRT_TRANSPORT_TCP_TLS)
                                continue;
+                       if (da->da_transport == XPRT_TRANSPORT_TCP &&
+                               mds_srv->nfs_client->cl_proto ==
+                                       XPRT_TRANSPORT_TCP_TLS) {
+                               struct sockaddr *addr =
+                                       (struct sockaddr *)&da->da_addr;
+                               struct sockaddr_in *sin =
+                                       (struct sockaddr_in *)&da->da_addr;
+                               struct sockaddr_in6 *sin6 =
+                                       (struct sockaddr_in6 *)&da->da_addr;
+
+                               /* for NFS with TLS we need to supply a correct
+                                * servername of the trunked transport, not the
+                                * servername of the main transport stored in
+                                * clp->cl_hostname. And set the protocol to
+                                * indicate to use TLS
+                                */
+                               servername[0] = '\0';
+                               switch(addr->sa_family) {
+                               case AF_INET:
+                                       snprintf(servername, sizeof(servername),
+                                               "%pI4", &sin->sin_addr.s_addr);
+                                       break;
+                               case AF_INET6:
+                                       snprintf(servername, sizeof(servername),
+                                               "%pI6", &sin6->sin6_addr);
+                                       break;
+                               default:
+                                       /* do not consider this address */
+                                       continue;
+                               }
+                               xprt_args.ident = XPRT_TRANSPORT_TCP_TLS;
+                               xprt_args.servername = servername;
+                       }
                        if (da->da_addr.ss_family != clp->cl_addr.ss_family)
                                continue;
+
                        /**
                        * Test this address for session trunking and
                        * add as an alias
@@ -953,6 +991,10 @@ static int _nfs4_pnfs_v4_ds_connect(struct nfs_server *mds_srv,
                        if (xprtdata.cred)
                                put_cred(xprtdata.cred);
                } else {
+                       if (da->da_transport == XPRT_TRANSPORT_TCP &&
+                               mds_srv->nfs_client->cl_proto ==
+                                       XPRT_TRANSPORT_TCP_TLS)
+                               da->da_transport = XPRT_TRANSPORT_TCP_TLS;
                        clp = nfs4_set_ds_client(mds_srv,
                                                &da->da_addr,
                                                da->da_addrlen,