diff options
author | kan <kan@FreeBSD.org> | 2009-06-18 17:10:43 +0000 |
---|---|---|
committer | kan <kan@FreeBSD.org> | 2009-06-18 17:10:43 +0000 |
commit | ee4de3e44a17a3ff08159350eea8f7c94dd1e5d7 (patch) | |
tree | 2a0f0b7ee0f67cd05c309fb30ec86d6fda69018f | |
parent | 1df38023872009fd9556c189e7da834c1d250b34 (diff) | |
download | FreeBSD-src-ee4de3e44a17a3ff08159350eea8f7c94dd1e5d7.zip FreeBSD-src-ee4de3e44a17a3ff08159350eea8f7c94dd1e5d7.tar.gz |
Re-do r192913 in less intrusive way. Only do IP_RECVDSTADDR/IP_SENDSRCADDR
dace for UPDv4 sockets bound to INADDR_ANY. Move the code to set
IP_RECVDSTADDR/IP_SENDSRCADDR into svc_dg.c, so that both TLI and non-TLI
users will be using it.
Back out my previous commit to mountd. Turns out the problem was affecting
more than one binary so it needs to me addressed in generic rpc code in
libc in order to fix them all.
Reported by: lstewart
Tested by: lstewart
-rw-r--r-- | include/rpc/svc_dg.h | 1 | ||||
-rw-r--r-- | lib/libc/rpc/svc_dg.c | 48 | ||||
-rw-r--r-- | lib/libc/rpc/svc_generic.c | 9 | ||||
-rw-r--r-- | usr.sbin/mountd/mountd.c | 7 |
4 files changed, 37 insertions, 28 deletions
diff --git a/include/rpc/svc_dg.h b/include/rpc/svc_dg.h index 3514745..e0d1f89 100644 --- a/include/rpc/svc_dg.h +++ b/include/rpc/svc_dg.h @@ -46,6 +46,7 @@ struct svc_dg_data { XDR su_xdrs; /* XDR handle */ char su_verfbody[MAX_AUTH_BYTES]; /* verifier body */ void *su_cache; /* cached data, NULL if none */ + struct netbuf su_srcaddr; /* dst address of last msg */ }; #define __rpcb_get_dg_xidp(x) (&((struct svc_dg_data *)(x)->xp_p2)->su_xid) diff --git a/lib/libc/rpc/svc_dg.c b/lib/libc/rpc/svc_dg.c index ea1f5ff..a78b160 100644 --- a/lib/libc/rpc/svc_dg.c +++ b/lib/libc/rpc/svc_dg.c @@ -97,8 +97,9 @@ int svc_dg_enablecache(SVCXPRT *, u_int); */ static const char svc_dg_str[] = "svc_dg_create: %s"; static const char svc_dg_err1[] = "could not get transport information"; -static const char svc_dg_err2[] = " transport does not support data transfer"; +static const char svc_dg_err2[] = "transport does not support data transfer"; static const char svc_dg_err3[] = "getsockname failed"; +static const char svc_dg_err4[] = "cannot set IP_RECVDSTADDR"; static const char __no_mem_str[] = "out of memory"; SVCXPRT * @@ -156,6 +157,23 @@ svc_dg_create(fd, sendsize, recvsize) xprt->xp_ltaddr.len = slen; memcpy(xprt->xp_ltaddr.buf, &ss, slen); + if (ss.ss_family == AF_INET) { + struct sockaddr_in *sin; + static const int true_value = 1; + + sin = (struct sockaddr_in *)(void *)&ss; + if (sin->sin_addr.s_addr == INADDR_ANY) { + su->su_srcaddr.buf = mem_alloc(sizeof (ss)); + su->su_srcaddr.maxlen = sizeof (ss); + + if (_setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, + &true_value, sizeof(true_value))) { + warnx(svc_dg_str, svc_dg_err4); + goto freedata_nowarn; + } + } + } + xprt_register(xprt); return (xprt); freedata: @@ -197,13 +215,15 @@ svc_dg_recvfrom(int fd, char *buf, int buflen, msg.msg_iovlen = 1; msg.msg_namelen = *raddrlen; msg.msg_name = (char *)raddr; - msg.msg_control = (caddr_t)tmp; - msg.msg_controllen = CMSG_LEN(sizeof(*lin)); + if (laddr != NULL) { + msg.msg_control = (caddr_t)tmp; + msg.msg_controllen = CMSG_LEN(sizeof(*lin)); + } rlen = _recvmsg(fd, &msg, 0); if (rlen >= 0) *raddrlen = msg.msg_namelen; - if (rlen == -1 || !laddr || + if (rlen == -1 || laddr == NULL || msg.msg_controllen < sizeof(struct cmsghdr) || msg.msg_flags & MSG_CTRUNC) return rlen; @@ -214,18 +234,19 @@ svc_dg_recvfrom(int fd, char *buf, int buflen, cmsg->cmsg_type == IP_RECVDSTADDR) { have_lin = TRUE; memcpy(&lin->sin_addr, - (struct in_addr *)CMSG_DATA(cmsg), sizeof(struct in_addr)); + (struct in_addr *)CMSG_DATA(cmsg), + sizeof(struct in_addr)); break; } } - if (!have_lin) - return rlen; - lin->sin_family = AF_INET; lin->sin_port = 0; *laddrlen = sizeof(struct sockaddr_in); + if (!have_lin) + lin->sin_addr.s_addr = INADDR_ANY; + return rlen; } @@ -246,7 +267,7 @@ again: alen = sizeof (struct sockaddr_storage); rlen = svc_dg_recvfrom(xprt->xp_fd, rpc_buffer(xprt), su->su_iosz, (struct sockaddr *)(void *)&ss, &alen, - (struct sockaddr *)xprt->xp_ltaddr.buf, &xprt->xp_ltaddr.len); + (struct sockaddr *)su->su_srcaddr.buf, &su->su_srcaddr.len); if (rlen == -1 && errno == EINTR) goto again; if (rlen == -1 || (rlen < (ssize_t)(4 * sizeof (u_int32_t)))) @@ -300,7 +321,8 @@ svc_dg_sendto(int fd, char *buf, int buflen, msg.msg_namelen = raddrlen; msg.msg_name = (char *)raddr; - if (laddr->sa_family == AF_INET && lin->s_addr != INADDR_ANY) { + if (laddr != NULL && laddr->sa_family == AF_INET && + lin->s_addr != INADDR_ANY) { msg.msg_control = (caddr_t)tmp; msg.msg_controllen = CMSG_LEN(sizeof(*lin)); cmsg = CMSG_FIRSTHDR(&msg); @@ -346,8 +368,8 @@ svc_dg_reply(xprt, msg) if (svc_dg_sendto(xprt->xp_fd, rpc_buffer(xprt), slen, (struct sockaddr *)xprt->xp_rtaddr.buf, (socklen_t)xprt->xp_rtaddr.len, - (struct sockaddr *)xprt->xp_ltaddr.buf, - xprt->xp_ltaddr.len) == (ssize_t) slen) { + (struct sockaddr *)su->su_srcaddr.buf, + (socklen_t)su->su_srcaddr.len) == (ssize_t) slen) { stat = TRUE; if (su->su_cache) cache_set(xprt, slen); @@ -393,6 +415,8 @@ svc_dg_destroy(xprt) (void)_close(xprt->xp_fd); XDR_DESTROY(&(su->su_xdrs)); (void) mem_free(rpc_buffer(xprt), su->su_iosz); + if (su->su_srcaddr.buf) + (void) mem_free(su->su_srcaddr.buf, su->su_srcaddr.maxlen); (void) mem_free(su, sizeof (*su)); if (xprt->xp_rtaddr.buf) (void) mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen); diff --git a/lib/libc/rpc/svc_generic.c b/lib/libc/rpc/svc_generic.c index 9b50b44..7f6cfb8 100644 --- a/lib/libc/rpc/svc_generic.c +++ b/lib/libc/rpc/svc_generic.c @@ -199,7 +199,6 @@ svc_tli_create(fd, nconf, bindaddr, sendsz, recvsz) struct __rpc_sockinfo si; struct sockaddr_storage ss; socklen_t slen; - static const int true_value = 1; if (fd == RPC_ANYFD) { if (nconf == NULL) { @@ -226,14 +225,6 @@ svc_tli_create(fd, nconf, bindaddr, sendsz, recvsz) } } - if (si.si_af == AF_INET && si.si_socktype == SOCK_DGRAM) { - if (_setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, - &true_value, sizeof(true_value))) { - warnx("svc_tli_create: cannot set IP_RECVDSTADDR"); - return (NULL); - } - } - /* * If the fd is unbound, try to bind it. */ diff --git a/usr.sbin/mountd/mountd.c b/usr.sbin/mountd/mountd.c index 0c19a2b..6977b93 100644 --- a/usr.sbin/mountd/mountd.c +++ b/usr.sbin/mountd/mountd.c @@ -568,13 +568,6 @@ create_service(struct netconfig *nconf) continue; } } - if (si.si_socktype == SOCK_DGRAM && - setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &one, - sizeof one) < 0) { - syslog(LOG_ERR, - "can't disable v4-in-v6 on IPv6 socket"); - exit(1); - } break; case AF_INET6: if (inet_pton(AF_INET6, hosts[nhostsbak], |