Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 27 Apr 2019 01:58:52 +0000 (UTC)
From:      Rick Macklem <rmacklem@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org
Subject:   svn commit: r346773 - in stable/12/sys: fs/nfsserver modules/nfsd
Message-ID:  <201904270158.x3R1wqDj087941@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: rmacklem
Date: Sat Apr 27 01:58:51 2019
New Revision: 346773
URL: https://svnweb.freebsd.org/changeset/base/346773

Log:
  MFC: r346191
  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.

Modified:
  stable/12/sys/fs/nfsserver/nfs_nfsdserv.c
  stable/12/sys/fs/nfsserver/nfs_nfsdstate.c
  stable/12/sys/modules/nfsd/Makefile
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/fs/nfsserver/nfs_nfsdserv.c
==============================================================================
--- stable/12/sys/fs/nfsserver/nfs_nfsdserv.c	Sat Apr 27 01:50:09 2019	(r346772)
+++ stable/12/sys/fs/nfsserver/nfs_nfsdserv.c	Sat Apr 27 01:58:51 2019	(r346773)
@@ -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
@@ -3655,8 +3657,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;
 
 	if ((nd->nd_flag & ND_NFSV41) != 0) {
@@ -3683,9 +3693,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;
@@ -3727,17 +3737,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);
@@ -3938,7 +3977,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
 
 	if (nfs_rootfhset == 0 || nfsd_checkrootexp(nd) != 0) {
 		nd->nd_repstat = NFSERR_WRONGSEC;
@@ -3960,16 +4004,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: stable/12/sys/fs/nfsserver/nfs_nfsdstate.c
==============================================================================
--- stable/12/sys/fs/nfsserver/nfs_nfsdstate.c	Sat Apr 27 01:50:09 2019	(r346772)
+++ stable/12/sys/fs/nfsserver/nfs_nfsdstate.c	Sat Apr 27 01:58:51 2019	(r346773)
@@ -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: stable/12/sys/modules/nfsd/Makefile
==============================================================================
--- stable/12/sys/modules/nfsd/Makefile	Sat Apr 27 01:50:09 2019	(r346772)
+++ stable/12/sys/modules/nfsd/Makefile	Sat Apr 27 01:58:51 2019	(r346773)
@@ -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
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201904270158.x3R1wqDj087941>