diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h index 23475b29e141..3b494a51fa88 100644 --- a/sys/fs/nfs/nfs_var.h +++ b/sys/fs/nfs/nfs_var.h @@ -306,7 +306,7 @@ void nfscl_reqstart(struct nfsrv_descript *, int, struct nfsmount *, nfsuint64 *nfscl_getcookie(struct nfsnode *, off_t off, int); void nfscl_fillsattr(struct nfsrv_descript *, struct vattr *, vnode_t, int, u_int32_t); -u_int8_t *nfscl_getmyip(struct nfsmount *, int *); +u_int8_t *nfscl_getmyip(struct nfsmount *, struct in6_addr *, int *); int nfsm_getfh(struct nfsrv_descript *, struct nfsfh **); int nfscl_mtofh(struct nfsrv_descript *, struct nfsfh **, struct nfsvattr *, int *); diff --git a/sys/fs/nfsclient/nfs_clport.c b/sys/fs/nfsclient/nfs_clport.c index cdccbc897c61..44085066216f 100644 --- a/sys/fs/nfsclient/nfs_clport.c +++ b/sys/fs/nfsclient/nfs_clport.c @@ -34,6 +34,7 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_inet.h" #include "opt_inet6.h" #include @@ -46,7 +47,9 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include +#include #include #include @@ -1038,73 +1041,66 @@ nfscl_loadfsinfo(struct nfsmount *nmp, struct nfsfsinfo *fsp) } /* - * Get a pointer to my IP addrress and return it. - * Return NULL if you can't find one. + * Lookups source address which should be used to communicate with + * @nmp and stores it inside @pdst. + * + * Returns 0 on success. */ u_int8_t * -nfscl_getmyip(struct nfsmount *nmp, int *isinet6p) +nfscl_getmyip(struct nfsmount *nmp, struct in6_addr *paddr, int *isinet6p) { - struct sockaddr_in sad, *sin; - struct rtentry *rt; - u_int8_t *retp = NULL; - static struct in_addr laddr; + int error, fibnum; - *isinet6p = 0; - /* - * Loop up a route for the destination address. - */ + fibnum = curthread->td_proc->p_fibnum; + +#ifdef INET if (nmp->nm_nam->sa_family == AF_INET) { - bzero(&sad, sizeof (sad)); - sin = (struct sockaddr_in *)nmp->nm_nam; - sad.sin_family = AF_INET; - sad.sin_len = sizeof (struct sockaddr_in); - sad.sin_addr.s_addr = sin->sin_addr.s_addr; - CURVNET_SET(CRED_TO_VNET(nmp->nm_sockreq.nr_cred)); - rt = rtalloc1_fib((struct sockaddr *)&sad, 0, 0UL, - curthread->td_proc->p_fibnum); - if (rt != NULL) { - if (rt->rt_ifp != NULL && - rt->rt_ifa != NULL && - ((rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0) && - rt->rt_ifa->ifa_addr->sa_family == AF_INET) { - sin = (struct sockaddr_in *) - rt->rt_ifa->ifa_addr; - laddr.s_addr = sin->sin_addr.s_addr; - retp = (u_int8_t *)&laddr; - } - RTFREE_LOCKED(rt); - } - CURVNET_RESTORE(); -#ifdef INET6 - } else if (nmp->nm_nam->sa_family == AF_INET6) { - struct sockaddr_in6 sad6, *sin6; - static struct in6_addr laddr6; + struct sockaddr_in *sin; + struct nhop4_extended nh_ext; - bzero(&sad6, sizeof (sad6)); - sin6 = (struct sockaddr_in6 *)nmp->nm_nam; - sad6.sin6_family = AF_INET6; - sad6.sin6_len = sizeof (struct sockaddr_in6); - sad6.sin6_addr = sin6->sin6_addr; + sin = (struct sockaddr_in *)nmp->nm_nam; CURVNET_SET(CRED_TO_VNET(nmp->nm_sockreq.nr_cred)); - rt = rtalloc1_fib((struct sockaddr *)&sad6, 0, 0UL, - curthread->td_proc->p_fibnum); - if (rt != NULL) { - if (rt->rt_ifp != NULL && - rt->rt_ifa != NULL && - ((rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0) && - rt->rt_ifa->ifa_addr->sa_family == AF_INET6) { - sin6 = (struct sockaddr_in6 *) - rt->rt_ifa->ifa_addr; - laddr6 = sin6->sin6_addr; - retp = (u_int8_t *)&laddr6; - *isinet6p = 1; - } - RTFREE_LOCKED(rt); - } + error = fib4_lookup_nh_ext(fibnum, sin->sin_addr, 0, 0, + &nh_ext); CURVNET_RESTORE(); -#endif + if (error != 0) + return (NULL); + + if ((ntohl(nh_ext.nh_src.s_addr) >> IN_CLASSA_NSHIFT) == + IN_LOOPBACKNET) { + /* Ignore loopback addresses */ + return (NULL); + } + + *isinet6p = 0; + *((struct in_addr *)paddr) = nh_ext.nh_src; + + return (u_int8_t *)paddr; } - return (retp); +#endif +#ifdef INET6 + if (nmp->nm_nam->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6; + + sin6 = (struct sockaddr_in6 *)nmp->nm_nam; + + CURVNET_SET(CRED_TO_VNET(nmp->nm_sockreq.nr_cred)); + error = in6_selectsrc_addr(fibnum, &sin6->sin6_addr, + sin6->sin6_scope_id, NULL, paddr, NULL); + CURVNET_RESTORE(); + if (error != 0) + return (NULL); + + if (IN6_IS_ADDR_LOOPBACK(paddr)) + return (NULL); + + /* Scope is embedded in */ + *isinet6p = 1; + + return (u_int8_t *)paddr; + } +#endif + return (NULL); } /* diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c index 710994442ff1..a7d47f0ab9e0 100644 --- a/sys/fs/nfsclient/nfs_clrpcops.c +++ b/sys/fs/nfsclient/nfs_clrpcops.c @@ -829,6 +829,7 @@ nfsrpc_setclient(struct nfsmount *nmp, struct nfsclclient *clp, int reclaim, u_int32_t lease; static u_int32_t rev = 0; struct nfsclds *dsp, *ndsp, *tdsp; + struct in6_addr a6; if (nfsboottime.tv_sec == 0) NFSSETBOOTTIME(nfsboottime); @@ -889,7 +890,7 @@ nfsrpc_setclient(struct nfsmount *nmp, struct nfsclclient *clp, int reclaim, *tl = txdr_unsigned(NFS_CALLBCKPROG); callblen = strlen(nfsv4_callbackaddr); if (callblen == 0) - cp = nfscl_getmyip(nmp, &isinet6); + cp = nfscl_getmyip(nmp, &a6, &isinet6); if (nfscl_enablecallb && nfs_numnfscbd > 0 && (callblen > 0 || cp != NULL)) { port = htons(nfsv4_cbport);