Author: rmacklem
Date: Sat Apr 13 22:00:09 2019
New Revision: 346191
URL: https://svnweb.freebsd.org/changeset/base/346191

Log:
  Add support for INET6 addresses to the kernel code that dumps open/lock state.
  
  PR#223036 reported that INET6 callback addresses were not printed by
  nfsdumpstate(8). This kernel patch adds INET6 addresses to the dump structure,
  so that nfsdumpstate(8) can print them out, post-r346190.
  The patch also includes the addition of #ifdef INET, INET6 as requested
  by bz@.
  
  PR:           223036
  Reviewed by:  bz, rgrimes
  MFC after:    2 weeks
  Differential Revision:        https://reviews.freebsd.org/D19839

Modified:
  head/sys/fs/nfsserver/nfs_nfsdserv.c
  head/sys/fs/nfsserver/nfs_nfsdstate.c
  head/sys/modules/nfsd/Makefile

Modified: head/sys/fs/nfsserver/nfs_nfsdserv.c
==============================================================================
--- head/sys/fs/nfsserver/nfs_nfsdserv.c        Sat Apr 13 21:45:45 2019        
(r346190)
+++ head/sys/fs/nfsserver/nfs_nfsdserv.c        Sat Apr 13 22:00:09 2019        
(r346191)
@@ -36,6 +36,8 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include "opt_inet.h"
+#include "opt_inet6.h"
 /*
  * nfs version 2, 3 and 4 server calls to vnode ops
  * - these routines generally have 3 phases
@@ -3677,8 +3679,16 @@ nfsrvd_setclientid(struct nfsrv_descript *nd, __unused
        int i;
        int error = 0, idlen;
        struct nfsclient *clp = NULL;
-       struct sockaddr_in *rad;
-       u_char *verf, *ucp, *ucp2, addrbuf[24];
+#ifdef INET
+       struct sockaddr_in *rin;
+#endif
+#ifdef INET6
+       struct sockaddr_in6 *rin6;
+#endif
+#if defined(INET) || defined(INET6)
+       u_char *ucp, *ucp2;
+#endif
+       u_char *verf, *addrbuf;
        nfsquad_t clientid, confirm;
        struct thread *p = curthread;
 
@@ -3706,9 +3716,9 @@ nfsrvd_setclientid(struct nfsrv_descript *nd, __unused
        clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
            nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
        NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
-       clp->lc_req.nr_nam = malloc(sizeof(*clp->lc_req.nr_nam), M_SONAME,
+       /* Allocated large enough for an AF_INET or AF_INET6 socket. */
+       clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
            M_WAITOK | M_ZERO);
-       NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
        clp->lc_req.nr_cred = NULL;
        NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
        clp->lc_idlen = idlen;
@@ -3750,17 +3760,46 @@ nfsrvd_setclientid(struct nfsrv_descript *nd, __unused
         */
        nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
        if (nd->nd_repstat == NFSERR_CLIDINUSE) {
-               if (clp->lc_flags & LCL_TCPCALLBACK)
-                       (void) nfsm_strtom(nd, "tcp", 3);
-               else 
-                       (void) nfsm_strtom(nd, "udp", 3);
-               rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
-               ucp = (u_char *)&rad->sin_addr.s_addr;
-               ucp2 = (u_char *)&rad->sin_port;
-               sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
-                   ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
-                   ucp2[0] & 0xff, ucp2[1] & 0xff);
+               /*
+                * 8 is the maximum length of the port# string.
+                */
+               addrbuf = malloc(INET6_ADDRSTRLEN + 8, M_TEMP, M_WAITOK);
+               switch (clp->lc_req.nr_nam->sa_family) {
+#ifdef INET
+               case AF_INET:
+                       if (clp->lc_flags & LCL_TCPCALLBACK)
+                               (void) nfsm_strtom(nd, "tcp", 3);
+                       else 
+                               (void) nfsm_strtom(nd, "udp", 3);
+                       rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
+                       ucp = (u_char *)&rin->sin_addr.s_addr;
+                       ucp2 = (u_char *)&rin->sin_port;
+                       sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
+                           ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
+                           ucp2[0] & 0xff, ucp2[1] & 0xff);
+                       break;
+#endif
+#ifdef INET6
+               case AF_INET6:
+                       if (clp->lc_flags & LCL_TCPCALLBACK)
+                               (void) nfsm_strtom(nd, "tcp6", 4);
+                       else 
+                               (void) nfsm_strtom(nd, "udp6", 4);
+                       rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
+                       ucp = inet_ntop(AF_INET6, &rin6->sin6_addr, addrbuf,
+                           INET6_ADDRSTRLEN);
+                       if (ucp != NULL)
+                               i = strlen(ucp);
+                       else
+                               i = 0;
+                       ucp2 = (u_char *)&rin6->sin6_port;
+                       sprintf(&addrbuf[i], ".%d.%d", ucp2[0] & 0xff,
+                           ucp2[1] & 0xff);
+                       break;
+#endif
+               }
                (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
+               free(addrbuf, M_TEMP);
        }
        if (clp) {
                free(clp->lc_req.nr_nam, M_SONAME);
@@ -3964,7 +4003,12 @@ nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused 
        uint32_t sp4type, v41flags;
        uint64_t owner_minor;
        struct timespec verstime;
-       struct sockaddr_in *sad, *rad;
+#ifdef INET
+       struct sockaddr_in *sin, *rin;
+#endif
+#ifdef INET6
+       struct sockaddr_in6 *sin6, *rin6;
+#endif
        struct thread *p = curthread;
 
        if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
@@ -3987,16 +4031,31 @@ nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused 
        clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
            nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
        NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
-       clp->lc_req.nr_nam = malloc(sizeof(*clp->lc_req.nr_nam), M_SONAME,
+       /* Allocated large enough for an AF_INET or AF_INET6 socket. */
+       clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
            M_WAITOK | M_ZERO);
-       NFSSOCKADDRSIZE(clp->lc_req.nr_nam, sizeof (struct sockaddr_in));
-       sad = NFSSOCKADDR(nd->nd_nam, struct sockaddr_in *);
-       rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
-       rad->sin_family = AF_INET;
-       rad->sin_addr.s_addr = 0;
-       rad->sin_port = 0;
-       if (sad->sin_family == AF_INET)
-               rad->sin_addr.s_addr = sad->sin_addr.s_addr;
+       switch (nd->nd_nam->sa_family) {
+#ifdef INET
+       case AF_INET:
+               rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
+               sin = (struct sockaddr_in *)nd->nd_nam;
+               rin->sin_family = AF_INET;
+               rin->sin_len = sizeof(struct sockaddr_in);
+               rin->sin_port = 0;
+               rin->sin_addr.s_addr = sin->sin_addr.s_addr;
+               break;
+#endif
+#ifdef INET6
+       case AF_INET6:
+               rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
+               sin6 = (struct sockaddr_in6 *)nd->nd_nam;
+               rin6->sin6_family = AF_INET6;
+               rin6->sin6_len = sizeof(struct sockaddr_in6);
+               rin6->sin6_port = 0;
+               rin6->sin6_addr = sin6->sin6_addr;
+               break;
+#endif
+       }
        clp->lc_req.nr_cred = NULL;
        NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
        clp->lc_idlen = idlen;

Modified: head/sys/fs/nfsserver/nfs_nfsdstate.c
==============================================================================
--- head/sys/fs/nfsserver/nfs_nfsdstate.c       Sat Apr 13 21:45:45 2019        
(r346190)
+++ head/sys/fs/nfsserver/nfs_nfsdstate.c       Sat Apr 13 22:00:09 2019        
(r346191)
@@ -30,6 +30,8 @@
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
 
+#include "opt_inet.h"
+#include "opt_inet6.h"
 #ifndef APPLEKEXT
 #include <sys/extattr.h>
 #include <fs/nfs/nfsport.h>
@@ -248,7 +250,12 @@ nfsrv_setclient(struct nfsrv_descript *nd, struct nfsc
        struct nfsclient *clp = NULL, *new_clp = *new_clpp;
        int i, error = 0, ret;
        struct nfsstate *stp, *tstp;
-       struct sockaddr_in *sad, *rad;
+#ifdef INET
+       struct sockaddr_in *sin, *rin;
+#endif
+#ifdef INET6
+       struct sockaddr_in6 *sin6, *rin6;
+#endif
        struct nfsdsession *sep, *nsep;
        int zapit = 0, gotit, hasstate = 0, igotlock;
        static u_int64_t confirm_index = 0;
@@ -400,10 +407,24 @@ nfsrv_setclient(struct nfsrv_descript *nd, struct nfsc
                 * If the uid doesn't match, return NFSERR_CLIDINUSE after
                 * filling out the correct ipaddr and portnum.
                 */
-               sad = NFSSOCKADDR(new_clp->lc_req.nr_nam, struct sockaddr_in *);
-               rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
-               sad->sin_addr.s_addr = rad->sin_addr.s_addr;
-               sad->sin_port = rad->sin_port;
+               switch (clp->lc_req.nr_nam->sa_family) {
+#ifdef INET
+               case AF_INET:
+                       sin = (struct sockaddr_in *)new_clp->lc_req.nr_nam;
+                       rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
+                       sin->sin_addr.s_addr = rin->sin_addr.s_addr;
+                       sin->sin_port = rin->sin_port;
+                       break;
+#endif
+#ifdef INET6
+               case AF_INET6:
+                       sin6 = (struct sockaddr_in6 *)new_clp->lc_req.nr_nam;
+                       rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
+                       sin6->sin6_addr = rin6->sin6_addr;
+                       sin6->sin6_port = rin6->sin6_port;
+                       break;
+#endif
+               }
                NFSLOCKV4ROOTMUTEX();
                nfsv4_unlock(&nfsv4rootfs_lock, 1);
                NFSUNLOCKV4ROOTMUTEX();
@@ -956,9 +977,13 @@ nfsrv_dumpaclient(struct nfsclient *clp, struct nfsd_d
 {
        struct nfsstate *stp, *openstp, *lckownstp;
        struct nfslock *lop;
-       struct sockaddr *sad;
-       struct sockaddr_in *rad;
-       struct sockaddr_in6 *rad6;
+       sa_family_t af;
+#ifdef INET
+       struct sockaddr_in *rin;
+#endif
+#ifdef INET6
+       struct sockaddr_in6 *rin6;
+#endif
 
        dumpp->ndcl_nopenowners = dumpp->ndcl_nlockowners = 0;
        dumpp->ndcl_nopens = dumpp->ndcl_nlocks = 0;
@@ -966,14 +991,21 @@ nfsrv_dumpaclient(struct nfsclient *clp, struct nfsd_d
        dumpp->ndcl_flags = clp->lc_flags;
        dumpp->ndcl_clid.nclid_idlen = clp->lc_idlen;
        NFSBCOPY(clp->lc_id, dumpp->ndcl_clid.nclid_id, clp->lc_idlen);
-       sad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr *);
-       dumpp->ndcl_addrfam = sad->sa_family;
-       if (sad->sa_family == AF_INET) {
-               rad = (struct sockaddr_in *)sad;
-               dumpp->ndcl_cbaddr.sin_addr = rad->sin_addr;
-       } else {
-               rad6 = (struct sockaddr_in6 *)sad;
-               dumpp->ndcl_cbaddr.sin6_addr = rad6->sin6_addr;
+       af = clp->lc_req.nr_nam->sa_family;
+       dumpp->ndcl_addrfam = af;
+       switch (af) {
+#ifdef INET
+       case AF_INET:
+               rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
+               dumpp->ndcl_cbaddr.sin_addr = rin->sin_addr;
+               break;
+#endif
+#ifdef INET6
+       case AF_INET6:
+               rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
+               dumpp->ndcl_cbaddr.sin6_addr = rin6->sin6_addr;
+               break;
+#endif
        }
 
        /*
@@ -1014,9 +1046,13 @@ nfsrv_dumplocks(vnode_t vp, struct nfsd_dumplocks *ldu
        struct nfslock *lop;
        int cnt = 0;
        struct nfslockfile *lfp;
-       struct sockaddr *sad;
-       struct sockaddr_in *rad;
-       struct sockaddr_in6 *rad6;
+       sa_family_t af;
+#ifdef INET
+       struct sockaddr_in *rin;
+#endif
+#ifdef INET6
+       struct sockaddr_in6 *rin6;
+#endif
        int ret;
        fhandle_t nfh;
 
@@ -1058,14 +1094,22 @@ nfsrv_dumplocks(vnode_t vp, struct nfsd_dumplocks *ldu
                ldumpp[cnt].ndlck_clid.nclid_idlen = stp->ls_clp->lc_idlen;
                NFSBCOPY(stp->ls_clp->lc_id, ldumpp[cnt].ndlck_clid.nclid_id,
                    stp->ls_clp->lc_idlen);
-               sad=NFSSOCKADDR(stp->ls_clp->lc_req.nr_nam, struct sockaddr *);
-               ldumpp[cnt].ndlck_addrfam = sad->sa_family;
-               if (sad->sa_family == AF_INET) {
-                       rad = (struct sockaddr_in *)sad;
-                       ldumpp[cnt].ndlck_cbaddr.sin_addr = rad->sin_addr;
-               } else {
-                       rad6 = (struct sockaddr_in6 *)sad;
-                       ldumpp[cnt].ndlck_cbaddr.sin6_addr = rad6->sin6_addr;
+               af = stp->ls_clp->lc_req.nr_nam->sa_family;
+               ldumpp[cnt].ndlck_addrfam = af;
+               switch (af) {
+#ifdef INET
+               case AF_INET:
+                       rin = (struct sockaddr_in *)stp->ls_clp->lc_req.nr_nam;
+                       ldumpp[cnt].ndlck_cbaddr.sin_addr = rin->sin_addr;
+                       break;
+#endif
+#ifdef INET6
+               case AF_INET6:
+                       rin6 = (struct sockaddr_in6 *)
+                           stp->ls_clp->lc_req.nr_nam;
+                       ldumpp[cnt].ndlck_cbaddr.sin6_addr = rin6->sin6_addr;
+                       break;
+#endif
                }
                stp = LIST_NEXT(stp, ls_file);
                cnt++;
@@ -1090,14 +1134,22 @@ nfsrv_dumplocks(vnode_t vp, struct nfsd_dumplocks *ldu
                ldumpp[cnt].ndlck_clid.nclid_idlen = stp->ls_clp->lc_idlen;
                NFSBCOPY(stp->ls_clp->lc_id, ldumpp[cnt].ndlck_clid.nclid_id,
                    stp->ls_clp->lc_idlen);
-               sad=NFSSOCKADDR(stp->ls_clp->lc_req.nr_nam, struct sockaddr *);
-               ldumpp[cnt].ndlck_addrfam = sad->sa_family;
-               if (sad->sa_family == AF_INET) {
-                       rad = (struct sockaddr_in *)sad;
-                       ldumpp[cnt].ndlck_cbaddr.sin_addr = rad->sin_addr;
-               } else {
-                       rad6 = (struct sockaddr_in6 *)sad;
-                       ldumpp[cnt].ndlck_cbaddr.sin6_addr = rad6->sin6_addr;
+               af = stp->ls_clp->lc_req.nr_nam->sa_family;
+               ldumpp[cnt].ndlck_addrfam = af;
+               switch (af) {
+#ifdef INET
+               case AF_INET:
+                       rin = (struct sockaddr_in *)stp->ls_clp->lc_req.nr_nam;
+                       ldumpp[cnt].ndlck_cbaddr.sin_addr = rin->sin_addr;
+                       break;
+#endif
+#ifdef INET6
+               case AF_INET6:
+                       rin6 = (struct sockaddr_in6 *)
+                           stp->ls_clp->lc_req.nr_nam;
+                       ldumpp[cnt].ndlck_cbaddr.sin6_addr = rin6->sin6_addr;
+                       break;
+#endif
                }
                lop = LIST_NEXT(lop, lo_lckfile);
                cnt++;
@@ -1117,14 +1169,22 @@ nfsrv_dumplocks(vnode_t vp, struct nfsd_dumplocks *ldu
                ldumpp[cnt].ndlck_clid.nclid_idlen = stp->ls_clp->lc_idlen;
                NFSBCOPY(stp->ls_clp->lc_id, ldumpp[cnt].ndlck_clid.nclid_id,
                    stp->ls_clp->lc_idlen);
-               sad=NFSSOCKADDR(stp->ls_clp->lc_req.nr_nam, struct sockaddr *);
-               ldumpp[cnt].ndlck_addrfam = sad->sa_family;
-               if (sad->sa_family == AF_INET) {
-                       rad = (struct sockaddr_in *)sad;
-                       ldumpp[cnt].ndlck_cbaddr.sin_addr = rad->sin_addr;
-               } else {
-                       rad6 = (struct sockaddr_in6 *)sad;
-                       ldumpp[cnt].ndlck_cbaddr.sin6_addr = rad6->sin6_addr;
+               af = stp->ls_clp->lc_req.nr_nam->sa_family;
+               ldumpp[cnt].ndlck_addrfam = af;
+               switch (af) {
+#ifdef INET
+               case AF_INET:
+                       rin = (struct sockaddr_in *)stp->ls_clp->lc_req.nr_nam;
+                       ldumpp[cnt].ndlck_cbaddr.sin_addr = rin->sin_addr;
+                       break;
+#endif
+#ifdef INET6
+               case AF_INET6:
+                       rin6 = (struct sockaddr_in6 *)
+                           stp->ls_clp->lc_req.nr_nam;
+                       ldumpp[cnt].ndlck_cbaddr.sin6_addr = rin6->sin6_addr;
+                       break;
+#endif
                }
                stp = LIST_NEXT(stp, ls_file);
                cnt++;
@@ -3994,9 +4054,15 @@ nfsrv_getclientipaddr(struct nfsrv_descript *nd, struc
 {
        u_int32_t *tl;
        u_char *cp, *cp2;
-       int i, j;
-       struct sockaddr_in *rad, *sad;
-       u_char protocol[5], addr[24];
+       int i, j, maxalen = 0, minalen = 0;
+       sa_family_t af;
+#ifdef INET
+       struct sockaddr_in *rin, *sin;
+#endif
+#ifdef INET6
+       struct sockaddr_in6 *rin6, *sin6;
+#endif
+       u_char *addr;
        int error = 0, cantparse = 0;
        union {
                in_addr_t ival;
@@ -4007,27 +4073,44 @@ nfsrv_getclientipaddr(struct nfsrv_descript *nd, struc
                u_char cval[2];
        } port;
 
-       rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
-       rad->sin_family = AF_INET;
-       rad->sin_len = sizeof (struct sockaddr_in);
-       rad->sin_addr.s_addr = 0;
-       rad->sin_port = 0;
+       /* 8 is the maximum length of the port# string. */
+       addr = malloc(INET6_ADDRSTRLEN + 8, M_TEMP, M_WAITOK);
        clp->lc_req.nr_client = NULL;
        clp->lc_req.nr_lock = 0;
+       af = AF_UNSPEC;
        NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
        i = fxdr_unsigned(int, *tl);
        if (i >= 3 && i <= 4) {
-               error = nfsrv_mtostr(nd, protocol, i);
+               error = nfsrv_mtostr(nd, addr, i);
                if (error)
                        goto nfsmout;
-               if (!strcmp(protocol, "tcp")) {
+#ifdef INET
+               if (!strcmp(addr, "tcp")) {
                        clp->lc_flags |= LCL_TCPCALLBACK;
                        clp->lc_req.nr_sotype = SOCK_STREAM;
                        clp->lc_req.nr_soproto = IPPROTO_TCP;
-               } else if (!strcmp(protocol, "udp")) {
+                       af = AF_INET;
+               } else if (!strcmp(addr, "udp")) {
                        clp->lc_req.nr_sotype = SOCK_DGRAM;
                        clp->lc_req.nr_soproto = IPPROTO_UDP;
-               } else {
+                       af = AF_INET;
+               }
+#endif
+#ifdef INET6
+               if (af == AF_UNSPEC) {
+                       if (!strcmp(addr, "tcp6")) {
+                               clp->lc_flags |= LCL_TCPCALLBACK;
+                               clp->lc_req.nr_sotype = SOCK_STREAM;
+                               clp->lc_req.nr_soproto = IPPROTO_TCP;
+                               af = AF_INET6;
+                       } else if (!strcmp(addr, "udp6")) {
+                               clp->lc_req.nr_sotype = SOCK_DGRAM;
+                               clp->lc_req.nr_soproto = IPPROTO_UDP;
+                               af = AF_INET6;
+                       }
+               }
+#endif
+               if (af == AF_UNSPEC) {
                        cantparse = 1;
                }
        } else {
@@ -4038,6 +4121,36 @@ nfsrv_getclientipaddr(struct nfsrv_descript *nd, struc
                                goto nfsmout;
                }
        }
+       /*
+        * The caller has allocated clp->lc_req.nr_nam to be large enough
+        * for either AF_INET or AF_INET6 and zeroed out the contents.
+        * maxalen is set to the maximum length of the host IP address string
+        * plus 8 for the maximum length of the port#.
+        * minalen is set to the minimum length of the host IP address string
+        * plus 4 for the minimum length of the port#.
+        * These lengths do not include NULL termination,
+        * so INET[6]_ADDRSTRLEN - 1 is used in the calculations.
+        */
+       switch (af) {
+#ifdef INET
+       case AF_INET:
+               rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
+               rin->sin_family = AF_INET;
+               rin->sin_len = sizeof(struct sockaddr_in);
+               maxalen = INET_ADDRSTRLEN - 1 + 8;
+               minalen = 7 + 4;
+               break;
+#endif
+#ifdef INET6
+       case AF_INET6:
+               rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
+               rin6->sin6_family = AF_INET6;
+               rin6->sin6_len = sizeof(struct sockaddr_in6);
+               maxalen = INET6_ADDRSTRLEN - 1 + 8;
+               minalen = 3 + 4;
+               break;
+#endif
+       }
        NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
        i = fxdr_unsigned(int, *tl);
        if (i < 0) {
@@ -4045,18 +4158,43 @@ nfsrv_getclientipaddr(struct nfsrv_descript *nd, struc
                goto nfsmout;
        } else if (i == 0) {
                cantparse = 1;
-       } else if (!cantparse && i <= 23 && i >= 11) {
+       } else if (!cantparse && i <= maxalen && i >= minalen) {
                error = nfsrv_mtostr(nd, addr, i);
                if (error)
                        goto nfsmout;
 
                /*
                 * Parse out the address fields. We expect 6 decimal numbers
-                * separated by '.'s.
+                * separated by '.'s for AF_INET and two decimal numbers
+                * preceeded by '.'s for AF_INET6.
                 */
-               cp = addr;
-               i = 0;
-               while (*cp && i < 6) {
+               cp = NULL;
+               switch (af) {
+#ifdef INET6
+               /*
+                * For AF_INET6, first parse the host address.
+                */
+               case AF_INET6:
+                       cp = strchr(addr, '.');
+                       if (cp != NULL) {
+                               *cp++ = '\0';
+                               if (inet_pton(af, addr, &rin6->sin6_addr) == 1)
+                                       i = 4;
+                               else {
+                                       cp = NULL;
+                                       cantparse = 1;
+                               }
+                       }
+                       break;
+#endif
+#ifdef INET
+               case AF_INET:
+                       cp = addr;
+                       i = 0;
+                       break;
+#endif
+               }
+               while (cp != NULL && *cp && i < 6) {
                        cp2 = cp;
                        while (*cp2 && *cp2 != '.')
                                cp2++;
@@ -4080,11 +4218,30 @@ nfsrv_getclientipaddr(struct nfsrv_descript *nd, struc
                        i++;
                }
                if (!cantparse) {
-                       if (ip.ival != 0x0) {
-                               rad->sin_addr.s_addr = htonl(ip.ival);
-                               rad->sin_port = htons(port.sval);
-                       } else {
-                               cantparse = 1;
+                       /*
+                        * The host address INADDR_ANY is (mis)used to indicate
+                        * "there is no valid callback address".
+                        */
+                       switch (af) {
+#ifdef INET6
+                       case AF_INET6:
+                               if (!IN6_ARE_ADDR_EQUAL(&rin6->sin6_addr,
+                                   &in6addr_any))
+                                       rin6->sin6_port = htons(port.sval);
+                               else
+                                       cantparse = 1;
+                               break;
+#endif
+#ifdef INET
+                       case AF_INET:
+                               if (ip.ival != INADDR_ANY) {
+                                       rin->sin_addr.s_addr = htonl(ip.ival);
+                                       rin->sin_port = htons(port.sval);
+                               } else {
+                                       cantparse = 1;
+                               }
+                               break;
+#endif
                        }
                }
        } else {
@@ -4096,14 +4253,32 @@ nfsrv_getclientipaddr(struct nfsrv_descript *nd, struc
                }
        }
        if (cantparse) {
-               sad = NFSSOCKADDR(nd->nd_nam, struct sockaddr_in *);
-               if (sad->sin_family == AF_INET) {
-                       rad->sin_addr.s_addr = sad->sin_addr.s_addr;
-                       rad->sin_port = 0x0;
+               switch (nd->nd_nam->sa_family) {
+#ifdef INET
+               case AF_INET:
+                       sin = (struct sockaddr_in *)nd->nd_nam;
+                       rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
+                       rin->sin_family = AF_INET;
+                       rin->sin_len = sizeof(struct sockaddr_in);
+                       rin->sin_addr.s_addr = sin->sin_addr.s_addr;
+                       rin->sin_port = 0x0;
+                       break;
+#endif
+#ifdef INET6
+               case AF_INET6:
+                       sin6 = (struct sockaddr_in6 *)nd->nd_nam;
+                       rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
+                       rin6->sin6_family = AF_INET6;
+                       rin6->sin6_len = sizeof(struct sockaddr_in6);
+                       rin6->sin6_addr = sin6->sin6_addr;
+                       rin6->sin6_port = 0x0;
+                       break;
+#endif
                }
                clp->lc_program = 0;
        }
 nfsmout:
+       free(addr, M_TEMP);
        NFSEXITCODE2(error, nd);
        return (error);
 }

Modified: head/sys/modules/nfsd/Makefile
==============================================================================
--- head/sys/modules/nfsd/Makefile      Sat Apr 13 21:45:45 2019        
(r346190)
+++ head/sys/modules/nfsd/Makefile      Sat Apr 13 22:00:09 2019        
(r346191)
@@ -14,6 +14,7 @@ SRCS= vnode_if.h \
        nfs_nfsdport.c \
        opt_ufs.h \
        opt_nfs.h \
+       opt_inet.h \
        opt_inet6.h \
        opt_kgssapi.h
 


_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to